@stll/folio-core 0.66.1 → 0.66.2

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 (80) hide show
  1. package/dist/ai-edits/apply.d.ts +13 -1
  2. package/dist/ai-edits/apply.js +533 -136
  3. package/dist/ai-edits/batch-claims.d.ts +26 -0
  4. package/dist/ai-edits/batch-claims.js +30 -5
  5. package/dist/ai-edits/headless.d.ts +6 -0
  6. package/dist/ai-edits/headless.js +25 -3
  7. package/dist/ai-edits/newListNumbering.d.ts +4 -1
  8. package/dist/ai-edits/newListNumbering.js +4 -2
  9. package/dist/ai-edits/types.d.ts +1 -1
  10. package/dist/document-operations.d.ts +13 -1
  11. package/dist/document-operations.js +11 -4
  12. package/dist/docx/listNumberingInstances.d.ts +6 -4
  13. package/dist/docx/listNumberingInstances.js +12 -11
  14. package/dist/docx/numberingIds.d.ts +10 -0
  15. package/dist/docx/numberingIds.js +5 -1
  16. package/dist/docx/paragraphParser.js +16 -3
  17. package/dist/docx/paragraphProperties.js +2 -1
  18. package/dist/docx/serializer/paragraphSerializer.js +86 -66
  19. package/dist/i18n/messages/ar.gen.js +1 -0
  20. package/dist/i18n/messages/catalogs.gen.d.ts +17 -0
  21. package/dist/i18n/messages/catalogs.gen.js +17 -0
  22. package/dist/i18n/messages/cs.gen.js +1 -0
  23. package/dist/i18n/messages/de.gen.js +1 -0
  24. package/dist/i18n/messages/en.gen.js +1 -0
  25. package/dist/i18n/messages/es.gen.js +1 -0
  26. package/dist/i18n/messages/et.gen.js +1 -0
  27. package/dist/i18n/messages/fr.gen.js +1 -0
  28. package/dist/i18n/messages/he.gen.js +1 -0
  29. package/dist/i18n/messages/hi.gen.js +1 -0
  30. package/dist/i18n/messages/hu.gen.js +1 -0
  31. package/dist/i18n/messages/lt.gen.js +1 -0
  32. package/dist/i18n/messages/lv.gen.js +1 -0
  33. package/dist/i18n/messages/messages.gen.d.ts +1 -0
  34. package/dist/i18n/messages/pl.gen.js +1 -0
  35. package/dist/i18n/messages/pt-BR.gen.js +1 -0
  36. package/dist/i18n/messages/sk.gen.js +1 -0
  37. package/dist/i18n/messages/tr.gen.js +1 -0
  38. package/dist/i18n/messages/zh-CN.gen.js +1 -0
  39. package/dist/internal/wholeStoryRevisionResolution.d.ts +1 -1
  40. package/dist/internal/wholeStoryRevisionResolution.js +24 -9
  41. package/dist/layout-bridge/convert/runMarkFormatting.js +1 -0
  42. package/dist/markdown/renderRuns.js +68 -12
  43. package/dist/prosemirror/commands/comments.js +2 -0
  44. package/dist/prosemirror/commands/resolveParagraphProperties.js +15 -2
  45. package/dist/prosemirror/conversion/fromProseDoc.js +55 -18
  46. package/dist/prosemirror/conversion/hyphenTextCarriers.d.ts +23 -1
  47. package/dist/prosemirror/conversion/hyphenTextCarriers.js +46 -1
  48. package/dist/prosemirror/conversion/toProseDoc.js +15 -9
  49. package/dist/prosemirror/extensions/StarterKit.js +1 -1
  50. package/dist/prosemirror/extensions/features/pasteCleanup.js +6 -0
  51. package/dist/prosemirror/extensions/features/pastedHtmlLists.js +2 -1
  52. package/dist/prosemirror/extensions/markRegistry.d.ts +3 -1
  53. package/dist/prosemirror/extensions/markRegistry.js +3 -0
  54. package/dist/prosemirror/extensions/marks/HyphenElementExtension.d.ts +6 -0
  55. package/dist/prosemirror/extensions/marks/HyphenElementExtension.js +54 -0
  56. package/dist/prosemirror/fieldRepresentation.js +2 -1
  57. package/dist/prosemirror/hyphenElementAttrs.d.ts +10 -0
  58. package/dist/prosemirror/hyphenElementAttrs.js +32 -0
  59. package/dist/prosemirror/keptRangeBoundaries.d.ts +2 -0
  60. package/dist/prosemirror/keptRangeBoundaries.js +1 -1
  61. package/dist/prosemirror/listNumbering.js +3 -2
  62. package/dist/prosemirror/paragraphIndentation.js +2 -1
  63. package/dist/prosemirror/paragraphPropertyCarry.d.ts +1 -14
  64. package/dist/prosemirror/paragraphPropertyCarry.js +4 -28
  65. package/dist/prosemirror/plugins/suggestionMode.js +19 -6
  66. package/dist/prosemirror/replacedAnnotations.d.ts +1 -0
  67. package/dist/prosemirror/replacedAnnotations.js +1 -0
  68. package/dist/prosemirror/sectionCarrier.d.ts +8 -0
  69. package/dist/prosemirror/sectionCarrier.js +29 -1
  70. package/dist/prosemirror/styles/paragraphStyleCascade.d.ts +10 -0
  71. package/dist/prosemirror/styles/paragraphStyleCascade.js +12 -2
  72. package/dist/prosemirror/tableRunIn.d.ts +24 -9
  73. package/dist/prosemirror/tableRunIn.js +107 -21
  74. package/dist/prosemirror/textInput.js +3 -1
  75. package/dist/prosemirror/validation.js +6 -0
  76. package/dist/utils/createDocument.js +11 -8
  77. package/dist/utils/formatToStyle.js +2 -2
  78. package/dist/utils/units.d.ts +5 -0
  79. package/dist/utils/units.js +6 -1
  80. package/package.json +3 -3
@@ -26,6 +26,12 @@ type PositionRange = {
26
26
  from: number;
27
27
  to: number;
28
28
  };
29
+ /** A paragraph before a deleted one that ends its container; see `paragraphsBefore`. */
30
+ type ParagraphBefore = {
31
+ block: number;
32
+ /** Its break is not already pending deletion. */
33
+ keepsBreak: boolean;
34
+ };
29
35
  /** The text an operation rewrites (`text`), only marks (`annotation`), or breaks (`split`). */
30
36
  type InlineClaim = {
31
37
  type: "text" | "annotation" | "split";
@@ -55,6 +61,17 @@ export type BatchClaim = InlineClaim |
55
61
  * any other does — see `followedByInsertion`.
56
62
  */
57
63
  keepsParagraph: boolean;
64
+ /** The paragraph ends its container, before anything the batch adds. */
65
+ endsContainer: boolean;
66
+ /**
67
+ * Tracked, the paragraphs before one that ends its container, nearest
68
+ * first, up to the container's start or a block that is not one. The
69
+ * nearest the batch keeps, when its break stays, is the one whose break
70
+ * the deletion retires: accepting runs it into this paragraph with its
71
+ * own properties, as applied directly this one goes. Empty applied
72
+ * directly, and for a paragraph that ends nothing.
73
+ */
74
+ paragraphsBefore: readonly ParagraphBefore[];
58
75
  } |
59
76
  /**
60
77
  * Joins `block` with the block starting at `next`, where `block` ends.
@@ -128,6 +145,15 @@ export declare class BatchClaims {
128
145
  private readonly columnInsertions;
129
146
  /** Accepted deletions that keep their paragraph, by where the paragraph starts and ends. */
130
147
  private readonly keptParagraphs;
148
+ /**
149
+ * Whether a tracked deletion of a paragraph that ends its container retires
150
+ * the break of the paragraph before, given the claims accepted so far: the
151
+ * nearest paragraph before it the batch does not delete keeps its break,
152
+ * and no merge of the batch deletes that break first.
153
+ */
154
+ private retiresBreakBefore;
155
+ /** `role` with what it takes from the batch's other claims settled. */
156
+ private settled;
131
157
  /** `claim`'s roles, given the insertions accepted so far. */
132
158
  private rolesOf;
133
159
  /**
@@ -43,7 +43,10 @@ const blockRolesOf = (claim) => {
43
43
  block: claim.block,
44
44
  role: {
45
45
  kind: "deleteBlock",
46
- keepsParagraph: claim.keepsParagraph
46
+ keepsParagraph: claim.keepsParagraph,
47
+ endsContainer: claim.endsContainer,
48
+ paragraphsBefore: claim.paragraphsBefore,
49
+ retiresBreakBefore: false
47
50
  }
48
51
  }];
49
52
  case "merge": return [{
@@ -105,7 +108,7 @@ const rolesConflict = (left, right) => {
105
108
  if (ROLE_RANK[right.kind] > ROLE_RANK[left.kind]) return rolesConflict(right, left);
106
109
  switch (left.kind) {
107
110
  case "deleteBlock": switch (right.kind) {
108
- case "paragraphProperties": return !left.keepsParagraph;
111
+ case "paragraphProperties": return left.endsContainer && (!left.keepsParagraph || left.retiresBreakBefore);
109
112
  case "mergeNext": return false;
110
113
  default: return true;
111
114
  }
@@ -122,7 +125,7 @@ const rolesConflict = (left, right) => {
122
125
  case "mergeNext": return false;
123
126
  default: return true;
124
127
  }
125
- case "mergeNext": return right.kind === "paragraphProperties" && (left.joinsNow || left.setsProperties);
128
+ case "mergeNext": return right.kind === "paragraphProperties" && left.setsProperties;
126
129
  case "paragraphProperties": return right.kind === "split" || right.kind === "paragraphProperties";
127
130
  case "split":
128
131
  case "text":
@@ -155,6 +158,27 @@ var BatchClaims = class {
155
158
  columnInsertions = /* @__PURE__ */ new Map();
156
159
  /** Accepted deletions that keep their paragraph, by where the paragraph starts and ends. */
157
160
  keptParagraphs = /* @__PURE__ */ new Map();
161
+ /**
162
+ * Whether a tracked deletion of a paragraph that ends its container retires
163
+ * the break of the paragraph before, given the claims accepted so far: the
164
+ * nearest paragraph before it the batch does not delete keeps its break,
165
+ * and no merge of the batch deletes that break first.
166
+ */
167
+ retiresBreakBefore(role) {
168
+ for (const { block, keepsBreak } of role.paragraphsBefore) {
169
+ const entries = this.blocks.get(block) ?? [];
170
+ if (entries.some((entry) => entry.role.kind === "deleteBlock")) continue;
171
+ return keepsBreak && !entries.some((entry) => entry.role.kind === "mergeOwn");
172
+ }
173
+ return false;
174
+ }
175
+ /** `role` with what it takes from the batch's other claims settled. */
176
+ settled(role) {
177
+ return role.kind === "deleteBlock" ? {
178
+ ...role,
179
+ retiresBreakBefore: this.retiresBreakBefore(role)
180
+ } : role;
181
+ }
158
182
  /** `claim`'s roles, given the insertions accepted so far. */
159
183
  rolesOf(claim) {
160
184
  return blockRolesOf(claim).map(({ block, role }) => role.kind === "deleteBlock" && role.keepsParagraph && claim.type === "deleteBlock" && (this.insertions.has(claim.end) || this.insertions.has(claim.block)) ? {
@@ -184,8 +208,9 @@ var BatchClaims = class {
184
208
  * conflicts with none.
185
209
  */
186
210
  conflictOf(claim) {
187
- for (const { block, role } of this.rolesOf(claim)) {
188
- for (const entry of this.blocks.get(block) ?? []) if (rolesConflict(entry.role, role)) return entry.operationId;
211
+ for (const { block, role: claimed } of this.rolesOf(claim)) {
212
+ const role = this.settled(claimed);
213
+ for (const entry of this.blocks.get(block) ?? []) if (rolesConflict(this.settled(entry.role), role)) return entry.operationId;
189
214
  const fold = this.foldAt(block);
190
215
  if (fold !== null) return fold;
191
216
  if (role.kind === "deleteBlock") continue;
@@ -383,6 +383,12 @@ export declare class FolioDocxReviewer {
383
383
  * the anchor map the apply layer resolves operations against.
384
384
  */
385
385
  snapshot(): FolioAIEditSnapshot;
386
+ /**
387
+ * The numbering ids every story but `story` defines: the package's and the
388
+ * lists each story started. Numbering ids are package-wide, while a story's
389
+ * state completes its numbering from its own paragraphs only.
390
+ */
391
+ private numberingIdsOutside;
386
392
  /** Every suggestion id the document's stories still carry. */
387
393
  private activeSuggestionIds;
388
394
  /** Export staged AI operations for storage by the host, outside the DOCX. */
@@ -2,7 +2,7 @@ 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
4
  import { importReferencedStyleDefinitions, styleClosureNumberingReferences } from "../compare/style-resources.js";
5
- import { applyFolioDocumentOperations } from "../document-operations.js";
5
+ import { applyFolioDocumentOperationsInPackage } from "../document-operations.js";
6
6
  import { removeCommentMarkers } from "../docx/commentAnchorIndex.js";
7
7
  import { applyReplyThreadMarkers } from "../docx/commentReplyMarkers.js";
8
8
  import { commentTextParagraph } from "../docx/commentTextParagraph.js";
@@ -620,6 +620,26 @@ var FolioDocxReviewer = class FolioDocxReviewer {
620
620
  snapshot() {
621
621
  return createStateSnapshot(this.state);
622
622
  }
623
+ /**
624
+ * The numbering ids every story but `story` defines: the package's and the
625
+ * lists each story started. Numbering ids are package-wide, while a story's
626
+ * state completes its numbering from its own paragraphs only.
627
+ */
628
+ numberingIdsOutside(story) {
629
+ const key = editableStoryKey(story);
630
+ const states = [...story.type === "main" ? [] : [this.state], ...[...this.secondaryStoryStates.values()].filter(({ handle }) => editableStoryKey(handle) !== key).map(({ state }) => state)];
631
+ const numIds = /* @__PURE__ */ new Set();
632
+ const abstractNumIds = /* @__PURE__ */ new Set();
633
+ for (const state of states) {
634
+ const definitions = getDocumentNumbering(state)?.definitions;
635
+ for (const { numId } of definitions?.nums ?? []) numIds.add(numId);
636
+ for (const { abstractNumId } of definitions?.abstractNums ?? []) abstractNumIds.add(abstractNumId);
637
+ }
638
+ return {
639
+ numIds,
640
+ abstractNumIds
641
+ };
642
+ }
623
643
  /** Every suggestion id the document's stories still carry. */
624
644
  activeSuggestionIds() {
625
645
  const active = new Set(getSuggestions(this.state).map(({ suggestionId }) => suggestionId));
@@ -904,7 +924,7 @@ var FolioDocxReviewer = class FolioDocxReviewer {
904
924
  view.state = view.state.apply(transaction);
905
925
  }
906
926
  };
907
- const result = applyFolioDocumentOperations({
927
+ const result = applyFolioDocumentOperationsInPackage({
908
928
  view,
909
929
  snapshot: sourceSnapshot,
910
930
  batch,
@@ -915,6 +935,7 @@ var FolioDocxReviewer = class FolioDocxReviewer {
915
935
  ...tableTemplates !== void 0 && { tableTemplates },
916
936
  ...replacementBackground !== void 0 && { replacementBackground },
917
937
  undefinedReferences,
938
+ numberingIdsElsewhere: this.numberingIdsOutside(story),
918
939
  ...restagesSuggestions === true ? { restagesSuggestions } : { pendingSuggestionIds: this.activeSuggestionIds() },
919
940
  createCommentId: (text) => {
920
941
  const comment = createReviewerComment({
@@ -1577,9 +1598,10 @@ var FolioDocxReviewer = class FolioDocxReviewer {
1577
1598
  view.state = view.state.apply(transaction);
1578
1599
  }
1579
1600
  };
1580
- const applied = applyFolioDocumentOperations({
1601
+ const applied = applyFolioDocumentOperationsInPackage({
1581
1602
  undefinedReferences: "refuse",
1582
1603
  restagesSuggestions: true,
1604
+ numberingIdsElsewhere: this.numberingIdsOutside(story),
1583
1605
  view,
1584
1606
  snapshot,
1585
1607
  batch: {
@@ -1,3 +1,4 @@
1
+ import { NumberingIdsInUse } from "../docx/numberingIds.js";
1
2
  import { FolioContentStatedNumbering } from "../compare/content-types.js";
2
3
  import { ListKind } from "../docx/listNumberingInstances.js";
3
4
  import { FolioAIEditOperation, FolioAIListNumbering, FolioAINewListReference, FolioAIResolvedEditOperation } from "./types.js";
@@ -23,6 +24,8 @@ export declare const stageNewListOperations: (operations: readonly FolioAIEditOp
23
24
  * Replace every new-list request with a reference to an instance minted for
24
25
  * its operation: one instance per operation and kind. `numbering` is the map
25
26
  * the batch applies against; the result's map adds the minted instances.
27
+ * `elsewhere` holds the ids the package's other stories define, which no
28
+ * minted instance takes.
26
29
  */
27
- export declare const resolveNewListOperations: (operations: readonly FolioAIStagedEditOperation[], numbering: NumberingMap | null) => ResolvedNewLists;
30
+ export declare const resolveNewListOperations: (operations: readonly FolioAIStagedEditOperation[], numbering: NumberingMap | null, elsewhere: NumberingIdsInUse) => ResolvedNewLists;
28
31
  export {};
@@ -82,8 +82,10 @@ const stageNewListOperations = (operations) => deferNewListRequests(operations);
82
82
  * Replace every new-list request with a reference to an instance minted for
83
83
  * its operation: one instance per operation and kind. `numbering` is the map
84
84
  * the batch applies against; the result's map adds the minted instances.
85
+ * `elsewhere` holds the ids the package's other stories define, which no
86
+ * minted instance takes.
85
87
  */
86
- const resolveNewListOperations = (operations, numbering) => {
88
+ const resolveNewListOperations = (operations, numbering, elsewhere) => {
87
89
  let definitions = numbering?.definitions;
88
90
  let minted = false;
89
91
  return {
@@ -94,7 +96,7 @@ const resolveNewListOperations = (operations, numbering) => {
94
96
  if (value.kind !== "deferredNewList") return value;
95
97
  let numId = instances.get(value.allocation);
96
98
  if (numId === void 0) {
97
- const instance = mintListInstance(definitions, { kind: value.allocation.format });
99
+ const instance = mintListInstance(definitions, { kind: value.allocation.format }, elsewhere);
98
100
  definitions = instance.definitions;
99
101
  minted = true;
100
102
  numId = instance.numId;
@@ -654,7 +654,7 @@ export type FolioAIEditSkipReason = "missingBlock" | "changedBlock" | "ambiguous
654
654
  * next to it.
655
655
  */
656
656
  "pendingDeletion" |
657
- /** Resolve the removed paragraph mark before editing its properties separately. */
657
+ /** Resolve the removed paragraph mark before editing its properties separately, or before inserting a paragraph between it and a table. */
658
658
  "pendingParagraphMarkDeletion";
659
659
  export type FolioAIEditAppliedOperation = {
660
660
  id: string;
@@ -1,3 +1,4 @@
1
+ import { NumberingIdsInUse } from "./docx/numberingIds.js";
1
2
  import { document_d_exports } from "./types/document.js";
2
3
  import { FolioTableTemplates } from "./ai-edits/table-template.js";
3
4
  import { FolioAIEditAppliedOperation, FolioAIEditApplyMode, FolioAIEditNormalization, FolioAIEditOperation, FolioAIEditPrecondition, FolioAIEditSkippedOperation, FolioAIEditSnapshot, FolioAITextRangeHandle } from "./ai-edits/types.js";
@@ -313,5 +314,16 @@ export type ApplyFolioDocumentOperationsOptions = {
313
314
  */
314
315
  restagesSuggestions?: boolean;
315
316
  };
316
- export declare const applyFolioDocumentOperations: ({ view, snapshot, batch, story, author, createCommentId, createUndoHandle, revisionStamp, wordDiff, tableTemplates, replacementBackground, undefinedReferences, pendingSuggestionIds, restagesSuggestions }: ApplyFolioDocumentOperationsOptions) => FolioDocumentOperationResult;
317
+ export declare const applyFolioDocumentOperations: (input: ApplyFolioDocumentOperationsOptions) => FolioDocumentOperationResult;
318
+ /**
319
+ * Options of a caller that holds every story of the package: the numbering
320
+ * ids (`w:num`, `w:abstractNum`) the other stories define. A list the batch
321
+ * starts takes none of them, so its id names it in every story and survives a
322
+ * save.
323
+ */
324
+ type ApplyFolioDocumentOperationsInPackageOptions = ApplyFolioDocumentOperationsOptions & {
325
+ numberingIdsElsewhere: NumberingIdsInUse;
326
+ };
327
+ /** {@link applyFolioDocumentOperations} for a caller holding every story. Internal. */
328
+ export declare const applyFolioDocumentOperationsInPackage: ({ view, snapshot, batch, story, author, createCommentId, createUndoHandle, revisionStamp, wordDiff, tableTemplates, replacementBackground, undefinedReferences, pendingSuggestionIds, numberingIdsElsewhere, restagesSuggestions }: ApplyFolioDocumentOperationsInPackageOptions) => FolioDocumentOperationResult;
317
329
  export {};
@@ -1,6 +1,7 @@
1
- import { applyFolioAIEditOperations, previewFolioAIEditOperationsWithResult } from "./ai-edits/apply.js";
1
+ import { applyFolioAIEditOperationsInPackage, previewFolioAIEditOperationsWithResult } from "./ai-edits/apply.js";
2
2
  import { describeModelError, findIntroducedModelErrors } from "./ai-edits/result-validation.js";
3
3
  import { LIST_KINDS } from "./docx/listNumberingInstances.js";
4
+ import { NO_NUMBERING_IDS_IN_USE } from "./docx/numberingIds.js";
4
5
  import { getSuggestions } from "./prosemirror/commands/comments.js";
5
6
  import { completeNumberingForDoc } from "./prosemirror/listInstanceReferences.js";
6
7
  import { outlineLevelFromAttrValue } from "./prosemirror/outlineLevelAttr.js";
@@ -1290,7 +1291,12 @@ const inOperationOrder = (operations, skipped) => {
1290
1291
  const indexById = new Map(operations.map(({ id }, index) => [id, index]));
1291
1292
  return [...skipped].sort((left, right) => (indexById.get(left.id) ?? -1) - (indexById.get(right.id) ?? -1));
1292
1293
  };
1293
- const applyFolioDocumentOperations = ({ view, snapshot, batch, story = "main", author, createCommentId, createUndoHandle, revisionStamp, wordDiff, tableTemplates, replacementBackground, undefinedReferences, pendingSuggestionIds, restagesSuggestions }) => {
1294
+ const applyFolioDocumentOperations = (input) => applyFolioDocumentOperationsInPackage({
1295
+ ...input,
1296
+ numberingIdsElsewhere: NO_NUMBERING_IDS_IN_USE
1297
+ });
1298
+ /** {@link applyFolioDocumentOperations} for a caller holding every story. Internal. */
1299
+ const applyFolioDocumentOperationsInPackage = ({ view, snapshot, batch, story = "main", author, createCommentId, createUndoHandle, revisionStamp, wordDiff, tableTemplates, replacementBackground, undefinedReferences, pendingSuggestionIds, numberingIdsElsewhere, restagesSuggestions }) => {
1294
1300
  const validatedBatch = parseFolioDocumentOperationBatch(batch);
1295
1301
  const parsedBatch = restagesSuggestions === true ? validatedBatch : withDistinctSuggestionIds(validatedBatch, /* @__PURE__ */ new Set([...getSuggestions(view.state).map(({ suggestionId }) => suggestionId), ...pendingSuggestionIds ?? []]));
1296
1302
  const isAtomic = parsedBatch.atomic === true;
@@ -1306,6 +1312,7 @@ const applyFolioDocumentOperations = ({ view, snapshot, batch, story = "main", a
1306
1312
  ...wordDiff !== void 0 && { wordDiff },
1307
1313
  ...tableTemplates !== void 0 && { tableTemplates },
1308
1314
  ...replacementBackground !== void 0 && { replacementBackground },
1315
+ numberingIdsElsewhere,
1309
1316
  undefinedReferences
1310
1317
  };
1311
1318
  if (preview) return {
@@ -1319,7 +1326,7 @@ const applyFolioDocumentOperations = ({ view, snapshot, batch, story = "main", a
1319
1326
  const held = {};
1320
1327
  const commentIds = [];
1321
1328
  return {
1322
- outcome: applyFolioAIEditOperations({
1329
+ outcome: applyFolioAIEditOperationsInPackage({
1323
1330
  ...common,
1324
1331
  view: {
1325
1332
  state: view.state,
@@ -1510,4 +1517,4 @@ const applyFolioDocumentOperations = ({ view, snapshot, batch, story = "main", a
1510
1517
  undoHandle: result.applied.length > 0 && createUndoHandle !== void 0 ? createUndoHandle() : null
1511
1518
  };
1512
1519
  };
1513
- export { FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_BATCH_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_KEYS_BY_TYPE, 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_PAGE_BREAK_CLEAR_VALUES, FOLIO_PARAGRAPH_ALIGNMENT_VALUES, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioDocumentOperationReceiptsForStory, isFolioDocumentOperationModeSupported, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch };
1520
+ export { FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_BATCH_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_KEYS_BY_TYPE, 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_PAGE_BREAK_CLEAR_VALUES, FOLIO_PARAGRAPH_ALIGNMENT_VALUES, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, applyFolioDocumentOperations, applyFolioDocumentOperationsInPackage, assertSupportedFolioDocumentOperationVersion, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioDocumentOperationReceiptsForStory, isFolioDocumentOperationModeSupported, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch };
@@ -1,3 +1,4 @@
1
+ import { NumberingIdsInUse } from "./numberingIds.js";
1
2
  import { document_d_exports } from "../types/document.js";
2
3
  /** The two kinds of list a command can create. */
3
4
  export declare const LIST_KINDS: readonly ["bullet", "numbered"];
@@ -23,10 +24,11 @@ type MintedListInstance = {
23
24
  /**
24
25
  * Define a new list: a new `w:abstractNum` of the requested kind and the
25
26
  * `w:num` naming it. `definitions` must already hold every instance the
26
- * document references (see {@link completeListNumbering}), so the new ids
27
- * collide with none of them.
27
+ * story references (see {@link completeListNumbering}), and `elsewhere` the
28
+ * ids the package's other stories define, so the new ids collide with none of
29
+ * them.
28
30
  */
29
- export declare const mintListInstance: (definitions: document_d_exports.NumberingDefinitions | null | undefined, { kind, format, start }: NewListDefinition) => MintedListInstance;
31
+ export declare const mintListInstance: (definitions: document_d_exports.NumberingDefinitions | null | undefined, { kind, format, start }: NewListDefinition, elsewhere: NumberingIdsInUse) => MintedListInstance;
30
32
  type RestartListInstanceOptions = {
31
33
  abstractNumId: number;
32
34
  ilvl: number;
@@ -38,7 +40,7 @@ type RestartListInstanceOptions = {
38
40
  * makes a consumer count the instance on its own rather than continue the
39
41
  * other instances of the same definition.
40
42
  */
41
- export declare const restartListInstance: (definitions: document_d_exports.NumberingDefinitions | null | undefined, { abstractNumId, ilvl, start }: RestartListInstanceOptions) => MintedListInstance;
43
+ export declare const restartListInstance: (definitions: document_d_exports.NumberingDefinitions | null | undefined, { abstractNumId, ilvl, start }: RestartListInstanceOptions, elsewhere: NumberingIdsInUse) => MintedListInstance;
42
44
  /** One paragraph's numbering reference and the rendering it resolved to. */
43
45
  export type ListInstanceReference = {
44
46
  numId: number;
@@ -117,25 +117,26 @@ const EMPTY_DEFINITIONS = {
117
117
  nums: []
118
118
  };
119
119
  /** A fresh `w:numId` for `definitions`; zero is reserved for "no numbering". */
120
- const nextNumId = (definitions) => mintNumberingId({
120
+ const nextNumId = (definitions, elsewhere) => mintNumberingId({
121
121
  kind: "num",
122
- existingIds: (definitions?.nums ?? []).map(({ numId }) => numId)
122
+ existingIds: [...(definitions?.nums ?? []).map(({ numId }) => numId), ...elsewhere.numIds]
123
123
  });
124
124
  /** A fresh `w:abstractNumId` for `definitions`. */
125
- const nextAbstractNumId = (definitions) => mintNumberingId({
125
+ const nextAbstractNumId = (definitions, elsewhere) => mintNumberingId({
126
126
  kind: "abstract",
127
- existingIds: (definitions?.abstractNums ?? []).map(({ abstractNumId }) => abstractNumId)
127
+ existingIds: [...(definitions?.abstractNums ?? []).map(({ abstractNumId }) => abstractNumId), ...elsewhere.abstractNumIds]
128
128
  });
129
129
  /**
130
130
  * Define a new list: a new `w:abstractNum` of the requested kind and the
131
131
  * `w:num` naming it. `definitions` must already hold every instance the
132
- * document references (see {@link completeListNumbering}), so the new ids
133
- * collide with none of them.
132
+ * story references (see {@link completeListNumbering}), and `elsewhere` the
133
+ * ids the package's other stories define, so the new ids collide with none of
134
+ * them.
134
135
  */
135
- const mintListInstance = (definitions, { kind, format, start }) => {
136
+ const mintListInstance = (definitions, { kind, format, start }, elsewhere) => {
136
137
  const current = definitions ?? EMPTY_DEFINITIONS;
137
- const numId = nextNumId(current);
138
- const abstractNumId = nextAbstractNumId(current);
138
+ const numId = nextNumId(current, elsewhere);
139
+ const abstractNumId = nextAbstractNumId(current, elsewhere);
139
140
  const levelOverrides = levelZeroStart(start);
140
141
  const instance = {
141
142
  numId,
@@ -161,9 +162,9 @@ const mintListInstance = (definitions, { kind, format, start }) => {
161
162
  * makes a consumer count the instance on its own rather than continue the
162
163
  * other instances of the same definition.
163
164
  */
164
- const restartListInstance = (definitions, { abstractNumId, ilvl, start }) => {
165
+ const restartListInstance = (definitions, { abstractNumId, ilvl, start }, elsewhere) => {
165
166
  const current = definitions ?? EMPTY_DEFINITIONS;
166
- const numId = nextNumId(current);
167
+ const numId = nextNumId(current, elsewhere);
167
168
  const instance = {
168
169
  numId,
169
170
  abstractNumId,
@@ -1,4 +1,14 @@
1
1
  type NumberingKind = "num" | "abstract";
2
+ /**
3
+ * Numbering ids (`w:num`, `w:abstractNum`) defined outside the numbering a
4
+ * caller allocates against: the lists the package's other stories define. The
5
+ * ids are package-wide, so a list minted in one story takes none of them.
6
+ */
7
+ export type NumberingIdsInUse = {
8
+ numIds: ReadonlySet<number>;
9
+ abstractNumIds: ReadonlySet<number>;
10
+ };
11
+ export declare const NO_NUMBERING_IDS_IN_USE: NumberingIdsInUse;
2
12
  type MintNumberingIdOptions = {
3
13
  kind: NumberingKind;
4
14
  existingIds: Iterable<number>;
@@ -1,5 +1,9 @@
1
1
  import { createNumericIdAllocator } from "./numericIdAllocator.js";
2
2
  // src/docx/numberingIds.ts
3
+ const NO_NUMBERING_IDS_IN_USE = {
4
+ numIds: /* @__PURE__ */ new Set(),
5
+ abstractNumIds: /* @__PURE__ */ new Set()
6
+ };
3
7
  /** Independent offline packages can allocate deterministically without retaining realm state. */
4
8
  const createNumberingIdAllocator = (kind, existingIds) => {
5
9
  const allocator = createNumericIdAllocator({
@@ -12,4 +16,4 @@ const createNumberingIdAllocator = (kind, existingIds) => {
12
16
  const mintNumberingId = ({ kind, existingIds }) => {
13
17
  return createNumberingIdAllocator(kind, existingIds).next();
14
18
  };
15
- export { createNumberingIdAllocator, mintNumberingId };
19
+ export { NO_NUMBERING_IDS_IN_USE, createNumberingIdAllocator, mintNumberingId };
@@ -168,6 +168,19 @@ function paragraphStartsWithRenderedPageBreak(node) {
168
168
  if (outcome === "forced") return sawRenderedPageBreak;
169
169
  return outcome === "visible" && sawRenderedPageBreak;
170
170
  }
171
+ /**
172
+ * How each revision's content is read. A deletion's runs spell their text
173
+ * `w:delText` (ISO/IEC 29500-1 §17.3.3.7), read here as the text it stands
174
+ * for. A move source's runs spell it `w:t` (§17.13.5.22), which that reading
175
+ * leaves as it is; it also accepts the `w:delText` some writers put there, so
176
+ * both spellings give the same model, which the serializer writes as `w:t`.
177
+ */
178
+ const TRACKED_CHANGE_PARSE_CONTEXT = {
179
+ insertion: "default",
180
+ deletion: "deletion",
181
+ moveFrom: "deletion",
182
+ moveTo: "default"
183
+ };
171
184
  function replaceLocalName(name, localName) {
172
185
  if (!name) return `w:${localName}`;
173
186
  const colonIndex = name.indexOf(":");
@@ -405,7 +418,7 @@ const linkedRevisionContent = (wrapped, linkOver) => {
405
418
  return content;
406
419
  };
407
420
  const hoistRevision = (wrapper) => (child, { styles, theme, rels, media, previews, inScopeXmlns, items, linkOver }) => {
408
- const wrapped = parseParagraphContents(child, styles, theme, null, rels, media, previews, wrapper === "deletion" || wrapper === "moveFrom" ? "deletion" : "default", inScopeXmlns, "hyperlink");
421
+ const wrapped = parseParagraphContents(child, styles, theme, null, rels, media, previews, TRACKED_CHANGE_PARSE_CONTEXT[wrapper], inScopeXmlns, "hyperlink");
409
422
  const content = linkedRevisionContent(wrapped, linkOver);
410
423
  items.push({
411
424
  type: "hoistedRevision",
@@ -537,7 +550,7 @@ const fieldInlineWrapper = (element) => (child, context) => {
537
550
  };
538
551
  /** Read a field's revision with the same ownership rules as a paragraph revision. */
539
552
  const fieldTrackedChange = (type) => (child, { push, styles, theme, rels, media, previews, inScopeXmlns }) => {
540
- const parsedContent = parseParagraphContents(child, styles, theme, null, rels, media, previews, type === "deletion" || type === "moveFrom" ? "deletion" : "default", inScopeXmlns);
553
+ const parsedContent = parseParagraphContents(child, styles, theme, null, rels, media, previews, TRACKED_CHANGE_PARSE_CONTEXT[type], inScopeXmlns);
541
554
  if (parsedContent.length === 0 || !parsedContent.every(isTrackedChangeWrapperChild)) {
542
555
  push(preserveInlineChild(child));
543
556
  return;
@@ -901,7 +914,7 @@ const PARAGRAPH_CONTENT_UNDECLARED_NAMESPACES = { [OMML_NAMESPACE]: (child, { co
901
914
  /** All revision wrappers retain typed review ownership while parsing their children. */
902
915
  const trackedParagraphRevision = (type) => (child, { contents, styles, theme, rels, media, previews, inScopeXmlns, inlineScope }) => {
903
916
  const resolutionJoins = parseResolutionJoins(child);
904
- const parsedContent = parseParagraphContents(child, styles, theme, null, rels, media, previews, type === "deletion" || type === "moveFrom" ? "deletion" : "default", inScopeXmlns, inlineScope);
917
+ const parsedContent = parseParagraphContents(child, styles, theme, null, rels, media, previews, TRACKED_CHANGE_PARSE_CONTEXT[type], inScopeXmlns, inlineScope);
905
918
  pushTrackedChangeSegments({
906
919
  contents,
907
920
  type,
@@ -1,3 +1,4 @@
1
+ import { hangingFirstLineIndent } from "../utils/units.js";
1
2
  import { readAttributeBag } from "./attributeRemainder.js";
2
3
  import { parseBorderSpec } from "./borderParser.js";
3
4
  import { CAPTURE, dispatchChildrenWithContext, ownedElsewhere, sequencePositions } from "./containerChildren.js";
@@ -296,7 +297,7 @@ const readParagraphIndentation = (ind, formatting) => {
296
297
  if (firstLine !== void 0) formatting.indentFirstLine = firstLine;
297
298
  const hanging = parseNumericAttribute(ind, "w", "hanging");
298
299
  if (hanging !== void 0) {
299
- formatting.indentFirstLine = -hanging;
300
+ formatting.indentFirstLine = hangingFirstLineIndent(hanging);
300
301
  formatting.hangingIndent = true;
301
302
  }
302
303
  if (!(left !== void 0 || right !== void 0 || firstLine !== void 0 || hanging !== void 0)) return false;