@nestia/sdk 12.0.0-dev.20260612.2 → 12.0.0-rc.1

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 (103) hide show
  1. package/assets/bundle/distribute/package.json +1 -1
  2. package/lib/analyses/AccessorAnalyzer.js +33 -10
  3. package/lib/analyses/AccessorAnalyzer.js.map +1 -1
  4. package/lib/analyses/ConfigAnalyzer.js +11 -37
  5. package/lib/analyses/ConfigAnalyzer.js.map +1 -1
  6. package/lib/factories/ExpressionFactory.d.ts +9 -0
  7. package/lib/factories/ExpressionFactory.js +16 -0
  8. package/lib/factories/ExpressionFactory.js.map +1 -0
  9. package/lib/factories/IdentifierFactory.d.ts +22 -0
  10. package/lib/factories/IdentifierFactory.js +50 -0
  11. package/lib/factories/IdentifierFactory.js.map +1 -0
  12. package/lib/factories/LiteralFactory.d.ts +9 -0
  13. package/lib/factories/LiteralFactory.js +48 -0
  14. package/lib/factories/LiteralFactory.js.map +1 -0
  15. package/lib/factories/StatementFactory.d.ts +14 -0
  16. package/lib/factories/StatementFactory.js +20 -0
  17. package/lib/factories/StatementFactory.js.map +1 -0
  18. package/lib/factories/TypeFactory.d.ts +24 -0
  19. package/lib/factories/TypeFactory.js +27 -0
  20. package/lib/factories/TypeFactory.js.map +1 -0
  21. package/lib/generates/CloneGenerator.js +2 -2
  22. package/lib/generates/CloneGenerator.js.map +1 -1
  23. package/lib/generates/internal/E2eFileProgrammer.js +30 -29
  24. package/lib/generates/internal/E2eFileProgrammer.js.map +1 -1
  25. package/lib/generates/internal/FilePrinter.d.ts +2 -2
  26. package/lib/generates/internal/FilePrinter.js +14 -25
  27. package/lib/generates/internal/FilePrinter.js.map +1 -1
  28. package/lib/generates/internal/ImportDictionary.d.ts +1 -1
  29. package/lib/generates/internal/ImportDictionary.js +10 -9
  30. package/lib/generates/internal/ImportDictionary.js.map +1 -1
  31. package/lib/generates/internal/SdkAliasCollection.d.ts +12 -12
  32. package/lib/generates/internal/SdkAliasCollection.js +23 -25
  33. package/lib/generates/internal/SdkAliasCollection.js.map +1 -1
  34. package/lib/generates/internal/SdkFileProgrammer.js +2 -2
  35. package/lib/generates/internal/SdkFileProgrammer.js.map +1 -1
  36. package/lib/generates/internal/SdkHttpCloneProgrammer.d.ts +1 -1
  37. package/lib/generates/internal/SdkHttpCloneProgrammer.js +3 -3
  38. package/lib/generates/internal/SdkHttpCloneProgrammer.js.map +1 -1
  39. package/lib/generates/internal/SdkHttpFunctionProgrammer.d.ts +1 -1
  40. package/lib/generates/internal/SdkHttpFunctionProgrammer.js +45 -48
  41. package/lib/generates/internal/SdkHttpFunctionProgrammer.js.map +1 -1
  42. package/lib/generates/internal/SdkHttpNamespaceProgrammer.d.ts +1 -1
  43. package/lib/generates/internal/SdkHttpNamespaceProgrammer.js +61 -60
  44. package/lib/generates/internal/SdkHttpNamespaceProgrammer.js.map +1 -1
  45. package/lib/generates/internal/SdkHttpParameterProgrammer.d.ts +2 -2
  46. package/lib/generates/internal/SdkHttpParameterProgrammer.js +11 -13
  47. package/lib/generates/internal/SdkHttpParameterProgrammer.js.map +1 -1
  48. package/lib/generates/internal/SdkHttpRouteProgrammer.d.ts +1 -1
  49. package/lib/generates/internal/SdkHttpSimulationProgrammer.d.ts +1 -1
  50. package/lib/generates/internal/SdkHttpSimulationProgrammer.js +50 -48
  51. package/lib/generates/internal/SdkHttpSimulationProgrammer.js.map +1 -1
  52. package/lib/generates/internal/SdkMcpRouteProgrammer.d.ts +1 -1
  53. package/lib/generates/internal/SdkMcpRouteProgrammer.js +54 -53
  54. package/lib/generates/internal/SdkMcpRouteProgrammer.js.map +1 -1
  55. package/lib/generates/internal/SdkTypeProgrammer.d.ts +3 -3
  56. package/lib/generates/internal/SdkTypeProgrammer.js +42 -43
  57. package/lib/generates/internal/SdkTypeProgrammer.js.map +1 -1
  58. package/lib/generates/internal/SdkTypeTagProgrammer.d.ts +2 -1
  59. package/lib/generates/internal/SdkTypeTagProgrammer.js +7 -9
  60. package/lib/generates/internal/SdkTypeTagProgrammer.js.map +1 -1
  61. package/lib/generates/internal/SdkWebSocketNamespaceProgrammer.d.ts +2 -2
  62. package/lib/generates/internal/SdkWebSocketNamespaceProgrammer.js +45 -47
  63. package/lib/generates/internal/SdkWebSocketNamespaceProgrammer.js.map +1 -1
  64. package/lib/generates/internal/SdkWebSocketParameterProgrammer.d.ts +3 -3
  65. package/lib/generates/internal/SdkWebSocketParameterProgrammer.js +9 -9
  66. package/lib/generates/internal/SdkWebSocketParameterProgrammer.js.map +1 -1
  67. package/lib/generates/internal/SdkWebSocketRouteProgrammer.d.ts +2 -2
  68. package/lib/generates/internal/SdkWebSocketRouteProgrammer.js +34 -40
  69. package/lib/generates/internal/SdkWebSocketRouteProgrammer.js.map +1 -1
  70. package/lib/transform.d.ts +5 -9
  71. package/lib/transform.js +8 -31
  72. package/lib/transform.js.map +1 -1
  73. package/lib/utils/SourceFinder.d.ts +1 -0
  74. package/lib/utils/SourceFinder.js +6 -3
  75. package/lib/utils/SourceFinder.js.map +1 -1
  76. package/package.json +11 -11
  77. package/src/analyses/AccessorAnalyzer.ts +39 -10
  78. package/src/analyses/ConfigAnalyzer.ts +19 -5
  79. package/src/factories/ExpressionFactory.ts +23 -0
  80. package/src/factories/IdentifierFactory.ts +84 -0
  81. package/src/factories/LiteralFactory.ts +54 -0
  82. package/src/factories/StatementFactory.ts +56 -0
  83. package/src/factories/TypeFactory.ts +27 -0
  84. package/src/generates/CloneGenerator.ts +8 -7
  85. package/src/generates/internal/E2eFileProgrammer.ts +59 -53
  86. package/src/generates/internal/FilePrinter.ts +28 -36
  87. package/src/generates/internal/ImportDictionary.ts +19 -21
  88. package/src/generates/internal/SdkAliasCollection.ts +55 -49
  89. package/src/generates/internal/SdkFileProgrammer.ts +4 -7
  90. package/src/generates/internal/SdkHttpCloneProgrammer.ts +11 -13
  91. package/src/generates/internal/SdkHttpFunctionProgrammer.ts +90 -101
  92. package/src/generates/internal/SdkHttpNamespaceProgrammer.ts +153 -166
  93. package/src/generates/internal/SdkHttpParameterProgrammer.ts +15 -17
  94. package/src/generates/internal/SdkHttpRouteProgrammer.ts +1 -1
  95. package/src/generates/internal/SdkHttpSimulationProgrammer.ts +121 -130
  96. package/src/generates/internal/SdkMcpRouteProgrammer.ts +135 -140
  97. package/src/generates/internal/SdkTypeProgrammer.ts +389 -382
  98. package/src/generates/internal/SdkTypeTagProgrammer.ts +13 -17
  99. package/src/generates/internal/SdkWebSocketNamespaceProgrammer.ts +124 -130
  100. package/src/generates/internal/SdkWebSocketParameterProgrammer.ts +17 -15
  101. package/src/generates/internal/SdkWebSocketRouteProgrammer.ts +112 -139
  102. package/src/transform.ts +14 -45
  103. package/src/utils/SourceFinder.ts +9 -3
@@ -0,0 +1,84 @@
1
+ import {
2
+ type Expression,
3
+ type Identifier,
4
+ type ParameterDeclaration,
5
+ type StringLiteral,
6
+ SyntaxKind,
7
+ type Token,
8
+ type TypeNode,
9
+ factory,
10
+ } from "@ttsc/factory";
11
+
12
+ import { TypeFactory } from "./TypeFactory";
13
+
14
+ // Conservative "is this string a syntactically valid JavaScript variable
15
+ // name?" test, inlined to avoid pulling in @typia/utils' full namespace.
16
+ const VARIABLE_REGEX = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
17
+ const isVariableName = (str: string): boolean => VARIABLE_REGEX.test(str);
18
+
19
+ /**
20
+ * Identifier and member-access helpers. The surface kept here is the subset
21
+ * nestia generators actually call (`identifier`, `access`, `parameter`).
22
+ */
23
+ export namespace IdentifierFactory {
24
+ /**
25
+ * Build an identifier or string literal depending on whether `name` is a
26
+ * valid JavaScript identifier.
27
+ */
28
+ export const identifier = (name: string): Identifier | StringLiteral =>
29
+ isVariableName(name)
30
+ ? factory.createIdentifier(name)
31
+ : factory.createStringLiteral(name);
32
+
33
+ /**
34
+ * Member access on `input` by `key`. Falls back to element access when the
35
+ * key is not a valid identifier.
36
+ */
37
+ export const access = (
38
+ input: Expression,
39
+ key: string,
40
+ chain?: boolean,
41
+ ): Expression => {
42
+ const postfix = identifier(key);
43
+ if (postfix.kind === "StringLiteral")
44
+ return chain === true
45
+ ? factory.createElementAccessChain(
46
+ input,
47
+ factory.createToken(SyntaxKind.QuestionDotToken),
48
+ postfix,
49
+ )
50
+ : factory.createElementAccessExpression(input, postfix);
51
+ return chain === true
52
+ ? factory.createPropertyAccessChain(
53
+ input,
54
+ factory.createToken(SyntaxKind.QuestionDotToken),
55
+ postfix,
56
+ )
57
+ : factory.createPropertyAccessExpression(input, postfix);
58
+ };
59
+
60
+ /**
61
+ * Parameter declaration with default `any` type when the caller omits one.
62
+ * Passing a `QuestionToken` as `init` marks the parameter optional.
63
+ */
64
+ export const parameter = (
65
+ name: string | Identifier,
66
+ type?: TypeNode,
67
+ init?: Expression | Token,
68
+ ): ParameterDeclaration => {
69
+ const isQuestionToken =
70
+ !!init &&
71
+ init.kind === "Token" &&
72
+ (init as Token).token === SyntaxKind.QuestionToken;
73
+ return factory.createParameterDeclaration(
74
+ undefined,
75
+ undefined,
76
+ name,
77
+ isQuestionToken
78
+ ? factory.createToken(SyntaxKind.QuestionToken)
79
+ : undefined,
80
+ type ?? TypeFactory.keyword("any"),
81
+ isQuestionToken ? undefined : (init as Expression | undefined),
82
+ );
83
+ };
84
+ }
@@ -0,0 +1,54 @@
1
+ import { type Expression, factory } from "@ttsc/factory";
2
+
3
+ import { ExpressionFactory } from "./ExpressionFactory";
4
+ import { IdentifierFactory } from "./IdentifierFactory";
5
+
6
+ const PASSTHROUGH_KINDS = new Set<string>([
7
+ "ArrowFunction",
8
+ "CallExpression",
9
+ "Identifier",
10
+ ]);
11
+
12
+ const isNode = (value: unknown): value is Expression =>
13
+ typeof value === "object" &&
14
+ value !== null &&
15
+ typeof (value as { kind?: unknown }).kind === "string";
16
+
17
+ /**
18
+ * Recursive value-to-AST-literal builder. Hands back already-AST inputs
19
+ * unchanged (so callers can mix factory output with raw JS values inside the
20
+ * same object/array), and emits the appropriate literal node otherwise.
21
+ */
22
+ export namespace LiteralFactory {
23
+ export const write = (input: any): Expression => {
24
+ if (input === null) return factory.createNull();
25
+ if (isNode(input) && PASSTHROUGH_KINDS.has(input.kind)) return input;
26
+ if (Array.isArray(input)) return writeArray(input);
27
+ if (typeof input === "object") return writeObject(input as object);
28
+ if (typeof input === "boolean")
29
+ return input ? factory.createTrue() : factory.createFalse();
30
+ if (typeof input === "number") return ExpressionFactory.number(input);
31
+ if (typeof input === "string") return factory.createStringLiteral(input);
32
+ if (typeof input === "bigint")
33
+ return factory.createStringLiteral(input.toString());
34
+ if (typeof input === "function")
35
+ return factory.createIdentifier("undefined");
36
+ throw new TypeError("LiteralFactory.write: unsupported input type.");
37
+ };
38
+
39
+ const writeObject = (obj: object): Expression =>
40
+ factory.createObjectLiteralExpression(
41
+ Object.entries(obj)
42
+ .filter(([, value]) => value !== undefined)
43
+ .map(([key, value]) =>
44
+ factory.createPropertyAssignment(
45
+ IdentifierFactory.identifier(key),
46
+ write(value),
47
+ ),
48
+ ),
49
+ true,
50
+ );
51
+
52
+ const writeArray = (array: readonly any[]): Expression =>
53
+ factory.createArrayLiteralExpression(array.map(write), true);
54
+ }
@@ -0,0 +1,56 @@
1
+ import {
2
+ type Expression,
3
+ NodeFlags,
4
+ type TypeNode,
5
+ type VariableStatement,
6
+ factory,
7
+ } from "@ttsc/factory";
8
+
9
+ import { TypeFactory } from "./TypeFactory";
10
+
11
+ /** Variable-statement helpers. `constant` emits `const`, `mut` emits `let`. */
12
+ export namespace StatementFactory {
13
+ export const mut = (props: {
14
+ name: string;
15
+ type?: TypeNode | undefined;
16
+ initializer?: Expression | undefined;
17
+ }): VariableStatement =>
18
+ factory.createVariableStatement(
19
+ undefined,
20
+ factory.createVariableDeclarationList(
21
+ [
22
+ factory.createVariableDeclaration(
23
+ props.name,
24
+ undefined,
25
+ props.type !== undefined
26
+ ? props.type
27
+ : props.initializer === undefined
28
+ ? TypeFactory.keyword("any")
29
+ : undefined,
30
+ props.initializer,
31
+ ),
32
+ ],
33
+ NodeFlags.Let,
34
+ ),
35
+ );
36
+
37
+ export const constant = (props: {
38
+ name: string;
39
+ type?: TypeNode | undefined;
40
+ value?: Expression | undefined;
41
+ }): VariableStatement =>
42
+ factory.createVariableStatement(
43
+ undefined,
44
+ factory.createVariableDeclarationList(
45
+ [
46
+ factory.createVariableDeclaration(
47
+ props.name,
48
+ undefined,
49
+ props.type,
50
+ props.value,
51
+ ),
52
+ ],
53
+ NodeFlags.Const,
54
+ ),
55
+ );
56
+ }
@@ -0,0 +1,27 @@
1
+ import { type KeywordTypeNode, SyntaxKind, factory } from "@ttsc/factory";
2
+
3
+ /**
4
+ * Higher-level type-keyword factory.
5
+ *
6
+ * Wraps {@link factory.createKeywordTypeNode} with a name-based interface so
7
+ * generator code reads as `TypeFactory.keyword("any")` instead of selecting the
8
+ * `SyntaxKind.AnyKeyword` token by hand.
9
+ */
10
+ export namespace TypeFactory {
11
+ const KEYWORDS = {
12
+ void: SyntaxKind.VoidKeyword,
13
+ any: SyntaxKind.AnyKeyword,
14
+ unknown: SyntaxKind.UnknownKeyword,
15
+ boolean: SyntaxKind.BooleanKeyword,
16
+ number: SyntaxKind.NumberKeyword,
17
+ bigint: SyntaxKind.BigIntKeyword,
18
+ string: SyntaxKind.StringKeyword,
19
+ never: SyntaxKind.NeverKeyword,
20
+ undefined: SyntaxKind.UndefinedKeyword,
21
+ } as const;
22
+
23
+ export type Keyword = keyof typeof KEYWORDS;
24
+
25
+ export const keyword = (type: Keyword): KeywordTypeNode =>
26
+ factory.createKeywordTypeNode(KEYWORDS[type]);
27
+ }
@@ -1,9 +1,10 @@
1
1
  import {
2
- Node,
2
+ type Node,
3
3
  NodeFlags,
4
+ type Statement,
4
5
  SyntaxKind,
5
- TypeScriptFactory,
6
- } from "@nestia/factory";
6
+ factory,
7
+ } from "@ttsc/factory";
7
8
  import fs from "fs";
8
9
 
9
10
  import { INestiaProject } from "../structures/INestiaProject";
@@ -60,10 +61,10 @@ export namespace CloneGenerator {
60
61
  for (const child of modulo.children.values())
61
62
  internal.push(...iterate(importer)(child));
62
63
  output.push(
63
- TypeScriptFactory.createModuleDeclaration(
64
- [TypeScriptFactory.createModifier(SyntaxKind.ExportKeyword)],
65
- TypeScriptFactory.createIdentifier(modulo.name),
66
- TypeScriptFactory.createModuleBlock(internal),
64
+ factory.createModuleDeclaration(
65
+ [factory.createModifier(SyntaxKind.ExportKeyword)],
66
+ factory.createIdentifier(modulo.name),
67
+ factory.createModuleBlock(internal as Statement[]),
67
68
  NodeFlags.Namespace,
68
69
  ),
69
70
  );
@@ -1,11 +1,14 @@
1
1
  import {
2
- Node,
2
+ type Node,
3
3
  NodeFlags,
4
+ type NumericLiteral,
4
5
  SyntaxKind,
5
- TypeScriptFactory,
6
- } from "@nestia/factory";
7
- import { IdentifierFactory, LiteralFactory } from "@nestia/factory";
6
+ type TypeNode,
7
+ factory,
8
+ } from "@ttsc/factory";
8
9
 
10
+ import { IdentifierFactory } from "../../factories/IdentifierFactory";
11
+ import { LiteralFactory } from "../../factories/LiteralFactory";
9
12
  import { INestiaProject } from "../../structures/INestiaProject";
10
13
  import { ITypedHttpRoute } from "../../structures/ITypedHttpRoute";
11
14
  import { FilePrinter } from "./FilePrinter";
@@ -44,12 +47,12 @@ export namespace E2eFileProgrammer {
44
47
  (project: INestiaProject) =>
45
48
  (importer: ImportDictionary) =>
46
49
  (route: ITypedHttpRoute): Node =>
47
- TypeScriptFactory.createVariableStatement(
48
- [TypeScriptFactory.createModifier(SyntaxKind.ExportKeyword)],
49
- TypeScriptFactory.createVariableDeclarationList(
50
+ factory.createVariableStatement(
51
+ [factory.createModifier(SyntaxKind.ExportKeyword)],
52
+ factory.createVariableDeclarationList(
50
53
  [
51
- TypeScriptFactory.createVariableDeclaration(
52
- TypeScriptFactory.createIdentifier(getFunctionName(route)),
54
+ factory.createVariableDeclaration(
55
+ factory.createIdentifier(getFunctionName(route)),
53
56
  undefined,
54
57
  undefined,
55
58
  generateArrow(project)(importer)(route),
@@ -64,34 +67,36 @@ export namespace E2eFileProgrammer {
64
67
  (importer: ImportDictionary) =>
65
68
  (route: ITypedHttpRoute) => {
66
69
  const random = IdentifierFactory.access(
67
- TypeScriptFactory.createIdentifier(SdkImportWizard.typia(importer)),
70
+ factory.createIdentifier(SdkImportWizard.typia(importer)),
68
71
  "random",
69
72
  );
70
73
  const connection = route.headerObject
71
- ? TypeScriptFactory.createObjectLiteralExpression(
74
+ ? factory.createObjectLiteralExpression(
72
75
  [
73
- TypeScriptFactory.createSpreadAssignment(
74
- TypeScriptFactory.createIdentifier("connection"),
76
+ factory.createSpreadAssignment(
77
+ factory.createIdentifier("connection"),
75
78
  ),
76
- TypeScriptFactory.createPropertyAssignment(
79
+ factory.createPropertyAssignment(
77
80
  "headers",
78
- TypeScriptFactory.createObjectLiteralExpression(
81
+ factory.createObjectLiteralExpression(
79
82
  [
80
- TypeScriptFactory.createSpreadAssignment(
83
+ factory.createSpreadAssignment(
81
84
  IdentifierFactory.access(
82
- TypeScriptFactory.createIdentifier("connection"),
85
+ factory.createIdentifier("connection"),
83
86
  "headers",
84
87
  ),
85
88
  ),
86
- TypeScriptFactory.createSpreadAssignment(
87
- TypeScriptFactory.createCallExpression(
89
+ factory.createSpreadAssignment(
90
+ factory.createCallExpression(
88
91
  random,
89
92
  [
90
- project.config.clone === true
93
+ (project.config.clone === true
91
94
  ? SdkAliasCollection.from(project)(importer)(
92
95
  route.headerObject.metadata,
93
96
  )
94
- : SdkAliasCollection.name(route.headerObject),
97
+ : SdkAliasCollection.name(
98
+ route.headerObject,
99
+ )) as TypeNode,
95
100
  ],
96
101
  undefined,
97
102
  ),
@@ -103,7 +108,7 @@ export namespace E2eFileProgrammer {
103
108
  ],
104
109
  true,
105
110
  )
106
- : TypeScriptFactory.createIdentifier("connection");
111
+ : factory.createIdentifier("connection");
107
112
  const entries = SdkHttpParameterProgrammer.getEntries({
108
113
  project,
109
114
  importer,
@@ -112,8 +117,8 @@ export namespace E2eFileProgrammer {
112
117
  e2e: true,
113
118
  prefix: ["api", "functional", ...route.accessor].join(".") + ".",
114
119
  });
115
- const fetch = TypeScriptFactory.createCallExpression(
116
- TypeScriptFactory.createIdentifier(
120
+ const fetch = factory.createCallExpression(
121
+ factory.createIdentifier(
117
122
  ["api", "functional", ...route.accessor].join("."),
118
123
  ),
119
124
  undefined,
@@ -125,9 +130,9 @@ export namespace E2eFileProgrammer {
125
130
  Object.fromEntries(
126
131
  entries.map((e) => [
127
132
  e.key,
128
- TypeScriptFactory.createCallExpression(
133
+ factory.createCallExpression(
129
134
  IdentifierFactory.access(
130
- TypeScriptFactory.createIdentifier(
135
+ factory.createIdentifier(
131
136
  SdkImportWizard.typia(importer),
132
137
  ),
133
138
  "random",
@@ -140,11 +145,9 @@ export namespace E2eFileProgrammer {
140
145
  ),
141
146
  ]
142
147
  : entries.map((e) =>
143
- TypeScriptFactory.createCallExpression(
148
+ factory.createCallExpression(
144
149
  IdentifierFactory.access(
145
- TypeScriptFactory.createIdentifier(
146
- SdkImportWizard.typia(importer),
147
- ),
150
+ factory.createIdentifier(SdkImportWizard.typia(importer)),
148
151
  "random",
149
152
  ),
150
153
  [getRandomType(importer)(e)],
@@ -153,39 +156,41 @@ export namespace E2eFileProgrammer {
153
156
  )),
154
157
  ],
155
158
  );
156
- const assert = TypeScriptFactory.createCallExpression(
159
+ const assert = factory.createCallExpression(
157
160
  IdentifierFactory.access(
158
- TypeScriptFactory.createIdentifier(SdkImportWizard.typia(importer)),
161
+ factory.createIdentifier(SdkImportWizard.typia(importer)),
159
162
  "assert",
160
163
  ),
161
164
  undefined,
162
- [TypeScriptFactory.createIdentifier("output")],
165
+ [factory.createIdentifier("output")],
163
166
  );
164
167
 
165
- return TypeScriptFactory.createArrowFunction(
166
- [TypeScriptFactory.createModifier(SyntaxKind.AsyncKeyword)],
168
+ return factory.createArrowFunction(
169
+ [factory.createModifier(SyntaxKind.AsyncKeyword)],
167
170
  undefined,
168
171
  [
169
172
  IdentifierFactory.parameter(
170
173
  "connection",
171
- TypeScriptFactory.createTypeReferenceNode("api.IConnection"),
174
+ factory.createTypeReferenceNode("api.IConnection"),
172
175
  ),
173
176
  ],
174
177
  undefined,
175
178
  undefined,
176
- TypeScriptFactory.createBlock([
177
- TypeScriptFactory.createVariableStatement(
179
+ factory.createBlock([
180
+ factory.createVariableStatement(
178
181
  [],
179
- TypeScriptFactory.createVariableDeclarationList(
182
+ factory.createVariableDeclarationList(
180
183
  [
181
- TypeScriptFactory.createVariableDeclaration(
184
+ factory.createVariableDeclaration(
182
185
  "output",
183
186
  undefined,
184
187
  project.config.propagate !== true &&
185
188
  route.success.type!.name === "void"
186
189
  ? undefined
187
- : SdkAliasCollection.response(project)(importer)(route),
188
- TypeScriptFactory.createAwaitExpression(fetch),
190
+ : (SdkAliasCollection.response(project)(importer)(
191
+ route,
192
+ ) as TypeNode),
193
+ factory.createAwaitExpression(fetch),
189
194
  ),
190
195
  ],
191
196
  NodeFlags.Const,
@@ -193,7 +198,7 @@ export namespace E2eFileProgrammer {
193
198
  ),
194
199
  ...(route.success.binary === true
195
200
  ? []
196
- : [TypeScriptFactory.createExpressionStatement(assert)]),
201
+ : [factory.createExpressionStatement(assert)]),
197
202
  ]),
198
203
  );
199
204
  };
@@ -201,13 +206,14 @@ export namespace E2eFileProgrammer {
201
206
 
202
207
  const getRandomType =
203
208
  (importer: ImportDictionary) =>
204
- (entry: SdkHttpParameterProgrammer.IEntry): Node => {
205
- if (isPlainStringPathParameter(entry) === false) return entry.type;
206
- return TypeScriptFactory.createIntersectionTypeNode([
207
- entry.type,
208
- TypeScriptFactory.createTypeReferenceNode(
209
- TypeScriptFactory.createQualifiedName(
210
- TypeScriptFactory.createIdentifier(
209
+ (entry: SdkHttpParameterProgrammer.IEntry): TypeNode => {
210
+ if (isPlainStringPathParameter(entry) === false)
211
+ return entry.type as TypeNode;
212
+ return factory.createIntersectionTypeNode([
213
+ entry.type as TypeNode,
214
+ factory.createTypeReferenceNode(
215
+ factory.createQualifiedName(
216
+ factory.createIdentifier(
211
217
  importer.external({
212
218
  declaration: true,
213
219
  file: "typia",
@@ -215,11 +221,11 @@ const getRandomType =
215
221
  name: "tags",
216
222
  }),
217
223
  ),
218
- TypeScriptFactory.createIdentifier("MinLength"),
224
+ factory.createIdentifier("MinLength"),
219
225
  ),
220
226
  [
221
- TypeScriptFactory.createLiteralTypeNode(
222
- LiteralFactory.write(1) as Node,
227
+ factory.createLiteralTypeNode(
228
+ LiteralFactory.write(1) as NumericLiteral,
223
229
  ),
224
230
  ],
225
231
  ),
@@ -1,55 +1,47 @@
1
1
  import {
2
- Node,
2
+ type Node,
3
+ type Statement,
3
4
  SyntaxKind,
4
- TypeScriptFactory,
5
- TypeScriptPrinter,
6
- } from "@nestia/factory";
5
+ TsPrinter,
6
+ addSyntheticLeadingComment,
7
+ factory,
8
+ } from "@ttsc/factory";
7
9
  import fs from "fs";
8
10
  import { format } from "prettier";
9
11
 
10
12
  export namespace FilePrinter {
11
- export const description = <T extends Node>(
12
- node: T,
13
- comment: string,
14
- ): T => {
13
+ export const description = <T extends Node>(node: T, comment: string): T => {
15
14
  if (comment.length === 0) return node;
16
- node.emitNode ??= {};
17
- node.emitNode.leadingComments = [
18
- ...(node.emitNode.leadingComments ?? []),
19
- {
20
- kind: SyntaxKind.MultiLineCommentTrivia,
21
- text: [
22
- "*",
23
- ...comment
24
- .split("\r\n")
25
- .join("\n")
26
- .split("\n")
27
- .map(
28
- (str) =>
29
- ` * ${str.split("*/").join("*\\\\/").split("*\\/").join("*\\\\/")}`,
30
- ),
31
- "",
32
- ].join("\n"),
33
- hasTrailingNewLine: true,
34
- },
35
- ];
36
- return node;
15
+ return addSyntheticLeadingComment(
16
+ node,
17
+ SyntaxKind.MultiLineCommentTrivia,
18
+ [
19
+ "*",
20
+ ...comment
21
+ .split("\r\n")
22
+ .join("\n")
23
+ .split("\n")
24
+ .map(
25
+ (str) =>
26
+ ` * ${str.split("*/").join("*\\\\/").split("*\\/").join("*\\\\/")}`,
27
+ ),
28
+ "",
29
+ ].join("\n"),
30
+ true,
31
+ );
37
32
  };
38
33
 
39
34
  export const enter = () =>
40
- TypeScriptFactory.createExpressionStatement(
41
- TypeScriptFactory.createIdentifier("\n"),
42
- );
35
+ factory.createExpressionStatement(factory.createIdentifier("\n"));
43
36
 
44
37
  export const write = async (props: {
45
38
  location: string;
46
39
  statements: Node[];
47
40
  top?: string;
48
41
  }): Promise<void> => {
49
- const script: string = TypeScriptPrinter.write({
50
- statements: props.statements,
51
- top: props.top,
52
- });
42
+ const script: string =
43
+ (props.top ?? "") +
44
+ new TsPrinter().printFile(undefined, props.statements as Statement[]);
53
45
  await fs.promises.writeFile(props.location, await beautify(script), "utf8");
54
46
  };
55
47
 
@@ -1,4 +1,4 @@
1
- import { Node, TypeScriptFactory } from "@nestia/factory";
1
+ import { type ImportClause, type Node, factory } from "@ttsc/factory";
2
2
  import path from "path";
3
3
  import { HashMap, TreeMap, hash } from "tstl";
4
4
 
@@ -109,11 +109,10 @@ export class ImportDictionary {
109
109
  .sort((a, b) => a.file.localeCompare(b.file));
110
110
  for (const c of compositions)
111
111
  container.push(
112
- TypeScriptFactory.createImportDeclaration(
112
+ factory.createImportDeclaration(
113
113
  undefined,
114
114
  this.toImportClaude(c),
115
- TypeScriptFactory.createStringLiteral(c.file),
116
- undefined,
115
+ factory.createStringLiteral(c.file),
117
116
  ),
118
117
  );
119
118
  };
@@ -127,29 +126,28 @@ export class ImportDictionary {
127
126
  ];
128
127
  }
129
128
 
130
- private toImportClaude(c: ICompositeValue): Node {
129
+ private toImportClaude(c: ICompositeValue): ImportClause {
130
+ // A namespace import cannot carry a per-binding `type` modifier, so the
131
+ // type-only flag stays off here (a value namespace import resolves type
132
+ // members fine), matching the legacy printer output `import * as X`.
131
133
  if (c.asterisk !== null)
132
- return TypeScriptFactory.createImportClause(
133
- c.declaration,
134
+ return factory.createImportClause(
135
+ false,
134
136
  undefined,
135
- TypeScriptFactory.createNamespaceImport(
136
- TypeScriptFactory.createIdentifier(c.asterisk),
137
- ),
137
+ factory.createNamespaceImport(factory.createIdentifier(c.asterisk)),
138
138
  );
139
- return TypeScriptFactory.createImportClause(
139
+ // `c.declaration` (type-only) belongs on the import clause, not on each
140
+ // specifier — emitting both produces the invalid `import type { type X }`.
141
+ return factory.createImportClause(
140
142
  c.declaration,
141
- c.default !== null
142
- ? TypeScriptFactory.createIdentifier(c.default)
143
- : undefined,
143
+ c.default !== null ? factory.createIdentifier(c.default) : undefined,
144
144
  c.elements.size() !== 0
145
- ? TypeScriptFactory.createNamedImports(
145
+ ? factory.createNamedImports(
146
146
  Array.from(c.elements).map(({ first: name, second: alias }) =>
147
- TypeScriptFactory.createImportSpecifier(
148
- c.declaration,
149
- alias !== null
150
- ? TypeScriptFactory.createIdentifier(name)
151
- : undefined,
152
- TypeScriptFactory.createIdentifier(alias ?? name),
147
+ factory.createImportSpecifier(
148
+ false,
149
+ alias !== null ? factory.createIdentifier(name) : undefined,
150
+ factory.createIdentifier(alias ?? name),
153
151
  ),
154
152
  ),
155
153
  )