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 expect = chai.expect; 21const { 22 processUISyntax, 23 transformLog 24} = require('../lib/process_ui_syntax'); 25const { 26 validateUISyntax, 27 preprocessExtend, 28 resetComponentCollection, 29 componentCollection 30} = require('../lib/validate_ui_syntax'); 31const { 32 componentInfo, 33 readFile, 34 storedFileInfo 35} = require('../lib/utils'); 36const { 37 BUILD_ON, 38 OHOS_PLUGIN, 39 NATIVE_MODULE, 40 SYSTEM_PLUGIN 41} = require('../lib/pre_define'); 42const { 43 partialUpdateConfig, 44 projectConfig, 45 resources 46} = require('../main'); 47const processStructComponentV2 = require('../lib/process_struct_componentV2'); 48 49projectConfig.projectPath = path.resolve(process.cwd()); 50 51function expectActual(name, filePath, checkError = false) { 52 transformLog.errors = []; 53 resources.app["media"] = {icon:16777222}; 54 resources.app["font"] = {song:16777223}; 55 process.env.rawFileResource = './'; 56 process.env.compileMode = 'moduleJson'; 57 const content = require(filePath); 58 const source = content.source; 59 process.env.compiler = BUILD_ON; 60 componentInfo.id = 0; 61 componentCollection.customComponents.clear(); 62 resetComponentCollection(); 63 storedFileInfo.setCurrentArkTsFile(); 64 const afterProcess = sourceReplace(source); 65 if (checkError) { 66 transformLog.errors.push(...validateUISyntax(source, afterProcess.content, `${name}.ets`, "?entry")); 67 } else { 68 validateUISyntax(source, afterProcess.content, `${name}.ets`); 69 } 70 const compilerOptions = ts.readConfigFile( 71 path.resolve(__dirname, '../tsconfig.json'), ts.sys.readFile).config.compilerOptions; 72 Object.assign(compilerOptions, { 73 'sourceMap': false 74 }); 75 const result = ts.transpileModule(afterProcess.content, { 76 compilerOptions: compilerOptions, 77 fileName: `${name}.ets`, 78 transformers: { before: [processUISyntax(null, true)] } 79 }); 80 processStructComponentV2.default.resetStructMapInEts(); 81 if (checkError) { 82 assertError(name); 83 } else { 84 expect(result.outputText).eql(content.expectResult); 85 } 86} 87 88mocha.describe('compiler', () => { 89 let utPath = path.resolve(__dirname, './ut'); 90 if (process.argv.includes('--partialUpdate')) { 91 partialUpdateConfig.partialUpdateMode = true; 92 utPath = path.resolve(__dirname, './utForPartialUpdate'); 93 } else if (process.argv.includes('--assertError')) { 94 partialUpdateConfig.partialUpdateMode = true; 95 utPath = path.resolve(__dirname, './utForValidate'); 96 } 97 const utFiles = []; 98 readFile(utPath, utFiles); 99 utFiles.forEach((item) => { 100 const fileName = path.basename(item, '.ts'); 101 mocha.it(fileName, () => { 102 if (process.argv.includes('--assertError')) { 103 expectActual(fileName, item, true); 104 } else { 105 expectActual(fileName, item); 106 } 107 }); 108 }); 109}); 110 111function sourceReplace(source) { 112 let content = source; 113 const log = []; 114 content = preprocessExtend(content); 115 content = processSystemApi(content); 116 return { 117 content: content, 118 log: log 119 }; 120} 121 122function processSystemApi(content) { 123 const REG_SYSTEM = 124 /import\s+(.+)\s+from\s+['"]@(system|ohos)\.(\S+)['"]|import\s+(.+)\s*=\s*require\(\s*['"]@(system|ohos)\.(\S+)['"]\s*\)/g; 125 const REG_LIB_SO = 126 /import\s+(.+)\s+from\s+['"]lib(\S+)\.so['"]|import\s+(.+)\s*=\s*require\(\s*['"]lib(\S+)\.so['"]\s*\)/g; 127 const newContent = content.replace(REG_LIB_SO, (_, item1, item2, item3, item4) => { 128 const libSoValue = item1 || item3; 129 const libSoKey = item2 || item4; 130 return `var ${libSoValue} = globalThis.requireNapi("${libSoKey}", true);`; 131 }).replace(REG_SYSTEM, (item, item1, item2, item3, item4, item5, item6, item7) => { 132 let moduleType = item2 || item5; 133 let systemKey = item3 || item6; 134 let systemValue = item1 || item4; 135 if (NATIVE_MODULE.has(`${moduleType}.${systemKey}`)) { 136 item = `var ${systemValue} = globalThis.requireNativeModule('${moduleType}.${systemKey}')`; 137 } else if (moduleType === SYSTEM_PLUGIN) { 138 item = `var ${systemValue} = isSystemplugin('${systemKey}', '${SYSTEM_PLUGIN}') ? ` + 139 `globalThis.systemplugin.${systemKey} : globalThis.requireNapi('${systemKey}')`; 140 } else if (moduleType === OHOS_PLUGIN) { 141 item = `var ${systemValue} = globalThis.requireNapi('${systemKey}') || ` + 142 `(isSystemplugin('${systemKey}', '${OHOS_PLUGIN}') ? ` + 143 `globalThis.ohosplugin.${systemKey} : isSystemplugin('${systemKey}', '${SYSTEM_PLUGIN}') ` + 144 `? globalThis.systemplugin.${systemKey} : undefined)`; 145 } 146 return item; 147 }); 148 return newContent; 149} 150 151function replaceFunctions(message) { 152 const regex = /\${(.*?)}/g; 153 return message.replace(regex, (match, p1) => { 154 return eval(p1); 155 }); 156} 157 158function validateError(logmsg, logtype, message, type) { 159 expect(logmsg).to.be.equal(message); 160 expect(logtype).to.be.equal(type); 161} 162 163function assertError(fileName) { 164 const errorJson = require('./error.json'); 165 const errorInfo = errorJson[fileName]; 166 if (errorInfo) { 167 if (Array.isArray(errorInfo)) { 168 errorInfo.forEach((item, index) => { 169 validateError(transformLog.errors[index].message, transformLog.errors[index].type, replaceFunctions(item.message), item.type); 170 }); 171 } else { 172 validateError(transformLog.errors[0].message, transformLog.errors[0].type, replaceFunctions(errorInfo.message), errorInfo.type); 173 } 174 } 175} 176