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} from '../../../typedef/checker/result_type'; 27import { Comment } from '../../../typedef/parser/Comment'; 28import { 29 ApiType, 30 BasicApiInfo, 31 ApiInfo, 32 notJsDocApiTypes, 33} from '../../../typedef/parser/ApiInfoDefination'; 34import { CommonFunctions } from '../../../utils/checkUtils'; 35import { compositiveResult, compositiveLocalResult } from '../../../utils/checkUtils'; 36 37export class CheckHump { 38 /** 39 * 大驼峰检查: 40 * class、interface、枚举名 41 * 42 * @param {string} word 校验名称 43 * @return { boolean } 44 */ 45 static checkLargeHump(word: string): boolean { 46 return /^([A-Z][a-z0-9]*)*$/g.test(word); 47 } 48 /** 49 * 小驼峰检查: 50 * 变量名、方法名、参数名、namespace 51 * 52 * @param {string} word 校验名称 53 * @return { boolean } 54 */ 55 static checkSmallHump(word: string): boolean { 56 return /^[a-z]+[0-9]*([A-Z][a-z0-9]*)*$/g.test(word); 57 } 58 /** 59 * 全大写检查: 60 * 常量命名、枚举值 61 * 62 * @param {string} word 校验名称 63 * @return { boolean } 64 */ 65 static checkAllUppercaseHump(word: string): boolean { 66 return /^[A-Z]+[0-9]*([\_][A-Z0-9]+)*$/g.test(word); 67 } 68 69 /** 70 * 获取fileMap里的对应的apiinfos 71 * 72 * @param { FileInfoMap } fileMap 文件解析结果 73 * @param { string } apiKey 获取api名称 74 * @return {BasicApiInfo[]} apiInfo 75 */ 76 static getApiInfosInFileMap(fileMap: FileInfoMap, apiKey: string): BasicApiInfo[] { 77 if (apiKey === StringConstant.SELF) { 78 return []; 79 } 80 const apiInfoMap: ApiInfosMap = fileMap.get(apiKey) as ApiInfosMap; 81 return apiInfoMap.get(StringConstant.SELF) as BasicApiInfo[]; 82 } 83 84 /** 85 * 遍历所有api,进行api名称校验 86 * 87 * @param {BasicApiInfo[]} apiInfos 88 */ 89 static checkAllAPINameOfHump(apiInfos: BasicApiInfo[]): void { 90 apiInfos.forEach((apiInfo: BasicApiInfo) => { 91 if (!notJsDocApiTypes.has(apiInfo.getApiType())) { 92 CheckHump.checkAPINameOfHump(apiInfo as ApiInfo); 93 } 94 }); 95 } 96 /** 97 * api名称校验 98 * 99 * @param {ApiInfo} apiInfo api节点 100 */ 101 static checkAPINameOfHump(apiInfo: ApiInfo): void { 102 const jsDocInfo: Comment.JsDocInfo | undefined = apiInfo.getLastJsDocInfo(); 103 if (jsDocInfo) { 104 if (jsDocInfo.getDeprecatedVersion() !== '-1') { 105 return; 106 } 107 if (jsDocInfo.getSince() !== String(CommonFunctions.getCheckApiVersion())) { 108 return; 109 } 110 } 111 const apiType: string = apiInfo.getApiType(); 112 const filePath: string = apiInfo.getFilePath(); 113 const apiName: string = apiInfo.getApiName(); 114 let checkResult: string = ''; 115 if ( 116 apiType === ApiType.ENUM_VALUE || 117 (apiType === ApiType.CONSTANT && filePath.indexOf(`component${path.sep}ets${path.sep}`) === -1) 118 ) { 119 if (!CheckHump.checkAllUppercaseHump(apiName)) { 120 checkResult = CommonFunctions.createErrorInfo(ErrorMessage.ERROR_UPPERCASE_NAME, [apiName]); 121 } 122 } else if ( 123 apiType === ApiType.INTERFACE || 124 apiType === ApiType.CLASS || 125 apiType === ApiType.TYPE_ALIAS || 126 apiType === ApiType.ENUM 127 ) { 128 if (!CheckHump.checkLargeHump(apiName)) { 129 checkResult = CommonFunctions.createErrorInfo(ErrorMessage.ERROR_LARGE_HUMP_NAME, [apiName]); 130 } 131 } else if ( 132 apiType === ApiType.PROPERTY || 133 apiType === ApiType.METHOD || 134 apiType === ApiType.PARAM || 135 apiType === ApiType.NAMESPACE 136 ) { 137 if (!CheckHump.checkSmallHump(apiName)) { 138 checkResult = CommonFunctions.createErrorInfo(ErrorMessage.ERROR_SMALL_HUMP_NAME, [apiName]); 139 } 140 } 141 142 if (checkResult !== '') { 143 AddErrorLogs.addAPICheckErrorLogs( 144 ErrorID.TS_SYNTAX_ERROR_ID, 145 ErrorLevel.MIDDLE, 146 filePath, 147 { line: -1, character: -1 }, 148 ErrorType.MISSPELL_WORDS, 149 LogType.LOG_API, 150 -1, 151 apiName, 152 apiInfo.getDefinedText(), 153 checkResult, 154 compositiveResult, 155 compositiveLocalResult 156 ); 157 } 158 } 159 160 /** 161 * 校验文件名称: 162 * 只处理非component/ets/路径下的文件 163 * 传入节点必须是文件的SourceFile节点 164 * 165 * @param {FileInfoMap} fileInfo 文件节点 166 */ 167 static checkAPIFileName(fileInfo: FileInfoMap): void { 168 const fileApiInfo: BasicApiInfo = (fileInfo.get(StringConstant.SELF) as BasicApiInfo[])[0]; 169 if (fileApiInfo.getApiType() !== ApiType.SOURCE_FILE) { 170 return; 171 } 172 const filePath: string = fileApiInfo.getFilePath(); 173 if (filePath.indexOf(`component${path.sep}ets${path.sep}`) !== -1) { 174 return; 175 } 176 let moduleName = ''; 177 let exportAssignment = ''; 178 let version = 'NA'; 179 for (const apiKey of fileInfo.keys()) { 180 const apiInfos: BasicApiInfo[] = CheckHump.getApiInfosInFileMap(fileInfo, apiKey); 181 apiInfos.forEach((apiInfo) => { 182 if (!notJsDocApiTypes.has(apiInfo.getApiType())) { 183 const jsDocInfos: Comment.JsDocInfo[] = (apiInfo as ApiInfo).getJsDocInfos(); 184 version = jsDocInfos[0] ? jsDocInfos[0].getSince() : version; 185 } 186 moduleName = apiInfo.getApiType() === ApiType.NAMESPACE ? apiInfo.getApiName() : moduleName; 187 exportAssignment = apiInfo.getApiType() === ApiType.EXPORT_DEFAULT ? apiInfo.getApiName() : exportAssignment; 188 }); 189 } 190 const basename: string = path.basename(filePath).replace(new RegExp(StringConstant.DTS_EXTENSION, 'g'), ''); 191 192 const basenames: string[] = basename.split('.'); 193 const lastModuleName: string = basenames.length ? basenames[basenames.length - 1] : ''; 194 let checkResult: string = ''; 195 196 if (moduleName !== '' && exportAssignment === moduleName && !CheckHump.checkSmallHump(lastModuleName)) { 197 checkResult = ErrorMessage.ERROR_SMALL_HUMP_NAME_FILE; 198 } else if (moduleName === '' && exportAssignment !== moduleName && !CheckHump.checkLargeHump(lastModuleName)) { 199 checkResult = ErrorMessage.ERROR_LARGE_HUMP_NAME_FILE; 200 } 201 if (checkResult !== '' && version === String(CommonFunctions.getCheckApiVersion())) { 202 AddErrorLogs.addAPICheckErrorLogs( 203 ErrorID.MISSPELL_WORDS_ID, 204 ErrorLevel.MIDDLE, 205 filePath, 206 { line: -1, character: -1 }, 207 ErrorType.MISSPELL_WORDS, 208 LogType.LOG_API, 209 -1, 210 'NA', 211 'NA', 212 checkResult, 213 compositiveResult, 214 compositiveLocalResult 215 ); 216 } 217 } 218} 219