jamdesk 1.1.41 → 1.1.43
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/README.md +22 -0
- package/dist/__tests__/unit/dev-validate-cache.test.d.ts +2 -0
- package/dist/__tests__/unit/dev-validate-cache.test.d.ts.map +1 -0
- package/dist/__tests__/unit/dev-validate-cache.test.js +116 -0
- package/dist/__tests__/unit/dev-validate-cache.test.js.map +1 -0
- package/dist/__tests__/unit/dev-workspace-symlinks.test.d.ts +2 -0
- package/dist/__tests__/unit/dev-workspace-symlinks.test.d.ts.map +1 -0
- package/dist/__tests__/unit/dev-workspace-symlinks.test.js +105 -0
- package/dist/__tests__/unit/dev-workspace-symlinks.test.js.map +1 -0
- package/dist/__tests__/unit/language-filter.test.d.ts +2 -0
- package/dist/__tests__/unit/language-filter.test.d.ts.map +1 -0
- package/dist/__tests__/unit/language-filter.test.js +95 -0
- package/dist/__tests__/unit/language-filter.test.js.map +1 -0
- package/dist/__tests__/unit/vendored-sync.test.js +4 -0
- package/dist/__tests__/unit/vendored-sync.test.js.map +1 -1
- package/dist/commands/dev.d.ts +48 -3
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +134 -41
- package/dist/commands/dev.js.map +1 -1
- package/dist/index.js +15 -2
- package/dist/index.js.map +1 -1
- package/dist/lib/language-filter.d.ts +32 -0
- package/dist/lib/language-filter.d.ts.map +1 -0
- package/dist/lib/language-filter.js +28 -0
- package/dist/lib/language-filter.js.map +1 -0
- package/package.json +1 -1
- package/vendored/app/[[...slug]]/page.tsx +41 -28
- package/vendored/app/api/isr-health/route.ts +6 -4
- package/vendored/components/mdx/StepSlugContext.tsx +57 -0
- package/vendored/components/mdx/Steps.tsx +2 -2
- package/vendored/components/navigation/TableOfContents.tsx +77 -5
- package/vendored/lib/cache-tags.ts +25 -0
- package/vendored/lib/cache-utils.ts +19 -0
- package/vendored/lib/heading-extractor.ts +25 -6
- package/vendored/lib/indexnow.ts +1 -1
- package/vendored/lib/middleware-helpers.ts +103 -15
- package/vendored/lib/navigation-resolver.ts +1 -1
- package/vendored/lib/openapi-isr.ts +13 -8
- package/vendored/lib/r2-cleanup.ts +70 -0
- package/vendored/lib/r2-content.ts +0 -24
- package/vendored/lib/r2-manifest.ts +13 -3
- package/vendored/lib/revalidation-helpers.ts +41 -11
- package/vendored/lib/revalidation-trigger.ts +104 -28
- package/vendored/lib/scanner-blocklist.ts +265 -0
- package/vendored/lib/snippet-compiler-isr.ts +5 -2
- package/vendored/scripts/validate-links.cjs +17 -6
- package/vendored/workspace-package-lock.json +12 -12
- package/vendored/lib/cache-keys.ts +0 -117
package/README.md
CHANGED
|
@@ -105,6 +105,8 @@ npx jamdesk dev
|
|
|
105
105
|
| `jamdesk dev --webpack` | Use Webpack instead of Turbopack |
|
|
106
106
|
| `jamdesk dev --clean` | Clear cache before starting |
|
|
107
107
|
| `jamdesk dev --port 3001` | Custom port |
|
|
108
|
+
| `jamdesk dev --lang en` | Explicitly compile the default language (multi-lang sites) |
|
|
109
|
+
| `jamdesk dev --all-langs` | Compile every language (slower; legacy behavior) |
|
|
108
110
|
| `jamdesk login` | Log in to Jamdesk |
|
|
109
111
|
| `jamdesk logout` | Log out |
|
|
110
112
|
| `jamdesk whoami` | Show current user |
|
|
@@ -138,8 +140,28 @@ jamdesk dev --port 3001 # Custom port
|
|
|
138
140
|
|
|
139
141
|
The dev server auto-validates on startup, auto-recovers from corrupted Turbopack cache, and auto-increments the port if yours is taken. Full search, all themes, and all components work locally.
|
|
140
142
|
|
|
143
|
+
- `--clean` clears the project's workspace cache (`.next/` and version markers). For deeper "weird import error after CLI upgrade" recovery, use `jamdesk clean --all`, which also wipes `~/.jamdesk/node_modules/`.
|
|
144
|
+
|
|
141
145
|
Set a default port in [`~/.jamdeskrc`](#cli-defaults).
|
|
142
146
|
|
|
147
|
+
### Multi-language sites
|
|
148
|
+
|
|
149
|
+
When `docs.json` has a `navigation.languages` array with multiple entries, `jamdesk dev` compiles only the default language by default — Turbopack's cold compile is roughly 5x faster on a single-language tree.
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
jamdesk dev # Default language only (fast — recommended)
|
|
153
|
+
jamdesk dev --lang en # Explicitly select the default language (no-op equivalent)
|
|
154
|
+
jamdesk dev --all-langs # Compile every language (slow; matches CLI ≤1.1.42)
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
**Tip:** Run `jamdesk dev -v` to see cache-decision logs (e.g. "reusing Turbopack cache" or "Next.js version changed, clearing").
|
|
158
|
+
|
|
159
|
+
**Previewing a non-default language is not supported in this CLI version.** The per-entry symlink layer can skip non-default `<lang>/` subdirs cleanly, but cannot strip root-level default-language content while keeping a `<lang>/` subdir. Use `--all-langs` to view translated pages until follow-up support lands. Running e.g. `jamdesk dev --lang es` against a project whose default is `en` errors out with a message pointing at `--all-langs`.
|
|
160
|
+
|
|
161
|
+
Cross-language internal links (e.g. `/es/foo`) won't resolve when the active language is filtered out. Restart with `--all-langs` to preview translations.
|
|
162
|
+
|
|
163
|
+
**Known limitation:** Adding a NEW top-level directory to your project (e.g. `tutorials/`) while `jamdesk dev` is running won't be picked up automatically. Restart the dev server to see it.
|
|
164
|
+
|
|
143
165
|
## Authentication
|
|
144
166
|
|
|
145
167
|
### `jamdesk login`
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dev-validate-cache.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/unit/dev-validate-cache.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @vitest-environment node
|
|
3
|
+
*
|
|
4
|
+
* validateAndCleanCache must distinguish between:
|
|
5
|
+
* - CLI version bump only (preserve cache; Turbopack content-addresses
|
|
6
|
+
* vendored files via syncVendoredFiles, so a wipe is unnecessary churn —
|
|
7
|
+
* and 22 CLI releases per 90 days made warm cache nearly unreachable)
|
|
8
|
+
* - Next.js version bump (wipe; Turbopack's persistent-cache encoding
|
|
9
|
+
* can change between Next.js minor versions, and stale cache may
|
|
10
|
+
* produce broken builds)
|
|
11
|
+
* - Workspace corruption (turbopack cache present but app/ deleted) → wipe
|
|
12
|
+
* - Stale per-run lockfile under .next/dev/lock → remove
|
|
13
|
+
*
|
|
14
|
+
* See docs/plans/2026-04-29-jamdesk-dev-compile-perf.md for the empirical
|
|
15
|
+
* validation (warm restart 1.9s with cache preserved across vendored-file
|
|
16
|
+
* change vs. 67s wiped).
|
|
17
|
+
*/
|
|
18
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
19
|
+
import fs from 'fs-extra';
|
|
20
|
+
import path from 'path';
|
|
21
|
+
import { tmpdir } from 'os';
|
|
22
|
+
import { validateAndCleanCache } from '../../commands/dev.js';
|
|
23
|
+
describe('validateAndCleanCache', () => {
|
|
24
|
+
let tmpRoot;
|
|
25
|
+
let workspace;
|
|
26
|
+
let nextCache;
|
|
27
|
+
let cliVersionFile;
|
|
28
|
+
let nextVersionFile;
|
|
29
|
+
let blobPath;
|
|
30
|
+
beforeEach(() => {
|
|
31
|
+
tmpRoot = fs.mkdtempSync(path.join(tmpdir(), 'jam-cache-'));
|
|
32
|
+
workspace = path.join(tmpRoot, 'ws');
|
|
33
|
+
nextCache = path.join(workspace, '.next');
|
|
34
|
+
cliVersionFile = path.join(nextCache, '.jamdesk-cli-version');
|
|
35
|
+
nextVersionFile = path.join(nextCache, '.jamdesk-next-version');
|
|
36
|
+
fs.mkdirpSync(path.join(workspace, 'app'));
|
|
37
|
+
fs.mkdirpSync(path.join(nextCache, 'dev', 'cache', 'turbopack'));
|
|
38
|
+
blobPath = path.join(nextCache, 'dev', 'cache', 'turbopack', 'fake-cache-blob');
|
|
39
|
+
fs.writeFileSync(blobPath, 'x');
|
|
40
|
+
});
|
|
41
|
+
afterEach(() => {
|
|
42
|
+
fs.removeSync(tmpRoot);
|
|
43
|
+
});
|
|
44
|
+
it('preserves cache when both CLI and Next.js versions match', async () => {
|
|
45
|
+
fs.writeFileSync(cliVersionFile, '1.1.42');
|
|
46
|
+
fs.writeFileSync(nextVersionFile, '^16.2.4');
|
|
47
|
+
const result = await validateAndCleanCache({ nextCacheDir: nextCache, cliVersionFile, nextVersionFile, workspaceDir: workspace, currentNextVersion: '^16.2.4', verbose: false });
|
|
48
|
+
expect(result).toBe(true);
|
|
49
|
+
expect(fs.existsSync(blobPath)).toBe(true);
|
|
50
|
+
});
|
|
51
|
+
it('preserves cache when only the CLI version changes (Next.js still matches)', async () => {
|
|
52
|
+
fs.writeFileSync(cliVersionFile, '1.1.40');
|
|
53
|
+
fs.writeFileSync(nextVersionFile, '^16.2.4');
|
|
54
|
+
const result = await validateAndCleanCache({ nextCacheDir: nextCache, cliVersionFile, nextVersionFile, workspaceDir: workspace, currentNextVersion: '^16.2.4', verbose: false });
|
|
55
|
+
expect(result).toBe(true);
|
|
56
|
+
expect(fs.existsSync(blobPath)).toBe(true);
|
|
57
|
+
});
|
|
58
|
+
it('wipes cache when the Next.js version changes (Turbopack format compatibility)', async () => {
|
|
59
|
+
fs.writeFileSync(cliVersionFile, '1.1.42');
|
|
60
|
+
fs.writeFileSync(nextVersionFile, '16.1.7');
|
|
61
|
+
const result = await validateAndCleanCache({ nextCacheDir: nextCache, cliVersionFile, nextVersionFile, workspaceDir: workspace, currentNextVersion: '^16.2.4', verbose: false });
|
|
62
|
+
expect(result).toBe(false);
|
|
63
|
+
expect(fs.existsSync(blobPath)).toBe(false);
|
|
64
|
+
});
|
|
65
|
+
it('wipes cache when the next-version file is missing (first-run-after-upgrade safety)', async () => {
|
|
66
|
+
fs.writeFileSync(cliVersionFile, '1.1.40');
|
|
67
|
+
// nextVersionFile intentionally not written
|
|
68
|
+
const result = await validateAndCleanCache({ nextCacheDir: nextCache, cliVersionFile, nextVersionFile, workspaceDir: workspace, currentNextVersion: '^16.2.4', verbose: false });
|
|
69
|
+
expect(result).toBe(false);
|
|
70
|
+
expect(fs.existsSync(blobPath)).toBe(false);
|
|
71
|
+
});
|
|
72
|
+
it('wipes on workspace corruption (turbopack cache present but app/ missing)', async () => {
|
|
73
|
+
fs.writeFileSync(cliVersionFile, '1.1.42');
|
|
74
|
+
fs.writeFileSync(nextVersionFile, '^16.2.4');
|
|
75
|
+
fs.removeSync(path.join(workspace, 'app'));
|
|
76
|
+
const result = await validateAndCleanCache({ nextCacheDir: nextCache, cliVersionFile, nextVersionFile, workspaceDir: workspace, currentNextVersion: '^16.2.4', verbose: false });
|
|
77
|
+
expect(result).toBe(false);
|
|
78
|
+
expect(fs.existsSync(blobPath)).toBe(false);
|
|
79
|
+
});
|
|
80
|
+
it('removes a stale per-run lockfile when otherwise preserving cache', async () => {
|
|
81
|
+
fs.writeFileSync(cliVersionFile, '1.1.42');
|
|
82
|
+
fs.writeFileSync(nextVersionFile, '^16.2.4');
|
|
83
|
+
const runLock = path.join(nextCache, 'dev', 'lock');
|
|
84
|
+
fs.writeFileSync(runLock, '12345');
|
|
85
|
+
const result = await validateAndCleanCache({ nextCacheDir: nextCache, cliVersionFile, nextVersionFile, workspaceDir: workspace, currentNextVersion: '^16.2.4', verbose: false });
|
|
86
|
+
expect(result).toBe(true);
|
|
87
|
+
expect(fs.existsSync(runLock)).toBe(false);
|
|
88
|
+
});
|
|
89
|
+
it('handles missing CLI version file (first-ever run) — wipes (no Next.js version known either)', async () => {
|
|
90
|
+
// No version files at all — first run.
|
|
91
|
+
const result = await validateAndCleanCache({ nextCacheDir: nextCache, cliVersionFile, nextVersionFile, workspaceDir: workspace, currentNextVersion: '^16.2.4', verbose: false });
|
|
92
|
+
// Behavior on first run: no version files → wipe (the existing cache must
|
|
93
|
+
// be from before we tracked versions; safest to drop it).
|
|
94
|
+
expect(result).toBe(false);
|
|
95
|
+
expect(fs.existsSync(blobPath)).toBe(false);
|
|
96
|
+
});
|
|
97
|
+
it('preserves cache when CLI marker is missing but Next.js marker matches (asymmetric markers)', async () => {
|
|
98
|
+
// User manually deleted .jamdesk-cli-version, OR a partial write left
|
|
99
|
+
// only the next-version marker. The cachedNextVersion === currentNextVersion
|
|
100
|
+
// path should still preserve cache (no wipe needed; CLI marker isn't
|
|
101
|
+
// load-bearing for cache-format compatibility).
|
|
102
|
+
fs.writeFileSync(nextVersionFile, '^16.2.4');
|
|
103
|
+
// cliVersionFile intentionally not written
|
|
104
|
+
const result = await validateAndCleanCache({
|
|
105
|
+
nextCacheDir: nextCache,
|
|
106
|
+
cliVersionFile,
|
|
107
|
+
nextVersionFile,
|
|
108
|
+
workspaceDir: workspace,
|
|
109
|
+
currentNextVersion: '^16.2.4',
|
|
110
|
+
verbose: false,
|
|
111
|
+
});
|
|
112
|
+
expect(result).toBe(true);
|
|
113
|
+
expect(fs.existsSync(blobPath)).toBe(true);
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
//# sourceMappingURL=dev-validate-cache.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dev-validate-cache.test.js","sourceRoot":"","sources":["../../../src/__tests__/unit/dev-validate-cache.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dev-workspace-symlinks.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/unit/dev-workspace-symlinks.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @vitest-environment node
|
|
3
|
+
*
|
|
4
|
+
* Tests prepareProjectWorkspaceLinks — replaces the single
|
|
5
|
+
* <workspace>/projects/<name> -> <projectDir> symlink with per-entry
|
|
6
|
+
* symlinks that skip non-active language directories. This is what
|
|
7
|
+
* actually reduces Turbopack's filesystem scan from 403 MDX files to
|
|
8
|
+
* 135 on jamdesk-docs.
|
|
9
|
+
*/
|
|
10
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
11
|
+
import fs from 'fs-extra';
|
|
12
|
+
import path from 'path';
|
|
13
|
+
import { tmpdir } from 'os';
|
|
14
|
+
import { prepareProjectWorkspaceLinks } from '../../commands/dev.js';
|
|
15
|
+
import { output } from '../../lib/output.js';
|
|
16
|
+
describe('prepareProjectWorkspaceLinks', () => {
|
|
17
|
+
let tmpRoot;
|
|
18
|
+
let projectDir;
|
|
19
|
+
let workspaceProjectDir;
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
tmpRoot = fs.mkdtempSync(path.join(tmpdir(), 'jam-ws-'));
|
|
22
|
+
projectDir = path.join(tmpRoot, 'project');
|
|
23
|
+
workspaceProjectDir = path.join(tmpRoot, 'ws', 'projects', 'project');
|
|
24
|
+
// Set up a project layout that mirrors a multi-language docs project:
|
|
25
|
+
// project/
|
|
26
|
+
// ai/intro.mdx (en at root)
|
|
27
|
+
// development/foo.mdx (en at root)
|
|
28
|
+
// es/ai/intro.mdx (spanish)
|
|
29
|
+
// fr/ai/intro.mdx (french)
|
|
30
|
+
// docs.json
|
|
31
|
+
// images/logo.png
|
|
32
|
+
fs.mkdirpSync(path.join(projectDir, 'ai'));
|
|
33
|
+
fs.writeFileSync(path.join(projectDir, 'ai', 'intro.mdx'), '# en');
|
|
34
|
+
fs.mkdirpSync(path.join(projectDir, 'development'));
|
|
35
|
+
fs.writeFileSync(path.join(projectDir, 'development', 'foo.mdx'), '# en');
|
|
36
|
+
fs.mkdirpSync(path.join(projectDir, 'es', 'ai'));
|
|
37
|
+
fs.writeFileSync(path.join(projectDir, 'es', 'ai', 'intro.mdx'), '# es');
|
|
38
|
+
fs.mkdirpSync(path.join(projectDir, 'fr', 'ai'));
|
|
39
|
+
fs.writeFileSync(path.join(projectDir, 'fr', 'ai', 'intro.mdx'), '# fr');
|
|
40
|
+
fs.writeFileSync(path.join(projectDir, 'docs.json'), '{}');
|
|
41
|
+
fs.mkdirpSync(path.join(projectDir, 'images'));
|
|
42
|
+
fs.writeFileSync(path.join(projectDir, 'images', 'logo.png'), '');
|
|
43
|
+
});
|
|
44
|
+
afterEach(() => {
|
|
45
|
+
fs.removeSync(tmpRoot);
|
|
46
|
+
});
|
|
47
|
+
it('symlinks every top-level entry when skip set is empty', async () => {
|
|
48
|
+
await prepareProjectWorkspaceLinks(projectDir, workspaceProjectDir, new Set());
|
|
49
|
+
expect(fs.existsSync(path.join(workspaceProjectDir, 'ai', 'intro.mdx'))).toBe(true);
|
|
50
|
+
expect(fs.existsSync(path.join(workspaceProjectDir, 'es', 'ai', 'intro.mdx'))).toBe(true);
|
|
51
|
+
expect(fs.existsSync(path.join(workspaceProjectDir, 'fr', 'ai', 'intro.mdx'))).toBe(true);
|
|
52
|
+
expect(fs.existsSync(path.join(workspaceProjectDir, 'docs.json'))).toBe(true);
|
|
53
|
+
});
|
|
54
|
+
it('skips entries whose names are in the skip set', async () => {
|
|
55
|
+
await prepareProjectWorkspaceLinks(projectDir, workspaceProjectDir, new Set(['es', 'fr']));
|
|
56
|
+
expect(fs.existsSync(path.join(workspaceProjectDir, 'ai', 'intro.mdx'))).toBe(true);
|
|
57
|
+
expect(fs.existsSync(path.join(workspaceProjectDir, 'development', 'foo.mdx'))).toBe(true);
|
|
58
|
+
expect(fs.existsSync(path.join(workspaceProjectDir, 'docs.json'))).toBe(true);
|
|
59
|
+
expect(fs.existsSync(path.join(workspaceProjectDir, 'images', 'logo.png'))).toBe(true);
|
|
60
|
+
// Skipped:
|
|
61
|
+
expect(fs.existsSync(path.join(workspaceProjectDir, 'es'))).toBe(false);
|
|
62
|
+
expect(fs.existsSync(path.join(workspaceProjectDir, 'fr'))).toBe(false);
|
|
63
|
+
});
|
|
64
|
+
it('rebuilds the workspace links from scratch on subsequent calls', async () => {
|
|
65
|
+
// First call: no skip
|
|
66
|
+
await prepareProjectWorkspaceLinks(projectDir, workspaceProjectDir, new Set());
|
|
67
|
+
expect(fs.existsSync(path.join(workspaceProjectDir, 'es'))).toBe(true);
|
|
68
|
+
// Second call: skip es
|
|
69
|
+
await prepareProjectWorkspaceLinks(projectDir, workspaceProjectDir, new Set(['es']));
|
|
70
|
+
expect(fs.existsSync(path.join(workspaceProjectDir, 'es'))).toBe(false);
|
|
71
|
+
expect(fs.existsSync(path.join(workspaceProjectDir, 'fr'))).toBe(true);
|
|
72
|
+
expect(fs.existsSync(path.join(workspaceProjectDir, 'ai', 'intro.mdx'))).toBe(true);
|
|
73
|
+
});
|
|
74
|
+
it('handles a pre-existing single symlink at workspaceProjectDir (legacy layout)', async () => {
|
|
75
|
+
// Pre-create the legacy single-symlink layout
|
|
76
|
+
fs.mkdirpSync(path.dirname(workspaceProjectDir));
|
|
77
|
+
fs.symlinkSync(projectDir, workspaceProjectDir, 'junction');
|
|
78
|
+
await prepareProjectWorkspaceLinks(projectDir, workspaceProjectDir, new Set(['es', 'fr']));
|
|
79
|
+
const lstat = fs.lstatSync(workspaceProjectDir);
|
|
80
|
+
expect(lstat.isDirectory()).toBe(true);
|
|
81
|
+
expect(fs.existsSync(path.join(workspaceProjectDir, 'ai', 'intro.mdx'))).toBe(true);
|
|
82
|
+
expect(fs.existsSync(path.join(workspaceProjectDir, 'es'))).toBe(false);
|
|
83
|
+
});
|
|
84
|
+
it('surfaces friendly error (not raw stack trace) when fs.rm throws ENOTEMPTY', async () => {
|
|
85
|
+
// Regression: before safeRemoveCache, fs.remove raised an unfriendly stack
|
|
86
|
+
// trace when Turbopack still held open files. Now safeRemoveCache detects
|
|
87
|
+
// the race and calls process.exit(1) with a human-readable message.
|
|
88
|
+
const rmSpy = vi.spyOn(fs, 'rm');
|
|
89
|
+
const exitSpy = vi.spyOn(process, 'exit').mockImplementation(((code) => {
|
|
90
|
+
throw new Error(`process.exit:${code}`);
|
|
91
|
+
}));
|
|
92
|
+
const errorSpy = vi.spyOn(output, 'error').mockImplementation(() => undefined);
|
|
93
|
+
const enotempty = Object.assign(new Error('ENOTEMPTY'), { code: 'ENOTEMPTY' });
|
|
94
|
+
// fs.rm will be called by safeRemoveCache; make it fail with ENOTEMPTY
|
|
95
|
+
// even after the internal maxRetries — simulate persistent race condition.
|
|
96
|
+
rmSpy.mockRejectedValue(enotempty);
|
|
97
|
+
await expect(prepareProjectWorkspaceLinks(projectDir, workspaceProjectDir, new Set())).rejects.toThrow('process.exit:1');
|
|
98
|
+
const msg = errorSpy.mock.calls[0]?.[0] ?? '';
|
|
99
|
+
expect(msg).toContain('Another `jamdesk dev` instance');
|
|
100
|
+
expect(msg).toContain('pkill -f');
|
|
101
|
+
expect(exitSpy).toHaveBeenCalledWith(1);
|
|
102
|
+
vi.restoreAllMocks();
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
//# sourceMappingURL=dev-workspace-symlinks.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dev-workspace-symlinks.test.js","sourceRoot":"","sources":["../../../src/__tests__/unit/dev-workspace-symlinks.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACzE,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,CAAC;AAC5B,OAAO,EAAE,4BAA4B,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAE7C,QAAQ,CAAC,8BAA8B,EAAE,GAAG,EAAE;IAC5C,IAAI,OAAe,CAAC;IACpB,IAAI,UAAkB,CAAC;IACvB,IAAI,mBAA2B,CAAC;IAEhC,UAAU,CAAC,GAAG,EAAE;QACd,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC;QACzD,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QAC3C,mBAAmB,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;QAEtE,sEAAsE;QACtE,aAAa;QACb,sCAAsC;QACtC,uCAAuC;QACvC,mCAAmC;QACnC,kCAAkC;QAClC,gBAAgB;QAChB,sBAAsB;QACtB,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC;QAC3C,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,EAAE,WAAW,CAAC,EAAE,MAAM,CAAC,CAAC;QACnE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC,CAAC;QACpD,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,EAAE,SAAS,CAAC,EAAE,MAAM,CAAC,CAAC;QAC1E,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;QACjD,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,CAAC,EAAE,MAAM,CAAC,CAAC;QACzE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;QACjD,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,CAAC,EAAE,MAAM,CAAC,CAAC;QACzE,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,EAAE,IAAI,CAAC,CAAC;QAC3D,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC;QAC/C,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IACzB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE,KAAK,IAAI,EAAE;QACrE,MAAM,4BAA4B,CAAC,UAAU,EAAE,mBAAmB,EAAE,IAAI,GAAG,EAAU,CAAC,CAAC;QAEvF,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpF,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1F,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1F,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;QAC7D,MAAM,4BAA4B,CAAC,UAAU,EAAE,mBAAmB,EAAE,IAAI,GAAG,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;QAE3F,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpF,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,aAAa,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3F,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9E,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvF,WAAW;QACX,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxE,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+DAA+D,EAAE,KAAK,IAAI,EAAE;QAC7E,sBAAsB;QACtB,MAAM,4BAA4B,CAAC,UAAU,EAAE,mBAAmB,EAAE,IAAI,GAAG,EAAU,CAAC,CAAC;QACvF,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEvE,uBAAuB;QACvB,MAAM,4BAA4B,CAAC,UAAU,EAAE,mBAAmB,EAAE,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACrF,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxE,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvE,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8EAA8E,EAAE,KAAK,IAAI,EAAE;QAC5F,8CAA8C;QAC9C,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC,CAAC;QACjD,EAAE,CAAC,WAAW,CAAC,UAAU,EAAE,mBAAmB,EAAE,UAAU,CAAC,CAAC;QAE5D,MAAM,4BAA4B,CAAC,UAAU,EAAE,mBAAmB,EAAE,IAAI,GAAG,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;QAE3F,MAAM,KAAK,GAAG,EAAE,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;QAChD,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvC,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpF,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2EAA2E,EAAE,KAAK,IAAI,EAAE;QACzF,2EAA2E;QAC3E,0EAA0E;QAC1E,oEAAoE;QACpE,MAAM,KAAK,GAAG,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QACjC,MAAM,OAAO,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAa,EAAE,EAAE;YAC9E,MAAM,IAAI,KAAK,CAAC,gBAAgB,IAAI,EAAE,CAAC,CAAC;QAC1C,CAAC,CAAU,CAAC,CAAC;QACb,MAAM,QAAQ,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,kBAAkB,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAE/E,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,WAAW,CAAC,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;QAC/E,uEAAuE;QACvE,2EAA2E;QAC3E,KAAK,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC;QAEnC,MAAM,MAAM,CACV,4BAA4B,CAAC,UAAU,EAAE,mBAAmB,EAAE,IAAI,GAAG,EAAE,CAAC,CACzE,CAAC,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;QAEpC,MAAM,GAAG,GAAY,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAY,IAAI,EAAE,CAAC;QAClE,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,gCAAgC,CAAC,CAAC;QACxD,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QAClC,MAAM,CAAC,OAAO,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC;QAExC,EAAE,CAAC,eAAe,EAAE,CAAC;IACvB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"language-filter.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/unit/language-filter.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @vitest-environment node
|
|
3
|
+
*
|
|
4
|
+
* Tests for getActiveLanguageFilter — pure helper that decides which
|
|
5
|
+
* top-level language directories to skip when symlinking project content
|
|
6
|
+
* into the dev workspace. Multi-language sites' non-default languages
|
|
7
|
+
* inflate Turbopack's filesystem scan and balloon cold compile time
|
|
8
|
+
* (jamdesk-docs: 67s with 3 langs vs. 12.5s with 1 lang).
|
|
9
|
+
*/
|
|
10
|
+
import { describe, it, expect } from 'vitest';
|
|
11
|
+
import { getActiveLanguageFilter } from '../../lib/language-filter.js';
|
|
12
|
+
const config = (langs) => ({
|
|
13
|
+
navigation: { languages: langs.map(l => ({ language: l.language, default: l.default })) },
|
|
14
|
+
});
|
|
15
|
+
describe('getActiveLanguageFilter', () => {
|
|
16
|
+
it('returns null filter when project has no languages array', () => {
|
|
17
|
+
const result = getActiveLanguageFilter({ navigation: {} }, undefined, false);
|
|
18
|
+
expect(result).toEqual({ active: null, skip: new Set() });
|
|
19
|
+
});
|
|
20
|
+
it('returns null filter when project has only one language', () => {
|
|
21
|
+
const result = getActiveLanguageFilter(config([{ language: 'en', default: true }]), undefined, false);
|
|
22
|
+
expect(result).toEqual({ active: 'en', skip: new Set() });
|
|
23
|
+
});
|
|
24
|
+
it('skips non-default languages when active is the default', () => {
|
|
25
|
+
const result = getActiveLanguageFilter(config([
|
|
26
|
+
{ language: 'en', default: true },
|
|
27
|
+
{ language: 'es' },
|
|
28
|
+
{ language: 'fr' },
|
|
29
|
+
]), undefined, false);
|
|
30
|
+
expect(result.active).toBe('en');
|
|
31
|
+
expect(result.skip).toEqual(new Set(['es', 'fr']));
|
|
32
|
+
});
|
|
33
|
+
it('falls back to first language when none is marked default', () => {
|
|
34
|
+
const result = getActiveLanguageFilter(config([{ language: 'en' }, { language: 'es' }, { language: 'fr' }]), undefined, false);
|
|
35
|
+
expect(result.active).toBe('en');
|
|
36
|
+
expect(result.skip).toEqual(new Set(['es', 'fr']));
|
|
37
|
+
});
|
|
38
|
+
it('accepts --lang matching the default language (no-op equivalence)', () => {
|
|
39
|
+
const result = getActiveLanguageFilter(config([
|
|
40
|
+
{ language: 'en', default: true },
|
|
41
|
+
{ language: 'es' },
|
|
42
|
+
]), 'en', false);
|
|
43
|
+
expect(result.active).toBe('en');
|
|
44
|
+
expect(result.skip).toEqual(new Set(['es']));
|
|
45
|
+
});
|
|
46
|
+
it('throws on --lang for a non-default language (initial release scope)', () => {
|
|
47
|
+
// Non-default-language layouts mix root-level default-lang content with
|
|
48
|
+
// <lang>/ subdirs for translations; correctly stripping the default
|
|
49
|
+
// content while keeping <lang>/ takes more work and is deferred to a
|
|
50
|
+
// follow-up. For now, surface the workaround clearly.
|
|
51
|
+
expect(() => getActiveLanguageFilter(config([
|
|
52
|
+
{ language: 'en', default: true },
|
|
53
|
+
{ language: 'es' },
|
|
54
|
+
{ language: 'fr' },
|
|
55
|
+
]), 'es', false)).toThrow(/--lang es: previewing non-default languages.*--all-langs/i);
|
|
56
|
+
});
|
|
57
|
+
it('returns empty skip set when --all-langs is set', () => {
|
|
58
|
+
const result = getActiveLanguageFilter(config([
|
|
59
|
+
{ language: 'en', default: true },
|
|
60
|
+
{ language: 'es' },
|
|
61
|
+
]), undefined, true);
|
|
62
|
+
expect(result.active).toBe('en');
|
|
63
|
+
expect(result.skip).toEqual(new Set());
|
|
64
|
+
});
|
|
65
|
+
it('throws on --lang code that does not exist in docs.json', () => {
|
|
66
|
+
expect(() => getActiveLanguageFilter(config([{ language: 'en', default: true }, { language: 'es' }]), 'de', false)).toThrow(/--lang de.*not.*docs\.json.*Available: en, es/);
|
|
67
|
+
});
|
|
68
|
+
it('handles malformed languages array (entries missing language field) by ignoring them', () => {
|
|
69
|
+
const malformed = {
|
|
70
|
+
navigation: {
|
|
71
|
+
languages: [
|
|
72
|
+
{ language: 'en', default: true },
|
|
73
|
+
{ default: false }, // missing language: ignored
|
|
74
|
+
{ language: 'es' },
|
|
75
|
+
{ language: 42 }, // wrong type: ignored
|
|
76
|
+
],
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
const result = getActiveLanguageFilter(malformed, undefined, false);
|
|
80
|
+
expect(result.active).toBe('en');
|
|
81
|
+
expect(result.skip).toEqual(new Set(['es']));
|
|
82
|
+
});
|
|
83
|
+
it('returns null active when no valid language entries exist', () => {
|
|
84
|
+
const result = getActiveLanguageFilter({ navigation: { languages: [{ default: true }] } }, undefined, false);
|
|
85
|
+
expect(result).toEqual({ active: null, skip: new Set() });
|
|
86
|
+
});
|
|
87
|
+
it('rejects empty-string --lang as an invalid code (commander passes "" through)', () => {
|
|
88
|
+
// commander.js treats `--lang ""` as a value, not as missing — so
|
|
89
|
+
// langOption is "" (defined, but empty). Empty string is never a valid
|
|
90
|
+
// language code; surface it as a clear error rather than silently
|
|
91
|
+
// falling back to the default.
|
|
92
|
+
expect(() => getActiveLanguageFilter(config([{ language: 'en', default: true }, { language: 'es' }]), '', false)).toThrow(/--lang.*not.*docs\.json/);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
//# sourceMappingURL=language-filter.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"language-filter.test.js","sourceRoot":"","sources":["../../../src/__tests__/unit/language-filter.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -30,6 +30,10 @@ const SYNCED_FILES = [
|
|
|
30
30
|
// This file MUST be identical - it controls which languages are highlighted
|
|
31
31
|
// and which are passed through to special components like Mermaid
|
|
32
32
|
['build-service/lib/shiki-config.ts', 'cli/vendored/lib/shiki-config.ts'],
|
|
33
|
+
['build-service/lib/cache-tags.ts', 'cli/vendored/lib/cache-tags.ts'],
|
|
34
|
+
['build-service/lib/revalidation-helpers.ts', 'cli/vendored/lib/revalidation-helpers.ts'],
|
|
35
|
+
['build-service/lib/revalidation-trigger.ts', 'cli/vendored/lib/revalidation-trigger.ts'],
|
|
36
|
+
['build-service/lib/r2-manifest.ts', 'cli/vendored/lib/r2-manifest.ts'],
|
|
33
37
|
];
|
|
34
38
|
describe('CLI vendored files sync', () => {
|
|
35
39
|
it.each(SYNCED_FILES)('should have matching content: %s', async (buildServicePath, vendoredPath) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vendored-sync.test.js","sourceRoot":"","sources":["../../../src/__tests__/unit/vendored-sync.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAEpC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAE/D;;;;;;;;;GASG;AACH,MAAM,YAAY,GAAuB;IACvC,2EAA2E;IAC3E,4EAA4E;IAC5E,kEAAkE;IAClE,CAAC,mCAAmC,EAAE,kCAAkC,CAAC;
|
|
1
|
+
{"version":3,"file":"vendored-sync.test.js","sourceRoot":"","sources":["../../../src/__tests__/unit/vendored-sync.test.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/dev.d.ts
CHANGED
|
@@ -26,7 +26,19 @@ export interface DevOptions {
|
|
|
26
26
|
verbose: boolean;
|
|
27
27
|
webpack?: boolean;
|
|
28
28
|
clean?: boolean;
|
|
29
|
+
lang?: string;
|
|
30
|
+
allLangs?: boolean;
|
|
29
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* Returns the resolved (installed) Next.js version from
|
|
34
|
+
* `<depsDir>/node_modules/next/package.json`. Falls back to the
|
|
35
|
+
* declared pin in REQUIRED_DEPS when the file doesn't exist (first run
|
|
36
|
+
* before deps install, though ensureDependencies runs earlier so this
|
|
37
|
+
* path is defensive).
|
|
38
|
+
*
|
|
39
|
+
* Exported for unit testing.
|
|
40
|
+
*/
|
|
41
|
+
export declare function getInstalledNextVersion(depsDir: string): Promise<string>;
|
|
30
42
|
/**
|
|
31
43
|
* Sync vendored files to workspace, only copying files that changed.
|
|
32
44
|
* This preserves file timestamps for unchanged files, allowing Turbopack
|
|
@@ -38,11 +50,44 @@ export declare function syncVendoredFiles(srcDir: string, destDir: string, filte
|
|
|
38
50
|
removed: number;
|
|
39
51
|
}>;
|
|
40
52
|
/**
|
|
41
|
-
* Validates the .next cache and
|
|
42
|
-
* Returns true if cache is valid and
|
|
53
|
+
* Validates the .next cache and clears it when reuse would be unsafe.
|
|
54
|
+
* Returns true if cache is valid and reusable, false if it was cleared.
|
|
55
|
+
*
|
|
56
|
+
* Wipe conditions:
|
|
57
|
+
* - Next.js version changed (Turbopack persistent-cache encoding may
|
|
58
|
+
* have changed; safest to start fresh)
|
|
59
|
+
* - Workspace corruption (turbopack cache exists but app/ does not —
|
|
60
|
+
* happens when a previous dev session was killed mid-prep)
|
|
61
|
+
* - First-ever run with a pre-existing cache but no version files
|
|
62
|
+
* (cache predates version tracking; can't verify compatibility)
|
|
63
|
+
*
|
|
64
|
+
* Preserve conditions (everything else, in particular):
|
|
65
|
+
* - CLI version changed but Next.js version is the same. Turbopack's
|
|
66
|
+
* content-addressed cache invalidates per-file when syncVendoredFiles
|
|
67
|
+
* copies changed vendored files; we don't need a wipe.
|
|
68
|
+
*
|
|
69
|
+
* Exported for unit testing.
|
|
70
|
+
*/
|
|
71
|
+
export interface ValidateCacheOptions {
|
|
72
|
+
nextCacheDir: string;
|
|
73
|
+
cliVersionFile: string;
|
|
74
|
+
nextVersionFile: string;
|
|
75
|
+
workspaceDir: string;
|
|
76
|
+
currentNextVersion: string;
|
|
77
|
+
verbose: boolean;
|
|
78
|
+
}
|
|
79
|
+
export declare function validateAndCleanCache(opts: ValidateCacheOptions): Promise<boolean>;
|
|
80
|
+
/**
|
|
81
|
+
* Prepares <workspace>/projects/<name>/ as a directory with per-entry symlinks
|
|
82
|
+
* to the real <projectDir>/. Skip set entries are omitted — used to keep
|
|
83
|
+
* non-active-language directories out of Turbopack's filesystem scan, which
|
|
84
|
+
* scales linearly with file count. See docs/plans/2026-04-29-jamdesk-dev-compile-perf.md.
|
|
85
|
+
*
|
|
86
|
+
* Always rebuilds from scratch (cheap; only symlinks). Handles legacy
|
|
87
|
+
* single-symlink layout (CLI ≤1.1.42) by replacing it with the new layout.
|
|
43
88
|
*
|
|
44
89
|
* Exported for unit testing.
|
|
45
90
|
*/
|
|
46
|
-
export declare function
|
|
91
|
+
export declare function prepareProjectWorkspaceLinks(projectDir: string, workspaceProjectDir: string, skip: Set<string>): Promise<void>;
|
|
47
92
|
export declare function dev(options: DevOptions): Promise<void>;
|
|
48
93
|
//# sourceMappingURL=dev.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/commands/dev.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/commands/dev.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA0BH;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAO/E;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAqCD;;;;;;;;GAQG;AACH,wBAAsB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAO9E;AA+GD;;;;GAIG;AAGH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,GACxC,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAuE/D;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,oBAAoB;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,oBAAoB,GACzB,OAAO,CAAC,OAAO,CAAC,CA4DlB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,4BAA4B,CAChD,UAAU,EAAE,MAAM,EAClB,mBAAmB,EAAE,MAAM,EAC3B,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,GAChB,OAAO,CAAC,IAAI,CAAC,CAiBf;AAED,wBAAsB,GAAG,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAsvB5D"}
|