@nestia/core 12.0.0-dev.20260601.1 → 12.0.0-dev.20260612.2
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.
- package/LICENSE +21 -21
- package/MIGRATION.md +169 -169
- package/README.md +93 -93
- package/lib/adaptors/McpAdaptor.d.ts +75 -0
- package/lib/adaptors/McpAdaptor.js +257 -0
- package/lib/adaptors/McpAdaptor.js.map +1 -0
- package/lib/adaptors/WebSocketAdaptor.js +4 -4
- package/lib/adaptors/WebSocketAdaptor.js.map +1 -1
- package/lib/decorators/McpRoute.d.ts +69 -0
- package/lib/decorators/McpRoute.js +58 -0
- package/lib/decorators/McpRoute.js.map +1 -0
- package/lib/decorators/TypedParam.js +4 -4
- package/lib/decorators/TypedParam.js.map +1 -1
- package/lib/decorators/TypedRoute.js +1 -1
- package/lib/decorators/TypedRoute.js.map +1 -1
- package/lib/decorators/internal/IMcpRouteReflect.d.ts +2 -0
- package/lib/decorators/internal/IMcpRouteReflect.js +3 -0
- package/lib/decorators/internal/IMcpRouteReflect.js.map +1 -0
- package/lib/decorators/internal/get_path_and_querify.js +4 -4
- package/lib/decorators/internal/get_path_and_querify.js.map +1 -1
- package/lib/decorators/internal/get_path_and_stringify.js +4 -4
- package/lib/decorators/internal/get_path_and_stringify.js.map +1 -1
- package/lib/decorators/internal/load_controller.js +34 -65
- package/lib/decorators/internal/load_controller.js.map +1 -1
- package/lib/decorators/internal/validate_request_body.js +4 -4
- package/lib/decorators/internal/validate_request_body.js.map +1 -1
- package/lib/decorators/internal/validate_request_form_data.js +4 -4
- package/lib/decorators/internal/validate_request_form_data.js.map +1 -1
- package/lib/decorators/internal/validate_request_headers.js +4 -4
- package/lib/decorators/internal/validate_request_headers.js.map +1 -1
- package/lib/decorators/internal/validate_request_query.js +4 -4
- package/lib/decorators/internal/validate_request_query.js.map +1 -1
- package/lib/module.d.ts +2 -0
- package/lib/module.js +2 -0
- package/lib/module.js.map +1 -1
- package/native/cmd/ttsc-nestia/main.go +11 -11
- package/native/go.mod +32 -32
- package/native/go.sum +54 -54
- package/native/plugin/plan.go +102 -102
- package/native/transform/ast.go +32 -32
- package/native/transform/build.go +380 -444
- package/native/transform/cleanup.go +408 -408
- package/native/transform/contributor.go +97 -68
- package/native/transform/core_querify.go +231 -227
- package/native/transform/core_transform.go +1996 -1713
- package/native/transform/core_websocket.go +115 -115
- package/native/transform/exports.go +13 -13
- package/native/transform/mcp_transform.go +414 -0
- package/native/transform/node_transform.go +357 -0
- package/native/transform/path_rewrite.go +285 -285
- package/native/transform/printer.go +244 -244
- package/native/transform/rewrite.go +668 -662
- package/native/transform/run.go +73 -73
- package/native/transform/transform.go +336 -403
- package/native/transform/typia_fast.go +352 -326
- package/native/transform/typia_replacement.go +24 -24
- package/native/transform.cjs +43 -43
- package/package.json +15 -8
- package/src/adaptors/McpAdaptor.ts +276 -0
- package/src/adaptors/WebSocketAdaptor.ts +429 -429
- package/src/decorators/DynamicModule.ts +44 -44
- package/src/decorators/EncryptedBody.ts +97 -97
- package/src/decorators/EncryptedController.ts +40 -40
- package/src/decorators/EncryptedModule.ts +98 -98
- package/src/decorators/EncryptedRoute.ts +213 -213
- package/src/decorators/HumanRoute.ts +21 -21
- package/src/decorators/McpRoute.ts +154 -0
- package/src/decorators/NoTransformConfigurationError.ts +40 -40
- package/src/decorators/PlainBody.ts +76 -76
- package/src/decorators/SwaggerCustomizer.ts +97 -97
- package/src/decorators/SwaggerExample.ts +180 -180
- package/src/decorators/TypedBody.ts +57 -57
- package/src/decorators/TypedException.ts +147 -147
- package/src/decorators/TypedFormData.ts +187 -187
- package/src/decorators/TypedHeaders.ts +66 -66
- package/src/decorators/TypedParam.ts +77 -77
- package/src/decorators/TypedQuery.ts +234 -234
- package/src/decorators/TypedRoute.ts +198 -196
- package/src/decorators/WebSocketRoute.ts +242 -242
- package/src/decorators/doNotThrowTransformError.ts +5 -5
- package/src/decorators/internal/EncryptedConstant.ts +2 -2
- package/src/decorators/internal/IMcpRouteReflect.ts +40 -0
- package/src/decorators/internal/IWebSocketRouteReflect.ts +23 -23
- package/src/decorators/internal/get_path_and_querify.ts +94 -94
- package/src/decorators/internal/get_path_and_stringify.ts +110 -110
- package/src/decorators/internal/get_text_body.ts +16 -16
- package/src/decorators/internal/headers_to_object.ts +11 -11
- package/src/decorators/internal/is_request_body_undefined.ts +12 -12
- package/src/decorators/internal/load_controller.ts +91 -76
- package/src/decorators/internal/route_error.ts +43 -43
- package/src/decorators/internal/validate_request_body.ts +64 -64
- package/src/decorators/internal/validate_request_form_data.ts +67 -67
- package/src/decorators/internal/validate_request_headers.ts +76 -76
- package/src/decorators/internal/validate_request_query.ts +83 -83
- package/src/index.ts +5 -5
- package/src/module.ts +25 -23
- package/src/options/IRequestBodyValidator.ts +20 -20
- package/src/options/IRequestFormDataProps.ts +27 -27
- package/src/options/IRequestHeadersValidator.ts +22 -22
- package/src/options/IRequestQueryValidator.ts +20 -20
- package/src/options/IResponseBodyQuerifier.ts +25 -25
- package/src/options/IResponseBodyStringifier.ts +30 -30
- package/src/transform.ts +101 -101
- package/src/typings/Creator.ts +3 -3
- package/src/typings/get-function-location.d.ts +7 -7
- package/src/utils/ArrayUtil.ts +7 -7
- package/src/utils/ExceptionManager.ts +115 -115
- package/src/utils/Singleton.ts +16 -16
- package/src/utils/SourceFinder.ts +54 -54
- package/src/utils/VersioningStrategy.ts +27 -27
- package/native/transform/cleanup_test.go +0 -76
- package/native/transform/commonjs_import_alias_test.go +0 -49
- package/native/transform/core_dispatch_test.go +0 -127
- package/native/transform/path_rewrite_test.go +0 -243
- package/native/transform/rewrite_test.go +0 -118
- package/native/transform/rewrite_unique_base_test.go +0 -48
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
package transform
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
5
|
+
shimprinter "github.com/microsoft/typescript-go/shim/printer"
|
|
6
|
+
"github.com/samchon/nestia/packages/core/native/plugin"
|
|
7
|
+
"github.com/samchon/ttsc/packages/ttsc/driver"
|
|
8
|
+
nativecontext "github.com/samchon/typia/packages/typia/native/core/context"
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
// nestiaCoreNodeTransform builds the @nestia/core AST-integration transformer for
|
|
12
|
+
// one emit run. It mirrors typia's transform.Transform / FileTransformer: per
|
|
13
|
+
// source file it allocates a shared ec-mode ImportProgrammer, rebuilds every
|
|
14
|
+
// nestia-core decorator call with its generated validator argument nodes (whose
|
|
15
|
+
// runtime references resolve to namespace imports tsgo's module-transform
|
|
16
|
+
// aliases), injects those imports, and normalizes the synthetic operator tokens
|
|
17
|
+
// typia's programmers leave nil. A diagnostic is appended for any site whose
|
|
18
|
+
// generation raises a (recovered) transform error, matching the legacy text
|
|
19
|
+
// path's swallow-and-report behavior.
|
|
20
|
+
//
|
|
21
|
+
// addDiagnostic receives one entry per failed site; the build command turns a
|
|
22
|
+
// non-empty diagnostic slice into a non-zero exit.
|
|
23
|
+
func nestiaCoreNodeTransform(
|
|
24
|
+
prog *driver.Program,
|
|
25
|
+
plan plugin.Plan,
|
|
26
|
+
addDiagnostic func(Diagnostic),
|
|
27
|
+
) driver.PluginTransform {
|
|
28
|
+
if plan.Core == false {
|
|
29
|
+
return func(_ *shimprinter.EmitContext, sf *shimast.SourceFile) *shimast.SourceFile {
|
|
30
|
+
return sf
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
options := readNestiaCoreOptions(plan)
|
|
34
|
+
strictReported := false
|
|
35
|
+
return func(ec *shimprinter.EmitContext, sf *shimast.SourceFile) *shimast.SourceFile {
|
|
36
|
+
if sf == nil || sf.IsDeclarationFile {
|
|
37
|
+
return sf
|
|
38
|
+
}
|
|
39
|
+
if nestiaCoreStrictMode(prog) == false && strictReported == false {
|
|
40
|
+
strictReported = true
|
|
41
|
+
addDiagnostic(nestiaCoreGlobalDiagnostic("@nestia/core", "strict mode is required."))
|
|
42
|
+
}
|
|
43
|
+
importer := nativecontext.NewImportProgrammer(nativecontext.ImportProgrammer_IOptions{
|
|
44
|
+
InternalPrefix: "typia_transform_",
|
|
45
|
+
Runtime: "typia",
|
|
46
|
+
})
|
|
47
|
+
importer.SetEmitContext(ec)
|
|
48
|
+
state := newNestiaCoreTransformState(prog, options)
|
|
49
|
+
state.importer = importer
|
|
50
|
+
state.ec = ec
|
|
51
|
+
|
|
52
|
+
replacements := map[*shimast.Node]*shimast.CallExpression{}
|
|
53
|
+
context := newNestiaCoreFileContext(sf)
|
|
54
|
+
sf.ForEachChild(func(node *shimast.Node) bool {
|
|
55
|
+
nestiaCoreCollectNodeReplacements(state, context, node, replacements, addDiagnostic)
|
|
56
|
+
return false
|
|
57
|
+
})
|
|
58
|
+
if len(replacements) == 0 {
|
|
59
|
+
// Nothing rewritten: no imports were injected, so leave the file as-is
|
|
60
|
+
// (the shared typia transform pass handles any typia call sites).
|
|
61
|
+
return sf
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Traverse with the emit EmitContext, not a standalone factory: every
|
|
65
|
+
// ancestor node the visitor recreates to hold a rebuilt decorator call
|
|
66
|
+
// gets an `original` link back to its parse-tree node, so tsgo's emit
|
|
67
|
+
// resolver can recover the binder symbol when it marks linked references.
|
|
68
|
+
// A plain factory drops that link, so tsgo's MarkLinkedReferences pass
|
|
69
|
+
// nil-panics (and exported namespaces silently vanish). Mirrors typia's
|
|
70
|
+
// FileTransformer emit-context traversal.
|
|
71
|
+
var visitor *shimast.NodeVisitor
|
|
72
|
+
visitor = ec.NewNodeVisitor(func(node *shimast.Node) *shimast.Node {
|
|
73
|
+
if node == nil {
|
|
74
|
+
return nil
|
|
75
|
+
}
|
|
76
|
+
if node.Kind == shimast.KindCallExpression {
|
|
77
|
+
if updated, ok := replacements[node]; ok {
|
|
78
|
+
// Link the rebuilt decorator call back to its parse-tree node and
|
|
79
|
+
// keep visiting it through the emit EmitContext (like typia's
|
|
80
|
+
// FileTransformer returns visitor.VisitEachChild(next)). Visiting
|
|
81
|
+
// the substituted subtree is what wires the injected validator
|
|
82
|
+
// nodes' parents and original links, so tsgo's emit resolver can
|
|
83
|
+
// recover their binder symbols when it marks linked references —
|
|
84
|
+
// returning the node raw leaves that subtree untracked and the
|
|
85
|
+
// resolver nil-panics.
|
|
86
|
+
ec.SetOriginal(updated.AsNode(), node)
|
|
87
|
+
return visitor.VisitEachChild(updated.AsNode())
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return visitor.VisitEachChild(node)
|
|
91
|
+
})
|
|
92
|
+
visited := visitor.VisitNode(sf.AsNode())
|
|
93
|
+
if visited == nil {
|
|
94
|
+
return sf
|
|
95
|
+
}
|
|
96
|
+
result := visited.AsSourceFile()
|
|
97
|
+
result = nestiaCoreInjectImports(result, importer.ToStatements(), ec)
|
|
98
|
+
// The node path prints through tsgo's printer, which dereferences the
|
|
99
|
+
// conditional ?/: operator tokens typia's programmers leave nil; the
|
|
100
|
+
// legacy text path filled them via normalizeNestiaSyntheticTokens before
|
|
101
|
+
// printing, so do the same here.
|
|
102
|
+
normalizeNestiaSyntheticTokens(result.AsNode())
|
|
103
|
+
return result
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// nestiaCoreCollectNodeReplacements walks a node looking for nestia-core
|
|
108
|
+
// parameter / method decorator calls. For each, it generates the appended
|
|
109
|
+
// validator argument nodes via the shared ec-importer and records a rebuilt
|
|
110
|
+
// CallExpression keyed by the original decorator call node, for the visitor to
|
|
111
|
+
// substitute.
|
|
112
|
+
func nestiaCoreCollectNodeReplacements(
|
|
113
|
+
state *nestiaCoreTransformState,
|
|
114
|
+
context nestiaCoreFileContext,
|
|
115
|
+
node *shimast.Node,
|
|
116
|
+
replacements map[*shimast.Node]*shimast.CallExpression,
|
|
117
|
+
addDiagnostic func(Diagnostic),
|
|
118
|
+
) {
|
|
119
|
+
if node == nil {
|
|
120
|
+
return
|
|
121
|
+
}
|
|
122
|
+
switch node.Kind {
|
|
123
|
+
case shimast.KindParameter:
|
|
124
|
+
nestiaCoreCollectParameterReplacements(state, context, node, replacements, addDiagnostic)
|
|
125
|
+
case shimast.KindMethodDeclaration:
|
|
126
|
+
nestiaCoreCollectMethodReplacements(state, context, node, replacements, addDiagnostic)
|
|
127
|
+
}
|
|
128
|
+
node.ForEachChild(func(child *shimast.Node) bool {
|
|
129
|
+
nestiaCoreCollectNodeReplacements(state, context, child, replacements, addDiagnostic)
|
|
130
|
+
return false
|
|
131
|
+
})
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
func nestiaCoreCollectParameterReplacements(
|
|
135
|
+
state *nestiaCoreTransformState,
|
|
136
|
+
context nestiaCoreFileContext,
|
|
137
|
+
node *shimast.Node,
|
|
138
|
+
replacements map[*shimast.Node]*shimast.CallExpression,
|
|
139
|
+
addDiagnostic func(Diagnostic),
|
|
140
|
+
) {
|
|
141
|
+
decorators := node.Decorators()
|
|
142
|
+
if len(decorators) == 0 {
|
|
143
|
+
return
|
|
144
|
+
}
|
|
145
|
+
type candidate struct {
|
|
146
|
+
call *shimast.CallExpression
|
|
147
|
+
segments []string
|
|
148
|
+
kind string
|
|
149
|
+
}
|
|
150
|
+
candidates := []candidate{}
|
|
151
|
+
for _, decorator := range decorators {
|
|
152
|
+
call, segments, ok := nestiaCoreRawDecoratorCall(decorator)
|
|
153
|
+
if !ok {
|
|
154
|
+
continue
|
|
155
|
+
}
|
|
156
|
+
canonical := nestiaCoreCanonicalSegments(context, segments)
|
|
157
|
+
kind := nestiaCoreParameterKind(canonical)
|
|
158
|
+
if kind == "" || nestiaCoreDecoratorReference(state.prog, context, decorator, segments, canonical) == false {
|
|
159
|
+
continue
|
|
160
|
+
}
|
|
161
|
+
candidates = append(candidates, candidate{call: call, segments: segments, kind: kind})
|
|
162
|
+
}
|
|
163
|
+
if len(candidates) == 0 {
|
|
164
|
+
return
|
|
165
|
+
}
|
|
166
|
+
typ := state.prog.Checker.GetTypeAtLocation(nestiaCoreOriginalNode(state.ec, node))
|
|
167
|
+
for _, candidate := range candidates {
|
|
168
|
+
// Hand typia the real callee node (e.g. `core.TypedBody`) as the modulo,
|
|
169
|
+
// mirroring typia's own transformer (props.Expression.Expression). typia's
|
|
170
|
+
// programmers read its source-span text via GetTextOfNode for the error
|
|
171
|
+
// method label; a synthesized identifier has no source span and nil-panics,
|
|
172
|
+
// so map back to the parse-tree callee when typia rebuilt this decorator.
|
|
173
|
+
modulo := nestiaCoreOriginalNode(state.ec, candidate.call.Expression)
|
|
174
|
+
nodes, ok, err := nestiaCoreParameterArgumentNodes(state.prog, state.importer, state.ec, state.options, candidate.call, modulo, candidate.kind, typ)
|
|
175
|
+
if err != nil {
|
|
176
|
+
addDiagnostic(nestiaCoreDiagnostic(nestiaCoreSiteFor(context.file, candidate.call, candidate.kind, candidate.segments), err.Error()))
|
|
177
|
+
continue
|
|
178
|
+
}
|
|
179
|
+
if !ok {
|
|
180
|
+
continue
|
|
181
|
+
}
|
|
182
|
+
replacements[candidate.call.AsNode()] = nestiaCoreAppendArgumentNodes(candidate.call, nodes, state.ec)
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
func nestiaCoreCollectMethodReplacements(
|
|
187
|
+
state *nestiaCoreTransformState,
|
|
188
|
+
context nestiaCoreFileContext,
|
|
189
|
+
node *shimast.Node,
|
|
190
|
+
replacements map[*shimast.Node]*shimast.CallExpression,
|
|
191
|
+
addDiagnostic func(Diagnostic),
|
|
192
|
+
) {
|
|
193
|
+
decorators := node.Decorators()
|
|
194
|
+
if len(decorators) == 0 {
|
|
195
|
+
return
|
|
196
|
+
}
|
|
197
|
+
type candidate struct {
|
|
198
|
+
call *shimast.CallExpression
|
|
199
|
+
segments []string
|
|
200
|
+
kind string
|
|
201
|
+
}
|
|
202
|
+
candidates := []candidate{}
|
|
203
|
+
for _, decorator := range decorators {
|
|
204
|
+
call, segments, ok := nestiaCoreRawDecoratorCall(decorator)
|
|
205
|
+
if !ok {
|
|
206
|
+
continue
|
|
207
|
+
}
|
|
208
|
+
canonical := nestiaCoreCanonicalSegments(context, segments)
|
|
209
|
+
if nestiaCoreDecoratorReference(state.prog, context, decorator, segments, canonical) == false {
|
|
210
|
+
continue
|
|
211
|
+
}
|
|
212
|
+
// @WebSocketRoute carries no injected validator (it is not a method kind),
|
|
213
|
+
// but its acceptor/driver parameter shapes are validated here, mirroring the
|
|
214
|
+
// legacy visitNestiaCoreNode path. Validate against the parse-tree method so
|
|
215
|
+
// parameter type text resolves even when typia rebuilt this method.
|
|
216
|
+
if len(canonical) != 0 && canonical[len(canonical)-1] == "WebSocketRoute" {
|
|
217
|
+
for _, diag := range validateNestiaCoreWebSocketRoute(state.prog, context, nestiaCoreOriginalNode(state.ec, node), call, canonical) {
|
|
218
|
+
addDiagnostic(diag)
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
kind := nestiaCoreMethodKind(canonical)
|
|
222
|
+
if kind == "" {
|
|
223
|
+
continue
|
|
224
|
+
}
|
|
225
|
+
if kind == "McpRoute" {
|
|
226
|
+
if nestiaCoreMcpRouteAlreadyTransformed(call) {
|
|
227
|
+
continue
|
|
228
|
+
}
|
|
229
|
+
} else if nestiaCoreShouldSkipMethodDecorator(state.prog, call) {
|
|
230
|
+
continue
|
|
231
|
+
}
|
|
232
|
+
candidates = append(candidates, candidate{call: call, segments: segments, kind: kind})
|
|
233
|
+
}
|
|
234
|
+
if len(candidates) == 0 {
|
|
235
|
+
return
|
|
236
|
+
}
|
|
237
|
+
typ := NestiaCoreMethodReturnType(state.prog, nestiaCoreOriginalNode(state.ec, node))
|
|
238
|
+
if typ == nil {
|
|
239
|
+
return
|
|
240
|
+
}
|
|
241
|
+
for _, candidate := range candidates {
|
|
242
|
+
if candidate.kind == "McpRoute" {
|
|
243
|
+
generated, err := nestiaCoreMcpRouteArgumentNode(state.prog, state.importer, state.ec, state.options, context.file, nestiaCoreOriginalNode(state.ec, node), candidate.call, typ)
|
|
244
|
+
if err != nil {
|
|
245
|
+
addDiagnostic(nestiaCoreDiagnostic(nestiaCoreSiteFor(context.file, candidate.call, candidate.kind, candidate.segments), err.Error()))
|
|
246
|
+
continue
|
|
247
|
+
}
|
|
248
|
+
replacements[candidate.call.AsNode()] = nestiaCoreReplaceArgumentNodes(candidate.call, []*shimast.Node{generated}, state.ec)
|
|
249
|
+
continue
|
|
250
|
+
}
|
|
251
|
+
// Real callee node as modulo (see nestiaCoreCollectParameterReplacements).
|
|
252
|
+
modulo := nestiaCoreOriginalNode(state.ec, candidate.call.Expression)
|
|
253
|
+
generated, err := nestiaCoreMethodArgumentNode(state.prog, state.importer, state.ec, state.options, modulo, candidate.kind, typ)
|
|
254
|
+
if err != nil {
|
|
255
|
+
addDiagnostic(nestiaCoreDiagnostic(nestiaCoreSiteFor(context.file, candidate.call, candidate.kind, candidate.segments), err.Error()))
|
|
256
|
+
continue
|
|
257
|
+
}
|
|
258
|
+
replacements[candidate.call.AsNode()] = nestiaCoreAppendArgumentNodes(candidate.call, []*shimast.Node{generated}, state.ec)
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// nestiaCoreOriginalNode returns the parse-tree node a (possibly synthetic) node
|
|
263
|
+
// was rebuilt from, so checker queries that need binder symbols or types resolve
|
|
264
|
+
// against the original. core runs after typia in the shared emit pass: when typia
|
|
265
|
+
// lowers a `typia.random<T>()` call that sits in a decorator argument or method
|
|
266
|
+
// body, it rebuilds the enclosing method (and its parameters) into synthetic
|
|
267
|
+
// nodes that carry no binder symbol. GetSignatureFromDeclaration /
|
|
268
|
+
// GetTypeAtLocation then nil-panic on them, and GetTextOfNode on a synthetic
|
|
269
|
+
// callee has no source span. ec.MostOriginal walks the original-link chain back
|
|
270
|
+
// to the parse node; it is a no-op for nodes core sees before typia touched them.
|
|
271
|
+
func nestiaCoreOriginalNode(ec *shimprinter.EmitContext, node *shimast.Node) *shimast.Node {
|
|
272
|
+
if ec == nil || node == nil {
|
|
273
|
+
return node
|
|
274
|
+
}
|
|
275
|
+
if original := ec.MostOriginal(node); original != nil {
|
|
276
|
+
return original
|
|
277
|
+
}
|
|
278
|
+
return node
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// nestiaCoreReplaceArgumentNodes rebuilds a decorator call with the generated
|
|
282
|
+
// nodes replacing every original argument.
|
|
283
|
+
func nestiaCoreReplaceArgumentNodes(call *shimast.CallExpression, replacements []*shimast.Node, ec *shimprinter.EmitContext) *shimast.CallExpression {
|
|
284
|
+
f := nativecontext.EmitFactoryOf(nestiaCoreFactory, ec)
|
|
285
|
+
updated := f.NewCallExpression(
|
|
286
|
+
call.Expression,
|
|
287
|
+
call.QuestionDotToken,
|
|
288
|
+
call.TypeArguments,
|
|
289
|
+
f.NewNodeList(replacements),
|
|
290
|
+
call.AsNode().Flags,
|
|
291
|
+
)
|
|
292
|
+
return updated.AsCallExpression()
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// nestiaCoreAppendArgumentNodes rebuilds a decorator call with the generated
|
|
296
|
+
// validator nodes appended after its original arguments.
|
|
297
|
+
func nestiaCoreAppendArgumentNodes(call *shimast.CallExpression, appended []*shimast.Node, ec *shimprinter.EmitContext) *shimast.CallExpression {
|
|
298
|
+
f := nativecontext.EmitFactoryOf(nestiaCoreFactory, ec)
|
|
299
|
+
existing := []*shimast.Node{}
|
|
300
|
+
if call.Arguments != nil {
|
|
301
|
+
existing = append(existing, call.Arguments.Nodes...)
|
|
302
|
+
}
|
|
303
|
+
args := make([]*shimast.Node, 0, len(existing)+len(appended))
|
|
304
|
+
args = append(args, existing...)
|
|
305
|
+
args = append(args, appended...)
|
|
306
|
+
updated := f.NewCallExpression(
|
|
307
|
+
call.Expression,
|
|
308
|
+
call.QuestionDotToken,
|
|
309
|
+
call.TypeArguments,
|
|
310
|
+
f.NewNodeList(args),
|
|
311
|
+
call.AsNode().Flags,
|
|
312
|
+
)
|
|
313
|
+
return updated.AsCallExpression()
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// nestiaCoreInjectImports prepends the importer's namespace-import statements
|
|
317
|
+
// after any leading "use ..." prologue, mirroring typia's
|
|
318
|
+
// fileTransformer_inject_imports.
|
|
319
|
+
func nestiaCoreInjectImports(file *shimast.SourceFile, imports []*shimast.Node, ec *shimprinter.EmitContext) *shimast.SourceFile {
|
|
320
|
+
if file == nil || len(imports) == 0 {
|
|
321
|
+
return file
|
|
322
|
+
}
|
|
323
|
+
f := nativecontext.EmitFactoryOf(nestiaCoreFactory, ec)
|
|
324
|
+
index := 0
|
|
325
|
+
for ; index < len(file.Statements.Nodes); index++ {
|
|
326
|
+
stmt := file.Statements.Nodes[index]
|
|
327
|
+
if stmt == nil || stmt.Kind != shimast.KindExpressionStatement {
|
|
328
|
+
break
|
|
329
|
+
}
|
|
330
|
+
expression := stmt.AsExpressionStatement().Expression
|
|
331
|
+
if expression == nil || expression.Kind != shimast.KindStringLiteral {
|
|
332
|
+
break
|
|
333
|
+
}
|
|
334
|
+
if text := expression.AsStringLiteral().Text; len(text) < 4 || text[:4] != "use " {
|
|
335
|
+
break
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
nodes := make([]*shimast.Node, 0, len(file.Statements.Nodes)+len(imports))
|
|
339
|
+
nodes = append(nodes, file.Statements.Nodes[:index]...)
|
|
340
|
+
nodes = append(nodes, imports...)
|
|
341
|
+
nodes = append(nodes, file.Statements.Nodes[index:]...)
|
|
342
|
+
return f.UpdateSourceFile(
|
|
343
|
+
file,
|
|
344
|
+
f.NewNodeList(nodes),
|
|
345
|
+
file.EndOfFileToken,
|
|
346
|
+
).AsSourceFile()
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
func nestiaCoreSiteFor(file *shimast.SourceFile, call *shimast.CallExpression, kind string, segments []string) nestiaCoreSite {
|
|
350
|
+
return nestiaCoreSite{
|
|
351
|
+
File: file,
|
|
352
|
+
FilePath: file.FileName(),
|
|
353
|
+
Call: call,
|
|
354
|
+
Kind: kind,
|
|
355
|
+
Segments: segments,
|
|
356
|
+
}
|
|
357
|
+
}
|