@bilig/headless 0.1.83 → 0.1.85

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.
Files changed (36) hide show
  1. package/README.md +5 -5
  2. package/dist/change-order.d.ts +1 -1
  3. package/dist/change-order.js +2 -2
  4. package/dist/change-order.js.map +1 -1
  5. package/dist/index.d.ts +2 -2
  6. package/dist/index.js +2 -2
  7. package/dist/index.js.map +1 -1
  8. package/dist/initial-sheet-load.d.ts +2 -2
  9. package/dist/initial-sheet-load.js +9 -9
  10. package/dist/initial-sheet-load.js.map +1 -1
  11. package/dist/matrix-mutation-plan.d.ts +2 -2
  12. package/dist/matrix-mutation-plan.js +6 -7
  13. package/dist/matrix-mutation-plan.js.map +1 -1
  14. package/dist/persistence.d.ts +2 -2
  15. package/dist/persistence.js +66 -77
  16. package/dist/persistence.js.map +1 -1
  17. package/dist/tracked-engine-event-refs.d.ts +2 -2
  18. package/dist/tracked-engine-event-refs.js +2 -4
  19. package/dist/tracked-engine-event-refs.js.map +1 -1
  20. package/dist/work-paper-errors.d.ts +1 -1
  21. package/dist/work-paper-errors.js +36 -38
  22. package/dist/work-paper-errors.js.map +1 -1
  23. package/dist/work-paper-runtime.d.ts +4 -4
  24. package/dist/work-paper-runtime.js +413 -495
  25. package/dist/work-paper-runtime.js.map +1 -1
  26. package/dist/work-paper-scratch-evaluator.d.ts +2 -2
  27. package/dist/work-paper-scratch-evaluator.js +3 -3
  28. package/dist/work-paper-scratch-evaluator.js.map +1 -1
  29. package/dist/work-paper-sheet-replacement.d.ts +1 -1
  30. package/dist/work-paper-sheet-replacement.js +2 -2
  31. package/dist/work-paper-sheet-replacement.js.map +1 -1
  32. package/dist/work-paper-types.d.ts +19 -19
  33. package/dist/work-paper.d.ts +3 -3
  34. package/dist/work-paper.js +3 -3
  35. package/dist/work-paper.js.map +1 -1
  36. package/package.json +4 -4
@@ -1,36 +1,36 @@
1
- import { SpreadsheetEngine, makeCellKey, } from "@bilig/core";
2
- import { ErrorCode, MAX_COLS, MAX_ROWS, ValueTag, } from "@bilig/protocol";
3
- import { excelSerialToDateParts, formatAddress, formatRangeAddress, installExternalFunctionAdapter, isArrayValue, isCellReferenceText, parseCellAddress, parseFormula, parseRangeAddress, serializeFormula, translateFormulaReferences, } from "@bilig/formula";
4
- import { loadInitialMixedSheet, tryLoadInitialLiteralSheet } from "./initial-sheet-load.js";
5
- import { orderWorkPaperCellChanges } from "./change-order.js";
6
- import { WorkPaperConfigValueTooBigError, WorkPaperConfigValueTooSmallError, WorkPaperEvaluationSuspendedError, WorkPaperExpectedValueOfTypeError, WorkPaperOperationError, WorkPaperParseError, WorkPaperSheetError, WorkPaperExpectedOneOfValuesError, WorkPaperFunctionPluginValidationError, WorkPaperInvalidArgumentsError, WorkPaperLanguageAlreadyRegisteredError, WorkPaperLanguageNotRegisteredError, WorkPaperNamedExpressionDoesNotExistError, WorkPaperNamedExpressionNameIsAlreadyTakenError, WorkPaperNamedExpressionNameIsInvalidError, WorkPaperNoOperationToRedoError, WorkPaperNoOperationToUndoError, WorkPaperNoRelativeAddressesAllowedError, WorkPaperNoSheetWithIdError, WorkPaperNoSheetWithNameError, WorkPaperNotAFormulaError, WorkPaperNothingToPasteError, WorkPaperSheetNameAlreadyTakenError, WorkPaperSheetSizeLimitExceededError, WorkPaperUnableToParseError, } from "./work-paper-errors.js";
7
- import { buildMatrixMutationPlan } from "./matrix-mutation-plan.js";
8
- import { captureTrackedEngineEvent } from "./tracked-engine-event-refs.js";
9
- import { calculateWorkPaperFormulaInScratchWorkbook } from "./work-paper-scratch-evaluator.js";
10
- import { replaceWorkPaperSheetContent } from "./work-paper-sheet-replacement.js";
1
+ import { SpreadsheetEngine, makeCellKey } from '@bilig/core';
2
+ import { ErrorCode, MAX_COLS, MAX_ROWS, ValueTag, } from '@bilig/protocol';
3
+ import { excelSerialToDateParts, formatAddress, formatRangeAddress, installExternalFunctionAdapter, isArrayValue, isCellReferenceText, parseCellAddress, parseFormula, parseRangeAddress, serializeFormula, translateFormulaReferences, } from '@bilig/formula';
4
+ import { loadInitialMixedSheet, tryLoadInitialLiteralSheet } from './initial-sheet-load.js';
5
+ import { orderWorkPaperCellChanges } from './change-order.js';
6
+ import { WorkPaperConfigValueTooBigError, WorkPaperConfigValueTooSmallError, WorkPaperEvaluationSuspendedError, WorkPaperExpectedValueOfTypeError, WorkPaperOperationError, WorkPaperParseError, WorkPaperSheetError, WorkPaperExpectedOneOfValuesError, WorkPaperFunctionPluginValidationError, WorkPaperInvalidArgumentsError, WorkPaperLanguageAlreadyRegisteredError, WorkPaperLanguageNotRegisteredError, WorkPaperNamedExpressionDoesNotExistError, WorkPaperNamedExpressionNameIsAlreadyTakenError, WorkPaperNamedExpressionNameIsInvalidError, WorkPaperNoOperationToRedoError, WorkPaperNoOperationToUndoError, WorkPaperNoRelativeAddressesAllowedError, WorkPaperNoSheetWithIdError, WorkPaperNoSheetWithNameError, WorkPaperNotAFormulaError, WorkPaperNothingToPasteError, WorkPaperSheetNameAlreadyTakenError, WorkPaperSheetSizeLimitExceededError, WorkPaperUnableToParseError, } from './work-paper-errors.js';
7
+ import { buildMatrixMutationPlan } from './matrix-mutation-plan.js';
8
+ import { captureTrackedEngineEvent } from './tracked-engine-event-refs.js';
9
+ import { calculateWorkPaperFormulaInScratchWorkbook } from './work-paper-scratch-evaluator.js';
10
+ import { replaceWorkPaperSheetContent } from './work-paper-sheet-replacement.js';
11
11
  const EMPTY_NAMED_EXPRESSION_VALUES = new Map();
12
12
  const VISIBILITY_SHEET_STRIDE = MAX_ROWS * MAX_COLS;
13
13
  const DEFAULT_CONFIG = Object.freeze({
14
14
  accentSensitive: false,
15
15
  caseSensitive: false,
16
- caseFirst: "false",
16
+ caseFirst: 'false',
17
17
  chooseAddressMappingPolicy: undefined,
18
18
  context: undefined,
19
- currencySymbol: ["$"],
19
+ currencySymbol: ['$'],
20
20
  dateFormats: [],
21
- functionArgSeparator: ",",
22
- decimalSeparator: ".",
21
+ functionArgSeparator: ',',
22
+ decimalSeparator: '.',
23
23
  evaluateNullToZero: true,
24
24
  functionPlugins: [],
25
25
  ignorePunctuation: false,
26
- language: "enGB",
27
- ignoreWhiteSpace: "standard",
26
+ language: 'enGB',
27
+ ignoreWhiteSpace: 'standard',
28
28
  leapYear1900: true,
29
- licenseKey: "internal",
30
- localeLang: "en-US",
29
+ licenseKey: 'internal',
30
+ localeLang: 'en-US',
31
31
  matchWholeCell: true,
32
- arrayColumnSeparator: ",",
33
- arrayRowSeparator: ";",
32
+ arrayColumnSeparator: ',',
33
+ arrayRowSeparator: ';',
34
34
  maxRows: MAX_ROWS,
35
35
  maxColumns: MAX_COLS,
36
36
  nullDate: { year: 1899, month: 12, day: 30 },
@@ -41,7 +41,7 @@ const DEFAULT_CONFIG = Object.freeze({
41
41
  stringifyDateTime: undefined,
42
42
  stringifyDuration: undefined,
43
43
  smartRounding: true,
44
- thousandSeparator: ",",
44
+ thousandSeparator: ',',
45
45
  timeFormats: [],
46
46
  useArrayArithmetic: true,
47
47
  useColumnIndex: false,
@@ -51,83 +51,83 @@ const DEFAULT_CONFIG = Object.freeze({
51
51
  useWildcards: true,
52
52
  });
53
53
  const WORKPAPER_CONFIG_KEYS = [
54
- "accentSensitive",
55
- "caseSensitive",
56
- "caseFirst",
57
- "chooseAddressMappingPolicy",
58
- "context",
59
- "currencySymbol",
60
- "dateFormats",
61
- "functionArgSeparator",
62
- "decimalSeparator",
63
- "evaluateNullToZero",
64
- "functionPlugins",
65
- "ignorePunctuation",
66
- "language",
67
- "ignoreWhiteSpace",
68
- "leapYear1900",
69
- "licenseKey",
70
- "localeLang",
71
- "matchWholeCell",
72
- "arrayColumnSeparator",
73
- "arrayRowSeparator",
74
- "maxRows",
75
- "maxColumns",
76
- "nullDate",
77
- "nullYear",
78
- "parseDateTime",
79
- "precisionEpsilon",
80
- "precisionRounding",
81
- "stringifyDateTime",
82
- "stringifyDuration",
83
- "smartRounding",
84
- "thousandSeparator",
85
- "timeFormats",
86
- "useArrayArithmetic",
87
- "useColumnIndex",
88
- "useStats",
89
- "undoLimit",
90
- "useRegularExpressions",
91
- "useWildcards",
54
+ 'accentSensitive',
55
+ 'caseSensitive',
56
+ 'caseFirst',
57
+ 'chooseAddressMappingPolicy',
58
+ 'context',
59
+ 'currencySymbol',
60
+ 'dateFormats',
61
+ 'functionArgSeparator',
62
+ 'decimalSeparator',
63
+ 'evaluateNullToZero',
64
+ 'functionPlugins',
65
+ 'ignorePunctuation',
66
+ 'language',
67
+ 'ignoreWhiteSpace',
68
+ 'leapYear1900',
69
+ 'licenseKey',
70
+ 'localeLang',
71
+ 'matchWholeCell',
72
+ 'arrayColumnSeparator',
73
+ 'arrayRowSeparator',
74
+ 'maxRows',
75
+ 'maxColumns',
76
+ 'nullDate',
77
+ 'nullYear',
78
+ 'parseDateTime',
79
+ 'precisionEpsilon',
80
+ 'precisionRounding',
81
+ 'stringifyDateTime',
82
+ 'stringifyDuration',
83
+ 'smartRounding',
84
+ 'thousandSeparator',
85
+ 'timeFormats',
86
+ 'useArrayArithmetic',
87
+ 'useColumnIndex',
88
+ 'useStats',
89
+ 'undoLimit',
90
+ 'useRegularExpressions',
91
+ 'useWildcards',
92
92
  ];
93
93
  const WORKPAPER_PUBLIC_ERROR_NAMES = new Set([
94
- "WorkPaperConfigValueTooBigError",
95
- "WorkPaperConfigValueTooSmallError",
96
- "WorkPaperEvaluationSuspendedError",
97
- "WorkPaperExpectedOneOfValuesError",
98
- "WorkPaperExpectedValueOfTypeError",
99
- "WorkPaperFunctionPluginValidationError",
100
- "WorkPaperInvalidAddressError",
101
- "WorkPaperInvalidArgumentsError",
102
- "WorkPaperLanguageAlreadyRegisteredError",
103
- "WorkPaperLanguageNotRegisteredError",
104
- "WorkPaperMissingTranslationError",
105
- "WorkPaperNamedExpressionDoesNotExistError",
106
- "WorkPaperNamedExpressionNameIsAlreadyTakenError",
107
- "WorkPaperNamedExpressionNameIsInvalidError",
108
- "WorkPaperNoOperationToRedoError",
109
- "WorkPaperNoOperationToUndoError",
110
- "WorkPaperNoRelativeAddressesAllowedError",
111
- "WorkPaperNoSheetWithIdError",
112
- "WorkPaperNoSheetWithNameError",
113
- "WorkPaperNotAFormulaError",
114
- "WorkPaperNothingToPasteError",
115
- "WorkPaperProtectedFunctionTranslationError",
116
- "WorkPaperSheetNameAlreadyTakenError",
117
- "WorkPaperSheetSizeLimitExceededError",
118
- "WorkPaperSourceLocationHasArrayError",
119
- "WorkPaperTargetLocationHasArrayError",
120
- "WorkPaperUnableToParseError",
121
- "WorkPaperConfigError",
122
- "WorkPaperSheetError",
123
- "WorkPaperNamedExpressionError",
124
- "WorkPaperClipboardError",
125
- "WorkPaperParseError",
126
- "WorkPaperOperationError",
94
+ 'WorkPaperConfigValueTooBigError',
95
+ 'WorkPaperConfigValueTooSmallError',
96
+ 'WorkPaperEvaluationSuspendedError',
97
+ 'WorkPaperExpectedOneOfValuesError',
98
+ 'WorkPaperExpectedValueOfTypeError',
99
+ 'WorkPaperFunctionPluginValidationError',
100
+ 'WorkPaperInvalidAddressError',
101
+ 'WorkPaperInvalidArgumentsError',
102
+ 'WorkPaperLanguageAlreadyRegisteredError',
103
+ 'WorkPaperLanguageNotRegisteredError',
104
+ 'WorkPaperMissingTranslationError',
105
+ 'WorkPaperNamedExpressionDoesNotExistError',
106
+ 'WorkPaperNamedExpressionNameIsAlreadyTakenError',
107
+ 'WorkPaperNamedExpressionNameIsInvalidError',
108
+ 'WorkPaperNoOperationToRedoError',
109
+ 'WorkPaperNoOperationToUndoError',
110
+ 'WorkPaperNoRelativeAddressesAllowedError',
111
+ 'WorkPaperNoSheetWithIdError',
112
+ 'WorkPaperNoSheetWithNameError',
113
+ 'WorkPaperNotAFormulaError',
114
+ 'WorkPaperNothingToPasteError',
115
+ 'WorkPaperProtectedFunctionTranslationError',
116
+ 'WorkPaperSheetNameAlreadyTakenError',
117
+ 'WorkPaperSheetSizeLimitExceededError',
118
+ 'WorkPaperSourceLocationHasArrayError',
119
+ 'WorkPaperTargetLocationHasArrayError',
120
+ 'WorkPaperUnableToParseError',
121
+ 'WorkPaperConfigError',
122
+ 'WorkPaperSheetError',
123
+ 'WorkPaperNamedExpressionError',
124
+ 'WorkPaperClipboardError',
125
+ 'WorkPaperParseError',
126
+ 'WorkPaperOperationError',
127
127
  ]);
128
- const WORKPAPER_VERSION = "0.1.2";
129
- const WORKPAPER_BUILD_DATE = "2026-04-10";
130
- const WORKPAPER_RELEASE_DATE = "2026-04-10";
128
+ const WORKPAPER_VERSION = '0.1.2';
129
+ const WORKPAPER_BUILD_DATE = '2026-04-10';
130
+ const WORKPAPER_RELEASE_DATE = '2026-04-10';
131
131
  const globalCustomFunctions = new Map();
132
132
  let customAdapterInstalled = false;
133
133
  let nextWorkbookId = 1;
@@ -136,14 +136,14 @@ function ensureCustomAdapterInstalled() {
136
136
  return;
137
137
  }
138
138
  installExternalFunctionAdapter({
139
- surface: "host",
139
+ surface: 'host',
140
140
  resolveFunction(name) {
141
141
  const implementation = globalCustomFunctions.get(name.trim().toUpperCase());
142
142
  if (!implementation) {
143
143
  return undefined;
144
144
  }
145
145
  return {
146
- kind: "scalar",
146
+ kind: 'scalar',
147
147
  implementation: (...args) => {
148
148
  const result = implementation(...args);
149
149
  if (!result) {
@@ -159,10 +159,7 @@ function ensureCustomAdapterInstalled() {
159
159
  function clonePluginDefinition(plugin) {
160
160
  return {
161
161
  ...plugin,
162
- implementedFunctions: Object.fromEntries(Object.entries(plugin.implementedFunctions).map(([name, metadata]) => [
163
- name,
164
- { ...metadata },
165
- ])),
162
+ implementedFunctions: Object.fromEntries(Object.entries(plugin.implementedFunctions).map(([name, metadata]) => [name, { ...metadata }])),
166
163
  aliases: plugin.aliases ? { ...plugin.aliases } : undefined,
167
164
  functions: plugin.functions ? { ...plugin.functions } : undefined,
168
165
  };
@@ -170,15 +167,11 @@ function clonePluginDefinition(plugin) {
170
167
  function cloneConfig(config) {
171
168
  return {
172
169
  ...config,
173
- chooseAddressMappingPolicy: config.chooseAddressMappingPolicy
174
- ? { ...config.chooseAddressMappingPolicy }
175
- : undefined,
170
+ chooseAddressMappingPolicy: config.chooseAddressMappingPolicy ? { ...config.chooseAddressMappingPolicy } : undefined,
176
171
  context: config.context !== undefined ? structuredClone(config.context) : undefined,
177
172
  currencySymbol: config.currencySymbol ? [...config.currencySymbol] : undefined,
178
173
  dateFormats: config.dateFormats ? [...config.dateFormats] : undefined,
179
- functionPlugins: config.functionPlugins
180
- ? config.functionPlugins.map((plugin) => clonePluginDefinition(plugin))
181
- : undefined,
174
+ functionPlugins: config.functionPlugins ? config.functionPlugins.map((plugin) => clonePluginDefinition(plugin)) : undefined,
182
175
  nullDate: config.nullDate ? { ...config.nullDate } : undefined,
183
176
  timeFormats: config.timeFormats ? [...config.timeFormats] : undefined,
184
177
  };
@@ -193,10 +186,10 @@ function scalarValueFromLiteral(value) {
193
186
  if (value === null) {
194
187
  return emptyValue();
195
188
  }
196
- if (typeof value === "number") {
189
+ if (typeof value === 'number') {
197
190
  return { tag: ValueTag.Number, value };
198
191
  }
199
- if (typeof value === "boolean") {
192
+ if (typeof value === 'boolean') {
200
193
  return { tag: ValueTag.Boolean, value };
201
194
  }
202
195
  return { tag: ValueTag.String, value, stringId: 0 };
@@ -265,13 +258,13 @@ function normalizeName(name) {
265
258
  return name.trim().toUpperCase();
266
259
  }
267
260
  function makeNamedExpressionKey(name, scope) {
268
- return `${scope ?? "workbook"}:${normalizeName(name)}`;
261
+ return `${scope ?? 'workbook'}:${normalizeName(name)}`;
269
262
  }
270
263
  function makeInternalScopedName(scope, name) {
271
264
  return `__BILIG_WORKPAPER_SCOPE_${scope}_${normalizeName(name)}`;
272
265
  }
273
266
  function isFormulaContent(content) {
274
- return typeof content === "string" && content.trim().startsWith("=");
267
+ return typeof content === 'string' && content.trim().startsWith('=');
275
268
  }
276
269
  function isCellValueMatrix(value) {
277
270
  return Array.isArray(value);
@@ -283,16 +276,13 @@ function matrixContainsFormulaContent(content) {
283
276
  return content.some((row) => row.some((cell) => isFormulaContent(cell)));
284
277
  }
285
278
  function isDeferredBatchLiteralContent(content) {
286
- return (content === null ||
287
- typeof content === "boolean" ||
288
- typeof content === "number" ||
289
- typeof content === "string");
279
+ return content === null || typeof content === 'boolean' || typeof content === 'number' || typeof content === 'string';
290
280
  }
291
281
  function canUseInitialMixedSheetFastPath(content) {
292
- return content.some((row) => row.some((value) => typeof value === "string" && value.trim().startsWith("=")));
282
+ return content.some((row) => row.some((value) => typeof value === 'string' && value.trim().startsWith('=')));
293
283
  }
294
284
  function stripLeadingEquals(formula) {
295
- return formula.trim().startsWith("=") ? formula.trim().slice(1) : formula.trim();
285
+ return formula.trim().startsWith('=') ? formula.trim().slice(1) : formula.trim();
296
286
  }
297
287
  function assertRowAndColumn(value, label) {
298
288
  if (!Number.isInteger(value) || value < 0) {
@@ -300,18 +290,18 @@ function assertRowAndColumn(value, label) {
300
290
  }
301
291
  }
302
292
  function assertRange(range) {
303
- assertRowAndColumn(range.start.sheet, "start.sheet");
304
- assertRowAndColumn(range.start.row, "start.row");
305
- assertRowAndColumn(range.start.col, "start.col");
306
- assertRowAndColumn(range.end.sheet, "end.sheet");
307
- assertRowAndColumn(range.end.row, "end.row");
308
- assertRowAndColumn(range.end.col, "end.col");
293
+ assertRowAndColumn(range.start.sheet, 'start.sheet');
294
+ assertRowAndColumn(range.start.row, 'start.row');
295
+ assertRowAndColumn(range.start.col, 'start.col');
296
+ assertRowAndColumn(range.end.sheet, 'end.sheet');
297
+ assertRowAndColumn(range.end.row, 'end.row');
298
+ assertRowAndColumn(range.end.col, 'end.col');
309
299
  if (range.start.sheet !== range.end.sheet) {
310
- throw new WorkPaperInvalidArgumentsError("Ranges must stay on a single sheet");
300
+ throw new WorkPaperInvalidArgumentsError('Ranges must stay on a single sheet');
311
301
  }
312
302
  }
313
303
  function isCellRange(value) {
314
- return "start" in value && "end" in value;
304
+ return 'start' in value && 'end' in value;
315
305
  }
316
306
  function cloneCellValue(value) {
317
307
  switch (value.tag) {
@@ -332,35 +322,35 @@ function cloneCellValue(value) {
332
322
  function transformFormulaNode(node, transform) {
333
323
  const current = transform(node);
334
324
  switch (current.kind) {
335
- case "BooleanLiteral":
336
- case "CellRef":
337
- case "ColumnRef":
338
- case "ErrorLiteral":
339
- case "NameRef":
340
- case "NumberLiteral":
341
- case "RangeRef":
342
- case "RowRef":
343
- case "SpillRef":
344
- case "StringLiteral":
345
- case "StructuredRef":
325
+ case 'BooleanLiteral':
326
+ case 'CellRef':
327
+ case 'ColumnRef':
328
+ case 'ErrorLiteral':
329
+ case 'NameRef':
330
+ case 'NumberLiteral':
331
+ case 'RangeRef':
332
+ case 'RowRef':
333
+ case 'SpillRef':
334
+ case 'StringLiteral':
335
+ case 'StructuredRef':
346
336
  return current;
347
- case "UnaryExpr":
337
+ case 'UnaryExpr':
348
338
  return {
349
339
  ...current,
350
340
  argument: transformFormulaNode(current.argument, transform),
351
341
  };
352
- case "BinaryExpr":
342
+ case 'BinaryExpr':
353
343
  return {
354
344
  ...current,
355
345
  left: transformFormulaNode(current.left, transform),
356
346
  right: transformFormulaNode(current.right, transform),
357
347
  };
358
- case "CallExpr":
348
+ case 'CallExpr':
359
349
  return {
360
350
  ...current,
361
351
  args: current.args.map((argument) => transformFormulaNode(argument, transform)),
362
352
  };
363
- case "InvokeExpr":
353
+ case 'InvokeExpr':
364
354
  return {
365
355
  ...current,
366
356
  callee: transformFormulaNode(current.callee, transform),
@@ -372,33 +362,33 @@ function transformFormulaNode(node, transform) {
372
362
  }
373
363
  function collectFormulaNameRefs(node, output) {
374
364
  switch (node.kind) {
375
- case "BooleanLiteral":
376
- case "CellRef":
377
- case "ColumnRef":
378
- case "ErrorLiteral":
379
- case "NameRef":
380
- if (node.kind === "NameRef") {
365
+ case 'BooleanLiteral':
366
+ case 'CellRef':
367
+ case 'ColumnRef':
368
+ case 'ErrorLiteral':
369
+ case 'NameRef':
370
+ if (node.kind === 'NameRef') {
381
371
  output.add(node.name);
382
372
  }
383
373
  return;
384
- case "NumberLiteral":
385
- case "RangeRef":
386
- case "RowRef":
387
- case "SpillRef":
388
- case "StringLiteral":
389
- case "StructuredRef":
374
+ case 'NumberLiteral':
375
+ case 'RangeRef':
376
+ case 'RowRef':
377
+ case 'SpillRef':
378
+ case 'StringLiteral':
379
+ case 'StructuredRef':
390
380
  return;
391
- case "UnaryExpr":
381
+ case 'UnaryExpr':
392
382
  collectFormulaNameRefs(node.argument, output);
393
383
  return;
394
- case "BinaryExpr":
384
+ case 'BinaryExpr':
395
385
  collectFormulaNameRefs(node.left, output);
396
386
  collectFormulaNameRefs(node.right, output);
397
387
  return;
398
- case "CallExpr":
388
+ case 'CallExpr':
399
389
  node.args.forEach((argument) => collectFormulaNameRefs(argument, output));
400
390
  return;
401
- case "InvokeExpr":
391
+ case 'InvokeExpr':
402
392
  collectFormulaNameRefs(node.callee, output);
403
393
  node.args.forEach((argument) => collectFormulaNameRefs(argument, output));
404
394
  return;
@@ -417,37 +407,36 @@ function isAbsoluteColumnReference(value) {
417
407
  }
418
408
  function formulaHasRelativeReferences(node) {
419
409
  switch (node.kind) {
420
- case "BooleanLiteral":
421
- case "ErrorLiteral":
422
- case "NameRef":
423
- case "NumberLiteral":
424
- case "StringLiteral":
425
- case "StructuredRef":
410
+ case 'BooleanLiteral':
411
+ case 'ErrorLiteral':
412
+ case 'NameRef':
413
+ case 'NumberLiteral':
414
+ case 'StringLiteral':
415
+ case 'StructuredRef':
426
416
  return false;
427
- case "CellRef":
428
- case "SpillRef":
417
+ case 'CellRef':
418
+ case 'SpillRef':
429
419
  return !isAbsoluteCellReference(node.ref);
430
- case "RowRef":
420
+ case 'RowRef':
431
421
  return !isAbsoluteRowReference(node.ref);
432
- case "ColumnRef":
422
+ case 'ColumnRef':
433
423
  return !isAbsoluteColumnReference(node.ref);
434
- case "RangeRef":
435
- if (node.refKind === "cells") {
424
+ case 'RangeRef':
425
+ if (node.refKind === 'cells') {
436
426
  return !isAbsoluteCellReference(node.start) || !isAbsoluteCellReference(node.end);
437
427
  }
438
- if (node.refKind === "rows") {
428
+ if (node.refKind === 'rows') {
439
429
  return !isAbsoluteRowReference(node.start) || !isAbsoluteRowReference(node.end);
440
430
  }
441
431
  return !isAbsoluteColumnReference(node.start) || !isAbsoluteColumnReference(node.end);
442
- case "UnaryExpr":
432
+ case 'UnaryExpr':
443
433
  return formulaHasRelativeReferences(node.argument);
444
- case "BinaryExpr":
434
+ case 'BinaryExpr':
445
435
  return formulaHasRelativeReferences(node.left) || formulaHasRelativeReferences(node.right);
446
- case "CallExpr":
436
+ case 'CallExpr':
447
437
  return node.args.some((argument) => formulaHasRelativeReferences(argument));
448
- case "InvokeExpr":
449
- return (formulaHasRelativeReferences(node.callee) ||
450
- node.args.some((argument) => formulaHasRelativeReferences(argument)));
438
+ case 'InvokeExpr':
439
+ return formulaHasRelativeReferences(node.callee) || node.args.some((argument) => formulaHasRelativeReferences(argument));
451
440
  default:
452
441
  return false;
453
442
  }
@@ -457,77 +446,62 @@ function compareSheetNames(left, right) {
457
446
  }
458
447
  function checkWorkPaperLicenseKeyValidity(licenseKey) {
459
448
  if (!licenseKey || licenseKey.trim().length === 0) {
460
- return "missing";
449
+ return 'missing';
461
450
  }
462
- if (licenseKey === "internal" ||
463
- licenseKey === "gpl-v3" ||
464
- licenseKey === "internal-use-in-handsontable") {
465
- return "valid";
451
+ if (licenseKey === 'internal' || licenseKey === 'gpl-v3' || licenseKey === 'internal-use-in-handsontable') {
452
+ return 'valid';
466
453
  }
467
- return "invalid";
454
+ return 'invalid';
468
455
  }
469
456
  function validateWorkPaperConfig(config) {
470
457
  if (config.maxRows !== undefined && (!Number.isInteger(config.maxRows) || config.maxRows < 1)) {
471
- throw new WorkPaperConfigValueTooSmallError("maxRows", 1);
458
+ throw new WorkPaperConfigValueTooSmallError('maxRows', 1);
472
459
  }
473
- if (config.maxColumns !== undefined &&
474
- (!Number.isInteger(config.maxColumns) || config.maxColumns < 1)) {
475
- throw new WorkPaperConfigValueTooSmallError("maxColumns", 1);
460
+ if (config.maxColumns !== undefined && (!Number.isInteger(config.maxColumns) || config.maxColumns < 1)) {
461
+ throw new WorkPaperConfigValueTooSmallError('maxColumns', 1);
476
462
  }
477
463
  if ((config.maxRows ?? MAX_ROWS) > MAX_ROWS) {
478
- throw new WorkPaperConfigValueTooBigError("maxRows", MAX_ROWS);
464
+ throw new WorkPaperConfigValueTooBigError('maxRows', MAX_ROWS);
479
465
  }
480
466
  if ((config.maxColumns ?? MAX_COLS) > MAX_COLS) {
481
- throw new WorkPaperConfigValueTooBigError("maxColumns", MAX_COLS);
482
- }
483
- if (config.decimalSeparator !== undefined &&
484
- config.decimalSeparator !== "." &&
485
- config.decimalSeparator !== ",") {
486
- throw new WorkPaperExpectedOneOfValuesError('".", ","', "decimalSeparator");
487
- }
488
- if (config.arrayColumnSeparator !== undefined &&
489
- config.arrayColumnSeparator !== "," &&
490
- config.arrayColumnSeparator !== ";") {
491
- throw new WorkPaperExpectedOneOfValuesError('",", ";"', "arrayColumnSeparator");
492
- }
493
- if (config.arrayRowSeparator !== undefined &&
494
- config.arrayRowSeparator !== ";" &&
495
- config.arrayRowSeparator !== "|") {
496
- throw new WorkPaperExpectedOneOfValuesError('";", "|"', "arrayRowSeparator");
497
- }
498
- if (config.ignoreWhiteSpace !== undefined &&
499
- config.ignoreWhiteSpace !== "standard" &&
500
- config.ignoreWhiteSpace !== "any") {
501
- throw new WorkPaperExpectedOneOfValuesError('"standard", "any"', "ignoreWhiteSpace");
502
- }
503
- if (config.caseFirst !== undefined &&
504
- config.caseFirst !== "upper" &&
505
- config.caseFirst !== "lower" &&
506
- config.caseFirst !== "false") {
507
- throw new WorkPaperExpectedOneOfValuesError('"upper", "lower", "false"', "caseFirst");
467
+ throw new WorkPaperConfigValueTooBigError('maxColumns', MAX_COLS);
468
+ }
469
+ if (config.decimalSeparator !== undefined && config.decimalSeparator !== '.' && config.decimalSeparator !== ',') {
470
+ throw new WorkPaperExpectedOneOfValuesError('".", ","', 'decimalSeparator');
471
+ }
472
+ if (config.arrayColumnSeparator !== undefined && config.arrayColumnSeparator !== ',' && config.arrayColumnSeparator !== ';') {
473
+ throw new WorkPaperExpectedOneOfValuesError('",", ";"', 'arrayColumnSeparator');
474
+ }
475
+ if (config.arrayRowSeparator !== undefined && config.arrayRowSeparator !== ';' && config.arrayRowSeparator !== '|') {
476
+ throw new WorkPaperExpectedOneOfValuesError('";", "|"', 'arrayRowSeparator');
477
+ }
478
+ if (config.ignoreWhiteSpace !== undefined && config.ignoreWhiteSpace !== 'standard' && config.ignoreWhiteSpace !== 'any') {
479
+ throw new WorkPaperExpectedOneOfValuesError('"standard", "any"', 'ignoreWhiteSpace');
480
+ }
481
+ if (config.caseFirst !== undefined && config.caseFirst !== 'upper' && config.caseFirst !== 'lower' && config.caseFirst !== 'false') {
482
+ throw new WorkPaperExpectedOneOfValuesError('"upper", "lower", "false"', 'caseFirst');
508
483
  }
509
484
  if (config.chooseAddressMappingPolicy !== undefined &&
510
- (typeof config.chooseAddressMappingPolicy !== "object" ||
485
+ (typeof config.chooseAddressMappingPolicy !== 'object' ||
511
486
  config.chooseAddressMappingPolicy === null ||
512
- (config.chooseAddressMappingPolicy.mode !== "dense" &&
513
- config.chooseAddressMappingPolicy.mode !== "sparse"))) {
514
- throw new WorkPaperExpectedOneOfValuesError('"dense", "sparse"', "chooseAddressMappingPolicy.mode");
487
+ (config.chooseAddressMappingPolicy.mode !== 'dense' && config.chooseAddressMappingPolicy.mode !== 'sparse'))) {
488
+ throw new WorkPaperExpectedOneOfValuesError('"dense", "sparse"', 'chooseAddressMappingPolicy.mode');
515
489
  }
516
- if (config.parseDateTime !== undefined && typeof config.parseDateTime !== "function") {
517
- throw new WorkPaperExpectedValueOfTypeError("function", "parseDateTime");
490
+ if (config.parseDateTime !== undefined && typeof config.parseDateTime !== 'function') {
491
+ throw new WorkPaperExpectedValueOfTypeError('function', 'parseDateTime');
518
492
  }
519
- if (config.stringifyDateTime !== undefined && typeof config.stringifyDateTime !== "function") {
520
- throw new WorkPaperExpectedValueOfTypeError("function", "stringifyDateTime");
493
+ if (config.stringifyDateTime !== undefined && typeof config.stringifyDateTime !== 'function') {
494
+ throw new WorkPaperExpectedValueOfTypeError('function', 'stringifyDateTime');
521
495
  }
522
- if (config.stringifyDuration !== undefined && typeof config.stringifyDuration !== "function") {
523
- throw new WorkPaperExpectedValueOfTypeError("function", "stringifyDuration");
496
+ if (config.stringifyDuration !== undefined && typeof config.stringifyDuration !== 'function') {
497
+ throw new WorkPaperExpectedValueOfTypeError('function', 'stringifyDuration');
524
498
  }
525
499
  if (config.context !== undefined) {
526
500
  try {
527
501
  structuredClone(config.context);
528
502
  }
529
503
  catch {
530
- throw new WorkPaperExpectedValueOfTypeError("structured-cloneable value", "context");
504
+ throw new WorkPaperExpectedValueOfTypeError('structured-cloneable value', 'context');
531
505
  }
532
506
  }
533
507
  }
@@ -539,7 +513,7 @@ function validateSheetWithinLimits(sheetName, sheet, config) {
539
513
  }
540
514
  sheet.forEach((row) => {
541
515
  if (!Array.isArray(row)) {
542
- throw new WorkPaperUnableToParseError({ sheetName, reason: "Rows must be arrays" });
516
+ throw new WorkPaperUnableToParseError({ sheetName, reason: 'Rows must be arrays' });
543
517
  }
544
518
  });
545
519
  }
@@ -551,29 +525,29 @@ function isHistoryRecordArray(value) {
551
525
  }
552
526
  function withEventChanges(event, changes) {
553
527
  switch (event.eventName) {
554
- case "sheetAdded":
528
+ case 'sheetAdded':
555
529
  return event;
556
- case "sheetRemoved":
530
+ case 'sheetRemoved':
557
531
  return {
558
- eventName: "sheetRemoved",
532
+ eventName: 'sheetRemoved',
559
533
  payload: {
560
534
  ...event.payload,
561
535
  changes,
562
536
  },
563
537
  };
564
- case "sheetRenamed":
538
+ case 'sheetRenamed':
565
539
  return event;
566
- case "namedExpressionAdded":
540
+ case 'namedExpressionAdded':
567
541
  return {
568
- eventName: "namedExpressionAdded",
542
+ eventName: 'namedExpressionAdded',
569
543
  payload: {
570
544
  ...event.payload,
571
545
  changes,
572
546
  },
573
547
  };
574
- case "namedExpressionRemoved":
548
+ case 'namedExpressionRemoved':
575
549
  return {
576
- eventName: "namedExpressionRemoved",
550
+ eventName: 'namedExpressionRemoved',
577
551
  payload: {
578
552
  ...event.payload,
579
553
  changes,
@@ -640,7 +614,7 @@ class WorkPaperEmitter {
640
614
  }
641
615
  dispatchDetailed(event) {
642
616
  switch (event.eventName) {
643
- case "sheetAdded":
617
+ case 'sheetAdded':
644
618
  this.listeners.sheetAdded.forEach((listener) => {
645
619
  listener(event.payload.sheetName);
646
620
  });
@@ -648,7 +622,7 @@ class WorkPaperEmitter {
648
622
  listener(event.payload);
649
623
  });
650
624
  return;
651
- case "sheetRemoved":
625
+ case 'sheetRemoved':
652
626
  this.listeners.sheetRemoved.forEach((listener) => {
653
627
  listener(event.payload.sheetName, event.payload.changes);
654
628
  });
@@ -656,7 +630,7 @@ class WorkPaperEmitter {
656
630
  listener(event.payload);
657
631
  });
658
632
  return;
659
- case "sheetRenamed":
633
+ case 'sheetRenamed':
660
634
  this.listeners.sheetRenamed.forEach((listener) => {
661
635
  listener(event.payload.oldName, event.payload.newName);
662
636
  });
@@ -664,7 +638,7 @@ class WorkPaperEmitter {
664
638
  listener(event.payload);
665
639
  });
666
640
  return;
667
- case "namedExpressionAdded":
641
+ case 'namedExpressionAdded':
668
642
  this.listeners.namedExpressionAdded.forEach((listener) => {
669
643
  listener(event.payload.name, event.payload.changes);
670
644
  });
@@ -672,7 +646,7 @@ class WorkPaperEmitter {
672
646
  listener(event.payload);
673
647
  });
674
648
  return;
675
- case "namedExpressionRemoved":
649
+ case 'namedExpressionRemoved':
676
650
  this.listeners.namedExpressionRemoved.forEach((listener) => {
677
651
  listener(event.payload.name, event.payload.changes);
678
652
  });
@@ -680,7 +654,7 @@ class WorkPaperEmitter {
680
654
  listener(event.payload);
681
655
  });
682
656
  return;
683
- case "valuesUpdated":
657
+ case 'valuesUpdated':
684
658
  this.listeners.valuesUpdated.forEach((listener) => {
685
659
  listener(event.payload.changes);
686
660
  });
@@ -688,7 +662,7 @@ class WorkPaperEmitter {
688
662
  listener(event.payload);
689
663
  });
690
664
  return;
691
- case "evaluationSuspended":
665
+ case 'evaluationSuspended':
692
666
  this.listeners.evaluationSuspended.forEach((listener) => {
693
667
  listener();
694
668
  });
@@ -696,7 +670,7 @@ class WorkPaperEmitter {
696
670
  listener(event.payload);
697
671
  });
698
672
  return;
699
- case "evaluationResumed":
673
+ case 'evaluationResumed':
700
674
  this.listeners.evaluationResumed.forEach((listener) => {
701
675
  listener(event.payload.changes);
702
676
  });
@@ -757,7 +731,7 @@ export class WorkPaper {
757
731
  ...cloneConfig(configInput),
758
732
  };
759
733
  this.engine = new SpreadsheetEngine({
760
- workbookName: "Workbook",
734
+ workbookName: 'Workbook',
761
735
  useColumnIndex: this.config.useColumnIndex,
762
736
  trackReplicaVersions: false,
763
737
  });
@@ -802,9 +776,7 @@ export class WorkPaper {
802
776
  for (let row = 0; row < dimensions.height; row += 1) {
803
777
  const address = { sheet: sheetId, row, col: column };
804
778
  const value = this.getCellValue(address);
805
- const isMatch = typeof matcher === "string"
806
- ? value.tag === ValueTag.String && value.value === matcher
807
- : matcher(value);
779
+ const isMatch = typeof matcher === 'string' ? value.tag === ValueTag.String && value.value === matcher : matcher(value);
808
780
  if (isMatch) {
809
781
  matches.push(address);
810
782
  }
@@ -896,7 +868,7 @@ export class WorkPaper {
896
868
  }
897
869
  }
898
870
  static unregisterFunctionPlugin(plugin) {
899
- const pluginId = typeof plugin === "string" ? plugin : plugin.id;
871
+ const pluginId = typeof plugin === 'string' ? plugin : plugin.id;
900
872
  this.functionPluginRegistry.delete(pluginId);
901
873
  }
902
874
  static registerFunction(functionId, plugin, translations) {
@@ -923,8 +895,7 @@ export class WorkPaper {
923
895
  }
924
896
  if (nextPlugin.aliases) {
925
897
  Object.entries(nextPlugin.aliases).forEach(([alias, target]) => {
926
- if (target.trim().toUpperCase() === normalized ||
927
- alias.trim().toUpperCase() === normalized) {
898
+ if (target.trim().toUpperCase() === normalized || alias.trim().toUpperCase() === normalized) {
928
899
  delete nextPlugin.aliases[alias];
929
900
  }
930
901
  });
@@ -936,7 +907,7 @@ export class WorkPaper {
936
907
  this.functionPluginRegistry.clear();
937
908
  }
938
909
  static getRegisteredFunctionNames(languageCode) {
939
- const normalized = languageCode ?? "enGB";
910
+ const normalized = languageCode ?? 'enGB';
940
911
  const language = this.languageRegistry.get(normalized);
941
912
  const functions = [...this.functionPluginRegistry.values()].flatMap((plugin) => Object.keys(plugin.implementedFunctions));
942
913
  if (!language?.functions) {
@@ -946,8 +917,7 @@ export class WorkPaper {
946
917
  }
947
918
  static getFunctionPlugin(functionId) {
948
919
  const normalized = functionId.trim().toUpperCase();
949
- const plugin = [...this.functionPluginRegistry.values()].find((candidate) => candidate.implementedFunctions[normalized] !== undefined ||
950
- candidate.aliases?.[normalized] !== undefined);
920
+ const plugin = [...this.functionPluginRegistry.values()].find((candidate) => candidate.implementedFunctions[normalized] !== undefined || candidate.aliases?.[normalized] !== undefined);
951
921
  return plugin ? clonePluginDefinition(plugin) : undefined;
952
922
  }
953
923
  static getAllFunctionPlugins() {
@@ -1057,25 +1027,21 @@ export class WorkPaper {
1057
1027
  this.engine.recalculateNow();
1058
1028
  }
1059
1029
  catch (error) {
1060
- throw new WorkPaperOperationError(this.messageOf(error, "Recalculation failed"));
1030
+ throw new WorkPaperOperationError(this.messageOf(error, 'Recalculation failed'));
1061
1031
  }
1062
1032
  return [];
1063
1033
  }
1064
1034
  const beforeVisibility = this.ensureVisibilityCache();
1065
- const beforeNames = this.namedExpressions.size > 0
1066
- ? this.ensureNamedExpressionValueCache()
1067
- : EMPTY_NAMED_EXPRESSION_VALUES;
1035
+ const beforeNames = this.namedExpressions.size > 0 ? this.ensureNamedExpressionValueCache() : EMPTY_NAMED_EXPRESSION_VALUES;
1068
1036
  this.drainTrackedEngineEvents();
1069
1037
  try {
1070
1038
  this.engine.recalculateNow();
1071
1039
  }
1072
1040
  catch (error) {
1073
- throw new WorkPaperOperationError(this.messageOf(error, "Recalculation failed"));
1041
+ throw new WorkPaperOperationError(this.messageOf(error, 'Recalculation failed'));
1074
1042
  }
1075
1043
  const afterVisibility = this.captureVisibilitySnapshot();
1076
- const afterNames = this.namedExpressions.size > 0
1077
- ? this.captureNamedExpressionValueSnapshot()
1078
- : EMPTY_NAMED_EXPRESSION_VALUES;
1044
+ const afterNames = this.namedExpressions.size > 0 ? this.captureNamedExpressionValueSnapshot() : EMPTY_NAMED_EXPRESSION_VALUES;
1079
1045
  this.visibilityCache = afterVisibility;
1080
1046
  this.namedExpressionValueCache = afterNames;
1081
1047
  const changes = [
@@ -1083,7 +1049,7 @@ export class WorkPaper {
1083
1049
  ...this.computeNamedExpressionChanges(beforeNames, afterNames),
1084
1050
  ];
1085
1051
  if (changes.length > 0) {
1086
- this.emitter.emitDetailed({ eventName: "valuesUpdated", payload: { changes } });
1052
+ this.emitter.emitDetailed({ eventName: 'valuesUpdated', payload: { changes } });
1087
1053
  }
1088
1054
  return changes;
1089
1055
  }
@@ -1126,7 +1092,7 @@ export class WorkPaper {
1126
1092
  if (!this.evaluationSuspended) {
1127
1093
  this.flushQueuedEvents();
1128
1094
  if (changes.length > 0) {
1129
- this.emitter.emitDetailed({ eventName: "valuesUpdated", payload: { changes } });
1095
+ this.emitter.emitDetailed({ eventName: 'valuesUpdated', payload: { changes } });
1130
1096
  }
1131
1097
  }
1132
1098
  return changes;
@@ -1149,7 +1115,7 @@ export class WorkPaper {
1149
1115
  this.suspendedUsesTrackedFastPath = false;
1150
1116
  }
1151
1117
  this.drainTrackedEngineEvents();
1152
- this.emitter.emitDetailed({ eventName: "evaluationSuspended", payload: {} });
1118
+ this.emitter.emitDetailed({ eventName: 'evaluationSuspended', payload: {} });
1153
1119
  }
1154
1120
  resumeEvaluation() {
1155
1121
  this.assertNotDisposed();
@@ -1165,9 +1131,9 @@ export class WorkPaper {
1165
1131
  this.suspendedNamedValues = null;
1166
1132
  this.suspendedUsesTrackedFastPath = false;
1167
1133
  this.flushQueuedEvents();
1168
- this.emitter.emitDetailed({ eventName: "evaluationResumed", payload: { changes } });
1134
+ this.emitter.emitDetailed({ eventName: 'evaluationResumed', payload: { changes } });
1169
1135
  if (changes.length > 0) {
1170
- this.emitter.emitDetailed({ eventName: "valuesUpdated", payload: { changes } });
1136
+ this.emitter.emitDetailed({ eventName: 'valuesUpdated', payload: { changes } });
1171
1137
  }
1172
1138
  return changes;
1173
1139
  }
@@ -1251,15 +1217,10 @@ export class WorkPaper {
1251
1217
  for (let colOffset = 0; colOffset < targetWidth; colOffset += 1) {
1252
1218
  const targetRow = target.start.row + rowOffset;
1253
1219
  const targetCol = target.start.col + colOffset;
1254
- const sourceRow = (((targetRow - (offsetsFromTarget ? target.start.row : source.start.row)) %
1255
- sourceHeight) +
1256
- sourceHeight) %
1257
- sourceHeight;
1258
- const sourceCol = (((targetCol - (offsetsFromTarget ? target.start.col : source.start.col)) % sourceWidth) +
1259
- sourceWidth) %
1260
- sourceWidth;
1220
+ const sourceRow = (((targetRow - (offsetsFromTarget ? target.start.row : source.start.row)) % sourceHeight) + sourceHeight) % sourceHeight;
1221
+ const sourceCol = (((targetCol - (offsetsFromTarget ? target.start.col : source.start.col)) % sourceWidth) + sourceWidth) % sourceWidth;
1261
1222
  const raw = sourceSerialized[sourceRow]?.[sourceCol] ?? null;
1262
- if (typeof raw === "string" && raw.startsWith("=")) {
1223
+ if (typeof raw === 'string' && raw.startsWith('=')) {
1263
1224
  row.push(`=${translateFormulaReferences(raw.slice(1), targetRow - (source.start.row + sourceRow), targetCol - (source.start.col + sourceCol))}`);
1264
1225
  }
1265
1226
  else {
@@ -1288,11 +1249,11 @@ export class WorkPaper {
1288
1249
  return undefined;
1289
1250
  }
1290
1251
  const parsed = parseFormula(stripLeadingEquals(formula));
1291
- if (parsed.kind !== "CallExpr" || parsed.callee.trim().toUpperCase() !== "HYPERLINK") {
1252
+ if (parsed.kind !== 'CallExpr' || parsed.callee.trim().toUpperCase() !== 'HYPERLINK') {
1292
1253
  return undefined;
1293
1254
  }
1294
1255
  const firstArgument = parsed.args[0];
1295
- return firstArgument?.kind === "StringLiteral" ? firstArgument.value : undefined;
1256
+ return firstArgument?.kind === 'StringLiteral' ? firstArgument.value : undefined;
1296
1257
  }
1297
1258
  getCellSerialized(address) {
1298
1259
  this.prepareReadableState();
@@ -1396,7 +1357,7 @@ export class WorkPaper {
1396
1357
  : undefined;
1397
1358
  try {
1398
1359
  const parsed = parseRangeAddress(value, defaultSheetName);
1399
- if (parsed.kind !== "cells") {
1360
+ if (parsed.kind !== 'cells') {
1400
1361
  return undefined;
1401
1362
  }
1402
1363
  const sheetName = parsed.sheetName ?? defaultSheetName;
@@ -1415,18 +1376,18 @@ export class WorkPaper {
1415
1376
  }
1416
1377
  simpleCellAddressToString(address, optionsOrContextSheetId = {}) {
1417
1378
  this.assertNotDisposed();
1418
- const includeSheetName = typeof optionsOrContextSheetId === "number"
1379
+ const includeSheetName = typeof optionsOrContextSheetId === 'number'
1419
1380
  ? optionsOrContextSheetId !== address.sheet
1420
1381
  : optionsOrContextSheetId.includeSheetName === true;
1421
1382
  return formatQualifiedCellAddress(includeSheetName ? this.sheetName(address.sheet) : undefined, address.row, address.col);
1422
1383
  }
1423
1384
  simpleCellRangeToString(range, optionsOrContextSheetId = {}) {
1424
- const includeSheetName = typeof optionsOrContextSheetId === "number"
1385
+ const includeSheetName = typeof optionsOrContextSheetId === 'number'
1425
1386
  ? optionsOrContextSheetId !== range.start.sheet
1426
1387
  : optionsOrContextSheetId.includeSheetName === true;
1427
1388
  const sheetName = includeSheetName ? this.sheetName(range.start.sheet) : undefined;
1428
1389
  return formatRangeAddress({
1429
- kind: "cells",
1390
+ kind: 'cells',
1430
1391
  sheetName,
1431
1392
  start: {
1432
1393
  row: range.start.row,
@@ -1445,8 +1406,7 @@ export class WorkPaper {
1445
1406
  if (!isCellRange(address)) {
1446
1407
  return this.toDependencyRefs(this.engine.getDependents(this.sheetName(address.sheet), this.a1(address)).directDependents);
1447
1408
  }
1448
- return this.collectRangeDependencies(address, (cellAddress) => this.engine.getDependents(this.sheetName(cellAddress.sheet), this.a1(cellAddress))
1449
- .directDependents);
1409
+ return this.collectRangeDependencies(address, (cellAddress) => this.engine.getDependents(this.sheetName(cellAddress.sheet), this.a1(cellAddress)).directDependents);
1450
1410
  }
1451
1411
  getCellPrecedents(address) {
1452
1412
  this.flushPendingBatchOps();
@@ -1474,12 +1434,12 @@ export class WorkPaper {
1474
1434
  this.flushPendingBatchOps();
1475
1435
  const cell = this.engine.getCell(this.sheetName(address.sheet), this.a1(address));
1476
1436
  if (this.isCellEmpty(address)) {
1477
- return "EMPTY";
1437
+ return 'EMPTY';
1478
1438
  }
1479
1439
  if (this.isCellPartOfArray(address)) {
1480
- return "ARRAY";
1440
+ return 'ARRAY';
1481
1441
  }
1482
- return cell.formula ? "FORMULA" : "VALUE";
1442
+ return cell.formula ? 'FORMULA' : 'VALUE';
1483
1443
  }
1484
1444
  doesCellHaveSimpleValue(address) {
1485
1445
  this.flushPendingBatchOps();
@@ -1488,58 +1448,52 @@ export class WorkPaper {
1488
1448
  }
1489
1449
  doesCellHaveFormula(address) {
1490
1450
  this.flushPendingBatchOps();
1491
- return (this.engine.getCell(this.sheetName(address.sheet), this.a1(address)).formula !== undefined);
1451
+ return this.engine.getCell(this.sheetName(address.sheet), this.a1(address)).formula !== undefined;
1492
1452
  }
1493
1453
  isCellEmpty(address) {
1494
1454
  this.flushPendingBatchOps();
1495
- return (this.engine.getCellValue(this.sheetName(address.sheet), this.a1(address)).tag ===
1496
- ValueTag.Empty);
1455
+ return this.engine.getCellValue(this.sheetName(address.sheet), this.a1(address)).tag === ValueTag.Empty;
1497
1456
  }
1498
1457
  isCellPartOfArray(address) {
1499
1458
  this.flushPendingBatchOps();
1500
- return this.engine
1501
- .getSpillRanges()
1502
- .some((spill) => {
1459
+ return this.engine.getSpillRanges().some((spill) => {
1503
1460
  if (this.requireSheetId(spill.sheetName) !== address.sheet) {
1504
1461
  return false;
1505
1462
  }
1506
1463
  const owner = parseCellAddress(spill.address, spill.sheetName);
1507
- return (address.row >= owner.row &&
1508
- address.row < owner.row + spill.rows &&
1509
- address.col >= owner.col &&
1510
- address.col < owner.col + spill.cols);
1464
+ return (address.row >= owner.row && address.row < owner.row + spill.rows && address.col >= owner.col && address.col < owner.col + spill.cols);
1511
1465
  });
1512
1466
  }
1513
1467
  getCellValueType(address) {
1514
1468
  const value = this.getCellValue(address);
1515
1469
  switch (value.tag) {
1516
1470
  case ValueTag.Number:
1517
- return "NUMBER";
1471
+ return 'NUMBER';
1518
1472
  case ValueTag.String:
1519
- return "STRING";
1473
+ return 'STRING';
1520
1474
  case ValueTag.Boolean:
1521
- return "BOOLEAN";
1475
+ return 'BOOLEAN';
1522
1476
  case ValueTag.Error:
1523
- return "ERROR";
1477
+ return 'ERROR';
1524
1478
  case ValueTag.Empty:
1525
1479
  default:
1526
- return "EMPTY";
1480
+ return 'EMPTY';
1527
1481
  }
1528
1482
  }
1529
1483
  getCellValueDetailedType(address) {
1530
1484
  const type = this.getCellValueType(address);
1531
- if (type !== "NUMBER") {
1485
+ if (type !== 'NUMBER') {
1532
1486
  return type;
1533
1487
  }
1534
- const format = this.getCellValueFormat(address)?.toLowerCase() ?? "";
1535
- if (format.includes("yy") || format.includes("dd")) {
1536
- if (format.includes("h") || format.includes("s")) {
1537
- return "DATETIME";
1488
+ const format = this.getCellValueFormat(address)?.toLowerCase() ?? '';
1489
+ if (format.includes('yy') || format.includes('dd')) {
1490
+ if (format.includes('h') || format.includes('s')) {
1491
+ return 'DATETIME';
1538
1492
  }
1539
- return "DATE";
1493
+ return 'DATE';
1540
1494
  }
1541
- if (format.includes("h") || format.includes("s")) {
1542
- return "TIME";
1495
+ if (format.includes('h') || format.includes('s')) {
1496
+ return 'TIME';
1543
1497
  }
1544
1498
  return type;
1545
1499
  }
@@ -1577,7 +1531,7 @@ export class WorkPaper {
1577
1531
  throw new WorkPaperNamedExpressionNameIsAlreadyTakenError(expressionName);
1578
1532
  }
1579
1533
  return this.captureChanges({
1580
- eventName: "namedExpressionAdded",
1534
+ eventName: 'namedExpressionAdded',
1581
1535
  payload: {
1582
1536
  name: expressionName.trim(),
1583
1537
  scope,
@@ -1601,7 +1555,7 @@ export class WorkPaper {
1601
1555
  }
1602
1556
  const existing = this.namedExpressionRecord(expressionName, scope);
1603
1557
  return this.captureChanges({
1604
- eventName: "namedExpressionRemoved",
1558
+ eventName: 'namedExpressionRemoved',
1605
1559
  payload: {
1606
1560
  name: existing.publicName,
1607
1561
  scope: existing.scope,
@@ -1629,7 +1583,7 @@ export class WorkPaper {
1629
1583
  .toSorted((left, right) => (left.scope ?? -1) - (right.scope ?? -1) || left.name.localeCompare(right.name));
1630
1584
  }
1631
1585
  normalizeFormula(formula) {
1632
- if (!formula.trim().startsWith("=")) {
1586
+ if (!formula.trim().startsWith('=')) {
1633
1587
  throw new WorkPaperNotAFormulaError();
1634
1588
  }
1635
1589
  try {
@@ -1640,7 +1594,7 @@ export class WorkPaper {
1640
1594
  }
1641
1595
  }
1642
1596
  calculateFormula(formula, scope) {
1643
- if (!formula.trim().startsWith("=")) {
1597
+ if (!formula.trim().startsWith('=')) {
1644
1598
  throw new WorkPaperNotAFormulaError();
1645
1599
  }
1646
1600
  try {
@@ -1675,11 +1629,11 @@ export class WorkPaper {
1675
1629
  });
1676
1630
  }
1677
1631
  catch (error) {
1678
- throw new WorkPaperParseError(this.messageOf(error, "Unable to calculate formula"));
1632
+ throw new WorkPaperParseError(this.messageOf(error, 'Unable to calculate formula'));
1679
1633
  }
1680
1634
  }
1681
1635
  getNamedExpressionsFromFormula(formula) {
1682
- if (!formula.trim().startsWith("=")) {
1636
+ if (!formula.trim().startsWith('=')) {
1683
1637
  throw new WorkPaperNotAFormulaError();
1684
1638
  }
1685
1639
  try {
@@ -1689,11 +1643,11 @@ export class WorkPaper {
1689
1643
  return [...names].toSorted(compareSheetNames);
1690
1644
  }
1691
1645
  catch (error) {
1692
- throw new WorkPaperParseError(this.messageOf(error, "Unable to inspect formula"));
1646
+ throw new WorkPaperParseError(this.messageOf(error, 'Unable to inspect formula'));
1693
1647
  }
1694
1648
  }
1695
1649
  validateFormula(formula) {
1696
- if (!formula.trim().startsWith("=")) {
1650
+ if (!formula.trim().startsWith('=')) {
1697
1651
  return false;
1698
1652
  }
1699
1653
  try {
@@ -1705,7 +1659,7 @@ export class WorkPaper {
1705
1659
  }
1706
1660
  }
1707
1661
  getRegisteredFunctionNames(languageCode) {
1708
- const code = languageCode ?? this.config.language ?? "enGB";
1662
+ const code = languageCode ?? this.config.language ?? 'enGB';
1709
1663
  const language = WorkPaper.languageRegistry.get(code);
1710
1664
  const functions = [...this.functionSnapshot.values()]
1711
1665
  .filter((binding) => binding.publicName === binding.publicName.toUpperCase())
@@ -1770,12 +1724,11 @@ export class WorkPaper {
1770
1724
  setCellContents(address, content) {
1771
1725
  this.assertNotDisposed();
1772
1726
  const sheet = this.sheetRecord(address.sheet);
1773
- assertRowAndColumn(address.row, "address.row");
1774
- assertRowAndColumn(address.col, "address.col");
1727
+ assertRowAndColumn(address.row, 'address.row');
1728
+ assertRowAndColumn(address.col, 'address.col');
1775
1729
  if (!isWorkPaperSheetMatrix(content)) {
1776
- if (address.row >= (this.config.maxRows ?? MAX_ROWS) ||
1777
- address.col >= (this.config.maxColumns ?? MAX_COLS)) {
1778
- throw new WorkPaperOperationError("Cell contents cannot be set");
1730
+ if (address.row >= (this.config.maxRows ?? MAX_ROWS) || address.col >= (this.config.maxColumns ?? MAX_COLS)) {
1731
+ throw new WorkPaperOperationError('Cell contents cannot be set');
1779
1732
  }
1780
1733
  const existingCellIndex = sheet.grid.get(address.row, address.col);
1781
1734
  if (this.enqueueSuspendedLiteralMutation(address.sheet, address.row, address.col, content, existingCellIndex)) {
@@ -1787,16 +1740,16 @@ export class WorkPaper {
1787
1740
  const mutate = () => {
1788
1741
  this.flushPendingBatchOps();
1789
1742
  const mutation = content === null
1790
- ? { kind: "clearCell", row: address.row, col: address.col }
1791
- : typeof content === "string" && content.trim().startsWith("=")
1743
+ ? { kind: 'clearCell', row: address.row, col: address.col }
1744
+ : typeof content === 'string' && content.trim().startsWith('=')
1792
1745
  ? {
1793
- kind: "setCellFormula",
1746
+ kind: 'setCellFormula',
1794
1747
  row: address.row,
1795
1748
  col: address.col,
1796
1749
  formula: this.rewriteFormulaForStorage(stripLeadingEquals(content), address.sheet),
1797
1750
  }
1798
1751
  : {
1799
- kind: "setCellValue",
1752
+ kind: 'setCellValue',
1800
1753
  row: address.row,
1801
1754
  col: address.col,
1802
1755
  value: content,
@@ -1804,7 +1757,7 @@ export class WorkPaper {
1804
1757
  this.applyCellMutationRefs([{ sheetId: address.sheet, mutation }], {
1805
1758
  captureUndo: true,
1806
1759
  potentialNewCells: content === null || existingCellIndex !== -1 ? 0 : 1,
1807
- source: "local",
1760
+ source: 'local',
1808
1761
  returnUndoOps: false,
1809
1762
  reuseRefs: true,
1810
1763
  });
@@ -1817,7 +1770,7 @@ export class WorkPaper {
1817
1770
  });
1818
1771
  }
1819
1772
  if (!this.isItPossibleToSetCellContents(address, content)) {
1820
- throw new WorkPaperOperationError("Cell contents cannot be set");
1773
+ throw new WorkPaperOperationError('Cell contents cannot be set');
1821
1774
  }
1822
1775
  return this.captureChanges(undefined, () => {
1823
1776
  if (isWorkPaperSheetMatrix(content)) {
@@ -1828,9 +1781,9 @@ export class WorkPaper {
1828
1781
  });
1829
1782
  }
1830
1783
  swapRowIndexes(sheetId, rowAOrMappings, rowB) {
1831
- const mappings = this.normalizeAxisSwapMappings("row", rowAOrMappings, rowB);
1784
+ const mappings = this.normalizeAxisSwapMappings('row', rowAOrMappings, rowB);
1832
1785
  if (!this.isItPossibleToSwapRowIndexes(sheetId, mappings)) {
1833
- throw new WorkPaperOperationError("Rows cannot be swapped");
1786
+ throw new WorkPaperOperationError('Rows cannot be swapped');
1834
1787
  }
1835
1788
  return this.batch(() => {
1836
1789
  mappings.forEach(([rowA, mappedRowB]) => {
@@ -1850,7 +1803,7 @@ export class WorkPaper {
1850
1803
  }
1851
1804
  setRowOrder(sheetId, rowOrder) {
1852
1805
  if (!this.isItPossibleToSetRowOrder(sheetId, rowOrder)) {
1853
- throw new WorkPaperOperationError("Row order is invalid");
1806
+ throw new WorkPaperOperationError('Row order is invalid');
1854
1807
  }
1855
1808
  const current = rowOrder.toSorted((left, right) => left - right);
1856
1809
  return this.batch(() => {
@@ -1866,9 +1819,9 @@ export class WorkPaper {
1866
1819
  });
1867
1820
  }
1868
1821
  swapColumnIndexes(sheetId, columnAOrMappings, columnB) {
1869
- const mappings = this.normalizeAxisSwapMappings("column", columnAOrMappings, columnB);
1822
+ const mappings = this.normalizeAxisSwapMappings('column', columnAOrMappings, columnB);
1870
1823
  if (!this.isItPossibleToSwapColumnIndexes(sheetId, mappings)) {
1871
- throw new WorkPaperOperationError("Columns cannot be swapped");
1824
+ throw new WorkPaperOperationError('Columns cannot be swapped');
1872
1825
  }
1873
1826
  return this.batch(() => {
1874
1827
  mappings.forEach(([columnA, mappedColumnB]) => {
@@ -1888,7 +1841,7 @@ export class WorkPaper {
1888
1841
  }
1889
1842
  setColumnOrder(sheetId, columnOrder) {
1890
1843
  if (!this.isItPossibleToSetColumnOrder(sheetId, columnOrder)) {
1891
- throw new WorkPaperOperationError("Column order is invalid");
1844
+ throw new WorkPaperOperationError('Column order is invalid');
1892
1845
  }
1893
1846
  const current = columnOrder.toSorted((left, right) => left - right);
1894
1847
  return this.batch(() => {
@@ -1906,7 +1859,7 @@ export class WorkPaper {
1906
1859
  addRows(sheetId, startOrInterval, countOrInterval, ...restIntervals) {
1907
1860
  const indexes = this.normalizeAxisIntervals(startOrInterval, countOrInterval, restIntervals);
1908
1861
  if (!this.isItPossibleToAddRows(sheetId, ...indexes)) {
1909
- throw new WorkPaperOperationError("Rows cannot be added");
1862
+ throw new WorkPaperOperationError('Rows cannot be added');
1910
1863
  }
1911
1864
  return this.batchStructuralChanges(() => {
1912
1865
  indexes.forEach(([start, amount]) => {
@@ -1917,7 +1870,7 @@ export class WorkPaper {
1917
1870
  removeRows(sheetId, startOrInterval, countOrInterval, ...restIntervals) {
1918
1871
  const indexes = this.normalizeAxisIntervals(startOrInterval, countOrInterval, restIntervals);
1919
1872
  if (!this.isItPossibleToRemoveRows(sheetId, ...indexes)) {
1920
- throw new WorkPaperOperationError("Rows cannot be removed");
1873
+ throw new WorkPaperOperationError('Rows cannot be removed');
1921
1874
  }
1922
1875
  return this.batchStructuralChanges(() => {
1923
1876
  indexes
@@ -1930,7 +1883,7 @@ export class WorkPaper {
1930
1883
  addColumns(sheetId, startOrInterval, countOrInterval, ...restIntervals) {
1931
1884
  const indexes = this.normalizeAxisIntervals(startOrInterval, countOrInterval, restIntervals);
1932
1885
  if (!this.isItPossibleToAddColumns(sheetId, ...indexes)) {
1933
- throw new WorkPaperOperationError("Columns cannot be added");
1886
+ throw new WorkPaperOperationError('Columns cannot be added');
1934
1887
  }
1935
1888
  return this.batchStructuralChanges(() => {
1936
1889
  indexes.forEach(([start, amount]) => {
@@ -1941,7 +1894,7 @@ export class WorkPaper {
1941
1894
  removeColumns(sheetId, startOrInterval, countOrInterval, ...restIntervals) {
1942
1895
  const indexes = this.normalizeAxisIntervals(startOrInterval, countOrInterval, restIntervals);
1943
1896
  if (!this.isItPossibleToRemoveColumns(sheetId, ...indexes)) {
1944
- throw new WorkPaperOperationError("Columns cannot be removed");
1897
+ throw new WorkPaperOperationError('Columns cannot be removed');
1945
1898
  }
1946
1899
  return this.batchStructuralChanges(() => {
1947
1900
  indexes
@@ -1953,7 +1906,7 @@ export class WorkPaper {
1953
1906
  }
1954
1907
  moveCells(source, target) {
1955
1908
  if (!this.isItPossibleToMoveCells(source, target)) {
1956
- throw new WorkPaperOperationError("Cells cannot be moved");
1909
+ throw new WorkPaperOperationError('Cells cannot be moved');
1957
1910
  }
1958
1911
  const sourceHeight = source.end.row - source.start.row;
1959
1912
  const sourceWidth = source.end.col - source.start.col;
@@ -1967,7 +1920,7 @@ export class WorkPaper {
1967
1920
  }
1968
1921
  moveRows(sheetId, start, count, target) {
1969
1922
  if (!this.isItPossibleToMoveRows(sheetId, start, count, target)) {
1970
- throw new WorkPaperOperationError("Rows cannot be moved");
1923
+ throw new WorkPaperOperationError('Rows cannot be moved');
1971
1924
  }
1972
1925
  return this.canUseTrackedStructuralFastPath()
1973
1926
  ? this.batchStructuralChanges(() => {
@@ -1979,7 +1932,7 @@ export class WorkPaper {
1979
1932
  }
1980
1933
  moveColumns(sheetId, start, count, target) {
1981
1934
  if (!this.isItPossibleToMoveColumns(sheetId, start, count, target)) {
1982
- throw new WorkPaperOperationError("Columns cannot be moved");
1935
+ throw new WorkPaperOperationError('Columns cannot be moved');
1983
1936
  }
1984
1937
  return this.canUseTrackedStructuralFastPath()
1985
1938
  ? this.batchStructuralChanges(() => {
@@ -2003,14 +1956,14 @@ export class WorkPaper {
2003
1956
  const sheetId = this.requireSheetId(name);
2004
1957
  const payload = { sheetId, sheetName: name };
2005
1958
  if (this.shouldSuppressEvents()) {
2006
- this.queuedEvents.push({ eventName: "sheetAdded", payload });
1959
+ this.queuedEvents.push({ eventName: 'sheetAdded', payload });
2007
1960
  }
2008
1961
  else {
2009
- this.emitter.emitDetailed({ eventName: "sheetAdded", payload });
1962
+ this.emitter.emitDetailed({ eventName: 'sheetAdded', payload });
2010
1963
  }
2011
1964
  const changes = this.computeChangesAfterMutation(beforeVisibility, beforeNames);
2012
1965
  if (!this.shouldSuppressEvents() && changes.length > 0) {
2013
- this.emitter.emitDetailed({ eventName: "valuesUpdated", payload: { changes } });
1966
+ this.emitter.emitDetailed({ eventName: 'valuesUpdated', payload: { changes } });
2014
1967
  }
2015
1968
  return name;
2016
1969
  }
@@ -2020,7 +1973,7 @@ export class WorkPaper {
2020
1973
  }
2021
1974
  const sheetName = this.sheetName(sheetId);
2022
1975
  return this.captureChanges({
2023
- eventName: "sheetRemoved",
1976
+ eventName: 'sheetRemoved',
2024
1977
  payload: {
2025
1978
  sheetId,
2026
1979
  sheetName,
@@ -2042,7 +1995,7 @@ export class WorkPaper {
2042
1995
  }
2043
1996
  this.engine.clearRange({
2044
1997
  sheetName: this.sheetName(sheetId),
2045
- startAddress: "A1",
1998
+ startAddress: 'A1',
2046
1999
  endAddress: formatAddress(dimensions.height - 1, dimensions.width - 1),
2047
2000
  });
2048
2001
  });
@@ -2062,7 +2015,7 @@ export class WorkPaper {
2062
2015
  const oldName = this.sheetName(sheetId);
2063
2016
  const newName = nextName.trim();
2064
2017
  return this.captureChanges({
2065
- eventName: "sheetRenamed",
2018
+ eventName: 'sheetRenamed',
2066
2019
  payload: {
2067
2020
  sheetId,
2068
2021
  oldName,
@@ -2078,58 +2031,53 @@ export class WorkPaper {
2078
2031
  if (isCellRange(addressOrRange)) {
2079
2032
  assertRange(addressOrRange);
2080
2033
  this.sheetRecord(addressOrRange.start.sheet);
2081
- return (addressOrRange.end.row < (this.config.maxRows ?? MAX_ROWS) &&
2082
- addressOrRange.end.col < (this.config.maxColumns ?? MAX_COLS));
2034
+ return addressOrRange.end.row < (this.config.maxRows ?? MAX_ROWS) && addressOrRange.end.col < (this.config.maxColumns ?? MAX_COLS);
2083
2035
  }
2084
2036
  this.sheetRecord(addressOrRange.sheet);
2085
- assertRowAndColumn(addressOrRange.row, "address.row");
2086
- assertRowAndColumn(addressOrRange.col, "address.col");
2037
+ assertRowAndColumn(addressOrRange.row, 'address.row');
2038
+ assertRowAndColumn(addressOrRange.col, 'address.col');
2087
2039
  if (content === undefined) {
2088
- return (addressOrRange.row < (this.config.maxRows ?? MAX_ROWS) &&
2089
- addressOrRange.col < (this.config.maxColumns ?? MAX_COLS));
2040
+ return addressOrRange.row < (this.config.maxRows ?? MAX_ROWS) && addressOrRange.col < (this.config.maxColumns ?? MAX_COLS);
2090
2041
  }
2091
2042
  if (Array.isArray(content)) {
2092
2043
  if (!content.every((row) => Array.isArray(row))) {
2093
- throw new WorkPaperInvalidArgumentsError("Content matrix must be a two-dimensional array");
2044
+ throw new WorkPaperInvalidArgumentsError('Content matrix must be a two-dimensional array');
2094
2045
  }
2095
2046
  const height = content.length;
2096
2047
  const width = Math.max(0, ...content.map((row) => row.length));
2097
2048
  return (addressOrRange.row + height <= (this.config.maxRows ?? MAX_ROWS) &&
2098
2049
  addressOrRange.col + width <= (this.config.maxColumns ?? MAX_COLS));
2099
2050
  }
2100
- return (addressOrRange.row < (this.config.maxRows ?? MAX_ROWS) &&
2101
- addressOrRange.col < (this.config.maxColumns ?? MAX_COLS));
2051
+ return addressOrRange.row < (this.config.maxRows ?? MAX_ROWS) && addressOrRange.col < (this.config.maxColumns ?? MAX_COLS);
2102
2052
  }
2103
2053
  isItPossibleToSwapRowIndexes(sheetId, rowAOrMappings, rowB) {
2104
2054
  this.sheetRecord(sheetId);
2105
- const mappings = this.normalizeAxisSwapMappings("row", rowAOrMappings, rowB);
2055
+ const mappings = this.normalizeAxisSwapMappings('row', rowAOrMappings, rowB);
2106
2056
  return mappings.every(([rowA, mappedRowB]) => {
2107
- assertRowAndColumn(rowA, "rowA");
2108
- assertRowAndColumn(mappedRowB, "rowB");
2057
+ assertRowAndColumn(rowA, 'rowA');
2058
+ assertRowAndColumn(mappedRowB, 'rowB');
2109
2059
  return true;
2110
2060
  });
2111
2061
  }
2112
2062
  isItPossibleToSetRowOrder(sheetId, rowOrder) {
2113
2063
  this.sheetRecord(sheetId);
2114
- if (new Set(rowOrder).size !== rowOrder.length ||
2115
- rowOrder.some((value) => !Number.isInteger(value) || value < 0)) {
2064
+ if (new Set(rowOrder).size !== rowOrder.length || rowOrder.some((value) => !Number.isInteger(value) || value < 0)) {
2116
2065
  return false;
2117
2066
  }
2118
2067
  return true;
2119
2068
  }
2120
2069
  isItPossibleToSwapColumnIndexes(sheetId, columnAOrMappings, columnB) {
2121
2070
  this.sheetRecord(sheetId);
2122
- const mappings = this.normalizeAxisSwapMappings("column", columnAOrMappings, columnB);
2071
+ const mappings = this.normalizeAxisSwapMappings('column', columnAOrMappings, columnB);
2123
2072
  return mappings.every(([columnA, mappedColumnB]) => {
2124
- assertRowAndColumn(columnA, "columnA");
2125
- assertRowAndColumn(mappedColumnB, "columnB");
2073
+ assertRowAndColumn(columnA, 'columnA');
2074
+ assertRowAndColumn(mappedColumnB, 'columnB');
2126
2075
  return true;
2127
2076
  });
2128
2077
  }
2129
2078
  isItPossibleToSetColumnOrder(sheetId, columnOrder) {
2130
2079
  this.sheetRecord(sheetId);
2131
- if (new Set(columnOrder).size !== columnOrder.length ||
2132
- columnOrder.some((value) => !Number.isInteger(value) || value < 0)) {
2080
+ if (new Set(columnOrder).size !== columnOrder.length || columnOrder.some((value) => !Number.isInteger(value) || value < 0)) {
2133
2081
  return false;
2134
2082
  }
2135
2083
  return true;
@@ -2137,60 +2085,60 @@ export class WorkPaper {
2137
2085
  isItPossibleToAddRows(sheetId, startOrInterval, countOrInterval, ...restIntervals) {
2138
2086
  this.sheetRecord(sheetId);
2139
2087
  return this.normalizeAxisIntervals(startOrInterval, countOrInterval, restIntervals).every(([start, count]) => {
2140
- assertRowAndColumn(start, "start");
2141
- assertRowAndColumn(count, "count");
2088
+ assertRowAndColumn(start, 'start');
2089
+ assertRowAndColumn(count, 'count');
2142
2090
  return count > 0 && start + count <= (this.config.maxRows ?? MAX_ROWS);
2143
2091
  });
2144
2092
  }
2145
2093
  isItPossibleToRemoveRows(sheetId, startOrInterval, countOrInterval, ...restIntervals) {
2146
2094
  this.sheetRecord(sheetId);
2147
2095
  return this.normalizeAxisIntervals(startOrInterval, countOrInterval, restIntervals).every(([start, count]) => {
2148
- assertRowAndColumn(start, "start");
2149
- assertRowAndColumn(count, "count");
2096
+ assertRowAndColumn(start, 'start');
2097
+ assertRowAndColumn(count, 'count');
2150
2098
  return count > 0;
2151
2099
  });
2152
2100
  }
2153
2101
  isItPossibleToAddColumns(sheetId, startOrInterval, countOrInterval, ...restIntervals) {
2154
2102
  this.sheetRecord(sheetId);
2155
2103
  return this.normalizeAxisIntervals(startOrInterval, countOrInterval, restIntervals).every(([start, count]) => {
2156
- assertRowAndColumn(start, "start");
2157
- assertRowAndColumn(count, "count");
2104
+ assertRowAndColumn(start, 'start');
2105
+ assertRowAndColumn(count, 'count');
2158
2106
  return count > 0 && start + count <= (this.config.maxColumns ?? MAX_COLS);
2159
2107
  });
2160
2108
  }
2161
2109
  isItPossibleToRemoveColumns(sheetId, startOrInterval, countOrInterval, ...restIntervals) {
2162
2110
  this.sheetRecord(sheetId);
2163
2111
  return this.normalizeAxisIntervals(startOrInterval, countOrInterval, restIntervals).every(([start, count]) => {
2164
- assertRowAndColumn(start, "start");
2165
- assertRowAndColumn(count, "count");
2112
+ assertRowAndColumn(start, 'start');
2113
+ assertRowAndColumn(count, 'count');
2166
2114
  return count > 0;
2167
2115
  });
2168
2116
  }
2169
2117
  isItPossibleToMoveCells(source, target) {
2170
2118
  assertRange(source);
2171
- assertRowAndColumn(target.sheet, "target.sheet");
2172
- assertRowAndColumn(target.row, "target.row");
2173
- assertRowAndColumn(target.col, "target.col");
2119
+ assertRowAndColumn(target.sheet, 'target.sheet');
2120
+ assertRowAndColumn(target.row, 'target.row');
2121
+ assertRowAndColumn(target.col, 'target.col');
2174
2122
  return source.start.sheet === target.sheet;
2175
2123
  }
2176
2124
  isItPossibleToMoveRows(sheetId, start, count, target) {
2177
2125
  this.sheetRecord(sheetId);
2178
- assertRowAndColumn(start, "start");
2179
- assertRowAndColumn(count, "count");
2180
- assertRowAndColumn(target, "target");
2126
+ assertRowAndColumn(start, 'start');
2127
+ assertRowAndColumn(count, 'count');
2128
+ assertRowAndColumn(target, 'target');
2181
2129
  return count > 0;
2182
2130
  }
2183
2131
  isItPossibleToMoveColumns(sheetId, start, count, target) {
2184
2132
  this.sheetRecord(sheetId);
2185
- assertRowAndColumn(start, "start");
2186
- assertRowAndColumn(count, "count");
2187
- assertRowAndColumn(target, "target");
2133
+ assertRowAndColumn(start, 'start');
2134
+ assertRowAndColumn(count, 'count');
2135
+ assertRowAndColumn(target, 'target');
2188
2136
  return count > 0;
2189
2137
  }
2190
2138
  isItPossibleToAddSheet(sheetName) {
2191
2139
  const trimmed = sheetName.trim();
2192
2140
  if (trimmed.length === 0) {
2193
- throw new WorkPaperInvalidArgumentsError("Sheet name must be non-empty");
2141
+ throw new WorkPaperInvalidArgumentsError('Sheet name must be non-empty');
2194
2142
  }
2195
2143
  return !this.doesSheetExist(trimmed);
2196
2144
  }
@@ -2203,17 +2151,17 @@ export class WorkPaper {
2203
2151
  isItPossibleToReplaceSheetContent(sheetId, content) {
2204
2152
  this.sheetRecord(sheetId);
2205
2153
  if (!content.every((row) => Array.isArray(row))) {
2206
- throw new WorkPaperInvalidArgumentsError("Sheet content must be a two-dimensional array");
2154
+ throw new WorkPaperInvalidArgumentsError('Sheet content must be a two-dimensional array');
2207
2155
  }
2208
2156
  const height = content.length;
2209
2157
  const width = Math.max(0, ...content.map((row) => row.length));
2210
- return (height <= (this.config.maxRows ?? MAX_ROWS) && width <= (this.config.maxColumns ?? MAX_COLS));
2158
+ return height <= (this.config.maxRows ?? MAX_ROWS) && width <= (this.config.maxColumns ?? MAX_COLS);
2211
2159
  }
2212
2160
  isItPossibleToRenameSheet(sheetId, nextName) {
2213
2161
  this.sheetRecord(sheetId);
2214
2162
  const trimmed = nextName.trim();
2215
2163
  if (trimmed.length === 0) {
2216
- throw new WorkPaperInvalidArgumentsError("Sheet name must be non-empty");
2164
+ throw new WorkPaperInvalidArgumentsError('Sheet name must be non-empty');
2217
2165
  }
2218
2166
  const existing = this.engine.workbook.getSheet(trimmed);
2219
2167
  return !existing || existing.id === sheetId;
@@ -2290,9 +2238,7 @@ export class WorkPaper {
2290
2238
  ensureNamedExpressionValueCache() {
2291
2239
  if (!this.namedExpressionValueCache) {
2292
2240
  this.namedExpressionValueCache =
2293
- this.namedExpressions.size > 0
2294
- ? this.captureNamedExpressionValueSnapshot()
2295
- : EMPTY_NAMED_EXPRESSION_VALUES;
2241
+ this.namedExpressions.size > 0 ? this.captureNamedExpressionValueSnapshot() : EMPTY_NAMED_EXPRESSION_VALUES;
2296
2242
  }
2297
2243
  return this.namedExpressionValueCache;
2298
2244
  }
@@ -2307,13 +2253,13 @@ export class WorkPaper {
2307
2253
  this.engine.applyCellMutationsAtWithOptions(ops, {
2308
2254
  captureUndo: true,
2309
2255
  potentialNewCells: potentialNewCells > 0 ? potentialNewCells : undefined,
2310
- source: "local",
2256
+ source: 'local',
2311
2257
  returnUndoOps: false,
2312
2258
  reuseRefs: true,
2313
2259
  });
2314
2260
  }
2315
2261
  applyCellMutationRefs(refs, options) {
2316
- if (this.evaluationSuspended && (options.source ?? "local") === "local") {
2262
+ if (this.evaluationSuspended && (options.source ?? 'local') === 'local') {
2317
2263
  for (let index = 0; index < refs.length; index += 1) {
2318
2264
  const ref = refs[index];
2319
2265
  if (!ref) {
@@ -2322,30 +2268,29 @@ export class WorkPaper {
2322
2268
  const mutation = ref.mutation;
2323
2269
  this.suspendedCellMutationRefs.push({
2324
2270
  sheetId: ref.sheetId,
2325
- mutation: mutation.kind === "setCellValue"
2271
+ mutation: mutation.kind === 'setCellValue'
2326
2272
  ? {
2327
- kind: "setCellValue",
2273
+ kind: 'setCellValue',
2328
2274
  row: mutation.row,
2329
2275
  col: mutation.col,
2330
2276
  value: mutation.value,
2331
2277
  }
2332
- : mutation.kind === "setCellFormula"
2278
+ : mutation.kind === 'setCellFormula'
2333
2279
  ? {
2334
- kind: "setCellFormula",
2280
+ kind: 'setCellFormula',
2335
2281
  row: mutation.row,
2336
2282
  col: mutation.col,
2337
2283
  formula: mutation.formula,
2338
2284
  }
2339
2285
  : {
2340
- kind: "clearCell",
2286
+ kind: 'clearCell',
2341
2287
  row: mutation.row,
2342
2288
  col: mutation.col,
2343
2289
  },
2344
2290
  });
2345
2291
  }
2346
2292
  this.suspendedCellMutationPotentialNewCells +=
2347
- options.potentialNewCells ??
2348
- refs.reduce((count, ref) => (ref?.mutation.kind === "clearCell" ? count : count + 1), 0);
2293
+ options.potentialNewCells ?? refs.reduce((count, ref) => (ref?.mutation.kind === 'clearCell' ? count : count + 1), 0);
2349
2294
  return;
2350
2295
  }
2351
2296
  this.engine.applyCellMutationsAtWithOptions(refs, options);
@@ -2361,24 +2306,22 @@ export class WorkPaper {
2361
2306
  this.engine.applyCellMutationsAtWithOptions(refs, {
2362
2307
  captureUndo: true,
2363
2308
  potentialNewCells: potentialNewCells > 0 ? potentialNewCells : undefined,
2364
- source: "local",
2309
+ source: 'local',
2365
2310
  returnUndoOps: false,
2366
2311
  reuseRefs: true,
2367
2312
  });
2368
2313
  }
2369
2314
  enqueueSuspendedLiteralMutation(sheetId, row, col, content, existingCellIndex = this.engine.workbook.getSheetById(sheetId)?.grid.get(row, col) ?? -1) {
2370
- if (!this.evaluationSuspended ||
2371
- !isDeferredBatchLiteralContent(content) ||
2372
- isFormulaContent(content)) {
2315
+ if (!this.evaluationSuspended || !isDeferredBatchLiteralContent(content) || isFormulaContent(content)) {
2373
2316
  return false;
2374
2317
  }
2375
2318
  if (content === null) {
2376
- this.suspendedCellMutationRefs.push({ sheetId, mutation: { kind: "clearCell", row, col } });
2319
+ this.suspendedCellMutationRefs.push({ sheetId, mutation: { kind: 'clearCell', row, col } });
2377
2320
  return true;
2378
2321
  }
2379
2322
  this.suspendedCellMutationRefs.push({
2380
2323
  sheetId,
2381
- mutation: { kind: "setCellValue", row, col, value: content },
2324
+ mutation: { kind: 'setCellValue', row, col, value: content },
2382
2325
  });
2383
2326
  if (existingCellIndex === -1) {
2384
2327
  this.suspendedCellMutationPotentialNewCells += 1;
@@ -2386,19 +2329,16 @@ export class WorkPaper {
2386
2329
  return true;
2387
2330
  }
2388
2331
  enqueueDeferredBatchLiteral(sheetId, row, col, content, existingCellIndex = this.engine.workbook.getSheetById(sheetId)?.grid.get(row, col) ?? -1) {
2389
- if (this.batchDepth === 0 ||
2390
- this.evaluationSuspended ||
2391
- !isDeferredBatchLiteralContent(content) ||
2392
- isFormulaContent(content)) {
2332
+ if (this.batchDepth === 0 || this.evaluationSuspended || !isDeferredBatchLiteralContent(content) || isFormulaContent(content)) {
2393
2333
  return false;
2394
2334
  }
2395
2335
  if (content === null) {
2396
- this.pendingBatchOps.push({ sheetId, mutation: { kind: "clearCell", row, col } });
2336
+ this.pendingBatchOps.push({ sheetId, mutation: { kind: 'clearCell', row, col } });
2397
2337
  return true;
2398
2338
  }
2399
2339
  this.pendingBatchOps.push({
2400
2340
  sheetId,
2401
- mutation: { kind: "setCellValue", row, col, value: content },
2341
+ mutation: { kind: 'setCellValue', row, col, value: content },
2402
2342
  });
2403
2343
  if (existingCellIndex === -1) {
2404
2344
  this.pendingBatchPotentialNewCells += 1;
@@ -2411,7 +2351,7 @@ export class WorkPaper {
2411
2351
  }
2412
2352
  assertNotDisposed() {
2413
2353
  if (this.disposed) {
2414
- throw new WorkPaperOperationError("Workbook has been disposed");
2354
+ throw new WorkPaperOperationError('Workbook has been disposed');
2415
2355
  }
2416
2356
  }
2417
2357
  assertReadable() {
@@ -2510,10 +2450,7 @@ export class WorkPaper {
2510
2450
  const cellChanges = [];
2511
2451
  afterVisibility.forEach((afterSheet, sheetId) => {
2512
2452
  const beforeSheet = beforeVisibility.get(sheetId);
2513
- const cellKeys = new Set([
2514
- ...(beforeSheet?.cells.keys() ?? []),
2515
- ...afterSheet.cells.keys(),
2516
- ]);
2453
+ const cellKeys = new Set([...(beforeSheet?.cells.keys() ?? []), ...afterSheet.cells.keys()]);
2517
2454
  [...cellKeys]
2518
2455
  .toSorted((left, right) => left - right)
2519
2456
  .forEach((cellKey) => {
@@ -2527,7 +2464,7 @@ export class WorkPaper {
2527
2464
  const col = localKey % MAX_COLS;
2528
2465
  const address = formatAddress(row, col);
2529
2466
  cellChanges.push({
2530
- kind: "cell",
2467
+ kind: 'cell',
2531
2468
  address: { sheet: sheetId, row, col },
2532
2469
  sheetName: afterSheet.sheetName,
2533
2470
  a1: address,
@@ -2538,7 +2475,7 @@ export class WorkPaper {
2538
2475
  return orderWorkPaperCellChanges(cellChanges, this.listSheetRecords());
2539
2476
  }
2540
2477
  computeCellChangesFromTrackedEvents(beforeVisibility, events) {
2541
- if (events.some((event) => event.invalidation === "full")) {
2478
+ if (events.some((event) => event.invalidation === 'full')) {
2542
2479
  return null;
2543
2480
  }
2544
2481
  const nextVisibility = beforeVisibility;
@@ -2599,8 +2536,7 @@ export class WorkPaper {
2599
2536
  const sheet = ensureMutableSheet(change.address.sheet, change.sheetName);
2600
2537
  if (sheet.order < previousSheetOrder ||
2601
2538
  (sheet.order === previousSheetOrder &&
2602
- (change.address.row < previousRow ||
2603
- (change.address.row === previousRow && change.address.col < previousCol)))) {
2539
+ (change.address.row < previousRow || (change.address.row === previousRow && change.address.col < previousCol)))) {
2604
2540
  alreadySorted = false;
2605
2541
  }
2606
2542
  if (change.newValue.tag === ValueTag.Empty) {
@@ -2610,7 +2546,7 @@ export class WorkPaper {
2610
2546
  sheet.cells.set(cellKey, change.newValue);
2611
2547
  }
2612
2548
  directChanges[index] = {
2613
- kind: "cell",
2549
+ kind: 'cell',
2614
2550
  address: change.address,
2615
2551
  sheetName: change.sheetName,
2616
2552
  a1: change.a1,
@@ -2635,7 +2571,7 @@ export class WorkPaper {
2635
2571
  const cellKey = makeCellKey(change.address.sheet, change.address.row, change.address.col);
2636
2572
  latestChangesByKey.delete(cellKey);
2637
2573
  latestChangesByKey.set(cellKey, {
2638
- kind: "cell",
2574
+ kind: 'cell',
2639
2575
  address: change.address,
2640
2576
  sheetName: change.sheetName,
2641
2577
  a1: change.a1,
@@ -2671,7 +2607,7 @@ export class WorkPaper {
2671
2607
  return;
2672
2608
  }
2673
2609
  namedExpressionChanges.push({
2674
- kind: "named-expression",
2610
+ kind: 'named-expression',
2675
2611
  name: expression.publicName,
2676
2612
  scope: expression.scope,
2677
2613
  newValue: cloneNamedExpressionValue(afterValue),
@@ -2680,32 +2616,23 @@ export class WorkPaper {
2680
2616
  return namedExpressionChanges.toSorted(compareWorkPaperNamedExpressionChanges);
2681
2617
  }
2682
2618
  canUseTrackedStructuralFastPath() {
2683
- return (this.batchDepth === 0 &&
2684
- !this.evaluationSuspended &&
2685
- this.visibilityCache === null &&
2686
- this.namedExpressions.size === 0);
2619
+ return this.batchDepth === 0 && !this.evaluationSuspended && this.visibilityCache === null && this.namedExpressions.size === 0;
2687
2620
  }
2688
2621
  canUseTrackedMutationFastPath() {
2689
- return (this.batchDepth === 0 &&
2690
- !this.evaluationSuspended &&
2691
- this.visibilityCache === null &&
2692
- this.namedExpressions.size === 0);
2622
+ return this.batchDepth === 0 && !this.evaluationSuspended && this.visibilityCache === null && this.namedExpressions.size === 0;
2693
2623
  }
2694
2624
  downgradeTrackedBatchFastPath() {
2695
2625
  if (!this.batchUsesTrackedFastPath || this.batchDepth === 0) {
2696
2626
  return;
2697
2627
  }
2698
2628
  this.batchStartVisibility = this.ensureVisibilityCache();
2699
- this.batchStartNamedValues =
2700
- this.namedExpressions.size > 0
2701
- ? this.ensureNamedExpressionValueCache()
2702
- : EMPTY_NAMED_EXPRESSION_VALUES;
2629
+ this.batchStartNamedValues = this.namedExpressions.size > 0 ? this.ensureNamedExpressionValueCache() : EMPTY_NAMED_EXPRESSION_VALUES;
2703
2630
  this.batchUsesTrackedFastPath = false;
2704
2631
  }
2705
2632
  computeTrackedChangesWithoutVisibilityCache(events) {
2706
2633
  const fastPath = this.computeCellChangesFromTrackedEvents(new Map(), events);
2707
2634
  if (!fastPath) {
2708
- throw new WorkPaperOperationError("Mutation emitted an unsupported invalidation pattern for tracked changes");
2635
+ throw new WorkPaperOperationError('Mutation emitted an unsupported invalidation pattern for tracked changes');
2709
2636
  }
2710
2637
  return fastPath.changes;
2711
2638
  }
@@ -2719,11 +2646,11 @@ export class WorkPaper {
2719
2646
  if (error instanceof Error && WORKPAPER_PUBLIC_ERROR_NAMES.has(error.name)) {
2720
2647
  throw error;
2721
2648
  }
2722
- throw new WorkPaperOperationError(this.messageOf(error, "Mutation failed"));
2649
+ throw new WorkPaperOperationError(this.messageOf(error, 'Mutation failed'));
2723
2650
  }
2724
2651
  const changes = this.computeTrackedChangesWithoutVisibilityCache(this.drainTrackedEngineEvents());
2725
2652
  if (changes.length > 0) {
2726
- this.emitter.emitDetailed({ eventName: "valuesUpdated", payload: { changes } });
2653
+ this.emitter.emitDetailed({ eventName: 'valuesUpdated', payload: { changes } });
2727
2654
  }
2728
2655
  return changes;
2729
2656
  }
@@ -2747,15 +2674,13 @@ export class WorkPaper {
2747
2674
  const changes = this.computeTrackedChangesWithoutVisibilityCache(this.drainTrackedEngineEvents());
2748
2675
  this.flushQueuedEvents();
2749
2676
  if (changes.length > 0) {
2750
- this.emitter.emitDetailed({ eventName: "valuesUpdated", payload: { changes } });
2677
+ this.emitter.emitDetailed({ eventName: 'valuesUpdated', payload: { changes } });
2751
2678
  }
2752
2679
  return changes;
2753
2680
  }
2754
2681
  computeChangesAfterMutation(beforeVisibility, beforeNames) {
2755
2682
  const hasNamedExpressions = this.namedExpressions.size > 0;
2756
- const afterNames = hasNamedExpressions
2757
- ? this.captureNamedExpressionValueSnapshot()
2758
- : EMPTY_NAMED_EXPRESSION_VALUES;
2683
+ const afterNames = hasNamedExpressions ? this.captureNamedExpressionValueSnapshot() : EMPTY_NAMED_EXPRESSION_VALUES;
2759
2684
  const fastPath = this.computeCellChangesFromTrackedEvents(beforeVisibility, this.drainTrackedEngineEvents());
2760
2685
  let cellChanges;
2761
2686
  if (fastPath) {
@@ -2768,9 +2693,7 @@ export class WorkPaper {
2768
2693
  this.visibilityCache = afterVisibility;
2769
2694
  }
2770
2695
  this.namedExpressionValueCache = afterNames;
2771
- return hasNamedExpressions
2772
- ? [...cellChanges, ...this.computeNamedExpressionChanges(beforeNames, afterNames)]
2773
- : cellChanges;
2696
+ return hasNamedExpressions ? [...cellChanges, ...this.computeNamedExpressionChanges(beforeNames, afterNames)] : cellChanges;
2774
2697
  }
2775
2698
  captureChanges(semanticEvent, mutate) {
2776
2699
  this.assertNotDisposed();
@@ -2786,7 +2709,7 @@ export class WorkPaper {
2786
2709
  if (error instanceof Error && WORKPAPER_PUBLIC_ERROR_NAMES.has(error.name)) {
2787
2710
  throw error;
2788
2711
  }
2789
- throw new WorkPaperOperationError(this.messageOf(error, "Mutation failed"));
2712
+ throw new WorkPaperOperationError(this.messageOf(error, 'Mutation failed'));
2790
2713
  }
2791
2714
  if (semanticEvent) {
2792
2715
  this.queuedEvents.push(semanticEvent);
@@ -2794,9 +2717,7 @@ export class WorkPaper {
2794
2717
  return [];
2795
2718
  }
2796
2719
  const beforeVisibility = this.ensureVisibilityCache();
2797
- const beforeNames = this.namedExpressions.size > 0
2798
- ? this.ensureNamedExpressionValueCache()
2799
- : EMPTY_NAMED_EXPRESSION_VALUES;
2720
+ const beforeNames = this.namedExpressions.size > 0 ? this.ensureNamedExpressionValueCache() : EMPTY_NAMED_EXPRESSION_VALUES;
2800
2721
  this.drainTrackedEngineEvents();
2801
2722
  try {
2802
2723
  mutate();
@@ -2805,7 +2726,7 @@ export class WorkPaper {
2805
2726
  if (error instanceof Error && WORKPAPER_PUBLIC_ERROR_NAMES.has(error.name)) {
2806
2727
  throw error;
2807
2728
  }
2808
- throw new WorkPaperOperationError(this.messageOf(error, "Mutation failed"));
2729
+ throw new WorkPaperOperationError(this.messageOf(error, 'Mutation failed'));
2809
2730
  }
2810
2731
  const changes = semanticEvent === undefined
2811
2732
  ? this.computeChangesAfterMutation(beforeVisibility, beforeNames)
@@ -2829,7 +2750,7 @@ export class WorkPaper {
2829
2750
  }
2830
2751
  }
2831
2752
  if (!this.shouldSuppressEvents() && changes.length > 0) {
2832
- this.emitter.emitDetailed({ eventName: "valuesUpdated", payload: { changes } });
2753
+ this.emitter.emitDetailed({ eventName: 'valuesUpdated', payload: { changes } });
2833
2754
  }
2834
2755
  return changes;
2835
2756
  }
@@ -2844,14 +2765,14 @@ export class WorkPaper {
2844
2765
  });
2845
2766
  }
2846
2767
  getUndoStack() {
2847
- const stack = Reflect.get(this.engine, "undoStack");
2768
+ const stack = Reflect.get(this.engine, 'undoStack');
2848
2769
  if (!isHistoryRecordArray(stack)) {
2849
2770
  return [];
2850
2771
  }
2851
2772
  return stack;
2852
2773
  }
2853
2774
  getRedoStack() {
2854
- const stack = Reflect.get(this.engine, "redoStack");
2775
+ const stack = Reflect.get(this.engine, 'redoStack');
2855
2776
  if (!isHistoryRecordArray(stack)) {
2856
2777
  return [];
2857
2778
  }
@@ -2863,9 +2784,9 @@ export class WorkPaper {
2863
2784
  }
2864
2785
  historyTransactionOps(record) {
2865
2786
  switch (record.kind) {
2866
- case "ops":
2787
+ case 'ops':
2867
2788
  return record.ops;
2868
- case "single-op":
2789
+ case 'single-op':
2869
2790
  return [record.op];
2870
2791
  }
2871
2792
  }
@@ -2877,12 +2798,12 @@ export class WorkPaper {
2877
2798
  const entries = undoStack.splice(startIndex);
2878
2799
  const merged = {
2879
2800
  forward: {
2880
- kind: "ops",
2801
+ kind: 'ops',
2881
2802
  ops: entries.flatMap((entry) => this.historyTransactionOps(entry.forward)),
2882
2803
  potentialNewCells: sumNumbers(entries.map((entry) => entry.forward.potentialNewCells)),
2883
2804
  },
2884
2805
  inverse: {
2885
- kind: "ops",
2806
+ kind: 'ops',
2886
2807
  ops: entries.toReversed().flatMap((entry) => this.historyTransactionOps(entry.inverse)),
2887
2808
  potentialNewCells: sumNumbers(entries.map((entry) => entry.inverse.potentialNewCells)),
2888
2809
  },
@@ -2912,7 +2833,7 @@ export class WorkPaper {
2912
2833
  col: targetLeftCorner.col + columnOffset,
2913
2834
  };
2914
2835
  let nextValue = raw;
2915
- if (typeof raw === "string" && raw.startsWith("=")) {
2836
+ if (typeof raw === 'string' && raw.startsWith('=')) {
2916
2837
  nextValue = `=${translateFormulaReferences(raw.slice(1), destination.row - (sourceAnchor.row + rowOffset), destination.col - (sourceAnchor.col + columnOffset))}`;
2917
2838
  }
2918
2839
  this.applyRawContent(destination, nextValue);
@@ -2931,7 +2852,7 @@ export class WorkPaper {
2931
2852
  this.applyCellMutationRefs(refs, {
2932
2853
  captureUndo: true,
2933
2854
  potentialNewCells,
2934
- source: "local",
2855
+ source: 'local',
2935
2856
  returnUndoOps: false,
2936
2857
  reuseRefs: true,
2937
2858
  });
@@ -2954,7 +2875,7 @@ export class WorkPaper {
2954
2875
  }
2955
2876
  this.applyCellMutationRefs(phaseRefs, applyOptions);
2956
2877
  };
2957
- const phaseSource = options.captureUndo === false ? "restore" : "local";
2878
+ const phaseSource = options.captureUndo === false ? 'restore' : 'local';
2958
2879
  if (formulaRefs.length === 0) {
2959
2880
  applyPlannedRefs(refs, {
2960
2881
  captureUndo: options.captureUndo,
@@ -3005,16 +2926,16 @@ export class WorkPaper {
3005
2926
  applyRawContent(address, content) {
3006
2927
  const existingCellIndex = this.engine.workbook.getSheetById(address.sheet)?.grid.get(address.row, address.col) ?? -1;
3007
2928
  const mutation = content === null
3008
- ? { kind: "clearCell", row: address.row, col: address.col }
3009
- : typeof content === "string" && content.trim().startsWith("=")
2929
+ ? { kind: 'clearCell', row: address.row, col: address.col }
2930
+ : typeof content === 'string' && content.trim().startsWith('=')
3010
2931
  ? {
3011
- kind: "setCellFormula",
2932
+ kind: 'setCellFormula',
3012
2933
  row: address.row,
3013
2934
  col: address.col,
3014
2935
  formula: this.rewriteFormulaForStorage(stripLeadingEquals(content), address.sheet),
3015
2936
  }
3016
2937
  : {
3017
- kind: "setCellValue",
2938
+ kind: 'setCellValue',
3018
2939
  row: address.row,
3019
2940
  col: address.col,
3020
2941
  value: content,
@@ -3022,7 +2943,7 @@ export class WorkPaper {
3022
2943
  this.applyCellMutationRefs([{ sheetId: address.sheet, mutation }], {
3023
2944
  captureUndo: true,
3024
2945
  potentialNewCells: content === null || existingCellIndex !== -1 ? 0 : 1,
3025
- source: "local",
2946
+ source: 'local',
3026
2947
  returnUndoOps: false,
3027
2948
  reuseRefs: true,
3028
2949
  });
@@ -3072,8 +2993,7 @@ export class WorkPaper {
3072
2993
  validateCurrentSheetsWithinLimits(nextConfig) {
3073
2994
  this.listSheetRecords().forEach((sheet) => {
3074
2995
  const dimensions = this.getSheetDimensions(sheet.id);
3075
- if (dimensions.height > (nextConfig.maxRows ?? MAX_ROWS) ||
3076
- dimensions.width > (nextConfig.maxColumns ?? MAX_COLS)) {
2996
+ if (dimensions.height > (nextConfig.maxRows ?? MAX_ROWS) || dimensions.width > (nextConfig.maxColumns ?? MAX_COLS)) {
3077
2997
  throw new WorkPaperSheetSizeLimitExceededError();
3078
2998
  }
3079
2999
  });
@@ -3095,7 +3015,7 @@ export class WorkPaper {
3095
3015
  return true;
3096
3016
  }
3097
3017
  canApplyRuntimeOnlyConfigUpdate(changedKeys) {
3098
- return changedKeys.every((key) => key === "useColumnIndex" || key === "useStats");
3018
+ return changedKeys.every((key) => key === 'useColumnIndex' || key === 'useStats');
3099
3019
  }
3100
3020
  applyRuntimeOnlyConfigUpdate(nextConfig) {
3101
3021
  if (this.config.useColumnIndex !== nextConfig.useColumnIndex) {
@@ -3113,9 +3033,7 @@ export class WorkPaper {
3113
3033
  validateSheetWithinLimits(sheetName, sheet, nextConfig);
3114
3034
  });
3115
3035
  }
3116
- const serializedNamedExpressions = canReuseSnapshot
3117
- ? null
3118
- : this.getAllNamedExpressionsSerialized();
3036
+ const serializedNamedExpressions = canReuseSnapshot ? null : this.getAllNamedExpressionsSerialized();
3119
3037
  const suspended = this.evaluationSuspended;
3120
3038
  const clipboard = this.clipboard
3121
3039
  ? {
@@ -3129,7 +3047,7 @@ export class WorkPaper {
3129
3047
  this.namedExpressions.clear();
3130
3048
  }
3131
3049
  this.engine = new SpreadsheetEngine({
3132
- workbookName: "Workbook",
3050
+ workbookName: 'Workbook',
3133
3051
  useColumnIndex: this.config.useColumnIndex,
3134
3052
  trackReplicaVersions: false,
3135
3053
  });
@@ -3165,20 +3083,20 @@ export class WorkPaper {
3165
3083
  }
3166
3084
  }
3167
3085
  normalizeAxisIntervals(startOrInterval, countOrInterval, restIntervals = []) {
3168
- if (typeof startOrInterval === "number") {
3086
+ if (typeof startOrInterval === 'number') {
3169
3087
  if (Array.isArray(countOrInterval)) {
3170
- throw new WorkPaperInvalidArgumentsError("Axis interval count must be a number");
3088
+ throw new WorkPaperInvalidArgumentsError('Axis interval count must be a number');
3171
3089
  }
3172
- const resolvedCount = typeof countOrInterval === "number" ? countOrInterval : 1;
3090
+ const resolvedCount = typeof countOrInterval === 'number' ? countOrInterval : 1;
3173
3091
  return [[startOrInterval, resolvedCount]];
3174
3092
  }
3175
- if (typeof countOrInterval === "number") {
3176
- throw new WorkPaperInvalidArgumentsError("Axis interval count is only valid with a numeric start");
3093
+ if (typeof countOrInterval === 'number') {
3094
+ throw new WorkPaperInvalidArgumentsError('Axis interval count is only valid with a numeric start');
3177
3095
  }
3178
3096
  return [startOrInterval, ...(countOrInterval ? [countOrInterval] : []), ...restIntervals].map(([start, count]) => [start, count ?? 1]);
3179
3097
  }
3180
3098
  normalizeAxisSwapMappings(label, startOrMappings, end) {
3181
- if (typeof startOrMappings === "number") {
3099
+ if (typeof startOrMappings === 'number') {
3182
3100
  if (end === undefined) {
3183
3101
  throw new WorkPaperInvalidArgumentsError(`${label} swap requires two indexes`);
3184
3102
  }
@@ -3193,9 +3111,9 @@ export class WorkPaper {
3193
3111
  this.getDenseRange(range, (address) => address).forEach((row) => {
3194
3112
  row.forEach((address) => {
3195
3113
  this.toDependencyRefs(readDependencies(address)).forEach((dependency) => {
3196
- const key = dependency.kind === "cell"
3114
+ const key = dependency.kind === 'cell'
3197
3115
  ? `cell:${dependency.address.sheet}:${dependency.address.row}:${dependency.address.col}`
3198
- : dependency.kind === "range"
3116
+ : dependency.kind === 'range'
3199
3117
  ? `range:${dependency.range.start.sheet}:${dependency.range.start.row}:${dependency.range.start.col}:${dependency.range.end.row}:${dependency.range.end.col}`
3200
3118
  : `name:${dependency.name}`;
3201
3119
  if (seen.has(key)) {
@@ -3214,10 +3132,10 @@ export class WorkPaper {
3214
3132
  }
3215
3133
  try {
3216
3134
  const transformed = transformFormulaNode(parseFormula(stripLeadingEquals(formula)), (node) => {
3217
- if (node.kind === "NameRef") {
3135
+ if (node.kind === 'NameRef') {
3218
3136
  return this.rewriteNameRefForStorage(node, ownerSheetId);
3219
3137
  }
3220
- if (node.kind === "CallExpr") {
3138
+ if (node.kind === 'CallExpr') {
3221
3139
  return this.rewriteCallForStorage(node);
3222
3140
  }
3223
3141
  return node;
@@ -3225,7 +3143,7 @@ export class WorkPaper {
3225
3143
  return serializeFormula(transformed);
3226
3144
  }
3227
3145
  catch (error) {
3228
- throw new WorkPaperParseError(this.messageOf(error, "Unable to store formula"));
3146
+ throw new WorkPaperParseError(this.messageOf(error, 'Unable to store formula'));
3229
3147
  }
3230
3148
  }
3231
3149
  restorePublicFormula(formula, ownerSheetId) {
@@ -3233,10 +3151,10 @@ export class WorkPaper {
3233
3151
  return formula;
3234
3152
  }
3235
3153
  const transformed = transformFormulaNode(parseFormula(formula), (node) => {
3236
- if (node.kind === "NameRef") {
3154
+ if (node.kind === 'NameRef') {
3237
3155
  return this.rewriteNameRefForPublic(node, ownerSheetId);
3238
3156
  }
3239
- if (node.kind === "CallExpr") {
3157
+ if (node.kind === 'CallExpr') {
3240
3158
  return this.rewriteCallForPublic(node);
3241
3159
  }
3242
3160
  return node;
@@ -3320,12 +3238,12 @@ export class WorkPaper {
3320
3238
  }
3321
3239
  }
3322
3240
  toDefinedNameSnapshot(expression, scope) {
3323
- if (expression === null || typeof expression === "number" || typeof expression === "boolean") {
3241
+ if (expression === null || typeof expression === 'number' || typeof expression === 'boolean') {
3324
3242
  return expression;
3325
3243
  }
3326
- if (typeof expression === "string" && expression.trim().startsWith("=")) {
3244
+ if (typeof expression === 'string' && expression.trim().startsWith('=')) {
3327
3245
  return {
3328
- kind: "formula",
3246
+ kind: 'formula',
3329
3247
  formula: `=${this.rewriteFormulaForStorage(stripLeadingEquals(expression), scope ?? this.listSheetRecords()[0]?.id ?? 1)}`,
3330
3248
  };
3331
3249
  }
@@ -3340,10 +3258,10 @@ export class WorkPaper {
3340
3258
  }
3341
3259
  evaluateNamedExpression(expression) {
3342
3260
  const raw = expression.expression;
3343
- if (raw === null || typeof raw === "number" || typeof raw === "boolean") {
3261
+ if (raw === null || typeof raw === 'number' || typeof raw === 'boolean') {
3344
3262
  return scalarValueFromLiteral(raw);
3345
3263
  }
3346
- if (typeof raw === "string" && !raw.trim().startsWith("=")) {
3264
+ if (typeof raw === 'string' && !raw.trim().startsWith('=')) {
3347
3265
  return scalarValueFromLiteral(raw);
3348
3266
  }
3349
3267
  return this.calculateFormula(raw, expression.scope);
@@ -3372,7 +3290,7 @@ export class WorkPaper {
3372
3290
  try {
3373
3291
  const parsedCell = parseCellAddress(value);
3374
3292
  return {
3375
- kind: "cell",
3293
+ kind: 'cell',
3376
3294
  address: {
3377
3295
  sheet: this.requireSheetId(parsedCell.sheetName ?? this.listSheetRecords()[0].name),
3378
3296
  row: parsedCell.row,
@@ -3383,9 +3301,9 @@ export class WorkPaper {
3383
3301
  catch {
3384
3302
  try {
3385
3303
  const parsedRange = parseRangeAddress(value);
3386
- if (parsedRange.kind === "cells") {
3304
+ if (parsedRange.kind === 'cells') {
3387
3305
  return {
3388
- kind: "range",
3306
+ kind: 'range',
3389
3307
  range: {
3390
3308
  start: {
3391
3309
  sheet: this.requireSheetId(parsedRange.sheetName ?? this.listSheetRecords()[0].name),
@@ -3402,10 +3320,10 @@ export class WorkPaper {
3402
3320
  }
3403
3321
  }
3404
3322
  catch {
3405
- return { kind: "name", name: value };
3323
+ return { kind: 'name', name: value };
3406
3324
  }
3407
3325
  }
3408
- return { kind: "name", name: value };
3326
+ return { kind: 'name', name: value };
3409
3327
  });
3410
3328
  }
3411
3329
  messageOf(error, fallback) {
@@ -3419,7 +3337,7 @@ function cloneNamedExpressionValue(value) {
3419
3337
  return value.map((row) => row.map((cell) => cloneCellValue(cell)));
3420
3338
  }
3421
3339
  function compareWorkPaperNamedExpressionChanges(left, right) {
3422
- if (left.kind !== "named-expression" || right.kind !== "named-expression") {
3340
+ if (left.kind !== 'named-expression' || right.kind !== 'named-expression') {
3423
3341
  return 0;
3424
3342
  }
3425
3343
  return (left.scope ?? -1) - (right.scope ?? -1) || left.name.localeCompare(right.name);
@@ -3432,7 +3350,7 @@ function sourceRangeRef(sheetName, range) {
3432
3350
  };
3433
3351
  }
3434
3352
  function sumNumbers(values) {
3435
- const filtered = values.filter((value) => typeof value === "number");
3353
+ const filtered = values.filter((value) => typeof value === 'number');
3436
3354
  if (filtered.length === 0) {
3437
3355
  return undefined;
3438
3356
  }