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 fs from 'fs'; 16import path from 'path'; 17import ts from 'typescript'; 18import { Check } from './api_check_plugin'; 19import { AddErrorLogs } from './compile_info'; 20import { 21 ApiResultSimpleInfo, 22 ErrorType, 23 ErrorID, 24 LogType, 25 ErrorLevel, 26 ApiResultInfo, 27} from '../../../typedef/checker/result_type'; 28import { StringConstant } from '../../../utils/Constant'; 29import { CompolerOptions, ObtainFullPath } from '../../../utils/checkUtils'; 30import { compositiveResult, compositiveLocalResult } from '../../../utils/checkUtils'; 31 32export class TsSyntaxCheck { 33 /** 34 * ts语法检查工具入口 35 * @param { string } url -File path for storing critical information. 36 */ 37 static checkAPISyntax(url: string): ApiResultSimpleInfo[] { 38 const tsResult: ApiResultSimpleInfo[] = []; 39 const tsLocalResult: ApiResultInfo[] = []; 40 if (fs.existsSync(url)) { 41 const fullFilesPath: string[] = []; 42 ObtainFullPath.getFullFiles(path.resolve(__dirname, '../../../../../../api'), fullFilesPath); 43 const files: Array<string> = Check.getMdFiles(url); 44 const program: ts.Program = ts.createProgram({ 45 rootNames: fullFilesPath, 46 options: CompolerOptions.getCompolerOptions(), 47 }); 48 //ts存在bug,仅为解决无法绑定sourcefile根节点的问题 49 program.getTypeChecker(); 50 const programSourceFiles: readonly ts.SourceFile[] = program.getSourceFiles(); 51 const host: ts.CompilerHost = ts.createCompilerHost(CompolerOptions.getCompolerOptions()); 52 const diagnostics: ts.Diagnostic[] = ts.runArkTSLinter(program, host); 53 files.forEach((filePath: string, index: number) => { 54 TsSyntaxCheck.checkAPISyntaxCallback( 55 filePath, 56 program, 57 diagnostics, 58 programSourceFiles, 59 compositiveResult, 60 compositiveLocalResult 61 ); 62 console.log(`api check scaning file in no ${++index}!`); 63 }); 64 } 65 return tsResult; 66 } 67 /** 68 * ts检查主要处理过程 69 * @param { string } fileName 70 * @param { ts.Program } program 71 * @param { ts.Diagnostic[] } diagnostics 72 * @param { readonly ts.SourceFile[] } programSourceFiles 73 * @param { ApiResultSimpleInfo[] } tsResult 74 * @param { ApiResultInfo[] } checkErrorAllInfos 75 */ 76 static checkAPISyntaxCallback( 77 fileName: string, 78 program: ts.Program, 79 diagnostics: ts.Diagnostic[], 80 programSourceFiles: readonly ts.SourceFile[], 81 tsResult: ApiResultSimpleInfo[], 82 checkErrorAllInfos: ApiResultInfo[] 83 ): void { 84 const fileContent: string = fs.readFileSync(fileName, StringConstant.UTF8); 85 const node: ts.Node = ts.createSourceFile(fileName, fileContent, ts.ScriptTarget.ES2017, true); 86 const fileSuffix: string = fileName.substring(fileName.lastIndexOf('.'), fileName.length); 87 // tsc诊断日志 88 if (fileSuffix === '.ts') { 89 const targetSourceFile: ts.SourceFile = node.getSourceFile(); 90 programSourceFiles.forEach((programSourceFile) => { 91 if (programSourceFile.fileName === targetSourceFile.fileName) { 92 const result: readonly ts.Diagnostic[] = program.getSemanticDiagnostics(programSourceFile); 93 result.forEach((item) => { 94 const filePath: string = item.file?.fileName as string; 95 const fileName: string = filePath.substring(filePath.indexOf('api'), filePath.length); 96 AddErrorLogs.addAPICheckErrorLogs( 97 ErrorID.TS_SYNTAX_ERROR_ID, 98 ErrorLevel.MIDDLE, 99 fileName, 100 ts.getLineAndCharacterOfPosition(node.getSourceFile(), item.start as number), 101 ErrorType.TS_SYNTAX_ERROR, 102 LogType.LOG_API, 103 -1, 104 'NA', 105 'NA', 106 item.messageText as string, 107 tsResult, 108 checkErrorAllInfos 109 ); 110 }); 111 } 112 }); 113 } 114 // ArkTS诊断日志 115 if (fileSuffix === '.ets') { 116 diagnostics.forEach((item) => { 117 if (path.normalize(item.file?.fileName as string) === path.normalize(fileName)) { 118 const filePath: string = item.file?.fileName as string; 119 const fileName: string = filePath.substring(filePath.indexOf('api'), filePath.length); 120 AddErrorLogs.addAPICheckErrorLogs( 121 ErrorID.TS_SYNTAX_ERROR_ID, 122 ErrorLevel.MIDDLE, 123 fileName, 124 ts.getLineAndCharacterOfPosition(node.getSourceFile(), item.start as number), 125 ErrorType.TS_SYNTAX_ERROR, 126 LogType.LOG_API, 127 -1, 128 'NA', 129 'NA', 130 item.messageText as string, 131 tsResult, 132 checkErrorAllInfos 133 ); 134 } 135 }); 136 } 137 } 138} 139