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