UNPKG

@mui/internal-docs-infra

Version:

MUI Infra - internal documentation creation tools.

152 lines (150 loc) 6.05 kB
/** * Recursively walks a jsondiffpatch delta looking for any inserted hast * element with `className === 'collapse'`. Used to mark a manifest entry * as layout-affecting (phase 1, coordinated barrier so peers stay in * lockstep) so the runtime doesn't have to decompress the embedded hast * payload on every selection change to classify the swap. * * Walks every nested value rather than interpreting jsondiffpatch's * opcodes (`[value]` for insert, `[oldValue, 0, 0]` for delete, `_t: 'a'` * + `_N` keys for array ops). The collapse placeholder is only ever * produced by `compactCollapseInTreeInPlace` on the *transform* side of * the diff, so any hast element with className 'collapse' anywhere in * the delta tree is necessarily part of an insertion or in-place rewrite. */ export function deltaContainsCollapse(delta) { if (delta === null || typeof delta !== 'object') { return false; } const candidate = delta; if (candidate.type === 'element') { const cls = candidate.properties?.className; if (cls === 'collapse') { return true; } if (Array.isArray(cls) && cls.includes('collapse')) { return true; } } if (Array.isArray(delta)) { for (const item of delta) { if (deltaContainsCollapse(item)) { return true; } } return false; } for (const value of Object.values(delta)) { if (deltaContainsCollapse(value)) { return true; } } return false; } /** * Splits a `Transforms` map (as produced by `diffHast`, which always * carries deltas for entries that change the source — rename-only * entries pass through with no delta) into the variant-level `manifest` * (no `delta`) and the `embedded` map that should ride inside * `source.data.transforms`. * * Entries with a meaningful delta land in both the manifest (with * `hasDelta: true`) and the embedded map. Rename-only entries (no * delta but a renamed `fileName`) land only in the manifest with * `hasDelta` omitted or `false`; consumers use this flag to hide the * transform toggle while still applying the rename when the user has * the matching transform preference selected. Entries with neither a * delta nor a rename are dropped from both. * * Returns `undefined` when no entry survived — callers should treat that * as "no transforms to record". * * This is the single source of truth for the manifest / embedded split; * both `computeHastDeltas` (per-file diffs) and the variant-level embed * step in `loadIsomorphicCodeVariant` go through it so the wire shape * stays consistent. */ export function splitTransformsForEmbed(transforms) { const manifest = {}; const embedded = {}; let kept = false; for (const [transformKey, transformValue] of Object.entries(transforms)) { if (!transformValue) { continue; } const hasMeaningfulDelta = !!transformValue.delta && typeof transformValue.delta === 'object' && Object.keys(transformValue.delta).length > 0; const renamed = !!transformValue.fileName; if (hasMeaningfulDelta) { embedded[transformKey] = transformValue; // The manifest entry keeps every field except `delta` (which only // ever travels embedded inside `root.data.transforms`). In // particular `comments` must survive serialization: transformers // that add or relocate lines emit an explicit post-transform map, // and the client-side `applyCodeTransformWithComments` consults // it in preference to the auto-shift fallback. Dropping it here // would silently downgrade those transforms to the wipe-only // remap path on hydrated payloads. `hasDelta: true` flags this // entry for `getAvailableTransforms` so the transform toggle is // surfaced in the UI. `hasCollapse` is propagated here so the // runtime can classify the swap as layout-affecting (phase 1) // versus non-layout (phase 2) without decompressing the embedded // hast payload — `diffHast` sets it directly from // `wiped.size > 0`; the `deltaContainsCollapse` walk only runs // for legacy callers that build a `Transforms` map without going // through `diffHast`. const hasCollapse = transformValue.hasCollapse ?? deltaContainsCollapse(transformValue.delta); // `hasCollapseInFocus` only ever comes from `diffHast`; legacy // callers (that bypass the diff and so never set it) fall back // to `hasCollapse`, matching the pre-focus behavior of the // runtime classifier. const hasCollapseInFocus = transformValue.hasCollapseInFocus ?? hasCollapse; const manifestEntry = { ...transformValue, hasDelta: true, hasCollapse, hasCollapseInFocus }; delete manifestEntry.delta; manifest[transformKey] = manifestEntry; kept = true; } else if (renamed) { // Rename-only entry: no source-level change, just a `fileName` // (and optionally `comments`). Keep it in the manifest so the // runtime can still apply the rename when the user has the // matching transform preference selected, but skip embedding — // there's no delta to ride along inside `source.data.transforms`. const { delta: droppedDelta, hasDelta: droppedHasDelta, hasCollapse: droppedHasCollapse, hasCollapseInFocus: droppedHasCollapseInFocus, ...rest } = transformValue; manifest[transformKey] = { ...rest, hasDelta: false, hasCollapse: false, hasCollapseInFocus: false }; kept = true; } } if (!kept) { return undefined; } return { manifest, embedded }; } /** * Embeds `embedded` transforms inside `root.data.transforms` so they ride * along inside the (possibly later compressed) hast payload and stay out * of the variant-level wire shape that ends up in HTML / module graph. */ export function embedTransformsInRoot(root, embedded) { root.data = { ...(root.data || {}), transforms: embedded }; }