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_CONSTRUCTOR_ID, 20 COMPONENT_CONSTRUCTOR_PARENT, 21 COMPONENT_CONSTRUCTOR_PARAMS, 22 COMPONENT_CONSTRUCTOR_UPDATE_PARAMS, 23 COMPONENT_WATCH_FUNCTION, 24 BASE_COMPONENT_NAME, 25 INTERFACE_NAME_SUFFIX, 26 COMPONENT_CONSTRUCTOR_LOCALSTORAGE 27} from './pre_define'; 28 29import { 30 localStorageLinkCollection, 31 localStoragePropCollection 32} from './validate_ui_syntax'; 33 34export function getInitConstructor(members: ts.NodeArray<ts.Node>, parentComponentName: ts.Identifier 35 ): ts.ConstructorDeclaration { 36 let ctorNode: any = members.find(item => { 37 return ts.isConstructorDeclaration(item); 38 }); 39 if (ctorNode) { 40 ctorNode = updateConstructor(ctorNode, [], [], true); 41 } 42 return initConstructorParams(ctorNode, parentComponentName); 43} 44 45export function updateConstructor(ctorNode: ts.ConstructorDeclaration,para: ts.ParameterDeclaration[], 46 addStatements: ts.Statement[], isSuper: boolean = false, isAdd: boolean = false, 47 parentComponentName?: ts.Identifier): ts.ConstructorDeclaration { 48 let modifyPara: ts.ParameterDeclaration[]; 49 if (para && para.length) { 50 modifyPara = Array.from(ctorNode.parameters); 51 if (modifyPara) { 52 modifyPara.push(...para); 53 } 54 } 55 let modifyBody: ts.Statement[]; 56 if (addStatements && addStatements.length && ctorNode) { 57 modifyBody = Array.from(ctorNode.body.statements); 58 if (modifyBody) { 59 if (isSuper) { 60 modifyBody.unshift(...addStatements); 61 } else { 62 modifyBody.push(...addStatements); 63 } 64 } 65 } 66 if (ctorNode) { 67 let ctorPara: ts.ParameterDeclaration[] | ts.NodeArray<ts.ParameterDeclaration> = 68 modifyPara || ctorNode.parameters; 69 if (isAdd) { 70 ctorPara = addParamsType(ctorNode, modifyPara, parentComponentName); 71 } 72 ctorNode = ts.factory.updateConstructorDeclaration(ctorNode, ctorNode.decorators, 73 ctorNode.modifiers, modifyPara || ctorNode.parameters, 74 ts.factory.createBlock(modifyBody || ctorNode.body.statements, true)); 75 } 76 return ctorNode; 77} 78 79function initConstructorParams(node: ts.ConstructorDeclaration, parentComponentName: ts.Identifier): 80 ts.ConstructorDeclaration { 81 if (!ts.isIdentifier(parentComponentName)) { 82 return; 83 } 84 const localStorageNum: number = localStorageLinkCollection.get(parentComponentName.getText()).size + 85 localStoragePropCollection.get(parentComponentName.getText()).size; 86 const paramNames: Set<string> = new Set([COMPONENT_CONSTRUCTOR_ID, COMPONENT_CONSTRUCTOR_PARENT, 87 COMPONENT_CONSTRUCTOR_PARAMS, localStorageNum ? COMPONENT_CONSTRUCTOR_LOCALSTORAGE : 88 COMPONENT_CONSTRUCTOR_PARAMS]); 89 const newParameters: ts.ParameterDeclaration[] = Array.from(node.parameters); 90 if (newParameters.length !== 0) { 91 // @ts-ignore 92 newParameters.splice(0, newParameters.length); 93 } 94 paramNames.forEach((paramName: string) => { 95 // @ts-ignore 96 newParameters.push(ts.factory.createParameterDeclaration(undefined, undefined, undefined, 97 ts.factory.createIdentifier(paramName), undefined, undefined, undefined)); 98 }); 99 100 return ts.factory.updateConstructorDeclaration(node, undefined, node.modifiers, newParameters, 101 node.body); 102} 103 104function addParamsType(ctorNode: ts.ConstructorDeclaration, modifyPara: ts.ParameterDeclaration[], 105 parentComponentName: ts.Identifier): ts.ParameterDeclaration[] { 106 const tsPara: ts.ParameterDeclaration[] | ts.NodeArray<ts.ParameterDeclaration> = 107 modifyPara || ctorNode.parameters; 108 const newTSPara: ts.ParameterDeclaration[] = []; 109 tsPara.forEach((item) => { 110 let parameter: ts.ParameterDeclaration = item; 111 switch (item.name.escapedText) { 112 case COMPONENT_CONSTRUCTOR_ID: 113 parameter = ts.factory.updateParameterDeclaration(item, item.decorators, item.modifiers, 114 item.dotDotDotToken, item.name, item.questionToken, 115 ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), item.initializer); 116 break; 117 case COMPONENT_CONSTRUCTOR_PARENT: 118 parameter = ts.factory.createParameterDeclaration(item.decorators, item.modifiers, 119 item.dotDotDotToken, item.name, item.questionToken, 120 ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(BASE_COMPONENT_NAME), undefined), 121 item.initializer); 122 break; 123 case COMPONENT_CONSTRUCTOR_PARAMS: 124 parameter = ts.factory.updateParameterDeclaration(item, item.decorators, item.modifiers, 125 item.dotDotDotToken, item.name, item.questionToken, 126 ts.factory.createTypeReferenceNode(ts.factory.createIdentifier( 127 parentComponentName.getText() + INTERFACE_NAME_SUFFIX), undefined), item.initializer); 128 break; 129 } 130 newTSPara.push(parameter); 131 }) 132 return newTSPara; 133} 134 135export function addConstructor(ctorNode: any, watchMap: Map<string, ts.Node>, 136 parentComponentName: ts.Identifier): ts.ConstructorDeclaration { 137 const watchStatements: ts.ExpressionStatement[] = []; 138 const localStorageNum: number = localStorageLinkCollection.get(parentComponentName.getText()).size + 139 localStoragePropCollection.get(parentComponentName.getText()).size; 140 watchMap.forEach((value, key) => { 141 const watchNode: ts.ExpressionStatement = ts.factory.createExpressionStatement( 142 ts.factory.createCallExpression( 143 ts.factory.createPropertyAccessExpression( 144 ts.factory.createThis(), 145 ts.factory.createIdentifier(COMPONENT_WATCH_FUNCTION) 146 ), 147 undefined, 148 [ 149 ts.factory.createStringLiteral(key), 150 ts.isStringLiteral(value) ? 151 ts.factory.createPropertyAccessExpression(ts.factory.createThis(), 152 ts.factory.createIdentifier(value.text)) : value as ts.PropertyAccessExpression 153 ] 154 )); 155 watchStatements.push(watchNode); 156 }); 157 const callSuperStatement: ts.Statement = ts.factory.createExpressionStatement( 158 ts.factory.createCallExpression(ts.factory.createSuper(), undefined, 159 localStorageNum ? 160 [ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_ID), 161 ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARENT), 162 ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_LOCALSTORAGE)] : 163 [ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_ID), 164 ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARENT)] 165 )); 166 const updateWithValueParamsStatement: ts.Statement = ts.factory.createExpressionStatement( 167 ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression( 168 ts.factory.createThis(), ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UPDATE_PARAMS)), 169 undefined, [ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARAMS)])); 170 return updateConstructor(updateConstructor(ctorNode, [], [callSuperStatement], true), [], 171 [updateWithValueParamsStatement, ...watchStatements], false, true, parentComponentName); 172} 173