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