@ricsam/formula-engine 0.0.10 → 0.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/core/engine.cjs +6 -6
- package/dist/cjs/core/engine.cjs.map +3 -3
- package/dist/cjs/core/managers/style-manager.cjs +6 -8
- package/dist/cjs/core/managers/style-manager.cjs.map +3 -3
- package/dist/cjs/package.json +1 -1
- package/dist/mjs/core/engine.mjs +6 -6
- package/dist/mjs/core/engine.mjs.map +3 -3
- package/dist/mjs/core/managers/style-manager.mjs +6 -8
- package/dist/mjs/core/managers/style-manager.mjs.map +3 -3
- package/dist/mjs/package.json +1 -1
- package/dist/types/core/engine.d.ts +4 -4
- package/dist/types/core/managers/style-manager.d.ts +4 -6
- package/package.json +1 -1
package/dist/cjs/core/engine.cjs
CHANGED
|
@@ -76,7 +76,7 @@ class FormulaEngine {
|
|
|
76
76
|
this.dependencyManager = new import_dependency_manager.DependencyManager(cacheManager, this.workbookManager);
|
|
77
77
|
const formulaEvaluator = new import_formula_evaluator.FormulaEvaluator(this.tableManager, this.dependencyManager, this.namedExpressionManager);
|
|
78
78
|
this.evaluationManager = new import_evaluation_manager.EvaluationManager(this.workbookManager, this.tableManager, formulaEvaluator, this.dependencyManager);
|
|
79
|
-
this.styleManager = new import_style_manager.StyleManager(this.
|
|
79
|
+
this.styleManager = new import_style_manager.StyleManager(this.evaluationManager);
|
|
80
80
|
this.copyManager = new import_copy_manager.CopyManager(this.workbookManager, this.evaluationManager, this.styleManager);
|
|
81
81
|
this.autoFillManager = new import_autofill_utils.AutoFill(this.workbookManager, this);
|
|
82
82
|
this._workbookManager = this.workbookManager;
|
|
@@ -233,8 +233,8 @@ class FormulaEngine {
|
|
|
233
233
|
}
|
|
234
234
|
return removed;
|
|
235
235
|
}
|
|
236
|
-
getConditionalStyles(
|
|
237
|
-
return this.styleManager.getConditionalStyles(
|
|
236
|
+
getConditionalStyles(range) {
|
|
237
|
+
return this.styleManager.getConditionalStyles(range);
|
|
238
238
|
}
|
|
239
239
|
getCellStyle(cellAddress) {
|
|
240
240
|
return this.styleManager.getCellStyle(cellAddress);
|
|
@@ -250,8 +250,8 @@ class FormulaEngine {
|
|
|
250
250
|
}
|
|
251
251
|
return removed;
|
|
252
252
|
}
|
|
253
|
-
getCellStyles(
|
|
254
|
-
return this.styleManager.getCellStyles(
|
|
253
|
+
getCellStyles(range) {
|
|
254
|
+
return this.styleManager.getCellStyles(range);
|
|
255
255
|
}
|
|
256
256
|
clearCellStyles(range) {
|
|
257
257
|
this.styleManager.clearCellStyles(range);
|
|
@@ -463,4 +463,4 @@ class FormulaEngine {
|
|
|
463
463
|
}
|
|
464
464
|
}
|
|
465
465
|
|
|
466
|
-
//# debugId=
|
|
466
|
+
//# debugId=3C5F3EFFB9C7440364756E2164756E21
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/core/engine.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"/**\n * Main FormulaEngine class\n * Core API implementation for spreadsheet calculations\n */\n\nimport {\n type CellAddress,\n type CellStyle,\n type ConditionalStyle,\n type CopyCellsOptions,\n type DirectCellStyle,\n type NamedExpression,\n type RangeAddress,\n type SerializedCellValue,\n type SingleEvaluationResult,\n type SpreadsheetRange,\n type SpreadsheetRangeEnd,\n type TableDefinition,\n} from \"./types.cjs\";\n\nimport type { FillDirection } from \"@ricsam/selection-manager\";\nimport { FormulaEvaluator } from \"../evaluator/formula-evaluator.cjs\";\nimport { AutoFill } from \"./autofill-utils.cjs\";\nimport { WorkbookManager } from \"./managers/workbook-manager.cjs\";\nimport { deserialize, serialize } from \"./map-serializer.cjs\";\nimport { renameNamedExpressionInFormula } from \"./named-expression-renamer.cjs\";\nimport { renameSheetInFormula } from \"./sheet-renamer.cjs\";\nimport { renameTableInFormula } from \"./table-renamer.cjs\";\nimport { renameWorkbookInFormula } from \"./workbook-renamer.cjs\";\nimport { cellAddressToKey, keyToCellAddress } from \"./utils.cjs\";\nimport { CacheManager } from \"./managers/cache-manager.cjs\";\nimport { NamedExpressionManager } from \"./managers/named-expression-manager.cjs\";\nimport { TableManager } from \"./managers/table-manager.cjs\";\nimport { EventManager } from \"./managers/event-manager.cjs\";\nimport { EvaluationManager } from \"./managers/evaluation-manager.cjs\";\nimport { DependencyManager } from \"./managers/dependency-manager.cjs\";\nimport { StyleManager } from \"./managers/style-manager.cjs\";\nimport { CopyManager } from \"./managers/copy-manager.cjs\";\n\n/**\n * Main FormulaEngine class\n */\nexport class FormulaEngine {\n private workbookManager: WorkbookManager;\n private namedExpressionManager: NamedExpressionManager;\n private tableManager: TableManager;\n private eventManager: EventManager;\n private evaluationManager: EvaluationManager;\n private autoFillManager: AutoFill;\n private dependencyManager: DependencyManager;\n private styleManager: StyleManager;\n private copyManager: CopyManager;\n\n /**\n * Public access to the store manager for testing\n */\n public _workbookManager: WorkbookManager;\n public _namedExpressionManager: NamedExpressionManager;\n public _tableManager: TableManager;\n public _eventManager: EventManager;\n public _evaluationManager: EvaluationManager;\n public _autoFillManager: AutoFill;\n public _dependencyManager: DependencyManager;\n public _styleManager: StyleManager;\n\n constructor() {\n this.eventManager = new EventManager();\n this.workbookManager = new WorkbookManager();\n this.namedExpressionManager = new NamedExpressionManager();\n this.tableManager = new TableManager(this.workbookManager);\n const cacheManager = new CacheManager();\n this.dependencyManager = new DependencyManager(\n cacheManager,\n this.workbookManager\n );\n\n const formulaEvaluator = new FormulaEvaluator(\n this.tableManager,\n this.dependencyManager,\n this.namedExpressionManager,\n );\n\n this.evaluationManager = new EvaluationManager(\n this.workbookManager,\n this.tableManager,\n formulaEvaluator,\n this.dependencyManager\n );\n\n this.styleManager = new StyleManager(\n this.workbookManager,\n this.evaluationManager\n );\n this.copyManager = new CopyManager(\n this.workbookManager,\n this.evaluationManager,\n this.styleManager\n );\n\n this.autoFillManager = new AutoFill(this.workbookManager, this);\n\n this._workbookManager = this.workbookManager;\n this._namedExpressionManager = this.namedExpressionManager;\n this._tableManager = this.tableManager;\n this._eventManager = this.eventManager;\n this._evaluationManager = this.evaluationManager;\n this._autoFillManager = this.autoFillManager;\n this._dependencyManager = this.dependencyManager;\n this._styleManager = this.styleManager;\n }\n\n /**\n * Static factory method to build an empty engine\n */\n static buildEmpty(): FormulaEngine {\n return new FormulaEngine();\n }\n\n //#region Cell\n getCellEvaluationResult(\n cellAddress: CellAddress\n ): SingleEvaluationResult | undefined {\n return this.evaluationManager.getCellEvaluationResult(cellAddress);\n }\n\n getCellValue(cellAddress: CellAddress, debug?: boolean): SerializedCellValue {\n const result = this.getCellEvaluationResult(cellAddress);\n if (!result) {\n return \"\";\n }\n\n return this.evaluationManager.evaluationResultToSerializedValue(\n result,\n cellAddress,\n debug\n );\n }\n\n evaluateFormula(\n /**\n * formula without the leading = sign\n */\n formula: string, cellAddress: CellAddress): SerializedCellValue {\n return this.evaluationManager.evaluateFormula(formula, cellAddress);\n }\n\n getCellDependents(\n address: CellAddress | SpreadsheetRange\n ): (SpreadsheetRange | CellAddress)[] {\n throw new Error(\"Not implemented\");\n }\n\n getCellPrecedents(\n address: CellAddress | SpreadsheetRange\n ): (SpreadsheetRange | CellAddress)[] {\n throw new Error(\"Not implemented\");\n }\n\n //#endregion\n\n //#region Named Expressions\n addNamedExpression({\n expression,\n expressionName,\n sheetName,\n workbookName,\n }: {\n expression: string;\n expressionName: string;\n sheetName?: string;\n workbookName?: string;\n }) {\n this.namedExpressionManager.addNamedExpression({\n expression,\n expressionName,\n sheetName,\n workbookName,\n });\n\n // Re-evaluate all sheets since named expressions can be referenced from anywhere\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n removeNamedExpression({\n expressionName,\n sheetName,\n workbookName,\n }: {\n expressionName: string;\n sheetName?: string;\n workbookName?: string;\n }) {\n const found = this.namedExpressionManager.removeNamedExpression({\n expressionName,\n sheetName,\n workbookName,\n });\n\n if (found) {\n // Re-evaluate all sheets since named expressions can be referenced from anywhere\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n return found;\n }\n\n updateNamedExpression({\n expression,\n expressionName,\n sheetName,\n workbookName,\n }: {\n expression: string;\n expressionName: string;\n sheetName?: string;\n workbookName?: string;\n }) {\n this.namedExpressionManager.updateNamedExpression({\n expression,\n expressionName,\n sheetName,\n workbookName,\n });\n\n // Re-evaluate all sheets since named expressions can be referenced from anywhere\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n renameNamedExpression({\n expressionName,\n sheetName,\n workbookName,\n newName,\n }: {\n expressionName: string;\n sheetName?: string;\n workbookName?: string;\n newName: string;\n }) {\n const result = this.namedExpressionManager.renameNamedExpression({\n expressionName,\n sheetName,\n workbookName,\n newName,\n });\n\n // Update all formulas that reference this named expression in sheet cells\n this.workbookManager.updateAllFormulas((formula) =>\n renameNamedExpressionInFormula(formula, expressionName, newName)\n );\n\n // Update named expressions that reference this named expression\n this.namedExpressionManager.updateAllNamedExpressions((formula) =>\n renameNamedExpressionInFormula(formula, expressionName, newName)\n );\n\n // Re-evaluate all sheets since named expressions can be referenced from anywhere\n this.reevaluate();\n this.eventManager.emitUpdate();\n\n return result;\n }\n\n setNamedExpressions(\n opts: (\n | {\n type: \"global\";\n }\n | {\n type: \"sheet\";\n sheetName: string;\n workbookName: string;\n }\n | {\n type: \"workbook\";\n workbookName: string;\n }\n ) & {\n expressions: Map<string, NamedExpression>;\n }\n ) {\n this.namedExpressionManager.setNamedExpressions(opts);\n\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n //#endregion\n\n //#region Tables\n addTable(props: {\n tableName: string;\n sheetName: string;\n workbookName: string;\n start: string;\n numRows: SpreadsheetRangeEnd;\n numCols: number;\n }) {\n const table = this.tableManager.addTable({\n ...props,\n getCellValue: (cellAddress: CellAddress) =>\n this.getCellValue(cellAddress),\n });\n\n // Re-evaluate all sheets since structured references might depend on this table\n this.reevaluate();\n this.eventManager.emitUpdate();\n\n return table;\n }\n\n renameTable(\n workbookName: string,\n names: { oldName: string; newName: string }\n ) {\n this.tableManager.renameTable(workbookName, names);\n\n // Update all formulas that reference this table in sheet cells\n this.workbookManager.updateAllFormulas((formula) =>\n renameTableInFormula(formula, names.oldName, names.newName)\n );\n\n // Update named expressions that reference this table\n this.namedExpressionManager.updateAllNamedExpressions((formula) =>\n renameTableInFormula(formula, names.oldName, names.newName)\n );\n\n // Re-evaluate all sheets since structured references might depend on this table\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n updateTable(opts: {\n tableName: string;\n sheetName?: string;\n start?: string;\n numRows?: SpreadsheetRangeEnd;\n numCols?: number;\n workbookName: string;\n }) {\n this.tableManager.updateTable({\n ...opts,\n getCellValue: (cellAddress: CellAddress) =>\n this.getCellValue(cellAddress),\n });\n\n // Re-evaluate all sheets since structured references might depend on this table\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n removeTable(opts: { tableName: string; workbookName: string }) {\n const found = this.tableManager.removeTable(opts);\n\n if (found) {\n // Re-evaluate all sheets since structured references might depend on this table\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n return found;\n }\n\n resetTables(tables: Map<string, Map<string, TableDefinition>>) {\n this.tableManager.resetTables(tables);\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n getTables(workbookName: string) {\n return this.tableManager.getTables(workbookName);\n }\n\n isCellInTable(cellAddress: CellAddress): TableDefinition | undefined {\n return this.tableManager.isCellInTable(cellAddress);\n }\n\n //#endregion\n\n //#region Conditional Styling\n /**\n * Add a conditional style rule\n */\n addConditionalStyle(style: ConditionalStyle): void {\n this.styleManager.addConditionalStyle(style);\n this.eventManager.emitUpdate();\n }\n\n /**\n * Remove a conditional style rule by index\n */\n removeConditionalStyle(workbookName: string, index: number): boolean {\n const removed = this.styleManager.removeConditionalStyle(workbookName, index);\n if (removed) {\n this.eventManager.emitUpdate();\n }\n return removed;\n }\n\n /**\n * Get all conditional styles for a workbook\n */\n getConditionalStyles(workbookName: string): ConditionalStyle[] {\n return this.styleManager.getConditionalStyles(workbookName);\n }\n\n /**\n * Get the computed style for a specific cell\n */\n getCellStyle(cellAddress: CellAddress): CellStyle | undefined {\n return this.styleManager.getCellStyle(cellAddress);\n }\n\n /**\n * Add a direct cell style rule\n */\n addCellStyle(style: DirectCellStyle): void {\n this.styleManager.addCellStyle(style);\n this.eventManager.emitUpdate();\n }\n\n /**\n * Remove a direct cell style rule by index\n */\n removeCellStyle(workbookName: string, index: number): boolean {\n const removed = this.styleManager.removeCellStyle(workbookName, index);\n if (removed) {\n this.eventManager.emitUpdate();\n }\n return removed;\n }\n\n /**\n * Get all direct cell styles for a workbook\n */\n getCellStyles(workbookName: string): DirectCellStyle[] {\n return this.styleManager.getCellStyles(workbookName);\n }\n\n /**\n * Clear all cell styles and conditional styles for a given range\n * Adjusts existing style ranges rather than deleting them entirely\n */\n clearCellStyles(range: RangeAddress): void {\n this.styleManager.clearCellStyles(range);\n this.eventManager.emitUpdate();\n }\n\n //#endregion\n\n //#region Copy/Paste\n /**\n * Copy cells from source to target\n */\n copyCells(\n source: CellAddress[],\n target: CellAddress,\n options: CopyCellsOptions\n ): void {\n this.copyManager.copyCells(source, target, options);\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n //#endregion\n\n //#region Sheets\n addSheet(opts: { workbookName: string; sheetName: string }) {\n const newSheet = this.workbookManager.addSheet(opts);\n const wbLevel = this.namedExpressionManager.addSheet(opts);\n this.reevaluate();\n this.eventManager.emitUpdate();\n return newSheet;\n }\n\n removeSheet(opts: { workbookName: string; sheetName: string }) {\n const sheet = this.workbookManager.removeSheet(opts);\n\n // Clean up related data\n this.namedExpressionManager.removeSheet(opts);\n this.tableManager.removeSheet(opts);\n this.styleManager.removeSheetStyles(opts.workbookName, opts.sheetName);\n\n // Add engine-specific logic: re-evaluate since references might be affected\n this.reevaluate();\n this.eventManager.emitUpdate();\n\n return sheet;\n }\n\n renameSheet(opts: {\n sheetName: string;\n newSheetName: string;\n workbookName: string;\n }) {\n const sheet = this.workbookManager.renameSheet(opts);\n\n // Update scoped named expressions\n this.namedExpressionManager.renameSheet(opts);\n\n // Update tables that belong to the renamed sheet\n this.tableManager.updateTablesForSheetRename(opts);\n\n // Update conditional styles that reference this sheet\n this.styleManager.updateSheetName(\n opts.workbookName,\n opts.sheetName,\n opts.newSheetName\n );\n\n // Update all formulas that reference this sheet\n this.workbookManager.updateAllFormulas((formula) =>\n renameSheetInFormula({\n formula,\n oldSheetName: opts.sheetName,\n newSheetName: opts.newSheetName,\n })\n );\n\n // Add engine-specific logic: re-evaluate since references might be affected\n this.reevaluate();\n this.eventManager.emitUpdate();\n\n return sheet;\n }\n\n getSheets(workbookName: string) {\n return this.workbookManager.getSheets(workbookName);\n }\n\n getSheet({\n workbookName,\n sheetName,\n }: {\n workbookName: string;\n sheetName: string;\n }) {\n return this.workbookManager.getSheet({ workbookName, sheetName });\n }\n\n getSheetSerialized(opts: {\n sheetName: string;\n workbookName: string;\n }): Map<string, SerializedCellValue> {\n return this.workbookManager.getSheetSerialized(opts);\n }\n\n //#endregion\n\n //#region Workbook\n addWorkbook(workbookName: string) {\n this.workbookManager.addWorkbook(workbookName);\n this.namedExpressionManager.addWorkbook(workbookName);\n this.tableManager.addWorkbook(workbookName);\n\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n removeWorkbook(workbookName: string) {\n this.workbookManager.removeWorkbook(workbookName);\n this.namedExpressionManager.removeWorkbook(workbookName);\n this.tableManager.removeWorkbook(workbookName);\n this.styleManager.removeWorkbookStyles(workbookName);\n\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n cloneWorkbook(fromWorkbookName: string, toWorkbookName: string) {\n // Check if source workbook exists\n const sourceWorkbook = this.workbookManager\n .getWorkbooks()\n .get(fromWorkbookName);\n if (!sourceWorkbook) {\n throw new Error(`Source workbook \"${fromWorkbookName}\" not found`);\n }\n\n // Check if target workbook name already exists\n if (this.workbookManager.getWorkbooks().has(toWorkbookName)) {\n throw new Error(`Target workbook \"${toWorkbookName}\" already exists`);\n }\n\n // Create new workbook\n this.addWorkbook(toWorkbookName);\n\n // Clone all sheets from source workbook\n for (const [sheetName, sheet] of sourceWorkbook.sheets) {\n // Add sheet to target workbook\n this.addSheet({\n workbookName: toWorkbookName,\n sheetName: sheetName,\n });\n\n // Copy all cell content using setSheetContent for efficiency\n this.setSheetContent(\n {\n workbookName: toWorkbookName,\n sheetName: sheetName,\n },\n new Map(sheet.content)\n );\n }\n\n // Clone workbook-scoped named expressions\n const sourceWorkbookExpressions = this.namedExpressionManager\n .getNamedExpressions()\n .workbookExpressions.get(fromWorkbookName);\n if (sourceWorkbookExpressions) {\n for (const [name, expression] of sourceWorkbookExpressions) {\n this.addNamedExpression({\n expressionName: name,\n expression: expression.expression,\n workbookName: toWorkbookName,\n });\n }\n }\n\n // Clone sheet-scoped named expressions\n const sourceSheetExpressions = this.namedExpressionManager\n .getNamedExpressions()\n .sheetExpressions.get(fromWorkbookName);\n if (sourceSheetExpressions) {\n for (const [sheetName, sheetExpressions] of sourceSheetExpressions) {\n for (const [name, expression] of sheetExpressions) {\n this.addNamedExpression({\n expressionName: name,\n expression: expression.expression,\n workbookName: toWorkbookName,\n sheetName: sheetName,\n });\n }\n }\n }\n\n // Clone tables\n const sourceTables = this.tableManager.tables.get(fromWorkbookName);\n if (sourceTables) {\n for (const [tableName, table] of sourceTables) {\n this.tableManager.copyTable(\n {\n workbookName: fromWorkbookName,\n tableName: tableName,\n },\n {\n workbookName: toWorkbookName,\n tableName: tableName,\n }\n );\n }\n }\n\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n renameWorkbook(opts: { workbookName: string; newWorkbookName: string }) {\n this.workbookManager.renameWorkbook(opts);\n\n // Update scoped named expressions\n this.namedExpressionManager.renameWorkbook(opts);\n\n // Update tables that belong to the renamed sheet\n this.tableManager.updateTablesForWorkbookRename(opts);\n\n // Update conditional styles that reference this workbook\n this.styleManager.updateWorkbookName(\n opts.workbookName,\n opts.newWorkbookName\n );\n\n // Update all formulas that reference this workbook\n this.workbookManager.updateAllFormulas((formula) =>\n renameWorkbookInFormula({\n formula,\n oldWorkbookName: opts.workbookName,\n newWorkbookName: opts.newWorkbookName,\n })\n );\n\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n getWorkbooks() {\n return this.workbookManager.getWorkbooks();\n }\n //#endregion\n\n //#region CRUD Operations\n /**\n * Overrides the content of a sheet.\n * @param sheetName - The name of the sheet to set the content of\n * @param content - A map of cell addresses to their serialized values\n * @remarks This method is used to set the content of a sheet. It will re-evaluate all sheets to ensure all dependencies are resolved correctly.\n */\n setSheetContent(\n opts: { sheetName: string; workbookName: string },\n content: Map<string, SerializedCellValue>\n ) {\n this.workbookManager.setSheetContent(opts, content);\n\n // Re-evaluate all sheets to ensure all dependencies are resolved correctly\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n setCellContent(address: CellAddress, content: SerializedCellValue) {\n this.workbookManager.setCellContent(address, content);\n\n // Re-evaluate all sheets to ensure all dependencies are resolved correctly\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n //#endregion\n\n //#region Evaluation\n\n /**\n * Re-evaluates all sheets to ensure all dependencies are resolved correctly\n *\n * but just clears the evaluation cache\n */\n reevaluate() {\n this.evaluationManager.clearEvaluationCache();\n }\n //#endregion\n\n //#region Auto-fill\n /**\n * Auto-fills the fillRange based on the seedRange and the direction.\n */\n autoFill(\n opts: { sheetName: string; workbookName: string },\n /**\n * The user's original selection that defines the pattern/series.\n */\n seedRange: SpreadsheetRange,\n /**\n * the new cells populated by the drag, excluding the seed\n */\n fillRange: SpreadsheetRange,\n /**\n * The direction of the fill.\n */\n direction: FillDirection\n ) {\n this.autoFillManager.fill(opts, seedRange, fillRange, direction);\n }\n\n /**\n * Removes the content in the spreadsheet that is inside the range.\n */\n clearSpreadsheetRange(address: RangeAddress) {\n this.workbookManager.clearSpreadsheetRange(address);\n\n // Re-evaluate all sheets to ensure all dependencies are resolved correctly\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n //#endregion\n\n //#region State - UI library integration\n getState() {\n return {\n workbooks: this.workbookManager.getWorkbooks(),\n namedExpressions: this.namedExpressionManager.getNamedExpressions(),\n tables: this.tableManager.tables,\n conditionalStyles: this.styleManager.getAllConditionalStyles(),\n cellStyles: this.styleManager.getAllCellStyles(),\n };\n }\n\n onUpdate(listener: () => void) {\n return this.eventManager.onUpdate(listener);\n }\n\n serializeEngine(): string {\n return serialize(this.getState());\n }\n\n resetToSerializedEngine(data: string) {\n const deserialized = deserialize(data) as ReturnType<typeof this.getState>;\n\n this.workbookManager.resetWorkbooks(deserialized.workbooks);\n\n deserialized.workbooks.forEach((workbook) => {\n this.namedExpressionManager.addWorkbook(workbook.name);\n this.tableManager.addWorkbook(workbook.name);\n workbook.sheets.forEach((sheet) => {\n this.namedExpressionManager.addSheet({\n workbookName: workbook.name,\n sheetName: sheet.name,\n });\n });\n });\n\n this.namedExpressionManager.resetNamedExpressions(\n deserialized.namedExpressions\n );\n this.tableManager.resetTables(deserialized.tables);\n \n // Reset styles if present\n // Handle backward compatibility: if conditionalStyles is a Map, convert it\n let conditionalStylesArray: ConditionalStyle[] | undefined;\n let cellStylesArray: DirectCellStyle[] | undefined;\n \n if (deserialized.conditionalStyles) {\n if (deserialized.conditionalStyles instanceof Map) {\n // Old format: Map<string, ConditionalStyle[]>\n conditionalStylesArray = Array.from(deserialized.conditionalStyles.values()).flat();\n } else if (Array.isArray(deserialized.conditionalStyles)) {\n // New format: ConditionalStyle[]\n conditionalStylesArray = deserialized.conditionalStyles;\n }\n }\n \n if (deserialized.cellStyles) {\n if (Array.isArray(deserialized.cellStyles)) {\n cellStylesArray = deserialized.cellStyles;\n }\n }\n \n this.styleManager.resetStyles(conditionalStylesArray, cellStylesArray);\n\n // Re-evaluate all sheets to ensure all dependencies are resolved correctly\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n //#endregion\n}\n"
|
|
5
|
+
"/**\n * Main FormulaEngine class\n * Core API implementation for spreadsheet calculations\n */\n\nimport {\n type CellAddress,\n type CellStyle,\n type ConditionalStyle,\n type CopyCellsOptions,\n type DirectCellStyle,\n type NamedExpression,\n type RangeAddress,\n type SerializedCellValue,\n type SingleEvaluationResult,\n type SpreadsheetRange,\n type SpreadsheetRangeEnd,\n type TableDefinition,\n} from \"./types.cjs\";\n\nimport type { FillDirection } from \"@ricsam/selection-manager\";\nimport { FormulaEvaluator } from \"../evaluator/formula-evaluator.cjs\";\nimport { AutoFill } from \"./autofill-utils.cjs\";\nimport { WorkbookManager } from \"./managers/workbook-manager.cjs\";\nimport { deserialize, serialize } from \"./map-serializer.cjs\";\nimport { renameNamedExpressionInFormula } from \"./named-expression-renamer.cjs\";\nimport { renameSheetInFormula } from \"./sheet-renamer.cjs\";\nimport { renameTableInFormula } from \"./table-renamer.cjs\";\nimport { renameWorkbookInFormula } from \"./workbook-renamer.cjs\";\nimport { cellAddressToKey, keyToCellAddress } from \"./utils.cjs\";\nimport { CacheManager } from \"./managers/cache-manager.cjs\";\nimport { NamedExpressionManager } from \"./managers/named-expression-manager.cjs\";\nimport { TableManager } from \"./managers/table-manager.cjs\";\nimport { EventManager } from \"./managers/event-manager.cjs\";\nimport { EvaluationManager } from \"./managers/evaluation-manager.cjs\";\nimport { DependencyManager } from \"./managers/dependency-manager.cjs\";\nimport { StyleManager } from \"./managers/style-manager.cjs\";\nimport { CopyManager } from \"./managers/copy-manager.cjs\";\n\n/**\n * Main FormulaEngine class\n */\nexport class FormulaEngine {\n private workbookManager: WorkbookManager;\n private namedExpressionManager: NamedExpressionManager;\n private tableManager: TableManager;\n private eventManager: EventManager;\n private evaluationManager: EvaluationManager;\n private autoFillManager: AutoFill;\n private dependencyManager: DependencyManager;\n private styleManager: StyleManager;\n private copyManager: CopyManager;\n\n /**\n * Public access to the store manager for testing\n */\n public _workbookManager: WorkbookManager;\n public _namedExpressionManager: NamedExpressionManager;\n public _tableManager: TableManager;\n public _eventManager: EventManager;\n public _evaluationManager: EvaluationManager;\n public _autoFillManager: AutoFill;\n public _dependencyManager: DependencyManager;\n public _styleManager: StyleManager;\n\n constructor() {\n this.eventManager = new EventManager();\n this.workbookManager = new WorkbookManager();\n this.namedExpressionManager = new NamedExpressionManager();\n this.tableManager = new TableManager(this.workbookManager);\n const cacheManager = new CacheManager();\n this.dependencyManager = new DependencyManager(\n cacheManager,\n this.workbookManager\n );\n\n const formulaEvaluator = new FormulaEvaluator(\n this.tableManager,\n this.dependencyManager,\n this.namedExpressionManager,\n );\n\n this.evaluationManager = new EvaluationManager(\n this.workbookManager,\n this.tableManager,\n formulaEvaluator,\n this.dependencyManager\n );\n\n this.styleManager = new StyleManager(\n this.evaluationManager\n );\n this.copyManager = new CopyManager(\n this.workbookManager,\n this.evaluationManager,\n this.styleManager\n );\n\n this.autoFillManager = new AutoFill(this.workbookManager, this);\n\n this._workbookManager = this.workbookManager;\n this._namedExpressionManager = this.namedExpressionManager;\n this._tableManager = this.tableManager;\n this._eventManager = this.eventManager;\n this._evaluationManager = this.evaluationManager;\n this._autoFillManager = this.autoFillManager;\n this._dependencyManager = this.dependencyManager;\n this._styleManager = this.styleManager;\n }\n\n /**\n * Static factory method to build an empty engine\n */\n static buildEmpty(): FormulaEngine {\n return new FormulaEngine();\n }\n\n //#region Cell\n getCellEvaluationResult(\n cellAddress: CellAddress\n ): SingleEvaluationResult | undefined {\n return this.evaluationManager.getCellEvaluationResult(cellAddress);\n }\n\n getCellValue(cellAddress: CellAddress, debug?: boolean): SerializedCellValue {\n const result = this.getCellEvaluationResult(cellAddress);\n if (!result) {\n return \"\";\n }\n\n return this.evaluationManager.evaluationResultToSerializedValue(\n result,\n cellAddress,\n debug\n );\n }\n\n evaluateFormula(\n /**\n * formula without the leading = sign\n */\n formula: string, cellAddress: CellAddress): SerializedCellValue {\n return this.evaluationManager.evaluateFormula(formula, cellAddress);\n }\n\n getCellDependents(\n address: CellAddress | SpreadsheetRange\n ): (SpreadsheetRange | CellAddress)[] {\n throw new Error(\"Not implemented\");\n }\n\n getCellPrecedents(\n address: CellAddress | SpreadsheetRange\n ): (SpreadsheetRange | CellAddress)[] {\n throw new Error(\"Not implemented\");\n }\n\n //#endregion\n\n //#region Named Expressions\n addNamedExpression({\n expression,\n expressionName,\n sheetName,\n workbookName,\n }: {\n expression: string;\n expressionName: string;\n sheetName?: string;\n workbookName?: string;\n }) {\n this.namedExpressionManager.addNamedExpression({\n expression,\n expressionName,\n sheetName,\n workbookName,\n });\n\n // Re-evaluate all sheets since named expressions can be referenced from anywhere\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n removeNamedExpression({\n expressionName,\n sheetName,\n workbookName,\n }: {\n expressionName: string;\n sheetName?: string;\n workbookName?: string;\n }) {\n const found = this.namedExpressionManager.removeNamedExpression({\n expressionName,\n sheetName,\n workbookName,\n });\n\n if (found) {\n // Re-evaluate all sheets since named expressions can be referenced from anywhere\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n return found;\n }\n\n updateNamedExpression({\n expression,\n expressionName,\n sheetName,\n workbookName,\n }: {\n expression: string;\n expressionName: string;\n sheetName?: string;\n workbookName?: string;\n }) {\n this.namedExpressionManager.updateNamedExpression({\n expression,\n expressionName,\n sheetName,\n workbookName,\n });\n\n // Re-evaluate all sheets since named expressions can be referenced from anywhere\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n renameNamedExpression({\n expressionName,\n sheetName,\n workbookName,\n newName,\n }: {\n expressionName: string;\n sheetName?: string;\n workbookName?: string;\n newName: string;\n }) {\n const result = this.namedExpressionManager.renameNamedExpression({\n expressionName,\n sheetName,\n workbookName,\n newName,\n });\n\n // Update all formulas that reference this named expression in sheet cells\n this.workbookManager.updateAllFormulas((formula) =>\n renameNamedExpressionInFormula(formula, expressionName, newName)\n );\n\n // Update named expressions that reference this named expression\n this.namedExpressionManager.updateAllNamedExpressions((formula) =>\n renameNamedExpressionInFormula(formula, expressionName, newName)\n );\n\n // Re-evaluate all sheets since named expressions can be referenced from anywhere\n this.reevaluate();\n this.eventManager.emitUpdate();\n\n return result;\n }\n\n setNamedExpressions(\n opts: (\n | {\n type: \"global\";\n }\n | {\n type: \"sheet\";\n sheetName: string;\n workbookName: string;\n }\n | {\n type: \"workbook\";\n workbookName: string;\n }\n ) & {\n expressions: Map<string, NamedExpression>;\n }\n ) {\n this.namedExpressionManager.setNamedExpressions(opts);\n\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n //#endregion\n\n //#region Tables\n addTable(props: {\n tableName: string;\n sheetName: string;\n workbookName: string;\n start: string;\n numRows: SpreadsheetRangeEnd;\n numCols: number;\n }) {\n const table = this.tableManager.addTable({\n ...props,\n getCellValue: (cellAddress: CellAddress) =>\n this.getCellValue(cellAddress),\n });\n\n // Re-evaluate all sheets since structured references might depend on this table\n this.reevaluate();\n this.eventManager.emitUpdate();\n\n return table;\n }\n\n renameTable(\n workbookName: string,\n names: { oldName: string; newName: string }\n ) {\n this.tableManager.renameTable(workbookName, names);\n\n // Update all formulas that reference this table in sheet cells\n this.workbookManager.updateAllFormulas((formula) =>\n renameTableInFormula(formula, names.oldName, names.newName)\n );\n\n // Update named expressions that reference this table\n this.namedExpressionManager.updateAllNamedExpressions((formula) =>\n renameTableInFormula(formula, names.oldName, names.newName)\n );\n\n // Re-evaluate all sheets since structured references might depend on this table\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n updateTable(opts: {\n tableName: string;\n sheetName?: string;\n start?: string;\n numRows?: SpreadsheetRangeEnd;\n numCols?: number;\n workbookName: string;\n }) {\n this.tableManager.updateTable({\n ...opts,\n getCellValue: (cellAddress: CellAddress) =>\n this.getCellValue(cellAddress),\n });\n\n // Re-evaluate all sheets since structured references might depend on this table\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n removeTable(opts: { tableName: string; workbookName: string }) {\n const found = this.tableManager.removeTable(opts);\n\n if (found) {\n // Re-evaluate all sheets since structured references might depend on this table\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n return found;\n }\n\n resetTables(tables: Map<string, Map<string, TableDefinition>>) {\n this.tableManager.resetTables(tables);\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n getTables(workbookName: string) {\n return this.tableManager.getTables(workbookName);\n }\n\n isCellInTable(cellAddress: CellAddress): TableDefinition | undefined {\n return this.tableManager.isCellInTable(cellAddress);\n }\n\n //#endregion\n\n //#region Conditional Styling\n /**\n * Add a conditional style rule\n */\n addConditionalStyle(style: ConditionalStyle): void {\n this.styleManager.addConditionalStyle(style);\n this.eventManager.emitUpdate();\n }\n\n /**\n * Remove a conditional style rule by index\n */\n removeConditionalStyle(workbookName: string, index: number): boolean {\n const removed = this.styleManager.removeConditionalStyle(workbookName, index);\n if (removed) {\n this.eventManager.emitUpdate();\n }\n return removed;\n }\n\n /**\n * Get all conditional styles for a range\n */\n getConditionalStyles(range: RangeAddress): ConditionalStyle[] {\n return this.styleManager.getConditionalStyles(range);\n }\n\n /**\n * Get the computed style for a specific cell\n */\n getCellStyle(cellAddress: CellAddress): CellStyle | undefined {\n return this.styleManager.getCellStyle(cellAddress);\n }\n\n /**\n * Add a direct cell style rule\n */\n addCellStyle(style: DirectCellStyle): void {\n this.styleManager.addCellStyle(style);\n this.eventManager.emitUpdate();\n }\n\n /**\n * Remove a direct cell style rule by index\n */\n removeCellStyle(workbookName: string, index: number): boolean {\n const removed = this.styleManager.removeCellStyle(workbookName, index);\n if (removed) {\n this.eventManager.emitUpdate();\n }\n return removed;\n }\n\n /**\n * Get all direct cell styles for a range\n */\n getCellStyles(range: RangeAddress): DirectCellStyle[] {\n return this.styleManager.getCellStyles(range);\n }\n\n /**\n * Clear all cell styles and conditional styles for a given range\n * Adjusts existing style ranges rather than deleting them entirely\n */\n clearCellStyles(range: RangeAddress): void {\n this.styleManager.clearCellStyles(range);\n this.eventManager.emitUpdate();\n }\n\n //#endregion\n\n //#region Copy/Paste\n /**\n * Copy cells from source to target\n */\n copyCells(\n source: CellAddress[],\n target: CellAddress,\n options: CopyCellsOptions\n ): void {\n this.copyManager.copyCells(source, target, options);\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n //#endregion\n\n //#region Sheets\n addSheet(opts: { workbookName: string; sheetName: string }) {\n const newSheet = this.workbookManager.addSheet(opts);\n const wbLevel = this.namedExpressionManager.addSheet(opts);\n this.reevaluate();\n this.eventManager.emitUpdate();\n return newSheet;\n }\n\n removeSheet(opts: { workbookName: string; sheetName: string }) {\n const sheet = this.workbookManager.removeSheet(opts);\n\n // Clean up related data\n this.namedExpressionManager.removeSheet(opts);\n this.tableManager.removeSheet(opts);\n this.styleManager.removeSheetStyles(opts.workbookName, opts.sheetName);\n\n // Add engine-specific logic: re-evaluate since references might be affected\n this.reevaluate();\n this.eventManager.emitUpdate();\n\n return sheet;\n }\n\n renameSheet(opts: {\n sheetName: string;\n newSheetName: string;\n workbookName: string;\n }) {\n const sheet = this.workbookManager.renameSheet(opts);\n\n // Update scoped named expressions\n this.namedExpressionManager.renameSheet(opts);\n\n // Update tables that belong to the renamed sheet\n this.tableManager.updateTablesForSheetRename(opts);\n\n // Update conditional styles that reference this sheet\n this.styleManager.updateSheetName(\n opts.workbookName,\n opts.sheetName,\n opts.newSheetName\n );\n\n // Update all formulas that reference this sheet\n this.workbookManager.updateAllFormulas((formula) =>\n renameSheetInFormula({\n formula,\n oldSheetName: opts.sheetName,\n newSheetName: opts.newSheetName,\n })\n );\n\n // Add engine-specific logic: re-evaluate since references might be affected\n this.reevaluate();\n this.eventManager.emitUpdate();\n\n return sheet;\n }\n\n getSheets(workbookName: string) {\n return this.workbookManager.getSheets(workbookName);\n }\n\n getSheet({\n workbookName,\n sheetName,\n }: {\n workbookName: string;\n sheetName: string;\n }) {\n return this.workbookManager.getSheet({ workbookName, sheetName });\n }\n\n getSheetSerialized(opts: {\n sheetName: string;\n workbookName: string;\n }): Map<string, SerializedCellValue> {\n return this.workbookManager.getSheetSerialized(opts);\n }\n\n //#endregion\n\n //#region Workbook\n addWorkbook(workbookName: string) {\n this.workbookManager.addWorkbook(workbookName);\n this.namedExpressionManager.addWorkbook(workbookName);\n this.tableManager.addWorkbook(workbookName);\n\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n removeWorkbook(workbookName: string) {\n this.workbookManager.removeWorkbook(workbookName);\n this.namedExpressionManager.removeWorkbook(workbookName);\n this.tableManager.removeWorkbook(workbookName);\n this.styleManager.removeWorkbookStyles(workbookName);\n\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n cloneWorkbook(fromWorkbookName: string, toWorkbookName: string) {\n // Check if source workbook exists\n const sourceWorkbook = this.workbookManager\n .getWorkbooks()\n .get(fromWorkbookName);\n if (!sourceWorkbook) {\n throw new Error(`Source workbook \"${fromWorkbookName}\" not found`);\n }\n\n // Check if target workbook name already exists\n if (this.workbookManager.getWorkbooks().has(toWorkbookName)) {\n throw new Error(`Target workbook \"${toWorkbookName}\" already exists`);\n }\n\n // Create new workbook\n this.addWorkbook(toWorkbookName);\n\n // Clone all sheets from source workbook\n for (const [sheetName, sheet] of sourceWorkbook.sheets) {\n // Add sheet to target workbook\n this.addSheet({\n workbookName: toWorkbookName,\n sheetName: sheetName,\n });\n\n // Copy all cell content using setSheetContent for efficiency\n this.setSheetContent(\n {\n workbookName: toWorkbookName,\n sheetName: sheetName,\n },\n new Map(sheet.content)\n );\n }\n\n // Clone workbook-scoped named expressions\n const sourceWorkbookExpressions = this.namedExpressionManager\n .getNamedExpressions()\n .workbookExpressions.get(fromWorkbookName);\n if (sourceWorkbookExpressions) {\n for (const [name, expression] of sourceWorkbookExpressions) {\n this.addNamedExpression({\n expressionName: name,\n expression: expression.expression,\n workbookName: toWorkbookName,\n });\n }\n }\n\n // Clone sheet-scoped named expressions\n const sourceSheetExpressions = this.namedExpressionManager\n .getNamedExpressions()\n .sheetExpressions.get(fromWorkbookName);\n if (sourceSheetExpressions) {\n for (const [sheetName, sheetExpressions] of sourceSheetExpressions) {\n for (const [name, expression] of sheetExpressions) {\n this.addNamedExpression({\n expressionName: name,\n expression: expression.expression,\n workbookName: toWorkbookName,\n sheetName: sheetName,\n });\n }\n }\n }\n\n // Clone tables\n const sourceTables = this.tableManager.tables.get(fromWorkbookName);\n if (sourceTables) {\n for (const [tableName, table] of sourceTables) {\n this.tableManager.copyTable(\n {\n workbookName: fromWorkbookName,\n tableName: tableName,\n },\n {\n workbookName: toWorkbookName,\n tableName: tableName,\n }\n );\n }\n }\n\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n renameWorkbook(opts: { workbookName: string; newWorkbookName: string }) {\n this.workbookManager.renameWorkbook(opts);\n\n // Update scoped named expressions\n this.namedExpressionManager.renameWorkbook(opts);\n\n // Update tables that belong to the renamed sheet\n this.tableManager.updateTablesForWorkbookRename(opts);\n\n // Update conditional styles that reference this workbook\n this.styleManager.updateWorkbookName(\n opts.workbookName,\n opts.newWorkbookName\n );\n\n // Update all formulas that reference this workbook\n this.workbookManager.updateAllFormulas((formula) =>\n renameWorkbookInFormula({\n formula,\n oldWorkbookName: opts.workbookName,\n newWorkbookName: opts.newWorkbookName,\n })\n );\n\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n getWorkbooks() {\n return this.workbookManager.getWorkbooks();\n }\n //#endregion\n\n //#region CRUD Operations\n /**\n * Overrides the content of a sheet.\n * @param sheetName - The name of the sheet to set the content of\n * @param content - A map of cell addresses to their serialized values\n * @remarks This method is used to set the content of a sheet. It will re-evaluate all sheets to ensure all dependencies are resolved correctly.\n */\n setSheetContent(\n opts: { sheetName: string; workbookName: string },\n content: Map<string, SerializedCellValue>\n ) {\n this.workbookManager.setSheetContent(opts, content);\n\n // Re-evaluate all sheets to ensure all dependencies are resolved correctly\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n setCellContent(address: CellAddress, content: SerializedCellValue) {\n this.workbookManager.setCellContent(address, content);\n\n // Re-evaluate all sheets to ensure all dependencies are resolved correctly\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n //#endregion\n\n //#region Evaluation\n\n /**\n * Re-evaluates all sheets to ensure all dependencies are resolved correctly\n *\n * but just clears the evaluation cache\n */\n reevaluate() {\n this.evaluationManager.clearEvaluationCache();\n }\n //#endregion\n\n //#region Auto-fill\n /**\n * Auto-fills the fillRange based on the seedRange and the direction.\n */\n autoFill(\n opts: { sheetName: string; workbookName: string },\n /**\n * The user's original selection that defines the pattern/series.\n */\n seedRange: SpreadsheetRange,\n /**\n * the new cells populated by the drag, excluding the seed\n */\n fillRange: SpreadsheetRange,\n /**\n * The direction of the fill.\n */\n direction: FillDirection\n ) {\n this.autoFillManager.fill(opts, seedRange, fillRange, direction);\n }\n\n /**\n * Removes the content in the spreadsheet that is inside the range.\n */\n clearSpreadsheetRange(address: RangeAddress) {\n this.workbookManager.clearSpreadsheetRange(address);\n\n // Re-evaluate all sheets to ensure all dependencies are resolved correctly\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n //#endregion\n\n //#region State - UI library integration\n getState() {\n return {\n workbooks: this.workbookManager.getWorkbooks(),\n namedExpressions: this.namedExpressionManager.getNamedExpressions(),\n tables: this.tableManager.tables,\n conditionalStyles: this.styleManager.getAllConditionalStyles(),\n cellStyles: this.styleManager.getAllCellStyles(),\n };\n }\n\n onUpdate(listener: () => void) {\n return this.eventManager.onUpdate(listener);\n }\n\n serializeEngine(): string {\n return serialize(this.getState());\n }\n\n resetToSerializedEngine(data: string) {\n const deserialized = deserialize(data) as ReturnType<typeof this.getState>;\n\n this.workbookManager.resetWorkbooks(deserialized.workbooks);\n\n deserialized.workbooks.forEach((workbook) => {\n this.namedExpressionManager.addWorkbook(workbook.name);\n this.tableManager.addWorkbook(workbook.name);\n workbook.sheets.forEach((sheet) => {\n this.namedExpressionManager.addSheet({\n workbookName: workbook.name,\n sheetName: sheet.name,\n });\n });\n });\n\n this.namedExpressionManager.resetNamedExpressions(\n deserialized.namedExpressions\n );\n this.tableManager.resetTables(deserialized.tables);\n \n // Reset styles if present\n // Handle backward compatibility: if conditionalStyles is a Map, convert it\n let conditionalStylesArray: ConditionalStyle[] | undefined;\n let cellStylesArray: DirectCellStyle[] | undefined;\n \n if (deserialized.conditionalStyles) {\n if (deserialized.conditionalStyles instanceof Map) {\n // Old format: Map<string, ConditionalStyle[]>\n conditionalStylesArray = Array.from(deserialized.conditionalStyles.values()).flat();\n } else if (Array.isArray(deserialized.conditionalStyles)) {\n // New format: ConditionalStyle[]\n conditionalStylesArray = deserialized.conditionalStyles;\n }\n }\n \n if (deserialized.cellStyles) {\n if (Array.isArray(deserialized.cellStyles)) {\n cellStylesArray = deserialized.cellStyles;\n }\n }\n \n this.styleManager.resetStyles(conditionalStylesArray, cellStylesArray);\n\n // Re-evaluate all sheets to ensure all dependencies are resolved correctly\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n //#endregion\n}\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqBiC,IAAjC;AACyB,IAAzB;AACgC,IAAhC;AACuC,IAAvC;AAC+C,IAA/C;AACqC,IAArC;AACqC,IAArC;AACwC,IAAxC;AAE6B,IAA7B;AACuC,IAAvC;AAC6B,IAA7B;AAC6B,IAA7B;AACkC,IAAlC;AACkC,IAAlC;AAC6B,IAA7B;AAC4B,IAA5B;AAAA;AAKO,MAAM,cAAc;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAKD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEP,WAAW,GAAG;AAAA,IACZ,KAAK,eAAe,IAAI;AAAA,IACxB,KAAK,kBAAkB,IAAI;AAAA,IAC3B,KAAK,yBAAyB,IAAI;AAAA,IAClC,KAAK,eAAe,IAAI,kCAAa,KAAK,eAAe;AAAA,IACzD,MAAM,eAAe,IAAI;AAAA,IACzB,KAAK,oBAAoB,IAAI,4CAC3B,cACA,KAAK,eACP;AAAA,IAEA,MAAM,mBAAmB,IAAI,0CAC3B,KAAK,cACL,KAAK,mBACL,KAAK,sBACP;AAAA,IAEA,KAAK,oBAAoB,IAAI,4CAC3B,KAAK,iBACL,KAAK,cACL,kBACA,KAAK,iBACP;AAAA,IAEA,KAAK,eAAe,IAAI,kCACtB,KAAK,
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "3C5F3EFFB9C7440364756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -37,12 +37,10 @@ var import_color_utils = require("../utils/color-utils.cjs");
|
|
|
37
37
|
var import_range_utils = require("../utils/range-utils.cjs");
|
|
38
38
|
|
|
39
39
|
class StyleManager {
|
|
40
|
-
workbookManager;
|
|
41
40
|
evaluationManager;
|
|
42
41
|
conditionalStyles = [];
|
|
43
42
|
cellStyles = [];
|
|
44
|
-
constructor(
|
|
45
|
-
this.workbookManager = workbookManager;
|
|
43
|
+
constructor(evaluationManager) {
|
|
46
44
|
this.evaluationManager = evaluationManager;
|
|
47
45
|
}
|
|
48
46
|
addConditionalStyle(style) {
|
|
@@ -66,8 +64,8 @@ class StyleManager {
|
|
|
66
64
|
}
|
|
67
65
|
return false;
|
|
68
66
|
}
|
|
69
|
-
getConditionalStyles(
|
|
70
|
-
return this.conditionalStyles.filter((style) => style && style.area && style.area.
|
|
67
|
+
getConditionalStyles(range) {
|
|
68
|
+
return this.conditionalStyles.filter((style) => style.area.workbookName === range.workbookName && style.area.sheetName === range.sheetName && import_range_utils.rangesIntersect(style.area.range, range.range));
|
|
71
69
|
}
|
|
72
70
|
addCellStyle(style) {
|
|
73
71
|
this.cellStyles.push(style);
|
|
@@ -90,8 +88,8 @@ class StyleManager {
|
|
|
90
88
|
}
|
|
91
89
|
return false;
|
|
92
90
|
}
|
|
93
|
-
getCellStyles(
|
|
94
|
-
return this.cellStyles.filter((style) => style && style.area && style.area.workbookName === workbookName);
|
|
91
|
+
getCellStyles(range) {
|
|
92
|
+
return this.cellStyles.filter((style) => style && style.area.sheetName === range.sheetName && style.area.workbookName === range.workbookName && import_range_utils.rangesIntersect(style.area.range, range.range));
|
|
95
93
|
}
|
|
96
94
|
getAllConditionalStyles() {
|
|
97
95
|
return [...this.conditionalStyles];
|
|
@@ -384,4 +382,4 @@ class StyleManager {
|
|
|
384
382
|
}
|
|
385
383
|
}
|
|
386
384
|
|
|
387
|
-
//# debugId=
|
|
385
|
+
//# debugId=18836366B9A1BC4164756E2164756E21
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/core/managers/style-manager.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"/**\n * StyleManager - Manages conditional styling for cells\n */\n\nimport type {\n CellAddress,\n CellStyle,\n ConditionalStyle,\n DirectCellStyle,\n RangeAddress,\n SerializedCellValue,\n} from \"../types.cjs\";\nimport type { WorkbookManager } from \"./workbook-manager.cjs\";\nimport type { EvaluationManager } from \"./evaluation-manager.cjs\";\nimport { isCellInRange } from \"../utils.cjs\";\nimport {\n calculateGradientFactor,\n interpolateLCH,\n lchToHex,\n} from \"../utils/color-utils.cjs\";\nimport { subtractRange, rangesIntersect } from \"../utils/range-utils.cjs\";\n\nexport class StyleManager {\n private conditionalStyles: ConditionalStyle[] = [];\n private cellStyles: DirectCellStyle[] = [];\n\n constructor(\n private workbookManager: WorkbookManager,\n private evaluationManager: EvaluationManager\n ) {}\n\n /**\n * Add a conditional style rule\n */\n addConditionalStyle(style: ConditionalStyle): void {\n this.conditionalStyles.push(style);\n }\n\n /**\n * Remove a conditional style rule by index for a specific workbook\n */\n removeConditionalStyle(workbookName: string, index: number): boolean {\n const workbookStyles = this.conditionalStyles.filter(\n (style) => style.area.workbookName === workbookName\n );\n if (index < 0 || index >= workbookStyles.length) {\n return false;\n }\n // Find the actual index in the full array\n let currentIndex = 0;\n for (let i = 0; i < this.conditionalStyles.length; i++) {\n const style = this.conditionalStyles[i];\n if (style && style.area.workbookName === workbookName) {\n if (currentIndex === index) {\n this.conditionalStyles.splice(i, 1);\n return true;\n }\n currentIndex++;\n }\n }\n return false;\n }\n\n /**\n * Get all conditional styles for a workbook\n */\n getConditionalStyles(workbookName: string): ConditionalStyle[] {\n return this.conditionalStyles.filter(\n (style) => style && style.area && style.area.workbookName === workbookName\n );\n }\n\n /**\n * Add a direct cell style rule\n */\n addCellStyle(style: DirectCellStyle): void {\n this.cellStyles.push(style);\n }\n\n /**\n * Remove a direct cell style rule by index for a specific workbook\n */\n removeCellStyle(workbookName: string, index: number): boolean {\n const workbookStyles = this.cellStyles.filter(\n (style) => style && style.area && style.area.workbookName === workbookName\n );\n if (index < 0 || index >= workbookStyles.length) {\n return false;\n }\n // Find the actual index in the full array\n let currentIndex = 0;\n for (let i = 0; i < this.cellStyles.length; i++) {\n const style = this.cellStyles[i];\n if (style && style.area && style.area.workbookName === workbookName) {\n if (currentIndex === index) {\n this.cellStyles.splice(i, 1);\n return true;\n }\n currentIndex++;\n }\n }\n return false;\n }\n\n /**\n * Get all direct cell styles for a workbook\n */\n getCellStyles(workbookName: string): DirectCellStyle[] {\n return this.cellStyles.filter(\n (style) => style && style.area && style.area.workbookName === workbookName\n );\n }\n\n /**\n * Get all conditional styles across all workbooks (for serialization)\n */\n getAllConditionalStyles(): ConditionalStyle[] {\n return [...this.conditionalStyles];\n }\n\n /**\n * Get all cell styles (for serialization)\n */\n getAllCellStyles(): DirectCellStyle[] {\n return [...this.cellStyles];\n }\n\n /**\n * Reset all styles (for deserialization)\n */\n resetStyles(\n conditionalStyles?: ConditionalStyle[],\n cellStyles?: DirectCellStyle[]\n ): void {\n this.conditionalStyles = conditionalStyles ? [...conditionalStyles] : [];\n this.cellStyles = cellStyles ? [...cellStyles] : [];\n }\n\n /**\n * Remove all styles for a workbook\n */\n removeWorkbookStyles(workbookName: string): void {\n this.conditionalStyles = this.conditionalStyles.filter(\n (style) => style.area.workbookName !== workbookName\n );\n this.cellStyles = this.cellStyles.filter(\n (style) => style.area.workbookName !== workbookName\n );\n }\n\n /**\n * Update workbook name in all style references\n */\n updateWorkbookName(oldName: string, newName: string): void {\n // Update conditional styles\n this.conditionalStyles = this.conditionalStyles.map((style) => {\n if (style.area.workbookName === oldName) {\n return {\n ...style,\n area: {\n ...style.area,\n workbookName: newName,\n },\n };\n }\n return style;\n });\n // Update cell styles\n this.cellStyles = this.cellStyles.map((style) => {\n if (style.area.workbookName === oldName) {\n return {\n ...style,\n area: {\n ...style.area,\n workbookName: newName,\n },\n };\n }\n return style;\n });\n }\n\n /**\n * Update sheet name in style references\n */\n updateSheetName(\n workbookName: string,\n oldSheetName: string,\n newSheetName: string\n ): void {\n // Update conditional styles\n this.conditionalStyles = this.conditionalStyles.map((style) => {\n if (\n style.area.workbookName === workbookName &&\n style.area.sheetName === oldSheetName\n ) {\n return {\n ...style,\n area: {\n ...style.area,\n sheetName: newSheetName,\n },\n };\n }\n return style;\n });\n // Update cell styles\n this.cellStyles = this.cellStyles.map((style) => {\n if (\n style.area.workbookName === workbookName &&\n style.area.sheetName === oldSheetName\n ) {\n return {\n ...style,\n area: {\n ...style.area,\n sheetName: newSheetName,\n },\n };\n }\n return style;\n });\n }\n\n /**\n * Remove styles that reference a deleted sheet\n */\n removeSheetStyles(workbookName: string, sheetName: string): void {\n this.conditionalStyles = this.conditionalStyles.filter(\n (style) =>\n !(\n style.area.workbookName === workbookName &&\n style.area.sheetName === sheetName\n )\n );\n this.cellStyles = this.cellStyles.filter(\n (style) =>\n !(\n style.area.workbookName === workbookName &&\n style.area.sheetName === sheetName\n )\n );\n }\n\n /**\n * Get the style for a specific cell\n * Returns the first matching style (first match wins)\n * Checks cellStyles first, then conditionalStyles\n */\n getCellStyle(cellAddress: CellAddress): CellStyle | undefined {\n // First check direct cell styles\n for (const cellStyle of this.cellStyles) {\n if (!cellStyle || !cellStyle.area) {\n continue;\n }\n if (\n cellStyle.area.workbookName === cellAddress.workbookName &&\n cellStyle.area.sheetName === cellAddress.sheetName &&\n isCellInRange(cellAddress, cellStyle.area.range)\n ) {\n return cellStyle.style;\n }\n }\n\n // Then check conditional styles\n for (const style of this.conditionalStyles) {\n if (!style || !style.area) {\n continue;\n }\n // Check if cell is in the style's area\n if (\n style.area.sheetName !== cellAddress.sheetName ||\n style.area.workbookName !== cellAddress.workbookName\n ) {\n continue;\n }\n\n if (!isCellInRange(cellAddress, style.area.range)) {\n continue;\n }\n\n // Cell is in area, evaluate condition\n if (style.condition.type === \"formula\") {\n const result = this.evaluateFormulaCondition(cellAddress, style);\n if (result) return result;\n } else {\n const result = this.evaluateGradientCondition(cellAddress, style);\n if (result) return result;\n }\n }\n\n return undefined;\n }\n\n /**\n * Evaluate a formula-based style condition\n */\n private evaluateFormulaCondition(\n cellAddress: CellAddress,\n style: ConditionalStyle\n ): CellStyle | undefined {\n if (style.condition.type !== \"formula\") {\n return undefined;\n }\n\n try {\n // Evaluate formula in context of the cell\n // evaluateFormula expects a full cell value (with = prefix for formulas)\n const formula = style.condition.formula.startsWith(\"=\")\n ? style.condition.formula\n : `=${style.condition.formula}`;\n\n const result = this.evaluationManager.evaluateFormula(\n formula,\n cellAddress\n );\n\n // Check if result is truthy\n const isTruthy =\n result === true ||\n result === \"TRUE\" ||\n (typeof result === \"number\" && result !== 0);\n\n if (isTruthy) {\n return {\n backgroundColor: lchToHex(style.condition.color),\n };\n }\n } catch (error) {\n // If formula evaluation fails, don't apply style\n console.warn(\"Failed to evaluate formula condition:\", error);\n }\n\n return undefined;\n }\n\n /**\n * Evaluate a gradient-based style condition\n */\n private evaluateGradientCondition(\n cellAddress: CellAddress,\n style: ConditionalStyle\n ): CellStyle | undefined {\n if (style.condition.type !== \"gradient\") {\n return undefined;\n }\n\n try {\n // Get the cell's evaluation result\n const evalResult =\n this.evaluationManager.getCellEvaluationResult(cellAddress);\n if (!evalResult || evalResult.type !== \"value\") {\n return undefined;\n }\n if (evalResult.result.type !== \"number\") {\n return undefined;\n }\n const cellValue = evalResult.result.value;\n\n // Calculate min and max values for the gradient\n const { min: minValue, max: maxValue } = this.calculateGradientBounds(\n style,\n cellAddress\n );\n\n if (minValue === null || maxValue === null) {\n return undefined;\n }\n\n // Calculate interpolation factor\n const factor = calculateGradientFactor(cellValue, minValue, maxValue);\n\n // Interpolate between min and max colors\n const minColor = style.condition.min.color;\n const maxColor = style.condition.max.color;\n const interpolatedColor = interpolateLCH(minColor, maxColor, factor);\n\n return {\n backgroundColor: lchToHex(interpolatedColor),\n };\n } catch (error) {\n console.warn(\"Failed to evaluate gradient condition:\", error);\n return undefined;\n }\n }\n\n /**\n * Calculate min and max bounds for a gradient\n */\n private calculateGradientBounds(\n style: ConditionalStyle,\n cellAddress: CellAddress\n ): { min: number | null; max: number | null } {\n if (style.condition.type !== \"gradient\") {\n return { min: null, max: null };\n }\n\n const { min: minConfig, max: maxConfig } = style.condition;\n const topLeftCell: CellAddress = {\n workbookName: style.area.workbookName,\n sheetName: style.area.sheetName,\n colIndex: style.area.range.start.col,\n rowIndex: style.area.range.start.row,\n };\n\n // Calculate min value\n let minValue: number | null = null;\n if (minConfig.type === \"lowest_value\") {\n // Evaluate MIN(range) formula directly\n try {\n const rangeRef = this.getRangeReference(style.area);\n const result = this.evaluationManager.evaluateFormula(\n `=MIN(${rangeRef})`,\n topLeftCell\n );\n if (typeof result === \"number\") {\n minValue = result;\n }\n } catch (error) {\n console.warn(\"Failed to calculate MIN:\", error);\n }\n } else {\n // Evaluate valueFormula in context of area's top-left cell\n const formula = minConfig.valueFormula.startsWith(\"=\")\n ? minConfig.valueFormula\n : `=${minConfig.valueFormula}`;\n const result = this.evaluationManager.evaluateFormula(\n formula,\n topLeftCell\n );\n if (typeof result === \"number\") {\n minValue = result;\n }\n }\n\n // Calculate max value\n let maxValue: number | null = null;\n if (maxConfig.type === \"highest_value\") {\n // Evaluate MAX(range) formula directly\n try {\n const rangeRef = this.getRangeReference(style.area);\n const result = this.evaluationManager.evaluateFormula(\n `=MAX(${rangeRef})`,\n topLeftCell\n );\n if (typeof result === \"number\") {\n maxValue = result;\n }\n } catch (error) {\n console.warn(\"Failed to calculate MAX:\", error);\n }\n } else {\n // Evaluate valueFormula in context of area's top-left cell\n const formula = maxConfig.valueFormula.startsWith(\"=\")\n ? maxConfig.valueFormula\n : `=${maxConfig.valueFormula}`;\n const result = this.evaluationManager.evaluateFormula(\n formula,\n topLeftCell\n );\n if (typeof result === \"number\") {\n maxValue = result;\n }\n }\n\n return { min: minValue, max: maxValue };\n }\n\n /**\n * Get a range reference string from a RangeAddress\n * Follows CANONICAL_RANGES.md format:\n * - Closed: A5:D10\n * - Row-bounded (col-open): A5:10\n * - Col-bounded (row-open): A5:D\n * - Open both: A5:INFINITY\n */\n private getRangeReference(area: RangeAddress): string {\n const colToLetter = (col: number): string => {\n let result = \"\";\n let c = col;\n while (c >= 0) {\n result = String.fromCharCode(65 + (c % 26)) + result;\n c = Math.floor(c / 26) - 1;\n }\n return result;\n };\n\n const startCol = colToLetter(area.range.start.col);\n const startRow = area.range.start.row + 1; // Convert to 1-based\n\n const isColInfinity = area.range.end.col.type === \"infinity\";\n const isRowInfinity = area.range.end.row.type === \"infinity\";\n\n let rangeStr: string;\n\n if (isColInfinity && isRowInfinity) {\n // Open both: A5:INFINITY\n rangeStr = `${startCol}${startRow}:INFINITY`;\n } else if (isColInfinity) {\n // Row-bounded (col-open): A5:10\n if (area.range.end.row.type === \"number\") {\n const endRow = area.range.end.row.value + 1; // Convert to 1-based\n rangeStr = `${startCol}${startRow}:${endRow}`;\n } else {\n rangeStr = `${startCol}${startRow}:INFINITY`;\n }\n } else if (isRowInfinity) {\n // Col-bounded (row-open): A5:D\n if (area.range.end.col.type === \"number\") {\n const endCol = colToLetter(area.range.end.col.value);\n rangeStr = `${startCol}${startRow}:${endCol}`;\n } else {\n rangeStr = `${startCol}${startRow}:INFINITY`;\n }\n } else {\n // Closed rectangle: A5:D10\n if (\n area.range.end.col.type === \"number\" &&\n area.range.end.row.type === \"number\"\n ) {\n const endCol = colToLetter(area.range.end.col.value);\n const endRow = area.range.end.row.value + 1; // Convert to 1-based\n rangeStr = `${startCol}${startRow}:${endCol}${endRow}`;\n } else {\n // Fallback to INFINITY if types don't match\n rangeStr = `${startCol}${startRow}:INFINITY`;\n }\n }\n\n // Quote sheet name if it contains spaces or special characters\n const needsQuotes = /[ '!]/.test(area.sheetName);\n const sheetRef = needsQuotes\n ? `'${area.sheetName.replace(/'/g, \"''\")}'`\n : area.sheetName;\n\n // Construct the full reference: [workbook]'sheet'!range\n return `[${area.workbookName}]${sheetRef}!${rangeStr}`;\n }\n\n /**\n * Clear cell styles and conditional styles for a given range\n * Adjusts existing style ranges rather than deleting them entirely\n */\n clearCellStyles(range: RangeAddress): void {\n // Process cellStyles\n const newCellStyles: DirectCellStyle[] = [];\n for (const cellStyle of this.cellStyles) {\n if (!cellStyle || !cellStyle.area) {\n newCellStyles.push(cellStyle);\n continue;\n }\n\n // Check if this style intersects with the clear range\n if (\n cellStyle.area.workbookName === range.workbookName &&\n cellStyle.area.sheetName === range.sheetName &&\n rangesIntersect(cellStyle.area.range, range.range)\n ) {\n // Subtract the clear range from this style's range\n const remainingRanges = subtractRange(cellStyle.area.range, range.range);\n \n // Add new styles for each remaining range\n for (const remainingRange of remainingRanges) {\n newCellStyles.push({\n area: {\n workbookName: cellStyle.area.workbookName,\n sheetName: cellStyle.area.sheetName,\n range: remainingRange,\n },\n style: cellStyle.style,\n });\n }\n } else {\n // No intersection, keep the style as-is\n newCellStyles.push(cellStyle);\n }\n }\n this.cellStyles = newCellStyles;\n\n // Process conditionalStyles\n const newConditionalStyles: ConditionalStyle[] = [];\n for (const conditionalStyle of this.conditionalStyles) {\n if (!conditionalStyle || !conditionalStyle.area) {\n newConditionalStyles.push(conditionalStyle);\n continue;\n }\n\n // Check if this style intersects with the clear range\n if (\n conditionalStyle.area.workbookName === range.workbookName &&\n conditionalStyle.area.sheetName === range.sheetName &&\n rangesIntersect(conditionalStyle.area.range, range.range)\n ) {\n // Subtract the clear range from this style's range\n const remainingRanges = subtractRange(conditionalStyle.area.range, range.range);\n \n // Add new styles for each remaining range\n for (const remainingRange of remainingRanges) {\n newConditionalStyles.push({\n area: {\n workbookName: conditionalStyle.area.workbookName,\n sheetName: conditionalStyle.area.sheetName,\n range: remainingRange,\n },\n condition: conditionalStyle.condition,\n });\n }\n } else {\n // No intersection, keep the style as-is\n newConditionalStyles.push(conditionalStyle);\n }\n }\n this.conditionalStyles = newConditionalStyles;\n }\n}\n"
|
|
5
|
+
"/**\n * StyleManager - Manages conditional styling for cells\n */\n\nimport type {\n CellAddress,\n CellStyle,\n ConditionalStyle,\n DirectCellStyle,\n RangeAddress,\n SerializedCellValue,\n} from \"../types.cjs\";\nimport type { WorkbookManager } from \"./workbook-manager.cjs\";\nimport type { EvaluationManager } from \"./evaluation-manager.cjs\";\nimport { isCellInRange } from \"../utils.cjs\";\nimport {\n calculateGradientFactor,\n interpolateLCH,\n lchToHex,\n} from \"../utils/color-utils.cjs\";\nimport { subtractRange, rangesIntersect } from \"../utils/range-utils.cjs\";\n\nexport class StyleManager {\n private conditionalStyles: ConditionalStyle[] = [];\n private cellStyles: DirectCellStyle[] = [];\n\n constructor(private evaluationManager: EvaluationManager) {}\n\n /**\n * Add a conditional style rule\n */\n addConditionalStyle(style: ConditionalStyle): void {\n this.conditionalStyles.push(style);\n }\n\n /**\n * Remove a conditional style rule by index for a specific workbook\n */\n removeConditionalStyle(workbookName: string, index: number): boolean {\n const workbookStyles = this.conditionalStyles.filter(\n (style) => style.area.workbookName === workbookName\n );\n if (index < 0 || index >= workbookStyles.length) {\n return false;\n }\n // Find the actual index in the full array\n let currentIndex = 0;\n for (let i = 0; i < this.conditionalStyles.length; i++) {\n const style = this.conditionalStyles[i];\n if (style && style.area.workbookName === workbookName) {\n if (currentIndex === index) {\n this.conditionalStyles.splice(i, 1);\n return true;\n }\n currentIndex++;\n }\n }\n return false;\n }\n\n /**\n * Get all conditional styles for a range\n */\n getConditionalStyles(range: RangeAddress): ConditionalStyle[] {\n return this.conditionalStyles.filter(\n (style) =>\n style.area.workbookName === range.workbookName &&\n style.area.sheetName === range.sheetName &&\n rangesIntersect(style.area.range, range.range)\n );\n }\n\n /**\n * Add a direct cell style rule\n */\n addCellStyle(style: DirectCellStyle): void {\n this.cellStyles.push(style);\n }\n\n /**\n * Remove a direct cell style rule by index for a specific workbook\n */\n removeCellStyle(workbookName: string, index: number): boolean {\n const workbookStyles = this.cellStyles.filter(\n (style) => style && style.area && style.area.workbookName === workbookName\n );\n if (index < 0 || index >= workbookStyles.length) {\n return false;\n }\n // Find the actual index in the full array\n let currentIndex = 0;\n for (let i = 0; i < this.cellStyles.length; i++) {\n const style = this.cellStyles[i];\n if (style && style.area && style.area.workbookName === workbookName) {\n if (currentIndex === index) {\n this.cellStyles.splice(i, 1);\n return true;\n }\n currentIndex++;\n }\n }\n return false;\n }\n\n /**\n * Get all direct cell styles for a workbook\n */\n getCellStyles(range: RangeAddress): DirectCellStyle[] {\n return this.cellStyles.filter(\n (style) =>\n style &&\n style.area.sheetName === range.sheetName &&\n style.area.workbookName === range.workbookName &&\n rangesIntersect(style.area.range, range.range)\n );\n }\n\n /**\n * Get all conditional styles across all workbooks (for serialization)\n */\n getAllConditionalStyles(): ConditionalStyle[] {\n return [...this.conditionalStyles];\n }\n\n /**\n * Get all cell styles (for serialization)\n */\n getAllCellStyles(): DirectCellStyle[] {\n return [...this.cellStyles];\n }\n\n /**\n * Reset all styles (for deserialization)\n */\n resetStyles(\n conditionalStyles?: ConditionalStyle[],\n cellStyles?: DirectCellStyle[]\n ): void {\n this.conditionalStyles = conditionalStyles ? [...conditionalStyles] : [];\n this.cellStyles = cellStyles ? [...cellStyles] : [];\n }\n\n /**\n * Remove all styles for a workbook\n */\n removeWorkbookStyles(workbookName: string): void {\n this.conditionalStyles = this.conditionalStyles.filter(\n (style) => style.area.workbookName !== workbookName\n );\n this.cellStyles = this.cellStyles.filter(\n (style) => style.area.workbookName !== workbookName\n );\n }\n\n /**\n * Update workbook name in all style references\n */\n updateWorkbookName(oldName: string, newName: string): void {\n // Update conditional styles\n this.conditionalStyles = this.conditionalStyles.map((style) => {\n if (style.area.workbookName === oldName) {\n return {\n ...style,\n area: {\n ...style.area,\n workbookName: newName,\n },\n };\n }\n return style;\n });\n // Update cell styles\n this.cellStyles = this.cellStyles.map((style) => {\n if (style.area.workbookName === oldName) {\n return {\n ...style,\n area: {\n ...style.area,\n workbookName: newName,\n },\n };\n }\n return style;\n });\n }\n\n /**\n * Update sheet name in style references\n */\n updateSheetName(\n workbookName: string,\n oldSheetName: string,\n newSheetName: string\n ): void {\n // Update conditional styles\n this.conditionalStyles = this.conditionalStyles.map((style) => {\n if (\n style.area.workbookName === workbookName &&\n style.area.sheetName === oldSheetName\n ) {\n return {\n ...style,\n area: {\n ...style.area,\n sheetName: newSheetName,\n },\n };\n }\n return style;\n });\n // Update cell styles\n this.cellStyles = this.cellStyles.map((style) => {\n if (\n style.area.workbookName === workbookName &&\n style.area.sheetName === oldSheetName\n ) {\n return {\n ...style,\n area: {\n ...style.area,\n sheetName: newSheetName,\n },\n };\n }\n return style;\n });\n }\n\n /**\n * Remove styles that reference a deleted sheet\n */\n removeSheetStyles(workbookName: string, sheetName: string): void {\n this.conditionalStyles = this.conditionalStyles.filter(\n (style) =>\n !(\n style.area.workbookName === workbookName &&\n style.area.sheetName === sheetName\n )\n );\n this.cellStyles = this.cellStyles.filter(\n (style) =>\n !(\n style.area.workbookName === workbookName &&\n style.area.sheetName === sheetName\n )\n );\n }\n\n /**\n * Get the style for a specific cell\n * Returns the first matching style (first match wins)\n * Checks cellStyles first, then conditionalStyles\n */\n getCellStyle(cellAddress: CellAddress): CellStyle | undefined {\n // First check direct cell styles\n for (const cellStyle of this.cellStyles) {\n if (!cellStyle || !cellStyle.area) {\n continue;\n }\n if (\n cellStyle.area.workbookName === cellAddress.workbookName &&\n cellStyle.area.sheetName === cellAddress.sheetName &&\n isCellInRange(cellAddress, cellStyle.area.range)\n ) {\n return cellStyle.style;\n }\n }\n\n // Then check conditional styles\n for (const style of this.conditionalStyles) {\n if (!style || !style.area) {\n continue;\n }\n // Check if cell is in the style's area\n if (\n style.area.sheetName !== cellAddress.sheetName ||\n style.area.workbookName !== cellAddress.workbookName\n ) {\n continue;\n }\n\n if (!isCellInRange(cellAddress, style.area.range)) {\n continue;\n }\n\n // Cell is in area, evaluate condition\n if (style.condition.type === \"formula\") {\n const result = this.evaluateFormulaCondition(cellAddress, style);\n if (result) return result;\n } else {\n const result = this.evaluateGradientCondition(cellAddress, style);\n if (result) return result;\n }\n }\n\n return undefined;\n }\n\n /**\n * Evaluate a formula-based style condition\n */\n private evaluateFormulaCondition(\n cellAddress: CellAddress,\n style: ConditionalStyle\n ): CellStyle | undefined {\n if (style.condition.type !== \"formula\") {\n return undefined;\n }\n\n try {\n // Evaluate formula in context of the cell\n // evaluateFormula expects a full cell value (with = prefix for formulas)\n const formula = style.condition.formula.startsWith(\"=\")\n ? style.condition.formula\n : `=${style.condition.formula}`;\n\n const result = this.evaluationManager.evaluateFormula(\n formula,\n cellAddress\n );\n\n // Check if result is truthy\n const isTruthy =\n result === true ||\n result === \"TRUE\" ||\n (typeof result === \"number\" && result !== 0);\n\n if (isTruthy) {\n return {\n backgroundColor: lchToHex(style.condition.color),\n };\n }\n } catch (error) {\n // If formula evaluation fails, don't apply style\n console.warn(\"Failed to evaluate formula condition:\", error);\n }\n\n return undefined;\n }\n\n /**\n * Evaluate a gradient-based style condition\n */\n private evaluateGradientCondition(\n cellAddress: CellAddress,\n style: ConditionalStyle\n ): CellStyle | undefined {\n if (style.condition.type !== \"gradient\") {\n return undefined;\n }\n\n try {\n // Get the cell's evaluation result\n const evalResult =\n this.evaluationManager.getCellEvaluationResult(cellAddress);\n if (!evalResult || evalResult.type !== \"value\") {\n return undefined;\n }\n if (evalResult.result.type !== \"number\") {\n return undefined;\n }\n const cellValue = evalResult.result.value;\n\n // Calculate min and max values for the gradient\n const { min: minValue, max: maxValue } = this.calculateGradientBounds(\n style,\n cellAddress\n );\n\n if (minValue === null || maxValue === null) {\n return undefined;\n }\n\n // Calculate interpolation factor\n const factor = calculateGradientFactor(cellValue, minValue, maxValue);\n\n // Interpolate between min and max colors\n const minColor = style.condition.min.color;\n const maxColor = style.condition.max.color;\n const interpolatedColor = interpolateLCH(minColor, maxColor, factor);\n\n return {\n backgroundColor: lchToHex(interpolatedColor),\n };\n } catch (error) {\n console.warn(\"Failed to evaluate gradient condition:\", error);\n return undefined;\n }\n }\n\n /**\n * Calculate min and max bounds for a gradient\n */\n private calculateGradientBounds(\n style: ConditionalStyle,\n cellAddress: CellAddress\n ): { min: number | null; max: number | null } {\n if (style.condition.type !== \"gradient\") {\n return { min: null, max: null };\n }\n\n const { min: minConfig, max: maxConfig } = style.condition;\n const topLeftCell: CellAddress = {\n workbookName: style.area.workbookName,\n sheetName: style.area.sheetName,\n colIndex: style.area.range.start.col,\n rowIndex: style.area.range.start.row,\n };\n\n // Calculate min value\n let minValue: number | null = null;\n if (minConfig.type === \"lowest_value\") {\n // Evaluate MIN(range) formula directly\n try {\n const rangeRef = this.getRangeReference(style.area);\n const result = this.evaluationManager.evaluateFormula(\n `=MIN(${rangeRef})`,\n topLeftCell\n );\n if (typeof result === \"number\") {\n minValue = result;\n }\n } catch (error) {\n console.warn(\"Failed to calculate MIN:\", error);\n }\n } else {\n // Evaluate valueFormula in context of area's top-left cell\n const formula = minConfig.valueFormula.startsWith(\"=\")\n ? minConfig.valueFormula\n : `=${minConfig.valueFormula}`;\n const result = this.evaluationManager.evaluateFormula(\n formula,\n topLeftCell\n );\n if (typeof result === \"number\") {\n minValue = result;\n }\n }\n\n // Calculate max value\n let maxValue: number | null = null;\n if (maxConfig.type === \"highest_value\") {\n // Evaluate MAX(range) formula directly\n try {\n const rangeRef = this.getRangeReference(style.area);\n const result = this.evaluationManager.evaluateFormula(\n `=MAX(${rangeRef})`,\n topLeftCell\n );\n if (typeof result === \"number\") {\n maxValue = result;\n }\n } catch (error) {\n console.warn(\"Failed to calculate MAX:\", error);\n }\n } else {\n // Evaluate valueFormula in context of area's top-left cell\n const formula = maxConfig.valueFormula.startsWith(\"=\")\n ? maxConfig.valueFormula\n : `=${maxConfig.valueFormula}`;\n const result = this.evaluationManager.evaluateFormula(\n formula,\n topLeftCell\n );\n if (typeof result === \"number\") {\n maxValue = result;\n }\n }\n\n return { min: minValue, max: maxValue };\n }\n\n /**\n * Get a range reference string from a RangeAddress\n * Follows CANONICAL_RANGES.md format:\n * - Closed: A5:D10\n * - Row-bounded (col-open): A5:10\n * - Col-bounded (row-open): A5:D\n * - Open both: A5:INFINITY\n */\n private getRangeReference(area: RangeAddress): string {\n const colToLetter = (col: number): string => {\n let result = \"\";\n let c = col;\n while (c >= 0) {\n result = String.fromCharCode(65 + (c % 26)) + result;\n c = Math.floor(c / 26) - 1;\n }\n return result;\n };\n\n const startCol = colToLetter(area.range.start.col);\n const startRow = area.range.start.row + 1; // Convert to 1-based\n\n const isColInfinity = area.range.end.col.type === \"infinity\";\n const isRowInfinity = area.range.end.row.type === \"infinity\";\n\n let rangeStr: string;\n\n if (isColInfinity && isRowInfinity) {\n // Open both: A5:INFINITY\n rangeStr = `${startCol}${startRow}:INFINITY`;\n } else if (isColInfinity) {\n // Row-bounded (col-open): A5:10\n if (area.range.end.row.type === \"number\") {\n const endRow = area.range.end.row.value + 1; // Convert to 1-based\n rangeStr = `${startCol}${startRow}:${endRow}`;\n } else {\n rangeStr = `${startCol}${startRow}:INFINITY`;\n }\n } else if (isRowInfinity) {\n // Col-bounded (row-open): A5:D\n if (area.range.end.col.type === \"number\") {\n const endCol = colToLetter(area.range.end.col.value);\n rangeStr = `${startCol}${startRow}:${endCol}`;\n } else {\n rangeStr = `${startCol}${startRow}:INFINITY`;\n }\n } else {\n // Closed rectangle: A5:D10\n if (\n area.range.end.col.type === \"number\" &&\n area.range.end.row.type === \"number\"\n ) {\n const endCol = colToLetter(area.range.end.col.value);\n const endRow = area.range.end.row.value + 1; // Convert to 1-based\n rangeStr = `${startCol}${startRow}:${endCol}${endRow}`;\n } else {\n // Fallback to INFINITY if types don't match\n rangeStr = `${startCol}${startRow}:INFINITY`;\n }\n }\n\n // Quote sheet name if it contains spaces or special characters\n const needsQuotes = /[ '!]/.test(area.sheetName);\n const sheetRef = needsQuotes\n ? `'${area.sheetName.replace(/'/g, \"''\")}'`\n : area.sheetName;\n\n // Construct the full reference: [workbook]'sheet'!range\n return `[${area.workbookName}]${sheetRef}!${rangeStr}`;\n }\n\n /**\n * Clear cell styles and conditional styles for a given range\n * Adjusts existing style ranges rather than deleting them entirely\n */\n clearCellStyles(range: RangeAddress): void {\n // Process cellStyles\n const newCellStyles: DirectCellStyle[] = [];\n for (const cellStyle of this.cellStyles) {\n if (!cellStyle || !cellStyle.area) {\n newCellStyles.push(cellStyle);\n continue;\n }\n\n // Check if this style intersects with the clear range\n if (\n cellStyle.area.workbookName === range.workbookName &&\n cellStyle.area.sheetName === range.sheetName &&\n rangesIntersect(cellStyle.area.range, range.range)\n ) {\n // Subtract the clear range from this style's range\n const remainingRanges = subtractRange(\n cellStyle.area.range,\n range.range\n );\n\n // Add new styles for each remaining range\n for (const remainingRange of remainingRanges) {\n newCellStyles.push({\n area: {\n workbookName: cellStyle.area.workbookName,\n sheetName: cellStyle.area.sheetName,\n range: remainingRange,\n },\n style: cellStyle.style,\n });\n }\n } else {\n // No intersection, keep the style as-is\n newCellStyles.push(cellStyle);\n }\n }\n this.cellStyles = newCellStyles;\n\n // Process conditionalStyles\n const newConditionalStyles: ConditionalStyle[] = [];\n for (const conditionalStyle of this.conditionalStyles) {\n if (!conditionalStyle || !conditionalStyle.area) {\n newConditionalStyles.push(conditionalStyle);\n continue;\n }\n\n // Check if this style intersects with the clear range\n if (\n conditionalStyle.area.workbookName === range.workbookName &&\n conditionalStyle.area.sheetName === range.sheetName &&\n rangesIntersect(conditionalStyle.area.range, range.range)\n ) {\n // Subtract the clear range from this style's range\n const remainingRanges = subtractRange(\n conditionalStyle.area.range,\n range.range\n );\n\n // Add new styles for each remaining range\n for (const remainingRange of remainingRanges) {\n newConditionalStyles.push({\n area: {\n workbookName: conditionalStyle.area.workbookName,\n sheetName: conditionalStyle.area.sheetName,\n range: remainingRange,\n },\n condition: conditionalStyle.condition,\n });\n }\n } else {\n // No intersection, keep the style as-is\n newConditionalStyles.push(conditionalStyle);\n }\n }\n this.conditionalStyles = newConditionalStyles;\n }\n}\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAc8B,IAA9B;AAKO,IAJP;AAK+C,IAA/C;AAAA;AAEO,MAAM,aAAa;AAAA,
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "18836366B9A1BC4164756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
package/dist/cjs/package.json
CHANGED
package/dist/mjs/core/engine.mjs
CHANGED
|
@@ -43,7 +43,7 @@ class FormulaEngine {
|
|
|
43
43
|
this.dependencyManager = new DependencyManager(cacheManager, this.workbookManager);
|
|
44
44
|
const formulaEvaluator = new FormulaEvaluator(this.tableManager, this.dependencyManager, this.namedExpressionManager);
|
|
45
45
|
this.evaluationManager = new EvaluationManager(this.workbookManager, this.tableManager, formulaEvaluator, this.dependencyManager);
|
|
46
|
-
this.styleManager = new StyleManager(this.
|
|
46
|
+
this.styleManager = new StyleManager(this.evaluationManager);
|
|
47
47
|
this.copyManager = new CopyManager(this.workbookManager, this.evaluationManager, this.styleManager);
|
|
48
48
|
this.autoFillManager = new AutoFill(this.workbookManager, this);
|
|
49
49
|
this._workbookManager = this.workbookManager;
|
|
@@ -200,8 +200,8 @@ class FormulaEngine {
|
|
|
200
200
|
}
|
|
201
201
|
return removed;
|
|
202
202
|
}
|
|
203
|
-
getConditionalStyles(
|
|
204
|
-
return this.styleManager.getConditionalStyles(
|
|
203
|
+
getConditionalStyles(range) {
|
|
204
|
+
return this.styleManager.getConditionalStyles(range);
|
|
205
205
|
}
|
|
206
206
|
getCellStyle(cellAddress) {
|
|
207
207
|
return this.styleManager.getCellStyle(cellAddress);
|
|
@@ -217,8 +217,8 @@ class FormulaEngine {
|
|
|
217
217
|
}
|
|
218
218
|
return removed;
|
|
219
219
|
}
|
|
220
|
-
getCellStyles(
|
|
221
|
-
return this.styleManager.getCellStyles(
|
|
220
|
+
getCellStyles(range) {
|
|
221
|
+
return this.styleManager.getCellStyles(range);
|
|
222
222
|
}
|
|
223
223
|
clearCellStyles(range) {
|
|
224
224
|
this.styleManager.clearCellStyles(range);
|
|
@@ -433,4 +433,4 @@ export {
|
|
|
433
433
|
FormulaEngine
|
|
434
434
|
};
|
|
435
435
|
|
|
436
|
-
//# debugId=
|
|
436
|
+
//# debugId=5C2BDBA1C9A73AE864756E2164756E21
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/core/engine.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"/**\n * Main FormulaEngine class\n * Core API implementation for spreadsheet calculations\n */\n\nimport {\n type CellAddress,\n type CellStyle,\n type ConditionalStyle,\n type CopyCellsOptions,\n type DirectCellStyle,\n type NamedExpression,\n type RangeAddress,\n type SerializedCellValue,\n type SingleEvaluationResult,\n type SpreadsheetRange,\n type SpreadsheetRangeEnd,\n type TableDefinition,\n} from \"./types.mjs\";\n\nimport type { FillDirection } from \"@ricsam/selection-manager\";\nimport { FormulaEvaluator } from \"../evaluator/formula-evaluator.mjs\";\nimport { AutoFill } from \"./autofill-utils.mjs\";\nimport { WorkbookManager } from \"./managers/workbook-manager.mjs\";\nimport { deserialize, serialize } from \"./map-serializer.mjs\";\nimport { renameNamedExpressionInFormula } from \"./named-expression-renamer.mjs\";\nimport { renameSheetInFormula } from \"./sheet-renamer.mjs\";\nimport { renameTableInFormula } from \"./table-renamer.mjs\";\nimport { renameWorkbookInFormula } from \"./workbook-renamer.mjs\";\nimport { cellAddressToKey, keyToCellAddress } from \"./utils.mjs\";\nimport { CacheManager } from \"./managers/cache-manager.mjs\";\nimport { NamedExpressionManager } from \"./managers/named-expression-manager.mjs\";\nimport { TableManager } from \"./managers/table-manager.mjs\";\nimport { EventManager } from \"./managers/event-manager.mjs\";\nimport { EvaluationManager } from \"./managers/evaluation-manager.mjs\";\nimport { DependencyManager } from \"./managers/dependency-manager.mjs\";\nimport { StyleManager } from \"./managers/style-manager.mjs\";\nimport { CopyManager } from \"./managers/copy-manager.mjs\";\n\n/**\n * Main FormulaEngine class\n */\nexport class FormulaEngine {\n private workbookManager: WorkbookManager;\n private namedExpressionManager: NamedExpressionManager;\n private tableManager: TableManager;\n private eventManager: EventManager;\n private evaluationManager: EvaluationManager;\n private autoFillManager: AutoFill;\n private dependencyManager: DependencyManager;\n private styleManager: StyleManager;\n private copyManager: CopyManager;\n\n /**\n * Public access to the store manager for testing\n */\n public _workbookManager: WorkbookManager;\n public _namedExpressionManager: NamedExpressionManager;\n public _tableManager: TableManager;\n public _eventManager: EventManager;\n public _evaluationManager: EvaluationManager;\n public _autoFillManager: AutoFill;\n public _dependencyManager: DependencyManager;\n public _styleManager: StyleManager;\n\n constructor() {\n this.eventManager = new EventManager();\n this.workbookManager = new WorkbookManager();\n this.namedExpressionManager = new NamedExpressionManager();\n this.tableManager = new TableManager(this.workbookManager);\n const cacheManager = new CacheManager();\n this.dependencyManager = new DependencyManager(\n cacheManager,\n this.workbookManager\n );\n\n const formulaEvaluator = new FormulaEvaluator(\n this.tableManager,\n this.dependencyManager,\n this.namedExpressionManager,\n );\n\n this.evaluationManager = new EvaluationManager(\n this.workbookManager,\n this.tableManager,\n formulaEvaluator,\n this.dependencyManager\n );\n\n this.styleManager = new StyleManager(\n this.workbookManager,\n this.evaluationManager\n );\n this.copyManager = new CopyManager(\n this.workbookManager,\n this.evaluationManager,\n this.styleManager\n );\n\n this.autoFillManager = new AutoFill(this.workbookManager, this);\n\n this._workbookManager = this.workbookManager;\n this._namedExpressionManager = this.namedExpressionManager;\n this._tableManager = this.tableManager;\n this._eventManager = this.eventManager;\n this._evaluationManager = this.evaluationManager;\n this._autoFillManager = this.autoFillManager;\n this._dependencyManager = this.dependencyManager;\n this._styleManager = this.styleManager;\n }\n\n /**\n * Static factory method to build an empty engine\n */\n static buildEmpty(): FormulaEngine {\n return new FormulaEngine();\n }\n\n //#region Cell\n getCellEvaluationResult(\n cellAddress: CellAddress\n ): SingleEvaluationResult | undefined {\n return this.evaluationManager.getCellEvaluationResult(cellAddress);\n }\n\n getCellValue(cellAddress: CellAddress, debug?: boolean): SerializedCellValue {\n const result = this.getCellEvaluationResult(cellAddress);\n if (!result) {\n return \"\";\n }\n\n return this.evaluationManager.evaluationResultToSerializedValue(\n result,\n cellAddress,\n debug\n );\n }\n\n evaluateFormula(\n /**\n * formula without the leading = sign\n */\n formula: string, cellAddress: CellAddress): SerializedCellValue {\n return this.evaluationManager.evaluateFormula(formula, cellAddress);\n }\n\n getCellDependents(\n address: CellAddress | SpreadsheetRange\n ): (SpreadsheetRange | CellAddress)[] {\n throw new Error(\"Not implemented\");\n }\n\n getCellPrecedents(\n address: CellAddress | SpreadsheetRange\n ): (SpreadsheetRange | CellAddress)[] {\n throw new Error(\"Not implemented\");\n }\n\n //#endregion\n\n //#region Named Expressions\n addNamedExpression({\n expression,\n expressionName,\n sheetName,\n workbookName,\n }: {\n expression: string;\n expressionName: string;\n sheetName?: string;\n workbookName?: string;\n }) {\n this.namedExpressionManager.addNamedExpression({\n expression,\n expressionName,\n sheetName,\n workbookName,\n });\n\n // Re-evaluate all sheets since named expressions can be referenced from anywhere\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n removeNamedExpression({\n expressionName,\n sheetName,\n workbookName,\n }: {\n expressionName: string;\n sheetName?: string;\n workbookName?: string;\n }) {\n const found = this.namedExpressionManager.removeNamedExpression({\n expressionName,\n sheetName,\n workbookName,\n });\n\n if (found) {\n // Re-evaluate all sheets since named expressions can be referenced from anywhere\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n return found;\n }\n\n updateNamedExpression({\n expression,\n expressionName,\n sheetName,\n workbookName,\n }: {\n expression: string;\n expressionName: string;\n sheetName?: string;\n workbookName?: string;\n }) {\n this.namedExpressionManager.updateNamedExpression({\n expression,\n expressionName,\n sheetName,\n workbookName,\n });\n\n // Re-evaluate all sheets since named expressions can be referenced from anywhere\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n renameNamedExpression({\n expressionName,\n sheetName,\n workbookName,\n newName,\n }: {\n expressionName: string;\n sheetName?: string;\n workbookName?: string;\n newName: string;\n }) {\n const result = this.namedExpressionManager.renameNamedExpression({\n expressionName,\n sheetName,\n workbookName,\n newName,\n });\n\n // Update all formulas that reference this named expression in sheet cells\n this.workbookManager.updateAllFormulas((formula) =>\n renameNamedExpressionInFormula(formula, expressionName, newName)\n );\n\n // Update named expressions that reference this named expression\n this.namedExpressionManager.updateAllNamedExpressions((formula) =>\n renameNamedExpressionInFormula(formula, expressionName, newName)\n );\n\n // Re-evaluate all sheets since named expressions can be referenced from anywhere\n this.reevaluate();\n this.eventManager.emitUpdate();\n\n return result;\n }\n\n setNamedExpressions(\n opts: (\n | {\n type: \"global\";\n }\n | {\n type: \"sheet\";\n sheetName: string;\n workbookName: string;\n }\n | {\n type: \"workbook\";\n workbookName: string;\n }\n ) & {\n expressions: Map<string, NamedExpression>;\n }\n ) {\n this.namedExpressionManager.setNamedExpressions(opts);\n\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n //#endregion\n\n //#region Tables\n addTable(props: {\n tableName: string;\n sheetName: string;\n workbookName: string;\n start: string;\n numRows: SpreadsheetRangeEnd;\n numCols: number;\n }) {\n const table = this.tableManager.addTable({\n ...props,\n getCellValue: (cellAddress: CellAddress) =>\n this.getCellValue(cellAddress),\n });\n\n // Re-evaluate all sheets since structured references might depend on this table\n this.reevaluate();\n this.eventManager.emitUpdate();\n\n return table;\n }\n\n renameTable(\n workbookName: string,\n names: { oldName: string; newName: string }\n ) {\n this.tableManager.renameTable(workbookName, names);\n\n // Update all formulas that reference this table in sheet cells\n this.workbookManager.updateAllFormulas((formula) =>\n renameTableInFormula(formula, names.oldName, names.newName)\n );\n\n // Update named expressions that reference this table\n this.namedExpressionManager.updateAllNamedExpressions((formula) =>\n renameTableInFormula(formula, names.oldName, names.newName)\n );\n\n // Re-evaluate all sheets since structured references might depend on this table\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n updateTable(opts: {\n tableName: string;\n sheetName?: string;\n start?: string;\n numRows?: SpreadsheetRangeEnd;\n numCols?: number;\n workbookName: string;\n }) {\n this.tableManager.updateTable({\n ...opts,\n getCellValue: (cellAddress: CellAddress) =>\n this.getCellValue(cellAddress),\n });\n\n // Re-evaluate all sheets since structured references might depend on this table\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n removeTable(opts: { tableName: string; workbookName: string }) {\n const found = this.tableManager.removeTable(opts);\n\n if (found) {\n // Re-evaluate all sheets since structured references might depend on this table\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n return found;\n }\n\n resetTables(tables: Map<string, Map<string, TableDefinition>>) {\n this.tableManager.resetTables(tables);\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n getTables(workbookName: string) {\n return this.tableManager.getTables(workbookName);\n }\n\n isCellInTable(cellAddress: CellAddress): TableDefinition | undefined {\n return this.tableManager.isCellInTable(cellAddress);\n }\n\n //#endregion\n\n //#region Conditional Styling\n /**\n * Add a conditional style rule\n */\n addConditionalStyle(style: ConditionalStyle): void {\n this.styleManager.addConditionalStyle(style);\n this.eventManager.emitUpdate();\n }\n\n /**\n * Remove a conditional style rule by index\n */\n removeConditionalStyle(workbookName: string, index: number): boolean {\n const removed = this.styleManager.removeConditionalStyle(workbookName, index);\n if (removed) {\n this.eventManager.emitUpdate();\n }\n return removed;\n }\n\n /**\n * Get all conditional styles for a workbook\n */\n getConditionalStyles(workbookName: string): ConditionalStyle[] {\n return this.styleManager.getConditionalStyles(workbookName);\n }\n\n /**\n * Get the computed style for a specific cell\n */\n getCellStyle(cellAddress: CellAddress): CellStyle | undefined {\n return this.styleManager.getCellStyle(cellAddress);\n }\n\n /**\n * Add a direct cell style rule\n */\n addCellStyle(style: DirectCellStyle): void {\n this.styleManager.addCellStyle(style);\n this.eventManager.emitUpdate();\n }\n\n /**\n * Remove a direct cell style rule by index\n */\n removeCellStyle(workbookName: string, index: number): boolean {\n const removed = this.styleManager.removeCellStyle(workbookName, index);\n if (removed) {\n this.eventManager.emitUpdate();\n }\n return removed;\n }\n\n /**\n * Get all direct cell styles for a workbook\n */\n getCellStyles(workbookName: string): DirectCellStyle[] {\n return this.styleManager.getCellStyles(workbookName);\n }\n\n /**\n * Clear all cell styles and conditional styles for a given range\n * Adjusts existing style ranges rather than deleting them entirely\n */\n clearCellStyles(range: RangeAddress): void {\n this.styleManager.clearCellStyles(range);\n this.eventManager.emitUpdate();\n }\n\n //#endregion\n\n //#region Copy/Paste\n /**\n * Copy cells from source to target\n */\n copyCells(\n source: CellAddress[],\n target: CellAddress,\n options: CopyCellsOptions\n ): void {\n this.copyManager.copyCells(source, target, options);\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n //#endregion\n\n //#region Sheets\n addSheet(opts: { workbookName: string; sheetName: string }) {\n const newSheet = this.workbookManager.addSheet(opts);\n const wbLevel = this.namedExpressionManager.addSheet(opts);\n this.reevaluate();\n this.eventManager.emitUpdate();\n return newSheet;\n }\n\n removeSheet(opts: { workbookName: string; sheetName: string }) {\n const sheet = this.workbookManager.removeSheet(opts);\n\n // Clean up related data\n this.namedExpressionManager.removeSheet(opts);\n this.tableManager.removeSheet(opts);\n this.styleManager.removeSheetStyles(opts.workbookName, opts.sheetName);\n\n // Add engine-specific logic: re-evaluate since references might be affected\n this.reevaluate();\n this.eventManager.emitUpdate();\n\n return sheet;\n }\n\n renameSheet(opts: {\n sheetName: string;\n newSheetName: string;\n workbookName: string;\n }) {\n const sheet = this.workbookManager.renameSheet(opts);\n\n // Update scoped named expressions\n this.namedExpressionManager.renameSheet(opts);\n\n // Update tables that belong to the renamed sheet\n this.tableManager.updateTablesForSheetRename(opts);\n\n // Update conditional styles that reference this sheet\n this.styleManager.updateSheetName(\n opts.workbookName,\n opts.sheetName,\n opts.newSheetName\n );\n\n // Update all formulas that reference this sheet\n this.workbookManager.updateAllFormulas((formula) =>\n renameSheetInFormula({\n formula,\n oldSheetName: opts.sheetName,\n newSheetName: opts.newSheetName,\n })\n );\n\n // Add engine-specific logic: re-evaluate since references might be affected\n this.reevaluate();\n this.eventManager.emitUpdate();\n\n return sheet;\n }\n\n getSheets(workbookName: string) {\n return this.workbookManager.getSheets(workbookName);\n }\n\n getSheet({\n workbookName,\n sheetName,\n }: {\n workbookName: string;\n sheetName: string;\n }) {\n return this.workbookManager.getSheet({ workbookName, sheetName });\n }\n\n getSheetSerialized(opts: {\n sheetName: string;\n workbookName: string;\n }): Map<string, SerializedCellValue> {\n return this.workbookManager.getSheetSerialized(opts);\n }\n\n //#endregion\n\n //#region Workbook\n addWorkbook(workbookName: string) {\n this.workbookManager.addWorkbook(workbookName);\n this.namedExpressionManager.addWorkbook(workbookName);\n this.tableManager.addWorkbook(workbookName);\n\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n removeWorkbook(workbookName: string) {\n this.workbookManager.removeWorkbook(workbookName);\n this.namedExpressionManager.removeWorkbook(workbookName);\n this.tableManager.removeWorkbook(workbookName);\n this.styleManager.removeWorkbookStyles(workbookName);\n\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n cloneWorkbook(fromWorkbookName: string, toWorkbookName: string) {\n // Check if source workbook exists\n const sourceWorkbook = this.workbookManager\n .getWorkbooks()\n .get(fromWorkbookName);\n if (!sourceWorkbook) {\n throw new Error(`Source workbook \"${fromWorkbookName}\" not found`);\n }\n\n // Check if target workbook name already exists\n if (this.workbookManager.getWorkbooks().has(toWorkbookName)) {\n throw new Error(`Target workbook \"${toWorkbookName}\" already exists`);\n }\n\n // Create new workbook\n this.addWorkbook(toWorkbookName);\n\n // Clone all sheets from source workbook\n for (const [sheetName, sheet] of sourceWorkbook.sheets) {\n // Add sheet to target workbook\n this.addSheet({\n workbookName: toWorkbookName,\n sheetName: sheetName,\n });\n\n // Copy all cell content using setSheetContent for efficiency\n this.setSheetContent(\n {\n workbookName: toWorkbookName,\n sheetName: sheetName,\n },\n new Map(sheet.content)\n );\n }\n\n // Clone workbook-scoped named expressions\n const sourceWorkbookExpressions = this.namedExpressionManager\n .getNamedExpressions()\n .workbookExpressions.get(fromWorkbookName);\n if (sourceWorkbookExpressions) {\n for (const [name, expression] of sourceWorkbookExpressions) {\n this.addNamedExpression({\n expressionName: name,\n expression: expression.expression,\n workbookName: toWorkbookName,\n });\n }\n }\n\n // Clone sheet-scoped named expressions\n const sourceSheetExpressions = this.namedExpressionManager\n .getNamedExpressions()\n .sheetExpressions.get(fromWorkbookName);\n if (sourceSheetExpressions) {\n for (const [sheetName, sheetExpressions] of sourceSheetExpressions) {\n for (const [name, expression] of sheetExpressions) {\n this.addNamedExpression({\n expressionName: name,\n expression: expression.expression,\n workbookName: toWorkbookName,\n sheetName: sheetName,\n });\n }\n }\n }\n\n // Clone tables\n const sourceTables = this.tableManager.tables.get(fromWorkbookName);\n if (sourceTables) {\n for (const [tableName, table] of sourceTables) {\n this.tableManager.copyTable(\n {\n workbookName: fromWorkbookName,\n tableName: tableName,\n },\n {\n workbookName: toWorkbookName,\n tableName: tableName,\n }\n );\n }\n }\n\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n renameWorkbook(opts: { workbookName: string; newWorkbookName: string }) {\n this.workbookManager.renameWorkbook(opts);\n\n // Update scoped named expressions\n this.namedExpressionManager.renameWorkbook(opts);\n\n // Update tables that belong to the renamed sheet\n this.tableManager.updateTablesForWorkbookRename(opts);\n\n // Update conditional styles that reference this workbook\n this.styleManager.updateWorkbookName(\n opts.workbookName,\n opts.newWorkbookName\n );\n\n // Update all formulas that reference this workbook\n this.workbookManager.updateAllFormulas((formula) =>\n renameWorkbookInFormula({\n formula,\n oldWorkbookName: opts.workbookName,\n newWorkbookName: opts.newWorkbookName,\n })\n );\n\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n getWorkbooks() {\n return this.workbookManager.getWorkbooks();\n }\n //#endregion\n\n //#region CRUD Operations\n /**\n * Overrides the content of a sheet.\n * @param sheetName - The name of the sheet to set the content of\n * @param content - A map of cell addresses to their serialized values\n * @remarks This method is used to set the content of a sheet. It will re-evaluate all sheets to ensure all dependencies are resolved correctly.\n */\n setSheetContent(\n opts: { sheetName: string; workbookName: string },\n content: Map<string, SerializedCellValue>\n ) {\n this.workbookManager.setSheetContent(opts, content);\n\n // Re-evaluate all sheets to ensure all dependencies are resolved correctly\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n setCellContent(address: CellAddress, content: SerializedCellValue) {\n this.workbookManager.setCellContent(address, content);\n\n // Re-evaluate all sheets to ensure all dependencies are resolved correctly\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n //#endregion\n\n //#region Evaluation\n\n /**\n * Re-evaluates all sheets to ensure all dependencies are resolved correctly\n *\n * but just clears the evaluation cache\n */\n reevaluate() {\n this.evaluationManager.clearEvaluationCache();\n }\n //#endregion\n\n //#region Auto-fill\n /**\n * Auto-fills the fillRange based on the seedRange and the direction.\n */\n autoFill(\n opts: { sheetName: string; workbookName: string },\n /**\n * The user's original selection that defines the pattern/series.\n */\n seedRange: SpreadsheetRange,\n /**\n * the new cells populated by the drag, excluding the seed\n */\n fillRange: SpreadsheetRange,\n /**\n * The direction of the fill.\n */\n direction: FillDirection\n ) {\n this.autoFillManager.fill(opts, seedRange, fillRange, direction);\n }\n\n /**\n * Removes the content in the spreadsheet that is inside the range.\n */\n clearSpreadsheetRange(address: RangeAddress) {\n this.workbookManager.clearSpreadsheetRange(address);\n\n // Re-evaluate all sheets to ensure all dependencies are resolved correctly\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n //#endregion\n\n //#region State - UI library integration\n getState() {\n return {\n workbooks: this.workbookManager.getWorkbooks(),\n namedExpressions: this.namedExpressionManager.getNamedExpressions(),\n tables: this.tableManager.tables,\n conditionalStyles: this.styleManager.getAllConditionalStyles(),\n cellStyles: this.styleManager.getAllCellStyles(),\n };\n }\n\n onUpdate(listener: () => void) {\n return this.eventManager.onUpdate(listener);\n }\n\n serializeEngine(): string {\n return serialize(this.getState());\n }\n\n resetToSerializedEngine(data: string) {\n const deserialized = deserialize(data) as ReturnType<typeof this.getState>;\n\n this.workbookManager.resetWorkbooks(deserialized.workbooks);\n\n deserialized.workbooks.forEach((workbook) => {\n this.namedExpressionManager.addWorkbook(workbook.name);\n this.tableManager.addWorkbook(workbook.name);\n workbook.sheets.forEach((sheet) => {\n this.namedExpressionManager.addSheet({\n workbookName: workbook.name,\n sheetName: sheet.name,\n });\n });\n });\n\n this.namedExpressionManager.resetNamedExpressions(\n deserialized.namedExpressions\n );\n this.tableManager.resetTables(deserialized.tables);\n \n // Reset styles if present\n // Handle backward compatibility: if conditionalStyles is a Map, convert it\n let conditionalStylesArray: ConditionalStyle[] | undefined;\n let cellStylesArray: DirectCellStyle[] | undefined;\n \n if (deserialized.conditionalStyles) {\n if (deserialized.conditionalStyles instanceof Map) {\n // Old format: Map<string, ConditionalStyle[]>\n conditionalStylesArray = Array.from(deserialized.conditionalStyles.values()).flat();\n } else if (Array.isArray(deserialized.conditionalStyles)) {\n // New format: ConditionalStyle[]\n conditionalStylesArray = deserialized.conditionalStyles;\n }\n }\n \n if (deserialized.cellStyles) {\n if (Array.isArray(deserialized.cellStyles)) {\n cellStylesArray = deserialized.cellStyles;\n }\n }\n \n this.styleManager.resetStyles(conditionalStylesArray, cellStylesArray);\n\n // Re-evaluate all sheets to ensure all dependencies are resolved correctly\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n //#endregion\n}\n"
|
|
5
|
+
"/**\n * Main FormulaEngine class\n * Core API implementation for spreadsheet calculations\n */\n\nimport {\n type CellAddress,\n type CellStyle,\n type ConditionalStyle,\n type CopyCellsOptions,\n type DirectCellStyle,\n type NamedExpression,\n type RangeAddress,\n type SerializedCellValue,\n type SingleEvaluationResult,\n type SpreadsheetRange,\n type SpreadsheetRangeEnd,\n type TableDefinition,\n} from \"./types.mjs\";\n\nimport type { FillDirection } from \"@ricsam/selection-manager\";\nimport { FormulaEvaluator } from \"../evaluator/formula-evaluator.mjs\";\nimport { AutoFill } from \"./autofill-utils.mjs\";\nimport { WorkbookManager } from \"./managers/workbook-manager.mjs\";\nimport { deserialize, serialize } from \"./map-serializer.mjs\";\nimport { renameNamedExpressionInFormula } from \"./named-expression-renamer.mjs\";\nimport { renameSheetInFormula } from \"./sheet-renamer.mjs\";\nimport { renameTableInFormula } from \"./table-renamer.mjs\";\nimport { renameWorkbookInFormula } from \"./workbook-renamer.mjs\";\nimport { cellAddressToKey, keyToCellAddress } from \"./utils.mjs\";\nimport { CacheManager } from \"./managers/cache-manager.mjs\";\nimport { NamedExpressionManager } from \"./managers/named-expression-manager.mjs\";\nimport { TableManager } from \"./managers/table-manager.mjs\";\nimport { EventManager } from \"./managers/event-manager.mjs\";\nimport { EvaluationManager } from \"./managers/evaluation-manager.mjs\";\nimport { DependencyManager } from \"./managers/dependency-manager.mjs\";\nimport { StyleManager } from \"./managers/style-manager.mjs\";\nimport { CopyManager } from \"./managers/copy-manager.mjs\";\n\n/**\n * Main FormulaEngine class\n */\nexport class FormulaEngine {\n private workbookManager: WorkbookManager;\n private namedExpressionManager: NamedExpressionManager;\n private tableManager: TableManager;\n private eventManager: EventManager;\n private evaluationManager: EvaluationManager;\n private autoFillManager: AutoFill;\n private dependencyManager: DependencyManager;\n private styleManager: StyleManager;\n private copyManager: CopyManager;\n\n /**\n * Public access to the store manager for testing\n */\n public _workbookManager: WorkbookManager;\n public _namedExpressionManager: NamedExpressionManager;\n public _tableManager: TableManager;\n public _eventManager: EventManager;\n public _evaluationManager: EvaluationManager;\n public _autoFillManager: AutoFill;\n public _dependencyManager: DependencyManager;\n public _styleManager: StyleManager;\n\n constructor() {\n this.eventManager = new EventManager();\n this.workbookManager = new WorkbookManager();\n this.namedExpressionManager = new NamedExpressionManager();\n this.tableManager = new TableManager(this.workbookManager);\n const cacheManager = new CacheManager();\n this.dependencyManager = new DependencyManager(\n cacheManager,\n this.workbookManager\n );\n\n const formulaEvaluator = new FormulaEvaluator(\n this.tableManager,\n this.dependencyManager,\n this.namedExpressionManager,\n );\n\n this.evaluationManager = new EvaluationManager(\n this.workbookManager,\n this.tableManager,\n formulaEvaluator,\n this.dependencyManager\n );\n\n this.styleManager = new StyleManager(\n this.evaluationManager\n );\n this.copyManager = new CopyManager(\n this.workbookManager,\n this.evaluationManager,\n this.styleManager\n );\n\n this.autoFillManager = new AutoFill(this.workbookManager, this);\n\n this._workbookManager = this.workbookManager;\n this._namedExpressionManager = this.namedExpressionManager;\n this._tableManager = this.tableManager;\n this._eventManager = this.eventManager;\n this._evaluationManager = this.evaluationManager;\n this._autoFillManager = this.autoFillManager;\n this._dependencyManager = this.dependencyManager;\n this._styleManager = this.styleManager;\n }\n\n /**\n * Static factory method to build an empty engine\n */\n static buildEmpty(): FormulaEngine {\n return new FormulaEngine();\n }\n\n //#region Cell\n getCellEvaluationResult(\n cellAddress: CellAddress\n ): SingleEvaluationResult | undefined {\n return this.evaluationManager.getCellEvaluationResult(cellAddress);\n }\n\n getCellValue(cellAddress: CellAddress, debug?: boolean): SerializedCellValue {\n const result = this.getCellEvaluationResult(cellAddress);\n if (!result) {\n return \"\";\n }\n\n return this.evaluationManager.evaluationResultToSerializedValue(\n result,\n cellAddress,\n debug\n );\n }\n\n evaluateFormula(\n /**\n * formula without the leading = sign\n */\n formula: string, cellAddress: CellAddress): SerializedCellValue {\n return this.evaluationManager.evaluateFormula(formula, cellAddress);\n }\n\n getCellDependents(\n address: CellAddress | SpreadsheetRange\n ): (SpreadsheetRange | CellAddress)[] {\n throw new Error(\"Not implemented\");\n }\n\n getCellPrecedents(\n address: CellAddress | SpreadsheetRange\n ): (SpreadsheetRange | CellAddress)[] {\n throw new Error(\"Not implemented\");\n }\n\n //#endregion\n\n //#region Named Expressions\n addNamedExpression({\n expression,\n expressionName,\n sheetName,\n workbookName,\n }: {\n expression: string;\n expressionName: string;\n sheetName?: string;\n workbookName?: string;\n }) {\n this.namedExpressionManager.addNamedExpression({\n expression,\n expressionName,\n sheetName,\n workbookName,\n });\n\n // Re-evaluate all sheets since named expressions can be referenced from anywhere\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n removeNamedExpression({\n expressionName,\n sheetName,\n workbookName,\n }: {\n expressionName: string;\n sheetName?: string;\n workbookName?: string;\n }) {\n const found = this.namedExpressionManager.removeNamedExpression({\n expressionName,\n sheetName,\n workbookName,\n });\n\n if (found) {\n // Re-evaluate all sheets since named expressions can be referenced from anywhere\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n return found;\n }\n\n updateNamedExpression({\n expression,\n expressionName,\n sheetName,\n workbookName,\n }: {\n expression: string;\n expressionName: string;\n sheetName?: string;\n workbookName?: string;\n }) {\n this.namedExpressionManager.updateNamedExpression({\n expression,\n expressionName,\n sheetName,\n workbookName,\n });\n\n // Re-evaluate all sheets since named expressions can be referenced from anywhere\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n renameNamedExpression({\n expressionName,\n sheetName,\n workbookName,\n newName,\n }: {\n expressionName: string;\n sheetName?: string;\n workbookName?: string;\n newName: string;\n }) {\n const result = this.namedExpressionManager.renameNamedExpression({\n expressionName,\n sheetName,\n workbookName,\n newName,\n });\n\n // Update all formulas that reference this named expression in sheet cells\n this.workbookManager.updateAllFormulas((formula) =>\n renameNamedExpressionInFormula(formula, expressionName, newName)\n );\n\n // Update named expressions that reference this named expression\n this.namedExpressionManager.updateAllNamedExpressions((formula) =>\n renameNamedExpressionInFormula(formula, expressionName, newName)\n );\n\n // Re-evaluate all sheets since named expressions can be referenced from anywhere\n this.reevaluate();\n this.eventManager.emitUpdate();\n\n return result;\n }\n\n setNamedExpressions(\n opts: (\n | {\n type: \"global\";\n }\n | {\n type: \"sheet\";\n sheetName: string;\n workbookName: string;\n }\n | {\n type: \"workbook\";\n workbookName: string;\n }\n ) & {\n expressions: Map<string, NamedExpression>;\n }\n ) {\n this.namedExpressionManager.setNamedExpressions(opts);\n\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n //#endregion\n\n //#region Tables\n addTable(props: {\n tableName: string;\n sheetName: string;\n workbookName: string;\n start: string;\n numRows: SpreadsheetRangeEnd;\n numCols: number;\n }) {\n const table = this.tableManager.addTable({\n ...props,\n getCellValue: (cellAddress: CellAddress) =>\n this.getCellValue(cellAddress),\n });\n\n // Re-evaluate all sheets since structured references might depend on this table\n this.reevaluate();\n this.eventManager.emitUpdate();\n\n return table;\n }\n\n renameTable(\n workbookName: string,\n names: { oldName: string; newName: string }\n ) {\n this.tableManager.renameTable(workbookName, names);\n\n // Update all formulas that reference this table in sheet cells\n this.workbookManager.updateAllFormulas((formula) =>\n renameTableInFormula(formula, names.oldName, names.newName)\n );\n\n // Update named expressions that reference this table\n this.namedExpressionManager.updateAllNamedExpressions((formula) =>\n renameTableInFormula(formula, names.oldName, names.newName)\n );\n\n // Re-evaluate all sheets since structured references might depend on this table\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n updateTable(opts: {\n tableName: string;\n sheetName?: string;\n start?: string;\n numRows?: SpreadsheetRangeEnd;\n numCols?: number;\n workbookName: string;\n }) {\n this.tableManager.updateTable({\n ...opts,\n getCellValue: (cellAddress: CellAddress) =>\n this.getCellValue(cellAddress),\n });\n\n // Re-evaluate all sheets since structured references might depend on this table\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n removeTable(opts: { tableName: string; workbookName: string }) {\n const found = this.tableManager.removeTable(opts);\n\n if (found) {\n // Re-evaluate all sheets since structured references might depend on this table\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n return found;\n }\n\n resetTables(tables: Map<string, Map<string, TableDefinition>>) {\n this.tableManager.resetTables(tables);\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n getTables(workbookName: string) {\n return this.tableManager.getTables(workbookName);\n }\n\n isCellInTable(cellAddress: CellAddress): TableDefinition | undefined {\n return this.tableManager.isCellInTable(cellAddress);\n }\n\n //#endregion\n\n //#region Conditional Styling\n /**\n * Add a conditional style rule\n */\n addConditionalStyle(style: ConditionalStyle): void {\n this.styleManager.addConditionalStyle(style);\n this.eventManager.emitUpdate();\n }\n\n /**\n * Remove a conditional style rule by index\n */\n removeConditionalStyle(workbookName: string, index: number): boolean {\n const removed = this.styleManager.removeConditionalStyle(workbookName, index);\n if (removed) {\n this.eventManager.emitUpdate();\n }\n return removed;\n }\n\n /**\n * Get all conditional styles for a range\n */\n getConditionalStyles(range: RangeAddress): ConditionalStyle[] {\n return this.styleManager.getConditionalStyles(range);\n }\n\n /**\n * Get the computed style for a specific cell\n */\n getCellStyle(cellAddress: CellAddress): CellStyle | undefined {\n return this.styleManager.getCellStyle(cellAddress);\n }\n\n /**\n * Add a direct cell style rule\n */\n addCellStyle(style: DirectCellStyle): void {\n this.styleManager.addCellStyle(style);\n this.eventManager.emitUpdate();\n }\n\n /**\n * Remove a direct cell style rule by index\n */\n removeCellStyle(workbookName: string, index: number): boolean {\n const removed = this.styleManager.removeCellStyle(workbookName, index);\n if (removed) {\n this.eventManager.emitUpdate();\n }\n return removed;\n }\n\n /**\n * Get all direct cell styles for a range\n */\n getCellStyles(range: RangeAddress): DirectCellStyle[] {\n return this.styleManager.getCellStyles(range);\n }\n\n /**\n * Clear all cell styles and conditional styles for a given range\n * Adjusts existing style ranges rather than deleting them entirely\n */\n clearCellStyles(range: RangeAddress): void {\n this.styleManager.clearCellStyles(range);\n this.eventManager.emitUpdate();\n }\n\n //#endregion\n\n //#region Copy/Paste\n /**\n * Copy cells from source to target\n */\n copyCells(\n source: CellAddress[],\n target: CellAddress,\n options: CopyCellsOptions\n ): void {\n this.copyManager.copyCells(source, target, options);\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n //#endregion\n\n //#region Sheets\n addSheet(opts: { workbookName: string; sheetName: string }) {\n const newSheet = this.workbookManager.addSheet(opts);\n const wbLevel = this.namedExpressionManager.addSheet(opts);\n this.reevaluate();\n this.eventManager.emitUpdate();\n return newSheet;\n }\n\n removeSheet(opts: { workbookName: string; sheetName: string }) {\n const sheet = this.workbookManager.removeSheet(opts);\n\n // Clean up related data\n this.namedExpressionManager.removeSheet(opts);\n this.tableManager.removeSheet(opts);\n this.styleManager.removeSheetStyles(opts.workbookName, opts.sheetName);\n\n // Add engine-specific logic: re-evaluate since references might be affected\n this.reevaluate();\n this.eventManager.emitUpdate();\n\n return sheet;\n }\n\n renameSheet(opts: {\n sheetName: string;\n newSheetName: string;\n workbookName: string;\n }) {\n const sheet = this.workbookManager.renameSheet(opts);\n\n // Update scoped named expressions\n this.namedExpressionManager.renameSheet(opts);\n\n // Update tables that belong to the renamed sheet\n this.tableManager.updateTablesForSheetRename(opts);\n\n // Update conditional styles that reference this sheet\n this.styleManager.updateSheetName(\n opts.workbookName,\n opts.sheetName,\n opts.newSheetName\n );\n\n // Update all formulas that reference this sheet\n this.workbookManager.updateAllFormulas((formula) =>\n renameSheetInFormula({\n formula,\n oldSheetName: opts.sheetName,\n newSheetName: opts.newSheetName,\n })\n );\n\n // Add engine-specific logic: re-evaluate since references might be affected\n this.reevaluate();\n this.eventManager.emitUpdate();\n\n return sheet;\n }\n\n getSheets(workbookName: string) {\n return this.workbookManager.getSheets(workbookName);\n }\n\n getSheet({\n workbookName,\n sheetName,\n }: {\n workbookName: string;\n sheetName: string;\n }) {\n return this.workbookManager.getSheet({ workbookName, sheetName });\n }\n\n getSheetSerialized(opts: {\n sheetName: string;\n workbookName: string;\n }): Map<string, SerializedCellValue> {\n return this.workbookManager.getSheetSerialized(opts);\n }\n\n //#endregion\n\n //#region Workbook\n addWorkbook(workbookName: string) {\n this.workbookManager.addWorkbook(workbookName);\n this.namedExpressionManager.addWorkbook(workbookName);\n this.tableManager.addWorkbook(workbookName);\n\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n removeWorkbook(workbookName: string) {\n this.workbookManager.removeWorkbook(workbookName);\n this.namedExpressionManager.removeWorkbook(workbookName);\n this.tableManager.removeWorkbook(workbookName);\n this.styleManager.removeWorkbookStyles(workbookName);\n\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n cloneWorkbook(fromWorkbookName: string, toWorkbookName: string) {\n // Check if source workbook exists\n const sourceWorkbook = this.workbookManager\n .getWorkbooks()\n .get(fromWorkbookName);\n if (!sourceWorkbook) {\n throw new Error(`Source workbook \"${fromWorkbookName}\" not found`);\n }\n\n // Check if target workbook name already exists\n if (this.workbookManager.getWorkbooks().has(toWorkbookName)) {\n throw new Error(`Target workbook \"${toWorkbookName}\" already exists`);\n }\n\n // Create new workbook\n this.addWorkbook(toWorkbookName);\n\n // Clone all sheets from source workbook\n for (const [sheetName, sheet] of sourceWorkbook.sheets) {\n // Add sheet to target workbook\n this.addSheet({\n workbookName: toWorkbookName,\n sheetName: sheetName,\n });\n\n // Copy all cell content using setSheetContent for efficiency\n this.setSheetContent(\n {\n workbookName: toWorkbookName,\n sheetName: sheetName,\n },\n new Map(sheet.content)\n );\n }\n\n // Clone workbook-scoped named expressions\n const sourceWorkbookExpressions = this.namedExpressionManager\n .getNamedExpressions()\n .workbookExpressions.get(fromWorkbookName);\n if (sourceWorkbookExpressions) {\n for (const [name, expression] of sourceWorkbookExpressions) {\n this.addNamedExpression({\n expressionName: name,\n expression: expression.expression,\n workbookName: toWorkbookName,\n });\n }\n }\n\n // Clone sheet-scoped named expressions\n const sourceSheetExpressions = this.namedExpressionManager\n .getNamedExpressions()\n .sheetExpressions.get(fromWorkbookName);\n if (sourceSheetExpressions) {\n for (const [sheetName, sheetExpressions] of sourceSheetExpressions) {\n for (const [name, expression] of sheetExpressions) {\n this.addNamedExpression({\n expressionName: name,\n expression: expression.expression,\n workbookName: toWorkbookName,\n sheetName: sheetName,\n });\n }\n }\n }\n\n // Clone tables\n const sourceTables = this.tableManager.tables.get(fromWorkbookName);\n if (sourceTables) {\n for (const [tableName, table] of sourceTables) {\n this.tableManager.copyTable(\n {\n workbookName: fromWorkbookName,\n tableName: tableName,\n },\n {\n workbookName: toWorkbookName,\n tableName: tableName,\n }\n );\n }\n }\n\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n renameWorkbook(opts: { workbookName: string; newWorkbookName: string }) {\n this.workbookManager.renameWorkbook(opts);\n\n // Update scoped named expressions\n this.namedExpressionManager.renameWorkbook(opts);\n\n // Update tables that belong to the renamed sheet\n this.tableManager.updateTablesForWorkbookRename(opts);\n\n // Update conditional styles that reference this workbook\n this.styleManager.updateWorkbookName(\n opts.workbookName,\n opts.newWorkbookName\n );\n\n // Update all formulas that reference this workbook\n this.workbookManager.updateAllFormulas((formula) =>\n renameWorkbookInFormula({\n formula,\n oldWorkbookName: opts.workbookName,\n newWorkbookName: opts.newWorkbookName,\n })\n );\n\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n getWorkbooks() {\n return this.workbookManager.getWorkbooks();\n }\n //#endregion\n\n //#region CRUD Operations\n /**\n * Overrides the content of a sheet.\n * @param sheetName - The name of the sheet to set the content of\n * @param content - A map of cell addresses to their serialized values\n * @remarks This method is used to set the content of a sheet. It will re-evaluate all sheets to ensure all dependencies are resolved correctly.\n */\n setSheetContent(\n opts: { sheetName: string; workbookName: string },\n content: Map<string, SerializedCellValue>\n ) {\n this.workbookManager.setSheetContent(opts, content);\n\n // Re-evaluate all sheets to ensure all dependencies are resolved correctly\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n\n setCellContent(address: CellAddress, content: SerializedCellValue) {\n this.workbookManager.setCellContent(address, content);\n\n // Re-evaluate all sheets to ensure all dependencies are resolved correctly\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n //#endregion\n\n //#region Evaluation\n\n /**\n * Re-evaluates all sheets to ensure all dependencies are resolved correctly\n *\n * but just clears the evaluation cache\n */\n reevaluate() {\n this.evaluationManager.clearEvaluationCache();\n }\n //#endregion\n\n //#region Auto-fill\n /**\n * Auto-fills the fillRange based on the seedRange and the direction.\n */\n autoFill(\n opts: { sheetName: string; workbookName: string },\n /**\n * The user's original selection that defines the pattern/series.\n */\n seedRange: SpreadsheetRange,\n /**\n * the new cells populated by the drag, excluding the seed\n */\n fillRange: SpreadsheetRange,\n /**\n * The direction of the fill.\n */\n direction: FillDirection\n ) {\n this.autoFillManager.fill(opts, seedRange, fillRange, direction);\n }\n\n /**\n * Removes the content in the spreadsheet that is inside the range.\n */\n clearSpreadsheetRange(address: RangeAddress) {\n this.workbookManager.clearSpreadsheetRange(address);\n\n // Re-evaluate all sheets to ensure all dependencies are resolved correctly\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n //#endregion\n\n //#region State - UI library integration\n getState() {\n return {\n workbooks: this.workbookManager.getWorkbooks(),\n namedExpressions: this.namedExpressionManager.getNamedExpressions(),\n tables: this.tableManager.tables,\n conditionalStyles: this.styleManager.getAllConditionalStyles(),\n cellStyles: this.styleManager.getAllCellStyles(),\n };\n }\n\n onUpdate(listener: () => void) {\n return this.eventManager.onUpdate(listener);\n }\n\n serializeEngine(): string {\n return serialize(this.getState());\n }\n\n resetToSerializedEngine(data: string) {\n const deserialized = deserialize(data) as ReturnType<typeof this.getState>;\n\n this.workbookManager.resetWorkbooks(deserialized.workbooks);\n\n deserialized.workbooks.forEach((workbook) => {\n this.namedExpressionManager.addWorkbook(workbook.name);\n this.tableManager.addWorkbook(workbook.name);\n workbook.sheets.forEach((sheet) => {\n this.namedExpressionManager.addSheet({\n workbookName: workbook.name,\n sheetName: sheet.name,\n });\n });\n });\n\n this.namedExpressionManager.resetNamedExpressions(\n deserialized.namedExpressions\n );\n this.tableManager.resetTables(deserialized.tables);\n \n // Reset styles if present\n // Handle backward compatibility: if conditionalStyles is a Map, convert it\n let conditionalStylesArray: ConditionalStyle[] | undefined;\n let cellStylesArray: DirectCellStyle[] | undefined;\n \n if (deserialized.conditionalStyles) {\n if (deserialized.conditionalStyles instanceof Map) {\n // Old format: Map<string, ConditionalStyle[]>\n conditionalStylesArray = Array.from(deserialized.conditionalStyles.values()).flat();\n } else if (Array.isArray(deserialized.conditionalStyles)) {\n // New format: ConditionalStyle[]\n conditionalStylesArray = deserialized.conditionalStyles;\n }\n }\n \n if (deserialized.cellStyles) {\n if (Array.isArray(deserialized.cellStyles)) {\n cellStylesArray = deserialized.cellStyles;\n }\n }\n \n this.styleManager.resetStyles(conditionalStylesArray, cellStylesArray);\n\n // Re-evaluate all sheets to ensure all dependencies are resolved correctly\n this.reevaluate();\n this.eventManager.emitUpdate();\n }\n //#endregion\n}\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";AAqBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAKO,MAAM,cAAc;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAKD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEP,WAAW,GAAG;AAAA,IACZ,KAAK,eAAe,IAAI;AAAA,IACxB,KAAK,kBAAkB,IAAI;AAAA,IAC3B,KAAK,yBAAyB,IAAI;AAAA,IAClC,KAAK,eAAe,IAAI,aAAa,KAAK,eAAe;AAAA,IACzD,MAAM,eAAe,IAAI;AAAA,IACzB,KAAK,oBAAoB,IAAI,kBAC3B,cACA,KAAK,eACP;AAAA,IAEA,MAAM,mBAAmB,IAAI,iBAC3B,KAAK,cACL,KAAK,mBACL,KAAK,sBACP;AAAA,IAEA,KAAK,oBAAoB,IAAI,kBAC3B,KAAK,iBACL,KAAK,cACL,kBACA,KAAK,iBACP;AAAA,IAEA,KAAK,eAAe,IAAI,aACtB,KAAK,
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "5C2BDBA1C9A73AE864756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -8,12 +8,10 @@ import {
|
|
|
8
8
|
import { subtractRange, rangesIntersect } from "../utils/range-utils.mjs";
|
|
9
9
|
|
|
10
10
|
class StyleManager {
|
|
11
|
-
workbookManager;
|
|
12
11
|
evaluationManager;
|
|
13
12
|
conditionalStyles = [];
|
|
14
13
|
cellStyles = [];
|
|
15
|
-
constructor(
|
|
16
|
-
this.workbookManager = workbookManager;
|
|
14
|
+
constructor(evaluationManager) {
|
|
17
15
|
this.evaluationManager = evaluationManager;
|
|
18
16
|
}
|
|
19
17
|
addConditionalStyle(style) {
|
|
@@ -37,8 +35,8 @@ class StyleManager {
|
|
|
37
35
|
}
|
|
38
36
|
return false;
|
|
39
37
|
}
|
|
40
|
-
getConditionalStyles(
|
|
41
|
-
return this.conditionalStyles.filter((style) => style && style.area && style.area.
|
|
38
|
+
getConditionalStyles(range) {
|
|
39
|
+
return this.conditionalStyles.filter((style) => style.area.workbookName === range.workbookName && style.area.sheetName === range.sheetName && rangesIntersect(style.area.range, range.range));
|
|
42
40
|
}
|
|
43
41
|
addCellStyle(style) {
|
|
44
42
|
this.cellStyles.push(style);
|
|
@@ -61,8 +59,8 @@ class StyleManager {
|
|
|
61
59
|
}
|
|
62
60
|
return false;
|
|
63
61
|
}
|
|
64
|
-
getCellStyles(
|
|
65
|
-
return this.cellStyles.filter((style) => style && style.area && style.area.workbookName === workbookName);
|
|
62
|
+
getCellStyles(range) {
|
|
63
|
+
return this.cellStyles.filter((style) => style && style.area.sheetName === range.sheetName && style.area.workbookName === range.workbookName && rangesIntersect(style.area.range, range.range));
|
|
66
64
|
}
|
|
67
65
|
getAllConditionalStyles() {
|
|
68
66
|
return [...this.conditionalStyles];
|
|
@@ -358,4 +356,4 @@ export {
|
|
|
358
356
|
StyleManager
|
|
359
357
|
};
|
|
360
358
|
|
|
361
|
-
//# debugId=
|
|
359
|
+
//# debugId=C7567859FAB695F264756E2164756E21
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/core/managers/style-manager.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"/**\n * StyleManager - Manages conditional styling for cells\n */\n\nimport type {\n CellAddress,\n CellStyle,\n ConditionalStyle,\n DirectCellStyle,\n RangeAddress,\n SerializedCellValue,\n} from \"../types.mjs\";\nimport type { WorkbookManager } from \"./workbook-manager.mjs\";\nimport type { EvaluationManager } from \"./evaluation-manager.mjs\";\nimport { isCellInRange } from \"../utils.mjs\";\nimport {\n calculateGradientFactor,\n interpolateLCH,\n lchToHex,\n} from \"../utils/color-utils.mjs\";\nimport { subtractRange, rangesIntersect } from \"../utils/range-utils.mjs\";\n\nexport class StyleManager {\n private conditionalStyles: ConditionalStyle[] = [];\n private cellStyles: DirectCellStyle[] = [];\n\n constructor(\n private workbookManager: WorkbookManager,\n private evaluationManager: EvaluationManager\n ) {}\n\n /**\n * Add a conditional style rule\n */\n addConditionalStyle(style: ConditionalStyle): void {\n this.conditionalStyles.push(style);\n }\n\n /**\n * Remove a conditional style rule by index for a specific workbook\n */\n removeConditionalStyle(workbookName: string, index: number): boolean {\n const workbookStyles = this.conditionalStyles.filter(\n (style) => style.area.workbookName === workbookName\n );\n if (index < 0 || index >= workbookStyles.length) {\n return false;\n }\n // Find the actual index in the full array\n let currentIndex = 0;\n for (let i = 0; i < this.conditionalStyles.length; i++) {\n const style = this.conditionalStyles[i];\n if (style && style.area.workbookName === workbookName) {\n if (currentIndex === index) {\n this.conditionalStyles.splice(i, 1);\n return true;\n }\n currentIndex++;\n }\n }\n return false;\n }\n\n /**\n * Get all conditional styles for a workbook\n */\n getConditionalStyles(workbookName: string): ConditionalStyle[] {\n return this.conditionalStyles.filter(\n (style) => style && style.area && style.area.workbookName === workbookName\n );\n }\n\n /**\n * Add a direct cell style rule\n */\n addCellStyle(style: DirectCellStyle): void {\n this.cellStyles.push(style);\n }\n\n /**\n * Remove a direct cell style rule by index for a specific workbook\n */\n removeCellStyle(workbookName: string, index: number): boolean {\n const workbookStyles = this.cellStyles.filter(\n (style) => style && style.area && style.area.workbookName === workbookName\n );\n if (index < 0 || index >= workbookStyles.length) {\n return false;\n }\n // Find the actual index in the full array\n let currentIndex = 0;\n for (let i = 0; i < this.cellStyles.length; i++) {\n const style = this.cellStyles[i];\n if (style && style.area && style.area.workbookName === workbookName) {\n if (currentIndex === index) {\n this.cellStyles.splice(i, 1);\n return true;\n }\n currentIndex++;\n }\n }\n return false;\n }\n\n /**\n * Get all direct cell styles for a workbook\n */\n getCellStyles(workbookName: string): DirectCellStyle[] {\n return this.cellStyles.filter(\n (style) => style && style.area && style.area.workbookName === workbookName\n );\n }\n\n /**\n * Get all conditional styles across all workbooks (for serialization)\n */\n getAllConditionalStyles(): ConditionalStyle[] {\n return [...this.conditionalStyles];\n }\n\n /**\n * Get all cell styles (for serialization)\n */\n getAllCellStyles(): DirectCellStyle[] {\n return [...this.cellStyles];\n }\n\n /**\n * Reset all styles (for deserialization)\n */\n resetStyles(\n conditionalStyles?: ConditionalStyle[],\n cellStyles?: DirectCellStyle[]\n ): void {\n this.conditionalStyles = conditionalStyles ? [...conditionalStyles] : [];\n this.cellStyles = cellStyles ? [...cellStyles] : [];\n }\n\n /**\n * Remove all styles for a workbook\n */\n removeWorkbookStyles(workbookName: string): void {\n this.conditionalStyles = this.conditionalStyles.filter(\n (style) => style.area.workbookName !== workbookName\n );\n this.cellStyles = this.cellStyles.filter(\n (style) => style.area.workbookName !== workbookName\n );\n }\n\n /**\n * Update workbook name in all style references\n */\n updateWorkbookName(oldName: string, newName: string): void {\n // Update conditional styles\n this.conditionalStyles = this.conditionalStyles.map((style) => {\n if (style.area.workbookName === oldName) {\n return {\n ...style,\n area: {\n ...style.area,\n workbookName: newName,\n },\n };\n }\n return style;\n });\n // Update cell styles\n this.cellStyles = this.cellStyles.map((style) => {\n if (style.area.workbookName === oldName) {\n return {\n ...style,\n area: {\n ...style.area,\n workbookName: newName,\n },\n };\n }\n return style;\n });\n }\n\n /**\n * Update sheet name in style references\n */\n updateSheetName(\n workbookName: string,\n oldSheetName: string,\n newSheetName: string\n ): void {\n // Update conditional styles\n this.conditionalStyles = this.conditionalStyles.map((style) => {\n if (\n style.area.workbookName === workbookName &&\n style.area.sheetName === oldSheetName\n ) {\n return {\n ...style,\n area: {\n ...style.area,\n sheetName: newSheetName,\n },\n };\n }\n return style;\n });\n // Update cell styles\n this.cellStyles = this.cellStyles.map((style) => {\n if (\n style.area.workbookName === workbookName &&\n style.area.sheetName === oldSheetName\n ) {\n return {\n ...style,\n area: {\n ...style.area,\n sheetName: newSheetName,\n },\n };\n }\n return style;\n });\n }\n\n /**\n * Remove styles that reference a deleted sheet\n */\n removeSheetStyles(workbookName: string, sheetName: string): void {\n this.conditionalStyles = this.conditionalStyles.filter(\n (style) =>\n !(\n style.area.workbookName === workbookName &&\n style.area.sheetName === sheetName\n )\n );\n this.cellStyles = this.cellStyles.filter(\n (style) =>\n !(\n style.area.workbookName === workbookName &&\n style.area.sheetName === sheetName\n )\n );\n }\n\n /**\n * Get the style for a specific cell\n * Returns the first matching style (first match wins)\n * Checks cellStyles first, then conditionalStyles\n */\n getCellStyle(cellAddress: CellAddress): CellStyle | undefined {\n // First check direct cell styles\n for (const cellStyle of this.cellStyles) {\n if (!cellStyle || !cellStyle.area) {\n continue;\n }\n if (\n cellStyle.area.workbookName === cellAddress.workbookName &&\n cellStyle.area.sheetName === cellAddress.sheetName &&\n isCellInRange(cellAddress, cellStyle.area.range)\n ) {\n return cellStyle.style;\n }\n }\n\n // Then check conditional styles\n for (const style of this.conditionalStyles) {\n if (!style || !style.area) {\n continue;\n }\n // Check if cell is in the style's area\n if (\n style.area.sheetName !== cellAddress.sheetName ||\n style.area.workbookName !== cellAddress.workbookName\n ) {\n continue;\n }\n\n if (!isCellInRange(cellAddress, style.area.range)) {\n continue;\n }\n\n // Cell is in area, evaluate condition\n if (style.condition.type === \"formula\") {\n const result = this.evaluateFormulaCondition(cellAddress, style);\n if (result) return result;\n } else {\n const result = this.evaluateGradientCondition(cellAddress, style);\n if (result) return result;\n }\n }\n\n return undefined;\n }\n\n /**\n * Evaluate a formula-based style condition\n */\n private evaluateFormulaCondition(\n cellAddress: CellAddress,\n style: ConditionalStyle\n ): CellStyle | undefined {\n if (style.condition.type !== \"formula\") {\n return undefined;\n }\n\n try {\n // Evaluate formula in context of the cell\n // evaluateFormula expects a full cell value (with = prefix for formulas)\n const formula = style.condition.formula.startsWith(\"=\")\n ? style.condition.formula\n : `=${style.condition.formula}`;\n\n const result = this.evaluationManager.evaluateFormula(\n formula,\n cellAddress\n );\n\n // Check if result is truthy\n const isTruthy =\n result === true ||\n result === \"TRUE\" ||\n (typeof result === \"number\" && result !== 0);\n\n if (isTruthy) {\n return {\n backgroundColor: lchToHex(style.condition.color),\n };\n }\n } catch (error) {\n // If formula evaluation fails, don't apply style\n console.warn(\"Failed to evaluate formula condition:\", error);\n }\n\n return undefined;\n }\n\n /**\n * Evaluate a gradient-based style condition\n */\n private evaluateGradientCondition(\n cellAddress: CellAddress,\n style: ConditionalStyle\n ): CellStyle | undefined {\n if (style.condition.type !== \"gradient\") {\n return undefined;\n }\n\n try {\n // Get the cell's evaluation result\n const evalResult =\n this.evaluationManager.getCellEvaluationResult(cellAddress);\n if (!evalResult || evalResult.type !== \"value\") {\n return undefined;\n }\n if (evalResult.result.type !== \"number\") {\n return undefined;\n }\n const cellValue = evalResult.result.value;\n\n // Calculate min and max values for the gradient\n const { min: minValue, max: maxValue } = this.calculateGradientBounds(\n style,\n cellAddress\n );\n\n if (minValue === null || maxValue === null) {\n return undefined;\n }\n\n // Calculate interpolation factor\n const factor = calculateGradientFactor(cellValue, minValue, maxValue);\n\n // Interpolate between min and max colors\n const minColor = style.condition.min.color;\n const maxColor = style.condition.max.color;\n const interpolatedColor = interpolateLCH(minColor, maxColor, factor);\n\n return {\n backgroundColor: lchToHex(interpolatedColor),\n };\n } catch (error) {\n console.warn(\"Failed to evaluate gradient condition:\", error);\n return undefined;\n }\n }\n\n /**\n * Calculate min and max bounds for a gradient\n */\n private calculateGradientBounds(\n style: ConditionalStyle,\n cellAddress: CellAddress\n ): { min: number | null; max: number | null } {\n if (style.condition.type !== \"gradient\") {\n return { min: null, max: null };\n }\n\n const { min: minConfig, max: maxConfig } = style.condition;\n const topLeftCell: CellAddress = {\n workbookName: style.area.workbookName,\n sheetName: style.area.sheetName,\n colIndex: style.area.range.start.col,\n rowIndex: style.area.range.start.row,\n };\n\n // Calculate min value\n let minValue: number | null = null;\n if (minConfig.type === \"lowest_value\") {\n // Evaluate MIN(range) formula directly\n try {\n const rangeRef = this.getRangeReference(style.area);\n const result = this.evaluationManager.evaluateFormula(\n `=MIN(${rangeRef})`,\n topLeftCell\n );\n if (typeof result === \"number\") {\n minValue = result;\n }\n } catch (error) {\n console.warn(\"Failed to calculate MIN:\", error);\n }\n } else {\n // Evaluate valueFormula in context of area's top-left cell\n const formula = minConfig.valueFormula.startsWith(\"=\")\n ? minConfig.valueFormula\n : `=${minConfig.valueFormula}`;\n const result = this.evaluationManager.evaluateFormula(\n formula,\n topLeftCell\n );\n if (typeof result === \"number\") {\n minValue = result;\n }\n }\n\n // Calculate max value\n let maxValue: number | null = null;\n if (maxConfig.type === \"highest_value\") {\n // Evaluate MAX(range) formula directly\n try {\n const rangeRef = this.getRangeReference(style.area);\n const result = this.evaluationManager.evaluateFormula(\n `=MAX(${rangeRef})`,\n topLeftCell\n );\n if (typeof result === \"number\") {\n maxValue = result;\n }\n } catch (error) {\n console.warn(\"Failed to calculate MAX:\", error);\n }\n } else {\n // Evaluate valueFormula in context of area's top-left cell\n const formula = maxConfig.valueFormula.startsWith(\"=\")\n ? maxConfig.valueFormula\n : `=${maxConfig.valueFormula}`;\n const result = this.evaluationManager.evaluateFormula(\n formula,\n topLeftCell\n );\n if (typeof result === \"number\") {\n maxValue = result;\n }\n }\n\n return { min: minValue, max: maxValue };\n }\n\n /**\n * Get a range reference string from a RangeAddress\n * Follows CANONICAL_RANGES.md format:\n * - Closed: A5:D10\n * - Row-bounded (col-open): A5:10\n * - Col-bounded (row-open): A5:D\n * - Open both: A5:INFINITY\n */\n private getRangeReference(area: RangeAddress): string {\n const colToLetter = (col: number): string => {\n let result = \"\";\n let c = col;\n while (c >= 0) {\n result = String.fromCharCode(65 + (c % 26)) + result;\n c = Math.floor(c / 26) - 1;\n }\n return result;\n };\n\n const startCol = colToLetter(area.range.start.col);\n const startRow = area.range.start.row + 1; // Convert to 1-based\n\n const isColInfinity = area.range.end.col.type === \"infinity\";\n const isRowInfinity = area.range.end.row.type === \"infinity\";\n\n let rangeStr: string;\n\n if (isColInfinity && isRowInfinity) {\n // Open both: A5:INFINITY\n rangeStr = `${startCol}${startRow}:INFINITY`;\n } else if (isColInfinity) {\n // Row-bounded (col-open): A5:10\n if (area.range.end.row.type === \"number\") {\n const endRow = area.range.end.row.value + 1; // Convert to 1-based\n rangeStr = `${startCol}${startRow}:${endRow}`;\n } else {\n rangeStr = `${startCol}${startRow}:INFINITY`;\n }\n } else if (isRowInfinity) {\n // Col-bounded (row-open): A5:D\n if (area.range.end.col.type === \"number\") {\n const endCol = colToLetter(area.range.end.col.value);\n rangeStr = `${startCol}${startRow}:${endCol}`;\n } else {\n rangeStr = `${startCol}${startRow}:INFINITY`;\n }\n } else {\n // Closed rectangle: A5:D10\n if (\n area.range.end.col.type === \"number\" &&\n area.range.end.row.type === \"number\"\n ) {\n const endCol = colToLetter(area.range.end.col.value);\n const endRow = area.range.end.row.value + 1; // Convert to 1-based\n rangeStr = `${startCol}${startRow}:${endCol}${endRow}`;\n } else {\n // Fallback to INFINITY if types don't match\n rangeStr = `${startCol}${startRow}:INFINITY`;\n }\n }\n\n // Quote sheet name if it contains spaces or special characters\n const needsQuotes = /[ '!]/.test(area.sheetName);\n const sheetRef = needsQuotes\n ? `'${area.sheetName.replace(/'/g, \"''\")}'`\n : area.sheetName;\n\n // Construct the full reference: [workbook]'sheet'!range\n return `[${area.workbookName}]${sheetRef}!${rangeStr}`;\n }\n\n /**\n * Clear cell styles and conditional styles for a given range\n * Adjusts existing style ranges rather than deleting them entirely\n */\n clearCellStyles(range: RangeAddress): void {\n // Process cellStyles\n const newCellStyles: DirectCellStyle[] = [];\n for (const cellStyle of this.cellStyles) {\n if (!cellStyle || !cellStyle.area) {\n newCellStyles.push(cellStyle);\n continue;\n }\n\n // Check if this style intersects with the clear range\n if (\n cellStyle.area.workbookName === range.workbookName &&\n cellStyle.area.sheetName === range.sheetName &&\n rangesIntersect(cellStyle.area.range, range.range)\n ) {\n // Subtract the clear range from this style's range\n const remainingRanges = subtractRange(cellStyle.area.range, range.range);\n \n // Add new styles for each remaining range\n for (const remainingRange of remainingRanges) {\n newCellStyles.push({\n area: {\n workbookName: cellStyle.area.workbookName,\n sheetName: cellStyle.area.sheetName,\n range: remainingRange,\n },\n style: cellStyle.style,\n });\n }\n } else {\n // No intersection, keep the style as-is\n newCellStyles.push(cellStyle);\n }\n }\n this.cellStyles = newCellStyles;\n\n // Process conditionalStyles\n const newConditionalStyles: ConditionalStyle[] = [];\n for (const conditionalStyle of this.conditionalStyles) {\n if (!conditionalStyle || !conditionalStyle.area) {\n newConditionalStyles.push(conditionalStyle);\n continue;\n }\n\n // Check if this style intersects with the clear range\n if (\n conditionalStyle.area.workbookName === range.workbookName &&\n conditionalStyle.area.sheetName === range.sheetName &&\n rangesIntersect(conditionalStyle.area.range, range.range)\n ) {\n // Subtract the clear range from this style's range\n const remainingRanges = subtractRange(conditionalStyle.area.range, range.range);\n \n // Add new styles for each remaining range\n for (const remainingRange of remainingRanges) {\n newConditionalStyles.push({\n area: {\n workbookName: conditionalStyle.area.workbookName,\n sheetName: conditionalStyle.area.sheetName,\n range: remainingRange,\n },\n condition: conditionalStyle.condition,\n });\n }\n } else {\n // No intersection, keep the style as-is\n newConditionalStyles.push(conditionalStyle);\n }\n }\n this.conditionalStyles = newConditionalStyles;\n }\n}\n"
|
|
5
|
+
"/**\n * StyleManager - Manages conditional styling for cells\n */\n\nimport type {\n CellAddress,\n CellStyle,\n ConditionalStyle,\n DirectCellStyle,\n RangeAddress,\n SerializedCellValue,\n} from \"../types.mjs\";\nimport type { WorkbookManager } from \"./workbook-manager.mjs\";\nimport type { EvaluationManager } from \"./evaluation-manager.mjs\";\nimport { isCellInRange } from \"../utils.mjs\";\nimport {\n calculateGradientFactor,\n interpolateLCH,\n lchToHex,\n} from \"../utils/color-utils.mjs\";\nimport { subtractRange, rangesIntersect } from \"../utils/range-utils.mjs\";\n\nexport class StyleManager {\n private conditionalStyles: ConditionalStyle[] = [];\n private cellStyles: DirectCellStyle[] = [];\n\n constructor(private evaluationManager: EvaluationManager) {}\n\n /**\n * Add a conditional style rule\n */\n addConditionalStyle(style: ConditionalStyle): void {\n this.conditionalStyles.push(style);\n }\n\n /**\n * Remove a conditional style rule by index for a specific workbook\n */\n removeConditionalStyle(workbookName: string, index: number): boolean {\n const workbookStyles = this.conditionalStyles.filter(\n (style) => style.area.workbookName === workbookName\n );\n if (index < 0 || index >= workbookStyles.length) {\n return false;\n }\n // Find the actual index in the full array\n let currentIndex = 0;\n for (let i = 0; i < this.conditionalStyles.length; i++) {\n const style = this.conditionalStyles[i];\n if (style && style.area.workbookName === workbookName) {\n if (currentIndex === index) {\n this.conditionalStyles.splice(i, 1);\n return true;\n }\n currentIndex++;\n }\n }\n return false;\n }\n\n /**\n * Get all conditional styles for a range\n */\n getConditionalStyles(range: RangeAddress): ConditionalStyle[] {\n return this.conditionalStyles.filter(\n (style) =>\n style.area.workbookName === range.workbookName &&\n style.area.sheetName === range.sheetName &&\n rangesIntersect(style.area.range, range.range)\n );\n }\n\n /**\n * Add a direct cell style rule\n */\n addCellStyle(style: DirectCellStyle): void {\n this.cellStyles.push(style);\n }\n\n /**\n * Remove a direct cell style rule by index for a specific workbook\n */\n removeCellStyle(workbookName: string, index: number): boolean {\n const workbookStyles = this.cellStyles.filter(\n (style) => style && style.area && style.area.workbookName === workbookName\n );\n if (index < 0 || index >= workbookStyles.length) {\n return false;\n }\n // Find the actual index in the full array\n let currentIndex = 0;\n for (let i = 0; i < this.cellStyles.length; i++) {\n const style = this.cellStyles[i];\n if (style && style.area && style.area.workbookName === workbookName) {\n if (currentIndex === index) {\n this.cellStyles.splice(i, 1);\n return true;\n }\n currentIndex++;\n }\n }\n return false;\n }\n\n /**\n * Get all direct cell styles for a workbook\n */\n getCellStyles(range: RangeAddress): DirectCellStyle[] {\n return this.cellStyles.filter(\n (style) =>\n style &&\n style.area.sheetName === range.sheetName &&\n style.area.workbookName === range.workbookName &&\n rangesIntersect(style.area.range, range.range)\n );\n }\n\n /**\n * Get all conditional styles across all workbooks (for serialization)\n */\n getAllConditionalStyles(): ConditionalStyle[] {\n return [...this.conditionalStyles];\n }\n\n /**\n * Get all cell styles (for serialization)\n */\n getAllCellStyles(): DirectCellStyle[] {\n return [...this.cellStyles];\n }\n\n /**\n * Reset all styles (for deserialization)\n */\n resetStyles(\n conditionalStyles?: ConditionalStyle[],\n cellStyles?: DirectCellStyle[]\n ): void {\n this.conditionalStyles = conditionalStyles ? [...conditionalStyles] : [];\n this.cellStyles = cellStyles ? [...cellStyles] : [];\n }\n\n /**\n * Remove all styles for a workbook\n */\n removeWorkbookStyles(workbookName: string): void {\n this.conditionalStyles = this.conditionalStyles.filter(\n (style) => style.area.workbookName !== workbookName\n );\n this.cellStyles = this.cellStyles.filter(\n (style) => style.area.workbookName !== workbookName\n );\n }\n\n /**\n * Update workbook name in all style references\n */\n updateWorkbookName(oldName: string, newName: string): void {\n // Update conditional styles\n this.conditionalStyles = this.conditionalStyles.map((style) => {\n if (style.area.workbookName === oldName) {\n return {\n ...style,\n area: {\n ...style.area,\n workbookName: newName,\n },\n };\n }\n return style;\n });\n // Update cell styles\n this.cellStyles = this.cellStyles.map((style) => {\n if (style.area.workbookName === oldName) {\n return {\n ...style,\n area: {\n ...style.area,\n workbookName: newName,\n },\n };\n }\n return style;\n });\n }\n\n /**\n * Update sheet name in style references\n */\n updateSheetName(\n workbookName: string,\n oldSheetName: string,\n newSheetName: string\n ): void {\n // Update conditional styles\n this.conditionalStyles = this.conditionalStyles.map((style) => {\n if (\n style.area.workbookName === workbookName &&\n style.area.sheetName === oldSheetName\n ) {\n return {\n ...style,\n area: {\n ...style.area,\n sheetName: newSheetName,\n },\n };\n }\n return style;\n });\n // Update cell styles\n this.cellStyles = this.cellStyles.map((style) => {\n if (\n style.area.workbookName === workbookName &&\n style.area.sheetName === oldSheetName\n ) {\n return {\n ...style,\n area: {\n ...style.area,\n sheetName: newSheetName,\n },\n };\n }\n return style;\n });\n }\n\n /**\n * Remove styles that reference a deleted sheet\n */\n removeSheetStyles(workbookName: string, sheetName: string): void {\n this.conditionalStyles = this.conditionalStyles.filter(\n (style) =>\n !(\n style.area.workbookName === workbookName &&\n style.area.sheetName === sheetName\n )\n );\n this.cellStyles = this.cellStyles.filter(\n (style) =>\n !(\n style.area.workbookName === workbookName &&\n style.area.sheetName === sheetName\n )\n );\n }\n\n /**\n * Get the style for a specific cell\n * Returns the first matching style (first match wins)\n * Checks cellStyles first, then conditionalStyles\n */\n getCellStyle(cellAddress: CellAddress): CellStyle | undefined {\n // First check direct cell styles\n for (const cellStyle of this.cellStyles) {\n if (!cellStyle || !cellStyle.area) {\n continue;\n }\n if (\n cellStyle.area.workbookName === cellAddress.workbookName &&\n cellStyle.area.sheetName === cellAddress.sheetName &&\n isCellInRange(cellAddress, cellStyle.area.range)\n ) {\n return cellStyle.style;\n }\n }\n\n // Then check conditional styles\n for (const style of this.conditionalStyles) {\n if (!style || !style.area) {\n continue;\n }\n // Check if cell is in the style's area\n if (\n style.area.sheetName !== cellAddress.sheetName ||\n style.area.workbookName !== cellAddress.workbookName\n ) {\n continue;\n }\n\n if (!isCellInRange(cellAddress, style.area.range)) {\n continue;\n }\n\n // Cell is in area, evaluate condition\n if (style.condition.type === \"formula\") {\n const result = this.evaluateFormulaCondition(cellAddress, style);\n if (result) return result;\n } else {\n const result = this.evaluateGradientCondition(cellAddress, style);\n if (result) return result;\n }\n }\n\n return undefined;\n }\n\n /**\n * Evaluate a formula-based style condition\n */\n private evaluateFormulaCondition(\n cellAddress: CellAddress,\n style: ConditionalStyle\n ): CellStyle | undefined {\n if (style.condition.type !== \"formula\") {\n return undefined;\n }\n\n try {\n // Evaluate formula in context of the cell\n // evaluateFormula expects a full cell value (with = prefix for formulas)\n const formula = style.condition.formula.startsWith(\"=\")\n ? style.condition.formula\n : `=${style.condition.formula}`;\n\n const result = this.evaluationManager.evaluateFormula(\n formula,\n cellAddress\n );\n\n // Check if result is truthy\n const isTruthy =\n result === true ||\n result === \"TRUE\" ||\n (typeof result === \"number\" && result !== 0);\n\n if (isTruthy) {\n return {\n backgroundColor: lchToHex(style.condition.color),\n };\n }\n } catch (error) {\n // If formula evaluation fails, don't apply style\n console.warn(\"Failed to evaluate formula condition:\", error);\n }\n\n return undefined;\n }\n\n /**\n * Evaluate a gradient-based style condition\n */\n private evaluateGradientCondition(\n cellAddress: CellAddress,\n style: ConditionalStyle\n ): CellStyle | undefined {\n if (style.condition.type !== \"gradient\") {\n return undefined;\n }\n\n try {\n // Get the cell's evaluation result\n const evalResult =\n this.evaluationManager.getCellEvaluationResult(cellAddress);\n if (!evalResult || evalResult.type !== \"value\") {\n return undefined;\n }\n if (evalResult.result.type !== \"number\") {\n return undefined;\n }\n const cellValue = evalResult.result.value;\n\n // Calculate min and max values for the gradient\n const { min: minValue, max: maxValue } = this.calculateGradientBounds(\n style,\n cellAddress\n );\n\n if (minValue === null || maxValue === null) {\n return undefined;\n }\n\n // Calculate interpolation factor\n const factor = calculateGradientFactor(cellValue, minValue, maxValue);\n\n // Interpolate between min and max colors\n const minColor = style.condition.min.color;\n const maxColor = style.condition.max.color;\n const interpolatedColor = interpolateLCH(minColor, maxColor, factor);\n\n return {\n backgroundColor: lchToHex(interpolatedColor),\n };\n } catch (error) {\n console.warn(\"Failed to evaluate gradient condition:\", error);\n return undefined;\n }\n }\n\n /**\n * Calculate min and max bounds for a gradient\n */\n private calculateGradientBounds(\n style: ConditionalStyle,\n cellAddress: CellAddress\n ): { min: number | null; max: number | null } {\n if (style.condition.type !== \"gradient\") {\n return { min: null, max: null };\n }\n\n const { min: minConfig, max: maxConfig } = style.condition;\n const topLeftCell: CellAddress = {\n workbookName: style.area.workbookName,\n sheetName: style.area.sheetName,\n colIndex: style.area.range.start.col,\n rowIndex: style.area.range.start.row,\n };\n\n // Calculate min value\n let minValue: number | null = null;\n if (minConfig.type === \"lowest_value\") {\n // Evaluate MIN(range) formula directly\n try {\n const rangeRef = this.getRangeReference(style.area);\n const result = this.evaluationManager.evaluateFormula(\n `=MIN(${rangeRef})`,\n topLeftCell\n );\n if (typeof result === \"number\") {\n minValue = result;\n }\n } catch (error) {\n console.warn(\"Failed to calculate MIN:\", error);\n }\n } else {\n // Evaluate valueFormula in context of area's top-left cell\n const formula = minConfig.valueFormula.startsWith(\"=\")\n ? minConfig.valueFormula\n : `=${minConfig.valueFormula}`;\n const result = this.evaluationManager.evaluateFormula(\n formula,\n topLeftCell\n );\n if (typeof result === \"number\") {\n minValue = result;\n }\n }\n\n // Calculate max value\n let maxValue: number | null = null;\n if (maxConfig.type === \"highest_value\") {\n // Evaluate MAX(range) formula directly\n try {\n const rangeRef = this.getRangeReference(style.area);\n const result = this.evaluationManager.evaluateFormula(\n `=MAX(${rangeRef})`,\n topLeftCell\n );\n if (typeof result === \"number\") {\n maxValue = result;\n }\n } catch (error) {\n console.warn(\"Failed to calculate MAX:\", error);\n }\n } else {\n // Evaluate valueFormula in context of area's top-left cell\n const formula = maxConfig.valueFormula.startsWith(\"=\")\n ? maxConfig.valueFormula\n : `=${maxConfig.valueFormula}`;\n const result = this.evaluationManager.evaluateFormula(\n formula,\n topLeftCell\n );\n if (typeof result === \"number\") {\n maxValue = result;\n }\n }\n\n return { min: minValue, max: maxValue };\n }\n\n /**\n * Get a range reference string from a RangeAddress\n * Follows CANONICAL_RANGES.md format:\n * - Closed: A5:D10\n * - Row-bounded (col-open): A5:10\n * - Col-bounded (row-open): A5:D\n * - Open both: A5:INFINITY\n */\n private getRangeReference(area: RangeAddress): string {\n const colToLetter = (col: number): string => {\n let result = \"\";\n let c = col;\n while (c >= 0) {\n result = String.fromCharCode(65 + (c % 26)) + result;\n c = Math.floor(c / 26) - 1;\n }\n return result;\n };\n\n const startCol = colToLetter(area.range.start.col);\n const startRow = area.range.start.row + 1; // Convert to 1-based\n\n const isColInfinity = area.range.end.col.type === \"infinity\";\n const isRowInfinity = area.range.end.row.type === \"infinity\";\n\n let rangeStr: string;\n\n if (isColInfinity && isRowInfinity) {\n // Open both: A5:INFINITY\n rangeStr = `${startCol}${startRow}:INFINITY`;\n } else if (isColInfinity) {\n // Row-bounded (col-open): A5:10\n if (area.range.end.row.type === \"number\") {\n const endRow = area.range.end.row.value + 1; // Convert to 1-based\n rangeStr = `${startCol}${startRow}:${endRow}`;\n } else {\n rangeStr = `${startCol}${startRow}:INFINITY`;\n }\n } else if (isRowInfinity) {\n // Col-bounded (row-open): A5:D\n if (area.range.end.col.type === \"number\") {\n const endCol = colToLetter(area.range.end.col.value);\n rangeStr = `${startCol}${startRow}:${endCol}`;\n } else {\n rangeStr = `${startCol}${startRow}:INFINITY`;\n }\n } else {\n // Closed rectangle: A5:D10\n if (\n area.range.end.col.type === \"number\" &&\n area.range.end.row.type === \"number\"\n ) {\n const endCol = colToLetter(area.range.end.col.value);\n const endRow = area.range.end.row.value + 1; // Convert to 1-based\n rangeStr = `${startCol}${startRow}:${endCol}${endRow}`;\n } else {\n // Fallback to INFINITY if types don't match\n rangeStr = `${startCol}${startRow}:INFINITY`;\n }\n }\n\n // Quote sheet name if it contains spaces or special characters\n const needsQuotes = /[ '!]/.test(area.sheetName);\n const sheetRef = needsQuotes\n ? `'${area.sheetName.replace(/'/g, \"''\")}'`\n : area.sheetName;\n\n // Construct the full reference: [workbook]'sheet'!range\n return `[${area.workbookName}]${sheetRef}!${rangeStr}`;\n }\n\n /**\n * Clear cell styles and conditional styles for a given range\n * Adjusts existing style ranges rather than deleting them entirely\n */\n clearCellStyles(range: RangeAddress): void {\n // Process cellStyles\n const newCellStyles: DirectCellStyle[] = [];\n for (const cellStyle of this.cellStyles) {\n if (!cellStyle || !cellStyle.area) {\n newCellStyles.push(cellStyle);\n continue;\n }\n\n // Check if this style intersects with the clear range\n if (\n cellStyle.area.workbookName === range.workbookName &&\n cellStyle.area.sheetName === range.sheetName &&\n rangesIntersect(cellStyle.area.range, range.range)\n ) {\n // Subtract the clear range from this style's range\n const remainingRanges = subtractRange(\n cellStyle.area.range,\n range.range\n );\n\n // Add new styles for each remaining range\n for (const remainingRange of remainingRanges) {\n newCellStyles.push({\n area: {\n workbookName: cellStyle.area.workbookName,\n sheetName: cellStyle.area.sheetName,\n range: remainingRange,\n },\n style: cellStyle.style,\n });\n }\n } else {\n // No intersection, keep the style as-is\n newCellStyles.push(cellStyle);\n }\n }\n this.cellStyles = newCellStyles;\n\n // Process conditionalStyles\n const newConditionalStyles: ConditionalStyle[] = [];\n for (const conditionalStyle of this.conditionalStyles) {\n if (!conditionalStyle || !conditionalStyle.area) {\n newConditionalStyles.push(conditionalStyle);\n continue;\n }\n\n // Check if this style intersects with the clear range\n if (\n conditionalStyle.area.workbookName === range.workbookName &&\n conditionalStyle.area.sheetName === range.sheetName &&\n rangesIntersect(conditionalStyle.area.range, range.range)\n ) {\n // Subtract the clear range from this style's range\n const remainingRanges = subtractRange(\n conditionalStyle.area.range,\n range.range\n );\n\n // Add new styles for each remaining range\n for (const remainingRange of remainingRanges) {\n newConditionalStyles.push({\n area: {\n workbookName: conditionalStyle.area.workbookName,\n sheetName: conditionalStyle.area.sheetName,\n range: remainingRange,\n },\n condition: conditionalStyle.condition,\n });\n }\n } else {\n // No intersection, keep the style as-is\n newConditionalStyles.push(conditionalStyle);\n }\n }\n this.conditionalStyles = newConditionalStyles;\n }\n}\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";AAcA;AACA;AAAA;AAAA;AAAA;AAAA;AAKA;AAAA;AAEO,MAAM,aAAa;AAAA,
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "C7567859FAB695F264756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
package/dist/mjs/package.json
CHANGED
|
@@ -121,9 +121,9 @@ export declare class FormulaEngine {
|
|
|
121
121
|
*/
|
|
122
122
|
removeConditionalStyle(workbookName: string, index: number): boolean;
|
|
123
123
|
/**
|
|
124
|
-
* Get all conditional styles for a
|
|
124
|
+
* Get all conditional styles for a range
|
|
125
125
|
*/
|
|
126
|
-
getConditionalStyles(
|
|
126
|
+
getConditionalStyles(range: RangeAddress): ConditionalStyle[];
|
|
127
127
|
/**
|
|
128
128
|
* Get the computed style for a specific cell
|
|
129
129
|
*/
|
|
@@ -137,9 +137,9 @@ export declare class FormulaEngine {
|
|
|
137
137
|
*/
|
|
138
138
|
removeCellStyle(workbookName: string, index: number): boolean;
|
|
139
139
|
/**
|
|
140
|
-
* Get all direct cell styles for a
|
|
140
|
+
* Get all direct cell styles for a range
|
|
141
141
|
*/
|
|
142
|
-
getCellStyles(
|
|
142
|
+
getCellStyles(range: RangeAddress): DirectCellStyle[];
|
|
143
143
|
/**
|
|
144
144
|
* Clear all cell styles and conditional styles for a given range
|
|
145
145
|
* Adjusts existing style ranges rather than deleting them entirely
|
|
@@ -2,14 +2,12 @@
|
|
|
2
2
|
* StyleManager - Manages conditional styling for cells
|
|
3
3
|
*/
|
|
4
4
|
import type { CellAddress, CellStyle, ConditionalStyle, DirectCellStyle, RangeAddress } from "../types";
|
|
5
|
-
import type { WorkbookManager } from "./workbook-manager";
|
|
6
5
|
import type { EvaluationManager } from "./evaluation-manager";
|
|
7
6
|
export declare class StyleManager {
|
|
8
|
-
private workbookManager;
|
|
9
7
|
private evaluationManager;
|
|
10
8
|
private conditionalStyles;
|
|
11
9
|
private cellStyles;
|
|
12
|
-
constructor(
|
|
10
|
+
constructor(evaluationManager: EvaluationManager);
|
|
13
11
|
/**
|
|
14
12
|
* Add a conditional style rule
|
|
15
13
|
*/
|
|
@@ -19,9 +17,9 @@ export declare class StyleManager {
|
|
|
19
17
|
*/
|
|
20
18
|
removeConditionalStyle(workbookName: string, index: number): boolean;
|
|
21
19
|
/**
|
|
22
|
-
* Get all conditional styles for a
|
|
20
|
+
* Get all conditional styles for a range
|
|
23
21
|
*/
|
|
24
|
-
getConditionalStyles(
|
|
22
|
+
getConditionalStyles(range: RangeAddress): ConditionalStyle[];
|
|
25
23
|
/**
|
|
26
24
|
* Add a direct cell style rule
|
|
27
25
|
*/
|
|
@@ -33,7 +31,7 @@ export declare class StyleManager {
|
|
|
33
31
|
/**
|
|
34
32
|
* Get all direct cell styles for a workbook
|
|
35
33
|
*/
|
|
36
|
-
getCellStyles(
|
|
34
|
+
getCellStyles(range: RangeAddress): DirectCellStyle[];
|
|
37
35
|
/**
|
|
38
36
|
* Get all conditional styles across all workbooks (for serialization)
|
|
39
37
|
*/
|