• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2021-2022 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
16const ts = require('typescript')
17const path = require('path')
18const fs = require('fs')
19
20const addTSInterfaceSet = ['ForEach', 'LazyForEach', 'TapGesture', 'LongPressGesture', 'LongPressGesture',
21  'PanGesture', 'SwipeGesture', 'PinchGesture', 'RotationGesture', 'GestureGroup','PageTransitionEnter',
22  'PageTransitionExit'];
23const addTSAttributeSet = ['AlphabetIndexer', 'Animator', 'Badge', 'Blank', 'Button', 'Calendar', 'Canvas',
24  'Checkbox', 'CheckboxGroup', 'Circle', 'Column', 'ColumnSplit', 'Counter', 'DataPanel', 'DatePicker',
25  'Divider', 'Ellipse', 'Flex', 'FormComponent', 'Gauge', 'Grid', 'GridItem', 'GridContainer', 'Image',
26  'ImageAnimator', 'Line', 'List', 'ListItem', 'ListItemGroup', 'LoadingProgress', 'Marquee', 'Navigation', 'Navigator',
27  'Panel', 'Path', 'PatternLock', 'Piece', 'PluginComponent', 'Polygon', 'Polyline', 'Progress',
28  'QRCode', 'Radio', 'Rating', 'Rect', 'Refresh', 'Row', 'RowSplit', 'Scroll', 'ScrollBar', 'Search',
29  'Select', 'Shape', 'Sheet', 'Slider', 'Span', 'Stack', 'Stepper', 'StepperItem', 'Swiper',
30  'TabContent', 'Tabs', 'Text', 'TextArea', 'TextClock', 'TextInput', 'TextPicker', 'TextTimer',
31  'Toggle', 'Video', 'Web', 'XComponent', 'RichText', 'RemoteWindow', 'WaterFlow', 'FlowItem'];
32
33generateTargetFile(process.argv[2], process.argv[3]);
34function generateTargetFile(filePath, output) {
35  const files = [];
36  const globalTsFile = path.resolve(filePath, '../../ets/global.d.ts');
37  const featureAbilityPath = path.resolve(filePath, '../../../common/full/featureability.d.ts');
38  const middleTsFile = path.resolve(filePath, 'middle_class.d.ts');
39  if (fs.existsSync(globalTsFile)) {
40    files.push(globalTsFile);
41  }
42  if (fs.existsSync(featureAbilityPath)) {
43    files.push(featureAbilityPath);
44  }
45  readFile(filePath, files);
46  if (!fs.existsSync(output)) {
47    mkDir(output);
48  }
49  const license = `/*
50  * Copyright (c) 2021 Huawei Device Co., Ltd.
51  * Licensed under the Apache License, Version 2.0 (the "License");
52  * you may not use this file except in compliance with the License.
53  * You may obtain a copy of the License at
54  *
55  *     http://www.apache.org/licenses/LICENSE-2.0
56  *
57  * Unless required by applicable law or agreed to in writing, software
58  * distributed under the License is distributed on an "AS IS" BASIS,
59  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
60  * See the License for the specific language governing permissions and
61  * limitations under the License.
62  */`;
63  files.forEach((item) => {
64    let content = fs.readFileSync(item, 'utf8');
65    const fileName = path.resolve(output, path.basename(item));
66    if (item === featureAbilityPath) {
67      content = processsFile(content, fileName, true);
68    } else if (item === globalTsFile) {
69      content = license + '\n\n' + processsFile(content, fileName, true);
70    } else {
71      content = processImportType(content);
72    }
73    fs.writeFile(fileName, content, err => {
74      if (err) {
75        console.error(err);
76        return;
77      }
78    });
79  });
80}
81
82function processImportType(content) {
83  return content.replace(/(import\s*\(("|'))(\.\.\/api\/[^("|')]*("|')\)\.)/g, (item, item1, item2, item3) => {
84    return item1 + '../../' + item3;
85  })
86}
87
88function readFile(dir, fileDir) {
89  const files = fs.readdirSync(dir);
90  files.forEach((element) => {
91    const filePath = path.join(dir, element);
92    const status = fs.statSync(filePath);
93    if (status.isDirectory()) {
94      readFile(filePath, fileDir);
95    } else {
96      fileDir.push(filePath);
97    }
98  });
99}
100
101function mkDir(filePath) {
102  const parent = path.join(filePath, '..');
103  if (!(fs.existsSync(parent) && !fs.statSync(parent).isFile())) {
104    mkDir(parent);
105  }
106  fs.mkdirSync(filePath);
107}
108
109function processsFile(content, fileName, isGlobal) {
110  let sourceFile = ts.createSourceFile(fileName, content, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
111  const newStatements = [];
112  if (sourceFile.statements && sourceFile.statements.length) {
113    if (isGlobal) {
114      sourceFile.statements.forEach((node) => {
115        if (!ts.isImportDeclaration(node)) {
116          if (node.modifiers && node.modifiers.length && node.modifiers[0].kind === ts.SyntaxKind.ExportKeyword) {
117            node.modifiers.splice(0, 1);
118          }
119          if (isVariable(node)) {
120            const name = node.declarationList.declarations[0].name.getText();
121            const type = node.declarationList.declarations[0].type.getText();
122            if (name.indexOf(type) !== -1) {
123              const declarationNode = ts.factory.updateVariableDeclaration(node.declarationList.declarations[0],
124                ts.factory.createIdentifier(type), node.declarationList.declarations[0].exclamationToken,
125                node.declarationList.declarations[0].type, node.declarationList.declarations[0].initializer);
126              node.declarationList = ts.factory.updateVariableDeclarationList(node.declarationList, [declarationNode]);
127            }
128          }
129          newStatements.push(node);
130        }
131      });
132    } else {
133      sourceFile.statements.forEach((node) => {
134        processComponent(node, newStatements);
135      });
136    }
137  }
138  sourceFile = ts.factory.updateSourceFile(sourceFile, newStatements);
139  const printer = ts.createPrinter({ removeComments: false, newLine: ts.NewLineKind.LineFeed });
140  const result = printer.printNode(ts.EmitHint.Unspecified, sourceFile, sourceFile);
141  return result;
142}
143
144function processComponent(node, newStatements) {
145  let extendNode = null;
146  if (isInterface(node)) {
147    const componentName = node.name.getText().replace(/Interface$/, '');
148    const result = validateComponentMembers(node, componentName);
149    if (result.isComponentName) {
150      const heritageClause = ts.factory.createHeritageClause(ts.SyntaxKind.ExtendsKeyword,
151        [ts.factory.createExpressionWithTypeArguments(result.extendNode, undefined)]);
152      extendNode = null;
153      node = ts.factory.updateInterfaceDeclaration(node, node.decorators, node.modifiers,
154        node.name, node.typeParameters, [heritageClause], node.members);
155    }
156    if (addTSInterfaceSet.includes(componentName)) {
157      node = ts.factory.updateInterfaceDeclaration(node, node.decorators, node.modifiers, node.name,
158        node.typeParameters, [ts.factory.createHeritageClause(ts.SyntaxKind.ExtendsKeyword,
159          [ts.factory.createExpressionWithTypeArguments(ts.factory.createIdentifier('TS' + componentName + 'Interface'),
160          undefined)])], node.members);
161    }
162  }
163  if (isClass(node) && addTSAttributeSet.includes(node.name.getText().replace(/Attribute$/, ''))) {
164    node = ts.factory.updateClassDeclaration(node, node.decorators, node.modifiers, node.name,
165      node.typeParameters, [ts.factory.createHeritageClause(ts.SyntaxKind.ExtendsKeyword,
166        [ts.factory.createExpressionWithTypeArguments(ts.factory.createIdentifier('TS' + node.name.getText()),
167        undefined)])], node.members);
168  }
169  newStatements.push(node);
170}
171
172function validateComponentMembers(node, componentName) {
173  let extendNode = null;
174  let isComponentName = false;
175  if (node.members) {
176    for (let i = 0; i < node.members.length; i++) {
177      const callSignNode = node.members[i];
178      if (isSignNode(callSignNode)) {
179        const callSignName = callSignNode.type.typeName.getText().replace(/Attribute$/, '');
180        if (componentName === callSignName) {
181          extendNode = callSignNode.type.typeName;
182          isComponentName = true;
183          break;
184        }
185      }
186    }
187  }
188  return { isComponentName, extendNode }
189}
190
191function isVariable(node) {
192  if (ts.isVariableStatement(node) && node.declarationList && node.declarationList.declarations &&
193    node.declarationList.declarations.length && ts.isVariableDeclaration(node.declarationList.declarations[0]) &&
194    node.declarationList.declarations[0].name && node.declarationList.declarations[0].type) {
195    return true;
196  }
197  return false;
198}
199
200function isInterface(node) {
201  return ts.isInterfaceDeclaration(node) && node.name && ts.isIdentifier(node.name) &&
202    /Interface$/.test(node.name.getText());
203}
204
205function isClass(node) {
206  return ts.isClassDeclaration(node) && node.name && ts.isIdentifier(node.name) &&
207    /Attribute$/.test(node.name.getText());
208}
209
210function isSignNode(node) {
211  return (ts.isCallSignatureDeclaration(node) || ts.isConstructSignatureDeclaration(node)) &&
212    node.type && ts.isTypeReferenceNode(node.type) && node.type.typeName && ts.isIdentifier(node.type.typeName) &&
213    /Attribute$/.test(node.type.typeName.getText());
214}
215
216generateComponentConfig(process.argv[4]);
217function generateComponentConfig(dir) {
218  const configFile = path.resolve(dir, 'component_map.js');
219  if (fs.existsSync(configFile)) {
220    const { COMPONENT_MAP, FORM_MAP } = require(configFile);
221    try {
222      fs.writeFileSync(path.resolve(dir, '../component_config.json'), JSON.stringify(COMPONENT_MAP));
223      fs.writeFileSync(path.resolve(dir, '../form_config.json'), JSON.stringify(FORM_MAP));
224    } catch (error) {
225      console.error(error);
226    }
227  }
228}
229