@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,214 @@
|
|
|
1
|
+
// src/ooxml/props.ts
|
|
2
|
+
import { childOrderOf } from "./childOrder.js";
|
|
3
|
+
import { attrsText, emptyTagXml } from "./element.js";
|
|
4
|
+
import { wName } from "./names.js";
|
|
5
|
+
import { parseAttrs, readTag } from "./tagScan.js";
|
|
6
|
+
import { elementChildren, localPart, namespaceDecls, parseXml } from "./xml.js";
|
|
7
|
+
function rawAttrs(source, tag) {
|
|
8
|
+
const closeLength = tag.kind === "empty" ? 2 : 1;
|
|
9
|
+
const attrs = source.slice(tag.nameEnd, tag.end - closeLength).trim();
|
|
10
|
+
return attrs.length > 0 ? attrs : null;
|
|
11
|
+
}
|
|
12
|
+
function innerXml(xml) {
|
|
13
|
+
const open = readTag(xml, 0);
|
|
14
|
+
if (!open || xml[0] !== "<" || open.kind !== "open") return "";
|
|
15
|
+
const close = xml.lastIndexOf("</");
|
|
16
|
+
return close > open.end ? xml.slice(open.end, close) : "";
|
|
17
|
+
}
|
|
18
|
+
function parseProps(xml) {
|
|
19
|
+
const open = readTag(xml, 0);
|
|
20
|
+
if (!open || xml[0] !== "<") return null;
|
|
21
|
+
const attrs = rawAttrs(xml, open);
|
|
22
|
+
if (open.kind === "empty") {
|
|
23
|
+
return open.end === xml.length ? { tag: open.name, attrs, children: [] } : null;
|
|
24
|
+
}
|
|
25
|
+
if (open.kind !== "open") return null;
|
|
26
|
+
const children = [];
|
|
27
|
+
let depth = 0;
|
|
28
|
+
let childStart = -1;
|
|
29
|
+
let childName = "";
|
|
30
|
+
let i = open.end;
|
|
31
|
+
let gapStart = open.end;
|
|
32
|
+
const gapBefore = (start) => {
|
|
33
|
+
const gap = xml.slice(gapStart, start);
|
|
34
|
+
return gap.length > 0 ? { before: gap } : {};
|
|
35
|
+
};
|
|
36
|
+
while (i < xml.length) {
|
|
37
|
+
const lt = xml.indexOf("<", i);
|
|
38
|
+
if (lt === -1) return null;
|
|
39
|
+
const tag = readTag(xml, lt);
|
|
40
|
+
if (!tag) return null;
|
|
41
|
+
if (tag.kind === "other") {
|
|
42
|
+
i = tag.end;
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (depth === 0) {
|
|
46
|
+
if (tag.kind === "close") {
|
|
47
|
+
if (tag.name !== open.name || tag.end !== xml.length) return null;
|
|
48
|
+
const tail = xml.slice(gapStart, lt);
|
|
49
|
+
return tail.length > 0 ? { tag: open.name, attrs, children, tail } : { tag: open.name, attrs, children };
|
|
50
|
+
}
|
|
51
|
+
childStart = lt;
|
|
52
|
+
childName = tag.name;
|
|
53
|
+
if (tag.kind === "empty") {
|
|
54
|
+
children.push({
|
|
55
|
+
name: localPart(childName),
|
|
56
|
+
xml: xml.slice(childStart, tag.end),
|
|
57
|
+
...gapBefore(childStart)
|
|
58
|
+
});
|
|
59
|
+
gapStart = tag.end;
|
|
60
|
+
} else {
|
|
61
|
+
depth = 1;
|
|
62
|
+
}
|
|
63
|
+
} else if (tag.kind === "open") {
|
|
64
|
+
depth += 1;
|
|
65
|
+
} else if (tag.kind === "close") {
|
|
66
|
+
depth -= 1;
|
|
67
|
+
if (depth === 0) {
|
|
68
|
+
children.push({
|
|
69
|
+
name: localPart(childName),
|
|
70
|
+
xml: xml.slice(childStart, tag.end),
|
|
71
|
+
...gapBefore(childStart)
|
|
72
|
+
});
|
|
73
|
+
gapStart = tag.end;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
i = tag.end;
|
|
77
|
+
}
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
function renderProps(props) {
|
|
81
|
+
const tail = props.tail ?? "";
|
|
82
|
+
if (props.children.length === 0 && tail.trim().length === 0) return "";
|
|
83
|
+
const open = props.attrs ? `<${props.tag} ${props.attrs}>` : `<${props.tag}>`;
|
|
84
|
+
const inner = props.children.map((child) => (child.before ?? "") + child.xml).join("");
|
|
85
|
+
return open + inner + tail + `</${props.tag}>`;
|
|
86
|
+
}
|
|
87
|
+
function insertIndex(children, name, order, tag) {
|
|
88
|
+
const target = order.indexOf(name);
|
|
89
|
+
if (target === -1) {
|
|
90
|
+
throw new Error(
|
|
91
|
+
`${name} is not a child the order of ${tag} knows; add it to CHILD_ORDER`
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
const at = children.findIndex((child) => order.indexOf(child.name) > target);
|
|
95
|
+
return at === -1 ? children.length : at;
|
|
96
|
+
}
|
|
97
|
+
function dropChildren(children, name) {
|
|
98
|
+
const kept = [];
|
|
99
|
+
let carried = "";
|
|
100
|
+
for (const child of children) {
|
|
101
|
+
const before = carried + (child.before ?? "");
|
|
102
|
+
if (child.name === name) {
|
|
103
|
+
carried = before;
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
carried = "";
|
|
107
|
+
kept.push(
|
|
108
|
+
before === "" ? { name: child.name, xml: child.xml } : { ...child, before }
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
return { kept, carried };
|
|
112
|
+
}
|
|
113
|
+
function tailWith(props, carried) {
|
|
114
|
+
const tail = carried + (props.tail ?? "");
|
|
115
|
+
return tail === "" ? {} : { tail };
|
|
116
|
+
}
|
|
117
|
+
function setChild(props, name, xml, parent) {
|
|
118
|
+
const order = childOrderOf(localPart(props.tag), parent);
|
|
119
|
+
const at = props.children.findIndex((entry) => entry.name === name);
|
|
120
|
+
if (at !== -1 && xml !== null) {
|
|
121
|
+
const rest = dropChildren(props.children.slice(at + 1), name);
|
|
122
|
+
return {
|
|
123
|
+
...props,
|
|
124
|
+
children: [
|
|
125
|
+
...props.children.slice(0, at),
|
|
126
|
+
{ ...props.children[at], xml },
|
|
127
|
+
...rest.kept
|
|
128
|
+
],
|
|
129
|
+
...tailWith(props, rest.carried)
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
const { kept, carried } = dropChildren(props.children, name);
|
|
133
|
+
if (xml === null) {
|
|
134
|
+
return { ...props, children: kept, ...tailWith(props, carried) };
|
|
135
|
+
}
|
|
136
|
+
const index = insertIndex(kept, name, order, props.tag);
|
|
137
|
+
return {
|
|
138
|
+
...props,
|
|
139
|
+
children: [...kept.slice(0, index), { name, xml }, ...kept.slice(index)],
|
|
140
|
+
...tailWith(props, carried)
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
function propsChild(children, name) {
|
|
144
|
+
return children.find((child) => child.name === name);
|
|
145
|
+
}
|
|
146
|
+
function attrsOf(props) {
|
|
147
|
+
return props.attrs === null ? [] : parseAttrs(props.attrs);
|
|
148
|
+
}
|
|
149
|
+
function withAttrs(props, attrs) {
|
|
150
|
+
return { ...props, attrs: attrs.length === 0 ? null : attrsText(attrs) };
|
|
151
|
+
}
|
|
152
|
+
function childElement(props, name) {
|
|
153
|
+
const child = propsChild(props.children, name);
|
|
154
|
+
if (child === void 0) return { tag: null, attrs: [] };
|
|
155
|
+
const parsed = parseProps(child.xml);
|
|
156
|
+
const attrs = parsed === null ? null : attrsOf(parsed);
|
|
157
|
+
return parsed === null || attrs === null ? null : { tag: parsed.tag, attrs };
|
|
158
|
+
}
|
|
159
|
+
function renderElement(props) {
|
|
160
|
+
return renderProps(props) || emptyTagXml(props.tag, props.attrs);
|
|
161
|
+
}
|
|
162
|
+
function orderedElement(tag, attrs, children) {
|
|
163
|
+
const empty = withAttrs({ tag, attrs: null, children: [] }, attrs);
|
|
164
|
+
return renderElement(
|
|
165
|
+
children.reduce(
|
|
166
|
+
(props, child) => setChild(props, child.name, child.xml),
|
|
167
|
+
empty
|
|
168
|
+
)
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
function editPath(props, path, edit, parent) {
|
|
172
|
+
const [name, ...rest] = path;
|
|
173
|
+
const current = propsChild(props.children, name);
|
|
174
|
+
const parsed = current === void 0 ? null : parseProps(current.xml);
|
|
175
|
+
if (current !== void 0 && parsed === null) return null;
|
|
176
|
+
if (rest.length === 0) {
|
|
177
|
+
const next = edit(parsed);
|
|
178
|
+
return setChild(props, name, next && renderElement(next), parent);
|
|
179
|
+
}
|
|
180
|
+
const nested = editPath(
|
|
181
|
+
parsed ?? { tag: wName(name), attrs: null, children: [] },
|
|
182
|
+
rest,
|
|
183
|
+
edit,
|
|
184
|
+
localPart(props.tag)
|
|
185
|
+
);
|
|
186
|
+
if (nested === null) return null;
|
|
187
|
+
const rendered = renderProps(nested);
|
|
188
|
+
return setChild(props, name, rendered === "" ? null : rendered, parent);
|
|
189
|
+
}
|
|
190
|
+
function editChild(props, path, edit) {
|
|
191
|
+
return editPath(props, path, edit, void 0);
|
|
192
|
+
}
|
|
193
|
+
function parsePropsXml(xml) {
|
|
194
|
+
try {
|
|
195
|
+
const wrapped = `<props ${namespaceDecls(xml)}>${xml}</props>`;
|
|
196
|
+
return elementChildren(parseXml(wrapped).documentElement)[0] ?? null;
|
|
197
|
+
} catch {
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
export {
|
|
202
|
+
attrsOf,
|
|
203
|
+
childElement,
|
|
204
|
+
editChild,
|
|
205
|
+
innerXml,
|
|
206
|
+
orderedElement,
|
|
207
|
+
parseProps,
|
|
208
|
+
parsePropsXml,
|
|
209
|
+
propsChild,
|
|
210
|
+
renderElement,
|
|
211
|
+
renderProps,
|
|
212
|
+
setChild,
|
|
213
|
+
withAttrs
|
|
214
|
+
};
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The simple types the schema names, one `{parse, format}` pair each.
|
|
3
|
+
*
|
|
4
|
+
* A measurement in OOXML is a union rather than a count. `w:pgSz w:w` is either a number of twips
|
|
5
|
+
* or a universal measure such as `8.5in` (§22.9.2.14, §22.9.2.15), and reading only the leading
|
|
6
|
+
* digits turns Letter paper into a page 8.5 twips wide. A boolean is any of `1`, `0`, `true`,
|
|
7
|
+
* `false`, `on` and `off` (§17.17.4). Deciding either at the call site is how a document comes to
|
|
8
|
+
* be read one way in one reader and another way in the next, so both are decided here, and the
|
|
9
|
+
* writer that puts a value back reaches for the same pair.
|
|
10
|
+
*
|
|
11
|
+
* Readers accept the decimal counts some producers write in integer slots. `format` answers null
|
|
12
|
+
* for a value it cannot record; a caller that intends to round must do so before formatting.
|
|
13
|
+
*/
|
|
14
|
+
import { type TabAlignment, type TabLeader } from "../model/tabStops";
|
|
15
|
+
export interface SimpleType<T> {
|
|
16
|
+
/** null for an absent or unreadable value; see the type's producer compatibility rules */
|
|
17
|
+
parse(value: string | null): T | null;
|
|
18
|
+
/** null for a value the type cannot record */
|
|
19
|
+
format(value: T): string | null;
|
|
20
|
+
}
|
|
21
|
+
/** A twip is a twentieth of a point */
|
|
22
|
+
export declare const TWIPS_PER_PT = 20;
|
|
23
|
+
export declare const TWIPS_PER_INCH = 1440;
|
|
24
|
+
/** `w:sz` counts a font size in half-points, so 24 is 12pt */
|
|
25
|
+
export declare const HALF_POINTS_PER_PT = 2;
|
|
26
|
+
/** `w:sz` on a border counts its thickness in eighths of a point */
|
|
27
|
+
export declare const EIGHTHS_PER_PT = 8;
|
|
28
|
+
/**
|
|
29
|
+
* The largest font size a writer here records.
|
|
30
|
+
*
|
|
31
|
+
* The schema puts no ceiling on `w:sz`, but Word's own limit is 819pt, and a size beyond it is
|
|
32
|
+
* one no word processor will show back.
|
|
33
|
+
*/
|
|
34
|
+
export declare const MAX_FONT_SIZE_PT = 819;
|
|
35
|
+
/** `8.5in` -> 12240. null for anything ST_UniversalMeasure does not admit (§22.9.2.15) */
|
|
36
|
+
export declare function universalMeasureToTwips(value: string): number | null;
|
|
37
|
+
/** Twips, unsigned (§22.9.2.14): `w:pgSz`, `w:trHeight`, `w:spacing/@before`, `w:tcMar` */
|
|
38
|
+
export declare const ST_TwipsMeasure: SimpleType<number>;
|
|
39
|
+
/** Twips, signed (§17.18.81): `w:ind`, `w:tab/@pos`, `w:spacing/@line` */
|
|
40
|
+
export declare const ST_SignedTwipsMeasure: SimpleType<number>;
|
|
41
|
+
/**
|
|
42
|
+
* Half-points (§17.18.42): `w:sz` and `w:szCs`.
|
|
43
|
+
*
|
|
44
|
+
* `format` refuses a size no writer here records: one off the half-point step the unit counts in,
|
|
45
|
+
* one of nothing at all, and one past `MAX_FONT_SIZE_PT`.
|
|
46
|
+
*/
|
|
47
|
+
export declare const ST_HpsMeasure: SimpleType<number>;
|
|
48
|
+
/** Half-points, signed (§17.18.80): `w:position` */
|
|
49
|
+
export declare const ST_SignedHpsMeasure: SimpleType<number>;
|
|
50
|
+
/**
|
|
51
|
+
* Eighths of a point (§17.18.23): the thickness of a border side.
|
|
52
|
+
*
|
|
53
|
+
* Alone among the measurements this restricts `ST_UnsignedDecimalNumber` rather than uniting with a
|
|
54
|
+
* universal measure, so a thickness is a count and a unit written beside it is not one.
|
|
55
|
+
*/
|
|
56
|
+
export declare const ST_EighthPointMeasure: SimpleType<number>;
|
|
57
|
+
/** A whole number, signed (§17.18.10): `w:numId`, `w:ilvl`, `w:start` */
|
|
58
|
+
export declare const ST_DecimalNumber: SimpleType<number>;
|
|
59
|
+
/** A whole number, unsigned (§22.9.2.16): `w:id` on a comment or a note */
|
|
60
|
+
export declare const ST_UnsignedDecimalNumber: SimpleType<number>;
|
|
61
|
+
/**
|
|
62
|
+
* A boolean (§17.17.4).
|
|
63
|
+
*
|
|
64
|
+
* The schema unites `xsd:boolean` with the pair `on` and `off`, so all six spellings say the same
|
|
65
|
+
* thing and nothing else says either. An element that carries no `w:val` at all is on, which is a
|
|
66
|
+
* rule about the element rather than about this value, so it is the caller that applies it.
|
|
67
|
+
*/
|
|
68
|
+
export declare const ST_OnOff: SimpleType<boolean>;
|
|
69
|
+
/** A color, which is either six hex digits or the word `auto` (§17.18.38) */
|
|
70
|
+
export type HexColor = {
|
|
71
|
+
kind: "auto";
|
|
72
|
+
} | {
|
|
73
|
+
kind: "rgb";
|
|
74
|
+
hex: string;
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* `ST_HexColor` keeps the digits exactly as the document spelled them, so a color read and written
|
|
78
|
+
* back leaves the file as it was. A caller comparing two colors gathers them first.
|
|
79
|
+
*/
|
|
80
|
+
export declare const ST_HexColor: SimpleType<HexColor>;
|
|
81
|
+
/**
|
|
82
|
+
* The width of a table or a cell (§17.18.107), which `w:type` beside it says how to read.
|
|
83
|
+
*
|
|
84
|
+
* `number` is the bare count, meaning twips under `dxa` and fiftieths of a percent under `pct`.
|
|
85
|
+
* `percent` carried its own `%`, and `twips` was written as a universal measure, which says an
|
|
86
|
+
* absolute width whatever `w:type` claims.
|
|
87
|
+
*/
|
|
88
|
+
export type MeasurementOrPercent = {
|
|
89
|
+
kind: "number";
|
|
90
|
+
value: number;
|
|
91
|
+
} | {
|
|
92
|
+
kind: "percent";
|
|
93
|
+
value: number;
|
|
94
|
+
} | {
|
|
95
|
+
kind: "twips";
|
|
96
|
+
value: number;
|
|
97
|
+
};
|
|
98
|
+
export declare const ST_MeasurementOrPercent: SimpleType<MeasurementOrPercent>;
|
|
99
|
+
/** The kinds of custom tab stop, with the two Transitional spellings folded in */
|
|
100
|
+
export type TabJc = TabAlignment | "bar" | "clear";
|
|
101
|
+
export declare const ST_TabJc: SimpleType<TabJc>;
|
|
102
|
+
/** The character a tab stop draws the space it covers with (§17.18.85) */
|
|
103
|
+
export declare const ST_TabTlc: SimpleType<TabLeader>;
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
// src/ooxml/simpleTypes.ts
|
|
2
|
+
import {
|
|
3
|
+
TAB_LEADERS,
|
|
4
|
+
TAB_STOP_ALIGNMENTS
|
|
5
|
+
} from "../model/tabStops.js";
|
|
6
|
+
var TWIPS_PER_PT = 20;
|
|
7
|
+
var TWIPS_PER_INCH = 1440;
|
|
8
|
+
var HALF_POINTS_PER_PT = 2;
|
|
9
|
+
var EIGHTHS_PER_PT = 8;
|
|
10
|
+
var MAX_FONT_SIZE_PT = 819;
|
|
11
|
+
var TWIPS_PER_UNIT = {
|
|
12
|
+
mm: TWIPS_PER_INCH / 25.4,
|
|
13
|
+
cm: TWIPS_PER_INCH / 2.54,
|
|
14
|
+
in: TWIPS_PER_INCH,
|
|
15
|
+
pt: TWIPS_PER_PT,
|
|
16
|
+
pc: TWIPS_PER_PT * 12,
|
|
17
|
+
pi: TWIPS_PER_PT * 12
|
|
18
|
+
};
|
|
19
|
+
var UNIVERSAL_MEASURE = /^(-?[0-9]+(?:\.[0-9]+)?)(mm|cm|in|pt|pc|pi)$/;
|
|
20
|
+
function universalMeasureToTwips(value) {
|
|
21
|
+
const matched = UNIVERSAL_MEASURE.exec(value.trim());
|
|
22
|
+
if (!matched) return null;
|
|
23
|
+
const amount = Number(matched[1]);
|
|
24
|
+
const twips = amount * TWIPS_PER_UNIT[matched[2]];
|
|
25
|
+
return Number.isFinite(twips) ? twips : null;
|
|
26
|
+
}
|
|
27
|
+
var DECIMAL_NUMBER = /^[+-]?[0-9]+(?:\.[0-9]+)?$/;
|
|
28
|
+
function decimalNumber(value) {
|
|
29
|
+
const text = value.trim();
|
|
30
|
+
if (!DECIMAL_NUMBER.test(text)) return null;
|
|
31
|
+
const parsed = Number(text);
|
|
32
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
33
|
+
}
|
|
34
|
+
function measure({ twipsPerUnit, signed }) {
|
|
35
|
+
const admits = (value) => signed || value >= 0;
|
|
36
|
+
return {
|
|
37
|
+
parse(value) {
|
|
38
|
+
if (value === null) return null;
|
|
39
|
+
const counted = decimalNumber(value);
|
|
40
|
+
if (counted !== null) return admits(counted) ? counted : null;
|
|
41
|
+
const twips = universalMeasureToTwips(value);
|
|
42
|
+
if (twips === null) return null;
|
|
43
|
+
const converted = twips / twipsPerUnit;
|
|
44
|
+
return admits(converted) ? converted : null;
|
|
45
|
+
},
|
|
46
|
+
format(value) {
|
|
47
|
+
if (!Number.isSafeInteger(value) || !admits(value)) return null;
|
|
48
|
+
return `${value}`;
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
var ST_TwipsMeasure = measure({
|
|
53
|
+
twipsPerUnit: 1,
|
|
54
|
+
signed: false
|
|
55
|
+
});
|
|
56
|
+
var ST_SignedTwipsMeasure = measure({
|
|
57
|
+
twipsPerUnit: 1,
|
|
58
|
+
signed: true
|
|
59
|
+
});
|
|
60
|
+
var HPS_MEASURE = measure({
|
|
61
|
+
twipsPerUnit: TWIPS_PER_PT / HALF_POINTS_PER_PT,
|
|
62
|
+
signed: false
|
|
63
|
+
});
|
|
64
|
+
var ST_HpsMeasure = {
|
|
65
|
+
parse: HPS_MEASURE.parse,
|
|
66
|
+
format(value) {
|
|
67
|
+
if (value <= 0 || value > MAX_FONT_SIZE_PT * HALF_POINTS_PER_PT) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
return HPS_MEASURE.format(value);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
var ST_SignedHpsMeasure = measure({
|
|
74
|
+
twipsPerUnit: TWIPS_PER_PT / HALF_POINTS_PER_PT,
|
|
75
|
+
signed: true
|
|
76
|
+
});
|
|
77
|
+
function wholeNumber(signed) {
|
|
78
|
+
const admits = (value) => signed || value >= 0;
|
|
79
|
+
return {
|
|
80
|
+
parse(value) {
|
|
81
|
+
if (value === null) return null;
|
|
82
|
+
const parsed = decimalNumber(value);
|
|
83
|
+
if (parsed === null) return null;
|
|
84
|
+
const whole = Math.trunc(parsed);
|
|
85
|
+
return Number.isSafeInteger(whole) && admits(whole) ? whole : null;
|
|
86
|
+
},
|
|
87
|
+
format(value) {
|
|
88
|
+
if (!Number.isSafeInteger(value) || !admits(value)) return null;
|
|
89
|
+
return `${value}`;
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
var ST_EighthPointMeasure = wholeNumber(false);
|
|
94
|
+
var ST_DecimalNumber = wholeNumber(true);
|
|
95
|
+
var ST_UnsignedDecimalNumber = wholeNumber(false);
|
|
96
|
+
var ST_OnOff = {
|
|
97
|
+
parse(value) {
|
|
98
|
+
if (value === null) return null;
|
|
99
|
+
const text = value.trim();
|
|
100
|
+
if (text === "1" || text === "true" || text === "on") return true;
|
|
101
|
+
if (text === "0" || text === "false" || text === "off") return false;
|
|
102
|
+
return null;
|
|
103
|
+
},
|
|
104
|
+
format(value) {
|
|
105
|
+
return value ? "1" : "0";
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
var HEX_RGB = /^[0-9a-fA-F]{6}$/;
|
|
109
|
+
var ST_HexColor = {
|
|
110
|
+
parse(value) {
|
|
111
|
+
if (value === null) return null;
|
|
112
|
+
if (value === "auto") return { kind: "auto" };
|
|
113
|
+
return HEX_RGB.test(value) ? { kind: "rgb", hex: value } : null;
|
|
114
|
+
},
|
|
115
|
+
format(value) {
|
|
116
|
+
return value.kind === "auto" ? "auto" : value.hex;
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
var PERCENT = /^(-?[0-9]+(?:\.[0-9]+)?)%$/;
|
|
120
|
+
var ST_MeasurementOrPercent = {
|
|
121
|
+
parse(value) {
|
|
122
|
+
if (value === null) return null;
|
|
123
|
+
const text = value.trim();
|
|
124
|
+
const percent = PERCENT.exec(text);
|
|
125
|
+
if (percent) {
|
|
126
|
+
const amount = decimalNumber(percent[1]);
|
|
127
|
+
return amount === null ? null : { kind: "percent", value: amount };
|
|
128
|
+
}
|
|
129
|
+
const counted = decimalNumber(text);
|
|
130
|
+
if (counted !== null) return { kind: "number", value: counted };
|
|
131
|
+
const twips = universalMeasureToTwips(text);
|
|
132
|
+
return twips === null ? null : { kind: "twips", value: twips };
|
|
133
|
+
},
|
|
134
|
+
format(value) {
|
|
135
|
+
if (!Number.isFinite(value.value)) return null;
|
|
136
|
+
if (value.kind === "percent") return `${value.value}%`;
|
|
137
|
+
if (value.kind === "twips") return `${value.value / TWIPS_PER_PT}pt`;
|
|
138
|
+
return ST_DecimalNumber.format(value.value);
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
var TAB_JC_BY_VALUE = {
|
|
142
|
+
...Object.fromEntries(TAB_STOP_ALIGNMENTS.map((align) => [align, align])),
|
|
143
|
+
clear: "clear",
|
|
144
|
+
left: "start",
|
|
145
|
+
right: "end"
|
|
146
|
+
};
|
|
147
|
+
var ST_TabJc = {
|
|
148
|
+
parse(value) {
|
|
149
|
+
return value !== null && Object.hasOwn(TAB_JC_BY_VALUE, value) ? TAB_JC_BY_VALUE[value] : null;
|
|
150
|
+
},
|
|
151
|
+
format(value) {
|
|
152
|
+
return value;
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
var ST_TabTlc = {
|
|
156
|
+
parse(value) {
|
|
157
|
+
return TAB_LEADERS.find((leader) => leader === value) ?? null;
|
|
158
|
+
},
|
|
159
|
+
format(value) {
|
|
160
|
+
return value;
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
export {
|
|
164
|
+
EIGHTHS_PER_PT,
|
|
165
|
+
HALF_POINTS_PER_PT,
|
|
166
|
+
MAX_FONT_SIZE_PT,
|
|
167
|
+
ST_DecimalNumber,
|
|
168
|
+
ST_EighthPointMeasure,
|
|
169
|
+
ST_HexColor,
|
|
170
|
+
ST_HpsMeasure,
|
|
171
|
+
ST_MeasurementOrPercent,
|
|
172
|
+
ST_OnOff,
|
|
173
|
+
ST_SignedHpsMeasure,
|
|
174
|
+
ST_SignedTwipsMeasure,
|
|
175
|
+
ST_TabJc,
|
|
176
|
+
ST_TabTlc,
|
|
177
|
+
ST_TwipsMeasure,
|
|
178
|
+
ST_UnsignedDecimalNumber,
|
|
179
|
+
TWIPS_PER_INCH,
|
|
180
|
+
TWIPS_PER_PT,
|
|
181
|
+
universalMeasureToTwips
|
|
182
|
+
};
|
package/dist/ooxml/tabStops.js
CHANGED
|
@@ -1,28 +1,7 @@
|
|
|
1
1
|
// src/ooxml/tabStops.ts
|
|
2
|
+
import { ST_SignedTwipsMeasure, ST_TabJc, ST_TabTlc } from "./simpleTypes.js";
|
|
2
3
|
import { twipsToPt, wAttr } from "./units.js";
|
|
3
4
|
import { childByLocalName } from "./xml.js";
|
|
4
|
-
var ALIGN_BY_VALUE = {
|
|
5
|
-
left: "start",
|
|
6
|
-
start: "start",
|
|
7
|
-
center: "center",
|
|
8
|
-
right: "end",
|
|
9
|
-
end: "end",
|
|
10
|
-
decimal: "decimal",
|
|
11
|
-
num: "num",
|
|
12
|
-
bar: "bar",
|
|
13
|
-
clear: "clear"
|
|
14
|
-
};
|
|
15
|
-
var LEADERS = /* @__PURE__ */ new Set([
|
|
16
|
-
"none",
|
|
17
|
-
"dot",
|
|
18
|
-
"hyphen",
|
|
19
|
-
"underscore",
|
|
20
|
-
"heavy",
|
|
21
|
-
"middleDot"
|
|
22
|
-
]);
|
|
23
|
-
function tabLeader(value) {
|
|
24
|
-
return value !== null && LEADERS.has(value) ? value : void 0;
|
|
25
|
-
}
|
|
26
5
|
function readTabStopDirectives(pPr) {
|
|
27
6
|
if (!pPr) return [];
|
|
28
7
|
const tabs = childByLocalName(pPr, "tabs");
|
|
@@ -30,18 +9,20 @@ function readTabStopDirectives(pPr) {
|
|
|
30
9
|
const stops = [];
|
|
31
10
|
for (const tab of Array.from(tabs.children)) {
|
|
32
11
|
if (tab.localName !== "tab") continue;
|
|
33
|
-
const positionPt = twipsToPt(
|
|
34
|
-
|
|
35
|
-
|
|
12
|
+
const positionPt = twipsToPt(
|
|
13
|
+
ST_SignedTwipsMeasure.parse(wAttr(tab, "pos"))
|
|
14
|
+
);
|
|
15
|
+
const align = ST_TabJc.parse(wAttr(tab, "val"));
|
|
16
|
+
if (positionPt === null || align === null) continue;
|
|
36
17
|
if (align === "clear") {
|
|
37
18
|
stops.push({ positionPt, align });
|
|
38
19
|
continue;
|
|
39
20
|
}
|
|
40
|
-
const leader =
|
|
21
|
+
const leader = ST_TabTlc.parse(wAttr(tab, "leader"));
|
|
41
22
|
stops.push({
|
|
42
23
|
positionPt,
|
|
43
24
|
align,
|
|
44
|
-
...leader ===
|
|
25
|
+
...leader === null ? {} : { leader }
|
|
45
26
|
});
|
|
46
27
|
}
|
|
47
28
|
return stops;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading one tag out of a part or a fragment without parsing the whole of it.
|
|
3
|
+
*
|
|
4
|
+
* Everything the writers hold is text, and an edit slices one element or one attribute out of it,
|
|
5
|
+
* so the spots those slices run between have to be found in the text itself. A `>` may stand
|
|
6
|
+
* inside an attribute value and a `<` inside a comment, which is why a tag is read construct by
|
|
7
|
+
* construct rather than searched for.
|
|
8
|
+
*/
|
|
9
|
+
import type { XmlAttr } from "./element";
|
|
10
|
+
export type TagKind = "open" | "close" | "empty" | "other";
|
|
11
|
+
export interface Tag {
|
|
12
|
+
kind: TagKind;
|
|
13
|
+
/** The name exactly as written, prefix included. Empty for a construct that has none */
|
|
14
|
+
name: string;
|
|
15
|
+
/** The spot where the tag name ends. This is the start of the attribute string */
|
|
16
|
+
nameEnd: number;
|
|
17
|
+
/** The spot right after the tag ends */
|
|
18
|
+
end: number;
|
|
19
|
+
}
|
|
20
|
+
/** Reads a single tag starting at a `<`. null if it cannot be made out */
|
|
21
|
+
export declare function readTag(source: string, lt: number): Tag | null;
|
|
22
|
+
/**
|
|
23
|
+
* Where the root element's opening tag starts, past the prolog.
|
|
24
|
+
*
|
|
25
|
+
* The prolog is walked construct by construct so that a `<` inside a comment or a processing
|
|
26
|
+
* instruction is not taken for the root. -1 when the source holds no element at all.
|
|
27
|
+
*/
|
|
28
|
+
export declare function rootTagAt(xml: string): number;
|
|
29
|
+
/**
|
|
30
|
+
* The attribute text of an opening tag as pairs, references decoded, each name spelled as it was
|
|
31
|
+
* written. null for a shape a parser would refuse: an unquoted value, a missing name, one name
|
|
32
|
+
* given twice, or a reference nothing declares.
|
|
33
|
+
*/
|
|
34
|
+
export declare function parseAttrs(raw: string): XmlAttr[] | null;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// src/ooxml/tagScan.ts
|
|
2
|
+
function skipPast(source, from, marker) {
|
|
3
|
+
const at = source.indexOf(marker, from);
|
|
4
|
+
return at === -1 ? -1 : at + marker.length;
|
|
5
|
+
}
|
|
6
|
+
function otherTag(end) {
|
|
7
|
+
return end === -1 ? null : { kind: "other", name: "", nameEnd: end, end };
|
|
8
|
+
}
|
|
9
|
+
function readTag(source, lt) {
|
|
10
|
+
if (source.startsWith("<?", lt)) return otherTag(skipPast(source, lt, "?>"));
|
|
11
|
+
if (source.startsWith("<!--", lt))
|
|
12
|
+
return otherTag(skipPast(source, lt, "-->"));
|
|
13
|
+
if (source.startsWith("<![CDATA[", lt))
|
|
14
|
+
return otherTag(skipPast(source, lt, "]]>"));
|
|
15
|
+
if (source.startsWith("<!", lt)) return otherTag(skipPast(source, lt, ">"));
|
|
16
|
+
const closing = source.startsWith("</", lt);
|
|
17
|
+
let i = lt + (closing ? 2 : 1);
|
|
18
|
+
const nameStart = i;
|
|
19
|
+
while (i < source.length && !" \r\n/>".includes(source[i])) i += 1;
|
|
20
|
+
const name = source.slice(nameStart, i);
|
|
21
|
+
if (!name) return null;
|
|
22
|
+
const nameEnd = i;
|
|
23
|
+
let quote = null;
|
|
24
|
+
while (i < source.length) {
|
|
25
|
+
const ch = source[i];
|
|
26
|
+
if (quote !== null) {
|
|
27
|
+
if (ch === quote) quote = null;
|
|
28
|
+
} else if (ch === '"' || ch === "'") {
|
|
29
|
+
quote = ch;
|
|
30
|
+
} else if (ch === ">") {
|
|
31
|
+
const selfClosing = source[i - 1] === "/";
|
|
32
|
+
const kind = closing ? "close" : selfClosing ? "empty" : "open";
|
|
33
|
+
return { kind, name, nameEnd, end: i + 1 };
|
|
34
|
+
}
|
|
35
|
+
i += 1;
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
function rootTagAt(xml) {
|
|
40
|
+
let at = 0;
|
|
41
|
+
for (; ; ) {
|
|
42
|
+
const lt = xml.indexOf("<", at);
|
|
43
|
+
if (lt === -1) return -1;
|
|
44
|
+
const tag = readTag(xml, lt);
|
|
45
|
+
if (!tag) return -1;
|
|
46
|
+
if (tag.kind !== "other") return lt;
|
|
47
|
+
at = tag.end;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
var ENTITIES = {
|
|
51
|
+
amp: "&",
|
|
52
|
+
lt: "<",
|
|
53
|
+
gt: ">",
|
|
54
|
+
quot: '"',
|
|
55
|
+
apos: "'"
|
|
56
|
+
};
|
|
57
|
+
var HIGHEST_CODE_POINT = 1114111;
|
|
58
|
+
function referenceText(name) {
|
|
59
|
+
const named = ENTITIES[name];
|
|
60
|
+
if (named !== void 0) return named;
|
|
61
|
+
const numeric = /^#(?:[xX]([0-9a-fA-F]+)|(\d+))$/.exec(name);
|
|
62
|
+
if (!numeric) return null;
|
|
63
|
+
const [, hex, decimal] = numeric;
|
|
64
|
+
const code = Number.parseInt(hex ?? decimal, hex === void 0 ? 10 : 16);
|
|
65
|
+
if (code > HIGHEST_CODE_POINT || code >= 55296 && code <= 57343) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
return String.fromCodePoint(code);
|
|
69
|
+
}
|
|
70
|
+
function decodeReferences(value) {
|
|
71
|
+
if (!value.includes("&")) return value;
|
|
72
|
+
let decoded = "";
|
|
73
|
+
let at = 0;
|
|
74
|
+
for (; ; ) {
|
|
75
|
+
const amp = value.indexOf("&", at);
|
|
76
|
+
if (amp === -1) return decoded + value.slice(at);
|
|
77
|
+
const semicolon = value.indexOf(";", amp);
|
|
78
|
+
if (semicolon === -1) return null;
|
|
79
|
+
const text = referenceText(value.slice(amp + 1, semicolon));
|
|
80
|
+
if (text === null) return null;
|
|
81
|
+
decoded += value.slice(at, amp) + text;
|
|
82
|
+
at = semicolon + 1;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
var ATTRIBUTE = /(\s*)([^\s=/><"']+)\s*=\s*(?:"([^"<]*)"|'([^'<]*)')/y;
|
|
86
|
+
function parseAttrs(raw) {
|
|
87
|
+
const attrs = [];
|
|
88
|
+
const names = /* @__PURE__ */ new Set();
|
|
89
|
+
let at = 0;
|
|
90
|
+
for (; ; ) {
|
|
91
|
+
ATTRIBUTE.lastIndex = at;
|
|
92
|
+
const matched = ATTRIBUTE.exec(raw);
|
|
93
|
+
if (!matched) return raw.slice(at).trim() === "" ? attrs : null;
|
|
94
|
+
const [, separator, name, doubled, singled] = matched;
|
|
95
|
+
if (at > 0 && separator === "") return null;
|
|
96
|
+
if (names.has(name)) return null;
|
|
97
|
+
names.add(name);
|
|
98
|
+
const value = decodeReferences(doubled ?? singled);
|
|
99
|
+
if (value === null) return null;
|
|
100
|
+
attrs.push([name, value]);
|
|
101
|
+
at = ATTRIBUTE.lastIndex;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
export {
|
|
105
|
+
parseAttrs,
|
|
106
|
+
readTag,
|
|
107
|
+
rootTagAt
|
|
108
|
+
};
|