• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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}