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 (judgmentTypedeclaration(type) && observedClassCollection.has(type.typeName.escapedText.toString())) { 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 (judgmentTypedeclaration(types[i]) && !observedClassCollection.has(types[i].typeName.escapedText.toString())) { 952 return false; 953 } 954 } 955 return true; 956 } 957 return false; 958} 959 960function judgmentTypedeclaration(type: ts.TypeNode): boolean { 961 return ts.isTypeReferenceNode(type) && type.typeName && ts.isIdentifier(type.typeName); 962} 963 964function validateAppStorageDecoractorsNonSingleKey(node: ts.PropertyDeclaration, 965 log: LogInfo[]): void { 966 if (ts.isIdentifier(node.decorators[0].expression)) { 967 validateDecoratorNonSingleKey(node.decorators[0].expression, log); 968 } else if (ts.isCallExpression(node.decorators[0].expression) && 969 ts.isIdentifier(node.decorators[0].expression.expression)) { 970 validateDecoratorNonSingleKey(node.decorators[0].expression.expression, log); 971 } 972} 973 974function isSingleKey(node: ts.PropertyDeclaration): boolean { 975 if (ts.isCallExpression(node.decorators[0].expression) && 976 node.decorators[0].expression.arguments && 977 node.decorators[0].expression.arguments.length === 1 && 978 (ts.isIdentifier(node.decorators[0].expression.arguments[0]) || 979 ts.isStringLiteral(node.decorators[0].expression.arguments[0]))) { 980 return true; 981 } 982} 983 984function validateMultiDecorators(name: ts.Identifier, log: LogInfo[]): void { 985 log.push({ 986 type: LogType.ERROR, 987 message: `The property '${name.escapedText.toString()}' cannot have mutilate state management decorators.`, 988 pos: name.getStart() 989 }); 990} 991 992function validateDecoratorNonSingleKey(decoratorsIdentifier: ts.Identifier, 993 log: LogInfo[]): void { 994 log.push({ 995 type: LogType.ERROR, 996 message: `The decorator ${decoratorsIdentifier.escapedText.toString()} should have a single key.`, 997 pos: decoratorsIdentifier.getStart() 998 }); 999} 1000 1001function validatePropertyNonDefaultValue(propertyName: ts.Identifier, decorator: string, 1002 log: LogInfo[]): void { 1003 log.push({ 1004 type: LogType.ERROR, 1005 message: `The ${decorator} property '${propertyName.getText()}' must be specified a default value.`, 1006 pos: propertyName.getStart() 1007 }); 1008} 1009 1010function validatePropertyDefaultValue(propertyName: ts.Identifier, decorator: string, 1011 log: LogInfo[]): void { 1012 log.push({ 1013 type: LogType.ERROR, 1014 message: `The ${decorator} property '${propertyName.getText()}' cannot be specified a default value.`, 1015 pos: propertyName.getStart() 1016 }); 1017} 1018 1019function validatePropertyNonType(propertyName: ts.Identifier, log: LogInfo[]): void { 1020 log.push({ 1021 type: LogType.ERROR, 1022 message: `The property '${propertyName.getText()}' must specify a type.`, 1023 pos: propertyName.getStart() 1024 }); 1025} 1026 1027function validateNonSimpleType(propertyName: ts.Identifier, decorator: string, 1028 log: LogInfo[]): void { 1029 log.push({ 1030 type: LogType.ERROR, 1031 message: `The type of the ${decorator} property '${propertyName.getText()}' ` + 1032 `can only be string, number or boolean.`, 1033 pos: propertyName.getStart() 1034 }); 1035} 1036 1037function validateNonObservedClassType(propertyName: ts.Identifier, decorator: string, 1038 log: LogInfo[]): void { 1039 log.push({ 1040 type: LogType.ERROR, 1041 message: `The type of the ${decorator} property '${propertyName.getText()}' can only be ` + 1042 `objects of classes decorated with ${COMPONENT_OBSERVED_DECORATOR} class decorator in ets (not ts).`, 1043 pos: propertyName.getStart() 1044 }); 1045} 1046 1047function validateHasIllegalQuestionToken(propertyName: ts.Identifier, decorator: string, 1048 log: LogInfo[]): void { 1049 log.push({ 1050 type: LogType.WARN, 1051 message: `The ${decorator} property '${propertyName.getText()}' cannot be an optional parameter.`, 1052 pos: propertyName.getStart() 1053 }); 1054} 1055 1056function validateHasIllegalDecoratorInEntry(parentName: ts.Identifier, propertyName: ts.Identifier, 1057 decorator: string, log: LogInfo[]): void { 1058 log.push({ 1059 type: LogType.WARN, 1060 message: `The @Entry component '${parentName.getText()}' cannot have the ` + 1061 `${decorator} property '${propertyName.getText()}'.`, 1062 pos: propertyName.getStart() 1063 }); 1064} 1065 1066function validateForbiddenUseStateType(propertyName: ts.Identifier, decorator: string, type: string, 1067 log: LogInfo[]): void { 1068 log.push({ 1069 type: LogType.ERROR, 1070 message: `The ${decorator} property '${propertyName.getText()}' cannot be a '${type}' object.`, 1071 pos: propertyName.getStart() 1072 }); 1073} 1074 1075function validateDuplicateDecorator(decorator: ts.Decorator, log: LogInfo[]): void { 1076 log.push({ 1077 type: LogType.ERROR, 1078 message: `The decorator '${decorator.getText()}' cannot have the same name as the built-in ` + 1079 `style attribute '${decorator.getText().replace('@', '')}'.`, 1080 pos: decorator.getStart() 1081 }); 1082} 1083 1084function validateWatchDecorator(propertyName: ts.Identifier, length: number, log: LogInfo[]): boolean { 1085 if (length === 1) { 1086 log.push({ 1087 type: LogType.ERROR, 1088 message: `Regular variable '${propertyName.escapedText.toString()}' can not be decorated with @Watch.`, 1089 pos: propertyName.getStart() 1090 }); 1091 return false; 1092 } 1093 return true; 1094} 1095 1096function validateWatchParam(type: LogType, pos: number, log: LogInfo[]): void { 1097 log.push({ 1098 type: type, 1099 message: 'The parameter should be a string.', 1100 pos: pos 1101 }); 1102} 1103 1104function validateVariableType(typeNode: ts.TypeNode, log: LogInfo[]): void { 1105 log.push({ 1106 type: LogType.ERROR, 1107 message: `The state variable type here is '${typeNode.getText()}', ` + 1108 `it contains both a simple type and an object type,\n ` + 1109 `which are not allowed to be defined for state variable of a struct.`, 1110 pos: typeNode.getStart() 1111 }); 1112} 1113 1114function updateObservedPropertyPU(item: ts.PropertyDeclaration, name: ts.Identifier, 1115 type: ts.TypeNode, program: ts.Program): ts.ExpressionStatement { 1116 return ts.factory.createExpressionStatement(ts.factory.createBinaryExpression( 1117 createPropertyAccessExpressionWithThis(`__${name.getText()}`), 1118 ts.factory.createToken(ts.SyntaxKind.EqualsToken), ts.factory.createNewExpression( 1119 ts.factory.createIdentifier(isSimpleType(type, program) ? OBSERVED_PROPERTY_SIMPLE_PU : 1120 OBSERVED_PROPERTY_OBJECT_PU), undefined, [item.initializer, ts.factory.createThis(), 1121 ts.factory.createStringLiteral(name.escapedText.toString())]))); 1122} 1123 1124function updateSynchedPropertyTwoWayPU(nameIdentifier: ts.Identifier, type: ts.TypeNode, 1125 program: ts.Program): ts.ExpressionStatement { 1126 const name: string = nameIdentifier.escapedText.toString(); 1127 const functionName: string = isSimpleType(type, program) ? 1128 SYNCHED_PROPERTY_SIMPLE_TWO_WAY_PU : SYNCHED_PROPERTY_OBJECT_TWO_WAY_PU; 1129 return createInitExpressionStatementForDecorator(name, functionName, 1130 createPropertyAccessExpressionWithParams(name)); 1131} 1132 1133function updateSynchedPropertyOneWayPU(nameIdentifier: ts.Identifier, type: ts.TypeNode, 1134 decoractor: string, log: LogInfo[], program: ts.Program): ts.ExpressionStatement { 1135 const name: string = nameIdentifier.escapedText.toString(); 1136 if (isSimpleType(type, program, log)) { 1137 return createInitExpressionStatementForDecorator(name, SYNCHED_PROPERTY_SIMPLE_ONE_WAY_PU, 1138 createPropertyAccessExpressionWithParams(name)); 1139 } else { 1140 return createInitExpressionStatementForDecorator(name, SYNCHED_PROPERTY_OBJECT_ONE_WAY_PU, 1141 createPropertyAccessExpressionWithParams(name)); 1142 } 1143} 1144 1145function updateSynchedPropertyNesedObjectPU(nameIdentifier: ts.Identifier, 1146 type: ts.TypeNode, decoractor: string, log: LogInfo[]): ts.ExpressionStatement { 1147 if (isObservedClassType(type)) { 1148 return createInitExpressionStatementForDecorator(nameIdentifier.getText(), SYNCHED_PROPERTY_NESED_OBJECT_PU, 1149 createPropertyAccessExpressionWithParams(nameIdentifier.getText())); 1150 } else { 1151 validateNonObservedClassType(nameIdentifier, decoractor, log); 1152 } 1153} 1154 1155function validateCustomDecorator(decorators: ts.NodeArray<ts.Decorator>, log: LogInfo[]): boolean { 1156 let hasInnerDecorator: boolean = false; 1157 let hasCustomDecorator: boolean = false; 1158 let innerDecorator: ts.Decorator; 1159 for(let i = 0; i < decorators.length; i++) { 1160 let decorator: ts.Decorator = decorators[i]; 1161 const decoratorName: string = decorator.getText().replace(/\(.*\)$/, '').trim(); 1162 if (INNER_COMPONENT_MEMBER_DECORATORS.has(decoratorName)) { 1163 hasInnerDecorator = true; 1164 innerDecorator = innerDecorator ? innerDecorator : decorator; 1165 } else { 1166 hasCustomDecorator = true; 1167 } 1168 } 1169 if (hasCustomDecorator && hasInnerDecorator) { 1170 log.push({ 1171 type: LogType.ERROR, 1172 message: `The inner decorator ${innerDecorator.getText()} cannot be used together with custom decorator.`, 1173 pos: innerDecorator.getStart() 1174 }); 1175 } else if(!hasInnerDecorator) { 1176 return true; 1177 } 1178 return false; 1179} 1180 1181function validatePropDecorator(decorators: ts.NodeArray<ts.Decorator>): boolean { 1182 for(let i = 0; i < decorators.length; i++) { 1183 let decorator: ts.Decorator = decorators[i]; 1184 const decoratorName: string = decorator.getText().replace(/\(.*\)$/, '').trim(); 1185 if (COMPONENT_PROP_DECORATOR === decoratorName) { 1186 return true; 1187 } 1188 } 1189 return false; 1190} 1191