@usejunior/docx-core 0.19.1 → 0.21.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.
- package/README.md +12 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/cli/conformance-adapter.d.ts.map +1 -1
- package/dist/cli/conformance-adapter.js +0 -27
- package/dist/cli/conformance-adapter.js.map +1 -1
- package/dist/core-types.d.ts +1 -139
- package/dist/core-types.d.ts.map +1 -1
- package/dist/core-types.js +1 -3
- package/dist/core-types.js.map +1 -1
- package/dist/generation/compile.d.ts.map +1 -1
- package/dist/generation/compile.js +1 -3
- package/dist/generation/compile.js.map +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -1
- package/dist/index.js.map +1 -1
- package/dist/integration/generation-probes.d.ts +36 -2
- package/dist/integration/generation-probes.d.ts.map +1 -1
- package/dist/integration/generation-probes.js +137 -15
- package/dist/integration/generation-probes.js.map +1 -1
- package/dist/integration/libreoffice-oracle.d.ts +3 -1
- package/dist/integration/libreoffice-oracle.d.ts.map +1 -1
- package/dist/integration/libreoffice-oracle.js +10 -4
- package/dist/integration/libreoffice-oracle.js.map +1 -1
- package/dist/integration/synthetic-docx-fixture.d.ts.map +1 -1
- package/dist/integration/synthetic-docx-fixture.js +8 -0
- package/dist/integration/synthetic-docx-fixture.js.map +1 -1
- package/dist/primitives/accept_ai_edits.js +14 -2
- package/dist/primitives/accept_ai_edits.js.map +1 -1
- package/dist/primitives/accept_changes.d.ts +6 -0
- package/dist/primitives/accept_changes.d.ts.map +1 -1
- package/dist/primitives/accept_changes.js +236 -62
- package/dist/primitives/accept_changes.js.map +1 -1
- package/dist/primitives/bookmarks.d.ts +8 -2
- package/dist/primitives/bookmarks.d.ts.map +1 -1
- package/dist/primitives/bookmarks.js +31 -7
- package/dist/primitives/bookmarks.js.map +1 -1
- package/dist/primitives/comments.d.ts +101 -5
- package/dist/primitives/comments.d.ts.map +1 -1
- package/dist/primitives/comments.js +356 -156
- package/dist/primitives/comments.js.map +1 -1
- package/dist/primitives/conformance.d.ts +42 -0
- package/dist/primitives/conformance.d.ts.map +1 -0
- package/dist/primitives/conformance.js +61 -0
- package/dist/primitives/conformance.js.map +1 -0
- package/dist/primitives/document.d.ts +145 -2
- package/dist/primitives/document.d.ts.map +1 -1
- package/dist/primitives/document.js +505 -27
- package/dist/primitives/document.js.map +1 -1
- package/dist/primitives/document_view-headings.d.ts +3 -1
- package/dist/primitives/document_view-headings.d.ts.map +1 -1
- package/dist/primitives/document_view-headings.js +5 -5
- package/dist/primitives/document_view-headings.js.map +1 -1
- package/dist/primitives/document_view.d.ts +2 -0
- package/dist/primitives/document_view.d.ts.map +1 -1
- package/dist/primitives/document_view.js +18 -4
- package/dist/primitives/document_view.js.map +1 -1
- package/dist/primitives/errors.d.ts +3 -2
- package/dist/primitives/errors.d.ts.map +1 -1
- package/dist/primitives/errors.js +3 -1
- package/dist/primitives/errors.js.map +1 -1
- package/dist/primitives/extract_revisions.d.ts +23 -6
- package/dist/primitives/extract_revisions.d.ts.map +1 -1
- package/dist/primitives/extract_revisions.js +208 -38
- package/dist/primitives/extract_revisions.js.map +1 -1
- package/dist/primitives/field_evaluation.d.ts +70 -0
- package/dist/primitives/field_evaluation.d.ts.map +1 -0
- package/dist/primitives/field_evaluation.js +462 -0
- package/dist/primitives/field_evaluation.js.map +1 -0
- package/dist/primitives/footnotes.d.ts +53 -3
- package/dist/primitives/footnotes.d.ts.map +1 -1
- package/dist/primitives/footnotes.js +228 -83
- package/dist/primitives/footnotes.js.map +1 -1
- package/dist/primitives/index.d.ts +12 -1
- package/dist/primitives/index.d.ts.map +1 -1
- package/dist/primitives/index.js +12 -1
- package/dist/primitives/index.js.map +1 -1
- package/dist/primitives/merge_runs.d.ts +3 -1
- package/dist/primitives/merge_runs.d.ts.map +1 -1
- package/dist/primitives/merge_runs.js +12 -2
- package/dist/primitives/merge_runs.js.map +1 -1
- package/dist/primitives/namespaces.d.ts +10 -2
- package/dist/primitives/namespaces.d.ts.map +1 -1
- package/dist/primitives/namespaces.js +11 -2
- package/dist/primitives/namespaces.js.map +1 -1
- package/dist/primitives/note_conversion.d.ts +11 -0
- package/dist/primitives/note_conversion.d.ts.map +1 -0
- package/dist/primitives/note_conversion.js +12 -0
- package/dist/primitives/note_conversion.js.map +1 -0
- package/dist/primitives/paragraph-index.d.ts +31 -0
- package/dist/primitives/paragraph-index.d.ts.map +1 -0
- package/dist/primitives/paragraph-index.js +140 -0
- package/dist/primitives/paragraph-index.js.map +1 -0
- package/dist/primitives/paragraph_merge_formatting.d.ts +24 -0
- package/dist/primitives/paragraph_merge_formatting.d.ts.map +1 -0
- package/dist/primitives/paragraph_merge_formatting.js +86 -0
- package/dist/primitives/paragraph_merge_formatting.js.map +1 -0
- package/dist/primitives/paragraph_numbering.d.ts +40 -0
- package/dist/primitives/paragraph_numbering.d.ts.map +1 -0
- package/dist/primitives/paragraph_numbering.js +198 -0
- package/dist/primitives/paragraph_numbering.js.map +1 -0
- package/dist/primitives/paragraph_structure.d.ts +19 -0
- package/dist/primitives/paragraph_structure.d.ts.map +1 -0
- package/dist/primitives/paragraph_structure.js +66 -0
- package/dist/primitives/paragraph_structure.js.map +1 -0
- package/dist/primitives/reject_changes.d.ts +6 -0
- package/dist/primitives/reject_changes.d.ts.map +1 -1
- package/dist/primitives/reject_changes.js +278 -68
- package/dist/primitives/reject_changes.js.map +1 -1
- package/dist/primitives/relationships.d.ts +22 -0
- package/dist/primitives/relationships.d.ts.map +1 -1
- package/dist/primitives/relationships.js +87 -0
- package/dist/primitives/relationships.js.map +1 -1
- package/dist/primitives/revision-parts.d.ts +15 -0
- package/dist/primitives/revision-parts.d.ts.map +1 -1
- package/dist/primitives/revision-parts.js +33 -1
- package/dist/primitives/revision-parts.js.map +1 -1
- package/dist/primitives/sectPrAudit.d.ts.map +1 -1
- package/dist/primitives/sectPrAudit.js +10 -1
- package/dist/primitives/sectPrAudit.js.map +1 -1
- package/dist/primitives/sections.d.ts +135 -0
- package/dist/primitives/sections.d.ts.map +1 -0
- package/dist/primitives/sections.js +644 -0
- package/dist/primitives/sections.js.map +1 -0
- package/dist/primitives/styles.d.ts +61 -0
- package/dist/primitives/styles.d.ts.map +1 -1
- package/dist/primitives/styles.js +207 -25
- package/dist/primitives/styles.js.map +1 -1
- package/dist/primitives/symbol_run_content.d.ts +42 -0
- package/dist/primitives/symbol_run_content.d.ts.map +1 -0
- package/dist/primitives/symbol_run_content.js +79 -0
- package/dist/primitives/symbol_run_content.js.map +1 -0
- package/dist/primitives/table_cells.d.ts +49 -0
- package/dist/primitives/table_cells.d.ts.map +1 -0
- package/dist/primitives/table_cells.js +149 -0
- package/dist/primitives/table_cells.js.map +1 -0
- package/dist/primitives/table_columns.d.ts +50 -0
- package/dist/primitives/table_columns.d.ts.map +1 -0
- package/dist/primitives/table_columns.js +138 -0
- package/dist/primitives/table_columns.js.map +1 -0
- package/dist/primitives/table_edit_common.d.ts +39 -0
- package/dist/primitives/table_edit_common.d.ts.map +1 -0
- package/dist/primitives/table_edit_common.js +163 -0
- package/dist/primitives/table_edit_common.js.map +1 -0
- package/dist/primitives/table_occupancy.d.ts +39 -0
- package/dist/primitives/table_occupancy.d.ts.map +1 -0
- package/dist/primitives/table_occupancy.js +145 -0
- package/dist/primitives/table_occupancy.js.map +1 -0
- package/dist/primitives/table_rows.d.ts +56 -0
- package/dist/primitives/table_rows.d.ts.map +1 -0
- package/dist/primitives/table_rows.js +390 -0
- package/dist/primitives/table_rows.js.map +1 -0
- package/dist/primitives/text.d.ts +69 -1
- package/dist/primitives/text.d.ts.map +1 -1
- package/dist/primitives/text.js +592 -102
- package/dist/primitives/text.js.map +1 -1
- package/dist/primitives/track-changes-emitter.d.ts +23 -0
- package/dist/primitives/track-changes-emitter.d.ts.map +1 -1
- package/dist/primitives/track-changes-emitter.js +64 -1
- package/dist/primitives/track-changes-emitter.js.map +1 -1
- package/dist/primitives/validate_document.d.ts.map +1 -1
- package/dist/primitives/validate_document.js +22 -1
- package/dist/primitives/validate_document.js.map +1 -1
- package/dist/primitives/zip.d.ts +22 -1
- package/dist/primitives/zip.d.ts.map +1 -1
- package/dist/primitives/zip.js +47 -8
- package/dist/primitives/zip.js.map +1 -1
- package/dist/shared/docx/DocxArchive.d.ts +6 -2
- package/dist/shared/docx/DocxArchive.d.ts.map +1 -1
- package/dist/shared/docx/DocxArchive.js +17 -4
- package/dist/shared/docx/DocxArchive.js.map +1 -1
- package/dist/shared/field-semantics.d.ts +26 -0
- package/dist/shared/field-semantics.d.ts.map +1 -0
- package/dist/shared/field-semantics.js +232 -0
- package/dist/shared/field-semantics.js.map +1 -0
- package/dist/shared/field-structure.d.ts +10 -1
- package/dist/shared/field-structure.d.ts.map +1 -1
- package/dist/shared/field-structure.js +31 -12
- package/dist/shared/field-structure.js.map +1 -1
- package/package.json +4 -5
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { OOXML, W } from './namespaces.js';
|
|
2
|
+
import { getAttributeSafe } from './xml-helpers.js';
|
|
3
|
+
function wordAttr(element, localName) {
|
|
4
|
+
return getAttributeSafe(element, OOXML.W_NS, localName, 'w');
|
|
5
|
+
}
|
|
6
|
+
function kindOf(element) {
|
|
7
|
+
if (element.namespaceURI !== OOXML.W_NS)
|
|
8
|
+
return 'other';
|
|
9
|
+
switch (element.localName) {
|
|
10
|
+
case W.r: return 'run';
|
|
11
|
+
case W.t: return 'text';
|
|
12
|
+
case W.tab: return 'tab';
|
|
13
|
+
case W.br: return 'break';
|
|
14
|
+
case W.commentRangeStart: return 'comment-range-start';
|
|
15
|
+
case W.commentRangeEnd: return 'comment-range-end';
|
|
16
|
+
case W.commentReference: return 'comment-reference';
|
|
17
|
+
case W.footnoteReference: return 'footnote-reference';
|
|
18
|
+
case W.fldChar:
|
|
19
|
+
case W.instrText:
|
|
20
|
+
case 'delInstrText': return 'field-code';
|
|
21
|
+
case 'bookmarkStart':
|
|
22
|
+
case 'bookmarkEnd': return 'bookmark';
|
|
23
|
+
default: return 'other';
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Build the canonical structural and visible-coordinate index for one
|
|
28
|
+
* WordprocessingML paragraph. Every descendant run and marker receives a
|
|
29
|
+
* structural coordinate; field instruction text remains zero-width while
|
|
30
|
+
* cached field results participate in visible coordinates.
|
|
31
|
+
*
|
|
32
|
+
* @conformance ECMA-376 edition 5, Part 1 § 17.16.18
|
|
33
|
+
* @see https://github.com/UseJunior/safe-docx/issues/904
|
|
34
|
+
*/
|
|
35
|
+
export function buildParagraphIndex(paragraph) {
|
|
36
|
+
const nodes = [];
|
|
37
|
+
const runs = [];
|
|
38
|
+
const fieldStack = [];
|
|
39
|
+
const instructions = new Map();
|
|
40
|
+
let nextFieldId = 1;
|
|
41
|
+
let structuralIndex = 0;
|
|
42
|
+
let visibleOffset = 0;
|
|
43
|
+
let runIndex = -1;
|
|
44
|
+
const currentResultId = () => {
|
|
45
|
+
if (fieldStack.length === 0 || fieldStack.some((frame) => frame.phase === 'instruction'))
|
|
46
|
+
return null;
|
|
47
|
+
return fieldStack.at(-1).id;
|
|
48
|
+
};
|
|
49
|
+
const visit = (element, containingRun) => {
|
|
50
|
+
if (element !== paragraph && element.namespaceURI === OOXML.W_NS && element.localName === W.p)
|
|
51
|
+
return;
|
|
52
|
+
const isRun = element.namespaceURI === OOXML.W_NS && element.localName === W.r;
|
|
53
|
+
let activeRun = containingRun;
|
|
54
|
+
if (isRun) {
|
|
55
|
+
runIndex += 1;
|
|
56
|
+
activeRun = {
|
|
57
|
+
element,
|
|
58
|
+
structuralIndex: structuralIndex++,
|
|
59
|
+
runIndex,
|
|
60
|
+
runVisibleOffset: 0,
|
|
61
|
+
visibleStart: visibleOffset,
|
|
62
|
+
visibleEnd: visibleOffset,
|
|
63
|
+
kind: 'run',
|
|
64
|
+
visibleText: '',
|
|
65
|
+
isFieldResult: false,
|
|
66
|
+
fieldResultId: null,
|
|
67
|
+
fieldInstruction: null,
|
|
68
|
+
};
|
|
69
|
+
nodes.push(activeRun);
|
|
70
|
+
runs.push(activeRun);
|
|
71
|
+
}
|
|
72
|
+
else if (element !== paragraph) {
|
|
73
|
+
const node = {
|
|
74
|
+
element,
|
|
75
|
+
structuralIndex: structuralIndex++,
|
|
76
|
+
runIndex: activeRun?.runIndex ?? null,
|
|
77
|
+
runVisibleOffset: activeRun ? visibleOffset - activeRun.visibleStart : 0,
|
|
78
|
+
visibleStart: visibleOffset,
|
|
79
|
+
visibleEnd: visibleOffset,
|
|
80
|
+
kind: kindOf(element),
|
|
81
|
+
visibleText: '',
|
|
82
|
+
isFieldResult: false,
|
|
83
|
+
fieldResultId: null,
|
|
84
|
+
fieldInstruction: null,
|
|
85
|
+
};
|
|
86
|
+
nodes.push(node);
|
|
87
|
+
if (node.kind === 'field-code' && element.localName === W.fldChar) {
|
|
88
|
+
const type = wordAttr(element, 'fldCharType') ?? '';
|
|
89
|
+
if (type === 'begin')
|
|
90
|
+
fieldStack.push({ id: nextFieldId++, phase: 'instruction', instruction: '' });
|
|
91
|
+
else if (type === 'separate') {
|
|
92
|
+
const frame = fieldStack.at(-1);
|
|
93
|
+
if (frame) {
|
|
94
|
+
frame.phase = 'result';
|
|
95
|
+
instructions.set(frame.id, frame.instruction.trim());
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
else if (type === 'end')
|
|
99
|
+
fieldStack.pop();
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
const instructionFrame = [...fieldStack].reverse().find((frame) => frame.phase === 'instruction');
|
|
103
|
+
if (instructionFrame && (element.localName === W.instrText || element.localName === 'delInstrText')) {
|
|
104
|
+
instructionFrame.instruction += element.textContent ?? '';
|
|
105
|
+
}
|
|
106
|
+
else if (activeRun && !instructionFrame && (node.kind === 'text' || node.kind === 'tab' || node.kind === 'break')) {
|
|
107
|
+
const text = node.kind === 'text' ? (element.textContent ?? '') : node.kind === 'tab' ? '\t' : '\n';
|
|
108
|
+
const resultId = currentResultId();
|
|
109
|
+
node.visibleText = text;
|
|
110
|
+
node.visibleEnd += text.length;
|
|
111
|
+
node.isFieldResult = resultId !== null;
|
|
112
|
+
node.fieldResultId = resultId;
|
|
113
|
+
visibleOffset += text.length;
|
|
114
|
+
if (activeRun) {
|
|
115
|
+
activeRun.visibleText += text;
|
|
116
|
+
activeRun.visibleEnd = visibleOffset;
|
|
117
|
+
activeRun.isFieldResult ||= resultId !== null;
|
|
118
|
+
if (activeRun.visibleText.length === text.length)
|
|
119
|
+
activeRun.fieldResultId = resultId;
|
|
120
|
+
else if (activeRun.fieldResultId !== resultId)
|
|
121
|
+
activeRun.fieldResultId = null;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (!isRun || activeRun) {
|
|
127
|
+
for (const child of Array.from(element.childNodes)) {
|
|
128
|
+
if (child.nodeType === 1)
|
|
129
|
+
visit(child, activeRun);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
visit(paragraph, null);
|
|
134
|
+
for (const node of nodes) {
|
|
135
|
+
if (node.fieldResultId !== null)
|
|
136
|
+
node.fieldInstruction = instructions.get(node.fieldResultId) ?? null;
|
|
137
|
+
}
|
|
138
|
+
return { paragraph, text: runs.map((run) => run.visibleText).join(''), nodes, runs };
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=paragraph-index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paragraph-index.js","sourceRoot":"","sources":["../../src/primitives/paragraph-index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** Remove vacated mark-property containers after selected revision resolution.
|
|
2
|
+
* This is an implementation cleanup policy, not a normative requirement.
|
|
3
|
+
* @internal
|
|
4
|
+
* @see https://github.com/UseJunior/safe-docx/issues/982
|
|
5
|
+
*/
|
|
6
|
+
export declare function removeEmptyParagraphMarkProperties(paragraph: Element): void;
|
|
7
|
+
/** Formatting-only test; never use this to decide whether to remove a paragraph. */
|
|
8
|
+
export declare function isEmptyParagraphFormattingRun(element: Element): boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Transfer the leading paragraph's base formatting when its content owns the
|
|
11
|
+
* merged paragraph. Break removal and formatting selection are separate:
|
|
12
|
+
* delimiter removal alone does not imply that the following style wins.
|
|
13
|
+
* Paragraph-mark run formatting follows the same owner; the surviving mark
|
|
14
|
+
* retains its revision markers and section boundary.
|
|
15
|
+
*
|
|
16
|
+
* The formatting-selection callers are characterized against LibreOffice;
|
|
17
|
+
* the cited section governs property ordering, not a claim of Word evidence.
|
|
18
|
+
*
|
|
19
|
+
* @internal
|
|
20
|
+
* @conformance ECMA-376 edition 5, Part 1 § 17.3.1.26
|
|
21
|
+
* @see openspec/changes/archive/2026-09-17-repair-paragraph-merge-formatting/design.md
|
|
22
|
+
*/
|
|
23
|
+
export declare function retainLeadingParagraphFormatting(leading: Element, following: Element): void;
|
|
24
|
+
//# sourceMappingURL=paragraph_merge_formatting.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paragraph_merge_formatting.d.ts","sourceRoot":"","sources":["../../src/primitives/paragraph_merge_formatting.ts"],"names":[],"mappings":"AAQA;;;;GAIG;AACH,wBAAgB,kCAAkC,CAAC,SAAS,EAAE,OAAO,GAAG,IAAI,CAQ3E;AAED,oFAAoF;AACpF,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAGvE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gCAAgC,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,GAAG,IAAI,CAmC3F"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { OOXML } from './namespaces.js';
|
|
2
|
+
const W = OOXML.W_NS;
|
|
3
|
+
const children = (node) => Array.from(node.childNodes)
|
|
4
|
+
.filter((child) => child.nodeType === 1);
|
|
5
|
+
const properties = (paragraph) => children(paragraph)
|
|
6
|
+
.find(child => child.namespaceURI === W && child.localName === 'pPr');
|
|
7
|
+
/** Remove vacated mark-property containers after selected revision resolution.
|
|
8
|
+
* This is an implementation cleanup policy, not a normative requirement.
|
|
9
|
+
* @internal
|
|
10
|
+
* @see https://github.com/UseJunior/safe-docx/issues/982
|
|
11
|
+
*/
|
|
12
|
+
export function removeEmptyParagraphMarkProperties(paragraph) {
|
|
13
|
+
const pPr = properties(paragraph);
|
|
14
|
+
if (!pPr)
|
|
15
|
+
return;
|
|
16
|
+
const rPr = children(pPr).find(child => child.namespaceURI === W && child.localName === 'rPr');
|
|
17
|
+
const vacated = (element) => element.attributes.length === 0 &&
|
|
18
|
+
Array.from(element.childNodes).every(node => node.nodeType === 3 && !node.nodeValue?.trim());
|
|
19
|
+
if (rPr && vacated(rPr))
|
|
20
|
+
pPr.removeChild(rPr);
|
|
21
|
+
if (vacated(pPr))
|
|
22
|
+
paragraph.removeChild(pPr);
|
|
23
|
+
}
|
|
24
|
+
/** Formatting-only test; never use this to decide whether to remove a paragraph. */
|
|
25
|
+
export function isEmptyParagraphFormattingRun(element) {
|
|
26
|
+
return element.namespaceURI === W && element.localName === 'r' && children(element).every(child => child.namespaceURI === W && (child.localName === 'rPr' || (child.localName === 't' && !child.textContent)));
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Transfer the leading paragraph's base formatting when its content owns the
|
|
30
|
+
* merged paragraph. Break removal and formatting selection are separate:
|
|
31
|
+
* delimiter removal alone does not imply that the following style wins.
|
|
32
|
+
* Paragraph-mark run formatting follows the same owner; the surviving mark
|
|
33
|
+
* retains its revision markers and section boundary.
|
|
34
|
+
*
|
|
35
|
+
* The formatting-selection callers are characterized against LibreOffice;
|
|
36
|
+
* the cited section governs property ordering, not a claim of Word evidence.
|
|
37
|
+
*
|
|
38
|
+
* @internal
|
|
39
|
+
* @conformance ECMA-376 edition 5, Part 1 § 17.3.1.26
|
|
40
|
+
* @see openspec/changes/archive/2026-09-17-repair-paragraph-merge-formatting/design.md
|
|
41
|
+
*/
|
|
42
|
+
export function retainLeadingParagraphFormatting(leading, following) {
|
|
43
|
+
const source = properties(leading);
|
|
44
|
+
const target = properties(following);
|
|
45
|
+
// A section boundary is not a CT_PPrBase formatting child. The mark
|
|
46
|
+
// resolver already decides which break survives; do not let a retained
|
|
47
|
+
// section suppress restoration of alignment/style onto surviving content.
|
|
48
|
+
// Section bindings remain on the surviving mark below, not in `base`.
|
|
49
|
+
const result = following.ownerDocument.createElementNS(W, 'w:pPr');
|
|
50
|
+
const base = source ? children(source).filter(child => child.namespaceURI !== W || !['rPr', 'sectPr', 'pPrChange'].includes(child.localName)) : [];
|
|
51
|
+
for (const child of base)
|
|
52
|
+
result.appendChild(child.cloneNode(true));
|
|
53
|
+
const sourceMark = source && children(source).find(child => child.namespaceURI === W && child.localName === 'rPr');
|
|
54
|
+
const targetMark = target && children(target).find(child => child.namespaceURI === W && child.localName === 'rPr');
|
|
55
|
+
const mark = following.ownerDocument.createElementNS(W, 'w:rPr');
|
|
56
|
+
const revisions = new Set(['ins', 'del', 'moveFrom', 'moveTo']);
|
|
57
|
+
// CT_ParaRPr requires the surviving revision sequence BEFORE glyph properties.
|
|
58
|
+
for (const child of targetMark ? children(targetMark) : []) {
|
|
59
|
+
if (child.namespaceURI === W && revisions.has(child.localName))
|
|
60
|
+
mark.appendChild(child.cloneNode(true));
|
|
61
|
+
}
|
|
62
|
+
for (const child of sourceMark ? children(sourceMark) : []) {
|
|
63
|
+
if (child.namespaceURI !== W || (!revisions.has(child.localName) && child.localName !== 'rPrChange'))
|
|
64
|
+
mark.appendChild(child.cloneNode(true));
|
|
65
|
+
}
|
|
66
|
+
// A formatting transfer must not silently resolve another author's pending
|
|
67
|
+
// history. Prefer the chosen owner's record; otherwise retain the survivor's.
|
|
68
|
+
const markHistory = [sourceMark, targetMark].flatMap(node => node ? children(node) : [])
|
|
69
|
+
.find(child => child.namespaceURI === W && child.localName === 'rPrChange');
|
|
70
|
+
if (markHistory)
|
|
71
|
+
mark.appendChild(markHistory.cloneNode(true));
|
|
72
|
+
if (mark.childNodes.length)
|
|
73
|
+
result.appendChild(mark);
|
|
74
|
+
const boundary = target && children(target).find(child => child.namespaceURI === W && child.localName === 'sectPr');
|
|
75
|
+
if (boundary)
|
|
76
|
+
result.appendChild(boundary.cloneNode(true));
|
|
77
|
+
const history = [source, target].flatMap(node => node ? children(node) : [])
|
|
78
|
+
.find(child => child.namespaceURI === W && child.localName === 'pPrChange');
|
|
79
|
+
if (history)
|
|
80
|
+
result.appendChild(history.cloneNode(true));
|
|
81
|
+
if (target)
|
|
82
|
+
following.removeChild(target);
|
|
83
|
+
if (result.childNodes.length)
|
|
84
|
+
following.insertBefore(result, following.firstChild);
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=paragraph_merge_formatting.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paragraph_merge_formatting.js","sourceRoot":"","sources":["../../src/primitives/paragraph_merge_formatting.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type RevisionContext } from './track-changes-emitter.js';
|
|
2
|
+
export type DirectParagraphNumbering = {
|
|
3
|
+
numId: string;
|
|
4
|
+
ilvl: number;
|
|
5
|
+
};
|
|
6
|
+
export type ParagraphNumberingMutation = {
|
|
7
|
+
paragraphId: string;
|
|
8
|
+
numbering: DirectParagraphNumbering | null;
|
|
9
|
+
};
|
|
10
|
+
export type ParagraphNumberingMutationResult = {
|
|
11
|
+
paragraphId: string;
|
|
12
|
+
changed: boolean;
|
|
13
|
+
previous: DirectParagraphNumbering | null;
|
|
14
|
+
current: DirectParagraphNumbering | null;
|
|
15
|
+
warning?: string;
|
|
16
|
+
};
|
|
17
|
+
export type ParagraphNumberingMutationErrorCode = 'PARAGRAPH_NOT_FOUND' | 'INCOMPLETE_NUMBERING' | 'NUMBERING_PART_MISSING' | 'NUMBERING_INSTANCE_NOT_FOUND' | 'ABSTRACT_NUMBERING_NOT_FOUND' | 'NUMBERING_LEVEL_NOT_FOUND' | 'INVALID_NUMBERING_REFERENCE';
|
|
18
|
+
export declare class ParagraphNumberingMutationError extends Error {
|
|
19
|
+
readonly code: ParagraphNumberingMutationErrorCode;
|
|
20
|
+
constructor(code: ParagraphNumberingMutationErrorCode, message: string);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Read only the paragraph's direct `w:numPr`; style-inherited numbering is not
|
|
24
|
+
* considered.
|
|
25
|
+
*
|
|
26
|
+
* @conformance ECMA-376 edition 5, Part 1 § 17.3.1.19
|
|
27
|
+
* @see #653
|
|
28
|
+
*/
|
|
29
|
+
export declare function getDirectParagraphNumbering(doc: Document, paragraphId: string): DirectParagraphNumbering | null;
|
|
30
|
+
/**
|
|
31
|
+
* Mutate one paragraph's direct list reference while preserving the numbering
|
|
32
|
+
* definitions and unrelated paragraph properties.
|
|
33
|
+
*
|
|
34
|
+
* @conformance ECMA-376 edition 5, Part 1 § 17.3.1.19
|
|
35
|
+
* @conformance ECMA-376 edition 5, Part 1 § 17.9.18
|
|
36
|
+
* @conformance ECMA-376 edition 5, Part 1 § 17.9.3
|
|
37
|
+
* @see #653
|
|
38
|
+
*/
|
|
39
|
+
export declare function setDirectParagraphNumbering(documentDoc: Document, numberingDoc: Document | null, mutation: ParagraphNumberingMutation, ctx?: RevisionContext): ParagraphNumberingMutationResult;
|
|
40
|
+
//# sourceMappingURL=paragraph_numbering.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paragraph_numbering.d.ts","sourceRoot":"","sources":["../../src/primitives/paragraph_numbering.ts"],"names":[],"mappings":"AAIA,OAAO,EAEL,KAAK,eAAe,EACrB,MAAM,4BAA4B,CAAC;AAEpC,MAAM,MAAM,wBAAwB,GAAG;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,wBAAwB,GAAG,IAAI,CAAC;CAC5C,CAAC;AAEF,MAAM,MAAM,gCAAgC,GAAG;IAC7C,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,wBAAwB,GAAG,IAAI,CAAC;IAC1C,OAAO,EAAE,wBAAwB,GAAG,IAAI,CAAC;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,mCAAmC,GAC3C,qBAAqB,GACrB,sBAAsB,GACtB,wBAAwB,GACxB,8BAA8B,GAC9B,8BAA8B,GAC9B,2BAA2B,GAC3B,6BAA6B,CAAC;AAElC,qBAAa,+BAAgC,SAAQ,KAAK;aAEtC,IAAI,EAAE,mCAAmC;gBAAzC,IAAI,EAAE,mCAAmC,EACzD,OAAO,EAAE,MAAM;CAKlB;AAkCD;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CACzC,GAAG,EAAE,QAAQ,EACb,WAAW,EAAE,MAAM,GAClB,wBAAwB,GAAG,IAAI,CAgBjC;AA4FD;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CACzC,WAAW,EAAE,QAAQ,EACrB,YAAY,EAAE,QAAQ,GAAG,IAAI,EAC7B,QAAQ,EAAE,0BAA0B,EACpC,GAAG,CAAC,EAAE,eAAe,GACpB,gCAAgC,CA6ElC"}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { findParagraphByBookmarkId } from './bookmarks.js';
|
|
2
|
+
import { getDirectChildrenByName } from './dom-helpers.js';
|
|
3
|
+
import { OOXML, W } from './namespaces.js';
|
|
4
|
+
import { parseNumberingXml } from './numbering.js';
|
|
5
|
+
import { buildPPrChangeElement, } from './track-changes-emitter.js';
|
|
6
|
+
export class ParagraphNumberingMutationError extends Error {
|
|
7
|
+
code;
|
|
8
|
+
constructor(code, message) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.code = code;
|
|
11
|
+
this.name = 'ParagraphNumberingMutationError';
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
function getWAttr(el, localName) {
|
|
15
|
+
return el.getAttributeNS(OOXML.W_NS, localName)
|
|
16
|
+
|| el.getAttribute(`w:${localName}`)
|
|
17
|
+
|| el.getAttribute(localName)
|
|
18
|
+
|| null;
|
|
19
|
+
}
|
|
20
|
+
function parseDirectNumberingFromParagraph(paragraph) {
|
|
21
|
+
const pPr = getDirectChildrenByName(paragraph, W.pPr)[0] ?? null;
|
|
22
|
+
const numPr = pPr ? getDirectChildrenByName(pPr, W.numPr)[0] ?? null : null;
|
|
23
|
+
if (!numPr)
|
|
24
|
+
return { value: null, complete: true };
|
|
25
|
+
const numIdEl = getDirectChildrenByName(numPr, W.numId)[0] ?? null;
|
|
26
|
+
const ilvlEl = getDirectChildrenByName(numPr, W.ilvl)[0] ?? null;
|
|
27
|
+
const numId = numIdEl ? getWAttr(numIdEl, W.val) : null;
|
|
28
|
+
const ilvlText = ilvlEl ? getWAttr(ilvlEl, W.val) : null;
|
|
29
|
+
const ilvl = ilvlText !== null ? Number(ilvlText) : Number.NaN;
|
|
30
|
+
if (numId === null
|
|
31
|
+
|| !/^[1-9]\d*$/.test(numId)
|
|
32
|
+
|| !Number.isSafeInteger(ilvl)
|
|
33
|
+
|| ilvl < 0) {
|
|
34
|
+
return { value: null, complete: false };
|
|
35
|
+
}
|
|
36
|
+
return { value: { numId, ilvl }, complete: true };
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Read only the paragraph's direct `w:numPr`; style-inherited numbering is not
|
|
40
|
+
* considered.
|
|
41
|
+
*
|
|
42
|
+
* @conformance ECMA-376 edition 5, Part 1 § 17.3.1.19
|
|
43
|
+
* @see #653
|
|
44
|
+
*/
|
|
45
|
+
export function getDirectParagraphNumbering(doc, paragraphId) {
|
|
46
|
+
const paragraph = findParagraphByBookmarkId(doc, paragraphId);
|
|
47
|
+
if (!paragraph) {
|
|
48
|
+
throw new ParagraphNumberingMutationError('PARAGRAPH_NOT_FOUND', `Paragraph '${paragraphId}' was not found.`);
|
|
49
|
+
}
|
|
50
|
+
const parsed = parseDirectNumberingFromParagraph(paragraph);
|
|
51
|
+
if (!parsed.complete) {
|
|
52
|
+
throw new ParagraphNumberingMutationError('INCOMPLETE_NUMBERING', `Paragraph '${paragraphId}' has an incomplete or invalid direct w:numPr.`);
|
|
53
|
+
}
|
|
54
|
+
return parsed.value;
|
|
55
|
+
}
|
|
56
|
+
function validateRequestedNumbering(numberingDoc, requested) {
|
|
57
|
+
if (!/^[1-9]\d*$/.test(requested.numId)
|
|
58
|
+
|| !Number.isSafeInteger(requested.ilvl)
|
|
59
|
+
|| requested.ilvl < 0) {
|
|
60
|
+
throw new ParagraphNumberingMutationError('INVALID_NUMBERING_REFERENCE', 'numId must be a positive decimal string and ilvl must be a non-negative safe integer.');
|
|
61
|
+
}
|
|
62
|
+
if (!numberingDoc) {
|
|
63
|
+
throw new ParagraphNumberingMutationError('NUMBERING_PART_MISSING', 'The document has no word/numbering.xml part.');
|
|
64
|
+
}
|
|
65
|
+
const model = parseNumberingXml(numberingDoc);
|
|
66
|
+
const instance = model.nums.get(requested.numId);
|
|
67
|
+
if (!instance) {
|
|
68
|
+
throw new ParagraphNumberingMutationError('NUMBERING_INSTANCE_NOT_FOUND', `Numbering instance '${requested.numId}' was not found in word/numbering.xml.`);
|
|
69
|
+
}
|
|
70
|
+
const abstract = model.abstractNums.get(instance.abstractNumId);
|
|
71
|
+
if (!abstract) {
|
|
72
|
+
throw new ParagraphNumberingMutationError('ABSTRACT_NUMBERING_NOT_FOUND', `Numbering instance '${requested.numId}' references missing abstract numbering '${instance.abstractNumId}'.`);
|
|
73
|
+
}
|
|
74
|
+
if (!abstract.levels.has(requested.ilvl)) {
|
|
75
|
+
throw new ParagraphNumberingMutationError('NUMBERING_LEVEL_NOT_FOUND', `Numbering instance '${requested.numId}' has no level ${requested.ilvl}.`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function ensureParagraphProperties(paragraph) {
|
|
79
|
+
const existing = getDirectChildrenByName(paragraph, W.pPr)[0];
|
|
80
|
+
if (existing)
|
|
81
|
+
return existing;
|
|
82
|
+
const pPr = paragraph.ownerDocument.createElementNS(OOXML.W_NS, `w:${W.pPr}`);
|
|
83
|
+
paragraph.insertBefore(pPr, paragraph.firstChild);
|
|
84
|
+
return pPr;
|
|
85
|
+
}
|
|
86
|
+
function insertNumPrInSchemaOrder(pPr, numPr) {
|
|
87
|
+
const successors = new Set([
|
|
88
|
+
'suppressLineNumbers',
|
|
89
|
+
'pBdr',
|
|
90
|
+
'shd',
|
|
91
|
+
'tabs',
|
|
92
|
+
'suppressAutoHyphens',
|
|
93
|
+
'kinsoku',
|
|
94
|
+
'wordWrap',
|
|
95
|
+
'overflowPunct',
|
|
96
|
+
'topLinePunct',
|
|
97
|
+
'autoSpaceDE',
|
|
98
|
+
'autoSpaceDN',
|
|
99
|
+
'bidi',
|
|
100
|
+
'adjustRightInd',
|
|
101
|
+
'snapToGrid',
|
|
102
|
+
W.spacing,
|
|
103
|
+
W.ind,
|
|
104
|
+
'contextualSpacing',
|
|
105
|
+
'mirrorIndents',
|
|
106
|
+
'suppressOverlap',
|
|
107
|
+
W.jc,
|
|
108
|
+
'textDirection',
|
|
109
|
+
'textAlignment',
|
|
110
|
+
'textboxTightWrap',
|
|
111
|
+
'outlineLvl',
|
|
112
|
+
'divId',
|
|
113
|
+
'cnfStyle',
|
|
114
|
+
W.rPr,
|
|
115
|
+
W.sectPr,
|
|
116
|
+
'pPrChange',
|
|
117
|
+
]);
|
|
118
|
+
const successor = Array.from(pPr.children)
|
|
119
|
+
.find((child) => successors.has(child.localName));
|
|
120
|
+
if (successor)
|
|
121
|
+
pPr.insertBefore(numPr, successor);
|
|
122
|
+
else
|
|
123
|
+
pPr.appendChild(numPr);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Mutate one paragraph's direct list reference while preserving the numbering
|
|
127
|
+
* definitions and unrelated paragraph properties.
|
|
128
|
+
*
|
|
129
|
+
* @conformance ECMA-376 edition 5, Part 1 § 17.3.1.19
|
|
130
|
+
* @conformance ECMA-376 edition 5, Part 1 § 17.9.18
|
|
131
|
+
* @conformance ECMA-376 edition 5, Part 1 § 17.9.3
|
|
132
|
+
* @see #653
|
|
133
|
+
*/
|
|
134
|
+
export function setDirectParagraphNumbering(documentDoc, numberingDoc, mutation, ctx) {
|
|
135
|
+
const paragraph = findParagraphByBookmarkId(documentDoc, mutation.paragraphId);
|
|
136
|
+
if (!paragraph) {
|
|
137
|
+
throw new ParagraphNumberingMutationError('PARAGRAPH_NOT_FOUND', `Paragraph '${mutation.paragraphId}' was not found.`);
|
|
138
|
+
}
|
|
139
|
+
if (mutation.numbering) {
|
|
140
|
+
validateRequestedNumbering(numberingDoc, mutation.numbering);
|
|
141
|
+
}
|
|
142
|
+
const parsedPrevious = parseDirectNumberingFromParagraph(paragraph);
|
|
143
|
+
const existingPPr = getDirectChildrenByName(paragraph, W.pPr)[0] ?? null;
|
|
144
|
+
const existingNumPrs = existingPPr
|
|
145
|
+
? getDirectChildrenByName(existingPPr, W.numPr)
|
|
146
|
+
: [];
|
|
147
|
+
if (!mutation.numbering && existingNumPrs.length === 0) {
|
|
148
|
+
return {
|
|
149
|
+
paragraphId: mutation.paragraphId,
|
|
150
|
+
changed: false,
|
|
151
|
+
previous: null,
|
|
152
|
+
current: null,
|
|
153
|
+
warning: 'The paragraph has no direct w:numPr; style-inherited numbering was not changed.',
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
if (mutation.numbering
|
|
157
|
+
&& parsedPrevious.complete
|
|
158
|
+
&& parsedPrevious.value?.numId === mutation.numbering.numId
|
|
159
|
+
&& parsedPrevious.value.ilvl === mutation.numbering.ilvl
|
|
160
|
+
&& existingNumPrs.length === 1) {
|
|
161
|
+
return {
|
|
162
|
+
paragraphId: mutation.paragraphId,
|
|
163
|
+
changed: false,
|
|
164
|
+
previous: parsedPrevious.value,
|
|
165
|
+
current: parsedPrevious.value,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
const oldPPr = existingPPr ? existingPPr.cloneNode(true) : null;
|
|
169
|
+
const pPr = mutation.numbering
|
|
170
|
+
? ensureParagraphProperties(paragraph)
|
|
171
|
+
: existingPPr;
|
|
172
|
+
for (const stale of getDirectChildrenByName(pPr, W.numPr)) {
|
|
173
|
+
pPr.removeChild(stale);
|
|
174
|
+
}
|
|
175
|
+
if (mutation.numbering) {
|
|
176
|
+
const numPr = documentDoc.createElementNS(OOXML.W_NS, `w:${W.numPr}`);
|
|
177
|
+
const ilvl = documentDoc.createElementNS(OOXML.W_NS, `w:${W.ilvl}`);
|
|
178
|
+
ilvl.setAttributeNS(OOXML.W_NS, `w:${W.val}`, String(mutation.numbering.ilvl));
|
|
179
|
+
const numId = documentDoc.createElementNS(OOXML.W_NS, `w:${W.numId}`);
|
|
180
|
+
numId.setAttributeNS(OOXML.W_NS, `w:${W.val}`, mutation.numbering.numId);
|
|
181
|
+
numPr.appendChild(ilvl);
|
|
182
|
+
numPr.appendChild(numId);
|
|
183
|
+
insertNumPrInSchemaOrder(pPr, numPr);
|
|
184
|
+
}
|
|
185
|
+
if (ctx) {
|
|
186
|
+
for (const stale of getDirectChildrenByName(pPr, 'pPrChange')) {
|
|
187
|
+
pPr.removeChild(stale);
|
|
188
|
+
}
|
|
189
|
+
pPr.appendChild(buildPPrChangeElement(oldPPr, ctx));
|
|
190
|
+
}
|
|
191
|
+
return {
|
|
192
|
+
paragraphId: mutation.paragraphId,
|
|
193
|
+
changed: true,
|
|
194
|
+
previous: parsedPrevious.complete ? parsedPrevious.value : null,
|
|
195
|
+
current: mutation.numbering,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
//# sourceMappingURL=paragraph_numbering.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paragraph_numbering.js","sourceRoot":"","sources":["../../src/primitives/paragraph_numbering.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAC3D,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EACL,qBAAqB,GAEtB,MAAM,4BAA4B,CAAC;AA6BpC,MAAM,OAAO,+BAAgC,SAAQ,KAAK;IAEtC;IADlB,YACkB,IAAyC,EACzD,OAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAC;QAHC,SAAI,GAAJ,IAAI,CAAqC;QAIzD,IAAI,CAAC,IAAI,GAAG,iCAAiC,CAAC;IAChD,CAAC;CACF;AAED,SAAS,QAAQ,CAAC,EAAW,EAAE,SAAiB;IAC9C,OAAO,EAAE,CAAC,cAAc,CAAC,KAAK,CAAC,IAAI,EAAE,SAAS,CAAC;WAC1C,EAAE,CAAC,YAAY,CAAC,KAAK,SAAS,EAAE,CAAC;WACjC,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC;WAC1B,IAAI,CAAC;AACZ,CAAC;AAED,SAAS,iCAAiC,CACxC,SAAkB;IAElB,MAAM,GAAG,GAAG,uBAAuB,CAAC,SAAS,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;IACjE,MAAM,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,uBAAuB,CAAC,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IAC5E,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAEnD,MAAM,OAAO,GAAG,uBAAuB,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;IACnE,MAAM,MAAM,GAAG,uBAAuB,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;IACjE,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACxD,MAAM,QAAQ,GAAG,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACzD,MAAM,IAAI,GAAG,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;IAE/D,IACE,KAAK,KAAK,IAAI;WACX,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC;WACzB,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC;WAC3B,IAAI,GAAG,CAAC,EACX,CAAC;QACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IAC1C,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AACpD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,2BAA2B,CACzC,GAAa,EACb,WAAmB;IAEnB,MAAM,SAAS,GAAG,yBAAyB,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IAC9D,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,+BAA+B,CACvC,qBAAqB,EACrB,cAAc,WAAW,kBAAkB,CAC5C,CAAC;IACJ,CAAC;IACD,MAAM,MAAM,GAAG,iCAAiC,CAAC,SAAS,CAAC,CAAC;IAC5D,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;QACrB,MAAM,IAAI,+BAA+B,CACvC,sBAAsB,EACtB,cAAc,WAAW,gDAAgD,CAC1E,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC,KAAK,CAAC;AACtB,CAAC;AAED,SAAS,0BAA0B,CACjC,YAA6B,EAC7B,SAAmC;IAEnC,IACE,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;WAChC,CAAC,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,IAAI,CAAC;WACrC,SAAS,CAAC,IAAI,GAAG,CAAC,EACrB,CAAC;QACD,MAAM,IAAI,+BAA+B,CACvC,6BAA6B,EAC7B,uFAAuF,CACxF,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,MAAM,IAAI,+BAA+B,CACvC,wBAAwB,EACxB,8CAA8C,CAC/C,CAAC;IACJ,CAAC;IAED,MAAM,KAAK,GAAG,iBAAiB,CAAC,YAAY,CAAC,CAAC;IAC9C,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACjD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,+BAA+B,CACvC,8BAA8B,EAC9B,uBAAuB,SAAS,CAAC,KAAK,wCAAwC,CAC/E,CAAC;IACJ,CAAC;IACD,MAAM,QAAQ,GAAG,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;IAChE,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,+BAA+B,CACvC,8BAA8B,EAC9B,uBAAuB,SAAS,CAAC,KAAK,4CAA4C,QAAQ,CAAC,aAAa,IAAI,CAC7G,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;QACzC,MAAM,IAAI,+BAA+B,CACvC,2BAA2B,EAC3B,uBAAuB,SAAS,CAAC,KAAK,kBAAkB,SAAS,CAAC,IAAI,GAAG,CAC1E,CAAC;IACJ,CAAC;AACH,CAAC;AAED,SAAS,yBAAyB,CAAC,SAAkB;IACnD,MAAM,QAAQ,GAAG,uBAAuB,CAAC,SAAS,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9D,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC9B,MAAM,GAAG,GAAG,SAAS,CAAC,aAAc,CAAC,eAAe,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;IAC/E,SAAS,CAAC,YAAY,CAAC,GAAG,EAAE,SAAS,CAAC,UAAU,CAAC,CAAC;IAClD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,wBAAwB,CAAC,GAAY,EAAE,KAAc;IAC5D,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC;QACzB,qBAAqB;QACrB,MAAM;QACN,KAAK;QACL,MAAM;QACN,qBAAqB;QACrB,SAAS;QACT,UAAU;QACV,eAAe;QACf,cAAc;QACd,aAAa;QACb,aAAa;QACb,MAAM;QACN,gBAAgB;QAChB,YAAY;QACZ,CAAC,CAAC,OAAO;QACT,CAAC,CAAC,GAAG;QACL,mBAAmB;QACnB,eAAe;QACf,iBAAiB;QACjB,CAAC,CAAC,EAAE;QACJ,eAAe;QACf,eAAe;QACf,kBAAkB;QAClB,YAAY;QACZ,OAAO;QACP,UAAU;QACV,CAAC,CAAC,GAAG;QACL,CAAC,CAAC,MAAM;QACR,WAAW;KACZ,CAAC,CAAC;IACH,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC;SACvC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,CAAE,KAAiB,CAAC,SAAS,CAAC,CAAC,CAAC;IACjE,IAAI,SAAS;QAAE,GAAG,CAAC,YAAY,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;;QAC7C,GAAG,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;AAC9B,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,2BAA2B,CACzC,WAAqB,EACrB,YAA6B,EAC7B,QAAoC,EACpC,GAAqB;IAErB,MAAM,SAAS,GAAG,yBAAyB,CAAC,WAAW,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC;IAC/E,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,+BAA+B,CACvC,qBAAqB,EACrB,cAAc,QAAQ,CAAC,WAAW,kBAAkB,CACrD,CAAC;IACJ,CAAC;IAED,IAAI,QAAQ,CAAC,SAAS,EAAE,CAAC;QACvB,0BAA0B,CAAC,YAAY,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC;IAC/D,CAAC;IAED,MAAM,cAAc,GAAG,iCAAiC,CAAC,SAAS,CAAC,CAAC;IACpE,MAAM,WAAW,GAAG,uBAAuB,CAAC,SAAS,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;IACzE,MAAM,cAAc,GAAG,WAAW;QAChC,CAAC,CAAC,uBAAuB,CAAC,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC;QAC/C,CAAC,CAAC,EAAE,CAAC;IAEP,IAAI,CAAC,QAAQ,CAAC,SAAS,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvD,OAAO;YACL,WAAW,EAAE,QAAQ,CAAC,WAAW;YACjC,OAAO,EAAE,KAAK;YACd,QAAQ,EAAE,IAAI;YACd,OAAO,EAAE,IAAI;YACb,OAAO,EAAE,iFAAiF;SAC3F,CAAC;IACJ,CAAC;IAED,IACE,QAAQ,CAAC,SAAS;WACf,cAAc,CAAC,QAAQ;WACvB,cAAc,CAAC,KAAK,EAAE,KAAK,KAAK,QAAQ,CAAC,SAAS,CAAC,KAAK;WACxD,cAAc,CAAC,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC,SAAS,CAAC,IAAI;WACrD,cAAc,CAAC,MAAM,KAAK,CAAC,EAC9B,CAAC;QACD,OAAO;YACL,WAAW,EAAE,QAAQ,CAAC,WAAW;YACjC,OAAO,EAAE,KAAK;YACd,QAAQ,EAAE,cAAc,CAAC,KAAK;YAC9B,OAAO,EAAE,cAAc,CAAC,KAAK;SAC9B,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,SAAS,CAAC,IAAI,CAAY,CAAC,CAAC,CAAC,IAAI,CAAC;IAC3E,MAAM,GAAG,GAAG,QAAQ,CAAC,SAAS;QAC5B,CAAC,CAAC,yBAAyB,CAAC,SAAS,CAAC;QACtC,CAAC,CAAC,WAAY,CAAC;IAEjB,KAAK,MAAM,KAAK,IAAI,uBAAuB,CAAC,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1D,GAAG,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IACzB,CAAC;IAED,IAAI,QAAQ,CAAC,SAAS,EAAE,CAAC;QACvB,MAAM,KAAK,GAAG,WAAW,CAAC,eAAe,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;QACtE,MAAM,IAAI,GAAG,WAAW,CAAC,eAAe,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QACpE,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;QAC/E,MAAM,KAAK,GAAG,WAAW,CAAC,eAAe,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;QACtE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,QAAQ,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACzE,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QACxB,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QACzB,wBAAwB,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACvC,CAAC;IAED,IAAI,GAAG,EAAE,CAAC;QACR,KAAK,MAAM,KAAK,IAAI,uBAAuB,CAAC,GAAG,EAAE,WAAW,CAAC,EAAE,CAAC;YAC9D,GAAG,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QACzB,CAAC;QACD,GAAG,CAAC,WAAW,CAAC,qBAAqB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;IACtD,CAAC;IAED,OAAO;QACL,WAAW,EAAE,QAAQ,CAAC,WAAW;QACjC,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI;QAC/D,OAAO,EAAE,QAAQ,CAAC,SAAS;KAC5B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Block-level structural rules shared by the revision resolvers
|
|
3
|
+
* (accept_changes, reject_changes) and the untracked paragraph-blanking path
|
|
4
|
+
* in text.ts. This module is a leaf: it must import nothing but namespaces,
|
|
5
|
+
* because text.ts sits below bookmarks.ts and table_rows.ts in the import
|
|
6
|
+
* graph and the resolvers sit above them (`npm run check:cycles`).
|
|
7
|
+
*
|
|
8
|
+
* @see https://github.com/UseJunior/safe-docx/issues/740
|
|
9
|
+
*/
|
|
10
|
+
export declare const RANGE_MARKUP_BLOCK_SIBLING_LOCALS: ReadonlySet<string>;
|
|
11
|
+
/**
|
|
12
|
+
* True iff removing an emptied paragraph keeps its parent structurally valid
|
|
13
|
+
* for Word: the parent must retain at least one block element, must not end
|
|
14
|
+
* on a w:tbl (a trailing table needs a following paragraph), and two tables
|
|
15
|
+
* must not become adjacent (Word merges back-to-back tables). w:sectPr is
|
|
16
|
+
* ignored — a trailing body sectPr is not a block element.
|
|
17
|
+
*/
|
|
18
|
+
export declare function canSafelyRemoveEmptyParagraph(p: Element): boolean;
|
|
19
|
+
//# sourceMappingURL=paragraph_structure.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paragraph_structure.d.ts","sourceRoot":"","sources":["../../src/primitives/paragraph_structure.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAeH,eAAO,MAAM,iCAAiC,EAAE,WAAW,CAAC,MAAM,CAWhE,CAAC;AAEH;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CA0BjE"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Block-level structural rules shared by the revision resolvers
|
|
3
|
+
* (accept_changes, reject_changes) and the untracked paragraph-blanking path
|
|
4
|
+
* in text.ts. This module is a leaf: it must import nothing but namespaces,
|
|
5
|
+
* because text.ts sits below bookmarks.ts and table_rows.ts in the import
|
|
6
|
+
* graph and the resolvers sit above them (`npm run check:cycles`).
|
|
7
|
+
*
|
|
8
|
+
* @see https://github.com/UseJunior/safe-docx/issues/740
|
|
9
|
+
*/
|
|
10
|
+
import { OOXML } from './namespaces.js';
|
|
11
|
+
const W_NS = OOXML.W_NS;
|
|
12
|
+
function isW(node, localName) {
|
|
13
|
+
return !!node && node.nodeType === 1 && node.namespaceURI === W_NS
|
|
14
|
+
&& node.localName === localName;
|
|
15
|
+
}
|
|
16
|
+
// Marker-ish elements that may sit between two paragraphs at block level
|
|
17
|
+
// without ending the search for a merge target: the full EG_RangeMarkupElements
|
|
18
|
+
// schema group (wml.xsd), plus permStart/permEnd range markers and proofErr
|
|
19
|
+
// proofing anchors.
|
|
20
|
+
export const RANGE_MARKUP_BLOCK_SIBLING_LOCALS = new Set([
|
|
21
|
+
'bookmarkStart', 'bookmarkEnd',
|
|
22
|
+
'commentRangeStart', 'commentRangeEnd',
|
|
23
|
+
'moveFromRangeStart', 'moveFromRangeEnd',
|
|
24
|
+
'moveToRangeStart', 'moveToRangeEnd',
|
|
25
|
+
'customXmlInsRangeStart', 'customXmlInsRangeEnd',
|
|
26
|
+
'customXmlDelRangeStart', 'customXmlDelRangeEnd',
|
|
27
|
+
'customXmlMoveFromRangeStart', 'customXmlMoveFromRangeEnd',
|
|
28
|
+
'customXmlMoveToRangeStart', 'customXmlMoveToRangeEnd',
|
|
29
|
+
'permStart', 'permEnd',
|
|
30
|
+
'proofErr',
|
|
31
|
+
]);
|
|
32
|
+
/**
|
|
33
|
+
* True iff removing an emptied paragraph keeps its parent structurally valid
|
|
34
|
+
* for Word: the parent must retain at least one block element, must not end
|
|
35
|
+
* on a w:tbl (a trailing table needs a following paragraph), and two tables
|
|
36
|
+
* must not become adjacent (Word merges back-to-back tables). w:sectPr is
|
|
37
|
+
* ignored — a trailing body sectPr is not a block element.
|
|
38
|
+
*/
|
|
39
|
+
export function canSafelyRemoveEmptyParagraph(p) {
|
|
40
|
+
const blockSibling = (start, dir) => {
|
|
41
|
+
let sibling = start;
|
|
42
|
+
while (sibling) {
|
|
43
|
+
if (sibling.nodeType === 1) {
|
|
44
|
+
const el = sibling;
|
|
45
|
+
if ((el.namespaceURI === W_NS && RANGE_MARKUP_BLOCK_SIBLING_LOCALS.has(el.localName ?? '')) ||
|
|
46
|
+
isW(el, 'sectPr')) {
|
|
47
|
+
sibling = sibling[dir];
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
return el;
|
|
51
|
+
}
|
|
52
|
+
sibling = sibling[dir];
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
};
|
|
56
|
+
const prev = blockSibling(p.previousSibling, 'previousSibling');
|
|
57
|
+
const next = blockSibling(p.nextSibling, 'nextSibling');
|
|
58
|
+
if (!prev && !next)
|
|
59
|
+
return false;
|
|
60
|
+
if (prev && isW(prev, 'tbl') && !next)
|
|
61
|
+
return false;
|
|
62
|
+
if (prev && next && isW(prev, 'tbl') && isW(next, 'tbl'))
|
|
63
|
+
return false;
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=paragraph_structure.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paragraph_structure.js","sourceRoot":"","sources":["../../src/primitives/paragraph_structure.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAExC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;AAExB,SAAS,GAAG,CAAC,IAAiB,EAAE,SAAiB;IAC/C,OAAO,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,QAAQ,KAAK,CAAC,IAAK,IAAgB,CAAC,YAAY,KAAK,IAAI;WACzE,IAAgB,CAAC,SAAS,KAAK,SAAS,CAAC;AACjD,CAAC;AAED,yEAAyE;AACzE,gFAAgF;AAChF,4EAA4E;AAC5E,oBAAoB;AACpB,MAAM,CAAC,MAAM,iCAAiC,GAAwB,IAAI,GAAG,CAAC;IAC5E,eAAe,EAAE,aAAa;IAC9B,mBAAmB,EAAE,iBAAiB;IACtC,oBAAoB,EAAE,kBAAkB;IACxC,kBAAkB,EAAE,gBAAgB;IACpC,wBAAwB,EAAE,sBAAsB;IAChD,wBAAwB,EAAE,sBAAsB;IAChD,6BAA6B,EAAE,2BAA2B;IAC1D,2BAA2B,EAAE,yBAAyB;IACtD,WAAW,EAAE,SAAS;IACtB,UAAU;CACX,CAAC,CAAC;AAEH;;;;;;GAMG;AACH,MAAM,UAAU,6BAA6B,CAAC,CAAU;IACtD,MAAM,YAAY,GAAG,CAAC,KAAkB,EAAE,GAAsC,EAAkB,EAAE;QAClG,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,OAAO,OAAO,EAAE,CAAC;YACf,IAAI,OAAO,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;gBAC3B,MAAM,EAAE,GAAG,OAAkB,CAAC;gBAC9B,IACE,CAAC,EAAE,CAAC,YAAY,KAAK,IAAI,IAAI,iCAAiC,CAAC,GAAG,CAAC,EAAE,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;oBACvF,GAAG,CAAC,EAAE,EAAE,QAAQ,CAAC,EACjB,CAAC;oBACD,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;oBACvB,SAAS;gBACX,CAAC;gBACD,OAAO,EAAE,CAAC;YACZ,CAAC;YACD,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QACzB,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;IAEF,MAAM,IAAI,GAAG,YAAY,CAAC,CAAC,CAAC,eAAe,EAAE,iBAAiB,CAAC,CAAC;IAChE,MAAM,IAAI,GAAG,YAAY,CAAC,CAAC,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;IACxD,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IACjC,IAAI,IAAI,IAAI,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IACpD,IAAI,IAAI,IAAI,IAAI,IAAI,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACvE,OAAO,IAAI,CAAC;AACd,CAAC"}
|