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