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