@nestia/sdk 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.
Files changed (87) hide show
  1. package/assets/bundle/distribute/package.json +1 -1
  2. package/assets/config/nestia.config.ts +19 -19
  3. package/lib/NestiaSwaggerComposer.js +2 -0
  4. package/lib/NestiaSwaggerComposer.js.map +1 -1
  5. package/lib/analyses/ImportAnalyzer.d.ts +6 -5
  6. package/lib/analyses/ImportAnalyzer.js +30 -15
  7. package/lib/analyses/ImportAnalyzer.js.map +1 -1
  8. package/lib/analyses/ReflectControllerAnalyzer.js +18 -9
  9. package/lib/analyses/ReflectControllerAnalyzer.js.map +1 -1
  10. package/lib/analyses/ReflectHttpOperationAnalyzer.d.ts +1 -1
  11. package/lib/analyses/ReflectHttpOperationAnalyzer.js +8 -6
  12. package/lib/analyses/ReflectHttpOperationAnalyzer.js.map +1 -1
  13. package/lib/analyses/ReflectHttpOperationExceptionAnalyzer.d.ts +1 -1
  14. package/lib/analyses/ReflectHttpOperationExceptionAnalyzer.js.map +1 -1
  15. package/lib/analyses/ReflectHttpOperationParameterAnalyzer.d.ts +1 -1
  16. package/lib/analyses/ReflectHttpOperationParameterAnalyzer.js +1 -1
  17. package/lib/analyses/ReflectHttpOperationParameterAnalyzer.js.map +1 -1
  18. package/lib/analyses/ReflectWebSocketOperationAnalyzer.d.ts +1 -1
  19. package/lib/analyses/ReflectWebSocketOperationAnalyzer.js +10 -6
  20. package/lib/analyses/ReflectWebSocketOperationAnalyzer.js.map +1 -1
  21. package/lib/analyses/TypedHttpRouteAnalyzer.js +13 -7
  22. package/lib/analyses/TypedHttpRouteAnalyzer.js.map +1 -1
  23. package/lib/executable/internal/NestiaSdkCommand.js +7 -4
  24. package/lib/executable/internal/NestiaSdkCommand.js.map +1 -1
  25. package/lib/generates/E2eGenerator.js +1 -4
  26. package/lib/generates/E2eGenerator.js.map +1 -1
  27. package/lib/generates/SdkGenerator.js +1 -4
  28. package/lib/generates/SdkGenerator.js.map +1 -1
  29. package/lib/generates/SwaggerGenerator.js +5 -5
  30. package/lib/generates/SwaggerGenerator.js.map +1 -1
  31. package/lib/generates/internal/ImportDictionary.js +14 -6
  32. package/lib/generates/internal/ImportDictionary.js.map +1 -1
  33. package/lib/generates/internal/SdkDistributionComposer.js +27 -22
  34. package/lib/generates/internal/SdkDistributionComposer.js.map +1 -1
  35. package/lib/generates/internal/SdkFileProgrammer.js +1 -4
  36. package/lib/generates/internal/SdkFileProgrammer.js.map +1 -1
  37. package/lib/generates/internal/SdkHttpCloneReferencer.js +13 -9
  38. package/lib/generates/internal/SdkHttpCloneReferencer.js.map +1 -1
  39. package/lib/generates/internal/SdkWebSocketCloneProgrammer.js +6 -3
  40. package/lib/generates/internal/SdkWebSocketCloneProgrammer.js.map +1 -1
  41. package/lib/generates/internal/SwaggerOperationComposer.d.ts +1 -1
  42. package/lib/generates/internal/SwaggerOperationComposer.js.map +1 -1
  43. package/lib/internal/legacy.d.ts +44 -46
  44. package/lib/internal/legacy.js +35 -48
  45. package/lib/internal/legacy.js.map +1 -1
  46. package/lib/structures/IReflectHttpOperationException.d.ts +1 -1
  47. package/lib/structures/IReflectHttpOperationParameter.d.ts +1 -1
  48. package/lib/structures/IReflectImport.d.ts +2 -0
  49. package/lib/structures/ITypedHttpRouteParameter.d.ts +1 -1
  50. package/lib/utils/TsConfigReader.js +3 -1
  51. package/lib/utils/TsConfigReader.js.map +1 -1
  52. package/lib/validators/HttpHeadersValidator.d.ts +3 -2
  53. package/lib/validators/HttpHeadersValidator.js +3 -2
  54. package/lib/validators/HttpHeadersValidator.js.map +1 -1
  55. package/lib/validators/HttpQueryValidator.d.ts +4 -4
  56. package/lib/validators/HttpQueryValidator.js +4 -4
  57. package/native/sdk/register.go +6 -35
  58. package/native/sdk/sdk_transform.go +80 -304
  59. package/package.json +9 -9
  60. package/src/NestiaSwaggerComposer.ts +2 -0
  61. package/src/analyses/ImportAnalyzer.ts +24 -15
  62. package/src/analyses/ReflectControllerAnalyzer.ts +19 -10
  63. package/src/analyses/ReflectHttpOperationAnalyzer.ts +5 -2
  64. package/src/analyses/ReflectHttpOperationExceptionAnalyzer.ts +2 -2
  65. package/src/analyses/ReflectHttpOperationParameterAnalyzer.ts +3 -3
  66. package/src/analyses/ReflectWebSocketOperationAnalyzer.ts +14 -7
  67. package/src/analyses/TypedHttpRouteAnalyzer.ts +74 -35
  68. package/src/executable/internal/NestiaSdkCommand.ts +8 -5
  69. package/src/generates/E2eGenerator.ts +1 -3
  70. package/src/generates/SdkGenerator.ts +1 -3
  71. package/src/generates/SwaggerGenerator.ts +5 -6
  72. package/src/generates/internal/ImportDictionary.ts +23 -11
  73. package/src/generates/internal/SdkDistributionComposer.ts +25 -23
  74. package/src/generates/internal/SdkFileProgrammer.ts +1 -3
  75. package/src/generates/internal/SdkHttpCloneReferencer.ts +15 -10
  76. package/src/generates/internal/SdkWebSocketCloneProgrammer.ts +4 -3
  77. package/src/generates/internal/SwaggerOperationComposer.ts +1 -1
  78. package/src/internal/legacy.ts +83 -73
  79. package/src/structures/IReflectHttpOperationException.ts +1 -1
  80. package/src/structures/IReflectHttpOperationParameter.ts +1 -1
  81. package/src/structures/IReflectImport.ts +2 -0
  82. package/src/structures/ITypedApplication.ts +0 -1
  83. package/src/structures/ITypedHttpRouteException.ts +0 -1
  84. package/src/structures/ITypedHttpRouteParameter.ts +1 -1
  85. package/src/utils/TsConfigReader.ts +11 -3
  86. package/src/validators/HttpHeadersValidator.ts +3 -2
  87. package/src/validators/HttpQueryValidator.ts +4 -4
@@ -13,7 +13,7 @@ import (
13
13
  "github.com/samchon/ttsc/packages/ttsc/driver"
14
14
  )
15
15
 
16
- // sdkMetadataNamespace is the import alias the legacy (text/program-mutation)
16
+ // sdkMetadataNamespace is the import alias the ApplyProgram (program-mutation)
17
17
  // path references. The emit-context path lets tsgo's module-transform pick the
18
18
  // generated alias itself, so it does not use this constant.
19
19
  const sdkMetadataNamespace = "__OperationMetadata"
@@ -30,12 +30,11 @@ const sdkMetadataMember = "OperationMetadata"
30
30
  // ttsc classifies this package (name != "main") as a linked transform and
31
31
  // statically links it into the `@nestia/core` host binary — but only for
32
32
  // projects that depend on `@nestia/sdk`. The direct linked-plugin path keeps
33
- // old plugin plans working, while the contributor collectors let the aggregate
34
- // core host run SDK metadata rewrites without starting a second native backend.
33
+ // old plugin plans working, while the emit-transform collector lets the
34
+ // aggregate core host run the SDK metadata pass inside the shared emit context
35
+ // without starting a second native backend.
35
36
  func init() {
36
37
  driver.RegisterPlugin(linkedPlugin{})
37
- transform.RegisterBuildOutputRewriteCollector(collectSDKBuildOutputRewriter)
38
- transform.RegisterSourceRewriteCollector(collectSDKSourceRewriteMap)
39
38
  transform.RegisterEmitTransformCollector(collectSDKEmitTransform)
40
39
  }
41
40
 
@@ -84,8 +83,8 @@ func (linkedPlugin) ApplyProgram(prog *driver.Program, _ driver.PluginContext) e
84
83
  // `@<ns>.OperationMetadata("<json>")` decorator plus a namespace import of
85
84
  // `@nestia/sdk`, both built with ec.Factory and referenced through
86
85
  // NewGeneratedNameForNode(modSpec), so tsgo's builtin module-transform emits the
87
- // `require("@nestia/sdk")` and aliases the reference itself no hand-rolled
88
- // `__OperationMetadata` namespace and no text-splice.
86
+ // `require("@nestia/sdk")` and aliases the reference itself, with no
87
+ // hand-rolled `__OperationMetadata` namespace.
89
88
  //
90
89
  // Core's build command wires this into `prog.EmitWithPluginTransformers`
91
90
  // alongside the typia and core transforms, exactly as the typia build command
@@ -169,34 +168,6 @@ func collectSDKEmitTransform(
169
168
  }
170
169
  return EmitTransform(prog)
171
170
  }
172
-
173
- func collectSDKBuildOutputRewriter(
174
- prog *driver.Program,
175
- plan plugin.Plan,
176
- ) (*transform.BuildOutputRewriter, []transform.Diagnostic) {
177
- if shouldRunSDKContributorTransform() == false {
178
- return nil, nil
179
- }
180
- plan.SDK = true
181
- set, diagnostics := collectNestiaSDKBuildRewrites(prog, plan)
182
- return &transform.BuildOutputRewriter{
183
- Len: set.Len,
184
- Apply: set.Apply,
185
- }, diagnostics
186
- }
187
-
188
- func collectSDKSourceRewriteMap(
189
- prog *driver.Program,
190
- plan plugin.Plan,
191
- onlyFile string,
192
- ) (map[string][]transform.SourceRewrite, []transform.Diagnostic) {
193
- if shouldRunSDKContributorTransform() == false {
194
- return map[string][]transform.SourceRewrite{}, nil
195
- }
196
- plan.SDK = true
197
- return collectNestiaSDKSourceRewriteMap(prog, plan, onlyFile)
198
- }
199
-
200
171
  func shouldRunSDKContributorTransform() bool {
201
172
  return os.Getenv("NESTIA_SDK_TRANSFORM") == "1"
202
173
  }
@@ -12,7 +12,6 @@ import (
12
12
  shimast "github.com/microsoft/typescript-go/shim/ast"
13
13
  shimchecker "github.com/microsoft/typescript-go/shim/checker"
14
14
  shimscanner "github.com/microsoft/typescript-go/shim/scanner"
15
- "github.com/samchon/nestia/packages/core/native/plugin"
16
15
  "github.com/samchon/nestia/packages/core/native/transform"
17
16
  "github.com/samchon/ttsc/packages/ttsc/driver"
18
17
  nativecontext "github.com/samchon/typia/packages/typia/native/core/context"
@@ -31,10 +30,6 @@ type nestiaSDKSite struct {
31
30
  Metadata string
32
31
  }
33
32
 
34
- type nestiaSDKBuildRewriteSet struct {
35
- byPath map[string][]nestiaSDKSite
36
- }
37
-
38
33
  type nestiaSDKContext struct {
39
34
  prog *driver.Program
40
35
  collection *schemametadata.MetadataCollection
@@ -79,112 +74,6 @@ func (ctx *nestiaSDKContext) imports(file *shimast.SourceFile) []nestiaSDKImport
79
74
  ctx.importsByFile[name] = imports
80
75
  return imports
81
76
  }
82
-
83
- func newNestiaSDKBuildRewriteSet() *nestiaSDKBuildRewriteSet {
84
- return &nestiaSDKBuildRewriteSet{byPath: map[string][]nestiaSDKSite{}}
85
- }
86
-
87
- func (rs *nestiaSDKBuildRewriteSet) Add(site nestiaSDKSite) {
88
- if site.FilePath == "" {
89
- return
90
- }
91
- path := filepath.ToSlash(site.FilePath)
92
- rs.byPath[path] = append(rs.byPath[path], site)
93
- }
94
-
95
- func (rs *nestiaSDKBuildRewriteSet) Len() int {
96
- if rs == nil {
97
- return 0
98
- }
99
- count := 0
100
- for _, sites := range rs.byPath {
101
- count += len(sites)
102
- }
103
- return count
104
- }
105
-
106
- func (rs *nestiaSDKBuildRewriteSet) Apply(outputName string, text string) (string, error) {
107
- if rs == nil || len(rs.byPath) == 0 {
108
- return text, nil
109
- }
110
- srcPath, ok := rs.findSourceForOutput(outputName)
111
- if !ok {
112
- return text, nil
113
- }
114
- out := text
115
- out = insertSDKOperationMetadataDecorators(out, rs.byPath[srcPath])
116
- return injectSDKOperationMetadataImport(out), nil
117
- }
118
-
119
- func (rs *nestiaSDKBuildRewriteSet) findSourceForOutput(outputName string) (string, bool) {
120
- outSlash := strings.TrimSuffix(filepath.ToSlash(outputName), filepath.Ext(outputName))
121
- for path := range rs.byPath {
122
- srcStem := strings.TrimSuffix(filepath.ToSlash(path), filepath.Ext(path))
123
- if transform.OutputMatchesSourceStem(outSlash, srcStem) {
124
- return path, true
125
- }
126
- }
127
- return "", false
128
- }
129
-
130
- func collectNestiaSDKSourceRewriteMap(
131
- prog *driver.Program,
132
- plan plugin.Plan,
133
- onlyFile string,
134
- ) (map[string][]transform.SourceRewrite, []transform.Diagnostic) {
135
- if plan.SDK == false {
136
- return map[string][]transform.SourceRewrite{}, nil
137
- }
138
- sites, diagnostics := collectNestiaSDKSites(prog)
139
- rewrites := map[string][]transform.SourceRewrite{}
140
- touched := map[string]bool{}
141
- for _, site := range sites {
142
- file := filepath.ToSlash(site.FilePath)
143
- if onlyFile != "" && file != filepath.ToSlash(onlyFile) {
144
- continue
145
- }
146
- source, ok := transform.SourceFileText(site.File)
147
- if !ok {
148
- diagnostics = append(diagnostics, nestiaSDKDiagnostic(site, "source text is unavailable"))
149
- continue
150
- }
151
- insert := site.Method.Pos()
152
- if decorators := site.Method.Decorators(); len(decorators) != 0 {
153
- insert = decorators[0].Pos()
154
- }
155
- indent := sourceLineIndent(source, insert)
156
- rewrites[file] = append(rewrites[file], transform.NewSourceRewrite(
157
- insert,
158
- insert,
159
- "\n"+indent+"@__OperationMetadata.OperationMetadata("+site.Metadata+" as any)\n",
160
- ))
161
- touched[file] = true
162
- }
163
- for file := range touched {
164
- rewrites[file] = append(rewrites[file], transform.NewSourceRewrite(
165
- 0,
166
- 0,
167
- "import * as __OperationMetadata from \"@nestia/sdk\";\n",
168
- ))
169
- }
170
- return rewrites, diagnostics
171
- }
172
-
173
- func collectNestiaSDKBuildRewrites(
174
- prog *driver.Program,
175
- plan plugin.Plan,
176
- ) (*nestiaSDKBuildRewriteSet, []transform.Diagnostic) {
177
- set := newNestiaSDKBuildRewriteSet()
178
- if plan.SDK == false {
179
- return set, nil
180
- }
181
- sites, diagnostics := collectNestiaSDKSites(prog)
182
- for _, site := range sites {
183
- set.Add(site)
184
- }
185
- return set, diagnostics
186
- }
187
-
188
77
  func collectNestiaSDKSites(prog *driver.Program) ([]nestiaSDKSite, []transform.Diagnostic) {
189
78
  sites := []nestiaSDKSite{}
190
79
  diagnostics := []transform.Diagnostic{}
@@ -193,7 +82,7 @@ func collectNestiaSDKSites(prog *driver.Program) ([]nestiaSDKSite, []transform.D
193
82
  if file == nil || file.IsDeclarationFile {
194
83
  continue
195
84
  }
196
- visited := map[string]bool{}
85
+ visited := map[int]bool{}
197
86
  file.ForEachChild(func(node *shimast.Node) bool {
198
87
  visitNestiaSDKNode(context, file, node, visited, &sites, &diagnostics)
199
88
  return false
@@ -209,7 +98,7 @@ func visitNestiaSDKNode(
209
98
  context *nestiaSDKContext,
210
99
  file *shimast.SourceFile,
211
100
  node *shimast.Node,
212
- visited map[string]bool,
101
+ visited map[int]bool,
213
102
  sites *[]nestiaSDKSite,
214
103
  diagnostics *[]transform.Diagnostic,
215
104
  ) {
@@ -220,7 +109,10 @@ func visitNestiaSDKNode(
220
109
  className := nestiaSDKParentClassName(node)
221
110
  methodName := nestiaSDKMethodName(node)
222
111
  if className != "" && methodName != "" {
223
- key := className + "." + methodName
112
+ // A method's source position is unique in this file. Class and method
113
+ // names are not: namespaces can legitimately export identically named
114
+ // controller classes and methods.
115
+ key := node.Pos()
224
116
  if visited[key] == false {
225
117
  visited[key] = true
226
118
  metadata, err := nestiaSDKMetadataText(context, file, node)
@@ -483,7 +375,12 @@ type nestiaSDKImportInfo struct {
483
375
  File string
484
376
  Asterisk string
485
377
  Default string
486
- Elements []string
378
+ Elements []nestiaSDKImportElement
379
+ }
380
+
381
+ type nestiaSDKImportElement struct {
382
+ Local string
383
+ Imported string
487
384
  }
488
385
 
489
386
  func nestiaSDKAnalyzeImports(file *shimast.SourceFile) []nestiaSDKImportInfo {
@@ -505,7 +402,7 @@ func nestiaSDKAnalyzeImports(file *shimast.SourceFile) []nestiaSDKImportInfo {
505
402
  }
506
403
  info := nestiaSDKImportInfo{
507
404
  File: nestiaSDKNormalizeImportPath(file.FileName(), decl.ModuleSpecifier.Text()),
508
- Elements: []string{},
405
+ Elements: []nestiaSDKImportElement{},
509
406
  }
510
407
  if name := clause.Name(); name != nil {
511
408
  info.Default = name.Text()
@@ -527,7 +424,14 @@ func nestiaSDKAnalyzeImports(file *shimast.SourceFile) []nestiaSDKImportInfo {
527
424
  continue
528
425
  }
529
426
  if name := spec.Name(); name != nil {
530
- info.Elements = append(info.Elements, name.Text())
427
+ imported := name.Text()
428
+ if property := spec.PropertyName; property != nil {
429
+ imported = property.Text()
430
+ }
431
+ info.Elements = append(info.Elements, nestiaSDKImportElement{
432
+ Local: name.Text(),
433
+ Imported: imported,
434
+ })
531
435
  }
532
436
  }
533
437
  }
@@ -596,7 +500,7 @@ func nestiaSDKImportMatches(prefixes map[string]bool, imp nestiaSDKImportInfo) b
596
500
  return true
597
501
  }
598
502
  for _, elem := range imp.Elements {
599
- if prefixes[elem] {
503
+ if prefixes[elem.Local] {
600
504
  return true
601
505
  }
602
506
  }
@@ -605,9 +509,13 @@ func nestiaSDKImportMatches(prefixes map[string]bool, imp nestiaSDKImportInfo) b
605
509
 
606
510
  func nestiaSDKImportLiteral(imp nestiaSDKImportInfo, prefixes map[string]bool) map[string]any {
607
511
  elements := []string{}
512
+ aliases := map[string]string{}
608
513
  for _, elem := range imp.Elements {
609
- if prefixes[elem] {
610
- elements = append(elements, elem)
514
+ if prefixes[elem.Local] {
515
+ elements = append(elements, elem.Local)
516
+ if elem.Imported != elem.Local {
517
+ aliases[elem.Local] = elem.Imported
518
+ }
611
519
  }
612
520
  }
613
521
  asterisk := any(nestiaSDKLiteralNull)
@@ -618,12 +526,16 @@ func nestiaSDKImportLiteral(imp nestiaSDKImportInfo, prefixes map[string]bool) m
618
526
  if imp.Default != "" && prefixes[imp.Default] {
619
527
  def = imp.Default
620
528
  }
621
- return map[string]any{
529
+ output := map[string]any{
622
530
  "file": imp.File,
623
531
  "asterisk": asterisk,
624
532
  "default": def,
625
533
  "elements": elements,
626
534
  }
535
+ if len(aliases) != 0 {
536
+ output["elementAliases"] = aliases
537
+ }
538
+ return output
627
539
  }
628
540
 
629
541
  func nestiaSDKResponse(
@@ -1168,24 +1080,58 @@ func nestiaSDKUnionRank(order map[string]int, name string) int {
1168
1080
  }
1169
1081
 
1170
1082
  func nestiaSDKIsTypeGuardError(prog *driver.Program, typ *shimchecker.Type, typeNode *shimast.Node) bool {
1171
- if typeNode != nil {
1172
- name := nestiaSDKTypeNodeText(typeNode)
1173
- if name == "TypeGuardError" || strings.HasPrefix(name, "TypeGuardError<") {
1083
+ if prog == nil || prog.Checker == nil {
1084
+ return false
1085
+ }
1086
+ var symbol *shimast.Symbol
1087
+ if typeNode != nil && typeNode.Kind == shimast.KindTypeReference {
1088
+ ref := typeNode.AsTypeReferenceNode()
1089
+ symbol = prog.Checker.GetSymbolAtLocation(ref.TypeName)
1090
+ }
1091
+ if symbol == nil && typ != nil {
1092
+ symbol = typ.Symbol()
1093
+ }
1094
+ if symbol == nil {
1095
+ return false
1096
+ }
1097
+ if symbol.Flags&shimast.SymbolFlagsAlias != 0 {
1098
+ if aliased := shimchecker.Checker_getAliasedSymbol(prog.Checker, symbol); aliased != nil {
1099
+ symbol = aliased
1100
+ }
1101
+ }
1102
+ if symbol.Name != "TypeGuardError" {
1103
+ return false
1104
+ }
1105
+ for _, declaration := range symbol.Declarations {
1106
+ source := shimast.GetSourceFileOfNode(declaration)
1107
+ if source == nil {
1108
+ continue
1109
+ }
1110
+ if nestiaSDKIsTypiaSourceFile(prog, source) {
1174
1111
  return true
1175
1112
  }
1176
- if typeNode.Kind == shimast.KindTypeReference {
1177
- ref := typeNode.AsTypeReferenceNode()
1178
- name = nestiaSDKEntityNameText(ref.TypeName)
1179
- if name == "TypeGuardError" {
1180
- return true
1113
+ }
1114
+ return false
1115
+ }
1116
+
1117
+ func nestiaSDKIsTypiaSourceFile(prog *driver.Program, source *shimast.SourceFile) bool {
1118
+ if prog == nil || prog.FS == nil || source == nil {
1119
+ return false
1120
+ }
1121
+ for directory := filepath.Dir(source.FileName()); ; {
1122
+ contents, ok := prog.FS.ReadFile(filepath.Join(directory, "package.json"))
1123
+ if ok {
1124
+ var pack struct {
1125
+ Name string `json:"name"`
1181
1126
  }
1127
+ return json.Unmarshal([]byte(contents), &pack) == nil && pack.Name == "typia"
1182
1128
  }
1129
+ parent := filepath.Dir(directory)
1130
+ if parent == directory {
1131
+ return false
1132
+ }
1133
+ directory = parent
1183
1134
  }
1184
- if prog != nil && prog.Checker != nil && typ != nil {
1185
- name := prog.Checker.TypeToString(typ)
1186
- return name == "TypeGuardError" || strings.HasPrefix(name, "TypeGuardError<")
1187
- }
1188
- return false
1189
1135
  }
1190
1136
 
1191
1137
  func nestiaSDKTypeGuardErrorSchemaPipe() any {
@@ -1572,36 +1518,12 @@ func nestiaSDKParameterName(node *shimast.Node) string {
1572
1518
  }
1573
1519
  return strings.Trim(node.Name().Text(), "\"'")
1574
1520
  }
1575
-
1576
- func nestiaSDKParameterTypeName(prog *driver.Program, node *shimast.Node, typ *shimchecker.Type) string {
1577
- if node != nil && node.AsParameterDeclaration() != nil {
1578
- if typeNode := node.AsParameterDeclaration().Type; typeNode != nil {
1579
- return nestiaSDKTypeNodeText(typeNode)
1580
- }
1581
- }
1582
- return nestiaSDKTypeNameFromChecker(prog, typ)
1583
- }
1584
-
1585
1521
  func nestiaSDKParameterTypeNode(node *shimast.Node) *shimast.Node {
1586
1522
  if node != nil && node.AsParameterDeclaration() != nil {
1587
1523
  return node.AsParameterDeclaration().Type
1588
1524
  }
1589
1525
  return nil
1590
1526
  }
1591
-
1592
- func nestiaSDKMethodReturnTypeName(
1593
- prog *driver.Program,
1594
- method *shimast.Node,
1595
- typ *shimchecker.Type,
1596
- ) string {
1597
- if method != nil && method.FunctionLikeData() != nil {
1598
- if typeNode := method.FunctionLikeData().Type; typeNode != nil {
1599
- return nestiaSDKReturnTypeNodeText(prog, typeNode)
1600
- }
1601
- }
1602
- return nestiaSDKTypeNameFromChecker(prog, typ)
1603
- }
1604
-
1605
1527
  func nestiaSDKMethodReturnTypeNode(prog *driver.Program, method *shimast.Node) *shimast.Node {
1606
1528
  if method != nil && method.FunctionLikeData() != nil {
1607
1529
  if typeNode := method.FunctionLikeData().Type; typeNode != nil {
@@ -1624,18 +1546,6 @@ func nestiaSDKReturnTypeNode(prog *driver.Program, node *shimast.Node) *shimast.
1624
1546
  func nestiaSDKEntityNameText(node *shimast.Node) string {
1625
1547
  return nestiaSDKTypeNodeText(node)
1626
1548
  }
1627
-
1628
- func nestiaSDKReturnTypeNodeText(prog *driver.Program, node *shimast.Node) string {
1629
- text := nestiaSDKTypeNodeText(node)
1630
- if node != nil && node.Kind == shimast.KindTypeReference {
1631
- ref := node.AsTypeReferenceNode()
1632
- if ref != nil && ref.TypeArguments != nil && len(ref.TypeArguments.Nodes) == 1 && nestiaSDKIsAsyncReturnWrapper(prog, ref.TypeName, nestiaSDKEntityNameText(ref.TypeName)) {
1633
- return nestiaSDKTypeNodeText(ref.TypeArguments.Nodes[0])
1634
- }
1635
- }
1636
- return text
1637
- }
1638
-
1639
1549
  func nestiaSDKIsAsyncReturnWrapper(
1640
1550
  prog *driver.Program,
1641
1551
  node *shimast.Node,
@@ -1722,145 +1632,11 @@ func nestiaSDKTypeNodeText(node *shimast.Node) string {
1722
1632
  return strings.TrimSpace(source[start:end])
1723
1633
  }
1724
1634
 
1725
- func nestiaSDKTypeNameFromChecker(prog *driver.Program, typ *shimchecker.Type) string {
1726
- if prog != nil && prog.Checker != nil && typ != nil {
1727
- return prog.Checker.TypeToString(typ)
1728
- }
1729
- return "any"
1730
- }
1731
-
1732
- func insertSDKOperationMetadataDecorators(text string, sites []nestiaSDKSite) string {
1733
- if len(sites) == 0 {
1734
- return text
1735
- }
1736
- cursor := 0
1737
- out := text
1738
- for _, site := range sites {
1739
- next, ok := insertSDKOperationMetadataDecorator(out, site, cursor)
1740
- if ok {
1741
- out = next.text
1742
- cursor = next.cursor
1743
- continue
1744
- }
1745
- next, ok = insertSDKOperationMetadataDecorator(out, site, 0)
1746
- if ok {
1747
- out = next.text
1748
- cursor = next.cursor
1749
- }
1750
- }
1751
- return out
1752
- }
1753
-
1754
1635
  type sdkOperationMetadataInsertResult struct {
1755
1636
  text string
1756
1637
  cursor int
1757
1638
  }
1758
1639
 
1759
- func insertSDKOperationMetadataDecorator(text string, site nestiaSDKSite, offset int) (sdkOperationMetadataInsertResult, bool) {
1760
- if offset < 0 || offset > len(text) {
1761
- offset = 0
1762
- }
1763
- needle := "], " + site.ClassName + ".prototype, \"" + site.MethodName + "\","
1764
- relative := strings.Index(text[offset:], needle)
1765
- idx := -1
1766
- if relative >= 0 {
1767
- idx = offset + relative
1768
- }
1769
- if idx < 0 {
1770
- return sdkOperationMetadataInsertResult{text: text, cursor: offset}, false
1771
- }
1772
- head := strings.LastIndex(text[:idx], "__decorate([")
1773
- if head < 0 {
1774
- return sdkOperationMetadataInsertResult{text: text, cursor: offset}, false
1775
- }
1776
- if strings.Contains(text[head:idx], "__OperationMetadata.OperationMetadata") {
1777
- return sdkOperationMetadataInsertResult{
1778
- text: text,
1779
- cursor: idx + len(needle),
1780
- }, true
1781
- }
1782
- insert := head + len("__decorate([")
1783
- decorator := "\n __OperationMetadata.OperationMetadata(" + site.Metadata + "),"
1784
- next := text[:insert] + decorator + text[insert:]
1785
- return sdkOperationMetadataInsertResult{
1786
- text: next,
1787
- cursor: idx + len(decorator) + len(needle),
1788
- }, true
1789
- }
1790
-
1791
- func injectSDKOperationMetadataImport(text string) string {
1792
- if strings.Contains(text, "__OperationMetadata.OperationMetadata") == false ||
1793
- strings.Contains(text, "const __OperationMetadata = require(\"@nestia/sdk\")") ||
1794
- strings.Contains(text, "__OperationMetadata = __importStar(require(\"@nestia/sdk\"))") ||
1795
- strings.Contains(text, "import * as __OperationMetadata from \"@nestia/sdk\"") {
1796
- return text
1797
- }
1798
- esModule := sdkIsESModuleOutput(text)
1799
- var stmt string
1800
- if esModule {
1801
- stmt = "import * as __OperationMetadata from \"@nestia/sdk\";\n"
1802
- } else {
1803
- stmt = "const __OperationMetadata = require(\"@nestia/sdk\");\n"
1804
- }
1805
- index := sdkRuntimeImportInsertionIndex(text, esModule)
1806
- return text[:index] + stmt + text[index:]
1807
- }
1808
-
1809
- func sdkIsESModuleOutput(text string) bool {
1810
- return regexp.MustCompile(`(?m)^(import\s|import\{|import\*|export\s)`).MatchString(text)
1811
- }
1812
-
1813
- func sdkRuntimeImportInsertionIndex(text string, esModule bool) int {
1814
- index := 0
1815
- if strings.HasPrefix(text, "#!") {
1816
- if next := strings.IndexByte(text, '\n'); next >= 0 {
1817
- index = next + 1
1818
- } else {
1819
- return len(text)
1820
- }
1821
- }
1822
- if esModule {
1823
- return index
1824
- }
1825
- for {
1826
- next := sdkConsumeRuntimeImportPrefix(text[index:])
1827
- if next == 0 {
1828
- return index
1829
- }
1830
- index += next
1831
- }
1832
- }
1833
-
1834
- func sdkConsumeRuntimeImportPrefix(text string) int {
1835
- for _, prefix := range []string{
1836
- "\"use strict\";\n",
1837
- "'use strict';\n",
1838
- "/* @ttsc-rewritten */\n",
1839
- } {
1840
- if strings.HasPrefix(text, prefix) {
1841
- return len(prefix)
1842
- }
1843
- }
1844
- return 0
1845
- }
1846
-
1847
- func sourceLineIndent(source string, pos int) string {
1848
- if pos < 0 || pos > len(source) {
1849
- return ""
1850
- }
1851
- start := strings.LastIndex(source[:pos], "\n")
1852
- if start < 0 {
1853
- start = 0
1854
- } else {
1855
- start++
1856
- }
1857
- end := start
1858
- for end < len(source) && (source[end] == ' ' || source[end] == '\t') {
1859
- end++
1860
- }
1861
- return source[start:end]
1862
- }
1863
-
1864
1640
  func nestiaSDKDiagnostic(site nestiaSDKSite, message string) transform.Diagnostic {
1865
1641
  line, column := 0, 0
1866
1642
  if site.File != nil && site.Method != nil {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nestia/sdk",
3
- "version": "12.0.0",
3
+ "version": "12.1.0",
4
4
  "description": "Nestia SDK and Swagger generator",
5
5
  "main": "lib/index.js",
6
6
  "bin": {
@@ -45,22 +45,22 @@
45
45
  },
46
46
  "homepage": "https://nestia.io",
47
47
  "dependencies": {
48
- "@ttsc/factory": "^0.18.4",
49
- "@typia/interface": "^13.0.2",
50
- "@typia/utils": "^13.0.2",
48
+ "@ttsc/factory": "^0.20.0",
49
+ "@typia/interface": "^13.2.0",
50
+ "@typia/utils": "^13.2.0",
51
51
  "get-function-location": "^2.0.0",
52
52
  "glob": "^11.0.3",
53
53
  "path-to-regexp": "^6.2.1",
54
54
  "prettier": "^3.8.1",
55
55
  "tgrid": "^1.2.1",
56
- "ttsc": "^0.18.4",
56
+ "ttsc": "^0.20.0",
57
57
  "tstl": "^3.0.0",
58
- "typia": "^13.0.2",
59
- "@nestia/core": "^12.0.0",
60
- "@nestia/fetcher": "^12.0.0"
58
+ "typia": "^13.2.0",
59
+ "@nestia/core": "^12.1.0",
60
+ "@nestia/fetcher": "^12.1.0"
61
61
  },
62
62
  "peerDependencies": {
63
- "@nestia/core": "^12.0.0"
63
+ "@nestia/core": "^12.1.0"
64
64
  },
65
65
  "devDependencies": {
66
66
  "@modelcontextprotocol/sdk": "^1.18.0",
@@ -101,6 +101,8 @@ export namespace NestiaSwaggerComposer {
101
101
  }),
102
102
  );
103
103
  }
104
+ if (project.errors.length)
105
+ throw report({ type: "error", errors: project.errors });
104
106
  AccessorAnalyzer.analyze(routes);
105
107
  return routes;
106
108
  };
@@ -4,11 +4,12 @@ import { MapUtil } from "../utils/MapUtil";
4
4
  export namespace ImportAnalyzer {
5
5
  /**
6
6
  * @deprecated Removed in the Go-migration cycle. Import metadata is now
7
- * attached by the native transformer in `packages/core/native/cmd/ttsc-nestia`
8
- * and consumed via `IOperationMetadata.imports`. Call sites that previously
9
- * walked a `ts.SourceFile` to derive imports should read the metadata
10
- * delivered through `Reflect.getMetadata("nestia/OperationMetadata", …)`
11
- * instead. See `packages/core/MIGRATION.md`.
7
+ * attached by the native transformer in
8
+ * `packages/core/native/cmd/ttsc-nestia` and consumed via
9
+ * `IOperationMetadata.imports`. Call sites that previously walked a
10
+ * `ts.SourceFile` to derive imports should read the metadata delivered
11
+ * through `Reflect.getMetadata("nestia/OperationMetadata", …)` instead. See
12
+ * `packages/core/MIGRATION.md`.
12
13
  */
13
14
  export const analyze = (): never => {
14
15
  throw new Error(
@@ -72,21 +73,29 @@ export namespace ImportAnalyzer {
72
73
  asterisk: null,
73
74
  }) satisfies IReflectImport,
74
75
  );
75
- const instances: Set<string> = new Set(
76
- imports.map((imp) => imp.elements).flat(),
77
- );
76
+ const instances: Map<string, string> = new Map();
77
+ for (const imp of imports)
78
+ for (const local of imp.elements)
79
+ instances.set(local, imp.elementAliases?.[local] ?? local);
78
80
  if (instances.size !== 0) {
79
- if (defaultImports.length !== 0)
80
- defaultImports[0]!.elements = Array.from(instances).sort();
81
- else
82
- defaultImports.push({
81
+ const elements = Array.from(instances.keys()).sort();
82
+ const elementAliases: Record<string, string> = {};
83
+ for (const local of elements) {
84
+ const imported = instances.get(local)!;
85
+ if (imported !== local) elementAliases[local] = imported;
86
+ }
87
+ const target: IReflectImport =
88
+ defaultImports[0] ?? {
83
89
  file,
84
- elements: Array.from(instances).sort(),
90
+ elements: [],
85
91
  default: null,
86
92
  asterisk: null,
87
- });
93
+ };
94
+ target.elements = elements;
95
+ if (Object.keys(elementAliases).length !== 0)
96
+ target.elementAliases = elementAliases;
97
+ if (defaultImports.length === 0) defaultImports.push(target);
88
98
  }
89
99
  return [...allStarImports, ...defaultImports];
90
100
  }
91
-
92
101
  }