@office-open/xml 0.10.12 → 0.10.13
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/index.d.mts +3 -54
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +44 -25
- package/dist/index.mjs.map +1 -0
- package/dist/{utils-t-_-N57p.d.mts → utils-BFKTfRa8.d.mts} +4 -61
- package/dist/utils-BFKTfRa8.d.mts.map +1 -0
- package/dist/utils.d.mts +2 -2
- package/dist/utils.mjs +20 -5
- package/dist/utils.mjs.map +1 -0
- package/package.json +2 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
import { C as
|
|
1
|
+
import { A as XmlObject, C as IgnoreOptions, D as XmlAttrs, E as XmlAtom, O as XmlDesc, S as ElementObject, T as Xml2JsOptions, _ as textOf, a as attrMeasure, b as Element, c as childText, d as colorAttr, f as findChild, g as isNonEmpty, h as hasChild, i as attrBool, j as XmlOption, k as XmlDescArray, l as children, m as findFirst, n as allChildren, o as attrNum, p as findDeep, r as attr, s as childCount, t as NonEmptyArray, u as collectText, v as Attributes, w as Js2XmlOptions, x as ElementCompact, y as DeclarationAttributes } from "./utils-BFKTfRa8.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/serialize.d.ts
|
|
4
|
-
/**
|
|
5
|
-
* Serialize IXmlableObject to XML string.
|
|
6
|
-
* @deprecated Use `stringify` (Element → string) instead. This IXmlableObject path
|
|
7
|
-
* will be removed once the Descriptor migration is complete.
|
|
8
|
-
*/
|
|
9
4
|
declare function xml(input: Record<string, unknown> | Record<string, unknown>[], options?: boolean | string | {
|
|
10
5
|
indent?: boolean | string;
|
|
11
6
|
declaration?: boolean | {
|
|
@@ -22,66 +17,20 @@ declare function parseAttributes(str: string): Record<string, string>;
|
|
|
22
17
|
//#endregion
|
|
23
18
|
//#region src/stringify.d.ts
|
|
24
19
|
declare function stringify(js: Element, options?: Js2XmlOptions): string;
|
|
25
|
-
/** @deprecated Use `stringify` instead. xml-js compatible alias. */
|
|
26
20
|
declare function json2xml(json: Element, options?: Js2XmlOptions): string;
|
|
27
21
|
//#endregion
|
|
28
22
|
//#region src/convert.d.ts
|
|
29
|
-
/**
|
|
30
|
-
* Convert XmlObject (node-xml format) directly to Element (xml-js format).
|
|
31
|
-
* Eliminates the redundant xml() → xml2js() bridge path.
|
|
32
|
-
*/
|
|
33
23
|
declare function toElement(xmlObject: Record<string, unknown>): Element;
|
|
34
24
|
//#endregion
|
|
35
25
|
//#region src/escape.d.ts
|
|
36
|
-
/** Escape text content for XML. Fast path returns original string when no special chars. */
|
|
37
26
|
declare function escapeXml(str: string): string;
|
|
38
|
-
/**
|
|
39
|
-
* Build an XML attribute string fragment from a record.
|
|
40
|
-
* `undefined` values are automatically skipped.
|
|
41
|
-
* String values are escaped via `escapeXml`.
|
|
42
|
-
*
|
|
43
|
-
* @example
|
|
44
|
-
* attrs({ id: 1, name: "foo", hidden: undefined })
|
|
45
|
-
* // => ' id="1" name="foo"'
|
|
46
|
-
*/
|
|
47
27
|
declare function attrs(record: Record<string, string | number | boolean | undefined>): string;
|
|
48
|
-
/**
|
|
49
|
-
* Build an XML attribute string without escaping.
|
|
50
|
-
*
|
|
51
|
-
* Same as `attrs()` but skips `typeof` checks and `escapeXml` — use only when
|
|
52
|
-
* all values are known-safe (numbers, booleans, or strings free of `& " ' < >`).
|
|
53
|
-
* Avoids per-call array and `Object.keys()` allocation in hot loops.
|
|
54
|
-
*
|
|
55
|
-
* @example
|
|
56
|
-
* attrsRaw({ r: "A1", s: 5 })
|
|
57
|
-
* // => ' r="A1" s="5"'
|
|
58
|
-
*/
|
|
59
28
|
declare function attrsRaw(record: Record<string, string | number | boolean | undefined>): string;
|
|
60
|
-
/**
|
|
61
|
-
* Build a self-closing XML element: `<tag attrStr/>`.
|
|
62
|
-
* `attrStr` is a pre-serialized attribute string (from `attrs()`) or undefined.
|
|
63
|
-
*/
|
|
64
29
|
declare function selfCloseElement(tag: string, attrStr?: string): string;
|
|
65
|
-
/**
|
|
66
|
-
* Build a complete XML element string from name, optional attributes, and string children.
|
|
67
|
-
*
|
|
68
|
-
* Replaces `new BuilderElement({...})` + `.toXml()` / `.serialize()` with a
|
|
69
|
-
* single function call returning a string — zero object allocation.
|
|
70
|
-
*
|
|
71
|
-
* @param name Element tag name (e.g. `"a:srgbClr"`)
|
|
72
|
-
* @param attrRecord Optional flat attribute map; `undefined` values are skipped
|
|
73
|
-
* @param children Optional pre-serialized child XML strings
|
|
74
|
-
*
|
|
75
|
-
* @example
|
|
76
|
-
* ```ts
|
|
77
|
-
* element("a:solidFill", undefined, [element("a:srgbClr", { val: "FF0000" })])
|
|
78
|
-
* // => '<a:solidFill><a:srgbClr val="FF0000"/></a:solidFill>'
|
|
79
|
-
* ```
|
|
80
|
-
*/
|
|
81
30
|
declare function element(name: string, attrRecord?: Readonly<Record<string, string | number | boolean | undefined>>, children?: readonly string[]): string;
|
|
82
31
|
//#endregion
|
|
83
32
|
//#region src/json.d.ts
|
|
84
|
-
/** Convert XML string to JSON string — xml-js compatible export */
|
|
85
33
|
declare function xml2json(xml: string, options?: Xml2JsOptions): string;
|
|
86
34
|
//#endregion
|
|
87
|
-
export { type Attributes, type DeclarationAttributes, type Element, type ElementCompact, type ElementObject, type IgnoreOptions, type Js2XmlOptions, type Xml2JsOptions, type XmlAtom, type XmlAttrs, type XmlDesc, type XmlDescArray, type XmlObject, type XmlOption, allChildren, attr, attrBool, attrMeasure, attrNum, attrs, attrsRaw, childCount, childText, children, collectText, colorAttr, element, escapeXml, findChild, findDeep, findFirst, hasChild, stringify as js2xml, stringify, json2xml, nativeTypeValue, parse, parse as xml2js, parseAttributes, selfCloseElement, textOf, toElement, unescapeXml, xml, xml2json };
|
|
35
|
+
export { type Attributes, type DeclarationAttributes, type Element, type ElementCompact, type ElementObject, type IgnoreOptions, type Js2XmlOptions, NonEmptyArray, type Xml2JsOptions, type XmlAtom, type XmlAttrs, type XmlDesc, type XmlDescArray, type XmlObject, type XmlOption, allChildren, attr, attrBool, attrMeasure, attrNum, attrs, attrsRaw, childCount, childText, children, collectText, colorAttr, element, escapeXml, findChild, findDeep, findFirst, hasChild, isNonEmpty, stringify as js2xml, stringify, json2xml, nativeTypeValue, parse, parse as xml2js, parseAttributes, selfCloseElement, textOf, toElement, unescapeXml, xml, xml2json };
|
|
36
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/serialize.ts","../src/parse.ts","../src/stringify.ts","../src/convert.ts","../src/escape.ts","../src/json.ts"],"mappings":";;;iBASgB,GAAA,CACd,KAAA,EAAO,MAAA,oBAA0B,MAAM,qBACvC,OAAA;EAIM,MAAA;EACA,WAAA;IAA0B,QAAA;IAAmB,UAAA;EAAA;AAAA;;;iBCHrC,WAAA,CAAY,GAAW;AAAA,iBAWvB,eAAA,CAAgB,KAAa;AAAA,iBAa7B,KAAA,CAAM,SAAA,UAAmB,OAAA,GAAU,aAAA,GAAgB,OAAO;AAAA,iBAmN1D,eAAA,CAAgB,GAAA,WAAc,MAAM;;;iBCrPpC,SAAA,CAAU,EAAA,EAAI,OAAA,EAAS,OAAA,GAAU,aAAa;AAAA,iBAmB9C,QAAA,CAAS,IAAA,EAAM,OAAA,EAAS,OAAA,GAAU,aAAa;;;iBChB/C,SAAA,CAAU,SAAA,EAAW,MAAA,oBAA0B,OAAO;;;iBCLtD,SAAA,CAAU,GAAW;AAAA,iBA6CrB,KAAA,CAAM,MAA6D,EAArD,MAAM;AAAA,iBAqBpB,QAAA,CAAS,MAA6D,EAArD,MAAM;AAAA,iBAevB,gBAAA,CAAiB,GAAA,UAAa,OAAgB;AAAA,iBAoB9C,OAAA,CACd,IAAA,UACA,UAAA,GAAa,QAAQ,CAAC,MAAA,kDACtB,QAAA;;;iBCrGc,QAAA,CAAS,GAAA,UAAa,OAAA,GAAU,aAAa"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { allChildren, attr, attrBool, attrMeasure, attrNum, childCount, childText, children, collectText, colorAttr, findChild, findDeep, findFirst, hasChild, textOf } from "./utils.mjs";
|
|
1
|
+
import { allChildren, attr, attrBool, attrMeasure, attrNum, childCount, childText, children, collectText, colorAttr, findChild, findDeep, findFirst, hasChild, isNonEmpty, textOf } from "./utils.mjs";
|
|
2
2
|
//#region src/escape.ts
|
|
3
3
|
/** Escape text content for XML. Fast path returns original string when no special chars. */
|
|
4
4
|
function escapeXml(str) {
|
|
@@ -42,11 +42,7 @@ function escapeXml(str) {
|
|
|
42
42
|
*/
|
|
43
43
|
function attrs(record) {
|
|
44
44
|
const parts = [];
|
|
45
|
-
const
|
|
46
|
-
for (let i = 0; i < keys.length; i++) {
|
|
47
|
-
const v = record[keys[i]];
|
|
48
|
-
if (v !== void 0) parts.push(` ${keys[i]}="${typeof v === "string" ? escapeXml(v) : v}"`);
|
|
49
|
-
}
|
|
45
|
+
for (const [key, v] of Object.entries(record)) if (v !== void 0) parts.push(` ${key}="${typeof v === "string" ? escapeXml(v) : v}"`);
|
|
50
46
|
return parts.join("");
|
|
51
47
|
}
|
|
52
48
|
/**
|
|
@@ -101,8 +97,8 @@ function element(name, attrRecord, children) {
|
|
|
101
97
|
//#region src/serialize.ts
|
|
102
98
|
const DEFAULT_INDENT = " ";
|
|
103
99
|
/**
|
|
104
|
-
* Serialize
|
|
105
|
-
* @deprecated Use `stringify` (Element → string) instead. This
|
|
100
|
+
* Serialize a Record-based XML object tree to an XML string.
|
|
101
|
+
* @deprecated Use `stringify` (Element → string) instead. This object-tree path
|
|
106
102
|
* will be removed once the Descriptor migration is complete.
|
|
107
103
|
*/
|
|
108
104
|
function xml(input, options) {
|
|
@@ -120,8 +116,11 @@ function xml(input, options) {
|
|
|
120
116
|
}
|
|
121
117
|
const items = Array.isArray(input) ? input : [input];
|
|
122
118
|
for (let i = 0; i < items.length; i++) {
|
|
123
|
-
const
|
|
124
|
-
|
|
119
|
+
const item = items[i];
|
|
120
|
+
if (!item) continue;
|
|
121
|
+
const key = Object.keys(item)[0];
|
|
122
|
+
if (!key) continue;
|
|
123
|
+
parts.push(formatElement(key, item[key], opts.indent, 0));
|
|
125
124
|
if (opts.indent && i < items.length - 1) parts.push("\n");
|
|
126
125
|
}
|
|
127
126
|
return parts.join("");
|
|
@@ -136,7 +135,7 @@ function normalizeOptions$1(options) {
|
|
|
136
135
|
};
|
|
137
136
|
}
|
|
138
137
|
/**
|
|
139
|
-
* Single-pass XML formatter: directly converts
|
|
138
|
+
* Single-pass XML formatter: directly converts a Record-based XML object to string,
|
|
140
139
|
* eliminating the intermediate ResolvedElement tree.
|
|
141
140
|
*/
|
|
142
141
|
function formatElement(name, values, indent, depth) {
|
|
@@ -171,8 +170,8 @@ function formatElement(name, values, indent, depth) {
|
|
|
171
170
|
const attr = value._attributes;
|
|
172
171
|
for (const key of Object.keys(attr)) attrParts.push(`${key}="${escapeXml(String(attr[key]))}"`);
|
|
173
172
|
} else if (value && typeof value === "object") {
|
|
174
|
-
const
|
|
175
|
-
elemParts.push(formatElement(
|
|
173
|
+
const childKey = Object.keys(value)[0];
|
|
174
|
+
if (childKey) elemParts.push(formatElement(childKey, value[childKey], indent, depth + 1));
|
|
176
175
|
} else if (value != null) textParts.push(escapeXml(String(value)));
|
|
177
176
|
}
|
|
178
177
|
} else textParts.push(escapeXml(String(values)));
|
|
@@ -243,7 +242,7 @@ function parse(xmlString, options) {
|
|
|
243
242
|
if (trim) text = text.trim();
|
|
244
243
|
if (ignoreText) continue;
|
|
245
244
|
if (text.length > 0) {
|
|
246
|
-
if (captureSpaces || text.trim().length > 0 || isPreserveContext(stack)) addField(stack
|
|
245
|
+
if (captureSpaces || text.trim().length > 0 || isPreserveContext(stack)) addField(peek(stack), "text", text);
|
|
247
246
|
}
|
|
248
247
|
continue;
|
|
249
248
|
}
|
|
@@ -257,8 +256,8 @@ function parse(xmlString, options) {
|
|
|
257
256
|
if (xmlMatch) {
|
|
258
257
|
if (!ignoreDeclaration) {
|
|
259
258
|
if (!result.declaration) result.declaration = {};
|
|
260
|
-
const attrs = parseAttributes(xmlMatch[1]);
|
|
261
|
-
if (nativeTypeAttributes) for (const key
|
|
259
|
+
const attrs = parseAttributes(xmlMatch[1] ?? "");
|
|
260
|
+
if (nativeTypeAttributes) for (const key in attrs) attrs[key] = nativeTypeValue(attrs[key]);
|
|
262
261
|
result.declaration.attributes = attrs;
|
|
263
262
|
}
|
|
264
263
|
}
|
|
@@ -269,8 +268,8 @@ function parse(xmlString, options) {
|
|
|
269
268
|
if (end === -1) break;
|
|
270
269
|
const comment = xmlString.slice(i + 3, end);
|
|
271
270
|
i = end + 3;
|
|
272
|
-
if (!ignoreComment) if (trim) addField(stack
|
|
273
|
-
else addField(stack
|
|
271
|
+
if (!ignoreComment) if (trim) addField(peek(stack), "comment", comment.trim());
|
|
272
|
+
else addField(peek(stack), "comment", comment);
|
|
274
273
|
continue;
|
|
275
274
|
}
|
|
276
275
|
if (xmlString.charCodeAt(i) === 33 && xmlString.slice(i, i + 8) === "![CDATA[") {
|
|
@@ -278,8 +277,8 @@ function parse(xmlString, options) {
|
|
|
278
277
|
if (end === -1) break;
|
|
279
278
|
const cdata = xmlString.slice(i + 8, end);
|
|
280
279
|
i = end + 3;
|
|
281
|
-
if (!ignoreCdata) if (trim) addField(stack
|
|
282
|
-
else addField(stack
|
|
280
|
+
if (!ignoreCdata) if (trim) addField(peek(stack), "cdata", cdata.trim());
|
|
281
|
+
else addField(peek(stack), "cdata", cdata);
|
|
283
282
|
continue;
|
|
284
283
|
}
|
|
285
284
|
if (xmlString.charCodeAt(i) === 33 && xmlString.slice(i, i + 9) === "!DOCTYPE") {
|
|
@@ -287,7 +286,7 @@ function parse(xmlString, options) {
|
|
|
287
286
|
if (end === -1) break;
|
|
288
287
|
const doctype = xmlString.slice(i + 9, end).trim();
|
|
289
288
|
i = end + 1;
|
|
290
|
-
if (!ignoreDoctype) addField(stack
|
|
289
|
+
if (!ignoreDoctype) addField(peek(stack), "doctype", doctype);
|
|
291
290
|
continue;
|
|
292
291
|
}
|
|
293
292
|
if (xmlString.charCodeAt(i) === 47) {
|
|
@@ -302,7 +301,7 @@ function parse(xmlString, options) {
|
|
|
302
301
|
let pos = tagNameEnd;
|
|
303
302
|
const attributes = parseAttributesFromXml(xmlString, pos);
|
|
304
303
|
pos = attributes.pos;
|
|
305
|
-
if (nativeTypeAttributes) for (const key
|
|
304
|
+
if (nativeTypeAttributes) for (const key in attributes.attrs) attributes.attrs[key] = nativeTypeValue(attributes.attrs[key]);
|
|
306
305
|
const isSelfClosing = xmlString.charCodeAt(pos) === 47;
|
|
307
306
|
if (isSelfClosing) pos += 2;
|
|
308
307
|
else pos++;
|
|
@@ -311,7 +310,7 @@ function parse(xmlString, options) {
|
|
|
311
310
|
name: tagName
|
|
312
311
|
};
|
|
313
312
|
if (Object.keys(attributes.attrs).length > 0) element.attributes = attributes.attrs;
|
|
314
|
-
const parent = stack
|
|
313
|
+
const parent = peek(stack);
|
|
315
314
|
if (!parent.elements) parent.elements = [];
|
|
316
315
|
parent.elements.push(element);
|
|
317
316
|
if (!isSelfClosing) stack.push(element);
|
|
@@ -391,6 +390,17 @@ function parseAttributes(str) {
|
|
|
391
390
|
}
|
|
392
391
|
return result;
|
|
393
392
|
}
|
|
393
|
+
/**
|
|
394
|
+
* Top of the parse stack. The stack is guaranteed non-empty — the result root
|
|
395
|
+
* is pushed at init and push/pop stay balanced across well-formed input — so
|
|
396
|
+
* this is a compile-time narrow (one non-null assertion) rather than a runtime
|
|
397
|
+
* check: it must not add a throw path that changes how `parse` surfaces
|
|
398
|
+
* malformed documents. Centralising the access keeps that single `!` off the
|
|
399
|
+
* read sites, matching the "wrap indexed access behind a helper" pattern.
|
|
400
|
+
*/
|
|
401
|
+
function peek(stack) {
|
|
402
|
+
return stack[stack.length - 1];
|
|
403
|
+
}
|
|
394
404
|
function addField(parent, type, value) {
|
|
395
405
|
if (!parent.elements) parent.elements = [];
|
|
396
406
|
if (type === "text" || type === "cdata") {
|
|
@@ -408,7 +418,9 @@ function addField(parent, type, value) {
|
|
|
408
418
|
/** True when the nearest ancestor with an explicit xml:space sets "preserve". */
|
|
409
419
|
function isPreserveContext(stack) {
|
|
410
420
|
for (let i = stack.length - 1; i >= 0; i--) {
|
|
411
|
-
const
|
|
421
|
+
const node = stack[i];
|
|
422
|
+
if (!node) continue;
|
|
423
|
+
const space = node.attributes?.["xml:space"];
|
|
412
424
|
if (space !== void 0) return space === "preserve";
|
|
413
425
|
}
|
|
414
426
|
return false;
|
|
@@ -495,6 +507,7 @@ function writeElements(elements, opts, depth, firstLine) {
|
|
|
495
507
|
const parts = [];
|
|
496
508
|
for (let i = 0; i < elements.length; i++) {
|
|
497
509
|
const element = elements[i];
|
|
510
|
+
if (!element) continue;
|
|
498
511
|
const isFirst = firstLine && i === 0;
|
|
499
512
|
switch (element.type) {
|
|
500
513
|
case "element":
|
|
@@ -572,6 +585,10 @@ function writeDoctype(doctype) {
|
|
|
572
585
|
*/
|
|
573
586
|
function toElement(xmlObject) {
|
|
574
587
|
const tagName = Object.keys(xmlObject)[0];
|
|
588
|
+
if (!tagName) return {
|
|
589
|
+
type: "element",
|
|
590
|
+
name: ""
|
|
591
|
+
};
|
|
575
592
|
const value = xmlObject[tagName];
|
|
576
593
|
const element = {
|
|
577
594
|
type: "element",
|
|
@@ -617,4 +634,6 @@ function xml2json(xml, options) {
|
|
|
617
634
|
return JSON.stringify(parse(xml, options));
|
|
618
635
|
}
|
|
619
636
|
//#endregion
|
|
620
|
-
export { allChildren, attr, attrBool, attrMeasure, attrNum, attrs, attrsRaw, childCount, childText, children, collectText, colorAttr, element, escapeXml, findChild, findDeep, findFirst, hasChild, stringify as js2xml, stringify, json2xml, nativeTypeValue, parse, parse as xml2js, parseAttributes, selfCloseElement, textOf, toElement, unescapeXml, xml, xml2json };
|
|
637
|
+
export { allChildren, attr, attrBool, attrMeasure, attrNum, attrs, attrsRaw, childCount, childText, children, collectText, colorAttr, element, escapeXml, findChild, findDeep, findFirst, hasChild, isNonEmpty, stringify as js2xml, stringify, json2xml, nativeTypeValue, parse, parse as xml2js, parseAttributes, selfCloseElement, textOf, toElement, unescapeXml, xml, xml2json };
|
|
638
|
+
|
|
639
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["normalizeOptions","xml2js"],"sources":["../src/escape.ts","../src/serialize.ts","../src/parse.ts","../src/stringify.ts","../src/convert.ts","../src/json.ts"],"sourcesContent":["/** Escape text content for XML. Fast path returns original string when no special chars. */\nexport function escapeXml(str: string): string {\n // Fast path: most text content doesn't contain XML-special characters.\n // Manual scan avoids regex overhead; returning the original string reference\n // means zero allocation for the common case.\n for (let i = 0; i < str.length; i++) {\n const c = str.charCodeAt(i);\n if (c === 38 || c === 34 || c === 39 || c === 60 || c === 62) {\n // & \" ' < >\n // Slow path: slice-and-append avoids regex + temporary match objects.\n let s = \"\";\n let last = 0;\n for (let j = i; j < str.length; j++) {\n const cj = str.charCodeAt(j);\n if (cj === 38) {\n s += str.slice(last, j) + \"&\";\n last = j + 1;\n } else if (cj === 34) {\n s += str.slice(last, j) + \""\";\n last = j + 1;\n } else if (cj === 39) {\n s += str.slice(last, j) + \"'\";\n last = j + 1;\n } else if (cj === 60) {\n s += str.slice(last, j) + \"<\";\n last = j + 1;\n } else if (cj === 62) {\n s += str.slice(last, j) + \">\";\n last = j + 1;\n }\n }\n return s + str.slice(last);\n }\n }\n return str;\n}\n\n/**\n * Build an XML attribute string fragment from a record.\n * `undefined` values are automatically skipped.\n * String values are escaped via `escapeXml`.\n *\n * @example\n * attrs({ id: 1, name: \"foo\", hidden: undefined })\n * // => ' id=\"1\" name=\"foo\"'\n */\nexport function attrs(record: Record<string, string | number | boolean | undefined>): string {\n const parts: string[] = [];\n for (const [key, v] of Object.entries(record)) {\n if (v !== undefined) {\n parts.push(` ${key}=\"${typeof v === \"string\" ? escapeXml(v) : v}\"`);\n }\n }\n return parts.join(\"\");\n}\n\n/**\n * Build an XML attribute string without escaping.\n *\n * Same as `attrs()` but skips `typeof` checks and `escapeXml` — use only when\n * all values are known-safe (numbers, booleans, or strings free of `& \" ' < >`).\n * Avoids per-call array and `Object.keys()` allocation in hot loops.\n *\n * @example\n * attrsRaw({ r: \"A1\", s: 5 })\n * // => ' r=\"A1\" s=\"5\"'\n */\nexport function attrsRaw(record: Record<string, string | number | boolean | undefined>): string {\n let s = \"\";\n for (const key in record) {\n const v = record[key];\n if (v !== undefined) {\n s += ` ${key}=\"${v}\"`;\n }\n }\n return s;\n}\n\n/**\n * Build a self-closing XML element: `<tag attrStr/>`.\n * `attrStr` is a pre-serialized attribute string (from `attrs()`) or undefined.\n */\nexport function selfCloseElement(tag: string, attrStr?: string): string {\n return attrStr ? `<${tag}${attrStr}/>` : `<${tag}/>`;\n}\n\n/**\n * Build a complete XML element string from name, optional attributes, and string children.\n *\n * Replaces `new BuilderElement({...})` + `.toXml()` / `.serialize()` with a\n * single function call returning a string — zero object allocation.\n *\n * @param name Element tag name (e.g. `\"a:srgbClr\"`)\n * @param attrRecord Optional flat attribute map; `undefined` values are skipped\n * @param children Optional pre-serialized child XML strings\n *\n * @example\n * ```ts\n * element(\"a:solidFill\", undefined, [element(\"a:srgbClr\", { val: \"FF0000\" })])\n * // => '<a:solidFill><a:srgbClr val=\"FF0000\"/></a:solidFill>'\n * ```\n */\nexport function element(\n name: string,\n attrRecord?: Readonly<Record<string, string | number | boolean | undefined>>,\n children?: readonly string[],\n): string {\n const attrStr = attrRecord ? attrs(attrRecord) : undefined;\n if (!children || children.length === 0) return selfCloseElement(name, attrStr);\n const body = children.join(\"\");\n return body.length === 0\n ? selfCloseElement(name, attrStr)\n : `<${name}${attrStr ?? \"\"}>${body}</${name}>`;\n}\n","import { escapeXml } from \"./escape\";\n\nconst DEFAULT_INDENT = \" \";\n\n/**\n * Serialize a Record-based XML object tree to an XML string.\n * @deprecated Use `stringify` (Element → string) instead. This object-tree path\n * will be removed once the Descriptor migration is complete.\n */\nexport function xml(\n input: Record<string, unknown> | Record<string, unknown>[],\n options?:\n | boolean\n | string\n | {\n indent?: boolean | string;\n declaration?: boolean | { encoding?: string; standalone?: string };\n },\n): string {\n const opts = normalizeOptions(options);\n const parts: string[] = [];\n\n if (opts.declaration) {\n const declOpts = opts.declaration === true ? {} : opts.declaration;\n const enc = declOpts.encoding || \"UTF-8\";\n const sa = declOpts.standalone;\n const declParts: string[] = [`<?xml version=\"1.0\" encoding=\"${enc}\"`];\n if (sa) declParts.push(` standalone=\"${sa}\"`);\n declParts.push(\"?>\");\n parts.push(declParts.join(\"\"));\n if (opts.indent) parts.push(\"\\n\");\n }\n\n const items = Array.isArray(input) ? input : [input];\n for (let i = 0; i < items.length; i++) {\n const item = items[i];\n if (!item) continue;\n const key = Object.keys(item)[0];\n if (!key) continue;\n parts.push(formatElement(key, item[key], opts.indent, 0));\n if (opts.indent && i < items.length - 1) parts.push(\"\\n\");\n }\n\n return parts.join(\"\");\n}\n\ntype XmlInputOptions = {\n indent?: boolean | string;\n declaration?: boolean | { encoding?: string; standalone?: string };\n};\n\nfunction normalizeOptions(options?: boolean | string | XmlInputOptions): {\n indent: string;\n declaration: XmlInputOptions[\"declaration\"];\n} {\n const opts =\n typeof options === \"object\" && !Array.isArray(options)\n ? options\n : { indent: options as boolean | string };\n let indent = \"\";\n if (opts.indent) {\n indent = opts.indent === true ? DEFAULT_INDENT : String(opts.indent);\n }\n return { indent, declaration: opts.declaration };\n}\n\n/**\n * Single-pass XML formatter: directly converts a Record-based XML object to string,\n * eliminating the intermediate ResolvedElement tree.\n */\nfunction formatElement(name: string, values: unknown, indent: string, depth: number): string {\n const attrParts: string[] = [];\n const textParts: string[] = [];\n const elemParts: string[] = [];\n let emptyArray = false;\n\n if (values == null) {\n const attrStr = attrParts.length ? \" \" + attrParts.join(\" \") : \"\";\n const ind = indent ? indent.repeat(depth) : \"\";\n return `${ind}<${name}${attrStr}/>`;\n }\n\n if (typeof values === \"object\") {\n const obj = values as Record<string, unknown>;\n if (obj._attr) {\n const attr = obj._attr as Record<string, unknown>;\n for (const key of Object.keys(attr)) {\n attrParts.push(`${key}=\"${escapeXml(String(attr[key]))}\"`);\n }\n }\n if (obj._attributes) {\n const attr = obj._attributes as Record<string, unknown>;\n for (const key of Object.keys(attr)) {\n attrParts.push(`${key}=\"${escapeXml(String(attr[key]))}\"`);\n }\n }\n if (obj._cdata) {\n const escaped = String(obj._cdata as string).replace(/\\]\\]>/g, \"]]]]><![CDATA[>\");\n textParts.push(`<![CDATA[${escaped}]]>`);\n }\n if (Array.isArray(values)) {\n if (values.length === 0) {\n emptyArray = true;\n } else {\n for (const value of values) {\n if (value && typeof value === \"object\" && \"_attr\" in value) {\n const attr = (value as Record<string, unknown>)._attr as Record<string, unknown>;\n for (const key of Object.keys(attr)) {\n attrParts.push(`${key}=\"${escapeXml(String(attr[key]))}\"`);\n }\n } else if (value && typeof value === \"object\" && \"_attributes\" in value) {\n const attr = (value as Record<string, unknown>)._attributes as Record<string, unknown>;\n for (const key of Object.keys(attr)) {\n attrParts.push(`${key}=\"${escapeXml(String(attr[key]))}\"`);\n }\n } else if (value && typeof value === \"object\") {\n const childKeys = Object.keys(value);\n const childKey = childKeys[0];\n if (childKey) {\n elemParts.push(\n formatElement(\n childKey,\n (value as Record<string, unknown>)[childKey],\n indent,\n depth + 1,\n ),\n );\n }\n } else if (value != null) {\n textParts.push(escapeXml(String(value)));\n }\n }\n }\n }\n } else {\n textParts.push(escapeXml(String(values as string | number | boolean)));\n }\n\n const ind = indent ? indent.repeat(depth) : \"\";\n const attrStr = attrParts.length ? \" \" + attrParts.join(\" \") : \"\";\n const totalParts = textParts.length + elemParts.length;\n\n if (totalParts === 0) {\n return emptyArray ? `${ind}<${name}${attrStr}></${name}>` : `${ind}<${name}${attrStr}/>`;\n }\n\n // Text-only optimization: single text child, no element children\n if (elemParts.length === 0 && textParts.length === 1) {\n return indent\n ? `${ind}<${name}${attrStr}>${textParts[0]}</${name}>`\n : `<${name}${attrStr}>${textParts[0]}</${name}>`;\n }\n\n // Mixed content\n const parts: string[] = [];\n parts.push(`${ind}<${name}${attrStr}>`);\n if (indent) parts.push(\"\\n\");\n const childIndent = indent ? indent.repeat(depth + 1) : \"\";\n for (const t of textParts) {\n parts.push(`${childIndent}${t}`);\n if (indent) parts.push(\"\\n\");\n }\n for (const e of elemParts) {\n parts.push(e);\n if (indent) parts.push(\"\\n\");\n }\n parts.push(`${ind}</${name}>`);\n return parts.join(\"\");\n}\n","import type { Element, Xml2JsOptions } from \"./types\";\n\nconst ENTITY_MAP: Record<string, string> = {\n \"&\": \"&\",\n \"<\": \"<\",\n \">\": \">\",\n \""\": '\"',\n \"'\": \"'\",\n};\n// Matches the five named entities plus numeric character references\n// (A decimal, B hex).\nconst ENTITY_PATTERN = /&(?:amp|lt|gt|quot|apos|#x[0-9a-fA-F]+|#[0-9]+);/g;\n\nexport function unescapeXml(str: string): string {\n return str.replace(ENTITY_PATTERN, (match) => {\n if (ENTITY_MAP[match] !== undefined) return ENTITY_MAP[match];\n // Numeric character reference: strip \"&#\" prefix and \";\" suffix.\n const body = match.slice(2, -1);\n const code =\n body[0] === \"x\" || body[0] === \"X\" ? parseInt(body.slice(1), 16) : parseInt(body, 10);\n return Number.isFinite(code) && code >= 0 ? String.fromCodePoint(code) : match;\n });\n}\n\nexport function nativeTypeValue(value: string): string | number | boolean {\n if (value === \"\") return value;\n const n = Number(value);\n // Only coerce when lossless: leading zeros (\"00992297\"), exponential\n // notation (\"1e5\"), and a leading sign (\"+5\") must stay strings so hex-like\n // values (rsid, color) survive parse → stringify round-trips byte-exact.\n if (!isNaN(n) && String(n) === value) return n;\n const lower = value.toLowerCase();\n if (lower === \"true\") return true;\n if (lower === \"false\") return false;\n return value;\n}\n\nexport function parse(xmlString: string, options?: Xml2JsOptions): Element {\n const captureSpaces = options?.captureSpacesBetweenElements ?? false;\n const trim = options?.trim ?? false;\n const ignoreDeclaration = options?.ignoreDeclaration ?? false;\n const ignoreText = options?.ignoreText ?? false;\n const ignoreComment = options?.ignoreComment ?? false;\n const ignoreCdata = options?.ignoreCdata ?? false;\n const ignoreDoctype = options?.ignoreDoctype ?? false;\n const nativeTypeAttributes = options?.nativeTypeAttributes ?? false;\n\n const result: Element = {};\n const stack: Element[] = [result];\n\n let i = 0;\n const len = xmlString.length;\n\n while (i < len) {\n // Text node: read up to the next '<'. Pure-whitespace nodes (indentation)\n // are dropped below unless captureSpaces is on, but leading/trailing\n // spaces of nodes that have content are preserved.\n if (xmlString.charCodeAt(i) !== 0x3c /* < */) {\n const start = i;\n while (i < len && xmlString.charCodeAt(i) !== 0x3c) i++;\n let text = unescapeXml(xmlString.slice(start, i));\n if (trim) text = text.trim();\n if (ignoreText) continue;\n if (text.length > 0) {\n if (captureSpaces || text.trim().length > 0 || isPreserveContext(stack)) {\n addField(peek(stack), \"text\", text);\n }\n }\n continue;\n }\n\n i++;\n\n // <? processing instruction / declaration\n if (xmlString.charCodeAt(i) === 0x3f /* ? */) {\n const end = xmlString.indexOf(\"?>\", i + 1);\n if (end === -1) break;\n const body = xmlString.slice(i + 1, end);\n i = end + 2;\n\n const xmlMatch = body.match(/^xml\\s+(.*)$/s);\n if (xmlMatch) {\n if (!ignoreDeclaration) {\n if (!result.declaration) {\n result.declaration = {};\n }\n const attrs = parseAttributes(xmlMatch[1] ?? \"\");\n if (nativeTypeAttributes) {\n for (const key in attrs) {\n attrs[key] = nativeTypeValue(attrs[key] as string) as string;\n }\n }\n result.declaration.attributes = attrs;\n }\n }\n continue;\n }\n\n // !-- comment\n if (xmlString.charCodeAt(i) === 0x21 && xmlString.slice(i, i + 3) === \"!--\") {\n const end = xmlString.indexOf(\"-->\", i + 3);\n if (end === -1) break;\n const comment = xmlString.slice(i + 3, end);\n i = end + 3;\n if (!ignoreComment) {\n if (trim) addField(peek(stack), \"comment\", comment.trim());\n else addField(peek(stack), \"comment\", comment);\n }\n continue;\n }\n\n // ![CDATA[\n if (xmlString.charCodeAt(i) === 0x21 && xmlString.slice(i, i + 8) === \"![CDATA[\") {\n const end = xmlString.indexOf(\"]]>\", i + 8);\n if (end === -1) break;\n const cdata = xmlString.slice(i + 8, end);\n i = end + 3;\n if (!ignoreCdata) {\n if (trim) addField(peek(stack), \"cdata\", cdata.trim());\n else addField(peek(stack), \"cdata\", cdata);\n }\n continue;\n }\n\n // <!DOCTYPE\n if (xmlString.charCodeAt(i) === 0x21 && xmlString.slice(i, i + 9) === \"!DOCTYPE\") {\n const end = xmlString.indexOf(\">\", i + 9);\n if (end === -1) break;\n const doctype = xmlString.slice(i + 9, end).trim();\n i = end + 1;\n if (!ignoreDoctype) {\n addField(peek(stack), \"doctype\", doctype);\n }\n continue;\n }\n\n // </ closing tag\n if (xmlString.charCodeAt(i) === 0x2f /* / */) {\n const end = xmlString.indexOf(\">\", i + 1);\n if (end === -1) break;\n i = end + 1;\n stack.pop();\n continue;\n }\n\n // < opening tag\n const tagNameEnd = findTagNameEnd(xmlString, i);\n const tagName = xmlString.slice(i, tagNameEnd);\n let pos = tagNameEnd;\n\n const attributes = parseAttributesFromXml(xmlString, pos);\n pos = attributes.pos;\n\n if (nativeTypeAttributes) {\n for (const key in attributes.attrs) {\n attributes.attrs[key] = nativeTypeValue(attributes.attrs[key] as string) as string;\n }\n }\n\n const isSelfClosing = xmlString.charCodeAt(pos) === 0x2f /* / */;\n if (isSelfClosing) pos += 2;\n else pos++;\n\n const element: Element = {\n type: \"element\",\n name: tagName,\n };\n if (Object.keys(attributes.attrs).length > 0) {\n element.attributes = attributes.attrs;\n }\n\n const parent = peek(stack);\n if (!parent.elements) {\n parent.elements = [];\n }\n parent.elements.push(element);\n\n if (!isSelfClosing) {\n stack.push(element);\n }\n\n i = pos;\n }\n\n if (result.elements) {\n const temp = result.elements;\n delete result.elements;\n result.elements = temp;\n delete result.text;\n }\n\n return result;\n}\n\nfunction findTagNameEnd(str: string, start: number): number {\n let i = start;\n const len = str.length;\n while (i < len) {\n const ch = str.charCodeAt(i);\n if (ch === 0x20 || ch === 0x09 || ch === 0x0a || ch === 0x0d || ch === 0x2f || ch === 0x3e) {\n return i;\n }\n i++;\n }\n return i;\n}\n\nfunction parseAttributesFromXml(\n str: string,\n start: number,\n): { attrs: Record<string, string>; pos: number } {\n const attrs: Record<string, string> = {};\n let i = start;\n const len = str.length;\n\n while (i < len) {\n while (i < len && isWhitespace(str.charCodeAt(i))) i++;\n if (i >= len || str.charCodeAt(i) === 0x3e || str.charCodeAt(i) === 0x2f) {\n break;\n }\n\n const nameStart = i;\n while (i < len && str.charCodeAt(i) !== 0x3d) {\n if (str.charCodeAt(i) === 0x3e || str.charCodeAt(i) === 0x2f) break;\n i++;\n }\n const name = str.slice(nameStart, i);\n\n if (str.charCodeAt(i) !== 0x3d) break;\n i++;\n\n while (i < len && isWhitespace(str.charCodeAt(i))) i++;\n\n const quote = str.charCodeAt(i);\n if (quote !== 0x22 && quote !== 0x27) break;\n i++;\n const valueStart = i;\n while (i < len && str.charCodeAt(i) !== quote) i++;\n attrs[name] = unescapeXml(str.slice(valueStart, i));\n i++;\n }\n\n return { attrs, pos: i };\n}\n\n/** @deprecated Use `parse` instead. xml-js compatible alias. */\nexport { parse as xml2js };\n\nexport function parseAttributes(str: string): Record<string, string> {\n const result: Record<string, string> = {};\n let i = 0;\n const len = str.length;\n\n while (i < len) {\n while (i < len && isWhitespace(str.charCodeAt(i))) i++;\n if (i >= len) break;\n\n const nameStart = i;\n while (i < len && str.charCodeAt(i) !== 0x3d) {\n if (isWhitespace(str.charCodeAt(i))) break;\n i++;\n }\n const name = str.slice(nameStart, i);\n\n while (i < len && isWhitespace(str.charCodeAt(i))) i++;\n if (i >= len || str.charCodeAt(i) !== 0x3d) break;\n i++;\n\n while (i < len && isWhitespace(str.charCodeAt(i))) i++;\n\n const quote = str.charCodeAt(i);\n if (quote !== 0x22 && quote !== 0x27) break;\n i++;\n const valueStart = i;\n while (i < len && str.charCodeAt(i) !== quote) i++;\n result[name] = unescapeXml(str.slice(valueStart, i));\n i++;\n }\n return result;\n}\n\n/**\n * Top of the parse stack. The stack is guaranteed non-empty — the result root\n * is pushed at init and push/pop stay balanced across well-formed input — so\n * this is a compile-time narrow (one non-null assertion) rather than a runtime\n * check: it must not add a throw path that changes how `parse` surfaces\n * malformed documents. Centralising the access keeps that single `!` off the\n * read sites, matching the \"wrap indexed access behind a helper\" pattern.\n */\nfunction peek(stack: Element[]): Element {\n return stack[stack.length - 1]!;\n}\n\nfunction addField(parent: Element, type: string, value: string) {\n if (!parent.elements) {\n parent.elements = [];\n }\n // Merge adjacent text/cdata nodes: a CDATA section containing the literal\n // `]]>` is serialized as two adjacent CDATA sections and must reassemble\n // into a single node on parse. Adjacent text nodes likewise merge.\n if (type === \"text\" || type === \"cdata\") {\n const last = parent.elements[parent.elements.length - 1];\n if (last && last.type === type) {\n const key = type as \"text\" | \"cdata\";\n last[key] = (last[key] as string) + value;\n return;\n }\n }\n const element: Element = { type };\n (element as Record<string, unknown>)[type] = value;\n parent.elements.push(element);\n}\n\n/** True when the nearest ancestor with an explicit xml:space sets \"preserve\". */\nfunction isPreserveContext(stack: Element[]): boolean {\n for (let i = stack.length - 1; i >= 0; i--) {\n const node = stack[i];\n if (!node) continue;\n const space = node.attributes?.[\"xml:space\"];\n if (space !== undefined) return space === \"preserve\";\n }\n return false;\n}\n\nfunction isWhitespace(ch: number): boolean {\n return ch === 0x20 || ch === 0x09 || ch === 0x0a || ch === 0x0d;\n}\n","import { escapeXml } from \"./escape\";\nimport type { Element, Js2XmlOptions } from \"./types\";\n\nexport function stringify(js: Element, options?: Js2XmlOptions): string {\n const opts = normalizeOptions(options);\n const parts: string[] = [];\n\n if (js.declaration && !opts.ignoreDeclaration) {\n parts.push(writeDeclaration(js.declaration));\n }\n\n if (js.elements?.length) {\n parts.push(writeElements(js.elements, opts, 0, !parts.length));\n }\n\n return parts.join(\"\");\n}\n\n/** @deprecated Use `stringify` instead. xml-js compatible alias. */\nexport { stringify as js2xml };\n\n/** @deprecated Use `stringify` instead. xml-js compatible alias. */\nexport function json2xml(json: Element, options?: Js2XmlOptions): string {\n return stringify(json, options);\n}\n\nfunction normalizeOptions(options?: Js2XmlOptions): {\n spaces: string;\n ignoreDeclaration: boolean;\n ignoreText: boolean;\n ignoreComment: boolean;\n ignoreCdata: boolean;\n ignoreDoctype: boolean;\n fullTagEmptyElement: boolean;\n indentText: boolean;\n indentCdata: boolean;\n attributeValueFn?: Js2XmlOptions[\"attributeValueFn\"];\n} {\n if (!options) {\n return {\n spaces: \"\",\n ignoreDeclaration: false,\n ignoreText: false,\n ignoreComment: false,\n ignoreCdata: false,\n ignoreDoctype: false,\n fullTagEmptyElement: false,\n indentText: false,\n indentCdata: false,\n };\n }\n let spaces = \"\";\n if (options.spaces != null) {\n spaces = typeof options.spaces === \"number\" ? \" \".repeat(options.spaces) : options.spaces;\n }\n return {\n spaces,\n ignoreDeclaration: options.ignoreDeclaration ?? false,\n ignoreText: options.ignoreText ?? false,\n ignoreComment: options.ignoreComment ?? false,\n ignoreCdata: options.ignoreCdata ?? false,\n ignoreDoctype: options.ignoreDoctype ?? false,\n fullTagEmptyElement: options.fullTagEmptyElement ?? false,\n indentText: options.indentText ?? false,\n indentCdata: options.indentCdata ?? false,\n attributeValueFn: options.attributeValueFn,\n };\n}\n\nfunction writeIndentation(spaces: string, depth: number, firstLine: boolean): string {\n return (!firstLine && spaces ? \"\\n\" : \"\") + spaces.repeat(depth);\n}\n\nfunction writeDeclaration(declaration: NonNullable<Element[\"declaration\"]>): string {\n const attrs = declaration.attributes;\n if (!attrs) return '<?xml version=\"1.0\"?>';\n\n const parts: string[] = [`<?xml version=\"1.0\"`];\n if (attrs.encoding) parts.push(` encoding=\"${attrs.encoding}\"`);\n if (attrs.standalone) parts.push(` standalone=\"${attrs.standalone}\"`);\n return parts.join(\"\") + \"?>\";\n}\n\nfunction writeAttributes(\n attributes: Record<string, string | number | undefined>,\n elementName: string,\n element: Element,\n attributeValueFn?: Js2XmlOptions[\"attributeValueFn\"],\n): string {\n const parts: string[] = [];\n for (const key of Object.keys(attributes)) {\n const value = attributes[key];\n if (value === null || value === undefined) continue;\n\n // attributeValueFn (xml-js hook) owns escaping when provided; otherwise\n // we escape all XML-special characters ourselves.\n const raw = String(value);\n const attr = attributeValueFn\n ? attributeValueFn(raw, key, elementName, element)\n : escapeXml(raw);\n parts.push(` ${key}=\"${attr}\"`);\n }\n return parts.join(\"\");\n}\n\nfunction writeElement(\n element: Element,\n opts: ReturnType<typeof normalizeOptions>,\n depth: number,\n): string {\n if (!element.name) return \"\";\n const name = element.name;\n const attrStr = element.attributes\n ? writeAttributes(element.attributes, name, element, opts.attributeValueFn)\n : \"\";\n const withClosingTag =\n (element.elements?.length ?? 0) > 0 ||\n element.attributes?.[\"xml:space\"] === \"preserve\" ||\n opts.fullTagEmptyElement;\n\n if (!withClosingTag) {\n return `<${name}${attrStr}/>`;\n }\n\n const parts: string[] = [];\n parts.push(`<${name}${attrStr}>`);\n const hasChildElements = element.elements?.some((e) => e.type === \"element\") ?? false;\n if (element.elements?.length) {\n parts.push(writeElements(element.elements, opts, depth + 1, false));\n }\n if (opts.spaces && hasChildElements) {\n parts.push(\"\\n\" + opts.spaces.repeat(depth));\n }\n parts.push(`</${name}>`);\n return parts.join(\"\");\n}\n\nfunction writeElements(\n elements: Element[],\n opts: ReturnType<typeof normalizeOptions>,\n depth: number,\n firstLine: boolean,\n): string {\n const parts: string[] = [];\n for (let i = 0; i < elements.length; i++) {\n const element = elements[i];\n if (!element) continue;\n const isFirst = firstLine && i === 0;\n switch (element.type) {\n case \"element\":\n parts.push(writeIndentation(opts.spaces, depth, isFirst));\n parts.push(writeElement(element, opts, depth));\n break;\n case \"text\":\n if (opts.ignoreText) continue;\n if (opts.indentText) parts.push(writeIndentation(opts.spaces, depth, isFirst));\n parts.push(writeText(element.text));\n break;\n case \"cdata\":\n if (opts.ignoreCdata) continue;\n if (opts.indentCdata) parts.push(writeIndentation(opts.spaces, depth, isFirst));\n parts.push(writeCdata(element.cdata));\n break;\n case \"comment\":\n if (opts.ignoreComment) continue;\n parts.push(writeIndentation(opts.spaces, depth, isFirst));\n parts.push(writeComment(element.comment));\n break;\n case \"doctype\":\n if (opts.ignoreDoctype) continue;\n parts.push(writeIndentation(opts.spaces, depth, isFirst));\n parts.push(writeDoctype(element.doctype));\n break;\n default:\n break;\n }\n }\n return parts.join(\"\");\n}\n\nfunction writeText(text: string | number | boolean | undefined | null): string {\n if (text == null) return \"\";\n const str = String(text);\n // Fast path: most text content doesn't contain XML-special characters.\n for (let i = 0; i < str.length; i++) {\n const c = str.charCodeAt(i);\n if (c === 38 || c === 60 || c === 62) {\n // & < >\n let s = \"\";\n let last = 0;\n for (let j = i; j < str.length; j++) {\n const cj = str.charCodeAt(j);\n if (cj === 38) {\n s += str.slice(last, j) + \"&\";\n last = j + 1;\n } else if (cj === 60) {\n s += str.slice(last, j) + \"<\";\n last = j + 1;\n } else if (cj === 62) {\n s += str.slice(last, j) + \">\";\n last = j + 1;\n }\n }\n return s + str.slice(last);\n }\n }\n return str;\n}\n\nfunction writeCdata(cdata: string | undefined | null): string {\n if (cdata == null) return \"\";\n const escaped = cdata.replace(/\\]\\]>/g, \"]]]]><![CDATA[>\");\n return `<![CDATA[${escaped}]]>`;\n}\n\nfunction writeComment(comment: string | undefined | null): string {\n if (comment == null) return \"\";\n return `<!--${comment}-->`;\n}\n\nfunction writeDoctype(doctype: string | undefined | null): string {\n if (doctype == null) return \"\";\n return `<!DOCTYPE ${doctype}>`;\n}\n\ntype NonNullable<T> = T extends null | undefined ? never : T;\n","import type { Element, Attributes } from \"./types\";\n\n/**\n * Convert XmlObject (node-xml format) directly to Element (xml-js format).\n * Eliminates the redundant xml() → xml2js() bridge path.\n */\nexport function toElement(xmlObject: Record<string, unknown>): Element {\n const tagName = Object.keys(xmlObject)[0];\n if (!tagName) {\n return { type: \"element\", name: \"\" };\n }\n const value = xmlObject[tagName];\n\n const element: Element = {\n type: \"element\",\n name: tagName,\n };\n\n if (value == null) {\n return element;\n }\n\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n element.elements = [{ type: \"text\", text: String(value) }];\n return element;\n }\n\n if (Array.isArray(value)) {\n const children: Element[] = [];\n for (const item of value) {\n if (item && typeof item === \"object\" && \"_attr\" in item) {\n element.attributes = item._attr as Attributes;\n } else if (item && typeof item === \"object\") {\n const childKeys = Object.keys(item);\n if (childKeys[0] === \"_cdata\") {\n children.push({ type: \"cdata\", cdata: String(item._cdata) });\n } else {\n children.push(toElement(item));\n }\n } else if (item != null) {\n children.push({ type: \"text\", text: String(item) });\n }\n }\n if (children.length > 0) {\n element.elements = children;\n }\n return element;\n }\n\n if (typeof value === \"object\" && value !== null) {\n const obj = value as { _attr?: Attributes; _cdata?: string };\n if (obj._attr) {\n element.attributes = obj._attr;\n }\n if (obj._cdata) {\n element.elements = [{ type: \"cdata\", cdata: String(obj._cdata) }];\n }\n }\n\n return element;\n}\n","import { xml2js } from \"./parse\";\nimport type { Xml2JsOptions } from \"./types\";\n\n/** Convert XML string to JSON string — xml-js compatible export */\nexport function xml2json(xml: string, options?: Xml2JsOptions): string {\n return JSON.stringify(xml2js(xml, options));\n}\n"],"mappings":"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"}
|
|
@@ -122,80 +122,23 @@ type XmlObject = {
|
|
|
122
122
|
} | XmlDesc;
|
|
123
123
|
//#endregion
|
|
124
124
|
//#region src/utils.d.ts
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
*/
|
|
125
|
+
type NonEmptyArray<T> = readonly [T, ...ReadonlyArray<T>];
|
|
126
|
+
declare const isNonEmpty: <T>(arr: readonly T[]) => arr is NonEmptyArray<T>;
|
|
128
127
|
declare function findChild(parent: Element | undefined, name: string): Element | undefined;
|
|
129
|
-
/**
|
|
130
|
-
* Get all direct child elements matching the given name.
|
|
131
|
-
*/
|
|
132
128
|
declare function children(parent: Element | undefined, name: string): Element[];
|
|
133
|
-
/**
|
|
134
|
-
* Get all direct child elements.
|
|
135
|
-
*/
|
|
136
129
|
declare function allChildren(parent: Element | undefined): Element[];
|
|
137
|
-
/**
|
|
138
|
-
* Get text content of the first child element with the given name.
|
|
139
|
-
*/
|
|
140
130
|
declare function childText(parent: Element | undefined, name: string): string;
|
|
141
|
-
/**
|
|
142
|
-
* Get text content of an element.
|
|
143
|
-
* Handles cases where text may be directly on .text or in a child element.
|
|
144
|
-
*/
|
|
145
131
|
declare function textOf(element: Element | undefined): string;
|
|
146
|
-
/**
|
|
147
|
-
* Collect text from all direct text nodes within an element.
|
|
148
|
-
*/
|
|
149
132
|
declare function collectText(element: Element | undefined): string;
|
|
150
|
-
/**
|
|
151
|
-
* Get an attribute value as a string.
|
|
152
|
-
*/
|
|
153
133
|
declare function attr(element: Element | undefined, name: string): string | undefined;
|
|
154
|
-
/**
|
|
155
|
-
* Get an attribute value as a number.
|
|
156
|
-
*/
|
|
157
134
|
declare function attrNum(element: Element | undefined, name: string): number | undefined;
|
|
158
|
-
/**
|
|
159
|
-
* Get a measurement attribute as a number or a verbatim measure/percent string.
|
|
160
|
-
*
|
|
161
|
-
* Counterpart to {@link attrNum} for XSD attribute unions of a decimal number
|
|
162
|
-
* and UniversalMeasure/Percentage (ST_TwipsMeasure, ST_MeasurementOrPercent,
|
|
163
|
-
* CT_TblWidth/@w, CT_Height/@val): a plain numeric token yields a number, while
|
|
164
|
-
* UniversalMeasure ("5mm") and Percentage ("50%") stay verbatim so they
|
|
165
|
-
* round-trip with the stringify-side value helpers in @office-open/core.
|
|
166
|
-
*
|
|
167
|
-
* For CT_TblWidth with type="pct", the fiftieths token ("5000" = 100%) is a
|
|
168
|
-
* plain numeric token and is returned as the number 5000; the stringify side
|
|
169
|
-
* emits it verbatim (never "5000%", which is a different XSD branch).
|
|
170
|
-
*/
|
|
171
135
|
declare function attrMeasure(element: Element | undefined, name: string): number | string | undefined;
|
|
172
|
-
/**
|
|
173
|
-
* Get an attribute value as a boolean.
|
|
174
|
-
*/
|
|
175
136
|
declare function attrBool(element: Element | undefined, name: string): boolean | undefined;
|
|
176
|
-
/**
|
|
177
|
-
* Get a hex color attribute, handling nativeTypeValue coercion.
|
|
178
|
-
* nativeTypeAttributes converts "000000" → 0 (number); this recovers
|
|
179
|
-
* the original 6-digit hex string by zero-padding numeric values.
|
|
180
|
-
*/
|
|
181
137
|
declare function colorAttr(element: Element | undefined, name: string): string | undefined;
|
|
182
|
-
/**
|
|
183
|
-
* Check if an element has a specific child element.
|
|
184
|
-
*/
|
|
185
138
|
declare function hasChild(parent: Element | undefined, name: string): boolean;
|
|
186
|
-
/**
|
|
187
|
-
* Find deep descendant elements matching the given name.
|
|
188
|
-
*/
|
|
189
139
|
declare function findDeep(parent: Element | undefined, name: string): Element[];
|
|
190
|
-
/**
|
|
191
|
-
* Find the first descendant element with the given name (depth-first pre-order).
|
|
192
|
-
* Short-circuits at the first match — prefer this over `findDeep(parent, name)[0]`
|
|
193
|
-
* to avoid traversing the whole subtree and allocating the full results array.
|
|
194
|
-
*/
|
|
195
140
|
declare function findFirst(parent: Element | undefined, name: string): Element | undefined;
|
|
196
|
-
/**
|
|
197
|
-
* Get the number of direct child elements.
|
|
198
|
-
*/
|
|
199
141
|
declare function childCount(parent: Element | undefined): number;
|
|
200
142
|
//#endregion
|
|
201
|
-
export {
|
|
143
|
+
export { XmlObject as A, IgnoreOptions as C, XmlAttrs as D, XmlAtom as E, XmlDesc as O, ElementObject as S, Xml2JsOptions as T, textOf as _, attrMeasure as a, Element as b, childText as c, colorAttr as d, findChild as f, isNonEmpty as g, hasChild as h, attrBool as i, XmlOption as j, XmlDescArray as k, children as l, findFirst as m, allChildren as n, attrNum as o, findDeep as p, attr as r, childCount as s, NonEmptyArray as t, collectText as u, Attributes as v, Js2XmlOptions as w, ElementCompact as x, DeclarationAttributes as y };
|
|
144
|
+
//# sourceMappingURL=utils-BFKTfRa8.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils-BFKTfRa8.d.mts","names":[],"sources":["../src/types.ts","../src/utils.ts"],"mappings":"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"}
|
package/dist/utils.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
export { allChildren, attr, attrBool, attrMeasure, attrNum, childCount, childText, children, collectText, colorAttr, findChild, findDeep, findFirst, hasChild, textOf };
|
|
1
|
+
import { _ as textOf, a as attrMeasure, c as childText, d as colorAttr, f as findChild, g as isNonEmpty, h as hasChild, i as attrBool, l as children, m as findFirst, n as allChildren, o as attrNum, p as findDeep, r as attr, s as childCount, t as NonEmptyArray, u as collectText } from "./utils-BFKTfRa8.mjs";
|
|
2
|
+
export { NonEmptyArray, allChildren, attr, attrBool, attrMeasure, attrNum, childCount, childText, children, collectText, colorAttr, findChild, findDeep, findFirst, hasChild, isNonEmpty, textOf };
|
package/dist/utils.mjs
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
//#region src/utils.ts
|
|
2
2
|
/**
|
|
3
|
+
* User-defined type guard narrowing an array to {@link NonEmptyArray}.
|
|
4
|
+
* Prefer this over a bare `arr.length > 0` check, which TypeScript does
|
|
5
|
+
* not reliably narrow into a non-empty tuple at the read site.
|
|
6
|
+
*/
|
|
7
|
+
const isNonEmpty = (arr) => arr.length > 0;
|
|
8
|
+
/**
|
|
3
9
|
* Find the first direct child element with the given name.
|
|
4
10
|
*/
|
|
5
11
|
function findChild(parent, name) {
|
|
@@ -30,7 +36,11 @@ function childText(parent, name) {
|
|
|
30
36
|
function textOf(element) {
|
|
31
37
|
if (!element) return "";
|
|
32
38
|
if (element.text !== void 0 && typeof element.text === "string") return element.text;
|
|
33
|
-
if (element.elements && element.elements.length > 0)
|
|
39
|
+
if (element.elements && element.elements.length > 0) {
|
|
40
|
+
let text = "";
|
|
41
|
+
for (const e of element.elements) if (typeof e.text === "string") text += e.text;
|
|
42
|
+
return text;
|
|
43
|
+
}
|
|
34
44
|
return "";
|
|
35
45
|
}
|
|
36
46
|
/**
|
|
@@ -119,12 +129,15 @@ function hasChild(parent, name) {
|
|
|
119
129
|
*/
|
|
120
130
|
function findDeep(parent, name) {
|
|
121
131
|
const result = [];
|
|
122
|
-
|
|
132
|
+
collectDeep(parent, name, result);
|
|
133
|
+
return result;
|
|
134
|
+
}
|
|
135
|
+
function collectDeep(parent, name, result) {
|
|
136
|
+
if (!parent) return;
|
|
123
137
|
for (const child of parent.elements ?? []) {
|
|
124
138
|
if (child.name === name) result.push(child);
|
|
125
|
-
|
|
139
|
+
collectDeep(child, name, result);
|
|
126
140
|
}
|
|
127
|
-
return result;
|
|
128
141
|
}
|
|
129
142
|
/**
|
|
130
143
|
* Find the first descendant element with the given name (depth-first pre-order).
|
|
@@ -146,4 +159,6 @@ function childCount(parent) {
|
|
|
146
159
|
return parent?.elements?.length ?? 0;
|
|
147
160
|
}
|
|
148
161
|
//#endregion
|
|
149
|
-
export { allChildren, attr, attrBool, attrMeasure, attrNum, childCount, childText, children, collectText, colorAttr, findChild, findDeep, findFirst, hasChild, textOf };
|
|
162
|
+
export { allChildren, attr, attrBool, attrMeasure, attrNum, childCount, childText, children, collectText, colorAttr, findChild, findDeep, findFirst, hasChild, isNonEmpty, textOf };
|
|
163
|
+
|
|
164
|
+
//# sourceMappingURL=utils.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.mjs","names":[],"sources":["../src/utils.ts"],"sourcesContent":["import type { Element } from \"./types\";\n\n/**\n * A readonly array guaranteed to have at least one element. Use with\n * {@link isNonEmpty} to narrow `T[]` so indexed access (e.g. `arr[0]`)\n * returns `T` instead of `T | undefined` under `noUncheckedIndexedAccess`.\n */\nexport type NonEmptyArray<T> = readonly [T, ...ReadonlyArray<T>];\n\n/**\n * User-defined type guard narrowing an array to {@link NonEmptyArray}.\n * Prefer this over a bare `arr.length > 0` check, which TypeScript does\n * not reliably narrow into a non-empty tuple at the read site.\n */\nexport const isNonEmpty = <T>(arr: readonly T[]): arr is NonEmptyArray<T> => arr.length > 0;\n\n/**\n * Find the first direct child element with the given name.\n */\nexport function findChild(parent: Element | undefined, name: string): Element | undefined {\n return parent?.elements?.find((e) => e.name === name);\n}\n\n/**\n * Get all direct child elements matching the given name.\n */\nexport function children(parent: Element | undefined, name: string): Element[] {\n return parent?.elements?.filter((e) => e.name === name) ?? [];\n}\n\n/**\n * Get all direct child elements.\n */\nexport function allChildren(parent: Element | undefined): Element[] {\n return parent?.elements ?? [];\n}\n\n/**\n * Get text content of the first child element with the given name.\n */\nexport function childText(parent: Element | undefined, name: string): string {\n const child = findChild(parent, name);\n return textOf(child);\n}\n\n/**\n * Get text content of an element.\n * Handles cases where text may be directly on .text or in a child element.\n */\nexport function textOf(element: Element | undefined): string {\n if (!element) return \"\";\n if (element.text !== undefined && typeof element.text === \"string\") return element.text;\n if (element.elements && element.elements.length > 0) {\n let text = \"\";\n for (const e of element.elements) {\n if (typeof e.text === \"string\") text += e.text;\n }\n return text;\n }\n return \"\";\n}\n\n/**\n * Collect text from all direct text nodes within an element.\n */\nexport function collectText(element: Element | undefined): string {\n if (!element) return \"\";\n const parts: string[] = [];\n collectTextRecursive(element, parts);\n return parts.join(\"\");\n}\n\nfunction collectTextRecursive(element: Element | undefined, parts: string[]): void {\n if (!element) return;\n if (element.text !== undefined && typeof element.text === \"string\") {\n parts.push(element.text);\n }\n if (element.elements) {\n for (const child of element.elements) {\n collectTextRecursive(child, parts);\n }\n }\n}\n\n/**\n * Get an attribute value as a string.\n */\nexport function attr(element: Element | undefined, name: string): string | undefined {\n const v = element?.attributes?.[name];\n return v !== undefined ? String(v) : undefined;\n}\n\n/**\n * Get an attribute value as a number.\n */\nexport function attrNum(element: Element | undefined, name: string): number | undefined {\n const v = element?.attributes?.[name];\n if (v === undefined) return undefined;\n const n = Number(v);\n return isNaN(n) ? undefined : n;\n}\n\n/**\n * Get a measurement attribute as a number or a verbatim measure/percent string.\n *\n * Counterpart to {@link attrNum} for XSD attribute unions of a decimal number\n * and UniversalMeasure/Percentage (ST_TwipsMeasure, ST_MeasurementOrPercent,\n * CT_TblWidth/@w, CT_Height/@val): a plain numeric token yields a number, while\n * UniversalMeasure (\"5mm\") and Percentage (\"50%\") stay verbatim so they\n * round-trip with the stringify-side value helpers in @office-open/core.\n *\n * For CT_TblWidth with type=\"pct\", the fiftieths token (\"5000\" = 100%) is a\n * plain numeric token and is returned as the number 5000; the stringify side\n * emits it verbatim (never \"5000%\", which is a different XSD branch).\n */\nexport function attrMeasure(\n element: Element | undefined,\n name: string,\n): number | string | undefined {\n const v = element?.attributes?.[name];\n if (v === undefined) return undefined;\n const raw = String(v);\n const n = Number(raw);\n return Number.isNaN(n) ? raw : n;\n}\n\n/**\n * Get an attribute value as a boolean.\n */\nexport function attrBool(element: Element | undefined, name: string): boolean | undefined {\n const v = element?.attributes?.[name];\n if (v === undefined) return undefined;\n if (typeof v === \"boolean\") return v;\n const lower = String(v).toLowerCase();\n if (lower === \"true\" || lower === \"1\") return true;\n if (lower === \"false\" || lower === \"0\") return false;\n return undefined;\n}\n\n/**\n * Get a hex color attribute, handling nativeTypeValue coercion.\n * nativeTypeAttributes converts \"000000\" → 0 (number); this recovers\n * the original 6-digit hex string by zero-padding numeric values.\n */\nexport function colorAttr(element: Element | undefined, name: string): string | undefined {\n const raw = element?.attributes?.[name];\n if (raw === undefined || raw === \"\") return undefined;\n if (typeof raw === \"boolean\") return undefined;\n if (typeof raw === \"number\") {\n return String(raw).padStart(6, \"0\");\n }\n if (raw === \"auto\") return \"auto\";\n if (/^[0-9A-Fa-f]{6}$/.test(raw)) return raw;\n return raw;\n}\n\n/**\n * Check if an element has a specific child element.\n */\nexport function hasChild(parent: Element | undefined, name: string): boolean {\n return parent?.elements?.some((e) => e.name === name) ?? false;\n}\n\n/**\n * Find deep descendant elements matching the given name.\n */\nexport function findDeep(parent: Element | undefined, name: string): Element[] {\n const result: Element[] = [];\n collectDeep(parent, name, result);\n return result;\n}\n\nfunction collectDeep(parent: Element | undefined, name: string, result: Element[]): void {\n if (!parent) return;\n for (const child of parent.elements ?? []) {\n if (child.name === name) result.push(child);\n collectDeep(child, name, result);\n }\n}\n\n/**\n * Find the first descendant element with the given name (depth-first pre-order).\n * Short-circuits at the first match — prefer this over `findDeep(parent, name)[0]`\n * to avoid traversing the whole subtree and allocating the full results array.\n */\nexport function findFirst(parent: Element | undefined, name: string): Element | undefined {\n if (!parent) return undefined;\n for (const child of parent.elements ?? []) {\n if (child.name === name) return child;\n const found = findFirst(child, name);\n if (found) return found;\n }\n return undefined;\n}\n\n/**\n * Get the number of direct child elements.\n */\nexport function childCount(parent: Element | undefined): number {\n return parent?.elements?.length ?? 0;\n}\n"],"mappings":";;;;;;AAcA,MAAa,cAAiB,QAA+C,IAAI,SAAS;;;;AAK1F,SAAgB,UAAU,QAA6B,MAAmC;CACxF,OAAO,QAAQ,UAAU,MAAM,MAAM,EAAE,SAAS,IAAI;AACtD;;;;AAKA,SAAgB,SAAS,QAA6B,MAAyB;CAC7E,OAAO,QAAQ,UAAU,QAAQ,MAAM,EAAE,SAAS,IAAI,KAAK,CAAC;AAC9D;;;;AAKA,SAAgB,YAAY,QAAwC;CAClE,OAAO,QAAQ,YAAY,CAAC;AAC9B;;;;AAKA,SAAgB,UAAU,QAA6B,MAAsB;CAE3E,OAAO,OADO,UAAU,QAAQ,IACd,CAAC;AACrB;;;;;AAMA,SAAgB,OAAO,SAAsC;CAC3D,IAAI,CAAC,SAAS,OAAO;CACrB,IAAI,QAAQ,SAAS,KAAA,KAAa,OAAO,QAAQ,SAAS,UAAU,OAAO,QAAQ;CACnF,IAAI,QAAQ,YAAY,QAAQ,SAAS,SAAS,GAAG;EACnD,IAAI,OAAO;EACX,KAAK,MAAM,KAAK,QAAQ,UACtB,IAAI,OAAO,EAAE,SAAS,UAAU,QAAQ,EAAE;EAE5C,OAAO;CACT;CACA,OAAO;AACT;;;;AAKA,SAAgB,YAAY,SAAsC;CAChE,IAAI,CAAC,SAAS,OAAO;CACrB,MAAM,QAAkB,CAAC;CACzB,qBAAqB,SAAS,KAAK;CACnC,OAAO,MAAM,KAAK,EAAE;AACtB;AAEA,SAAS,qBAAqB,SAA8B,OAAuB;CACjF,IAAI,CAAC,SAAS;CACd,IAAI,QAAQ,SAAS,KAAA,KAAa,OAAO,QAAQ,SAAS,UACxD,MAAM,KAAK,QAAQ,IAAI;CAEzB,IAAI,QAAQ,UACV,KAAK,MAAM,SAAS,QAAQ,UAC1B,qBAAqB,OAAO,KAAK;AAGvC;;;;AAKA,SAAgB,KAAK,SAA8B,MAAkC;CACnF,MAAM,IAAI,SAAS,aAAa;CAChC,OAAO,MAAM,KAAA,IAAY,OAAO,CAAC,IAAI,KAAA;AACvC;;;;AAKA,SAAgB,QAAQ,SAA8B,MAAkC;CACtF,MAAM,IAAI,SAAS,aAAa;CAChC,IAAI,MAAM,KAAA,GAAW,OAAO,KAAA;CAC5B,MAAM,IAAI,OAAO,CAAC;CAClB,OAAO,MAAM,CAAC,IAAI,KAAA,IAAY;AAChC;;;;;;;;;;;;;;AAeA,SAAgB,YACd,SACA,MAC6B;CAC7B,MAAM,IAAI,SAAS,aAAa;CAChC,IAAI,MAAM,KAAA,GAAW,OAAO,KAAA;CAC5B,MAAM,MAAM,OAAO,CAAC;CACpB,MAAM,IAAI,OAAO,GAAG;CACpB,OAAO,OAAO,MAAM,CAAC,IAAI,MAAM;AACjC;;;;AAKA,SAAgB,SAAS,SAA8B,MAAmC;CACxF,MAAM,IAAI,SAAS,aAAa;CAChC,IAAI,MAAM,KAAA,GAAW,OAAO,KAAA;CAC5B,IAAI,OAAO,MAAM,WAAW,OAAO;CACnC,MAAM,QAAQ,OAAO,CAAC,CAAC,CAAC,YAAY;CACpC,IAAI,UAAU,UAAU,UAAU,KAAK,OAAO;CAC9C,IAAI,UAAU,WAAW,UAAU,KAAK,OAAO;AAEjD;;;;;;AAOA,SAAgB,UAAU,SAA8B,MAAkC;CACxF,MAAM,MAAM,SAAS,aAAa;CAClC,IAAI,QAAQ,KAAA,KAAa,QAAQ,IAAI,OAAO,KAAA;CAC5C,IAAI,OAAO,QAAQ,WAAW,OAAO,KAAA;CACrC,IAAI,OAAO,QAAQ,UACjB,OAAO,OAAO,GAAG,CAAC,CAAC,SAAS,GAAG,GAAG;CAEpC,IAAI,QAAQ,QAAQ,OAAO;CAC3B,IAAI,mBAAmB,KAAK,GAAG,GAAG,OAAO;CACzC,OAAO;AACT;;;;AAKA,SAAgB,SAAS,QAA6B,MAAuB;CAC3E,OAAO,QAAQ,UAAU,MAAM,MAAM,EAAE,SAAS,IAAI,KAAK;AAC3D;;;;AAKA,SAAgB,SAAS,QAA6B,MAAyB;CAC7E,MAAM,SAAoB,CAAC;CAC3B,YAAY,QAAQ,MAAM,MAAM;CAChC,OAAO;AACT;AAEA,SAAS,YAAY,QAA6B,MAAc,QAAyB;CACvF,IAAI,CAAC,QAAQ;CACb,KAAK,MAAM,SAAS,OAAO,YAAY,CAAC,GAAG;EACzC,IAAI,MAAM,SAAS,MAAM,OAAO,KAAK,KAAK;EAC1C,YAAY,OAAO,MAAM,MAAM;CACjC;AACF;;;;;;AAOA,SAAgB,UAAU,QAA6B,MAAmC;CACxF,IAAI,CAAC,QAAQ,OAAO,KAAA;CACpB,KAAK,MAAM,SAAS,OAAO,YAAY,CAAC,GAAG;EACzC,IAAI,MAAM,SAAS,MAAM,OAAO;EAChC,MAAM,QAAQ,UAAU,OAAO,IAAI;EACnC,IAAI,OAAO,OAAO;CACpB;AAEF;;;;AAKA,SAAgB,WAAW,QAAqC;CAC9D,OAAO,QAAQ,UAAU,UAAU;AACrC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@office-open/xml",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.13",
|
|
4
4
|
"description": "XML parsing and serialization for Office Open XML. Zero dependencies, drop-in replacement for xml + xml-js.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"office-open",
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
"dist"
|
|
29
29
|
],
|
|
30
30
|
"type": "module",
|
|
31
|
+
"sideEffects": false,
|
|
31
32
|
"main": "dist/index.mjs",
|
|
32
33
|
"types": "dist/index.d.mts",
|
|
33
34
|
"exports": {
|