jamdesk 1.1.69 → 1.1.71
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/validate.integration.test.js +21 -0
- package/dist/__tests__/integration/validate.integration.test.js.map +1 -1
- package/dist/__tests__/unit/extract-hooks.test.js +102 -1
- package/dist/__tests__/unit/extract-hooks.test.js.map +1 -1
- package/dist/__tests__/unit/mdx-validator.test.js +22 -0
- package/dist/__tests__/unit/mdx-validator.test.js.map +1 -1
- package/dist/__tests__/unit/migrate-mdx.test.js +121 -1
- package/dist/__tests__/unit/migrate-mdx.test.js.map +1 -1
- package/dist/__tests__/unit/relative-mdx-imports.test.d.ts +2 -0
- package/dist/__tests__/unit/relative-mdx-imports.test.d.ts.map +1 -0
- package/dist/__tests__/unit/relative-mdx-imports.test.js +452 -0
- package/dist/__tests__/unit/relative-mdx-imports.test.js.map +1 -0
- package/dist/__tests__/unit/relocate-snippets.test.d.ts +2 -0
- package/dist/__tests__/unit/relocate-snippets.test.d.ts.map +1 -0
- package/dist/__tests__/unit/relocate-snippets.test.js +542 -0
- package/dist/__tests__/unit/relocate-snippets.test.js.map +1 -0
- package/dist/__tests__/unit/run-build-script.test.js +23 -1
- package/dist/__tests__/unit/run-build-script.test.js.map +1 -1
- package/dist/__tests__/unit/warn-relative-imports.test.d.ts +2 -0
- package/dist/__tests__/unit/warn-relative-imports.test.d.ts.map +1 -0
- package/dist/__tests__/unit/warn-relative-imports.test.js +44 -0
- package/dist/__tests__/unit/warn-relative-imports.test.js.map +1 -0
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +22 -8
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/migrate/convert-mdx.d.ts +5 -1
- package/dist/commands/migrate/convert-mdx.d.ts.map +1 -1
- package/dist/commands/migrate/convert-mdx.js +19 -6
- package/dist/commands/migrate/convert-mdx.js.map +1 -1
- package/dist/commands/migrate/extract-hooks.d.ts +26 -0
- package/dist/commands/migrate/extract-hooks.d.ts.map +1 -1
- package/dist/commands/migrate/extract-hooks.js +71 -12
- package/dist/commands/migrate/extract-hooks.js.map +1 -1
- package/dist/commands/migrate/fix-mdx-syntax.d.ts +38 -0
- package/dist/commands/migrate/fix-mdx-syntax.d.ts.map +1 -0
- package/dist/commands/migrate/fix-mdx-syntax.js +80 -0
- package/dist/commands/migrate/fix-mdx-syntax.js.map +1 -0
- package/dist/commands/migrate/index.d.ts.map +1 -1
- package/dist/commands/migrate/index.js +165 -3
- package/dist/commands/migrate/index.js.map +1 -1
- package/dist/commands/migrate/relocate-snippets.d.ts +30 -0
- package/dist/commands/migrate/relocate-snippets.d.ts.map +1 -0
- package/dist/commands/migrate/relocate-snippets.js +357 -0
- package/dist/commands/migrate/relocate-snippets.js.map +1 -0
- package/dist/commands/validate.d.ts.map +1 -1
- package/dist/commands/validate.js +31 -1
- package/dist/commands/validate.js.map +1 -1
- package/dist/lib/mdx-syntax-fixes.d.ts +14 -0
- package/dist/lib/mdx-syntax-fixes.d.ts.map +1 -0
- package/dist/lib/mdx-syntax-fixes.js +38 -0
- package/dist/lib/mdx-syntax-fixes.js.map +1 -0
- package/dist/lib/mdx-validator.d.ts +11 -2
- package/dist/lib/mdx-validator.d.ts.map +1 -1
- package/dist/lib/mdx-validator.js +41 -4
- package/dist/lib/mdx-validator.js.map +1 -1
- package/dist/lib/relative-mdx-imports.d.ts +44 -0
- package/dist/lib/relative-mdx-imports.d.ts.map +1 -0
- package/dist/lib/relative-mdx-imports.js +145 -0
- package/dist/lib/relative-mdx-imports.js.map +1 -0
- package/dist/lib/run-build-script.d.ts.map +1 -1
- package/dist/lib/run-build-script.js +7 -0
- package/dist/lib/run-build-script.js.map +1 -1
- package/dist/lib/warn-relative-imports.d.ts +2 -0
- package/dist/lib/warn-relative-imports.d.ts.map +1 -0
- package/dist/lib/warn-relative-imports.js +29 -0
- package/dist/lib/warn-relative-imports.js.map +1 -0
- package/package.json +1 -1
- package/vendored/app/(unlock)/jd/unlock/page.tsx +32 -0
- package/vendored/app/[[...slug]]/page.tsx +63 -15
- package/vendored/components/navigation/SocialFooter.tsx +4 -18
- package/vendored/lib/branding-url.ts +9 -0
- package/vendored/lib/layout-helpers.tsx +7 -9
- package/vendored/lib/preprocess-mdx.ts +42 -0
- package/vendored/scripts/compile-snippets.cjs +50 -7
- package/vendored/workspace-package-lock.json +3 -3
|
@@ -10,6 +10,7 @@ import { homedir } from 'os';
|
|
|
10
10
|
import { createRequire } from 'module';
|
|
11
11
|
import { pathToFileURL } from 'url';
|
|
12
12
|
import { preprocessFrontmatter } from './frontmatter-utils.js';
|
|
13
|
+
import { unindentClosingTagsAfterLists } from './mdx-syntax-fixes.js';
|
|
13
14
|
let cachedMdx = null;
|
|
14
15
|
/**
|
|
15
16
|
* Build the user-facing error thrown when @mdx-js/mdx can't be resolved.
|
|
@@ -43,9 +44,17 @@ async function importMdx() {
|
|
|
43
44
|
return cachedMdx;
|
|
44
45
|
}
|
|
45
46
|
/**
|
|
46
|
-
* Validate a single MDX file's content
|
|
47
|
+
* Validate a single MDX file's content.
|
|
48
|
+
*
|
|
49
|
+
* @param applySyntaxFixes - Whether to apply the same in-memory rewrites
|
|
50
|
+
* that build-service's preprocessMdx pipeline applies at render time
|
|
51
|
+
* (e.g. unindenting closing tags absorbed by list items). Default `true`
|
|
52
|
+
* so dev's gate matches what actually compiles. Pass `false` to see the
|
|
53
|
+
* verdict against raw on-disk content — used by `jamdesk migrate` to
|
|
54
|
+
* detect files that *would* break without the runtime safety net.
|
|
47
55
|
*/
|
|
48
|
-
export async function validateMdxFile(content, filePath) {
|
|
56
|
+
export async function validateMdxFile(content, filePath, options = {}) {
|
|
57
|
+
const { applySyntaxFixes = true } = options;
|
|
49
58
|
const { compile } = await importMdx();
|
|
50
59
|
const matter = (await import('gray-matter')).default;
|
|
51
60
|
// Pre-process frontmatter to handle common issues
|
|
@@ -61,9 +70,13 @@ export async function validateMdxFile(content, filePath) {
|
|
|
61
70
|
suggestion: 'Check YAML syntax between --- markers',
|
|
62
71
|
};
|
|
63
72
|
}
|
|
64
|
-
// Step 2: Validate MDX syntax
|
|
73
|
+
// Step 2: Validate MDX syntax. By default, mirror the runtime preprocess
|
|
74
|
+
// pipeline so dev's gate matches what gets compiled at request time.
|
|
75
|
+
const toCompile = applySyntaxFixes
|
|
76
|
+
? unindentClosingTagsAfterLists(processedContent).content
|
|
77
|
+
: processedContent;
|
|
65
78
|
try {
|
|
66
|
-
await compile(
|
|
79
|
+
await compile(toCompile, { jsx: true });
|
|
67
80
|
return null; // Valid
|
|
68
81
|
}
|
|
69
82
|
catch (err) {
|
|
@@ -97,6 +110,10 @@ export function extractAllPages(navigation) {
|
|
|
97
110
|
if ('tabs' in item && Array.isArray(item.tabs)) {
|
|
98
111
|
processItems(item.tabs);
|
|
99
112
|
}
|
|
113
|
+
// Handle dropdowns (Mintlify navigation grouping)
|
|
114
|
+
if ('dropdowns' in item && Array.isArray(item.dropdowns)) {
|
|
115
|
+
processItems(item.dropdowns);
|
|
116
|
+
}
|
|
100
117
|
}
|
|
101
118
|
}
|
|
102
119
|
}
|
|
@@ -119,6 +136,15 @@ export function extractAllPages(navigation) {
|
|
|
119
136
|
if (navigation.groups && Array.isArray(navigation.groups)) {
|
|
120
137
|
processItems(navigation.groups);
|
|
121
138
|
}
|
|
139
|
+
// Handle pages structure: { pages: [...] } — produced by
|
|
140
|
+
// convertMintlifyToJamdesk when the source had a top-level navigation array.
|
|
141
|
+
if (navigation.pages && Array.isArray(navigation.pages)) {
|
|
142
|
+
processItems(navigation.pages);
|
|
143
|
+
}
|
|
144
|
+
// Handle top-level dropdowns: { dropdowns: [...] }
|
|
145
|
+
if (navigation.dropdowns && Array.isArray(navigation.dropdowns)) {
|
|
146
|
+
processItems(navigation.dropdowns);
|
|
147
|
+
}
|
|
122
148
|
// Handle flat array: [...]
|
|
123
149
|
if (Array.isArray(navigation)) {
|
|
124
150
|
processItems(navigation);
|
|
@@ -168,6 +194,17 @@ function formatMdxError(err, filePath) {
|
|
|
168
194
|
suggestion =
|
|
169
195
|
'A < character is being parsed as JSX. Use < or rewrite (e.g., "Below 50%" instead of "<50%")';
|
|
170
196
|
}
|
|
197
|
+
else if (message.includes('Expected the closing tag') &&
|
|
198
|
+
message.includes('listItem')) {
|
|
199
|
+
// Indented closing tags get absorbed into the previous list item:
|
|
200
|
+
// - last bullet
|
|
201
|
+
// </Card> ← 2-space indent makes this part of the listItem
|
|
202
|
+
// The fix is always to unindent the closing tag flush-left (or
|
|
203
|
+
// separate it from the list with a blank line).
|
|
204
|
+
suggestion =
|
|
205
|
+
'Closing tag is indented and got absorbed into the preceding list item. ' +
|
|
206
|
+
'Unindent the closing tag flush-left, or add a blank line between the last list item and the closing tag.';
|
|
207
|
+
}
|
|
171
208
|
else if (message.includes('Expected closing tag')) {
|
|
172
209
|
suggestion = 'Add the missing closing tag or use self-closing syntax (<Component />)';
|
|
173
210
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mdx-validator.js","sourceRoot":"","sources":["../../src/lib/mdx-validator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"mdx-validator.js","sourceRoot":"","sources":["../../src/lib/mdx-validator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detect and rewrite parent-relative MDX imports.
|
|
3
|
+
*
|
|
4
|
+
* Mintlify supports `import X from '../snippets/foo.mdx'`; Jamdesk only
|
|
5
|
+
* resolves root-relative `import X from '/snippets/foo.mdx'`. The
|
|
6
|
+
* detector finds candidates; the rewriter fixes the ones that resolve
|
|
7
|
+
* under a `snippets/` directory (conservative — see plan).
|
|
8
|
+
*/
|
|
9
|
+
export interface RelativeMdxImport {
|
|
10
|
+
/** The import specifier as written, e.g. '../snippets/foo.mdx'. */
|
|
11
|
+
specifier: string;
|
|
12
|
+
/** 1-indexed line number in the source. */
|
|
13
|
+
line: number;
|
|
14
|
+
/** The full matched import statement (for replacement). */
|
|
15
|
+
raw: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function stripFencedCodeBlocks(content: string): string;
|
|
18
|
+
/**
|
|
19
|
+
* Pass `alreadyStripped: true` when the caller already ran
|
|
20
|
+
* `stripFencedCodeBlocks` — avoids redoing the regex pass when the same
|
|
21
|
+
* stripped content drives multiple analyses (e.g. link extraction +
|
|
22
|
+
* import detection during relocation).
|
|
23
|
+
*/
|
|
24
|
+
export declare function detectRelativeMdxImports(content: string, alreadyStripped?: boolean): RelativeMdxImport[];
|
|
25
|
+
export interface RewriteResult {
|
|
26
|
+
/** Content with applicable imports rewritten. */
|
|
27
|
+
content: string;
|
|
28
|
+
/** Specifiers that were successfully rewritten. */
|
|
29
|
+
rewrites: {
|
|
30
|
+
from: string;
|
|
31
|
+
to: string;
|
|
32
|
+
line: number;
|
|
33
|
+
}[];
|
|
34
|
+
/** Human-readable warnings for imports left untouched. */
|
|
35
|
+
warnings: string[];
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Rewrite parent-relative MDX imports to root-relative `/snippets/*` form
|
|
39
|
+
* when the resolved target sits under a top-level `snippets/` directory.
|
|
40
|
+
* Imports that resolve elsewhere (siblings, non-existent files, paths
|
|
41
|
+
* outside `projectRoot`) are left untouched and reported in `warnings`.
|
|
42
|
+
*/
|
|
43
|
+
export declare function rewriteRelativeMdxImports(content: string, filePath: string, projectRoot: string): Promise<RewriteResult>;
|
|
44
|
+
//# sourceMappingURL=relative-mdx-imports.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relative-mdx-imports.d.ts","sourceRoot":"","sources":["../../src/lib/relative-mdx-imports.ts"],"names":[],"mappings":"AAIA;;;;;;;GAOG;AAEH,MAAM,WAAW,iBAAiB;IAChC,mEAAmE;IACnE,SAAS,EAAE,MAAM,CAAC;IAClB,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,2DAA2D;IAC3D,GAAG,EAAE,MAAM,CAAC;CACb;AA8BD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAQ7D;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,MAAM,EACf,eAAe,UAAQ,GACtB,iBAAiB,EAAE,CAiBrB;AAED,MAAM,WAAW,aAAa;IAC5B,iDAAiD;IACjD,OAAO,EAAE,MAAM,CAAC;IAChB,mDAAmD;IACnD,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACvD,0DAA0D;IAC1D,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,aAAa,CAAC,CA0FxB"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
// builder/cli/src/lib/relative-mdx-imports.ts
|
|
2
|
+
import fs from 'fs-extra';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
// Captures: import <binding> from '<./or../><path>.mdx';
|
|
5
|
+
// Quotes: single or double. Named: { Foo, Bar } (multi-line ok). Default: Foo.
|
|
6
|
+
// Namespace: * as Foo. Type-only: import type X. Combined: Default, { Named }.
|
|
7
|
+
// Side-effect imports (`import "..mdx"` with no binding) are intentionally
|
|
8
|
+
// ignored — MDX needs a binding to render the snippet.
|
|
9
|
+
//
|
|
10
|
+
// Anchored to start-of-line (with `gm` + `^[ \t]*`) so the regex can't match
|
|
11
|
+
// the literal English word "import" inside a heading or prose paragraph and
|
|
12
|
+
// then bridge across multiple lines to the real import — that produced wrong
|
|
13
|
+
// `line` numbers in user-facing warnings (validate/dev print `<file>:<line>`).
|
|
14
|
+
//
|
|
15
|
+
// The binding character class allows identifiers, `$`, `*` (namespace), commas,
|
|
16
|
+
// braces, spaces, and newlines (for multi-line `{ ... }` lists). It explicitly
|
|
17
|
+
// excludes quotes and slashes so the bridge can't extend past the next `"` or
|
|
18
|
+
// jump into a sibling import on a later line.
|
|
19
|
+
const RELATIVE_MDX_IMPORT_RE = /^[ \t]*import\s+(?:type\s+)?[\w$*{}, \n\r]+\s+from\s+["'](\.{1,2}\/[^"']+\.mdx)["']\s*;?/gm;
|
|
20
|
+
// Replaces fenced code-block bodies with same-shape blanks so line numbers are
|
|
21
|
+
// preserved but imports inside fences don't match. Handles both ``` and ~~~
|
|
22
|
+
// fences with optional info strings (e.g. ```mdx shared/example.mdx wrap).
|
|
23
|
+
// Indent class is `( *)` (not the CommonMark `{0,3}`) so we also catch fences
|
|
24
|
+
// nested in numbered list items / `<CodeGroup>` blocks where the fence opens
|
|
25
|
+
// at column 4+ (real Mintlify pattern in `create/reusable-snippets.mdx`).
|
|
26
|
+
// The capture binds `\1` to the exact indent so the close has to match.
|
|
27
|
+
const FENCED_CODE_BLOCK_RE = /^( *)(```+|~~~+)[^\n]*\n([\s\S]*?)\n\1\2\s*$/gm;
|
|
28
|
+
export function stripFencedCodeBlocks(content) {
|
|
29
|
+
return content.replace(FENCED_CODE_BLOCK_RE, (match, _indent, _fence, body) => {
|
|
30
|
+
// Replace body with blank lines of same count to preserve line numbers.
|
|
31
|
+
const bodyLines = body.split('\n').length;
|
|
32
|
+
const fenceOpen = match.split('\n')[0];
|
|
33
|
+
const fenceClose = match.split('\n').slice(-1)[0];
|
|
34
|
+
return [fenceOpen, ...Array(bodyLines).fill(''), fenceClose].join('\n');
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Pass `alreadyStripped: true` when the caller already ran
|
|
39
|
+
* `stripFencedCodeBlocks` — avoids redoing the regex pass when the same
|
|
40
|
+
* stripped content drives multiple analyses (e.g. link extraction +
|
|
41
|
+
* import detection during relocation).
|
|
42
|
+
*/
|
|
43
|
+
export function detectRelativeMdxImports(content, alreadyStripped = false) {
|
|
44
|
+
const stripped = alreadyStripped ? content : stripFencedCodeBlocks(content);
|
|
45
|
+
const out = [];
|
|
46
|
+
RELATIVE_MDX_IMPORT_RE.lastIndex = 0;
|
|
47
|
+
let match;
|
|
48
|
+
while ((match = RELATIVE_MDX_IMPORT_RE.exec(stripped)) !== null) {
|
|
49
|
+
const before = stripped.slice(0, match.index);
|
|
50
|
+
// 1-indexed line of the `import` keyword. Line numbers preserved by
|
|
51
|
+
// stripFencedCodeBlocks (replaces body with same-count blank lines).
|
|
52
|
+
const line = before.split('\n').length;
|
|
53
|
+
out.push({
|
|
54
|
+
specifier: match[1],
|
|
55
|
+
line,
|
|
56
|
+
raw: match[0],
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
return out;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Rewrite parent-relative MDX imports to root-relative `/snippets/*` form
|
|
63
|
+
* when the resolved target sits under a top-level `snippets/` directory.
|
|
64
|
+
* Imports that resolve elsewhere (siblings, non-existent files, paths
|
|
65
|
+
* outside `projectRoot`) are left untouched and reported in `warnings`.
|
|
66
|
+
*/
|
|
67
|
+
export async function rewriteRelativeMdxImports(content, filePath, projectRoot) {
|
|
68
|
+
const matches = detectRelativeMdxImports(content);
|
|
69
|
+
const rewrites = [];
|
|
70
|
+
const warnings = [];
|
|
71
|
+
const fileDir = path.dirname(filePath);
|
|
72
|
+
const snippetsRoot = path.join(projectRoot, 'snippets');
|
|
73
|
+
const relPath = path.relative(projectRoot, filePath);
|
|
74
|
+
let next = content;
|
|
75
|
+
for (const m of matches) {
|
|
76
|
+
const resolved = path.resolve(fileDir, m.specifier);
|
|
77
|
+
if (!(await fs.pathExists(resolved))) {
|
|
78
|
+
// Resume-after-partial: a previous relocate run may have moved the
|
|
79
|
+
// file to `/snippets/<sameRel>` while leaving this importer's path
|
|
80
|
+
// untouched (e.g. user manually moved files, or relocate aborted
|
|
81
|
+
// mid-flight on a second pass). The relocator preserves source-dir
|
|
82
|
+
// structure when moving, so probing `snippets/<resolved-rel>` is
|
|
83
|
+
// the inverse of that move and cheaply makes re-runs idempotent.
|
|
84
|
+
const resolvedRel = path.relative(projectRoot, resolved);
|
|
85
|
+
if (!resolvedRel.startsWith('..') &&
|
|
86
|
+
!path.isAbsolute(resolvedRel) &&
|
|
87
|
+
!resolvedRel.startsWith(`snippets${path.sep}`)) {
|
|
88
|
+
const movedCandidate = path.join(snippetsRoot, resolvedRel);
|
|
89
|
+
if (await fs.pathExists(movedCandidate)) {
|
|
90
|
+
const newSpec = `/snippets/${resolvedRel.replaceAll(path.sep, '/')}`;
|
|
91
|
+
// Replacer functions (not strings) — `$` in user paths would
|
|
92
|
+
// otherwise be interpreted as String.replace backreferences.
|
|
93
|
+
const newImport = m.raw.replace(m.specifier, () => newSpec);
|
|
94
|
+
next = next.replace(m.raw, () => newImport);
|
|
95
|
+
rewrites.push({ from: m.specifier, to: newSpec, line: m.line });
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
// Mintlify-style root-snippets fallback. `../snippets/X` from `zh/folder/`
|
|
100
|
+
// resolves literally to `zh/snippets/X` (doesn't exist), but the user
|
|
101
|
+
// almost always meant `<root>/snippets/X` — Mintlify resolves it that
|
|
102
|
+
// way regardless of depth, and localized pages copy the import verbatim.
|
|
103
|
+
const rootSnippetMatch = m.specifier.match(/^(?:\.\.\/)+snippets\/(.+\.mdx)$/);
|
|
104
|
+
if (rootSnippetMatch) {
|
|
105
|
+
const rootCandidate = path.join(snippetsRoot, rootSnippetMatch[1]);
|
|
106
|
+
if (await fs.pathExists(rootCandidate)) {
|
|
107
|
+
const newSpec = `/snippets/${rootSnippetMatch[1]}`;
|
|
108
|
+
const newImport = m.raw.replace(m.specifier, () => newSpec);
|
|
109
|
+
next = next.replace(m.raw, () => newImport);
|
|
110
|
+
rewrites.push({ from: m.specifier, to: newSpec, line: m.line });
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
warnings.push(`${relPath}:${m.line}: ${m.specifier} — target file doesn't exist; ` +
|
|
115
|
+
`create the snippet or remove this import`);
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
const rel = path.relative(snippetsRoot, resolved);
|
|
119
|
+
if (rel.startsWith('..') || path.isAbsolute(rel)) {
|
|
120
|
+
// Target exists but isn't under /snippets/. The user has to decide.
|
|
121
|
+
const targetRel = path.relative(projectRoot, resolved);
|
|
122
|
+
const suggestedSnippetPath = `/snippets/${path.basename(resolved)}`;
|
|
123
|
+
// If the suggested destination already holds a different file,
|
|
124
|
+
// saying "Move the file to <X>" would clobber. Surface the conflict
|
|
125
|
+
// so the user knows to rename or merge instead.
|
|
126
|
+
const collision = await fs.pathExists(path.join(snippetsRoot, path.basename(resolved)));
|
|
127
|
+
if (collision) {
|
|
128
|
+
warnings.push(`${relPath}:${m.line}: ${m.specifier} → ${targetRel} is not under /snippets/, ` +
|
|
129
|
+
`but ${suggestedSnippetPath} already exists with different content. ` +
|
|
130
|
+
`Rename one of the files or inline this import.`);
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
warnings.push(`${relPath}:${m.line}: ${m.specifier} → ${targetRel} is not under /snippets/. ` +
|
|
134
|
+
`Move the file to ${suggestedSnippetPath} (and update this import) or inline its content.`);
|
|
135
|
+
}
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
const newSpec = `/snippets/${rel.replaceAll(path.sep, '/')}`;
|
|
139
|
+
const newImport = m.raw.replace(m.specifier, () => newSpec);
|
|
140
|
+
next = next.replace(m.raw, () => newImport);
|
|
141
|
+
rewrites.push({ from: m.specifier, to: newSpec, line: m.line });
|
|
142
|
+
}
|
|
143
|
+
return { content: next, rewrites, warnings };
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=relative-mdx-imports.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relative-mdx-imports.js","sourceRoot":"","sources":["../../src/lib/relative-mdx-imports.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-build-script.d.ts","sourceRoot":"","sources":["../../src/lib/run-build-script.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAOD,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GACjE,OAAO,CAAC,YAAY,CAAC,
|
|
1
|
+
{"version":3,"file":"run-build-script.d.ts","sourceRoot":"","sources":["../../src/lib/run-build-script.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAOD,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GACjE,OAAO,CAAC,YAAY,CAAC,CAsBvB;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,MAAM,EAAE,EACjB,OAAO,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GACjE,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,EAAE,YAAY,EAAE,CAAA;CAAE,CAAC,CAIjE"}
|
|
@@ -31,6 +31,13 @@ export async function runBuildScript(script, options) {
|
|
|
31
31
|
if (stderr)
|
|
32
32
|
process.stderr.write(stderr);
|
|
33
33
|
}
|
|
34
|
+
else if (stderr) {
|
|
35
|
+
// Successful scripts that wrote to stderr signalled a non-fatal warning
|
|
36
|
+
// (e.g. compile-snippets snippet-name collision). Surfacing these even
|
|
37
|
+
// in non-verbose mode means the next dev start doesn't blow up
|
|
38
|
+
// mysteriously when the warning's resolution lapses.
|
|
39
|
+
process.stderr.write(stderr);
|
|
40
|
+
}
|
|
34
41
|
return { script, success: true };
|
|
35
42
|
}
|
|
36
43
|
catch (error) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-build-script.js","sourceRoot":"","sources":["../../src/lib/run-build-script.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAEjC,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;AAUlC,qEAAqE;AACrE,iDAAiD;AACjD,uDAAuD;AACvD,MAAM,UAAU,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AAEpC,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,MAAc,EACd,OAAkE;IAElE,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC,gBAAgB,MAAM,EAAE,EAAE;YACnE,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,SAAS,EAAE,UAAU;SACtB,CAAC,CAAC;QACH,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACpB,IAAI,MAAM;gBAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YACzC,IAAI,MAAM;gBAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAC3C,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACnC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,GAAG,KAA6C,CAAC;QACxD,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC;IAC/E,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,OAAiB,EACjB,OAAkE;IAElE,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IAClF,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IACnD,OAAO,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;AACxE,CAAC"}
|
|
1
|
+
{"version":3,"file":"run-build-script.js","sourceRoot":"","sources":["../../src/lib/run-build-script.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAEjC,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;AAUlC,qEAAqE;AACrE,iDAAiD;AACjD,uDAAuD;AACvD,MAAM,UAAU,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AAEpC,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,MAAc,EACd,OAAkE;IAElE,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC,gBAAgB,MAAM,EAAE,EAAE;YACnE,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,SAAS,EAAE,UAAU;SACtB,CAAC,CAAC;QACH,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACpB,IAAI,MAAM;gBAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YACzC,IAAI,MAAM;gBAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAC3C,CAAC;aAAM,IAAI,MAAM,EAAE,CAAC;YAClB,wEAAwE;YACxE,uEAAuE;YACvE,+DAA+D;YAC/D,qDAAqD;YACrD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAC/B,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACnC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,GAAG,KAA6C,CAAC;QACxD,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC;IAC/E,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,OAAiB,EACjB,OAAkE;IAElE,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IAClF,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IACnD,OAAO,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;AACxE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"warn-relative-imports.d.ts","sourceRoot":"","sources":["../../src/lib/warn-relative-imports.ts"],"names":[],"mappings":"AAIA,wBAAsB,wBAAwB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA0BlF"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { glob } from 'glob';
|
|
2
|
+
import { readFile } from 'node:fs/promises';
|
|
3
|
+
import { detectRelativeMdxImports } from './relative-mdx-imports.js';
|
|
4
|
+
export async function warnOnRelativeMdxImports(projectDir) {
|
|
5
|
+
const files = await glob('**/*.mdx', {
|
|
6
|
+
cwd: projectDir,
|
|
7
|
+
ignore: ['**/node_modules/**', '**/.git/**'],
|
|
8
|
+
absolute: true,
|
|
9
|
+
});
|
|
10
|
+
let offending = 0;
|
|
11
|
+
for (const file of files) {
|
|
12
|
+
try {
|
|
13
|
+
const content = await readFile(file, 'utf-8');
|
|
14
|
+
if (detectRelativeMdxImports(content).length > 0)
|
|
15
|
+
offending++;
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
// unreadable file — skip
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
if (offending > 0) {
|
|
22
|
+
console.warn(`\n⚠ Found ${offending} MDX file(s) with parent-relative imports. ` +
|
|
23
|
+
`Run "jamdesk migrate" to auto-fix; "jamdesk validate" lists each one with the ` +
|
|
24
|
+
`specific manual action when migrate can't help. Pages with these imports will ` +
|
|
25
|
+
`fail to compile.\n`);
|
|
26
|
+
}
|
|
27
|
+
return offending;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=warn-relative-imports.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"warn-relative-imports.js","sourceRoot":"","sources":["../../src/lib/warn-relative-imports.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAErE,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,UAAkB;IAC/D,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,UAAU,EAAE;QACnC,GAAG,EAAE,UAAU;QACf,MAAM,EAAE,CAAC,oBAAoB,EAAE,YAAY,CAAC;QAC5C,QAAQ,EAAE,IAAI;KACf,CAAC,CAAC;IAEH,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YAC9C,IAAI,wBAAwB,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC;gBAAE,SAAS,EAAE,CAAC;QAChE,CAAC;QAAC,MAAM,CAAC;YACP,yBAAyB;QAC3B,CAAC;IACH,CAAC;IAED,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;QAClB,OAAO,CAAC,IAAI,CACV,aAAa,SAAS,6CAA6C;YACnE,gFAAgF;YAChF,gFAAgF;YAChF,oBAAoB,CACrB,CAAC;IACJ,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jamdesk",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.71",
|
|
4
4
|
"description": "CLI for Jamdesk — build, preview, and deploy documentation sites from MDX. Dev server with hot reload, 50+ components, OpenAPI support, AI search, and Mintlify migration",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jamdesk",
|
|
@@ -2,6 +2,7 @@ import { headers } from 'next/headers';
|
|
|
2
2
|
import { getDocsConfig } from '@/lib/docs-isr';
|
|
3
3
|
import { normalizeLogo } from '@/lib/docs-types';
|
|
4
4
|
import { sanitizeFrom } from '@/lib/sanitize-from';
|
|
5
|
+
import { getBrandingUrl } from '@/lib/branding-url';
|
|
5
6
|
import UnlockForm from './UnlockForm';
|
|
6
7
|
|
|
7
8
|
interface UnlockPageProps {
|
|
@@ -29,14 +30,19 @@ export default async function UnlockPage({ searchParams }: UnlockPageProps) {
|
|
|
29
30
|
const from = sanitizeFrom(rawFrom ?? null);
|
|
30
31
|
const showError = params.error === '1';
|
|
31
32
|
|
|
33
|
+
const showBranding = process.env.NEXT_PUBLIC_SHOW_BRANDING !== 'false';
|
|
34
|
+
const brandingUrl = getBrandingUrl(slug);
|
|
35
|
+
|
|
32
36
|
return (
|
|
33
37
|
<main
|
|
34
38
|
style={{
|
|
35
39
|
minHeight: '100vh',
|
|
36
40
|
display: 'flex',
|
|
41
|
+
flexDirection: 'column',
|
|
37
42
|
alignItems: 'center',
|
|
38
43
|
justifyContent: 'center',
|
|
39
44
|
padding: '24px 16px',
|
|
45
|
+
gap: 24,
|
|
40
46
|
}}
|
|
41
47
|
>
|
|
42
48
|
<section
|
|
@@ -152,6 +158,32 @@ export default async function UnlockPage({ searchParams }: UnlockPageProps) {
|
|
|
152
158
|
</p>
|
|
153
159
|
)}
|
|
154
160
|
</section>
|
|
161
|
+
|
|
162
|
+
{showBranding && (
|
|
163
|
+
<a
|
|
164
|
+
href={brandingUrl}
|
|
165
|
+
target="_blank"
|
|
166
|
+
rel="noopener noreferrer"
|
|
167
|
+
style={{
|
|
168
|
+
display: 'inline-flex',
|
|
169
|
+
alignItems: 'center',
|
|
170
|
+
gap: 6,
|
|
171
|
+
fontSize: 13,
|
|
172
|
+
color: '#9ca3af',
|
|
173
|
+
textDecoration: 'none',
|
|
174
|
+
}}
|
|
175
|
+
>
|
|
176
|
+
Powered by
|
|
177
|
+
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
178
|
+
<img
|
|
179
|
+
src="/_jd/branding/jamdesk-wordmark.svg"
|
|
180
|
+
alt="Jamdesk"
|
|
181
|
+
width={58}
|
|
182
|
+
height={15}
|
|
183
|
+
style={{ display: 'inline-block', verticalAlign: 'middle' }}
|
|
184
|
+
/>
|
|
185
|
+
</a>
|
|
186
|
+
)}
|
|
155
187
|
</main>
|
|
156
188
|
);
|
|
157
189
|
}
|
|
@@ -25,54 +25,102 @@ interface PageProps {
|
|
|
25
25
|
}>;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
// Mirror of the CLI's detector regex in cli/src/lib/relative-mdx-imports.ts.
|
|
29
|
+
// Duplicated intentionally — build-service uses bundler module resolution
|
|
30
|
+
// and shouldn't reach into cli/src/. Keep the regex itself in sync with
|
|
31
|
+
// that file. Two intentional simplifications vs the CLI version:
|
|
32
|
+
// - no `g` flag (boolean test, not iteration)
|
|
33
|
+
// - fence stripping replaces matches with empty string instead of
|
|
34
|
+
// blank lines of equal count — line numbers don't matter here, only
|
|
35
|
+
// a yes/no skip decision (the CLI preserves them for warning text).
|
|
36
|
+
const PARENT_RELATIVE_MDX_IMPORT_RE =
|
|
37
|
+
/^[ \t]*import\s+(?:type\s+)?[\w$*{}, \n\r]+\s+from\s+["']\.{1,2}\/[^"']+\.mdx["']\s*;?/m;
|
|
38
|
+
|
|
39
|
+
const FENCED_CODE_BLOCK_RE =
|
|
40
|
+
/^( *)(```+|~~~+)[^\n]*\n([\s\S]*?)\n\1\2\s*$/gm;
|
|
41
|
+
|
|
42
|
+
export function pageHasRelativeMdxImport(filePath: string): boolean {
|
|
43
|
+
try {
|
|
44
|
+
// Read the full file — MDX imports can appear at any top-level position
|
|
45
|
+
// (after a long prose intro or table of contents), and a slice was
|
|
46
|
+
// missing real imports past byte ~8192 in 70-94 KB customer pages.
|
|
47
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
48
|
+
// Strip fenced code blocks so documentation examples (e.g.
|
|
49
|
+
// ```mdx\nimport X from "../snippets/foo.mdx";\n```) don't false-trigger.
|
|
50
|
+
return PARENT_RELATIVE_MDX_IMPORT_RE.test(content.replace(FENCED_CODE_BLOCK_RE, ''));
|
|
51
|
+
} catch {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
interface CollectedPaths {
|
|
57
|
+
supported: string[];
|
|
58
|
+
skipped: string[];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function getAllDocPaths(): CollectedPaths {
|
|
29
62
|
const contentDir = getContentDir();
|
|
30
|
-
const
|
|
63
|
+
const supported: string[] = [];
|
|
64
|
+
const skipped: string[] = [];
|
|
31
65
|
|
|
32
66
|
function traverseDir(dir: string, basePath: string = '') {
|
|
33
67
|
if (!fs.existsSync(dir)) return;
|
|
34
68
|
const files = fs.readdirSync(dir);
|
|
35
69
|
for (const file of files) {
|
|
36
|
-
// Skip dotfiles (.claude, .git, etc.)
|
|
37
70
|
if (file.startsWith('.')) continue;
|
|
38
71
|
const filePath = path.join(dir, file);
|
|
39
72
|
let stat;
|
|
40
73
|
try {
|
|
41
74
|
stat = fs.statSync(filePath);
|
|
42
75
|
} catch {
|
|
43
|
-
// Broken symlink or inaccessible — skip
|
|
44
76
|
continue;
|
|
45
77
|
}
|
|
46
78
|
if (stat.isDirectory()) {
|
|
47
79
|
traverseDir(filePath, path.join(basePath, file));
|
|
48
80
|
} else if (file.endsWith('.mdx')) {
|
|
49
81
|
const slug = path.join(basePath, file.replace(/\.mdx$/, ''));
|
|
50
|
-
|
|
82
|
+
if (pageHasRelativeMdxImport(filePath)) {
|
|
83
|
+
skipped.push(slug);
|
|
84
|
+
} else {
|
|
85
|
+
supported.push(slug);
|
|
86
|
+
}
|
|
51
87
|
}
|
|
52
88
|
}
|
|
53
89
|
}
|
|
54
90
|
|
|
55
91
|
traverseDir(contentDir);
|
|
56
|
-
return
|
|
92
|
+
return { supported, skipped };
|
|
57
93
|
}
|
|
58
94
|
|
|
95
|
+
// In `jamdesk dev`, Next.js calls generateStaticParams during initial
|
|
96
|
+
// compile AND for each lazily-compiled route (every page click). Without
|
|
97
|
+
// a guard the same multi-line warning floods the dev console after every
|
|
98
|
+
// navigation. Cache the prior skipped set and re-log only when it changes
|
|
99
|
+
// — that way a user who fixes one import still sees the list shrink, but
|
|
100
|
+
// repeated calls with no change stay quiet.
|
|
101
|
+
let lastSkippedKey: string | null = null;
|
|
102
|
+
|
|
59
103
|
export async function generateStaticParams() {
|
|
60
104
|
// ISR: pages generated on-demand, no build-time pre-render.
|
|
61
105
|
if (isIsrMode()) return [];
|
|
62
106
|
|
|
63
|
-
const
|
|
64
|
-
// next-mdx-remote can't compile relative MDX imports — skip those tests.
|
|
65
|
-
const unsupportedPatterns = ['deep-relative-test', 'relative-snippets-test'];
|
|
107
|
+
const { supported, skipped } = getAllDocPaths();
|
|
66
108
|
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
109
|
+
const skippedKey = skipped.length === 0 ? '' : skipped.slice().sort().join('\n');
|
|
110
|
+
if (skippedKey !== lastSkippedKey) {
|
|
111
|
+
lastSkippedKey = skippedKey;
|
|
112
|
+
if (skipped.length > 0) {
|
|
113
|
+
console.log(`[Build] Skipped ${skipped.length} page(s) with parent-relative MDX imports:`);
|
|
114
|
+
for (const slug of skipped) {
|
|
115
|
+
console.log(` - ${slug}`);
|
|
116
|
+
}
|
|
117
|
+
console.log(' Run "jamdesk migrate" to auto-fix moveable imports, or "jamdesk validate" for per-import detail.');
|
|
118
|
+
}
|
|
119
|
+
}
|
|
72
120
|
|
|
73
121
|
return [
|
|
74
122
|
{ slug: [] },
|
|
75
|
-
...
|
|
123
|
+
...supported.map((p) => ({ slug: p.split('/') })),
|
|
76
124
|
];
|
|
77
125
|
}
|
|
78
126
|
|
|
@@ -3,19 +3,9 @@
|
|
|
3
3
|
import Image from 'next/image';
|
|
4
4
|
import type { DocsConfig, SocialPlatform, FooterLinkColumn } from '@/lib/docs-types';
|
|
5
5
|
import { getIconClass } from '@/lib/icon-utils';
|
|
6
|
+
import { getBrandingUrl } from '@/lib/branding-url';
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
// Uses NEXT_PUBLIC_ prefix so these are inlined during build for client components
|
|
9
|
-
const showBranding = process.env.NEXT_PUBLIC_SHOW_BRANDING !== 'false'; // Default true
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Generate branding URL with UTM parameters for attribution tracking.
|
|
13
|
-
* projectSlug is passed as a prop (works in ISR multi-tenant mode).
|
|
14
|
-
* Falls back to NEXT_PUBLIC_PROJECT_SLUG env var (works in CLI dev mode).
|
|
15
|
-
*/
|
|
16
|
-
function getBrandingUrl(projectSlug: string): string {
|
|
17
|
-
return `https://www.jamdesk.com?utm_campaign=poweredBy&utm_medium=referral&utm_source=${projectSlug}`;
|
|
18
|
-
}
|
|
8
|
+
const showBranding = process.env.NEXT_PUBLIC_SHOW_BRANDING !== 'false';
|
|
19
9
|
|
|
20
10
|
interface SocialFooterProps {
|
|
21
11
|
config: DocsConfig;
|
|
@@ -150,23 +140,19 @@ export function SocialFooter({ config, hidden, projectSlug }: SocialFooterProps)
|
|
|
150
140
|
return null;
|
|
151
141
|
}
|
|
152
142
|
|
|
153
|
-
// Resolve slug: prop (ISR) → env var (CLI dev) → fallback
|
|
154
|
-
const slug = projectSlug || process.env.NEXT_PUBLIC_PROJECT_SLUG || 'docs';
|
|
155
|
-
|
|
156
143
|
return (
|
|
157
144
|
<footer className="mt-12 sm:mt-16 pt-6 sm:pt-8 border-t border-[var(--color-border)]">
|
|
158
145
|
{hasLinks && <LinkColumns columns={links} />}
|
|
159
|
-
{/* Desktop: row layout, Mobile: column layout */}
|
|
160
146
|
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
|
|
161
147
|
{hasSocials && <SocialIcons socials={socials} />}
|
|
162
148
|
{showBranding && (
|
|
163
149
|
<a
|
|
164
|
-
href={getBrandingUrl(
|
|
150
|
+
href={getBrandingUrl(projectSlug)}
|
|
165
151
|
target="_blank"
|
|
166
152
|
rel="noopener noreferrer"
|
|
167
153
|
className="group flex items-center gap-1 text-sm text-[#AEAEAE] hover:text-[#6A6D70] transition-colors whitespace-nowrap"
|
|
168
154
|
>
|
|
169
|
-
|
|
155
|
+
Powered by
|
|
170
156
|
<span className="relative inline-block w-[58px] h-[15px] top-[1px]">
|
|
171
157
|
<Image
|
|
172
158
|
src="/_jd/branding/jamdesk-wordmark.svg"
|