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