@portabletext/editor 8.1.0 → 8.1.2
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/README.md +3 -3
- package/lib/{get-container-D1nM_ww9.js → get-container-D2pN5Npr.js} +3 -3
- package/lib/{get-container-D1nM_ww9.js.map → get-container-D2pN5Npr.js.map} +1 -1
- package/lib/{get-parent-Ci5241qs.js → get-parent-DgaKcy8-.js} +18 -12
- package/lib/get-parent-DgaKcy8-.js.map +1 -0
- package/lib/{get-path-sub-schema-CZd9VcVM.js → get-path-sub-schema-Dd0QYZ0m.js} +2 -2
- package/lib/{get-path-sub-schema-CZd9VcVM.js.map → get-path-sub-schema-Dd0QYZ0m.js.map} +1 -1
- package/lib/index.js +291 -264
- package/lib/index.js.map +1 -1
- package/lib/{selector.is-selecting-entire-blocks-DPnzucrd.js → selector.is-selecting-entire-blocks-BFhnnkHf.js} +4 -4
- package/lib/{selector.is-selecting-entire-blocks-DPnzucrd.js.map → selector.is-selecting-entire-blocks-BFhnnkHf.js.map} +1 -1
- package/lib/selectors/index.js +4 -4
- package/lib/traversal/index.js +3 -3
- package/lib/{util.is-equal-selections-N1hxVUbE.js → util.is-equal-selections-BdK98okY.js} +2 -2
- package/lib/{util.is-equal-selections-N1hxVUbE.js.map → util.is-equal-selections-BdK98okY.js.map} +1 -1
- package/lib/{util.slice-blocks-B2fZcNok.js → util.slice-blocks-_ElaB53f.js} +2 -2
- package/lib/{util.slice-blocks-B2fZcNok.js.map → util.slice-blocks-_ElaB53f.js.map} +1 -1
- package/lib/utils/index.js +3 -3
- package/package.json +2 -3
- package/lib/get-parent-Ci5241qs.js.map +0 -1
package/README.md
CHANGED
|
@@ -13,14 +13,14 @@
|
|
|
13
13
|
|
|
14
14
|
This library provides you with the building blocks to create a completely custom editor experience built on top of Portable Text. We recommend [checking out the official documentation](https://www.portabletext.org/). The following guide includes the basics to get your started.
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
To set up an editor you need to:
|
|
17
17
|
|
|
18
18
|
- Create a schema that defines the rich text and block content elements.
|
|
19
19
|
- Create a toolbar to toggle and insert these elements.
|
|
20
20
|
- Set up rendering for each element type in the editor, including text blocks and inline formatting.
|
|
21
21
|
- Render the editor.
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
The [Portable Text Playground](../../apps/playground/) is a complete editor built with this library. Use it as a reference.
|
|
24
24
|
|
|
25
25
|
### Add the library to your project
|
|
26
26
|
|
|
@@ -361,7 +361,7 @@ Extend the editor with [official plugins](../../#editor-plugins).
|
|
|
361
361
|
|
|
362
362
|
## End-user experience
|
|
363
363
|
|
|
364
|
-
|
|
364
|
+
A large E2E test suite, generated from a [human-readable Gherkin spec](./gherkin-spec/), guards the end-user experience: how selection, editing, and formatting behave under real keyboard and pointer input.
|
|
365
365
|
|
|
366
366
|
## Development
|
|
367
367
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { C as getAncestors, _ as comparePoints, b as isEditableContainer, g as isAfterPoint, m as rangeEdges, r as comparePoints$1, u as getNodes, v as comparePaths, y as isObject$1 } from "./get-path-sub-schema-
|
|
1
|
+
import { a as getChildren, d as isKeyedSegment, r as getNode } from "./get-parent-DgaKcy8-.js";
|
|
2
|
+
import { C as getAncestors, _ as comparePoints, b as isEditableContainer, g as isAfterPoint, m as rangeEdges, r as comparePoints$1, u as getNodes, v as comparePaths, y as isObject$1 } from "./get-path-sub-schema-Dd0QYZ0m.js";
|
|
3
3
|
import { getSubSchema, isSpan, isTextBlock } from "@portabletext/schema";
|
|
4
4
|
function getAncestor(snapshot, path, options) {
|
|
5
5
|
let { match, mode = "lowest" } = options, ancestors = getAncestors(snapshot, path);
|
|
@@ -219,4 +219,4 @@ function getContainer(snapshot, path) {
|
|
|
219
219
|
}
|
|
220
220
|
export { getAncestor as _, getTextBlock as a, pathContains as c, isRange as d, isPoint as f, isLeafObject as g, getLeaf as h, getFirstChild as i, getSpan as l, isPath as m, getUnionSchema as n, rangeIntersects as o, isObject as p, getLastChild as r, isBeforePoint as s, getContainer as t, getText as u };
|
|
221
221
|
|
|
222
|
-
//# sourceMappingURL=get-container-
|
|
222
|
+
//# sourceMappingURL=get-container-D2pN5Npr.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-container-D1nM_ww9.js","names":[],"sources":["../src/traversal/get-ancestor.ts","../src/traversal/is-leaf-object.ts","../src/traversal/get-leaf.ts","../src/engine/path/is-path.ts","../src/engine/utils/is-object.ts","../src/engine/point/is-point.ts","../src/engine/range/is-range.ts","../src/traversal/get-text.ts","../src/traversal/get-span.ts","../src/traversal/path-contains.ts","../src/engine/point/is-before-point.ts","../src/traversal/range-intersects.ts","../src/traversal/get-text-block.ts","../src/traversal/get-first-child.ts","../src/traversal/get-last-child.ts","../src/traversal/get-union-schema.ts","../src/traversal/get-container.ts"],"sourcesContent":["import type {PortableTextBlock} from '@portabletext/schema'\nimport type {Path} from '../engine/interfaces/path'\nimport {getAncestors} from './get-ancestors'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Find an ancestor of the node at a given path that matches a predicate.\n * Does not check the node at the path itself, only its ancestors.\n *\n * `mode: 'lowest'` (default) returns the nearest matching ancestor.\n * `mode: 'highest'` returns the outermost matching ancestor.\n *\n * When `match` is a type predicate, the returned `node` narrows to that type.\n *\n * @public\n */\nexport function getAncestor<TMatch extends PortableTextBlock>(\n snapshot: TraversalSnapshot,\n path: Path,\n options: {\n match: (node: PortableTextBlock, path: Path) => node is TMatch\n mode?: 'lowest' | 'highest'\n },\n): {node: TMatch; path: Path} | undefined\n/**\n * @public\n */\nexport function getAncestor(\n snapshot: TraversalSnapshot,\n path: Path,\n options: {\n match: (node: PortableTextBlock, path: Path) => boolean\n mode?: 'lowest' | 'highest'\n },\n): {node: PortableTextBlock; path: Path} | undefined\nexport function getAncestor(\n snapshot: TraversalSnapshot,\n path: Path,\n options: {\n match: (node: PortableTextBlock, path: Path) => boolean\n mode?: 'lowest' | 'highest'\n },\n): {node: PortableTextBlock; path: Path} | undefined {\n const {match, mode = 'lowest'} = options\n const ancestors = getAncestors(snapshot, path)\n\n if (mode === 'highest') {\n for (const ancestor of [...ancestors].reverse()) {\n if (match(ancestor.node, ancestor.path)) {\n return ancestor\n }\n }\n return undefined\n }\n\n for (const ancestor of ancestors) {\n if (match(ancestor.node, ancestor.path)) {\n return ancestor\n }\n }\n\n return undefined\n}\n","import type {PortableTextObject} from '@portabletext/schema'\nimport type {Path} from '../engine/interfaces/path'\nimport {isEditableContainer} from '../schema/is-editable-container'\nimport {isObject} from './is-object'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Check if a node is a leaf object: an object node that has no editable\n * children (not a container).\n * Returns true for block objects and inline objects that don't have\n * registered editable content (containers).\n *\n * @public\n */\nexport function isLeafObject(\n snapshot: TraversalSnapshot,\n node: unknown,\n path: Path,\n): node is PortableTextObject {\n return isObject(snapshot, node) && !isEditableContainer(snapshot, node, path)\n}\n","import type {Node} from '../engine/interfaces/node'\nimport type {Path} from '../engine/interfaces/path'\nimport {getChildren} from './get-children'\nimport {getNode} from './get-node'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Get the deepest leaf node starting from a path, walking toward either the\n * start or end edge. A leaf is any node that has no children according to the\n * traversal context.\n *\n * @public\n */\nexport function getLeaf(\n snapshot: TraversalSnapshot,\n path: Path,\n options: {edge: 'start' | 'end'},\n): {node: Node; path: Path} | undefined {\n const {edge} = options\n\n let currentPath = path\n\n // If starting from root (empty path), descend into first/last child\n if (currentPath.length === 0) {\n const children = getChildren(snapshot, [])\n if (children.length === 0) {\n return undefined\n }\n const firstOrLast = edge === 'end' ? children.at(-1)! : children.at(0)!\n const nodeChildren = getChildren(snapshot, firstOrLast.path)\n if (nodeChildren.length === 0) {\n return firstOrLast\n }\n currentPath = firstOrLast.path\n } else {\n // Check if the node at path is already a leaf\n const entry = getNode(snapshot, currentPath)\n if (!entry) {\n return undefined\n }\n const children = getChildren(snapshot, currentPath)\n if (children.length === 0) {\n return entry\n }\n }\n\n // Descend to deepest leaf\n while (true) {\n const children = getChildren(snapshot, currentPath)\n if (children.length === 0) {\n const entry = getNode(snapshot, currentPath)\n return entry ?? undefined\n }\n const child = edge === 'end' ? children.at(-1)! : children.at(0)!\n currentPath = child.path\n }\n}\n","import {isKeyedSegment} from '../../utils/util.is-keyed-segment'\nimport type {Path} from '../interfaces/path'\n\nexport function isPath(value: any): value is Path {\n return (\n Array.isArray(value) &&\n (value.length === 0 ||\n typeof value[0] === 'number' ||\n typeof value[0] === 'string' ||\n isKeyedSegment(value[0]))\n )\n}\n","export const isObject = (value: any) =>\n typeof value === 'object' && value !== null\n","import type {Point} from '../interfaces/point'\nimport {isPath} from '../path/is-path'\nimport {isObject} from '../utils/is-object'\n\nexport function isPoint(value: any): value is Point {\n return (\n isObject(value) && typeof value.offset === 'number' && isPath(value.path)\n )\n}\n","import type {Range} from '../interfaces/range'\nimport {isPoint} from '../point/is-point'\nimport {isObject} from '../utils/is-object'\n\nexport function isRange(value: any): value is Range {\n return isObject(value) && isPoint(value.anchor) && isPoint(value.focus)\n}\n","import {isSpan} from '@portabletext/schema'\nimport type {Path} from '../engine/interfaces/path'\nimport {getNode} from './get-node'\nimport {getNodes} from './get-nodes'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Get the concatenated text content of the node at a given path.\n *\n * @public\n */\nexport function getText(\n snapshot: TraversalSnapshot,\n path: Path,\n): string | undefined {\n const entry = getNode(snapshot, path)\n\n if (!entry) {\n return undefined\n }\n\n if (isSpan({schema: snapshot.context.schema}, entry.node)) {\n return entry.node.text\n }\n\n let text = ''\n\n for (const descendant of getNodes(snapshot, {at: path})) {\n if (isSpan({schema: snapshot.context.schema}, descendant.node)) {\n text += descendant.node.text\n }\n }\n\n return text\n}\n","import {isSpan, type PortableTextSpan} from '@portabletext/schema'\nimport type {Path} from '../engine/interfaces/path'\nimport {getNode} from './get-node'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Get the span node at a given path.\n *\n * @public\n */\nexport function getSpan(\n snapshot: TraversalSnapshot,\n path: Path,\n): {node: PortableTextSpan; path: Path} | undefined {\n const entry = getNode(snapshot, path)\n\n if (!entry) {\n return undefined\n }\n\n if (!isSpan({schema: snapshot.context.schema}, entry.node)) {\n return undefined\n }\n\n return {node: entry.node, path: entry.path}\n}\n","import type {Path} from '../types/paths'\nimport {isKeyedSegment} from '../utils/util.is-keyed-segment'\n\n/**\n * Returns true if `ancestor` is equal to `descendant`, or if `descendant`\n * lives anywhere inside `ancestor`'s subtree.\n *\n * @public\n */\nexport function pathContains(ancestor: Path, descendant: Path): boolean {\n if (ancestor.length > descendant.length) {\n return false\n }\n\n for (let i = 0; i < ancestor.length; i++) {\n const segment = ancestor[i]\n const otherSegment = descendant[i]\n\n if (isKeyedSegment(segment) && isKeyedSegment(otherSegment)) {\n if (segment._key !== otherSegment._key) {\n return false\n }\n } else if (segment !== otherSegment) {\n return false\n }\n }\n\n return true\n}\n","import type {Node} from '../interfaces/node'\nimport type {Point} from '../interfaces/point'\nimport {comparePoints} from './compare-points'\n\nexport function isBeforePoint(\n point: Point,\n another: Point,\n root: {value: Array<Node>},\n): boolean {\n return comparePoints(point, another, root) === -1\n}\n","import {comparePaths} from '../engine/path/compare-paths'\nimport {isAfterPoint} from '../engine/point/is-after-point'\nimport {isBeforePoint} from '../engine/point/is-before-point'\nimport {isPoint} from '../engine/point/is-point'\nimport {isRange} from '../engine/range/is-range'\nimport {rangeEdges} from '../engine/range/range-edges'\nimport type {EditorSelection, EditorSelectionPoint} from '../types/editor'\nimport type {Path} from '../types/paths'\nimport {comparePoints} from './compare-points'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Returns true if `range` and the supplied `target` intersect. The target\n * may be a `Path`, an `EditorSelectionPoint`, or another\n * `EditorSelection`.\n *\n * For a `Path` or `EditorSelectionPoint` target, \"intersect\" means the\n * target lies at or between `range`'s start and end edges (inclusive).\n *\n * For an `EditorSelection` target, \"intersect\" means either endpoint of\n * `target` lies inside `range`, or `range` strictly encloses `target`.\n *\n * Pass `snapshot.context.selection` as `range` to ask the question against\n * the editor's current selection.\n *\n * Returns `false` when either `range` or `target` is `null`.\n *\n * @public\n */\nexport function rangeIntersects(\n snapshot: TraversalSnapshot,\n range: EditorSelection,\n target: Path | EditorSelectionPoint | EditorSelection,\n): boolean {\n if (!range || target === null) {\n return false\n }\n\n const root = {value: snapshot.context.value}\n\n if (isRange(target)) {\n if (\n rangeIntersects(snapshot, range, target.anchor) ||\n rangeIntersects(snapshot, range, target.focus)\n ) {\n return true\n }\n const [rs, re] = rangeEdges(range, root)\n const [ts, te] = rangeEdges(target, root)\n return isBeforePoint(rs, ts, root) && isAfterPoint(re, te, root)\n }\n\n const [start, end] = rangeEdges(range, root)\n let isAfterStart = false\n let isBeforeEnd = false\n\n if (isPoint(target)) {\n isAfterStart = comparePoints(snapshot, target, start) >= 0\n isBeforeEnd = comparePoints(snapshot, target, end) <= 0\n } else {\n isAfterStart = comparePaths(target, start.path, root) >= 0\n isBeforeEnd = comparePaths(target, end.path, root) <= 0\n }\n\n return isAfterStart && isBeforeEnd\n}\n","import {isTextBlock, type PortableTextTextBlock} from '@portabletext/schema'\nimport type {Path} from '../engine/interfaces/path'\nimport {getNode} from './get-node'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Get the text block node at a given path.\n *\n * @public\n */\nexport function getTextBlock(\n snapshot: TraversalSnapshot,\n path: Path,\n): {node: PortableTextTextBlock; path: Path} | undefined {\n const entry = getNode(snapshot, path)\n\n if (!entry) {\n return undefined\n }\n\n if (!isTextBlock({schema: snapshot.context.schema}, entry.node)) {\n return undefined\n }\n\n return {node: entry.node, path: entry.path}\n}\n","import type {Node} from '../engine/interfaces/node'\nimport type {Path} from '../engine/interfaces/path'\nimport {getChildren} from './get-children'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Get the first child of a node at a given path.\n *\n * @public\n */\nexport function getFirstChild(\n snapshot: TraversalSnapshot,\n path: Path,\n): {node: Node; path: Path} | undefined {\n return getChildren(snapshot, path).at(0)\n}\n","import type {Node} from '../engine/interfaces/node'\nimport type {Path} from '../engine/interfaces/path'\nimport {getChildren} from './get-children'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Get the last child of a node at a given path.\n *\n * @public\n */\nexport function getLastChild(\n snapshot: TraversalSnapshot,\n path: Path,\n): {node: Node; path: Path} | undefined {\n const children = getChildren(snapshot, path)\n\n return children.at(-1)\n}\n","import {getSubSchema, type Schema} from '@portabletext/schema'\nimport type {Containers} from '../schema/resolve-containers'\n\n/**\n * Return a `Schema` that contains every named member declared anywhere\n * in the editor's schema graph that is reachable from a position where text\n * is edited - the root schema merged with the sub-schema of every registered\n * container whose field accepts text blocks, deduped by name. Useful for\n * rendering a static toolbar whose buttons stay stable across selection\n * moves while still reflecting everything that could plausibly be edited or\n * inserted somewhere.\n *\n * Containers whose field does NOT accept text blocks (e.g. a `table`\n * container whose `rows` field only accepts `row` objects, or a `row`\n * container whose `cells` field only accepts `cell` objects) are\n * **structural**: their immediate `of` types are organizational, not\n * insertable user content. Those structural types are excluded from the\n * union. Their nested text-block-accepting descendants (e.g. a `cell`\n * that contains a `content` field of `{type: 'block'}`) are reached via\n * those descendants' own container registration.\n *\n * Pair with `getPathSubSchema` (or a path-based intersection across a\n * range) to determine which of the union's members are applicable at the\n * current selection.\n *\n * @public\n */\nexport function getUnionSchema(schema: Schema, containers: Containers): Schema {\n const decorators = mergeByName(schema.decorators, [])\n const annotations = mergeByName(schema.annotations, [])\n const lists = mergeByName(schema.lists, [])\n const styles = mergeByName(schema.styles, [])\n const inlineObjects = mergeByName(schema.inlineObjects, [])\n const blockObjects = mergeByName(schema.blockObjects, [])\n\n for (const container of containers.values()) {\n if (!acceptsTextBlock(container.field.of, schema.block.name)) {\n continue\n }\n const sub = getSubSchema(schema, container.field.of)\n mergeByName(sub.decorators, decorators)\n mergeByName(sub.annotations, annotations)\n mergeByName(sub.lists, lists)\n mergeByName(sub.styles, styles)\n mergeByName(sub.inlineObjects, inlineObjects)\n mergeByName(sub.blockObjects, blockObjects)\n }\n\n return {\n ...schema,\n decorators,\n annotations,\n lists,\n styles,\n inlineObjects,\n blockObjects,\n }\n}\n\nfunction acceptsTextBlock(\n of: ReadonlyArray<{type: string}>,\n blockName: string,\n): boolean {\n return of.some(\n (member) => member.type === 'block' || member.type === blockName,\n )\n}\n\nfunction mergeByName<T extends {name: string}>(\n source: ReadonlyArray<T>,\n target: Array<T>,\n): Array<T> {\n for (const entry of source) {\n if (target.some((existing) => existing.name === entry.name)) {\n continue\n }\n target.push(entry)\n }\n return target\n}\n","import type {Node} from '../engine/interfaces/node'\nimport type {Path} from '../engine/interfaces/path'\nimport {isEditableContainer} from '../schema/is-editable-container'\nimport {getNode} from './get-node'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Get the registered editable container at a given path.\n *\n * @public\n */\nexport function getContainer(\n snapshot: TraversalSnapshot,\n path: Path,\n): {node: Node; path: Path} | undefined {\n const entry = getNode(snapshot, path)\n\n if (!entry) {\n return undefined\n }\n\n if (!isEditableContainer(snapshot, entry.node, entry.path)) {\n return undefined\n }\n\n return {node: entry.node, path: entry.path}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"get-container-D2pN5Npr.js","names":[],"sources":["../src/traversal/get-ancestor.ts","../src/traversal/is-leaf-object.ts","../src/traversal/get-leaf.ts","../src/engine/path/is-path.ts","../src/engine/utils/is-object.ts","../src/engine/point/is-point.ts","../src/engine/range/is-range.ts","../src/traversal/get-text.ts","../src/traversal/get-span.ts","../src/traversal/path-contains.ts","../src/engine/point/is-before-point.ts","../src/traversal/range-intersects.ts","../src/traversal/get-text-block.ts","../src/traversal/get-first-child.ts","../src/traversal/get-last-child.ts","../src/traversal/get-union-schema.ts","../src/traversal/get-container.ts"],"sourcesContent":["import type {PortableTextBlock} from '@portabletext/schema'\nimport type {Path} from '../engine/interfaces/path'\nimport {getAncestors} from './get-ancestors'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Find an ancestor of the node at a given path that matches a predicate.\n * Does not check the node at the path itself, only its ancestors.\n *\n * `mode: 'lowest'` (default) returns the nearest matching ancestor.\n * `mode: 'highest'` returns the outermost matching ancestor.\n *\n * When `match` is a type predicate, the returned `node` narrows to that type.\n *\n * @public\n */\nexport function getAncestor<TMatch extends PortableTextBlock>(\n snapshot: TraversalSnapshot,\n path: Path,\n options: {\n match: (node: PortableTextBlock, path: Path) => node is TMatch\n mode?: 'lowest' | 'highest'\n },\n): {node: TMatch; path: Path} | undefined\n/**\n * @public\n */\nexport function getAncestor(\n snapshot: TraversalSnapshot,\n path: Path,\n options: {\n match: (node: PortableTextBlock, path: Path) => boolean\n mode?: 'lowest' | 'highest'\n },\n): {node: PortableTextBlock; path: Path} | undefined\nexport function getAncestor(\n snapshot: TraversalSnapshot,\n path: Path,\n options: {\n match: (node: PortableTextBlock, path: Path) => boolean\n mode?: 'lowest' | 'highest'\n },\n): {node: PortableTextBlock; path: Path} | undefined {\n const {match, mode = 'lowest'} = options\n const ancestors = getAncestors(snapshot, path)\n\n if (mode === 'highest') {\n for (const ancestor of [...ancestors].reverse()) {\n if (match(ancestor.node, ancestor.path)) {\n return ancestor\n }\n }\n return undefined\n }\n\n for (const ancestor of ancestors) {\n if (match(ancestor.node, ancestor.path)) {\n return ancestor\n }\n }\n\n return undefined\n}\n","import type {PortableTextObject} from '@portabletext/schema'\nimport type {Path} from '../engine/interfaces/path'\nimport {isEditableContainer} from '../schema/is-editable-container'\nimport {isObject} from './is-object'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Check if a node is a leaf object: an object node that has no editable\n * children (not a container).\n * Returns true for block objects and inline objects that don't have\n * registered editable content (containers).\n *\n * @public\n */\nexport function isLeafObject(\n snapshot: TraversalSnapshot,\n node: unknown,\n path: Path,\n): node is PortableTextObject {\n return isObject(snapshot, node) && !isEditableContainer(snapshot, node, path)\n}\n","import type {Node} from '../engine/interfaces/node'\nimport type {Path} from '../engine/interfaces/path'\nimport {getChildren} from './get-children'\nimport {getNode} from './get-node'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Get the deepest leaf node starting from a path, walking toward either the\n * start or end edge. A leaf is any node that has no children according to the\n * traversal context.\n *\n * @public\n */\nexport function getLeaf(\n snapshot: TraversalSnapshot,\n path: Path,\n options: {edge: 'start' | 'end'},\n): {node: Node; path: Path} | undefined {\n const {edge} = options\n\n let currentPath = path\n\n // If starting from root (empty path), descend into first/last child\n if (currentPath.length === 0) {\n const children = getChildren(snapshot, [])\n if (children.length === 0) {\n return undefined\n }\n const firstOrLast = edge === 'end' ? children.at(-1)! : children.at(0)!\n const nodeChildren = getChildren(snapshot, firstOrLast.path)\n if (nodeChildren.length === 0) {\n return firstOrLast\n }\n currentPath = firstOrLast.path\n } else {\n // Check if the node at path is already a leaf\n const entry = getNode(snapshot, currentPath)\n if (!entry) {\n return undefined\n }\n const children = getChildren(snapshot, currentPath)\n if (children.length === 0) {\n return entry\n }\n }\n\n // Descend to deepest leaf\n while (true) {\n const children = getChildren(snapshot, currentPath)\n if (children.length === 0) {\n const entry = getNode(snapshot, currentPath)\n return entry ?? undefined\n }\n const child = edge === 'end' ? children.at(-1)! : children.at(0)!\n currentPath = child.path\n }\n}\n","import {isKeyedSegment} from '../../utils/util.is-keyed-segment'\nimport type {Path} from '../interfaces/path'\n\nexport function isPath(value: any): value is Path {\n return (\n Array.isArray(value) &&\n (value.length === 0 ||\n typeof value[0] === 'number' ||\n typeof value[0] === 'string' ||\n isKeyedSegment(value[0]))\n )\n}\n","export const isObject = (value: any) =>\n typeof value === 'object' && value !== null\n","import type {Point} from '../interfaces/point'\nimport {isPath} from '../path/is-path'\nimport {isObject} from '../utils/is-object'\n\nexport function isPoint(value: any): value is Point {\n return (\n isObject(value) && typeof value.offset === 'number' && isPath(value.path)\n )\n}\n","import type {Range} from '../interfaces/range'\nimport {isPoint} from '../point/is-point'\nimport {isObject} from '../utils/is-object'\n\nexport function isRange(value: any): value is Range {\n return isObject(value) && isPoint(value.anchor) && isPoint(value.focus)\n}\n","import {isSpan} from '@portabletext/schema'\nimport type {Path} from '../engine/interfaces/path'\nimport {getNode} from './get-node'\nimport {getNodes} from './get-nodes'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Get the concatenated text content of the node at a given path.\n *\n * @public\n */\nexport function getText(\n snapshot: TraversalSnapshot,\n path: Path,\n): string | undefined {\n const entry = getNode(snapshot, path)\n\n if (!entry) {\n return undefined\n }\n\n if (isSpan({schema: snapshot.context.schema}, entry.node)) {\n return entry.node.text\n }\n\n let text = ''\n\n for (const descendant of getNodes(snapshot, {at: path})) {\n if (isSpan({schema: snapshot.context.schema}, descendant.node)) {\n text += descendant.node.text\n }\n }\n\n return text\n}\n","import {isSpan, type PortableTextSpan} from '@portabletext/schema'\nimport type {Path} from '../engine/interfaces/path'\nimport {getNode} from './get-node'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Get the span node at a given path.\n *\n * @public\n */\nexport function getSpan(\n snapshot: TraversalSnapshot,\n path: Path,\n): {node: PortableTextSpan; path: Path} | undefined {\n const entry = getNode(snapshot, path)\n\n if (!entry) {\n return undefined\n }\n\n if (!isSpan({schema: snapshot.context.schema}, entry.node)) {\n return undefined\n }\n\n return {node: entry.node, path: entry.path}\n}\n","import type {Path} from '../types/paths'\nimport {isKeyedSegment} from '../utils/util.is-keyed-segment'\n\n/**\n * Returns true if `ancestor` is equal to `descendant`, or if `descendant`\n * lives anywhere inside `ancestor`'s subtree.\n *\n * @public\n */\nexport function pathContains(ancestor: Path, descendant: Path): boolean {\n if (ancestor.length > descendant.length) {\n return false\n }\n\n for (let i = 0; i < ancestor.length; i++) {\n const segment = ancestor[i]\n const otherSegment = descendant[i]\n\n if (isKeyedSegment(segment) && isKeyedSegment(otherSegment)) {\n if (segment._key !== otherSegment._key) {\n return false\n }\n } else if (segment !== otherSegment) {\n return false\n }\n }\n\n return true\n}\n","import type {Node} from '../interfaces/node'\nimport type {Point} from '../interfaces/point'\nimport {comparePoints} from './compare-points'\n\nexport function isBeforePoint(\n point: Point,\n another: Point,\n root: {value: Array<Node>},\n): boolean {\n return comparePoints(point, another, root) === -1\n}\n","import {comparePaths} from '../engine/path/compare-paths'\nimport {isAfterPoint} from '../engine/point/is-after-point'\nimport {isBeforePoint} from '../engine/point/is-before-point'\nimport {isPoint} from '../engine/point/is-point'\nimport {isRange} from '../engine/range/is-range'\nimport {rangeEdges} from '../engine/range/range-edges'\nimport type {EditorSelection, EditorSelectionPoint} from '../types/editor'\nimport type {Path} from '../types/paths'\nimport {comparePoints} from './compare-points'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Returns true if `range` and the supplied `target` intersect. The target\n * may be a `Path`, an `EditorSelectionPoint`, or another\n * `EditorSelection`.\n *\n * For a `Path` or `EditorSelectionPoint` target, \"intersect\" means the\n * target lies at or between `range`'s start and end edges (inclusive).\n *\n * For an `EditorSelection` target, \"intersect\" means either endpoint of\n * `target` lies inside `range`, or `range` strictly encloses `target`.\n *\n * Pass `snapshot.context.selection` as `range` to ask the question against\n * the editor's current selection.\n *\n * Returns `false` when either `range` or `target` is `null`.\n *\n * @public\n */\nexport function rangeIntersects(\n snapshot: TraversalSnapshot,\n range: EditorSelection,\n target: Path | EditorSelectionPoint | EditorSelection,\n): boolean {\n if (!range || target === null) {\n return false\n }\n\n const root = {value: snapshot.context.value}\n\n if (isRange(target)) {\n if (\n rangeIntersects(snapshot, range, target.anchor) ||\n rangeIntersects(snapshot, range, target.focus)\n ) {\n return true\n }\n const [rs, re] = rangeEdges(range, root)\n const [ts, te] = rangeEdges(target, root)\n return isBeforePoint(rs, ts, root) && isAfterPoint(re, te, root)\n }\n\n const [start, end] = rangeEdges(range, root)\n let isAfterStart = false\n let isBeforeEnd = false\n\n if (isPoint(target)) {\n isAfterStart = comparePoints(snapshot, target, start) >= 0\n isBeforeEnd = comparePoints(snapshot, target, end) <= 0\n } else {\n isAfterStart = comparePaths(target, start.path, root) >= 0\n isBeforeEnd = comparePaths(target, end.path, root) <= 0\n }\n\n return isAfterStart && isBeforeEnd\n}\n","import {isTextBlock, type PortableTextTextBlock} from '@portabletext/schema'\nimport type {Path} from '../engine/interfaces/path'\nimport {getNode} from './get-node'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Get the text block node at a given path.\n *\n * @public\n */\nexport function getTextBlock(\n snapshot: TraversalSnapshot,\n path: Path,\n): {node: PortableTextTextBlock; path: Path} | undefined {\n const entry = getNode(snapshot, path)\n\n if (!entry) {\n return undefined\n }\n\n if (!isTextBlock({schema: snapshot.context.schema}, entry.node)) {\n return undefined\n }\n\n return {node: entry.node, path: entry.path}\n}\n","import type {Node} from '../engine/interfaces/node'\nimport type {Path} from '../engine/interfaces/path'\nimport {getChildren} from './get-children'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Get the first child of a node at a given path.\n *\n * @public\n */\nexport function getFirstChild(\n snapshot: TraversalSnapshot,\n path: Path,\n): {node: Node; path: Path} | undefined {\n return getChildren(snapshot, path).at(0)\n}\n","import type {Node} from '../engine/interfaces/node'\nimport type {Path} from '../engine/interfaces/path'\nimport {getChildren} from './get-children'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Get the last child of a node at a given path.\n *\n * @public\n */\nexport function getLastChild(\n snapshot: TraversalSnapshot,\n path: Path,\n): {node: Node; path: Path} | undefined {\n const children = getChildren(snapshot, path)\n\n return children.at(-1)\n}\n","import {getSubSchema, type Schema} from '@portabletext/schema'\nimport type {Containers} from '../schema/resolve-containers'\n\n/**\n * Return a `Schema` that contains every named member declared anywhere\n * in the editor's schema graph that is reachable from a position where text\n * is edited - the root schema merged with the sub-schema of every registered\n * container whose field accepts text blocks, deduped by name. Useful for\n * rendering a static toolbar whose buttons stay stable across selection\n * moves while still reflecting everything that could plausibly be edited or\n * inserted somewhere.\n *\n * Containers whose field does NOT accept text blocks (e.g. a `table`\n * container whose `rows` field only accepts `row` objects, or a `row`\n * container whose `cells` field only accepts `cell` objects) are\n * **structural**: their immediate `of` types are organizational, not\n * insertable user content. Those structural types are excluded from the\n * union. Their nested text-block-accepting descendants (e.g. a `cell`\n * that contains a `content` field of `{type: 'block'}`) are reached via\n * those descendants' own container registration.\n *\n * Pair with `getPathSubSchema` (or a path-based intersection across a\n * range) to determine which of the union's members are applicable at the\n * current selection.\n *\n * @public\n */\nexport function getUnionSchema(schema: Schema, containers: Containers): Schema {\n const decorators = mergeByName(schema.decorators, [])\n const annotations = mergeByName(schema.annotations, [])\n const lists = mergeByName(schema.lists, [])\n const styles = mergeByName(schema.styles, [])\n const inlineObjects = mergeByName(schema.inlineObjects, [])\n const blockObjects = mergeByName(schema.blockObjects, [])\n\n for (const container of containers.values()) {\n if (!acceptsTextBlock(container.field.of, schema.block.name)) {\n continue\n }\n const sub = getSubSchema(schema, container.field.of)\n mergeByName(sub.decorators, decorators)\n mergeByName(sub.annotations, annotations)\n mergeByName(sub.lists, lists)\n mergeByName(sub.styles, styles)\n mergeByName(sub.inlineObjects, inlineObjects)\n mergeByName(sub.blockObjects, blockObjects)\n }\n\n return {\n ...schema,\n decorators,\n annotations,\n lists,\n styles,\n inlineObjects,\n blockObjects,\n }\n}\n\nfunction acceptsTextBlock(\n of: ReadonlyArray<{type: string}>,\n blockName: string,\n): boolean {\n return of.some(\n (member) => member.type === 'block' || member.type === blockName,\n )\n}\n\nfunction mergeByName<T extends {name: string}>(\n source: ReadonlyArray<T>,\n target: Array<T>,\n): Array<T> {\n for (const entry of source) {\n if (target.some((existing) => existing.name === entry.name)) {\n continue\n }\n target.push(entry)\n }\n return target\n}\n","import type {Node} from '../engine/interfaces/node'\nimport type {Path} from '../engine/interfaces/path'\nimport {isEditableContainer} from '../schema/is-editable-container'\nimport {getNode} from './get-node'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Get the registered editable container at a given path.\n *\n * @public\n */\nexport function getContainer(\n snapshot: TraversalSnapshot,\n path: Path,\n): {node: Node; path: Path} | undefined {\n const entry = getNode(snapshot, path)\n\n if (!entry) {\n return undefined\n }\n\n if (!isEditableContainer(snapshot, entry.node, entry.path)) {\n return undefined\n }\n\n return {node: entry.node, path: entry.path}\n}\n"],"mappings":"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"}
|
|
@@ -155,7 +155,11 @@ function getNodeChildren(context, node, parent) {
|
|
|
155
155
|
* @public
|
|
156
156
|
*/
|
|
157
157
|
function getNode(snapshot, path) {
|
|
158
|
-
|
|
158
|
+
let result = resolveNode(snapshot, path);
|
|
159
|
+
return result.status === "found" ? result.entry : void 0;
|
|
160
|
+
}
|
|
161
|
+
function resolveNode(snapshot, path) {
|
|
162
|
+
if (path.length === 0) return { status: "missing" };
|
|
159
163
|
let { context, blockIndexMap } = snapshot, currentChildren = context.value, currentFieldName, node, currentParent, resolvedPath = [];
|
|
160
164
|
for (let i = 0; i < path.length; i++) {
|
|
161
165
|
let segment = path[i];
|
|
@@ -166,7 +170,7 @@ function getNode(snapshot, path) {
|
|
|
166
170
|
}
|
|
167
171
|
for (let j = i + 1; j < path.length; j++) {
|
|
168
172
|
let s = path[j];
|
|
169
|
-
if (isKeyedSegment(s) || typeof s == "number") return;
|
|
173
|
+
if (isKeyedSegment(s) || typeof s == "number") return { status: "unreachable" };
|
|
170
174
|
}
|
|
171
175
|
break;
|
|
172
176
|
}
|
|
@@ -175,8 +179,8 @@ function getNode(snapshot, path) {
|
|
|
175
179
|
let index = blockIndexMap.get(serializePath(resolvedPath));
|
|
176
180
|
index !== void 0 && currentChildren[index]?._key === segment._key ? node = currentChildren[index] : (node = currentChildren.find((child) => child._key === segment._key), node && node._key !== void 0 && (resolvedPath[resolvedPath.length - 1] = { _key: node._key }));
|
|
177
181
|
} else if (typeof segment == "number") node = currentChildren.at(segment), node && resolvedPath.push({ _key: node._key });
|
|
178
|
-
else return;
|
|
179
|
-
if (!node) return;
|
|
182
|
+
else return { status: "missing" };
|
|
183
|
+
if (!node) return { status: "missing" };
|
|
180
184
|
let hasMoreSegments = !1;
|
|
181
185
|
for (let j = i + 1; j < path.length; j++) {
|
|
182
186
|
let s = path[j];
|
|
@@ -187,17 +191,19 @@ function getNode(snapshot, path) {
|
|
|
187
191
|
}
|
|
188
192
|
if (hasMoreSegments) {
|
|
189
193
|
let next = getNodeChildren(context, node, currentParent);
|
|
190
|
-
if (!next) return;
|
|
194
|
+
if (!next) return { status: "missing" };
|
|
191
195
|
currentChildren = next.children, currentFieldName = next.fieldName, currentParent = next.parent;
|
|
192
196
|
} else currentFieldName = void 0;
|
|
193
197
|
}
|
|
194
|
-
if (node) {
|
|
195
|
-
|
|
196
|
-
|
|
198
|
+
if (!node) return { status: "missing" };
|
|
199
|
+
for (; resolvedPath.length > 0 && typeof resolvedPath[resolvedPath.length - 1] == "string";) resolvedPath.pop();
|
|
200
|
+
return {
|
|
201
|
+
status: "found",
|
|
202
|
+
entry: {
|
|
197
203
|
node,
|
|
198
204
|
path: resolvedPath
|
|
199
|
-
}
|
|
200
|
-
}
|
|
205
|
+
}
|
|
206
|
+
};
|
|
201
207
|
}
|
|
202
208
|
/**
|
|
203
209
|
* Get the parent path of a path.
|
|
@@ -232,6 +238,6 @@ function getParent(snapshot, path, options) {
|
|
|
232
238
|
};
|
|
233
239
|
if (!(options?.match && !options.match(result.node, result.path))) return result;
|
|
234
240
|
}
|
|
235
|
-
export {
|
|
241
|
+
export { getChildren as a, isRecord as c, isKeyedSegment as d, resolveNode as i, isTypedObject as l, parentPath as n, getNodeChildren as o, getNode as r, getContainerChildren as s, getParent as t, serializePath as u };
|
|
236
242
|
|
|
237
|
-
//# sourceMappingURL=get-parent-
|
|
243
|
+
//# sourceMappingURL=get-parent-DgaKcy8-.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-parent-DgaKcy8-.js","names":[],"sources":["../src/utils/util.is-keyed-segment.ts","../src/paths/serialize-path.ts","../src/utils/asserters.ts","../src/traversal/get-container-children.ts","../src/traversal/get-children.ts","../src/traversal/get-node.ts","../src/engine/path/parent-path.ts","../src/traversal/get-parent.ts"],"sourcesContent":["import type {KeyedSegment} from '../types/paths'\n\n/**\n * @public\n */\nexport function isKeyedSegment(segment: unknown): segment is KeyedSegment {\n return typeof segment === 'object' && segment !== null && '_key' in segment\n}\n","import type {Path} from '../types/paths'\nimport {isKeyedSegment} from '../utils/util.is-keyed-segment'\n\n/**\n * Serialize a keyed path to a string using Sanity's bracket notation.\n *\n * - `[{_key: 'k0'}]` -> `[_key==\"k0\"]`\n * - `[{_key: 'k0'}, 'children', {_key: 's0'}]` -> `[_key==\"k0\"].children[_key==\"s0\"]`\n * - `[{_key: 't0'}, 'rows', {_key: 'r0'}, 'cells', {_key: 'c0'}, 'content', {_key: 'b0'}, 'children', {_key: 's0'}]` -> `[_key==\"t0\"].rows[_key==\"r0\"].cells[_key==\"c0\"].content[_key==\"b0\"].children[_key==\"s0\"]`\n */\nexport function serializePath(path: Path): string {\n return path.reduce<string>((result, segment, index) => {\n if (isKeyedSegment(segment)) {\n return `${result}[_key==\"${segment._key}\"]`\n }\n\n const separator = index === 0 ? '' : '.'\n return `${result}${separator}${segment}`\n }, '')\n}\n","import type {TypedObject} from '@portabletext/schema'\n\nexport function isTypedObject(object: unknown): object is TypedObject {\n return isRecord(object) && typeof object['_type'] === 'string'\n}\n\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && (typeof value === 'object' || typeof value === 'function')\n}\n","import type {Node} from '../engine/interfaces/node'\nimport type {\n Containers,\n RegisteredContainer,\n} from '../schema/resolve-containers'\n\n/**\n * Resolve a container node's editable child array.\n *\n * Returns `{children, container}` for a node registered as a container:\n * `children` is the node's editable child array, and `container` is the\n * node's own container registration. Read `container.field.name` for the\n * path segment that reaches `children`, and thread `container` back in as\n * `parent` when descending into them.\n *\n * Returns `undefined` for anything that is not a container: text blocks,\n * spans, leaves, and unregistered objects. It is node-based and resolves\n * in one step with no path re-walk, so recursive descent over containers\n * is linear in nesting depth. The caller seeds the document root from\n * `context.value` itself.\n *\n * @beta\n */\nexport function getContainerChildren(\n containers: Containers,\n node: Node,\n parent?: RegisteredContainer,\n):\n | {\n children: Array<Node>\n container: RegisteredContainer\n }\n | undefined {\n const resolved = resolveNodeContainer(containers, parent, node)\n\n if (!resolved) {\n return undefined\n }\n\n const fieldValue = (node as Record<string, unknown>)[resolved.field.name]\n\n if (!Array.isArray(fieldValue)) {\n return undefined\n }\n\n return {\n children: fieldValue as Array<Node>,\n container: resolved,\n }\n}\n\n/**\n * Pick the positional override from `parent.of` if present; fall back\n * to the top-level entry. Returns only `RegisteredContainer` entries\n * since leaves do not have editable children.\n */\nfunction resolveNodeContainer(\n containers: Containers,\n parent: RegisteredContainer | undefined,\n node: Node,\n): RegisteredContainer | undefined {\n if (parent?.of) {\n for (const entry of parent.of) {\n if (entry.type === node._type) {\n // Only return container entries; leaves have no editable children.\n if ('field' in entry) {\n return entry\n }\n return undefined\n }\n }\n }\n return containers.get(node._type)\n}\n","import {isTextBlock} from '@portabletext/schema'\nimport type {EditorSchema} from '../editor/editor-schema'\nimport type {Node} from '../engine/interfaces/node'\nimport type {Path} from '../engine/interfaces/path'\nimport {serializePath} from '../paths/serialize-path'\nimport type {\n Containers,\n RegisteredContainer,\n} from '../schema/resolve-containers'\nimport {isTypedObject} from '../utils/asserters'\nimport {isKeyedSegment} from '../utils/util.is-keyed-segment'\nimport {getContainerChildren} from './get-container-children'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Get the children of a node at a given path.\n *\n * @public\n */\nexport function getChildren(\n snapshot: TraversalSnapshot,\n path: Path,\n): Array<{node: Node; path: Path}> {\n let currentChildren: Array<Node> = snapshot.context.value\n let currentFieldName = 'value'\n let currentPath: Path = []\n let isRoot = true\n let currentParent: RegisteredContainer | undefined\n\n for (const segment of path) {\n if (typeof segment === 'string') {\n continue\n }\n\n let node: Node | undefined\n if (isKeyedSegment(segment)) {\n // Resolve via `blockIndexMap` (O(1)) and fall back to a linear scan on a\n // miss or when the snapshot's map disagrees with the value, mirroring\n // `getNode`. The candidate path is this segment's full keyed path.\n const candidatePath: Path = isRoot\n ? [{_key: segment._key}]\n : [...currentPath, currentFieldName, {_key: segment._key}]\n const index = snapshot.blockIndexMap.get(serializePath(candidatePath))\n node =\n index !== undefined && currentChildren[index]?._key === segment._key\n ? currentChildren[index]\n : currentChildren.find((child) => child._key === segment._key)\n } else if (typeof segment === 'number') {\n node = currentChildren.at(segment)\n }\n\n if (!node) {\n return []\n }\n\n currentPath = isRoot\n ? [{_key: node._key}]\n : [...currentPath, currentFieldName, {_key: node._key}]\n isRoot = false\n\n const next = getNodeChildren(snapshot.context, node, currentParent)\n\n if (!next) {\n return []\n }\n\n currentChildren = next.children\n currentFieldName = next.fieldName\n currentParent = next.parent\n }\n\n return currentChildren.map((child) => ({\n node: child,\n path: isRoot\n ? [{_key: child._key}]\n : [...currentPath, currentFieldName, {_key: child._key}],\n }))\n}\n\n/**\n * Resolve a node's editable child array.\n *\n * When `parent` is provided and its `of` declares a positional entry\n * matching `node._type`, that positional entry's `field` is used.\n * Otherwise the top-level `containers.get(node._type)` provides the\n * fallback.\n *\n * The returned `parent` is the resolved container entry for `node`\n * itself (used by the caller to thread further descent).\n *\n * Internal descent kernel shared by the positional traversal utilities\n * (`getChildren`, `getNode`, `getNodes`, `getAncestors`); it folds the\n * text-block, container, and root-document cases. Public consumers that\n * only need to descend containers use {@link getContainerChildren}.\n */\nexport function getNodeChildren(\n context: {\n schema: EditorSchema\n containers: Containers\n },\n node: Node | {value: Array<Node>},\n parent?: RegisteredContainer,\n):\n | {\n children: Array<Node>\n fieldName: string\n parent: RegisteredContainer | undefined\n }\n | undefined {\n // Text blocks store children in .children\n if (isTextBlock(context, node)) {\n return {\n children: node.children,\n fieldName: 'children',\n parent: undefined,\n }\n }\n\n if (isTypedObject(node)) {\n const result = getContainerChildren(context.containers, node, parent)\n\n if (result) {\n return {\n children: result.children,\n fieldName: result.container.field.name,\n parent: result.container,\n }\n }\n }\n\n // Root context: has .value array but no _key or _type\n if (\n 'value' in node &&\n Array.isArray(node['value']) &&\n !('_key' in node) &&\n !('_type' in node)\n ) {\n return {\n children: node['value'] as Array<Node>,\n fieldName: 'value',\n parent: undefined,\n }\n }\n\n return undefined\n}\n","import type {Node} from '../engine/interfaces/node'\nimport type {Path} from '../engine/interfaces/path'\nimport {serializePath} from '../paths/serialize-path'\nimport type {RegisteredContainer} from '../schema/resolve-containers'\nimport {isKeyedSegment} from '../utils/util.is-keyed-segment'\nimport {getNodeChildren} from './get-children'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Get the node at a given path.\n *\n * The path can be either keyed (KeyedSegment + field name strings) or\n * indexed (numbers). Keyed segments are resolved by matching `_key`,\n * field name strings name a structural descent into the previous\n * node's children, and numbers are resolved by index.\n *\n * The returned `path` always identifies the returned node: it's fully\n * keyed (numeric indices are converted to `KeyedSegment`s) and any\n * trailing segments in the input that point outside the value tree —\n * e.g. an object node's primitive field, or an annotation reached via\n * `'markDefs'` on a text block — are stripped so that\n * `getNode(snapshot, entry.path).node === entry.node`.\n *\n * The walk stops when a string segment names a field that isn't the\n * current node's structural child array. Annotations live in\n * `markDefs` on a text block, alongside `children` rather than inside\n * it, so `getNode` resolves an annotation path to the enclosing text\n * block. Use `getAnnotation` to resolve the annotation itself.\n *\n * @public\n */\nexport function getNode(\n snapshot: TraversalSnapshot,\n path: Path,\n): {node: Node; path: Path} | undefined {\n const result = resolveNode(snapshot, path)\n return result.status === 'found' ? result.entry : undefined\n}\n\n/**\n * Result of walking a path against a snapshot.\n *\n * `unreachable` is the one outcome that means \"structurally impossible\n * by design\": the path digs past a sidecar field (e.g. `markDefs` on\n * a text block) into a keyed/indexed segment, which `getNode` can\n * never resolve (use `getAnnotation` for annotations). Every other\n * negative outcome is `missing`; on those branches a caller bug and a\n * benign race (the node removed by a concurrent edit) produce the\n * same state, so they cannot be told apart.\n */\nexport type ResolveNodeResult =\n | {status: 'found'; entry: {node: Node; path: Path}}\n | {status: 'missing'}\n | {status: 'unreachable'}\n\nexport function resolveNode(\n snapshot: TraversalSnapshot,\n path: Path,\n): ResolveNodeResult {\n if (path.length === 0) {\n return {status: 'missing'}\n }\n\n const {context, blockIndexMap} = snapshot\n let currentChildren: Array<Node> = context.value\n let currentFieldName: string | undefined\n let node: Node | undefined\n let currentParent: RegisteredContainer | undefined\n const resolvedPath: Path = []\n\n for (let i = 0; i < path.length; i++) {\n const segment = path[i]\n\n if (typeof segment === 'string') {\n // A string segment names a structural descent. If it matches the\n // field name produced by the previous node's `getNodeChildren`,\n // it's part of the value-tree descent — push it and continue.\n // Otherwise the string names a sidecar field (markDefs on a text\n // block, a primitive field on an object). If the input keeps\n // digging past it with more keyed/numeric segments, the caller\n // wanted a node inside the sidecar and `getNode` can't reach it\n // (use `getAnnotation` for annotations); report unreachable.\n // Otherwise the rest is just trailing field names — let the loop\n // exit and the post-loop strip remove them.\n if (currentFieldName !== undefined && segment === currentFieldName) {\n resolvedPath.push(segment)\n continue\n }\n for (let j = i + 1; j < path.length; j++) {\n const s = path[j]\n if (isKeyedSegment(s) || typeof s === 'number') {\n return {status: 'unreachable'}\n }\n }\n break\n }\n\n if (isKeyedSegment(segment)) {\n resolvedPath.push(segment)\n const index = blockIndexMap.get(serializePath(resolvedPath))\n if (\n index !== undefined &&\n currentChildren[index]?._key === segment._key\n ) {\n node = currentChildren[index]\n } else {\n // The map can miss (unkeyed transient nodes, e.g. `{_type:'table'}`\n // inserted by a remote patch before normalize mints a key) or\n // disagree with the traversed value (snapshots that pair the live\n // map with a pre-apply value, e.g. `textPatch`). Fall back to a\n // linear scan in both cases.\n node = currentChildren.find((child) => child._key === segment._key)\n if (node && node._key !== undefined) {\n resolvedPath[resolvedPath.length - 1] = {_key: node._key}\n }\n }\n } else if (typeof segment === 'number') {\n node = currentChildren.at(segment)\n if (node) {\n resolvedPath.push({_key: node._key})\n }\n } else {\n return {status: 'missing'}\n }\n\n if (!node) {\n return {status: 'missing'}\n }\n\n let hasMoreSegments = false\n for (let j = i + 1; j < path.length; j++) {\n const s = path[j]\n if (isKeyedSegment(s) || typeof s === 'number') {\n hasMoreSegments = true\n break\n }\n }\n\n if (hasMoreSegments) {\n const next = getNodeChildren(context, node, currentParent)\n\n if (!next) {\n return {status: 'missing'}\n }\n\n currentChildren = next.children\n currentFieldName = next.fieldName\n currentParent = next.parent\n } else {\n currentFieldName = undefined\n }\n }\n\n if (!node) {\n return {status: 'missing'}\n }\n\n // Strip trailing field-name segments. The walker may have pushed\n // matching field names during structural descent; if the deepest\n // reached keyed segment was the last keyed segment in the input,\n // any further field names that followed are part of the input but\n // don't identify the returned node.\n while (\n resolvedPath.length > 0 &&\n typeof resolvedPath[resolvedPath.length - 1] === 'string'\n ) {\n resolvedPath.pop()\n }\n\n return {status: 'found', entry: {node, path: resolvedPath}}\n}\n","import {isKeyedSegment} from '../../utils/util.is-keyed-segment'\nimport type {Path} from '../interfaces/path'\n\n/**\n * Get the parent path of a path.\n *\n * Drops the last node segment (keyed or numeric) and the preceding field\n * name string.\n *\n * [{_key:'b1'}, 'children', {_key:'s1'}] → [{_key:'b1'}]\n * [{_key:'b1'}, 'children', 0] → [{_key:'b1'}]\n * [{_key:'b1'}] → []\n */\nexport function parentPath(path: Path): Path {\n if (path.length === 0) {\n throw new Error(`Cannot get the parent path of the root path [${path}].`)\n }\n\n let lastNodeIndex = -1\n for (let i = path.length - 1; i >= 0; i--) {\n if (isKeyedSegment(path[i]) || typeof path[i] === 'number') {\n lastNodeIndex = i\n break\n }\n }\n\n if (lastNodeIndex === -1) {\n return []\n }\n\n const result = path.slice(0, lastNodeIndex)\n\n if (result.length > 0 && typeof result[result.length - 1] === 'string') {\n return result.slice(0, -1)\n }\n\n return result\n}\n","import type {PortableTextBlock} from '@portabletext/schema'\nimport type {Path} from '../engine/interfaces/path'\nimport {parentPath} from '../engine/path/parent-path'\nimport {getNode} from './get-node'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Get the parent of a node at a given path.\n *\n * A parent has children, so it is always a `PortableTextBlock` (text block\n * or object node).\n *\n * When `match` is provided and the parent does not satisfy it, returns\n * `undefined`.\n *\n * @public\n */\nexport function getParent<TMatch extends PortableTextBlock>(\n snapshot: TraversalSnapshot,\n path: Path,\n options: {\n match: (node: PortableTextBlock, path: Path) => node is TMatch\n },\n): {node: TMatch; path: Path} | undefined\n/**\n * @public\n */\nexport function getParent(\n snapshot: TraversalSnapshot,\n path: Path,\n options?: {\n match?: (node: PortableTextBlock, path: Path) => boolean\n },\n): {node: PortableTextBlock; path: Path} | undefined\nexport function getParent(\n snapshot: TraversalSnapshot,\n path: Path,\n options?: {\n match?: (node: PortableTextBlock, path: Path) => boolean\n },\n): {node: PortableTextBlock; path: Path} | undefined {\n if (path.length === 0) {\n return undefined\n }\n\n const parent = parentPath(path)\n\n if (parent.length === 0) {\n return undefined\n }\n\n const entry = getNode(snapshot, parent)\n\n if (!entry) {\n return undefined\n }\n\n const result = {node: entry.node as PortableTextBlock, path: entry.path}\n\n if (options?.match && !options.match(result.node, result.path)) {\n return undefined\n }\n\n return result\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as getChildren, d as isKeyedSegment, l as isTypedObject, n as parentPath, o as getNodeChildren, r as getNode, t as getParent, u as serializePath } from "./get-parent-DgaKcy8-.js";
|
|
2
2
|
import { getSubSchema } from "@portabletext/schema";
|
|
3
3
|
/**
|
|
4
4
|
* Get all ancestors of the node at a given path, from nearest to furthest.
|
|
@@ -510,4 +510,4 @@ function getPathSubSchema(snapshot, path) {
|
|
|
510
510
|
}
|
|
511
511
|
export { getAncestors as C, hasNode as S, comparePoints$1 as _, isInline as a, isEditableContainer as b, isSpanNode as c, resolveChildEntryIndex as d, isAncestorPath as f, isAfterPoint as g, isBackwardRange as h, getEnclosingBlock as i, getSibling as l, rangeEdges as m, getEnclosingContainer as n, getBlock as o, isTextBlockNode as p, comparePoints as r, isBlock as s, getPathSubSchema as t, getNodes as u, comparePaths as v, resolveContainerAt as x, isObject as y };
|
|
512
512
|
|
|
513
|
-
//# sourceMappingURL=get-path-sub-schema-
|
|
513
|
+
//# sourceMappingURL=get-path-sub-schema-Dd0QYZ0m.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-path-sub-schema-CZd9VcVM.js","names":[],"sources":["../src/traversal/get-ancestors.ts","../src/traversal/has-node.ts","../src/schema/resolve-container-at.ts","../src/schema/is-editable-container.ts","../src/traversal/is-object.ts","../src/engine/path/compare-paths.ts","../src/engine/point/compare-points.ts","../src/engine/point/is-after-point.ts","../src/engine/range/is-backward-range.ts","../src/engine/range/range-edges.ts","../src/engine/node/is-text-block-node.ts","../src/engine/path/is-ancestor-path.ts","../src/traversal/resolve-child-entry-index.ts","../src/traversal/get-nodes.ts","../src/traversal/get-sibling.ts","../src/engine/node/is-span-node.ts","../src/traversal/is-block.ts","../src/traversal/is-inline.ts","../src/traversal/get-enclosing-block.ts","../src/traversal/compare-points.ts","../src/schema/descend-to-parent.ts","../src/schema/get-enclosing-container.ts","../src/traversal/get-path-sub-schema.ts"],"sourcesContent":["import type {PortableTextBlock} from '@portabletext/schema'\nimport type {Node} from '../engine/interfaces/node'\nimport type {Path} from '../engine/interfaces/path'\nimport {serializePath} from '../paths/serialize-path'\nimport type {RegisteredContainer} from '../schema/resolve-containers'\nimport {isKeyedSegment} from '../utils/util.is-keyed-segment'\nimport {getNodeChildren} from './get-children'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Get all ancestors of the node at a given path, from nearest to furthest.\n *\n * For a path like [{_key:'t1'}, 'rows', {_key:'r1'}, 'cells', {_key:'c1'}],\n * the ancestors are (nearest first):\n * [{_key:'t1'}, 'rows', {_key:'r1'}]\n * [{_key:'t1'}]\n *\n * Walks from root to the target in a single pass collecting each ancestor\n * as it goes.\n *\n * Every ancestor is a `PortableTextBlock`: only text blocks and object\n * nodes can contain children.\n *\n * @public\n */\nexport function getAncestors(\n snapshot: TraversalSnapshot,\n path: Path,\n): Array<{node: PortableTextBlock; path: Path}> {\n // Collect keyed-segment indices to know where each ancestor's path ends.\n const keyedIndices: Array<number> = []\n for (let i = 0; i < path.length; i++) {\n if (isKeyedSegment(path[i])) {\n keyedIndices.push(i)\n }\n }\n\n // Need at least 2 keyed segments to have an ancestor (the last is self).\n if (keyedIndices.length <= 1) {\n return []\n }\n\n const {context, blockIndexMap} = snapshot\n let currentChildren: Array<Node> = context.value\n let currentParent: RegisteredContainer | undefined\n\n const ancestorsByDepth: Array<{node: PortableTextBlock; path: Path}> = []\n const resolvedPath: Path = []\n\n // Descend once. We walk only as far as the second-to-last keyed segment;\n // the last keyed segment is the target itself, which is not an ancestor.\n const targetKeyedIndex = keyedIndices[keyedIndices.length - 1]!\n\n let segmentIndex = 0\n while (segmentIndex < targetKeyedIndex) {\n const segment = path[segmentIndex]!\n\n if (typeof segment === 'string') {\n resolvedPath.push(segment)\n segmentIndex++\n continue\n }\n\n let node: Node | undefined\n if (isKeyedSegment(segment)) {\n resolvedPath.push(segment)\n const index = blockIndexMap.get(serializePath(resolvedPath))\n if (\n index !== undefined &&\n currentChildren[index]?._key === segment._key\n ) {\n node = currentChildren[index]\n } else {\n // The map can miss (unkeyed transient nodes, e.g. `{_type:'table'}`\n // inserted by a remote patch before normalize mints a key) or\n // disagree with the traversed value (snapshots that pair the live\n // map with a pre-apply value, e.g. `textPatch`). Fall back to a\n // linear scan in both cases.\n node = currentChildren.find((child) => child._key === segment._key)\n if (node && node._key !== undefined) {\n resolvedPath[resolvedPath.length - 1] = {_key: node._key}\n }\n }\n } else if (typeof segment === 'number') {\n node = currentChildren.at(segment)\n if (node) {\n resolvedPath.push({_key: node._key})\n }\n } else {\n return []\n }\n\n if (!node) {\n return []\n }\n\n // Descend with positional awareness. `getNodeChildren` checks the\n // current parent's `of` for a positional override before falling\n // back to the top-level `containers` map - so same-`_type`\n // registered under different parents with different `field`\n // resolves to the right entry at this position.\n const next = getNodeChildren(context, node, currentParent)\n if (!next) {\n return []\n }\n\n // An ancestor has children, so it is never a span. The narrowing\n // from `Node` to `PortableTextBlock` (text block | object) is safe.\n ancestorsByDepth.push({\n node: node as PortableTextBlock,\n path: resolvedPath.slice(),\n })\n\n currentChildren = next.children\n currentParent = next.parent\n segmentIndex++\n }\n\n // Return nearest-first (reverse of document order at the call site).\n return ancestorsByDepth.reverse()\n}\n","import type {Path} from '../engine/interfaces/path'\nimport {getNode} from './get-node'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Check if a node exists at a given path.\n *\n * @public\n */\nexport function hasNode(snapshot: TraversalSnapshot, path: Path): boolean {\n return getNode(snapshot, path) !== undefined\n}\n","import type {Node} from '../engine/interfaces/node'\nimport type {Path} from '../engine/interfaces/path'\nimport {isKeyedSegment} from '../utils/util.is-keyed-segment'\nimport type {\n Containers,\n RegisteredContainer,\n RegisteredPositional,\n} from './container-types'\n\n/**\n * Walk the editor value following `path` and return the\n * {@link RegisteredContainer} or {@link RegisteredPositional} that applies\n * at `path`'s target position.\n *\n * Resolution rules at each step:\n *\n * 1. **Positional override.** If the current parent declares the\n * child's `_type` in its `of`, the positional entry wins.\n * Used to resolve same-`_type` registered under different\n * parents with different `field` values.\n *\n * 2. **Global fallback.** If the parent has no positional override,\n * fall back to the top-level entry for `_type` in\n * `containers`.\n *\n * 3. **Chain validity.** If any ancestor along the path has no\n * resolved container entry (unregistered or not reachable as a\n * container at its position), return `undefined`.\n *\n * Returns `undefined` when the target's `_type` is not registered\n * at this position. Returns a {@link RegisteredPositional} when the target\n * resolves to a leaf in a positional `of` (terminal node with no\n * editable children).\n *\n * @alpha\n */\nexport function resolveContainerAt(\n containers: Containers,\n value: ReadonlyArray<Node>,\n path: Path,\n): RegisteredContainer | RegisteredPositional | undefined {\n const keyedIndices: Array<number> = []\n for (let index = 0; index < path.length; index++) {\n if (isKeyedSegment(path[index])) {\n keyedIndices.push(index)\n }\n }\n if (keyedIndices.length === 0) {\n return undefined\n }\n\n let currentChildren: ReadonlyArray<Node> = value\n let parent: RegisteredContainer | undefined\n let resolved: RegisteredContainer | RegisteredPositional | undefined\n const targetKeyedIndex = keyedIndices[keyedIndices.length - 1]!\n\n let segmentIndex = 0\n while (segmentIndex <= targetKeyedIndex) {\n const segment = path[segmentIndex]!\n if (typeof segment === 'string') {\n segmentIndex++\n continue\n }\n\n let node: Node | undefined\n if (isKeyedSegment(segment)) {\n node = currentChildren.find((child) => child._key === segment._key)\n } else if (typeof segment === 'number') {\n node = currentChildren.at(segment)\n } else {\n return undefined\n }\n if (!node) {\n return undefined\n }\n\n resolved = resolveNodeEntry(containers, parent, node)\n if (!resolved) {\n return undefined\n }\n\n if (segmentIndex < targetKeyedIndex) {\n // Walk one more level. The resolved entry must be a container\n // (have children) for descent to continue.\n if (!('field' in resolved)) {\n return undefined\n }\n const fieldValue = (node as Record<string, unknown>)[resolved.field.name]\n if (!Array.isArray(fieldValue)) {\n return undefined\n }\n parent = resolved\n currentChildren = fieldValue as Array<Node>\n }\n segmentIndex++\n }\n\n return resolved\n}\n\nfunction resolveNodeEntry(\n containers: Containers,\n parent: RegisteredContainer | undefined,\n node: Node,\n): RegisteredContainer | RegisteredPositional | undefined {\n if (parent?.of) {\n for (const entry of parent.of) {\n if (entry.type === node._type) {\n return entry\n }\n }\n }\n return containers.get(node._type)\n}\n","import type {Node} from '../engine/interfaces/node'\nimport type {Path} from '../engine/interfaces/path'\nimport type {TraversalSnapshot} from '../traversal/traversal-snapshot'\nimport {resolveContainerAt} from './resolve-container-at'\n\n/**\n * Check if a node at the given path is a registered editable container.\n *\n * Position-aware: {@link resolveContainerAt} descends from the editor\n * root threading the resolved parent at each step, so positionally-\n * registered containers (e.g. `cell` registered only inside\n * `table.of`) are recognized when reached through their declared\n * parent.\n */\nexport function isEditableContainer(\n snapshot: TraversalSnapshot,\n _node: Node,\n path: Path,\n): boolean {\n if (snapshot.context.containers.size === 0) {\n return false\n }\n\n // `resolveContainerAt` aborts on the first unregistered object-node\n // ancestor (chain validity falls out of the single descent), so the\n // single call below answers both \"is the node here a container?\" and\n // \"is the ancestor chain valid?\" in one walk.\n const resolved = resolveContainerAt(\n snapshot.context.containers,\n snapshot.context.value,\n path,\n )\n return !!(resolved && 'field' in resolved)\n}\n","import type {PortableTextObject} from '@portabletext/schema'\nimport {isTypedObject} from '../utils/asserters'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Check if a node is an object node (not a text block or span).\n *\n * @public\n */\nexport function isObject(\n snapshot: TraversalSnapshot,\n node: unknown,\n): node is PortableTextObject {\n return (\n isTypedObject(node) &&\n node._type !== snapshot.context.schema.block.name &&\n node._type !== snapshot.context.schema.span.name\n )\n}\n","import {isKeyedSegment} from '../../utils/util.is-keyed-segment'\nimport type {Node} from '../interfaces/node'\nimport type {Path} from '../interfaces/path'\n\n/**\n * Compare two paths in document order.\n *\n * When paths contain keyed segments, the root node tree is needed to\n * resolve document order. Without a root, keyed segments are compared\n * by _key string (consistent but not necessarily document order).\n */\nexport function comparePaths(\n path: Path,\n another: Path,\n root: {value: Array<Node>},\n): -1 | 0 | 1 {\n const min = Math.min(path.length, another.length)\n let currentChildren: Array<Node> | undefined = root?.value\n let currentNode: Node | undefined\n\n for (let i = 0; i < min; i++) {\n const segment = path[i]!\n const otherSegment = another[i]!\n\n if (isKeyedSegment(segment) && isKeyedSegment(otherSegment)) {\n if (segment._key === otherSegment._key) {\n if (currentChildren) {\n currentNode = currentChildren.find((c) => c._key === segment._key)\n currentChildren = undefined\n }\n continue\n }\n\n if (currentChildren) {\n const segmentIndex = currentChildren.findIndex(\n (c) => c._key === segment._key,\n )\n const otherSegmentIndex = currentChildren.findIndex(\n (c) => c._key === otherSegment._key,\n )\n if (segmentIndex !== -1 && otherSegmentIndex !== -1) {\n return segmentIndex < otherSegmentIndex ? -1 : 1\n }\n }\n\n // Fallback: compare by _key string\n if (segment._key < otherSegment._key) {\n return -1\n }\n if (segment._key > otherSegment._key) {\n return 1\n }\n continue\n }\n\n if (typeof segment === 'string' && typeof otherSegment === 'string') {\n if (segment === otherSegment) {\n if (currentNode) {\n const fieldValue = (currentNode as Record<string, unknown>)[segment]\n currentChildren = Array.isArray(fieldValue)\n ? (fieldValue as Array<Node>)\n : undefined\n currentNode = undefined\n }\n continue\n }\n if (segment < otherSegment) {\n return -1\n }\n if (segment > otherSegment) {\n return 1\n }\n continue\n }\n\n if (typeof segment === 'number' && typeof otherSegment === 'number') {\n if (segment < otherSegment) {\n return -1\n }\n if (segment > otherSegment) {\n return 1\n }\n continue\n }\n\n break\n }\n\n return 0\n}\n","import type {Node} from '../interfaces/node'\nimport type {Point} from '../interfaces/point'\nimport {comparePaths} from '../path/compare-paths'\n\nexport function comparePoints(\n point: Point,\n another: Point,\n root: {value: Array<Node>},\n): -1 | 0 | 1 {\n const result = comparePaths(point.path, another.path, root)\n if (result === 0) {\n if (point.offset < another.offset) {\n return -1\n }\n if (point.offset > another.offset) {\n return 1\n }\n return 0\n }\n return result\n}\n","import type {Node} from '../interfaces/node'\nimport type {Point} from '../interfaces/point'\nimport {comparePoints} from './compare-points'\n\nexport function isAfterPoint(\n point: Point,\n another: Point,\n root: {value: Array<Node>},\n): boolean {\n return comparePoints(point, another, root) === 1\n}\n","import type {Node} from '../interfaces/node'\nimport type {Range} from '../interfaces/range'\nimport {isAfterPoint} from '../point/is-after-point'\n\nexport function isBackwardRange(\n range: Range,\n root: {value: Array<Node>},\n): boolean {\n const {anchor, focus} = range\n return isAfterPoint(anchor, focus, root)\n}\n","import type {Node} from '../interfaces/node'\nimport type {Point} from '../interfaces/point'\nimport type {Range} from '../interfaces/range'\nimport {isBackwardRange} from './is-backward-range'\n\nexport function rangeEdges(\n range: Range,\n root: {value: Array<Node>},\n): [Point, Point] {\n const {anchor, focus} = range\n return isBackwardRange(range, root) ? [focus, anchor] : [anchor, focus]\n}\n","import type {PortableTextObject, PortableTextSpan} from '@portabletext/schema'\nimport type {EditorSchema} from '../../editor/editor-schema'\nimport {isTypedObject} from '../../utils/asserters'\n\ntype TextBlockNode = {\n _type: string\n _key: string\n children?: Array<PortableTextSpan | PortableTextObject>\n markDefs?: Array<PortableTextObject>\n style?: string\n listItem?: string\n level?: number\n}\n\n/**\n * Checks if a node is a text block based on `_type` alone, without requiring\n * `children` to be present. This is needed to identify text blocks before\n * normalization has had a chance to add the missing `children` property.\n */\nexport function isTextBlockNode(\n context: {schema: EditorSchema},\n node: unknown,\n): node is TextBlockNode {\n return isTypedObject(node) && node._type === context.schema.block.name\n}\n","import {isKeyedSegment} from '../../utils/util.is-keyed-segment'\nimport type {Path} from '../interfaces/path'\n\nexport function isAncestorPath(path: Path, another: Path): boolean {\n if (path.length >= another.length) {\n return false\n }\n\n for (let i = 0; i < path.length; i++) {\n const segment = path[i]\n const otherSegment = another[i]\n\n if (isKeyedSegment(segment) && isKeyedSegment(otherSegment)) {\n if (segment._key !== otherSegment._key) {\n return false\n }\n } else if (segment !== otherSegment) {\n return false\n }\n }\n\n return true\n}\n","import type {Node} from '../engine/interfaces/node'\nimport type {Path} from '../engine/interfaces/path'\nimport {serializePath} from '../paths/serialize-path'\nimport {isKeyedSegment} from '../utils/util.is-keyed-segment'\n\n/**\n * The index of the child addressed by `childPath`'s last segment within\n * `children` (entries as resolved by `getChildren`). Numeric last\n * segments are literal, bounds-checked indices. Keyed segments resolve\n * through `blockIndexMap` when the path is fully keyed (the map's id\n * space), verified against the entry at the mapped position, with a\n * linear scan fallback for misses, disagreements, and paths the map\n * cannot key, mirroring `getNode`/`getChildren`. Returns `-1` when the\n * child is not found.\n *\n * The map is taken explicitly rather than assumed current: some callers\n * deliberately resolve against pre-operation map state. The engine\n * keeps raw-array siblings of this helper (`resolveChildIndex` in\n * `apply-operation.ts`, `childIndexFromMap` in\n * `transform-block-index-map.ts`) for call sites that hold plain node\n * arrays mid-mutation, where no entries exist.\n */\nexport function resolveChildEntryIndex(\n blockIndexMap: ReadonlyMap<string, number>,\n children: ReadonlyArray<{node: Node; path: Path}>,\n childPath: Path,\n): number {\n const lastSegment = childPath[childPath.length - 1]\n\n if (typeof lastSegment === 'number') {\n return lastSegment >= 0 && lastSegment < children.length ? lastSegment : -1\n }\n\n if (!isKeyedSegment(lastSegment)) {\n return -1\n }\n\n let fullyKeyed = true\n for (\n let segmentIndex = 0;\n segmentIndex < childPath.length - 1;\n segmentIndex++\n ) {\n const segment = childPath[segmentIndex]\n if (typeof segment !== 'string' && !isKeyedSegment(segment)) {\n fullyKeyed = false\n break\n }\n }\n\n if (fullyKeyed) {\n const mappedIndex = blockIndexMap.get(serializePath(childPath))\n if (\n mappedIndex !== undefined &&\n children[mappedIndex]?.node._key === lastSegment._key\n ) {\n return mappedIndex\n }\n }\n\n return children.findIndex((child) => child.node._key === lastSegment._key)\n}\n","import type {EditorSchema} from '../editor/editor-schema'\nimport type {Node} from '../engine/interfaces/node'\nimport type {Path} from '../engine/interfaces/path'\nimport {isAncestorPath} from '../engine/path/is-ancestor-path'\nimport {serializePath} from '../paths/serialize-path'\nimport type {\n Containers,\n RegisteredContainer,\n} from '../schema/resolve-containers'\nimport {getChildren, getNodeChildren} from './get-children'\nimport {resolveChildEntryIndex} from './resolve-child-entry-index'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Get the descendant nodes of the node at a given path.\n *\n * When `from` and `to` are provided, performs a range-bounded DFS traversal,\n * yielding only nodes between `from` and `to` (inclusive). Both paths are\n * always in document order: `from` is the earlier path, `to` is the later\n * path. The `reverse` flag controls iteration direction within that range.\n *\n * When `match` is provided, only yields nodes where the predicate returns true.\n * The traversal still visits all nodes in range - `match` is a filter, not a\n * traversal control.\n *\n * When `at` is provided, traverses descendants of the node at that path\n * instead of the root.\n */\nexport function* getNodes(\n snapshot: TraversalSnapshot,\n options: {\n at?: Path\n from?: Path\n to?: Path\n match?: (node: Node, path: Path) => boolean\n reverse?: boolean\n } = {},\n): Generator<{node: Node; path: Path}, void, undefined> {\n const {at = [], from, to, match, reverse = false} = options\n\n if (from === undefined && to === undefined) {\n yield* getNodesSimple(snapshot, at, {match, reverse})\n return\n }\n\n yield* getNodesInRange(snapshot, at, {from, to, match, reverse})\n}\n\n/**\n * Get descendant nodes of a standalone node (not in the editor tree).\n * Used for cases like getDirtyPaths where the node hasn't been inserted yet.\n */\nexport function* getNodeDescendants(\n context: {\n schema: EditorSchema\n containers: Containers\n },\n node: Node | {value: Array<Node>},\n): Generator<{node: Node; path: Path}, void, undefined> {\n // The editor root wrapper ({value: [...]}) is not a real node, so its field\n // name is not part of paths. For standalone nodes (a real {_key, _type, ...}\n // passed in by callers like getDirtyPaths), the field name IS part of the\n // path.\n const isRoot = !('_key' in node) && !('_type' in node)\n yield* walkStandalone(context, node, [], isRoot)\n}\n\nfunction* walkStandalone(\n context: {\n schema: EditorSchema\n containers: Containers\n },\n node: Node | {value: Array<Node>},\n path: Path,\n isRoot: boolean,\n parent?: RegisteredContainer,\n): Generator<{node: Node; path: Path}, void, undefined> {\n const next = getNodeChildren(context, node, parent)\n if (!next) {\n return\n }\n\n for (const child of next.children) {\n const childPath: Path = isRoot\n ? [{_key: child._key}]\n : [...path, next.fieldName, {_key: child._key}]\n yield {node: child, path: childPath}\n yield* walkStandalone(context, child, childPath, false, next.parent)\n }\n}\n\n/**\n * Simple recursive DFS - the original behavior.\n * Yields all descendants of the node at `path`.\n */\nfunction* getNodesSimple(\n snapshot: TraversalSnapshot,\n path: Path,\n options: {\n match?: (node: Node, path: Path) => boolean\n reverse?: boolean\n },\n): Generator<{node: Node; path: Path}, void, undefined> {\n const {match, reverse = false} = options\n\n const children = getChildren(snapshot, path)\n\n const entries = reverse ? [...children].reverse() : children\n\n for (const entry of entries) {\n if (!match || match(entry.node, entry.path)) {\n yield entry\n }\n\n yield* getNodesSimple(snapshot, entry.path, options)\n }\n}\n\n/**\n * Compare two keyed paths in DFS pre-order. Returns -1, 0, or 1.\n *\n * Walks both paths in parallel; at the first divergence, consults\n * `blockIndexMap` for the sibling indices and compares them.\n *\n * Deliberately not `comparePaths` (`engine/path/compare-paths.ts`):\n * that compare treats an ancestor/descendant pair as equal (0), while\n * range traversal needs the ancestor ordered first (-1/1), it is what\n * excludes `to`'s descendants from a range. The two compares answer\n * different questions and must not be merged.\n */\nfunction comparePathsInTree(\n snapshot: TraversalSnapshot,\n pathA: Path,\n pathB: Path,\n): -1 | 0 | 1 {\n // Walk both full paths in parallel; at the first divergent keyed\n // segment, consult blockIndexMap for the sibling indices. The map is\n // keyed by serialized paths that include both keyed and field-name\n // segments, so we keep the full path prefix as we descend.\n const minLength = Math.min(pathA.length, pathB.length)\n const prefix: Path = []\n\n for (let i = 0; i < minLength; i++) {\n const segA = pathA[i]!\n const segB = pathB[i]!\n\n if (\n typeof segA === 'string' ||\n typeof segB === 'string' ||\n typeof segA === 'number' ||\n typeof segB === 'number' ||\n Array.isArray(segA) ||\n Array.isArray(segB)\n ) {\n prefix.push(segA as never)\n continue\n }\n\n if (segA._key === segB._key) {\n prefix.push(segA)\n continue\n }\n\n const indexA =\n snapshot.blockIndexMap.get(serializePath([...prefix, segA])) ?? -1\n const indexB =\n snapshot.blockIndexMap.get(serializePath([...prefix, segB])) ?? -1\n if (indexA < indexB) {\n return -1\n }\n if (indexA > indexB) {\n return 1\n }\n return 0\n }\n\n // One path is a prefix of the other (ancestor relationship).\n // In DFS order, shorter path (ancestor) comes first.\n if (pathA.length < pathB.length) {\n return -1\n }\n if (pathA.length > pathB.length) {\n return 1\n }\n\n return 0\n}\n\n/**\n * Range-bounded recursive DFS traversal.\n *\n * `from` and `to` are always in document order (from is earlier, to is\n * later), regardless of traversal direction.\n */\nfunction* getNodesInRange(\n snapshot: TraversalSnapshot,\n path: Path,\n options: {\n from?: Path\n to?: Path\n match?: (node: Node, path: Path) => boolean\n reverse?: boolean\n },\n): Generator<{node: Node; path: Path}, void, undefined> {\n const {from, to, match, reverse = false} = options\n\n const children = getChildren(snapshot, path)\n\n // Seek instead of scan: only the children between the boundaries'\n // branches at this level can intersect [from, to], so resolve those\n // positions (O(1) through `blockIndexMap`) and iterate the window\n // between them. The per-entry checks below stay the semantic source\n // of truth; an unresolvable boundary just leaves its side of the\n // window open, degrading to the previous full scan.\n const startIndex =\n from === undefined ? 0 : (boundaryChildIndex(snapshot, children, from) ?? 0)\n const endIndex =\n to === undefined\n ? children.length - 1\n : (boundaryChildIndex(snapshot, children, to) ?? children.length - 1)\n const window = children.slice(startIndex, endIndex + 1)\n const entries = reverse ? window.reverse() : window\n\n for (const entry of entries) {\n if (canStopTraversal(snapshot, entry.path, from, to, reverse)) {\n return\n }\n\n if (!couldContainInRangeNodes(snapshot, entry.path, from, to)) {\n continue\n }\n\n if (isInRange(snapshot, entry.path, from, to)) {\n if (!match || match(entry.node, entry.path)) {\n yield entry\n }\n }\n\n yield* getNodesInRange(snapshot, entry.path, options)\n }\n}\n\n/**\n * The index of the child whose subtree `boundary` passes through, at\n * the level `children` was resolved for. `undefined` when the boundary\n * does not pass through this level or cannot be resolved, in which\n * case the caller must not narrow the window on that side.\n */\nfunction boundaryChildIndex(\n snapshot: TraversalSnapshot,\n children: Array<{node: Node; path: Path}>,\n boundary: Path,\n): number | undefined {\n const firstChild = children[0]\n if (!firstChild) {\n return undefined\n }\n const childPathLength = firstChild.path.length\n if (boundary.length < childPathLength) {\n return undefined\n }\n\n // The children share every path segment but the last; the boundary\n // passes through this level only when that shared prefix is an\n // ancestor of it.\n const sharedPrefix = firstChild.path.slice(0, -1)\n if (sharedPrefix.length > 0 && !isAncestorPath(sharedPrefix, boundary)) {\n return undefined\n }\n\n const resolvedIndex = resolveChildEntryIndex(\n snapshot.blockIndexMap,\n children,\n boundary.slice(0, childPathLength),\n )\n return resolvedIndex === -1 ? undefined : resolvedIndex\n}\n\n/**\n * Check if a node is within the [from, to] range in document order.\n * Both bounds are inclusive. Ancestor nodes of from or to are also\n * considered in range since they contain the range boundary.\n */\nfunction isInRange(\n snapshot: TraversalSnapshot,\n nodePath: Path,\n from: Path | undefined,\n to: Path | undefined,\n): boolean {\n if (\n from !== undefined &&\n comparePathsInTree(snapshot, nodePath, from) === -1\n ) {\n if (!isAncestorPath(nodePath, from)) {\n return false\n }\n }\n\n if (to !== undefined && comparePathsInTree(snapshot, nodePath, to) === 1) {\n if (!isAncestorPath(nodePath, to)) {\n return false\n }\n }\n\n return true\n}\n\n/**\n * Check if a subtree rooted at `nodePath` could contain any nodes in the\n * [from, to] range.\n */\nfunction couldContainInRangeNodes(\n snapshot: TraversalSnapshot,\n nodePath: Path,\n from: Path | undefined,\n to: Path | undefined,\n): boolean {\n if (isInRange(snapshot, nodePath, from, to)) {\n return true\n }\n\n if (from !== undefined && isAncestorPath(nodePath, from)) {\n return true\n }\n\n if (to !== undefined && isAncestorPath(nodePath, to)) {\n return true\n }\n\n return false\n}\n\n/**\n * Check if all remaining nodes in iteration order will be outside the range.\n */\nfunction canStopTraversal(\n snapshot: TraversalSnapshot,\n nodePath: Path,\n from: Path | undefined,\n to: Path | undefined,\n reverse: boolean,\n): boolean {\n if (reverse) {\n if (from === undefined) {\n return false\n }\n\n return (\n comparePathsInTree(snapshot, nodePath, from) === -1 &&\n !isAncestorPath(nodePath, from)\n )\n }\n\n if (to === undefined) {\n return false\n }\n\n return comparePathsInTree(snapshot, nodePath, to) === 1\n}\n","import type {Node} from '../engine/interfaces/node'\nimport type {Path} from '../engine/interfaces/path'\nimport {parentPath} from '../engine/path/parent-path'\nimport {getChildren} from './get-children'\nimport {resolveChildEntryIndex} from './resolve-child-entry-index'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Get a sibling of the node at a given path.\n *\n * Without `match`, returns the immediate next or previous sibling.\n * With `match`, returns the first sibling in `direction` that satisfies\n * the predicate.\n *\n * When `match` is a type predicate, the returned `node` narrows to that type.\n *\n * @public\n */\nexport function getSibling<TMatch extends Node>(\n snapshot: TraversalSnapshot,\n path: Path,\n options: {\n direction: 'next' | 'previous'\n match: (node: Node, path: Path) => node is TMatch\n },\n): {node: TMatch; path: Path} | undefined\n/**\n * @public\n */\nexport function getSibling(\n snapshot: TraversalSnapshot,\n path: Path,\n options: {\n direction: 'next' | 'previous'\n match?: (node: Node, path: Path) => boolean\n },\n): {node: Node; path: Path} | undefined\nexport function getSibling(\n snapshot: TraversalSnapshot,\n path: Path,\n options: {\n direction: 'next' | 'previous'\n match?: (node: Node, path: Path) => boolean\n },\n): {node: Node; path: Path} | undefined {\n const {direction, match} = options\n\n if (path.length === 0) {\n return undefined\n }\n\n const parent = parentPath(path)\n const children = getChildren(snapshot, parent)\n\n const currentIndex = resolveChildEntryIndex(\n snapshot.blockIndexMap,\n children,\n path,\n )\n\n if (currentIndex === -1) {\n return undefined\n }\n\n if (!match) {\n const siblingIndex =\n direction === 'next' ? currentIndex + 1 : currentIndex - 1\n\n if (siblingIndex < 0 || siblingIndex >= children.length) {\n return undefined\n }\n\n return children[siblingIndex]\n }\n\n const candidates =\n direction === 'next'\n ? children.slice(currentIndex + 1)\n : children.slice(0, currentIndex).reverse()\n\n return candidates.find((child) => match(child.node, child.path))\n}\n","import type {EditorSchema} from '../../editor/editor-schema'\nimport {isTypedObject} from '../../utils/asserters'\n\nexport type SpanNode = {\n _type: string\n _key: string\n text?: string\n marks?: Array<string>\n}\n\n/**\n * Checks if a node is a span based on `_type` alone, without requiring `text`\n * to be present. This is needed to identify spans before normalization has had\n * a chance to add the missing `text` property.\n */\nexport function isSpanNode(\n context: {schema: EditorSchema},\n node: unknown,\n): node is SpanNode {\n return isTypedObject(node) && node._type === context.schema.span.name\n}\n","import type {PortableTextBlock} from '@portabletext/schema'\nimport type {Path} from '../engine/interfaces/path'\nimport {isSpanNode} from '../engine/node/is-span-node'\nimport {isTextBlockNode} from '../engine/node/is-text-block-node'\nimport {getNode} from './get-node'\nimport {getParent} from './get-parent'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Determine if a node at the given path is a block.\n *\n * A node is a block if its parent is not a text block. Top-level nodes\n * (direct children of the editor) are always blocks. Children of text blocks\n * (spans and inline objects) are not blocks. Children of containers are\n * blocks within that container.\n *\n * @public\n */\nexport function isBlock(snapshot: TraversalSnapshot, path: Path): boolean {\n const parent = getParent(snapshot, path)\n\n if (!parent) {\n return true\n }\n\n return !isTextBlockNode({schema: snapshot.context.schema}, parent.node)\n}\n\n/**\n * Get the node at the given path if it is a block.\n *\n * Returns the node narrowed to PortableTextBlock, or undefined if the node\n * doesn't exist or is not a block.\n *\n * @public\n */\nexport function getBlock(\n snapshot: TraversalSnapshot,\n path: Path,\n): {node: PortableTextBlock; path: Path} | undefined {\n const entry = getNode(snapshot, path)\n\n if (!entry) {\n return undefined\n }\n\n if (!isBlock(snapshot, path)) {\n return undefined\n }\n\n if (isSpanNode({schema: snapshot.context.schema}, entry.node)) {\n return undefined\n }\n\n return {node: entry.node, path: entry.path}\n}\n","import type {Path} from '../engine/interfaces/path'\nimport {isBlock} from './is-block'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Determine if a node at the given path is inline.\n *\n * A node is inline if its parent is a text block. This is the inverse of\n * `isBlock`. Top-level nodes are never inline.\n *\n * @public\n */\nexport function isInline(snapshot: TraversalSnapshot, path: Path): boolean {\n return !isBlock(snapshot, path)\n}\n","import type {PortableTextBlock} from '@portabletext/schema'\nimport type {Path} from '../engine/interfaces/path'\nimport {getAncestors} from './get-ancestors'\nimport {getBlock} from './is-block'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Walk up from a path to find the nearest enclosing block.\n *\n * Returns the node at the path if it is a block, otherwise the first ancestor\n * that is a block. Works at any depth — inside a container this returns the\n * container-internal block, not the outer container.\n *\n * With `match`, returns the first enclosing block that also satisfies the\n * predicate. When `match` is a type predicate, the returned `node` narrows\n * to that type.\n *\n * `mode: 'lowest'` (default) returns the innermost enclosing block; the node\n * at the path itself counts. `mode: 'highest'` returns the outermost\n * ancestor that matches, falling back to the node at the path only if no\n * ancestor does.\n *\n * @public\n */\nexport function getEnclosingBlock<TMatch extends PortableTextBlock>(\n snapshot: TraversalSnapshot,\n path: Path,\n options: {\n match: (node: PortableTextBlock, path: Path) => node is TMatch\n mode?: 'lowest' | 'highest'\n },\n): {node: TMatch; path: Path} | undefined\n/**\n * @public\n */\nexport function getEnclosingBlock(\n snapshot: TraversalSnapshot,\n path: Path,\n options?: {\n match?: (node: PortableTextBlock, path: Path) => boolean\n mode?: 'lowest' | 'highest'\n },\n): {node: PortableTextBlock; path: Path} | undefined\nexport function getEnclosingBlock(\n snapshot: TraversalSnapshot,\n path: Path,\n options?: {\n match?: (node: PortableTextBlock, path: Path) => boolean\n mode?: 'lowest' | 'highest'\n },\n): {node: PortableTextBlock; path: Path} | undefined {\n const match = options?.match\n const mode = options?.mode ?? 'lowest'\n\n if (mode === 'highest') {\n const ancestors = getAncestors(snapshot, path)\n\n for (const ancestor of [...ancestors].reverse()) {\n if (!match || match(ancestor.node, ancestor.path)) {\n return ancestor\n }\n }\n\n const direct = getBlock(snapshot, path)\n\n if (direct && (!match || match(direct.node, direct.path))) {\n return direct\n }\n\n return undefined\n }\n\n const direct = getBlock(snapshot, path)\n\n if (direct && (!match || match(direct.node, direct.path))) {\n return direct\n }\n\n for (const ancestor of getAncestors(snapshot, path)) {\n if (!match || match(ancestor.node, ancestor.path)) {\n return ancestor\n }\n }\n\n return undefined\n}\n","import {comparePaths} from '../engine/path/compare-paths'\nimport type {EditorSelectionPoint} from '../types/editor'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Returns:\n *\n * - `-1` if `pointA` is before `pointB`\n * - `0` if `pointA` and `pointB` are equal\n * - `1` if `pointA` is after `pointB`.\n *\n * Compares the two points by document order, resolved at any depth. When\n * the paths are equal, compares offsets.\n *\n * @public\n */\nexport function comparePoints(\n snapshot: TraversalSnapshot,\n pointA: EditorSelectionPoint,\n pointB: EditorSelectionPoint,\n): -1 | 0 | 1 {\n const pathComparison = comparePaths(pointA.path, pointB.path, {\n value: snapshot.context.value,\n })\n\n if (pathComparison !== 0) {\n return pathComparison\n }\n\n if (pointA.offset < pointB.offset) {\n return -1\n }\n\n if (pointA.offset > pointB.offset) {\n return 1\n }\n\n return 0\n}\n","import type {Path} from '../engine/interfaces/path'\nimport {getAncestors} from '../traversal/get-ancestors'\nimport {isObject} from '../traversal/is-object'\nimport type {TraversalSnapshot} from '../traversal/traversal-snapshot'\nimport type {RegisteredContainer} from './container-types'\nimport {resolveContainerAt} from './resolve-container-at'\n\n/**\n * Descent primitive: return the immediate parent\n * {@link RegisteredContainer} of the node at `path` (and that parent's\n * path), or `undefined` when the target's immediate parent is the\n * editor root, when no object-node ancestor is a registered container,\n * or when descent hits an ancestor whose `_type` is not registered.\n *\n * Walks ancestors and resolves each object-node ancestor positionally\n * via {@link resolveContainerAt}. Text-block and span ancestors are\n * skipped - \"container\" here means the enclosing object container,\n * not the text-block holding spans.\n */\nexport function descendToParent(\n snapshot: TraversalSnapshot,\n path: Path,\n): {parent: RegisteredContainer; parentPath: Path} | undefined {\n const ancestors = getAncestors(snapshot, path)\n for (const ancestor of ancestors) {\n if (!isObject(snapshot, ancestor.node)) {\n continue\n }\n const resolved = resolveContainerAt(\n snapshot.context.containers,\n snapshot.context.value,\n ancestor.path,\n )\n if (!resolved || !('field' in resolved)) {\n return undefined\n }\n return {parent: resolved, parentPath: ancestor.path}\n }\n return undefined\n}\n","import type {OfDefinition} from '@portabletext/schema'\nimport type {Path} from '../engine/interfaces/path'\nimport type {TraversalSnapshot} from '../traversal/traversal-snapshot'\nimport {descendToParent} from './descend-to-parent'\n\n/**\n * Return the immediate registered-container ancestor of `path` along\n * with its `of` array (the schema definitions accepted at this position).\n *\n * Position-aware: nested-only registrations (e.g. `cell` registered\n * only inside `table.row.of`) are recognized via the same descent\n * primitive used by all parent-aware traversal.\n *\n * Returns `undefined` when `path` has no registered-container ancestor\n * (i.e. is at the document root) or when descent hits a leaf-resolved\n * ancestor.\n */\nexport function getEnclosingContainer(\n snapshot: TraversalSnapshot,\n path: Path,\n):\n | {\n of: ReadonlyArray<OfDefinition>\n path: Path\n }\n | undefined {\n const descent = descendToParent(snapshot, path)\n if (!descent) {\n return undefined\n }\n return {\n of: descent.parent.field.of,\n path: descent.parentPath,\n }\n}\n","import {getSubSchema, type Schema} from '@portabletext/schema'\nimport type {Path} from '../engine/interfaces/path'\nimport {getEnclosingContainer} from '../schema/get-enclosing-container'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Return the `Schema` view that applies at a given path.\n *\n * For paths at the root of the document, or for paths where no ancestor is\n * a registered container, returns the top-level schema. For paths inside a\n * container, walks ancestors to find the nearest container and returns the\n * sub-schema derived from its `of` declaration.\n *\n * @public\n */\nexport function getPathSubSchema(\n snapshot: TraversalSnapshot,\n path: Path,\n): Schema {\n const enclosing = getEnclosingContainer(snapshot, path)\n\n if (!enclosing) {\n return snapshot.context.schema\n }\n\n return getSubSchema(snapshot.context.schema, enclosing.of)\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"get-path-sub-schema-Dd0QYZ0m.js","names":[],"sources":["../src/traversal/get-ancestors.ts","../src/traversal/has-node.ts","../src/schema/resolve-container-at.ts","../src/schema/is-editable-container.ts","../src/traversal/is-object.ts","../src/engine/path/compare-paths.ts","../src/engine/point/compare-points.ts","../src/engine/point/is-after-point.ts","../src/engine/range/is-backward-range.ts","../src/engine/range/range-edges.ts","../src/engine/node/is-text-block-node.ts","../src/engine/path/is-ancestor-path.ts","../src/traversal/resolve-child-entry-index.ts","../src/traversal/get-nodes.ts","../src/traversal/get-sibling.ts","../src/engine/node/is-span-node.ts","../src/traversal/is-block.ts","../src/traversal/is-inline.ts","../src/traversal/get-enclosing-block.ts","../src/traversal/compare-points.ts","../src/schema/descend-to-parent.ts","../src/schema/get-enclosing-container.ts","../src/traversal/get-path-sub-schema.ts"],"sourcesContent":["import type {PortableTextBlock} from '@portabletext/schema'\nimport type {Node} from '../engine/interfaces/node'\nimport type {Path} from '../engine/interfaces/path'\nimport {serializePath} from '../paths/serialize-path'\nimport type {RegisteredContainer} from '../schema/resolve-containers'\nimport {isKeyedSegment} from '../utils/util.is-keyed-segment'\nimport {getNodeChildren} from './get-children'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Get all ancestors of the node at a given path, from nearest to furthest.\n *\n * For a path like [{_key:'t1'}, 'rows', {_key:'r1'}, 'cells', {_key:'c1'}],\n * the ancestors are (nearest first):\n * [{_key:'t1'}, 'rows', {_key:'r1'}]\n * [{_key:'t1'}]\n *\n * Walks from root to the target in a single pass collecting each ancestor\n * as it goes.\n *\n * Every ancestor is a `PortableTextBlock`: only text blocks and object\n * nodes can contain children.\n *\n * @public\n */\nexport function getAncestors(\n snapshot: TraversalSnapshot,\n path: Path,\n): Array<{node: PortableTextBlock; path: Path}> {\n // Collect keyed-segment indices to know where each ancestor's path ends.\n const keyedIndices: Array<number> = []\n for (let i = 0; i < path.length; i++) {\n if (isKeyedSegment(path[i])) {\n keyedIndices.push(i)\n }\n }\n\n // Need at least 2 keyed segments to have an ancestor (the last is self).\n if (keyedIndices.length <= 1) {\n return []\n }\n\n const {context, blockIndexMap} = snapshot\n let currentChildren: Array<Node> = context.value\n let currentParent: RegisteredContainer | undefined\n\n const ancestorsByDepth: Array<{node: PortableTextBlock; path: Path}> = []\n const resolvedPath: Path = []\n\n // Descend once. We walk only as far as the second-to-last keyed segment;\n // the last keyed segment is the target itself, which is not an ancestor.\n const targetKeyedIndex = keyedIndices[keyedIndices.length - 1]!\n\n let segmentIndex = 0\n while (segmentIndex < targetKeyedIndex) {\n const segment = path[segmentIndex]!\n\n if (typeof segment === 'string') {\n resolvedPath.push(segment)\n segmentIndex++\n continue\n }\n\n let node: Node | undefined\n if (isKeyedSegment(segment)) {\n resolvedPath.push(segment)\n const index = blockIndexMap.get(serializePath(resolvedPath))\n if (\n index !== undefined &&\n currentChildren[index]?._key === segment._key\n ) {\n node = currentChildren[index]\n } else {\n // The map can miss (unkeyed transient nodes, e.g. `{_type:'table'}`\n // inserted by a remote patch before normalize mints a key) or\n // disagree with the traversed value (snapshots that pair the live\n // map with a pre-apply value, e.g. `textPatch`). Fall back to a\n // linear scan in both cases.\n node = currentChildren.find((child) => child._key === segment._key)\n if (node && node._key !== undefined) {\n resolvedPath[resolvedPath.length - 1] = {_key: node._key}\n }\n }\n } else if (typeof segment === 'number') {\n node = currentChildren.at(segment)\n if (node) {\n resolvedPath.push({_key: node._key})\n }\n } else {\n return []\n }\n\n if (!node) {\n return []\n }\n\n // Descend with positional awareness. `getNodeChildren` checks the\n // current parent's `of` for a positional override before falling\n // back to the top-level `containers` map - so same-`_type`\n // registered under different parents with different `field`\n // resolves to the right entry at this position.\n const next = getNodeChildren(context, node, currentParent)\n if (!next) {\n return []\n }\n\n // An ancestor has children, so it is never a span. The narrowing\n // from `Node` to `PortableTextBlock` (text block | object) is safe.\n ancestorsByDepth.push({\n node: node as PortableTextBlock,\n path: resolvedPath.slice(),\n })\n\n currentChildren = next.children\n currentParent = next.parent\n segmentIndex++\n }\n\n // Return nearest-first (reverse of document order at the call site).\n return ancestorsByDepth.reverse()\n}\n","import type {Path} from '../engine/interfaces/path'\nimport {getNode} from './get-node'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Check if a node exists at a given path.\n *\n * @public\n */\nexport function hasNode(snapshot: TraversalSnapshot, path: Path): boolean {\n return getNode(snapshot, path) !== undefined\n}\n","import type {Node} from '../engine/interfaces/node'\nimport type {Path} from '../engine/interfaces/path'\nimport {isKeyedSegment} from '../utils/util.is-keyed-segment'\nimport type {\n Containers,\n RegisteredContainer,\n RegisteredPositional,\n} from './container-types'\n\n/**\n * Walk the editor value following `path` and return the\n * {@link RegisteredContainer} or {@link RegisteredPositional} that applies\n * at `path`'s target position.\n *\n * Resolution rules at each step:\n *\n * 1. **Positional override.** If the current parent declares the\n * child's `_type` in its `of`, the positional entry wins.\n * Used to resolve same-`_type` registered under different\n * parents with different `field` values.\n *\n * 2. **Global fallback.** If the parent has no positional override,\n * fall back to the top-level entry for `_type` in\n * `containers`.\n *\n * 3. **Chain validity.** If any ancestor along the path has no\n * resolved container entry (unregistered or not reachable as a\n * container at its position), return `undefined`.\n *\n * Returns `undefined` when the target's `_type` is not registered\n * at this position. Returns a {@link RegisteredPositional} when the target\n * resolves to a leaf in a positional `of` (terminal node with no\n * editable children).\n *\n * @alpha\n */\nexport function resolveContainerAt(\n containers: Containers,\n value: ReadonlyArray<Node>,\n path: Path,\n): RegisteredContainer | RegisteredPositional | undefined {\n const keyedIndices: Array<number> = []\n for (let index = 0; index < path.length; index++) {\n if (isKeyedSegment(path[index])) {\n keyedIndices.push(index)\n }\n }\n if (keyedIndices.length === 0) {\n return undefined\n }\n\n let currentChildren: ReadonlyArray<Node> = value\n let parent: RegisteredContainer | undefined\n let resolved: RegisteredContainer | RegisteredPositional | undefined\n const targetKeyedIndex = keyedIndices[keyedIndices.length - 1]!\n\n let segmentIndex = 0\n while (segmentIndex <= targetKeyedIndex) {\n const segment = path[segmentIndex]!\n if (typeof segment === 'string') {\n segmentIndex++\n continue\n }\n\n let node: Node | undefined\n if (isKeyedSegment(segment)) {\n node = currentChildren.find((child) => child._key === segment._key)\n } else if (typeof segment === 'number') {\n node = currentChildren.at(segment)\n } else {\n return undefined\n }\n if (!node) {\n return undefined\n }\n\n resolved = resolveNodeEntry(containers, parent, node)\n if (!resolved) {\n return undefined\n }\n\n if (segmentIndex < targetKeyedIndex) {\n // Walk one more level. The resolved entry must be a container\n // (have children) for descent to continue.\n if (!('field' in resolved)) {\n return undefined\n }\n const fieldValue = (node as Record<string, unknown>)[resolved.field.name]\n if (!Array.isArray(fieldValue)) {\n return undefined\n }\n parent = resolved\n currentChildren = fieldValue as Array<Node>\n }\n segmentIndex++\n }\n\n return resolved\n}\n\nfunction resolveNodeEntry(\n containers: Containers,\n parent: RegisteredContainer | undefined,\n node: Node,\n): RegisteredContainer | RegisteredPositional | undefined {\n if (parent?.of) {\n for (const entry of parent.of) {\n if (entry.type === node._type) {\n return entry\n }\n }\n }\n return containers.get(node._type)\n}\n","import type {Node} from '../engine/interfaces/node'\nimport type {Path} from '../engine/interfaces/path'\nimport type {TraversalSnapshot} from '../traversal/traversal-snapshot'\nimport {resolveContainerAt} from './resolve-container-at'\n\n/**\n * Check if a node at the given path is a registered editable container.\n *\n * Position-aware: {@link resolveContainerAt} descends from the editor\n * root threading the resolved parent at each step, so positionally-\n * registered containers (e.g. `cell` registered only inside\n * `table.of`) are recognized when reached through their declared\n * parent.\n */\nexport function isEditableContainer(\n snapshot: TraversalSnapshot,\n _node: Node,\n path: Path,\n): boolean {\n if (snapshot.context.containers.size === 0) {\n return false\n }\n\n // `resolveContainerAt` aborts on the first unregistered object-node\n // ancestor (chain validity falls out of the single descent), so the\n // single call below answers both \"is the node here a container?\" and\n // \"is the ancestor chain valid?\" in one walk.\n const resolved = resolveContainerAt(\n snapshot.context.containers,\n snapshot.context.value,\n path,\n )\n return !!(resolved && 'field' in resolved)\n}\n","import type {PortableTextObject} from '@portabletext/schema'\nimport {isTypedObject} from '../utils/asserters'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Check if a node is an object node (not a text block or span).\n *\n * @public\n */\nexport function isObject(\n snapshot: TraversalSnapshot,\n node: unknown,\n): node is PortableTextObject {\n return (\n isTypedObject(node) &&\n node._type !== snapshot.context.schema.block.name &&\n node._type !== snapshot.context.schema.span.name\n )\n}\n","import {isKeyedSegment} from '../../utils/util.is-keyed-segment'\nimport type {Node} from '../interfaces/node'\nimport type {Path} from '../interfaces/path'\n\n/**\n * Compare two paths in document order.\n *\n * When paths contain keyed segments, the root node tree is needed to\n * resolve document order. Without a root, keyed segments are compared\n * by _key string (consistent but not necessarily document order).\n */\nexport function comparePaths(\n path: Path,\n another: Path,\n root: {value: Array<Node>},\n): -1 | 0 | 1 {\n const min = Math.min(path.length, another.length)\n let currentChildren: Array<Node> | undefined = root?.value\n let currentNode: Node | undefined\n\n for (let i = 0; i < min; i++) {\n const segment = path[i]!\n const otherSegment = another[i]!\n\n if (isKeyedSegment(segment) && isKeyedSegment(otherSegment)) {\n if (segment._key === otherSegment._key) {\n if (currentChildren) {\n currentNode = currentChildren.find((c) => c._key === segment._key)\n currentChildren = undefined\n }\n continue\n }\n\n if (currentChildren) {\n const segmentIndex = currentChildren.findIndex(\n (c) => c._key === segment._key,\n )\n const otherSegmentIndex = currentChildren.findIndex(\n (c) => c._key === otherSegment._key,\n )\n if (segmentIndex !== -1 && otherSegmentIndex !== -1) {\n return segmentIndex < otherSegmentIndex ? -1 : 1\n }\n }\n\n // Fallback: compare by _key string\n if (segment._key < otherSegment._key) {\n return -1\n }\n if (segment._key > otherSegment._key) {\n return 1\n }\n continue\n }\n\n if (typeof segment === 'string' && typeof otherSegment === 'string') {\n if (segment === otherSegment) {\n if (currentNode) {\n const fieldValue = (currentNode as Record<string, unknown>)[segment]\n currentChildren = Array.isArray(fieldValue)\n ? (fieldValue as Array<Node>)\n : undefined\n currentNode = undefined\n }\n continue\n }\n if (segment < otherSegment) {\n return -1\n }\n if (segment > otherSegment) {\n return 1\n }\n continue\n }\n\n if (typeof segment === 'number' && typeof otherSegment === 'number') {\n if (segment < otherSegment) {\n return -1\n }\n if (segment > otherSegment) {\n return 1\n }\n continue\n }\n\n break\n }\n\n return 0\n}\n","import type {Node} from '../interfaces/node'\nimport type {Point} from '../interfaces/point'\nimport {comparePaths} from '../path/compare-paths'\n\nexport function comparePoints(\n point: Point,\n another: Point,\n root: {value: Array<Node>},\n): -1 | 0 | 1 {\n const result = comparePaths(point.path, another.path, root)\n if (result === 0) {\n if (point.offset < another.offset) {\n return -1\n }\n if (point.offset > another.offset) {\n return 1\n }\n return 0\n }\n return result\n}\n","import type {Node} from '../interfaces/node'\nimport type {Point} from '../interfaces/point'\nimport {comparePoints} from './compare-points'\n\nexport function isAfterPoint(\n point: Point,\n another: Point,\n root: {value: Array<Node>},\n): boolean {\n return comparePoints(point, another, root) === 1\n}\n","import type {Node} from '../interfaces/node'\nimport type {Range} from '../interfaces/range'\nimport {isAfterPoint} from '../point/is-after-point'\n\nexport function isBackwardRange(\n range: Range,\n root: {value: Array<Node>},\n): boolean {\n const {anchor, focus} = range\n return isAfterPoint(anchor, focus, root)\n}\n","import type {Node} from '../interfaces/node'\nimport type {Point} from '../interfaces/point'\nimport type {Range} from '../interfaces/range'\nimport {isBackwardRange} from './is-backward-range'\n\nexport function rangeEdges(\n range: Range,\n root: {value: Array<Node>},\n): [Point, Point] {\n const {anchor, focus} = range\n return isBackwardRange(range, root) ? [focus, anchor] : [anchor, focus]\n}\n","import type {PortableTextObject, PortableTextSpan} from '@portabletext/schema'\nimport type {EditorSchema} from '../../editor/editor-schema'\nimport {isTypedObject} from '../../utils/asserters'\n\ntype TextBlockNode = {\n _type: string\n _key: string\n children?: Array<PortableTextSpan | PortableTextObject>\n markDefs?: Array<PortableTextObject>\n style?: string\n listItem?: string\n level?: number\n}\n\n/**\n * Checks if a node is a text block based on `_type` alone, without requiring\n * `children` to be present. This is needed to identify text blocks before\n * normalization has had a chance to add the missing `children` property.\n */\nexport function isTextBlockNode(\n context: {schema: EditorSchema},\n node: unknown,\n): node is TextBlockNode {\n return isTypedObject(node) && node._type === context.schema.block.name\n}\n","import {isKeyedSegment} from '../../utils/util.is-keyed-segment'\nimport type {Path} from '../interfaces/path'\n\nexport function isAncestorPath(path: Path, another: Path): boolean {\n if (path.length >= another.length) {\n return false\n }\n\n for (let i = 0; i < path.length; i++) {\n const segment = path[i]\n const otherSegment = another[i]\n\n if (isKeyedSegment(segment) && isKeyedSegment(otherSegment)) {\n if (segment._key !== otherSegment._key) {\n return false\n }\n } else if (segment !== otherSegment) {\n return false\n }\n }\n\n return true\n}\n","import type {Node} from '../engine/interfaces/node'\nimport type {Path} from '../engine/interfaces/path'\nimport {serializePath} from '../paths/serialize-path'\nimport {isKeyedSegment} from '../utils/util.is-keyed-segment'\n\n/**\n * The index of the child addressed by `childPath`'s last segment within\n * `children` (entries as resolved by `getChildren`). Numeric last\n * segments are literal, bounds-checked indices. Keyed segments resolve\n * through `blockIndexMap` when the path is fully keyed (the map's id\n * space), verified against the entry at the mapped position, with a\n * linear scan fallback for misses, disagreements, and paths the map\n * cannot key, mirroring `getNode`/`getChildren`. Returns `-1` when the\n * child is not found.\n *\n * The map is taken explicitly rather than assumed current: some callers\n * deliberately resolve against pre-operation map state. The engine\n * keeps raw-array siblings of this helper (`resolveChildIndex` in\n * `apply-operation.ts`, `childIndexFromMap` in\n * `transform-block-index-map.ts`) for call sites that hold plain node\n * arrays mid-mutation, where no entries exist.\n */\nexport function resolveChildEntryIndex(\n blockIndexMap: ReadonlyMap<string, number>,\n children: ReadonlyArray<{node: Node; path: Path}>,\n childPath: Path,\n): number {\n const lastSegment = childPath[childPath.length - 1]\n\n if (typeof lastSegment === 'number') {\n return lastSegment >= 0 && lastSegment < children.length ? lastSegment : -1\n }\n\n if (!isKeyedSegment(lastSegment)) {\n return -1\n }\n\n let fullyKeyed = true\n for (\n let segmentIndex = 0;\n segmentIndex < childPath.length - 1;\n segmentIndex++\n ) {\n const segment = childPath[segmentIndex]\n if (typeof segment !== 'string' && !isKeyedSegment(segment)) {\n fullyKeyed = false\n break\n }\n }\n\n if (fullyKeyed) {\n const mappedIndex = blockIndexMap.get(serializePath(childPath))\n if (\n mappedIndex !== undefined &&\n children[mappedIndex]?.node._key === lastSegment._key\n ) {\n return mappedIndex\n }\n }\n\n return children.findIndex((child) => child.node._key === lastSegment._key)\n}\n","import type {EditorSchema} from '../editor/editor-schema'\nimport type {Node} from '../engine/interfaces/node'\nimport type {Path} from '../engine/interfaces/path'\nimport {isAncestorPath} from '../engine/path/is-ancestor-path'\nimport {serializePath} from '../paths/serialize-path'\nimport type {\n Containers,\n RegisteredContainer,\n} from '../schema/resolve-containers'\nimport {getChildren, getNodeChildren} from './get-children'\nimport {resolveChildEntryIndex} from './resolve-child-entry-index'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Get the descendant nodes of the node at a given path.\n *\n * When `from` and `to` are provided, performs a range-bounded DFS traversal,\n * yielding only nodes between `from` and `to` (inclusive). Both paths are\n * always in document order: `from` is the earlier path, `to` is the later\n * path. The `reverse` flag controls iteration direction within that range.\n *\n * When `match` is provided, only yields nodes where the predicate returns true.\n * The traversal still visits all nodes in range - `match` is a filter, not a\n * traversal control.\n *\n * When `at` is provided, traverses descendants of the node at that path\n * instead of the root.\n */\nexport function* getNodes(\n snapshot: TraversalSnapshot,\n options: {\n at?: Path\n from?: Path\n to?: Path\n match?: (node: Node, path: Path) => boolean\n reverse?: boolean\n } = {},\n): Generator<{node: Node; path: Path}, void, undefined> {\n const {at = [], from, to, match, reverse = false} = options\n\n if (from === undefined && to === undefined) {\n yield* getNodesSimple(snapshot, at, {match, reverse})\n return\n }\n\n yield* getNodesInRange(snapshot, at, {from, to, match, reverse})\n}\n\n/**\n * Get descendant nodes of a standalone node (not in the editor tree).\n * Used for cases like getDirtyPaths where the node hasn't been inserted yet.\n */\nexport function* getNodeDescendants(\n context: {\n schema: EditorSchema\n containers: Containers\n },\n node: Node | {value: Array<Node>},\n): Generator<{node: Node; path: Path}, void, undefined> {\n // The editor root wrapper ({value: [...]}) is not a real node, so its field\n // name is not part of paths. For standalone nodes (a real {_key, _type, ...}\n // passed in by callers like getDirtyPaths), the field name IS part of the\n // path.\n const isRoot = !('_key' in node) && !('_type' in node)\n yield* walkStandalone(context, node, [], isRoot)\n}\n\nfunction* walkStandalone(\n context: {\n schema: EditorSchema\n containers: Containers\n },\n node: Node | {value: Array<Node>},\n path: Path,\n isRoot: boolean,\n parent?: RegisteredContainer,\n): Generator<{node: Node; path: Path}, void, undefined> {\n const next = getNodeChildren(context, node, parent)\n if (!next) {\n return\n }\n\n for (const child of next.children) {\n const childPath: Path = isRoot\n ? [{_key: child._key}]\n : [...path, next.fieldName, {_key: child._key}]\n yield {node: child, path: childPath}\n yield* walkStandalone(context, child, childPath, false, next.parent)\n }\n}\n\n/**\n * Simple recursive DFS - the original behavior.\n * Yields all descendants of the node at `path`.\n */\nfunction* getNodesSimple(\n snapshot: TraversalSnapshot,\n path: Path,\n options: {\n match?: (node: Node, path: Path) => boolean\n reverse?: boolean\n },\n): Generator<{node: Node; path: Path}, void, undefined> {\n const {match, reverse = false} = options\n\n const children = getChildren(snapshot, path)\n\n const entries = reverse ? [...children].reverse() : children\n\n for (const entry of entries) {\n if (!match || match(entry.node, entry.path)) {\n yield entry\n }\n\n yield* getNodesSimple(snapshot, entry.path, options)\n }\n}\n\n/**\n * Compare two keyed paths in DFS pre-order. Returns -1, 0, or 1.\n *\n * Walks both paths in parallel; at the first divergence, consults\n * `blockIndexMap` for the sibling indices and compares them.\n *\n * Deliberately not `comparePaths` (`engine/path/compare-paths.ts`):\n * that compare treats an ancestor/descendant pair as equal (0), while\n * range traversal needs the ancestor ordered first (-1/1), it is what\n * excludes `to`'s descendants from a range. The two compares answer\n * different questions and must not be merged.\n */\nfunction comparePathsInTree(\n snapshot: TraversalSnapshot,\n pathA: Path,\n pathB: Path,\n): -1 | 0 | 1 {\n // Walk both full paths in parallel; at the first divergent keyed\n // segment, consult blockIndexMap for the sibling indices. The map is\n // keyed by serialized paths that include both keyed and field-name\n // segments, so we keep the full path prefix as we descend.\n const minLength = Math.min(pathA.length, pathB.length)\n const prefix: Path = []\n\n for (let i = 0; i < minLength; i++) {\n const segA = pathA[i]!\n const segB = pathB[i]!\n\n if (\n typeof segA === 'string' ||\n typeof segB === 'string' ||\n typeof segA === 'number' ||\n typeof segB === 'number' ||\n Array.isArray(segA) ||\n Array.isArray(segB)\n ) {\n prefix.push(segA as never)\n continue\n }\n\n if (segA._key === segB._key) {\n prefix.push(segA)\n continue\n }\n\n const indexA =\n snapshot.blockIndexMap.get(serializePath([...prefix, segA])) ?? -1\n const indexB =\n snapshot.blockIndexMap.get(serializePath([...prefix, segB])) ?? -1\n if (indexA < indexB) {\n return -1\n }\n if (indexA > indexB) {\n return 1\n }\n return 0\n }\n\n // One path is a prefix of the other (ancestor relationship).\n // In DFS order, shorter path (ancestor) comes first.\n if (pathA.length < pathB.length) {\n return -1\n }\n if (pathA.length > pathB.length) {\n return 1\n }\n\n return 0\n}\n\n/**\n * Range-bounded recursive DFS traversal.\n *\n * `from` and `to` are always in document order (from is earlier, to is\n * later), regardless of traversal direction.\n */\nfunction* getNodesInRange(\n snapshot: TraversalSnapshot,\n path: Path,\n options: {\n from?: Path\n to?: Path\n match?: (node: Node, path: Path) => boolean\n reverse?: boolean\n },\n): Generator<{node: Node; path: Path}, void, undefined> {\n const {from, to, match, reverse = false} = options\n\n const children = getChildren(snapshot, path)\n\n // Seek instead of scan: only the children between the boundaries'\n // branches at this level can intersect [from, to], so resolve those\n // positions (O(1) through `blockIndexMap`) and iterate the window\n // between them. The per-entry checks below stay the semantic source\n // of truth; an unresolvable boundary just leaves its side of the\n // window open, degrading to the previous full scan.\n const startIndex =\n from === undefined ? 0 : (boundaryChildIndex(snapshot, children, from) ?? 0)\n const endIndex =\n to === undefined\n ? children.length - 1\n : (boundaryChildIndex(snapshot, children, to) ?? children.length - 1)\n const window = children.slice(startIndex, endIndex + 1)\n const entries = reverse ? window.reverse() : window\n\n for (const entry of entries) {\n if (canStopTraversal(snapshot, entry.path, from, to, reverse)) {\n return\n }\n\n if (!couldContainInRangeNodes(snapshot, entry.path, from, to)) {\n continue\n }\n\n if (isInRange(snapshot, entry.path, from, to)) {\n if (!match || match(entry.node, entry.path)) {\n yield entry\n }\n }\n\n yield* getNodesInRange(snapshot, entry.path, options)\n }\n}\n\n/**\n * The index of the child whose subtree `boundary` passes through, at\n * the level `children` was resolved for. `undefined` when the boundary\n * does not pass through this level or cannot be resolved, in which\n * case the caller must not narrow the window on that side.\n */\nfunction boundaryChildIndex(\n snapshot: TraversalSnapshot,\n children: Array<{node: Node; path: Path}>,\n boundary: Path,\n): number | undefined {\n const firstChild = children[0]\n if (!firstChild) {\n return undefined\n }\n const childPathLength = firstChild.path.length\n if (boundary.length < childPathLength) {\n return undefined\n }\n\n // The children share every path segment but the last; the boundary\n // passes through this level only when that shared prefix is an\n // ancestor of it.\n const sharedPrefix = firstChild.path.slice(0, -1)\n if (sharedPrefix.length > 0 && !isAncestorPath(sharedPrefix, boundary)) {\n return undefined\n }\n\n const resolvedIndex = resolveChildEntryIndex(\n snapshot.blockIndexMap,\n children,\n boundary.slice(0, childPathLength),\n )\n return resolvedIndex === -1 ? undefined : resolvedIndex\n}\n\n/**\n * Check if a node is within the [from, to] range in document order.\n * Both bounds are inclusive. Ancestor nodes of from or to are also\n * considered in range since they contain the range boundary.\n */\nfunction isInRange(\n snapshot: TraversalSnapshot,\n nodePath: Path,\n from: Path | undefined,\n to: Path | undefined,\n): boolean {\n if (\n from !== undefined &&\n comparePathsInTree(snapshot, nodePath, from) === -1\n ) {\n if (!isAncestorPath(nodePath, from)) {\n return false\n }\n }\n\n if (to !== undefined && comparePathsInTree(snapshot, nodePath, to) === 1) {\n if (!isAncestorPath(nodePath, to)) {\n return false\n }\n }\n\n return true\n}\n\n/**\n * Check if a subtree rooted at `nodePath` could contain any nodes in the\n * [from, to] range.\n */\nfunction couldContainInRangeNodes(\n snapshot: TraversalSnapshot,\n nodePath: Path,\n from: Path | undefined,\n to: Path | undefined,\n): boolean {\n if (isInRange(snapshot, nodePath, from, to)) {\n return true\n }\n\n if (from !== undefined && isAncestorPath(nodePath, from)) {\n return true\n }\n\n if (to !== undefined && isAncestorPath(nodePath, to)) {\n return true\n }\n\n return false\n}\n\n/**\n * Check if all remaining nodes in iteration order will be outside the range.\n */\nfunction canStopTraversal(\n snapshot: TraversalSnapshot,\n nodePath: Path,\n from: Path | undefined,\n to: Path | undefined,\n reverse: boolean,\n): boolean {\n if (reverse) {\n if (from === undefined) {\n return false\n }\n\n return (\n comparePathsInTree(snapshot, nodePath, from) === -1 &&\n !isAncestorPath(nodePath, from)\n )\n }\n\n if (to === undefined) {\n return false\n }\n\n return comparePathsInTree(snapshot, nodePath, to) === 1\n}\n","import type {Node} from '../engine/interfaces/node'\nimport type {Path} from '../engine/interfaces/path'\nimport {parentPath} from '../engine/path/parent-path'\nimport {getChildren} from './get-children'\nimport {resolveChildEntryIndex} from './resolve-child-entry-index'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Get a sibling of the node at a given path.\n *\n * Without `match`, returns the immediate next or previous sibling.\n * With `match`, returns the first sibling in `direction` that satisfies\n * the predicate.\n *\n * When `match` is a type predicate, the returned `node` narrows to that type.\n *\n * @public\n */\nexport function getSibling<TMatch extends Node>(\n snapshot: TraversalSnapshot,\n path: Path,\n options: {\n direction: 'next' | 'previous'\n match: (node: Node, path: Path) => node is TMatch\n },\n): {node: TMatch; path: Path} | undefined\n/**\n * @public\n */\nexport function getSibling(\n snapshot: TraversalSnapshot,\n path: Path,\n options: {\n direction: 'next' | 'previous'\n match?: (node: Node, path: Path) => boolean\n },\n): {node: Node; path: Path} | undefined\nexport function getSibling(\n snapshot: TraversalSnapshot,\n path: Path,\n options: {\n direction: 'next' | 'previous'\n match?: (node: Node, path: Path) => boolean\n },\n): {node: Node; path: Path} | undefined {\n const {direction, match} = options\n\n if (path.length === 0) {\n return undefined\n }\n\n const parent = parentPath(path)\n const children = getChildren(snapshot, parent)\n\n const currentIndex = resolveChildEntryIndex(\n snapshot.blockIndexMap,\n children,\n path,\n )\n\n if (currentIndex === -1) {\n return undefined\n }\n\n if (!match) {\n const siblingIndex =\n direction === 'next' ? currentIndex + 1 : currentIndex - 1\n\n if (siblingIndex < 0 || siblingIndex >= children.length) {\n return undefined\n }\n\n return children[siblingIndex]\n }\n\n const candidates =\n direction === 'next'\n ? children.slice(currentIndex + 1)\n : children.slice(0, currentIndex).reverse()\n\n return candidates.find((child) => match(child.node, child.path))\n}\n","import type {EditorSchema} from '../../editor/editor-schema'\nimport {isTypedObject} from '../../utils/asserters'\n\nexport type SpanNode = {\n _type: string\n _key: string\n text?: string\n marks?: Array<string>\n}\n\n/**\n * Checks if a node is a span based on `_type` alone, without requiring `text`\n * to be present. This is needed to identify spans before normalization has had\n * a chance to add the missing `text` property.\n */\nexport function isSpanNode(\n context: {schema: EditorSchema},\n node: unknown,\n): node is SpanNode {\n return isTypedObject(node) && node._type === context.schema.span.name\n}\n","import type {PortableTextBlock} from '@portabletext/schema'\nimport type {Path} from '../engine/interfaces/path'\nimport {isSpanNode} from '../engine/node/is-span-node'\nimport {isTextBlockNode} from '../engine/node/is-text-block-node'\nimport {getNode} from './get-node'\nimport {getParent} from './get-parent'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Determine if a node at the given path is a block.\n *\n * A node is a block if its parent is not a text block. Top-level nodes\n * (direct children of the editor) are always blocks. Children of text blocks\n * (spans and inline objects) are not blocks. Children of containers are\n * blocks within that container.\n *\n * @public\n */\nexport function isBlock(snapshot: TraversalSnapshot, path: Path): boolean {\n const parent = getParent(snapshot, path)\n\n if (!parent) {\n return true\n }\n\n return !isTextBlockNode({schema: snapshot.context.schema}, parent.node)\n}\n\n/**\n * Get the node at the given path if it is a block.\n *\n * Returns the node narrowed to PortableTextBlock, or undefined if the node\n * doesn't exist or is not a block.\n *\n * @public\n */\nexport function getBlock(\n snapshot: TraversalSnapshot,\n path: Path,\n): {node: PortableTextBlock; path: Path} | undefined {\n const entry = getNode(snapshot, path)\n\n if (!entry) {\n return undefined\n }\n\n if (!isBlock(snapshot, path)) {\n return undefined\n }\n\n if (isSpanNode({schema: snapshot.context.schema}, entry.node)) {\n return undefined\n }\n\n return {node: entry.node, path: entry.path}\n}\n","import type {Path} from '../engine/interfaces/path'\nimport {isBlock} from './is-block'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Determine if a node at the given path is inline.\n *\n * A node is inline if its parent is a text block. This is the inverse of\n * `isBlock`. Top-level nodes are never inline.\n *\n * @public\n */\nexport function isInline(snapshot: TraversalSnapshot, path: Path): boolean {\n return !isBlock(snapshot, path)\n}\n","import type {PortableTextBlock} from '@portabletext/schema'\nimport type {Path} from '../engine/interfaces/path'\nimport {getAncestors} from './get-ancestors'\nimport {getBlock} from './is-block'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Walk up from a path to find the nearest enclosing block.\n *\n * Returns the node at the path if it is a block, otherwise the first ancestor\n * that is a block. Works at any depth — inside a container this returns the\n * container-internal block, not the outer container.\n *\n * With `match`, returns the first enclosing block that also satisfies the\n * predicate. When `match` is a type predicate, the returned `node` narrows\n * to that type.\n *\n * `mode: 'lowest'` (default) returns the innermost enclosing block; the node\n * at the path itself counts. `mode: 'highest'` returns the outermost\n * ancestor that matches, falling back to the node at the path only if no\n * ancestor does.\n *\n * @public\n */\nexport function getEnclosingBlock<TMatch extends PortableTextBlock>(\n snapshot: TraversalSnapshot,\n path: Path,\n options: {\n match: (node: PortableTextBlock, path: Path) => node is TMatch\n mode?: 'lowest' | 'highest'\n },\n): {node: TMatch; path: Path} | undefined\n/**\n * @public\n */\nexport function getEnclosingBlock(\n snapshot: TraversalSnapshot,\n path: Path,\n options?: {\n match?: (node: PortableTextBlock, path: Path) => boolean\n mode?: 'lowest' | 'highest'\n },\n): {node: PortableTextBlock; path: Path} | undefined\nexport function getEnclosingBlock(\n snapshot: TraversalSnapshot,\n path: Path,\n options?: {\n match?: (node: PortableTextBlock, path: Path) => boolean\n mode?: 'lowest' | 'highest'\n },\n): {node: PortableTextBlock; path: Path} | undefined {\n const match = options?.match\n const mode = options?.mode ?? 'lowest'\n\n if (mode === 'highest') {\n const ancestors = getAncestors(snapshot, path)\n\n for (const ancestor of [...ancestors].reverse()) {\n if (!match || match(ancestor.node, ancestor.path)) {\n return ancestor\n }\n }\n\n const direct = getBlock(snapshot, path)\n\n if (direct && (!match || match(direct.node, direct.path))) {\n return direct\n }\n\n return undefined\n }\n\n const direct = getBlock(snapshot, path)\n\n if (direct && (!match || match(direct.node, direct.path))) {\n return direct\n }\n\n for (const ancestor of getAncestors(snapshot, path)) {\n if (!match || match(ancestor.node, ancestor.path)) {\n return ancestor\n }\n }\n\n return undefined\n}\n","import {comparePaths} from '../engine/path/compare-paths'\nimport type {EditorSelectionPoint} from '../types/editor'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Returns:\n *\n * - `-1` if `pointA` is before `pointB`\n * - `0` if `pointA` and `pointB` are equal\n * - `1` if `pointA` is after `pointB`.\n *\n * Compares the two points by document order, resolved at any depth. When\n * the paths are equal, compares offsets.\n *\n * @public\n */\nexport function comparePoints(\n snapshot: TraversalSnapshot,\n pointA: EditorSelectionPoint,\n pointB: EditorSelectionPoint,\n): -1 | 0 | 1 {\n const pathComparison = comparePaths(pointA.path, pointB.path, {\n value: snapshot.context.value,\n })\n\n if (pathComparison !== 0) {\n return pathComparison\n }\n\n if (pointA.offset < pointB.offset) {\n return -1\n }\n\n if (pointA.offset > pointB.offset) {\n return 1\n }\n\n return 0\n}\n","import type {Path} from '../engine/interfaces/path'\nimport {getAncestors} from '../traversal/get-ancestors'\nimport {isObject} from '../traversal/is-object'\nimport type {TraversalSnapshot} from '../traversal/traversal-snapshot'\nimport type {RegisteredContainer} from './container-types'\nimport {resolveContainerAt} from './resolve-container-at'\n\n/**\n * Descent primitive: return the immediate parent\n * {@link RegisteredContainer} of the node at `path` (and that parent's\n * path), or `undefined` when the target's immediate parent is the\n * editor root, when no object-node ancestor is a registered container,\n * or when descent hits an ancestor whose `_type` is not registered.\n *\n * Walks ancestors and resolves each object-node ancestor positionally\n * via {@link resolveContainerAt}. Text-block and span ancestors are\n * skipped - \"container\" here means the enclosing object container,\n * not the text-block holding spans.\n */\nexport function descendToParent(\n snapshot: TraversalSnapshot,\n path: Path,\n): {parent: RegisteredContainer; parentPath: Path} | undefined {\n const ancestors = getAncestors(snapshot, path)\n for (const ancestor of ancestors) {\n if (!isObject(snapshot, ancestor.node)) {\n continue\n }\n const resolved = resolveContainerAt(\n snapshot.context.containers,\n snapshot.context.value,\n ancestor.path,\n )\n if (!resolved || !('field' in resolved)) {\n return undefined\n }\n return {parent: resolved, parentPath: ancestor.path}\n }\n return undefined\n}\n","import type {OfDefinition} from '@portabletext/schema'\nimport type {Path} from '../engine/interfaces/path'\nimport type {TraversalSnapshot} from '../traversal/traversal-snapshot'\nimport {descendToParent} from './descend-to-parent'\n\n/**\n * Return the immediate registered-container ancestor of `path` along\n * with its `of` array (the schema definitions accepted at this position).\n *\n * Position-aware: nested-only registrations (e.g. `cell` registered\n * only inside `table.row.of`) are recognized via the same descent\n * primitive used by all parent-aware traversal.\n *\n * Returns `undefined` when `path` has no registered-container ancestor\n * (i.e. is at the document root) or when descent hits a leaf-resolved\n * ancestor.\n */\nexport function getEnclosingContainer(\n snapshot: TraversalSnapshot,\n path: Path,\n):\n | {\n of: ReadonlyArray<OfDefinition>\n path: Path\n }\n | undefined {\n const descent = descendToParent(snapshot, path)\n if (!descent) {\n return undefined\n }\n return {\n of: descent.parent.field.of,\n path: descent.parentPath,\n }\n}\n","import {getSubSchema, type Schema} from '@portabletext/schema'\nimport type {Path} from '../engine/interfaces/path'\nimport {getEnclosingContainer} from '../schema/get-enclosing-container'\nimport type {TraversalSnapshot} from './traversal-snapshot'\n\n/**\n * Return the `Schema` view that applies at a given path.\n *\n * For paths at the root of the document, or for paths where no ancestor is\n * a registered container, returns the top-level schema. For paths inside a\n * container, walks ancestors to find the nearest container and returns the\n * sub-schema derived from its `of` declaration.\n *\n * @public\n */\nexport function getPathSubSchema(\n snapshot: TraversalSnapshot,\n path: Path,\n): Schema {\n const enclosing = getEnclosingContainer(snapshot, path)\n\n if (!enclosing) {\n return snapshot.context.schema\n }\n\n return getSubSchema(snapshot.context.schema, enclosing.of)\n}\n"],"mappings":"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"}
|