@ricsam/formula-engine 0.0.15 → 0.0.17
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/autofill-utils.cjs +73 -35
- package/dist/cjs/core/autofill-utils.cjs.map +3 -3
- package/dist/cjs/core/cell-mover.cjs +178 -0
- package/dist/cjs/core/cell-mover.cjs.map +10 -0
- package/dist/cjs/core/engine.cjs +126 -3
- package/dist/cjs/core/engine.cjs.map +3 -3
- package/dist/cjs/core/managers/copy-manager.cjs +337 -82
- package/dist/cjs/core/managers/copy-manager.cjs.map +3 -3
- package/dist/cjs/core/managers/reference-manager.cjs +124 -0
- package/dist/cjs/core/managers/reference-manager.cjs.map +10 -0
- package/dist/cjs/core/managers/style-manager.cjs +115 -147
- package/dist/cjs/core/managers/style-manager.cjs.map +3 -3
- package/dist/cjs/core/managers/workbook-manager.cjs +104 -3
- package/dist/cjs/core/managers/workbook-manager.cjs.map +3 -3
- package/dist/cjs/core/types.cjs.map +2 -2
- package/dist/cjs/package.json +1 -1
- package/dist/mjs/core/autofill-utils.mjs +73 -35
- package/dist/mjs/core/autofill-utils.mjs.map +3 -3
- package/dist/mjs/core/cell-mover.mjs +148 -0
- package/dist/mjs/core/cell-mover.mjs.map +10 -0
- package/dist/mjs/core/engine.mjs +126 -3
- package/dist/mjs/core/engine.mjs.map +3 -3
- package/dist/mjs/core/managers/copy-manager.mjs +339 -82
- package/dist/mjs/core/managers/copy-manager.mjs.map +3 -3
- package/dist/mjs/core/managers/reference-manager.mjs +93 -0
- package/dist/mjs/core/managers/reference-manager.mjs.map +10 -0
- package/dist/mjs/core/managers/style-manager.mjs +115 -147
- package/dist/mjs/core/managers/style-manager.mjs.map +3 -3
- package/dist/mjs/core/managers/workbook-manager.mjs +104 -3
- package/dist/mjs/core/managers/workbook-manager.mjs.map +3 -3
- package/dist/mjs/core/types.mjs.map +2 -2
- package/dist/mjs/package.json +1 -1
- package/dist/types/core/autofill-utils.d.ts +4 -0
- package/dist/types/core/cell-mover.d.ts +63 -0
- package/dist/types/core/engine.d.ts +123 -9
- package/dist/types/core/managers/copy-manager.d.ts +47 -2
- package/dist/types/core/managers/reference-manager.d.ts +54 -0
- package/dist/types/core/managers/style-manager.d.ts +6 -6
- package/dist/types/core/managers/workbook-manager.d.ts +40 -1
- package/dist/types/core/types.d.ts +52 -11
- package/package.json +1 -1
|
@@ -81,7 +81,8 @@ class WorkbookManager {
|
|
|
81
81
|
}
|
|
82
82
|
this.workbooks.set(workbookName, {
|
|
83
83
|
name: workbookName,
|
|
84
|
-
sheets: new Map
|
|
84
|
+
sheets: new Map,
|
|
85
|
+
workbookMetadata: undefined
|
|
85
86
|
});
|
|
86
87
|
}
|
|
87
88
|
removeWorkbook(workbookName) {
|
|
@@ -163,7 +164,9 @@ class WorkbookManager {
|
|
|
163
164
|
const sheet = {
|
|
164
165
|
name: sheetName,
|
|
165
166
|
index: workbook.sheets.size,
|
|
166
|
-
content: new Map
|
|
167
|
+
content: new Map,
|
|
168
|
+
metadata: new Map,
|
|
169
|
+
sheetMetadata: undefined
|
|
167
170
|
};
|
|
168
171
|
if (workbook.sheets.has(sheet.name)) {
|
|
169
172
|
throw new Error("Sheet already exists");
|
|
@@ -235,6 +238,43 @@ class WorkbookManager {
|
|
|
235
238
|
update(workbook.sheets);
|
|
236
239
|
});
|
|
237
240
|
}
|
|
241
|
+
updateFormulasExcluding(excludeCellsSet, updateCallback) {
|
|
242
|
+
this.workbooks.forEach((workbook, workbookName) => {
|
|
243
|
+
workbook.sheets.forEach((sheet, sheetName) => {
|
|
244
|
+
sheet.content.forEach((cell, key) => {
|
|
245
|
+
if (typeof cell === "string" && cell.startsWith("=")) {
|
|
246
|
+
const { colIndex, rowIndex } = parseCellReference(key);
|
|
247
|
+
const cellKey = `${workbookName}:${sheetName}:${colIndex}:${rowIndex}`;
|
|
248
|
+
if (excludeCellsSet.has(cellKey)) {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
const formula = cell.slice(1);
|
|
252
|
+
const updatedFormula = updateCallback(formula);
|
|
253
|
+
if (updatedFormula !== formula) {
|
|
254
|
+
sheet.content.set(key, `=${updatedFormula}`);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
updateFormulasForWorkbook(workbookName, updateCallback) {
|
|
262
|
+
const workbook = this.workbooks.get(workbookName);
|
|
263
|
+
if (!workbook) {
|
|
264
|
+
throw new WorkbookNotFoundError(workbookName);
|
|
265
|
+
}
|
|
266
|
+
workbook.sheets.forEach((sheet) => {
|
|
267
|
+
sheet.content.forEach((cell, key) => {
|
|
268
|
+
if (typeof cell === "string" && cell.startsWith("=")) {
|
|
269
|
+
const formula = cell.slice(1);
|
|
270
|
+
const updatedFormula = updateCallback(formula);
|
|
271
|
+
if (updatedFormula !== formula) {
|
|
272
|
+
sheet.content.set(key, `=${updatedFormula}`);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
});
|
|
277
|
+
}
|
|
238
278
|
getSheetSerialized({
|
|
239
279
|
workbookName,
|
|
240
280
|
sheetName
|
|
@@ -325,6 +365,64 @@ class WorkbookManager {
|
|
|
325
365
|
this.addCellToGroups(indexes, address.rowIndex, address.colIndex, adr);
|
|
326
366
|
}
|
|
327
367
|
}
|
|
368
|
+
setCellMetadata(address, metadata) {
|
|
369
|
+
const sheet = this.getSheet({
|
|
370
|
+
workbookName: address.workbookName,
|
|
371
|
+
sheetName: address.sheetName
|
|
372
|
+
});
|
|
373
|
+
if (!sheet) {
|
|
374
|
+
throw new SheetNotFoundError(address.sheetName);
|
|
375
|
+
}
|
|
376
|
+
const key = getCellReference(address);
|
|
377
|
+
if (metadata === undefined) {
|
|
378
|
+
sheet.metadata.delete(key);
|
|
379
|
+
} else {
|
|
380
|
+
sheet.metadata.set(key, metadata);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
getCellMetadata(address) {
|
|
384
|
+
const sheet = this.getSheet({
|
|
385
|
+
workbookName: address.workbookName,
|
|
386
|
+
sheetName: address.sheetName
|
|
387
|
+
});
|
|
388
|
+
if (!sheet) {
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
391
|
+
const key = getCellReference(address);
|
|
392
|
+
return sheet.metadata.get(key);
|
|
393
|
+
}
|
|
394
|
+
getSheetMetadataSerialized(opts) {
|
|
395
|
+
const sheet = this.getSheet(opts);
|
|
396
|
+
return sheet?.metadata || new Map;
|
|
397
|
+
}
|
|
398
|
+
setSheetMetadata(opts, metadata) {
|
|
399
|
+
const sheet = this.getSheet(opts);
|
|
400
|
+
if (!sheet) {
|
|
401
|
+
throw new SheetNotFoundError(opts.sheetName);
|
|
402
|
+
}
|
|
403
|
+
sheet.sheetMetadata = metadata;
|
|
404
|
+
}
|
|
405
|
+
getSheetMetadata(opts) {
|
|
406
|
+
const sheet = this.getSheet(opts);
|
|
407
|
+
if (!sheet) {
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
return sheet.sheetMetadata;
|
|
411
|
+
}
|
|
412
|
+
setWorkbookMetadata(workbookName, metadata) {
|
|
413
|
+
const workbook = this.workbooks.get(workbookName);
|
|
414
|
+
if (!workbook) {
|
|
415
|
+
throw new Error(`Workbook "${workbookName}" not found`);
|
|
416
|
+
}
|
|
417
|
+
workbook.workbookMetadata = metadata;
|
|
418
|
+
}
|
|
419
|
+
getWorkbookMetadata(workbookName) {
|
|
420
|
+
const workbook = this.workbooks.get(workbookName);
|
|
421
|
+
if (!workbook) {
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
return workbook.workbookMetadata;
|
|
425
|
+
}
|
|
328
426
|
setSheetContent(opts, newContent) {
|
|
329
427
|
const sheet = this.getSheet(opts);
|
|
330
428
|
if (!sheet) {
|
|
@@ -351,11 +449,14 @@ class WorkbookManager {
|
|
|
351
449
|
throw new SheetNotFoundError(address.sheetName);
|
|
352
450
|
}
|
|
353
451
|
const newContent = new Map(sheet.content);
|
|
452
|
+
const newMetadata = new Map(sheet.metadata);
|
|
354
453
|
for (const cellAddress of this.iterateCellsInRange(address)) {
|
|
355
454
|
const cellRef = getCellReference(cellAddress);
|
|
356
455
|
newContent.delete(cellRef);
|
|
456
|
+
newMetadata.delete(cellRef);
|
|
357
457
|
}
|
|
358
458
|
this.setSheetContent(address, newContent);
|
|
459
|
+
sheet.metadata = newMetadata;
|
|
359
460
|
}
|
|
360
461
|
*iterateCellsInRange(address) {
|
|
361
462
|
const sheet = this.getSheet(address);
|
|
@@ -444,4 +545,4 @@ export {
|
|
|
444
545
|
IndexEntryBinarySearch
|
|
445
546
|
};
|
|
446
547
|
|
|
447
|
-
//# debugId=
|
|
548
|
+
//# debugId=495D50D4550C2C5B64756E2164756E21
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/core/managers/workbook-manager.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import {\n FormulaError,\n type CellAddress,\n type FiniteSpreadsheetRange,\n type LocalCellAddress,\n type SerializedCellValue,\n type Sheet,\n type SpreadsheetRange,\n type Workbook,\n} from \"../types.mjs\";\nimport { getCellReference, parseCellReference } from \"../utils.mjs\";\n\nimport type { RangeAddress } from \"../types.mjs\";\nimport { buildRangeEvalOrder } from \"./range-eval-order-builder.mjs\";\nimport {\n EvaluationError,\n SheetNotFoundError,\n WorkbookNotFoundError,\n} from \"../../evaluator/evaluation-error.mjs\";\nimport { normalizeSerializedCellValue } from \"../../parser/formatter.mjs\";\n\ninterface IndexEntry {\n number: number;\n key: string;\n}\n\nexport interface SheetIndexes {\n // lookup maps - cells grouped by row/column\n rowGroups: Map<number, IndexEntry[]>; // row number -> cells in that row (sorted by col)\n colGroups: Map<number, IndexEntry[]>; // col number -> cells in that col (sorted by row)\n\n // Sorted flat indexes - for finding cells before a given row/col\n cellsSortedByRow: IndexEntry[];\n cellsSortedByCol: IndexEntry[];\n}\n\n/**\n * Utility class for binary search operations on IndexEntry arrays\n */\nexport class IndexEntryBinarySearch {\n /**\n * Find the insertion point for a number in a sorted IndexEntry array\n * Returns the index where the number should be inserted to maintain sort order\n */\n static findInsertionPoint(entries: IndexEntry[], target: number): number {\n let left = 0;\n let right = entries.length;\n\n while (left < right) {\n const mid = Math.floor((left + right) / 2);\n const midEntry = entries[mid];\n if (midEntry && midEntry.number < target) {\n left = mid + 1;\n } else {\n right = mid;\n }\n }\n\n return left;\n }\n\n /**\n * Find the first element >= target\n * Returns the index of the first element, or -1 if not found\n */\n static findFirstGreaterOrEqual(\n entries: IndexEntry[],\n target: number\n ): number {\n if (entries.length === 0) return -1;\n\n let left = 0;\n let right = entries.length - 1;\n let result = -1;\n\n while (left <= right) {\n const mid = Math.floor((left + right) / 2);\n const midEntry = entries[mid];\n if (midEntry && midEntry.number >= target) {\n result = mid;\n right = mid - 1;\n } else {\n left = mid + 1;\n }\n }\n\n return result;\n }\n\n /**\n * Find the rightmost position where we could insert a target value\n * Useful for finding elements that come before a target\n */\n static findRightmostInsertionPoint(\n entries: IndexEntry[],\n target: number\n ): number {\n return IndexEntryBinarySearch.findInsertionPoint(entries, target);\n }\n}\n\nexport class WorkbookManager {\n private workbooks: Map<string, Workbook> = new Map();\n\n // Map from \"workbookName|sheetName\" to indexes\n private sheetIndexes: Map<string, SheetIndexes> = new Map();\n\n /**\n * Generate a key for the sheet indexes map\n */\n private getSheetIndexKey(workbookName: string, sheetName: string): string {\n return `${workbookName}|${sheetName}`;\n }\n\n /**\n * Get or create indexes for a sheet\n */\n public getSheetIndexes(opts: {\n workbookName: string;\n sheetName: string;\n }): SheetIndexes {\n const key = this.getSheetIndexKey(opts.workbookName, opts.sheetName);\n let indexes = this.sheetIndexes.get(key);\n\n if (!indexes) {\n indexes = {\n rowGroups: new Map(),\n colGroups: new Map(),\n cellsSortedByRow: [],\n cellsSortedByCol: [],\n };\n this.sheetIndexes.set(key, indexes);\n }\n\n return indexes;\n }\n\n getSheets(workbookName: string): Map<string, Sheet> {\n const workbook = this.workbooks.get(workbookName);\n if (!workbook) {\n throw new WorkbookNotFoundError(workbookName);\n }\n return workbook.sheets;\n }\n\n getWorkbooks(): Map<string, Workbook> {\n return this.workbooks;\n }\n\n addWorkbook(workbookName: string): void {\n if (this.workbooks.has(workbookName)) {\n throw new Error(\"Workbook already exists\");\n }\n this.workbooks.set(workbookName, {\n name: workbookName,\n sheets: new Map(),\n });\n }\n\n removeWorkbook(workbookName: string): void {\n const workbook = this.workbooks.get(workbookName);\n if (!workbook) {\n throw new WorkbookNotFoundError(workbookName);\n }\n\n // Clean up indexes for all sheets in this workbook\n for (const sheetName of workbook.sheets.keys()) {\n const key = this.getSheetIndexKey(workbookName, sheetName);\n this.sheetIndexes.delete(key);\n }\n\n this.workbooks.delete(workbookName);\n }\n\n isContentEmpty(content: SerializedCellValue): boolean {\n return content === \"\" || content === undefined;\n }\n\n renameWorkbook(opts: {\n workbookName: string;\n newWorkbookName: string;\n }): void {\n const workbook = this.workbooks.get(opts.workbookName);\n if (!workbook) {\n throw new Error(\"Workbook not found\");\n }\n\n // Update indexes for all sheets in this workbook\n for (const sheetName of workbook.sheets.keys()) {\n const oldKey = this.getSheetIndexKey(opts.workbookName, sheetName);\n const newKey = this.getSheetIndexKey(opts.newWorkbookName, sheetName);\n const indexes = this.sheetIndexes.get(oldKey);\n if (indexes) {\n this.sheetIndexes.set(newKey, indexes);\n this.sheetIndexes.delete(oldKey);\n }\n }\n\n this.workbooks.set(opts.newWorkbookName, workbook);\n this.workbooks.delete(opts.workbookName);\n workbook.name = opts.newWorkbookName;\n }\n\n resetWorkbooks(workbooks: Map<string, Workbook>): void {\n this.workbooks.clear();\n this.sheetIndexes.clear();\n\n workbooks.forEach((workbook, workbookName) => {\n this.workbooks.set(workbookName, workbook);\n workbook.sheets.forEach((sheet) => {\n // Initialize indexes for this sheet\n const indexes = this.getSheetIndexes({\n workbookName,\n sheetName: sheet.name,\n });\n indexes.rowGroups.clear();\n indexes.colGroups.clear();\n indexes.cellsSortedByRow = [];\n indexes.cellsSortedByCol = [];\n\n sheet.content.forEach((value, key) => {\n this.setCellContent(\n {\n workbookName,\n sheetName: sheet.name,\n colIndex: parseCellReference(key).colIndex,\n rowIndex: parseCellReference(key).rowIndex,\n },\n value,\n {\n sheet,\n buildingFromScratch: true,\n }\n );\n });\n });\n });\n }\n\n getSheet({\n workbookName,\n sheetName,\n }: {\n workbookName: string;\n sheetName: string;\n }): Sheet | undefined {\n const workbook = this.workbooks.get(workbookName);\n const sheet = workbook?.sheets.get(sheetName);\n return sheet;\n }\n\n addSheet({\n workbookName,\n sheetName,\n }: {\n workbookName: string;\n sheetName: string;\n }): Sheet {\n const workbook = this.workbooks.get(workbookName);\n if (!workbook) {\n throw new WorkbookNotFoundError(workbookName);\n }\n const sheet = {\n name: sheetName,\n index: workbook.sheets.size,\n content: new Map(),\n };\n\n if (workbook.sheets.has(sheet.name)) {\n throw new Error(\"Sheet already exists\");\n }\n\n workbook.sheets.set(sheetName, sheet);\n\n // Initialize empty indexes for this sheet\n this.getSheetIndexes({ workbookName, sheetName });\n\n return sheet;\n }\n\n removeSheet({\n workbookName,\n sheetName,\n }: {\n workbookName: string;\n sheetName: string;\n }): Sheet {\n const workbook = this.workbooks.get(workbookName);\n if (!workbook) {\n throw new WorkbookNotFoundError(workbookName);\n }\n const sheet = workbook.sheets.get(sheetName);\n if (!sheet) {\n throw new Error(\"Sheet not found\");\n }\n\n // Remove the sheet\n workbook.sheets.delete(sheetName);\n\n // Clean up indexes for this sheet\n const key = this.getSheetIndexKey(workbookName, sheetName);\n this.sheetIndexes.delete(key);\n\n return sheet;\n }\n\n renameSheet({\n workbookName,\n sheetName,\n newSheetName,\n }: {\n workbookName: string;\n sheetName: string;\n newSheetName: string;\n }): Sheet {\n const workbook = this.workbooks.get(workbookName);\n if (!workbook) {\n throw new WorkbookNotFoundError(workbookName);\n }\n const sheet = workbook.sheets.get(sheetName);\n if (!sheet) {\n throw new SheetNotFoundError(sheetName);\n }\n\n if (workbook.sheets.has(newSheetName)) {\n throw new Error(\"Sheet with new name already exists\");\n }\n\n // Update sheet name\n sheet.name = newSheetName;\n\n // Update sheets map\n workbook.sheets.set(newSheetName, sheet);\n workbook.sheets.delete(sheetName);\n\n // Move indexes to new key\n const oldKey = this.getSheetIndexKey(workbookName, sheetName);\n const newKey = this.getSheetIndexKey(workbookName, newSheetName);\n const indexes = this.sheetIndexes.get(oldKey);\n if (indexes) {\n this.sheetIndexes.set(newKey, indexes);\n this.sheetIndexes.delete(oldKey);\n }\n\n return sheet;\n }\n\n updateAllFormulas(updateCallback: (formula: string) => string): void {\n const update = (map: Map<string, Sheet>) => {\n map.forEach((sheet) => {\n sheet.content.forEach((cell, key) => {\n if (typeof cell === \"string\" && cell.startsWith(\"=\")) {\n const formula = cell.slice(1);\n const updatedFormula = updateCallback(formula);\n\n // Only update if the formula actually changed\n if (updatedFormula !== formula) {\n sheet.content.set(key, `=${updatedFormula}`);\n }\n }\n });\n });\n };\n\n this.workbooks.forEach((workbook) => {\n update(workbook.sheets);\n });\n }\n\n getSheetSerialized({\n workbookName,\n sheetName,\n }: {\n workbookName: string;\n sheetName: string;\n }): Map<string, SerializedCellValue> {\n const workbook = this.workbooks.get(workbookName);\n if (!workbook) {\n throw new WorkbookNotFoundError(workbookName);\n }\n const sheet = workbook.sheets.get(sheetName);\n if (!sheet) {\n throw new SheetNotFoundError(sheetName);\n }\n\n return sheet.content;\n }\n\n /**\n * Add a cell to the grouped indexes\n */\n private addCellToGroups(\n indexes: SheetIndexes,\n rowIndex: number,\n colIndex: number,\n key: string\n ): void {\n // Add to row group (cells in this row, sorted by column)\n let rowGroup = indexes.rowGroups.get(rowIndex);\n if (!rowGroup) {\n rowGroup = [];\n indexes.rowGroups.set(rowIndex, rowGroup);\n }\n const colEntry: IndexEntry = { number: colIndex, key };\n const colInsertIdx = this.findInsertIndex(rowGroup, colIndex);\n rowGroup.splice(colInsertIdx, 0, colEntry);\n\n // Add to column group (cells in this column, sorted by row)\n let colGroup = indexes.colGroups.get(colIndex);\n if (!colGroup) {\n colGroup = [];\n indexes.colGroups.set(colIndex, colGroup);\n }\n const rowEntry: IndexEntry = { number: rowIndex, key };\n const rowInsertIdx = this.findInsertIndex(colGroup, rowIndex);\n colGroup.splice(rowInsertIdx, 0, rowEntry);\n\n // Add to sorted flat indexes\n this.insertSorted(indexes.cellsSortedByRow, { number: rowIndex, key });\n this.insertSorted(indexes.cellsSortedByCol, { number: colIndex, key });\n }\n\n /**\n * Remove a cell from the grouped indexes\n */\n private removeCellFromGroups(\n indexes: SheetIndexes,\n rowIndex: number,\n colIndex: number,\n key: string\n ): void {\n // Remove from row group\n const rowGroup = indexes.rowGroups.get(rowIndex);\n if (rowGroup) {\n const filteredGroup = rowGroup.filter((e) => e.key !== key);\n if (filteredGroup.length === 0) {\n indexes.rowGroups.delete(rowIndex);\n } else {\n indexes.rowGroups.set(rowIndex, filteredGroup);\n }\n }\n\n // Remove from column group\n const colGroup = indexes.colGroups.get(colIndex);\n if (colGroup) {\n const filteredGroup = colGroup.filter((e) => e.key !== key);\n if (filteredGroup.length === 0) {\n indexes.colGroups.delete(colIndex);\n } else {\n indexes.colGroups.set(colIndex, filteredGroup);\n }\n }\n\n // Remove from sorted flat indexes\n indexes.cellsSortedByRow = indexes.cellsSortedByRow.filter(\n (item) => item.key !== key\n );\n indexes.cellsSortedByCol = indexes.cellsSortedByCol.filter(\n (item) => item.key !== key\n );\n }\n\n /**\n * Find insertion index in sorted array\n */\n private findInsertIndex(entries: IndexEntry[], n: number): number {\n return IndexEntryBinarySearch.findInsertionPoint(entries, n);\n }\n\n /**\n * Inserts an item into a sorted array by number, maintaining sort order.\n * If an item with the same number and key already exists, it won't be added again.\n */\n private insertSorted(array: IndexEntry[], item: IndexEntry): void {\n // Check if item already exists (same number and key)\n const existingIndex = array.findIndex(\n (existing) => existing.number === item.number && existing.key === item.key\n );\n\n if (existingIndex !== -1) {\n // Item already exists, no need to add it again\n return;\n }\n\n // Find the insertion point using binary search for efficiency\n const insertionPoint = IndexEntryBinarySearch.findInsertionPoint(\n array,\n item.number\n );\n\n // Insert at the found position\n array.splice(insertionPoint, 0, item);\n }\n\n setCellContent(\n address: CellAddress,\n content: SerializedCellValue,\n options?: {\n /**\n * for extra performance, if the sheet is already known, it can be passed in\n */\n sheet?: Sheet;\n /**\n * if the sheet is being built from scratch, we can skip some checks\n */\n buildingFromScratch?: boolean;\n }\n ): void {\n const sheet =\n options?.sheet ||\n this.getSheet({\n sheetName: address.sheetName,\n workbookName: address.workbookName,\n });\n\n if (!sheet) {\n throw new SheetNotFoundError(address.sheetName);\n }\n\n const indexes = this.getSheetIndexes({\n workbookName: address.workbookName,\n sheetName: address.sheetName,\n });\n const adr = getCellReference(address);\n\n if (this.isContentEmpty(content)) {\n if (!options?.buildingFromScratch) {\n sheet.content.delete(adr);\n // Remove from all indexes\n this.removeCellFromGroups(\n indexes,\n address.rowIndex,\n address.colIndex,\n adr\n );\n }\n } else {\n sheet.content.set(adr, content);\n // Add to all indexes\n this.addCellToGroups(indexes, address.rowIndex, address.colIndex, adr);\n }\n }\n\n /**\n * Replace all content for a sheet (safely, without breaking references)\n * This method clears the existing Map and repopulates it rather than replacing the Map reference\n */\n setSheetContent(\n opts: { sheetName: string; workbookName: string },\n newContent: Map<string, SerializedCellValue>\n ): void {\n const sheet = this.getSheet(opts);\n if (!sheet) {\n throw new SheetNotFoundError(opts.sheetName);\n }\n\n // Clear existing content without breaking the Map reference\n sheet.content.clear();\n\n // Clean up indexes for this sheet\n const key = this.getSheetIndexKey(opts.workbookName, opts.sheetName);\n this.sheetIndexes.delete(key);\n\n // Repopulate with new content\n newContent.forEach((value, key) => {\n this.setCellContent(\n {\n workbookName: opts.workbookName,\n sheetName: opts.sheetName,\n colIndex: parseCellReference(key).colIndex,\n rowIndex: parseCellReference(key).rowIndex,\n },\n value,\n {\n sheet,\n buildingFromScratch: true,\n }\n );\n });\n }\n\n /**\n * Removes the content in the spreadsheet that is inside the range.\n * OPTIMIZED: Uses indexes to only process cells that actually exist.\n * ENHANCED: Now supports infinite ranges.\n */\n clearSpreadsheetRange(address: RangeAddress) {\n const sheet = this.getSheet(address);\n\n if (!sheet) {\n throw new SheetNotFoundError(address.sheetName);\n }\n\n // Get current sheet content and prepare new content with cleared cells\n const newContent = new Map(sheet.content);\n\n // Use iterateCellsInRange to only process cells that actually exist\n // This handles both finite and infinite ranges efficiently\n for (const cellAddress of this.iterateCellsInRange(address)) {\n const cellRef = getCellReference(cellAddress);\n\n // Remove from content\n newContent.delete(cellRef);\n }\n\n // setSheetContent will rebuild indexes from scratch, so no need to manually update them\n this.setSheetContent(address, newContent);\n }\n\n /**\n * Optimized generator to iterate over cells defined in the content within a range\n * Uses indexes to efficiently find and yield only cells that exist within the range\n */\n *iterateCellsInRange(address: RangeAddress): Generator<CellAddress> {\n // First check if the sheet exists\n const sheet = this.getSheet(address);\n if (!sheet) {\n throw new SheetNotFoundError(address.sheetName);\n }\n\n const indexes = this.getSheetIndexes(address);\n\n const range = address.range;\n\n // Use the sorted index to find only rows that actually contain cells\n // This avoids iterating through empty rows regardless of finite/infinite bounds\n\n if (range.end.row.type === \"number\") {\n // Finite bounds: Use binary search to find the range of cells to check\n const startIndex = IndexEntryBinarySearch.findFirstGreaterOrEqual(\n indexes.cellsSortedByRow,\n range.start.row\n );\n\n if (startIndex === -1) return; // No cells at or after start row\n\n // Process cells from startIndex until we exceed the end row\n for (let i = startIndex; i < indexes.cellsSortedByRow.length; i++) {\n const cellEntry = indexes.cellsSortedByRow[i];\n if (!cellEntry) continue;\n\n const parsed = parseCellReference(cellEntry.key);\n\n // Stop if we've gone beyond the row range\n if (parsed.rowIndex > range.end.row.value) break;\n\n // Check if cell is within column bounds\n if (parsed.colIndex < range.start.col) continue;\n\n if (\n range.end.col.type === \"number\" &&\n parsed.colIndex > range.end.col.value\n ) {\n continue; // Skip this cell but keep checking others in different rows\n }\n\n yield {\n rowIndex: parsed.rowIndex,\n colIndex: parsed.colIndex,\n sheetName: address.sheetName,\n workbookName: address.workbookName,\n };\n }\n } else {\n // Infinite row bounds: Use binary search to find starting point\n const startIndex = IndexEntryBinarySearch.findFirstGreaterOrEqual(\n indexes.cellsSortedByRow,\n range.start.row\n );\n\n if (startIndex === -1) return; // No cells at or after start row\n\n // Process all cells from startIndex to end\n for (let i = startIndex; i < indexes.cellsSortedByRow.length; i++) {\n const cellEntry = indexes.cellsSortedByRow[i];\n if (!cellEntry) continue;\n\n const parsed = parseCellReference(cellEntry.key);\n\n // Check if cell is within column bounds\n if (parsed.colIndex < range.start.col) continue;\n\n if (\n range.end.col.type === \"number\" &&\n parsed.colIndex > range.end.col.value\n ) {\n continue; // Skip this cell but keep checking others in different rows\n }\n\n yield {\n rowIndex: parsed.rowIndex,\n colIndex: parsed.colIndex,\n sheetName: address.sheetName,\n workbookName: address.workbookName,\n };\n }\n }\n }\n\n getCellsInRange(address: RangeAddress): CellAddress[] {\n return Array.from(this.iterateCellsInRange(address));\n }\n\n private getCellContent(cellAddress: CellAddress): SerializedCellValue {\n const sheet = this.getSheet(cellAddress);\n if (!sheet) {\n throw new SheetNotFoundError(cellAddress.sheetName);\n }\n return sheet.content.get(getCellReference(cellAddress));\n }\n\n public getSerializedCellValue(cellAddress: CellAddress): SerializedCellValue {\n const sheet = this.getSheet(cellAddress);\n if (!sheet) {\n throw new SheetNotFoundError(cellAddress.sheetName);\n }\n return normalizeSerializedCellValue(\n sheet.content.get(getCellReference(cellAddress))\n );\n }\n\n public isCellEmpty(cellAddress: CellAddress): boolean {\n const content = this.getCellContent(cellAddress);\n return (\n content === undefined || (typeof content === \"string\" && content === \"\")\n );\n }\n public isFormulaCell(cellAddress: CellAddress): boolean {\n const content = this.getCellContent(cellAddress);\n return typeof content === \"string\" && content.startsWith(\"=\");\n }\n\n /**\n * Build evaluation order for a range\n * Delegates to the buildRangeEvalOrder function\n */\n public buildRangeEvalOrder(\n lookupOrder: \"row-major\" | \"col-major\",\n lookupRange: RangeAddress\n ) {\n // Import and call the function\n return buildRangeEvalOrder.call(this, lookupOrder, lookupRange);\n }\n}\n"
|
|
5
|
+
"import {\n FormulaError,\n type CellAddress,\n type FiniteSpreadsheetRange,\n type LocalCellAddress,\n type SerializedCellValue,\n type Sheet,\n type SpreadsheetRange,\n type Workbook,\n} from \"../types.mjs\";\nimport { getCellReference, parseCellReference } from \"../utils.mjs\";\n\nimport type { RangeAddress } from \"../types.mjs\";\nimport { buildRangeEvalOrder } from \"./range-eval-order-builder.mjs\";\nimport {\n EvaluationError,\n SheetNotFoundError,\n WorkbookNotFoundError,\n} from \"../../evaluator/evaluation-error.mjs\";\nimport { normalizeSerializedCellValue } from \"../../parser/formatter.mjs\";\n\ninterface IndexEntry {\n number: number;\n key: string;\n}\n\nexport interface SheetIndexes {\n // lookup maps - cells grouped by row/column\n rowGroups: Map<number, IndexEntry[]>; // row number -> cells in that row (sorted by col)\n colGroups: Map<number, IndexEntry[]>; // col number -> cells in that col (sorted by row)\n\n // Sorted flat indexes - for finding cells before a given row/col\n cellsSortedByRow: IndexEntry[];\n cellsSortedByCol: IndexEntry[];\n}\n\n/**\n * Utility class for binary search operations on IndexEntry arrays\n */\nexport class IndexEntryBinarySearch {\n /**\n * Find the insertion point for a number in a sorted IndexEntry array\n * Returns the index where the number should be inserted to maintain sort order\n */\n static findInsertionPoint(entries: IndexEntry[], target: number): number {\n let left = 0;\n let right = entries.length;\n\n while (left < right) {\n const mid = Math.floor((left + right) / 2);\n const midEntry = entries[mid];\n if (midEntry && midEntry.number < target) {\n left = mid + 1;\n } else {\n right = mid;\n }\n }\n\n return left;\n }\n\n /**\n * Find the first element >= target\n * Returns the index of the first element, or -1 if not found\n */\n static findFirstGreaterOrEqual(\n entries: IndexEntry[],\n target: number\n ): number {\n if (entries.length === 0) return -1;\n\n let left = 0;\n let right = entries.length - 1;\n let result = -1;\n\n while (left <= right) {\n const mid = Math.floor((left + right) / 2);\n const midEntry = entries[mid];\n if (midEntry && midEntry.number >= target) {\n result = mid;\n right = mid - 1;\n } else {\n left = mid + 1;\n }\n }\n\n return result;\n }\n\n /**\n * Find the rightmost position where we could insert a target value\n * Useful for finding elements that come before a target\n */\n static findRightmostInsertionPoint(\n entries: IndexEntry[],\n target: number\n ): number {\n return IndexEntryBinarySearch.findInsertionPoint(entries, target);\n }\n}\n\nexport class WorkbookManager {\n private workbooks: Map<string, Workbook> = new Map();\n\n // Map from \"workbookName|sheetName\" to indexes\n private sheetIndexes: Map<string, SheetIndexes> = new Map();\n\n /**\n * Generate a key for the sheet indexes map\n */\n private getSheetIndexKey(workbookName: string, sheetName: string): string {\n return `${workbookName}|${sheetName}`;\n }\n\n /**\n * Get or create indexes for a sheet\n */\n public getSheetIndexes(opts: {\n workbookName: string;\n sheetName: string;\n }): SheetIndexes {\n const key = this.getSheetIndexKey(opts.workbookName, opts.sheetName);\n let indexes = this.sheetIndexes.get(key);\n\n if (!indexes) {\n indexes = {\n rowGroups: new Map(),\n colGroups: new Map(),\n cellsSortedByRow: [],\n cellsSortedByCol: [],\n };\n this.sheetIndexes.set(key, indexes);\n }\n\n return indexes;\n }\n\n getSheets(workbookName: string): Map<string, Sheet> {\n const workbook = this.workbooks.get(workbookName);\n if (!workbook) {\n throw new WorkbookNotFoundError(workbookName);\n }\n return workbook.sheets;\n }\n\n getWorkbooks(): Map<string, Workbook> {\n return this.workbooks;\n }\n\n addWorkbook(workbookName: string): void {\n if (this.workbooks.has(workbookName)) {\n throw new Error(\"Workbook already exists\");\n }\n this.workbooks.set(workbookName, {\n name: workbookName,\n sheets: new Map(),\n workbookMetadata: undefined,\n });\n }\n\n removeWorkbook(workbookName: string): void {\n const workbook = this.workbooks.get(workbookName);\n if (!workbook) {\n throw new WorkbookNotFoundError(workbookName);\n }\n\n // Clean up indexes for all sheets in this workbook\n for (const sheetName of workbook.sheets.keys()) {\n const key = this.getSheetIndexKey(workbookName, sheetName);\n this.sheetIndexes.delete(key);\n }\n\n this.workbooks.delete(workbookName);\n }\n\n isContentEmpty(content: SerializedCellValue): boolean {\n return content === \"\" || content === undefined;\n }\n\n renameWorkbook(opts: {\n workbookName: string;\n newWorkbookName: string;\n }): void {\n const workbook = this.workbooks.get(opts.workbookName);\n if (!workbook) {\n throw new Error(\"Workbook not found\");\n }\n\n // Update indexes for all sheets in this workbook\n for (const sheetName of workbook.sheets.keys()) {\n const oldKey = this.getSheetIndexKey(opts.workbookName, sheetName);\n const newKey = this.getSheetIndexKey(opts.newWorkbookName, sheetName);\n const indexes = this.sheetIndexes.get(oldKey);\n if (indexes) {\n this.sheetIndexes.set(newKey, indexes);\n this.sheetIndexes.delete(oldKey);\n }\n }\n\n this.workbooks.set(opts.newWorkbookName, workbook);\n this.workbooks.delete(opts.workbookName);\n workbook.name = opts.newWorkbookName;\n }\n\n resetWorkbooks(workbooks: Map<string, Workbook>): void {\n this.workbooks.clear();\n this.sheetIndexes.clear();\n\n workbooks.forEach((workbook, workbookName) => {\n this.workbooks.set(workbookName, workbook);\n workbook.sheets.forEach((sheet) => {\n // Initialize indexes for this sheet\n const indexes = this.getSheetIndexes({\n workbookName,\n sheetName: sheet.name,\n });\n indexes.rowGroups.clear();\n indexes.colGroups.clear();\n indexes.cellsSortedByRow = [];\n indexes.cellsSortedByCol = [];\n\n sheet.content.forEach((value, key) => {\n this.setCellContent(\n {\n workbookName,\n sheetName: sheet.name,\n colIndex: parseCellReference(key).colIndex,\n rowIndex: parseCellReference(key).rowIndex,\n },\n value,\n {\n sheet,\n buildingFromScratch: true,\n }\n );\n });\n });\n });\n }\n\n getSheet({\n workbookName,\n sheetName,\n }: {\n workbookName: string;\n sheetName: string;\n }): Sheet | undefined {\n const workbook = this.workbooks.get(workbookName);\n const sheet = workbook?.sheets.get(sheetName);\n return sheet;\n }\n\n addSheet({\n workbookName,\n sheetName,\n }: {\n workbookName: string;\n sheetName: string;\n }): Sheet {\n const workbook = this.workbooks.get(workbookName);\n if (!workbook) {\n throw new WorkbookNotFoundError(workbookName);\n }\n const sheet = {\n name: sheetName,\n index: workbook.sheets.size,\n content: new Map(),\n metadata: new Map(),\n sheetMetadata: undefined,\n };\n\n if (workbook.sheets.has(sheet.name)) {\n throw new Error(\"Sheet already exists\");\n }\n\n workbook.sheets.set(sheetName, sheet);\n\n // Initialize empty indexes for this sheet\n this.getSheetIndexes({ workbookName, sheetName });\n\n return sheet;\n }\n\n removeSheet({\n workbookName,\n sheetName,\n }: {\n workbookName: string;\n sheetName: string;\n }): Sheet {\n const workbook = this.workbooks.get(workbookName);\n if (!workbook) {\n throw new WorkbookNotFoundError(workbookName);\n }\n const sheet = workbook.sheets.get(sheetName);\n if (!sheet) {\n throw new Error(\"Sheet not found\");\n }\n\n // Remove the sheet\n workbook.sheets.delete(sheetName);\n\n // Clean up indexes for this sheet\n const key = this.getSheetIndexKey(workbookName, sheetName);\n this.sheetIndexes.delete(key);\n\n return sheet;\n }\n\n renameSheet({\n workbookName,\n sheetName,\n newSheetName,\n }: {\n workbookName: string;\n sheetName: string;\n newSheetName: string;\n }): Sheet {\n const workbook = this.workbooks.get(workbookName);\n if (!workbook) {\n throw new WorkbookNotFoundError(workbookName);\n }\n const sheet = workbook.sheets.get(sheetName);\n if (!sheet) {\n throw new SheetNotFoundError(sheetName);\n }\n\n if (workbook.sheets.has(newSheetName)) {\n throw new Error(\"Sheet with new name already exists\");\n }\n\n // Update sheet name\n sheet.name = newSheetName;\n\n // Update sheets map\n workbook.sheets.set(newSheetName, sheet);\n workbook.sheets.delete(sheetName);\n\n // Move indexes to new key\n const oldKey = this.getSheetIndexKey(workbookName, sheetName);\n const newKey = this.getSheetIndexKey(workbookName, newSheetName);\n const indexes = this.sheetIndexes.get(oldKey);\n if (indexes) {\n this.sheetIndexes.set(newKey, indexes);\n this.sheetIndexes.delete(oldKey);\n }\n\n return sheet;\n }\n\n updateAllFormulas(updateCallback: (formula: string) => string): void {\n const update = (map: Map<string, Sheet>) => {\n map.forEach((sheet) => {\n sheet.content.forEach((cell, key) => {\n if (typeof cell === \"string\" && cell.startsWith(\"=\")) {\n const formula = cell.slice(1);\n const updatedFormula = updateCallback(formula);\n\n // Only update if the formula actually changed\n if (updatedFormula !== formula) {\n sheet.content.set(key, `=${updatedFormula}`);\n }\n }\n });\n });\n };\n\n this.workbooks.forEach((workbook) => {\n update(workbook.sheets);\n });\n }\n\n updateFormulasExcluding(\n excludeCellsSet: Set<string>,\n updateCallback: (formula: string) => string\n ): void {\n this.workbooks.forEach((workbook, workbookName) => {\n workbook.sheets.forEach((sheet, sheetName) => {\n sheet.content.forEach((cell, key) => {\n if (typeof cell === \"string\" && cell.startsWith(\"=\")) {\n const { colIndex, rowIndex } = parseCellReference(key);\n const cellKey = `${workbookName}:${sheetName}:${colIndex}:${rowIndex}`;\n \n // Skip if this cell is in the exclude set\n if (excludeCellsSet.has(cellKey)) {\n return;\n }\n\n const formula = cell.slice(1);\n const updatedFormula = updateCallback(formula);\n\n // Only update if the formula actually changed\n if (updatedFormula !== formula) {\n sheet.content.set(key, `=${updatedFormula}`);\n }\n }\n });\n });\n });\n }\n\n updateFormulasForWorkbook(\n workbookName: string,\n updateCallback: (formula: string) => string\n ): void {\n const workbook = this.workbooks.get(workbookName);\n if (!workbook) {\n throw new WorkbookNotFoundError(workbookName);\n }\n\n workbook.sheets.forEach((sheet) => {\n sheet.content.forEach((cell, key) => {\n if (typeof cell === \"string\" && cell.startsWith(\"=\")) {\n const formula = cell.slice(1);\n const updatedFormula = updateCallback(formula);\n\n // Only update if the formula actually changed\n if (updatedFormula !== formula) {\n sheet.content.set(key, `=${updatedFormula}`);\n }\n }\n });\n });\n }\n\n getSheetSerialized({\n workbookName,\n sheetName,\n }: {\n workbookName: string;\n sheetName: string;\n }): Map<string, SerializedCellValue> {\n const workbook = this.workbooks.get(workbookName);\n if (!workbook) {\n throw new WorkbookNotFoundError(workbookName);\n }\n const sheet = workbook.sheets.get(sheetName);\n if (!sheet) {\n throw new SheetNotFoundError(sheetName);\n }\n\n return sheet.content;\n }\n\n /**\n * Add a cell to the grouped indexes\n */\n private addCellToGroups(\n indexes: SheetIndexes,\n rowIndex: number,\n colIndex: number,\n key: string\n ): void {\n // Add to row group (cells in this row, sorted by column)\n let rowGroup = indexes.rowGroups.get(rowIndex);\n if (!rowGroup) {\n rowGroup = [];\n indexes.rowGroups.set(rowIndex, rowGroup);\n }\n const colEntry: IndexEntry = { number: colIndex, key };\n const colInsertIdx = this.findInsertIndex(rowGroup, colIndex);\n rowGroup.splice(colInsertIdx, 0, colEntry);\n\n // Add to column group (cells in this column, sorted by row)\n let colGroup = indexes.colGroups.get(colIndex);\n if (!colGroup) {\n colGroup = [];\n indexes.colGroups.set(colIndex, colGroup);\n }\n const rowEntry: IndexEntry = { number: rowIndex, key };\n const rowInsertIdx = this.findInsertIndex(colGroup, rowIndex);\n colGroup.splice(rowInsertIdx, 0, rowEntry);\n\n // Add to sorted flat indexes\n this.insertSorted(indexes.cellsSortedByRow, { number: rowIndex, key });\n this.insertSorted(indexes.cellsSortedByCol, { number: colIndex, key });\n }\n\n /**\n * Remove a cell from the grouped indexes\n */\n private removeCellFromGroups(\n indexes: SheetIndexes,\n rowIndex: number,\n colIndex: number,\n key: string\n ): void {\n // Remove from row group\n const rowGroup = indexes.rowGroups.get(rowIndex);\n if (rowGroup) {\n const filteredGroup = rowGroup.filter((e) => e.key !== key);\n if (filteredGroup.length === 0) {\n indexes.rowGroups.delete(rowIndex);\n } else {\n indexes.rowGroups.set(rowIndex, filteredGroup);\n }\n }\n\n // Remove from column group\n const colGroup = indexes.colGroups.get(colIndex);\n if (colGroup) {\n const filteredGroup = colGroup.filter((e) => e.key !== key);\n if (filteredGroup.length === 0) {\n indexes.colGroups.delete(colIndex);\n } else {\n indexes.colGroups.set(colIndex, filteredGroup);\n }\n }\n\n // Remove from sorted flat indexes\n indexes.cellsSortedByRow = indexes.cellsSortedByRow.filter(\n (item) => item.key !== key\n );\n indexes.cellsSortedByCol = indexes.cellsSortedByCol.filter(\n (item) => item.key !== key\n );\n }\n\n /**\n * Find insertion index in sorted array\n */\n private findInsertIndex(entries: IndexEntry[], n: number): number {\n return IndexEntryBinarySearch.findInsertionPoint(entries, n);\n }\n\n /**\n * Inserts an item into a sorted array by number, maintaining sort order.\n * If an item with the same number and key already exists, it won't be added again.\n */\n private insertSorted(array: IndexEntry[], item: IndexEntry): void {\n // Check if item already exists (same number and key)\n const existingIndex = array.findIndex(\n (existing) => existing.number === item.number && existing.key === item.key\n );\n\n if (existingIndex !== -1) {\n // Item already exists, no need to add it again\n return;\n }\n\n // Find the insertion point using binary search for efficiency\n const insertionPoint = IndexEntryBinarySearch.findInsertionPoint(\n array,\n item.number\n );\n\n // Insert at the found position\n array.splice(insertionPoint, 0, item);\n }\n\n setCellContent(\n address: CellAddress,\n content: SerializedCellValue,\n options?: {\n /**\n * for extra performance, if the sheet is already known, it can be passed in\n */\n sheet?: Sheet;\n /**\n * if the sheet is being built from scratch, we can skip some checks\n */\n buildingFromScratch?: boolean;\n }\n ): void {\n const sheet =\n options?.sheet ||\n this.getSheet({\n sheetName: address.sheetName,\n workbookName: address.workbookName,\n });\n\n if (!sheet) {\n throw new SheetNotFoundError(address.sheetName);\n }\n\n const indexes = this.getSheetIndexes({\n workbookName: address.workbookName,\n sheetName: address.sheetName,\n });\n const adr = getCellReference(address);\n\n if (this.isContentEmpty(content)) {\n if (!options?.buildingFromScratch) {\n sheet.content.delete(adr);\n // Remove from all indexes\n this.removeCellFromGroups(\n indexes,\n address.rowIndex,\n address.colIndex,\n adr\n );\n }\n } else {\n sheet.content.set(adr, content);\n // Add to all indexes\n this.addCellToGroups(indexes, address.rowIndex, address.colIndex, adr);\n }\n }\n\n /**\n * Set metadata for a cell\n */\n setCellMetadata<TMetadata = unknown>(address: CellAddress, metadata: TMetadata | undefined): void {\n const sheet = this.getSheet({\n workbookName: address.workbookName,\n sheetName: address.sheetName,\n });\n if (!sheet) {\n throw new SheetNotFoundError(address.sheetName);\n }\n\n const key = getCellReference(address);\n if (metadata === undefined) {\n sheet.metadata.delete(key);\n } else {\n sheet.metadata.set(key, metadata);\n }\n }\n\n /**\n * Get metadata for a cell\n */\n getCellMetadata<TMetadata = unknown>(address: CellAddress): TMetadata | undefined {\n const sheet = this.getSheet({\n workbookName: address.workbookName,\n sheetName: address.sheetName,\n });\n if (!sheet) {\n return undefined;\n }\n\n const key = getCellReference(address);\n return sheet.metadata.get(key) as TMetadata | undefined;\n }\n\n /**\n * Get all metadata for a sheet\n */\n getSheetMetadataSerialized<TMetadata = unknown>(opts: {\n sheetName: string;\n workbookName: string;\n }): Map<string, TMetadata> {\n const sheet = this.getSheet(opts);\n return sheet?.metadata || new Map();\n }\n\n /**\n * Set metadata for a sheet\n */\n setSheetMetadata<TSheetMetadata = unknown>(\n opts: { workbookName: string; sheetName: string },\n metadata: TSheetMetadata\n ): void {\n const sheet = this.getSheet(opts);\n if (!sheet) {\n throw new SheetNotFoundError(opts.sheetName);\n }\n sheet.sheetMetadata = metadata;\n }\n\n /**\n * Get metadata for a sheet\n */\n getSheetMetadata<TSheetMetadata = unknown>(\n opts: { workbookName: string; sheetName: string }\n ): TSheetMetadata | undefined {\n const sheet = this.getSheet(opts);\n if (!sheet) {\n return undefined;\n }\n return sheet.sheetMetadata as TSheetMetadata | undefined;\n }\n\n /**\n * Set metadata for a workbook\n */\n setWorkbookMetadata<TWorkbookMetadata = unknown>(\n workbookName: string,\n metadata: TWorkbookMetadata\n ): void {\n const workbook = this.workbooks.get(workbookName);\n if (!workbook) {\n throw new Error(`Workbook \"${workbookName}\" not found`);\n }\n workbook.workbookMetadata = metadata;\n }\n\n /**\n * Get metadata for a workbook\n */\n getWorkbookMetadata<TWorkbookMetadata = unknown>(\n workbookName: string\n ): TWorkbookMetadata | undefined {\n const workbook = this.workbooks.get(workbookName);\n if (!workbook) {\n return undefined;\n }\n return workbook.workbookMetadata as TWorkbookMetadata | undefined;\n }\n\n /**\n * Replace all content for a sheet (safely, without breaking references)\n * This method clears the existing Map and repopulates it rather than replacing the Map reference\n */\n setSheetContent(\n opts: { sheetName: string; workbookName: string },\n newContent: Map<string, SerializedCellValue>\n ): void {\n const sheet = this.getSheet(opts);\n if (!sheet) {\n throw new SheetNotFoundError(opts.sheetName);\n }\n\n // Clear existing content without breaking the Map reference\n sheet.content.clear();\n\n // Clean up indexes for this sheet\n const key = this.getSheetIndexKey(opts.workbookName, opts.sheetName);\n this.sheetIndexes.delete(key);\n\n // Repopulate with new content\n newContent.forEach((value, key) => {\n this.setCellContent(\n {\n workbookName: opts.workbookName,\n sheetName: opts.sheetName,\n colIndex: parseCellReference(key).colIndex,\n rowIndex: parseCellReference(key).rowIndex,\n },\n value,\n {\n sheet,\n buildingFromScratch: true,\n }\n );\n });\n }\n\n /**\n * Removes the content in the spreadsheet that is inside the range.\n * OPTIMIZED: Uses indexes to only process cells that actually exist.\n * ENHANCED: Now supports infinite ranges.\n */\n clearSpreadsheetRange(address: RangeAddress) {\n const sheet = this.getSheet(address);\n\n if (!sheet) {\n throw new SheetNotFoundError(address.sheetName);\n }\n\n // Get current sheet content and prepare new content with cleared cells\n const newContent = new Map(sheet.content);\n const newMetadata = new Map(sheet.metadata);\n\n // Use iterateCellsInRange to only process cells that actually exist\n // This handles both finite and infinite ranges efficiently\n for (const cellAddress of this.iterateCellsInRange(address)) {\n const cellRef = getCellReference(cellAddress);\n\n // Remove from content and metadata\n newContent.delete(cellRef);\n newMetadata.delete(cellRef);\n }\n\n // Update content\n this.setSheetContent(address, newContent);\n \n // Update metadata\n sheet.metadata = newMetadata;\n }\n\n /**\n * Optimized generator to iterate over cells defined in the content within a range\n * Uses indexes to efficiently find and yield only cells that exist within the range\n */\n *iterateCellsInRange(address: RangeAddress): Generator<CellAddress> {\n // First check if the sheet exists\n const sheet = this.getSheet(address);\n if (!sheet) {\n throw new SheetNotFoundError(address.sheetName);\n }\n\n const indexes = this.getSheetIndexes(address);\n\n const range = address.range;\n\n // Use the sorted index to find only rows that actually contain cells\n // This avoids iterating through empty rows regardless of finite/infinite bounds\n\n if (range.end.row.type === \"number\") {\n // Finite bounds: Use binary search to find the range of cells to check\n const startIndex = IndexEntryBinarySearch.findFirstGreaterOrEqual(\n indexes.cellsSortedByRow,\n range.start.row\n );\n\n if (startIndex === -1) return; // No cells at or after start row\n\n // Process cells from startIndex until we exceed the end row\n for (let i = startIndex; i < indexes.cellsSortedByRow.length; i++) {\n const cellEntry = indexes.cellsSortedByRow[i];\n if (!cellEntry) continue;\n\n const parsed = parseCellReference(cellEntry.key);\n\n // Stop if we've gone beyond the row range\n if (parsed.rowIndex > range.end.row.value) break;\n\n // Check if cell is within column bounds\n if (parsed.colIndex < range.start.col) continue;\n\n if (\n range.end.col.type === \"number\" &&\n parsed.colIndex > range.end.col.value\n ) {\n continue; // Skip this cell but keep checking others in different rows\n }\n\n yield {\n rowIndex: parsed.rowIndex,\n colIndex: parsed.colIndex,\n sheetName: address.sheetName,\n workbookName: address.workbookName,\n };\n }\n } else {\n // Infinite row bounds: Use binary search to find starting point\n const startIndex = IndexEntryBinarySearch.findFirstGreaterOrEqual(\n indexes.cellsSortedByRow,\n range.start.row\n );\n\n if (startIndex === -1) return; // No cells at or after start row\n\n // Process all cells from startIndex to end\n for (let i = startIndex; i < indexes.cellsSortedByRow.length; i++) {\n const cellEntry = indexes.cellsSortedByRow[i];\n if (!cellEntry) continue;\n\n const parsed = parseCellReference(cellEntry.key);\n\n // Check if cell is within column bounds\n if (parsed.colIndex < range.start.col) continue;\n\n if (\n range.end.col.type === \"number\" &&\n parsed.colIndex > range.end.col.value\n ) {\n continue; // Skip this cell but keep checking others in different rows\n }\n\n yield {\n rowIndex: parsed.rowIndex,\n colIndex: parsed.colIndex,\n sheetName: address.sheetName,\n workbookName: address.workbookName,\n };\n }\n }\n }\n\n getCellsInRange(address: RangeAddress): CellAddress[] {\n return Array.from(this.iterateCellsInRange(address));\n }\n\n public getCellContent(cellAddress: CellAddress): SerializedCellValue {\n const sheet = this.getSheet(cellAddress);\n if (!sheet) {\n throw new SheetNotFoundError(cellAddress.sheetName);\n }\n return sheet.content.get(getCellReference(cellAddress));\n }\n\n public getSerializedCellValue(cellAddress: CellAddress): SerializedCellValue {\n const sheet = this.getSheet(cellAddress);\n if (!sheet) {\n throw new SheetNotFoundError(cellAddress.sheetName);\n }\n return normalizeSerializedCellValue(\n sheet.content.get(getCellReference(cellAddress))\n );\n }\n\n public isCellEmpty(cellAddress: CellAddress): boolean {\n const content = this.getCellContent(cellAddress);\n return (\n content === undefined || (typeof content === \"string\" && content === \"\")\n );\n }\n public isFormulaCell(cellAddress: CellAddress): boolean {\n const content = this.getCellContent(cellAddress);\n return typeof content === \"string\" && content.startsWith(\"=\");\n }\n\n /**\n * Build evaluation order for a range\n * Delegates to the buildRangeEvalOrder function\n */\n public buildRangeEvalOrder(\n lookupOrder: \"row-major\" | \"col-major\",\n lookupRange: RangeAddress\n ) {\n // Import and call the function\n return buildRangeEvalOrder.call(this, lookupOrder, lookupRange);\n }\n}\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": "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",
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "495D50D4550C2C5B64756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/core/types.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"/**\n * Core type definitions for FormulaEngine\n * This file contains all fundamental types used throughout the engine\n */\n\nimport type { EvaluationContext } from \"../evaluator/evaluation-context.mjs\";\nimport type { FormulaEvaluator } from \"../evaluator/formula-evaluator.mjs\";\nimport type { FunctionNode } from \"../parser/ast.mjs\";\nimport type { DependencyNode } from \"./managers/dependency-node.mjs\";\nimport type { LookupOrder } from \"./managers/range-eval-order-builder.mjs\";\n\n// Cell addressing types\nexport interface CellAddress {\n sheetName: string;\n workbookName: string;\n colIndex: number;\n rowIndex: number;\n}\n\nexport interface RangeAddress {\n sheetName: string;\n workbookName: string;\n range: SpreadsheetRange;\n}\n\nexport interface LocalCellAddress {\n colIndex: number;\n rowIndex: number;\n}\n\nexport type ArethmeticEvaluator = (\n left: CellValue,\n right: CellValue,\n context: EvaluationContext\n) => CellValue | ErrorEvaluationResult;\n\nexport type PositiveInfinity = {\n type: \"infinity\";\n sign: \"positive\";\n};\n\nexport type CellInfinity = {\n type: \"infinity\";\n sign: \"positive\" | \"negative\";\n};\n\nexport type CellNumber = {\n type: \"number\";\n value: number;\n};\n\nexport type SpreadsheetRangeEnd = CellNumber | PositiveInfinity;\n\nexport type SpreadsheetRange = {\n start: {\n col: number;\n row: number;\n };\n end: {\n col: SpreadsheetRangeEnd;\n row: SpreadsheetRangeEnd;\n };\n};\n\nexport type RelativeRange = {\n start: {\n col: number;\n row: number;\n };\n width: SpreadsheetRangeEnd;\n height: SpreadsheetRangeEnd;\n};\n\nexport type FiniteSpreadsheetRange = {\n start: {\n col: number;\n row: number;\n };\n end: {\n col: number;\n row: number;\n };\n};\n\nexport type CellString = {\n type: \"string\";\n value: string;\n};\n\nexport type CellBoolean = {\n type: \"boolean\";\n value: boolean;\n};\n\n// Cell value types\nexport type CellValue = CellNumber | CellString | CellBoolean | CellInfinity;\n/**\n * undefined and \"\" are considered empty values\n * undefineds are converted to \"\" in the engine\n *\n * any empty values are deleted from the sheet content\n */\nexport type SerializedCellValue = string | number | boolean | undefined;\n\n// Named expressions\nexport interface NamedExpression {\n name: string;\n expression: string;\n}\n\nexport interface TableDefinition {\n name: string;\n start: {\n rowIndex: number;\n colIndex: number;\n };\n headers: Map<string, { name: string; index: number }>;\n endRow: SpreadsheetRangeEnd;\n sheetName: string;\n workbookName: string;\n}\n\n// Formula errors\nexport enum FormulaError {\n DIV0 = \"#DIV/0!\",\n NA = \"#N/A\",\n NAME = \"#NAME?\",\n NUM = \"#NUM!\",\n REF = \"#REF!\",\n VALUE = \"#VALUE!\",\n CYCLE = \"#CYCLE!\",\n ERROR = \"#ERROR!\",\n SPILL = \"#SPILL!\",\n}\n\n// Sheet structure\nexport interface Sheet {\n name: string;\n index: number; // 0-based index of the sheet\n content: Map<string, SerializedCellValue>;\n}\n\nexport interface Workbook {\n name: string;\n sheets: Map<string, Sheet>;\n}\n\nexport type ValueEvaluationResult = {\n type: \"value\";\n result: CellValue;\n /**\n * If the terminating evaluation result is a reference (see evaluateReference)\n * then we store information about the source cell for context dependent functions like CELL\n */\n sourceCell?: CellAddress;\n};\n\nexport type AwaitingEvaluationResult = {\n type: \"awaiting-evaluation\";\n waitingFor: DependencyNode;\n errAddress: DependencyNode;\n /**\n * If the terminating evaluation result is a reference (see evaluateReference)\n * then we store information about the source cell for context dependent functions like CELL\n */\n sourceCell?: CellAddress;\n};\n\nexport type DoesNotSpillResult = {\n type: \"does-not-spill\";\n};\n\nexport type ErrorEvaluationResult =\n | {\n type: \"error\";\n err: FormulaError;\n errAddress: DependencyNode;\n message: string;\n /**\n * If the terminating evaluation result is a reference (see evaluateReference)\n * then we store information about the source cell for context dependent functions like CELL\n */\n sourceCell?: CellAddress;\n }\n | AwaitingEvaluationResult;\n\nexport type SingleEvaluationResult =\n | ValueEvaluationResult\n | ErrorEvaluationResult;\n\nexport type SpilledValuesEvaluator = (\n spillOffset: { x: number; y: number },\n context: EvaluationContext\n) => SingleEvaluationResult;\n\nexport type SpilledValuesEvaluationResult = {\n type: \"spilled-values\";\n\n /**\n * When a raw range is evaluated, we will add it to the sourceRange so it can be used e.g. for context dependent functions\n */\n sourceRange?: RangeAddress;\n\n /**\n * If the terminating evaluation result is a reference (see evaluateReference)\n * then we store information about the source cell for context dependent functions like CELL\n * sourceCell will only be defined on a spilledValue when a single value is looked up,\n */\n sourceCell?: CellAddress;\n\n spillArea: (origin: CellAddress) => SpreadsheetRange;\n /**\n * for debugging we add a source string to denote where the spilled values were created\n */\n source: string;\n evaluate: SpilledValuesEvaluator;\n /**\n * evaluateAllCells evaluates all non-empty cells in the spilled range.\n * Because a spilled range can be open-ended, we need to have logic for which cells we should evaluate.\n * e.g. when evaluating a range such as D:D only the cells in the current sheet residing in\n * column D should be evaluated and cells producing spilled values that spill onto D:D.\n *\n * In order to evaluate spilled cells in D:D the range evaluateAllCells need to get all cells in the\n * the intersection of the spilled range and D:D, for that reason evaluateAllCells gets an intersection parameter,\n * where the intersection is relative to the origin.\n *\n * #### Producers:\n * In e.g. SEQUENCE and evaluateRange we have logic for which cells in a spilled range we should evaluate,\n *\n * #### Nesting:\n * e.g. evaluation of scalar operators where we want to nest e.g. `5 * right.evaluate()`\n * can be implemented by calling\n * ```ts\n * const vals = child.evaluateAllCells.call(this, options);\n * return vals.map(val => ({ ...val, result: 5 * val.result }));\n * ```\n *\n * #### Consumers:\n * Only functions that need access to all spilled values in a range end up calling evaluateAllCells, e.g.\n * SUM, MIN, MAX, MATCH. Other types of functions like INDEX doesn't need to evaluate all cells in a range,\n * but does a lookup into a spilled range using the evaluate method.\n *\n */\n evaluateAllCells: (\n this: FormulaEvaluator,\n options: {\n /**\n * an intersection relative to the origin\n */\n intersection?: SpreadsheetRange;\n evaluate: SpilledValuesEvaluator;\n context: EvaluationContext;\n /**\n * origin is the cell address that the spilled range is spilled from\n * e.g. in A3=B2:B4 the origin is A3\n */\n origin: CellAddress;\n\n lookupOrder: LookupOrder;\n }\n ) => EvaluateAllCellsResult;\n};\n\nexport type EvaluateAllCellsResult =\n | ErrorEvaluationResult\n | {\n type: \"values\";\n values: CellInRangeResult[];\n };\n\nexport type CellInRangeResult = {\n result: SingleEvaluationResult;\n relativePos: { x: number; y: number };\n};\n\nexport type FunctionEvaluationResult =\n | SingleEvaluationResult\n | SpilledValuesEvaluationResult;\n\nexport type SpilledValue = {\n /**\n * spillOnto is the range that the spilled value is spilled onto\n */\n spillOnto: SpreadsheetRange;\n /**\n * origin is the cell address that the spilled value is spilled from\n */\n origin: CellAddress;\n};\n\n/**\n * Function definition\n */\nexport interface FunctionDefinition {\n name: string;\n evaluate: (\n this: FormulaEvaluator,\n node: FunctionNode,\n context: EvaluationContext\n ) => FunctionEvaluationResult;\n aliases?: string[];\n}\n\n/**\n * Evaluation result\n */\nexport type EvaluationResult = {\n dependencies: Set<string>;\n} & FunctionEvaluationResult;\n\nexport type SCC = {\n id: number;\n nodes: Set<DependencyNode>; // All nodes considering soft + hard edges\n evaluationOrder: DependencyNode[]; // Flat topologically ordered list\n resolved: boolean;\n hardEdgeSCCs: Set<DependencyNode>[]; // SCCs formed by only hard edges (regular dependencies)\n};\n\nexport type SCCDAG = {\n sccList: SCC[];\n sccGraph: Map<number, Set<number>>; // Adjacency list of SCC dependencies\n};\n\nexport type EvaluationOrder = {\n evaluationOrder: Set<DependencyNode>;\n hasCycle: boolean;\n cycleNodes?: Set<DependencyNode>;\n hash: string;\n sccDAG?: SCCDAG;\n};\n\n// Conditional Styling types\nexport interface LCHColor {\n l: number; // Lightness: 0-100\n c: number; // Chroma: 0-150+\n h: number; // Hue: 0-360\n}\n\nexport interface FormulaStyleCondition {\n type: \"formula\";\n formula: string;\n color: LCHColor;\n}\n\nexport interface GradientStyleCondition {\n type: \"gradient\";\n min:\n | { type: \"lowest_value\"; color: LCHColor }\n | { type: \"number\"; color: LCHColor; valueFormula: string };\n max:\n | { type: \"highest_value\"; color: LCHColor }\n | { type: \"number\"; color: LCHColor; valueFormula: string };\n}\n\nexport type StyleCondition = FormulaStyleCondition | GradientStyleCondition;\n\nexport interface ConditionalStyle {\n area: RangeAddress;\n condition: StyleCondition;\n}\n\nexport interface DirectCellStyle {\n area: RangeAddress;\n style: CellStyle\n}\n\nexport interface CellStyle {\n backgroundColor?: string; // Hex color format\n color?: string; // Text color in hex format\n fontSize?: number; // Font size in pixels\n bold?: boolean;\n italic?: boolean;\n underline?: boolean;\n}\n\nexport interface CopyCellsOptions {\n cut: boolean;\n /**\n * all: Copy everything from the source to the target\n * content: Copy only the content from the source to the target\n * style: Copy only the style from the source to the target\n */\n target: 'all' | 'content' | 'style';\n /**\n * The type of the content to copy\n * value: Copy the value from the source to the target,\n * e.g. if the cell has the formula =123 + 123 then the value is 246\n * formula: Copy the formula from the source to the target,\n * e.g. if the cell has the formula =123 + 123 then the formula is =123 + 123 is copied\n */\n type: \"value\" | \"formula\";\n}\n"
|
|
5
|
+
"/**\n * Core type definitions for FormulaEngine\n * This file contains all fundamental types used throughout the engine\n */\n\nimport type { EvaluationContext } from \"../evaluator/evaluation-context.mjs\";\nimport type { FormulaEvaluator } from \"../evaluator/formula-evaluator.mjs\";\nimport type { FunctionNode } from \"../parser/ast.mjs\";\nimport type { DependencyNode } from \"./managers/dependency-node.mjs\";\nimport type { LookupOrder } from \"./managers/range-eval-order-builder.mjs\";\n\n// Cell addressing types\nexport interface CellAddress {\n sheetName: string;\n workbookName: string;\n colIndex: number;\n rowIndex: number;\n}\n\nexport interface RangeAddress {\n sheetName: string;\n workbookName: string;\n range: SpreadsheetRange;\n}\n\nexport interface LocalCellAddress {\n colIndex: number;\n rowIndex: number;\n}\n\nexport type ArethmeticEvaluator = (\n left: CellValue,\n right: CellValue,\n context: EvaluationContext\n) => CellValue | ErrorEvaluationResult;\n\nexport type PositiveInfinity = {\n type: \"infinity\";\n sign: \"positive\";\n};\n\nexport type CellInfinity = {\n type: \"infinity\";\n sign: \"positive\" | \"negative\";\n};\n\nexport type CellNumber = {\n type: \"number\";\n value: number;\n};\n\nexport type SpreadsheetRangeEnd = CellNumber | PositiveInfinity;\n\nexport type SpreadsheetRange = {\n start: {\n col: number;\n row: number;\n };\n end: {\n col: SpreadsheetRangeEnd;\n row: SpreadsheetRangeEnd;\n };\n};\n\nexport type RelativeRange = {\n start: {\n col: number;\n row: number;\n };\n width: SpreadsheetRangeEnd;\n height: SpreadsheetRangeEnd;\n};\n\nexport type FiniteSpreadsheetRange = {\n start: {\n col: number;\n row: number;\n };\n end: {\n col: number;\n row: number;\n };\n};\n\nexport type CellString = {\n type: \"string\";\n value: string;\n};\n\nexport type CellBoolean = {\n type: \"boolean\";\n value: boolean;\n};\n\n// Cell value types\nexport type CellValue = CellNumber | CellString | CellBoolean | CellInfinity;\n/**\n * undefined and \"\" are considered empty values\n * undefineds are converted to \"\" in the engine\n *\n * any empty values are deleted from the sheet content\n */\nexport type SerializedCellValue = string | number | boolean | undefined;\n\n\n// Named expressions\nexport interface NamedExpression {\n name: string;\n expression: string;\n}\n\nexport interface TableDefinition {\n name: string;\n start: {\n rowIndex: number;\n colIndex: number;\n };\n headers: Map<string, { name: string; index: number }>;\n endRow: SpreadsheetRangeEnd;\n sheetName: string;\n workbookName: string;\n}\n\n// Formula errors\nexport enum FormulaError {\n DIV0 = \"#DIV/0!\",\n NA = \"#N/A\",\n NAME = \"#NAME?\",\n NUM = \"#NUM!\",\n REF = \"#REF!\",\n VALUE = \"#VALUE!\",\n CYCLE = \"#CYCLE!\",\n ERROR = \"#ERROR!\",\n SPILL = \"#SPILL!\",\n}\n\n// Sheet structure\nexport interface Sheet<TCellMetadata = unknown, TSheetMetadata = unknown> {\n name: string;\n index: number; // 0-based index of the sheet\n content: Map<string, SerializedCellValue>;\n /**\n * Cell metadata - arbitrary consumer-defined data per cell\n * Examples: rich text content, links, comments, custom app data\n * The engine stores and copies this data but doesn't interpret it\n * Keyed by cell reference (e.g., \"A1\")\n */\n metadata: Map<string, TCellMetadata>;\n /**\n * Sheet-level metadata - arbitrary consumer-defined data for the entire sheet\n * Examples: text boxes, drawings, frozen panes, print settings\n * The engine stores and copies this data but doesn't interpret it\n */\n sheetMetadata: TSheetMetadata;\n}\n\nexport interface Workbook<TCellMetadata = unknown, TSheetMetadata = unknown, TWorkbookMetadata = unknown> {\n name: string;\n sheets: Map<string, Sheet<TCellMetadata, TSheetMetadata>>;\n /**\n * Workbook-level metadata - arbitrary consumer-defined data for the entire workbook\n * Examples: themes, custom ribbons, document properties, workbook settings\n * The engine stores and copies this data but doesn't interpret it\n */\n workbookMetadata: TWorkbookMetadata;\n}\n\n/**\n * Tracked reference - a stable reference to a range that updates automatically\n * when workbooks/sheets are renamed and becomes invalid when they're deleted\n */\nexport interface TrackedReference {\n id: string; // UUID\n address: RangeAddress; // The range being tracked\n isValid: boolean; // False if sheet/workbook deleted\n}\n\nexport type ValueEvaluationResult = {\n type: \"value\";\n result: CellValue;\n /**\n * If the terminating evaluation result is a reference (see evaluateReference)\n * then we store information about the source cell for context dependent functions like CELL\n */\n sourceCell?: CellAddress;\n};\n\nexport type AwaitingEvaluationResult = {\n type: \"awaiting-evaluation\";\n waitingFor: DependencyNode;\n errAddress: DependencyNode;\n /**\n * If the terminating evaluation result is a reference (see evaluateReference)\n * then we store information about the source cell for context dependent functions like CELL\n */\n sourceCell?: CellAddress;\n};\n\nexport type DoesNotSpillResult = {\n type: \"does-not-spill\";\n};\n\nexport type ErrorEvaluationResult =\n | {\n type: \"error\";\n err: FormulaError;\n errAddress: DependencyNode;\n message: string;\n /**\n * If the terminating evaluation result is a reference (see evaluateReference)\n * then we store information about the source cell for context dependent functions like CELL\n */\n sourceCell?: CellAddress;\n }\n | AwaitingEvaluationResult;\n\nexport type SingleEvaluationResult =\n | ValueEvaluationResult\n | ErrorEvaluationResult;\n\nexport type SpilledValuesEvaluator = (\n spillOffset: { x: number; y: number },\n context: EvaluationContext\n) => SingleEvaluationResult;\n\nexport type SpilledValuesEvaluationResult = {\n type: \"spilled-values\";\n\n /**\n * When a raw range is evaluated, we will add it to the sourceRange so it can be used e.g. for context dependent functions\n */\n sourceRange?: RangeAddress;\n\n /**\n * If the terminating evaluation result is a reference (see evaluateReference)\n * then we store information about the source cell for context dependent functions like CELL\n * sourceCell will only be defined on a spilledValue when a single value is looked up,\n */\n sourceCell?: CellAddress;\n\n spillArea: (origin: CellAddress) => SpreadsheetRange;\n /**\n * for debugging we add a source string to denote where the spilled values were created\n */\n source: string;\n evaluate: SpilledValuesEvaluator;\n /**\n * evaluateAllCells evaluates all non-empty cells in the spilled range.\n * Because a spilled range can be open-ended, we need to have logic for which cells we should evaluate.\n * e.g. when evaluating a range such as D:D only the cells in the current sheet residing in\n * column D should be evaluated and cells producing spilled values that spill onto D:D.\n *\n * In order to evaluate spilled cells in D:D the range evaluateAllCells need to get all cells in the\n * the intersection of the spilled range and D:D, for that reason evaluateAllCells gets an intersection parameter,\n * where the intersection is relative to the origin.\n *\n * #### Producers:\n * In e.g. SEQUENCE and evaluateRange we have logic for which cells in a spilled range we should evaluate,\n *\n * #### Nesting:\n * e.g. evaluation of scalar operators where we want to nest e.g. `5 * right.evaluate()`\n * can be implemented by calling\n * ```ts\n * const vals = child.evaluateAllCells.call(this, options);\n * return vals.map(val => ({ ...val, result: 5 * val.result }));\n * ```\n *\n * #### Consumers:\n * Only functions that need access to all spilled values in a range end up calling evaluateAllCells, e.g.\n * SUM, MIN, MAX, MATCH. Other types of functions like INDEX doesn't need to evaluate all cells in a range,\n * but does a lookup into a spilled range using the evaluate method.\n *\n */\n evaluateAllCells: (\n this: FormulaEvaluator,\n options: {\n /**\n * an intersection relative to the origin\n */\n intersection?: SpreadsheetRange;\n evaluate: SpilledValuesEvaluator;\n context: EvaluationContext;\n /**\n * origin is the cell address that the spilled range is spilled from\n * e.g. in A3=B2:B4 the origin is A3\n */\n origin: CellAddress;\n\n lookupOrder: LookupOrder;\n }\n ) => EvaluateAllCellsResult;\n};\n\nexport type EvaluateAllCellsResult =\n | ErrorEvaluationResult\n | {\n type: \"values\";\n values: CellInRangeResult[];\n };\n\nexport type CellInRangeResult = {\n result: SingleEvaluationResult;\n relativePos: { x: number; y: number };\n};\n\nexport type FunctionEvaluationResult =\n | SingleEvaluationResult\n | SpilledValuesEvaluationResult;\n\nexport type SpilledValue = {\n /**\n * spillOnto is the range that the spilled value is spilled onto\n */\n spillOnto: SpreadsheetRange;\n /**\n * origin is the cell address that the spilled value is spilled from\n */\n origin: CellAddress;\n};\n\n/**\n * Function definition\n */\nexport interface FunctionDefinition {\n name: string;\n evaluate: (\n this: FormulaEvaluator,\n node: FunctionNode,\n context: EvaluationContext\n ) => FunctionEvaluationResult;\n aliases?: string[];\n}\n\n/**\n * Evaluation result\n */\nexport type EvaluationResult = {\n dependencies: Set<string>;\n} & FunctionEvaluationResult;\n\nexport type SCC = {\n id: number;\n nodes: Set<DependencyNode>; // All nodes considering soft + hard edges\n evaluationOrder: DependencyNode[]; // Flat topologically ordered list\n resolved: boolean;\n hardEdgeSCCs: Set<DependencyNode>[]; // SCCs formed by only hard edges (regular dependencies)\n};\n\nexport type SCCDAG = {\n sccList: SCC[];\n sccGraph: Map<number, Set<number>>; // Adjacency list of SCC dependencies\n};\n\nexport type EvaluationOrder = {\n evaluationOrder: Set<DependencyNode>;\n hasCycle: boolean;\n cycleNodes?: Set<DependencyNode>;\n hash: string;\n sccDAG?: SCCDAG;\n};\n\n// Conditional Styling types\nexport interface LCHColor {\n l: number; // Lightness: 0-100\n c: number; // Chroma: 0-150+\n h: number; // Hue: 0-360\n}\n\nexport interface FormulaStyleCondition {\n type: \"formula\";\n formula: string;\n color: LCHColor;\n}\n\nexport interface GradientStyleCondition {\n type: \"gradient\";\n min:\n | { type: \"lowest_value\"; color: LCHColor }\n | { type: \"number\"; color: LCHColor; valueFormula: string };\n max:\n | { type: \"highest_value\"; color: LCHColor }\n | { type: \"number\"; color: LCHColor; valueFormula: string };\n}\n\nexport type StyleCondition = FormulaStyleCondition | GradientStyleCondition;\n\nexport interface ConditionalStyle {\n areas: RangeAddress[];\n condition: StyleCondition;\n}\n\nexport interface DirectCellStyle {\n areas: RangeAddress[];\n style: CellStyle\n}\n\nexport interface CellStyle {\n backgroundColor?: string; // Hex color format\n color?: string; // Text color in hex format\n fontSize?: number; // Font size in pixels\n bold?: boolean;\n italic?: boolean;\n underline?: boolean;\n}\n\nexport interface CopyCellsOptions {\n /**\n * Whether this is a cut operation (clears source cells after copying)\n * @default false\n */\n cut?: boolean;\n /**\n * What to include in the copy operation.\n * - Use 'all' as shorthand for ['content', 'style', 'metadata']\n * - Use array for fine-grained control over what to copy:\n * - ['content'] - copy only values/formulas\n * - ['style'] - copy only formatting\n * - ['metadata'] - copy only metadata (rich text, links, etc.)\n * - ['content', 'style'] - copy content and formatting\n * - ['content', 'metadata'] - copy content and metadata\n * - ['style', 'metadata'] - copy formatting and metadata\n * - ['content', 'style', 'metadata'] - same as 'all'\n * @default 'all'\n */\n include?: 'all' | ('content' | 'style' | 'metadata')[];\n /**\n * The type of the content to copy\n * value: Copy the value from the source to the target,\n * e.g. if the cell has the formula =123 + 123 then the value is 246\n * formula: Copy the formula from the source to the target,\n * e.g. if the cell has the formula =123 + 123 then the formula is =123 + 123 is copied\n * @default 'formula'\n */\n type?: \"value\" | \"formula\";\n}\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";
|
|
7
|
+
"mappings": ";AA4HO,IAAK;AAAA,CAAL,CAAK,kBAAL;AAAA,EACL,wBAAO;AAAA,EACP,sBAAK;AAAA,EACL,wBAAO;AAAA,EACP,uBAAM;AAAA,EACN,uBAAM;AAAA,EACN,yBAAQ;AAAA,EACR,yBAAQ;AAAA,EACR,yBAAQ;AAAA,EACR,yBAAQ;AAAA,GATE;",
|
|
8
8
|
"debugId": "0E7C5AF634572D3964756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
package/dist/mjs/package.json
CHANGED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Information about cells being moved
|
|
3
|
+
*/
|
|
4
|
+
export interface MovedCellsInfo {
|
|
5
|
+
/**
|
|
6
|
+
* Set of cell keys in format "workbookName:sheetName:colIndex:rowIndex"
|
|
7
|
+
* for fast O(1) lookup
|
|
8
|
+
*/
|
|
9
|
+
cellsSet: Set<string>;
|
|
10
|
+
/**
|
|
11
|
+
* Workbook name of the source cells (all moved cells must be in same workbook/sheet)
|
|
12
|
+
*/
|
|
13
|
+
workbookName: string;
|
|
14
|
+
/**
|
|
15
|
+
* Sheet name of the source cells
|
|
16
|
+
*/
|
|
17
|
+
sheetName: string;
|
|
18
|
+
/**
|
|
19
|
+
* Row offset for the move (targetRow - sourceRow)
|
|
20
|
+
*/
|
|
21
|
+
rowOffset: number;
|
|
22
|
+
/**
|
|
23
|
+
* Column offset for the move (targetCol - sourceCol)
|
|
24
|
+
*/
|
|
25
|
+
colOffset: number;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Updates cell and range references in a formula when cells are moved
|
|
29
|
+
*
|
|
30
|
+
* @param formula - The formula string (without the leading =)
|
|
31
|
+
* @param movedCells - Information about which cells were moved
|
|
32
|
+
* @returns The updated formula string, or the original if no changes were made
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* // Moving A1 to D5 (offset: col+3, row+4)
|
|
36
|
+
* updateReferencesForMovedCells("A1+B1", {...}) // "D5+B1" (only A1 updated)
|
|
37
|
+
* updateReferencesForMovedCells("SUM(A1:D5)", {...}) // "SUM(E4:H9)" (if entire range moved)
|
|
38
|
+
*/
|
|
39
|
+
export declare function updateReferencesForMovedCells(formula: string, movedCells: MovedCellsInfo): string;
|
|
40
|
+
/**
|
|
41
|
+
* Checks if a formula contains a reference to a specific cell
|
|
42
|
+
*
|
|
43
|
+
* @param formula - The formula string (without the leading =)
|
|
44
|
+
* @param workbookName - The workbook name
|
|
45
|
+
* @param sheetName - The sheet name
|
|
46
|
+
* @param colIndex - The column index
|
|
47
|
+
* @param rowIndex - The row index
|
|
48
|
+
* @returns True if the formula references the cell
|
|
49
|
+
*/
|
|
50
|
+
export declare function formulaReferencesCell(formula: string, workbookName: string, sheetName: string, colIndex: number, rowIndex: number): boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Checks if a formula contains a reference to a specific range
|
|
53
|
+
*
|
|
54
|
+
* @param formula - The formula string (without the leading =)
|
|
55
|
+
* @param workbookName - The workbook name
|
|
56
|
+
* @param sheetName - The sheet name
|
|
57
|
+
* @param startCol - Range start column
|
|
58
|
+
* @param startRow - Range start row
|
|
59
|
+
* @param endCol - Range end column
|
|
60
|
+
* @param endRow - Range end row
|
|
61
|
+
* @returns True if the formula references the range
|
|
62
|
+
*/
|
|
63
|
+
export declare function formulaReferencesRange(formula: string, workbookName: string, sheetName: string, startCol: number, startRow: number, endCol: number, endRow: number): boolean;
|