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