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