@ontrails/trails 1.0.0-beta.13 → 1.0.0-beta.15
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/.turbo/turbo-lint.log +1 -1
- package/CHANGELOG.md +29 -0
- package/__tests__/examples.test.ts +39 -0
- package/dist/src/app.d.ts.map +1 -1
- package/dist/src/app.js +12 -1
- package/dist/src/app.js.map +1 -1
- package/dist/src/cli.js +4 -3
- package/dist/src/cli.js.map +1 -1
- package/dist/src/trails/add-surface.d.ts +3 -3
- package/dist/src/trails/add-surface.d.ts.map +1 -1
- package/dist/src/trails/add-surface.js +46 -24
- package/dist/src/trails/add-surface.js.map +1 -1
- package/dist/src/trails/add-trail.d.ts +3 -1
- package/dist/src/trails/add-trail.d.ts.map +1 -1
- package/dist/src/trails/add-trail.js +49 -22
- package/dist/src/trails/add-trail.js.map +1 -1
- package/dist/src/trails/add-trailhead.d.ts +13 -0
- package/dist/src/trails/add-trailhead.d.ts.map +1 -0
- package/dist/src/trails/add-trailhead.js +88 -0
- package/dist/src/trails/add-trailhead.js.map +1 -0
- package/dist/src/trails/add-verify.d.ts +1 -1
- package/dist/src/trails/add-verify.d.ts.map +1 -1
- package/dist/src/trails/add-verify.js +17 -16
- package/dist/src/trails/add-verify.js.map +1 -1
- package/dist/src/trails/create-scaffold.d.ts +1 -1
- package/dist/src/trails/create-scaffold.d.ts.map +1 -1
- package/dist/src/trails/create-scaffold.js +34 -27
- package/dist/src/trails/create-scaffold.js.map +1 -1
- package/dist/src/trails/create.d.ts +9 -13
- package/dist/src/trails/create.d.ts.map +1 -1
- package/dist/src/trails/create.js +40 -35
- package/dist/src/trails/create.js.map +1 -1
- package/dist/src/trails/dev-clean.d.ts +9 -0
- package/dist/src/trails/dev-clean.d.ts.map +1 -0
- package/dist/src/trails/dev-clean.js +66 -0
- package/dist/src/trails/dev-clean.js.map +1 -0
- package/dist/src/trails/dev-reset.d.ts +6 -0
- package/dist/src/trails/dev-reset.d.ts.map +1 -0
- package/dist/src/trails/dev-reset.js +39 -0
- package/dist/src/trails/dev-reset.js.map +1 -0
- package/dist/src/trails/dev-stats.d.ts +7 -0
- package/dist/src/trails/dev-stats.d.ts.map +1 -0
- package/dist/src/trails/dev-stats.js +61 -0
- package/dist/src/trails/dev-stats.js.map +1 -0
- package/dist/src/trails/dev-support.d.ts +64 -0
- package/dist/src/trails/dev-support.d.ts.map +1 -0
- package/dist/src/trails/dev-support.js +181 -0
- package/dist/src/trails/dev-support.js.map +1 -0
- package/dist/src/trails/draft-promote.d.ts +18 -0
- package/dist/src/trails/draft-promote.d.ts.map +1 -0
- package/dist/src/trails/draft-promote.js +400 -0
- package/dist/src/trails/draft-promote.js.map +1 -0
- package/dist/src/trails/guide.d.ts +14 -4
- package/dist/src/trails/guide.d.ts.map +1 -1
- package/dist/src/trails/guide.js +22 -41
- package/dist/src/trails/guide.js.map +1 -1
- package/dist/src/trails/load-app.d.ts +9 -1
- package/dist/src/trails/load-app.d.ts.map +1 -1
- package/dist/src/trails/load-app.js +404 -13
- package/dist/src/trails/load-app.js.map +1 -1
- package/dist/src/trails/project.d.ts.map +1 -1
- package/dist/src/trails/project.js +14 -3
- package/dist/src/trails/project.js.map +1 -1
- package/dist/src/trails/survey.d.ts +6 -60
- package/dist/src/trails/survey.d.ts.map +1 -1
- package/dist/src/trails/survey.js +83 -182
- package/dist/src/trails/survey.js.map +1 -1
- package/dist/src/trails/topo-constants.d.ts +3 -0
- package/dist/src/trails/topo-constants.d.ts.map +1 -0
- package/dist/src/trails/topo-constants.js +3 -0
- package/dist/src/trails/topo-constants.js.map +1 -0
- package/dist/src/trails/topo-export.d.ts +19 -0
- package/dist/src/trails/topo-export.d.ts.map +1 -0
- package/dist/src/trails/topo-export.js +31 -0
- package/dist/src/trails/topo-export.js.map +1 -0
- package/dist/src/trails/topo-history.d.ts +20 -0
- package/dist/src/trails/topo-history.d.ts.map +1 -0
- package/dist/src/trails/topo-history.js +32 -0
- package/dist/src/trails/topo-history.js.map +1 -0
- package/dist/src/trails/topo-pin.d.ts +17 -0
- package/dist/src/trails/topo-pin.d.ts.map +1 -0
- package/dist/src/trails/topo-pin.js +31 -0
- package/dist/src/trails/topo-pin.js.map +1 -0
- package/dist/src/trails/topo-read-support.d.ts +58 -0
- package/dist/src/trails/topo-read-support.d.ts.map +1 -0
- package/dist/src/trails/topo-read-support.js +167 -0
- package/dist/src/trails/topo-read-support.js.map +1 -0
- package/dist/src/trails/topo-reports.d.ts +54 -0
- package/dist/src/trails/topo-reports.d.ts.map +1 -0
- package/dist/src/trails/topo-reports.js +128 -0
- package/dist/src/trails/topo-reports.js.map +1 -0
- package/dist/src/trails/topo-show.d.ts +23 -0
- package/dist/src/trails/topo-show.d.ts.map +1 -0
- package/dist/src/trails/topo-show.js +49 -0
- package/dist/src/trails/topo-show.js.map +1 -0
- package/dist/src/trails/topo-store-support.d.ts +13 -0
- package/dist/src/trails/topo-store-support.d.ts.map +1 -0
- package/dist/src/trails/topo-store-support.js +55 -0
- package/dist/src/trails/topo-store-support.js.map +1 -0
- package/dist/src/trails/topo-support.d.ts +76 -0
- package/dist/src/trails/topo-support.d.ts.map +1 -0
- package/dist/src/trails/topo-support.js +132 -0
- package/dist/src/trails/topo-support.js.map +1 -0
- package/dist/src/trails/topo-unpin.d.ts +20 -0
- package/dist/src/trails/topo-unpin.d.ts.map +1 -0
- package/dist/src/trails/topo-unpin.js +44 -0
- package/dist/src/trails/topo-unpin.js.map +1 -0
- package/dist/src/trails/topo-verify.d.ts +5 -0
- package/dist/src/trails/topo-verify.d.ts.map +1 -0
- package/dist/src/trails/topo-verify.js +24 -0
- package/dist/src/trails/topo-verify.js.map +1 -0
- package/dist/src/trails/topo.d.ts +5 -0
- package/dist/src/trails/topo.d.ts.map +1 -0
- package/dist/src/trails/topo.js +63 -0
- package/dist/src/trails/topo.js.map +1 -0
- package/dist/src/trails/warden.d.ts +3 -2
- package/dist/src/trails/warden.d.ts.map +1 -1
- package/dist/src/trails/warden.js +37 -27
- package/dist/src/trails/warden.js.map +1 -1
- package/dist/src/versions.d.ts +12 -0
- package/dist/src/versions.d.ts.map +1 -0
- package/dist/src/versions.js +23 -0
- package/dist/src/versions.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +8 -7
- package/src/__tests__/add-trail.test.ts +97 -0
- package/src/__tests__/create.test.ts +91 -27
- package/src/__tests__/draft-promote.test.ts +144 -0
- package/src/__tests__/guide.test.ts +10 -5
- package/src/__tests__/load-app.test.ts +406 -2
- package/src/__tests__/survey.test.ts +221 -60
- package/src/__tests__/topo-dev.test.ts +426 -0
- package/src/app.ts +24 -2
- package/src/clack.ts +1 -1
- package/src/cli.ts +4 -3
- package/src/trails/add-surface.ts +150 -0
- package/src/trails/add-trail.ts +46 -10
- package/src/trails/add-verify.ts +11 -6
- package/src/trails/create-scaffold.ts +16 -3
- package/src/trails/create.ts +76 -71
- package/src/trails/dev-clean.ts +77 -0
- package/src/trails/dev-reset.ts +45 -0
- package/src/trails/dev-stats.ts +67 -0
- package/src/trails/dev-support.ts +328 -0
- package/src/trails/draft-promote.ts +739 -0
- package/src/trails/guide.ts +23 -41
- package/src/trails/load-app.ts +556 -14
- package/src/trails/project.ts +17 -3
- package/src/trails/survey.ts +110 -285
- package/src/trails/topo-constants.ts +2 -0
- package/src/trails/topo-export.ts +35 -0
- package/src/trails/topo-history.ts +38 -0
- package/src/trails/topo-pin.ts +38 -0
- package/src/trails/topo-read-support.ts +329 -0
- package/src/trails/topo-reports.ts +228 -0
- package/src/trails/topo-show.ts +54 -0
- package/src/trails/topo-store-support.ts +104 -0
- package/src/trails/topo-support.ts +230 -0
- package/src/trails/topo-unpin.ts +56 -0
- package/src/trails/topo-verify.ts +25 -0
- package/src/trails/topo.ts +69 -0
- package/src/trails/warden.ts +13 -3
- package/src/versions.ts +43 -0
- package/tsconfig.tests.json +10 -0
- package/src/trails/add-trailhead.ts +0 -121
|
@@ -1,9 +1,226 @@
|
|
|
1
|
-
import { describe, expect, test } from 'bun:test';
|
|
1
|
+
import { afterAll, describe, expect, test } from 'bun:test';
|
|
2
|
+
import {
|
|
3
|
+
existsSync,
|
|
4
|
+
mkdirSync,
|
|
5
|
+
readdirSync,
|
|
6
|
+
readFileSync,
|
|
7
|
+
rmSync,
|
|
8
|
+
utimesSync,
|
|
9
|
+
writeFileSync,
|
|
10
|
+
} from 'node:fs';
|
|
11
|
+
import { tmpdir } from 'node:os';
|
|
2
12
|
import { resolve } from 'node:path';
|
|
3
13
|
|
|
4
|
-
import { loadApp } from '../trails/load-app.js';
|
|
14
|
+
import { loadApp, loadFreshAppLease } from '../trails/load-app.js';
|
|
15
|
+
|
|
16
|
+
const writeLoadAppFixture = (cwd: string, name: string): void => {
|
|
17
|
+
writeFileSync(
|
|
18
|
+
resolve(cwd, 'src/app.ts'),
|
|
19
|
+
`export const app = {
|
|
20
|
+
name: '${name}',
|
|
21
|
+
trails: new Map(),
|
|
22
|
+
signals: new Map(),
|
|
23
|
+
resources: new Map()
|
|
24
|
+
};`
|
|
25
|
+
);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const assertLoadAppCaching = async (cwd: string): Promise<void> => {
|
|
29
|
+
writeLoadAppFixture(cwd, 'first');
|
|
30
|
+
|
|
31
|
+
const first = await loadApp('./src/app.ts', cwd);
|
|
32
|
+
|
|
33
|
+
writeLoadAppFixture(cwd, 'second');
|
|
34
|
+
|
|
35
|
+
const cached = await loadApp('./src/app.ts', cwd);
|
|
36
|
+
const fresh = await loadApp('./src/app.ts', cwd, { fresh: true });
|
|
37
|
+
|
|
38
|
+
expect(first.name).toBe('first');
|
|
39
|
+
expect(cached.name).toBe('first');
|
|
40
|
+
expect(fresh.name).toBe('second');
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const writeDependentLoadAppFixture = (cwd: string, name: string): void => {
|
|
44
|
+
writeFileSync(resolve(cwd, 'src/name.ts'), `export const name = '${name}';`);
|
|
45
|
+
writeFileSync(
|
|
46
|
+
resolve(cwd, 'src/app.ts'),
|
|
47
|
+
`import { name } from './name.ts';
|
|
48
|
+
|
|
49
|
+
export const app = {
|
|
50
|
+
name,
|
|
51
|
+
trails: new Map(),
|
|
52
|
+
signals: new Map(),
|
|
53
|
+
resources: new Map()
|
|
54
|
+
};`
|
|
55
|
+
);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const writeJsSpecifierLoadAppFixture = (cwd: string, name: string): void => {
|
|
59
|
+
writeFileSync(resolve(cwd, 'src/name.ts'), `export const name = '${name}';`);
|
|
60
|
+
writeFileSync(
|
|
61
|
+
resolve(cwd, 'src/app.ts'),
|
|
62
|
+
`import { name } from './name.js';
|
|
63
|
+
|
|
64
|
+
export const app = {
|
|
65
|
+
name,
|
|
66
|
+
trails: new Map(),
|
|
67
|
+
signals: new Map(),
|
|
68
|
+
resources: new Map()
|
|
69
|
+
};`
|
|
70
|
+
);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const assertLoadAppDependencyCaching = async (cwd: string): Promise<void> => {
|
|
74
|
+
writeDependentLoadAppFixture(cwd, 'first');
|
|
75
|
+
|
|
76
|
+
const first = await loadApp('./src/app.ts', cwd);
|
|
77
|
+
|
|
78
|
+
writeDependentLoadAppFixture(cwd, 'second');
|
|
79
|
+
|
|
80
|
+
const cached = await loadApp('./src/app.ts', cwd);
|
|
81
|
+
const fresh = await loadApp('./src/app.ts', cwd, { fresh: true });
|
|
82
|
+
|
|
83
|
+
expect(first.name).toBe('first');
|
|
84
|
+
expect(cached.name).toBe('first');
|
|
85
|
+
expect(fresh.name).toBe('second');
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const assertLoadAppJsSpecifierCaching = async (cwd: string): Promise<void> => {
|
|
89
|
+
writeJsSpecifierLoadAppFixture(cwd, 'first');
|
|
90
|
+
|
|
91
|
+
const first = await loadApp('./src/app.ts', cwd);
|
|
92
|
+
|
|
93
|
+
writeJsSpecifierLoadAppFixture(cwd, 'second');
|
|
94
|
+
|
|
95
|
+
const cached = await loadApp('./src/app.ts', cwd);
|
|
96
|
+
const fresh = await loadApp('./src/app.ts', cwd, { fresh: true });
|
|
97
|
+
|
|
98
|
+
expect(first.name).toBe('first');
|
|
99
|
+
expect(cached.name).toBe('first');
|
|
100
|
+
expect(fresh.name).toBe('second');
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const writeGraphFixture = (cwd: string, name: string): void => {
|
|
104
|
+
writeFileSync(
|
|
105
|
+
resolve(cwd, 'src/app.ts'),
|
|
106
|
+
`export const graph = {
|
|
107
|
+
name: '${name}',
|
|
108
|
+
trails: new Map(),
|
|
109
|
+
signals: new Map(),
|
|
110
|
+
resources: new Map()
|
|
111
|
+
};`
|
|
112
|
+
);
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const writeWorkspaceDependencyFixture = (cwd: string): void => {
|
|
116
|
+
writeFileSync(
|
|
117
|
+
resolve(cwd, 'src/app.ts'),
|
|
118
|
+
`import { Result, topo, trail } from '@ontrails/core';
|
|
119
|
+
import { z } from 'zod';
|
|
120
|
+
|
|
121
|
+
const sample = trail('sample', {
|
|
122
|
+
blaze: async () => Result.ok({ ok: true }),
|
|
123
|
+
input: z.object({}),
|
|
124
|
+
output: z.object({ ok: z.boolean() }),
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
export const app = topo('fixture', { sample });
|
|
128
|
+
`
|
|
129
|
+
);
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
// Bytes that are intentionally not valid UTF-8. Decoding then re-encoding
|
|
133
|
+
// would replace them with U+FFFD and corrupt the file.
|
|
134
|
+
const BINARY_SIBLING_BYTES = new Uint8Array([
|
|
135
|
+
0, 1, 2, 255, 254, 253, 192, 193, 245, 255, 128, 129,
|
|
136
|
+
]);
|
|
137
|
+
|
|
138
|
+
const BINARY_SIBLING_APP_SOURCE = `import { readFileSync } from 'node:fs';
|
|
139
|
+
import { fileURLToPath } from 'node:url';
|
|
140
|
+
import { dirname, resolve } from 'node:path';
|
|
141
|
+
|
|
142
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
143
|
+
const bytes = readFileSync(resolve(here, 'blob.bin'));
|
|
144
|
+
|
|
145
|
+
export const app = {
|
|
146
|
+
name: Array.from(bytes).join(','),
|
|
147
|
+
trails: new Map(),
|
|
148
|
+
signals: new Map(),
|
|
149
|
+
resources: new Map()
|
|
150
|
+
};`;
|
|
151
|
+
|
|
152
|
+
const assertLoadAppPreservesBinarySiblings = async (
|
|
153
|
+
cwd: string
|
|
154
|
+
): Promise<void> => {
|
|
155
|
+
mkdirSync(resolve(cwd, 'src'), { recursive: true });
|
|
156
|
+
writeFileSync(resolve(cwd, 'src/blob.bin'), BINARY_SIBLING_BYTES);
|
|
157
|
+
writeFileSync(resolve(cwd, 'src/app.ts'), BINARY_SIBLING_APP_SOURCE);
|
|
158
|
+
|
|
159
|
+
const fresh = await loadApp('./src/app.ts', cwd, { fresh: true });
|
|
160
|
+
const originalBytes = readFileSync(resolve(cwd, 'src/blob.bin'));
|
|
161
|
+
const expected = [...originalBytes].join(',');
|
|
162
|
+
expect(fresh.name).toBe(expected);
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Seed a stale mirror dir under `.trails-tmp/` with an mtime well past the
|
|
167
|
+
* 10-minute freshness threshold, simulating a directory abandoned by a
|
|
168
|
+
* signal-killed process.
|
|
169
|
+
*/
|
|
170
|
+
const seedStaleMirrorDir = (cwd: string): string => {
|
|
171
|
+
mkdirSync(resolve(cwd, 'src'), { recursive: true });
|
|
172
|
+
writeLoadAppFixture(cwd, 'stale-cleanup');
|
|
173
|
+
const mirrorParent = resolve(cwd, '.trails-tmp');
|
|
174
|
+
const staleDir = resolve(mirrorParent, 'load-app-fresh-stale-fixture');
|
|
175
|
+
mkdirSync(staleDir, { recursive: true });
|
|
176
|
+
writeFileSync(resolve(staleDir, 'marker'), 'stale');
|
|
177
|
+
const oneHourAgo = new Date(Date.now() - 60 * 60 * 1000);
|
|
178
|
+
utimesSync(staleDir, oneHourAgo, oneHourAgo);
|
|
179
|
+
return staleDir;
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
const assertStaleDirCleaned = (cwd: string, staleDir: string): void => {
|
|
183
|
+
expect(existsSync(staleDir)).toBe(false);
|
|
184
|
+
const mirrorParent = resolve(cwd, '.trails-tmp');
|
|
185
|
+
const remaining = readdirSync(mirrorParent).filter((entry) =>
|
|
186
|
+
entry.startsWith('load-app-fresh-')
|
|
187
|
+
);
|
|
188
|
+
expect(remaining.length).toBeGreaterThan(0);
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
const countFreshMirrorRoots = (cwd: string): number => {
|
|
192
|
+
const mirrorParent = resolve(cwd, '.trails-tmp');
|
|
193
|
+
if (!existsSync(mirrorParent)) {
|
|
194
|
+
return 0;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return readdirSync(mirrorParent).filter((entry) =>
|
|
198
|
+
entry.startsWith('load-app-fresh-')
|
|
199
|
+
).length;
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
const workspaceTmpRoot = resolve(import.meta.dir, '../..', '.tmp-tests');
|
|
5
203
|
|
|
6
204
|
describe('loadApp', () => {
|
|
205
|
+
afterAll(() => {
|
|
206
|
+
rmSync(workspaceTmpRoot, { force: true, recursive: true });
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
test('resolves named graph export', async () => {
|
|
210
|
+
const cwd = resolve(
|
|
211
|
+
tmpdir(),
|
|
212
|
+
`trails-load-graph-${Date.now()}-${Math.random().toString(36).slice(2)}`
|
|
213
|
+
);
|
|
214
|
+
try {
|
|
215
|
+
mkdirSync(resolve(cwd, 'src'), { recursive: true });
|
|
216
|
+
writeGraphFixture(cwd, 'graph-test');
|
|
217
|
+
const loaded = await loadApp('./src/app.ts', cwd);
|
|
218
|
+
expect(loaded.name).toBe('graph-test');
|
|
219
|
+
} finally {
|
|
220
|
+
rmSync(cwd, { force: true, recursive: true });
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
|
|
7
224
|
test('resolves relative module paths from cwd', async () => {
|
|
8
225
|
// import.meta.dir is src/__tests__/, go up two to get apps/trails/
|
|
9
226
|
const cwd = resolve(import.meta.dir, '../..');
|
|
@@ -12,4 +229,191 @@ describe('loadApp', () => {
|
|
|
12
229
|
expect(app.name).toBe('trails');
|
|
13
230
|
expect(app.get('survey')).toBeDefined();
|
|
14
231
|
});
|
|
232
|
+
|
|
233
|
+
test('can bypass module caching with fresh loading', async () => {
|
|
234
|
+
const cwd = resolve(
|
|
235
|
+
tmpdir(),
|
|
236
|
+
`trails-load-app-${Date.now()}-${Math.random().toString(36).slice(2)}`
|
|
237
|
+
);
|
|
238
|
+
|
|
239
|
+
try {
|
|
240
|
+
mkdirSync(resolve(cwd, 'src'), { recursive: true });
|
|
241
|
+
await assertLoadAppCaching(cwd);
|
|
242
|
+
} finally {
|
|
243
|
+
rmSync(cwd, { force: true, recursive: true });
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
test('fresh loading reloads transitive local imports', async () => {
|
|
248
|
+
const cwd = resolve(
|
|
249
|
+
tmpdir(),
|
|
250
|
+
`trails-load-app-deps-${Date.now()}-${Math.random().toString(36).slice(2)}`
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
try {
|
|
254
|
+
mkdirSync(resolve(cwd, 'src'), { recursive: true });
|
|
255
|
+
await assertLoadAppDependencyCaching(cwd);
|
|
256
|
+
} finally {
|
|
257
|
+
rmSync(cwd, { force: true, recursive: true });
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
test('fresh loading resolves .js specifiers to local .ts sources', async () => {
|
|
262
|
+
const cwd = resolve(
|
|
263
|
+
tmpdir(),
|
|
264
|
+
`trails-load-app-js-specifier-${Date.now()}-${Math.random()
|
|
265
|
+
.toString(36)
|
|
266
|
+
.slice(2)}`
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
try {
|
|
270
|
+
mkdirSync(resolve(cwd, 'src'), { recursive: true });
|
|
271
|
+
await assertLoadAppJsSpecifierCaching(cwd);
|
|
272
|
+
} finally {
|
|
273
|
+
rmSync(cwd, { force: true, recursive: true });
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
test('fresh loading mirrors siblings reached via computed dynamic imports', async () => {
|
|
278
|
+
const cwd = resolve(
|
|
279
|
+
tmpdir(),
|
|
280
|
+
`trails-load-app-dynamic-${Date.now()}-${Math.random()
|
|
281
|
+
.toString(36)
|
|
282
|
+
.slice(2)}`
|
|
283
|
+
);
|
|
284
|
+
|
|
285
|
+
try {
|
|
286
|
+
mkdirSync(resolve(cwd, 'src/parts'), { recursive: true });
|
|
287
|
+
writeFileSync(
|
|
288
|
+
resolve(cwd, 'src/parts/alpha.ts'),
|
|
289
|
+
`export const label = 'alpha';`
|
|
290
|
+
);
|
|
291
|
+
writeFileSync(
|
|
292
|
+
resolve(cwd, 'src/parts/beta.ts'),
|
|
293
|
+
`export const label = 'beta';`
|
|
294
|
+
);
|
|
295
|
+
writeFileSync(
|
|
296
|
+
resolve(cwd, 'src/app.ts'),
|
|
297
|
+
`const which = 'beta';
|
|
298
|
+
const mod = await import(\`./parts/\${which}.ts\`);
|
|
299
|
+
|
|
300
|
+
export const app = {
|
|
301
|
+
name: mod.label,
|
|
302
|
+
trails: new Map(),
|
|
303
|
+
signals: new Map(),
|
|
304
|
+
resources: new Map()
|
|
305
|
+
};`
|
|
306
|
+
);
|
|
307
|
+
|
|
308
|
+
const fresh = await loadApp('./src/app.ts', cwd, { fresh: true });
|
|
309
|
+
expect(fresh.name).toBe('beta');
|
|
310
|
+
} finally {
|
|
311
|
+
rmSync(cwd, { force: true, recursive: true });
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
test('fresh loading preserves binary sibling bytes in the mirror', async () => {
|
|
316
|
+
const cwd = resolve(
|
|
317
|
+
tmpdir(),
|
|
318
|
+
`trails-load-app-binary-${Date.now()}-${Math.random()
|
|
319
|
+
.toString(36)
|
|
320
|
+
.slice(2)}`
|
|
321
|
+
);
|
|
322
|
+
|
|
323
|
+
try {
|
|
324
|
+
await assertLoadAppPreservesBinarySiblings(cwd);
|
|
325
|
+
} finally {
|
|
326
|
+
rmSync(cwd, { force: true, recursive: true });
|
|
327
|
+
}
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
test('fresh loading opportunistically cleans up stale mirror roots', async () => {
|
|
331
|
+
const cwd = resolve(
|
|
332
|
+
tmpdir(),
|
|
333
|
+
`trails-load-app-stale-${Date.now()}-${Math.random()
|
|
334
|
+
.toString(36)
|
|
335
|
+
.slice(2)}`
|
|
336
|
+
);
|
|
337
|
+
|
|
338
|
+
try {
|
|
339
|
+
const staleDir = seedStaleMirrorDir(cwd);
|
|
340
|
+
await loadApp('./src/app.ts', cwd, { fresh: true });
|
|
341
|
+
assertStaleDirCleaned(cwd, staleDir);
|
|
342
|
+
} finally {
|
|
343
|
+
rmSync(cwd, { force: true, recursive: true });
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
describe('loadApp fresh lifecycle', () => {
|
|
349
|
+
test('leased fresh loads remove their mirror root when released', async () => {
|
|
350
|
+
const cwd = resolve(
|
|
351
|
+
tmpdir(),
|
|
352
|
+
`trails-load-app-lease-${Date.now()}-${Math.random()
|
|
353
|
+
.toString(36)
|
|
354
|
+
.slice(2)}`
|
|
355
|
+
);
|
|
356
|
+
|
|
357
|
+
try {
|
|
358
|
+
mkdirSync(resolve(cwd, 'src'), { recursive: true });
|
|
359
|
+
writeLoadAppFixture(cwd, 'leased');
|
|
360
|
+
|
|
361
|
+
const lease = await loadFreshAppLease('./src/app.ts', cwd);
|
|
362
|
+
|
|
363
|
+
expect(lease.app.name).toBe('leased');
|
|
364
|
+
expect(existsSync(lease.mirrorRoot)).toBe(true);
|
|
365
|
+
|
|
366
|
+
lease.release();
|
|
367
|
+
|
|
368
|
+
expect(existsSync(lease.mirrorRoot)).toBe(false);
|
|
369
|
+
} finally {
|
|
370
|
+
rmSync(cwd, { force: true, recursive: true });
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
test('fresh loading retains mirrors so deferred imports from earlier apps still resolve', async () => {
|
|
375
|
+
const cwd = resolve(
|
|
376
|
+
tmpdir(),
|
|
377
|
+
`trails-load-app-retained-${Date.now()}-${Math.random()
|
|
378
|
+
.toString(36)
|
|
379
|
+
.slice(2)}`
|
|
380
|
+
);
|
|
381
|
+
|
|
382
|
+
try {
|
|
383
|
+
mkdirSync(resolve(cwd, 'src'), { recursive: true });
|
|
384
|
+
|
|
385
|
+
for (let index = 0; index < 6; index += 1) {
|
|
386
|
+
writeLoadAppFixture(cwd, `retained-${String(index)}`);
|
|
387
|
+
await loadApp('./src/app.ts', cwd, { fresh: true });
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// All fresh mirrors stay on disk for the lifetime of the process so a
|
|
391
|
+
// previously returned Topo can still resolve deferred relative
|
|
392
|
+
// `import()` calls. Cleanup happens on process exit, not by LRU age.
|
|
393
|
+
expect(countFreshMirrorRoots(cwd)).toBe(6);
|
|
394
|
+
} finally {
|
|
395
|
+
rmSync(cwd, { force: true, recursive: true });
|
|
396
|
+
}
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
test('fresh loading preserves workspace package resolution for mirrored apps', async () => {
|
|
400
|
+
const cwd = resolve(
|
|
401
|
+
workspaceTmpRoot,
|
|
402
|
+
`trails-load-app-workspace-deps-${Date.now()}-${Math.random()
|
|
403
|
+
.toString(36)
|
|
404
|
+
.slice(2)}`
|
|
405
|
+
);
|
|
406
|
+
|
|
407
|
+
try {
|
|
408
|
+
mkdirSync(resolve(cwd, 'src'), { recursive: true });
|
|
409
|
+
writeWorkspaceDependencyFixture(cwd);
|
|
410
|
+
|
|
411
|
+
const app = await loadApp('./src/app.ts', cwd, { fresh: true });
|
|
412
|
+
|
|
413
|
+
expect(app.name).toBe('fixture');
|
|
414
|
+
expect(app.get('sample')).toBeDefined();
|
|
415
|
+
} finally {
|
|
416
|
+
rmSync(cwd, { force: true, recursive: true });
|
|
417
|
+
}
|
|
418
|
+
});
|
|
15
419
|
});
|