• 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 */
15import path from 'path';
16import fs, { Stats } from 'fs';
17import { Workbook, Worksheet } from 'exceljs';
18import ts, { LineAndCharacter } from 'typescript';
19import { ApiResultSimpleInfo, ApiResultInfo } from '../typedef/checker/result_type';
20
21export class PosOfNode {
22  /**
23   * 获取行列信息
24   * @param { ts.Node } node
25   * @param { ts.Diagnostic } diagnostic
26   */
27  static getPosOfNode(node: ts.Node, diagnostic: ts.Diagnostic): string {
28    const posOfNode: LineAndCharacter = ts.getLineAndCharacterOfPosition(
29      node.getSourceFile(),
30      diagnostic.start as number
31    );
32    const location: string =
33      (diagnostic.file?.fileName as string) + `(line: ${posOfNode.line + 1}, col: ${posOfNode.character + 1})`;
34    return location;
35  }
36}
37
38export class CompolerOptions {
39  /**
40   * tsconfig配置项设置
41   */
42  static getCompolerOptions(): ts.CompilerOptions {
43    const compilerOptions: ts.CompilerOptions = ts.readConfigFile(
44      path.resolve(__dirname, '../../tsconfig.json'),
45      ts.sys.readFile
46    ).config.compilerOptions;
47    Object.assign(compilerOptions, {
48      target: 'es2020',
49      jsx: 'preserve',
50      incremental: undefined,
51      declaration: undefined,
52      declarationMap: undefined,
53      emitDeclarationOnly: undefined,
54      outFile: undefined,
55      composite: undefined,
56      tsBuildInfoFile: undefined,
57      noEmit: undefined,
58      isolatedModules: true,
59      paths: undefined,
60      rootDirs: undefined,
61      types: undefined,
62      out: undefined,
63      noLib: undefined,
64      noResolve: true,
65      noEmitOnError: undefined,
66      declarationDir: undefined,
67      suppressOutputPathCheck: true,
68      allowNonTsExtensions: true,
69    });
70    return compilerOptions;
71  }
72}
73
74export class GenerateFile {
75  /**
76   * 将错误信息输出为txt文件
77   * @param { ApiResultSimpleInfo[] } resultData
78   * @param { string } outputPath
79   * @param { string } option
80   */
81  static writeFile(resultData: ApiResultSimpleInfo[], outputPath: string, option: object): void {
82    const STANDARD_INDENT: number = 2;
83    fs.writeFile(
84      path.resolve(__dirname, outputPath),
85      JSON.stringify(resultData, null, STANDARD_INDENT),
86      option,
87      (err) => {
88        if (err) {
89          console.error(`ERROR FOR CREATE FILE:${err}`);
90        } else {
91          console.log('API CHECK FINISH!');
92        }
93      }
94    );
95  }
96
97  /**
98   * 将错误信息输出为excel文件
99   * @param { ApiResultInfo[] } apiCheckArr
100   */
101  static async writeExcelFile(apiCheckArr: ApiResultInfo[]): Promise<void> {
102    const workbook: Workbook = new Workbook();
103    const sheet: Worksheet = workbook.addWorksheet('Js Api', { views: [{ xSplit: 1 }] });
104    sheet.getRow(1).values = [
105      'order',
106      'errorType',
107      'fileName',
108      'apiName',
109      'apiContent',
110      'type',
111      'errorInfo',
112      'version',
113      'model',
114    ];
115    for (let i = 1; i <= apiCheckArr.length; i++) {
116      const apiData: ApiResultInfo = apiCheckArr[i - 1];
117      sheet.getRow(i + 1).values = [
118        i,
119        apiData.getErrorType(),
120        apiData.getLocation(),
121        apiData.getApiName(),
122        apiData.getApiFullText(),
123        apiData.getApiType(),
124        apiData.getMessage(),
125        apiData.getVersion(),
126        apiData.getBaseName(),
127      ];
128    }
129    workbook.xlsx.writeBuffer().then((buffer) => {
130      fs.writeFile(path.resolve(__dirname, '../coreImpl/checker/Js_Api.xlsx'), buffer, function (err) {
131        if (err) {
132          console.error(err);
133          return;
134        }
135      });
136    });
137  }
138}
139
140export class ObtainFullPath {
141  /**
142   * 获取仓库中api文件夹下的所有d.ts和d.ets路径
143   * @param { string } dir -api路径
144   * @param { string[] } utFiles -存放具体路径的数组
145   */
146  static getFullFiles(dir: string, utFiles: string[]): void {
147    try {
148      const files: string[] = fs.readdirSync(dir);
149      files.forEach((element) => {
150        const filePath: string = path.join(dir, element);
151        const status: Stats = fs.statSync(filePath);
152        if (status.isDirectory()) {
153          ObtainFullPath.getFullFiles(filePath, utFiles);
154        } else {
155          if (/\.d\.ts/.test(filePath) || /\.d\.ets/.test(filePath) || /\.ts/.test(filePath)) {
156            utFiles.push(filePath);
157          }
158        }
159      });
160    } catch (e) {
161      console.error('ETS ERROR: ' + e);
162    }
163  }
164}
165
166export class CommonFunctions {
167  /**
168   * 判断标签是否为官方标签
169   */
170  static isOfficialTag(tagName: string): boolean {
171    return tagsArrayOfOrder.indexOf(tagName) === -1;
172  }
173
174  /**
175   * Replaces the set placeholder with the target
176   * @param { string } errorInfo
177   * @param { string[] } params
178   * @returns { string }
179   */
180  static createErrorInfo(errorInfo: string, params: string[]): string {
181    params.forEach((param) => {
182      errorInfo = errorInfo.replace('$$', param);
183    });
184    return errorInfo;
185  }
186
187  /**
188   * Obtain the current version to be checked
189   * @returns { number }
190   */
191  static getCheckApiVersion(): number {
192    const packageJsonPath: string = path.join(__dirname, '../../package.json');
193    let packageJson;
194    let checkApiVersion: number = -1;
195    try {
196      const packageJsonContent: string = fs.readFileSync(packageJsonPath, 'utf8');
197      packageJson = JSON.parse(packageJsonContent);
198      checkApiVersion = JSON.parse(packageJsonContent).checkApiVersion;
199    } catch (error) {
200      throw `Failed to read package.json or parse JSON content: ${error}`;
201    }
202    if (!checkApiVersion) {
203      throw 'Please configure the correct API version to be verified';
204    }
205    return checkApiVersion;
206  }
207
208  static judgeSpecialCase(type: ts.SyntaxKind): string[] {
209    let specialCaseType: string[] = [];
210    if (type === ts.SyntaxKind.TypeLiteral) {
211      specialCaseType = ['object'];
212    } else if (type === ts.SyntaxKind.FunctionType) {
213      specialCaseType = ['function'];
214    }
215    return specialCaseType;
216  }
217}
218
219/**
220 * The order between labels
221 */
222export const tagsArrayOfOrder: string[] = [
223  'namespace', 'struct', 'extends', 'typedef', 'interface', 'permission', 'enum', 'constant', 'type', 'param', 'default',
224  'returns', 'readonly', 'throws', 'static', 'fires', 'syscap', 'systemapi', 'famodelonly', 'FAModelOnly',
225  'stagemodelonly', 'StageModelOnly', 'crossplatform', 'form', 'atomicservice', 'since', 'deprecated', 'useinstead',
226  'test', 'example'
227];
228
229/**
230 * Official label
231 */
232export const officialTagArr: string[] = [
233  'abstract', 'access', 'alias', 'async', 'augments', 'author', 'borrows', 'class', 'classdesc', 'constructs',
234  'copyright', 'event', 'exports', 'external', 'file', 'function', 'generator', 'global', 'hideconstructor', 'ignore',
235  'implements', 'inheritdoc', 'inner', 'instance', 'lends', 'license', 'listens', 'member', 'memberof', 'mixes',
236  'mixin', 'modifies', 'module', 'package', 'private', 'property', 'protected', 'public', 'requires', 'see', 'summary',
237  'this', 'todo', 'tutorial', 'variation', 'version', 'yields', 'also', 'description', 'kind', 'name', 'undocumented'
238];
239
240/**
241 * Inherit tag
242 */
243export const inheritTagArr: string[] = ['test', 'famodelonly', 'FAModelOnly', 'stagemodelonly', 'StageModelOnly',
244  'deprecated', 'systemapi'];
245
246/**
247 * Optional tag
248 */
249export const optionalTags: string[] = [
250  'static', 'fires', 'systemapi', 'famodelonly', 'FAModelOnly', 'stagemodelonly',
251  'StageModelOnly', 'crossplatform', 'deprecated', 'test', 'form', 'example', 'atomicservice'
252];
253/**
254 * conditional optional tag
255 */
256export const conditionalOptionalTags: string[] = ['type', 'default', 'readonly', 'permission', 'throws'];
257
258/**
259 * All api types that can use the permission tag.
260 */
261export const permissionOptionalTags: ts.SyntaxKind[] = [
262  ts.SyntaxKind.FunctionDeclaration,
263  ts.SyntaxKind.MethodSignature,
264  ts.SyntaxKind.MethodDeclaration,
265  ts.SyntaxKind.CallSignature,
266  ts.SyntaxKind.Constructor,
267  ts.SyntaxKind.PropertyDeclaration,
268  ts.SyntaxKind.PropertySignature,
269  ts.SyntaxKind.VariableStatement,
270];
271
272/**
273 * Each api type corresponds to a set of available tags.
274 */
275export const apiLegalityCheckTypeMap: Map<ts.SyntaxKind, string[]> = new Map([
276  [ts.SyntaxKind.CallSignature, ['param', 'returns', 'permission', 'throws', 'syscap', 'since']],
277  [ts.SyntaxKind.ClassDeclaration, ['extends', 'syscap', 'since']],
278  [ts.SyntaxKind.Constructor, ['param', 'syscap', 'permission', 'throws', 'since']],
279  [ts.SyntaxKind.EnumDeclaration, ['enum', 'syscap', 'since']],
280  [ts.SyntaxKind.FunctionDeclaration, ['param', 'returns', 'permission', 'throws', 'syscap', 'since']],
281  [ts.SyntaxKind.InterfaceDeclaration, ['interface', 'typedef', 'extends', 'syscap', 'since']],
282  [ts.SyntaxKind.MethodDeclaration, ['param', 'returns', 'permission', 'throws', 'syscap', 'since']],
283  [ts.SyntaxKind.MethodSignature, ['param', 'returns', 'permission', 'syscap', 'since']],
284  [ts.SyntaxKind.ModuleDeclaration, ['namespace', 'syscap', 'since']],
285  [ts.SyntaxKind.PropertyDeclaration, ['type', 'default', 'permission', 'throws', 'readonly', 'syscap', 'since']],
286  [ts.SyntaxKind.PropertySignature, ['type', 'default', 'permission', 'throws', 'readonly', 'syscap', 'since']],
287  [ts.SyntaxKind.VariableStatement, ['constant', 'default', 'permission', 'throws', 'syscap', 'since']],
288]);
289
290/**
291 * An array of online error messages
292 */
293export const compositiveResult: ApiResultSimpleInfo[] = [];
294
295/**
296 * An array of local error messages
297 */
298export const compositiveLocalResult: ApiResultInfo[] = [];
299
300export const punctuationMarkSet: Set<string> = new Set(['\\{', '\\}', '\\(', '\\)', '\\[', '\\]', '\\@', '\\.', '\\:',
301  '\\,', '\\;', '\\(', '\\)', '\\"', '\\/', '\\_', '\\-', '\\=', '\\?', '\\<', '\\>', '\\,', '\\!', '\\#', '\:', '\,',
302  '\\:', '\\|', '\\%', '\\+', '\\`', '\\\\', '\\\'']);
303