Skip to content

Commit bb51484

Browse files
authored
Refine ts import/export infos (#354)
1 parent a2019a5 commit bb51484

File tree

4 files changed

+99
-57
lines changed

4 files changed

+99
-57
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -800,7 +800,7 @@ private fun Int.toEtsClassCategory(): EtsClassCategory {
800800

801801
private fun Int.toEtsExportType(): EtsExportType {
802802
return when (this) {
803-
0 -> EtsExportType.NAME_SPACE
803+
0 -> EtsExportType.NAMESPACE
804804
1 -> EtsExportType.CLASS
805805
2 -> EtsExportType.METHOD
806806
3 -> EtsExportType.LOCAL

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

Lines changed: 59 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ package org.jacodb.ets.model
2323
* @property type The [type][EtsExportType] of export.
2424
* @property from The module or path being exported from (null for direct exports).
2525
* @property nameBeforeAs The original name before 'as' aliasing (null if no aliasing).
26+
* @property modifiers Export modifiers.
2627
*/
2728
data class EtsExportInfo(
2829
val name: String,
@@ -33,7 +34,7 @@ data class EtsExportInfo(
3334
) : Base {
3435

3536
// Note: Export statements do not have decorators in JS/TS.
36-
override val decorators: List<EtsDecorator> = emptyList()
37+
override val decorators: List<EtsDecorator> get() = emptyList()
3738

3839
/**
3940
* Export clause name without any aliasing.
@@ -65,15 +66,26 @@ data class EtsExportInfo(
6566
}
6667

6768
/**
68-
* Whether this export is a star re-export (re-exporting everything from another module).
69+
* Whether this export is a re-export.
70+
*
71+
* ```ts
72+
* export { value } from './module';
73+
* export * from './module';
74+
* ```
75+
*/
76+
val isReExport: Boolean
77+
get() = from != null
78+
79+
/**
80+
* Whether this export is a star re-export.
6981
*
7082
* ```ts
7183
* export * from './module';
7284
* export * as Utils from './utils';
7385
* ```
7486
*/
75-
val isStarExport: Boolean
76-
get() = from != null && originalName == "*"
87+
val isStarReExport: Boolean
88+
get() = isReExport && originalName == "*"
7789

7890
/**
7991
* Whether this export is aliased.
@@ -85,17 +97,14 @@ data class EtsExportInfo(
8597
* ```
8698
*/
8799
val isAliased: Boolean
88-
get() = nameBeforeAs != null && nameBeforeAs != name
89-
90-
override val isDefault: Boolean
91-
get() = isDefaultExport
100+
get() = name != originalName
92101

93102
override fun toString(): String {
94103
return when {
95104
// Re-exports
96105
from != null -> {
97106
val alias = if (isAliased) " as $name" else ""
98-
if (isStarExport) {
107+
if (isStarReExport) {
99108
"export *$alias from '$from'"
100109
} else {
101110
"export { $originalName$alias } from '$from'"
@@ -120,10 +129,50 @@ data class EtsExportInfo(
120129
* Type of export in TypeScript/JavaScript.
121130
*/
122131
enum class EtsExportType {
123-
NAME_SPACE,
132+
/**
133+
* Namespace export:
134+
* ```ts
135+
* export namespace MyNamespace { ... }
136+
* ```
137+
*/
138+
NAMESPACE,
139+
140+
/**
141+
* Class export:
142+
* ```ts
143+
* export class MyClass { ... }
144+
* ```
145+
*/
124146
CLASS,
147+
148+
/**
149+
* Function export:
150+
* ```ts
151+
* export function myFunction() { ... }
152+
* ```
153+
*/
125154
METHOD,
155+
156+
/**
157+
* Local variable/constant export:
158+
* ```ts
159+
* export const myVariable = 42;
160+
* export let myLet = 'hello';
161+
* export var myVar = true;
162+
* ```
163+
*/
126164
LOCAL,
165+
166+
/**
167+
* Type export:
168+
* ```ts
169+
* export type MyType = string | number;
170+
* ```
171+
*/
127172
TYPE,
173+
174+
/**
175+
* Unknown export type, fallback for unrecognized export patterns.
176+
*/
128177
UNKNOWN;
129178
}

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

Lines changed: 38 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -33,29 +33,41 @@ data class EtsImportInfo(
3333
override val modifiers: EtsModifiers = EtsModifiers.EMPTY,
3434
) : Base {
3535

36+
init {
37+
if (type == EtsImportType.SIDE_EFFECT) {
38+
require(name.isEmpty()) { "Side-effect imports should have empty name" }
39+
require(nameBeforeAs == null) { "Side-effect imports should not have nameBeforeAs" }
40+
} else {
41+
require(name.isNotEmpty()) { "Only side-effect imports can have empty name" }
42+
}
43+
}
44+
3645
// Note: Import statements do not have decorators in JS/TS.
37-
override val decorators: List<EtsDecorator> = emptyList()
46+
override val decorators: List<EtsDecorator> get() = emptyList()
3847

3948
/**
4049
* Import clause name without any aliasing.
4150
*/
42-
val originalName: String = nameBeforeAs ?: name
51+
val originalName: String
52+
get() = nameBeforeAs ?: name
4353

4454
/**
4555
* Whether this is a default import.
4656
*
4757
* ```ts
4858
* import React from 'react';
59+
* import { default as React } from 'react';
4960
* ```
5061
*/
5162
val isDefaultImport: Boolean
52-
get() = type == EtsImportType.DEFAULT || originalName == "default"
63+
get() = type == EtsImportType.DEFAULT
5364

5465
/**
5566
* Whether this is a named import.
5667
*
5768
* ```ts
5869
* import { useState } from 'react';
70+
* import { Component as ReactComponent } from 'react';
5971
* ```
6072
*/
6173
val isNamedImport: Boolean
@@ -69,7 +81,7 @@ data class EtsImportInfo(
6981
* ```
7082
*/
7183
val isNamespaceImport: Boolean
72-
get() = type == EtsImportType.NAMESPACE || nameBeforeAs == "*"
84+
get() = type == EtsImportType.NAMESPACE
7385

7486
/**
7587
* Whether this is a side-effect import.
@@ -81,47 +93,28 @@ data class EtsImportInfo(
8193
val isSideEffectImport: Boolean
8294
get() = type == EtsImportType.SIDE_EFFECT
8395

84-
/**
85-
* Whether this import uses aliasing.
86-
*
87-
* ```ts
88-
* import { Component as ReactComponent };
89-
* ```
90-
*/
91-
val isAliased: Boolean
92-
get() = nameBeforeAs != null && nameBeforeAs != "*" && nameBeforeAs != name
93-
94-
override val isDefault: Boolean
95-
get() = isDefaultImport || super.isDefault
96-
97-
override fun toString(): String = buildString {
98-
append("import ")
99-
100-
when {
101-
isSideEffectImport -> {
102-
// Side effect import: import './styles.css'
103-
append("'$from'")
104-
}
105-
106-
isNamespaceImport -> {
107-
// Namespace import: import * as Utils from './utils'
108-
append("* as $name from '$from'")
109-
}
110-
111-
isAliased -> {
112-
// Aliased import: import { Component as ReactComponent } from 'react'
113-
append("{ $originalName as $name } from '$from'")
114-
}
115-
116-
isNamedImport -> {
117-
// Named import: import { useState } from 'react'
118-
append("{ $name } from '$from'")
119-
}
120-
121-
isDefaultImport -> {
122-
// Default import: import React from 'react'
123-
append("$name from '$from'")
124-
}
96+
override fun toString(): String = when(type) {
97+
EtsImportType.DEFAULT -> {
98+
// Default import: import React from 'react'
99+
"import $name from '$from'"
100+
}
101+
102+
EtsImportType.NAMED -> {
103+
// Named import:
104+
// import { useState } from 'react'
105+
// import { Component as ReactComponent } from 'react'
106+
val alias = if (name != originalName) " as $name" else ""
107+
"import { $originalName$alias } from '$from'"
108+
}
109+
110+
EtsImportType.NAMESPACE -> {
111+
// Namespace import: import * as Utils from './utils'
112+
"import * as $name from '$from'"
113+
}
114+
115+
EtsImportType.SIDE_EFFECT -> {
116+
// Side effect import: import './styles.css'
117+
"import '$from'"
125118
}
126119
}
127120
}

jacodb-ets/src/test/kotlin/org/jacodb/ets/test/EtsImportTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ class EtsImportTest {
7373
it.name == "React" && it.from == "react"
7474
}
7575
assertNotNull(reactImport, "Should find React default import")
76-
assertTrue(reactImport.isDefault, "React import should be marked as default")
76+
assertTrue(reactImport.isDefaultImport, "React import should be marked as default")
7777
assertNull(reactImport.nameBeforeAs, "React import is not aliased")
7878
assertEquals("React", reactImport.name)
7979
logger.info { "✓ Default import test passed: $reactImport" }

0 commit comments

Comments
 (0)