• 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 path from 'path';
17import ts from 'typescript';
18import fs from 'fs';
19
20import { SourceMapGenerator } from './fast_build/ark_compiler/generate_sourcemap';
21import {
22  EXTNAME_TS,
23  EXTNAME_ETS
24} from './pre_define';
25import {
26  genTemporaryPath,
27  mkdirsSync,
28  toUnixPath,
29} from './utils';
30import {
31  newSourceMaps as webpackNewSourceMaps,
32  transformModuleSpecifier,
33  writeObfuscatedSourceCode,
34} from './ark_utils';
35import { processSystemApi } from './validate_ui_syntax';
36import { isDebug } from './fast_build/ark_compiler/utils';
37import { getRelativeSourcePath } from './fast_build/ark_compiler/common/ob_config_resolver';
38import {
39  CompileEvent,
40  createAndStartEvent,
41  stopEvent,
42 } from './performance';
43
44export const SRC_MAIN: string = 'src/main';
45
46export async function writeFileSyncByNode(node: ts.SourceFile, projectConfig: Object, metaInfo: Object, moduleId?: string,
47  parentEvent?: CompileEvent, logger?: Object): Promise<void> {
48  const eventWriteFileSyncByNode = createAndStartEvent(parentEvent, 'write file sync by node');
49  const eventGenContentAndSourceMapInfo = createAndStartEvent(eventWriteFileSyncByNode, 'generate content and source map information');
50  const mixedInfo: { content: string, sourceMapJson: ts.RawSourceMap } = genContentAndSourceMapInfo(node, moduleId, projectConfig, metaInfo);
51  const sourceMapGenerator = SourceMapGenerator.getInstance();
52  stopEvent(eventGenContentAndSourceMapInfo);
53
54  /**
55   * In the following situation:
56   * A typescript source file whose name is 'Test.ts', which is used via `import xxx for 'test'` in another source file.
57
58   * The value of "node.fileName" consists of "test.ts", which does not correspond with the source file's actual name and would lead to a compilation error.
59   * The value of moduleId is same as the actual file name, so it would be used here for locating the target source file.
60
61   * Note: current realization is related to the moduleId mechanism in the rollup framework, which is needed to be reconsidered to improve the code robustness.
62   * In the current realization, when moduleId mechanism is changed, there would be a compilation error.
63   */
64  let filePath: string = moduleId ? moduleId : node.fileName;
65  let temporaryFile: string = genTemporaryPath(filePath, projectConfig.projectPath, process.env.cachePath,
66    projectConfig, metaInfo);
67  if (temporaryFile.length === 0) {
68    return;
69  }
70  if (temporaryFile.endsWith(EXTNAME_ETS)) {
71    temporaryFile = temporaryFile.replace(/\.ets$/, EXTNAME_TS);
72  }
73  let relativeFilePath = getRelativeSourcePath(filePath, projectConfig.projectRootPath, metaInfo?.belongProjectPath);
74  let sourceMaps: Object;
75  if (process.env.compileTool === 'rollup') {
76    const key = sourceMapGenerator.isNewSourceMaps() ? moduleId! : relativeFilePath;
77    sourceMapGenerator.fillSourceMapPackageInfo(moduleId!, mixedInfo.sourceMapJson);
78    sourceMapGenerator.updateSourceMap(key, mixedInfo.sourceMapJson);
79    sourceMaps = sourceMapGenerator.getSourceMaps();
80  } else {
81    webpackNewSourceMaps[relativeFilePath] = mixedInfo.sourceMapJson;
82    sourceMaps = webpackNewSourceMaps;
83  }
84  if (!isDebug(projectConfig)) {
85    const eventWriteObfuscatedSourceCode = createAndStartEvent(eventWriteFileSyncByNode, 'write obfuscated source code');
86    await writeObfuscatedSourceCode({
87        content: mixedInfo.content,
88        buildFilePath: temporaryFile,
89        relativeSourceFilePath: relativeFilePath,
90        originSourceFilePath: node.fileName,
91        rollupModuleId: moduleId ? moduleId : undefined
92      }, logger, projectConfig, sourceMaps);
93    stopEvent(eventWriteObfuscatedSourceCode);
94    return;
95  }
96  mkdirsSync(path.dirname(temporaryFile));
97  fs.writeFileSync(temporaryFile, mixedInfo.content);
98  stopEvent(eventWriteFileSyncByNode);
99}
100
101function genContentAndSourceMapInfo(node: ts.SourceFile, moduleId: string | undefined, projectConfig: Object, metaInfo: Object): Object {
102  const printer: ts.Printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
103  const options: ts.CompilerOptions = {
104    sourceMap: true
105  };
106  const mapOpions: Object = {
107    sourceMap: true,
108    inlineSourceMap: false,
109    inlineSources: false,
110    sourceRoot: '',
111    mapRoot: '',
112    extendedDiagnostics: false
113  };
114  const host: ts.CompilerHost = ts.createCompilerHost(options);
115  const fileName: string = moduleId ? moduleId : node.fileName;
116  // @ts-ignore
117  const sourceMapGenerator: ts.SourceMapGenerator = ts.createSourceMapGenerator(
118    host,
119    // @ts-ignore
120    ts.getBaseFileName(fileName),
121    '',
122    '',
123    mapOpions
124  );
125  // @ts-ignore
126  const writer: ts.EmitTextWriter = ts.createTextWriter(
127    // @ts-ignore
128    ts.getNewLineCharacter({ newLine: ts.NewLineKind.LineFeed, removeComments: false }));
129  printer.writeFile(node, writer, sourceMapGenerator);
130  const sourceMapJson: ts.RawSourceMap = sourceMapGenerator.toJSON();
131  sourceMapJson.sources = [
132    toUnixPath(fileName).startsWith(toUnixPath(projectConfig.projectRootPath)) ?
133    toUnixPath(fileName).replace(toUnixPath(projectConfig.projectRootPath) + '/', '') :
134    toUnixPath(fileName).replace(toUnixPath(metaInfo.belongProjectPath) + '/', '')
135  ];
136  let content: string = writer.getText();
137  if (process.env.compileTool !== 'rollup') {
138    content = transformModuleSpecifier(fileName, processSystemApi(content, true), projectConfig);
139  }
140
141  return {
142    content: content,
143    sourceMapJson: sourceMapJson
144  };
145}
146