• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import path from 'path';
17import { AddErrorLogs } from './compile_info';
18import { StringConstant } from '../../../utils/Constant';
19import { ApiInfosMap, FileInfoMap } from '../../parser/parser';
20import {
21  ErrorType,
22  ErrorID,
23  LogType,
24  ErrorLevel,
25  ErrorMessage,
26  ApiCheckInfo,
27  ErrorBaseInfo,
28} from '../../../typedef/checker/result_type';
29import { Comment } from '../../../typedef/parser/Comment';
30import {
31  ApiType,
32  BasicApiInfo,
33  ApiInfo,
34  notJsDocApiTypes,
35} from '../../../typedef/parser/ApiInfoDefination';
36import { CommonFunctions } from '../../../utils/checkUtils';
37import { compositiveResult, compositiveLocalResult } from '../../../utils/checkUtils';
38import { currentFilePath } from './api_check_plugin';
39
40export class CheckHump {
41  /**
42   * 大驼峰检查:
43   * class、interface、枚举名
44   *
45   * @param {string} word 校验名称
46   * @return { boolean }
47   */
48  static checkLargeHump(word: string): boolean {
49    return /^([A-Z][a-z0-9]*)*$/g.test(word);
50  }
51  /**
52   * 小驼峰检查:
53   * 变量名、方法名、参数名、namespace
54   *
55   * @param {string} word 校验名称
56   * @return { boolean }
57   */
58  static checkSmallHump(word: string): boolean {
59    return /^[a-z]+[0-9]*([A-Z][a-z0-9]*)*$/g.test(word);
60  }
61  /**
62   * 全大写检查:
63   * 常量命名、枚举值
64   *
65   * @param {string} word 校验名称
66   * @return { boolean }
67   */
68  static checkAllUppercaseHump(word: string): boolean {
69    return /^[A-Z]+[0-9]*([\_][A-Z0-9]+)*$/g.test(word);
70  }
71
72  /**
73   * 获取fileMap里的对应的apiinfos
74   *
75   * @param { FileInfoMap } fileMap 文件解析结果
76   * @param { string } apiKey 获取api名称
77   * @return {BasicApiInfo[]} apiInfo
78   */
79  static getApiInfosInFileMap(fileMap: FileInfoMap, apiKey: string): BasicApiInfo[] {
80    if (apiKey === StringConstant.SELF) {
81      return [];
82    }
83    const apiInfoMap: ApiInfosMap = fileMap.get(apiKey) as ApiInfosMap;
84    return apiInfoMap.get(StringConstant.SELF) as BasicApiInfo[];
85  }
86
87  /**
88   * 遍历所有api,进行api名称校验
89   *
90   * @param {BasicApiInfo[]} apiInfos
91   */
92  static checkAllAPINameOfHump(apiInfos: BasicApiInfo[]): void {
93    apiInfos.forEach((apiInfo: BasicApiInfo) => {
94      if (!notJsDocApiTypes.has(apiInfo.getApiType())) {
95        CheckHump.checkAPINameOfHump(apiInfo as ApiInfo);
96      }
97    });
98  }
99  /**
100   * api名称校验
101   *
102   * @param {ApiInfo} apiInfo api节点
103   */
104  static checkAPINameOfHump(apiInfo: ApiInfo): void {
105    const jsDocInfo: Comment.JsDocInfo | undefined = apiInfo.getLastJsDocInfo();
106    const publishVersion: string = apiInfo.getJsDocInfos().length > 0 ? apiInfo.getJsDocInfos()[0].getSince() : '';
107    if (jsDocInfo) {
108      if (jsDocInfo.getDeprecatedVersion() !== '-1') {
109        return;
110      }
111      if (publishVersion !== String(CommonFunctions.getCheckApiVersion())) {
112        return;
113      }
114    }
115    const apiType: string = apiInfo.getApiType();
116    const filePath: string = apiInfo.getFilePath();
117    let apiName: string = apiInfo.getApiName();
118    let checkResult: string = '';
119    if (apiInfo.getIsJoinType()) {
120      apiName = apiName.split('_')[0];
121    }
122    if (
123      apiType === ApiType.ENUM_VALUE ||
124      (apiType === ApiType.CONSTANT && filePath.indexOf(`component${path.sep}ets${path.sep}`) === -1)
125    ) {
126      if (!CheckHump.checkAllUppercaseHump(apiName)) {
127        checkResult = CommonFunctions.createErrorInfo(ErrorMessage.ERROR_UPPERCASE_NAME, [apiName]);
128      }
129    } else if (
130      apiType === ApiType.INTERFACE ||
131      apiType === ApiType.CLASS ||
132      apiType === ApiType.TYPE_ALIAS ||
133      apiType === ApiType.ENUM
134    ) {
135      if (!CheckHump.checkLargeHump(apiName)) {
136        checkResult = CommonFunctions.createErrorInfo(ErrorMessage.ERROR_LARGE_HUMP_NAME, [apiName]);
137      }
138    } else if (
139      apiType === ApiType.PROPERTY ||
140      apiType === ApiType.METHOD ||
141      apiType === ApiType.PARAM ||
142      apiType === ApiType.NAMESPACE
143    ) {
144      if (!CheckHump.checkSmallHump(apiName)) {
145        checkResult = CommonFunctions.createErrorInfo(ErrorMessage.ERROR_SMALL_HUMP_NAME, [apiName]);
146      }
147    }
148
149    if (checkResult !== '') {
150      const errorBaseInfo: ErrorBaseInfo = new ErrorBaseInfo();
151      errorBaseInfo
152        .setErrorID(ErrorID.NAMING_ERRORS_ID)
153        .setErrorLevel(ErrorLevel.MIDDLE)
154        .setErrorType(ErrorType.NAMING_ERRORS)
155        .setLogType(LogType.LOG_JSDOC)
156        .setErrorInfo(checkResult);
157      const apiInfoHump: ApiCheckInfo = CommonFunctions.getErrorInfo(apiInfo, undefined, currentFilePath,
158        errorBaseInfo);
159      AddErrorLogs.addAPICheckErrorLogs(apiInfoHump, compositiveResult, compositiveLocalResult);
160    }
161  }
162
163  /**
164   * 校验文件名称:
165   * 只处理非component/ets/路径下的文件
166   * 传入节点必须是文件的SourceFile节点
167   *
168   * @param {FileInfoMap} fileInfo 文件节点
169   */
170  static checkAPIFileName(fileInfo: FileInfoMap): void {
171    const fileApiInfo: BasicApiInfo = (fileInfo.get(StringConstant.SELF) as BasicApiInfo[])[0];
172    if (fileApiInfo.getApiType() !== ApiType.SOURCE_FILE) {
173      return;
174    }
175    const filePath: string = fileApiInfo.getFilePath();
176    if (filePath.indexOf(`component${path.sep}ets${path.sep}`) !== -1) {
177      return;
178    }
179    let moduleName = '';
180    let exportAssignment = '';
181    let version = 'NA';
182    for (const apiKey of fileInfo.keys()) {
183      const apiInfos: BasicApiInfo[] = CheckHump.getApiInfosInFileMap(fileInfo, apiKey);
184      apiInfos.forEach((apiInfo) => {
185        if (!notJsDocApiTypes.has(apiInfo.getApiType())) {
186          const jsDocInfos: Comment.JsDocInfo[] = (apiInfo as ApiInfo).getJsDocInfos();
187          version = jsDocInfos[0] ? CommonFunctions.getSinceVersion(jsDocInfos[0].getSince()) : version;
188        }
189        moduleName = apiInfo.getApiType() === ApiType.NAMESPACE ? apiInfo.getApiName() : moduleName;
190        exportAssignment = (apiInfo.getApiType() === ApiType.EXPORT_DEFAULT || apiInfo.getIsExport()) ? apiInfo.getApiName().replace(StringConstant.EXPORT_DEFAULT, '') : exportAssignment;
191      });
192    }
193    const basename: string = path.basename(filePath).replace(new RegExp(StringConstant.DTS_EXTENSION, 'g'), '').replace(new RegExp(StringConstant.DETS_EXTENSION, 'g'), '');
194
195    const basenames: string[] = basename.split('.');
196    const lastModuleName: string = basenames.length ? basenames[basenames.length - 1] : '';
197    let checkResult: string = '';
198
199    if (moduleName !== '' && exportAssignment === moduleName && !CheckHump.checkSmallHump(lastModuleName)) {
200      checkResult = ErrorMessage.ERROR_SMALL_HUMP_NAME_FILE;
201    } else if (moduleName === '' && exportAssignment !== moduleName && !CheckHump.checkLargeHump(lastModuleName)) {
202      checkResult = ErrorMessage.ERROR_LARGE_HUMP_NAME_FILE;
203    }
204    if (checkResult !== '' && version === String(CommonFunctions.getCheckApiVersion())) {
205      const errorBaseInfo: ErrorBaseInfo = new ErrorBaseInfo();
206      errorBaseInfo
207        .setErrorID(ErrorID.NAMING_ERRORS_ID)
208        .setErrorLevel(ErrorLevel.MIDDLE)
209        .setErrorType(ErrorType.NAMING_ERRORS)
210        .setLogType(LogType.LOG_JSDOC)
211        .setErrorInfo(checkResult);
212      const apiInfoHump: ApiCheckInfo = CommonFunctions.getErrorInfo(fileApiInfo, undefined, currentFilePath,
213        errorBaseInfo);
214      AddErrorLogs.addAPICheckErrorLogs(apiInfoHump, compositiveResult, compositiveLocalResult);
215    }
216  }
217}
218