mirror of
https://gitee.com/openharmony/interface_sdk-js
synced 2024-11-23 07:10:52 +00:00
ts语法检查工具
Signed-off-by: fanjiaojiao0729 <fanjiaojiao@huawei.com>
This commit is contained in:
parent
f853ff6b5b
commit
212d803f6f
@ -15,8 +15,10 @@
|
||||
import path from 'path';
|
||||
import { ApiResultSimpleInfo } from '../../typedef/checker/result_type';
|
||||
import { Check } from './src/api_check_plugin';
|
||||
import { TsSyntaxCheck } from './src/ts_check_plugin';
|
||||
import { FileUtils } from '../../utils/FileUtils';
|
||||
import { LogUtil } from '../../utils/logUtil';
|
||||
import { GenerateFile } from '../../utils/checkUtils';
|
||||
|
||||
/**
|
||||
* local entrance
|
||||
@ -26,10 +28,12 @@ export class LocalEntry {
|
||||
const mdFilesPath = path.resolve(FileUtils.getBaseDirName(), '../mdFiles.txt');
|
||||
let result: ApiResultSimpleInfo[] = [];
|
||||
try {
|
||||
result = Check.scanEntry(mdFilesPath);
|
||||
result = TsSyntaxCheck.checkAPISyntax(mdFilesPath);
|
||||
result.concat(Check.scanEntry(mdFilesPath));
|
||||
} catch (error) {
|
||||
LogUtil.e('API_CHECK_ERROR', error);
|
||||
} finally {
|
||||
GenerateFile.writeFile(result, '../result.txt', {});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -28,11 +28,11 @@ export class AddErrorLogs {
|
||||
* @param { string } apiName -error message api name
|
||||
* @param { string } apiFullText -error message api text
|
||||
* @param { string } message -error infomation
|
||||
* @param { ApiResultSimpleInfo[] } checkErrorArr -array for storing error information
|
||||
* @param { ApiResultSimpleInfo[] } checkErrorInfos -array for storing error information
|
||||
*/
|
||||
static addAPICheckErrorLogs(id: number, level: number, filePath: string, location: string, errorType: string,
|
||||
apiType: string, version: number, apiName: string, apiFullText: string,
|
||||
message: string, checkErrorArr: ApiResultSimpleInfo[]): void {
|
||||
message: string, checkErrorInfos: ApiResultSimpleInfo[], checkErrorAllInfos: ApiResultInfo[]): void {
|
||||
const apiChecktSimpleErrorLog: ApiResultSimpleInfo = new ApiResultSimpleInfo();
|
||||
apiChecktSimpleErrorLog
|
||||
.setID(id)
|
||||
@ -50,8 +50,10 @@ export class AddErrorLogs {
|
||||
.setVersion(version)
|
||||
.setLevel(level)
|
||||
.setApiName(apiName)
|
||||
.setApiFullText(apiFullText);
|
||||
|
||||
checkErrorArr.push(apiChecktSimpleErrorLog);
|
||||
.setApiFullText(apiFullText)
|
||||
.setBaseName(filePath.substring(filePath.lastIndexOf('/') + 1, filePath.length));
|
||||
checkErrorInfos.push(apiChecktSimpleErrorLog);
|
||||
checkErrorAllInfos.push(apiCheckErrorLog);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import ts from 'typescript';
|
||||
import { Check } from './api_check_plugin';
|
||||
import { AddErrorLogs } from './compile_info';
|
||||
import { ApiResultSimpleInfo, ErrorType, ErrorID, LogType, ErrorLevel, ApiResultInfo } from
|
||||
'../../../typedef/checker/result_type';
|
||||
import { StringConstant } from '../../../utils/Constant';
|
||||
import { PosOfNode, CompolerOptions, ObtainFullPath, GenerateFile } from '../../../utils/checkUtils';
|
||||
|
||||
export class TsSyntaxCheck {
|
||||
/**
|
||||
* ts语法检查工具入口
|
||||
* @param { string } url -File path for storing critical information.
|
||||
*/
|
||||
static checkAPISyntax(url: string): ApiResultSimpleInfo[] {
|
||||
const tsResult: ApiResultSimpleInfo[] = [];
|
||||
const tsLocalResult: ApiResultInfo[] = [];
|
||||
if (fs.existsSync(url)) {
|
||||
const fullFilesPath: string[] = [];
|
||||
ObtainFullPath.getFullFiles(path.resolve(__dirname, '../../../../../../api'), fullFilesPath);
|
||||
const files: Array<string> = Check.getMdFiles(url);
|
||||
const program: ts.Program = ts.createProgram({
|
||||
rootNames: fullFilesPath,
|
||||
options: CompolerOptions.getCompolerOptions()
|
||||
});
|
||||
//ts存在bug,仅为解决无法绑定sourcefile根节点的问题
|
||||
program.getTypeChecker();
|
||||
const programSourceFiles: readonly ts.SourceFile[] = program.getSourceFiles();
|
||||
const host: ts.CompilerHost = ts.createCompilerHost(CompolerOptions.getCompolerOptions());
|
||||
const diagnostics: ts.Diagnostic[] = ts.runArkTSLinter(program, host);
|
||||
files.forEach((filePath: string, index: number) => {
|
||||
TsSyntaxCheck.checkAPISyntaxCallback(filePath, program, diagnostics, programSourceFiles, tsResult, tsLocalResult);
|
||||
console.log(`scaning file in no ${++index}!`);
|
||||
});
|
||||
}
|
||||
GenerateFile.writeExcelFile(tsLocalResult);
|
||||
return tsResult;
|
||||
}
|
||||
/**
|
||||
* ts检查主要处理过程
|
||||
* @param { string } fileName
|
||||
* @param { ts.Program } program
|
||||
* @param { ts.Diagnostic[] } diagnostics
|
||||
* @param { readonly ts.SourceFile[] } programSourceFiles
|
||||
* @param { ApiResultSimpleInfo[] } tsResult
|
||||
* @param { ApiResultInfo[] } checkErrorAllInfos
|
||||
*/
|
||||
static checkAPISyntaxCallback(fileName: string, program: ts.Program, diagnostics: ts.Diagnostic[],
|
||||
programSourceFiles: readonly ts.SourceFile[], tsResult: ApiResultSimpleInfo[],
|
||||
checkErrorAllInfos: ApiResultInfo[]): void {
|
||||
const fileContent: string = fs.readFileSync(fileName, StringConstant.UTF8);
|
||||
const node: ts.Node = ts.createSourceFile(fileName, fileContent, ts.ScriptTarget.ES2017, true);
|
||||
const fileSuffix: string = fileName.substring(fileName.lastIndexOf('.'), fileName.length);
|
||||
// tsc诊断日志
|
||||
if (fileSuffix === '.ts') {
|
||||
const targetSourceFile: ts.SourceFile = node.getSourceFile();
|
||||
programSourceFiles.forEach(programSourceFile => {
|
||||
if (programSourceFile.fileName === targetSourceFile.fileName) {
|
||||
const result: readonly ts.Diagnostic[] = program.getSemanticDiagnostics(programSourceFile);
|
||||
result.forEach(item => {
|
||||
AddErrorLogs.addAPICheckErrorLogs(ErrorID.TS_SYNTAX_ERROR_ID, ErrorLevel.MIDDLE,
|
||||
item.file?.fileName as string, PosOfNode.getPosOfNode(node, item),
|
||||
ErrorType.TS_SYNTAX_ERROR, LogType.LOG_API, -1, 'NA', 'NA', item.messageText as string, tsResult,
|
||||
checkErrorAllInfos);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
// ArkTS诊断日志
|
||||
if (fileSuffix === '.ets') {
|
||||
diagnostics.forEach(item => {
|
||||
if (path.normalize(item.file?.fileName as string) === path.normalize(fileName)) {
|
||||
AddErrorLogs.addAPICheckErrorLogs(ErrorID.TS_SYNTAX_ERROR_ID, ErrorLevel.MIDDLE,
|
||||
item.file?.fileName as string, PosOfNode.getPosOfNode(node, item),
|
||||
ErrorType.TS_SYNTAX_ERROR, LogType.LOG_API, -1, 'NA', 'NA', item.messageText as string, tsResult,
|
||||
checkErrorAllInfos);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -47,7 +47,8 @@ export enum ErrorType {
|
||||
PARAMETER_ERRORS = 'wrong parameter',
|
||||
API_PAIR_ERRORS = 'limited api pair errors',
|
||||
ILLEGAL_ANY = 'illegal any',
|
||||
API_CHANGE_ERRORS = 'api change errors'
|
||||
API_CHANGE_ERRORS = 'api change errors',
|
||||
TS_SYNTAX_ERROR = 'TS syntax error'
|
||||
}
|
||||
|
||||
/**
|
||||
@ -67,7 +68,8 @@ export enum ErrorID {
|
||||
PARAMETER_ERRORS_ID = 9,
|
||||
API_PAIR_ERRORS_ID = 10,
|
||||
ILLEGAL_ANY_ID = 11,
|
||||
API_CHANGE_ERRORS_ID = 12
|
||||
API_CHANGE_ERRORS_ID = 12,
|
||||
TS_SYNTAX_ERROR_ID = 13
|
||||
}
|
||||
|
||||
/**
|
||||
@ -211,6 +213,7 @@ export class ApiResultInfo {
|
||||
level: number = -1;
|
||||
apiName: string = '';
|
||||
apiFullText: string = '';
|
||||
baseName: string = '';
|
||||
|
||||
setErrorType(errorType: string): ApiResultInfo {
|
||||
this.errorType = errorType;
|
||||
@ -282,4 +285,12 @@ export class ApiResultInfo {
|
||||
getApiFullText(): string {
|
||||
return this.apiFullText;
|
||||
}
|
||||
setBaseName(baseName: string): ApiResultInfo {
|
||||
this.baseName = baseName;
|
||||
return this;
|
||||
}
|
||||
|
||||
getBaseName(): string {
|
||||
return this.baseName;
|
||||
}
|
||||
}
|
135
build-tools/dts_parser/src/utils/checkUtils.ts
Normal file
135
build-tools/dts_parser/src/utils/checkUtils.ts
Normal file
@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import path from 'path';
|
||||
import fs, { Stats } from 'fs';
|
||||
import { Workbook, Worksheet } from 'exceljs';
|
||||
import ts, { LineAndCharacter } from 'typescript';
|
||||
import { ApiResultSimpleInfo, ApiResultInfo } from '../typedef/checker/result_type';
|
||||
|
||||
export class PosOfNode {
|
||||
/**
|
||||
* 获取行列信息
|
||||
* @param { ts.Node } node
|
||||
* @param { ts.Diagnostic } diagnostic
|
||||
*/
|
||||
static getPosOfNode(node: ts.Node, diagnostic: ts.Diagnostic): string {
|
||||
const posOfNode: LineAndCharacter = ts.getLineAndCharacterOfPosition(node.getSourceFile(),
|
||||
diagnostic.start as number);
|
||||
const location: string = diagnostic.file?.fileName as string +
|
||||
`(line: ${posOfNode.line + 1}, col: ${posOfNode.character + 1})`;
|
||||
return location;
|
||||
}
|
||||
}
|
||||
export class CompolerOptions {
|
||||
/**
|
||||
* tsconfig配置项设置
|
||||
*/
|
||||
static getCompolerOptions(): ts.CompilerOptions {
|
||||
const compilerOptions: ts.CompilerOptions = ts.readConfigFile(path.resolve(__dirname, '../../tsconfig.json'),
|
||||
ts.sys.readFile).config.compilerOptions;
|
||||
Object.assign(compilerOptions, {
|
||||
target: 'es2020',
|
||||
jsx: 'preserve',
|
||||
incremental: undefined,
|
||||
declaration: undefined,
|
||||
declarationMap: undefined,
|
||||
emitDeclarationOnly: undefined,
|
||||
outFile: undefined,
|
||||
composite: undefined,
|
||||
tsBuildInfoFile: undefined,
|
||||
noEmit: undefined,
|
||||
isolatedModules: true,
|
||||
paths: undefined,
|
||||
rootDirs: undefined,
|
||||
types: undefined,
|
||||
out: undefined,
|
||||
noLib: undefined,
|
||||
noResolve: true,
|
||||
noEmitOnError: undefined,
|
||||
declarationDir: undefined,
|
||||
suppressOutputPathCheck: true,
|
||||
allowNonTsExtensions: true
|
||||
});
|
||||
return compilerOptions;
|
||||
}
|
||||
}
|
||||
|
||||
export class GenerateFile {
|
||||
/**
|
||||
* 将错误信息输出为txt文件
|
||||
* @param { ApiResultSimpleInfo[] } resultData
|
||||
* @param { string } outputPath
|
||||
* @param { string } option
|
||||
*/
|
||||
static writeFile(resultData: ApiResultSimpleInfo[], outputPath: string, option: object): void {
|
||||
const STANDARD_INDENT: number = 2;
|
||||
fs.writeFile(path.resolve(__dirname, outputPath), JSON.stringify(resultData, null, STANDARD_INDENT), option, (err) => {
|
||||
if (err) {
|
||||
console.error(`ERROR FOR CREATE FILE:${err}`);
|
||||
} else {
|
||||
console.log('API CHECK FINISH!');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 将错误信息输出为excel文件
|
||||
* @param { ApiResultInfo[] } apiCheckArr
|
||||
*/
|
||||
static async writeExcelFile(apiCheckArr: ApiResultInfo[]): Promise<void> {
|
||||
const workbook: Workbook = new Workbook();
|
||||
const sheet: Worksheet = workbook.addWorksheet('Js Api', { views: [{ xSplit: 1 }] });
|
||||
sheet.getRow(1).values = ['order', 'errorType', 'fileName', 'apiName', 'apiContent', 'type', 'errorInfo', 'version', 'model'];
|
||||
for (let i = 1; i <= apiCheckArr.length; i++) {
|
||||
const apiData: ApiResultInfo = apiCheckArr[i - 1];
|
||||
sheet.getRow(i + 1).values = [i, apiData.getErrorType(), apiData.getLocation(), apiData.getApiName(),
|
||||
apiData.getApiFullText(), apiData.getApiType(), apiData.getMessage(), apiData.getVersion(), apiData.getBaseName()];
|
||||
}
|
||||
workbook.xlsx.writeBuffer().then((buffer) => {
|
||||
fs.writeFile(path.resolve(__dirname, '../coreImpl/checker/Js_Api.xlsx'), buffer, function (err) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
return;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class ObtainFullPath {
|
||||
/**
|
||||
* 获取仓库中api文件夹下的所有d.ts和d.ets路径
|
||||
* @param { string } dir -api路径
|
||||
* @param { string[] } utFiles -存放具体路径的数组
|
||||
*/
|
||||
static getFullFiles(dir: string, utFiles: string[]): void {
|
||||
try {
|
||||
const files: string[] = fs.readdirSync(dir);
|
||||
files.forEach((element) => {
|
||||
const filePath: string = path.join(dir, element);
|
||||
const status: Stats = fs.statSync(filePath);
|
||||
if (status.isDirectory()) {
|
||||
ObtainFullPath.getFullFiles(filePath, utFiles);
|
||||
} else {
|
||||
if (/\.d\.ts/.test(filePath) || /\.d\.ets/.test(filePath)) {
|
||||
utFiles.push(filePath);
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('ETS ERROR: ' + e);
|
||||
}
|
||||
}
|
||||
}
|
@ -12,7 +12,7 @@
|
||||
|
||||
/* Language and Environment */
|
||||
"target": "es2020", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
|
||||
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
||||
"lib": ["es2015","es2020"], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
||||
// "jsx": "preserve", /* Specify what JSX code is generated. */
|
||||
"experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
|
||||
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
|
||||
@ -96,6 +96,6 @@
|
||||
|
||||
/* Completeness */
|
||||
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
||||
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
||||
// "skipLibCheck": true /* Skip type checking all .d.ts files. */
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user