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 */ 15 16import { 17 createCompilerHost, 18 createPrinter, 19 createProgram, 20 createSourceFile, 21 ScriptTarget, 22} from 'typescript'; 23 24import type { 25 CompilerHost, 26 CompilerOptions, 27 Printer, 28 Program, 29 SourceFile, 30 TypeChecker, 31} from 'typescript'; 32 33import path from 'path'; 34import { Extension } from '../common/type'; 35import type { PathAndExtension } from '../common/type'; 36import { FileUtils } from './FileUtils'; 37 38export class TypeUtils { 39 /** 40 * performing symbol analysis on the original abstract syntax tree can cause sourcemap errors 41 * @param oldAst 42 * 43 */ 44 public static createNewSourceFile(oldAst: SourceFile): SourceFile { 45 let printer: Printer = createPrinter(); 46 let content: string = printer.printFile(oldAst); 47 48 const pathOrExtension: PathAndExtension = FileUtils.getFileSuffix(oldAst.fileName); 49 const fileSuffix = pathOrExtension.ext === Extension.DETS ? Extension.DETS : Extension.TS; 50 const { dir, name } = path.parse(oldAst.fileName); 51 const targetName: string = path.join(dir, name) + '__tmp' + fileSuffix; 52 return createSourceFile(targetName, content, ScriptTarget.ES2015, true); 53 } 54 55 public static createChecker(ast: SourceFile): TypeChecker { 56 const host: CompilerHost = createCompilerHost({}); 57 58 const customHost: CompilerHost = { 59 getSourceFile(name, languageVersion): SourceFile | undefined { 60 if (name === ast.fileName) { 61 return ast; 62 } else { 63 return host.getSourceFile(name, languageVersion); 64 } 65 }, 66 // optional 67 getDefaultLibLocation: () => '', 68 getDefaultLibFileName: () => '', 69 writeFile: (filename, data) => { 70 }, 71 getCurrentDirectory: () => '', 72 useCaseSensitiveFileNames: host.useCaseSensitiveFileNames, 73 getCanonicalFileName: host.getCanonicalFileName, 74 getNewLine: host.getNewLine, 75 fileExists: () => true, 76 readFile: (name): string => { 77 return name === ast.fileName ? ast.text : host.readFile(name); 78 }, 79 // must, read program.ts => createCompilerHost 80 directoryExists: undefined, 81 getEnvironmentVariable: undefined, 82 getDirectories: undefined, 83 }; 84 85 let option: CompilerOptions = {}; 86 if (ast.fileName.endsWith('.js')) { 87 option.allowJs = true; 88 } 89 90 let program: Program = createProgram([ast.fileName], option, customHost); 91 return program.getTypeChecker(); 92 } 93} 94