@nestia/core 12.0.0-dev.20260601.1 → 12.0.0-dev.20260612.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/LICENSE +21 -21
  2. package/MIGRATION.md +169 -169
  3. package/README.md +93 -93
  4. package/lib/adaptors/McpAdaptor.d.ts +75 -0
  5. package/lib/adaptors/McpAdaptor.js +257 -0
  6. package/lib/adaptors/McpAdaptor.js.map +1 -0
  7. package/lib/adaptors/WebSocketAdaptor.js +4 -4
  8. package/lib/adaptors/WebSocketAdaptor.js.map +1 -1
  9. package/lib/decorators/McpRoute.d.ts +69 -0
  10. package/lib/decorators/McpRoute.js +58 -0
  11. package/lib/decorators/McpRoute.js.map +1 -0
  12. package/lib/decorators/TypedParam.js +4 -4
  13. package/lib/decorators/TypedParam.js.map +1 -1
  14. package/lib/decorators/TypedRoute.js +1 -1
  15. package/lib/decorators/TypedRoute.js.map +1 -1
  16. package/lib/decorators/internal/IMcpRouteReflect.d.ts +2 -0
  17. package/lib/decorators/internal/IMcpRouteReflect.js +3 -0
  18. package/lib/decorators/internal/IMcpRouteReflect.js.map +1 -0
  19. package/lib/decorators/internal/get_path_and_querify.js +4 -4
  20. package/lib/decorators/internal/get_path_and_querify.js.map +1 -1
  21. package/lib/decorators/internal/get_path_and_stringify.js +4 -4
  22. package/lib/decorators/internal/get_path_and_stringify.js.map +1 -1
  23. package/lib/decorators/internal/load_controller.js +34 -65
  24. package/lib/decorators/internal/load_controller.js.map +1 -1
  25. package/lib/decorators/internal/validate_request_body.js +4 -4
  26. package/lib/decorators/internal/validate_request_body.js.map +1 -1
  27. package/lib/decorators/internal/validate_request_form_data.js +4 -4
  28. package/lib/decorators/internal/validate_request_form_data.js.map +1 -1
  29. package/lib/decorators/internal/validate_request_headers.js +4 -4
  30. package/lib/decorators/internal/validate_request_headers.js.map +1 -1
  31. package/lib/decorators/internal/validate_request_query.js +4 -4
  32. package/lib/decorators/internal/validate_request_query.js.map +1 -1
  33. package/lib/module.d.ts +2 -0
  34. package/lib/module.js +2 -0
  35. package/lib/module.js.map +1 -1
  36. package/native/cmd/ttsc-nestia/main.go +11 -11
  37. package/native/go.mod +32 -32
  38. package/native/go.sum +54 -54
  39. package/native/plugin/plan.go +102 -102
  40. package/native/transform/ast.go +32 -32
  41. package/native/transform/build.go +380 -444
  42. package/native/transform/cleanup.go +408 -408
  43. package/native/transform/contributor.go +97 -68
  44. package/native/transform/core_querify.go +231 -227
  45. package/native/transform/core_transform.go +1996 -1713
  46. package/native/transform/core_websocket.go +115 -115
  47. package/native/transform/exports.go +13 -13
  48. package/native/transform/mcp_transform.go +414 -0
  49. package/native/transform/node_transform.go +357 -0
  50. package/native/transform/path_rewrite.go +285 -285
  51. package/native/transform/printer.go +244 -244
  52. package/native/transform/rewrite.go +668 -662
  53. package/native/transform/run.go +73 -73
  54. package/native/transform/transform.go +336 -403
  55. package/native/transform/typia_fast.go +352 -326
  56. package/native/transform/typia_replacement.go +24 -24
  57. package/native/transform.cjs +43 -43
  58. package/package.json +15 -8
  59. package/src/adaptors/McpAdaptor.ts +276 -0
  60. package/src/adaptors/WebSocketAdaptor.ts +429 -429
  61. package/src/decorators/DynamicModule.ts +44 -44
  62. package/src/decorators/EncryptedBody.ts +97 -97
  63. package/src/decorators/EncryptedController.ts +40 -40
  64. package/src/decorators/EncryptedModule.ts +98 -98
  65. package/src/decorators/EncryptedRoute.ts +213 -213
  66. package/src/decorators/HumanRoute.ts +21 -21
  67. package/src/decorators/McpRoute.ts +154 -0
  68. package/src/decorators/NoTransformConfigurationError.ts +40 -40
  69. package/src/decorators/PlainBody.ts +76 -76
  70. package/src/decorators/SwaggerCustomizer.ts +97 -97
  71. package/src/decorators/SwaggerExample.ts +180 -180
  72. package/src/decorators/TypedBody.ts +57 -57
  73. package/src/decorators/TypedException.ts +147 -147
  74. package/src/decorators/TypedFormData.ts +187 -187
  75. package/src/decorators/TypedHeaders.ts +66 -66
  76. package/src/decorators/TypedParam.ts +77 -77
  77. package/src/decorators/TypedQuery.ts +234 -234
  78. package/src/decorators/TypedRoute.ts +198 -196
  79. package/src/decorators/WebSocketRoute.ts +242 -242
  80. package/src/decorators/doNotThrowTransformError.ts +5 -5
  81. package/src/decorators/internal/EncryptedConstant.ts +2 -2
  82. package/src/decorators/internal/IMcpRouteReflect.ts +40 -0
  83. package/src/decorators/internal/IWebSocketRouteReflect.ts +23 -23
  84. package/src/decorators/internal/get_path_and_querify.ts +94 -94
  85. package/src/decorators/internal/get_path_and_stringify.ts +110 -110
  86. package/src/decorators/internal/get_text_body.ts +16 -16
  87. package/src/decorators/internal/headers_to_object.ts +11 -11
  88. package/src/decorators/internal/is_request_body_undefined.ts +12 -12
  89. package/src/decorators/internal/load_controller.ts +91 -76
  90. package/src/decorators/internal/route_error.ts +43 -43
  91. package/src/decorators/internal/validate_request_body.ts +64 -64
  92. package/src/decorators/internal/validate_request_form_data.ts +67 -67
  93. package/src/decorators/internal/validate_request_headers.ts +76 -76
  94. package/src/decorators/internal/validate_request_query.ts +83 -83
  95. package/src/index.ts +5 -5
  96. package/src/module.ts +25 -23
  97. package/src/options/IRequestBodyValidator.ts +20 -20
  98. package/src/options/IRequestFormDataProps.ts +27 -27
  99. package/src/options/IRequestHeadersValidator.ts +22 -22
  100. package/src/options/IRequestQueryValidator.ts +20 -20
  101. package/src/options/IResponseBodyQuerifier.ts +25 -25
  102. package/src/options/IResponseBodyStringifier.ts +30 -30
  103. package/src/transform.ts +101 -101
  104. package/src/typings/Creator.ts +3 -3
  105. package/src/typings/get-function-location.d.ts +7 -7
  106. package/src/utils/ArrayUtil.ts +7 -7
  107. package/src/utils/ExceptionManager.ts +115 -115
  108. package/src/utils/Singleton.ts +16 -16
  109. package/src/utils/SourceFinder.ts +54 -54
  110. package/src/utils/VersioningStrategy.ts +27 -27
  111. package/native/transform/cleanup_test.go +0 -76
  112. package/native/transform/commonjs_import_alias_test.go +0 -49
  113. package/native/transform/core_dispatch_test.go +0 -127
  114. package/native/transform/path_rewrite_test.go +0 -243
  115. package/native/transform/rewrite_test.go +0 -118
  116. package/native/transform/rewrite_unique_base_test.go +0 -48
@@ -1,285 +1,285 @@
1
- package transform
2
-
3
- import (
4
- "path/filepath"
5
- "sort"
6
- "strings"
7
-
8
- shimast "github.com/microsoft/typescript-go/shim/ast"
9
- shimcore "github.com/microsoft/typescript-go/shim/core"
10
- "github.com/samchon/ttsc/packages/ttsc/driver"
11
- )
12
-
13
- type pathsRewriter struct {
14
- basePath string
15
- outDir string
16
- patterns []pathsPattern
17
- rootDir string
18
- sourceFiles map[string]string
19
- }
20
-
21
- type pathsPattern struct {
22
- pattern string
23
- targets []string
24
- }
25
-
26
- func newPathsRewriter(prog *driver.Program) *pathsRewriter {
27
- out := &pathsRewriter{sourceFiles: map[string]string{}}
28
- if prog == nil || prog.ParsedConfig == nil || prog.ParsedConfig.ParsedConfig == nil || prog.ParsedConfig.ParsedConfig.CompilerOptions == nil {
29
- return out
30
- }
31
- options := prog.ParsedConfig.ParsedConfig.CompilerOptions
32
- out.basePath = filepath.Clean(options.GetPathsBasePath(prog.Host.GetCurrentDirectory()))
33
- out.outDir = optionalPath(options.OutDir, prog.Host.GetCurrentDirectory())
34
- out.rootDir = optionalPath(options.RootDir, prog.Host.GetCurrentDirectory())
35
- files := prog.SourceFiles()
36
- if out.rootDir == "" {
37
- out.rootDir = commonSourceDir(files)
38
- }
39
- for _, file := range files {
40
- name := normalizePath(file.FileName())
41
- out.sourceFiles[name] = name
42
- out.sourceFiles[stripKnownSourceExtension(name)] = name
43
- }
44
- if options.Paths != nil {
45
- for pattern, targets := range options.Paths.Entries() {
46
- out.patterns = append(out.patterns, pathsPattern{
47
- pattern: pattern,
48
- targets: append([]string(nil), targets...),
49
- })
50
- }
51
- }
52
- sort.SliceStable(out.patterns, func(i, j int) bool {
53
- return patternRank(out.patterns[i].pattern) > patternRank(out.patterns[j].pattern)
54
- })
55
- return out
56
- }
57
-
58
- func (r *pathsRewriter) applyAll(files []*shimast.SourceFile) {
59
- if r == nil || len(r.patterns) == 0 {
60
- return
61
- }
62
- for _, file := range files {
63
- r.apply(file)
64
- }
65
- }
66
-
67
- func (r *pathsRewriter) apply(file *shimast.SourceFile) {
68
- if r == nil || file == nil || len(r.patterns) == 0 {
69
- return
70
- }
71
- visitModuleSpecifiers(file.AsNode(), func(lit *shimast.Node) {
72
- if lit == nil || lit.Kind != shimast.KindStringLiteral {
73
- return
74
- }
75
- spec := lit.Text()
76
- rewritten, ok := r.rewrite(file.FileName(), spec)
77
- if ok && rewritten != spec {
78
- lit.AsStringLiteral().Text = rewritten
79
- lit.Flags |= shimast.NodeFlagsSynthesized
80
- lit.Loc = shimcore.UndefinedTextRange()
81
- }
82
- })
83
- }
84
-
85
- func visitModuleSpecifiers(node *shimast.Node, visit func(*shimast.Node)) {
86
- if node == nil {
87
- return
88
- }
89
- switch node.Kind {
90
- case shimast.KindImportDeclaration:
91
- visit(node.AsImportDeclaration().ModuleSpecifier)
92
- case shimast.KindExportDeclaration:
93
- visit(node.AsExportDeclaration().ModuleSpecifier)
94
- case shimast.KindImportEqualsDeclaration:
95
- ref := node.AsImportEqualsDeclaration().ModuleReference
96
- if ref != nil && ref.Kind == shimast.KindExternalModuleReference {
97
- visit(ref.AsExternalModuleReference().Expression)
98
- }
99
- case shimast.KindImportType:
100
- arg := node.AsImportTypeNode().Argument
101
- if arg != nil && arg.Kind == shimast.KindLiteralType {
102
- visit(arg.AsLiteralTypeNode().Literal)
103
- }
104
- case shimast.KindModuleDeclaration:
105
- decl := node.AsModuleDeclaration()
106
- if decl != nil {
107
- visit(decl.Name())
108
- }
109
- case shimast.KindCallExpression:
110
- call := node.AsCallExpression()
111
- if isModuleSpecifierCall(call) && call.Arguments != nil && len(call.Arguments.Nodes) > 0 {
112
- visit(call.Arguments.Nodes[0])
113
- }
114
- }
115
- node.ForEachChild(func(child *shimast.Node) bool {
116
- visitModuleSpecifiers(child, visit)
117
- return false
118
- })
119
- }
120
-
121
- func isModuleSpecifierCall(call *shimast.CallExpression) bool {
122
- if call == nil || call.Expression == nil {
123
- return false
124
- }
125
- switch call.Expression.Kind {
126
- case shimast.KindImportKeyword:
127
- return true
128
- case shimast.KindIdentifier:
129
- return call.Expression.Text() == "require"
130
- default:
131
- return false
132
- }
133
- }
134
-
135
- func (r *pathsRewriter) rewrite(fromSource string, specifier string) (string, bool) {
136
- if specifier == "" || strings.HasPrefix(specifier, ".") || strings.HasPrefix(specifier, "/") {
137
- return specifier, false
138
- }
139
- targetSource, ok := r.resolveSource(specifier)
140
- if !ok {
141
- return specifier, false
142
- }
143
- fromOut := r.outputPathForSource(fromSource)
144
- targetOut := r.outputPathForSource(targetSource)
145
- if fromOut == "" || targetOut == "" {
146
- return specifier, false
147
- }
148
- rel, err := filepath.Rel(filepath.Dir(fromOut), targetOut)
149
- if err != nil {
150
- return specifier, false
151
- }
152
- rel = filepath.ToSlash(rel)
153
- if !strings.HasPrefix(rel, ".") {
154
- rel = "./" + rel
155
- }
156
- return rel, true
157
- }
158
-
159
- func (r *pathsRewriter) resolveSource(specifier string) (string, bool) {
160
- for _, pattern := range r.patterns {
161
- star, ok := matchPattern(pattern.pattern, specifier)
162
- if !ok {
163
- continue
164
- }
165
- for _, target := range pattern.targets {
166
- candidate := strings.Replace(target, "*", star, 1)
167
- resolved := normalizePath(filepath.Join(r.basePath, candidate))
168
- if source, ok := r.lookupSource(resolved); ok {
169
- return source, true
170
- }
171
- }
172
- }
173
- return "", false
174
- }
175
-
176
- func (r *pathsRewriter) lookupSource(candidate string) (string, bool) {
177
- if source, ok := r.sourceFiles[normalizePath(candidate)]; ok {
178
- return source, true
179
- }
180
- stem := stripKnownSourceExtension(normalizePath(candidate))
181
- if source, ok := r.sourceFiles[stem]; ok {
182
- return source, true
183
- }
184
- for _, ext := range []string{".ts", ".tsx", ".mts", ".cts"} {
185
- if source, ok := r.sourceFiles[stem+ext]; ok {
186
- return source, true
187
- }
188
- }
189
- for _, ext := range []string{".ts", ".tsx", ".mts", ".cts"} {
190
- if source, ok := r.sourceFiles[normalizePath(filepath.Join(stem, "index"+ext))]; ok {
191
- return source, true
192
- }
193
- }
194
- return "", false
195
- }
196
-
197
- func (r *pathsRewriter) outputPathForSource(source string) string {
198
- if r.outDir == "" || r.rootDir == "" {
199
- return ""
200
- }
201
- rel, err := filepath.Rel(r.rootDir, source)
202
- if err != nil || isOutsideRelativePath(rel) {
203
- return ""
204
- }
205
- return normalizePath(filepath.Join(r.outDir, replaceSourceExtension(rel, emittedJavaScriptExtension(rel))))
206
- }
207
-
208
- func emittedJavaScriptExtension(source string) string {
209
- switch strings.ToLower(filepath.Ext(source)) {
210
- case ".mts":
211
- return ".mjs"
212
- case ".cts":
213
- return ".cjs"
214
- default:
215
- return ".js"
216
- }
217
- }
218
-
219
- func matchPattern(pattern string, specifier string) (string, bool) {
220
- if !strings.Contains(pattern, "*") {
221
- return "", pattern == specifier
222
- }
223
- parts := strings.SplitN(pattern, "*", 2)
224
- if !strings.HasPrefix(specifier, parts[0]) || !strings.HasSuffix(specifier, parts[1]) {
225
- return "", false
226
- }
227
- return specifier[len(parts[0]) : len(specifier)-len(parts[1])], true
228
- }
229
-
230
- func patternRank(pattern string) int {
231
- return len(strings.ReplaceAll(pattern, "*", ""))
232
- }
233
-
234
- func optionalPath(value string, cwd string) string {
235
- if value == "" {
236
- return ""
237
- }
238
- if filepath.IsAbs(value) {
239
- return normalizePath(value)
240
- }
241
- return normalizePath(filepath.Join(cwd, value))
242
- }
243
-
244
- func commonSourceDir(files []*shimast.SourceFile) string {
245
- if len(files) == 0 {
246
- return ""
247
- }
248
- common := normalizePath(filepath.Dir(files[0].FileName()))
249
- for _, file := range files[1:] {
250
- dir := normalizePath(filepath.Dir(file.FileName()))
251
- for common != "" && !strings.HasPrefix(dir+"/", common+"/") {
252
- next := filepath.Dir(common)
253
- if next == common {
254
- return common
255
- }
256
- common = normalizePath(next)
257
- }
258
- }
259
- return common
260
- }
261
-
262
- func normalizePath(value string) string {
263
- if value == "" {
264
- return ""
265
- }
266
- return filepath.ToSlash(filepath.Clean(value))
267
- }
268
-
269
- func isOutsideRelativePath(rel string) bool {
270
- return rel == ".." || strings.HasPrefix(filepath.ToSlash(rel), "../")
271
- }
272
-
273
- func stripKnownSourceExtension(value string) string {
274
- lower := strings.ToLower(value)
275
- for _, ext := range []string{".d.ts", ".d.mts", ".d.cts", ".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"} {
276
- if strings.HasSuffix(lower, ext) {
277
- return value[:len(value)-len(ext)]
278
- }
279
- }
280
- return strings.TrimSuffix(value, filepath.Ext(value))
281
- }
282
-
283
- func replaceSourceExtension(value string, ext string) string {
284
- return stripKnownSourceExtension(filepath.ToSlash(value)) + ext
285
- }
1
+ package transform
2
+
3
+ import (
4
+ "path/filepath"
5
+ "sort"
6
+ "strings"
7
+
8
+ shimast "github.com/microsoft/typescript-go/shim/ast"
9
+ shimcore "github.com/microsoft/typescript-go/shim/core"
10
+ "github.com/samchon/ttsc/packages/ttsc/driver"
11
+ )
12
+
13
+ type pathsRewriter struct {
14
+ basePath string
15
+ outDir string
16
+ patterns []pathsPattern
17
+ rootDir string
18
+ sourceFiles map[string]string
19
+ }
20
+
21
+ type pathsPattern struct {
22
+ pattern string
23
+ targets []string
24
+ }
25
+
26
+ func newPathsRewriter(prog *driver.Program) *pathsRewriter {
27
+ out := &pathsRewriter{sourceFiles: map[string]string{}}
28
+ if prog == nil || prog.ParsedConfig == nil || prog.ParsedConfig.ParsedConfig == nil || prog.ParsedConfig.ParsedConfig.CompilerOptions == nil {
29
+ return out
30
+ }
31
+ options := prog.ParsedConfig.ParsedConfig.CompilerOptions
32
+ out.basePath = filepath.Clean(options.GetPathsBasePath(prog.Host.GetCurrentDirectory()))
33
+ out.outDir = optionalPath(options.OutDir, prog.Host.GetCurrentDirectory())
34
+ out.rootDir = optionalPath(options.RootDir, prog.Host.GetCurrentDirectory())
35
+ files := prog.SourceFiles()
36
+ if out.rootDir == "" {
37
+ out.rootDir = commonSourceDir(files)
38
+ }
39
+ for _, file := range files {
40
+ name := normalizePath(file.FileName())
41
+ out.sourceFiles[name] = name
42
+ out.sourceFiles[stripKnownSourceExtension(name)] = name
43
+ }
44
+ if options.Paths != nil {
45
+ for pattern, targets := range options.Paths.Entries() {
46
+ out.patterns = append(out.patterns, pathsPattern{
47
+ pattern: pattern,
48
+ targets: append([]string(nil), targets...),
49
+ })
50
+ }
51
+ }
52
+ sort.SliceStable(out.patterns, func(i, j int) bool {
53
+ return patternRank(out.patterns[i].pattern) > patternRank(out.patterns[j].pattern)
54
+ })
55
+ return out
56
+ }
57
+
58
+ func (r *pathsRewriter) applyAll(files []*shimast.SourceFile) {
59
+ if r == nil || len(r.patterns) == 0 {
60
+ return
61
+ }
62
+ for _, file := range files {
63
+ r.apply(file)
64
+ }
65
+ }
66
+
67
+ func (r *pathsRewriter) apply(file *shimast.SourceFile) {
68
+ if r == nil || file == nil || len(r.patterns) == 0 {
69
+ return
70
+ }
71
+ visitModuleSpecifiers(file.AsNode(), func(lit *shimast.Node) {
72
+ if lit == nil || lit.Kind != shimast.KindStringLiteral {
73
+ return
74
+ }
75
+ spec := lit.Text()
76
+ rewritten, ok := r.rewrite(file.FileName(), spec)
77
+ if ok && rewritten != spec {
78
+ lit.AsStringLiteral().Text = rewritten
79
+ lit.Flags |= shimast.NodeFlagsSynthesized
80
+ lit.Loc = shimcore.UndefinedTextRange()
81
+ }
82
+ })
83
+ }
84
+
85
+ func visitModuleSpecifiers(node *shimast.Node, visit func(*shimast.Node)) {
86
+ if node == nil {
87
+ return
88
+ }
89
+ switch node.Kind {
90
+ case shimast.KindImportDeclaration:
91
+ visit(node.AsImportDeclaration().ModuleSpecifier)
92
+ case shimast.KindExportDeclaration:
93
+ visit(node.AsExportDeclaration().ModuleSpecifier)
94
+ case shimast.KindImportEqualsDeclaration:
95
+ ref := node.AsImportEqualsDeclaration().ModuleReference
96
+ if ref != nil && ref.Kind == shimast.KindExternalModuleReference {
97
+ visit(ref.AsExternalModuleReference().Expression)
98
+ }
99
+ case shimast.KindImportType:
100
+ arg := node.AsImportTypeNode().Argument
101
+ if arg != nil && arg.Kind == shimast.KindLiteralType {
102
+ visit(arg.AsLiteralTypeNode().Literal)
103
+ }
104
+ case shimast.KindModuleDeclaration:
105
+ decl := node.AsModuleDeclaration()
106
+ if decl != nil {
107
+ visit(decl.Name())
108
+ }
109
+ case shimast.KindCallExpression:
110
+ call := node.AsCallExpression()
111
+ if isModuleSpecifierCall(call) && call.Arguments != nil && len(call.Arguments.Nodes) > 0 {
112
+ visit(call.Arguments.Nodes[0])
113
+ }
114
+ }
115
+ node.ForEachChild(func(child *shimast.Node) bool {
116
+ visitModuleSpecifiers(child, visit)
117
+ return false
118
+ })
119
+ }
120
+
121
+ func isModuleSpecifierCall(call *shimast.CallExpression) bool {
122
+ if call == nil || call.Expression == nil {
123
+ return false
124
+ }
125
+ switch call.Expression.Kind {
126
+ case shimast.KindImportKeyword:
127
+ return true
128
+ case shimast.KindIdentifier:
129
+ return call.Expression.Text() == "require"
130
+ default:
131
+ return false
132
+ }
133
+ }
134
+
135
+ func (r *pathsRewriter) rewrite(fromSource string, specifier string) (string, bool) {
136
+ if specifier == "" || strings.HasPrefix(specifier, ".") || strings.HasPrefix(specifier, "/") {
137
+ return specifier, false
138
+ }
139
+ targetSource, ok := r.resolveSource(specifier)
140
+ if !ok {
141
+ return specifier, false
142
+ }
143
+ fromOut := r.outputPathForSource(fromSource)
144
+ targetOut := r.outputPathForSource(targetSource)
145
+ if fromOut == "" || targetOut == "" {
146
+ return specifier, false
147
+ }
148
+ rel, err := filepath.Rel(filepath.Dir(fromOut), targetOut)
149
+ if err != nil {
150
+ return specifier, false
151
+ }
152
+ rel = filepath.ToSlash(rel)
153
+ if !strings.HasPrefix(rel, ".") {
154
+ rel = "./" + rel
155
+ }
156
+ return rel, true
157
+ }
158
+
159
+ func (r *pathsRewriter) resolveSource(specifier string) (string, bool) {
160
+ for _, pattern := range r.patterns {
161
+ star, ok := matchPattern(pattern.pattern, specifier)
162
+ if !ok {
163
+ continue
164
+ }
165
+ for _, target := range pattern.targets {
166
+ candidate := strings.Replace(target, "*", star, 1)
167
+ resolved := normalizePath(filepath.Join(r.basePath, candidate))
168
+ if source, ok := r.lookupSource(resolved); ok {
169
+ return source, true
170
+ }
171
+ }
172
+ }
173
+ return "", false
174
+ }
175
+
176
+ func (r *pathsRewriter) lookupSource(candidate string) (string, bool) {
177
+ if source, ok := r.sourceFiles[normalizePath(candidate)]; ok {
178
+ return source, true
179
+ }
180
+ stem := stripKnownSourceExtension(normalizePath(candidate))
181
+ if source, ok := r.sourceFiles[stem]; ok {
182
+ return source, true
183
+ }
184
+ for _, ext := range []string{".ts", ".tsx", ".mts", ".cts"} {
185
+ if source, ok := r.sourceFiles[stem+ext]; ok {
186
+ return source, true
187
+ }
188
+ }
189
+ for _, ext := range []string{".ts", ".tsx", ".mts", ".cts"} {
190
+ if source, ok := r.sourceFiles[normalizePath(filepath.Join(stem, "index"+ext))]; ok {
191
+ return source, true
192
+ }
193
+ }
194
+ return "", false
195
+ }
196
+
197
+ func (r *pathsRewriter) outputPathForSource(source string) string {
198
+ if r.outDir == "" || r.rootDir == "" {
199
+ return ""
200
+ }
201
+ rel, err := filepath.Rel(r.rootDir, source)
202
+ if err != nil || isOutsideRelativePath(rel) {
203
+ return ""
204
+ }
205
+ return normalizePath(filepath.Join(r.outDir, replaceSourceExtension(rel, emittedJavaScriptExtension(rel))))
206
+ }
207
+
208
+ func emittedJavaScriptExtension(source string) string {
209
+ switch strings.ToLower(filepath.Ext(source)) {
210
+ case ".mts":
211
+ return ".mjs"
212
+ case ".cts":
213
+ return ".cjs"
214
+ default:
215
+ return ".js"
216
+ }
217
+ }
218
+
219
+ func matchPattern(pattern string, specifier string) (string, bool) {
220
+ if !strings.Contains(pattern, "*") {
221
+ return "", pattern == specifier
222
+ }
223
+ parts := strings.SplitN(pattern, "*", 2)
224
+ if !strings.HasPrefix(specifier, parts[0]) || !strings.HasSuffix(specifier, parts[1]) {
225
+ return "", false
226
+ }
227
+ return specifier[len(parts[0]) : len(specifier)-len(parts[1])], true
228
+ }
229
+
230
+ func patternRank(pattern string) int {
231
+ return len(strings.ReplaceAll(pattern, "*", ""))
232
+ }
233
+
234
+ func optionalPath(value string, cwd string) string {
235
+ if value == "" {
236
+ return ""
237
+ }
238
+ if filepath.IsAbs(value) {
239
+ return normalizePath(value)
240
+ }
241
+ return normalizePath(filepath.Join(cwd, value))
242
+ }
243
+
244
+ func commonSourceDir(files []*shimast.SourceFile) string {
245
+ if len(files) == 0 {
246
+ return ""
247
+ }
248
+ common := normalizePath(filepath.Dir(files[0].FileName()))
249
+ for _, file := range files[1:] {
250
+ dir := normalizePath(filepath.Dir(file.FileName()))
251
+ for common != "" && !strings.HasPrefix(dir+"/", common+"/") {
252
+ next := filepath.Dir(common)
253
+ if next == common {
254
+ return common
255
+ }
256
+ common = normalizePath(next)
257
+ }
258
+ }
259
+ return common
260
+ }
261
+
262
+ func normalizePath(value string) string {
263
+ if value == "" {
264
+ return ""
265
+ }
266
+ return filepath.ToSlash(filepath.Clean(value))
267
+ }
268
+
269
+ func isOutsideRelativePath(rel string) bool {
270
+ return rel == ".." || strings.HasPrefix(filepath.ToSlash(rel), "../")
271
+ }
272
+
273
+ func stripKnownSourceExtension(value string) string {
274
+ lower := strings.ToLower(value)
275
+ for _, ext := range []string{".d.ts", ".d.mts", ".d.cts", ".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"} {
276
+ if strings.HasSuffix(lower, ext) {
277
+ return value[:len(value)-len(ext)]
278
+ }
279
+ }
280
+ return strings.TrimSuffix(value, filepath.Ext(value))
281
+ }
282
+
283
+ func replaceSourceExtension(value string, ext string) string {
284
+ return stripKnownSourceExtension(filepath.ToSlash(value)) + ext
285
+ }