@linxiraos/pi-utils 1.0.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 +449 -0
- package/README.md +36 -0
- package/dist/types/abortable.d.ts +32 -0
- package/dist/types/acp/connection.d.ts +118 -0
- package/dist/types/acp/protocol.d.ts +526 -0
- package/dist/types/acp/schema.d.ts +41 -0
- package/dist/types/acp/stream.d.ts +8 -0
- package/dist/types/acp/transport.d.ts +81 -0
- package/dist/types/acp.d.ts +6 -0
- package/dist/types/async.d.ts +20 -0
- package/dist/types/binary.d.ts +17 -0
- package/dist/types/browsers.d.ts +68 -0
- package/dist/types/chalk.d.ts +125 -0
- package/dist/types/cli.d.ts +134 -0
- package/dist/types/color.d.ts +102 -0
- package/dist/types/dates.d.ts +7 -0
- package/dist/types/dirs.d.ts +282 -0
- package/dist/types/docx/converter.d.ts +46 -0
- package/dist/types/docx/xml.d.ts +26 -0
- package/dist/types/docx/zip.d.ts +6 -0
- package/dist/types/docx.d.ts +11 -0
- package/dist/types/dom/core.d.ts +431 -0
- package/dist/types/dom/parser.d.ts +7 -0
- package/dist/types/dom/selector.d.ts +5 -0
- package/dist/types/dom.d.ts +5 -0
- package/dist/types/env.d.ts +124 -0
- package/dist/types/fetch-retry.d.ts +96 -0
- package/dist/types/file-lock.d.ts +23 -0
- package/dist/types/format.d.ts +37 -0
- package/dist/types/frontmatter.d.ts +46 -0
- package/dist/types/fs-error.d.ts +31 -0
- package/dist/types/glob.d.ts +28 -0
- package/dist/types/headers.d.ts +34 -0
- package/dist/types/index.d.ts +39 -0
- package/dist/types/json-parse.d.ts +74 -0
- package/dist/types/json.d.ts +14 -0
- package/dist/types/logger/rotating-file.d.ts +18 -0
- package/dist/types/logger.d.ts +96 -0
- package/dist/types/loop-phase.d.ts +10 -0
- package/dist/types/lru.d.ts +46 -0
- package/dist/types/marked/core.d.ts +445 -0
- package/dist/types/marked.d.ts +2 -0
- package/dist/types/mermaid-ascii.d.ts +11 -0
- package/dist/types/mime.d.ts +29 -0
- package/dist/types/module-timer.d.ts +1 -0
- package/dist/types/path-tree.d.ts +76 -0
- package/dist/types/path.d.ts +2 -0
- package/dist/types/peek-file.d.ts +29 -0
- package/dist/types/postmortem.d.ts +104 -0
- package/dist/types/process-name.d.ts +7 -0
- package/dist/types/procmgr.d.ts +74 -0
- package/dist/types/prompt.d.ts +18 -0
- package/dist/types/ptree.d.ts +110 -0
- package/dist/types/readability/readability.d.ts +9 -0
- package/dist/types/readability/readerable.d.ts +10 -0
- package/dist/types/readability/types.d.ts +70 -0
- package/dist/types/readability.d.ts +4 -0
- package/dist/types/ring.d.ts +93 -0
- package/dist/types/runtime-install.d.ts +78 -0
- package/dist/types/sanitize-text.d.ts +29 -0
- package/dist/types/snowflake.d.ts +25 -0
- package/dist/types/stderr-guard.d.ts +22 -0
- package/dist/types/stream.d.ts +67 -0
- package/dist/types/tab-spacing.d.ts +24 -0
- package/dist/types/temp.d.ts +17 -0
- package/dist/types/template.d.ts +62 -0
- package/dist/types/timing-buffer.d.ts +22 -0
- package/dist/types/tls-fetch.d.ts +37 -0
- package/dist/types/turndown/gfm.d.ts +11 -0
- package/dist/types/turndown/html.d.ts +5 -0
- package/dist/types/turndown/service.d.ts +21 -0
- package/dist/types/turndown/types.d.ts +70 -0
- package/dist/types/turndown.d.ts +4 -0
- package/dist/types/type-guards.d.ts +5 -0
- package/dist/types/vendor/mermaid-ascii/ascii/ansi.d.ts +41 -0
- package/dist/types/vendor/mermaid-ascii/ascii/canvas.d.ts +89 -0
- package/dist/types/vendor/mermaid-ascii/ascii/class-diagram.d.ts +7 -0
- package/dist/types/vendor/mermaid-ascii/ascii/converter.d.ts +12 -0
- package/dist/types/vendor/mermaid-ascii/ascii/draw.d.ts +66 -0
- package/dist/types/vendor/mermaid-ascii/ascii/edge-bundling.d.ts +48 -0
- package/dist/types/vendor/mermaid-ascii/ascii/edge-routing.d.ts +43 -0
- package/dist/types/vendor/mermaid-ascii/ascii/er-diagram.d.ts +7 -0
- package/dist/types/vendor/mermaid-ascii/ascii/grid.d.ts +56 -0
- package/dist/types/vendor/mermaid-ascii/ascii/index.d.ts +65 -0
- package/dist/types/vendor/mermaid-ascii/ascii/multiline-utils.d.ts +27 -0
- package/dist/types/vendor/mermaid-ascii/ascii/pathfinder.d.ts +17 -0
- package/dist/types/vendor/mermaid-ascii/ascii/sequence.d.ts +7 -0
- package/dist/types/vendor/mermaid-ascii/ascii/shapes/circle.d.ts +11 -0
- package/dist/types/vendor/mermaid-ascii/ascii/shapes/corners.d.ts +34 -0
- package/dist/types/vendor/mermaid-ascii/ascii/shapes/diamond.d.ts +11 -0
- package/dist/types/vendor/mermaid-ascii/ascii/shapes/hexagon.d.ts +11 -0
- package/dist/types/vendor/mermaid-ascii/ascii/shapes/index.d.ts +26 -0
- package/dist/types/vendor/mermaid-ascii/ascii/shapes/rectangle.d.ts +31 -0
- package/dist/types/vendor/mermaid-ascii/ascii/shapes/rounded.d.ts +11 -0
- package/dist/types/vendor/mermaid-ascii/ascii/shapes/special.d.ts +59 -0
- package/dist/types/vendor/mermaid-ascii/ascii/shapes/stadium.d.ts +17 -0
- package/dist/types/vendor/mermaid-ascii/ascii/shapes/state.d.ts +30 -0
- package/dist/types/vendor/mermaid-ascii/ascii/shapes/types.d.ts +55 -0
- package/dist/types/vendor/mermaid-ascii/ascii/types.d.ts +206 -0
- package/dist/types/vendor/mermaid-ascii/ascii/validate.d.ts +51 -0
- package/dist/types/vendor/mermaid-ascii/ascii/xychart.d.ts +2 -0
- package/dist/types/vendor/mermaid-ascii/class/parser.d.ts +6 -0
- package/dist/types/vendor/mermaid-ascii/class/types.d.ts +102 -0
- package/dist/types/vendor/mermaid-ascii/er/parser.d.ts +6 -0
- package/dist/types/vendor/mermaid-ascii/er/types.d.ts +76 -0
- package/dist/types/vendor/mermaid-ascii/index.d.ts +1 -0
- package/dist/types/vendor/mermaid-ascii/multiline-utils.d.ts +9 -0
- package/dist/types/vendor/mermaid-ascii/parser.d.ts +7 -0
- package/dist/types/vendor/mermaid-ascii/sequence/parser.d.ts +6 -0
- package/dist/types/vendor/mermaid-ascii/sequence/types.d.ts +130 -0
- package/dist/types/vendor/mermaid-ascii/text-metrics.d.ts +21 -0
- package/dist/types/vendor/mermaid-ascii/types.d.ts +114 -0
- package/dist/types/vendor/mermaid-ascii/xychart/colors.d.ts +25 -0
- package/dist/types/vendor/mermaid-ascii/xychart/parser.d.ts +6 -0
- package/dist/types/vendor/mermaid-ascii/xychart/types.d.ts +145 -0
- package/dist/types/version.d.ts +18 -0
- package/dist/types/vterm/buffer.d.ts +99 -0
- package/dist/types/vterm/terminal.d.ts +44 -0
- package/dist/types/vterm.d.ts +8 -0
- package/dist/types/which.d.ts +37 -0
- package/dist/types/worker-host.d.ts +51 -0
- package/dist/types/xml.d.ts +31 -0
- package/package.json +59 -0
- package/src/abortable.ts +109 -0
- package/src/acp/connection.ts +344 -0
- package/src/acp/protocol.ts +466 -0
- package/src/acp/schema.ts +160 -0
- package/src/acp/stream.ts +82 -0
- package/src/acp/transport.ts +213 -0
- package/src/acp.ts +6 -0
- package/src/async.ts +91 -0
- package/src/binary.ts +50 -0
- package/src/browsers.ts +501 -0
- package/src/chalk.ts +312 -0
- package/src/cli.ts +529 -0
- package/src/color.ts +302 -0
- package/src/dates.ts +194 -0
- package/src/dirs.ts +1026 -0
- package/src/docx/converter.ts +681 -0
- package/src/docx/xml.ts +166 -0
- package/src/docx/zip.ts +87 -0
- package/src/docx.ts +20 -0
- package/src/dom/core.ts +1254 -0
- package/src/dom/parser.ts +370 -0
- package/src/dom/selector.ts +290 -0
- package/src/dom.ts +33 -0
- package/src/env.ts +400 -0
- package/src/fetch-retry.ts +379 -0
- package/src/file-lock.ts +69 -0
- package/src/format.ts +113 -0
- package/src/frontmatter.ts +205 -0
- package/src/fs-error.ts +56 -0
- package/src/glob.ts +189 -0
- package/src/headers.ts +167 -0
- package/src/index.ts +59 -0
- package/src/json-parse.ts +821 -0
- package/src/json.ts +23 -0
- package/src/logger/rotating-file.ts +149 -0
- package/src/logger.ts +798 -0
- package/src/loop-phase.ts +49 -0
- package/src/lru.ts +185 -0
- package/src/marked/core.ts +1576 -0
- package/src/marked.ts +2 -0
- package/src/mermaid-ascii.ts +31 -0
- package/src/mime.ts +159 -0
- package/src/module-timer.ts +148 -0
- package/src/path-tree.ts +147 -0
- package/src/path.ts +28 -0
- package/src/peek-file.ts +188 -0
- package/src/postmortem.ts +433 -0
- package/src/process-name.ts +57 -0
- package/src/procmgr.ts +247 -0
- package/src/prompt.ts +545 -0
- package/src/ptree.ts +412 -0
- package/src/readability/readability.ts +533 -0
- package/src/readability/readerable.ts +51 -0
- package/src/readability/types.ts +72 -0
- package/src/readability.ts +11 -0
- package/src/ring.ts +169 -0
- package/src/runtime-install.ts +393 -0
- package/src/sanitize-text.ts +96 -0
- package/src/snowflake.ts +121 -0
- package/src/stderr-guard.ts +155 -0
- package/src/stream.ts +454 -0
- package/src/tab-spacing.ts +336 -0
- package/src/temp.ts +134 -0
- package/src/template.ts +586 -0
- package/src/timing-buffer.ts +47 -0
- package/src/tls-fetch.ts +178 -0
- package/src/turndown/gfm.ts +106 -0
- package/src/turndown/html.ts +257 -0
- package/src/turndown/service.ts +334 -0
- package/src/turndown/types.ts +81 -0
- package/src/turndown.ts +5 -0
- package/src/type-guards.ts +17 -0
- package/src/vendor/mermaid-ascii/NOTICE +33 -0
- package/src/vendor/mermaid-ascii/ascii/ansi.ts +409 -0
- package/src/vendor/mermaid-ascii/ascii/canvas.ts +476 -0
- package/src/vendor/mermaid-ascii/ascii/class-diagram.ts +699 -0
- package/src/vendor/mermaid-ascii/ascii/converter.ts +271 -0
- package/src/vendor/mermaid-ascii/ascii/draw.ts +1382 -0
- package/src/vendor/mermaid-ascii/ascii/edge-bundling.ts +328 -0
- package/src/vendor/mermaid-ascii/ascii/edge-routing.ts +297 -0
- package/src/vendor/mermaid-ascii/ascii/er-diagram.ts +441 -0
- package/src/vendor/mermaid-ascii/ascii/grid.ts +578 -0
- package/src/vendor/mermaid-ascii/ascii/index.ts +187 -0
- package/src/vendor/mermaid-ascii/ascii/multiline-utils.ts +78 -0
- package/src/vendor/mermaid-ascii/ascii/pathfinder.ts +277 -0
- package/src/vendor/mermaid-ascii/ascii/sequence.ts +460 -0
- package/src/vendor/mermaid-ascii/ascii/shapes/circle.ts +27 -0
- package/src/vendor/mermaid-ascii/ascii/shapes/corners.ts +127 -0
- package/src/vendor/mermaid-ascii/ascii/shapes/diamond.ts +27 -0
- package/src/vendor/mermaid-ascii/ascii/shapes/hexagon.ts +27 -0
- package/src/vendor/mermaid-ascii/ascii/shapes/index.ts +101 -0
- package/src/vendor/mermaid-ascii/ascii/shapes/rectangle.ts +175 -0
- package/src/vendor/mermaid-ascii/ascii/shapes/rounded.ts +27 -0
- package/src/vendor/mermaid-ascii/ascii/shapes/special.ts +296 -0
- package/src/vendor/mermaid-ascii/ascii/shapes/stadium.ts +114 -0
- package/src/vendor/mermaid-ascii/ascii/shapes/state.ts +192 -0
- package/src/vendor/mermaid-ascii/ascii/shapes/types.ts +73 -0
- package/src/vendor/mermaid-ascii/ascii/types.ts +273 -0
- package/src/vendor/mermaid-ascii/ascii/validate.ts +120 -0
- package/src/vendor/mermaid-ascii/ascii/xychart.ts +875 -0
- package/src/vendor/mermaid-ascii/class/parser.ts +290 -0
- package/src/vendor/mermaid-ascii/class/types.ts +121 -0
- package/src/vendor/mermaid-ascii/er/parser.ts +181 -0
- package/src/vendor/mermaid-ascii/er/types.ts +91 -0
- package/src/vendor/mermaid-ascii/index.ts +14 -0
- package/src/vendor/mermaid-ascii/multiline-utils.ts +30 -0
- package/src/vendor/mermaid-ascii/parser.ts +645 -0
- package/src/vendor/mermaid-ascii/sequence/parser.ts +207 -0
- package/src/vendor/mermaid-ascii/sequence/types.ts +146 -0
- package/src/vendor/mermaid-ascii/text-metrics.ts +71 -0
- package/src/vendor/mermaid-ascii/types.ts +164 -0
- package/src/vendor/mermaid-ascii/xychart/colors.ts +140 -0
- package/src/vendor/mermaid-ascii/xychart/parser.ts +115 -0
- package/src/vendor/mermaid-ascii/xychart/types.ts +150 -0
- package/src/version.ts +99 -0
- package/src/vterm/buffer.ts +218 -0
- package/src/vterm/terminal.ts +773 -0
- package/src/vterm.ts +8 -0
- package/src/which.ts +234 -0
- package/src/worker-host.ts +100 -0
- package/src/xml.ts +313 -0
package/src/docx/xml.ts
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
interface XmlText {
|
|
2
|
+
readonly kind: "text";
|
|
3
|
+
readonly value: string;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
/** A minimal XML element used by the DOCX reader. */
|
|
7
|
+
export interface XmlElement {
|
|
8
|
+
readonly kind: "element";
|
|
9
|
+
readonly name: string;
|
|
10
|
+
readonly attributes: ReadonlyMap<string, string>;
|
|
11
|
+
readonly children: readonly XmlNode[];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** A node in the DOCX reader's minimal XML tree. */
|
|
15
|
+
export type XmlNode = XmlElement | XmlText;
|
|
16
|
+
|
|
17
|
+
const ENTITY_PATTERN = /&(?:#x[\da-fA-F]+|#\d+|amp|apos|gt|lt|quot);/g;
|
|
18
|
+
const ATTRIBUTE_PATTERN = /([^\s=]+)\s*=\s*(?:"([^"]*)"|'([^']*)')/g;
|
|
19
|
+
|
|
20
|
+
function decodeEntities(value: string): string {
|
|
21
|
+
return value.replace(ENTITY_PATTERN, entity => {
|
|
22
|
+
switch (entity) {
|
|
23
|
+
case "&":
|
|
24
|
+
return "&";
|
|
25
|
+
case "'":
|
|
26
|
+
return "'";
|
|
27
|
+
case ">":
|
|
28
|
+
return ">";
|
|
29
|
+
case "<":
|
|
30
|
+
return "<";
|
|
31
|
+
case """:
|
|
32
|
+
return '"';
|
|
33
|
+
default: {
|
|
34
|
+
const hexadecimal = entity[2] === "x";
|
|
35
|
+
const digits = entity.slice(hexadecimal ? 3 : 2, -1);
|
|
36
|
+
const codePoint = Number.parseInt(digits, hexadecimal ? 16 : 10);
|
|
37
|
+
return Number.isFinite(codePoint) ? String.fromCodePoint(codePoint) : entity;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Return the namespace-independent part of an XML qualified name. */
|
|
44
|
+
export function localName(name: string): string {
|
|
45
|
+
const colon = name.indexOf(":");
|
|
46
|
+
return colon === -1 ? name : name.slice(colon + 1);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Parse XML into a small namespace-tolerant element tree. */
|
|
50
|
+
export function parseXml(source: string): XmlElement {
|
|
51
|
+
const synthetic: { name: string; attributes: Map<string, string>; children: XmlNode[] } = {
|
|
52
|
+
name: "#document",
|
|
53
|
+
attributes: new Map(),
|
|
54
|
+
children: [],
|
|
55
|
+
};
|
|
56
|
+
const stack: Array<{ name: string; attributes: Map<string, string>; children: XmlNode[] }> = [synthetic];
|
|
57
|
+
let offset = 0;
|
|
58
|
+
while (offset < source.length) {
|
|
59
|
+
const lessThan = source.indexOf("<", offset);
|
|
60
|
+
if (lessThan === -1) {
|
|
61
|
+
const value = decodeEntities(source.slice(offset));
|
|
62
|
+
if (value) stack[stack.length - 1].children.push({ kind: "text", value });
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
if (lessThan > offset) {
|
|
66
|
+
const value = decodeEntities(source.slice(offset, lessThan));
|
|
67
|
+
if (value) stack[stack.length - 1].children.push({ kind: "text", value });
|
|
68
|
+
}
|
|
69
|
+
if (source.startsWith("<!--", lessThan)) {
|
|
70
|
+
const end = source.indexOf("-->", lessThan + 4);
|
|
71
|
+
if (end === -1) throw new Error("Invalid XML: unterminated comment");
|
|
72
|
+
offset = end + 3;
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (source.startsWith("<![CDATA[", lessThan)) {
|
|
76
|
+
const end = source.indexOf("]]>", lessThan + 9);
|
|
77
|
+
if (end === -1) throw new Error("Invalid XML: unterminated CDATA section");
|
|
78
|
+
stack[stack.length - 1].children.push({ kind: "text", value: source.slice(lessThan + 9, end) });
|
|
79
|
+
offset = end + 3;
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
if (source.startsWith("<?", lessThan)) {
|
|
83
|
+
const end = source.indexOf("?>", lessThan + 2);
|
|
84
|
+
if (end === -1) throw new Error("Invalid XML: unterminated processing instruction");
|
|
85
|
+
offset = end + 2;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
if (source.startsWith("<!", lessThan)) {
|
|
89
|
+
const end = source.indexOf(">", lessThan + 2);
|
|
90
|
+
if (end === -1) throw new Error("Invalid XML: unterminated declaration");
|
|
91
|
+
offset = end + 1;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
const end = source.indexOf(">", lessThan + 1);
|
|
95
|
+
if (end === -1) throw new Error("Invalid XML: unterminated tag");
|
|
96
|
+
const raw = source.slice(lessThan + 1, end).trim();
|
|
97
|
+
if (raw.startsWith("/")) {
|
|
98
|
+
if (stack.length === 1) throw new Error("Invalid XML: unexpected closing tag");
|
|
99
|
+
const closingName = raw.slice(1).trim();
|
|
100
|
+
const completed = stack.pop();
|
|
101
|
+
if (!completed || completed.name !== closingName)
|
|
102
|
+
throw new Error(`Invalid XML: mismatched closing tag ${closingName}`);
|
|
103
|
+
stack[stack.length - 1].children.push({
|
|
104
|
+
kind: "element",
|
|
105
|
+
name: completed.name,
|
|
106
|
+
attributes: completed.attributes,
|
|
107
|
+
children: completed.children,
|
|
108
|
+
});
|
|
109
|
+
} else {
|
|
110
|
+
const selfClosing = raw.endsWith("/");
|
|
111
|
+
const tag = selfClosing ? raw.slice(0, -1).trim() : raw;
|
|
112
|
+
const whitespace = tag.search(/\s/);
|
|
113
|
+
const name = whitespace === -1 ? tag : tag.slice(0, whitespace);
|
|
114
|
+
const attributes = new Map<string, string>();
|
|
115
|
+
ATTRIBUTE_PATTERN.lastIndex = whitespace === -1 ? tag.length : whitespace;
|
|
116
|
+
for (let match = ATTRIBUTE_PATTERN.exec(tag); match; match = ATTRIBUTE_PATTERN.exec(tag)) {
|
|
117
|
+
attributes.set(match[1], decodeEntities(match[2] ?? match[3] ?? ""));
|
|
118
|
+
}
|
|
119
|
+
const pending = { name, attributes, children: [] as XmlNode[] };
|
|
120
|
+
if (selfClosing) {
|
|
121
|
+
stack[stack.length - 1].children.push({ kind: "element", ...pending });
|
|
122
|
+
} else {
|
|
123
|
+
stack.push(pending);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
offset = end + 1;
|
|
127
|
+
}
|
|
128
|
+
if (stack.length !== 1) throw new Error(`Invalid XML: unclosed tag ${stack[stack.length - 1].name}`);
|
|
129
|
+
const roots = synthetic.children.filter((node): node is XmlElement => node.kind === "element");
|
|
130
|
+
if (roots.length !== 1) throw new Error("Invalid XML: expected one root element");
|
|
131
|
+
return roots[0];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** Return direct element children, optionally filtered by local name. */
|
|
135
|
+
export function childElements(element: XmlElement, name?: string): XmlElement[] {
|
|
136
|
+
return element.children.filter(
|
|
137
|
+
(node): node is XmlElement => node.kind === "element" && (name === undefined || localName(node.name) === name),
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** Return the first direct child with the given local name. */
|
|
142
|
+
export function firstChild(element: XmlElement | undefined, name: string): XmlElement | undefined {
|
|
143
|
+
if (!element) return undefined;
|
|
144
|
+
return element.children.find((node): node is XmlElement => node.kind === "element" && localName(node.name) === name);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** Return an attribute by qualified or namespace-independent name. */
|
|
148
|
+
export function attribute(element: XmlElement | undefined, name: string): string | undefined {
|
|
149
|
+
if (!element) return undefined;
|
|
150
|
+
const exact = element.attributes.get(name);
|
|
151
|
+
if (exact !== undefined) return exact;
|
|
152
|
+
for (const [attributeName, value] of element.attributes) {
|
|
153
|
+
if (localName(attributeName) === localName(name)) return value;
|
|
154
|
+
}
|
|
155
|
+
return undefined;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** Return all descendant elements with a given local name. */
|
|
159
|
+
export function descendants(element: XmlElement, name: string): XmlElement[] {
|
|
160
|
+
const matches: XmlElement[] = [];
|
|
161
|
+
for (const child of childElements(element)) {
|
|
162
|
+
if (localName(child.name) === name) matches.push(child);
|
|
163
|
+
matches.push(...descendants(child, name));
|
|
164
|
+
}
|
|
165
|
+
return matches;
|
|
166
|
+
}
|
package/src/docx/zip.ts
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import * as zlib from "node:zlib";
|
|
2
|
+
|
|
3
|
+
const LOCAL_FILE_SIGNATURE = 0x04034b50;
|
|
4
|
+
const CENTRAL_FILE_SIGNATURE = 0x02014b50;
|
|
5
|
+
const END_SIGNATURE = 0x06054b50;
|
|
6
|
+
const MAX_END_SEARCH = 65_557;
|
|
7
|
+
const UTF8 = new TextDecoder();
|
|
8
|
+
|
|
9
|
+
/** The decompressed members of a DOCX ZIP package. */
|
|
10
|
+
export type ZipEntries = ReadonlyMap<string, Uint8Array>;
|
|
11
|
+
|
|
12
|
+
function view(bytes: Uint8Array): DataView {
|
|
13
|
+
return new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function findEndRecord(bytes: Uint8Array): number {
|
|
17
|
+
const data = view(bytes);
|
|
18
|
+
for (
|
|
19
|
+
let offset = bytes.byteLength - 22, limit = Math.max(0, bytes.byteLength - MAX_END_SEARCH);
|
|
20
|
+
offset >= limit;
|
|
21
|
+
offset--
|
|
22
|
+
) {
|
|
23
|
+
if (data.getUint32(offset, true) === END_SIGNATURE) return offset;
|
|
24
|
+
}
|
|
25
|
+
throw new Error("Invalid DOCX: missing ZIP end record");
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Decode a ZIP package by walking its central directory. */
|
|
29
|
+
export function readZip(bytes: Uint8Array): ZipEntries {
|
|
30
|
+
if (bytes.byteLength < 22) throw new Error("Invalid DOCX: truncated ZIP package");
|
|
31
|
+
const data = view(bytes);
|
|
32
|
+
const endOffset = findEndRecord(bytes);
|
|
33
|
+
const entryCount = data.getUint16(endOffset + 10, true);
|
|
34
|
+
const centralSize = data.getUint32(endOffset + 12, true);
|
|
35
|
+
const centralOffset = data.getUint32(endOffset + 16, true);
|
|
36
|
+
if (entryCount === 0xffff || centralSize === 0xffffffff || centralOffset === 0xffffffff) {
|
|
37
|
+
throw new Error("Invalid DOCX: ZIP64 packages are not supported");
|
|
38
|
+
}
|
|
39
|
+
if (centralOffset + centralSize > bytes.byteLength) throw new Error("Invalid DOCX: truncated ZIP central directory");
|
|
40
|
+
const entries = new Map<string, Uint8Array>();
|
|
41
|
+
let offset = centralOffset;
|
|
42
|
+
for (let index = 0; index < entryCount; index++) {
|
|
43
|
+
if (offset + 46 > bytes.byteLength || data.getUint32(offset, true) !== CENTRAL_FILE_SIGNATURE) {
|
|
44
|
+
throw new Error("Invalid DOCX: malformed ZIP central directory");
|
|
45
|
+
}
|
|
46
|
+
const flags = data.getUint16(offset + 8, true);
|
|
47
|
+
const method = data.getUint16(offset + 10, true);
|
|
48
|
+
const compressedSize = data.getUint32(offset + 20, true);
|
|
49
|
+
const uncompressedSize = data.getUint32(offset + 24, true);
|
|
50
|
+
const nameLength = data.getUint16(offset + 28, true);
|
|
51
|
+
const extraLength = data.getUint16(offset + 30, true);
|
|
52
|
+
const commentLength = data.getUint16(offset + 32, true);
|
|
53
|
+
const localOffset = data.getUint32(offset + 42, true);
|
|
54
|
+
const entryEnd = offset + 46 + nameLength + extraLength + commentLength;
|
|
55
|
+
if (entryEnd > bytes.byteLength) throw new Error("Invalid DOCX: truncated ZIP entry");
|
|
56
|
+
const name = UTF8.decode(bytes.subarray(offset + 46, offset + 46 + nameLength)).replaceAll("\\", "/");
|
|
57
|
+
if ((flags & 1) !== 0) throw new Error(`Invalid DOCX: encrypted ZIP member ${name}`);
|
|
58
|
+
if (localOffset + 30 > bytes.byteLength || data.getUint32(localOffset, true) !== LOCAL_FILE_SIGNATURE) {
|
|
59
|
+
throw new Error(`Invalid DOCX: missing local header for ${name}`);
|
|
60
|
+
}
|
|
61
|
+
const localNameLength = data.getUint16(localOffset + 26, true);
|
|
62
|
+
const localExtraLength = data.getUint16(localOffset + 28, true);
|
|
63
|
+
const payloadOffset = localOffset + 30 + localNameLength + localExtraLength;
|
|
64
|
+
const payloadEnd = payloadOffset + compressedSize;
|
|
65
|
+
if (payloadEnd > bytes.byteLength) throw new Error(`Invalid DOCX: truncated ZIP member ${name}`);
|
|
66
|
+
const compressed = bytes.subarray(payloadOffset, payloadEnd);
|
|
67
|
+
let decoded: Uint8Array;
|
|
68
|
+
if (method === 0) {
|
|
69
|
+
decoded = compressed;
|
|
70
|
+
} else if (method === 8) {
|
|
71
|
+
decoded = zlib.inflateRawSync(compressed, { maxOutputLength: Math.max(uncompressedSize, 1) });
|
|
72
|
+
} else {
|
|
73
|
+
throw new Error(`Invalid DOCX: unsupported ZIP compression method ${method}`);
|
|
74
|
+
}
|
|
75
|
+
if (decoded.byteLength !== uncompressedSize)
|
|
76
|
+
throw new Error(`Invalid DOCX: size mismatch for ZIP member ${name}`);
|
|
77
|
+
if (name && !name.endsWith("/")) entries.set(name, decoded);
|
|
78
|
+
offset = entryEnd;
|
|
79
|
+
}
|
|
80
|
+
return entries;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Decode a ZIP member as UTF-8 text. */
|
|
84
|
+
export function readZipText(entries: ZipEntries, name: string): string | undefined {
|
|
85
|
+
const bytes = entries.get(name);
|
|
86
|
+
return bytes ? UTF8.decode(bytes) : undefined;
|
|
87
|
+
}
|
package/src/docx.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** Behavior-compatible reimplementation of mammoth's used surface. */
|
|
2
|
+
export {
|
|
3
|
+
type ConvertToHtmlOptions,
|
|
4
|
+
convertToHtml,
|
|
5
|
+
type DocxImage,
|
|
6
|
+
type DocxInput,
|
|
7
|
+
type DocxMessage,
|
|
8
|
+
type DocxResult,
|
|
9
|
+
type ImageAttributeConverter,
|
|
10
|
+
type ImageAttributes,
|
|
11
|
+
type ImageConverter,
|
|
12
|
+
images,
|
|
13
|
+
} from "./docx/converter";
|
|
14
|
+
|
|
15
|
+
import { convertToHtml, images } from "./docx/converter";
|
|
16
|
+
|
|
17
|
+
/** Mammoth-shaped default export for drop-in consumer imports. */
|
|
18
|
+
const docx = { convertToHtml, images };
|
|
19
|
+
|
|
20
|
+
export default docx;
|