@mui/internal-docs-infra 0.10.1-canary.7 → 0.11.1-canary.1

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.
Files changed (171) hide show
  1. package/CodeControllerContext/CodeControllerContext.d.mts +7 -1
  2. package/CodeControllerContext/CodeControllerContext.mjs +2 -1
  3. package/CodeHighlighter/CodeHighlighter.mjs +25 -10
  4. package/CodeHighlighter/CodeHighlighterClient.mjs +54 -25
  5. package/CodeHighlighter/CodeHighlighterContext.d.mts +21 -1
  6. package/CodeHighlighter/CodeHighlighterContext.mjs +9 -0
  7. package/CodeHighlighter/errors.mjs +2 -2
  8. package/CodeHighlighter/parseControlledCode.d.mts +8 -1
  9. package/CodeHighlighter/parseControlledCode.mjs +57 -17
  10. package/CodeHighlighter/types.d.mts +60 -2
  11. package/CodeProvider/CodeContext.d.mts +10 -2
  12. package/CodeProvider/CodeProvider.mjs +76 -35
  13. package/CodeProvider/createParseSourceWorkerClient.d.mts +41 -0
  14. package/CodeProvider/createParseSourceWorkerClient.mjs +144 -0
  15. package/CodeProvider/parseSourceWorker.d.mts +19 -0
  16. package/CodeProvider/parseSourceWorker.mjs +92 -0
  17. package/abstractCreateDemo/abstractCreateDemo.d.mts +18 -0
  18. package/abstractCreateDemo/abstractCreateDemo.mjs +34 -3
  19. package/abstractCreateDemoClient/abstractCreateDemoClient.d.mts +11 -5
  20. package/abstractCreateDemoClient/abstractCreateDemoClient.mjs +43 -17
  21. package/cli/ensureDemoClients.d.mts +66 -0
  22. package/cli/ensureDemoClients.mjs +377 -0
  23. package/cli/index.mjs +3 -2
  24. package/cli/loadNextConfig.d.mts +8 -4
  25. package/cli/loadNextConfig.mjs +31 -1
  26. package/cli/runBrowser.d.mts +12 -0
  27. package/cli/runBrowser.mjs +175 -0
  28. package/cli/runValidate.mjs +41 -1
  29. package/cli/validateWorker.mjs +1 -1
  30. package/package.json +131 -88
  31. package/pipeline/enhanceCodeEmphasis/enhanceCodeEmphasis.mjs +8 -3
  32. package/pipeline/loadIsomorphicCodeSource/index.d.mts +1 -0
  33. package/pipeline/loadIsomorphicCodeSource/index.mjs +1 -0
  34. package/pipeline/loadIsomorphicCodeSource/loadIsomorphicCodeSource.d.mts +76 -0
  35. package/pipeline/loadIsomorphicCodeSource/loadIsomorphicCodeSource.mjs +154 -0
  36. package/pipeline/{loadCodeVariant → loadIsomorphicCodeVariant}/index.d.mts +1 -1
  37. package/pipeline/{loadCodeVariant → loadIsomorphicCodeVariant}/index.mjs +1 -1
  38. package/pipeline/{loadCodeVariant → loadIsomorphicCodeVariant}/loadCodeFallback.mjs +60 -41
  39. package/pipeline/{loadCodeVariant/loadCodeVariant.d.mts → loadIsomorphicCodeVariant/loadIsomorphicCodeVariant.d.mts} +1 -1
  40. package/pipeline/{loadCodeVariant/loadCodeVariant.mjs → loadIsomorphicCodeVariant/loadIsomorphicCodeVariant.mjs} +105 -41
  41. package/pipeline/loadIsomorphicCodeVariant/runSourceEnhancers.d.mts +24 -0
  42. package/pipeline/loadIsomorphicCodeVariant/runSourceEnhancers.mjs +64 -0
  43. package/pipeline/loadPrecomputedCodeHighlighter/loadPrecomputedCodeHighlighter.d.mts +13 -0
  44. package/pipeline/loadPrecomputedCodeHighlighter/loadPrecomputedCodeHighlighter.mjs +7 -7
  45. package/pipeline/loadPrecomputedCodeHighlighterClient/collectDeclaredNames.d.mts +14 -0
  46. package/pipeline/loadPrecomputedCodeHighlighterClient/collectDeclaredNames.mjs +65 -0
  47. package/pipeline/loadPrecomputedCodeHighlighterClient/findServerOnlyExternals.d.mts +18 -0
  48. package/pipeline/loadPrecomputedCodeHighlighterClient/findServerOnlyExternals.mjs +47 -0
  49. package/pipeline/loadPrecomputedCodeHighlighterClient/generateResolvedExternals.d.mts +6 -1
  50. package/pipeline/loadPrecomputedCodeHighlighterClient/generateResolvedExternals.mjs +13 -5
  51. package/pipeline/loadPrecomputedCodeHighlighterClient/loadPrecomputedCodeHighlighterClient.mjs +33 -9
  52. package/pipeline/loadPrecomputedSitemap/loadPrecomputedSitemap.mjs +2 -2
  53. package/pipeline/loadPrecomputedTypes/loadPrecomputedTypes.mjs +2 -2
  54. package/pipeline/loadServerCodeMeta/loadServerCodeMeta.d.mts +1 -1
  55. package/pipeline/loadServerCodeMeta/loadServerCodeMeta.mjs +2 -2
  56. package/pipeline/loadServerCodeSource/index.d.mts +1 -0
  57. package/pipeline/loadServerCodeSource/index.mjs +1 -0
  58. package/pipeline/{loadServerSource/loadServerSource.d.mts → loadServerCodeSource/loadServerCodeSource.d.mts} +5 -5
  59. package/pipeline/loadServerCodeSource/loadServerCodeSource.mjs +43 -0
  60. package/pipeline/loadServerSitemap/loadServerSitemap.mjs +1 -1
  61. package/pipeline/loadServerTypesMeta/formatType.mjs +25 -3
  62. package/pipeline/loaderUtils/applyUrlPrefix.d.mts +40 -0
  63. package/pipeline/loaderUtils/applyUrlPrefix.mjs +99 -0
  64. package/pipeline/loaderUtils/convertCommentsToOneIndexed.d.mts +8 -0
  65. package/pipeline/loaderUtils/convertCommentsToOneIndexed.mjs +16 -0
  66. package/pipeline/loaderUtils/generateFileSlug.d.mts +9 -0
  67. package/pipeline/loaderUtils/generateFileSlug.mjs +36 -0
  68. package/pipeline/loaderUtils/index.d.mts +3 -1
  69. package/pipeline/loaderUtils/index.mjs +3 -1
  70. package/pipeline/loaderUtils/parseImportsAndComments.d.mts +7 -4
  71. package/pipeline/loaderUtils/parseImportsAndComments.mjs +33 -13
  72. package/pipeline/parseCreateFactoryCall/index.d.mts +2 -0
  73. package/pipeline/parseCreateFactoryCall/index.mjs +2 -0
  74. package/pipeline/{loadPrecomputedCodeHighlighter → parseCreateFactoryCall}/parseCreateFactoryCall.d.mts +1 -3
  75. package/pipeline/{loadPrecomputedCodeHighlighter → parseCreateFactoryCall}/parseCreateFactoryCall.mjs +2 -1
  76. package/pipeline/parseSource/calculateFrameRanges.d.mts +9 -0
  77. package/pipeline/parseSource/grammarMaps.d.mts +18 -0
  78. package/pipeline/parseSource/grammarMaps.mjs +53 -0
  79. package/pipeline/parseSource/grammars.d.mts +6 -11
  80. package/pipeline/parseSource/grammars.mjs +9 -47
  81. package/pipeline/parseSource/index.d.mts +1 -1
  82. package/pipeline/parseSource/index.mjs +1 -1
  83. package/pipeline/parseSource/parseSource.d.mts +4 -0
  84. package/pipeline/parseSource/parseSource.mjs +8 -1
  85. package/pipeline/transformHtmlCodeBlock/transformHtmlCodeBlock.d.mts +2 -2
  86. package/pipeline/transformHtmlCodeBlock/transformHtmlCodeBlock.mjs +6 -6
  87. package/pipeline/transformHtmlCodeInline/transformHtmlCodeInline.mjs +2 -1
  88. package/useCode/Pre.browser.d.mts +1 -0
  89. package/useCode/Pre.browser.mjs +291 -0
  90. package/useCode/Pre.d.mts +21 -1
  91. package/useCode/Pre.mjs +331 -3
  92. package/useCode/cloneRangeWithInlineStyles.d.mts +47 -0
  93. package/useCode/cloneRangeWithInlineStyles.mjs +123 -0
  94. package/useCode/generateVariantMarkdown.d.mts +18 -0
  95. package/useCode/generateVariantMarkdown.mjs +89 -0
  96. package/useCode/stripLeadingPerLine.d.mts +38 -0
  97. package/useCode/stripLeadingPerLine.mjs +104 -0
  98. package/useCode/useCode.d.mts +31 -3
  99. package/useCode/useCode.mjs +46 -12
  100. package/useCode/useCodeUtils.mjs +1 -1
  101. package/useCode/useCopyFunctionality.d.mts +15 -2
  102. package/useCode/useCopyFunctionality.mjs +57 -7
  103. package/useCode/useEditable.browser.d.mts +1 -0
  104. package/useCode/useEditable.browser.mjs +1464 -0
  105. package/useCode/useEditable.d.mts +110 -0
  106. package/useCode/useEditable.mjs +1288 -0
  107. package/useCode/useEditableUtils.d.mts +83 -0
  108. package/useCode/useEditableUtils.mjs +373 -0
  109. package/useCode/useFileNavigation.d.mts +17 -3
  110. package/useCode/useFileNavigation.mjs +62 -43
  111. package/useCode/useSourceEditing.d.mts +30 -5
  112. package/useCode/useSourceEditing.mjs +360 -17
  113. package/useCode/useSourceEnhancing.d.mts +0 -36
  114. package/useCode/useSourceEnhancing.mjs +123 -52
  115. package/useCodeWindow/index.d.mts +1 -0
  116. package/useCodeWindow/index.mjs +1 -0
  117. package/useCodeWindow/useCodeWindow.d.mts +87 -0
  118. package/useCodeWindow/useCodeWindow.mjs +280 -0
  119. package/useCopier/index.d.mts +2 -2
  120. package/useDemo/createCodeSandbox.d.mts +1 -1
  121. package/useDemo/createStackBlitz.d.mts +1 -1
  122. package/useDemo/exportVariant.mjs +2 -2
  123. package/useDemo/index.d.mts +1 -1
  124. package/useDemo/index.mjs +1 -1
  125. package/useDemo/useDemo.d.mts +6 -3
  126. package/useDemo/useDemo.mjs +7 -5
  127. package/useScrollAnchor/index.d.mts +1 -0
  128. package/useScrollAnchor/index.mjs +1 -0
  129. package/useScrollAnchor/useScrollAnchor.d.mts +44 -0
  130. package/useScrollAnchor/useScrollAnchor.mjs +113 -0
  131. package/withDocsInfra/withDeploymentConfig.mjs +134 -0
  132. package/withDocsInfra/withDocsInfra.d.mts +20 -0
  133. package/withDocsInfra/withDocsInfra.mjs +30 -3
  134. package/pipeline/loadServerSource/index.d.mts +0 -1
  135. package/pipeline/loadServerSource/index.mjs +0 -1
  136. package/pipeline/loadServerSource/loadServerSource.mjs +0 -165
  137. /package/pipeline/{loadCodeVariant → loadIsomorphicCodeVariant}/addCodeVariantPaths.d.mts +0 -0
  138. /package/pipeline/{loadCodeVariant → loadIsomorphicCodeVariant}/addCodeVariantPaths.mjs +0 -0
  139. /package/pipeline/{loadCodeVariant → loadIsomorphicCodeVariant}/applyCodeTransform.d.mts +0 -0
  140. /package/pipeline/{loadCodeVariant → loadIsomorphicCodeVariant}/applyCodeTransform.mjs +0 -0
  141. /package/pipeline/{loadCodeVariant → loadIsomorphicCodeVariant}/calculateMainFilePath.d.mts +0 -0
  142. /package/pipeline/{loadCodeVariant → loadIsomorphicCodeVariant}/calculateMainFilePath.mjs +0 -0
  143. /package/pipeline/{loadCodeVariant → loadIsomorphicCodeVariant}/computeHastDeltas.d.mts +0 -0
  144. /package/pipeline/{loadCodeVariant → loadIsomorphicCodeVariant}/computeHastDeltas.mjs +0 -0
  145. /package/pipeline/{loadCodeVariant → loadIsomorphicCodeVariant}/diffHast.d.mts +0 -0
  146. /package/pipeline/{loadCodeVariant → loadIsomorphicCodeVariant}/diffHast.mjs +0 -0
  147. /package/pipeline/{loadCodeVariant → loadIsomorphicCodeVariant}/enhanceCode.d.mts +0 -0
  148. /package/pipeline/{loadCodeVariant → loadIsomorphicCodeVariant}/enhanceCode.mjs +0 -0
  149. /package/pipeline/{loadCodeVariant → loadIsomorphicCodeVariant}/examineCodeVariant.d.mts +0 -0
  150. /package/pipeline/{loadCodeVariant → loadIsomorphicCodeVariant}/examineCodeVariant.mjs +0 -0
  151. /package/pipeline/{loadCodeVariant → loadIsomorphicCodeVariant}/flattenCodeVariant.d.mts +0 -0
  152. /package/pipeline/{loadCodeVariant → loadIsomorphicCodeVariant}/flattenCodeVariant.mjs +0 -0
  153. /package/pipeline/{loadCodeVariant → loadIsomorphicCodeVariant}/hasAllCodeVariants.d.mts +0 -0
  154. /package/pipeline/{loadCodeVariant → loadIsomorphicCodeVariant}/hasAllCodeVariants.mjs +0 -0
  155. /package/pipeline/{loadCodeVariant → loadIsomorphicCodeVariant}/loadCodeFallback.d.mts +0 -0
  156. /package/pipeline/{loadCodeVariant → loadIsomorphicCodeVariant}/maybeCodeInitialData.d.mts +0 -0
  157. /package/pipeline/{loadCodeVariant → loadIsomorphicCodeVariant}/maybeCodeInitialData.mjs +0 -0
  158. /package/pipeline/{loadCodeVariant → loadIsomorphicCodeVariant}/mergeCodeMetadata.d.mts +0 -0
  159. /package/pipeline/{loadCodeVariant → loadIsomorphicCodeVariant}/mergeCodeMetadata.mjs +0 -0
  160. /package/pipeline/{loadCodeVariant → loadIsomorphicCodeVariant}/parseCode.d.mts +0 -0
  161. /package/pipeline/{loadCodeVariant → loadIsomorphicCodeVariant}/parseCode.mjs +0 -0
  162. /package/pipeline/{loadCodeVariant → loadIsomorphicCodeVariant}/pathUtils.d.mts +0 -0
  163. /package/pipeline/{loadCodeVariant → loadIsomorphicCodeVariant}/pathUtils.mjs +0 -0
  164. /package/pipeline/{loadCodeVariant → loadIsomorphicCodeVariant}/transformSource.d.mts +0 -0
  165. /package/pipeline/{loadCodeVariant → loadIsomorphicCodeVariant}/transformSource.mjs +0 -0
  166. /package/pipeline/{loadPrecomputedCodeHighlighter → parseCreateFactoryCall}/parseFunctionArguments.d.mts +0 -0
  167. /package/pipeline/{loadPrecomputedCodeHighlighter → parseCreateFactoryCall}/parseFunctionArguments.mjs +0 -0
  168. /package/pipeline/{loadPrecomputedCodeHighlighter → parseCreateFactoryCall}/replacePrecomputeValue.d.mts +0 -0
  169. /package/pipeline/{loadPrecomputedCodeHighlighter → parseCreateFactoryCall}/replacePrecomputeValue.mjs +0 -0
  170. /package/pipeline/{loadPrecomputedCodeHighlighter → parseCreateFactoryCall}/serializeFunctionArguments.d.mts +0 -0
  171. /package/pipeline/{loadPrecomputedCodeHighlighter → parseCreateFactoryCall}/serializeFunctionArguments.mjs +0 -0
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import type { ControlledCode } from "../CodeHighlighter/types.mjs";
2
+ import type { ControlledCode, SourceEnhancers } from "../CodeHighlighter/types.mjs";
3
3
  export type Selection = {
4
4
  variant: string;
5
5
  fileName?: string;
@@ -43,6 +43,11 @@ export interface CodeControllerContext {
43
43
  * e.g. `{ variantA: {}, variantB: {} }`.
44
44
  */
45
45
  components?: Record<string, React.ReactNode> | undefined;
46
+ /**
47
+ * Additional source enhancers to apply to parsed HAST sources.
48
+ * These are merged with enhancers from CodeProvider and useCode opts.
49
+ */
50
+ sourceEnhancers?: SourceEnhancers;
46
51
  }
47
52
  export declare const CodeControllerContext: React.Context<CodeControllerContext | undefined>;
48
53
  /**
@@ -66,4 +71,5 @@ export declare function useControlledCode(): {
66
71
  setCode: React.Dispatch<React.SetStateAction<ControlledCode | undefined>> | undefined;
67
72
  setSelection: React.Dispatch<React.SetStateAction<Selection>> | undefined;
68
73
  components: Record<string, React.ReactNode> | undefined;
74
+ sourceEnhancers: SourceEnhancers | undefined;
69
75
  };
@@ -35,6 +35,7 @@ export function useControlledCode() {
35
35
  selection: context?.selection,
36
36
  setCode: context?.setCode,
37
37
  setSelection: context?.setSelection,
38
- components: context?.components
38
+ components: context?.components,
39
+ sourceEnhancers: context?.sourceEnhancers
39
40
  };
40
41
  }
@@ -1,10 +1,11 @@
1
1
  import * as React from 'react';
2
- import { loadCodeVariant } from "../pipeline/loadCodeVariant/loadCodeVariant.mjs";
3
- import { loadCodeFallback } from "../pipeline/loadCodeVariant/loadCodeFallback.mjs";
2
+ import { loadIsomorphicCodeVariant } from "../pipeline/loadIsomorphicCodeVariant/loadIsomorphicCodeVariant.mjs";
3
+ import { loadCodeFallback } from "../pipeline/loadIsomorphicCodeVariant/loadCodeFallback.mjs";
4
4
  import { CodeHighlighterClient } from "./CodeHighlighterClient.mjs";
5
- import { maybeCodeInitialData } from "../pipeline/loadCodeVariant/maybeCodeInitialData.mjs";
6
- import { hasAllVariants } from "../pipeline/loadCodeVariant/hasAllCodeVariants.mjs";
5
+ import { maybeCodeInitialData } from "../pipeline/loadIsomorphicCodeVariant/maybeCodeInitialData.mjs";
6
+ import { hasAllVariants } from "../pipeline/loadIsomorphicCodeVariant/hasAllCodeVariants.mjs";
7
7
  import { getFileNameFromUrl, getLanguageFromExtension } from "../pipeline/loaderUtils/index.mjs";
8
+ import { replaceUrlPrefix } from "../pipeline/loaderUtils/applyUrlPrefix.mjs";
8
9
  import { codeToFallbackProps } from "./codeToFallbackProps.mjs";
9
10
  import * as Errors from "./errors.mjs";
10
11
  import { jsx as _jsx } from "react/jsx-runtime";
@@ -13,17 +14,25 @@ const DEBUG = false; // Set to true for debugging purposes
13
14
  function createClientProps(props) {
14
15
  const highlightAfter = props.highlightAfter === 'stream' ? 'init' : props.highlightAfter;
15
16
  const enhanceAfter = props.enhanceAfter === 'stream' ? 'init' : props.enhanceAfter;
17
+
18
+ // Rewrite the top-level URL before it leaves the server. The client never
19
+ // receives `urlPrefix` (and shouldn't deal with `file://` URLs), so any
20
+ // local URL must be translated to its hosted form here. Variant-level URLs
21
+ // inside `code`/`precompute` are already rewritten upstream (by
22
+ // `loadIsomorphicCodeVariant` on the server, or by the demo factory for precomputed
23
+ // input).
24
+ const url = props.urlPrefix && props.url ? replaceUrlPrefix(props.url, props.urlPrefix) : props.url;
16
25
  const contentProps = {
17
26
  code: props.code || props.precompute,
18
27
  components: props.components,
19
28
  name: props.name,
20
29
  slug: props.slug,
21
- url: props.url,
30
+ url,
22
31
  variantType: props.variantType,
23
32
  ...props.contentProps
24
33
  };
25
34
  return {
26
- url: props.url,
35
+ url,
27
36
  code: props.code,
28
37
  precompute: props.precompute,
29
38
  components: props.components,
@@ -115,14 +124,15 @@ async function CodeSourceLoader(props) {
115
124
  } else if (props.deferParsing === 'none') {
116
125
  output = 'hast';
117
126
  }
118
- return loadCodeVariant(variantUrl, variantName, variantCode, {
127
+ return loadIsomorphicCodeVariant(variantUrl, variantName, variantCode, {
119
128
  sourceParser: props.sourceParser,
120
129
  loadSource: props.loadSource,
121
130
  loadVariantMeta: props.loadVariantMeta,
122
131
  sourceTransformers: props.sourceTransformers,
123
132
  sourceEnhancers: props.sourceEnhancers,
124
133
  globalsCode: resolvedGlobalsCode,
125
- output
134
+ output,
135
+ urlPrefix: props.urlPrefix
126
136
  }).then(variant => ({
127
137
  name: variantName,
128
138
  variant
@@ -182,7 +192,6 @@ async function CodeHighlighterSuspense(props) {
182
192
  function renderWithInitialSource(props) {
183
193
  const ContentLoading = props.ContentLoading;
184
194
  const {
185
- url,
186
195
  slug,
187
196
  name,
188
197
  initialVariant,
@@ -191,6 +200,11 @@ function renderWithInitialSource(props) {
191
200
  fallbackUsesExtraFiles,
192
201
  fallbackUsesAllVariants
193
202
  } = props;
203
+
204
+ // Rewrite the top-level URL before it reaches the loading fallback so the
205
+ // browser never sees `file://` URLs. See `createClientProps` for the same
206
+ // rewrite on the regular client path.
207
+ const url = props.urlPrefix && props.url ? replaceUrlPrefix(props.url, props.urlPrefix) : props.url;
194
208
  const fallbackProps = codeToFallbackProps(initialVariant, code, initialFilename, fallbackUsesExtraFiles, fallbackUsesAllVariants);
195
209
 
196
210
  // Get the component for the selected variant
@@ -272,7 +286,8 @@ async function CodeInitialSourceLoader(props) {
272
286
  initialFilename: fileName,
273
287
  variants,
274
288
  globalsCode,
275
- output
289
+ output,
290
+ urlPrefix: props.urlPrefix
276
291
  });
277
292
  return renderWithInitialSource({
278
293
  ...props,
@@ -3,12 +3,12 @@
3
3
  import * as React from 'react';
4
4
  import { useCodeContext } from "../CodeProvider/CodeContext.mjs";
5
5
  import { CodeHighlighterContext } from "./CodeHighlighterContext.mjs";
6
- import { maybeCodeInitialData } from "../pipeline/loadCodeVariant/maybeCodeInitialData.mjs";
7
- import { hasAllVariants } from "../pipeline/loadCodeVariant/hasAllCodeVariants.mjs";
6
+ import { maybeCodeInitialData } from "../pipeline/loadIsomorphicCodeVariant/maybeCodeInitialData.mjs";
7
+ import { hasAllVariants } from "../pipeline/loadIsomorphicCodeVariant/hasAllCodeVariants.mjs";
8
8
  import { CodeHighlighterFallbackContext } from "./CodeHighlighterFallbackContext.mjs";
9
9
  import { useControlledCode } from "../CodeControllerContext/index.mjs";
10
10
  import { codeToFallbackProps } from "./codeToFallbackProps.mjs";
11
- import { mergeCodeMetadata } from "../pipeline/loadCodeVariant/mergeCodeMetadata.mjs";
11
+ import { mergeCodeMetadata } from "../pipeline/loadIsomorphicCodeVariant/mergeCodeMetadata.mjs";
12
12
  import * as Errors from "./errors.mjs";
13
13
  import { jsx as _jsx } from "react/jsx-runtime";
14
14
  const DEBUG = false; // Set to true for debugging purposes
@@ -50,6 +50,11 @@ function useInitialData({
50
50
  }
51
51
  }
52
52
 
53
+ // Signal to downstream loaders that a fallback fetch is pending. Used to gate
54
+ // `useAllVariants` so it can reuse the data populated by the fallback rather
55
+ // than racing it and re-fetching the same variant.
56
+ const fallbackPending = Boolean(needsFallback && url && loadCodeFallback);
57
+
53
58
  // TODO: fallbackInitialRenderOnly option? this would mean we can't fetch fallback data on the client side
54
59
  // Load initial data if not provided
55
60
  React.useEffect(() => {
@@ -90,6 +95,9 @@ function useInitialData({
90
95
  }
91
96
  })();
92
97
  }, [initialData, reason, needsFallback, variantName, code, setCode, highlightAfter, url, sourceParser, loadSource, loadVariantMeta, loadCodeMeta, sourceEnhancers, fallbackUsesExtraFiles, fallbackUsesAllVariants, fileName, variants, globalsCode, setProcessedGlobalsCode, loadCodeFallback]);
98
+ return {
99
+ fallbackPending
100
+ };
93
101
  }
94
102
  function useAllVariants({
95
103
  readyForContent,
@@ -100,16 +108,17 @@ function useAllVariants({
100
108
  setCode,
101
109
  processedGlobalsCode,
102
110
  globalsCode,
103
- setProcessedGlobalsCode
111
+ setProcessedGlobalsCode,
112
+ fallbackPending
104
113
  }) {
105
114
  const {
106
115
  loadCodeMeta,
107
116
  loadVariantMeta,
108
117
  loadSource,
109
- loadCodeVariant,
118
+ loadIsomorphicCodeVariant,
110
119
  sourceEnhancers
111
120
  } = useCodeContext();
112
- const needsData = !readyForContent && !isControlled;
121
+ const needsData = !readyForContent && !isControlled && !fallbackPending;
113
122
 
114
123
  // validation
115
124
  React.useMemo(() => {
@@ -117,7 +126,7 @@ function useAllVariants({
117
126
  if (!url) {
118
127
  throw new Errors.ErrorCodeHighlighterClientMissingUrlForVariants();
119
128
  }
120
- if (!loadCodeVariant) {
129
+ if (!loadIsomorphicCodeVariant) {
121
130
  throw new Errors.ErrorCodeHighlighterClientMissingLoadVariant(url);
122
131
  }
123
132
  if (!code && !loadCodeMeta) {
@@ -143,9 +152,9 @@ function useAllVariants({
143
152
  throw new Errors.ErrorCodeHighlighterClientMissingLoadSourceForUnloadedUrls();
144
153
  }
145
154
  }
146
- }, [code, globalsCode, loadCodeMeta, loadCodeVariant, loadSource, needsData, url]);
155
+ }, [code, globalsCode, loadCodeMeta, loadIsomorphicCodeVariant, loadSource, needsData, url]);
147
156
  React.useEffect(() => {
148
- if (!needsData || !url || !loadCodeVariant) {
157
+ if (!needsData || !url || !loadIsomorphicCodeVariant) {
149
158
  return;
150
159
  }
151
160
 
@@ -190,7 +199,7 @@ function useAllVariants({
190
199
  // Only include if this variant exists in the globalsCode
191
200
  return codeObj[name];
192
201
  }).filter(item => Boolean(item));
193
- return loadCodeVariant(url, name, loadedCode[name], {
202
+ return loadIsomorphicCodeVariant(url, name, loadedCode[name], {
194
203
  disableParsing: true,
195
204
  disableTransforms: true,
196
205
  loadSource,
@@ -222,7 +231,7 @@ function useAllVariants({
222
231
  console.error(new Errors.ErrorCodeHighlighterClientLoadAllVariantsFailure(url, error));
223
232
  }
224
233
  })();
225
- }, [needsData, variants, url, code, setCode, loadSource, loadVariantMeta, loadCodeMeta, sourceEnhancers, processedGlobalsCode, globalsCode, setProcessedGlobalsCode, loadCodeVariant]);
234
+ }, [needsData, variants, url, code, setCode, loadSource, loadVariantMeta, loadCodeMeta, sourceEnhancers, processedGlobalsCode, globalsCode, setProcessedGlobalsCode, loadIsomorphicCodeVariant]);
226
235
  return {
227
236
  readyForContent
228
237
  };
@@ -246,6 +255,7 @@ function useCodeParsing({
246
255
  url
247
256
  }) {
248
257
  const {
258
+ sourceParser,
249
259
  parseSource,
250
260
  parseCode
251
261
  } = useCodeContext();
@@ -285,6 +295,12 @@ function useCodeParsing({
285
295
  return undefined;
286
296
  }
287
297
  if (!parseSource) {
298
+ // A CodeProvider is present and its async `sourceParser` promise hasn't
299
+ // resolved yet — wait for it instead of erroring. The memo will re-run
300
+ // once `parseSource` is populated.
301
+ if (sourceParser) {
302
+ return undefined;
303
+ }
288
304
  if (forceClient) {
289
305
  console.error(new Errors.ErrorCodeHighlighterClientMissingParseSource(url, true));
290
306
  } else {
@@ -301,7 +317,7 @@ function useCodeParsing({
301
317
  return undefined;
302
318
  }
303
319
  return parseCode(code, parseSource);
304
- }, [code, shouldHighlight, parseSource, parseCode, forceClient, url]);
320
+ }, [code, shouldHighlight, sourceParser, parseSource, parseCode, forceClient, url]);
305
321
  const deferHighlight = !shouldHighlight;
306
322
  return {
307
323
  parsedCode,
@@ -354,7 +370,8 @@ function useCodeTransforms({
354
370
  function useControlledCodeParsing({
355
371
  code,
356
372
  forceClient,
357
- url
373
+ url,
374
+ preParsedCache
358
375
  }) {
359
376
  const {
360
377
  parseSource,
@@ -384,8 +401,8 @@ function useControlledCodeParsing({
384
401
  }
385
402
  return undefined;
386
403
  }
387
- return parseControlledCode(code, parseSource);
388
- }, [code, parseSource, parseControlledCode, forceClient, url]);
404
+ return parseControlledCode(code, parseSource, preParsedCache);
405
+ }, [code, parseSource, parseControlledCode, forceClient, url, preParsedCache]);
389
406
  return {
390
407
  parsedControlledCode
391
408
  };
@@ -403,7 +420,7 @@ function useGlobalsCodeMerging({
403
420
  loadCodeMeta,
404
421
  loadSource,
405
422
  loadVariantMeta,
406
- loadCodeVariant
423
+ loadIsomorphicCodeVariant
407
424
  } = useCodeContext();
408
425
 
409
426
  // Set processedGlobalsCode if we have ready Code objects but haven't stored them yet
@@ -423,7 +440,7 @@ function useGlobalsCodeMerging({
423
440
  }
424
441
  // If not all ready, fall through to loading logic below
425
442
  }
426
- if (!loadCodeVariant) {
443
+ if (!loadIsomorphicCodeVariant) {
427
444
  console.error(new Errors.ErrorCodeHighlighterClientMissingLoadVariantForGlobals());
428
445
  return;
429
446
  }
@@ -469,7 +486,7 @@ function useGlobalsCodeMerging({
469
486
 
470
487
  // Need to load this variant
471
488
  try {
472
- const result = await loadCodeVariant(originalUrl || '',
489
+ const result = await loadIsomorphicCodeVariant(originalUrl || '',
473
490
  // Use the original URL if available
474
491
  variantName, codeObj[variantName],
475
492
  // May be undefined or string
@@ -492,7 +509,7 @@ function useGlobalsCodeMerging({
492
509
  console.error(new Errors.ErrorCodeHighlighterClientLoadGlobalsCodeFailure(url || 'No URL', error));
493
510
  }
494
511
  })();
495
- }, [url, globalsCode, processedGlobalsCode, setProcessedGlobalsCode, loadCodeMeta, loadSource, loadVariantMeta, variants, loadCodeVariant]);
512
+ }, [url, globalsCode, processedGlobalsCode, setProcessedGlobalsCode, loadCodeMeta, loadSource, loadVariantMeta, variants, loadIsomorphicCodeVariant]);
496
513
 
497
514
  // Determine globalsCodeObjects to use (prefer processed, fallback to direct if ready)
498
515
  const globalsCodeObjects = React.useMemo(() => {
@@ -674,7 +691,9 @@ export function CodeHighlighterClient(props) {
674
691
  fallbackUsesExtraFiles,
675
692
  fallbackUsesAllVariants
676
693
  } = props;
677
- useInitialData({
694
+ const {
695
+ fallbackPending
696
+ } = useInitialData({
678
697
  variants,
679
698
  variantName,
680
699
  code,
@@ -747,7 +766,8 @@ export function CodeHighlighterClient(props) {
747
766
  setCode,
748
767
  processedGlobalsCode,
749
768
  globalsCode: props.globalsCode,
750
- setProcessedGlobalsCode
769
+ setProcessedGlobalsCode,
770
+ fallbackPending
751
771
  });
752
772
 
753
773
  // Merge globalsCode with internal state code (fetched data) - this should be stable once ready
@@ -790,12 +810,20 @@ export function CodeHighlighterClient(props) {
790
810
  parsedCode,
791
811
  variantName
792
812
  });
813
+
814
+ // Per-highlighter pre-parsed HAST cache. Lives in a ref so the same Map
815
+ // instance is shared across renders without becoming a React dep. The
816
+ // editable populates it via `useSourceEditing` (which reads it from
817
+ // `CodeHighlighterContext`), and `parseControlledCode` consults it on
818
+ // every render to skip the sync main-thread parse on exact source matches.
819
+ const [preParsedCache] = React.useState(() => new Map());
793
820
  const {
794
821
  parsedControlledCode
795
822
  } = useControlledCodeParsing({
796
823
  code: controlled?.code,
797
824
  forceClient: props.forceClient,
798
- url: props.url
825
+ url: props.url,
826
+ preParsedCache
799
827
  });
800
828
 
801
829
  // Determine the final overlaid code (controlled takes precedence)
@@ -803,7 +831,7 @@ export function CodeHighlighterClient(props) {
803
831
 
804
832
  // For fallback context, use the processed code or fall back to non-controlled code
805
833
  const codeForFallback = overlaidCode || (controlled?.code ? undefined : props.code || code);
806
- const fallbackContext = React.useMemo(() => codeToFallbackProps(variantName, codeForFallback, fileName, props.fallbackUsesExtraFiles, props.fallbackUsesAllVariants), [variantName, codeForFallback, fileName, props.fallbackUsesExtraFiles, props.fallbackUsesAllVariants]);
834
+ const fallbackContext = React.useMemo(() => activeCodeReady ? undefined : codeToFallbackProps(variantName, codeForFallback, fileName, props.fallbackUsesExtraFiles, props.fallbackUsesAllVariants), [activeCodeReady, variantName, codeForFallback, fileName, props.fallbackUsesExtraFiles, props.fallbackUsesAllVariants]);
807
835
  const context = React.useMemo(() => ({
808
836
  code: overlaidCode,
809
837
  // Use processed/transformed code
@@ -813,8 +841,9 @@ export function CodeHighlighterClient(props) {
813
841
  components: controlled?.components || props.components,
814
842
  availableTransforms: isControlled ? [] : availableTransforms,
815
843
  url: props.url,
816
- deferHighlight
817
- }), [overlaidCode, controlled?.setCode, selection, controlled?.selection, controlled?.setSelection, controlled?.components, props.components, isControlled, availableTransforms, props.url, deferHighlight]);
844
+ deferHighlight,
845
+ preParsedCache
846
+ }), [overlaidCode, controlled?.setCode, selection, controlled?.selection, controlled?.setSelection, controlled?.components, props.components, isControlled, availableTransforms, props.url, deferHighlight, preParsedCache]);
818
847
  if (!props.variants && !props.components && !activeCode) {
819
848
  throw new Errors.ErrorCodeHighlighterClientMissingData();
820
849
  }
@@ -1,6 +1,17 @@
1
1
  import * as React from 'react';
2
- import { type Code, type ControlledCode } from "./types.mjs";
2
+ import { type Code, type ControlledCode, type HastRoot } from "./types.mjs";
3
3
  import { type Selection } from "../CodeControllerContext/index.mjs";
4
+ /**
5
+ * One cached pre-parsed file. Stored per-fileName: each new write replaces
6
+ * any previous entry for that file. The `source` string is the cache key —
7
+ * `parseControlledCode` only reuses `hast` when the controlled-code source
8
+ * is byte-identical, which guarantees the cached HAST matches the input
9
+ * that produced it.
10
+ */
11
+ export interface PreParsedCacheEntry {
12
+ source: string;
13
+ hast: HastRoot;
14
+ }
4
15
  export interface CodeHighlighterContextType {
5
16
  code?: Code;
6
17
  setCode?: React.Dispatch<React.SetStateAction<ControlledCode | undefined>>;
@@ -10,6 +21,15 @@ export interface CodeHighlighterContextType {
10
21
  availableTransforms?: string[];
11
22
  url?: string;
12
23
  deferHighlight?: boolean;
24
+ /**
25
+ * Per-file pre-parsed HAST cache. Populated by `useSourceEditing` when the
26
+ * editable supplies a worker-parsed result alongside a source change, and
27
+ * read by `parseControlledCode` to skip the (sync, main-thread) parse on
28
+ * exact source matches. Owned by `CodeHighlighterClient` via `useRef` so
29
+ * the same `Map` instance is shared across render cycles without being a
30
+ * React dep.
31
+ */
32
+ preParsedCache?: Map<string, PreParsedCacheEntry>;
13
33
  }
14
34
  export declare const CodeHighlighterContext: React.Context<CodeHighlighterContextType | undefined>;
15
35
  export declare function useCodeHighlighterContext(): CodeHighlighterContextType;
@@ -1,6 +1,15 @@
1
1
  'use client';
2
2
 
3
3
  import * as React from 'react';
4
+
5
+ /**
6
+ * One cached pre-parsed file. Stored per-fileName: each new write replaces
7
+ * any previous entry for that file. The `source` string is the cache key —
8
+ * `parseControlledCode` only reuses `hast` when the controlled-code source
9
+ * is byte-identical, which guarantees the cached HAST matches the input
10
+ * that produced it.
11
+ */
12
+
4
13
  export const CodeHighlighterContext = /*#__PURE__*/React.createContext(undefined);
5
14
  if (process.env.NODE_ENV !== "production") CodeHighlighterContext.displayName = "CodeHighlighterContext";
6
15
  export function useCodeHighlighterContext() {
@@ -156,7 +156,7 @@ export class ErrorCodeHighlighterClientMissingLoadFallbackCode extends ErrorCode
156
156
  }
157
157
  export class ErrorCodeHighlighterClientMissingLoadVariant extends ErrorCodeHighlighterClientProvider {
158
158
  constructor(url) {
159
- super(`Missing loadCodeVariant function - loadCodeVariant function is required when no initial code is provided (${url || 'No URL'})`);
159
+ super(`Missing loadIsomorphicCodeVariant function - loadIsomorphicCodeVariant function is required when no initial code is provided (${url || 'No URL'})`);
160
160
  }
161
161
  }
162
162
  export class ErrorCodeHighlighterClientMissingLoadCodeMeta extends ErrorCodeHighlighterClientProvider {
@@ -273,7 +273,7 @@ export class ErrorCodeHighlighterClientTransformProcessingFailure extends ErrorC
273
273
  }
274
274
  export class ErrorCodeHighlighterClientMissingLoadVariantForGlobals extends ErrorCodeHighlighterClientProvider {
275
275
  constructor() {
276
- super(`loadCodeVariant function is required for loading missing variants in globalsCode`);
276
+ super(`loadIsomorphicCodeVariant function is required for loading missing variants in globalsCode`);
277
277
  }
278
278
  }
279
279
  export class ErrorCodeHighlighterClientLoadVariantFailureForGlobals extends ErrorCodeHighlighterClientLoader {
@@ -1,6 +1,13 @@
1
1
  import type { Code, ControlledCode, ParseSource } from "./types.mjs";
2
+ import type { PreParsedCacheEntry } from "./CodeHighlighterContext.mjs";
2
3
  /**
3
4
  * Pure function to parse controlled code and convert it to regular Code format.
4
5
  * Handles the conversion from ControlledCode (string|null sources) to Code (HAST nodes).
6
+ *
7
+ * When `preParsedCache` is supplied, each file's source is first looked up in
8
+ * the cache. If the cached entry's source string matches byte-for-byte, the
9
+ * cached HAST is reused and `parseSource` is skipped for that file. On a
10
+ * mismatch the stale entry is evicted before re-parsing so the cache cannot
11
+ * grow stale across rapid edits.
5
12
  */
6
- export declare function parseControlledCode(controlledCode: ControlledCode, parseSource: ParseSource): Code;
13
+ export declare function parseControlledCode(controlledCode: ControlledCode, parseSource: ParseSource, preParsedCache?: Map<string, PreParsedCacheEntry>): Code;
@@ -1,8 +1,32 @@
1
1
  /**
2
2
  * Pure function to parse controlled code and convert it to regular Code format.
3
3
  * Handles the conversion from ControlledCode (string|null sources) to Code (HAST nodes).
4
+ *
5
+ * When `preParsedCache` is supplied, each file's source is first looked up in
6
+ * the cache. If the cached entry's source string matches byte-for-byte, the
7
+ * cached HAST is reused and `parseSource` is skipped for that file. On a
8
+ * mismatch the stale entry is evicted before re-parsing so the cache cannot
9
+ * grow stale across rapid edits.
4
10
  */
5
- export function parseControlledCode(controlledCode, parseSource) {
11
+ export function parseControlledCode(controlledCode, parseSource, preParsedCache) {
12
+ /**
13
+ * Try the cache for `fileName`/`source`. Returns the cached HAST on an
14
+ * exact match; evicts and returns `undefined` on a mismatch.
15
+ */
16
+ const tryCache = (fileName, source) => {
17
+ if (!preParsedCache) {
18
+ return undefined;
19
+ }
20
+ const entry = preParsedCache.get(fileName);
21
+ if (!entry) {
22
+ return undefined;
23
+ }
24
+ if (entry.source === source) {
25
+ return entry.hast;
26
+ }
27
+ preParsedCache.delete(fileName);
28
+ return undefined;
29
+ };
6
30
  const parsed = {};
7
31
  for (const [variant, variantCode] of Object.entries(controlledCode)) {
8
32
  if (variantCode === null) {
@@ -15,11 +39,16 @@ export function parseControlledCode(controlledCode, parseSource) {
15
39
  // Convert null to empty string, then parse
16
40
  const sourceToProcess = variantCode.source === null ? '' : variantCode.source;
17
41
  if (typeof sourceToProcess === 'string' && variantCode.fileName) {
18
- try {
19
- mainSource = parseSource(sourceToProcess, variantCode.fileName);
20
- } catch (error) {
21
- // Keep original string if parsing fails
22
- mainSource = sourceToProcess;
42
+ const cached = tryCache(variantCode.fileName, sourceToProcess);
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
+ }
23
52
  }
24
53
  } else if (typeof sourceToProcess === 'string' && !variantCode.fileName) {
25
54
  // Return a basic HAST root node with the source text for unsupported file types
@@ -45,22 +74,32 @@ export function parseControlledCode(controlledCode, parseSource) {
45
74
  // Convert null to empty string, then parse
46
75
  const fileSourceToProcess = fileData.source === null ? '' : fileData.source;
47
76
  if (typeof fileSourceToProcess === 'string') {
48
- // Parse string sources
49
- try {
50
- const parsedSource = parseSource(fileSourceToProcess, fileName);
51
- parsedExtraFiles[fileName] = {
52
- source: parsedSource
53
- };
54
- } catch (error) {
55
- // Keep original if parsing fails
77
+ const cached = tryCache(fileName, fileSourceToProcess);
78
+ if (cached) {
56
79
  parsedExtraFiles[fileName] = {
57
- source: fileSourceToProcess
80
+ source: cached,
81
+ comments: fileData.comments
58
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
+ }
59
97
  }
60
98
  } else {
61
99
  // Keep other values as-is
62
100
  parsedExtraFiles[fileName] = {
63
- source: fileSourceToProcess
101
+ source: fileSourceToProcess,
102
+ comments: fileData.comments
64
103
  };
65
104
  }
66
105
  }
@@ -71,7 +110,8 @@ export function parseControlledCode(controlledCode, parseSource) {
71
110
  url: variantCode.url,
72
111
  source: mainSource,
73
112
  extraFiles,
74
- filesOrder: variantCode.filesOrder
113
+ filesOrder: variantCode.filesOrder,
114
+ comments: variantCode.comments
75
115
  };
76
116
  }
77
117
  }