1/* 2 * Copyright (c) 2021 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 16const ts = require('typescript'); 17const path = require('path'); 18const chai = require('chai'); 19const mocha = require('mocha'); 20const fs = require('fs'); 21const expect = chai.expect; 22const { 23 processUISyntax, 24 transformLog 25} = require('../lib/process_ui_syntax'); 26const { 27 validateUISyntax, 28 preprocessExtend, 29 resetComponentCollection, 30 componentCollection 31} = require('../lib/validate_ui_syntax'); 32const { 33 componentInfo, 34 readFile, 35 storedFileInfo 36} = require('../lib/utils'); 37const { 38 BUILD_ON, 39 OHOS_PLUGIN, 40 NATIVE_MODULE, 41 SYSTEM_PLUGIN 42} = require('../lib/pre_define'); 43const { 44 projectConfig, 45 resources 46} = require('../main'); 47const processStructComponentV2 = require('../lib/process_struct_componentV2'); 48const { getCompilerHost } = require('../lib/fast_build/ets_ui/rollup-plugin-ets-typescript'); 49const { processKitImport } = require('../lib/process_kit_import'); 50const { ModuleSourceFile } = require('../lib/fast_build/ark_compiler/module/module_source_file'); 51 52projectConfig.projectPath = path.resolve(process.cwd()); 53 54function processModule(compilerOptions, etsFilePath) { 55 const compilerHost = getCompilerHost(); 56 const tsProgram = ts.createProgram([etsFilePath], compilerOptions, compilerHost); 57 tsProgram.emit(tsProgram.getSourceFile(etsFilePath), undefined, undefined, undefined, 58 { 59 before: [ 60 processUISyntax(null, true), 61 processKitImport(etsFilePath, undefined, undefined, false) 62 ] 63 } 64 ); 65} 66 67function processIntermediateTS(content, filePath, afterProcess) { 68 projectConfig.processTs = true; 69 const etsCheckerCompilerOptions = require('../lib/ets_checker').compilerOptions; 70 etsCheckerCompilerOptions.lib = ["lib.es2021.d.ts"]; 71 if (content.etsAnnotationsEnable) { 72 Object.assign(etsCheckerCompilerOptions, { 73 'etsAnnotationsEnable': true 74 }); 75 } 76 const etsFilePath = filePath.replace('.ts', '.ets'); 77 fs.writeFileSync(etsFilePath, afterProcess.content); 78 processModule(etsCheckerCompilerOptions, etsFilePath); 79 sourceFile = ModuleSourceFile.getSourceFiles().find((element) => element.moduleId.includes(etsFilePath)); 80 result = generateIntermediateContent(sourceFile); 81 fs.unlinkSync(etsFilePath); 82 projectConfig.processTs = false; 83 return result; 84} 85 86function expectActual(name, filePath, checkError = false) { 87 transformLog.errors = []; 88 resources.app["media"] = {icon:16777222}; 89 resources.app["font"] = {song:16777223}; 90 process.env.rawFileResource = './'; 91 process.env.compileMode = 'moduleJson'; 92 const content = require(filePath); 93 const source = content.source; 94 process.env.compiler = BUILD_ON; 95 componentInfo.id = 0; 96 componentCollection.customComponents.clear(); 97 resetComponentCollection(); 98 storedFileInfo.setCurrentArkTsFile(); 99 const afterProcess = sourceReplace(source); 100 if (checkError) { 101 transformLog.errors.push(...validateUISyntax(source, afterProcess.content, `${name}.ets`, "?entry")); 102 } else { 103 validateUISyntax(source, afterProcess.content, `${name}.ets`); 104 } 105 const compilerOptions = ts.readConfigFile( 106 path.resolve(__dirname, '../tsconfig.json'), ts.sys.readFile).config.compilerOptions; 107 Object.assign(compilerOptions, { 108 'sourceMap': false 109 }); 110 let actualResult = ''; 111 if (content.emitIntermediateTS) { 112 actualResult = processIntermediateTS(content, filePath, afterProcess); 113 } else { 114 const result = ts.transpileModule(afterProcess.content, { 115 compilerOptions: compilerOptions, 116 fileName: `${name}.ets`, 117 transformers: { before: [processUISyntax(null, true)] } 118 }); 119 actualResult = result.outputText; 120 } 121 processStructComponentV2.default.resetStructMapInEts(); 122 expect(actualResult).eql(content.expectResult); 123} 124 125function generateIntermediateContent(sourceFile) { 126 const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed }); 127 const writer = ts.createTextWriter( 128 ts.getNewLineCharacter({ newLine: ts.NewLineKind.LineFeed, removeComments: false })); 129 printer.writeFile(sourceFile.source, writer, undefined); 130 return writer.getText(); 131} 132 133mocha.describe('compiler', () => { 134 let utPath = path.resolve(__dirname, './ut'); 135 const utFiles = []; 136 readFile(utPath, utFiles); 137 utFiles.forEach((item) => { 138 const fileName = path.basename(item, '.ts'); 139 mocha.it(fileName, () => { 140 expectActual(fileName, item); 141 }); 142 }); 143}); 144 145function sourceReplace(source) { 146 let content = source; 147 const log = []; 148 content = preprocessExtend(content); 149 content = processSystemApi(content); 150 return { 151 content: content, 152 log: log 153 }; 154} 155 156function processSystemApi(content) { 157 const REG_SYSTEM = 158 /import\s+(.+)\s+from\s+['"]@(system|ohos)\.(\S+)['"]|import\s+(.+)\s*=\s*require\(\s*['"]@(system|ohos)\.(\S+)['"]\s*\)/g; 159 const REG_LIB_SO = 160 /import\s+(.+)\s+from\s+['"]lib(\S+)\.so['"]|import\s+(.+)\s*=\s*require\(\s*['"]lib(\S+)\.so['"]\s*\)/g; 161 const newContent = content.replace(REG_LIB_SO, (_, item1, item2, item3, item4) => { 162 const libSoValue = item1 || item3; 163 const libSoKey = item2 || item4; 164 return `var ${libSoValue} = globalThis.requireNapi("${libSoKey}", true);`; 165 }).replace(REG_SYSTEM, (item, item1, item2, item3, item4, item5, item6, item7) => { 166 let moduleType = item2 || item5; 167 let systemKey = item3 || item6; 168 let systemValue = item1 || item4; 169 if (NATIVE_MODULE.has(`${moduleType}.${systemKey}`)) { 170 item = `var ${systemValue} = globalThis.requireNativeModule('${moduleType}.${systemKey}')`; 171 } else if (moduleType === SYSTEM_PLUGIN) { 172 item = `var ${systemValue} = isSystemplugin('${systemKey}', '${SYSTEM_PLUGIN}') ? ` + 173 `globalThis.systemplugin.${systemKey} : globalThis.requireNapi('${systemKey}')`; 174 } else if (moduleType === OHOS_PLUGIN) { 175 item = `var ${systemValue} = globalThis.requireNapi('${systemKey}') || ` + 176 `(isSystemplugin('${systemKey}', '${OHOS_PLUGIN}') ? ` + 177 `globalThis.ohosplugin.${systemKey} : isSystemplugin('${systemKey}', '${SYSTEM_PLUGIN}') ` + 178 `? globalThis.systemplugin.${systemKey} : undefined)`; 179 } 180 return item; 181 }); 182 return newContent; 183} 184