@office-kit/xlsx 0.17.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -4
- package/dist/{cell-style-DjKKPWDL.mjs → cell-style-CbB4nXTY.mjs} +11 -4
- package/dist/cell-style-CbB4nXTY.mjs.map +1 -0
- package/dist/{differential-7KGzbliB.mjs → differential-QLaKEiBk.mjs} +2 -2
- package/dist/{differential-7KGzbliB.mjs.map → differential-QLaKEiBk.mjs.map} +1 -1
- package/dist/io/load.d.ts +2 -0
- package/dist/io.mjs +2 -2
- package/dist/{iterparse-DZE0zy2M.mjs → iterparse-CZoRXvZW.mjs} +2 -2
- package/dist/{iterparse-DZE0zy2M.mjs.map → iterparse-CZoRXvZW.mjs.map} +1 -1
- package/dist/{load-DIdQ_zum.mjs → load-BpnCPv1S.mjs} +25 -13
- package/dist/load-BpnCPv1S.mjs.map +1 -0
- package/dist/{manifest-BHUYpjUG.mjs → manifest-9p0ccqmR.mjs} +10 -11
- package/dist/manifest-9p0ccqmR.mjs.map +1 -0
- package/dist/node.mjs +1 -1
- package/dist/packaging.mjs +1 -1
- package/dist/{parser-By6RWZVW.mjs → parser-B1tB9YaE.mjs} +15 -5
- package/dist/parser-B1tB9YaE.mjs.map +1 -0
- package/dist/{save-ax11Gsw0.mjs → save-1Z3344nz.mjs} +6 -6
- package/dist/{save-ax11Gsw0.mjs.map → save-1Z3344nz.mjs.map} +1 -1
- package/dist/schema.mjs +1 -1
- package/dist/{serialize-Dmb6Vtt9.mjs → serialize-BtxgssFK.mjs} +2 -2
- package/dist/{serialize-Dmb6Vtt9.mjs.map → serialize-BtxgssFK.mjs.map} +1 -1
- package/dist/{serializer-dhv07Z6F.mjs → serializer-N6XIwsgp.mjs} +2 -2
- package/dist/{serializer-dhv07Z6F.mjs.map → serializer-N6XIwsgp.mjs.map} +1 -1
- package/dist/streaming.mjs +34 -17
- package/dist/streaming.mjs.map +1 -1
- package/dist/styles/display-text.d.ts +95 -0
- package/dist/styles/format-code.d.ts +125 -0
- package/dist/styles/index.d.ts +1 -0
- package/dist/styles/numbers.d.ts +7 -0
- package/dist/styles.mjs +1161 -4
- package/dist/styles.mjs.map +1 -0
- package/dist/{stylesheet-writer-BBYjNSMA.mjs → stylesheet-writer-BEn-0P0x.mjs} +341 -105
- package/dist/stylesheet-writer-BEn-0P0x.mjs.map +1 -0
- package/dist/{table-BFi2WmgG.mjs → table-BxOLUZs3.mjs} +2 -2
- package/dist/{table-BFi2WmgG.mjs.map → table-BxOLUZs3.mjs.map} +1 -1
- package/dist/{tree-BX-sRRVp.mjs → tree-CspNjuYl.mjs} +12 -2
- package/dist/tree-CspNjuYl.mjs.map +1 -0
- package/dist/workbook/index.d.ts +1 -1
- package/dist/workbook/workbook.d.ts +9 -46
- package/dist/{workbook-CMel6UcI.mjs → workbook-tG9oYtzU.mjs} +46 -9
- package/dist/workbook-tG9oYtzU.mjs.map +1 -0
- package/dist/workbook.mjs +2 -2
- package/dist/worksheet/index.d.ts +1 -1
- package/dist/worksheet/worksheet.d.ts +55 -14
- package/dist/{worksheet-Cxn2c-jz.mjs → worksheet-DLMyDD7W.mjs} +85 -20
- package/dist/worksheet-DLMyDD7W.mjs.map +1 -0
- package/dist/worksheet.mjs +3 -3
- package/dist/xml/namespaces.d.ts +7 -0
- package/dist/xml/parser.d.ts +12 -0
- package/dist/xml/strict-package.d.ts +14 -0
- package/dist/xml.mjs +4 -4
- package/package.json +1 -1
- package/dist/cell-style-DjKKPWDL.mjs.map +0 -1
- package/dist/load-DIdQ_zum.mjs.map +0 -1
- package/dist/manifest-BHUYpjUG.mjs.map +0 -1
- package/dist/parser-By6RWZVW.mjs.map +0 -1
- package/dist/stylesheet-writer-BBYjNSMA.mjs.map +0 -1
- package/dist/tree-BX-sRRVp.mjs.map +0 -1
- package/dist/workbook-CMel6UcI.mjs.map +0 -1
- package/dist/worksheet-Cxn2c-jz.mjs.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { r as normalizeFormulaText } from "./inference-BMvv9cUY.mjs";
|
|
2
|
-
import { a as addTable,
|
|
2
|
+
import { a as addTable, dn as parseMultiCellRange } from "./worksheet-DLMyDD7W.mjs";
|
|
3
3
|
//#region src/worksheet/conditional-formatting.ts
|
|
4
4
|
function makeConditionalFormatting(opts) {
|
|
5
5
|
return {
|
|
@@ -112,4 +112,4 @@ const addExcelTable = (wb, ws, opts) => {
|
|
|
112
112
|
//#endregion
|
|
113
113
|
export { makeCfRule as a, makeDataValidation as i, makeTableColumn as n, makeConditionalFormatting as o, makeTableDefinition as r, addExcelTable as t };
|
|
114
114
|
|
|
115
|
-
//# sourceMappingURL=table-
|
|
115
|
+
//# sourceMappingURL=table-BxOLUZs3.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"table-BFi2WmgG.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 { normalizeFormulaText } from '../utils/formula-text.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 ?? []).map((f) => normalizeFormulaText(f)),\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 { normalizeFormulaText } from '../utils/formula-text.js';\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: normalizeFormulaText(opts.formula1) } : {}),\n ...(opts.formula2 !== undefined ? { formula2: normalizeFormulaText(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'`, with or without a leading `=`).\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 { addTable, 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 *\n * Goes through {@link addTable}, so the definition is checked against the sheet\n * before it lands. Pass `headerRowCount: 0` for a genuinely header-less table.\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 return addTable(ws, def);\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"table-BxOLUZs3.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 { normalizeFormulaText } from '../utils/formula-text.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 ?? []).map((f) => normalizeFormulaText(f)),\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 { normalizeFormulaText } from '../utils/formula-text.js';\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: normalizeFormulaText(opts.formula1) } : {}),\n ...(opts.formula2 !== undefined ? { formula2: normalizeFormulaText(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'`, with or without a leading `=`).\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 { addTable, 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 *\n * Goes through {@link addTable}, so the definition is checked against the sheet\n * before it lands. Pass `headerRowCount: 0` for a genuinely header-less table.\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 return addTable(ws, def);\n};\n"],"mappings":"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"}
|
|
@@ -25,6 +25,7 @@ const DRAWING_NS = "http://schemas.openxmlformats.org/drawingml/2006/main";
|
|
|
25
25
|
const SHEET_DRAWING_NS = "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing";
|
|
26
26
|
const CHART_DRAWING_NS = "http://schemas.openxmlformats.org/drawingml/2006/chartDrawing";
|
|
27
27
|
const PICTURE_NS = "http://schemas.openxmlformats.org/drawingml/2006/picture";
|
|
28
|
+
const STRICT_NS_ROOT = "http://purl.oclc.org/ooxml/";
|
|
28
29
|
const CUSTOMUI_NS = "http://schemas.microsoft.com/office/2006/relationships/ui/extensibility";
|
|
29
30
|
const MARKUP_COMPAT_NS = "http://schemas.openxmlformats.org/markup-compatibility/2006";
|
|
30
31
|
const X14_NS = "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main";
|
|
@@ -136,6 +137,15 @@ function parseQName(name) {
|
|
|
136
137
|
local: m[2] ?? ""
|
|
137
138
|
};
|
|
138
139
|
}
|
|
140
|
+
/**
|
|
141
|
+
* Local part of a Clark-notation name. {@link parseQName} answers the same
|
|
142
|
+
* question and also hands back the namespace; this one runs per element in the
|
|
143
|
+
* SAX readers, so it skips the match object.
|
|
144
|
+
*/
|
|
145
|
+
function localNameOf(name) {
|
|
146
|
+
const brace = name.lastIndexOf("}");
|
|
147
|
+
return brace < 0 ? name : name.slice(brace + 1);
|
|
148
|
+
}
|
|
139
149
|
//#endregion
|
|
140
150
|
//#region src/xml/tree.ts
|
|
141
151
|
/**
|
|
@@ -189,6 +199,6 @@ function appendChild(parent, child) {
|
|
|
189
199
|
return parent;
|
|
190
200
|
}
|
|
191
201
|
//#endregion
|
|
192
|
-
export { PACKAGE_PIVOT_CACHE as $, COREPROPS_NS as A,
|
|
202
|
+
export { PACKAGE_PIVOT_CACHE as $, COREPROPS_NS as A, XSI_NS as At, DCTERMS_PREFIX as B, CHARTSHEET_TYPE as C, X16_NS as Ct, COMMENTS_NS as D, XLTX_TYPE as Dt, CHART_TYPE as E, XLTM_TYPE as Et, CUSTPROPS_NS as F, EXTERNAL_LINK_TYPE as G, DRAWING_NS as H, CX_NS as I, PACKAGE_CHARTS as J, IMAGE_NS as K, DCMITYPE_NS as L, CPROPS_TYPE as M, parseQName as Mt, CTRLPROPS_TYPE as N, qname as Nt, COMMENTS_TYPE as O, XML_NS as Ot, CUSTOMUI_NS as P, PACKAGE_IMAGES as Q, DCORE_NS as R, CHARTSHAPE_TYPE as S, X15_NS as St, CHART_NS as T, XLSX_TYPE as Tt, DRAWING_TYPE as U, DEFAULT_PREFIXES as V, EXTERNAL_LINK_NS as W, PACKAGE_CHARTSHEETS_RELS as X, PACKAGE_CHARTSHEETS as Y, PACKAGE_DRAWINGS as Z, ARC_WORKBOOK_RELS as _, VBA_TYPE as _t, findChildren as a, PACKAGE_WORKSHEET_RELS as at, C16_NS as b, WORKSHEET_TYPE as bt, ARC_CONTENT_TYPES as c, PKG_REL_NS as ct, ARC_CUSTOM_UI as d, SHEET_DRAWING_NS as dt, PACKAGE_PIVOT_TABLE as et, ARC_ROOT_RELS as f, SHEET_MAIN_NS as ft, ARC_WORKBOOK as g, THREADED_COMMENTS_NS as gt, ARC_THEME as h, THEME_TYPE as ht, findChild as i, PACKAGE_WORKSHEETS as it, CPROPS_FMTID as j, localNameOf as jt, CONTYPES_NS as k, XPROPS_NS as kt, ARC_CORE as l, REL_NS as lt, ARC_STYLE as m, STYLES_TYPE as mt, el as n, PACKAGE_RELS as nt, ACTIVEX_TYPE as o, PACKAGE_XL as ot, ARC_SHARED_STRINGS as p, STRICT_NS_ROOT as pt, MARKUP_COMPAT_NS as q, elNs as r, PACKAGE_THEME as rt, ARC_APP as s, PICTURE_NS as st, appendChild as t, PACKAGE_PROPS as tt, ARC_CUSTOM as u, SHARED_STRINGS_TYPE as ut, C14_NS as v, VML_NS as vt, CHART_DRAWING_NS as w, XLSM_TYPE as wt, CHARTEX_TYPE as x, X14_NS as xt, C15_NS as y, VTYPES_NS as yt, DCTERMS_NS as z };
|
|
193
203
|
|
|
194
|
-
//# sourceMappingURL=tree-
|
|
204
|
+
//# sourceMappingURL=tree-CspNjuYl.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree-CspNjuYl.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// ---- ISO 29500 strict -------------------------------------------------------\n//\n// \"Strict Open XML Spreadsheet\" in Excel's Save As dialog writes the same\n// document model as the transitional form above, under a `purl.oclc.org`\n// namespace family instead of a `schemas.openxmlformats.org` one, and it keeps\n// the `.xlsx` extension. The reader is built on transitional QNames, so\n// `strict-package.ts` matches element roots and relationship types against this\n// prefix to name the format instead of reporting a lookup miss.\n//\n// Detection is per part: a converter can write the package relationships in one\n// family and the parts in the other, so a hit on one part says nothing about\n// the rest of the package. The OPC layer (`PKG_NS` above) is identical in both\n// variants, which is why this prefix covers the markup namespaces only.\nexport const STRICT_NS_ROOT = 'http://purl.oclc.org/ooxml/';\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\n/**\n * Local part of a Clark-notation name. {@link parseQName} answers the same\n * question and also hands back the namespace; this one runs per element in the\n * SAX readers, so it skips the match object.\n */\nexport function localNameOf(name: string): string {\n const brace = name.lastIndexOf('}');\n return brace < 0 ? name : name.slice(brace + 1);\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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"}
|
package/dist/workbook/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export type { CellSummary, SheetRef, SheetState, Workbook, WorkbookOverview, WorkbookSheetOverview, WorkbookStats, } from './workbook.js';
|
|
2
|
-
export { addChartsheet, addWorksheet, createWorkbook, describeWorkbook, getActiveSheet, getCellAtAddress, getCellSummary, getChartsheet, getSheet, getSheetState, getWorkbookCellsByKind, getWorkbookStats, iterWorksheets, listCustomXmlParts, moveSheet, removeSheet, renameSheet, setActiveSheet, setCellAtAddress, setSheetState, sheetNames, } from './workbook.js';
|
|
2
|
+
export { addChartsheet, addWorksheet, createWorkbook, describeWorkbook, getActiveSheet, getCellAtAddress, getCellSummary, getChartsheet, getSheet, getSheetByIndex, getSheetState, getWorkbookCellsByKind, getWorkbookStats, iterWorksheets, listCustomXmlParts, moveSheet, removeSheet, renameSheet, setActiveSheet, setCellAtAddress, setSheetState, sheetNames, } from './workbook.js';
|
|
3
3
|
export type { DefinedName, DefinedNameTarget } from './defined-names.js';
|
|
4
4
|
export { addDefinedName, getDefinedName, getDefinedNameTarget, listDefinedNames, makeDefinedName, removeDefinedName, } from './defined-names.js';
|
|
5
5
|
export type { WorkbookProtection } from './protection.js';
|
|
@@ -234,53 +234,13 @@ export declare function addWorksheet(wb: Workbook, title: string, opts?: {
|
|
|
234
234
|
index?: number;
|
|
235
235
|
state?: SheetState;
|
|
236
236
|
}): Worksheet;
|
|
237
|
-
/**
|
|
238
|
-
* 0-based tab-strip index of the sheet (worksheet *or* chartsheet) with the
|
|
239
|
-
* given title, or `-1` when not present. Useful when the caller wants to act on
|
|
240
|
-
* the index for `setActiveSheet` / `swapSheets` / similar operations without
|
|
241
|
-
* manually scanning `wb.sheets`.
|
|
242
|
-
*/
|
|
243
|
-
export declare function getSheetIndex(wb: Workbook, title: string): number;
|
|
244
|
-
/**
|
|
245
|
-
* True iff the workbook has a sheet (worksheet *or* chartsheet) with the given
|
|
246
|
-
* title. Thin shortcut over {@link getSheetIndex}.
|
|
247
|
-
*/
|
|
248
|
-
export declare function hasSheet(wb: Workbook, title: string): boolean;
|
|
249
|
-
/**
|
|
250
|
-
* Count sheets in the workbook, with optional kind/state filters. Mirrors the
|
|
251
|
-
* filter shape of {@link getSheetTitles} but skips the array allocation when
|
|
252
|
-
* the caller only needs the count.
|
|
253
|
-
*/
|
|
254
|
-
export declare function countSheets(wb: Workbook, opts?: {
|
|
255
|
-
kind?: 'worksheet' | 'chartsheet';
|
|
256
|
-
state?: SheetState;
|
|
257
|
-
}): number;
|
|
258
|
-
/**
|
|
259
|
-
* Sheet titles in tab-strip order. By default returns titles for every sheet
|
|
260
|
-
* (worksheets + chartsheets). Optional filters narrow to one kind
|
|
261
|
-
* (`'worksheet'` / `'chartsheet'`) or one state (`'visible' | 'hidden' |
|
|
262
|
-
* 'veryHidden'`).
|
|
263
|
-
*/
|
|
264
|
-
export declare function getSheetTitles(wb: Workbook, opts?: {
|
|
265
|
-
kind?: 'worksheet' | 'chartsheet';
|
|
266
|
-
state?: SheetState;
|
|
267
|
-
}): string[];
|
|
268
|
-
/**
|
|
269
|
-
* True iff the workbook has a **worksheet** (not a chartsheet) with the given
|
|
270
|
-
* title. Distinct from {@link hasSheet} (matches either kind) and {@link
|
|
271
|
-
* hasChartsheet} (chartsheets only).
|
|
272
|
-
*/
|
|
273
|
-
export declare function hasWorksheet(wb: Workbook, title: string): boolean;
|
|
274
|
-
/**
|
|
275
|
-
* True iff the workbook has a **chartsheet** (not a worksheet) with the given
|
|
276
|
-
* title. Distinct from {@link hasSheet}, which matches either kind. Use this
|
|
277
|
-
* when the caller needs to discriminate before calling chartsheet-only
|
|
278
|
-
* operations.
|
|
279
|
-
*/
|
|
280
|
-
export declare function hasChartsheet(wb: Workbook, title: string): boolean;
|
|
281
237
|
/** Look up a Worksheet by title. Returns undefined for missing names or chartsheets. */
|
|
282
238
|
export declare function getSheet(wb: Workbook, title: string): Worksheet | undefined;
|
|
283
|
-
/**
|
|
239
|
+
/**
|
|
240
|
+
* Look up a Worksheet by its 0-based tab-strip index. Returns `undefined` both
|
|
241
|
+
* for an out-of-range index and for a slot holding a chartsheet, so one check
|
|
242
|
+
* on the result covers the bounds test and the sheet-kind discrimination.
|
|
243
|
+
*/
|
|
284
244
|
export declare function getSheetByIndex(wb: Workbook, idx: number): Worksheet | undefined;
|
|
285
245
|
/** Look up a Chartsheet by title. Returns undefined for missing names or worksheets. */
|
|
286
246
|
export declare function getChartsheet(wb: Workbook, title: string): Chartsheet | undefined;
|
|
@@ -290,7 +250,10 @@ export declare function addChartsheet(wb: Workbook, title: string, opts?: {
|
|
|
290
250
|
state?: SheetState;
|
|
291
251
|
chart?: ChartReference;
|
|
292
252
|
}): Chartsheet;
|
|
293
|
-
/**
|
|
253
|
+
/**
|
|
254
|
+
* Every sheet title in tab-strip order, chartsheets included, so a title in
|
|
255
|
+
* the list is not necessarily one {@link getSheet} resolves.
|
|
256
|
+
*/
|
|
294
257
|
export declare function sheetNames(wb: Workbook): string[];
|
|
295
258
|
/** Remove a sheet by title. No-op if the title is not registered. */
|
|
296
259
|
export declare function removeSheet(wb: Workbook, title: string): void;
|
|
@@ -1,13 +1,35 @@
|
|
|
1
|
-
import { o as OpenXmlSchemaError } from "./exceptions-D-CFwxgm.mjs";
|
|
1
|
+
import { a as OpenXmlNotImplementedError, o as OpenXmlSchemaError } from "./exceptions-D-CFwxgm.mjs";
|
|
2
2
|
import { h as parseSheetRange, s as coordinateToTuple } from "./coordinate-CxC88uBk.mjs";
|
|
3
3
|
import { h as isFormulaValue } from "./cell-B5OUUdfI.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-Cv6UtInY.mjs";
|
|
6
6
|
import { a as unescapeCellString, n as escapeXmlAttr, r as escapeXmlText, t as escapeCellString } from "./escape-rA5UpibT.mjs";
|
|
7
|
-
import { a as findChildren, ft as SHEET_MAIN_NS, i as findChild
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import { _ as getCellNumberFormat,
|
|
7
|
+
import { Mt as parseQName, Nt as qname, a as findChildren, ft as SHEET_MAIN_NS, i as findChild } from "./tree-CspNjuYl.mjs";
|
|
8
|
+
import { n as parseXml } from "./parser-B1tB9YaE.mjs";
|
|
9
|
+
import { A as getCellHyperlink, D as getCellComment, Sn as colorToHex, T as getCell, _ as countCellsByKind, ct as makeWorksheet, fn as parseRange, gn as rangeToString, ln as multiCellRangeContainsCell, mn as rangeContainsCell, u as classifyCellValue, wt as setCellByCoord, z as getMergedRangeAt } from "./worksheet-DLMyDD7W.mjs";
|
|
10
|
+
import { _ as getCellNumberFormat, g as getCellFont, h as getCellFill, ht as makeStylesheet, m as getCellBorder, p as getCellAlignment, tn as stableStringify, v as getCellProtection } from "./cell-style-CbB4nXTY.mjs";
|
|
11
|
+
//#region src/xml/strict-package.ts
|
|
12
|
+
const strictPackageError = (found) => new OpenXmlNotImplementedError(`ISO 29500 strict ("Strict Open XML Spreadsheet" in Excel's Save As dialog) is not supported: ${found}. Re-save the file from Excel as "Excel Workbook (.xlsx)" to get the transitional form.`);
|
|
13
|
+
/**
|
|
14
|
+
* Throw when `rootName`, a Clark-notation element name, is in the strict
|
|
15
|
+
* namespace family. Belongs on a reader's root-element mismatch path: the
|
|
16
|
+
* transitional lookup has already failed by then, and strict is the one cause
|
|
17
|
+
* worth naming rather than reporting as an unexpected root.
|
|
18
|
+
*/
|
|
19
|
+
function assertNotStrictRoot(rootName) {
|
|
20
|
+
if (!parseQName(rootName).ns.startsWith("http://purl.oclc.org/ooxml/")) return;
|
|
21
|
+
throw strictPackageError(`part root element is "${rootName}"`);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Throw when any of `types` is the strict spelling of an OPC relationship type.
|
|
25
|
+
* Strict renames the relationship namespace but not the package namespace, so
|
|
26
|
+
* the container still parses and only its officeDocument pointer goes
|
|
27
|
+
* unrecognised.
|
|
28
|
+
*/
|
|
29
|
+
function assertNotStrictRelTypes(types) {
|
|
30
|
+
for (const type of types) if (type.startsWith("http://purl.oclc.org/ooxml/")) throw strictPackageError(`package relationship type is "${type}"`);
|
|
31
|
+
}
|
|
32
|
+
//#endregion
|
|
11
33
|
//#region src/workbook/shared-strings.ts
|
|
12
34
|
const SST_TAG = `{${SHEET_MAIN_NS}}sst`;
|
|
13
35
|
const SI_TAG = `{${SHEET_MAIN_NS}}si`;
|
|
@@ -94,7 +116,10 @@ const collectText = (node) => {
|
|
|
94
116
|
*/
|
|
95
117
|
function parseSharedStringsXml(bytes) {
|
|
96
118
|
const root = parseXml(bytes);
|
|
97
|
-
if (root.name !== SST_TAG)
|
|
119
|
+
if (root.name !== SST_TAG) {
|
|
120
|
+
assertNotStrictRoot(root.name);
|
|
121
|
+
throw new OpenXmlSchemaError(`parseSharedStringsXml: root is "${root.name}", expected sst`);
|
|
122
|
+
}
|
|
98
123
|
const table = makeSharedStrings();
|
|
99
124
|
for (const si of findChildren(root, SI_TAG)) {
|
|
100
125
|
const entry = parseRichString(si);
|
|
@@ -327,6 +352,15 @@ function addWorksheet(wb, title, opts) {
|
|
|
327
352
|
function getSheet(wb, title) {
|
|
328
353
|
for (const s of wb.sheets) if (s.kind === "worksheet" && s.sheet.title === title) return s.sheet;
|
|
329
354
|
}
|
|
355
|
+
/**
|
|
356
|
+
* Look up a Worksheet by its 0-based tab-strip index. Returns `undefined` both
|
|
357
|
+
* for an out-of-range index and for a slot holding a chartsheet, so one check
|
|
358
|
+
* on the result covers the bounds test and the sheet-kind discrimination.
|
|
359
|
+
*/
|
|
360
|
+
function getSheetByIndex(wb, idx) {
|
|
361
|
+
const ref = wb.sheets[idx];
|
|
362
|
+
return ref?.kind === "worksheet" ? ref.sheet : void 0;
|
|
363
|
+
}
|
|
330
364
|
/** Look up a Chartsheet by title. Returns undefined for missing names or worksheets. */
|
|
331
365
|
function getChartsheet(wb, title) {
|
|
332
366
|
for (const s of wb.sheets) if (s.kind === "chartsheet" && s.sheet.title === title) return s.sheet;
|
|
@@ -354,7 +388,10 @@ function addChartsheet(wb, title, opts) {
|
|
|
354
388
|
}
|
|
355
389
|
return cs;
|
|
356
390
|
}
|
|
357
|
-
/**
|
|
391
|
+
/**
|
|
392
|
+
* Every sheet title in tab-strip order, chartsheets included, so a title in
|
|
393
|
+
* the list is not necessarily one {@link getSheet} resolves.
|
|
394
|
+
*/
|
|
358
395
|
function sheetNames(wb) {
|
|
359
396
|
return wb.sheets.map((s) => s.sheet.title);
|
|
360
397
|
}
|
|
@@ -657,6 +694,6 @@ function listCustomXmlParts(wb) {
|
|
|
657
694
|
return out;
|
|
658
695
|
}
|
|
659
696
|
//#endregion
|
|
660
|
-
export {
|
|
697
|
+
export { parseSharedStringsXml as A, validateSheetTitle as C, getSharedStringIndex as D, getSharedStringAt as E, assertNotStrictRoot as F, sharedStringCount as M, sharedStringsToBytes as N, makeSharedStrings as O, assertNotStrictRelTypes as P, sheetNames as S, addSharedString as T, removeSheet as _, getActiveSheet as a, setCellAtAddress as b, getChartsheet as c, getSheetState as d, getWorkbookCellsByKind as f, moveSheet as g, listCustomXmlParts as h, describeWorkbook as i, serializeRichString as j, parseRichString as k, getSheet as l, iterWorksheets as m, addWorksheet as n, getCellAtAddress as o, getWorkbookStats as p, createWorkbook as r, getCellSummary as s, addChartsheet as t, getSheetByIndex as u, renameSheet as v, addSharedRichText as w, setSheetState as x, setActiveSheet as y };
|
|
661
698
|
|
|
662
|
-
//# sourceMappingURL=workbook-
|
|
699
|
+
//# sourceMappingURL=workbook-tG9oYtzU.mjs.map
|