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