svedit 0.12.0 → 0.13.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.
Files changed (86) hide show
  1. package/README.md +33 -21
  2. package/dist/Command.svelte.d.ts +38 -30
  3. package/dist/Command.svelte.d.ts.map +1 -1
  4. package/dist/Command.svelte.js +271 -326
  5. package/dist/CustomProperty.svelte +3 -5
  6. package/dist/CustomProperty.svelte.d.ts +3 -6
  7. package/dist/CustomProperty.svelte.d.ts.map +1 -1
  8. package/dist/KeyMapper.svelte.d.ts +19 -6
  9. package/dist/KeyMapper.svelte.d.ts.map +1 -1
  10. package/dist/KeyMapper.svelte.js +95 -112
  11. package/dist/Node.svelte +16 -13
  12. package/dist/Node.svelte.d.ts +3 -5
  13. package/dist/Node.svelte.d.ts.map +1 -1
  14. package/dist/NodeArrayProperty.svelte +39 -22
  15. package/dist/NodeArrayProperty.svelte.d.ts +3 -5
  16. package/dist/NodeArrayProperty.svelte.d.ts.map +1 -1
  17. package/dist/NodeCaret.svelte +1 -1
  18. package/dist/NodeCaret.svelte.d.ts +6 -14
  19. package/dist/NodeCaret.svelte.d.ts.map +1 -1
  20. package/dist/NodeGap.svelte +12 -6
  21. package/dist/NodeGap.svelte.d.ts +7 -14
  22. package/dist/NodeGap.svelte.d.ts.map +1 -1
  23. package/dist/NodeGapMarkers.svelte +19 -10
  24. package/dist/NodeGapMarkers.svelte.d.ts +6 -11
  25. package/dist/NodeGapMarkers.svelte.d.ts.map +1 -1
  26. package/dist/NodeSelectionMarkers.svelte +20 -6
  27. package/dist/NodeSelectionMarkers.svelte.d.ts +2 -5
  28. package/dist/NodeSelectionMarkers.svelte.d.ts.map +1 -1
  29. package/dist/Session.svelte.d.ts +81 -129
  30. package/dist/Session.svelte.d.ts.map +1 -1
  31. package/dist/Session.svelte.js +542 -648
  32. package/dist/Svedit.svelte +144 -138
  33. package/dist/Svedit.svelte.d.ts +30 -10
  34. package/dist/Svedit.svelte.d.ts.map +1 -1
  35. package/dist/TextProperty.svelte +32 -18
  36. package/dist/TextProperty.svelte.d.ts +3 -5
  37. package/dist/TextProperty.svelte.d.ts.map +1 -1
  38. package/dist/Transaction.svelte.d.ts +64 -127
  39. package/dist/Transaction.svelte.d.ts.map +1 -1
  40. package/dist/Transaction.svelte.js +839 -1001
  41. package/dist/UnknownNode.svelte +4 -3
  42. package/dist/UnknownNode.svelte.d.ts +5 -9
  43. package/dist/UnknownNode.svelte.d.ts.map +1 -1
  44. package/dist/doc_utils.d.ts +67 -155
  45. package/dist/doc_utils.d.ts.map +1 -1
  46. package/dist/doc_utils.js +619 -863
  47. package/dist/index.d.ts +20 -17
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +1 -17
  50. package/dist/node_visibility.svelte.d.ts +110 -9
  51. package/dist/node_visibility.svelte.d.ts.map +1 -1
  52. package/dist/node_visibility.svelte.js +473 -544
  53. package/dist/paste_utils.d.ts +11 -44
  54. package/dist/paste_utils.d.ts.map +1 -1
  55. package/dist/paste_utils.js +111 -152
  56. package/dist/transforms.svelte.d.ts +9 -7
  57. package/dist/transforms.svelte.d.ts.map +1 -1
  58. package/dist/transforms.svelte.js +125 -150
  59. package/dist/types.d.ts +277 -309
  60. package/dist/types.d.ts.map +1 -0
  61. package/dist/types.js +1 -0
  62. package/dist/utils.d.ts +40 -119
  63. package/dist/utils.d.ts.map +1 -1
  64. package/dist/utils.js +346 -473
  65. package/package.json +69 -70
  66. package/src/lib/{Command.svelte.js → Command.svelte.ts} +29 -17
  67. package/src/lib/CustomProperty.svelte +3 -5
  68. package/src/lib/{KeyMapper.svelte.js → KeyMapper.svelte.ts} +28 -11
  69. package/src/lib/Node.svelte +16 -13
  70. package/src/lib/NodeArrayProperty.svelte +39 -22
  71. package/src/lib/NodeCaret.svelte +1 -1
  72. package/src/lib/NodeGap.svelte +12 -6
  73. package/src/lib/NodeGapMarkers.svelte +19 -10
  74. package/src/lib/NodeSelectionMarkers.svelte +20 -6
  75. package/src/lib/{Session.svelte.js → Session.svelte.ts} +130 -127
  76. package/src/lib/Svedit.svelte +144 -138
  77. package/src/lib/TextProperty.svelte +32 -18
  78. package/src/lib/{Transaction.svelte.js → Transaction.svelte.ts} +139 -143
  79. package/src/lib/UnknownNode.svelte +4 -3
  80. package/src/lib/{doc_utils.js → doc_utils.ts} +247 -206
  81. package/src/lib/{index.js → index.ts} +47 -0
  82. package/src/lib/{node_visibility.svelte.js → node_visibility.svelte.ts} +68 -92
  83. package/src/lib/{paste_utils.js → paste_utils.ts} +47 -58
  84. package/src/lib/{transforms.svelte.js → transforms.svelte.ts} +39 -21
  85. package/src/lib/{types.d.ts → types.ts} +143 -66
  86. package/src/lib/{utils.js → utils.ts} +110 -129
@@ -13,6 +13,53 @@ export { default as NodeSelectionMarkers } from './NodeSelectionMarkers.svelte';
13
13
  export { default as Session } from './Session.svelte.js';
14
14
  export { default as Transaction } from './Transaction.svelte.js';
15
15
 
16
+ // Public types
17
+ export type {
18
+ // Schema definition
19
+ DocumentSchema,
20
+ NodeSchema,
21
+ NodeKind,
22
+ PropertyDefinition,
23
+ PropertyType,
24
+ // Schema-derived node types
25
+ PropertyValue,
26
+ NodeOfType,
27
+ AnyNode,
28
+ NodeMap,
29
+ DynamicRecord,
30
+ SessionConfig,
31
+ CommandRegistry,
32
+ DocumentOperation,
33
+ Inspection,
34
+ // Documents and nodes
35
+ Document,
36
+ DocumentNode,
37
+ DocumentPath,
38
+ NodeId,
39
+ // Values
40
+ Text,
41
+ NodeArray,
42
+ Attachment,
43
+ Mark,
44
+ Annotation,
45
+ // Selections
46
+ Selection,
47
+ TextSelection,
48
+ NodeSelection,
49
+ PropertySelection,
50
+ SelectionRange,
51
+ // Component props and render contexts
52
+ SveditProps,
53
+ SveditContext,
54
+ TextPropertyProps,
55
+ CustomPropertyProps,
56
+ NodeArrayPropertyProps,
57
+ NodeProps,
58
+ NodeArrayAttachmentContext
59
+ } from './types.js';
60
+ export type { SelectedAttachment } from './doc_utils.js';
61
+ export type { Keymap } from './KeyMapper.svelte.js';
62
+
16
63
  // Document utilities
17
64
  export {
18
65
  define_document_schema,
@@ -120,9 +120,8 @@ class VisibilityRegistry {
120
120
  * Stable references — once a SvelteSet is created for an array path
121
121
  * it survives re-renders so consumers stay subscribed.
122
122
  *
123
- * @type {Map<string, SvelteSet<number>>}
124
123
  */
125
- #array_indices = new Map();
124
+ #array_indices: Map<string, SvelteSet<number>> = new Map();
126
125
 
127
126
  /**
128
127
  * Per-array edge-proximity state. `first` is true when the first
@@ -138,15 +137,12 @@ class VisibilityRegistry {
138
137
  * only render when the edge node has actually reached the matching
139
138
  * end of its container.
140
139
  *
141
- * @type {SvelteMap<string, { first: boolean, last: boolean }>}
142
140
  */
143
- edge_map = new SvelteMap();
141
+ edge_map: SvelteMap<string, { first: boolean; last: boolean }> = new SvelteMap();
144
142
 
145
- /** @type {IntersectionObserver | null} */
146
- #io = null;
143
+ #io: IntersectionObserver | null = null;
147
144
 
148
- /** @type {IntersectionObserver | null} */
149
- #view_io = null;
145
+ #view_io: IntersectionObserver | null = null;
150
146
 
151
147
  /**
152
148
  * Re-syncs edge state when a registered array's box changes size
@@ -156,35 +152,31 @@ class VisibilityRegistry {
156
152
  * change, so neither of the other two triggers would catch them.
157
153
  * Writes are change-detected, so redundant firings are no-ops.
158
154
  *
159
- * @type {ResizeObserver | null}
160
155
  */
161
- #array_ro = null;
156
+ #array_ro: ResizeObserver | null = null;
162
157
 
163
158
  /**
164
159
  * Registered node elements and the path each was registered under.
165
160
  * The attachment closure carries the path, so a stale data-path
166
161
  * attribute can never desync state.
167
162
  *
168
- * @type {Map<HTMLElement, string>}
169
163
  */
170
- #registered_paths = new Map();
164
+ #registered_paths: Map<HTMLElement, string> = new Map();
171
165
 
172
166
  /**
173
167
  * Which element currently owns a node path. Guards unregistration
174
168
  * against keyed-update collisions (see module doc).
175
169
  *
176
- * @type {Map<string, HTMLElement>}
177
170
  */
178
- #path_owners = new Map();
171
+ #path_owners: Map<string, HTMLElement> = new Map();
179
172
 
180
- /** @type {Set<HTMLElement>} */
181
- #near_nodes = new Set();
173
+ #near_nodes: Set<HTMLElement> = new Set();
182
174
 
183
- /** Registered node-array container elements. @type {Set<Element>} */
184
- #array_els = new Set();
175
+ /** Registered node-array container elements. */
176
+ #array_els: Set<Element> = new Set();
185
177
 
186
- /** Which element currently owns an array path. @type {Map<string, Element>} */
187
- #array_owners = new Map();
178
+ /** Which element currently owns an array path. */
179
+ #array_owners: Map<string, Element> = new Map();
188
180
 
189
181
  /**
190
182
  * When true, a second IO (rootMargin 0, actual viewport) toggles
@@ -271,10 +263,8 @@ class VisibilityRegistry {
271
263
  * the set and reads `.has()` in the same derived never subscribes
272
264
  * and never re-evaluates.
273
265
  *
274
- * @param {string} array_path_str
275
- * @returns {SvelteSet<number>}
276
266
  */
277
- get_array_indices(array_path_str) {
267
+ get_array_indices(array_path_str: string): SvelteSet<number> {
278
268
  let set = this.#array_indices.get(array_path_str);
279
269
  if (!set) {
280
270
  set = new SvelteSet();
@@ -291,10 +281,9 @@ class VisibilityRegistry {
291
281
  * viewport transitions. Re-runs when the element is recreated or
292
282
  * its path changes; the teardown unregisters collision-safely.
293
283
  *
294
- * @param {string} path
295
284
  */
296
- track_node(path) {
297
- return (/** @type {HTMLElement} */ el) => {
285
+ track_node(path: string) {
286
+ return (el: HTMLElement) => {
298
287
  this.#register_node(el, path);
299
288
  return () => this.#unregister_node(el, path);
300
289
  };
@@ -305,10 +294,9 @@ class VisibilityRegistry {
305
294
  * arrays get their edge state synced on mount, on scroll (via the
306
295
  * document scroll listener) and after document changes.
307
296
  *
308
- * @param {string} path
309
297
  */
310
- track_array(path) {
311
- return (/** @type {Element} */ el) => {
298
+ track_array(path: string) {
299
+ return (el: Element) => {
312
300
  this.start();
313
301
  this.#array_els.add(el);
314
302
  this.#array_owners.set(path, el);
@@ -334,9 +322,8 @@ class VisibilityRegistry {
334
322
  * registry instance. Scopes the document-level scroll listener to
335
323
  * this editor without any DOM traversal.
336
324
  *
337
- * @param {Element} el
338
325
  */
339
- has_array(el) {
326
+ has_array(el: Element): boolean {
340
327
  return this.#array_els.has(el);
341
328
  }
342
329
 
@@ -351,11 +338,7 @@ class VisibilityRegistry {
351
338
  }
352
339
  }
353
340
 
354
- /**
355
- * @param {HTMLElement} el
356
- * @param {string} path
357
- */
358
- #register_node(el, path) {
341
+ #register_node(el: HTMLElement, path: string): void {
359
342
  this.start();
360
343
  untrack(() => {
361
344
  this.#registered_paths.set(el, path);
@@ -373,24 +356,20 @@ class VisibilityRegistry {
373
356
  const vw = window.innerWidth;
374
357
  const is_near =
375
358
  !this.visibility_culling ||
376
- (bcr.bottom > -OVERSCAN_PX &&
377
- bcr.top < vh + OVERSCAN_PX &&
378
- bcr.right > -OVERSCAN_PX &&
379
- bcr.left < vw + OVERSCAN_PX);
359
+ (bcr!.bottom > -OVERSCAN_PX &&
360
+ bcr!.top < vh + OVERSCAN_PX &&
361
+ bcr!.right > -OVERSCAN_PX &&
362
+ bcr!.left < vw + OVERSCAN_PX);
380
363
  if (is_near) this.#add_near_node(el, path);
381
364
 
382
365
  if (this.view_classes) {
383
- const in_viewport = bcr.bottom > 0 && bcr.top < vh && bcr.right > 0 && bcr.left < vw;
384
- this.#apply_view_classes(el, in_viewport, bcr, vh);
366
+ const in_viewport = bcr!.bottom > 0 && bcr!.top < vh && bcr!.right > 0 && bcr!.left < vw;
367
+ this.#apply_view_classes(el, in_viewport, bcr!, vh);
385
368
  }
386
369
  });
387
370
  }
388
371
 
389
- /**
390
- * @param {HTMLElement} el
391
- * @param {string} path
392
- */
393
- #unregister_node(el, path) {
372
+ #unregister_node(el: HTMLElement, path: string): void {
394
373
  this.#registered_paths.delete(el);
395
374
  this.#near_nodes.delete(el);
396
375
  this.#io?.unobserve(el);
@@ -406,21 +385,13 @@ class VisibilityRegistry {
406
385
  });
407
386
  }
408
387
 
409
- /**
410
- * @param {HTMLElement} el
411
- * @param {string} path
412
- */
413
- #add_near_node(el, path) {
388
+ #add_near_node(el: HTMLElement, path: string): void {
414
389
  this.#near_nodes.add(el);
415
390
  const split = this.#split_path(path);
416
391
  if (split) this.get_array_indices(split.array_path).add(split.index);
417
392
  }
418
393
 
419
- /**
420
- * @param {HTMLElement} el
421
- * @param {string} path
422
- */
423
- #remove_near_node(el, path) {
394
+ #remove_near_node(el: HTMLElement, path: string): void {
424
395
  this.#near_nodes.delete(el);
425
396
  if (this.#path_owners.get(path) !== el) return;
426
397
  const split = this.#split_path(path);
@@ -445,12 +416,10 @@ class VisibilityRegistry {
445
416
  * called transitively from $effect contexts without self-
446
417
  * invalidation.
447
418
  *
448
- * @param {Element} array_el
449
- * @returns {boolean}
450
419
  */
451
- sync_edge_state(array_el) {
420
+ sync_edge_state(array_el: Element): boolean {
452
421
  if (!array_el) return false;
453
- const path = /** @type {HTMLElement} */ (array_el).dataset.path;
422
+ const path = (array_el as HTMLElement).dataset.path;
454
423
  if (!path) return false;
455
424
 
456
425
  // Check computed overflow BEFORE touching scroll metrics. Reading
@@ -487,13 +456,12 @@ class VisibilityRegistry {
487
456
  });
488
457
  }
489
458
 
490
- /**
491
- * @param {HTMLElement} el
492
- * @param {boolean} in_viewport
493
- * @param {DOMRectReadOnly} bcr
494
- * @param {number} vh
495
- */
496
- #apply_view_classes(el, in_viewport, bcr, vh) {
459
+ #apply_view_classes(
460
+ el: HTMLElement,
461
+ in_viewport: boolean,
462
+ bcr: DOMRectReadOnly,
463
+ vh: number
464
+ ): void {
497
465
  const cl = el.classList;
498
466
  cl.toggle('in-view', in_viewport);
499
467
  if (in_viewport) {
@@ -508,11 +476,7 @@ class VisibilityRegistry {
508
476
  }
509
477
  }
510
478
 
511
- /**
512
- * @param {string} path
513
- * @returns {{ array_path: string, index: number } | null}
514
- */
515
- #split_path(path) {
479
+ #split_path(path: string): { array_path: string; index: number } | null {
516
480
  const sep = path.lastIndexOf(PATH_SEPARATOR);
517
481
  if (sep < 0) return null;
518
482
  const index = parseInt(path.slice(sep + PATH_SEPARATOR.length), 10);
@@ -524,11 +488,10 @@ class VisibilityRegistry {
524
488
  * Overscan IO callback. Manages the array_indices sets; NodeGap
525
489
  * reacts to the map writes and updates .positioned declaratively.
526
490
  *
527
- * @param {IntersectionObserverEntry[]} entries
528
491
  */
529
- #process_near(entries) {
492
+ #process_near(entries: IntersectionObserverEntry[]): void {
530
493
  for (const entry of entries) {
531
- const el = /** @type {HTMLElement} */ (entry.target);
494
+ const el = entry.target as HTMLElement;
532
495
  const path = this.#registered_paths.get(el);
533
496
  if (!path || !el.isConnected) continue;
534
497
 
@@ -544,12 +507,11 @@ class VisibilityRegistry {
544
507
  * Runs on a separate observer with rootMargin 0 so thresholds
545
508
  * fire at actual viewport edges, not the overscan boundary.
546
509
  *
547
- * @param {IntersectionObserverEntry[]} entries
548
510
  */
549
- #process_view(entries) {
511
+ #process_view(entries: IntersectionObserverEntry[]): void {
550
512
  const vh = window.innerHeight;
551
513
  for (const entry of entries) {
552
- const el = /** @type {HTMLElement} */ (entry.target);
514
+ const el = entry.target as HTMLElement;
553
515
  if (!this.#registered_paths.has(el) || !el.isConnected) continue;
554
516
  this.#apply_view_classes(el, entry.isIntersecting, entry.boundingClientRect, vh);
555
517
  }
@@ -564,9 +526,16 @@ class VisibilityRegistry {
564
526
  * The IntersectionObservers own viewport changes; document changes
565
527
  * only trigger an edge-state re-sync over the registered arrays.
566
528
  *
567
- * @param {object} svedit - Svedit context (session, editable)
529
+ * @param svedit - Svedit context (session, editable)
568
530
  */
569
- export function create_node_visibility(svedit) {
531
+ export function create_node_visibility(svedit: {
532
+ session: {
533
+ config?: { view_classes?: boolean; visibility_culling?: boolean };
534
+ doc: unknown;
535
+ };
536
+ editable: boolean;
537
+ visibility_registry?: VisibilityRegistryApi;
538
+ }): void {
570
539
  const registry = new VisibilityRegistry();
571
540
  registry.view_classes = svedit.session?.config?.view_classes !== false;
572
541
  registry.visibility_culling = svedit.session?.config?.visibility_culling !== false;
@@ -587,9 +556,8 @@ export function create_node_visibility(svedit) {
587
556
  * coalesces array scrolls into one RAF that reads only scrollLeft /
588
557
  * scrollWidth / clientWidth — no per-node BCRs.
589
558
  */
590
- /** @type {Set<Element>} */
591
559
  // eslint-disable-next-line svelte/prefer-svelte-reactivity -- Non-reactive RAF queue.
592
- const pending_scroll_arrays = new Set();
560
+ const pending_scroll_arrays: Set<Element> = new Set();
593
561
  let scroll_raf = 0;
594
562
  function flush_scroll_sync() {
595
563
  scroll_raf = 0;
@@ -598,9 +566,8 @@ export function create_node_visibility(svedit) {
598
566
  }
599
567
  pending_scroll_arrays.clear();
600
568
  }
601
- /** @param {Event} event */
602
- function on_scroll(event) {
603
- const target = /** @type {Element | null} */ (event.target);
569
+ function on_scroll(event: Event) {
570
+ const target = event.target as Element | null;
604
571
  const arr = target?.closest?.('[data-type="node_array"]');
605
572
  if (!arr || !registry.has_array(arr)) return;
606
573
  pending_scroll_arrays.add(arr);
@@ -636,6 +603,13 @@ export function create_node_visibility(svedit) {
636
603
  });
637
604
  }
638
605
 
606
+ export type VisibilityRegistryApi = {
607
+ edge_map: SvelteMap<string, { first: boolean; last: boolean }>;
608
+ get_array_indices(array_path_str: string): SvelteSet<number>;
609
+ track_node(path: string): (el: HTMLElement) => () => void;
610
+ track_array(path: string): (el: Element) => () => void;
611
+ };
612
+
639
613
  /**
640
614
  * Pure visibility check for a gap's `.positioned` class. NodeGap calls
641
615
  * this from a $derived, so the `near.has()` reads are tracked at
@@ -648,13 +622,15 @@ export function create_node_visibility(svedit) {
648
622
  * $derived (see the note there): membership reads on a set created
649
623
  * within the same derived are not tracked by Svelte.
650
624
  *
651
- * @param {SvelteSet<number>} near - near child indices of the array
652
- * @param {{ first: boolean, last: boolean } | undefined} edge_state
653
- * @param {number} offset
654
- * @param {boolean} is_last
655
- * @param {boolean} empty
625
+ * @param near - near child indices of the array
656
626
  */
657
- export function should_position_gap(near, edge_state, offset, is_last, empty) {
627
+ export function should_position_gap(
628
+ near: SvelteSet<number>,
629
+ edge_state: { first: boolean; last: boolean } | undefined,
630
+ offset: number,
631
+ is_last: boolean,
632
+ empty: boolean
633
+ ): boolean {
658
634
  if (!near) return false;
659
635
 
660
636
  if (empty) {
@@ -1,12 +1,23 @@
1
- /**
2
- * @import { DocumentSchema } from './types.d.ts'
3
- */
1
+ import type { Text, DocumentNode, DocumentSchema } from './types.js';
4
2
 
5
- export function normalize_line_endings(text) {
3
+ function is_record(value: unknown): value is Record<string, unknown> {
4
+ return typeof value === 'object' && value !== null;
5
+ }
6
+
7
+ function is_text(value: unknown): value is Text {
8
+ return (
9
+ is_record(value) &&
10
+ typeof value.content === 'string' &&
11
+ Array.isArray(value.marks) &&
12
+ Array.isArray(value.annotations)
13
+ );
14
+ }
15
+
16
+ export function normalize_line_endings(text: string): string {
6
17
  return text.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
7
18
  }
8
19
 
9
- export function dedent_plain_text(plain_text) {
20
+ export function dedent_plain_text(plain_text: string): string {
10
21
  const lines = normalize_line_endings(plain_text).split('\n');
11
22
  if (lines.length < 2) return plain_text;
12
23
 
@@ -42,23 +53,21 @@ export function dedent_plain_text(plain_text) {
42
53
  .join('\n');
43
54
  }
44
55
 
45
- export function split_plain_text_paragraphs(plain_text) {
56
+ export function split_plain_text_paragraphs(plain_text: string): string[] {
46
57
  return normalize_line_endings(plain_text)
47
58
  .split(/\n{2,}/)
48
59
  .map((fragment) => fragment.trim())
49
60
  .filter(Boolean);
50
61
  }
51
62
 
52
- export function normalize_plain_text_for_single_line_property(plain_text) {
63
+ export function normalize_plain_text_for_single_line_property(plain_text: string): string {
53
64
  return normalize_line_endings(plain_text).replace(/\s*\n+\s*/g, ' ');
54
65
  }
55
66
 
56
- /**
57
- * @param {string | null | undefined} node_type
58
- * @param {DocumentSchema} schema
59
- * @returns {string | null}
60
- */
61
- export function get_text_property_name(node_type, schema) {
67
+ export function get_text_property_name(
68
+ node_type: string | null | undefined,
69
+ schema: DocumentSchema
70
+ ): string | null {
62
71
  if (!node_type) return null;
63
72
  const node_schema = schema[node_type];
64
73
  if (!node_schema || node_schema.kind !== 'text') return null;
@@ -70,75 +79,55 @@ export function get_text_property_name(node_type, schema) {
70
79
  );
71
80
  }
72
81
 
73
- /**
74
- * @param {any} node
75
- * @param {DocumentSchema} schema
76
- * @returns {{ content: string, marks: any[], annotations: any[] } | null}
77
- */
78
- export function get_text_content(node, schema) {
79
- if (!node || typeof node !== 'object') return null;
80
-
81
- const is_text_value = (value) =>
82
- value &&
83
- typeof value.content === 'string' &&
84
- Array.isArray(value.marks) &&
85
- Array.isArray(value.annotations);
82
+ export function get_text_content(node: unknown, schema: DocumentSchema): Text | null {
83
+ if (!is_record(node)) return null;
86
84
 
87
- const text_property_name = get_text_property_name(node.type, schema);
88
- if (text_property_name && is_text_value(node[text_property_name])) {
85
+ const node_type = typeof node.type === 'string' ? node.type : null;
86
+ const text_property_name = get_text_property_name(node_type, schema);
87
+ if (text_property_name && is_text(node[text_property_name])) {
89
88
  return node[text_property_name];
90
89
  }
91
90
 
92
- if (is_text_value(node.content)) {
91
+ if (is_text(node.content)) {
93
92
  return node.content;
94
93
  }
95
94
 
96
95
  return null;
97
96
  }
98
97
 
99
- /**
100
- * @param {any} node
101
- * @param {DocumentSchema} schema
102
- * @returns {boolean}
103
- */
104
- export function is_text_like_node_payload(node, schema) {
105
- if (!node || typeof node !== 'object') return false;
106
- if (schema[node.type]?.kind === 'text') return true;
98
+ export function is_text_like_node_payload(node: unknown, schema: DocumentSchema): boolean {
99
+ if (!is_record(node)) return false;
100
+ if (typeof node.type === 'string' && schema[node.type]?.kind === 'text') return true;
107
101
  return !!get_text_content(node, schema);
108
102
  }
109
103
 
110
- /**
111
- * @param {any} node_array_property_definition
112
- * @param {DocumentSchema} schema
113
- * @returns {string | null}
114
- */
115
- export function get_default_text_node(node_array_property_definition, schema) {
104
+ export function get_default_text_node(
105
+ node_array_property_definition: unknown,
106
+ schema: DocumentSchema
107
+ ): string | null {
116
108
  if (
117
- node_array_property_definition?.type !== 'node_array' ||
109
+ !is_record(node_array_property_definition) ||
110
+ node_array_property_definition.type !== 'node_array' ||
118
111
  !Array.isArray(node_array_property_definition.node_types)
119
112
  ) {
120
113
  return null;
121
114
  }
122
115
 
123
116
  const default_node_type = node_array_property_definition.default_node_type;
124
- if (default_node_type && schema[default_node_type]?.kind === 'text') {
117
+ if (typeof default_node_type === 'string' && schema[default_node_type]?.kind === 'text') {
125
118
  return default_node_type;
126
119
  }
127
120
 
128
- return (
129
- node_array_property_definition.node_types.find(
130
- (node_type) => schema[node_type]?.kind === 'text'
131
- ) || null
132
- );
121
+ return (node_array_property_definition.node_types.find(
122
+ (node_type: unknown) => typeof node_type === 'string' && schema[node_type]?.kind === 'text'
123
+ ) || null) as string | null;
133
124
  }
134
125
 
135
- /**
136
- * @param {string[]} paragraph_fragments
137
- * @param {string | null | undefined} node_type
138
- * @param {DocumentSchema} schema
139
- * @returns {{ main_nodes: string[], nodes: Record<string, any> } | null}
140
- */
141
- export function create_plain_text_nodes_payload(paragraph_fragments, node_type, schema) {
126
+ export function create_plain_text_nodes_payload(
127
+ paragraph_fragments: string[],
128
+ node_type: string | null | undefined,
129
+ schema: DocumentSchema
130
+ ): { main_nodes: string[]; nodes: Record<string, DocumentNode> } | null {
142
131
  if (!Array.isArray(paragraph_fragments) || paragraph_fragments.length === 0 || !node_type) {
143
132
  return null;
144
133
  }
@@ -146,7 +135,7 @@ export function create_plain_text_nodes_payload(paragraph_fragments, node_type,
146
135
  const text_property_name = get_text_property_name(node_type, schema);
147
136
  if (!text_property_name) return null;
148
137
 
149
- const payload = {
138
+ const payload: { main_nodes: string[]; nodes: Record<string, DocumentNode> } = {
150
139
  main_nodes: [],
151
140
  nodes: {}
152
141
  };