@nestia/core 12.0.0 → 12.1.0
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/lib/adaptors/McpAdaptor.js +21 -18
- package/lib/adaptors/McpAdaptor.js.map +1 -1
- package/lib/decorators/EncryptedBody.js +2 -7
- package/lib/decorators/EncryptedBody.js.map +1 -1
- package/lib/decorators/EncryptedRoute.js +1 -1
- package/lib/decorators/EncryptedRoute.js.map +1 -1
- package/lib/decorators/McpRoute.js +1 -1
- package/lib/decorators/McpRoute.js.map +1 -1
- package/lib/decorators/NoTransformConfigurationError.js +2 -2
- package/lib/decorators/PlainBody.js +2 -7
- package/lib/decorators/PlainBody.js.map +1 -1
- package/lib/decorators/SwaggerCustomizer.js +2 -2
- package/lib/decorators/SwaggerCustomizer.js.map +1 -1
- package/lib/decorators/SwaggerExample.d.ts +37 -40
- package/lib/decorators/SwaggerExample.js +24 -26
- package/lib/decorators/SwaggerExample.js.map +1 -1
- package/lib/decorators/TypedBody.js +3 -7
- package/lib/decorators/TypedBody.js.map +1 -1
- package/lib/decorators/TypedException.d.ts +1 -1
- package/lib/decorators/TypedFormData.js +2 -7
- package/lib/decorators/TypedFormData.js.map +1 -1
- package/lib/decorators/TypedQuery.js +2 -9
- package/lib/decorators/TypedQuery.js.map +1 -1
- package/lib/decorators/WebSocketRoute.js +1 -1
- package/lib/decorators/WebSocketRoute.js.map +1 -1
- package/lib/decorators/internal/get_path_and_querify.js +1 -1
- package/lib/decorators/internal/get_path_and_querify.js.map +1 -1
- package/lib/decorators/internal/is_media_type.d.ts +1 -0
- package/lib/decorators/internal/is_media_type.js +11 -0
- package/lib/decorators/internal/is_media_type.js.map +1 -0
- package/lib/decorators/internal/validate_request_query.js.map +1 -1
- package/native/plugin/plan.go +17 -0
- package/native/transform/build.go +39 -80
- package/native/transform/contributor.go +4 -64
- package/native/transform/core_transform.go +42 -705
- package/native/transform/node_transform.go +3 -5
- package/native/transform/printer.go +0 -217
- package/native/transform/transform.go +2 -91
- package/native/transform/typia_fast.go +0 -320
- package/package.json +8 -8
- package/src/adaptors/McpAdaptor.ts +29 -21
- package/src/decorators/EncryptedBody.ts +2 -9
- package/src/decorators/EncryptedRoute.ts +1 -1
- package/src/decorators/McpRoute.ts +6 -5
- package/src/decorators/NoTransformConfigurationError.ts +2 -2
- package/src/decorators/PlainBody.ts +2 -9
- package/src/decorators/SwaggerCustomizer.ts +8 -2
- package/src/decorators/SwaggerExample.ts +43 -45
- package/src/decorators/TypedBody.ts +5 -9
- package/src/decorators/TypedException.ts +1 -1
- package/src/decorators/TypedFormData.ts +7 -9
- package/src/decorators/TypedQuery.ts +7 -12
- package/src/decorators/WebSocketRoute.ts +1 -1
- package/src/decorators/internal/get_path_and_querify.ts +1 -1
- package/src/decorators/internal/is_media_type.ts +10 -0
- package/src/decorators/internal/validate_request_query.ts +2 -1
- package/native/transform/cleanup.go +0 -408
- package/native/transform/exports.go +0 -13
- package/native/transform/rewrite.go +0 -668
- package/native/transform/typia_replacement.go +0 -24
|
@@ -6,11 +6,8 @@ import (
|
|
|
6
6
|
"path/filepath"
|
|
7
7
|
"regexp"
|
|
8
8
|
"runtime/debug"
|
|
9
|
-
"sort"
|
|
10
|
-
"strconv"
|
|
11
9
|
"strings"
|
|
12
10
|
"sync"
|
|
13
|
-
"unicode"
|
|
14
11
|
|
|
15
12
|
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
16
13
|
shimchecker "github.com/microsoft/typescript-go/shim/checker"
|
|
@@ -53,15 +50,13 @@ type nestiaCoreTransformState struct {
|
|
|
53
50
|
prog *driver.Program
|
|
54
51
|
options nestiaCoreOptions
|
|
55
52
|
// importer is the file-scoped ImportProgrammer shared by every validator
|
|
56
|
-
// generated for the current file
|
|
57
|
-
// the
|
|
58
|
-
//
|
|
59
|
-
//
|
|
60
|
-
// that cannot be reused verbatim across files.
|
|
53
|
+
// generated for the current file. When set, generation result caching is
|
|
54
|
+
// disabled: the cache keys on text, but ec-mode nodes embed per-file
|
|
55
|
+
// NewGeneratedNameForNode imports that cannot be reused verbatim across
|
|
56
|
+
// files. The nil case is defensive — every current caller supplies one.
|
|
61
57
|
importer *nativecontext.ImportProgrammer
|
|
62
|
-
// ec is the emit EmitContext
|
|
63
|
-
//
|
|
64
|
-
// factories build emit-tracked nodes.
|
|
58
|
+
// ec is the emit EmitContext. Threaded into ITypiaContext.Emit so typia's
|
|
59
|
+
// per-programmer factories build emit-tracked nodes.
|
|
65
60
|
ec *shimprinter.EmitContext
|
|
66
61
|
cache map[nestiaCoreCacheKey][]string
|
|
67
62
|
cacheHits int
|
|
@@ -130,388 +125,9 @@ func readNestiaCoreOptions(plan plugin.Plan) nestiaCoreOptions {
|
|
|
130
125
|
return options
|
|
131
126
|
}
|
|
132
127
|
|
|
133
|
-
func collectNestiaCoreSourceRewriteMap(
|
|
134
|
-
prog *driver.Program,
|
|
135
|
-
plan plugin.Plan,
|
|
136
|
-
onlyFile string,
|
|
137
|
-
) (map[string][]SourceRewrite, []Diagnostic) {
|
|
138
|
-
if plan.Core == false {
|
|
139
|
-
return map[string][]SourceRewrite{}, nil
|
|
140
|
-
}
|
|
141
|
-
options := readNestiaCoreOptions(plan)
|
|
142
|
-
sites, diagnostics := collectNestiaCoreSites(newNestiaCoreTransformState(prog, options))
|
|
143
|
-
rewrites := map[string][]SourceRewrite{}
|
|
144
|
-
for _, site := range sites {
|
|
145
|
-
if onlyFile != "" && filepath.ToSlash(site.FilePath) != filepath.ToSlash(onlyFile) {
|
|
146
|
-
continue
|
|
147
|
-
}
|
|
148
|
-
source, ok := SourceFileText(site.File)
|
|
149
|
-
if !ok {
|
|
150
|
-
diagnostics = append(diagnostics, nestiaCoreDiagnostic(site, "source text is unavailable"))
|
|
151
|
-
continue
|
|
152
|
-
}
|
|
153
|
-
open, close, ok := callArgumentBounds(source, site.Call)
|
|
154
|
-
if !ok {
|
|
155
|
-
diagnostics = append(diagnostics, nestiaCoreDiagnostic(site, "failed to locate decorator arguments"))
|
|
156
|
-
continue
|
|
157
|
-
}
|
|
158
|
-
replacement := strings.Join(site.Arguments, ", ")
|
|
159
|
-
if site.ReplaceArguments == false {
|
|
160
|
-
replacement = appendArgumentsText(source[open+1:close], site.Arguments)
|
|
161
|
-
}
|
|
162
|
-
rewrites[filepath.ToSlash(site.FilePath)] = append(rewrites[filepath.ToSlash(site.FilePath)], SourceRewrite{
|
|
163
|
-
start: open + 1,
|
|
164
|
-
end: close,
|
|
165
|
-
replacement: replacement,
|
|
166
|
-
})
|
|
167
|
-
}
|
|
168
|
-
return rewrites, diagnostics
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
func collectNestiaCoreBuildRewrites(
|
|
172
|
-
prog *driver.Program,
|
|
173
|
-
plan plugin.Plan,
|
|
174
|
-
rewrites *nativeRewriteSet,
|
|
175
|
-
) []Diagnostic {
|
|
176
|
-
if plan.Core == false {
|
|
177
|
-
return nil
|
|
178
|
-
}
|
|
179
|
-
options := readNestiaCoreOptions(plan)
|
|
180
|
-
sites, diagnostics := collectNestiaCoreSites(newNestiaCoreTransformState(prog, options))
|
|
181
|
-
for _, site := range sites {
|
|
182
|
-
expectedArgumentCount := site.ArgCount
|
|
183
|
-
expectedArgumentsText := nestiaCoreStableOriginalArgumentText(site)
|
|
184
|
-
rewrites.Add(nativeRewrite{
|
|
185
|
-
FilePath: site.FilePath,
|
|
186
|
-
RootName: site.Segments[0],
|
|
187
|
-
Namespaces: site.Segments[1:],
|
|
188
|
-
AppendArguments: site.Arguments,
|
|
189
|
-
ReplaceArguments: site.ReplaceArguments,
|
|
190
|
-
TargetExpressionCandidates: nestiaCoreTargetCandidates(prog, site),
|
|
191
|
-
SourceStart: site.Call.AsNode().Pos(),
|
|
192
|
-
ExpectedArgumentCount: &expectedArgumentCount,
|
|
193
|
-
ExpectedArgumentsText: expectedArgumentsText,
|
|
194
|
-
})
|
|
195
|
-
}
|
|
196
|
-
return diagnostics
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
func nestiaCoreOriginalArgumentText(site nestiaCoreSite) string {
|
|
200
|
-
source, ok := SourceFileText(site.File)
|
|
201
|
-
if !ok {
|
|
202
|
-
return ""
|
|
203
|
-
}
|
|
204
|
-
open, close, ok := callArgumentBounds(source, site.Call)
|
|
205
|
-
if !ok {
|
|
206
|
-
return ""
|
|
207
|
-
}
|
|
208
|
-
return strings.TrimSpace(source[open+1 : close])
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
func nestiaCoreStableOriginalArgumentText(site nestiaCoreSite) string {
|
|
212
|
-
text := nestiaCoreOriginalArgumentText(site)
|
|
213
|
-
if strings.Contains(text, "=>") || strings.Contains(text, "function") {
|
|
214
|
-
return ""
|
|
215
|
-
}
|
|
216
|
-
return text
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
func collectNestiaCoreSites(state *nestiaCoreTransformState) ([]nestiaCoreSite, []Diagnostic) {
|
|
220
|
-
sites := []nestiaCoreSite{}
|
|
221
|
-
diagnostics := []Diagnostic{}
|
|
222
|
-
prog := state.prog
|
|
223
|
-
if nestiaCoreStrictMode(prog) == false {
|
|
224
|
-
diagnostics = append(diagnostics, nestiaCoreGlobalDiagnostic("@nestia/core", "strict mode is required."))
|
|
225
|
-
}
|
|
226
|
-
for _, file := range prog.SourceFiles() {
|
|
227
|
-
if file == nil || file.IsDeclarationFile {
|
|
228
|
-
continue
|
|
229
|
-
}
|
|
230
|
-
context := newNestiaCoreFileContext(file)
|
|
231
|
-
file.ForEachChild(func(node *shimast.Node) bool {
|
|
232
|
-
visitNestiaCoreNode(state, context, node, &sites, &diagnostics)
|
|
233
|
-
return false
|
|
234
|
-
})
|
|
235
|
-
}
|
|
236
|
-
if os.Getenv("TTSC_NESTIA_PROFILE") != "" {
|
|
237
|
-
fmt.Fprintf(stderr, "ttsc-nestia profile: core-cache hits=%d misses=%d\n", state.cacheHits, state.cacheMisses)
|
|
238
|
-
}
|
|
239
|
-
return sites, diagnostics
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
func visitNestiaCoreNode(
|
|
243
|
-
state *nestiaCoreTransformState,
|
|
244
|
-
context nestiaCoreFileContext,
|
|
245
|
-
node *shimast.Node,
|
|
246
|
-
sites *[]nestiaCoreSite,
|
|
247
|
-
diagnostics *[]Diagnostic,
|
|
248
|
-
) {
|
|
249
|
-
if node == nil {
|
|
250
|
-
return
|
|
251
|
-
}
|
|
252
|
-
switch node.Kind {
|
|
253
|
-
case shimast.KindParameter:
|
|
254
|
-
decorators := node.Decorators()
|
|
255
|
-
if len(decorators) == 0 {
|
|
256
|
-
break
|
|
257
|
-
}
|
|
258
|
-
type candidate struct {
|
|
259
|
-
decorator *shimast.Node
|
|
260
|
-
call *shimast.CallExpression
|
|
261
|
-
segments []string
|
|
262
|
-
kind string
|
|
263
|
-
}
|
|
264
|
-
candidates := []candidate{}
|
|
265
|
-
for _, decorator := range decorators {
|
|
266
|
-
call, segments, ok := nestiaCoreRawDecoratorCall(decorator)
|
|
267
|
-
if !ok {
|
|
268
|
-
continue
|
|
269
|
-
}
|
|
270
|
-
canonical := nestiaCoreCanonicalSegments(context, segments)
|
|
271
|
-
kind := nestiaCoreParameterKind(canonical)
|
|
272
|
-
if kind == "" || nestiaCoreDecoratorReference(state.prog, context, decorator, segments, canonical) == false {
|
|
273
|
-
continue
|
|
274
|
-
}
|
|
275
|
-
candidates = append(candidates, candidate{
|
|
276
|
-
decorator: decorator,
|
|
277
|
-
call: call,
|
|
278
|
-
segments: segments,
|
|
279
|
-
kind: kind,
|
|
280
|
-
})
|
|
281
|
-
}
|
|
282
|
-
if len(candidates) == 0 {
|
|
283
|
-
break
|
|
284
|
-
}
|
|
285
|
-
typ := state.prog.Checker.GetTypeAtLocation(node)
|
|
286
|
-
for _, candidate := range candidates {
|
|
287
|
-
site, ok, err := transformNestiaCoreParameterDecorator(
|
|
288
|
-
state,
|
|
289
|
-
context.file,
|
|
290
|
-
candidate.call,
|
|
291
|
-
candidate.segments,
|
|
292
|
-
candidate.kind,
|
|
293
|
-
typ,
|
|
294
|
-
)
|
|
295
|
-
if err != nil {
|
|
296
|
-
*diagnostics = append(*diagnostics, nestiaCoreDiagnostic(site, err.Error()))
|
|
297
|
-
} else if ok {
|
|
298
|
-
*sites = append(*sites, site)
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
case shimast.KindMethodDeclaration:
|
|
302
|
-
decorators := node.Decorators()
|
|
303
|
-
if len(decorators) == 0 {
|
|
304
|
-
break
|
|
305
|
-
}
|
|
306
|
-
type candidate struct {
|
|
307
|
-
call *shimast.CallExpression
|
|
308
|
-
segments []string
|
|
309
|
-
kind string
|
|
310
|
-
}
|
|
311
|
-
candidates := []candidate{}
|
|
312
|
-
for _, decorator := range decorators {
|
|
313
|
-
call, segments, ok := nestiaCoreRawDecoratorCall(decorator)
|
|
314
|
-
if !ok {
|
|
315
|
-
continue
|
|
316
|
-
}
|
|
317
|
-
canonical := nestiaCoreCanonicalSegments(context, segments)
|
|
318
|
-
if nestiaCoreDecoratorReference(state.prog, context, decorator, segments, canonical) == false {
|
|
319
|
-
continue
|
|
320
|
-
}
|
|
321
|
-
if len(canonical) != 0 && canonical[len(canonical)-1] == "WebSocketRoute" {
|
|
322
|
-
*diagnostics = append(*diagnostics, validateNestiaCoreWebSocketRoute(state.prog, context, node, call, canonical)...)
|
|
323
|
-
}
|
|
324
|
-
kind := nestiaCoreMethodKind(canonical)
|
|
325
|
-
if kind == "" {
|
|
326
|
-
continue
|
|
327
|
-
}
|
|
328
|
-
if kind == "McpRoute" {
|
|
329
|
-
if nestiaCoreMcpRouteAlreadyTransformed(call) {
|
|
330
|
-
continue
|
|
331
|
-
}
|
|
332
|
-
} else if nestiaCoreShouldSkipMethodDecorator(state.prog, call) {
|
|
333
|
-
continue
|
|
334
|
-
}
|
|
335
|
-
candidates = append(candidates, candidate{
|
|
336
|
-
call: call,
|
|
337
|
-
segments: segments,
|
|
338
|
-
kind: kind,
|
|
339
|
-
})
|
|
340
|
-
}
|
|
341
|
-
if len(candidates) == 0 {
|
|
342
|
-
break
|
|
343
|
-
}
|
|
344
|
-
typ := NestiaCoreMethodReturnType(state.prog, node)
|
|
345
|
-
if typ != nil {
|
|
346
|
-
for _, candidate := range candidates {
|
|
347
|
-
site, ok, err := transformNestiaCoreMethodDecorator(
|
|
348
|
-
state,
|
|
349
|
-
context.file,
|
|
350
|
-
node,
|
|
351
|
-
candidate.call,
|
|
352
|
-
candidate.segments,
|
|
353
|
-
candidate.kind,
|
|
354
|
-
typ,
|
|
355
|
-
)
|
|
356
|
-
if err != nil {
|
|
357
|
-
*diagnostics = append(*diagnostics, nestiaCoreDiagnostic(site, err.Error()))
|
|
358
|
-
} else if ok {
|
|
359
|
-
*sites = append(*sites, site)
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
node.ForEachChild(func(child *shimast.Node) bool {
|
|
365
|
-
visitNestiaCoreNode(state, context, child, sites, diagnostics)
|
|
366
|
-
return false
|
|
367
|
-
})
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
func transformNestiaCoreParameterDecorator(
|
|
371
|
-
state *nestiaCoreTransformState,
|
|
372
|
-
file *shimast.SourceFile,
|
|
373
|
-
call *shimast.CallExpression,
|
|
374
|
-
segments []string,
|
|
375
|
-
kind string,
|
|
376
|
-
typ *shimchecker.Type,
|
|
377
|
-
) (nestiaCoreSite, bool, error) {
|
|
378
|
-
modulo := nestiaCoreModuloNode(call.Expression)
|
|
379
|
-
arguments, ok, err := state.parameterArguments(call, segments, modulo, kind, typ)
|
|
380
|
-
if err != nil || !ok {
|
|
381
|
-
return nestiaCoreSite{
|
|
382
|
-
File: file,
|
|
383
|
-
FilePath: file.FileName(),
|
|
384
|
-
Call: call,
|
|
385
|
-
Modulo: modulo,
|
|
386
|
-
Kind: kind,
|
|
387
|
-
Type: typ,
|
|
388
|
-
Segments: segments,
|
|
389
|
-
}, ok, err
|
|
390
|
-
}
|
|
391
|
-
return nestiaCoreSite{
|
|
392
|
-
File: file,
|
|
393
|
-
FilePath: file.FileName(),
|
|
394
|
-
Call: call,
|
|
395
|
-
Modulo: modulo,
|
|
396
|
-
Kind: kind,
|
|
397
|
-
Type: typ,
|
|
398
|
-
ArgCount: nestiaCoreArgumentCount(call),
|
|
399
|
-
Segments: segments,
|
|
400
|
-
Arguments: arguments,
|
|
401
|
-
}, true, nil
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
func transformNestiaCoreMethodDecorator(
|
|
405
|
-
state *nestiaCoreTransformState,
|
|
406
|
-
file *shimast.SourceFile,
|
|
407
|
-
method *shimast.Node,
|
|
408
|
-
call *shimast.CallExpression,
|
|
409
|
-
segments []string,
|
|
410
|
-
kind string,
|
|
411
|
-
typ *shimchecker.Type,
|
|
412
|
-
) (nestiaCoreSite, bool, error) {
|
|
413
|
-
modulo := nestiaCoreModuloNode(call.Expression)
|
|
414
|
-
if kind == "McpRoute" {
|
|
415
|
-
arguments, err := state.mcpRouteArguments(file, method, call, typ)
|
|
416
|
-
if err != nil {
|
|
417
|
-
return nestiaCoreSite{
|
|
418
|
-
File: file,
|
|
419
|
-
FilePath: file.FileName(),
|
|
420
|
-
Call: call,
|
|
421
|
-
Modulo: modulo,
|
|
422
|
-
Kind: kind,
|
|
423
|
-
Type: typ,
|
|
424
|
-
Segments: segments,
|
|
425
|
-
Arguments: arguments,
|
|
426
|
-
}, false, err
|
|
427
|
-
}
|
|
428
|
-
return nestiaCoreSite{
|
|
429
|
-
File: file,
|
|
430
|
-
FilePath: file.FileName(),
|
|
431
|
-
Call: call,
|
|
432
|
-
Modulo: modulo,
|
|
433
|
-
Kind: kind,
|
|
434
|
-
Type: typ,
|
|
435
|
-
ArgCount: nestiaCoreArgumentCount(call),
|
|
436
|
-
Segments: segments,
|
|
437
|
-
Arguments: arguments,
|
|
438
|
-
ReplaceArguments: true,
|
|
439
|
-
}, true, nil
|
|
440
|
-
}
|
|
441
|
-
arguments, err := state.methodArguments(file, segments, modulo, kind, typ, nestiaCoreArgumentCount(call))
|
|
442
|
-
if err != nil {
|
|
443
|
-
return nestiaCoreSite{
|
|
444
|
-
File: file,
|
|
445
|
-
FilePath: file.FileName(),
|
|
446
|
-
Call: call,
|
|
447
|
-
Modulo: modulo,
|
|
448
|
-
Kind: kind,
|
|
449
|
-
Type: typ,
|
|
450
|
-
Segments: segments,
|
|
451
|
-
}, false, err
|
|
452
|
-
}
|
|
453
|
-
return nestiaCoreSite{
|
|
454
|
-
File: file,
|
|
455
|
-
FilePath: file.FileName(),
|
|
456
|
-
Call: call,
|
|
457
|
-
Modulo: modulo,
|
|
458
|
-
Kind: kind,
|
|
459
|
-
Type: typ,
|
|
460
|
-
ArgCount: nestiaCoreArgumentCount(call),
|
|
461
|
-
Segments: segments,
|
|
462
|
-
Arguments: arguments,
|
|
463
|
-
}, true, nil
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
func (state *nestiaCoreTransformState) parameterArguments(
|
|
467
|
-
call *shimast.CallExpression,
|
|
468
|
-
segments []string,
|
|
469
|
-
modulo *shimast.Node,
|
|
470
|
-
kind string,
|
|
471
|
-
typ *shimchecker.Type,
|
|
472
|
-
) ([]string, bool, error) {
|
|
473
|
-
key := state.cacheKey(segments, kind, typ, nestiaCoreArgumentCount(call), kind == "TypedQuery")
|
|
474
|
-
return state.cachedArguments(key, func() ([]string, bool, error) {
|
|
475
|
-
return nestiaCoreParameterArguments(state.prog, state.options, call, modulo, kind, typ)
|
|
476
|
-
})
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
func (state *nestiaCoreTransformState) methodArguments(
|
|
480
|
-
file *shimast.SourceFile,
|
|
481
|
-
segments []string,
|
|
482
|
-
modulo *shimast.Node,
|
|
483
|
-
kind string,
|
|
484
|
-
typ *shimchecker.Type,
|
|
485
|
-
argCount int,
|
|
486
|
-
) ([]string, error) {
|
|
487
|
-
key := state.cacheKey(segments, kind, typ, argCount, kind == "TypedQueryRoute")
|
|
488
|
-
arguments, _, err := state.cachedArguments(key, func() ([]string, bool, error) {
|
|
489
|
-
node, err := nestiaCoreMethodArgumentNode(state.prog, state.importer, state.ec, state.options, modulo, kind, typ)
|
|
490
|
-
if err != nil {
|
|
491
|
-
return nil, false, err
|
|
492
|
-
}
|
|
493
|
-
return []string{emitNestiaCoreExpression(state.prog, file, node, false)}, true, nil
|
|
494
|
-
})
|
|
495
|
-
return arguments, err
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
func (state *nestiaCoreTransformState) mcpRouteArguments(
|
|
499
|
-
file *shimast.SourceFile,
|
|
500
|
-
method *shimast.Node,
|
|
501
|
-
call *shimast.CallExpression,
|
|
502
|
-
typ *shimchecker.Type,
|
|
503
|
-
) ([]string, error) {
|
|
504
|
-
node, err := nestiaCoreMcpRouteArgumentNode(state.prog, nil, nil, state.options, file, method, call, typ)
|
|
505
|
-
if err != nil {
|
|
506
|
-
return nil, err
|
|
507
|
-
}
|
|
508
|
-
return []string{emitNestiaCoreExpression(state.prog, file, node, false)}, nil
|
|
509
|
-
}
|
|
510
|
-
|
|
511
128
|
// nestiaCoreMethodArgumentNode builds the single appended decorator-argument
|
|
512
129
|
// node for a method decorator (TypedRoute / TypedQueryRoute). The importer is
|
|
513
|
-
// the
|
|
514
|
-
// text path.
|
|
130
|
+
// the file-scoped ec-mode ImportProgrammer.
|
|
515
131
|
func nestiaCoreMethodArgumentNode(
|
|
516
132
|
prog *driver.Program,
|
|
517
133
|
importer *nativecontext.ImportProgrammer, ec *shimprinter.EmitContext,
|
|
@@ -529,46 +145,6 @@ func nestiaCoreMethodArgumentNode(
|
|
|
529
145
|
}
|
|
530
146
|
})
|
|
531
147
|
}
|
|
532
|
-
|
|
533
|
-
func (state *nestiaCoreTransformState) cachedArguments(
|
|
534
|
-
key nestiaCoreCacheKey,
|
|
535
|
-
generate func() ([]string, bool, error),
|
|
536
|
-
) ([]string, bool, error) {
|
|
537
|
-
if cached, ok := state.cache[key]; ok {
|
|
538
|
-
state.cacheHits++
|
|
539
|
-
return append([]string(nil), cached...), true, nil
|
|
540
|
-
}
|
|
541
|
-
state.cacheMisses++
|
|
542
|
-
arguments, ok, err := generate()
|
|
543
|
-
if err != nil || ok == false {
|
|
544
|
-
return arguments, ok, err
|
|
545
|
-
}
|
|
546
|
-
state.cache[key] = append([]string(nil), arguments...)
|
|
547
|
-
return append([]string(nil), arguments...), true, nil
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
func (state *nestiaCoreTransformState) cacheKey(
|
|
551
|
-
segments []string,
|
|
552
|
-
kind string,
|
|
553
|
-
typ *shimchecker.Type,
|
|
554
|
-
argCount int,
|
|
555
|
-
allowOptional bool,
|
|
556
|
-
) nestiaCoreCacheKey {
|
|
557
|
-
return nestiaCoreCacheKey{
|
|
558
|
-
Kind: kind,
|
|
559
|
-
Type: typ,
|
|
560
|
-
TypeName: nestiaCoreTypeNameText(state.prog, typ),
|
|
561
|
-
Modulo: strings.Join(segments, "."),
|
|
562
|
-
Validate: state.options.Validate,
|
|
563
|
-
Stringify: state.options.Stringify,
|
|
564
|
-
StringifyNull: state.options.StringifyNull,
|
|
565
|
-
Llm: state.options.Llm,
|
|
566
|
-
LlmStrict: state.options.LlmStrict,
|
|
567
|
-
ArgCount: argCount,
|
|
568
|
-
AllowOptional: allowOptional,
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
|
|
572
148
|
func nestiaCoreRawDecoratorCall(decorator *shimast.Node) (*shimast.CallExpression, []string, bool) {
|
|
573
149
|
if decorator == nil || decorator.Kind != NestiaCoreKindDecorator {
|
|
574
150
|
return nil, nil, false
|
|
@@ -705,58 +281,6 @@ func IsNestiaCoreCall(prog *driver.Program, node *shimast.Node) bool {
|
|
|
705
281
|
strings.Contains(location, "@nestia/core/src/decorators/") ||
|
|
706
282
|
strings.Contains(location, "packages/core/src/decorators/")
|
|
707
283
|
}
|
|
708
|
-
|
|
709
|
-
func isNestiaCoreImportedExpression(node *shimast.Node, segments []string) bool {
|
|
710
|
-
if len(segments) == 0 {
|
|
711
|
-
return false
|
|
712
|
-
}
|
|
713
|
-
source := shimast.GetSourceFileOfNode(node)
|
|
714
|
-
if source == nil || source.Statements == nil {
|
|
715
|
-
return false
|
|
716
|
-
}
|
|
717
|
-
root := segments[0]
|
|
718
|
-
for _, stmt := range source.Statements.Nodes {
|
|
719
|
-
if stmt == nil || stmt.Kind != shimast.KindImportDeclaration {
|
|
720
|
-
continue
|
|
721
|
-
}
|
|
722
|
-
decl := stmt.AsImportDeclaration()
|
|
723
|
-
if decl == nil || decl.ImportClause == nil || decl.ModuleSpecifier == nil || decl.ModuleSpecifier.Kind != shimast.KindStringLiteral {
|
|
724
|
-
continue
|
|
725
|
-
}
|
|
726
|
-
if decl.ModuleSpecifier.Text() != "@nestia/core" {
|
|
727
|
-
continue
|
|
728
|
-
}
|
|
729
|
-
clause := decl.ImportClause.AsImportClause()
|
|
730
|
-
if clause == nil || clause.PhaseModifier == shimast.KindTypeKeyword {
|
|
731
|
-
continue
|
|
732
|
-
}
|
|
733
|
-
if name := clause.Name(); name != nil && name.Text() == root {
|
|
734
|
-
return true
|
|
735
|
-
}
|
|
736
|
-
if clause.NamedBindings == nil || clause.NamedBindings.Kind != shimast.KindNamedImports {
|
|
737
|
-
continue
|
|
738
|
-
}
|
|
739
|
-
named := clause.NamedBindings.AsNamedImports()
|
|
740
|
-
if named == nil || named.Elements == nil {
|
|
741
|
-
continue
|
|
742
|
-
}
|
|
743
|
-
for _, elem := range named.Elements.Nodes {
|
|
744
|
-
if elem == nil {
|
|
745
|
-
continue
|
|
746
|
-
}
|
|
747
|
-
spec := elem.AsImportSpecifier()
|
|
748
|
-
if spec == nil || spec.IsTypeOnly {
|
|
749
|
-
continue
|
|
750
|
-
}
|
|
751
|
-
name := spec.Name()
|
|
752
|
-
if name != nil && name.Text() == root {
|
|
753
|
-
return true
|
|
754
|
-
}
|
|
755
|
-
}
|
|
756
|
-
}
|
|
757
|
-
return false
|
|
758
|
-
}
|
|
759
|
-
|
|
760
284
|
func nestiaCoreParameterKind(segments []string) string {
|
|
761
285
|
suffixes := map[string]string{
|
|
762
286
|
"EncryptedBody": "TypedBody",
|
|
@@ -801,45 +325,10 @@ func nestiaCoreMethodKind(segments []string) string {
|
|
|
801
325
|
}
|
|
802
326
|
}
|
|
803
327
|
|
|
804
|
-
func nestiaCoreParameterArguments(
|
|
805
|
-
prog *driver.Program,
|
|
806
|
-
options nestiaCoreOptions,
|
|
807
|
-
call *shimast.CallExpression,
|
|
808
|
-
modulo *shimast.Node,
|
|
809
|
-
kind string,
|
|
810
|
-
typ *shimchecker.Type,
|
|
811
|
-
) ([]string, bool, error) {
|
|
812
|
-
nodes, ok, err := nestiaCoreParameterArgumentNodes(prog, nil, nil, options, call, modulo, kind, typ)
|
|
813
|
-
if err != nil || !ok {
|
|
814
|
-
return nil, ok, err
|
|
815
|
-
}
|
|
816
|
-
file := shimast.GetSourceFileOfNode(call.AsNode())
|
|
817
|
-
output := make([]string, 0, len(nodes))
|
|
818
|
-
for _, node := range nodes {
|
|
819
|
-
output = append(output, nestiaCoreArgumentNodeToText(prog, file, node))
|
|
820
|
-
}
|
|
821
|
-
return output, true, nil
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
// nestiaCoreArgumentNodeToText prints a single appended decorator-argument node
|
|
825
|
-
// for the legacy text-splice path. Keyword nodes (undefined / true) print as
|
|
826
|
-
// their literal text; validator nodes go through the type-stripping printer.
|
|
827
|
-
func nestiaCoreArgumentNodeToText(prog *driver.Program, file *shimast.SourceFile, node *shimast.Node) string {
|
|
828
|
-
switch node.Kind {
|
|
829
|
-
case shimast.KindUndefinedKeyword:
|
|
830
|
-
return "undefined"
|
|
831
|
-
case shimast.KindTrueKeyword:
|
|
832
|
-
return "true"
|
|
833
|
-
}
|
|
834
|
-
return emitNestiaCoreExpression(prog, file, node, false)
|
|
835
|
-
}
|
|
836
|
-
|
|
837
328
|
// nestiaCoreParameterArgumentNodes builds the appended decorator-argument nodes
|
|
838
329
|
// for a parameter decorator. The importer is the file-scoped ImportProgrammer:
|
|
839
|
-
//
|
|
840
|
-
//
|
|
841
|
-
// legacy text behavior. Returning nodes (not text) is the single source of truth
|
|
842
|
-
// shared by the text path (nestiaCoreParameterArguments) and the AST emit path.
|
|
330
|
+
// it is the shared ec-mode importer, so the validator's runtime references
|
|
331
|
+
// resolve to tsgo-aliased namespace imports.
|
|
843
332
|
func nestiaCoreParameterArgumentNodes(
|
|
844
333
|
prog *driver.Program,
|
|
845
334
|
importer *nativecontext.ImportProgrammer, ec *shimprinter.EmitContext,
|
|
@@ -1198,9 +687,8 @@ func nestiaCoreGenerateTypedQueryRoute(prog *driver.Program, importer *nativecon
|
|
|
1198
687
|
// validator generation. The importer argument is the file-scoped ImportProgrammer:
|
|
1199
688
|
// on the AST-integration emit path it is the shared, ec-mode importer (so every
|
|
1200
689
|
// generated validator references namespace imports tsgo's module-transform
|
|
1201
|
-
// aliases, and all injected imports collapse into one ToStatements() set).
|
|
1202
|
-
// importer
|
|
1203
|
-
// text-splice behavior used by the `transform` / `check` source paths.
|
|
690
|
+
// aliases, and all injected imports collapse into one ToStatements() set). A nil
|
|
691
|
+
// importer falls back to a throwaway one; no current caller relies on it.
|
|
1204
692
|
func nestiaCoreTypiaContext(prog *driver.Program, importer *nativecontext.ImportProgrammer, ec *shimprinter.EmitContext, numeric bool, finite bool, functional bool) nativecontext.ITypiaContext {
|
|
1205
693
|
if importer == nil {
|
|
1206
694
|
importer = nativecontext.NewImportProgrammer(nativecontext.ImportProgrammer_IOptions{
|
|
@@ -1222,8 +710,7 @@ func nestiaCoreTypiaContext(prog *driver.Program, importer *nativecontext.Import
|
|
|
1222
710
|
// Seed the emit context so typia's per-programmer factories
|
|
1223
711
|
// (EmitFactoryOf(..., Context.Emit)) build emit-tracked nodes; without it
|
|
1224
712
|
// the generated validator/stringifier nodes have no original link and
|
|
1225
|
-
// tsgo's MarkLinkedReferences pass nil-panics during emit.
|
|
1226
|
-
// legacy text path.
|
|
713
|
+
// tsgo's MarkLinkedReferences pass nil-panics during emit.
|
|
1227
714
|
Emit: ec,
|
|
1228
715
|
}
|
|
1229
716
|
}
|
|
@@ -1521,55 +1008,6 @@ func safeNestiaCoreGenerateNode(generator func() (*shimast.Node, error)) (node *
|
|
|
1521
1008
|
return generator()
|
|
1522
1009
|
}
|
|
1523
1010
|
|
|
1524
|
-
func safeNestiaCoreGenerate(
|
|
1525
|
-
generator func() (*shimast.Node, error),
|
|
1526
|
-
prog *driver.Program,
|
|
1527
|
-
file *shimast.SourceFile,
|
|
1528
|
-
preserveTypes bool,
|
|
1529
|
-
) (text string, err error) {
|
|
1530
|
-
defer func() {
|
|
1531
|
-
if exp := recover(); exp != nil {
|
|
1532
|
-
if os.Getenv("NESTIA_NATIVE_DEBUG_STACK") != "" {
|
|
1533
|
-
err = fmt.Errorf("%v\n%s", exp, debug.Stack())
|
|
1534
|
-
} else {
|
|
1535
|
-
err = fmt.Errorf("%v", exp)
|
|
1536
|
-
}
|
|
1537
|
-
}
|
|
1538
|
-
}()
|
|
1539
|
-
node, err := generator()
|
|
1540
|
-
if err != nil {
|
|
1541
|
-
return "", err
|
|
1542
|
-
}
|
|
1543
|
-
return emitNestiaCoreExpression(prog, file, node, preserveTypes), nil
|
|
1544
|
-
}
|
|
1545
|
-
|
|
1546
|
-
func emitNestiaCoreExpression(prog *driver.Program, file *shimast.SourceFile, node *shimast.Node, preserveTypes bool) string {
|
|
1547
|
-
var text string
|
|
1548
|
-
if preserveTypes {
|
|
1549
|
-
text = emitNestiaPreservingTypesWithIdentifierSubstitutions(node, file, nil)
|
|
1550
|
-
} else {
|
|
1551
|
-
text = emitNestiaWithIdentifierSubstitutions(
|
|
1552
|
-
node,
|
|
1553
|
-
file,
|
|
1554
|
-
identifierSubstitutionsForEmit(prog, file),
|
|
1555
|
-
)
|
|
1556
|
-
}
|
|
1557
|
-
return cleanupNestiaCorePrintedExpression(text)
|
|
1558
|
-
}
|
|
1559
|
-
|
|
1560
|
-
func cleanupNestiaCorePrintedExpression(text string) string {
|
|
1561
|
-
text = strings.TrimSpace(text)
|
|
1562
|
-
text = strings.TrimSuffix(text, ";")
|
|
1563
|
-
text = nestiaCoreSingleParameterArrowPattern.ReplaceAllString(text, `${1}(${2}) =>`)
|
|
1564
|
-
if strings.HasPrefix(text, "(") && strings.HasSuffix(text, ")") {
|
|
1565
|
-
return text
|
|
1566
|
-
}
|
|
1567
|
-
if strings.Contains(text, "=>") || strings.Contains(text, "function") {
|
|
1568
|
-
return "(" + text + ")"
|
|
1569
|
-
}
|
|
1570
|
-
return text
|
|
1571
|
-
}
|
|
1572
|
-
|
|
1573
1011
|
var nestiaCoreSingleParameterArrowPattern = regexp.MustCompile(`(^|[\s(=,:?])([A-Za-z_$][A-Za-z0-9_$]*) =>`)
|
|
1574
1012
|
|
|
1575
1013
|
func NestiaCoreMethodReturnType(prog *driver.Program, node *shimast.Node) *shimchecker.Type {
|
|
@@ -1768,19 +1206,41 @@ func callArgumentBounds(source string, call *shimast.CallExpression) (int, int,
|
|
|
1768
1206
|
return 0, 0, false
|
|
1769
1207
|
}
|
|
1770
1208
|
open += start
|
|
1771
|
-
close, ok :=
|
|
1209
|
+
close, ok := matchClosingParen(source, open)
|
|
1772
1210
|
return open, close, ok
|
|
1773
1211
|
}
|
|
1774
1212
|
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1213
|
+
// matchClosingParen returns the index of the ')' closing the '(' at pos,
|
|
1214
|
+
// skipping over quoted and template spans so a parenthesis inside a string
|
|
1215
|
+
// literal argument cannot unbalance the scan.
|
|
1216
|
+
func matchClosingParen(text string, pos int) (int, bool) {
|
|
1217
|
+
if pos >= len(text) || text[pos] != '(' {
|
|
1218
|
+
return 0, false
|
|
1219
|
+
}
|
|
1220
|
+
depth := 1
|
|
1221
|
+
for i := pos + 1; i < len(text); i++ {
|
|
1222
|
+
switch text[i] {
|
|
1223
|
+
case '(':
|
|
1224
|
+
depth++
|
|
1225
|
+
case ')':
|
|
1226
|
+
depth--
|
|
1227
|
+
if depth == 0 {
|
|
1228
|
+
return i, true
|
|
1229
|
+
}
|
|
1230
|
+
case '"', '\'', '`':
|
|
1231
|
+
q := text[i]
|
|
1232
|
+
j := i + 1
|
|
1233
|
+
for j < len(text) && text[j] != q {
|
|
1234
|
+
if text[j] == '\\' {
|
|
1235
|
+
j++
|
|
1236
|
+
}
|
|
1237
|
+
j++
|
|
1238
|
+
}
|
|
1239
|
+
i = j
|
|
1240
|
+
}
|
|
1780
1241
|
}
|
|
1781
|
-
return
|
|
1242
|
+
return 0, false
|
|
1782
1243
|
}
|
|
1783
|
-
|
|
1784
1244
|
func NestiaCoreExpressionSegments(node *shimast.Node) []string {
|
|
1785
1245
|
if node == nil {
|
|
1786
1246
|
return nil
|
|
@@ -1804,15 +1264,6 @@ func NestiaCoreExpressionSegments(node *shimast.Node) []string {
|
|
|
1804
1264
|
}
|
|
1805
1265
|
return nil
|
|
1806
1266
|
}
|
|
1807
|
-
|
|
1808
|
-
func nestiaCoreModuloNode(node *shimast.Node) *shimast.Node {
|
|
1809
|
-
segments := NestiaCoreExpressionSegments(node)
|
|
1810
|
-
if len(segments) == 0 {
|
|
1811
|
-
return nestiaCoreFactory.NewIdentifier("nestia_core_transform")
|
|
1812
|
-
}
|
|
1813
|
-
return nestiaCoreFactory.NewIdentifier(strings.Join(segments, "_"))
|
|
1814
|
-
}
|
|
1815
|
-
|
|
1816
1267
|
func nestiaCoreTypeName(prog *driver.Program, typ *shimchecker.Type) *string {
|
|
1817
1268
|
name := nestiaCoreTypeNameText(prog, typ)
|
|
1818
1269
|
return &name
|
|
@@ -1851,126 +1302,12 @@ func nestiaCoreSegmentsHaveSuffix(segments []string, suffix []string) bool {
|
|
|
1851
1302
|
return true
|
|
1852
1303
|
}
|
|
1853
1304
|
|
|
1854
|
-
func nestiaCoreTargetCandidates(prog *driver.Program, site nestiaCoreSite) []string {
|
|
1855
|
-
if len(site.Segments) == 0 {
|
|
1856
|
-
return nil
|
|
1857
|
-
}
|
|
1858
|
-
candidates := []string{strings.Join(site.Segments, ".")}
|
|
1859
|
-
substitutions := identifierSubstitutionsForEmit(prog, site.File)
|
|
1860
|
-
if substitutions != nil {
|
|
1861
|
-
if mapped, ok := substitutions[site.Segments[0]]; ok {
|
|
1862
|
-
parts := append([]string{mapped}, site.Segments[1:]...)
|
|
1863
|
-
candidates = append(candidates, strings.Join(parts, "."))
|
|
1864
|
-
}
|
|
1865
|
-
}
|
|
1866
|
-
sort.SliceStable(candidates, func(i, j int) bool {
|
|
1867
|
-
return len(candidates[i]) > len(candidates[j])
|
|
1868
|
-
})
|
|
1869
|
-
return candidates
|
|
1870
|
-
}
|
|
1871
|
-
|
|
1872
|
-
func identifierSubstitutionsForEmit(program *driver.Program, file any) map[string]string {
|
|
1873
|
-
if program == nil {
|
|
1874
|
-
return nil
|
|
1875
|
-
}
|
|
1876
|
-
sourceFile, ok := file.(*shimast.SourceFile)
|
|
1877
|
-
if ok == false {
|
|
1878
|
-
return nil
|
|
1879
|
-
}
|
|
1880
|
-
return commonJSImportIdentifierSubstitutions(sourceFile)
|
|
1881
|
-
}
|
|
1882
|
-
|
|
1883
1305
|
type commonJSImportIdentifierSubstitutionsCacheEntry struct {
|
|
1884
1306
|
value map[string]string
|
|
1885
1307
|
}
|
|
1886
1308
|
|
|
1887
1309
|
var commonJSImportIdentifierSubstitutionsCache sync.Map
|
|
1888
1310
|
|
|
1889
|
-
func commonJSImportIdentifierSubstitutions(file *shimast.SourceFile) map[string]string {
|
|
1890
|
-
if file == nil || file.Statements == nil {
|
|
1891
|
-
return nil
|
|
1892
|
-
}
|
|
1893
|
-
if cached, ok := commonJSImportIdentifierSubstitutionsCache.Load(file); ok {
|
|
1894
|
-
return cached.(commonJSImportIdentifierSubstitutionsCacheEntry).value
|
|
1895
|
-
}
|
|
1896
|
-
output := map[string]string{}
|
|
1897
|
-
counts := map[string]int{}
|
|
1898
|
-
for _, stmt := range file.Statements.Nodes {
|
|
1899
|
-
if stmt == nil || stmt.Kind != shimast.KindImportDeclaration {
|
|
1900
|
-
continue
|
|
1901
|
-
}
|
|
1902
|
-
decl := stmt.AsImportDeclaration()
|
|
1903
|
-
if decl == nil || decl.ImportClause == nil || decl.ModuleSpecifier == nil || decl.ModuleSpecifier.Kind != shimast.KindStringLiteral {
|
|
1904
|
-
continue
|
|
1905
|
-
}
|
|
1906
|
-
clause := decl.ImportClause.AsImportClause()
|
|
1907
|
-
if clause == nil || clause.PhaseModifier == shimast.KindTypeKeyword {
|
|
1908
|
-
continue
|
|
1909
|
-
}
|
|
1910
|
-
base := commonJSImportAliasBase(decl.ModuleSpecifier.Text())
|
|
1911
|
-
counts[base]++
|
|
1912
|
-
moduleAlias := base + "_" + strconv.Itoa(counts[base])
|
|
1913
|
-
if name := clause.Name(); name != nil {
|
|
1914
|
-
output[name.Text()] = moduleAlias + ".default"
|
|
1915
|
-
}
|
|
1916
|
-
if clause.NamedBindings == nil || clause.NamedBindings.Kind != shimast.KindNamedImports {
|
|
1917
|
-
continue
|
|
1918
|
-
}
|
|
1919
|
-
named := clause.NamedBindings.AsNamedImports()
|
|
1920
|
-
if named == nil || named.Elements == nil {
|
|
1921
|
-
continue
|
|
1922
|
-
}
|
|
1923
|
-
for _, elem := range named.Elements.Nodes {
|
|
1924
|
-
if elem == nil {
|
|
1925
|
-
continue
|
|
1926
|
-
}
|
|
1927
|
-
spec := elem.AsImportSpecifier()
|
|
1928
|
-
if spec == nil || spec.IsTypeOnly {
|
|
1929
|
-
continue
|
|
1930
|
-
}
|
|
1931
|
-
name := spec.Name()
|
|
1932
|
-
if name == nil {
|
|
1933
|
-
continue
|
|
1934
|
-
}
|
|
1935
|
-
local := name.Text()
|
|
1936
|
-
imported := local
|
|
1937
|
-
if spec.PropertyName != nil {
|
|
1938
|
-
imported = spec.PropertyName.Text()
|
|
1939
|
-
}
|
|
1940
|
-
output[local] = moduleAlias + "." + imported
|
|
1941
|
-
}
|
|
1942
|
-
}
|
|
1943
|
-
if len(output) == 0 {
|
|
1944
|
-
output = nil
|
|
1945
|
-
}
|
|
1946
|
-
commonJSImportIdentifierSubstitutionsCache.Store(file, commonJSImportIdentifierSubstitutionsCacheEntry{value: output})
|
|
1947
|
-
return output
|
|
1948
|
-
}
|
|
1949
|
-
|
|
1950
|
-
func commonJSImportAliasBase(module string) string {
|
|
1951
|
-
base := strings.TrimSuffix(filepath.Base(module), filepath.Ext(module))
|
|
1952
|
-
if base == "" || base == "." || base == string(filepath.Separator) {
|
|
1953
|
-
base = "mod"
|
|
1954
|
-
}
|
|
1955
|
-
var builder strings.Builder
|
|
1956
|
-
for _, r := range base {
|
|
1957
|
-
if r == '_' || r == '$' || unicode.IsLetter(r) || unicode.IsDigit(r) {
|
|
1958
|
-
builder.WriteRune(r)
|
|
1959
|
-
} else {
|
|
1960
|
-
builder.WriteByte('_')
|
|
1961
|
-
}
|
|
1962
|
-
}
|
|
1963
|
-
text := builder.String()
|
|
1964
|
-
if text == "" {
|
|
1965
|
-
text = "mod"
|
|
1966
|
-
}
|
|
1967
|
-
first := []rune(text)[0]
|
|
1968
|
-
if first != '_' && first != '$' && !unicode.IsLetter(first) {
|
|
1969
|
-
text = "_" + text
|
|
1970
|
-
}
|
|
1971
|
-
return text
|
|
1972
|
-
}
|
|
1973
|
-
|
|
1974
1311
|
func nestiaCoreDiagnostic(site nestiaCoreSite, message string) Diagnostic {
|
|
1975
1312
|
line, column := 0, 0
|
|
1976
1313
|
if site.File != nil && site.Call != nil {
|