### Clone and set up the monorepo Source: https://github.com/datocms/structured-text/blob/main/README.md Initial setup commands for the monorepo: clone, install, build, and test. Run `npm run build` before `npm test` on a fresh checkout. ```sh git clone https://github.com/datocms/structured-text && cd structured-text npm install # one install for all ten packages; no bootstrap step npm run build # turbo, in dependency order npm test # eslint, then the Jest suite (448 tests, nothing external) ``` -------------------------------- ### Install with npm Source: https://github.com/datocms/structured-text/blob/main/packages/to-markdown/README.md Install the package using npm. ```sh npm install datocms-structured-text-to-markdown ``` -------------------------------- ### Install with npm Source: https://github.com/datocms/structured-text/blob/main/packages/slate-utils/README.md Install the package using npm. Run this command in your project directory to add datocms-structured-text-slate-utils as a dependency. ```sh npm install datocms-structured-text-slate-utils ``` -------------------------------- ### Install datocms-structured-text-dastdown Source: https://github.com/datocms/structured-text/blob/main/packages/dastdown/README.md Install the package from npm. ```sh npm install datocms-structured-text-dastdown ``` -------------------------------- ### Install a preview package from pkg.pr.new Source: https://github.com/datocms/structured-text/blob/main/README.md Installs a preview package published from a branch commit. The URL is available in the GitHub check run and PR comment. ```sh npm i https://pkg.pr.new/datocms-structured-text-utils@ ``` -------------------------------- ### Install with yarn Source: https://github.com/datocms/structured-text/blob/main/packages/to-markdown/README.md Install the package using yarn. ```sh yarn add datocms-structured-text-to-markdown ``` -------------------------------- ### Install and build all packages Source: https://github.com/datocms/structured-text/blob/main/CLAUDE.md One install for the whole workspace, then build every package in dependency order via turbo run build. Use npx turbo run build --filter= to build a specific package and its dependencies. ```bash npm install # One install for the whole workspace; no bootstrap step npm run build # turbo run build — every package, in dependency order npx turbo run build --filter= # ...and its dependencies only ``` -------------------------------- ### Install with yarn Source: https://github.com/datocms/structured-text/blob/main/packages/slate-utils/README.md Install the package using yarn. Run this command in your project directory to add datocms-structured-text-slate-utils as a dependency. ```sh yarn add datocms-structured-text-slate-utils ``` -------------------------------- ### Example handler for

tag Source: https://github.com/datocms/structured-text/blob/main/packages/html-to-structured-text/README.md Shows the shape of a handler function for a `hast` node, using the `

` tag as an example. Handlers can return a promise resolving to a `dast` node, an array of `dast` nodes, or `undefined` to skip the node. Default handlers validate parent-child relationships and ignore invalid nodes. ```js import { visitChildren } from 'datocms-html-to-structured-text'; // Handler for the

tag. async function p(createDastNode, hastNode, context) { return createDastNode('paragraph', { children: await visitChildren(createDastNode, hastNode, context), }); } ``` -------------------------------- ### dast JSON example: composed document Source: https://github.com/datocms/structured-text/blob/main/packages/dastdown/SPEC.md A JSON example of a composed document using the dast schema. It shows the root node with a heading child at level 2. Use this as a reference for the expected structure when round-tripping documents. ```json { "schema": "dast", "document": { "type": "root", "children": [ { "type": "heading", "level": 2, "children": [ { "type": "paragraph", "children": [ { "type": "span", "value": "A composed document" } ] } ] } ] } } ``` -------------------------------- ### Custom renderers for itemLink, inlineItem, block Source: https://github.com/datocms/structured-text/blob/main/packages/to-plain-text/README.md Advanced usage with custom renderers for itemLink, inlineItem, and block. The example shows how to provide a GraphQL response and options object to render, producing custom plain text output. ```javascript import { render } from 'datocms-structured-text-to-plain-text'; const graphqlResponse = { value: { schema: 'dast', document: { type: 'root', children: [ { type: 'paragraph', children: [ { type: 'span', value: 'A ', }, { type: 'itemLink', item: '344312', children: [ { type: 'span', value: 'record hyperlink', }, ], }, { type: 'span', value: ' and an inline record: ', }, { type: 'inlineItem', item: '344312', }, ], }, { type: 'block', item: '812394', }, ], }, }, blocks: [ { id: '812394', image: { url: 'http://www.datocms-assets.com/1312/image.png' }, }, ], links: [{ id: '344312', title: 'Foo', slug: 'foo' }], }; const options = { renderBlock({ record }) { return `[Image ${record.image.url}]`; }, renderInlineRecord({ record, adapter: { renderNode } }) { return `[Inline ${record.slug}]${children}[/Inline]`; }, renderLinkToRecord({ record, children, adapter: { renderNode } }) { return `[Link to ${record.slug}]${children}[/Link]`; }, }; render(document, options); // -> A [Link to foo]record hyperlink[/Link] and an inline record: [Inline foo]Foo[/Inline] // [Image http://www.datocms-assets.com/1312/image.png] ``` -------------------------------- ### Render DAST document to DOM nodes Source: https://github.com/datocms/structured-text/blob/main/packages/to-dom-nodes/README.md Imports the render function from datocms-structured-text-to-dom-nodes and renders a DAST document into DOM nodes. The first example uses the 'dast' schema with a document containing a paragraph and span. The second example uses the default schema with marks for strong and underline. ```javascript import { render } from 'datocms-structured-text-to-dom-nodes'; let nodes = render({ schema: 'dast', document: { type: 'root', children: [ { type: 'paragraph', children: [ { type: 'span', value: 'Hello world!', }, ], }, ], }, }); console.log(nodes.map((node) => node.outerHTML)); // -> ["

Hello world!

" ``` -------------------------------- ### Custom renderers for itemLink, inlineItem, and block Source: https://github.com/datocms/structured-text/blob/main/packages/to-html-string/README.md Shows how to pass custom renderers for linked records, inline records, and blocks. Includes a GraphQL response example with blocks and links. ```javascript import { render } from 'datocms-structured-text-to-html-string'; const graphqlResponse = { value: { schema: 'dast', document: { type: 'root', children: [ { type: 'paragraph', children: [ { type: 'span', value: 'A ', }, { type: 'itemLink', item: '344312', children: [ { type: 'span', value: 'record hyperlink', }, ], }, { type: 'span', value: ' and an inline record: ', }, { type: 'inlineItem', item: '344312', }, ], }, { type: 'block', item: '812394', }, ], }, }, blocks: [ { id: '812394', image: { url: 'http://www.datocms-assets.com/1312/image.png' }, }, ], links: [{ id: '344312', title: 'Foo', slug: 'foo' }], }; const options = { renderBlock({ record, adapter: { renderNode } }) { return renderNode( 'figure', {}, renderNode('img', { src: record.image.url }), ); }, renderInlineRecord({ record, adapter: { renderNode } }) { return renderNode('a', { href: `/blog/${record.slug}` }, record.title); }, renderLinkToRecord({ record, children, adapter: { renderNode } }) { return renderNode('a', { href: `/blog/${record.slug}` }, children); }, }; render(document, options); // ->

A record hyperlink and an inline record: Foo

//
``` -------------------------------- ### Find nodes with findFirstNode, findFirstNodeAsync, collectNodes, collectNodesAsync Source: https://github.com/datocms/structured-text/blob/main/packages/utils/README.md Use predicates or type guards like isHeading and isSpan to find specific nodes. The example shows finding the first heading, collecting all spans, and collecting spans with a 'strong' mark. ```javascript import { findFirstNode, findFirstNodeAsync, collectNodes, collectNodesAsync, isSpan, isHeading, } from 'datocms-structured-text-utils'; // Find first node matching condition const firstHeading = findFirstNode(structuredText, isHeading); if (firstHeading) { console.log(`Found heading: ${firstHeading.node.level}`); } // Collect all nodes matching condition const allSpans = collectNodes(structuredText, isSpan); const textContent = allSpans.map(({ node }) => node.value).join(''); // Find nodes with specific attributes const strongText = collectNodes( structuredText, (node) => isSpan(node) && node.marks?.includes('strong'), ); ``` -------------------------------- ### Basic render usage Source: https://github.com/datocms/structured-text/blob/main/packages/to-plain-text/README.md Basic usage of the render function to convert a Structured Text document to plain text. The example shows a heading with a span containing newlines, which are replaced with spaces in the output. ```javascript import { render } from 'datocms-structured-text-to-plain-text'; const structuredText = { value: { schema: 'dast', document: { type: 'root', children: [ { type: 'heading', level: 1, children: [ { type: 'span', value: 'This\nis a\ntitle!', }, ], }, ], }, }, }; render(structuredText); // -> "This is a title!" ``` -------------------------------- ### Round-trip property parse(serialize(d)) ≡ canonicalize(d) Source: https://github.com/datocms/structured-text/blob/main/packages/dastdown/README.md Round-trip property example: parse(serialize(d)) is equivalent to canonicalize(d). This demonstrates that serializing and parsing normalizes the document. ```js import { parse, serialize, canonicalize, } from 'datocms-structured-text-dastdown'; parse(serialize(d)); // ≡ canonicalize(d) ``` -------------------------------- ### Reduce tree with reduceNodes and reduceNodesAsync Source: https://github.com/datocms/structured-text/blob/main/packages/utils/README.md Reduce the entire tree to a single value using a reducer function. The example extracts all text content and counts nodes by type. ```javascript import { reduceNodes, reduceNodesAsync } from 'datocms-structured-text-utils'; // Extract all text content const textContent = reduceNodes( structuredText, (acc, node) => { if (isSpan(node)) { return acc + node.value; } return acc; }, '', ); // Count nodes by type const nodeCounts = reduceNodes( structuredText, (acc, node) => { acc[node.type] = (acc[node.type] || 0) + 1; return acc; }, {}, ); ``` -------------------------------- ### Check conditions with someNode, everyNode, and async variants Source: https://github.com/datocms/structured-text/blob/main/packages/utils/README.md Use these utilities to test if any or all nodes in a structured text tree match a condition. The functions support both synchronous and asynchronous predicates, with short-circuit evaluation. The example shows checking for headings, verifying span text content, and performing async block validation. ```javascript import { someNode, everyNode, someNodeAsync, everyNodeAsync, isHeading, isSpan, isBlock, } from 'datocms-structured-text-utils'; // Check if document contains any headings const hasHeadings = someNode(structuredText, isHeading); // Check if all spans have text content const allSpansHaveText = everyNode( structuredText, (node) => !isSpan(node) || (node.value && node.value.length > 0), ); // Async validation const allBlocksValid = await everyNodeAsync( structuredText, async (node) => !isBlock(node) || (await validateBlock(node.item)), ); ``` -------------------------------- ### Split a node that contains an image using liftAssets Source: https://github.com/datocms/structured-text/blob/main/packages/contentful-to-structured-text/README.md This example shows how to preprocess Rich Text to lift embedded asset blocks out of list items before converting to DAST. It includes a sample richTextWithAssets object, a call to liftAssets, a handlers object for the embedded-asset-block node, and the liftAssets function implementation. The liftAssets function moves embedded-asset-block nodes to the root, splitting the list into two parts when necessary. ```javascript import { liftAssets } from 'datocms-contentful-to-structured-text'; const richTextWithAssets = { nodeType: 'document', data: {}, content: [ { nodeType: 'unordered-list', content: [ { nodeType: 'list-item', content: [ { nodeType: 'paragraph', content: [ { nodeType: 'text', value: 'text', marks: [], data: {}, }, ], data: {}, }, { content: [], data: { target: { sys: { id: 'zzz', linkType: 'Asset', type: 'Link', }, }, }, nodeType: 'embedded-asset-block', }, { nodeType: 'paragraph', content: [ { nodeType: 'text', value: 'text', marks: [], data: {}, }, ], data: {}, }, ], data: {}, }, ], data: {}, }, ], }; liftAssets(richTextWithAssets); const handlers = { 'embedded-asset-block': async (createNode, node, context) => { const item = '123'; return createNode('block', { item, }); }, }; const dast = await richTextToStructuredText(richTextWithAssets, { handlers }); ``` ```javascript function liftAssets(richText) { const visit = (node, cb, index = 0, parents = []) => { if (node.content && node.content.length > 0) { node.content.forEach((child, index) => { visit(child, cb, index, [...parents, node]); }); } cb(node, index, parents); }; const liftedImages = new WeakSet(); visit(richText, (node, index, parents) => { if ( !node || node.nodeType !== 'embedded-asset-block' || liftedImages.has(node) || parents.length === 1 // is a top level asset ) { return; } const imgParent = parents[parents.length - 1]; imgParent.content.splice(index, 1); let i = parents.length; let splitChildrenIndex = index; const contentAfterSplitPoint = []; while (--i > 0) { const parent = parents[i]; const parentsParent = parents[i - 1]; contentAfterSplitPoint = parent.content.splice(splitChildrenIndex); splitChildrenIndex = parentsParent.content.indexOf(parent); let nodeInserted = false; if (i === 1) { splitChildrenIndex += 1; parentsParent.content.splice(splitChildrenIndex, 0, node); liftedImages.add(node); nodeInserted = true; } splitChildrenIndex += 1; if (contentAfterSplitPoint.length > 0) { parentsParent.content.splice(splitChildrenIndex, 0, { ...parent, content: contentAfterSplitPoint, }); } // Remove the parent if empty if (parent.content.length === 0) { splitChildrenIndex -= 1; parentsParent.content.splice( nodeInserted ? splitChildrenIndex - 1 : splitChildrenIndex, 1, ); } } }); } ``` -------------------------------- ### serialize with plain ids and nested-response items Source: https://github.com/datocms/structured-text/blob/main/packages/dastdown/README.md Example of serializing a dast document with plain string ids and with nested-response items (objects with an id). Both produce the same dastdown string. The request shape (items without ids) is not supported. ```js import { serialize } from 'datocms-structured-text-dastdown'; // works with plain ids: serialize({ schema: 'dast', document: { type: 'root', children: [{ type: 'block', item: 'abc-123' }], }, }); // → '\n' // works with nested-response items too — only `id` is read: serialize({ schema: 'dast', document: { type: 'root', children: [ { type: 'block', item: { id: 'abc-123' /* ...rest of Item */ } }, ], }, }); // → '\n' ``` -------------------------------- ### Basic usage of inspect() to render an ASCII tree Source: https://github.com/datocms/structured-text/blob/main/packages/utils/README.md Imports the inspect function from datocms-structured-text-utils and renders a structured text document as an ASCII tree. The example defines a document with heading, paragraph, and block nodes, then logs the inspect result to the console. ```javascript import { inspect } from 'datocms-structured-text-utils'; const structuredText = { schema: 'dast', document: { type: 'root', children: [ { type: 'heading', level: 1, children: [{ type: 'span', value: 'Main Title' }], }, { type: 'paragraph', children: [ { type: 'span', value: 'This is a ' }, { type: 'span', marks: ['strong'], value: 'bold' }, { type: 'span', value: ' paragraph.' }, ], }, { type: 'block', item: 'block-123', }, ], }, }; console.log(inspect(structuredText)); ``` -------------------------------- ### Release and release:next Source: https://github.com/datocms/structured-text/blob/main/CLAUDE.md npm run release builds, tests, versions, publishes to npm, tags, and generates release notes. npm run release:next does the same under the 'next' dist-tag. ```bash npm run release # Build, test, version, publish to npm, tag, release notes npm run release:next # The same, under the 'next' dist-tag ``` -------------------------------- ### Basic usage with schema 'dast' Source: https://github.com/datocms/structured-text/blob/main/packages/to-html-string/README.md Renders a simple paragraph with 'Hello world!' using the 'dast' schema. The render function returns an HTML string. ```javascript import { render } from 'datocms-structured-text-to-html-string'; render({ schema: 'dast', document: { type: 'root', children: [ { type: 'paragraph', children: [ { type: 'span', value: 'Hello world!', }, ], }, ], }, }); // ->

Hello world!

``` -------------------------------- ### Run tests Source: https://github.com/datocms/structured-text/blob/main/CLAUDE.md npm test runs the linter and all tests. Use jest to run tests only, or jest to run specific test files. ```bash npm test # Run linter and all tests jest # Run tests only jest # Run specific test file(s) ``` -------------------------------- ### Catching DastdownParseError from parse Source: https://github.com/datocms/structured-text/blob/main/packages/dastdown/README.md Example of catching a DastdownParseError thrown by parse on malformed input. The error exposes line and column properties (1-indexed) and a message. ```js import { parse, DastdownParseError } from 'datocms-structured-text-dastdown'; try { parse('####### too many hashes'); } catch (err) { if (err instanceof DastdownParseError) { console.log(err.line, err.column, err.message); } } ``` -------------------------------- ### Create a changeset with npx changeset Source: https://github.com/datocms/structured-text/blob/main/README.md Creates a changeset file for a user-visible change. Select the changed packages and bump level (`patch` for bug fixes, `minor` for new features). ```sh npx changeset ``` -------------------------------- ### Context Source: https://github.com/datocms/structured-text/blob/main/packages/html-to-structured-text/README.md Documentation for the context object passed to every handler. ```APIDOC ## [CONTEXT] Context ### Description Every handler receives a `context` object with the following shape. ### Properties - **parentNodeType** (NodeType) - Required - The current parent `dast` node type. - **parentNode** (HastNodes | null) - Required - The parent `hast` node. - **handlers** (Record) - Required - A reference to the current handlers - merged default + user handlers. - **defaultHandlers** (Record) - Required - A reference to the default handlers record (map). - **wrapText** (boolean) - Required - true if the content can include newlines, and false if not (such as in headings). - **marks** (Mark[]) - Optional - Marks for span nodes. - **codePrefix** (string) - Optional - Prefix for language detection in code blocks. Default is `language-`. - **allowedBlocks** (string[]) - Required - Allowed block types. - **allowedHeadingLevels** (Array<1 | 2 | 3 | 4 | 5 | 6>) - Required - Allowed heading levels. - **allowedMarks** (Mark[]) - Required - Allowed marks. - **global** (GlobalContext) - Required - Properties in this object are available to every handler — Context is not deeply cloned. ### GlobalContext Properties - **baseUrlFound** (boolean) - Optional - Whether the library has found a tag or should not look further. - **baseUrl** (string | null) - Optional - tag url. Used for resolving relative URLs. - **[key: string]** (unknown) - Optional - Additional properties. ### Example ```ts import type { Nodes as HastNodes } from 'hast'; export interface GlobalContext { baseUrlFound?: boolean; baseUrl?: string | null; [key: string]: unknown; } export interface Context { parentNodeType: NodeType; parentNode: HastNodes | null; handlers: Record; defaultHandlers: Record; wrapText: boolean; marks?: Mark[]; codePrefix?: string; allowedBlocks: string[]; allowedHeadingLevels: Array<1 | 2 | 3 | 4 | 5 | 6>; allowedMarks: Mark[]; global: GlobalContext; } ``` ``` -------------------------------- ### Build a single package Source: https://github.com/datocms/structured-text/blob/main/CLAUDE.md Navigate to packages/ and run npm run build to compile TypeScript to both CommonJS (dist/cjs) and ESM (dist/esm). ```bash npm run build # Compiles TypeScript to both CommonJS (dist/cjs) and ESM (dist/esm) ``` -------------------------------- ### Filter nodes with filterNodes and filterNodesAsync Source: https://github.com/datocms/structured-text/blob/main/packages/utils/README.md Remove nodes that don't match a predicate. The example removes all code blocks and demonstrates async filtering with external validation for block items. ```javascript import { filterNodes, filterNodesAsync, isCode, isBlock, } from 'datocms-structured-text-utils'; // Remove all code blocks const withoutCode = filterNodes(structuredText, (node) => !isCode(node)); // Async filtering with external validation const validated = await filterNodesAsync(structuredText, async (node) => { if (isBlock(node)) { return await validateBlockItem(node.item); } return true; }); ``` -------------------------------- ### Lint and format Source: https://github.com/datocms/structured-text/blob/main/CLAUDE.md npm run lint runs ESLint on all .ts/.tsx files; npm run prettier formats all TypeScript and JSON files. A pre-commit hook runs pretty-quick --staged. ```bash npm run lint # ESLint check on all .ts/.tsx files npm run prettier # Format all TypeScript and JSON files ``` -------------------------------- ### Release packages with npm run release Source: https://github.com/datocms/structured-text/blob/main/README.md Releases packages: builds, tests, applies changesets, publishes to npm, and creates GitHub releases. ```sh npm run release ``` -------------------------------- ### Custom renderers for text, nodes, and marks Source: https://github.com/datocms/structured-text/blob/main/packages/to-html-string/README.md Shows how to pass custom renderers for text, nodes, and marks. Uses renderNodeRule and renderMarkRule to override heading and strong rendering. ```javascript import { render, renderNodeRule } from 'datocms-structured-text-to-html-string'; import { isHeading } from 'datocms-structured-text-utils'; const structuredText = { type: 'root', children: [ { type: 'heading', level: 1, content: [ { type: 'span', value: 'Hello world!', }, ], }, ], }; const options = { renderText: (text) => text.replace(/Hello/, 'Howdy'), customNodeRules: [ renderNodeRule( isHeading, ({ adapter: { renderNode }, node, children, key }) => { return renderNode(`h${node.level + 1}`, { key }, children); }, ), ], customMarkRules: [ renderMarkRule('strong', ({ adapter: { renderNode }, children, key }) => { return renderNode('b', { key }, children); }), ], }; render(document, options); // ->

Howdy world!

``` -------------------------------- ### Visit all nodes with forEachNode and forEachNodeAsync Source: https://github.com/datocms/structured-text/blob/main/packages/utils/README.md Uses pre-order traversal to visit every node in the tree. The synchronous version calls forEachNode with a callback receiving node, parent, and path; the asynchronous version uses forEachNodeAsync with an async callback. Requires a structuredText object and an optional processNode function. ```javascript import { forEachNode, forEachNodeAsync } from 'datocms-structured-text-utils'; // Synchronous traversal forEachNode(structuredText, (node, parent, path) => { console.log(`Node type: ${node.type}, Path: ${path.join('.')}`); }); // Asynchronous traversal await forEachNodeAsync(structuredText, async (node, parent, path) => { await processNode(node); }); ``` -------------------------------- ### Options Source: https://github.com/datocms/structured-text/blob/main/packages/html-to-structured-text/README.md Documentation for the options object accepted by all *ToStructuredText utilities. ```APIDOC ## [OPTIONS] htmlToStructuredText ### Description All `*ToStructuredText` utilities accept an optional `options` object as second argument to customize the transformation behavior. ### Options - **newlines** (boolean) - Optional - Whether to preserve newlines. - **handlers** (Record) - Optional - Override existing `hast` node handlers or add new ones. - **preprocess** ((hast: HastRoot) => void) - Optional - Allows to tweak the `hast` tree before transforming it to a `dast` document. - **allowedBlocks** (Array) - Optional - Array of allowed block nodes. - **allowedMarks** (Mark[]) - Optional - Array of allowed marks. - **allowedHeadingLevels** (Array<1 | 2 | 3 | 4 | 5 | 6>) - Optional - Array of allowed heading levels for 'heading' nodes. - **shared** (Record) - Optional - Properties shared across handler invocations via context.global. ### Example ```ts import type { Root as HastRoot } from 'hast'; type Options = Partial<{ newlines: boolean; handlers: Record; preprocess: (hast: HastRoot) => void; allowedBlocks: Array< BlockquoteType | CodeType | HeadingType | LinkType | ListType >; allowedMarks: Mark[]; allowedHeadingLevels: Array<1 | 2 | 3 | 4 | 5 | 6>; shared: Record; }>; ``` ``` -------------------------------- ### Custom rendering with render and renderNodeRule Source: https://github.com/datocms/structured-text/blob/main/packages/to-markdown/README.md Pass custom renderers for nodes and text to the render function. Import render and renderNodeRule from the package to override default node rendering behavior. ```javascript import { render, renderNodeRule } from 'datocms-structured-text'; ``` -------------------------------- ### Basic usage without schema Source: https://github.com/datocms/structured-text/blob/main/packages/to-html-string/README.md Renders a paragraph with strong and underline marks. Uses 'content' instead of 'children' and no schema field. ```javascript render({ type: 'root', children: [ { type: 'paragraph', content: [ { type: 'span', value: 'Hello', marks: ['strong'], }, { type: 'span', value: ' world!', marks: ['underline'], }, ], }, ], }); // ->

Hello world!

``` -------------------------------- ### inspect Source: https://github.com/datocms/structured-text/blob/main/packages/utils/README.md Renders a structured text document or node as an ASCII tree. It accepts an optional options object with a blockFormatter callback for custom formatting of block nodes. ```APIDOC ## inspect ### Description Renders a structured text document or node as an ASCII tree. It accepts an optional options object with a blockFormatter callback for custom formatting of block nodes. ### Method Function ### Signature `inspect(structuredText, options?)` ### Parameters - **structuredText** (object) - Required - The structured text document or node to render. - **options** (object) - Optional - Configuration options. - **blockFormatter** (function) - Optional - A callback to format block nodes. Receives the block item and maxWidth, returns a string. ### Request Example ```javascript import { inspect } from 'datocms-structured-text-utils'; const structuredText = { schema: 'dast', document: { type: 'root', children: [ { type: 'heading', level: 1, children: [{ type: 'span', value: 'Main Title' }], }, { type: 'paragraph', children: [ { type: 'span', value: 'This is a ' }, { type: 'span', marks: ['strong'], value: 'bold' }, { type: 'span', value: ' paragraph.' }, ], }, { type: 'block', item: 'block-123', }, ], }, }; console.log(inspect(structuredText)); ``` ### Response Example ``` ├ heading (level: 1) │ └ span "Main Title" ├ paragraph │ ├ span "This is a " │ ├ span (marks: strong) "bold" │ └ span " paragraph." └ block (item: "block-123") ``` ### Custom Block Formatting Example ```javascript import { inspect } from 'datocms-structured-text-utils'; const blockObject = { id: 'block-456', type: 'item', attributes: { title: 'Hero Section', subtitle: 'Welcome to our site', buttonText: 'Get Started', }, }; const tree = inspect(document, { blockFormatter: (item, maxWidth) => { if (typeof item === 'string') return `ID: ${item}`; return `id: ${item.id}\ntitle: ${item.attributes.title}`; }, }); console.log(tree); ``` ### Response Example (Custom Block Formatting) ``` ├ paragraph │ └ span "Content before block" ├ block │ id: 456 │ title: Hero Section └ paragraph └ span "Content after block" ``` ``` -------------------------------- ### Serialize, edit, and parse dastdown Source: https://github.com/datocms/structured-text/blob/main/packages/dastdown/README.md Shows the core workflow: serialize a structured text field to dastdown, edit it as plain text, then parse back and update the record. The comment shows the expected dastdown output for a simple document. ```js import { parse, serialize } from 'datocms-structured-text-dastdown'; // 1. fetch the record and turn its structured text field into dastdown const record = await client.items.find('article-id'); const text = serialize(record.body); // → # Title // // A paragraph about Acme Corp with **strong** text and a [link](https://example.com). // // > A quote. // {attribution="Anon"} // // // 2. edit as plain text — search/replace, regex, diff/merge, LLM rewrite, … const edited = text .replace(/Acme Corp/g, '**Acme Inc.**') // rename + bold every occurrence .replace(/^# (.+)$/m, '# $1 (2026 edition)'); // tweak the H1 // 3. parse back to dast and push the update await client.items.update('article-id', { body: parse(edited) }); ``` -------------------------------- ### render(structuredText, options?) Source: https://github.com/datocms/structured-text/blob/main/packages/to-markdown/README.md Converts a Structured Text document to a Markdown string. Accepts the document and optional rendering options for customizing node and mark rendering. ```APIDOC ## [FUNCTION] render(structuredText, options?) ### Description Converts a Structured Text document to a Markdown string. ### Method FUNCTION ### Endpoint render(structuredText, options?) ### Parameters #### Path Parameters - **structuredText** (Structured Text document) - Required - The Structured Text document (can be a full GraphQL response or a plain document) #### Query Parameters - **options** (object) - Optional - Rendering options - **customNodeRules** (Array) - Optional - Array of custom node rendering rules - **customMarkRules** (Array) - Optional - Array of custom mark rendering rules - **renderInlineRecord** (Function) - Optional - Function to render `inlineItem` nodes - **renderLinkToRecord** (Function) - Optional - Function to render `itemLink` nodes - **renderBlock** (Function) - Optional - Function to render `block` nodes - **renderInlineBlock** (Function) - Optional - Function to render `inlineBlock` nodes - **renderText** (Function) - Optional - Function to customize text rendering - **renderNode** (Function) - Optional - Function to customize node rendering - **renderFragment** (Function) - Optional - Function to customize fragment rendering ### Response #### Success Response (200) - **result** (string or null) - A Markdown string, or `null` if the input is empty. #### Response Example ```markdown # Example Markdown ``` ``` -------------------------------- ### Render a DAST document to Markdown Source: https://github.com/datocms/structured-text/blob/main/packages/to-markdown/README.md Basic usage of the render function with a DAST document, producing Markdown output. ```javascript import { render } from 'datocms-structured-text-to-markdown'; render({ schema: 'dast', document: { type: 'root', children: [ { type: 'heading', level: 1, children: [ { type: 'span', value: 'Hello world!', }, ], }, { type: 'paragraph', children: [ { type: 'span', value: 'This is a paragraph.', }, ], }, ], }, }); // -> # Hello world! // // This is a paragraph. ```