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