@office-kit/xlsx 0.17.0 → 0.18.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.
Files changed (61) hide show
  1. package/README.md +78 -4
  2. package/dist/{cell-style-DjKKPWDL.mjs → cell-style-CbB4nXTY.mjs} +11 -4
  3. package/dist/cell-style-CbB4nXTY.mjs.map +1 -0
  4. package/dist/{differential-7KGzbliB.mjs → differential-QLaKEiBk.mjs} +2 -2
  5. package/dist/{differential-7KGzbliB.mjs.map → differential-QLaKEiBk.mjs.map} +1 -1
  6. package/dist/io/load.d.ts +2 -0
  7. package/dist/io.mjs +2 -2
  8. package/dist/{iterparse-DZE0zy2M.mjs → iterparse-CZoRXvZW.mjs} +2 -2
  9. package/dist/{iterparse-DZE0zy2M.mjs.map → iterparse-CZoRXvZW.mjs.map} +1 -1
  10. package/dist/{load-DIdQ_zum.mjs → load-BpnCPv1S.mjs} +25 -13
  11. package/dist/load-BpnCPv1S.mjs.map +1 -0
  12. package/dist/{manifest-BHUYpjUG.mjs → manifest-9p0ccqmR.mjs} +10 -11
  13. package/dist/manifest-9p0ccqmR.mjs.map +1 -0
  14. package/dist/node.mjs +1 -1
  15. package/dist/packaging.mjs +1 -1
  16. package/dist/{parser-By6RWZVW.mjs → parser-B1tB9YaE.mjs} +15 -5
  17. package/dist/parser-B1tB9YaE.mjs.map +1 -0
  18. package/dist/{save-ax11Gsw0.mjs → save-1Z3344nz.mjs} +6 -6
  19. package/dist/{save-ax11Gsw0.mjs.map → save-1Z3344nz.mjs.map} +1 -1
  20. package/dist/schema.mjs +1 -1
  21. package/dist/{serialize-Dmb6Vtt9.mjs → serialize-BtxgssFK.mjs} +2 -2
  22. package/dist/{serialize-Dmb6Vtt9.mjs.map → serialize-BtxgssFK.mjs.map} +1 -1
  23. package/dist/{serializer-dhv07Z6F.mjs → serializer-N6XIwsgp.mjs} +2 -2
  24. package/dist/{serializer-dhv07Z6F.mjs.map → serializer-N6XIwsgp.mjs.map} +1 -1
  25. package/dist/streaming.mjs +34 -17
  26. package/dist/streaming.mjs.map +1 -1
  27. package/dist/styles/display-text.d.ts +95 -0
  28. package/dist/styles/format-code.d.ts +125 -0
  29. package/dist/styles/index.d.ts +1 -0
  30. package/dist/styles/numbers.d.ts +7 -0
  31. package/dist/styles.mjs +1161 -4
  32. package/dist/styles.mjs.map +1 -0
  33. package/dist/{stylesheet-writer-BBYjNSMA.mjs → stylesheet-writer-BEn-0P0x.mjs} +341 -105
  34. package/dist/stylesheet-writer-BEn-0P0x.mjs.map +1 -0
  35. package/dist/{table-BFi2WmgG.mjs → table-BxOLUZs3.mjs} +2 -2
  36. package/dist/{table-BFi2WmgG.mjs.map → table-BxOLUZs3.mjs.map} +1 -1
  37. package/dist/{tree-BX-sRRVp.mjs → tree-CspNjuYl.mjs} +12 -2
  38. package/dist/tree-CspNjuYl.mjs.map +1 -0
  39. package/dist/workbook/index.d.ts +1 -1
  40. package/dist/workbook/workbook.d.ts +9 -46
  41. package/dist/{workbook-CMel6UcI.mjs → workbook-tG9oYtzU.mjs} +46 -9
  42. package/dist/workbook-tG9oYtzU.mjs.map +1 -0
  43. package/dist/workbook.mjs +2 -2
  44. package/dist/worksheet/index.d.ts +1 -1
  45. package/dist/worksheet/worksheet.d.ts +55 -14
  46. package/dist/{worksheet-Cxn2c-jz.mjs → worksheet-DLMyDD7W.mjs} +85 -20
  47. package/dist/worksheet-DLMyDD7W.mjs.map +1 -0
  48. package/dist/worksheet.mjs +3 -3
  49. package/dist/xml/namespaces.d.ts +7 -0
  50. package/dist/xml/parser.d.ts +12 -0
  51. package/dist/xml/strict-package.d.ts +14 -0
  52. package/dist/xml.mjs +4 -4
  53. package/package.json +1 -1
  54. package/dist/cell-style-DjKKPWDL.mjs.map +0 -1
  55. package/dist/load-DIdQ_zum.mjs.map +0 -1
  56. package/dist/manifest-BHUYpjUG.mjs.map +0 -1
  57. package/dist/parser-By6RWZVW.mjs.map +0 -1
  58. package/dist/stylesheet-writer-BBYjNSMA.mjs.map +0 -1
  59. package/dist/tree-BX-sRRVp.mjs.map +0 -1
  60. package/dist/workbook-CMel6UcI.mjs.map +0 -1
  61. package/dist/worksheet-Cxn2c-jz.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"serialize-Dmb6Vtt9.mjs","names":[],"sources":["../src/schema/core.ts","../src/utils/xsd-boolean.ts","../src/schema/serialize.ts"],"sourcesContent":["// Schema layer types — pure data, zero classes.\n//\n// A Schema<T> describes how a plain `T` is mapped to and from an XmlNode. The\n// runtime serialiser (src/schema/serialize.ts) is a single switch-on-kind walk\n// that needs nothing beyond these tables; bundlers can drop schemas a build\n// path never imports because each lives in its own const.\n//\n// Lazy element schemas (`schema: () => SideSchema`) are how circular references\n// — Border has Sides, Side has its own Color, etc. — stay expressible without\n// hoisting hazards at module load.\n\n/** Primitive coercion kinds attribute values may declare. */\nexport type Primitive = 'string' | 'int' | 'float' | 'bool';\n\nexport interface AttrDef {\n kind: Primitive | 'enum';\n /** Allowed values when kind === 'enum'. */\n values?: readonly string[];\n /** Treat the attribute as optional; missing → undefined. */\n optional?: boolean;\n /**\n * Default applied during fromTree when the attribute is absent. Never\n * auto-stripped during toTree — round-trip equivalence is the primary\n * concern; explicit emitters decide when to omit.\n */\n default?: unknown;\n /** Numeric range bounds for kind in {'int', 'float'}. */\n min?: number;\n max?: number;\n /** XML attribute name when it differs from the property key on T. */\n xmlName?: string;\n /** Namespace URI for the XML attribute. Empty / undefined = no namespace. */\n xmlNs?: string;\n}\n\n/**\n * Discriminated union of element shapes a schema can declare. Names are\n * unprefixed (`xmlNs` carries the namespace); the serialiser pairs them into\n * Clark names internally.\n */\nexport type ElementDef =\n | {\n kind: 'text';\n /** Property key on T — the value lands at `T[key]`. */\n key: string;\n /** XML element local name. Defaults to `key` when omitted. */\n name?: string;\n xmlNs?: string;\n primitive: Primitive;\n optional?: boolean;\n default?: unknown;\n /**\n * Fixed attributes always emitted on this element. Keys in Clark\n * notation. On parse, attributes other than these are ignored; keep the\n * schema strict only for the value (text content).\n *\n * Used for the `xsi:type=\"dcterms:W3CDTF\"` marker that docProps/core.xml\n * emits on its <dcterms:created> / <dcterms:modified> children, and\n * similar fixed-marker patterns.\n */\n attrs?: Record<string, string>;\n }\n | {\n kind: 'object';\n key: string;\n name?: string;\n xmlNs?: string;\n // Schema is contravariant in T at the element boundary; named types\n // come back via T anyway. The `any` is intentional — `unknown` would\n // force a cast in every concrete schema definition with no extra safety.\n // oxlint-disable-next-line typescript/no-explicit-any\n schema: () => Schema<any>;\n optional?: boolean;\n }\n | {\n kind: 'sequence';\n key: string;\n /** Local name of the repeated child element. */\n itemName: string;\n itemNs?: string;\n // See ElementDef.kind === 'object' for why `any` survives here.\n // oxlint-disable-next-line typescript/no-explicit-any\n itemSchema: () => Schema<any>;\n /** Optional wrapper element holding the items. */\n container?: { name: string; xmlNs?: string; count?: boolean };\n }\n | {\n /**\n * Empty marker element — `<key/>` whose presence sets `T[key] = true`,\n * absence leaves it `undefined`. Used by Font's `<b/>`, `<i/>`, etc.\n */\n kind: 'empty';\n key: string;\n name?: string;\n xmlNs?: string;\n }\n | {\n /**\n * `<key val=\"value\"/>` style child carrying a single primitive value via\n * an attribute (default `val`). This is openpyxl's NestedString /\n * NestedFloat / NestedInteger / NestedBool / NestedNoneSet pattern; it\n * shows up across Font, NumberFormat children and several chart\n * sub-elements.\n */\n kind: 'nested';\n key: string;\n name?: string;\n xmlNs?: string;\n primitive: Primitive | 'enum';\n /** Allowed values when primitive === 'enum'. */\n values?: readonly string[];\n /** Attribute name carrying the value. Defaults to \"val\". */\n valAttr?: string;\n /** Numeric range bounds (int / float). */\n min?: number;\n max?: number;\n optional?: boolean;\n default?: unknown;\n }\n | {\n /**\n * Opaque round-trip slot — fromTree stores the matched child as a raw\n * `XmlNode`, toTree splices it back verbatim. Used for subtrees we don't\n * want to model in detail (e.g. the vt:vector content under app.xml's\n * HeadingPairs / TitlesOfParts) but still need to preserve byte-for-byte\n * through edits.\n */\n kind: 'raw';\n key: string;\n name?: string;\n xmlNs?: string;\n optional?: boolean;\n };\n\nexport interface Schema<T> {\n /** Local element name. */\n tagname: string;\n /** Namespace URI of this element. */\n xmlNs?: string;\n /** Attribute table keyed by property name on T. */\n attrs: { readonly [K in keyof T & string]?: AttrDef };\n /** Child elements in declaration / emission order. */\n elements: ReadonlyArray<ElementDef>;\n /** Hook to normalise the parsed object (e.g., infer derived fields). */\n postParse?: (value: T, node: import('../xml/tree.js').XmlNode) => T;\n /** Hook to normalise the value before serialisation. */\n preSerialize?: (value: T) => T;\n}\n\n/**\n * Identity helper that pins inference to the supplied `T`. The runtime is just\n * `s => s`; the value matters only for the call-site type.\n */\nexport function defineSchema<T>(s: Schema<T>): Schema<T> {\n return s;\n}\n","/**\n * Parse an xsd:boolean, or `undefined` when the text is outside its lexical\n * space. The type's whiteSpace facet is `collapse`, so the padding a\n * pretty-printer leaves around the text is insignificant and a reformatted\n * part reads the same as a compact one. `t` / `f` and mixed case are outside\n * the lexical space proper, but openpyxl accepts them, so the readers here do\n * too rather than rejecting a file another tool opens.\n */\nexport const parseXsdBoolean = (raw: string | undefined): boolean | undefined => {\n // Excel writes `1` / `0`; answer the common spellings without allocating.\n if (raw === '1' || raw === 'true') return true;\n if (raw === '0' || raw === 'false') return false;\n if (raw === undefined) return undefined;\n const text = raw.trim().toLowerCase();\n if (text === '1' || text === 'true' || text === 't') return true;\n if (text === '0' || text === 'false' || text === 'f') return false;\n return undefined;\n};\n","// Schema-driven (de)serialisation. One switch-on-kind walk in each direction;\n// the schema does the work, no class-based descriptors.\n//\n// `toTree` and `fromTree` are pure functions over plain data. They run the same\n// on the schema layer's own types and on user types in the styles / chart /\n// drawing modules.\n\nimport { OpenXmlSchemaError } from '../utils/exceptions.js';\nimport { parseXsdBoolean } from '../utils/xsd-boolean.js';\nimport { qname } from '../xml/namespaces.js';\nimport { el, type XmlNode } from '../xml/tree.js';\nimport type { AttrDef, ElementDef, Primitive, Schema } from './core.js';\n\n// ---- coercion helpers -------------------------------------------------------\n\nconst coerceFromString = (raw: string, kind: Primitive | 'enum', def: AttrDef): unknown => {\n switch (kind) {\n case 'string':\n return raw;\n case 'int': {\n const n = Number.parseInt(raw, 10);\n if (!Number.isFinite(n)) throw new OpenXmlSchemaError(`expected an integer, got \"${raw}\"`);\n if (def.min !== undefined && n < def.min) throw new OpenXmlSchemaError(`int \"${n}\" is below min ${def.min}`);\n if (def.max !== undefined && n > def.max) throw new OpenXmlSchemaError(`int \"${n}\" is above max ${def.max}`);\n return n;\n }\n case 'float': {\n const n = Number.parseFloat(raw);\n if (!Number.isFinite(n)) throw new OpenXmlSchemaError(`expected a number, got \"${raw}\"`);\n if (def.min !== undefined && n < def.min) throw new OpenXmlSchemaError(`float \"${n}\" is below min ${def.min}`);\n if (def.max !== undefined && n > def.max) throw new OpenXmlSchemaError(`float \"${n}\" is above max ${def.max}`);\n return n;\n }\n case 'bool': {\n const v = parseXsdBoolean(raw);\n if (v === undefined) throw new OpenXmlSchemaError(`expected a boolean, got \"${raw}\"`);\n return v;\n }\n case 'enum': {\n if (!def.values?.includes(raw)) {\n throw new OpenXmlSchemaError(`expected one of [${def.values?.join(', ') ?? ''}], got \"${raw}\"`);\n }\n return raw;\n }\n }\n};\n\nconst coerceToString = (value: unknown, kind: Primitive | 'enum', def: AttrDef): string => {\n switch (kind) {\n case 'string':\n if (typeof value !== 'string') throw new OpenXmlSchemaError(`expected a string, got ${typeof value}`);\n return value;\n case 'int': {\n if (typeof value !== 'number' || !Number.isFinite(value) || !Number.isInteger(value)) {\n throw new OpenXmlSchemaError(`expected an integer, got ${String(value)}`);\n }\n return String(value);\n }\n case 'float': {\n if (typeof value !== 'number' || !Number.isFinite(value)) {\n throw new OpenXmlSchemaError(`expected a number, got ${String(value)}`);\n }\n return String(value);\n }\n case 'bool': {\n if (typeof value !== 'boolean') throw new OpenXmlSchemaError(`expected a boolean, got ${typeof value}`);\n // OOXML convention: '1' / '0'.\n return value ? '1' : '0';\n }\n case 'enum': {\n if (typeof value !== 'string' || !def.values || !def.values.includes(value)) {\n throw new OpenXmlSchemaError(`enum value out of range: ${String(value)}`);\n }\n return value;\n }\n }\n};\n\nconst attrXmlKey = (key: string, def: AttrDef): string => qname(def.xmlNs ?? '', def.xmlName ?? key);\nconst elementXmlName = (def: ElementDef, fallbackNs: string | undefined): string => {\n const local = def.kind === 'sequence' ? (def.container?.name ?? def.itemName) : (def.name ?? def.key);\n const ns = def.kind === 'sequence' ? (def.container?.xmlNs ?? def.itemNs ?? fallbackNs) : (def.xmlNs ?? fallbackNs);\n return qname(ns ?? '', local);\n};\n\n// ---- toTree -----------------------------------------------------------------\n\n/** Serialise a value of `T` into an {@link XmlNode} per the supplied schema. */\nexport function toTree<T>(value: T, schema: Schema<T>): XmlNode {\n const v = (schema.preSerialize ? schema.preSerialize(value) : value) as Record<string, unknown>;\n const node = el(qname(schema.xmlNs ?? '', schema.tagname));\n\n for (const [key, def] of Object.entries(schema.attrs) as Array<[string, AttrDef | undefined]>) {\n if (def === undefined) continue;\n const raw = v[key];\n if (raw === undefined) {\n if (def.optional) continue;\n throw new OpenXmlSchemaError(`<${schema.tagname}>: required attribute \"${key}\" is missing`);\n }\n node.attrs[attrXmlKey(key, def)] = coerceToString(raw, def.kind, def);\n }\n\n for (const def of schema.elements) {\n const raw = v[def.key];\n if (raw === undefined) {\n // 'empty' has no `optional`; presence is binary on the value itself.\n // 'sequence' is implicitly optional (undefined / [] = no items). 'raw'\n // uses the same optional flag as text/object.\n if ((def.kind === 'text' || def.kind === 'object' || def.kind === 'raw') && !def.optional) {\n throw new OpenXmlSchemaError(`<${schema.tagname}>: required element \"${def.key}\" is missing`);\n }\n continue;\n }\n switch (def.kind) {\n case 'text': {\n const text = coerceToString(raw, def.primitive, { kind: def.primitive });\n node.children.push(el(elementXmlName(def, schema.xmlNs), def.attrs ?? {}, [], text));\n break;\n }\n case 'empty': {\n if (raw === true) node.children.push(el(elementXmlName(def, schema.xmlNs), {}, []));\n break;\n }\n case 'nested': {\n const valAttr = def.valAttr ?? 'val';\n const fakeAttrDef: AttrDef = {\n kind: def.primitive,\n ...(def.values !== undefined ? { values: def.values } : {}),\n ...(def.min !== undefined ? { min: def.min } : {}),\n ...(def.max !== undefined ? { max: def.max } : {}),\n };\n const text = coerceToString(raw, def.primitive, fakeAttrDef);\n node.children.push(el(elementXmlName(def, schema.xmlNs), { [valAttr]: text }, []));\n break;\n }\n case 'object': {\n const sub = toTree(raw as Record<string, unknown>, def.schema());\n // Allow the schema to declare its own tagname OR be addressed by the\n // parent under a different element name. We honour the schema's tagname\n // (it's the canonical identity for that type).\n if (def.name !== undefined && sub.name !== qname(def.xmlNs ?? schema.xmlNs ?? '', def.name)) {\n // Re-tag the produced element to the parent-defined name.\n sub.name = qname(def.xmlNs ?? schema.xmlNs ?? '', def.name);\n } else if (def.name === undefined && def.key !== sub.name.replace(/^\\{[^}]*\\}/, '')) {\n // No explicit `name` — use the property key as the local name.\n sub.name = qname(def.xmlNs ?? schema.xmlNs ?? '', def.key);\n }\n node.children.push(sub);\n break;\n }\n case 'raw': {\n // Splice the stored XmlNode back verbatim, but realign its name to the\n // schema-declared position so the output is well-formed even when the\n // caller mutates `name`.\n const sub = raw as XmlNode;\n const expected = elementXmlName(def, schema.xmlNs);\n if (sub.name !== expected) {\n node.children.push({ ...sub, name: expected });\n } else {\n node.children.push(sub);\n }\n break;\n }\n case 'sequence': {\n const items = raw as ReadonlyArray<Record<string, unknown>>;\n const itemSchema = def.itemSchema();\n const built = items.map((item) => {\n const sub = toTree(item, itemSchema);\n // Re-tag to the declared itemName / itemNs.\n sub.name = qname(def.itemNs ?? itemSchema.xmlNs ?? '', def.itemName);\n return sub;\n });\n if (def.container !== undefined) {\n const containerAttrs: Record<string, string> = {};\n if (def.container.count) containerAttrs['count'] = String(items.length);\n node.children.push(el(elementXmlName(def, schema.xmlNs), containerAttrs, built));\n } else {\n for (const c of built) node.children.push(c);\n }\n break;\n }\n }\n }\n\n return node;\n}\n\n// ---- fromTree ---------------------------------------------------------------\n\nconst childByName = (node: XmlNode, fullName: string): XmlNode | undefined => {\n for (const c of node.children) if (c.name === fullName) return c;\n return undefined;\n};\n\nconst childrenByName = (node: XmlNode, fullName: string): XmlNode[] => {\n const out: XmlNode[] = [];\n for (const c of node.children) if (c.name === fullName) out.push(c);\n return out;\n};\n\n/** Materialise a value of `T` from an {@link XmlNode} per the supplied schema. */\nexport function fromTree<T>(node: XmlNode, schema: Schema<T>): T {\n const out: Record<string, unknown> = {};\n const expectedTag = qname(schema.xmlNs ?? '', schema.tagname);\n if (node.name !== expectedTag) {\n throw new OpenXmlSchemaError(`fromTree: expected <${schema.tagname}> (Clark \"${expectedTag}\"), got \"${node.name}\"`);\n }\n\n for (const [key, def] of Object.entries(schema.attrs) as Array<[string, AttrDef | undefined]>) {\n if (def === undefined) continue;\n const xmlKey = attrXmlKey(key, def);\n const raw = node.attrs[xmlKey];\n if (raw === undefined) {\n if (def.default !== undefined) out[key] = def.default;\n else if (!def.optional) {\n throw new OpenXmlSchemaError(`<${schema.tagname}>: required attribute \"${key}\" is missing`);\n }\n continue;\n }\n out[key] = coerceFromString(raw, def.kind, def);\n }\n\n for (const def of schema.elements) {\n const fullName = elementXmlName(def, schema.xmlNs);\n switch (def.kind) {\n case 'text': {\n const child = childByName(node, fullName);\n if (child === undefined) {\n if (def.default !== undefined) out[def.key] = def.default;\n else if (!def.optional) {\n throw new OpenXmlSchemaError(`<${schema.tagname}>: required text element \"${def.key}\" is missing`);\n }\n break;\n }\n out[def.key] = coerceFromString(child.text ?? '', def.primitive, { kind: def.primitive });\n break;\n }\n case 'empty': {\n const child = childByName(node, fullName);\n if (child !== undefined) out[def.key] = true;\n // Absent → leave key unset so the value compares equal to the\n // round-trip-emitting input that omitted it.\n break;\n }\n case 'nested': {\n const child = childByName(node, fullName);\n if (child === undefined) {\n // The element itself was omitted: leave the field unset for optional\n // nested elements, regardless of `default`. `default` here governs\n // the \"child present but @val omitted\" case (e.g. <u/> meaning\n // underline=single per ECMA-376 §18.4.13), not \"child entirely\n // absent\".\n if (!def.optional) {\n throw new OpenXmlSchemaError(`<${schema.tagname}>: required nested element \"${def.key}\" is missing`);\n }\n break;\n }\n const valAttr = def.valAttr ?? 'val';\n const raw = child.attrs[valAttr];\n if (raw === undefined) {\n if (def.default !== undefined) {\n out[def.key] = def.default;\n break;\n }\n throw new OpenXmlSchemaError(\n `<${schema.tagname}>: nested element \"${def.key}\" missing attribute \"${valAttr}\"`,\n );\n }\n out[def.key] = coerceFromString(raw, def.primitive, {\n kind: def.primitive,\n ...(def.values !== undefined ? { values: def.values } : {}),\n ...(def.min !== undefined ? { min: def.min } : {}),\n ...(def.max !== undefined ? { max: def.max } : {}),\n });\n break;\n }\n case 'raw': {\n const child = childByName(node, fullName);\n if (child === undefined) {\n if (!def.optional) {\n throw new OpenXmlSchemaError(`<${schema.tagname}>: required raw element \"${def.key}\" is missing`);\n }\n break;\n }\n out[def.key] = child;\n break;\n }\n case 'object': {\n const child = childByName(node, fullName);\n if (child === undefined) {\n if (!def.optional) {\n throw new OpenXmlSchemaError(`<${schema.tagname}>: required element \"${def.key}\" is missing`);\n }\n break;\n }\n const itemSchema = def.schema();\n // Address the child by the parent-declared name even if the child\n // schema names itself differently.\n const renamed: XmlNode =\n child.name === qname(itemSchema.xmlNs ?? '', itemSchema.tagname)\n ? child\n : { ...child, name: qname(itemSchema.xmlNs ?? '', itemSchema.tagname) };\n out[def.key] = fromTree(renamed, itemSchema);\n break;\n }\n case 'sequence': {\n const itemSchema = def.itemSchema();\n const itemFullName = qname(def.itemNs ?? itemSchema.xmlNs ?? '', def.itemName);\n const itemSchemaName = qname(itemSchema.xmlNs ?? '', itemSchema.tagname);\n const containerNode = def.container !== undefined ? childByName(node, fullName) : node;\n const items: unknown[] = [];\n if (containerNode !== undefined) {\n const matches = childrenByName(containerNode, itemFullName);\n for (const m of matches) {\n const renamed: XmlNode = m.name === itemSchemaName ? m : { ...m, name: itemSchemaName };\n items.push(fromTree(renamed, itemSchema));\n }\n }\n out[def.key] = items;\n break;\n }\n }\n }\n\n const built = out as unknown as T;\n return schema.postParse ? schema.postParse(built, node) : built;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"serialize-BtxgssFK.mjs","names":[],"sources":["../src/schema/core.ts","../src/utils/xsd-boolean.ts","../src/schema/serialize.ts"],"sourcesContent":["// Schema layer types — pure data, zero classes.\n//\n// A Schema<T> describes how a plain `T` is mapped to and from an XmlNode. The\n// runtime serialiser (src/schema/serialize.ts) is a single switch-on-kind walk\n// that needs nothing beyond these tables; bundlers can drop schemas a build\n// path never imports because each lives in its own const.\n//\n// Lazy element schemas (`schema: () => SideSchema`) are how circular references\n// — Border has Sides, Side has its own Color, etc. — stay expressible without\n// hoisting hazards at module load.\n\n/** Primitive coercion kinds attribute values may declare. */\nexport type Primitive = 'string' | 'int' | 'float' | 'bool';\n\nexport interface AttrDef {\n kind: Primitive | 'enum';\n /** Allowed values when kind === 'enum'. */\n values?: readonly string[];\n /** Treat the attribute as optional; missing → undefined. */\n optional?: boolean;\n /**\n * Default applied during fromTree when the attribute is absent. Never\n * auto-stripped during toTree — round-trip equivalence is the primary\n * concern; explicit emitters decide when to omit.\n */\n default?: unknown;\n /** Numeric range bounds for kind in {'int', 'float'}. */\n min?: number;\n max?: number;\n /** XML attribute name when it differs from the property key on T. */\n xmlName?: string;\n /** Namespace URI for the XML attribute. Empty / undefined = no namespace. */\n xmlNs?: string;\n}\n\n/**\n * Discriminated union of element shapes a schema can declare. Names are\n * unprefixed (`xmlNs` carries the namespace); the serialiser pairs them into\n * Clark names internally.\n */\nexport type ElementDef =\n | {\n kind: 'text';\n /** Property key on T — the value lands at `T[key]`. */\n key: string;\n /** XML element local name. Defaults to `key` when omitted. */\n name?: string;\n xmlNs?: string;\n primitive: Primitive;\n optional?: boolean;\n default?: unknown;\n /**\n * Fixed attributes always emitted on this element. Keys in Clark\n * notation. On parse, attributes other than these are ignored; keep the\n * schema strict only for the value (text content).\n *\n * Used for the `xsi:type=\"dcterms:W3CDTF\"` marker that docProps/core.xml\n * emits on its <dcterms:created> / <dcterms:modified> children, and\n * similar fixed-marker patterns.\n */\n attrs?: Record<string, string>;\n }\n | {\n kind: 'object';\n key: string;\n name?: string;\n xmlNs?: string;\n // Schema is contravariant in T at the element boundary; named types\n // come back via T anyway. The `any` is intentional — `unknown` would\n // force a cast in every concrete schema definition with no extra safety.\n // oxlint-disable-next-line typescript/no-explicit-any\n schema: () => Schema<any>;\n optional?: boolean;\n }\n | {\n kind: 'sequence';\n key: string;\n /** Local name of the repeated child element. */\n itemName: string;\n itemNs?: string;\n // See ElementDef.kind === 'object' for why `any` survives here.\n // oxlint-disable-next-line typescript/no-explicit-any\n itemSchema: () => Schema<any>;\n /** Optional wrapper element holding the items. */\n container?: { name: string; xmlNs?: string; count?: boolean };\n }\n | {\n /**\n * Empty marker element — `<key/>` whose presence sets `T[key] = true`,\n * absence leaves it `undefined`. Used by Font's `<b/>`, `<i/>`, etc.\n */\n kind: 'empty';\n key: string;\n name?: string;\n xmlNs?: string;\n }\n | {\n /**\n * `<key val=\"value\"/>` style child carrying a single primitive value via\n * an attribute (default `val`). This is openpyxl's NestedString /\n * NestedFloat / NestedInteger / NestedBool / NestedNoneSet pattern; it\n * shows up across Font, NumberFormat children and several chart\n * sub-elements.\n */\n kind: 'nested';\n key: string;\n name?: string;\n xmlNs?: string;\n primitive: Primitive | 'enum';\n /** Allowed values when primitive === 'enum'. */\n values?: readonly string[];\n /** Attribute name carrying the value. Defaults to \"val\". */\n valAttr?: string;\n /** Numeric range bounds (int / float). */\n min?: number;\n max?: number;\n optional?: boolean;\n default?: unknown;\n }\n | {\n /**\n * Opaque round-trip slot — fromTree stores the matched child as a raw\n * `XmlNode`, toTree splices it back verbatim. Used for subtrees we don't\n * want to model in detail (e.g. the vt:vector content under app.xml's\n * HeadingPairs / TitlesOfParts) but still need to preserve byte-for-byte\n * through edits.\n */\n kind: 'raw';\n key: string;\n name?: string;\n xmlNs?: string;\n optional?: boolean;\n };\n\nexport interface Schema<T> {\n /** Local element name. */\n tagname: string;\n /** Namespace URI of this element. */\n xmlNs?: string;\n /** Attribute table keyed by property name on T. */\n attrs: { readonly [K in keyof T & string]?: AttrDef };\n /** Child elements in declaration / emission order. */\n elements: ReadonlyArray<ElementDef>;\n /** Hook to normalise the parsed object (e.g., infer derived fields). */\n postParse?: (value: T, node: import('../xml/tree.js').XmlNode) => T;\n /** Hook to normalise the value before serialisation. */\n preSerialize?: (value: T) => T;\n}\n\n/**\n * Identity helper that pins inference to the supplied `T`. The runtime is just\n * `s => s`; the value matters only for the call-site type.\n */\nexport function defineSchema<T>(s: Schema<T>): Schema<T> {\n return s;\n}\n","/**\n * Parse an xsd:boolean, or `undefined` when the text is outside its lexical\n * space. The type's whiteSpace facet is `collapse`, so the padding a\n * pretty-printer leaves around the text is insignificant and a reformatted\n * part reads the same as a compact one. `t` / `f` and mixed case are outside\n * the lexical space proper, but openpyxl accepts them, so the readers here do\n * too rather than rejecting a file another tool opens.\n */\nexport const parseXsdBoolean = (raw: string | undefined): boolean | undefined => {\n // Excel writes `1` / `0`; answer the common spellings without allocating.\n if (raw === '1' || raw === 'true') return true;\n if (raw === '0' || raw === 'false') return false;\n if (raw === undefined) return undefined;\n const text = raw.trim().toLowerCase();\n if (text === '1' || text === 'true' || text === 't') return true;\n if (text === '0' || text === 'false' || text === 'f') return false;\n return undefined;\n};\n","// Schema-driven (de)serialisation. One switch-on-kind walk in each direction;\n// the schema does the work, no class-based descriptors.\n//\n// `toTree` and `fromTree` are pure functions over plain data. They run the same\n// on the schema layer's own types and on user types in the styles / chart /\n// drawing modules.\n\nimport { OpenXmlSchemaError } from '../utils/exceptions.js';\nimport { parseXsdBoolean } from '../utils/xsd-boolean.js';\nimport { qname } from '../xml/namespaces.js';\nimport { el, type XmlNode } from '../xml/tree.js';\nimport type { AttrDef, ElementDef, Primitive, Schema } from './core.js';\n\n// ---- coercion helpers -------------------------------------------------------\n\nconst coerceFromString = (raw: string, kind: Primitive | 'enum', def: AttrDef): unknown => {\n switch (kind) {\n case 'string':\n return raw;\n case 'int': {\n const n = Number.parseInt(raw, 10);\n if (!Number.isFinite(n)) throw new OpenXmlSchemaError(`expected an integer, got \"${raw}\"`);\n if (def.min !== undefined && n < def.min) throw new OpenXmlSchemaError(`int \"${n}\" is below min ${def.min}`);\n if (def.max !== undefined && n > def.max) throw new OpenXmlSchemaError(`int \"${n}\" is above max ${def.max}`);\n return n;\n }\n case 'float': {\n const n = Number.parseFloat(raw);\n if (!Number.isFinite(n)) throw new OpenXmlSchemaError(`expected a number, got \"${raw}\"`);\n if (def.min !== undefined && n < def.min) throw new OpenXmlSchemaError(`float \"${n}\" is below min ${def.min}`);\n if (def.max !== undefined && n > def.max) throw new OpenXmlSchemaError(`float \"${n}\" is above max ${def.max}`);\n return n;\n }\n case 'bool': {\n const v = parseXsdBoolean(raw);\n if (v === undefined) throw new OpenXmlSchemaError(`expected a boolean, got \"${raw}\"`);\n return v;\n }\n case 'enum': {\n if (!def.values?.includes(raw)) {\n throw new OpenXmlSchemaError(`expected one of [${def.values?.join(', ') ?? ''}], got \"${raw}\"`);\n }\n return raw;\n }\n }\n};\n\nconst coerceToString = (value: unknown, kind: Primitive | 'enum', def: AttrDef): string => {\n switch (kind) {\n case 'string':\n if (typeof value !== 'string') throw new OpenXmlSchemaError(`expected a string, got ${typeof value}`);\n return value;\n case 'int': {\n if (typeof value !== 'number' || !Number.isFinite(value) || !Number.isInteger(value)) {\n throw new OpenXmlSchemaError(`expected an integer, got ${String(value)}`);\n }\n return String(value);\n }\n case 'float': {\n if (typeof value !== 'number' || !Number.isFinite(value)) {\n throw new OpenXmlSchemaError(`expected a number, got ${String(value)}`);\n }\n return String(value);\n }\n case 'bool': {\n if (typeof value !== 'boolean') throw new OpenXmlSchemaError(`expected a boolean, got ${typeof value}`);\n // OOXML convention: '1' / '0'.\n return value ? '1' : '0';\n }\n case 'enum': {\n if (typeof value !== 'string' || !def.values || !def.values.includes(value)) {\n throw new OpenXmlSchemaError(`enum value out of range: ${String(value)}`);\n }\n return value;\n }\n }\n};\n\nconst attrXmlKey = (key: string, def: AttrDef): string => qname(def.xmlNs ?? '', def.xmlName ?? key);\nconst elementXmlName = (def: ElementDef, fallbackNs: string | undefined): string => {\n const local = def.kind === 'sequence' ? (def.container?.name ?? def.itemName) : (def.name ?? def.key);\n const ns = def.kind === 'sequence' ? (def.container?.xmlNs ?? def.itemNs ?? fallbackNs) : (def.xmlNs ?? fallbackNs);\n return qname(ns ?? '', local);\n};\n\n// ---- toTree -----------------------------------------------------------------\n\n/** Serialise a value of `T` into an {@link XmlNode} per the supplied schema. */\nexport function toTree<T>(value: T, schema: Schema<T>): XmlNode {\n const v = (schema.preSerialize ? schema.preSerialize(value) : value) as Record<string, unknown>;\n const node = el(qname(schema.xmlNs ?? '', schema.tagname));\n\n for (const [key, def] of Object.entries(schema.attrs) as Array<[string, AttrDef | undefined]>) {\n if (def === undefined) continue;\n const raw = v[key];\n if (raw === undefined) {\n if (def.optional) continue;\n throw new OpenXmlSchemaError(`<${schema.tagname}>: required attribute \"${key}\" is missing`);\n }\n node.attrs[attrXmlKey(key, def)] = coerceToString(raw, def.kind, def);\n }\n\n for (const def of schema.elements) {\n const raw = v[def.key];\n if (raw === undefined) {\n // 'empty' has no `optional`; presence is binary on the value itself.\n // 'sequence' is implicitly optional (undefined / [] = no items). 'raw'\n // uses the same optional flag as text/object.\n if ((def.kind === 'text' || def.kind === 'object' || def.kind === 'raw') && !def.optional) {\n throw new OpenXmlSchemaError(`<${schema.tagname}>: required element \"${def.key}\" is missing`);\n }\n continue;\n }\n switch (def.kind) {\n case 'text': {\n const text = coerceToString(raw, def.primitive, { kind: def.primitive });\n node.children.push(el(elementXmlName(def, schema.xmlNs), def.attrs ?? {}, [], text));\n break;\n }\n case 'empty': {\n if (raw === true) node.children.push(el(elementXmlName(def, schema.xmlNs), {}, []));\n break;\n }\n case 'nested': {\n const valAttr = def.valAttr ?? 'val';\n const fakeAttrDef: AttrDef = {\n kind: def.primitive,\n ...(def.values !== undefined ? { values: def.values } : {}),\n ...(def.min !== undefined ? { min: def.min } : {}),\n ...(def.max !== undefined ? { max: def.max } : {}),\n };\n const text = coerceToString(raw, def.primitive, fakeAttrDef);\n node.children.push(el(elementXmlName(def, schema.xmlNs), { [valAttr]: text }, []));\n break;\n }\n case 'object': {\n const sub = toTree(raw as Record<string, unknown>, def.schema());\n // Allow the schema to declare its own tagname OR be addressed by the\n // parent under a different element name. We honour the schema's tagname\n // (it's the canonical identity for that type).\n if (def.name !== undefined && sub.name !== qname(def.xmlNs ?? schema.xmlNs ?? '', def.name)) {\n // Re-tag the produced element to the parent-defined name.\n sub.name = qname(def.xmlNs ?? schema.xmlNs ?? '', def.name);\n } else if (def.name === undefined && def.key !== sub.name.replace(/^\\{[^}]*\\}/, '')) {\n // No explicit `name` — use the property key as the local name.\n sub.name = qname(def.xmlNs ?? schema.xmlNs ?? '', def.key);\n }\n node.children.push(sub);\n break;\n }\n case 'raw': {\n // Splice the stored XmlNode back verbatim, but realign its name to the\n // schema-declared position so the output is well-formed even when the\n // caller mutates `name`.\n const sub = raw as XmlNode;\n const expected = elementXmlName(def, schema.xmlNs);\n if (sub.name !== expected) {\n node.children.push({ ...sub, name: expected });\n } else {\n node.children.push(sub);\n }\n break;\n }\n case 'sequence': {\n const items = raw as ReadonlyArray<Record<string, unknown>>;\n const itemSchema = def.itemSchema();\n const built = items.map((item) => {\n const sub = toTree(item, itemSchema);\n // Re-tag to the declared itemName / itemNs.\n sub.name = qname(def.itemNs ?? itemSchema.xmlNs ?? '', def.itemName);\n return sub;\n });\n if (def.container !== undefined) {\n const containerAttrs: Record<string, string> = {};\n if (def.container.count) containerAttrs['count'] = String(items.length);\n node.children.push(el(elementXmlName(def, schema.xmlNs), containerAttrs, built));\n } else {\n for (const c of built) node.children.push(c);\n }\n break;\n }\n }\n }\n\n return node;\n}\n\n// ---- fromTree ---------------------------------------------------------------\n\nconst childByName = (node: XmlNode, fullName: string): XmlNode | undefined => {\n for (const c of node.children) if (c.name === fullName) return c;\n return undefined;\n};\n\nconst childrenByName = (node: XmlNode, fullName: string): XmlNode[] => {\n const out: XmlNode[] = [];\n for (const c of node.children) if (c.name === fullName) out.push(c);\n return out;\n};\n\n/** Materialise a value of `T` from an {@link XmlNode} per the supplied schema. */\nexport function fromTree<T>(node: XmlNode, schema: Schema<T>): T {\n const out: Record<string, unknown> = {};\n const expectedTag = qname(schema.xmlNs ?? '', schema.tagname);\n if (node.name !== expectedTag) {\n throw new OpenXmlSchemaError(`fromTree: expected <${schema.tagname}> (Clark \"${expectedTag}\"), got \"${node.name}\"`);\n }\n\n for (const [key, def] of Object.entries(schema.attrs) as Array<[string, AttrDef | undefined]>) {\n if (def === undefined) continue;\n const xmlKey = attrXmlKey(key, def);\n const raw = node.attrs[xmlKey];\n if (raw === undefined) {\n if (def.default !== undefined) out[key] = def.default;\n else if (!def.optional) {\n throw new OpenXmlSchemaError(`<${schema.tagname}>: required attribute \"${key}\" is missing`);\n }\n continue;\n }\n out[key] = coerceFromString(raw, def.kind, def);\n }\n\n for (const def of schema.elements) {\n const fullName = elementXmlName(def, schema.xmlNs);\n switch (def.kind) {\n case 'text': {\n const child = childByName(node, fullName);\n if (child === undefined) {\n if (def.default !== undefined) out[def.key] = def.default;\n else if (!def.optional) {\n throw new OpenXmlSchemaError(`<${schema.tagname}>: required text element \"${def.key}\" is missing`);\n }\n break;\n }\n out[def.key] = coerceFromString(child.text ?? '', def.primitive, { kind: def.primitive });\n break;\n }\n case 'empty': {\n const child = childByName(node, fullName);\n if (child !== undefined) out[def.key] = true;\n // Absent → leave key unset so the value compares equal to the\n // round-trip-emitting input that omitted it.\n break;\n }\n case 'nested': {\n const child = childByName(node, fullName);\n if (child === undefined) {\n // The element itself was omitted: leave the field unset for optional\n // nested elements, regardless of `default`. `default` here governs\n // the \"child present but @val omitted\" case (e.g. <u/> meaning\n // underline=single per ECMA-376 §18.4.13), not \"child entirely\n // absent\".\n if (!def.optional) {\n throw new OpenXmlSchemaError(`<${schema.tagname}>: required nested element \"${def.key}\" is missing`);\n }\n break;\n }\n const valAttr = def.valAttr ?? 'val';\n const raw = child.attrs[valAttr];\n if (raw === undefined) {\n if (def.default !== undefined) {\n out[def.key] = def.default;\n break;\n }\n throw new OpenXmlSchemaError(\n `<${schema.tagname}>: nested element \"${def.key}\" missing attribute \"${valAttr}\"`,\n );\n }\n out[def.key] = coerceFromString(raw, def.primitive, {\n kind: def.primitive,\n ...(def.values !== undefined ? { values: def.values } : {}),\n ...(def.min !== undefined ? { min: def.min } : {}),\n ...(def.max !== undefined ? { max: def.max } : {}),\n });\n break;\n }\n case 'raw': {\n const child = childByName(node, fullName);\n if (child === undefined) {\n if (!def.optional) {\n throw new OpenXmlSchemaError(`<${schema.tagname}>: required raw element \"${def.key}\" is missing`);\n }\n break;\n }\n out[def.key] = child;\n break;\n }\n case 'object': {\n const child = childByName(node, fullName);\n if (child === undefined) {\n if (!def.optional) {\n throw new OpenXmlSchemaError(`<${schema.tagname}>: required element \"${def.key}\" is missing`);\n }\n break;\n }\n const itemSchema = def.schema();\n // Address the child by the parent-declared name even if the child\n // schema names itself differently.\n const renamed: XmlNode =\n child.name === qname(itemSchema.xmlNs ?? '', itemSchema.tagname)\n ? child\n : { ...child, name: qname(itemSchema.xmlNs ?? '', itemSchema.tagname) };\n out[def.key] = fromTree(renamed, itemSchema);\n break;\n }\n case 'sequence': {\n const itemSchema = def.itemSchema();\n const itemFullName = qname(def.itemNs ?? itemSchema.xmlNs ?? '', def.itemName);\n const itemSchemaName = qname(itemSchema.xmlNs ?? '', itemSchema.tagname);\n const containerNode = def.container !== undefined ? childByName(node, fullName) : node;\n const items: unknown[] = [];\n if (containerNode !== undefined) {\n const matches = childrenByName(containerNode, itemFullName);\n for (const m of matches) {\n const renamed: XmlNode = m.name === itemSchemaName ? m : { ...m, name: itemSchemaName };\n items.push(fromTree(renamed, itemSchema));\n }\n }\n out[def.key] = items;\n break;\n }\n }\n }\n\n const built = out as unknown as T;\n return schema.postParse ? schema.postParse(built, node) : built;\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { n as escapeXmlAttr, r as escapeXmlText } from "./escape-rA5UpibT.mjs";
2
- import { At as parseQName, Dt as XML_NS, V as DEFAULT_PREFIXES } from "./tree-BX-sRRVp.mjs";
2
+ import { Mt as parseQName, Ot as XML_NS, V as DEFAULT_PREFIXES } from "./tree-CspNjuYl.mjs";
3
3
  //#region src/xml/serializer.ts
4
4
  /**
5
5
  * Serialize an {@link XmlNode} tree into a UTF-8 byte payload. The
@@ -125,4 +125,4 @@ const emit = (out, node, allocation, isRoot) => {
125
125
  //#endregion
126
126
  export { serializeXml as t };
127
127
 
128
- //# sourceMappingURL=serializer-dhv07Z6F.mjs.map
128
+ //# sourceMappingURL=serializer-N6XIwsgp.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"serializer-dhv07Z6F.mjs","names":[],"sources":["../src/xml/serializer.ts"],"sourcesContent":["// DOM-style XML serializer. Inverse of src/xml/parser.ts.\n//\n// XmlNode trees use Clark-notation names (`{ns}local`); the serializer\n// rebuilds prefix mappings and emits a single UTF-8 byte payload.\n//\n// Algorithm:\n// 1. walk the tree once, collecting every namespace URI used by\n// elements or attributes;\n// 2. assign each URI a prefix — DEFAULT_PREFIXES first, then\n// auto-generated `ns{N}` — and decide which (if any) becomes the\n// default (xmlns=\"…\") namespace by reusing the root element's NS;\n// 3. emit the XML declaration, root open tag with all xmlns / xmlns:*\n// declarations, then a recursive children walk that escapes text\n// and attribute values.\n//\n// Output style matches openpyxl/Excel: no whitespace between elements,\n// `<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>` on its own\n// line, attribute values quoted with `\"`.\n\nimport { escapeXmlAttr, escapeXmlText } from '../utils/escape.js';\nimport { DEFAULT_PREFIXES, parseQName, XML_NS } from './namespaces.js';\nimport type { XmlNode } from './tree.js';\n\nexport interface SerializeOptions {\n /** Emit `<?xml … ?>` declaration. Defaults to true. */\n xmlDeclaration?: boolean;\n /** `standalone` attribute on the declaration. Defaults to 'yes'. */\n standalone?: 'yes' | 'no' | 'omit';\n /**\n * Namespace URI → prefix already bound by an ancestor, for a fragment being\n * spliced into a larger document. Those bindings are reused and not\n * redeclared on the fragment's own root. `''` means the ancestor's default\n * namespace — attributes never inherit a default binding, so only use it for\n * a namespace whose attributes are unqualified (every SpreadsheetML part).\n */\n inScopePrefixes?: Readonly<Record<string, string>>;\n}\n\n/**\n * Serialize an {@link XmlNode} tree into a UTF-8 byte payload. The\n * inverse of {@link parseXml}: `parseXml(serializeXml(n))` yields a\n * tree structurally equivalent to `n` modulo attribute insertion order\n * (which both directions preserve on Node 18+ / V8).\n */\nexport function serializeXml(root: XmlNode, opts: SerializeOptions = {}): Uint8Array {\n const { xmlDeclaration = true, standalone = 'yes', inScopePrefixes } = opts;\n\n const allocation = allocatePrefixes(root, inScopePrefixes);\n const out: string[] = [];\n\n if (xmlDeclaration) {\n out.push('<?xml version=\"1.0\" encoding=\"UTF-8\"');\n if (standalone !== 'omit') out.push(` standalone=\"${standalone}\"`);\n out.push('?>\\n');\n }\n\n emit(out, root, allocation, /* isRoot */ true);\n\n return new TextEncoder().encode(out.join(''));\n}\n\n// ---- prefix allocation ------------------------------------------------------\n\ninterface Allocation {\n /** ns URI → prefix ('' = default namespace) */\n prefixOf: Map<string, string>;\n /** prefix declarations to emit on the root element, in deterministic order */\n declarations: Array<{ prefix: string; ns: string }>;\n}\n\nconst allocatePrefixes = (root: XmlNode, inScope?: Readonly<Record<string, string>>): Allocation => {\n const used = new Set<string>();\n collectNamespaces(root, used, /* attrsToo */ true);\n used.delete(''); // empty NS = unprefixed names; not emitted as xmlns\n\n const prefixOf = new Map<string, string>();\n // Bindings an ancestor already declared: reuse them, and leave them out of\n // this fragment's own declarations.\n const inherited = new Set<string>();\n for (const [ns, prefix] of Object.entries(inScope ?? {})) {\n if (ns === '' || prefixOf.has(ns)) continue;\n prefixOf.set(ns, prefix);\n inherited.add(ns);\n }\n\n // Decide the default namespace. Prefer the root element's NS if its\n // canonical prefix in DEFAULT_PREFIXES is empty (i.e. designed to live\n // as a default), so the bulk of the root subtree stays unprefixed — unless\n // an ancestor already bound that namespace, in which case its binding wins.\n const rootNs = parseQName(root.name).ns;\n let defaultNs = '';\n if (rootNs && DEFAULT_PREFIXES[rootNs] === '' && !prefixOf.has(rootNs)) {\n defaultNs = rootNs;\n prefixOf.set(defaultNs, '');\n }\n // `xml` and `xmlns` are reserved by the XMLNS spec; xml ↔ XML_NS is\n // predefined and must NOT be redeclared via xmlns:xml=\"…\".\n prefixOf.set(XML_NS, 'xml');\n\n // Pass 1: respect DEFAULT_PREFIXES for namespaces that have a\n // canonical short prefix.\n let auto = 0;\n const usedPrefixes = new Set<string>(['', 'xml', 'xmlns', ...prefixOf.values()]);\n const ordered = Array.from(used).sort();\n for (const ns of ordered) {\n if (prefixOf.has(ns)) continue;\n const preferred = DEFAULT_PREFIXES[ns];\n if (preferred !== undefined && preferred !== '' && !usedPrefixes.has(preferred)) {\n prefixOf.set(ns, preferred);\n usedPrefixes.add(preferred);\n }\n }\n // Pass 2: auto-allocate for the remainder.\n for (const ns of ordered) {\n if (prefixOf.has(ns)) continue;\n let prefix = `ns${auto++}`;\n while (usedPrefixes.has(prefix)) prefix = `ns${auto++}`;\n prefixOf.set(ns, prefix);\n usedPrefixes.add(prefix);\n }\n\n // Emission order: default first, then other prefixes alphabetically by ns\n // URI for determinism. XML_NS is reserved and never declared.\n const declarations: Array<{ prefix: string; ns: string }> = [];\n if (defaultNs !== '') declarations.push({ prefix: '', ns: defaultNs });\n const inheritedDefault = [...inherited].find((ns) => prefixOf.get(ns) === '');\n for (const ns of ordered) {\n if (ns === defaultNs) continue;\n if (ns === inheritedDefault) continue;\n if (ns === XML_NS) continue;\n if (inherited.has(ns)) continue;\n const prefix = prefixOf.get(ns);\n if (prefix === undefined) continue;\n declarations.push({ prefix, ns });\n }\n\n return { prefixOf, declarations };\n};\n\nconst collectNamespaces = (node: XmlNode, into: Set<string>, attrsToo: boolean): void => {\n into.add(parseQName(node.name).ns);\n if (attrsToo) {\n for (const attrName of Object.keys(node.attrs)) {\n into.add(parseQName(attrName).ns);\n }\n }\n for (const c of node.children) collectNamespaces(c, into, attrsToo);\n};\n\n// ---- emission ---------------------------------------------------------------\n\nconst buildElementPrefix = (name: string, prefixOf: Map<string, string>): string => {\n const { ns, local } = parseQName(name);\n if (ns === '') return local;\n const prefix = prefixOf.get(ns);\n if (prefix === undefined || prefix === '') return local;\n return `${prefix}:${local}`;\n};\n\nconst buildAttrPrefix = (name: string, prefixOf: Map<string, string>): string => {\n const { ns, local } = parseQName(name);\n if (ns === '') return local;\n // Attributes never inherit the default namespace; if the namespace is\n // mapped to the default prefix, they still need an explicit prefix.\n const prefix = prefixOf.get(ns);\n if (prefix === undefined || prefix === '') {\n // Attribute lives in a namespace that we marked as default-only;\n // fall through to no prefix (the namespace must already be declared\n // by ancestor walk, but for default-namespace attrs that's invalid\n // XML — we keep it bare anyway since OOXML never produces this).\n return local;\n }\n return `${prefix}:${local}`;\n};\n\nconst emit = (out: string[], node: XmlNode, allocation: Allocation, isRoot: boolean): void => {\n const tag = buildElementPrefix(node.name, allocation.prefixOf);\n out.push('<', tag);\n\n if (isRoot) {\n for (const { prefix, ns } of allocation.declarations) {\n out.push(prefix === '' ? ` xmlns=\"${escapeXmlAttr(ns)}\"` : ` xmlns:${prefix}=\"${escapeXmlAttr(ns)}\"`);\n }\n }\n\n for (const [name, value] of Object.entries(node.attrs)) {\n const attrName = buildAttrPrefix(name, allocation.prefixOf);\n out.push(' ', attrName, '=\"', escapeXmlAttr(value), '\"');\n }\n\n const text = node.text;\n const hasText = text !== undefined && text !== '';\n const hasChildren = node.children.length > 0;\n if (!hasText && !hasChildren) {\n out.push('/>');\n return;\n }\n\n out.push('>');\n if (hasText) out.push(escapeXmlText(text));\n for (const c of node.children) emit(out, c, allocation, /* isRoot */ false);\n out.push('</', tag, '>');\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"serializer-N6XIwsgp.mjs","names":[],"sources":["../src/xml/serializer.ts"],"sourcesContent":["// DOM-style XML serializer. Inverse of src/xml/parser.ts.\n//\n// XmlNode trees use Clark-notation names (`{ns}local`); the serializer\n// rebuilds prefix mappings and emits a single UTF-8 byte payload.\n//\n// Algorithm:\n// 1. walk the tree once, collecting every namespace URI used by\n// elements or attributes;\n// 2. assign each URI a prefix — DEFAULT_PREFIXES first, then\n// auto-generated `ns{N}` — and decide which (if any) becomes the\n// default (xmlns=\"…\") namespace by reusing the root element's NS;\n// 3. emit the XML declaration, root open tag with all xmlns / xmlns:*\n// declarations, then a recursive children walk that escapes text\n// and attribute values.\n//\n// Output style matches openpyxl/Excel: no whitespace between elements,\n// `<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>` on its own\n// line, attribute values quoted with `\"`.\n\nimport { escapeXmlAttr, escapeXmlText } from '../utils/escape.js';\nimport { DEFAULT_PREFIXES, parseQName, XML_NS } from './namespaces.js';\nimport type { XmlNode } from './tree.js';\n\nexport interface SerializeOptions {\n /** Emit `<?xml … ?>` declaration. Defaults to true. */\n xmlDeclaration?: boolean;\n /** `standalone` attribute on the declaration. Defaults to 'yes'. */\n standalone?: 'yes' | 'no' | 'omit';\n /**\n * Namespace URI → prefix already bound by an ancestor, for a fragment being\n * spliced into a larger document. Those bindings are reused and not\n * redeclared on the fragment's own root. `''` means the ancestor's default\n * namespace — attributes never inherit a default binding, so only use it for\n * a namespace whose attributes are unqualified (every SpreadsheetML part).\n */\n inScopePrefixes?: Readonly<Record<string, string>>;\n}\n\n/**\n * Serialize an {@link XmlNode} tree into a UTF-8 byte payload. The\n * inverse of {@link parseXml}: `parseXml(serializeXml(n))` yields a\n * tree structurally equivalent to `n` modulo attribute insertion order\n * (which both directions preserve on Node 18+ / V8).\n */\nexport function serializeXml(root: XmlNode, opts: SerializeOptions = {}): Uint8Array {\n const { xmlDeclaration = true, standalone = 'yes', inScopePrefixes } = opts;\n\n const allocation = allocatePrefixes(root, inScopePrefixes);\n const out: string[] = [];\n\n if (xmlDeclaration) {\n out.push('<?xml version=\"1.0\" encoding=\"UTF-8\"');\n if (standalone !== 'omit') out.push(` standalone=\"${standalone}\"`);\n out.push('?>\\n');\n }\n\n emit(out, root, allocation, /* isRoot */ true);\n\n return new TextEncoder().encode(out.join(''));\n}\n\n// ---- prefix allocation ------------------------------------------------------\n\ninterface Allocation {\n /** ns URI → prefix ('' = default namespace) */\n prefixOf: Map<string, string>;\n /** prefix declarations to emit on the root element, in deterministic order */\n declarations: Array<{ prefix: string; ns: string }>;\n}\n\nconst allocatePrefixes = (root: XmlNode, inScope?: Readonly<Record<string, string>>): Allocation => {\n const used = new Set<string>();\n collectNamespaces(root, used, /* attrsToo */ true);\n used.delete(''); // empty NS = unprefixed names; not emitted as xmlns\n\n const prefixOf = new Map<string, string>();\n // Bindings an ancestor already declared: reuse them, and leave them out of\n // this fragment's own declarations.\n const inherited = new Set<string>();\n for (const [ns, prefix] of Object.entries(inScope ?? {})) {\n if (ns === '' || prefixOf.has(ns)) continue;\n prefixOf.set(ns, prefix);\n inherited.add(ns);\n }\n\n // Decide the default namespace. Prefer the root element's NS if its\n // canonical prefix in DEFAULT_PREFIXES is empty (i.e. designed to live\n // as a default), so the bulk of the root subtree stays unprefixed — unless\n // an ancestor already bound that namespace, in which case its binding wins.\n const rootNs = parseQName(root.name).ns;\n let defaultNs = '';\n if (rootNs && DEFAULT_PREFIXES[rootNs] === '' && !prefixOf.has(rootNs)) {\n defaultNs = rootNs;\n prefixOf.set(defaultNs, '');\n }\n // `xml` and `xmlns` are reserved by the XMLNS spec; xml ↔ XML_NS is\n // predefined and must NOT be redeclared via xmlns:xml=\"…\".\n prefixOf.set(XML_NS, 'xml');\n\n // Pass 1: respect DEFAULT_PREFIXES for namespaces that have a\n // canonical short prefix.\n let auto = 0;\n const usedPrefixes = new Set<string>(['', 'xml', 'xmlns', ...prefixOf.values()]);\n const ordered = Array.from(used).sort();\n for (const ns of ordered) {\n if (prefixOf.has(ns)) continue;\n const preferred = DEFAULT_PREFIXES[ns];\n if (preferred !== undefined && preferred !== '' && !usedPrefixes.has(preferred)) {\n prefixOf.set(ns, preferred);\n usedPrefixes.add(preferred);\n }\n }\n // Pass 2: auto-allocate for the remainder.\n for (const ns of ordered) {\n if (prefixOf.has(ns)) continue;\n let prefix = `ns${auto++}`;\n while (usedPrefixes.has(prefix)) prefix = `ns${auto++}`;\n prefixOf.set(ns, prefix);\n usedPrefixes.add(prefix);\n }\n\n // Emission order: default first, then other prefixes alphabetically by ns\n // URI for determinism. XML_NS is reserved and never declared.\n const declarations: Array<{ prefix: string; ns: string }> = [];\n if (defaultNs !== '') declarations.push({ prefix: '', ns: defaultNs });\n const inheritedDefault = [...inherited].find((ns) => prefixOf.get(ns) === '');\n for (const ns of ordered) {\n if (ns === defaultNs) continue;\n if (ns === inheritedDefault) continue;\n if (ns === XML_NS) continue;\n if (inherited.has(ns)) continue;\n const prefix = prefixOf.get(ns);\n if (prefix === undefined) continue;\n declarations.push({ prefix, ns });\n }\n\n return { prefixOf, declarations };\n};\n\nconst collectNamespaces = (node: XmlNode, into: Set<string>, attrsToo: boolean): void => {\n into.add(parseQName(node.name).ns);\n if (attrsToo) {\n for (const attrName of Object.keys(node.attrs)) {\n into.add(parseQName(attrName).ns);\n }\n }\n for (const c of node.children) collectNamespaces(c, into, attrsToo);\n};\n\n// ---- emission ---------------------------------------------------------------\n\nconst buildElementPrefix = (name: string, prefixOf: Map<string, string>): string => {\n const { ns, local } = parseQName(name);\n if (ns === '') return local;\n const prefix = prefixOf.get(ns);\n if (prefix === undefined || prefix === '') return local;\n return `${prefix}:${local}`;\n};\n\nconst buildAttrPrefix = (name: string, prefixOf: Map<string, string>): string => {\n const { ns, local } = parseQName(name);\n if (ns === '') return local;\n // Attributes never inherit the default namespace; if the namespace is\n // mapped to the default prefix, they still need an explicit prefix.\n const prefix = prefixOf.get(ns);\n if (prefix === undefined || prefix === '') {\n // Attribute lives in a namespace that we marked as default-only;\n // fall through to no prefix (the namespace must already be declared\n // by ancestor walk, but for default-namespace attrs that's invalid\n // XML — we keep it bare anyway since OOXML never produces this).\n return local;\n }\n return `${prefix}:${local}`;\n};\n\nconst emit = (out: string[], node: XmlNode, allocation: Allocation, isRoot: boolean): void => {\n const tag = buildElementPrefix(node.name, allocation.prefixOf);\n out.push('<', tag);\n\n if (isRoot) {\n for (const { prefix, ns } of allocation.declarations) {\n out.push(prefix === '' ? ` xmlns=\"${escapeXmlAttr(ns)}\"` : ` xmlns:${prefix}=\"${escapeXmlAttr(ns)}\"`);\n }\n }\n\n for (const [name, value] of Object.entries(node.attrs)) {\n const attrName = buildAttrPrefix(name, allocation.prefixOf);\n out.push(' ', attrName, '=\"', escapeXmlAttr(value), '\"');\n }\n\n const text = node.text;\n const hasText = text !== undefined && text !== '';\n const hasChildren = node.children.length > 0;\n if (!hasText && !hasChildren) {\n out.push('/>');\n return;\n }\n\n out.push('>');\n if (hasText) out.push(escapeXmlText(text));\n for (const c of node.children) emit(out, c, allocation, /* isRoot */ false);\n out.push('</', tag, '>');\n};\n"],"mappings":"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"}
@@ -2,28 +2,24 @@ import { i as OpenXmlIoError, o as OpenXmlSchemaError } from "./exceptions-D-CFw
2
2
  import { _ as rowNumberFromAttr, c as derivedRowNumber, s as coordinateToTuple } from "./coordinate-CxC88uBk.mjs";
3
3
  import { t as ERROR_CODES } from "./inference-BMvv9cUY.mjs";
4
4
  import { a as unescapeCellString, n as escapeXmlAttr } from "./escape-rA5UpibT.mjs";
5
- import { _ as ARC_WORKBOOK_RELS, c as ARC_CONTENT_TYPES, f as ARC_ROOT_RELS, ft as SHEET_MAIN_NS, g as ARC_WORKBOOK, lt as REL_NS, m as ARC_STYLE, p as ARC_SHARED_STRINGS, pt as STYLES_TYPE, ut as SHARED_STRINGS_TYPE, wt as XLSX_TYPE, yt as WORKSHEET_TYPE } from "./tree-BX-sRRVp.mjs";
6
- import { t as stylesheetToBytes, v as serializeCell, x as parseCellNumber } from "./stylesheet-writer-BBYjNSMA.mjs";
7
- import { t as parseXml } from "./parser-By6RWZVW.mjs";
8
- import { r as parseXsdBoolean } from "./serialize-Dmb6Vtt9.mjs";
9
- import { $ as findByType, Q as findById, a as makeManifest, n as addOverride, nt as relsFromBytes, o as manifestFromBytes, rt as relsToBytes, s as manifestToBytes, t as addDefault, tt as makeRelationships } from "./manifest-BHUYpjUG.mjs";
10
- import { ct as buildXfPatch, ht as makeStylesheet, it as addCellXf, lt as defaultCellXf } from "./cell-style-DjKKPWDL.mjs";
11
- import { A as serializeRichString, D as makeSharedStrings, S as validateSheetTitle, k as parseSharedStringsXml } from "./workbook-CMel6UcI.mjs";
12
- import { a as parseDate1904, c as resolveRelTarget, l as parseStylesheetXml, n as SHARED_STRINGS_PART, o as parseSheetEntries, r as STYLES_PART, s as readOptionalWorkbookPart, t as OFFICE_DOC_REL_TYPE } from "./load-DIdQ_zum.mjs";
5
+ import { Tt as XLSX_TYPE, _ as ARC_WORKBOOK_RELS, bt as WORKSHEET_TYPE, c as ARC_CONTENT_TYPES, f as ARC_ROOT_RELS, ft as SHEET_MAIN_NS, g as ARC_WORKBOOK, jt as localNameOf, lt as REL_NS, m as ARC_STYLE, mt as STYLES_TYPE, p as ARC_SHARED_STRINGS, ut as SHARED_STRINGS_TYPE } from "./tree-CspNjuYl.mjs";
6
+ import { t as stylesheetToBytes, v as serializeCell, x as parseCellNumber } from "./stylesheet-writer-BEn-0P0x.mjs";
7
+ import { n as parseXml } from "./parser-B1tB9YaE.mjs";
8
+ import { r as parseXsdBoolean } from "./serialize-BtxgssFK.mjs";
9
+ import { $ as findByType, Q as findById, a as makeManifest, n as addOverride, nt as relsFromBytes, o as manifestFromBytes, rt as relsToBytes, s as manifestToBytes, t as addDefault, tt as makeRelationships } from "./manifest-9p0ccqmR.mjs";
10
+ import { A as parseSharedStringsXml, C as validateSheetTitle, F as assertNotStrictRoot, O as makeSharedStrings, P as assertNotStrictRelTypes, j as serializeRichString } from "./workbook-tG9oYtzU.mjs";
11
+ import { ct as buildXfPatch, ht as makeStylesheet, it as addCellXf, lt as defaultCellXf } from "./cell-style-CbB4nXTY.mjs";
12
+ import { c as readOptionalWorkbookPart, i as WORKBOOK_TAG, l as resolveRelTarget, n as SHARED_STRINGS_PART, o as parseDate1904, r as STYLES_PART, s as parseSheetEntries, t as OFFICE_DOC_REL_TYPE, u as parseStylesheetXml } from "./load-BpnCPv1S.mjs";
13
13
  import { t as openZip } from "./reader-pC7bxYAs.mjs";
14
14
  import { t as utf8ByteLength } from "./utf8-OAkCDG5g.mjs";
15
15
  import { t as createZipWriter } from "./writer-C38RBZCy.mjs";
16
- import { t as iterParse } from "./iterparse-DZE0zy2M.mjs";
16
+ import { t as iterParse } from "./iterparse-CZoRXvZW.mjs";
17
17
  //#region src/streaming/read-only.ts
18
18
  const relsPathFor = (partPath) => {
19
19
  const i = partPath.lastIndexOf("/");
20
20
  if (i < 0) return `_rels/${partPath}.rels`;
21
21
  return `${partPath.slice(0, i)}/_rels/${partPath.slice(i + 1)}.rels`;
22
22
  };
23
- const localName = (qname) => {
24
- const i = qname.lastIndexOf("}");
25
- return i < 0 ? qname : qname.slice(i + 1);
26
- };
27
23
  const decodeCellValue = (t, vText, inlineText, sst, sheet, col, row) => {
28
24
  switch (t) {
29
25
  case "n": return parseCellNumber(vText, sheet, col, row);
@@ -49,6 +45,14 @@ const decodeCellValue = (t, vText, inlineText, sst, sheet, col, row) => {
49
45
  * SAX-iterate `<sheetData>/<row>/<c>` events out of the worksheet bytes (or a
50
46
  * stream that yields them), yielding one `ReadOnlyCell[]` per row that matches
51
47
  * `opts`.
48
+ *
49
+ * `readSheetData` in `../worksheet/reader.ts` walks the same element shapes for
50
+ * `loadWorkbook`. The two stay separate because this one is an async generator
51
+ * over a stream with a row band and an early exit, and that per-event cost is
52
+ * what the other one exists to avoid. Where a row or cell with no `@r` lands
53
+ * has to come out the same in both, and is asserted to: see "agrees with
54
+ * loadWorkbook on where every cell lands" in
55
+ * `tests/worksheet/row-without-r-attribute.test.ts`.
52
56
  */
53
57
  async function* iterSheetRows(title, sheetInput, sst, opts) {
54
58
  const minRow = opts.minRow ?? 1;
@@ -83,10 +87,15 @@ async function* iterSheetRows(title, sheetInput, sst, opts) {
83
87
  let inIsT = false;
84
88
  let isText = "";
85
89
  let isRunText = "";
90
+ let checkedRoot = false;
86
91
  for await (const ev of iterParse(sheetInput)) {
87
92
  const e = ev;
88
93
  if (e.kind === "start") {
89
- const local = localName(e.name);
94
+ if (!checkedRoot) {
95
+ assertNotStrictRoot(e.name);
96
+ checkedRoot = true;
97
+ }
98
+ const local = localNameOf(e.name);
90
99
  if (!inSheetData) {
91
100
  if (local === "sheetData") inSheetData = true;
92
101
  continue;
@@ -147,7 +156,7 @@ async function* iterSheetRows(title, sheetInput, sst, opts) {
147
156
  else if (inIsT) isRunText += e.text;
148
157
  continue;
149
158
  }
150
- const local = localName(e.name);
159
+ const local = localNameOf(e.name);
151
160
  if (!inSheetData) continue;
152
161
  switch (local) {
153
162
  case "sheetData":
@@ -456,11 +465,19 @@ async function loadWorkbookStream(source, opts = {}) {
456
465
  if (!archive.has("[Content_Types].xml")) throw new OpenXmlSchemaError(`loadWorkbookStream: missing "${ARC_CONTENT_TYPES}"`);
457
466
  manifestFromBytes(archive.read(ARC_CONTENT_TYPES));
458
467
  if (!archive.has(ARC_ROOT_RELS)) throw new OpenXmlSchemaError(`loadWorkbookStream: missing "${ARC_ROOT_RELS}"`);
459
- const officeDocRel = findByType(relsFromBytes(archive.read(ARC_ROOT_RELS)), OFFICE_DOC_REL_TYPE);
460
- if (!officeDocRel) throw new OpenXmlSchemaError(`loadWorkbookStream: no officeDocument relationship in root rels`);
468
+ const rootRels = relsFromBytes(archive.read(ARC_ROOT_RELS));
469
+ const officeDocRel = findByType(rootRels, OFFICE_DOC_REL_TYPE);
470
+ if (!officeDocRel) {
471
+ assertNotStrictRelTypes(rootRels.rels.map((r) => r.type));
472
+ throw new OpenXmlSchemaError(`loadWorkbookStream: no officeDocument relationship in root rels`);
473
+ }
461
474
  const workbookPath = resolveRelTarget("", officeDocRel.target);
462
475
  if (!archive.has(workbookPath)) throw new OpenXmlSchemaError(`loadWorkbookStream: workbook part "${workbookPath}" missing`);
463
476
  const workbookRoot = parseXml(archive.read(workbookPath));
477
+ if (workbookRoot.name !== WORKBOOK_TAG) {
478
+ assertNotStrictRoot(workbookRoot.name);
479
+ throw new OpenXmlSchemaError(`loadWorkbookStream: ${workbookPath} root is "${workbookRoot.name}", expected workbook`);
480
+ }
464
481
  const declaredSheets = parseSheetEntries(workbookRoot);
465
482
  const wbRelsPath = relsPathFor(workbookPath);
466
483
  if (declaredSheets.length > 0 && !archive.has(wbRelsPath)) throw new OpenXmlSchemaError(`loadWorkbookStream: workbook has sheets but rels part "${wbRelsPath}" is missing`);