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