1/* 2 * Copyright (c) 2023-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 */ 15 16namespace ts { 17export namespace ArkTSLinter_1_0 { 18 19export class TSCCompiledProgram { 20 private diagnosticsExtractor: TypeScriptDiagnosticsExtractor; 21 private wasStrict: boolean; 22 23 constructor(program: ArkTSProgram, reverseStrictBuilderProgram: ArkTSProgram) { 24 const strict = program.wasStrict ? program.builderProgram : reverseStrictBuilderProgram.builderProgram; 25 const nonStrict = program.wasStrict ? reverseStrictBuilderProgram.builderProgram : program.builderProgram; 26 this.diagnosticsExtractor = new TypeScriptDiagnosticsExtractor(strict, nonStrict); 27 this.wasStrict = program.wasStrict; 28 } 29 30 public getOriginalProgram(): Program { 31 return this.wasStrict 32 ? this.diagnosticsExtractor.strictProgram.getProgram() 33 : this.diagnosticsExtractor.nonStrictProgram.getProgram(); 34 } 35 36 public getStrictProgram(): Program { 37 return this.diagnosticsExtractor.strictProgram.getProgram(); 38 } 39 40 public getStrictBuilderProgram(): BuilderProgram { 41 return this.diagnosticsExtractor.strictProgram; 42 } 43 44 public getNonStrictBuilderProgram(): BuilderProgram { 45 return this.diagnosticsExtractor.nonStrictProgram; 46 } 47 48 public getStrictDiagnostics(fileName: string): Diagnostic[] { 49 return this.diagnosticsExtractor.getStrictDiagnostics(fileName); 50 } 51 52 public doAllGetDiagnostics() { 53 this.diagnosticsExtractor.doAllGetDiagnostics(); 54 } 55} 56 57class TypeScriptDiagnosticsExtractor { 58 constructor(public strictProgram: BuilderProgram, public nonStrictProgram: BuilderProgram) { 59 } 60 61 /** 62 * Returns diagnostics which appear in strict compilation mode only 63 */ 64 public getStrictDiagnostics(fileName: string): Diagnostic[] { 65 // workaround for a tsc bug 66 const strict = getAllDiagnostics(this.strictProgram, fileName).filter(diag => !(diag.length === 0 && diag.start === 0)); 67 const nonStrict = getAllDiagnostics(this.nonStrictProgram, fileName); 68 69 // collect hashes for later easier comparison 70 const nonStrictHashes = nonStrict.reduce((result, value) => { 71 const hash = hashDiagnostic(value); 72 if (hash) { 73 result.add(hash); 74 } 75 return result; 76 }, new Set<string>()); 77 // return diagnostics which weren't detected in non-strict mode 78 return strict.filter(value => { 79 const hash = hashDiagnostic(value); 80 return (hash && !nonStrictHashes.has(hash)); 81 }); 82 } 83 84 public doAllGetDiagnostics() { 85 this.strictProgram.getSemanticDiagnostics(); 86 this.strictProgram.getSyntacticDiagnostics(); 87 this.nonStrictProgram.getSemanticDiagnostics(); 88 this.nonStrictProgram.getSyntacticDiagnostics(); 89 } 90} 91 92function getAllDiagnostics(program: BuilderProgram, fileName: string): Diagnostic[] { 93 const sourceFile = program.getSourceFile(fileName); 94 return program.getSemanticDiagnostics(sourceFile) 95 .concat(program.getSyntacticDiagnostics(sourceFile)) 96 .filter(diag => diag.file === sourceFile); 97} 98 99function hashDiagnostic(diagnostic: Diagnostic): string | undefined { 100 if (diagnostic.start === undefined || diagnostic.length === undefined) { 101 return undefined; 102 } 103 return `${diagnostic.code}%${diagnostic.start}%${diagnostic.length}`; 104} 105 106} 107}