@typia/transform 12.0.0-dev.20260309 → 12.0.0-dev.20260310

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/package.json +4 -4
  2. package/src/CallExpressionTransformer.ts +579 -579
  3. package/src/FileTransformer.ts +143 -143
  4. package/src/ITransformProps.ts +20 -20
  5. package/src/ImportTransformer.ts +262 -262
  6. package/src/NodeTransformer.ts +25 -25
  7. package/src/TransformerError.ts +85 -85
  8. package/src/TypiaGenerator.ts +172 -172
  9. package/src/features/AssertTransformer.ts +24 -24
  10. package/src/features/CreateAssertTransformer.ts +24 -24
  11. package/src/features/CreateIsTransformer.ts +18 -18
  12. package/src/features/CreateRandomTransformer.ts +42 -42
  13. package/src/features/CreateValidateTransformer.ts +18 -18
  14. package/src/features/IsTransformer.ts +18 -18
  15. package/src/features/RandomTransformer.ts +40 -40
  16. package/src/features/ValidateTransformer.ts +18 -18
  17. package/src/features/functional/FunctionalGenericTransformer.ts +55 -55
  18. package/src/features/http/CreateHttpAssertFormDataTransformer.ts +13 -13
  19. package/src/features/http/CreateHttpAssertHeadersTransformer.ts +13 -13
  20. package/src/features/http/CreateHttpAssertQueryTransformer.ts +13 -13
  21. package/src/features/http/CreateHttpFormDataTransformer.ts +13 -13
  22. package/src/features/http/CreateHttpHeadersTransformer.ts +13 -13
  23. package/src/features/http/CreateHttpIsFormDataTransformer.ts +13 -13
  24. package/src/features/http/CreateHttpIsHeadersTransformer.ts +13 -13
  25. package/src/features/http/CreateHttpIsQueryTransformer.ts +13 -13
  26. package/src/features/http/CreateHttpParameterTransformer.ts +13 -13
  27. package/src/features/http/CreateHttpQueryTransformer.ts +13 -13
  28. package/src/features/http/CreateHttpValidateFormDataTransformer.ts +13 -13
  29. package/src/features/http/CreateHttpValidateHeadersTransformer.ts +13 -13
  30. package/src/features/http/CreateHttpValidateQueryTransformer.ts +13 -13
  31. package/src/features/http/HttpAssertFormDataTransformer.ts +13 -13
  32. package/src/features/http/HttpAssertHeadersTransformer.ts +13 -13
  33. package/src/features/http/HttpAssertQueryTransformer.ts +13 -13
  34. package/src/features/http/HttpFormDataTransformer.ts +13 -13
  35. package/src/features/http/HttpHeadersTransformer.ts +13 -13
  36. package/src/features/http/HttpIsFormDataTransformer.ts +13 -13
  37. package/src/features/http/HttpIsHeadersTransformer.ts +13 -13
  38. package/src/features/http/HttpIsQueryTransformer.ts +13 -13
  39. package/src/features/http/HttpParameterTransformer.ts +13 -13
  40. package/src/features/http/HttpQueryTransformer.ts +13 -13
  41. package/src/features/http/HttpValidateFormDataTransformer.ts +13 -13
  42. package/src/features/http/HttpValidateHeadersTransformer.ts +13 -13
  43. package/src/features/http/HttpValidateQueryTransformer.ts +13 -13
  44. package/src/features/json/JsonApplicationTransformer.ts +99 -99
  45. package/src/features/json/JsonAssertParseTransformer.ts +13 -13
  46. package/src/features/json/JsonAssertStringifyTransformer.ts +13 -13
  47. package/src/features/json/JsonCreateAssertParseTransformer.ts +13 -13
  48. package/src/features/json/JsonCreateAssertStringifyTransformer.ts +13 -13
  49. package/src/features/json/JsonCreateIsParseTransformer.ts +13 -13
  50. package/src/features/json/JsonCreateIsStringifyTransformer.ts +13 -13
  51. package/src/features/json/JsonCreateStringifyTransformer.ts +13 -13
  52. package/src/features/json/JsonCreateValidateParseTransformer.ts +13 -13
  53. package/src/features/json/JsonCreateValidateStringifyProgrammer.ts +13 -13
  54. package/src/features/json/JsonIsParseTransformer.ts +13 -13
  55. package/src/features/json/JsonIsStringifyTransformer.ts +13 -13
  56. package/src/features/json/JsonSchemaTransformer.ts +120 -120
  57. package/src/features/json/JsonSchemasTransformer.ts +130 -130
  58. package/src/features/json/JsonStringifyTransformer.ts +13 -13
  59. package/src/features/json/JsonValidateParseTransformer.ts +13 -13
  60. package/src/features/json/JsonValidateStringifyTransformer.ts +13 -13
  61. package/src/features/llm/LlmApplicationTransformer.ts +224 -224
  62. package/src/features/llm/LlmCoerceTransformer.ts +95 -95
  63. package/src/features/llm/LlmControllerTransformer.ts +81 -81
  64. package/src/features/llm/LlmCreateCoerceTransformer.ts +84 -84
  65. package/src/features/llm/LlmCreateParseTransformer.ts +84 -84
  66. package/src/features/llm/LlmParametersTransformer.ts +76 -76
  67. package/src/features/llm/LlmParseTransformer.ts +95 -95
  68. package/src/features/llm/LlmSchemaTransformer.ts +87 -87
  69. package/src/features/misc/MiscAssertCloneTransformer.ts +13 -13
  70. package/src/features/misc/MiscAssertPruneTransformer.ts +13 -13
  71. package/src/features/misc/MiscCloneTransformer.ts +13 -13
  72. package/src/features/misc/MiscCreateAssertCloneTransformer.ts +13 -13
  73. package/src/features/misc/MiscCreateAssertPruneTransformer.ts +13 -13
  74. package/src/features/misc/MiscCreateCloneTransformer.ts +13 -13
  75. package/src/features/misc/MiscCreateIsCloneTransformer.ts +13 -13
  76. package/src/features/misc/MiscCreateIsPruneTransformer.ts +13 -13
  77. package/src/features/misc/MiscCreatePruneTransformer.ts +13 -13
  78. package/src/features/misc/MiscCreateValidateCloneTransformer.ts +13 -13
  79. package/src/features/misc/MiscCreateValidatePruneTransformer.ts +13 -13
  80. package/src/features/misc/MiscIsCloneTransformer.ts +13 -13
  81. package/src/features/misc/MiscIsPruneTransformer.ts +13 -13
  82. package/src/features/misc/MiscLiteralsTransformer.ts +34 -34
  83. package/src/features/misc/MiscPruneTransformer.ts +13 -13
  84. package/src/features/misc/MiscValidateCloneTransformer.ts +13 -13
  85. package/src/features/misc/MiscValidatePruneTransformer.ts +13 -13
  86. package/src/features/notations/NotationAssertGeneralTransformer.ts +19 -19
  87. package/src/features/notations/NotationCreateAssertGeneralTransformer.ts +19 -19
  88. package/src/features/notations/NotationCreateGeneralTransformer.ts +19 -19
  89. package/src/features/notations/NotationCreateIsGeneralTransformer.ts +19 -19
  90. package/src/features/notations/NotationCreateValidateGeneralTransformer.ts +19 -19
  91. package/src/features/notations/NotationGeneralTransformer.ts +18 -18
  92. package/src/features/notations/NotationIsGeneralTransformer.ts +19 -19
  93. package/src/features/notations/NotationValidateGeneralTransformer.ts +19 -19
  94. package/src/features/protobuf/ProtobufAssertDecodeTransformer.ts +13 -13
  95. package/src/features/protobuf/ProtobufAssertEncodeTransformer.ts +13 -13
  96. package/src/features/protobuf/ProtobufCreateAssertDecodeTransformer.ts +13 -13
  97. package/src/features/protobuf/ProtobufCreateAssertEncodeTransformer.ts +13 -13
  98. package/src/features/protobuf/ProtobufCreateDecodeTransformer.ts +13 -13
  99. package/src/features/protobuf/ProtobufCreateEncodeTransformer.ts +13 -13
  100. package/src/features/protobuf/ProtobufCreateIsDecodeTransformer.ts +13 -13
  101. package/src/features/protobuf/ProtobufCreateIsEncodeTransformer.ts +13 -13
  102. package/src/features/protobuf/ProtobufCreateValidateDecodeTransformer.ts +13 -13
  103. package/src/features/protobuf/ProtobufCreateValidateEncodeTransformer.ts +13 -13
  104. package/src/features/protobuf/ProtobufDecodeTransformer.ts +13 -13
  105. package/src/features/protobuf/ProtobufEncodeTransformer.ts +13 -13
  106. package/src/features/protobuf/ProtobufIsDecodeTransformer.ts +13 -13
  107. package/src/features/protobuf/ProtobufIsEncodeTransformer.ts +13 -13
  108. package/src/features/protobuf/ProtobufMessageTransformer.ts +34 -34
  109. package/src/features/protobuf/ProtobufValidateDecodeTransformer.ts +13 -13
  110. package/src/features/protobuf/ProtobufValidateEncodeTransformer.ts +13 -13
  111. package/src/features/reflect/ReflectMetadataTransformer.ts +69 -69
  112. package/src/features/reflect/ReflectNameTransformer.ts +81 -81
  113. package/src/features/reflect/ReflectSchemaTransformer.ts +65 -65
  114. package/src/features/reflect/ReflectSchemasTransformer.ts +69 -69
  115. package/src/index.ts +7 -7
  116. package/src/internal/GenericTransformer.ts +101 -101
  117. package/src/transform.ts +68 -68
@@ -1,262 +1,262 @@
1
- import path from "path";
2
- import ts from "typescript";
3
-
4
- /**
5
- * Transforms import paths for typia build output.
6
- *
7
- * Rewrites relative import paths when building typia packages. Also removes
8
- * unused typia imports that only contained transformable function calls (since
9
- * those are replaced at compile time).
10
- *
11
- * @author Jeongho Nam - https://github.com/samchon
12
- */
13
- export namespace ImportTransformer {
14
- export const transform =
15
- (props: { from: string; to: string }) =>
16
- (context: ts.TransformationContext) =>
17
- (file: ts.SourceFile) =>
18
- transform_file({
19
- top: props.from,
20
- to: props.to,
21
- context,
22
- file,
23
- });
24
-
25
- const transform_file = (props: {
26
- top: string;
27
- to: string;
28
- context: ts.TransformationContext;
29
- file: ts.SourceFile;
30
- }): ts.SourceFile => {
31
- if (props.file.isDeclarationFile) return props.file;
32
-
33
- const from: string = get_directory_path(
34
- path.resolve(props.file.getSourceFile().fileName),
35
- );
36
- const to: string = from.replace(props.top, props.to);
37
-
38
- // First pass: transform relative imports
39
- let transformedFile = ts.visitEachChild(
40
- props.file,
41
- (node) =>
42
- transform_node({
43
- top: props.top,
44
- from,
45
- to,
46
- node,
47
- }),
48
- props.context,
49
- );
50
-
51
- // Second pass: remove unused typia imports
52
- transformedFile = removeUnusedTypiaImports(transformedFile);
53
-
54
- return transformedFile;
55
- };
56
-
57
- const transform_node = (props: {
58
- top: string;
59
- from: string;
60
- to: string;
61
- node: ts.Node;
62
- }) => {
63
- if (
64
- !ts.isImportDeclaration(props.node) ||
65
- !ts.isStringLiteral(props.node.moduleSpecifier)
66
- )
67
- return props.node;
68
-
69
- const text: string = props.node.moduleSpecifier.text;
70
- if (text[0] !== ".") return props.node;
71
-
72
- const location: string = path.resolve(props.from, text);
73
- if (location.indexOf(props.top) === 0) return props.node;
74
-
75
- const replaced: string = (() => {
76
- const simple: string = path
77
- .relative(props.to, location)
78
- .split(path.sep)
79
- .join("/");
80
- return simple[0] === "." ? simple : `./${simple}`;
81
- })();
82
-
83
- return ts.factory.createImportDeclaration(
84
- undefined,
85
- props.node.importClause,
86
- ts.factory.createStringLiteral(replaced),
87
- props.node.assertClause,
88
- );
89
- };
90
- }
91
-
92
- const get_directory_path = (file: string): string => {
93
- const split: string[] = path.resolve(file).split(path.sep);
94
- split.pop();
95
- return path.resolve(split.join(path.sep));
96
- };
97
-
98
- /** Remove unused typia imports that are only used in transformable calls */
99
- const removeUnusedTypiaImports = (file: ts.SourceFile): ts.SourceFile => {
100
- // Find typia imports and collect all identifiers
101
- interface ImportMetadata {
102
- declaration: ts.ImportDeclaration;
103
- default: boolean;
104
- }
105
- const imports: Map<string, ImportMetadata> = new Map();
106
- for (const stmt of file.statements) {
107
- if (
108
- ts.isImportDeclaration(stmt) === false ||
109
- ts.isStringLiteral(stmt.moduleSpecifier) === false ||
110
- stmt.moduleSpecifier.text !== "typia" ||
111
- stmt.importClause === undefined
112
- )
113
- continue;
114
-
115
- // Track default import (import typia from 'typia')
116
- if (stmt.importClause.name)
117
- imports.set(stmt.importClause.name.text, {
118
- declaration: stmt,
119
- default: true,
120
- });
121
-
122
- // Track named imports (import { tags } from 'typia') - keep these
123
- if (
124
- stmt.importClause.namedBindings &&
125
- ts.isNamedImports(stmt.importClause.namedBindings)
126
- )
127
- for (const element of stmt.importClause.namedBindings.elements)
128
- imports.set(element.name.text, {
129
- declaration: stmt,
130
- default: false,
131
- });
132
- }
133
- if (imports.size === 0) return file; // No typia imports to check
134
-
135
- // Find usage of typia identifiers that are NOT transformable calls
136
- const nonTransformableUsage = new Set<string>();
137
- const checkUsage = (node: ts.Node) => {
138
- if (ts.isIdentifier(node) && imports.has(node.text)) {
139
- const identifier: string = node.text;
140
- // Check if this identifier is being used as part of a property access
141
- if (
142
- node.parent &&
143
- ts.isPropertyAccessExpression(node.parent) &&
144
- node.parent.expression === node
145
- ) {
146
- // This is typia.something - check if it's a transformable call pattern
147
- if (!isLikelyTransformableCall(node.parent))
148
- nonTransformableUsage.add(identifier);
149
- } else
150
- // Direct usage of the typia identifier (not as property access)
151
- // This is definitely non-transformable usage
152
- nonTransformableUsage.add(identifier);
153
- }
154
- ts.forEachChild(node, checkUsage);
155
- };
156
-
157
- // Check all statements except import declarations
158
- for (const stmt of file.statements)
159
- if (
160
- !ts.isImportDeclaration(stmt) ||
161
- !ts.isStringLiteral(stmt.moduleSpecifier) ||
162
- stmt.moduleSpecifier.text !== "typia"
163
- )
164
- checkUsage(stmt);
165
-
166
- // Update import statements
167
- const newStatements: ts.Statement[] = file.statements
168
- .map((stmt) => {
169
- if (
170
- ts.isImportDeclaration(stmt) &&
171
- ts.isStringLiteral(stmt.moduleSpecifier) &&
172
- stmt.moduleSpecifier.text === "typia" &&
173
- stmt.importClause
174
- ) {
175
- const newImportClause = filterTypiaImportClause(
176
- stmt.importClause,
177
- nonTransformableUsage,
178
- );
179
- if (newImportClause)
180
- return ts.factory.createImportDeclaration(
181
- stmt.modifiers,
182
- newImportClause,
183
- stmt.moduleSpecifier,
184
- stmt.attributes,
185
- );
186
- return null; // Skip adding the import if all imports are unused
187
- }
188
- return stmt;
189
- })
190
- .filter((stmt) => stmt !== null);
191
- return ts.factory.updateSourceFile(
192
- file,
193
- newStatements,
194
- file.isDeclarationFile,
195
- file.referencedFiles,
196
- file.typeReferenceDirectives,
197
- file.hasNoDefaultLib,
198
- file.libReferenceDirectives,
199
- );
200
- };
201
-
202
- /**
203
- * Check if a property access expression looks like a transformable typia call
204
- * This uses heuristics to detect patterns like typia.xxx(),
205
- * typia.namespace.xxx()
206
- */
207
- const isLikelyTransformableCall = (
208
- node: ts.PropertyAccessExpression,
209
- ): boolean => {
210
- // Check if this is eventually part of a call expression
211
- let current: ts.Node = node;
212
-
213
- // Walk up the chain to find if this leads to a call expression
214
- // Handle patterns like: typia.xxx(), typia.namespace.xxx()
215
- while (ts.isPropertyAccessExpression(current)) {
216
- current = current.parent;
217
- }
218
-
219
- // If the final result is a call expression, this is likely transformable
220
- if (
221
- ts.isCallExpression(current) &&
222
- (current.expression === node ||
223
- (ts.isPropertyAccessExpression(current.expression) &&
224
- isTypiaPropertyChain(current.expression)))
225
- ) {
226
- return true;
227
- }
228
-
229
- return false;
230
- };
231
-
232
- /** Check if a property access expression is part of a typia.xxx.yyy chain */
233
- const isTypiaPropertyChain = (node: ts.PropertyAccessExpression): boolean => {
234
- let current: ts.Expression = node;
235
-
236
- while (ts.isPropertyAccessExpression(current)) {
237
- current = current.expression;
238
- }
239
-
240
- return ts.isIdentifier(current) && current.text === "typia";
241
- };
242
-
243
- /** Filter import clause to remove unused default imports */
244
- const filterTypiaImportClause = (
245
- importClause: ts.ImportClause,
246
- usedImports: Set<string>,
247
- ): ts.ImportClause | undefined => {
248
- const hasDefaultImport =
249
- importClause.name && usedImports.has(importClause.name.text);
250
- const namedBindings = importClause.namedBindings; // Always keep named bindings like { tags }
251
-
252
- // Return undefined if no imports are used
253
- if (!hasDefaultImport && !namedBindings) {
254
- return undefined;
255
- }
256
-
257
- return ts.factory.createImportClause(
258
- importClause.isTypeOnly,
259
- hasDefaultImport ? importClause.name : undefined,
260
- namedBindings,
261
- );
262
- };
1
+ import path from "path";
2
+ import ts from "typescript";
3
+
4
+ /**
5
+ * Transforms import paths for typia build output.
6
+ *
7
+ * Rewrites relative import paths when building typia packages. Also removes
8
+ * unused typia imports that only contained transformable function calls (since
9
+ * those are replaced at compile time).
10
+ *
11
+ * @author Jeongho Nam - https://github.com/samchon
12
+ */
13
+ export namespace ImportTransformer {
14
+ export const transform =
15
+ (props: { from: string; to: string }) =>
16
+ (context: ts.TransformationContext) =>
17
+ (file: ts.SourceFile) =>
18
+ transform_file({
19
+ top: props.from,
20
+ to: props.to,
21
+ context,
22
+ file,
23
+ });
24
+
25
+ const transform_file = (props: {
26
+ top: string;
27
+ to: string;
28
+ context: ts.TransformationContext;
29
+ file: ts.SourceFile;
30
+ }): ts.SourceFile => {
31
+ if (props.file.isDeclarationFile) return props.file;
32
+
33
+ const from: string = get_directory_path(
34
+ path.resolve(props.file.getSourceFile().fileName),
35
+ );
36
+ const to: string = from.replace(props.top, props.to);
37
+
38
+ // First pass: transform relative imports
39
+ let transformedFile = ts.visitEachChild(
40
+ props.file,
41
+ (node) =>
42
+ transform_node({
43
+ top: props.top,
44
+ from,
45
+ to,
46
+ node,
47
+ }),
48
+ props.context,
49
+ );
50
+
51
+ // Second pass: remove unused typia imports
52
+ transformedFile = removeUnusedTypiaImports(transformedFile);
53
+
54
+ return transformedFile;
55
+ };
56
+
57
+ const transform_node = (props: {
58
+ top: string;
59
+ from: string;
60
+ to: string;
61
+ node: ts.Node;
62
+ }) => {
63
+ if (
64
+ !ts.isImportDeclaration(props.node) ||
65
+ !ts.isStringLiteral(props.node.moduleSpecifier)
66
+ )
67
+ return props.node;
68
+
69
+ const text: string = props.node.moduleSpecifier.text;
70
+ if (text[0] !== ".") return props.node;
71
+
72
+ const location: string = path.resolve(props.from, text);
73
+ if (location.indexOf(props.top) === 0) return props.node;
74
+
75
+ const replaced: string = (() => {
76
+ const simple: string = path
77
+ .relative(props.to, location)
78
+ .split(path.sep)
79
+ .join("/");
80
+ return simple[0] === "." ? simple : `./${simple}`;
81
+ })();
82
+
83
+ return ts.factory.createImportDeclaration(
84
+ undefined,
85
+ props.node.importClause,
86
+ ts.factory.createStringLiteral(replaced),
87
+ props.node.assertClause,
88
+ );
89
+ };
90
+ }
91
+
92
+ const get_directory_path = (file: string): string => {
93
+ const split: string[] = path.resolve(file).split(path.sep);
94
+ split.pop();
95
+ return path.resolve(split.join(path.sep));
96
+ };
97
+
98
+ /** Remove unused typia imports that are only used in transformable calls */
99
+ const removeUnusedTypiaImports = (file: ts.SourceFile): ts.SourceFile => {
100
+ // Find typia imports and collect all identifiers
101
+ interface ImportMetadata {
102
+ declaration: ts.ImportDeclaration;
103
+ default: boolean;
104
+ }
105
+ const imports: Map<string, ImportMetadata> = new Map();
106
+ for (const stmt of file.statements) {
107
+ if (
108
+ ts.isImportDeclaration(stmt) === false ||
109
+ ts.isStringLiteral(stmt.moduleSpecifier) === false ||
110
+ stmt.moduleSpecifier.text !== "typia" ||
111
+ stmt.importClause === undefined
112
+ )
113
+ continue;
114
+
115
+ // Track default import (import typia from 'typia')
116
+ if (stmt.importClause.name)
117
+ imports.set(stmt.importClause.name.text, {
118
+ declaration: stmt,
119
+ default: true,
120
+ });
121
+
122
+ // Track named imports (import { tags } from 'typia') - keep these
123
+ if (
124
+ stmt.importClause.namedBindings &&
125
+ ts.isNamedImports(stmt.importClause.namedBindings)
126
+ )
127
+ for (const element of stmt.importClause.namedBindings.elements)
128
+ imports.set(element.name.text, {
129
+ declaration: stmt,
130
+ default: false,
131
+ });
132
+ }
133
+ if (imports.size === 0) return file; // No typia imports to check
134
+
135
+ // Find usage of typia identifiers that are NOT transformable calls
136
+ const nonTransformableUsage = new Set<string>();
137
+ const checkUsage = (node: ts.Node) => {
138
+ if (ts.isIdentifier(node) && imports.has(node.text)) {
139
+ const identifier: string = node.text;
140
+ // Check if this identifier is being used as part of a property access
141
+ if (
142
+ node.parent &&
143
+ ts.isPropertyAccessExpression(node.parent) &&
144
+ node.parent.expression === node
145
+ ) {
146
+ // This is typia.something - check if it's a transformable call pattern
147
+ if (!isLikelyTransformableCall(node.parent))
148
+ nonTransformableUsage.add(identifier);
149
+ } else
150
+ // Direct usage of the typia identifier (not as property access)
151
+ // This is definitely non-transformable usage
152
+ nonTransformableUsage.add(identifier);
153
+ }
154
+ ts.forEachChild(node, checkUsage);
155
+ };
156
+
157
+ // Check all statements except import declarations
158
+ for (const stmt of file.statements)
159
+ if (
160
+ !ts.isImportDeclaration(stmt) ||
161
+ !ts.isStringLiteral(stmt.moduleSpecifier) ||
162
+ stmt.moduleSpecifier.text !== "typia"
163
+ )
164
+ checkUsage(stmt);
165
+
166
+ // Update import statements
167
+ const newStatements: ts.Statement[] = file.statements
168
+ .map((stmt) => {
169
+ if (
170
+ ts.isImportDeclaration(stmt) &&
171
+ ts.isStringLiteral(stmt.moduleSpecifier) &&
172
+ stmt.moduleSpecifier.text === "typia" &&
173
+ stmt.importClause
174
+ ) {
175
+ const newImportClause = filterTypiaImportClause(
176
+ stmt.importClause,
177
+ nonTransformableUsage,
178
+ );
179
+ if (newImportClause)
180
+ return ts.factory.createImportDeclaration(
181
+ stmt.modifiers,
182
+ newImportClause,
183
+ stmt.moduleSpecifier,
184
+ stmt.attributes,
185
+ );
186
+ return null; // Skip adding the import if all imports are unused
187
+ }
188
+ return stmt;
189
+ })
190
+ .filter((stmt) => stmt !== null);
191
+ return ts.factory.updateSourceFile(
192
+ file,
193
+ newStatements,
194
+ file.isDeclarationFile,
195
+ file.referencedFiles,
196
+ file.typeReferenceDirectives,
197
+ file.hasNoDefaultLib,
198
+ file.libReferenceDirectives,
199
+ );
200
+ };
201
+
202
+ /**
203
+ * Check if a property access expression looks like a transformable typia call
204
+ * This uses heuristics to detect patterns like typia.xxx(),
205
+ * typia.namespace.xxx()
206
+ */
207
+ const isLikelyTransformableCall = (
208
+ node: ts.PropertyAccessExpression,
209
+ ): boolean => {
210
+ // Check if this is eventually part of a call expression
211
+ let current: ts.Node = node;
212
+
213
+ // Walk up the chain to find if this leads to a call expression
214
+ // Handle patterns like: typia.xxx(), typia.namespace.xxx()
215
+ while (ts.isPropertyAccessExpression(current)) {
216
+ current = current.parent;
217
+ }
218
+
219
+ // If the final result is a call expression, this is likely transformable
220
+ if (
221
+ ts.isCallExpression(current) &&
222
+ (current.expression === node ||
223
+ (ts.isPropertyAccessExpression(current.expression) &&
224
+ isTypiaPropertyChain(current.expression)))
225
+ ) {
226
+ return true;
227
+ }
228
+
229
+ return false;
230
+ };
231
+
232
+ /** Check if a property access expression is part of a typia.xxx.yyy chain */
233
+ const isTypiaPropertyChain = (node: ts.PropertyAccessExpression): boolean => {
234
+ let current: ts.Expression = node;
235
+
236
+ while (ts.isPropertyAccessExpression(current)) {
237
+ current = current.expression;
238
+ }
239
+
240
+ return ts.isIdentifier(current) && current.text === "typia";
241
+ };
242
+
243
+ /** Filter import clause to remove unused default imports */
244
+ const filterTypiaImportClause = (
245
+ importClause: ts.ImportClause,
246
+ usedImports: Set<string>,
247
+ ): ts.ImportClause | undefined => {
248
+ const hasDefaultImport =
249
+ importClause.name && usedImports.has(importClause.name.text);
250
+ const namedBindings = importClause.namedBindings; // Always keep named bindings like { tags }
251
+
252
+ // Return undefined if no imports are used
253
+ if (!hasDefaultImport && !namedBindings) {
254
+ return undefined;
255
+ }
256
+
257
+ return ts.factory.createImportClause(
258
+ importClause.isTypeOnly,
259
+ hasDefaultImport ? importClause.name : undefined,
260
+ namedBindings,
261
+ );
262
+ };
@@ -1,25 +1,25 @@
1
- import { ITypiaContext } from "@typia/core";
2
- import ts from "typescript";
3
-
4
- import { CallExpressionTransformer } from "./CallExpressionTransformer";
5
-
6
- /**
7
- * TypeScript AST node transformer.
8
- *
9
- * Delegates call expression nodes to {@link CallExpressionTransformer} for
10
- * potential `typia.*` function transformation. Non-call nodes pass through.
11
- *
12
- * @author Jeongho Nam - https://github.com/samchon
13
- */
14
- export namespace NodeTransformer {
15
- export const transform = (props: {
16
- context: ITypiaContext;
17
- node: ts.Node;
18
- }): ts.Node | null =>
19
- ts.isCallExpression(props.node) && props.node.parent
20
- ? CallExpressionTransformer.transform({
21
- context: props.context,
22
- expression: props.node,
23
- })
24
- : props.node;
25
- }
1
+ import { ITypiaContext } from "@typia/core";
2
+ import ts from "typescript";
3
+
4
+ import { CallExpressionTransformer } from "./CallExpressionTransformer";
5
+
6
+ /**
7
+ * TypeScript AST node transformer.
8
+ *
9
+ * Delegates call expression nodes to {@link CallExpressionTransformer} for
10
+ * potential `typia.*` function transformation. Non-call nodes pass through.
11
+ *
12
+ * @author Jeongho Nam - https://github.com/samchon
13
+ */
14
+ export namespace NodeTransformer {
15
+ export const transform = (props: {
16
+ context: ITypiaContext;
17
+ node: ts.Node;
18
+ }): ts.Node | null =>
19
+ ts.isCallExpression(props.node) && props.node.parent
20
+ ? CallExpressionTransformer.transform({
21
+ context: props.context,
22
+ expression: props.node,
23
+ })
24
+ : props.node;
25
+ }