@nestia/core 12.0.0-dev.20260520.1 → 12.0.0-dev.20260521.1
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/transform.d.ts +8 -0
- package/lib/transform.js +28 -12
- package/lib/transform.js.map +1 -1
- package/native/cmd/ttsc-nestia/main.go +2 -63
- package/native/go.mod +1 -1
- package/native/transform/ast.go +32 -0
- package/native/{cmd/ttsc-nestia → transform}/build.go +14 -35
- package/native/{cmd/ttsc-nestia → transform}/cleanup.go +1 -1
- package/native/transform/cleanup_test.go +76 -0
- package/native/transform/commonjs_import_alias_test.go +49 -0
- package/native/transform/core_dispatch_test.go +127 -0
- package/native/{cmd/ttsc-nestia → transform}/core_querify.go +1 -1
- package/native/{cmd/ttsc-nestia → transform}/core_transform.go +26 -26
- package/native/{cmd/ttsc-nestia → transform}/core_websocket.go +10 -10
- package/native/transform/exports.go +13 -0
- package/native/{cmd/ttsc-nestia → transform}/path_rewrite.go +1 -1
- package/native/transform/path_rewrite_test.go +243 -0
- package/native/{cmd/ttsc-nestia → transform}/printer.go +1 -1
- package/native/{cmd/ttsc-nestia → transform}/rewrite.go +3 -3
- package/native/transform/rewrite_test.go +118 -0
- package/native/transform/rewrite_unique_base_test.go +48 -0
- package/native/transform/run.go +72 -0
- package/native/{cmd/ttsc-nestia → transform}/transform.go +25 -36
- package/native/{cmd/ttsc-nestia → transform}/typia_fast.go +1 -1
- package/native/{cmd/ttsc-nestia → transform}/typia_replacement.go +1 -1
- package/native/transform.cjs +34 -12
- package/package.json +8 -7
- package/src/transform.ts +39 -20
- package/native/cmd/ttsc-nestia/sdk_metadata_json.go +0 -327
- package/native/cmd/ttsc-nestia/sdk_transform.go +0 -1541
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
package transform
|
|
2
|
+
|
|
3
|
+
import "testing"
|
|
4
|
+
|
|
5
|
+
func TestNativeRewriteSetFindSourceByUniqueBase(t *testing.T) {
|
|
6
|
+
set := newNativeRewriteSet()
|
|
7
|
+
set.Add(nativeRewrite{
|
|
8
|
+
FilePath: "/repo/tests/test-transform-options/src/validate.ts",
|
|
9
|
+
Method: "TypedBody",
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
got, ok := set.findSourceForOutput(
|
|
13
|
+
"/repo/tests/test-transform-options/lib/validate-assert/validate.js",
|
|
14
|
+
)
|
|
15
|
+
if !ok {
|
|
16
|
+
t.Fatal("expected unique basename fallback to match source")
|
|
17
|
+
}
|
|
18
|
+
if got != "/repo/tests/test-transform-options/src/validate.ts" {
|
|
19
|
+
t.Fatalf("unexpected source match: %q", got)
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Verifies the unique-basename fallback does not match a sibling output that
|
|
24
|
+
// lives inside the same `src/` tree as the registered source.
|
|
25
|
+
//
|
|
26
|
+
// Regression: the fallback used to match any output sharing a basename with
|
|
27
|
+
// a registered source, so `src/index.ts` silently absorbed rewrites destined
|
|
28
|
+
// for every `src/.../index.ts` neighbor produced by ttsc's virtual fs. The
|
|
29
|
+
// symptom was `could not locate typia.*(...)` on unrelated generated files.
|
|
30
|
+
//
|
|
31
|
+
// 1. Register one rewrite for `/repo/tests/foo/src/index.ts`.
|
|
32
|
+
// 2. Ask findSourceForOutput for a sibling output inside the same src tree.
|
|
33
|
+
// 3. Expect no match.
|
|
34
|
+
func TestNativeRewriteSetFindSourceByUniqueBaseSkipsSourceTreeSiblings(t *testing.T) {
|
|
35
|
+
set := newNativeRewriteSet()
|
|
36
|
+
set.Add(nativeRewrite{
|
|
37
|
+
FilePath: "/repo/tests/foo/src/index.ts",
|
|
38
|
+
Method: "schemas",
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
// Output sits inside the same src/ tree, not in lib/dist/bin/build — it
|
|
42
|
+
// must not absorb the rewrite registered for src/index.ts.
|
|
43
|
+
if got, ok := set.findSourceForOutput(
|
|
44
|
+
"/cache/.ttsc/project/1/fs/posix/repo/tests/foo/src/api/functional/health/index.js",
|
|
45
|
+
); ok {
|
|
46
|
+
t.Fatalf("expected no match for source-tree sibling, got %q", got)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
package transform
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"fmt"
|
|
5
|
+
"io"
|
|
6
|
+
"os"
|
|
7
|
+
"runtime/debug"
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
var (
|
|
11
|
+
stdout io.Writer = os.Stdout
|
|
12
|
+
stderr io.Writer = os.Stderr
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
// Run wraps run() in a panic recovery envelope so that any unexpected
|
|
16
|
+
// panic surfaces as a one-line transform-diagnostic on stderr instead of
|
|
17
|
+
// a multi-line raw Go stack trace. The diagnostic uses the same `<file> -
|
|
18
|
+
// error TS(code): message` shape as every other nestia / typia diagnostic;
|
|
19
|
+
// ttsc reads it via `error.stderr` (`RuntimeCompiler.compile` at
|
|
20
|
+
// `ConfigAnalyzer.ts:170-174`) rather than its structured-diagnostic regex,
|
|
21
|
+
// which is a pre-existing protocol shared by all `nestia.*` codes. The
|
|
22
|
+
// full stack is preserved behind NESTIA_NATIVE_DEBUG_STACK for triage.
|
|
23
|
+
//
|
|
24
|
+
// This is the `@nestia/core` plugin entry point — it performs the typia
|
|
25
|
+
// and `@nestia/core` decorator transforms only. The `@nestia/sdk` metadata
|
|
26
|
+
// transform lives in its own plugin (`packages/sdk/native`).
|
|
27
|
+
func Run(args []string) (code int) {
|
|
28
|
+
defer func() {
|
|
29
|
+
if exp := recover(); exp != nil {
|
|
30
|
+
diag := Diagnostic{
|
|
31
|
+
Code: "nestia.internal.panic",
|
|
32
|
+
Message: fmt.Sprintf("ttsc-nestia panicked: %v", exp),
|
|
33
|
+
}
|
|
34
|
+
WriteTypiaTransformDiagnostics(stderr, []Diagnostic{diag}, "")
|
|
35
|
+
if os.Getenv("NESTIA_NATIVE_DEBUG_STACK") != "" {
|
|
36
|
+
fmt.Fprintln(stderr, string(debug.Stack()))
|
|
37
|
+
}
|
|
38
|
+
code = 3
|
|
39
|
+
}
|
|
40
|
+
}()
|
|
41
|
+
return run(args)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
func run(args []string) int {
|
|
45
|
+
if len(args) == 0 {
|
|
46
|
+
return runHelp(nil)
|
|
47
|
+
}
|
|
48
|
+
command := args[0]
|
|
49
|
+
rest := args[1:]
|
|
50
|
+
switch command {
|
|
51
|
+
case "build":
|
|
52
|
+
return runBuild(rest)
|
|
53
|
+
case "check":
|
|
54
|
+
return runCheck(rest)
|
|
55
|
+
case "transform":
|
|
56
|
+
return runTransform(rest)
|
|
57
|
+
case "version":
|
|
58
|
+
fmt.Fprintln(stdout, "ttsc-nestia 0.1.0")
|
|
59
|
+
return 0
|
|
60
|
+
case "help", "-h", "--help":
|
|
61
|
+
return runHelp(rest)
|
|
62
|
+
default:
|
|
63
|
+
fmt.Fprintf(stderr, "ttsc-nestia: unknown command %q\n", command)
|
|
64
|
+
return 2
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
func runHelp(args []string) int {
|
|
69
|
+
_ = args
|
|
70
|
+
fmt.Fprintln(stdout, "usage: ttsc-nestia <build|check|transform|version>")
|
|
71
|
+
return 0
|
|
72
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
package
|
|
1
|
+
package transform
|
|
2
2
|
|
|
3
3
|
import (
|
|
4
4
|
"bytes"
|
|
@@ -94,27 +94,21 @@ func runTransform(args []string) int {
|
|
|
94
94
|
readTypiaPluginOptions(cwd, *tsconfigPath),
|
|
95
95
|
)
|
|
96
96
|
if len(diagnostics) > 0 {
|
|
97
|
-
|
|
97
|
+
WriteTypiaTransformDiagnostics(stderr, diagnostics, cwd)
|
|
98
98
|
return 3
|
|
99
99
|
}
|
|
100
100
|
coreRewriteMap, coreDiagnostics := collectNestiaCoreSourceRewriteMap(prog, plan, absFile)
|
|
101
101
|
if len(coreDiagnostics) > 0 {
|
|
102
|
-
|
|
102
|
+
WriteTypiaTransformDiagnostics(stderr, coreDiagnostics, cwd)
|
|
103
103
|
return 3
|
|
104
104
|
}
|
|
105
105
|
rewrites = append(rewrites, coreRewriteMap[filepath.ToSlash(absFile)]...)
|
|
106
|
-
|
|
107
|
-
if len(sdkDiagnostics) > 0 {
|
|
108
|
-
writeTypiaTransformDiagnostics(stderr, sdkDiagnostics, cwd)
|
|
109
|
-
return 3
|
|
110
|
-
}
|
|
111
|
-
rewrites = append(rewrites, sdkRewriteMap[filepath.ToSlash(absFile)]...)
|
|
112
|
-
source, ok := sourceFileText(target)
|
|
106
|
+
source, ok := SourceFileText(target)
|
|
113
107
|
if !ok {
|
|
114
108
|
fmt.Fprintf(stderr, "ttsc-nestia transform: source text is unavailable for %s\n", absFile)
|
|
115
109
|
return 3
|
|
116
110
|
}
|
|
117
|
-
source, err =
|
|
111
|
+
source, err = ApplySourceRewrites(source, rewrites)
|
|
118
112
|
if err != nil {
|
|
119
113
|
fmt.Fprintf(stderr, "ttsc-nestia transform: source rewrite: %v\n", err)
|
|
120
114
|
return 3
|
|
@@ -150,11 +144,6 @@ func runTransformProject(prog *driver.Program, cwd string, tsconfigPath string,
|
|
|
150
144
|
rewrites[file] = append(rewrites[file], entries...)
|
|
151
145
|
}
|
|
152
146
|
diags = append(diags, coreDiags...)
|
|
153
|
-
sdkRewriteMap, sdkDiags := collectNestiaSDKSourceRewriteMap(prog, plan, "")
|
|
154
|
-
for file, entries := range sdkRewriteMap {
|
|
155
|
-
rewrites[file] = append(rewrites[file], entries...)
|
|
156
|
-
}
|
|
157
|
-
diags = append(diags, sdkDiags...)
|
|
158
147
|
output := transformProjectOutput{
|
|
159
148
|
Diagnostics: make([]transformCompilerDiagnostic, 0, len(diags)),
|
|
160
149
|
TypeScript: map[string]string{},
|
|
@@ -164,7 +153,7 @@ func runTransformProject(prog *driver.Program, cwd string, tsconfigPath string,
|
|
|
164
153
|
}
|
|
165
154
|
for _, file := range prog.SourceFiles() {
|
|
166
155
|
filename := filepath.ToSlash(file.FileName())
|
|
167
|
-
source, ok :=
|
|
156
|
+
source, ok := SourceFileText(file)
|
|
168
157
|
if !ok {
|
|
169
158
|
output.Diagnostics = append(
|
|
170
159
|
output.Diagnostics,
|
|
@@ -172,7 +161,7 @@ func runTransformProject(prog *driver.Program, cwd string, tsconfigPath string,
|
|
|
172
161
|
)
|
|
173
162
|
continue
|
|
174
163
|
}
|
|
175
|
-
transformed, err :=
|
|
164
|
+
transformed, err := ApplySourceRewrites(source, rewrites[filename])
|
|
176
165
|
if err != nil {
|
|
177
166
|
output.Diagnostics = append(
|
|
178
167
|
output.Diagnostics,
|
|
@@ -192,7 +181,7 @@ func runTransformProject(prog *driver.Program, cwd string, tsconfigPath string,
|
|
|
192
181
|
return 0
|
|
193
182
|
}
|
|
194
183
|
|
|
195
|
-
type
|
|
184
|
+
type SourceRewrite struct {
|
|
196
185
|
start int
|
|
197
186
|
end int
|
|
198
187
|
replacement string
|
|
@@ -203,30 +192,30 @@ func collectTypiaSourceRewrites(
|
|
|
203
192
|
cwd string,
|
|
204
193
|
onlyFile string,
|
|
205
194
|
pluginOptions typiaadapter.PluginOptions,
|
|
206
|
-
) ([]
|
|
195
|
+
) ([]SourceRewrite, []Diagnostic) {
|
|
207
196
|
sites := collectNestiaTypiaCallSites(prog.SourceFiles(), prog.Checker)
|
|
208
|
-
rewrites := []
|
|
209
|
-
diagnostics := []
|
|
197
|
+
rewrites := []SourceRewrite{}
|
|
198
|
+
diagnostics := []Diagnostic{}
|
|
210
199
|
for _, site := range sites {
|
|
211
200
|
if filepath.ToSlash(site.FilePath) != filepath.ToSlash(onlyFile) {
|
|
212
201
|
continue
|
|
213
202
|
}
|
|
214
203
|
if reason := typiaadapter.UnsupportedReason(site); reason != "" {
|
|
215
|
-
diagnostics = append(diagnostics,
|
|
204
|
+
diagnostics = append(diagnostics, NewDiagnostic(site, reason))
|
|
216
205
|
continue
|
|
217
206
|
}
|
|
218
207
|
expr, handled, err := typiaadapter.EmitCallWithOptionsPreservingTypes(prog, site, pluginOptions)
|
|
219
208
|
if !handled {
|
|
220
|
-
diagnostics = append(diagnostics,
|
|
209
|
+
diagnostics = append(diagnostics, NewDiagnostic(site, "method not covered"))
|
|
221
210
|
continue
|
|
222
211
|
}
|
|
223
212
|
if err != nil {
|
|
224
|
-
diagnostics = append(diagnostics,
|
|
213
|
+
diagnostics = append(diagnostics, NewDiagnostic(site, err.Error()))
|
|
225
214
|
continue
|
|
226
215
|
}
|
|
227
216
|
expr = parenthesizeTypiaReplacement(site, expr)
|
|
228
217
|
node := site.Call.AsNode()
|
|
229
|
-
rewrites = append(rewrites,
|
|
218
|
+
rewrites = append(rewrites, SourceRewrite{
|
|
230
219
|
start: node.Pos(),
|
|
231
220
|
end: node.End(),
|
|
232
221
|
replacement: expr,
|
|
@@ -239,28 +228,28 @@ func collectTypiaSourceRewrites(
|
|
|
239
228
|
func collectTypiaSourceRewriteMap(
|
|
240
229
|
prog *driver.Program,
|
|
241
230
|
pluginOptions typiaadapter.PluginOptions,
|
|
242
|
-
) (map[string][]
|
|
231
|
+
) (map[string][]SourceRewrite, []Diagnostic) {
|
|
243
232
|
sites := collectNestiaTypiaCallSites(prog.SourceFiles(), prog.Checker)
|
|
244
|
-
rewrites := map[string][]
|
|
245
|
-
diagnostics := []
|
|
233
|
+
rewrites := map[string][]SourceRewrite{}
|
|
234
|
+
diagnostics := []Diagnostic{}
|
|
246
235
|
for _, site := range sites {
|
|
247
236
|
file := filepath.ToSlash(site.FilePath)
|
|
248
237
|
if reason := typiaadapter.UnsupportedReason(site); reason != "" {
|
|
249
|
-
diagnostics = append(diagnostics,
|
|
238
|
+
diagnostics = append(diagnostics, NewDiagnostic(site, reason))
|
|
250
239
|
continue
|
|
251
240
|
}
|
|
252
241
|
expr, handled, err := typiaadapter.EmitCallWithOptionsPreservingTypes(prog, site, pluginOptions)
|
|
253
242
|
if !handled {
|
|
254
|
-
diagnostics = append(diagnostics,
|
|
243
|
+
diagnostics = append(diagnostics, NewDiagnostic(site, "method not covered"))
|
|
255
244
|
continue
|
|
256
245
|
}
|
|
257
246
|
if err != nil {
|
|
258
|
-
diagnostics = append(diagnostics,
|
|
247
|
+
diagnostics = append(diagnostics, NewDiagnostic(site, err.Error()))
|
|
259
248
|
continue
|
|
260
249
|
}
|
|
261
250
|
expr = parenthesizeTypiaReplacement(site, expr)
|
|
262
251
|
node := site.Call.AsNode()
|
|
263
|
-
rewrites[file] = append(rewrites[file],
|
|
252
|
+
rewrites[file] = append(rewrites[file], SourceRewrite{
|
|
264
253
|
start: node.Pos(),
|
|
265
254
|
end: node.End(),
|
|
266
255
|
replacement: expr,
|
|
@@ -269,7 +258,7 @@ func collectTypiaSourceRewriteMap(
|
|
|
269
258
|
return rewrites, diagnostics
|
|
270
259
|
}
|
|
271
260
|
|
|
272
|
-
func
|
|
261
|
+
func ApplySourceRewrites(source string, rewrites []SourceRewrite) (string, error) {
|
|
273
262
|
sort.SliceStable(rewrites, func(i, j int) bool {
|
|
274
263
|
return rewrites[i].start > rewrites[j].start
|
|
275
264
|
})
|
|
@@ -289,7 +278,7 @@ func applySourceRewrites(source string, rewrites []transformSourceRewrite) (stri
|
|
|
289
278
|
return output, nil
|
|
290
279
|
}
|
|
291
280
|
|
|
292
|
-
func
|
|
281
|
+
func SourceFileText(target any) (string, bool) {
|
|
293
282
|
type sourceText interface {
|
|
294
283
|
Text() string
|
|
295
284
|
}
|
|
@@ -369,7 +358,7 @@ func newTransformCompilerDiagnostic(
|
|
|
369
358
|
}
|
|
370
359
|
|
|
371
360
|
func transformDiagnosticToCompilerDiagnostic(
|
|
372
|
-
diag
|
|
361
|
+
diag Diagnostic,
|
|
373
362
|
) transformCompilerDiagnostic {
|
|
374
363
|
var ptr *string
|
|
375
364
|
if diag.File != "" {
|
package/native/transform.cjs
CHANGED
|
@@ -1,20 +1,42 @@
|
|
|
1
|
+
const fs = require("node:fs");
|
|
1
2
|
const path = require("node:path");
|
|
2
3
|
|
|
4
|
+
// `@nestia/core` ttsc plugin descriptor.
|
|
5
|
+
//
|
|
6
|
+
// `source` is the Go command package of the executable transform host
|
|
7
|
+
// (`cmd/ttsc-nestia`, package `main`).
|
|
8
|
+
//
|
|
9
|
+
// `@nestia/sdk` is NOT a standalone ttsc plugin: its Go transform is declared
|
|
10
|
+
// here as a `contributor`, discovered by resolving `@nestia/sdk` from the
|
|
11
|
+
// project. ttsc statically links a contributor's Go source into this host
|
|
12
|
+
// binary. Consequences:
|
|
13
|
+
//
|
|
14
|
+
// - A project that depends on `@nestia/core` but not `@nestia/sdk` never
|
|
15
|
+
// links, compiles, or ships any SDK transform code.
|
|
16
|
+
// - When the `@nestia/core` plugin itself is disabled, this descriptor is
|
|
17
|
+
// never evaluated, so the SDK contributor is never linked either.
|
|
3
18
|
function createTtscPlugin(context) {
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
typeof transform === "string" && transform.includes("@nestia/sdk")
|
|
7
|
-
? "@nestia/sdk"
|
|
8
|
-
: "@nestia/core";
|
|
9
|
-
const peer =
|
|
10
|
-
name === "@nestia/sdk"
|
|
11
|
-
? ["@nestia/core/lib/transform"]
|
|
12
|
-
: ["@nestia/sdk/lib/transform"];
|
|
13
|
-
return {
|
|
14
|
-
name,
|
|
19
|
+
const plugin = {
|
|
20
|
+
name: "@nestia/core",
|
|
15
21
|
source: path.resolve(__dirname, "cmd", "ttsc-nestia"),
|
|
16
|
-
composes: ["typia/lib/transform"
|
|
22
|
+
composes: ["typia/lib/transform"],
|
|
17
23
|
};
|
|
24
|
+
const sdk = resolveSdkContributorSource(context);
|
|
25
|
+
if (sdk !== null) plugin.contributors = [{ name: "sdk", source: sdk }];
|
|
26
|
+
return plugin;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function resolveSdkContributorSource(context) {
|
|
30
|
+
const paths = [__dirname];
|
|
31
|
+
if (context && typeof context.projectRoot === "string")
|
|
32
|
+
paths.push(context.projectRoot);
|
|
33
|
+
try {
|
|
34
|
+
const manifest = require.resolve("@nestia/sdk/package.json", { paths });
|
|
35
|
+
const source = path.resolve(path.dirname(manifest), "native", "sdk");
|
|
36
|
+
return fs.existsSync(source) ? source : null;
|
|
37
|
+
} catch {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
18
40
|
}
|
|
19
41
|
|
|
20
42
|
module.exports = createTtscPlugin;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nestia/core",
|
|
3
|
-
"version": "12.0.0-dev.
|
|
3
|
+
"version": "12.0.0-dev.20260521.1",
|
|
4
4
|
"description": "Super-fast validation decorators of NestJS",
|
|
5
5
|
"types": "lib/index.d.ts",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -46,8 +46,8 @@
|
|
|
46
46
|
},
|
|
47
47
|
"homepage": "https://nestia.io",
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@typia/interface": "13.0.0-dev.
|
|
50
|
-
"@typia/utils": "13.0.0-dev.
|
|
49
|
+
"@typia/interface": "13.0.0-dev.20260521.1",
|
|
50
|
+
"@typia/utils": "13.0.0-dev.20260521.1",
|
|
51
51
|
"get-function-location": "^2.0.0",
|
|
52
52
|
"glob": "^11.0.3",
|
|
53
53
|
"path-parser": "^6.1.0",
|
|
@@ -55,17 +55,17 @@
|
|
|
55
55
|
"reflect-metadata": ">=0.1.12",
|
|
56
56
|
"rxjs": ">=6.0.3",
|
|
57
57
|
"tgrid": "^1.1.0",
|
|
58
|
-
"typia": "13.0.0-dev.
|
|
58
|
+
"typia": "13.0.0-dev.20260521.1",
|
|
59
59
|
"ws": "^7.5.3",
|
|
60
|
-
"@nestia/fetcher": "^12.0.0-dev.
|
|
60
|
+
"@nestia/fetcher": "^12.0.0-dev.20260521.1"
|
|
61
61
|
},
|
|
62
62
|
"peerDependencies": {
|
|
63
63
|
"@nestjs/common": ">=7.0.1",
|
|
64
64
|
"@nestjs/core": ">=7.0.1",
|
|
65
65
|
"reflect-metadata": ">=0.1.12",
|
|
66
66
|
"rxjs": ">=6.0.3",
|
|
67
|
-
"typia": "13.0.0-dev.
|
|
68
|
-
"@nestia/fetcher": "^12.0.0-dev.
|
|
67
|
+
"typia": "13.0.0-dev.20260521.1",
|
|
68
|
+
"@nestia/fetcher": "^12.0.0-dev.20260521.1"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
71
|
"@nestjs/common": "^11.1.6",
|
|
@@ -90,6 +90,7 @@
|
|
|
90
90
|
"native/go.mod",
|
|
91
91
|
"native/go.sum",
|
|
92
92
|
"native/plugin",
|
|
93
|
+
"native/transform",
|
|
93
94
|
"native/transform.cjs",
|
|
94
95
|
"src"
|
|
95
96
|
],
|
package/src/transform.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
1
2
|
import path from "node:path";
|
|
2
3
|
import { fileURLToPath } from "node:url";
|
|
3
4
|
|
|
@@ -6,53 +7,71 @@ interface ITtscPluginFactoryContext {
|
|
|
6
7
|
projectRoot: string;
|
|
7
8
|
}
|
|
8
9
|
|
|
9
|
-
/**
|
|
10
|
-
* @internal
|
|
11
|
-
*
|
|
12
|
-
* The `composes` array order is load-bearing: `typia/lib/transform` first
|
|
13
|
-
* (host), then peers consumed by the Go binary's `plugin.ParsePlan`.
|
|
14
|
-
*/
|
|
10
|
+
/** @internal */
|
|
15
11
|
interface ITtscPlugin {
|
|
16
12
|
name: string;
|
|
17
13
|
source: string;
|
|
18
14
|
composes: string[];
|
|
15
|
+
contributors?: { name: string; source: string }[];
|
|
19
16
|
}
|
|
20
17
|
|
|
21
18
|
const filename: string = currentFilename();
|
|
22
19
|
const dirname: string = path.dirname(filename);
|
|
23
20
|
|
|
21
|
+
/**
|
|
22
|
+
* `@nestia/core` ttsc plugin descriptor.
|
|
23
|
+
*
|
|
24
|
+
* `@nestia/sdk` is not a standalone plugin: its Go transform is declared here
|
|
25
|
+
* as a `contributor` that ttsc statically links into this host binary, and
|
|
26
|
+
* only when `@nestia/sdk` is actually resolvable from the project. A project
|
|
27
|
+
* depending on `@nestia/core` alone never compiles any SDK transform code.
|
|
28
|
+
*/
|
|
24
29
|
export function createTtscPlugin(
|
|
25
30
|
context: ITtscPluginFactoryContext,
|
|
26
31
|
): ITtscPlugin {
|
|
27
|
-
const
|
|
28
|
-
resolvePackageRoot("@nestia/core/package.json", context.projectRoot) ??
|
|
29
|
-
inferPackageRoot();
|
|
30
|
-
return {
|
|
32
|
+
const plugin: ITtscPlugin = {
|
|
31
33
|
name: "@nestia/core",
|
|
32
|
-
source: path.resolve(root, "native", "cmd", "ttsc-nestia"),
|
|
33
|
-
composes: [
|
|
34
|
-
"typia/lib/transform",
|
|
35
|
-
"@nestia/sdk/lib/transform",
|
|
36
|
-
],
|
|
34
|
+
source: path.resolve(root(context), "native", "cmd", "ttsc-nestia"),
|
|
35
|
+
composes: ["typia/lib/transform"],
|
|
37
36
|
};
|
|
37
|
+
const sdk: string | null = resolveSdkContributorSource(context);
|
|
38
|
+
if (sdk !== null) plugin.contributors = [{ name: "sdk", source: sdk }];
|
|
39
|
+
return plugin;
|
|
38
40
|
}
|
|
39
41
|
export default createTtscPlugin;
|
|
40
42
|
|
|
43
|
+
function root(context: ITtscPluginFactoryContext): string {
|
|
44
|
+
return (
|
|
45
|
+
resolvePackageRoot("@nestia/core/package.json", context.projectRoot) ??
|
|
46
|
+
path.resolve(dirname, "..")
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function resolveSdkContributorSource(
|
|
51
|
+
context: ITtscPluginFactoryContext,
|
|
52
|
+
): string | null {
|
|
53
|
+
const manifest: string | null = resolvePackageRoot(
|
|
54
|
+
"@nestia/sdk/package.json",
|
|
55
|
+
context.projectRoot,
|
|
56
|
+
);
|
|
57
|
+
if (manifest === null) return null;
|
|
58
|
+
const source: string = path.resolve(manifest, "native", "sdk");
|
|
59
|
+
return fs.existsSync(source) ? source : null;
|
|
60
|
+
}
|
|
61
|
+
|
|
41
62
|
function resolvePackageRoot(
|
|
42
63
|
packageJson: string,
|
|
43
64
|
projectRoot: string,
|
|
44
65
|
): string | null {
|
|
45
66
|
try {
|
|
46
|
-
return path.dirname(
|
|
67
|
+
return path.dirname(
|
|
68
|
+
require.resolve(packageJson, { paths: [dirname, projectRoot] }),
|
|
69
|
+
);
|
|
47
70
|
} catch {
|
|
48
71
|
return null;
|
|
49
72
|
}
|
|
50
73
|
}
|
|
51
74
|
|
|
52
|
-
function inferPackageRoot(): string {
|
|
53
|
-
return path.resolve(dirname, "..");
|
|
54
|
-
}
|
|
55
|
-
|
|
56
75
|
function currentFilename(): string {
|
|
57
76
|
if (
|
|
58
77
|
typeof __filename === "string" &&
|