@mui/internal-docs-infra 0.12.1-canary.1 → 0.12.1-canary.11
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/ChunkProvider/PreloadProvider.mjs +1 -2
- package/ChunkProvider/usePreload.d.mts +1 -1
- package/ChunkProvider/usePreload.mjs +0 -1
- package/CodeControllerContext/CodeControllerContext.d.mts +41 -6
- package/CodeControllerContext/CodeControllerContext.mjs +14 -0
- package/CodeHighlighter/CodeHighlighter.mjs +1 -1
- package/CodeHighlighter/CodeHighlighterClient.d.mts +1 -1
- package/CodeHighlighter/CodeHighlighterClient.mjs +118 -21
- package/CodeHighlighter/CodeHighlighterContext.d.mts +8 -2
- package/CodeHighlighter/buildStringFallback.d.mts +1 -1
- package/CodeHighlighter/codeToFallbackProps.d.mts +1 -1
- package/CodeHighlighter/createClientProps.mjs +4 -1
- package/CodeHighlighter/fallbackCompression.d.mts +1 -1
- package/CodeHighlighter/fallbackFormat.d.mts +1 -1
- package/CodeHighlighter/fallbackFormat.mjs +1 -1
- package/CodeHighlighter/parseControlledCode.d.mts +13 -4
- package/CodeHighlighter/parseControlledCode.mjs +41 -49
- package/CodeHighlighter/prepareInitialSource.mjs +1 -1
- package/CodeHighlighter/resolveFallbackCritical.d.mts +1 -1
- package/CodeHighlighter/resolveFallbackCritical.mjs +1 -1
- package/CodeHighlighter/types.d.mts +22 -1
- package/CodeHighlighter/useGrammarsReady.mjs +44 -9
- package/CodeProvider/createParseSourceWorkerClient.d.mts +6 -0
- package/CodeProvider/createParseSourceWorkerClient.mjs +83 -15
- package/CodeProvider/useCodeProviderValue.mjs +50 -4
- package/abstractCreateDemo/abstractCreateDemo.d.mts +15 -1
- package/abstractCreateDemo/abstractCreateDemo.mjs +8 -0
- package/abstractCreateDemoClient/abstractCreateDemoClient.mjs +4 -0
- package/abstractCreateTypes/abstractCreateTypes.d.mts +12 -1
- package/abstractCreateTypes/abstractCreateTypes.mjs +4 -0
- package/abstractCreateTypes/typesToJsx.d.mts +8 -0
- package/abstractCreateTypes/typesToJsx.mjs +2 -1
- package/cli/loadNextConfig.d.mts +9 -0
- package/cli/loadNextConfig.mjs +11 -2
- package/cli/runValidate.mjs +15 -7
- package/cli/validateWorker.d.mts +1 -0
- package/cli/validateWorker.mjs +2 -1
- package/createDemoData/createDemoData.d.mts +1 -1
- package/package.json +44 -8
- package/pipeline/cacheUtils/constants.d.mts +5 -0
- package/pipeline/cacheUtils/constants.mjs +5 -0
- package/pipeline/cacheUtils/hashCacheContent.d.mts +5 -0
- package/pipeline/cacheUtils/hashCacheContent.mjs +9 -0
- package/pipeline/cacheUtils/index.d.mts +9 -0
- package/pipeline/cacheUtils/index.mjs +7 -0
- package/pipeline/cacheUtils/loadFileCache.d.mts +13 -0
- package/pipeline/cacheUtils/loadFileCache.mjs +20 -0
- package/pipeline/cacheUtils/loadFileCacheEntry.d.mts +13 -0
- package/pipeline/cacheUtils/loadFileCacheEntry.mjs +47 -0
- package/pipeline/cacheUtils/resolveCachePath.d.mts +16 -0
- package/pipeline/cacheUtils/resolveCachePath.mjs +24 -0
- package/pipeline/cacheUtils/saveFileCache.d.mts +17 -0
- package/pipeline/cacheUtils/saveFileCache.mjs +54 -0
- package/pipeline/cacheUtils/types.d.mts +23 -0
- package/pipeline/cacheUtils/types.mjs +1 -0
- package/pipeline/cacheUtils/withFileCache.d.mts +40 -0
- package/pipeline/cacheUtils/withFileCache.mjs +81 -0
- package/pipeline/hastUtils/hastUtils.d.mts +1 -1
- package/pipeline/hastUtils/hastUtils.mjs +0 -1
- package/pipeline/loadIsomorphicCodeSource/loadIsomorphicCodeSource.d.mts +1 -1
- package/pipeline/loadIsomorphicCodeSource/loadIsomorphicCodeSource.mjs +1 -1
- package/pipeline/loadIsomorphicCodeVariant/applyCodeTransform.mjs +0 -1
- package/pipeline/loadIsomorphicCodeVariant/diffHast.d.mts +1 -1
- package/pipeline/loadIsomorphicCodeVariant/hasAllCodeVariants.d.mts +1 -1
- package/pipeline/loadIsomorphicCodeVariant/maybeCodeInitialData.d.mts +1 -1
- package/pipeline/loadPrecomputedSitemap/loadPrecomputedSitemap.d.mts +6 -0
- package/pipeline/loadPrecomputedSitemap/loadPrecomputedSitemap.mjs +2 -1
- package/pipeline/loadPrecomputedTypes/loadPrecomputedTypes.d.mts +6 -0
- package/pipeline/loadPrecomputedTypes/loadPrecomputedTypes.mjs +5 -1
- package/pipeline/loadServerCodeMeta/resolveModulePathWithFs.d.mts +1 -1
- package/pipeline/loadServerCodeMeta/resolveModulePathWithFs.mjs +0 -1
- package/pipeline/loadServerPageIndex/enrichPageIndex.d.mts +15 -0
- package/pipeline/loadServerPageIndex/enrichPageIndex.mjs +50 -0
- package/pipeline/loadServerPageIndex/extractPrefixAndTitle.d.mts +19 -0
- package/pipeline/loadServerPageIndex/extractPrefixAndTitle.mjs +80 -0
- package/pipeline/loadServerPageIndex/index.d.mts +5 -2
- package/pipeline/loadServerPageIndex/index.mjs +4 -1
- package/pipeline/loadServerPageIndex/loadServerPageIndex.d.mts +13 -22
- package/pipeline/loadServerPageIndex/loadServerPageIndex.mjs +32 -124
- package/pipeline/loadServerPageIndex/resolvePageIndexCacheKey.d.mts +13 -0
- package/pipeline/loadServerPageIndex/resolvePageIndexCacheKey.mjs +23 -0
- package/pipeline/loadServerTypes/highlightTypes.d.mts +3 -3
- package/pipeline/loadServerTypes/highlightTypesMeta.d.mts +4 -4
- package/pipeline/loadServerTypes/loadServerTypes.d.mts +2 -2
- package/pipeline/loadServerTypes/loadServerTypes.mjs +67 -7
- package/pipeline/loadServerTypesMeta/createOptimizedProgram.d.mts +2 -1
- package/pipeline/loadServerTypesMeta/formatClass.d.mts +2 -2
- package/pipeline/loadServerTypesMeta/formatComponent.d.mts +2 -2
- package/pipeline/loadServerTypesMeta/formatFunction.d.mts +2 -2
- package/pipeline/loadServerTypesMeta/formatHook.d.mts +2 -2
- package/pipeline/loadServerTypesMeta/formatRaw.d.mts +2 -2
- package/pipeline/loadServerTypesMeta/formatType.d.mts +1 -1
- package/pipeline/loadServerTypesMeta/loadServerTypesMeta.d.mts +7 -7
- package/pipeline/loadServerTypesMeta/loadServerTypesMeta.mjs +1 -1
- package/pipeline/loadServerTypesMeta/processTypes.d.mts +2 -2
- package/pipeline/loadServerTypesMeta/worker.d.mts +1 -1
- package/pipeline/loadServerTypesText/loadServerTypesText.d.mts +16 -2
- package/pipeline/loadServerTypesText/loadServerTypesText.mjs +30 -8
- package/pipeline/loadServerTypesText/normalizeTypesSourceDataForCache.d.mts +2 -0
- package/pipeline/loadServerTypesText/normalizeTypesSourceDataForCache.mjs +144 -0
- package/pipeline/loadServerTypesText/resolveTypesCacheKey.d.mts +19 -0
- package/pipeline/loadServerTypesText/resolveTypesCacheKey.mjs +29 -0
- package/pipeline/loaderUtils/parseImportsAndComments.d.mts +5 -3
- package/pipeline/loaderUtils/parseImportsAndComments.mjs +284 -40
- package/pipeline/parseCreateFactoryCall/parseCreateFactoryCall.d.mts +2 -2
- package/pipeline/parseCreateFactoryCall/parseCreateFactoryCall.mjs +2 -3
- package/pipeline/parseSource/detectFileTypes.d.mts +16 -0
- package/pipeline/parseSource/detectFileTypes.mjs +44 -0
- package/pipeline/syncPageIndex/mergeMetadataMarkdown.d.mts +25 -1
- package/pipeline/syncPageIndex/mergeMetadataMarkdown.mjs +79 -49
- package/pipeline/syncPageIndex/metadataToMarkdown.d.mts +15 -1
- package/pipeline/syncPageIndex/metadataToMarkdown.mjs +32 -10
- package/pipeline/syncPageIndex/syncPageIndex.d.mts +12 -0
- package/pipeline/syncPageIndex/syncPageIndex.mjs +72 -12
- package/pipeline/syncTypes/generateTypesMarkdown.d.mts +2 -2
- package/pipeline/syncTypes/syncTypes.d.mts +7 -0
- package/pipeline/syncTypes/syncTypes.mjs +31 -1
- package/pipeline/transformHtmlCodeBlock/transformHtmlCodeBlock.mjs +1 -1
- package/pipeline/transformMarkdownCode/transformMarkdownCode.mjs +25 -15
- package/pipeline/transformMarkdownMetadata/transformMarkdownMetadata.mjs +3 -0
- package/pipeline/transformMarkdownMetadata/types.d.mts +8 -1
- package/useCode/EditableEngine.d.mts +1 -1
- package/useCode/Pre.d.mts +9 -2
- package/useCode/Pre.mjs +5 -4
- package/useCode/TransformEngine.d.mts +1 -1
- package/useCode/useCode.d.mts +17 -1
- package/useCode/useCode.mjs +10 -0
- package/useCode/useCopyFunctionality.d.mts +2 -2
- package/useCode/useEditable.browser.mjs +0 -1
- package/useCode/useFileNavigation.d.mts +3 -0
- package/useCode/useFileNavigation.mjs +3 -1
- package/useCode/useSourceEditing.mjs +44 -9
- package/useCode/useSourceEnhancing.mjs +41 -9
- package/useCode/useTransformManagement.d.mts +2 -2
- package/useCode/useTransformManagement.mjs +0 -1
- package/useCode/useUIState.d.mts +4 -0
- package/useCode/useUIState.mjs +8 -1
- package/useCode/useVariantSelection.d.mts +1 -1
- package/useCoordinated/useCoordinated.d.mts +1 -1
- package/useCoordinated/useCoordinatedLocalStorage.d.mts +1 -1
- package/useCoordinated/useCoordinatedLocalStorage.mjs +0 -1
- package/useCoordinated/useCoordinatedPreference.d.mts +1 -1
- package/useCoordinated/useCoordinatedPreference.mjs +0 -1
- package/useCrossTabState/index.d.mts +2 -0
- package/useCrossTabState/index.mjs +2 -0
- package/useCrossTabState/useCrossTabMirror.d.mts +26 -0
- package/useCrossTabState/useCrossTabMirror.mjs +108 -0
- package/useCrossTabState/useCrossTabState.d.mts +21 -0
- package/useCrossTabState/useCrossTabState.mjs +31 -0
- package/useDemo/exportVariant.mjs +2 -4
- package/useDemo/exportVariantAsCra.d.mts +1 -1
- package/useDemo/exportVariantAsCra.mjs +0 -1
- package/useDemo/useDemo.d.mts +4 -1
- package/useDemo/useDemo.mjs +5 -0
- package/useDemoController/BuildEngine.d.mts +2 -0
- package/useDemoController/BuildEngine.mjs +10 -0
- package/useDemoController/DemoRunner.d.mts +34 -0
- package/useDemoController/DemoRunner.mjs +83 -0
- package/useDemoController/ErrorBoundary.d.mts +34 -0
- package/useDemoController/ErrorBoundary.mjs +49 -0
- package/useDemoController/Runner.d.mts +44 -0
- package/useDemoController/Runner.mjs +71 -0
- package/useDemoController/absolutizeImports.d.mts +13 -0
- package/useDemoController/absolutizeImports.mjs +73 -0
- package/useDemoController/buildScope.d.mts +48 -0
- package/useDemoController/buildScope.mjs +268 -0
- package/useDemoController/collectSources.d.mts +67 -0
- package/useDemoController/collectSources.mjs +92 -0
- package/useDemoController/compileCssModule.d.mts +64 -0
- package/useDemoController/compileCssModule.mjs +40 -0
- package/useDemoController/compileCssWithPostcss.d.mts +17 -0
- package/useDemoController/compileCssWithPostcss.mjs +89 -0
- package/useDemoController/compileModule.d.mts +14 -0
- package/useDemoController/compileModule.mjs +17 -0
- package/useDemoController/constants.d.mts +13 -0
- package/useDemoController/constants.mjs +13 -0
- package/useDemoController/createRequire.d.mts +10 -0
- package/useDemoController/createRequire.mjs +17 -0
- package/useDemoController/createTranspileWorkerClient.d.mts +27 -0
- package/useDemoController/createTranspileWorkerClient.mjs +139 -0
- package/useDemoController/cssModules.d.mts +47 -0
- package/useDemoController/currentBrowserTarget.d.mts +16 -0
- package/useDemoController/currentBrowserTarget.mjs +36 -0
- package/useDemoController/evalCode.d.mts +12 -0
- package/useDemoController/evalCode.mjs +35 -0
- package/useDemoController/generateCssModuleSource.d.mts +11 -0
- package/useDemoController/generateCssModuleSource.mjs +55 -0
- package/useDemoController/generateElement.d.mts +21 -0
- package/useDemoController/generateElement.mjs +26 -0
- package/useDemoController/hashString.d.mts +11 -0
- package/useDemoController/hashString.mjs +20 -0
- package/useDemoController/importCode.d.mts +11 -0
- package/useDemoController/importCode.mjs +15 -0
- package/useDemoController/index.d.mts +1 -0
- package/useDemoController/index.mjs +1 -0
- package/useDemoController/instantiateElement.d.mts +24 -0
- package/useDemoController/instantiateElement.mjs +57 -0
- package/useDemoController/instantiateModule.d.mts +17 -0
- package/useDemoController/instantiateModule.mjs +24 -0
- package/useDemoController/resolveCssImports.d.mts +27 -0
- package/useDemoController/resolveCssImports.mjs +79 -0
- package/useDemoController/transformCode.d.mts +14 -0
- package/useDemoController/transformCode.mjs +42 -0
- package/useDemoController/transpileClientSingleton.d.mts +10 -0
- package/useDemoController/transpileClientSingleton.mjs +83 -0
- package/useDemoController/transpileSource.d.mts +29 -0
- package/useDemoController/transpileSource.mjs +36 -0
- package/useDemoController/transpileWorker.d.mts +14 -0
- package/useDemoController/transpileWorker.mjs +41 -0
- package/useDemoController/types.d.mts +30 -0
- package/useDemoController/types.mjs +1 -0
- package/useDemoController/useDemoController.d.mts +65 -0
- package/useDemoController/useDemoController.mjs +184 -0
- package/useDemoController/useRunner.d.mts +53 -0
- package/useDemoController/useRunner.mjs +118 -0
- package/useDemoController/useVariantBuilds.d.mts +31 -0
- package/useDemoController/useVariantBuilds.mjs +188 -0
- package/useSearch/types.d.mts +1 -1
- package/useType/TypesDataProvider.mjs +1 -2
- package/useType/useType.d.mts +1 -1
- package/useType/useTypeProp.d.mts +1 -1
- package/withDocsInfra/withDeploymentConfig.mjs +7 -0
- package/withDocsInfra/withDocsInfra.d.mts +14 -0
- package/withDocsInfra/withDocsInfra.mjs +25 -11
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
import { PreloadContext } from "./PreloadContext.mjs";
|
|
5
|
-
|
|
5
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
6
6
|
/**
|
|
7
7
|
* Scopes a cross-instance preload cache (typically at a layout). Descendants
|
|
8
8
|
* call `usePreload` to start dynamic imports of shared helpers keyed by a
|
|
@@ -10,7 +10,6 @@ import { PreloadContext } from "./PreloadContext.mjs";
|
|
|
10
10
|
* instance reuses its promise - so a helper a chunk's data implies (a transform
|
|
11
11
|
* fn, say) is fetched once, in parallel with the content, across the page.
|
|
12
12
|
*/
|
|
13
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
14
13
|
export function PreloadProvider({
|
|
15
14
|
children
|
|
16
15
|
}) {
|
|
@@ -43,6 +43,12 @@ export interface CodeControllerContext {
|
|
|
43
43
|
* e.g. `{ variantA: {}, variantB: {} }`.
|
|
44
44
|
*/
|
|
45
45
|
components?: Record<string, React.ReactNode> | undefined;
|
|
46
|
+
/**
|
|
47
|
+
* Current runtime error message per variant key (or `null` when the variant
|
|
48
|
+
* rendered cleanly), as reported by the preview components. Demos surface the
|
|
49
|
+
* selected variant's error via `useDemo().error`.
|
|
50
|
+
*/
|
|
51
|
+
errors?: Record<string, string | null> | undefined;
|
|
46
52
|
/**
|
|
47
53
|
* Additional source enhancers to apply to parsed HAST sources.
|
|
48
54
|
* These are merged with enhancers from CodeProvider and useCode opts.
|
|
@@ -52,13 +58,38 @@ export interface CodeControllerContext {
|
|
|
52
58
|
* Called once when a block in this controller's scope first activates for
|
|
53
59
|
* editing — immediately for `editActivation: 'eager'`, or on first engagement
|
|
54
60
|
* (hover / focus / click) for `'interaction'`. Lets the host react to "editing
|
|
55
|
-
* has begun" (e.g. fetch the editable source, light up UI
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
61
|
+
* has begun" (e.g. fetch the editable source, light up UI, or preload its live
|
|
62
|
+
* runtime). `deps` reports which file kinds the block spans — `js` when it has any
|
|
63
|
+
* JS/TS/JSX/TSX/MJS file, `css` when it has any CSS file — so the host can warm only
|
|
64
|
+
* the engine chunks it will need. `CodeHighlighter` separately warms its own
|
|
65
|
+
* live-editing dependencies (engine, grammars, worker) at the same moment, so a host
|
|
66
|
+
* that only wants the default behavior can leave this unset.
|
|
59
67
|
*/
|
|
60
|
-
onActivate?: (
|
|
68
|
+
onActivate?: (deps: {
|
|
69
|
+
js: boolean;
|
|
70
|
+
css: boolean;
|
|
71
|
+
}) => void;
|
|
61
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* Props a code-controller component receives: `children` to wrap and the optional
|
|
75
|
+
* `url` identifying the demo, plus any custom props `T` (typically a specific
|
|
76
|
+
* controller's options). Mirrors `ContentProps` — a small base extended by `T`.
|
|
77
|
+
*/
|
|
78
|
+
export type CodeControllerProps<T extends {} = {}> = {
|
|
79
|
+
children: React.ReactNode;
|
|
80
|
+
/**
|
|
81
|
+
* The demo's url — identifies this controller, e.g. as the per-demo key for
|
|
82
|
+
* cross-tab sync. Supplied by the demo factory, or passed explicitly.
|
|
83
|
+
*/
|
|
84
|
+
url?: string;
|
|
85
|
+
} & T;
|
|
86
|
+
/**
|
|
87
|
+
* A code-controller component — the counterpart to `DemoContent`. It wraps `children`
|
|
88
|
+
* in a {@link CodeControllerContext} provider, typically sourcing the value from a hook
|
|
89
|
+
* such as `useDemoController`. Parameterize with `T` for the controller's own props
|
|
90
|
+
* (e.g. `CodeController<UseDemoControllerOptions>`).
|
|
91
|
+
*/
|
|
92
|
+
export type CodeController<T extends {} = {}> = React.ComponentType<CodeControllerProps<T>>;
|
|
62
93
|
export declare const CodeControllerContext: React.Context<CodeControllerContext | undefined>;
|
|
63
94
|
/**
|
|
64
95
|
* Hook to access controlled code state and setters. This is useful for custom
|
|
@@ -81,6 +112,10 @@ export declare function useControlledCode(): {
|
|
|
81
112
|
setCode: React.Dispatch<React.SetStateAction<ControlledCode | undefined>> | undefined;
|
|
82
113
|
setSelection: React.Dispatch<React.SetStateAction<Selection>> | undefined;
|
|
83
114
|
components: Record<string, React.ReactNode> | undefined;
|
|
115
|
+
errors: Record<string, string | null> | undefined;
|
|
84
116
|
sourceEnhancers: SourceEnhancers | undefined;
|
|
85
|
-
onActivate: ((
|
|
117
|
+
onActivate: ((deps: {
|
|
118
|
+
js: boolean;
|
|
119
|
+
css: boolean;
|
|
120
|
+
}) => void) | undefined;
|
|
86
121
|
};
|
|
@@ -10,6 +10,19 @@ import * as React from 'react';
|
|
|
10
10
|
* event fires.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Props a code-controller component receives: `children` to wrap and the optional
|
|
15
|
+
* `url` identifying the demo, plus any custom props `T` (typically a specific
|
|
16
|
+
* controller's options). Mirrors `ContentProps` — a small base extended by `T`.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* A code-controller component — the counterpart to `DemoContent`. It wraps `children`
|
|
21
|
+
* in a {@link CodeControllerContext} provider, typically sourcing the value from a hook
|
|
22
|
+
* such as `useDemoController`. Parameterize with `T` for the controller's own props
|
|
23
|
+
* (e.g. `CodeController<UseDemoControllerOptions>`).
|
|
24
|
+
*/
|
|
25
|
+
|
|
13
26
|
export const CodeControllerContext = /*#__PURE__*/React.createContext(undefined);
|
|
14
27
|
|
|
15
28
|
/**
|
|
@@ -36,6 +49,7 @@ export function useControlledCode() {
|
|
|
36
49
|
setCode: context?.setCode,
|
|
37
50
|
setSelection: context?.setSelection,
|
|
38
51
|
components: context?.components,
|
|
52
|
+
errors: context?.errors,
|
|
39
53
|
sourceEnhancers: context?.sourceEnhancers,
|
|
40
54
|
onActivate: context?.onActivate
|
|
41
55
|
};
|
|
@@ -107,7 +107,7 @@ export function CodeHighlighter(props) {
|
|
|
107
107
|
|
|
108
108
|
// No ContentLoading: render the content/full-load directly, with no loading
|
|
109
109
|
// fallback (the client shows nothing until content is ready). For
|
|
110
|
-
// `
|
|
110
|
+
// `highlightAfter: 'init'`, `createClientProps` folds each variant's highlighted-visible
|
|
111
111
|
// `fallbackCritical` over its plain `fallback`, so `<Pre>` paints the visible frames
|
|
112
112
|
// highlighted on the first render (no decompression) and decodes the full tree after
|
|
113
113
|
// paint (the `decodeAllowed` latch).
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { CodeHighlighterClientProps } from "./types.mjs";
|
|
2
2
|
export declare function CodeHighlighterClient(props: CodeHighlighterClientProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -18,6 +18,7 @@ import { useSpeculativeUseCodePreload } from "./useSpeculativeUseCodePreload.mjs
|
|
|
18
18
|
import { useSpeculativeGrammarPreload } from "./useSpeculativeGrammarPreload.mjs";
|
|
19
19
|
import { useGrammarsReady } from "./useGrammarsReady.mjs";
|
|
20
20
|
import { detectGrammarScopes } from "../pipeline/parseSource/detectGrammarScopes.mjs";
|
|
21
|
+
import { detectFileTypes } from "../pipeline/parseSource/detectFileTypes.mjs";
|
|
21
22
|
import { useChunk } from "../CoordinatedLazy/useChunk.mjs";
|
|
22
23
|
import { useCoordinatedSwap } from "../CoordinatedLazy/useCoordinatedSwap.mjs";
|
|
23
24
|
import { CoordinatedFallbackContext } from "../CoordinatedLazy/CoordinatedFallbackContext.mjs";
|
|
@@ -27,12 +28,40 @@ import * as Errors from "./errors.mjs";
|
|
|
27
28
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
28
29
|
const DEBUG = false; // Set to true for debugging purposes
|
|
29
30
|
|
|
31
|
+
// Safety-net deadline (ms) for the default `'idle'` highlight/enhance swaps. They
|
|
32
|
+
// defer the swap to `requestIdleCallback`, which a busy main thread can starve
|
|
33
|
+
// INDEFINITELY — leaving code stuck at its un-highlighted first paint until a full
|
|
34
|
+
// reload. The `timeout` guarantees the swap still runs even if the browser never
|
|
35
|
+
// goes idle (idle normally wins long before this deadline).
|
|
36
|
+
const IDLE_SWAP_TIMEOUT_MS = 10_000;
|
|
37
|
+
|
|
38
|
+
// Safety-net deadline (ms) for the async transform-deltas pipeline. If it neither
|
|
39
|
+
// resolves nor rejects (a stalled worker / hung delta computation), the block would
|
|
40
|
+
// otherwise wait on `waitingForTransformedCode` forever — code stuck un-highlighted
|
|
41
|
+
// until a reload. On timeout we publish the un-delta'd parsed HAST so the gate drops.
|
|
42
|
+
const TRANSFORM_PIPELINE_TIMEOUT_MS = 10_000;
|
|
43
|
+
|
|
30
44
|
// `useChunk` is the chunk loader/renderer, but here we use only its loading
|
|
31
45
|
// engine (load-when-enabled + abort + `refresh()` with stale-while-revalidate),
|
|
32
46
|
// so the content component is an unused placeholder.
|
|
33
47
|
function NoopChunkContent() {
|
|
34
48
|
return null;
|
|
35
49
|
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Inject a build-time `fallback` into a bridged live-preview node. The controller's
|
|
53
|
+
* components are erased to `ReactNode` across the context, so the type argument on
|
|
54
|
+
* `isValidElement` re-narrows the node to one that accepts `fallback` — no cast. A
|
|
55
|
+
* non-element node (nothing to clone) is returned untouched.
|
|
56
|
+
*/
|
|
57
|
+
function injectFallback(node, fallback) {
|
|
58
|
+
if (! /*#__PURE__*/React.isValidElement(node)) {
|
|
59
|
+
return node;
|
|
60
|
+
}
|
|
61
|
+
return /*#__PURE__*/React.cloneElement(node, {
|
|
62
|
+
fallback
|
|
63
|
+
});
|
|
64
|
+
}
|
|
36
65
|
function useInitialData({
|
|
37
66
|
variants,
|
|
38
67
|
variantName,
|
|
@@ -120,7 +149,7 @@ function useInitialData({
|
|
|
120
149
|
}
|
|
121
150
|
|
|
122
151
|
// Fold each variant's highlighted-visible `fallbackCritical` over its plain
|
|
123
|
-
// `fallback` (under `
|
|
152
|
+
// `fallback` (under `highlightAfter: 'init'`) and strip the staging field, so the
|
|
124
153
|
// hoisted loading fallback is already highlighted and nothing leaks to the
|
|
125
154
|
// content. `collapseToEmpty` isn't threaded into the client here, so the `false`
|
|
126
155
|
// form is assumed: under collapse-to-empty this may promote a few frames that are
|
|
@@ -337,13 +366,15 @@ function useCodeParsing({
|
|
|
337
366
|
const [isHighlightAllowed, setIsHighlightAllowed] = React.useState(highlightAfter === 'init' || highlightAfter === 'hydration' && isHydrated);
|
|
338
367
|
React.useEffect(() => {
|
|
339
368
|
if (highlightAfter === 'idle') {
|
|
340
|
-
return requestIdle(() => setIsHighlightAllowed(true)
|
|
369
|
+
return requestIdle(() => setIsHighlightAllowed(true), {
|
|
370
|
+
timeout: IDLE_SWAP_TIMEOUT_MS
|
|
371
|
+
});
|
|
341
372
|
}
|
|
342
373
|
return undefined;
|
|
343
374
|
}, [highlightAfter]);
|
|
344
375
|
|
|
345
376
|
// Highlight instantly once hydrated, as a non-blocking client transition,
|
|
346
|
-
// rather than deferring to a scheduled task. (`
|
|
377
|
+
// rather than deferring to a scheduled task. (`highlightAfter: 'idle'` above is
|
|
347
378
|
// the mode that deliberately keeps the unhighlighted first paint and swaps in
|
|
348
379
|
// the highlighted tree on a later idle render.)
|
|
349
380
|
React.useEffect(() => {
|
|
@@ -421,9 +452,9 @@ function useCodeParsing({
|
|
|
421
452
|
const waitingForParsedCode = shouldHighlight && !!code && !allVariantsAlreadyHighlighted && !parsedCode;
|
|
422
453
|
|
|
423
454
|
// Only signal `deferHighlight` while a highlight pass is actively in
|
|
424
|
-
// flight. When `shouldHighlight` is `false` (e.g. `
|
|
425
|
-
// before the idle window fires
|
|
426
|
-
//
|
|
455
|
+
// flight. When `shouldHighlight` is `false` (e.g. `highlightAfter: 'idle'`
|
|
456
|
+
// before the idle window fires) we render the un-highlighted source
|
|
457
|
+
// as-is — downstream
|
|
427
458
|
// consumers like `useTransformManagement`'s `awaitHighlight` gate must
|
|
428
459
|
// commit eagerly against that source instead of blocking the barrier
|
|
429
460
|
// indefinitely. Once the trigger fires, `shouldHighlight` flips true,
|
|
@@ -436,7 +467,7 @@ function useCodeParsing({
|
|
|
436
467
|
// needs to know whether the published `code` should be rendered as
|
|
437
468
|
// highlighted HAST *now*. That answer is false in two distinct
|
|
438
469
|
// windows that `deferHighlight` deliberately collapses out:
|
|
439
|
-
// 1. The trigger for `
|
|
470
|
+
// 1. The trigger for `highlightAfter: 'hydration' | 'idle'`
|
|
440
471
|
// hasn't fired yet — `shouldHighlight` is still false. The
|
|
441
472
|
// precomputed `codeWithGlobals` already contains HAST, so
|
|
442
473
|
// without a render-side gate `<Pre>` would render highlighted
|
|
@@ -483,9 +514,30 @@ function useCodeTransforms({
|
|
|
483
514
|
// so this effect never publishes a synchronous pass-through state.
|
|
484
515
|
React.useEffect(() => {
|
|
485
516
|
if (!parsedCode || !sourceParser || !computeHastDeltasLoader) {
|
|
486
|
-
return;
|
|
517
|
+
return undefined;
|
|
487
518
|
}
|
|
488
519
|
|
|
520
|
+
// `settled` guards against two wedges: (1) a late write from a SUPERSEDED run
|
|
521
|
+
// (the cleanup flips it so an in-flight pipeline for an older `parsedCode` can't
|
|
522
|
+
// clobber the current one), and (2) the timeout below committing twice. The first
|
|
523
|
+
// commit wins.
|
|
524
|
+
let settled = false;
|
|
525
|
+
const commit = output => {
|
|
526
|
+
if (!settled) {
|
|
527
|
+
settled = true;
|
|
528
|
+
setTransformedState({
|
|
529
|
+
input: parsedCode,
|
|
530
|
+
output
|
|
531
|
+
});
|
|
532
|
+
}
|
|
533
|
+
};
|
|
534
|
+
|
|
535
|
+
// Safety net: if the pipeline neither resolves NOR rejects (a stalled worker / hung
|
|
536
|
+
// delta computation), the `catch` never fires and `waitingForTransformedCode` would
|
|
537
|
+
// stay true forever. Fall back to the un-delta'd parsed HAST so the gate drops and
|
|
538
|
+
// the block shows highlighted (un-transformed) code rather than plain text forever.
|
|
539
|
+
const timer = setTimeout(() => commit(parsedCode), TRANSFORM_PIPELINE_TIMEOUT_MS);
|
|
540
|
+
|
|
489
541
|
// Process transformations for all variants
|
|
490
542
|
(async () => {
|
|
491
543
|
try {
|
|
@@ -494,18 +546,18 @@ function useCodeTransforms({
|
|
|
494
546
|
// kept out of the initial bundle under CodeProviderLazy.
|
|
495
547
|
const [parseSource, computeHastDeltas] = await Promise.all([sourceParser, computeHastDeltasLoader()]);
|
|
496
548
|
const enhanced = await computeHastDeltas(parsedCode, parseSource);
|
|
497
|
-
|
|
498
|
-
input: parsedCode,
|
|
499
|
-
output: enhanced
|
|
500
|
-
});
|
|
549
|
+
commit(enhanced);
|
|
501
550
|
} catch (error) {
|
|
502
551
|
console.error(new Errors.ErrorCodeHighlighterClientTransformProcessingFailure(error));
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
});
|
|
552
|
+
commit(parsedCode);
|
|
553
|
+
} finally {
|
|
554
|
+
clearTimeout(timer);
|
|
507
555
|
}
|
|
508
556
|
})();
|
|
557
|
+
return () => {
|
|
558
|
+
settled = true; // a newer run (or unmount) supersedes this one; ignore late writes
|
|
559
|
+
clearTimeout(timer);
|
|
560
|
+
};
|
|
509
561
|
}, [parsedCode, sourceParser, computeHastDeltasLoader]);
|
|
510
562
|
|
|
511
563
|
// When the full async pipeline is wired, expose the cached output regardless
|
|
@@ -903,10 +955,21 @@ export function CodeHighlighterClient(props) {
|
|
|
903
955
|
// the editable speculative preload below and notifies the CodeControllerContext.
|
|
904
956
|
const [editingActivated, setEditingActivated] = React.useState(false);
|
|
905
957
|
const controllerOnActivate = controlled?.onActivate;
|
|
958
|
+
// Which live-editing engine chunks the controller should preload on activation: `js`
|
|
959
|
+
// if the demo has any JS/TS file, `css` if any CSS file. Stable across keystrokes
|
|
960
|
+
// (editing changes source content, never which files exist), like the grammar scopes
|
|
961
|
+
// below.
|
|
962
|
+
const editableFileTypes = React.useMemo(() => {
|
|
963
|
+
const editableCode = props.code ?? code;
|
|
964
|
+
return editableCode ? detectFileTypes(editableCode) : {
|
|
965
|
+
js: false,
|
|
966
|
+
css: false
|
|
967
|
+
};
|
|
968
|
+
}, [props.code, code]);
|
|
906
969
|
const handleEditingActivated = React.useCallback(() => {
|
|
907
970
|
setEditingActivated(true);
|
|
908
|
-
controllerOnActivate?.();
|
|
909
|
-
}, [controllerOnActivate]);
|
|
971
|
+
controllerOnActivate?.(editableFileTypes);
|
|
972
|
+
}, [controllerOnActivate, editableFileTypes]);
|
|
910
973
|
|
|
911
974
|
// Grammar scopes the editable files need for live re-highlighting. Unlike the
|
|
912
975
|
// speculative highlight/transform preloads — which intentionally skip
|
|
@@ -1061,7 +1124,9 @@ export function CodeHighlighterClient(props) {
|
|
|
1061
1124
|
const [isEnhanceAllowed, setIsEnhanceAllowed] = React.useState(enhanceAfter === 'init' || enhanceAfter === 'hydration' && isHydrated);
|
|
1062
1125
|
React.useEffect(() => {
|
|
1063
1126
|
if (enhanceAfter === 'idle') {
|
|
1064
|
-
return requestIdle(() => setIsEnhanceAllowed(true)
|
|
1127
|
+
return requestIdle(() => setIsEnhanceAllowed(true), {
|
|
1128
|
+
timeout: IDLE_SWAP_TIMEOUT_MS
|
|
1129
|
+
});
|
|
1065
1130
|
}
|
|
1066
1131
|
return undefined;
|
|
1067
1132
|
}, [enhanceAfter]);
|
|
@@ -1268,13 +1333,45 @@ export function CodeHighlighterClient(props) {
|
|
|
1268
1333
|
setFallbackHasts: handleSetFallbackHasts,
|
|
1269
1334
|
onHookCalled: handleHookCalled
|
|
1270
1335
|
}), [variantName, codeForFallback, fileName, props.fallbackUsesExtraFiles, props.fallbackUsesAllVariants, handleSetFallbackHasts, handleHookCalled]);
|
|
1336
|
+
|
|
1337
|
+
// Keep the build-time render for any variant the controller hasn't produced a live
|
|
1338
|
+
// preview for yet — an in-flight build, a build error, or a variant with no live build
|
|
1339
|
+
// at all — by merging PER VARIANT (live entries override the build-time ones; the rest
|
|
1340
|
+
// stay visible). A whole-object swap (`controlled?.components || props.components`) would
|
|
1341
|
+
// drop the build-time render for ALL variants the instant ANY one went live, flashing
|
|
1342
|
+
// empty previews; the merge keeps "no live entry ⇒ show the build-time render".
|
|
1343
|
+
//
|
|
1344
|
+
// Each live entry is the lazy `DemoRunner`. Render it under a `Suspense` whose fallback is
|
|
1345
|
+
// that variant's build-time render (shown while the chunk resolves), AND inject the same
|
|
1346
|
+
// build-time render as the runner's `fallback` prop — so a live preview that throws on its
|
|
1347
|
+
// FIRST render, before any successful one (e.g. a render-error first edit, where the
|
|
1348
|
+
// baseline never got to paint), shows the original instead of blanking.
|
|
1349
|
+
const bridgedComponents = React.useMemo(() => {
|
|
1350
|
+
const live = controlled?.components;
|
|
1351
|
+
if (!live) {
|
|
1352
|
+
return props.components;
|
|
1353
|
+
}
|
|
1354
|
+
const merged = {
|
|
1355
|
+
...(props.components || {})
|
|
1356
|
+
};
|
|
1357
|
+
for (const variant of Object.keys(live)) {
|
|
1358
|
+
const buildTime = props.components?.[variant];
|
|
1359
|
+
const liveNode = injectFallback(live[variant], buildTime);
|
|
1360
|
+
merged[variant] = /*#__PURE__*/React.createElement(React.Suspense, {
|
|
1361
|
+
key: variant,
|
|
1362
|
+
fallback: buildTime ?? null
|
|
1363
|
+
}, liveNode);
|
|
1364
|
+
}
|
|
1365
|
+
return merged;
|
|
1366
|
+
}, [controlled?.components, props.components]);
|
|
1271
1367
|
const context = React.useMemo(() => ({
|
|
1272
1368
|
code: overlaidCode,
|
|
1273
1369
|
// Use processed/transformed code
|
|
1274
1370
|
setCode: controlled?.setCode,
|
|
1275
1371
|
selection: controlled?.selection || selection,
|
|
1276
1372
|
setSelection: controlled?.setSelection || setSelection,
|
|
1277
|
-
components:
|
|
1373
|
+
components: bridgedComponents,
|
|
1374
|
+
errors: controlled?.errors,
|
|
1278
1375
|
// Only suppress when an external CodeController owns the code; static
|
|
1279
1376
|
// `props.code` still needs the locally-computed list.
|
|
1280
1377
|
availableTransforms: controlled?.code ? [] : availableTransforms,
|
|
@@ -1287,7 +1384,7 @@ export function CodeHighlighterClient(props) {
|
|
|
1287
1384
|
onEditingActivated: handleEditingActivated,
|
|
1288
1385
|
refresh,
|
|
1289
1386
|
preParsedCache
|
|
1290
|
-
}), [overlaidCode, controlled?.setCode, selection, controlled?.selection, controlled?.setSelection, controlled?.
|
|
1387
|
+
}), [overlaidCode, controlled?.setCode, selection, controlled?.selection, controlled?.setSelection, bridgedComponents, controlled?.errors, controlled?.code, availableTransforms, props.url, deferHighlight, activeFallbacks, highlightReady, highlightAfter, editActivation, handleEditingActivated, refresh, preParsedCache]);
|
|
1291
1388
|
if (!props.variants && !props.components && !activeCode) {
|
|
1292
1389
|
throw new Errors.ErrorCodeHighlighterClientMissingData();
|
|
1293
1390
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import type { Code, ControlledCode, Fallbacks, HastRoot } from "./types.mjs";
|
|
3
|
+
import type { Selection } from "../CodeControllerContext/index.mjs";
|
|
4
4
|
/**
|
|
5
5
|
* One cached pre-parsed file. Stored per-fileName: each new write replaces
|
|
6
6
|
* any previous entry for that file. The `source` string is the cache key —
|
|
@@ -18,6 +18,12 @@ export interface CodeHighlighterContextType {
|
|
|
18
18
|
selection?: Selection;
|
|
19
19
|
setSelection?: React.Dispatch<React.SetStateAction<Selection>>;
|
|
20
20
|
components?: Record<string, React.ReactNode>;
|
|
21
|
+
/**
|
|
22
|
+
* Current runtime error message per variant key (or `null` when the variant
|
|
23
|
+
* rendered cleanly), bridged from the controller context. Surfaced through
|
|
24
|
+
* `useDemo().error`.
|
|
25
|
+
*/
|
|
26
|
+
errors?: Record<string, string | null>;
|
|
21
27
|
availableTransforms?: string[];
|
|
22
28
|
url?: string;
|
|
23
29
|
deferHighlight?: boolean;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { SourceComments, SourceEnhancers } from "./types.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import type { FallbackNode } from "./fallbackFormat.mjs";
|
|
3
3
|
export interface StringFallbackResult {
|
|
4
4
|
/** Compact, windowed fallback frames (text only — `.line` spans stripped). */
|
|
5
5
|
fallback: FallbackNode[];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { BaseContentLoadingProps, Code, Fallbacks } from "./types.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import type { SourceLineCounts } from "../useCode/sourceLineCounts.mjs";
|
|
3
3
|
/** Per-variant → per-file line metadata threaded for the fallback. */
|
|
4
4
|
export type LineCountsByVariant = Record<string, Record<string, SourceLineCounts>>;
|
|
5
5
|
export declare function codeToFallbackProps(variant: string, code?: Code, _fileName?: string, _needsAllFiles?: boolean, needsAllVariants?: boolean, allFallbackHasts?: Record<string, Fallbacks>, allLineCounts?: LineCountsByVariant): BaseContentLoadingProps;
|
|
@@ -13,7 +13,7 @@ export function createClientProps(props) {
|
|
|
13
13
|
const enhanceAfter = props.enhanceAfter === 'stream' ? 'init' : props.enhanceAfter;
|
|
14
14
|
|
|
15
15
|
// Resolve the staging `fallbackCritical` on every variant of both carriers before
|
|
16
|
-
// they cross to the client: under `
|
|
16
|
+
// they cross to the client: under `highlightAfter: 'init'` (not `collapseToEmpty`)
|
|
17
17
|
// promote it over the plain `fallback` so the first paint is highlighted with no
|
|
18
18
|
// decompression, and always strip it so it never reaches `Content`/`ContentLoading`
|
|
19
19
|
// or bloats the payload. `code` and `precompute` are forwarded separately (the
|
|
@@ -45,6 +45,9 @@ export function createClientProps(props) {
|
|
|
45
45
|
} : undefined),
|
|
46
46
|
...(props.initialExpanded !== undefined ? {
|
|
47
47
|
initialExpanded: props.initialExpanded
|
|
48
|
+
} : undefined),
|
|
49
|
+
...(props.initialDisabled !== undefined ? {
|
|
50
|
+
initialDisabled: props.initialDisabled
|
|
48
51
|
} : undefined)
|
|
49
52
|
};
|
|
50
53
|
return {
|
|
@@ -79,7 +79,7 @@ export declare function fallbackIsHighlighted(fallback: FallbackNode[]): boolean
|
|
|
79
79
|
* render (`visibleFrames`). Off-screen frames are omitted — they flatten to exactly
|
|
80
80
|
* {@link buildRootFallback}'s plain output, so storing them would just duplicate
|
|
81
81
|
* `fallback` in the precompute. {@link promoteCriticalFallback} splices these back
|
|
82
|
-
* over the plain fallback for `
|
|
82
|
+
* over the plain fallback for `highlightAfter: 'init'` (paint highlighted on the first
|
|
83
83
|
* render, zero decompression). Frame indices count `span.frame` children only,
|
|
84
84
|
* matching `getInitialVisibleFrames`.
|
|
85
85
|
*
|
|
@@ -259,7 +259,7 @@ export function fallbackIsHighlighted(fallback) {
|
|
|
259
259
|
* render (`visibleFrames`). Off-screen frames are omitted — they flatten to exactly
|
|
260
260
|
* {@link buildRootFallback}'s plain output, so storing them would just duplicate
|
|
261
261
|
* `fallback` in the precompute. {@link promoteCriticalFallback} splices these back
|
|
262
|
-
* over the plain fallback for `
|
|
262
|
+
* over the plain fallback for `highlightAfter: 'init'` (paint highlighted on the first
|
|
263
263
|
* render, zero decompression). Frame indices count `span.frame` children only,
|
|
264
264
|
* matching `getInitialVisibleFrames`.
|
|
265
265
|
*
|
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
import type { Code, ControlledCode, ParseSource } from "./types.mjs";
|
|
2
2
|
import type { PreParsedCacheEntry } from "./CodeHighlighterContext.mjs";
|
|
3
|
+
/**
|
|
4
|
+
* Cache key for a parsed file. Qualified by variant so two variants that share a
|
|
5
|
+
* file name (e.g. both have `Demo.tsx`) get independent entries instead of
|
|
6
|
+
* evicting each other. The `\u0000` separator cannot appear in a variant key or
|
|
7
|
+
* file name, so the two parts can never run together ambiguously.
|
|
8
|
+
*/
|
|
9
|
+
export declare function preParsedCacheKey(variant: string, fileName: string): string;
|
|
3
10
|
/**
|
|
4
11
|
* Pure function to parse controlled code and convert it to regular Code format.
|
|
5
12
|
* Handles the conversion from ControlledCode (string|null sources) to Code (HAST nodes).
|
|
6
13
|
*
|
|
7
14
|
* When `preParsedCache` is supplied, each file's source is first looked up in
|
|
8
|
-
* the cache. If the cached entry's source string
|
|
9
|
-
* cached HAST is reused and `parseSource` is skipped
|
|
10
|
-
*
|
|
11
|
-
*
|
|
15
|
+
* the cache (keyed by variant + file name). If the cached entry's source string
|
|
16
|
+
* matches byte-for-byte, the cached HAST is reused and `parseSource` is skipped.
|
|
17
|
+
* A fresh parse is WRITTEN THROUGH to the cache, so on the next controlled-code
|
|
18
|
+
* change (a keystroke updates one file) every unchanged file is reused instead
|
|
19
|
+
* of re-parsed — only the edited file's source differs. A stale entry is evicted
|
|
20
|
+
* and replaced; a parse failure keeps the raw string and is not cached.
|
|
12
21
|
*/
|
|
13
22
|
export declare function parseControlledCode(controlledCode: ControlledCode, parseSource: ParseSource, preParsedCache?: Map<string, PreParsedCacheEntry>): Code;
|
|
@@ -1,31 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cache key for a parsed file. Qualified by variant so two variants that share a
|
|
3
|
+
* file name (e.g. both have `Demo.tsx`) get independent entries instead of
|
|
4
|
+
* evicting each other. The `\u0000` separator cannot appear in a variant key or
|
|
5
|
+
* file name, so the two parts can never run together ambiguously.
|
|
6
|
+
*/
|
|
7
|
+
export function preParsedCacheKey(variant, fileName) {
|
|
8
|
+
return `${variant}\u0000${fileName}`;
|
|
9
|
+
}
|
|
10
|
+
|
|
1
11
|
/**
|
|
2
12
|
* Pure function to parse controlled code and convert it to regular Code format.
|
|
3
13
|
* Handles the conversion from ControlledCode (string|null sources) to Code (HAST nodes).
|
|
4
14
|
*
|
|
5
15
|
* When `preParsedCache` is supplied, each file's source is first looked up in
|
|
6
|
-
* the cache. If the cached entry's source string
|
|
7
|
-
* cached HAST is reused and `parseSource` is skipped
|
|
8
|
-
*
|
|
9
|
-
*
|
|
16
|
+
* the cache (keyed by variant + file name). If the cached entry's source string
|
|
17
|
+
* matches byte-for-byte, the cached HAST is reused and `parseSource` is skipped.
|
|
18
|
+
* A fresh parse is WRITTEN THROUGH to the cache, so on the next controlled-code
|
|
19
|
+
* change (a keystroke updates one file) every unchanged file is reused instead
|
|
20
|
+
* of re-parsed — only the edited file's source differs. A stale entry is evicted
|
|
21
|
+
* and replaced; a parse failure keeps the raw string and is not cached.
|
|
10
22
|
*/
|
|
11
23
|
export function parseControlledCode(controlledCode, parseSource, preParsedCache) {
|
|
12
24
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
25
|
+
* Resolves one file's string source to HAST, reusing a cached parse on an exact
|
|
26
|
+
* source match and writing a fresh parse through to the cache. Returns the raw
|
|
27
|
+
* string (uncached) if `parseSource` throws.
|
|
15
28
|
*/
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
29
|
+
const resolveSource = (variant, fileName, source) => {
|
|
30
|
+
const key = preParsedCacheKey(variant, fileName);
|
|
31
|
+
const entry = preParsedCache?.get(key);
|
|
32
|
+
if (entry) {
|
|
33
|
+
if (entry.source === source) {
|
|
34
|
+
return entry.hast;
|
|
35
|
+
}
|
|
36
|
+
preParsedCache?.delete(key);
|
|
23
37
|
}
|
|
24
|
-
|
|
25
|
-
|
|
38
|
+
try {
|
|
39
|
+
const hast = parseSource(source, fileName);
|
|
40
|
+
preParsedCache?.set(key, {
|
|
41
|
+
source,
|
|
42
|
+
hast
|
|
43
|
+
});
|
|
44
|
+
return hast;
|
|
45
|
+
} catch {
|
|
46
|
+
return source;
|
|
26
47
|
}
|
|
27
|
-
preParsedCache.delete(fileName);
|
|
28
|
-
return undefined;
|
|
29
48
|
};
|
|
30
49
|
const parsed = {};
|
|
31
50
|
for (const [variant, variantCode] of Object.entries(controlledCode)) {
|
|
@@ -39,17 +58,7 @@ export function parseControlledCode(controlledCode, parseSource, preParsedCache)
|
|
|
39
58
|
// Convert null to empty string, then parse
|
|
40
59
|
const sourceToProcess = variantCode.source === null ? '' : variantCode.source;
|
|
41
60
|
if (typeof sourceToProcess === 'string' && variantCode.fileName) {
|
|
42
|
-
|
|
43
|
-
if (cached) {
|
|
44
|
-
mainSource = cached;
|
|
45
|
-
} else {
|
|
46
|
-
try {
|
|
47
|
-
mainSource = parseSource(sourceToProcess, variantCode.fileName);
|
|
48
|
-
} catch (error) {
|
|
49
|
-
// Keep original string if parsing fails
|
|
50
|
-
mainSource = sourceToProcess;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
61
|
+
mainSource = resolveSource(variant, variantCode.fileName, sourceToProcess);
|
|
53
62
|
} else if (typeof sourceToProcess === 'string' && !variantCode.fileName) {
|
|
54
63
|
// Return a basic HAST root node with the source text for unsupported file types
|
|
55
64
|
// This indicates that the source has at least passed through the parsing pipeline
|
|
@@ -74,27 +83,10 @@ export function parseControlledCode(controlledCode, parseSource, preParsedCache)
|
|
|
74
83
|
// Convert null to empty string, then parse
|
|
75
84
|
const fileSourceToProcess = fileData.source === null ? '' : fileData.source;
|
|
76
85
|
if (typeof fileSourceToProcess === 'string') {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
comments: fileData.comments
|
|
82
|
-
};
|
|
83
|
-
} else {
|
|
84
|
-
try {
|
|
85
|
-
const parsedSource = parseSource(fileSourceToProcess, fileName);
|
|
86
|
-
parsedExtraFiles[fileName] = {
|
|
87
|
-
source: parsedSource,
|
|
88
|
-
comments: fileData.comments
|
|
89
|
-
};
|
|
90
|
-
} catch (error) {
|
|
91
|
-
// Keep original if parsing fails
|
|
92
|
-
parsedExtraFiles[fileName] = {
|
|
93
|
-
source: fileSourceToProcess,
|
|
94
|
-
comments: fileData.comments
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
}
|
|
86
|
+
parsedExtraFiles[fileName] = {
|
|
87
|
+
source: resolveSource(variant, fileName, fileSourceToProcess),
|
|
88
|
+
comments: fileData.comments
|
|
89
|
+
};
|
|
98
90
|
} else {
|
|
99
91
|
// Keep other values as-is
|
|
100
92
|
parsedExtraFiles[fileName] = {
|
|
@@ -33,7 +33,7 @@ export function prepareInitialSource(props) {
|
|
|
33
33
|
const initialExpandedEnabled = initialExpanded === true;
|
|
34
34
|
|
|
35
35
|
// Fold each variant's staging `fallbackCritical` into its plain `fallback` up front
|
|
36
|
-
// (under `
|
|
36
|
+
// (under `highlightAfter: 'init'`, not `collapseToEmpty`), then strip it. The hoisted
|
|
37
37
|
// loading fallback is therefore already highlighted-visible — so the first paint is
|
|
38
38
|
// highlighted with no decompression — while the rest of this function (strip, hoist,
|
|
39
39
|
// window, compress) operates on a single `fallback` field with no awareness of the
|
|
@@ -4,7 +4,7 @@ type HighlightAfter = CodeHighlighterBaseProps<{}>['highlightAfter'];
|
|
|
4
4
|
* Resolve the staging `fallbackCritical` field at a server→client (or client-load)
|
|
5
5
|
* boundary, returning a clone of `code` ready to cross to the client:
|
|
6
6
|
*
|
|
7
|
-
* - **Promote** — under `
|
|
7
|
+
* - **Promote** — under `highlightAfter: 'init'` (and not `collapseToEmpty`), each
|
|
8
8
|
* variant whose `fallbackCritical` *and* plain `fallback` are both present has the
|
|
9
9
|
* sparse `fallbackCritical` diff spliced over its `fallback` (`promoteCriticalFallback`)
|
|
10
10
|
* — the visible frames become highlighted, the rest stay plain — so the first paint is
|