Skip to content

Commit 0a50288

Browse files
authored
Model ETS imports/exports (#345)
1 parent 8681e6e commit 0a50288

File tree

15 files changed

+996
-28
lines changed

15 files changed

+996
-28
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ jobs:
116116
DEST_DIR="arkanalyzer"
117117
MAX_RETRIES=10
118118
RETRY_DELAY=3 # Delay between retries in seconds
119-
BRANCH="neo/2025-07-18"
119+
BRANCH="neo/2025-08-12"
120120
121121
for ((i=1; i<=MAX_RETRIES; i++)); do
122122
git clone --depth=1 --branch $BRANCH $REPO_URL $DEST_DIR && break

jacodb-ets/src/main/kotlin/org/jacodb/ets/dto/Convert.kt

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.jacodb.ets.dto
1818

19+
import mu.KotlinLogging
1920
import org.jacodb.ets.model.BasicBlock
2021
import org.jacodb.ets.model.EtsAddExpr
2122
import org.jacodb.ets.model.EtsAliasType
@@ -50,6 +51,8 @@ import org.jacodb.ets.model.EtsEntity
5051
import org.jacodb.ets.model.EtsEnumValueType
5152
import org.jacodb.ets.model.EtsEqExpr
5253
import org.jacodb.ets.model.EtsExpExpr
54+
import org.jacodb.ets.model.EtsExportInfo
55+
import org.jacodb.ets.model.EtsExportType
5356
import org.jacodb.ets.model.EtsExpr
5457
import org.jacodb.ets.model.EtsField
5558
import org.jacodb.ets.model.EtsFieldImpl
@@ -63,6 +66,8 @@ import org.jacodb.ets.model.EtsGlobalRef
6366
import org.jacodb.ets.model.EtsGtEqExpr
6467
import org.jacodb.ets.model.EtsGtExpr
6568
import org.jacodb.ets.model.EtsIfStmt
69+
import org.jacodb.ets.model.EtsImportInfo
70+
import org.jacodb.ets.model.EtsImportType
6671
import org.jacodb.ets.model.EtsInExpr
6772
import org.jacodb.ets.model.EtsInstanceCallExpr
6873
import org.jacodb.ets.model.EtsInstanceFieldRef
@@ -131,6 +136,8 @@ import org.jacodb.ets.model.EtsValue
131136
import org.jacodb.ets.model.EtsVoidType
132137
import org.jacodb.ets.model.EtsYieldExpr
133138

139+
private val logger = KotlinLogging.logger {}
140+
134141
class EtsMethodBuilder(
135142
signature: EtsMethodSignature,
136143
typeParameters: List<EtsType> = emptyList(),
@@ -715,10 +722,14 @@ fun EtsFileDto.toEtsFile(): EtsFile {
715722
val signature = signature.toEtsFileSignature()
716723
val classes = classes.map { it.toEtsClass() }
717724
val namespaces = namespaces.map { it.toEtsNamespace() }
725+
val importInfos = importInfos.map { it.toEtsImportInfo() }
726+
val exportInfos = exportInfos.map { it.toEtsExportInfo() }
718727
return EtsFile(
719728
signature = signature,
720729
classes = classes,
721730
namespaces = namespaces,
731+
importInfos = importInfos,
732+
exportInfos = exportInfos,
722733
)
723734
}
724735

@@ -737,6 +748,32 @@ fun LocalDto.toEtsLocal(): EtsLocal {
737748
)
738749
}
739750

751+
fun ImportInfoDto.toEtsImportInfo(): EtsImportInfo {
752+
return EtsImportInfo(
753+
name = importName,
754+
type = when (importType) {
755+
"Identifier" -> EtsImportType.DEFAULT
756+
"NamedImports" -> EtsImportType.NAMED
757+
"NamespaceImport" -> EtsImportType.NAMESPACE
758+
"" -> EtsImportType.SIDE_EFFECT
759+
else -> error("Unknown import type: $importType")
760+
},
761+
from = importFrom,
762+
nameBeforeAs = nameBeforeAs,
763+
modifiers = EtsModifiers(modifiers),
764+
)
765+
}
766+
767+
fun ExportInfoDto.toEtsExportInfo(): EtsExportInfo {
768+
return EtsExportInfo(
769+
name = exportName,
770+
type = exportType.toEtsExportType(),
771+
from = exportFrom,
772+
nameBeforeAs = nameBeforeAs,
773+
modifiers = EtsModifiers(modifiers),
774+
)
775+
}
776+
740777
private fun Int.toEtsClassCategory(): EtsClassCategory {
741778
return when (this) {
742779
0 -> EtsClassCategory.CLASS
@@ -748,3 +785,18 @@ private fun Int.toEtsClassCategory(): EtsClassCategory {
748785
else -> error("Unknown class category: $this")
749786
}
750787
}
788+
789+
private fun Int.toEtsExportType(): EtsExportType {
790+
return when (this) {
791+
0 -> EtsExportType.NAME_SPACE
792+
1 -> EtsExportType.CLASS
793+
2 -> EtsExportType.METHOD
794+
3 -> EtsExportType.LOCAL
795+
4 -> EtsExportType.TYPE
796+
9 -> EtsExportType.UNKNOWN
797+
else -> {
798+
logger.warn { "Unknown export type value: $this, defaulting to UNKNOWN" }
799+
EtsExportType.UNKNOWN
800+
}
801+
}
802+
}

jacodb-ets/src/main/kotlin/org/jacodb/ets/dto/Model.kt

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -93,25 +93,22 @@ data class BodyDto(
9393

9494
@Serializable
9595
data class ImportInfoDto(
96-
val importClauseName: String,
97-
val importType: String,
96+
val importName: String,
97+
val importType: String, // "Identifier" | "NamedImports" | "NamespaceImport" | ""
9898
val importFrom: String,
9999
val nameBeforeAs: String? = null,
100100
val modifiers: Int,
101101
// val decorators: List<DecoratorDto>,
102-
val originTsPosition: LineColPositionDto? = null,
103102
)
104103

105104
@Serializable
106105
data class ExportInfoDto(
107-
val exportClauseName: String,
108-
val exportClauseType: Int,
106+
val exportName: String,
107+
val exportType: Int, // enum ExportType
109108
val exportFrom: String? = null,
110109
val nameBeforeAs: String? = null,
111-
val isDefault: Boolean,
112110
val modifiers: Int,
113111
// val decorators: List<DecoratorDto>,
114-
val originTsPosition: LineColPositionDto? = null,
115112
)
116113

117114
@Serializable
@@ -120,9 +117,3 @@ data class DecoratorDto(
120117
// val content: String? = null,
121118
// val param: String? = null,
122119
)
123-
124-
@Serializable
125-
data class LineColPositionDto(
126-
val line: Int,
127-
val col: Int,
128-
)

jacodb-ets/src/main/kotlin/org/jacodb/ets/dto/Types.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ data class LexicalEnvTypeDto(
7373
data class EnumValueTypeDto(
7474
val signature: FieldSignatureDto,
7575
val constant: ConstantDto? = null,
76-
): TypeDto
76+
) : TypeDto
7777

7878
@Serializable
7979
@SerialName("VoidType")

jacodb-ets/src/main/kotlin/org/jacodb/ets/model/Class.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class EtsClassImpl(
4444
override val superClass: EtsClassSignature? = null,
4545
override val implementedInterfaces: List<EtsClassSignature> = emptyList(),
4646
override val typeParameters: List<EtsType> = emptyList(),
47-
override val modifiers: EtsModifiers = EtsModifiers.Companion.EMPTY,
47+
override val modifiers: EtsModifiers = EtsModifiers.EMPTY,
4848
override val decorators: List<EtsDecorator> = emptyList(),
4949
) : EtsClass {
5050
init {
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/*
2+
* Copyright 2022 UnitTestBot contributors (utbot.org)
3+
* <p>
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* <p>
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
* <p>
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.jacodb.ets.model
18+
19+
/**
20+
* Represents export information for TypeScript/JavaScript exports.
21+
*
22+
* @property name The name of the exported entity.
23+
* @property type The [type][EtsExportType] of export.
24+
* @property from The module or path being exported from (null for direct exports).
25+
* @property nameBeforeAs The original name before 'as' aliasing (null if no aliasing).
26+
*/
27+
data class EtsExportInfo(
28+
val name: String,
29+
val type: EtsExportType,
30+
val from: String? = null,
31+
val nameBeforeAs: String? = null,
32+
override val modifiers: EtsModifiers = EtsModifiers.EMPTY,
33+
) : Base {
34+
35+
// Note: Export statements do not have decorators in JS/TS.
36+
override val decorators: List<EtsDecorator> = emptyList()
37+
38+
/**
39+
* Export clause name without any aliasing.
40+
*/
41+
val originalName: String
42+
get() = nameBeforeAs ?: name
43+
44+
/**
45+
* Whether this export is a default export.
46+
*
47+
* ```ts
48+
* export default value;
49+
* export { value as default };
50+
* export { default } from './module';
51+
* export { default as Name } from './module';
52+
* ```
53+
*/
54+
val isDefaultExport: Boolean
55+
get() {
56+
// For re-exports:
57+
// export { default } from './module'
58+
// export { default as Name } from './module'
59+
if (from != null) return originalName == "default"
60+
61+
// For direct exports:
62+
// export default value
63+
// export { value as default }
64+
return super.isDefault
65+
}
66+
67+
/**
68+
* Whether this export is a star re-export (re-exporting everything from another module).
69+
*
70+
* ```ts
71+
* export * from './module';
72+
* export * as Utils from './utils';
73+
* ```
74+
*/
75+
val isStarExport: Boolean
76+
get() = from != null && originalName == "*"
77+
78+
/**
79+
* Whether this export is aliased.
80+
*
81+
* ```ts
82+
* export { value as Name } from './module';
83+
* export { default as Name } from './module';
84+
* export * as Utils from './utils';
85+
* ```
86+
*/
87+
val isAliased: Boolean
88+
get() = nameBeforeAs != null && nameBeforeAs != name
89+
90+
override val isDefault: Boolean
91+
get() = isDefaultExport
92+
93+
override fun toString(): String {
94+
return when {
95+
// Re-exports
96+
from != null -> {
97+
val alias = if (isAliased) " as $name" else ""
98+
if (isStarExport) {
99+
"export *$alias from '$from'"
100+
} else {
101+
"export { $originalName$alias } from '$from'"
102+
}
103+
}
104+
105+
// Direct default export
106+
isDefaultExport -> {
107+
"export default $originalName"
108+
}
109+
110+
// Direct named export
111+
else -> {
112+
val alias = if (isAliased) " as $name" else ""
113+
"export { $originalName$alias }"
114+
}
115+
}
116+
}
117+
}
118+
119+
/**
120+
* Type of export in TypeScript/JavaScript.
121+
*/
122+
enum class EtsExportType {
123+
NAME_SPACE,
124+
CLASS,
125+
METHOD,
126+
LOCAL,
127+
TYPE,
128+
UNKNOWN;
129+
}

jacodb-ets/src/main/kotlin/org/jacodb/ets/model/Field.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ interface EtsField : Base {
3030

3131
class EtsFieldImpl(
3232
override val signature: EtsFieldSignature,
33-
override val modifiers: EtsModifiers = EtsModifiers.Companion.EMPTY,
33+
override val modifiers: EtsModifiers = EtsModifiers.EMPTY,
3434
val isOptional: Boolean = false, // '?'
3535
val isDefinitelyAssigned: Boolean = false, // '!'
3636
) : EtsField {

jacodb-ets/src/main/kotlin/org/jacodb/ets/model/File.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ class EtsFile(
2020
val signature: EtsFileSignature,
2121
val classes: List<EtsClass>,
2222
val namespaces: List<EtsNamespace>,
23+
val importInfos: List<EtsImportInfo> = emptyList(),
24+
val exportInfos: List<EtsExportInfo> = emptyList(),
2325
) {
2426
init {
2527
classes.forEach { (it as EtsClassImpl).declaringFile = this }

0 commit comments

Comments
 (0)