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'; 17 18import { 19 COMPONENT_STATE_DECORATOR, 20 COMPONENT_PROVIDE_DECORATOR, 21 COMPONENT_LINK_DECORATOR, 22 COMPONENT_PROP_DECORATOR, 23 COMPONENT_STORAGE_LINK_DECORATOR, 24 COMPONENT_STORAGE_PROP_DECORATOR, 25 COMPONENT_OBJECT_LINK_DECORATOR, 26 COMPONENT_CONSUME_DECORATOR, 27 SYNCHED_PROPERTY_NESED_OBJECT, 28 SYNCHED_PROPERTY_SIMPLE_TWO_WAY, 29 SYNCHED_PROPERTY_SIMPLE_ONE_WAY, 30 OBSERVED_PROPERTY_OBJECT, 31 OBSERVED_PROPERTY_SIMPLE, 32 COMPONENT_BUILD_FUNCTION, 33 BASE_COMPONENT_NAME, 34 CREATE_CONSTRUCTOR_PARAMS, 35 COMPONENT_CONSTRUCTOR_UPDATE_PARAMS, 36 COMPONENT_CONSTRUCTOR_INITIAL_PARAMS, 37 COMPONENT_CONSTRUCTOR_PURGE_VARIABLE_DEP, 38 COMPONENT_CONSTRUCTOR_DELETE_PARAMS, 39 COMPONENT_DECORATOR_PREVIEW, 40 CREATE_CONSTRUCTOR_SUBSCRIBER_MANAGER, 41 ABOUT_TO_BE_DELETE_FUNCTION_ID, 42 ABOUT_TO_BE_DELETE_FUNCTION_ID__, 43 CREATE_CONSTRUCTOR_GET_FUNCTION, 44 CREATE_CONSTRUCTOR_DELETE_FUNCTION, 45 FOREACH_OBSERVED_OBJECT, 46 FOREACH_GET_RAW_OBJECT, 47 COMPONENT_BUILDER_DECORATOR, 48 COMPONENT_TRANSITION_FUNCTION, 49 COMPONENT_CREATE_FUNCTION, 50 GEOMETRY_VIEW, 51 COMPONENT_STYLES_DECORATOR, 52 STYLES, 53 INTERFACE_NAME_SUFFIX, 54 OBSERVED_PROPERTY_ABSTRACT, 55 COMPONENT_LOCAL_STORAGE_LINK_DECORATOR, 56 COMPONENT_LOCAL_STORAGE_PROP_DECORATOR, 57 COMPONENT_CONSTRUCTOR_LOCALSTORAGE, 58 COMPONENT_SET_AND_LINK, 59 COMPONENT_SET_AND_PROP, 60 COMPONENT_CONSTRUCTOR_UNDEFINED, 61 CUSTOM_COMPONENT, 62 COMPONENT_CONSTRUCTOR_PARENT, 63 NULL, 64 INNER_COMPONENT_MEMBER_DECORATORS, 65 COMPONENT_RERENDER_FUNCTION, 66 RMELMTID, 67 ABOUTTOBEDELETEDINTERNAL, 68 UPDATEDIRTYELEMENTS, 69 LINKS_DECORATORS, 70 BASE_COMPONENT_NAME_PU, 71 OBSERVED_PROPERTY_SIMPLE_PU, 72 OBSERVED_PROPERTY_OBJECT_PU, 73 SYNCHED_PROPERTY_SIMPLE_TWO_WAY_PU, 74 SYNCHED_PROPERTY_SIMPLE_ONE_WAY_PU, 75 SYNCHED_PROPERTY_NESED_OBJECT_PU, 76 OBSERVED_PROPERTY_ABSTRACT_PU, 77 CREATE_LOCAL_STORAGE_LINK, 78 CREATE_LOCAL_STORAGE_PROP, 79 COMPONENT_UPDATE_STATE_VARS, 80 COMPONENT_WATCH_DECORATOR, 81 $$ 82} from './pre_define'; 83import { 84 BUILDIN_STYLE_NAMES, 85 CUSTOM_BUILDER_METHOD, 86 INNER_STYLE_FUNCTION, 87 INTERFACE_NODE_SET, 88 STYLES_ATTRIBUTE, 89 INNER_CUSTOM_BUILDER_METHOD 90} from './component_map'; 91import { 92 componentCollection, 93 linkCollection, 94 localStorageLinkCollection, 95 localStoragePropCollection, 96 propCollection 97} from './validate_ui_syntax'; 98import { 99 addConstructor, 100 getInitConstructor 101} from './process_component_constructor'; 102import { 103 ControllerType, 104 processMemberVariableDecorators, 105 UpdateResult, 106 stateObjectCollection, 107 curPropMap, 108 decoratorParamSet, 109 isSimpleType 110} from './process_component_member'; 111import { 112 processComponentBuild, 113 processComponentBlock 114} from './process_component_build'; 115import { 116 LogType, 117 LogInfo, 118 hasDecorator, 119 getPossibleBuilderTypeParameter 120} from './utils'; 121import { builderTypeParameter } from './process_ui_syntax'; 122import { partialUpdateConfig } from '../main'; 123 124export function processComponentClass(node: ts.StructDeclaration, context: ts.TransformationContext, 125 log: LogInfo[], program: ts.Program): ts.ClassDeclaration { 126 const memberNode: ts.ClassElement[] = 127 processMembers(node.members, node.name, context, log, program, checkPreview(node)); 128 return ts.factory.createClassDeclaration(undefined, node.modifiers, node.name, 129 node.typeParameters, updateHeritageClauses(node, log), memberNode); 130} 131 132function checkPreview(node: ts.ClassDeclaration) { 133 let hasPreview: boolean = false; 134 if (node && node.decorators) { 135 for (let i = 0; i < node.decorators.length; i++) { 136 const name: string = node.decorators[i].getText().replace(/\([^\(\)]*\)/, '').trim(); 137 if (name === COMPONENT_DECORATOR_PREVIEW) { 138 hasPreview = true; 139 break; 140 } 141 } 142 } 143 return hasPreview; 144} 145 146type BuildCount = { 147 count: number; 148} 149 150function processMembers(members: ts.NodeArray<ts.ClassElement>, parentComponentName: ts.Identifier, 151 context: ts.TransformationContext, log: LogInfo[], program: ts.Program, hasPreview: boolean): ts.ClassElement[] { 152 const buildCount: BuildCount = { count: 0 }; 153 let ctorNode: any = getInitConstructor(members, parentComponentName); 154 const newMembers: ts.ClassElement[] = []; 155 const watchMap: Map<string, ts.Node> = new Map(); 156 const updateParamsStatements: ts.Statement[] = []; 157 const stateVarsStatements: ts.Statement[] = []; 158 const purgeVariableDepStatements: ts.Statement[] = []; 159 const rerenderStatements: ts.Statement[] = []; 160 const deleteParamsStatements: ts.PropertyDeclaration[] = []; 161 const checkController: ControllerType = 162 { hasController: !componentCollection.customDialogs.has(parentComponentName.getText()) }; 163 const interfaceNode = ts.factory.createInterfaceDeclaration(undefined, undefined, 164 parentComponentName.getText() + INTERFACE_NAME_SUFFIX, undefined, undefined, []); 165 members.forEach((item: ts.ClassElement) => { 166 let updateItem: ts.ClassElement; 167 if (ts.isPropertyDeclaration(item)) { 168 if (isStaticProperty(item)) { 169 newMembers.push(item); 170 validateDecorators(item, log); 171 } else { 172 addPropertyMember(item, newMembers, program, parentComponentName.getText(), log); 173 const result: UpdateResult = processMemberVariableDecorators(parentComponentName, item, 174 ctorNode, watchMap, checkController, log, program, context, hasPreview, interfaceNode); 175 if (result.isItemUpdate()) { 176 updateItem = result.getProperity(); 177 } else { 178 updateItem = item; 179 } 180 if (result.getVariableGet()) { 181 newMembers.push(result.getVariableGet()); 182 } 183 if (result.getVariableSet()) { 184 newMembers.push(result.getVariableSet()); 185 } 186 if (result.isCtorUpdate()) { 187 ctorNode = result.getCtor(); 188 } 189 if (result.getUpdateParams()) { 190 updateParamsStatements.push(result.getUpdateParams()); 191 } 192 if (result.getStateVarsParams()) { 193 stateVarsStatements.push(result.getStateVarsParams()); 194 } 195 if (result.isDeleteParams()) { 196 deleteParamsStatements.push(item); 197 } 198 if (result.getControllerSet()) { 199 newMembers.push(result.getControllerSet()); 200 } 201 processPropertyUnchanged(result, purgeVariableDepStatements); 202 } 203 } 204 if (ts.isMethodDeclaration(item) && item.name) { 205 updateItem = 206 processComponentMethod(item, parentComponentName, context, log, buildCount); 207 } 208 if (updateItem) { 209 newMembers.push(updateItem); 210 } 211 }); 212 INTERFACE_NODE_SET.add(interfaceNode); 213 validateBuildMethodCount(buildCount, parentComponentName, log); 214 validateHasController(parentComponentName, checkController, log); 215 newMembers.unshift(addDeleteParamsFunc(deleteParamsStatements)); 216 addIntoNewMembers(newMembers, parentComponentName, updateParamsStatements, 217 purgeVariableDepStatements, rerenderStatements, stateVarsStatements); 218 newMembers.unshift(addConstructor(ctorNode, watchMap, parentComponentName)); 219 curPropMap.clear(); 220 return newMembers; 221} 222 223function isStaticProperty(property: ts.PropertyDeclaration): boolean { 224 return property.modifiers && property.modifiers.length && property.modifiers.some(modifier => { 225 return modifier.kind === ts.SyntaxKind.StaticKeyword; 226 }); 227} 228 229function validateDecorators(item: ts.ClassElement, log: LogInfo[]): void { 230 if (item.decorators && item.decorators.length) { 231 item.decorators.map((decorator: ts.Decorator) => { 232 const decoratorName: string = decorator.getText(); 233 if (INNER_COMPONENT_MEMBER_DECORATORS.has(decoratorName)) { 234 log.push({ 235 type: LogType.ERROR, 236 message: `The static variable of struct cannot be used together with built-in decorators.`, 237 pos: item.getStart() 238 }); 239 } 240 }); 241 } 242} 243 244function processPropertyUnchanged( 245 result: UpdateResult, 246 purgeVariableDepStatements: ts.Statement[] 247): void { 248 if (partialUpdateConfig.partialUpdateMode) { 249 if (result.getPurgeVariableDepStatement()) { 250 purgeVariableDepStatements.push(result.getPurgeVariableDepStatement()); 251 } 252 } 253} 254 255function addIntoNewMembers( 256 newMembers: ts.ClassElement[], 257 parentComponentName: ts.Identifier, 258 updateParamsStatements: ts.Statement[], 259 purgeVariableDepStatements: ts.Statement[], 260 rerenderStatements: ts.Statement[], 261 stateVarsStatements: ts.Statement[] 262): void { 263 if (partialUpdateConfig.partialUpdateMode) { 264 newMembers.unshift( 265 addInitialParamsFunc(updateParamsStatements, parentComponentName), 266 addUpdateStateVarsFunc(stateVarsStatements, parentComponentName), 267 addPurgeVariableDepFunc(purgeVariableDepStatements) 268 ); 269 newMembers.push(addRerenderFunc(rerenderStatements)); 270 } else { 271 newMembers.unshift(addUpdateParamsFunc(updateParamsStatements, parentComponentName)); 272 } 273} 274 275function addPropertyMember(item: ts.ClassElement, newMembers: ts.ClassElement[], 276 program: ts.Program, parentComponentName: string, log: LogInfo[]): void { 277 const propertyItem: ts.PropertyDeclaration = item as ts.PropertyDeclaration; 278 let decoratorName: string; 279 let updatePropertyItem: ts.PropertyDeclaration; 280 const type: ts.TypeNode = propertyItem.type; 281 if (!propertyItem.decorators || propertyItem.decorators.length === 0) { 282 updatePropertyItem = createPropertyDeclaration(propertyItem, type, true); 283 newMembers.push(updatePropertyItem); 284 } else if (propertyItem.decorators) { 285 for (let i = 0; i < propertyItem.decorators.length; i++) { 286 let newType: ts.TypeNode; 287 decoratorName = propertyItem.decorators[i].getText().replace(/\(.*\)$/, '').trim(); 288 let isLocalStorage: boolean = false; 289 if (!partialUpdateConfig.partialUpdateMode) { 290 newType = createTypeReference(decoratorName, type, log, program); 291 } else { 292 newType = createTypeReferencePU(decoratorName, type, log, program); 293 } 294 if ( 295 decoratorName === COMPONENT_LOCAL_STORAGE_LINK_DECORATOR || 296 decoratorName === COMPONENT_LOCAL_STORAGE_PROP_DECORATOR 297 ) { 298 isLocalStorage = true; 299 } 300 const newUpdatePropertyItem = createPropertyDeclaration( 301 propertyItem, newType, false, isLocalStorage, parentComponentName); 302 if (!updatePropertyItem) { 303 updatePropertyItem = newUpdatePropertyItem; 304 } else if (INNER_COMPONENT_MEMBER_DECORATORS.has(decoratorName) && 305 decoratorName !== COMPONENT_WATCH_DECORATOR) { 306 updatePropertyItem = newUpdatePropertyItem; 307 } 308 } 309 if (updatePropertyItem) { 310 newMembers.push(updatePropertyItem); 311 } 312 } 313} 314 315function createPropertyDeclaration(propertyItem: ts.PropertyDeclaration, newType: ts.TypeNode | undefined, 316 normalVar: boolean, isLocalStorage: boolean = false, parentComponentName: string = null): ts.PropertyDeclaration { 317 if (typeof newType === undefined) { 318 return undefined; 319 } 320 let prefix: string = ''; 321 if (!normalVar) { 322 prefix = '__'; 323 } 324 const privateM: ts.ModifierToken<ts.SyntaxKind.PrivateKeyword> = 325 ts.factory.createModifier(ts.SyntaxKind.PrivateKeyword); 326 return ts.factory.updatePropertyDeclaration(propertyItem, undefined, 327 propertyItem.modifiers || [privateM], prefix + propertyItem.name.getText(), 328 propertyItem.questionToken, newType, isLocalStorage ? 329 createLocalStroageCallExpression(propertyItem, propertyItem.name.getText(), 330 parentComponentName) : undefined); 331} 332 333function createLocalStroageCallExpression(node: ts.PropertyDeclaration, name: string, 334 parentComponentName: string): ts.CallExpression { 335 const localStorageLink: Set<string> = localStorageLinkCollection.get(parentComponentName).get(name); 336 const localStorageProp: Set<string> = localStoragePropCollection.get(parentComponentName).get(name); 337 let localFuncName: string; 338 const localValue: ts.Expression[] = [ 339 ts.factory.createStringLiteral(localStorageLink && !localStorageProp ? 340 Array.from(localStorageLink)[0] : !localStorageLink && localStorageProp ? 341 Array.from(localStorageProp)[0] : COMPONENT_CONSTRUCTOR_UNDEFINED), 342 node.initializer ? node.initializer : ts.factory.createNumericLiteral(COMPONENT_CONSTRUCTOR_UNDEFINED), 343 ts.factory.createThis(), ts.factory.createStringLiteral(name || COMPONENT_CONSTRUCTOR_UNDEFINED) 344 ]; 345 if (!partialUpdateConfig.partialUpdateMode) { 346 localFuncName = localStorageLink && !localStorageProp ? COMPONENT_SET_AND_LINK : 347 COMPONENT_SET_AND_PROP; 348 } else { 349 localFuncName = localStorageLink && !localStorageProp ? CREATE_LOCAL_STORAGE_LINK : 350 CREATE_LOCAL_STORAGE_PROP; 351 localValue.splice(-2, 1); 352 } 353 return ts.factory.createCallExpression( 354 ts.factory.createPropertyAccessExpression( 355 !partialUpdateConfig.partialUpdateMode ? 356 ts.factory.createPropertyAccessExpression( 357 ts.factory.createThis(), 358 ts.factory.createIdentifier(`${COMPONENT_CONSTRUCTOR_LOCALSTORAGE}_`) 359 ) : ts.factory.createThis(), 360 ts.factory.createIdentifier(localFuncName) 361 ), 362 [node.type], 363 localValue 364 ); 365} 366 367function processComponentMethod(node: ts.MethodDeclaration, parentComponentName: ts.Identifier, 368 context: ts.TransformationContext, log: LogInfo[], buildCount: BuildCount): ts.MethodDeclaration { 369 let updateItem: ts.MethodDeclaration = node; 370 const name: string = node.name.getText(); 371 const customBuilder: ts.Decorator[] = []; 372 if (name === COMPONENT_BUILD_FUNCTION) { 373 buildCount.count = buildCount.count + 1; 374 if (node.parameters.length) { 375 log.push({ 376 type: LogType.ERROR, 377 message: `The 'build' method can not have arguments.`, 378 pos: node.getStart() 379 }); 380 } 381 const buildNode: ts.MethodDeclaration = processComponentBuild(node, log); 382 updateItem = processBuildMember(buildNode, context, log); 383 } else if (node.body && ts.isBlock(node.body)) { 384 if (name === COMPONENT_TRANSITION_FUNCTION) { 385 updateItem = ts.factory.updateMethodDeclaration(node, node.decorators, node.modifiers, 386 node.asteriskToken, node.name, node.questionToken, node.typeParameters, node.parameters, 387 node.type, processComponentBlock(node.body, false, log, true)); 388 } else if (hasDecorator(node, COMPONENT_BUILDER_DECORATOR, customBuilder)) { 389 CUSTOM_BUILDER_METHOD.add(name); 390 INNER_CUSTOM_BUILDER_METHOD.add(name); 391 builderTypeParameter.params = getPossibleBuilderTypeParameter(node.parameters); 392 let parameters: ts.NodeArray<ts.ParameterDeclaration> = ts.factory.createNodeArray(Array.from(node.parameters)); 393 parameters.push(createParentParameter()); 394 const builderNode: ts.MethodDeclaration = ts.factory.updateMethodDeclaration(node, customBuilder, 395 node.modifiers, node.asteriskToken, node.name, node.questionToken, node.typeParameters, 396 parameters, node.type, processComponentBlock(node.body, false, log, false, true)); 397 builderTypeParameter.params = []; 398 updateItem = processBuildMember(builderNode, context, log, true); 399 } else if (hasDecorator(node, COMPONENT_STYLES_DECORATOR)) { 400 if (node.parameters && node.parameters.length === 0) { 401 if (ts.isBlock(node.body) && node.body.statements && node.body.statements.length) { 402 INNER_STYLE_FUNCTION.set(name, node.body); 403 STYLES_ATTRIBUTE.add(name); 404 BUILDIN_STYLE_NAMES.add(name); 405 decoratorParamSet.add(STYLES); 406 } 407 } else { 408 log.push({ 409 type: LogType.ERROR, 410 message: `@Styles can't have parameters.`, 411 pos: node.getStart() 412 }); 413 } 414 return; 415 } 416 } 417 return updateItem; 418} 419 420export function createParentParameter(): ts.ParameterDeclaration { 421 return ts.factory.createParameterDeclaration(undefined, undefined, undefined, 422 ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARENT), undefined, undefined, 423 ts.factory.createIdentifier(NULL)); 424} 425 426export function processBuildMember(node: ts.MethodDeclaration | ts.FunctionDeclaration, context: ts.TransformationContext, 427 log: LogInfo[], isBuilder = false): ts.MethodDeclaration | ts.FunctionDeclaration { 428 return ts.visitNode(node, visitBuild); 429 function visitBuild(node: ts.Node): ts.Node { 430 if (isGeometryView(node)) { 431 node = processGeometryView(node as ts.ExpressionStatement, log); 432 } 433 if (isProperty(node)) { 434 node = createReference(node as ts.PropertyAssignment, log, isBuilder); 435 } 436 if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.name) && 437 stateObjectCollection.has(checkStateName(node)) && node.parent && ts.isCallExpression(node.parent) && 438 ts.isPropertyAccessExpression(node.parent.expression) && node !== node.parent.expression && 439 node.parent.expression.name.escapedText.toString() !== FOREACH_GET_RAW_OBJECT) { 440 return ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression( 441 ts.factory.createIdentifier(FOREACH_OBSERVED_OBJECT), 442 ts.factory.createIdentifier(FOREACH_GET_RAW_OBJECT)), undefined, [node]); 443 } 444 return ts.visitEachChild(node, visitBuild, context); 445 } 446 function checkStateName(node: ts.PropertyAccessExpression): string { 447 if (node.expression && !node.expression.expression && node.name && ts.isIdentifier(node.name)) { 448 return node.name.escapedText.toString(); 449 } 450 return null; 451 } 452} 453 454function isGeometryView(node: ts.Node): boolean { 455 if (ts.isExpressionStatement(node) && ts.isCallExpression(node.expression)) { 456 const call: ts.CallExpression = node.expression; 457 const exp: ts.Expression = call.expression; 458 const args: ts.NodeArray<ts.Expression> = call.arguments; 459 if (ts.isPropertyAccessExpression(exp) && ts.isIdentifier(exp.expression) && 460 exp.expression.escapedText.toString() === GEOMETRY_VIEW && ts.isIdentifier(exp.name) && 461 exp.name.escapedText.toString() === COMPONENT_CREATE_FUNCTION && args && args.length === 1 && 462 (ts.isArrowFunction(args[0]) || ts.isFunctionExpression(args[0]))) { 463 return true; 464 } 465 } 466 return false; 467} 468 469function processGeometryView(node: ts.ExpressionStatement, 470 log: LogInfo[]): ts.ExpressionStatement { 471 const exp: ts.CallExpression = node.expression as ts.CallExpression; 472 const arg: ts.ArrowFunction | ts.FunctionExpression = 473 exp.arguments[0] as ts.ArrowFunction | ts.FunctionExpression; 474 return ts.factory.updateExpressionStatement(node, ts.factory.updateCallExpression(exp, 475 exp.expression, undefined, [ts.factory.createArrowFunction(undefined, undefined, arg.parameters, 476 undefined, ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), 477 getGeometryReaderFunctionBlock(arg, log))])); 478} 479 480function getGeometryReaderFunctionBlock(node: ts.ArrowFunction | ts.FunctionExpression, 481 log: LogInfo[]): ts.Block { 482 let blockNode: ts.Block; 483 if (ts.isBlock(node.body)) { 484 blockNode = node.body; 485 } else if (ts.isArrowFunction(node) && ts.isCallExpression(node.body)) { 486 blockNode = ts.factory.createBlock([ts.factory.createExpressionStatement(node.body)]); 487 } 488 return processComponentBlock(blockNode, false, log); 489} 490 491function updateHeritageClauses(node: ts.StructDeclaration, log: LogInfo[]) 492 : ts.NodeArray<ts.HeritageClause> { 493 if (node.heritageClauses && !checkHeritageClauses(node)) { 494 log.push({ 495 type: LogType.ERROR, 496 message: 'The struct component is not allowed to extends other class or implements other interface.', 497 pos: node.heritageClauses.pos 498 }); 499 } 500 const result:ts.HeritageClause[] = []; 501 const heritageClause:ts.HeritageClause = createHeritageClause(); 502 result.push(heritageClause); 503 return ts.factory.createNodeArray(result); 504} 505 506function checkHeritageClauses(node: ts.StructDeclaration): boolean { 507 if (node.heritageClauses.length === 1 && node.heritageClauses[0].types && 508 node.heritageClauses[0].types.length === 1) { 509 const expressionNode: ts.ExpressionWithTypeArguments = node.heritageClauses[0].types[0]; 510 if (expressionNode.expression && ts.isIdentifier(expressionNode.expression) && 511 expressionNode.expression.escapedText.toString() === CUSTOM_COMPONENT) { 512 return true; 513 } 514 } 515 return false; 516} 517 518export function isProperty(node: ts.Node): Boolean { 519 if (judgmentParentType(node)) { 520 if (node.parent.parent.expression && ts.isIdentifier(node.parent.parent.expression) && 521 !BUILDIN_STYLE_NAMES.has(node.parent.parent.expression.escapedText.toString()) && 522 componentCollection.customComponents.has( 523 node.parent.parent.expression.escapedText.toString())) { 524 return true; 525 } else if (ts.isPropertyAccessExpression(node.parent.parent.expression) && 526 ts.isIdentifier(node.parent.parent.expression.expression) && 527 componentCollection.customComponents.has( 528 node.parent.parent.expression.name.escapedText.toString())) { 529 return true; 530 } 531 } 532 return false; 533} 534 535function judgmentParentType(node: ts.Node): boolean { 536 return ts.isPropertyAssignment(node) && node.name && ts.isIdentifier(node.name) && 537 node.parent && ts.isObjectLiteralExpression(node.parent) && node.parent.parent && 538 (ts.isCallExpression(node.parent.parent) || ts.isEtsComponentExpression(node.parent.parent)); 539} 540 541export function createReference(node: ts.PropertyAssignment, log: LogInfo[], isBuilder = false): ts.PropertyAssignment { 542 const linkParentComponent: string[] = getParentNode(node, linkCollection).slice(1); 543 const propParentComponent: string[] = getParentNode(node, propCollection).slice(1); 544 const propertyName: ts.Identifier = node.name as ts.Identifier; 545 let initText: string; 546 const LINK_REG: RegExp = /^\$/g; 547 const initExpression: ts.Expression = node.initializer; 548 let is$$: boolean = false; 549 if (ts.isIdentifier(initExpression) && 550 initExpression.escapedText.toString().match(LINK_REG)) { 551 initText = initExpression.escapedText.toString().replace(LINK_REG, ''); 552 } else if (ts.isPropertyAccessExpression(initExpression) && initExpression.expression && 553 initExpression.expression.kind === ts.SyntaxKind.ThisKeyword && 554 ts.isIdentifier(initExpression.name) && initExpression.name.escapedText.toString().match(LINK_REG)) { 555 initText = initExpression.name.escapedText.toString().replace(LINK_REG, ''); 556 } else if (isBuilder && ts.isPropertyAccessExpression(initExpression) && initExpression.expression && 557 ts.isIdentifier(initExpression.expression) && initExpression.expression.escapedText.toString() === $$ && 558 ts.isIdentifier(initExpression.name) && linkParentComponent.includes(propertyName.escapedText.toString())) { 559 is$$ = true; 560 initText = initExpression.name.escapedText.toString(); 561 } else if (isMatchInitExpression(initExpression) && 562 linkParentComponent.includes(propertyName.escapedText.toString())) { 563 initText = initExpression.name.escapedText.toString().replace(LINK_REG, ''); 564 } 565 if (initText) { 566 node = addDoubleUnderline(node, propertyName, initText, is$$); 567 } 568 return node; 569} 570 571function isMatchInitExpression(initExpression: ts.Expression): boolean { 572 return ts.isPropertyAccessExpression(initExpression) && 573 initExpression.expression && 574 initExpression.expression.kind === ts.SyntaxKind.ThisKeyword && 575 ts.isIdentifier(initExpression.name); 576} 577 578function addDoubleUnderline(node: ts.PropertyAssignment, propertyName: ts.Identifier, 579 initText: string, is$$ = false): ts.PropertyAssignment { 580 return ts.factory.updatePropertyAssignment(node, propertyName, 581 ts.factory.createPropertyAccessExpression( 582 is$$ && partialUpdateConfig.partialUpdateMode ? ts.factory.createIdentifier($$) : ts.factory.createThis(), 583 ts.factory.createIdentifier(`__${initText}`))); 584} 585 586function getParentNode(node: ts.PropertyAssignment, collection: Map<string, Set<string>>): string[] { 587 const grandparentNode: ts.NewExpression = node.parent.parent as ts.NewExpression; 588 const grandparentExpression: ts.Identifier | ts.PropertyAccessExpression = 589 grandparentNode.expression as ts.Identifier | ts.PropertyAccessExpression; 590 let parentComponent: Set<string> = new Set(); 591 let grandparentName: string; 592 if (ts.isIdentifier(grandparentExpression)) { 593 grandparentName = grandparentExpression.escapedText.toString(); 594 parentComponent = collection.get(grandparentName); 595 } else if (ts.isPropertyAccessExpression(grandparentExpression)) { 596 grandparentName = grandparentExpression.name.escapedText.toString(); 597 parentComponent = collection.get(grandparentName); 598 } else { 599 // ignore 600 } 601 if (!parentComponent) { 602 parentComponent = new Set(); 603 } 604 return [grandparentName, ...parentComponent]; 605} 606 607function addUpdateParamsFunc(statements: ts.Statement[], parentComponentName: ts.Identifier): 608 ts.MethodDeclaration { 609 return createParamsInitBlock(COMPONENT_CONSTRUCTOR_UPDATE_PARAMS, statements, parentComponentName); 610} 611 612function addInitialParamsFunc(statements: ts.Statement[], parentComponentName: ts.Identifier): ts.MethodDeclaration { 613 return createParamsInitBlock(COMPONENT_CONSTRUCTOR_INITIAL_PARAMS, statements, parentComponentName); 614} 615 616function addUpdateStateVarsFunc(statements: ts.Statement[], parentComponentName: ts.Identifier): ts.MethodDeclaration { 617 return createParamsInitBlock(COMPONENT_UPDATE_STATE_VARS, statements, parentComponentName); 618} 619 620function addPurgeVariableDepFunc(statements: ts.Statement[]): ts.MethodDeclaration { 621 return ts.factory.createMethodDeclaration( 622 undefined, undefined, undefined, 623 ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PURGE_VARIABLE_DEP), 624 undefined, undefined, [ts.factory.createParameterDeclaration(undefined, undefined, undefined, 625 ts.factory.createIdentifier(RMELMTID), undefined, undefined, undefined)], undefined, 626 ts.factory.createBlock(statements, true)); 627} 628 629function addDeleteParamsFunc(statements: ts.PropertyDeclaration[]): ts.MethodDeclaration { 630 const deleteStatements: ts.ExpressionStatement[] = []; 631 statements.forEach((statement: ts.PropertyDeclaration) => { 632 const name: ts.Identifier = statement.name as ts.Identifier; 633 let paramsStatement: ts.ExpressionStatement; 634 if (!partialUpdateConfig.partialUpdateMode || statement.decorators) { 635 paramsStatement = createParamsWithUnderlineStatement(name); 636 } 637 deleteStatements.push(paramsStatement); 638 }); 639 const defaultStatement: ts.ExpressionStatement = 640 ts.factory.createExpressionStatement(ts.factory.createCallExpression( 641 ts.factory.createPropertyAccessExpression( 642 ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression( 643 ts.factory.createIdentifier(CREATE_CONSTRUCTOR_SUBSCRIBER_MANAGER), 644 ts.factory.createIdentifier(CREATE_CONSTRUCTOR_GET_FUNCTION)), undefined, []), 645 ts.factory.createIdentifier(CREATE_CONSTRUCTOR_DELETE_FUNCTION)), 646 undefined, [ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression( 647 ts.factory.createThis(), ts.factory.createIdentifier( 648 !partialUpdateConfig.partialUpdateMode ? 649 ABOUT_TO_BE_DELETE_FUNCTION_ID : ABOUT_TO_BE_DELETE_FUNCTION_ID__)), 650 undefined, [])])); 651 deleteStatements.push(defaultStatement); 652 if (partialUpdateConfig.partialUpdateMode) { 653 const aboutToBeDeletedInternalStatement: ts.ExpressionStatement = createDeletedInternalStatement(); 654 deleteStatements.push(aboutToBeDeletedInternalStatement); 655 } 656 const deleteParamsMethod: ts.MethodDeclaration = 657 createParamsInitBlock(COMPONENT_CONSTRUCTOR_DELETE_PARAMS, deleteStatements); 658 return deleteParamsMethod; 659} 660 661function createParamsWithUnderlineStatement(name: ts.Identifier): ts.ExpressionStatement { 662 return ts.factory.createExpressionStatement( 663 ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression( 664 ts.factory.createPropertyAccessExpression(ts.factory.createThis(), 665 ts.factory.createIdentifier(`__${name.escapedText.toString()}`)), 666 ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_DELETE_PARAMS)), undefined, [])); 667} 668 669function createDeletedInternalStatement(): ts.ExpressionStatement { 670 return ts.factory.createExpressionStatement(ts.factory.createCallExpression( 671 ts.factory.createPropertyAccessExpression(ts.factory.createThis(), 672 ts.factory.createIdentifier(ABOUTTOBEDELETEDINTERNAL)), undefined, [])); 673} 674 675function addRerenderFunc(statements: ts.Statement[]): ts.MethodDeclaration { 676 let updateDirtyElementStatement: ts.Statement = ts.factory.createExpressionStatement( 677 ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression( 678 ts.factory.createThis(), ts.factory.createIdentifier(UPDATEDIRTYELEMENTS)), undefined, [])); 679 statements.push(updateDirtyElementStatement); 680 return ts.factory.createMethodDeclaration(undefined, undefined, undefined, 681 ts.factory.createIdentifier(COMPONENT_RERENDER_FUNCTION), undefined, undefined, [], undefined, 682 ts.factory.createBlock(statements, true)); 683} 684 685function createParamsInitBlock(express: string, statements: ts.Statement[], 686 parentComponentName?: ts.Identifier): ts.MethodDeclaration { 687 const methodDeclaration: ts.MethodDeclaration = ts.factory.createMethodDeclaration(undefined, 688 undefined, undefined, ts.factory.createIdentifier(express), undefined, undefined, 689 [ts.factory.createParameterDeclaration(undefined, undefined, undefined, 690 express === COMPONENT_CONSTRUCTOR_DELETE_PARAMS ? undefined : 691 ts.factory.createIdentifier(CREATE_CONSTRUCTOR_PARAMS), undefined, 692 express === COMPONENT_CONSTRUCTOR_DELETE_PARAMS ? undefined : 693 ts.factory.createTypeReferenceNode( 694 ts.factory.createIdentifier(parentComponentName.getText() + INTERFACE_NAME_SUFFIX), undefined), 695 undefined)], undefined, ts.factory.createBlock(statements, true)); 696 return methodDeclaration; 697} 698 699function validateBuildMethodCount(buildCount: BuildCount, parentComponentName: ts.Identifier, 700 log: LogInfo[]): void { 701 if (buildCount.count !== 1) { 702 log.push({ 703 type: LogType.ERROR, 704 message: `struct '${parentComponentName.getText()}' must be at least or at most one 'build' method.`, 705 pos: parentComponentName.getStart() 706 }); 707 } 708} 709 710function validateHasController(componentName: ts.Identifier, checkController: ControllerType, 711 log: LogInfo[]): void { 712 if (!checkController.hasController) { 713 log.push({ 714 type: LogType.ERROR, 715 message: '@CustomDialog component should have a property of the CustomDialogController type.', 716 pos: componentName.pos 717 }); 718 } 719} 720 721function createHeritageClause(): ts.HeritageClause { 722 if (partialUpdateConfig.partialUpdateMode) { 723 return ts.factory.createHeritageClause( 724 ts.SyntaxKind.ExtendsKeyword, 725 [ts.factory.createExpressionWithTypeArguments(ts.factory.createIdentifier(BASE_COMPONENT_NAME_PU), [])] 726 ); 727 } 728 return ts.factory.createHeritageClause( 729 ts.SyntaxKind.ExtendsKeyword, 730 [ts.factory.createExpressionWithTypeArguments(ts.factory.createIdentifier(BASE_COMPONENT_NAME), [])] 731 ); 732} 733 734function createTypeReference(decoratorName: string, type: ts.TypeNode, log: LogInfo[], 735 program: ts.Program): ts.TypeNode { 736 let newType: ts.TypeNode; 737 switch (decoratorName) { 738 case COMPONENT_STATE_DECORATOR: 739 case COMPONENT_PROVIDE_DECORATOR: 740 newType = ts.factory.createTypeReferenceNode( 741 isSimpleType(type, program, log) 742 ? OBSERVED_PROPERTY_SIMPLE 743 : OBSERVED_PROPERTY_OBJECT, 744 [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)] 745 ); 746 break; 747 case COMPONENT_LINK_DECORATOR: 748 case COMPONENT_CONSUME_DECORATOR: 749 newType = ts.factory.createTypeReferenceNode( 750 isSimpleType(type, program, log) 751 ? SYNCHED_PROPERTY_SIMPLE_TWO_WAY 752 : SYNCHED_PROPERTY_SIMPLE_ONE_WAY, 753 [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)] 754 ); 755 break; 756 case COMPONENT_PROP_DECORATOR: 757 newType = ts.factory.createTypeReferenceNode( 758 SYNCHED_PROPERTY_SIMPLE_ONE_WAY, 759 [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)] 760 ); 761 break; 762 case COMPONENT_OBJECT_LINK_DECORATOR: 763 newType = ts.factory.createTypeReferenceNode( 764 SYNCHED_PROPERTY_NESED_OBJECT, 765 [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)] 766 ); 767 break; 768 case COMPONENT_STORAGE_PROP_DECORATOR: 769 case COMPONENT_STORAGE_LINK_DECORATOR: 770 newType = ts.factory.createTypeReferenceNode(OBSERVED_PROPERTY_ABSTRACT, [ 771 type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), 772 ]); 773 break; 774 case COMPONENT_LOCAL_STORAGE_LINK_DECORATOR: 775 case COMPONENT_LOCAL_STORAGE_PROP_DECORATOR: 776 newType = ts.factory.createTypeReferenceNode(OBSERVED_PROPERTY_ABSTRACT, [ 777 type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), 778 ]); 779 break; 780 } 781 return newType; 782} 783 784function createTypeReferencePU(decoratorName: string, type: ts.TypeNode, log: LogInfo[], 785 program: ts.Program): ts.TypeNode { 786 let newType: ts.TypeNode; 787 switch (decoratorName) { 788 case COMPONENT_STATE_DECORATOR: 789 case COMPONENT_PROVIDE_DECORATOR: 790 newType = ts.factory.createTypeReferenceNode( 791 isSimpleType(type, program, log) 792 ? OBSERVED_PROPERTY_SIMPLE_PU 793 : OBSERVED_PROPERTY_OBJECT_PU, 794 [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)] 795 ); 796 break; 797 case COMPONENT_LINK_DECORATOR: 798 newType = ts.factory.createTypeReferenceNode( 799 isSimpleType(type, program, log) 800 ? SYNCHED_PROPERTY_SIMPLE_TWO_WAY_PU 801 : SYNCHED_PROPERTY_SIMPLE_ONE_WAY_PU, 802 [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)] 803 ); 804 break; 805 case COMPONENT_PROP_DECORATOR: 806 newType = ts.factory.createTypeReferenceNode( 807 SYNCHED_PROPERTY_SIMPLE_ONE_WAY_PU, 808 [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)] 809 ); 810 break; 811 case COMPONENT_OBJECT_LINK_DECORATOR: 812 newType = ts.factory.createTypeReferenceNode( 813 SYNCHED_PROPERTY_NESED_OBJECT_PU, 814 [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)] 815 ); 816 break; 817 case COMPONENT_CONSUME_DECORATOR: 818 case COMPONENT_STORAGE_PROP_DECORATOR: 819 case COMPONENT_STORAGE_LINK_DECORATOR: 820 newType = ts.factory.createTypeReferenceNode(OBSERVED_PROPERTY_ABSTRACT_PU, [ 821 type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), 822 ]); 823 break; 824 case COMPONENT_LOCAL_STORAGE_LINK_DECORATOR: 825 case COMPONENT_LOCAL_STORAGE_PROP_DECORATOR: 826 newType = ts.factory.createTypeReferenceNode(OBSERVED_PROPERTY_ABSTRACT_PU, [ 827 type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), 828 ]); 829 break; 830 } 831 return newType; 832} 833