File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change 1+ import { existsSync } from "node:fs" ;
2+ import { dirname , join } from "node:path" ;
3+
4+ let cachedProjectRoot : string | undefined ;
5+
6+ /**
7+ * Finds the project root by walking up from `process.cwd()` looking for `tsconfig.json`.
8+ *
9+ * In deployed environments, `process.cwd()` may not be the project root
10+ * (e.g., `cd .amplify-hosting/compute/default/ && node app.js`).
11+ * Walking up to find `tsconfig.json` — which is never copied to deployment directories —
12+ * gives us the real project root.
13+ *
14+ * The result is cached since the project root doesn't change during a process's lifetime.
15+ */
16+ export function findProjectRoot ( ) : string {
17+ if ( cachedProjectRoot !== undefined ) {
18+ return cachedProjectRoot ;
19+ }
20+ let projectRoot = process . cwd ( ) ;
21+ for ( let d = projectRoot ; d !== dirname ( d ) ; d = dirname ( d ) ) {
22+ if ( existsSync ( join ( d , "tsconfig.json" ) ) ) {
23+ projectRoot = d ;
24+ break ;
25+ }
26+ }
27+ cachedProjectRoot = projectRoot ;
28+ return projectRoot ;
29+ }
30+
31+ /** @internal Exposed for testing only */
32+ export function _resetProjectRootCache ( ) {
33+ cachedProjectRoot = undefined ;
34+ }
Original file line number Diff line number Diff line change 1+ import { test } from "node:test" ;
2+ import assert from "node:assert" ;
3+ import { existsSync } from "node:fs" ;
4+ import { join } from "node:path" ;
5+ import { findProjectRoot , _resetProjectRootCache } from "../src/path.js" ;
6+
7+ test ( "findProjectRoot" , async ( t ) => {
8+ t . afterEach ( ( ) => {
9+ _resetProjectRootCache ( ) ;
10+ } ) ;
11+
12+ await t . test ( "returns a directory containing tsconfig.json" , ( ) => {
13+ const root = findProjectRoot ( ) ;
14+ assert . ok (
15+ existsSync ( join ( root , "tsconfig.json" ) ) ,
16+ `Expected ${ root } to contain tsconfig.json` ,
17+ ) ;
18+ } ) ;
19+
20+ await t . test ( "caches the result across calls" , ( ) => {
21+ const first = findProjectRoot ( ) ;
22+ const second = findProjectRoot ( ) ;
23+ assert . strictEqual ( first , second ) ;
24+ } ) ;
25+ } ) ;
Original file line number Diff line number Diff line change 1+ import { existsSync } from "node:fs" ;
2+ import { dirname , join } from "node:path" ;
3+
4+ let cachedProjectRoot : string | undefined ;
5+
6+ /**
7+ * Finds the project root by walking up from `process.cwd()` looking for `tsconfig.json`.
8+ *
9+ * In deployed environments, `process.cwd()` may not be the project root
10+ * (e.g., `cd .amplify-hosting/compute/default/ && node app.js`).
11+ * Walking up to find `tsconfig.json` — which is never copied to deployment directories —
12+ * gives us the real project root.
13+ *
14+ * The result is cached since the project root doesn't change during a process's lifetime.
15+ */
16+ export function findProjectRoot ( ) : string {
17+ if ( cachedProjectRoot !== undefined ) {
18+ return cachedProjectRoot ;
19+ }
20+ let projectRoot = process . cwd ( ) ;
21+ for ( let d = projectRoot ; d !== dirname ( d ) ; d = dirname ( d ) ) {
22+ if ( existsSync ( join ( d , "tsconfig.json" ) ) ) {
23+ projectRoot = d ;
24+ break ;
25+ }
26+ }
27+ cachedProjectRoot = projectRoot ;
28+ return projectRoot ;
29+ }
30+
31+ /** @internal Exposed for testing only */
32+ export function _resetProjectRootCache ( ) {
33+ cachedProjectRoot = undefined ;
34+ }
Original file line number Diff line number Diff line change 1+ import { test } from "node:test" ;
2+ import assert from "node:assert" ;
3+ import { existsSync } from "node:fs" ;
4+ import { join } from "node:path" ;
5+ import { findProjectRoot , _resetProjectRootCache } from "../src/path.js" ;
6+
7+ test ( "findProjectRoot" , async ( t ) => {
8+ t . afterEach ( ( ) => {
9+ _resetProjectRootCache ( ) ;
10+ } ) ;
11+
12+ await t . test ( "returns a directory containing tsconfig.json" , ( ) => {
13+ const root = findProjectRoot ( ) ;
14+ assert . ok (
15+ existsSync ( join ( root , "tsconfig.json" ) ) ,
16+ `Expected ${ root } to contain tsconfig.json` ,
17+ ) ;
18+ } ) ;
19+
20+ await t . test ( "caches the result across calls" , ( ) => {
21+ const first = findProjectRoot ( ) ;
22+ const second = findProjectRoot ( ) ;
23+ assert . strictEqual ( first , second ) ;
24+ } ) ;
25+ } ) ;
You can’t perform that action at this time.
0 commit comments