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'; 17const path = require('path'); 18 19import { 20 INNER_COMPONENT_MEMBER_DECORATORS, 21 COMPONENT_NON_DECORATOR, 22 COMPONENT_STATE_DECORATOR, 23 COMPONENT_PROP_DECORATOR, 24 COMPONENT_LINK_DECORATOR, 25 COMPONENT_STORAGE_PROP_DECORATOR, 26 COMPONENT_STORAGE_LINK_DECORATOR, 27 COMPONENT_PROVIDE_DECORATOR, 28 COMPONENT_CONSUME_DECORATOR, 29 COMPONENT_OBJECT_LINK_DECORATOR, 30 COMPONENT_WATCH_DECORATOR, 31 COMPONENT_OBSERVED_DECORATOR, 32 OBSERVED_PROPERTY_SIMPLE, 33 OBSERVED_PROPERTY_OBJECT, 34 SYNCHED_PROPERTY_SIMPLE_ONE_WAY, 35 SYNCHED_PROPERTY_SIMPLE_TWO_WAY, 36 SYNCHED_PROPERTY_OBJECT_TWO_WAY, 37 SYNCHED_PROPERTY_NESED_OBJECT, 38 CREATE_GET_METHOD, 39 CREATE_SET_METHOD, 40 CREATE_NEWVALUE_IDENTIFIER, 41 CREATE_CONSTRUCTOR_PARAMS, 42 ADD_PROVIDED_VAR, 43 INITIALIZE_CONSUME_FUNCTION, 44 APP_STORAGE, 45 APP_STORAGE_SET_AND_PROP, 46 APP_STORAGE_SET_AND_LINK, 47 COMPONENT_CONSTRUCTOR_UNDEFINED, 48 SET_CONTROLLER_METHOD, 49 SET_CONTROLLER_CTR, 50 SET_CONTROLLER_CTR_TYPE, 51 BASE_COMPONENT_NAME, 52 COMPONENT_CREATE_FUNCTION, 53 COMPONENT_BUILDERPARAM_DECORATOR, 54 COMPONENT_LOCAL_STORAGE_LINK_DECORATOR, 55 COMPONENT_LOCAL_STORAGE_PROP_DECORATOR, 56 EXTNAME_ETS, 57 _GENERATE_ID, 58 RMELMTID, 59 PURGEDEPENDENCYONELMTID, 60 BASICDECORATORS, 61 BASE_COMPONENT_NAME_PU, 62 OBSERVED_PROPERTY_SIMPLE_PU, 63 OBSERVED_PROPERTY_OBJECT_PU, 64 SYNCHED_PROPERTY_SIMPLE_TWO_WAY_PU, 65 SYNCHED_PROPERTY_OBJECT_TWO_WAY_PU, 66 SYNCHED_PROPERTY_SIMPLE_ONE_WAY_PU, 67 SYNCHED_PROPERTY_OBJECT_ONE_WAY_PU, 68 SYNCHED_PROPERTY_NESED_OBJECT_PU, 69 COMPONENT_CUSTOM_DECORATOR, 70 THIS, 71 CREATE_STORAGE_LINK, 72 CREATE_STORAGE_PROP, 73 ELMTID, 74 COMPONENT_CONSTRUCTOR_PARAMS, 75 RESERT, 76 COMPONENT_IF_UNDEFINED, 77 COMPONENT_PARAMS_LAMBDA_FUNCTION, 78 OBSERVED, 79 COMPONENT_REQUIRE_DECORATOR, 80 TRUE, 81 FALSE 82} from './pre_define'; 83import { 84 forbiddenUseStateType, 85 BUILDIN_STYLE_NAMES 86} from './component_map'; 87import { 88 observedClassCollection, 89 enumCollection, 90 componentCollection, 91 classMethodCollection 92} from './validate_ui_syntax'; 93import { updateConstructor } from './process_component_constructor'; 94import { 95 LogType, 96 LogInfo, 97 componentInfo, 98 storedFileInfo 99} from './utils'; 100import { 101 createReference, 102 isProperty, 103 isRegularProperty 104} from './process_component_class'; 105import { transformLog, resourceFileName } from './process_ui_syntax'; 106import { 107 globalProgram, 108 projectConfig, 109 partialUpdateConfig 110} from '../main'; 111import { 112 parentConditionalExpression, 113 createFunction, 114 getRealNodePos, 115 isWrappedBuilder 116} from './process_component_build'; 117import { 118 CUSTOM_BUILDER_METHOD, 119 INNER_CUSTOM_LOCALBUILDER_METHOD 120} from './component_map'; 121 122export type ControllerType = { 123 hasController: boolean 124}; 125 126export const observedPropertyDecorators: Set<string> = 127 new Set([COMPONENT_STATE_DECORATOR, COMPONENT_PROVIDE_DECORATOR]); 128 129export const propAndLinkDecorators: Set<string> = 130 new Set([COMPONENT_PROP_DECORATOR, COMPONENT_LINK_DECORATOR]); 131 132export const appStorageDecorators: Set<string> = 133 new Set([COMPONENT_STORAGE_PROP_DECORATOR, COMPONENT_STORAGE_LINK_DECORATOR, 134 COMPONENT_LOCAL_STORAGE_LINK_DECORATOR, COMPONENT_LOCAL_STORAGE_PROP_DECORATOR]); 135 136export const mandatorySpecifyDefaultValueDecorators: Set<string> = 137 new Set([...observedPropertyDecorators, ...appStorageDecorators]); 138 139export const forbiddenSpecifyDefaultValueDecorators: Set<string> = 140 new Set([COMPONENT_LINK_DECORATOR, COMPONENT_CONSUME_DECORATOR, COMPONENT_OBJECT_LINK_DECORATOR]); 141 142export const mandatoryToInitViaParamDecorators: Set<string> = 143 new Set([...propAndLinkDecorators, COMPONENT_OBJECT_LINK_DECORATOR]); 144 145export const setUpdateParamsDecorators: Set<string> = 146 new Set([...observedPropertyDecorators, COMPONENT_PROP_DECORATOR, COMPONENT_OBJECT_LINK_DECORATOR, 147 COMPONENT_BUILDERPARAM_DECORATOR 148 ]); 149 150export const setStateVarsDecorators: Set<string> = new Set([COMPONENT_OBJECT_LINK_DECORATOR]); 151 152export const immutableDecorators: Set<string> = 153 new Set([COMPONENT_OBJECT_LINK_DECORATOR, COMPONENT_BUILDERPARAM_DECORATOR]); 154 155export const simpleTypes: Set<ts.SyntaxKind> = new Set([ts.SyntaxKind.StringKeyword, 156 ts.SyntaxKind.NumberKeyword, ts.SyntaxKind.BooleanKeyword, ts.SyntaxKind.EnumDeclaration]); 157 158export const decoratorParamSet: Set<string> = new Set(); 159 160export const stateObjectCollection: Set<string> = new Set(); 161 162export class UpdateResult { 163 private itemUpdate: boolean = false; 164 private ctorUpdate: boolean = false; 165 private properity: ts.PropertyDeclaration; 166 private ctor: ts.ConstructorDeclaration; 167 private variableGet: ts.GetAccessorDeclaration; 168 private variableSet: ts.SetAccessorDeclaration; 169 private updateParams: ts.Statement; 170 private deleteParams: boolean = false; 171 private controllerSet: ts.MethodDeclaration; 172 private purgeVariableDepStatement: ts.Statement; 173 private decoratorName: string; 174 private stateVarsParams: ts.Statement; 175 176 public setProperity(updateItem: ts.PropertyDeclaration) { 177 this.itemUpdate = true; 178 this.properity = updateItem; 179 } 180 181 public setCtor(updateCtor: ts.ConstructorDeclaration) { 182 this.ctorUpdate = true; 183 this.ctor = updateCtor; 184 } 185 186 public setControllerSet(updateControllerSet: ts.MethodDeclaration) { 187 this.controllerSet = updateControllerSet; 188 } 189 190 public getControllerSet(): ts.MethodDeclaration { 191 return this.controllerSet; 192 } 193 194 public setVariableGet(updateVariableGet: ts.GetAccessorDeclaration) { 195 this.variableGet = updateVariableGet; 196 } 197 198 public setVariableSet(updateVariableSet: ts.SetAccessorDeclaration) { 199 this.variableSet = updateVariableSet; 200 } 201 202 public setUpdateParams(updateParams: ts.Statement) { 203 this.updateParams = updateParams; 204 } 205 206 public setStateVarsParams(stateVarsParams: ts.Statement) { 207 this.stateVarsParams = stateVarsParams; 208 } 209 210 public setDeleteParams(deleteParams: boolean) { 211 this.deleteParams = deleteParams; 212 } 213 214 public setPurgeVariableDepStatement(purgeVariableDepStatement: ts.Statement) { 215 this.purgeVariableDepStatement = purgeVariableDepStatement; 216 } 217 218 public setDecoratorName(decoratorName: string) { 219 this.decoratorName = decoratorName; 220 } 221 222 public isItemUpdate(): boolean { 223 return this.itemUpdate; 224 } 225 226 public isCtorUpdate(): boolean { 227 return this.ctorUpdate; 228 } 229 230 public getProperity(): ts.PropertyDeclaration { 231 return this.properity; 232 } 233 234 public getCtor(): ts.ConstructorDeclaration { 235 return this.ctor; 236 } 237 238 public getUpdateParams(): ts.Statement { 239 return this.updateParams; 240 } 241 242 public getStateVarsParams(): ts.Statement { 243 return this.stateVarsParams; 244 } 245 246 public getPurgeVariableDepStatement(): ts.Statement { 247 return this.purgeVariableDepStatement; 248 } 249 250 public getVariableGet(): ts.GetAccessorDeclaration { 251 return this.variableGet; 252 } 253 254 public getVariableSet(): ts.SetAccessorDeclaration { 255 return this.variableSet; 256 } 257 258 public getDecoratorName(): string { 259 return this.decoratorName; 260 } 261 262 public isDeleteParams(): boolean { 263 return this.deleteParams; 264 } 265} 266 267export const curPropMap: Map<string, string> = new Map(); 268 269export function processMemberVariableDecorators(parentName: ts.Identifier, 270 item: ts.PropertyDeclaration, ctorNode: ts.ConstructorDeclaration, watchMap: Map<string, ts.Node>, 271 checkController: ControllerType, log: LogInfo[], program: ts.Program, context: ts.TransformationContext, 272 hasPreview: boolean, interfaceNode: ts.InterfaceDeclaration): UpdateResult { 273 const updateResult: UpdateResult = new UpdateResult(); 274 const name: ts.Identifier = item.name as ts.Identifier; 275 const decorators: readonly ts.Decorator[] = ts.getAllDecorators(item); 276 if (isRegularProperty(decorators)) { 277 if (!name.escapedText) { 278 return updateResult; 279 } 280 curPropMap.set(name.escapedText.toString(), COMPONENT_NON_DECORATOR); 281 updateResult.setProperity(undefined); 282 updateResult.setUpdateParams(createUpdateParams(name, COMPONENT_NON_DECORATOR)); 283 updateResult.setCtor(updateConstructor(ctorNode, [], [ 284 createVariableInitStatement(item, COMPONENT_NON_DECORATOR, log, program, context, hasPreview, 285 interfaceNode)], [])); 286 updateResult.setControllerSet(createControllerSet(item, parentName, name, checkController)); 287 if (partialUpdateConfig.partialUpdateMode) { 288 updateResult.setDeleteParams(true); 289 } 290 } else if (!item.type) { 291 validatePropertyNonType(name, log); 292 return updateResult; 293 } else if (validateCustomDecorator(decorators, log)) { 294 updateResult.setUpdateParams(createUpdateParams(name, COMPONENT_CUSTOM_DECORATOR)); 295 } else { 296 processPropertyNodeDecorator(parentName, item, updateResult, ctorNode, name, watchMap, 297 log, program, context, hasPreview, interfaceNode); 298 } 299 if (decorators && decorators.length && validatePropDecorator(decorators)) { 300 updateResult.setStateVarsParams(createStateVarsBody(name)); 301 } 302 return updateResult; 303} 304 305function createStateVarsBody(name: ts.Identifier): ts.ExpressionStatement { 306 return ts.factory.createExpressionStatement(ts.factory.createCallExpression( 307 ts.factory.createPropertyAccessExpression( 308 ts.factory.createPropertyAccessExpression( 309 ts.factory.createThis(), 310 ts.factory.createIdentifier('__' + name.escapedText.toString()) 311 ), 312 ts.factory.createIdentifier(RESERT) 313 ), 314 undefined, 315 [ts.factory.createPropertyAccessExpression( 316 ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARAMS), 317 name 318 )] 319 )); 320} 321 322function createControllerSet(node: ts.PropertyDeclaration, componentName: ts.Identifier, 323 name: ts.Identifier, checkController: ControllerType): ts.MethodDeclaration { 324 if (componentCollection.customDialogs.has(componentName.getText()) && node.type && 325 node.type.getText() === SET_CONTROLLER_CTR_TYPE) { 326 checkController.hasController = true; 327 return ts.factory.createMethodDeclaration(undefined, undefined, 328 ts.factory.createIdentifier(SET_CONTROLLER_METHOD), undefined, undefined, 329 [ts.factory.createParameterDeclaration(undefined, undefined, 330 ts.factory.createIdentifier(SET_CONTROLLER_CTR), undefined, 331 ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(SET_CONTROLLER_CTR_TYPE), 332 undefined), undefined)], undefined, ts.factory.createBlock( 333 [ts.factory.createExpressionStatement(ts.factory.createBinaryExpression( 334 ts.factory.createPropertyAccessExpression(ts.factory.createThis(), name), 335 ts.factory.createToken(ts.SyntaxKind.EqualsToken), 336 ts.factory.createIdentifier(SET_CONTROLLER_CTR)))], true)); 337 } 338 return undefined; 339} 340 341function processPropertyNodeDecorator(parentName: ts.Identifier, node: ts.PropertyDeclaration, 342 updateResult: UpdateResult, ctorNode: ts.ConstructorDeclaration, name: ts.Identifier, 343 watchMap: Map<string, ts.Node>, log: LogInfo[], program: ts.Program, 344 context: ts.TransformationContext, hasPreview: boolean, interfaceNode: ts.InterfaceDeclaration): void { 345 const decorators: readonly ts.Decorator[] = ts.getAllDecorators(node); 346 const propertyDecorators: string[] = []; 347 for (let i = 0; i < decorators.length; i++) { 348 const decoratorName: string = decorators[i].getText().replace(/\(.*\)$/, '').trim(); 349 const includeWatchAndRequire: boolean = 350 [COMPONENT_WATCH_DECORATOR, COMPONENT_REQUIRE_DECORATOR].includes(decoratorName); 351 if (!includeWatchAndRequire) { 352 curPropMap.set(name.escapedText.toString(), decoratorName); 353 } 354 if (BUILDIN_STYLE_NAMES.has(decoratorName.replace('@', ''))) { 355 validateDuplicateDecorator(decorators[i], log); 356 } 357 if (!includeWatchAndRequire && isForbiddenUseStateType(node.type)) { 358 // @ts-ignore 359 validateForbiddenUseStateType(name, decoratorName, node.type.typeName.getText(), log); 360 return; 361 } 362 if (parentName.getText() === componentCollection.entryComponent && 363 mandatoryToInitViaParamDecorators.has(decoratorName)) { 364 validateHasIllegalDecoratorInEntry(parentName, name, decoratorName, log); 365 } 366 if (node.initializer && forbiddenSpecifyDefaultValueDecorators.has(decoratorName)) { 367 validatePropertyDefaultValue(name, decoratorName, log); 368 return; 369 } else if (!node.initializer && mandatorySpecifyDefaultValueDecorators.has(decoratorName)) { 370 validatePropertyNonDefaultValue(name, decoratorName, log); 371 return; 372 } 373 if (node.questionToken && mandatoryToInitViaParamDecorators.has(decoratorName) && !(decoratorName === COMPONENT_PROP_DECORATOR && node.initializer)) { 374 validateHasIllegalQuestionToken(name, decoratorName, log); 375 } 376 if (!isSimpleType(node.type, program) && 377 decoratorName !== COMPONENT_BUILDERPARAM_DECORATOR) { 378 stateObjectCollection.add(name.escapedText.toString()); 379 } 380 if (decoratorName === COMPONENT_WATCH_DECORATOR && 381 validateWatchDecorator(name, decorators, log)) { 382 processWatch(node, decorators[i], watchMap, log); 383 } else if (INNER_COMPONENT_MEMBER_DECORATORS.has(decoratorName)) { 384 propertyDecorators.push(decoratorName); 385 if (decoratorName !== COMPONENT_REQUIRE_DECORATOR) { 386 processStateDecorators(node, decoratorName, updateResult, ctorNode, log, program, context, 387 hasPreview, interfaceNode); 388 } 389 } 390 } 391 validatePropertyDecorator(propertyDecorators, name, log); 392} 393 394function validatePropertyDecorator(propertyDecorators: string[], name: ts.Identifier, 395 log: LogInfo[]): void { 396 if (propertyDecorators.length > 1 && !validateRequireDecorator(propertyDecorators)) { 397 validateMultiDecorators(name, log); 398 } 399} 400 401const DECORATOR_LENGTH: number = 2; 402const SUPPORT_REQUIRE_DECORATOR: string[] = [COMPONENT_PROP_DECORATOR, 403 COMPONENT_BUILDERPARAM_DECORATOR, COMPONENT_STATE_DECORATOR, COMPONENT_PROVIDE_DECORATOR, 404 COMPONENT_WATCH_DECORATOR 405]; 406 407function validateRequireDecorator(propertyDecorators: string[]): boolean { 408 const isSupportRequire: boolean = propertyDecorators.some((item: string) => { 409 return SUPPORT_REQUIRE_DECORATOR.includes(item); 410 }); 411 return propertyDecorators.length === DECORATOR_LENGTH && 412 propertyDecorators.includes(COMPONENT_REQUIRE_DECORATOR) && isSupportRequire; 413} 414 415function processStateDecorators(node: ts.PropertyDeclaration, decorator: string, 416 updateResult: UpdateResult, ctorNode: ts.ConstructorDeclaration, log: LogInfo[], 417 program: ts.Program, context: ts.TransformationContext, hasPreview:boolean, 418 interfaceNode: ts.InterfaceDeclaration): void { 419 const name: ts.Identifier = node.name as ts.Identifier; 420 updateResult.setProperity(undefined); 421 const updateState: ts.Statement[] = []; 422 const variableInitStatement: ts.Statement = 423 createVariableInitStatement(node, decorator, log, program, context, hasPreview, interfaceNode); 424 if (variableInitStatement) { 425 updateState.push(variableInitStatement); 426 } 427 addAddProvidedVar(node, name, decorator, updateState); 428 updateResult.setCtor(updateConstructor(ctorNode, [], [...updateState], [], false)); 429 if (decorator !== COMPONENT_BUILDERPARAM_DECORATOR) { 430 updateResult.setVariableGet(createGetAccessor(name, CREATE_GET_METHOD)); 431 updateResult.setDeleteParams(true); 432 } 433 if (!immutableDecorators.has(decorator)) { 434 updateResult.setVariableSet(createSetAccessor(name, CREATE_SET_METHOD, node.type)); 435 } 436 if (setUpdateParamsDecorators.has(decorator)) { 437 updateResult.setUpdateParams(createUpdateParams(name, decorator, node)); 438 } 439 if (projectConfig.optLazyForEach) { 440 setStateVarsDecorators.add(COMPONENT_STATE_DECORATOR); 441 } 442 if (setStateVarsDecorators.has(decorator)) { 443 updateResult.setStateVarsParams(createStateVarsParams(name, decorator)); 444 } 445 if (partialUpdateConfig.partialUpdateMode && BASICDECORATORS.has(decorator)) { 446 const variableWithUnderLink: string = '__' + name.escapedText.toString(); 447 updateResult.setDecoratorName(decorator); 448 updateResult.setPurgeVariableDepStatement(createPurgeVariableDepStatement(variableWithUnderLink)); 449 } 450} 451 452function createPurgeVariableDepStatement(variableWithUnderLink: string): ts.Statement { 453 return ts.factory.createExpressionStatement( 454 ts.factory.createCallExpression( 455 ts.factory.createPropertyAccessExpression( 456 ts.factory.createPropertyAccessExpression( 457 ts.factory.createThis(), 458 ts.factory.createIdentifier(variableWithUnderLink) 459 ), 460 ts.factory.createIdentifier(PURGEDEPENDENCYONELMTID) 461 ), 462 undefined, 463 [ts.factory.createIdentifier(RMELMTID)] 464 ) 465 ); 466} 467 468function processWatch(node: ts.PropertyDeclaration, decorator: ts.Decorator, 469 watchMap: Map<string, ts.Node>, log: LogInfo[]): void { 470 if (node.name) { 471 const propertyName: string = node.name.getText(); 472 if (decorator.expression && ts.isCallExpression(decorator.expression) && 473 decorator.expression.arguments && decorator.expression.arguments.length === 1) { 474 const currentClassMethod: Set<string> = getClassMethod(node); 475 const argument: ts.Node = decorator.expression.arguments[0]; 476 if (ts.isStringLiteral(argument)) { 477 if (currentClassMethod && currentClassMethod.has(argument.text)) { 478 watchMap.set(propertyName, argument); 479 } else { 480 log.push({ 481 type: LogType.ERROR, 482 message: `Cannot find name ${argument.getText()} in struct '${node.parent.name.getText()}'.`, 483 pos: argument.getStart() 484 }); 485 } 486 } else if (ts.isIdentifier(decorator.expression.arguments[0])) { 487 const content: string = decorator.expression.arguments[0].getText(); 488 const propertyNode: ts.PropertyAccessExpression = createPropertyAccessExpressionWithThis(content); 489 watchMap.set(propertyName, propertyNode); 490 decoratorParamSet.add(content); 491 validateWatchParam(LogType.WARN, argument.getStart(), log); 492 } else if (ts.isPropertyAccessExpression(decorator.expression.arguments[0])) { 493 watchMap.set(propertyName, decorator.expression.arguments[0]); 494 validateWatchParam(LogType.WARN, argument.getStart(), log); 495 } else { 496 validateWatchParam(LogType.ERROR, argument.getStart(), log); 497 } 498 } 499 } 500} 501 502function getClassMethod(node: ts.PropertyDeclaration): Set<string> { 503 const sourceFile: ts.SourceFile = node.getSourceFile(); 504 const filePath: string = sourceFile ? sourceFile.fileName : undefined; 505 if (filePath && classMethodCollection.get(filePath)) { 506 return classMethodCollection.get(filePath).get(node.parent.name.getText()); 507 } 508 return new Set(); 509} 510 511function createVariableInitStatement(node: ts.PropertyDeclaration, decorator: string, 512 log: LogInfo[], program: ts.Program, context: ts.TransformationContext, hasPreview: boolean, 513 interfaceNode: ts.InterfaceDeclaration): ts.Statement { 514 const name: ts.Identifier = node.name as ts.Identifier; 515 let type: ts.TypeNode; 516 let updateState: ts.ExpressionStatement; 517 if (node.type) { 518 type = node.type; 519 } 520 switch (decorator) { 521 case COMPONENT_NON_DECORATOR: 522 updateState = updateNormalProperty(node, name, log, context); 523 break; 524 case COMPONENT_STATE_DECORATOR: 525 case COMPONENT_PROVIDE_DECORATOR: 526 updateState = !partialUpdateConfig.partialUpdateMode ? 527 updateObservedProperty(node, name, type, program) : updateObservedPropertyPU(node, name, type, program); 528 break; 529 case COMPONENT_LINK_DECORATOR: 530 wrongDecoratorInPreview(node, COMPONENT_LINK_DECORATOR, hasPreview, log); 531 updateState = !partialUpdateConfig.partialUpdateMode ? 532 updateSynchedPropertyTwoWay(name, type, program) : updateSynchedPropertyTwoWayPU(name, type, program); 533 break; 534 case COMPONENT_PROP_DECORATOR: 535 wrongDecoratorInPreview(node, COMPONENT_PROP_DECORATOR, hasPreview, log); 536 updateState = !partialUpdateConfig.partialUpdateMode ? 537 updateSynchedPropertyOneWay(name, type, decorator, log, program) : 538 updateSynchedPropertyOneWayPU(name, type, decorator, log, program); 539 break; 540 case COMPONENT_STORAGE_PROP_DECORATOR: 541 case COMPONENT_STORAGE_LINK_DECORATOR: 542 updateState = updateStoragePropAndLinkProperty(node, name, decorator); 543 break; 544 case COMPONENT_OBJECT_LINK_DECORATOR: 545 updateState = !partialUpdateConfig.partialUpdateMode ? 546 updateSynchedPropertyNesedObject(name, type, decorator, log) : 547 updateSynchedPropertyNesedObjectPU(name, type, decorator, log); 548 break; 549 case COMPONENT_CONSUME_DECORATOR: 550 wrongDecoratorInPreview(node, COMPONENT_CONSUME_DECORATOR, hasPreview, log); 551 updateState = updateConsumeProperty(node, name); 552 break; 553 case COMPONENT_BUILDERPARAM_DECORATOR: 554 updateState = updateBuilderParamProperty(node, name, log); 555 } 556 const members = interfaceNode.members; 557 members.push(ts.factory.createPropertySignature(undefined, name, 558 ts.factory.createToken(ts.SyntaxKind.QuestionToken), type)); 559 interfaceNode = ts.factory.updateInterfaceDeclaration(interfaceNode, 560 ts.getModifiers(interfaceNode), interfaceNode.name, interfaceNode.typeParameters, 561 interfaceNode.heritageClauses, members); 562 return updateState; 563} 564 565function wrongDecoratorInPreview(node: ts.PropertyDeclaration, decorator: string, 566 hasPreview: boolean, log: LogInfo[]): void { 567 if (hasPreview && projectConfig.isPreview) { 568 log.push({ 569 type: LogType.WARN, 570 message: `The variable with ${decorator} in component with @Preview may ` + 571 `cause error in component preview mode`, 572 pos: node.getStart() 573 }); 574 } 575} 576 577function createUpdateParams(name: ts.Identifier, decorator: string, 578 localInitializationNode: ts.PropertyDeclaration = undefined): ts.Statement { 579 let updateParamsNode: ts.Statement; 580 switch (decorator) { 581 case COMPONENT_NON_DECORATOR: 582 case COMPONENT_STATE_DECORATOR: 583 case COMPONENT_PROVIDE_DECORATOR: 584 case COMPONENT_CUSTOM_DECORATOR: 585 updateParamsNode = createUpdateParamsWithIf(name); 586 break; 587 case COMPONENT_PROP_DECORATOR: 588 if (!partialUpdateConfig.partialUpdateMode) { 589 updateParamsNode = createUpdateParamsWithoutIf(name); 590 } else { 591 if (localInitializationNode && localInitializationNode.initializer) { 592 updateParamsNode = createUpdateParamsWithIf(name, true, 593 localInitializationNode.initializer); 594 } 595 } 596 break; 597 case COMPONENT_BUILDERPARAM_DECORATOR: 598 updateParamsNode = createUpdateParamsWithIf(name); 599 break; 600 case COMPONENT_OBJECT_LINK_DECORATOR: 601 updateParamsNode = createUpdateParamsWithSet(name); 602 break; 603 } 604 return updateParamsNode; 605} 606 607function createStateVarsParams(name: ts.Identifier, decorator: string): ts.Statement { 608 let updateParamsNode: ts.Statement; 609 switch (decorator) { 610 case COMPONENT_OBJECT_LINK_DECORATOR: 611 updateParamsNode = createUpdateParamsWithSet(name); 612 break; 613 case COMPONENT_STATE_DECORATOR: 614 updateParamsNode = createUpdateParamsForState(name); 615 break; 616 } 617 return updateParamsNode; 618} 619 620function createUpdateParamsWithIf(name: ts.Identifier, isProp: boolean = false, 621 initializeNode: ts.Expression = undefined): ts.IfStatement { 622 return ts.factory.createIfStatement(ts.factory.createBinaryExpression( 623 ts.factory.createPropertyAccessExpression( 624 ts.factory.createIdentifier(CREATE_CONSTRUCTOR_PARAMS), 625 ts.factory.createIdentifier(name.escapedText.toString())), 626 isProp ? ts.factory.createToken(ts.SyntaxKind.EqualsEqualsEqualsToken) : 627 ts.factory.createToken(ts.SyntaxKind.ExclamationEqualsEqualsToken), 628 ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED)), 629 isProp ? ts.factory.createBlock([createUpdateParamsWithSet(name, true, initializeNode)]) : 630 ts.factory.createBlock([ 631 createUpdateParamsWithoutIf(name)], true), undefined); 632} 633 634function createUpdateParamsForState(name: ts.Identifier): ts.IfStatement { 635 return ts.factory.createIfStatement(createPropertyAccessExpressionWithParams(name.getText()), 636 ts.factory.createBlock([createUpdateParamsWithSet(name)])); 637} 638 639function createUpdateParamsWithoutIf(name: ts.Identifier): ts.ExpressionStatement { 640 return ts.factory.createExpressionStatement(ts.factory.createBinaryExpression( 641 createPropertyAccessExpressionWithThis(name.getText()), 642 ts.factory.createToken(ts.SyntaxKind.EqualsToken), 643 createPropertyAccessExpressionWithParams(name.getText()))); 644} 645 646function createUpdateParamsWithSet(name: ts.Identifier, hasElse: boolean = false, 647 initializeNode: ts.Expression = undefined): ts.ExpressionStatement { 648 return ts.factory.createExpressionStatement(ts.factory.createCallExpression( 649 ts.factory.createPropertyAccessExpression(createPropertyAccessExpressionWithThis(`__${name.getText()}`), 650 ts.factory.createIdentifier(CREATE_SET_METHOD)), undefined, 651 [hasElse ? initializeNode : createPropertyAccessExpressionWithParams(name.getText())])); 652} 653 654function updateNormalProperty(node: ts.PropertyDeclaration, name: ts.Identifier, 655 log: LogInfo[], context: ts.TransformationContext): ts.ExpressionStatement { 656 const init: ts.Expression = 657 ts.visitNode(node.initializer, visitDialogController); 658 function visitDialogController(node: ts.Node): ts.Node { 659 if (isProperty(node)) { 660 node = createReference(node as ts.PropertyAssignment, log); 661 } 662 return ts.visitEachChild(node, visitDialogController, context); 663 } 664 return ts.factory.createExpressionStatement(ts.factory.createBinaryExpression( 665 createPropertyAccessExpressionWithThis(name.getText()), 666 ts.factory.createToken(ts.SyntaxKind.EqualsToken), init || 667 ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED))); 668} 669 670function updateObservedProperty(item: ts.PropertyDeclaration, name: ts.Identifier, 671 type: ts.TypeNode, program: ts.Program): ts.ExpressionStatement { 672 return ts.factory.createExpressionStatement(ts.factory.createBinaryExpression( 673 createPropertyAccessExpressionWithThis(`__${name.getText()}`), 674 ts.factory.createToken(ts.SyntaxKind.EqualsToken), ts.factory.createNewExpression( 675 ts.factory.createIdentifier(isSimpleType(type, program) ? OBSERVED_PROPERTY_SIMPLE : 676 OBSERVED_PROPERTY_OBJECT), undefined, [item.initializer, ts.factory.createThis(), 677 ts.factory.createStringLiteral(name.escapedText.toString())]))); 678} 679 680function updateSynchedPropertyTwoWay(nameIdentifier: ts.Identifier, type: ts.TypeNode, 681 program: ts.Program): ts.ExpressionStatement { 682 const name: string = nameIdentifier.escapedText.toString(); 683 const functionName: string = isSimpleType(type, program) ? 684 SYNCHED_PROPERTY_SIMPLE_TWO_WAY : SYNCHED_PROPERTY_OBJECT_TWO_WAY; 685 return createInitExpressionStatementForDecorator(name, functionName, 686 createPropertyAccessExpressionWithParams(name)); 687} 688 689function updateSynchedPropertyOneWay(nameIdentifier: ts.Identifier, type: ts.TypeNode, 690 decoractor: string, log: LogInfo[], program: ts.Program): ts.ExpressionStatement { 691 const name: string = nameIdentifier.escapedText.toString(); 692 if (isSimpleType(type, program)) { 693 return createInitExpressionStatementForDecorator(name, SYNCHED_PROPERTY_SIMPLE_ONE_WAY, 694 createPropertyAccessExpressionWithParams(name)); 695 } else { 696 validateNonSimpleType(nameIdentifier, decoractor, log); 697 return undefined; 698 } 699} 700 701export function findDecoratorIndex(decorators: readonly ts.Decorator[], nameList: string[]): number { 702 return decorators.findIndex((item: ts.Decorator) => { 703 return nameList.includes(item.getText().replace(/\(.*\)$/, '').trim()); 704 }); 705} 706 707function updateStoragePropAndLinkProperty(node: ts.PropertyDeclaration, name: ts.Identifier, 708 decorator: string): ts.ExpressionStatement { 709 const decorators: readonly ts.Decorator[] = ts.getAllDecorators(node); 710 if (isSingleKey(node)) { 711 let setFuncName: string; 712 let storageFuncName: string; 713 const index: number = findDecoratorIndex(decorators, [decorator]); 714 const storageValue: ts.Expression[] = [ 715 decorators[index].expression.arguments[0], 716 node.initializer, 717 ts.factory.createThis(), 718 ts.factory.createStringLiteral(name.getText()) 719 ]; 720 if (!partialUpdateConfig.partialUpdateMode) { 721 setFuncName = decorator === COMPONENT_STORAGE_PROP_DECORATOR ? 722 APP_STORAGE_SET_AND_PROP : APP_STORAGE_SET_AND_LINK; 723 storageFuncName = APP_STORAGE; 724 } else { 725 setFuncName = decorator === COMPONENT_STORAGE_PROP_DECORATOR ? 726 CREATE_STORAGE_PROP : CREATE_STORAGE_LINK; 727 storageFuncName = THIS; 728 storageValue.splice(2, 1); 729 } 730 return ts.factory.createExpressionStatement(ts.factory.createBinaryExpression( 731 createPropertyAccessExpressionWithThis(`__${name.getText()}`), 732 ts.factory.createToken(ts.SyntaxKind.EqualsToken), ts.factory.createCallExpression( 733 ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(storageFuncName), 734 ts.factory.createIdentifier(setFuncName)), undefined, storageValue))); 735 } 736 return undefined; 737} 738 739function getDecoratorKey(node: ts.PropertyDeclaration, isProvided: boolean = false): [string, boolean, ts.Node, boolean] { 740 let key: string; 741 let isStringKey: boolean = false; 742 let isProvidedParamObj: boolean = false; 743 const decorators: readonly ts.Decorator[] = ts.getAllDecorators(node); 744 const index: number = findDecoratorIndex(decorators, [COMPONENT_PROVIDE_DECORATOR, COMPONENT_CONSUME_DECORATOR]); 745 // @ts-ignore 746 let keyNameNode: ts.Node = decorators[index].expression.arguments[0]; 747 if (ts.isIdentifier(keyNameNode)) { 748 key = keyNameNode.getText(); 749 decoratorParamSet.add(key); 750 } else if (ts.isStringLiteral(keyNameNode)) { 751 key = keyNameNode.text; 752 isStringKey = true; 753 } else if (isProvided && ts.isObjectLiteralExpression(keyNameNode) && keyNameNode.properties.length === 1 && 754 ts.isPropertyAssignment(keyNameNode.properties[0]) && keyNameNode.properties[0].initializer) { 755 key = keyNameNode.properties[0].initializer.text; 756 keyNameNode = keyNameNode.properties[0].initializer; 757 isProvidedParamObj = true; 758 } else { 759 key = keyNameNode.getText(); 760 } 761 return [key, isStringKey, keyNameNode, isProvidedParamObj]; 762} 763 764function updateSynchedPropertyNesedObject(nameIdentifier: ts.Identifier, 765 type: ts.TypeNode, decoractor: string, log: LogInfo[]): ts.ExpressionStatement { 766 if (isObservedClassType(type)) { 767 return createInitExpressionStatementForDecorator(nameIdentifier.getText(), SYNCHED_PROPERTY_NESED_OBJECT, 768 createPropertyAccessExpressionWithParams(nameIdentifier.getText())); 769 } else { 770 validateNonObservedClassType(nameIdentifier, decoractor, log); 771 } 772 return undefined; 773} 774 775function updateConsumeProperty(node: ts.PropertyDeclaration, 776 nameIdentifier: ts.Identifier): ts.ExpressionStatement { 777 const name: string = nameIdentifier.getText(); 778 let propertyOrAliasName: string; 779 const propertyAndStringKey: [string?, boolean?, ts.Node?, boolean?] = []; 780 if (isSingleKey(node, true)) { 781 propertyAndStringKey.push(...getDecoratorKey(node)); 782 propertyOrAliasName = propertyAndStringKey[0]; 783 } else { 784 propertyOrAliasName = name; 785 } 786 return ts.factory.createExpressionStatement(ts.factory.createBinaryExpression( 787 createPropertyAccessExpressionWithThis(`__${name}`), 788 ts.factory.createToken(ts.SyntaxKind.EqualsToken), ts.factory.createCallExpression( 789 createPropertyAccessExpressionWithThis(INITIALIZE_CONSUME_FUNCTION), undefined, [ 790 propertyAndStringKey.length === 0 ? ts.factory.createStringLiteral(propertyOrAliasName) : 791 propertyAndStringKey.length === 4 && propertyAndStringKey[2] as ts.Expression, ts.factory.createStringLiteral(name)]))); 792} 793 794function updateBuilderParamProperty(node: ts.PropertyDeclaration, 795 nameIdentifier: ts.Identifier, log: LogInfo[]): ts.ExpressionStatement { 796 const name: string = nameIdentifier.getText(); 797 if (judgeBuilderParamAssignedByBuilder(node)) { 798 log.push({ 799 type: LogType.ERROR, 800 message: 'BuilderParam property can only initialized by Builder function or LocalBuilder method in struct.', 801 pos: node.getStart() 802 }); 803 } 804 return ts.factory.createExpressionStatement(ts.factory.createBinaryExpression( 805 createPropertyAccessExpressionWithThis(name), ts.factory.createToken(ts.SyntaxKind.EqualsToken), 806 node.initializer || ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED) 807 )); 808} 809 810export function judgeBuilderParamAssignedByBuilder(node: ts.PropertyDeclaration): boolean { 811 return node.initializer && !(node.initializer && (ts.isIdentifier(node.initializer) && 812 CUSTOM_BUILDER_METHOD.has(node.initializer.escapedText.toString()) || 813 ts.isPropertyAccessExpression(node.initializer) && node.initializer.name && 814 ts.isIdentifier(node.initializer.name) && 815 (CUSTOM_BUILDER_METHOD.has(node.initializer.name.escapedText.toString()) || 816 INNER_CUSTOM_LOCALBUILDER_METHOD.has(node.initializer.name.escapedText.toString())) || 817 isWrappedBuilder(node.initializer as ts.PropertyAccessExpression))); 818} 819 820export function createViewCreate(node: ts.NewExpression | ts.Identifier): ts.CallExpression { 821 if (partialUpdateConfig.partialUpdateMode) { 822 return createFunction(ts.factory.createIdentifier(BASE_COMPONENT_NAME_PU), 823 ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION), ts.factory.createNodeArray([node])); 824 } 825 return createFunction(ts.factory.createIdentifier(BASE_COMPONENT_NAME), 826 ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION), ts.factory.createNodeArray([node])); 827} 828 829export function createCustomComponentNewExpression(node: ts.CallExpression, name: string, 830 isBuilder: boolean = false, isGlobalBuilder: boolean = false, 831 isCutomDialog: boolean = false): ts.NewExpression { 832 const newNode: ts.NewExpression = ts.factory.createNewExpression(node.expression, 833 node.typeArguments, node.arguments.length ? node.arguments : []); 834 return addCustomComponentId(newNode, node, name, isBuilder, isGlobalBuilder, isCutomDialog); 835} 836 837function addCustomComponentId(node: ts.NewExpression, oldNode: ts.CallExpression, componentName: string, 838 isBuilder: boolean = false, isGlobalBuilder: boolean = false, 839 isCutomDialog: boolean = false): ts.NewExpression { 840 const posOfNode = transformLog.sourceFile.getLineAndCharacterOfPosition(getRealNodePos(node)); 841 const line: number = posOfNode.line + 1; 842 const col: number = posOfNode.character + 1; 843 for (const item of componentCollection.customComponents) { 844 componentInfo.componentNames.add(item); 845 } 846 componentInfo.componentNames.forEach((name: string) => { 847 let argumentsArray: ts.Expression[]; 848 if (node.arguments && node.arguments.length) { 849 argumentsArray = Array.from(node.arguments); 850 if (partialUpdateConfig.partialUpdateMode && node.arguments.length === 1) { 851 manageLocalStorageComponents(oldNode, argumentsArray); 852 } 853 } 854 if (componentName === name) { 855 if (!argumentsArray) { 856 argumentsArray = [ts.factory.createObjectLiteralExpression([], true)]; 857 if (partialUpdateConfig.partialUpdateMode) { 858 argumentsArray.push(ts.factory.createIdentifier(COMPONENT_IF_UNDEFINED)); 859 } 860 } 861 if (!partialUpdateConfig.partialUpdateMode) { 862 ++componentInfo.id; 863 argumentsArray.unshift(isBuilder ? ts.factory.createBinaryExpression( 864 ts.factory.createStringLiteral(path.basename(transformLog.sourceFile.fileName, EXTNAME_ETS) + '_'), 865 ts.factory.createToken(ts.SyntaxKind.PlusToken), ts.factory.createIdentifier(_GENERATE_ID)) : 866 ts.factory.createStringLiteral(componentInfo.id.toString()), 867 isBuilder ? parentConditionalExpression() : ts.factory.createThis()); 868 } else { 869 argumentsArray.unshift((isGlobalBuilder || storedFileInfo.processLocalBuilder) ? parentConditionalExpression() : ts.factory.createThis()); 870 argumentsArray.push(isCutomDialog ? ts.factory.createPrefixUnaryExpression( 871 ts.SyntaxKind.MinusToken, 872 ts.factory.createNumericLiteral('1')) : ts.factory.createIdentifier(ELMTID), 873 createArrowFunctionNode(), componentParamRowAndColumn(line, col)); 874 } 875 node = 876 ts.factory.updateNewExpression(node, node.expression, node.typeArguments, argumentsArray); 877 } else if (argumentsArray) { 878 node = 879 ts.factory.updateNewExpression(node, node.expression, node.typeArguments, argumentsArray); 880 } 881 }); 882 return node; 883} 884 885function manageLocalStorageComponents(node: ts.CallExpression, argumentsArray: ts.Expression[]): void { 886 if (isLocalStorageParameter(node)) { 887 argumentsArray.unshift(ts.factory.createObjectLiteralExpression([], false)); 888 } else { 889 argumentsArray.push(ts.factory.createIdentifier(COMPONENT_IF_UNDEFINED)); 890 } 891} 892 893export function isLocalStorageParameter(node: ts.CallExpression): boolean { 894 return globalProgram.checker && globalProgram.checker.getResolvedSignature && 895 globalProgram.checker.getResolvedSignature(node) && 896 globalProgram.checker.getResolvedSignature(node).parameters && 897 globalProgram.checker.getResolvedSignature(node).parameters.length === 1 && 898 globalProgram.checker.getResolvedSignature(node).parameters[0].escapedName === '##storage'; 899} 900 901function componentParamRowAndColumn(line: number, col: number): ts.ObjectLiteralExpression { 902 return ts.factory.createObjectLiteralExpression( 903 [ 904 ts.factory.createPropertyAssignment( 905 ts.factory.createIdentifier('page'), 906 ts.factory.createStringLiteral(path.relative(process.cwd(), resourceFileName).replace(/\\/g, '/')) 907 ), 908 ts.factory.createPropertyAssignment( 909 ts.factory.createIdentifier('line'), 910 ts.factory.createNumericLiteral(line) 911 ), 912 ts.factory.createPropertyAssignment( 913 ts.factory.createIdentifier('col'), 914 ts.factory.createNumericLiteral(col) 915 ) 916 ], 917 false 918 ); 919} 920 921function createArrowFunctionNode(): ts.ArrowFunction { 922 return ts.factory.createArrowFunction( 923 undefined, 924 undefined, 925 [], 926 undefined, 927 ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), 928 ts.factory.createBlock( 929 [], 930 false 931 ) 932 ); 933} 934 935function createInitExpressionStatementForDecorator(propertyName: string, functionName: string, 936 parameterNode: ts.Expression): ts.ExpressionStatement { 937 return ts.factory.createExpressionStatement(ts.factory.createBinaryExpression( 938 createPropertyAccessExpressionWithThis(`__${propertyName}`), 939 ts.factory.createToken(ts.SyntaxKind.EqualsToken), ts.factory.createNewExpression( 940 ts.factory.createIdentifier(functionName), undefined, [parameterNode, ts.factory.createThis(), 941 ts.factory.createStringLiteral(propertyName)]))); 942} 943 944function createPropertyAccessExpressionWithParams(propertyName: string): ts.PropertyAccessExpression { 945 return ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(CREATE_CONSTRUCTOR_PARAMS), 946 ts.factory.createIdentifier(propertyName)); 947} 948 949function createPropertyAccessExpressionWithThis(propertyName: string): ts.PropertyAccessExpression { 950 return ts.factory.createPropertyAccessExpression(ts.factory.createThis(), 951 ts.factory.createIdentifier(propertyName)); 952} 953 954function addAddProvidedVar(node: ts.PropertyDeclaration, name: ts.Identifier, 955 decoratorName: string, updateState: ts.Statement[]): void { 956 if (decoratorName === COMPONENT_PROVIDE_DECORATOR) { 957 let parameterName: string; 958 const parameterNameAndStringKey: [string?, boolean?, ts.Node?, boolean?] = []; 959 if (isSingleKey(node, true)) { 960 parameterNameAndStringKey.push(...getDecoratorKey(node, true)); 961 parameterName = parameterNameAndStringKey[0]; 962 updateState.push(createAddProvidedVar(parameterName, name, parameterNameAndStringKey[1], parameterNameAndStringKey[2], 963 parameterNameAndStringKey[3])); 964 } 965 if (parameterName !== name.getText()) { 966 updateState.push(createAddProvidedVar(name.getText(), name, true, undefined, parameterNameAndStringKey[3])); 967 } 968 } 969} 970 971function createAddProvidedVar(propertyOrAliasName: string, 972 name: ts.Identifier, isString: boolean, decoratorKeyNode: ts.Node, 973 isProvidedParamObj: boolean): ts.ExpressionStatement { 974 return ts.factory.createExpressionStatement(ts.factory.createCallExpression( 975 createPropertyAccessExpressionWithThis(ADD_PROVIDED_VAR), undefined, [ 976 isString ? ts.factory.createStringLiteral(propertyOrAliasName) : decoratorKeyNode as ts.Expression, 977 createPropertyAccessExpressionWithThis(`__${name.getText()}`), 978 isProvidedParamObj ? ts.factory.createIdentifier(TRUE) : ts.factory.createIdentifier(FALSE)])); 979} 980 981function createGetAccessor(item: ts.Identifier, express: string): ts.GetAccessorDeclaration { 982 const getAccessorStatement: ts.GetAccessorDeclaration = 983 ts.factory.createGetAccessorDeclaration(undefined, item, [], undefined, 984 ts.factory.createBlock([ts.factory.createReturnStatement( 985 ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression( 986 createPropertyAccessExpressionWithThis(`__${item.getText()}`), 987 ts.factory.createIdentifier(express)), undefined, []))], true)); 988 return getAccessorStatement; 989} 990 991function createSetAccessor(item: ts.Identifier, express: string, type: ts.TypeNode): 992 ts.SetAccessorDeclaration { 993 const setAccessorStatement: ts.SetAccessorDeclaration = 994 ts.factory.createSetAccessorDeclaration(undefined, item, 995 [ts.factory.createParameterDeclaration(undefined, undefined, 996 ts.factory.createIdentifier(CREATE_NEWVALUE_IDENTIFIER), undefined, type, 997 undefined)], ts.factory.createBlock([ts.factory.createExpressionStatement( 998 ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression( 999 createPropertyAccessExpressionWithThis(`__${item.getText()}`), 1000 ts.factory.createIdentifier(express)), undefined, 1001 [ts.factory.createIdentifier(CREATE_NEWVALUE_IDENTIFIER)]))], true)); 1002 return setAccessorStatement; 1003} 1004 1005function isForbiddenUseStateType(typeNode: ts.TypeNode): boolean { 1006 if (ts.isTypeReferenceNode(typeNode) && ts.isIdentifier(typeNode.typeName) && 1007 forbiddenUseStateType.has(typeNode.typeName.getText())) { 1008 return true; 1009 } 1010 return false; 1011} 1012 1013export function isSimpleType(typeNode: ts.TypeNode, program: ts.Program, log?: LogInfo[]): boolean { 1014 typeNode = typeNode || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword); 1015 let checker: ts.TypeChecker; 1016 if (globalProgram.program) { 1017 checker = globalProgram.program.getTypeChecker(); 1018 } else if (globalProgram.watchProgram) { 1019 checker = globalProgram.watchProgram.getCurrentProgram().getProgram().getTypeChecker(); 1020 } else if (program) { 1021 checker = program.getTypeChecker(); 1022 } 1023 return getDeclarationType(typeNode, checker, log); 1024} 1025 1026function getDeclarationType(typeNode: ts.TypeNode, checker: ts.TypeChecker, log: LogInfo[]): boolean { 1027 if (simpleTypes.has(typeNode.kind)) { 1028 return true; 1029 } 1030 if (ts.isTypeReferenceNode(typeNode) && typeNode.typeName && ts.isIdentifier(typeNode.typeName) && 1031 enumCollection.has(typeNode.typeName.escapedText.toString())) { 1032 return true; 1033 } 1034 if (checker) { 1035 const type: ts.Type = checker.getTypeFromTypeNode(typeNode); 1036 /* Enum */ 1037 if (type.flags & (32 | 1024)) { 1038 return true; 1039 } 1040 // @ts-ignore 1041 if (type.types && type.types.length) { 1042 // @ts-ignore 1043 const types = type.types; 1044 let referenceType: boolean = false; 1045 for (let i = 0; i < types.length; i++) { 1046 if (!isBasicType(types[i].flags)) { 1047 referenceType = true; 1048 } 1049 } 1050 if (!referenceType) { 1051 return true; 1052 } 1053 } 1054 } 1055 return false; 1056} 1057 1058export function isBasicType(flags: number): boolean { 1059 if (flags & (4 | /* String */ 8 | /* Number */ 16 | /* Boolean */ 32 | /* Enum */ 64 | /* BigInt */ 1060 128 | /* StringLiteral */ 256 | /* NumberLiteral */ 512 /* BooleanLiteral */| 1024 /* EnumLiteral */| 1061 2048 /* BigIntLiteral */)) { 1062 return true; 1063 } 1064 return false; 1065} 1066 1067function isObservedClassType(type: ts.TypeNode): boolean { 1068 if (judgmentTypedeclaration(type) && observedClassCollection.has(type.typeName.escapedText.toString())) { 1069 return true; 1070 } else if (ts.isUnionTypeNode(type) && type.types) { 1071 const types: ts.NodeArray<ts.TypeNode> = type.types; 1072 for (let i = 0; i < types.length; i++) { 1073 if (judgmentTypedeclaration(types[i]) && !observedClassCollection.has(types[i].typeName.escapedText.toString())) { 1074 return false; 1075 } 1076 } 1077 return true; 1078 } 1079 return false; 1080} 1081 1082function judgmentTypedeclaration(type: ts.TypeNode): boolean { 1083 return ts.isTypeReferenceNode(type) && type.typeName && ts.isIdentifier(type.typeName); 1084} 1085 1086export function isSingleKey(node: ts.PropertyDeclaration, isOptionalKey: boolean = false): boolean { 1087 const decorators: readonly ts.Decorator[] = ts.getAllDecorators(node); 1088 const optionalKeyDecorator: Set<string> = new Set(['Provide', 'Consume']); 1089 return decorators.some((item: ts.Decorator) => { 1090 return ts.isCallExpression(item.expression) && 1091 item.expression.arguments && 1092 item.expression.arguments.length === 1 && 1093 ts.isIdentifier(item.expression.expression) && 1094 (!isOptionalKey || optionalKeyDecorator.has(item.expression.expression.escapedText.toString())); 1095 }); 1096} 1097 1098function validateMultiDecorators(name: ts.Identifier, log: LogInfo[]): void { 1099 log.push({ 1100 type: LogType.ERROR, 1101 message: `The property '${name.escapedText.toString()}' cannot have mutilate state management decorators.`, 1102 pos: name.getStart() 1103 }); 1104} 1105 1106function validatePropertyNonDefaultValue(propertyName: ts.Identifier, decorator: string, 1107 log: LogInfo[]): void { 1108 log.push({ 1109 type: LogType.ERROR, 1110 message: `The ${decorator} property '${propertyName.getText()}' must be specified a default value.`, 1111 pos: propertyName.getStart() 1112 }); 1113} 1114 1115function validatePropertyDefaultValue(propertyName: ts.Identifier, decorator: string, 1116 log: LogInfo[]): void { 1117 log.push({ 1118 type: LogType.ERROR, 1119 message: `The ${decorator} property '${propertyName.getText()}' cannot be specified a default value.` + 1120 'Solutions:>Please initialize the rules according to the decorator.', 1121 pos: propertyName.getStart() 1122 }); 1123} 1124 1125function validatePropertyNonType(propertyName: ts.Identifier, log: LogInfo[]): void { 1126 log.push({ 1127 type: LogType.ERROR, 1128 message: `The property '${propertyName.getText()}' must specify a type.`, 1129 pos: propertyName.getStart() 1130 }); 1131} 1132 1133function validateNonSimpleType(propertyName: ts.Identifier, decorator: string, 1134 log: LogInfo[]): void { 1135 log.push({ 1136 type: projectConfig.optLazyForEach ? LogType.WARN : LogType.ERROR, 1137 message: `The type of the ${decorator} property '${propertyName.getText()}' ` + 1138 `can only be string, number or boolean.`, 1139 pos: propertyName.getStart() 1140 }); 1141} 1142 1143function validateNonObservedClassType(propertyName: ts.Identifier, decorator: string, 1144 log: LogInfo[]): void { 1145 log.push({ 1146 type: projectConfig.optLazyForEach ? LogType.WARN : LogType.ERROR, 1147 message: `The type of the ${decorator} property '${propertyName.getText()}' can only be ` + 1148 `objects of classes decorated with ${COMPONENT_OBSERVED_DECORATOR} class decorator in ets (not ts).`, 1149 pos: propertyName.getStart() 1150 }); 1151} 1152 1153function validateHasIllegalQuestionToken(propertyName: ts.Identifier, decorator: string, 1154 log: LogInfo[]): void { 1155 log.push({ 1156 type: LogType.WARN, 1157 message: `The ${decorator} property '${propertyName.getText()}' cannot be an optional parameter.`, 1158 pos: propertyName.getStart() 1159 }); 1160} 1161 1162function validateHasIllegalDecoratorInEntry(parentName: ts.Identifier, propertyName: ts.Identifier, 1163 decorator: string, log: LogInfo[]): void { 1164 log.push({ 1165 type: LogType.WARN, 1166 message: `The @Entry component '${parentName.getText()}' cannot have the ` + 1167 `${decorator} property '${propertyName.getText()}'.`, 1168 pos: propertyName.getStart() 1169 }); 1170} 1171 1172function validateForbiddenUseStateType(propertyName: ts.Identifier, decorator: string, type: string, 1173 log: LogInfo[]): void { 1174 log.push({ 1175 type: LogType.ERROR, 1176 message: `The ${decorator} property '${propertyName.getText()}' cannot be a '${type}' object.`, 1177 pos: propertyName.getStart() 1178 }); 1179} 1180 1181function validateDuplicateDecorator(decorator: ts.Decorator, log: LogInfo[]): void { 1182 log.push({ 1183 type: LogType.ERROR, 1184 message: `The decorator '${decorator.getText()}' cannot have the same name as the built-in ` + 1185 `style attribute '${decorator.getText().replace('@', '')}'.`, 1186 pos: decorator.getStart() 1187 }); 1188} 1189 1190function validateWatchDecorator(propertyName: ts.Identifier, decorators: readonly ts.Decorator[], 1191 log: LogInfo[]): boolean { 1192 let isRegular: boolean = false; 1193 if (decorators.length === DECORATOR_LENGTH) { 1194 isRegular = decorators.some((item: ts.Decorator) => { 1195 return item.getText() === COMPONENT_REQUIRE_DECORATOR; 1196 }); 1197 } 1198 if (decorators.length === 1 || isRegular) { 1199 log.push({ 1200 type: LogType.ERROR, 1201 message: `Regular variable '${propertyName.escapedText.toString()}' can not be decorated with @Watch.`, 1202 pos: propertyName.getStart() 1203 }); 1204 return false; 1205 } 1206 return true; 1207} 1208 1209function validateWatchParam(type: LogType, pos: number, log: LogInfo[]): void { 1210 log.push({ 1211 type: type, 1212 message: 'The parameter should be a string.', 1213 pos: pos 1214 }); 1215} 1216 1217function updateObservedPropertyPU(item: ts.PropertyDeclaration, name: ts.Identifier, 1218 type: ts.TypeNode, program: ts.Program): ts.ExpressionStatement { 1219 return ts.factory.createExpressionStatement(ts.factory.createBinaryExpression( 1220 createPropertyAccessExpressionWithThis(`__${name.getText()}`), 1221 ts.factory.createToken(ts.SyntaxKind.EqualsToken), ts.factory.createNewExpression( 1222 ts.factory.createIdentifier(isSimpleType(type, program) ? OBSERVED_PROPERTY_SIMPLE_PU : 1223 OBSERVED_PROPERTY_OBJECT_PU), undefined, [item.initializer, ts.factory.createThis(), 1224 ts.factory.createStringLiteral(name.escapedText.toString())]))); 1225} 1226 1227function updateSynchedPropertyTwoWayPU(nameIdentifier: ts.Identifier, type: ts.TypeNode, 1228 program: ts.Program): ts.ExpressionStatement { 1229 const name: string = nameIdentifier.escapedText.toString(); 1230 const functionName: string = isSimpleType(type, program) ? 1231 SYNCHED_PROPERTY_SIMPLE_TWO_WAY_PU : SYNCHED_PROPERTY_OBJECT_TWO_WAY_PU; 1232 return createInitExpressionStatementForDecorator(name, functionName, 1233 createPropertyAccessExpressionWithParams(name)); 1234} 1235 1236function updateSynchedPropertyOneWayPU(nameIdentifier: ts.Identifier, type: ts.TypeNode, 1237 decoractor: string, log: LogInfo[], program: ts.Program): ts.ExpressionStatement { 1238 const name: string = nameIdentifier.escapedText.toString(); 1239 if (isSimpleType(type, program, log)) { 1240 return createInitExpressionStatementForDecorator(name, SYNCHED_PROPERTY_SIMPLE_ONE_WAY_PU, 1241 createPropertyAccessExpressionWithParams(name)); 1242 } else { 1243 return createInitExpressionStatementForDecorator(name, SYNCHED_PROPERTY_OBJECT_ONE_WAY_PU, 1244 createPropertyAccessExpressionWithParams(name)); 1245 } 1246} 1247 1248function updateSynchedPropertyNesedObjectPU(nameIdentifier: ts.Identifier, 1249 type: ts.TypeNode, decoractor: string, log: LogInfo[]): ts.ExpressionStatement { 1250 if (partialUpdateConfig.partialUpdateMode && projectConfig.compileMode === 'esmodule' && checkObjectLinkType(type)) { 1251 return createInitExpressionStatementForDecorator(nameIdentifier.getText(), SYNCHED_PROPERTY_NESED_OBJECT_PU, 1252 createPropertyAccessExpressionWithParams(nameIdentifier.getText())); 1253 } else if ((projectConfig.compileMode !== 'esmodule' || !partialUpdateConfig.partialUpdateMode) && isObservedClassType(type)) { 1254 return createInitExpressionStatementForDecorator(nameIdentifier.getText(), SYNCHED_PROPERTY_NESED_OBJECT_PU, 1255 createPropertyAccessExpressionWithParams(nameIdentifier.getText())); 1256 } else { 1257 validateNonObservedClassType(nameIdentifier, decoractor, log); 1258 return undefined; 1259 } 1260} 1261 1262function validateCustomDecorator(decorators: readonly ts.Decorator[], log: LogInfo[]): boolean { 1263 let hasInnerDecorator: boolean = false; 1264 let hasCustomDecorator: boolean = false; 1265 let innerDecorator: ts.Decorator; 1266 for (let i = 0; i < decorators.length; i++) { 1267 const decorator: ts.Decorator = decorators[i]; 1268 const decoratorName: string = decorator.getText().replace(/\(.*\)$/, '').trim(); 1269 if (INNER_COMPONENT_MEMBER_DECORATORS.has(decoratorName)) { 1270 hasInnerDecorator = true; 1271 innerDecorator = innerDecorator || decorator; 1272 } else { 1273 hasCustomDecorator = true; 1274 } 1275 } 1276 if (hasCustomDecorator && hasInnerDecorator) { 1277 log.push({ 1278 type: LogType.ERROR, 1279 message: `The inner decorator ${innerDecorator.getText()} cannot be used together with custom decorator.`, 1280 pos: innerDecorator.getStart() 1281 }); 1282 } else if (!hasInnerDecorator) { 1283 return true; 1284 } 1285 return false; 1286} 1287 1288function validatePropDecorator(decorators: readonly ts.Decorator[]): boolean { 1289 for (let i = 0; i < decorators.length; i++) { 1290 const decorator: ts.Decorator = decorators[i]; 1291 const decoratorName: string = decorator.getText().replace(/\(.*\)$/, '').trim(); 1292 if (COMPONENT_PROP_DECORATOR === decoratorName) { 1293 return true; 1294 } 1295 } 1296 return false; 1297} 1298 1299function checkObjectLinkType(typeNode: ts.TypeNode): boolean { 1300 if (globalProgram.checker) { 1301 const type: ts.Type = globalProgram.checker.getTypeFromTypeNode(typeNode); 1302 if (typeNode.parent && ts.isPropertyDeclaration(typeNode.parent) && isObserved(type)) { 1303 return true; 1304 } 1305 // @ts-ignore 1306 if (type.types && type.types.length) { 1307 let observedNumber: number = 0; 1308 for (let i = 0; i < type.types.length; i++) { 1309 if (type.types[i].intrinsicName) { 1310 return false; 1311 } 1312 if (isObserved(type.types[i])) { 1313 observedNumber += 1; 1314 } 1315 } 1316 if (observedNumber === type.types.length) { 1317 return true; 1318 } else { 1319 return false; 1320 } 1321 } 1322 } 1323 return false; 1324} 1325 1326function isObserved(type: ts.Type): boolean { 1327 if (type && type.getSymbol() && type.getSymbol().declarations) { 1328 return type.getSymbol().declarations.some((classDeclaration: ts.ClassDeclaration) => { 1329 const decorators: readonly ts.Decorator[] = ts.getAllDecorators(classDeclaration); 1330 if (ts.isClassDeclaration(classDeclaration) && decorators) { 1331 return decorators.some((decorator: ts.Decorator) => { 1332 return ts.isIdentifier(decorator.expression) && decorator.expression.escapedText.toString() === OBSERVED; 1333 }); 1334 } 1335 return false; 1336 }); 1337 } 1338 return false; 1339} 1340 1341export function resetProcessComponentMember(): void { 1342 decoratorParamSet.clear(); 1343} 1344