@univerjs/engine-formula 0.12.4 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/es/facade.js CHANGED
@@ -1,15 +1,15 @@
1
- import { FBase as f, FUniver as d } from "@univerjs/core/facade";
2
- import { Inject as c, ICommandService as p, Injector as _, IConfigService as C } from "@univerjs/core";
3
- import { LexerTreeBuilder as v, SetFormulaCalculationStartMutation as l, SetFormulaCalculationStopMutation as S, SetFormulaCalculationNotificationMutation as m, GlobalComputingStatusService as x, ENGINE_FORMULA_CYCLE_REFERENCE_COUNT as h } from "@univerjs/engine-formula";
4
- import { firstValueFrom as g, race as E, filter as F, timer as B, map as I } from "rxjs";
5
- var T = Object.getOwnPropertyDescriptor, N = (e, t, r, i) => {
6
- for (var o = i > 1 ? void 0 : i ? T(t, r) : t, a = e.length - 1, u; a >= 0; a--)
7
- (u = e[a]) && (o = u(o) || o);
8
- return o;
9
- }, n = (e, t) => (r, i) => t(r, i, e);
10
- let s = class extends f {
11
- constructor(e, t, r, i) {
12
- super(), this._commandService = e, this._injector = t, this._lexerTreeBuilder = r, this._configService = i, this._initialize();
1
+ import { FBase as h, FUniver as S } from "@univerjs/core/facade";
2
+ import { Inject as c, ICommandService as _, Injector as v, IConfigService as g } from "@univerjs/core";
3
+ import { LexerTreeBuilder as x, SetFormulaCalculationStartMutation as d, SetFormulaCalculationStopMutation as E, SetFormulaCalculationNotificationMutation as p, GlobalComputingStatusService as F, ENGINE_FORMULA_CYCLE_REFERENCE_COUNT as T, SetFormulaCalculationResultMutation as y, SetFormulaStringBatchCalculationResultMutation as w, SetFormulaStringBatchCalculationMutation as R, SetFormulaDependencyCalculationResultMutation as M, SetFormulaDependencyCalculationMutation as b, SetCellFormulaDependencyCalculationResultMutation as D, SetCellFormulaDependencyCalculationMutation as I, SetQueryFormulaDependencyResultMutation as f, SetQueryFormulaDependencyMutation as C } from "@univerjs/engine-formula";
4
+ import { firstValueFrom as P, race as B, filter as L, timer as N, map as O } from "rxjs";
5
+ var A = Object.getOwnPropertyDescriptor, j = (e, t, i, r) => {
6
+ for (var n = r > 1 ? void 0 : r ? A(t, i) : t, a = e.length - 1, o; a >= 0; a--)
7
+ (o = e[a]) && (n = o(n) || n);
8
+ return n;
9
+ }, u = (e, t) => (i, r) => t(i, r, e);
10
+ let m = class extends h {
11
+ constructor(e, t, i, r) {
12
+ super(), this._commandService = e, this._injector = t, this._lexerTreeBuilder = i, this._configService = r, this._initialize();
13
13
  }
14
14
  /**
15
15
  * @ignore
@@ -38,8 +38,8 @@ let s = class extends f {
38
38
  * console.log(result);
39
39
  * ```
40
40
  */
41
- moveFormulaRefOffset(e, t, r, i) {
42
- return this._lexerTreeBuilder.moveFormulaRefOffset(e, t, r, i);
41
+ moveFormulaRefOffset(e, t, i, r) {
42
+ return this._lexerTreeBuilder.moveFormulaRefOffset(e, t, i, r);
43
43
  }
44
44
  /**
45
45
  * Resolves the formula string to a 'node' node
@@ -66,7 +66,7 @@ let s = class extends f {
66
66
  * ```
67
67
  */
68
68
  executeCalculation() {
69
- this._commandService.executeCommand(l.id, { commands: [], forceCalculation: !0 }, { onlyLocal: !0 });
69
+ this._commandService.executeCommand(d.id, { commands: [], forceCalculation: !0 }, { onlyLocal: !0 });
70
70
  }
71
71
  /**
72
72
  * Stop the calculation of the formula.
@@ -78,7 +78,7 @@ let s = class extends f {
78
78
  * ```
79
79
  */
80
80
  stopCalculation() {
81
- this._commandService.executeCommand(S.id, {});
81
+ this._commandService.executeCommand(E.id, {});
82
82
  }
83
83
  /**
84
84
  * Listening calculation starts.
@@ -95,9 +95,9 @@ let s = class extends f {
95
95
  */
96
96
  calculationStart(e) {
97
97
  return this._commandService.onCommandExecuted((t) => {
98
- if (t.id === l.id) {
99
- const r = t.params;
100
- e(r.forceCalculation);
98
+ if (t.id === d.id) {
99
+ const i = t.params;
100
+ e(i.forceCalculation);
101
101
  }
102
102
  });
103
103
  }
@@ -116,10 +116,10 @@ let s = class extends f {
116
116
  */
117
117
  calculationEnd(e) {
118
118
  return this._commandService.onCommandExecuted((t) => {
119
- if (t.id !== m.id)
119
+ if (t.id !== p.id)
120
120
  return;
121
- const r = t.params;
122
- r.functionsExecutedState !== void 0 && e(r.functionsExecutedState);
121
+ const i = t.params;
122
+ i.functionsExecutedState !== void 0 && e(i.functionsExecutedState);
123
123
  });
124
124
  }
125
125
  /**
@@ -139,10 +139,10 @@ let s = class extends f {
139
139
  * ```
140
140
  */
141
141
  whenComputingCompleteAsync(e) {
142
- const t = this._injector.get(x);
143
- return t.computingStatus ? Promise.resolve(!0) : g(E(
144
- t.computingStatus$.pipe(F((r) => r)),
145
- B(e != null ? e : 3e4).pipe(I(() => !1))
142
+ const t = this._injector.get(F);
143
+ return t.computingStatus ? Promise.resolve(!0) : P(B(
144
+ t.computingStatus$.pipe(L((i) => i)),
145
+ N(e != null ? e : 3e4).pipe(O(() => !1))
146
146
  ));
147
147
  }
148
148
  /**
@@ -151,10 +151,10 @@ let s = class extends f {
151
151
  */
152
152
  onCalculationEnd() {
153
153
  return new Promise((e, t) => {
154
- const r = setTimeout(() => {
154
+ const i = setTimeout(() => {
155
155
  t(new Error("Calculation end timeout"));
156
- }, 3e4), i = this.calculationEnd(() => {
157
- clearTimeout(r), i.dispose(), e();
156
+ }, 3e4), r = this.calculationEnd(() => {
157
+ clearTimeout(i), r.dispose(), e();
158
158
  });
159
159
  });
160
160
  }
@@ -173,10 +173,10 @@ let s = class extends f {
173
173
  */
174
174
  calculationProcessing(e) {
175
175
  return this._commandService.onCommandExecuted((t) => {
176
- if (t.id !== m.id)
176
+ if (t.id !== p.id)
177
177
  return;
178
- const r = t.params;
179
- r.stageInfo !== void 0 && e(r.stageInfo);
178
+ const i = t.params;
179
+ i.stageInfo !== void 0 && e(i.stageInfo);
180
180
  });
181
181
  }
182
182
  /**
@@ -192,21 +192,374 @@ let s = class extends f {
192
192
  * ```
193
193
  */
194
194
  setMaxIteration(e) {
195
- this._configService.setConfig(h, e);
195
+ this._configService.setConfig(T, e);
196
+ }
197
+ /**
198
+ * Listens for the moment when formula-calculation results are applied.
199
+ *
200
+ * This event fires after the engine completes a calculation cycle and
201
+ * dispatches a `SetFormulaCalculationResultMutation`.
202
+ * The callback is invoked during an idle frame to avoid blocking UI updates.
203
+ *
204
+ * @param {Function} callback - A function called with the calculation result payload
205
+ * once the result-application mutation is emitted.
206
+ * @returns {IDisposable} A disposable used to unsubscribe from the event.
207
+ *
208
+ * @example
209
+ * ```ts
210
+ * const formulaEngine = univerAPI.getFormula();
211
+ *
212
+ * const dispose = formulaEngine.calculationResultApplied((result) => {
213
+ * console.log('Calculation results applied:', result);
214
+ * });
215
+ *
216
+ * // Later…
217
+ * dispose.dispose();
218
+ * ```
219
+ */
220
+ calculationResultApplied(e) {
221
+ return this._commandService.onCommandExecuted((t) => {
222
+ if (t.id !== y.id)
223
+ return;
224
+ const i = t.params;
225
+ i !== void 0 && requestIdleCallback(() => {
226
+ e(i);
227
+ });
228
+ });
229
+ }
230
+ /**
231
+ * Waits for formula-calculation results to be applied.
232
+ *
233
+ * This method resolves under three conditions:
234
+ * 1. A real calculation runs and the engine emits a "calculation started" signal,
235
+ * followed by a "calculation result applied" signal.
236
+ * 2. No calculation actually starts within 500 ms — the method assumes there is
237
+ * nothing to wait for and resolves automatically.
238
+ * 3. A global 30 s timeout triggers, in which case the promise rejects.
239
+ *
240
+ * The API internally listens to both “calculation in progress” events and
241
+ * “calculation result applied” events, ensuring it behaves correctly whether
242
+ * formulas are recalculated or skipped due to cache/state.
243
+ *
244
+ * @returns {Promise<void>} A promise that resolves when calculation results are applied
245
+ * or when no calculation occurs within the start-detection window.
246
+ *
247
+ * @example
248
+ * ```ts
249
+ * const formulaEngine = univerAPI.getFormula();
250
+ *
251
+ * // Wait for formula updates to apply before reading values.
252
+ * await formulaEngine.onCalculationResultApplied();
253
+ *
254
+ * const value = sheet.getRange("C24").getValue();
255
+ * console.log("Updated value:", value);
256
+ * ```
257
+ */
258
+ onCalculationResultApplied() {
259
+ return new Promise((e, t) => {
260
+ let i = !1, r = !1;
261
+ const n = setTimeout(() => {
262
+ l(), t(new Error("Calculation end timeout"));
263
+ }, 3e4), a = setTimeout(() => {
264
+ i || (l(), e());
265
+ }, 500), o = this.calculationProcessing(() => {
266
+ i || (i = !0, clearTimeout(a));
267
+ }), s = this.calculationResultApplied(() => {
268
+ r || (r = !0, l(), e());
269
+ });
270
+ function l() {
271
+ clearTimeout(n), clearTimeout(a), o.dispose(), s.dispose();
272
+ }
273
+ });
274
+ }
275
+ /**
276
+ * Execute a batch of formulas asynchronously and receive computed results.
277
+ *
278
+ * Each formula cell is represented as a string array:
279
+ * [fullFormula, ...subFormulas]
280
+ *
281
+ * Where:
282
+ * - fullFormula (index 0) is the complete formula expression written in the cell.
283
+ * Example: "=SUM(A1:A10) + SQRT(D7)".
284
+ *
285
+ * - subFormulas (index 1+) are **optional decomposed expressions** extracted from
286
+ * the full formula. Each of them can be independently computed by the formula engine.
287
+ *
288
+ * These sub-expressions can include:
289
+ * - Single-cell references: "A2", "B2", "C5"
290
+ * - Range references: "A1:A10"
291
+ * - Function calls: "SQRT(D7)", "ABS(A2-B2)"
292
+ * - Any sub-formula that was parsed out of the original formula and can be
293
+ * evaluated on its own.
294
+ *
295
+ * The batch execution engine may use these sub-formulas for dependency resolution,
296
+ * incremental computation, or performance optimizations.
297
+ *
298
+ * @param {IFormulaStringMap} formulas
299
+ * Nested structure (unit → sheet → row → column) describing formulas and
300
+ * their decomposed sub-expressions.
301
+ *
302
+ * @param {number} [timeout]
303
+ * Optional timeout in milliseconds. If no result is received within this
304
+ * period, the promise will be rejected.
305
+ *
306
+ * @returns {Promise<IFormulaExecuteResultMap>}
307
+ * A promise that resolves with the computed value map mirroring
308
+ * the input structure.
309
+ *
310
+ * @example
311
+ * ```ts
312
+ * const formulaEngine = univerAPI.getFormula();
313
+ * const formulas = {
314
+ * Book1: {
315
+ * Sheet1: {
316
+ * 2: {
317
+ * 3: [
318
+ * // Full formula:
319
+ * "=SUM(A1:A10) + SQRT(D7)",
320
+ *
321
+ * // Decomposed sub-formulas (each one can be evaluated independently):
322
+ * "SUM(A1:A10)", // sub-formula 1
323
+ * "SQRT(D7)", // sub-formula 2
324
+ * "A1:A10", // range reference
325
+ * "D7", // single-cell reference
326
+ * ],
327
+ * },
328
+ * 4: {
329
+ * 5: [
330
+ * "=A2 + B2 + SQRT(C5)",
331
+ * "A2",
332
+ * "B2",
333
+ * "SQRT(C5)",
334
+ * ],
335
+ * }
336
+ * },
337
+ * },
338
+ * };
339
+ *
340
+ * const result = await formulaEngine.executeFormulas(formulas);
341
+ * console.log(result);
342
+ * ```
343
+ */
344
+ executeFormulas(e, t = 3e4) {
345
+ return new Promise((i, r) => {
346
+ const n = this._commandService.onCommandExecuted((o) => {
347
+ if (o.id !== w.id)
348
+ return;
349
+ const s = o.params;
350
+ clearTimeout(a), n.dispose(), s.result != null ? i(s.result) : r(new Error("Formula batch calculation returned no result"));
351
+ }), a = setTimeout(() => {
352
+ n.dispose(), r(new Error("Formula batch calculation timeout"));
353
+ }, t);
354
+ this._commandService.executeCommand(
355
+ R.id,
356
+ { formulas: e },
357
+ { onlyLocal: !0 }
358
+ );
359
+ });
360
+ }
361
+ /**
362
+ * Retrieve all formula dependency trees that were produced during the latest
363
+ * dependency-analysis run. This triggers a local dependency-calculation command
364
+ * and returns the complete set of dependency trees once the calculation finishes.
365
+ *
366
+ * @param {number} [timeout]
367
+ * Optional timeout in milliseconds. If no result is received within this
368
+ * period, the promise will be rejected.
369
+ *
370
+ * @returns {Promise<IFormulaDependencyTreeJson[]>}
371
+ * A promise that resolves with the array of dependency trees.
372
+ *
373
+ * @example
374
+ * ```ts
375
+ * const formulaEngine = univerAPI.getFormula();
376
+ *
377
+ * // Fetch all dependency trees generated for the current workbook.
378
+ * const trees = await formulaEngine.getAllDependencyTrees();
379
+ * console.log('All dependency trees:', trees);
380
+ * ```
381
+ */
382
+ getAllDependencyTrees(e = 3e4) {
383
+ return new Promise((t, i) => {
384
+ const r = this._commandService.onCommandExecuted((a) => {
385
+ if (a.id !== M.id)
386
+ return;
387
+ const o = a.params;
388
+ clearTimeout(n), r.dispose(), o.result != null ? t(o.result) : t([]);
389
+ }), n = setTimeout(() => {
390
+ r.dispose(), i(new Error("Formula dependency calculation timeout"));
391
+ }, e);
392
+ this._commandService.executeCommand(
393
+ b.id,
394
+ void 0,
395
+ { onlyLocal: !0 }
396
+ );
397
+ });
398
+ }
399
+ /**
400
+ * Retrieve the dependency tree of a specific cell. This triggers a local
401
+ * dependency-calculation command for the given unit, sheet, and cell location,
402
+ * and returns the computed dependency tree when the calculation is completed.
403
+ *
404
+ * @param param The target cell location:
405
+ * - `unitId` The workbook ID.
406
+ * - `sheetId` The sheet ID.
407
+ * - `row` The zero-based row index.
408
+ * - `column` The zero-based column index.
409
+ *
410
+ * @param {number} [timeout]
411
+ * Optional timeout in milliseconds. If no result is received within this
412
+ * period, the promise will be rejected.
413
+ *
414
+ * @returns {Promise<IFormulaDependencyTreeFullJson | undefined>}
415
+ * A promise that resolves with the dependency tree or `undefined`
416
+ * if no tree exists for that cell.
417
+ *
418
+ * @example
419
+ * ```ts
420
+ * const formulaEngine = univerAPI.getFormula();
421
+ *
422
+ * // Query the dependency tree for cell B2 in a specific sheet.
423
+ * const tree = await formulaEngine.getCellDependencyTree({
424
+ * unitId: 'workbook1',
425
+ * sheetId: 'sheet1',
426
+ * row: 1,
427
+ * column: 1,
428
+ * });
429
+ *
430
+ * console.log('Cell dependency tree:', tree);
431
+ * ```
432
+ */
433
+ getCellDependencyTree(e, t = 3e4) {
434
+ return new Promise((i, r) => {
435
+ const n = this._commandService.onCommandExecuted((o) => {
436
+ if (o.id !== D.id)
437
+ return;
438
+ const s = o.params;
439
+ clearTimeout(a), n.dispose(), i(s.result);
440
+ }), a = setTimeout(() => {
441
+ n.dispose(), r(new Error("Cell dependency calculation timeout"));
442
+ }, t);
443
+ this._commandService.executeCommand(
444
+ I.id,
445
+ e,
446
+ { onlyLocal: !0 }
447
+ );
448
+ });
449
+ }
450
+ /**
451
+ * Retrieve the full dependency trees for all formulas that *depend on* the
452
+ * specified ranges. This triggers a local dependency-calculation command and
453
+ * resolves once the calculation completes.
454
+ *
455
+ * @param unitRanges An array of workbook/sheet ranges to query. Each range
456
+ * includes:
457
+ * - `unitId` The workbook ID.
458
+ * - `sheetId` The sheet ID.
459
+ * - `range` The row/column boundaries.
460
+ *
461
+ * @param {number} [timeout]
462
+ * Optional timeout in milliseconds. If no result is received within this
463
+ * period, the promise will be rejected.
464
+ *
465
+ * @returns {Promise<IFormulaDependencyTreeJson[]>}
466
+ * A promise that resolves with an array of `IFormulaDependencyTreeJson`
467
+ * representing formulas and their relationships within the dependency graph.
468
+ *
469
+ * @example
470
+ * ```ts
471
+ * const formulaEngine = univerAPI.getFormula();
472
+ *
473
+ * // Query all formulas that depend on A1:B10 in Sheet1.
474
+ * const dependents = await formulaEngine.getRangeDependents([
475
+ * { unitId: 'workbook1', sheetId: 'sheet1', range: { startRow: 0, endRow: 9, startColumn: 0, endColumn: 1 } }
476
+ * ]);
477
+ *
478
+ * console.log('Dependent formulas:', dependents);
479
+ * ```
480
+ */
481
+ getRangeDependents(e, t = 3e4) {
482
+ return new Promise((i, r) => {
483
+ const n = this._commandService.onCommandExecuted((o) => {
484
+ if (o.id !== f.id)
485
+ return;
486
+ const s = o.params;
487
+ clearTimeout(a), n.dispose(), s.result != null ? i(s.result) : i([]);
488
+ }), a = setTimeout(() => {
489
+ n.dispose(), r(new Error("Range dependents calculation timeout"));
490
+ }, t);
491
+ this._commandService.executeCommand(
492
+ C.id,
493
+ { unitRanges: e },
494
+ { onlyLocal: !0 }
495
+ );
496
+ });
497
+ }
498
+ /**
499
+ * Retrieve the dependency trees of all formulas *inside* the specified ranges.
500
+ * Unlike `getRangeDependents`, this API only returns formulas whose definitions
501
+ * physically reside within the queried ranges.
502
+ *
503
+ * Internally this triggers the same dependency-calculation command but with
504
+ * `isInRange = true`, and the promise resolves when the results are ready.
505
+ *
506
+ * @param unitRanges An array of workbook/sheet ranges defining the lookup
507
+ * boundaries:
508
+ * - `unitId` The workbook ID.
509
+ * - `sheetId` The sheet ID.
510
+ * - `range` The zero-based grid range.
511
+ *
512
+ * @param {number} [timeout]
513
+ * Optional timeout in milliseconds. If no result is received within this
514
+ * period, the promise will be rejected.
515
+ *
516
+ * @returns {Promise<IFormulaDependencyTreeJson[]>}
517
+ * A promise that resolves with an array of `IFormulaDependencyTreeJson`
518
+ * describing every formula found in the provided ranges along with
519
+ * their parent/child relationships.
520
+ *
521
+ * @example
522
+ * ```ts
523
+ * const formulaEngine = univerAPI.getFormula();
524
+ *
525
+ * // Query all formulas that lie within A1:D20 in Sheet1.
526
+ * const formulasInRange = await formulaEngine.getInRangeFormulas([
527
+ * { unitId: 'workbook1', sheetId: 'sheet1', range: { startRow: 0, endRow: 19, startColumn: 0, endColumn: 3 } }
528
+ * ]);
529
+ *
530
+ * console.log('Formulas inside range:', formulasInRange);
531
+ * ```
532
+ */
533
+ getInRangeFormulas(e, t = 3e4) {
534
+ return new Promise((i, r) => {
535
+ const n = this._commandService.onCommandExecuted((o) => {
536
+ if (o.id !== f.id)
537
+ return;
538
+ const s = o.params;
539
+ clearTimeout(a), n.dispose(), s.result != null ? i(s.result) : i([]);
540
+ }), a = setTimeout(() => {
541
+ n.dispose(), r(new Error("In-range formulas calculation timeout"));
542
+ }, t);
543
+ this._commandService.executeCommand(
544
+ C.id,
545
+ { unitRanges: e, isInRange: !0 },
546
+ { onlyLocal: !0 }
547
+ );
548
+ });
196
549
  }
197
550
  };
198
- s = N([
199
- n(0, c(p)),
200
- n(1, c(_)),
201
- n(2, c(v)),
202
- n(3, C)
203
- ], s);
204
- class O extends d {
551
+ m = j([
552
+ u(0, c(_)),
553
+ u(1, c(v)),
554
+ u(2, c(x)),
555
+ u(3, g)
556
+ ], m);
557
+ class U extends S {
205
558
  getFormula() {
206
- return this._injector.createInstance(s);
559
+ return this._injector.createInstance(m);
207
560
  }
208
561
  }
209
- d.extend(O);
562
+ S.extend(U);
210
563
  export {
211
- s as FFormula
564
+ m as FFormula
212
565
  };