@nestia/core 12.0.0-dev.20260520.1 → 12.0.0-dev.20260521.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 (30) hide show
  1. package/lib/transform.d.ts +8 -0
  2. package/lib/transform.js +28 -12
  3. package/lib/transform.js.map +1 -1
  4. package/native/cmd/ttsc-nestia/main.go +2 -63
  5. package/native/go.mod +1 -1
  6. package/native/transform/ast.go +32 -0
  7. package/native/{cmd/ttsc-nestia → transform}/build.go +14 -35
  8. package/native/{cmd/ttsc-nestia → transform}/cleanup.go +1 -1
  9. package/native/transform/cleanup_test.go +76 -0
  10. package/native/transform/commonjs_import_alias_test.go +49 -0
  11. package/native/transform/core_dispatch_test.go +127 -0
  12. package/native/{cmd/ttsc-nestia → transform}/core_querify.go +1 -1
  13. package/native/{cmd/ttsc-nestia → transform}/core_transform.go +26 -26
  14. package/native/{cmd/ttsc-nestia → transform}/core_websocket.go +10 -10
  15. package/native/transform/exports.go +13 -0
  16. package/native/{cmd/ttsc-nestia → transform}/path_rewrite.go +1 -1
  17. package/native/transform/path_rewrite_test.go +243 -0
  18. package/native/{cmd/ttsc-nestia → transform}/printer.go +1 -1
  19. package/native/{cmd/ttsc-nestia → transform}/rewrite.go +3 -3
  20. package/native/transform/rewrite_test.go +118 -0
  21. package/native/transform/rewrite_unique_base_test.go +48 -0
  22. package/native/transform/run.go +72 -0
  23. package/native/{cmd/ttsc-nestia → transform}/transform.go +25 -36
  24. package/native/{cmd/ttsc-nestia → transform}/typia_fast.go +1 -1
  25. package/native/{cmd/ttsc-nestia → transform}/typia_replacement.go +1 -1
  26. package/native/transform.cjs +34 -12
  27. package/package.json +8 -7
  28. package/src/transform.ts +39 -20
  29. package/native/cmd/ttsc-nestia/sdk_metadata_json.go +0 -327
  30. 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 main
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
- writeTypiaTransformDiagnostics(stderr, diagnostics, cwd)
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
- writeTypiaTransformDiagnostics(stderr, coreDiagnostics, cwd)
102
+ WriteTypiaTransformDiagnostics(stderr, coreDiagnostics, cwd)
103
103
  return 3
104
104
  }
105
105
  rewrites = append(rewrites, coreRewriteMap[filepath.ToSlash(absFile)]...)
106
- sdkRewriteMap, sdkDiagnostics := collectNestiaSDKSourceRewriteMap(prog, plan, absFile)
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 = applySourceRewrites(source, rewrites)
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 := sourceFileText(file)
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 := applySourceRewrites(source, rewrites[filename])
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 transformSourceRewrite struct {
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
- ) ([]transformSourceRewrite, []typiaTransformDiagnostic) {
195
+ ) ([]SourceRewrite, []Diagnostic) {
207
196
  sites := collectNestiaTypiaCallSites(prog.SourceFiles(), prog.Checker)
208
- rewrites := []transformSourceRewrite{}
209
- diagnostics := []typiaTransformDiagnostic{}
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, newTypiaTransformDiagnostic(site, reason))
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, newTypiaTransformDiagnostic(site, "method not covered"))
209
+ diagnostics = append(diagnostics, NewDiagnostic(site, "method not covered"))
221
210
  continue
222
211
  }
223
212
  if err != nil {
224
- diagnostics = append(diagnostics, newTypiaTransformDiagnostic(site, err.Error()))
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, transformSourceRewrite{
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][]transformSourceRewrite, []typiaTransformDiagnostic) {
231
+ ) (map[string][]SourceRewrite, []Diagnostic) {
243
232
  sites := collectNestiaTypiaCallSites(prog.SourceFiles(), prog.Checker)
244
- rewrites := map[string][]transformSourceRewrite{}
245
- diagnostics := []typiaTransformDiagnostic{}
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, newTypiaTransformDiagnostic(site, reason))
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, newTypiaTransformDiagnostic(site, "method not covered"))
243
+ diagnostics = append(diagnostics, NewDiagnostic(site, "method not covered"))
255
244
  continue
256
245
  }
257
246
  if err != nil {
258
- diagnostics = append(diagnostics, newTypiaTransformDiagnostic(site, err.Error()))
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], transformSourceRewrite{
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 applySourceRewrites(source string, rewrites []transformSourceRewrite) (string, error) {
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 sourceFileText(target any) (string, bool) {
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 typiaTransformDiagnostic,
361
+ diag Diagnostic,
373
362
  ) transformCompilerDiagnostic {
374
363
  var ptr *string
375
364
  if diag.File != "" {
@@ -1,4 +1,4 @@
1
- package main
1
+ package transform
2
2
 
3
3
  import (
4
4
  "path/filepath"
@@ -1,4 +1,4 @@
1
- package main
1
+ package transform
2
2
 
3
3
  import (
4
4
  "strings"
@@ -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 transform = context?.plugin?.transform;
5
- const name =
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", ...peer],
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.20260520.1",
3
+ "version": "12.0.0-dev.20260521.2",
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.20260520.2",
50
- "@typia/utils": "13.0.0-dev.20260520.2",
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.20260520.2",
58
+ "typia": "13.0.0-dev.20260521.1",
59
59
  "ws": "^7.5.3",
60
- "@nestia/fetcher": "^12.0.0-dev.20260520.1"
60
+ "@nestia/fetcher": "^12.0.0-dev.20260521.2"
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.20260520.2",
68
- "@nestia/fetcher": "^12.0.0-dev.20260520.1"
67
+ "typia": "13.0.0-dev.20260521.1",
68
+ "@nestia/fetcher": "^12.0.0-dev.20260521.2"
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 root: string =
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(require.resolve(packageJson, { paths: [projectRoot] }));
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" &&