• 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 ts, { CatchClause, Declaration, Expression, TypeChecker, VariableDeclarationList } from 'typescript';
17import {
18  IntentEntryInfo,
19  intentEntryInfoChecker,
20  IntentLinkInfo,
21  IntentLinkInfoChecker,
22  intentMethodInfoChecker,
23  LinkIntentParamMapping,
24  IntentPageInfoChecker,
25  ParamChecker,
26  IntentEntityInfoChecker,
27  intentFormInfoChecker
28} from './intentType';
29import { IntentLogger } from './intentLogger';
30import path from 'path';
31import { getNormalizedOhmUrlByFilepath } from '../ark_utils';
32import { globalModulePaths, projectConfig } from '../../main';
33import fs from 'fs';
34import json5 from 'json5';
35import { ProjectCollections } from 'arkguard';
36import {
37  COMPONENT_USER_INTENTS_DECORATOR,
38  COMPONENT_USER_INTENTS_DECORATOR_ENTITY,
39  COMPONENT_USER_INTENTS_DECORATOR_ENTRY,
40  COMPONENT_USER_INTENTS_DECORATOR_FUNCTION,
41  COMPONENT_USER_INTENTS_DECORATOR_METHOD,
42  COMPONENT_USER_INTENTS_DECORATOR_PAGE,
43  COMPONENT_USER_INTENTS_DECORATOR_FORM
44} from '../pre_define';
45import { CompileEvent, createAndStartEvent, stopEvent } from '../performance';
46import {emitLogInfo, getTransformLog, LogInfo, LogType} from '../utils';
47import {ABILITY_SUBSYSTEM_CODE} from '../../lib/hvigor_error_code/hvigor_error_info';
48import {resetLog, transformLog} from '../process_ui_syntax';
49
50type StaticValue = string | number | boolean | null | undefined | StaticValue[] | { [key: string]: StaticValue };
51
52interface methodParametersInfo {
53  functionName: string;
54  parameters: Record<string, string>,
55  args: ts.NodeArray<ts.Expression>;
56}
57
58interface schemaVerifyType {
59  type: string;
60  isEntity?: boolean;
61}
62
63class ParseIntent {
64  private checker: ts.TypeChecker;
65  public intentData: object[];
66  private currentFilePath: string;
67  private heritageClassSet: Set<string>;
68  private updatePageIntentObj: Map<string, object[]>;
69  public isUpdateCompile: boolean = true;
70  private isInitCache: boolean = false;
71  private entityMap: Map<string, object>;
72  private entityOwnerMap: Map<string, string[]>;
73  private moduleJsonInfo: Map<string, object[]>;
74  private EntityHeritageClassSet: Set<string>;
75  private EntityExtendsMap: Map<string, string>;
76  private transformLog: LogInfo[];
77  private currentNode: ts.Node;
78
79  constructor() {
80    this.intentData = [];
81    this.currentFilePath = '';
82    this.heritageClassSet = new Set<string>();
83    this.heritageClassSet.add('IntentEntity_sdk');
84    this.heritageClassSet.add('InsightIntentEntryExecutor_sdk');
85    this.updatePageIntentObj = new Map();
86    this.entityMap = new Map();
87    this.entityOwnerMap = new Map();
88    this.moduleJsonInfo = new Map();
89    this.EntityHeritageClassSet = new Set();
90    this.EntityExtendsMap = new Map();
91  }
92
93  private hasDecorator(node: ts.Node, decorators: string[]): boolean {
94    if (!node.modifiers) {
95      return false;
96    }
97    return node.modifiers.some(decorator => {
98      if (!ts.isDecorator(decorator)) {
99        return false;
100      }
101      let decoratorName: string | undefined;
102      if (ts.isCallExpression(decorator.expression)) {
103        decoratorName = `@${decorator.expression.expression.getText()}`;
104      }
105      return decoratorName !== undefined && decorators.includes(decoratorName);
106    });
107  }
108
109  public detectInsightIntent(
110    node: ts.ClassDeclaration, metaInfo: object, filePath: string, eventOrEventFactory: CompileEvent | undefined, transformLog: LogInfo[]): ts.Node {
111    this.initInsightIntent(node, metaInfo, transformLog, filePath);
112    const eventParseIntentTime: CompileEvent | undefined = createAndStartEvent(eventOrEventFactory, 'parseIntentTime');
113    const definedDecorators: string[] = [COMPONENT_USER_INTENTS_DECORATOR, COMPONENT_USER_INTENTS_DECORATOR_ENTRY,
114      COMPONENT_USER_INTENTS_DECORATOR_FUNCTION, COMPONENT_USER_INTENTS_DECORATOR_PAGE, COMPONENT_USER_INTENTS_DECORATOR_ENTITY,
115      COMPONENT_USER_INTENTS_DECORATOR_FORM];
116    if (ts.isClassDeclaration(node) && !this.hasDecorator(node, [COMPONENT_USER_INTENTS_DECORATOR_FUNCTION])) {
117      node.members.forEach((member) => {
118        if (ts.isMethodDeclaration(member) && this.hasModifier(member, ts.SyntaxKind.StaticKeyword) &&
119          this.hasDecorator(member, [COMPONENT_USER_INTENTS_DECORATOR_METHOD])) {
120          const errorMessage: string = 'Methods decorated with @InsightIntentFunctionMethod must be in a class decorated with @InsightIntentFunction.';
121          this.transformLog.push({
122            type: LogType.ERROR,
123            message: errorMessage,
124            pos: node.getStart(),
125            code: '10110013',
126            description: 'InsightIntent Compiler Error',
127            solutions: ['Either move the method or add @InsightIntentFunction to the class']
128          });
129          return;
130        }
131      });
132    }
133    if (this.hasDecorator(node, definedDecorators)) {
134      const checker: TypeChecker = metaInfo.checker;
135      this.handleIntent(node, checker, filePath, metaInfo);
136      node = this.removeDecorator(node, definedDecorators.concat(COMPONENT_USER_INTENTS_DECORATOR_METHOD));
137    }
138    stopEvent(eventParseIntentTime);
139    return node;
140  }
141
142  private initInsightIntent(node: ts.ClassDeclaration, metaInfo: object, transformLog: LogInfo[], filePath: string): void {
143    this.transformLog = transformLog;
144    this.currentNode = node;
145    if (!this.isInitCache) {
146      if (projectConfig.cachePath) {
147        const cacheSourceMapPath: string =
148          path.join(projectConfig.cachePath, 'insight_compile_cache.json'); // The user's intents configuration file
149        this.isUpdateCompile = fs.existsSync(cacheSourceMapPath);
150        this.isInitCache = true;
151      } else {
152        this.isUpdateCompile = false;
153      }
154    }
155    if (this.isUpdateCompile) {
156      const pkgParams: object = {
157        pkgName: metaInfo.pkgName,
158        pkgPath: metaInfo.pkgPath
159      };
160      if (!projectConfig.pkgContextInfo) {
161        return;
162      }
163      const Logger: IntentLogger = IntentLogger.getInstance();
164      const recordName: string = getNormalizedOhmUrlByFilepath(filePath, projectConfig, Logger, pkgParams, null);
165      if (!this.updatePageIntentObj.has(`@normalized:${recordName}`)) {
166        this.updatePageIntentObj.set(`@normalized:${recordName}`, []);
167      }
168    }
169  }
170
171  private handleIntent(node: ts.ClassDeclaration, checker: ts.TypeChecker, filepath: string, metaInfo: Object = {}): void {
172    this.checker = checker;
173    this.currentFilePath = filepath;
174    if (!filepath.endsWith('.ets')) {
175      const errorMessage: string = 'The intent decorator can only be used in .ets files.';
176      this.transformLog.push({
177        type: LogType.ERROR,
178        message: errorMessage,
179        pos: this.currentNode.getStart(),
180        code: '10110001',
181        description: 'InsightIntent Compiler Error',
182        solutions: ['Move it to an .ets file']
183      });
184      return;
185    }
186    const pkgParams: object = {
187      pkgName: metaInfo.pkgName,
188      pkgPath: metaInfo.pkgPath
189    };
190    node.modifiers.forEach(decorator => {
191      this.handleDecorator(node, decorator, filepath, pkgParams);
192    });
193  }
194
195  private handleDecorator(node: ts.ClassDeclaration, decorator: ts.Decorator, filepath: string, pkgParams: object): void {
196    const expr: ts.Expression = decorator.expression;
197    if (!expr || !ts.isCallExpression(expr)) {
198      return;
199    }
200    const argumentKind: ts.SyntaxKind | undefined = expr.arguments[0]?.kind;
201    if (argumentKind && argumentKind === ts.SyntaxKind.NullKeyword || argumentKind && argumentKind === ts.SyntaxKind.UndefinedKeyword) {
202      return;
203    }
204    const symbol: ts.Symbol = this.checker.getTypeAtLocation(decorator.expression.expression)?.getSymbol();
205    const declarations: ts.Declaration[] | undefined = symbol?.getDeclarations();
206    if (!declarations || declarations.length === 0) {
207      return;
208    }
209    const decoratorSourceFile: string = declarations[0].getSourceFile().fileName;
210    const isGlobalPathFlag: boolean = this.isGlobalPath(decoratorSourceFile);
211    if (!isGlobalPathFlag) {
212      return;
213    }
214    if (!projectConfig.pkgContextInfo) {
215      const errorMessage: string = 'Failed to generate standard OHMUrl.';
216      this.transformLog.push({
217        type: LogType.ERROR, message: errorMessage, pos: this.currentNode.getStart(),
218        code: '10111027',
219        description: 'InsightIntent Compiler Error',
220        solutions: ['Set useNormalizedOHMUrl to true in build-profile.json5']
221      });
222      return;
223    }
224    const Logger: IntentLogger = IntentLogger.getInstance();
225    const recordName: string = getNormalizedOhmUrlByFilepath(filepath, projectConfig, Logger, pkgParams, null);
226    const intentObj: object = {
227      'decoratorFile': `@normalized:${recordName}`,
228      'decoratorClass': node.name.text
229    };
230    const originalDecorator: string = '@' + decorator.expression.expression.getText();
231    if (originalDecorator === COMPONENT_USER_INTENTS_DECORATOR) {
232      this.handleLinkDecorator(intentObj, node, decorator);
233    } else if (originalDecorator === COMPONENT_USER_INTENTS_DECORATOR_ENTRY) {
234      this.handleEntryDecorator(intentObj, node, decorator, pkgParams);
235    } else if (originalDecorator === COMPONENT_USER_INTENTS_DECORATOR_FUNCTION) {
236      this.handleMethodDecorator(intentObj, node, decorator);
237    } else if (originalDecorator === COMPONENT_USER_INTENTS_DECORATOR_PAGE) {
238      this.handlePageDecorator(intentObj, node, decorator, pkgParams);
239    } else if (originalDecorator === COMPONENT_USER_INTENTS_DECORATOR_ENTITY) {
240      this.handleEntityDecorator(intentObj, node, decorator, pkgParams);
241    } else if (originalDecorator === COMPONENT_USER_INTENTS_DECORATOR_FORM) {
242      this.handleFormDecorator(intentObj, node, decorator, pkgParams);
243    }
244  }
245
246  private handleFormDecorator(intentObj: object, node: ts.ClassDeclaration, decorator: ts.Decorator,
247    pkgParams: object): void {
248    const expr: ts.Expression = decorator.expression;
249    if (ts.isCallExpression(expr)) {
250      const args: ts.NodeArray<ts.Expression> = expr.arguments;
251      Object.assign(intentObj, {
252        'bundleName': projectConfig.bundleName,
253        'moduleName': projectConfig.moduleName,
254        'decoratorType': COMPONENT_USER_INTENTS_DECORATOR_FORM
255      });
256      this.analyzeDecoratorArgs(args, intentObj, intentFormInfoChecker);
257      const properties: Record<string, schemaVerifyType> = this.parseClassNode(node, intentObj.intentName, COMPONENT_USER_INTENTS_DECORATOR_FORM);
258      this.processFormInfo(node, this.currentFilePath, pkgParams, intentObj);
259      this.schemaValidateSync(properties, intentObj.parameters);
260      this.createObfuscation(node);
261      if (this.isUpdateCompile) {
262        this.updatePageIntentObj.get(intentObj.decoratorFile).push(intentObj);
263      }
264      this.intentData.push(intentObj);
265    } else {
266      const errorMessage: string = 'Decorators must be called as functions.';
267      this.transformLog.push({
268        type: LogType.ERROR,
269        message: errorMessage,
270        pos: this.currentNode.getStart(),
271        code: '10110002',
272        description: 'InsightIntent Compiler Error',
273        solutions: ['Add parentheses after the decorator name']
274      });
275      return;
276    }
277  }
278
279  private handleEntityDecorator(intentObj: object, node: ts.ClassDeclaration, decorator: ts.Decorator,
280    pkgParams: object): void {
281    const entityClassName: string = this.checker.getTypeAtLocation(node).getSymbol().getName();
282    const expr: ts.Expression = decorator.expression;
283    if (ts.isCallExpression(expr)) {
284      const args: ts.NodeArray<ts.Expression> = expr.arguments;
285      Object.assign(intentObj, {
286        'decoratorType': COMPONENT_USER_INTENTS_DECORATOR_ENTITY,
287        'className': intentObj.decoratorClass
288      });
289      delete intentObj.decoratorClass;
290      this.analyzeDecoratorArgs(args, intentObj, IntentEntityInfoChecker);
291      const properties: Record<string, schemaVerifyType> = this.parseClassNode(node, undefined, COMPONENT_USER_INTENTS_DECORATOR_ENTITY);
292      const entityId: string = this.getEntityId(node);
293      Object.assign(properties, {
294        'entityId': entityId
295      });
296      Object.assign(intentObj, {
297        'entityId': entityId
298      });
299      this.schemaValidateSync(properties, intentObj.parameters);
300      this.analyzeBaseClass(node, pkgParams, intentObj, COMPONENT_USER_INTENTS_DECORATOR_ENTITY);
301      this.createObfuscation(node);
302      if (this.entityMap.has(entityClassName)) {
303       const errorMessage: string = 'Multiple @InsightIntentEntity decorators applied to the same class.';
304        this.transformLog.push({
305          type: LogType.ERROR,
306          message: errorMessage,
307          pos: this.currentNode.getStart(),
308          code: '10110020',
309          description: 'InsightIntent Compiler Error',
310          solutions: ['Remove duplicates']
311        });
312        return;
313      } else {
314        this.entityMap.set(entityClassName, intentObj);
315      }
316    } else {
317      const errorMessage: string = 'Decorators must be called as functions.';
318      this.transformLog.push({
319        type: LogType.ERROR,
320        message: errorMessage,
321        pos: this.currentNode.getStart(),
322        code: '10110002',
323        description: 'InsightIntent Compiler Error',
324        solutions: ['Add parentheses after the decorator name']
325      });
326      return;
327    }
328  }
329
330  private handlePageDecorator(intentObj: object, node: ts.ClassDeclaration, decorator: ts.Decorator,
331    pkgParams: object): void {
332    const expr: ts.Expression = decorator.expression;
333    if (ts.isClassDeclaration(node)) {
334      const errorMessage: string = `@InsightIntentPage must be applied to a struct page.`;
335      this.transformLog.push({
336        type: LogType.ERROR,
337        message: errorMessage,
338        pos: this.currentNode.getStart(),
339        code: '10110016',
340        description: 'InsightIntent Compiler Error',
341        solutions: ['Decorate a struct page with @InsightIntentPage']
342      });
343      return;
344    }
345    if (ts.isCallExpression(expr)) {
346      const args: ts.NodeArray<ts.Expression> = expr.arguments;
347      Object.assign(intentObj, {
348        'bundleName': projectConfig.bundleName,
349        'moduleName': projectConfig.moduleName,
350        'decoratorType': COMPONENT_USER_INTENTS_DECORATOR_PAGE
351      });
352      this.analyzeDecoratorArgs(args, intentObj, IntentPageInfoChecker);
353      this.validatePagePath(intentObj, pkgParams);
354      this.createObfuscation(node);
355      if (this.isUpdateCompile) {
356        this.updatePageIntentObj.get(intentObj.decoratorFile).push(intentObj);
357      }
358      this.intentData.push(intentObj);
359    } else {
360       const errorMessage: string = 'Decorators must be called as functions.';
361      this.transformLog.push({
362        type: LogType.ERROR,
363        message: errorMessage,
364        pos: this.currentNode.getStart(),
365        code: '10110002',
366        description: 'InsightIntent Compiler Error',
367        solutions: ['Add parentheses after the decorator name']
368      });
369      return;
370    }
371  }
372
373  private handleMethodDecorator(intentObj: object, node: ts.ClassDeclaration, decorator: ts.Decorator): void {
374    const isExported: boolean = node.modifiers?.some(mod => mod.kind === ts.SyntaxKind.ExportKeyword);
375    if (!isExported) {
376      const errorMessage: string = 'The class decorated with @InsightIntentFunction must be exported.';
377      this.transformLog.push({
378        type: LogType.ERROR,
379        message: errorMessage,
380        pos: this.currentNode.getStart(),
381        code: '10110014',
382        description: 'InsightIntent Compiler Error',
383        solutions: ['Add an export statement']
384      });
385      return;
386    }
387    const expr: ts.Expression = decorator.expression;
388    if (ts.isCallExpression(expr)) {
389      Object.assign(intentObj, {
390        'bundleName': projectConfig.bundleName,
391        'moduleName': projectConfig.moduleName,
392        'decoratorType': COMPONENT_USER_INTENTS_DECORATOR_METHOD
393      });
394      const methodParameters: methodParametersInfo[] = this.parseClassMethods(node, COMPONENT_USER_INTENTS_DECORATOR_METHOD);
395      methodParameters?.forEach(methodDecorator => {
396        const functionName: string = methodDecorator.functionName;
397        const methodArgs: ts.NodeArray<ts.Expression> = methodDecorator.args;
398        const properties: Record<string, string> = methodDecorator.parameters;
399        const functionParamList: Array<string> = Object.keys(properties);
400        const methodObj: object = Object.assign({}, intentObj, { functionName, 'functionParamList': functionParamList });
401        this.analyzeDecoratorArgs(methodArgs, methodObj, intentMethodInfoChecker);
402        if (this.isUpdateCompile) {
403          this.updatePageIntentObj.get(methodObj.decoratorFile).push(methodObj);
404        }
405        this.intentData.push(methodObj);
406      });
407      this.createObfuscation(node);
408    } else {
409      const errorMessage: string = 'Decorators must be called as functions.';
410      this.transformLog.push({
411        type: LogType.ERROR,
412        message: errorMessage,
413        pos: this.currentNode.getStart(),
414        code: '10110002',
415        description: 'InsightIntent Compiler Error',
416        solutions: ['Add parentheses after the decorator name']
417      });
418      return;
419    }
420  }
421
422  private handleLinkDecorator(intentObj: object, node: ts.ClassDeclaration, decorator: ts.Decorator): void {
423    const expr: ts.Expression = decorator.expression;
424    if (ts.isCallExpression(expr)) {
425      const args: ts.NodeArray<ts.Expression> = expr.arguments;
426      this.analyzeDecoratorArgs<IntentLinkInfo>(args, intentObj, IntentLinkInfoChecker);
427      Object.assign(intentObj, {
428        'bundleName': projectConfig.bundleName,
429        'moduleName': projectConfig.moduleName,
430        'decoratorType': COMPONENT_USER_INTENTS_DECORATOR
431      });
432      this.createObfuscation(node);
433      if (this.isUpdateCompile) {
434        this.updatePageIntentObj.get(intentObj.decoratorFile).push(intentObj);
435      }
436      this.intentData.push(intentObj);
437    } else {
438      const errorMessage: string = 'Decorators must be called as functions.';
439      this.transformLog.push({
440        type: LogType.ERROR,
441        message: errorMessage,
442        pos: this.currentNode.getStart(),
443        code: '10110002',
444        description: 'InsightIntent Compiler Error',
445        solutions: ['Add parentheses after the decorator name']
446      });
447      return;
448    }
449  }
450
451  private handleEntryDecorator(intentObj: object, node: ts.ClassDeclaration, decorator: ts.Decorator,
452    pkgParams: object): void {
453      const isExported: boolean = node.modifiers?.some(mod => mod.kind === ts.SyntaxKind.ExportKeyword);
454    const isDefault: boolean = node.modifiers?.some(mod => mod.kind === ts.SyntaxKind.DefaultKeyword);
455    if (!(isExported && isDefault)) {
456      const errorMessage: string = 'The class decorated with @InsightIntentEntry must be exported as default.';
457      this.transformLog.push({
458        type: LogType.ERROR,
459        message: errorMessage,
460        pos: this.currentNode.getStart(),
461        code: '10110019',
462        description: 'InsightIntent Compiler Error',
463        solutions: ['Use the \'export default\' syntax']
464      });
465      return;
466    }
467    const expr: ts.Expression = decorator.expression;
468    if (ts.isCallExpression(expr)) {
469      const args: ts.NodeArray<ts.Expression> = expr.arguments;
470      Object.assign(intentObj, {
471        'bundleName': projectConfig.bundleName,
472        'moduleName': projectConfig.moduleName,
473        'decoratorType': COMPONENT_USER_INTENTS_DECORATOR_ENTRY
474      });
475      this.analyzeDecoratorArgs<IntentEntryInfo>(args, intentObj, intentEntryInfoChecker);
476      const properties: Record<string, schemaVerifyType> = this.parseClassNode(node, intentObj.intentName, COMPONENT_USER_INTENTS_DECORATOR_ENTRY);
477      this.schemaValidateSync(properties, intentObj.parameters);
478      this.analyzeBaseClass(node, pkgParams, intentObj, COMPONENT_USER_INTENTS_DECORATOR_ENTRY);
479      this.createObfuscation(node);
480      this.processExecuteModeParam(intentObj);
481      if (this.isUpdateCompile) {
482        this.updatePageIntentObj.get(intentObj.decoratorFile).push(intentObj);
483      }
484      this.intentData.push(intentObj);
485    } else {
486      const errorMessage: string = 'Decorators must be called as functions.';
487      this.transformLog.push({
488        type: LogType.ERROR,
489        message: errorMessage,
490        pos: this.currentNode.getStart(),
491        code: '10110002',
492        description: 'InsightIntent Compiler Error',
493        solutions: ['Add parentheses after the decorator name']
494      });
495      return;
496    }
497  }
498
499  private processFormInfo(node: ts.ClassDeclaration, formClassPath: string, pkgParams: object,
500    intentObj: object): void {
501    if (this.moduleJsonInfo.size === 0 && pkgParams.pkgPath) {
502      this.readModuleJsonInfo(pkgParams);
503    }
504    const extensionAbilities: object[] = this.moduleJsonInfo.get('extensionAbilities');
505    const bindFormInfo: object = extensionAbilities.find(extensionInfo => {
506      const formSrcEntryPath: string = path.join(pkgParams.pkgPath, 'src', 'main', extensionInfo.srcEntry);
507      return formSrcEntryPath === formClassPath && extensionInfo.type === 'form';
508    });
509    this.verifyFormName(bindFormInfo, intentObj);
510    const isExported: boolean = node.modifiers?.some(mod => mod.kind === ts.SyntaxKind.ExportKeyword);
511    const isDefault: boolean = node.modifiers?.some(mod => mod.kind === ts.SyntaxKind.DefaultKeyword);
512    if (!(bindFormInfo && isExported && isDefault)) {
513      const errorMessage: string = '@InsightIntentForm must be applied to formExtensionAbility.';
514      this.transformLog.push({
515        type: LogType.ERROR,
516        message: errorMessage,
517        pos: this.currentNode.getStart(),
518        code: '10110022',
519        description: 'InsightIntent Compiler Error',
520        solutions: ['Decorate the formExtensionAbility class with @InsightIntentForm']
521      });
522      return;
523    }
524  }
525
526  private verifyFormName(bindFormInfo: object, intentObj: object): void {
527    if (!bindFormInfo) {
528      return;
529    }
530    let formNameFound: boolean = false;
531    intentObj.abilityName = bindFormInfo.name;
532    bindFormInfo.metadata?.forEach(metaData => {
533      const formConfigName = `${metaData.resource.split(':').pop()}.json`;
534      const formConfigPath = path.join(projectConfig.aceProfilePath, formConfigName);
535      if (!fs.existsSync(formConfigPath)) {
536        return;
537      }
538      const formData = fs.readFileSync(formConfigPath, 'utf8');
539      const formConfigs = JSON.parse(formData).forms;
540      if (formConfigs?.some(form => form.name === intentObj.formName)) {
541        formNameFound = true;
542      }
543    });
544    if (!formNameFound) {
545      const errorMessage: string = 'formName in @InsightIntentForm must match the widget name registered in formExtensionAbility.';
546      this.transformLog.push({
547        type: LogType.ERROR,
548        message: errorMessage,
549        pos: this.currentNode.getStart(),
550        code: '10110023',
551        description: 'InsightIntent Compiler Error',
552        solutions: ['Update formName to match the registered widget name']
553      });
554      return;
555    }
556  }
557
558  private readModuleJsonInfo(pkgParams: object): void {
559    const moduleJsonPath: string = path.join(pkgParams.pkgPath, 'src/main', 'module.json5');
560    if (!fs.existsSync(moduleJsonPath)) {
561      const errorMessage: string = `The module.json5 file is missing.`;
562      this.transformLog.push({
563        type: LogType.ERROR,
564        message: errorMessage,
565        pos: this.currentNode.getStart(),
566        code: '10110024',
567        description: 'InsightIntent Compiler Error',
568        solutions: ['Check the expected paths (typically entry/src/main/config.json or module.json5) and restore the file']
569      });
570      return;
571    }
572    if (!projectConfig.modulePathMap) {
573      return;
574    }
575      const jsonStr: string = fs.readFileSync(moduleJsonPath, 'utf8');
576      const obj: object = json5.parse(jsonStr);
577      if (obj.module?.abilities) {
578        this.moduleJsonInfo.set('abilities', obj.module.abilities);
579      }
580      if (obj.module?.extensionAbilities) {
581        this.moduleJsonInfo.set('extensionAbilities', obj.module.extensionAbilities);
582      }
583  }
584
585  private validatePagePath(intentObj: object, pkgParams: object): void {
586    if (pkgParams.pkgPath) {
587      const normalPagePath: string = path.join(pkgParams.pkgPath, 'src/main', intentObj.pagePath + '.ets');
588      if (!fs.existsSync(normalPagePath)) {
589        const errorMessage: string = `PagePath in @InsightIntentPage does not match the actual page path.`;
590        this.transformLog.push({
591          type: LogType.ERROR,
592          message: errorMessage,
593          pos: this.currentNode.getStart(),
594          code: '10110017',
595          description: 'InsightIntent Compiler Error',
596          solutions: ['Verify the file path']
597        });
598        return;
599      } else {
600        const Logger: IntentLogger = IntentLogger.getInstance();
601        intentObj.pagePath =
602          '@normalized:' + getNormalizedOhmUrlByFilepath(normalPagePath, projectConfig, Logger, pkgParams, null);
603      }
604    }
605  }
606
607  private isGlobalPath(parentFilePath: string): boolean {
608    return globalModulePaths?.some(globalPath => {
609      const normalizedParent: string = path.normalize(parentFilePath).replace(/\\/g, '/');
610      const normalizedGlobalPath: string = path.normalize(globalPath).replace(/\\/g, '/');
611      return normalizedParent.startsWith(normalizedGlobalPath);
612    });
613  }
614
615  private analyzeBaseClass(node: ts.ClassDeclaration, pkgParams: object, intentObj: object,
616    decoratorFlag: string): void {
617    const interfaces: ts.ExpressionWithTypeArguments[] = [];
618    if (decoratorFlag === COMPONENT_USER_INTENTS_DECORATOR_ENTRY) {
619      node.heritageClauses?.forEach(clause => {
620        if (clause.token === ts.SyntaxKind.ExtendsKeyword) {
621          interfaces.push(...clause.types);
622        }
623      });
624      this.processEntryBaseClass(interfaces, intentObj, pkgParams);
625    } else if (decoratorFlag === COMPONENT_USER_INTENTS_DECORATOR_ENTITY) {
626      node.heritageClauses?.forEach(clause => {
627        if (clause.token === ts.SyntaxKind.ImplementsKeyword || clause.token === ts.SyntaxKind.ExtendsKeyword) {
628          interfaces.push(...clause.types);
629        }
630      });
631      if (interfaces.length > 0) {
632        const parentNode: ts.ExpressionWithTypeArguments = interfaces[0];
633        this.analyzeClassHeritage(parentNode, node, pkgParams, intentObj);
634      } else {
635       const errorMessage: string = `Classes decorated with @InsightIntentEntity must implement InsightIntent.IntentEntity.`;
636        this.transformLog.push({
637          type: LogType.ERROR,
638          message: errorMessage,
639          pos: this.currentNode.getStart(),
640          code: '10110021',
641          description: 'InsightIntent Compiler Error',
642          solutions: ['Add the implementation or inherit from a base intent entity']
643        });
644        return;
645      }
646    }
647  }
648
649  private processEntryBaseClass(interfaces: ts.ExpressionWithTypeArguments[], intentObj: object,
650    pkgParams: object): void {
651    if (interfaces.length > 0) {
652      const parentNode: ts.ExpressionWithTypeArguments = interfaces[0];
653      const parentClassName: string = parentNode.expression.getText();
654      const parentNodeSymbol: ts.Symbol = this.checker.getTypeAtLocation(parentNode).getSymbol();
655      const parentFilePath: string = parentNodeSymbol.getDeclarations()?.[0].getSourceFile().fileName;
656      const isGlobalPathFlag: boolean = this.isGlobalPath(parentFilePath);
657      if (!(isGlobalPathFlag && parentClassName === 'InsightIntentEntryExecutor')) {
658        const errorMessage: string = `Classes decorated with @InsightIntentEntry must inherit from InsightIntentEntryExecutor.`;
659        this.transformLog.push({
660          type: LogType.ERROR,
661          message: errorMessage,
662          pos: this.currentNode.getStart(),
663          code: '10110018',
664          description: 'InsightIntent Compiler Error',
665          solutions: ['Add the inheritance']
666        });
667        return;
668      }
669      const logger: IntentLogger = IntentLogger.getInstance();
670      const parentRecordName: string =
671        getNormalizedOhmUrlByFilepath(parentFilePath, projectConfig, logger, pkgParams, null);
672      const recordPath: string = isGlobalPathFlag ? `sdk` : `@normalized:${parentRecordName}`;
673      this.collectClassInheritanceInfo(parentNode, intentObj, parentClassName, recordPath);
674    } else {
675      const errorMessage: string = `Classes decorated with @InsightIntentEntry must inherit from InsightIntentEntryExecutor.`;
676      this.transformLog.push({
677        type: LogType.ERROR,
678        message: errorMessage,
679        pos: this.currentNode.getStart(),
680        code: '10110018',
681        description: 'InsightIntent Compiler Error',
682        solutions: ['Add the inheritance']
683      });
684      return;
685    }
686  }
687
688  private hasModifier(node: ts.Node, modifier: ts.SyntaxKind): boolean {
689    return (node.modifiers || []).some(m => m.kind === modifier);
690  }
691
692  private parseClassMethods(classNode: ts.ClassDeclaration, decoratorType: string): methodParametersInfo[] {
693    const methodsArr: methodParametersInfo[] = [];
694    for (const member of classNode.members) {
695      if (!ts.isMethodDeclaration(member)) {
696        continue;
697      }
698      const decorator: ts.ModifierLike = member.modifiers?.find(modifier => {
699        if (!ts.isDecorator(modifier)) {
700          return false;
701        }
702        let decoratorName: string | undefined;
703        if (ts.isCallExpression(modifier.expression)) {
704          decoratorName = `@${modifier.expression.expression.getText()}`;
705        }
706        return decoratorName === decoratorType;
707      });
708      if (decorator && ts.isCallExpression(decorator.expression)) {
709        if (!this.hasModifier(member, ts.SyntaxKind.StaticKeyword)) {
710          const errorMessage: string = `Methods decorated with @InsightIntentFunctionMethod must be static.`;
711          this.transformLog.push({
712            type: LogType.ERROR,
713            message: errorMessage,
714            pos: this.currentNode.getStart(),
715            code: '10110015',
716            description: 'InsightIntent Compiler Error',
717            solutions: ['Change the method to static']
718          });
719          return undefined;
720        }
721        let parameters: Record<string, string> = {};
722        member.parameters.forEach(param => {
723          const paramName: string = param.name.getText();
724          parameters[paramName] = this.checker.typeToString(
725            this.checker.getTypeAtLocation(param),
726            param,
727            ts.TypeFormatFlags.NoTruncation
728          );
729        });
730        const obj: methodParametersInfo = {
731          functionName: member.name.getText(),
732          parameters: parameters,
733          args: decorator.expression.arguments
734        };
735        methodsArr.push(obj);
736      }
737    }
738    return methodsArr;
739  }
740
741  private analyzeClassHeritage(
742    parentNode: ts.ExpressionWithTypeArguments, node: ts.ClassDeclaration, pkgParams: object, intentObj: object
743  ): void {
744    const parentSymbol: ts.Symbol = this.checker.getTypeAtLocation(parentNode).getSymbol();
745    let parentClassName: string;
746    node.heritageClauses.forEach(clause => {
747      if (clause.token === ts.SyntaxKind.ExtendsKeyword) {
748        parentClassName = parentNode.expression.getText();
749      } else if (clause.token === ts.SyntaxKind.ImplementsKeyword) {
750        parentClassName = parentSymbol.getName();
751      }
752    });
753    intentObj.parentClassName = parentClassName;
754    const parentFilePath: string = parentSymbol.getDeclarations()?.[0].getSourceFile().fileName;
755    const logger: IntentLogger = IntentLogger.getInstance();
756    const baseClassName: string = this.checker.getTypeAtLocation(node).getSymbol().getName();
757    const baseFilePath: string = node.getSourceFile().fileName;
758    const baseRecordName: string = getNormalizedOhmUrlByFilepath(baseFilePath, projectConfig, logger, pkgParams, null);
759    const isGlobalPathFlag: boolean = this.isGlobalPath(parentFilePath);
760    const parentRecordName: string =
761      getNormalizedOhmUrlByFilepath(parentFilePath, projectConfig, logger, pkgParams, null);
762    if (isGlobalPathFlag) {
763      if (parentClassName !== 'IntentEntity') {
764       const errorMessage: string = `Classes decorated with @InsightIntentEntity must implement InsightIntent.IntentEntity.`;
765        this.transformLog.push({
766          type: LogType.ERROR,
767          message: errorMessage,
768          pos: this.currentNode.getStart(),
769          code: '10110021',
770          description: 'InsightIntent Compiler Error',
771          solutions: ['Add the implementation or inherit from a base intent entity']
772        });
773        return;
774      }
775      this.EntityHeritageClassSet.add(parentClassName + '_' + `sdk`);
776    } else {
777      this.EntityHeritageClassSet.add(parentClassName + '_' + `@normalized:${parentRecordName}`);
778      this.EntityExtendsMap.set(baseClassName, parentClassName);
779    }
780    this.heritageClassSet.add(baseClassName + '_' + `@normalized:${baseRecordName}`);
781  }
782
783  private collectClassInheritanceInfo(
784    parentNode: ts.ExpressionWithTypeArguments, intentObj: object, parentClassName: string, recordPath: string
785  ): void {
786    const ClassInheritanceInfo: object = {
787      'parentClassName': parentClassName,
788      'definitionFilePath': recordPath,
789      'generics': []
790    };
791    if (parentNode.typeArguments?.length > 0) {
792      parentNode.typeArguments.forEach((arg): void => {
793        this.getInheritanceInfoByTypeNode(arg, ClassInheritanceInfo, intentObj);
794      });
795    }
796    Object.assign(intentObj, {
797      'ClassInheritanceInfo': ClassInheritanceInfo
798    });
799  }
800
801  private getInheritanceInfoByTypeNode(arg: ts.TypeNode, ClassInheritanceInfo: object, intentObj: object): void {
802    const generic = {};
803    const genericType: ts.Type = this.checker.getTypeAtLocation(arg);
804    let genericName: string;
805    let genericSource: string | undefined;
806    let recordGenericSource: string;
807    const genericSymbol: ts.Symbol | undefined = genericType.getSymbol();
808    if (genericSymbol) {
809      genericName = genericSymbol.getName();
810      genericSource = genericSymbol.declarations?.[0]?.getSourceFile().fileName;
811      recordGenericSource = path.relative(projectConfig.moduleName, genericSource).replace(/\\/g, '/');
812      if (this.entityOwnerMap.has(intentObj.intentName)) {
813        const entityNames: string[] = this.entityOwnerMap.get(intentObj.intentName);
814        entityNames.push(genericName);
815        this.entityOwnerMap.set(intentObj.intentName, entityNames);
816      } else {
817        this.entityOwnerMap.set(intentObj.intentName, [genericName]);
818      }
819    } else {
820      genericName = this.checker.typeToString(genericType);
821      const parentTypeNode: ts.Node = arg.parent;
822      if (ts.isTypeReferenceNode(parentTypeNode)) {
823        const contextualType: ts.Type = this.checker.getTypeAtLocation(parentTypeNode);
824        const symbol: ts.Symbol = contextualType?.getSymbol();
825        genericSource = symbol?.declarations?.[0]?.getSourceFile().fileName;
826      }
827      if (!genericSource && this.isPrimitiveType(genericType)) {
828        recordGenericSource = 'lib.es5.d.ts';
829      }
830    }
831    Object.assign(generic,
832      {
833        'typeName': genericName,
834        'definitionFilePath': recordGenericSource
835      });
836    ClassInheritanceInfo.generics.push(generic);
837  }
838
839  private isPrimitiveType(type: ts.Type): boolean {
840    return (
841      (type.flags & ts.TypeFlags.StringLike) ||
842        (type.flags & ts.TypeFlags.NumberLike) ||
843        (type.flags & ts.TypeFlags.BooleanLike)
844    ) !== 0;
845  }
846
847  private parseClassNode(node: ts.ClassDeclaration, intentName: string, decoratorType: string): Record<string, schemaVerifyType> {
848    const mergedObject: Record<string, schemaVerifyType> = {};
849    const type: ts.Type = this.checker.getTypeAtLocation(node);
850    const propertiesOfType: ts.Symbol[] = this.checker.getPropertiesOfType(type);
851    propertiesOfType.forEach((prop) => {
852      const objItem: Record<string, schemaVerifyType> = this.processProperty(prop, intentName, decoratorType);
853      Object.assign(mergedObject, objItem);
854    });
855    return mergedObject;
856  }
857
858  private getEntityId(node: ts.ClassDeclaration): string {
859    let entityId: string;
860    const type: ts.Type = this.checker.getTypeAtLocation(node);
861    const propertiesOfType: ts.Symbol[] = this.checker.getPropertiesOfType(type);
862    propertiesOfType.forEach((prop) => {
863      if (prop.getName() === 'entityId') {
864        const declaration: ts.Declaration = prop.getDeclarations()?.[0];
865        if (declaration) {
866          const initializer = ts.isIdentifier(declaration.initializer) ?
867            this.checker.getSymbolAtLocation(declaration.initializer)?.valueDeclaration?.initializer :
868          declaration.initializer;
869          entityId = initializer.text;
870        }
871      }
872    });
873    return entityId;
874  }
875
876  private processProperty(prop: ts.Symbol, intentName: string, decoratorType: string): Record<string, schemaVerifyType> {
877    const propType: ts.Type = this.checker.getTypeOfSymbol(prop);
878    const { category } = this.getTypeCategory(propType);
879    const obj: Record<string, schemaVerifyType> = {};
880    const propName: string = prop.getName();
881    const entryBlackList: string[] = ['executeMode', 'context', 'windowStage', 'uiExtensionSession', 'onExecute'];
882    const formBlackList: string[] = ['context'];
883    if (decoratorType === COMPONENT_USER_INTENTS_DECORATOR_ENTRY && entryBlackList.includes(propName)) {
884      return obj;
885    } else if (decoratorType === COMPONENT_USER_INTENTS_DECORATOR_ENTRY && formBlackList.includes(propName)) {
886      return obj;
887    }
888    const tempschemaVerifyType: schemaVerifyType = {
889      type: '',
890      isEntity: false
891    };
892    if (category === 'object') {
893      tempschemaVerifyType.type = 'object';
894      if (this.isEntity(propType, intentName)) {
895        tempschemaVerifyType.isEntity = true;
896      }
897    } else if (category === 'array') {
898      if (this.isEntity(propType, intentName)) {
899        tempschemaVerifyType.type = 'array';
900        tempschemaVerifyType.isEntity = true;
901      }
902    } else {
903      tempschemaVerifyType.type = this.checker.typeToString(propType);
904    }
905    Object.assign(obj, {
906      [propName]: tempschemaVerifyType
907    });
908    return obj;
909  }
910
911  private isEntity(propType: ts.Type, intentName: string): boolean {
912    let propDeclaration: ts.Declaration;
913    let elementType: ts.Type | undefined;
914    const typeSymbol: ts.Symbol = propType.getSymbol();
915    if (this.isArrayType(propType)) {
916      elementType = (propType as ts.TypeReference).typeArguments?.[0];
917      propDeclaration = elementType.getSymbol()?.getDeclarations()[0];
918    } else {
919      propDeclaration = typeSymbol.getDeclarations()?.[0];
920    }
921    if (!propDeclaration) {
922      return false;
923    }
924    return propDeclaration.modifiers?.some(decorator => {
925      if (!ts.isDecorator(decorator)) {
926        return false;
927      }
928      let decoratorName: string | undefined;
929      if (ts.isCallExpression(decorator.expression)) {
930        decoratorName = `@${decorator.expression.expression.getText()}`;
931      }
932      if (decoratorName === '@InsightIntentEntity') {
933        const typeSymbol: ts.Symbol = propType.getSymbol();
934        const propertyClassName: string = typeSymbol.getName();
935        if (this.entityOwnerMap.has(intentName)) {
936          const entityNames: string[] = this.entityOwnerMap.get(intentName);
937          entityNames.push(propertyClassName);
938          this.entityOwnerMap.set(intentName, entityNames);
939        } else {
940          this.entityOwnerMap.set(intentName, [propertyClassName]);
941        }
942        return true;
943      }
944      return false;
945    });
946  }
947
948  private getTypeCategory(type: ts.Type): { category: 'array' | 'object'; } {
949    const flags: ts.TypeFlags = type.getFlags();
950    const valueDeclaration: ts.Declaration | undefined = type.getSymbol()?.valueDeclaration;
951    const isEnum: boolean = valueDeclaration ? ts.isEnumDeclaration(valueDeclaration) : false;
952
953    const isPrimitive: boolean = !!(flags & ts.TypeFlags.StringLike) ||
954      !!(flags & ts.TypeFlags.NumberLike) ||
955      !!(flags & ts.TypeFlags.BooleanLike) ||
956      !!(flags & ts.TypeFlags.Null) ||
957      !!(flags & ts.TypeFlags.Undefined);
958
959    const isArray: boolean = this.isArrayType(type);
960    const isObject: boolean = !isPrimitive &&
961      !isArray &&
962      (!!(flags & ts.TypeFlags.Object) || isEnum);
963    let category: 'array' | 'object';
964    if (isArray) {
965      category = 'array';
966    } else if (isObject) {
967      category = 'object';
968    }
969    return { category };
970  }
971
972  private isArrayType(type: ts.Type): boolean {
973    let isArray: boolean;
974    const symbol: ts.Symbol | undefined = type.getSymbol();
975    const flags: ts.TypeFlags = type.getFlags();
976    if (symbol) {
977      isArray = symbol.getName() === 'Array';
978    } else {
979      isArray = !!(flags & ts.TypeFlags.Object) &&
980        !!(type as ts.ObjectType).objectFlags && ts.ObjectFlags.Reference &&
981        ((type as ts.TypeReference).target.getSymbol()?.getName() === 'Array');
982    }
983    return isArray;
984  }
985
986  private removeDecorator(node: ts.ClassDeclaration, decoratorNames: string[]): ts.ClassDeclaration {
987    const filteredModifiers: ts.ModifierLike[] = node.modifiers.filter(decorator => {
988      if (!ts.isDecorator(decorator)) {
989        return true;
990      }
991      let decoratorName: string | undefined;
992      if (ts.isCallExpression(decorator.expression)) {
993        decoratorName = `@${decorator.expression.expression.getText()}`;
994      }
995      return !decoratorNames.includes(decoratorName);
996    });
997    const updatedMembers: ts.ClassElement[] = node.members.map(member => {
998      return this.reduceMembers(member);
999    });
1000    return ts.factory.updateClassDeclaration(
1001      node,
1002      filteredModifiers,
1003      node.name,
1004      node.typeParameters,
1005      node.heritageClauses,
1006      ts.factory.createNodeArray(updatedMembers)
1007    );
1008  }
1009
1010  private reduceMembers(member: ts.ClassElement): ts.ClassElement {
1011    if (ts.isMethodDeclaration(member) && this.hasModifier(member, ts.SyntaxKind.StaticKeyword)) {
1012      const memberModifiers: ts.ModifierLike[] = (member.modifiers ?? []).filter(decorator => {
1013        if (!ts.isDecorator(decorator)) {
1014          return true;
1015        }
1016        let decoratorName: string | undefined;
1017        if (ts.isCallExpression(decorator.expression)) {
1018          decoratorName = `@${decorator.expression.expression.getText()}`;
1019        }
1020        return decoratorName !== COMPONENT_USER_INTENTS_DECORATOR_METHOD;
1021      });
1022      if (memberModifiers.length !== (member.modifiers?.length ?? 0)) {
1023        return ts.factory.updateMethodDeclaration(
1024          member,
1025          memberModifiers,
1026          member.asteriskToken,
1027          member.name,
1028          member.questionToken,
1029          member.typeParameters,
1030          member.parameters,
1031          member.type,
1032          member.body!
1033        );
1034      }
1035    }
1036    return member;
1037  }
1038
1039  private isSymbolConstant(symbol: ts.Symbol): boolean {
1040    const declaration: Declaration = symbol.valueDeclaration;
1041
1042    if (!this.isConstVariable(declaration)) {
1043      return false;
1044    }
1045    const varDecl: ts.VariableDeclaration = declaration as ts.VariableDeclaration;
1046    const initializer: Expression = varDecl.initializer;
1047    return initializer ? this.isConstantExpression(initializer) : false;
1048  }
1049
1050  private isConstVariable(node: ts.Node | undefined): node is ts.VariableDeclaration {
1051    if (!node || !ts.isVariableDeclaration(node)) {
1052      return false;
1053    }
1054
1055    const varList: VariableDeclarationList | CatchClause = node.parent;
1056    return !!varList && ts.isVariableDeclarationList(varList) &&
1057      (varList.flags & ts.NodeFlags.Const) !== 0;
1058  }
1059
1060  private isConstantExpression(node: ts.Node): boolean {
1061    let flag: boolean = true;
1062    if (ts.isLiteralExpression(node) || node.kind === ts.SyntaxKind.TrueKeyword ||
1063      node.kind === ts.SyntaxKind.FalseKeyword) {
1064      flag = true;
1065    }
1066
1067    if (ts.isIdentifier(node)) {
1068      const symbol: Symbol | undefined = this.checker.getSymbolAtLocation(node);
1069      flag = symbol ? this.isSymbolConstant(symbol) : false;
1070    }
1071
1072    if (ts.isArrayLiteralExpression(node)) {
1073      flag = node.elements.every(element => this.isConstantExpression(element));
1074    }
1075
1076    if (ts.isObjectLiteralExpression(node)) {
1077      flag = node.properties.every(property => {
1078        if (ts.isPropertyAssignment(property)) {
1079          const nameIsConst: boolean = !ts.isComputedPropertyName(property.name);
1080          return nameIsConst && this.isConstantExpression(property.initializer);
1081        }
1082
1083        return false;
1084      });
1085    }
1086
1087    if (ts.isCallExpression(node) && node.expression.getText() === '$r') {
1088      flag = node.arguments.every(node => {
1089        return ts.isStringLiteral(node);
1090      });
1091    }
1092    if (!flag) {
1093      const errorMessage: string = `Decorator parameters must be compile-time constants.`;
1094      this.transformLog.push({
1095        type: LogType.ERROR,
1096        message: errorMessage,
1097        pos: this.currentNode.getStart(),
1098        code: '10110000',
1099        description: 'InsightIntent Compiler Error',
1100        solutions: ['Use a fixed value (such as a string literal) instead of a variable']
1101      });
1102      return false;
1103    }
1104    return flag;
1105  }
1106
1107  private validateRequiredIntentLinkInfo<T>(
1108    node: ts.ObjectLiteralExpression,
1109    paramCheckFields: ParamChecker<T>
1110  ): void {
1111    const existingParams: Set<keyof T> = new Set<keyof T>();
1112    const requiredFields: (keyof T)[] = paramCheckFields.requiredFields;
1113    const nestedCheckers: Map<string, ParamChecker<LinkIntentParamMapping>> = paramCheckFields.nestedCheckers;
1114    const allowedFields: Set<keyof T> = paramCheckFields.allowFields;
1115    const paramValidators: Record<keyof T, (v: ts.Expression) => boolean> = paramCheckFields.paramValidators;
1116    for (const prop of node.properties) {
1117      this.validateFields(prop, allowedFields, paramValidators);
1118      existingParams.add(prop.name.text);
1119      if (nestedCheckers && nestedCheckers.has(prop.name.text)) {
1120        this.validateSelfParamFields(prop, nestedCheckers);
1121      }
1122    }
1123    const missingFields: (keyof T)[] = requiredFields.filter(f => !existingParams.has(f));
1124    if (missingFields.length > 0) {
1125      const errorMessage: string = `Required parameters are missing for the decorator.`;
1126      this.transformLog.push({
1127        type: LogType.ERROR,
1128        message: errorMessage,
1129        pos: this.currentNode.getStart(),
1130        code: '10110003',
1131        description: 'InsightIntent Compiler Error',
1132        solutions: ['Add the required parameters as specified in the error message']
1133      });
1134      return;
1135    }
1136  }
1137
1138  private validateSelfParamFields(prop: ts.Node,
1139    nestedCheckers: Map<string, ParamChecker<LinkIntentParamMapping>>): void {
1140    const checker: ParamChecker<LinkIntentParamMapping> = nestedCheckers.get(prop.name.text);
1141    if (ts.isArrayLiteralExpression(prop.initializer)) {
1142      prop.initializer.elements.every(elem => {
1143        if (ts.isIdentifier(elem)) {
1144          const symbol: ts.Symbol | undefined = this.checker.getSymbolAtLocation(elem);
1145          const declaration: ts.Declaration = symbol?.valueDeclaration;
1146          this.validateRequiredIntentLinkInfo<LinkIntentParamMapping>(declaration.initializer, checker);
1147        } else {
1148          this.validateRequiredIntentLinkInfo<LinkIntentParamMapping>(elem, checker);
1149        }
1150      });
1151    } else if (ts.isIdentifier(prop)) {
1152      const symbol: ts.Symbol | undefined = this.checker.getSymbolAtLocation(prop);
1153      const declaration: ts.Declaration = symbol?.valueDeclaration;
1154      this.validateRequiredIntentLinkInfo<LinkIntentParamMapping>(declaration.initializer, checker);
1155    } else {
1156      this.validateRequiredIntentLinkInfo<LinkIntentParamMapping>(prop, checker);
1157    }
1158  }
1159
1160  private validateFields<T>(
1161    prop: ts.Node, allowedFields: Set<keyof T>, paramValidators: Record<keyof T, (v: ts.Expression) => boolean>
1162  ): void {
1163    const paramName: keyof T = prop.name.text;
1164    if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name)) {
1165      if (!allowedFields.has(paramName)) {
1166        const errorMessage: string = `Unsupported parameters found in the decorator.`;
1167        this.transformLog.push({
1168          type: LogType.ERROR,
1169          message: errorMessage,
1170          pos: this.currentNode.getStart(),
1171          code: '10110005',
1172          description: 'InsightIntent Compiler Error',
1173          solutions: ['Remove any parameters that are not supported.']
1174        });
1175        return;
1176      }
1177      const validator: Function = paramValidators[paramName];
1178      if (ts.isIdentifier(prop.initializer)) {
1179        const symbol: ts.Symbol | undefined = this.checker.getSymbolAtLocation(prop.initializer);
1180        const declaration: ts.Declaration = symbol?.valueDeclaration;
1181        if (validator && !validator(declaration?.initializer)) {
1182          const errorMessage: string = `The parameter type does not match the decorator's requirement.`;
1183          this.transformLog.push({
1184            type: LogType.ERROR,
1185            message: errorMessage,
1186            pos: this.currentNode.getStart(),
1187            code: '10110004',
1188            description: 'InsightIntent Compiler Error',
1189            solutions: ['Adjust the type to match the expected type.']
1190          });
1191          return;
1192        }
1193      } else {
1194        if (validator && !validator(prop.initializer)) {
1195          const errorMessage: string = `The parameter type does not match the decorator's requirement.`;
1196          this.transformLog.push({
1197            type: LogType.ERROR,
1198            message: errorMessage,
1199            pos: this.currentNode.getStart(),
1200            code: '10110004',
1201            description: 'InsightIntent Compiler Error',
1202            solutions: ['Adjust the type to match the expected type.']
1203          });
1204          return;
1205        }
1206      }
1207    }
1208  }
1209
1210  private analyzeDecoratorArgs<T>(args: ts.NodeArray<ts.Expression>, intentObj: object,
1211    paramChecker: ParamChecker<T>): void {
1212    args.forEach(arg => {
1213      if (ts.isIdentifier(arg)) {
1214        const symbol: ts.Symbol | undefined = this.checker.getSymbolAtLocation(arg);
1215        const declaration: ts.Declaration = symbol?.valueDeclaration;
1216        this.validateRequiredIntentLinkInfo<T>(declaration.initializer, paramChecker);
1217      } else {
1218        this.validateRequiredIntentLinkInfo<T>(arg, paramChecker);
1219      }
1220      const res: StaticValue = this.parseStaticObject(arg);
1221      Object.assign(intentObj, res);
1222      this.collectSchemaInfo(intentObj);
1223    });
1224  }
1225
1226  private createObfuscation(classNode: ts.Node): void {
1227    ProjectCollections.projectWhiteListManager?.fileWhiteListInfo.fileKeepInfo.arkUIKeepInfo.globalNames.add(classNode.name.text);
1228    const isExported: boolean = classNode.modifiers?.some(mod => mod.kind === ts.SyntaxKind.ExportKeyword);
1229    if (isExported) {
1230      ProjectCollections.projectWhiteListManager?.fileWhiteListInfo.fileKeepInfo.arkUIKeepInfo.propertyNames.add(classNode.name.text);
1231    }
1232    classNode.members.forEach(member => {
1233      if (ts.isPropertyDeclaration(member) && member.name || ts.isFunctionDeclaration(member) ||
1234      ts.isMethodDeclaration(member) ||
1235      ts.isGetAccessor(member) || ts.isSetAccessor(member)) {
1236        const propName: string = member.name.getText();
1237        ProjectCollections.projectWhiteListManager?.fileWhiteListInfo.fileKeepInfo.arkUIKeepInfo.propertyNames.add(propName);
1238      }
1239    });
1240  }
1241
1242  private parseStaticObject(node: ts.Node, visited: Set<ts.Node> = new Set()): StaticValue | undefined {
1243    if (visited.has(node)) {
1244     const errorMessage: string = `Circular dependencies detected in decorator parameters.`;
1245      this.transformLog.push({
1246        type: LogType.ERROR, message: errorMessage, pos: this.currentNode.getStart(),
1247        code: '10110006',
1248        description: 'InsightIntent Compiler Error',
1249        solutions: ['Refactor the data structure by extracting common variables or using ID references to avoid nesting']
1250      });
1251      return undefined;
1252    }
1253    visited.add(node);
1254    const literalValue: StaticValue | undefined = this.parseLiteralValue(node);
1255    if (literalValue !== undefined) {
1256      return literalValue;
1257    }
1258    if (ts.isIdentifier(node)) {
1259      const isStatic: boolean = this.isConstantExpression(node);
1260      if (isStatic) {
1261        const symbol: ts.Symbol | undefined = this.checker.getSymbolAtLocation(node);
1262        const declaration: ts.Declaration = symbol?.valueDeclaration;
1263        return this.parseStaticObject(declaration.initializer, visited);
1264      }
1265    }
1266    if (ts.isArrayLiteralExpression(node)) {
1267      return this.processArrayElements(node.elements);
1268    }
1269    if (ts.isObjectLiteralExpression(node)) {
1270      return this.processObjectElements(node);
1271    }
1272    if (ts.isCallExpression(node) && node.expression.getText() === '$r') {
1273      const isStatic: boolean = this.isConstantExpression(node);
1274      if (!isStatic) {
1275        return undefined;
1276      }
1277      return node.getText();
1278    }
1279    if (ts.isPropertyAccessExpression(node)) {
1280      return this.processEnumElement(node);
1281    }
1282    const errorMessage: string = `Unsupported parameters found in the decorator.`;
1283    this.transformLog.push({
1284      type: LogType.ERROR, message: errorMessage, pos: this.currentNode.getStart(),
1285      code: '10110005',
1286      description: 'InsightIntent Compiler Error',
1287      solutions: ['Remove any parameters that are not supported']
1288    });
1289    return undefined;
1290  }
1291
1292  private parseLiteralValue(node: ts.Node): StaticValue | undefined {
1293    if (ts.isStringLiteral(node)) {
1294      return node.text;
1295    }
1296    if (ts.isNumericLiteral(node)) {
1297      return parseFloat(node.text);
1298    }
1299    if (node.kind === ts.SyntaxKind.TrueKeyword) {
1300      return true;
1301    }
1302    if (node.kind === ts.SyntaxKind.FalseKeyword) {
1303      return false;
1304    }
1305    if (node.kind === ts.SyntaxKind.NullKeyword) {
1306      return null;
1307    }
1308    if (node.kind === ts.SyntaxKind.UndefinedKeyword) {
1309      return undefined;
1310    }
1311    return undefined;
1312  }
1313
1314  private processEnumElement(node: ts.PropertyAccessExpression): string {
1315    const enumValue: string = node?.getText().split('.').pop();
1316    const executeModeEnum: Map<string, string> = new Map();
1317    executeModeEnum.set('UI_ABILITY_FOREGROUND', '0');
1318    executeModeEnum.set('UI_ABILITY_BACKGROUND', '1');
1319    executeModeEnum.set('UI_EXTENSION_ABILITY', '2');
1320    executeModeEnum.set('SERVICE_EXTENSION_ABILITY', '3');
1321    const paramCategoryEnum: Map<string, string> = new Map();
1322    paramCategoryEnum.set('LINK', 'link');
1323    paramCategoryEnum.set('WANT', 'want');
1324    if (executeModeEnum.has(enumValue)) {
1325      return executeModeEnum.get(enumValue);
1326    } else if (paramCategoryEnum.has(enumValue)) {
1327      return paramCategoryEnum.get(enumValue);
1328    } else {
1329     const errorMessage: string = `Unsupported parameters found in the decorator.`;
1330      this.transformLog.push({
1331        type: LogType.ERROR,
1332        message: errorMessage,
1333        pos: this.currentNode.getStart(),
1334        code: '10110005',
1335        description: 'InsightIntent Compiler Error',
1336        solutions: ['Remove any parameters that are not supported']
1337      });
1338      return '';
1339    }
1340  }
1341
1342  private processObjectElements(elements: ts.ObjectLiteralExpression): { [key: string]: StaticValue } {
1343    const obj: { [key: string]: StaticValue } = {};
1344    for (const prop of elements.properties) {
1345      if (ts.isPropertyAssignment(prop)) {
1346        const key: string = this.parsePropertyKey(prop.name);
1347        const value: StaticValue = this.parseStaticObject(prop.initializer);
1348        if (key !== undefined && value !== undefined) {
1349          obj[key] = value;
1350        }
1351      }
1352
1353      if (ts.isSpreadAssignment(prop)) {
1354        const spreadObj: StaticValue = this.parseStaticObject(prop.expression);
1355        if (typeof spreadObj === 'object' && spreadObj !== null) {
1356          Object.assign(obj, spreadObj);
1357        }
1358      }
1359    }
1360    return obj;
1361  }
1362
1363  private processArrayElements(elements: readonly ts.Node[]): StaticValue[] {
1364    const parsedElements: StaticValue[] = [];
1365
1366    elements.forEach((element) => {
1367      if (ts.isSpreadElement(element)) {
1368        const spreadValue: StaticValue = this.parseStaticObject(element.expression);
1369        if (Array.isArray(spreadValue)) {
1370          parsedElements.push(...spreadValue);
1371        }
1372      } else {
1373        const value: StaticValue = this.parseStaticObject(element);
1374        parsedElements.push(value);
1375      }
1376    });
1377
1378    return parsedElements;
1379  }
1380
1381  private parsePropertyKey(node: ts.PropertyName): string | undefined {
1382    if (ts.isLiteralExpression(node)) {
1383      return node.text;
1384    }
1385
1386    if (ts.isIdentifier(node)) {
1387      return node.text;
1388    }
1389    return undefined;
1390  }
1391
1392  private processExecuteModeParam(intentObj: object): void {
1393    if (intentObj.executeMode) {
1394      intentObj.executeMode.forEach((item: string, index: number) => {
1395        if (item === '0') {
1396          intentObj.executeMode[index] = 'foreground';
1397        }
1398        if (item === '1') {
1399          intentObj.executeMode[index] = 'background';
1400        }
1401        if (item === '2') {
1402          intentObj.executeMode[index] = 'uiextension';
1403        }
1404        if (item === '3') {
1405          intentObj.executeMode[index] = 'serviceextension';
1406        }
1407      });
1408    }
1409  }
1410
1411  private collectSchemaInfo(intentObj: object): void {
1412    if (intentObj.schema) {
1413      const schemaPath: string = path.join(
1414        __dirname, '../../insight_intents/schema',
1415        `${intentObj.schema}_${intentObj.intentVersion}.json`
1416      );
1417      if (fs.existsSync(schemaPath)) {
1418        const schemaContent: string = fs.readFileSync(schemaPath, 'utf-8');
1419        const schemaObj: object = JSON.parse(schemaContent);
1420        intentObj.parameters = schemaObj.parameters;
1421        intentObj.llmDescription = schemaObj.llmDescription;
1422        intentObj.keywords = schemaObj.keywords;
1423        intentObj.intentName = schemaObj.intentName;
1424        intentObj.result = schemaObj.result;
1425        intentObj.domain = schemaObj.domain;
1426      }
1427    }
1428  }
1429
1430  private verifyInheritanceChain(): void {
1431    this.EntityHeritageClassSet.forEach(entityClassInfo => {
1432      if (!this.heritageClassSet.has(entityClassInfo)) {
1433        const errorMessage: string = `Classes decorated with @InsightIntentEntity must implement InsightIntent.IntentEntity.`;
1434        this.transformLog.push({
1435          type: LogType.ERROR,
1436          message: errorMessage,
1437          pos: this.currentNode.getStart(),
1438          code: '10110021',
1439          description: 'InsightIntent Compiler Error',
1440          solutions: ['Add the implementation or inherit from a base intent entity']
1441        });
1442        return;
1443      }
1444    });
1445  }
1446
1447  private schemaValidationRequiredRule(schemaData: Record<string, schemaVerifyType>, schemaObj: object): void {
1448    const reqData: Map<string, boolean> = new Map();
1449    schemaObj.required.forEach(key => reqData.set(key, true));
1450    if (schemaObj.properties) {
1451      const paramsSchema: object = schemaObj.properties;
1452      const keyArr: string[] = Object.keys(paramsSchema);
1453      keyArr.forEach(key => {
1454        if (!schemaData[key] && reqData.get(key)) {
1455          const errorMessage: string = `A required field in the class property is missing.`;
1456          this.transformLog.push({
1457            type: LogType.ERROR,
1458            message: errorMessage,
1459            pos: this.currentNode.getStart(),
1460            code: '10110008',
1461            description: 'InsightIntent Compiler Error',
1462            solutions: ['Add the required field as specified by the JSON Schema']
1463          });
1464          return;
1465        }
1466      });
1467    }
1468  }
1469
1470  private schemaPropertiesValidation(schemaData: Record<string, schemaVerifyType>, schemaObj: object): void {
1471    if (schemaObj.properties) {
1472      Object.entries(schemaObj.properties).forEach(([key, value]) => {
1473        if ((schemaData[key]?.type && value.type !== schemaData[key].type) ||
1474          value.type === 'object' && schemaData[key]?.isEntity === false) {
1475          const errorMessage: string = `The field type of the class property does not match the JSON Schema.`;
1476          this.transformLog.push({
1477            type: LogType.ERROR,
1478            message: errorMessage,
1479            pos: this.currentNode.getStart(),
1480            code: '10110009',
1481            description: 'InsightIntent Compiler Error',
1482            solutions: ['Correct the type to match the requirement']
1483          });
1484          return;
1485        }
1486      });
1487    }
1488  }
1489
1490  private schemaValidateRules(schemaData: Record<string, schemaVerifyType>, schemaObj: object): void {
1491    const schemaKeys: string[] = Object.keys(schemaData);
1492    if (schemaObj.oneOf) {
1493      let count: number = 0;
1494      const requiredOne: string[][] = schemaObj.oneOf.map(item => item.required);
1495      requiredOne.forEach(val => {
1496        const isContain: boolean = val.every((item): boolean => {
1497          return schemaKeys.includes(item);
1498        });
1499        if (isContain) {
1500          count++;
1501        }
1502      });
1503      if (count !== 1) {
1504        const errorMessage: string = `The class property parameter violates the oneOf/anyOf validation rules in the JSON Schema.`;
1505        this.transformLog.push({
1506          type: LogType.ERROR,
1507          message: errorMessage,
1508          pos: this.currentNode.getStart(),
1509          code: '10110010',
1510          description: 'InsightIntent Compiler Error',
1511          solutions: ['Modify it to satisfy the rules']
1512        });
1513        return;
1514      }
1515    }
1516    if (schemaObj.anyOf) {
1517      let count: number = 0;
1518      const requiredAny: string[][] = schemaObj.anyOf.map(item => item.required);
1519      requiredAny.forEach(val => {
1520        const isContain: boolean = val.every((item): boolean => {
1521          return schemaKeys.includes(item);
1522        });
1523        if (isContain) {
1524          count++;
1525        }
1526      });
1527      if (count === 0) {
1528        const errorMessage: string = `The class property parameter violates the oneOf/anyOf validation rules in the JSON Schema.`;
1529        this.transformLog.push({
1530          type: LogType.ERROR,
1531          message: errorMessage,
1532          pos: this.currentNode.getStart(),
1533          code: '10110010',
1534          description: 'InsightIntent Compiler Error',
1535          solutions: ['Modify it to satisfy the rules']
1536        });
1537        return;
1538      }
1539    }
1540  }
1541
1542  private schemaValidateSync(schemaData: Record<string, schemaVerifyType>, schemaObj: object): void {
1543    if (!schemaObj) {
1544      return;
1545    }
1546    if (schemaObj.additionalProperties === false) {
1547      this.schemaAdditionalPropertiesValidation(schemaData, schemaObj.properties);
1548    }
1549    if (schemaObj.items && schemaObj.items.type === 'array') {
1550      this.schemaValidateSync(schemaData, schemaObj.items.items);
1551    }
1552    if (schemaObj.type !== 'object') {
1553      const errorMessage: string = `The root type of the JSON Schema for Parameters must be object.`;
1554      this.transformLog.push({
1555        type: LogType.ERROR,
1556        message: errorMessage,
1557        pos: this.currentNode.getStart(),
1558        code: '10110007',
1559        description: 'InsightIntent Compiler Error',
1560        solutions: ['Change the top-level definition to {"type":"object", ...}']
1561      });
1562      return;
1563    }
1564    if (schemaObj.properties) {
1565      const items: string[] = Object.keys(schemaObj.properties);
1566      if (items.length === 1 && items[0].type === 'array') {
1567        this.schemaValidateSync(schemaData, items[0].items);
1568      } else {
1569        this.schemaPropertiesValidation(schemaData, schemaObj);
1570      }
1571    }
1572    if (schemaObj.required) {
1573      this.schemaValidationRequiredRule(schemaData, schemaObj);
1574    }
1575    this.schemaValidateRules(schemaData, schemaObj);
1576  }
1577
1578  private schemaAdditionalPropertiesValidation(schemaData: Record<string, schemaVerifyType>, schemaProps: object): void {
1579    for (const key of Object.keys(schemaData)) {
1580      if (!schemaProps[key]) {
1581        const errorMessage: string = `The class property includes parameters not defined in the JSON Schema.`;
1582        this.transformLog.push({
1583          type: LogType.ERROR,
1584          message: errorMessage,
1585          pos: this.currentNode.getStart(),
1586          code: '10110011',
1587          description: 'InsightIntent Compiler Error',
1588          solutions: ['Remove any extra parameters']
1589        });
1590        return;
1591      }
1592    }
1593  }
1594
1595  private processEntityOwnerMap(): void {
1596    for (const [intentName, entityClassNames] of this.entityOwnerMap.entries()) {
1597      const expandedClassNames = new Set<string>(entityClassNames);
1598      entityClassNames.forEach(className => {
1599        this.visitEntityHeritage(className, expandedClassNames);
1600      });
1601      if (expandedClassNames.size > entityClassNames.length) {
1602        this.entityOwnerMap.set(intentName, Array.from(expandedClassNames));
1603      }
1604    }
1605  }
1606
1607  private visitEntityHeritage(className: string, expandedClassNames: Set<string>): void {
1608    const parentClassName: string = this.EntityExtendsMap.get(className);
1609    if (parentClassName && !expandedClassNames.has(parentClassName)) {
1610      expandedClassNames.add(parentClassName);
1611      this.visitEntityHeritage(parentClassName, expandedClassNames);
1612    }
1613  }
1614
1615  private matchEntities(): void {
1616    if (this.entityMap.size === 0) {
1617      return;
1618    }
1619    this.processEntityOwnerMap();
1620    const intentNameMappingMap: Map<string, object> = new Map();
1621    this.intentData.forEach(data => {
1622      intentNameMappingMap.set(data.intentName, data);
1623    });
1624    for (const [intentName, entityClassNames] of this.entityOwnerMap.entries()) {
1625      const targetIntent: object = intentNameMappingMap.get(intentName);
1626      if (!targetIntent) {
1627        continue;
1628      }
1629      const matchedEntities: object[] = [];
1630      entityClassNames.forEach(entityClassName => {
1631        if (this.entityMap.has(entityClassName)) {
1632          matchedEntities.push(this.entityMap.get(entityClassName));
1633        }
1634      });
1635      if (matchedEntities.length !== 0) {
1636        targetIntent.entities = matchedEntities;
1637      }
1638    }
1639  }
1640
1641  // This method writes the parsed data to a file.
1642  public writeUserIntentJsonFile(harIntentDataObj: object, share: object): void {
1643    const cachePath: string =
1644      path.join(projectConfig.cachePath, 'insight_compile_cache.json'); // Compiled cache file
1645    if (!projectConfig.aceProfilePath || !(fs.existsSync(cachePath) || this.intentData.length > 0 || Object.keys(harIntentDataObj).length !== 0)) {
1646      return;
1647    }
1648    const mergedData: object = this.processIntentData(harIntentDataObj);
1649    const cacheSourceMapPath: string = path.join(projectConfig.aceProfilePath, 'insight_intent.json'); // The user's intents configuration file
1650    try {
1651      if (Object.keys(mergedData).length > 0) {
1652        const cacheContent: object = {
1653          'extractInsightIntents': this.intentData,
1654          'entityOwnerMap': Object.fromEntries(this.entityOwnerMap.entries()),
1655          'entityMap': Object.fromEntries(this.entityMap.entries()),
1656          'heritageClassSet': Object.fromEntries(this.heritageClassSet.entries()),
1657          'entityHeritageClassSet': Object.fromEntries(this.EntityHeritageClassSet.entries()),
1658          'entityExtendsMap': Object.fromEntries(this.EntityExtendsMap.entries())
1659        };
1660        fs.writeFileSync(cacheSourceMapPath, JSON.stringify(mergedData, null, 2), 'utf-8');
1661        fs.writeFileSync(cachePath, JSON.stringify(cacheContent, null, 2), 'utf-8');
1662      } else if (fs.existsSync(cacheSourceMapPath)) {
1663        fs.unlinkSync(cacheSourceMapPath);
1664      }
1665      const normalizedPath: string = path.normalize(projectConfig.aceProfilePath);
1666      const fullPath: string = path.join(normalizedPath, '../../../module.json');
1667      if (fs.existsSync(fullPath)) {
1668        const rawData: string = fs.readFileSync(fullPath, 'utf8');
1669        const jsonData: object = JSON.parse(rawData);
1670        if (jsonData?.module) {
1671          jsonData.module.hasInsightIntent = Object.keys(mergedData).length > 0 ? true : undefined;
1672        }
1673        const updatedJson: string = JSON.stringify(jsonData, null, 2);
1674        fs.writeFileSync(fullPath, updatedJson, 'utf8');
1675      }
1676    } catch (e) {
1677      const errorMessage: string = `Failed to write to the intent configuration file.`;
1678      this.transformLog.push({
1679        type: LogType.ERROR, message: errorMessage, pos: this.currentNode.getStart(),
1680        code: '10110025',
1681        description: 'InsightIntent Compiler Error',
1682        solutions: ['Check file permissions, free disk space, or restart DevEco Studio']
1683      });
1684      return;
1685    }
1686    const logger = share.getLogger('etsTransform');
1687    const hvigorLogger = share.getHvigorConsoleLogger?.(ABILITY_SUBSYSTEM_CODE);
1688    if (transformLog && transformLog.errors.length && !projectConfig.ignoreWarning) {
1689      emitLogInfo(logger, getTransformLog(transformLog), true, this.currentFilePath, hvigorLogger);
1690      resetLog();
1691    }
1692  }
1693
1694  private processUpdateEntities(cacheDataObj: object): void {
1695    const decoratorFileMapping: Set<string> = new Set(this.updatePageIntentObj.keys());
1696    if (cacheDataObj.entityOwnerMap && Object.keys(cacheDataObj.entityOwnerMap || {}).length > 0) {
1697      const cacheEntityOwnerMap: Map<string, string[]> = cacheDataObj.entityOwnerMap as Map<string, string[]>;
1698      for (const [intentName, entityClassNames] of Object.entries(cacheEntityOwnerMap)) {
1699        if (!this.entityOwnerMap.has(intentName)) {
1700          this.entityOwnerMap.set(intentName, entityClassNames);
1701        }
1702      }
1703    }
1704    if (cacheDataObj.entityMap && Object.keys(cacheDataObj.entityMap || {}).length > 0) {
1705      const cacheEntityMap: Map<string, object> = cacheDataObj.entityMap as Map<string, object>;
1706      for (const [className, entityObj] of Object.entries(cacheEntityMap)) {
1707        if (!decoratorFileMapping.has(entityObj.decoratorFile)) {
1708          this.entityMap.set(entityObj.className, entityObj);
1709        }
1710      }
1711    }
1712    this.processUpdateHeritageVerify(cacheDataObj);
1713    this.intentData.map(userIntent => {
1714      if (userIntent.entities) {
1715        delete userIntent.entities;
1716      }
1717    });
1718  }
1719
1720  private processUpdateHeritageVerify(cacheDataObj: object): void {
1721    const decoratorFileMapping: Set<string> = new Set(this.updatePageIntentObj.keys());
1722    if (cacheDataObj.heritageClassSet && Object.keys(cacheDataObj.heritageClassSet || {}).length > 0) {
1723      const cacheHeritageClassSet: Set<string> = cacheDataObj.heritageClassSet as Set<string>;
1724      for (const entityPathInfo of Object.values(cacheHeritageClassSet)) {
1725        const decoratorFilePath: string = entityPathInfo.split('_').pop();
1726        if (!decoratorFileMapping.has(decoratorFilePath)) {
1727          this.heritageClassSet.add(entityPathInfo);
1728        }
1729      }
1730    }
1731    if (cacheDataObj.entityHeritageClassSet && Object.keys(cacheDataObj.entityHeritageClassSet || {}).length > 0) {
1732      const cacheEntityExtendsMap: Set<string> = cacheDataObj.entityHeritageClassSet as Set<string>;
1733      for (const entityPathInfo of Object.values(cacheEntityExtendsMap)) {
1734        const decoratorFilePath: string = entityPathInfo.split('_').pop();
1735        if (decoratorFileMapping.has(decoratorFilePath)) {
1736          this.EntityHeritageClassSet.add(entityPathInfo);
1737        }
1738      }
1739    }
1740    if (cacheDataObj.entityExtendsMap && Object.keys(cacheDataObj.entityExtendsMap || {}).length > 0) {
1741      const cacheEntityExtendsMap: Map<string, string> = cacheDataObj.entityExtendsMap as Map<string, string>;
1742      for (const [baseClassName, parentClassName] of Object.entries(cacheEntityExtendsMap)) {
1743        if (!this.EntityExtendsMap.has(baseClassName)) {
1744          this.EntityExtendsMap.set(baseClassName, parentClassName);
1745        }
1746      }
1747    }
1748  }
1749
1750  private processIntentData(harIntentDataObj: object): object {
1751    const cacheSourceMapPath: string =
1752      path.join(projectConfig.aceProfilePath, 'insight_intent.json'); // The user's intents configuration file
1753    const cachePath: string = path.join(projectConfig.cachePath, 'insight_compile_cache.json'); // Compiled cache file
1754    if (!fs.existsSync(projectConfig.aceProfilePath)) {
1755      fs.mkdirSync(projectConfig.aceProfilePath, { recursive: true });
1756    }
1757    if (this.isUpdateCompile && fs.existsSync(cachePath)) {
1758      const cacheData: string = fs.readFileSync(cachePath, 'utf8');
1759      const cacheDataObj: object = JSON.parse(cacheData);
1760      const insightIntents: object[] = cacheDataObj.extractInsightIntents.filter(insightIntent => {
1761        return !this.updatePageIntentObj.has(insightIntent.decoratorFile);
1762      });
1763      this.updatePageIntentObj.forEach(insightIntent => {
1764        insightIntents.push(...insightIntent);
1765      });
1766      this.intentData = insightIntents;
1767      this.processUpdateEntities(cacheDataObj);
1768    }
1769    this.verifyInheritanceChain();
1770    this.matchEntities();
1771    let writeJsonData: object = {};
1772    if (fs.existsSync(cacheSourceMapPath)) {
1773      const originIntents: string = fs.readFileSync(cacheSourceMapPath, 'utf8');
1774      const jsonData: object = JSON.parse(originIntents);
1775      Object.assign(jsonData, {
1776        'extractInsightIntents': this.intentData
1777      });
1778      writeJsonData = jsonData;
1779    } else if (this.intentData.length > 0) {
1780      Object.assign(writeJsonData, {
1781        'extractInsightIntents': this.intentData
1782      });
1783    }
1784    const mergedData: object = this.mergeHarData(writeJsonData, harIntentDataObj);
1785    this.validateIntentIntentName(mergedData);
1786    return mergedData;
1787  }
1788
1789  private mergeHarData(writeJsonData: object, harIntentDataObj: object): object {
1790    let mergedData: object = {};
1791    if (writeJsonData) {
1792      mergedData = JSON.parse(JSON.stringify(writeJsonData));
1793    }
1794    Object.keys(harIntentDataObj || {})?.forEach(harName => {
1795      if (harIntentDataObj[harName].extractInsightIntents) {
1796        harIntentDataObj[harName].extractInsightIntents.forEach(intentObj => {
1797          intentObj.moduleName = projectConfig.moduleName;
1798          intentObj.bundleName = projectConfig.bundleName;
1799        });
1800        if (harIntentDataObj[harName].extractInsightIntents) {
1801          mergedData.extractInsightIntents?.push(...harIntentDataObj[harName].extractInsightIntents);
1802        }
1803      }
1804    });
1805    return mergedData;
1806  }
1807
1808  // This method get the user's intents from the bytecode HAR package.
1809  public getHarData(): object {
1810    const harIntentDataObj: object = {};
1811    if (fs.existsSync(projectConfig.aceBuildJson)) {
1812      const loaderJson: string = fs.readFileSync(projectConfig.aceBuildJson, 'utf8');
1813      const { byteCodeHarInfo } = JSON.parse(loaderJson);
1814      Object.keys(byteCodeHarInfo || {})?.forEach((harName) => {
1815        const harAbcFilePath = byteCodeHarInfo[harName].abcPath as string;
1816        const harModulePath: string = harAbcFilePath.split('ets')[0];
1817        const harSourcePath: string = path.join(harModulePath, 'src', 'main', 'resources', 'base', 'profile');
1818        const intentDataSourcePath: string = path.join(harSourcePath, 'insight_intent.json');
1819        let harIntentData: object = {};
1820        if (fs.existsSync(intentDataSourcePath)) {
1821          harIntentData = JSON.parse(fs.readFileSync(intentDataSourcePath, 'utf8')) as object;
1822        }
1823        Object.assign(harIntentDataObj, {
1824          harName: harIntentData
1825        });
1826      });
1827    }
1828    return harIntentDataObj;
1829  }
1830
1831  private validateIntentIntentName(writeJsonData: object): void {
1832    const duplicates = new Set<string>();
1833    writeJsonData.insightIntents?.forEach(insightIntent => {
1834      duplicates.add(insightIntent.intentName);
1835    });
1836    writeJsonData.extractInsightIntents?.forEach(item => {
1837      if (duplicates.has(item.intentName)) {
1838        const errorMessage: string = `Duplicate intentName definitions found.`;
1839        this.transformLog.push({
1840          type: LogType.ERROR,
1841          message: errorMessage,
1842          pos: this.currentNode.getStart(),
1843          code: '10110012',
1844          description: 'InsightIntent Compiler Error',
1845          solutions: ['Rename or remove duplicate entries']
1846        });
1847        return;
1848      } else if (item.intentName !== undefined) {
1849        duplicates.add(item.intentName);
1850      }
1851    });
1852  }
1853
1854  public clear(): void {
1855    this.intentData = [];
1856    this.checker = null;
1857    this.currentFilePath = '';
1858    this.heritageClassSet = new Set<string>();
1859    this.heritageClassSet.add('IntentEntity_sdk');
1860    this.heritageClassSet.add('InsightIntentEntryExecutor_sdk');
1861    this.isInitCache = false;
1862    this.isUpdateCompile = true;
1863    this.updatePageIntentObj = new Map();
1864    this.entityMap = new Map();
1865    this.entityOwnerMap = new Map();
1866    this.moduleJsonInfo = new Map();
1867    this.EntityHeritageClassSet = new Set();
1868    this.EntityExtendsMap = new Map();
1869  }
1870}
1871
1872export default new ParseIntent();
1873