• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2024-2025 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 ts from 'ohos-typescript';
17import { LineColPosition } from '../../base/Position';
18import { ArkExport, ExportInfo, ExportType, FromInfo } from '../ArkExport';
19import { buildModifiers } from './builderUtils';
20import { ArkFile } from '../ArkFile';
21import { ALL, DEFAULT } from '../../common/TSConst';
22import { ArkBaseModel, ModifierType } from '../ArkBaseModel';
23import { IRUtils } from '../../common/IRUtils';
24import { ArkClass } from '../ArkClass';
25import { buildNormalArkClassFromArkFile } from './ArkClassBuilder';
26import { ArkNamespace } from '../ArkNamespace';
27
28export { buildExportInfo, buildExportAssignment, buildExportDeclaration };
29
30function buildExportInfo(arkInstance: ArkExport, arkFile: ArkFile, line: LineColPosition): ExportInfo {
31    let exportClauseName: string;
32    if (arkInstance instanceof ArkBaseModel && arkInstance.isDefault()) {
33        exportClauseName = DEFAULT;
34    } else {
35        exportClauseName = arkInstance.getName();
36    }
37    return new ExportInfo.Builder()
38        .exportClauseName(exportClauseName)
39        .exportClauseType(arkInstance.getExportType())
40        .modifiers(arkInstance.getModifiers())
41        .arkExport(arkInstance)
42        .originTsPosition(line)
43        .declaringArkFile(arkFile)
44        .build();
45}
46
47export function buildDefaultExportInfo(im: FromInfo, file: ArkFile, arkExport?: ArkExport): ExportInfo {
48    return new ExportInfo.Builder()
49        .exportClauseType(arkExport?.getExportType() ?? ExportType.CLASS)
50        .exportClauseName(im.getOriginName())
51        .declaringArkFile(file)
52        .arkExport(arkExport ?? file.getDefaultClass())
53        .build();
54}
55
56function buildExportDeclaration(node: ts.ExportDeclaration, sourceFile: ts.SourceFile, arkFile: ArkFile): ExportInfo[] {
57    const originTsPosition = LineColPosition.buildFromNode(node, sourceFile);
58    const tsSourceCode = node.getText(sourceFile);
59    const modifiers = node.modifiers ? buildModifiers(node) : 0;
60    let exportFrom = '';
61    if (node.moduleSpecifier && ts.isStringLiteral(node.moduleSpecifier)) {
62        exportFrom = node.moduleSpecifier.text;
63    }
64    let exportInfos: ExportInfo[] = [];
65    // just like: export {xxx as x} from './yy'
66    if (node.exportClause && ts.isNamedExports(node.exportClause) && node.exportClause.elements) {
67        node.exportClause.elements.forEach(element => {
68            let builder = new ExportInfo.Builder()
69                .exportClauseType(ExportType.UNKNOWN)
70                .exportClauseName(element.name.text)
71                .tsSourceCode(tsSourceCode)
72                .exportFrom(exportFrom)
73                .originTsPosition(originTsPosition)
74                .declaringArkFile(arkFile)
75                .setLeadingComments(IRUtils.getCommentsMetadata(node, sourceFile, arkFile.getScene().getOptions(), true))
76                .setTrailingComments(IRUtils.getCommentsMetadata(node, sourceFile, arkFile.getScene().getOptions(), false))
77                .modifiers(modifiers);
78            if (element.propertyName && ts.isIdentifier(element.propertyName)) {
79                builder.nameBeforeAs(element.propertyName.text);
80            }
81            exportInfos.push(builder.build());
82        });
83        return exportInfos;
84    }
85
86    let builder1 = new ExportInfo.Builder()
87        .exportClauseType(ExportType.UNKNOWN)
88        .nameBeforeAs(ALL)
89        .modifiers(modifiers)
90        .tsSourceCode(tsSourceCode)
91        .exportFrom(exportFrom)
92        .declaringArkFile(arkFile)
93        .setLeadingComments(IRUtils.getCommentsMetadata(node, sourceFile, arkFile.getScene().getOptions(), true))
94        .setTrailingComments(IRUtils.getCommentsMetadata(node, sourceFile, arkFile.getScene().getOptions(), false))
95        .originTsPosition(originTsPosition);
96    if (node.exportClause && ts.isNamespaceExport(node.exportClause) && ts.isIdentifier(node.exportClause.name)) {
97        // just like: export * as xx from './yy'
98        exportInfos.push(builder1.exportClauseName(node.exportClause.name.text).build());
99    } else if (!node.exportClause && node.moduleSpecifier) {
100        // just like: export * from './yy'
101        exportInfos.push(builder1.exportClauseName(ALL).build());
102    }
103    return exportInfos;
104}
105
106function buildExportAssignment(node: ts.ExportAssignment, sourceFile: ts.SourceFile, arkFile: ArkFile): ExportInfo[] {
107    let exportInfos: ExportInfo[] = [];
108    if (!node.expression) {
109        return exportInfos;
110    }
111    const originTsPosition = LineColPosition.buildFromNode(node, sourceFile);
112    const tsSourceCode = node.getText(sourceFile);
113    let modifiers = buildModifiers(node);
114
115    if (isKeyword(node.getChildren(sourceFile), ts.SyntaxKind.DefaultKeyword) || node.isExportEquals) {
116        modifiers |= ModifierType.DEFAULT;
117    }
118
119    let exportInfo = new ExportInfo.Builder()
120        .exportClauseType(ExportType.UNKNOWN)
121        .modifiers(modifiers)
122        .tsSourceCode(tsSourceCode)
123        .originTsPosition(originTsPosition)
124        .declaringArkFile(arkFile)
125        .exportClauseName(DEFAULT)
126        .setLeadingComments(IRUtils.getCommentsMetadata(node, sourceFile, arkFile.getScene().getOptions(), true))
127        .setTrailingComments(IRUtils.getCommentsMetadata(node, sourceFile, arkFile.getScene().getOptions(), false));
128
129    if (ts.isNewExpression(node.expression) && ts.isClassExpression(node.expression.expression)) {
130        let cls: ArkClass = new ArkClass();
131        buildNormalArkClassFromArkFile(node.expression.expression, arkFile, cls, sourceFile);
132    }
133
134    if (ts.isIdentifier(node.expression)) {
135        // just like: export default xx
136        exportInfo.nameBeforeAs(node.expression.text);
137    } else if (ts.isAsExpression(node.expression)) {
138        // just like: export default xx as YY
139        exportInfo.nameBeforeAs(node.expression.expression.getText(sourceFile));
140    }
141    exportInfos.push(exportInfo.build());
142
143    return exportInfos;
144}
145
146/**
147 * export const c = '', b = 1;
148 * @param node
149 * @param sourceFile
150 * @param arkFile
151 */
152export function buildExportVariableStatement(node: ts.VariableStatement, sourceFile: ts.SourceFile, arkFile: ArkFile, namespace?: ArkNamespace): ExportInfo[] {
153    let exportInfos: ExportInfo[] = [];
154    const originTsPosition = LineColPosition.buildFromNode(node, sourceFile);
155    const modifiers = node.modifiers ? buildModifiers(node) : 0;
156    const tsSourceCode = node.getText(sourceFile);
157    node.declarationList.declarations.forEach(dec => {
158        const exportInfoBuilder = new ExportInfo.Builder()
159            .exportClauseName(dec.name.getText(sourceFile))
160            .exportClauseType(ExportType.LOCAL)
161            .modifiers(modifiers)
162            .tsSourceCode(tsSourceCode)
163            .originTsPosition(originTsPosition)
164            .declaringArkFile(arkFile);
165        if (namespace) {
166            exportInfoBuilder.declaringArkNamespace(namespace);
167        }
168        exportInfos.push(exportInfoBuilder.build());
169    });
170    return exportInfos;
171}
172
173/**
174 * export type MyType = string;
175 * @param node
176 * @param sourceFile
177 * @param arkFile
178 */
179export function buildExportTypeAliasDeclaration(node: ts.TypeAliasDeclaration, sourceFile: ts.SourceFile, arkFile: ArkFile): ExportInfo[] {
180    let exportInfos: ExportInfo[] = [];
181    const originTsPosition = LineColPosition.buildFromNode(node, sourceFile);
182    const modifiers = node.modifiers ? buildModifiers(node) : 0;
183    const tsSourceCode = node.getText(sourceFile);
184    const exportInfo = new ExportInfo.Builder()
185        .exportClauseName(node.name.text)
186        .exportClauseType(ExportType.TYPE)
187        .tsSourceCode(tsSourceCode)
188        .modifiers(modifiers)
189        .originTsPosition(originTsPosition)
190        .declaringArkFile(arkFile)
191        .build();
192    exportInfos.push(exportInfo);
193    return exportInfos;
194}
195
196export function isExported(modifierArray: ts.NodeArray<ts.ModifierLike> | undefined): boolean {
197    if (!modifierArray) {
198        return false;
199    }
200    for (let child of modifierArray) {
201        if (child.kind === ts.SyntaxKind.ExportKeyword) {
202            return true;
203        }
204    }
205    return false;
206}
207
208function isKeyword(modifierArray: ts.Node[] | undefined, keyword: ts.SyntaxKind): boolean {
209    if (!modifierArray) {
210        return false;
211    }
212    for (let child of modifierArray) {
213        if (child.kind === keyword) {
214            return true;
215        }
216    }
217    return false;
218}
219