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