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