@stll/folio-core 0.54.2 → 0.55.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/dist/ai-edits/apply.js +22 -1
- package/dist/ai-edits/headless.js +1 -0
- package/dist/compare/content-types.d.ts +3 -15
- package/dist/controller/canonicalComposition.d.ts +36 -0
- package/dist/controller/canonicalComposition.js +168 -0
- package/dist/controller/canonicalInput.d.ts +45 -0
- package/dist/controller/canonicalInput.js +338 -0
- package/dist/controller/canonicalOperations.d.ts +22 -0
- package/dist/controller/canonicalOperations.js +85 -0
- package/dist/controller/canonicalReview.d.ts +12 -0
- package/dist/controller/canonicalReview.js +19 -0
- package/dist/controller/canonicalSession.d.ts +149 -0
- package/dist/controller/canonicalSession.js +1038 -0
- package/dist/controller/canonicalStoryEditor.d.ts +34 -0
- package/dist/controller/canonicalStoryEditor.js +82 -0
- package/dist/controller/canonicalStructure.d.ts +16 -0
- package/dist/controller/canonicalStructure.js +269 -0
- package/dist/controller/folioEditor.d.ts +1 -1
- package/dist/controller/folioEditor.js +9 -0
- package/dist/controller/headerFooterEditorManager.d.ts +4 -0
- package/dist/controller/headerFooterEditorManager.js +71 -3
- package/dist/controller/hiddenEditorApi.d.ts +35 -0
- package/dist/controller/hiddenEditorApi.js +25 -8
- package/dist/controller/hiddenEditorManager.d.ts +11 -2
- package/dist/controller/hiddenEditorManager.js +456 -30
- package/dist/controller/layoutPipeline.d.ts +1 -1
- package/dist/controller/layoutPipeline.js +2 -0
- package/dist/controller/noteEditorManager.d.ts +4 -0
- package/dist/controller/noteEditorManager.js +113 -15
- package/dist/docx/attributeRemainder.js +1 -0
- package/dist/docx/canonicalSessionInput.d.ts +11 -0
- package/dist/docx/canonicalSessionInput.js +27 -0
- package/dist/docx/canonicalStoryRepack.d.ts +10 -0
- package/dist/docx/canonicalStoryRepack.js +41 -0
- package/dist/docx/contentTypeRegistry.d.ts +8 -0
- package/dist/docx/contentTypeRegistry.js +64 -0
- package/dist/docx/ensureParaIds.d.ts +7 -1
- package/dist/docx/ensureParaIds.js +163 -211
- package/dist/docx/foldedListNumberFields.d.ts +85 -0
- package/dist/docx/foldedListNumberFields.js +267 -0
- package/dist/docx/headerFooterVerbatim.d.ts +14 -1
- package/dist/docx/headerFooterVerbatim.js +95 -2
- package/dist/docx/noteIds.d.ts +5 -0
- package/dist/docx/noteIds.js +6 -2
- package/dist/docx/noteReferenceMark.d.ts +3 -1
- package/dist/docx/noteReferenceMark.js +15 -14
- package/dist/docx/numberingParser.d.ts +3 -1
- package/dist/docx/numberingParser.js +17 -3
- package/dist/docx/packageParts.d.ts +3 -1
- package/dist/docx/packageParts.js +65 -16
- package/dist/docx/paragraphMarkPropertyPresence.d.ts +9 -0
- package/dist/docx/paragraphMarkPropertyPresence.js +21 -0
- package/dist/docx/paragraphParser.js +101 -53
- package/dist/docx/paragraphPropertySource.d.ts +15 -1
- package/dist/docx/paragraphPropertySource.js +76 -22
- package/dist/docx/parser.js +2 -1
- package/dist/docx/reviewHistoryNamespace.d.ts +4 -0
- package/dist/docx/reviewHistoryNamespace.js +4 -0
- package/dist/docx/reviewResolutionProvenance.d.ts +25 -0
- package/dist/docx/reviewResolutionProvenance.js +153 -0
- package/dist/docx/rezip.d.ts +7 -3
- package/dist/docx/rezip.js +107 -45
- package/dist/docx/runConsolidator.d.ts +2 -58
- package/dist/docx/runConsolidator.js +3 -175
- package/dist/docx/runParser.d.ts +2 -1
- package/dist/docx/runParser.js +156 -116
- package/dist/docx/saveDiagnostics.d.ts +11 -0
- package/dist/docx/saveDiagnostics.js +0 -0
- package/dist/docx/selectiveSave.d.ts +2 -1
- package/dist/docx/selectiveSave.js +4 -1
- package/dist/docx/selectiveXmlPatch.d.ts +16 -8
- package/dist/docx/selectiveXmlPatch.js +74 -2
- package/dist/docx/serializer/headerFooterSerializer.d.ts +5 -1
- package/dist/docx/serializer/headerFooterSerializer.js +19 -11
- package/dist/docx/serializer/noteSerializer.d.ts +2 -2
- package/dist/docx/serializer/noteSerializer.js +24 -8
- package/dist/docx/serializer/paragraphSerializer.js +41 -4
- package/dist/docx/serializer/partNamespaces.js +2 -1
- package/dist/docx/serializer/runSerializer.js +3 -1
- package/dist/docx/settingsHeaderFooterUpdate.d.ts +5 -0
- package/dist/docx/settingsHeaderFooterUpdate.js +90 -0
- package/dist/docx/settingsParser.d.ts +1 -2
- package/dist/docx/settingsParser.js +5 -6
- package/dist/docx/storyBlockReplay.d.ts +11 -0
- package/dist/docx/storyBlockReplay.js +367 -0
- package/dist/docx/streamingXmlParser.d.ts +22 -1
- package/dist/docx/streamingXmlParser.js +49 -3
- package/dist/docx/structuralXmlPatch.js +8 -1
- package/dist/docx/verbatimCapture.d.ts +3 -1
- package/dist/docx/verbatimCapture.js +49 -6
- package/dist/i18n/messages/ar.gen.d.ts +5 -0
- package/dist/i18n/messages/ar.gen.js +656 -0
- package/dist/i18n/messages/cs.gen.d.ts +5 -0
- package/dist/i18n/messages/cs.gen.js +656 -0
- package/dist/i18n/messages/de.gen.d.ts +5 -0
- package/dist/i18n/messages/de.gen.js +656 -0
- package/dist/i18n/messages/en.gen.d.ts +5 -0
- package/dist/i18n/messages/en.gen.js +656 -0
- package/dist/i18n/messages/es.gen.d.ts +5 -0
- package/dist/i18n/messages/es.gen.js +656 -0
- package/dist/i18n/messages/et.gen.d.ts +5 -0
- package/dist/i18n/messages/et.gen.js +656 -0
- package/dist/i18n/messages/fr.gen.d.ts +5 -0
- package/dist/i18n/messages/fr.gen.js +656 -0
- package/dist/i18n/messages/he.gen.d.ts +5 -0
- package/dist/i18n/messages/he.gen.js +656 -0
- package/dist/i18n/messages/hi.gen.d.ts +5 -0
- package/dist/i18n/messages/hi.gen.js +656 -0
- package/dist/i18n/messages/hu.gen.d.ts +5 -0
- package/dist/i18n/messages/hu.gen.js +656 -0
- package/dist/i18n/messages/locales.d.ts +5 -0
- package/dist/i18n/messages/locales.js +22 -0
- package/dist/i18n/messages/lt.gen.d.ts +5 -0
- package/dist/i18n/messages/lt.gen.js +656 -0
- package/dist/i18n/messages/lv.gen.d.ts +5 -0
- package/dist/i18n/messages/lv.gen.js +656 -0
- package/dist/i18n/messages/pl.gen.d.ts +5 -0
- package/dist/i18n/messages/pl.gen.js +656 -0
- package/dist/i18n/messages/pt-BR.gen.d.ts +5 -0
- package/dist/i18n/messages/pt-BR.gen.js +656 -0
- package/dist/i18n/messages/sk.gen.d.ts +5 -0
- package/dist/i18n/messages/sk.gen.js +656 -0
- package/dist/i18n/messages/tr.gen.d.ts +5 -0
- package/dist/i18n/messages/tr.gen.js +656 -0
- package/dist/i18n/messages/zh-CN.gen.d.ts +5 -0
- package/dist/i18n/messages/zh-CN.gen.js +656 -0
- package/dist/i18n/messages.d.ts +2 -3
- package/dist/i18n/messages.js +1 -19
- package/dist/internal/noteMarkerAttrs.d.ts +8 -0
- package/dist/internal/noteMarkerAttrs.js +16 -0
- package/dist/internal/pageBreakRunSourceDescendantIndex.js +1 -0
- package/dist/internal/prosemirrorAttrBoundary.d.ts +21 -0
- package/dist/internal/prosemirrorAttrBoundary.js +50 -0
- package/dist/layout-bridge/convert/footnoteLayout.d.ts +1 -0
- package/dist/layout-bridge/convert/footnoteLayout.js +3 -3
- package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -0
- package/dist/layout-bridge/convert/headerFooterLayout.js +1 -0
- package/dist/layout-bridge/convert/noteReferences.d.ts +1 -3
- package/dist/layout-bridge/convert/noteReferences.js +1 -6
- package/dist/layout-bridge/convert/paragraphRuns.js +2 -4
- package/dist/layout-bridge/convert/toFlowBlocks.d.ts +2 -2
- package/dist/layout-bridge/convert/toFlowBlocks.js +2 -2
- package/dist/managers/DocumentLoaderManager.d.ts +1 -0
- package/dist/managers/DocumentLoaderManager.js +8 -1
- package/dist/markdown/renderBlock.js +15 -1
- package/dist/markdown/renderParagraph.js +9 -13
- package/dist/markdown/renderRuns.js +3 -2
- package/dist/markdown/renderTable.js +2 -0
- package/dist/markdown/types.d.ts +3 -9
- package/dist/prosemirror/attrs/index.d.ts +2 -12
- package/dist/prosemirror/attrs/index.js +22 -48
- package/dist/prosemirror/bookmarkBoundaryAttrs.d.ts +2 -1
- package/dist/prosemirror/canonicalCommands.d.ts +97 -0
- package/dist/prosemirror/canonicalCommands.js +28 -0
- package/dist/prosemirror/commands/pageBreak.js +15 -1
- package/dist/prosemirror/commentReferenceAttrs.d.ts +2 -1
- package/dist/prosemirror/conversion/fromProseDoc.js +91 -19
- package/dist/prosemirror/conversion/listRenderingDefinition.d.ts +6 -0
- package/dist/prosemirror/conversion/listRenderingDefinition.js +97 -0
- package/dist/prosemirror/conversion/toProseDoc.d.ts +4 -3
- package/dist/prosemirror/conversion/toProseDoc.js +51 -11
- package/dist/prosemirror/executeEditorCommand.d.ts +11 -0
- package/dist/prosemirror/executeEditorCommand.js +26 -0
- package/dist/prosemirror/extensions/StarterKit.js +2 -0
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +50 -19
- package/dist/prosemirror/extensions/features/ListExtension.js +18 -5
- package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +5 -2
- package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +13 -1
- package/dist/prosemirror/extensions/marks/TextColorExtension.js +3 -2
- package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.js +2 -0
- package/dist/prosemirror/extensions/marks/markUtils.js +70 -8
- package/dist/prosemirror/extensions/nodes/NoteMarkerExtension.d.ts +6 -0
- package/dist/prosemirror/extensions/nodes/NoteMarkerExtension.js +36 -0
- package/dist/prosemirror/extensions/nodes/PreservedXmlExtension.js +4 -2
- package/dist/prosemirror/listMarker.d.ts +1 -0
- package/dist/prosemirror/listMarker.js +16 -7
- package/dist/prosemirror/listNumbering.js +26 -5
- package/dist/prosemirror/listRenderingAttrs.d.ts +1 -0
- package/dist/prosemirror/listRenderingAttrs.js +3 -0
- package/dist/prosemirror/markupViewNotes.js +3 -2
- package/dist/prosemirror/moveRangeBoundaryAttrs.d.ts +2 -1
- package/dist/prosemirror/noteReferenceReview.js +5 -3
- package/dist/prosemirror/plugins/suggestionMode.js +50 -2
- package/dist/prosemirror/rangeAnchorAttrs.d.ts +2 -1
- package/dist/prosemirror/runFormattingFromMarks.d.ts +4 -1
- package/dist/prosemirror/runFormattingFromMarks.js +15 -1
- package/dist/prosemirror/runFormattingInlineCarriers.d.ts +2 -1
- package/dist/prosemirror/runFormattingInlineCarriers.js +4 -1
- package/dist/prosemirror/schema/marks.d.ts +2 -0
- package/dist/prosemirror/schema/nodes.d.ts +10 -2
- package/dist/prosemirror/textBoxAnchorAttrs.d.ts +2 -1
- package/dist/prosemirror/textInput.js +5 -1
- package/dist/prosemirror/trackedRevisionPath.js +2 -1
- package/dist/prosemirror/trackedRunInlineAtoms.d.ts +1 -0
- package/dist/prosemirror/trackedRunInlineAtoms.js +1 -0
- package/dist/prosemirror/validation.js +4 -0
- package/dist/types/content.d.ts +2 -2
- package/dist/utils/createDocument.js +2 -2
- package/package.json +14 -2
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
//#region src/docx/foldedListNumberFields.ts
|
|
2
|
+
/** Zero-width markup that can stand between a field and its tab. */
|
|
3
|
+
const RANGE_MARKER_TYPES = /* @__PURE__ */ new Set([
|
|
4
|
+
"bookmarkStart",
|
|
5
|
+
"bookmarkEnd",
|
|
6
|
+
"commentRangeStart",
|
|
7
|
+
"commentRangeEnd",
|
|
8
|
+
"commentReference"
|
|
9
|
+
]);
|
|
10
|
+
/** Markup that shows nothing and so does not end the start of a paragraph. */
|
|
11
|
+
const ZERO_WIDTH_TYPES = /* @__PURE__ */ new Set([
|
|
12
|
+
...RANGE_MARKER_TYPES,
|
|
13
|
+
"moveFromRangeStart",
|
|
14
|
+
"moveFromRangeEnd",
|
|
15
|
+
"moveToRangeStart",
|
|
16
|
+
"moveToRangeEnd"
|
|
17
|
+
]);
|
|
18
|
+
/** Whether `content` is markup that may stand between a field and the tab that follows it. */
|
|
19
|
+
const isListNumberGapMarker = (content) => RANGE_MARKER_TYPES.has(content.type);
|
|
20
|
+
const isZeroWidth = (content) => ZERO_WIDTH_TYPES.has(content.type) || content.type === "preservedInline" && content.text === "";
|
|
21
|
+
/** Whether `content` is a `LISTNUM` field, by its parsed type or its instruction. */
|
|
22
|
+
const isListNumberField = (content) => content.type === "complexField" && (content.fieldType === "LISTNUM" || content.instruction.trim().toUpperCase().startsWith("LISTNUM"));
|
|
23
|
+
/** A run that holds one tab and nothing else. */
|
|
24
|
+
const isTabOnlyRun = (content) => content.type === "run" && content.content.length === 1 && content.content[0]?.type === "tab";
|
|
25
|
+
/** The text a field's cached result puts in the marker. */
|
|
26
|
+
const cachedListNumberText = (field) => {
|
|
27
|
+
let text = "";
|
|
28
|
+
for (const run of field.fieldResult) for (const piece of run.content) if (piece.type === "text") text += piece.text;
|
|
29
|
+
return text;
|
|
30
|
+
};
|
|
31
|
+
const isRecord = (value) => typeof value === "object" && value !== null;
|
|
32
|
+
/** Whether `value` is what a capture stands for: a complex field, or a run. */
|
|
33
|
+
const isFoldedListNumber = (value) => {
|
|
34
|
+
if (!isRecord(value)) return false;
|
|
35
|
+
if (value["kind"] === "field") {
|
|
36
|
+
const field = value["field"];
|
|
37
|
+
return isRecord(field) && field["type"] === "complexField" && typeof field["instruction"] === "string" && Array.isArray(field["fieldCode"]) && Array.isArray(field["fieldResult"]);
|
|
38
|
+
}
|
|
39
|
+
if (value["kind"] === "tab") {
|
|
40
|
+
const run = value["run"];
|
|
41
|
+
return isRecord(run) && run["type"] === "run" && Array.isArray(run["content"]);
|
|
42
|
+
}
|
|
43
|
+
return false;
|
|
44
|
+
};
|
|
45
|
+
/** What `content` stands for when it is a capture the fold left, else nothing. */
|
|
46
|
+
const foldedListNumberOf = (content) => content.type === "preservedInline" ? content.foldedListNumber : void 0;
|
|
47
|
+
/** Whether `content` is a capture the fold left in place of a field or its tab. */
|
|
48
|
+
const isFoldedListNumberCapture = (content) => foldedListNumberOf(content) !== void 0;
|
|
49
|
+
/**
|
|
50
|
+
* Replace the `LISTNUM` fields that open a paragraph, and the tab after each,
|
|
51
|
+
* by captures of the markup they were read from.
|
|
52
|
+
*
|
|
53
|
+
* Only what stands ahead of the first thing the line shows is folded: a field
|
|
54
|
+
* after text is on the line where the text is. `sourceMarkupOf` answers the
|
|
55
|
+
* markup; a field it has none for is left as the field it is, and ends the
|
|
56
|
+
* fold. Bookmark and comment markers between a field and its tab stay where
|
|
57
|
+
* they are, and the tab is still the field's when only they separate the two.
|
|
58
|
+
*/
|
|
59
|
+
const foldListNumberFields = (content, sourceMarkupOf) => {
|
|
60
|
+
const folded = [];
|
|
61
|
+
const cached = [];
|
|
62
|
+
let fieldCount = 0;
|
|
63
|
+
let leading = true;
|
|
64
|
+
let awaitingTab = false;
|
|
65
|
+
for (const item of content) {
|
|
66
|
+
if (isListNumberField(item)) fieldCount += 1;
|
|
67
|
+
if (!leading) {
|
|
68
|
+
folded.push(item);
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (awaitingTab && RANGE_MARKER_TYPES.has(item.type)) {
|
|
72
|
+
folded.push(item);
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (awaitingTab) {
|
|
76
|
+
awaitingTab = false;
|
|
77
|
+
const tabMarkup = isTabOnlyRun(item) ? sourceMarkupOf(item) : void 0;
|
|
78
|
+
if (isTabOnlyRun(item) && tabMarkup !== void 0) {
|
|
79
|
+
folded.push({
|
|
80
|
+
type: "preservedInline",
|
|
81
|
+
xml: tabMarkup,
|
|
82
|
+
text: "",
|
|
83
|
+
foldedListNumber: {
|
|
84
|
+
kind: "tab",
|
|
85
|
+
run: item
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (isListNumberField(item)) {
|
|
92
|
+
const markup = sourceMarkupOf(item);
|
|
93
|
+
if (markup !== void 0) {
|
|
94
|
+
folded.push({
|
|
95
|
+
type: "preservedInline",
|
|
96
|
+
xml: markup,
|
|
97
|
+
text: "",
|
|
98
|
+
foldedListNumber: {
|
|
99
|
+
kind: "field",
|
|
100
|
+
field: item
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
const text = cachedListNumberText(item);
|
|
104
|
+
if (text) cached.push(text);
|
|
105
|
+
awaitingTab = true;
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
folded.push(item);
|
|
110
|
+
leading = isZeroWidth(item);
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
content: folded,
|
|
114
|
+
cached,
|
|
115
|
+
fieldCount
|
|
116
|
+
};
|
|
117
|
+
};
|
|
118
|
+
const isCapture = (item) => item?.kind === "field" || item?.kind === "tab";
|
|
119
|
+
/**
|
|
120
|
+
* Decide which captures of a paragraph stay hidden, and what its marker shows.
|
|
121
|
+
*
|
|
122
|
+
* `markerShowsFields` says whether the paragraph's marker shows folded fields
|
|
123
|
+
* at all. When it does not, no capture is hidden.
|
|
124
|
+
*
|
|
125
|
+
* When it does, the captures it shows are the ones that open the paragraph:
|
|
126
|
+
* those ahead of the first thing the line shows, each field followed at most
|
|
127
|
+
* by its own tab. Text put in front of them was put in front of the body, not
|
|
128
|
+
* of the marker, so if the first capture no longer opens the paragraph, it
|
|
129
|
+
* and the captures that stand with it go back to the start. Every capture
|
|
130
|
+
* further in is on the line.
|
|
131
|
+
*/
|
|
132
|
+
const planListNumberFold = (items, markerShowsFields) => {
|
|
133
|
+
const unmoved = items.map((_, index) => index);
|
|
134
|
+
const none = {
|
|
135
|
+
order: unmoved,
|
|
136
|
+
hidden: /* @__PURE__ */ new Set(),
|
|
137
|
+
suffix: void 0
|
|
138
|
+
};
|
|
139
|
+
const first = items.findIndex((item) => isCapture(item));
|
|
140
|
+
if (!markerShowsFields || first === -1) return none;
|
|
141
|
+
let order = unmoved;
|
|
142
|
+
if (items.slice(0, first).some((item) => item.kind === "shown")) {
|
|
143
|
+
let end = first + 1;
|
|
144
|
+
for (let index = first + 1; index < items.length; index += 1) {
|
|
145
|
+
const item = items[index];
|
|
146
|
+
if (item?.kind === "shown") break;
|
|
147
|
+
if (isCapture(item)) end = index + 1;
|
|
148
|
+
}
|
|
149
|
+
order = [
|
|
150
|
+
...unmoved.slice(first, end),
|
|
151
|
+
...unmoved.slice(0, first),
|
|
152
|
+
...unmoved.slice(end)
|
|
153
|
+
];
|
|
154
|
+
}
|
|
155
|
+
const hidden = /* @__PURE__ */ new Set();
|
|
156
|
+
const cached = [];
|
|
157
|
+
let fieldAwaitsTab = false;
|
|
158
|
+
for (const index of order) {
|
|
159
|
+
const item = items[index];
|
|
160
|
+
if (item?.kind === "hidden") continue;
|
|
161
|
+
if (item?.kind === "field") {
|
|
162
|
+
hidden.add(index);
|
|
163
|
+
if (item.cached) cached.push(item.cached);
|
|
164
|
+
fieldAwaitsTab = true;
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
if (item?.kind === "tab" && fieldAwaitsTab) {
|
|
168
|
+
hidden.add(index);
|
|
169
|
+
fieldAwaitsTab = false;
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
return cached.length === 0 ? none : {
|
|
175
|
+
order,
|
|
176
|
+
hidden,
|
|
177
|
+
suffix: cached.join(" ")
|
|
178
|
+
};
|
|
179
|
+
};
|
|
180
|
+
/**
|
|
181
|
+
* What a paragraph's marker says about folded fields. It shows them after a
|
|
182
|
+
* tab its own level text does not have; a bullet shows only its glyph.
|
|
183
|
+
*/
|
|
184
|
+
const listMarkerFoldState = ({ marker, template, isBullet, numbered }) => {
|
|
185
|
+
const tab = marker?.indexOf(" ") ?? -1;
|
|
186
|
+
if (!marker || !numbered || isBullet || !template || template.includes(" ") || tab === -1) return {
|
|
187
|
+
showsFields: false,
|
|
188
|
+
base: marker ?? ""
|
|
189
|
+
};
|
|
190
|
+
return {
|
|
191
|
+
showsFields: true,
|
|
192
|
+
base: marker.slice(0, tab)
|
|
193
|
+
};
|
|
194
|
+
};
|
|
195
|
+
/** The marker text for `state` showing `suffix`. */
|
|
196
|
+
const listMarkerWithFold = (state, suffix) => suffix === void 0 ? state.base : `${state.base}\t${suffix}`;
|
|
197
|
+
const foldItemOf = (content) => {
|
|
198
|
+
const folded = foldedListNumberOf(content);
|
|
199
|
+
if (folded) return folded.kind === "field" ? {
|
|
200
|
+
kind: "field",
|
|
201
|
+
cached: cachedListNumberText(folded.field)
|
|
202
|
+
} : { kind: "tab" };
|
|
203
|
+
return isZeroWidth(content) ? { kind: "hidden" } : { kind: "shown" };
|
|
204
|
+
};
|
|
205
|
+
/** The item a capture stands for, which shows on the line; any other item is itself. */
|
|
206
|
+
const unfoldedListNumberContent = (content) => {
|
|
207
|
+
const folded = foldedListNumberOf(content);
|
|
208
|
+
if (!folded) return content;
|
|
209
|
+
return folded.kind === "field" ? folded.field : folded.run;
|
|
210
|
+
};
|
|
211
|
+
/**
|
|
212
|
+
* The one definition of a tracked change for the fold: content inserted,
|
|
213
|
+
* deleted, or moved from or to a place under revision tracking.
|
|
214
|
+
*/
|
|
215
|
+
const isTrackedChange = (content) => content.type === "insertion" || content.type === "deletion" || content.type === "moveFrom" || content.type === "moveTo";
|
|
216
|
+
/**
|
|
217
|
+
* `content` with every capture inside a tracked change replaced by the item
|
|
218
|
+
* it stands for. A tracked change is written with its own spellings (deleted
|
|
219
|
+
* text is `w:delText`, a deleted instruction `w:delInstrText`), which markup
|
|
220
|
+
* replayed as it was read does not have; the field and the run do.
|
|
221
|
+
*/
|
|
222
|
+
const withTrackedCapturesShown = (content) => {
|
|
223
|
+
let changed = false;
|
|
224
|
+
const next = content.map((item) => {
|
|
225
|
+
if (!isTrackedChange(item)) return item;
|
|
226
|
+
if (!item.content.some((child) => foldedListNumberOf(child) !== void 0)) return item;
|
|
227
|
+
changed = true;
|
|
228
|
+
return {
|
|
229
|
+
...item,
|
|
230
|
+
content: item.content.map((child) => {
|
|
231
|
+
const folded = foldedListNumberOf(child);
|
|
232
|
+
if (!folded) return child;
|
|
233
|
+
return structuredClone(folded.kind === "field" ? folded.field : folded.run);
|
|
234
|
+
})
|
|
235
|
+
};
|
|
236
|
+
});
|
|
237
|
+
return changed ? next : content;
|
|
238
|
+
};
|
|
239
|
+
/**
|
|
240
|
+
* Bring `paragraph` to the one form the fold allows: the captures its marker
|
|
241
|
+
* shows stand at its start, every other capture is the field or the tab it
|
|
242
|
+
* stood for, and the marker shows exactly the fields still hidden behind it.
|
|
243
|
+
* A capture under a tracked change is never hidden.
|
|
244
|
+
*/
|
|
245
|
+
const normalizeFoldedListNumbers = (paragraph) => {
|
|
246
|
+
paragraph.content = withTrackedCapturesShown(paragraph.content);
|
|
247
|
+
const rendering = paragraph.listRendering;
|
|
248
|
+
const state = listMarkerFoldState({
|
|
249
|
+
marker: rendering?.marker,
|
|
250
|
+
template: rendering?.markerTemplate,
|
|
251
|
+
isBullet: rendering?.isBullet === true,
|
|
252
|
+
numbered: rendering !== void 0
|
|
253
|
+
});
|
|
254
|
+
const content = paragraph.content;
|
|
255
|
+
if (!state.showsFields && !content.some(isFoldedListNumberCapture)) return;
|
|
256
|
+
const plan = planListNumberFold(content.map(foldItemOf), state.showsFields);
|
|
257
|
+
const next = [];
|
|
258
|
+
for (const index of plan.order) {
|
|
259
|
+
const item = content[index];
|
|
260
|
+
if (item === void 0) continue;
|
|
261
|
+
next.push(plan.hidden.has(index) || !isFoldedListNumberCapture(item) ? item : structuredClone(unfoldedListNumberContent(item)));
|
|
262
|
+
}
|
|
263
|
+
paragraph.content = next;
|
|
264
|
+
if (rendering && state.showsFields) rendering.marker = listMarkerWithFold(state, plan.suffix);
|
|
265
|
+
};
|
|
266
|
+
//#endregion
|
|
267
|
+
export { foldListNumberFields, foldedListNumberOf, isFoldedListNumber, isFoldedListNumberCapture, isListNumberField, isListNumberGapMarker, isTabOnlyRun, normalizeFoldedListNumbers, planListNumberFold, unfoldedListNumberContent };
|
|
@@ -1,9 +1,22 @@
|
|
|
1
1
|
import { document_d_exports } from "../types/document.js";
|
|
2
2
|
//#region src/docx/headerFooterVerbatim.d.ts
|
|
3
|
+
type HeaderFooterSourceBaseline = {
|
|
4
|
+
type: "missing";
|
|
5
|
+
} | {
|
|
6
|
+
type: "mismatch";
|
|
7
|
+
} | {
|
|
8
|
+
type: "captured";
|
|
9
|
+
content: readonly document_d_exports.BlockContent[];
|
|
10
|
+
};
|
|
11
|
+
declare const captureHeaderFooterPackageBaselines: (document: document_d_exports.Document) => void;
|
|
12
|
+
/** Transfer the parsed package registry only across a trusted document graph clone. */
|
|
13
|
+
declare const copyHeaderFooterPackageBaselines: (target: document_d_exports.Document, source: document_d_exports.Document) => void;
|
|
14
|
+
declare const getHeaderFooterSourceBaseline: (hf: document_d_exports.HeaderFooter, originalBuffer?: ArrayBuffer) => HeaderFooterSourceBaseline;
|
|
15
|
+
declare const canReplayHeaderFooterBlocks: (hf: document_d_exports.HeaderFooter, baselineContent: readonly document_d_exports.BlockContent[]) => boolean;
|
|
3
16
|
declare const getHeaderFooterVerbatimXml: (hf: document_d_exports.HeaderFooter) => string | undefined;
|
|
4
17
|
declare const canReplayHeaderFooterVerbatim: (hf: document_d_exports.HeaderFooter) => boolean;
|
|
5
18
|
declare const assignHeaderFooterVerbatimXml: (hf: document_d_exports.HeaderFooter, xml: string) => void;
|
|
6
19
|
declare const refreshHeaderFooterVerbatimFingerprint: (hf: document_d_exports.HeaderFooter) => void;
|
|
7
20
|
declare const clearHeaderFooterVerbatimXml: (hf: document_d_exports.HeaderFooter) => void;
|
|
8
21
|
//#endregion
|
|
9
|
-
export { assignHeaderFooterVerbatimXml, canReplayHeaderFooterVerbatim, clearHeaderFooterVerbatimXml, getHeaderFooterVerbatimXml, refreshHeaderFooterVerbatimFingerprint };
|
|
22
|
+
export { assignHeaderFooterVerbatimXml, canReplayHeaderFooterBlocks, canReplayHeaderFooterVerbatim, captureHeaderFooterPackageBaselines, clearHeaderFooterVerbatimXml, copyHeaderFooterPackageBaselines, getHeaderFooterSourceBaseline, getHeaderFooterVerbatimXml, refreshHeaderFooterVerbatimFingerprint };
|
|
@@ -1,5 +1,89 @@
|
|
|
1
|
+
import { canonicalJson } from "../utils/canonicalJson.js";
|
|
2
|
+
import { Result } from "better-result";
|
|
1
3
|
//#region src/docx/headerFooterVerbatim.ts
|
|
4
|
+
const fingerprintBaselines = /* @__PURE__ */ new WeakMap();
|
|
5
|
+
const readFingerprint = (hf) => {
|
|
6
|
+
const fingerprint = hf.verbatimFingerprint;
|
|
7
|
+
if (!fingerprint) return void 0;
|
|
8
|
+
const cached = fingerprintBaselines.get(hf);
|
|
9
|
+
if (cached?.fingerprint === fingerprint) return cached.value;
|
|
10
|
+
const parsed = Result.try(() => JSON.parse(fingerprint));
|
|
11
|
+
const value = parsed.isOk() ? parsed.value : void 0;
|
|
12
|
+
fingerprintBaselines.set(hf, {
|
|
13
|
+
fingerprint,
|
|
14
|
+
value
|
|
15
|
+
});
|
|
16
|
+
return value;
|
|
17
|
+
};
|
|
18
|
+
const BASELINE_HANDLE = Symbol("header-footer-source-baseline");
|
|
19
|
+
const contentBaselines = /* @__PURE__ */ new WeakMap();
|
|
20
|
+
const captureContentBaseline = (hf) => {
|
|
21
|
+
const fingerprint = hf.verbatimFingerprint;
|
|
22
|
+
if (fingerprint === void 0) return;
|
|
23
|
+
const handle = {};
|
|
24
|
+
const content = structuredClone(hf.content);
|
|
25
|
+
contentBaselines.set(handle, {
|
|
26
|
+
fingerprint,
|
|
27
|
+
xml: hf.verbatimXml,
|
|
28
|
+
contentFingerprint: canonicalJson(content),
|
|
29
|
+
content
|
|
30
|
+
});
|
|
31
|
+
Object.defineProperty(hf, BASELINE_HANDLE, {
|
|
32
|
+
value: handle,
|
|
33
|
+
enumerable: true,
|
|
34
|
+
configurable: true
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
const packageBaselines = /* @__PURE__ */ new WeakMap();
|
|
38
|
+
const captureHeaderFooterPackageBaselines = (document) => {
|
|
39
|
+
if (!document.originalBuffer) return;
|
|
40
|
+
const handles = /* @__PURE__ */ new Map();
|
|
41
|
+
for (const parts of [document.package.headers, document.package.footers]) for (const hf of parts?.values() ?? []) {
|
|
42
|
+
if (!(BASELINE_HANDLE in hf) || typeof hf[BASELINE_HANDLE] !== "object" || hf[BASELINE_HANDLE] === null || hf.verbatimFingerprint === void 0 || hf.verbatimXml === void 0) continue;
|
|
43
|
+
const bySource = handles.get(hf.verbatimFingerprint) ?? /* @__PURE__ */ new Map();
|
|
44
|
+
bySource.set(hf.verbatimXml, hf[BASELINE_HANDLE]);
|
|
45
|
+
handles.set(hf.verbatimFingerprint, bySource);
|
|
46
|
+
}
|
|
47
|
+
packageBaselines.set(document.originalBuffer, handles);
|
|
48
|
+
};
|
|
49
|
+
/** Transfer the parsed package registry only across a trusted document graph clone. */
|
|
50
|
+
const copyHeaderFooterPackageBaselines = (target, source) => {
|
|
51
|
+
if (!target.originalBuffer || !source.originalBuffer) return;
|
|
52
|
+
const baselines = packageBaselines.get(source.originalBuffer);
|
|
53
|
+
if (baselines) packageBaselines.set(target.originalBuffer, baselines);
|
|
54
|
+
};
|
|
55
|
+
const getHeaderFooterSourceBaseline = (hf, originalBuffer) => {
|
|
56
|
+
let handle;
|
|
57
|
+
if (BASELINE_HANDLE in hf) handle = hf[BASELINE_HANDLE];
|
|
58
|
+
else if (originalBuffer && hf.verbatimFingerprint !== void 0 && hf.verbatimXml !== void 0) handle = packageBaselines.get(originalBuffer)?.get(hf.verbatimFingerprint)?.get(hf.verbatimXml);
|
|
59
|
+
if (handle === void 0 && !(BASELINE_HANDLE in hf)) return { type: "missing" };
|
|
60
|
+
if (typeof handle !== "object" || handle === null) return { type: "mismatch" };
|
|
61
|
+
const baseline = contentBaselines.get(handle);
|
|
62
|
+
if (!baseline || baseline.fingerprint !== hf.verbatimFingerprint || baseline.xml !== hf.verbatimXml || baseline.contentFingerprint !== canonicalJson(baseline.content)) return { type: "mismatch" };
|
|
63
|
+
return {
|
|
64
|
+
type: "captured",
|
|
65
|
+
content: baseline.content
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
const canReplayHeaderFooterBlocks = (hf, baselineContent) => {
|
|
69
|
+
if (hf.rawWatermarkXml !== void 0) {
|
|
70
|
+
const index = hf.watermarkBlockIndex;
|
|
71
|
+
if (index === void 0 || !Number.isInteger(index) || index < 0 || index >= baselineContent.length || baselineContent.length !== hf.content.length || canonicalJson(baselineContent.at(index)) !== canonicalJson(hf.content.at(index))) return false;
|
|
72
|
+
}
|
|
73
|
+
const baseline = readFingerprint(hf);
|
|
74
|
+
if (baseline === null || typeof baseline !== "object" || !("type" in baseline) || baseline.type !== hf.type) return false;
|
|
75
|
+
return canonicalJson({
|
|
76
|
+
watermark: "watermark" in baseline ? baseline.watermark : void 0,
|
|
77
|
+
watermarkBlockIndex: "watermarkBlockIndex" in baseline ? baseline.watermarkBlockIndex : void 0,
|
|
78
|
+
rawWatermarkXml: "rawWatermarkXml" in baseline ? baseline.rawWatermarkXml : void 0
|
|
79
|
+
}) === canonicalJson({
|
|
80
|
+
watermark: hf.watermark,
|
|
81
|
+
watermarkBlockIndex: hf.watermarkBlockIndex,
|
|
82
|
+
rawWatermarkXml: hf.rawWatermarkXml
|
|
83
|
+
});
|
|
84
|
+
};
|
|
2
85
|
const headerFooterSerializationFingerprint = (hf) => JSON.stringify({
|
|
86
|
+
type: hf.type,
|
|
3
87
|
content: hf.content,
|
|
4
88
|
watermark: hf.watermark,
|
|
5
89
|
watermarkBlockIndex: hf.watermarkBlockIndex,
|
|
@@ -9,22 +93,31 @@ const getHeaderFooterVerbatimXml = (hf) => hf.verbatimXml;
|
|
|
9
93
|
const canReplayHeaderFooterVerbatim = (hf) => {
|
|
10
94
|
const ext = hf;
|
|
11
95
|
if (!ext.verbatimXml || !ext.verbatimFingerprint) return false;
|
|
12
|
-
return
|
|
96
|
+
return canonicalJson(readFingerprint(hf)) === canonicalJson({
|
|
97
|
+
type: hf.type,
|
|
98
|
+
content: hf.content,
|
|
99
|
+
watermark: hf.watermark,
|
|
100
|
+
watermarkBlockIndex: hf.watermarkBlockIndex,
|
|
101
|
+
rawWatermarkXml: hf.rawWatermarkXml
|
|
102
|
+
});
|
|
13
103
|
};
|
|
14
104
|
const assignHeaderFooterVerbatimXml = (hf, xml) => {
|
|
15
105
|
const ext = hf;
|
|
16
106
|
ext.verbatimXml = xml;
|
|
17
107
|
ext.verbatimFingerprint = headerFooterSerializationFingerprint(hf);
|
|
108
|
+
captureContentBaseline(hf);
|
|
18
109
|
};
|
|
19
110
|
const refreshHeaderFooterVerbatimFingerprint = (hf) => {
|
|
20
111
|
const ext = hf;
|
|
21
112
|
if (!ext.verbatimXml) return;
|
|
22
113
|
ext.verbatimFingerprint = headerFooterSerializationFingerprint(hf);
|
|
114
|
+
captureContentBaseline(hf);
|
|
23
115
|
};
|
|
24
116
|
const clearHeaderFooterVerbatimXml = (hf) => {
|
|
25
117
|
const ext = hf;
|
|
26
118
|
delete ext.verbatimXml;
|
|
27
119
|
delete ext.verbatimFingerprint;
|
|
120
|
+
Reflect.deleteProperty(hf, BASELINE_HANDLE);
|
|
28
121
|
};
|
|
29
122
|
//#endregion
|
|
30
|
-
export { assignHeaderFooterVerbatimXml, canReplayHeaderFooterVerbatim, clearHeaderFooterVerbatimXml, getHeaderFooterVerbatimXml, refreshHeaderFooterVerbatimFingerprint };
|
|
123
|
+
export { assignHeaderFooterVerbatimXml, canReplayHeaderFooterBlocks, canReplayHeaderFooterVerbatim, captureHeaderFooterPackageBaselines, clearHeaderFooterVerbatimXml, copyHeaderFooterPackageBaselines, getHeaderFooterSourceBaseline, getHeaderFooterVerbatimXml, refreshHeaderFooterVerbatimFingerprint };
|
package/dist/docx/noteIds.d.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
//#region src/docx/noteIds.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* The next free endnote id among `existingIds`, a document's endnotes. Ids are
|
|
4
|
+
* unique per document, so the allocator lives for one call: the result
|
|
5
|
+
* depends only on the document, never on what other documents minted.
|
|
6
|
+
*/
|
|
2
7
|
declare const mintEndnoteId: (existingIds: Iterable<number>) => number;
|
|
3
8
|
//#endregion
|
|
4
9
|
export { mintEndnoteId };
|
package/dist/docx/noteIds.js
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import { createNumericIdAllocator } from "./numericIdAllocator.js";
|
|
2
2
|
//#region src/docx/noteIds.ts
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* The next free endnote id among `existingIds`, a document's endnotes. Ids are
|
|
5
|
+
* unique per document, so the allocator lives for one call: the result
|
|
6
|
+
* depends only on the document, never on what other documents minted.
|
|
7
|
+
*/
|
|
4
8
|
const mintEndnoteId = (existingIds) => {
|
|
5
|
-
const allocator =
|
|
9
|
+
const allocator = createNumericIdAllocator({
|
|
6
10
|
space: "endnote",
|
|
7
11
|
firstId: 1
|
|
8
12
|
});
|
|
@@ -3,6 +3,8 @@ import { document_d_exports } from "../types/document.js";
|
|
|
3
3
|
type NoteKind = "footnote" | "endnote";
|
|
4
4
|
/** The run carrying a note's in-note reference mark, in the note reference style. */
|
|
5
5
|
declare const noteReferenceMarkRun: (kind: NoteKind) => document_d_exports.Run;
|
|
6
|
+
/** Whether a note already owns its typed marker, including inside tracked content. */
|
|
7
|
+
declare const hasNoteReferenceMark: (kind: NoteKind, content: readonly document_d_exports.BlockContent[]) => boolean;
|
|
6
8
|
/**
|
|
7
9
|
* A note's content with its reference mark run at the start of its first
|
|
8
10
|
* paragraph, added when the note has none.
|
|
@@ -12,4 +14,4 @@ declare const withNoteReferenceMark: (kind: NoteKind, content: readonly document
|
|
|
12
14
|
declare function createNote(kind: "footnote", id: number, content: readonly document_d_exports.BlockContent[]): document_d_exports.Footnote;
|
|
13
15
|
declare function createNote(kind: "endnote", id: number, content: readonly document_d_exports.BlockContent[]): document_d_exports.Endnote;
|
|
14
16
|
//#endregion
|
|
15
|
-
export { createNote, noteReferenceMarkRun, withNoteReferenceMark };
|
|
17
|
+
export { createNote, hasNoteReferenceMark, noteReferenceMarkRun, withNoteReferenceMark };
|
|
@@ -1,37 +1,38 @@
|
|
|
1
1
|
import { cloneParagraphWithPropertySource } from "./paragraphPropertySource.js";
|
|
2
|
+
import { visitDocxParagraphs, visitParagraphRuns } from "./paragraphTraversal.js";
|
|
2
3
|
//#region src/docx/noteReferenceMark.ts
|
|
3
|
-
const MARK_ELEMENT = /<(?:[\w.-]+:)?(?:footnote|endnote)Ref[\s/>]/u;
|
|
4
4
|
/** The run carrying a note's in-note reference mark, in the note reference style. */
|
|
5
5
|
const noteReferenceMarkRun = (kind) => ({
|
|
6
6
|
type: "run",
|
|
7
7
|
formatting: { styleId: kind === "footnote" ? "FootnoteReference" : "EndnoteReference" },
|
|
8
8
|
content: [{
|
|
9
|
-
type: "
|
|
10
|
-
|
|
11
|
-
text: ""
|
|
9
|
+
type: "noteMarker",
|
|
10
|
+
kind
|
|
12
11
|
}]
|
|
13
12
|
});
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
13
|
+
/** Whether a note already owns its typed marker, including inside tracked content. */
|
|
14
|
+
const hasNoteReferenceMark = (kind, content) => {
|
|
15
|
+
let found = false;
|
|
16
|
+
visitDocxParagraphs({ documentBody: { content: [...content] } }, (paragraph) => {
|
|
17
|
+
visitParagraphRuns(paragraph, (run) => {
|
|
18
|
+
if (run.content.some((child) => child.type === "noteMarker" && child.kind === kind)) found = true;
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
return found;
|
|
20
22
|
};
|
|
21
23
|
/**
|
|
22
24
|
* A note's content with its reference mark run at the start of its first
|
|
23
25
|
* paragraph, added when the note has none.
|
|
24
26
|
*/
|
|
25
27
|
const withNoteReferenceMark = (kind, content) => {
|
|
26
|
-
if (
|
|
28
|
+
if (hasNoteReferenceMark(kind, content)) return [...content];
|
|
27
29
|
const index = content.findIndex((block) => block.type === "paragraph");
|
|
28
30
|
const mark = noteReferenceMarkRun(kind);
|
|
29
31
|
if (index === -1) return [{
|
|
30
32
|
type: "paragraph",
|
|
31
33
|
content: [mark]
|
|
32
34
|
}, ...content];
|
|
33
|
-
|
|
34
|
-
return content.map((block, position) => position === index ? cloneParagraphWithPropertySource(paragraph, { content: [mark, ...paragraph.content] }) : block);
|
|
35
|
+
return content.map((block, position) => position === index && block.type === "paragraph" ? cloneParagraphWithPropertySource(block, { content: [mark, ...block.content] }) : block);
|
|
35
36
|
};
|
|
36
37
|
function createNote(kind, id, content) {
|
|
37
38
|
return kind === "footnote" ? {
|
|
@@ -45,4 +46,4 @@ function createNote(kind, id, content) {
|
|
|
45
46
|
};
|
|
46
47
|
}
|
|
47
48
|
//#endregion
|
|
48
|
-
export { createNote, noteReferenceMarkRun, withNoteReferenceMark };
|
|
49
|
+
export { createNote, hasNoteReferenceMark, noteReferenceMarkRun, withNoteReferenceMark };
|
|
@@ -81,7 +81,9 @@ declare function getBulletCharacter(level: document_d_exports.ListLevel): string
|
|
|
81
81
|
* Check if a list level is a bullet (not numbered)
|
|
82
82
|
*/
|
|
83
83
|
declare function isBulletLevel(level: document_d_exports.ListLevel): boolean;
|
|
84
|
+
/** Whether a numbering definition uses a bullet marker rather than a numeric or hidden one. */
|
|
85
|
+
declare const numberingLevelUsesBulletMarker: (level: Pick<document_d_exports.ListLevel, "numFmt"> | null | undefined) => boolean;
|
|
84
86
|
/** Whether a numbering level reserves horizontal space for a visible marker. */
|
|
85
87
|
declare const numberingLevelHasMarkerSlot: (level: Pick<document_d_exports.ListLevel, "numFmt">) => boolean;
|
|
86
88
|
//#endregion
|
|
87
|
-
export { NumberingMap, computeListRendering, counterFormatOf, createNumberingMap, customNumberFormatPadWidth, formatOoxmlCounter as formatNumber, getBulletCharacter, getCachedNumberingMap, isBulletLevel, markerAlignmentForLevel, markerFormattingFromLevel, numberingLevelHasMarkerSlot, padDecimal, parseNumbering, renderListMarker };
|
|
89
|
+
export { NumberingMap, computeListRendering, counterFormatOf, createNumberingMap, customNumberFormatPadWidth, formatOoxmlCounter as formatNumber, getBulletCharacter, getCachedNumberingMap, isBulletLevel, markerAlignmentForLevel, markerFormattingFromLevel, numberingLevelHasMarkerSlot, numberingLevelUsesBulletMarker, padDecimal, parseNumbering, renderListMarker };
|
|
@@ -6,7 +6,20 @@ import { parseParagraphProperties } from "./paragraphProperties.js";
|
|
|
6
6
|
import { LevelSuffixSchema, NumberFormatSchema, ParagraphAlignmentSchema, narrowEnum } from "./parserEnums.js";
|
|
7
7
|
import { RUN_PROPERTY_OWNERS, parseRunProperties } from "./runParser.js";
|
|
8
8
|
import { findChild, getAttribute, parseBooleanElement, parseNumericAttribute, parseOnOffAttribute, parseXmlDocument } from "./xmlParser.js";
|
|
9
|
+
import { isNumberingLevel } from "@stll/docx-core/model";
|
|
9
10
|
//#region src/docx/numberingParser.ts
|
|
11
|
+
/**
|
|
12
|
+
* Numbering/List Parser for DOCX
|
|
13
|
+
*
|
|
14
|
+
* Parses numbering.xml to extract:
|
|
15
|
+
* - Abstract numbering definitions (templates with levels)
|
|
16
|
+
* - Numbering instances (concrete references with optional overrides)
|
|
17
|
+
*
|
|
18
|
+
* OOXML Structure:
|
|
19
|
+
* - w:abstractNum - Template definitions with 9 levels (0-8)
|
|
20
|
+
* - w:num - Instances that reference abstractNum and can override levels
|
|
21
|
+
* - w:lvl - Level definition with start, format, text pattern, etc.
|
|
22
|
+
*/
|
|
10
23
|
/** `w:abstractNum` reads its id; everything else it carries is the remainder's. */
|
|
11
24
|
const MODELLED_ABSTRACT_NUM_ATTRIBUTES = /* @__PURE__ */ new Set(["abstractNumId"]);
|
|
12
25
|
/** `w:lvl` reads the level it defines and Word's two template markers. */
|
|
@@ -117,7 +130,6 @@ function parseAbstractNumbering(element) {
|
|
|
117
130
|
return abstractNum;
|
|
118
131
|
}
|
|
119
132
|
/** ECMA-376 §17.9.1: a `w:abstractNum` defines levels 0 through 8 and no more. */
|
|
120
|
-
const MAX_LIST_LEVEL = 8;
|
|
121
133
|
const MULTI_LEVEL_TYPES = [
|
|
122
134
|
"hybridMultilevel",
|
|
123
135
|
"multilevel",
|
|
@@ -392,7 +404,7 @@ function createNumberingMap(definitions) {
|
|
|
392
404
|
return {
|
|
393
405
|
definitions,
|
|
394
406
|
getLevel(numId, ilvl) {
|
|
395
|
-
if (ilvl
|
|
407
|
+
if (!isNumberingLevel(ilvl)) return null;
|
|
396
408
|
const num = numMap.get(numId);
|
|
397
409
|
if (!num) return null;
|
|
398
410
|
if (num.levelOverrides) {
|
|
@@ -524,7 +536,9 @@ function getBulletCharacter(level) {
|
|
|
524
536
|
function isBulletLevel(level) {
|
|
525
537
|
return level.numFmt === "bullet" || level.numFmt === "none";
|
|
526
538
|
}
|
|
539
|
+
/** Whether a numbering definition uses a bullet marker rather than a numeric or hidden one. */
|
|
540
|
+
const numberingLevelUsesBulletMarker = (level) => level?.numFmt === "bullet";
|
|
527
541
|
/** Whether a numbering level reserves horizontal space for a visible marker. */
|
|
528
542
|
const numberingLevelHasMarkerSlot = (level) => level.numFmt !== "none";
|
|
529
543
|
//#endregion
|
|
530
|
-
export { computeListRendering, counterFormatOf, createNumberingMap, customNumberFormatPadWidth, formatOoxmlCounter as formatNumber, getBulletCharacter, getCachedNumberingMap, isBulletLevel, markerAlignmentForLevel, markerFormattingFromLevel, numberingLevelHasMarkerSlot, padDecimal, parseNumbering, renderListMarker };
|
|
544
|
+
export { computeListRendering, counterFormatOf, createNumberingMap, customNumberFormatPadWidth, formatOoxmlCounter as formatNumber, getBulletCharacter, getCachedNumberingMap, isBulletLevel, markerAlignmentForLevel, markerFormattingFromLevel, numberingLevelHasMarkerSlot, numberingLevelUsesBulletMarker, padDecimal, parseNumbering, renderListMarker };
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import JSZip from "jszip";
|
|
2
2
|
//#region src/docx/packageParts.d.ts
|
|
3
|
+
/** Resolve an internal URI reference once, before comparing it with ZIP entries. */
|
|
4
|
+
declare const resolvePackageRelationshipTarget: (target: string, relsPath: string) => string | undefined;
|
|
3
5
|
/**
|
|
4
6
|
* Whether an entry path would escape the package when a host writes the archive
|
|
5
7
|
* to disk: absolute, backslash-separated, or climbing out through `..`. This is
|
|
@@ -76,4 +78,4 @@ type PackageIntegrityReport = {
|
|
|
76
78
|
*/
|
|
77
79
|
declare const checkPackageIntegrity: (zip: JSZip) => Promise<PackageIntegrityReport>;
|
|
78
80
|
//#endregion
|
|
79
|
-
export { PackageIntegrityReport, PackageReferenceRepair, checkPackageIntegrity, isUnsafePackagePath, reconcilePackageReferences, removeUnsafeEntries };
|
|
81
|
+
export { PackageIntegrityReport, PackageReferenceRepair, checkPackageIntegrity, isUnsafePackagePath, reconcilePackageReferences, removeUnsafeEntries, resolvePackageRelationshipTarget };
|