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