@portone/docx-editor 0.2.0 → 0.3.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.
- package/CHANGELOG.md +174 -0
- package/CONTRIBUTING.md +9 -1
- package/dist/DocxEditor.d.ts +6 -0
- package/dist/DocxEditor.js +12 -29
- package/dist/core.d.ts +23 -8
- package/dist/core.js +9 -4
- package/dist/docx/cloning.d.ts +38 -0
- package/dist/docx/cloning.js +74 -0
- package/dist/docx/commentOnlyChange.d.ts +14 -7
- package/dist/docx/commentOnlyChange.js +9 -139
- package/dist/docx/comments/constants.d.ts +3 -4
- package/dist/docx/comments/constants.js +4 -5
- package/dist/docx/comments/grammar.d.ts +86 -0
- package/dist/docx/comments/grammar.js +223 -0
- package/dist/docx/comments/parts.d.ts +52 -0
- package/dist/docx/comments/parts.js +279 -0
- package/dist/docx/comments/people.d.ts +11 -2
- package/dist/docx/comments/people.js +28 -106
- package/dist/docx/comments/policy.d.ts +7 -0
- package/dist/docx/comments/policy.js +43 -0
- package/dist/docx/comments/reading.d.ts +5 -3
- package/dist/docx/comments/reading.js +30 -29
- package/dist/docx/comments/writing.d.ts +19 -7
- package/dist/docx/comments/writing.js +105 -137
- package/dist/docx/documentSettings.d.ts +7 -0
- package/dist/docx/documentSettings.js +10 -2
- package/dist/docx/exportDocx.d.ts +40 -5
- package/dist/docx/exportDocx.js +71 -72
- package/dist/docx/exportRefs.d.ts +5 -2
- package/dist/docx/exportRefs.js +3 -1
- package/dist/docx/fidelity.d.ts +43 -0
- package/dist/docx/fidelity.js +64 -0
- package/dist/docx/formatting/attrs.d.ts +27 -0
- package/dist/docx/formatting/attrs.js +31 -0
- package/dist/docx/formatting/context.d.ts +31 -0
- package/dist/docx/formatting/context.js +42 -0
- package/dist/docx/formatting/direct.d.ts +6 -5
- package/dist/docx/formatting/direct.js +52 -81
- package/dist/docx/formatting/resolve.d.ts +45 -0
- package/dist/docx/formatting/resolve.js +140 -0
- package/dist/docx/formatting/runProperties.d.ts +93 -0
- package/dist/docx/formatting/runProperties.js +316 -0
- package/dist/docx/formatting/styles.js +3 -3
- package/dist/docx/formatting/tabStops.js +7 -22
- package/dist/docx/formatting.d.ts +4 -1
- package/dist/docx/formatting.js +4 -1
- package/dist/docx/headersFooters.js +13 -22
- package/dist/docx/identities.d.ts +67 -0
- package/dist/docx/identities.js +174 -0
- package/dist/docx/importDocx.d.ts +12 -1
- package/dist/docx/importDocx.js +72 -79
- package/dist/docx/importParagraph.d.ts +1 -1
- package/dist/docx/importParagraph.js +4 -3
- package/dist/docx/importTable.d.ts +1 -1
- package/dist/docx/importTable.js +17 -1
- package/dist/docx/invariants.d.ts +33 -0
- package/dist/docx/invariants.js +256 -0
- package/dist/docx/media.d.ts +6 -4
- package/dist/docx/media.js +6 -37
- package/dist/docx/newLists.d.ts +20 -0
- package/dist/docx/newLists.js +36 -0
- package/dist/docx/notes.js +6 -12
- package/dist/docx/numberingPlanner.d.ts +8 -0
- package/dist/docx/numberingPlanner.js +19 -0
- package/dist/docx/packageParts.d.ts +42 -0
- package/dist/docx/packageParts.js +135 -0
- package/dist/docx/pageGeometry.d.ts +2 -0
- package/dist/docx/pageGeometry.js +18 -9
- package/dist/docx/paraProps.d.ts +10 -22
- package/dist/docx/paraProps.js +75 -99
- package/dist/docx/partPlan.d.ts +36 -0
- package/dist/docx/partPlan.js +59 -0
- package/dist/docx/protectionPolicy.d.ts +127 -0
- package/dist/docx/protectionPolicy.js +169 -0
- package/dist/docx/relationships.d.ts +1 -1
- package/dist/docx/relationships.js +15 -15
- package/dist/docx/runProps.d.ts +9 -22
- package/dist/docx/runProps.js +15 -168
- package/dist/docx/scan.js +20 -52
- package/dist/docx/sdt.js +14 -37
- package/dist/docx/sdtProps.d.ts +8 -1
- package/dist/docx/sdtProps.js +10 -0
- package/dist/docx/serializeBlock.d.ts +2 -0
- package/dist/docx/serializeBlock.js +9 -7
- package/dist/docx/serializeParagraph.d.ts +2 -1
- package/dist/docx/serializeParagraph.js +25 -14
- package/dist/docx/serializeTable.js +63 -32
- package/dist/docx/session.d.ts +42 -14
- package/dist/docx/session.js +43 -17
- package/dist/docx/storyProjection.d.ts +36 -0
- package/dist/docx/storyProjection.js +23 -0
- package/dist/docx/tableFormatting/editing.js +130 -185
- package/dist/docx/tableFormatting/reading.d.ts +16 -6
- package/dist/docx/tableFormatting/reading.js +40 -20
- package/dist/docx/tableTemplate.js +37 -5
- package/dist/docx/theme.d.ts +0 -6
- package/dist/docx/theme.js +0 -8
- package/dist/download.d.ts +8 -5
- package/dist/download.js +2 -0
- package/dist/editor/clipboard/images.js +17 -3
- package/dist/editor/clipboard/inlineFormatting.d.ts +7 -0
- package/dist/editor/clipboard/inlineFormatting.js +20 -30
- package/dist/editor/commands/breakCommands.js +4 -3
- package/dist/editor/commands/canRunCommand.d.ts +2 -2
- package/dist/editor/commands/canRunCommand.js +1 -1
- package/dist/editor/commands/comments/editing.d.ts +6 -2
- package/dist/editor/commands/comments/editing.js +21 -36
- package/dist/editor/commands/exportQueries.d.ts +15 -0
- package/dist/editor/commands/exportQueries.js +14 -0
- package/dist/editor/commands/fidelityQueries.d.ts +12 -0
- package/dist/editor/commands/fidelityQueries.js +8 -0
- package/dist/editor/commands/formatting/editing.d.ts +2 -2
- package/dist/editor/commands/formatting/editing.js +26 -108
- package/dist/editor/commands/formatting/propertyCommands.d.ts +21 -0
- package/dist/editor/commands/formatting/propertyCommands.js +103 -0
- package/dist/editor/commands/formatting/shared.d.ts +3 -3
- package/dist/editor/commands/formatting/shared.js +5 -2
- package/dist/editor/commands/historyCommands.js +2 -1
- package/dist/editor/commands/indentCommands.js +5 -4
- package/dist/editor/commands/index.d.ts +11 -0
- package/dist/editor/commands/index.js +5 -0
- package/dist/editor/commands/linkCommands.js +5 -6
- package/dist/editor/commands/listCommands.js +8 -10
- package/dist/editor/commands/lockCommands.d.ts +7 -1
- package/dist/editor/commands/lockCommands.js +35 -37
- package/dist/editor/commands/paragraphCommands.js +28 -31
- package/dist/editor/commands/spacingCommands.js +1 -1
- package/dist/editor/commands/tabCommands.js +4 -3
- package/dist/editor/createEditor.d.ts +17 -29
- package/dist/editor/createEditor.js +61 -67
- package/dist/editor/documentStyles.d.ts +11 -35
- package/dist/editor/documentStyles.js +9 -52
- package/dist/editor/editorDocument.d.ts +56 -0
- package/dist/editor/editorDocument.js +74 -0
- package/dist/editor/externalClipboard.js +166 -33
- package/dist/editor/insertImage.js +4 -3
- package/dist/editor/insertTable.js +4 -3
- package/dist/editor/paragraphEdits.d.ts +11 -18
- package/dist/editor/paragraphEdits.js +7 -16
- package/dist/editor/plugins/displayDerivation.d.ts +47 -0
- package/dist/editor/plugins/displayDerivation.js +78 -0
- package/dist/editor/plugins/documentProtection.d.ts +3 -3
- package/dist/editor/plugins/imagePaste.js +4 -3
- package/dist/editor/plugins/keymap.js +18 -3
- package/dist/editor/plugins/lockedContent.d.ts +4 -4
- package/dist/editor/plugins/lockedContent.js +1 -1
- package/dist/editor/plugins/numberingDecorations.d.ts +5 -11
- package/dist/editor/plugins/numberingDecorations.js +7 -17
- package/dist/editor/plugins/paragraphDisplay.d.ts +7 -0
- package/dist/editor/plugins/paragraphDisplay.js +51 -0
- package/dist/editor/plugins/tabLayout.js +1 -1
- package/dist/editor/plugins/tableDisplay.d.ts +6 -0
- package/dist/editor/plugins/tableDisplay.js +16 -0
- package/dist/index.d.ts +2 -0
- package/dist/model/format.d.ts +30 -8
- package/dist/model/format.js +35 -22
- package/dist/model/tabStops.d.ts +9 -0
- package/dist/model/tabStops.js +18 -0
- package/dist/numbering/listTemplate.js +49 -10
- package/dist/numbering/parseNumbering.d.ts +14 -1
- package/dist/numbering/parseNumbering.js +35 -22
- package/dist/numbering/writeNumbering.d.ts +3 -4
- package/dist/numbering/writeNumbering.js +14 -25
- package/dist/ooxml/childOrder.d.ts +34 -0
- package/dist/ooxml/childOrder.js +496 -0
- package/dist/ooxml/element.d.ts +65 -0
- package/dist/ooxml/element.js +68 -0
- package/dist/ooxml/errors.d.ts +3 -2
- package/dist/ooxml/fragment.d.ts +53 -0
- package/dist/ooxml/fragment.js +76 -0
- package/dist/ooxml/image.d.ts +4 -0
- package/dist/ooxml/image.js +3 -5
- package/dist/ooxml/names.d.ts +27 -0
- package/dist/ooxml/names.js +29 -0
- package/dist/ooxml/partSplice.d.ts +67 -0
- package/dist/ooxml/partSplice.js +169 -0
- package/dist/ooxml/precedence.d.ts +31 -0
- package/dist/ooxml/precedence.js +51 -0
- package/dist/ooxml/props.d.ts +112 -0
- package/dist/ooxml/props.js +214 -0
- package/dist/ooxml/simpleTypes.d.ts +103 -0
- package/dist/ooxml/simpleTypes.js +182 -0
- package/dist/ooxml/tabStops.js +8 -27
- package/dist/ooxml/tagScan.d.ts +34 -0
- package/dist/ooxml/tagScan.js +108 -0
- package/dist/ooxml/units.d.ts +25 -13
- package/dist/ooxml/units.js +65 -31
- package/dist/ooxml/xml.d.ts +52 -0
- package/dist/ooxml/xml.js +64 -5
- package/dist/page/blockKinds.d.ts +103 -0
- package/dist/page/blockKinds.js +11 -0
- package/dist/page/kinds/index.d.ts +6 -0
- package/dist/page/kinds/index.js +10 -0
- package/dist/page/kinds/paragraphKind.d.ts +10 -0
- package/dist/page/kinds/paragraphKind.js +71 -0
- package/dist/page/kinds/tableKind.d.ts +10 -0
- package/dist/page/kinds/tableKind.js +178 -0
- package/dist/page/measureBlocks.d.ts +3 -1
- package/dist/page/measureBlocks.js +24 -25
- package/dist/page/pageDecorations.d.ts +27 -28
- package/dist/page/pageDecorations.js +70 -151
- package/dist/page/pageLayout.d.ts +10 -62
- package/dist/page/pageLayout.js +60 -53
- package/dist/page/usePageLayout.d.ts +2 -2
- package/dist/page/usePageLayout.js +3 -11
- package/dist/schema/attrRoles.d.ts +42 -0
- package/dist/schema/attrRoles.js +141 -0
- package/dist/schema/displayDerivation.d.ts +82 -0
- package/dist/schema/displayDerivation.js +130 -0
- package/dist/schema/docxSchema.d.ts +9 -0
- package/dist/schema/docxSchema.js +237 -114
- package/dist/schema/editGuard.d.ts +99 -0
- package/dist/schema/editGuard.js +43 -0
- package/dist/schema/guards.d.ts +91 -0
- package/dist/schema/guards.js +108 -0
- package/dist/schema/index.d.ts +2 -0
- package/dist/schema/index.js +2 -0
- package/dist/schema/locks.d.ts +17 -77
- package/dist/schema/locks.js +26 -70
- package/dist/schema/preservedGuards.d.ts +50 -0
- package/dist/schema/preservedGuards.js +80 -0
- package/dist/schema/protection.d.ts +17 -4
- package/dist/schema/protection.js +4 -2
- package/dist/schema/sourceEquality.d.ts +19 -0
- package/dist/schema/sourceEquality.js +39 -0
- package/dist/styles/inlineStyle.js +15 -6
- package/dist/table/cellFormatting.d.ts +8 -1
- package/dist/table/cellFormatting.js +10 -17
- package/dist/table/commands.d.ts +2 -2
- package/dist/table/commands.js +20 -18
- package/dist/table/format.d.ts +3 -0
- package/dist/table/format.js +3 -9
- package/dist/table/gridBorders.d.ts +14 -16
- package/dist/table/gridBorders.js +3 -41
- package/dist/table/index.d.ts +2 -2
- package/dist/table/merge.d.ts +4 -8
- package/dist/table/merge.js +5 -5
- package/package.json +10 -3
- package/dist/docx/comments/contentTypes.d.ts +0 -7
- package/dist/docx/comments/contentTypes.js +0 -38
- package/dist/docx/formatting/effectiveParagraph.d.ts +0 -15
- package/dist/docx/formatting/effectiveParagraph.js +0 -81
- package/dist/docx/propsXml.d.ts +0 -49
- package/dist/docx/propsXml.js +0 -302
- package/dist/docx/uniqueControls.d.ts +0 -14
- package/dist/docx/uniqueControls.js +0 -62
- package/dist/editor/plugins/bookmarkProtection.d.ts +0 -3
- package/dist/editor/plugins/bookmarkProtection.js +0 -28
- package/dist/editor/plugins/commentReservations.d.ts +0 -5
- package/dist/editor/plugins/commentReservations.js +0 -26
- package/dist/editor/plugins/noteProtection.d.ts +0 -3
- package/dist/editor/plugins/noteProtection.js +0 -25
- package/dist/editor/plugins/styledParagraphs.d.ts +0 -15
- package/dist/editor/plugins/styledParagraphs.js +0 -65
- package/dist/page/tableMeasurements.d.ts +0 -10
- package/dist/page/tableMeasurements.js +0 -115
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
// src/docx/invariants.ts
|
|
2
|
+
import { spanCount } from "../model/format.js";
|
|
3
|
+
import {
|
|
4
|
+
attributeByLocalName,
|
|
5
|
+
parseXml,
|
|
6
|
+
W_NS,
|
|
7
|
+
withXmlParser
|
|
8
|
+
} from "../ooxml/xml.js";
|
|
9
|
+
import {
|
|
10
|
+
commentReferencesIn,
|
|
11
|
+
commentsChanged,
|
|
12
|
+
commentsRootProblem,
|
|
13
|
+
extensionsChanged,
|
|
14
|
+
extensionsRootProblem
|
|
15
|
+
} from "./comments.js";
|
|
16
|
+
import {
|
|
17
|
+
commentsExtendedPart,
|
|
18
|
+
commentsPart,
|
|
19
|
+
peoplePart
|
|
20
|
+
} from "./comments/parts.js";
|
|
21
|
+
import { unrecordedAuthors } from "./comments/people.js";
|
|
22
|
+
import { currentCommentBodies } from "./comments/writing.js";
|
|
23
|
+
import { identityProblems } from "./identities.js";
|
|
24
|
+
import { insertedImageSrcs } from "./media.js";
|
|
25
|
+
import { newNumIds, numberingPartOf } from "./newLists.js";
|
|
26
|
+
import { CONTENT_TYPES_PATH } from "./packageParts.js";
|
|
27
|
+
import { lostOriginal } from "./serializeBlock.js";
|
|
28
|
+
import {
|
|
29
|
+
originalBlock,
|
|
30
|
+
sessionOf
|
|
31
|
+
} from "./session.js";
|
|
32
|
+
function markerSourceOf(node, session) {
|
|
33
|
+
if (node.type.name === "rawInline" || node.type.name === "rawBlock") {
|
|
34
|
+
return typeof node.attrs.xml === "string" ? node.attrs.xml : null;
|
|
35
|
+
}
|
|
36
|
+
if (node.type.isInGroup("preserved")) {
|
|
37
|
+
return originalBlock(node, session)?.xml ?? null;
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
var bookmarkPairs = {
|
|
42
|
+
name: "bookmarkPairs",
|
|
43
|
+
check(doc, session) {
|
|
44
|
+
const problems = [];
|
|
45
|
+
const open = /* @__PURE__ */ new Map();
|
|
46
|
+
const used = /* @__PURE__ */ new Set();
|
|
47
|
+
doc.descendants((node, pos) => {
|
|
48
|
+
const source = markerSourceOf(node, session);
|
|
49
|
+
if (source === null) return true;
|
|
50
|
+
if (!source.includes("bookmark")) return true;
|
|
51
|
+
let root;
|
|
52
|
+
try {
|
|
53
|
+
root = parseXml(
|
|
54
|
+
session.documentPrefix + source + session.documentSuffix
|
|
55
|
+
).documentElement;
|
|
56
|
+
} catch {
|
|
57
|
+
problems.push({
|
|
58
|
+
code: "malformed-xml",
|
|
59
|
+
message: "preserved bookmark XML could not be parsed",
|
|
60
|
+
pos
|
|
61
|
+
});
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
for (const marker of Array.from(root.getElementsByTagName("*"))) {
|
|
65
|
+
if (marker.namespaceURI !== W_NS || marker.localName !== "bookmarkStart" && marker.localName !== "bookmarkEnd")
|
|
66
|
+
continue;
|
|
67
|
+
const kind = marker.localName.slice("bookmark".length);
|
|
68
|
+
const value = attributeByLocalName(marker, "id");
|
|
69
|
+
if (value === null || value === "") {
|
|
70
|
+
problems.push({
|
|
71
|
+
code: "malformed-xml",
|
|
72
|
+
message: `a bookmark${kind} has no id`,
|
|
73
|
+
pos
|
|
74
|
+
});
|
|
75
|
+
} else if (kind === "Start") {
|
|
76
|
+
if (used.has(value)) {
|
|
77
|
+
problems.push({
|
|
78
|
+
code: "malformed-xml",
|
|
79
|
+
message: `bookmark ${value} has more than one start marker`,
|
|
80
|
+
pos
|
|
81
|
+
});
|
|
82
|
+
} else {
|
|
83
|
+
open.set(value, pos);
|
|
84
|
+
used.add(value);
|
|
85
|
+
}
|
|
86
|
+
} else if (!open.delete(value)) {
|
|
87
|
+
problems.push({
|
|
88
|
+
code: "malformed-xml",
|
|
89
|
+
message: `bookmark ${value} ends without an earlier start marker`,
|
|
90
|
+
pos
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return true;
|
|
95
|
+
});
|
|
96
|
+
for (const [id, pos] of open) {
|
|
97
|
+
problems.push({
|
|
98
|
+
code: "malformed-xml",
|
|
99
|
+
message: `bookmark ${id} has no end marker`,
|
|
100
|
+
pos
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
return problems;
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
function mergeReachesPastLastRow(table) {
|
|
107
|
+
let overlong = false;
|
|
108
|
+
table.forEach((row, _offset, at) => {
|
|
109
|
+
row.forEach((cell) => {
|
|
110
|
+
if (at + spanCount(cell.attrs.rowspan) > table.childCount) {
|
|
111
|
+
overlong = true;
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
return overlong;
|
|
116
|
+
}
|
|
117
|
+
var tableGrids = {
|
|
118
|
+
name: "tableGrids",
|
|
119
|
+
check(doc) {
|
|
120
|
+
const problems = [];
|
|
121
|
+
doc.descendants((node, pos) => {
|
|
122
|
+
if (node.type.name !== "table") return true;
|
|
123
|
+
if (mergeReachesPastLastRow(node)) {
|
|
124
|
+
problems.push({
|
|
125
|
+
code: "invalid-table",
|
|
126
|
+
message: "a vertical merge in the table reaches past the last row",
|
|
127
|
+
pos
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
return true;
|
|
131
|
+
});
|
|
132
|
+
return problems;
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
function lostOriginalOf(node, session) {
|
|
136
|
+
if (node.type.name === "rawInline" || node.type.name === "rawBlock") {
|
|
137
|
+
return typeof node.attrs.xml === "string" ? null : "a preserved element has lost its original XML";
|
|
138
|
+
}
|
|
139
|
+
if (node.type.isInGroup("preserved")) {
|
|
140
|
+
return originalBlock(node, session) ? null : lostOriginal(node, session);
|
|
141
|
+
}
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
var preservedOriginals = {
|
|
145
|
+
name: "preservedOriginals",
|
|
146
|
+
check(doc, session) {
|
|
147
|
+
const problems = [];
|
|
148
|
+
doc.descendants((node, pos) => {
|
|
149
|
+
const message = lostOriginalOf(node, session);
|
|
150
|
+
if (message !== null)
|
|
151
|
+
problems.push({ code: "lost-original", message, pos });
|
|
152
|
+
return true;
|
|
153
|
+
});
|
|
154
|
+
return problems;
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
var uniqueIdentities = {
|
|
158
|
+
name: "uniqueIdentities",
|
|
159
|
+
check(doc) {
|
|
160
|
+
return identityProblems(doc);
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
var numberingPart = {
|
|
164
|
+
name: "numberingPart",
|
|
165
|
+
check(doc, session) {
|
|
166
|
+
if (numberingPartOf(session) !== null) return [];
|
|
167
|
+
if (newNumIds(doc, session).length === 0) return [];
|
|
168
|
+
return [
|
|
169
|
+
{
|
|
170
|
+
code: "missing-numbering-part",
|
|
171
|
+
message: "cannot add a new list to a document that has no numbering.xml"
|
|
172
|
+
}
|
|
173
|
+
];
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
function addsCommentsPart(doc, session) {
|
|
177
|
+
const bodyChanged = commentsChanged(doc, session);
|
|
178
|
+
const threadChanged = extensionsChanged(doc, session);
|
|
179
|
+
if (!bodyChanged && !threadChanged) return false;
|
|
180
|
+
if (commentsPart.pathIn(session) === null || session.comments.xml === null)
|
|
181
|
+
return true;
|
|
182
|
+
const references = commentReferencesIn(doc);
|
|
183
|
+
if (threadChanged && (references.size > 0 || session.comments.extendedPartPath !== null) && (commentsExtendedPart.pathIn(session) === null || session.comments.extendedXml === null))
|
|
184
|
+
return true;
|
|
185
|
+
return bodyChanged && (peoplePart.pathIn(session) === null || session.comments.people.xml === null) && unrecordedAuthors(
|
|
186
|
+
currentCommentBodies(references).values(),
|
|
187
|
+
session.comments.people
|
|
188
|
+
).size > 0;
|
|
189
|
+
}
|
|
190
|
+
var mediaContentTypes = {
|
|
191
|
+
name: "mediaContentTypes",
|
|
192
|
+
check(doc, session) {
|
|
193
|
+
if (session.parts.has(CONTENT_TYPES_PATH)) return [];
|
|
194
|
+
const problems = [];
|
|
195
|
+
if (insertedImageSrcs(doc).length > 0) {
|
|
196
|
+
problems.push({
|
|
197
|
+
code: "missing-content-types",
|
|
198
|
+
message: `cannot add an image to a package that has no ${CONTENT_TYPES_PATH}`
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
if (addsCommentsPart(doc, session)) {
|
|
202
|
+
problems.push({
|
|
203
|
+
code: "missing-content-types",
|
|
204
|
+
message: `cannot add a part to a package that has no ${CONTENT_TYPES_PATH}`
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
return problems;
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
var commentPartRoots = {
|
|
211
|
+
name: "commentPartRoots",
|
|
212
|
+
check(doc, session) {
|
|
213
|
+
const problems = [];
|
|
214
|
+
const { xml, extendedXml, extendedPartPath } = session.comments;
|
|
215
|
+
if (xml !== null && commentsChanged(doc, session)) {
|
|
216
|
+
const problem = commentsRootProblem(xml);
|
|
217
|
+
if (problem !== null)
|
|
218
|
+
problems.push({ code: "malformed-xml", message: problem });
|
|
219
|
+
}
|
|
220
|
+
if (extendedXml !== null && extensionsChanged(doc, session) && (commentReferencesIn(doc).size > 0 || extendedPartPath !== null)) {
|
|
221
|
+
const problem = extensionsRootProblem(extendedXml);
|
|
222
|
+
if (problem !== null)
|
|
223
|
+
problems.push({ code: "malformed-xml", message: problem });
|
|
224
|
+
}
|
|
225
|
+
return problems;
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
var EXPORT_INVARIANTS = [
|
|
229
|
+
bookmarkPairs,
|
|
230
|
+
tableGrids,
|
|
231
|
+
preservedOriginals,
|
|
232
|
+
uniqueIdentities,
|
|
233
|
+
numberingPart,
|
|
234
|
+
mediaContentTypes,
|
|
235
|
+
commentPartRoots
|
|
236
|
+
];
|
|
237
|
+
var answered = /* @__PURE__ */ new WeakMap();
|
|
238
|
+
function problemsOf(doc, session) {
|
|
239
|
+
const known = answered.get(doc);
|
|
240
|
+
if (known && known.session === session) return known.problems;
|
|
241
|
+
const problems = EXPORT_INVARIANTS.flatMap(
|
|
242
|
+
(invariant) => invariant.check(doc, session)
|
|
243
|
+
);
|
|
244
|
+
answered.set(doc, { session, problems });
|
|
245
|
+
return problems;
|
|
246
|
+
}
|
|
247
|
+
function exportProblems(doc, session, options) {
|
|
248
|
+
return withXmlParser(
|
|
249
|
+
options?.xmlParser,
|
|
250
|
+
() => problemsOf(doc, sessionOf(session))
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
export {
|
|
254
|
+
exportProblems,
|
|
255
|
+
problemsOf
|
|
256
|
+
};
|
package/dist/docx/media.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* bytes without blob-URL lifetime management; `MAX_IMAGE_BYTES` bounds the memory tradeoff.
|
|
4
4
|
*/
|
|
5
5
|
import type { Node as PMNode } from "prosemirror-model";
|
|
6
|
-
import {
|
|
6
|
+
import type { PartPlanContext } from "./partPlan";
|
|
7
7
|
import type { SessionStore } from "./session";
|
|
8
8
|
/** The images the body can refer to, as data URLs keyed by relationship id */
|
|
9
9
|
export type ImageSources = ReadonlyMap<string, string>;
|
|
@@ -46,10 +46,12 @@ export interface MediaAdditions {
|
|
|
46
46
|
/** The parts to write into the zip alongside the body */
|
|
47
47
|
parts: ReadonlyMap<string, Uint8Array>;
|
|
48
48
|
}
|
|
49
|
+
/** The srcs of the images that were not in the document when it was opened, in document order */
|
|
50
|
+
export declare function insertedImageSrcs(doc: PMNode): string[];
|
|
49
51
|
/**
|
|
50
52
|
* What the package needs for the images that were inserted during editing: the media parts,
|
|
51
|
-
* the relationships pointing at them
|
|
52
|
-
* null when every image in the document came out of the document itself.
|
|
53
|
+
* with the relationships pointing at them and the content types declaring them asked of the
|
|
54
|
+
* context. null when every image in the document came out of the document itself.
|
|
53
55
|
*
|
|
54
56
|
* The relationships go through the writer the export shares between its writers
|
|
55
57
|
* (`docx/relationships`), so the part is written once with everything in it.
|
|
@@ -57,4 +59,4 @@ export interface MediaAdditions {
|
|
|
57
59
|
* Bytes that are already in the package are not written a second time: an inserted image
|
|
58
60
|
* whose fingerprint matches one that is already there reuses its relationship.
|
|
59
61
|
*/
|
|
60
|
-
export declare function planImageMedia(doc: PMNode, session: SessionStore,
|
|
62
|
+
export declare function planImageMedia(doc: PMNode, session: SessionStore, context: PartPlanContext): MediaAdditions | null;
|
package/dist/docx/media.js
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
imageMimeOf,
|
|
6
6
|
toImageSrc
|
|
7
7
|
} from "../ooxml/image.js";
|
|
8
|
-
import {
|
|
8
|
+
import { R_NS } from "../ooxml/xml.js";
|
|
9
9
|
import {
|
|
10
10
|
directoryOf,
|
|
11
11
|
readRelationships,
|
|
@@ -13,7 +13,6 @@ import {
|
|
|
13
13
|
resolveTarget
|
|
14
14
|
} from "./relationships.js";
|
|
15
15
|
var IMAGE_REL_TYPE = `${R_NS}/image`;
|
|
16
|
-
var CONTENT_TYPES_PATH = "[Content_Types].xml";
|
|
17
16
|
var EXTENSION_BY_MIME = {
|
|
18
17
|
"image/png": "png",
|
|
19
18
|
"image/jpeg": "jpeg",
|
|
@@ -114,6 +113,7 @@ function decodeImage(src) {
|
|
|
114
113
|
const bytes = fromBase64(imageBase64Of(src));
|
|
115
114
|
return {
|
|
116
115
|
bytes,
|
|
116
|
+
mime,
|
|
117
117
|
extension: EXTENSION_BY_MIME[mime],
|
|
118
118
|
key: contentKey(bytes)
|
|
119
119
|
};
|
|
@@ -148,42 +148,14 @@ function maxDocPrId(session) {
|
|
|
148
148
|
}
|
|
149
149
|
return max;
|
|
150
150
|
}
|
|
151
|
-
|
|
152
|
-
function withImageContentTypes(parts, extensions) {
|
|
153
|
-
const original = parts.get(CONTENT_TYPES_PATH);
|
|
154
|
-
if (!original) {
|
|
155
|
-
throw new DocxExportError(
|
|
156
|
-
"missing-content-types",
|
|
157
|
-
`cannot add an image to a package that has no ${CONTENT_TYPES_PATH}`
|
|
158
|
-
);
|
|
159
|
-
}
|
|
160
|
-
const { text, hadBom } = decodeUtf8(original);
|
|
161
|
-
const missing = Array.from(extensions).filter(
|
|
162
|
-
(extension) => !new RegExp(`<Default[^>]+Extension="${extension}"`, "i").test(text)
|
|
163
|
-
);
|
|
164
|
-
if (missing.length === 0) return null;
|
|
165
|
-
const open = TYPES_OPEN_TAG.exec(text);
|
|
166
|
-
if (!open) {
|
|
167
|
-
throw new DocxExportError(
|
|
168
|
-
"malformed-xml",
|
|
169
|
-
`${CONTENT_TYPES_PATH} has no Types element`
|
|
170
|
-
);
|
|
171
|
-
}
|
|
172
|
-
const declarations = missing.map((extension) => {
|
|
173
|
-
const mime = MIME_BY_EXTENSION.get(extension);
|
|
174
|
-
return `<Default Extension="${extension}" ContentType="${mime}"/>`;
|
|
175
|
-
}).join("");
|
|
176
|
-
const at = open.index + open[0].length;
|
|
177
|
-
return encodeUtf8(text.slice(0, at) + declarations + text.slice(at), hadBom);
|
|
178
|
-
}
|
|
179
|
-
function planImageMedia(doc, session, relationships) {
|
|
151
|
+
function planImageMedia(doc, session, context) {
|
|
180
152
|
const srcs = insertedImageSrcs(doc);
|
|
181
153
|
if (srcs.length === 0) return null;
|
|
154
|
+
const { relationships, contentTypes } = context;
|
|
182
155
|
const relIdByContent = imageRelIdsByContent(session, relationships.opened);
|
|
183
156
|
const directory = directoryOf(session.mainPartPath);
|
|
184
157
|
const relIdBySrc = /* @__PURE__ */ new Map();
|
|
185
158
|
const parts = /* @__PURE__ */ new Map();
|
|
186
|
-
const extensions = /* @__PURE__ */ new Set();
|
|
187
159
|
for (const src of srcs) {
|
|
188
160
|
const image = decodeImage(src);
|
|
189
161
|
const reused = relIdByContent.get(image.key);
|
|
@@ -194,20 +166,17 @@ function planImageMedia(doc, session, relationships) {
|
|
|
194
166
|
const target = `media/image-${image.key}.${image.extension}`;
|
|
195
167
|
const relId = relationships.add({ type: IMAGE_REL_TYPE, target });
|
|
196
168
|
parts.set(directory + target, image.bytes);
|
|
197
|
-
|
|
169
|
+
contentTypes.addDefault(image.extension, image.mime);
|
|
198
170
|
relIdByContent.set(image.key, relId);
|
|
199
171
|
relIdBySrc.set(src, relId);
|
|
200
172
|
}
|
|
201
|
-
if (extensions.size > 0) {
|
|
202
|
-
const contentTypes = withImageContentTypes(session.parts, extensions);
|
|
203
|
-
if (contentTypes) parts.set(CONTENT_TYPES_PATH, contentTypes);
|
|
204
|
-
}
|
|
205
173
|
return { refs: imageRefs(relIdBySrc, maxDocPrId(session) + 1), parts };
|
|
206
174
|
}
|
|
207
175
|
export {
|
|
208
176
|
MAX_IMAGE_BYTES,
|
|
209
177
|
NO_IMAGES,
|
|
210
178
|
NO_IMAGE_REFS,
|
|
179
|
+
insertedImageSrcs,
|
|
211
180
|
planImageMedia,
|
|
212
181
|
readImageSources
|
|
213
182
|
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The lists that were started during editing, and the part their definitions are written into.
|
|
3
|
+
*
|
|
4
|
+
* Both the writer and the export invariants ask these questions, so they stand apart from the
|
|
5
|
+
* writer rather than being read off it.
|
|
6
|
+
*/
|
|
7
|
+
import type { Node as PMNode } from "prosemirror-model";
|
|
8
|
+
import type { SessionStore } from "./session";
|
|
9
|
+
/**
|
|
10
|
+
* The numbering ids that appeared during editing and have no definition.
|
|
11
|
+
*
|
|
12
|
+
* An id that was already in use without a definition when the document was opened is left alone,
|
|
13
|
+
* because exporting such a document without editing it must not disturb numbering.xml.
|
|
14
|
+
*/
|
|
15
|
+
export declare function newNumIds(doc: PMNode, session: SessionStore): number[];
|
|
16
|
+
/** The numbering part as it was opened, which a new definition is spliced into. null when the document has none */
|
|
17
|
+
export declare function numberingPartOf(session: SessionStore): {
|
|
18
|
+
path: string;
|
|
19
|
+
bytes: Uint8Array;
|
|
20
|
+
} | null;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// src/docx/newLists.ts
|
|
2
|
+
import { toParagraphFormat } from "../model/format.js";
|
|
3
|
+
import { parseNumbering } from "../numbering/parseNumbering.js";
|
|
4
|
+
function collectNumIds(node, into) {
|
|
5
|
+
const visit = (candidate) => {
|
|
6
|
+
if (candidate.type.name !== "paragraph") return true;
|
|
7
|
+
const numId = toParagraphFormat(candidate.attrs.format)?.numbering?.numId;
|
|
8
|
+
if (numId !== void 0) into.add(numId);
|
|
9
|
+
return false;
|
|
10
|
+
};
|
|
11
|
+
if (visit(node)) node.descendants(visit);
|
|
12
|
+
}
|
|
13
|
+
function numIdsIn(node) {
|
|
14
|
+
const used = /* @__PURE__ */ new Set();
|
|
15
|
+
collectNumIds(node, used);
|
|
16
|
+
return used;
|
|
17
|
+
}
|
|
18
|
+
function numIdsAtOpen(session) {
|
|
19
|
+
const used = /* @__PURE__ */ new Set();
|
|
20
|
+
for (const block of session.blocks) collectNumIds(block.node, used);
|
|
21
|
+
return used;
|
|
22
|
+
}
|
|
23
|
+
function newNumIds(doc, session) {
|
|
24
|
+
const defined = parseNumbering(session.numberingXml).lists;
|
|
25
|
+
const atOpen = numIdsAtOpen(session);
|
|
26
|
+
return Array.from(numIdsIn(doc)).filter((numId) => !defined.has(numId) && !atOpen.has(numId)).sort((a, b) => a - b);
|
|
27
|
+
}
|
|
28
|
+
function numberingPartOf(session) {
|
|
29
|
+
const path = session.numberingPartPath;
|
|
30
|
+
const bytes = path === null ? void 0 : session.parts.get(path);
|
|
31
|
+
return path === null || bytes === void 0 ? null : { path, bytes };
|
|
32
|
+
}
|
|
33
|
+
export {
|
|
34
|
+
newNumIds,
|
|
35
|
+
numberingPartOf
|
|
36
|
+
};
|
package/dist/docx/notes.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
// src/docx/notes.ts
|
|
2
2
|
import {
|
|
3
|
+
attributeByLocalName,
|
|
3
4
|
decodeUtf8,
|
|
4
5
|
elementChildren,
|
|
5
6
|
parseXml,
|
|
6
7
|
R_NS,
|
|
7
8
|
W_NS
|
|
8
9
|
} from "../ooxml/xml.js";
|
|
9
|
-
import {
|
|
10
|
+
import { relatedPartPath } from "./packageParts.js";
|
|
10
11
|
var EMPTY_PART = {
|
|
11
12
|
partPath: null,
|
|
12
13
|
ordered: [],
|
|
@@ -16,9 +17,6 @@ var NO_NOTES = {
|
|
|
16
17
|
footnotes: EMPTY_PART,
|
|
17
18
|
endnotes: EMPTY_PART
|
|
18
19
|
};
|
|
19
|
-
function attribute(el, localName) {
|
|
20
|
-
return Array.from(el.attributes).find((entry) => entry.localName === localName)?.value ?? null;
|
|
21
|
-
}
|
|
22
20
|
function inlineText(node) {
|
|
23
21
|
if (node.localName === "t") return node.textContent ?? "";
|
|
24
22
|
if (node.localName === "tab") return " ";
|
|
@@ -31,20 +29,16 @@ function noteText(el) {
|
|
|
31
29
|
return Array.from(el.getElementsByTagNameNS(W_NS, "p")).map(inlineText).join("\n");
|
|
32
30
|
}
|
|
33
31
|
function notePart(parts, mainPartPath, kind) {
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
(entry) => entry.type === relationshipType && !entry.external
|
|
37
|
-
);
|
|
38
|
-
if (!relationship) return EMPTY_PART;
|
|
39
|
-
const partPath = resolveTarget(mainPartPath, relationship.target);
|
|
32
|
+
const partPath = relatedPartPath(parts, mainPartPath, `${R_NS}/${kind}s`);
|
|
33
|
+
if (partPath === null) return EMPTY_PART;
|
|
40
34
|
const bytes = parts.get(partPath);
|
|
41
35
|
if (!bytes) return { ...EMPTY_PART, partPath };
|
|
42
36
|
const root = parseXml(decodeUtf8(bytes).text).documentElement;
|
|
43
37
|
const elements = elementChildren(root).filter((el) => el.localName === kind);
|
|
44
38
|
const ordered = elements.flatMap((el) => {
|
|
45
|
-
const id =
|
|
39
|
+
const id = attributeByLocalName(el, "id");
|
|
46
40
|
if (id === null) return [];
|
|
47
|
-
const type =
|
|
41
|
+
const type = attributeByLocalName(el, "type");
|
|
48
42
|
const regular = type === null || type === "normal";
|
|
49
43
|
const label = regular ? "?" : "";
|
|
50
44
|
return [{ kind, id, label, text: noteText(el), type }];
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The numbering part with the definition of every list started during editing spliced in.
|
|
3
|
+
*
|
|
4
|
+
* The original text is left as is and only the new definitions go in. Nothing is written when no
|
|
5
|
+
* list was started.
|
|
6
|
+
*/
|
|
7
|
+
import type { PartPlanner } from "./partPlan";
|
|
8
|
+
export declare const numberingPlanner: PartPlanner;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// src/docx/numberingPlanner.ts
|
|
2
|
+
import { addListDefinitions } from "../numbering/writeNumbering.js";
|
|
3
|
+
import { decodeUtf8, encodeUtf8 } from "../ooxml/xml.js";
|
|
4
|
+
import { newNumIds, numberingPartOf } from "./newLists.js";
|
|
5
|
+
var numberingPlanner = {
|
|
6
|
+
name: "numbering",
|
|
7
|
+
plan(doc, session) {
|
|
8
|
+
const added = newNumIds(doc, session);
|
|
9
|
+
const original = numberingPartOf(session);
|
|
10
|
+
if (added.length === 0 || original === null) return null;
|
|
11
|
+
const { text, hadBom } = decodeUtf8(original.bytes);
|
|
12
|
+
return /* @__PURE__ */ new Map([
|
|
13
|
+
[original.path, encodeUtf8(addListDefinitions(text, added), hadBom)]
|
|
14
|
+
]);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
export {
|
|
18
|
+
numberingPlanner
|
|
19
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where a part sits in the package, asked one way by every reader and writer, and the content
|
|
3
|
+
* types part every part the export adds is declared in.
|
|
4
|
+
*
|
|
5
|
+
* A part beside the body is found through the relationship the main part declares for it, and a
|
|
6
|
+
* part the export adds takes the first name beside the main part that nothing has claimed. Each
|
|
7
|
+
* reader used to find its part with a lookup of its own, so the rule for what counts as the
|
|
8
|
+
* related part lived in five places.
|
|
9
|
+
*/
|
|
10
|
+
export declare const CONTENT_TYPES_PATH = "[Content_Types].xml";
|
|
11
|
+
/**
|
|
12
|
+
* Where the part the main part relates under this type sits. null for no such relationship, and
|
|
13
|
+
* for one that points outside the package, which no part of it can stand behind.
|
|
14
|
+
*/
|
|
15
|
+
export declare function relatedPartPath(parts: ReadonlyMap<string, Uint8Array>, mainPartPath: string, type: string): string | null;
|
|
16
|
+
/** A part as text, and null for a path there is no part at, so a missing relationship reads as a missing part */
|
|
17
|
+
export declare function readPart(parts: ReadonlyMap<string, Uint8Array>, path: string | null): string | null;
|
|
18
|
+
/** `comments.xml`, then `comments2.xml`, and so on beside the main part: the first name no part of the package has taken */
|
|
19
|
+
export declare function availablePartPath(parts: ReadonlyMap<string, Uint8Array>, mainPartPath: string, stem: string): string;
|
|
20
|
+
/**
|
|
21
|
+
* The content types part as an export leaves it: what the package declared when it was opened,
|
|
22
|
+
* and every declaration the planners asked for on top, written once at the end.
|
|
23
|
+
*
|
|
24
|
+
* Each writer that added a part used to splice its own declaration in and hand the result to the
|
|
25
|
+
* next, so what the part came to hold depended on the order they were called in, and a writer
|
|
26
|
+
* called without the last one's result wrote over its declaration.
|
|
27
|
+
*/
|
|
28
|
+
export interface ContentTypeWriter {
|
|
29
|
+
/** Declares the type of the one part at this path */
|
|
30
|
+
addOverride(partPath: string, contentType: string): void;
|
|
31
|
+
/** Declares the type of every part with this extension */
|
|
32
|
+
addDefault(extension: string, contentType: string): void;
|
|
33
|
+
/**
|
|
34
|
+
* The part with everything added, or null when nothing was added or everything asked for was
|
|
35
|
+
* declared already. The additions go right after the opening tag, the defaults ahead of the
|
|
36
|
+
* overrides, whichever order they were asked in.
|
|
37
|
+
*/
|
|
38
|
+
part(): Uint8Array | null;
|
|
39
|
+
}
|
|
40
|
+
/** XML parts named by OPC content types, even when their URI has no .xml suffix. */
|
|
41
|
+
export declare function declaredXmlParts(types: Uint8Array, paths: Iterable<string>): ReadonlySet<string>;
|
|
42
|
+
export declare function contentTypeWriter(parts: ReadonlyMap<string, Uint8Array>): ContentTypeWriter;
|