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 fs from 'fs'; 17import path from 'path'; 18import { ApiType } from '../../../typedef/parser/ApiInfoDefination'; 19import { 20 ErrorType, 21 ErrorID, 22 LogType, 23 ErrorLevel, 24 ErrorTagFormat, 25 ErrorMessage, 26} from '../../../typedef/checker/result_type'; 27import { BasicApiInfo } from '../../../typedef/parser/ApiInfoDefination'; 28import { tagsArrayOfOrder, officialTagArr, CommonFunctions } from '../../../utils/checkUtils'; 29import { AddErrorLogs } from './compile_info'; 30import { compositiveResult, compositiveLocalResult, punctuationMarkSet } from '../../../utils/checkUtils'; 31import { Set } from 'typescript'; 32 33const dictionariesContent: string = fs.readFileSync(path.resolve(__dirname, '../config/dictionaries.txt'), 'utf-8'); 34const dictionariesArr: string[] = dictionariesContent.split(/[(\r\n)\r\n]+/g); 35const dictionariesSupplementaryContent: string = fs.readFileSync( 36 path.resolve(__dirname, '../config/dictionaries_supplementary.txt'), 37 'utf-8' 38); 39const dictionariesSupplementaryArr: string[] = dictionariesSupplementaryContent.split(/[(\r\n)\r\n]+/g); 40const dictionariesSet: Set<string> = new Set([ 41 ...dictionariesArr, 42 ...dictionariesSupplementaryArr, 43 ...tagsArrayOfOrder, 44 ...officialTagArr, 45]); 46 47export class WordsCheck { 48 /** 49 * words spell check 50 * @param { BasicApiInfo[] } baseInfos 51 */ 52 static wordCheckResultsProcessing(baseInfos: BasicApiInfo[]): void { 53 baseInfos.forEach((baseInfo) => { 54 if (baseInfo.getApiType() !== ApiType.SOURCE_FILE) { 55 const nodeFullText = JSON.stringify(baseInfo.getNode()?.getFullText()); 56 const nodeText = nodeFullText.substring(nodeFullText.indexOf('/**'), nodeFullText.length); 57 const apiText = nodeText.indexOf('{') > -1 ? nodeText.substring(0, nodeText.indexOf('{')) : nodeText; 58 WordsCheck.wordsCheck(apiText, baseInfo); 59 } 60 }); 61 } 62 63 /** 64 * Break the obtained api information into single words. 65 * @param { string } apiText 66 * @param { BasicApiInfo } baseInfo 67 */ 68 static wordsCheck(apiText: string, baseInfo: BasicApiInfo): void { 69 const reg = /\s{2,}/g; 70 const regx = /(\/\*|\*\/|\*)|\\n|\\r/g; 71 let fullText: string = apiText.replace(regx, ' '); 72 punctuationMarkSet.forEach(punctuationMark => { 73 const punctuationMarkReg = new RegExp(punctuationMark, 'g'); 74 if (punctuationMarkReg.test(fullText)) { 75 fullText = fullText.replace(punctuationMarkReg, ' ').replace(reg, ' '); 76 } 77 }); 78 let apiWordsArr = fullText.split(/\s/g); 79 const errorWords: string[] = []; 80 apiWordsArr.forEach((apiWord) => { 81 const basicWords: string[] = WordsCheck.splitComplexWords(apiWord); 82 basicWords.forEach((basicWord) => { 83 if (!WordsCheck.checkBaseWord(basicWord.toLowerCase())) { 84 errorWords.push(basicWord); 85 const wordsCheckFormat: ErrorTagFormat = { 86 state: false, 87 errorInfo: CommonFunctions.createErrorInfo(ErrorMessage.ERROR_WORD, [basicWord]), 88 }; 89 AddErrorLogs.addAPICheckErrorLogs( 90 ErrorID.MISSPELL_WORDS_ID, 91 ErrorLevel.MIDDLE, 92 baseInfo.getFilePath(), 93 baseInfo.getPos(), 94 ErrorType.MISSPELL_WORDS, 95 LogType.LOG_JSDOC, 96 -1, 97 baseInfo.getApiName(), 98 baseInfo.getDefinedText(), 99 wordsCheckFormat.errorInfo, 100 compositiveResult, 101 compositiveLocalResult 102 ); 103 } 104 }); 105 }); 106 } 107 108 /** 109 * Whether compound words are underlined 110 * @param { string } word 111 * @returns { boolean } 112 */ 113 static hasUnderline(word: string): boolean { 114 return /(?<!^)\_/g.test(word); 115 } 116 117 /** 118 * split complex words 119 * @param { string } complexWord 120 * @returns { string[] } 121 */ 122 static splitComplexWords(complexWord: string): string[] { 123 let basicWords: string[] = []; 124 // splite underlineWord 125 if (WordsCheck.hasUnderline(complexWord)) { 126 basicWords = complexWord.split(/(?<!^)\_/g); 127 } else { 128 // splite complexWord 129 if (!/(?<!^)(?=[A-Z])/g.test(complexWord)) { 130 basicWords.push(complexWord); 131 } else { 132 basicWords = complexWord.split(/(?<!^)(?=[A-Z])/g); 133 } 134 } 135 const newBaseWords: string[] = []; 136 basicWords.forEach((word) => { 137 if (/[0-9]/g.test(word)) { 138 newBaseWords.concat(word.split(/0-9/g)); 139 } else { 140 newBaseWords.push(word); 141 } 142 }); 143 return newBaseWords; 144 } 145 146 /** 147 * check base word 148 * @param { string } word 149 * @returns { boolean } 150 */ 151 static checkBaseWord(word: string): boolean { 152 if (/^[a-z][0-9]+$/g.test(word)) { 153 return false; 154 } else if (/^[A-Za-z]+/g.test(word) && !dictionariesSet.has(word.toLowerCase())) { 155 return false; 156 } 157 return true; 158 } 159} 160