• 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  CARD_LOG_TYPE_IMPORT,
31  DECORATOR_REUSEABLE,
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} from './validate_ui_syntax';
60import {
61  getExtensionIfUnfullySpecifiedFilepath,
62  hasDecorator,
63  LogInfo,
64  LogType,
65  repeatLog,
66  storedFileInfo
67} from './utils';
68import {
69  projectConfig,
70  sdkConfigs,
71  sdkConfigPrefix,
72  globalProgram
73} from '../main';
74import {
75  CUSTOM_BUILDER_METHOD,
76  INNER_COMPONENT_NAMES,
77  GLOBAL_CUSTOM_BUILDER_METHOD
78} from './component_map';
79import { validatorCard } from './process_ui_syntax';
80import { SOURCE_FILES } from './ets_checker';
81
82const IMPORT_FILE_ASTCACHE: Map<string, ts.SourceFile> = process.env.watchMode === 'true' ? new Map() : SOURCE_FILES;
83
84export default function processImport(node: ts.ImportDeclaration | ts.ImportEqualsDeclaration |
85  ts.ExportDeclaration, pagesDir: string, log: LogInfo[], asName: Map<string, string> = new Map(),
86isEntryPage: boolean = true, pathCollection: Set<string> = new Set()): void {
87  let filePath: string;
88  let defaultName: string;
89  if (ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) {
90    filePath = node.moduleSpecifier.getText().replace(/'|"/g, '');
91    if (ts.isImportDeclaration(node) && node.importClause && node.importClause.name &&
92      ts.isIdentifier(node.importClause.name)) {
93      defaultName = node.importClause.name.escapedText.toString();
94      if (isEntryPage) {
95        asName.set(defaultName, defaultName);
96      }
97    }
98    if (ts.isImportDeclaration(node) && node.importClause && node.importClause.namedBindings &&
99      ts.isNamedImports(node.importClause.namedBindings) &&
100      node.importClause.namedBindings.elements && isEntryPage) {
101      node.importClause.namedBindings.elements.forEach(item => {
102        if (item.name && ts.isIdentifier(item.name)) {
103          validateModuleName(item.name, log);
104          if (item.propertyName && ts.isIdentifier(item.propertyName) && asName) {
105            asName.set(item.propertyName.escapedText.toString(), item.name.escapedText.toString());
106          } else {
107            asName.set(item.name.escapedText.toString(), item.name.escapedText.toString());
108          }
109        }
110      });
111    }
112  } else {
113    if (node.moduleReference && ts.isExternalModuleReference(node.moduleReference) &&
114      node.moduleReference.expression && ts.isStringLiteral(node.moduleReference.expression)) {
115      filePath = node.moduleReference.expression.text;
116      defaultName = node.name.escapedText.toString();
117      if (isEntryPage) {
118        asName.set(defaultName, defaultName);
119      }
120    }
121  }
122
123  try {
124    const fileResolvePath: string = getFileFullPath(filePath, pagesDir);
125    if (fs.existsSync(fileResolvePath) && fs.statSync(fileResolvePath).isFile() &&
126      !pathCollection.has(fileResolvePath)) {
127      let sourceFile: ts.SourceFile;
128      pathCollection.add(fileResolvePath);
129      if (IMPORT_FILE_ASTCACHE.has(fileResolvePath)) {
130        sourceFile = IMPORT_FILE_ASTCACHE.get(fileResolvePath);
131      } else {
132        sourceFile = generateSourceFileAST(fileResolvePath, filePath);
133        IMPORT_FILE_ASTCACHE[fileResolvePath] = sourceFile;
134      }
135      visitAllNode(sourceFile, sourceFile, defaultName, asName, path.dirname(fileResolvePath), log,
136        new Set(), new Set(), new Set(), new Map(), pathCollection, fileResolvePath, /\.d\.ets$/.test(fileResolvePath));
137    }
138  } catch (e) {
139    // ignore
140  }
141}
142
143function generateSourceFileAST(fileResolvePath: string, filePath: string): ts.SourceFile {
144  const originContent: string = fs.readFileSync(fileResolvePath, { encoding: 'utf-8' });
145  const content: string = path.extname(fileResolvePath) === EXTNAME_ETS ?
146    preprocessNewExtend(preprocessExtend(processSystemApi(originContent))) : originContent;
147  return ts.createSourceFile(fileResolvePath, content, ts.ScriptTarget.Latest, true, ts.ScriptKind.ETS);
148}
149
150type structDecoratorResult = {
151  hasRecycle: boolean
152}
153
154function visitAllNode(node: ts.Node, sourceFile: ts.SourceFile, defaultNameFromParent: string,
155  asNameFromParent: Map<string, string>, pagesDir: string, log: LogInfo[], entryCollection: Set<string>,
156  exportCollection: Set<string>, defaultCollection: Set<string>, asExportCollection: Map<string, string>,
157  pathCollection: Set<string>, fileResolvePath: string, isDETS: boolean) {
158  if (isObservedClass(node)) {
159    collectSpecialFunctionNode(node as ts.ClassDeclaration, asNameFromParent, defaultNameFromParent, defaultCollection,
160      asExportCollection, observedClassCollection);
161    // @ts-ignore
162    observedClassCollection.add(node.name.getText());
163  }
164  if (isCustomDialogClass(node)) {
165    collectSpecialFunctionNode(node as ts.StructDeclaration, asNameFromParent, defaultNameFromParent, defaultCollection,
166      asExportCollection, componentCollection.customDialogs);
167    // @ts-ignore
168    componentCollection.customDialogs.add(node.name.getText());
169  }
170  if (ts.isEnumDeclaration(node) && node.name) {
171    enumCollection.add(node.name.getText());
172  }
173  const structDecorator: structDecoratorResult = { hasRecycle: false };
174  if (ts.isStructDeclaration(node) && ts.isIdentifier(node.name) && isCustomComponent(node, structDecorator)) {
175    addDependencies(node, defaultNameFromParent, asNameFromParent, isDETS, structDecorator);
176    isExportEntry(node, log, entryCollection, exportCollection, defaultCollection, fileResolvePath, sourceFile);
177    if (asExportCollection.has(node.name.getText())) {
178      componentCollection.customComponents.add(asExportCollection.get(node.name.getText()));
179      if (isDETS) {
180        storedFileInfo.getCurrentArkTsFile().compFromDETS.add(asExportCollection.get(node.name.getText()));
181      }
182      if (structDecorator.hasRecycle) {
183        storedFileInfo.getCurrentArkTsFile().recycleComponents.add(asExportCollection.get(node.name.getText()));
184      }
185    }
186    if (node.modifiers && node.modifiers.length >= 2 && node.modifiers[0] &&
187      node.modifiers[0].kind === ts.SyntaxKind.ExportKeyword && node.modifiers[1] &&
188      node.modifiers[1].kind === ts.SyntaxKind.DefaultKeyword) {
189      if (!defaultNameFromParent && hasCollection(node.name)) {
190        addDefaultExport(node, isDETS, structDecorator);
191      } else if (defaultNameFromParent && asNameFromParent.has(defaultNameFromParent)) {
192        componentCollection.customComponents.add(asNameFromParent.get(defaultNameFromParent));
193        if (isDETS) {
194          storedFileInfo.getCurrentArkTsFile().compFromDETS.add(asNameFromParent.get(defaultNameFromParent));
195        }
196        if (structDecorator.hasRecycle) {
197          storedFileInfo.getCurrentArkTsFile().recycleComponents.add(asNameFromParent.get(defaultNameFromParent));
198        }
199      }
200    }
201    if (defaultCollection.has(node.name.getText())) {
202      componentCollection.customComponents.add(CUSTOM_COMPONENT_DEFAULT);
203      if (isDETS) {
204        storedFileInfo.getCurrentArkTsFile().compFromDETS.add(CUSTOM_COMPONENT_DEFAULT);
205      }
206      if (structDecorator.hasRecycle) {
207        storedFileInfo.getCurrentArkTsFile().recycleComponents.add(CUSTOM_COMPONENT_DEFAULT);
208      }
209    }
210  }
211  if (ts.isFunctionDeclaration(node) && hasDecorator(node, COMPONENT_BUILDER_DECORATOR)) {
212    collectSpecialFunctionNode(node, asNameFromParent, defaultNameFromParent, defaultCollection,
213      asExportCollection, CUSTOM_BUILDER_METHOD);
214    collectSpecialFunctionNode(node, asNameFromParent, defaultNameFromParent, defaultCollection,
215      asExportCollection, GLOBAL_CUSTOM_BUILDER_METHOD);
216  }
217  if (ts.isExportAssignment(node) && node.expression && ts.isIdentifier(node.expression) &&
218    hasCollection(node.expression)) {
219    if (defaultNameFromParent) {
220      const propertiesName: string = node.expression.escapedText.toString();
221      setDependencies(defaultNameFromParent, linkCollection.get(propertiesName),
222        propertyCollection.get(propertiesName), propCollection.get(propertiesName),
223        builderParamObjectCollection.get(propertiesName), stateCollection.get(propertiesName),
224        regularCollection.get(propertiesName), storagePropCollection.get(propertiesName),
225        storageLinkCollection.get(propertiesName), provideCollection.get(propertiesName),
226        consumeCollection.get(propertiesName), objectLinkCollection.get(propertiesName),
227        localStorageLinkCollection.get(propertiesName), localStoragePropCollection.get(propertiesName),
228        builderParamInitialization.get(propertiesName), propInitialization.get(propertiesName), isDETS,
229        structDecorator);
230    }
231    addDefaultExport(node, isDETS, structDecorator);
232  }
233  if (ts.isExportAssignment(node) && node.expression && ts.isIdentifier(node.expression)) {
234    if (defaultNameFromParent) {
235      asNameFromParent.set(node.expression.getText(), asNameFromParent.get(defaultNameFromParent));
236    }
237    defaultCollection.add(node.expression.getText());
238  }
239  if (ts.isExportDeclaration(node) && node.exportClause &&
240    ts.isNamedExports(node.exportClause) && node.exportClause.elements) {
241    node.exportClause.elements.forEach(item => {
242      if (process.env.watchMode === 'true') {
243        exportCollection.add((item.propertyName ? item.propertyName : item.name).escapedText.toString());
244      }
245      if (item.name && ts.isIdentifier(item.name)) {
246        if (!item.propertyName) {
247          asExportCollection.set(item.name.escapedText.toString(), item.name.escapedText.toString());
248        } else if (item.propertyName && ts.isIdentifier(item.propertyName)) {
249          validateModuleName(item.name, log, sourceFile, fileResolvePath);
250          if (hasCollection(item.propertyName)) {
251            let asExportName: string = item.name.escapedText.toString();
252            const asExportPropertyName: string = item.propertyName.escapedText.toString();
253            if (asNameFromParent.has(asExportName)) {
254              asExportName = asNameFromParent.get(asExportName);
255            }
256            setDependencies(asExportName, linkCollection.get(asExportPropertyName),
257              propertyCollection.get(asExportPropertyName),
258              propCollection.get(asExportPropertyName),
259              builderParamObjectCollection.get(asExportPropertyName),
260              stateCollection.get(asExportPropertyName), regularCollection.get(asExportPropertyName),
261              storagePropCollection.get(asExportPropertyName), storageLinkCollection.get(asExportPropertyName),
262              provideCollection.get(asExportPropertyName), consumeCollection.get(asExportPropertyName),
263              objectLinkCollection.get(asExportPropertyName), localStorageLinkCollection.get(asExportPropertyName),
264              localStoragePropCollection.get(asExportPropertyName), builderParamInitialization.get(asExportPropertyName),
265              propInitialization.get(asExportPropertyName), isDETS, structDecorator);
266          }
267          asExportCollection.set(item.propertyName.escapedText.toString(), item.name.escapedText.toString());
268        }
269      }
270      if (item.name && ts.isIdentifier(item.name) && asNameFromParent.has(item.name.escapedText.toString()) &&
271        item.propertyName && ts.isIdentifier(item.propertyName)) {
272        asNameFromParent.set(item.propertyName.escapedText.toString(),
273          asNameFromParent.get(item.name.escapedText.toString()));
274      }
275    });
276  }
277  if (ts.isExportDeclaration(node) && node.moduleSpecifier &&
278    ts.isStringLiteral(node.moduleSpecifier)) {
279    if (process.env.watchMode === 'true' && node.exportClause && ts.isNamedExports(node.exportClause) &&
280      node.exportClause.elements) {
281      node.exportClause.elements.forEach(item => {
282        exportCollection.add((item.propertyName ? item.propertyName : item.name).escapedText.toString());
283        if (item.propertyName && ts.isIdentifier(item.propertyName) && item.name &&
284          ts.isIdentifier(item.name) && asNameFromParent.has(item.name.escapedText.toString())) {
285          asNameFromParent.set(item.propertyName.escapedText.toString(),
286            asNameFromParent.get(item.name.escapedText.toString()));
287          defaultCollection.add(item.name.escapedText.toString());
288        }
289      });
290    }
291    processImport(node, pagesDir, log, asNameFromParent, true, new Set(pathCollection));
292  }
293  if (ts.isImportDeclaration(node)) {
294    if (node.importClause && node.importClause.name && ts.isIdentifier(node.importClause.name) &&
295      asNameFromParent.has(node.importClause.name.getText())) {
296      processImport(node, pagesDir, log, asNameFromParent, false, new Set(pathCollection));
297    } else if (node.importClause && node.importClause.namedBindings &&
298      ts.isNamedImports(node.importClause.namedBindings) && node.importClause.namedBindings.elements) {
299      let nested: boolean = false;
300      node.importClause.namedBindings.elements.forEach(item => {
301        if (item.name && ts.isIdentifier(item.name) && asNameFromParent.has(item.name.escapedText.toString())) {
302          nested = true;
303          if (item.propertyName && ts.isIdentifier(item.propertyName)) {
304            asNameFromParent.set(item.propertyName.escapedText.toString(),
305              asNameFromParent.get(item.name.escapedText.toString()));
306          }
307        }
308      });
309      if (nested) {
310        processImport(node, pagesDir, log, asNameFromParent, false, new Set(pathCollection));
311      }
312    }
313  }
314  node.getChildren().reverse().forEach((item: ts.Node) => visitAllNode(item, sourceFile,
315    defaultNameFromParent, asNameFromParent, pagesDir, log, entryCollection, exportCollection,
316    defaultCollection, asExportCollection, pathCollection, fileResolvePath, isDETS));
317}
318
319function collectSpecialFunctionNode(node: ts.FunctionDeclaration | ts.ClassDeclaration | ts.StructDeclaration,
320  asNameFromParent: Map<string, string>, defaultNameFromParent: string, defaultCollection: Set<string>,
321  asExportCollection: Map<string, string>, collection: Set<string>): void {
322  const name: string = node.name.getText();
323  let componentName: string;
324  if (asNameFromParent.has(name)) {
325    collection.add(asNameFromParent.get(name));
326  } else if (node.modifiers && node.modifiers.length >= 1 && node.modifiers[0] &&
327    node.modifiers[0].kind === ts.SyntaxKind.ExportKeyword) {
328    if (node.modifiers.length == 1) {
329      collection.add(name);
330    } else if (node.modifiers.length >= 2 && node.modifiers[1] && node.modifiers[1].kind ===
331      ts.SyntaxKind.DefaultKeyword) {
332      collection.add(CUSTOM_COMPONENT_DEFAULT);
333      if (defaultNameFromParent && asNameFromParent.has(defaultNameFromParent)) {
334        collection.add(asNameFromParent.get(defaultNameFromParent));
335      }
336    }
337  } else if (defaultCollection.has(name)) {
338    collection.add(CUSTOM_COMPONENT_DEFAULT);
339  } else if (asExportCollection.has(name)) {
340    collection.add(asExportCollection.get(name));
341  }
342}
343
344function isExportEntry(node: ts.StructDeclaration, log: LogInfo[], entryCollection: Set<string>,
345  exportCollection: Set<string>, defaultCollection: Set<string>, fileResolvePath: string,
346  sourceFile: ts.SourceFile): void {
347  if (process.env.watchMode === 'true' && node && node.decorators) {
348    let existExport: boolean = false;
349    let existEntry: boolean = false;
350    if (node.modifiers) {
351      for (let i = 0; i < node.modifiers.length; i++) {
352        if (node.modifiers[i].kind === ts.SyntaxKind.ExportKeyword) {
353          existExport = true;
354          break;
355        }
356      }
357    }
358    for (let i = 0; i < node.decorators.length; i++) {
359      if (node.decorators[i].getText() === COMPONENT_DECORATOR_ENTRY) {
360        entryCollection.add(node.name.escapedText.toString());
361        existEntry = true;
362        break;
363      }
364    }
365  }
366}
367
368function remindExportEntryComponent(node: ts.Node, log: LogInfo[], fileResolvePath: string,
369  sourceFile: ts.SourceFile): void {
370  const posOfNode: ts.LineAndCharacter = sourceFile.getLineAndCharacterOfPosition(node.getStart());
371  const line: number = posOfNode.line + 1;
372  const column: number = posOfNode.character + 1;
373  const warnInfo: LogInfo = {
374    type: LogType.WARN,
375    message: `It's not a recommended way to export struct with @Entry decorator, ` +
376      `which may cause ACE Engine error in component preview mode.`,
377    pos: node.getStart(),
378    fileName: fileResolvePath,
379    line: line,
380    column: column
381  };
382  if (!repeatLog.has(fileResolvePath)) {
383    log.push(warnInfo);
384    repeatLog.set(fileResolvePath, warnInfo);
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  if (defaultNameFromParent && node.modifiers && node.modifiers.length >= 2 && node.modifiers[0] &&
393    node.modifiers[1] && node.modifiers[0].kind === ts.SyntaxKind.ExportKeyword &&
394    node.modifiers[1].kind === ts.SyntaxKind.DefaultKeyword) {
395    setDependencies(defaultNameFromParent, 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), 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, 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,
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, 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  linkCollection.set(component, linkArray);
504  propertyCollection.set(component, propertyArray);
505  if (!propCollection.get(component)) {
506    propCollection.set(component, propArray);
507  }
508  builderParamObjectCollection.set(component, builderParamArray);
509  componentCollection.customComponents.add(component);
510  if (isDETS) {
511    storedFileInfo.getCurrentArkTsFile().compFromDETS.add(component);
512  }
513  if (structDecorator.hasRecycle) {
514    storedFileInfo.getCurrentArkTsFile().recycleComponents.add(component);
515  }
516  stateCollection.set(component, stateArray);
517  regularCollection.set(component, regularArray);
518  storagePropCollection.set(component, storagePropsArray);
519  storageLinkCollection.set(component, storageLinksArray);
520  provideCollection.set(component, providesArray);
521  consumeCollection.set(component, consumesArray);
522  objectLinkCollection.set(component, objectLinksArray);
523  localStorageLinkCollection.set(component, localStorageLinkMap);
524  localStoragePropCollection.set(component, localStoragePropMap);
525  if (!builderParamInitialization.get(component)) {
526    builderParamInitialization.set(component, builderParamData);
527  }
528  if (!propInitialization.get(component)) {
529    propInitialization.set(component, propData);
530  }
531}
532
533function hasCollection(node: ts.Identifier): boolean {
534  const name: string = node.escapedText.toString();
535  return linkCollection.has(name) ||
536    propCollection.has(name) ||
537    propertyCollection.has(name) ||
538    builderParamObjectCollection.has(name) ||
539    stateCollection.has(name) ||
540    regularCollection.has(name) ||
541    storagePropCollection.has(name) ||
542    storageLinkCollection.has(name) ||
543    provideCollection.has(name) ||
544    consumeCollection.has(name) ||
545    objectLinkCollection.has(name) ||
546    localStorageLinkCollection.has(name) ||
547    localStoragePropCollection.has(name)
548}
549
550function isModule(filePath: string): boolean {
551  return !/^(\.|\.\.)?\//.test(filePath) || filePath.indexOf(projectConfig.packageDir) > -1;
552}
553
554function isCustomComponent(node: ts.StructDeclaration, structDecorator: structDecoratorResult): boolean {
555  let isComponent: boolean = false;
556  if (node.decorators && node.decorators.length) {
557    for (let i = 0; i < node.decorators.length; ++i) {
558      const decoratorName: ts.Identifier = node.decorators[i].expression as ts.Identifier;
559      if (ts.isIdentifier(decoratorName)) {
560        const name: string = decoratorName.escapedText.toString();
561        if (CUSTOM_DECORATOR_NAME.has(name)) {
562          isComponent = true;
563        }
564        if (name === DECORATOR_REUSEABLE) {
565          structDecorator.hasRecycle = true;
566        }
567      }
568    }
569  }
570  return isComponent;
571}
572
573let packageJsonEntry: string = '';
574
575function isPackageJsonEntry(filePath: string): boolean {
576  const packageJsonPath: string = path.join(filePath, projectConfig.packageJson);
577  if (fs.existsSync(packageJsonPath)) {
578    let entryTypes: string;
579    let entryMain: string;
580    try {
581      const packageJson: Object =
582        (projectConfig.packageManagerType === 'npm' ? JSON : JSON5).parse(fs.readFileSync(packageJsonPath).toString());
583      entryTypes = packageJson.types;
584      entryMain = packageJson.main;
585    } catch (e) {
586      return false;
587    }
588    if (entryExist(filePath, entryTypes)) {
589      packageJsonEntry = path.resolve(filePath, entryTypes);
590      return true;
591    } else if (entryExist(filePath, entryMain)) {
592      packageJsonEntry = path.resolve(filePath, entryMain);
593      return true;
594    }
595  }
596}
597
598function entryExist(filePath: string, entry: string): boolean {
599  return typeof entry === 'string' && fs.existsSync(path.resolve(filePath, entry)) &&
600    fs.statSync(path.resolve(filePath, entry)).isFile();
601}
602
603function getModuleFilePath(filePath: string): string {
604  if (filePath && path.extname(filePath) !== EXTNAME_ETS && isModule(filePath)) {
605    filePath += EXTNAME_ETS;
606  }
607  return filePath;
608}
609
610function getFileResolvePath(fileResolvePath: string, pagesDir: string, filePath: string,
611  projectPath: string): string {
612  const moduleFilePath: string = getModuleFilePath(filePath);
613  const defaultModule: string = path.join(projectPath, moduleFilePath);
614  if (fs.existsSync(defaultModule)) {
615    return defaultModule;
616  }
617  let entryModule: string;
618  let etsModule: string;
619  if (new RegExp(`^@(${sdkConfigPrefix})\\.`).test(filePath.trim())) {
620    for (let i = 0; i < sdkConfigs.length; i++) {
621      const systemModule: string = path.resolve(sdkConfigs[i].apiPath, filePath + '.d.ets');
622      if (fs.existsSync(systemModule)) {
623        return systemModule;
624      }
625    }
626  }
627  if (!projectConfig.aceModuleJsonPath) {
628    entryModule = path.join(projectPath, '../../../../../', moduleFilePath);
629    etsModule = path.join(projectPath, '../../', moduleFilePath);
630  } else {
631    entryModule = path.join(projectPath, '../../../../', moduleFilePath);
632    etsModule = path.join(projectPath, '../', moduleFilePath);
633  }
634  if (fs.existsSync(entryModule)) {
635    return entryModule;
636  }
637  if (fs.existsSync(etsModule)) {
638    return etsModule;
639  }
640  let curPageDir: string = pagesDir;
641  while (!fs.existsSync(fileResolvePath)) {
642    if (filePath.indexOf(projectConfig.packageDir) > -1) {
643      fileResolvePath = path.join(curPageDir, filePath);
644    } else {
645      fileResolvePath = path.join(curPageDir, projectConfig.packageDir, filePath);
646    }
647    if (fs.existsSync(fileResolvePath + EXTNAME_ETS)) {
648      fileResolvePath = fileResolvePath + EXTNAME_ETS;
649    } else if (isPackageJsonEntry(fileResolvePath)) {
650      fileResolvePath = packageJsonEntry;
651      if (fs.statSync(fileResolvePath).isDirectory()) {
652        if (fs.existsSync(path.join(fileResolvePath, INDEX_ETS))) {
653          fileResolvePath = path.join(fileResolvePath, INDEX_ETS);
654        } else if (fs.existsSync(path.join(fileResolvePath, INDEX_TS))) {
655          fileResolvePath = path.join(fileResolvePath, INDEX_TS);
656        }
657      }
658    } else if (fs.existsSync(path.join(fileResolvePath, INDEX_ETS))) {
659      fileResolvePath = path.join(fileResolvePath, INDEX_ETS);
660    } else if (fs.existsSync(path.join(fileResolvePath, INDEX_TS))) {
661      fileResolvePath = path.join(fileResolvePath, INDEX_TS);
662    }
663    if (curPageDir === path.parse(curPageDir).root) {
664      break;
665    }
666    curPageDir = path.dirname(curPageDir);
667  }
668  return fileResolvePath;
669}
670
671function getFileFullPath(filePath: string, pagesDir: string): string {
672  if (filePath && path.extname(filePath) !== EXTNAME_ETS && path.extname(filePath) !== EXTNAME_TS &&
673      !isModule(filePath)) {
674    const dirIndexEtsPath: string = path.resolve(path.resolve(pagesDir, filePath), INDEX_ETS);
675    const dirIndexTsPath: string = path.resolve(path.resolve(pagesDir, filePath), INDEX_TS);
676    if (/^(\.|\.\.)\//.test(filePath) && !fs.existsSync(path.resolve(pagesDir, filePath + EXTNAME_ETS)) &&
677      fs.existsSync(dirIndexEtsPath)) {
678      filePath = dirIndexEtsPath;
679    } else if (/^(\.|\.\.)\//.test(filePath) && !fs.existsSync(path.resolve(pagesDir, filePath + EXTNAME_TS)) &&
680      fs.existsSync(dirIndexTsPath)) {
681      filePath = dirIndexTsPath;
682    } else {
683      filePath += getExtensionIfUnfullySpecifiedFilepath(path.resolve(pagesDir, filePath));
684    }
685  }
686
687  let fileResolvePath: string;
688  if (/^(\.|\.\.)\//.test(filePath) && filePath.indexOf(projectConfig.packageDir) < 0) {
689    fileResolvePath = path.resolve(pagesDir, filePath);
690  } else if (/^\//.test(filePath) && filePath.indexOf(projectConfig.packageDir) < 0 ||
691    fs.existsSync(filePath) && fs.statSync(filePath).isFile()) {
692    fileResolvePath = filePath;
693  } else {
694    fileResolvePath = getFileResolvePath(fileResolvePath, pagesDir, filePath, projectConfig.projectPath);
695  }
696
697  return fileResolvePath;
698}
699
700function validateModuleName(moduleNode: ts.Identifier, log: LogInfo[], sourceFile?: ts.SourceFile,
701  fileResolvePath?: string): void {
702  const moduleName: string = moduleNode.escapedText.toString();
703  if (INNER_COMPONENT_NAMES.has(moduleName)) {
704    const error: LogInfo = {
705      type: LogType.ERROR,
706      message: `The module name '${moduleName}' can not be the same as the inner component name.`,
707      pos: moduleNode.getStart()
708    };
709    if (sourceFile && fileResolvePath) {
710      const posOfNode: ts.LineAndCharacter = sourceFile.getLineAndCharacterOfPosition(moduleNode.getStart());
711      const line: number = posOfNode.line + 1;
712      const column: number = posOfNode.character + 1;
713      Object.assign(error, {
714        fileName: fileResolvePath,
715        line: line,
716        column: column
717      });
718    }
719    log.push(error);
720  }
721}
722
723export function processImportModule(node: ts.ImportDeclaration): void {
724  let importSymbol: ts.Symbol;
725  let realSymbol: ts.Symbol;
726  let originNode: ts.Node;
727  // import xxx from 'xxx'
728  if (node.importClause && node.importClause.name && ts.isIdentifier(node.importClause.name)) {
729    getDefinedNode(importSymbol, realSymbol, originNode, node.importClause.name);
730  }
731
732  // import {xxx} from 'xxx'
733  if (node.importClause && node.importClause.namedBindings &&
734    ts.isNamedImports(node.importClause.namedBindings) &&
735    node.importClause.namedBindings.elements) {
736    node.importClause.namedBindings.elements.forEach((importSpecifier: ts.ImportSpecifier) => {
737      if (ts.isImportSpecifier(importSpecifier) && importSpecifier.name && ts.isIdentifier(importSpecifier.name)) {
738        getDefinedNode(importSymbol, realSymbol, originNode, importSpecifier.name);
739      }
740    });
741  }
742
743  // import * as xxx from 'xxx'
744  if (node.importClause && node.importClause.namedBindings &&
745    ts.isNamespaceImport(node.importClause.namedBindings) && node.importClause.namedBindings.name &&
746    ts.isIdentifier(node.importClause.namedBindings.name)) {
747    getDefinedNode(importSymbol, realSymbol, originNode, node.importClause.namedBindings.name);
748  }
749}
750
751function getDefinedNode(importSymbol: ts.Symbol, realSymbol: ts.Symbol, originNode: ts.Node,
752  usedNode: ts.Identifier): void {
753  importSymbol = globalProgram.checker.getSymbolAtLocation(usedNode);
754  if (importSymbol) {
755    realSymbol = globalProgram.checker.getAliasedSymbol(importSymbol);
756  } else {
757    realSymbol = null;
758  }
759  if (realSymbol && realSymbol.declarations) {
760    originNode = realSymbol.declarations[0];
761  } else {
762    originNode = null;
763  }
764  if (originNode) {
765    if (ts.isSourceFile(originNode) && realSymbol.escapedName) {
766      const escapedName: string = realSymbol.escapedName.toString().replace(/^("|')/, '').replace(/("|')$/, '');
767      if (fs.existsSync(escapedName + '.ets') || fs.existsSync(escapedName + '.ts') &&
768        realSymbol.exports && realSymbol.exports instanceof Map) {
769        getIntegrationNodeInfo(originNode, usedNode, realSymbol.exports);
770        return;
771      }
772    }
773    processImportNode(originNode, usedNode, false, null);
774  }
775}
776
777function getIntegrationNodeInfo(originNode: ts.Node, usedNode: ts.Identifier, exportsMap: ts.SymbolTable): void {
778  for (const usedSymbol of exportsMap) {
779    try {
780      originNode = globalProgram.checker.getAliasedSymbol(usedSymbol[1]).declarations[0];
781    } catch (e) {
782      if (usedSymbol[1] && usedSymbol[1].declarations) {
783        originNode = usedSymbol[1].declarations[0];
784      }
785    }
786    processImportNode(originNode, usedNode, true, usedSymbol[0]);
787  }
788}
789
790function processImportNode(originNode: ts.Node, usedNode: ts.Identifier, importIntegration: boolean,
791  usedPropName: string): void {
792  const structDecorator: structDecoratorResult = { hasRecycle: false };
793  let name: string;
794  if (importIntegration) {
795    name = usedPropName;
796  } else {
797    name = usedNode.escapedText.toString();
798  }
799  let needCollection: boolean = true;
800  const originFile: string = originNode.getSourceFile() ? originNode.getSourceFile().fileName : undefined;
801  const ownFile: string = usedNode.getSourceFile() ? usedNode.getSourceFile().fileName : undefined;
802  if (ts.isStructDeclaration(originNode) && ts.isIdentifier(originNode.name)) {
803    if (isCustomDialogClass(originNode)) {
804      componentCollection.customDialogs.add(name);
805    }
806    if (isCustomComponent(originNode, structDecorator)) {
807      let isDETS: boolean = false;
808      componentCollection.customComponents.add(name);
809      const ComponentSet: IComponentSet = getComponentSet(originNode, false);
810      while (originNode) {
811        if (ts.isSourceFile(originNode) && /\.d\.ets$/.test(originNode.fileName)) {
812          isDETS = true;
813        }
814        originNode = originNode.parent;
815      }
816      if (isDETS) {
817        storedFileInfo.getCurrentArkTsFile().compFromDETS.add(name);
818      }
819      if (structDecorator.hasRecycle) {
820        storedFileInfo.getCurrentArkTsFile().recycleComponents.add(name);
821      }
822      setDependencies(name, ComponentSet.links, ComponentSet.properties,
823        ComponentSet.props, ComponentSet.builderParams, ComponentSet.states, ComponentSet.regulars,
824        ComponentSet.storageProps, ComponentSet.storageLinks, ComponentSet.provides,
825        ComponentSet.consumes, ComponentSet.objectLinks, ComponentSet.localStorageLink,
826        ComponentSet.localStorageProp, ComponentSet.builderParamData, ComponentSet.propData, isDETS,
827        structDecorator);
828    }
829  } else if (isObservedClass(originNode)) {
830    observedClassCollection.add(name);
831  } else if (ts.isFunctionDeclaration(originNode) && hasDecorator(originNode, COMPONENT_BUILDER_DECORATOR)) {
832    CUSTOM_BUILDER_METHOD.add(name);
833    GLOBAL_CUSTOM_BUILDER_METHOD.add(name);
834  } else if (ts.isEnumDeclaration(originNode) && originNode.name) {
835    enumCollection.add(name);
836  } else {
837    needCollection = false;
838  }
839  if (needCollection && ownFile && originFile) {
840    storedFileInfo.transformCacheFiles[ownFile].children.push({
841      fileName: originFile,
842      mtimeMs: fs.existsSync(originFile) ? fs.statSync(originFile).mtimeMs: 0
843    });
844  }
845}
846