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_DELETE_PARAMS, 37 COMPONENT_DECORATOR_PREVIEW, 38 CREATE_CONSTRUCTOR_SUBSCRIBER_MANAGER, 39 ABOUT_TO_BE_DELETE_FUNCTION_ID, 40 CREATE_CONSTRUCTOR_GET_FUNCTION, 41 CREATE_CONSTRUCTOR_DELETE_FUNCTION, 42 FOREACH_OBSERVED_OBJECT, 43 FOREACH_GET_RAW_OBJECT, 44 COMPONENT_BUILDER_DECORATOR, 45 COMPONENT_TRANSITION_FUNCTION, 46 COMPONENT_CREATE_FUNCTION, 47 GEOMETRY_VIEW, 48 COMPONENT_STYLES_DECORATOR, 49 STYLES, 50 INTERFACE_NAME_SUFFIX, 51 OBSERVED_PROPERTY_ABSTRACT, 52 COMPONENT_LOCAL_STORAGE_LINK_DECORATOR, 53 COMPONENT_LOCAL_STORAGE_PROP_DECORATOR, 54 COMPONENT_CONSTRUCTOR_LOCALSTORAGE, 55 COMPONENT_SET_AND_LINK, 56 COMPONENT_SET_AND_PROP, 57 COMPONENT_CONSTRUCTOR_UNDEFINED 58} from './pre_define'; 59import { 60 BUILDIN_STYLE_NAMES, 61 CUSTOM_BUILDER_METHOD, 62 INNER_STYLE_FUNCTION, 63 INTERFACE_NODE_SET, 64 STYLES_ATTRIBUTE 65} from './component_map'; 66import { 67 componentCollection, 68 linkCollection, 69 localStorageLinkCollection, 70 localStoragePropCollection 71} from './validate_ui_syntax'; 72import { 73 addConstructor, 74 getInitConstructor 75} from './process_component_constructor'; 76import { 77 ControllerType, 78 processMemberVariableDecorators, 79 UpdateResult, 80 stateObjectCollection, 81 curPropMap, 82 decoratorParamSet, 83 isSimpleType 84} from './process_component_member'; 85import { 86 processComponentBuild, 87 processComponentBlock 88} from './process_component_build'; 89import { 90 LogType, 91 LogInfo, 92 hasDecorator 93} from './utils'; 94 95export function processComponentClass(node: ts.StructDeclaration, context: ts.TransformationContext, 96 log: LogInfo[], program: ts.Program): ts.ClassDeclaration { 97 validateInheritClass(node, log); 98 const memberNode: ts.ClassElement[] = 99 processMembers(node.members, node.name, context, log, program, checkPreview(node)); 100 return ts.factory.createClassDeclaration(undefined, node.modifiers, node.name, 101 node.typeParameters, updateHeritageClauses(node), memberNode); 102} 103 104function checkPreview(node: ts.ClassDeclaration) { 105 let hasPreview: boolean = false; 106 if (node && node.decorators) { 107 for (let i = 0; i < node.decorators.length; i++) { 108 const name: string = node.decorators[i].getText().replace(/\([^\(\)]*\)/, '').trim(); 109 if (name === COMPONENT_DECORATOR_PREVIEW) { 110 hasPreview = true; 111 break; 112 } 113 } 114 } 115 return hasPreview; 116} 117 118type BuildCount = { 119 count: number; 120} 121 122function processMembers(members: ts.NodeArray<ts.ClassElement>, parentComponentName: ts.Identifier, 123 context: ts.TransformationContext, log: LogInfo[], program: ts.Program, hasPreview: boolean): ts.ClassElement[] { 124 const buildCount: BuildCount = { count: 0 }; 125 let ctorNode: any = getInitConstructor(members, parentComponentName); 126 const newMembers: ts.ClassElement[] = []; 127 const watchMap: Map<string, ts.Node> = new Map(); 128 const updateParamsStatements: ts.Statement[] = []; 129 const deleteParamsStatements: ts.PropertyDeclaration[] = []; 130 const checkController: ControllerType = 131 { hasController: !componentCollection.customDialogs.has(parentComponentName.getText()) }; 132 const interfaceNode = ts.factory.createInterfaceDeclaration(undefined, undefined, 133 parentComponentName.getText() + INTERFACE_NAME_SUFFIX, undefined, undefined, []); 134 members.forEach((item: ts.ClassElement) => { 135 let updateItem: ts.ClassElement; 136 if (ts.isPropertyDeclaration(item)) { 137 addPropertyMember(item, newMembers, program, parentComponentName.getText(), log); 138 const result: UpdateResult = processMemberVariableDecorators(parentComponentName, item, 139 ctorNode, watchMap, checkController, log, program, context, hasPreview, interfaceNode); 140 if (result.isItemUpdate()) { 141 updateItem = result.getProperity(); 142 } else { 143 updateItem = item; 144 } 145 if (result.getVariableGet()) { 146 newMembers.push(result.getVariableGet()); 147 } 148 if (result.getVariableSet()) { 149 newMembers.push(result.getVariableSet()); 150 } 151 if (result.isCtorUpdate()) { 152 ctorNode = result.getCtor(); 153 } 154 if (result.getUpdateParams()) { 155 updateParamsStatements.push(result.getUpdateParams()); 156 } 157 if (result.isDeleteParams()) { 158 deleteParamsStatements.push(item); 159 } 160 if (result.getControllerSet()) { 161 newMembers.push(result.getControllerSet()); 162 } 163 } 164 if (ts.isMethodDeclaration(item) && item.name) { 165 updateItem = 166 processComponentMethod(item, parentComponentName, context, log, buildCount); 167 } 168 if (updateItem) { 169 newMembers.push(updateItem); 170 } 171 }); 172 INTERFACE_NODE_SET.add(interfaceNode); 173 validateBuildMethodCount(buildCount, parentComponentName, log); 174 validateHasController(parentComponentName, checkController, log); 175 newMembers.unshift(addDeleteParamsFunc(deleteParamsStatements)); 176 newMembers.unshift(addUpdateParamsFunc(updateParamsStatements, parentComponentName)); 177 newMembers.unshift(addConstructor(ctorNode, watchMap, parentComponentName)); 178 return newMembers; 179} 180 181function addPropertyMember(item: ts.ClassElement, newMembers: ts.ClassElement[], 182 program: ts.Program, parentComponentName: string, log: LogInfo[]): void { 183 const propertyItem: ts.PropertyDeclaration = item as ts.PropertyDeclaration; 184 let decoratorName: string; 185 let updatePropertyItem: ts.PropertyDeclaration; 186 const type: ts.TypeNode = propertyItem.type; 187 if (!propertyItem.decorators || propertyItem.decorators.length === 0) { 188 updatePropertyItem = createPropertyDeclaration(propertyItem, type, true); 189 newMembers.push(updatePropertyItem); 190 } else if (propertyItem.decorators) { 191 for (let i = 0; i < propertyItem.decorators.length; i++) { 192 let newType: ts.TypeNode; 193 decoratorName = propertyItem.decorators[i].getText().replace(/\(.*\)$/, '').trim(); 194 let isLocalStorage: boolean = false; 195 switch (decoratorName) { 196 case COMPONENT_STATE_DECORATOR: 197 case COMPONENT_PROVIDE_DECORATOR: 198 newType = ts.factory.createTypeReferenceNode(isSimpleType(type, program, log) ? 199 OBSERVED_PROPERTY_SIMPLE : OBSERVED_PROPERTY_OBJECT, [type || 200 ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)]); 201 break; 202 case COMPONENT_LINK_DECORATOR: 203 case COMPONENT_CONSUME_DECORATOR: 204 newType = ts.factory.createTypeReferenceNode(isSimpleType(type, program, log) ? 205 SYNCHED_PROPERTY_SIMPLE_TWO_WAY : SYNCHED_PROPERTY_SIMPLE_ONE_WAY, [type || 206 ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)]); 207 break; 208 case COMPONENT_PROP_DECORATOR: 209 newType = ts.factory.createTypeReferenceNode(SYNCHED_PROPERTY_SIMPLE_ONE_WAY, [type || 210 ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)]); 211 break; 212 case COMPONENT_OBJECT_LINK_DECORATOR: 213 newType = ts.factory.createTypeReferenceNode(SYNCHED_PROPERTY_NESED_OBJECT, [type || 214 ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)]); 215 break; 216 case COMPONENT_STORAGE_PROP_DECORATOR: 217 case COMPONENT_STORAGE_LINK_DECORATOR: 218 newType = ts.factory.createTypeReferenceNode(OBSERVED_PROPERTY_ABSTRACT, [type || 219 ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)]); 220 break; 221 case COMPONENT_LOCAL_STORAGE_LINK_DECORATOR: 222 case COMPONENT_LOCAL_STORAGE_PROP_DECORATOR: 223 newType = ts.factory.createTypeReferenceNode(OBSERVED_PROPERTY_ABSTRACT, [type || 224 ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)]); 225 isLocalStorage = true; 226 break; 227 } 228 updatePropertyItem = createPropertyDeclaration(propertyItem, newType, false, 229 isLocalStorage, parentComponentName); 230 if (updatePropertyItem) { 231 newMembers.push(updatePropertyItem); 232 } 233 } 234 } 235} 236 237function createPropertyDeclaration(propertyItem: ts.PropertyDeclaration, newType: ts.TypeNode | undefined, 238 normalVar: boolean, isLocalStorage: boolean = false, parentComponentName: string = null): ts.PropertyDeclaration { 239 if (typeof newType === undefined) { 240 return undefined; 241 } 242 let prefix: string = ''; 243 if (!normalVar) { 244 prefix = '__'; 245 } 246 const privateM: ts.ModifierToken<ts.SyntaxKind.PrivateKeyword> = 247 ts.factory.createModifier(ts.SyntaxKind.PrivateKeyword); 248 return ts.factory.updatePropertyDeclaration(propertyItem, undefined, 249 propertyItem.modifiers || [privateM], prefix + propertyItem.name.getText(), 250 propertyItem.questionToken, newType, isLocalStorage ? 251 createLocalStroageCallExpression(propertyItem, propertyItem.name.getText(), 252 parentComponentName) : undefined); 253} 254 255function createLocalStroageCallExpression(node: ts.PropertyDeclaration, name: string, 256 parentComponentName: string): ts.CallExpression { 257 const localStorageLink: Set<string> = localStorageLinkCollection.get(parentComponentName).get(name); 258 const localStorageProp: Set<string> = localStoragePropCollection.get(parentComponentName).get(name); 259 return ts.factory.createCallExpression( 260 ts.factory.createPropertyAccessExpression( 261 ts.factory.createPropertyAccessExpression( 262 ts.factory.createThis(), 263 ts.factory.createIdentifier(`${COMPONENT_CONSTRUCTOR_LOCALSTORAGE}_`) 264 ), 265 ts.factory.createIdentifier(localStorageLink && !localStorageProp ? COMPONENT_SET_AND_LINK : 266 COMPONENT_SET_AND_PROP) 267 ), 268 [node.type], 269 [ 270 ts.factory.createStringLiteral(localStorageLink && !localStorageProp ? 271 Array.from(localStorageLink)[0] : !localStorageLink && localStorageProp ? 272 Array.from(localStorageProp)[0] : COMPONENT_CONSTRUCTOR_UNDEFINED), 273 ts.factory.createNumericLiteral(node.initializer ? node.initializer.getText() : 274 COMPONENT_CONSTRUCTOR_UNDEFINED), ts.factory.createThis(), 275 ts.factory.createStringLiteral(name || COMPONENT_CONSTRUCTOR_UNDEFINED) 276 ] 277 ); 278} 279 280function processComponentMethod(node: ts.MethodDeclaration, parentComponentName: ts.Identifier, 281 context: ts.TransformationContext, log: LogInfo[], buildCount: BuildCount): ts.MethodDeclaration { 282 let updateItem: ts.MethodDeclaration = node; 283 const name: string = node.name.getText(); 284 if (name === COMPONENT_BUILD_FUNCTION) { 285 buildCount.count = buildCount.count + 1; 286 updateItem = processBuildMember(node, context, log); 287 curPropMap.clear(); 288 } else if (node.body && ts.isBlock(node.body)) { 289 if (name === COMPONENT_TRANSITION_FUNCTION) { 290 updateItem = ts.factory.updateMethodDeclaration(node, node.decorators, node.modifiers, 291 node.asteriskToken, node.name, node.questionToken, node.typeParameters, node.parameters, 292 node.type, processComponentBlock(node.body, false, log, true)); 293 } else if (hasDecorator(node, COMPONENT_BUILDER_DECORATOR)) { 294 CUSTOM_BUILDER_METHOD.add(name); 295 updateItem = ts.factory.updateMethodDeclaration(node, undefined, node.modifiers, 296 node.asteriskToken, node.name, node.questionToken, node.typeParameters, node.parameters, 297 node.type, processComponentBlock(node.body, false, log)); 298 } else if (hasDecorator(node, COMPONENT_STYLES_DECORATOR)) { 299 if (node.parameters && node.parameters.length === 0) { 300 if (ts.isBlock(node.body) && node.body.statements && node.body.statements.length) { 301 INNER_STYLE_FUNCTION.set(name, node.body); 302 STYLES_ATTRIBUTE.add(name); 303 BUILDIN_STYLE_NAMES.add(name); 304 decoratorParamSet.add(STYLES); 305 } 306 } else { 307 log.push({ 308 type: LogType.ERROR, 309 message: `@Styles can't have parameters.`, 310 pos: node.getStart() 311 }); 312 } 313 return; 314 } 315 } 316 return updateItem; 317} 318 319function processBuildMember(node: ts.MethodDeclaration, context: ts.TransformationContext, 320 log: LogInfo[]): ts.MethodDeclaration { 321 if (node.parameters.length) { 322 log.push({ 323 type: LogType.ERROR, 324 message: `The 'build' method can not have arguments.`, 325 pos: node.getStart() 326 }); 327 } 328 const buildNode: ts.MethodDeclaration = processComponentBuild(node, log); 329 return ts.visitNode(buildNode, visitBuild); 330 function visitBuild(node: ts.Node): ts.Node { 331 if (isGeometryView(node)) { 332 node = processGeometryView(node as ts.ExpressionStatement, log); 333 } 334 if (isProperty(node)) { 335 node = createReference(node as ts.PropertyAssignment); 336 } 337 if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.name) && 338 stateObjectCollection.has(node.name.escapedText.toString()) && node.parent && 339 ts.isCallExpression(node.parent) && ts.isPropertyAccessExpression(node.parent.expression) && 340 node.parent.expression.name.escapedText.toString() !== FOREACH_GET_RAW_OBJECT) { 341 return ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression( 342 ts.factory.createIdentifier(FOREACH_OBSERVED_OBJECT), 343 ts.factory.createIdentifier(FOREACH_GET_RAW_OBJECT)), undefined, [node]); 344 } 345 return ts.visitEachChild(node, visitBuild, context); 346 } 347} 348 349function isGeometryView(node: ts.Node): boolean { 350 if (ts.isExpressionStatement(node) && ts.isCallExpression(node.expression)) { 351 const call: ts.CallExpression = node.expression; 352 const exp: ts.Expression = call.expression; 353 const args: ts.NodeArray<ts.Expression> = call.arguments; 354 if (ts.isPropertyAccessExpression(exp) && ts.isIdentifier(exp.expression) && 355 exp.expression.escapedText.toString() === GEOMETRY_VIEW && ts.isIdentifier(exp.name) && 356 exp.name.escapedText.toString() === COMPONENT_CREATE_FUNCTION && args && args.length === 1 && 357 (ts.isArrowFunction(args[0]) || ts.isFunctionExpression(args[0]))) { 358 return true; 359 } 360 } 361 return false; 362} 363 364function processGeometryView(node: ts.ExpressionStatement, 365 log: LogInfo[]): ts.ExpressionStatement { 366 const exp: ts.CallExpression = node.expression as ts.CallExpression; 367 const arg: ts.ArrowFunction | ts.FunctionExpression = 368 exp.arguments[0] as ts.ArrowFunction | ts.FunctionExpression; 369 return ts.factory.updateExpressionStatement(node, ts.factory.updateCallExpression(exp, 370 exp.expression, undefined, [ts.factory.createArrowFunction(undefined, undefined, arg.parameters, 371 undefined, ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), 372 getGeometryReaderFunctionBlock(arg, log))])); 373} 374 375function getGeometryReaderFunctionBlock(node: ts.ArrowFunction | ts.FunctionExpression, 376 log: LogInfo[]): ts.Block { 377 let blockNode: ts.Block; 378 if (ts.isBlock(node.body)) { 379 blockNode = node.body; 380 } else if (ts.isArrowFunction(node) && ts.isCallExpression(node.body)) { 381 blockNode = ts.factory.createBlock([ts.factory.createExpressionStatement(node.body)]); 382 } 383 return processComponentBlock(blockNode, false, log); 384} 385 386function updateHeritageClauses(node: ts.StructDeclaration): ts.NodeArray<ts.HeritageClause> { 387 const result:ts.HeritageClause[] = []; 388 const heritageClause:ts.HeritageClause = ts.factory.createHeritageClause( 389 ts.SyntaxKind.ExtendsKeyword, 390 [ts.factory.createExpressionWithTypeArguments( 391 ts.factory.createIdentifier(BASE_COMPONENT_NAME), [])]); 392 393 if (node.heritageClauses) { 394 result.push(...node.heritageClauses); 395 } 396 result.push(heritageClause); 397 398 return ts.factory.createNodeArray(result); 399} 400 401export function isProperty(node: ts.Node): Boolean { 402 if (judgmentParentType(node)) { 403 if (node.parent.parent.expression && ts.isIdentifier(node.parent.parent.expression) && 404 !BUILDIN_STYLE_NAMES.has(node.parent.parent.expression.escapedText.toString()) && 405 componentCollection.customComponents.has( 406 node.parent.parent.expression.escapedText.toString())) { 407 return true; 408 } else if (ts.isPropertyAccessExpression(node.parent.parent.expression) && 409 ts.isIdentifier(node.parent.parent.expression.expression) && 410 componentCollection.customComponents.has( 411 node.parent.parent.expression.name.escapedText.toString())) { 412 return true; 413 } 414 } 415 return false; 416} 417 418function judgmentParentType(node: ts.Node): boolean { 419 return ts.isPropertyAssignment(node) && node.name && ts.isIdentifier(node.name) && 420 node.parent && ts.isObjectLiteralExpression(node.parent) && node.parent.parent && 421 (ts.isCallExpression(node.parent.parent) || ts.isEtsComponentExpression(node.parent.parent)); 422} 423 424export function createReference(node: ts.PropertyAssignment): ts.PropertyAssignment { 425 const linkParentComponent: string[] = getParentNode(node, linkCollection).slice(1); 426 const propertyName: ts.Identifier = node.name as ts.Identifier; 427 let initText: string; 428 const LINK_REG: RegExp = /^\$/g; 429 const initExpression: ts.Expression = node.initializer; 430 if (ts.isIdentifier(initExpression) && 431 initExpression.escapedText.toString().match(LINK_REG)) { 432 initText = initExpression.escapedText.toString().replace(LINK_REG, ''); 433 } else if (ts.isPropertyAccessExpression(initExpression) && initExpression.expression && 434 initExpression.expression.kind === ts.SyntaxKind.ThisKeyword && 435 ts.isIdentifier(initExpression.name) && initExpression.name.escapedText.toString().match(LINK_REG)) { 436 initText = initExpression.name.escapedText.toString().replace(LINK_REG, ''); 437 } else if (isMatchInitExpression(initExpression) && 438 initExpression.name.escapedText.toString().match(LINK_REG) && 439 linkParentComponent.includes(propertyName.escapedText.toString())) { 440 initText = initExpression.name.escapedText.toString().replace(LINK_REG, ''); 441 } 442 if (initText) { 443 node = addDoubleUnderline(node, propertyName, initText); 444 } 445 return node; 446} 447 448function isMatchInitExpression(initExpression: ts.Expression): boolean { 449 return ts.isPropertyAccessExpression(initExpression) && 450 initExpression.expression && 451 initExpression.expression.kind === ts.SyntaxKind.ThisKeyword && 452 ts.isIdentifier(initExpression.name); 453} 454 455function addDoubleUnderline(node: ts.PropertyAssignment, propertyName: ts.Identifier, 456 initText: string): ts.PropertyAssignment { 457 return ts.factory.updatePropertyAssignment(node, propertyName, 458 ts.factory.createPropertyAccessExpression(ts.factory.createThis(), 459 ts.factory.createIdentifier(`__${initText}`))); 460} 461 462function getParentNode(node: ts.PropertyAssignment, collection: Map<string, Set<string>>): string[] { 463 const grandparentNode: ts.NewExpression = node.parent.parent as ts.NewExpression; 464 const grandparentExpression: ts.Identifier | ts.PropertyAccessExpression = 465 grandparentNode.expression as ts.Identifier | ts.PropertyAccessExpression; 466 let parentComponent: Set<string> = new Set(); 467 let grandparentName: string; 468 if (ts.isIdentifier(grandparentExpression)) { 469 grandparentName = grandparentExpression.escapedText.toString(); 470 parentComponent = collection.get(grandparentName); 471 } else if (ts.isPropertyAccessExpression(grandparentExpression)) { 472 grandparentName = grandparentExpression.name.escapedText.toString(); 473 parentComponent = collection.get(grandparentName); 474 } else { 475 // ignore 476 } 477 if (!parentComponent) { 478 parentComponent = new Set(); 479 } 480 return [grandparentName, ...parentComponent]; 481} 482 483function addUpdateParamsFunc(statements: ts.Statement[], parentComponentName: ts.Identifier): 484 ts.MethodDeclaration { 485 return createParamsInitBlock(COMPONENT_CONSTRUCTOR_UPDATE_PARAMS, statements, parentComponentName); 486} 487 488function addDeleteParamsFunc(statements: ts.PropertyDeclaration[]): ts.MethodDeclaration { 489 const deleteStatements: ts.ExpressionStatement[] = []; 490 statements.forEach((statement: ts.PropertyDeclaration) => { 491 const name: ts.Identifier = statement.name as ts.Identifier; 492 const paramsStatement: ts.ExpressionStatement = ts.factory.createExpressionStatement( 493 ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression( 494 ts.factory.createPropertyAccessExpression(ts.factory.createThis(), 495 ts.factory.createIdentifier(`__${name.escapedText.toString()}`)), 496 ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_DELETE_PARAMS)), undefined, [])); 497 deleteStatements.push(paramsStatement); 498 }); 499 const defaultStatement: ts.ExpressionStatement = 500 ts.factory.createExpressionStatement(ts.factory.createCallExpression( 501 ts.factory.createPropertyAccessExpression( 502 ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression( 503 ts.factory.createIdentifier(CREATE_CONSTRUCTOR_SUBSCRIBER_MANAGER), 504 ts.factory.createIdentifier(CREATE_CONSTRUCTOR_GET_FUNCTION)), undefined, []), 505 ts.factory.createIdentifier(CREATE_CONSTRUCTOR_DELETE_FUNCTION)), 506 undefined, [ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression( 507 ts.factory.createThis(), ts.factory.createIdentifier(ABOUT_TO_BE_DELETE_FUNCTION_ID)), 508 undefined, [])])); 509 deleteStatements.push(defaultStatement); 510 const deleteParamsMethod: ts.MethodDeclaration = 511 createParamsInitBlock(COMPONENT_CONSTRUCTOR_DELETE_PARAMS, deleteStatements); 512 return deleteParamsMethod; 513} 514 515function createParamsInitBlock(express: string, statements: ts.Statement[], 516 parentComponentName?: ts.Identifier): ts.MethodDeclaration { 517 const methodDeclaration: ts.MethodDeclaration = ts.factory.createMethodDeclaration(undefined, 518 undefined, undefined, ts.factory.createIdentifier(express), undefined, undefined, 519 [ts.factory.createParameterDeclaration(undefined, undefined, undefined, 520 express === COMPONENT_CONSTRUCTOR_DELETE_PARAMS ? undefined : 521 ts.factory.createIdentifier(CREATE_CONSTRUCTOR_PARAMS), undefined, 522 express === COMPONENT_CONSTRUCTOR_DELETE_PARAMS ? undefined : 523 ts.factory.createTypeReferenceNode( 524 ts.factory.createIdentifier(parentComponentName.getText() + INTERFACE_NAME_SUFFIX), undefined), 525 undefined)], undefined, ts.factory.createBlock(statements, true)); 526 return methodDeclaration; 527} 528 529function validateBuildMethodCount(buildCount: BuildCount, parentComponentName: ts.Identifier, 530 log: LogInfo[]): void { 531 if (buildCount.count !== 1) { 532 log.push({ 533 type: LogType.ERROR, 534 message: `struct '${parentComponentName.getText()}' must be at least or at most one 'build' method.`, 535 pos: parentComponentName.getStart() 536 }); 537 } 538} 539 540function validateInheritClass(node: ts.StructDeclaration, log: LogInfo[]): void { 541 if (node.heritageClauses) { 542 log.push({ 543 type: LogType.ERROR, 544 message: '@Component should not be inherit other Classes.', 545 pos: node.heritageClauses.pos 546 }); 547 } 548} 549 550function validateHasController(componentName: ts.Identifier, checkController: ControllerType, 551 log: LogInfo[]): void { 552 if (!checkController.hasController) { 553 log.push({ 554 type: LogType.ERROR, 555 message: '@CustomDialog component should have a property of the CustomDialogController type.', 556 pos: componentName.pos 557 }); 558 } 559} 560