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 MagicString from 'magic-string'; 17import { createFilter } from '@rollup/pluginutils'; 18 19import { 20 NATIVE_MODULE, 21 SYSTEM_PLUGIN, 22 OHOS_PLUGIN 23} from '../../pre_define'; 24import { 25 systemModules, 26 projectConfig 27} from '../../../main'; 28import { writeUseOSFiles } from '../../utils'; 29 30const filter: any = createFilter(/(?<!\.d)\.(ets|ts|js)$/); 31 32export function apiTransform() { 33 const useOSFiles: Set<string> = new Set(); 34 return { 35 name: 'apiTransform', 36 transform(code: string, id: string) { 37 const magicString = new MagicString(code); 38 if (filter(id)) { 39 if (projectConfig.compileMode === "esmodule") { 40 code = processSystemApiAndLibso(code, id, useOSFiles); 41 } else { 42 code = processSystemApi(code, id); 43 code = processLibso(code, id, useOSFiles); 44 } 45 } 46 return { 47 code: code, 48 map: magicString.generateMap({ hires: true }) 49 }; 50 }, 51 buildEnd() { 52 if (projectConfig.isPreview && projectConfig.aceSoPath && 53 useOSFiles && useOSFiles.size > 0) { 54 writeUseOSFiles(useOSFiles); 55 } 56 } 57 }; 58} 59 60function processSystemApi(content: string, sourcePath: string): string { 61 const REG_SYSTEM: RegExp = 62 /import\s+(.+)\s+from\s+['"]@(system|ohos)\.(\S+)['"]|import\s+(.+)\s*=\s*require\(\s*['"]@(system|ohos)\.(\S+)['"]\s*\)/g; 63 return content.replace(REG_SYSTEM, (item, item1, item2, item3, item4, item5, item6) => { 64 const moduleType: string = item2 || item5; 65 const systemKey: string = item3 || item6; 66 const systemValue: string = item1 || item4; 67 const systemModule: string = `${moduleType}.${systemKey}`; 68 checkModuleExist(systemModule, sourcePath); 69 if (NATIVE_MODULE.has(systemModule)) { 70 item = `var ${systemValue} = globalThis.requireNativeModule('${moduleType}.${systemKey}')`; 71 } else if (moduleType === SYSTEM_PLUGIN || moduleType === OHOS_PLUGIN) { 72 item = `var ${systemValue} = globalThis.requireNapi('${systemKey}')`; 73 } 74 return item; 75 }); 76} 77 78function checkModuleExist(systemModule: string, sourcePath: string): void { 79 const module: string = `@${systemModule.trim()}.d.ts`; 80 if (/\.js$/.test(sourcePath) && !systemModules.includes(module)) { 81 const message: string = 82 `Cannot find module '${module}' or its corresponding type declarations.`; 83 console.error(`BUILDERROR File: ${sourcePath}\n ${message}`); 84 } 85} 86 87function processLibso(content: string, sourcePath: string, useOSFiles: Set<string>): string { 88 const REG_LIB_SO: RegExp = 89 /import\s+(.+)\s+from\s+['"]lib(\S+)\.so['"]|import\s+(.+)\s*=\s*require\(\s*['"]lib(\S+)\.so['"]\s*\)/g; 90 return content.replace(REG_LIB_SO, (_, item1, item2, item3, item4) => { 91 useOSFiles.add(sourcePath); 92 const libSoValue: string = item1 || item3; 93 const libSoKey: string = item2 || item4; 94 return projectConfig.bundleName && projectConfig.moduleName 95 ? `var ${libSoValue} = globalThis.requireNapi("${libSoKey}", true, "${projectConfig.bundleName}/${projectConfig.moduleName}");` 96 : `var ${libSoValue} = globalThis.requireNapi("${libSoKey}", true);`; 97 }); 98} 99 100// It is rare to use `import xxx = require('module')` for system module and user native library, 101// Here keep tackling with this for compatibility concern. 102function processSystemApiAndLibso(content: string, sourcePath: string, useOSFiles: Set<string>): string { 103 const REG_SYSTEM: RegExp = /import\s+(.+)\s*=\s*require\(\s*['"]@(system|ohos)\.(\S+)['"]\s*\)/g; 104 // Import libso should be recored in useOSFiles. 105 const REG_LIB_SO: RegExp = 106 /import\s+(.+)\s+from\s+['"]lib(\S+)\.so['"]|import\s+(.+)\s*=\s*require\(\s*['"]lib(\S+)\.so['"]\s*\)/g; 107 108 return content.replace(REG_SYSTEM, (_, item1, item2, item3, item4, item5, item6) => { 109 const moduleType: string = item2 || item5; 110 const systemKey: string = item3 || item6; 111 const systemValue: string = item1 || item4; 112 const systemModule: string = `${moduleType}.${systemKey}`; 113 checkModuleExist(systemModule, sourcePath); 114 return `import ${systemValue} from '@${moduleType}.${systemKey}'`; 115 }).replace(REG_LIB_SO, (_, item1, item2, item3, item4) => { 116 useOSFiles.add(sourcePath); 117 const libSoValue: string = item1 || item3; 118 const libSoKey: string = item2 || item4; 119 return `import ${libSoValue} from 'lib${libSoKey}.so'`; 120 }); 121}