• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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