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