@office-kit/xlsx 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/{cell-D9CaNKnU.mjs → cell-BucgGwl3.mjs} +2 -2
  2. package/dist/{cell-D9CaNKnU.mjs.map → cell-BucgGwl3.mjs.map} +1 -1
  3. package/dist/{cell-style-BEDjMX1y.mjs → cell-style-CN9JXOwm.mjs} +8 -6
  4. package/dist/cell-style-CN9JXOwm.mjs.map +1 -0
  5. package/dist/cell.mjs +1 -1
  6. package/dist/coordinate-96Ecci4d.mjs.map +1 -1
  7. package/dist/datetime-B2ySVlXt.mjs.map +1 -1
  8. package/dist/{differential-D4dg-qtZ.mjs → differential-YEjxNScf.mjs} +2 -2
  9. package/dist/{differential-D4dg-qtZ.mjs.map → differential-YEjxNScf.mjs.map} +1 -1
  10. package/dist/drawing-BxzLuryn.mjs.map +1 -1
  11. package/dist/escape-DFTE7ZJc.mjs.map +1 -1
  12. package/dist/{inference-B3ES3KEJ.mjs → inference-BrI9uIY4.mjs} +2 -2
  13. package/dist/{inference-B3ES3KEJ.mjs.map → inference-BrI9uIY4.mjs.map} +1 -1
  14. package/dist/io.mjs +4 -4
  15. package/dist/io.mjs.map +1 -1
  16. package/dist/{load-D5cbhoGx.mjs → load-BG5-CtPk.mjs} +10 -10
  17. package/dist/{load-D5cbhoGx.mjs.map → load-BG5-CtPk.mjs.map} +1 -1
  18. package/dist/{manifest-Dps1-OpP.mjs → manifest-CVL1_t0O.mjs} +7 -5
  19. package/dist/{manifest-Dps1-OpP.mjs.map → manifest-CVL1_t0O.mjs.map} +1 -1
  20. package/dist/node.mjs +3 -3
  21. package/dist/node.mjs.map +1 -1
  22. package/dist/packaging.mjs +1 -1
  23. package/dist/{parser-DuLejQy1.mjs → parser-nk0Lqmcb.mjs} +3 -2
  24. package/dist/{parser-DuLejQy1.mjs.map → parser-nk0Lqmcb.mjs.map} +1 -1
  25. package/dist/{reader-D1fNW9k1.mjs → reader-BNaUTVCy.mjs} +3 -2
  26. package/dist/{reader-D1fNW9k1.mjs.map → reader-BNaUTVCy.mjs.map} +1 -1
  27. package/dist/{save-RohQtgEZ.mjs → save-BcpDpE90.mjs} +7 -7
  28. package/dist/{save-RohQtgEZ.mjs.map → save-BcpDpE90.mjs.map} +1 -1
  29. package/dist/{serializer-BwbgHYJV.mjs → serializer-DQzTTNOS.mjs} +2 -2
  30. package/dist/{serializer-BwbgHYJV.mjs.map → serializer-DQzTTNOS.mjs.map} +1 -1
  31. package/dist/streaming.mjs +13 -11
  32. package/dist/streaming.mjs.map +1 -1
  33. package/dist/styles/borders.d.ts +1 -1
  34. package/dist/styles.mjs +3 -3
  35. package/dist/{stylesheet-writer-C2eRmn22.mjs → stylesheet-writer-P1Hxoqzm.mjs} +32 -26
  36. package/dist/{stylesheet-writer-C2eRmn22.mjs.map → stylesheet-writer-P1Hxoqzm.mjs.map} +1 -1
  37. package/dist/{table-DkX6UniA.mjs → table-BifavDVW.mjs} +2 -2
  38. package/dist/{table-DkX6UniA.mjs.map → table-BifavDVW.mjs.map} +1 -1
  39. package/dist/utf8-D91g1XTG.mjs.map +1 -1
  40. package/dist/utils.mjs +1 -1
  41. package/dist/utils.mjs.map +1 -1
  42. package/dist/{workbook-HGYNRBlV.mjs → workbook-T1Y3lstQ.mjs} +5 -5
  43. package/dist/{workbook-HGYNRBlV.mjs.map → workbook-T1Y3lstQ.mjs.map} +1 -1
  44. package/dist/workbook.mjs +1 -1
  45. package/dist/{worksheet-CmCNoIgD.mjs → worksheet-C6CWgvP5.mjs} +2 -2
  46. package/dist/{worksheet-CmCNoIgD.mjs.map → worksheet-C6CWgvP5.mjs.map} +1 -1
  47. package/dist/worksheet.mjs +2 -2
  48. package/dist/{writer-DspzfkNA.mjs → writer-IyFccCRJ.mjs} +3 -3
  49. package/dist/{writer-DspzfkNA.mjs.map → writer-IyFccCRJ.mjs.map} +1 -1
  50. package/dist/xml.mjs +2 -2
  51. package/dist/zip.mjs +2 -2
  52. package/package.json +23 -31
  53. package/dist/cell-style-BEDjMX1y.mjs.map +0 -1
@@ -1,4 +1,4 @@
1
- import { Sn as parseMultiCellRange } from "./worksheet-CmCNoIgD.mjs";
1
+ import { Sn as parseMultiCellRange } from "./worksheet-C6CWgvP5.mjs";
2
2
  //#region src/worksheet/conditional-formatting.ts
3
3
  function makeConditionalFormatting(opts) {
4
4
  return {
@@ -110,4 +110,4 @@ const addExcelTable = (wb, ws, opts) => {
110
110
  //#endregion
111
111
  export { makeCfRule as a, makeDataValidation as i, makeTableColumn as n, makeConditionalFormatting as o, makeTableDefinition as r, addExcelTable as t };
112
112
 
113
- //# sourceMappingURL=table-DkX6UniA.mjs.map
113
+ //# sourceMappingURL=table-BifavDVW.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"table-DkX6UniA.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":"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"}
1
+ {"version":3,"file":"table-BifavDVW.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":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"utf8-D91g1XTG.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-D91g1XTG.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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"}
package/dist/utils.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { a as OpenXmlNotImplementedError, i as OpenXmlIoError, n as OpenXmlError, o as OpenXmlSchemaError, r as OpenXmlInvalidWorkbookError, t as OpenXmlDecompressionBombError } from "./exceptions-D-CFwxgm.mjs";
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
- import { n as inferCellType, t as ERROR_CODES } from "./inference-B3ES3KEJ.mjs";
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
5
  import { i as unescapeCellString, t as escapeCellString } from "./escape-DFTE7ZJc.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";
@@ -1 +1 @@
1
- {"version":3,"file":"utils.mjs","names":[],"sources":["../src/utils/css.ts"],"sourcesContent":["// CSS-record → inline-style serializer.\n//\n// Companion to the `*ToCss` style helpers (fontToCss / fillToCss /\n// borderToCss / alignmentToCss / cellStyleToCss): once a caller has\n// merged the partials into a `Record<string, string>`, this turns it\n// into a stable `style=\"…\"` attribute value for HTML preview.\n\n/**\n * Serialize a CSS-property record to an inline-style declaration string\n * (`prop1: val1; prop2: val2`). Properties are alphabetised so the\n * output is deterministic across runs.\n *\n * - Empty record returns `''`.\n * - Empty-string values are skipped (treat as \"unset\").\n * - Values containing `;` are dropped — they would terminate the\n * declaration early and risk attribute-injection in `style=\"…\"`\n * contexts. Callers should pre-escape user data; this is a\n * defensive last line.\n *\n * The returned string is suitable for direct interpolation into an\n * HTML `style=\"…\"` attribute *after* the usual attribute-value HTML\n * escaping (no `&` / `\"` injection here — this only guards against\n * stray semicolons).\n */\nexport function cssRecordToInlineStyle(record: Record<string, string> | undefined): string {\n if (!record) return '';\n const parts: string[] = [];\n for (const key of Object.keys(record).sort()) {\n const value = record[key];\n if (value === undefined || value === '') continue;\n if (value.includes(';')) continue;\n parts.push(`${key}: ${value}`);\n }\n return parts.join('; ');\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAwBA,SAAgB,uBAAuB,QAAoD;CACzF,IAAI,CAAC,QAAQ,OAAO;CACpB,MAAM,QAAkB,CAAC;CACzB,KAAK,MAAM,OAAO,OAAO,KAAK,MAAM,EAAE,KAAK,GAAG;EAC5C,MAAM,QAAQ,OAAO;EACrB,IAAI,UAAU,KAAA,KAAa,UAAU,IAAI;EACzC,IAAI,MAAM,SAAS,GAAG,GAAG;EACzB,MAAM,KAAK,GAAG,IAAI,IAAI,OAAO;CAC/B;CACA,OAAO,MAAM,KAAK,IAAI;AACxB"}
1
+ {"version":3,"file":"utils.mjs","names":[],"sources":["../src/utils/css.ts"],"sourcesContent":["// CSS-record → inline-style serializer.\n//\n// Companion to the `*ToCss` style helpers (fontToCss / fillToCss /\n// borderToCss / alignmentToCss / cellStyleToCss): once a caller has\n// merged the partials into a `Record<string, string>`, this turns it\n// into a stable `style=\"…\"` attribute value for HTML preview.\n\n/**\n * Serialize a CSS-property record to an inline-style declaration string\n * (`prop1: val1; prop2: val2`). Properties are alphabetised so the\n * output is deterministic across runs.\n *\n * - Empty record returns `''`.\n * - Empty-string values are skipped (treat as \"unset\").\n * - Values containing `;` are dropped — they would terminate the\n * declaration early and risk attribute-injection in `style=\"…\"`\n * contexts. Callers should pre-escape user data; this is a\n * defensive last line.\n *\n * The returned string is suitable for direct interpolation into an\n * HTML `style=\"…\"` attribute *after* the usual attribute-value HTML\n * escaping (no `&` / `\"` injection here — this only guards against\n * stray semicolons).\n */\nexport function cssRecordToInlineStyle(record: Record<string, string> | undefined): string {\n if (!record) return '';\n const parts: string[] = [];\n for (const key of Object.keys(record).sort()) {\n const value = record[key];\n if (value === undefined || value === '') continue;\n if (value.includes(';')) continue;\n parts.push(`${key}: ${value}`);\n }\n return parts.join('; ');\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAwBA,SAAgB,uBAAuB,QAAoD;CACzF,IAAI,CAAC,QAAQ,OAAO;CACpB,MAAM,QAAkB,CAAC;CACzB,KAAK,MAAM,OAAO,OAAO,KAAK,MAAM,CAAC,CAAC,KAAK,GAAG;EAC5C,MAAM,QAAQ,OAAO;EACrB,IAAI,UAAU,KAAA,KAAa,UAAU,IAAI;EACzC,IAAI,MAAM,SAAS,GAAG,GAAG;EACzB,MAAM,KAAK,GAAG,IAAI,IAAI,OAAO;CAC/B;CACA,OAAO,MAAM,KAAK,IAAI;AACxB"}
@@ -1,13 +1,13 @@
1
1
  import { o as OpenXmlSchemaError } from "./exceptions-D-CFwxgm.mjs";
2
2
  import { m as parseSheetRange, s as coordinateToTuple } from "./coordinate-96Ecci4d.mjs";
3
- import { h as isFormulaValue } from "./cell-D9CaNKnU.mjs";
3
+ import { h as isFormulaValue } from "./cell-BucgGwl3.mjs";
4
4
  import { t as makeChartsheet } from "./chartsheet-C3-tqkPy.mjs";
5
5
  import { a as makeChartDrawingItem, d as makeAbsoluteAnchor, o as makeDrawing } from "./drawing-BxzLuryn.mjs";
6
6
  import { i as unescapeCellString, n as escapeXmlAttr, r as escapeXmlText, t as escapeCellString } from "./escape-DFTE7ZJc.mjs";
7
7
  import { a as findChildren, ft as SHEET_MAIN_NS, i as findChild, jt as qname } from "./tree-Bbs1C8Rc.mjs";
8
- import { t as parseXml } from "./parser-DuLejQy1.mjs";
9
- import { Cn as parseRange, D as getCellHyperlink, Dn as rangeToString, E as getCellComment, L as getMergedRangeAt, Tn as rangeContainsCell, _ as countCellsByKind, at as makeWorksheet, bn as multiCellRangeContainsCell, nn as colorToHex, u as classifyCellValue, w as getCell, xt as setCellByCoord } from "./worksheet-CmCNoIgD.mjs";
10
- import { _ as getCellNumberFormat, ft as makeStylesheet, g as getCellFont, h as getCellFill, m as getCellBorder, p as getCellAlignment, v as getCellProtection } from "./cell-style-BEDjMX1y.mjs";
8
+ import { t as parseXml } from "./parser-nk0Lqmcb.mjs";
9
+ import { Cn as parseRange, D as getCellHyperlink, Dn as rangeToString, E as getCellComment, L as getMergedRangeAt, Tn as rangeContainsCell, _ as countCellsByKind, at as makeWorksheet, bn as multiCellRangeContainsCell, nn as colorToHex, u as classifyCellValue, w as getCell, xt as setCellByCoord } from "./worksheet-C6CWgvP5.mjs";
10
+ import { _ as getCellNumberFormat, ft as makeStylesheet, g as getCellFont, h as getCellFill, m as getCellBorder, p as getCellAlignment, v as getCellProtection } from "./cell-style-CN9JXOwm.mjs";
11
11
  //#region src/workbook/shared-strings.ts
12
12
  const SST_TAG = `{${SHEET_MAIN_NS}}sst`;
13
13
  const SI_TAG = `{${SHEET_MAIN_NS}}si`;
@@ -633,4 +633,4 @@ function listCustomXmlParts(wb) {
633
633
  //#endregion
634
634
  export { sharedStringsToBytes as A, addSharedString as C, parseSharedStringsXml as D, makeSharedStrings as E, serializeRichTextRuns as O, validateSheetTitle as S, getSharedStringIndex as T, renameSheet as _, getActiveSheet as a, setSheetState as b, getChartsheet as c, getWorkbookCellsByKind as d, getWorkbookStats as f, removeSheet as g, moveSheet as h, describeWorkbook as i, sharedStringCount as k, getSheet as l, listCustomXmlParts as m, addWorksheet as n, getCellAtAddress as o, iterWorksheets as p, createWorkbook as r, getCellSummary as s, addChartsheet as t, getSheetState as u, setActiveSheet as v, getSharedStringAt as w, sheetNames as x, setCellAtAddress as y };
635
635
 
636
- //# sourceMappingURL=workbook-HGYNRBlV.mjs.map
636
+ //# sourceMappingURL=workbook-T1Y3lstQ.mjs.map