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 */ 15import fs from 'fs'; 16import { Parser, FilesMap } from '../../parser/parser'; 17import { ApiInfo, BasicApiInfo, notJsDocApiTypes } from '../../../typedef/parser/ApiInfoDefination'; 18import { 19 ErrorType, 20 ErrorID, 21 LogType, 22 ErrorLevel, 23 ErrorTagFormat, 24 ErrorMessage, 25} from '../../../typedef/checker/result_type'; 26import { ClassInfo } from '../../../typedef/parser/ApiInfoDefination'; 27import { Comment } from '../../../typedef/parser/Comment'; 28import { compositiveResult, compositiveLocalResult } from '../../../utils/checkUtils'; 29import { OrderCheck } from './tag_order_check'; 30import { TagNameCheck } from './tag_name_check'; 31import { LegalityCheck } from './tag_legality_check'; 32import { TagRepeatCheck } from './tag_repeat_check'; 33import { AddErrorLogs } from './compile_info'; 34import { toNumber } from 'lodash'; 35import { TagValueCheck } from './tag_value_check'; 36import { WordsCheck } from './words_check'; 37import { ForbiddenWordsCheck } from './forbidden_words_check'; 38import { ApiNamingCheck } from './naming_check'; 39import { CheckHump } from './check_hump'; 40import { EventMethodChecker } from './event_method_check'; 41import { EventMethodData } from '../../../typedef/checker/event_method_check_interface'; 42import { ApiChangeCheck } from './check_api_diff'; 43import { TagInheritCheck } from './tag_inherit_check'; 44 45export class Check { 46 /** 47 * checker tool main entrance 48 * @param { string } url -File path for storing file information. 49 */ 50 static scanEntry(url: string): void { 51 if (fs.existsSync(url)) { 52 const files: Array<string> = Check.getMdFiles(url); 53 ApiChangeCheck.checkApiChange(); 54 files.forEach((filePath: string, index: number) => { 55 console.log(`scaning file in no ${++index}!`); 56 const fileParseResult: FilesMap = Check.parseAPICodeStyle(filePath); 57 const baseInfos: BasicApiInfo[] = Parser.getAllBasicApi(fileParseResult); 58 Check.checkNodeInfos(baseInfos as ClassInfo[]); 59 const currFileInfo = fileParseResult.get(filePath); 60 if (currFileInfo) { 61 CheckHump.checkAPIFileName(currFileInfo); 62 } 63 CheckHump.checkAllAPINameOfHump(baseInfos); 64 //words check 65 WordsCheck.wordCheckResultsProcessing(baseInfos); 66 // event check 67 const eventMethodChecker: EventMethodChecker = new EventMethodChecker(fileParseResult); 68 const eventMethodDataMap: Map<string, EventMethodData> = eventMethodChecker.getAllEventMethod(); 69 eventMethodChecker.checkEventMethod(eventMethodDataMap); 70 }); 71 } 72 } 73 74 /** 75 * Obtain the path of the file to be checked. 76 * @param { string } url -File path for storing file information. 77 * @returns { Array<string> } -file path array 78 */ 79 static getMdFiles(url: string): Array<string> { 80 const content: string = fs.readFileSync(url, 'utf-8'); 81 const mdFiles: Array<string> = content.split(/[(\r\n)\r\n]+/); 82 return mdFiles; 83 } 84 85 /** 86 * Based on a single file path,parse it using the Parser method. 87 * @param { string } filePath -single file path to be checked 88 * @returns { FilesMap } 89 */ 90 static parseAPICodeStyle(filePath: string): FilesMap { 91 const fileDir: string = filePath.substring(0, filePath.lastIndexOf('\\')); 92 const parseResult: FilesMap = Parser.parseFile(fileDir, filePath); 93 return parseResult; 94 } 95 96 /** 97 * Obtain all API information and check api jsdoc 98 * @param { ClassInfo[] } baseInfos 99 */ 100 static checkNodeInfos(baseInfos: ClassInfo[]): void { 101 let allNodeInfos: ApiInfo[] = []; 102 Check.getHasJsdocApiInfos(baseInfos, allNodeInfos); 103 104 // for all nodes of the current file 105 allNodeInfos.forEach((singleApi: ApiInfo) => { 106 const apiJsdoc: Comment.JsDocInfo | undefined = singleApi.getLastJsDocInfo(); 107 if (apiJsdoc === undefined) { 108 AddErrorLogs.addAPICheckErrorLogs( 109 ErrorID.NO_JSDOC_ID, 110 ErrorLevel.MIDDLE, 111 singleApi.getFilePath(), 112 singleApi.getPos(), 113 ErrorType.NO_JSDOC, 114 LogType.LOG_JSDOC, 115 -1, 116 singleApi.getApiName(), 117 singleApi.getDefinedText(), 118 ErrorMessage.ERROR_NO_JSDOC, 119 compositiveResult, 120 compositiveLocalResult 121 ); 122 } else { 123 // legality check 124 const tagLegalityCheckResult: ErrorTagFormat[] = LegalityCheck.apiLegalityCheck(singleApi, apiJsdoc); 125 // order check 126 const orderCheckResult: ErrorTagFormat = OrderCheck.orderCheck(apiJsdoc); 127 // api naming check 128 const namingCheckResult: ErrorTagFormat = ApiNamingCheck.namingCheck(singleApi); 129 // tags name check 130 const tagNamseCheckResult: ErrorTagFormat = TagNameCheck.tagNameCheck(apiJsdoc); 131 // tags inherit check 132 const tagInheritCheckResult: ErrorTagFormat = TagInheritCheck.tagInheritCheck(singleApi); 133 // tags value check 134 const tagValueCheckResult: ErrorTagFormat[] = TagValueCheck.tagValueCheck(singleApi, apiJsdoc); 135 // tags repeat check 136 const tagRepeatCheckResult: ErrorTagFormat[] = TagRepeatCheck.tagRepeatCheck(apiJsdoc); 137 // api forbidden wors check 138 const forbiddenWorsCheckResult: ErrorTagFormat = ForbiddenWordsCheck.forbiddenWordsCheck(singleApi as ClassInfo); 139 if (!orderCheckResult.state) { 140 AddErrorLogs.addAPICheckErrorLogs( 141 ErrorID.WRONG_ORDER_ID, 142 ErrorLevel.MIDDLE, 143 singleApi.getFilePath(), 144 singleApi.getPos(), 145 ErrorType.WRONG_ORDER, 146 LogType.LOG_JSDOC, 147 toNumber(apiJsdoc.since), 148 singleApi.getApiName(), 149 singleApi.getDefinedText(), 150 orderCheckResult.errorInfo, 151 compositiveResult, 152 compositiveLocalResult 153 ); 154 } 155 if (!tagNamseCheckResult.state) { 156 AddErrorLogs.addAPICheckErrorLogs( 157 ErrorID.UNKNOW_DECORATOR_ID, 158 ErrorLevel.MIDDLE, 159 singleApi.getFilePath(), 160 singleApi.getPos(), 161 ErrorType.UNKNOW_DECORATOR, 162 LogType.LOG_JSDOC, 163 toNumber(apiJsdoc.since), 164 singleApi.getApiName(), 165 singleApi.getDefinedText(), 166 tagNamseCheckResult.errorInfo, 167 compositiveResult, 168 compositiveLocalResult 169 ); 170 } 171 if (!forbiddenWorsCheckResult.state) { 172 AddErrorLogs.addAPICheckErrorLogs( 173 ErrorID.FORBIDDEN_WORDS_ID, 174 ErrorLevel.MIDDLE, 175 singleApi.getFilePath(), 176 singleApi.getPos(), 177 ErrorType.FORBIDDEN_WORDS, 178 LogType.LOG_API, 179 toNumber(apiJsdoc.since), 180 singleApi.getApiName(), 181 singleApi.getDefinedText(), 182 forbiddenWorsCheckResult.errorInfo, 183 compositiveResult, 184 compositiveLocalResult 185 ); 186 } 187 if (!namingCheckResult.state) { 188 AddErrorLogs.addAPICheckErrorLogs( 189 ErrorID.NAMING_ERRORS_ID, 190 ErrorLevel.MIDDLE, 191 singleApi.getFilePath(), 192 singleApi.getPos(), 193 ErrorType.NAMING_ERRORS, 194 LogType.LOG_API, 195 toNumber(apiJsdoc.since), 196 singleApi.getApiName(), 197 singleApi.getDefinedText(), 198 namingCheckResult.errorInfo, 199 compositiveResult, 200 compositiveLocalResult 201 ); 202 } 203 if (!tagInheritCheckResult.state) { 204 AddErrorLogs.addAPICheckErrorLogs( 205 ErrorID.WRONG_SCENE_ID, 206 ErrorLevel.MIDDLE, 207 singleApi.getFilePath(), 208 singleApi.getPos(), 209 ErrorType.WRONG_SCENE, 210 LogType.LOG_JSDOC, 211 toNumber(apiJsdoc.since), 212 singleApi.getApiName(), 213 singleApi.getDefinedText(), 214 tagInheritCheckResult.errorInfo, 215 compositiveResult, 216 compositiveLocalResult 217 ); 218 } 219 tagLegalityCheckResult.forEach((legalityResult) => { 220 if (legalityResult.state === false) { 221 AddErrorLogs.addAPICheckErrorLogs( 222 ErrorID.WRONG_SCENE_ID, 223 ErrorLevel.MIDDLE, 224 singleApi.getFilePath(), 225 singleApi.getPos(), 226 ErrorType.WRONG_SCENE, 227 LogType.LOG_JSDOC, 228 toNumber(apiJsdoc.since), 229 singleApi.getApiName(), 230 singleApi.getDefinedText(), 231 legalityResult.errorInfo, 232 compositiveResult, 233 compositiveLocalResult 234 ); 235 } 236 }); 237 tagValueCheckResult.forEach((valueResult) => { 238 if (valueResult.state === false) { 239 AddErrorLogs.addAPICheckErrorLogs( 240 ErrorID.WRONG_SCENE_ID, 241 ErrorLevel.MIDDLE, 242 singleApi.getFilePath(), 243 singleApi.getPos(), 244 ErrorType.WRONG_SCENE, 245 LogType.LOG_JSDOC, 246 toNumber(apiJsdoc.since), 247 singleApi.getApiName(), 248 singleApi.getDefinedText(), 249 valueResult.errorInfo, 250 compositiveResult, 251 compositiveLocalResult 252 ); 253 } 254 }); 255 tagRepeatCheckResult.forEach((repeatResult) => { 256 if (repeatResult.state === false) { 257 AddErrorLogs.addAPICheckErrorLogs( 258 ErrorID.WRONG_SCENE_ID, 259 ErrorLevel.MIDDLE, 260 singleApi.getFilePath(), 261 singleApi.getPos(), 262 ErrorType.WRONG_SCENE, 263 LogType.LOG_JSDOC, 264 toNumber(apiJsdoc.since), 265 singleApi.getApiName(), 266 singleApi.getDefinedText(), 267 repeatResult.errorInfo, 268 compositiveResult, 269 compositiveLocalResult 270 ); 271 } 272 }); 273 } 274 }); 275 } 276 /** 277 * Filter out all nodes with comments. 278 * @param { BasicApiInfo[] } childNodeApis -original data. 279 * @param { ApiInfo[] } childNodeInfos -processed data. 280 */ 281 static getHasJsdocApiInfos(childNodeApis: BasicApiInfo[], childNodeInfos: ApiInfo[]): void { 282 childNodeApis.forEach((childNodeApi) => { 283 if (!notJsDocApiTypes.has(childNodeApi.getApiType())) { 284 childNodeInfos.push(childNodeApi as ApiInfo); 285 } 286 }); 287 return; 288 } 289} 290