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