1/*
2 * Copyright (c) 2021-2022 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 */
15const path = require('path');
16const {
17  ErrorType,
18  ErrorLevel,
19  FileType,
20  getApiVersion,
21  getCheckApiVersion,
22  requireTypescriptModule
23} = require('./utils');
24const { addAPICheckErrorLogs, getParentkind } = require('./compile_info');
25const ts = requireTypescriptModule();
26const nameDictionary = require('./name_dictionary.json');
27const nameScenarioScope = require('./name_scenario_scope.json');
28
29function checkNaming(node, sourcefile, fileName) {
30  const apiVersionToBeVerified = getCheckApiVersion();
31  const apiVersion = Number(getApiVersion(node));
32
33  if (apiVersionToBeVerified.indexOf('^') === 0) {
34    const minCheckApiVersion = Number(apiVersionToBeVerified.substr(1));
35    checkApiVerion(minCheckApiVersion);
36    if (apiVersion > minCheckApiVersion) {
37      checkApiNaming(node, sourcefile, fileName);
38    }
39  } else if (apiVersion === Number(apiVersionToBeVerified)) {
40    checkApiNaming(node, sourcefile, fileName);
41  } else {
42    checkApiVerion(apiVersionToBeVerified);
43  }
44}
45exports.checkNaming = checkNaming;
46
47function checkApiNaming(node, sourcefile, fileName) {
48  const lowIdentifier = node.getText().toLowerCase();
49  const apiParentKind = [];
50  getParentkind(node, apiParentKind);
51  if (node.parent.kind === ts.SyntaxKind.TypeReference || apiParentKind.includes('JSDoc')) {
52    return;
53  }
54  checkApiNamingWords(node, sourcefile, fileName, lowIdentifier);
55  checkApiNamingScenario(node, sourcefile, fileName, lowIdentifier);
56}
57
58function checkApiNamingWords(node, sourcefile, fileName, lowIdentifier) {
59  const lowercaseNamingMap = getlowercaseNamingMap();
60  for (const [key, value] of lowercaseNamingMap) {
61    const prohibitedWordIndex = lowIdentifier.indexOf(key);
62    if (prohibitedWordIndex === -1) {
63      continue;
64    }
65    const lowercaseIgnoreWordArr = value.ignore.map(word => word.toLowerCase());
66    const internalWord = node.getText().substr(prohibitedWordIndex, key.length);
67    const errorInfo = `Prohibited word in [${node.getText()}]:{${internalWord}}.The word allowed is [${value.suggestion}]`;
68    if (lowercaseIgnoreWordArr.length === 0) {
69      addAPICheckErrorLogs(node, sourcefile, fileName, ErrorType.NAMING_ERRORS, errorInfo, FileType.LOG_API,
70        ErrorLevel.MIDDLE
71      );
72      break;
73    } else {
74      const isIgnoreWord = checkIgnoreWord(lowercaseIgnoreWordArr, lowIdentifier, value.badWord);
75      if (isIgnoreWord === false) {
76        addAPICheckErrorLogs(node, sourcefile, fileName, ErrorType.NAMING_ERRORS, errorInfo, FileType.LOG_API,
77          ErrorLevel.MIDDLE
78        );
79      }
80    }
81  }
82}
83
84function checkIgnoreWord(lowercaseIgnoreWordArr, lowIdentifier, badWord) {
85  let isIgnoreWord = false;
86  const isNamingFoot = lowIdentifier.substring(lowIdentifier.length - badWord.length, lowIdentifier.length) === badWord;
87  for (let i = 0; i < lowercaseIgnoreWordArr.length; i++) {
88    if (lowercaseIgnoreWordArr[i] && lowIdentifier.indexOf(lowercaseIgnoreWordArr[i]) !== -1) {
89      isIgnoreWord = true;
90      break;
91    }
92  }
93  if (!isNamingFoot) {
94    isIgnoreWord = true;
95  }
96  return isIgnoreWord;
97}
98
99function checkApiVerion(apiVersion) {
100  if (isNaN(parseInt(apiVersion))) {
101    throw 'Please configure the correct API version to be verified';
102  }
103}
104
105function checkApiNamingScenario(node, sourcefile, fileName, lowIdentifier) {
106  const lowercaseNamingScenarioMap = getlowercaseNamingScenarioMap();
107  for (const [key, value] of lowercaseNamingScenarioMap) {
108    const prohibitedWordIndex = lowIdentifier.indexOf(key);
109    if (
110      prohibitedWordIndex !== -1 &&
111      !isInAllowedFiles(value.files, path.basename(fileName))
112    ) {
113      const internalWord = node.getText().substr(prohibitedWordIndex, key.length);
114      const errorInfo = `Prohibited word in [${node.getText()}]:{${internalWord}} in the [${path.basename(fileName)}] file`;
115      addAPICheckErrorLogs(node, sourcefile, fileName, ErrorType.NAMING_ERRORS, errorInfo, FileType.LOG_API,
116        ErrorLevel.MIDDLE
117      );
118    }
119  }
120}
121
122function getlowercaseNamingMap() {
123  const lowercaseNamingMap = new Map();
124  for (const item of nameDictionary) {
125    const key = item.badWord.toLowerCase();
126    const { badWord, suggestion, ignore } = item;
127    lowercaseNamingMap.set(key, { badWord, suggestion, ignore });
128  }
129  return lowercaseNamingMap;
130}
131
132function getlowercaseNamingScenarioMap() {
133  const lowercaseNamingScenarioMap = new Map();
134  for (const item of nameScenarioScope) {
135    const key = item.word.toLowerCase();
136    const { word, files } = item;
137    lowercaseNamingScenarioMap.set(key, { word, files });
138  }
139  return lowercaseNamingScenarioMap;
140}
141
142function isInAllowedFiles(files, fileName) {
143  for (const item of files) {
144    const pattern = new RegExp(item);
145    pattern.test(fileName);
146    if (pattern.test(fileName)) {
147      return true;
148    }
149  }
150  return false;
151}
152