jamdesk 1.1.97 → 1.1.99
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/dist/__tests__/integration/migrate.integration.test.js +17 -0
- package/dist/__tests__/integration/migrate.integration.test.js.map +1 -1
- package/dist/__tests__/unit/deps-sync.test.js +4 -1
- package/dist/__tests__/unit/deps-sync.test.js.map +1 -1
- package/dist/__tests__/unit/docs-config.test.js +31 -0
- package/dist/__tests__/unit/docs-config.test.js.map +1 -1
- package/dist/__tests__/unit/migrate-convert.test.js +91 -0
- package/dist/__tests__/unit/migrate-convert.test.js.map +1 -1
- package/dist/__tests__/unit/migrate-detect.test.js +49 -2
- package/dist/__tests__/unit/migrate-detect.test.js.map +1 -1
- package/dist/__tests__/unit/migrate-resolve-theme.test.d.ts +2 -0
- package/dist/__tests__/unit/migrate-resolve-theme.test.d.ts.map +1 -0
- package/dist/__tests__/unit/migrate-resolve-theme.test.js +29 -0
- package/dist/__tests__/unit/migrate-resolve-theme.test.js.map +1 -0
- package/dist/__tests__/unit/openapi-license-identifier.test.d.ts +2 -0
- package/dist/__tests__/unit/openapi-license-identifier.test.d.ts.map +1 -0
- package/dist/__tests__/unit/openapi-license-identifier.test.js +42 -0
- package/dist/__tests__/unit/openapi-license-identifier.test.js.map +1 -0
- package/dist/__tests__/unit/openapi-schema-patch-sync.test.d.ts +2 -0
- package/dist/__tests__/unit/openapi-schema-patch-sync.test.d.ts.map +1 -0
- package/dist/__tests__/unit/openapi-schema-patch-sync.test.js +56 -0
- package/dist/__tests__/unit/openapi-schema-patch-sync.test.js.map +1 -0
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +7 -1
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/migrate/convert.d.ts +2 -1
- package/dist/commands/migrate/convert.d.ts.map +1 -1
- package/dist/commands/migrate/convert.js +30 -2
- package/dist/commands/migrate/convert.js.map +1 -1
- package/dist/commands/migrate/detect.d.ts +6 -0
- package/dist/commands/migrate/detect.d.ts.map +1 -1
- package/dist/commands/migrate/detect.js +32 -0
- package/dist/commands/migrate/detect.js.map +1 -1
- package/dist/commands/migrate/index.d.ts +7 -1
- package/dist/commands/migrate/index.d.ts.map +1 -1
- package/dist/commands/migrate/index.js +37 -17
- package/dist/commands/migrate/index.js.map +1 -1
- package/dist/commands/validate.d.ts.map +1 -1
- package/dist/commands/validate.js +5 -1
- package/dist/commands/validate.js.map +1 -1
- package/dist/lib/deps.d.ts +27 -19
- package/dist/lib/deps.d.ts.map +1 -1
- package/dist/lib/deps.js +41 -30
- package/dist/lib/deps.js.map +1 -1
- package/dist/lib/docs-config.d.ts +16 -0
- package/dist/lib/docs-config.d.ts.map +1 -1
- package/dist/lib/docs-config.js +25 -0
- package/dist/lib/docs-config.js.map +1 -1
- package/dist/lib/output.d.ts +8 -0
- package/dist/lib/output.d.ts.map +1 -1
- package/dist/lib/output.js +15 -0
- package/dist/lib/output.js.map +1 -1
- package/package.json +1 -1
- package/scripts/patch-openapi-schemas.js +52 -32
- package/vendored/components/navigation/Sidebar.tsx +1 -1
- package/vendored/lib/navigation-resolver.ts +15 -0
- package/vendored/workspace-package-lock.json +15 -15
- package/dist/__tests__/unit/dev-workspace-symlinks.test.d.ts +0 -2
- package/dist/__tests__/unit/dev-workspace-symlinks.test.d.ts.map +0 -1
- package/dist/__tests__/unit/dev-workspace-symlinks.test.js +0 -112
- package/dist/__tests__/unit/dev-workspace-symlinks.test.js.map +0 -1
- package/dist/__tests__/unit/language-filter.test.d.ts +0 -2
- package/dist/__tests__/unit/language-filter.test.d.ts.map +0 -1
- package/dist/__tests__/unit/language-filter.test.js +0 -166
- package/dist/__tests__/unit/language-filter.test.js.map +0 -1
- package/dist/__tests__/unit/output.test.d.ts +0 -2
- package/dist/__tests__/unit/output.test.d.ts.map +0 -1
- package/dist/__tests__/unit/output.test.js +0 -61
- package/dist/__tests__/unit/output.test.js.map +0 -1
- package/dist/lib/language-filter.d.ts +0 -31
- package/dist/lib/language-filter.d.ts.map +0 -1
- package/dist/lib/language-filter.js +0 -14
- package/dist/lib/language-filter.js.map +0 -1
|
@@ -1,24 +1,31 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* Patch
|
|
3
|
+
* Patch two defects in @apidevtools/openapi-schemas@2.1.0's bundled
|
|
4
|
+
* OpenAPI 3.1 meta-schema. Both are idempotent and self-cleaning once
|
|
5
|
+
* upstream ships fixes (https://github.com/APIDevTools/openapi-schemas):
|
|
4
6
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* `description` field on a server variable is rejected with:
|
|
7
|
+
* 1. server-variable typo: `properties` declares `descriptions` (plural)
|
|
8
|
+
* instead of `description`. With `unevaluatedProperties: false` on the
|
|
9
|
+
* same def, a spec-valid `description` is rejected with:
|
|
10
|
+
* #/servers/0/variables/<name> must NOT have unevaluated properties
|
|
10
11
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
12
|
+
* 2. license over-constraint: the `license` def carries
|
|
13
|
+
* "oneOf": [ {"required":["identifier"]}, {"required":["url"]} ]
|
|
14
|
+
* which forces every license to have an `identifier` or a `url`. The
|
|
15
|
+
* OpenAPI 3.1 spec (§4.8.4) only requires `name`; `identifier` and
|
|
16
|
+
* `url` are optional and merely mutually exclusive. A `{ name }`-only
|
|
17
|
+
* license is valid (Mintlify accepts it; `jamdesk migrate`'s
|
|
18
|
+
* auto-discovered Mintlify starter spec uses `{ "name": "MIT" }`).
|
|
19
|
+
* The correct constraint is `not: { required: [identifier, url] }`.
|
|
18
20
|
*
|
|
19
21
|
* This file runs as an npm `postinstall` script in the package root, so
|
|
20
22
|
* `__dirname` is always `<package>/scripts/` and `node_modules` resolves
|
|
21
23
|
* one level up.
|
|
24
|
+
*
|
|
25
|
+
* The CLI's *workspace* install (~/.jamdesk) is patched separately and
|
|
26
|
+
* identically by patchWorkspaceOpenApiSchemas() in src/lib/deps.ts — if
|
|
27
|
+
* you change the patch logic here, mirror it there (and in
|
|
28
|
+
* build-service/scripts/patch-openapi-schemas.js).
|
|
22
29
|
*/
|
|
23
30
|
|
|
24
31
|
import fs from 'fs';
|
|
@@ -55,30 +62,45 @@ try {
|
|
|
55
62
|
process.exit(0);
|
|
56
63
|
}
|
|
57
64
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
+
/**
|
|
66
|
+
* Fix 1: server-variable `descriptions` -> `description`.
|
|
67
|
+
* Returns true if it changed the schema.
|
|
68
|
+
*/
|
|
69
|
+
function patchServerVariable(s) {
|
|
70
|
+
const props = s?.$defs?.['server-variable']?.properties;
|
|
71
|
+
if (!props) return false; // Shape changed upstream — leave alone.
|
|
72
|
+
if (props.description) return false; // Already patched / upstream fixed.
|
|
73
|
+
if (!props.descriptions) return false; // No typo to fix.
|
|
74
|
+
props.description = props.descriptions;
|
|
75
|
+
delete props.descriptions;
|
|
76
|
+
return true;
|
|
65
77
|
}
|
|
66
78
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
79
|
+
/**
|
|
80
|
+
* Fix 2: license over-constraint. Replace the bad `oneOf` with the
|
|
81
|
+
* spec-correct mutual-exclusivity guard. Returns true if it changed.
|
|
82
|
+
*/
|
|
83
|
+
function patchLicense(s) {
|
|
84
|
+
const license = s?.$defs?.license;
|
|
85
|
+
if (!license || typeof license !== 'object') return false;
|
|
86
|
+
if (!Array.isArray(license.oneOf)) return false; // Already patched / fixed.
|
|
87
|
+
delete license.oneOf;
|
|
88
|
+
license.not = { required: ['identifier', 'url'] };
|
|
89
|
+
return true;
|
|
70
90
|
}
|
|
71
91
|
|
|
72
|
-
|
|
73
|
-
|
|
92
|
+
const patched = [];
|
|
93
|
+
if (patchServerVariable(schema)) patched.push('server-variable typo (descriptions → description)');
|
|
94
|
+
if (patchLicense(schema)) patched.push('license oneOf → not(identifier+url)');
|
|
95
|
+
|
|
96
|
+
if (patched.length === 0) {
|
|
74
97
|
process.exit(0);
|
|
75
98
|
}
|
|
76
99
|
|
|
77
|
-
props.description = props.descriptions;
|
|
78
|
-
delete props.descriptions;
|
|
79
|
-
|
|
80
100
|
try {
|
|
81
|
-
|
|
101
|
+
// Trailing newline keeps this byte-identical to fs-extra's writeJson
|
|
102
|
+
// (jsonfile finalEOL) used by the runtime patch in src/lib/deps.ts.
|
|
103
|
+
fs.writeFileSync(schemaPath, JSON.stringify(schema, null, 2) + '\n');
|
|
82
104
|
} catch (err) {
|
|
83
105
|
console.warn(
|
|
84
106
|
'[jamdesk] patch-openapi-schemas: failed to write patch, skipping:',
|
|
@@ -86,6 +108,4 @@ try {
|
|
|
86
108
|
);
|
|
87
109
|
process.exit(0);
|
|
88
110
|
}
|
|
89
|
-
console.log(
|
|
90
|
-
'[jamdesk] patched openapi-schemas 3.1 server-variable typo (descriptions → description)'
|
|
91
|
-
);
|
|
111
|
+
console.log(`[jamdesk] patched openapi-schemas 3.1: ${patched.join('; ')}`);
|
|
@@ -539,7 +539,7 @@ export function Sidebar({ config, layout = 'header-logo', tabsPosition: tabsPosi
|
|
|
539
539
|
<div className="flex flex-col gap-1 px-4 pt-4">
|
|
540
540
|
{resolvedNav.externalAnchors.map((anchor) => (
|
|
541
541
|
<a
|
|
542
|
-
key={anchor.name}
|
|
542
|
+
key={`${anchor.href}|${anchor.name}`}
|
|
543
543
|
href={anchor.href}
|
|
544
544
|
target="_blank"
|
|
545
545
|
rel="noopener noreferrer"
|
|
@@ -460,6 +460,21 @@ export function resolveNavigation(
|
|
|
460
460
|
}
|
|
461
461
|
}
|
|
462
462
|
|
|
463
|
+
// Dedupe exact (name+href) repeats. `jamdesk migrate` historically emitted
|
|
464
|
+
// external anchors in BOTH config.anchors and navigation.global.anchors, so
|
|
465
|
+
// the resolver would otherwise return the same link twice. Keyed on
|
|
466
|
+
// name+href (not name alone) so two genuinely distinct anchors that share a
|
|
467
|
+
// label are preserved — Sidebar.tsx keys them by href|name, so distinct
|
|
468
|
+
// hrefs no longer collide as React keys. First occurrence wins, so
|
|
469
|
+
// top-level config.anchors takes precedence over global.anchors.
|
|
470
|
+
const seenAnchors = new Set<string>();
|
|
471
|
+
result.externalAnchors = result.externalAnchors.filter((anchor) => {
|
|
472
|
+
const dedupeKey = `${anchor.name}\0${anchor.href}`;
|
|
473
|
+
if (seenAnchors.has(dedupeKey)) return false;
|
|
474
|
+
seenAnchors.add(dedupeKey);
|
|
475
|
+
return true;
|
|
476
|
+
});
|
|
477
|
+
|
|
463
478
|
// Resolve top-level tabs
|
|
464
479
|
if (navigation.tabs) {
|
|
465
480
|
result.tabs = navigation.tabs.map(resolveTab);
|
|
@@ -1921,9 +1921,9 @@
|
|
|
1921
1921
|
}
|
|
1922
1922
|
},
|
|
1923
1923
|
"node_modules/@types/node": {
|
|
1924
|
-
"version": "25.
|
|
1925
|
-
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.
|
|
1926
|
-
"integrity": "sha512-
|
|
1924
|
+
"version": "25.9.0",
|
|
1925
|
+
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.0.tgz",
|
|
1926
|
+
"integrity": "sha512-AOQwYUNolgy3VosiRqXrACUXTN8nJUtPl7FJXMqZVyxiiCLhQuG3jXKvCS1ALr+Y2OmZhzzLVlYPEqJaiqkaJQ==",
|
|
1927
1927
|
"license": "MIT",
|
|
1928
1928
|
"dependencies": {
|
|
1929
1929
|
"undici-types": ">=7.24.0 <7.24.7"
|
|
@@ -2134,9 +2134,9 @@
|
|
|
2134
2134
|
}
|
|
2135
2135
|
},
|
|
2136
2136
|
"node_modules/baseline-browser-mapping": {
|
|
2137
|
-
"version": "2.10.
|
|
2138
|
-
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.
|
|
2139
|
-
"integrity": "sha512-
|
|
2137
|
+
"version": "2.10.31",
|
|
2138
|
+
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.31.tgz",
|
|
2139
|
+
"integrity": "sha512-MujYO3eP72uvmSE0i4wltsodRfIpZATP3jvzRNRGGxgzId7aVocVJJV3nf01qnzzKFGxQVC9bpWxl5cjxTr/7Q==",
|
|
2140
2140
|
"license": "Apache-2.0",
|
|
2141
2141
|
"bin": {
|
|
2142
2142
|
"baseline-browser-mapping": "dist/cli.cjs"
|
|
@@ -2913,9 +2913,9 @@
|
|
|
2913
2913
|
}
|
|
2914
2914
|
},
|
|
2915
2915
|
"node_modules/dompurify": {
|
|
2916
|
-
"version": "3.4.
|
|
2917
|
-
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.
|
|
2918
|
-
"integrity": "sha512-
|
|
2916
|
+
"version": "3.4.5",
|
|
2917
|
+
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.5.tgz",
|
|
2918
|
+
"integrity": "sha512-OrwIBKsdNSVEeubdJ1HBv/wNENRM9ytAVCv7YXt//A3vPdVMNuACRqK9mXCGCBW2ln7BT/A4X0jXHo2Gu89miA==",
|
|
2919
2919
|
"license": "(MPL-2.0 OR Apache-2.0)",
|
|
2920
2920
|
"optionalDependencies": {
|
|
2921
2921
|
"@types/trusted-types": "^2.0.7"
|
|
@@ -2934,9 +2934,9 @@
|
|
|
2934
2934
|
"license": "ISC"
|
|
2935
2935
|
},
|
|
2936
2936
|
"node_modules/enhanced-resolve": {
|
|
2937
|
-
"version": "5.21.
|
|
2938
|
-
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.21.
|
|
2939
|
-
"integrity": "sha512-
|
|
2937
|
+
"version": "5.21.4",
|
|
2938
|
+
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.21.4.tgz",
|
|
2939
|
+
"integrity": "sha512-wE4fDO8OjJhrPFH69HUQStq5oKvGRTNXEyW+k5C/pUQLASSsTu7obd2V3GvCDgPcY9AWjhJ4jz9Kh7iRvrxhJg==",
|
|
2940
2940
|
"license": "MIT",
|
|
2941
2941
|
"dependencies": {
|
|
2942
2942
|
"graceful-fs": "^4.2.4",
|
|
@@ -4067,9 +4067,9 @@
|
|
|
4067
4067
|
}
|
|
4068
4068
|
},
|
|
4069
4069
|
"node_modules/lru-cache": {
|
|
4070
|
-
"version": "11.
|
|
4071
|
-
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.
|
|
4072
|
-
"integrity": "sha512-
|
|
4070
|
+
"version": "11.4.0",
|
|
4071
|
+
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.4.0.tgz",
|
|
4072
|
+
"integrity": "sha512-W+R+kFL4HgVxONq2bhXPi3bGpzGe/yEhVOp233qw9wCRtgncJ15P3bC+e4zZMu4Cq7d+WAJjXGW0uUkifhcatA==",
|
|
4073
4073
|
"license": "BlueOak-1.0.0",
|
|
4074
4074
|
"engines": {
|
|
4075
4075
|
"node": "20 || >=22"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"dev-workspace-symlinks.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/unit/dev-workspace-symlinks.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,112 +0,0 @@
|
|
|
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
|
-
});
|
|
53
|
-
it('does not symlink docs.json (caller writes a filtered copy)', async () => {
|
|
54
|
-
// docs.json must not be symlinked — the caller writes a per-language
|
|
55
|
-
// filtered copy, and fs.writeFile through a symlink would clobber the
|
|
56
|
-
// user's source docs.json.
|
|
57
|
-
await prepareProjectWorkspaceLinks(projectDir, workspaceProjectDir, new Set());
|
|
58
|
-
expect(fs.existsSync(path.join(workspaceProjectDir, 'docs.json'))).toBe(false);
|
|
59
|
-
});
|
|
60
|
-
it('skips entries whose names are in the skip set', async () => {
|
|
61
|
-
await prepareProjectWorkspaceLinks(projectDir, workspaceProjectDir, new Set(['es', 'fr']));
|
|
62
|
-
expect(fs.existsSync(path.join(workspaceProjectDir, 'ai', 'intro.mdx'))).toBe(true);
|
|
63
|
-
expect(fs.existsSync(path.join(workspaceProjectDir, 'development', 'foo.mdx'))).toBe(true);
|
|
64
|
-
expect(fs.existsSync(path.join(workspaceProjectDir, 'images', 'logo.png'))).toBe(true);
|
|
65
|
-
// Skipped:
|
|
66
|
-
expect(fs.existsSync(path.join(workspaceProjectDir, 'es'))).toBe(false);
|
|
67
|
-
expect(fs.existsSync(path.join(workspaceProjectDir, 'fr'))).toBe(false);
|
|
68
|
-
// docs.json not symlinked — caller writes a filtered copy.
|
|
69
|
-
expect(fs.existsSync(path.join(workspaceProjectDir, 'docs.json'))).toBe(false);
|
|
70
|
-
});
|
|
71
|
-
it('rebuilds the workspace links from scratch on subsequent calls', async () => {
|
|
72
|
-
// First call: no skip
|
|
73
|
-
await prepareProjectWorkspaceLinks(projectDir, workspaceProjectDir, new Set());
|
|
74
|
-
expect(fs.existsSync(path.join(workspaceProjectDir, 'es'))).toBe(true);
|
|
75
|
-
// Second call: skip es
|
|
76
|
-
await prepareProjectWorkspaceLinks(projectDir, workspaceProjectDir, new Set(['es']));
|
|
77
|
-
expect(fs.existsSync(path.join(workspaceProjectDir, 'es'))).toBe(false);
|
|
78
|
-
expect(fs.existsSync(path.join(workspaceProjectDir, 'fr'))).toBe(true);
|
|
79
|
-
expect(fs.existsSync(path.join(workspaceProjectDir, 'ai', 'intro.mdx'))).toBe(true);
|
|
80
|
-
});
|
|
81
|
-
it('handles a pre-existing single symlink at workspaceProjectDir (legacy layout)', async () => {
|
|
82
|
-
// Pre-create the legacy single-symlink layout
|
|
83
|
-
fs.mkdirpSync(path.dirname(workspaceProjectDir));
|
|
84
|
-
fs.symlinkSync(projectDir, workspaceProjectDir, 'junction');
|
|
85
|
-
await prepareProjectWorkspaceLinks(projectDir, workspaceProjectDir, new Set(['es', 'fr']));
|
|
86
|
-
const lstat = fs.lstatSync(workspaceProjectDir);
|
|
87
|
-
expect(lstat.isDirectory()).toBe(true);
|
|
88
|
-
expect(fs.existsSync(path.join(workspaceProjectDir, 'ai', 'intro.mdx'))).toBe(true);
|
|
89
|
-
expect(fs.existsSync(path.join(workspaceProjectDir, 'es'))).toBe(false);
|
|
90
|
-
});
|
|
91
|
-
it('surfaces friendly error (not raw stack trace) when fs.rm throws ENOTEMPTY', async () => {
|
|
92
|
-
// Regression: before safeRemoveCache, fs.remove raised an unfriendly stack
|
|
93
|
-
// trace when Turbopack still held open files. Now safeRemoveCache detects
|
|
94
|
-
// the race and calls process.exit(1) with a human-readable message.
|
|
95
|
-
const rmSpy = vi.spyOn(fs, 'rm');
|
|
96
|
-
const exitSpy = vi.spyOn(process, 'exit').mockImplementation(((code) => {
|
|
97
|
-
throw new Error(`process.exit:${code}`);
|
|
98
|
-
}));
|
|
99
|
-
const errorSpy = vi.spyOn(output, 'error').mockImplementation(() => undefined);
|
|
100
|
-
const enotempty = Object.assign(new Error('ENOTEMPTY'), { code: 'ENOTEMPTY' });
|
|
101
|
-
// fs.rm will be called by safeRemoveCache; make it fail with ENOTEMPTY
|
|
102
|
-
// even after the internal maxRetries — simulate persistent race condition.
|
|
103
|
-
rmSpy.mockRejectedValue(enotempty);
|
|
104
|
-
await expect(prepareProjectWorkspaceLinks(projectDir, workspaceProjectDir, new Set())).rejects.toThrow('process.exit:1');
|
|
105
|
-
const msg = errorSpy.mock.calls[0]?.[0] ?? '';
|
|
106
|
-
expect(msg).toContain('Another `jamdesk dev` instance');
|
|
107
|
-
expect(msg).toContain('pkill -f');
|
|
108
|
-
expect(exitSpy).toHaveBeenCalledWith(1);
|
|
109
|
-
vi.restoreAllMocks();
|
|
110
|
-
});
|
|
111
|
-
});
|
|
112
|
-
//# sourceMappingURL=dev-workspace-symlinks.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"dev-workspace-symlinks.test.js","sourceRoot":"","sources":["../../../src/__tests__/unit/dev-workspace-symlinks.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"language-filter.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/unit/language-filter.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,166 +0,0 @@
|
|
|
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, isPageInSkippedLanguage, filterConfigByActiveLanguage, } 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
|
-
describe('isPageInSkippedLanguage', () => {
|
|
96
|
-
it('returns false when skip set is empty', () => {
|
|
97
|
-
expect(isPageInSkippedLanguage('fr/introduction', new Set())).toBe(false);
|
|
98
|
-
});
|
|
99
|
-
it('returns true when first path segment is a skipped language', () => {
|
|
100
|
-
expect(isPageInSkippedLanguage('fr/introduction', new Set(['fr']))).toBe(true);
|
|
101
|
-
});
|
|
102
|
-
it('returns true for nested paths inside a skipped language', () => {
|
|
103
|
-
expect(isPageInSkippedLanguage('fr/setup/connecting-github', new Set(['fr', 'de']))).toBe(true);
|
|
104
|
-
});
|
|
105
|
-
it('returns false when first segment is the active language', () => {
|
|
106
|
-
expect(isPageInSkippedLanguage('en/introduction', new Set(['fr']))).toBe(false);
|
|
107
|
-
});
|
|
108
|
-
it('returns false for unprefixed root pages', () => {
|
|
109
|
-
expect(isPageInSkippedLanguage('introduction', new Set(['fr']))).toBe(false);
|
|
110
|
-
});
|
|
111
|
-
it('does not match when the skip code is a prefix-substring of a different segment', () => {
|
|
112
|
-
// Guard against startsWith('fr/') matching e.g. 'fr-something/foo'
|
|
113
|
-
expect(isPageInSkippedLanguage('fr-something/foo', new Set(['fr']))).toBe(false);
|
|
114
|
-
});
|
|
115
|
-
it('returns true for a path with a fragment anchor in a skipped language', () => {
|
|
116
|
-
// Broken-anchor warnings from validate-links.cjs surface as link values
|
|
117
|
-
// like `fr/introduction#missing-section` — the fragment lives past the
|
|
118
|
-
// first segment so the language check still works.
|
|
119
|
-
expect(isPageInSkippedLanguage('fr/introduction#setup', new Set(['fr']))).toBe(true);
|
|
120
|
-
});
|
|
121
|
-
});
|
|
122
|
-
describe('filterConfigByActiveLanguage', () => {
|
|
123
|
-
it('returns the input unchanged (same reference) when skip is empty', () => {
|
|
124
|
-
const config = { name: 'foo', navigation: { languages: [{ language: 'en' }] } };
|
|
125
|
-
const result = filterConfigByActiveLanguage(config, { active: 'en', skip: new Set() });
|
|
126
|
-
expect(result).toBe(config);
|
|
127
|
-
});
|
|
128
|
-
it('drops skipped languages from navigation.languages', () => {
|
|
129
|
-
const config = {
|
|
130
|
-
name: 'jamdesk-docs',
|
|
131
|
-
navigation: {
|
|
132
|
-
languages: [
|
|
133
|
-
{ language: 'en', default: true, tabs: [{ tab: 'Guide' }] },
|
|
134
|
-
{ language: 'fr', tabs: [{ tab: 'Guide' }] },
|
|
135
|
-
{ language: 'de', tabs: [{ tab: 'Guide' }] },
|
|
136
|
-
],
|
|
137
|
-
},
|
|
138
|
-
};
|
|
139
|
-
const result = filterConfigByActiveLanguage(config, {
|
|
140
|
-
active: 'en',
|
|
141
|
-
skip: new Set(['fr', 'de']),
|
|
142
|
-
});
|
|
143
|
-
expect(result.navigation.languages).toEqual([
|
|
144
|
-
{ language: 'en', default: true, tabs: [{ tab: 'Guide' }] },
|
|
145
|
-
]);
|
|
146
|
-
// Top-level fields preserved.
|
|
147
|
-
expect(result.name).toBe('jamdesk-docs');
|
|
148
|
-
// Original config untouched.
|
|
149
|
-
expect(config.navigation.languages).toHaveLength(3);
|
|
150
|
-
});
|
|
151
|
-
it('preserves other navigation fields (tabs, global, anchors, etc.)', () => {
|
|
152
|
-
const config = {
|
|
153
|
-
navigation: {
|
|
154
|
-
languages: [{ language: 'en' }, { language: 'fr' }],
|
|
155
|
-
global: { anchors: [{ anchor: 'Support' }] },
|
|
156
|
-
},
|
|
157
|
-
};
|
|
158
|
-
const result = filterConfigByActiveLanguage(config, {
|
|
159
|
-
active: 'en',
|
|
160
|
-
skip: new Set(['fr']),
|
|
161
|
-
});
|
|
162
|
-
expect(result.navigation.global).toEqual({ anchors: [{ anchor: 'Support' }] });
|
|
163
|
-
expect(result.navigation.languages).toHaveLength(1);
|
|
164
|
-
});
|
|
165
|
-
});
|
|
166
|
-
//# sourceMappingURL=language-filter.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"language-filter.test.js","sourceRoot":"","sources":["../../../src/__tests__/unit/language-filter.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"output.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/unit/output.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @vitest-environment node
|
|
3
|
-
*
|
|
4
|
-
* Unit tests for output.runWithSlowHint. Covers the close race where
|
|
5
|
-
* the timer fires on the same tick as the work resolving — `done`
|
|
6
|
-
* must short-circuit the callback to avoid a stale hint after success.
|
|
7
|
-
*/
|
|
8
|
-
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
9
|
-
import { output } from '../../lib/output.js';
|
|
10
|
-
describe('output.runWithSlowHint', () => {
|
|
11
|
-
beforeEach(() => {
|
|
12
|
-
vi.useFakeTimers();
|
|
13
|
-
});
|
|
14
|
-
afterEach(() => {
|
|
15
|
-
vi.useRealTimers();
|
|
16
|
-
});
|
|
17
|
-
it('does not fire onSlow when work resolves before the threshold', async () => {
|
|
18
|
-
const onSlow = vi.fn();
|
|
19
|
-
const promise = output.runWithSlowHint(1000, onSlow, async () => {
|
|
20
|
-
await new Promise((r) => setTimeout(r, 500));
|
|
21
|
-
return 'done';
|
|
22
|
-
});
|
|
23
|
-
await vi.advanceTimersByTimeAsync(500);
|
|
24
|
-
const result = await promise;
|
|
25
|
-
expect(result).toBe('done');
|
|
26
|
-
expect(onSlow).not.toHaveBeenCalled();
|
|
27
|
-
// Run any pending timers to confirm the hint stays suppressed even
|
|
28
|
-
// if the cleanup happened to lose the clearTimeout race.
|
|
29
|
-
await vi.advanceTimersByTimeAsync(2000);
|
|
30
|
-
expect(onSlow).not.toHaveBeenCalled();
|
|
31
|
-
});
|
|
32
|
-
it('fires onSlow exactly once when work runs past the threshold', async () => {
|
|
33
|
-
const onSlow = vi.fn();
|
|
34
|
-
const promise = output.runWithSlowHint(1000, onSlow, async () => {
|
|
35
|
-
await new Promise((r) => setTimeout(r, 3000));
|
|
36
|
-
return 42;
|
|
37
|
-
});
|
|
38
|
-
await vi.advanceTimersByTimeAsync(1000);
|
|
39
|
-
expect(onSlow).toHaveBeenCalledTimes(1);
|
|
40
|
-
await vi.advanceTimersByTimeAsync(2000);
|
|
41
|
-
const result = await promise;
|
|
42
|
-
expect(result).toBe(42);
|
|
43
|
-
expect(onSlow).toHaveBeenCalledTimes(1);
|
|
44
|
-
});
|
|
45
|
-
it('clears the timer when work rejects', async () => {
|
|
46
|
-
const onSlow = vi.fn();
|
|
47
|
-
const error = new Error('boom');
|
|
48
|
-
const promise = output.runWithSlowHint(1000, onSlow, async () => {
|
|
49
|
-
throw error;
|
|
50
|
-
});
|
|
51
|
-
await expect(promise).rejects.toBe(error);
|
|
52
|
-
await vi.advanceTimersByTimeAsync(2000);
|
|
53
|
-
expect(onSlow).not.toHaveBeenCalled();
|
|
54
|
-
});
|
|
55
|
-
it('returns the work result through to the caller', async () => {
|
|
56
|
-
const onSlow = vi.fn();
|
|
57
|
-
const result = await output.runWithSlowHint(1000, onSlow, async () => ({ a: 1 }));
|
|
58
|
-
expect(result).toEqual({ a: 1 });
|
|
59
|
-
});
|
|
60
|
-
});
|
|
61
|
-
//# sourceMappingURL=output.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"output.test.js","sourceRoot":"","sources":["../../../src/__tests__/unit/output.test.ts"],"names":[],"mappings":"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"}
|