@platecms/delta-cast 0.6.0 → 0.8.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/package.json +3 -4
- package/src/lib/invalid-cast.error.ts +6 -0
- package/src/lib/normalize-cast.spec.ts +2123 -0
- package/src/lib/normalize-cast.ts +390 -0
- package/src/lib/schemas/schema.json +1 -0
- package/src/lib/schemas/schema.ts +234 -0
- package/src/lib/validate-cast.spec.ts +324 -0
- package/src/lib/validate-cast.ts +198 -0
- package/src/index.js +0 -7
- package/src/index.js.map +0 -1
- package/src/lib/invalid-cast.error.d.ts +0 -3
- package/src/lib/invalid-cast.error.js +0 -11
- package/src/lib/invalid-cast.error.js.map +0 -1
- package/src/lib/normalize-cast.d.ts +0 -9
- package/src/lib/normalize-cast.js +0 -190
- package/src/lib/normalize-cast.js.map +0 -1
- package/src/lib/schemas/schema.d.ts +0 -105
- package/src/lib/schemas/schema.js +0 -3
- package/src/lib/schemas/schema.js.map +0 -1
- package/src/lib/validate-cast.d.ts +0 -2
- package/src/lib/validate-cast.js +0 -149
- package/src/lib/validate-cast.js.map +0 -1
- /package/src/{index.d.ts → index.ts} +0 -0
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
import { Content, Parent, Root } from "./schemas/schema";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Formatting node priority for nesting order (lower number = higher priority)
|
|
5
|
+
* This constant should be used across all packages to ensure consistent formatting hierarchy.
|
|
6
|
+
*/
|
|
7
|
+
export const FORMATTING_PRIORITY = {
|
|
8
|
+
bold: 1,
|
|
9
|
+
italic: 2,
|
|
10
|
+
underline: 3,
|
|
11
|
+
strikethrough: 4,
|
|
12
|
+
highlight: 5,
|
|
13
|
+
} as const;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Type guard to check if a node has children
|
|
17
|
+
*/
|
|
18
|
+
function hasChildren(node: Content | Parent): node is Content & { children: Content[] } {
|
|
19
|
+
return "children" in node && Array.isArray((node as { children: unknown }).children);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Type guard to check if a node is a formatting node
|
|
24
|
+
*/
|
|
25
|
+
function isFormattingNode(node: Content): boolean {
|
|
26
|
+
const formattingTypes = ["bold", "italic", "underline", "strikethrough", "highlight"];
|
|
27
|
+
return formattingTypes.includes(node.type);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Determines if two nodes can be merged
|
|
32
|
+
*/
|
|
33
|
+
function canMerge(node1: Content, node2: Content): boolean {
|
|
34
|
+
// Formatting nodes: merge if same type and mergeable
|
|
35
|
+
const mergeableTypes = ["bold", "italic", "underline", "strikethrough", "highlight", "text"];
|
|
36
|
+
if (mergeableTypes.includes(node1.type) && node1.type === node2.type) {
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Merges two nodes by combining their content
|
|
45
|
+
*/
|
|
46
|
+
function mergeNodes(source: Content, target: Content): void {
|
|
47
|
+
if (source.type === "text" && target.type === "text") {
|
|
48
|
+
// Concatenate text values
|
|
49
|
+
target.value = source.value + target.value;
|
|
50
|
+
} else if (source.type === target.type && hasChildren(source) && hasChildren(target)) {
|
|
51
|
+
// Combine children arrays for formatting nodes
|
|
52
|
+
const sourceWithChildren = source as Content & { children: Content[] };
|
|
53
|
+
const targetWithChildren = target as Content & { children: Content[] };
|
|
54
|
+
targetWithChildren.children = [...sourceWithChildren.children, ...targetWithChildren.children];
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Determines if a child formatting node should be above its parent in the hierarchy
|
|
60
|
+
*/
|
|
61
|
+
function shouldChildBeAboveParent(childType: string, parentType: string): boolean {
|
|
62
|
+
const childPriority = FORMATTING_PRIORITY[childType as keyof typeof FORMATTING_PRIORITY] || 999;
|
|
63
|
+
const parentPriority = FORMATTING_PRIORITY[parentType as keyof typeof FORMATTING_PRIORITY] || 999;
|
|
64
|
+
|
|
65
|
+
return childPriority < parentPriority;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Splits a parent node into separate nodes while preserving other grandparent children.
|
|
70
|
+
* Gets all the siblings before and after the child, and creates at most two new parent nodes which are inserted
|
|
71
|
+
* before and after the original parent node in the grandparent node, containing the original before and after children respectively.
|
|
72
|
+
* Example:
|
|
73
|
+
* Input:
|
|
74
|
+
* {
|
|
75
|
+
* type: 'italic',
|
|
76
|
+
* children: [
|
|
77
|
+
* { type: 'text', value: 'Another parent' },
|
|
78
|
+
* { type: 'bold', children: [
|
|
79
|
+
* { type: 'text', value: 'Before' },
|
|
80
|
+
* { type: 'text', value: 'Child node' },
|
|
81
|
+
* { type: 'text', value: 'After' }
|
|
82
|
+
* ] },
|
|
83
|
+
* { type: 'text', value: 'Even more parents' }
|
|
84
|
+
* ]
|
|
85
|
+
* }
|
|
86
|
+
* Output:
|
|
87
|
+
* {
|
|
88
|
+
* type: 'italic',
|
|
89
|
+
* children: [
|
|
90
|
+
* { type: 'text', value: 'Another parent' },
|
|
91
|
+
* { type: 'bold', children: [
|
|
92
|
+
* { type: 'text', value: 'Before' },
|
|
93
|
+
* ] },
|
|
94
|
+
* { type: 'bold', children: [
|
|
95
|
+
* { type: 'text', value: 'Child node' },
|
|
96
|
+
* ] },
|
|
97
|
+
* { type: 'bold', children: [
|
|
98
|
+
* { type: 'text', value: 'After' },
|
|
99
|
+
* ] },
|
|
100
|
+
* { type: 'text', value: 'Even more parents' }
|
|
101
|
+
* ]
|
|
102
|
+
* }
|
|
103
|
+
* @param grandParent
|
|
104
|
+
* @param parent
|
|
105
|
+
* @param child
|
|
106
|
+
* @param parentIndexInGrandParent
|
|
107
|
+
* @param childIndexInParent
|
|
108
|
+
* @returns The number of new parent nodes inserted before the original parent node
|
|
109
|
+
*/
|
|
110
|
+
function splitParentIntoSeparateNodes(
|
|
111
|
+
grandParent: Parent,
|
|
112
|
+
parent: Parent,
|
|
113
|
+
child: Parent,
|
|
114
|
+
parentIndexInGrandParent: number,
|
|
115
|
+
childIndexInParent: number,
|
|
116
|
+
): number {
|
|
117
|
+
const siblingsBeforeChild = parent.children.slice(0, childIndexInParent);
|
|
118
|
+
const siblingsAfterChild = parent.children.slice(childIndexInParent + 1);
|
|
119
|
+
|
|
120
|
+
let insertionOffset = 0;
|
|
121
|
+
if (siblingsBeforeChild.length > 0) {
|
|
122
|
+
const newBeforeParent: Parent = { ...parent, children: siblingsBeforeChild };
|
|
123
|
+
grandParent.children.splice(parentIndexInGrandParent, 0, newBeforeParent as Content);
|
|
124
|
+
insertionOffset = 1;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (siblingsAfterChild.length > 0) {
|
|
128
|
+
const newAfterParent: Parent = { ...parent, children: siblingsAfterChild };
|
|
129
|
+
grandParent.children.splice(parentIndexInGrandParent + 1 + insertionOffset, 0, newAfterParent as Content);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
parent.children = [child as Content];
|
|
133
|
+
|
|
134
|
+
return insertionOffset;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Processes a formatting child to determine if it should be flipped with its parent.
|
|
139
|
+
* This assumes that both the parent and child are formatting nodes.
|
|
140
|
+
*/
|
|
141
|
+
function processFormattingChild(
|
|
142
|
+
grandParent: Parent,
|
|
143
|
+
parent: Parent,
|
|
144
|
+
child: Parent,
|
|
145
|
+
parentIndexInGrandParent: number,
|
|
146
|
+
childIndexInParent: number,
|
|
147
|
+
): boolean {
|
|
148
|
+
if (!shouldChildBeAboveParent(child.type, parent.type)) {
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
let parentIndexInGrandParentOffset = 0;
|
|
153
|
+
if (parent.children.length > 1) {
|
|
154
|
+
parentIndexInGrandParentOffset += splitParentIntoSeparateNodes(
|
|
155
|
+
grandParent,
|
|
156
|
+
parent,
|
|
157
|
+
child,
|
|
158
|
+
parentIndexInGrandParent,
|
|
159
|
+
childIndexInParent,
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
parent.children = child.children;
|
|
164
|
+
child.children = [parent as Content];
|
|
165
|
+
grandParent.children[parentIndexInGrandParent + parentIndexInGrandParentOffset] = child as Content;
|
|
166
|
+
return true;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Single pass of the bubble sort algorithm for formatting nodes
|
|
171
|
+
*/
|
|
172
|
+
function bubbleFormattingNodes(node: Parent, parent?: Parent, nodeIndexInParent?: number): boolean {
|
|
173
|
+
let hasChanges = false;
|
|
174
|
+
|
|
175
|
+
if (!hasChildren(node)) {
|
|
176
|
+
return hasChanges;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// DFS: process children first
|
|
180
|
+
for (let i = 0; i < node.children.length; i++) {
|
|
181
|
+
const child = node.children[i];
|
|
182
|
+
if (hasChildren(child)) {
|
|
183
|
+
hasChanges = bubbleFormattingNodes(child, node, i) || hasChanges;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// If not a formatting node, return
|
|
188
|
+
if (!isFormattingNode(node)) {
|
|
189
|
+
return hasChanges;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// If no parent is provided, we are at the root, and we don't need to check for formatting nodes
|
|
193
|
+
if (!parent || nodeIndexInParent === undefined) {
|
|
194
|
+
return hasChanges;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
for (let i = 0; i < node.children.length; i++) {
|
|
198
|
+
const child = node.children[i];
|
|
199
|
+
if (isFormattingNode(child) && hasChildren(child)) {
|
|
200
|
+
hasChanges = processFormattingChild(parent, node, child, nodeIndexInParent, i) || hasChanges;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return hasChanges;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Determines if a node should be removed because it's empty
|
|
209
|
+
*/
|
|
210
|
+
function shouldRemoveEmptyNode(node: Content): boolean {
|
|
211
|
+
// Only remove empty formatting (inline) nodes
|
|
212
|
+
if (!isFormattingNode(node)) {
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// For formatting nodes with children, check if they're empty
|
|
217
|
+
if (!hasChildren(node) || node.children.length === 0) {
|
|
218
|
+
return true;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Merges adjacent nodes that can be combined (text nodes and same-type formatting nodes)
|
|
226
|
+
* Example:
|
|
227
|
+
* Input:
|
|
228
|
+
* {
|
|
229
|
+
* type: 'root',
|
|
230
|
+
* children: [
|
|
231
|
+
* { type: 'text', value: 'Hello' },
|
|
232
|
+
* { type: 'text', value: ' world' }
|
|
233
|
+
* ]
|
|
234
|
+
* }
|
|
235
|
+
* Output:
|
|
236
|
+
* {
|
|
237
|
+
* type: 'root',
|
|
238
|
+
* children: [
|
|
239
|
+
* { type: 'text', value: 'Hello world' }
|
|
240
|
+
* ]
|
|
241
|
+
* }
|
|
242
|
+
*/
|
|
243
|
+
function mergeAdjacentNodes(node: Parent): boolean {
|
|
244
|
+
let hasChanges = false;
|
|
245
|
+
|
|
246
|
+
// Process current level
|
|
247
|
+
for (let i = 0; i < node.children.length - 1; i++) {
|
|
248
|
+
const current = node.children[i];
|
|
249
|
+
const next = node.children[i + 1];
|
|
250
|
+
|
|
251
|
+
if (canMerge(current, next)) {
|
|
252
|
+
// Merge current into next, remove current
|
|
253
|
+
mergeNodes(current, next);
|
|
254
|
+
node.children.splice(i, 1);
|
|
255
|
+
hasChanges = true;
|
|
256
|
+
i--; // Check the same position again since we removed an element
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Recursively process children
|
|
261
|
+
for (const child of node.children) {
|
|
262
|
+
if (hasChildren(child)) {
|
|
263
|
+
hasChanges = mergeAdjacentNodes(child) || hasChanges;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return hasChanges;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Reorders formatting nodes to follow the standard hierarchy using bubble sort approach
|
|
272
|
+
*/
|
|
273
|
+
function reorderFormattingNodes(node: Parent): boolean {
|
|
274
|
+
let hasChanges = true;
|
|
275
|
+
let anyChanges = false;
|
|
276
|
+
|
|
277
|
+
// Keep bubbling until no more changes (like bubble sort)
|
|
278
|
+
while (hasChanges) {
|
|
279
|
+
hasChanges = false;
|
|
280
|
+
hasChanges = bubbleFormattingNodes(node) || hasChanges;
|
|
281
|
+
if (hasChanges) {
|
|
282
|
+
anyChanges = true;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
return anyChanges;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Removes duplicate formatting nodes using bottom-up consolidation approach
|
|
291
|
+
*/
|
|
292
|
+
function removeDuplicateFormatting(
|
|
293
|
+
node: Parent,
|
|
294
|
+
ancestorsFormattingNodeTypes: string[],
|
|
295
|
+
parent?: Parent,
|
|
296
|
+
nodeIndexInParent?: number,
|
|
297
|
+
): boolean {
|
|
298
|
+
let hasChanges = false;
|
|
299
|
+
|
|
300
|
+
if (!hasChildren(node)) {
|
|
301
|
+
return hasChanges;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// Create new array with current node's type if it's a formatting node
|
|
305
|
+
const newAncestorsFormattingNodeTypes = isFormattingNode(node)
|
|
306
|
+
? [...ancestorsFormattingNodeTypes, node.type]
|
|
307
|
+
: ancestorsFormattingNodeTypes;
|
|
308
|
+
|
|
309
|
+
// DFS: process children first
|
|
310
|
+
for (let i = 0; i < node.children.length; i++) {
|
|
311
|
+
const child = node.children[i];
|
|
312
|
+
if (hasChildren(child)) {
|
|
313
|
+
hasChanges = removeDuplicateFormatting(child, newAncestorsFormattingNodeTypes, node, i) || hasChanges;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
if (!parent || nodeIndexInParent === undefined) {
|
|
318
|
+
return hasChanges;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Then process current level for duplicate formatting
|
|
322
|
+
if (ancestorsFormattingNodeTypes.includes(node.type)) {
|
|
323
|
+
parent.children.splice(nodeIndexInParent, 1, ...node.children);
|
|
324
|
+
hasChanges = true;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
return hasChanges;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Removes empty nodes from the CAST tree
|
|
332
|
+
*/
|
|
333
|
+
function cleanupEmptyNodes(node: Parent): boolean {
|
|
334
|
+
let hasChanges = false;
|
|
335
|
+
|
|
336
|
+
if (!hasChildren(node)) {
|
|
337
|
+
return hasChanges;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// DFS: process children first
|
|
341
|
+
for (let i = node.children.length - 1; i >= 0; i--) {
|
|
342
|
+
const child = node.children[i];
|
|
343
|
+
if (hasChildren(child)) {
|
|
344
|
+
hasChanges = cleanupEmptyNodes(child) || hasChanges;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Then process current level - remove empty children
|
|
349
|
+
// Iterate backwards to avoid index issues when removing items
|
|
350
|
+
for (let i = node.children.length - 1; i >= 0; i--) {
|
|
351
|
+
const child = node.children[i];
|
|
352
|
+
|
|
353
|
+
if (shouldRemoveEmptyNode(child)) {
|
|
354
|
+
node.children.splice(i, 1);
|
|
355
|
+
hasChanges = true;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
return hasChanges;
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Normalizes a CAST tree to ensure it is in a consistent and predictable state.
|
|
363
|
+
* This function applies various normalization rules to merge equivalent nodes,
|
|
364
|
+
* reorder formatting, and clean up empty structures.
|
|
365
|
+
*
|
|
366
|
+
* @param root - The CAST root node to normalize
|
|
367
|
+
* @returns A normalized copy of the CAST tree
|
|
368
|
+
*/
|
|
369
|
+
export function normalizeCast(root: Root): Root {
|
|
370
|
+
let hasChanges = true;
|
|
371
|
+
const currentRoot = JSON.parse(JSON.stringify(root)) as Root;
|
|
372
|
+
|
|
373
|
+
while (hasChanges) {
|
|
374
|
+
hasChanges = false;
|
|
375
|
+
|
|
376
|
+
// Pass 1: Merge adjacent nodes
|
|
377
|
+
hasChanges = mergeAdjacentNodes(currentRoot) || hasChanges;
|
|
378
|
+
|
|
379
|
+
// Pass 2: Reorder formatting nodes
|
|
380
|
+
hasChanges = reorderFormattingNodes(currentRoot) || hasChanges;
|
|
381
|
+
|
|
382
|
+
// Pass 3: Remove duplicate formatting
|
|
383
|
+
hasChanges = removeDuplicateFormatting(currentRoot, []) || hasChanges;
|
|
384
|
+
|
|
385
|
+
// Pass 4: Clean up empty nodes
|
|
386
|
+
hasChanges = cleanupEmptyNodes(currentRoot) || hasChanges;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
return currentRoot;
|
|
390
|
+
}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { Node, Literal as UnistLiteral, Parent as UnistParent } from "unist";
|
|
2
|
+
|
|
3
|
+
export type Content = BlockContent | InlineContent;
|
|
4
|
+
|
|
5
|
+
export type BlockContent = BlockContentMap[keyof BlockContentMap];
|
|
6
|
+
export type InlineContent = InlineContentMap[keyof InlineContentMap];
|
|
7
|
+
|
|
8
|
+
export interface BlockContentMap {
|
|
9
|
+
paragraph: Paragraph;
|
|
10
|
+
heading: Heading;
|
|
11
|
+
list: List;
|
|
12
|
+
// List item should not be used anywhere except in the list's children
|
|
13
|
+
listItem: ListItem;
|
|
14
|
+
blockquote: Blockquote;
|
|
15
|
+
code: Code;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface InlineContentMap {
|
|
19
|
+
text: Text;
|
|
20
|
+
bold: Bold;
|
|
21
|
+
italic: Italic;
|
|
22
|
+
underline: Underline;
|
|
23
|
+
strikethrough: Strikethrough;
|
|
24
|
+
inlineCode: InlineCode;
|
|
25
|
+
highlight: Highlight;
|
|
26
|
+
contentValue: InterpolatedContentValue;
|
|
27
|
+
externalLink: ExternalLink;
|
|
28
|
+
internalLink: InternalLink;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface Parent extends UnistParent {
|
|
32
|
+
children: Content[];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface Literal extends UnistLiteral {
|
|
36
|
+
value: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/*
|
|
40
|
+
** Specific CAST Definitions
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* The root node of a CAST document. The unist tree starts here. Each CAST document has one root node.
|
|
45
|
+
*
|
|
46
|
+
* ```json
|
|
47
|
+
* {
|
|
48
|
+
* "type": "root",
|
|
49
|
+
* "children": [
|
|
50
|
+
* ...
|
|
51
|
+
* ]
|
|
52
|
+
* }
|
|
53
|
+
*/
|
|
54
|
+
export interface Root extends Parent {
|
|
55
|
+
type: "root";
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/*
|
|
59
|
+
** Block Content
|
|
60
|
+
*/
|
|
61
|
+
export interface Paragraph extends Parent {
|
|
62
|
+
type: "paragraph";
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* The children of a paragraph are inline content.
|
|
66
|
+
*/
|
|
67
|
+
children: InlineContent[];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface Heading extends Parent {
|
|
71
|
+
type: "heading";
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* The level of a heading is a number between 1 and 6.
|
|
75
|
+
*/
|
|
76
|
+
level: 1 | 2 | 3 | 4 | 5 | 6;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* The children of a heading are inline content.
|
|
80
|
+
*/
|
|
81
|
+
children: InlineContent[];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface List extends Parent {
|
|
85
|
+
type: "list";
|
|
86
|
+
|
|
87
|
+
children: ListItem[];
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Whether the list is ordered or not.
|
|
91
|
+
*/
|
|
92
|
+
ordered: boolean;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* The start of an ordered list.
|
|
96
|
+
*/
|
|
97
|
+
start?: number;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export interface ListItem extends Parent {
|
|
101
|
+
type: "listItem";
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* The children of a list item are inline content.
|
|
105
|
+
*/
|
|
106
|
+
children: InlineContent[];
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export interface Blockquote extends Parent {
|
|
110
|
+
type: "blockquote";
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* The children of a blockquote are inline content.
|
|
114
|
+
*/
|
|
115
|
+
children: InlineContent[];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export interface Code extends Parent {
|
|
119
|
+
type: "code";
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* The language of the code block.
|
|
123
|
+
*/
|
|
124
|
+
lang?: string;
|
|
125
|
+
|
|
126
|
+
children: Text[];
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/*
|
|
130
|
+
** Inline Content
|
|
131
|
+
*/
|
|
132
|
+
export interface Text extends Literal {
|
|
133
|
+
type: "text";
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export interface Bold extends Parent {
|
|
137
|
+
type: "bold";
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* The children of a bold node are inline content.
|
|
141
|
+
*/
|
|
142
|
+
children: InlineContent[];
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export interface Italic extends Parent {
|
|
146
|
+
type: "italic";
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* The children of an italic node are inline content.
|
|
150
|
+
*/
|
|
151
|
+
children: InlineContent[];
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export interface Underline extends Parent {
|
|
155
|
+
type: "underline";
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* The children of an underline node are inline content.
|
|
159
|
+
*/
|
|
160
|
+
children: InlineContent[];
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export interface Strikethrough extends Parent {
|
|
164
|
+
type: "strikethrough";
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* The children of a strikethrough node are inline content.
|
|
168
|
+
*/
|
|
169
|
+
children: InlineContent[];
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export interface InlineCode extends Literal {
|
|
173
|
+
type: "inlineCode";
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export interface Highlight extends Parent {
|
|
177
|
+
type: "highlight";
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* The children of a highlight node are inline content
|
|
181
|
+
*/
|
|
182
|
+
children: InlineContent[];
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Represents an interpolated Content Value. Interpolated values are values that are stored elsewhere in the database
|
|
187
|
+
* and inserted into the document at request-time.
|
|
188
|
+
*/
|
|
189
|
+
export interface InterpolatedContentValue extends Node {
|
|
190
|
+
type: "contentValue";
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* The PRN (identifier) of the referenced Content Value.
|
|
194
|
+
*/
|
|
195
|
+
prn: string;
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* The nested CAST tree of the referenced Content Value.
|
|
199
|
+
*/
|
|
200
|
+
value?: Root;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export interface ExternalLink extends Parent {
|
|
204
|
+
type: "externalLink";
|
|
205
|
+
|
|
206
|
+
children: Text[];
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* The URL of the link.
|
|
210
|
+
*/
|
|
211
|
+
url: string;
|
|
212
|
+
|
|
213
|
+
target?: "_parent" | "_top" | "blank" | "self";
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export interface InternalLink extends Parent {
|
|
217
|
+
type: "internalLink";
|
|
218
|
+
|
|
219
|
+
children: Text[];
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* The PRN (identifier) of the referenced Path Part or Grid Placement.
|
|
223
|
+
*/
|
|
224
|
+
prn: string;
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* The URL of the link. Consists of the channel and the path part. Optionally includes a grid placement reference (e.g. #anchor-name).
|
|
228
|
+
* Even though the URL is marked as optional, it is always defined when retrieving an internal link.
|
|
229
|
+
* It is not required when saving an internal link.
|
|
230
|
+
*/
|
|
231
|
+
url?: string;
|
|
232
|
+
|
|
233
|
+
target?: "_parent" | "_top" | "blank" | "self";
|
|
234
|
+
}
|