@ricsam/formula-engine 0.0.8 → 0.0.9
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 +5 -1
- package/dist/cjs/core/engine.cjs.map +3 -3
- package/dist/cjs/core/managers/style-manager.cjs +50 -1
- package/dist/cjs/core/managers/style-manager.cjs.map +3 -3
- package/dist/cjs/core/utils/range-utils.cjs +114 -0
- package/dist/cjs/core/utils/range-utils.cjs.map +10 -0
- package/dist/cjs/package.json +1 -1
- package/dist/mjs/core/engine.mjs +5 -1
- package/dist/mjs/core/engine.mjs.map +3 -3
- package/dist/mjs/core/managers/style-manager.mjs +50 -1
- package/dist/mjs/core/managers/style-manager.mjs.map +3 -3
- package/dist/mjs/core/utils/range-utils.mjs +84 -0
- package/dist/mjs/core/utils/range-utils.mjs.map +10 -0
- package/dist/mjs/package.json +1 -1
- package/dist/types/core/engine.d.ts +5 -0
- package/dist/types/core/managers/style-manager.d.ts +6 -1
- package/dist/types/core/utils/range-utils.d.ts +21 -0
- package/package.json +1 -1
package/dist/cjs/core/engine.cjs
CHANGED
|
@@ -253,6 +253,10 @@ class FormulaEngine {
|
|
|
253
253
|
getCellStyles(workbookName) {
|
|
254
254
|
return this.styleManager.getCellStyles(workbookName);
|
|
255
255
|
}
|
|
256
|
+
clearCellStyles(range) {
|
|
257
|
+
this.styleManager.clearCellStyles(range);
|
|
258
|
+
this.eventManager.emitUpdate();
|
|
259
|
+
}
|
|
256
260
|
copyCells(source, target, options) {
|
|
257
261
|
this.copyManager.copyCells(source, target, options);
|
|
258
262
|
this.reevaluate();
|
|
@@ -459,4 +463,4 @@ class FormulaEngine {
|
|
|
459
463
|
}
|
|
460
464
|
}
|
|
461
465
|
|
|
462
|
-
//# debugId=
|
|
466
|
+
//# debugId=44B2616D8CC284FF64756E2164756E21
|
|
@@ -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 //#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.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"
|
|
6
6
|
],
|
|
7
|
-
"mappings": "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
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "44B2616D8CC284FF64756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -34,6 +34,7 @@ __export(exports_style_manager, {
|
|
|
34
34
|
module.exports = __toCommonJS(exports_style_manager);
|
|
35
35
|
var import_utils = require("../utils.cjs");
|
|
36
36
|
var import_color_utils = require("../utils/color-utils.cjs");
|
|
37
|
+
var import_range_utils = require("../utils/range-utils.cjs");
|
|
37
38
|
|
|
38
39
|
class StyleManager {
|
|
39
40
|
workbookManager;
|
|
@@ -333,6 +334,54 @@ class StyleManager {
|
|
|
333
334
|
const sheetRef = needsQuotes ? `'${area.sheetName.replace(/'/g, "''")}'` : area.sheetName;
|
|
334
335
|
return `[${area.workbookName}]${sheetRef}!${rangeStr}`;
|
|
335
336
|
}
|
|
337
|
+
clearCellStyles(range) {
|
|
338
|
+
const newCellStyles = [];
|
|
339
|
+
for (const cellStyle of this.cellStyles) {
|
|
340
|
+
if (!cellStyle || !cellStyle.area) {
|
|
341
|
+
newCellStyles.push(cellStyle);
|
|
342
|
+
continue;
|
|
343
|
+
}
|
|
344
|
+
if (cellStyle.area.workbookName === range.workbookName && cellStyle.area.sheetName === range.sheetName && import_range_utils.rangesIntersect(cellStyle.area.range, range.range)) {
|
|
345
|
+
const remainingRanges = import_range_utils.subtractRange(cellStyle.area.range, range.range);
|
|
346
|
+
for (const remainingRange of remainingRanges) {
|
|
347
|
+
newCellStyles.push({
|
|
348
|
+
area: {
|
|
349
|
+
workbookName: cellStyle.area.workbookName,
|
|
350
|
+
sheetName: cellStyle.area.sheetName,
|
|
351
|
+
range: remainingRange
|
|
352
|
+
},
|
|
353
|
+
style: cellStyle.style
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
} else {
|
|
357
|
+
newCellStyles.push(cellStyle);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
this.cellStyles = newCellStyles;
|
|
361
|
+
const newConditionalStyles = [];
|
|
362
|
+
for (const conditionalStyle of this.conditionalStyles) {
|
|
363
|
+
if (!conditionalStyle || !conditionalStyle.area) {
|
|
364
|
+
newConditionalStyles.push(conditionalStyle);
|
|
365
|
+
continue;
|
|
366
|
+
}
|
|
367
|
+
if (conditionalStyle.area.workbookName === range.workbookName && conditionalStyle.area.sheetName === range.sheetName && import_range_utils.rangesIntersect(conditionalStyle.area.range, range.range)) {
|
|
368
|
+
const remainingRanges = import_range_utils.subtractRange(conditionalStyle.area.range, range.range);
|
|
369
|
+
for (const remainingRange of remainingRanges) {
|
|
370
|
+
newConditionalStyles.push({
|
|
371
|
+
area: {
|
|
372
|
+
workbookName: conditionalStyle.area.workbookName,
|
|
373
|
+
sheetName: conditionalStyle.area.sheetName,
|
|
374
|
+
range: remainingRange
|
|
375
|
+
},
|
|
376
|
+
condition: conditionalStyle.condition
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
} else {
|
|
380
|
+
newConditionalStyles.push(conditionalStyle);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
this.conditionalStyles = newConditionalStyles;
|
|
384
|
+
}
|
|
336
385
|
}
|
|
337
386
|
|
|
338
|
-
//# debugId=
|
|
387
|
+
//# debugId=6E81315BA365AF4964756E2164756E21
|
|
@@ -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\";\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"
|
|
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"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAc8B,IAA9B;AAKO,IAJP;AAAA;
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "6E81315BA365AF4964756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __moduleCache = /* @__PURE__ */ new WeakMap;
|
|
6
|
+
var __toCommonJS = (from) => {
|
|
7
|
+
var entry = __moduleCache.get(from), desc;
|
|
8
|
+
if (entry)
|
|
9
|
+
return entry;
|
|
10
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function")
|
|
12
|
+
__getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
|
|
13
|
+
get: () => from[key],
|
|
14
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
15
|
+
}));
|
|
16
|
+
__moduleCache.set(from, entry);
|
|
17
|
+
return entry;
|
|
18
|
+
};
|
|
19
|
+
var __export = (target, all) => {
|
|
20
|
+
for (var name in all)
|
|
21
|
+
__defProp(target, name, {
|
|
22
|
+
get: all[name],
|
|
23
|
+
enumerable: true,
|
|
24
|
+
configurable: true,
|
|
25
|
+
set: (newValue) => all[name] = () => newValue
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// src/core/utils/range-utils.ts
|
|
30
|
+
var exports_range_utils = {};
|
|
31
|
+
__export(exports_range_utils, {
|
|
32
|
+
subtractRange: () => subtractRange,
|
|
33
|
+
rangesIntersect: () => rangesIntersect,
|
|
34
|
+
isRangeContained: () => isRangeContained
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(exports_range_utils);
|
|
37
|
+
function rangesIntersect(range1, range2) {
|
|
38
|
+
const r1EndCol = range1.end.col.type === "number" ? range1.end.col.value : Infinity;
|
|
39
|
+
const r1EndRow = range1.end.row.type === "number" ? range1.end.row.value : Infinity;
|
|
40
|
+
const r2EndCol = range2.end.col.type === "number" ? range2.end.col.value : Infinity;
|
|
41
|
+
const r2EndRow = range2.end.row.type === "number" ? range2.end.row.value : Infinity;
|
|
42
|
+
const colOverlap = range1.start.col <= r2EndCol && range2.start.col <= r1EndCol;
|
|
43
|
+
const rowOverlap = range1.start.row <= r2EndRow && range2.start.row <= r1EndRow;
|
|
44
|
+
return colOverlap && rowOverlap;
|
|
45
|
+
}
|
|
46
|
+
function isRangeContained(inner, outer) {
|
|
47
|
+
const innerEndCol = inner.end.col.type === "number" ? inner.end.col.value : Infinity;
|
|
48
|
+
const innerEndRow = inner.end.row.type === "number" ? inner.end.row.value : Infinity;
|
|
49
|
+
const outerEndCol = outer.end.col.type === "number" ? outer.end.col.value : Infinity;
|
|
50
|
+
const outerEndRow = outer.end.row.type === "number" ? outer.end.row.value : Infinity;
|
|
51
|
+
return inner.start.col >= outer.start.col && inner.start.row >= outer.start.row && innerEndCol <= outerEndCol && innerEndRow <= outerEndRow;
|
|
52
|
+
}
|
|
53
|
+
function subtractRange(original, subtract) {
|
|
54
|
+
if (!rangesIntersect(original, subtract)) {
|
|
55
|
+
return [original];
|
|
56
|
+
}
|
|
57
|
+
if (isRangeContained(original, subtract)) {
|
|
58
|
+
return [];
|
|
59
|
+
}
|
|
60
|
+
const result = [];
|
|
61
|
+
const origEndCol = original.end.col.type === "number" ? original.end.col.value : Infinity;
|
|
62
|
+
const origEndRow = original.end.row.type === "number" ? original.end.row.value : Infinity;
|
|
63
|
+
const subEndCol = subtract.end.col.type === "number" ? subtract.end.col.value : Infinity;
|
|
64
|
+
const subEndRow = subtract.end.row.type === "number" ? subtract.end.row.value : Infinity;
|
|
65
|
+
const intersectStartCol = Math.max(original.start.col, subtract.start.col);
|
|
66
|
+
const intersectStartRow = Math.max(original.start.row, subtract.start.row);
|
|
67
|
+
const intersectEndCol = Math.min(origEndCol, subEndCol);
|
|
68
|
+
const intersectEndRow = Math.min(origEndRow, subEndRow);
|
|
69
|
+
if (original.start.row < intersectStartRow) {
|
|
70
|
+
result.push({
|
|
71
|
+
start: { col: original.start.col, row: original.start.row },
|
|
72
|
+
end: {
|
|
73
|
+
col: createRangeEnd(origEndCol),
|
|
74
|
+
row: createRangeEnd(intersectStartRow - 1)
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
if (origEndRow > intersectEndRow) {
|
|
79
|
+
result.push({
|
|
80
|
+
start: { col: original.start.col, row: intersectEndRow + 1 },
|
|
81
|
+
end: {
|
|
82
|
+
col: createRangeEnd(origEndCol),
|
|
83
|
+
row: createRangeEnd(origEndRow)
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
if (original.start.col < intersectStartCol) {
|
|
88
|
+
result.push({
|
|
89
|
+
start: { col: original.start.col, row: intersectStartRow },
|
|
90
|
+
end: {
|
|
91
|
+
col: createRangeEnd(intersectStartCol - 1),
|
|
92
|
+
row: createRangeEnd(intersectEndRow)
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
if (origEndCol > intersectEndCol) {
|
|
97
|
+
result.push({
|
|
98
|
+
start: { col: intersectEndCol + 1, row: intersectStartRow },
|
|
99
|
+
end: {
|
|
100
|
+
col: createRangeEnd(origEndCol),
|
|
101
|
+
row: createRangeEnd(intersectEndRow)
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
return result;
|
|
106
|
+
}
|
|
107
|
+
function createRangeEnd(value) {
|
|
108
|
+
if (!isFinite(value)) {
|
|
109
|
+
return { type: "infinity", sign: "positive" };
|
|
110
|
+
}
|
|
111
|
+
return { type: "number", value };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
//# debugId=E61D49F827B99F2964756E2164756E21
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/core/utils/range-utils.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"/**\n * Range utility functions for handling range arithmetic and operations\n */\n\nimport type { SpreadsheetRange, SpreadsheetRangeEnd } from \"../types.cjs\";\n\n/**\n * Check if two ranges intersect\n */\nexport function rangesIntersect(\n range1: SpreadsheetRange,\n range2: SpreadsheetRange\n): boolean {\n // Get finite end values\n const r1EndCol =\n range1.end.col.type === \"number\" ? range1.end.col.value : Infinity;\n const r1EndRow =\n range1.end.row.type === \"number\" ? range1.end.row.value : Infinity;\n const r2EndCol =\n range2.end.col.type === \"number\" ? range2.end.col.value : Infinity;\n const r2EndRow =\n range2.end.row.type === \"number\" ? range2.end.row.value : Infinity;\n\n // Check if ranges overlap\n const colOverlap =\n range1.start.col <= r2EndCol && range2.start.col <= r1EndCol;\n const rowOverlap =\n range1.start.row <= r2EndRow && range2.start.row <= r1EndRow;\n\n return colOverlap && rowOverlap;\n}\n\n/**\n * Check if one range is completely contained within another\n */\nexport function isRangeContained(\n inner: SpreadsheetRange,\n outer: SpreadsheetRange\n): boolean {\n const innerEndCol =\n inner.end.col.type === \"number\" ? inner.end.col.value : Infinity;\n const innerEndRow =\n inner.end.row.type === \"number\" ? inner.end.row.value : Infinity;\n const outerEndCol =\n outer.end.col.type === \"number\" ? outer.end.col.value : Infinity;\n const outerEndRow =\n outer.end.row.type === \"number\" ? outer.end.row.value : Infinity;\n\n return (\n inner.start.col >= outer.start.col &&\n inner.start.row >= outer.start.row &&\n innerEndCol <= outerEndCol &&\n innerEndRow <= outerEndRow\n );\n}\n\n/**\n * Subtract one range from another, returning the remaining ranges\n * Returns an array of ranges representing `original - subtract`\n * \n * For infinite ranges in the original:\n * - If subtract range is finite, we still return the infinite portions\n * - This can result in up to 4 ranges (4 sides around the subtracted area)\n */\nexport function subtractRange(\n original: SpreadsheetRange,\n subtract: SpreadsheetRange\n): SpreadsheetRange[] {\n // If ranges don't intersect, return original unchanged\n if (!rangesIntersect(original, subtract)) {\n return [original];\n }\n\n // If original is completely contained in subtract, return empty\n if (isRangeContained(original, subtract)) {\n return [];\n }\n\n const result: SpreadsheetRange[] = [];\n\n // Get finite end values for easier arithmetic\n const origEndCol =\n original.end.col.type === \"number\" ? original.end.col.value : Infinity;\n const origEndRow =\n original.end.row.type === \"number\" ? original.end.row.value : Infinity;\n const subEndCol =\n subtract.end.col.type === \"number\" ? subtract.end.col.value : Infinity;\n const subEndRow =\n subtract.end.row.type === \"number\" ? subtract.end.row.value : Infinity;\n\n // Calculate the intersection bounds\n const intersectStartCol = Math.max(original.start.col, subtract.start.col);\n const intersectStartRow = Math.max(original.start.row, subtract.start.row);\n const intersectEndCol = Math.min(origEndCol, subEndCol);\n const intersectEndRow = Math.min(origEndRow, subEndRow);\n\n // Create up to 4 rectangles around the intersection:\n // Top, Bottom, Left, Right\n\n // Top rectangle (above the intersection)\n if (original.start.row < intersectStartRow) {\n result.push({\n start: { col: original.start.col, row: original.start.row },\n end: {\n col: createRangeEnd(origEndCol),\n row: createRangeEnd(intersectStartRow - 1),\n },\n });\n }\n\n // Bottom rectangle (below the intersection)\n if (origEndRow > intersectEndRow) {\n result.push({\n start: { col: original.start.col, row: intersectEndRow + 1 },\n end: {\n col: createRangeEnd(origEndCol),\n row: createRangeEnd(origEndRow),\n },\n });\n }\n\n // Left rectangle (left of the intersection, within the vertical bounds of intersection)\n if (original.start.col < intersectStartCol) {\n result.push({\n start: { col: original.start.col, row: intersectStartRow },\n end: {\n col: createRangeEnd(intersectStartCol - 1),\n row: createRangeEnd(intersectEndRow),\n },\n });\n }\n\n // Right rectangle (right of the intersection, within the vertical bounds of intersection)\n if (origEndCol > intersectEndCol) {\n result.push({\n start: { col: intersectEndCol + 1, row: intersectStartRow },\n end: {\n col: createRangeEnd(origEndCol),\n row: createRangeEnd(intersectEndRow),\n },\n });\n }\n\n return result;\n}\n\n/**\n * Helper to create a SpreadsheetRangeEnd from a number (handles infinity)\n */\nfunction createRangeEnd(value: number): SpreadsheetRangeEnd {\n if (!isFinite(value)) {\n return { type: \"infinity\", sign: \"positive\" };\n }\n return { type: \"number\", value };\n}\n\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "E61D49F827B99F2964756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
package/dist/cjs/package.json
CHANGED
package/dist/mjs/core/engine.mjs
CHANGED
|
@@ -220,6 +220,10 @@ class FormulaEngine {
|
|
|
220
220
|
getCellStyles(workbookName) {
|
|
221
221
|
return this.styleManager.getCellStyles(workbookName);
|
|
222
222
|
}
|
|
223
|
+
clearCellStyles(range) {
|
|
224
|
+
this.styleManager.clearCellStyles(range);
|
|
225
|
+
this.eventManager.emitUpdate();
|
|
226
|
+
}
|
|
223
227
|
copyCells(source, target, options) {
|
|
224
228
|
this.copyManager.copyCells(source, target, options);
|
|
225
229
|
this.reevaluate();
|
|
@@ -429,4 +433,4 @@ export {
|
|
|
429
433
|
FormulaEngine
|
|
430
434
|
};
|
|
431
435
|
|
|
432
|
-
//# debugId=
|
|
436
|
+
//# debugId=D080BCAFF49575BE64756E2164756E21
|
|
@@ -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 //#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.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"
|
|
6
6
|
],
|
|
7
|
-
"mappings": "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
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "D080BCAFF49575BE64756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
interpolateLCH,
|
|
6
6
|
lchToHex
|
|
7
7
|
} from "../utils/color-utils.mjs";
|
|
8
|
+
import { subtractRange, rangesIntersect } from "../utils/range-utils.mjs";
|
|
8
9
|
|
|
9
10
|
class StyleManager {
|
|
10
11
|
workbookManager;
|
|
@@ -304,9 +305,57 @@ class StyleManager {
|
|
|
304
305
|
const sheetRef = needsQuotes ? `'${area.sheetName.replace(/'/g, "''")}'` : area.sheetName;
|
|
305
306
|
return `[${area.workbookName}]${sheetRef}!${rangeStr}`;
|
|
306
307
|
}
|
|
308
|
+
clearCellStyles(range) {
|
|
309
|
+
const newCellStyles = [];
|
|
310
|
+
for (const cellStyle of this.cellStyles) {
|
|
311
|
+
if (!cellStyle || !cellStyle.area) {
|
|
312
|
+
newCellStyles.push(cellStyle);
|
|
313
|
+
continue;
|
|
314
|
+
}
|
|
315
|
+
if (cellStyle.area.workbookName === range.workbookName && cellStyle.area.sheetName === range.sheetName && rangesIntersect(cellStyle.area.range, range.range)) {
|
|
316
|
+
const remainingRanges = subtractRange(cellStyle.area.range, range.range);
|
|
317
|
+
for (const remainingRange of remainingRanges) {
|
|
318
|
+
newCellStyles.push({
|
|
319
|
+
area: {
|
|
320
|
+
workbookName: cellStyle.area.workbookName,
|
|
321
|
+
sheetName: cellStyle.area.sheetName,
|
|
322
|
+
range: remainingRange
|
|
323
|
+
},
|
|
324
|
+
style: cellStyle.style
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
} else {
|
|
328
|
+
newCellStyles.push(cellStyle);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
this.cellStyles = newCellStyles;
|
|
332
|
+
const newConditionalStyles = [];
|
|
333
|
+
for (const conditionalStyle of this.conditionalStyles) {
|
|
334
|
+
if (!conditionalStyle || !conditionalStyle.area) {
|
|
335
|
+
newConditionalStyles.push(conditionalStyle);
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
if (conditionalStyle.area.workbookName === range.workbookName && conditionalStyle.area.sheetName === range.sheetName && rangesIntersect(conditionalStyle.area.range, range.range)) {
|
|
339
|
+
const remainingRanges = subtractRange(conditionalStyle.area.range, range.range);
|
|
340
|
+
for (const remainingRange of remainingRanges) {
|
|
341
|
+
newConditionalStyles.push({
|
|
342
|
+
area: {
|
|
343
|
+
workbookName: conditionalStyle.area.workbookName,
|
|
344
|
+
sheetName: conditionalStyle.area.sheetName,
|
|
345
|
+
range: remainingRange
|
|
346
|
+
},
|
|
347
|
+
condition: conditionalStyle.condition
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
} else {
|
|
351
|
+
newConditionalStyles.push(conditionalStyle);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
this.conditionalStyles = newConditionalStyles;
|
|
355
|
+
}
|
|
307
356
|
}
|
|
308
357
|
export {
|
|
309
358
|
StyleManager
|
|
310
359
|
};
|
|
311
360
|
|
|
312
|
-
//# debugId=
|
|
361
|
+
//# debugId=DA8554FFDBF6EBC164756E2164756E21
|
|
@@ -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\";\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"
|
|
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"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";AAcA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "DA8554FFDBF6EBC164756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// src/core/utils/range-utils.ts
|
|
2
|
+
function rangesIntersect(range1, range2) {
|
|
3
|
+
const r1EndCol = range1.end.col.type === "number" ? range1.end.col.value : Infinity;
|
|
4
|
+
const r1EndRow = range1.end.row.type === "number" ? range1.end.row.value : Infinity;
|
|
5
|
+
const r2EndCol = range2.end.col.type === "number" ? range2.end.col.value : Infinity;
|
|
6
|
+
const r2EndRow = range2.end.row.type === "number" ? range2.end.row.value : Infinity;
|
|
7
|
+
const colOverlap = range1.start.col <= r2EndCol && range2.start.col <= r1EndCol;
|
|
8
|
+
const rowOverlap = range1.start.row <= r2EndRow && range2.start.row <= r1EndRow;
|
|
9
|
+
return colOverlap && rowOverlap;
|
|
10
|
+
}
|
|
11
|
+
function isRangeContained(inner, outer) {
|
|
12
|
+
const innerEndCol = inner.end.col.type === "number" ? inner.end.col.value : Infinity;
|
|
13
|
+
const innerEndRow = inner.end.row.type === "number" ? inner.end.row.value : Infinity;
|
|
14
|
+
const outerEndCol = outer.end.col.type === "number" ? outer.end.col.value : Infinity;
|
|
15
|
+
const outerEndRow = outer.end.row.type === "number" ? outer.end.row.value : Infinity;
|
|
16
|
+
return inner.start.col >= outer.start.col && inner.start.row >= outer.start.row && innerEndCol <= outerEndCol && innerEndRow <= outerEndRow;
|
|
17
|
+
}
|
|
18
|
+
function subtractRange(original, subtract) {
|
|
19
|
+
if (!rangesIntersect(original, subtract)) {
|
|
20
|
+
return [original];
|
|
21
|
+
}
|
|
22
|
+
if (isRangeContained(original, subtract)) {
|
|
23
|
+
return [];
|
|
24
|
+
}
|
|
25
|
+
const result = [];
|
|
26
|
+
const origEndCol = original.end.col.type === "number" ? original.end.col.value : Infinity;
|
|
27
|
+
const origEndRow = original.end.row.type === "number" ? original.end.row.value : Infinity;
|
|
28
|
+
const subEndCol = subtract.end.col.type === "number" ? subtract.end.col.value : Infinity;
|
|
29
|
+
const subEndRow = subtract.end.row.type === "number" ? subtract.end.row.value : Infinity;
|
|
30
|
+
const intersectStartCol = Math.max(original.start.col, subtract.start.col);
|
|
31
|
+
const intersectStartRow = Math.max(original.start.row, subtract.start.row);
|
|
32
|
+
const intersectEndCol = Math.min(origEndCol, subEndCol);
|
|
33
|
+
const intersectEndRow = Math.min(origEndRow, subEndRow);
|
|
34
|
+
if (original.start.row < intersectStartRow) {
|
|
35
|
+
result.push({
|
|
36
|
+
start: { col: original.start.col, row: original.start.row },
|
|
37
|
+
end: {
|
|
38
|
+
col: createRangeEnd(origEndCol),
|
|
39
|
+
row: createRangeEnd(intersectStartRow - 1)
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
if (origEndRow > intersectEndRow) {
|
|
44
|
+
result.push({
|
|
45
|
+
start: { col: original.start.col, row: intersectEndRow + 1 },
|
|
46
|
+
end: {
|
|
47
|
+
col: createRangeEnd(origEndCol),
|
|
48
|
+
row: createRangeEnd(origEndRow)
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
if (original.start.col < intersectStartCol) {
|
|
53
|
+
result.push({
|
|
54
|
+
start: { col: original.start.col, row: intersectStartRow },
|
|
55
|
+
end: {
|
|
56
|
+
col: createRangeEnd(intersectStartCol - 1),
|
|
57
|
+
row: createRangeEnd(intersectEndRow)
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
if (origEndCol > intersectEndCol) {
|
|
62
|
+
result.push({
|
|
63
|
+
start: { col: intersectEndCol + 1, row: intersectStartRow },
|
|
64
|
+
end: {
|
|
65
|
+
col: createRangeEnd(origEndCol),
|
|
66
|
+
row: createRangeEnd(intersectEndRow)
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
72
|
+
function createRangeEnd(value) {
|
|
73
|
+
if (!isFinite(value)) {
|
|
74
|
+
return { type: "infinity", sign: "positive" };
|
|
75
|
+
}
|
|
76
|
+
return { type: "number", value };
|
|
77
|
+
}
|
|
78
|
+
export {
|
|
79
|
+
subtractRange,
|
|
80
|
+
rangesIntersect,
|
|
81
|
+
isRangeContained
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
//# debugId=F3D0BBCF4CE38B2764756E2164756E21
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/core/utils/range-utils.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"/**\n * Range utility functions for handling range arithmetic and operations\n */\n\nimport type { SpreadsheetRange, SpreadsheetRangeEnd } from \"../types.mjs\";\n\n/**\n * Check if two ranges intersect\n */\nexport function rangesIntersect(\n range1: SpreadsheetRange,\n range2: SpreadsheetRange\n): boolean {\n // Get finite end values\n const r1EndCol =\n range1.end.col.type === \"number\" ? range1.end.col.value : Infinity;\n const r1EndRow =\n range1.end.row.type === \"number\" ? range1.end.row.value : Infinity;\n const r2EndCol =\n range2.end.col.type === \"number\" ? range2.end.col.value : Infinity;\n const r2EndRow =\n range2.end.row.type === \"number\" ? range2.end.row.value : Infinity;\n\n // Check if ranges overlap\n const colOverlap =\n range1.start.col <= r2EndCol && range2.start.col <= r1EndCol;\n const rowOverlap =\n range1.start.row <= r2EndRow && range2.start.row <= r1EndRow;\n\n return colOverlap && rowOverlap;\n}\n\n/**\n * Check if one range is completely contained within another\n */\nexport function isRangeContained(\n inner: SpreadsheetRange,\n outer: SpreadsheetRange\n): boolean {\n const innerEndCol =\n inner.end.col.type === \"number\" ? inner.end.col.value : Infinity;\n const innerEndRow =\n inner.end.row.type === \"number\" ? inner.end.row.value : Infinity;\n const outerEndCol =\n outer.end.col.type === \"number\" ? outer.end.col.value : Infinity;\n const outerEndRow =\n outer.end.row.type === \"number\" ? outer.end.row.value : Infinity;\n\n return (\n inner.start.col >= outer.start.col &&\n inner.start.row >= outer.start.row &&\n innerEndCol <= outerEndCol &&\n innerEndRow <= outerEndRow\n );\n}\n\n/**\n * Subtract one range from another, returning the remaining ranges\n * Returns an array of ranges representing `original - subtract`\n * \n * For infinite ranges in the original:\n * - If subtract range is finite, we still return the infinite portions\n * - This can result in up to 4 ranges (4 sides around the subtracted area)\n */\nexport function subtractRange(\n original: SpreadsheetRange,\n subtract: SpreadsheetRange\n): SpreadsheetRange[] {\n // If ranges don't intersect, return original unchanged\n if (!rangesIntersect(original, subtract)) {\n return [original];\n }\n\n // If original is completely contained in subtract, return empty\n if (isRangeContained(original, subtract)) {\n return [];\n }\n\n const result: SpreadsheetRange[] = [];\n\n // Get finite end values for easier arithmetic\n const origEndCol =\n original.end.col.type === \"number\" ? original.end.col.value : Infinity;\n const origEndRow =\n original.end.row.type === \"number\" ? original.end.row.value : Infinity;\n const subEndCol =\n subtract.end.col.type === \"number\" ? subtract.end.col.value : Infinity;\n const subEndRow =\n subtract.end.row.type === \"number\" ? subtract.end.row.value : Infinity;\n\n // Calculate the intersection bounds\n const intersectStartCol = Math.max(original.start.col, subtract.start.col);\n const intersectStartRow = Math.max(original.start.row, subtract.start.row);\n const intersectEndCol = Math.min(origEndCol, subEndCol);\n const intersectEndRow = Math.min(origEndRow, subEndRow);\n\n // Create up to 4 rectangles around the intersection:\n // Top, Bottom, Left, Right\n\n // Top rectangle (above the intersection)\n if (original.start.row < intersectStartRow) {\n result.push({\n start: { col: original.start.col, row: original.start.row },\n end: {\n col: createRangeEnd(origEndCol),\n row: createRangeEnd(intersectStartRow - 1),\n },\n });\n }\n\n // Bottom rectangle (below the intersection)\n if (origEndRow > intersectEndRow) {\n result.push({\n start: { col: original.start.col, row: intersectEndRow + 1 },\n end: {\n col: createRangeEnd(origEndCol),\n row: createRangeEnd(origEndRow),\n },\n });\n }\n\n // Left rectangle (left of the intersection, within the vertical bounds of intersection)\n if (original.start.col < intersectStartCol) {\n result.push({\n start: { col: original.start.col, row: intersectStartRow },\n end: {\n col: createRangeEnd(intersectStartCol - 1),\n row: createRangeEnd(intersectEndRow),\n },\n });\n }\n\n // Right rectangle (right of the intersection, within the vertical bounds of intersection)\n if (origEndCol > intersectEndCol) {\n result.push({\n start: { col: intersectEndCol + 1, row: intersectStartRow },\n end: {\n col: createRangeEnd(origEndCol),\n row: createRangeEnd(intersectEndRow),\n },\n });\n }\n\n return result;\n}\n\n/**\n * Helper to create a SpreadsheetRangeEnd from a number (handles infinity)\n */\nfunction createRangeEnd(value: number): SpreadsheetRangeEnd {\n if (!isFinite(value)) {\n return { type: \"infinity\", sign: \"positive\" };\n }\n return { type: \"number\", value };\n}\n\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "F3D0BBCF4CE38B2764756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
package/dist/mjs/package.json
CHANGED
|
@@ -140,6 +140,11 @@ export declare class FormulaEngine {
|
|
|
140
140
|
* Get all direct cell styles for a workbook
|
|
141
141
|
*/
|
|
142
142
|
getCellStyles(workbookName: string): DirectCellStyle[];
|
|
143
|
+
/**
|
|
144
|
+
* Clear all cell styles and conditional styles for a given range
|
|
145
|
+
* Adjusts existing style ranges rather than deleting them entirely
|
|
146
|
+
*/
|
|
147
|
+
clearCellStyles(range: RangeAddress): void;
|
|
143
148
|
/**
|
|
144
149
|
* Copy cells from source to target
|
|
145
150
|
*/
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* StyleManager - Manages conditional styling for cells
|
|
3
3
|
*/
|
|
4
|
-
import type { CellAddress, CellStyle, ConditionalStyle, DirectCellStyle } from "../types";
|
|
4
|
+
import type { CellAddress, CellStyle, ConditionalStyle, DirectCellStyle, RangeAddress } from "../types";
|
|
5
5
|
import type { WorkbookManager } from "./workbook-manager";
|
|
6
6
|
import type { EvaluationManager } from "./evaluation-manager";
|
|
7
7
|
export declare class StyleManager {
|
|
@@ -89,4 +89,9 @@ export declare class StyleManager {
|
|
|
89
89
|
* - Open both: A5:INFINITY
|
|
90
90
|
*/
|
|
91
91
|
private getRangeReference;
|
|
92
|
+
/**
|
|
93
|
+
* Clear cell styles and conditional styles for a given range
|
|
94
|
+
* Adjusts existing style ranges rather than deleting them entirely
|
|
95
|
+
*/
|
|
96
|
+
clearCellStyles(range: RangeAddress): void;
|
|
92
97
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Range utility functions for handling range arithmetic and operations
|
|
3
|
+
*/
|
|
4
|
+
import type { SpreadsheetRange } from "../types";
|
|
5
|
+
/**
|
|
6
|
+
* Check if two ranges intersect
|
|
7
|
+
*/
|
|
8
|
+
export declare function rangesIntersect(range1: SpreadsheetRange, range2: SpreadsheetRange): boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Check if one range is completely contained within another
|
|
11
|
+
*/
|
|
12
|
+
export declare function isRangeContained(inner: SpreadsheetRange, outer: SpreadsheetRange): boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Subtract one range from another, returning the remaining ranges
|
|
15
|
+
* Returns an array of ranges representing `original - subtract`
|
|
16
|
+
*
|
|
17
|
+
* For infinite ranges in the original:
|
|
18
|
+
* - If subtract range is finite, we still return the infinite portions
|
|
19
|
+
* - This can result in up to 4 ranges (4 sides around the subtracted area)
|
|
20
|
+
*/
|
|
21
|
+
export declare function subtractRange(original: SpreadsheetRange, subtract: SpreadsheetRange): SpreadsheetRange[];
|