@portabletext/toolkit
Advanced tools
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/asserters.ts","../src/buildMarksTree.ts","../src/nestLists.ts","../src/sortMarksByOccurences.ts","../src/spanToPlainText.ts","../src/toPlainText.ts"],"sourcesContent":[],"mappings":"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"} | ||
| {"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/asserters.ts","../src/buildMarksTree.ts","../src/nestLists.ts","../src/sortMarksByOccurences.ts","../src/spanToPlainText.ts","../src/toPlainText.ts"],"mappings":";;AAUA;;cAAa,mBAAA;;;AAKb;cAAa,qBAAA;;;;KAKD,mBAAA;;;;;AAOZ;KAAY,uBAAA,GAA0B,2BAAA,GAA8B,6BAAA;;;;AAMpE;UAAiB,2BAAA;;;;EAIf,KAAA;;;;EAKA,IAAA;;;;EAKA,IAAA;EAsBe;;;EAjBf,KAAA;;;;EAKA,QAAA;;;;EAKA,QAAA,EAAU,2BAAA;AAAA;AA0CZ;;;;AAAA,UAnCiB,6BAAA;;;;EAIf,KAAA;;;;EAKA,IAAA;;;AAoCF;EA/BE,IAAA;;;;EAKA,KAAA;EA0Ce;;;EArCf,QAAA;;;;EAKA,QAAA,GAAW,yBAAA,GAA4B,6BAAA;AAAA;;;;UAMxB,2BAAA,SAAoC,yBAAA,CACnD,0BAAA,EACA,gBAAA,GAAmB,uBAAA;;;;;;UAQJ,eAAA;;;;EAIf,KAAA;;;;EAKA,IAAA;AAAA;;;;;UAOe,6BAAA,WACL,0BAAA,GAA6B,0BAAA;ECjH9B;;;EDsHT,KAAA;;;;EAKA,IAAA;EC3GF;;;;EDiHE,OAAA,GAAU,CAAA;;;;;EAMV,OAAA;;;;;EAMA,QAAA;EChGF;;;;EDsGE,QAAA,GAAW,eAAA,GAAkB,6BAAA,GAAgC,oBAAA;AAAA;AA3J/D;;;;;AAKA;AALA,iBCMgB,kBAAA,CACd,IAAA,EAAM,oBAAA,GAAuB,gBAAA,GAC5B,IAAA,IAAQ,gBAAA;;;;ADEX;;;iBCcgB,mBAAA,CACd,IAAA,EAAM,iBAAA,GAAoB,WAAA,GACzB,IAAA,IAAQ,iBAAA;;ADTX;;;;;iBCoCgB,2BAAA,CACd,KAAA,EAAO,iBAAA,GAAoB,WAAA,GAC1B,KAAA,IAAS,yBAAA;;;;;;;;iBAgBI,yBAAA,CACd,KAAA,EAAO,WAAA,GAAc,uBAAA,GACpB,KAAA,IAAS,uBAAA;;;;;ADdZ;;;iBCyBgB,yBAAA,CACd,IAAA,EAAM,WAAA,GAAc,6BAAA,GACnB,IAAA,IAAQ,6BAAA;;;;;;;;iBAWK,6BAAA,CACd,IAAA,EAAM,WAAA,GAAc,eAAA,GACnB,IAAA,IAAQ,eAAA;ADnGX;;;;;AAKA;;;;;AAKA;;;;;AAOA;;;;;AAMA;;;;;;;;;;;AAvBA,iBE+BgB,cAAA,WAAyB,0BAAA,GAA6B,0BAAA,CAAA,CACpE,KAAA,EAAO,iBAAA,CAAkB,CAAA,KACvB,6BAAA,CAA8B,CAAA,IAAK,eAAA,GAAkB,oBAAA;AAAA,KC5B7C,0BAAA,MACR,CAAA,GACA,2BAAA,GACA,6BAAA;;;;;AHHJ;;;;;AAKA;;;;;AAOA;;;;;AAMA;;;iBGSgB,SAAA,WAAoB,WAAA,GAAc,iBAAA,GAAoB,WAAA,CAAA,CACpE,MAAA,EAAQ,CAAA,IACR,IAAA,cACE,CAAA,GAAI,6BAAA;AAAA,iBACQ,SAAA,WAAoB,WAAA,GAAc,iBAAA,GAAoB,WAAA,CAAA,CACpE,MAAA,EAAQ,CAAA,IACR,IAAA,YACE,CAAA,GAAI,2BAAA;AAAA,iBACQ,SAAA,WAAoB,WAAA,GAAc,iBAAA,GAAoB,WAAA,CAAA,CACpE,MAAA,EAAQ,CAAA,IACR,IAAA,uBACE,CAAA,GAAI,2BAAA,GAA8B,6BAAA;;AH3CtC;;;;;AAKA;;;;;AAKA;;;;;AAOA;;;;;AAMA;;;;;;;;;;;;;AAoCA;;;iBI1BgB,qBAAA,CACd,IAAA,EAAM,gBAAA,GAAmB,WAAA,EACzB,KAAA,UACA,aAAA,GAAgB,gBAAA,GAAmB,WAAA;;AJpCrC;;;;;AAKA;;;;iBKFgB,eAAA,CAAgB,IAAA,EAAM,6BAAA;;ALHtC;;;;;AAKA;;;;;iBMGgB,WAAA,CACd,KAAA,EAAO,iBAAA,GAAoB,oBAAA,KAAyB,iBAAA"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.js","names":["occurences: Record<string, number>","rootNode: ToolkitNestedPortableTextSpan<M>","nodeStack: ToolkitNestedPortableTextSpan<M>[]","node: ToolkitNestedPortableTextSpan<M>","tree: ToolkitNestListsOutputNode<T>[]","currentList: ToolkitPortableTextList | undefined","newLastChild: ToolkitPortableTextListItem"],"sources":["../src/asserters.ts","../src/sortMarksByOccurences.ts","../src/buildMarksTree.ts","../src/nestLists.ts","../src/spanToPlainText.ts","../src/toPlainText.ts","../src/types.ts"],"sourcesContent":["import type {\n ArbitraryTypedObject,\n PortableTextBlock,\n PortableTextListItemBlock,\n PortableTextSpan,\n TypedObject,\n} from '@portabletext/types'\n\nimport type {ToolkitNestedPortableTextSpan, ToolkitPortableTextList, ToolkitTextNode} from './types'\n\n/**\n * Strict check to determine if node is a correctly formatted Portable Text span.\n *\n * @param node - Node to check\n * @returns True if valid Portable Text span, otherwise false\n */\nexport function isPortableTextSpan(\n node: ArbitraryTypedObject | PortableTextSpan,\n): node is PortableTextSpan {\n return (\n node._type === 'span' &&\n 'text' in node &&\n typeof node.text === 'string' &&\n (typeof node.marks === 'undefined' ||\n (Array.isArray(node.marks) && node.marks.every((mark) => typeof mark === 'string')))\n )\n}\n\n/**\n * Strict check to determine if node is a correctly formatted Portable Text block.\n *\n * @param node - Node to check\n * @returns True if valid Portable Text block, otherwise false\n */\nexport function isPortableTextBlock(\n node: PortableTextBlock | TypedObject,\n): node is PortableTextBlock {\n return (\n // A block doesn't _have_ to be named 'block' - to differentiate between\n // allowed child types and marks, one might name them differently\n typeof node._type === 'string' &&\n // Toolkit-types like nested spans are @-prefixed\n node._type[0] !== '@' &&\n // `markDefs` isn't _required_ per say, but if it's there, it needs to be an array\n (!('markDefs' in node) ||\n !node.markDefs ||\n (Array.isArray(node.markDefs) &&\n // Every mark definition needs to have an `_key` to be mappable in child spans\n node.markDefs.every((def) => typeof def._key === 'string'))) &&\n // `children` is required and needs to be an array\n 'children' in node &&\n Array.isArray(node.children) &&\n // All children are objects with `_type` (usually spans, but can contain other stuff)\n node.children.every((child) => typeof child === 'object' && '_type' in child)\n )\n}\n\n/**\n * Strict check to determine if node is a correctly formatted portable list item block.\n *\n * @param block - Block to check\n * @returns True if valid Portable Text list item block, otherwise false\n */\nexport function isPortableTextListItemBlock(\n block: PortableTextBlock | TypedObject,\n): block is PortableTextListItemBlock {\n return (\n isPortableTextBlock(block) &&\n 'listItem' in block &&\n typeof block.listItem === 'string' &&\n (typeof block.level === 'undefined' || typeof block.level === 'number')\n )\n}\n\n/**\n * Loose check to determine if block is a toolkit list node.\n * Only checks `_type`, assumes correct structure.\n *\n * @param block - Block to check\n * @returns True if toolkit list, otherwise false\n */\nexport function isPortableTextToolkitList(\n block: TypedObject | ToolkitPortableTextList,\n): block is ToolkitPortableTextList {\n return block._type === '@list'\n}\n\n/**\n * Loose check to determine if span is a toolkit span node.\n * Only checks `_type`, assumes correct structure.\n *\n * @param span - Span to check\n * @returns True if toolkit span, otherwise false\n */\nexport function isPortableTextToolkitSpan(\n span: TypedObject | ToolkitNestedPortableTextSpan,\n): span is ToolkitNestedPortableTextSpan {\n return span._type === '@span'\n}\n\n/**\n * Loose check to determine if node is a toolkit text node.\n * Only checks `_type`, assumes correct structure.\n *\n * @param node - Node to check\n * @returns True if toolkit text node, otherwise false\n */\nexport function isPortableTextToolkitTextNode(\n node: TypedObject | ToolkitTextNode,\n): node is ToolkitTextNode {\n return node._type === '@text'\n}\n","import type {PortableTextSpan, TypedObject} from '@portabletext/types'\n\nimport {isPortableTextSpan} from './asserters'\n\nconst knownDecorators = ['strong', 'em', 'code', 'underline', 'strike-through']\n\n/**\n * Figures out the optimal order of marks, in order to minimize the amount of\n * nesting/repeated elements in environments such as HTML. For instance, a naive\n * implementation might render something like:\n *\n * ```html\n * <strong>This block contains </strong>\n * <strong><a href=\"https://some.url/\">a link</a></strong>\n * <strong> and some bolded text</strong>\n * ```\n *\n * ...whereas an optimal order would be:\n *\n * ```html\n * <strong>\n * This block contains <a href=\"https://some.url/\">a link</a> and some bolded text\n * </strong>\n * ```\n *\n * This is particularly necessary for cases like links, where you don't want multiple\n * individual links for different segments of the link text, even if parts of it are\n * bolded/italicized.\n *\n * This function is meant to be used like: `block.children.map(sortMarksByOccurences)`,\n * and is used internally in {@link buildMarksTree | `buildMarksTree()`}.\n *\n * The marks are sorted in the following order:\n *\n * 1. Marks that are shared amongst the most adjacent siblings\n * 2. Non-default marks (links, custom metadata)\n * 3. Decorators (bold, emphasis, code etc), in a predefined, preferred order\n *\n * @param span - The current span to sort\n * @param index - The index of the current span within the block\n * @param blockChildren - All children of the block being sorted\n * @returns Array of decorators and annotations, sorted by \"most adjacent siblings\"\n */\nexport function sortMarksByOccurences(\n span: PortableTextSpan | TypedObject,\n index: number,\n blockChildren: (PortableTextSpan | TypedObject)[],\n): string[] {\n if (!isPortableTextSpan(span) || !span.marks) {\n return []\n }\n\n if (!span.marks.length) {\n return []\n }\n\n // Slicing because we'll be sorting with `sort()`, which mutates\n const marks = span.marks.slice()\n const occurences: Record<string, number> = {}\n marks.forEach((mark) => {\n occurences[mark] = 1\n\n for (let siblingIndex = index + 1; siblingIndex < blockChildren.length; siblingIndex++) {\n const sibling = blockChildren[siblingIndex]\n\n if (\n sibling &&\n isPortableTextSpan(sibling) &&\n Array.isArray(sibling.marks) &&\n sibling.marks.indexOf(mark) !== -1\n ) {\n occurences[mark]++\n } else {\n break\n }\n }\n })\n\n return marks.sort((markA, markB) => sortMarks(occurences, markA, markB))\n}\n\nfunction sortMarks<U extends string, T extends Record<U, number>>(\n occurences: T,\n markA: U,\n markB: U,\n): number {\n const aOccurences = occurences[markA]\n const bOccurences = occurences[markB]\n\n if (aOccurences !== bOccurences) {\n return bOccurences - aOccurences\n }\n\n const aKnownPos = knownDecorators.indexOf(markA)\n const bKnownPos = knownDecorators.indexOf(markB)\n\n // Sort known decorators last\n if (aKnownPos !== bKnownPos) {\n return aKnownPos - bKnownPos\n }\n\n // Sort other marks simply by key\n return markA.localeCompare(markB)\n}\n","import type {\n ArbitraryTypedObject,\n PortableTextBlock,\n PortableTextMarkDefinition,\n} from '@portabletext/types'\n\nimport type {ToolkitNestedPortableTextSpan, ToolkitTextNode} from './types'\n\nimport {isPortableTextSpan} from './asserters'\nimport {sortMarksByOccurences} from './sortMarksByOccurences'\n\n/**\n * Takes a Portable Text block and returns a nested tree of nodes optimized for rendering\n * in HTML-like environments where you want marks/annotations to be nested inside of eachother.\n * For instance, a naive span-by-span rendering might yield:\n *\n * ```html\n * <strong>This block contains </strong>\n * <strong><a href=\"https://some.url/\">a link</a></strong>\n * <strong> and some bolded and </strong>\n * <em><strong>italicized text</strong></em>\n * ```\n *\n * ...whereas an optimal order would be:\n *\n * ```html\n * <strong>\n * This block contains <a href=\"https://some.url/\">a link</a>\n * and some bolded and <em>italicized text</em>\n * </strong>\n * ```\n *\n * Note that since \"native\" Portable Text spans cannot be nested,\n * this function returns an array of \"toolkit specific\" types:\n * {@link ToolkitTextNode | `@text`} and {@link ToolkitNestedPortableTextSpan | `@span` }.\n *\n * The toolkit-specific type can hold both types, as well as any arbitrary inline objects,\n * creating an actual tree.\n *\n * @param block - The Portable Text block to create a tree of nodes from\n * @returns Array of (potentially) nested spans, text nodes and/or arbitrary inline objects\n */\nexport function buildMarksTree<M extends PortableTextMarkDefinition = PortableTextMarkDefinition>(\n block: PortableTextBlock<M>,\n): (ToolkitNestedPortableTextSpan<M> | ToolkitTextNode | ArbitraryTypedObject)[] {\n const {children} = block\n const markDefs = block.markDefs ?? []\n if (!children || !children.length) {\n return []\n }\n\n const sortedMarks = children.map(sortMarksByOccurences)\n\n const rootNode: ToolkitNestedPortableTextSpan<M> = {\n _type: '@span',\n children: [],\n markType: '<unknown>',\n }\n\n let nodeStack: ToolkitNestedPortableTextSpan<M>[] = [rootNode]\n\n for (let i = 0; i < children.length; i++) {\n const span = children[i]\n if (!span) {\n continue\n }\n\n const marksNeeded = sortedMarks[i] || []\n let pos = 1\n\n // Start at position one. Root is always plain and should never be removed\n if (nodeStack.length > 1) {\n for (pos; pos < nodeStack.length; pos++) {\n const mark = nodeStack[pos]?.markKey || ''\n const index = marksNeeded.indexOf(mark)\n\n if (index === -1) {\n break\n }\n\n marksNeeded.splice(index, 1)\n }\n }\n\n // Keep from beginning to first miss\n nodeStack = nodeStack.slice(0, pos)\n\n // Add needed nodes\n let currentNode = nodeStack[nodeStack.length - 1]\n if (!currentNode) {\n continue\n }\n\n for (const markKey of marksNeeded) {\n const markDef = markDefs?.find((def) => def._key === markKey)\n const markType = markDef ? markDef._type : markKey\n const node: ToolkitNestedPortableTextSpan<M> = {\n _type: '@span',\n _key: span._key,\n children: [],\n markDef,\n markType,\n markKey,\n }\n\n currentNode.children.push(node)\n nodeStack.push(node)\n currentNode = node\n }\n\n // Split at newlines to make individual line chunks, but keep newline\n // characters as individual elements in the array. We use these characters\n // in the span serializer to trigger hard-break rendering\n if (isPortableTextSpan(span)) {\n const lines = span.text.split('\\n')\n for (let line = lines.length; line-- > 1; ) {\n lines.splice(line, 0, '\\n')\n }\n\n currentNode.children = currentNode.children.concat(\n lines.map((text) => ({_type: '@text', text})),\n )\n } else {\n // This is some other inline object, not a text span\n currentNode.children = currentNode.children.concat(span)\n }\n }\n\n return rootNode.children\n}\n","import type {PortableTextBlock, PortableTextListItemBlock, TypedObject} from '@portabletext/types'\n\nimport type {\n ToolkitListNestMode,\n ToolkitPortableTextDirectList,\n ToolkitPortableTextHtmlList,\n ToolkitPortableTextList,\n ToolkitPortableTextListItem,\n} from './types'\n\nimport {\n isPortableTextListItemBlock,\n isPortableTextSpan,\n isPortableTextToolkitList,\n} from './asserters'\n\nexport type ToolkitNestListsOutputNode<T> =\n | T\n | ToolkitPortableTextHtmlList\n | ToolkitPortableTextDirectList\n\n/**\n * Takes an array of blocks and returns an array of nodes optimized for rendering in HTML-like\n * environment, where lists are nested inside of eachother instead of appearing \"flat\" as in\n * native Portable Text data structures.\n *\n * Note that the list node is not a native Portable Text node type, and thus is represented\n * using the {@link ToolkitPortableTextList | `@list`} type name (`{_type: '@list'}`).\n *\n * The nesting can be configured in two modes:\n *\n * - `direct`: deeper list nodes will appear as a direct child of the parent list\n * - `html`, deeper list nodes will appear as a child of the last _list item_ in the parent list\n *\n * When using `direct`, all list nodes will be of type {@link ToolkitPortableTextDirectList},\n * while with `html` they will be of type {@link ToolkitPortableTextHtmlList}\n *\n * These modes are available as {@link LIST_NEST_MODE_HTML} and {@link LIST_NEST_MODE_DIRECT}.\n *\n * @param blocks - Array of Portable Text blocks and other arbitrary types\n * @param mode - Mode to use for nesting, `direct` or `html`\n * @returns Array of potentially nested nodes optimized for rendering\n */\nexport function nestLists<T extends TypedObject = PortableTextBlock | TypedObject>(\n blocks: T[],\n mode: 'direct',\n): (T | ToolkitPortableTextDirectList)[]\nexport function nestLists<T extends TypedObject = PortableTextBlock | TypedObject>(\n blocks: T[],\n mode: 'html',\n): (T | ToolkitPortableTextHtmlList)[]\nexport function nestLists<T extends TypedObject = PortableTextBlock | TypedObject>(\n blocks: T[],\n mode: 'direct' | 'html',\n): (T | ToolkitPortableTextHtmlList | ToolkitPortableTextDirectList)[]\nexport function nestLists<T extends TypedObject = PortableTextBlock | TypedObject>(\n blocks: T[],\n mode: ToolkitListNestMode,\n): ToolkitNestListsOutputNode<T>[] {\n const tree: ToolkitNestListsOutputNode<T>[] = []\n let currentList: ToolkitPortableTextList | undefined\n\n for (let i = 0; i < blocks.length; i++) {\n const block = blocks[i]\n if (!block) {\n continue\n }\n\n if (!isPortableTextListItemBlock(block)) {\n tree.push(block)\n currentList = undefined\n continue\n }\n\n // Start of a new list?\n if (!currentList) {\n currentList = listFromBlock(block, i, mode)\n tree.push(currentList)\n continue\n }\n\n // New list item within same list?\n if (blockMatchesList(block, currentList)) {\n currentList.children.push(block)\n continue\n }\n\n // Different list props, are we going deeper?\n if ((block.level || 1) > currentList.level) {\n const newList = listFromBlock(block, i, mode)\n\n if (mode === 'html') {\n // Because HTML is kinda weird, nested lists needs to be nested within list items.\n // So while you would think that we could populate the parent list with a new sub-list,\n // we actually have to target the last list element (child) of the parent.\n // However, at this point we need to be very careful - simply pushing to the list of children\n // will mutate the input, and we don't want to blindly clone the entire tree.\n\n // Clone the last child while adding our new list as the last child of it\n const lastListItem = currentList.children[\n currentList.children.length - 1\n ] as ToolkitPortableTextListItem\n\n const newLastChild: ToolkitPortableTextListItem = {\n ...lastListItem,\n children: [...lastListItem.children, newList],\n }\n\n // Swap the last child\n currentList.children[currentList.children.length - 1] = newLastChild\n } else {\n ;(currentList as ToolkitPortableTextDirectList).children.push(\n newList as ToolkitPortableTextDirectList,\n )\n }\n\n // Set the newly created, deeper list as the current\n currentList = newList\n continue\n }\n\n // Different list props, are we going back up the tree?\n if ((block.level || 1) < currentList.level) {\n // Current list has ended, and we need to hook up with a parent of the same level and type\n const matchingBranch = tree[tree.length - 1]\n const match = matchingBranch && findListMatching(matchingBranch, block)\n if (match) {\n currentList = match\n currentList.children.push(block)\n continue\n }\n\n // Similar parent can't be found, assume new list\n currentList = listFromBlock(block, i, mode)\n tree.push(currentList)\n continue\n }\n\n // Different list props, different list style?\n if (block.listItem !== currentList.listItem) {\n const matchingBranch = tree[tree.length - 1]\n const match = matchingBranch && findListMatching(matchingBranch, {level: block.level || 1})\n if (match && match.listItem === block.listItem) {\n currentList = match\n currentList.children.push(block)\n continue\n } else {\n currentList = listFromBlock(block, i, mode)\n tree.push(currentList)\n continue\n }\n }\n\n // oxlint-disable-next-line no-console\n console.warn('Unknown state encountered for block', block)\n tree.push(block)\n }\n\n return tree\n}\n\nfunction blockMatchesList(block: PortableTextBlock, list: ToolkitPortableTextList) {\n return (block.level || 1) === list.level && block.listItem === list.listItem\n}\n\nfunction listFromBlock(\n block: PortableTextListItemBlock,\n index: number,\n mode: ToolkitListNestMode,\n): ToolkitPortableTextList {\n return {\n _type: '@list',\n _key: `${block._key || `${index}`}-parent`,\n mode,\n level: block.level || 1,\n listItem: block.listItem,\n children: [block],\n }\n}\n\nfunction findListMatching<T extends TypedObject | PortableTextBlock>(\n rootNode: T,\n matching: Partial<PortableTextListItemBlock>,\n): ToolkitPortableTextList | undefined {\n const level = matching.level || 1\n const style = matching.listItem || 'normal'\n const filterOnType = typeof matching.listItem === 'string'\n if (\n isPortableTextToolkitList(rootNode) &&\n (rootNode.level || 1) === level &&\n filterOnType &&\n (rootNode.listItem || 'normal') === style\n ) {\n return rootNode\n }\n\n if (!('children' in rootNode)) {\n return undefined\n }\n\n const node = rootNode.children[rootNode.children.length - 1]\n return node && !isPortableTextSpan(node) ? findListMatching(node, matching) : undefined\n}\n","import type {ToolkitNestedPortableTextSpan} from './types'\n\nimport {isPortableTextToolkitSpan, isPortableTextToolkitTextNode} from './asserters'\n\n/**\n * Returns the plain-text representation of a\n * {@link ToolkitNestedPortableTextSpan | toolkit-specific Portable Text span}.\n *\n * Useful if you have a subset of nested nodes and want the text from just those,\n * instead of for the entire Portable Text block.\n *\n * @param span - Span node to get text from (Portable Text toolkit specific type)\n * @returns The plain-text version of the span\n */\nexport function spanToPlainText(span: ToolkitNestedPortableTextSpan): string {\n let text = ''\n span.children.forEach((current) => {\n if (isPortableTextToolkitTextNode(current)) {\n text += current.text\n } else if (isPortableTextToolkitSpan(current)) {\n text += spanToPlainText(current)\n }\n })\n return text\n}\n","import type {ArbitraryTypedObject, PortableTextBlock} from '@portabletext/types'\n\nimport {isPortableTextBlock, isPortableTextSpan} from './asserters'\n\nconst leadingSpace = /^\\s/\nconst trailingSpace = /\\s$/\n\n/**\n * Takes a Portable Text block (or an array of them) and returns the text value\n * of all the Portable Text span nodes. Adds whitespace when encountering inline,\n * non-span nodes to ensure text flow is optimal.\n *\n * Note that this only accounts for regular Portable Text blocks - any text inside\n * custom content types are not included in the output.\n *\n * @param block - Single block or an array of blocks to extract text from\n * @returns The plain-text content of the blocks\n */\nexport function toPlainText(\n block: PortableTextBlock | ArbitraryTypedObject[] | PortableTextBlock[],\n): string {\n const blocks = Array.isArray(block) ? block : [block]\n let text = ''\n\n blocks.forEach((current, index) => {\n if (!isPortableTextBlock(current)) {\n return\n }\n\n let pad = false\n current.children.forEach((span) => {\n if (isPortableTextSpan(span)) {\n // If the previous element was a non-span, and we have no natural whitespace\n // between the previous and the next span, insert it to give the spans some\n // room to breathe. However, don't do so if this is the first span.\n text += pad && text && !trailingSpace.test(text) && !leadingSpace.test(span.text) ? ' ' : ''\n text += span.text\n pad = false\n } else {\n pad = true\n }\n })\n\n if (index !== blocks.length - 1) {\n text += '\\n\\n'\n }\n })\n\n return text\n}\n","import type {\n ArbitraryTypedObject,\n PortableTextListItemBlock,\n PortableTextMarkDefinition,\n PortableTextSpan,\n} from '@portabletext/types'\n\n/**\n * List nesting mode for HTML, see the {@link nestLists | `nestLists()` function}\n */\nexport const LIST_NEST_MODE_HTML = 'html'\n\n/**\n * List nesting mode for direct, nested lists, see the {@link nestLists | `nestLists()` function}\n */\nexport const LIST_NEST_MODE_DIRECT = 'direct'\n\n/**\n * List nesting mode, see the {@link nestLists | `nestLists()` function}\n */\nexport type ToolkitListNestMode = 'html' | 'direct'\n\n/**\n * Toolkit-specific type representing a nested list\n *\n * See the `nestLists()` function for more info\n */\nexport type ToolkitPortableTextList = ToolkitPortableTextHtmlList | ToolkitPortableTextDirectList\n\n/**\n * Toolkit-specific type representing a nested list in HTML mode, where deeper lists are nested\n * inside of the _list items_, eg `<ul><li>Some text<ul><li>Deeper</li></ul></li></ul>`\n */\nexport interface ToolkitPortableTextHtmlList {\n /**\n * Type name, prefixed with `@` to signal that this is a toolkit-specific node.\n */\n _type: '@list'\n\n /**\n * Unique key for this list (within its parent)\n */\n _key: string\n\n /**\n * List mode, signaling that list nodes will appear as children of the _list items_\n */\n mode: 'html'\n\n /**\n * Level/depth of this list node (starts at `1`)\n */\n level: number\n\n /**\n * Style of this list item (`bullet`, `number` are common values, but can be customized)\n */\n listItem: string\n\n /**\n * Child nodes of this list - toolkit-specific list items which can themselves hold deeper lists\n */\n children: ToolkitPortableTextListItem[]\n}\n\n/**\n * Toolkit-specific type representing a nested list in \"direct\" mode, where deeper lists are nested\n * inside of the lists children, alongside other blocks.\n */\nexport interface ToolkitPortableTextDirectList {\n /**\n * Type name, prefixed with `@` to signal that this is a toolkit-specific node.\n */\n _type: '@list'\n\n /**\n * Unique key for this list (within its parent)\n */\n _key: string\n\n /**\n * List mode, signaling that list nodes can appear as direct children\n */\n mode: 'direct'\n\n /**\n * Level/depth of this list node (starts at `1`)\n */\n level: number\n\n /**\n * Style of this list item (`bullet`, `number` are common values, but can be customized)\n */\n listItem: string\n\n /**\n * Child nodes of this list - either portable text list items, or another, deeper list\n */\n children: (PortableTextListItemBlock | ToolkitPortableTextDirectList)[]\n}\n\n/**\n * Toolkit-specific type representing a list item block, but where the children can be another list\n */\nexport interface ToolkitPortableTextListItem extends PortableTextListItemBlock<\n PortableTextMarkDefinition,\n PortableTextSpan | ToolkitPortableTextList\n> {}\n\n/**\n * Toolkit-specific type representing a text node, used when nesting spans.\n *\n * See the {@link buildMarksTree | `buildMarksTree()` function}\n */\nexport interface ToolkitTextNode {\n /**\n * Type name, prefixed with `@` to signal that this is a toolkit-specific node.\n */\n _type: '@text'\n\n /**\n * The actual string value of the text node\n */\n text: string\n}\n\n/**\n * Toolkit-specific type representing a portable text span that can hold other spans.\n * In this type, each span only has a single mark, instead of an array of them.\n */\nexport interface ToolkitNestedPortableTextSpan<\n M extends PortableTextMarkDefinition = PortableTextMarkDefinition,\n> {\n /**\n * Type name, prefixed with `@` to signal that this is a toolkit-specific node.\n */\n _type: '@span'\n\n /**\n * Unique key for this span\n */\n _key?: string\n\n /**\n * Holds the value (definition) of the mark in the case of annotations.\n * `undefined` if the mark is a decorator (strong, em or similar).\n */\n markDef?: M\n\n /**\n * The key of the mark definition (in the case of annotations).\n * `undefined` if the mark is a decorator (strong, em or similar).\n */\n markKey?: string\n\n /**\n * Type of the mark. For annotations, this is the `_type` property of the value.\n * For decorators, it will hold the name of the decorator (strong, em or similar).\n */\n markType: string\n\n /**\n * Child nodes of this span. Can be toolkit-specific text nodes, nested spans\n * or any inline object type.\n */\n children: (ToolkitTextNode | ToolkitNestedPortableTextSpan | ArbitraryTypedObject)[]\n}\n"],"mappings":"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"} | ||
| {"version":3,"file":"index.js","names":[],"sources":["../src/asserters.ts","../src/sortMarksByOccurences.ts","../src/buildMarksTree.ts","../src/nestLists.ts","../src/spanToPlainText.ts","../src/toPlainText.ts","../src/types.ts"],"sourcesContent":["import type {\n ArbitraryTypedObject,\n PortableTextBlock,\n PortableTextListItemBlock,\n PortableTextSpan,\n TypedObject,\n} from '@portabletext/types'\n\nimport type {ToolkitNestedPortableTextSpan, ToolkitPortableTextList, ToolkitTextNode} from './types'\n\n/**\n * Strict check to determine if node is a correctly formatted Portable Text span.\n *\n * @param node - Node to check\n * @returns True if valid Portable Text span, otherwise false\n */\nexport function isPortableTextSpan(\n node: ArbitraryTypedObject | PortableTextSpan,\n): node is PortableTextSpan {\n return (\n node._type === 'span' &&\n 'text' in node &&\n typeof node.text === 'string' &&\n (typeof node.marks === 'undefined' ||\n (Array.isArray(node.marks) && node.marks.every((mark) => typeof mark === 'string')))\n )\n}\n\n/**\n * Strict check to determine if node is a correctly formatted Portable Text block.\n *\n * @param node - Node to check\n * @returns True if valid Portable Text block, otherwise false\n */\nexport function isPortableTextBlock(\n node: PortableTextBlock | TypedObject,\n): node is PortableTextBlock {\n return (\n // A block doesn't _have_ to be named 'block' - to differentiate between\n // allowed child types and marks, one might name them differently\n typeof node._type === 'string' &&\n // Toolkit-types like nested spans are @-prefixed\n node._type[0] !== '@' &&\n // `markDefs` isn't _required_ per say, but if it's there, it needs to be an array\n (!('markDefs' in node) ||\n !node.markDefs ||\n (Array.isArray(node.markDefs) &&\n // Every mark definition needs to have an `_key` to be mappable in child spans\n node.markDefs.every((def) => typeof def._key === 'string'))) &&\n // `children` is required and needs to be an array\n 'children' in node &&\n Array.isArray(node.children) &&\n // All children are objects with `_type` (usually spans, but can contain other stuff)\n node.children.every((child) => typeof child === 'object' && '_type' in child)\n )\n}\n\n/**\n * Strict check to determine if node is a correctly formatted portable list item block.\n *\n * @param block - Block to check\n * @returns True if valid Portable Text list item block, otherwise false\n */\nexport function isPortableTextListItemBlock(\n block: PortableTextBlock | TypedObject,\n): block is PortableTextListItemBlock {\n return (\n isPortableTextBlock(block) &&\n 'listItem' in block &&\n typeof block.listItem === 'string' &&\n (typeof block.level === 'undefined' || typeof block.level === 'number')\n )\n}\n\n/**\n * Loose check to determine if block is a toolkit list node.\n * Only checks `_type`, assumes correct structure.\n *\n * @param block - Block to check\n * @returns True if toolkit list, otherwise false\n */\nexport function isPortableTextToolkitList(\n block: TypedObject | ToolkitPortableTextList,\n): block is ToolkitPortableTextList {\n return block._type === '@list'\n}\n\n/**\n * Loose check to determine if span is a toolkit span node.\n * Only checks `_type`, assumes correct structure.\n *\n * @param span - Span to check\n * @returns True if toolkit span, otherwise false\n */\nexport function isPortableTextToolkitSpan(\n span: TypedObject | ToolkitNestedPortableTextSpan,\n): span is ToolkitNestedPortableTextSpan {\n return span._type === '@span'\n}\n\n/**\n * Loose check to determine if node is a toolkit text node.\n * Only checks `_type`, assumes correct structure.\n *\n * @param node - Node to check\n * @returns True if toolkit text node, otherwise false\n */\nexport function isPortableTextToolkitTextNode(\n node: TypedObject | ToolkitTextNode,\n): node is ToolkitTextNode {\n return node._type === '@text'\n}\n","import type {PortableTextSpan, TypedObject} from '@portabletext/types'\n\nimport {isPortableTextSpan} from './asserters'\n\nconst knownDecorators = ['strong', 'em', 'code', 'underline', 'strike-through']\n\n/**\n * Figures out the optimal order of marks, in order to minimize the amount of\n * nesting/repeated elements in environments such as HTML. For instance, a naive\n * implementation might render something like:\n *\n * ```html\n * <strong>This block contains </strong>\n * <strong><a href=\"https://some.url/\">a link</a></strong>\n * <strong> and some bolded text</strong>\n * ```\n *\n * ...whereas an optimal order would be:\n *\n * ```html\n * <strong>\n * This block contains <a href=\"https://some.url/\">a link</a> and some bolded text\n * </strong>\n * ```\n *\n * This is particularly necessary for cases like links, where you don't want multiple\n * individual links for different segments of the link text, even if parts of it are\n * bolded/italicized.\n *\n * This function is meant to be used like: `block.children.map(sortMarksByOccurences)`,\n * and is used internally in {@link buildMarksTree | `buildMarksTree()`}.\n *\n * The marks are sorted in the following order:\n *\n * 1. Marks that are shared amongst the most adjacent siblings\n * 2. Non-default marks (links, custom metadata)\n * 3. Decorators (bold, emphasis, code etc), in a predefined, preferred order\n *\n * @param span - The current span to sort\n * @param index - The index of the current span within the block\n * @param blockChildren - All children of the block being sorted\n * @returns Array of decorators and annotations, sorted by \"most adjacent siblings\"\n */\nexport function sortMarksByOccurences(\n span: PortableTextSpan | TypedObject,\n index: number,\n blockChildren: (PortableTextSpan | TypedObject)[],\n): string[] {\n if (!isPortableTextSpan(span) || !span.marks) {\n return []\n }\n\n if (!span.marks.length) {\n return []\n }\n\n // Slicing because we'll be sorting with `sort()`, which mutates\n const marks = span.marks.slice()\n const occurences: Record<string, number> = {}\n marks.forEach((mark) => {\n occurences[mark] = 1\n\n for (let siblingIndex = index + 1; siblingIndex < blockChildren.length; siblingIndex++) {\n const sibling = blockChildren[siblingIndex]\n\n if (\n sibling &&\n isPortableTextSpan(sibling) &&\n Array.isArray(sibling.marks) &&\n sibling.marks.indexOf(mark) !== -1\n ) {\n occurences[mark]++\n } else {\n break\n }\n }\n })\n\n return marks.sort((markA, markB) => sortMarks(occurences, markA, markB))\n}\n\nfunction sortMarks<U extends string, T extends Record<U, number>>(\n occurences: T,\n markA: U,\n markB: U,\n): number {\n const aOccurences = occurences[markA]\n const bOccurences = occurences[markB]\n\n if (aOccurences !== bOccurences) {\n return bOccurences - aOccurences\n }\n\n const aKnownPos = knownDecorators.indexOf(markA)\n const bKnownPos = knownDecorators.indexOf(markB)\n\n // Sort known decorators last\n if (aKnownPos !== bKnownPos) {\n return aKnownPos - bKnownPos\n }\n\n // Sort other marks simply by key\n return markA.localeCompare(markB)\n}\n","import type {\n ArbitraryTypedObject,\n PortableTextBlock,\n PortableTextMarkDefinition,\n} from '@portabletext/types'\n\nimport {isPortableTextSpan} from './asserters'\nimport {sortMarksByOccurences} from './sortMarksByOccurences'\nimport type {ToolkitNestedPortableTextSpan, ToolkitTextNode} from './types'\n\n/**\n * Takes a Portable Text block and returns a nested tree of nodes optimized for rendering\n * in HTML-like environments where you want marks/annotations to be nested inside of eachother.\n * For instance, a naive span-by-span rendering might yield:\n *\n * ```html\n * <strong>This block contains </strong>\n * <strong><a href=\"https://some.url/\">a link</a></strong>\n * <strong> and some bolded and </strong>\n * <em><strong>italicized text</strong></em>\n * ```\n *\n * ...whereas an optimal order would be:\n *\n * ```html\n * <strong>\n * This block contains <a href=\"https://some.url/\">a link</a>\n * and some bolded and <em>italicized text</em>\n * </strong>\n * ```\n *\n * Note that since \"native\" Portable Text spans cannot be nested,\n * this function returns an array of \"toolkit specific\" types:\n * {@link ToolkitTextNode | `@text`} and {@link ToolkitNestedPortableTextSpan | `@span` }.\n *\n * The toolkit-specific type can hold both types, as well as any arbitrary inline objects,\n * creating an actual tree.\n *\n * @param block - The Portable Text block to create a tree of nodes from\n * @returns Array of (potentially) nested spans, text nodes and/or arbitrary inline objects\n */\nexport function buildMarksTree<M extends PortableTextMarkDefinition = PortableTextMarkDefinition>(\n block: PortableTextBlock<M>,\n): (ToolkitNestedPortableTextSpan<M> | ToolkitTextNode | ArbitraryTypedObject)[] {\n const {children} = block\n const markDefs = block.markDefs ?? []\n if (!children || !children.length) {\n return []\n }\n\n const sortedMarks = children.map(sortMarksByOccurences)\n\n const rootNode: ToolkitNestedPortableTextSpan<M> = {\n _type: '@span',\n children: [],\n markType: '<unknown>',\n }\n\n let nodeStack: ToolkitNestedPortableTextSpan<M>[] = [rootNode]\n\n for (let i = 0; i < children.length; i++) {\n const span = children[i]\n if (!span) {\n continue\n }\n\n const marksNeeded = sortedMarks[i] || []\n let pos = 1\n\n // Start at position one. Root is always plain and should never be removed\n if (nodeStack.length > 1) {\n for (pos; pos < nodeStack.length; pos++) {\n const mark = nodeStack[pos]?.markKey || ''\n const index = marksNeeded.indexOf(mark)\n\n if (index === -1) {\n break\n }\n\n marksNeeded.splice(index, 1)\n }\n }\n\n // Keep from beginning to first miss\n nodeStack = nodeStack.slice(0, pos)\n\n // Add needed nodes\n let currentNode = nodeStack[nodeStack.length - 1]\n if (!currentNode) {\n continue\n }\n\n for (const markKey of marksNeeded) {\n const markDef = markDefs?.find((def) => def._key === markKey)\n const markType = markDef ? markDef._type : markKey\n const node: ToolkitNestedPortableTextSpan<M> = {\n _type: '@span',\n _key: span._key,\n children: [],\n markDef,\n markType,\n markKey,\n }\n\n currentNode.children.push(node)\n nodeStack.push(node)\n currentNode = node\n }\n\n // Split at newlines to make individual line chunks, but keep newline\n // characters as individual elements in the array. We use these characters\n // in the span serializer to trigger hard-break rendering\n if (isPortableTextSpan(span)) {\n const lines = span.text.split('\\n')\n for (let line = lines.length; line-- > 1; ) {\n lines.splice(line, 0, '\\n')\n }\n\n currentNode.children = currentNode.children.concat(\n lines.map((text) => ({_type: '@text', text})),\n )\n } else {\n // This is some other inline object, not a text span\n currentNode.children = currentNode.children.concat(span)\n }\n }\n\n return rootNode.children\n}\n","import type {PortableTextBlock, PortableTextListItemBlock, TypedObject} from '@portabletext/types'\n\nimport {\n isPortableTextListItemBlock,\n isPortableTextSpan,\n isPortableTextToolkitList,\n} from './asserters'\nimport type {\n ToolkitListNestMode,\n ToolkitPortableTextDirectList,\n ToolkitPortableTextHtmlList,\n ToolkitPortableTextList,\n ToolkitPortableTextListItem,\n} from './types'\n\nexport type ToolkitNestListsOutputNode<T> =\n | T\n | ToolkitPortableTextHtmlList\n | ToolkitPortableTextDirectList\n\n/**\n * Takes an array of blocks and returns an array of nodes optimized for rendering in HTML-like\n * environment, where lists are nested inside of eachother instead of appearing \"flat\" as in\n * native Portable Text data structures.\n *\n * Note that the list node is not a native Portable Text node type, and thus is represented\n * using the {@link ToolkitPortableTextList | `@list`} type name (`{_type: '@list'}`).\n *\n * The nesting can be configured in two modes:\n *\n * - `direct`: deeper list nodes will appear as a direct child of the parent list\n * - `html`, deeper list nodes will appear as a child of the last _list item_ in the parent list\n *\n * When using `direct`, all list nodes will be of type {@link ToolkitPortableTextDirectList},\n * while with `html` they will be of type {@link ToolkitPortableTextHtmlList}\n *\n * These modes are available as {@link LIST_NEST_MODE_HTML} and {@link LIST_NEST_MODE_DIRECT}.\n *\n * @param blocks - Array of Portable Text blocks and other arbitrary types\n * @param mode - Mode to use for nesting, `direct` or `html`\n * @returns Array of potentially nested nodes optimized for rendering\n */\nexport function nestLists<T extends TypedObject = PortableTextBlock | TypedObject>(\n blocks: T[],\n mode: 'direct',\n): (T | ToolkitPortableTextDirectList)[]\nexport function nestLists<T extends TypedObject = PortableTextBlock | TypedObject>(\n blocks: T[],\n mode: 'html',\n): (T | ToolkitPortableTextHtmlList)[]\nexport function nestLists<T extends TypedObject = PortableTextBlock | TypedObject>(\n blocks: T[],\n mode: 'direct' | 'html',\n): (T | ToolkitPortableTextHtmlList | ToolkitPortableTextDirectList)[]\nexport function nestLists<T extends TypedObject = PortableTextBlock | TypedObject>(\n blocks: T[],\n mode: ToolkitListNestMode,\n): ToolkitNestListsOutputNode<T>[] {\n const tree: ToolkitNestListsOutputNode<T>[] = []\n let currentList: ToolkitPortableTextList | undefined\n\n for (let i = 0; i < blocks.length; i++) {\n const block = blocks[i]\n if (!block) {\n continue\n }\n\n if (!isPortableTextListItemBlock(block)) {\n tree.push(block)\n currentList = undefined\n continue\n }\n\n // Start of a new list?\n if (!currentList) {\n currentList = listFromBlock(block, i, mode)\n tree.push(currentList)\n continue\n }\n\n // New list item within same list?\n if (blockMatchesList(block, currentList)) {\n currentList.children.push(block)\n continue\n }\n\n // Different list props, are we going deeper?\n if ((block.level || 1) > currentList.level) {\n const newList = listFromBlock(block, i, mode)\n\n if (mode === 'html') {\n // Because HTML is kinda weird, nested lists needs to be nested within list items.\n // So while you would think that we could populate the parent list with a new sub-list,\n // we actually have to target the last list element (child) of the parent.\n // However, at this point we need to be very careful - simply pushing to the list of children\n // will mutate the input, and we don't want to blindly clone the entire tree.\n\n // Clone the last child while adding our new list as the last child of it\n const lastListItem = currentList.children[\n currentList.children.length - 1\n ] as ToolkitPortableTextListItem\n\n const newLastChild: ToolkitPortableTextListItem = {\n ...lastListItem,\n children: [...lastListItem.children, newList],\n }\n\n // Swap the last child\n currentList.children[currentList.children.length - 1] = newLastChild\n } else {\n ;(currentList as ToolkitPortableTextDirectList).children.push(\n newList as ToolkitPortableTextDirectList,\n )\n }\n\n // Set the newly created, deeper list as the current\n currentList = newList\n continue\n }\n\n // Different list props, are we going back up the tree?\n if ((block.level || 1) < currentList.level) {\n // Current list has ended, and we need to hook up with a parent of the same level and type\n const matchingBranch = tree[tree.length - 1]\n const match = matchingBranch && findListMatching(matchingBranch, block)\n if (match) {\n currentList = match\n currentList.children.push(block)\n continue\n }\n\n // Similar parent can't be found, assume new list\n currentList = listFromBlock(block, i, mode)\n tree.push(currentList)\n continue\n }\n\n // Different list props, different list style?\n if (block.listItem !== currentList.listItem) {\n const matchingBranch = tree[tree.length - 1]\n const match = matchingBranch && findListMatching(matchingBranch, {level: block.level || 1})\n if (match && match.listItem === block.listItem) {\n currentList = match\n currentList.children.push(block)\n continue\n } else {\n currentList = listFromBlock(block, i, mode)\n tree.push(currentList)\n continue\n }\n }\n\n // oxlint-disable-next-line no-console\n console.warn('Unknown state encountered for block', block)\n tree.push(block)\n }\n\n return tree\n}\n\nfunction blockMatchesList(block: PortableTextBlock, list: ToolkitPortableTextList) {\n return (block.level || 1) === list.level && block.listItem === list.listItem\n}\n\nfunction listFromBlock(\n block: PortableTextListItemBlock,\n index: number,\n mode: ToolkitListNestMode,\n): ToolkitPortableTextList {\n return {\n _type: '@list',\n _key: `${block._key || `${index}`}-parent`,\n mode,\n level: block.level || 1,\n listItem: block.listItem,\n children: [block],\n }\n}\n\nfunction findListMatching<T extends TypedObject | PortableTextBlock>(\n rootNode: T,\n matching: Partial<PortableTextListItemBlock>,\n): ToolkitPortableTextList | undefined {\n const level = matching.level || 1\n const style = matching.listItem || 'normal'\n const filterOnType = typeof matching.listItem === 'string'\n if (\n isPortableTextToolkitList(rootNode) &&\n (rootNode.level || 1) === level &&\n filterOnType &&\n (rootNode.listItem || 'normal') === style\n ) {\n return rootNode\n }\n\n if (!('children' in rootNode)) {\n return undefined\n }\n\n const node = rootNode.children[rootNode.children.length - 1]\n return node && !isPortableTextSpan(node) ? findListMatching(node, matching) : undefined\n}\n","import {isPortableTextToolkitSpan, isPortableTextToolkitTextNode} from './asserters'\nimport type {ToolkitNestedPortableTextSpan} from './types'\n\n/**\n * Returns the plain-text representation of a\n * {@link ToolkitNestedPortableTextSpan | toolkit-specific Portable Text span}.\n *\n * Useful if you have a subset of nested nodes and want the text from just those,\n * instead of for the entire Portable Text block.\n *\n * @param span - Span node to get text from (Portable Text toolkit specific type)\n * @returns The plain-text version of the span\n */\nexport function spanToPlainText(span: ToolkitNestedPortableTextSpan): string {\n let text = ''\n span.children.forEach((current) => {\n if (isPortableTextToolkitTextNode(current)) {\n text += current.text\n } else if (isPortableTextToolkitSpan(current)) {\n text += spanToPlainText(current)\n }\n })\n return text\n}\n","import type {ArbitraryTypedObject, PortableTextBlock} from '@portabletext/types'\n\nimport {isPortableTextBlock, isPortableTextSpan} from './asserters'\n\nconst leadingSpace = /^\\s/\nconst trailingSpace = /\\s$/\n\n/**\n * Takes a Portable Text block (or an array of them) and returns the text value\n * of all the Portable Text span nodes. Adds whitespace when encountering inline,\n * non-span nodes to ensure text flow is optimal.\n *\n * Note that this only accounts for regular Portable Text blocks - any text inside\n * custom content types are not included in the output.\n *\n * @param block - Single block or an array of blocks to extract text from\n * @returns The plain-text content of the blocks\n */\nexport function toPlainText(\n block: PortableTextBlock | ArbitraryTypedObject[] | PortableTextBlock[],\n): string {\n const blocks = Array.isArray(block) ? block : [block]\n let text = ''\n\n blocks.forEach((current, index) => {\n if (!isPortableTextBlock(current)) {\n return\n }\n\n let pad = false\n current.children.forEach((span) => {\n if (isPortableTextSpan(span)) {\n // If the previous element was a non-span, and we have no natural whitespace\n // between the previous and the next span, insert it to give the spans some\n // room to breathe. However, don't do so if this is the first span.\n text += pad && text && !trailingSpace.test(text) && !leadingSpace.test(span.text) ? ' ' : ''\n text += span.text\n pad = false\n } else {\n pad = true\n }\n })\n\n if (index !== blocks.length - 1) {\n text += '\\n\\n'\n }\n })\n\n return text\n}\n","import type {\n ArbitraryTypedObject,\n PortableTextListItemBlock,\n PortableTextMarkDefinition,\n PortableTextSpan,\n} from '@portabletext/types'\n\n/**\n * List nesting mode for HTML, see the {@link nestLists | `nestLists()` function}\n */\nexport const LIST_NEST_MODE_HTML = 'html'\n\n/**\n * List nesting mode for direct, nested lists, see the {@link nestLists | `nestLists()` function}\n */\nexport const LIST_NEST_MODE_DIRECT = 'direct'\n\n/**\n * List nesting mode, see the {@link nestLists | `nestLists()` function}\n */\nexport type ToolkitListNestMode = 'html' | 'direct'\n\n/**\n * Toolkit-specific type representing a nested list\n *\n * See the `nestLists()` function for more info\n */\nexport type ToolkitPortableTextList = ToolkitPortableTextHtmlList | ToolkitPortableTextDirectList\n\n/**\n * Toolkit-specific type representing a nested list in HTML mode, where deeper lists are nested\n * inside of the _list items_, eg `<ul><li>Some text<ul><li>Deeper</li></ul></li></ul>`\n */\nexport interface ToolkitPortableTextHtmlList {\n /**\n * Type name, prefixed with `@` to signal that this is a toolkit-specific node.\n */\n _type: '@list'\n\n /**\n * Unique key for this list (within its parent)\n */\n _key: string\n\n /**\n * List mode, signaling that list nodes will appear as children of the _list items_\n */\n mode: 'html'\n\n /**\n * Level/depth of this list node (starts at `1`)\n */\n level: number\n\n /**\n * Style of this list item (`bullet`, `number` are common values, but can be customized)\n */\n listItem: string\n\n /**\n * Child nodes of this list - toolkit-specific list items which can themselves hold deeper lists\n */\n children: ToolkitPortableTextListItem[]\n}\n\n/**\n * Toolkit-specific type representing a nested list in \"direct\" mode, where deeper lists are nested\n * inside of the lists children, alongside other blocks.\n */\nexport interface ToolkitPortableTextDirectList {\n /**\n * Type name, prefixed with `@` to signal that this is a toolkit-specific node.\n */\n _type: '@list'\n\n /**\n * Unique key for this list (within its parent)\n */\n _key: string\n\n /**\n * List mode, signaling that list nodes can appear as direct children\n */\n mode: 'direct'\n\n /**\n * Level/depth of this list node (starts at `1`)\n */\n level: number\n\n /**\n * Style of this list item (`bullet`, `number` are common values, but can be customized)\n */\n listItem: string\n\n /**\n * Child nodes of this list - either portable text list items, or another, deeper list\n */\n children: (PortableTextListItemBlock | ToolkitPortableTextDirectList)[]\n}\n\n/**\n * Toolkit-specific type representing a list item block, but where the children can be another list\n */\nexport interface ToolkitPortableTextListItem extends PortableTextListItemBlock<\n PortableTextMarkDefinition,\n PortableTextSpan | ToolkitPortableTextList\n> {}\n\n/**\n * Toolkit-specific type representing a text node, used when nesting spans.\n *\n * See the {@link buildMarksTree | `buildMarksTree()` function}\n */\nexport interface ToolkitTextNode {\n /**\n * Type name, prefixed with `@` to signal that this is a toolkit-specific node.\n */\n _type: '@text'\n\n /**\n * The actual string value of the text node\n */\n text: string\n}\n\n/**\n * Toolkit-specific type representing a portable text span that can hold other spans.\n * In this type, each span only has a single mark, instead of an array of them.\n */\nexport interface ToolkitNestedPortableTextSpan<\n M extends PortableTextMarkDefinition = PortableTextMarkDefinition,\n> {\n /**\n * Type name, prefixed with `@` to signal that this is a toolkit-specific node.\n */\n _type: '@span'\n\n /**\n * Unique key for this span\n */\n _key?: string\n\n /**\n * Holds the value (definition) of the mark in the case of annotations.\n * `undefined` if the mark is a decorator (strong, em or similar).\n */\n markDef?: M\n\n /**\n * The key of the mark definition (in the case of annotations).\n * `undefined` if the mark is a decorator (strong, em or similar).\n */\n markKey?: string\n\n /**\n * Type of the mark. For annotations, this is the `_type` property of the value.\n * For decorators, it will hold the name of the decorator (strong, em or similar).\n */\n markType: string\n\n /**\n * Child nodes of this span. Can be toolkit-specific text nodes, nested spans\n * or any inline object type.\n */\n children: (ToolkitTextNode | ToolkitNestedPortableTextSpan | ArbitraryTypedObject)[]\n}\n"],"mappings":"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"} |
+11
-11
| { | ||
| "name": "@portabletext/toolkit", | ||
| "version": "5.0.1", | ||
| "version": "5.0.2", | ||
| "description": "Toolkit of handy utility functions for dealing with Portable Text", | ||
@@ -36,3 +36,3 @@ "keywords": [ | ||
| "dependencies": { | ||
| "@portabletext/types": "^4.0.1" | ||
| "@portabletext/types": "^4.0.2" | ||
| }, | ||
@@ -43,12 +43,12 @@ "devDependencies": { | ||
| "@sanity/tsconfig": "^2.1.0", | ||
| "@sanity/tsdown-config": "^0.5.2", | ||
| "@types/node": "^24.10.4", | ||
| "@vitest/coverage-v8": "^4.0.16", | ||
| "oxfmt": "^0.21.0", | ||
| "oxlint": "^1.36.0", | ||
| "oxlint-tsgolint": "^0.10.0", | ||
| "tsdown": "^0.18.4", | ||
| "typedoc": "^0.28.15", | ||
| "@sanity/tsdown-config": "^0.5.8", | ||
| "@types/node": "^24.11.0", | ||
| "@vitest/coverage-v8": "^4.0.18", | ||
| "oxfmt": "^0.36.0", | ||
| "oxlint": "^1.51.0", | ||
| "oxlint-tsgolint": "^0.16.0", | ||
| "tsdown": "^0.20.3", | ||
| "typedoc": "^0.28.17", | ||
| "typescript": "5.9.3", | ||
| "vitest": "^4.0.16" | ||
| "vitest": "^4.0.18" | ||
| }, | ||
@@ -55,0 +55,0 @@ "engines": { |
56239
-2.21%Updated