• 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 type { TypeAliasEntity, TypeAliasTypeEntity } from '../declaration-node/typeAliasDeclaration';
17import { firstCharacterToUppercase, getOhosInterfacesDir } from '../common/commonUtils';
18import path from 'path';
19import fs from 'fs';
20import type { SourceFile } from 'typescript';
21
22const interceptIndex = 2;
23
24/**
25 * generate type alias
26 * @param typeAliasEntity
27 * @param isInner
28 * @param sourceFile
29 * @param extraImport
30 * @returns
31 */
32export function generateTypeAliasDeclaration(
33  typeAliasEntity: TypeAliasEntity, isInner: boolean, sourceFile: SourceFile, extraImport: string[]
34): string {
35  let typeAliasName = '';
36  if (!isInner) {
37    typeAliasName += `export const ${typeAliasEntity.typeAliasName} = `;
38  } else {
39    typeAliasName += `const ${typeAliasEntity.typeAliasName} = `;
40  }
41
42  let typeAliasValue = '';
43
44  const typeAliasTypeElements = typeAliasEntity.typeAliasTypeElements;
45
46  if (typeAliasTypeElements) {
47    typeAliasValue += parseImportExpression(typeAliasTypeElements, sourceFile, extraImport);
48  }
49
50  if (!typeAliasValue) {
51    typeAliasValue += `'[PC Preview] unknown ${typeAliasEntity.typeAliasName}'`;
52  }
53  return typeAliasName + typeAliasValue + ';';
54}
55
56function getImportFileFullPath(typeName: string): string {
57  const importRelatePathTmp = typeName.match(/\('[^'()]+'\)/);
58  if (!importRelatePathTmp) {
59    return '';
60  }
61  const importRelatePath = importRelatePathTmp[0].substring(interceptIndex, importRelatePathTmp[0].length - interceptIndex);
62  const tmpRealPath = getOhosInterfacesDir() + importRelatePath.replace('../api', '').replace(/\//g, path.sep);
63  if (fs.existsSync(tmpRealPath + '.d.ts')) {
64    return tmpRealPath + '.d.ts';
65  }
66
67  if (fs.existsSync(tmpRealPath + '.d.ets')) {
68    return tmpRealPath + '.d.ets';
69  }
70  console.warn(`Can not find import \'${importRelatePath}\'`);
71  return '';
72}
73
74function pathToImportPath(currentFilePath: string, importFilePath: string): string {
75  const currentFilePathSteps = currentFilePath.replace(/.d.e?ts/, '').split('/');
76  const importFilePathSteps = importFilePath.replace(/.d.e?ts/, '').split(path.sep);
77  const importFilePathStepsLength = importFilePathSteps.length;
78  importFilePathSteps[importFilePathStepsLength - 1] = importFilePathSteps[importFilePathStepsLength - 1]
79    .replace('@', '').replace(/\./g, '_');
80  let differStepIndex: number;
81  for (differStepIndex = 0; differStepIndex < currentFilePathSteps.length; differStepIndex++) {
82    if (currentFilePathSteps[differStepIndex] !== importFilePathSteps[differStepIndex]) {
83      break;
84    }
85  }
86  const currentFileDifferPathSteps = currentFilePathSteps.slice(differStepIndex);
87  const importFileDifferPathSteps = importFilePathSteps.slice(differStepIndex);
88  if (currentFileDifferPathSteps.length === importFileDifferPathSteps.length
89    && currentFileDifferPathSteps.length === 1) {
90    return `./${path.basename(importFilePath)}`;
91  } else {
92    const steps = [];
93    for (let i = 0; i < currentFileDifferPathSteps.length - 1; i++) {
94      steps.push('..');
95    }
96    const fullSteps = steps.concat(importFileDifferPathSteps);
97    return fullSteps.join('/');
98  }
99}
100
101function parseImportExpression(
102  typeAliasTypeElements: TypeAliasTypeEntity[], sourceFile: SourceFile, extraImport: string[]
103): string {
104  for (let i = 0; i < typeAliasTypeElements.length; i++) {
105    const typeAliasTypeElement = typeAliasTypeElements[i];
106    const typeName = typeAliasTypeElement.typeName;
107    if (!typeName?.trim().startsWith('import(')) {
108      continue;
109    }
110    const splitTypeName = typeName.split(')');
111    const propertiesIndex = 1;
112    const properties = splitTypeName[propertiesIndex];
113    const importPath = getImportFileFullPath(typeName);
114    const realImportPath = pathToImportPath(sourceFile.fileName, importPath);
115    if (!importPath) {
116      continue;
117    }
118    const importFileContent = fs.readFileSync(importPath, 'utf-8');
119    if (properties.startsWith('.default')) {
120      let result = importFileContent.match(/export\sdefault\sclass\s[a-zA-Z]+/);
121      if (result) {
122        const defaultModuleName = '_' + result[0].replace(/export\sdefault\sclass\s/, '');
123        const importStr = `import ${defaultModuleName} from '${realImportPath}';\n`;
124        !extraImport.includes(importStr) && extraImport.push(importStr);
125        return `${defaultModuleName}${properties.replace('.default', '')}`;
126      }
127      result = importFileContent.match(/export\sdefault\s[a-zA-Z]+;/);
128      if (result) {
129        const moduleName = result[0]
130          .replace(/export\sdefault\s/, '')
131          .replace(';', '');
132        const mockFunctionName = `mock${firstCharacterToUppercase(moduleName)}`;
133        const importStr = `import {${mockFunctionName}} from '${realImportPath}';\n`;
134        !extraImport.includes(importStr) && extraImport.push(importStr);
135        return `${mockFunctionName}()${properties.replace('.default', '')}`;
136      }
137    } else {
138      const moduleName = properties.replace('.', '').split('.')[0];
139      const importStr = `import {${moduleName} as _${moduleName}} from '${realImportPath}';\n`;
140      !extraImport.includes(importStr) && extraImport.push(importStr);
141      return `_${properties.replace('.', '')}`;
142    }
143  }
144  return '';
145}
146