@mui/internal-docs-infra 0.11.1-canary.19 → 0.11.1-canary.20
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/CodeHighlighter/types.d.mts +1 -0
- package/package.json +2 -2
- package/pipeline/hastUtils/hastDecompress.mjs +10 -4
- package/pipeline/hastUtils/hastUtils.mjs +6 -6
- package/pipeline/lintJavascriptDemoFocus/lintJavascriptDemoFocus.mjs +10 -7
- package/pipeline/loadIsomorphicCodeVariant/decodeSource.d.mts +19 -0
- package/pipeline/loadIsomorphicCodeVariant/decodeSource.mjs +25 -0
- package/pipeline/loadIsomorphicCodeVariant/decodeSourceToText.d.mts +17 -0
- package/pipeline/loadIsomorphicCodeVariant/decodeSourceToText.mjs +26 -0
- package/pipeline/loadIsomorphicCodeVariant/flattenCodeVariant.mjs +5 -4
- package/pipeline/parseSource/addLineGutters.mjs +11 -1
- package/useCode/EditableEngine.mjs +397 -62
- package/useCode/SourceEditingEngine.mjs +215 -45
- package/useCode/liveEditingBugs.browser.d.mts +1 -0
- package/useCode/liveEditingBugs.browser.mjs +825 -0
- package/useCode/useCode.d.mts +11 -0
- package/useCode/useCode.mjs +13 -0
- package/useCode/useCopyFunctionality.mjs +12 -10
- package/useCode/useEditableUtils.d.mts +50 -1
- package/useCode/useEditableUtils.mjs +29 -0
- package/useCode/useSourceEditing.mjs +57 -30
- package/useCodeWindow/useCodeWindow.mjs +9 -1
- package/useDemo/exportVariant.d.mts +12 -5
- package/useDemo/exportVariant.mjs +55 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mui/internal-docs-infra",
|
|
3
|
-
"version": "0.11.1-canary.
|
|
3
|
+
"version": "0.11.1-canary.20",
|
|
4
4
|
"author": "MUI Team",
|
|
5
5
|
"description": "MUI Infra - internal documentation creation tools.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -768,5 +768,5 @@
|
|
|
768
768
|
"bin": {
|
|
769
769
|
"docs-infra": "./cli/index.mjs"
|
|
770
770
|
},
|
|
771
|
-
"gitSha": "
|
|
771
|
+
"gitSha": "b61bf7023e4336cc842f108768ebbdfd79e56fad"
|
|
772
772
|
}
|
|
@@ -19,13 +19,19 @@ export function decompressHast(base64, textContent) {
|
|
|
19
19
|
const dictionary = buildDictionary(textContent);
|
|
20
20
|
if (textContent != null) {
|
|
21
21
|
verifyChecksum(raw, dictionary);
|
|
22
|
-
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
const deflated = textContent != null ? raw.subarray(CHECKSUM_BYTES) : raw;
|
|
25
|
+
return strFromU8(inflateSync(deflated, {
|
|
23
26
|
dictionary
|
|
24
27
|
}));
|
|
28
|
+
} catch (error) {
|
|
29
|
+
// A raw inflate failure (e.g. fflate's "unexpected EOF") is almost always a
|
|
30
|
+
// payload that was compressed with a fallback dictionary being decoded
|
|
31
|
+
// without one — the checksum prefix is then read as deflate data. Surface
|
|
32
|
+
// that cause instead of the cryptic `{code:0}` the raw error stringifies to.
|
|
33
|
+
throw new Error(`Failed to decompress payload${textContent == null ? ' — if it was compressed with a fallback dictionary, that dictionary must be provided' : ''}: ${error instanceof Error ? error.message : String(error)}`);
|
|
25
34
|
}
|
|
26
|
-
return strFromU8(inflateSync(raw, {
|
|
27
|
-
dictionary
|
|
28
|
-
}));
|
|
29
35
|
}
|
|
30
36
|
|
|
31
37
|
/**
|
|
@@ -28,13 +28,13 @@ export function hastOrJsonToJsx(hastOrJson, components, fallback) {
|
|
|
28
28
|
try {
|
|
29
29
|
hast = JSON.parse(hastOrJson.hastJson);
|
|
30
30
|
} catch (error) {
|
|
31
|
-
throw new Error(`Failed to parse hastJson: ${
|
|
31
|
+
throw new Error(`Failed to parse hastJson: ${error instanceof Error ? error.message : String(error)}`);
|
|
32
32
|
}
|
|
33
33
|
} else if ('hastCompressed' in hastOrJson) {
|
|
34
34
|
try {
|
|
35
35
|
hast = JSON.parse(decompressHast(hastOrJson.hastCompressed, fallbackDictionary(fallback)));
|
|
36
36
|
} catch (error) {
|
|
37
|
-
throw new Error(`Failed to parse hastCompressed: ${
|
|
37
|
+
throw new Error(`Failed to parse hastCompressed: ${error instanceof Error ? error.message : String(error)}`);
|
|
38
38
|
}
|
|
39
39
|
} else {
|
|
40
40
|
hast = hastOrJson;
|
|
@@ -55,13 +55,13 @@ export function stringOrHastToString(source, fallback) {
|
|
|
55
55
|
try {
|
|
56
56
|
hast = JSON.parse(source.hastJson);
|
|
57
57
|
} catch (error) {
|
|
58
|
-
throw new Error(`Failed to parse hastJson: ${
|
|
58
|
+
throw new Error(`Failed to parse hastJson: ${error instanceof Error ? error.message : String(error)}`);
|
|
59
59
|
}
|
|
60
60
|
} else if ('hastCompressed' in source) {
|
|
61
61
|
try {
|
|
62
62
|
hast = JSON.parse(decompressHast(source.hastCompressed, fallbackDictionary(fallback)));
|
|
63
63
|
} catch (error) {
|
|
64
|
-
throw new Error(`Failed to parse hastCompressed: ${
|
|
64
|
+
throw new Error(`Failed to parse hastCompressed: ${error instanceof Error ? error.message : String(error)}`);
|
|
65
65
|
}
|
|
66
66
|
} else {
|
|
67
67
|
hast = source;
|
|
@@ -79,13 +79,13 @@ export function stringOrHastToJsx(source, highlighted, components, fallback) {
|
|
|
79
79
|
try {
|
|
80
80
|
hast = JSON.parse(source.hastJson);
|
|
81
81
|
} catch (error) {
|
|
82
|
-
throw new Error(`Failed to parse hastJson: ${
|
|
82
|
+
throw new Error(`Failed to parse hastJson: ${error instanceof Error ? error.message : String(error)}`);
|
|
83
83
|
}
|
|
84
84
|
} else if ('hastCompressed' in source) {
|
|
85
85
|
try {
|
|
86
86
|
hast = JSON.parse(decompressHast(source.hastCompressed, fallbackDictionary(fallback)));
|
|
87
87
|
} catch (error) {
|
|
88
|
-
throw new Error(`Failed to parse hastCompressed: ${
|
|
88
|
+
throw new Error(`Failed to parse hastCompressed: ${error instanceof Error ? error.message : String(error)}`);
|
|
89
89
|
}
|
|
90
90
|
} else {
|
|
91
91
|
hast = source;
|
|
@@ -297,13 +297,16 @@ function reportPreview(context, sourceCode, {
|
|
|
297
297
|
if (options.wrapReturn && returnStatement) {
|
|
298
298
|
const hasParens = hasReturnParens(sourceCode, returnStatement);
|
|
299
299
|
if (hasParens) {
|
|
300
|
-
// Already `return (...)` — just insert the comment inside
|
|
300
|
+
// Already `return (...)` — just insert the comment inside. The focus
|
|
301
|
+
// sits one level deeper than the function body, so `@padding 2` keeps
|
|
302
|
+
// the `return (` line and the function signature/closing brace visible
|
|
303
|
+
// as context when collapsed.
|
|
301
304
|
const lineStartOffset = sourceCode.getIndexFromLoc({
|
|
302
305
|
line: firstNode.loc.start.line,
|
|
303
306
|
column: 0
|
|
304
307
|
});
|
|
305
308
|
if (isSingleLine) {
|
|
306
|
-
return fixer.insertTextBeforeRange([lineStartOffset, lineStartOffset], `${indentation}// @focus\n`);
|
|
309
|
+
return fixer.insertTextBeforeRange([lineStartOffset, lineStartOffset], `${indentation}// @focus @padding 2\n`);
|
|
307
310
|
}
|
|
308
311
|
const lastLineStartOffset = sourceCode.getIndexFromLoc({
|
|
309
312
|
line: lastNode.loc.end.line,
|
|
@@ -311,7 +314,7 @@ function reportPreview(context, sourceCode, {
|
|
|
311
314
|
});
|
|
312
315
|
const lastLine = sourceCode.lines[lastNode.loc.end.line - 1];
|
|
313
316
|
const lastIndentation = lastLine.match(/^\s*/)?.[0] ?? '';
|
|
314
|
-
return [fixer.insertTextBeforeRange([lineStartOffset, lineStartOffset], `${indentation}// @focus-start\n`), fixer.insertTextAfterRange([lastLineStartOffset, lastLineStartOffset + lastLine.length], `\n${lastIndentation}// @focus-end`)];
|
|
317
|
+
return [fixer.insertTextBeforeRange([lineStartOffset, lineStartOffset], `${indentation}// @focus-start @padding 2\n`), fixer.insertTextAfterRange([lastLineStartOffset, lastLineStartOffset + lastLine.length], `\n${lastIndentation}// @focus-end`)];
|
|
315
318
|
}
|
|
316
319
|
|
|
317
320
|
// No parens — wrap `return <X>` into `return (\n // comment\n <X>\n)`
|
|
@@ -319,9 +322,9 @@ function reportPreview(context, sourceCode, {
|
|
|
319
322
|
const returnIndentation = sourceCode.lines[returnStatement.loc.start.line - 1].match(/^\s*/)?.[0] ?? '';
|
|
320
323
|
const innerIndentation = `${returnIndentation} `;
|
|
321
324
|
if (isSingleLine) {
|
|
322
|
-
return [fixer.replaceTextRange([returnKeywordEnd, firstNode.range[0]], ` (\n${innerIndentation}// @focus\n${innerIndentation}`), fixer.insertTextAfterRange(lastNode.range, `\n${returnIndentation})`)];
|
|
325
|
+
return [fixer.replaceTextRange([returnKeywordEnd, firstNode.range[0]], ` (\n${innerIndentation}// @focus @padding 2\n${innerIndentation}`), fixer.insertTextAfterRange(lastNode.range, `\n${returnIndentation})`)];
|
|
323
326
|
}
|
|
324
|
-
return [fixer.replaceTextRange([returnKeywordEnd, firstNode.range[0]], ` (\n${innerIndentation}// @focus-start\n${innerIndentation}`), fixer.insertTextAfterRange(lastNode.range, `\n${innerIndentation}// @focus-end\n${returnIndentation})`)];
|
|
327
|
+
return [fixer.replaceTextRange([returnKeywordEnd, firstNode.range[0]], ` (\n${innerIndentation}// @focus-start @padding 2\n${innerIndentation}`), fixer.insertTextAfterRange(lastNode.range, `\n${innerIndentation}// @focus-end\n${returnIndentation})`)];
|
|
325
328
|
}
|
|
326
329
|
|
|
327
330
|
// Non-wrapper: wrapReturn with implicit-return arrow — wrap expression in parens with comment.
|
|
@@ -332,9 +335,9 @@ function reportPreview(context, sourceCode, {
|
|
|
332
335
|
const arrowIndentation = sourceCode.lines[arrowToken.loc.start.line - 1].match(/^\s*/)?.[0] ?? '';
|
|
333
336
|
const innerIndentation = `${arrowIndentation} `;
|
|
334
337
|
if (isSingleLine) {
|
|
335
|
-
return [fixer.replaceTextRange([arrowToken.range[1], firstNode.range[0]], ` (\n${innerIndentation}// @focus\n${innerIndentation}`), fixer.insertTextAfterRange(lastNode.range, `\n${arrowIndentation})`)];
|
|
338
|
+
return [fixer.replaceTextRange([arrowToken.range[1], firstNode.range[0]], ` (\n${innerIndentation}// @focus @padding 2\n${innerIndentation}`), fixer.insertTextAfterRange(lastNode.range, `\n${arrowIndentation})`)];
|
|
336
339
|
}
|
|
337
|
-
return [fixer.replaceTextRange([arrowToken.range[1], firstNode.range[0]], ` (\n${innerIndentation}// @focus-start\n${innerIndentation}`), fixer.insertTextAfterRange(lastNode.range, `\n${innerIndentation}// @focus-end\n${arrowIndentation})`)];
|
|
340
|
+
return [fixer.replaceTextRange([arrowToken.range[1], firstNode.range[0]], ` (\n${innerIndentation}// @focus-start @padding 2\n${innerIndentation}`), fixer.insertTextAfterRange(lastNode.range, `\n${innerIndentation}// @focus-end\n${arrowIndentation})`)];
|
|
338
341
|
}
|
|
339
342
|
}
|
|
340
343
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { VariantSource } from "../../CodeHighlighter/types.mjs";
|
|
2
|
+
import type { FallbackNode } from "../../CodeHighlighter/fallbackFormat.mjs";
|
|
3
|
+
/**
|
|
4
|
+
* Decode a `VariantSource` into a form that carries no serialization: a plain
|
|
5
|
+
* string stays a string, while a serialized `hastCompressed` / `hastJson`
|
|
6
|
+
* payload (or a live `HastRoot`) resolves to a live `HastRoot`. The
|
|
7
|
+
* `{ hastJson }` / `{ hastCompressed }` shapes never leak out, so consumers can
|
|
8
|
+
* read the source as text (`stringOrHastToString`) or inspect / transform the
|
|
9
|
+
* HAST tree directly without handling a DEFLATE dictionary.
|
|
10
|
+
*
|
|
11
|
+
* Decoding reuses the shared `decodeHastSource` cache — so a source already
|
|
12
|
+
* decoded for rendering is not inflated again — then returns a
|
|
13
|
+
* `structuredClone` of the tree. The clone matters: `decodeHastSource` hands
|
|
14
|
+
* back a read-only tree shared with the live render, and the result here is
|
|
15
|
+
* handed to user code (the `transformVariant` hook), which must be able to
|
|
16
|
+
* mutate it without corrupting that shared tree. `fallback` is the DEFLATE
|
|
17
|
+
* dictionary for a `hastCompressed` source.
|
|
18
|
+
*/
|
|
19
|
+
export declare function decodeSource(source: VariantSource, fallback?: FallbackNode[]): VariantSource;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { decodeHastSource } from "./decodeHastSource.mjs";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Decode a `VariantSource` into a form that carries no serialization: a plain
|
|
5
|
+
* string stays a string, while a serialized `hastCompressed` / `hastJson`
|
|
6
|
+
* payload (or a live `HastRoot`) resolves to a live `HastRoot`. The
|
|
7
|
+
* `{ hastJson }` / `{ hastCompressed }` shapes never leak out, so consumers can
|
|
8
|
+
* read the source as text (`stringOrHastToString`) or inspect / transform the
|
|
9
|
+
* HAST tree directly without handling a DEFLATE dictionary.
|
|
10
|
+
*
|
|
11
|
+
* Decoding reuses the shared `decodeHastSource` cache — so a source already
|
|
12
|
+
* decoded for rendering is not inflated again — then returns a
|
|
13
|
+
* `structuredClone` of the tree. The clone matters: `decodeHastSource` hands
|
|
14
|
+
* back a read-only tree shared with the live render, and the result here is
|
|
15
|
+
* handed to user code (the `transformVariant` hook), which must be able to
|
|
16
|
+
* mutate it without corrupting that shared tree. `fallback` is the DEFLATE
|
|
17
|
+
* dictionary for a `hastCompressed` source.
|
|
18
|
+
*/
|
|
19
|
+
export function decodeSource(source, fallback) {
|
|
20
|
+
if (typeof source === 'string') {
|
|
21
|
+
return source;
|
|
22
|
+
}
|
|
23
|
+
const root = decodeHastSource(source, fallback);
|
|
24
|
+
return root ? structuredClone(root) : source;
|
|
25
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { VariantSource } from "../../CodeHighlighter/types.mjs";
|
|
2
|
+
import type { FallbackNode } from "../../CodeHighlighter/fallbackFormat.mjs";
|
|
3
|
+
/**
|
|
4
|
+
* Decode a `VariantSource` to its plain text, reusing the shared
|
|
5
|
+
* `decodeHastSource` cache so a `hastCompressed` / `hastJson` payload that was
|
|
6
|
+
* already decoded for rendering is not inflated and parsed a second time.
|
|
7
|
+
*
|
|
8
|
+
* String sources are returned unchanged and need no `fallback`. For an encoded
|
|
9
|
+
* source, `fallback` supplies the DEFLATE dictionary required to decode a
|
|
10
|
+
* `hastCompressed` payload (the file's compact fallback text); omitting it for
|
|
11
|
+
* such a payload surfaces a descriptive error from `decodeHastSource` rather
|
|
12
|
+
* than a cryptic inflate failure.
|
|
13
|
+
*
|
|
14
|
+
* `null` / `undefined` sources resolve to an empty string so callers can treat
|
|
15
|
+
* a missing source the same as an empty file.
|
|
16
|
+
*/
|
|
17
|
+
export declare function decodeSourceToText(source: VariantSource | null | undefined, fallback?: FallbackNode[]): string;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { toText } from 'hast-util-to-text';
|
|
2
|
+
import { decodeHastSource } from "./decodeHastSource.mjs";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Decode a `VariantSource` to its plain text, reusing the shared
|
|
6
|
+
* `decodeHastSource` cache so a `hastCompressed` / `hastJson` payload that was
|
|
7
|
+
* already decoded for rendering is not inflated and parsed a second time.
|
|
8
|
+
*
|
|
9
|
+
* String sources are returned unchanged and need no `fallback`. For an encoded
|
|
10
|
+
* source, `fallback` supplies the DEFLATE dictionary required to decode a
|
|
11
|
+
* `hastCompressed` payload (the file's compact fallback text); omitting it for
|
|
12
|
+
* such a payload surfaces a descriptive error from `decodeHastSource` rather
|
|
13
|
+
* than a cryptic inflate failure.
|
|
14
|
+
*
|
|
15
|
+
* `null` / `undefined` sources resolve to an empty string so callers can treat
|
|
16
|
+
* a missing source the same as an empty file.
|
|
17
|
+
*/
|
|
18
|
+
export function decodeSourceToText(source, fallback) {
|
|
19
|
+
if (source == null || typeof source === 'string') {
|
|
20
|
+
return source ?? '';
|
|
21
|
+
}
|
|
22
|
+
const root = decodeHastSource(source, fallback);
|
|
23
|
+
return root ? toText(root, {
|
|
24
|
+
whitespace: 'pre'
|
|
25
|
+
}) : '';
|
|
26
|
+
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Uses addPathsToVariant for the core logic, then flattens the result
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { decodeSourceToText } from "./decodeSourceToText.mjs";
|
|
8
8
|
import { addPathsToVariant } from "./addCodeVariantPaths.mjs";
|
|
9
9
|
/**
|
|
10
10
|
* Flatten a VariantCode into a flat files structure
|
|
@@ -21,8 +21,9 @@ export function flattenCodeVariant(variant) {
|
|
|
21
21
|
if (variantWithPaths.path && variantWithPaths.source !== undefined) {
|
|
22
22
|
result[variantWithPaths.path] = {
|
|
23
23
|
// The source may be `hastCompressed`; its `fallback` is the DEFLATE
|
|
24
|
-
// dictionary needed to decode it back to text.
|
|
25
|
-
|
|
24
|
+
// dictionary needed to decode it back to text. `decodeSourceToText` reuses
|
|
25
|
+
// the shared decode cache rather than re-inflating on every export.
|
|
26
|
+
source: decodeSourceToText(variantWithPaths.source, variantWithPaths.fallback)
|
|
26
27
|
};
|
|
27
28
|
}
|
|
28
29
|
|
|
@@ -39,7 +40,7 @@ export function flattenCodeVariant(variant) {
|
|
|
39
40
|
continue;
|
|
40
41
|
}
|
|
41
42
|
result[fileWithPath.path] = {
|
|
42
|
-
source:
|
|
43
|
+
source: decodeSourceToText(fileWithPath.source, fileWithPath.fallback),
|
|
43
44
|
...(fileWithPath.metadata && {
|
|
44
45
|
metadata: fileWithPath.metadata
|
|
45
46
|
})
|
|
@@ -159,7 +159,17 @@ export function starryNightGutter(tree, sourceLines, frameSize = 120) {
|
|
|
159
159
|
const startLine = Number(lineChildren[0].properties.dataLn) - 1;
|
|
160
160
|
const endLine = Number(lineChildren[lineChildren.length - 1].properties.dataLn);
|
|
161
161
|
const joined = sourceLines.slice(startLine, endLine).join('\n');
|
|
162
|
-
|
|
162
|
+
// Non-final frames are always followed by more content, so their text
|
|
163
|
+
// ends with the line separator. The final frame's text ends with a
|
|
164
|
+
// newline only when the source itself does — mirroring the highlighted
|
|
165
|
+
// render, whose last `.line` span is then followed by a trailing `\n`
|
|
166
|
+
// text node. `sourceLines` has one more entry than `lineNumber` exactly
|
|
167
|
+
// when the source ended with a newline (the empty segment after it
|
|
168
|
+
// never became a line). This keeps the plain-text fallback the same
|
|
169
|
+
// height as the highlighted render (no hydration jump) AND makes the
|
|
170
|
+
// root fallback dictionary an exact match for the raw source text.
|
|
171
|
+
const sourceEndsWithNewline = sourceLines.length > lineNumber;
|
|
172
|
+
const text = frameIndex < lastIndex || sourceEndsWithNewline ? `${joined}\n` : joined;
|
|
163
173
|
// Cast to `ElementData` because `hast-util-from-parse5` augments
|
|
164
174
|
// it with a required `position` field (upstream bug — should be
|
|
165
175
|
// optional). We're not running through that parser here, so the
|