fix(formula): add graph api (#6313)

This commit is contained in:
Univer
2025-12-15 19:43:02 +08:00
committed by GitHub
parent b485708076
commit b2a757b6a7
15 changed files with 242 additions and 39 deletions
+9 -1
View File
@@ -26,6 +26,7 @@ import type {
ObjectMatrix,
Styles,
} from '@univerjs/core';
import type { sequenceNodeType } from '../engine/utils/sequence';
import type { IImageFormulaInfo } from '../engine/value-object/primitive-object';
export const ERROR_VALUE_OBJECT_CLASS_TYPE = 'errorValueObject';
@@ -134,7 +135,7 @@ export interface IUnitImageFormulaDataType {
[unitId: string]: Nullable<{ [sheetId: string]: ObjectMatrix<Nullable<IImageFormulaInfo>> }>;
}
export interface IArrayFormulaUnitCellType extends IRuntimeUnitDataPrimitiveType {}
export interface IArrayFormulaUnitCellType extends IRuntimeUnitDataPrimitiveType { }
export interface IFormulaData {
[unitId: string]: Nullable<{ [sheetId: string]: Nullable<IObjectMatrixPrimitiveType<Nullable<IFormulaDataItem>>> }>;
@@ -223,6 +224,7 @@ export interface IFormulaDatasetConfig {
unitStylesData?: IUnitStylesData;
unitSheetNameMap?: IUnitSheetNameMap;
maxIteration?: number;
isCalculateTreeModel?: boolean;
rowData?: IUnitRowData; // Include rows hidden by filters
}
@@ -230,3 +232,9 @@ export enum ConcatenateType {
FRONT,
BACK,
}
export interface IExprTreeNode {
value: string;
children: IExprTreeNode[];
type?: sequenceNodeType;
}
@@ -93,7 +93,7 @@ export class CalculateController extends Disposable {
private async _calculate(
formulaDirtyData: Partial<IFormulaDirtyData>
) {
const { forceCalculation: forceCalculate = false, dirtyRanges = [], dirtyNameMap = {}, dirtyDefinedNameMap = {}, dirtyUnitFeatureMap = {}, dirtyUnitOtherFormulaMap = {}, clearDependencyTreeCache = {}, maxIteration = DEFAULT_CYCLE_REFERENCE_COUNT, rowData } = formulaDirtyData;
const { forceCalculation: forceCalculate = false, dirtyRanges = [], dirtyNameMap = {}, dirtyDefinedNameMap = {}, dirtyUnitFeatureMap = {}, dirtyUnitOtherFormulaMap = {}, clearDependencyTreeCache = {}, maxIteration = DEFAULT_CYCLE_REFERENCE_COUNT, rowData, isCalculateTreeModel = false } = formulaDirtyData;
const formulaData = this._formulaDataModel.getFormulaData();
const arrayFormulaCellData = this._formulaDataModel.getArrayFormulaCellData();
@@ -112,6 +112,7 @@ export class CalculateController extends Disposable {
dirtyUnitOtherFormulaMap,
clearDependencyTreeCache,
maxIteration,
isCalculateTreeModel,
rowData,
});
}
@@ -229,7 +230,7 @@ export class CalculateController extends Disposable {
}
private async _applyResult(data: IAllRuntimeData) {
const { unitData, unitOtherData, arrayFormulaRange, arrayFormulaCellData, clearArrayFormulaCellData, arrayFormulaEmbedded, imageFormulaData } = data;
const { unitData, unitOtherData, arrayFormulaRange, arrayFormulaCellData, clearArrayFormulaCellData, arrayFormulaEmbedded, imageFormulaData, dependencyTreeModelData } = data;
if (!unitData) {
console.error('No sheetData from Formula Engine!');
@@ -267,6 +268,18 @@ export class CalculateController extends Disposable {
);
}
if (dependencyTreeModelData.length > 0) {
this._commandService.executeCommand(
SetFormulaDependencyCalculationResultMutation.id,
{
result: dependencyTreeModelData,
},
{
onlyLocal: true,
}
);
}
this._commandService.executeCommand(
SetFormulaCalculationResultMutation.id,
{
@@ -24,6 +24,8 @@ export const DEFAULT_CYCLE_REFERENCE_COUNT = 1;
export const ENGINE_FORMULA_CYCLE_REFERENCE_COUNT = 'CYCLE_REFERENCE_COUNT';
export const ENGINE_FORMULA_RETURN_DEPENDENCY_TREE = 'RETURN_DEPENDENCY_TREE';
export const configSymbol = Symbol(ENGINE_FORMULA_PLUGIN_CONFIG_KEY);
export interface IUniverEngineFormulaConfig {
@@ -15,7 +15,7 @@
*/
import type { IRange, Nullable } from '@univerjs/core';
import type { IDirtyUnitSheetDefinedNameMap } from '../../basics/common';
import type { IDirtyUnitSheetDefinedNameMap, IExprTreeNode, ISuperTable } from '../../basics/common';
import type { IFunctionNames } from '../../basics/function';
import type { IDefinedNamesServiceParam } from '../../services/defined-names.service';
@@ -1951,4 +1951,14 @@ export class LexerTreeBuilder extends Disposable {
getNewFormulaWithPrefix(formulaString: string, hasFunction: (functionToken: IFunctionNames) => boolean): string | null {
return null;
}
getFormulaExprTree(
formulaString: string,
unitId: string,
hasFunction: (functionToken: IFunctionNames) => boolean,
getDefinedNameName: (unitId: string, name: string) => Nullable<IDefinedNamesServiceParam>,
getTable: (unitId: string, tableName: string) => Nullable<ISuperTable>
): IExprTreeNode | null {
return null;
}
}
@@ -39,6 +39,7 @@ import { ErrorValueObject } from '../value-object/base-value-object';
import { BaseAstNode } from './base-ast-node';
import { BaseAstNodeFactory, DEFAULT_AST_NODE_FACTORY_Z_INDEX } from './base-ast-node-factory';
import { NODE_ORDER_MAP, NodeType } from './node-type';
import { splitTableStructuredRef } from '../utils/reference';
export class ReferenceNode extends BaseAstNode {
private _refOffsetX = 0;
@@ -187,6 +188,12 @@ export class ReferenceNodeFactory extends BaseAstNodeFactory {
const makeRef = (type: ReferenceObjectType) =>
new ReferenceNode(currentConfigService, runtimeService, tokenTrim, type, isPrepareMerge);
const tableMap = this._getTableMap();
const isSuperTableDirect = tableMap?.has(tokenTrim) ?? false;
if (isSuperTableDirect) {
return this._getTableReferenceNode(tokenTrim, isLexerNode, isPrepareMerge, true);
}
const isCellRange = regexTestSingeRange(tokenTrim);
if (isCellRange) {
return makeRef(ReferenceObjectType.CELL);
@@ -203,12 +210,6 @@ export class ReferenceNodeFactory extends BaseAstNodeFactory {
return makeRef(ReferenceObjectType.COLUMN);
}
const tableMap = this._getTableMap();
const isSuperTableDirect = tableMap?.has(tokenTrim) ?? false;
if (isSuperTableDirect) {
return this._getTableReferenceNode(tokenTrim, isLexerNode, isPrepareMerge, true);
}
return this._getTableReferenceNode(tokenTrim, isLexerNode, isPrepareMerge, false);
}
@@ -216,7 +217,7 @@ export class ReferenceNodeFactory extends BaseAstNodeFactory {
if (!this._checkTokenIsTableReference(tokenTrim) && !isSuperTableDirectly) {
return;
}
const { tableName, columnStruct } = this._splitTableStructuredRef(tokenTrim);
const { tableName, columnStruct } = splitTableStructuredRef(tokenTrim);
const tableMap = this._getTableMap();
if (!isLexerNode && tableMap?.has(tableName)) {
const columnDataString = columnStruct;
@@ -233,17 +234,6 @@ export class ReferenceNodeFactory extends BaseAstNodeFactory {
}
}
private _splitTableStructuredRef(ref: string) {
const idx = ref.indexOf('[');
if (idx === -1) {
return { tableName: ref, struct: '' };
}
return {
tableName: ref.slice(0, idx),
columnStruct: ref.slice(idx), // 包含外层 [[...]]
};
}
private _checkTokenIsTableReference(token: string): boolean {
return regexTestReferenceTableAllColumn(token) || regexTestReferenceTableSingleColumn(token) || regexTestReferenceTableMultipleColumn(token) || regexTestReferenceTableTitleOnlyAnyHash(token);
}
@@ -56,7 +56,7 @@ export function generateRandomDependencyTreeId(dependencyManagerService: IDepend
}
export interface IFormulaDependencyGenerator {
generate(): Promise<IFormulaDependencyTree[]>;
generate(isCalculateTreeModel?: boolean): Promise<IFormulaDependencyTree[]>;
getAllDependencyJson(): Promise<IFormulaDependencyTreeJson[]>;
getCellDependencyJson(unitId: string, sheetId: string, row: number, column: number): Promise<IFormulaDependencyTreeFullJson | undefined>;
getRangeDependents(unitRanges: IUnitRange[]): Promise<IFormulaDependencyTreeJson[]>;
@@ -91,7 +91,7 @@ export class FormulaDependencyGenerator extends Disposable {
FORMULA_AST_CACHE.clear();
}
async generate() {
async generate(isCalculateTreeModel = false) {
this._updateRangeFlatten();
// const formulaInterpreter = Interpreter.create(interpreterDatasetConfig);
@@ -122,6 +122,12 @@ export class FormulaDependencyGenerator extends Disposable {
const treeList = await this._generateTreeList(formulaData, otherFormulaData, unitData);
if (isCalculateTreeModel) {
this._runtimeService.setDependencyTreeModelData(
this._getAllDependencyJson(treeList)
);
}
const updateTreeList = this._getUpdateTreeListAndMakeDependency(treeList);
let finalTreeList = this._calculateRunList(updateTreeList);
@@ -1376,9 +1382,7 @@ export class FormulaDependencyGenerator extends Disposable {
}
async getAllDependencyJson(): Promise<IFormulaDependencyTreeJson[]> {
const treeList = await this._getAllTreeList();
protected _getAllDependencyJson(treeList: IFormulaDependencyTree[]): IFormulaDependencyTreeJson[] {
this._startFormulaDependencyTreeModel();
const results: FormulaDependencyTreeModel[] = [];
@@ -1399,6 +1403,14 @@ export class FormulaDependencyGenerator extends Disposable {
return resultsJson;
}
async getAllDependencyJson(): Promise<IFormulaDependencyTreeJson[]> {
const treeList = await this._getAllTreeList();
const resultsJson = this._getAllDependencyJson(treeList);
return resultsJson;
}
protected _setRealFormulaString(treeModel: FormulaDependencyTreeModel) {
if (!treeModel.refTreeId) {
return;
@@ -464,3 +464,14 @@ function startsWithNonAlphabetic(name: string) {
// Check if the first character is not a letter (including non-English characters)
return !/^\p{Letter}/u.test(name.charAt(0));
}
export function splitTableStructuredRef(ref: string) {
const idx = ref.indexOf('[');
if (idx === -1) {
return { tableName: ref, struct: '' };
}
return {
tableName: ref.slice(0, idx),
columnStruct: ref.slice(idx), // include [[...]]
};
}
@@ -24,6 +24,7 @@ export enum sequenceNodeType {
REFERENCE,
ARRAY,
DEFINED_NAME,
TABLE,
}
export interface ISequenceNode {
+126 -3
View File
@@ -15,10 +15,10 @@
*/
import type { ICommandInfo, IDisposable, IUnitRange } from '@univerjs/core';
import type { FormulaExecutedStateType, IExecutionInProgressParams, IFormulaDependencyTreeFullJson, IFormulaDependencyTreeJson, IFormulaExecuteResultMap, IFormulaStringMap, ISequenceNode, ISetCellFormulaDependencyCalculationResultMutation, ISetFormulaCalculationNotificationMutation, ISetFormulaCalculationResultMutation, ISetFormulaCalculationStartMutation, ISetFormulaDependencyCalculationResultMutation, ISetFormulaStringBatchCalculationResultMutation } from '@univerjs/engine-formula';
import type { FormulaExecutedStateType, IExecutionInProgressParams, IExprTreeNode, IFormulaDependencyTreeFullJson, IFormulaDependencyTreeJson, IFormulaExecuteResultMap, IFormulaStringMap, ISequenceNode, ISetCellFormulaDependencyCalculationResultMutation, ISetFormulaCalculationNotificationMutation, ISetFormulaCalculationResultMutation, ISetFormulaCalculationStartMutation, ISetFormulaDependencyCalculationResultMutation, ISetFormulaStringBatchCalculationResultMutation } from '@univerjs/engine-formula';
import { ICommandService, IConfigService, Inject, Injector } from '@univerjs/core';
import { FBase } from '@univerjs/core/facade';
import { ENGINE_FORMULA_CYCLE_REFERENCE_COUNT, GlobalComputingStatusService, LexerTreeBuilder, SetCellFormulaDependencyCalculationMutation, SetCellFormulaDependencyCalculationResultMutation, SetFormulaCalculationNotificationMutation, SetFormulaCalculationResultMutation, SetFormulaCalculationStartMutation, SetFormulaCalculationStopMutation, SetFormulaDependencyCalculationMutation, SetFormulaDependencyCalculationResultMutation, SetFormulaStringBatchCalculationMutation, SetFormulaStringBatchCalculationResultMutation, SetQueryFormulaDependencyMutation, SetQueryFormulaDependencyResultMutation } from '@univerjs/engine-formula';
import { ENGINE_FORMULA_CYCLE_REFERENCE_COUNT, ENGINE_FORMULA_RETURN_DEPENDENCY_TREE, GlobalComputingStatusService, IDefinedNamesService, IFunctionService, ISuperTableService, LexerTreeBuilder, SetCellFormulaDependencyCalculationMutation, SetCellFormulaDependencyCalculationResultMutation, SetFormulaCalculationNotificationMutation, SetFormulaCalculationResultMutation, SetFormulaCalculationStartMutation, SetFormulaCalculationStopMutation, SetFormulaDependencyCalculationMutation, SetFormulaDependencyCalculationResultMutation, SetFormulaStringBatchCalculationMutation, SetFormulaStringBatchCalculationResultMutation, SetQueryFormulaDependencyMutation, SetQueryFormulaDependencyResultMutation } from '@univerjs/engine-formula';
import { filter, firstValueFrom, map, race, timer } from 'rxjs';
/**
@@ -30,7 +30,11 @@ export class FFormula extends FBase {
@Inject(ICommandService) protected readonly _commandService: ICommandService,
@Inject(Injector) protected readonly _injector: Injector,
@Inject(LexerTreeBuilder) private _lexerTreeBuilder: LexerTreeBuilder,
@IConfigService protected readonly _configService: IConfigService
@IConfigService protected readonly _configService: IConfigService,
@IFunctionService private readonly _functionService: IFunctionService,
@IDefinedNamesService private readonly _definedNamesService: IDefinedNamesService,
@ISuperTableService private readonly _superTableService: ISuperTableService
) {
super();
this._initialize();
@@ -721,4 +725,123 @@ export class FFormula extends FBase {
);
});
}
/**
* Enable or disable emitting formula dependency trees after each formula calculation.
*
* When enabled, the formula engine will emit the dependency trees produced by
* each completed formula calculation through the internal command system.
* Consumers can obtain the result by listening for the corresponding
* calculation-result command.
*
* When disabled, dependency trees will not be emitted.
*
* This option only controls whether dependency trees are exposed.
* It does not affect formula calculation behavior.
*
* @param {boolean} value
* Whether to emit formula dependency trees after calculation.
* - `true`: Emit dependency trees after each calculation.
* - `false`: Do not emit dependency trees (default behavior).
*
* @example
* ```ts
* const formulaEngine = univerAPI.getFormula();
*
* // Enable dependency tree emission
* formulaEngine.setFormulaReturnDependencyTree(true);
*
* // Listen for dependency trees produced by formula calculation
* const trees = await new Promise<IFormulaDependencyTreeJson[]>((resolve, reject) => {
* const timer = setTimeout(() => {
* disposable.dispose();
* reject(new Error('Timeout waiting for formula dependency trees'));
* }, 30_000);
*
* const disposable = commandService.onCommandExecuted((command) => {
* if (command.id !== SetFormulaDependencyCalculationResultMutation.id) {
* return;
* }
*
* clearTimeout(timer);
* disposable.dispose();
*
* const params = command.params as ISetFormulaDependencyCalculationResultMutation;
* resolve(params.result ?? []);
* });
* });
*
* console.log('Dependency trees:', trees);
* ```
*/
setFormulaReturnDependencyTree(value: boolean): void {
this._configService.setConfig(ENGINE_FORMULA_RETURN_DEPENDENCY_TREE, value);
}
/**
* Parse a formula string and return its **formula expression tree**.
*
* This API analyzes the syntactic structure of a formula and builds an
* expression tree that reflects how the formula is composed (functions,
* operators, ranges, and nested expressions), without performing calculation
* or dependency evaluation.
*
* The returned tree is suitable for:
* - Formula structure visualization
* - Explaining complex formulas (e.g. LET / LAMBDA)
* - Debugging or inspecting formula composition
* - Building advanced formula tooling
*
* ---
*
* @example
* ```ts
* const formulaEngine = univerAPI.getFormula();
*
* const formula = '=LET(x,SUM(A1,B1,A1:B10),y,OFFSET(A1:B10,0,1),SUM(x,y)+x)+1';
*
* const exprTree = formulaEngine.getFormulaExpressTree(formula);
*
* console.log(exprTree);
* ```
*
* Example output (simplified):
*
* ```json
* {
* "value": "let(x,sum(A1,B1,A1:B10),y,offset(A1:B10,0,1),sum(x,y)+x)+1",
* "children": [
* {
* "value": "let(x,sum(A1,B1,A1:B10),y,offset(A1:B10,0,1),sum(x,y)+x)",
* "children": [
* {
* "value": "sum(A1,B1,A1:B10)",
* "children": [
* {
* "value": "A1:B10",
* "children": []
* }
* ]
* },
* {
* "value": "offset(A1:B10,0,1)",
* "children": [
* {
* "value": "A1:B10",
* "children": []
* }
* ]
* }
* ]
* }
* ]
* }
* ```
*
* @param formulaString The formula string to parse (with or without leading `=`)
* @returns A formula expression tree describing the hierarchical structure of the formula
*/
getFormulaExpressTree(formulaString: string, unitId: string): IExprTreeNode | null {
return this._lexerTreeBuilder.getFormulaExprTree(formulaString, unitId, this._functionService.hasExecutor.bind(this._functionService), this._definedNamesService.getValueByName.bind(this._definedNamesService), this._superTableService.getTable.bind(this._superTableService));
}
}
+3 -2
View File
@@ -37,7 +37,7 @@ export type {
} from './basics/common';
export { BooleanValue } from './basics/common';
export { type IOtherFormulaData } from './basics/common';
export { type IUnitRowData } from './basics/common';
export type { IExprTreeNode, ISuperTable, IUnitRowData } from './basics/common';
export { isInDirtyRange } from './basics/dirty';
export { ERROR_TYPE_SET, ErrorType } from './basics/error-type';
export { type ISheetFormulaError } from './basics/error-type';
@@ -82,7 +82,7 @@ export { type IRemoveOtherFormulaMutationParams, type ISetOtherFormulaMutationPa
export { RemoveSuperTableMutation, SetSuperTableMutation, SetSuperTableOptionMutation } from './commands/mutations/set-super-table.mutation';
export type { ISetSuperTableMutationParam, ISetSuperTableMutationSearchParam } from './commands/mutations/set-super-table.mutation';
export { CalculateController } from './controller/calculate.controller';
export { ENGINE_FORMULA_CYCLE_REFERENCE_COUNT, ENGINE_FORMULA_PLUGIN_CONFIG_KEY, type IUniverEngineFormulaConfig } from './controller/config.schema';
export { ENGINE_FORMULA_CYCLE_REFERENCE_COUNT, ENGINE_FORMULA_PLUGIN_CONFIG_KEY, ENGINE_FORMULA_RETURN_DEPENDENCY_TREE, type IUniverEngineFormulaConfig } from './controller/config.schema';
export { Lexer } from './engine/analysis/lexer';
export { LexerNode } from './engine/analysis/lexer-node';
export { LexerTreeBuilder } from './engine/analysis/lexer-tree-builder';
@@ -128,6 +128,7 @@ export {
serializeRangeWithSheet,
serializeRangeWithSpreadsheet,
singleReferenceToGrid,
splitTableStructuredRef,
unquoteSheetName,
} from './engine/utils/reference';
export { handleRefStringInfo } from './engine/utils/reference';
@@ -90,6 +90,8 @@ export class CalculateFormulaService extends Disposable implements ICalculateFor
private _executeLock = new AsyncLock();
protected _isCalculateTreeModel: boolean = false;
constructor(
@IConfigService protected readonly _configService: IConfigService,
@Inject(Lexer) protected readonly _lexer: Lexer,
@@ -145,6 +147,8 @@ export class CalculateFormulaService extends Disposable implements ICalculateFor
const cycleReferenceCount = (formulaDatasetConfig.maxIteration || DEFAULT_CYCLE_REFERENCE_COUNT) as number;
this._isCalculateTreeModel = formulaDatasetConfig.isCalculateTreeModel || false;
this._executeLock.acquire('FORMULA_EXECUTION_LOCK', async () => {
for (let i = 0; i < cycleReferenceCount; i++) {
this._runtimeService.setFormulaCycleIndex(i);
@@ -265,7 +269,7 @@ export class CalculateFormulaService extends Disposable implements ICalculateFor
this._executionInProgressListener$.next(this._runtimeService.getRuntimeState());
const treeList = (await this._formulaDependencyGenerator.generate()).reverse();
const treeList = (await this._formulaDependencyGenerator.generate(this._isCalculateTreeModel)).reverse();
const interpreter = this._interpreter;
@@ -46,6 +46,7 @@ export interface IFormulaDirtyData {
dirtyUnitOtherFormulaMap: IDirtyUnitOtherFormulaMap;
clearDependencyTreeCache: IDirtyUnitSheetNameMap; // unitId -> sheetId
maxIteration?: number;
isCalculateTreeModel?: boolean; // whether to calculate the dependency tree model
rowData?: IUnitRowData; // Include rows hidden by filters
}
@@ -24,6 +24,7 @@ import type {
IRuntimeUnitDataType,
} from '../basics/common';
import type { BaseAstNode } from '../engine/ast-node/base-ast-node';
import type { IFormulaDependencyTreeJson } from '../engine/dependency/dependency-tree';
import type { BaseReferenceObject, FunctionVariantType } from '../engine/reference-object/base-reference-object';
import type { ArrayValueObject } from '../engine/value-object/array-value-object';
import type { BaseValueObject } from '../engine/value-object/base-value-object';
@@ -77,6 +78,8 @@ export interface IAllRuntimeData {
runtimeFeatureRange: { [featureId: string]: IFeatureDirtyRangeType };
runtimeFeatureCellData: { [featureId: string]: IRuntimeUnitDataType };
dependencyTreeModelData: IFormulaDependencyTreeJson[];
}
export interface IExecutionInProgressParams {
@@ -190,6 +193,10 @@ export interface IFormulaRuntimeService {
clearArrayObjectCache(): void;
getRuntimeImageFormulaData(): IRuntimeImageFormulaDataType[];
setDependencyTreeModelData(data: IFormulaDependencyTreeJson[]): void;
getDependencyTreeModelData(): IFormulaDependencyTreeJson[];
}
export class FormulaRuntimeService extends Disposable implements IFormulaRuntimeService {
@@ -241,6 +248,8 @@ export class FormulaRuntimeService extends Disposable implements IFormulaRuntime
private _isCycleDependency: boolean = false;
private _dependencyTreeModelData: IFormulaDependencyTreeJson[] = [];
constructor(
@IFormulaCurrentConfigService private readonly _currentConfigService: IFormulaCurrentConfigService,
@IHyperlinkEngineFormulaService private readonly _hyperlinkEngineFormulaService: IHyperlinkEngineFormulaService
@@ -752,6 +761,14 @@ export class FormulaRuntimeService extends Disposable implements IFormulaRuntime
this._runtimeFeatureCellData[featureId] = featureData;
}
setDependencyTreeModelData(data: IFormulaDependencyTreeJson[]) {
this._dependencyTreeModelData = data;
}
getDependencyTreeModelData() {
return this._dependencyTreeModelData;
}
getRuntimeImageFormulaData() {
return this._runtimeImageFormulaData;
}
@@ -769,6 +786,8 @@ export class FormulaRuntimeService extends Disposable implements IFormulaRuntime
runtimeFeatureRange: this.getRuntimeFeatureRange(),
runtimeFeatureCellData: this.getRuntimeFeatureCellData(),
dependencyTreeModelData: this.getDependencyTreeModelData(),
};
}
@@ -39,6 +39,8 @@ export interface ISuperTableService {
remove(unitId: string, tableName: string): void;
update$: Observable<unknown>;
getTable(unitId: string, tableName: string): Nullable<ISuperTable>;
}
export class SuperTableService extends Disposable implements ISuperTableService {
@@ -92,6 +94,10 @@ export class SuperTableService extends Disposable implements ISuperTableService
this._tableOptionMap.set(tableOption, tableOptionType);
}
getTable(unitId: string, tableName: string): Nullable<ISuperTable> {
return this._tableMap.get(unitId)?.get(tableName);
}
private _update() {
this._update$.next(null);
}
@@ -29,6 +29,7 @@ import type { IUniverSheetsFormulaBaseConfig } from './config.schema';
import { Disposable, ICommandService, IConfigService, ILogService, Inject, LocaleService } from '@univerjs/core';
import {
ENGINE_FORMULA_CYCLE_REFERENCE_COUNT,
ENGINE_FORMULA_RETURN_DEPENDENCY_TREE,
FormulaDataModel,
FormulaExecutedStateType,
FormulaExecuteStageType,
@@ -36,6 +37,7 @@ import {
SetFormulaCalculationNotificationMutation,
SetFormulaCalculationStartMutation,
SetFormulaCalculationStopMutation,
SetFormulaStringBatchCalculationMutation,
} from '@univerjs/engine-formula';
import {
ClearSelectionFormatCommand,
@@ -170,9 +172,14 @@ export class TriggerCalculationController extends Disposable {
// The filtering information is not synchronized to the worker and must be passed in from the main thread each time
this.disposeWithMe(
this._commandService.beforeCommandExecuted((command: ICommandInfo) => {
if (command.id === SetFormulaCalculationStartMutation.id) {
if (command.id === SetFormulaCalculationStartMutation.id || command.id === SetFormulaStringBatchCalculationMutation.id) {
const params = command.params as ISetFormulaCalculationStartMutation;
if (command.id === SetFormulaCalculationStartMutation.id) {
const isCalculateTreeModel = this._configService.getConfig<boolean>(ENGINE_FORMULA_RETURN_DEPENDENCY_TREE) || false;
params.isCalculateTreeModel = isCalculateTreeModel;
}
params.maxIteration = this._configService.getConfig(ENGINE_FORMULA_CYCLE_REFERENCE_COUNT) as number | undefined;
params.rowData = this._formulaDataModel.getHiddenRowsFiltered();
}
})
@@ -272,7 +279,6 @@ export class TriggerCalculationController extends Disposable {
dirtyUnitOtherFormulaMap: allDirtyUnitOtherFormulaMap,
forceCalculation: false,
clearDependencyTreeCache: allClearDependencyTreeCache,
maxIteration: (this._configService.getConfig(ENGINE_FORMULA_CYCLE_REFERENCE_COUNT)) as number | undefined,
// numfmtItemMap,
};
}
@@ -291,8 +297,6 @@ export class TriggerCalculationController extends Disposable {
this._mergeDirtyUnitFeatureOrOtherFormulaMap(allDirtyUnitOtherFormulaMap, dirtyData2.dirtyUnitOtherFormulaMap);
this._mergeDirtyNameMap(allClearDependencyTreeCache, dirtyData2.clearDependencyTreeCache);
const maxIteration = dirtyData1.maxIteration || dirtyData2.maxIteration;
return {
dirtyRanges: allDirtyRanges,
dirtyNameMap: allDirtyNameMap,
@@ -301,7 +305,6 @@ export class TriggerCalculationController extends Disposable {
dirtyUnitOtherFormulaMap: allDirtyUnitOtherFormulaMap,
forceCalculation: !!this._forceCalculating,
clearDependencyTreeCache: allClearDependencyTreeCache,
maxIteration,
};
}
@@ -552,7 +555,6 @@ export class TriggerCalculationController extends Disposable {
dirtyUnitFeatureMap,
dirtyUnitOtherFormulaMap,
clearDependencyTreeCache,
maxIteration: this._configService.getConfig(ENGINE_FORMULA_CYCLE_REFERENCE_COUNT) as number | undefined,
};
}
}