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