• 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 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