@ricsam/formula-engine 0.0.7 → 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.
@@ -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
+ }
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@ricsam/formula-engine",
3
- "version": "0.0.7",
3
+ "version": "0.0.9",
4
4
  "type": "module"
5
5
  }
@@ -2,7 +2,7 @@
2
2
  * Main FormulaEngine class
3
3
  * Core API implementation for spreadsheet calculations
4
4
  */
5
- import { type CellAddress, type CellStyle, type ConditionalStyle, type DirectCellStyle, type NamedExpression, type RangeAddress, type SerializedCellValue, type SingleEvaluationResult, type SpreadsheetRange, type SpreadsheetRangeEnd, type TableDefinition } from "./types";
5
+ import { type CellAddress, type CellStyle, type ConditionalStyle, type CopyCellsOptions, type DirectCellStyle, type NamedExpression, type RangeAddress, type SerializedCellValue, type SingleEvaluationResult, type SpreadsheetRange, type SpreadsheetRangeEnd, type TableDefinition } from "./types";
6
6
  import type { FillDirection } from "@ricsam/selection-manager";
7
7
  import { AutoFill } from "./autofill-utils";
8
8
  import { WorkbookManager } from "./managers/workbook-manager";
@@ -24,6 +24,7 @@ export declare class FormulaEngine {
24
24
  private autoFillManager;
25
25
  private dependencyManager;
26
26
  private styleManager;
27
+ private copyManager;
27
28
  /**
28
29
  * Public access to the store manager for testing
29
30
  */
@@ -139,6 +140,15 @@ export declare class FormulaEngine {
139
140
  * Get all direct cell styles for a workbook
140
141
  */
141
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;
148
+ /**
149
+ * Copy cells from source to target
150
+ */
151
+ copyCells(source: CellAddress[], target: CellAddress, options: CopyCellsOptions): void;
142
152
  addSheet(opts: {
143
153
  workbookName: string;
144
154
  sheetName: string;
@@ -0,0 +1,50 @@
1
+ /**
2
+ * CopyManager - Manages cell copy/paste operations
3
+ */
4
+ import type { CellAddress, CopyCellsOptions } from "../types";
5
+ import type { WorkbookManager } from "./workbook-manager";
6
+ import type { EvaluationManager } from "./evaluation-manager";
7
+ import type { StyleManager } from "./style-manager";
8
+ export declare class CopyManager {
9
+ private workbookManager;
10
+ private evaluationManager;
11
+ private styleManager;
12
+ constructor(workbookManager: WorkbookManager, evaluationManager: EvaluationManager, styleManager: StyleManager);
13
+ /**
14
+ * Copy cells from source to target
15
+ */
16
+ copyCells(source: CellAddress[], target: CellAddress, options: CopyCellsOptions): void;
17
+ /**
18
+ * Find the top-left cell (minimum row/col indices)
19
+ */
20
+ private findTopLeft;
21
+ /**
22
+ * Copy content from one cell to another
23
+ */
24
+ private copyCellContent;
25
+ /**
26
+ * Adjust formula references when copying
27
+ * Based on autofill-utils.ts adjustFormulaReferences
28
+ */
29
+ private adjustFormulaReferences;
30
+ /**
31
+ * Copy formatting (cellStyles and conditionalStyles) from source to target
32
+ */
33
+ private copyFormatting;
34
+ /**
35
+ * Get bounding box for a set of cells
36
+ */
37
+ private getBoundingBox;
38
+ /**
39
+ * Check if two ranges intersect
40
+ */
41
+ private rangesIntersect;
42
+ /**
43
+ * Adjust a range by row and column offsets
44
+ */
45
+ private adjustRange;
46
+ /**
47
+ * Clear source cells (for cut operation)
48
+ */
49
+ private clearSourceCells;
50
+ }
@@ -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
  }
@@ -311,4 +311,13 @@ export interface DirectCellStyle {
311
311
  export interface CellStyle {
312
312
  backgroundColor?: string;
313
313
  color?: string;
314
+ fontSize?: number;
315
+ bold?: boolean;
316
+ italic?: boolean;
317
+ underline?: boolean;
318
+ }
319
+ export interface CopyCellsOptions {
320
+ cut: boolean;
321
+ type: "value" | "formula";
322
+ formatting: boolean;
314
323
  }
@@ -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[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ricsam/formula-engine",
3
- "version": "0.0.7",
3
+ "version": "0.0.9",
4
4
  "module": "./dist/mjs/lib.mjs",
5
5
  "scripts": {
6
6
  "test": "bun test",