1/* 2 * Copyright (c) 2022-2025 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 * as arkts from '@koalaui/libarkts'; 17import { ComponentTransformer } from './component-transformer'; 18import { PreprocessorTransformer } from './preprocessor-transform'; 19import { CheckedTransformer } from './checked-transformer'; 20import { Plugins, PluginContext, ProjectConfig } from '../common/plugin-context'; 21import { ProgramVisitor } from '../common/program-visitor'; 22import { EXTERNAL_SOURCE_PREFIX_NAMES } from '../common/predefines'; 23import { debugDump, debugLog, getDumpFileName } from '../common/debug'; 24 25export function uiTransform(): Plugins { 26 return { 27 name: 'ui-plugin', 28 parsed: parsedTransform, 29 checked: checkedTransform, 30 clean() { 31 arkts.arktsGlobal.clearContext(); 32 }, 33 }; 34} 35 36function parsedTransform(this: PluginContext): arkts.EtsScript | undefined { 37 let script: arkts.EtsScript | undefined; 38 console.log('[UI PLUGIN] AFTER PARSED ENTER'); 39 const contextPtr = arkts.arktsGlobal.compilerContext?.peer ?? this.getContextPtr(); 40 if (!!contextPtr) { 41 let program = arkts.getOrUpdateGlobalContext(contextPtr).program; 42 script = program.astNode; 43 const cachePath: string | undefined = this.getProjectConfig()?.cachePath; 44 debugLog('[BEFORE PARSED SCRIPT] script: ', script.dumpSrc()); 45 debugDump( 46 script.dumpSrc(), 47 getDumpFileName(0, 'SRC', 1, 'UI_AfterParse_Begin'), 48 true, 49 cachePath, 50 program.programFileNameWithExtension 51 ); 52 arkts.Performance.getInstance().createEvent('ui-parsed'); 53 program = parsedProgramVisit(program, this); 54 script = program.astNode; 55 arkts.Performance.getInstance().stopEvent('ui-parsed', true); 56 debugLog('[AFTER PARSED SCRIPT] script: ', script.dumpSrc()); 57 debugDump( 58 script.dumpSrc(), 59 getDumpFileName(0, 'SRC', 2, 'UI_AfterParse_End'), 60 true, 61 cachePath, 62 program.programFileNameWithExtension 63 ); 64 this.setArkTSAst(script); 65 console.log('[UI PLUGIN] AFTER PARSED EXIT'); 66 return script; 67 } 68 console.log('[UI PLUGIN] AFTER PARSED EXIT WITH NO TRANSFORM'); 69 return script; 70} 71 72function parsedProgramVisit( 73 program: arkts.Program, 74 context: PluginContext, 75 canSkipPhases: boolean = false 76): arkts.Program { 77 if (canSkipPhases) { 78 debugLog('[SKIP PHASE] phase: ui-parsed, moduleName: ', program.moduleName); 79 } else { 80 debugLog('[CANT SKIP PHASE] phase: ui-parsed, moduleName: ', program.moduleName); 81 const componentTransformer = new ComponentTransformer(); 82 const preprocessorTransformer = new PreprocessorTransformer(); 83 const programVisitor = new ProgramVisitor({ 84 pluginName: uiTransform.name, 85 state: arkts.Es2pandaContextState.ES2PANDA_STATE_PARSED, 86 visitors: [componentTransformer, preprocessorTransformer], 87 skipPrefixNames: EXTERNAL_SOURCE_PREFIX_NAMES, 88 pluginContext: context, 89 }); 90 program = programVisitor.programVisitor(program); 91 } 92 return program; 93} 94 95function checkedTransform(this: PluginContext): arkts.EtsScript | undefined { 96 let script: arkts.EtsScript | undefined; 97 console.log('[UI PLUGIN] AFTER CHECKED ENTER'); 98 const contextPtr = arkts.arktsGlobal.compilerContext?.peer ?? this.getContextPtr(); 99 if (!!contextPtr) { 100 let program = arkts.getOrUpdateGlobalContext(contextPtr).program; 101 script = program.astNode; 102 const cachePath: string | undefined = this.getProjectConfig()?.cachePath; 103 debugLog('[BEFORE STRUCT SCRIPT] script: ', script.dumpSrc()); 104 debugDump( 105 script.dumpSrc(), 106 getDumpFileName(0, 'SRC', 3, 'UI_AfterCheck_Begin'), 107 true, 108 cachePath, 109 program.programFileNameWithExtension 110 ); 111 arkts.Performance.getInstance().createEvent('ui-checked'); 112 program = checkedProgramVisit(program, this); 113 script = program.astNode; 114 arkts.Performance.getInstance().stopEvent('ui-checked', true); 115 debugLog('[AFTER STRUCT SCRIPT] script: ', script.dumpSrc()); 116 debugDump( 117 script.dumpSrc(), 118 getDumpFileName(0, 'SRC', 4, 'UI_AfterCheck_End'), 119 true, 120 cachePath, 121 program.programFileNameWithExtension 122 ); 123 arkts.GlobalInfo.getInfoInstance().reset(); 124 arkts.Performance.getInstance().createEvent('ui-recheck'); 125 arkts.recheckSubtree(script); 126 arkts.Performance.getInstance().stopEvent('ui-recheck', true); 127 arkts.Performance.getInstance().clearAllEvents(); 128 this.setArkTSAst(script); 129 console.log('[UI PLUGIN] AFTER CHECKED EXIT'); 130 return script; 131 } 132 console.log('[UI PLUGIN] AFTER CHECKED EXIT WITH NO TRANSFORM'); 133 return script; 134} 135 136function checkedProgramVisit( 137 program: arkts.Program, 138 context: PluginContext, 139 canSkipPhases: boolean = false 140): arkts.Program { 141 if (canSkipPhases) { 142 debugLog('[SKIP PHASE] phase: ui-checked, moduleName: ', program.moduleName); 143 } else { 144 debugLog('[CANT SKIP PHASE] phase: ui-checked, moduleName: ', program.moduleName); 145 const projectConfig: ProjectConfig | undefined = context.getProjectConfig(); 146 const checkedTransformer = new CheckedTransformer(projectConfig); 147 const programVisitor = new ProgramVisitor({ 148 pluginName: uiTransform.name, 149 state: arkts.Es2pandaContextState.ES2PANDA_STATE_CHECKED, 150 visitors: [checkedTransformer], 151 skipPrefixNames: EXTERNAL_SOURCE_PREFIX_NAMES, 152 pluginContext: context, 153 }); 154 program = programVisitor.programVisitor(program); 155 } 156 return program; 157}