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 { 16 ErrorTagFormat, 17 NameDictionaryType, 18 NameScenarioType, 19 ErrorMessage, 20} from '../../../typedef/checker/result_type'; 21import { ApiInfo } from '../../../typedef/parser/ApiInfoDefination'; 22import { Comment } from '../../../typedef/parser/Comment'; 23import { CommonFunctions, punctuationMarkSet } from '../../../utils/checkUtils'; 24import { WordsCheck } from './words_check'; 25const nameDictionary = require('../config/name_dictionary.json'); 26const nameScenarioScope = require('../config/name_scenario_scope.json'); 27 28export class ApiNamingCheck { 29 /** 30 * Check if the Api name is correct. 31 * @param { Comment.JsDocInfo } apiJsdoc -api jsdoc all infomation 32 * @returns { boolean } 33 */ 34 static namingCheck(singleApi: ApiInfo): ErrorTagFormat { 35 const tagNameCheckResult: ErrorTagFormat = { 36 state: true, 37 errorInfo: '', 38 }; 39 const jsDocInfo: Comment.JsDocInfo[] = singleApi.getJsDocInfos(); 40 const publishVersion: string = CommonFunctions.getSinceVersion(jsDocInfo[0].getSince()); 41 const apiVersionToBeVerified: string = CommonFunctions.getCheckApiVersion(); 42 const fileName: string = singleApi.getFilePath().toLowerCase(); 43 const reg = /\s{2,}/g; 44 const regx = /(\/\*|\*\/|\*)|\n|\r/g; 45 let apiText: string = singleApi.getDefinedText().replace(regx, ' '); 46 punctuationMarkSet.forEach(punctuationMark => { 47 const punctuationMarkReg = new RegExp(punctuationMark, 'g'); 48 if (punctuationMarkReg.test(apiText)) { apiText = apiText.replace(punctuationMarkReg, ' ').replace(reg, ' '); } 49 }); 50 let apiWordsArr = apiText.split(/\s/g); 51 let basicWords: string[] = []; 52 apiWordsArr.forEach((apiWord) => { WordsCheck.splitComplexWords(apiWord, basicWords); }); 53 basicWords.forEach((basicWord: string) => { 54 if (publishVersion === apiVersionToBeVerified) { 55 ApiNamingCheck.checkApiNamingWords(basicWord, tagNameCheckResult); 56 ApiNamingCheck.checkApiNamingScenario(fileName, tagNameCheckResult, singleApi); 57 } 58 }); 59 return tagNameCheckResult; 60 } 61 62 /** 63 * 64 * @param { string } lowIdentifier 65 * @param { ErrorTagFormat } tagNameCheckResult 66 */ 67 static checkApiNamingWords(lowIdentifier: string, tagNameCheckResult: ErrorTagFormat): void { 68 const lowercaseNamingMap: Map<string, NameDictionaryType> = ApiNamingCheck.getlowercaseNamingMap(); 69 for (const [key, value] of lowercaseNamingMap) { 70 const prohibitedWordIndex: number = lowIdentifier.indexOf(key); 71 if (prohibitedWordIndex === -1) { 72 continue; 73 } 74 const lowercaseIgnoreWordArr: string[] = value.ignore.map((word: string) => word.toLowerCase()); 75 const internalWord: string = lowIdentifier.substring(prohibitedWordIndex, prohibitedWordIndex + key.length); 76 if (lowercaseIgnoreWordArr.length === 0) { 77 tagNameCheckResult.state = false; 78 tagNameCheckResult.errorInfo = CommonFunctions.createErrorInfo(ErrorMessage.ERROR_NAMING, [ 79 lowIdentifier, 80 internalWord, 81 value.suggestion, 82 ]); 83 break; 84 } else { 85 const isIgnoreWord: boolean = ApiNamingCheck.checkIgnoreWord(lowercaseIgnoreWordArr, lowIdentifier); 86 if (isIgnoreWord === false) { 87 tagNameCheckResult.state = false; 88 tagNameCheckResult.errorInfo = CommonFunctions.createErrorInfo(ErrorMessage.ERROR_NAMING, [ 89 lowIdentifier, 90 internalWord, 91 value.suggestion, 92 ]); 93 } 94 } 95 } 96 } 97 98 /** 99 * 100 * @param {string} lowIdentifier 101 * @param {ErrorTagFormat} tagNameCheckResult 102 * @param {ApiInfo} singleApi 103 */ 104 static checkApiNamingScenario(lowIdentifier: string, tagNameCheckResult: ErrorTagFormat, singleApi: ApiInfo): void { 105 const lowercaseNamingScenarioMap = ApiNamingCheck.getlowercaseNamingScenarioMap(); 106 for (const [key, value] of lowercaseNamingScenarioMap) { 107 const prohibitedWordIndex: number = lowIdentifier.indexOf(key); 108 if (prohibitedWordIndex !== -1 && !ApiNamingCheck.isInAllowedFiles(value.files, singleApi.getFilePath())) { 109 tagNameCheckResult.state = false; 110 tagNameCheckResult.errorInfo = CommonFunctions.createErrorInfo(ErrorMessage.ERROR_SCENARIO, [ 111 lowIdentifier, 112 key, 113 singleApi.getFilePath(), 114 ]); 115 } 116 } 117 } 118 119 /** 120 * 121 * @returns 122 */ 123 static getlowercaseNamingMap(): Map<string, NameDictionaryType> { 124 const lowercaseNamingMap: Map<string, NameDictionaryType> = new Map(); 125 for (const item of nameDictionary) { 126 const namingKey: string = item.badWord.toLowerCase(); 127 const namingValue: NameDictionaryType = item; 128 lowercaseNamingMap.set(namingKey, namingValue); 129 } 130 return lowercaseNamingMap; 131 } 132 133 /** 134 * 135 * @param { string[] } lowercaseIgnoreWordArr 136 * @param { string }lowIdentifier 137 * @returns { boolean } 138 */ 139 static checkIgnoreWord(lowercaseIgnoreWordArr: string[], lowIdentifier: string): boolean { 140 let isIgnoreWord: boolean = false; 141 for (let i = 0; i < lowercaseIgnoreWordArr.length; i++) { 142 if (lowercaseIgnoreWordArr[i] && lowIdentifier.indexOf(lowercaseIgnoreWordArr[i]) !== -1) { 143 isIgnoreWord = true; 144 break; 145 } 146 } 147 return isIgnoreWord; 148 } 149 150 /** 151 * 152 * @returns { Map<string, NameScenarioType> } 153 */ 154 static getlowercaseNamingScenarioMap(): Map<string, NameScenarioType> { 155 const lowercaseNamingScenarioMap: Map<string, NameScenarioType> = new Map(); 156 for (const item of nameScenarioScope) { 157 const scenarioKey = item.word.toLowerCase(); 158 const scenarioValue: NameScenarioType = item; 159 lowercaseNamingScenarioMap.set(scenarioKey, scenarioValue); 160 } 161 return lowercaseNamingScenarioMap; 162 } 163 164 /** 165 * 166 * @param { string[] } files 167 * @param { string } fileName 168 * @returns { boolean } 169 */ 170 static isInAllowedFiles(files: string[], fileName: string): boolean { 171 for (const item of files) { 172 const pattern: RegExp = new RegExp(item); 173 pattern.test(fileName); 174 if (pattern.test(fileName)) { 175 return true; 176 } 177 } 178 return false; 179 } 180} 181