• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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}