@stll/folio-core 0.58.5 → 0.59.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 (101) hide show
  1. package/dist/ai-edits/apply.d.ts +11 -12
  2. package/dist/ai-edits/apply.js +179 -168
  3. package/dist/ai-edits/headless.d.ts +15 -13
  4. package/dist/ai-edits/headless.js +40 -13
  5. package/dist/ai-edits/index.d.ts +3 -3
  6. package/dist/ai-edits/newListNumbering.d.ts +3 -9
  7. package/dist/ai-edits/newListNumbering.js +36 -41
  8. package/dist/ai-edits/referenceClassification.d.ts +22 -0
  9. package/dist/ai-edits/referenceClassification.js +21 -0
  10. package/dist/ai-edits/snapshot.js +39 -40
  11. package/dist/ai-edits/types.d.ts +24 -32
  12. package/dist/compare/column-alignment.d.ts +4 -4
  13. package/dist/compare/compare.d.ts +3 -7
  14. package/dist/compare/compare.js +25 -27
  15. package/dist/compare/content-alignment.d.ts +9 -9
  16. package/dist/compare/content-types.d.ts +23 -10
  17. package/dist/compare/content-types.js +14 -0
  18. package/dist/compare/content.d.ts +16 -17
  19. package/dist/compare/content.js +30 -7
  20. package/dist/compare/formatting.d.ts +3 -3
  21. package/dist/compare/import-style-closure.d.ts +22 -0
  22. package/dist/compare/import-style-closure.js +33 -0
  23. package/dist/compare/inserted-resource-snapshot.d.ts +15 -0
  24. package/dist/compare/inserted-resource-snapshot.js +63 -0
  25. package/dist/compare/plan.js +20 -13
  26. package/dist/compare/scenario.js +12 -2
  27. package/dist/compare/style-resources.d.ts +8 -2
  28. package/dist/compare/style-resources.js +63 -14
  29. package/dist/compare/verification.d.ts +15 -3
  30. package/dist/compare/verification.js +47 -8
  31. package/dist/compat/eigenpal.d.ts +4 -4
  32. package/dist/controller/canonicalListRendering.js +13 -22
  33. package/dist/controller/canonicalPublicOperations.js +1 -1
  34. package/dist/controller/canonicalStructure.js +45 -21
  35. package/dist/document-operations.d.ts +4 -9
  36. package/dist/document-operations.js +45 -41
  37. package/dist/docx/attributeRemainder.d.ts +1 -1
  38. package/dist/docx/index.d.ts +1 -1
  39. package/dist/docx/listMarkerComputation.js +9 -14
  40. package/dist/docx/listTemplate.d.ts +22 -0
  41. package/dist/docx/listTemplate.js +40 -0
  42. package/dist/docx/numberingParser.js +2 -2
  43. package/dist/docx/numberingReferenceNormalization.js +3 -3
  44. package/dist/docx/paragraphParser.js +3 -4
  45. package/dist/docx/rezip.js +2 -2
  46. package/dist/docx/server/materializeYjsDocx.js +2 -2
  47. package/dist/docx/server/migrateYjsAttrSchema.js +5 -5
  48. package/dist/generated/text_shaper.js +8 -4
  49. package/dist/generated/text_shaper_bg.wasm +0 -0
  50. package/dist/index.d.ts +4 -4
  51. package/dist/internal/paragraphFormattingSerialization.d.ts +1 -8
  52. package/dist/internal/paragraphFormattingSerialization.js +6 -20
  53. package/dist/layout-bridge/convert/flowConversionShared.d.ts +1 -1
  54. package/dist/layout-bridge/convert/listMarkers.d.ts +1 -2
  55. package/dist/layout-bridge/convert/listMarkers.js +3 -11
  56. package/dist/layout-bridge/convert/paragraphAttrs.d.ts +1 -1
  57. package/dist/layout-bridge/convert/paragraphAttrs.js +8 -4
  58. package/dist/layout-bridge/convert/toFlowBlocks.d.ts +2 -1
  59. package/dist/layout-bridge/convert/toFlowBlocks.js +2 -1
  60. package/dist/markdown/renderParagraph.js +29 -3
  61. package/dist/prosemirror/commands/comments.js +5 -32
  62. package/dist/prosemirror/commands/paragraphBookmarkJoin.d.ts +7 -1
  63. package/dist/prosemirror/commands/paragraphBookmarkJoin.js +35 -1
  64. package/dist/prosemirror/commands/propertyChangeScope.js +6 -0
  65. package/dist/prosemirror/commands/resolveParagraphProperties.js +10 -5
  66. package/dist/prosemirror/conversion/fromProseDoc.js +23 -9
  67. package/dist/prosemirror/conversion/toProseDoc.js +31 -7
  68. package/dist/prosemirror/extensions/core/ParagraphExtension.js +29 -14
  69. package/dist/prosemirror/extensions/features/ListExtension.js +51 -21
  70. package/dist/prosemirror/listInstanceReferences.js +21 -15
  71. package/dist/prosemirror/listLabels.d.ts +4 -3
  72. package/dist/prosemirror/listLabels.js +18 -51
  73. package/dist/prosemirror/listMarker.d.ts +2 -19
  74. package/dist/prosemirror/listMarker.js +28 -57
  75. package/dist/prosemirror/listNumbering.js +16 -6
  76. package/dist/prosemirror/listRendering.d.ts +4 -3
  77. package/dist/prosemirror/listRendering.js +22 -3
  78. package/dist/prosemirror/listRenderingAttrs.d.ts +2 -1
  79. package/dist/prosemirror/listRenderingAttrs.js +6 -11
  80. package/dist/prosemirror/numberedRefFields.js +9 -5
  81. package/dist/prosemirror/numberingAttr.d.ts +19 -1
  82. package/dist/prosemirror/numberingAttr.js +16 -2
  83. package/dist/prosemirror/paragraphIndentation.js +5 -2
  84. package/dist/prosemirror/paragraphMarkJoin.js +17 -3
  85. package/dist/prosemirror/paragraphPropertyCarry.js +5 -6
  86. package/dist/prosemirror/plugins/transactionInvariants.js +6 -2
  87. package/dist/prosemirror/schema/nodes.d.ts +2 -1
  88. package/dist/prosemirror/selectionState.js +5 -1
  89. package/dist/prosemirror/storyListNumbering.js +11 -12
  90. package/dist/prosemirror/styles/paragraphStyleCascade.js +2 -6
  91. package/dist/prosemirror/styles/resolvedStyleAttrs.d.ts +11 -4
  92. package/dist/prosemirror/styles/resolvedStyleAttrs.js +28 -18
  93. package/dist/prosemirror/yjsDocumentMetadata.d.ts +9 -3
  94. package/dist/prosemirror/yjsDocumentMetadata.js +42 -10
  95. package/dist/redline.d.ts +17 -1
  96. package/dist/redline.js +118 -57
  97. package/dist/server.d.ts +3 -3
  98. package/dist/server.js +2 -2
  99. package/dist/version-comparison.d.ts +1 -2
  100. package/dist/version-comparison.js +1 -2
  101. package/package.json +4 -3
@@ -1,7 +1,7 @@
1
1
  import { document_d_exports } from "../types/document.js";
2
2
  import { FolioTableTemplates } from "./table-template.js";
3
3
  import { FolioAIBlock, FolioAIEditApplyMode, FolioAIEditApplyResult, FolioAIEditOperation, FolioAIEditSnapshot } from "./types.js";
4
- import { FolioReplacementBackground, FolioRevisionStamp, FolioUndefinedStylePolicy, FolioWordDiffOptions } from "./apply.js";
4
+ import { FolioReplacementBackground, FolioRevisionStamp, FolioUndefinedReferencePolicy, FolioWordDiffOptions } from "./apply.js";
5
5
  import { ImportReferencedStyleDefinitionsResult } from "../compare/style-resources.js";
6
6
  import { InlineProvenanceTargetOptions } from "../compare/inline-provenance.js";
7
7
  import { MatchInlineAtomsOptions } from "../compare/inline-atoms.js";
@@ -21,6 +21,8 @@ type FolioDocxReviewerOptions = {
21
21
  };
22
22
  /** Options for {@link FolioDocxReviewer.applyOperations}. */
23
23
  type FolioApplyOperationsOptions = {
24
+ /** Required policy for undefined style and numbering references. */
25
+ undefinedReferences: FolioUndefinedReferencePolicy;
24
26
  /** `"tracked-changes"` (default) produces ins/del redlines; `"direct"` edits in place. */
25
27
  mode?: FolioAIEditApplyMode;
26
28
  /**
@@ -160,13 +162,6 @@ type FolioApplyDocumentOperationsToStoryOptions = FolioApplyDocumentOperationsOp
160
162
  * the target document — keeps them instead.
161
163
  */
162
164
  replacementBackground?: FolioReplacementBackground;
163
- /**
164
- * What an operation naming a paragraph style the document does not define
165
- * does. Refusing it is the default; a caller copying another document's
166
- * style references — `compareDocx` and `generateRedlineDocx` reproducing the
167
- * revised document — keeps them instead.
168
- */
169
- undefinedStyles?: FolioUndefinedStylePolicy;
170
165
  };
171
166
  type FolioHeaderFooterStoryHandle = Extract<FolioEditableDocumentStoryHandle, {
172
167
  type: "header" | "footer";
@@ -213,15 +208,22 @@ type StoryInlineAtomsResult = {
213
208
  status: "budget-exceeded";
214
209
  };
215
210
  type StageTargetNumberingResult = "unchanged" | "staged" | "conflict";
211
+ type StageTargetStylesOptions = {
212
+ source: FolioDocxReviewer;
213
+ snapshots: readonly FolioAIEditSnapshot[];
214
+ importedHeaderFooterSnapshots: readonly FolioAIEditSnapshot[];
215
+ numberingReferenceMap?: ReadonlyMap<number, number>;
216
+ };
216
217
  type FolioDocxComparisonAccess = {
217
218
  stageTerminalTableReviewCarrier: (target: Node) => boolean;
218
- stageTargetStyles: (source: FolioDocxReviewer, snapshots: readonly FolioAIEditSnapshot[], importedHeaderFooterSnapshots: readonly FolioAIEditSnapshot[]) => ImportReferencedStyleDefinitionsResult;
219
+ stageTargetStyles: (options: StageTargetStylesOptions) => ImportReferencedStyleDefinitionsResult;
219
220
  createComparisonHeaderFooter: (source: FolioDocxReviewer, story: FolioHeaderFooterStoryHandle) => Promise<FolioHeaderFooterStoryHandle | null>;
220
221
  matchInlineAtoms: (options: MatchStoryInlineAtomsOptions) => StoryInlineAtomsResult;
221
222
  matchInlineProvenance: (options: MatchStoryInlineProvenanceOptions) => StoryInlineProvenanceResult;
222
223
  projectStories: (mode: FolioDocxComparisonProjectionMode) => FolioDocxComparisonProjection;
223
224
  snapshotReviewedStory: (options?: FolioReadReviewedStoryOptions) => FolioAIEditSnapshot | null;
224
225
  numberingDefinitions: () => document_d_exports.NumberingDefinitions | null | undefined;
226
+ styleDefinitions: () => document_d_exports.Document["package"]["styles"];
225
227
  planTargetNumberingReferences: (target: document_d_exports.NumberingDefinitions | null | undefined, references: readonly {
226
228
  numId: number;
227
229
  level: number;
@@ -328,7 +330,7 @@ type FolioReviewCommentFilter = {
328
330
  * const { blocks } = reviewer.snapshot();
329
331
  * reviewer.applyOperations([
330
332
  * { id: "1", type: "replaceInBlock", blockId: blocks[0].id, find: "$50k", replace: "$500k" },
331
- * ]);
333
+ * ], { undefinedReferences: "refuse" });
332
334
  * const reviewed = await reviewer.toBuffer();
333
335
  * ```
334
336
  */
@@ -436,16 +438,16 @@ declare class FolioDocxReviewer {
436
438
  * verbatim via a headless `{ state, dispatch }` seam; the resulting state
437
439
  * (including any comments) is retained for {@link toBuffer}.
438
440
  */
439
- applyOperations(operations: FolioAIEditOperation[], options?: FolioApplyOperationsOptions): FolioAIEditApplyResult;
441
+ applyOperations(operations: FolioAIEditOperation[], options: FolioApplyOperationsOptions): FolioAIEditApplyResult;
440
442
  /**
441
443
  * Apply a versioned document-operation batch against the current state.
442
444
  * This is the contract entry point for serialized callers; the legacy
443
445
  * {@link applyOperations} method delegates here so both APIs keep identical
444
446
  * edit semantics.
445
447
  */
446
- applyDocumentOperations(batch: FolioDocumentOperationBatch, options?: FolioApplyDocumentOperationsOptions): FolioDocumentOperationResult;
448
+ applyDocumentOperations(batch: FolioDocumentOperationBatch, options: FolioApplyDocumentOperationsOptions): FolioDocumentOperationResult;
447
449
  /** Apply a versioned operation batch to one editable document story. */
448
- applyDocumentOperationsToStory({ story, batch, snapshot, revisionStamp, wordDiff, tableTemplates, replacementBackground, undefinedStyles }: FolioApplyDocumentOperationsToStoryOptions): FolioDocumentOperationResult;
450
+ applyDocumentOperationsToStory({ story, batch, snapshot, revisionStamp, wordDiff, tableTemplates, replacementBackground, undefinedReferences }: FolioApplyDocumentOperationsToStoryOptions): FolioDocumentOperationResult;
449
451
  /** Apply a batch; the notes whose references it deletes or removes follow them. */
450
452
  private applyDocumentOperationsInternal;
451
453
  private applyDocumentOperationsToStoryState;
@@ -1,7 +1,7 @@
1
1
  import { matchInlineAtoms } from "../compare/inline-atoms.js";
2
2
  import { matchInlineProvenance } from "../compare/inline-provenance.js";
3
3
  import { stageSectionBoundaryProperties } from "../compare/section-boundary-properties.js";
4
- import { importReferencedStyleDefinitions } from "../compare/style-resources.js";
4
+ import { importReferencedStyleDefinitions, styleClosureNumberingReferences } from "../compare/style-resources.js";
5
5
  import { applyFolioDocumentOperations } from "../document-operations.js";
6
6
  import { applyReplyThreadMarkers } from "../docx/commentReplyMarkers.js";
7
7
  import { rebindDrawingImageRelationship } from "../docx/drawingRelationships.js";
@@ -42,6 +42,7 @@ import { anchoredCommentIdsInBlocks, anchoredCommentIdsInProseDoc, withoutLostCo
42
42
  import { noteReferenceEditsAllowed } from "./note-references.js";
43
43
  import { FolioPendingSuggestionRegistry, createPendingSuggestionSourceSnapshot, withoutPendingSuggestionCommentMarks } from "./pending-suggestions.js";
44
44
  import { getCommentAnchorsFromDoc, getTrackedChangeGroupIdsFromDoc, getTrackedChangeStatsFromDoc, getTrackedChangesFromDoc, getTrackedChangesFromSnapshot } from "./read.js";
45
+ import { classifyResourceReference } from "./referenceClassification.js";
45
46
  import { collectNoteReferenceLabels, createFolioAIEditSnapshotWithStyleResolver, detachFolioAIEditSnapshotExternalHyperlinks, folioStoryTables, isFolioAIContentBlock, normalizeFolioAIBlockText, sourceDocumentOf } from "./snapshot.js";
46
47
  import { matchTableGeometry } from "./table-geometry.js";
47
48
  import { tableTemplateCanCrossPackageLosslessly } from "./table-template.js";
@@ -371,7 +372,7 @@ const paragraphPlainText = (paragraph) => {
371
372
  * const { blocks } = reviewer.snapshot();
372
373
  * reviewer.applyOperations([
373
374
  * { id: "1", type: "replaceInBlock", blockId: blocks[0].id, find: "$50k", replace: "$500k" },
374
- * ]);
375
+ * ], { undefinedReferences: "refuse" });
375
376
  * const reviewed = await reviewer.toBuffer();
376
377
  * ```
377
378
  */
@@ -415,7 +416,7 @@ var FolioDocxReviewer = class FolioDocxReviewer {
415
416
  this.loadedMainCommentIds = anchoredCommentIdsInProseDoc(args.state.doc);
416
417
  comparisonAccessByReviewer.set(this, Object.freeze({
417
418
  stageTerminalTableReviewCarrier: (target) => this.stageTerminalTableReviewCarrier(target),
418
- stageTargetStyles: (source, snapshots, importedHeaderFooterSnapshots) => this.stageTargetStyles(source, snapshots, importedHeaderFooterSnapshots),
419
+ stageTargetStyles: (options) => this.stageTargetStyles(options),
419
420
  createComparisonHeaderFooter: (source, story) => this.createComparisonHeaderFooter(source, story),
420
421
  finalSectionProperties: () => this.currentFinalSectionProperties(),
421
422
  stageFinalSectionProperties: ({ target, previous, revision }) => this.stageFinalSectionProperties({
@@ -473,16 +474,17 @@ var FolioDocxReviewer = class FolioDocxReviewer {
473
474
  projectStories: (mode) => this.projectComparisonStoriesInternal(mode),
474
475
  snapshotReviewedStory: (options) => this.snapshotReviewedStoryInternal(options),
475
476
  numberingDefinitions: () => this.baseDocument.package.numbering,
477
+ styleDefinitions: () => this.importedStyles ?? this.baseDocument.package.styles,
476
478
  planTargetNumberingReferences: (target, references) => this.planTargetNumberingReferences(target, references),
477
479
  stageTargetNumbering: (target, references, remappedNumIds) => this.stageTargetNumbering(target, references, remappedNumIds)
478
480
  }));
479
481
  }
480
- stageTargetStyles(source, snapshots, importedHeaderFooterSnapshots) {
482
+ stageTargetStyles({ source, snapshots, importedHeaderFooterSnapshots, numberingReferenceMap }) {
481
483
  const destination = this.baseDocument.package;
482
484
  const sourcePackage = source.baseDocument.package;
483
485
  const destinationStyles = this.importedStyles ?? destination.styles;
484
- const existing = new Set(destinationStyles?.styles.map(({ styleId }) => styleId));
485
- const sourceStyleIds = new Set(sourcePackage.styles?.styles.map(({ styleId }) => styleId));
486
+ const sourceStylesById = new Map(sourcePackage.styles?.styles.map((style) => [style.styleId, style]));
487
+ const destinationStyleIds = new Set(destinationStyles?.styles.map(({ styleId }) => styleId));
486
488
  const collect = (document) => {
487
489
  const references = /* @__PURE__ */ new Set();
488
490
  document.descendants((node) => {
@@ -508,7 +510,12 @@ var FolioDocxReviewer = class FolioDocxReviewer {
508
510
  let materializeDefaultParagraphStyle = false;
509
511
  for (const snapshot of resourceSnapshots) {
510
512
  if (hasUnstyledParagraph(sourceDocumentOf(snapshot))) materializeDefaultParagraphStyle = true;
511
- for (const styleId of collect(sourceDocumentOf(snapshot))) if (sourceStyleIds.has(styleId) && !existing.has(styleId)) referencedStyleIds.add(styleId);
513
+ for (const styleId of collect(sourceDocumentOf(snapshot))) if (classifyResourceReference({
514
+ kind: "style",
515
+ id: styleId,
516
+ sourceDefines: (id) => sourceStylesById.has(id),
517
+ destinationDefines: (id) => destinationStyleIds.has(id)
518
+ }) === "sourceDefined") referencedStyleIds.add(styleId);
512
519
  }
513
520
  const reservedStyleIds = /* @__PURE__ */ new Set();
514
521
  if (referencedStyleIds.size > 0) for (const handle of this.listStoryHandlesInternal()) {
@@ -516,7 +523,22 @@ var FolioDocxReviewer = class FolioDocxReviewer {
516
523
  if (!state) continue;
517
524
  for (const styleId of collect(state.doc)) if (referencedStyleIds.has(styleId)) reservedStyleIds.add(styleId);
518
525
  }
526
+ let styleNumberingReferenceMap = numberingReferenceMap ?? /* @__PURE__ */ new Map();
527
+ if (numberingReferenceMap !== void 0) {
528
+ const remaining = styleClosureNumberingReferences(sourcePackage.styles, [...referencedStyleIds]).filter(({ numId }) => !numberingReferenceMap.has(numId));
529
+ const planned = this.planTargetNumberingReferences(sourcePackage.numbering, remaining);
530
+ if (planned === null) return {
531
+ status: "unalignable",
532
+ detail: "a referenced style has undefined numbering"
533
+ };
534
+ styleNumberingReferenceMap = new Map([...planned, ...numberingReferenceMap]);
535
+ if (this.stageTargetNumbering(sourcePackage.numbering, remaining, planned) === "conflict") return {
536
+ status: "unalignable",
537
+ detail: "a referenced style's numbering could not be imported"
538
+ };
539
+ }
519
540
  const result = importReferencedStyleDefinitions({
541
+ numberingReferenceMap: styleNumberingReferenceMap,
520
542
  sourceStyles: sourcePackage.styles,
521
543
  destinationStyles,
522
544
  sourceTheme: sourcePackage.theme,
@@ -685,6 +707,7 @@ var FolioDocxReviewer = class FolioDocxReviewer {
685
707
  },
686
708
  apply: (record, snapshot) => {
687
709
  const result = this.applyDocumentOperationsInternal({
710
+ undefinedReferences: "refuse",
688
711
  story: record.story,
689
712
  batch: {
690
713
  version: 1,
@@ -873,7 +896,7 @@ var FolioDocxReviewer = class FolioDocxReviewer {
873
896
  * verbatim via a headless `{ state, dispatch }` seam; the resulting state
874
897
  * (including any comments) is retained for {@link toBuffer}.
875
898
  */
876
- applyOperations(operations, options = {}) {
899
+ applyOperations(operations, options) {
877
900
  const { applied, skipped } = this.applyDocumentOperationsInternal({
878
901
  story: MAIN_STORY,
879
902
  batch: {
@@ -884,6 +907,7 @@ var FolioDocxReviewer = class FolioDocxReviewer {
884
907
  ...options.snapshot !== void 0 && { snapshot: options.snapshot },
885
908
  ...options.revisionStamp !== void 0 && { revisionStamp: options.revisionStamp },
886
909
  ...options.wordDiff !== void 0 && { wordDiff: options.wordDiff },
910
+ undefinedReferences: options.undefinedReferences,
887
911
  createUndoEntry: false
888
912
  });
889
913
  return {
@@ -897,18 +921,19 @@ var FolioDocxReviewer = class FolioDocxReviewer {
897
921
  * {@link applyOperations} method delegates here so both APIs keep identical
898
922
  * edit semantics.
899
923
  */
900
- applyDocumentOperations(batch, options = {}) {
924
+ applyDocumentOperations(batch, options) {
901
925
  return this.applyDocumentOperationsInternal({
902
926
  story: MAIN_STORY,
903
927
  batch,
904
928
  ...options.snapshot !== void 0 && { snapshot: options.snapshot },
905
929
  ...options.revisionStamp !== void 0 && { revisionStamp: options.revisionStamp },
906
930
  ...options.wordDiff !== void 0 && { wordDiff: options.wordDiff },
931
+ undefinedReferences: options.undefinedReferences,
907
932
  createUndoEntry: true
908
933
  });
909
934
  }
910
935
  /** Apply a versioned operation batch to one editable document story. */
911
- applyDocumentOperationsToStory({ story, batch, snapshot, revisionStamp, wordDiff, tableTemplates, replacementBackground, undefinedStyles }) {
936
+ applyDocumentOperationsToStory({ story, batch, snapshot, revisionStamp, wordDiff, tableTemplates, replacementBackground, undefinedReferences }) {
912
937
  return this.applyDocumentOperationsInternal({
913
938
  story,
914
939
  batch,
@@ -917,7 +942,7 @@ var FolioDocxReviewer = class FolioDocxReviewer {
917
942
  ...wordDiff !== void 0 && { wordDiff },
918
943
  ...tableTemplates !== void 0 && { tableTemplates },
919
944
  ...replacementBackground !== void 0 && { replacementBackground },
920
- ...undefinedStyles !== void 0 && { undefinedStyles },
945
+ undefinedReferences,
921
946
  createUndoEntry: true
922
947
  });
923
948
  }
@@ -926,7 +951,7 @@ var FolioDocxReviewer = class FolioDocxReviewer {
926
951
  if (noteReferenceEditsAllowed()) return this.applyDocumentOperationsToStoryState(options);
927
952
  return this.withNotesFollowingReferences(() => this.applyDocumentOperationsToStoryState(options));
928
953
  }
929
- applyDocumentOperationsToStoryState({ story, batch, author, snapshot, revisionStamp, wordDiff, tableTemplates, replacementBackground, undefinedStyles, createUndoEntry }) {
954
+ applyDocumentOperationsToStoryState({ story, batch, author, snapshot, revisionStamp, wordDiff, tableTemplates, replacementBackground, undefinedReferences, createUndoEntry }) {
930
955
  const beforeState = this.requireEditableStoryState(story);
931
956
  const operationAuthor = author ?? this.author;
932
957
  const sourceSnapshot = snapshot ?? createStateSnapshot(beforeState);
@@ -947,7 +972,7 @@ var FolioDocxReviewer = class FolioDocxReviewer {
947
972
  ...wordDiff !== void 0 && { wordDiff },
948
973
  ...tableTemplates !== void 0 && { tableTemplates },
949
974
  ...replacementBackground !== void 0 && { replacementBackground },
950
- ...undefinedStyles !== void 0 && { undefinedStyles },
975
+ undefinedReferences,
951
976
  createCommentId: (text) => {
952
977
  const comment = createReviewerComment({
953
978
  id: this.nextCommentId(),
@@ -1616,6 +1641,7 @@ var FolioDocxReviewer = class FolioDocxReviewer {
1616
1641
  }
1617
1642
  };
1618
1643
  const applied = applyFolioDocumentOperations({
1644
+ undefinedReferences: "refuse",
1619
1645
  view,
1620
1646
  snapshot,
1621
1647
  batch: {
@@ -2214,6 +2240,7 @@ const getFolioDocxComparisonAccess = (reviewer) => comparisonAccessByReviewer.ge
2214
2240
  const applyFolioAIEditsToBuffer = async (buffer, operations, options = {}) => {
2215
2241
  const reviewer = await FolioDocxReviewer.fromBuffer(buffer, { ...options.author !== void 0 && { author: options.author } });
2216
2242
  const { applied, skipped } = reviewer.applyOperations(operations, {
2243
+ undefinedReferences: "refuse",
2217
2244
  ...options.mode !== void 0 && { mode: options.mode },
2218
2245
  ...options.snapshot !== void 0 && { snapshot: options.snapshot }
2219
2246
  });
@@ -1,7 +1,7 @@
1
1
  import { FolioContentParagraphKind } from "../compare/content-types.js";
2
- import { FolioAIBlock, FolioAIBlockAnchor, FolioAIBlockKind, FolioAIBlockPreviewRun, FolioAIBlockStructuralBoundary, FolioAIBlockTableLocation, FolioAIComment, FolioAIEditAppliedOperation, FolioAIEditApplyMode, FolioAIEditApplyResult, FolioAIEditNormalization, FolioAIEditNormalizationCode, FolioAIEditOperation, FolioAIEditPrecondition, FolioAIEditReviewMeta, FolioAIEditSeverity, FolioAIEditSkipReason, FolioAIEditSkippedOperation, FolioAIEditSnapshot, FolioAIInlineBooleanProperty, FolioAIInlineFormatting, FolioAIInlineFormattingPatch, FolioAIInsertFormattingScope, FolioAIParagraphSpacing, FolioAISignatureParty, FolioAITextRangeHandle, FolioDocumentNavigationTarget, FolioDocumentOutline, FolioDocumentOutlineEntry, FolioDocumentSection, FolioDocumentSectionHandle, FolioDocumentSectionReadResult } from "./types.js";
2
+ import { FolioAIBlock, FolioAIBlockAnchor, FolioAIBlockKind, FolioAIBlockPreviewRun, FolioAIBlockStructuralBoundary, FolioAIBlockTableLocation, FolioAIComment, FolioAIDiagnosticBlock, FolioAIEditAppliedOperation, FolioAIEditApplyMode, FolioAIEditApplyResult, FolioAIEditNormalization, FolioAIEditNormalizationCode, FolioAIEditOperation, FolioAIEditPrecondition, FolioAIEditReviewMeta, FolioAIEditSeverity, FolioAIEditSkipReason, FolioAIEditSkippedOperation, FolioAIEditSnapshot, FolioAIInlineBooleanProperty, FolioAIInlineFormatting, FolioAIInlineFormattingPatch, FolioAIInsertFormattingScope, FolioAIParagraphBlock, FolioAIParagraphSpacing, FolioAISignatureParty, FolioAITextRangeHandle, FolioDocumentNavigationTarget, FolioDocumentOutline, FolioDocumentOutlineEntry, FolioDocumentSection, FolioDocumentSectionHandle, FolioDocumentSectionReadResult } from "./types.js";
3
3
  import { WORD_DIFF_GRANULARITIES, WordDiffGranularity, WordDiffNormalization, WordDiffOptions, WordDiffSegment, diffWordSegments } from "./word-diff.js";
4
- import { FolioAIEditApplyOutcome, FolioAIEditView, FolioRevisionStamp, FolioWordDiffOptions, applyFolioAIEditOperations } from "./apply.js";
4
+ import { FolioAIEditApplyOutcome, FolioAIEditView, FolioRevisionStamp, FolioUndefinedReferencePolicy, FolioWordDiffOptions, applyFolioAIEditOperations } from "./apply.js";
5
5
  import { DocPositionRange, clampRangeToDocSize, resolveFolioAIBlockRange, resolveFolioAITextRange, resolvePassageRange } from "./blockRange.js";
6
6
  import { buildAnnotatedBlockText } from "./clean-text.js";
7
7
  import { ApplyFolioDocumentOperationsOptions, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, FOLIO_LINE_SPACING_RULE_VALUES, FOLIO_PARAGRAPH_ALIGNMENT_VALUES, FolioDocumentOperation, FolioDocumentOperationAffectedTarget, FolioDocumentOperationBatch, FolioDocumentOperationCapabilities, FolioDocumentOperationIssue, FolioDocumentOperationMode, FolioDocumentOperationPrecondition, FolioDocumentOperationReceipt, FolioDocumentOperationRecovery, FolioDocumentOperationResult, FolioDocumentOperationResultBase, FolioDocumentOperationStatus, FolioDocumentOperationStory, FolioDocumentOperationType, FolioDocumentOperationUndoFailureReason, FolioDocumentOperationUndoHandle, FolioDocumentOperationUndoResult, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, isFolioDocumentOperationModeSupported, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch } from "../document-operations.js";
@@ -11,4 +11,4 @@ import { createFolioAIEditSnapshot, createFolioAIEditSnapshotWithStyleResolver,
11
11
  import { FOLIO_RESOLVED_REVIEWED_VIEWS, FOLIO_REVIEWED_VIEWS, FolioApplyDocumentOperationsToStoryOptions, FolioDocumentStory, FolioDocumentStoryHandle, FolioDocumentStoryNotFoundError, FolioEditableDocumentStoryHandle, FolioReadReviewedStoryOptions, FolioResolveReviewedStoryOptions, FolioResolvedReviewedView, FolioReviewedStory, FolioReviewedView, UnsupportedFolioReviewedViewError, isFolioResolvedReviewedView, isFolioReviewedView } from "./headless.js";
12
12
  import { getFolioDocumentOutline, readFolioDocumentSection } from "./scoped-reading.js";
13
13
  import { getFolioParaIdFromBlockId } from "../types/block-id.js";
14
- export { type ApplyFolioDocumentOperationsOptions, type DocPositionRange, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, FOLIO_LINE_SPACING_RULE_VALUES, FOLIO_PARAGRAPH_ALIGNMENT_VALUES, FOLIO_PENDING_SUGGESTION_VERSION, FOLIO_RESOLVED_REVIEWED_VIEWS, FOLIO_REVIEWED_VIEWS, type FolioAIBlock, type FolioAIBlockAnchor, type FolioAIBlockKind, type FolioAIBlockPreviewRun, type FolioAIBlockStructuralBoundary, type FolioAIBlockTableLocation, type FolioAIComment, type FolioAIEditAppliedOperation, type FolioAIEditApplyMode, type FolioAIEditApplyOutcome, type FolioAIEditApplyResult, type FolioAIEditNormalization, type FolioAIEditNormalizationCode, type FolioAIEditOperation, type FolioAIEditPrecondition, type FolioAIEditReviewMeta, type FolioAIEditSeverity, type FolioAIEditSkipReason, type FolioAIEditSkippedOperation, type FolioAIEditSnapshot, type FolioAIEditView, type FolioAIInlineBooleanProperty, type FolioAIInlineFormatting, type FolioAIInlineFormattingPatch, type FolioAIInsertFormattingScope, type FolioAIParagraphSpacing, type FolioAISignatureParty, type FolioAITextRangeHandle, type FolioApplyDocumentOperationsToStoryOptions, type FolioCommentAnchor, type FolioContentParagraphKind, type FolioDocumentNavigationTarget, type FolioDocumentOperation, type FolioDocumentOperationAffectedTarget, type FolioDocumentOperationBatch, type FolioDocumentOperationCapabilities, type FolioDocumentOperationIssue, type FolioDocumentOperationMode, type FolioDocumentOperationPrecondition, type FolioDocumentOperationReceipt, type FolioDocumentOperationRecovery, type FolioDocumentOperationResult, type FolioDocumentOperationResultBase, type FolioDocumentOperationStatus, type FolioDocumentOperationStory, type FolioDocumentOperationType, type FolioDocumentOperationUndoFailureReason, type FolioDocumentOperationUndoHandle, type FolioDocumentOperationUndoResult, type FolioDocumentOutline, type FolioDocumentOutlineEntry, type FolioDocumentSection, type FolioDocumentSectionHandle, type FolioDocumentSectionReadResult, type FolioDocumentStory, type FolioDocumentStoryHandle, FolioDocumentStoryNotFoundError, type FolioEditableDocumentStoryHandle, type FolioPendingSuggestionLoadResult, type FolioPendingSuggestionRecord, FolioPendingSuggestionRegistry, type FolioPendingSuggestionStaleReason, type FolioReadReviewedStoryOptions, type FolioResolveReviewedStoryOptions, type FolioResolvedReviewedView, type FolioReviewChange, type FolioReviewChangeKind, type FolioReviewedStory, type FolioReviewedView, type FolioRevisionStamp, type FolioWordDiffOptions, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, UnsupportedFolioReviewedViewError, WORD_DIFF_GRANULARITIES, type WordDiffGranularity, type WordDiffNormalization, type WordDiffOptions, type WordDiffSegment, applyFolioAIEditOperations, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, buildAnnotatedBlockText, clampRangeToDocSize, createFolioAIEditSnapshot, createFolioAIEditSnapshotWithStyleResolver, createFolioAITextRangeHandle, createPendingSuggestionSourceSnapshot, diffWordSegments, getCommentAnchorsFromDoc, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioDocumentOutline, getFolioParaIdFromBlockId, getTrackedChangesFromDoc, hashFolioAIBlockText, isFolioAIContentBlock, isFolioDocumentOperationModeSupported, isFolioResolvedReviewedView, isFolioReviewedView, isSupportedFolioDocumentOperationVersion, normalizeFolioAIBlockText, parseFolioDocumentOperationBatch, readFolioDocumentSection, resolveFolioAIBlockRange, resolveFolioAITextRange, resolvePassageRange };
14
+ export { type ApplyFolioDocumentOperationsOptions, type DocPositionRange, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, FOLIO_LINE_SPACING_RULE_VALUES, FOLIO_PARAGRAPH_ALIGNMENT_VALUES, FOLIO_PENDING_SUGGESTION_VERSION, FOLIO_RESOLVED_REVIEWED_VIEWS, FOLIO_REVIEWED_VIEWS, type FolioAIBlock, type FolioAIBlockAnchor, type FolioAIBlockKind, type FolioAIBlockPreviewRun, type FolioAIBlockStructuralBoundary, type FolioAIBlockTableLocation, type FolioAIComment, type FolioAIDiagnosticBlock, type FolioAIEditAppliedOperation, type FolioAIEditApplyMode, type FolioAIEditApplyOutcome, type FolioAIEditApplyResult, type FolioAIEditNormalization, type FolioAIEditNormalizationCode, type FolioAIEditOperation, type FolioAIEditPrecondition, type FolioAIEditReviewMeta, type FolioAIEditSeverity, type FolioAIEditSkipReason, type FolioAIEditSkippedOperation, type FolioAIEditSnapshot, type FolioAIEditView, type FolioAIInlineBooleanProperty, type FolioAIInlineFormatting, type FolioAIInlineFormattingPatch, type FolioAIInsertFormattingScope, type FolioAIParagraphBlock, type FolioAIParagraphSpacing, type FolioAISignatureParty, type FolioAITextRangeHandle, type FolioApplyDocumentOperationsToStoryOptions, type FolioCommentAnchor, type FolioContentParagraphKind, type FolioDocumentNavigationTarget, type FolioDocumentOperation, type FolioDocumentOperationAffectedTarget, type FolioDocumentOperationBatch, type FolioDocumentOperationCapabilities, type FolioDocumentOperationIssue, type FolioDocumentOperationMode, type FolioDocumentOperationPrecondition, type FolioDocumentOperationReceipt, type FolioDocumentOperationRecovery, type FolioDocumentOperationResult, type FolioDocumentOperationResultBase, type FolioDocumentOperationStatus, type FolioDocumentOperationStory, type FolioDocumentOperationType, type FolioDocumentOperationUndoFailureReason, type FolioDocumentOperationUndoHandle, type FolioDocumentOperationUndoResult, type FolioDocumentOutline, type FolioDocumentOutlineEntry, type FolioDocumentSection, type FolioDocumentSectionHandle, type FolioDocumentSectionReadResult, type FolioDocumentStory, type FolioDocumentStoryHandle, FolioDocumentStoryNotFoundError, type FolioEditableDocumentStoryHandle, type FolioPendingSuggestionLoadResult, type FolioPendingSuggestionRecord, FolioPendingSuggestionRegistry, type FolioPendingSuggestionStaleReason, type FolioReadReviewedStoryOptions, type FolioResolveReviewedStoryOptions, type FolioResolvedReviewedView, type FolioReviewChange, type FolioReviewChangeKind, type FolioReviewedStory, type FolioReviewedView, type FolioRevisionStamp, type FolioUndefinedReferencePolicy, type FolioWordDiffOptions, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, UnsupportedFolioReviewedViewError, WORD_DIFF_GRANULARITIES, type WordDiffGranularity, type WordDiffNormalization, type WordDiffOptions, type WordDiffSegment, applyFolioAIEditOperations, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, buildAnnotatedBlockText, clampRangeToDocSize, createFolioAIEditSnapshot, createFolioAIEditSnapshotWithStyleResolver, createFolioAITextRangeHandle, createPendingSuggestionSourceSnapshot, diffWordSegments, getCommentAnchorsFromDoc, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioDocumentOutline, getFolioParaIdFromBlockId, getTrackedChangesFromDoc, hashFolioAIBlockText, isFolioAIContentBlock, isFolioDocumentOperationModeSupported, isFolioResolvedReviewedView, isFolioReviewedView, isSupportedFolioDocumentOperationVersion, normalizeFolioAIBlockText, parseFolioDocumentOperationBatch, readFolioDocumentSection, resolveFolioAIBlockRange, resolveFolioAITextRange, resolvePassageRange };
@@ -1,16 +1,10 @@
1
- import { FolioAIEditOperation, FolioAIListNumbering, FolioAIListReference, FolioAINewListReference } from "./types.js";
1
+ import { FolioAIEditOperation, FolioAIListNumbering, FolioAINewListReference, FolioAIResolvedEditOperation } from "./types.js";
2
2
  import { NumberingMap } from "../docx/numberingParser.js";
3
3
  //#region src/ai-edits/newListNumbering.d.ts
4
4
  /** Whether `numbering` asks for a new list rather than naming an instance. */
5
5
  declare const isFolioAINewListReference: (numbering: FolioAIListNumbering) => numbering is FolioAINewListReference;
6
- /**
7
- * The concrete instance an operation's numbering names once new lists are
8
- * resolved. A new-list request reaching this point skipped resolution, which
9
- * is a bug in the apply path rather than a malformed operation.
10
- */
11
- declare const concreteListReference: (numbering: FolioAIListNumbering) => FolioAIListReference;
12
6
  type ResolvedNewLists = {
13
- operations: FolioAIEditOperation[];
7
+ operations: FolioAIResolvedEditOperation[];
14
8
  numbering: NumberingMap | null;
15
9
  };
16
10
  /**
@@ -20,4 +14,4 @@ type ResolvedNewLists = {
20
14
  */
21
15
  declare const resolveNewListOperations: (operations: readonly FolioAIEditOperation[], numbering: NumberingMap | null) => ResolvedNewLists;
22
16
  //#endregion
23
- export { concreteListReference, isFolioAINewListReference, resolveNewListOperations };
17
+ export { isFolioAINewListReference, resolveNewListOperations };
@@ -1,9 +1,9 @@
1
1
  import { mintListInstance } from "../docx/listNumberingInstances.js";
2
2
  import { createNumberingMap } from "../docx/numberingParser.js";
3
- import { panic } from "better-result";
3
+ import { paragraphNumberingReference } from "../docx/numberingReference.js";
4
4
  //#region src/ai-edits/newListNumbering.ts
5
5
  /**
6
- * Operations that start a new list (`numbering: { start: "new", kind }`)
6
+ * Operations that start a new list (`numbering: { kind: "newList", format }`)
7
7
  * resolved to the numbering instance each one defines.
8
8
  *
9
9
  * The instance is minted against the document's numbering (the package's
@@ -14,16 +14,7 @@ import { panic } from "better-result";
14
14
  * defines it in the saved package (see `docx/listNumberingInstances.ts`).
15
15
  */
16
16
  /** Whether `numbering` asks for a new list rather than naming an instance. */
17
- const isFolioAINewListReference = (numbering) => "start" in numbering;
18
- /**
19
- * The concrete instance an operation's numbering names once new lists are
20
- * resolved. A new-list request reaching this point skipped resolution, which
21
- * is a bug in the apply path rather than a malformed operation.
22
- */
23
- const concreteListReference = (numbering) => {
24
- if (isFolioAINewListReference(numbering)) return panic("A new-list numbering request reached apply unresolved");
25
- return numbering;
26
- };
17
+ const isFolioAINewListReference = (numbering) => numbering.kind === "newList";
27
18
  /**
28
19
  * Replace every new-list request with a reference to an instance minted for
29
20
  * its operation: one instance per operation and kind. `numbering` is the map
@@ -35,51 +26,55 @@ const resolveNewListOperations = (operations, numbering) => {
35
26
  const resolveOperation = (operation) => {
36
27
  const instances = /* @__PURE__ */ new Map();
37
28
  const resolve = (value) => {
38
- if (value === null || value === void 0 || !isFolioAINewListReference(value)) return value;
39
- let numId = instances.get(value.kind);
29
+ if (value === void 0 || !isFolioAINewListReference(value)) return value;
30
+ let numId = instances.get(value.format);
40
31
  if (numId === void 0) {
41
- const instance = mintListInstance(definitions, { kind: value.kind });
32
+ const instance = mintListInstance(definitions, { kind: value.format });
42
33
  definitions = instance.definitions;
43
34
  numId = instance.numId;
44
- instances.set(value.kind, numId);
35
+ instances.set(value.format, numId);
45
36
  minted = true;
46
37
  }
47
- return {
38
+ return paragraphNumberingReference({
48
39
  numId,
49
- level: value.level ?? 0
40
+ ilvl: value.level ?? 0
41
+ });
42
+ };
43
+ const resolveProperties = (properties) => {
44
+ const { numbering: request, ...rest } = properties;
45
+ const resolved = resolve(request);
46
+ return {
47
+ ...rest,
48
+ ...resolved !== void 0 && { numbering: resolved }
50
49
  };
51
50
  };
52
- const resolveProperties = (properties) => properties?.numbering ? {
53
- ...properties,
54
- numbering: resolve(properties.numbering)
55
- } : properties;
56
51
  switch (operation.type) {
57
52
  case "insertAfterBlock":
58
- case "insertBeforeBlock": return operation.numbering ? {
59
- ...operation,
60
- numbering: resolve(operation.numbering)
61
- } : operation;
62
- case "setBlockParagraphProperties": return operation.properties.numbering ? {
53
+ case "insertBeforeBlock": {
54
+ const { numbering: request, ...rest } = operation;
55
+ const resolved = resolve(request);
56
+ return {
57
+ ...rest,
58
+ ...resolved !== void 0 && { numbering: resolved }
59
+ };
60
+ }
61
+ case "setBlockParagraphProperties": return {
63
62
  ...operation,
64
- properties: {
65
- ...operation.properties,
66
- numbering: resolve(operation.properties.numbering)
67
- }
68
- } : operation;
63
+ properties: resolveProperties(operation.properties)
64
+ };
69
65
  case "splitBlock": {
70
- const firstParagraphProperties = resolveProperties(operation.firstParagraphProperties);
71
- const secondParagraphProperties = resolveProperties(operation.secondParagraphProperties);
66
+ const { firstParagraphProperties: firstRequest, secondParagraphProperties: secondRequest, ...rest } = operation;
72
67
  return {
73
- ...operation,
74
- ...firstParagraphProperties && { firstParagraphProperties },
75
- ...secondParagraphProperties && { secondParagraphProperties }
68
+ ...rest,
69
+ ...firstRequest !== void 0 && { firstParagraphProperties: resolveProperties(firstRequest) },
70
+ ...secondRequest !== void 0 && { secondParagraphProperties: resolveProperties(secondRequest) }
76
71
  };
77
72
  }
78
73
  case "mergeBlockWithNext": {
79
- const mergedParagraphProperties = resolveProperties(operation.mergedParagraphProperties);
74
+ const { mergedParagraphProperties: request, ...rest } = operation;
80
75
  return {
81
- ...operation,
82
- ...mergedParagraphProperties && { mergedParagraphProperties }
76
+ ...rest,
77
+ ...request !== void 0 && { mergedParagraphProperties: resolveProperties(request) }
83
78
  };
84
79
  }
85
80
  default: return operation;
@@ -91,4 +86,4 @@ const resolveNewListOperations = (operations, numbering) => {
91
86
  };
92
87
  };
93
88
  //#endregion
94
- export { concreteListReference, isFolioAINewListReference, resolveNewListOperations };
89
+ export { isFolioAINewListReference, resolveNewListOperations };
@@ -0,0 +1,22 @@
1
+ //#region src/ai-edits/referenceClassification.d.ts
2
+ type ResourceReferenceClassificationOptions = {
3
+ kind: "style";
4
+ id: string;
5
+ sourceDefines: (id: string) => boolean;
6
+ destinationDefines: (id: string) => boolean;
7
+ } | {
8
+ kind: "numbering";
9
+ id: number;
10
+ sourceDefines: (id: number) => boolean;
11
+ destinationDefines: (id: number) => boolean;
12
+ };
13
+ declare const REFERENCE_DISPOSITIONS: {
14
+ readonly sourceDefined: "sourceDefined";
15
+ readonly destinationCollision: "destinationCollision";
16
+ readonly unknown: "unknown";
17
+ };
18
+ type ReferenceDisposition = (typeof REFERENCE_DISPOSITIONS)[keyof typeof REFERENCE_DISPOSITIONS];
19
+ /** A missing source reference may stay dangling, but cannot acquire destination meaning. */
20
+ declare const classifyResourceReference: (reference: ResourceReferenceClassificationOptions) => ReferenceDisposition;
21
+ //#endregion
22
+ export { classifyResourceReference };
@@ -0,0 +1,21 @@
1
+ import { panic } from "better-result";
2
+ //#region src/ai-edits/referenceClassification.ts
3
+ const REFERENCE_DISPOSITIONS = {
4
+ sourceDefined: "sourceDefined",
5
+ destinationCollision: "destinationCollision",
6
+ unknown: "unknown"
7
+ };
8
+ const classifyReferenceSpace = ({ id, sourceDefines, destinationDefines }) => {
9
+ if (sourceDefines(id)) return REFERENCE_DISPOSITIONS.sourceDefined;
10
+ return destinationDefines(id) ? REFERENCE_DISPOSITIONS.destinationCollision : REFERENCE_DISPOSITIONS.unknown;
11
+ };
12
+ /** A missing source reference may stay dangling, but cannot acquire destination meaning. */
13
+ const classifyResourceReference = (reference) => {
14
+ switch (reference.kind) {
15
+ case "style": return classifyReferenceSpace(reference);
16
+ case "numbering": return classifyReferenceSpace(reference);
17
+ default: return panic("Unhandled resource reference kind", { reference });
18
+ }
19
+ };
20
+ //#endregion
21
+ export { classifyResourceReference };
@@ -1,11 +1,11 @@
1
+ import { INHERITED_PARAGRAPH_NUMBERING } from "../compare/content-types.js";
1
2
  import { isAltChunkMarkup } from "../docx/altChunk.js";
2
3
  import { EMPTY_BUILT_IN_STYLE_INDEX, resolveHeadingLevel } from "../docx/builtInStyles.js";
3
- import { resolveParagraphNumbering } from "../docx/numberingReference.js";
4
4
  import { OPAQUE_REVISION_CARRIER_READER_DIAGNOSTIC, isOpaqueNestedRowMarkup, opaqueRevisionCarrierName } from "../docx/opaqueCarrier.js";
5
5
  import { recreateProseNodeWithParagraphPropertySource } from "../docx/paragraphPropertySource.js";
6
6
  import { expectCharacterStyleMarkAttrs, expectHyperlinkMarkAttrs, expectParagraphAttrs, expectRunFormattingOverrideMarkAttrs } from "../prosemirror/attrs/index.js";
7
7
  import { createListLabelCounter } from "../prosemirror/listLabels.js";
8
- import { paragraphNumberingAttr, readParagraphNumberingAttr } from "../prosemirror/numberingAttr.js";
8
+ import { effectiveParagraphNumberingReference, paragraphNumberingAttr, paragraphNumberingSourcesFromBoundary, readParagraphNumberingAttr } from "../prosemirror/numberingAttr.js";
9
9
  import { readOutlineLevelAttr } from "../prosemirror/outlineLevelAttr.js";
10
10
  import { directParagraphAlignment } from "../prosemirror/paragraphAlignment.js";
11
11
  import { directParagraphIndentation } from "../prosemirror/paragraphIndentation.js";
@@ -42,16 +42,21 @@ const remapFolioAIEditSnapshotNumberingReferences = (snapshot, numIdMap) => {
42
42
  if (numIdMap.size === 0) return snapshot;
43
43
  const metadata = metadataOf(snapshot);
44
44
  const remapNode = (node) => {
45
- const numPr = readParagraphNumberingAttr(node.attrs["numPr"]);
46
- if (numPr?.kind !== "reference") return node;
47
- const remappedNumId = numIdMap.get(numPr.numId);
48
- if (remappedNumId === void 0) return node;
45
+ const remapReference = (numPr) => {
46
+ if (numPr?.kind !== "reference") return void 0;
47
+ const numId = numIdMap.get(numPr.numId);
48
+ return numId === void 0 ? void 0 : paragraphNumberingAttr({
49
+ ...numPr,
50
+ numId
51
+ });
52
+ };
53
+ const numPr = remapReference(readParagraphNumberingAttr(node.attrs["numPr"]));
54
+ const numPrFromStyle = remapReference(readParagraphNumberingAttr(node.attrs["numPrFromStyle"]));
55
+ if (numPr === void 0 && numPrFromStyle === void 0) return node;
49
56
  return recreateProseNodeWithParagraphPropertySource(node, { attrs: {
50
57
  ...node.attrs,
51
- numPr: paragraphNumberingAttr({
52
- ...numPr,
53
- numId: remappedNumId
54
- })
58
+ ...numPr && { numPr },
59
+ ...numPrFromStyle && { numPrFromStyle }
55
60
  } });
56
61
  };
57
62
  const remapped = remapDocument(metadata.sourceDocument, remapNode);
@@ -347,7 +352,15 @@ const alignedNoteReferenceLabels = (base, revised) => numberNoteReferencesLazily
347
352
  */
348
353
  const relabelFolioAIEditSnapshotNoteReferences = (snapshot, labels) => {
349
354
  const metadata = metadataOf(snapshot);
350
- if (!snapshot.blocks.some((block) => block.structuralBoundaries?.some(({ type }) => type === "noteReference"))) return snapshot;
355
+ if (!snapshot.blocks.some((block) => {
356
+ switch (block.kind) {
357
+ case "diagnostic": return false;
358
+ case "paragraph":
359
+ case "heading":
360
+ case "listItem": return block.structuralBoundaries?.some(({ type }) => type === "noteReference") ?? false;
361
+ default: return panic("Unhandled snapshot block kind", { block });
362
+ }
363
+ })) return snapshot;
351
364
  return createFolioAIEditSnapshotInternal(metadata.sourceDocument, metadata.styleResolver, labels);
352
365
  };
353
366
  const STORY_TABLE_CONTAINER = "container";
@@ -524,7 +537,6 @@ const createFolioAIEditSnapshotInternal = (doc, styleResolver, noteReferenceLabe
524
537
  const displayLabel = getDisplayLabel(node, listLabel, kind === "heading");
525
538
  const styleId = getStyleId(node);
526
539
  const directOutlineLevel = node.type.name === "paragraph" ? expectParagraphAttrs(node)._originalFormatting?.outlineLevel : void 0;
527
- const listLevel = getListLevel(node);
528
540
  const listReference = getListReference(node);
529
541
  const numberingReferenceKey = getNumberingReferenceKey(node);
530
542
  if (numberingReferenceKey) numberingReferenceKeys.add(numberingReferenceKey);
@@ -552,7 +564,7 @@ const createFolioAIEditSnapshotInternal = (doc, styleResolver, noteReferenceLabe
552
564
  ...displayLabel !== void 0 && { displayLabel },
553
565
  ...styleId !== void 0 && { styleId },
554
566
  ...directOutlineLevel !== void 0 && { directOutlineLevel },
555
- ...listLevel !== void 0 && { listLevel },
567
+ statedNumbering: readParagraphNumberingAttr(node.attrs["numPr"]) ?? INHERITED_PARAGRAPH_NUMBERING,
556
568
  ...listReference !== void 0 && { listReference },
557
569
  ...directAlignment !== void 0 && { directAlignment },
558
570
  ...directSpacing !== void 0 && { directSpacing },
@@ -616,12 +628,12 @@ const createFolioAIEditSnapshotWithStyleResolver = (doc, styleResolver) => creat
616
628
  /**
617
629
  * What a reader sees the block as, heading first: a numbered heading (`1.
618
630
  * Scope`, numbered through its style or its own `w:numPr`) is a heading that
619
- * shows a number, with the number in `displayLabel` and its level in
620
- * `listLevel`. A paragraph is a list item when it shows a marker, which is
631
+ * shows a number, with the number in `displayLabel` and its effective level in
632
+ * `listReference`. A paragraph is a list item when it shows a marker, which is
621
633
  * when it has a label. One whose numbering shows none (a `w:vanish` level, a
622
634
  * level its list does not define, or `w:numId="0"` cancelling its style's
623
- * numbering) reads as prose and is a paragraph, keeping its `listLevel` and
624
- * `listReference`.
635
+ * numbering) reads as prose and is a paragraph, keeping its `statedNumbering` and
636
+ * effective `listReference`.
625
637
  */
626
638
  const getBlockKind = (headingLevel, listLabel) => {
627
639
  if (headingLevel !== void 0) return "heading";
@@ -641,35 +653,22 @@ const getDisplayLabel = (node, listLabel, isHeading) => {
641
653
  const styleId = node.attrs["styleId"];
642
654
  if (isHeading && typeof styleId === "string") return styleId;
643
655
  };
644
- /**
645
- * The level the paragraph's `<w:numPr>` states, and only that. An absent
646
- * `w:ilvl` renders as level zero but is not a stated zero, and a caller that
647
- * writes it back would turn an untouched paragraph into one stating a level
648
- * its source never did.
649
- */
650
- const getListLevel = (node) => {
651
- const numPr = readParagraphNumberingAttr(node.attrs["numPr"]);
652
- return numPr === null || numPr.kind === "none" ? void 0 : numPr.ilvl;
653
- };
654
- /**
655
- * The numbering a paragraph attr states, read through the model's own reader.
656
- *
657
- * The two functions below used to test the reserved id relationally
658
- * (`numId > 0`, `numId <= 0`), which is the one spelling that disagreed with
659
- * the other four: a malformed package's negative id is a dangling reference
660
- * everywhere else and "not numbered" here.
661
- */
662
- const statedNumbering = (node) => resolveParagraphNumbering(readParagraphNumberingAttr(node.attrs["numPr"]) ?? void 0);
663
656
  const getListReference = (node) => {
664
- const numbering = statedNumbering(node);
665
- return numbering.kind === "reference" ? {
657
+ const numbering = effectiveParagraphNumberingReference(paragraphNumberingSourcesFromBoundary({
658
+ numPr: readParagraphNumberingAttr(node.attrs["numPr"]),
659
+ numPrFromStyle: readParagraphNumberingAttr(node.attrs["numPrFromStyle"])
660
+ }));
661
+ return numbering ? {
666
662
  numId: numbering.numId,
667
663
  level: numbering.ilvl
668
664
  } : void 0;
669
665
  };
670
666
  const getNumberingReferenceKey = (node) => {
671
- const numbering = statedNumbering(node);
672
- return numbering.kind === "reference" ? `${String(numbering.numId)}:${String(numbering.ilvl)}` : null;
667
+ const numbering = effectiveParagraphNumberingReference(paragraphNumberingSourcesFromBoundary({
668
+ numPr: readParagraphNumberingAttr(node.attrs["numPr"]),
669
+ numPrFromStyle: readParagraphNumberingAttr(node.attrs["numPrFromStyle"])
670
+ }));
671
+ return numbering ? `${String(numbering.numId)}:${String(numbering.ilvl)}` : null;
673
672
  };
674
673
  const getStyleId = (node) => {
675
674
  const styleId = node.attrs["styleId"];