@nestia/sdk 12.0.0 → 13.0.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 (103) 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 +7 -8
  28. package/lib/generates/SdkGenerator.js.map +1 -1
  29. package/lib/generates/SwaggerGenerator.js +8 -9
  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/SdkHttpCloneProgrammer.js +3 -3
  38. package/lib/generates/internal/SdkHttpCloneProgrammer.js.map +1 -1
  39. package/lib/generates/internal/SdkHttpCloneReferencer.js +14 -10
  40. package/lib/generates/internal/SdkHttpCloneReferencer.js.map +1 -1
  41. package/lib/generates/internal/SdkTypeProgrammer.js +16 -8
  42. package/lib/generates/internal/SdkTypeProgrammer.js.map +1 -1
  43. package/lib/generates/internal/SdkWebSocketCloneProgrammer.js +6 -3
  44. package/lib/generates/internal/SdkWebSocketCloneProgrammer.js.map +1 -1
  45. package/lib/generates/internal/SwaggerOperationComposer.d.ts +1 -1
  46. package/lib/generates/internal/SwaggerOperationComposer.js +35 -7
  47. package/lib/generates/internal/SwaggerOperationComposer.js.map +1 -1
  48. package/lib/generates/internal/SwaggerOperationResponseComposer.js +68 -26
  49. package/lib/generates/internal/SwaggerOperationResponseComposer.js.map +1 -1
  50. package/lib/internal/legacy.d.ts +44 -46
  51. package/lib/internal/legacy.js +35 -48
  52. package/lib/internal/legacy.js.map +1 -1
  53. package/lib/structures/IReflectHttpOperationException.d.ts +1 -1
  54. package/lib/structures/IReflectHttpOperationParameter.d.ts +1 -1
  55. package/lib/structures/IReflectImport.d.ts +2 -0
  56. package/lib/structures/ITypedHttpRouteParameter.d.ts +1 -1
  57. package/lib/utils/StringUtil.d.ts +32 -0
  58. package/lib/utils/StringUtil.js +40 -3
  59. package/lib/utils/StringUtil.js.map +1 -1
  60. package/lib/utils/TsConfigReader.js +3 -1
  61. package/lib/utils/TsConfigReader.js.map +1 -1
  62. package/lib/validators/HttpHeadersValidator.d.ts +3 -2
  63. package/lib/validators/HttpHeadersValidator.js +3 -2
  64. package/lib/validators/HttpHeadersValidator.js.map +1 -1
  65. package/lib/validators/HttpQueryValidator.d.ts +4 -4
  66. package/lib/validators/HttpQueryValidator.js +4 -4
  67. package/native/go.mod +1 -1
  68. package/native/go.sum +32 -32
  69. package/native/sdk/register.go +6 -35
  70. package/native/sdk/sdk_transform.go +80 -304
  71. package/package.json +9 -9
  72. package/src/NestiaSwaggerComposer.ts +2 -0
  73. package/src/analyses/ImportAnalyzer.ts +26 -18
  74. package/src/analyses/ReflectControllerAnalyzer.ts +19 -10
  75. package/src/analyses/ReflectHttpOperationAnalyzer.ts +5 -2
  76. package/src/analyses/ReflectHttpOperationExceptionAnalyzer.ts +2 -2
  77. package/src/analyses/ReflectHttpOperationParameterAnalyzer.ts +3 -3
  78. package/src/analyses/ReflectWebSocketOperationAnalyzer.ts +14 -7
  79. package/src/analyses/TypedHttpRouteAnalyzer.ts +74 -35
  80. package/src/executable/internal/NestiaSdkCommand.ts +8 -5
  81. package/src/generates/E2eGenerator.ts +1 -3
  82. package/src/generates/SdkGenerator.ts +7 -7
  83. package/src/generates/SwaggerGenerator.ts +15 -7
  84. package/src/generates/internal/ImportDictionary.ts +23 -11
  85. package/src/generates/internal/SdkDistributionComposer.ts +25 -23
  86. package/src/generates/internal/SdkFileProgrammer.ts +1 -3
  87. package/src/generates/internal/SdkHttpCloneProgrammer.ts +3 -3
  88. package/src/generates/internal/SdkHttpCloneReferencer.ts +16 -11
  89. package/src/generates/internal/SdkTypeProgrammer.ts +18 -10
  90. package/src/generates/internal/SdkWebSocketCloneProgrammer.ts +4 -3
  91. package/src/generates/internal/SwaggerOperationComposer.ts +40 -8
  92. package/src/generates/internal/SwaggerOperationResponseComposer.ts +72 -26
  93. package/src/internal/legacy.ts +83 -73
  94. package/src/structures/IReflectHttpOperationException.ts +1 -1
  95. package/src/structures/IReflectHttpOperationParameter.ts +1 -1
  96. package/src/structures/IReflectImport.ts +2 -0
  97. package/src/structures/ITypedApplication.ts +0 -1
  98. package/src/structures/ITypedHttpRouteException.ts +0 -1
  99. package/src/structures/ITypedHttpRouteParameter.ts +1 -1
  100. package/src/utils/StringUtil.ts +43 -3
  101. package/src/utils/TsConfigReader.ts +11 -3
  102. package/src/validators/HttpHeadersValidator.ts +3 -2
  103. package/src/validators/HttpQueryValidator.ts +4 -4
@@ -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": "13.0.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.28.1",
49
+ "@typia/interface": "^14.0.1",
50
+ "@typia/utils": "^14.0.1",
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.28.1",
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": "^14.0.1",
59
+ "@nestia/core": "^13.0.0",
60
+ "@nestia/fetcher": "^13.0.0"
61
61
  },
62
62
  "peerDependencies": {
63
- "@nestia/core": "^12.0.0"
63
+ "@nestia/core": "^13.0.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,28 @@ 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({
83
- file,
84
- elements: Array.from(instances).sort(),
85
- default: null,
86
- asterisk: null,
87
- });
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 = defaultImports[0] ?? {
88
+ file,
89
+ elements: [],
90
+ default: null,
91
+ asterisk: null,
92
+ };
93
+ target.elements = elements;
94
+ if (Object.keys(elementAliases).length !== 0)
95
+ target.elementAliases = elementAliases;
96
+ if (defaultImports.length === 0) defaultImports.push(target);
88
97
  }
89
98
  return [...allStarImports, ...defaultImports];
90
99
  }
91
-
92
100
  }
@@ -6,11 +6,11 @@ import {
6
6
 
7
7
  import { INestiaProject } from "../structures/INestiaProject";
8
8
  import { INestiaSdkInput } from "../structures/INestiaSdkInput";
9
+ import { IOperationMetadata } from "../structures/IOperationMetadata";
9
10
  import { IReflectController } from "../structures/IReflectController";
10
11
  import { IReflectHttpOperation } from "../structures/IReflectHttpOperation";
11
12
  import { IReflectMcpOperation } from "../structures/IReflectMcpOperation";
12
13
  import { IReflectWebSocketOperation } from "../structures/IReflectWebSocketOperation";
13
- import { IOperationMetadata } from "../structures/IOperationMetadata";
14
14
  import { ArrayUtil } from "../utils/ArrayUtil";
15
15
  import { ReflectHttpOperationAnalyzer } from "./ReflectHttpOperationAnalyzer";
16
16
  import { ReflectMcpOperationAnalyzer } from "./ReflectMcpOperationAnalyzer";
@@ -97,16 +97,25 @@ export namespace ReflectControllerAnalyzer {
97
97
  };
98
98
 
99
99
  function _Get_prototype_entries(creator: any): Array<[string, unknown]> {
100
- const keyList = Object.getOwnPropertyNames(creator.prototype);
101
- const entries: Array<[string, unknown]> = keyList.map((key) => [
102
- key,
103
- creator.prototype[key],
104
- ]);
100
+ const visited: Set<string> = new Set();
101
+ return iterate(creator);
105
102
 
106
- const parent = Object.getPrototypeOf(creator);
107
- if (parent.prototype !== undefined)
108
- entries.push(..._Get_prototype_entries(parent));
103
+ function iterate(target: any): Array<[string, unknown]> {
104
+ const keyList: string[] = Object.getOwnPropertyNames(
105
+ target.prototype,
106
+ ).filter((key) => {
107
+ if (visited.has(key)) return false;
108
+ visited.add(key);
109
+ return true;
110
+ });
111
+ const entries: Array<[string, unknown]> = keyList.map((key) => [
112
+ key,
113
+ target.prototype[key],
114
+ ]);
109
115
 
110
- return entries;
116
+ const parent: any = Object.getPrototypeOf(target);
117
+ if (parent.prototype !== undefined) entries.push(...iterate(parent));
118
+ return entries;
119
+ }
111
120
  }
112
121
  }
@@ -18,7 +18,8 @@ import { ReflectMetadataAnalyzer } from "./ReflectMetadataAnalyzer";
18
18
 
19
19
  export namespace ReflectHttpOperationAnalyzer {
20
20
  export interface IProps {
21
- project: Omit<INestiaProject, "config">;
21
+ project: Omit<INestiaProject, "config"> &
22
+ Partial<Pick<INestiaProject, "config">>;
22
23
  controller: IReflectController;
23
24
  function: Function;
24
25
  name: string;
@@ -107,7 +108,9 @@ export namespace ReflectHttpOperationAnalyzer {
107
108
  .filter((x) => parameters.some((y) => x.index === y.index))
108
109
  .map((x) => x.imports),
109
110
  ...(success.binary === true ? [] : props.metadata.success.imports),
110
- ...Object.values(props.metadata.exceptions).map((e) => e.imports),
111
+ ...(props.project.config?.propagate === true
112
+ ? Object.values(props.metadata.exceptions).map((e) => e.imports)
113
+ : []),
111
114
  ].flat(),
112
115
  ),
113
116
  description: props.metadata.description,