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