@relyio/sdk 0.10.0 → 0.12.0
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/CHANGELOG.md +135 -0
- package/dist/chunk-3DRDHXLY.js +680 -0
- package/dist/{chunk-2HP566NI.cjs → chunk-3MSFWXQL.cjs} +37 -65
- package/dist/{chunk-DC4QLAI3.cjs → chunk-DXCVO6M5.cjs} +46 -59
- package/dist/chunk-FI5VIF4M.cjs +686 -0
- package/dist/{chunk-2L5JUW7O.js → chunk-FRJEUAAF.js} +46 -59
- package/dist/{chunk-IGHYC2WM.js → chunk-POEEDYFM.js} +38 -65
- package/dist/client/index.cjs +3 -3
- package/dist/client/index.d.cts +5 -4
- package/dist/client/index.d.ts +5 -4
- package/dist/client/index.js +1 -1
- package/dist/{define-schema-rbTrXxNN.d.ts → define-schema-DgctHlI2.d.cts} +50 -229
- package/dist/{define-schema-W-0u1Jg1.d.cts → define-schema-mrEZbY1h.d.ts} +50 -229
- package/dist/{define-content-type-DfnTu26S.d.cts → include-paths-CL4gHv6I.d.cts} +1691 -739
- package/dist/{define-content-type-DfnTu26S.d.ts → include-paths-CrJNTsMl.d.ts} +1691 -739
- package/dist/{index-B9hDmCho.d.ts → index-B9RfZVF1.d.ts} +3 -2
- package/dist/{index-KuYgc7eG.d.cts → index-BrvEg6-A.d.cts} +110 -49
- package/dist/{index-rLEBSFvK.d.ts → index-Pw0onkJe.d.ts} +110 -49
- package/dist/{index-NnLCwSqF.d.cts → index-b-AkfTUv.d.cts} +3 -2
- package/dist/index.cjs +102 -85
- package/dist/index.d.cts +14 -10
- package/dist/index.d.ts +14 -10
- package/dist/index.js +4 -3
- package/dist/rich-text/index.cjs +29 -0
- package/dist/rich-text/index.d.cts +148 -0
- package/dist/rich-text/index.d.ts +148 -0
- package/dist/rich-text/index.js +4 -0
- package/dist/rich-text.d-rKmpgdGd.d.cts +200 -0
- package/dist/rich-text.d-rKmpgdGd.d.ts +200 -0
- package/dist/schema/index.cjs +34 -38
- package/dist/schema/index.d.cts +86 -38
- package/dist/schema/index.d.ts +86 -38
- package/dist/schema/index.js +1 -1
- package/dist/types/index.d.cts +3 -2
- package/dist/types/index.d.ts +3 -2
- package/package.json +8 -2
- package/dist/.tsbuildinfo +0 -1
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { w as RichTextValue, t as RichTextTable, c as RichTextCodeGroup, o as RichTextNode, r as RichTextSpan, m as RichTextMark } from '../rich-text.d-rKmpgdGd.cjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The one walk of a rich-text tree into elements, for every output (REL-1804).
|
|
5
|
+
*
|
|
6
|
+
* Rich text is a versioned tree (ADR 0013, `RichTextValue`). What each built-in looks like by
|
|
7
|
+
* default — which element a node or a mark becomes, with which attributes, holding what — is
|
|
8
|
+
* written here once, generic over the output: {@link richTextToHtml} hands it a target that builds
|
|
9
|
+
* strings, `@relyio/react`'s `<RichText>` one that builds React elements. So the HTML a server
|
|
10
|
+
* writes and the markup `<RichText>` renders are one rendering by construction, not two kept equal
|
|
11
|
+
* by hand; a test over the corpus holds them byte for byte.
|
|
12
|
+
*
|
|
13
|
+
* Three rules every output inherits from this walk:
|
|
14
|
+
*
|
|
15
|
+
* - **Every tag is a literal here, never data.** A heading's level picks from a fixed table, and a
|
|
16
|
+
* level the table lacks renders as a paragraph. An attribute's name is a literal too; its value is
|
|
17
|
+
* the target's to escape.
|
|
18
|
+
* - **A link to an unsafe scheme is not a link.** An `href` is drawn only when it is relative or
|
|
19
|
+
* `http:`, `https:`, `mailto:` or `tel:` ({@link safeRichTextHref}); any other scheme —
|
|
20
|
+
* `javascript:`, `data:`, `vbscript:`, … — renders the link's text with no anchor, and a site's
|
|
21
|
+
* own `link` renderer is never handed one.
|
|
22
|
+
* - **Version 1 grows by addition** (`rich-text-format.md`). The switches below cover every node
|
|
23
|
+
* and mark of the vocabulary this build knows, with no fallback: a type added to it fails to
|
|
24
|
+
* compile here until it is drawn. At run time a newer server can still send a `_type` this build
|
|
25
|
+
* does not know; such a node renders nothing, and such a mark renders its text unformatted. Never
|
|
26
|
+
* an error.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/** Every element the default rendering of rich text uses. A tag is always one of these literals. */
|
|
30
|
+
type RichTextTag = 'p' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'blockquote' | 'ul' | 'ol' | 'li' | 'input' | 'pre' | 'code' | 'figure' | 'figcaption' | 'div' | 'table' | 'thead' | 'tbody' | 'tr' | 'th' | 'td' | 'hr' | 'br' | 'a' | 'strong' | 'em' | 'u' | 's' | 'mark' | 'sub' | 'sup';
|
|
31
|
+
/** The elements that hold nothing and have no closing tag. */
|
|
32
|
+
declare const RICH_TEXT_VOID_TAGS: ReadonlySet<RichTextTag>;
|
|
33
|
+
/**
|
|
34
|
+
* An element's attributes, in the order they are written. A value is a string or a number, or
|
|
35
|
+
* `true` for a boolean attribute that is present. `style` is a CSS declaration list (`text-align:center`).
|
|
36
|
+
*/
|
|
37
|
+
type RichTextAttributes = Readonly<Record<string, string | number | true>>;
|
|
38
|
+
/** Every node a site may draw itself: all of them but a run of text, whose marks are drawn instead. */
|
|
39
|
+
type RichTextReplaceableNode = Exclude<RichTextNode, RichTextSpan>;
|
|
40
|
+
/** Where a node stands, for a renderer that draws it differently there. */
|
|
41
|
+
interface RichTextNodeContext {
|
|
42
|
+
/** Whether a table row or cell is in the table's header row; `false` for every other node. */
|
|
43
|
+
readonly header: boolean;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* What a walk of the tree builds with. {@link renderRichText} decides what each built-in becomes and
|
|
47
|
+
* calls `element` and `text` for it; `node` and `mark` are where an output may draw a node or a mark
|
|
48
|
+
* its own way, handed the default drawing to fall back on.
|
|
49
|
+
*/
|
|
50
|
+
interface RichTextTarget<Out> {
|
|
51
|
+
/** An element of the default rendering. `key` is the node's `_key` when the element is a node's own. */
|
|
52
|
+
element(tag: RichTextTag, attributes: RichTextAttributes | undefined, children: readonly Out[], key: string | undefined): Out;
|
|
53
|
+
/** Text, exactly as the tree holds it: the target escapes it. */
|
|
54
|
+
text(text: string): Out;
|
|
55
|
+
/**
|
|
56
|
+
* A node, given what it holds already drawn (`contents`) and the default drawing of it (`draw`).
|
|
57
|
+
* Return `draw(contents)` to draw it the default way.
|
|
58
|
+
*/
|
|
59
|
+
node(node: RichTextReplaceableNode, contents: readonly Out[], draw: (contents: readonly Out[]) => Out, context: RichTextNodeContext): Out;
|
|
60
|
+
/**
|
|
61
|
+
* A mark around `contents`, the runs it covers already drawn. A link reaches it only with a safe
|
|
62
|
+
* `href`. Return `draw(contents)` to draw it the default way.
|
|
63
|
+
*/
|
|
64
|
+
mark(mark: RichTextMark, contents: readonly Out[], draw: (contents: readonly Out[]) => Out): Out;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* What the walk renders: a `richText` field's tree, or a `table` or `code` field's value — exactly
|
|
68
|
+
* one of the tree's built-ins (REL-1806), drawn as the same block is inside a tree, so a table field
|
|
69
|
+
* on a page and a table in a doc render the same markup.
|
|
70
|
+
*/
|
|
71
|
+
type RichTextRenderable = RichTextValue | RichTextTable | RichTextCodeGroup;
|
|
72
|
+
/**
|
|
73
|
+
* Walk `value` into `target`'s output: one entry per block the tree holds, in order — or, for a
|
|
74
|
+
* `table` or `code` field's value, the one block it is. A block of a `_type` this build does not
|
|
75
|
+
* know adds nothing.
|
|
76
|
+
*/
|
|
77
|
+
declare function renderRichText<Out>(value: RichTextRenderable, target: RichTextTarget<Out>): Out[];
|
|
78
|
+
/**
|
|
79
|
+
* `href` as a link may carry it, or `undefined` when it must not be one: not a string, empty, or
|
|
80
|
+
* naming a scheme outside `http:`, `https:`, `mailto:` and `tel:`. The scheme is read the way a
|
|
81
|
+
* browser reads it — leading and trailing controls and spaces stripped, tabs and newlines removed
|
|
82
|
+
* anywhere — so `" java\tscript:"` is the `javascript:` it runs as. The `href` returned is the one
|
|
83
|
+
* given; escaping it is the output's.
|
|
84
|
+
*/
|
|
85
|
+
declare function safeRichTextHref(href: unknown): string | undefined;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Rich text as HTML (REL-1804): the default rendering ({@link renderRichText}) written as a string.
|
|
89
|
+
* No DOM and no dependency, so it runs the same in a browser, Node and a Worker.
|
|
90
|
+
*/
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* A rich-text value as HTML: every built-in drawn the way `<RichText>` from `@relyio/react` draws it
|
|
94
|
+
* with no components given, text and attributes escaped. `''` for an absent value. A `table` or
|
|
95
|
+
* `code` field's value — one of the tree's built-ins — is drawn as the same block inside a tree.
|
|
96
|
+
*
|
|
97
|
+
* - A link keeps its `href` only when it is relative or `http:`, `https:`, `mailto:` or `tel:`;
|
|
98
|
+
* one to any other scheme (`javascript:`, `data:`, …) renders its text with no anchor.
|
|
99
|
+
* - A node of a `_type` this version of the SDK does not know — content a newer server sends —
|
|
100
|
+
* renders nothing, and a mark it does not know leaves its text unformatted.
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* ```ts
|
|
104
|
+
* import { richTextToHtml } from '@relyio/sdk'
|
|
105
|
+
*
|
|
106
|
+
* const post = await relyio.content('post').findById('hello').execute()
|
|
107
|
+
* const html = richTextToHtml(post?.body) // '<h2>Getting started</h2><p>Install the <code>SDK</code>…</p>'
|
|
108
|
+
* ```
|
|
109
|
+
*/
|
|
110
|
+
declare function richTextToHtml(value: RichTextRenderable | undefined): string;
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Rich text as plain Markdown (REL-1804): GitHub Flavored Markdown — CommonMark with tables, task
|
|
114
|
+
* lists and strikethrough — which drops what it cannot hold. RelyIO Markdown, the form that
|
|
115
|
+
* round-trips through directives for what plain Markdown lacks, is a separate serializer (REL-1809).
|
|
116
|
+
*
|
|
117
|
+
* What plain Markdown cannot hold, and what becomes of it:
|
|
118
|
+
*
|
|
119
|
+
* - The marks `underline`, `highlight`, `subscript` and `superscript`: their text, unformatted.
|
|
120
|
+
* - A code block's `filename`, `label` and line range: dropped; a code group's tabs follow one
|
|
121
|
+
* another as fenced blocks.
|
|
122
|
+
* - A table's per-cell alignment: a column takes its first row's; a table with no header row gets
|
|
123
|
+
* an empty one, since a Markdown table has to have one; a cell's paragraphs and line breaks join
|
|
124
|
+
* with spaces.
|
|
125
|
+
* - A line break in a heading: a space. An empty paragraph or heading: nothing.
|
|
126
|
+
* - A link to a scheme other than `http:`, `https:`, `mailto:` and `tel:`: its text, as in HTML.
|
|
127
|
+
* - A node of a `_type` this version of the SDK does not know: nothing. A mark it does not know:
|
|
128
|
+
* its text, unformatted.
|
|
129
|
+
*
|
|
130
|
+
* Text is escaped so it reads back as the same text: `*`, `_`, a bracket or a backtick in a
|
|
131
|
+
* sentence is a character, not syntax.
|
|
132
|
+
*/
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* A rich-text value as plain Markdown, ending in a newline; `''` for an absent or empty value. What
|
|
136
|
+
* Markdown cannot hold is dropped, its text kept (see the module's notes). A `table` or `code`
|
|
137
|
+
* field's value — one of the tree's built-ins — is written as the same block inside a tree.
|
|
138
|
+
*
|
|
139
|
+
* @example
|
|
140
|
+
* ```ts
|
|
141
|
+
* import { richTextToMarkdown } from '@relyio/sdk'
|
|
142
|
+
*
|
|
143
|
+
* richTextToMarkdown(post.body) // '## Getting started\n\nInstall the `SDK`, then read the [**guide**](/docs/guide).\n'
|
|
144
|
+
* ```
|
|
145
|
+
*/
|
|
146
|
+
declare function richTextToMarkdown(value: RichTextRenderable | undefined): string;
|
|
147
|
+
|
|
148
|
+
export { RICH_TEXT_VOID_TAGS, type RichTextAttributes, type RichTextNodeContext, type RichTextRenderable, type RichTextReplaceableNode, type RichTextTag, type RichTextTarget, renderRichText, richTextToHtml, richTextToMarkdown, safeRichTextHref };
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { w as RichTextValue, t as RichTextTable, c as RichTextCodeGroup, o as RichTextNode, r as RichTextSpan, m as RichTextMark } from '../rich-text.d-rKmpgdGd.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The one walk of a rich-text tree into elements, for every output (REL-1804).
|
|
5
|
+
*
|
|
6
|
+
* Rich text is a versioned tree (ADR 0013, `RichTextValue`). What each built-in looks like by
|
|
7
|
+
* default — which element a node or a mark becomes, with which attributes, holding what — is
|
|
8
|
+
* written here once, generic over the output: {@link richTextToHtml} hands it a target that builds
|
|
9
|
+
* strings, `@relyio/react`'s `<RichText>` one that builds React elements. So the HTML a server
|
|
10
|
+
* writes and the markup `<RichText>` renders are one rendering by construction, not two kept equal
|
|
11
|
+
* by hand; a test over the corpus holds them byte for byte.
|
|
12
|
+
*
|
|
13
|
+
* Three rules every output inherits from this walk:
|
|
14
|
+
*
|
|
15
|
+
* - **Every tag is a literal here, never data.** A heading's level picks from a fixed table, and a
|
|
16
|
+
* level the table lacks renders as a paragraph. An attribute's name is a literal too; its value is
|
|
17
|
+
* the target's to escape.
|
|
18
|
+
* - **A link to an unsafe scheme is not a link.** An `href` is drawn only when it is relative or
|
|
19
|
+
* `http:`, `https:`, `mailto:` or `tel:` ({@link safeRichTextHref}); any other scheme —
|
|
20
|
+
* `javascript:`, `data:`, `vbscript:`, … — renders the link's text with no anchor, and a site's
|
|
21
|
+
* own `link` renderer is never handed one.
|
|
22
|
+
* - **Version 1 grows by addition** (`rich-text-format.md`). The switches below cover every node
|
|
23
|
+
* and mark of the vocabulary this build knows, with no fallback: a type added to it fails to
|
|
24
|
+
* compile here until it is drawn. At run time a newer server can still send a `_type` this build
|
|
25
|
+
* does not know; such a node renders nothing, and such a mark renders its text unformatted. Never
|
|
26
|
+
* an error.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/** Every element the default rendering of rich text uses. A tag is always one of these literals. */
|
|
30
|
+
type RichTextTag = 'p' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'blockquote' | 'ul' | 'ol' | 'li' | 'input' | 'pre' | 'code' | 'figure' | 'figcaption' | 'div' | 'table' | 'thead' | 'tbody' | 'tr' | 'th' | 'td' | 'hr' | 'br' | 'a' | 'strong' | 'em' | 'u' | 's' | 'mark' | 'sub' | 'sup';
|
|
31
|
+
/** The elements that hold nothing and have no closing tag. */
|
|
32
|
+
declare const RICH_TEXT_VOID_TAGS: ReadonlySet<RichTextTag>;
|
|
33
|
+
/**
|
|
34
|
+
* An element's attributes, in the order they are written. A value is a string or a number, or
|
|
35
|
+
* `true` for a boolean attribute that is present. `style` is a CSS declaration list (`text-align:center`).
|
|
36
|
+
*/
|
|
37
|
+
type RichTextAttributes = Readonly<Record<string, string | number | true>>;
|
|
38
|
+
/** Every node a site may draw itself: all of them but a run of text, whose marks are drawn instead. */
|
|
39
|
+
type RichTextReplaceableNode = Exclude<RichTextNode, RichTextSpan>;
|
|
40
|
+
/** Where a node stands, for a renderer that draws it differently there. */
|
|
41
|
+
interface RichTextNodeContext {
|
|
42
|
+
/** Whether a table row or cell is in the table's header row; `false` for every other node. */
|
|
43
|
+
readonly header: boolean;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* What a walk of the tree builds with. {@link renderRichText} decides what each built-in becomes and
|
|
47
|
+
* calls `element` and `text` for it; `node` and `mark` are where an output may draw a node or a mark
|
|
48
|
+
* its own way, handed the default drawing to fall back on.
|
|
49
|
+
*/
|
|
50
|
+
interface RichTextTarget<Out> {
|
|
51
|
+
/** An element of the default rendering. `key` is the node's `_key` when the element is a node's own. */
|
|
52
|
+
element(tag: RichTextTag, attributes: RichTextAttributes | undefined, children: readonly Out[], key: string | undefined): Out;
|
|
53
|
+
/** Text, exactly as the tree holds it: the target escapes it. */
|
|
54
|
+
text(text: string): Out;
|
|
55
|
+
/**
|
|
56
|
+
* A node, given what it holds already drawn (`contents`) and the default drawing of it (`draw`).
|
|
57
|
+
* Return `draw(contents)` to draw it the default way.
|
|
58
|
+
*/
|
|
59
|
+
node(node: RichTextReplaceableNode, contents: readonly Out[], draw: (contents: readonly Out[]) => Out, context: RichTextNodeContext): Out;
|
|
60
|
+
/**
|
|
61
|
+
* A mark around `contents`, the runs it covers already drawn. A link reaches it only with a safe
|
|
62
|
+
* `href`. Return `draw(contents)` to draw it the default way.
|
|
63
|
+
*/
|
|
64
|
+
mark(mark: RichTextMark, contents: readonly Out[], draw: (contents: readonly Out[]) => Out): Out;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* What the walk renders: a `richText` field's tree, or a `table` or `code` field's value — exactly
|
|
68
|
+
* one of the tree's built-ins (REL-1806), drawn as the same block is inside a tree, so a table field
|
|
69
|
+
* on a page and a table in a doc render the same markup.
|
|
70
|
+
*/
|
|
71
|
+
type RichTextRenderable = RichTextValue | RichTextTable | RichTextCodeGroup;
|
|
72
|
+
/**
|
|
73
|
+
* Walk `value` into `target`'s output: one entry per block the tree holds, in order — or, for a
|
|
74
|
+
* `table` or `code` field's value, the one block it is. A block of a `_type` this build does not
|
|
75
|
+
* know adds nothing.
|
|
76
|
+
*/
|
|
77
|
+
declare function renderRichText<Out>(value: RichTextRenderable, target: RichTextTarget<Out>): Out[];
|
|
78
|
+
/**
|
|
79
|
+
* `href` as a link may carry it, or `undefined` when it must not be one: not a string, empty, or
|
|
80
|
+
* naming a scheme outside `http:`, `https:`, `mailto:` and `tel:`. The scheme is read the way a
|
|
81
|
+
* browser reads it — leading and trailing controls and spaces stripped, tabs and newlines removed
|
|
82
|
+
* anywhere — so `" java\tscript:"` is the `javascript:` it runs as. The `href` returned is the one
|
|
83
|
+
* given; escaping it is the output's.
|
|
84
|
+
*/
|
|
85
|
+
declare function safeRichTextHref(href: unknown): string | undefined;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Rich text as HTML (REL-1804): the default rendering ({@link renderRichText}) written as a string.
|
|
89
|
+
* No DOM and no dependency, so it runs the same in a browser, Node and a Worker.
|
|
90
|
+
*/
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* A rich-text value as HTML: every built-in drawn the way `<RichText>` from `@relyio/react` draws it
|
|
94
|
+
* with no components given, text and attributes escaped. `''` for an absent value. A `table` or
|
|
95
|
+
* `code` field's value — one of the tree's built-ins — is drawn as the same block inside a tree.
|
|
96
|
+
*
|
|
97
|
+
* - A link keeps its `href` only when it is relative or `http:`, `https:`, `mailto:` or `tel:`;
|
|
98
|
+
* one to any other scheme (`javascript:`, `data:`, …) renders its text with no anchor.
|
|
99
|
+
* - A node of a `_type` this version of the SDK does not know — content a newer server sends —
|
|
100
|
+
* renders nothing, and a mark it does not know leaves its text unformatted.
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* ```ts
|
|
104
|
+
* import { richTextToHtml } from '@relyio/sdk'
|
|
105
|
+
*
|
|
106
|
+
* const post = await relyio.content('post').findById('hello').execute()
|
|
107
|
+
* const html = richTextToHtml(post?.body) // '<h2>Getting started</h2><p>Install the <code>SDK</code>…</p>'
|
|
108
|
+
* ```
|
|
109
|
+
*/
|
|
110
|
+
declare function richTextToHtml(value: RichTextRenderable | undefined): string;
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Rich text as plain Markdown (REL-1804): GitHub Flavored Markdown — CommonMark with tables, task
|
|
114
|
+
* lists and strikethrough — which drops what it cannot hold. RelyIO Markdown, the form that
|
|
115
|
+
* round-trips through directives for what plain Markdown lacks, is a separate serializer (REL-1809).
|
|
116
|
+
*
|
|
117
|
+
* What plain Markdown cannot hold, and what becomes of it:
|
|
118
|
+
*
|
|
119
|
+
* - The marks `underline`, `highlight`, `subscript` and `superscript`: their text, unformatted.
|
|
120
|
+
* - A code block's `filename`, `label` and line range: dropped; a code group's tabs follow one
|
|
121
|
+
* another as fenced blocks.
|
|
122
|
+
* - A table's per-cell alignment: a column takes its first row's; a table with no header row gets
|
|
123
|
+
* an empty one, since a Markdown table has to have one; a cell's paragraphs and line breaks join
|
|
124
|
+
* with spaces.
|
|
125
|
+
* - A line break in a heading: a space. An empty paragraph or heading: nothing.
|
|
126
|
+
* - A link to a scheme other than `http:`, `https:`, `mailto:` and `tel:`: its text, as in HTML.
|
|
127
|
+
* - A node of a `_type` this version of the SDK does not know: nothing. A mark it does not know:
|
|
128
|
+
* its text, unformatted.
|
|
129
|
+
*
|
|
130
|
+
* Text is escaped so it reads back as the same text: `*`, `_`, a bracket or a backtick in a
|
|
131
|
+
* sentence is a character, not syntax.
|
|
132
|
+
*/
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* A rich-text value as plain Markdown, ending in a newline; `''` for an absent or empty value. What
|
|
136
|
+
* Markdown cannot hold is dropped, its text kept (see the module's notes). A `table` or `code`
|
|
137
|
+
* field's value — one of the tree's built-ins — is written as the same block inside a tree.
|
|
138
|
+
*
|
|
139
|
+
* @example
|
|
140
|
+
* ```ts
|
|
141
|
+
* import { richTextToMarkdown } from '@relyio/sdk'
|
|
142
|
+
*
|
|
143
|
+
* richTextToMarkdown(post.body) // '## Getting started\n\nInstall the `SDK`, then read the [**guide**](/docs/guide).\n'
|
|
144
|
+
* ```
|
|
145
|
+
*/
|
|
146
|
+
declare function richTextToMarkdown(value: RichTextRenderable | undefined): string;
|
|
147
|
+
|
|
148
|
+
export { RICH_TEXT_VOID_TAGS, type RichTextAttributes, type RichTextNodeContext, type RichTextRenderable, type RichTextReplaceableNode, type RichTextTag, type RichTextTarget, renderRichText, richTextToHtml, richTextToMarkdown, safeRichTextHref };
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rich text's stored and served value: a tree we define (ADR 0013, REL-1803).
|
|
3
|
+
*
|
|
4
|
+
* A `richText` field holds one {@link RichTextValue} per locale — a documented, **versioned** JSON
|
|
5
|
+
* tree shaped like the editor's document: a quote and a list item hold blocks, lists nest, a text
|
|
6
|
+
* run names its marks. Every node carries `_type`; every node but a text run carries `_key`, unique
|
|
7
|
+
* within the field. It is not Portable Text (flat: a quote of two paragraphs becomes two quotes,
|
|
8
|
+
* nested lists become levels) and not TipTap's JSON (TipTap's node names and attributes would be
|
|
9
|
+
* our public API, and a TipTap upgrade a breaking change for customers). The vocabulary is written
|
|
10
|
+
* down for readers in `devtools/docs/guide/schema/field-types/rich-text-format.md`; this module is
|
|
11
|
+
* its one definition in code.
|
|
12
|
+
*
|
|
13
|
+
* **The version grows by addition.** {@link RICH_TEXT_VERSION} changes only when a node, a mark or
|
|
14
|
+
* an attribute is renamed, removed or reshaped. A new node type, a new mark, a new `list` style or a
|
|
15
|
+
* new optional attribute is not a version change — the docs set's built-ins (REL-1805: tables, task
|
|
16
|
+
* lists, code groups with tabs, highlight, sub- and superscript) arrived inside version 1, and P3b's
|
|
17
|
+
* entry links and declared blocks will, so a reader must treat a `_type` it does not know as content
|
|
18
|
+
* it cannot draw rather than as an error.
|
|
19
|
+
*
|
|
20
|
+
* **A field narrows the docs set** (REL-1805): its config's `structure`, `marks` and `multiline` are
|
|
21
|
+
* read by {@link richTextNarrowingOf}, held to on every write by {@link richTextNarrowingProblems}
|
|
22
|
+
* (the validation document's `x-richTextNarrowing` keyword), enforced in the editor by
|
|
23
|
+
* `@relyio/studio-core`'s `RichTextPolicy`, and applied by schema adaptation through
|
|
24
|
+
* {@link narrowRichText} when a field is narrowed over content it no longer allows.
|
|
25
|
+
*
|
|
26
|
+
* Who uses it: the projection writes and reads a live document by it (`@relyio/entry-projection`'s
|
|
27
|
+
* `./blocks`), the validation document holds a written value to it ({@link richTextProblems}), the
|
|
28
|
+
* write core keys a written value ({@link keyRichText}), the index embeds its text
|
|
29
|
+
* ({@link richTextPlainText}), and `@relyio/sdk` types a read by it (the types only, build-inlined
|
|
30
|
+
* through the package root).
|
|
31
|
+
*
|
|
32
|
+
* Dependency-free like `./declaration` (`__tests__/dependency-free.test.ts`): no import at all.
|
|
33
|
+
*/
|
|
34
|
+
/** The format's version. The stored value carries it, so a reader knows which vocabulary it holds. */
|
|
35
|
+
declare const RICH_TEXT_VERSION = 1;
|
|
36
|
+
/** The root's `_type`: what a value of a `richText` field is. */
|
|
37
|
+
declare const RICH_TEXT_TYPE = "richText";
|
|
38
|
+
/** A rich-text field's value: the root of the tree. The root is the field, so it has no `_key`. */
|
|
39
|
+
interface RichTextValue {
|
|
40
|
+
readonly _type: typeof RICH_TEXT_TYPE;
|
|
41
|
+
readonly version: typeof RICH_TEXT_VERSION;
|
|
42
|
+
readonly children: readonly RichTextBlock[];
|
|
43
|
+
}
|
|
44
|
+
/** What every node but a text run carries: its identity within the field (design decision 10). */
|
|
45
|
+
interface RichTextKeyed {
|
|
46
|
+
readonly _key: string;
|
|
47
|
+
}
|
|
48
|
+
/** A paragraph: inline content. */
|
|
49
|
+
interface RichTextParagraph extends RichTextKeyed {
|
|
50
|
+
readonly _type: 'paragraph';
|
|
51
|
+
readonly children: readonly RichTextInline[];
|
|
52
|
+
}
|
|
53
|
+
/** The heading levels, as numbers. */
|
|
54
|
+
declare const RICH_TEXT_HEADING_LEVELS: readonly [1, 2, 3, 4, 5, 6];
|
|
55
|
+
/** A heading of `level` 1 to 6: inline content. */
|
|
56
|
+
interface RichTextHeading extends RichTextKeyed {
|
|
57
|
+
readonly _type: 'heading';
|
|
58
|
+
readonly level: (typeof RICH_TEXT_HEADING_LEVELS)[number];
|
|
59
|
+
readonly children: readonly RichTextInline[];
|
|
60
|
+
}
|
|
61
|
+
/** A quote: one block or more — a quote of two paragraphs is one quote. */
|
|
62
|
+
interface RichTextQuote extends RichTextKeyed {
|
|
63
|
+
readonly _type: 'quote';
|
|
64
|
+
readonly children: readonly RichTextBlock[];
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* The list styles. Version 1 held `bullet` and `numbered`; REL-1805 added `task`, whose items each
|
|
68
|
+
* carry `checked`, without a version change.
|
|
69
|
+
*/
|
|
70
|
+
declare const RICH_TEXT_LIST_STYLES: readonly ['bullet', 'numbered', 'task'];
|
|
71
|
+
type RichTextListStyle = (typeof RICH_TEXT_LIST_STYLES)[number];
|
|
72
|
+
/**
|
|
73
|
+
* A list: one item or more. `start` is a numbered list's first number, present only when it is not
|
|
74
|
+
* `1`. Lists nest: an item holds blocks, and a list is a block.
|
|
75
|
+
*/
|
|
76
|
+
interface RichTextList extends RichTextKeyed {
|
|
77
|
+
readonly _type: 'list';
|
|
78
|
+
readonly style: RichTextListStyle;
|
|
79
|
+
readonly start?: number;
|
|
80
|
+
readonly children: readonly RichTextListItem[];
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* A list's item: blocks, the first of them a paragraph (the editor's model, `paragraph block*`).
|
|
84
|
+
* `checked` is a task list's item's, and present on every one of them: whether its task is done.
|
|
85
|
+
* An item of a bullet or a numbered list carries none.
|
|
86
|
+
*/
|
|
87
|
+
interface RichTextListItem extends RichTextKeyed {
|
|
88
|
+
readonly _type: 'listItem';
|
|
89
|
+
readonly checked?: boolean;
|
|
90
|
+
readonly children: readonly RichTextBlock[];
|
|
91
|
+
}
|
|
92
|
+
/** The lines of a file a code block is, 1-based and inclusive: the docs' code citations. */
|
|
93
|
+
interface RichTextCodeLines {
|
|
94
|
+
readonly start: number;
|
|
95
|
+
readonly end: number;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* A block of code: its text exactly, newlines included, with no marks, and the `language` it is
|
|
99
|
+
* written in when one is named. Standing in a code group it is one of the group's tabs, and `label`
|
|
100
|
+
* is the tab's name; `filename` is the file it shows and `lines` which of that file's lines. All
|
|
101
|
+
* three are optional, alone or in a group (REL-1805).
|
|
102
|
+
*/
|
|
103
|
+
interface RichTextCodeBlock extends RichTextKeyed {
|
|
104
|
+
readonly _type: 'codeBlock';
|
|
105
|
+
readonly language?: string;
|
|
106
|
+
readonly label?: string;
|
|
107
|
+
readonly filename?: string;
|
|
108
|
+
readonly lines?: RichTextCodeLines;
|
|
109
|
+
readonly text: string;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Code with tabs: one code block or more, each a tab — the same snippet for another language,
|
|
113
|
+
* package manager or client (REL-1805). Each tab's text is its own, so two people typing in two tabs
|
|
114
|
+
* keep both. A `code` field holds this node as its value (REL-1806).
|
|
115
|
+
*/
|
|
116
|
+
interface RichTextCodeGroup extends RichTextKeyed {
|
|
117
|
+
readonly _type: 'codeGroup';
|
|
118
|
+
readonly children: readonly RichTextCodeBlock[];
|
|
119
|
+
}
|
|
120
|
+
/** How a table cell's text is aligned. Absent is the reader's default. */
|
|
121
|
+
declare const RICH_TEXT_CELL_ALIGNMENTS: readonly ['left', 'center', 'right'];
|
|
122
|
+
type RichTextCellAlignment = (typeof RICH_TEXT_CELL_ALIGNMENTS)[number];
|
|
123
|
+
/**
|
|
124
|
+
* A table: one row or more, every row holding the same number of cells (REL-1805). `headerRow` is
|
|
125
|
+
* present, `true`, when the first row is the table's header. Cells hold formatted text, and nothing
|
|
126
|
+
* merges cells. A `table` field holds this node as its value (REL-1806).
|
|
127
|
+
*/
|
|
128
|
+
interface RichTextTable extends RichTextKeyed {
|
|
129
|
+
readonly _type: 'table';
|
|
130
|
+
readonly headerRow?: true;
|
|
131
|
+
readonly children: readonly RichTextTableRow[];
|
|
132
|
+
}
|
|
133
|
+
/** A table's row: one cell or more. */
|
|
134
|
+
interface RichTextTableRow extends RichTextKeyed {
|
|
135
|
+
readonly _type: 'tableRow';
|
|
136
|
+
readonly children: readonly RichTextTableCell[];
|
|
137
|
+
}
|
|
138
|
+
/** A table's cell: one paragraph or more of formatted text, and its alignment when one is set. */
|
|
139
|
+
interface RichTextTableCell extends RichTextKeyed {
|
|
140
|
+
readonly _type: 'tableCell';
|
|
141
|
+
readonly align?: RichTextCellAlignment;
|
|
142
|
+
readonly children: readonly RichTextParagraph[];
|
|
143
|
+
}
|
|
144
|
+
/** A horizontal rule between blocks. */
|
|
145
|
+
interface RichTextDivider extends RichTextKeyed {
|
|
146
|
+
readonly _type: 'divider';
|
|
147
|
+
}
|
|
148
|
+
/** A block: what a field, a quote and a list item hold. */
|
|
149
|
+
type RichTextBlock = RichTextParagraph | RichTextHeading | RichTextQuote | RichTextList | RichTextCodeBlock | RichTextCodeGroup | RichTextTable | RichTextDivider;
|
|
150
|
+
/**
|
|
151
|
+
* A run of text: its characters and the marks on all of them. `marks` is absent when there are
|
|
152
|
+
* none, and in {@link RICH_TEXT_MARK_TYPES}' order when there are, each type at most once. A text
|
|
153
|
+
* run has no `_key`: it is not addressable apart from the block that holds it, and the live document
|
|
154
|
+
* gives it no identity to keep.
|
|
155
|
+
*/
|
|
156
|
+
interface RichTextSpan {
|
|
157
|
+
readonly _type: 'text';
|
|
158
|
+
readonly text: string;
|
|
159
|
+
readonly marks?: readonly RichTextMark[];
|
|
160
|
+
}
|
|
161
|
+
/** A line break inside a paragraph or a heading. */
|
|
162
|
+
interface RichTextLineBreak extends RichTextKeyed {
|
|
163
|
+
readonly _type: 'lineBreak';
|
|
164
|
+
}
|
|
165
|
+
/** Inline content: what a paragraph and a heading hold. */
|
|
166
|
+
type RichTextInline = RichTextSpan | RichTextLineBreak;
|
|
167
|
+
/**
|
|
168
|
+
* The marks, in the order a run holds them: the link first, so a renderer that nests marks in this
|
|
169
|
+
* order wraps the formatting in the anchor. REL-1805 added highlight, subscript and superscript
|
|
170
|
+
* after the first six, and P3b adds the entry link, without a version change.
|
|
171
|
+
*/
|
|
172
|
+
declare const RICH_TEXT_MARK_TYPES: readonly ['link', 'bold', 'italic', 'underline', 'strike', 'code', 'highlight', 'subscript', 'superscript'];
|
|
173
|
+
type RichTextMarkType = (typeof RICH_TEXT_MARK_TYPES)[number];
|
|
174
|
+
/**
|
|
175
|
+
* A link to a URL. `href` is all a reader is given: whether it opens a new tab and which `rel` it
|
|
176
|
+
* carries are the site's rendering decisions, not content (the editor's defaults for them are not
|
|
177
|
+
* stored), and a link's title was dropped before the tree existed (REL-1942).
|
|
178
|
+
*/
|
|
179
|
+
interface RichTextLinkMark {
|
|
180
|
+
readonly _type: 'link';
|
|
181
|
+
readonly href: string;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* A mark: formatting by name, or a link. `code` holds no other mark beside it, and `subscript` and
|
|
185
|
+
* `superscript` are never on one run together.
|
|
186
|
+
*/
|
|
187
|
+
type RichTextMark = RichTextLinkMark | {
|
|
188
|
+
readonly _type: Exclude<RichTextMarkType, 'link'>;
|
|
189
|
+
};
|
|
190
|
+
/** Any node of the tree below the root. */
|
|
191
|
+
type RichTextNode = RichTextBlock | RichTextListItem | RichTextTableRow | RichTextTableCell | RichTextInline;
|
|
192
|
+
/**
|
|
193
|
+
* The built-in blocks a field's `structure` names (REL-1805): every block but the paragraph, which
|
|
194
|
+
* every field holds. A list is named by its style, since a field may want bullets and no tasks; a
|
|
195
|
+
* code group's tabs come with the group, whether or not `codeBlock` is named.
|
|
196
|
+
*/
|
|
197
|
+
declare const RICH_TEXT_STRUCTURES: readonly ['heading', 'quote', 'bulletList', 'numberedList', 'taskList', 'codeBlock', 'codeGroup', 'table', 'divider'];
|
|
198
|
+
type RichTextStructure = (typeof RICH_TEXT_STRUCTURES)[number];
|
|
199
|
+
|
|
200
|
+
export type { RichTextBlock as R, RichTextCellAlignment as a, RichTextCodeBlock as b, RichTextCodeGroup as c, RichTextCodeLines as d, RichTextDivider as e, RichTextHeading as f, RichTextInline as g, RichTextLineBreak as h, RichTextLinkMark as i, RichTextList as j, RichTextListItem as k, RichTextListStyle as l, RichTextMark as m, RichTextMarkType as n, RichTextNode as o, RichTextParagraph as p, RichTextQuote as q, RichTextSpan as r, RichTextStructure as s, RichTextTable as t, RichTextTableCell as u, RichTextTableRow as v, RichTextValue as w };
|