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