• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2021 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 from 'typescript';
17import fs from 'fs';
18import path from 'path';
19import JSON5 from 'json5';
20
21import {
22  EXTNAME_ETS,
23  EXTNAME_TS,
24  INDEX_ETS,
25  INDEX_TS,
26  CUSTOM_COMPONENT_DEFAULT,
27  CUSTOM_DECORATOR_NAME,
28  COMPONENT_DECORATOR_ENTRY,
29  COMPONENT_BUILDER_DECORATOR,
30  DECORATOR_REUSEABLE,
31  DECORATOR_REUSABLE_V2
32} from './pre_define';
33import {
34  propertyCollection,
35  linkCollection,
36  componentCollection,
37  preprocessExtend,
38  preprocessNewExtend,
39  processSystemApi,
40  propCollection,
41  isObservedClass,
42  isCustomDialogClass,
43  observedClassCollection,
44  enumCollection,
45  getComponentSet,
46  IComponentSet,
47  builderParamObjectCollection,
48  stateCollection,
49  regularCollection,
50  storagePropCollection,
51  storageLinkCollection,
52  provideCollection,
53  consumeCollection,
54  objectLinkCollection,
55  localStorageLinkCollection,
56  localStoragePropCollection,
57  builderParamInitialization,
58  propInitialization,
59  regularInitialization,
60  stateInitialization,
61  provideInitialization,
62  privateCollection,
63  regularStaticCollection
64} from './validate_ui_syntax';
65import {
66  CurrentProcessFile,
67  getExtensionIfUnfullySpecifiedFilepath,
68  hasDecorator,
69  LogInfo,
70  LogType,
71  storedFileInfo
72} from './utils';
73import {
74  projectConfig,
75  sdkConfigs,
76  sdkConfigPrefix,
77  globalProgram
78} from '../main';
79import {
80  CUSTOM_BUILDER_METHOD,
81  INNER_COMPONENT_NAMES,
82  GLOBAL_CUSTOM_BUILDER_METHOD
83} from './component_map';
84import {
85  type ResolveModuleInfo,
86  SOURCE_FILES
87} from './ets_checker';
88import {
89  getRealModulePath,
90  validateModuleSpecifier
91} from './fast_build/system_api/api_check_utils';
92import processStructComponentV2, { StructInfo } from './process_struct_componentV2';
93
94const IMPORT_FILE_ASTCACHE: Map<string, ts.SourceFile> =
95  process.env.watchMode === 'true' ? new Map() : (SOURCE_FILES || new Map());
96
97export default function processImport(node: ts.ImportDeclaration | ts.ImportEqualsDeclaration |
98  ts.ExportDeclaration, pagesDir: string, log: LogInfo[], asName: Map<string, string> = new Map(),
99  isEntryPage: boolean = true, pathCollection: Set<string> = new Set()): void {
100  let filePath: string;
101  let defaultName: string;
102  if (ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) {
103    filePath = node.moduleSpecifier.getText().replace(/'|"/g, '');
104    if (ts.isImportDeclaration(node) && node.importClause && node.importClause.name &&
105      ts.isIdentifier(node.importClause.name)) {
106      defaultName = node.importClause.name.escapedText.toString();
107      if (isEntryPage) {
108        asName.set(defaultName, defaultName);
109      }
110    }
111    if (ts.isImportDeclaration(node) && node.importClause && node.importClause.namedBindings &&
112      ts.isNamedImports(node.importClause.namedBindings) &&
113      node.importClause.namedBindings.elements && isEntryPage) {
114      validateModuleSpecifier(node.moduleSpecifier, log);
115      node.importClause.namedBindings.elements.forEach(item => {
116        if (item.name && ts.isIdentifier(item.name)) {
117          validateModuleName(item.name, log);
118          if (item.propertyName && ts.isIdentifier(item.propertyName) && asName) {
119            asName.set(item.propertyName.escapedText.toString(), item.name.escapedText.toString());
120          } else {
121            asName.set(item.name.escapedText.toString(), item.name.escapedText.toString());
122          }
123        }
124      });
125    }
126  } else {
127    if (node.moduleReference && ts.isExternalModuleReference(node.moduleReference) &&
128      node.moduleReference.expression && ts.isStringLiteral(node.moduleReference.expression)) {
129      filePath = node.moduleReference.expression.text;
130      defaultName = node.name.escapedText.toString();
131      if (isEntryPage) {
132        asName.set(defaultName, defaultName);
133      }
134    }
135  }
136
137  try {
138    const fileResolvePath: string = getFileFullPath(filePath, pagesDir);
139    if (fs.existsSync(fileResolvePath) && fs.statSync(fileResolvePath).isFile() &&
140      !pathCollection.has(fileResolvePath)) {
141      let sourceFile: ts.SourceFile;
142      pathCollection.add(fileResolvePath);
143      if (IMPORT_FILE_ASTCACHE.has(fileResolvePath)) {
144        sourceFile = IMPORT_FILE_ASTCACHE.get(fileResolvePath);
145      } else {
146        sourceFile = generateSourceFileAST(fileResolvePath, filePath);
147        IMPORT_FILE_ASTCACHE[fileResolvePath] = sourceFile;
148      }
149      visitAllNode(sourceFile, sourceFile, defaultName, asName, path.dirname(fileResolvePath), log,
150        new Set(), new Set(), new Set(), new Map(), pathCollection, fileResolvePath, /\.d\.ets$/.test(fileResolvePath));
151    }
152  } catch (e) {
153    // ignore
154  }
155}
156
157function generateSourceFileAST(fileResolvePath: string, filePath: string): ts.SourceFile {
158  const originContent: string = fs.readFileSync(fileResolvePath, { encoding: 'utf-8' });
159  const content: string = path.extname(fileResolvePath) === EXTNAME_ETS ?
160    preprocessNewExtend(preprocessExtend(processSystemApi(originContent))) : originContent;
161  return ts.createSourceFile(fileResolvePath, content, ts.ScriptTarget.Latest, true, ts.ScriptKind.ETS);
162}
163
164type structDecoratorResult = {
165  hasRecycle: boolean
166};
167
168const MODIFIER_LENGTH: number = 2;
169
170function visitAllNode(node: ts.Node, sourceFile: ts.SourceFile, defaultNameFromParent: string,
171  asNameFromParent: Map<string, string>, pagesDir: string, log: LogInfo[], entryCollection: Set<string>,
172  exportCollection: Set<string>, defaultCollection: Set<string>, asExportCollection: Map<string, string>,
173  pathCollection: Set<string>, fileResolvePath: string, isDETS: boolean): void {
174  if (isObservedClass(node)) {
175    collectSpecialFunctionNode(node as ts.ClassDeclaration, asNameFromParent, defaultNameFromParent, defaultCollection,
176      asExportCollection, observedClassCollection);
177    // @ts-ignore
178    observedClassCollection.add(node.name.getText());
179  }
180  if (isCustomDialogClass(node)) {
181    collectSpecialFunctionNode(node as ts.StructDeclaration, asNameFromParent, defaultNameFromParent, defaultCollection,
182      asExportCollection, componentCollection.customDialogs);
183    // @ts-ignore
184    componentCollection.customDialogs.add(node.name.getText());
185  }
186  if (ts.isEnumDeclaration(node) && node.name) {
187    enumCollection.add(node.name.getText());
188  }
189  const structDecorator: structDecoratorResult = { hasRecycle: false };
190  if (ts.isStructDeclaration(node) && ts.isIdentifier(node.name) && isCustomComponent(node, structDecorator)) {
191    addDependencies(node, defaultNameFromParent, asNameFromParent, isDETS, structDecorator);
192    isExportEntry(node, log, entryCollection, exportCollection, defaultCollection, fileResolvePath, sourceFile);
193    if (asExportCollection.has(node.name.getText())) {
194      componentCollection.customComponents.add(asExportCollection.get(node.name.getText()));
195      if (isDETS) {
196        storedFileInfo.getCurrentArkTsFile().compFromDETS.add(asExportCollection.get(node.name.getText()));
197      }
198      if (structDecorator.hasRecycle) {
199        storedFileInfo.getCurrentArkTsFile().recycleComponents.add(asExportCollection.get(node.name.getText()));
200      }
201    }
202    const modifiers: readonly ts.Modifier[] =
203      ts.canHaveModifiers(node) ? ts.getModifiers(node) : undefined;
204    if (modifiers && modifiers.length >= MODIFIER_LENGTH && modifiers[0] &&
205      modifiers[0].kind === ts.SyntaxKind.ExportKeyword && modifiers[1] &&
206      modifiers[1].kind === ts.SyntaxKind.DefaultKeyword) {
207      if (!defaultNameFromParent && hasCollection(node.name)) {
208        addDefaultExport(node, isDETS, structDecorator);
209      } else if (defaultNameFromParent && asNameFromParent.has(defaultNameFromParent)) {
210        componentCollection.customComponents.add(asNameFromParent.get(defaultNameFromParent));
211        if (isDETS) {
212          storedFileInfo.getCurrentArkTsFile().compFromDETS.add(asNameFromParent.get(defaultNameFromParent));
213        }
214        if (structDecorator.hasRecycle) {
215          storedFileInfo.getCurrentArkTsFile().recycleComponents.add(asNameFromParent.get(defaultNameFromParent));
216        }
217      }
218    }
219    if (defaultCollection.has(node.name.getText())) {
220      componentCollection.customComponents.add(CUSTOM_COMPONENT_DEFAULT);
221      if (isDETS) {
222        storedFileInfo.getCurrentArkTsFile().compFromDETS.add(CUSTOM_COMPONENT_DEFAULT);
223      }
224      if (structDecorator.hasRecycle) {
225        storedFileInfo.getCurrentArkTsFile().recycleComponents.add(CUSTOM_COMPONENT_DEFAULT);
226      }
227    }
228  }
229  if (ts.isFunctionDeclaration(node) && hasDecorator(node, COMPONENT_BUILDER_DECORATOR)) {
230    collectSpecialFunctionNode(node, asNameFromParent, defaultNameFromParent, defaultCollection,
231      asExportCollection, CUSTOM_BUILDER_METHOD);
232    collectSpecialFunctionNode(node, asNameFromParent, defaultNameFromParent, defaultCollection,
233      asExportCollection, GLOBAL_CUSTOM_BUILDER_METHOD);
234  }
235  if (ts.isExportAssignment(node) && node.expression && ts.isIdentifier(node.expression) &&
236    hasCollection(node.expression)) {
237    if (defaultNameFromParent) {
238      const propertiesName: string = node.expression.escapedText.toString();
239      setDependencies(defaultNameFromParent, undefined, linkCollection.get(propertiesName),
240        propertyCollection.get(propertiesName), propCollection.get(propertiesName),
241        builderParamObjectCollection.get(propertiesName), stateCollection.get(propertiesName),
242        regularCollection.get(propertiesName), storagePropCollection.get(propertiesName),
243        storageLinkCollection.get(propertiesName), provideCollection.get(propertiesName),
244        consumeCollection.get(propertiesName), objectLinkCollection.get(propertiesName),
245        localStorageLinkCollection.get(propertiesName), localStoragePropCollection.get(propertiesName),
246        builderParamInitialization.get(propertiesName), propInitialization.get(propertiesName), isDETS,
247        structDecorator);
248    }
249    addDefaultExport(node, isDETS, structDecorator);
250  }
251  if (ts.isExportAssignment(node) && node.expression && ts.isIdentifier(node.expression)) {
252    if (defaultNameFromParent) {
253      asNameFromParent.set(node.expression.getText(), asNameFromParent.get(defaultNameFromParent));
254    }
255    defaultCollection.add(node.expression.getText());
256  }
257  if (ts.isExportDeclaration(node) && node.exportClause &&
258    ts.isNamedExports(node.exportClause) && node.exportClause.elements) {
259    node.exportClause.elements.forEach(item => {
260      if (process.env.watchMode === 'true') {
261        exportCollection.add((item.propertyName ? item.propertyName : item.name).escapedText.toString());
262      }
263      if (item.name && ts.isIdentifier(item.name)) {
264        if (!item.propertyName) {
265          asExportCollection.set(item.name.escapedText.toString(), item.name.escapedText.toString());
266        } else if (item.propertyName && ts.isIdentifier(item.propertyName)) {
267          validateModuleName(item.name, log, sourceFile, fileResolvePath);
268          if (hasCollection(item.propertyName)) {
269            let asExportName: string = item.name.escapedText.toString();
270            const asExportPropertyName: string = item.propertyName.escapedText.toString();
271            if (asNameFromParent.has(asExportName)) {
272              asExportName = asNameFromParent.get(asExportName);
273            }
274            setDependencies(asExportName, undefined, linkCollection.get(asExportPropertyName),
275              propertyCollection.get(asExportPropertyName),
276              propCollection.get(asExportPropertyName),
277              builderParamObjectCollection.get(asExportPropertyName),
278              stateCollection.get(asExportPropertyName), regularCollection.get(asExportPropertyName),
279              storagePropCollection.get(asExportPropertyName), storageLinkCollection.get(asExportPropertyName),
280              provideCollection.get(asExportPropertyName), consumeCollection.get(asExportPropertyName),
281              objectLinkCollection.get(asExportPropertyName), localStorageLinkCollection.get(asExportPropertyName),
282              localStoragePropCollection.get(asExportPropertyName), builderParamInitialization.get(asExportPropertyName),
283              propInitialization.get(asExportPropertyName), isDETS, structDecorator);
284          }
285          asExportCollection.set(item.propertyName.escapedText.toString(), item.name.escapedText.toString());
286        }
287      }
288      if (item.name && ts.isIdentifier(item.name) && asNameFromParent.has(item.name.escapedText.toString()) &&
289        item.propertyName && ts.isIdentifier(item.propertyName)) {
290        asNameFromParent.set(item.propertyName.escapedText.toString(),
291          asNameFromParent.get(item.name.escapedText.toString()));
292      }
293    });
294  }
295  if (ts.isExportDeclaration(node) && node.moduleSpecifier &&
296    ts.isStringLiteral(node.moduleSpecifier)) {
297    if (process.env.watchMode === 'true' && node.exportClause && ts.isNamedExports(node.exportClause) &&
298      node.exportClause.elements) {
299      node.exportClause.elements.forEach(item => {
300        exportCollection.add((item.propertyName ? item.propertyName : item.name).escapedText.toString());
301        if (item.propertyName && ts.isIdentifier(item.propertyName) && item.name &&
302          ts.isIdentifier(item.name) && asNameFromParent.has(item.name.escapedText.toString())) {
303          asNameFromParent.set(item.propertyName.escapedText.toString(),
304            asNameFromParent.get(item.name.escapedText.toString()));
305          defaultCollection.add(item.name.escapedText.toString());
306        }
307      });
308    }
309    processImport(node, pagesDir, log, asNameFromParent, true, new Set(pathCollection));
310  }
311  if (ts.isImportDeclaration(node)) {
312    if (node.importClause && node.importClause.name && ts.isIdentifier(node.importClause.name) &&
313      asNameFromParent.has(node.importClause.name.getText())) {
314      processImport(node, pagesDir, log, asNameFromParent, false, new Set(pathCollection));
315    } else if (node.importClause && node.importClause.namedBindings &&
316      ts.isNamedImports(node.importClause.namedBindings) && node.importClause.namedBindings.elements) {
317      let nested: boolean = false;
318      node.importClause.namedBindings.elements.forEach(item => {
319        if (item.name && ts.isIdentifier(item.name) && asNameFromParent.has(item.name.escapedText.toString())) {
320          nested = true;
321          if (item.propertyName && ts.isIdentifier(item.propertyName)) {
322            asNameFromParent.set(item.propertyName.escapedText.toString(),
323              asNameFromParent.get(item.name.escapedText.toString()));
324          }
325        }
326      });
327      if (nested) {
328        processImport(node, pagesDir, log, asNameFromParent, false, new Set(pathCollection));
329      }
330    }
331  }
332  node.getChildren().reverse().forEach((item: ts.Node) => visitAllNode(item, sourceFile,
333    defaultNameFromParent, asNameFromParent, pagesDir, log, entryCollection, exportCollection,
334    defaultCollection, asExportCollection, pathCollection, fileResolvePath, isDETS));
335}
336
337function collectSpecialFunctionNode(node: ts.FunctionDeclaration | ts.ClassDeclaration | ts.StructDeclaration,
338  asNameFromParent: Map<string, string>, defaultNameFromParent: string, defaultCollection: Set<string>,
339  asExportCollection: Map<string, string>, collection: Set<string>): void {
340  const name: string = node.name.getText();
341  const modifiers: readonly ts.Modifier[] = ts.canHaveModifiers(node) ? ts.getModifiers(node) : undefined;
342  if (asNameFromParent.has(name)) {
343    collection.add(asNameFromParent.get(name));
344  } else if (modifiers && modifiers.length >= 1 && modifiers[0] &&
345    modifiers[0].kind === ts.SyntaxKind.ExportKeyword) {
346    if (modifiers.length === 1) {
347      collection.add(name);
348    } else if (modifiers.length >= MODIFIER_LENGTH && modifiers[1] && modifiers[1].kind ===
349      ts.SyntaxKind.DefaultKeyword) {
350      collection.add(CUSTOM_COMPONENT_DEFAULT);
351      if (defaultNameFromParent && asNameFromParent.has(defaultNameFromParent)) {
352        collection.add(asNameFromParent.get(defaultNameFromParent));
353      }
354    }
355  } else if (defaultCollection.has(name)) {
356    collection.add(CUSTOM_COMPONENT_DEFAULT);
357  } else if (asExportCollection.has(name)) {
358    collection.add(asExportCollection.get(name));
359  }
360}
361
362function isExportEntry(node: ts.StructDeclaration, log: LogInfo[], entryCollection: Set<string>,
363  exportCollection: Set<string>, defaultCollection: Set<string>, fileResolvePath: string,
364  sourceFile: ts.SourceFile): void {
365  const decorators: readonly ts.Decorator[] = ts.getAllDecorators(node);
366  if (process.env.watchMode === 'true' && node && decorators) {
367    let existExport: boolean = false;
368    let existEntry: boolean = false;
369    const modifiers: readonly ts.Modifier[] = ts.canHaveModifiers(node) ? ts.getModifiers(node) : undefined;
370    if (modifiers) {
371      for (let i = 0; i < modifiers.length; i++) {
372        if (modifiers[i].kind === ts.SyntaxKind.ExportKeyword) {
373          existExport = true;
374          break;
375        }
376      }
377    }
378    for (let i = 0; i < decorators.length; i++) {
379      if (decorators[i].getText() === COMPONENT_DECORATOR_ENTRY) {
380        entryCollection.add(node.name.escapedText.toString());
381        existEntry = true;
382        break;
383      }
384    }
385  }
386}
387
388function addDependencies(node: ts.StructDeclaration, defaultNameFromParent: string,
389  asNameFromParent: Map<string, string>, isDETS: boolean, structDecorator: structDecoratorResult): void {
390  const componentName: string = node.name.getText();
391  const ComponentSet: IComponentSet = getComponentSet(node, false);
392  const modifiers: readonly ts.Modifier[] = ts.canHaveModifiers(node) ? ts.getModifiers(node) : undefined;
393  if (defaultNameFromParent && modifiers && modifiers.length >= MODIFIER_LENGTH && modifiers[0] &&
394    modifiers[1] && modifiers[0].kind === ts.SyntaxKind.ExportKeyword &&
395    modifiers[1].kind === ts.SyntaxKind.DefaultKeyword) {
396    setDependencies(defaultNameFromParent, undefined, ComponentSet.links, ComponentSet.properties,
397      ComponentSet.props, ComponentSet.builderParams, ComponentSet.states, ComponentSet.regulars,
398      ComponentSet.storageProps, ComponentSet.storageLinks, ComponentSet.provides,
399      ComponentSet.consumes, ComponentSet.objectLinks, ComponentSet.localStorageLink,
400      ComponentSet.localStorageProp, ComponentSet.builderParamData, ComponentSet.propData, isDETS,
401      structDecorator);
402  } else if (asNameFromParent.has(componentName)) {
403    setDependencies(asNameFromParent.get(componentName), undefined, ComponentSet.links, ComponentSet.properties,
404      ComponentSet.props, ComponentSet.builderParams, ComponentSet.states, ComponentSet.regulars,
405      ComponentSet.storageProps, ComponentSet.storageLinks, ComponentSet.provides,
406      ComponentSet.consumes, ComponentSet.objectLinks, ComponentSet.localStorageLink,
407      ComponentSet.localStorageProp, ComponentSet.builderParamData, ComponentSet.propData, isDETS,
408      structDecorator);
409  } else {
410    setDependencies(componentName, undefined, ComponentSet.links, ComponentSet.properties, ComponentSet.props,
411      ComponentSet.builderParams, ComponentSet.states, ComponentSet.regulars,
412      ComponentSet.storageProps, ComponentSet.storageLinks, ComponentSet.provides,
413      ComponentSet.consumes, ComponentSet.objectLinks, ComponentSet.localStorageLink,
414      ComponentSet.localStorageProp, ComponentSet.builderParamData, ComponentSet.propData, isDETS,
415      structDecorator);
416  }
417}
418
419function addDefaultExport(node: ts.StructDeclaration | ts.ExportAssignment, isDETS: boolean,
420  structDecorator: structDecoratorResult): void {
421  let name: string;
422  if (ts.isStructDeclaration(node) && node.name && ts.isIdentifier(node.name)) {
423    name = node.name.escapedText.toString();
424  } else if (ts.isExportAssignment(node) && node.expression && ts.isIdentifier(node.expression)) {
425    name = node.expression.escapedText.toString();
426  } else {
427    return;
428  }
429  setDependencies(CUSTOM_COMPONENT_DEFAULT, undefined,
430    linkCollection.has(CUSTOM_COMPONENT_DEFAULT) ?
431      new Set([...linkCollection.get(CUSTOM_COMPONENT_DEFAULT), ...linkCollection.get(name)]) :
432      linkCollection.get(name),
433    propertyCollection.has(CUSTOM_COMPONENT_DEFAULT) ?
434      new Set([...propertyCollection.get(CUSTOM_COMPONENT_DEFAULT),
435        ...propertyCollection.get(name)]) : propertyCollection.get(name),
436    propCollection.has(CUSTOM_COMPONENT_DEFAULT) ?
437      new Set([...propCollection.get(CUSTOM_COMPONENT_DEFAULT), ...propCollection.get(name)]) :
438      propCollection.get(name),
439    builderParamObjectCollection.has(CUSTOM_COMPONENT_DEFAULT) ?
440      new Set([...builderParamObjectCollection.get(CUSTOM_COMPONENT_DEFAULT),
441        ...builderParamObjectCollection.get(name)]) : builderParamObjectCollection.get(name),
442    stateCollection.has(CUSTOM_COMPONENT_DEFAULT) ?
443      new Set([...stateCollection.get(CUSTOM_COMPONENT_DEFAULT),
444        ...stateCollection.get(name)]) : stateCollection.get(name),
445    regularCollection.has(CUSTOM_COMPONENT_DEFAULT) ?
446      new Set([...regularCollection.get(CUSTOM_COMPONENT_DEFAULT),
447        ...regularCollection.get(name)]) : regularCollection.get(name),
448    storagePropCollection.has(CUSTOM_COMPONENT_DEFAULT) ?
449      new Set([...storagePropCollection.get(CUSTOM_COMPONENT_DEFAULT),
450        ...storagePropCollection.get(name)]) : storagePropCollection.get(name),
451    storageLinkCollection.has(CUSTOM_COMPONENT_DEFAULT) ?
452      new Set([...storageLinkCollection.get(CUSTOM_COMPONENT_DEFAULT),
453        ...storageLinkCollection.get(name)]) : storageLinkCollection.get(name),
454    provideCollection.has(CUSTOM_COMPONENT_DEFAULT) ?
455      new Set([...provideCollection.get(CUSTOM_COMPONENT_DEFAULT),
456        ...provideCollection.get(name)]) : provideCollection.get(name),
457    consumeCollection.has(CUSTOM_COMPONENT_DEFAULT) ?
458      new Set([...consumeCollection.get(CUSTOM_COMPONENT_DEFAULT),
459        ...consumeCollection.get(name)]) : consumeCollection.get(name),
460    objectLinkCollection.has(CUSTOM_COMPONENT_DEFAULT) ?
461      new Set([...objectLinkCollection.get(CUSTOM_COMPONENT_DEFAULT),
462        ...objectLinkCollection.get(name)]) : objectLinkCollection.get(name),
463    getNewLocalStorageMap(localStorageLinkCollection, name),
464    getNewLocalStorageMap(localStoragePropCollection, name),
465    builderParamInitialization.has(CUSTOM_COMPONENT_DEFAULT) ?
466      new Set([...builderParamInitialization.get(CUSTOM_COMPONENT_DEFAULT),
467        ...builderParamInitialization.get(name)]) : builderParamInitialization.get(name),
468    propInitialization.has(CUSTOM_COMPONENT_DEFAULT) ?
469      new Set([...propInitialization.get(CUSTOM_COMPONENT_DEFAULT),
470        ...propInitialization.get(name)]) : propInitialization.get(name), isDETS,
471    structDecorator
472  );
473}
474
475function getNewLocalStorageMap(collection: Map<string, Map<string, Set<string>>>, name: string)
476  : Map<string, Set<string>> {
477  let localStorageLinkMap: Map<string, Set<string>> = new Map();
478  if (collection.has(CUSTOM_COMPONENT_DEFAULT)) {
479    const tempSet: Set<string> = new Set();
480    if (collection.get(CUSTOM_COMPONENT_DEFAULT)) {
481      for (const key of collection.get(CUSTOM_COMPONENT_DEFAULT).keys()) {
482        tempSet.add(key);
483      }
484    }
485    if (collection.get(name)) {
486      for (const key of collection.get(name).keys()) {
487        tempSet.add(key);
488      }
489    }
490    localStorageLinkMap.set(name, tempSet);
491  } else {
492    localStorageLinkMap = collection.get(name);
493  }
494  return localStorageLinkMap;
495}
496
497function setDependencies(component: string, asComponentName: string, linkArray: Set<string>, propertyArray: Set<string>,
498  propArray: Set<string>, builderParamArray: Set<string>, stateArray: Set<string>,
499  regularArray: Set<string>, storagePropsArray: Set<string>, storageLinksArray: Set<string>,
500  providesArray: Set<string>, consumesArray: Set<string>, objectLinksArray: Set<string>,
501  localStorageLinkMap: Map<string, Set<string>>, localStoragePropMap: Map<string, Set<string>>,
502  builderParamData: Set<string>, propData: Set<string>, isDETS: boolean,
503  structDecorator: structDecoratorResult): void {
504  if (asComponentName) {
505    linkCollection.set(asComponentName, linkArray);
506    storedFileInfo.overallLinkCollection.set(asComponentName, linkArray);
507  } else if (!asComponentName && component) {
508    linkCollection.set(component, linkArray);
509    if (projectConfig.compileMode === 'esmodule' && process.env.compileTool === 'rollup') {
510      storedFileInfo.overallLinkCollection.set(component, linkArray);
511    }
512  }
513  propertyCollection.set(component, propertyArray);
514  if (!propCollection.get(component)) {
515    propCollection.set(component, propArray);
516  }
517  if (asComponentName) {
518    storedFileInfo.overallBuilderParamCollection.set(asComponentName, builderParamArray);
519  } else if (!asComponentName && component && projectConfig.compileMode === 'esmodule' &&
520    process.env.compileTool === 'rollup') {
521    storedFileInfo.overallBuilderParamCollection.set(component, builderParamArray);
522  }
523  builderParamObjectCollection.set(component, builderParamArray);
524  componentCollection.customComponents.add(component);
525  if (isDETS) {
526    storedFileInfo.getCurrentArkTsFile().compFromDETS.add(component);
527  }
528  if (structDecorator.hasRecycle) {
529    storedFileInfo.getCurrentArkTsFile().recycleComponents.add(component);
530  }
531  stateCollection.set(component, stateArray);
532  regularCollection.set(component, regularArray);
533  storagePropCollection.set(component, storagePropsArray);
534  storageLinkCollection.set(component, storageLinksArray);
535  provideCollection.set(component, providesArray);
536  consumeCollection.set(component, consumesArray);
537  if (asComponentName) {
538    storedFileInfo.overallObjectLinkCollection.set(asComponentName, objectLinksArray);
539  } else if (!asComponentName && component && projectConfig.compileMode === 'esmodule' &&
540    process.env.compileTool === 'rollup') {
541    storedFileInfo.overallObjectLinkCollection.set(component, objectLinksArray);
542  }
543  objectLinkCollection.set(component, objectLinksArray);
544  localStorageLinkCollection.set(component, localStorageLinkMap);
545  localStoragePropCollection.set(component, localStoragePropMap);
546  if (!builderParamInitialization.get(component)) {
547    builderParamInitialization.set(component, builderParamData);
548  }
549  if (!propInitialization.get(component)) {
550    propInitialization.set(component, propData);
551  }
552}
553
554function hasCollection(node: ts.Identifier): boolean {
555  const name: string = node.escapedText.toString();
556  return linkCollection.has(name) ||
557    propCollection.has(name) ||
558    propertyCollection.has(name) ||
559    builderParamObjectCollection.has(name) ||
560    stateCollection.has(name) ||
561    regularCollection.has(name) ||
562    storagePropCollection.has(name) ||
563    storageLinkCollection.has(name) ||
564    provideCollection.has(name) ||
565    consumeCollection.has(name) ||
566    objectLinkCollection.has(name) ||
567    localStorageLinkCollection.has(name) ||
568    localStoragePropCollection.has(name);
569}
570
571function isModule(filePath: string): boolean {
572  return !/^(\.|\.\.)?\//.test(filePath) || filePath.indexOf(projectConfig.packageDir) > -1;
573}
574
575function isCustomComponent(node: ts.StructDeclaration, structDecorator: structDecoratorResult): boolean {
576  let isComponent: boolean = false;
577  const decorators: readonly ts.Decorator[] = ts.getAllDecorators(node);
578  if (decorators && decorators.length) {
579    for (let i = 0; i < decorators.length; ++i) {
580      const decoratorName: ts.Expression = decorators[i].expression;
581      if (ts.isIdentifier(decoratorName) || ts.isCallExpression(decoratorName)) {
582        let name: string = '';
583        if (ts.isCallExpression(decoratorName) && ts.isIdentifier(decoratorName.expression)) {
584          name = decoratorName.expression.escapedText.toString();
585        } else if (ts.isIdentifier(decoratorName)) {
586          name = decoratorName.escapedText.toString();
587        }
588        if (CUSTOM_DECORATOR_NAME.has(name)) {
589          isComponent = true;
590        }
591        if (name === DECORATOR_REUSEABLE) {
592          structDecorator.hasRecycle = true;
593        }
594      }
595    }
596  }
597  return isComponent;
598}
599
600let packageJsonEntry: string = '';
601
602function isPackageJsonEntry(filePath: string): boolean {
603  const packageJsonPath: string = path.join(filePath, projectConfig.packageJson);
604  if (fs.existsSync(packageJsonPath)) {
605    let entryTypes: string;
606    let entryMain: string;
607    try {
608      const packageJson: Object =
609        (projectConfig.packageManagerType === 'npm' ? JSON : JSON5).parse(fs.readFileSync(packageJsonPath).toString());
610      entryTypes = packageJson.types;
611      entryMain = packageJson.main;
612    } catch (e) {
613      return false;
614    }
615    if (entryExist(filePath, entryTypes)) {
616      packageJsonEntry = path.resolve(filePath, entryTypes);
617      return true;
618    } else if (entryExist(filePath, entryMain)) {
619      packageJsonEntry = path.resolve(filePath, entryMain);
620      return true;
621    }
622  }
623  return false;
624}
625
626function entryExist(filePath: string, entry: string): boolean {
627  return typeof entry === 'string' && fs.existsSync(path.resolve(filePath, entry)) &&
628    fs.statSync(path.resolve(filePath, entry)).isFile();
629}
630
631function getModuleFilePath(filePath: string): string {
632  if (filePath && path.extname(filePath) !== EXTNAME_ETS && isModule(filePath)) {
633    filePath += EXTNAME_ETS;
634  }
635  return filePath;
636}
637
638function getFileResolvePath(fileResolvePath: string, pagesDir: string, filePath: string,
639  projectPath: string): string {
640  const moduleFilePath: string = getModuleFilePath(filePath);
641  const defaultModule: string = path.join(projectPath, moduleFilePath);
642  if (fs.existsSync(defaultModule)) {
643    return defaultModule;
644  }
645  let entryModule: string;
646  let etsModule: string;
647  if (new RegExp(`^@(${sdkConfigPrefix})\\.`).test(filePath.trim())) {
648    for (let i = 0; i < sdkConfigs.length; i++) {
649      const resolveModuleInfo: ResolveModuleInfo = getRealModulePath(sdkConfigs[i].apiPath, filePath, ['.d.ts', '.d.ets']);
650      const systemModule: string = resolveModuleInfo.modulePath;
651      if (fs.existsSync(systemModule)) {
652        return systemModule;
653      }
654    }
655  }
656  if (!projectConfig.aceModuleJsonPath) {
657    entryModule = path.join(projectPath, '../../../../../', moduleFilePath);
658    etsModule = path.join(projectPath, '../../', moduleFilePath);
659  } else {
660    entryModule = path.join(projectPath, '../../../../', moduleFilePath);
661    etsModule = path.join(projectPath, '../', moduleFilePath);
662  }
663  if (fs.existsSync(entryModule)) {
664    return entryModule;
665  }
666  if (fs.existsSync(etsModule)) {
667    return etsModule;
668  }
669  let curPageDir: string = pagesDir;
670  while (!fs.existsSync(fileResolvePath)) {
671    if (filePath.indexOf(projectConfig.packageDir) > -1 && /^(\.|\.\.)\//.test(filePath)) {
672      fileResolvePath = path.join(curPageDir, filePath);
673    } else {
674      fileResolvePath = path.join(curPageDir, projectConfig.packageDir, filePath);
675    }
676    if (fs.existsSync(fileResolvePath + EXTNAME_ETS)) {
677      fileResolvePath = fileResolvePath + EXTNAME_ETS;
678    } else if (isPackageJsonEntry(fileResolvePath)) {
679      fileResolvePath = packageJsonEntry;
680      if (fs.statSync(fileResolvePath).isDirectory()) {
681        if (fs.existsSync(path.join(fileResolvePath, INDEX_ETS))) {
682          fileResolvePath = path.join(fileResolvePath, INDEX_ETS);
683        } else if (fs.existsSync(path.join(fileResolvePath, INDEX_TS))) {
684          fileResolvePath = path.join(fileResolvePath, INDEX_TS);
685        }
686      }
687    } else if (fs.existsSync(path.join(fileResolvePath, INDEX_ETS))) {
688      fileResolvePath = path.join(fileResolvePath, INDEX_ETS);
689    } else if (fs.existsSync(path.join(fileResolvePath, INDEX_TS))) {
690      fileResolvePath = path.join(fileResolvePath, INDEX_TS);
691    }
692    if (curPageDir === path.parse(curPageDir).root) {
693      break;
694    }
695    curPageDir = path.dirname(curPageDir);
696  }
697  return fileResolvePath;
698}
699
700function getFileFullPath(filePath: string, pagesDir: string): string {
701  if (filePath && path.extname(filePath) !== EXTNAME_ETS && path.extname(filePath) !== EXTNAME_TS &&
702      !isModule(filePath)) {
703    const dirIndexEtsPath: string = path.resolve(path.resolve(pagesDir, filePath), INDEX_ETS);
704    const dirIndexTsPath: string = path.resolve(path.resolve(pagesDir, filePath), INDEX_TS);
705    if (/^(\.|\.\.)\//.test(filePath) && !fs.existsSync(path.resolve(pagesDir, filePath + EXTNAME_ETS)) &&
706      fs.existsSync(dirIndexEtsPath)) {
707      filePath = dirIndexEtsPath;
708    } else if (/^(\.|\.\.)\//.test(filePath) && !fs.existsSync(path.resolve(pagesDir, filePath + EXTNAME_TS)) &&
709      fs.existsSync(dirIndexTsPath)) {
710      filePath = dirIndexTsPath;
711    } else {
712      filePath += getExtensionIfUnfullySpecifiedFilepath(path.resolve(pagesDir, filePath));
713    }
714  }
715
716  let fileResolvePath: string;
717  if (/^(\.|\.\.)\//.test(filePath) && filePath.indexOf(projectConfig.packageDir) < 0) {
718    fileResolvePath = path.resolve(pagesDir, filePath);
719  } else if (/^\//.test(filePath) && filePath.indexOf(projectConfig.packageDir) < 0 ||
720    fs.existsSync(filePath) && fs.statSync(filePath).isFile()) {
721    fileResolvePath = filePath;
722  } else {
723    fileResolvePath = getFileResolvePath(fileResolvePath, pagesDir, filePath, projectConfig.projectPath);
724  }
725
726  return fileResolvePath;
727}
728
729function validateModuleName(moduleNode: ts.Identifier, log: LogInfo[], sourceFile?: ts.SourceFile,
730  fileResolvePath?: string): void {
731  const moduleName: string = moduleNode.escapedText.toString();
732  if (INNER_COMPONENT_NAMES.has(moduleName)) {
733    const error: LogInfo = {
734      type: LogType.ERROR,
735      message: `The module name '${moduleName}' can not be the same as the inner component name.`,
736      pos: moduleNode.getStart(),
737      code: '10905235'
738    };
739    if (sourceFile && fileResolvePath) {
740      const posOfNode: ts.LineAndCharacter = sourceFile.getLineAndCharacterOfPosition(moduleNode.getStart());
741      const line: number = posOfNode.line + 1;
742      const column: number = posOfNode.character + 1;
743      Object.assign(error, {
744        fileName: fileResolvePath,
745        line: line,
746        column: column
747      });
748    }
749    log.push(error);
750  }
751}
752
753interface PageInfo {
754  pageFile: string;
755  setChildOnce: boolean;
756}
757
758export function processImportModule(node: ts.ImportDeclaration, pageFile: string, log: LogInfo[],
759  share: object = null): void {
760  let importSymbol: ts.Symbol;
761  let realSymbol: ts.Symbol;
762  let originNode: ts.Node;
763  const pageInfo: PageInfo = { pageFile: pageFile, setChildOnce: false };
764  validateModuleSpecifier(node.moduleSpecifier, log);
765
766  // import xxx from 'xxx'
767  if (node.importClause && node.importClause.name && ts.isIdentifier(node.importClause.name)) {
768    getDefinedNode(importSymbol, realSymbol, originNode, node.importClause.name, pageInfo, share);
769  }
770
771  // import {xxx} from 'xxx'
772  if (node.importClause && node.importClause.namedBindings &&
773    ts.isNamedImports(node.importClause.namedBindings) &&
774    node.importClause.namedBindings.elements) {
775    node.importClause.namedBindings.elements.forEach((importSpecifier: ts.ImportSpecifier) => {
776      if (ts.isImportSpecifier(importSpecifier) && importSpecifier.name && ts.isIdentifier(importSpecifier.name)) {
777        getDefinedNode(importSymbol, realSymbol, originNode, importSpecifier.name, pageInfo, share);
778      }
779    });
780  }
781
782  // import * as xxx from 'xxx'
783  if (node.importClause && node.importClause.namedBindings &&
784    ts.isNamespaceImport(node.importClause.namedBindings) && node.importClause.namedBindings.name &&
785    ts.isIdentifier(node.importClause.namedBindings.name)) {
786    storedFileInfo.isAsPageImport = true;
787    getDefinedNode(importSymbol, realSymbol, originNode, node.importClause.namedBindings.name, pageInfo, share);
788  }
789}
790
791function getDefinedNode(importSymbol: ts.Symbol, realSymbol: ts.Symbol, originNode: ts.Node,
792  usedNode: ts.Identifier, pageInfo: PageInfo, share: object = null): void {
793  const checker: ts.TypeChecker | undefined = CurrentProcessFile.getChecker();
794  importSymbol = checker?.getSymbolAtLocation(usedNode);
795  if (importSymbol) {
796    realSymbol = checker?.getAliasedSymbol(importSymbol);
797  } else {
798    realSymbol = null;
799  }
800  if (realSymbol && realSymbol.declarations) {
801    originNode = realSymbol.declarations[0];
802  } else {
803    originNode = null;
804  }
805  if (originNode) {
806    if (ts.isSourceFile(originNode) && realSymbol.escapedName) {
807      const escapedName: string = realSymbol.escapedName.toString().replace(/^("|')/, '').replace(/("|')$/, '');
808      if (fs.existsSync(escapedName + '.ets') || fs.existsSync(escapedName + '.ts') &&
809        realSymbol.exports && realSymbol.exports instanceof Map) {
810        getIntegrationNodeInfo(originNode, usedNode, realSymbol.exports, pageInfo, share);
811        return;
812      }
813    }
814    processImportNode(originNode, usedNode, false, null, pageInfo, share);
815  }
816}
817
818function getIntegrationNodeInfo(originNode: ts.Node, usedNode: ts.Identifier, exportsMap: ts.SymbolTable,
819  pageInfo: PageInfo, share: object = null): void {
820  for (const usedSymbol of exportsMap) {
821    try {
822      originNode = CurrentProcessFile.getChecker()?.getAliasedSymbol(usedSymbol[1]).declarations[0];
823    } catch (e) {
824      if (usedSymbol[1] && usedSymbol[1].declarations) {
825        for (let i = 0; i < usedSymbol[1].declarations.length; i++) {
826          originNode = usedSymbol[1].declarations[i];
827          exportAllManage(originNode, usedNode, pageInfo, share);
828        }
829      }
830    }
831    processImportNode(originNode, usedNode, true, usedSymbol[0], pageInfo, share);
832  }
833}
834
835// export * from 'xxx';
836function exportAllManage(originNode: ts.Node, usedNode: ts.Identifier, pageInfo: PageInfo, share: object = null): void {
837  let exportOriginNode: ts.Node;
838  if (!originNode.exportClause && originNode.moduleSpecifier && ts.isStringLiteral(originNode.moduleSpecifier)) {
839    const checker: ts.TypeChecker | undefined = CurrentProcessFile.getChecker();
840    const exportSymbol: ts.Symbol = checker?.getSymbolAtLocation(originNode.moduleSpecifier);
841    if (exportSymbol && exportSymbol.declarations) {
842      exportOriginNode = exportSymbol.declarations[0];
843    } else {
844      exportOriginNode = null;
845    }
846    if (exportOriginNode) {
847      if (ts.isSourceFile(exportOriginNode) && exportSymbol.escapedName) {
848        const escapedName: string = exportSymbol.escapedName.toString().replace(/^("|')/, '').replace(/("|')$/, '');
849        if (fs.existsSync(escapedName + '.ets') || fs.existsSync(escapedName + '.ts') &&
850          exportSymbol.exports && exportSymbol.exports instanceof Map) {
851          getIntegrationNodeInfo(originNode, usedNode, exportSymbol.exports, pageInfo, share);
852          return;
853        }
854      }
855    }
856  }
857}
858
859function processImportNode(originNode: ts.Node, usedNode: ts.Identifier, importIntegration: boolean,
860  usedPropName: string, pageInfo: PageInfo, share: object = null): void {
861  const structDecorator: structDecoratorResult = { hasRecycle: false };
862  let name: string;
863  let asComponentName: string;
864  if (importIntegration) {
865    if (storedFileInfo.isAsPageImport) {
866      asComponentName = usedNode.escapedText.toString() + '.' + usedPropName;
867    }
868    name = usedPropName;
869  } else {
870    name = usedNode.escapedText.toString();
871  }
872  let needCollection: boolean = true;
873  const originFile: string = originNode.getSourceFile() ? originNode.getSourceFile().fileName : undefined;
874  if (ts.isStructDeclaration(originNode) && ts.isIdentifier(originNode.name)) {
875    parseComponentInImportNode(originNode, name, asComponentName, structDecorator, originFile);
876  } else if (isObservedClass(originNode)) {
877    observedClassCollection.add(name);
878  } else if (ts.isFunctionDeclaration(originNode) && hasDecorator(originNode, COMPONENT_BUILDER_DECORATOR)) {
879    CUSTOM_BUILDER_METHOD.add(name);
880    GLOBAL_CUSTOM_BUILDER_METHOD.add(name);
881  } else if (ts.isEnumDeclaration(originNode) && originNode.name) {
882    enumCollection.add(name);
883  } else {
884    needCollection = false;
885  }
886  if (needCollection && pageInfo.pageFile && !pageInfo.setChildOnce && originFile) {
887    const childFile: string = path.resolve(getRealPath(originFile) || originFile);
888    const fileHash = share?.getHashByFilePath ? share.getHashByFilePath(childFile) : '';
889    storedFileInfo.transformCacheFiles[pageInfo.pageFile].children.push({
890      fileName: childFile,
891      mtimeMs: fs.existsSync(childFile) ? fs.statSync(childFile).mtimeMs : 0,
892      hash: fileHash
893    });
894    pageInfo.setChildOnce = true;
895  }
896}
897
898function getRealPath(filePath: string): string {
899  try {
900    const newPath: string = fs.realpathSync.native(filePath);
901    return newPath;
902  } catch (err) {
903    return undefined;
904  }
905}
906
907function setComponentCollectionInfo(name: string, componentSet: IComponentSet, isDETS: boolean,
908  structDecorator: structDecoratorResult, asComponentName: string): void {
909  setDependencies(name, asComponentName, componentSet.links, componentSet.properties,
910    componentSet.props, componentSet.builderParams, componentSet.states, componentSet.regulars,
911    componentSet.storageProps, componentSet.storageLinks, componentSet.provides,
912    componentSet.consumes, componentSet.objectLinks, componentSet.localStorageLink,
913    componentSet.localStorageProp, componentSet.builderParamData, componentSet.propData, isDETS,
914    structDecorator);
915  regularInitialization.set(name, componentSet.regularInit);
916  stateInitialization.set(name, componentSet.stateInit);
917  provideInitialization.set(name, componentSet.provideInit);
918  privateCollection.set(name, componentSet.privateCollection);
919  regularStaticCollection.set(name, componentSet.regularStaticCollection);
920  if (asComponentName) {
921    const asComponentNameStructInfo: StructInfo =
922      processStructComponentV2.getOrCreateStructInfo(asComponentName);
923    asComponentNameStructInfo.updatePropsDecoratorsV1.push(
924      ...componentSet.states, ...componentSet.props,
925      ...componentSet.provides, ...componentSet.objectLinks
926    );
927    asComponentNameStructInfo.linkDecoratorsV1.push(...componentSet.links);
928    return;
929  }
930  const nameStructInfo: StructInfo = processStructComponentV2.getOrCreateStructInfo(name);
931  nameStructInfo.updatePropsDecoratorsV1.push(
932    ...componentSet.states, ...componentSet.props,
933    ...componentSet.provides, ...componentSet.objectLinks
934  );
935  nameStructInfo.linkDecoratorsV1.push(...componentSet.links);
936}
937
938function parseComponentInImportNode(originNode: ts.StructDeclaration, name: string,
939  asComponentName: string, structDecorator: structDecoratorResult, originFile: string): void {
940  componentCollection.customComponents.add(name);
941  const structInfo: StructInfo = asComponentName ?
942    processStructComponentV2.getOrCreateStructInfo(asComponentName) :
943    processStructComponentV2.getOrCreateStructInfo(name);
944  if (isComponentV2(originNode)) {
945    parseComponentV2InImportNode(originNode, name, originFile, structInfo);
946    return;
947  }
948  if (isCustomDialogClass(originNode)) {
949    structInfo.isCustomDialog = true;
950    componentCollection.customDialogs.add(name);
951  }
952  if (isCustomComponent(originNode, structDecorator)) {
953    structInfo.isComponentV1 = true;
954    let isDETS: boolean = false;
955    const componentSet: IComponentSet = getComponentSet(originNode, false);
956    while (originNode) {
957      if (ts.isSourceFile(originNode) && /\.d\.ets$/.test(originNode.fileName)) {
958        isDETS = true;
959      }
960      originNode = originNode.parent;
961    }
962    setComponentCollectionInfo(name, componentSet, isDETS, structDecorator, asComponentName);
963  }
964}
965
966function parseComponentV2InImportNode(node: ts.StructDeclaration, name: string, originFile: string,
967  structInfo: StructInfo): void {
968  structInfo.isComponentV2 = true;
969  const isDETS: boolean = originFile && /\.d\.ets$/.test(originFile);
970  if (isDETS) {
971    storedFileInfo.getCurrentArkTsFile().compFromDETS.add(name);
972  }
973  if (isReusableV2(node)) {
974    storedFileInfo.getCurrentArkTsFile().reuseComponentsV2.add(name);
975  }
976  processStructComponentV2.parseComponentProperty(node, structInfo, null, null);
977}
978
979function isComponentV2(node: ts.StructDeclaration): boolean {
980  const decorators: readonly ts.Decorator[] = ts.getAllDecorators(node);
981  return decorators.some((item: ts.Decorator) => {
982    const name: string = item.getText().replace(/\([^\(\)]*\)/, '').replace('@', '').trim();
983    return name === 'ComponentV2';
984  });
985}
986
987function isReusableV2(node: ts.StructDeclaration): boolean {
988  const decorators: readonly ts.Decorator[] = ts.getAllDecorators(node);
989  return decorators.some((item: ts.Decorator) => {
990    const name: string = item.getText().replace(/\([^\(\)]*\)/, '').replace('@', '').trim();
991    return name === DECORATOR_REUSABLE_V2;
992  });
993}
994