@particle-academy/fancy-sheets 0.7.6 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -308,6 +308,52 @@ declare namespace SheetWorkbook {
308
308
  var displayName: string;
309
309
  }
310
310
 
311
+ type FormulaTokenType = "number" | "string" | "cellRef" | "rangeRef" | "sheetCellRef" | "sheetRangeRef" | "function" | "operator" | "paren" | "comma" | "boolean";
312
+ interface FormulaToken {
313
+ type: FormulaTokenType;
314
+ value: string;
315
+ position: number;
316
+ }
317
+ type FormulaASTNode = {
318
+ type: "number";
319
+ value: number;
320
+ } | {
321
+ type: "string";
322
+ value: string;
323
+ } | {
324
+ type: "boolean";
325
+ value: boolean;
326
+ } | {
327
+ type: "cellRef";
328
+ address: string;
329
+ } | {
330
+ type: "rangeRef";
331
+ start: string;
332
+ end: string;
333
+ } | {
334
+ type: "sheetCellRef";
335
+ sheet: string;
336
+ address: string;
337
+ } | {
338
+ type: "sheetRangeRef";
339
+ sheet: string;
340
+ start: string;
341
+ end: string;
342
+ } | {
343
+ type: "functionCall";
344
+ name: string;
345
+ args: FormulaASTNode[];
346
+ } | {
347
+ type: "binaryOp";
348
+ operator: string;
349
+ left: FormulaASTNode;
350
+ right: FormulaASTNode;
351
+ } | {
352
+ type: "unaryOp";
353
+ operator: string;
354
+ operand: FormulaASTNode;
355
+ };
356
+
311
357
  /** Convert 0-based column index to letter(s): 0="A", 25="Z", 26="AA" */
312
358
  declare function columnToLetter(col: number): string;
313
359
  /** Convert column letter(s) to 0-based index: "A"=0, "Z"=25, "AA"=26 */
@@ -332,4 +378,47 @@ declare function workbookToCSV(workbook: WorkbookData, sheetId?: string): string
332
378
  type FormulaRangeFunction = (args: CellValue[][]) => CellValue;
333
379
  declare function registerFunction(name: string, fn: FormulaRangeFunction): void;
334
380
 
335
- export { type CellAddress, type CellComment, type CellData, type CellFormat, type CellHighlight, type CellHighlightMap, type CellMap, type CellRange, type CellValue, type ColumnWidths, type FormulaRangeFunction, type MergedRegion, type SelectionState, Sheet, type SheetData, type SheetProps, SheetWorkbook, type SheetWorkbookProps, Spreadsheet, type SpreadsheetContextMenuItem, type SpreadsheetContextValue, type SpreadsheetProps, type TextAlign, type ToolbarButton, type WorkbookData, columnToLetter, createEmptySheet, createEmptyWorkbook, csvToWorkbook, letterToColumn, parseAddress, parseCSV, registerFunction, stringifyCSV, toAddress, useSpreadsheet, workbookToCSV };
381
+ /**
382
+ * Recalculate every formula cell in a workbook, resolving cross-sheet
383
+ * references. Pure — no React, no DOM — so it runs headless in Node for SSR,
384
+ * snapshots, export pipelines, and tests. Returns a new workbook with each
385
+ * formula cell's `computedValue` populated.
386
+ */
387
+ declare function recalculateWorkbook(workbook: WorkbookData): WorkbookData;
388
+ /**
389
+ * Recalculate all formula cells in a single sheet, with optional cross-sheet
390
+ * reference support when `allSheets` is supplied. Pure.
391
+ */
392
+ declare function recalculateSheet(sheet: SheetData, allSheets?: SheetData[]): SheetData;
393
+
394
+ declare function lexFormula(input: string): FormulaToken[];
395
+
396
+ /**
397
+ * Recursive descent parser for spreadsheet formulas.
398
+ * Operator precedence (low to high):
399
+ * 1. Comparison: =, <>, <, >, <=, >=
400
+ * 2. String concatenation: &
401
+ * 3. Addition/subtraction: +, -
402
+ * 4. Multiplication/division: *, /
403
+ * 5. Exponentiation: ^
404
+ * 6. Unary: -, +
405
+ * 7. Atoms: number, string, boolean, cellRef, rangeRef, function call, (expr)
406
+ */
407
+ declare function parseFormula(tokens: FormulaToken[]): FormulaASTNode;
408
+
409
+ type CellValueGetter = (address: string) => CellValue;
410
+ type RangeValueGetter = (start: string, end: string) => CellValue[];
411
+ type SheetCellValueGetter = (sheetName: string, address: string) => CellValue;
412
+ type SheetRangeValueGetter = (sheetName: string, start: string, end: string) => CellValue[];
413
+ interface EvaluatorContext {
414
+ getCellValue: CellValueGetter;
415
+ getRangeValues: RangeValueGetter;
416
+ getSheetCellValue?: SheetCellValueGetter;
417
+ getSheetRangeValues?: SheetRangeValueGetter;
418
+ }
419
+ declare function evaluateAST(node: FormulaASTNode, getCellValue: CellValueGetter, getRangeValues: RangeValueGetter, ctx?: {
420
+ getSheetCellValue?: SheetCellValueGetter;
421
+ getSheetRangeValues?: SheetRangeValueGetter;
422
+ }): CellValue;
423
+
424
+ export { type CellAddress, type CellComment, type CellData, type CellFormat, type CellHighlight, type CellHighlightMap, type CellMap, type CellRange, type CellValue, type CellValueGetter, type ColumnWidths, type EvaluatorContext, type FormulaASTNode, type FormulaRangeFunction, type FormulaToken, type FormulaTokenType, type MergedRegion, type RangeValueGetter, type SelectionState, Sheet, type SheetCellValueGetter, type SheetData, type SheetProps, type SheetRangeValueGetter, SheetWorkbook, type SheetWorkbookProps, Spreadsheet, type SpreadsheetContextMenuItem, type SpreadsheetContextValue, type SpreadsheetProps, type TextAlign, type ToolbarButton, type WorkbookData, columnToLetter, createEmptySheet, createEmptyWorkbook, csvToWorkbook, evaluateAST, letterToColumn, lexFormula, parseAddress, parseCSV, parseFormula, recalculateSheet, recalculateWorkbook, registerFunction, stringifyCSV, toAddress, useSpreadsheet, workbookToCSV };
package/dist/index.d.ts CHANGED
@@ -308,6 +308,52 @@ declare namespace SheetWorkbook {
308
308
  var displayName: string;
309
309
  }
310
310
 
311
+ type FormulaTokenType = "number" | "string" | "cellRef" | "rangeRef" | "sheetCellRef" | "sheetRangeRef" | "function" | "operator" | "paren" | "comma" | "boolean";
312
+ interface FormulaToken {
313
+ type: FormulaTokenType;
314
+ value: string;
315
+ position: number;
316
+ }
317
+ type FormulaASTNode = {
318
+ type: "number";
319
+ value: number;
320
+ } | {
321
+ type: "string";
322
+ value: string;
323
+ } | {
324
+ type: "boolean";
325
+ value: boolean;
326
+ } | {
327
+ type: "cellRef";
328
+ address: string;
329
+ } | {
330
+ type: "rangeRef";
331
+ start: string;
332
+ end: string;
333
+ } | {
334
+ type: "sheetCellRef";
335
+ sheet: string;
336
+ address: string;
337
+ } | {
338
+ type: "sheetRangeRef";
339
+ sheet: string;
340
+ start: string;
341
+ end: string;
342
+ } | {
343
+ type: "functionCall";
344
+ name: string;
345
+ args: FormulaASTNode[];
346
+ } | {
347
+ type: "binaryOp";
348
+ operator: string;
349
+ left: FormulaASTNode;
350
+ right: FormulaASTNode;
351
+ } | {
352
+ type: "unaryOp";
353
+ operator: string;
354
+ operand: FormulaASTNode;
355
+ };
356
+
311
357
  /** Convert 0-based column index to letter(s): 0="A", 25="Z", 26="AA" */
312
358
  declare function columnToLetter(col: number): string;
313
359
  /** Convert column letter(s) to 0-based index: "A"=0, "Z"=25, "AA"=26 */
@@ -332,4 +378,47 @@ declare function workbookToCSV(workbook: WorkbookData, sheetId?: string): string
332
378
  type FormulaRangeFunction = (args: CellValue[][]) => CellValue;
333
379
  declare function registerFunction(name: string, fn: FormulaRangeFunction): void;
334
380
 
335
- export { type CellAddress, type CellComment, type CellData, type CellFormat, type CellHighlight, type CellHighlightMap, type CellMap, type CellRange, type CellValue, type ColumnWidths, type FormulaRangeFunction, type MergedRegion, type SelectionState, Sheet, type SheetData, type SheetProps, SheetWorkbook, type SheetWorkbookProps, Spreadsheet, type SpreadsheetContextMenuItem, type SpreadsheetContextValue, type SpreadsheetProps, type TextAlign, type ToolbarButton, type WorkbookData, columnToLetter, createEmptySheet, createEmptyWorkbook, csvToWorkbook, letterToColumn, parseAddress, parseCSV, registerFunction, stringifyCSV, toAddress, useSpreadsheet, workbookToCSV };
381
+ /**
382
+ * Recalculate every formula cell in a workbook, resolving cross-sheet
383
+ * references. Pure — no React, no DOM — so it runs headless in Node for SSR,
384
+ * snapshots, export pipelines, and tests. Returns a new workbook with each
385
+ * formula cell's `computedValue` populated.
386
+ */
387
+ declare function recalculateWorkbook(workbook: WorkbookData): WorkbookData;
388
+ /**
389
+ * Recalculate all formula cells in a single sheet, with optional cross-sheet
390
+ * reference support when `allSheets` is supplied. Pure.
391
+ */
392
+ declare function recalculateSheet(sheet: SheetData, allSheets?: SheetData[]): SheetData;
393
+
394
+ declare function lexFormula(input: string): FormulaToken[];
395
+
396
+ /**
397
+ * Recursive descent parser for spreadsheet formulas.
398
+ * Operator precedence (low to high):
399
+ * 1. Comparison: =, <>, <, >, <=, >=
400
+ * 2. String concatenation: &
401
+ * 3. Addition/subtraction: +, -
402
+ * 4. Multiplication/division: *, /
403
+ * 5. Exponentiation: ^
404
+ * 6. Unary: -, +
405
+ * 7. Atoms: number, string, boolean, cellRef, rangeRef, function call, (expr)
406
+ */
407
+ declare function parseFormula(tokens: FormulaToken[]): FormulaASTNode;
408
+
409
+ type CellValueGetter = (address: string) => CellValue;
410
+ type RangeValueGetter = (start: string, end: string) => CellValue[];
411
+ type SheetCellValueGetter = (sheetName: string, address: string) => CellValue;
412
+ type SheetRangeValueGetter = (sheetName: string, start: string, end: string) => CellValue[];
413
+ interface EvaluatorContext {
414
+ getCellValue: CellValueGetter;
415
+ getRangeValues: RangeValueGetter;
416
+ getSheetCellValue?: SheetCellValueGetter;
417
+ getSheetRangeValues?: SheetRangeValueGetter;
418
+ }
419
+ declare function evaluateAST(node: FormulaASTNode, getCellValue: CellValueGetter, getRangeValues: RangeValueGetter, ctx?: {
420
+ getSheetCellValue?: SheetCellValueGetter;
421
+ getSheetRangeValues?: SheetRangeValueGetter;
422
+ }): CellValue;
423
+
424
+ export { type CellAddress, type CellComment, type CellData, type CellFormat, type CellHighlight, type CellHighlightMap, type CellMap, type CellRange, type CellValue, type CellValueGetter, type ColumnWidths, type EvaluatorContext, type FormulaASTNode, type FormulaRangeFunction, type FormulaToken, type FormulaTokenType, type MergedRegion, type RangeValueGetter, type SelectionState, Sheet, type SheetCellValueGetter, type SheetData, type SheetProps, type SheetRangeValueGetter, SheetWorkbook, type SheetWorkbookProps, Spreadsheet, type SpreadsheetContextMenuItem, type SpreadsheetContextValue, type SpreadsheetProps, type TextAlign, type ToolbarButton, type WorkbookData, columnToLetter, createEmptySheet, createEmptyWorkbook, csvToWorkbook, evaluateAST, letterToColumn, lexFormula, parseAddress, parseCSV, parseFormula, recalculateSheet, recalculateWorkbook, registerFunction, stringifyCSV, toAddress, useSpreadsheet, workbookToCSV };
package/dist/index.js CHANGED
@@ -1249,7 +1249,7 @@ function getRecalculationOrder(graph) {
1249
1249
  return order;
1250
1250
  }
1251
1251
 
1252
- // src/hooks/use-spreadsheet-store.ts
1252
+ // src/engine/recalc.ts
1253
1253
  function recalculateWorkbook(workbook) {
1254
1254
  const recalculated = [];
1255
1255
  for (const sheet of workbook.sheets) {
@@ -1261,33 +1261,6 @@ function recalculateWorkbook(workbook) {
1261
1261
  }
1262
1262
  return { ...workbook, sheets: finalSheets };
1263
1263
  }
1264
- function createInitialState(data) {
1265
- const workbook = data ?? createEmptyWorkbook();
1266
- return {
1267
- workbook: recalculateWorkbook(workbook),
1268
- selection: { activeCell: "A1", ranges: [{ start: "A1", end: "A1" }] },
1269
- editingCell: null,
1270
- editValue: "",
1271
- undoStack: [],
1272
- redoStack: []
1273
- };
1274
- }
1275
- function getActiveSheet(state) {
1276
- return state.workbook.sheets.find((s) => s.id === state.workbook.activeSheetId);
1277
- }
1278
- function updateActiveSheet(state, updater) {
1279
- return {
1280
- ...state.workbook,
1281
- sheets: state.workbook.sheets.map(
1282
- (s) => s.id === state.workbook.activeSheetId ? updater(s) : s
1283
- )
1284
- };
1285
- }
1286
- function pushUndo(state) {
1287
- const stack = [...state.undoStack, state.workbook];
1288
- if (stack.length > 50) stack.shift();
1289
- return { undoStack: stack, redoStack: [] };
1290
- }
1291
1264
  function recalculateSheet(sheet, allSheets) {
1292
1265
  const graph = buildDependencyGraph(sheet.cells);
1293
1266
  if (graph.size === 0) return sheet;
@@ -1344,6 +1317,35 @@ function recalculateSheet(sheet, allSheets) {
1344
1317
  }
1345
1318
  return { ...sheet, cells };
1346
1319
  }
1320
+
1321
+ // src/hooks/use-spreadsheet-store.ts
1322
+ function createInitialState(data) {
1323
+ const workbook = data ?? createEmptyWorkbook();
1324
+ return {
1325
+ workbook: recalculateWorkbook(workbook),
1326
+ selection: { activeCell: "A1", ranges: [{ start: "A1", end: "A1" }] },
1327
+ editingCell: null,
1328
+ editValue: "",
1329
+ undoStack: [],
1330
+ redoStack: []
1331
+ };
1332
+ }
1333
+ function getActiveSheet(state) {
1334
+ return state.workbook.sheets.find((s) => s.id === state.workbook.activeSheetId);
1335
+ }
1336
+ function updateActiveSheet(state, updater) {
1337
+ return {
1338
+ ...state.workbook,
1339
+ sheets: state.workbook.sheets.map(
1340
+ (s) => s.id === state.workbook.activeSheetId ? updater(s) : s
1341
+ )
1342
+ };
1343
+ }
1344
+ function pushUndo(state) {
1345
+ const stack = [...state.undoStack, state.workbook];
1346
+ if (stack.length > 50) stack.shift();
1347
+ return { undoStack: stack, redoStack: [] };
1348
+ }
1347
1349
  function getCellDisplayValue(cell) {
1348
1350
  if (!cell) return "";
1349
1351
  if (cell.computedValue !== void 0) return String(cell.computedValue);
@@ -2859,6 +2861,6 @@ function workbookToCSV(workbook, sheetId) {
2859
2861
  return stringifyCSV(data);
2860
2862
  }
2861
2863
 
2862
- export { Sheet, SheetWorkbook, Spreadsheet, columnToLetter, createEmptySheet, createEmptyWorkbook, csvToWorkbook, letterToColumn, parseAddress, parseCSV, registerFunction, stringifyCSV, toAddress, useSpreadsheet, workbookToCSV };
2864
+ export { Sheet, SheetWorkbook, Spreadsheet, columnToLetter, createEmptySheet, createEmptyWorkbook, csvToWorkbook, evaluateAST, letterToColumn, lexFormula, parseAddress, parseCSV, parseFormula, recalculateSheet, recalculateWorkbook, registerFunction, stringifyCSV, toAddress, useSpreadsheet, workbookToCSV };
2863
2865
  //# sourceMappingURL=index.js.map
2864
2866
  //# sourceMappingURL=index.js.map