• 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 path from 'path';
18import fs from 'fs';
19
20import {
21  PAGE_ENTRY_FUNCTION_NAME,
22  PREVIEW_COMPONENT_FUNCTION_NAME,
23  STORE_PREVIEW_COMPONENTS,
24  GET_PREVIEW_FLAG_FUNCTION_NAME,
25  COMPONENT_CONSTRUCTOR_UNDEFINED,
26  BUILD_ON,
27  COMPONENT_BUILDER_DECORATOR,
28  COMPONENT_CONCURRENT_DECORATOR,
29  COMPONENT_SENDABLE_DECORATOR,
30  COMPONENT_EXTEND_DECORATOR,
31  COMPONENT_STYLES_DECORATOR,
32  RESOURCE,
33  RESOURCE_TYPE,
34  WORKER_OBJECT,
35  RESOURCE_NAME_ID,
36  RESOURCE_NAME_TYPE,
37  RESOURCE_NAME_PARAMS,
38  RESOURCE_RAWFILE,
39  RESOURCE_NAME_BUNDLE,
40  RESOURCE_NAME_MODULE,
41  ATTRIBUTE_ANIMATETO_SET,
42  GLOBAL_CONTEXT,
43  INSTANCE,
44  SET_CONTROLLER_CTR_TYPE,
45  SET_CONTROLLER_METHOD,
46  JS_DIALOG,
47  CUSTOM_DIALOG_CONTROLLER_BUILDER,
48  ESMODULE,
49  EXTNAME_ETS,
50  GENERATE_ID,
51  _GENERATE_ID,
52  VIEWSTACKPROCESSOR,
53  STARTGETACCESSRECORDINGFOR,
54  ALLOCATENEWELMETIDFORNEXTCOMPONENT,
55  STOPGETACCESSRECORDING,
56  CARD_ENTRY_FUNCTION_NAME,
57  CARD_LOG_TYPE_COMPONENTS,
58  CARD_LOG_TYPE_DECORATORS,
59  CARD_LOG_TYPE_IMPORT,
60  COMPONENT_ANIMATABLE_EXTEND_DECORATOR,
61  CHECK_EXTEND_DECORATORS,
62  ELMTID,
63  ROUTENAME_NODE,
64  STORAGE_NODE,
65  STORAGE,
66  REGISTER_NAMED_ROUTE,
67  ROUTE_NAME,
68  PAGE_PATH,
69  ISINITIALRENDER,
70  CREATE_ANIMATABLE_PROPERTY,
71  UPDATE_ANIMATABLE_PROPERTY,
72  MY_IDS,
73  VIEW_STACK_PROCESSOR,
74  GET_AND_PUSH_FRAME_NODE,
75  COMPONENT_CONSTRUCTOR_PARENT,
76  WRAPBUILDER_FUNCTION,
77  FINISH_UPDATE_FUNC,
78  INTEGRATED_HSP,
79  FUNCTION,
80  PAGE_FULL_PATH,
81  LENGTH,
82  PUV2_VIEW_BASE,
83  CONTEXT_STACK
84} from './pre_define';
85import {
86  componentInfo,
87  LogInfo,
88  LogType,
89  hasDecorator,
90  IFileLog,
91  getPossibleBuilderTypeParameter,
92  storedFileInfo,
93  ExtendResult,
94  startTimeStatisticsLocation,
95  stopTimeStatisticsLocation,
96  CompilationTimeStatistics,
97  getStoredFileInfo,
98  ProcessFileInfo,
99  RouterInfo,
100  EntryOptionValue,
101  judgeUseSharedStorageForExpresion,
102  createGetSharedForVariable,
103  createGetShared
104} from './utils';
105import { writeFileSyncByNode } from './process_module_files';
106import {
107  componentCollection,
108  localStorageLinkCollection,
109  localStoragePropCollection
110} from './validate_ui_syntax';
111import {
112  processComponentClass,
113  createParentParameter,
114  processBuildMember,
115  checkFinalizeConstruction,
116  checkContextStack
117} from './process_component_class';
118import processImport, {
119  processImportModule
120} from './process_import';
121import {
122  processComponentBlock,
123  bindComponentAttr,
124  getName,
125  createViewStackProcessorStatement,
126  parseGlobalBuilderParams,
127  BuilderParamsResult
128} from './process_component_build';
129import {
130  BUILDIN_STYLE_NAMES,
131  CUSTOM_BUILDER_METHOD,
132  EXTEND_ATTRIBUTE,
133  INNER_STYLE_FUNCTION,
134  GLOBAL_STYLE_FUNCTION,
135  INTERFACE_NODE_SET,
136  ID_ATTRS,
137  GLOBAL_CUSTOM_BUILDER_METHOD
138} from './component_map';
139import {
140  resources,
141  projectConfig,
142  partialUpdateConfig
143} from '../main';
144import {
145  createCustomComponentNewExpression,
146  createViewCreate
147} from './process_component_member';
148import {
149  assignComponentParams,
150  assignmentFunction
151} from './process_custom_component';
152import { processDecorator } from './fast_build/ark_compiler/process_decorator';
153import { hasArkDecorator } from './fast_build/ark_compiler/utils';
154import {
155  checkTypeReference,
156  validateModuleSpecifier
157} from './fast_build/system_api/api_check_utils';
158import constantDefine from './constant_define';
159import processStructComponentV2 from './process_struct_componentV2';
160import createAstNodeUtils from './create_ast_node_utils';
161import {
162  processSendableClass,
163  processSendableFunction,
164  processSendableType
165} from './process_sendable';
166import {
167  routerOrNavPathWrite,
168  integratedHspType,
169  routerModuleType,
170  routerBundleOrModule
171} from './process_module_package';
172
173export let transformLog: IFileLog = new createAstNodeUtils.FileLog();
174export let contextGlobal: ts.TransformationContext;
175export let resourceFileName: string = '';
176export const builderTypeParameter: { params: string[] } = { params: [] };
177
178export function processUISyntax(program: ts.Program, ut = false,
179  compilationTime: CompilationTimeStatistics = null, filePath: string = ''): Function {
180  let entryNodeKey: ts.Expression;
181  return (context: ts.TransformationContext) => {
182    contextGlobal = context;
183    let pagesDir: string;
184    let pageFile: string;
185    let hasUseResource: boolean = false;
186    let hasStruct: boolean = false;
187    let StateManagementV2: { hasReusableV2: boolean } = { hasReusableV2: false };
188    return (node: ts.SourceFile) => {
189      startTimeStatisticsLocation(compilationTime ? compilationTime.processUISyntaxTime : undefined);
190      pagesDir = path.resolve(path.dirname(node.fileName));
191      resourceFileName = path.resolve(node.fileName);
192      pageFile = path.resolve(filePath !== '' ? filePath : node.fileName);
193      if (process.env.compiler === BUILD_ON || process.env.compileTool === 'rollup') {
194        storedFileInfo.transformCacheFiles[pageFile] = {
195          mtimeMs: fs.existsSync(pageFile) ? fs.statSync(pageFile).mtimeMs : 0,
196          children: []
197        };
198        transformLog.sourceFile = node;
199        preprocessIdAttrs(node.fileName);
200        if (!ut && (process.env.compileMode !== 'moduleJson' &&
201          path.resolve(node.fileName) === path.resolve(projectConfig.projectPath, 'app.ets') ||
202          /\.ts$/.test(node.fileName))) {
203          node = ts.visitEachChild(node, processResourceNode, context);
204          node = ts.factory.updateSourceFile(node,
205            insertImportModuleNode(Array.from(node.statements), hasUseResource));
206          if (projectConfig.compileMode === ESMODULE && projectConfig.processTs === true) {
207            if (process.env.compileTool !== 'rollup') {
208              const processedNode: ts.SourceFile = ts.getTypeExportImportAndConstEnumTransformer(context)(node);
209              writeFileSyncByNode(processedNode, projectConfig, undefined);
210            }
211          }
212          const visitEachChildNode: ts.SourceFile = ts.visitEachChild(node, visitor, context);
213          stopTimeStatisticsLocation(compilationTime ? compilationTime.processUISyntaxTime : undefined);
214          return visitEachChildNode;
215        }
216        const id: number = ++componentInfo.id;
217        node = ts.visitEachChild(node, processAllNodes, context);
218        if (context.getCompilerOptions().etsAnnotationsEnable) {
219          node = ts.getAnnotationTransformer()(context)(node);
220        }
221        node = createEntryNode(node, context, entryNodeKey, id);
222        GLOBAL_STYLE_FUNCTION.forEach((block, styleName) => {
223          BUILDIN_STYLE_NAMES.delete(styleName);
224        });
225        GLOBAL_STYLE_FUNCTION.clear();
226        const statements: ts.Statement[] = Array.from(node.statements);
227        if (!partialUpdateConfig.partialUpdateMode) {
228          generateId(statements, node);
229        }
230        INTERFACE_NODE_SET.forEach(item => {
231          statements.unshift(item);
232        });
233        if (StateManagementV2.hasReusableV2) {
234          statements.unshift(processStructComponentV2.createReusableV2ReflectFunction());
235        }
236        if (partialUpdateConfig.partialUpdateMode && hasStruct) {
237          if (storedFileInfo.hasLocalBuilderInFile) {
238            statements.unshift(checkContextStack());
239          }
240          statements.unshift(checkFinalizeConstruction());
241        }
242        createNavigationInit(resourceFileName, statements);
243        insertImportModuleNode(statements, hasUseResource);
244        node = ts.factory.updateSourceFile(node, statements);
245        INTERFACE_NODE_SET.clear();
246        if (projectConfig.compileMode === ESMODULE && projectConfig.processTs === true) {
247          if (process.env.compileTool !== 'rollup') {
248            const processedNode: ts.SourceFile = ts.getTypeExportImportAndConstEnumTransformer(context)(node);
249            writeFileSyncByNode(processedNode, projectConfig, undefined);
250          }
251        }
252        const visitEachChildNode: ts.SourceFile = ts.visitEachChild(node, visitor, context);
253        stopTimeStatisticsLocation(compilationTime ? compilationTime.processUISyntaxTime : undefined);
254        return visitEachChildNode;
255      } else {
256        stopTimeStatisticsLocation(compilationTime ? compilationTime.processUISyntaxTime : undefined);
257        return node;
258      }
259    };
260
261    function entryKeyNode(node: ts.Node): ts.Expression {
262      const decorators: readonly ts.Decorator[] = ts.getAllDecorators(node);
263      if (node && decorators && decorators.length) {
264        decorators.forEach(item => {
265          if (item.expression && ts.isCallExpression(item.expression) && ts.isIdentifier(item.expression.expression) &&
266            item.expression.expression.escapedText.toString() === 'Entry' && item.expression.arguments &&
267            item.expression.arguments.length && ts.isIdentifier(item.expression.arguments[0])) {
268            entryNodeKey = item.expression.arguments[0];
269          }
270        });
271      }
272      return entryNodeKey;
273    }
274
275    function isESObjectNode(node: ts.Node): boolean {
276      if (node.kind === ts.SyntaxKind.TypeReference) {
277        const n: TypeReferenceNode = node as TypeReferenceNode;
278        if (n.typeName?.kind === ts.SyntaxKind.Identifier && (n.typeName as ts.Identifier).escapedText === 'ESObject') {
279          return true;
280        }
281      }
282      return false;
283    }
284
285    function processAllNodes(node: ts.Node): ts.Node {
286      if (projectConfig.compileMode === 'esmodule' && process.env.compileTool === 'rollup' &&
287        ts.isImportDeclaration(node)) {
288        startTimeStatisticsLocation(compilationTime ? compilationTime.processImportTime : undefined);
289        processImportModule(node, pageFile, transformLog.errors);
290        stopTimeStatisticsLocation(compilationTime ? compilationTime.processImportTime : undefined);
291      } else if ((projectConfig.compileMode !== 'esmodule' || process.env.compileTool !== 'rollup') &&
292        (ts.isImportDeclaration(node) || ts.isImportEqualsDeclaration(node) ||
293        ts.isExportDeclaration(node) && node.moduleSpecifier && ts.isStringLiteral(node.moduleSpecifier))) {
294        processImport(node, pagesDir, transformLog.errors);
295      }
296      if (ts.isStructDeclaration(node)) {
297        hasStruct = true;
298        componentCollection.currentClassName = node.name.getText();
299        componentCollection.entryComponent === componentCollection.currentClassName && entryKeyNode(node);
300        startTimeStatisticsLocation(compilationTime ? compilationTime.processComponentClassTime : undefined);
301        node = processStructComponentV2.getOrCreateStructInfo(componentCollection.currentClassName).isComponentV2 ?
302          processStructComponentV2.processStructComponentV2(node, transformLog.errors, context, StateManagementV2) :
303          processComponentClass(node, context, transformLog.errors, program);
304        stopTimeStatisticsLocation(compilationTime ? compilationTime.processComponentClassTime : undefined);
305        componentCollection.currentClassName = null;
306        INNER_STYLE_FUNCTION.forEach((block, styleName) => {
307          BUILDIN_STYLE_NAMES.delete(styleName);
308        });
309        INNER_STYLE_FUNCTION.clear();
310      } else if (ts.isFunctionDeclaration(node)) {
311        if (hasDecorator(node, COMPONENT_EXTEND_DECORATOR, null, transformLog.errors)) {
312          node = processExtend(node, transformLog.errors, COMPONENT_EXTEND_DECORATOR);
313          // @ts-ignore
314          if (node && node.illegalDecorators) {
315            // @ts-ignore
316            node.illegalDecorators = undefined;
317          }
318        } else if (hasDecorator(node, COMPONENT_BUILDER_DECORATOR) && node.name && node.body &&
319          ts.isBlock(node.body)) {
320          storedFileInfo.processBuilder = true;
321          storedFileInfo.processGlobalBuilder = true;
322          CUSTOM_BUILDER_METHOD.add(node.name.getText());
323          builderTypeParameter.params = getPossibleBuilderTypeParameter(node.parameters);
324          const parameters: ts.NodeArray<ts.ParameterDeclaration> =
325            ts.factory.createNodeArray(Array.from(node.parameters));
326          parameters.push(createParentParameter());
327          if (projectConfig.optLazyForEach) {
328            parameters.push(initializeMYIDS());
329          }
330          storedFileInfo.builderLikeCollection = CUSTOM_BUILDER_METHOD;
331          const builderParamsResult: BuilderParamsResult = { firstParam: null };
332          parseGlobalBuilderParams(node.parameters, builderParamsResult);
333          const componentBlock: ts.Block = processComponentBlock(node.body, false, transformLog.errors, false, true,
334            node.name.getText(), undefined, true, builderParamsResult, true);
335          node = ts.factory.updateFunctionDeclaration(node, ts.getModifiers(node),
336            node.asteriskToken, node.name, node.typeParameters, parameters, node.type,
337            componentBlock);
338          builderParamsResult.firstParam = null;
339          // @ts-ignore
340          if (node && node.illegalDecorators) {
341            // @ts-ignore
342            node.illegalDecorators = undefined;
343          }
344          builderTypeParameter.params = [];
345          node = processBuildMember(node, context, transformLog.errors, true);
346          storedFileInfo.processBuilder = false;
347          storedFileInfo.processGlobalBuilder = false;
348        } else if (hasDecorator(node, COMPONENT_STYLES_DECORATOR)) {
349          if (node.parameters.length === 0) {
350            node = undefined;
351          } else {
352            transformLog.errors.push({
353              type: LogType.ERROR,
354              message: `'@Styles' decorated functions and methods cannot have arguments.`,
355              pos: node.getStart(),
356              code: '10905110'
357            });
358          }
359        } else if (hasDecorator(node, COMPONENT_CONCURRENT_DECORATOR)) {
360          // ark compiler's feature
361          node = processConcurrent(node);
362          if (node && node.illegalDecorators) {
363            // @ts-ignore
364            node.illegalDecorators = undefined;
365          }
366        } else if (hasArkDecorator(node, COMPONENT_SENDABLE_DECORATOR)) {
367          // ark compiler's feature
368          node = processSendableFunction(node);
369          if (node && node.illegalDecorators) {
370            node.illegalDecorators = undefined;
371          }
372        } else if (hasDecorator(node, COMPONENT_ANIMATABLE_EXTEND_DECORATOR, null, transformLog.errors)) {
373          node = processExtend(node, transformLog.errors, COMPONENT_ANIMATABLE_EXTEND_DECORATOR);
374          // @ts-ignore
375          if (node && node.illegalDecorators) {
376            // @ts-ignore
377            node.illegalDecorators = undefined;
378          }
379        }
380      } else if (isResource(node)) {
381        hasUseResource = true;
382        node = processResourceData(node as ts.CallExpression, filePath);
383      } else if (isWorker(node)) {
384        node = processWorker(node as ts.NewExpression);
385      } else if (isAnimateToOrImmediately(node)) {
386        node = processAnimateToOrImmediately(node as ts.CallExpression);
387      } else if (isCustomDialogController(node)) {
388        node = createCustomDialogController(node.parent, node, transformLog.errors);
389      } else if (isESObjectNode(node)) {
390        node = ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword);
391      } else if (ts.isDecorator(node)) {
392        // This processing is for mock instead of ui transformation
393        node = processDecorator(node);
394      } else if (isWrapBuilderFunction(node)) {
395        if (node.arguments && node.arguments[0] && (!ts.isIdentifier(node.arguments[0]) ||
396          ts.isIdentifier(node.arguments[0]) &&
397          !CUSTOM_BUILDER_METHOD.has(node.arguments[0].escapedText.toString()))) {
398          transformLog.errors.push({
399            type: LogType.ERROR,
400            message: `The wrapBuilder's parameter should be '@Builder' function.`,
401            pos: node.getStart(),
402            code: '10905109'
403          });
404        }
405      } else if (ts.isClassDeclaration(node)) {
406        if (hasDecorator(node, COMPONENT_SENDABLE_DECORATOR)) {
407          if (projectConfig.compileHar && !projectConfig.useTsHar) {
408            let warnMessage: string = 'If you use @Sendable in js har, an exception will occur during runtime.\n' +
409                                      'Please use @Sendable in ts har. You can configure {"name": "UseTsHar", ' +
410                                      '"value": "true"} in the "metadata" in the module.json5 file in har.';
411            transformLog.errors.push({
412              type: LogType.WARN,
413              message: warnMessage,
414              pos: node.getStart()
415            });
416          }
417          node = processSendableClass(node);
418        }
419      } else if (ts.isTypeAliasDeclaration(node) && hasArkDecorator(node, COMPONENT_SENDABLE_DECORATOR)) {
420        node = processSendableType(node);
421        if (node && node.illegalDecorators) {
422          node.illegalDecorators = undefined;
423        }
424      }
425      return ts.visitEachChild(node, processAllNodes, context);
426    }
427
428    function processResourceNode(node: ts.Node): ts.Node {
429      if (ts.isImportDeclaration(node)) {
430        validateModuleSpecifier(node.moduleSpecifier, transformLog.errors);
431      } else if (isResource(node)) {
432        hasUseResource = true;
433        node = processResourceData(node as ts.CallExpression, filePath);
434      } else if (ts.isTypeReferenceNode(node)) {
435        checkTypeReference(node, transformLog);
436      }
437      return ts.visitEachChild(node, processResourceNode, context);
438    }
439
440    function isWrapBuilderFunction(node: ts.Node): boolean {
441      if (ts.isCallExpression(node) && node.expression && ts.isIdentifier(node.expression) &&
442        node.expression.escapedText.toString() === WRAPBUILDER_FUNCTION) {
443        return true;
444      }
445      return false;
446    }
447
448    function visitor(node: ts.Node): ts.VisitResult<ts.Node> {
449      return ts.visitEachChild(node, visitor, context);
450    }
451  };
452}
453
454export function globalBuilderParamAssignment(): ts.VariableStatement {
455  const contextStackCondition: ts.PropertyAccessExpression = ts.factory.createPropertyAccessExpression(
456    ts.factory.createIdentifier(PUV2_VIEW_BASE),
457    ts.factory.createIdentifier(CONTEXT_STACK)
458  );
459  return ts.factory.createVariableStatement(
460    undefined,
461    ts.factory.createVariableDeclarationList(
462      [ts.factory.createVariableDeclaration(
463        ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARENT),
464        undefined,
465        undefined,
466        ts.factory.createConditionalExpression(
467          ts.factory.createBinaryExpression(
468            contextStackCondition,
469            ts.factory.createToken(ts.SyntaxKind.AmpersandAmpersandToken),
470            ts.factory.createPropertyAccessExpression(
471              contextStackCondition,
472              ts.factory.createIdentifier(LENGTH)
473            )
474          ),
475          ts.factory.createToken(ts.SyntaxKind.QuestionToken),
476          ts.factory.createElementAccessExpression(
477            contextStackCondition,
478            ts.factory.createBinaryExpression(
479              ts.factory.createPropertyAccessExpression(
480                contextStackCondition,
481                ts.factory.createIdentifier(LENGTH)
482              ),
483              ts.factory.createToken(ts.SyntaxKind.MinusToken),
484              ts.factory.createNumericLiteral('1')
485            )
486          ),
487          ts.factory.createToken(ts.SyntaxKind.ColonToken),
488          ts.factory.createNull()
489        )
490      )],
491      ts.NodeFlags.Const
492    ));
493}
494
495function createNavigationInit(fileName: string, statements: ts.Statement[]): void {
496  const newStoredFileInfo: ProcessFileInfo = getStoredFileInfo();
497  if (newStoredFileInfo.routerInfo.has(fileName)) {
498    const routerInfoArr: Array<RouterInfo> = newStoredFileInfo.routerInfo.get(fileName);
499    const builderStatements: ts.Statement[] = [];
500    routerInfoArr.forEach((item) => {
501      if (GLOBAL_CUSTOM_BUILDER_METHOD.has(item.buildFunction)) {
502        builderStatements.push(createNavigationRegister(item));
503      } else {
504        transformLog.errors.push({
505          type: LogType.ERROR,
506          message: `The buildFunction '${item.buildFunction}' configured in the routerMap json file does not exist.`,
507          code: '10904336'
508        });
509      }
510    });
511    statements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression(
512      ts.factory.createParenthesizedExpression(ts.factory.createFunctionExpression(
513        undefined, undefined, undefined, undefined, [], undefined,
514        ts.factory.createBlock(
515          [ts.factory.createIfStatement(ts.factory.createBinaryExpression(
516            ts.factory.createTypeOfExpression(ts.factory.createIdentifier(constantDefine.NAVIGATION_BUILDER_REGISTER)),
517            ts.factory.createToken(ts.SyntaxKind.EqualsEqualsEqualsToken), ts.factory.createStringLiteral(FUNCTION)),
518          ts.factory.createBlock(builderStatements, true), undefined)], true)
519      )), undefined, []
520    )));
521  }
522}
523
524function createNavigationRegister(routerInfo: RouterInfo): ts.Statement {
525  return ts.factory.createExpressionStatement(ts.factory.createCallExpression(
526    ts.factory.createIdentifier(constantDefine.NAVIGATION_BUILDER_REGISTER),
527    undefined,
528    [
529      ts.factory.createStringLiteral(routerInfo.name),
530      ts.factory.createCallExpression(
531        ts.factory.createIdentifier(WRAPBUILDER_FUNCTION),
532        undefined,
533        [ts.factory.createIdentifier(routerInfo.buildFunction)]
534      )
535    ]
536  ));
537}
538
539export function initializeMYIDS(): ts.ParameterDeclaration {
540  return ts.factory.createParameterDeclaration(
541    undefined,
542    undefined,
543    ts.factory.createIdentifier(MY_IDS),
544    undefined,
545    undefined,
546    ts.factory.createArrayLiteralExpression(
547      [],
548      false
549    )
550  );
551}
552
553function generateId(statements: ts.Statement[], node: ts.SourceFile): void {
554  statements.unshift(
555    ts.factory.createVariableStatement(
556      undefined,
557      ts.factory.createVariableDeclarationList(
558        [ts.factory.createVariableDeclaration(
559          ts.factory.createIdentifier(_GENERATE_ID),
560          undefined,
561          ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword),
562          ts.factory.createNumericLiteral('0')
563        )],
564        ts.NodeFlags.Let
565      )
566    ),
567    ts.factory.createFunctionDeclaration(
568      undefined,
569      undefined,
570      ts.factory.createIdentifier(GENERATE_ID),
571      undefined,
572      [],
573      ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
574      ts.factory.createBlock(
575        [ts.factory.createReturnStatement(ts.factory.createBinaryExpression(
576          ts.factory.createStringLiteral(path.basename(node.fileName, EXTNAME_ETS) + '_'),
577          ts.factory.createToken(ts.SyntaxKind.PlusToken), ts.factory.createPrefixUnaryExpression(
578            ts.SyntaxKind.PlusPlusToken,
579            ts.factory.createIdentifier(_GENERATE_ID)
580          )))],
581        true
582      )
583    )
584  );
585}
586
587function preprocessIdAttrs(fileName: string): void {
588  for (const [id, idInfo] of ID_ATTRS) {
589    if (fileName === idInfo.get('path')) {
590      ID_ATTRS.delete(id);
591    }
592  }
593}
594
595function isCustomDialogController(node: ts.Expression) {
596  const tempParent: ts.Node = node.parent;
597  // @ts-ignore
598  if (!node.parent && node.original) {
599    // @ts-ignore
600    node.parent = node.original.parent;
601  }
602  if (ts.isNewExpression(node) && node.expression && ts.isIdentifier(node.expression) &&
603    node.expression.escapedText.toString() === SET_CONTROLLER_CTR_TYPE) {
604    return true;
605  } else {
606    // @ts-ignore
607    node.parent = tempParent;
608    return false;
609  }
610}
611
612function createCustomDialogController(parent: ts.Expression, node: ts.NewExpression,
613  log: LogInfo[]): ts.NewExpression {
614  if (node.arguments && node.arguments.length === 1 &&
615    ts.isObjectLiteralExpression(node.arguments[0]) && node.arguments[0].properties) {
616    const newproperties: ts.ObjectLiteralElementLike[] = node.arguments[0].properties.map((item) => {
617      const componentName: string = isCustomDialogControllerPropertyAssignment(item, log);
618      if (componentName !== null) {
619        item = processCustomDialogControllerPropertyAssignment(parent,
620          item as ts.PropertyAssignment, componentName);
621      }
622      return item;
623    });
624    return ts.factory.createNewExpression(node.expression, node.typeArguments,
625      [ts.factory.createObjectLiteralExpression(newproperties, true), ts.factory.createThis()]);
626  } else {
627    return node;
628  }
629}
630
631function isCustomDialogControllerPropertyAssignment(node: ts.ObjectLiteralElementLike,
632  log: LogInfo[]): string {
633  if (ts.isPropertyAssignment(node) && ts.isIdentifier(node.name) &&
634    node.name.getText() === CUSTOM_DIALOG_CONTROLLER_BUILDER) {
635    if (node.initializer) {
636      const componentName: string = getName(node.initializer);
637      if (componentCollection.customDialogs.has(componentName)) {
638        return componentName;
639      }
640    } else {
641      validateCustomDialogControllerBuilderInit(node, log);
642    }
643  }
644  return null;
645}
646
647function validateCustomDialogControllerBuilderInit(node: ts.ObjectLiteralElementLike,
648  log: LogInfo[]): void {
649  log.push({
650    type: LogType.ERROR,
651    message: 'The builder should be initialized with a @CustomDialog Component.',
652    pos: node.getStart(),
653    code: '10905335'
654  });
655}
656
657function processCustomDialogControllerPropertyAssignment(parent: ts.Expression,
658  node: ts.PropertyAssignment, componentName: string): ts.PropertyAssignment {
659  if (ts.isCallExpression(node.initializer)) {
660    return ts.factory.updatePropertyAssignment(node, node.name,
661      processCustomDialogControllerBuilder(parent, node.initializer, componentName));
662  }
663  return undefined;
664}
665
666function processCustomDialogControllerBuilder(parent: ts.Expression,
667  node: ts.CallExpression, componentName: string): ts.ArrowFunction {
668  const newExp: ts.Expression = createCustomComponentNewExpression(node, componentName, false, false, true);
669  const jsDialog: ts.Identifier = ts.factory.createIdentifier(JS_DIALOG);
670  return createCustomComponentBuilderArrowFunction(node, parent, jsDialog, newExp);
671}
672
673function createCustomComponentBuilderArrowFunction(node: ts.CallExpression, parent: ts.Expression,
674  jsDialog: ts.Identifier, newExp: ts.Expression): ts.ArrowFunction {
675  let mountNodde: ts.PropertyAccessExpression;
676  if (ts.isBinaryExpression(parent)) {
677    mountNodde = parent.left;
678  } else if (ts.isVariableDeclaration(parent) || ts.isPropertyDeclaration(parent)) {
679    mountNodde = ts.factory.createPropertyAccessExpression(ts.factory.createThis(),
680      parent.name as ts.Identifier);
681  }
682  return ts.factory.createArrowFunction(
683    undefined,
684    undefined,
685    [],
686    undefined,
687    ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
688    ts.factory.createBlock(
689      [
690        ts.factory.createVariableStatement(
691          undefined,
692          ts.factory.createVariableDeclarationList(
693            [ts.factory.createVariableDeclaration(jsDialog, undefined, undefined, newExp)],
694            ts.NodeFlags.Let
695          )
696        ),
697        ts.factory.createExpressionStatement(
698          ts.factory.createCallExpression(
699            ts.factory.createPropertyAccessExpression(
700              jsDialog,
701              ts.factory.createIdentifier(SET_CONTROLLER_METHOD)
702            ),
703            undefined,
704            mountNodde ? [mountNodde] : undefined
705          )
706        ),
707        ts.factory.createExpressionStatement(createViewCreate(jsDialog)),
708        partialUpdateConfig.partialUpdateMode ? assignComponentParams(node) : undefined,
709        partialUpdateConfig.partialUpdateMode ? assignmentFunction(jsDialog.escapedText.toString()) : undefined
710      ],
711      true
712    )
713  );
714}
715
716export function isResource(node: ts.Node): boolean {
717  return ts.isCallExpression(node) && ts.isIdentifier(node.expression) &&
718    (node.expression.escapedText.toString() === RESOURCE ||
719    node.expression.escapedText.toString() === RESOURCE_RAWFILE) && node.arguments.length > 0;
720}
721
722export function isAnimateToOrImmediately(node: ts.Node): boolean {
723  return ts.isCallExpression(node) && ts.isIdentifier(node.expression) &&
724    ATTRIBUTE_ANIMATETO_SET.has(node.expression.escapedText.toString());
725}
726
727export function processResourceData(node: ts.CallExpression, filePath: string,
728  previewLog: {isAcceleratePreview: boolean, log: LogInfo[]} = {isAcceleratePreview: false, log: []}): ts.Node {
729  if (ts.isStringLiteral(node.arguments[0])) {
730    const resourceData: string[] = (node.arguments[0] as ts.StringLiteral).text.trim().split('.');
731    const isResourceModule: boolean = resourceData.length && /^\[.*\]$/g.test(resourceData[0]);
732    if (node.expression.getText() === RESOURCE_RAWFILE) {
733      isResourcefile(node, previewLog, isResourceModule);
734      if (resourceData && resourceData[0] && isResourceModule) {
735        return createResourceParam(-1, RESOURCE_TYPE.rawfile, [node.arguments[0]], resourceData[0], true);
736      } else {
737        return createResourceParam(0, RESOURCE_TYPE.rawfile, [node.arguments[0]], '', false);
738      }
739    } else {
740      return getResourceDataNode(node, previewLog, resourceData, isResourceModule, filePath);
741    }
742  } else if (node.expression.getText() === RESOURCE && node.arguments && node.arguments.length) {
743    resourcePreviewMessage(previewLog);
744    return createResourceParamWithVariable(node, -1, -1);
745  } else if (node.expression.getText() === RESOURCE_RAWFILE && node.arguments && node.arguments.length) {
746    resourcePreviewMessage(previewLog);
747    return createResourceParamWithVariable(node, -1, RESOURCE_TYPE.rawfile);
748  }
749  return node;
750}
751
752function resourcePreviewMessage(previewLog: {isAcceleratePreview: boolean, log: LogInfo[]}): void {
753  if (previewLog.isAcceleratePreview) {
754    previewLog.log.push({
755      type: LogType.ERROR,
756      message: 'not support AcceleratePreview',
757      code: '10906401'
758    });
759  }
760}
761
762function getResourceDataNode(node: ts.CallExpression,
763  previewLog: {isAcceleratePreview: boolean, log: LogInfo[]}, resourceData: string[], isResourceModule: boolean, filePath: string): ts.Node {
764  let resourceValue: number;
765  if (preCheckResourceData(resourceData, resources, node.arguments[0].getStart(), previewLog, isResourceModule, filePath)) {
766    let resourceType: number = RESOURCE_TYPE[resourceData[1]];
767    if (resourceType === undefined && !previewLog.isAcceleratePreview) {
768      transformLog.errors.push({
769        type: LogType.ERROR,
770        message: `The resource type '${resourceData[1]}' is not supported.`,
771        pos: node.getStart(),
772        code: '10906334'
773      });
774      return node;
775    }
776    if (isResourceModule) {
777      resourceValue = -1;
778      resourceType = -1;
779    } else {
780      resourceValue = resources[resourceData[0]][resourceData[1]][resourceData[2]];
781    }
782    return createResourceParam(resourceValue, resourceType,
783      projectConfig.compileHar || isResourceModule ? Array.from(node.arguments) : Array.from(node.arguments).slice(1),
784      resourceData.length && resourceData[0], isResourceModule);
785  }
786  return node;
787}
788
789function isResourcefile(node: ts.CallExpression, previewLog: {isAcceleratePreview: boolean, log: LogInfo[]}, isResourceModule: boolean): void {
790  if (!isResourceModule && process.env.rawFileResource && !storedFileInfo.resourcesArr.has(node.arguments[0].text) &&
791    !previewLog.isAcceleratePreview && process.env.compileMode === 'moduleJson') {
792    transformLog.errors.push({
793      type: LogType.ERROR,
794      message: `No such '${node.arguments[0].text}' resource in current module.`,
795      pos: node.getStart(),
796      code: '10904333'
797    });
798  }
799}
800
801function addBundleAndModuleParam(propertyArray: Array<ts.PropertyAssignment>, resourceModuleName: string, isResourceModule: boolean): void {
802  if (projectConfig.compileHar) {
803    projectConfig.bundleName = '__harDefaultBundleName__';
804    projectConfig.moduleName = '__harDefaultModuleName__';
805  }
806  const isDynamicBundleOrModule: boolean = isDynamic();
807  const moduleNameNode: ts.Expression = createResourceModuleNode(resourceModuleName, isResourceModule, isDynamicBundleOrModule);
808  if (projectConfig.bundleName || projectConfig.bundleName === '') {
809    propertyArray.push(ts.factory.createPropertyAssignment(
810      ts.factory.createStringLiteral(RESOURCE_NAME_BUNDLE),
811      (projectConfig.resetBundleName || projectConfig.allowEmptyBundleName) ? ts.factory.createStringLiteral('') :
812        createBundleOrModuleNode(isDynamicBundleOrModule, 'bundleName')
813    ));
814  }
815  if (projectConfig.moduleName || projectConfig.moduleName === '' || moduleNameNode) {
816    propertyArray.push(ts.factory.createPropertyAssignment(
817      ts.factory.createStringLiteral(RESOURCE_NAME_MODULE),
818      isResourceModule ? moduleNameNode : createBundleOrModuleNode(isDynamicBundleOrModule, 'moduleName')
819    ));
820  }
821}
822
823function createResourceModuleNode(resourceModuleName: string, isResourceModule: boolean,
824  isDynamicBundleOrModule: boolean): ts.Expression {
825  if (isResourceModule) {
826    if (resourceModuleName) {
827      const moduleName: string = resourceModuleName.replace(/^\[|\]$/g, '');
828      return ts.factory.createStringLiteral(moduleName);
829    }
830    if (isDynamicBundleOrModule) {
831      return ts.factory.createIdentifier('__MODULE_NAME__');
832    }
833    return projectConfig.moduleName ? ts.factory.createStringLiteral(projectConfig.moduleName) : undefined;
834  }
835  return undefined;
836}
837
838function createBundleOrModuleNode(isDynamicBundleOrModule: boolean, type: string): ts.Expression {
839  if (isDynamicBundleOrModule) {
840    return ts.factory.createIdentifier(type === 'bundleName' ? '__BUNDLE_NAME__' : '__MODULE_NAME__');
841  }
842  return ts.factory.createStringLiteral(type === 'bundleName' ? projectConfig.bundleName :
843    projectConfig.moduleName);
844}
845
846function createResourceParamWithVariable(node: ts.CallExpression, resourceValue: number, resourceType: number): ts.ObjectLiteralExpression {
847  const propertyArray: Array<ts.PropertyAssignment> = [
848    ts.factory.createPropertyAssignment(
849      ts.factory.createStringLiteral(RESOURCE_NAME_ID),
850      ts.factory.createNumericLiteral(resourceValue)
851    ),
852    ts.factory.createPropertyAssignment(
853      ts.factory.createStringLiteral(RESOURCE_NAME_TYPE),
854      ts.factory.createNumericLiteral(resourceType)
855    ),
856    ts.factory.createPropertyAssignment(
857      ts.factory.createIdentifier(RESOURCE_NAME_PARAMS),
858      ts.factory.createArrayLiteralExpression(Array.from(node.arguments), false)
859    )
860  ];
861
862  addBundleAndModuleParam(propertyArray, '', true);
863
864  const resourceParams: ts.ObjectLiteralExpression = ts.factory.createObjectLiteralExpression(
865    propertyArray, false);
866  return resourceParams;
867}
868
869function createResourceParam(resourceValue: number, resourceType: number, argsArr: ts.Expression[],
870  resourceModuleName: string, isResourceModule: boolean):
871  ts.ObjectLiteralExpression {
872  if (projectConfig.compileHar) {
873    resourceValue = -1;
874  }
875
876  const propertyArray: Array<ts.PropertyAssignment> = [
877    ts.factory.createPropertyAssignment(
878      ts.factory.createStringLiteral(RESOURCE_NAME_ID),
879      ts.factory.createNumericLiteral(resourceValue)
880    ),
881    ts.factory.createPropertyAssignment(
882      ts.factory.createStringLiteral(RESOURCE_NAME_TYPE),
883      ts.factory.createNumericLiteral(resourceType)
884    ),
885    ts.factory.createPropertyAssignment(
886      ts.factory.createIdentifier(RESOURCE_NAME_PARAMS),
887      ts.factory.createArrayLiteralExpression(argsArr, false)
888    )
889  ];
890
891  addBundleAndModuleParam(propertyArray, resourceModuleName, isResourceModule);
892
893  const resourceParams: ts.ObjectLiteralExpression = ts.factory.createObjectLiteralExpression(
894    propertyArray, false);
895  return resourceParams;
896}
897
898function preCheckResourceData(resourceData: string[], resources: object, pos: number,
899  previewLog: {isAcceleratePreview: boolean, log: LogInfo[]}, isResourceModule: boolean, filePath: string): boolean {
900  if (previewLog.isAcceleratePreview) {
901    return validateResourceData(resourceData, resources, pos, previewLog.log, true, isResourceModule, filePath);
902  } else {
903    return validateResourceData(resourceData, resources, pos, transformLog.errors, false, isResourceModule, filePath);
904  }
905}
906
907function validateResourceData(resourceData: string[], resources: object, pos: number, log: LogInfo[], isAcceleratePreview: boolean,
908  isResourceModule: boolean, filePath: string): boolean {
909  if (resourceData.length !== 3) {
910    log.push({
911      type: LogType.ERROR,
912      message: `Invalid resource file parameter. Enter a value in the format of 'xxx.yyy.zzz'.`,
913      pos,
914      code: '10905332'
915    });
916  } else {
917    if (!isAcceleratePreview && process.env.compileTool === 'rollup' && process.env.compileMode === 'moduleJson') {
918      storedFileInfo.collectResourceInFile(resourceData[1] + '_' + resourceData[2], path.resolve(filePath));
919    }
920    if (isResourceModule) {
921      if (/^\[.*\]$/.test(resourceData[0]) && projectConfig.hspResourcesMap) {
922        const resourceDataFirst: string = resourceData[0].replace(/^\[/, '').replace(/\]$/, '').trim();
923        return resourceCheck(resourceData, resources, pos, log, true, resourceDataFirst, false);
924      } else {
925        return resourceCheck(resourceData, resources, pos, log, false, resourceData[0], true);
926      }
927    } else {
928      return resourceCheck(resourceData, resources, pos, log, false, resourceData[0], false);
929    }
930  }
931  return false;
932}
933
934function resourceCheck(resourceData: string[], resources: object, pos: number, log: LogInfo[], isHspResourceModule: boolean,
935  resourceDataFirst: string, faOrNoHspResourcesMap: boolean): boolean {
936  const logType: LogType = isHspResourceModule ? LogType.WARN : LogType.ERROR;
937  if (!faOrNoHspResourcesMap && !resources[resourceDataFirst]) {
938    log.push({
939      type: logType,
940      message: `Unknown resource source '${resourceDataFirst}'.`,
941      pos,
942      code: '10903331'
943    });
944  } else if (!faOrNoHspResourcesMap && !resources[resourceDataFirst][resourceData[1]]) {
945    log.push({
946      type: logType,
947      message: `Unknown resource type '${resourceData[1]}'.`,
948      pos,
949      code: '10903330'
950    });
951  } else if (!faOrNoHspResourcesMap && !resources[resourceDataFirst][resourceData[1]][resourceData[2]]) {
952    log.push({
953      type: logType,
954      message: `Unknown resource name '${resourceData[2]}'.`,
955      pos,
956      code: '10903329'
957    });
958  } else {
959    return true;
960  }
961  return false;
962}
963
964function isWorker(node: ts.Node): boolean {
965  return ts.isNewExpression(node) && ts.isPropertyAccessExpression(node.expression) &&
966    ts.isIdentifier(node.expression.name) &&
967    node.expression.name.escapedText.toString() === WORKER_OBJECT;
968}
969
970function processWorker(node: ts.NewExpression): ts.Node {
971  if (node.arguments.length && ts.isStringLiteral(node.arguments[0])) {
972    const args: ts.Expression[] = Array.from(node.arguments);
973    // @ts-ignore
974    const workerPath: string = node.arguments[0].text;
975    const stringNode: ts.StringLiteral = ts.factory.createStringLiteral(
976      workerPath.replace(/\.ts$/, '.js'));
977    args.splice(0, 1, stringNode);
978    return ts.factory.updateNewExpression(node, node.expression, node.typeArguments, args);
979  }
980  return node;
981}
982
983export function processAnimateToOrImmediately(node: ts.CallExpression): ts.CallExpression {
984  return ts.factory.updateCallExpression(node, ts.factory.createPropertyAccessExpression(
985    ts.factory.createIdentifier(GLOBAL_CONTEXT),
986    ts.factory.createIdentifier(node.expression.escapedText.toString())),
987  node.typeArguments, node.arguments);
988}
989
990function processExtend(node: ts.FunctionDeclaration, log: LogInfo[],
991  decoratorName: string): ts.FunctionDeclaration {
992  const componentName: string = isExtendFunction(node, { decoratorName: '', componentName: '' }, true);
993  if (componentName && node.body && node.body.statements.length) {
994    const statementArray: ts.Statement[] = [];
995    let bodynode: ts.Block;
996    if (decoratorName === COMPONENT_EXTEND_DECORATOR) {
997      const attrSet: ts.CallExpression = node.body.statements[0].expression;
998      if (isOriginalExtend(node.body)) {
999        const changeCompName: ts.ExpressionStatement = ts.factory.createExpressionStatement(processExtendBody(attrSet));
1000        bindComponentAttr(changeCompName as ts.ExpressionStatement,
1001          ts.factory.createIdentifier(componentName), statementArray, log);
1002      } else {
1003        bodynode = ts.visitEachChild(node.body, traverseExtendExpression, contextGlobal);
1004      }
1005      let extendFunctionName: string;
1006      if (node.name.getText().startsWith('__' + componentName + '__')) {
1007        extendFunctionName = node.name.getText();
1008      } else {
1009        extendFunctionName = '__' + componentName + '__' + node.name.getText();
1010        collectExtend(EXTEND_ATTRIBUTE, componentName, node.name.escapedText.toString());
1011      }
1012      return ts.factory.updateFunctionDeclaration(node, ts.getModifiers(node), node.asteriskToken,
1013        ts.factory.createIdentifier(extendFunctionName), node.typeParameters,
1014        node.parameters, ts.factory.createToken(ts.SyntaxKind.VoidKeyword), isOriginalExtend(node.body) ?
1015          ts.factory.updateBlock(node.body, statementArray) : bodynode);
1016    }
1017    if (decoratorName === COMPONENT_ANIMATABLE_EXTEND_DECORATOR) {
1018      bindComponentAttr(node.body.statements[0],
1019        ts.factory.createIdentifier(componentName), statementArray, log);
1020      return ts.factory.updateFunctionDeclaration(node, ts.getModifiers(node), node.asteriskToken,
1021        node.name, node.typeParameters,
1022        [...node.parameters, ...createAnimatableParameterNode()], ts.factory.createToken(ts.SyntaxKind.VoidKeyword),
1023        ts.factory.updateBlock(node.body, createAnimatableBody(componentName, node.name,
1024          node.parameters, statementArray)));
1025    }
1026  }
1027  function traverseExtendExpression(node: ts.Node): ts.Node {
1028    if (ts.isExpressionStatement(node) && isDollarNode(node, componentName)) {
1029      const changeCompName: ts.ExpressionStatement =
1030        ts.factory.createExpressionStatement(processExtendBody(node.expression, componentName));
1031      const statementArray: ts.Statement[] = [];
1032      bindComponentAttr(changeCompName, ts.factory.createIdentifier(componentName), statementArray, []);
1033      return ts.factory.createBlock(statementArray, true);
1034    }
1035    return ts.visitEachChild(node, traverseExtendExpression, contextGlobal);
1036  }
1037  return undefined;
1038}
1039
1040function createAnimatableParameterNode(): ts.ParameterDeclaration[] {
1041  return [
1042    ts.factory.createParameterDeclaration(
1043      undefined, undefined, ts.factory.createIdentifier(ELMTID)),
1044    ts.factory.createParameterDeclaration(
1045      undefined, undefined, ts.factory.createIdentifier(ISINITIALRENDER)),
1046    ts.factory.createParameterDeclaration(
1047      undefined, undefined, ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARENT))
1048  ];
1049}
1050
1051function createAnimatableBody(componentName: string, funcName: ts.Identifier,
1052  parameters: ts.NodeArray<ts.ParameterDeclaration>, attrArray: ts.Statement[]): ts.Statement[] {
1053  const paramNode: ts.Identifier[] = [];
1054  parameters.forEach((item: ts.ParameterDeclaration) => {
1055    if (item.name && ts.isIdentifier(item.name)) {
1056      paramNode.push(item.name);
1057    }
1058  });
1059  return [
1060    ts.factory.createIfStatement(
1061      ts.factory.createIdentifier(ISINITIALRENDER),
1062      ts.factory.createBlock([
1063        createAnimatableProperty(componentName, funcName, parameters, paramNode, attrArray),
1064        ...attrArray
1065      ], true),
1066      ts.factory.createBlock([
1067        ts.factory.createExpressionStatement(ts.factory.createCallExpression(
1068          ts.factory.createPropertyAccessExpression(
1069            ts.factory.createIdentifier(componentName),
1070            ts.factory.createIdentifier(UPDATE_ANIMATABLE_PROPERTY)
1071          ), undefined,
1072          [ts.factory.createStringLiteral(funcName.escapedText.toString()), ...paramNode]
1073        ))
1074      ])
1075    )
1076  ];
1077}
1078
1079function createAnimatableProperty(componentName: string, funcName: ts.Identifier,
1080  parameters: ts.NodeArray<ts.ParameterDeclaration>,
1081  paramNode: ts.Identifier[], attrArray: ts.Statement[]) {
1082  const componentIdentifier: ts.Identifier = ts.factory.createIdentifier(componentName);
1083  return ts.factory.createExpressionStatement(
1084    ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(
1085      componentIdentifier,
1086      ts.factory.createIdentifier(CREATE_ANIMATABLE_PROPERTY)),
1087    undefined, [
1088      ts.factory.createStringLiteral(funcName.escapedText.toString()),
1089      ...paramNode,
1090      ts.factory.createArrowFunction(undefined, undefined, parameters, undefined,
1091        ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
1092        ts.factory.createBlock([
1093          createViewStackProcessorStatement(STARTGETACCESSRECORDINGFOR, ELMTID),
1094          createAnimatableFrameNode(componentName),
1095          ...attrArray,
1096          createViewStackProcessorStatement(STOPGETACCESSRECORDING),
1097          createAnimatableUpdateFunc()
1098        ], true))
1099    ]
1100    )
1101  );
1102}
1103
1104function createAnimatableFrameNode(componentName: string): ts.ExpressionStatement {
1105  return ts.factory.createExpressionStatement(ts.factory.createCallExpression(
1106    ts.factory.createPropertyAccessExpression(
1107      ts.factory.createIdentifier(VIEW_STACK_PROCESSOR),
1108      ts.factory.createIdentifier(GET_AND_PUSH_FRAME_NODE)
1109    ), undefined,
1110    [
1111      ts.factory.createStringLiteral(componentName),
1112      ts.factory.createIdentifier(ELMTID)
1113    ]
1114  ));
1115}
1116
1117function createAnimatableUpdateFunc(): ts.ExpressionStatement {
1118  return ts.factory.createExpressionStatement(ts.factory.createCallExpression(
1119    ts.factory.createPropertyAccessExpression(
1120      ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARENT),
1121      ts.factory.createIdentifier(FINISH_UPDATE_FUNC)
1122    ), undefined, [ts.factory.createIdentifier(ELMTID)]
1123  ));
1124}
1125
1126function processConcurrent(node: ts.FunctionDeclaration): ts.FunctionDeclaration {
1127  if (node.body) {
1128    const statementArray: ts.Statement[] =
1129      [ts.factory.createExpressionStatement(ts.factory.createStringLiteral('use concurrent')),
1130        ...node.body.statements];
1131    return ts.factory.updateFunctionDeclaration(node, ts.getModifiers(node), node.asteriskToken, node.name,
1132      node.typeParameters, node.parameters, node.type, ts.factory.updateBlock(node.body, statementArray));
1133  }
1134  return node;
1135}
1136
1137export function isOriginalExtend(node: ts.Block): boolean {
1138  let innerNode: ts.Node = node.statements[0];
1139  if (node.statements.length === 1 && ts.isExpressionStatement(innerNode)) {
1140    while (innerNode.expression) {
1141      innerNode = innerNode.expression;
1142    }
1143    if (ts.isIdentifier(innerNode) && innerNode.pos && innerNode.end && innerNode.pos === innerNode.end &&
1144      innerNode.escapedText.toString().match(/Instance$/)) {
1145      return true;
1146    }
1147  }
1148  return false;
1149}
1150
1151function isDollarNode(node: ts.ExpressionStatement, componentName: string): boolean {
1152  let innerNode: ts.Node = node;
1153  while (innerNode.expression) {
1154    innerNode = innerNode.expression;
1155  }
1156  let changedIdentifier: string = '$';
1157  if (process.env.compileTool === 'rollup' && storedFileInfo.reUseProgram) {
1158    changedIdentifier = `${componentName}Instance`;
1159  }
1160  if (ts.isIdentifier(innerNode) && innerNode.getText() === changedIdentifier) {
1161    return true;
1162  } else {
1163    return false;
1164  }
1165}
1166
1167function processExtendBody(node: ts.Node, componentName?: string): ts.Expression {
1168  switch (node.kind) {
1169    case ts.SyntaxKind.CallExpression:
1170      return ts.factory.createCallExpression(processExtendBody(node.expression, componentName),
1171        undefined, node.arguments);
1172    case ts.SyntaxKind.PropertyAccessExpression:
1173      return ts.factory.createPropertyAccessExpression(
1174        processExtendBody(node.expression, componentName), node.name);
1175    case ts.SyntaxKind.Identifier:
1176      if (!componentName) {
1177        return ts.factory.createIdentifier(node.escapedText.toString().replace(INSTANCE, ''));
1178      } else {
1179        return ts.factory.createIdentifier(componentName);
1180      }
1181  }
1182  return undefined;
1183}
1184
1185export function collectExtend(collectionSet: Map<string, Set<string>>, component: string, attribute: string): void {
1186  if (collectionSet.has(component)) {
1187    collectionSet.get(component).add(attribute);
1188  } else {
1189    collectionSet.set(component, new Set([attribute]));
1190  }
1191}
1192
1193export function isExtendFunction(node: ts.FunctionDeclaration, extendResult: ExtendResult,
1194  checkArguments: boolean = false): string {
1195  const decorators: readonly ts.Decorator[] = ts.getAllDecorators(node);
1196  if (decorators && decorators.length) {
1197    for (let i = 0, len = decorators.length; i < len; i++) {
1198      if (ts.isCallExpression(decorators[i].expression)) {
1199        parseExtendNode(decorators[i].expression as ts.CallExpression, extendResult, checkArguments);
1200        if (CHECK_EXTEND_DECORATORS.includes(extendResult.decoratorName) && extendResult.componentName) {
1201          return extendResult.componentName;
1202        }
1203      }
1204    }
1205  }
1206  return null;
1207}
1208
1209function parseExtendNode(node: ts.CallExpression, extendResult: ExtendResult, checkArguments: boolean): void {
1210  if (ts.isIdentifier(node.expression)) {
1211    extendResult.decoratorName = node.expression.escapedText.toString();
1212    if (checkArguments && CHECK_EXTEND_DECORATORS.includes(extendResult.decoratorName) &&
1213      node.arguments && node.arguments.length !== 1) {
1214      transformLog.errors.push({
1215        type: LogType.ERROR,
1216        message: `'@${extendResult.decoratorName}' should have one and only one parameter.`,
1217        pos: node.getStart(),
1218        code: '10905108'
1219      });
1220    }
1221  }
1222  if (node.arguments.length && ts.isIdentifier(node.arguments[0])) {
1223    extendResult.componentName = node.arguments[0].escapedText.toString();
1224  }
1225}
1226
1227function createEntryNode(node: ts.SourceFile, context: ts.TransformationContext,
1228  entryNodeKey: ts.Expression, id: number): ts.SourceFile {
1229  let cardRelativePath: string;
1230  if (projectConfig && projectConfig.cardObj) {
1231    cardRelativePath = projectConfig.cardObj[resourceFileName];
1232  }
1233  if (componentCollection.previewComponent.length === 0 || !projectConfig.isPreview) {
1234    if (componentCollection.entryComponent) {
1235      if (!partialUpdateConfig.partialUpdateMode) {
1236        const entryNode: ts.ExpressionStatement =
1237          createEntryFunction(componentCollection.entryComponent, context,
1238            cardRelativePath, entryNodeKey, id) as ts.ExpressionStatement;
1239        return context.factory.updateSourceFile(node, [...node.statements, entryNode]);
1240      } else {
1241        const entryNodes: ts.ExpressionStatement[] =
1242          createEntryFunction(componentCollection.entryComponent, context,
1243            cardRelativePath, entryNodeKey, id) as ts.ExpressionStatement[];
1244        return entryNodes ?
1245          context.factory.updateSourceFile(node, [...node.statements, ...entryNodes]) :
1246          context.factory.updateSourceFile(node, [...node.statements]);
1247      }
1248    } else {
1249      return node;
1250    }
1251  } else {
1252    const statementsArray: ts.Statement =
1253      createPreviewComponentFunction(componentCollection.entryComponent, context, cardRelativePath, entryNodeKey, id);
1254    return context.factory.updateSourceFile(node, [...node.statements, statementsArray]);
1255  }
1256}
1257
1258function createEntryFunction(name: string, context: ts.TransformationContext, cardRelativePath: string,
1259  entryNodeKey: ts.Expression, id: number): ts.ExpressionStatement | (ts.Statement | ts.Block)[] {
1260  const newArray: ts.Expression[] = [
1261    context.factory.createStringLiteral(id.toString()),
1262    context.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED),
1263    context.factory.createObjectLiteralExpression([], false)
1264  ];
1265  const [localStorageName, entryOptionNode]: [string, ts.Expression] = addStorageParam(name);
1266  if (localStorageName && entryNodeKey) {
1267    newArray.push(entryNodeKey);
1268  }
1269  const newExpressionParams: any[] = [
1270    context.factory.createNewExpression(
1271      context.factory.createIdentifier(name), undefined, newArray)];
1272  addCardStringliteral(newExpressionParams, context, cardRelativePath);
1273  if (!partialUpdateConfig.partialUpdateMode) {
1274    const newExpressionStatement: ts.ExpressionStatement =
1275      context.factory.createExpressionStatement(context.factory.createCallExpression(
1276        context.factory.createIdentifier(cardRelativePath ? CARD_ENTRY_FUNCTION_NAME :
1277          PAGE_ENTRY_FUNCTION_NAME), undefined, newExpressionParams));
1278    return newExpressionStatement;
1279  } else {
1280    if (cardRelativePath) {
1281      if (entryOptionNode && ts.isObjectLiteralExpression(entryOptionNode)) {
1282        transformLog.errors.push({
1283          type: LogType.ERROR,
1284          message: `'@Entry' doesn't support {} parameter in card`,
1285          pos: componentCollection.entryComponentPos,
1286          code: '10906218'
1287        });
1288      }
1289      return [
1290        createStartGetAccessRecording(context),
1291        createLoadDocument(context, name, cardRelativePath, localStorageName, entryNodeKey),
1292        createStopGetAccessRecording(context)
1293      ];
1294    } else {
1295      return createLoadPageConditionalJudgMent(context, name, cardRelativePath, localStorageName, entryOptionNode);
1296    }
1297  }
1298}
1299
1300function createLoadPageConditionalJudgMent(context: ts.TransformationContext, name: string,
1301  cardRelativePath: string, localStorageName: string, entryOptionNode: ts.Expression,
1302  argsArr: ts.Expression[] = undefined, isComponentPreview: boolean = false): (ts.Statement | ts.Block)[] {
1303  let isObject: boolean = false;
1304  const entryOptionValue: EntryOptionValue = new EntryOptionValue();
1305  if (!entryOptionNode) {
1306    let originArray: ts.ExpressionStatement[];
1307    if (projectConfig.minAPIVersion > 10) {
1308      if (componentCollection.entryComponent === name && componentCollection.localSharedStorage) {
1309        return [judgeRouteNameAndStorageForIdentifier(context, name,
1310          cardRelativePath, isObject, componentCollection.localSharedStorage, undefined, undefined, argsArr)];
1311      }
1312      const newArray: ts.Expression[] = [
1313        context.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED),
1314        context.factory.createObjectLiteralExpression([], false)
1315      ];
1316      const newExpressionParams: any[] = [
1317        context.factory.createNewExpression(context.factory.createIdentifier(name), undefined, newArray)];
1318      originArray = [
1319        createRegisterNamedRoute(context, newExpressionParams, false, undefined, false)
1320      ];
1321    } else {
1322      originArray = [
1323        createStartGetAccessRecording(context),
1324        createLoadDocument(context, name, cardRelativePath, localStorageName, entryOptionNode),
1325        createStopGetAccessRecording(context)
1326      ];
1327    }
1328    return originArray;
1329  }
1330  if (ts.isObjectLiteralExpression(entryOptionNode)) {
1331    isObject = true;
1332    if (entryOptionNode.properties) {
1333      entryOptionNode.properties.forEach((property) => {
1334        if (ts.isPropertyAssignment(property) && property.name && ts.isIdentifier(property.name)) {
1335          entryOptionValue[property.name.escapedText.toString()] = property.initializer;
1336        }
1337      });
1338      if (entryOptionValue.useSharedStorage) {
1339        entryOptionValue.storage = createGetShared(entryOptionValue);
1340      }
1341    }
1342  } else {
1343    isObject = false;
1344  }
1345  return generateLoadDocumentEntrance(isObject, entryOptionValue.routeName, entryOptionValue.storage,
1346    isComponentPreview, context, name, cardRelativePath, entryOptionNode, argsArr);
1347}
1348
1349function generateLoadDocumentEntrance(isObject: boolean, routeNameNode: ts.Expression,
1350  storageNode: ts.Expression, isComponentPreview: boolean, context: ts.TransformationContext,
1351  name: string, cardRelativePath: string, entryOptionNode: ts.Expression,
1352  argsArr: ts.Expression[]): (ts.ExpressionStatement | ts.Block | ts.IfStatement)[] {
1353  if (isObject) {
1354    if (routeNameNode && !storageNode) {
1355      return isComponentPreview ? [
1356        ...assignRouteNameAndStorage(routeNameNode),
1357        ...createLoadDocumentWithRoute(context, name, cardRelativePath, isObject, entryOptionNode,
1358          routeNameNode, storageNode, true, false, false, argsArr)
1359      ] : [ts.factory.createBlock([
1360        ...assignRouteNameAndStorage(routeNameNode),
1361        ...createLoadDocumentWithRoute(context, name, cardRelativePath, isObject, entryOptionNode,
1362          routeNameNode, storageNode, true, false, false, argsArr)
1363      ])];
1364    } else if (!routeNameNode && !storageNode) {
1365      return isComponentPreview ? [
1366        ...assignRouteNameAndStorage(routeNameNode),
1367        ...createLoadDocumentWithRoute(context, name, cardRelativePath, isObject, entryOptionNode,
1368          routeNameNode, storageNode, false, false, true, argsArr)
1369      ] : [ts.factory.createBlock([
1370        ...assignRouteNameAndStorage(routeNameNode),
1371        ...createLoadDocumentWithRoute(context, name, cardRelativePath, isObject, entryOptionNode,
1372          routeNameNode, storageNode, false, false, true, argsArr)
1373      ])];
1374    } else if (!routeNameNode && storageNode) {
1375      return isComponentPreview ? [
1376        ...assignRouteNameAndStorage(routeNameNode),
1377        ...createLoadDocumentWithRoute(context, name, cardRelativePath, isObject, entryOptionNode,
1378          routeNameNode, storageNode, false, true, true, argsArr)
1379      ] : [ts.factory.createBlock([
1380        ...assignRouteNameAndStorage(routeNameNode),
1381        ...createLoadDocumentWithRoute(context, name, cardRelativePath, isObject, entryOptionNode,
1382          routeNameNode, storageNode, false, true, true, argsArr)
1383      ])];
1384    } else {
1385      return isComponentPreview ? [
1386        ...assignRouteNameAndStorage(routeNameNode),
1387        judgeRouteNameAndStorage(context, name, cardRelativePath, isObject, entryOptionNode, routeNameNode, storageNode, argsArr)
1388      ] : [ts.factory.createBlock([
1389        ...assignRouteNameAndStorage(routeNameNode),
1390        judgeRouteNameAndStorage(context, name, cardRelativePath, isObject, entryOptionNode, routeNameNode, storageNode, argsArr)
1391      ])];
1392    }
1393  } else {
1394    return [
1395      judgeRouteNameAndStorage(context, name, cardRelativePath, isObject, entryOptionNode, routeNameNode, storageNode, argsArr)];
1396  }
1397}
1398
1399function judgeRouteNameAndStorage(context: ts.TransformationContext, name: string,
1400  cardRelativePath: string, isObject: boolean, entryOptionNode: ts.Expression, routeNameNode: ts.Expression,
1401  storageNode: ts.Expression, argsArr: ts.Expression[] = undefined): ts.IfStatement {
1402  return isObject ? judgeRouteNameAndStorageForObj(context, name, cardRelativePath, isObject, entryOptionNode,
1403    routeNameNode, storageNode, argsArr) : judgeRouteNameAndStorageForIdentifier(context, name,
1404    cardRelativePath, isObject, entryOptionNode, routeNameNode, storageNode, argsArr);
1405}
1406
1407function judgeRouteNameAndStorageForObj(context: ts.TransformationContext, name: string,
1408  cardRelativePath: string, isObject: boolean, entryOptionNode: ts.Expression, routeNameNode: ts.Expression,
1409  storageNode: ts.Expression, argsArr: ts.Expression[] = undefined): ts.IfStatement {
1410  return ts.factory.createIfStatement(
1411    judgeRouteAndStorageForObject(true),
1412    ts.factory.createBlock(
1413      [
1414        ...createLoadDocumentWithRoute(context, name, cardRelativePath, isObject, entryOptionNode,
1415          routeNameNode, storageNode, true, true, false, argsArr)
1416      ],
1417      true
1418    ), ts.factory.createBlock(
1419      [
1420        ...createLoadDocumentWithRoute(context, name, cardRelativePath, isObject, entryOptionNode,
1421          routeNameNode, storageNode, false, false, true, argsArr)
1422      ],
1423      true
1424    ));
1425}
1426
1427function judgeRouteNameAndStorageForIdentifier(context: ts.TransformationContext, name: string,
1428  cardRelativePath: string, isObject: boolean, entryOptionNode: ts.Expression, routeNameNode: ts.Expression,
1429  storageNode: ts.Expression, argsArr: ts.Expression[] = undefined): ts.IfStatement {
1430  return ts.factory.createIfStatement(
1431    judgeRouteAndStorageForIdentifier(entryOptionNode as ts.Identifier, true, true),
1432    ts.factory.createBlock(
1433      [
1434        ...createLoadDocumentWithRoute(context, name, cardRelativePath, isObject, entryOptionNode,
1435          routeNameNode, storageNode, true, true, false, argsArr)
1436      ],
1437      true
1438    ),
1439    ts.factory.createIfStatement(
1440      judgeRouteAndStorageForIdentifier(entryOptionNode as ts.Identifier, true, false),
1441      ts.factory.createBlock(
1442        [
1443          ...createLoadDocumentWithRoute(context, name, cardRelativePath, isObject, entryOptionNode,
1444            routeNameNode, storageNode, true, false, false, argsArr)
1445        ],
1446        true
1447      ),
1448      ts.factory.createIfStatement(
1449        judgeRouteAndStorageForIdentifier(entryOptionNode as ts.Identifier, false, true),
1450        ts.factory.createBlock(
1451          [
1452            ...createLoadDocumentWithRoute(context, name, cardRelativePath, isObject, entryOptionNode,
1453              routeNameNode, storageNode, false, true, true, argsArr)
1454          ],
1455          true
1456        ),
1457        ts.factory.createIfStatement(
1458          judgeUseSharedStorageForExpresion(entryOptionNode),
1459          ts.factory.createBlock(
1460            [...createSharedStorageWithRoute(context, name, cardRelativePath, entryOptionNode, true, argsArr)], true),
1461          ts.factory.createBlock(
1462            [...createLoadDocumentWithRoute(context, name, cardRelativePath, false, entryOptionNode,
1463              null, null, false, false, true, argsArr)
1464            ], true)
1465        )
1466      )
1467    )
1468  );
1469}
1470
1471function judgeRouteAndStorageForObject(hasRouteName: boolean): ts.BinaryExpression {
1472  return ts.factory.createBinaryExpression(
1473    ts.factory.createIdentifier(ROUTENAME_NODE),
1474    ts.factory.createToken(hasRouteName ? ts.SyntaxKind.ExclamationEqualsToken : ts.SyntaxKind.EqualsEqualsToken),
1475    ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED)
1476  );
1477}
1478
1479function judgeRouteAndStorageForIdentifier(entryOptionNode: ts.Identifier, hasRouteName: boolean,
1480  hasStorage: boolean): ts.BinaryExpression {
1481  return ts.factory.createBinaryExpression(
1482    ts.factory.createBinaryExpression(
1483      entryOptionNode,
1484      ts.factory.createToken(ts.SyntaxKind.AmpersandAmpersandToken),
1485      ts.factory.createBinaryExpression(
1486        ts.factory.createPropertyAccessExpression(
1487          entryOptionNode,
1488          ts.factory.createIdentifier(ROUTE_NAME)
1489        ),
1490        ts.factory.createToken(hasRouteName ? ts.SyntaxKind.ExclamationEqualsToken : ts.SyntaxKind.EqualsEqualsToken),
1491        ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED)
1492      )
1493    ),
1494    ts.factory.createToken(ts.SyntaxKind.AmpersandAmpersandToken),
1495    ts.factory.createBinaryExpression(
1496      ts.factory.createPropertyAccessExpression(
1497        entryOptionNode,
1498        ts.factory.createIdentifier(STORAGE)
1499      ),
1500      ts.factory.createToken(hasStorage ? ts.SyntaxKind.ExclamationEqualsToken : ts.SyntaxKind.EqualsEqualsToken),
1501      ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED)
1502    )
1503  );
1504}
1505
1506function assignRouteNameAndStorage(routeNameNode): ts.ExpressionStatement[] {
1507  const assignOperation: ts.VariableStatement[] = [];
1508  if (routeNameNode) {
1509    assignOperation.push(ts.factory.createVariableStatement(
1510      undefined,
1511      ts.factory.createVariableDeclarationList(
1512        [ts.factory.createVariableDeclaration(
1513          ts.factory.createIdentifier(ROUTENAME_NODE),
1514          undefined,
1515          undefined,
1516          routeNameNode
1517        )],
1518        ts.NodeFlags.Let
1519      )
1520    ));
1521  }
1522  return assignOperation;
1523}
1524
1525function createLoadDocumentWithRoute(context: ts.TransformationContext, name: string,
1526  cardRelativePath: string, isObject: boolean, entryOptionNode: ts.Expression,
1527  routeNameNode: ts.Node, storageNode: ts.Node, hasRouteName: boolean, hasStorage: boolean,
1528  shouldCreateAccsessRecording: boolean, argsArr: ts.Expression[]): ts.ExpressionStatement[] {
1529  const newArray: ts.Expression[] = [
1530    context.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED),
1531    context.factory.createObjectLiteralExpression([], false)
1532  ];
1533  if (entryOptionNode) {
1534    if (!isObject) {
1535      if (routeNameNode === null && storageNode === null) {
1536        newArray.push(entryOptionNode);
1537      } else {
1538        newArray.push(createGetSharedForVariable(entryOptionNode));
1539      }
1540    } else if (storageNode) {
1541      newArray.push(storageNode as ts.Expression);
1542    }
1543  }
1544  return loadDocumentWithRoute(context, name, newArray, argsArr, hasRouteName, shouldCreateAccsessRecording,
1545    isObject, entryOptionNode, cardRelativePath);
1546}
1547
1548function loadDocumentWithRoute(context: ts.TransformationContext, name: string, newArray: ts.Expression[],
1549  argsArr: ts.Expression[], hasRouteName: boolean, shouldCreateAccsessRecording: boolean,
1550  isObject: boolean, entryOptionNode: ts.Expression, cardRelativePath: string): ts.ExpressionStatement[] {
1551  const newExpressionParams = [context.factory.createNewExpression(
1552    context.factory.createIdentifier(name), undefined, newArray)];
1553  if (argsArr) {
1554    argsArr = [];
1555    componentCollection.previewComponent.forEach((componentName: string) => {
1556      const newExpression: ts.Expression = context.factory.createNewExpression(
1557        context.factory.createIdentifier(componentName), undefined,
1558        componentName === name ? newArray : newArray.slice(0, newArray.length - 1)
1559      );
1560      argsArr.push(context.factory.createStringLiteral(componentName), newExpression);
1561    });
1562  }
1563  if (hasRouteName) {
1564    return [
1565      shouldCreateAccsessRecording ? createStartGetAccessRecording(context) : undefined,
1566      createRegisterNamedRoute(context, newExpressionParams, isObject, entryOptionNode, hasRouteName),
1567      shouldCreateAccsessRecording ? createStopGetAccessRecording(context) : undefined];
1568  } else {
1569    if (projectConfig.minAPIVersion > 10) {
1570      return [createRegisterNamedRoute(context, newExpressionParams, isObject, entryOptionNode, hasRouteName)];
1571    } else {
1572      return [shouldCreateAccsessRecording ? createStartGetAccessRecording(context) : undefined,
1573        context.factory.createExpressionStatement(context.factory.createCallExpression(
1574          context.factory.createIdentifier(cardRelativePath ? CARD_ENTRY_FUNCTION_NAME :
1575            PAGE_ENTRY_FUNCTION_NAME), undefined, newExpressionParams)),
1576        shouldCreateAccsessRecording ? createStopGetAccessRecording(context) : undefined];
1577    }
1578  }
1579}
1580
1581function createRegisterNamedRoute(context: ts.TransformationContext, newExpressionParams: ts.NewExpression[],
1582  isObject: boolean, entryOptionNode: ts.Expression, hasRouteName: boolean): ts.ExpressionStatement {
1583  return context.factory.createExpressionStatement(context.factory.createCallExpression(
1584    context.factory.createIdentifier(REGISTER_NAMED_ROUTE),
1585    undefined,
1586    [
1587      context.factory.createArrowFunction(
1588        undefined,
1589        undefined,
1590        [],
1591        undefined,
1592        context.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
1593        newExpressionParams[0]
1594      ),
1595      hasRouteName ? isObject ? ts.factory.createIdentifier(ROUTENAME_NODE) : context.factory.createPropertyAccessExpression(
1596        entryOptionNode,
1597        context.factory.createIdentifier(ROUTE_NAME)
1598      ) : ts.factory.createStringLiteral(''),
1599      context.factory.createObjectLiteralExpression(
1600        [
1601          routerBundleOrModule(context, RESOURCE_NAME_BUNDLE),
1602          routerBundleOrModule(context, RESOURCE_NAME_MODULE),
1603          routerOrNavPathWrite(context, PAGE_PATH, projectConfig.projectPath, projectConfig.projectRootPath),
1604          routerOrNavPathWrite(context, PAGE_FULL_PATH, projectConfig.projectRootPath),
1605          context.factory.createPropertyAssignment(
1606            context.factory.createIdentifier(INTEGRATED_HSP),
1607            context.factory.createStringLiteral(integratedHspType())
1608          ),
1609          routerModuleType(context)
1610        ],
1611        false
1612      )
1613    ]
1614  ));
1615}
1616
1617export function createStartGetAccessRecording(context: ts.TransformationContext): ts.ExpressionStatement {
1618  return context.factory.createExpressionStatement(
1619    context.factory.createCallExpression(
1620      context.factory.createPropertyAccessExpression(
1621        context.factory.createIdentifier(VIEWSTACKPROCESSOR),
1622        context.factory.createIdentifier(STARTGETACCESSRECORDINGFOR)
1623      ),
1624      undefined,
1625      [context.factory.createCallExpression(
1626        context.factory.createPropertyAccessExpression(
1627          context.factory.createIdentifier(VIEWSTACKPROCESSOR),
1628          context.factory.createIdentifier(ALLOCATENEWELMETIDFORNEXTCOMPONENT)
1629        ),
1630        undefined,
1631        []
1632      )]
1633    )
1634  );
1635}
1636
1637function createLoadDocument(context: ts.TransformationContext, name: string,
1638  cardRelativePath: string, localStorageName: string, entryNodeKey: ts.Expression): ts.ExpressionStatement {
1639  const newArray: ts.Expression[] = [
1640    context.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED),
1641    context.factory.createObjectLiteralExpression([], false)
1642  ];
1643  if (localStorageName && entryNodeKey) {
1644    newArray.push(entryNodeKey);
1645  }
1646  const newExpressionParams: any[] = [
1647    context.factory.createNewExpression(
1648      context.factory.createIdentifier(name),
1649      undefined, newArray)];
1650  addCardStringliteral(newExpressionParams, context, cardRelativePath);
1651  return context.factory.createExpressionStatement(
1652    context.factory.createCallExpression(
1653      context.factory.createIdentifier(cardRelativePath ? CARD_ENTRY_FUNCTION_NAME :
1654        PAGE_ENTRY_FUNCTION_NAME), undefined, newExpressionParams)
1655  );
1656}
1657
1658function createStopGetAccessRecording(context: ts.TransformationContext): ts.ExpressionStatement {
1659  return context.factory.createExpressionStatement(
1660    context.factory.createCallExpression(
1661      context.factory.createPropertyAccessExpression(
1662        context.factory.createIdentifier(VIEWSTACKPROCESSOR),
1663        context.factory.createIdentifier(STOPGETACCESSRECORDING)
1664      ),
1665      undefined,
1666      []
1667    )
1668  );
1669}
1670
1671function addStorageParam(name: string): [string, ts.Expression] {
1672  let localStorageName: string;
1673  let localStorageNode: ts.Identifier | ts.ObjectLiteralExpression;
1674  const localStorageNum: number = (localStorageLinkCollection.get(name) || new Set()).size +
1675    (localStoragePropCollection.get(name) || new Set()).size;
1676  if (componentCollection.entryComponent === name) {
1677    if (componentCollection.localStorageNode) {
1678      localStorageNode = componentCollection.localStorageNode;
1679    }
1680    if (componentCollection.localStorageName) {
1681      localStorageName = componentCollection.localStorageName;
1682    }
1683    if (!hasStorage() && localStorageNum) {
1684      transformLog.errors.push({
1685        type: LogType.WARN,
1686        message: `'@Entry' should have a parameter, like '@Entry (storage)'.`,
1687        pos: componentCollection.entryComponentPos
1688      });
1689    }
1690  }
1691  return [localStorageName, localStorageNode];
1692}
1693
1694function hasStorage(): boolean {
1695  if (componentCollection.localStorageName || componentCollection.localStorageNode ||
1696    componentCollection.localSharedStorage) {
1697    return true;
1698  }
1699  return false;
1700}
1701
1702function createPreviewComponentFunction(name: string, context: ts.TransformationContext,
1703  cardRelativePath: string, entryNodeKey: ts.Expression, id: number): ts.Statement {
1704  const newArray: ts.Expression[] = partialUpdateConfig.partialUpdateMode ?
1705    [
1706      context.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED),
1707      context.factory.createObjectLiteralExpression([], false)
1708    ] :
1709    [
1710      context.factory.createStringLiteral(id.toString()),
1711      context.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED),
1712      context.factory.createObjectLiteralExpression([], false)
1713    ];
1714  const [localStorageName, entryOptionNode]: [string, ts.Expression] = addStorageParam(name);
1715  if (entryOptionNode) {
1716    newArray.push(entryOptionNode);
1717  }
1718  const argsArr: ts.Expression[] = [];
1719  componentCollection.previewComponent.forEach(componentName => {
1720    const newExpression: ts.Expression = context.factory.createNewExpression(
1721      context.factory.createIdentifier(componentName),
1722      undefined,
1723      newArray
1724    );
1725    argsArr.push(context.factory.createStringLiteral(componentName));
1726    argsArr.push(newExpression);
1727  });
1728  const newExpressionParams: any[] = name ? [context.factory.createNewExpression(
1729    context.factory.createIdentifier(name), undefined, newArray)] : [];
1730  addCardStringliteral(newExpressionParams, context, cardRelativePath);
1731  const ifStatement: ts.Statement = context.factory.createIfStatement(
1732    context.factory.createCallExpression(
1733      context.factory.createIdentifier(GET_PREVIEW_FLAG_FUNCTION_NAME),
1734      undefined,
1735      []
1736    ),
1737    context.factory.createBlock(
1738      [...storePreviewComponents(name, entryOptionNode, argsArr),
1739        context.factory.createExpressionStatement(context.factory.createCallExpression(
1740          context.factory.createIdentifier(PREVIEW_COMPONENT_FUNCTION_NAME),
1741          undefined,
1742          []
1743        ))],
1744      true
1745    ),
1746    context.factory.createBlock(
1747      createPreviewElseBlock(name, context, cardRelativePath, localStorageName, entryOptionNode,
1748        newExpressionParams, argsArr),
1749      true
1750    )
1751  );
1752  return ifStatement;
1753}
1754
1755function storePreviewComponents(name: string, entryOptionNode: ts.Expression, argsArr: ts.Expression[]):
1756  (ts.ExpressionStatement | ts.VariableStatement | ts.IfStatement)[] {
1757  let isObject: boolean = false;
1758  let storageNode: ts.Expression;
1759  if (!entryOptionNode) {
1760    return [ts.factory.createExpressionStatement(ts.factory.createCallExpression(
1761      ts.factory.createIdentifier(STORE_PREVIEW_COMPONENTS),
1762      undefined,
1763      [
1764        ts.factory.createNumericLiteral(componentCollection.previewComponent.length),
1765        ...argsArr
1766      ]
1767    ))];
1768  }
1769  if (ts.isObjectLiteralExpression(entryOptionNode)) {
1770    isObject = true;
1771    if (entryOptionNode.properties) {
1772      entryOptionNode.properties.forEach((property) => {
1773        if (ts.isPropertyAssignment(property) && property.name && ts.isIdentifier(property.name) &&
1774          property.name.escapedText.toString() === STORAGE) {
1775          storageNode = property.initializer;
1776        }
1777      });
1778    }
1779  } else {
1780    isObject = false;
1781  }
1782  const newArray: ts.Expression[] = [
1783    ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED),
1784    ts.factory.createObjectLiteralExpression([], false)
1785  ];
1786  const newArgsArr: ts.Expression[] = [];
1787  if (isObject) {
1788    return processObjectStorage(storageNode, newArray, name, newArgsArr);
1789  } else {
1790    return [ts.factory.createIfStatement(
1791      ts.factory.createBinaryExpression(
1792        entryOptionNode,
1793        ts.factory.createToken(ts.SyntaxKind.AmpersandAmpersandToken),
1794        ts.factory.createBinaryExpression(
1795          ts.factory.createPropertyAccessExpression(
1796            entryOptionNode,
1797            ts.factory.createIdentifier(STORAGE)
1798          ),
1799          ts.factory.createToken(ts.SyntaxKind.ExclamationEqualsToken),
1800          ts.factory.createIdentifier('undefined')
1801        )
1802      ),
1803      ts.factory.createBlock(
1804        [returnStorePreview(entryOptionNode, true, name)],
1805        true
1806      ),
1807      ts.factory.createBlock(
1808        [returnStorePreview(entryOptionNode, false, name)],
1809        true
1810      )
1811    )];
1812  }
1813}
1814
1815function processObjectStorage(storageNode: ts.Expression, newArray: ts.Expression[], name: string,
1816  newArgsArr: ts.Expression[]): (ts.ExpressionStatement | ts.VariableStatement)[] {
1817  if (storageNode) {
1818    newArray.push(ts.factory.createIdentifier(STORAGE_NODE));
1819    componentCollection.previewComponent.forEach(componentName => {
1820      const newExpression: ts.Expression = ts.factory.createNewExpression(
1821        ts.factory.createIdentifier(componentName),
1822        undefined,
1823        componentName === name ? newArray : newArray.slice(0, newArray.length - 1)
1824      );
1825      newArgsArr.push(ts.factory.createStringLiteral(componentName));
1826      newArgsArr.push(newExpression);
1827    });
1828    return [ts.factory.createVariableStatement(
1829      undefined,
1830      ts.factory.createVariableDeclarationList(
1831        [ts.factory.createVariableDeclaration(
1832          ts.factory.createIdentifier(STORAGE_NODE),
1833          undefined,
1834          undefined,
1835          storageNode
1836        )],
1837        ts.NodeFlags.Let
1838      )
1839    ), ts.factory.createExpressionStatement(ts.factory.createCallExpression(
1840      ts.factory.createIdentifier(STORE_PREVIEW_COMPONENTS),
1841      undefined,
1842      [
1843        ts.factory.createNumericLiteral(componentCollection.previewComponent.length),
1844        ...newArgsArr
1845      ]
1846    ))];
1847  } else {
1848    componentCollection.previewComponent.forEach(componentName => {
1849      const newExpression: ts.Expression = ts.factory.createNewExpression(
1850        ts.factory.createIdentifier(componentName),
1851        undefined,
1852        newArray
1853      );
1854      newArgsArr.push(ts.factory.createStringLiteral(componentName));
1855      newArgsArr.push(newExpression);
1856    });
1857    return [ts.factory.createExpressionStatement(ts.factory.createCallExpression(
1858      ts.factory.createIdentifier(STORE_PREVIEW_COMPONENTS),
1859      undefined,
1860      [
1861        ts.factory.createNumericLiteral(componentCollection.previewComponent.length),
1862        ...newArgsArr
1863      ]
1864    ))];
1865  }
1866}
1867
1868function returnStorePreview(entryOptionNode: ts.Expression, hasStorage: boolean, name: string): ts.ExpressionStatement {
1869  const newArray: ts.Expression[] = [
1870    ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED),
1871    ts.factory.createObjectLiteralExpression([], false)
1872  ];
1873  const newArgsArr: ts.Expression[] = [];
1874  newArray.push(hasStorage ? ts.factory.createPropertyAccessExpression(
1875    entryOptionNode,
1876    ts.factory.createIdentifier(STORAGE)
1877  ) : entryOptionNode);
1878  componentCollection.previewComponent.forEach(componentName => {
1879    const newExpression: ts.Expression = ts.factory.createNewExpression(
1880      ts.factory.createIdentifier(componentName),
1881      undefined,
1882      componentName === name ? newArray : newArray.slice(0, newArray.length - 1)
1883    );
1884    newArgsArr.push(ts.factory.createStringLiteral(componentName));
1885    newArgsArr.push(newExpression);
1886  });
1887  return ts.factory.createExpressionStatement(ts.factory.createCallExpression(
1888    ts.factory.createIdentifier(STORE_PREVIEW_COMPONENTS),
1889    undefined,
1890    [
1891      ts.factory.createNumericLiteral(componentCollection.previewComponent.length),
1892      ...newArgsArr
1893    ]
1894  ));
1895}
1896
1897function createPreviewElseBlock(name: string, context: ts.TransformationContext, cardRelativePath: string,
1898  localStorageName: string, entryOptionNode: ts.Expression, newExpressionParams: ts.Expression[],
1899  argsArr: ts.Expression[]): (ts.ExpressionStatement | ts.IfStatement | ts.Block | ts.Statement)[] {
1900  if (name) {
1901    if (!partialUpdateConfig.partialUpdateMode) {
1902      return [context.factory.createExpressionStatement(context.factory.createCallExpression(
1903        context.factory.createIdentifier(STORE_PREVIEW_COMPONENTS),
1904        undefined,
1905        [
1906          context.factory.createNumericLiteral(componentCollection.previewComponent.length),
1907          ...argsArr
1908        ]
1909      )),
1910      context.factory.createExpressionStatement(context.factory.createCallExpression(
1911        context.factory.createIdentifier(cardRelativePath ? CARD_ENTRY_FUNCTION_NAME :
1912          PAGE_ENTRY_FUNCTION_NAME), undefined, newExpressionParams
1913      ))];
1914    } else {
1915      if (cardRelativePath) {
1916        if (entryOptionNode && ts.isObjectLiteralExpression(entryOptionNode)) {
1917          transformLog.errors.push({
1918            type: LogType.ERROR,
1919            message: `'@Entry' doesn't support {} parameter in card`,
1920            pos: componentCollection.entryComponentPos,
1921            code: '10906217'
1922          });
1923        }
1924        return [
1925          name ? createStartGetAccessRecording(context) : undefined,
1926          name ? context.factory.createExpressionStatement(context.factory.createCallExpression(
1927            context.factory.createIdentifier(cardRelativePath ? CARD_ENTRY_FUNCTION_NAME :
1928              PAGE_ENTRY_FUNCTION_NAME), undefined, newExpressionParams
1929          )) : undefined,
1930          name ? createStopGetAccessRecording(context) : undefined
1931        ];
1932      }
1933      return createLoadPageConditionalJudgMent(context, name, cardRelativePath, localStorageName,
1934        entryOptionNode, argsArr, true);
1935    }
1936  }
1937  return undefined;
1938}
1939
1940export function resetLog(): void {
1941  transformLog.errors = [];
1942}
1943
1944function addCardStringliteral(newExpressionParams: any[], context: ts.TransformationContext,
1945  cardRelativePath: string): void {
1946  const bundleName = projectConfig.allowEmptyBundleName ? '' : projectConfig.bundleName;
1947  if (cardRelativePath) {
1948    newExpressionParams.push(context.factory.createStringLiteral(
1949      bundleName + '/' + projectConfig.moduleName + '/' + cardRelativePath));
1950  }
1951}
1952
1953export function validatorCard(log: LogInfo[], type: number, pos: number,
1954  name: string = ''): void {
1955  if (projectConfig && projectConfig.cardObj && resourceFileName &&
1956    projectConfig.cardObj[resourceFileName]) {
1957    const logInfo: LogInfo = {
1958      type: LogType.ERROR,
1959      message: '',
1960      pos: pos
1961    };
1962    switch (type) {
1963      case CARD_LOG_TYPE_COMPONENTS:
1964        logInfo.message = `Card page cannot use the component ${name}.`;
1965        logInfo.code = '10905216';
1966        break;
1967      case CARD_LOG_TYPE_DECORATORS:
1968        logInfo.message = `Card page cannot use ${name}`;
1969        logInfo.code = '10905215';
1970        break;
1971      case CARD_LOG_TYPE_IMPORT:
1972        logInfo.message = `Card page cannot use import.`;
1973        logInfo.code = '10905214';
1974        break;
1975    }
1976    log.push(logInfo);
1977  }
1978}
1979
1980export function resetProcessUiSyntax(): void {
1981  transformLog = new createAstNodeUtils.FileLog();
1982  contextGlobal = undefined;
1983}
1984
1985function createSharedStorageWithRoute(context: ts.TransformationContext, name: string, cardRelativePath: string,
1986  entryOptionNode: ts.Expression, shouldCreateAccsessRecording: boolean, argsArr: ts.Expression[]): ts.Statement[] {
1987  const newArray: ts.Expression[] = [
1988    ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED),
1989    ts.factory.createObjectLiteralExpression([], false),
1990    createGetSharedForVariable(entryOptionNode, false)
1991  ];
1992  return loadDocumentWithRoute(context, name, newArray, argsArr, false, shouldCreateAccsessRecording,
1993    false, entryOptionNode, cardRelativePath);
1994}
1995
1996function insertImportModuleNode(statements: ts.Statement[], hasUseResource: boolean): ts.Statement[] {
1997  if (isDynamic() && (hasUseResource || componentCollection.entryComponent)) {
1998    statements.unshift(createAstNodeUtils.createImportNodeForModuleInfo());
1999  }
2000  return statements;
2001}
2002
2003// Do you want to start dynamic bundleName or moduleName.
2004export function isDynamic(): boolean {
2005  const isByteCodeHar: boolean = projectConfig.compileHar && projectConfig.byteCodeHar;
2006  const uiTransformOptimization: boolean = !!projectConfig.uiTransformOptimization;
2007  return uiTransformOptimization ? uiTransformOptimization : isByteCodeHar;
2008}
2009