• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 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 { KNativePointer } from './InteropTypes';
17import { BuildConfig } from './types';
18
19export enum PluginHook {
20  NEW = 'afterNew',
21  PARSED = 'parsed',
22  SCOPE_INITED = 'scopeInited',
23  CHECKED = 'checked',
24  LOWERED = 'lowered',
25  ASM_GENERATED = 'asmGenerated',
26  BIN_GENERATED = 'binGenerated',
27  CLEAN = 'clean'
28}
29
30type PluginHandlerFunction = () => void;
31
32type PluginHandlerObject = {
33  order: 'pre' | 'post' | undefined;
34  handler: PluginHandlerFunction;
35};
36
37type PluginHandler = PluginHandlerFunction | PluginHandlerObject;
38
39interface Plugins {
40  name: string;
41  afterNew?: PluginHandler;
42  parsed?: PluginHandler;
43  scopeInited?: PluginHandler;
44  checked?: PluginHandler;
45  lowered?: PluginHandler;
46  asmGenerated?: PluginHandler;
47  binGenerated?: PluginHandler;
48  clean?: PluginHandler;
49}
50
51type PluginExecutor = {
52  name: string;
53  handler: PluginHandler;
54};
55
56type PluginInitFunction = () => Plugins;
57
58type RawPlugins = {
59  name: string;
60  init: PluginInitFunction | undefined;
61};
62
63class PluginContext {
64  private ast: object | undefined;
65  private program: object | undefined;
66  private projectConfig: object | undefined;
67  private contextPtr: KNativePointer | undefined;
68
69  constructor() {
70    this.ast = undefined;
71    this.program = undefined;
72    this.projectConfig = undefined;
73    this.contextPtr = undefined;
74  }
75
76  public setArkTSAst(ast: object): void {
77    this.ast = ast;
78  }
79
80  public getArkTSAst(): object | undefined {
81    return this.ast;
82  }
83
84  public setArkTSProgram(program: object): void {
85    this.program = program;
86  }
87
88  public getArkTSProgram(): object | undefined {
89    return this.program;
90  }
91
92  public setProjectConfig(projectConfig: object): void {
93    this.projectConfig = projectConfig;
94  }
95
96  public getProjectConfig(): object | undefined {
97    return this.projectConfig;
98  }
99
100  public setContextPtr(ptr: KNativePointer): void {
101    this.contextPtr = ptr;
102  }
103
104  public getContextPtr(): KNativePointer | undefined {
105    return this.contextPtr;
106  }
107}
108
109export class PluginDriver {
110  private static instance: PluginDriver | undefined;
111  private sortedPlugins: Map<PluginHook, PluginExecutor[] | undefined>;
112  private allPlugins: Map<string, Plugins>;
113  private context: PluginContext;
114
115  constructor() {
116    this.sortedPlugins = new Map<PluginHook, PluginExecutor[] | undefined>();
117    this.allPlugins = new Map<string, Plugins>();
118    this.context = new PluginContext();
119  }
120
121  public static getInstance(): PluginDriver {
122    if (!this.instance) {
123      this.instance = new PluginDriver();
124    }
125    return this.instance;
126  }
127
128  public static destroyInstance(): void {
129    PluginDriver.instance = undefined;
130  }
131
132  public initPlugins(projectConfig: BuildConfig): void {
133    const pluginResults: RawPlugins[] = Object.entries(projectConfig.plugins).map(([key, value]) => {
134      let pluginObject = require(value as string);
135      let initFunction = Object.values(pluginObject)[0] as PluginInitFunction;
136      return {
137        name: key,
138        init: initFunction
139      };
140    });
141
142    pluginResults.forEach((plugin: RawPlugins) => {
143      if (plugin.init !== undefined) {
144        this.allPlugins.set(plugin.name, plugin.init());
145      }
146    });
147
148    this.context.setProjectConfig(projectConfig);
149  }
150
151  private getPlugins(hook: PluginHook): PluginExecutor[] | undefined {
152    if (!this.sortedPlugins.has(hook)) {
153      const sortedPlugins: PluginExecutor[] = this.getSortedPlugins(hook);
154      if (sortedPlugins.length === 0) {
155        this.sortedPlugins.set(hook, undefined);
156      } else {
157        this.sortedPlugins.set(hook, sortedPlugins);
158      }
159    }
160
161    return this.sortedPlugins.get(hook);
162  }
163
164  private getSortedPlugins(hook: PluginHook): PluginExecutor[] {
165    let pre: PluginExecutor[] = [];
166    let normal: PluginExecutor[] = [];
167    let post: PluginExecutor[] = [];
168
169    this.allPlugins.forEach((pluginObject: Plugins, name: string) => {
170      if (!pluginObject[hook]) {
171        return;
172      }
173
174      let pluginName: string = pluginObject.name;
175      let handler: PluginHandler = pluginObject[hook]!;
176      let order: string | undefined = typeof handler === 'object' ? handler.order : undefined;
177
178      let rawPluginHook: PluginExecutor = {
179        name: pluginName,
180        handler: typeof handler === 'object' ? handler.handler : handler
181      };
182
183      if (order === 'pre') {
184        pre.push(rawPluginHook);
185      } else if (order === 'post') {
186        post.push(rawPluginHook);
187      } else {
188        normal.push(rawPluginHook);
189      }
190    });
191
192    return [...pre, ...normal, ...post];
193  }
194
195  public runPluginHook(hook: PluginHook): void {
196    let plugins: PluginExecutor[] | undefined = this.getPlugins(hook);
197    if (!plugins) {
198      return;
199    }
200    plugins.forEach((executor: PluginExecutor) => {
201      return (executor.handler as Function).apply(this.context);
202    });
203  }
204
205  public getPluginContext(): PluginContext {
206    return this.context;
207  }
208}
209