• 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';
17
18import {
19  COMPONENT_NON_DECORATOR,
20  COMPONENT_STATE_DECORATOR,
21  COMPONENT_PROP_DECORATOR,
22  COMPONENT_LINK_DECORATOR,
23  COMPONENT_STORAGE_LINK_DECORATOR,
24  COMPONENT_PROVIDE_DECORATOR,
25  COMPONENT_OBJECT_LINK_DECORATOR,
26  COMPONENT_CREATE_FUNCTION,
27  COMPONENT_POP_FUNCTION,
28  BASE_COMPONENT_NAME,
29  CUSTOM_COMPONENT_EARLIER_CREATE_CHILD,
30  COMPONENT_CONSTRUCTOR_UPDATE_PARAMS,
31  CUSTOM_COMPONENT_FUNCTION_FIND_CHILD_BY_ID,
32  COMPONENT_CONSTRUCTOR_UNDEFINED,
33  CUSTOM_COMPONENT_NEEDS_UPDATE_FUNCTION,
34  CUSTOM_COMPONENT_MARK_STATIC_FUNCTION,
35  COMPONENT_COMMON,
36  GENERATE_ID,
37  ELMTID,
38  STARTGETACCESSRECORDINGFOR,
39  STOPGETACCESSRECORDING,
40  BASE_COMPONENT_NAME_PU,
41  OBSERVECOMPONENTCREATION,
42  OBSERVECOMPONENTCREATION2,
43  ISINITIALRENDER,
44  UPDATE_STATE_VARS_OF_CHIND_BY_ELMTID,
45  $$,
46  COMPONENT_RECYCLE,
47  COMPONENT_CREATE_RECYCLE,
48  RECYCLE_NODE,
49  ABOUT_TO_REUSE,
50  COMPONENT_RERENDER_FUNCTION,
51  OBSERVE_RECYCLE_COMPONENT_CREATION,
52  FUNCTION,
53  COMPONENT_IF_UNDEFINED,
54  COMPONENT_PARAMS_LAMBDA_FUNCTION,
55  COMPONENT_PARAMS_FUNCTION,
56  COMPONENT_ABOUTTOREUSEINTERNAL_FUNCTION,
57  NAME,
58  COMPONENT_CALL,
59  COMPONENT_CONSUME_DECORATOR,
60  COMPONENT_STORAGE_PROP_DECORATOR,
61  COMPONENT_LOCAL_STORAGE_PROP_DECORATOR,
62  COMPONENT_LOCAL_STORAGE_LINK_DECORATOR,
63  COMPONENTV2_LOCAL_DECORATOR,
64  COMPONENTV2_CONSUMER_DECORATOR,
65  COMPONENTV2_PROVIDER_DECORATOR
66} from './pre_define';
67import {
68  stateCollection,
69  linkCollection,
70  propCollection,
71  regularCollection,
72  storagePropCollection,
73  storageLinkCollection,
74  provideCollection,
75  consumeCollection,
76  objectLinkCollection,
77  isStaticViewCollection,
78  builderParamObjectCollection,
79  getLocalStorageCollection,
80  builderParamInitialization,
81  propInitialization,
82  regularInitialization,
83  stateInitialization,
84  provideInitialization,
85  privateCollection,
86  regularStaticCollection,
87  componentCollection,
88  localStorageLinkCollection,
89  localStoragePropCollection
90} from './validate_ui_syntax';
91import {
92  PropMapManager,
93  createViewCreate,
94  createCustomComponentNewExpression,
95  isLocalStorageParameter,
96  isBasicType,
97  isObservedV2
98} from './process_component_member';
99import {
100  LogType,
101  LogInfo,
102  componentInfo,
103  storedFileInfo,
104  CurrentProcessFile
105} from './utils';
106import {
107  bindComponentAttr,
108  parentConditionalExpression,
109  createComponentCreationStatement,
110  createFunction,
111  ComponentAttrInfo,
112  ifRetakeId,
113  transferBuilderCall,
114  createCollectElmtIdNode,
115  createViewStackProcessorStatement,
116  BuilderParamsResult
117} from './process_component_build';
118import {
119  partialUpdateConfig,
120  projectConfig,
121  globalProgram
122} from '../main';
123import {
124  GLOBAL_CUSTOM_BUILDER_METHOD
125} from './component_map';
126import {
127  createReference,
128  isProperty
129} from './process_component_class';
130import processStructComponentV2, { StructInfo, ParamDecoratorInfo } from './process_struct_componentV2';
131import constantDefine from './constant_define';
132import createAstNodeUtils from './create_ast_node_utils';
133import logMessageCollection from './log_message_collection';
134
135let decoractorMap: Map<string, Map<string, Set<string>>>;
136
137export function processCustomComponent(node: ts.ExpressionStatement, newStatements: ts.Statement[],
138  log: LogInfo[], name: string, isBuilder: boolean = false, isGlobalBuilder: boolean = false,
139  idName: ts.Expression = undefined, builderParamsResult: BuilderParamsResult = null,
140  isInRepeatTemplate: boolean = false): void {
141  decoractorMap = new Map(
142    [[COMPONENT_STATE_DECORATOR, stateCollection],
143      [COMPONENT_LINK_DECORATOR, linkCollection],
144      [COMPONENT_PROP_DECORATOR, propCollection],
145      [COMPONENT_NON_DECORATOR, regularCollection],
146      [COMPONENT_PROVIDE_DECORATOR, provideCollection],
147      [COMPONENT_OBJECT_LINK_DECORATOR, objectLinkCollection]]);
148  const componentNode: ts.CallExpression = getCustomComponentNode(node);
149  if (componentNode) {
150    const parentComponentType: ParentType = componentCollection.currentClassName ?
151    getParentComponentType(componentCollection.currentClassName) : getParentComponentType('');
152    const isRecycleComponent: boolean = isRecycle(name);
153    const isReuseComponentInV2: boolean = isReuseInV2(name);
154    logMessageCollection.checkNestedComponents(parentComponentType, isRecycleComponent, isReuseComponentInV2, node, log);
155    logMessageCollection.checkIfReuseV2InRepeatTemplate(isInRepeatTemplate, isReuseComponentInV2, node, log);
156    const hasChainCall: boolean = componentNode.parent &&
157      ts.isPropertyAccessExpression(componentNode.parent);
158    let ischangeNode: boolean = false;
159    let customComponentNewExpression: ts.NewExpression = createCustomComponentNewExpression(
160      componentNode, name, isBuilder, isGlobalBuilder);
161    let argumentsArray: ts.PropertyAssignment[];
162    const componentAttrInfo: ComponentAttrInfo = { reuseId: null, hasIdAttr: false, attrCount: 0, reuse: '' };
163    if (isHasChild(componentNode)) {
164      // @ts-ignore
165      argumentsArray = componentNode.arguments[0].properties.slice();
166      argumentsArray.forEach((item: ts.PropertyAssignment, index: number) => {
167        if (isToChange(item, name)) {
168          ischangeNode = true;
169          const propertyAssignmentNode: ts.PropertyAssignment = ts.factory.updatePropertyAssignment(
170            item, item.name, changeNodeFromCallToArrow(item.initializer as ts.CallExpression));
171          argumentsArray.splice(index, 1, propertyAssignmentNode);
172        }
173      });
174      if (ischangeNode) {
175        const newNode: ts.ExpressionStatement = ts.factory.updateExpressionStatement(node,
176          ts.factory.createNewExpression(componentNode.expression, componentNode.typeArguments,
177            [ts.factory.createObjectLiteralExpression(argumentsArray, true)]));
178        customComponentNewExpression = createCustomComponentNewExpression(
179          newNode.expression as ts.CallExpression, name, isBuilder);
180      }
181    }
182    let judgeIdStart: number;
183    if (partialUpdateConfig.partialUpdateMode && idName) {
184      judgeIdStart = newStatements.length;
185    }
186    let needCommon: boolean = false;
187    if (hasChainCall) {
188      if (partialUpdateConfig.partialUpdateMode) {
189        const commomComponentNode: ts.Statement[] = [ts.factory.createExpressionStatement(
190          createFunction(ts.factory.createIdentifier(COMPONENT_COMMON),
191            ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION), null))];
192        const immutableStatements: ts.Statement[] = [];
193        bindComponentAttr(node, ts.factory.createIdentifier(COMPONENT_COMMON), commomComponentNode,
194          log, true, false, immutableStatements, false, componentAttrInfo, isReuseComponentInV2);
195        needCommon = commomComponentNode.length > 1 || immutableStatements.length > 0;
196        if (componentAttrInfo.hasIdAttr && componentAttrInfo.attrCount === 1) {
197          commomComponentNode[0] = createCommonIdAttrNode();
198        }
199        if (needCommon) {
200          newStatements.push(createComponentCreationStatement(componentAttributes(COMPONENT_COMMON),
201            commomComponentNode, COMPONENT_COMMON, isGlobalBuilder, false, undefined, immutableStatements,
202            builderParamsResult, isRecycleComponent));
203        }
204      } else {
205        newStatements.push(ts.factory.createExpressionStatement(
206          createFunction(ts.factory.createIdentifier(COMPONENT_COMMON),
207            ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION), null)));
208        bindComponentAttr(node, ts.factory.createIdentifier(COMPONENT_COMMON), newStatements, log);
209      }
210    }
211    if (isRecycleComponent && partialUpdateConfig.partialUpdateMode) {
212      newStatements.push(createRecycleComponent(isGlobalBuilder));
213    }
214    addCustomComponent(node, newStatements, customComponentNewExpression, log, name, componentNode,
215      isBuilder, isGlobalBuilder, isRecycleComponent, componentAttrInfo, builderParamsResult, isReuseComponentInV2);
216    if (hasChainCall && (!partialUpdateConfig.partialUpdateMode || needCommon)) {
217      newStatements.push(ts.factory.createExpressionStatement(
218        createFunction(ts.factory.createIdentifier(COMPONENT_COMMON),
219          ts.factory.createIdentifier(COMPONENT_POP_FUNCTION), null)));
220    }
221    if (isRecycleComponent && partialUpdateConfig.partialUpdateMode) {
222      newStatements.push(componentAttributes(COMPONENT_RECYCLE));
223    }
224    if (partialUpdateConfig.partialUpdateMode && idName) {
225      newStatements.splice(judgeIdStart, newStatements.length - judgeIdStart,
226        ifRetakeId(newStatements.slice(judgeIdStart), idName));
227    }
228  }
229}
230
231function createCommonIdAttrNode(): ts.ExpressionStatement {
232  return ts.factory.createExpressionStatement(
233    createFunction(ts.factory.createIdentifier(COMPONENT_COMMON),
234      ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION),
235      // @ts-ignore
236      [ts.factory.createTrue()]));
237}
238
239export function isRecycle(componentName: string): boolean {
240  return storedFileInfo.getCurrentArkTsFile().recycleComponents.has(componentName);
241}
242
243export function isReuseInV2(componentName: string): boolean {
244  return storedFileInfo.getCurrentArkTsFile().reuseComponentsV2.has(componentName);
245}
246
247function createRecycleComponent(isGlobalBuilder: boolean): ts.Statement {
248  return createComponentCreationStatement(componentAttributes(COMPONENT_RECYCLE),
249    [ts.factory.createExpressionStatement(
250      createFunction(ts.factory.createIdentifier(COMPONENT_RECYCLE),
251        ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION), null))
252    ], COMPONENT_RECYCLE, isGlobalBuilder);
253}
254
255function componentAttributes(componentName: string): ts.Statement {
256  return ts.factory.createExpressionStatement(
257    ts.factory.createCallExpression(
258      ts.factory.createPropertyAccessExpression(
259        ts.factory.createIdentifier(componentName),
260        ts.factory.createIdentifier(COMPONENT_POP_FUNCTION)
261      ), undefined, []
262    ));
263}
264
265function isHasChild(node: ts.CallExpression): boolean {
266  return node.arguments && node.arguments[0] && ts.isObjectLiteralExpression(node.arguments[0]) &&
267    node.arguments[0].properties && node.arguments[0].properties.length > 0;
268}
269
270function isToChange(item: ts.PropertyAssignment, name: string): boolean {
271  const builderParamName: Set<string> = builderParamObjectCollection.get(name);
272  if (item.initializer && ts.isCallExpression(item.initializer) && builderParamName &&
273    builderParamName.has(item.name.getText()) &&
274    !/\.(bind|call|apply)/.test(item.initializer.getText())) {
275    return true;
276  }
277  return false;
278}
279
280function changeNodeFromCallToArrow(node: ts.CallExpression): ts.ConditionalExpression {
281  let builderBindThis: ts.ExpressionStatement = ts.factory.createExpressionStatement(node);
282  if (ts.isCallExpression(node) && node.expression && ts.isIdentifier(node.expression) &&
283    GLOBAL_CUSTOM_BUILDER_METHOD.has(node.expression.escapedText.toString())) {
284    builderBindThis = transferBuilderCall(ts.factory.createExpressionStatement(node), node.expression.escapedText.toString());
285  }
286  return changeNodeFromCallToArrowDetermine(node, builderBindThis);
287}
288
289function changeNodeFromCallToArrowDetermine(node: ts.CallExpression, builderBindThis: ts.ExpressionStatement): ts.ConditionalExpression {
290  if (ts.isCallExpression(node)) {
291    return ts.factory.createConditionalExpression(
292      ts.factory.createBinaryExpression(
293        ts.factory.createTypeOfExpression(node),
294        ts.factory.createToken(ts.SyntaxKind.EqualsEqualsEqualsToken),
295        ts.factory.createStringLiteral(FUNCTION)
296      ),
297      ts.factory.createToken(ts.SyntaxKind.QuestionToken),
298      node,
299      ts.factory.createToken(ts.SyntaxKind.ColonToken),
300      ts.factory.createArrowFunction(
301        undefined,
302        undefined,
303        [],
304        undefined,
305        ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
306        ts.factory.createBlock(
307          [builderBindThis],
308          true
309        )
310      )
311    );
312  }
313  return undefined;
314}
315
316function addCustomComponent(node: ts.ExpressionStatement, newStatements: ts.Statement[],
317  newNode: ts.NewExpression, log: LogInfo[], name: string, componentNode: ts.CallExpression,
318  isBuilder: boolean, isGlobalBuilder: boolean, isRecycleComponent: boolean,
319  componentAttrInfo: ComponentAttrInfo, builderParamsResult: BuilderParamsResult,
320  isReuseComponentInV2: boolean): void {
321  if (ts.isNewExpression(newNode)) {
322    const propertyArray: ts.ObjectLiteralElementLike[] = [];
323    validateCustomComponentPrams(componentNode, name, propertyArray, log, isBuilder);
324    addCustomComponentStatements(node, newStatements, newNode, name, propertyArray, componentNode,
325      isBuilder, isGlobalBuilder, isRecycleComponent, componentAttrInfo, builderParamsResult, log, isReuseComponentInV2);
326  }
327}
328
329function addCustomComponentStatements(node: ts.ExpressionStatement, newStatements: ts.Statement[],
330  newNode: ts.NewExpression, name: string, props: ts.ObjectLiteralElementLike[],
331  componentNode: ts.CallExpression, isBuilder: boolean, isGlobalBuilder: boolean,
332  isRecycleComponent: boolean, componentAttrInfo: ComponentAttrInfo,
333  builderParamsResult: BuilderParamsResult, log: LogInfo[], isReuseComponentInV2: boolean): void {
334  if (!partialUpdateConfig.partialUpdateMode) {
335    const id: string = componentInfo.id.toString();
336    newStatements.push(createFindChildById(id, name, isBuilder), createCustomComponentIfStatement(id,
337      ts.factory.updateExpressionStatement(node, createViewCreate(newNode)),
338      ts.factory.createObjectLiteralExpression(props, true), name));
339  } else {
340    newStatements.push(createCustomComponent(newNode, name, componentNode, isGlobalBuilder, isBuilder,
341      isRecycleComponent, componentAttrInfo, builderParamsResult, log, isReuseComponentInV2));
342  }
343}
344
345function createChildElmtId(node: ts.CallExpression, name: string, log: LogInfo[]): ts.PropertyAssignment[] {
346  const childParam: ts.PropertyAssignment[] = [];
347  const propsAndObjectLinks: string[] = [];
348  if (propCollection.get(name)) {
349    propsAndObjectLinks.push(...propCollection.get(name));
350  }
351  if (objectLinkCollection.get(name)) {
352    propsAndObjectLinks.push(...objectLinkCollection.get(name));
353  }
354  if (projectConfig.optLazyForEach && storedFileInfo.processLazyForEach && stateCollection.get(name)) {
355    propsAndObjectLinks.push(...stateCollection.get(name));
356  }
357  parseChildProperties(name, node, childParam, propsAndObjectLinks, log);
358  return childParam;
359}
360
361class ChildAndParentComponentInfo {
362  childStructInfo: StructInfo;
363  parentStructInfo: StructInfo;
364  paramDecoratorMap: Map<string, ParamDecoratorInfo>;
365  updatePropsDecoratorsV2: string[];
366  propsAndObjectLinks: string[];
367  childName: string;
368  forbiddenInitPropsV2: string[];
369  updatePropsForV1Parent: string[];
370  updatePropsForV2Parent: string[];
371  constructor(childName: string, childNode: ts.CallExpression, propsAndObjectLinks: string[]) {
372    this.childName = childName;
373    this.propsAndObjectLinks = propsAndObjectLinks;
374    this.childStructInfo = processStructComponentV2.getAliasStructInfo(childNode) ||
375      processStructComponentV2.getOrCreateStructInfo(childName);
376    this.paramDecoratorMap = this.childStructInfo.paramDecoratorMap;
377    this.updatePropsDecoratorsV2 = [...this.childStructInfo.eventDecoratorMap.keys(), ...this.paramDecoratorMap.keys()];
378    this.parentStructInfo = componentCollection.currentClassName ?
379      processStructComponentV2.getOrCreateStructInfo(componentCollection.currentClassName) :
380      new StructInfo();
381    this.forbiddenInitPropsV2 = [...this.childStructInfo.localDecoratorSet,
382      ...this.childStructInfo.providerDecoratorSet, ...this.childStructInfo.consumerDecoratorSet,
383      ...this.childStructInfo.regularSet];
384    this.updatePropsForV1Parent = getUpdatePropsForV1Parent();
385    this.updatePropsForV2Parent = [...this.parentStructInfo.localDecoratorSet,
386      ...this.parentStructInfo.paramDecoratorMap.keys(), ...this.parentStructInfo.providerDecoratorSet,
387      ...this.parentStructInfo.consumerDecoratorSet];
388  }
389}
390
391function getUpdatePropsForV1Parent(): string[] {
392  const propertiesMapArr: Array<Map<string, Set<string>>> = [
393    stateCollection, linkCollection, propCollection,
394    provideCollection, consumeCollection, objectLinkCollection,
395    storagePropCollection, storageLinkCollection
396  ];
397  const updatePropsForParent: string[] = [];
398  if (componentCollection.currentClassName) {
399    const localStorageSet: Set<string> = new Set();
400    getLocalStorageCollection(componentCollection.currentClassName, localStorageSet);
401    updatePropsForParent.push(...localStorageSet);
402    propertiesMapArr.forEach((item: Map<string, Set<string>>) => {
403      const value: Set<string> = item.get(componentCollection.currentClassName);
404      if (value) {
405        updatePropsForParent.push(...value);
406      }
407    });
408  }
409  return updatePropsForParent;
410}
411
412function parseChildProperties(childName: string, node: ts.CallExpression,
413  childParam: ts.PropertyAssignment[], propsAndObjectLinks: string[], log: LogInfo[]): void {
414  const childAndParentComponentInfo: ChildAndParentComponentInfo =
415    new ChildAndParentComponentInfo(childName, node, propsAndObjectLinks);
416  if (node.arguments[0].properties) {
417    node.arguments[0].properties.forEach((item: ts.PropertyAssignment) => {
418      if (ts.isIdentifier(item.name)) {
419        const itemName: string = item.name.escapedText.toString();
420        validateChildProperty(item, itemName, childParam, log, childAndParentComponentInfo);
421      }
422    });
423  }
424}
425
426function getForbbidenInitPropsV2Type(itemName: string, info: ChildAndParentComponentInfo): string {
427  let typeName: string = COMPONENT_NON_DECORATOR;
428  if (info.childStructInfo.localDecoratorSet.has(itemName)) {
429    typeName = COMPONENTV2_LOCAL_DECORATOR;
430  } else if (info.childStructInfo.consumerDecoratorSet.has(itemName)) {
431    typeName = COMPONENTV2_CONSUMER_DECORATOR;
432  } else if (info.childStructInfo.providerDecoratorSet.has(itemName)) {
433    typeName = COMPONENTV2_PROVIDER_DECORATOR;
434  }
435  return typeName;
436}
437
438function validateChildProperty(item: ts.PropertyAssignment, itemName: string,
439  childParam: ts.PropertyAssignment[], log: LogInfo[], info: ChildAndParentComponentInfo): void {
440  if (info.childStructInfo.isComponentV2) {
441    if (info.forbiddenInitPropsV2.includes(itemName)) {
442      const propType: string = getForbbidenInitPropsV2Type(itemName, info);
443      log.push({
444        type: LogType.ERROR,
445        message: `The '${propType}' property '${itemName}' in the custom component '${info.childName}'` +
446          ` cannot be initialized here (forbidden to specify).`,
447        pos: item.getStart(),
448        code: '10905324'
449      });
450      return;
451    }
452    if (info.paramDecoratorMap.has(itemName)) {
453      childParam.push(item);
454    }
455    if (isForbiddenAssignToComponentV2(item, itemName, info)) {
456      log.push({
457        type: LogType.ERROR,
458        message: `Property '${itemName}' in the '@ComponentV2' component '${info.childName}' is not allowed to be assigned value here.`,
459        pos: item.getStart(),
460        code: '10905323'
461      });
462    }
463  } else {
464    if (info.propsAndObjectLinks.includes(itemName)) {
465      childParam.push(item);
466    }
467  }
468  logMessageCollection.checkIfAssignToStaticProps(item, itemName, info.childStructInfo.staticPropertySet, log);
469}
470
471function isForbiddenTypeToComponentV1(type: ts.Type): boolean {
472  // @ts-ignore
473  if (type.types && type.types.length) {
474    // @ts-ignore
475    return !type.types.some((item: ts.Type) => {
476      return !isForbiddenTypeToComponentV1(item);
477    });
478  }
479  const allowedTypes: string[] = ['Set', 'Map', 'Date', 'Array'];
480  const name: string = type?.getSymbol()?.getName();
481  if (name && allowedTypes.includes(name)) {
482    return true;
483  }
484  return false;
485}
486
487function isForbiddenAssignToComponentV2(item: ts.PropertyAssignment, itemName: string,
488  info: ChildAndParentComponentInfo): boolean {
489    const checker: ts.TypeChecker | undefined = CurrentProcessFile.getChecker();
490  if (!info.parentStructInfo.isComponentV2 && info.updatePropsDecoratorsV2.includes(itemName) &&
491    isObervedProperty(item.initializer, info) && checker) {
492    const type: ts.Type = checker.getTypeAtLocation(item.initializer);
493    return !(isAllowedTypeToComponentV2(type) || isForbiddenTypeToComponentV1(type) || !(isObservedV2(type) || isFunctionType(type)));
494  }
495  return false;
496}
497
498// isFunctionType
499export function isFunctionType(type: ts.Type): boolean {
500  if (type.types && type.types.length) {
501    return !type.types.some((item: ts.Type) => {
502      return !isFunctionType(item);
503  });
504  }
505  const name: string = type?.getSymbol()?.getName();
506  if (name && name === 'Function') {
507    return true;
508  }
509  return false;
510}
511
512function isObervedProperty(value: ts.Expression, info: ChildAndParentComponentInfo,
513  isV1Parent: boolean = true): boolean {
514  if (value && ts.isPropertyAccessExpression(value) && value.expression.kind === ts.SyntaxKind.ThisKeyword &&
515    ts.isIdentifier(value.name)) {
516    const propertyName: string = value.name.escapedText.toString();
517    return isV1Parent ? info.updatePropsForV1Parent.includes(propertyName) :
518      info.updatePropsForV2Parent.includes(propertyName);
519  }
520  return false;
521}
522
523export function isAllowedTypeToComponentV2(type: ts.Type): boolean {
524  if (type) {
525    // @ts-ignore
526    if (type.types && type.types.length) {
527      // @ts-ignore
528      return type.types.some((item: ts.Type) => {
529        return isAllowedTypeToComponentV2(item);
530      });
531    }
532    // string|number|boolean|enum|null|undefined
533    if (isAllowedTypeForBasic(type.flags)) {
534      return true;
535    }
536  }
537  return false;
538}
539
540export function isAllowedTypeForBasic(flags: ts.TypeFlags): boolean {
541  if (isBasicType(flags) || (flags & (ts.TypeFlags.Null | ts.TypeFlags.Undefined))) {
542    return true;
543  }
544  return false;
545}
546
547function validateInitParam(childName: string, curChildProps: Set<string>,
548  node: ts.CallExpression, log: LogInfo[], parentStructInfo: StructInfo): void {
549  const childStructInfo: StructInfo = processStructComponentV2.getAliasStructInfo(node) ||
550    processStructComponentV2.getOrCreateStructInfo(childName);
551  const paramDecoratorMap: Map<string, ParamDecoratorInfo> = childStructInfo.paramDecoratorMap;
552  if (childStructInfo.isComponentV2) {
553    const needInitParam: string[] = [];
554    for (const item of paramDecoratorMap) {
555      if (item[1].hasRequire) {
556        needInitParam.push(item[0]);
557      }
558    }
559    needInitParam.forEach((paramName: string) => {
560      if (!curChildProps.has(paramName)) {
561        log.push({
562          type: LogType.ERROR,
563          message: `'@Require' decorated '${paramName}' must be initialized through the component constructor.`,
564          pos: node.getStart(),
565          code: '10905321'
566        });
567      }
568    });
569  } else if (parentStructInfo.isComponentV2 && childStructInfo.linkDecoratorsV1.length) {
570    log.push({
571      type: LogType.ERROR,
572      message: `A V2 component cannot be used with any member property decorated by '@Link' in a V1 component.`,
573      pos: node.getStart(),
574      code: '10905213'
575    });
576  }
577}
578
579function createCustomComponent(newNode: ts.NewExpression, name: string, componentNode: ts.CallExpression,
580  isGlobalBuilder: boolean, isBuilder: boolean, isRecycleComponent: boolean,
581  componentAttrInfo: ComponentAttrInfo, builderParamsResult: BuilderParamsResult, log: LogInfo[],
582  isReuseComponentInV2:boolean): ts.Block {
583  let componentParameter: ts.ObjectLiteralExpression;
584  if (componentNode.arguments && componentNode.arguments.length) {
585    componentParameter = ts.factory.createObjectLiteralExpression(createChildElmtId(componentNode, name, log), true);
586  } else {
587    componentParameter = ts.factory.createObjectLiteralExpression([], false);
588  }
589  const arrowArgArr: ts.ParameterDeclaration[] = [
590    ts.factory.createParameterDeclaration(undefined, undefined,
591      ts.factory.createIdentifier(ELMTID)
592    ),
593    ts.factory.createParameterDeclaration(undefined, undefined,
594      ts.factory.createIdentifier(ISINITIALRENDER)
595    )
596  ];
597  const arrowBolck: ts.Statement[] = [
598    projectConfig.optLazyForEach && storedFileInfo.processLazyForEach ? createCollectElmtIdNode() : undefined,
599    createIfCustomComponent(newNode, componentNode, componentParameter, name, isGlobalBuilder,
600      isBuilder, isRecycleComponent, componentAttrInfo, log)
601  ];
602  if (isRecycleComponent) {
603    arrowArgArr.push(ts.factory.createParameterDeclaration(
604      undefined, undefined, ts.factory.createIdentifier(RECYCLE_NODE),
605      undefined, undefined, ts.factory.createNull()
606    ));
607  } else if (partialUpdateConfig.optimizeComponent && isGlobalBuilder &&
608    builderParamsResult && builderParamsResult.firstParam) {
609    const paramName: ts.Identifier = builderParamsResult.firstParam.name as ts.Identifier;
610    arrowArgArr.push(ts.factory.createParameterDeclaration(undefined, undefined,
611      paramName, undefined, undefined, ts.factory.createIdentifier(`__${paramName.escapedText.toString()}__`)
612    ));
613  }
614  if (isRecycleComponent || !partialUpdateConfig.optimizeComponent) {
615    arrowBolck.unshift(createViewStackProcessorStatement(STARTGETACCESSRECORDINGFOR, ELMTID));
616    arrowBolck.push(createViewStackProcessorStatement(STOPGETACCESSRECORDING));
617  }
618  const observeArgArr: ts.Node[] = [
619    ts.factory.createArrowFunction(undefined, undefined, arrowArgArr, undefined,
620      ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
621      ts.factory.createBlock(arrowBolck, true))
622  ];
623  if (isRecycleComponent) {
624    componentAttrInfo.reuseId ? observeArgArr.unshift(componentAttrInfo.reuseId) :
625      observeArgArr.unshift(ts.factory.createStringLiteral(name));
626  } else if (partialUpdateConfig.optimizeComponent) {
627    observeArgArr.push(componentPop(name));
628  }
629  const reuseOrCreateArgArr: ts.ObjectLiteralExpression[] = [ts.factory.createObjectLiteralExpression(
630    generateReuseOrCreateArgArr(componentNode, componentAttrInfo, name, newNode), true)];
631  return ts.factory.createBlock(
632    [
633      ts.factory.createExpressionStatement(ts.factory.createCallExpression(
634        ts.factory.createPropertyAccessExpression(isGlobalBuilder ?
635          ts.factory.createParenthesizedExpression(parentConditionalExpression()) : ts.factory.createThis(),
636        isRecycleComponent ?
637          ts.factory.createIdentifier(OBSERVE_RECYCLE_COMPONENT_CREATION) :
638          isReuseComponentInV2 ? ts.factory.createIdentifier(constantDefine.REUSE_OR_CREATE_METHOD) :
639            ts.factory.createIdentifier(partialUpdateConfig.optimizeComponent ?
640              OBSERVECOMPONENTCREATION2 : OBSERVECOMPONENTCREATION)
641        ),
642        undefined, isReuseComponentInV2 ? reuseOrCreateArgArr as ts.Expression[] : observeArgArr as ts.Expression[]))
643    ],
644    true
645  );
646}
647
648function generateReuseOrCreateArgArr(componentNode: ts.CallExpression, componentAttrInfo: ComponentAttrInfo,
649  name: string, newNode: ts.NewExpression): ts.ObjectLiteralElementLike[] {
650  const reuseParamsArr: ts.ObjectLiteralElementLike[] = [];
651  if (componentNode.expression && ts.isIdentifier(componentNode.expression)) {
652    reuseParamsArr.push(ts.factory.createPropertyAssignment(
653      ts.factory.createIdentifier(constantDefine.COMPONENT_CLASS),
654      componentNode.expression
655    ));
656  }
657  reuseParamsArr.push(createReuseParameterArrowFunction(getArgumentsToPass(componentNode), constantDefine.GET_PARAMS, name));
658  reuseParamsArr.push(createReuseParameterArrowFunction(
659    [], constantDefine.GET_REUSE_ID, componentAttrInfo.reuse ? componentAttrInfo.reuse : name));
660  if (newNode.arguments.length >= 6 && ts.isObjectLiteralExpression(newNode.arguments[5])) {
661    reuseParamsArr.push(generateExtraInfo(true, newNode.arguments[5]));
662  } else {
663    reuseParamsArr.push(generateExtraInfo(false));
664  }
665  return reuseParamsArr;
666}
667
668function getArgumentsToPass(componentNode: ts.CallExpression): ts.NodeArray<ts.ObjectLiteralElementLike> | undefined[] {
669  if (componentNode.arguments && componentNode.arguments.length === 1 &&
670    ts.isObjectLiteralExpression(componentNode.arguments[0]) && componentNode.arguments[0].properties &&
671    componentNode.arguments[0].properties.length) {
672    return componentNode.arguments[0].properties;
673  }
674  return [];
675}
676
677function createReuseParameterArrowFunction(propertyArray: ts.NodeArray<ts.ObjectLiteralElementLike> | undefined[],
678  identifierName: string, name: string): ts.PropertyAssignment {
679  return ts.factory.createPropertyAssignment(
680    ts.factory.createIdentifier(identifierName),
681    ts.factory.createArrowFunction(
682      undefined,
683      undefined,
684      [],
685      undefined,
686      ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
687      identifierName === constantDefine.GET_REUSE_ID ?
688        ts.factory.createStringLiteral(name) :
689        ts.factory.createParenthesizedExpression(ts.factory.createObjectLiteralExpression(
690        propertyArray.length ? propertyArray : [],
691        true
692      ))
693    )
694  );
695}
696
697function generateExtraInfo(hasPositionInfo: boolean, positionInfo?: ts.ObjectLiteralExpression): ts.PropertyAssignment {
698  return ts.factory.createPropertyAssignment(
699    ts.factory.createIdentifier(constantDefine.EXTRA_INFO),
700    hasPositionInfo ?
701    positionInfo :
702    ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED)
703  );
704}
705
706function componentPop(name: string): ts.ObjectLiteralExpression {
707  return ts.factory.createObjectLiteralExpression(
708    [ts.factory.createPropertyAssignment(
709      ts.factory.createIdentifier(NAME),
710      ts.factory.createStringLiteral(name)
711    )],
712    false
713  );
714}
715
716export function assignComponentParams(componentNode: ts.CallExpression,
717  isBuilder: boolean = false): ts.VariableStatement {
718  const isParamsLambda: boolean = true;
719  const [keyArray, valueArray]: [ts.Node[], ts.Node[]] = splitComponentParams(componentNode, isBuilder, isParamsLambda);
720  let integrateParams: boolean = false;
721  if (!keyArray.length && componentNode.arguments && componentNode.arguments.length > 0 && componentNode.arguments[0]) {
722    integrateParams = true;
723  }
724  return ts.factory.createVariableStatement(
725    undefined,
726    ts.factory.createVariableDeclarationList([ts.factory.createVariableDeclaration(
727      ts.factory.createIdentifier(COMPONENT_PARAMS_LAMBDA_FUNCTION),
728      undefined,
729      undefined,
730      ts.factory.createArrowFunction(
731        undefined,
732        undefined,
733        [],
734        undefined,
735        ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
736        ts.factory.createBlock(
737          [ts.factory.createReturnStatement(
738            integrateParams ? paramsLambdaCallBack(componentNode) : ts.factory.createObjectLiteralExpression(
739              reWriteComponentParams(keyArray, valueArray),
740              true
741            )
742          )],
743          true
744        )
745      )
746    )],
747    ts.NodeFlags.Let
748    ));
749}
750
751function paramsLambdaCallBack(componentNode: ts.CallExpression): ts.Expression {
752  if (partialUpdateConfig.partialUpdateMode && componentNode.arguments.length === 1 &&
753    isLocalStorageParameter(componentNode)) {
754    return ts.factory.createObjectLiteralExpression([], true);
755  } else {
756    return componentNode.arguments[0];
757  }
758}
759
760function reWriteComponentParams(keyArray: ts.Node[], valueArray: ts.Node[]): (ts.PropertyAssignment |
761  ts.ShorthandPropertyAssignment)[] {
762  const returnProperties: (ts.PropertyAssignment | ts.ShorthandPropertyAssignment)[] = [];
763  keyArray.forEach((item: ts.Identifier, index: number) => {
764    if (!valueArray[index]) {
765      returnProperties.push(ts.factory.createShorthandPropertyAssignment(
766        item,
767        undefined
768      ));
769    } else {
770      returnProperties.push(ts.factory.createPropertyAssignment(
771        item,
772        valueArray[index] as ts.Identifier
773      ));
774    }
775  });
776  return returnProperties;
777}
778
779function splitComponentParams(componentNode: ts.CallExpression, isBuilder: boolean, isParamsLambda: boolean): [ts.Node[], ts.Node[]] {
780  const keyArray: ts.Node[] = [];
781  const valueArray: ts.Node[] = [];
782  if (componentNode.arguments && componentNode.arguments.length > 0 &&
783    ts.isObjectLiteralExpression(componentNode.arguments[0]) && componentNode.arguments[0].properties) {
784    componentNode.arguments[0].properties.forEach((propertyItem: ts.PropertyAssignment) => {
785      const newPropertyItem: ts.PropertyAssignment =
786        isProperty(propertyItem) ? createReference(propertyItem, [], isBuilder, isParamsLambda) : propertyItem;
787      keyArray.push(newPropertyItem.name);
788      valueArray.push(newPropertyItem.initializer);
789    });
790  }
791  return [keyArray, valueArray];
792}
793
794function createIfCustomComponent(newNode: ts.NewExpression, componentNode: ts.CallExpression,
795  componentParameter: ts.ObjectLiteralExpression, name: string, isGlobalBuilder: boolean, isBuilder: boolean,
796  isRecycleComponent: boolean, componentAttrInfo: ComponentAttrInfo, log: LogInfo[]): ts.IfStatement {
797  return ts.factory.createIfStatement(
798    ts.factory.createIdentifier(ISINITIALRENDER),
799    ts.factory.createBlock(
800      [componentParamDetachment(newNode, isRecycleComponent, name, log, componentNode),
801        isRecycleComponent ? createNewRecycleComponent(newNode, componentNode, name, componentAttrInfo) :
802          createNewComponent(COMPONENT_CALL, name, componentNode),
803        assignComponentParams(componentNode, isBuilder),
804        assignmentFunction(COMPONENT_CALL)
805      ], true),
806    ts.factory.createBlock(
807      [ts.factory.createExpressionStatement(ts.factory.createCallExpression(
808        ts.factory.createPropertyAccessExpression(isGlobalBuilder ?
809          ts.factory.createParenthesizedExpression(parentConditionalExpression()) : ts.factory.createThis(),
810        ts.factory.createIdentifier(UPDATE_STATE_VARS_OF_CHIND_BY_ELMTID)
811        ), undefined,
812        [ts.factory.createIdentifier(ELMTID), componentParameter]))], true)
813  );
814}
815
816export function assignmentFunction(componeParamName: string): ts.ExpressionStatement {
817  return ts.factory.createExpressionStatement(ts.factory.createBinaryExpression(
818    ts.factory.createPropertyAccessExpression(
819      ts.factory.createIdentifier(componeParamName),
820      ts.factory.createIdentifier(COMPONENT_PARAMS_FUNCTION)
821    ),
822    ts.factory.createToken(ts.SyntaxKind.EqualsToken),
823    ts.factory.createIdentifier(COMPONENT_PARAMS_LAMBDA_FUNCTION)
824  ));
825}
826
827function traverseChildComponentArgs(childParam: ts.Expression[], name: string, log: LogInfo[],
828  componentNode: ts.CallExpression): ts.Expression[] {
829  const childStructInfo: StructInfo = processStructComponentV2.getAliasStructInfo(componentNode) ||
830    processStructComponentV2.getOrCreateStructInfo(name);
831  if (!childStructInfo.isComponentV2) {
832    return childParam;
833  }
834  const objectLiteralIndex: number = 2;
835  if (childParam.length > objectLiteralIndex && ts.isObjectLiteralExpression(childParam[1]) &&
836    childParam[1].properties) {
837    const newProperties: ts.PropertyAssignment[] = [];
838    childParam[1].properties.forEach((item: ts.PropertyAssignment) => {
839      if (item.name && ts.isIdentifier(item.name)) {
840        const itemName: string = item.name.escapedText.toString();
841        updatePropertyAssignment(newProperties, itemName, item, childStructInfo, log);
842      }
843    });
844    if (newProperties.length) {
845      return getNewArgsForCustomComponent(childParam, newProperties);
846    }
847  }
848  return childParam;
849}
850
851function getNewArgsForCustomComponent(childParam: ts.Expression[],
852  newProperties: ts.PropertyAssignment[]): ts.Expression[] {
853  const newArr: ts.Expression[] = [];
854  const newObjectLiteralNode: ts.ObjectLiteralExpression =
855    ts.factory.updateObjectLiteralExpression(childParam[1], [...childParam[1].properties, ...newProperties]);
856  childParam.forEach((item: ts.Expression, index: number) => {
857    if (index === 1) {
858      newArr.push(newObjectLiteralNode);
859    } else {
860      newArr.push(item);
861    }
862  });
863  return newArr;
864}
865
866function updatePropertyAssignment(newProperties: ts.PropertyAssignment[],
867  itemName: string, item: ts.PropertyAssignment, childStructInfo: StructInfo, log: LogInfo[]): void {
868  if (isDoubleNonNullExpression(item.initializer) && !moreThanDoubleNonNull(item.initializer)) {
869    if (isLeftHandExpression(item.initializer.expression.expression)) {
870      const result: Record<string, boolean> = { hasQuestionToken: false };
871      traverseExpressionNode(item.initializer.expression.expression, result);
872      if (result.hasQuestionToken) {
873        log.push({
874          type: LogType.ERROR,
875          message: `The optional character can not be used in the initial value of property '${itemName}'.`,
876          pos: item.getStart(),
877          code: '10905320'
878        });
879        return;
880      }
881      if (childStructInfo.paramDecoratorMap.has(itemName) &&
882        childStructInfo.eventDecoratorMap.has('$' + itemName)) {
883        newProperties.push(createUpdateTwoWayNode(itemName, item.initializer.expression.expression));
884        return;
885      }
886      log.push({
887        type: LogType.ERROR,
888        message: 'When the two-way binding syntax is used, ' +
889          `the variable '${itemName}' must be decorated with '@Param', ` +
890          `and the '@Event' variable '$` + `${itemName}' ` + `must be defined in the ${childStructInfo.structName}.`,
891        pos: item.getStart(),
892        code: '10905319'
893      });
894      return;
895    }
896    log.push({
897      type: LogType.ERROR,
898      message: 'When the two-way binding syntax is used, ' +
899        `the initial value of property '${itemName}' must be a variable.`,
900      pos: item.getStart(),
901      code: '10905318'
902    });
903    return;
904  }
905}
906
907function validateTwoWayComputed(node: ts.PropertyAccessExpression, log: LogInfo[]): void {
908  if (ts.isPropertyAccessExpression(node) && node.expression &&
909    node.expression.kind === ts.SyntaxKind.ThisKeyword && globalProgram.checker) {
910    const symbol: ts.Symbol = globalProgram.checker.getSymbolAtLocation(node);
911    logMessageCollection.checkTwoWayComputed(node, symbol, log);
912  }
913}
914
915function createUpdateTwoWayNode(itemName: string, leftHandExpression: ts.Expression): ts.PropertyAssignment {
916  return ts.factory.createPropertyAssignment(
917    ts.factory.createIdentifier('$' + itemName),
918    ts.factory.createArrowFunction(undefined, undefined,
919      [createAstNodeUtils.createParameterDeclaration('value')], undefined,
920      ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
921      ts.factory.createBlock([
922        ts.factory.createExpressionStatement(ts.factory.createBinaryExpression(
923          leftHandExpression, ts.factory.createToken(ts.SyntaxKind.EqualsToken),
924          ts.factory.createIdentifier('value')
925        ))
926      ], false)
927    )
928  );
929}
930
931function isDoubleNonNullExpression(node: ts.Expression): boolean {
932  return node && ts.isNonNullExpression(node) && ts.isNonNullExpression(node.expression);
933}
934
935function moreThanDoubleNonNull(node: ts.Expression): boolean {
936  return node && ts.isNonNullExpression(node) && ts.isNonNullExpression(node.expression) && ts.isNonNullExpression(node.expression.expression);
937}
938
939function isLeftHandExpression(node: ts.Expression): boolean {
940  return node && (ts.isIdentifier(node) || ts.isPropertyAccessExpression(node));
941}
942
943function traverseExpressionNode(node: ts.Node, result: Record<string, boolean>): void {
944  if (ts.isOptionalChain(node) && !ts.isNonNullExpression(node) && node.questionDotToken) {
945    result.hasQuestionToken = true;
946  }
947  if (!result.hasQuestionToken) {
948    ts.forEachChild(node, (child: ts.Node) => traverseExpressionNode(child, result));
949  }
950}
951
952function componentParamDetachment(newNode: ts.NewExpression, isRecycleComponent: boolean,
953  name: string, log: LogInfo[], componentNode: ts.CallExpression): ts.VariableStatement {
954  const paramsArray: ts.Expression[] = newNode.arguments.length ? newNode.arguments : [];
955  const updateNewNode = ts.factory.updateNewExpression(newNode, newNode.expression,
956    newNode.typeArguments, traverseChildComponentArgs(paramsArray, name, log, componentNode));
957  return ts.factory.createVariableStatement(
958    undefined,
959    ts.factory.createVariableDeclarationList(
960      [ts.factory.createVariableDeclaration(
961        ts.factory.createIdentifier(COMPONENT_CALL),
962        undefined,
963        undefined,
964        isRecycleComponent ? ts.factory.createConditionalExpression(
965          ts.factory.createIdentifier(RECYCLE_NODE),
966          ts.factory.createToken(ts.SyntaxKind.QuestionToken),
967          ts.factory.createIdentifier(RECYCLE_NODE),
968          ts.factory.createToken(ts.SyntaxKind.ColonToken),
969          newNode) : updateNewNode
970      )],
971      ts.NodeFlags.Let
972    ));
973}
974
975function createNewComponent(componeParamName: string, name: string,
976  componentNode: ts.CallExpression): ts.Statement {
977  const childStructInfo: StructInfo = processStructComponentV2.getAliasStructInfo(componentNode) ||
978    processStructComponentV2.getOrCreateStructInfo(name);
979  return ts.factory.createExpressionStatement(
980    ts.factory.createCallExpression(
981      ts.factory.createPropertyAccessExpression(
982        ts.factory.createIdentifier(
983          childStructInfo.isComponentV2 ? constantDefine.STRUCT_PARENT : BASE_COMPONENT_NAME_PU),
984        ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION)
985      ), undefined, [ts.factory.createIdentifier(componeParamName)]));
986}
987
988function createNewRecycleComponent(newNode: ts.NewExpression, componentNode: ts.CallExpression,
989  name: string, componentAttrInfo: ComponentAttrInfo): ts.Statement {
990  let argNode: ts.Expression[] = [];
991  const componentParam: ts.PropertyAssignment[] = [];
992  if (componentNode.arguments && componentNode.arguments.length > 0 &&
993    ts.isObjectLiteralExpression(componentNode.arguments[0]) && componentNode.arguments[0].properties) {
994    componentNode.arguments[0].properties.forEach((propertyItem: ts.PropertyAssignment) => {
995      const newPropertyItem: ts.PropertyAssignment = isProperty(propertyItem) ?
996        createReference(propertyItem, [], false, false, true) : propertyItem;
997      componentParam.push(newPropertyItem);
998    });
999    argNode = [ts.factory.createObjectLiteralExpression(componentParam, false)];
1000  } else {
1001    argNode = [ts.factory.createObjectLiteralExpression([], false)];
1002  }
1003  const recycleNode: ts.CallExpression = ts.factory.createCallExpression(
1004    createRecyclePropertyNode(ABOUT_TO_REUSE), undefined, argNode);
1005  return ts.factory.createExpressionStatement(
1006    ts.factory.createCallExpression(
1007      ts.factory.createPropertyAccessExpression(
1008        ts.factory.createIdentifier(BASE_COMPONENT_NAME_PU),
1009        ts.factory.createIdentifier(COMPONENT_CREATE_RECYCLE)
1010      ), undefined,
1011      [
1012        ts.factory.createIdentifier(COMPONENT_CALL),
1013        ts.factory.createBinaryExpression(
1014          ts.factory.createIdentifier(RECYCLE_NODE),
1015          ts.factory.createToken(ts.SyntaxKind.ExclamationEqualsEqualsToken),
1016          ts.factory.createNull()
1017        ),
1018        componentAttrInfo.reuseId ? componentAttrInfo.reuseId as ts.Expression :
1019          ts.factory.createStringLiteral(name),
1020        ts.factory.createArrowFunction(undefined, undefined, [], undefined,
1021          ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
1022          ts.factory.createBlock([
1023            ts.factory.createIfStatement(
1024              ts.factory.createBinaryExpression(
1025                ts.factory.createIdentifier(RECYCLE_NODE),
1026                ts.factory.createToken(ts.SyntaxKind.AmpersandAmpersandToken),
1027                ts.factory.createBinaryExpression(
1028                  ts.factory.createTypeOfExpression(
1029                    createRecyclePropertyNode(COMPONENT_ABOUTTOREUSEINTERNAL_FUNCTION)),
1030                  ts.factory.createToken(ts.SyntaxKind.EqualsEqualsEqualsToken),
1031                  ts.factory.createStringLiteral(FUNCTION)
1032                )),
1033              ts.factory.createBlock([
1034                ts.factory.createExpressionStatement(ts.factory.createCallExpression(
1035                  createRecyclePropertyNode(COMPONENT_ABOUTTOREUSEINTERNAL_FUNCTION),
1036                  undefined,
1037                  []
1038                ))
1039              ], true),
1040              ts.factory.createBlock(
1041                [
1042                  ts.factory.createIfStatement(ts.factory.createBinaryExpression(
1043                    createRecyclePropertyNode(ABOUT_TO_REUSE), ts.factory.createToken(ts.SyntaxKind.AmpersandAmpersandToken),
1044                    ts.factory.createBinaryExpression(
1045                      ts.factory.createTypeOfExpression(createRecyclePropertyNode(ABOUT_TO_REUSE)),
1046                      ts.factory.createToken(ts.SyntaxKind.EqualsEqualsEqualsToken),
1047                      ts.factory.createStringLiteral(FUNCTION)
1048                    )),
1049                  ts.factory.createBlock([ts.factory.createExpressionStatement(recycleNode)], true)),
1050                  ts.factory.createExpressionStatement(ts.factory.createCallExpression(
1051                    createRecyclePropertyNode(COMPONENT_RERENDER_FUNCTION), undefined, []
1052                  ))
1053                ],
1054                true
1055              )
1056            )], true))
1057      ]));
1058}
1059
1060function createRecyclePropertyNode(recycleFunctionName: string): ts.PropertyAccessExpression {
1061  return ts.factory.createPropertyAccessExpression(
1062    ts.factory.createIdentifier(RECYCLE_NODE), ts.factory.createIdentifier(recycleFunctionName));
1063}
1064
1065function validateCustomComponentPrams(node: ts.CallExpression, name: string,
1066  props: ts.ObjectLiteralElementLike[], log: LogInfo[], isBuilder: boolean): void {
1067  const curChildProps: Set<string> = new Set([]);
1068  const nodeArguments: ts.NodeArray<ts.Expression> = node.arguments;
1069  const linkSet: Set<string> = getCollectionSet(name, linkCollection);
1070  if (nodeArguments && nodeArguments.length >= 1 &&
1071    ts.isObjectLiteralExpression(nodeArguments[0])) {
1072    const nodeArgument: ts.ObjectLiteralExpression = nodeArguments[0] as ts.ObjectLiteralExpression;
1073    const doubleExclamationCollection: string[] = [];
1074    const dollarPropertyCollection: string[] = [];
1075    nodeArgument.properties.forEach(item => {
1076      if (item.name && ts.isIdentifier(item.name)) {
1077        const propName: string = item.name.escapedText.toString();
1078        curChildProps.add(propName);
1079        logMessageCollection.checkIfAssignToStaticProps(item, propName, regularStaticCollection.get(name) || new Set(), log);
1080      }
1081      validateStateManagement(item, name, log, isBuilder, doubleExclamationCollection, dollarPropertyCollection);
1082      if (isNonThisProperty(item, linkSet)) {
1083        if (isToChange(item as ts.PropertyAssignment, name)) {
1084          item = ts.factory.updatePropertyAssignment(item as ts.PropertyAssignment,
1085            item.name, changeNodeFromCallToArrow(item.initializer));
1086        }
1087        props.push(item);
1088      }
1089    });
1090    logMessageCollection.checkIfNeedDollarEvent(doubleExclamationCollection, dollarPropertyCollection, node, log);
1091  }
1092  const parentStructInfo: StructInfo = componentCollection.currentClassName ?
1093    processStructComponentV2.getOrCreateStructInfo(componentCollection.currentClassName) :
1094    new StructInfo();
1095  validateInitDecorator(node, name, curChildProps, log);
1096  validateMandatoryToInitViaParam(node, name, curChildProps, log, parentStructInfo);
1097  validateInitParam(name, curChildProps, node, log, parentStructInfo);
1098}
1099
1100function getCustomComponentNode(node: ts.ExpressionStatement): ts.CallExpression {
1101  let temp: any = node.expression;
1102  let child: any = null;
1103  let componentNode: any = null;
1104  while (temp) {
1105    if (ts.isIdentifier(temp)) {
1106      child = temp;
1107      break;
1108    }
1109    temp = temp.expression;
1110  }
1111  if (child) {
1112    let parent = child.parent;
1113    while (parent) {
1114      if (ts.isExpressionStatement(parent)) {
1115        break;
1116      }
1117      if (ts.isCallExpression(parent) || ts.isEtsComponentExpression(parent)) {
1118        componentNode = parent;
1119        break;
1120      }
1121      parent = parent.parent;
1122    }
1123  }
1124  return componentNode;
1125}
1126
1127export enum ParentType {
1128  NormalComponentV1,
1129  NormalComponentV2,
1130  ReuseComponentV1,
1131  ReuseComponentV2,
1132  InvalidComponentType
1133}
1134
1135function getParentComponentType(parentName: string): ParentType {
1136  const parentCustomComponentInfo: StructInfo = parentName ?
1137    processStructComponentV2.getOrCreateStructInfo(parentName) : new StructInfo();
1138  let type: ParentType = ParentType.InvalidComponentType;
1139  if (parentCustomComponentInfo.isComponentV1 &&
1140    parentCustomComponentInfo.isReusable) {
1141    type = ParentType.ReuseComponentV1;
1142  } else if (parentCustomComponentInfo.isComponentV1 &&
1143    !parentCustomComponentInfo.isReusable) {
1144    type = ParentType.NormalComponentV1;
1145  } else if (parentCustomComponentInfo.isComponentV2 &&
1146    parentCustomComponentInfo.isReusableV2) {
1147    type = ParentType.ReuseComponentV2;
1148  } else if (parentCustomComponentInfo.isComponentV2 &&
1149    !parentCustomComponentInfo.isReusableV2) {
1150    type = ParentType.NormalComponentV2;
1151  }
1152  return type;
1153}
1154
1155function getCollectionSet(name: string, collection: Map<string, Set<string>>): Set<string> {
1156  if (!collection) {
1157    return new Set([]);
1158  }
1159  return collection.get(name) || new Set([]);
1160}
1161
1162function isThisProperty(node: ts.ObjectLiteralElementLike, propertySet: Set<string>): boolean {
1163  if (ts.isPropertyAssignment(node) && ts.isIdentifier(node.name) &&
1164    propertySet.has(node.name.escapedText.toString())) {
1165    return true;
1166  }
1167  return false;
1168}
1169
1170function isNonThisProperty(node: ts.ObjectLiteralElementLike, propertySet: Set<string>): boolean {
1171  if (ts.isPropertyAssignment(node) && ts.isIdentifier(node.name) &&
1172    (node.initializer.escapedText && node.initializer.escapedText.includes('$') ||
1173    ts.isPropertyAccessExpression(node.initializer) && node.initializer.expression &&
1174    node.initializer.expression.kind === ts.SyntaxKind.ThisKeyword &&
1175    ts.isIdentifier(node.initializer.name) && node.initializer.name.escapedText.toString().includes('$'))) {
1176    return false;
1177  }
1178  if (ts.isPropertyAssignment(node) && ts.isIdentifier(node.name) &&
1179    !propertySet.has(node.name.escapedText.toString())) {
1180    return true;
1181  }
1182  return false;
1183}
1184
1185function validateStateManagement(node: ts.ObjectLiteralElementLike, customComponentName: string, log: LogInfo[],
1186  isBuilder: boolean, doubleExclamationCollection: string[], dollarPropertyCollection: string[]): void {
1187  validateForbiddenToInitViaParam(node, customComponentName, log);
1188  if (componentCollection.currentClassName) {
1189    const parentStructInfo: StructInfo =
1190      processStructComponentV2.getOrCreateStructInfo(componentCollection.currentClassName);
1191    if (parentStructInfo.isComponentV2) {
1192      if (ts.isPropertyAssignment(node)) {
1193        checkDoubleExclamationPropertyAssignment(node, log, doubleExclamationCollection);
1194        checkDollarPropertyAssignment(node, dollarPropertyCollection);
1195      }
1196      return;
1197    }
1198  }
1199  checkFromParentToChild(node, customComponentName, log, isBuilder);
1200}
1201
1202function checkDoubleExclamationPropertyAssignment(node: ts.PropertyAssignment, log: LogInfo[], doubleExclamationCollection: string[]): void {
1203  if (node.initializer && isDoubleNonNullExpression(node.initializer)) {
1204    if (node.initializer.expression && node.initializer.expression.expression &&
1205      isLeftHandExpression(node.initializer.expression.expression)) {
1206        doubleExclamationCollection.push(node.name.getText());
1207        validateTwoWayComputed(node.initializer.expression.expression, log);
1208    }
1209  }
1210}
1211
1212function checkDollarPropertyAssignment(node: ts.PropertyAssignment, dollarPropertyCollection: string[]): void {
1213  const regex = /^\$[a-zA-Z_][a-zA-Z0-9_]*$/;
1214  if (node.name && ts.isIdentifier(node.name) && regex.test(node.name.escapedText.toString())) {
1215    dollarPropertyCollection.push(node.name.escapedText.toString());
1216  }
1217}
1218
1219function checkFromParentToChild(node: ts.ObjectLiteralElementLike, customComponentName: string,
1220  log: LogInfo[], isBuilder: boolean): void {
1221  let propertyName: string;
1222  if (ts.isIdentifier(node.name)) {
1223    propertyName = node.name.escapedText.toString();
1224  }
1225  const curPropertyKind: string = getPropertyDecoratorKind(propertyName, customComponentName);
1226  let parentPropertyName: string;
1227  if (curPropertyKind) {
1228    if (isInitFromParent(node)) {
1229      parentPropertyName =
1230        getParentPropertyName(node as ts.PropertyAssignment, curPropertyKind, log);
1231      let parentPropertyKind: string = PropMapManager.find(parentPropertyName);
1232      if (parentPropertyKind && !isCorrectInitFormParent(parentPropertyKind, curPropertyKind)) {
1233        validateIllegalInitFromParent(
1234          node, propertyName, curPropertyKind, parentPropertyName, parentPropertyKind, log);
1235      }
1236    } else if (isInitFromLocal(node) && ts.isPropertyAssignment(node) &&
1237      curPropertyKind !== COMPONENT_OBJECT_LINK_DECORATOR) {
1238      if (!isCorrectInitFormParent(COMPONENT_NON_DECORATOR, curPropertyKind)) {
1239        validateIllegalInitFromParent(node, propertyName, curPropertyKind,
1240          node.initializer.getText(), COMPONENT_NON_DECORATOR, log);
1241      }
1242    } else if (curPropertyKind === COMPONENT_OBJECT_LINK_DECORATOR && node.initializer &&
1243      (ts.isPropertyAccessExpression(node.initializer) ||
1244        ts.isElementAccessExpression(node.initializer) || ts.isIdentifier(node.initializer))) {
1245      return;
1246    } else {
1247      parentPropertyName =
1248        getParentPropertyName(node as ts.PropertyAssignment, curPropertyKind, log) || propertyName;
1249      const parentPropertyKind = COMPONENT_NON_DECORATOR;
1250      if (!isCorrectInitFormParent(parentPropertyKind, curPropertyKind)) {
1251        if (isBuilder && judgeStructAssignedDollar(node)) {
1252          log.push({
1253            type: LogType.WARN,
1254            message: `Unrecognized property '${parentPropertyName}', make sure it can be assigned to ` +
1255              `${curPropertyKind} property '${propertyName}' by yourself.`,
1256            // @ts-ignore
1257            pos: node.initializer ? node.initializer.getStart() : node.getStart()
1258          });
1259        } else {
1260          validateIllegalInitFromParent(
1261            node, propertyName, curPropertyKind, parentPropertyName, parentPropertyKind, log, LogType.WARN);
1262        }
1263      }
1264    }
1265  }
1266}
1267
1268function judgeStructAssignedDollar(node: ts.ObjectLiteralElementLike): boolean {
1269  return partialUpdateConfig.partialUpdateMode && node.initializer &&
1270    ts.isPropertyAccessExpression(node.initializer) &&
1271    node.initializer.expression && ts.isIdentifier(node.initializer.expression) &&
1272    node.initializer.expression.escapedText.toString() === $$;
1273}
1274
1275function isInitFromParent(node: ts.ObjectLiteralElementLike): boolean {
1276  if (ts.isPropertyAssignment(node) && node.initializer) {
1277    if (ts.isPropertyAccessExpression(node.initializer) && node.initializer.expression &&
1278    node.initializer.expression.kind === ts.SyntaxKind.ThisKeyword &&
1279    ts.isIdentifier(node.initializer.name)) {
1280      return true;
1281    } else if (ts.isIdentifier(node.initializer) &&
1282      matchStartWithDollar(node.initializer.getText())) {
1283      return true;
1284    }
1285  }
1286  return false;
1287}
1288
1289function isInitFromLocal(node: ts.ObjectLiteralElementLike): boolean {
1290  if (ts.isPropertyAssignment(node) && ts.isIdentifier(node.initializer) &&
1291    !matchStartWithDollar(node.initializer.getText())) {
1292    return true;
1293  }
1294  return false;
1295}
1296
1297function getParentPropertyName(node: ts.PropertyAssignment, curPropertyKind: string,
1298  log: LogInfo[]): string {
1299  const initExpression: ts.Expression = node.initializer;
1300  if (!initExpression) {
1301    return undefined;
1302  }
1303  let parentPropertyName: string = initExpression.getText();
1304  const symbol = globalProgram.checker?.getSymbolAtLocation(initExpression);
1305  if (curPropertyKind === COMPONENT_LINK_DECORATOR) {
1306    // @ts-ignore
1307    const initName: ts.Identifier = initExpression.name || initExpression;
1308    if (!symbol && hasDollar(initExpression)) {
1309      parentPropertyName = initName.getText().replace(/^\$/, '');
1310    } else {
1311      parentPropertyName = initName.getText();
1312    }
1313  } else {
1314    if (!symbol && hasDollar(initExpression)) {
1315      validateNonLinkWithDollar(node, log);
1316    }
1317    // @ts-ignore
1318    if (node.initializer && node.initializer.name) {
1319      parentPropertyName = node.initializer.name.getText();
1320    }
1321  }
1322
1323  return parentPropertyName;
1324}
1325
1326function isCorrectInitFormParent(parent: string, child: string): boolean {
1327  switch (child) {
1328    case COMPONENT_STATE_DECORATOR:
1329    case COMPONENT_PROP_DECORATOR:
1330    case COMPONENT_PROVIDE_DECORATOR:
1331      return true;
1332    case COMPONENT_NON_DECORATOR:
1333      if ([COMPONENT_NON_DECORATOR, COMPONENT_STATE_DECORATOR, COMPONENT_LINK_DECORATOR, COMPONENT_PROP_DECORATOR,
1334        COMPONENT_OBJECT_LINK_DECORATOR, COMPONENT_STORAGE_LINK_DECORATOR].includes(parent)) {
1335        return true;
1336      }
1337      break;
1338    case COMPONENT_LINK_DECORATOR:
1339    case COMPONENT_OBJECT_LINK_DECORATOR:
1340      return ![COMPONENT_NON_DECORATOR].includes(parent);
1341  }
1342  return false;
1343}
1344
1345function getPropertyDecoratorKind(propertyName: string, customComponentName: string): string {
1346  for (const item of decoractorMap.entries()) {
1347    if (getCollectionSet(customComponentName, item[1]).has(propertyName)) {
1348      return item[0];
1349    }
1350  }
1351  return undefined;
1352}
1353
1354function createFindChildById(id: string, name: string, isBuilder: boolean = false): ts.VariableStatement {
1355  return ts.factory.createVariableStatement(undefined, ts.factory.createVariableDeclarationList(
1356    [ts.factory.createVariableDeclaration(ts.factory.createIdentifier(
1357      `${CUSTOM_COMPONENT_EARLIER_CREATE_CHILD}${id}`), undefined, ts.factory.createTypeReferenceNode(
1358      ts.factory.createIdentifier(name)),
1359    ts.factory.createConditionalExpression(
1360      ts.factory.createParenthesizedExpression(
1361        ts.factory.createBinaryExpression(
1362          createConditionParent(isBuilder),
1363          ts.factory.createToken(ts.SyntaxKind.AmpersandAmpersandToken),
1364          ts.factory.createPropertyAccessExpression(
1365            createConditionParent(isBuilder),
1366            ts.factory.createIdentifier(CUSTOM_COMPONENT_FUNCTION_FIND_CHILD_BY_ID)
1367          ))), ts.factory.createToken(ts.SyntaxKind.QuestionToken),
1368      ts.factory.createAsExpression(ts.factory.createCallExpression(
1369        ts.factory.createPropertyAccessExpression(createConditionParent(isBuilder),
1370          ts.factory.createIdentifier(`${CUSTOM_COMPONENT_FUNCTION_FIND_CHILD_BY_ID}`)), undefined,
1371        [isBuilder ? ts.factory.createCallExpression(ts.factory.createIdentifier(GENERATE_ID),
1372          undefined, []) : ts.factory.createStringLiteral(id)]),
1373      ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(name))),
1374      ts.factory.createToken(ts.SyntaxKind.ColonToken),
1375      ts.factory.createIdentifier(COMPONENT_IF_UNDEFINED)))], ts.NodeFlags.Let));
1376}
1377
1378export function createConditionParent(isBuilder: boolean): ts.ParenthesizedExpression | ts.ThisExpression {
1379  return isBuilder ? ts.factory.createParenthesizedExpression(parentConditionalExpression()) : ts.factory.createThis();
1380}
1381
1382function createCustomComponentIfStatement(id: string, node: ts.ExpressionStatement,
1383  newObjectLiteralExpression: ts.ObjectLiteralExpression, parentName: string): ts.IfStatement {
1384  const viewName: string = `${CUSTOM_COMPONENT_EARLIER_CREATE_CHILD}${id}`;
1385  return ts.factory.createIfStatement(ts.factory.createBinaryExpression(
1386    ts.factory.createIdentifier(viewName),
1387    ts.factory.createToken(ts.SyntaxKind.EqualsEqualsToken),
1388    ts.factory.createIdentifier(`${COMPONENT_CONSTRUCTOR_UNDEFINED}`)),
1389  ts.factory.createBlock([node], true),
1390  ts.factory.createBlock([ts.factory.createExpressionStatement(ts.factory.createCallExpression(
1391    ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(
1392      viewName), ts.factory.createIdentifier(
1393      `${COMPONENT_CONSTRUCTOR_UPDATE_PARAMS}`)), undefined, [newObjectLiteralExpression])),
1394  isStaticViewCollection.get(parentName) ? createStaticIf(viewName) : undefined,
1395  ts.factory.createExpressionStatement(ts.factory.createCallExpression(
1396    ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(`${BASE_COMPONENT_NAME}`),
1397      ts.factory.createIdentifier(`${COMPONENT_CREATE_FUNCTION}`)), undefined,
1398    [ts.factory.createIdentifier(viewName)]))], true));
1399}
1400
1401function createStaticIf(name: string): ts.IfStatement {
1402  return ts.factory.createIfStatement(ts.factory.createPrefixUnaryExpression(
1403    ts.SyntaxKind.ExclamationToken, ts.factory.createCallExpression(
1404      ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(name),
1405        ts.factory.createIdentifier(CUSTOM_COMPONENT_NEEDS_UPDATE_FUNCTION)), undefined, [])),
1406  ts.factory.createBlock([ts.factory.createExpressionStatement(ts.factory.createCallExpression(
1407    ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(name),
1408      ts.factory.createIdentifier(CUSTOM_COMPONENT_MARK_STATIC_FUNCTION)),
1409    undefined, []))], true), undefined);
1410}
1411
1412function hasDollar(initExpression: ts.Expression): boolean {
1413  if (ts.isPropertyAccessExpression(initExpression) &&
1414    matchStartWithDollar(initExpression.name.getText())) {
1415    return true;
1416  } else if (ts.isIdentifier(initExpression) && matchStartWithDollar(initExpression.getText())) {
1417    return true;
1418  } else {
1419    return false;
1420  }
1421}
1422
1423function matchStartWithDollar(name: string): boolean {
1424  return /^\$/.test(name);
1425}
1426
1427function getForbbiddenToInitViaParamType(customComponentName: string,
1428  node: ts.Identifier): string {
1429  let propType: string = COMPONENT_CONSUME_DECORATOR;
1430  const propName: string = node.escapedText.toString();
1431  if (getCollectionSet(customComponentName, storageLinkCollection).has(propName)) {
1432    propType = COMPONENT_STORAGE_LINK_DECORATOR;
1433  } else if (getCollectionSet(customComponentName, storagePropCollection).has(propName)) {
1434    propType = COMPONENT_STORAGE_PROP_DECORATOR;
1435  } else if (ifLocalStorageLink(customComponentName, propName)) {
1436    propType = COMPONENT_LOCAL_STORAGE_LINK_DECORATOR;
1437  } else if (ifLocalStorageProp(customComponentName, propName)) {
1438    propType = COMPONENT_LOCAL_STORAGE_PROP_DECORATOR;
1439  }
1440  return propType;
1441}
1442
1443function ifLocalStorageProp(componentName: string, propName: string): boolean {
1444  if (!localStoragePropCollection.get(componentName).keys) {
1445    return false;
1446  } else {
1447    const collection: Set<string> = new Set();
1448    for (const key of localStoragePropCollection.get(componentName).keys()) {
1449      collection.add(key);
1450    }
1451    return collection.has(propName);
1452  }
1453}
1454
1455function ifLocalStorageLink(componentName: string, propName: string): boolean {
1456  if (!localStorageLinkCollection.get(componentName).keys) {
1457    return false;
1458  } else {
1459    const collection: Set<string> = new Set();
1460    for (const key of localStorageLinkCollection.get(componentName).keys()) {
1461      collection.add(key);
1462    }
1463    return collection.has(propName);
1464  }
1465}
1466
1467function validateForbiddenToInitViaParam(node: ts.ObjectLiteralElementLike,
1468  customComponentName: string, log: LogInfo[]): void {
1469  const forbiddenToInitViaParamSet: Set<string> = new Set([
1470    ...getCollectionSet(customComponentName, storageLinkCollection),
1471    ...getCollectionSet(customComponentName, storagePropCollection),
1472    ...getCollectionSet(customComponentName, consumeCollection)
1473  ]);
1474  const localStorageSet: Set<string> = new Set();
1475  getLocalStorageCollection(customComponentName, localStorageSet);
1476  if (isThisProperty(node, forbiddenToInitViaParamSet) || isThisProperty(node, localStorageSet)) {
1477    const nodeIdentifier: ts.Identifier = node.name as ts.Identifier;
1478    const propType: string = getForbbiddenToInitViaParamType(customComponentName, nodeIdentifier);
1479    log.push({
1480      type: LogType.ERROR,
1481      message: `The '${propType}' property '${node.name.getText()}' in the custom component '${customComponentName}'` +
1482        ` cannot be initialized here (forbidden to specify).`,
1483      pos: node.name.getStart(),
1484      code: '10905317'
1485    });
1486  }
1487}
1488
1489function validateMandatoryToInitViaParam(node: ts.CallExpression, customComponentName: string,
1490  curChildProps: Set<string>, log: LogInfo[], parentStructInfo: StructInfo): void {
1491  let mandatoryToInitViaParamSet: Set<string>;
1492  if (projectConfig.compileMode === 'esmodule' && process.env.compileTool === 'rollup' && node.expression) {
1493    const overAll: string[] = [
1494      ...getCollectionSet(node.expression.getText(), storedFileInfo.overallObjectLinkCollection)];
1495    if (!parentStructInfo.isComponentV2) {
1496      overAll.unshift(...getCollectionSet(node.expression.getText(), storedFileInfo.overallLinkCollection));
1497    }
1498    mandatoryToInitViaParamSet = new Set(overAll);
1499    customComponentName = node.expression.getText();
1500  } else {
1501    const arr: string[] = [...getCollectionSet(customComponentName, objectLinkCollection)];
1502    if (!parentStructInfo.isComponentV2) {
1503      arr.unshift(...getCollectionSet(customComponentName, linkCollection));
1504    }
1505    mandatoryToInitViaParamSet = new Set(arr);
1506  }
1507  mandatoryToInitViaParamSet.forEach(item => {
1508    if (item && !curChildProps.has(item)) {
1509      log.push({
1510        type: LogType.ERROR,
1511        message: `The property '${item}' in the custom component '${customComponentName}'` +
1512          ` is missing (mandatory to specify).`,
1513        pos: node.getStart(),
1514        code: '10905316'
1515      });
1516    }
1517  });
1518}
1519
1520function validateInitDecorator(node: ts.CallExpression, customComponentName: string,
1521  curChildProps: Set<string>, log: LogInfo[]): void {
1522  const mandatoryToInitViaParamSet: Set<string> = new Set([
1523    ...getCollectionSet(customComponentName, builderParamObjectCollection),
1524    ...getCollectionSet(customComponentName, propCollection),
1525    ...getCollectionSet(customComponentName, regularCollection),
1526    ...getCollectionSet(customComponentName, stateCollection),
1527    ...getCollectionSet(customComponentName, provideCollection)
1528  ]);
1529  const decoratorVariable: Set<string> = new Set([
1530    ...(builderParamInitialization.get(customComponentName) || []),
1531    ...(propInitialization.get(customComponentName) || []),
1532    ...(regularInitialization.get(customComponentName) || []),
1533    ...(stateInitialization.get(customComponentName) || []),
1534    ...(provideInitialization.get(customComponentName) || [])
1535  ]);
1536  mandatoryToInitViaParamSet.forEach((item: string) => {
1537    if (item && !curChildProps.has(item) && decoratorVariable && decoratorVariable.has(item)) {
1538      log.push({
1539        type: LogType.ERROR,
1540        message: `'@Require' decorated '${item}' must be initialized through the component constructor.`,
1541        pos: node.getStart(),
1542        code: '10905359'
1543      });
1544    }
1545  });
1546  const privateParamSet: Set<string> = privateCollection.get(customComponentName) || new Set([]);
1547  curChildProps.forEach((item: string) => {
1548    if (privateParamSet.has(item)) {
1549      log.push({
1550        type: LogType.WARN,
1551        message: `Property '${item}' is private and can not be initialized through the component constructor.`,
1552        pos: node.getStart()
1553      });
1554    }
1555  });
1556}
1557
1558function validateIllegalInitFromParent(node: ts.ObjectLiteralElementLike, propertyName: string,
1559  curPropertyKind: string, parentPropertyName: string, parentPropertyKind: string,
1560  log: LogInfo[], inputType: LogType = undefined): void {
1561  let type: LogType = LogType.ERROR;
1562  if (inputType) {
1563    type = inputType;
1564  } else if ([COMPONENT_STATE_DECORATOR, COMPONENT_OBJECT_LINK_DECORATOR].includes(
1565    parentPropertyKind) && curPropertyKind === COMPONENT_OBJECT_LINK_DECORATOR) {
1566    type = LogType.WARN;
1567  }
1568  PropMapManager.reserveLog(parentPropertyName, parentPropertyKind, {
1569    type: type,
1570    message: `The '${parentPropertyKind}' property '${parentPropertyName}' cannot be assigned to ` +
1571      `the '${curPropertyKind}' property '${propertyName}'.`,
1572    // @ts-ignore
1573    pos: node.initializer ? node.initializer.getStart() : node.getStart(),
1574    code: type === LogType.ERROR ? '10905315' : undefined
1575  });
1576}
1577
1578function validateNonLinkWithDollar(node: ts.PropertyAssignment, log: LogInfo[]): void {
1579  log.push({
1580    type: LogType.ERROR,
1581    message: `Property '${node.name.getText()}' cannot initialize` +
1582      ` using '$' to create a reference to a variable.`,
1583    pos: node.initializer.getStart(),
1584    code: '10905314'
1585  });
1586}
1587