@office-kit/xlsx 0.11.0 → 0.11.1

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 (155) hide show
  1. package/README.md +7 -0
  2. package/dist/cell/cell.d.ts +1 -1
  3. package/dist/cell/index.d.ts +4 -4
  4. package/dist/cell/rich-text.d.ts +1 -1
  5. package/dist/cell-BucgGwl3.mjs.map +1 -1
  6. package/dist/cell-style-DuvS_Lsg.mjs.map +1 -1
  7. package/dist/chart/chart-xml.d.ts +1 -1
  8. package/dist/chart/chart.d.ts +3 -3
  9. package/dist/chart/cx/chartex-xml.d.ts +1 -1
  10. package/dist/chart/cx/chartex.d.ts +2 -2
  11. package/dist/chart/index.d.ts +6 -6
  12. package/dist/chart/user-shapes-xml.d.ts +1 -1
  13. package/dist/chart/user-shapes.d.ts +2 -2
  14. package/dist/chart.mjs.map +1 -1
  15. package/dist/chartsheet/chartsheet-xml.d.ts +1 -1
  16. package/dist/chartsheet/chartsheet.d.ts +4 -4
  17. package/dist/chartsheet/index.d.ts +2 -2
  18. package/dist/chartsheet-C3-tqkPy.mjs.map +1 -1
  19. package/dist/coordinate-96Ecci4d.mjs.map +1 -1
  20. package/dist/datetime-B2ySVlXt.mjs.map +1 -1
  21. package/dist/defined-names-CviWmtQg.mjs.map +1 -1
  22. package/dist/differential-DvKU8fJt.mjs.map +1 -1
  23. package/dist/drawing/dml/dml-xml.d.ts +8 -8
  24. package/dist/drawing/dml/effect.d.ts +2 -2
  25. package/dist/drawing/dml/fill.d.ts +1 -1
  26. package/dist/drawing/dml/geometry.d.ts +1 -1
  27. package/dist/drawing/dml/line.d.ts +1 -1
  28. package/dist/drawing/dml/shape-properties.d.ts +5 -5
  29. package/dist/drawing/dml/text.d.ts +4 -4
  30. package/dist/drawing/drawing-xml.d.ts +1 -1
  31. package/dist/drawing/drawing.d.ts +9 -9
  32. package/dist/drawing/index.d.ts +14 -14
  33. package/dist/drawing-BxzLuryn.mjs.map +1 -1
  34. package/dist/drawing.mjs.map +1 -1
  35. package/dist/{escape-DFTE7ZJc.mjs → escape-rnWSPpWY.mjs} +4 -6
  36. package/dist/{escape-DFTE7ZJc.mjs.map → escape-rnWSPpWY.mjs.map} +1 -1
  37. package/dist/formula/tokenizer.d.ts +1 -1
  38. package/dist/formula/translate.d.ts +2 -2
  39. package/dist/io/browser.d.ts +2 -2
  40. package/dist/io/index.d.ts +7 -7
  41. package/dist/io/load.d.ts +4 -4
  42. package/dist/io/node-fs.d.ts +2 -2
  43. package/dist/io/node-save.d.ts +2 -2
  44. package/dist/io/node.d.ts +2 -2
  45. package/dist/io/save.d.ts +2 -2
  46. package/dist/io.mjs +2 -2
  47. package/dist/io.mjs.map +1 -1
  48. package/dist/{load-MyOIjtrU.mjs → load-Bghb1YHY.mjs} +5 -5
  49. package/dist/load-Bghb1YHY.mjs.map +1 -0
  50. package/dist/{manifest-Cm9K7D62.mjs → manifest-pLmx7KYh.mjs} +3 -3
  51. package/dist/manifest-pLmx7KYh.mjs.map +1 -0
  52. package/dist/node.d.ts +3 -3
  53. package/dist/node.mjs +1 -1
  54. package/dist/node.mjs.map +1 -1
  55. package/dist/packaging/core.d.ts +1 -1
  56. package/dist/packaging/custom.d.ts +2 -2
  57. package/dist/packaging/extended.d.ts +2 -2
  58. package/dist/packaging/index.d.ts +10 -10
  59. package/dist/packaging.mjs +1 -1
  60. package/dist/{parser-D3SLaOFe.mjs → parser-By6RWZVW.mjs} +39 -10
  61. package/dist/parser-By6RWZVW.mjs.map +1 -0
  62. package/dist/reader-BNaUTVCy.mjs.map +1 -1
  63. package/dist/{save-2moCT3Af.mjs → save-Bqcf8w3g.mjs} +6 -6
  64. package/dist/save-Bqcf8w3g.mjs.map +1 -0
  65. package/dist/schema/core.d.ts +1 -1
  66. package/dist/schema/index.d.ts +3 -3
  67. package/dist/schema/serialize.d.ts +2 -2
  68. package/dist/serialize-BC2Wu3bR.mjs.map +1 -1
  69. package/dist/{serializer-BtO2TrI7.mjs → serializer-C6nm0mRJ.mjs} +2 -2
  70. package/dist/serializer-C6nm0mRJ.mjs.map +1 -0
  71. package/dist/streaming/index.d.ts +2 -2
  72. package/dist/streaming/read-only.d.ts +4 -4
  73. package/dist/streaming/write-only.d.ts +7 -7
  74. package/dist/streaming.mjs +6 -6
  75. package/dist/streaming.mjs.map +1 -1
  76. package/dist/styles/alignment.schema.d.ts +2 -2
  77. package/dist/styles/borders.d.ts +1 -1
  78. package/dist/styles/borders.schema.d.ts +2 -2
  79. package/dist/styles/cell-style.d.ts +9 -9
  80. package/dist/styles/colors.schema.d.ts +2 -2
  81. package/dist/styles/differential.d.ts +7 -7
  82. package/dist/styles/fills.d.ts +1 -1
  83. package/dist/styles/fills.schema.d.ts +2 -2
  84. package/dist/styles/fonts.d.ts +1 -1
  85. package/dist/styles/fonts.schema.d.ts +2 -2
  86. package/dist/styles/index.d.ts +21 -21
  87. package/dist/styles/named-styles.d.ts +6 -6
  88. package/dist/styles/numbers.schema.d.ts +2 -2
  89. package/dist/styles/protection.schema.d.ts +2 -2
  90. package/dist/styles/stylesheet-reader.d.ts +1 -1
  91. package/dist/styles/stylesheet-writer.d.ts +1 -1
  92. package/dist/styles/stylesheet.d.ts +8 -8
  93. package/dist/{stylesheet-writer-BrOw4jMY.mjs → stylesheet-writer-HxaX7bGy.mjs} +6 -6
  94. package/dist/stylesheet-writer-HxaX7bGy.mjs.map +1 -0
  95. package/dist/table-1P8we2gS.mjs.map +1 -1
  96. package/dist/tree-BX-sRRVp.mjs.map +1 -1
  97. package/dist/user-shapes-DfmCGKB0.mjs.map +1 -1
  98. package/dist/utf8-Tn3nzyik.mjs.map +1 -1
  99. package/dist/utils/escape.d.ts +3 -5
  100. package/dist/utils/index.d.ts +11 -11
  101. package/dist/utils.mjs +1 -1
  102. package/dist/workbook/calc-properties.d.ts +1 -1
  103. package/dist/workbook/defined-names.d.ts +3 -3
  104. package/dist/workbook/index.d.ts +24 -24
  105. package/dist/workbook/protection.d.ts +1 -1
  106. package/dist/workbook/shared-strings.d.ts +2 -2
  107. package/dist/workbook/views.d.ts +1 -1
  108. package/dist/workbook/workbook-properties.d.ts +1 -1
  109. package/dist/workbook/workbook.d.ts +46 -46
  110. package/dist/{workbook-CARZS94U.mjs → workbook-BlZVXiyG.mjs} +3 -3
  111. package/dist/workbook-BlZVXiyG.mjs.map +1 -0
  112. package/dist/workbook.mjs +1 -1
  113. package/dist/workbook.mjs.map +1 -1
  114. package/dist/worksheet/auto-filter.d.ts +1 -1
  115. package/dist/worksheet/cell-range.d.ts +2 -2
  116. package/dist/worksheet/comments-xml.d.ts +1 -1
  117. package/dist/worksheet/conditional-formatting.d.ts +2 -2
  118. package/dist/worksheet/custom-sheet-views.d.ts +2 -2
  119. package/dist/worksheet/data-validations.d.ts +2 -2
  120. package/dist/worksheet/errors.d.ts +1 -1
  121. package/dist/worksheet/hyperlinks.d.ts +1 -1
  122. package/dist/worksheet/index.d.ts +46 -46
  123. package/dist/worksheet/ole-objects.d.ts +1 -1
  124. package/dist/worksheet/page-setup.d.ts +1 -1
  125. package/dist/worksheet/properties.d.ts +1 -1
  126. package/dist/worksheet/protected-ranges.d.ts +1 -1
  127. package/dist/worksheet/protection.d.ts +1 -1
  128. package/dist/worksheet/reader.d.ts +9 -9
  129. package/dist/worksheet/scenarios.d.ts +1 -1
  130. package/dist/worksheet/table-xml.d.ts +1 -1
  131. package/dist/worksheet/table.d.ts +3 -3
  132. package/dist/worksheet/worksheet.d.ts +31 -31
  133. package/dist/worksheet/writer.d.ts +9 -9
  134. package/dist/worksheet-C5Ensf_j.mjs.map +1 -1
  135. package/dist/worksheet.mjs.map +1 -1
  136. package/dist/writer-IyFccCRJ.mjs.map +1 -1
  137. package/dist/xml/index.d.ts +10 -10
  138. package/dist/xml/parser.d.ts +1 -1
  139. package/dist/xml/serializer.d.ts +1 -1
  140. package/dist/xml/stream-writer.d.ts +1 -1
  141. package/dist/xml.mjs +3 -3
  142. package/dist/xml.mjs.map +1 -1
  143. package/dist/zip/decompression-guard.d.ts +1 -1
  144. package/dist/zip/index.d.ts +6 -6
  145. package/dist/zip/random-access-reader.d.ts +2 -2
  146. package/dist/zip/reader.d.ts +2 -2
  147. package/dist/zip/writer.d.ts +1 -1
  148. package/package.json +4 -1
  149. package/dist/load-MyOIjtrU.mjs.map +0 -1
  150. package/dist/manifest-Cm9K7D62.mjs.map +0 -1
  151. package/dist/parser-D3SLaOFe.mjs.map +0 -1
  152. package/dist/save-2moCT3Af.mjs.map +0 -1
  153. package/dist/serializer-BtO2TrI7.mjs.map +0 -1
  154. package/dist/stylesheet-writer-BrOw4jMY.mjs.map +0 -1
  155. package/dist/workbook-CARZS94U.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"table-1P8we2gS.mjs","names":[],"sources":["../src/worksheet/conditional-formatting.ts","../src/worksheet/data-validations.ts","../src/worksheet/table.ts"],"sourcesContent":["// Conditional formatting.\n//\n// Stage-1 covers the **value-based** rule kinds (cellIs / expression / top10 /\n// aboveAverage / containsText family / containsBlanks family / duplicateValues\n// / uniqueValues / timePeriod). The visual rule kinds — colorScale / dataBar /\n// iconSet — round-trip as opaque inner XML (`innerXml` field) so the data\n// survives a save / load cycle without our needing to model cfvo / colors /\n// iconSets fully.\n\nimport { escapeXmlAttr } from '../utils/escape';\nimport { OpenXmlSchemaError } from '../utils/exceptions';\nimport { type MultiCellRange, parseMultiCellRange } from './cell-range';\n\nexport type ConditionalFormattingRuleType =\n | 'expression'\n | 'cellIs'\n | 'colorScale'\n | 'dataBar'\n | 'iconSet'\n | 'top10'\n | 'aboveAverage'\n | 'uniqueValues'\n | 'duplicateValues'\n | 'containsText'\n | 'notContainsText'\n | 'beginsWith'\n | 'endsWith'\n | 'containsBlanks'\n | 'notContainsBlanks'\n | 'containsErrors'\n | 'notContainsErrors'\n | 'timePeriod';\n\nexport type CellIsOperator =\n | 'lessThan'\n | 'lessThanOrEqual'\n | 'equal'\n | 'notEqual'\n | 'greaterThanOrEqual'\n | 'greaterThan'\n | 'between'\n | 'notBetween';\n\nexport type TextOperator = 'containsText' | 'notContains' | 'beginsWith' | 'endsWith';\n\nexport type TimePeriod =\n | 'today'\n | 'yesterday'\n | 'tomorrow'\n | 'last7Days'\n | 'thisMonth'\n | 'lastMonth'\n | 'nextMonth'\n | 'thisWeek'\n | 'lastWeek'\n | 'nextWeek';\n\nexport interface ConditionalFormattingRule {\n /** Wire-level rule kind. */\n type: ConditionalFormattingRuleType;\n /** 1-based priority — Excel evaluates lower priority first. */\n priority: number;\n /** Index into Stylesheet.dxfs for the cell-format applied when the rule fires. */\n dxfId?: number;\n /** Stop evaluating subsequent rules on the same cell when this rule matches. */\n stopIfTrue?: boolean;\n /** cellIs operator. */\n operator?: CellIsOperator | TextOperator | string;\n /** Comparison string for the contains-text family. */\n text?: string;\n /** top10: rank percentage flag. */\n percent?: boolean;\n /** top10: bottom-N flag (false = top-N, true = bottom-N). */\n bottom?: boolean;\n /** top10: rank value (defaults to 10). */\n rank?: number;\n /** aboveAverage: aboveAverage=\"0\" → below average. */\n aboveAverage?: boolean;\n /** aboveAverage: equalAverage flag. */\n equalAverage?: boolean;\n /** aboveAverage: stdDev. */\n stdDev?: number;\n /** timePeriod token. */\n timePeriod?: TimePeriod;\n /** 0..3 formula strings — varies by rule type. */\n formulas: string[];\n /**\n * Raw inner XML for colorScale / dataBar / iconSet rules. Stage-1 stores the\n * verbatim child markup so saves round-trip without our needing to model cfvo\n * / colors / iconSets fully.\n */\n innerXml?: string;\n}\n\nexport interface ConditionalFormatting {\n sqref: MultiCellRange;\n rules: ConditionalFormattingRule[];\n pivot?: boolean;\n}\n\nexport function makeConditionalFormatting(opts: {\n sqref: MultiCellRange | string;\n rules?: ConditionalFormattingRule[];\n pivot?: boolean;\n}): ConditionalFormatting {\n return {\n sqref: typeof opts.sqref === 'string' ? parseMultiCellRange(opts.sqref) : opts.sqref,\n rules: opts.rules ?? [],\n ...(opts.pivot !== undefined ? { pivot: opts.pivot } : {}),\n };\n}\n\nexport function makeCfRule(\n opts: Partial<ConditionalFormattingRule> & {\n type: ConditionalFormattingRuleType;\n priority: number;\n },\n): ConditionalFormattingRule {\n return {\n type: opts.type,\n priority: opts.priority,\n formulas: opts.formulas ?? [],\n ...(opts.dxfId !== undefined ? { dxfId: opts.dxfId } : {}),\n ...(opts.stopIfTrue !== undefined ? { stopIfTrue: opts.stopIfTrue } : {}),\n ...(opts.operator !== undefined ? { operator: opts.operator } : {}),\n ...(opts.text !== undefined ? { text: opts.text } : {}),\n ...(opts.percent !== undefined ? { percent: opts.percent } : {}),\n ...(opts.bottom !== undefined ? { bottom: opts.bottom } : {}),\n ...(opts.rank !== undefined ? { rank: opts.rank } : {}),\n ...(opts.aboveAverage !== undefined ? { aboveAverage: opts.aboveAverage } : {}),\n ...(opts.equalAverage !== undefined ? { equalAverage: opts.equalAverage } : {}),\n ...(opts.stdDev !== undefined ? { stdDev: opts.stdDev } : {}),\n ...(opts.timePeriod !== undefined ? { timePeriod: opts.timePeriod } : {}),\n ...(opts.innerXml !== undefined ? { innerXml: opts.innerXml } : {}),\n };\n}\n\n// ---- Worksheet ergonomic builders ---------------------------------------\n\nimport type { Worksheet } from './worksheet';\n\nconst resolveCfSqref = (sqref: MultiCellRange | string): MultiCellRange =>\n typeof sqref === 'string' ? parseMultiCellRange(sqref) : sqref;\n\nconst nextCfPriority = (ws: Worksheet): number => {\n let max = 0;\n for (const cf of ws.conditionalFormatting) {\n for (const r of cf.rules) {\n if (r.priority > max) max = r.priority;\n }\n }\n return max + 1;\n};\n\n/** Push one CF rule onto the worksheet, wrapping it in a ConditionalFormatting block keyed off `sqref`. */\nconst pushRule = (\n ws: Worksheet,\n sqref: MultiCellRange | string,\n rule: ConditionalFormattingRule,\n): ConditionalFormattingRule => {\n ws.conditionalFormatting.push(makeConditionalFormatting({ sqref: resolveCfSqref(sqref), rules: [rule] }));\n return rule;\n};\n\n/**\n * \"If cell value [op] formula → apply dxf\". Mirrors Excel's \"Highlight Cell\n * Rules → ...\" UI.\n */\nexport const addCellIsRule = (\n ws: Worksheet,\n sqref: MultiCellRange | string,\n opts: {\n operator: CellIsOperator;\n formula1: string;\n formula2?: string;\n dxfId?: number;\n stopIfTrue?: boolean;\n priority?: number;\n },\n): ConditionalFormattingRule => {\n const formulas = opts.formula2 !== undefined ? [opts.formula1, opts.formula2] : [opts.formula1];\n return pushRule(\n ws,\n sqref,\n makeCfRule({\n type: 'cellIs',\n priority: opts.priority ?? nextCfPriority(ws),\n operator: opts.operator,\n formulas,\n ...(opts.dxfId !== undefined ? { dxfId: opts.dxfId } : {}),\n ...(opts.stopIfTrue !== undefined ? { stopIfTrue: opts.stopIfTrue } : {}),\n }),\n );\n};\n\n/** Top-N or bottom-N rule. `bottom: true` → bottom-N. `percent: true` → percentile. */\nexport const addTopNRule = (\n ws: Worksheet,\n sqref: MultiCellRange | string,\n opts: { rank?: number; bottom?: boolean; percent?: boolean; dxfId?: number; priority?: number },\n): ConditionalFormattingRule => {\n return pushRule(\n ws,\n sqref,\n makeCfRule({\n type: 'top10',\n priority: opts.priority ?? nextCfPriority(ws),\n formulas: [],\n ...(opts.rank !== undefined ? { rank: opts.rank } : {}),\n ...(opts.bottom !== undefined ? { bottom: opts.bottom } : {}),\n ...(opts.percent !== undefined ? { percent: opts.percent } : {}),\n ...(opts.dxfId !== undefined ? { dxfId: opts.dxfId } : {}),\n }),\n );\n};\n\n/** Above/below-average rule. `aboveAverage: false` → below-average; provide `stdDev` for ±N stddev. */\nexport const addAverageRule = (\n ws: Worksheet,\n sqref: MultiCellRange | string,\n opts: {\n aboveAverage?: boolean;\n equalAverage?: boolean;\n stdDev?: number;\n dxfId?: number;\n priority?: number;\n },\n): ConditionalFormattingRule => {\n return pushRule(\n ws,\n sqref,\n makeCfRule({\n type: 'aboveAverage',\n priority: opts.priority ?? nextCfPriority(ws),\n formulas: [],\n ...(opts.aboveAverage !== undefined ? { aboveAverage: opts.aboveAverage } : {}),\n ...(opts.equalAverage !== undefined ? { equalAverage: opts.equalAverage } : {}),\n ...(opts.stdDev !== undefined ? { stdDev: opts.stdDev } : {}),\n ...(opts.dxfId !== undefined ? { dxfId: opts.dxfId } : {}),\n }),\n );\n};\n\n/** Duplicate-values rule (each cell whose value appears more than once gets the dxf). */\nexport const addDuplicateValuesRule = (\n ws: Worksheet,\n sqref: MultiCellRange | string,\n opts: { dxfId?: number; priority?: number; unique?: boolean } = {},\n): ConditionalFormattingRule => {\n return pushRule(\n ws,\n sqref,\n makeCfRule({\n type: opts.unique ? 'uniqueValues' : 'duplicateValues',\n priority: opts.priority ?? nextCfPriority(ws),\n formulas: [],\n ...(opts.dxfId !== undefined ? { dxfId: opts.dxfId } : {}),\n }),\n );\n};\n\n/** Free-form formula rule — any `=ISNUMBER(A1)`-style boolean expression. */\nexport const addFormulaRule = (\n ws: Worksheet,\n sqref: MultiCellRange | string,\n opts: { formula: string; dxfId?: number; stopIfTrue?: boolean; priority?: number },\n): ConditionalFormattingRule => {\n return pushRule(\n ws,\n sqref,\n makeCfRule({\n type: 'expression',\n priority: opts.priority ?? nextCfPriority(ws),\n formulas: [opts.formula],\n ...(opts.dxfId !== undefined ? { dxfId: opts.dxfId } : {}),\n ...(opts.stopIfTrue !== undefined ? { stopIfTrue: opts.stopIfTrue } : {}),\n }),\n );\n};\n\n/** Text-based rule (containsText / notContains / beginsWith / endsWith). */\nexport const addTextRule = (\n ws: Worksheet,\n sqref: MultiCellRange | string,\n opts: { operator: TextOperator; text: string; dxfId?: number; priority?: number },\n): ConditionalFormattingRule => {\n // Excel uses different `type` tokens for the four text operators.\n const typeMap: Record<TextOperator, ConditionalFormattingRuleType> = {\n containsText: 'containsText',\n notContains: 'notContainsText',\n beginsWith: 'beginsWith',\n endsWith: 'endsWith',\n };\n return pushRule(\n ws,\n sqref,\n makeCfRule({\n type: typeMap[opts.operator],\n priority: opts.priority ?? nextCfPriority(ws),\n operator: opts.operator,\n text: opts.text,\n formulas: [],\n ...(opts.dxfId !== undefined ? { dxfId: opts.dxfId } : {}),\n }),\n );\n};\n\n// ---- Visual rule builders (colorScale / dataBar / iconSet) --------------\n\nexport type CfvoType = 'min' | 'max' | 'num' | 'percent' | 'percentile' | 'formula';\n\nexport interface Cfvo {\n type: CfvoType;\n /** Required for num / percent / percentile / formula; ignored for min / max. */\n val?: string;\n}\n\nexport type IconSetStyle =\n | '3Arrows'\n | '3ArrowsGray'\n | '3Flags'\n | '3Signs'\n | '3Symbols'\n | '3Symbols2'\n | '3TrafficLights1'\n | '3TrafficLights2'\n | '4Arrows'\n | '4ArrowsGray'\n | '4Rating'\n | '4RedToBlack'\n | '4TrafficLights'\n | '5Arrows'\n | '5ArrowsGray'\n | '5Quarters'\n | '5Rating';\n\nconst escapeAttr = escapeXmlAttr;\n\nconst renderCfvo = (c: Cfvo): string => {\n if (c.type === 'min' || c.type === 'max') {\n if (c.val === undefined) return `<cfvo type=\"${c.type}\"/>`;\n return `<cfvo type=\"${c.type}\" val=\"${escapeAttr(c.val)}\"/>`;\n }\n if (c.val === undefined) {\n throw new OpenXmlSchemaError(`cfvo type \"${c.type}\" requires val`);\n }\n return `<cfvo type=\"${c.type}\" val=\"${escapeAttr(c.val)}\"/>`;\n};\n\nconst renderColor = (hex: string): string => `<color rgb=\"${escapeAttr(hex)}\"/>`;\n\n/**\n * Color-scale rule — gradient between 2 or 3 reference points. Each cfvo pairs\n * with one color.\n */\nexport const addColorScaleRule = (\n ws: Worksheet,\n sqref: MultiCellRange | string,\n opts: {\n cfvos: ReadonlyArray<Cfvo>;\n /** Hex strings, e.g. `'FFFF0000'`; one per cfvo. */\n colors: ReadonlyArray<string>;\n priority?: number;\n stopIfTrue?: boolean;\n },\n): ConditionalFormattingRule => {\n if (opts.cfvos.length !== 2 && opts.cfvos.length !== 3) {\n throw new OpenXmlSchemaError(`addColorScaleRule: cfvos must be length 2 or 3; got ${opts.cfvos.length}`);\n }\n if (opts.colors.length !== opts.cfvos.length) {\n throw new OpenXmlSchemaError(\n `addColorScaleRule: colors length (${opts.colors.length}) must match cfvos length (${opts.cfvos.length})`,\n );\n }\n const inner = `<colorScale>${opts.cfvos.map(renderCfvo).join('')}${opts.colors.map(renderColor).join('')}</colorScale>`;\n return pushRule(\n ws,\n sqref,\n makeCfRule({\n type: 'colorScale',\n priority: opts.priority ?? nextCfPriority(ws),\n formulas: [],\n innerXml: inner,\n ...(opts.stopIfTrue !== undefined ? { stopIfTrue: opts.stopIfTrue } : {}),\n }),\n );\n};\n\n/**\n * Data-bar rule — a gradient bar inside each cell sized to the value. Defaults\n * to `min`/`max` cfvos so the bar spans the visible range.\n */\nexport const addDataBarRule = (\n ws: Worksheet,\n sqref: MultiCellRange | string,\n opts: {\n color: string;\n minCfvo?: Cfvo;\n maxCfvo?: Cfvo;\n minLength?: number;\n maxLength?: number;\n showValue?: boolean;\n priority?: number;\n stopIfTrue?: boolean;\n },\n): ConditionalFormattingRule => {\n const min = opts.minCfvo ?? { type: 'min' };\n const max = opts.maxCfvo ?? { type: 'max' };\n let attrs = '';\n if (opts.minLength !== undefined) attrs += ` minLength=\"${opts.minLength}\"`;\n if (opts.maxLength !== undefined) attrs += ` maxLength=\"${opts.maxLength}\"`;\n if (opts.showValue !== undefined) attrs += ` showValue=\"${opts.showValue ? '1' : '0'}\"`;\n const inner = `<dataBar${attrs}>${renderCfvo(min)}${renderCfvo(max)}${renderColor(opts.color)}</dataBar>`;\n return pushRule(\n ws,\n sqref,\n makeCfRule({\n type: 'dataBar',\n priority: opts.priority ?? nextCfPriority(ws),\n formulas: [],\n innerXml: inner,\n ...(opts.stopIfTrue !== undefined ? { stopIfTrue: opts.stopIfTrue } : {}),\n }),\n );\n};\n\n/**\n * Icon-set rule — visual icons (arrows / lights / flags) drawn next to each\n * cell value. The number of cfvos depends on the icon set (3 for `3Arrows`, 4\n * for `4Arrows`, 5 for `5Arrows`, etc).\n */\nexport const addIconSetRule = (\n ws: Worksheet,\n sqref: MultiCellRange | string,\n opts: {\n iconSet: IconSetStyle | string;\n cfvos: ReadonlyArray<Cfvo>;\n reverse?: boolean;\n showValue?: boolean;\n percent?: boolean;\n priority?: number;\n stopIfTrue?: boolean;\n },\n): ConditionalFormattingRule => {\n if (opts.cfvos.length < 3 || opts.cfvos.length > 5) {\n throw new OpenXmlSchemaError(`addIconSetRule: cfvos must be length 3..5; got ${opts.cfvos.length}`);\n }\n let attrs = ` iconSet=\"${escapeAttr(opts.iconSet)}\"`;\n if (opts.reverse !== undefined) attrs += ` reverse=\"${opts.reverse ? '1' : '0'}\"`;\n if (opts.showValue !== undefined) attrs += ` showValue=\"${opts.showValue ? '1' : '0'}\"`;\n if (opts.percent !== undefined) attrs += ` percent=\"${opts.percent ? '1' : '0'}\"`;\n const inner = `<iconSet${attrs}>${opts.cfvos.map(renderCfvo).join('')}</iconSet>`;\n return pushRule(\n ws,\n sqref,\n makeCfRule({\n type: 'iconSet',\n priority: opts.priority ?? nextCfPriority(ws),\n formulas: [],\n innerXml: inner,\n ...(opts.stopIfTrue !== undefined ? { stopIfTrue: opts.stopIfTrue } : {}),\n }),\n );\n};\n","// Data validations.\n//\n// A DataValidation entry attaches a constraint (one of seven type kinds,\n// optional operator, two formula slots) to a sqref-style MultiCellRange.\n// Stage-1 maps every OOXML attribute we have a use for; imeMode + numeric/value\n// clamps land later when phase 7's Asian-locale support catches up.\n\nimport { type MultiCellRange, parseMultiCellRange } from './cell-range';\n\nexport type DataValidationType = 'whole' | 'decimal' | 'list' | 'date' | 'time' | 'textLength' | 'custom';\nexport type DataValidationOperator =\n | 'between'\n | 'notBetween'\n | 'equal'\n | 'notEqual'\n | 'greaterThan'\n | 'greaterThanOrEqual'\n | 'lessThan'\n | 'lessThanOrEqual';\nexport type DataValidationErrorStyle = 'stop' | 'warning' | 'information';\n\nexport interface DataValidation {\n /** Constraint kind. `'list'` is the dropdown form (formula1 = comma list or range). */\n type: DataValidationType;\n /** Comparison operator — only meaningful for whole/decimal/date/time/textLength. */\n operator?: DataValidationOperator;\n /** Lower-bound formula or list source. Always required for list/whole/decimal/date/time. */\n formula1?: string;\n /** Upper-bound formula. Used by between / notBetween only. */\n formula2?: string;\n /** Allow empty cells. */\n allowBlank?: boolean;\n /** Show the input message popover when the cell is selected. */\n showInputMessage?: boolean;\n /** Show the error message popover on invalid entry. */\n showErrorMessage?: boolean;\n errorTitle?: string;\n error?: string;\n errorStyle?: DataValidationErrorStyle;\n promptTitle?: string;\n prompt?: string;\n /** Excel inverts this attribute: `showDropDown=\"1\"` actually *hides* the dropdown arrow on list-type validators. We mirror the wire form. */\n showDropDown?: boolean;\n /** Apply-to range (sqref). */\n sqref: MultiCellRange;\n}\n\nexport function makeDataValidation(\n opts: Omit<Partial<DataValidation>, 'sqref'> & {\n type: DataValidationType;\n sqref: MultiCellRange | string;\n },\n): DataValidation {\n return {\n type: opts.type,\n sqref: typeof opts.sqref === 'string' ? parseMultiCellRange(opts.sqref) : opts.sqref,\n ...(opts.operator !== undefined ? { operator: opts.operator } : {}),\n ...(opts.formula1 !== undefined ? { formula1: opts.formula1 } : {}),\n ...(opts.formula2 !== undefined ? { formula2: opts.formula2 } : {}),\n ...(opts.allowBlank !== undefined ? { allowBlank: opts.allowBlank } : {}),\n ...(opts.showInputMessage !== undefined ? { showInputMessage: opts.showInputMessage } : {}),\n ...(opts.showErrorMessage !== undefined ? { showErrorMessage: opts.showErrorMessage } : {}),\n ...(opts.errorTitle !== undefined ? { errorTitle: opts.errorTitle } : {}),\n ...(opts.error !== undefined ? { error: opts.error } : {}),\n ...(opts.errorStyle !== undefined ? { errorStyle: opts.errorStyle } : {}),\n ...(opts.promptTitle !== undefined ? { promptTitle: opts.promptTitle } : {}),\n ...(opts.prompt !== undefined ? { prompt: opts.prompt } : {}),\n ...(opts.showDropDown !== undefined ? { showDropDown: opts.showDropDown } : {}),\n };\n}\n\n// ---- Worksheet ergonomic builders ---------------------------------------\n\nimport type { Worksheet } from './worksheet';\n\nconst resolveSqref = (sqref: MultiCellRange | string): MultiCellRange =>\n typeof sqref === 'string' ? parseMultiCellRange(sqref) : sqref;\n\nexport interface ValidationCommon {\n /** Show the dropdown / input prompt when the cell is selected. */\n prompt?: string;\n promptTitle?: string;\n /** Show an error dialog when the user types an invalid value. */\n error?: string;\n errorTitle?: string;\n errorStyle?: DataValidationErrorStyle;\n allowBlank?: boolean;\n}\n\n/**\n * Add a list-type dropdown validation to a range. `values` may be an inline\n * list (`['Red', 'Green', 'Blue']`) or a sheet reference\n * (`'=Sheet1!$A$1:$A$10'`).\n */\nexport const addListValidation = (\n ws: Worksheet,\n sqref: MultiCellRange | string,\n values: ReadonlyArray<string> | string,\n opts: ValidationCommon = {},\n): DataValidation => {\n const formula1 = Array.isArray(values)\n ? `\"${(values as ReadonlyArray<string>).join(',')}\"`\n : (values as string);\n const dv = makeDataValidation({\n type: 'list',\n sqref: resolveSqref(sqref),\n formula1,\n allowBlank: opts.allowBlank ?? true,\n showInputMessage: opts.prompt !== undefined,\n showErrorMessage: opts.error !== undefined || opts.errorStyle !== undefined,\n ...(opts.errorStyle !== undefined ? { errorStyle: opts.errorStyle } : {}),\n ...(opts.error !== undefined ? { error: opts.error } : {}),\n ...(opts.errorTitle !== undefined ? { errorTitle: opts.errorTitle } : {}),\n ...(opts.prompt !== undefined ? { prompt: opts.prompt } : {}),\n ...(opts.promptTitle !== undefined ? { promptTitle: opts.promptTitle } : {}),\n });\n ws.dataValidations.push(dv);\n return dv;\n};\n\n/**\n * Add a number-range validation. `between(min, max)` matches Excel's \"Whole\n * Number\" → \"between\" form by default. Use `kind: 'decimal'` for decimal\n * (default 'whole').\n */\nexport const addNumberValidation = (\n ws: Worksheet,\n sqref: MultiCellRange | string,\n range: { min: number; max?: number; operator?: DataValidationOperator; kind?: 'whole' | 'decimal' },\n opts: ValidationCommon = {},\n): DataValidation => {\n const operator: DataValidationOperator =\n range.operator ?? (range.max !== undefined ? 'between' : 'greaterThanOrEqual');\n const dv = makeDataValidation({\n type: range.kind ?? 'whole',\n sqref: resolveSqref(sqref),\n operator,\n formula1: String(range.min),\n ...(range.max !== undefined ? { formula2: String(range.max) } : {}),\n allowBlank: opts.allowBlank ?? true,\n showInputMessage: opts.prompt !== undefined,\n showErrorMessage: opts.error !== undefined || opts.errorStyle !== undefined,\n ...(opts.errorStyle !== undefined ? { errorStyle: opts.errorStyle } : {}),\n ...(opts.error !== undefined ? { error: opts.error } : {}),\n ...(opts.errorTitle !== undefined ? { errorTitle: opts.errorTitle } : {}),\n ...(opts.prompt !== undefined ? { prompt: opts.prompt } : {}),\n ...(opts.promptTitle !== undefined ? { promptTitle: opts.promptTitle } : {}),\n });\n ws.dataValidations.push(dv);\n return dv;\n};\n\n/**\n * Add a date-range validation. Dates are passed as Excel serial numbers (use\n * `dateToExcel` to convert from JS `Date`).\n */\nexport const addDateValidation = (\n ws: Worksheet,\n sqref: MultiCellRange | string,\n range: { min: number; max?: number; operator?: DataValidationOperator },\n opts: ValidationCommon = {},\n): DataValidation => {\n const operator: DataValidationOperator =\n range.operator ?? (range.max !== undefined ? 'between' : 'greaterThanOrEqual');\n const dv = makeDataValidation({\n type: 'date',\n sqref: resolveSqref(sqref),\n operator,\n formula1: String(range.min),\n ...(range.max !== undefined ? { formula2: String(range.max) } : {}),\n allowBlank: opts.allowBlank ?? true,\n showInputMessage: opts.prompt !== undefined,\n showErrorMessage: opts.error !== undefined || opts.errorStyle !== undefined,\n ...(opts.errorStyle !== undefined ? { errorStyle: opts.errorStyle } : {}),\n ...(opts.error !== undefined ? { error: opts.error } : {}),\n ...(opts.errorTitle !== undefined ? { errorTitle: opts.errorTitle } : {}),\n ...(opts.prompt !== undefined ? { prompt: opts.prompt } : {}),\n ...(opts.promptTitle !== undefined ? { promptTitle: opts.promptTitle } : {}),\n });\n ws.dataValidations.push(dv);\n return dv;\n};\n\n/** Add a custom-formula validation (`formula1` evaluated for each cell). */\nexport const addCustomValidation = (\n ws: Worksheet,\n sqref: MultiCellRange | string,\n formula: string,\n opts: ValidationCommon = {},\n): DataValidation => {\n const dv = makeDataValidation({\n type: 'custom',\n sqref: resolveSqref(sqref),\n formula1: formula,\n allowBlank: opts.allowBlank ?? true,\n showInputMessage: opts.prompt !== undefined,\n showErrorMessage: opts.error !== undefined || opts.errorStyle !== undefined,\n ...(opts.errorStyle !== undefined ? { errorStyle: opts.errorStyle } : {}),\n ...(opts.error !== undefined ? { error: opts.error } : {}),\n ...(opts.errorTitle !== undefined ? { errorTitle: opts.errorTitle } : {}),\n ...(opts.prompt !== undefined ? { prompt: opts.prompt } : {}),\n ...(opts.promptTitle !== undefined ? { promptTitle: opts.promptTitle } : {}),\n });\n ws.dataValidations.push(dv);\n return dv;\n};\n","// Excel Table object (xl/tables/tableN.xml).\n//\n// Tables ride on top of a worksheet range, give it a name + structured column\n// references, and own their own AutoFilter. Each table sits in a separate part\n// — the worksheet only carries a `<tableParts>` block pointing at the\n// workbook-rels rId. Stage-1 covers the table shell + columns + styleInfo +\n// autoFilter; sortState / totals row formulas / calculated column formulas /\n// xml extlst are reserved for later.\n\nimport type { Workbook } from '../workbook/workbook';\nimport type { AutoFilter } from './auto-filter';\nimport type { Worksheet } from './worksheet';\n\nexport interface TableColumn {\n /** 1-based column id (per-table). */\n id: number;\n /** Header name. */\n name: string;\n /** Totals-row aggregation function. */\n totalsRowFunction?: 'sum' | 'min' | 'max' | 'count' | 'countNums' | 'average' | 'stdDev' | 'var' | 'custom';\n /** Override label for the totals row. */\n totalsRowLabel?: string;\n /** Custom totals-row formula text. */\n totalsRowFormula?: string;\n /** Calculated-column formula. */\n calculatedColumnFormula?: string;\n}\n\nexport interface TableStyleInfo {\n /** Built-in style name (TableStyleMedium2, etc) or custom. */\n name?: string;\n showFirstColumn?: boolean;\n showLastColumn?: boolean;\n showRowStripes?: boolean;\n showColumnStripes?: boolean;\n}\n\nexport interface TableDefinition {\n /** Workbook-unique id (`<table id=\"N\">`). */\n id: number;\n /** Workbook-unique displayName — Excel surfaces this in formulas. */\n displayName: string;\n /** Optional friendly name; usually matches `displayName`. */\n name?: string;\n /** Range covered by the table, e.g. \"A1:E10\". */\n ref: string;\n /** Number of header rows. Defaults to 1; 0 means a header-less table. */\n headerRowCount?: number;\n /** Number of totals rows. */\n totalsRowCount?: number;\n /** Whether the totals row is currently visible. */\n totalsRowShown?: boolean;\n styleInfo?: TableStyleInfo;\n columns: TableColumn[];\n autoFilter?: AutoFilter;\n /** Worksheet-rels rId — populated on read; the writer assigns its own. */\n rId?: string;\n}\n\nexport function makeTableColumn(opts: { id: number; name: string }): TableColumn {\n return { id: opts.id, name: opts.name };\n}\n\nexport function makeTableDefinition(opts: {\n id: number;\n displayName: string;\n ref: string;\n name?: string;\n columns?: TableColumn[];\n headerRowCount?: number;\n totalsRowCount?: number;\n totalsRowShown?: boolean;\n styleInfo?: TableStyleInfo;\n autoFilter?: AutoFilter;\n}): TableDefinition {\n return {\n id: opts.id,\n displayName: opts.displayName,\n ref: opts.ref,\n columns: opts.columns ?? [],\n ...(opts.name !== undefined ? { name: opts.name } : {}),\n ...(opts.headerRowCount !== undefined ? { headerRowCount: opts.headerRowCount } : {}),\n ...(opts.totalsRowCount !== undefined ? { totalsRowCount: opts.totalsRowCount } : {}),\n ...(opts.totalsRowShown !== undefined ? { totalsRowShown: opts.totalsRowShown } : {}),\n ...(opts.styleInfo ? { styleInfo: opts.styleInfo } : {}),\n ...(opts.autoFilter ? { autoFilter: opts.autoFilter } : {}),\n };\n}\n\nconst nextTableId = (wb: Workbook): number => {\n let max = 0;\n for (const ref of wb.sheets) {\n if (ref.kind !== 'worksheet') continue;\n for (const t of ref.sheet.tables) {\n if (t.id > max) max = t.id;\n }\n }\n return max + 1;\n};\n\n/**\n * High-level wrapper that builds a TableDefinition + pushes it onto `ws.tables`\n * in one call. Auto-assigns the workbook-unique `id`, derives `displayName`\n * from the supplied `name`, and constructs `TableColumn` records (1-based ids)\n * from a string-array shorthand.\n */\nexport const addExcelTable = (\n wb: Workbook,\n ws: Worksheet,\n opts: {\n name: string;\n ref: string;\n columns: ReadonlyArray<string | TableColumn>;\n style?: string;\n styleInfo?: TableStyleInfo;\n headerRowCount?: number;\n totalsRowCount?: number;\n totalsRowShown?: boolean;\n autoFilter?: AutoFilter;\n displayName?: string;\n },\n): TableDefinition => {\n const cols: TableColumn[] = opts.columns.map((c, i): TableColumn =>\n typeof c === 'string' ? { id: i + 1, name: c } : c,\n );\n const styleInfo: TableStyleInfo | undefined =\n opts.styleInfo ??\n (opts.style !== undefined ? { name: opts.style, showRowStripes: true, showColumnStripes: false } : undefined);\n const def: TableDefinition = makeTableDefinition({\n id: nextTableId(wb),\n displayName: opts.displayName ?? opts.name,\n name: opts.name,\n ref: opts.ref,\n columns: cols,\n ...(opts.headerRowCount !== undefined ? { headerRowCount: opts.headerRowCount } : {}),\n ...(opts.totalsRowCount !== undefined ? { totalsRowCount: opts.totalsRowCount } : {}),\n ...(opts.totalsRowShown !== undefined ? { totalsRowShown: opts.totalsRowShown } : {}),\n ...(styleInfo ? { styleInfo } : {}),\n ...(opts.autoFilter ? { autoFilter: opts.autoFilter } : {}),\n });\n ws.tables.push(def);\n return def;\n};\n"],"mappings":";;AAoGA,SAAgB,0BAA0B,MAIhB;CACxB,OAAO;EACL,OAAO,OAAO,KAAK,UAAU,WAAW,oBAAoB,KAAK,KAAK,IAAI,KAAK;EAC/E,OAAO,KAAK,SAAS,CAAC;EACtB,GAAI,KAAK,UAAU,KAAA,IAAY,EAAE,OAAO,KAAK,MAAM,IAAI,CAAC;CAC1D;AACF;AAEA,SAAgB,WACd,MAI2B;CAC3B,OAAO;EACL,MAAM,KAAK;EACX,UAAU,KAAK;EACf,UAAU,KAAK,YAAY,CAAC;EAC5B,GAAI,KAAK,UAAU,KAAA,IAAY,EAAE,OAAO,KAAK,MAAM,IAAI,CAAC;EACxD,GAAI,KAAK,eAAe,KAAA,IAAY,EAAE,YAAY,KAAK,WAAW,IAAI,CAAC;EACvE,GAAI,KAAK,aAAa,KAAA,IAAY,EAAE,UAAU,KAAK,SAAS,IAAI,CAAC;EACjE,GAAI,KAAK,SAAS,KAAA,IAAY,EAAE,MAAM,KAAK,KAAK,IAAI,CAAC;EACrD,GAAI,KAAK,YAAY,KAAA,IAAY,EAAE,SAAS,KAAK,QAAQ,IAAI,CAAC;EAC9D,GAAI,KAAK,WAAW,KAAA,IAAY,EAAE,QAAQ,KAAK,OAAO,IAAI,CAAC;EAC3D,GAAI,KAAK,SAAS,KAAA,IAAY,EAAE,MAAM,KAAK,KAAK,IAAI,CAAC;EACrD,GAAI,KAAK,iBAAiB,KAAA,IAAY,EAAE,cAAc,KAAK,aAAa,IAAI,CAAC;EAC7E,GAAI,KAAK,iBAAiB,KAAA,IAAY,EAAE,cAAc,KAAK,aAAa,IAAI,CAAC;EAC7E,GAAI,KAAK,WAAW,KAAA,IAAY,EAAE,QAAQ,KAAK,OAAO,IAAI,CAAC;EAC3D,GAAI,KAAK,eAAe,KAAA,IAAY,EAAE,YAAY,KAAK,WAAW,IAAI,CAAC;EACvE,GAAI,KAAK,aAAa,KAAA,IAAY,EAAE,UAAU,KAAK,SAAS,IAAI,CAAC;CACnE;AACF;;;ACxFA,SAAgB,mBACd,MAIgB;CAChB,OAAO;EACL,MAAM,KAAK;EACX,OAAO,OAAO,KAAK,UAAU,WAAW,oBAAoB,KAAK,KAAK,IAAI,KAAK;EAC/E,GAAI,KAAK,aAAa,KAAA,IAAY,EAAE,UAAU,KAAK,SAAS,IAAI,CAAC;EACjE,GAAI,KAAK,aAAa,KAAA,IAAY,EAAE,UAAU,KAAK,SAAS,IAAI,CAAC;EACjE,GAAI,KAAK,aAAa,KAAA,IAAY,EAAE,UAAU,KAAK,SAAS,IAAI,CAAC;EACjE,GAAI,KAAK,eAAe,KAAA,IAAY,EAAE,YAAY,KAAK,WAAW,IAAI,CAAC;EACvE,GAAI,KAAK,qBAAqB,KAAA,IAAY,EAAE,kBAAkB,KAAK,iBAAiB,IAAI,CAAC;EACzF,GAAI,KAAK,qBAAqB,KAAA,IAAY,EAAE,kBAAkB,KAAK,iBAAiB,IAAI,CAAC;EACzF,GAAI,KAAK,eAAe,KAAA,IAAY,EAAE,YAAY,KAAK,WAAW,IAAI,CAAC;EACvE,GAAI,KAAK,UAAU,KAAA,IAAY,EAAE,OAAO,KAAK,MAAM,IAAI,CAAC;EACxD,GAAI,KAAK,eAAe,KAAA,IAAY,EAAE,YAAY,KAAK,WAAW,IAAI,CAAC;EACvE,GAAI,KAAK,gBAAgB,KAAA,IAAY,EAAE,aAAa,KAAK,YAAY,IAAI,CAAC;EAC1E,GAAI,KAAK,WAAW,KAAA,IAAY,EAAE,QAAQ,KAAK,OAAO,IAAI,CAAC;EAC3D,GAAI,KAAK,iBAAiB,KAAA,IAAY,EAAE,cAAc,KAAK,aAAa,IAAI,CAAC;CAC/E;AACF;;;ACVA,SAAgB,gBAAgB,MAAiD;CAC/E,OAAO;EAAE,IAAI,KAAK;EAAI,MAAM,KAAK;CAAK;AACxC;AAEA,SAAgB,oBAAoB,MAWhB;CAClB,OAAO;EACL,IAAI,KAAK;EACT,aAAa,KAAK;EAClB,KAAK,KAAK;EACV,SAAS,KAAK,WAAW,CAAC;EAC1B,GAAI,KAAK,SAAS,KAAA,IAAY,EAAE,MAAM,KAAK,KAAK,IAAI,CAAC;EACrD,GAAI,KAAK,mBAAmB,KAAA,IAAY,EAAE,gBAAgB,KAAK,eAAe,IAAI,CAAC;EACnF,GAAI,KAAK,mBAAmB,KAAA,IAAY,EAAE,gBAAgB,KAAK,eAAe,IAAI,CAAC;EACnF,GAAI,KAAK,mBAAmB,KAAA,IAAY,EAAE,gBAAgB,KAAK,eAAe,IAAI,CAAC;EACnF,GAAI,KAAK,YAAY,EAAE,WAAW,KAAK,UAAU,IAAI,CAAC;EACtD,GAAI,KAAK,aAAa,EAAE,YAAY,KAAK,WAAW,IAAI,CAAC;CAC3D;AACF;AAEA,MAAM,eAAe,OAAyB;CAC5C,IAAI,MAAM;CACV,KAAK,MAAM,OAAO,GAAG,QAAQ;EAC3B,IAAI,IAAI,SAAS,aAAa;EAC9B,KAAK,MAAM,KAAK,IAAI,MAAM,QACxB,IAAI,EAAE,KAAK,KAAK,MAAM,EAAE;CAE5B;CACA,OAAO,MAAM;AACf;;;;;;;AAQA,MAAa,iBACX,IACA,IACA,SAYoB;CACpB,MAAM,OAAsB,KAAK,QAAQ,KAAK,GAAG,MAC/C,OAAO,MAAM,WAAW;EAAE,IAAI,IAAI;EAAG,MAAM;CAAE,IAAI,CACnD;CACA,MAAM,YACJ,KAAK,cACJ,KAAK,UAAU,KAAA,IAAY;EAAE,MAAM,KAAK;EAAO,gBAAgB;EAAM,mBAAmB;CAAM,IAAI,KAAA;CACrG,MAAM,MAAuB,oBAAoB;EAC/C,IAAI,YAAY,EAAE;EAClB,aAAa,KAAK,eAAe,KAAK;EACtC,MAAM,KAAK;EACX,KAAK,KAAK;EACV,SAAS;EACT,GAAI,KAAK,mBAAmB,KAAA,IAAY,EAAE,gBAAgB,KAAK,eAAe,IAAI,CAAC;EACnF,GAAI,KAAK,mBAAmB,KAAA,IAAY,EAAE,gBAAgB,KAAK,eAAe,IAAI,CAAC;EACnF,GAAI,KAAK,mBAAmB,KAAA,IAAY,EAAE,gBAAgB,KAAK,eAAe,IAAI,CAAC;EACnF,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;EACjC,GAAI,KAAK,aAAa,EAAE,YAAY,KAAK,WAAW,IAAI,CAAC;CAC3D,CAAC;CACD,GAAG,OAAO,KAAK,GAAG;CAClB,OAAO;AACT"}
1
+ {"version":3,"file":"table-1P8we2gS.mjs","names":[],"sources":["../src/worksheet/conditional-formatting.ts","../src/worksheet/data-validations.ts","../src/worksheet/table.ts"],"sourcesContent":["// Conditional formatting.\n//\n// Stage-1 covers the **value-based** rule kinds (cellIs / expression / top10 /\n// aboveAverage / containsText family / containsBlanks family / duplicateValues\n// / uniqueValues / timePeriod). The visual rule kinds — colorScale / dataBar /\n// iconSet — round-trip as opaque inner XML (`innerXml` field) so the data\n// survives a save / load cycle without our needing to model cfvo / colors /\n// iconSets fully.\n\nimport { escapeXmlAttr } from '../utils/escape.js';\nimport { OpenXmlSchemaError } from '../utils/exceptions.js';\nimport { type MultiCellRange, parseMultiCellRange } from './cell-range.js';\n\nexport type ConditionalFormattingRuleType =\n | 'expression'\n | 'cellIs'\n | 'colorScale'\n | 'dataBar'\n | 'iconSet'\n | 'top10'\n | 'aboveAverage'\n | 'uniqueValues'\n | 'duplicateValues'\n | 'containsText'\n | 'notContainsText'\n | 'beginsWith'\n | 'endsWith'\n | 'containsBlanks'\n | 'notContainsBlanks'\n | 'containsErrors'\n | 'notContainsErrors'\n | 'timePeriod';\n\nexport type CellIsOperator =\n | 'lessThan'\n | 'lessThanOrEqual'\n | 'equal'\n | 'notEqual'\n | 'greaterThanOrEqual'\n | 'greaterThan'\n | 'between'\n | 'notBetween';\n\nexport type TextOperator = 'containsText' | 'notContains' | 'beginsWith' | 'endsWith';\n\nexport type TimePeriod =\n | 'today'\n | 'yesterday'\n | 'tomorrow'\n | 'last7Days'\n | 'thisMonth'\n | 'lastMonth'\n | 'nextMonth'\n | 'thisWeek'\n | 'lastWeek'\n | 'nextWeek';\n\nexport interface ConditionalFormattingRule {\n /** Wire-level rule kind. */\n type: ConditionalFormattingRuleType;\n /** 1-based priority — Excel evaluates lower priority first. */\n priority: number;\n /** Index into Stylesheet.dxfs for the cell-format applied when the rule fires. */\n dxfId?: number;\n /** Stop evaluating subsequent rules on the same cell when this rule matches. */\n stopIfTrue?: boolean;\n /** cellIs operator. */\n operator?: CellIsOperator | TextOperator | string;\n /** Comparison string for the contains-text family. */\n text?: string;\n /** top10: rank percentage flag. */\n percent?: boolean;\n /** top10: bottom-N flag (false = top-N, true = bottom-N). */\n bottom?: boolean;\n /** top10: rank value (defaults to 10). */\n rank?: number;\n /** aboveAverage: aboveAverage=\"0\" → below average. */\n aboveAverage?: boolean;\n /** aboveAverage: equalAverage flag. */\n equalAverage?: boolean;\n /** aboveAverage: stdDev. */\n stdDev?: number;\n /** timePeriod token. */\n timePeriod?: TimePeriod;\n /** 0..3 formula strings — varies by rule type. */\n formulas: string[];\n /**\n * Raw inner XML for colorScale / dataBar / iconSet rules. Stage-1 stores the\n * verbatim child markup so saves round-trip without our needing to model cfvo\n * / colors / iconSets fully.\n */\n innerXml?: string;\n}\n\nexport interface ConditionalFormatting {\n sqref: MultiCellRange;\n rules: ConditionalFormattingRule[];\n pivot?: boolean;\n}\n\nexport function makeConditionalFormatting(opts: {\n sqref: MultiCellRange | string;\n rules?: ConditionalFormattingRule[];\n pivot?: boolean;\n}): ConditionalFormatting {\n return {\n sqref: typeof opts.sqref === 'string' ? parseMultiCellRange(opts.sqref) : opts.sqref,\n rules: opts.rules ?? [],\n ...(opts.pivot !== undefined ? { pivot: opts.pivot } : {}),\n };\n}\n\nexport function makeCfRule(\n opts: Partial<ConditionalFormattingRule> & {\n type: ConditionalFormattingRuleType;\n priority: number;\n },\n): ConditionalFormattingRule {\n return {\n type: opts.type,\n priority: opts.priority,\n formulas: opts.formulas ?? [],\n ...(opts.dxfId !== undefined ? { dxfId: opts.dxfId } : {}),\n ...(opts.stopIfTrue !== undefined ? { stopIfTrue: opts.stopIfTrue } : {}),\n ...(opts.operator !== undefined ? { operator: opts.operator } : {}),\n ...(opts.text !== undefined ? { text: opts.text } : {}),\n ...(opts.percent !== undefined ? { percent: opts.percent } : {}),\n ...(opts.bottom !== undefined ? { bottom: opts.bottom } : {}),\n ...(opts.rank !== undefined ? { rank: opts.rank } : {}),\n ...(opts.aboveAverage !== undefined ? { aboveAverage: opts.aboveAverage } : {}),\n ...(opts.equalAverage !== undefined ? { equalAverage: opts.equalAverage } : {}),\n ...(opts.stdDev !== undefined ? { stdDev: opts.stdDev } : {}),\n ...(opts.timePeriod !== undefined ? { timePeriod: opts.timePeriod } : {}),\n ...(opts.innerXml !== undefined ? { innerXml: opts.innerXml } : {}),\n };\n}\n\n// ---- Worksheet ergonomic builders ---------------------------------------\n\nimport type { Worksheet } from './worksheet.js';\n\nconst resolveCfSqref = (sqref: MultiCellRange | string): MultiCellRange =>\n typeof sqref === 'string' ? parseMultiCellRange(sqref) : sqref;\n\nconst nextCfPriority = (ws: Worksheet): number => {\n let max = 0;\n for (const cf of ws.conditionalFormatting) {\n for (const r of cf.rules) {\n if (r.priority > max) max = r.priority;\n }\n }\n return max + 1;\n};\n\n/** Push one CF rule onto the worksheet, wrapping it in a ConditionalFormatting block keyed off `sqref`. */\nconst pushRule = (\n ws: Worksheet,\n sqref: MultiCellRange | string,\n rule: ConditionalFormattingRule,\n): ConditionalFormattingRule => {\n ws.conditionalFormatting.push(makeConditionalFormatting({ sqref: resolveCfSqref(sqref), rules: [rule] }));\n return rule;\n};\n\n/**\n * \"If cell value [op] formula → apply dxf\". Mirrors Excel's \"Highlight Cell\n * Rules → ...\" UI.\n */\nexport const addCellIsRule = (\n ws: Worksheet,\n sqref: MultiCellRange | string,\n opts: {\n operator: CellIsOperator;\n formula1: string;\n formula2?: string;\n dxfId?: number;\n stopIfTrue?: boolean;\n priority?: number;\n },\n): ConditionalFormattingRule => {\n const formulas = opts.formula2 !== undefined ? [opts.formula1, opts.formula2] : [opts.formula1];\n return pushRule(\n ws,\n sqref,\n makeCfRule({\n type: 'cellIs',\n priority: opts.priority ?? nextCfPriority(ws),\n operator: opts.operator,\n formulas,\n ...(opts.dxfId !== undefined ? { dxfId: opts.dxfId } : {}),\n ...(opts.stopIfTrue !== undefined ? { stopIfTrue: opts.stopIfTrue } : {}),\n }),\n );\n};\n\n/** Top-N or bottom-N rule. `bottom: true` → bottom-N. `percent: true` → percentile. */\nexport const addTopNRule = (\n ws: Worksheet,\n sqref: MultiCellRange | string,\n opts: { rank?: number; bottom?: boolean; percent?: boolean; dxfId?: number; priority?: number },\n): ConditionalFormattingRule => {\n return pushRule(\n ws,\n sqref,\n makeCfRule({\n type: 'top10',\n priority: opts.priority ?? nextCfPriority(ws),\n formulas: [],\n ...(opts.rank !== undefined ? { rank: opts.rank } : {}),\n ...(opts.bottom !== undefined ? { bottom: opts.bottom } : {}),\n ...(opts.percent !== undefined ? { percent: opts.percent } : {}),\n ...(opts.dxfId !== undefined ? { dxfId: opts.dxfId } : {}),\n }),\n );\n};\n\n/** Above/below-average rule. `aboveAverage: false` → below-average; provide `stdDev` for ±N stddev. */\nexport const addAverageRule = (\n ws: Worksheet,\n sqref: MultiCellRange | string,\n opts: {\n aboveAverage?: boolean;\n equalAverage?: boolean;\n stdDev?: number;\n dxfId?: number;\n priority?: number;\n },\n): ConditionalFormattingRule => {\n return pushRule(\n ws,\n sqref,\n makeCfRule({\n type: 'aboveAverage',\n priority: opts.priority ?? nextCfPriority(ws),\n formulas: [],\n ...(opts.aboveAverage !== undefined ? { aboveAverage: opts.aboveAverage } : {}),\n ...(opts.equalAverage !== undefined ? { equalAverage: opts.equalAverage } : {}),\n ...(opts.stdDev !== undefined ? { stdDev: opts.stdDev } : {}),\n ...(opts.dxfId !== undefined ? { dxfId: opts.dxfId } : {}),\n }),\n );\n};\n\n/** Duplicate-values rule (each cell whose value appears more than once gets the dxf). */\nexport const addDuplicateValuesRule = (\n ws: Worksheet,\n sqref: MultiCellRange | string,\n opts: { dxfId?: number; priority?: number; unique?: boolean } = {},\n): ConditionalFormattingRule => {\n return pushRule(\n ws,\n sqref,\n makeCfRule({\n type: opts.unique ? 'uniqueValues' : 'duplicateValues',\n priority: opts.priority ?? nextCfPriority(ws),\n formulas: [],\n ...(opts.dxfId !== undefined ? { dxfId: opts.dxfId } : {}),\n }),\n );\n};\n\n/** Free-form formula rule — any `=ISNUMBER(A1)`-style boolean expression. */\nexport const addFormulaRule = (\n ws: Worksheet,\n sqref: MultiCellRange | string,\n opts: { formula: string; dxfId?: number; stopIfTrue?: boolean; priority?: number },\n): ConditionalFormattingRule => {\n return pushRule(\n ws,\n sqref,\n makeCfRule({\n type: 'expression',\n priority: opts.priority ?? nextCfPriority(ws),\n formulas: [opts.formula],\n ...(opts.dxfId !== undefined ? { dxfId: opts.dxfId } : {}),\n ...(opts.stopIfTrue !== undefined ? { stopIfTrue: opts.stopIfTrue } : {}),\n }),\n );\n};\n\n/** Text-based rule (containsText / notContains / beginsWith / endsWith). */\nexport const addTextRule = (\n ws: Worksheet,\n sqref: MultiCellRange | string,\n opts: { operator: TextOperator; text: string; dxfId?: number; priority?: number },\n): ConditionalFormattingRule => {\n // Excel uses different `type` tokens for the four text operators.\n const typeMap: Record<TextOperator, ConditionalFormattingRuleType> = {\n containsText: 'containsText',\n notContains: 'notContainsText',\n beginsWith: 'beginsWith',\n endsWith: 'endsWith',\n };\n return pushRule(\n ws,\n sqref,\n makeCfRule({\n type: typeMap[opts.operator],\n priority: opts.priority ?? nextCfPriority(ws),\n operator: opts.operator,\n text: opts.text,\n formulas: [],\n ...(opts.dxfId !== undefined ? { dxfId: opts.dxfId } : {}),\n }),\n );\n};\n\n// ---- Visual rule builders (colorScale / dataBar / iconSet) --------------\n\nexport type CfvoType = 'min' | 'max' | 'num' | 'percent' | 'percentile' | 'formula';\n\nexport interface Cfvo {\n type: CfvoType;\n /** Required for num / percent / percentile / formula; ignored for min / max. */\n val?: string;\n}\n\nexport type IconSetStyle =\n | '3Arrows'\n | '3ArrowsGray'\n | '3Flags'\n | '3Signs'\n | '3Symbols'\n | '3Symbols2'\n | '3TrafficLights1'\n | '3TrafficLights2'\n | '4Arrows'\n | '4ArrowsGray'\n | '4Rating'\n | '4RedToBlack'\n | '4TrafficLights'\n | '5Arrows'\n | '5ArrowsGray'\n | '5Quarters'\n | '5Rating';\n\nconst escapeAttr = escapeXmlAttr;\n\nconst renderCfvo = (c: Cfvo): string => {\n if (c.type === 'min' || c.type === 'max') {\n if (c.val === undefined) return `<cfvo type=\"${c.type}\"/>`;\n return `<cfvo type=\"${c.type}\" val=\"${escapeAttr(c.val)}\"/>`;\n }\n if (c.val === undefined) {\n throw new OpenXmlSchemaError(`cfvo type \"${c.type}\" requires val`);\n }\n return `<cfvo type=\"${c.type}\" val=\"${escapeAttr(c.val)}\"/>`;\n};\n\nconst renderColor = (hex: string): string => `<color rgb=\"${escapeAttr(hex)}\"/>`;\n\n/**\n * Color-scale rule — gradient between 2 or 3 reference points. Each cfvo pairs\n * with one color.\n */\nexport const addColorScaleRule = (\n ws: Worksheet,\n sqref: MultiCellRange | string,\n opts: {\n cfvos: ReadonlyArray<Cfvo>;\n /** Hex strings, e.g. `'FFFF0000'`; one per cfvo. */\n colors: ReadonlyArray<string>;\n priority?: number;\n stopIfTrue?: boolean;\n },\n): ConditionalFormattingRule => {\n if (opts.cfvos.length !== 2 && opts.cfvos.length !== 3) {\n throw new OpenXmlSchemaError(`addColorScaleRule: cfvos must be length 2 or 3; got ${opts.cfvos.length}`);\n }\n if (opts.colors.length !== opts.cfvos.length) {\n throw new OpenXmlSchemaError(\n `addColorScaleRule: colors length (${opts.colors.length}) must match cfvos length (${opts.cfvos.length})`,\n );\n }\n const inner = `<colorScale>${opts.cfvos.map(renderCfvo).join('')}${opts.colors.map(renderColor).join('')}</colorScale>`;\n return pushRule(\n ws,\n sqref,\n makeCfRule({\n type: 'colorScale',\n priority: opts.priority ?? nextCfPriority(ws),\n formulas: [],\n innerXml: inner,\n ...(opts.stopIfTrue !== undefined ? { stopIfTrue: opts.stopIfTrue } : {}),\n }),\n );\n};\n\n/**\n * Data-bar rule — a gradient bar inside each cell sized to the value. Defaults\n * to `min`/`max` cfvos so the bar spans the visible range.\n */\nexport const addDataBarRule = (\n ws: Worksheet,\n sqref: MultiCellRange | string,\n opts: {\n color: string;\n minCfvo?: Cfvo;\n maxCfvo?: Cfvo;\n minLength?: number;\n maxLength?: number;\n showValue?: boolean;\n priority?: number;\n stopIfTrue?: boolean;\n },\n): ConditionalFormattingRule => {\n const min = opts.minCfvo ?? { type: 'min' };\n const max = opts.maxCfvo ?? { type: 'max' };\n let attrs = '';\n if (opts.minLength !== undefined) attrs += ` minLength=\"${opts.minLength}\"`;\n if (opts.maxLength !== undefined) attrs += ` maxLength=\"${opts.maxLength}\"`;\n if (opts.showValue !== undefined) attrs += ` showValue=\"${opts.showValue ? '1' : '0'}\"`;\n const inner = `<dataBar${attrs}>${renderCfvo(min)}${renderCfvo(max)}${renderColor(opts.color)}</dataBar>`;\n return pushRule(\n ws,\n sqref,\n makeCfRule({\n type: 'dataBar',\n priority: opts.priority ?? nextCfPriority(ws),\n formulas: [],\n innerXml: inner,\n ...(opts.stopIfTrue !== undefined ? { stopIfTrue: opts.stopIfTrue } : {}),\n }),\n );\n};\n\n/**\n * Icon-set rule — visual icons (arrows / lights / flags) drawn next to each\n * cell value. The number of cfvos depends on the icon set (3 for `3Arrows`, 4\n * for `4Arrows`, 5 for `5Arrows`, etc).\n */\nexport const addIconSetRule = (\n ws: Worksheet,\n sqref: MultiCellRange | string,\n opts: {\n iconSet: IconSetStyle | string;\n cfvos: ReadonlyArray<Cfvo>;\n reverse?: boolean;\n showValue?: boolean;\n percent?: boolean;\n priority?: number;\n stopIfTrue?: boolean;\n },\n): ConditionalFormattingRule => {\n if (opts.cfvos.length < 3 || opts.cfvos.length > 5) {\n throw new OpenXmlSchemaError(`addIconSetRule: cfvos must be length 3..5; got ${opts.cfvos.length}`);\n }\n let attrs = ` iconSet=\"${escapeAttr(opts.iconSet)}\"`;\n if (opts.reverse !== undefined) attrs += ` reverse=\"${opts.reverse ? '1' : '0'}\"`;\n if (opts.showValue !== undefined) attrs += ` showValue=\"${opts.showValue ? '1' : '0'}\"`;\n if (opts.percent !== undefined) attrs += ` percent=\"${opts.percent ? '1' : '0'}\"`;\n const inner = `<iconSet${attrs}>${opts.cfvos.map(renderCfvo).join('')}</iconSet>`;\n return pushRule(\n ws,\n sqref,\n makeCfRule({\n type: 'iconSet',\n priority: opts.priority ?? nextCfPriority(ws),\n formulas: [],\n innerXml: inner,\n ...(opts.stopIfTrue !== undefined ? { stopIfTrue: opts.stopIfTrue } : {}),\n }),\n );\n};\n","// Data validations.\n//\n// A DataValidation entry attaches a constraint (one of seven type kinds,\n// optional operator, two formula slots) to a sqref-style MultiCellRange.\n// Stage-1 maps every OOXML attribute we have a use for; imeMode + numeric/value\n// clamps land later when phase 7's Asian-locale support catches up.\n\nimport { type MultiCellRange, parseMultiCellRange } from './cell-range.js';\n\nexport type DataValidationType = 'whole' | 'decimal' | 'list' | 'date' | 'time' | 'textLength' | 'custom';\nexport type DataValidationOperator =\n | 'between'\n | 'notBetween'\n | 'equal'\n | 'notEqual'\n | 'greaterThan'\n | 'greaterThanOrEqual'\n | 'lessThan'\n | 'lessThanOrEqual';\nexport type DataValidationErrorStyle = 'stop' | 'warning' | 'information';\n\nexport interface DataValidation {\n /** Constraint kind. `'list'` is the dropdown form (formula1 = comma list or range). */\n type: DataValidationType;\n /** Comparison operator — only meaningful for whole/decimal/date/time/textLength. */\n operator?: DataValidationOperator;\n /** Lower-bound formula or list source. Always required for list/whole/decimal/date/time. */\n formula1?: string;\n /** Upper-bound formula. Used by between / notBetween only. */\n formula2?: string;\n /** Allow empty cells. */\n allowBlank?: boolean;\n /** Show the input message popover when the cell is selected. */\n showInputMessage?: boolean;\n /** Show the error message popover on invalid entry. */\n showErrorMessage?: boolean;\n errorTitle?: string;\n error?: string;\n errorStyle?: DataValidationErrorStyle;\n promptTitle?: string;\n prompt?: string;\n /** Excel inverts this attribute: `showDropDown=\"1\"` actually *hides* the dropdown arrow on list-type validators. We mirror the wire form. */\n showDropDown?: boolean;\n /** Apply-to range (sqref). */\n sqref: MultiCellRange;\n}\n\nexport function makeDataValidation(\n opts: Omit<Partial<DataValidation>, 'sqref'> & {\n type: DataValidationType;\n sqref: MultiCellRange | string;\n },\n): DataValidation {\n return {\n type: opts.type,\n sqref: typeof opts.sqref === 'string' ? parseMultiCellRange(opts.sqref) : opts.sqref,\n ...(opts.operator !== undefined ? { operator: opts.operator } : {}),\n ...(opts.formula1 !== undefined ? { formula1: opts.formula1 } : {}),\n ...(opts.formula2 !== undefined ? { formula2: opts.formula2 } : {}),\n ...(opts.allowBlank !== undefined ? { allowBlank: opts.allowBlank } : {}),\n ...(opts.showInputMessage !== undefined ? { showInputMessage: opts.showInputMessage } : {}),\n ...(opts.showErrorMessage !== undefined ? { showErrorMessage: opts.showErrorMessage } : {}),\n ...(opts.errorTitle !== undefined ? { errorTitle: opts.errorTitle } : {}),\n ...(opts.error !== undefined ? { error: opts.error } : {}),\n ...(opts.errorStyle !== undefined ? { errorStyle: opts.errorStyle } : {}),\n ...(opts.promptTitle !== undefined ? { promptTitle: opts.promptTitle } : {}),\n ...(opts.prompt !== undefined ? { prompt: opts.prompt } : {}),\n ...(opts.showDropDown !== undefined ? { showDropDown: opts.showDropDown } : {}),\n };\n}\n\n// ---- Worksheet ergonomic builders ---------------------------------------\n\nimport type { Worksheet } from './worksheet.js';\n\nconst resolveSqref = (sqref: MultiCellRange | string): MultiCellRange =>\n typeof sqref === 'string' ? parseMultiCellRange(sqref) : sqref;\n\nexport interface ValidationCommon {\n /** Show the dropdown / input prompt when the cell is selected. */\n prompt?: string;\n promptTitle?: string;\n /** Show an error dialog when the user types an invalid value. */\n error?: string;\n errorTitle?: string;\n errorStyle?: DataValidationErrorStyle;\n allowBlank?: boolean;\n}\n\n/**\n * Add a list-type dropdown validation to a range. `values` may be an inline\n * list (`['Red', 'Green', 'Blue']`) or a sheet reference\n * (`'=Sheet1!$A$1:$A$10'`).\n */\nexport const addListValidation = (\n ws: Worksheet,\n sqref: MultiCellRange | string,\n values: ReadonlyArray<string> | string,\n opts: ValidationCommon = {},\n): DataValidation => {\n const formula1 = Array.isArray(values)\n ? `\"${(values as ReadonlyArray<string>).join(',')}\"`\n : (values as string);\n const dv = makeDataValidation({\n type: 'list',\n sqref: resolveSqref(sqref),\n formula1,\n allowBlank: opts.allowBlank ?? true,\n showInputMessage: opts.prompt !== undefined,\n showErrorMessage: opts.error !== undefined || opts.errorStyle !== undefined,\n ...(opts.errorStyle !== undefined ? { errorStyle: opts.errorStyle } : {}),\n ...(opts.error !== undefined ? { error: opts.error } : {}),\n ...(opts.errorTitle !== undefined ? { errorTitle: opts.errorTitle } : {}),\n ...(opts.prompt !== undefined ? { prompt: opts.prompt } : {}),\n ...(opts.promptTitle !== undefined ? { promptTitle: opts.promptTitle } : {}),\n });\n ws.dataValidations.push(dv);\n return dv;\n};\n\n/**\n * Add a number-range validation. `between(min, max)` matches Excel's \"Whole\n * Number\" → \"between\" form by default. Use `kind: 'decimal'` for decimal\n * (default 'whole').\n */\nexport const addNumberValidation = (\n ws: Worksheet,\n sqref: MultiCellRange | string,\n range: { min: number; max?: number; operator?: DataValidationOperator; kind?: 'whole' | 'decimal' },\n opts: ValidationCommon = {},\n): DataValidation => {\n const operator: DataValidationOperator =\n range.operator ?? (range.max !== undefined ? 'between' : 'greaterThanOrEqual');\n const dv = makeDataValidation({\n type: range.kind ?? 'whole',\n sqref: resolveSqref(sqref),\n operator,\n formula1: String(range.min),\n ...(range.max !== undefined ? { formula2: String(range.max) } : {}),\n allowBlank: opts.allowBlank ?? true,\n showInputMessage: opts.prompt !== undefined,\n showErrorMessage: opts.error !== undefined || opts.errorStyle !== undefined,\n ...(opts.errorStyle !== undefined ? { errorStyle: opts.errorStyle } : {}),\n ...(opts.error !== undefined ? { error: opts.error } : {}),\n ...(opts.errorTitle !== undefined ? { errorTitle: opts.errorTitle } : {}),\n ...(opts.prompt !== undefined ? { prompt: opts.prompt } : {}),\n ...(opts.promptTitle !== undefined ? { promptTitle: opts.promptTitle } : {}),\n });\n ws.dataValidations.push(dv);\n return dv;\n};\n\n/**\n * Add a date-range validation. Dates are passed as Excel serial numbers (use\n * `dateToExcel` to convert from JS `Date`).\n */\nexport const addDateValidation = (\n ws: Worksheet,\n sqref: MultiCellRange | string,\n range: { min: number; max?: number; operator?: DataValidationOperator },\n opts: ValidationCommon = {},\n): DataValidation => {\n const operator: DataValidationOperator =\n range.operator ?? (range.max !== undefined ? 'between' : 'greaterThanOrEqual');\n const dv = makeDataValidation({\n type: 'date',\n sqref: resolveSqref(sqref),\n operator,\n formula1: String(range.min),\n ...(range.max !== undefined ? { formula2: String(range.max) } : {}),\n allowBlank: opts.allowBlank ?? true,\n showInputMessage: opts.prompt !== undefined,\n showErrorMessage: opts.error !== undefined || opts.errorStyle !== undefined,\n ...(opts.errorStyle !== undefined ? { errorStyle: opts.errorStyle } : {}),\n ...(opts.error !== undefined ? { error: opts.error } : {}),\n ...(opts.errorTitle !== undefined ? { errorTitle: opts.errorTitle } : {}),\n ...(opts.prompt !== undefined ? { prompt: opts.prompt } : {}),\n ...(opts.promptTitle !== undefined ? { promptTitle: opts.promptTitle } : {}),\n });\n ws.dataValidations.push(dv);\n return dv;\n};\n\n/** Add a custom-formula validation (`formula1` evaluated for each cell). */\nexport const addCustomValidation = (\n ws: Worksheet,\n sqref: MultiCellRange | string,\n formula: string,\n opts: ValidationCommon = {},\n): DataValidation => {\n const dv = makeDataValidation({\n type: 'custom',\n sqref: resolveSqref(sqref),\n formula1: formula,\n allowBlank: opts.allowBlank ?? true,\n showInputMessage: opts.prompt !== undefined,\n showErrorMessage: opts.error !== undefined || opts.errorStyle !== undefined,\n ...(opts.errorStyle !== undefined ? { errorStyle: opts.errorStyle } : {}),\n ...(opts.error !== undefined ? { error: opts.error } : {}),\n ...(opts.errorTitle !== undefined ? { errorTitle: opts.errorTitle } : {}),\n ...(opts.prompt !== undefined ? { prompt: opts.prompt } : {}),\n ...(opts.promptTitle !== undefined ? { promptTitle: opts.promptTitle } : {}),\n });\n ws.dataValidations.push(dv);\n return dv;\n};\n","// Excel Table object (xl/tables/tableN.xml).\n//\n// Tables ride on top of a worksheet range, give it a name + structured column\n// references, and own their own AutoFilter. Each table sits in a separate part\n// — the worksheet only carries a `<tableParts>` block pointing at the\n// workbook-rels rId. Stage-1 covers the table shell + columns + styleInfo +\n// autoFilter; sortState / totals row formulas / calculated column formulas /\n// xml extlst are reserved for later.\n\nimport type { Workbook } from '../workbook/workbook.js';\nimport type { AutoFilter } from './auto-filter.js';\nimport type { Worksheet } from './worksheet.js';\n\nexport interface TableColumn {\n /** 1-based column id (per-table). */\n id: number;\n /** Header name. */\n name: string;\n /** Totals-row aggregation function. */\n totalsRowFunction?: 'sum' | 'min' | 'max' | 'count' | 'countNums' | 'average' | 'stdDev' | 'var' | 'custom';\n /** Override label for the totals row. */\n totalsRowLabel?: string;\n /** Custom totals-row formula text. */\n totalsRowFormula?: string;\n /** Calculated-column formula. */\n calculatedColumnFormula?: string;\n}\n\nexport interface TableStyleInfo {\n /** Built-in style name (TableStyleMedium2, etc) or custom. */\n name?: string;\n showFirstColumn?: boolean;\n showLastColumn?: boolean;\n showRowStripes?: boolean;\n showColumnStripes?: boolean;\n}\n\nexport interface TableDefinition {\n /** Workbook-unique id (`<table id=\"N\">`). */\n id: number;\n /** Workbook-unique displayName — Excel surfaces this in formulas. */\n displayName: string;\n /** Optional friendly name; usually matches `displayName`. */\n name?: string;\n /** Range covered by the table, e.g. \"A1:E10\". */\n ref: string;\n /** Number of header rows. Defaults to 1; 0 means a header-less table. */\n headerRowCount?: number;\n /** Number of totals rows. */\n totalsRowCount?: number;\n /** Whether the totals row is currently visible. */\n totalsRowShown?: boolean;\n styleInfo?: TableStyleInfo;\n columns: TableColumn[];\n autoFilter?: AutoFilter;\n /** Worksheet-rels rId — populated on read; the writer assigns its own. */\n rId?: string;\n}\n\nexport function makeTableColumn(opts: { id: number; name: string }): TableColumn {\n return { id: opts.id, name: opts.name };\n}\n\nexport function makeTableDefinition(opts: {\n id: number;\n displayName: string;\n ref: string;\n name?: string;\n columns?: TableColumn[];\n headerRowCount?: number;\n totalsRowCount?: number;\n totalsRowShown?: boolean;\n styleInfo?: TableStyleInfo;\n autoFilter?: AutoFilter;\n}): TableDefinition {\n return {\n id: opts.id,\n displayName: opts.displayName,\n ref: opts.ref,\n columns: opts.columns ?? [],\n ...(opts.name !== undefined ? { name: opts.name } : {}),\n ...(opts.headerRowCount !== undefined ? { headerRowCount: opts.headerRowCount } : {}),\n ...(opts.totalsRowCount !== undefined ? { totalsRowCount: opts.totalsRowCount } : {}),\n ...(opts.totalsRowShown !== undefined ? { totalsRowShown: opts.totalsRowShown } : {}),\n ...(opts.styleInfo ? { styleInfo: opts.styleInfo } : {}),\n ...(opts.autoFilter ? { autoFilter: opts.autoFilter } : {}),\n };\n}\n\nconst nextTableId = (wb: Workbook): number => {\n let max = 0;\n for (const ref of wb.sheets) {\n if (ref.kind !== 'worksheet') continue;\n for (const t of ref.sheet.tables) {\n if (t.id > max) max = t.id;\n }\n }\n return max + 1;\n};\n\n/**\n * High-level wrapper that builds a TableDefinition + pushes it onto `ws.tables`\n * in one call. Auto-assigns the workbook-unique `id`, derives `displayName`\n * from the supplied `name`, and constructs `TableColumn` records (1-based ids)\n * from a string-array shorthand.\n */\nexport const addExcelTable = (\n wb: Workbook,\n ws: Worksheet,\n opts: {\n name: string;\n ref: string;\n columns: ReadonlyArray<string | TableColumn>;\n style?: string;\n styleInfo?: TableStyleInfo;\n headerRowCount?: number;\n totalsRowCount?: number;\n totalsRowShown?: boolean;\n autoFilter?: AutoFilter;\n displayName?: string;\n },\n): TableDefinition => {\n const cols: TableColumn[] = opts.columns.map((c, i): TableColumn =>\n typeof c === 'string' ? { id: i + 1, name: c } : c,\n );\n const styleInfo: TableStyleInfo | undefined =\n opts.styleInfo ??\n (opts.style !== undefined ? { name: opts.style, showRowStripes: true, showColumnStripes: false } : undefined);\n const def: TableDefinition = makeTableDefinition({\n id: nextTableId(wb),\n displayName: opts.displayName ?? opts.name,\n name: opts.name,\n ref: opts.ref,\n columns: cols,\n ...(opts.headerRowCount !== undefined ? { headerRowCount: opts.headerRowCount } : {}),\n ...(opts.totalsRowCount !== undefined ? { totalsRowCount: opts.totalsRowCount } : {}),\n ...(opts.totalsRowShown !== undefined ? { totalsRowShown: opts.totalsRowShown } : {}),\n ...(styleInfo ? { styleInfo } : {}),\n ...(opts.autoFilter ? { autoFilter: opts.autoFilter } : {}),\n });\n ws.tables.push(def);\n return def;\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"tree-BX-sRRVp.mjs","names":[],"sources":["../src/xml/namespaces.ts","../src/xml/tree.ts"],"sourcesContent":["// OOXML namespace and well-known package-path constants.\n//\n// Mirrors openpyxl/openpyxl/xml/constants.py so the test corpus stays directly\n// comparable. Where openpyxl exposes a single big dict (NAMESPACES) we keep\n// them as discrete `const` exports — bundlers can then drop the ones a given\n// build path never imports.\n\n// ---- W3C / Dublin Core ------------------------------------------------------\n\nexport const XML_NS = 'http://www.w3.org/XML/1998/namespace';\nexport const XSI_NS = 'http://www.w3.org/2001/XMLSchema-instance';\n\nexport const DCORE_NS = 'http://purl.org/dc/elements/1.1/';\nexport const DCTERMS_NS = 'http://purl.org/dc/terms/';\nexport const DCMITYPE_NS = 'http://purl.org/dc/dcmitype/';\nexport const DCTERMS_PREFIX = 'dcterms';\n\n// ---- ECMA-376 Office Document core ------------------------------------------\n\nconst DOC_NS = 'http://schemas.openxmlformats.org/officeDocument/2006/';\nexport const REL_NS = `${DOC_NS}relationships`;\nexport const COMMENTS_NS = `${REL_NS}/comments`;\nexport const IMAGE_NS = `${REL_NS}/image`;\nexport const VML_NS = `${REL_NS}/vmlDrawing`;\nexport const EXTERNAL_LINK_NS = `${REL_NS}/externalLink`;\nexport const VTYPES_NS = `${DOC_NS}docPropsVTypes`;\nexport const XPROPS_NS = `${DOC_NS}extended-properties`;\nexport const CUSTPROPS_NS = `${DOC_NS}custom-properties`;\nexport const CPROPS_FMTID = '{D5CDD505-2E9C-101B-9397-08002B2CF9AE}';\n\n// ---- Package layer ----------------------------------------------------------\n\nconst PKG_NS = 'http://schemas.openxmlformats.org/package/2006/';\nexport const PKG_REL_NS = `${PKG_NS}relationships`;\nexport const COREPROPS_NS = `${PKG_NS}metadata/core-properties`;\nexport const CONTYPES_NS = `${PKG_NS}content-types`;\n\n// ---- SpreadsheetML & DrawingML ----------------------------------------------\n\nexport const SHEET_MAIN_NS = 'http://schemas.openxmlformats.org/spreadsheetml/2006/main';\nexport const CHART_NS = 'http://schemas.openxmlformats.org/drawingml/2006/chart';\nexport const DRAWING_NS = 'http://schemas.openxmlformats.org/drawingml/2006/main';\nexport const SHEET_DRAWING_NS = 'http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing';\nexport const CHART_DRAWING_NS = 'http://schemas.openxmlformats.org/drawingml/2006/chartDrawing';\nexport const PICTURE_NS = 'http://schemas.openxmlformats.org/drawingml/2006/picture';\n\n// ---- Microsoft extensions ---------------------------------------------------\n\nexport const CUSTOMUI_NS = 'http://schemas.microsoft.com/office/2006/relationships/ui/extensibility';\nexport const MARKUP_COMPAT_NS = 'http://schemas.openxmlformats.org/markup-compatibility/2006';\nexport const X14_NS = 'http://schemas.microsoft.com/office/spreadsheetml/2009/9/main';\nexport const X15_NS = 'http://schemas.microsoft.com/office/spreadsheetml/2010/11/main';\n// \"Author capabilities\" — the namespace of the `<x15ac:absPath>` Excel writes\n// inside workbook.xml's `mc:Choice Requires=\"x15\"`. Only needed for its\n// canonical prefix, so it isn't exported.\nconst X15AC_NS = 'http://schemas.microsoft.com/office/spreadsheetml/2010/11/ac';\nexport const X16_NS = 'http://schemas.microsoft.com/office/spreadsheetml/2014/revision';\nexport const C14_NS = 'http://schemas.microsoft.com/office/drawing/2010/chart';\nexport const C15_NS = 'http://schemas.microsoft.com/office/drawing/2012/chart';\nexport const C16_NS = 'http://schemas.microsoft.com/office/drawing/2017/03/chart';\nexport const CX_NS = 'http://schemas.microsoft.com/office/drawing/2014/chartex';\nexport const THREADED_COMMENTS_NS = 'http://schemas.microsoft.com/office/spreadsheetml/2018/threadedcomments';\n\n// ---- Default prefix map -----------------------------------------------------\n//\n// Used when serialising XmlNode trees back to text: prefer these prefixes for\n// namespaces we recognise so output matches what Excel / openpyxl\n// conventionally emit. Entries are intentionally short — full prefix discovery\n// falls back to auto-generated names (`ns0`, `ns1`, ...) for namespaces not\n// listed here.\n\nexport const DEFAULT_PREFIXES: Readonly<Record<string, string>> = Object.freeze({\n [XML_NS]: 'xml',\n [XSI_NS]: 'xsi',\n [DCORE_NS]: 'dc',\n [DCTERMS_NS]: DCTERMS_PREFIX,\n [DCMITYPE_NS]: 'dcmitype',\n [REL_NS]: 'r',\n [VTYPES_NS]: 'vt',\n // app.xml uses XPROPS_NS as its default namespace; custom.xml uses\n // CUSTPROPS_NS the same way. Mark them as '' so serialised output matches\n // Office / openpyxl convention out of the box.\n [XPROPS_NS]: '',\n [CUSTPROPS_NS]: '',\n [PKG_REL_NS]: '',\n [COREPROPS_NS]: 'cp',\n [CONTYPES_NS]: '',\n [SHEET_MAIN_NS]: '',\n [CHART_NS]: 'c',\n [DRAWING_NS]: 'a',\n [SHEET_DRAWING_NS]: 'xdr',\n [CHART_DRAWING_NS]: 'cdr',\n [PICTURE_NS]: 'pic',\n [MARKUP_COMPAT_NS]: 'mc',\n [X14_NS]: 'x14',\n [X15_NS]: 'x15',\n [X15AC_NS]: 'x15ac',\n [X16_NS]: 'x16',\n [C14_NS]: 'c14',\n [C15_NS]: 'c15',\n [C16_NS]: 'c16',\n [CX_NS]: 'cx',\n [THREADED_COMMENTS_NS]: 'tc',\n});\n\n// ---- ZIP package paths ------------------------------------------------------\n\nexport const PACKAGE_PROPS = 'docProps';\nexport const PACKAGE_XL = 'xl';\nexport const PACKAGE_RELS = '_rels';\nexport const PACKAGE_THEME = `${PACKAGE_XL}/theme`;\nexport const PACKAGE_WORKSHEETS = `${PACKAGE_XL}/worksheets`;\nexport const PACKAGE_CHARTSHEETS = `${PACKAGE_XL}/chartsheets`;\nexport const PACKAGE_DRAWINGS = `${PACKAGE_XL}/drawings`;\nexport const PACKAGE_CHARTS = `${PACKAGE_XL}/charts`;\nexport const PACKAGE_IMAGES = `${PACKAGE_XL}/media`;\nexport const PACKAGE_PIVOT_TABLE = `${PACKAGE_XL}/pivotTables`;\nexport const PACKAGE_PIVOT_CACHE = `${PACKAGE_XL}/pivotCache`;\nexport const PACKAGE_WORKSHEET_RELS = `${PACKAGE_WORKSHEETS}/${PACKAGE_RELS}`;\nexport const PACKAGE_CHARTSHEETS_RELS = `${PACKAGE_CHARTSHEETS}/${PACKAGE_RELS}`;\n\nexport const ARC_CONTENT_TYPES = '[Content_Types].xml';\nexport const ARC_ROOT_RELS = `${PACKAGE_RELS}/.rels`;\nexport const ARC_WORKBOOK_RELS = `${PACKAGE_XL}/${PACKAGE_RELS}/workbook.xml.rels`;\nexport const ARC_CORE = `${PACKAGE_PROPS}/core.xml`;\nexport const ARC_APP = `${PACKAGE_PROPS}/app.xml`;\nexport const ARC_CUSTOM = `${PACKAGE_PROPS}/custom.xml`;\nexport const ARC_WORKBOOK = `${PACKAGE_XL}/workbook.xml`;\nexport const ARC_STYLE = `${PACKAGE_XL}/styles.xml`;\nexport const ARC_THEME = `${PACKAGE_THEME}/theme1.xml`;\nexport const ARC_SHARED_STRINGS = `${PACKAGE_XL}/sharedStrings.xml`;\nexport const ARC_CUSTOM_UI = 'customUI/customUI.xml';\n\n// ---- MIME / content-type strings -------------------------------------------\n\nconst WORKBOOK_TPL = 'application/vnd.openxmlformats-officedocument.spreadsheetml.%s.main+xml';\nconst SPREADSHEET_TPL = 'application/vnd.openxmlformats-officedocument.spreadsheetml.%s+xml';\nconst WORKBOOK_MACRO_TPL = 'application/vnd.ms-excel.%s.macroEnabled.main+xml';\nconst fmt = (tpl: string, kind: string): string => tpl.replace('%s', kind);\n\nexport const XLSX_TYPE = fmt(WORKBOOK_TPL, 'sheet');\nexport const XLTX_TYPE = fmt(WORKBOOK_TPL, 'template');\nexport const XLSM_TYPE = fmt(WORKBOOK_MACRO_TPL, 'sheet');\nexport const XLTM_TYPE = fmt(WORKBOOK_MACRO_TPL, 'template');\nexport const SHARED_STRINGS_TYPE = fmt(SPREADSHEET_TPL, 'sharedStrings');\nexport const EXTERNAL_LINK_TYPE = fmt(SPREADSHEET_TPL, 'externalLink');\nexport const WORKSHEET_TYPE = fmt(SPREADSHEET_TPL, 'worksheet');\nexport const COMMENTS_TYPE = fmt(SPREADSHEET_TPL, 'comments');\nexport const STYLES_TYPE = fmt(SPREADSHEET_TPL, 'styles');\nexport const CHARTSHEET_TYPE = fmt(SPREADSHEET_TPL, 'chartsheet');\nexport const DRAWING_TYPE = 'application/vnd.openxmlformats-officedocument.drawing+xml';\nexport const CHART_TYPE = 'application/vnd.openxmlformats-officedocument.drawingml.chart+xml';\nexport const CHARTEX_TYPE = 'application/vnd.ms-office.chartex+xml';\nexport const CHARTSHAPE_TYPE = 'application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml';\nexport const THEME_TYPE = 'application/vnd.openxmlformats-officedocument.theme+xml';\nexport const CPROPS_TYPE = 'application/vnd.openxmlformats-officedocument.custom-properties+xml';\nexport const VBA_TYPE = 'application/vnd.ms-office.vbaProject';\nexport const ACTIVEX_TYPE = 'application/vnd.ms-office.activeX+xml';\nexport const CTRLPROPS_TYPE = 'application/vnd.ms-excel.controlproperties+xml';\n\n// ---- QName helpers ----------------------------------------------------------\n\n/**\n * Build a Clark-notation QName: `{namespace}localname`. When `namespace` is\n * empty / undefined the local name is returned as-is.\n */\nexport function qname(namespace: string | undefined, local: string): string {\n return namespace ? `{${namespace}}${local}` : local;\n}\n\nconst QNAME_RE = /^\\{([^}]*)\\}(.+)$/;\n\n/**\n * Inverse of {@link qname}. Returns `{ ns, local }`. For unprefixed names `ns`\n * is the empty string.\n */\nexport function parseQName(name: string): { ns: string; local: string } {\n const m = QNAME_RE.exec(name);\n if (m === null) return { ns: '', local: name };\n return { ns: m[1] ?? '', local: m[2] ?? '' };\n}\n","// Lightweight XML tree representation used between the parser, the schema\n// layer, and the serializer.\n//\n// Plain object, no DOM, names in Clark notation `{ns}local` so namespace-aware\n// code does not depend on runtime prefix bookkeeping.\n\nimport { qname } from './namespaces';\n\nexport interface XmlNode {\n /** Clark-notation qualified name: `{namespace}local` or just `local`. */\n name: string;\n /** Attribute table; values are always strings (no value coercion at this layer). */\n attrs: Record<string, string>;\n /**\n * Optional element text. When an element has both text and child elements,\n * callers should set `text` and rely on `children` for mixed content; the\n * serializer emits `text` then children.\n */\n text?: string;\n /** Child element nodes in document order. */\n children: XmlNode[];\n}\n\n/**\n * Build an XmlNode from primitive bits. Attributes / children default to empty;\n * pass `undefined` for `text` to omit the text node.\n *\n * The element's name is always supplied in Clark notation. Use the {@link\n * qname} helper from `./namespaces` to keep call sites readable.\n */\nexport function el(\n name: string,\n attrs: Readonly<Record<string, string | number | boolean | null | undefined>> = {},\n children: ReadonlyArray<XmlNode> = [],\n text?: string,\n): XmlNode {\n const out: XmlNode = {\n name,\n attrs: normaliseAttrs(attrs),\n children: children.slice(),\n };\n if (text !== undefined) out.text = text;\n return out;\n}\n\nconst normaliseAttrs = (\n attrs: Readonly<Record<string, string | number | boolean | null | undefined>>,\n): Record<string, string> => {\n const out: Record<string, string> = {};\n for (const [k, v] of Object.entries(attrs)) {\n if (v === undefined || v === null) continue;\n out[k] = typeof v === 'string' ? v : String(v);\n }\n return out;\n};\n\n/**\n * Convenience: element with a Clark-notation name composed from a namespace URI\n * and local name.\n */\nexport function elNs(\n namespace: string | undefined,\n local: string,\n attrs?: Readonly<Record<string, string | number | boolean | null | undefined>>,\n children?: ReadonlyArray<XmlNode>,\n text?: string,\n): XmlNode {\n return el(qname(namespace, local), attrs, children, text);\n}\n\n/** Locate the first child matching the supplied Clark-notation name. */\nexport function findChild(node: XmlNode, name: string): XmlNode | undefined {\n for (const c of node.children) if (c.name === name) return c;\n return undefined;\n}\n\n/** All children matching the supplied Clark-notation name, in document order. */\nexport function findChildren(node: XmlNode, name: string): XmlNode[] {\n const out: XmlNode[] = [];\n for (const c of node.children) if (c.name === name) out.push(c);\n return out;\n}\n\n/**\n * Append `child` to `parent`. Mutates and returns `parent` for chaining during\n * construction. Avoid in hot paths — for cell writing the worksheet writer goes\n * through a templated emitter rather than building XmlNode trees per cell.\n */\nexport function appendChild(parent: XmlNode, child: XmlNode): XmlNode {\n parent.children.push(child);\n return parent;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"tree-BX-sRRVp.mjs","names":[],"sources":["../src/xml/namespaces.ts","../src/xml/tree.ts"],"sourcesContent":["// OOXML namespace and well-known package-path constants.\n//\n// Mirrors openpyxl/openpyxl/xml/constants.py so the test corpus stays directly\n// comparable. Where openpyxl exposes a single big dict (NAMESPACES) we keep\n// them as discrete `const` exports — bundlers can then drop the ones a given\n// build path never imports.\n\n// ---- W3C / Dublin Core ------------------------------------------------------\n\nexport const XML_NS = 'http://www.w3.org/XML/1998/namespace';\nexport const XSI_NS = 'http://www.w3.org/2001/XMLSchema-instance';\n\nexport const DCORE_NS = 'http://purl.org/dc/elements/1.1/';\nexport const DCTERMS_NS = 'http://purl.org/dc/terms/';\nexport const DCMITYPE_NS = 'http://purl.org/dc/dcmitype/';\nexport const DCTERMS_PREFIX = 'dcterms';\n\n// ---- ECMA-376 Office Document core ------------------------------------------\n\nconst DOC_NS = 'http://schemas.openxmlformats.org/officeDocument/2006/';\nexport const REL_NS = `${DOC_NS}relationships`;\nexport const COMMENTS_NS = `${REL_NS}/comments`;\nexport const IMAGE_NS = `${REL_NS}/image`;\nexport const VML_NS = `${REL_NS}/vmlDrawing`;\nexport const EXTERNAL_LINK_NS = `${REL_NS}/externalLink`;\nexport const VTYPES_NS = `${DOC_NS}docPropsVTypes`;\nexport const XPROPS_NS = `${DOC_NS}extended-properties`;\nexport const CUSTPROPS_NS = `${DOC_NS}custom-properties`;\nexport const CPROPS_FMTID = '{D5CDD505-2E9C-101B-9397-08002B2CF9AE}';\n\n// ---- Package layer ----------------------------------------------------------\n\nconst PKG_NS = 'http://schemas.openxmlformats.org/package/2006/';\nexport const PKG_REL_NS = `${PKG_NS}relationships`;\nexport const COREPROPS_NS = `${PKG_NS}metadata/core-properties`;\nexport const CONTYPES_NS = `${PKG_NS}content-types`;\n\n// ---- SpreadsheetML & DrawingML ----------------------------------------------\n\nexport const SHEET_MAIN_NS = 'http://schemas.openxmlformats.org/spreadsheetml/2006/main';\nexport const CHART_NS = 'http://schemas.openxmlformats.org/drawingml/2006/chart';\nexport const DRAWING_NS = 'http://schemas.openxmlformats.org/drawingml/2006/main';\nexport const SHEET_DRAWING_NS = 'http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing';\nexport const CHART_DRAWING_NS = 'http://schemas.openxmlformats.org/drawingml/2006/chartDrawing';\nexport const PICTURE_NS = 'http://schemas.openxmlformats.org/drawingml/2006/picture';\n\n// ---- Microsoft extensions ---------------------------------------------------\n\nexport const CUSTOMUI_NS = 'http://schemas.microsoft.com/office/2006/relationships/ui/extensibility';\nexport const MARKUP_COMPAT_NS = 'http://schemas.openxmlformats.org/markup-compatibility/2006';\nexport const X14_NS = 'http://schemas.microsoft.com/office/spreadsheetml/2009/9/main';\nexport const X15_NS = 'http://schemas.microsoft.com/office/spreadsheetml/2010/11/main';\n// \"Author capabilities\" — the namespace of the `<x15ac:absPath>` Excel writes\n// inside workbook.xml's `mc:Choice Requires=\"x15\"`. Only needed for its\n// canonical prefix, so it isn't exported.\nconst X15AC_NS = 'http://schemas.microsoft.com/office/spreadsheetml/2010/11/ac';\nexport const X16_NS = 'http://schemas.microsoft.com/office/spreadsheetml/2014/revision';\nexport const C14_NS = 'http://schemas.microsoft.com/office/drawing/2010/chart';\nexport const C15_NS = 'http://schemas.microsoft.com/office/drawing/2012/chart';\nexport const C16_NS = 'http://schemas.microsoft.com/office/drawing/2017/03/chart';\nexport const CX_NS = 'http://schemas.microsoft.com/office/drawing/2014/chartex';\nexport const THREADED_COMMENTS_NS = 'http://schemas.microsoft.com/office/spreadsheetml/2018/threadedcomments';\n\n// ---- Default prefix map -----------------------------------------------------\n//\n// Used when serialising XmlNode trees back to text: prefer these prefixes for\n// namespaces we recognise so output matches what Excel / openpyxl\n// conventionally emit. Entries are intentionally short — full prefix discovery\n// falls back to auto-generated names (`ns0`, `ns1`, ...) for namespaces not\n// listed here.\n\nexport const DEFAULT_PREFIXES: Readonly<Record<string, string>> = Object.freeze({\n [XML_NS]: 'xml',\n [XSI_NS]: 'xsi',\n [DCORE_NS]: 'dc',\n [DCTERMS_NS]: DCTERMS_PREFIX,\n [DCMITYPE_NS]: 'dcmitype',\n [REL_NS]: 'r',\n [VTYPES_NS]: 'vt',\n // app.xml uses XPROPS_NS as its default namespace; custom.xml uses\n // CUSTPROPS_NS the same way. Mark them as '' so serialised output matches\n // Office / openpyxl convention out of the box.\n [XPROPS_NS]: '',\n [CUSTPROPS_NS]: '',\n [PKG_REL_NS]: '',\n [COREPROPS_NS]: 'cp',\n [CONTYPES_NS]: '',\n [SHEET_MAIN_NS]: '',\n [CHART_NS]: 'c',\n [DRAWING_NS]: 'a',\n [SHEET_DRAWING_NS]: 'xdr',\n [CHART_DRAWING_NS]: 'cdr',\n [PICTURE_NS]: 'pic',\n [MARKUP_COMPAT_NS]: 'mc',\n [X14_NS]: 'x14',\n [X15_NS]: 'x15',\n [X15AC_NS]: 'x15ac',\n [X16_NS]: 'x16',\n [C14_NS]: 'c14',\n [C15_NS]: 'c15',\n [C16_NS]: 'c16',\n [CX_NS]: 'cx',\n [THREADED_COMMENTS_NS]: 'tc',\n});\n\n// ---- ZIP package paths ------------------------------------------------------\n\nexport const PACKAGE_PROPS = 'docProps';\nexport const PACKAGE_XL = 'xl';\nexport const PACKAGE_RELS = '_rels';\nexport const PACKAGE_THEME = `${PACKAGE_XL}/theme`;\nexport const PACKAGE_WORKSHEETS = `${PACKAGE_XL}/worksheets`;\nexport const PACKAGE_CHARTSHEETS = `${PACKAGE_XL}/chartsheets`;\nexport const PACKAGE_DRAWINGS = `${PACKAGE_XL}/drawings`;\nexport const PACKAGE_CHARTS = `${PACKAGE_XL}/charts`;\nexport const PACKAGE_IMAGES = `${PACKAGE_XL}/media`;\nexport const PACKAGE_PIVOT_TABLE = `${PACKAGE_XL}/pivotTables`;\nexport const PACKAGE_PIVOT_CACHE = `${PACKAGE_XL}/pivotCache`;\nexport const PACKAGE_WORKSHEET_RELS = `${PACKAGE_WORKSHEETS}/${PACKAGE_RELS}`;\nexport const PACKAGE_CHARTSHEETS_RELS = `${PACKAGE_CHARTSHEETS}/${PACKAGE_RELS}`;\n\nexport const ARC_CONTENT_TYPES = '[Content_Types].xml';\nexport const ARC_ROOT_RELS = `${PACKAGE_RELS}/.rels`;\nexport const ARC_WORKBOOK_RELS = `${PACKAGE_XL}/${PACKAGE_RELS}/workbook.xml.rels`;\nexport const ARC_CORE = `${PACKAGE_PROPS}/core.xml`;\nexport const ARC_APP = `${PACKAGE_PROPS}/app.xml`;\nexport const ARC_CUSTOM = `${PACKAGE_PROPS}/custom.xml`;\nexport const ARC_WORKBOOK = `${PACKAGE_XL}/workbook.xml`;\nexport const ARC_STYLE = `${PACKAGE_XL}/styles.xml`;\nexport const ARC_THEME = `${PACKAGE_THEME}/theme1.xml`;\nexport const ARC_SHARED_STRINGS = `${PACKAGE_XL}/sharedStrings.xml`;\nexport const ARC_CUSTOM_UI = 'customUI/customUI.xml';\n\n// ---- MIME / content-type strings -------------------------------------------\n\nconst WORKBOOK_TPL = 'application/vnd.openxmlformats-officedocument.spreadsheetml.%s.main+xml';\nconst SPREADSHEET_TPL = 'application/vnd.openxmlformats-officedocument.spreadsheetml.%s+xml';\nconst WORKBOOK_MACRO_TPL = 'application/vnd.ms-excel.%s.macroEnabled.main+xml';\nconst fmt = (tpl: string, kind: string): string => tpl.replace('%s', kind);\n\nexport const XLSX_TYPE = fmt(WORKBOOK_TPL, 'sheet');\nexport const XLTX_TYPE = fmt(WORKBOOK_TPL, 'template');\nexport const XLSM_TYPE = fmt(WORKBOOK_MACRO_TPL, 'sheet');\nexport const XLTM_TYPE = fmt(WORKBOOK_MACRO_TPL, 'template');\nexport const SHARED_STRINGS_TYPE = fmt(SPREADSHEET_TPL, 'sharedStrings');\nexport const EXTERNAL_LINK_TYPE = fmt(SPREADSHEET_TPL, 'externalLink');\nexport const WORKSHEET_TYPE = fmt(SPREADSHEET_TPL, 'worksheet');\nexport const COMMENTS_TYPE = fmt(SPREADSHEET_TPL, 'comments');\nexport const STYLES_TYPE = fmt(SPREADSHEET_TPL, 'styles');\nexport const CHARTSHEET_TYPE = fmt(SPREADSHEET_TPL, 'chartsheet');\nexport const DRAWING_TYPE = 'application/vnd.openxmlformats-officedocument.drawing+xml';\nexport const CHART_TYPE = 'application/vnd.openxmlformats-officedocument.drawingml.chart+xml';\nexport const CHARTEX_TYPE = 'application/vnd.ms-office.chartex+xml';\nexport const CHARTSHAPE_TYPE = 'application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml';\nexport const THEME_TYPE = 'application/vnd.openxmlformats-officedocument.theme+xml';\nexport const CPROPS_TYPE = 'application/vnd.openxmlformats-officedocument.custom-properties+xml';\nexport const VBA_TYPE = 'application/vnd.ms-office.vbaProject';\nexport const ACTIVEX_TYPE = 'application/vnd.ms-office.activeX+xml';\nexport const CTRLPROPS_TYPE = 'application/vnd.ms-excel.controlproperties+xml';\n\n// ---- QName helpers ----------------------------------------------------------\n\n/**\n * Build a Clark-notation QName: `{namespace}localname`. When `namespace` is\n * empty / undefined the local name is returned as-is.\n */\nexport function qname(namespace: string | undefined, local: string): string {\n return namespace ? `{${namespace}}${local}` : local;\n}\n\nconst QNAME_RE = /^\\{([^}]*)\\}(.+)$/;\n\n/**\n * Inverse of {@link qname}. Returns `{ ns, local }`. For unprefixed names `ns`\n * is the empty string.\n */\nexport function parseQName(name: string): { ns: string; local: string } {\n const m = QNAME_RE.exec(name);\n if (m === null) return { ns: '', local: name };\n return { ns: m[1] ?? '', local: m[2] ?? '' };\n}\n","// Lightweight XML tree representation used between the parser, the schema\n// layer, and the serializer.\n//\n// Plain object, no DOM, names in Clark notation `{ns}local` so namespace-aware\n// code does not depend on runtime prefix bookkeeping.\n\nimport { qname } from './namespaces.js';\n\nexport interface XmlNode {\n /** Clark-notation qualified name: `{namespace}local` or just `local`. */\n name: string;\n /** Attribute table; values are always strings (no value coercion at this layer). */\n attrs: Record<string, string>;\n /**\n * Optional element text. When an element has both text and child elements,\n * callers should set `text` and rely on `children` for mixed content; the\n * serializer emits `text` then children.\n */\n text?: string;\n /** Child element nodes in document order. */\n children: XmlNode[];\n}\n\n/**\n * Build an XmlNode from primitive bits. Attributes / children default to empty;\n * pass `undefined` for `text` to omit the text node.\n *\n * The element's name is always supplied in Clark notation. Use the {@link\n * qname} helper from `./namespaces` to keep call sites readable.\n */\nexport function el(\n name: string,\n attrs: Readonly<Record<string, string | number | boolean | null | undefined>> = {},\n children: ReadonlyArray<XmlNode> = [],\n text?: string,\n): XmlNode {\n const out: XmlNode = {\n name,\n attrs: normaliseAttrs(attrs),\n children: children.slice(),\n };\n if (text !== undefined) out.text = text;\n return out;\n}\n\nconst normaliseAttrs = (\n attrs: Readonly<Record<string, string | number | boolean | null | undefined>>,\n): Record<string, string> => {\n const out: Record<string, string> = {};\n for (const [k, v] of Object.entries(attrs)) {\n if (v === undefined || v === null) continue;\n out[k] = typeof v === 'string' ? v : String(v);\n }\n return out;\n};\n\n/**\n * Convenience: element with a Clark-notation name composed from a namespace URI\n * and local name.\n */\nexport function elNs(\n namespace: string | undefined,\n local: string,\n attrs?: Readonly<Record<string, string | number | boolean | null | undefined>>,\n children?: ReadonlyArray<XmlNode>,\n text?: string,\n): XmlNode {\n return el(qname(namespace, local), attrs, children, text);\n}\n\n/** Locate the first child matching the supplied Clark-notation name. */\nexport function findChild(node: XmlNode, name: string): XmlNode | undefined {\n for (const c of node.children) if (c.name === name) return c;\n return undefined;\n}\n\n/** All children matching the supplied Clark-notation name, in document order. */\nexport function findChildren(node: XmlNode, name: string): XmlNode[] {\n const out: XmlNode[] = [];\n for (const c of node.children) if (c.name === name) out.push(c);\n return out;\n}\n\n/**\n * Append `child` to `parent`. Mutates and returns `parent` for chaining during\n * construction. Avoid in hot paths — for cell writing the worksheet writer goes\n * through a templated emitter rather than building XmlNode trees per cell.\n */\nexport function appendChild(parent: XmlNode, child: XmlNode): XmlNode {\n parent.children.push(child);\n return parent;\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"user-shapes-DfmCGKB0.mjs","names":[],"sources":["../src/chart/chart.ts","../src/chart/user-shapes.ts"],"sourcesContent":["import type { ShapeProperties } from '../drawing/dml/shape-properties';\nimport type { TextBody } from '../drawing/dml/text';\nimport type { ChartDrawing } from './user-shapes';\n\n// ChartML data model.\n//\n// **Stage 1**: BarChart end-to-end. The full 17 SpreadsheetML chart kinds + 8\n// chartex kinds land across the upcoming iterations; this commit introduces the\n// shared shape so future kinds can plug in without breaking the public surface:\n//\n// ChartSpace\n// ├─ title?: string\n// ├─ legend?: { position: ... }\n// └─ plotArea\n// ├─ chart: BarChart | LineChart | PieChart | … (discriminated union)\n// ├─ catAx?: CategoryAxis (or Date / Series axis)\n// └─ valAx?: ValueAxis\n//\n// References to worksheet ranges (`Sheet1!$A$1:$A$5`) are kept as strings; the\n// optional `cache` field carries the last-known data so charts can be rendered\n// without reading the source data.\n\nexport type LegendPosition = 'r' | 't' | 'l' | 'b' | 'tr';\nexport type GroupingType = 'clustered' | 'stacked' | 'percentStacked' | 'standard';\nexport type BarDirection = 'bar' | 'col';\n\n/** Reference to a worksheet range plus an optional client-side cache of the resolved values. */\nexport interface NumericRef {\n /** Worksheet-qualified range string, e.g. `Sheet1!$B$1:$B$5`. */\n ref: string;\n /** Optional cached numeric values — Excel writes these for offline rendering. */\n cache?: number[];\n /** Optional `formatCode` Excel uses when rendering each cached value. */\n formatCode?: string;\n}\n\nexport interface CategoryRef {\n ref: string;\n /** Whether the cache is numeric or string. */\n cacheKind?: 'num' | 'str';\n /** String values (when `cacheKind === 'str'`) or numeric values. */\n cache?: ReadonlyArray<string | number>;\n formatCode?: string;\n}\n\n// ---- Series decorations: data labels, trendlines, error bars --------------\n\n/**\n * Number-format payload for chart axes / data labels (`<c:numFmt formatCode=\"…\"\n * sourceLinked=\"0|1\"/>`).\n *\n * Named `ChartNumberFormat` to avoid colliding with the cell-stylesheet\n * `NumberFormat` exported from `@office-kit/xlsx/styles`, which is a different shape\n * (`{ numFmtId, formatCode }`).\n */\nexport interface ChartNumberFormat {\n formatCode: string;\n sourceLinked?: boolean;\n}\n\nexport type DataLabelPosition = 'bestFit' | 'b' | 'ctr' | 'inBase' | 'inEnd' | 'l' | 'outEnd' | 'r' | 't';\n\n/** Per-point data label override. Lives inside `<c:dLbls><c:dLbl idx=\"N\">…</c:dLbl></c:dLbls>`. */\nexport interface DataLabel {\n idx: number;\n /** Delete this individual label (suppresses display even if the parent dLbls would show it). */\n delete?: boolean;\n /** Inline rich text or a cell reference. Mutually exclusive. */\n tx?: { kind: 'rich'; body: TextBody } | { kind: 'strRef'; ref: string };\n numFmt?: ChartNumberFormat;\n spPr?: ShapeProperties;\n txPr?: TextBody;\n dLblPos?: DataLabelPosition;\n showLegendKey?: boolean;\n showVal?: boolean;\n showCatName?: boolean;\n showSerName?: boolean;\n showPercent?: boolean;\n showBubbleSize?: boolean;\n separator?: string;\n}\n\n/** Series-wide data label settings. `<c:dLbls>` element. */\nexport interface DataLabelList {\n /** When true, suppress all labels (`<c:delete val=\"1\"/>`). */\n delete?: boolean;\n /** Per-point overrides. */\n dLbl?: DataLabel[];\n numFmt?: ChartNumberFormat;\n spPr?: ShapeProperties;\n txPr?: TextBody;\n dLblPos?: DataLabelPosition;\n showLegendKey?: boolean;\n showVal?: boolean;\n showCatName?: boolean;\n showSerName?: boolean;\n showPercent?: boolean;\n showBubbleSize?: boolean;\n separator?: string;\n showLeaderLines?: boolean;\n}\n\nexport type MarkerSymbol =\n | 'auto'\n | 'circle'\n | 'dash'\n | 'diamond'\n | 'dot'\n | 'none'\n | 'picture'\n | 'plus'\n | 'square'\n | 'star'\n | 'triangle'\n | 'x';\n\n/** Data-point marker on line / scatter / radar series (`<c:marker>` child of `<c:ser>`). */\nexport interface Marker {\n symbol?: MarkerSymbol;\n /** Marker size in points (2..72). */\n size?: number;\n spPr?: ShapeProperties;\n}\n\n/**\n * Per-point override on a series (`<c:dPt>` child of `<c:ser>`). Lets each bar\n * / slice / data point pick up its own colour, marker, explosion, etc.\n */\nexport interface DataPoint {\n /** 0-based index of the data point within the series. */\n idx: number;\n /** Invert fill when the data point's value is negative (bar / area / bubble). */\n invertIfNegative?: boolean;\n /** Per-point marker override (line / scatter / radar). */\n marker?: Marker;\n /** 3-D bubble flag (bubble series only). */\n bubble3D?: boolean;\n /** Slice explosion in % for pie / doughnut points (0..400). */\n explosion?: number;\n /** Per-point shape properties (fill / line colour). */\n spPr?: ShapeProperties;\n}\n\nexport type TrendlineType = 'exp' | 'linear' | 'log' | 'movingAvg' | 'poly' | 'power';\n\nexport interface Trendline {\n /** Display name shown in the chart legend (`<c:name>` text). */\n name?: string;\n spPr?: ShapeProperties;\n trendlineType: TrendlineType;\n /** Polynomial order (2..6) when `trendlineType === 'poly'`. */\n order?: number;\n /** Moving-average period when `trendlineType === 'movingAvg'`. */\n period?: number;\n /** Forecast forward periods. */\n forward?: number;\n /** Forecast backward periods. */\n backward?: number;\n /** Y-axis intercept (linear only). */\n intercept?: number;\n /** Display R² value on the chart. */\n dispRSqr?: boolean;\n /** Display the trendline equation. */\n dispEq?: boolean;\n}\n\nexport type ErrorBarDirection = 'x' | 'y';\nexport type ErrorBarType = 'both' | 'minus' | 'plus';\nexport type ErrorValType = 'cust' | 'fixedVal' | 'percentage' | 'stdDev' | 'stdErr';\n\nexport interface ErrorBars {\n /** Direction. Required only on scatter / bubble series; bar / line / area imply `'y'`. */\n errDir?: ErrorBarDirection;\n errBarType: ErrorBarType;\n errValType: ErrorValType;\n noEndCap?: boolean;\n /** Numeric magnitude for fixedVal / percentage / stdDev / stdErr. */\n val?: number;\n /** Custom plus-side data (NumericRef) — required when `errValType === 'cust'`. */\n plus?: NumericRef;\n /** Custom minus-side data (NumericRef) — required when `errValType === 'cust'`. */\n minus?: NumericRef;\n spPr?: ShapeProperties;\n}\n\nexport interface BarSeries {\n /** 0-based slot in the chart (`<c:idx>`). */\n idx: number;\n /** Render order (`<c:order>`). Usually equals `idx`. */\n order: number;\n /** Series title — either a static string or a cell reference. */\n tx?: { kind: 'literal'; value: string } | { kind: 'ref'; ref: string };\n /** Per-series shape properties (fill / line / effects). */\n spPr?: ShapeProperties;\n /** Invert fill on negative values (bar / line / area series). */\n invertIfNegative?: boolean;\n /**\n * Slice explosion in % (pie / doughnut series only; 0..400). Bar / line / area writers\n * ignore the field — leave it unset for those series.\n */\n explosion?: number;\n /** Per-point overrides. Empty / omitted means every point inherits the series defaults. */\n dPt?: DataPoint[];\n /** Series-wide data labels. */\n dLbls?: DataLabelList;\n /** Trendlines attached to this series. */\n trendline?: Trendline[];\n /** Error bars. Bar / line / area / radar default to a single y-direction entry. */\n errBars?: ErrorBars[];\n /** Categories. */\n cat?: CategoryRef;\n /** Values (always required for a bar series). */\n val: NumericRef;\n}\n\nexport interface BarChart {\n kind: 'bar';\n /** `bar` for horizontal bars, `col` for vertical columns. */\n barDir: BarDirection;\n /** Excel default is `clustered`. */\n grouping: GroupingType;\n varyColors?: boolean;\n series: BarSeries[];\n /** Bar gap width in % of bar width (Excel default 150). */\n gapWidth?: number;\n /**\n * Bar overlap in -100..100 % of bar width. Positive values overlap clustered bars; negative values\n * space them apart. For stacked / percentStacked grouping, omit and the serializer emits the\n * standard Excel default of 100 (flush stacking).\n */\n overlap?: number;\n /** Internal axis ids. The category and value axes carry the same numbers. */\n axIds: [number, number];\n}\n\nexport interface LineSeries extends BarSeries {\n /** Per-series smoothing toggle. */\n smooth?: boolean;\n /** Data-point marker (`<c:marker>` child of `<c:ser>`). */\n marker?: Marker;\n}\n\nexport interface LineChart {\n kind: 'line';\n grouping: GroupingType;\n varyColors?: boolean;\n series: LineSeries[];\n /** Whether to round corners between data points (chart-level default). */\n smooth?: boolean;\n axIds: [number, number];\n}\n\nexport interface AreaChart {\n kind: 'area';\n grouping: GroupingType;\n varyColors?: boolean;\n series: BarSeries[];\n axIds: [number, number];\n}\n\nexport interface PieChart {\n kind: 'pie';\n varyColors?: boolean;\n /** Pie / Doughnut have a single ring of slices — but Excel allows multiple series; we mirror that. */\n series: BarSeries[];\n}\n\nexport interface DoughnutChart {\n kind: 'doughnut';\n varyColors?: boolean;\n series: BarSeries[];\n /** Hole size in % of outer radius (10..90, Excel default 50). */\n holeSize?: number;\n /** First-slice rotation angle in degrees. */\n firstSliceAng?: number;\n}\n\nexport type ScatterStyle = 'line' | 'lineMarker' | 'marker' | 'none' | 'smooth' | 'smoothMarker';\n\nexport interface ScatterSeries {\n idx: number;\n order: number;\n tx?: BarSeries['tx'];\n spPr?: ShapeProperties;\n dPt?: DataPoint[];\n dLbls?: DataLabelList;\n trendline?: Trendline[];\n /** Up to 2 entries (one per direction). */\n errBars?: ErrorBars[];\n /** Data-point marker. */\n marker?: Marker;\n xVal?: NumericRef;\n yVal: NumericRef;\n smooth?: boolean;\n}\n\nexport interface ScatterChart {\n kind: 'scatter';\n scatterStyle: ScatterStyle;\n varyColors?: boolean;\n series: ScatterSeries[];\n axIds: [number, number];\n}\n\nexport type RadarStyle = 'standard' | 'marker' | 'filled';\n\nexport interface RadarChart {\n kind: 'radar';\n radarStyle: RadarStyle;\n varyColors?: boolean;\n series: BarSeries[];\n axIds: [number, number];\n}\n\nexport interface BubbleSeries {\n idx: number;\n order: number;\n tx?: BarSeries['tx'];\n spPr?: ShapeProperties;\n invertIfNegative?: boolean;\n dPt?: DataPoint[];\n dLbls?: DataLabelList;\n trendline?: Trendline[];\n /** Up to 2 entries (one per direction). */\n errBars?: ErrorBars[];\n xVal?: NumericRef;\n yVal: NumericRef;\n /** Bubble size — required for a real bubble chart. */\n bubbleSize: NumericRef;\n /** Per-series 3-D toggle. */\n bubble3D?: boolean;\n}\n\nexport type BubbleSizeRepresents = 'area' | 'w';\n\nexport interface BubbleChart {\n kind: 'bubble';\n varyColors?: boolean;\n series: BubbleSeries[];\n bubble3D?: boolean;\n /** Bubble scale 0..300 %. Excel default is 100. */\n bubbleScale?: number;\n showNegBubbles?: boolean;\n sizeRepresents?: BubbleSizeRepresents;\n axIds: [number, number];\n}\n\n/** `<c:hiLowLines>` child of stock charts. */\nexport interface HiLowLines {\n spPr?: ShapeProperties;\n}\n\n/** `<c:upBars>` / `<c:downBars>` child frame styling. */\nexport interface BarFrame {\n spPr?: ShapeProperties;\n}\n\n/** `<c:upDownBars>` child of stock charts. */\nexport interface UpDownBars {\n /** Gap width 0..500 between up/down bars. Excel default is 150. */\n gapWidth?: number;\n upBars?: BarFrame;\n downBars?: BarFrame;\n}\n\nexport interface StockChart {\n kind: 'stock';\n /** Up to 4 series — typically open / high / low / close. */\n series: BarSeries[];\n /** Boolean flag for the simple `<c:hiLowLines/>` form, or an object with `spPr` for custom line styling. */\n hiLowLines?: boolean | HiLowLines;\n /** Boolean for the simple form, or an object with gapWidth / upBars / downBars detail. */\n upDownBars?: boolean | UpDownBars;\n axIds: [number, number];\n}\n\nexport interface SurfaceChart {\n kind: 'surface';\n series: BarSeries[];\n /** Wireframe (line-only) when true; smoothed surface fill when false. */\n wireframe?: boolean;\n /** Surfaces use 3 axes: cat + val + ser. */\n axIds: [number, number, number];\n}\n\nexport type OfPieType = 'bar' | 'pie';\nexport type SplitType = 'auto' | 'cust' | 'percent' | 'pos' | 'val';\n\nexport interface OfPieChart {\n kind: 'ofPie';\n /** `bar` for \"Bar of Pie\", `pie` for \"Pie of Pie\". */\n ofPieType: OfPieType;\n varyColors?: boolean;\n series: BarSeries[];\n gapWidth?: number;\n splitType?: SplitType;\n /** Position threshold paired with `splitType='pos'`. */\n splitPos?: number;\n /** Indices of data points moved to the secondary plot when `splitType='cust'`. */\n custSplit?: number[];\n /** Secondary plot size as % of primary (5..200). */\n secondPieSize?: number;\n}\n\n// ---- 3-D chart variants ---------------------------------------------------\n//\n// 3-D charts share most of their attributes with their 2-D counterparts but\n// land on different XML tag names (<c:bar3DChart>, etc) and use 3 axes (cat /\n// val / ser). We keep them as distinct discriminated-union variants so the\n// chart kind stays type-narrowable.\n\nexport interface Bar3DChart {\n kind: 'bar3D';\n barDir: BarDirection;\n grouping: GroupingType;\n varyColors?: boolean;\n series: BarSeries[];\n gapWidth?: number;\n /** Bar 3-D adds a `gapDepth` attribute. */\n gapDepth?: number;\n /** Cluster | percentStacked | stacked … plus 'standard' which 2-D doesn't take. */\n shape?: 'cone' | 'coneToMax' | 'box' | 'cylinder' | 'pyramid' | 'pyramidToMax';\n axIds: [number, number, number];\n}\n\nexport interface Line3DChart {\n kind: 'line3D';\n grouping: GroupingType;\n varyColors?: boolean;\n series: LineSeries[];\n gapDepth?: number;\n axIds: [number, number, number];\n}\n\nexport interface Pie3DChart {\n kind: 'pie3D';\n varyColors?: boolean;\n series: BarSeries[];\n}\n\nexport interface Area3DChart {\n kind: 'area3D';\n grouping: GroupingType;\n varyColors?: boolean;\n series: BarSeries[];\n gapDepth?: number;\n axIds: [number, number, number];\n}\n\nexport interface Surface3DChart {\n kind: 'surface3D';\n series: BarSeries[];\n wireframe?: boolean;\n axIds: [number, number, number];\n}\n\n/** Discriminator union of all SpreadsheetML chart kinds modelled so far. */\nexport type ChartKind =\n | BarChart\n | LineChart\n | AreaChart\n | PieChart\n | DoughnutChart\n | ScatterChart\n | RadarChart\n | BubbleChart\n | StockChart\n | SurfaceChart\n | OfPieChart\n | Bar3DChart\n | Line3DChart\n | Pie3DChart\n | Area3DChart\n | Surface3DChart;\n\nexport type TickMark = 'cross' | 'in' | 'none' | 'out';\nexport type TickLabelPosition = 'high' | 'low' | 'nextTo' | 'none';\nexport type AxisCrosses = 'autoZero' | 'max' | 'min';\nexport type AxisOrientation = 'maxMin' | 'minMax';\nexport type AxisCrossBetween = 'between' | 'midCat';\nexport type CategoryLabelAlignment = 'ctr' | 'l' | 'r';\n\n/** `<c:scaling>` child of axes. */\nexport interface AxisScaling {\n orientation?: AxisOrientation;\n min?: number;\n max?: number;\n logBase?: number;\n}\n\ninterface AxisShared {\n axId: number;\n /** Crosses partner axis id. */\n crossAx: number;\n position?: 'b' | 't' | 'l' | 'r';\n delete?: boolean;\n /** Axis-line / tick formatting. */\n spPr?: ShapeProperties;\n /** Tick-label text formatting. */\n txPr?: TextBody;\n /** Axis title (`<c:title>`). Reuses the chart-title structure. */\n title?: ChartTitle;\n /** Tick-label number format. Default emitted is `General` / `sourceLinked=1`. */\n numFmt?: ChartNumberFormat;\n /** Major tick mark style. Default emitted is `out`. */\n majorTickMark?: TickMark;\n /** Minor tick mark style. Default emitted is `none`. */\n minorTickMark?: TickMark;\n /** Tick-label position. Default emitted is `nextTo`. */\n tickLblPos?: TickLabelPosition;\n /** Axis scaling (`<c:scaling>`). Default emitted is `orientation: 'minMax'`. */\n scaling?: AxisScaling;\n /** `<c:crosses>`. Default emitted is `autoZero`. Mutually exclusive with `crossesAt`. */\n crosses?: AxisCrosses;\n /** `<c:crossesAt val=\"...\"/>`. Numeric cross point on the partner axis. */\n crossesAt?: number;\n /**\n * Major gridlines. `true` keeps Excel's default rendering; pass\n * `{ spPr }` to override the line colour / width / dash. `false` /\n * `undefined` omit the element entirely.\n */\n majorGridlines?: boolean | Gridlines;\n /** Minor gridlines. Same shape as {@link AxisShared.majorGridlines}. */\n minorGridlines?: boolean | Gridlines;\n}\n\n/**\n * Rich `<c:majorGridlines>` / `<c:minorGridlines>` form. Wraps a\n * `ShapeProperties` so the gridline line can be styled (e.g. corporate-style\n * light-grey `D9D9D9`).\n */\nexport interface Gridlines {\n spPr?: ShapeProperties;\n}\n\nexport interface CategoryAxis extends AxisShared {\n /** `<c:auto>` — whether Excel auto-selects the axis type from the data. */\n auto?: boolean;\n /** Tick-label alignment. Default emitted is `ctr`. */\n lblAlgn?: CategoryLabelAlignment;\n /** Tick-label offset 0..1000. Default emitted is `100`. */\n lblOffset?: number;\n /** Suppress multi-level labels for hierarchical categories. */\n noMultiLvlLbl?: boolean;\n}\n\nexport interface ValueAxis extends AxisShared {\n /** Tick-axis crossing rule. Default emitted is `between`. */\n crossBetween?: AxisCrossBetween;\n /** Major unit spacing on the value axis. */\n majorUnit?: number;\n /** Minor unit spacing on the value axis. */\n minorUnit?: number;\n}\n\nexport type TimeUnit = 'days' | 'months' | 'years';\n\nexport interface DateAxis extends AxisShared {\n /** `<c:auto>` — auto-select axis type. */\n auto?: boolean;\n /** Tick-label offset 0..1000. Default emitted is `100`. */\n lblOffset?: number;\n /** Smallest interval the axis represents. */\n baseTimeUnit?: TimeUnit;\n /** Major unit spacing on the date axis (count of `majorTimeUnit`s). */\n majorUnit?: number;\n majorTimeUnit?: TimeUnit;\n /** Minor unit spacing on the date axis. */\n minorUnit?: number;\n minorTimeUnit?: TimeUnit;\n}\n\nexport interface SeriesAxis extends AxisShared {\n /** Skip every Nth tick label (1 = every label). */\n tickLblSkip?: number;\n /** Skip every Nth tick mark. */\n tickMarkSkip?: number;\n}\n\nexport interface PlotArea {\n chart: ChartKind;\n catAx?: CategoryAxis;\n valAx?: ValueAxis;\n /** Date / time axis. Replaces `catAx` when the categories are dates. */\n dateAx?: DateAxis;\n /** Series axis (used by `surface3DChart` / `surfaceChart`). */\n serAx?: SeriesAxis;\n /** Manual layout for the plot area inside the chart. */\n layout?: Layout;\n /** Plot-area shape properties (background fill, border line). */\n spPr?: ShapeProperties;\n}\n\nexport type LayoutMode = 'edge' | 'factor';\nexport type LayoutTarget = 'inner' | 'outer';\n\n/** `<c:manualLayout>` child of `<c:layout>`. All values are fractions of the chart space (0..1). */\nexport interface ManualLayout {\n layoutTarget?: LayoutTarget;\n xMode?: LayoutMode;\n yMode?: LayoutMode;\n wMode?: LayoutMode;\n hMode?: LayoutMode;\n x?: number;\n y?: number;\n w?: number;\n h?: number;\n}\n\n/** `<c:layout>` wrapper. Currently only `manualLayout` is exposed; the lone `<layoutId>` form is for chartex. */\nexport interface Layout {\n manualLayout?: ManualLayout;\n}\n\nexport interface Legend {\n position: LegendPosition;\n overlay?: boolean;\n layout?: Layout;\n spPr?: ShapeProperties;\n txPr?: TextBody;\n}\n\n/** Chart title with full DrawingML formatting support. */\nexport interface ChartTitle {\n /**\n * Plain title text. When set the serializer emits\n * `<c:tx><c:rich><a:p><a:r><a:t>text</a:t></a:r></c:rich></c:tx>`. Mutually\n * exclusive with `tx`.\n */\n text?: string;\n /** Rich text body — overrides `text` when both are present. */\n tx?: TextBody;\n overlay?: boolean;\n layout?: Layout;\n spPr?: ShapeProperties;\n txPr?: TextBody;\n}\n\n/** 3-D viewing options. Used by `bar3DChart`, `line3DChart`, `pie3DChart`, `area3DChart`, `surface3DChart`. */\nexport interface View3D {\n /** X-axis rotation in degrees, -90..90. */\n rotX?: number;\n /** Y-axis rotation in degrees, 0..359. */\n rotY?: number;\n /** Depth as a percentage of chart width, 20..2000. */\n depthPercent?: number;\n /** Height as a percentage of chart width, 5..500. */\n hPercent?: number;\n /** Use right-angle axes (orthographic). When true, perspective is ignored. */\n rAngAx?: boolean;\n /** Perspective angle 0..240 (0 = isometric, 30 = Excel default). */\n perspective?: number;\n}\n\n/** 3-D wall / floor frame. Children of `<c:chart>` for bar3D / line3D / area3D / surface3D / pie3D. */\nexport interface SurfaceFrame {\n /** Wall thickness in % of chart width (0..100). */\n thickness?: number;\n spPr?: ShapeProperties;\n}\n\nexport interface ChartSpace {\n /** Optional chart title. */\n title?: ChartTitle;\n legend?: Legend;\n plotArea: PlotArea;\n /**\n * Built-in Excel chart-style preset (1..48). Mapped to `<c:style val=\"N\"/>` inside\n * `<c:chartSpace>` and selects one entry of Excel's \"Chart Styles\" gallery.\n */\n style?: number;\n /** 3-D viewing options (applies to 3-D chart kinds; ignored otherwise by Excel). */\n view3D?: View3D;\n /** 3-D chart floor frame. */\n floor?: SurfaceFrame;\n /** 3-D chart side wall frame. */\n sideWall?: SurfaceFrame;\n /** 3-D chart back wall frame. */\n backWall?: SurfaceFrame;\n /** Honour the formatting hints in cached numeric data when rendering. */\n plotVisOnly?: boolean;\n /** Display blanks as gap, zero, or span — Excel default is `gap`. */\n dispBlanksAs?: 'gap' | 'zero' | 'span';\n /** Chart-space level shape properties (overall frame). */\n spPr?: ShapeProperties;\n /** Chart-space level default text properties. */\n txPr?: TextBody;\n /** Annotations / text boxes / arrows drawn over the chart. Serialised as `xl/drawings/chartDrawingN.xml`. */\n userShapes?: ChartDrawing;\n}\n\nexport function makeBarChart(opts: {\n barDir?: BarDirection;\n grouping?: GroupingType;\n series?: BarSeries[];\n axIds?: [number, number];\n varyColors?: boolean;\n gapWidth?: number;\n overlap?: number;\n}): BarChart {\n return {\n kind: 'bar',\n barDir: opts.barDir ?? 'col',\n grouping: opts.grouping ?? 'clustered',\n series: opts.series ?? [],\n axIds: opts.axIds ?? [1, 2],\n ...(opts.varyColors !== undefined ? { varyColors: opts.varyColors } : {}),\n ...(opts.gapWidth !== undefined ? { gapWidth: opts.gapWidth } : {}),\n ...(opts.overlap !== undefined ? { overlap: opts.overlap } : {}),\n };\n}\n\nexport function makeBarSeries(opts: {\n idx: number;\n order?: number;\n val: NumericRef;\n cat?: CategoryRef;\n tx?: BarSeries['tx'];\n}): BarSeries {\n return {\n idx: opts.idx,\n order: opts.order ?? opts.idx,\n val: opts.val,\n ...(opts.cat ? { cat: opts.cat } : {}),\n ...(opts.tx ? { tx: opts.tx } : {}),\n };\n}\n\nexport function makeChartSpace(opts: {\n plotArea: PlotArea;\n /** Plain string is wrapped in `{ text }`; pass `ChartTitle` for full formatting. */\n title?: string | ChartTitle;\n legend?: Legend;\n style?: number;\n view3D?: View3D;\n floor?: SurfaceFrame;\n sideWall?: SurfaceFrame;\n backWall?: SurfaceFrame;\n plotVisOnly?: boolean;\n dispBlanksAs?: ChartSpace['dispBlanksAs'];\n spPr?: ShapeProperties;\n txPr?: TextBody;\n}): ChartSpace {\n const title: ChartTitle | undefined = typeof opts.title === 'string' ? { text: opts.title } : opts.title;\n return {\n plotArea: opts.plotArea,\n ...(title !== undefined ? { title } : {}),\n ...(opts.legend ? { legend: opts.legend } : {}),\n ...(opts.style !== undefined ? { style: opts.style } : {}),\n ...(opts.view3D ? { view3D: opts.view3D } : {}),\n ...(opts.floor ? { floor: opts.floor } : {}),\n ...(opts.sideWall ? { sideWall: opts.sideWall } : {}),\n ...(opts.backWall ? { backWall: opts.backWall } : {}),\n ...(opts.plotVisOnly !== undefined ? { plotVisOnly: opts.plotVisOnly } : {}),\n ...(opts.dispBlanksAs !== undefined ? { dispBlanksAs: opts.dispBlanksAs } : {}),\n ...(opts.spPr ? { spPr: opts.spPr } : {}),\n ...(opts.txPr ? { txPr: opts.txPr } : {}),\n };\n}\n\nexport function makeLineChart(opts: {\n grouping?: GroupingType;\n series?: LineSeries[];\n axIds?: [number, number];\n varyColors?: boolean;\n smooth?: boolean;\n}): LineChart {\n return {\n kind: 'line',\n grouping: opts.grouping ?? 'standard',\n series: opts.series ?? [],\n axIds: opts.axIds ?? [1, 2],\n ...(opts.varyColors !== undefined ? { varyColors: opts.varyColors } : {}),\n ...(opts.smooth !== undefined ? { smooth: opts.smooth } : {}),\n };\n}\n\nexport function makeAreaChart(opts: {\n grouping?: GroupingType;\n series?: BarSeries[];\n axIds?: [number, number];\n varyColors?: boolean;\n}): AreaChart {\n return {\n kind: 'area',\n grouping: opts.grouping ?? 'standard',\n series: opts.series ?? [],\n axIds: opts.axIds ?? [1, 2],\n ...(opts.varyColors !== undefined ? { varyColors: opts.varyColors } : {}),\n };\n}\n\nexport function makePieChart(opts: { series?: BarSeries[]; varyColors?: boolean }): PieChart {\n return {\n kind: 'pie',\n series: opts.series ?? [],\n ...(opts.varyColors !== undefined ? { varyColors: opts.varyColors } : {}),\n };\n}\n\nexport function makeDoughnutChart(opts: {\n series?: BarSeries[];\n varyColors?: boolean;\n holeSize?: number;\n firstSliceAng?: number;\n}): DoughnutChart {\n return {\n kind: 'doughnut',\n series: opts.series ?? [],\n ...(opts.varyColors !== undefined ? { varyColors: opts.varyColors } : {}),\n ...(opts.holeSize !== undefined ? { holeSize: opts.holeSize } : {}),\n ...(opts.firstSliceAng !== undefined ? { firstSliceAng: opts.firstSliceAng } : {}),\n };\n}\n\nexport function makeScatterChart(opts: {\n scatterStyle?: ScatterStyle;\n series?: ScatterSeries[];\n axIds?: [number, number];\n varyColors?: boolean;\n}): ScatterChart {\n return {\n kind: 'scatter',\n scatterStyle: opts.scatterStyle ?? 'lineMarker',\n series: opts.series ?? [],\n axIds: opts.axIds ?? [1, 2],\n ...(opts.varyColors !== undefined ? { varyColors: opts.varyColors } : {}),\n };\n}\n\nexport function makeScatterSeries(opts: {\n idx: number;\n order?: number;\n tx?: BarSeries['tx'];\n xVal?: NumericRef;\n yVal: NumericRef;\n smooth?: boolean;\n marker?: Marker;\n}): ScatterSeries {\n return {\n idx: opts.idx,\n order: opts.order ?? opts.idx,\n yVal: opts.yVal,\n ...(opts.tx ? { tx: opts.tx } : {}),\n ...(opts.xVal ? { xVal: opts.xVal } : {}),\n ...(opts.smooth !== undefined ? { smooth: opts.smooth } : {}),\n ...(opts.marker ? { marker: opts.marker } : {}),\n };\n}\n\nexport function makeRadarChart(opts: {\n radarStyle?: RadarStyle;\n series?: BarSeries[];\n axIds?: [number, number];\n varyColors?: boolean;\n}): RadarChart {\n return {\n kind: 'radar',\n radarStyle: opts.radarStyle ?? 'standard',\n series: opts.series ?? [],\n axIds: opts.axIds ?? [1, 2],\n ...(opts.varyColors !== undefined ? { varyColors: opts.varyColors } : {}),\n };\n}\n\nexport function makeBubbleChart(opts: {\n series?: BubbleSeries[];\n axIds?: [number, number];\n varyColors?: boolean;\n bubble3D?: boolean;\n bubbleScale?: number;\n showNegBubbles?: boolean;\n sizeRepresents?: BubbleSizeRepresents;\n}): BubbleChart {\n return {\n kind: 'bubble',\n series: opts.series ?? [],\n axIds: opts.axIds ?? [1, 2],\n ...(opts.varyColors !== undefined ? { varyColors: opts.varyColors } : {}),\n ...(opts.bubble3D !== undefined ? { bubble3D: opts.bubble3D } : {}),\n ...(opts.bubbleScale !== undefined ? { bubbleScale: opts.bubbleScale } : {}),\n ...(opts.showNegBubbles !== undefined ? { showNegBubbles: opts.showNegBubbles } : {}),\n ...(opts.sizeRepresents !== undefined ? { sizeRepresents: opts.sizeRepresents } : {}),\n };\n}\n\nexport function makeBubbleSeries(opts: {\n idx: number;\n order?: number;\n tx?: BarSeries['tx'];\n xVal?: NumericRef;\n yVal: NumericRef;\n bubbleSize: NumericRef;\n bubble3D?: boolean;\n}): BubbleSeries {\n return {\n idx: opts.idx,\n order: opts.order ?? opts.idx,\n yVal: opts.yVal,\n bubbleSize: opts.bubbleSize,\n ...(opts.tx ? { tx: opts.tx } : {}),\n ...(opts.xVal ? { xVal: opts.xVal } : {}),\n ...(opts.bubble3D !== undefined ? { bubble3D: opts.bubble3D } : {}),\n };\n}\n\nexport function makeStockChart(opts: {\n series?: BarSeries[];\n axIds?: [number, number];\n hiLowLines?: boolean | HiLowLines;\n upDownBars?: boolean | UpDownBars;\n}): StockChart {\n return {\n kind: 'stock',\n series: opts.series ?? [],\n axIds: opts.axIds ?? [1, 2],\n ...(opts.hiLowLines !== undefined ? { hiLowLines: opts.hiLowLines } : {}),\n ...(opts.upDownBars !== undefined ? { upDownBars: opts.upDownBars } : {}),\n };\n}\n\nexport function makeSurfaceChart(opts: {\n series?: BarSeries[];\n wireframe?: boolean;\n axIds?: [number, number, number];\n}): SurfaceChart {\n return {\n kind: 'surface',\n series: opts.series ?? [],\n axIds: opts.axIds ?? [1, 2, 3],\n ...(opts.wireframe !== undefined ? { wireframe: opts.wireframe } : {}),\n };\n}\n\nexport function makeOfPieChart(opts: {\n ofPieType?: OfPieType;\n series?: BarSeries[];\n varyColors?: boolean;\n gapWidth?: number;\n splitType?: SplitType;\n splitPos?: number;\n custSplit?: number[];\n secondPieSize?: number;\n}): OfPieChart {\n return {\n kind: 'ofPie',\n ofPieType: opts.ofPieType ?? 'pie',\n series: opts.series ?? [],\n ...(opts.varyColors !== undefined ? { varyColors: opts.varyColors } : {}),\n ...(opts.gapWidth !== undefined ? { gapWidth: opts.gapWidth } : {}),\n ...(opts.splitType !== undefined ? { splitType: opts.splitType } : {}),\n ...(opts.splitPos !== undefined ? { splitPos: opts.splitPos } : {}),\n ...(opts.custSplit ? { custSplit: opts.custSplit } : {}),\n ...(opts.secondPieSize !== undefined ? { secondPieSize: opts.secondPieSize } : {}),\n };\n}\n\nexport function makeBar3DChart(opts: {\n barDir?: BarDirection;\n grouping?: GroupingType;\n series?: BarSeries[];\n axIds?: [number, number, number];\n varyColors?: boolean;\n gapWidth?: number;\n gapDepth?: number;\n shape?: Bar3DChart['shape'];\n}): Bar3DChart {\n return {\n kind: 'bar3D',\n barDir: opts.barDir ?? 'col',\n grouping: opts.grouping ?? 'clustered',\n series: opts.series ?? [],\n axIds: opts.axIds ?? [1, 2, 3],\n ...(opts.varyColors !== undefined ? { varyColors: opts.varyColors } : {}),\n ...(opts.gapWidth !== undefined ? { gapWidth: opts.gapWidth } : {}),\n ...(opts.gapDepth !== undefined ? { gapDepth: opts.gapDepth } : {}),\n ...(opts.shape !== undefined ? { shape: opts.shape } : {}),\n };\n}\n\nexport function makeLine3DChart(opts: {\n grouping?: GroupingType;\n series?: LineSeries[];\n axIds?: [number, number, number];\n varyColors?: boolean;\n gapDepth?: number;\n}): Line3DChart {\n return {\n kind: 'line3D',\n grouping: opts.grouping ?? 'standard',\n series: opts.series ?? [],\n axIds: opts.axIds ?? [1, 2, 3],\n ...(opts.varyColors !== undefined ? { varyColors: opts.varyColors } : {}),\n ...(opts.gapDepth !== undefined ? { gapDepth: opts.gapDepth } : {}),\n };\n}\n\nexport function makePie3DChart(opts: { series?: BarSeries[]; varyColors?: boolean }): Pie3DChart {\n return {\n kind: 'pie3D',\n series: opts.series ?? [],\n ...(opts.varyColors !== undefined ? { varyColors: opts.varyColors } : {}),\n };\n}\n\nexport function makeArea3DChart(opts: {\n grouping?: GroupingType;\n series?: BarSeries[];\n axIds?: [number, number, number];\n varyColors?: boolean;\n gapDepth?: number;\n}): Area3DChart {\n return {\n kind: 'area3D',\n grouping: opts.grouping ?? 'standard',\n series: opts.series ?? [],\n axIds: opts.axIds ?? [1, 2, 3],\n ...(opts.varyColors !== undefined ? { varyColors: opts.varyColors } : {}),\n ...(opts.gapDepth !== undefined ? { gapDepth: opts.gapDepth } : {}),\n };\n}\n\nexport function makeSurface3DChart(opts: {\n series?: BarSeries[];\n wireframe?: boolean;\n axIds?: [number, number, number];\n}): Surface3DChart {\n return {\n kind: 'surface3D',\n series: opts.series ?? [],\n axIds: opts.axIds ?? [1, 2, 3],\n ...(opts.wireframe !== undefined ? { wireframe: opts.wireframe } : {}),\n };\n}\n","// User shapes (chartDrawing) — annotations on a chart.\n//\n// `xl/drawings/chartDrawingN.xml` is referenced from a `<c:chartSpace>` via\n// `<c:userShapes r:id=\"...\">`. It contains text boxes, arrows, and other shapes\n// positioned either relatively (0..1 of chart width / height) or absolutely\n// (relative anchor + EMU extent).\n\nimport type { ShapeProperties, PositiveSize2D } from '../drawing/dml/shape-properties';\nimport type { TextBody } from '../drawing/dml/text';\n\n/** `<cdr:from>` / `<cdr:to>` marker. Decimal in 0..1. */\nexport interface ChartRelativeMarker {\n x: number;\n y: number;\n}\n\n/** `<cdr:sp>` shape leaf (text box / arrow / preset shape with optional text). */\nexport interface ChartDrawingShape {\n /** cNvPr id (1-based, unique per chartDrawing). */\n id: number;\n name?: string;\n descr?: string;\n hidden?: boolean;\n /** When true, emit `<cdr:nvSpPr><cdr:cNvSpPr txBox=\"1\"/>` so Excel renders the shape as a text-box. */\n txBox?: boolean;\n spPr?: ShapeProperties;\n txBody?: TextBody;\n}\n\n/** `<cdr:pic>` picture leaf. */\nexport interface ChartDrawingPicture {\n id: number;\n name?: string;\n descr?: string;\n /** rels-resolved id used by `<a:blip r:embed>`. */\n embedRId?: string;\n spPr?: ShapeProperties;\n}\n\nexport type UserShapeContent =\n | { kind: 'shape'; shape: ChartDrawingShape }\n | { kind: 'picture'; picture: ChartDrawingPicture };\n\nexport type UserShapeAnchor =\n | {\n kind: 'relSize';\n from: ChartRelativeMarker;\n to: ChartRelativeMarker;\n content: UserShapeContent;\n }\n | {\n kind: 'absSize';\n from: ChartRelativeMarker;\n ext: PositiveSize2D;\n content: UserShapeContent;\n };\n\nexport interface ChartDrawing {\n shapes: UserShapeAnchor[];\n}\n\nexport const makeChartDrawing = (shapes: UserShapeAnchor[] = []): ChartDrawing => ({ shapes });\n\nexport const makeChartShape = (opts: {\n id: number;\n name?: string;\n descr?: string;\n hidden?: boolean;\n txBox?: boolean;\n spPr?: ShapeProperties;\n txBody?: TextBody;\n}): ChartDrawingShape => ({\n id: opts.id,\n ...(opts.name !== undefined ? { name: opts.name } : {}),\n ...(opts.descr !== undefined ? { descr: opts.descr } : {}),\n ...(opts.hidden !== undefined ? { hidden: opts.hidden } : {}),\n ...(opts.txBox !== undefined ? { txBox: opts.txBox } : {}),\n ...(opts.spPr ? { spPr: opts.spPr } : {}),\n ...(opts.txBody ? { txBody: opts.txBody } : {}),\n});\n\nexport const makeRelSizeAnchor = (\n from: ChartRelativeMarker,\n to: ChartRelativeMarker,\n content: UserShapeContent,\n): UserShapeAnchor => ({ kind: 'relSize', from, to, content });\n\nexport const makeAbsSizeAnchor = (\n from: ChartRelativeMarker,\n ext: PositiveSize2D,\n content: UserShapeContent,\n): UserShapeAnchor => ({ kind: 'absSize', from, ext, content });\n"],"mappings":"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"}
1
+ {"version":3,"file":"user-shapes-DfmCGKB0.mjs","names":[],"sources":["../src/chart/chart.ts","../src/chart/user-shapes.ts"],"sourcesContent":["import type { ShapeProperties } from '../drawing/dml/shape-properties.js';\nimport type { TextBody } from '../drawing/dml/text.js';\nimport type { ChartDrawing } from './user-shapes.js';\n\n// ChartML data model.\n//\n// **Stage 1**: BarChart end-to-end. The full 17 SpreadsheetML chart kinds + 8\n// chartex kinds land across the upcoming iterations; this commit introduces the\n// shared shape so future kinds can plug in without breaking the public surface:\n//\n// ChartSpace\n// ├─ title?: string\n// ├─ legend?: { position: ... }\n// └─ plotArea\n// ├─ chart: BarChart | LineChart | PieChart | … (discriminated union)\n// ├─ catAx?: CategoryAxis (or Date / Series axis)\n// └─ valAx?: ValueAxis\n//\n// References to worksheet ranges (`Sheet1!$A$1:$A$5`) are kept as strings; the\n// optional `cache` field carries the last-known data so charts can be rendered\n// without reading the source data.\n\nexport type LegendPosition = 'r' | 't' | 'l' | 'b' | 'tr';\nexport type GroupingType = 'clustered' | 'stacked' | 'percentStacked' | 'standard';\nexport type BarDirection = 'bar' | 'col';\n\n/** Reference to a worksheet range plus an optional client-side cache of the resolved values. */\nexport interface NumericRef {\n /** Worksheet-qualified range string, e.g. `Sheet1!$B$1:$B$5`. */\n ref: string;\n /** Optional cached numeric values — Excel writes these for offline rendering. */\n cache?: number[];\n /** Optional `formatCode` Excel uses when rendering each cached value. */\n formatCode?: string;\n}\n\nexport interface CategoryRef {\n ref: string;\n /** Whether the cache is numeric or string. */\n cacheKind?: 'num' | 'str';\n /** String values (when `cacheKind === 'str'`) or numeric values. */\n cache?: ReadonlyArray<string | number>;\n formatCode?: string;\n}\n\n// ---- Series decorations: data labels, trendlines, error bars --------------\n\n/**\n * Number-format payload for chart axes / data labels (`<c:numFmt formatCode=\"…\"\n * sourceLinked=\"0|1\"/>`).\n *\n * Named `ChartNumberFormat` to avoid colliding with the cell-stylesheet\n * `NumberFormat` exported from `@office-kit/xlsx/styles`, which is a different shape\n * (`{ numFmtId, formatCode }`).\n */\nexport interface ChartNumberFormat {\n formatCode: string;\n sourceLinked?: boolean;\n}\n\nexport type DataLabelPosition = 'bestFit' | 'b' | 'ctr' | 'inBase' | 'inEnd' | 'l' | 'outEnd' | 'r' | 't';\n\n/** Per-point data label override. Lives inside `<c:dLbls><c:dLbl idx=\"N\">…</c:dLbl></c:dLbls>`. */\nexport interface DataLabel {\n idx: number;\n /** Delete this individual label (suppresses display even if the parent dLbls would show it). */\n delete?: boolean;\n /** Inline rich text or a cell reference. Mutually exclusive. */\n tx?: { kind: 'rich'; body: TextBody } | { kind: 'strRef'; ref: string };\n numFmt?: ChartNumberFormat;\n spPr?: ShapeProperties;\n txPr?: TextBody;\n dLblPos?: DataLabelPosition;\n showLegendKey?: boolean;\n showVal?: boolean;\n showCatName?: boolean;\n showSerName?: boolean;\n showPercent?: boolean;\n showBubbleSize?: boolean;\n separator?: string;\n}\n\n/** Series-wide data label settings. `<c:dLbls>` element. */\nexport interface DataLabelList {\n /** When true, suppress all labels (`<c:delete val=\"1\"/>`). */\n delete?: boolean;\n /** Per-point overrides. */\n dLbl?: DataLabel[];\n numFmt?: ChartNumberFormat;\n spPr?: ShapeProperties;\n txPr?: TextBody;\n dLblPos?: DataLabelPosition;\n showLegendKey?: boolean;\n showVal?: boolean;\n showCatName?: boolean;\n showSerName?: boolean;\n showPercent?: boolean;\n showBubbleSize?: boolean;\n separator?: string;\n showLeaderLines?: boolean;\n}\n\nexport type MarkerSymbol =\n | 'auto'\n | 'circle'\n | 'dash'\n | 'diamond'\n | 'dot'\n | 'none'\n | 'picture'\n | 'plus'\n | 'square'\n | 'star'\n | 'triangle'\n | 'x';\n\n/** Data-point marker on line / scatter / radar series (`<c:marker>` child of `<c:ser>`). */\nexport interface Marker {\n symbol?: MarkerSymbol;\n /** Marker size in points (2..72). */\n size?: number;\n spPr?: ShapeProperties;\n}\n\n/**\n * Per-point override on a series (`<c:dPt>` child of `<c:ser>`). Lets each bar\n * / slice / data point pick up its own colour, marker, explosion, etc.\n */\nexport interface DataPoint {\n /** 0-based index of the data point within the series. */\n idx: number;\n /** Invert fill when the data point's value is negative (bar / area / bubble). */\n invertIfNegative?: boolean;\n /** Per-point marker override (line / scatter / radar). */\n marker?: Marker;\n /** 3-D bubble flag (bubble series only). */\n bubble3D?: boolean;\n /** Slice explosion in % for pie / doughnut points (0..400). */\n explosion?: number;\n /** Per-point shape properties (fill / line colour). */\n spPr?: ShapeProperties;\n}\n\nexport type TrendlineType = 'exp' | 'linear' | 'log' | 'movingAvg' | 'poly' | 'power';\n\nexport interface Trendline {\n /** Display name shown in the chart legend (`<c:name>` text). */\n name?: string;\n spPr?: ShapeProperties;\n trendlineType: TrendlineType;\n /** Polynomial order (2..6) when `trendlineType === 'poly'`. */\n order?: number;\n /** Moving-average period when `trendlineType === 'movingAvg'`. */\n period?: number;\n /** Forecast forward periods. */\n forward?: number;\n /** Forecast backward periods. */\n backward?: number;\n /** Y-axis intercept (linear only). */\n intercept?: number;\n /** Display R² value on the chart. */\n dispRSqr?: boolean;\n /** Display the trendline equation. */\n dispEq?: boolean;\n}\n\nexport type ErrorBarDirection = 'x' | 'y';\nexport type ErrorBarType = 'both' | 'minus' | 'plus';\nexport type ErrorValType = 'cust' | 'fixedVal' | 'percentage' | 'stdDev' | 'stdErr';\n\nexport interface ErrorBars {\n /** Direction. Required only on scatter / bubble series; bar / line / area imply `'y'`. */\n errDir?: ErrorBarDirection;\n errBarType: ErrorBarType;\n errValType: ErrorValType;\n noEndCap?: boolean;\n /** Numeric magnitude for fixedVal / percentage / stdDev / stdErr. */\n val?: number;\n /** Custom plus-side data (NumericRef) — required when `errValType === 'cust'`. */\n plus?: NumericRef;\n /** Custom minus-side data (NumericRef) — required when `errValType === 'cust'`. */\n minus?: NumericRef;\n spPr?: ShapeProperties;\n}\n\nexport interface BarSeries {\n /** 0-based slot in the chart (`<c:idx>`). */\n idx: number;\n /** Render order (`<c:order>`). Usually equals `idx`. */\n order: number;\n /** Series title — either a static string or a cell reference. */\n tx?: { kind: 'literal'; value: string } | { kind: 'ref'; ref: string };\n /** Per-series shape properties (fill / line / effects). */\n spPr?: ShapeProperties;\n /** Invert fill on negative values (bar / line / area series). */\n invertIfNegative?: boolean;\n /**\n * Slice explosion in % (pie / doughnut series only; 0..400). Bar / line / area writers\n * ignore the field — leave it unset for those series.\n */\n explosion?: number;\n /** Per-point overrides. Empty / omitted means every point inherits the series defaults. */\n dPt?: DataPoint[];\n /** Series-wide data labels. */\n dLbls?: DataLabelList;\n /** Trendlines attached to this series. */\n trendline?: Trendline[];\n /** Error bars. Bar / line / area / radar default to a single y-direction entry. */\n errBars?: ErrorBars[];\n /** Categories. */\n cat?: CategoryRef;\n /** Values (always required for a bar series). */\n val: NumericRef;\n}\n\nexport interface BarChart {\n kind: 'bar';\n /** `bar` for horizontal bars, `col` for vertical columns. */\n barDir: BarDirection;\n /** Excel default is `clustered`. */\n grouping: GroupingType;\n varyColors?: boolean;\n series: BarSeries[];\n /** Bar gap width in % of bar width (Excel default 150). */\n gapWidth?: number;\n /**\n * Bar overlap in -100..100 % of bar width. Positive values overlap clustered bars; negative values\n * space them apart. For stacked / percentStacked grouping, omit and the serializer emits the\n * standard Excel default of 100 (flush stacking).\n */\n overlap?: number;\n /** Internal axis ids. The category and value axes carry the same numbers. */\n axIds: [number, number];\n}\n\nexport interface LineSeries extends BarSeries {\n /** Per-series smoothing toggle. */\n smooth?: boolean;\n /** Data-point marker (`<c:marker>` child of `<c:ser>`). */\n marker?: Marker;\n}\n\nexport interface LineChart {\n kind: 'line';\n grouping: GroupingType;\n varyColors?: boolean;\n series: LineSeries[];\n /** Whether to round corners between data points (chart-level default). */\n smooth?: boolean;\n axIds: [number, number];\n}\n\nexport interface AreaChart {\n kind: 'area';\n grouping: GroupingType;\n varyColors?: boolean;\n series: BarSeries[];\n axIds: [number, number];\n}\n\nexport interface PieChart {\n kind: 'pie';\n varyColors?: boolean;\n /** Pie / Doughnut have a single ring of slices — but Excel allows multiple series; we mirror that. */\n series: BarSeries[];\n}\n\nexport interface DoughnutChart {\n kind: 'doughnut';\n varyColors?: boolean;\n series: BarSeries[];\n /** Hole size in % of outer radius (10..90, Excel default 50). */\n holeSize?: number;\n /** First-slice rotation angle in degrees. */\n firstSliceAng?: number;\n}\n\nexport type ScatterStyle = 'line' | 'lineMarker' | 'marker' | 'none' | 'smooth' | 'smoothMarker';\n\nexport interface ScatterSeries {\n idx: number;\n order: number;\n tx?: BarSeries['tx'];\n spPr?: ShapeProperties;\n dPt?: DataPoint[];\n dLbls?: DataLabelList;\n trendline?: Trendline[];\n /** Up to 2 entries (one per direction). */\n errBars?: ErrorBars[];\n /** Data-point marker. */\n marker?: Marker;\n xVal?: NumericRef;\n yVal: NumericRef;\n smooth?: boolean;\n}\n\nexport interface ScatterChart {\n kind: 'scatter';\n scatterStyle: ScatterStyle;\n varyColors?: boolean;\n series: ScatterSeries[];\n axIds: [number, number];\n}\n\nexport type RadarStyle = 'standard' | 'marker' | 'filled';\n\nexport interface RadarChart {\n kind: 'radar';\n radarStyle: RadarStyle;\n varyColors?: boolean;\n series: BarSeries[];\n axIds: [number, number];\n}\n\nexport interface BubbleSeries {\n idx: number;\n order: number;\n tx?: BarSeries['tx'];\n spPr?: ShapeProperties;\n invertIfNegative?: boolean;\n dPt?: DataPoint[];\n dLbls?: DataLabelList;\n trendline?: Trendline[];\n /** Up to 2 entries (one per direction). */\n errBars?: ErrorBars[];\n xVal?: NumericRef;\n yVal: NumericRef;\n /** Bubble size — required for a real bubble chart. */\n bubbleSize: NumericRef;\n /** Per-series 3-D toggle. */\n bubble3D?: boolean;\n}\n\nexport type BubbleSizeRepresents = 'area' | 'w';\n\nexport interface BubbleChart {\n kind: 'bubble';\n varyColors?: boolean;\n series: BubbleSeries[];\n bubble3D?: boolean;\n /** Bubble scale 0..300 %. Excel default is 100. */\n bubbleScale?: number;\n showNegBubbles?: boolean;\n sizeRepresents?: BubbleSizeRepresents;\n axIds: [number, number];\n}\n\n/** `<c:hiLowLines>` child of stock charts. */\nexport interface HiLowLines {\n spPr?: ShapeProperties;\n}\n\n/** `<c:upBars>` / `<c:downBars>` child frame styling. */\nexport interface BarFrame {\n spPr?: ShapeProperties;\n}\n\n/** `<c:upDownBars>` child of stock charts. */\nexport interface UpDownBars {\n /** Gap width 0..500 between up/down bars. Excel default is 150. */\n gapWidth?: number;\n upBars?: BarFrame;\n downBars?: BarFrame;\n}\n\nexport interface StockChart {\n kind: 'stock';\n /** Up to 4 series — typically open / high / low / close. */\n series: BarSeries[];\n /** Boolean flag for the simple `<c:hiLowLines/>` form, or an object with `spPr` for custom line styling. */\n hiLowLines?: boolean | HiLowLines;\n /** Boolean for the simple form, or an object with gapWidth / upBars / downBars detail. */\n upDownBars?: boolean | UpDownBars;\n axIds: [number, number];\n}\n\nexport interface SurfaceChart {\n kind: 'surface';\n series: BarSeries[];\n /** Wireframe (line-only) when true; smoothed surface fill when false. */\n wireframe?: boolean;\n /** Surfaces use 3 axes: cat + val + ser. */\n axIds: [number, number, number];\n}\n\nexport type OfPieType = 'bar' | 'pie';\nexport type SplitType = 'auto' | 'cust' | 'percent' | 'pos' | 'val';\n\nexport interface OfPieChart {\n kind: 'ofPie';\n /** `bar` for \"Bar of Pie\", `pie` for \"Pie of Pie\". */\n ofPieType: OfPieType;\n varyColors?: boolean;\n series: BarSeries[];\n gapWidth?: number;\n splitType?: SplitType;\n /** Position threshold paired with `splitType='pos'`. */\n splitPos?: number;\n /** Indices of data points moved to the secondary plot when `splitType='cust'`. */\n custSplit?: number[];\n /** Secondary plot size as % of primary (5..200). */\n secondPieSize?: number;\n}\n\n// ---- 3-D chart variants ---------------------------------------------------\n//\n// 3-D charts share most of their attributes with their 2-D counterparts but\n// land on different XML tag names (<c:bar3DChart>, etc) and use 3 axes (cat /\n// val / ser). We keep them as distinct discriminated-union variants so the\n// chart kind stays type-narrowable.\n\nexport interface Bar3DChart {\n kind: 'bar3D';\n barDir: BarDirection;\n grouping: GroupingType;\n varyColors?: boolean;\n series: BarSeries[];\n gapWidth?: number;\n /** Bar 3-D adds a `gapDepth` attribute. */\n gapDepth?: number;\n /** Cluster | percentStacked | stacked … plus 'standard' which 2-D doesn't take. */\n shape?: 'cone' | 'coneToMax' | 'box' | 'cylinder' | 'pyramid' | 'pyramidToMax';\n axIds: [number, number, number];\n}\n\nexport interface Line3DChart {\n kind: 'line3D';\n grouping: GroupingType;\n varyColors?: boolean;\n series: LineSeries[];\n gapDepth?: number;\n axIds: [number, number, number];\n}\n\nexport interface Pie3DChart {\n kind: 'pie3D';\n varyColors?: boolean;\n series: BarSeries[];\n}\n\nexport interface Area3DChart {\n kind: 'area3D';\n grouping: GroupingType;\n varyColors?: boolean;\n series: BarSeries[];\n gapDepth?: number;\n axIds: [number, number, number];\n}\n\nexport interface Surface3DChart {\n kind: 'surface3D';\n series: BarSeries[];\n wireframe?: boolean;\n axIds: [number, number, number];\n}\n\n/** Discriminator union of all SpreadsheetML chart kinds modelled so far. */\nexport type ChartKind =\n | BarChart\n | LineChart\n | AreaChart\n | PieChart\n | DoughnutChart\n | ScatterChart\n | RadarChart\n | BubbleChart\n | StockChart\n | SurfaceChart\n | OfPieChart\n | Bar3DChart\n | Line3DChart\n | Pie3DChart\n | Area3DChart\n | Surface3DChart;\n\nexport type TickMark = 'cross' | 'in' | 'none' | 'out';\nexport type TickLabelPosition = 'high' | 'low' | 'nextTo' | 'none';\nexport type AxisCrosses = 'autoZero' | 'max' | 'min';\nexport type AxisOrientation = 'maxMin' | 'minMax';\nexport type AxisCrossBetween = 'between' | 'midCat';\nexport type CategoryLabelAlignment = 'ctr' | 'l' | 'r';\n\n/** `<c:scaling>` child of axes. */\nexport interface AxisScaling {\n orientation?: AxisOrientation;\n min?: number;\n max?: number;\n logBase?: number;\n}\n\ninterface AxisShared {\n axId: number;\n /** Crosses partner axis id. */\n crossAx: number;\n position?: 'b' | 't' | 'l' | 'r';\n delete?: boolean;\n /** Axis-line / tick formatting. */\n spPr?: ShapeProperties;\n /** Tick-label text formatting. */\n txPr?: TextBody;\n /** Axis title (`<c:title>`). Reuses the chart-title structure. */\n title?: ChartTitle;\n /** Tick-label number format. Default emitted is `General` / `sourceLinked=1`. */\n numFmt?: ChartNumberFormat;\n /** Major tick mark style. Default emitted is `out`. */\n majorTickMark?: TickMark;\n /** Minor tick mark style. Default emitted is `none`. */\n minorTickMark?: TickMark;\n /** Tick-label position. Default emitted is `nextTo`. */\n tickLblPos?: TickLabelPosition;\n /** Axis scaling (`<c:scaling>`). Default emitted is `orientation: 'minMax'`. */\n scaling?: AxisScaling;\n /** `<c:crosses>`. Default emitted is `autoZero`. Mutually exclusive with `crossesAt`. */\n crosses?: AxisCrosses;\n /** `<c:crossesAt val=\"...\"/>`. Numeric cross point on the partner axis. */\n crossesAt?: number;\n /**\n * Major gridlines. `true` keeps Excel's default rendering; pass\n * `{ spPr }` to override the line colour / width / dash. `false` /\n * `undefined` omit the element entirely.\n */\n majorGridlines?: boolean | Gridlines;\n /** Minor gridlines. Same shape as {@link AxisShared.majorGridlines}. */\n minorGridlines?: boolean | Gridlines;\n}\n\n/**\n * Rich `<c:majorGridlines>` / `<c:minorGridlines>` form. Wraps a\n * `ShapeProperties` so the gridline line can be styled (e.g. corporate-style\n * light-grey `D9D9D9`).\n */\nexport interface Gridlines {\n spPr?: ShapeProperties;\n}\n\nexport interface CategoryAxis extends AxisShared {\n /** `<c:auto>` — whether Excel auto-selects the axis type from the data. */\n auto?: boolean;\n /** Tick-label alignment. Default emitted is `ctr`. */\n lblAlgn?: CategoryLabelAlignment;\n /** Tick-label offset 0..1000. Default emitted is `100`. */\n lblOffset?: number;\n /** Suppress multi-level labels for hierarchical categories. */\n noMultiLvlLbl?: boolean;\n}\n\nexport interface ValueAxis extends AxisShared {\n /** Tick-axis crossing rule. Default emitted is `between`. */\n crossBetween?: AxisCrossBetween;\n /** Major unit spacing on the value axis. */\n majorUnit?: number;\n /** Minor unit spacing on the value axis. */\n minorUnit?: number;\n}\n\nexport type TimeUnit = 'days' | 'months' | 'years';\n\nexport interface DateAxis extends AxisShared {\n /** `<c:auto>` — auto-select axis type. */\n auto?: boolean;\n /** Tick-label offset 0..1000. Default emitted is `100`. */\n lblOffset?: number;\n /** Smallest interval the axis represents. */\n baseTimeUnit?: TimeUnit;\n /** Major unit spacing on the date axis (count of `majorTimeUnit`s). */\n majorUnit?: number;\n majorTimeUnit?: TimeUnit;\n /** Minor unit spacing on the date axis. */\n minorUnit?: number;\n minorTimeUnit?: TimeUnit;\n}\n\nexport interface SeriesAxis extends AxisShared {\n /** Skip every Nth tick label (1 = every label). */\n tickLblSkip?: number;\n /** Skip every Nth tick mark. */\n tickMarkSkip?: number;\n}\n\nexport interface PlotArea {\n chart: ChartKind;\n catAx?: CategoryAxis;\n valAx?: ValueAxis;\n /** Date / time axis. Replaces `catAx` when the categories are dates. */\n dateAx?: DateAxis;\n /** Series axis (used by `surface3DChart` / `surfaceChart`). */\n serAx?: SeriesAxis;\n /** Manual layout for the plot area inside the chart. */\n layout?: Layout;\n /** Plot-area shape properties (background fill, border line). */\n spPr?: ShapeProperties;\n}\n\nexport type LayoutMode = 'edge' | 'factor';\nexport type LayoutTarget = 'inner' | 'outer';\n\n/** `<c:manualLayout>` child of `<c:layout>`. All values are fractions of the chart space (0..1). */\nexport interface ManualLayout {\n layoutTarget?: LayoutTarget;\n xMode?: LayoutMode;\n yMode?: LayoutMode;\n wMode?: LayoutMode;\n hMode?: LayoutMode;\n x?: number;\n y?: number;\n w?: number;\n h?: number;\n}\n\n/** `<c:layout>` wrapper. Currently only `manualLayout` is exposed; the lone `<layoutId>` form is for chartex. */\nexport interface Layout {\n manualLayout?: ManualLayout;\n}\n\nexport interface Legend {\n position: LegendPosition;\n overlay?: boolean;\n layout?: Layout;\n spPr?: ShapeProperties;\n txPr?: TextBody;\n}\n\n/** Chart title with full DrawingML formatting support. */\nexport interface ChartTitle {\n /**\n * Plain title text. When set the serializer emits\n * `<c:tx><c:rich><a:p><a:r><a:t>text</a:t></a:r></c:rich></c:tx>`. Mutually\n * exclusive with `tx`.\n */\n text?: string;\n /** Rich text body — overrides `text` when both are present. */\n tx?: TextBody;\n overlay?: boolean;\n layout?: Layout;\n spPr?: ShapeProperties;\n txPr?: TextBody;\n}\n\n/** 3-D viewing options. Used by `bar3DChart`, `line3DChart`, `pie3DChart`, `area3DChart`, `surface3DChart`. */\nexport interface View3D {\n /** X-axis rotation in degrees, -90..90. */\n rotX?: number;\n /** Y-axis rotation in degrees, 0..359. */\n rotY?: number;\n /** Depth as a percentage of chart width, 20..2000. */\n depthPercent?: number;\n /** Height as a percentage of chart width, 5..500. */\n hPercent?: number;\n /** Use right-angle axes (orthographic). When true, perspective is ignored. */\n rAngAx?: boolean;\n /** Perspective angle 0..240 (0 = isometric, 30 = Excel default). */\n perspective?: number;\n}\n\n/** 3-D wall / floor frame. Children of `<c:chart>` for bar3D / line3D / area3D / surface3D / pie3D. */\nexport interface SurfaceFrame {\n /** Wall thickness in % of chart width (0..100). */\n thickness?: number;\n spPr?: ShapeProperties;\n}\n\nexport interface ChartSpace {\n /** Optional chart title. */\n title?: ChartTitle;\n legend?: Legend;\n plotArea: PlotArea;\n /**\n * Built-in Excel chart-style preset (1..48). Mapped to `<c:style val=\"N\"/>` inside\n * `<c:chartSpace>` and selects one entry of Excel's \"Chart Styles\" gallery.\n */\n style?: number;\n /** 3-D viewing options (applies to 3-D chart kinds; ignored otherwise by Excel). */\n view3D?: View3D;\n /** 3-D chart floor frame. */\n floor?: SurfaceFrame;\n /** 3-D chart side wall frame. */\n sideWall?: SurfaceFrame;\n /** 3-D chart back wall frame. */\n backWall?: SurfaceFrame;\n /** Honour the formatting hints in cached numeric data when rendering. */\n plotVisOnly?: boolean;\n /** Display blanks as gap, zero, or span — Excel default is `gap`. */\n dispBlanksAs?: 'gap' | 'zero' | 'span';\n /** Chart-space level shape properties (overall frame). */\n spPr?: ShapeProperties;\n /** Chart-space level default text properties. */\n txPr?: TextBody;\n /** Annotations / text boxes / arrows drawn over the chart. Serialised as `xl/drawings/chartDrawingN.xml`. */\n userShapes?: ChartDrawing;\n}\n\nexport function makeBarChart(opts: {\n barDir?: BarDirection;\n grouping?: GroupingType;\n series?: BarSeries[];\n axIds?: [number, number];\n varyColors?: boolean;\n gapWidth?: number;\n overlap?: number;\n}): BarChart {\n return {\n kind: 'bar',\n barDir: opts.barDir ?? 'col',\n grouping: opts.grouping ?? 'clustered',\n series: opts.series ?? [],\n axIds: opts.axIds ?? [1, 2],\n ...(opts.varyColors !== undefined ? { varyColors: opts.varyColors } : {}),\n ...(opts.gapWidth !== undefined ? { gapWidth: opts.gapWidth } : {}),\n ...(opts.overlap !== undefined ? { overlap: opts.overlap } : {}),\n };\n}\n\nexport function makeBarSeries(opts: {\n idx: number;\n order?: number;\n val: NumericRef;\n cat?: CategoryRef;\n tx?: BarSeries['tx'];\n}): BarSeries {\n return {\n idx: opts.idx,\n order: opts.order ?? opts.idx,\n val: opts.val,\n ...(opts.cat ? { cat: opts.cat } : {}),\n ...(opts.tx ? { tx: opts.tx } : {}),\n };\n}\n\nexport function makeChartSpace(opts: {\n plotArea: PlotArea;\n /** Plain string is wrapped in `{ text }`; pass `ChartTitle` for full formatting. */\n title?: string | ChartTitle;\n legend?: Legend;\n style?: number;\n view3D?: View3D;\n floor?: SurfaceFrame;\n sideWall?: SurfaceFrame;\n backWall?: SurfaceFrame;\n plotVisOnly?: boolean;\n dispBlanksAs?: ChartSpace['dispBlanksAs'];\n spPr?: ShapeProperties;\n txPr?: TextBody;\n}): ChartSpace {\n const title: ChartTitle | undefined = typeof opts.title === 'string' ? { text: opts.title } : opts.title;\n return {\n plotArea: opts.plotArea,\n ...(title !== undefined ? { title } : {}),\n ...(opts.legend ? { legend: opts.legend } : {}),\n ...(opts.style !== undefined ? { style: opts.style } : {}),\n ...(opts.view3D ? { view3D: opts.view3D } : {}),\n ...(opts.floor ? { floor: opts.floor } : {}),\n ...(opts.sideWall ? { sideWall: opts.sideWall } : {}),\n ...(opts.backWall ? { backWall: opts.backWall } : {}),\n ...(opts.plotVisOnly !== undefined ? { plotVisOnly: opts.plotVisOnly } : {}),\n ...(opts.dispBlanksAs !== undefined ? { dispBlanksAs: opts.dispBlanksAs } : {}),\n ...(opts.spPr ? { spPr: opts.spPr } : {}),\n ...(opts.txPr ? { txPr: opts.txPr } : {}),\n };\n}\n\nexport function makeLineChart(opts: {\n grouping?: GroupingType;\n series?: LineSeries[];\n axIds?: [number, number];\n varyColors?: boolean;\n smooth?: boolean;\n}): LineChart {\n return {\n kind: 'line',\n grouping: opts.grouping ?? 'standard',\n series: opts.series ?? [],\n axIds: opts.axIds ?? [1, 2],\n ...(opts.varyColors !== undefined ? { varyColors: opts.varyColors } : {}),\n ...(opts.smooth !== undefined ? { smooth: opts.smooth } : {}),\n };\n}\n\nexport function makeAreaChart(opts: {\n grouping?: GroupingType;\n series?: BarSeries[];\n axIds?: [number, number];\n varyColors?: boolean;\n}): AreaChart {\n return {\n kind: 'area',\n grouping: opts.grouping ?? 'standard',\n series: opts.series ?? [],\n axIds: opts.axIds ?? [1, 2],\n ...(opts.varyColors !== undefined ? { varyColors: opts.varyColors } : {}),\n };\n}\n\nexport function makePieChart(opts: { series?: BarSeries[]; varyColors?: boolean }): PieChart {\n return {\n kind: 'pie',\n series: opts.series ?? [],\n ...(opts.varyColors !== undefined ? { varyColors: opts.varyColors } : {}),\n };\n}\n\nexport function makeDoughnutChart(opts: {\n series?: BarSeries[];\n varyColors?: boolean;\n holeSize?: number;\n firstSliceAng?: number;\n}): DoughnutChart {\n return {\n kind: 'doughnut',\n series: opts.series ?? [],\n ...(opts.varyColors !== undefined ? { varyColors: opts.varyColors } : {}),\n ...(opts.holeSize !== undefined ? { holeSize: opts.holeSize } : {}),\n ...(opts.firstSliceAng !== undefined ? { firstSliceAng: opts.firstSliceAng } : {}),\n };\n}\n\nexport function makeScatterChart(opts: {\n scatterStyle?: ScatterStyle;\n series?: ScatterSeries[];\n axIds?: [number, number];\n varyColors?: boolean;\n}): ScatterChart {\n return {\n kind: 'scatter',\n scatterStyle: opts.scatterStyle ?? 'lineMarker',\n series: opts.series ?? [],\n axIds: opts.axIds ?? [1, 2],\n ...(opts.varyColors !== undefined ? { varyColors: opts.varyColors } : {}),\n };\n}\n\nexport function makeScatterSeries(opts: {\n idx: number;\n order?: number;\n tx?: BarSeries['tx'];\n xVal?: NumericRef;\n yVal: NumericRef;\n smooth?: boolean;\n marker?: Marker;\n}): ScatterSeries {\n return {\n idx: opts.idx,\n order: opts.order ?? opts.idx,\n yVal: opts.yVal,\n ...(opts.tx ? { tx: opts.tx } : {}),\n ...(opts.xVal ? { xVal: opts.xVal } : {}),\n ...(opts.smooth !== undefined ? { smooth: opts.smooth } : {}),\n ...(opts.marker ? { marker: opts.marker } : {}),\n };\n}\n\nexport function makeRadarChart(opts: {\n radarStyle?: RadarStyle;\n series?: BarSeries[];\n axIds?: [number, number];\n varyColors?: boolean;\n}): RadarChart {\n return {\n kind: 'radar',\n radarStyle: opts.radarStyle ?? 'standard',\n series: opts.series ?? [],\n axIds: opts.axIds ?? [1, 2],\n ...(opts.varyColors !== undefined ? { varyColors: opts.varyColors } : {}),\n };\n}\n\nexport function makeBubbleChart(opts: {\n series?: BubbleSeries[];\n axIds?: [number, number];\n varyColors?: boolean;\n bubble3D?: boolean;\n bubbleScale?: number;\n showNegBubbles?: boolean;\n sizeRepresents?: BubbleSizeRepresents;\n}): BubbleChart {\n return {\n kind: 'bubble',\n series: opts.series ?? [],\n axIds: opts.axIds ?? [1, 2],\n ...(opts.varyColors !== undefined ? { varyColors: opts.varyColors } : {}),\n ...(opts.bubble3D !== undefined ? { bubble3D: opts.bubble3D } : {}),\n ...(opts.bubbleScale !== undefined ? { bubbleScale: opts.bubbleScale } : {}),\n ...(opts.showNegBubbles !== undefined ? { showNegBubbles: opts.showNegBubbles } : {}),\n ...(opts.sizeRepresents !== undefined ? { sizeRepresents: opts.sizeRepresents } : {}),\n };\n}\n\nexport function makeBubbleSeries(opts: {\n idx: number;\n order?: number;\n tx?: BarSeries['tx'];\n xVal?: NumericRef;\n yVal: NumericRef;\n bubbleSize: NumericRef;\n bubble3D?: boolean;\n}): BubbleSeries {\n return {\n idx: opts.idx,\n order: opts.order ?? opts.idx,\n yVal: opts.yVal,\n bubbleSize: opts.bubbleSize,\n ...(opts.tx ? { tx: opts.tx } : {}),\n ...(opts.xVal ? { xVal: opts.xVal } : {}),\n ...(opts.bubble3D !== undefined ? { bubble3D: opts.bubble3D } : {}),\n };\n}\n\nexport function makeStockChart(opts: {\n series?: BarSeries[];\n axIds?: [number, number];\n hiLowLines?: boolean | HiLowLines;\n upDownBars?: boolean | UpDownBars;\n}): StockChart {\n return {\n kind: 'stock',\n series: opts.series ?? [],\n axIds: opts.axIds ?? [1, 2],\n ...(opts.hiLowLines !== undefined ? { hiLowLines: opts.hiLowLines } : {}),\n ...(opts.upDownBars !== undefined ? { upDownBars: opts.upDownBars } : {}),\n };\n}\n\nexport function makeSurfaceChart(opts: {\n series?: BarSeries[];\n wireframe?: boolean;\n axIds?: [number, number, number];\n}): SurfaceChart {\n return {\n kind: 'surface',\n series: opts.series ?? [],\n axIds: opts.axIds ?? [1, 2, 3],\n ...(opts.wireframe !== undefined ? { wireframe: opts.wireframe } : {}),\n };\n}\n\nexport function makeOfPieChart(opts: {\n ofPieType?: OfPieType;\n series?: BarSeries[];\n varyColors?: boolean;\n gapWidth?: number;\n splitType?: SplitType;\n splitPos?: number;\n custSplit?: number[];\n secondPieSize?: number;\n}): OfPieChart {\n return {\n kind: 'ofPie',\n ofPieType: opts.ofPieType ?? 'pie',\n series: opts.series ?? [],\n ...(opts.varyColors !== undefined ? { varyColors: opts.varyColors } : {}),\n ...(opts.gapWidth !== undefined ? { gapWidth: opts.gapWidth } : {}),\n ...(opts.splitType !== undefined ? { splitType: opts.splitType } : {}),\n ...(opts.splitPos !== undefined ? { splitPos: opts.splitPos } : {}),\n ...(opts.custSplit ? { custSplit: opts.custSplit } : {}),\n ...(opts.secondPieSize !== undefined ? { secondPieSize: opts.secondPieSize } : {}),\n };\n}\n\nexport function makeBar3DChart(opts: {\n barDir?: BarDirection;\n grouping?: GroupingType;\n series?: BarSeries[];\n axIds?: [number, number, number];\n varyColors?: boolean;\n gapWidth?: number;\n gapDepth?: number;\n shape?: Bar3DChart['shape'];\n}): Bar3DChart {\n return {\n kind: 'bar3D',\n barDir: opts.barDir ?? 'col',\n grouping: opts.grouping ?? 'clustered',\n series: opts.series ?? [],\n axIds: opts.axIds ?? [1, 2, 3],\n ...(opts.varyColors !== undefined ? { varyColors: opts.varyColors } : {}),\n ...(opts.gapWidth !== undefined ? { gapWidth: opts.gapWidth } : {}),\n ...(opts.gapDepth !== undefined ? { gapDepth: opts.gapDepth } : {}),\n ...(opts.shape !== undefined ? { shape: opts.shape } : {}),\n };\n}\n\nexport function makeLine3DChart(opts: {\n grouping?: GroupingType;\n series?: LineSeries[];\n axIds?: [number, number, number];\n varyColors?: boolean;\n gapDepth?: number;\n}): Line3DChart {\n return {\n kind: 'line3D',\n grouping: opts.grouping ?? 'standard',\n series: opts.series ?? [],\n axIds: opts.axIds ?? [1, 2, 3],\n ...(opts.varyColors !== undefined ? { varyColors: opts.varyColors } : {}),\n ...(opts.gapDepth !== undefined ? { gapDepth: opts.gapDepth } : {}),\n };\n}\n\nexport function makePie3DChart(opts: { series?: BarSeries[]; varyColors?: boolean }): Pie3DChart {\n return {\n kind: 'pie3D',\n series: opts.series ?? [],\n ...(opts.varyColors !== undefined ? { varyColors: opts.varyColors } : {}),\n };\n}\n\nexport function makeArea3DChart(opts: {\n grouping?: GroupingType;\n series?: BarSeries[];\n axIds?: [number, number, number];\n varyColors?: boolean;\n gapDepth?: number;\n}): Area3DChart {\n return {\n kind: 'area3D',\n grouping: opts.grouping ?? 'standard',\n series: opts.series ?? [],\n axIds: opts.axIds ?? [1, 2, 3],\n ...(opts.varyColors !== undefined ? { varyColors: opts.varyColors } : {}),\n ...(opts.gapDepth !== undefined ? { gapDepth: opts.gapDepth } : {}),\n };\n}\n\nexport function makeSurface3DChart(opts: {\n series?: BarSeries[];\n wireframe?: boolean;\n axIds?: [number, number, number];\n}): Surface3DChart {\n return {\n kind: 'surface3D',\n series: opts.series ?? [],\n axIds: opts.axIds ?? [1, 2, 3],\n ...(opts.wireframe !== undefined ? { wireframe: opts.wireframe } : {}),\n };\n}\n","// User shapes (chartDrawing) — annotations on a chart.\n//\n// `xl/drawings/chartDrawingN.xml` is referenced from a `<c:chartSpace>` via\n// `<c:userShapes r:id=\"...\">`. It contains text boxes, arrows, and other shapes\n// positioned either relatively (0..1 of chart width / height) or absolutely\n// (relative anchor + EMU extent).\n\nimport type { ShapeProperties, PositiveSize2D } from '../drawing/dml/shape-properties.js';\nimport type { TextBody } from '../drawing/dml/text.js';\n\n/** `<cdr:from>` / `<cdr:to>` marker. Decimal in 0..1. */\nexport interface ChartRelativeMarker {\n x: number;\n y: number;\n}\n\n/** `<cdr:sp>` shape leaf (text box / arrow / preset shape with optional text). */\nexport interface ChartDrawingShape {\n /** cNvPr id (1-based, unique per chartDrawing). */\n id: number;\n name?: string;\n descr?: string;\n hidden?: boolean;\n /** When true, emit `<cdr:nvSpPr><cdr:cNvSpPr txBox=\"1\"/>` so Excel renders the shape as a text-box. */\n txBox?: boolean;\n spPr?: ShapeProperties;\n txBody?: TextBody;\n}\n\n/** `<cdr:pic>` picture leaf. */\nexport interface ChartDrawingPicture {\n id: number;\n name?: string;\n descr?: string;\n /** rels-resolved id used by `<a:blip r:embed>`. */\n embedRId?: string;\n spPr?: ShapeProperties;\n}\n\nexport type UserShapeContent =\n | { kind: 'shape'; shape: ChartDrawingShape }\n | { kind: 'picture'; picture: ChartDrawingPicture };\n\nexport type UserShapeAnchor =\n | {\n kind: 'relSize';\n from: ChartRelativeMarker;\n to: ChartRelativeMarker;\n content: UserShapeContent;\n }\n | {\n kind: 'absSize';\n from: ChartRelativeMarker;\n ext: PositiveSize2D;\n content: UserShapeContent;\n };\n\nexport interface ChartDrawing {\n shapes: UserShapeAnchor[];\n}\n\nexport const makeChartDrawing = (shapes: UserShapeAnchor[] = []): ChartDrawing => ({ shapes });\n\nexport const makeChartShape = (opts: {\n id: number;\n name?: string;\n descr?: string;\n hidden?: boolean;\n txBox?: boolean;\n spPr?: ShapeProperties;\n txBody?: TextBody;\n}): ChartDrawingShape => ({\n id: opts.id,\n ...(opts.name !== undefined ? { name: opts.name } : {}),\n ...(opts.descr !== undefined ? { descr: opts.descr } : {}),\n ...(opts.hidden !== undefined ? { hidden: opts.hidden } : {}),\n ...(opts.txBox !== undefined ? { txBox: opts.txBox } : {}),\n ...(opts.spPr ? { spPr: opts.spPr } : {}),\n ...(opts.txBody ? { txBody: opts.txBody } : {}),\n});\n\nexport const makeRelSizeAnchor = (\n from: ChartRelativeMarker,\n to: ChartRelativeMarker,\n content: UserShapeContent,\n): UserShapeAnchor => ({ kind: 'relSize', from, to, content });\n\nexport const makeAbsSizeAnchor = (\n from: ChartRelativeMarker,\n ext: PositiveSize2D,\n content: UserShapeContent,\n): UserShapeAnchor => ({ kind: 'absSize', from, ext, content });\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"utf8-Tn3nzyik.mjs","names":[],"sources":["../src/xml/iterparse.ts","../src/utils/utf8.ts"],"sourcesContent":["// SAX iterator over OOXML XML payloads. Wraps `saxes` (XMLNS-aware) and yields\n// a flat stream of {start | end | text} events with names already converted to\n// Clark notation (`{ns}local`) — same shape as the DOM parser produces for\n// static XmlNode trees, so consumers can switch between bulk and streaming\n// reads without retouching name comparison.\n//\n// Phase 1 §3 acceptance: 1 k–row sheetData walked end-to-end with cell counts\n// matching the source. The phase-4 read-only worksheet drives real-world use;\n// this layer just produces the events.\n//\n// DOCTYPE / external entity declarations are forbidden. saxes does not expand\n// external entities, but a prescan also rejects DTDs in non-streaming inputs.\n// Streaming inputs are checked on the first chunk before being fed to the\n// parser.\n\nimport { SaxesParser } from 'saxes';\nimport { OpenXmlSchemaError } from '../utils/exceptions';\nimport { qname } from './namespaces';\n\nexport type SaxEvent =\n | { kind: 'start'; name: string; attrs: Record<string, string> }\n | { kind: 'end'; name: string }\n | { kind: 'text'; text: string };\n\n/**\n * Streamable input: `Uint8Array`, plain string, or a Web `ReadableStream` of\n * `Uint8Array` chunks (produced by xlsx zip entries via fflate, fetch, file\n * streams, etc.).\n */\nexport type SaxInput = Uint8Array | string | ReadableStream<Uint8Array>;\n\nconst DOCTYPE_RE = /<!DOCTYPE\\b/;\nconst ENTITY_RE = /<!ENTITY\\b/;\n\nconst checkDoctype = (text: string): void => {\n if (DOCTYPE_RE.test(text)) {\n throw new OpenXmlSchemaError('DTD declarations are not permitted in OOXML payloads');\n }\n if (ENTITY_RE.test(text)) {\n throw new OpenXmlSchemaError('Entity declarations are not permitted in OOXML payloads');\n }\n};\n\nconst isReadableStream = (v: unknown): v is ReadableStream<Uint8Array> => {\n return typeof v === 'object' && v !== null && typeof (v as ReadableStream).getReader === 'function';\n};\n\nconst decoder = (): TextDecoder => new TextDecoder('utf-8', { fatal: false });\n\ninterface SaxesOpenTag {\n name: string;\n uri: string;\n local: string;\n prefix: string;\n attributes: Record<string, { value: string; uri: string; local: string; prefix: string }>;\n isSelfClosing?: boolean;\n}\n\ninterface SaxesCloseTag {\n name: string;\n uri: string;\n local: string;\n prefix: string;\n}\n\nconst buildAttrsClark = (attrs: SaxesOpenTag['attributes']): Record<string, string> => {\n const out: Record<string, string> = {};\n for (const [, info] of Object.entries(attrs)) {\n // saxes already resolved the namespace when xmlns: true is set; raw xmlns /\n // xmlns:* declarations have prefix='xmlns' (or local==='xmlns' when\n // default) and we drop those — they're rebuilt by the serializer.\n if (info.prefix === 'xmlns' || (info.prefix === '' && info.local === 'xmlns')) continue;\n const key = qname(info.uri, info.local);\n out[key] = info.value;\n }\n return out;\n};\n\n/**\n * Parse the input as a stream of SAX events. Element / attribute names are\n * returned in Clark notation (`{ns}local`).\n */\nexport async function* iterParse(input: SaxInput): AsyncIterableIterator<SaxEvent> {\n // Set up the parser. xmlns: true gives us resolved {uri, local, prefix} on\n // every open / close tag and on every attribute.\n const parser = new SaxesParser({ xmlns: true, fragment: false });\n\n // Head-pointer ring instead of Array#shift: each saxes write() can produce\n // hundreds of events in a single synchronous batch (a `<row>` with dozens of\n // cells flushes one opentag + one text + one closetag per cell). `shift()`\n // is O(n) per element in V8, so a single-batch drain of N events would be\n // O(N²) before iteration. The head advances on yield; the queue is reset\n // (head + length) once it drains so memory stays bounded.\n let queue: SaxEvent[] = [];\n let head = 0;\n let pending: Error | undefined;\n\n parser.on('error', (err: Error) => {\n pending = err;\n });\n parser.on('doctype', () => {\n pending = new OpenXmlSchemaError('DTD declarations are not permitted in OOXML payloads');\n });\n parser.on('opentag', (node: SaxesOpenTag) => {\n queue.push({ kind: 'start', name: qname(node.uri, node.local), attrs: buildAttrsClark(node.attributes) });\n });\n parser.on('closetag', (node: SaxesCloseTag) => {\n queue.push({ kind: 'end', name: qname(node.uri, node.local) });\n });\n parser.on('text', (text: string) => {\n if (text.length > 0) queue.push({ kind: 'text', text });\n });\n\n const drain = function* (): IterableIterator<SaxEvent> {\n for (;;) {\n const ev = head < queue.length ? queue[head] : undefined;\n if (ev === undefined) {\n // Reset rather than grow forever; the next batch starts at index 0.\n queue = [];\n head = 0;\n return;\n }\n head++;\n yield ev;\n }\n };\n\n const feed = (chunk: string): void => {\n parser.write(chunk);\n if (pending !== undefined) throw pending;\n };\n\n if (typeof input === 'string') {\n checkDoctype(input);\n feed(input);\n } else if (input instanceof Uint8Array) {\n const text = decoder().decode(input);\n checkDoctype(text);\n feed(text);\n yield* drain();\n } else if (isReadableStream(input)) {\n const reader = input.getReader();\n const td = decoder();\n let firstChunkChecked = false;\n let firstChunkBuffer = '';\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n const chunk = td.decode(value, { stream: true });\n if (!firstChunkChecked) {\n // We need to see enough of the prologue to be sure no DOCTYPE is\n // hiding. Buffer until we have ~256 chars; if the stream ends before\n // we reach the threshold the tail handler below runs `checkDoctype`\n // on the accumulated prologue. (The previous `|| done` here was dead:\n // a true `done` short-circuits at the top of the loop.)\n firstChunkBuffer += chunk;\n if (firstChunkBuffer.length >= 256) {\n checkDoctype(firstChunkBuffer);\n firstChunkChecked = true;\n feed(firstChunkBuffer);\n yield* drain();\n }\n } else {\n feed(chunk);\n yield* drain();\n }\n }\n // Stream ended; flush decoder + any buffered prologue.\n const tail = td.decode();\n if (!firstChunkChecked) {\n const all = firstChunkBuffer + tail;\n checkDoctype(all);\n feed(all);\n yield* drain();\n } else if (tail.length > 0) {\n feed(tail);\n yield* drain();\n }\n } else {\n throw new OpenXmlSchemaError('iterParse: unsupported input type');\n }\n\n parser.close();\n if (pending !== undefined) throw pending;\n yield* drain();\n}\n","// Fast UTF-8 byte-length scan. Used by streaming writers to decide when their\n// pending string buffer should be encoded + flushed.\n//\n// `s.length` returns UTF-16 code units, which undercounts BMP characters above\n// U+007F (1 code unit, 2 UTF-8 bytes for U+0080–U+07FF, 3 bytes for the rest\n// of the BMP). For CJK-heavy payloads the discrepancy is ~3× — large enough\n// to push a \"64 KB\" flush threshold to 192 KB of resident text. We scan the\n// string once and account for each codepoint instead of running a full\n// TextEncoder, which would also have to materialise the byte buffer we don't\n// need yet.\nexport function utf8ByteLength(s: string): number {\n let n = 0;\n for (let i = 0; i < s.length; i++) {\n const c = s.charCodeAt(i);\n if (c < 0x80) {\n n += 1;\n } else if (c < 0x800) {\n n += 2;\n } else if (c >= 0xd800 && c <= 0xdbff) {\n // High surrogate. Only consume the next code unit when it actually\n // is a low surrogate — an unpaired high surrogate (followed by a\n // BMP char or by EOS) would otherwise swallow the next code unit\n // and undercount the string. TextEncoder replaces a lone high\n // surrogate with U+FFFD (3 bytes), so use 3 here too. A paired\n // surrogate encodes one 4-byte codepoint.\n const next = i + 1 < s.length ? s.charCodeAt(i + 1) : 0;\n if (next >= 0xdc00 && next <= 0xdfff) {\n n += 4;\n i++;\n } else {\n n += 3;\n }\n } else {\n // Includes unpaired low surrogates (0xDC00-0xDFFF), which encode as\n // U+FFFD = 3 UTF-8 bytes through TextEncoder.\n n += 3;\n }\n }\n return n;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"utf8-Tn3nzyik.mjs","names":[],"sources":["../src/xml/iterparse.ts","../src/utils/utf8.ts"],"sourcesContent":["// SAX iterator over OOXML XML payloads. Wraps `saxes` (XMLNS-aware) and yields\n// a flat stream of {start | end | text} events with names already converted to\n// Clark notation (`{ns}local`) — same shape as the DOM parser produces for\n// static XmlNode trees, so consumers can switch between bulk and streaming\n// reads without retouching name comparison.\n//\n// Phase 1 §3 acceptance: 1 k–row sheetData walked end-to-end with cell counts\n// matching the source. The phase-4 read-only worksheet drives real-world use;\n// this layer just produces the events.\n//\n// DOCTYPE / external entity declarations are forbidden. saxes does not expand\n// external entities, but a prescan also rejects DTDs in non-streaming inputs.\n// Streaming inputs are checked on the first chunk before being fed to the\n// parser.\n\nimport { SaxesParser } from 'saxes';\nimport { OpenXmlSchemaError } from '../utils/exceptions.js';\nimport { qname } from './namespaces.js';\n\nexport type SaxEvent =\n | { kind: 'start'; name: string; attrs: Record<string, string> }\n | { kind: 'end'; name: string }\n | { kind: 'text'; text: string };\n\n/**\n * Streamable input: `Uint8Array`, plain string, or a Web `ReadableStream` of\n * `Uint8Array` chunks (produced by xlsx zip entries via fflate, fetch, file\n * streams, etc.).\n */\nexport type SaxInput = Uint8Array | string | ReadableStream<Uint8Array>;\n\nconst DOCTYPE_RE = /<!DOCTYPE\\b/;\nconst ENTITY_RE = /<!ENTITY\\b/;\n\nconst checkDoctype = (text: string): void => {\n if (DOCTYPE_RE.test(text)) {\n throw new OpenXmlSchemaError('DTD declarations are not permitted in OOXML payloads');\n }\n if (ENTITY_RE.test(text)) {\n throw new OpenXmlSchemaError('Entity declarations are not permitted in OOXML payloads');\n }\n};\n\nconst isReadableStream = (v: unknown): v is ReadableStream<Uint8Array> => {\n return typeof v === 'object' && v !== null && typeof (v as ReadableStream).getReader === 'function';\n};\n\nconst decoder = (): TextDecoder => new TextDecoder('utf-8', { fatal: false });\n\ninterface SaxesOpenTag {\n name: string;\n uri: string;\n local: string;\n prefix: string;\n attributes: Record<string, { value: string; uri: string; local: string; prefix: string }>;\n isSelfClosing?: boolean;\n}\n\ninterface SaxesCloseTag {\n name: string;\n uri: string;\n local: string;\n prefix: string;\n}\n\nconst buildAttrsClark = (attrs: SaxesOpenTag['attributes']): Record<string, string> => {\n const out: Record<string, string> = {};\n for (const [, info] of Object.entries(attrs)) {\n // saxes already resolved the namespace when xmlns: true is set; raw xmlns /\n // xmlns:* declarations have prefix='xmlns' (or local==='xmlns' when\n // default) and we drop those — they're rebuilt by the serializer.\n if (info.prefix === 'xmlns' || (info.prefix === '' && info.local === 'xmlns')) continue;\n const key = qname(info.uri, info.local);\n out[key] = info.value;\n }\n return out;\n};\n\n/**\n * Parse the input as a stream of SAX events. Element / attribute names are\n * returned in Clark notation (`{ns}local`).\n */\nexport async function* iterParse(input: SaxInput): AsyncIterableIterator<SaxEvent> {\n // Set up the parser. xmlns: true gives us resolved {uri, local, prefix} on\n // every open / close tag and on every attribute.\n const parser = new SaxesParser({ xmlns: true, fragment: false });\n\n // Head-pointer ring instead of Array#shift: each saxes write() can produce\n // hundreds of events in a single synchronous batch (a `<row>` with dozens of\n // cells flushes one opentag + one text + one closetag per cell). `shift()`\n // is O(n) per element in V8, so a single-batch drain of N events would be\n // O(N²) before iteration. The head advances on yield; the queue is reset\n // (head + length) once it drains so memory stays bounded.\n let queue: SaxEvent[] = [];\n let head = 0;\n let pending: Error | undefined;\n\n parser.on('error', (err: Error) => {\n pending = err;\n });\n parser.on('doctype', () => {\n pending = new OpenXmlSchemaError('DTD declarations are not permitted in OOXML payloads');\n });\n parser.on('opentag', (node: SaxesOpenTag) => {\n queue.push({ kind: 'start', name: qname(node.uri, node.local), attrs: buildAttrsClark(node.attributes) });\n });\n parser.on('closetag', (node: SaxesCloseTag) => {\n queue.push({ kind: 'end', name: qname(node.uri, node.local) });\n });\n parser.on('text', (text: string) => {\n if (text.length > 0) queue.push({ kind: 'text', text });\n });\n\n const drain = function* (): IterableIterator<SaxEvent> {\n for (;;) {\n const ev = head < queue.length ? queue[head] : undefined;\n if (ev === undefined) {\n // Reset rather than grow forever; the next batch starts at index 0.\n queue = [];\n head = 0;\n return;\n }\n head++;\n yield ev;\n }\n };\n\n const feed = (chunk: string): void => {\n parser.write(chunk);\n if (pending !== undefined) throw pending;\n };\n\n if (typeof input === 'string') {\n checkDoctype(input);\n feed(input);\n } else if (input instanceof Uint8Array) {\n const text = decoder().decode(input);\n checkDoctype(text);\n feed(text);\n yield* drain();\n } else if (isReadableStream(input)) {\n const reader = input.getReader();\n const td = decoder();\n let firstChunkChecked = false;\n let firstChunkBuffer = '';\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n const chunk = td.decode(value, { stream: true });\n if (!firstChunkChecked) {\n // We need to see enough of the prologue to be sure no DOCTYPE is\n // hiding. Buffer until we have ~256 chars; if the stream ends before\n // we reach the threshold the tail handler below runs `checkDoctype`\n // on the accumulated prologue. (The previous `|| done` here was dead:\n // a true `done` short-circuits at the top of the loop.)\n firstChunkBuffer += chunk;\n if (firstChunkBuffer.length >= 256) {\n checkDoctype(firstChunkBuffer);\n firstChunkChecked = true;\n feed(firstChunkBuffer);\n yield* drain();\n }\n } else {\n feed(chunk);\n yield* drain();\n }\n }\n // Stream ended; flush decoder + any buffered prologue.\n const tail = td.decode();\n if (!firstChunkChecked) {\n const all = firstChunkBuffer + tail;\n checkDoctype(all);\n feed(all);\n yield* drain();\n } else if (tail.length > 0) {\n feed(tail);\n yield* drain();\n }\n } else {\n throw new OpenXmlSchemaError('iterParse: unsupported input type');\n }\n\n parser.close();\n if (pending !== undefined) throw pending;\n yield* drain();\n}\n","// Fast UTF-8 byte-length scan. Used by streaming writers to decide when their\n// pending string buffer should be encoded + flushed.\n//\n// `s.length` returns UTF-16 code units, which undercounts BMP characters above\n// U+007F (1 code unit, 2 UTF-8 bytes for U+0080–U+07FF, 3 bytes for the rest\n// of the BMP). For CJK-heavy payloads the discrepancy is ~3× — large enough\n// to push a \"64 KB\" flush threshold to 192 KB of resident text. We scan the\n// string once and account for each codepoint instead of running a full\n// TextEncoder, which would also have to materialise the byte buffer we don't\n// need yet.\nexport function utf8ByteLength(s: string): number {\n let n = 0;\n for (let i = 0; i < s.length; i++) {\n const c = s.charCodeAt(i);\n if (c < 0x80) {\n n += 1;\n } else if (c < 0x800) {\n n += 2;\n } else if (c >= 0xd800 && c <= 0xdbff) {\n // High surrogate. Only consume the next code unit when it actually\n // is a low surrogate — an unpaired high surrogate (followed by a\n // BMP char or by EOS) would otherwise swallow the next code unit\n // and undercount the string. TextEncoder replaces a lone high\n // surrogate with U+FFFD (3 bytes), so use 3 here too. A paired\n // surrogate encodes one 4-byte codepoint.\n const next = i + 1 < s.length ? s.charCodeAt(i + 1) : 0;\n if (next >= 0xdc00 && next <= 0xdfff) {\n n += 4;\n i++;\n } else {\n n += 3;\n }\n } else {\n // Includes unpaired low surrogates (0xDC00-0xDFFF), which encode as\n // U+FFFD = 3 UTF-8 bytes through TextEncoder.\n n += 3;\n }\n }\n return n;\n}\n"],"mappings":"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"}
@@ -25,10 +25,8 @@ export declare function escapeXmlText(s: string): string;
25
25
  *
26
26
  * Note: this deliberately does NOT escape `\r` / `\n` / `\t` to numeric
27
27
  * character references. XML 1.0 attribute-value normalisation would
28
- * collapse them to spaces in theory, but the parser used on the read side
29
- * (fast-xml-parser) does not decode numeric character references, so a
30
- * write-then-read round-trip would surface the literal `&#9;` instead of
31
- * recovering the original tab. Leaving the whitespace bytes literal keeps
32
- * the round-trip stable and matches what Excel itself emits.
28
+ * collapses them to spaces, but the DOM read path (fast-xml-parser) does not
29
+ * apply that normalisation, so the literal bytes round-trip through
30
+ * `loadWorkbook`. Leaving them literal also matches what Excel itself emits.
33
31
  */
34
32
  export declare function escapeXmlAttr(s: string): string;
@@ -1,11 +1,11 @@
1
- export type { CellCoordinate, CellCoordinateNumeric, CellRangeBoundaries } from './coordinate';
2
- export { boundariesToRangeString, columnIndexFromLetter, columnLetterFromIndex, coordinateFromString, coordinateToTuple, formatSheetQualifiedRef, isValidCellRef, isValidColumnLetter, isValidColumnNumber, isValidRangeRef, isValidRowNumber, MAX_COL, MAX_ROW, parseSheetRange, rangeBoundaries, tupleToCoordinate, } from './coordinate';
3
- export type { ExcelEpoch } from './datetime';
4
- export { dateToExcel, durationToExcel, excelToDate, excelToDuration, fromIso8601, MAC_EPOCH_MS, toIso8601, WINDOWS_EPOCH_MS, } from './datetime';
5
- export { cssRecordToInlineStyle } from './css';
6
- export { escapeCellString, unescapeCellString } from './escape';
7
- export type { OpenXmlErrorOptions } from './exceptions';
8
- export { OpenXmlDecompressionBombError, OpenXmlError, OpenXmlInvalidWorkbookError, OpenXmlIoError, OpenXmlNotImplementedError, OpenXmlSchemaError, } from './exceptions';
9
- export type { CellDataType } from './inference';
10
- export { ERROR_CODES, inferCellType } from './inference';
11
- export { cmFromEmu, EMU_PER_CM, EMU_PER_INCH, EMU_PER_PIXEL, EMU_PER_POINT, emuFromCm, emuFromInch, emuFromPoint, emuFromPx, inchFromEmu, pixelToPoint, pointFromEmu, pointToPixel, pxFromEmu, } from './units';
1
+ export type { CellCoordinate, CellCoordinateNumeric, CellRangeBoundaries } from './coordinate.js';
2
+ export { boundariesToRangeString, columnIndexFromLetter, columnLetterFromIndex, coordinateFromString, coordinateToTuple, formatSheetQualifiedRef, isValidCellRef, isValidColumnLetter, isValidColumnNumber, isValidRangeRef, isValidRowNumber, MAX_COL, MAX_ROW, parseSheetRange, rangeBoundaries, tupleToCoordinate, } from './coordinate.js';
3
+ export type { ExcelEpoch } from './datetime.js';
4
+ export { dateToExcel, durationToExcel, excelToDate, excelToDuration, fromIso8601, MAC_EPOCH_MS, toIso8601, WINDOWS_EPOCH_MS, } from './datetime.js';
5
+ export { cssRecordToInlineStyle } from './css.js';
6
+ export { escapeCellString, unescapeCellString } from './escape.js';
7
+ export type { OpenXmlErrorOptions } from './exceptions.js';
8
+ export { OpenXmlDecompressionBombError, OpenXmlError, OpenXmlInvalidWorkbookError, OpenXmlIoError, OpenXmlNotImplementedError, OpenXmlSchemaError, } from './exceptions.js';
9
+ export type { CellDataType } from './inference.js';
10
+ export { ERROR_CODES, inferCellType } from './inference.js';
11
+ export { cmFromEmu, EMU_PER_CM, EMU_PER_INCH, EMU_PER_PIXEL, EMU_PER_POINT, emuFromCm, emuFromInch, emuFromPoint, emuFromPx, inchFromEmu, pixelToPoint, pointFromEmu, pointToPixel, pxFromEmu, } from './units.js';
package/dist/utils.mjs CHANGED
@@ -2,7 +2,7 @@ import { a as OpenXmlNotImplementedError, i as OpenXmlIoError, n as OpenXmlError
2
2
  import { a as columnLetterFromIndex, c as formatSheetQualifiedRef, d as isValidColumnNumber, f as isValidRangeRef, g as tupleToCoordinate, h as rangeBoundaries, i as columnIndexFromLetter, l as isValidCellRef, m as parseSheetRange, n as MAX_ROW, o as coordinateFromString, p as isValidRowNumber, r as boundariesToRangeString, s as coordinateToTuple, t as MAX_COL, u as isValidColumnLetter } from "./coordinate-96Ecci4d.mjs";
3
3
  import { n as inferCellType, t as ERROR_CODES } from "./inference-BrI9uIY4.mjs";
4
4
  import { a as cmFromEmu, c as emuFromPoint, d as pixelToPoint, f as pointFromEmu, i as EMU_PER_POINT, l as emuFromPx, m as pxFromEmu, n as EMU_PER_INCH, o as emuFromCm, p as pointToPixel, r as EMU_PER_PIXEL, s as emuFromInch, t as EMU_PER_CM, u as inchFromEmu } from "./units-rOMQqXh2.mjs";
5
- import { i as unescapeCellString, t as escapeCellString } from "./escape-DFTE7ZJc.mjs";
5
+ import { i as unescapeCellString, t as escapeCellString } from "./escape-rnWSPpWY.mjs";
6
6
  import { a as excelToDate, c as toIso8601, i as durationToExcel, n as WINDOWS_EPOCH_MS, o as excelToDuration, r as dateToExcel, s as fromIso8601, t as MAC_EPOCH_MS } from "./datetime-B2ySVlXt.mjs";
7
7
  //#region src/utils/css.ts
8
8
  /**
@@ -23,7 +23,7 @@ export interface CalcProperties {
23
23
  forceFullCalc?: boolean;
24
24
  }
25
25
  export declare const makeCalcProperties: (opts?: CalcProperties) => CalcProperties;
26
- import type { Workbook } from './workbook';
26
+ import type { Workbook } from './workbook.js';
27
27
  /**
28
28
  * Set the recalculation mode. `'auto'` is Excel's default;
29
29
  * `'manual'` requires F9 to recompute formulas; `'autoNoTable'`