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 fs = require('fs');
17const path = require('path');
18const ts = require('typescript');
19const SECOND_PARAM = 2;
20const THIRD_PARAM = 3;
21const FOURTH_PARAM = 4;
22const FIFTH_PARAM = 5;
23const systemModules = [];
24
25function generateKitConfig(kitFilePath, output, apiFilePath, arktsFilePath) {
26  readSystemApis(apiFilePath, systemModules);
27  readSystemApis(arktsFilePath, systemModules);
28  const kitFiles = [];
29  readFile(kitFilePath, kitFiles);
30  if (fs.existsSync(output)) {
31    removeDir(output);
32  }
33  mkDir(output);
34  kitFiles.forEach((item) => {
35    let content = fs.readFileSync(item, 'utf8');
36    const outputPath = path.resolve(output, path.basename(item).replace('.d.ts', '.json'));
37    const symbol = {};
38    const kitSourceFile = ts.createSourceFile(item, content, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
39    if (kitSourceFile.statements && kitSourceFile.statements.length > 0) {
40      kitSourceFile.statements.forEach(statement => {
41        getImportDeclarationInfo(statement, symbol);
42      });
43    }
44    const result = {
45      'symbols': symbol
46    };
47    const STANDARD_INDENT = 2;
48    createKitConfigs(outputPath, JSON.stringify(result, null, STANDARD_INDENT));
49  });
50}
51
52function getImportDeclarationInfo(statement, symbol) {
53  if (!ts.isImportDeclaration(statement)) {
54    return;
55  }
56  let source = '';
57  if (statement.moduleSpecifier && ts.isStringLiteral(statement.moduleSpecifier)) {
58    source = statement.moduleSpecifier.getText().replace(/('|")*/g, '');
59    for (let i = 0; i < systemModules.length; i++) {
60      const moduleName = systemModules[i];
61      if (moduleName.replace(/(\.d\.ts|\.d\.ets)$/, '') === source) {
62        source = moduleName;
63        break;
64      }
65    }
66  }
67  if (statement.importClause) {
68    const clause = statement.importClause;
69    if (clause.name) {
70      addSymbol(symbol, clause.name.getText(), source, 'default');
71    }
72    if (clause.namedBindings) {
73      const binding = clause.namedBindings;
74      if (ts.isNamespaceImport(binding) && binding.name) {
75        addSymbol(symbol, binding.name.getText(), source, 'default');
76      } else if (ts.isNamedImports(binding) && binding.elements && binding.elements.length > 0) {
77        processNamedImports(binding.elements, symbol, source);
78      }
79    }
80  }
81}
82
83function processNamedImports(elements, symbol, source) {
84  elements.forEach(element => {
85    if (ts.isImportSpecifier(element)) {
86      const name = element.name.getText();
87      const bindingsName = element.propertyName ? element.propertyName.getText() : name;
88      addSymbol(symbol, name, source, bindingsName);
89    }
90  });
91}
92
93function addSymbol(symbol, name, source, bindings) {
94  symbol[name] = {
95    source: source,
96    bindings: bindings
97  };
98}
99
100function readFile(dir, fileDir) {
101  const files = fs.readdirSync(dir);
102  files.forEach((element) => {
103    const filePath = path.join(dir, element);
104    const status = fs.statSync(filePath);
105    if (status.isDirectory()) {
106      readFile(filePath, fileDir);
107    } else {
108      fileDir.push(filePath);
109    }
110  });
111}
112
113function readSystemApis(dir, fileDir) {
114  const files = fs.readdirSync(dir);
115  files.forEach(file => {
116    const filePath = path.join(dir, file);
117    const status = fs.statSync(filePath);
118    if (!status.isDirectory()) {
119      fileDir.push(file);
120    }
121  });
122}
123
124function mkDir(filePath) {
125  const parent = path.join(filePath, '..');
126  if (!(fs.existsSync(parent) && !fs.statSync(parent).isFile())) {
127    mkDir(parent);
128  }
129  fs.mkdirSync(filePath);
130}
131
132function removeDir(path) {
133  if (fs.existsSync(path)) {
134    fs.rmdirSync(path, {recursive: true});
135  }
136}
137
138function createKitConfigs(fileName, content) {
139  fs.writeFile(fileName, content, err => {
140    if (err) {
141      console.error(err);
142      return;
143    }
144  });
145}
146
147generateKitConfig(process.argv[SECOND_PARAM], process.argv[THIRD_PARAM], process.argv[FOURTH_PARAM], process.argv[FIFTH_PARAM]);
148