@stll/folio-core 0.39.1 → 0.41.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 (64) hide show
  1. package/dist/ai-edits/apply.js +6 -4
  2. package/dist/ai-edits/clean-text.d.ts +28 -6
  3. package/dist/ai-edits/clean-text.js +28 -13
  4. package/dist/ai-edits/headless.d.ts +12 -0
  5. package/dist/ai-edits/headless.js +26 -3
  6. package/dist/ai-edits/index.d.ts +2 -2
  7. package/dist/ai-edits/snapshot.d.ts +6 -1
  8. package/dist/ai-edits/snapshot.js +15 -10
  9. package/dist/ai-edits/types.d.ts +19 -6
  10. package/dist/ai-suggestions/text-positions.js +15 -3
  11. package/dist/compare/inline-atoms.js +2 -2
  12. package/dist/compat/eigenpal.d.ts +3 -2
  13. package/dist/compat/eigenpal.js +2 -1
  14. package/dist/display-list/primitives.d.ts +2 -1
  15. package/dist/document-operations.d.ts +24 -23
  16. package/dist/document-operations.js +163 -127
  17. package/dist/docx/blockPlainText.d.ts +8 -0
  18. package/dist/docx/blockPlainText.js +40 -0
  19. package/dist/docx/commentRangeIntegrity.js +0 -1
  20. package/dist/docx/compatibility.d.ts +16 -2
  21. package/dist/docx/compatibility.js +30 -9
  22. package/dist/docx/footnoteParser.js +4 -23
  23. package/dist/docx/graphicFrameLocks.d.ts +22 -0
  24. package/dist/docx/graphicFrameLocks.js +55 -0
  25. package/dist/docx/groupDrawingParser.d.ts +7 -1
  26. package/dist/docx/groupDrawingParser.js +11 -2
  27. package/dist/docx/headerFooterParser.d.ts +5 -1
  28. package/dist/docx/headerFooterParser.js +7 -21
  29. package/dist/docx/headerFooterVerbatim.d.ts +1 -12
  30. package/dist/docx/imageParser.js +5 -0
  31. package/dist/docx/imageRawXml.d.ts +33 -1
  32. package/dist/docx/imageRawXml.js +56 -1
  33. package/dist/docx/numberingParser.d.ts +1 -3
  34. package/dist/docx/runParser.js +43 -21
  35. package/dist/docx/serializer/runSerializer.js +4 -2
  36. package/dist/docx/server/createBilingualDocument.js +31 -5
  37. package/dist/docx/settingsParser.d.ts +2 -6
  38. package/dist/docx/shapeParser.js +32 -6
  39. package/dist/docx/vmlImageParser.d.ts +11 -1
  40. package/dist/docx/vmlImageParser.js +29 -2
  41. package/dist/headless-layout.js +1 -7
  42. package/dist/index.d.ts +3 -2
  43. package/dist/index.js +2 -1
  44. package/dist/internal/compare/inline-presentation.d.ts +11 -3
  45. package/dist/internal/compare/inline-presentation.js +8 -1
  46. package/dist/prosemirror/attrs/index.js +33 -3
  47. package/dist/prosemirror/conversion/fromProseDoc.d.ts +13 -2
  48. package/dist/prosemirror/conversion/fromProseDoc.js +85 -46
  49. package/dist/prosemirror/conversion/index.d.ts +2 -2
  50. package/dist/prosemirror/conversion/toProseDoc.js +12 -21
  51. package/dist/prosemirror/extensions/features/ListExtension.js +2 -1
  52. package/dist/prosemirror/extensions/nodes/ImageExtension.js +6 -0
  53. package/dist/prosemirror/imageCommit.js +7 -3
  54. package/dist/prosemirror/listMarker.d.ts +1 -1
  55. package/dist/prosemirror/listMarker.js +1 -18
  56. package/dist/prosemirror/listRenderingAttrs.d.ts +42 -0
  57. package/dist/prosemirror/listRenderingAttrs.js +80 -0
  58. package/dist/prosemirror/runFormattingInlineCarriers.d.ts +16 -1
  59. package/dist/prosemirror/runFormattingInlineCarriers.js +20 -1
  60. package/dist/prosemirror/schema/marks.d.ts +1 -1
  61. package/dist/prosemirror/schema/nodes.d.ts +20 -0
  62. package/dist/prosemirror/styles/resolvedStyleAttrs.js +2 -14
  63. package/dist/utils/mergeDocumentContent.js +1 -1
  64. package/package.json +2 -2
@@ -1,12 +1,13 @@
1
+ import { document_d_exports } from "./types/document.js";
1
2
  import { FolioTableTemplates } from "./ai-edits/table-template.js";
2
3
  import { FolioAIEditAppliedOperation, FolioAIEditApplyMode, FolioAIEditNormalization, FolioAIEditOperation, FolioAIEditPrecondition, FolioAIEditSkippedOperation, FolioAIEditSnapshot, FolioAITextRangeHandle } from "./ai-edits/types.js";
3
4
  import { FolioAIEditView, FolioRevisionStamp, FolioWordDiffOptions } from "./ai-edits/apply.js";
4
5
  //#region src/document-operations.d.ts
5
6
  declare const FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION: 1;
6
7
  /** Direct paragraph-alignment values accepted by the operation contract. */
7
- declare const FOLIO_PARAGRAPH_ALIGNMENT_VALUES: readonly ("left" | "center" | "right" | "both" | "distribute" | "mediumKashida" | "highKashida" | "lowKashida" | "thaiDistribute")[];
8
+ declare const FOLIO_PARAGRAPH_ALIGNMENT_VALUES: readonly document_d_exports.ParagraphAlignment[];
8
9
  /** `w:spacing/@w:lineRule` values accepted by the operation contract. */
9
- declare const FOLIO_LINE_SPACING_RULE_VALUES: readonly ("auto" | "exact" | "atLeast")[];
10
+ declare const FOLIO_LINE_SPACING_RULE_VALUES: readonly document_d_exports.LineSpacingRule[];
10
11
  /** `w:br/@w:clear` values accepted on an authored hard page break. */
11
12
  declare const FOLIO_PAGE_BREAK_CLEAR_VALUES: readonly ["none", "left", "right", "all"];
12
13
  declare const FOLIO_DOCUMENT_OPERATION_TYPES: readonly ["replaceInBlock", "replaceRange", "commentOnRange", "formatRange", "insertAfterBlock", "insertBeforeBlock", "replaceBlock", "deleteBlock", "splitBlock", "mergeBlockWithNext", "setBlockParagraphProperties", "insertTable", "deleteTable", "commentOnBlock", "insertSignatureTable", "insertTableRow", "deleteTableRow", "insertTableColumn", "deleteTableColumn", "mergeTableCells", "splitTableCell"];
@@ -95,27 +96,27 @@ type FolioDocumentOperationBatch = {
95
96
  * guessing, and so tool schemas can be derived from the contract.
96
97
  */
97
98
  declare const FOLIO_DOCUMENT_OPERATION_KEYS_BY_TYPE: Readonly<{
98
- readonly replaceInBlock: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId", "find", "replace", "comment"];
99
- readonly replaceRange: readonly ["id", "type", "range", "severity", "area", "precondition", "suggestionId", "replace", "comment"];
100
- readonly commentOnRange: readonly ["id", "type", "range", "severity", "area", "precondition", "comment"];
101
- readonly formatRange: readonly ["id", "type", "range", "severity", "area", "precondition", "suggestionId", "formatting"];
102
- readonly insertAfterBlock: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId", "text", "inheritFormatting", "alignment", "spacing", "indentation", "lineBreakMode", "listLevel", "numbering", "moveId", "pageBreakBefore", "hardPageBreak", "styleId", "comment"];
103
- readonly insertBeforeBlock: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId", "text", "inheritFormatting", "alignment", "spacing", "indentation", "lineBreakMode", "listLevel", "numbering", "moveId", "pageBreakBefore", "hardPageBreak", "styleId", "comment"];
104
- readonly replaceBlock: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId", "text", "preserveFormatting", "styleId", "comment"];
105
- readonly deleteBlock: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId", "moveId", "comment"];
106
- readonly splitBlock: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId", "offset", "separator", "firstParagraphProperties", "secondParagraphProperties"];
107
- readonly mergeBlockWithNext: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId", "separator", "mergedParagraphProperties"];
108
- readonly setBlockParagraphProperties: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId", "properties"];
109
- readonly insertTable: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId", "position", "rows"];
110
- readonly deleteTable: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId"];
111
- readonly commentOnBlock: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId", "quote", "comment"];
112
- readonly insertSignatureTable: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId", "position", "parties", "comment"];
113
- readonly insertTableRow: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId", "position", "cellTexts"];
114
- readonly deleteTableRow: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId"];
115
- readonly insertTableColumn: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId", "position", "cellTexts"];
116
- readonly deleteTableColumn: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId"];
117
- readonly mergeTableCells: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId", "endBlockId", "rowCount"];
118
- readonly splitTableCell: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId"];
99
+ readonly replaceInBlock: readonly string[];
100
+ readonly replaceRange: readonly string[];
101
+ readonly commentOnRange: readonly string[];
102
+ readonly formatRange: readonly string[];
103
+ readonly insertAfterBlock: readonly string[];
104
+ readonly insertBeforeBlock: readonly string[];
105
+ readonly replaceBlock: readonly string[];
106
+ readonly deleteBlock: readonly string[];
107
+ readonly splitBlock: readonly string[];
108
+ readonly mergeBlockWithNext: readonly string[];
109
+ readonly setBlockParagraphProperties: readonly string[];
110
+ readonly insertTable: readonly string[];
111
+ readonly deleteTable: readonly string[];
112
+ readonly commentOnBlock: readonly string[];
113
+ readonly insertSignatureTable: readonly string[];
114
+ readonly insertTableRow: readonly string[];
115
+ readonly deleteTableRow: readonly string[];
116
+ readonly insertTableColumn: readonly string[];
117
+ readonly deleteTableColumn: readonly string[];
118
+ readonly mergeTableCells: readonly string[];
119
+ readonly splitTableCell: readonly string[];
119
120
  }>;
120
121
  declare const parseFolioDocumentOperationBatch: (value: unknown) => FolioDocumentOperationBatch;
121
122
  /**
@@ -448,23 +448,145 @@ const readReviewMeta = (value, path) => {
448
448
  ...area !== void 0 && { area }
449
449
  };
450
450
  };
451
- const COMMON_OPERATION_KEYS = [
452
- "id",
453
- "type",
454
- "blockId",
455
- "severity",
456
- "area",
457
- "precondition",
458
- "suggestionId"
459
- ];
460
- const RANGE_OPERATION_KEYS = [
461
- "id",
462
- "type",
463
- "range",
464
- "severity",
465
- "area",
466
- "precondition"
467
- ];
451
+ const COMMON_OPERATION_KEY_DECISIONS = {
452
+ id: true,
453
+ type: true,
454
+ blockId: true,
455
+ severity: true,
456
+ area: true,
457
+ precondition: true,
458
+ suggestionId: true
459
+ };
460
+ const RANGE_OPERATION_KEY_DECISIONS = {
461
+ id: true,
462
+ type: true,
463
+ range: true,
464
+ severity: true,
465
+ area: true,
466
+ precondition: true
467
+ };
468
+ const OPERATION_KEY_DECISIONS = {
469
+ replaceInBlock: {
470
+ ...COMMON_OPERATION_KEY_DECISIONS,
471
+ find: true,
472
+ replace: true,
473
+ comment: true
474
+ },
475
+ replaceRange: {
476
+ ...RANGE_OPERATION_KEY_DECISIONS,
477
+ suggestionId: true,
478
+ replace: true,
479
+ comment: true
480
+ },
481
+ commentOnRange: {
482
+ ...RANGE_OPERATION_KEY_DECISIONS,
483
+ suggestionId: false,
484
+ comment: true
485
+ },
486
+ formatRange: {
487
+ ...RANGE_OPERATION_KEY_DECISIONS,
488
+ suggestionId: true,
489
+ formatting: true
490
+ },
491
+ insertAfterBlock: {
492
+ ...COMMON_OPERATION_KEY_DECISIONS,
493
+ text: true,
494
+ inheritFormatting: true,
495
+ alignment: true,
496
+ spacing: true,
497
+ indentation: true,
498
+ lineBreakMode: true,
499
+ formattingScope: true,
500
+ listLevel: true,
501
+ numbering: true,
502
+ moveId: true,
503
+ pageBreakBefore: true,
504
+ hardPageBreak: true,
505
+ styleId: true,
506
+ comment: true
507
+ },
508
+ insertBeforeBlock: {
509
+ ...COMMON_OPERATION_KEY_DECISIONS,
510
+ text: true,
511
+ inheritFormatting: true,
512
+ alignment: true,
513
+ spacing: true,
514
+ indentation: true,
515
+ lineBreakMode: true,
516
+ formattingScope: true,
517
+ listLevel: true,
518
+ numbering: true,
519
+ moveId: true,
520
+ pageBreakBefore: true,
521
+ hardPageBreak: true,
522
+ styleId: true,
523
+ comment: true
524
+ },
525
+ replaceBlock: {
526
+ ...COMMON_OPERATION_KEY_DECISIONS,
527
+ text: true,
528
+ preserveFormatting: true,
529
+ styleId: true,
530
+ comment: true
531
+ },
532
+ deleteBlock: {
533
+ ...COMMON_OPERATION_KEY_DECISIONS,
534
+ moveId: true,
535
+ comment: true
536
+ },
537
+ splitBlock: {
538
+ ...COMMON_OPERATION_KEY_DECISIONS,
539
+ offset: true,
540
+ separator: true,
541
+ firstParagraphProperties: true,
542
+ secondParagraphProperties: true
543
+ },
544
+ mergeBlockWithNext: {
545
+ ...COMMON_OPERATION_KEY_DECISIONS,
546
+ separator: true,
547
+ mergedParagraphProperties: true
548
+ },
549
+ setBlockParagraphProperties: {
550
+ ...COMMON_OPERATION_KEY_DECISIONS,
551
+ properties: true
552
+ },
553
+ insertTable: {
554
+ ...COMMON_OPERATION_KEY_DECISIONS,
555
+ position: true,
556
+ rows: true
557
+ },
558
+ deleteTable: COMMON_OPERATION_KEY_DECISIONS,
559
+ commentOnBlock: {
560
+ ...COMMON_OPERATION_KEY_DECISIONS,
561
+ quote: true,
562
+ comment: true
563
+ },
564
+ insertSignatureTable: {
565
+ ...COMMON_OPERATION_KEY_DECISIONS,
566
+ position: true,
567
+ parties: true,
568
+ comment: true
569
+ },
570
+ insertTableRow: {
571
+ ...COMMON_OPERATION_KEY_DECISIONS,
572
+ position: true,
573
+ cellTexts: true
574
+ },
575
+ deleteTableRow: COMMON_OPERATION_KEY_DECISIONS,
576
+ insertTableColumn: {
577
+ ...COMMON_OPERATION_KEY_DECISIONS,
578
+ position: true,
579
+ cellTexts: true
580
+ },
581
+ deleteTableColumn: COMMON_OPERATION_KEY_DECISIONS,
582
+ mergeTableCells: {
583
+ ...COMMON_OPERATION_KEY_DECISIONS,
584
+ endBlockId: true,
585
+ rowCount: true
586
+ },
587
+ splitTableCell: COMMON_OPERATION_KEY_DECISIONS
588
+ };
589
+ const acceptedKeys = (decisions) => Object.keys(decisions).filter((key) => decisions[key] === true);
468
590
  /**
469
591
  * Every property each operation type accepts on the wire; the parser
470
592
  * rejects any other key. Exported so a lenient front door (an LLM tool
@@ -472,116 +594,27 @@ const RANGE_OPERATION_KEYS = [
472
594
  * guessing, and so tool schemas can be derived from the contract.
473
595
  */
474
596
  const FOLIO_DOCUMENT_OPERATION_KEYS_BY_TYPE = Object.freeze({
475
- replaceInBlock: [
476
- ...COMMON_OPERATION_KEYS,
477
- "find",
478
- "replace",
479
- "comment"
480
- ],
481
- replaceRange: [
482
- ...RANGE_OPERATION_KEYS,
483
- "suggestionId",
484
- "replace",
485
- "comment"
486
- ],
487
- commentOnRange: [...RANGE_OPERATION_KEYS, "comment"],
488
- formatRange: [
489
- ...RANGE_OPERATION_KEYS,
490
- "suggestionId",
491
- "formatting"
492
- ],
493
- insertAfterBlock: [
494
- ...COMMON_OPERATION_KEYS,
495
- "text",
496
- "inheritFormatting",
497
- "alignment",
498
- "spacing",
499
- "indentation",
500
- "lineBreakMode",
501
- "listLevel",
502
- "numbering",
503
- "moveId",
504
- "pageBreakBefore",
505
- "hardPageBreak",
506
- "styleId",
507
- "comment"
508
- ],
509
- insertBeforeBlock: [
510
- ...COMMON_OPERATION_KEYS,
511
- "text",
512
- "inheritFormatting",
513
- "alignment",
514
- "spacing",
515
- "indentation",
516
- "lineBreakMode",
517
- "listLevel",
518
- "numbering",
519
- "moveId",
520
- "pageBreakBefore",
521
- "hardPageBreak",
522
- "styleId",
523
- "comment"
524
- ],
525
- replaceBlock: [
526
- ...COMMON_OPERATION_KEYS,
527
- "text",
528
- "preserveFormatting",
529
- "styleId",
530
- "comment"
531
- ],
532
- deleteBlock: [
533
- ...COMMON_OPERATION_KEYS,
534
- "moveId",
535
- "comment"
536
- ],
537
- splitBlock: [
538
- ...COMMON_OPERATION_KEYS,
539
- "offset",
540
- "separator",
541
- "firstParagraphProperties",
542
- "secondParagraphProperties"
543
- ],
544
- mergeBlockWithNext: [
545
- ...COMMON_OPERATION_KEYS,
546
- "separator",
547
- "mergedParagraphProperties"
548
- ],
549
- setBlockParagraphProperties: [...COMMON_OPERATION_KEYS, "properties"],
550
- insertTable: [
551
- ...COMMON_OPERATION_KEYS,
552
- "position",
553
- "rows"
554
- ],
555
- deleteTable: COMMON_OPERATION_KEYS,
556
- commentOnBlock: [
557
- ...COMMON_OPERATION_KEYS,
558
- "quote",
559
- "comment"
560
- ],
561
- insertSignatureTable: [
562
- ...COMMON_OPERATION_KEYS,
563
- "position",
564
- "parties",
565
- "comment"
566
- ],
567
- insertTableRow: [
568
- ...COMMON_OPERATION_KEYS,
569
- "position",
570
- "cellTexts"
571
- ],
572
- deleteTableRow: COMMON_OPERATION_KEYS,
573
- insertTableColumn: [
574
- ...COMMON_OPERATION_KEYS,
575
- "position",
576
- "cellTexts"
577
- ],
578
- deleteTableColumn: COMMON_OPERATION_KEYS,
579
- mergeTableCells: [
580
- ...COMMON_OPERATION_KEYS,
581
- "endBlockId",
582
- "rowCount"
583
- ],
584
- splitTableCell: COMMON_OPERATION_KEYS
597
+ replaceInBlock: acceptedKeys(OPERATION_KEY_DECISIONS.replaceInBlock),
598
+ replaceRange: acceptedKeys(OPERATION_KEY_DECISIONS.replaceRange),
599
+ commentOnRange: acceptedKeys(OPERATION_KEY_DECISIONS.commentOnRange),
600
+ formatRange: acceptedKeys(OPERATION_KEY_DECISIONS.formatRange),
601
+ insertAfterBlock: acceptedKeys(OPERATION_KEY_DECISIONS.insertAfterBlock),
602
+ insertBeforeBlock: acceptedKeys(OPERATION_KEY_DECISIONS.insertBeforeBlock),
603
+ replaceBlock: acceptedKeys(OPERATION_KEY_DECISIONS.replaceBlock),
604
+ deleteBlock: acceptedKeys(OPERATION_KEY_DECISIONS.deleteBlock),
605
+ splitBlock: acceptedKeys(OPERATION_KEY_DECISIONS.splitBlock),
606
+ mergeBlockWithNext: acceptedKeys(OPERATION_KEY_DECISIONS.mergeBlockWithNext),
607
+ setBlockParagraphProperties: acceptedKeys(OPERATION_KEY_DECISIONS.setBlockParagraphProperties),
608
+ insertTable: acceptedKeys(OPERATION_KEY_DECISIONS.insertTable),
609
+ deleteTable: acceptedKeys(OPERATION_KEY_DECISIONS.deleteTable),
610
+ commentOnBlock: acceptedKeys(OPERATION_KEY_DECISIONS.commentOnBlock),
611
+ insertSignatureTable: acceptedKeys(OPERATION_KEY_DECISIONS.insertSignatureTable),
612
+ insertTableRow: acceptedKeys(OPERATION_KEY_DECISIONS.insertTableRow),
613
+ deleteTableRow: acceptedKeys(OPERATION_KEY_DECISIONS.deleteTableRow),
614
+ insertTableColumn: acceptedKeys(OPERATION_KEY_DECISIONS.insertTableColumn),
615
+ deleteTableColumn: acceptedKeys(OPERATION_KEY_DECISIONS.deleteTableColumn),
616
+ mergeTableCells: acceptedKeys(OPERATION_KEY_DECISIONS.mergeTableCells),
617
+ splitTableCell: acceptedKeys(OPERATION_KEY_DECISIONS.splitTableCell)
585
618
  });
586
619
  const isFolioDocumentOperationType = (value) => Object.hasOwn(FOLIO_DOCUMENT_OPERATION_KEYS_BY_TYPE, value);
587
620
  const parseSignatureParties = (value, path) => {
@@ -762,6 +795,8 @@ const parseDocumentOperation = (value, index) => {
762
795
  });
763
796
  const lineBreakMode = value["lineBreakMode"];
764
797
  if (lineBreakMode !== void 0 && lineBreakMode !== "paragraph" && lineBreakMode !== "inline") return invalidBatch(`${path}.lineBreakMode`, "expected \"paragraph\" or \"inline\" when provided");
798
+ const formattingScope = value["formattingScope"];
799
+ if (formattingScope !== void 0 && formattingScope !== "firstParagraph" && formattingScope !== "allParagraphs") return invalidBatch(`${path}.formattingScope`, "expected \"firstParagraph\" or \"allParagraphs\" when provided");
765
800
  const text = readString(value, "text", path);
766
801
  if (hardPageBreak !== void 0 && text.length > 0) return invalidBatch(`${path}.text`, "expected empty text with hardPageBreak");
767
802
  if (hardPageBreak !== void 0 && pageBreakBefore !== void 0) return invalidBatch(`${path}.pageBreakBefore`, "cannot combine hardPageBreak with pageBreakBefore");
@@ -777,6 +812,7 @@ const parseDocumentOperation = (value, index) => {
777
812
  ...spacing !== void 0 && { spacing },
778
813
  ...indentation !== void 0 && { indentation },
779
814
  ...lineBreakMode !== void 0 && { lineBreakMode },
815
+ ...formattingScope !== void 0 && { formattingScope },
780
816
  ...listLevel !== void 0 && { listLevel },
781
817
  ...numbering !== void 0 && { numbering },
782
818
  ...moveId !== void 0 && { moveId },
@@ -0,0 +1,8 @@
1
+ import { document_d_exports } from "../types/document.js";
2
+ //#region src/docx/blockPlainText.d.ts
3
+ type PlainTextBlock = document_d_exports.Paragraph | document_d_exports.Table | document_d_exports.BlockSdt;
4
+ /** One entry per block, so callers can join or count lines as they need. */
5
+ declare const collectBlockTexts: (blocks: readonly PlainTextBlock[]) => string[];
6
+ declare const blockPlainText: (blocks: readonly PlainTextBlock[]) => string;
7
+ //#endregion
8
+ export { PlainTextBlock, blockPlainText, collectBlockTexts };
@@ -0,0 +1,40 @@
1
+ import { getParagraphText } from "./paragraphParser.js";
2
+ import { panic } from "better-result";
3
+ //#region src/docx/blockPlainText.ts
4
+ /**
5
+ * The one plain-text projection of a block sequence.
6
+ *
7
+ * Every story — body, header, footer, footnote, endnote — reads through here,
8
+ * so a reader, a hash and a comparison all see the same string for the same
9
+ * content. Header and footer text used to come from a separate walk that
10
+ * handled only text runs, silently dropping fields, hyperlinks, tabs, breaks
11
+ * and tracked changes, so the same paragraph read one way in a note and another
12
+ * in a header.
13
+ *
14
+ * Separators carry the structure a reader needs: paragraphs and table rows are
15
+ * newline-separated, cells within a row tab-separated. `getParagraphText` owns
16
+ * everything below block level and reads the accepted tracked-change view.
17
+ */
18
+ /** One entry per block, so callers can join or count lines as they need. */
19
+ const collectBlockTexts = (blocks) => {
20
+ const texts = [];
21
+ for (const block of blocks) switch (block.type) {
22
+ case "paragraph":
23
+ texts.push(getParagraphText(block));
24
+ break;
25
+ case "table":
26
+ for (const row of block.rows) {
27
+ if (row.formatting?.hidden === true) continue;
28
+ texts.push(row.cells.map((cell) => collectBlockTexts(cell.content).join("\n")).join(" "));
29
+ }
30
+ break;
31
+ case "blockSdt":
32
+ texts.push(...collectBlockTexts(block.content));
33
+ break;
34
+ default: panic(`Unsupported block in plain-text extraction: ${JSON.stringify(block)}`);
35
+ }
36
+ return texts;
37
+ };
38
+ const blockPlainText = (blocks) => collectBlockTexts(blocks).join("\n");
39
+ //#endregion
40
+ export { blockPlainText, collectBlockTexts };
@@ -107,7 +107,6 @@ const withoutOrphanBlockMarkers = (blocks, validCommentIds) => {
107
107
  const withoutOrphanBlockMarker = (block, validCommentIds) => {
108
108
  if (block.type === "paragraph") return withoutOrphanParagraphMarkers(block, validCommentIds);
109
109
  if (block.type === "table") return withoutOrphanTableMarkers(block, validCommentIds);
110
- if (!("content" in block) || !block.content) return block;
111
110
  const content = withoutOrphanBlockMarkers(block.content, validCommentIds);
112
111
  if (!content) return block;
113
112
  return {
@@ -1,4 +1,5 @@
1
1
  import { document_d_exports } from "../types/document.js";
2
+ import { DrawingSafetyClass } from "./imageRawXml.js";
2
3
  //#region src/docx/compatibility.d.ts
3
4
  type DocxCompatibilityReason = "opaqueDrawing";
4
5
  type FolioDocxCompatibilityHost = "browser" | "server" | "unknown";
@@ -26,14 +27,27 @@ type DocxCompatibilityIssue = {
26
27
  code: DocxCompatibilityReason;
27
28
  location: DocxCompatibilityLocation;
28
29
  };
30
+ /** A drawing and the fate the run serializer holds for it. */
31
+ type DocxDrawingClassification = {
32
+ class: DrawingSafetyClass;
33
+ location: DocxCompatibilityLocation;
34
+ };
35
+ /**
36
+ * Schema 2 replaced the per-drawing boolean judgement with
37
+ * {@link DocxDrawingClassification} and stopped reporting a replayable drawing
38
+ * as an issue; `issues` now holds opaque drawings only.
39
+ */
29
40
  type DocxCompatibility = {
30
- schemaVersion: 1;
41
+ schemaVersion: 2;
31
42
  context: DocxCompatibilityContext;
32
43
  canSafelyEdit: boolean;
44
+ /** Every drawing the walk reached, classified. */
45
+ drawings: DocxDrawingClassification[];
46
+ /** The blocking subset: drawings a save can neither replay nor regenerate. */
33
47
  issues: DocxCompatibilityIssue[];
34
48
  reasons: DocxCompatibilityReason[];
35
49
  unsupportedContentCount: number;
36
50
  };
37
51
  declare const inspectDocxCompatibility: (doc: document_d_exports.Document, options?: InspectDocxCompatibilityOptions) => DocxCompatibility;
38
52
  //#endregion
39
- export { DocxCompatibility, DocxCompatibilityContext, DocxCompatibilityIssue, DocxCompatibilityLocation, DocxCompatibilityPart, DocxCompatibilityReason, FolioDocxCompatibilityHost, FolioDocxCompatibilityProfile, InspectDocxCompatibilityOptions, inspectDocxCompatibility };
53
+ export { DocxCompatibility, DocxCompatibilityContext, DocxCompatibilityIssue, DocxCompatibilityLocation, DocxCompatibilityPart, DocxCompatibilityReason, DocxDrawingClassification, FolioDocxCompatibilityHost, FolioDocxCompatibilityProfile, InspectDocxCompatibilityOptions, inspectDocxCompatibility };
@@ -1,5 +1,16 @@
1
- import { DOCX_CONFORMANCE_CLASSES, DRAWING_RAW_XML_MODES } from "@stll/docx-core/model";
1
+ import { DRAWING_SAFETY_CLASSES, classifyDrawingSafety } from "./imageRawXml.js";
2
+ import { DOCX_CONFORMANCE_CLASSES } from "@stll/docx-core/model";
2
3
  //#region src/docx/compatibility.ts
4
+ /**
5
+ * Whether a parsed package can be edited without losing content on save.
6
+ *
7
+ * Every part walked here is re-serialized from the model at some point: the
8
+ * repack always rebuilds `word/document.xml`, headers and footers replay their
9
+ * captured bytes only while their content fingerprint is unchanged, and note
10
+ * parts are preserved except for edited paragraphs spliced back by `w:paraId`.
11
+ * So an opaque drawing anywhere in this walk is a real risk, while a drawing the
12
+ * serializer replays verbatim is not, whichever part holds it.
13
+ */
3
14
  const resolveCompatibilityContext = (doc, options) => ({
4
15
  host: options.host ?? "unknown",
5
16
  profile: options.profile ?? doc.package.conformanceClass ?? DOCX_CONFORMANCE_CLASSES.UNKNOWN
@@ -7,13 +18,16 @@ const resolveCompatibilityContext = (doc, options) => ({
7
18
  const inspectDocxCompatibility = (doc, options = {}) => {
8
19
  const context = resolveCompatibilityContext(doc, options);
9
20
  const reasons = /* @__PURE__ */ new Set();
21
+ const drawings = [];
10
22
  const issues = [];
11
- const record = (location) => {
23
+ const record = (drawing) => {
24
+ drawings.push(drawing);
25
+ if (drawing.class !== DRAWING_SAFETY_CLASSES.OPAQUE) return;
12
26
  const code = "opaqueDrawing";
13
27
  reasons.add(code);
14
28
  issues.push({
15
29
  code,
16
- location
30
+ location: drawing.location
17
31
  });
18
32
  };
19
33
  inspectBlocks(doc.package.document.content, {
@@ -54,9 +68,10 @@ const inspectDocxCompatibility = (doc, options = {}) => {
54
68
  record
55
69
  });
56
70
  return {
57
- schemaVersion: 1,
71
+ schemaVersion: 2,
58
72
  context,
59
73
  canSafelyEdit: issues.length === 0,
74
+ drawings,
60
75
  issues,
61
76
  reasons: Array.from(reasons),
62
77
  unsupportedContentCount: issues.length
@@ -146,11 +161,17 @@ function inspectHyperlink(hyperlink, context) {
146
161
  });
147
162
  }
148
163
  function inspectRun(run, context) {
149
- for (const [contentIndex, content] of run.content.entries()) if (content.type === "drawing" && content.rawXml && content.rawXmlMode !== DRAWING_RAW_XML_MODES.PRESERVE_ONLY) context.record({
150
- ...context.blockId === void 0 ? {} : { blockId: context.blockId },
151
- part: context.part,
152
- path: `${context.path}.content[${contentIndex}]`
153
- });
164
+ for (const [contentIndex, content] of run.content.entries()) {
165
+ if (content.type !== "drawing") continue;
166
+ context.record({
167
+ class: classifyDrawingSafety(content),
168
+ location: {
169
+ ...context.blockId === void 0 ? {} : { blockId: context.blockId },
170
+ part: context.part,
171
+ path: `${context.path}.content[${contentIndex}]`
172
+ }
173
+ });
174
+ }
154
175
  }
155
176
  //#endregion
156
177
  export { inspectDocxCompatibility };
@@ -1,9 +1,9 @@
1
+ import { blockPlainText } from "./blockPlainText.js";
1
2
  import { parseEndnoteProperties, parseFootnoteProperties } from "./notePropertiesParser.js";
2
- import { getParagraphText, parseParagraph } from "./paragraphParser.js";
3
+ import { parseParagraph } from "./paragraphParser.js";
3
4
  import { parseSdtProperties } from "./sdtProperties.js";
4
5
  import { parseTable } from "./tableParser.js";
5
6
  import { findChild, findChildren, getAttributes, getChildElements, getLocalName, parseXml } from "./xmlParser.js";
6
- import { panic } from "better-result";
7
7
  //#region src/docx/footnoteParser.ts
8
8
  /**
9
9
  * Parse note type attribute
@@ -173,32 +173,13 @@ function createEndnoteMap(byId, endnotes) {
173
173
  * Uses the accepted tracked-change view and recurses through every note block.
174
174
  */
175
175
  function getFootnoteText(footnote) {
176
- return collectNoteBlockTexts(footnote.content).join("\n");
176
+ return blockPlainText(footnote.content);
177
177
  }
178
178
  /**
179
179
  * Get plain text content of an endnote.
180
180
  */
181
181
  function getEndnoteText(endnote) {
182
- return collectNoteBlockTexts(endnote.content).join("\n");
183
- }
184
- function collectNoteBlockTexts(blocks) {
185
- const texts = [];
186
- for (const block of blocks) switch (block.type) {
187
- case "paragraph":
188
- texts.push(getParagraphText(block));
189
- break;
190
- case "table":
191
- for (const row of block.rows) {
192
- if (row.formatting?.hidden === true) continue;
193
- texts.push(row.cells.map((cell) => collectNoteBlockTexts(cell.content).join("\n")).join(" "));
194
- }
195
- break;
196
- case "blockSdt":
197
- texts.push(...collectNoteBlockTexts(block.content));
198
- break;
199
- default: panic(`Unsupported note block in plain-text extraction: ${JSON.stringify(block)}`);
200
- }
201
- return texts;
182
+ return blockPlainText(endnote.content);
202
183
  }
203
184
  /**
204
185
  * Check if a footnote is a separator (not regular content)
@@ -0,0 +1,22 @@
1
+ import { document_d_exports } from "../types/document.js";
2
+ import { XmlElement } from "./xmlParser.js";
3
+ //#region src/docx/graphicFrameLocks.d.ts
4
+ /** Every modeled lock, in schema order: the total map above keeps it exhaustive. */
5
+ declare const GRAPHIC_FRAME_LOCK_KEYS: ("noGrp" | "noDrilldown" | "noSelect" | "noChangeAspect" | "noMove" | "noResize")[];
6
+ /**
7
+ * Read the locks off a `wp:inline` or `wp:anchor` element.
8
+ *
9
+ * Returns undefined when the element is absent or carries no recognized
10
+ * attribute: an authored `<a:graphicFrameLocks/>` with nothing on it means the
11
+ * same as no element at all, so both stay "spec defaults" on the model.
12
+ */
13
+ declare const parseGraphicFrameLocks: (parent: XmlElement) => document_d_exports.ImageFrameLocks | undefined;
14
+ /**
15
+ * Emit the whole `wp:cNvGraphicFramePr` element for regenerated DrawingML.
16
+ *
17
+ * Absent locks mean no authored frame was ever parsed (a Folio-created
18
+ * picture), which keeps the historical `noChangeAspect="1"`.
19
+ */
20
+ declare const serializeGraphicFrameLocks: (locks: document_d_exports.ImageFrameLocks | undefined) => string;
21
+ //#endregion
22
+ export { GRAPHIC_FRAME_LOCK_KEYS, parseGraphicFrameLocks, serializeGraphicFrameLocks };