• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2023 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 fs from 'fs';
17import path from 'path';
18import ts from 'typescript';
19import { ImportElementEntity } from '../declaration-node/importAndExportDeclaration';
20
21export interface KitImportInfo {
22  fromPath: string,
23  isExport: string[],
24  isDefaultExport: string
25}
26
27// kit file map
28export const KIT_MAP = new Map<string, KitImportInfo[]>();
29
30/**
31 * get all kit files
32 * @param kitDir root path
33 */
34export function collectAllKitFiles(kitDir: string): void {
35  const arr = fs.readdirSync(kitDir);
36  arr.forEach(value => {
37    const fullPath = path.join(kitDir, value);
38    const stats = fs.statSync(fullPath);
39    if (stats.isDirectory()) {
40      collectAllKitFiles(fullPath);
41    } else {
42      let fileBaseName: string;
43      if (value.endsWith('.d.ts')) {
44        fileBaseName = path.basename(value, '.d.ts');
45      }
46      if (fileBaseName) {
47        handleKitFile(fullPath, fileBaseName);
48      }
49    }
50  });
51}
52
53/**
54 * kit file convert to ast
55 * @param kitPath kit file path
56 * @param fileName kit file name
57 */
58function handleKitFile(kitPath: string, fileName: string): void {
59  KIT_MAP.set(fileName, []);
60
61  const code = fs.readFileSync(kitPath);
62  const sourceFile = ts.createSourceFile(kitPath, code.toString(), ts.ScriptTarget.Latest);
63  sourceFile.forEachChild(node => {
64    if (ts.isImportDeclaration(node)) {
65      KIT_MAP.get(fileName).push(getKitImportDeclaration(node));
66    }
67  });
68}
69
70/**
71 * get kit file import declaration
72 * @param importNode kit file import node
73 * @returns KitImportInfo
74 */
75export function getKitImportDeclaration(importNode: ts.ImportDeclaration): KitImportInfo {
76  let isDefaultExport = '';
77  const isExport = [];
78  const moduleSpecifier = importNode.moduleSpecifier as ts.StringLiteral;
79  const fromPath = moduleSpecifier.text.trim();
80  const importClause = importNode.importClause;
81  if (importClause !== undefined) {
82    if (importClause.name) {
83      isDefaultExport = importClause.name.text.trim();
84    }
85    importClause.namedBindings?.forEachChild((node: ts.ImportSpecifier) => {
86      if (node.name) {
87        isExport.push(node.name.text.trim());
88      }
89    });
90  }
91
92  return {
93    fromPath,
94    isDefaultExport,
95    isExport
96  };
97}
98
99/**
100 * handle kit file import map info
101 * @param importEntity import entity data
102 * @returns ImportElementEntity[]
103 */
104export function handleImportKit(importEntity: ImportElementEntity): ImportElementEntity[] {
105  const importPath = importEntity.importPath.replace(/(\'|\")/g, '');
106  if (!importPath.startsWith('@kit.')) {
107    return [];
108  }
109  const importEntities: ImportElementEntity[] = [];
110  let importElements: string[];
111  if (importEntity.importElements.startsWith('{') && importEntity.importElements.endsWith('}')) {
112    importElements = importEntity.importElements
113      .substring(1, importEntity.importElements.length - 1)
114      .split(',')
115      .map(element => element.trim());
116  }
117
118  const kitImportInfos: KitImportInfo[] = KIT_MAP.get(importPath);
119  if (!kitImportInfos) {
120    throw new Error(`Can't find kitFileInfos from ${importPath}`);
121  }
122
123  importElements.forEach(element => {
124    importEntities.push(getKitImportInfo(kitImportInfos, element, importPath));
125  });
126  return importEntities;
127}
128
129/**
130 * get Kit file import map info
131 * @param kitImportInfos map infos
132 * @param element import entity info
133 * @param importPath import file path
134 * @returns ImportElementEntity
135 */
136function getKitImportInfo(kitImportInfos: KitImportInfo[], element: string, importPath: string): ImportElementEntity {
137  let defaultImport: string;
138  let commonImport: string;
139  const kitImportInfo = kitImportInfos.find(kitInfo => {
140    if (element === kitInfo.isDefaultExport) {
141      defaultImport = kitInfo.isDefaultExport;
142      return true;
143    } else if (kitInfo.isExport.includes(element)) {
144      commonImport = element;
145      return true;
146    } else {
147      return false;
148    }
149  });
150
151  if (!kitImportInfo) {
152    throw new Error(`Can't find ${element} from ${importPath}`);
153  }
154
155  const defaultImportStr = defaultImport ? `${defaultImport}${commonImport ? ',' : ''}` : '';
156  const commonImportsStr = commonImport ? `{ ${commonImport} }` : '';
157  return {
158    importElements: `${defaultImportStr} ${commonImportsStr}`,
159    importPath: kitImportInfo.fromPath
160  };
161}
162