@stll/folio-core 0.28.1 → 0.29.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 (33) hide show
  1. package/dist/layout-bridge/convert/toFlowBlocks.d.ts +1 -2
  2. package/dist/layout-bridge/convert/toFlowBlocks.js +61 -95
  3. package/dist/markdown/renderParagraph.js +7 -2
  4. package/dist/prosemirror/attrs/index.js +2 -1
  5. package/dist/prosemirror/bookmarkBoundaryAttrs.d.ts +8 -0
  6. package/dist/prosemirror/bookmarkBoundaryAttrs.js +66 -0
  7. package/dist/prosemirror/conversion/fromProseDoc.js +170 -52
  8. package/dist/prosemirror/conversion/toProseDoc.js +169 -61
  9. package/dist/prosemirror/extensions/StarterKit.js +11 -3
  10. package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.js +8 -4
  11. package/dist/prosemirror/extensions/features/PasteCleanupExtension.d.ts +4 -1
  12. package/dist/prosemirror/extensions/features/PasteCleanupExtension.js +9 -5
  13. package/dist/prosemirror/extensions/features/pasteCleanup.d.ts +10 -23
  14. package/dist/prosemirror/extensions/features/pasteCleanup.js +77 -22
  15. package/dist/prosemirror/extensions/nodes/BookmarkBoundaryExtension.d.ts +9 -0
  16. package/dist/prosemirror/extensions/nodes/BookmarkBoundaryExtension.js +67 -0
  17. package/dist/prosemirror/extensions/nodes/FieldExtension.d.ts +10 -4
  18. package/dist/prosemirror/extensions/nodes/FieldExtension.js +77 -59
  19. package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.d.ts +4 -1
  20. package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.js +4 -3
  21. package/dist/prosemirror/listMarker.d.ts +58 -0
  22. package/dist/prosemirror/listMarker.js +185 -0
  23. package/dist/prosemirror/numberedRefFields.d.ts +24 -0
  24. package/dist/prosemirror/numberedRefFields.js +276 -0
  25. package/dist/prosemirror/paraText.js +56 -17
  26. package/dist/prosemirror/plugins/anonymizationDecorations.js +1 -1
  27. package/dist/prosemirror/plugins/pmTextScan.d.ts +3 -1
  28. package/dist/prosemirror/plugins/pmTextScan.js +28 -7
  29. package/dist/prosemirror/plugins/templateDirectives.js +2 -2
  30. package/dist/prosemirror/schema/index.d.ts +2 -2
  31. package/dist/prosemirror/schema/nodes.d.ts +13 -1
  32. package/dist/prosemirror/validation.js +93 -0
  33. package/package.json +1 -1
@@ -1,5 +1,6 @@
1
1
  import { document_d_exports } from "../../types/document.js";
2
2
  import { BorderStyle, FlowBlock, ParagraphAttrs } from "../../layout-engine/types.js";
3
+ import { formatCounter, resolveListTemplate } from "../../prosemirror/listMarker.js";
3
4
  import { Node } from "prosemirror-model";
4
5
  //#region src/layout-bridge/convert/toFlowBlocks.d.ts
5
6
  /**
@@ -59,8 +60,6 @@ type ToFlowBlocksOptions = {
59
60
  /** Line pitch for the final body section, whose properties live outside the PM body. */
60
61
  finalSectionDocumentGridLinePitchTwips?: number;
61
62
  };
62
- declare function formatCounter(value: number, format: document_d_exports.NumberFormat | undefined): string;
63
- declare function resolveListTemplate(template: string, counters: number[], levelFormats: document_d_exports.NumberFormat[] | undefined, forceDecimal?: boolean): string;
64
63
  /**
65
64
  * Reset the block ID counter (useful for testing).
66
65
  */
@@ -1,6 +1,5 @@
1
1
  import { convertBulletToUnicode } from "../../docx/bulletMarkers.js";
2
2
  import { resolveDocumentGridLinePitch } from "../../docx/documentGrid.js";
3
- import { formatOoxmlCounter } from "../../docx/ooxmlCounterFormatter.js";
4
3
  import { setHyperlinkInstanceIndex } from "../../layout-engine/measure/hyperlinkInstance.js";
5
4
  import { setParagraphFrame } from "../../layout-engine/paragraphFrame.js";
6
5
  import { setTextBoxGroupId } from "../../layout-engine/textBoxGroup.js";
@@ -9,6 +8,8 @@ import { getPageNumbering } from "../../paged-layout/sectionGeometry.js";
9
8
  import { expectBlockSdtAttrs, expectCharacterSpacingMarkAttrs, expectCharacterStyleMarkAttrs, expectCommentMarkAttrs, expectEmphasisMarkAttrs, expectFieldAttrs, expectFontFamilyMarkAttrs, expectFontSizeMarkAttrs, expectFootnoteRefMarkAttrs, expectHardBreakAttrs, expectHighlightMarkAttrs, expectHyperlinkMarkAttrs, expectImageAttrs, expectLanguageMarkAttrs, expectMathAttrs, expectParagraphAttrs, expectRunFormattingOverrideMarkAttrs, expectRunShadingMarkAttrs, expectSymbolAttrs, expectTableAttrs, expectTableCellAttrs, expectTableRowAttrs, expectTextBoxAttrs, expectTextColorMarkAttrs, expectTextEffectMarkAttrs, expectTrackedChangeMarkAttrs, expectUnderlineMarkAttrs } from "../../prosemirror/attrs/index.js";
10
9
  import { autospacingMatchesBase } from "../../prosemirror/autospacingBase.js";
11
10
  import { runShadingAttrsToShading } from "../../prosemirror/conversion/runShadingMark.js";
11
+ import { advanceListMarker, advanceVisibleListMarker, cloneListCounterState, formatCounter, resolveListTemplate } from "../../prosemirror/listMarker.js";
12
+ import { resolveNumberedRefFields } from "../../prosemirror/numberedRefFields.js";
12
13
  import { directionToBidi } from "../../prosemirror/paragraphDirection.js";
13
14
  import { cascadeStyleTextFormatting } from "../../prosemirror/styles/styleToggleCascade.js";
14
15
  import { assertValidProseMirrorDocument } from "../../prosemirror/validation.js";
@@ -68,79 +69,12 @@ let blockIdCounter = 0;
68
69
  function nextBlockId() {
69
70
  return `block-${++blockIdCounter}`;
70
71
  }
71
- function formatNumberedMarker(counters, level) {
72
- const parts = [];
73
- for (let i = 0; i <= level; i += 1) {
74
- const value = counters[i] ?? 0;
75
- if (!Number.isFinite(value) || value <= 0) break;
76
- parts.push(value);
77
- }
78
- if (parts.length === 0) return "1.";
79
- return `${parts.join(".")}.`;
80
- }
81
- function formatCounter(value, format) {
82
- return formatOoxmlCounter(value, format);
83
- }
84
- function resolveListTemplate(template, counters, levelFormats, forceDecimal = false) {
85
- return template.replace(/%(?<digit>\d)(?<punct>[.):\]])?/gu, (...args) => {
86
- const { digit, punct = "" } = args.at(-1);
87
- const index = Number.parseInt(digit, 10) - 1;
88
- if (index < 0) return "";
89
- const counter = counters[index];
90
- if (counter === void 0 || Number.isNaN(counter)) return "";
91
- const formatted = formatCounter(counter, forceDecimal ? "decimal" : levelFormats?.[index]);
92
- return formatted ? `${formatted}${punct}` : "";
93
- });
94
- }
95
- function getLastListCounters(listCounters) {
96
- let lastCounters;
97
- for (const counters of listCounters.values()) lastCounters = counters;
98
- return lastCounters;
99
- }
100
72
  function applyMarkerAllCaps(marker, allCaps) {
101
73
  if (marker === null || !allCaps) return marker;
102
74
  return marker.toLocaleUpperCase();
103
75
  }
104
- function computeListMarker(pmAttrs, listCounters, abstractCounters, seenNumIds) {
105
- const numId = pmAttrs.numPr?.numId;
106
- if (numId === void 0 || numId === 0) {
107
- if (pmAttrs.listMarker?.includes("%") && !pmAttrs.listIsBullet) {
108
- const counters = getLastListCounters(listCounters);
109
- if (counters) return resolveListTemplate(pmAttrs.listMarker, counters, pmAttrs.listLevelNumFmts, pmAttrs.listIsLegal);
110
- }
111
- return null;
112
- }
113
- if (pmAttrs.listIsBullet) return convertBulletToUnicode(pmAttrs.listMarker || "");
114
- const level = pmAttrs.numPr?.ilvl ?? 0;
115
- const counters = listCounters.get(numId) ?? Array.from({ length: 9 }, () => NaN);
116
- const abstractNumId = pmAttrs.listAbstractNumId;
117
- if (level > 0) {
118
- const latestAbstractCounters = abstractNumId === void 0 ? void 0 : abstractCounters.get(abstractNumId);
119
- if (counters.slice(0, level).every((counter) => !Number.isFinite(counter))) for (let i = 0; i < level; i += 1) {
120
- const latestCounter = latestAbstractCounters?.[i];
121
- counters[i] = latestCounter !== void 0 && Number.isFinite(latestCounter) ? latestCounter : pmAttrs.listLevelStarts?.[i] ?? 1;
122
- }
123
- }
124
- const seenKey = `${numId}:${level}`;
125
- if (!seenNumIds.has(seenKey)) {
126
- seenNumIds.add(seenKey);
127
- if (pmAttrs.listStartOverride != null) counters[level] = pmAttrs.listStartOverride - 1;
128
- }
129
- if (!Number.isFinite(counters[level])) counters[level] = (pmAttrs.listLevelStarts?.[level] ?? 1) - 1;
130
- counters[level] = (counters[level] ?? 0) + 1;
131
- for (let i = level + 1; i < counters.length; i += 1) counters[i] = NaN;
132
- const childAdvances = pmAttrs.listImplicitChildLevelAdvances ?? 0;
133
- if (childAdvances > 0 && level + 1 < counters.length) {
134
- const childCounter = counters[level + 1];
135
- counters[level + 1] = (childCounter === void 0 || !Number.isFinite(childCounter) ? 0 : childCounter) + childAdvances;
136
- }
137
- listCounters.set(numId, counters);
138
- if (abstractNumId !== void 0) abstractCounters.set(abstractNumId, [...counters]);
139
- const levelFormats = pmAttrs.listLevelNumFmts ?? (pmAttrs.listNumFmt ? [pmAttrs.listNumFmt] : void 0);
140
- if (pmAttrs.listMarker && pmAttrs.listMarker.includes("%")) return resolveListTemplate(pmAttrs.listMarker, counters, levelFormats, pmAttrs.listIsLegal);
141
- if (pmAttrs.listMarker) return pmAttrs.listMarker;
142
- if ((levelFormats?.[level] ?? pmAttrs.listNumFmt) === "none" || pmAttrs.listMarker === "") return null;
143
- return formatNumberedMarker(counters, level);
76
+ function computeListMarker(pmAttrs, state) {
77
+ return advanceListMarker(pmAttrs, state);
144
78
  }
145
79
  /**
146
80
  * Reset the block ID counter (useful for testing).
@@ -515,6 +449,7 @@ function paragraphToRuns(node, startPos, _options) {
515
449
  const inTocParagraph = pmAttrs._tableOfContentsLevel !== void 0 || tableOfContentsStyleLevel({ styleId: paragraphStyleId }) !== void 0;
516
450
  let leadingRenderedPageBreakPending = pmAttrs.renderedPageBreakBefore === true;
517
451
  function pushRunsForChild(child, childPos) {
452
+ if (child.type.name === "bookmarkBoundary") return;
518
453
  if (child.type.name === "renderedPageBreak") {
519
454
  if (leadingRenderedPageBreakPending) {
520
455
  leadingRenderedPageBreakPending = false;
@@ -600,7 +535,7 @@ function paragraphToRuns(node, startPos, _options) {
600
535
  runs.push(run);
601
536
  return;
602
537
  }
603
- if (child.type.name === "field") {
538
+ if (child.type.name === "field" || child.type.name === "structuredField") {
604
539
  const attrs = expectFieldAttrs(child);
605
540
  const ft = attrs.fieldType;
606
541
  let mappedType = "OTHER";
@@ -620,7 +555,7 @@ function paragraphToRuns(node, startPos, _options) {
620
555
  kind: "field",
621
556
  fieldType: mappedType,
622
557
  instruction: attrs.instruction,
623
- fallback: attrs.displayText || "",
558
+ fallback: _options.numberedRefResults?.get(child) ?? attrs.displayText ?? "",
624
559
  ...attrs.fldLock ? { fldLock: true } : {},
625
560
  pmStart: childPos,
626
561
  pmEnd: childPos + child.nodeSize,
@@ -711,18 +646,18 @@ function toPreviousListAttrs(previousFormatting) {
711
646
  if (listMarkerSuffix !== void 0) attrs.listMarkerSuffix = listMarkerSuffix;
712
647
  return attrs;
713
648
  }
714
- function resolveDeletedListMarker(previousListAttrs, listCounters, listAbstractCounters, listSeenNumIds) {
715
- if (listCounters && previousListAttrs.numPr) {
716
- const marker = computeListMarker(previousListAttrs, listCounters, listAbstractCounters ?? /* @__PURE__ */ new Map(), listSeenNumIds ?? /* @__PURE__ */ new Set());
649
+ function resolveDeletedListMarker(previousListAttrs, listCounterState) {
650
+ if (listCounterState && previousListAttrs.numPr) {
651
+ const marker = computeListMarker(previousListAttrs, listCounterState);
717
652
  if (marker) return marker;
718
653
  }
719
654
  if (previousListAttrs.listMarker) return previousListAttrs.listIsBullet ? convertBulletToUnicode(previousListAttrs.listMarker) : previousListAttrs.listMarker;
720
655
  if (previousListAttrs.listIsBullet) return "•";
721
656
  return null;
722
657
  }
723
- function applyDeletedListMarkerAttrs(attrs, change, listCounters, listAbstractCounters, listSeenNumIds, theme) {
658
+ function applyDeletedListMarkerAttrs(attrs, change, listCounterState, theme) {
724
659
  const previousListAttrs = toPreviousListAttrs(change.previousFormatting);
725
- const marker = resolveDeletedListMarker(previousListAttrs, listCounters, listAbstractCounters, listSeenNumIds);
660
+ const marker = resolveDeletedListMarker(previousListAttrs, listCounterState);
726
661
  if (!marker) return;
727
662
  attrs.listMarker = marker;
728
663
  attrs.listMarkerRevision = toListMarkerRevision("del", change.info);
@@ -732,7 +667,7 @@ function applyDeletedListMarkerAttrs(attrs, change, listCounters, listAbstractCo
732
667
  if (previousListAttrs.listMarkerAlignment) attrs.listMarkerAlignment = previousListAttrs.listMarkerAlignment;
733
668
  if (previousListAttrs.listMarkerSuffix) attrs.listMarkerSuffix = previousListAttrs.listMarkerSuffix;
734
669
  }
735
- function convertParagraphAttrs(pmAttrs, theme, listCounters, listAbstractCounters, listSeenNumIds, defaultTabStopTwips, originalListCounters, originalListAbstractCounters, originalListSeenNumIds) {
670
+ function convertParagraphAttrs(pmAttrs, { theme, listCounterStreams, defaultTabStopTwips }) {
736
671
  const attrs = {};
737
672
  if (pmAttrs.alignment) {
738
673
  const align = pmAttrs.alignment;
@@ -851,15 +786,7 @@ function convertParagraphAttrs(pmAttrs, theme, listCounters, listAbstractCounter
851
786
  if (numberingInsertionChange) attrs.listMarkerRevision = toListMarkerRevision("ins", numberingInsertionChange.info);
852
787
  }
853
788
  }
854
- const useOriginalStream = attrs.listMarkerRevision?.kind === "del" && originalListCounters !== void 0;
855
- const streamCounters = useOriginalStream ? originalListCounters : listCounters;
856
- const resolvedMarker = applyMarkerAllCaps(streamCounters ? computeListMarker(pmAttrs, streamCounters, (useOriginalStream ? originalListAbstractCounters : listAbstractCounters) ?? /* @__PURE__ */ new Map(), (useOriginalStream ? originalListSeenNumIds : listSeenNumIds) ?? /* @__PURE__ */ new Set()) : null, pmAttrs.listMarkerAllCaps);
857
- const numberedNumId = pmAttrs.numPr?.numId;
858
- if (attrs.listMarkerRevision === void 0 && !pmAttrs.listIsBullet && originalListCounters !== void 0 && numberedNumId !== void 0 && numberedNumId !== 0) computeListMarker(pmAttrs, originalListCounters, originalListAbstractCounters ?? /* @__PURE__ */ new Map(), originalListSeenNumIds ?? /* @__PURE__ */ new Set());
859
- else if (changedNumberingChange !== void 0 && originalListCounters !== void 0) {
860
- const previousListAttrs = toPreviousListAttrs(changedNumberingChange.previousFormatting);
861
- if (previousListAttrs.numPr && !previousListAttrs.listIsBullet) computeListMarker(previousListAttrs, originalListCounters, originalListAbstractCounters ?? /* @__PURE__ */ new Map(), originalListSeenNumIds ?? /* @__PURE__ */ new Set());
862
- }
789
+ const resolvedMarker = applyMarkerAllCaps(advanceVisibleListMarker(pmAttrs, listCounterStreams).marker, pmAttrs.listMarkerAllCaps);
863
790
  if (resolvedMarker !== null) attrs.listMarker = resolvedMarker;
864
791
  else if (pmAttrs.listMarker) attrs.listMarker = pmAttrs.listIsBullet ? convertBulletToUnicode(pmAttrs.listMarker) : pmAttrs.listMarker;
865
792
  if (pmAttrs.listIsBullet !== void 0) attrs.listIsBullet = pmAttrs.listIsBullet;
@@ -870,7 +797,13 @@ function convertParagraphAttrs(pmAttrs, theme, listCounters, listAbstractCounter
870
797
  if (pmAttrs.listMarkerSecondSlotOffsetTwips !== void 0) attrs.listMarkerSecondSlotOffsetTwips = pmAttrs.listMarkerSecondSlotOffsetTwips;
871
798
  if (!pmAttrs.numPr) {
872
799
  const numberingRemovedChange = propertyChanges.find(isRemovedNumberingChange);
873
- if (numberingRemovedChange) applyDeletedListMarkerAttrs(attrs, numberingRemovedChange, originalListCounters, originalListAbstractCounters, originalListSeenNumIds, theme);
800
+ if (numberingRemovedChange) {
801
+ applyDeletedListMarkerAttrs(attrs, numberingRemovedChange, void 0, theme);
802
+ if (resolvedMarker !== null) {
803
+ attrs.listMarker = resolvedMarker;
804
+ attrs.listMarkerRevision = toListMarkerRevision("del", numberingRemovedChange.info);
805
+ }
806
+ }
874
807
  }
875
808
  if (defaultTabStopTwips !== void 0) attrs.defaultTabStopTwips = defaultTabStopTwips;
876
809
  const dtf = pmAttrs.defaultTextFormatting;
@@ -908,7 +841,11 @@ function hasOnlyVisuallyEmptyTextRuns(runs) {
908
841
  function convertParagraph(node, startPos, options) {
909
842
  const pmAttrs = expectParagraphAttrs(node);
910
843
  const runs = paragraphToRuns(node, startPos, options);
911
- const attrs = convertParagraphAttrs(pmAttrs, options.theme, options.listCounters, options.listAbstractCounters, options.listSeenNumIds, options.defaultTabStopTwips, options.originalListCounters, options.originalListAbstractCounters, options.originalListSeenNumIds);
844
+ const attrs = convertParagraphAttrs(pmAttrs, {
845
+ theme: options.theme,
846
+ listCounterStreams: options.listCounterStreams,
847
+ defaultTabStopTwips: options.defaultTabStopTwips
848
+ });
912
849
  if (options.lineBreakRules) attrs.lineBreakRules = options.lineBreakRules;
913
850
  if (options.justificationCompatibility) attrs.justificationCompatibility = options.justificationCompatibility;
914
851
  if (options.automaticHyphenation) attrs.automaticHyphenation = options.automaticHyphenation;
@@ -1283,6 +1220,11 @@ function convertTextBoxNode(node, startPos, opts) {
1283
1220
  if (attrs._docxGroupId !== void 0) setTextBoxGroupId(textBox, attrs._docxGroupId);
1284
1221
  return textBox;
1285
1222
  }
1223
+ function getLastMapKey(map) {
1224
+ let lastKey;
1225
+ for (const key of map.keys()) lastKey = key;
1226
+ return lastKey;
1227
+ }
1286
1228
  /**
1287
1229
  * Convert a ProseMirror document to FlowBlock array.
1288
1230
  *
@@ -1292,16 +1234,40 @@ function convertTextBoxNode(node, startPos, opts) {
1292
1234
  function toFlowBlocks(doc, options = {}) {
1293
1235
  assertValidProseMirrorDocument(doc, "Cannot layout invalid ProseMirror document");
1294
1236
  resetBlockIdCounter();
1237
+ const listCounters = options.listCounters ?? /* @__PURE__ */ new Map();
1238
+ const originalListCounters = options.originalListCounters ?? /* @__PURE__ */ new Map();
1239
+ const lastAdvancedNumId = getLastMapKey(listCounters);
1240
+ const lastAdvancedOriginalNumId = getLastMapKey(originalListCounters);
1241
+ const listCounterState = {
1242
+ counters: listCounters,
1243
+ abstractCounters: options.listAbstractCounters ?? /* @__PURE__ */ new Map(),
1244
+ seenLevels: options.listSeenNumIds ?? /* @__PURE__ */ new Set(),
1245
+ ...lastAdvancedNumId !== void 0 ? { lastAdvancedNumId } : {}
1246
+ };
1247
+ const originalListCounterState = {
1248
+ counters: originalListCounters,
1249
+ abstractCounters: options.originalListAbstractCounters ?? /* @__PURE__ */ new Map(),
1250
+ seenLevels: options.originalListSeenNumIds ?? /* @__PURE__ */ new Set(),
1251
+ ...lastAdvancedOriginalNumId !== void 0 ? { lastAdvancedNumId: lastAdvancedOriginalNumId } : {}
1252
+ };
1295
1253
  const opts = {
1296
1254
  ...options,
1297
1255
  defaultFont: options.defaultFont ?? DEFAULT_FONT,
1298
1256
  defaultSize: options.defaultSize ?? DEFAULT_SIZE,
1299
- listCounters: options.listCounters ?? /* @__PURE__ */ new Map(),
1300
- listAbstractCounters: options.listAbstractCounters ?? /* @__PURE__ */ new Map(),
1301
- listSeenNumIds: options.listSeenNumIds ?? /* @__PURE__ */ new Set(),
1302
- originalListCounters: options.originalListCounters ?? /* @__PURE__ */ new Map(),
1303
- originalListAbstractCounters: options.originalListAbstractCounters ?? /* @__PURE__ */ new Map(),
1304
- originalListSeenNumIds: options.originalListSeenNumIds ?? /* @__PURE__ */ new Set()
1257
+ listCounters: listCounterState.counters,
1258
+ listAbstractCounters: listCounterState.abstractCounters,
1259
+ listSeenNumIds: listCounterState.seenLevels,
1260
+ originalListCounters: originalListCounterState.counters,
1261
+ originalListAbstractCounters: originalListCounterState.abstractCounters,
1262
+ originalListSeenNumIds: originalListCounterState.seenLevels,
1263
+ listCounterStreams: {
1264
+ final: listCounterState,
1265
+ original: originalListCounterState
1266
+ },
1267
+ numberedRefResults: resolveNumberedRefFields(doc, {
1268
+ listCounterState: cloneListCounterState(listCounterState),
1269
+ originalListCounterState: cloneListCounterState(originalListCounterState)
1270
+ })
1305
1271
  };
1306
1272
  const blocks = [];
1307
1273
  const offset = 0;
@@ -1,4 +1,4 @@
1
- import { resolveListTemplate } from "../layout-bridge/convert/toFlowBlocks.js";
1
+ import { resolveListTemplate } from "../prosemirror/listMarker.js";
2
2
  import { isHeadingStyle, parseHeadingLevel } from "./headings.js";
3
3
  import { renderParagraphInline } from "./renderRuns.js";
4
4
  //#region src/markdown/renderParagraph.ts
@@ -58,7 +58,12 @@ function resolveTemplateMarker(ctx, list) {
58
58
  for (let i = level + 1; i < counters.length; i += 1) counters[i] = 0;
59
59
  ctx.listCounters.set(list.numId, counters);
60
60
  const levelFormats = list.levelNumFmts ?? (list.numFmt ? [list.numFmt] : void 0);
61
- return resolveListTemplate(list.marker, counters, levelFormats, list.isLegal).trim();
61
+ return resolveListTemplate({
62
+ template: list.marker,
63
+ counters,
64
+ levelFormats,
65
+ forceDecimal: list.isLegal
66
+ }).trim();
62
67
  }
63
68
  //#endregion
64
69
  export { renderParagraph };
@@ -371,10 +371,11 @@ const expectImageAttrs = (node) => expectCachedNodeAttrs(node, imageAttrsCache,
371
371
  const readFieldAttrs = (node) => {
372
372
  const attrs = attrsRecord(node.attrs);
373
373
  const issues = [];
374
- expectNodeType(node, "field", issues);
374
+ expectNodeTypeOneOf(node, ["field", "structuredField"], issues);
375
375
  requiredOneOf(attrs, "fieldType", "field.attrs.fieldType", issues, FIELD_TYPE_VALUES);
376
376
  requiredString(attrs, "instruction", "field.attrs.instruction", issues);
377
377
  requiredString(attrs, "displayText", "field.attrs.displayText", issues);
378
+ optionalString(attrs, "_numberedRefBaseline", "field.attrs._numberedRefBaseline", issues);
378
379
  requiredOneOf(attrs, "fieldKind", "field.attrs.fieldKind", issues, FIELD_KINDS);
379
380
  optionalBoolean(attrs, "fldLock", "field.attrs.fldLock", issues);
380
381
  optionalBoolean(attrs, "dirty", "field.attrs.dirty", issues);
@@ -0,0 +1,8 @@
1
+ import { BookmarkBoundaryAttrs } from "./schema/nodes.js";
2
+ import { ReadProseMirrorAttrsResult } from "./attrs/index.js";
3
+ import { Node } from "prosemirror-model";
4
+ //#region src/prosemirror/bookmarkBoundaryAttrs.d.ts
5
+ declare const readBookmarkBoundaryAttrs: (node: Node) => ReadProseMirrorAttrsResult<BookmarkBoundaryAttrs>;
6
+ declare const expectBookmarkBoundaryAttrs: (node: Node) => BookmarkBoundaryAttrs;
7
+ //#endregion
8
+ export { expectBookmarkBoundaryAttrs, readBookmarkBoundaryAttrs };
@@ -0,0 +1,66 @@
1
+ import { panic } from "better-result";
2
+ //#region src/prosemirror/bookmarkBoundaryAttrs.ts
3
+ const attrsCache = /* @__PURE__ */ new WeakMap();
4
+ const readBookmarkBoundaryAttrs = (node) => {
5
+ const issues = [];
6
+ if (node.type.name !== "bookmarkBoundary") issues.push({
7
+ path: "bookmarkBoundary.type.name",
8
+ message: `Expected bookmarkBoundary, got ${node.type.name}.`
9
+ });
10
+ const type = node.attrs["type"];
11
+ if (type !== "start" && type !== "end") issues.push({
12
+ path: "bookmarkBoundary.attrs.type",
13
+ message: "Expected \"start\" or \"end\"."
14
+ });
15
+ const id = node.attrs["id"];
16
+ if (typeof id !== "number" || !Number.isInteger(id) || id < 0) issues.push({
17
+ path: "bookmarkBoundary.attrs.id",
18
+ message: "Expected a non-negative integer."
19
+ });
20
+ const name = node.attrs["name"];
21
+ if (type === "start" && (typeof name !== "string" || name.length === 0)) issues.push({
22
+ path: "bookmarkBoundary.attrs.name",
23
+ message: "Expected a non-empty string for a bookmark start."
24
+ });
25
+ const colFirst = node.attrs["colFirst"];
26
+ if (colFirst !== void 0 && colFirst !== null && (typeof colFirst !== "number" || !Number.isInteger(colFirst) || colFirst < 0)) issues.push({
27
+ path: "bookmarkBoundary.attrs.colFirst",
28
+ message: "Expected a non-negative integer."
29
+ });
30
+ const colLast = node.attrs["colLast"];
31
+ if (colLast !== void 0 && colLast !== null && (typeof colLast !== "number" || !Number.isInteger(colLast) || colLast < 0)) issues.push({
32
+ path: "bookmarkBoundary.attrs.colLast",
33
+ message: "Expected a non-negative integer."
34
+ });
35
+ if (issues.length > 0 || typeof id !== "number") return {
36
+ ok: false,
37
+ issues
38
+ };
39
+ if (type === "start" && typeof name === "string") return {
40
+ ok: true,
41
+ value: {
42
+ type,
43
+ id,
44
+ name,
45
+ ...typeof colFirst === "number" ? { colFirst } : {},
46
+ ...typeof colLast === "number" ? { colLast } : {}
47
+ }
48
+ };
49
+ return {
50
+ ok: true,
51
+ value: {
52
+ type: "end",
53
+ id
54
+ }
55
+ };
56
+ };
57
+ const expectBookmarkBoundaryAttrs = (node) => {
58
+ const cached = attrsCache.get(node);
59
+ if (cached) return cached;
60
+ const result = readBookmarkBoundaryAttrs(node);
61
+ if (!result.ok) panic(`Invalid ProseMirror bookmark boundary attrs:\n${result.issues.map((issue) => `${issue.path}: ${issue.message}`).join("\n")}`);
62
+ attrsCache.set(node, result.value);
63
+ return result.value;
64
+ };
65
+ //#endregion
66
+ export { expectBookmarkBoundaryAttrs, readBookmarkBoundaryAttrs };