@univerjs-pro/engine-formula-rust 1.0.0-insiders.20260725-1b9c8d8
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/README.md +56 -0
- package/lib/index.js +2114 -0
- package/lib/types/adapters/rust-projection-remote-instance.service.d.ts +28 -0
- package/lib/types/binding.d.ts +105 -0
- package/lib/types/controllers/rust-engine-sync.controller.d.ts +40 -0
- package/lib/types/controllers/rust-same-runtime-projection.controller.d.ts +27 -0
- package/lib/types/index.d.ts +10 -0
- package/lib/types/numfmt.d.ts +145 -0
- package/lib/types/plugin.d.ts +35 -0
- package/lib/types/regression/formula-array-followers.d.ts +14 -0
- package/lib/types/regression/formula-value-normalization.d.ts +2 -0
- package/lib/types/regression/formula-volatile-dependencies.d.ts +7 -0
- package/lib/types/regression/real-univer-stage-timeouts.d.ts +7 -0
- package/lib/types/regression/rust-only-artifact-cache.d.ts +41 -0
- package/lib/types/regression/rust-only-discovery.d.ts +17 -0
- package/lib/types/regression/rust-only-excel-com-oracle.d.ts +57 -0
- package/lib/types/regression/rust-only-excel-process-cleanup.d.ts +3 -0
- package/lib/types/regression/rust-only-exchange-binary.d.ts +15 -0
- package/lib/types/regression/rust-only-failure-report.d.ts +13 -0
- package/lib/types/regression/rust-only-feature-extraction.d.ts +19 -0
- package/lib/types/regression/rust-only-formula-comparison.d.ts +43 -0
- package/lib/types/regression/rust-only-ooxml-diff.d.ts +23 -0
- package/lib/types/regression/rust-only-ooxml-feature-extraction.d.ts +7 -0
- package/lib/types/regression/rust-only-partial-artifacts.d.ts +7 -0
- package/lib/types/regression/rust-only-pipeline.d.ts +55 -0
- package/lib/types/regression/rust-only-process.d.ts +9 -0
- package/lib/types/regression/rust-only-real-runner.d.ts +103 -0
- package/lib/types/regression/rust-only-report.d.ts +131 -0
- package/lib/types/regression/rust-only-sequential-runner.d.ts +24 -0
- package/lib/types/regression/rust-only-timeout.d.ts +63 -0
- package/lib/types/regression/rust-only-view-host.d.ts +171 -0
- package/lib/types/regression/rust-only-workbook-json-formula-values.d.ts +2 -0
- package/lib/types/regression/rust-only-xlsx-formula-values.d.ts +8 -0
- package/lib/types/regression/xlsx-sample-compatibility.d.ts +56 -0
- package/lib/types/services/calculate-formula.service.d.ts +106 -0
- package/lib/types/services/rust-formula-projection.service.d.ts +70 -0
- package/lib/types/services/workbook-snapshot-materializer.d.ts +20 -0
- package/lib/types/types.d.ts +398 -0
- package/package.json +47 -0
package/lib/index.js
ADDED
|
@@ -0,0 +1,2114 @@
|
|
|
1
|
+
// src/binding.ts
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import process from "node:process";
|
|
4
|
+
var nativeBinding = null, nativeBindingSource = null, nodeRequire = createRequire(import.meta.url);
|
|
5
|
+
function getNativeBindingSource() {
|
|
6
|
+
return nativeBindingSource;
|
|
7
|
+
}
|
|
8
|
+
function formatBindingLoadError(error) {
|
|
9
|
+
return error instanceof Error ? error.message : String(error);
|
|
10
|
+
}
|
|
11
|
+
function createBindingLoadFailure(errors) {
|
|
12
|
+
return new Error(
|
|
13
|
+
[
|
|
14
|
+
"Failed to load native formula engine binding.",
|
|
15
|
+
`platform=${process.platform}`,
|
|
16
|
+
`arch=${process.arch}`,
|
|
17
|
+
"expected npm package=@univerjs-pro/engine-formula-rust-binding",
|
|
18
|
+
"attempted paths:",
|
|
19
|
+
...errors.map((item) => `- ${item}`)
|
|
20
|
+
].join(`
|
|
21
|
+
`)
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
async function loadNativeBinding() {
|
|
25
|
+
if (nativeBinding)
|
|
26
|
+
return nativeBinding;
|
|
27
|
+
if (typeof process < "u" && process.versions?.node) {
|
|
28
|
+
let errors = [];
|
|
29
|
+
try {
|
|
30
|
+
return nativeBinding = nodeRequire("@univerjs-pro/engine-formula-rust-binding"), nativeBindingSource = "@univerjs-pro/engine-formula-rust-binding", nativeBinding;
|
|
31
|
+
} catch (error) {
|
|
32
|
+
errors.push(`@univerjs-pro/engine-formula-rust-binding: ${formatBindingLoadError(error)}`);
|
|
33
|
+
}
|
|
34
|
+
throw createBindingLoadFailure(errors);
|
|
35
|
+
} else
|
|
36
|
+
throw new Error("WASM binding not yet implemented");
|
|
37
|
+
}
|
|
38
|
+
function executeOnRust(inputJson) {
|
|
39
|
+
if (!nativeBinding)
|
|
40
|
+
throw new Error("Native binding not loaded. Call loadNativeBinding() first.");
|
|
41
|
+
return nativeBinding.formulaEngineExecute(inputJson);
|
|
42
|
+
}
|
|
43
|
+
function buildLexerTreeOnRust(formula, transformSuffix = !0) {
|
|
44
|
+
if (!nativeBinding)
|
|
45
|
+
throw new Error("Native binding not loaded. Call loadNativeBinding() first.");
|
|
46
|
+
return nativeBinding.formulaLexerTreeBuild(formula, transformSuffix);
|
|
47
|
+
}
|
|
48
|
+
function buildSequenceNodesOnRust(formula) {
|
|
49
|
+
if (!nativeBinding)
|
|
50
|
+
throw new Error("Native binding not loaded. Call loadNativeBinding() first.");
|
|
51
|
+
return nativeBinding.formulaSequenceNodesBuild(formula);
|
|
52
|
+
}
|
|
53
|
+
function checkIfAddBracketOnRust(formula) {
|
|
54
|
+
if (!nativeBinding)
|
|
55
|
+
throw new Error("Native binding not loaded. Call loadNativeBinding() first.");
|
|
56
|
+
return nativeBinding.formulaCheckIfAddBracket(formula);
|
|
57
|
+
}
|
|
58
|
+
function formatNumberBatchOnRust(inputJson) {
|
|
59
|
+
if (!nativeBinding)
|
|
60
|
+
throw new Error("Native binding not loaded. Call loadNativeBinding() first.");
|
|
61
|
+
return nativeBinding.rustNumfmtFormatBatch(inputJson);
|
|
62
|
+
}
|
|
63
|
+
function parseNumberFormatInputBatchOnRust(inputJson) {
|
|
64
|
+
if (!nativeBinding)
|
|
65
|
+
throw new Error("Native binding not loaded. Call loadNativeBinding() first.");
|
|
66
|
+
return nativeBinding.rustNumfmtParseBatch(inputJson);
|
|
67
|
+
}
|
|
68
|
+
function parseNumberFormatMatrixBatchOnRust(inputJson) {
|
|
69
|
+
if (!nativeBinding)
|
|
70
|
+
throw new Error("Native binding not loaded. Call loadNativeBinding() first.");
|
|
71
|
+
return nativeBinding.rustNumfmtParseMatrixBatch(inputJson);
|
|
72
|
+
}
|
|
73
|
+
function analyzeNumberFormatBatchOnRust(inputJson) {
|
|
74
|
+
if (!nativeBinding)
|
|
75
|
+
throw new Error("Native binding not loaded. Call loadNativeBinding() first.");
|
|
76
|
+
return nativeBinding.rustNumfmtAnalyzeBatch(inputJson);
|
|
77
|
+
}
|
|
78
|
+
function loadSnapshotOnRust(snapshotJson) {
|
|
79
|
+
if (!nativeBinding)
|
|
80
|
+
throw new Error("Native binding not loaded. Call loadNativeBinding() first.");
|
|
81
|
+
return nativeBinding.rustEngineLoadSnapshot(snapshotJson);
|
|
82
|
+
}
|
|
83
|
+
function loadSnapshotBinaryOnRust(snapshotBytes) {
|
|
84
|
+
if (!nativeBinding)
|
|
85
|
+
throw new Error("Native binding not loaded. Call loadNativeBinding() first.");
|
|
86
|
+
return nativeBinding.rustEngineLoadSnapshotBinary(snapshotBytes);
|
|
87
|
+
}
|
|
88
|
+
function applyMutationOnRust(mutationJson) {
|
|
89
|
+
if (!nativeBinding)
|
|
90
|
+
throw new Error("Native binding not loaded. Call loadNativeBinding() first.");
|
|
91
|
+
return nativeBinding.rustEngineApplyMutation(mutationJson);
|
|
92
|
+
}
|
|
93
|
+
function disposeWorkbookOnRust(unitId) {
|
|
94
|
+
if (!nativeBinding)
|
|
95
|
+
throw new Error("Native binding not loaded. Call loadNativeBinding() first.");
|
|
96
|
+
return nativeBinding.rustEngineDisposeWorkbook(unitId);
|
|
97
|
+
}
|
|
98
|
+
function disposeAllWorkbooksOnRust() {
|
|
99
|
+
if (!nativeBinding)
|
|
100
|
+
throw new Error("Native binding not loaded. Call loadNativeBinding() first.");
|
|
101
|
+
return nativeBinding.rustEngineDisposeAllWorkbooks();
|
|
102
|
+
}
|
|
103
|
+
function getRustModelStats() {
|
|
104
|
+
if (!nativeBinding)
|
|
105
|
+
throw new Error("Native binding not loaded. Call loadNativeBinding() first.");
|
|
106
|
+
return nativeBinding.rustEngineGetModelStats();
|
|
107
|
+
}
|
|
108
|
+
function getRustCellOnRust(unitId, sheetId, row, col) {
|
|
109
|
+
if (!nativeBinding)
|
|
110
|
+
throw new Error("Native binding not loaded. Call loadNativeBinding() first.");
|
|
111
|
+
return nativeBinding.rustEngineGetCell(unitId, sheetId, row, col);
|
|
112
|
+
}
|
|
113
|
+
function getRustSheetStateOnRust(unitId, sheetId) {
|
|
114
|
+
if (!nativeBinding)
|
|
115
|
+
throw new Error("Native binding not loaded. Call loadNativeBinding() first.");
|
|
116
|
+
return nativeBinding.rustEngineGetSheetState(unitId, sheetId);
|
|
117
|
+
}
|
|
118
|
+
function getRustFormulaDataOnRust(unitId) {
|
|
119
|
+
if (!nativeBinding)
|
|
120
|
+
throw new Error("Native binding not loaded. Call loadNativeBinding() first.");
|
|
121
|
+
return nativeBinding.rustEngineGetFormulaData(unitId);
|
|
122
|
+
}
|
|
123
|
+
function buildRustDependencyGraphOnRust(unitId) {
|
|
124
|
+
if (!nativeBinding)
|
|
125
|
+
throw new Error("Native binding not loaded. Call loadNativeBinding() first.");
|
|
126
|
+
return nativeBinding.rustEngineBuildDependencyGraph(unitId);
|
|
127
|
+
}
|
|
128
|
+
function getRustDirtyDependenciesOnRust(dirtyRangesJson, unitId) {
|
|
129
|
+
if (!nativeBinding)
|
|
130
|
+
throw new Error("Native binding not loaded. Call loadNativeBinding() first.");
|
|
131
|
+
return nativeBinding.rustEngineGetDirtyDependencies(dirtyRangesJson, unitId);
|
|
132
|
+
}
|
|
133
|
+
function syncRustFormulaDependenciesOnRust(inputJson) {
|
|
134
|
+
if (!nativeBinding)
|
|
135
|
+
throw new Error("Native binding not loaded. Call loadNativeBinding() first.");
|
|
136
|
+
return nativeBinding.rustEngineSyncFormulaDependencies(inputJson);
|
|
137
|
+
}
|
|
138
|
+
function inspectRustFormulaDependencyGraphOnRust() {
|
|
139
|
+
if (!nativeBinding)
|
|
140
|
+
throw new Error("Native binding not loaded. Call loadNativeBinding() first.");
|
|
141
|
+
return nativeBinding.rustEngineInspectFormulaDependencyGraph();
|
|
142
|
+
}
|
|
143
|
+
function markRustFormulaDirtyOnRust(inputJson) {
|
|
144
|
+
if (!nativeBinding)
|
|
145
|
+
throw new Error("Native binding not loaded. Call loadNativeBinding() first.");
|
|
146
|
+
return nativeBinding.rustEngineMarkFormulaDirty(inputJson);
|
|
147
|
+
}
|
|
148
|
+
function clearRustFormulaDependenciesOnRust(inputJson) {
|
|
149
|
+
if (!nativeBinding)
|
|
150
|
+
throw new Error("Native binding not loaded. Call loadNativeBinding() first.");
|
|
151
|
+
return nativeBinding.rustEngineClearFormulaDependencies(inputJson);
|
|
152
|
+
}
|
|
153
|
+
function clearRustFormulaDirtyOnRust() {
|
|
154
|
+
if (!nativeBinding)
|
|
155
|
+
throw new Error("Native binding not loaded. Call loadNativeBinding() first.");
|
|
156
|
+
return nativeBinding.rustEngineClearFormulaDirty();
|
|
157
|
+
}
|
|
158
|
+
function executeDirtyFormulasOnRust(maxIteration, includeCalculatedNodes, includeRuntimeData, includeResultBatches) {
|
|
159
|
+
if (!nativeBinding)
|
|
160
|
+
throw new Error("Native binding not loaded. Call loadNativeBinding() first.");
|
|
161
|
+
return nativeBinding.rustEngineExecuteDirtyFormulas(
|
|
162
|
+
maxIteration,
|
|
163
|
+
includeCalculatedNodes,
|
|
164
|
+
includeRuntimeData,
|
|
165
|
+
includeResultBatches
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
function materializeWorkbookSnapshotOnRust(workbookJson, unitId, rev, dirtyInputJson) {
|
|
169
|
+
if (!nativeBinding)
|
|
170
|
+
throw new Error("Native binding not loaded. Call loadNativeBinding() first.");
|
|
171
|
+
return nativeBinding.rustMaterializeWorkbookSnapshot(workbookJson, unitId, rev, dirtyInputJson);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// src/controllers/rust-engine-sync.controller.ts
|
|
175
|
+
import { CommandType, Disposable, ICommandService, setDependencies } from "@univerjs/core";
|
|
176
|
+
|
|
177
|
+
// src/services/rust-formula-projection.service.ts
|
|
178
|
+
import { CellValueType, ObjectMatrix } from "@univerjs/core";
|
|
179
|
+
var XLSX_WORKBOOK_CALCULATION_RESOURCE = "UNIVER_CLI_XLSX_WORKBOOK_CALCULATION_PLUGIN", EXTERNAL_DATA_RESOURCE = "SHEET_EXTERNAL_DATA_PLUGIN", EXTERNAL_DATA_SIGNATURE = "external_data", RUST_UPSERT_REFERENCE_DATA_MUTATION_ID = "formula.mutation.upsert-reference-data", RUST_FORMULA_RELEVANT_MUTATIONS = /* @__PURE__ */ new Set([
|
|
180
|
+
"sheet.mutation.set-range-values",
|
|
181
|
+
"sheet.mutation.insert-row",
|
|
182
|
+
"sheet.mutation.insert-col",
|
|
183
|
+
"sheet.mutation.insert-sheet",
|
|
184
|
+
"sheet.mutation.move-range",
|
|
185
|
+
"sheet.mutation.move-rows",
|
|
186
|
+
"sheet.mutation.move-columns",
|
|
187
|
+
"sheet.mutation.move-cols",
|
|
188
|
+
"sheet.mutation.remove-col",
|
|
189
|
+
"sheet.mutation.remove-rows",
|
|
190
|
+
"sheet.mutation.remove-sheet",
|
|
191
|
+
"sheet.mutation.set-col-hidden",
|
|
192
|
+
"sheet.mutation.set-col-visible",
|
|
193
|
+
"sheet.mutation.set-row-hidden",
|
|
194
|
+
"sheet.mutation.set-row-visible",
|
|
195
|
+
"sheet.mutation.set-worksheet-name",
|
|
196
|
+
"sheet.mutation.reorder-range",
|
|
197
|
+
"sheet.mutation.set-worksheet-row-count",
|
|
198
|
+
"sheet.mutation.set-worksheet-column-count",
|
|
199
|
+
"formula.mutation.set-array-formula-data",
|
|
200
|
+
"formula.mutation.set-defined-name",
|
|
201
|
+
"formula.mutation.set-feature-calculation",
|
|
202
|
+
"formula.mutation.set-formula-data",
|
|
203
|
+
"formula.mutation.set-image-formula-data",
|
|
204
|
+
"formula.mutation.set-other-formula",
|
|
205
|
+
"formula.mutation.set-super-table",
|
|
206
|
+
"formula.mutation.set-super-table-option",
|
|
207
|
+
"formula.mutation.remove-defined-name",
|
|
208
|
+
"formula.mutation.remove-feature-calculation",
|
|
209
|
+
"formula.mutation.remove-other-formula",
|
|
210
|
+
"formula.mutation.remove-super-table"
|
|
211
|
+
]), RUST_INCREMENTAL_DEPENDENCY_MUTATIONS = /* @__PURE__ */ new Set(["sheet.mutation.set-range-values"]);
|
|
212
|
+
function isRustFormulaRelevantMutation(id) {
|
|
213
|
+
return RUST_FORMULA_RELEVANT_MUTATIONS.has(id);
|
|
214
|
+
}
|
|
215
|
+
function isRustIncrementalDependencyMutation(id) {
|
|
216
|
+
return RUST_INCREMENTAL_DEPENDENCY_MUTATIONS.has(id);
|
|
217
|
+
}
|
|
218
|
+
function createReferenceDataUpsertMutations(config, needs) {
|
|
219
|
+
let unitNameMap = config.unitNameMap, grouped = /* @__PURE__ */ new Map();
|
|
220
|
+
for (let need of needs) {
|
|
221
|
+
let key = `${need.unitId}\0${need.sheetId}`, group = grouped.get(key) ?? [];
|
|
222
|
+
group.push(need), grouped.set(key, group);
|
|
223
|
+
}
|
|
224
|
+
return Array.from(grouped.values()).flatMap((group) => {
|
|
225
|
+
let first = group[0], unitData = config.allUnitData?.[first.unitId], sheetNameMap = config.unitSheetNameMap?.[first.unitId] ?? {}, resolvedSheetId = unitData?.[first.sheetId] ? first.sheetId : sheetNameMap[first.sheetId] ?? first.sheetId, sheet = unitData?.[resolvedSheetId];
|
|
226
|
+
if (!sheet)
|
|
227
|
+
return [];
|
|
228
|
+
let sheetName = Object.entries(sheetNameMap).find(([, sheetId]) => sheetId === resolvedSheetId)?.[0] ?? first.sheetId, ranges = group.map(({ range }) => range);
|
|
229
|
+
return [
|
|
230
|
+
{
|
|
231
|
+
id: RUST_UPSERT_REFERENCE_DATA_MUTATION_ID,
|
|
232
|
+
params: {
|
|
233
|
+
unitId: first.unitId,
|
|
234
|
+
name: unitNameMap?.[first.unitId]?.name,
|
|
235
|
+
sheet: {
|
|
236
|
+
name: sheetName,
|
|
237
|
+
sheetId: resolvedSheetId,
|
|
238
|
+
rowCount: sheet.rowCount,
|
|
239
|
+
columnCount: sheet.columnCount,
|
|
240
|
+
coverage: ranges,
|
|
241
|
+
cellData: serializeCellDataInRanges(sheet.cellData, ranges)
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
dirtyRanges: ranges.map((range) => ({
|
|
245
|
+
unitId: first.unitId,
|
|
246
|
+
sheetId: resolvedSheetId,
|
|
247
|
+
range
|
|
248
|
+
}))
|
|
249
|
+
}
|
|
250
|
+
];
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
function serializeRuntimeWorkbookSnapshots(workbooks) {
|
|
254
|
+
return {
|
|
255
|
+
workbooks: workbooks.map((workbook) => serializeRuntimeWorkbookSnapshot(workbook))
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
function serializeRuntimeWorkbookSnapshot(input) {
|
|
259
|
+
let { snapshot } = input, sheetOrder = snapshot.sheetOrder?.length > 0 ? snapshot.sheetOrder : Object.keys(snapshot.sheets ?? {}), calculation = serializeCalculation(snapshot), precisionAsDisplayed = calculation?.fullPrecision === !1, sheets = sheetOrder.map(
|
|
260
|
+
(sheetId) => serializeSheetSnapshot(sheetId, snapshot.sheets?.[sheetId], snapshot.styles, precisionAsDisplayed)
|
|
261
|
+
).filter((sheet) => sheet != null);
|
|
262
|
+
return {
|
|
263
|
+
unitId: input.unitId || snapshot.id,
|
|
264
|
+
name: snapshot.name,
|
|
265
|
+
sheets,
|
|
266
|
+
...calculation ? { calculation } : {},
|
|
267
|
+
resources: serializeResources(snapshot),
|
|
268
|
+
definedNames: serializeDefinedNames(input.definedNames, snapshot),
|
|
269
|
+
externalLinks: serializeExternalLinks(snapshot),
|
|
270
|
+
tables: serializeTables(snapshot)
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
function rustExecutionOutputToFormulaCalculationPatch(output) {
|
|
274
|
+
let arrayFormulaOutput = output;
|
|
275
|
+
return {
|
|
276
|
+
unitData: output.resultBatches?.length ? resultBatchesToUnitData(output.resultBatches) : runtimeDataToUnitData(output.runtimeData),
|
|
277
|
+
unitOtherData: otherFormulaDataToUnitOtherData(output.otherFormulaData),
|
|
278
|
+
...arrayFormulaOutput.arrayFormulaRange ? { arrayFormulaRange: arrayFormulaOutput.arrayFormulaRange } : {},
|
|
279
|
+
...arrayFormulaOutput.arrayFormulaCellData ? { arrayFormulaCellData: arrayFormulaOutput.arrayFormulaCellData } : {},
|
|
280
|
+
errors: output.errors?.map((error) => ({
|
|
281
|
+
code: "RUST_FORMULA_CALCULATION_ERROR",
|
|
282
|
+
unitId: error.unitId,
|
|
283
|
+
sheetId: error.sheetId,
|
|
284
|
+
row: error.row,
|
|
285
|
+
column: error.column,
|
|
286
|
+
message: error.message
|
|
287
|
+
}))
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
function otherFormulaDataToUnitOtherData(otherFormulaData) {
|
|
291
|
+
let unitOtherData = {};
|
|
292
|
+
return Object.entries(otherFormulaData ?? {}).forEach(([unitId, sheetMap]) => {
|
|
293
|
+
if (!sheetMap) return;
|
|
294
|
+
let unitSheetData = {};
|
|
295
|
+
unitOtherData[unitId] = unitSheetData, Object.entries(sheetMap).forEach(([sheetId, formulaMap]) => {
|
|
296
|
+
if (!formulaMap) return;
|
|
297
|
+
let sheetData = {};
|
|
298
|
+
unitSheetData[sheetId] = sheetData, Object.entries(formulaMap).forEach(([formulaId, rowMap]) => {
|
|
299
|
+
if (!rowMap) return;
|
|
300
|
+
let formulaData = {};
|
|
301
|
+
sheetData[formulaId] = formulaData, Object.entries(rowMap).forEach(([rowKey, colMap]) => {
|
|
302
|
+
if (!colMap) return;
|
|
303
|
+
let row = Number(rowKey), rowData = {};
|
|
304
|
+
formulaData[row] = rowData, Object.entries(colMap).forEach(([colKey, value]) => {
|
|
305
|
+
rowData[Number(colKey)] = [[cellDataFromRustValue(value)]];
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
});
|
|
309
|
+
});
|
|
310
|
+
}), unitOtherData;
|
|
311
|
+
}
|
|
312
|
+
function createFormulaProjectionDesyncSignal(reason, error, mutationId) {
|
|
313
|
+
return {
|
|
314
|
+
reason,
|
|
315
|
+
mutationId,
|
|
316
|
+
message: error instanceof Error ? error.message : String(error)
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
var RustFormulaProjectionService = class {
|
|
320
|
+
_nativeLoaded = !1;
|
|
321
|
+
async load(workbooks) {
|
|
322
|
+
await this._ensureNativeLoaded();
|
|
323
|
+
try {
|
|
324
|
+
return {
|
|
325
|
+
stats: JSON.parse(loadSnapshotOnRust(JSON.stringify(serializeRuntimeWorkbookSnapshots(workbooks))))
|
|
326
|
+
};
|
|
327
|
+
} catch (error) {
|
|
328
|
+
return {
|
|
329
|
+
desync: createFormulaProjectionDesyncSignal("snapshot-load-failed", error),
|
|
330
|
+
errors: [errorToFormulaCalculationError("RUST_FORMULA_LOAD_ERROR", error)]
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
async applyMutation(mutation) {
|
|
335
|
+
await this._ensureNativeLoaded();
|
|
336
|
+
try {
|
|
337
|
+
return {
|
|
338
|
+
stats: JSON.parse(applyMutationOnRust(JSON.stringify(normalizeRustEngineMutation(mutation)))),
|
|
339
|
+
dependencyInvalidated: !isRustIncrementalDependencyMutation(mutation.id)
|
|
340
|
+
};
|
|
341
|
+
} catch (error) {
|
|
342
|
+
return {
|
|
343
|
+
dependencyInvalidated: !0,
|
|
344
|
+
desync: createFormulaProjectionDesyncSignal("mutation-apply-failed", error, mutation.id),
|
|
345
|
+
errors: [errorToFormulaCalculationError("RUST_FORMULA_MUTATION_ERROR", error)]
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
async syncFormulaDependencies(input) {
|
|
350
|
+
return await this._ensureNativeLoaded(), JSON.parse(syncRustFormulaDependenciesOnRust(JSON.stringify(input)));
|
|
351
|
+
}
|
|
352
|
+
async markDirty(input) {
|
|
353
|
+
return await this._ensureNativeLoaded(), JSON.parse(markRustFormulaDirtyOnRust(JSON.stringify(input)));
|
|
354
|
+
}
|
|
355
|
+
async calculateDirty(maxIteration = 1) {
|
|
356
|
+
await this._ensureNativeLoaded();
|
|
357
|
+
try {
|
|
358
|
+
let output = JSON.parse(
|
|
359
|
+
executeDirtyFormulasOnRust(maxIteration, !1, !1, !0)
|
|
360
|
+
);
|
|
361
|
+
return rustExecutionOutputToFormulaCalculationPatch(output);
|
|
362
|
+
} catch (error) {
|
|
363
|
+
return {
|
|
364
|
+
unitData: {},
|
|
365
|
+
unitOtherData: {},
|
|
366
|
+
desync: createFormulaProjectionDesyncSignal("dirty-calculation-failed", error),
|
|
367
|
+
errors: [errorToFormulaCalculationError("RUST_FORMULA_CALCULATION_ERROR", error)]
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
async reset() {
|
|
372
|
+
await this._ensureNativeLoaded();
|
|
373
|
+
try {
|
|
374
|
+
return clearRustFormulaDirtyOnRust(), clearRustFormulaDependenciesOnRust(
|
|
375
|
+
JSON.stringify({
|
|
376
|
+
unitId: "",
|
|
377
|
+
clearSheetFormulas: !0,
|
|
378
|
+
clearFeatureFormulas: !0,
|
|
379
|
+
clearOtherFormulas: !0
|
|
380
|
+
})
|
|
381
|
+
), {
|
|
382
|
+
stats: JSON.parse(loadSnapshotOnRust(JSON.stringify({ workbooks: [] })))
|
|
383
|
+
};
|
|
384
|
+
} catch (error) {
|
|
385
|
+
return {
|
|
386
|
+
desync: createFormulaProjectionDesyncSignal("projection-reset-failed", error),
|
|
387
|
+
errors: [errorToFormulaCalculationError("RUST_FORMULA_RESET_ERROR", error)]
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
async disposeWorkbook(unitId) {
|
|
392
|
+
await this._ensureNativeLoaded();
|
|
393
|
+
try {
|
|
394
|
+
return { stats: JSON.parse(disposeWorkbookOnRust(unitId)) };
|
|
395
|
+
} catch (error) {
|
|
396
|
+
return {
|
|
397
|
+
desync: createFormulaProjectionDesyncSignal("workbook-dispose-failed", error),
|
|
398
|
+
errors: [errorToFormulaCalculationError("RUST_FORMULA_DISPOSE_ERROR", error)]
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
async _ensureNativeLoaded() {
|
|
403
|
+
this._nativeLoaded || (await loadNativeBinding(), this._nativeLoaded = !0);
|
|
404
|
+
}
|
|
405
|
+
};
|
|
406
|
+
function normalizeRustEngineMutation(mutation) {
|
|
407
|
+
return {
|
|
408
|
+
id: mutation.id,
|
|
409
|
+
params: mutation.params ?? {},
|
|
410
|
+
dirtyRanges: Array.isArray(mutation.dirtyRanges) ? mutation.dirtyRanges : []
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
function resultBatchesToUnitData(resultBatches) {
|
|
414
|
+
let unitData = {};
|
|
415
|
+
for (let batch of resultBatches) {
|
|
416
|
+
let unitSheetData = unitData[batch.unitId] ?? {};
|
|
417
|
+
unitData[batch.unitId] = unitSheetData;
|
|
418
|
+
let sheetData = unitSheetData[batch.sheetId] ?? {};
|
|
419
|
+
unitSheetData[batch.sheetId] = sheetData;
|
|
420
|
+
for (let index = 0; index < batch.values.length; index++) {
|
|
421
|
+
let row = batch.rows[index], col = batch.cols[index], value = batch.values[index], rowData = sheetData[row] ?? {};
|
|
422
|
+
sheetData[row] = rowData, rowData[col] = cellDataFromRustValue(value);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
return unitData;
|
|
426
|
+
}
|
|
427
|
+
function runtimeDataToUnitData(runtimeData) {
|
|
428
|
+
let unitData = {};
|
|
429
|
+
return Object.entries(runtimeData ?? {}).forEach(([unitId, sheetMap]) => {
|
|
430
|
+
if (!sheetMap) return;
|
|
431
|
+
let unitSheetData = {};
|
|
432
|
+
unitData[unitId] = unitSheetData, Object.entries(sheetMap).forEach(([sheetId, rowMap]) => {
|
|
433
|
+
if (!rowMap) return;
|
|
434
|
+
let sheetData = {};
|
|
435
|
+
unitSheetData[sheetId] = sheetData, Object.entries(rowMap).forEach(([rowKey, colMap]) => {
|
|
436
|
+
if (!colMap) return;
|
|
437
|
+
let row = Number(rowKey), rowData = {};
|
|
438
|
+
sheetData[row] = rowData, Object.entries(colMap).forEach(([colKey, value]) => {
|
|
439
|
+
rowData[Number(colKey)] = cellDataFromRustValue(value);
|
|
440
|
+
});
|
|
441
|
+
});
|
|
442
|
+
});
|
|
443
|
+
}), unitData;
|
|
444
|
+
}
|
|
445
|
+
function cellDataFromRustValue(value) {
|
|
446
|
+
if (value == null)
|
|
447
|
+
return null;
|
|
448
|
+
if (typeof value == "number")
|
|
449
|
+
return { t: CellValueType.NUMBER, v: value };
|
|
450
|
+
if (typeof value == "boolean")
|
|
451
|
+
return { t: CellValueType.BOOLEAN, v: value };
|
|
452
|
+
if (typeof value == "string")
|
|
453
|
+
return { t: CellValueType.STRING, v: value };
|
|
454
|
+
if (isRecord(value)) {
|
|
455
|
+
let cell = sanitizeCoreCellData(value);
|
|
456
|
+
if (Object.keys(cell).length > 0)
|
|
457
|
+
return cell;
|
|
458
|
+
}
|
|
459
|
+
return { v: value };
|
|
460
|
+
}
|
|
461
|
+
function sanitizeCoreCellData(value) {
|
|
462
|
+
let cell = {};
|
|
463
|
+
for (let key of ["v", "t", "p", "s", "f", "si", "ref", "xf", "custom"])
|
|
464
|
+
key in value && (cell[key] = value[key]);
|
|
465
|
+
return cell;
|
|
466
|
+
}
|
|
467
|
+
function serializeResources(snapshot) {
|
|
468
|
+
let resources = snapshot.resources;
|
|
469
|
+
if (!resources || typeof resources != "object")
|
|
470
|
+
return;
|
|
471
|
+
let serialized = {};
|
|
472
|
+
for (let [id, resource] of Object.entries(resources))
|
|
473
|
+
typeof resource?.name == "string" && (serialized[id] = {
|
|
474
|
+
name: resource.name,
|
|
475
|
+
data: resource.data
|
|
476
|
+
});
|
|
477
|
+
return Object.keys(serialized).length > 0 ? serialized : void 0;
|
|
478
|
+
}
|
|
479
|
+
function serializeCalculation(snapshot) {
|
|
480
|
+
for (let resource of Object.values(
|
|
481
|
+
snapshot.resources ?? {}
|
|
482
|
+
)) {
|
|
483
|
+
if (resource?.name !== XLSX_WORKBOOK_CALCULATION_RESOURCE)
|
|
484
|
+
continue;
|
|
485
|
+
let data = parseResourceData(resource.data);
|
|
486
|
+
if (!data || typeof data != "object")
|
|
487
|
+
return;
|
|
488
|
+
let fullPrecision = data.fullPrecision;
|
|
489
|
+
return typeof fullPrecision == "boolean" ? { fullPrecision } : void 0;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
function serializeTables(snapshot) {
|
|
493
|
+
for (let resource of Object.values(
|
|
494
|
+
snapshot.resources ?? {}
|
|
495
|
+
)) {
|
|
496
|
+
if (resource?.name !== "SHEET_TABLE_PLUGIN")
|
|
497
|
+
continue;
|
|
498
|
+
let data = parseResourceData(resource.data);
|
|
499
|
+
if (!data || typeof data != "object")
|
|
500
|
+
return;
|
|
501
|
+
let tables = {};
|
|
502
|
+
for (let [sheetId, sheetTables] of Object.entries(data)) {
|
|
503
|
+
let tableList = sheetTables?.tables;
|
|
504
|
+
if (Array.isArray(tableList))
|
|
505
|
+
for (let table of tableList) {
|
|
506
|
+
let serialized = serializeTableSnapshot(sheetId, table, snapshot);
|
|
507
|
+
serialized && (tables[serialized.name] = serialized.table);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
return Object.keys(tables).length > 0 ? tables : void 0;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
function serializeTableSnapshot(sheetId, table, snapshot) {
|
|
514
|
+
if (!table || typeof table != "object")
|
|
515
|
+
return null;
|
|
516
|
+
let record = table, name2 = typeof record.name == "string" ? record.name : void 0, range = record.range;
|
|
517
|
+
if (!name2 || !range || typeof range.startRow != "number" || typeof range.endRow != "number" || typeof range.startColumn != "number" || typeof range.endColumn != "number")
|
|
518
|
+
return null;
|
|
519
|
+
let columns = Array.isArray(record.columns) ? record.columns.map((column) => {
|
|
520
|
+
let displayName = column?.displayName;
|
|
521
|
+
return typeof displayName == "string" ? { displayName } : null;
|
|
522
|
+
}).filter((column) => column != null) : [], showHeader = record.options?.showHeader !== !1, showFooter = typeof record.options?.showFooter == "boolean" ? record.options.showFooter : inferTableFooter(snapshot, sheetId, range.startRow, range.endRow, range.startColumn, range.endColumn);
|
|
523
|
+
return {
|
|
524
|
+
name: name2,
|
|
525
|
+
table: {
|
|
526
|
+
sheetId,
|
|
527
|
+
range: {
|
|
528
|
+
startRow: range.startRow,
|
|
529
|
+
endRow: range.endRow,
|
|
530
|
+
startColumn: range.startColumn,
|
|
531
|
+
endColumn: range.endColumn
|
|
532
|
+
},
|
|
533
|
+
columns,
|
|
534
|
+
showHeader,
|
|
535
|
+
showFooter
|
|
536
|
+
}
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
function parseResourceData(data) {
|
|
540
|
+
if (typeof data != "string")
|
|
541
|
+
return data;
|
|
542
|
+
try {
|
|
543
|
+
return JSON.parse(data || "{}");
|
|
544
|
+
} catch {
|
|
545
|
+
return;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
function inferTableFooter(snapshot, sheetId, startRow, endRow, startColumn, endColumn) {
|
|
549
|
+
let row = snapshot.sheets?.[sheetId]?.cellData?.[endRow];
|
|
550
|
+
if (!row)
|
|
551
|
+
return !1;
|
|
552
|
+
for (let col = startColumn; col <= endColumn; col++) {
|
|
553
|
+
let cell = row[col];
|
|
554
|
+
if (cell && (typeof cell.f == "string" && /\bSUBTOTAL\s*\(/iu.test(cell.f) || col === startColumn && typeof cell.v == "string" && cell.v.trim().toLowerCase() === "total"))
|
|
555
|
+
return !0;
|
|
556
|
+
}
|
|
557
|
+
return !1;
|
|
558
|
+
}
|
|
559
|
+
function serializeExternalLinks(snapshot) {
|
|
560
|
+
let externalLinks = snapshot.externalLinks, serializedLinks = Array.isArray(externalLinks) ? externalLinks.map((link) => serializeExternalLink(link)).filter((link) => link != null) : [];
|
|
561
|
+
return serializedLinks.push(...serializeExternalLinksFromResource(snapshot)), serializedLinks.length > 0 ? serializedLinks : void 0;
|
|
562
|
+
}
|
|
563
|
+
function serializeExternalLinksFromResource(snapshot) {
|
|
564
|
+
let links = [];
|
|
565
|
+
for (let resource of Object.values(
|
|
566
|
+
snapshot.resources ?? {}
|
|
567
|
+
)) {
|
|
568
|
+
if (resource?.name !== EXTERNAL_DATA_RESOURCE)
|
|
569
|
+
continue;
|
|
570
|
+
let data = parseResourceData(resource.data);
|
|
571
|
+
if (isRecord(data)) {
|
|
572
|
+
if (data.schemaVersion === 1 && Array.isArray(data.links)) {
|
|
573
|
+
links.push(
|
|
574
|
+
...data.links.map((link) => serializeVersionedExternalLink(link)).filter((link) => link != null)
|
|
575
|
+
);
|
|
576
|
+
continue;
|
|
577
|
+
}
|
|
578
|
+
if (!(data.signature !== EXTERNAL_DATA_SIGNATURE || !isRecord(data.units)))
|
|
579
|
+
for (let [unitId, unit] of Object.entries(data.units)) {
|
|
580
|
+
let link = serializeExternalDataUnit(unitId, unit);
|
|
581
|
+
link && links.push(link);
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
return links;
|
|
586
|
+
}
|
|
587
|
+
function serializeVersionedExternalLink(link) {
|
|
588
|
+
if (!isRecord(link) || !Number.isInteger(link.slot) || Number(link.slot) <= 0 || !isRecord(link.target))
|
|
589
|
+
return null;
|
|
590
|
+
let target = link.target, cache = isRecord(link.cache) ? link.cache : void 0, cachedSheets = Array.isArray(cache?.sheets) ? cache.sheets.map((sheet) => serializeVersionedExternalSheet(sheet)).filter((sheet) => sheet != null) : [], cachedNames = new Set(cachedSheets.map((sheet) => sheet.name.toLocaleLowerCase())), uncachedSheets = Array.isArray(link.sheetNames) ? link.sheetNames.flatMap((item) => {
|
|
591
|
+
if (!isRecord(item)) return [];
|
|
592
|
+
let { name: name2 } = item;
|
|
593
|
+
return typeof name2 != "string" || cachedNames.has(name2.toLocaleLowerCase()) ? [] : [
|
|
594
|
+
{
|
|
595
|
+
name: name2,
|
|
596
|
+
rowCount: 1048576,
|
|
597
|
+
columnCount: 16384,
|
|
598
|
+
cellData: {},
|
|
599
|
+
coverage: []
|
|
600
|
+
}
|
|
601
|
+
];
|
|
602
|
+
}) : [], sheets = [...cachedSheets, ...uncachedSheets], definedNames = serializeVersionedExternalDefinedNames(link.definedNames), tables = serializeVersionedExternalTables(link.tables), aliases = [link.name, target.name, target.uri].filter(
|
|
603
|
+
(alias) => typeof alias == "string" && alias.length > 0
|
|
604
|
+
);
|
|
605
|
+
return {
|
|
606
|
+
...aliases.length > 0 ? { aliases: [...new Set(aliases)] } : {},
|
|
607
|
+
...definedNames ? { definedNames } : {},
|
|
608
|
+
sheets,
|
|
609
|
+
...tables ? { tables } : {},
|
|
610
|
+
...typeof target.uri == "string" ? { target: target.uri } : typeof target.name == "string" ? { target: target.name } : typeof link.name == "string" ? { target: link.name } : {},
|
|
611
|
+
unitId: String(link.slot)
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
function serializeVersionedExternalDefinedNames(value) {
|
|
615
|
+
if (!Array.isArray(value))
|
|
616
|
+
return;
|
|
617
|
+
let result = {};
|
|
618
|
+
for (let item of value)
|
|
619
|
+
!isRecord(item) || typeof item.name != "string" || (result[item.name] = {
|
|
620
|
+
name: item.name,
|
|
621
|
+
...typeof item.formulaOrRefString == "string" ? { formulaOrRefString: item.formulaOrRefString } : {}
|
|
622
|
+
});
|
|
623
|
+
return Object.keys(result).length > 0 ? result : void 0;
|
|
624
|
+
}
|
|
625
|
+
function serializeVersionedExternalTables(value) {
|
|
626
|
+
if (!Array.isArray(value))
|
|
627
|
+
return;
|
|
628
|
+
let result = {};
|
|
629
|
+
for (let item of value) {
|
|
630
|
+
if (!isRecord(item) || typeof item.name != "string" || typeof item.sheetName != "string" || !isRange(item.range)) continue;
|
|
631
|
+
let columns = Array.isArray(item.columns) ? item.columns.flatMap((column) => {
|
|
632
|
+
if (!isRecord(column)) return [];
|
|
633
|
+
let { name: name2 } = column;
|
|
634
|
+
return typeof name2 == "string" ? [{ displayName: name2 }] : [];
|
|
635
|
+
}) : [];
|
|
636
|
+
result[item.name] = {
|
|
637
|
+
sheetId: item.sheetName,
|
|
638
|
+
range: item.range,
|
|
639
|
+
columns,
|
|
640
|
+
showHeader: item.showHeader !== !1
|
|
641
|
+
};
|
|
642
|
+
}
|
|
643
|
+
return Object.keys(result).length > 0 ? result : void 0;
|
|
644
|
+
}
|
|
645
|
+
function serializeVersionedExternalSheet(sheet) {
|
|
646
|
+
if (!isRecord(sheet) || typeof sheet.name != "string") return null;
|
|
647
|
+
let cellData = {};
|
|
648
|
+
if (Array.isArray(sheet.cells))
|
|
649
|
+
for (let cell of sheet.cells) {
|
|
650
|
+
if (!isExternalCell(cell)) continue;
|
|
651
|
+
let { row, column } = cell;
|
|
652
|
+
(cellData[row] ??= {})[column] = {
|
|
653
|
+
v: cell.value,
|
|
654
|
+
...typeof cell.valueType == "number" ? { t: cell.valueType } : {}
|
|
655
|
+
};
|
|
656
|
+
}
|
|
657
|
+
return {
|
|
658
|
+
name: sheet.name,
|
|
659
|
+
...typeof sheet.sheetId == "string" ? { sheetId: sheet.sheetId } : {},
|
|
660
|
+
rowCount: typeof sheet.rowCount == "number" ? sheet.rowCount : 0,
|
|
661
|
+
columnCount: typeof sheet.columnCount == "number" ? sheet.columnCount : 0,
|
|
662
|
+
cellData,
|
|
663
|
+
coverage: Array.isArray(sheet.coverage) ? sheet.coverage.filter(isRange) : []
|
|
664
|
+
};
|
|
665
|
+
}
|
|
666
|
+
function isRange(value) {
|
|
667
|
+
return value != null && typeof value == "object" && "startRow" in value && typeof value.startRow == "number" && "endRow" in value && typeof value.endRow == "number" && "startColumn" in value && typeof value.startColumn == "number" && "endColumn" in value && typeof value.endColumn == "number";
|
|
668
|
+
}
|
|
669
|
+
function isRustTableSnapshot(value) {
|
|
670
|
+
return value != null && typeof value == "object" && "sheetId" in value && typeof value.sheetId == "string" && "range" in value && isRange(value.range) && "columns" in value && Array.isArray(value.columns);
|
|
671
|
+
}
|
|
672
|
+
function isExternalCell(value) {
|
|
673
|
+
return isRecord(value) && Number.isInteger(value.row) && Number.isInteger(value.column);
|
|
674
|
+
}
|
|
675
|
+
function serializeExternalDataUnit(unitId, unit) {
|
|
676
|
+
if (!unit || typeof unit != "object")
|
|
677
|
+
return null;
|
|
678
|
+
let record = unit;
|
|
679
|
+
if (!record.sheets || typeof record.sheets != "object")
|
|
680
|
+
return null;
|
|
681
|
+
let sheets = Object.values(record.sheets).map((sheet) => serializeExternalSheet(sheet)).filter((sheet) => sheet != null);
|
|
682
|
+
if (sheets.length === 0)
|
|
683
|
+
return null;
|
|
684
|
+
let definedNames = serializeExternalDefinedNames(record.definedNames);
|
|
685
|
+
return {
|
|
686
|
+
...definedNames === void 0 ? {} : { definedNames },
|
|
687
|
+
sheets,
|
|
688
|
+
...typeof record.target == "string" ? { target: record.target } : {},
|
|
689
|
+
unitId
|
|
690
|
+
};
|
|
691
|
+
}
|
|
692
|
+
function serializeExternalLink(link) {
|
|
693
|
+
if (!isRecord(link))
|
|
694
|
+
return null;
|
|
695
|
+
let record = link;
|
|
696
|
+
if (!Array.isArray(record.sheets))
|
|
697
|
+
return null;
|
|
698
|
+
let sheets = record.sheets.map((sheet) => serializeExternalSheet(sheet)).filter((sheet) => sheet != null);
|
|
699
|
+
if (sheets.length === 0)
|
|
700
|
+
return null;
|
|
701
|
+
let definedNames = serializeExternalDefinedNames(record.definedNames), tables = serializeExternalTables(record.tables);
|
|
702
|
+
return {
|
|
703
|
+
...definedNames === void 0 ? {} : { definedNames },
|
|
704
|
+
sheets,
|
|
705
|
+
...tables === void 0 ? {} : { tables },
|
|
706
|
+
...typeof record.target == "string" ? { target: record.target } : {},
|
|
707
|
+
...typeof record.unitId == "string" ? { unitId: record.unitId } : {}
|
|
708
|
+
};
|
|
709
|
+
}
|
|
710
|
+
function serializeExternalTables(value) {
|
|
711
|
+
if (!isRecord(value)) return;
|
|
712
|
+
let result = {};
|
|
713
|
+
for (let [name2, table] of Object.entries(value))
|
|
714
|
+
!table || typeof table != "object" || isRustTableSnapshot(table) && (result[name2] = table);
|
|
715
|
+
return Object.keys(result).length > 0 ? result : void 0;
|
|
716
|
+
}
|
|
717
|
+
function serializeExternalDefinedNames(value) {
|
|
718
|
+
if (!isRecord(value))
|
|
719
|
+
return;
|
|
720
|
+
let definedNames = {};
|
|
721
|
+
for (let [key, item] of Object.entries(value)) {
|
|
722
|
+
if (!isRecord(item))
|
|
723
|
+
continue;
|
|
724
|
+
let record = item, name2 = typeof record.name == "string" ? record.name : key;
|
|
725
|
+
definedNames[key] = {
|
|
726
|
+
...typeof record.id == "string" ? { id: record.id } : {},
|
|
727
|
+
name: name2,
|
|
728
|
+
...typeof record.formulaOrRefString == "string" ? { formulaOrRefString: record.formulaOrRefString } : {},
|
|
729
|
+
...typeof record.localSheetId == "string" ? { localSheetId: record.localSheetId } : {}
|
|
730
|
+
};
|
|
731
|
+
}
|
|
732
|
+
return Object.keys(definedNames).length > 0 ? definedNames : void 0;
|
|
733
|
+
}
|
|
734
|
+
function serializeExternalSheet(sheet) {
|
|
735
|
+
if (!sheet || typeof sheet != "object")
|
|
736
|
+
return null;
|
|
737
|
+
let record = sheet;
|
|
738
|
+
return typeof record.name != "string" ? null : {
|
|
739
|
+
name: record.name,
|
|
740
|
+
...typeof record.sheetId == "string" ? { sheetId: record.sheetId } : {},
|
|
741
|
+
rowCount: typeof record.rowCount == "number" ? record.rowCount : 0,
|
|
742
|
+
columnCount: typeof record.columnCount == "number" ? record.columnCount : 0,
|
|
743
|
+
cellData: serializeCellData(record.cellData)
|
|
744
|
+
};
|
|
745
|
+
}
|
|
746
|
+
function serializeDefinedNames(definedNames, snapshot) {
|
|
747
|
+
let direct = definedNames && Object.keys(definedNames).length > 0 ? definedNames : extractDefinedNames(snapshot), sheetIds = new Set(Object.keys(snapshot.sheets ?? {})), sheetNameToId = new Map(
|
|
748
|
+
Object.entries(snapshot.sheets ?? {}).map(([sheetId, sheet]) => [sheet.name, sheetId])
|
|
749
|
+
);
|
|
750
|
+
return Object.fromEntries(
|
|
751
|
+
Object.entries(direct).map(([id, definedName]) => [
|
|
752
|
+
id,
|
|
753
|
+
{
|
|
754
|
+
id: definedName.id,
|
|
755
|
+
name: definedName.name,
|
|
756
|
+
formulaOrRefString: definedName.formulaOrRefString,
|
|
757
|
+
localSheetId: normalizeDefinedNameLocalSheetId(
|
|
758
|
+
definedName.localSheetId,
|
|
759
|
+
definedName.formulaOrRefString,
|
|
760
|
+
sheetIds,
|
|
761
|
+
sheetNameToId
|
|
762
|
+
)
|
|
763
|
+
}
|
|
764
|
+
])
|
|
765
|
+
);
|
|
766
|
+
}
|
|
767
|
+
function normalizeDefinedNameLocalSheetId(localSheetId, formulaOrRefString, sheetIds, sheetNameToId) {
|
|
768
|
+
if (!localSheetId || localSheetId === "AllDefaultWorkbook")
|
|
769
|
+
return localSheetId;
|
|
770
|
+
let sheetName = extractLeadingSheetName(formulaOrRefString), sheetIdFromFormula = sheetName ? sheetNameToId.get(sheetName) : void 0;
|
|
771
|
+
return sheetIdFromFormula && sheetIdFromFormula !== localSheetId ? sheetIdFromFormula : sheetIds.has(localSheetId) || !sheetName ? localSheetId : sheetIdFromFormula ?? localSheetId;
|
|
772
|
+
}
|
|
773
|
+
function extractLeadingSheetName(formulaOrRefString) {
|
|
774
|
+
if (!formulaOrRefString)
|
|
775
|
+
return;
|
|
776
|
+
let quotedMatch = /^'((?:[^']|'')+)'!/.exec(formulaOrRefString);
|
|
777
|
+
return quotedMatch ? quotedMatch[1].replace(/''/g, "'") : /^([^=!]+)!/.exec(formulaOrRefString)?.[1];
|
|
778
|
+
}
|
|
779
|
+
function extractDefinedNames(snapshot) {
|
|
780
|
+
let direct = snapshot.definedNames;
|
|
781
|
+
if (direct && Object.keys(direct).length > 0)
|
|
782
|
+
return direct;
|
|
783
|
+
for (let resource of Object.values(
|
|
784
|
+
snapshot.resources ?? {}
|
|
785
|
+
)) {
|
|
786
|
+
if (resource?.name !== "SHEET_DEFINED_NAME_PLUGIN")
|
|
787
|
+
continue;
|
|
788
|
+
let data = parseResourceData(resource.data);
|
|
789
|
+
return data && typeof data == "object" ? data : {};
|
|
790
|
+
}
|
|
791
|
+
return {};
|
|
792
|
+
}
|
|
793
|
+
function serializeSheetSnapshot(sheetId, sheet, styles, precisionAsDisplayed) {
|
|
794
|
+
return sheet ? {
|
|
795
|
+
sheetId: sheet.id ?? sheetId,
|
|
796
|
+
name: sheet.name,
|
|
797
|
+
rowCount: sheet.rowCount ?? 0,
|
|
798
|
+
columnCount: sheet.columnCount ?? 0,
|
|
799
|
+
transitionEvaluation: sheet.transitionEvaluation === !0,
|
|
800
|
+
cellData: serializeCellData(sheet.cellData, styles, precisionAsDisplayed),
|
|
801
|
+
rowData: serializeVisibilityData(sheet.rowData),
|
|
802
|
+
columnData: serializeVisibilityData(sheet.columnData)
|
|
803
|
+
} : null;
|
|
804
|
+
}
|
|
805
|
+
function serializeCellData(cellData = {}, styles, precisionAsDisplayed = !1) {
|
|
806
|
+
let result = {}, rawCellData = cellData instanceof ObjectMatrix ? cellData.getData() : cellData;
|
|
807
|
+
for (let [rowKey, row] of Object.entries(rawCellData ?? {})) {
|
|
808
|
+
if (!row)
|
|
809
|
+
continue;
|
|
810
|
+
let serializedRow = {};
|
|
811
|
+
for (let [colKey, cell] of Object.entries(row)) {
|
|
812
|
+
if (!cell || typeof cell != "object")
|
|
813
|
+
continue;
|
|
814
|
+
let cellRecord = cell, value = {};
|
|
815
|
+
if ("v" in cellRecord && (value.v = cellRecord.v), typeof cellRecord.t == "number" && (value.t = cellRecord.t), "p" in cellRecord && (value.p = cellRecord.p), typeof cellRecord.f == "string" && (value.f = cellRecord.f), typeof cellRecord.si == "string" && (value.si = cellRecord.si), typeof cellRecord.ref == "string" && (value.ref = cellRecord.ref), typeof cellRecord.xf == "string" && (value.xf = cellRecord.xf), "s" in cellRecord && (value.s = cellRecord.s), precisionAsDisplayed && typeof cellRecord.f == "string") {
|
|
816
|
+
let displayPrecision = inferDisplayPrecision(cellRecord.s, styles);
|
|
817
|
+
displayPrecision !== void 0 && (value.displayPrecision = displayPrecision);
|
|
818
|
+
}
|
|
819
|
+
Object.keys(value).length > 0 && (serializedRow[Number(colKey)] = value);
|
|
820
|
+
}
|
|
821
|
+
Object.keys(serializedRow).length > 0 && (result[Number(rowKey)] = serializedRow);
|
|
822
|
+
}
|
|
823
|
+
return result;
|
|
824
|
+
}
|
|
825
|
+
function serializeCellDataInRanges(cellData, ranges) {
|
|
826
|
+
let serialized = serializeCellData(cellData), result = {};
|
|
827
|
+
for (let [rowKey, row] of Object.entries(serialized)) {
|
|
828
|
+
let rowIndex = Number(rowKey);
|
|
829
|
+
for (let [columnKey, value] of Object.entries(row)) {
|
|
830
|
+
let columnIndex = Number(columnKey);
|
|
831
|
+
ranges.some(
|
|
832
|
+
(range) => rowIndex >= range.startRow && rowIndex <= range.endRow && columnIndex >= range.startColumn && columnIndex <= range.endColumn
|
|
833
|
+
) && ((result[rowIndex] ??= {})[columnIndex] = value);
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
return result;
|
|
837
|
+
}
|
|
838
|
+
function inferDisplayPrecision(styleId, styles) {
|
|
839
|
+
if (typeof styleId != "string" || !styles || typeof styles != "object")
|
|
840
|
+
return;
|
|
841
|
+
let style = styles[styleId];
|
|
842
|
+
if (!style || typeof style != "object")
|
|
843
|
+
return;
|
|
844
|
+
let numberFormat = style.n;
|
|
845
|
+
if (!numberFormat || typeof numberFormat != "object")
|
|
846
|
+
return;
|
|
847
|
+
let pattern = numberFormat.pattern;
|
|
848
|
+
return typeof pattern == "string" ? inferFixedNumberFormatPrecision(pattern) : void 0;
|
|
849
|
+
}
|
|
850
|
+
function inferFixedNumberFormatPrecision(pattern) {
|
|
851
|
+
let cleaned = (pattern.split(";")[0] ?? pattern).replace(/"[^"]*"/gu, "").replace(/\\./gu, "").replace(/_.|\*./gu, "");
|
|
852
|
+
if (!/[0#?]/u.test(cleaned) || /[%Ee]|[ymdhsa]/iu.test(cleaned))
|
|
853
|
+
return;
|
|
854
|
+
let decimalMatch = cleaned.match(/\.([0#?]+)/u);
|
|
855
|
+
return decimalMatch?.[1] ? decimalMatch[1].length : 0;
|
|
856
|
+
}
|
|
857
|
+
function serializeVisibilityData(data = {}) {
|
|
858
|
+
let result = {};
|
|
859
|
+
for (let [indexKey, metadata] of Object.entries(data))
|
|
860
|
+
!metadata || typeof metadata != "object" || !("hd" in metadata) || (result[Number(indexKey)] = {
|
|
861
|
+
hd: metadata.hd
|
|
862
|
+
});
|
|
863
|
+
return result;
|
|
864
|
+
}
|
|
865
|
+
function errorToFormulaCalculationError(code, error) {
|
|
866
|
+
return {
|
|
867
|
+
code,
|
|
868
|
+
message: error instanceof Error ? error.message : String(error)
|
|
869
|
+
};
|
|
870
|
+
}
|
|
871
|
+
function isRecord(value) {
|
|
872
|
+
return typeof value == "object" && value !== null && !Array.isArray(value);
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
// src/controllers/rust-engine-sync.controller.ts
|
|
876
|
+
var rustEngineSyncState = {
|
|
877
|
+
snapshotEpoch: 0,
|
|
878
|
+
dependencyInvalidationEpoch: 0
|
|
879
|
+
};
|
|
880
|
+
function getRustEngineSyncState() {
|
|
881
|
+
return { ...rustEngineSyncState };
|
|
882
|
+
}
|
|
883
|
+
function markRustSnapshotLoaded() {
|
|
884
|
+
rustEngineSyncState.snapshotEpoch += 1, rustEngineSyncState.dependencyInvalidationEpoch += 1;
|
|
885
|
+
}
|
|
886
|
+
function markRustFormulaDependenciesInvalidated() {
|
|
887
|
+
rustEngineSyncState.dependencyInvalidationEpoch += 1;
|
|
888
|
+
}
|
|
889
|
+
function emitRustEngineSyncDebugEvent(event) {
|
|
890
|
+
let hook = globalThis.__UNIVER_RUST_FORMULA_DEBUG_HOOK__;
|
|
891
|
+
typeof hook == "function" && hook(event);
|
|
892
|
+
}
|
|
893
|
+
function summarizeObjectMatrixPayload(value) {
|
|
894
|
+
if (!value || typeof value != "object")
|
|
895
|
+
return {};
|
|
896
|
+
let cellValueCells = 0;
|
|
897
|
+
for (let row of Object.values(value))
|
|
898
|
+
!row || typeof row != "object" || (cellValueCells += Object.keys(row).length);
|
|
899
|
+
return {
|
|
900
|
+
cellValueRows: Object.keys(value).length,
|
|
901
|
+
cellValueCells
|
|
902
|
+
};
|
|
903
|
+
}
|
|
904
|
+
function hasObjectMatrixValues(value) {
|
|
905
|
+
return !value || typeof value != "object" ? !1 : Object.values(value).some(
|
|
906
|
+
(row) => row != null && typeof row == "object" && Object.keys(row).length > 0
|
|
907
|
+
);
|
|
908
|
+
}
|
|
909
|
+
function hasRecordEntries(value) {
|
|
910
|
+
return value != null && typeof value == "object" && Object.keys(value).length > 0;
|
|
911
|
+
}
|
|
912
|
+
function countDisplayPrecisionCells(snapshot) {
|
|
913
|
+
let count = 0;
|
|
914
|
+
for (let workbook of snapshot.workbooks)
|
|
915
|
+
for (let sheet of workbook.sheets)
|
|
916
|
+
for (let row of Object.values(sheet.cellData))
|
|
917
|
+
for (let cell of Object.values(row))
|
|
918
|
+
typeof cell.displayPrecision == "number" && (count += 1);
|
|
919
|
+
return count;
|
|
920
|
+
}
|
|
921
|
+
var RustEngineSyncController = class extends Disposable {
|
|
922
|
+
constructor(_commandService) {
|
|
923
|
+
super();
|
|
924
|
+
this._commandService = _commandService;
|
|
925
|
+
this._initialize();
|
|
926
|
+
}
|
|
927
|
+
_commandService;
|
|
928
|
+
_nativeReady = !1;
|
|
929
|
+
_snapshotLoaded = !1;
|
|
930
|
+
_projectionLoadPromise = null;
|
|
931
|
+
_pendingMutations = [];
|
|
932
|
+
_initialize() {
|
|
933
|
+
this.disposeWithMe(
|
|
934
|
+
this._commandService.onCommandExecuted((command, options) => {
|
|
935
|
+
this._shouldSyncMutation(command, options) && this._queueOrSyncMutation(this._serializeMutation(command, options));
|
|
936
|
+
})
|
|
937
|
+
);
|
|
938
|
+
}
|
|
939
|
+
async loadProjection(workbooks) {
|
|
940
|
+
let loadPromise = this._loadProjection(workbooks);
|
|
941
|
+
this._projectionLoadPromise = loadPromise;
|
|
942
|
+
try {
|
|
943
|
+
await loadPromise;
|
|
944
|
+
} finally {
|
|
945
|
+
this._projectionLoadPromise === loadPromise && (this._projectionLoadPromise = null);
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
async waitForProjectionLoad() {
|
|
949
|
+
await this._projectionLoadPromise;
|
|
950
|
+
}
|
|
951
|
+
async _loadProjection(workbooks) {
|
|
952
|
+
await loadNativeBinding(), this._nativeReady = !0;
|
|
953
|
+
let serializeStartedAt = performance.now(), snapshot = serializeRuntimeWorkbookSnapshots(workbooks);
|
|
954
|
+
this._loadSerializedSnapshot(snapshot, performance.now() - serializeStartedAt);
|
|
955
|
+
}
|
|
956
|
+
applyProjectionMutation(mutation) {
|
|
957
|
+
this._queueOrSyncMutation(mutation);
|
|
958
|
+
}
|
|
959
|
+
upsertReferenceData(config, needs) {
|
|
960
|
+
let mutations = createReferenceDataUpsertMutations(config, needs);
|
|
961
|
+
return mutations.forEach((mutation) => this._queueOrSyncMutation(mutation)), mutations.length;
|
|
962
|
+
}
|
|
963
|
+
disposeProjectionWorkbook(unitId) {
|
|
964
|
+
if (!(!this._nativeReady || !this._snapshotLoaded))
|
|
965
|
+
try {
|
|
966
|
+
disposeWorkbookOnRust(unitId), markRustFormulaDependenciesInvalidated();
|
|
967
|
+
} catch {
|
|
968
|
+
this._markProjectionDesynced();
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
dispose() {
|
|
972
|
+
if (super.dispose(), this._pendingMutations.length = 0, this._projectionLoadPromise = null, !this._nativeReady) {
|
|
973
|
+
this._snapshotLoaded = !1;
|
|
974
|
+
return;
|
|
975
|
+
}
|
|
976
|
+
try {
|
|
977
|
+
disposeAllWorkbooksOnRust();
|
|
978
|
+
} catch {
|
|
979
|
+
this._markProjectionDesynced();
|
|
980
|
+
return;
|
|
981
|
+
}
|
|
982
|
+
this._nativeReady = !1, this._snapshotLoaded = !1;
|
|
983
|
+
}
|
|
984
|
+
_loadSerializedSnapshot(snapshot, serializeMs) {
|
|
985
|
+
let precisionAsDisplayedWorkbookCount = snapshot.workbooks.filter(
|
|
986
|
+
(workbook) => workbook.calculation?.fullPrecision === !1
|
|
987
|
+
).length, displayPrecisionCellCount = countDisplayPrecisionCells(snapshot), pendingCountCoveredBySnapshot = this._pendingMutations.length, stringifyStartedAt = performance.now(), snapshotJson = JSON.stringify(snapshot), stringifyMs = performance.now() - stringifyStartedAt, snapshotBuffer = globalThis.Buffer?.from(snapshotJson), nativeStartedAt = performance.now(), nativeOutput = snapshotBuffer ? loadSnapshotBinaryOnRust(snapshotBuffer) : loadSnapshotOnRust(snapshotJson), nativeMs = performance.now() - nativeStartedAt, nativeTimings;
|
|
988
|
+
try {
|
|
989
|
+
nativeTimings = JSON.parse(nativeOutput).timingsMs;
|
|
990
|
+
} catch {
|
|
991
|
+
nativeTimings = void 0;
|
|
992
|
+
}
|
|
993
|
+
emitRustEngineSyncDebugEvent({
|
|
994
|
+
type: "loadSnapshot",
|
|
995
|
+
payload: {
|
|
996
|
+
workbookCount: snapshot.workbooks.length,
|
|
997
|
+
serializeMs,
|
|
998
|
+
stringifyMs,
|
|
999
|
+
nativeMs,
|
|
1000
|
+
precisionAsDisplayedWorkbookCount,
|
|
1001
|
+
displayPrecisionCellCount,
|
|
1002
|
+
snapshotBytes: snapshotBuffer?.byteLength ?? snapshotJson.length,
|
|
1003
|
+
transport: snapshotBuffer ? "binary-json" : "string-json",
|
|
1004
|
+
nativeTimings
|
|
1005
|
+
}
|
|
1006
|
+
}), this._pendingMutations.splice(0, pendingCountCoveredBySnapshot), this._snapshotLoaded = !0, markRustSnapshotLoaded(), this._flushPendingMutations();
|
|
1007
|
+
}
|
|
1008
|
+
_queueOrSyncMutation(mutation) {
|
|
1009
|
+
if (!this._nativeReady || !this._snapshotLoaded) {
|
|
1010
|
+
this._pendingMutations.push(mutation);
|
|
1011
|
+
return;
|
|
1012
|
+
}
|
|
1013
|
+
this._syncMutation(mutation);
|
|
1014
|
+
}
|
|
1015
|
+
_flushPendingMutations() {
|
|
1016
|
+
for (; this._pendingMutations.length > 0; ) {
|
|
1017
|
+
let mutation = this._pendingMutations.shift();
|
|
1018
|
+
mutation && this._syncMutation(mutation);
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
_syncMutation(mutation) {
|
|
1022
|
+
let totalStartedAt = performance.now(), stringifyStartedAt = performance.now(), payload = JSON.stringify(mutation), stringifyMs = performance.now() - stringifyStartedAt, nativeStartedAt = performance.now();
|
|
1023
|
+
try {
|
|
1024
|
+
applyMutationOnRust(payload), isRustIncrementalDependencyMutation(mutation.id) || markRustFormulaDependenciesInvalidated();
|
|
1025
|
+
} catch {
|
|
1026
|
+
this._markProjectionDesynced();
|
|
1027
|
+
} finally {
|
|
1028
|
+
emitRustEngineSyncDebugEvent({
|
|
1029
|
+
type: "applyMutation",
|
|
1030
|
+
payload: {
|
|
1031
|
+
id: mutation.id,
|
|
1032
|
+
stringifyMs,
|
|
1033
|
+
nativeMs: performance.now() - nativeStartedAt,
|
|
1034
|
+
totalMs: performance.now() - totalStartedAt,
|
|
1035
|
+
...summarizeObjectMatrixPayload(
|
|
1036
|
+
mutation.params?.cellValue
|
|
1037
|
+
)
|
|
1038
|
+
}
|
|
1039
|
+
});
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
_markProjectionDesynced() {
|
|
1043
|
+
this._nativeReady = !1, this._snapshotLoaded = !1;
|
|
1044
|
+
}
|
|
1045
|
+
_shouldSyncMutation(command, options) {
|
|
1046
|
+
if (command.type !== CommandType.MUTATION || !isRustFormulaRelevantMutation(command.id))
|
|
1047
|
+
return !1;
|
|
1048
|
+
let syncOptions = options;
|
|
1049
|
+
if (syncOptions?.fromRustFormulaEngine === !0 || syncOptions?.applyFormulaCalculationResult === !0 || command.id === "sheet.mutation.set-range-values" && !hasObjectMatrixValues(command.params?.cellValue))
|
|
1050
|
+
return !1;
|
|
1051
|
+
if (command.id === "formula.mutation.set-formula-calculation-result") {
|
|
1052
|
+
let params = command.params;
|
|
1053
|
+
if (!hasRecordEntries(params?.unitData) && !hasRecordEntries(params?.unitOtherData))
|
|
1054
|
+
return !1;
|
|
1055
|
+
}
|
|
1056
|
+
if (command.id === "formula.mutation.set-array-formula-data") {
|
|
1057
|
+
let params = command.params;
|
|
1058
|
+
if (!hasRecordEntries(params?.arrayFormulaRange) && !hasRecordEntries(params?.arrayFormulaCellData) && !hasRecordEntries(params?.arrayFormulaEmbedded))
|
|
1059
|
+
return !1;
|
|
1060
|
+
}
|
|
1061
|
+
return !0;
|
|
1062
|
+
}
|
|
1063
|
+
_serializeMutation(command, options) {
|
|
1064
|
+
let dirtyRanges = options?.dirtyRanges;
|
|
1065
|
+
return {
|
|
1066
|
+
id: command.id,
|
|
1067
|
+
params: command.params ?? {},
|
|
1068
|
+
dirtyRanges: Array.isArray(dirtyRanges) ? dirtyRanges : []
|
|
1069
|
+
};
|
|
1070
|
+
}
|
|
1071
|
+
};
|
|
1072
|
+
setDependencies(RustEngineSyncController, [ICommandService]);
|
|
1073
|
+
|
|
1074
|
+
// src/numfmt.ts
|
|
1075
|
+
var nativeBindingReady = null;
|
|
1076
|
+
function ensureNativeBinding() {
|
|
1077
|
+
return nativeBindingReady ??= loadNativeBinding().catch((error) => {
|
|
1078
|
+
throw nativeBindingReady = null, error;
|
|
1079
|
+
}), nativeBindingReady;
|
|
1080
|
+
}
|
|
1081
|
+
function parseJsonOutput(output) {
|
|
1082
|
+
return JSON.parse(output);
|
|
1083
|
+
}
|
|
1084
|
+
async function formatNumberBatch(input) {
|
|
1085
|
+
return await ensureNativeBinding(), parseJsonOutput(formatNumberBatchOnRust(JSON.stringify(input)));
|
|
1086
|
+
}
|
|
1087
|
+
async function parseNumberFormatBatch(input) {
|
|
1088
|
+
return await ensureNativeBinding(), parseJsonOutput(parseNumberFormatInputBatchOnRust(JSON.stringify(input)));
|
|
1089
|
+
}
|
|
1090
|
+
async function parseNumberFormatMatrixBatch(input) {
|
|
1091
|
+
return await ensureNativeBinding(), parseJsonOutput(
|
|
1092
|
+
parseNumberFormatMatrixBatchOnRust(JSON.stringify(input))
|
|
1093
|
+
);
|
|
1094
|
+
}
|
|
1095
|
+
async function analyzeNumberFormatBatch(input) {
|
|
1096
|
+
return await ensureNativeBinding(), parseJsonOutput(analyzeNumberFormatBatchOnRust(JSON.stringify(input)));
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
// src/plugin.ts
|
|
1100
|
+
import { IConfigService as IConfigService2, Injector, setDependencies as setDependencies4, touchDependencies } from "@univerjs/core";
|
|
1101
|
+
import { ICalculateFormulaService } from "@univerjs/engine-formula";
|
|
1102
|
+
import { UniverProFormulaEnginePlugin } from "@univerjs-pro/engine-formula";
|
|
1103
|
+
|
|
1104
|
+
// package.json
|
|
1105
|
+
var name = "@univerjs-pro/engine-formula-rust", version = "1.0.0-insiders.20260725-1b9c8d8";
|
|
1106
|
+
|
|
1107
|
+
// src/controllers/rust-same-runtime-projection.controller.ts
|
|
1108
|
+
import {
|
|
1109
|
+
Disposable as Disposable2,
|
|
1110
|
+
CommandType as CommandType2,
|
|
1111
|
+
ICommandService as ICommandService2,
|
|
1112
|
+
IUniverInstanceService,
|
|
1113
|
+
LocaleType,
|
|
1114
|
+
setDependencies as setDependencies2,
|
|
1115
|
+
toDisposable,
|
|
1116
|
+
UniverInstanceType
|
|
1117
|
+
} from "@univerjs/core";
|
|
1118
|
+
import { FormulaDataModel, ISuperTableService, SetFormulaCalculationResultMutation } from "@univerjs/engine-formula";
|
|
1119
|
+
var RustSameRuntimeProjectionController = class extends Disposable2 {
|
|
1120
|
+
constructor(_univerInstanceService, _rustEngineSyncController, _formulaDataModel, _superTableService, _commandService) {
|
|
1121
|
+
super();
|
|
1122
|
+
this._univerInstanceService = _univerInstanceService;
|
|
1123
|
+
this._rustEngineSyncController = _rustEngineSyncController;
|
|
1124
|
+
this._formulaDataModel = _formulaDataModel;
|
|
1125
|
+
this._superTableService = _superTableService;
|
|
1126
|
+
this._commandService = _commandService;
|
|
1127
|
+
this._initialize();
|
|
1128
|
+
}
|
|
1129
|
+
_univerInstanceService;
|
|
1130
|
+
_rustEngineSyncController;
|
|
1131
|
+
_formulaDataModel;
|
|
1132
|
+
_superTableService;
|
|
1133
|
+
_commandService;
|
|
1134
|
+
_projectionReload = null;
|
|
1135
|
+
_projectionReloadRequested = !1;
|
|
1136
|
+
_initialize() {
|
|
1137
|
+
this._scheduleProjectionReload(), this.disposeWithMe(
|
|
1138
|
+
toDisposable(
|
|
1139
|
+
this._univerInstanceService.getTypeOfUnitAdded$(UniverInstanceType.UNIVER_SHEET).subscribe(() => {
|
|
1140
|
+
this._scheduleProjectionReload();
|
|
1141
|
+
})
|
|
1142
|
+
)
|
|
1143
|
+
), this.disposeWithMe(
|
|
1144
|
+
toDisposable(
|
|
1145
|
+
this._univerInstanceService.getTypeOfUnitAdded$(UniverInstanceType.UNIVER_BASE).subscribe(() => {
|
|
1146
|
+
this._scheduleProjectionReload();
|
|
1147
|
+
})
|
|
1148
|
+
)
|
|
1149
|
+
), this.disposeWithMe(
|
|
1150
|
+
this._commandService.onCommandExecuted((command) => {
|
|
1151
|
+
command.type !== CommandType2.MUTATION || !hasUnitId(command.params) || this._univerInstanceService.getUnit(command.params.unitId, UniverInstanceType.UNIVER_BASE) && (hasTrigger(command.params) && command.params.trigger === SetFormulaCalculationResultMutation.id || this._scheduleProjectionReload());
|
|
1152
|
+
})
|
|
1153
|
+
), this.disposeWithMe(
|
|
1154
|
+
toDisposable(
|
|
1155
|
+
this._univerInstanceService.getTypeOfUnitDisposed$(UniverInstanceType.UNIVER_BASE).subscribe((base) => {
|
|
1156
|
+
this._rustEngineSyncController.disposeProjectionWorkbook(base.getUnitId());
|
|
1157
|
+
})
|
|
1158
|
+
)
|
|
1159
|
+
), this.disposeWithMe(
|
|
1160
|
+
toDisposable(
|
|
1161
|
+
this._univerInstanceService.getTypeOfUnitDisposed$(UniverInstanceType.UNIVER_SHEET).subscribe((workbook) => {
|
|
1162
|
+
this._rustEngineSyncController.disposeProjectionWorkbook(workbook.getUnitId());
|
|
1163
|
+
})
|
|
1164
|
+
)
|
|
1165
|
+
);
|
|
1166
|
+
}
|
|
1167
|
+
_scheduleProjectionReload() {
|
|
1168
|
+
this._projectionReloadRequested = !0, !this._projectionReload && (this._projectionReload = this._drainProjectionReloads().finally(() => {
|
|
1169
|
+
this._projectionReload = null, this._projectionReloadRequested && this._scheduleProjectionReload();
|
|
1170
|
+
}));
|
|
1171
|
+
}
|
|
1172
|
+
async _drainProjectionReloads() {
|
|
1173
|
+
for (; this._projectionReloadRequested; )
|
|
1174
|
+
this._projectionReloadRequested = !1, await this._loadAllWorkbookProjections();
|
|
1175
|
+
}
|
|
1176
|
+
async _loadAllWorkbookProjections() {
|
|
1177
|
+
let workbooks = this._univerInstanceService.getAllUnitsForType(UniverInstanceType.UNIVER_SHEET).map((workbook) => ({
|
|
1178
|
+
unitId: workbook.getUnitId(),
|
|
1179
|
+
snapshot: workbook.getSnapshot()
|
|
1180
|
+
})), calculationData = this._formulaDataModel.getCalculateData(), formulaData = this._formulaDataModel.getFormulaData(), baseWorkbooks = this._univerInstanceService.getAllUnitsForType(UniverInstanceType.UNIVER_BASE).map(
|
|
1181
|
+
(base) => this._createBaseWorkbookProjection(
|
|
1182
|
+
base.getUnitId(),
|
|
1183
|
+
calculationData.allUnitData,
|
|
1184
|
+
calculationData.unitSheetNameMap,
|
|
1185
|
+
calculationData.unitNameMap ?? {},
|
|
1186
|
+
formulaData
|
|
1187
|
+
)
|
|
1188
|
+
).filter((workbook) => workbook != null);
|
|
1189
|
+
workbooks.push(...baseWorkbooks), await this._rustEngineSyncController.loadProjection(workbooks);
|
|
1190
|
+
}
|
|
1191
|
+
_createBaseWorkbookProjection(unitId, allUnitData, unitSheetNameMap, unitNameMap, formulaData) {
|
|
1192
|
+
let unitData = allUnitData[unitId];
|
|
1193
|
+
if (!unitData) return null;
|
|
1194
|
+
let sheetNameMap = unitSheetNameMap[unitId] ?? {}, sheetOrder = Object.keys(unitData), resources = this._createBaseTableResource(unitId), sheets = {};
|
|
1195
|
+
for (let sheetId of sheetOrder) {
|
|
1196
|
+
let sheet = unitData[sheetId];
|
|
1197
|
+
if (!sheet) continue;
|
|
1198
|
+
let cellData = this._rawCellData(sheet.cellData);
|
|
1199
|
+
for (let [rowKey, row] of Object.entries(formulaData[unitId]?.[sheetId] ?? {}))
|
|
1200
|
+
for (let [columnKey, formula] of Object.entries(row ?? {})) {
|
|
1201
|
+
if (!formula) continue;
|
|
1202
|
+
let rowIndex = Number(rowKey), columnIndex = Number(columnKey), current = cellData[rowIndex]?.[columnIndex] ?? {};
|
|
1203
|
+
(cellData[rowIndex] ??= {})[columnIndex] = { ...current, ...formula };
|
|
1204
|
+
}
|
|
1205
|
+
sheets[sheetId] = {
|
|
1206
|
+
id: sheetId,
|
|
1207
|
+
name: Object.entries(sheetNameMap).find(([, currentSheetId]) => currentSheetId === sheetId)?.[0] ?? sheetId,
|
|
1208
|
+
rowCount: sheet.rowCount,
|
|
1209
|
+
columnCount: sheet.columnCount,
|
|
1210
|
+
cellData,
|
|
1211
|
+
rowData: sheet.rowData,
|
|
1212
|
+
columnData: sheet.columnData
|
|
1213
|
+
};
|
|
1214
|
+
}
|
|
1215
|
+
return {
|
|
1216
|
+
unitId,
|
|
1217
|
+
snapshot: {
|
|
1218
|
+
id: unitId,
|
|
1219
|
+
name: unitNameMap[unitId]?.name ?? unitId,
|
|
1220
|
+
appVersion: "",
|
|
1221
|
+
locale: LocaleType.EN_US,
|
|
1222
|
+
styles: {},
|
|
1223
|
+
sheetOrder,
|
|
1224
|
+
sheets,
|
|
1225
|
+
resources
|
|
1226
|
+
}
|
|
1227
|
+
};
|
|
1228
|
+
}
|
|
1229
|
+
_createBaseTableResource(unitId) {
|
|
1230
|
+
let tableMap = this._superTableService.getTableMap(unitId);
|
|
1231
|
+
if (!tableMap) return [];
|
|
1232
|
+
let data = {};
|
|
1233
|
+
for (let [name2, table] of tableMap) {
|
|
1234
|
+
let columns = Array.from(table.titleMap.entries()).toSorted((left, right) => left[1] - right[1]).map(([displayName]) => ({ displayName }));
|
|
1235
|
+
(data[table.sheetId] ??= { tables: [] }).tables.push({
|
|
1236
|
+
name: name2,
|
|
1237
|
+
range: table.range,
|
|
1238
|
+
columns,
|
|
1239
|
+
options: { showHeader: table.showHeader !== !1 }
|
|
1240
|
+
});
|
|
1241
|
+
}
|
|
1242
|
+
return [
|
|
1243
|
+
{
|
|
1244
|
+
name: "SHEET_TABLE_PLUGIN",
|
|
1245
|
+
data: JSON.stringify(data)
|
|
1246
|
+
}
|
|
1247
|
+
];
|
|
1248
|
+
}
|
|
1249
|
+
_rawCellData(cellData) {
|
|
1250
|
+
let raw = cellData.getData(), result = {};
|
|
1251
|
+
for (let [row, values] of Object.entries(raw ?? {})) {
|
|
1252
|
+
let rowData = {};
|
|
1253
|
+
for (let [column, value] of Object.entries(values ?? {}))
|
|
1254
|
+
value && (rowData[Number(column)] = { ...value });
|
|
1255
|
+
result[Number(row)] = rowData;
|
|
1256
|
+
}
|
|
1257
|
+
return result;
|
|
1258
|
+
}
|
|
1259
|
+
};
|
|
1260
|
+
function hasUnitId(value) {
|
|
1261
|
+
return value != null && typeof value == "object" && "unitId" in value && typeof value.unitId == "string";
|
|
1262
|
+
}
|
|
1263
|
+
function hasTrigger(value) {
|
|
1264
|
+
return "trigger" in value && typeof value.trigger == "string";
|
|
1265
|
+
}
|
|
1266
|
+
setDependencies2(RustSameRuntimeProjectionController, [
|
|
1267
|
+
IUniverInstanceService,
|
|
1268
|
+
RustEngineSyncController,
|
|
1269
|
+
FormulaDataModel,
|
|
1270
|
+
ISuperTableService,
|
|
1271
|
+
ICommandService2
|
|
1272
|
+
]);
|
|
1273
|
+
|
|
1274
|
+
// src/services/calculate-formula.service.ts
|
|
1275
|
+
import {
|
|
1276
|
+
AsyncLock,
|
|
1277
|
+
createIdentifier,
|
|
1278
|
+
Disposable as Disposable3,
|
|
1279
|
+
ICommandService as ICommandService3,
|
|
1280
|
+
IConfigService,
|
|
1281
|
+
setDependencies as setDependencies3
|
|
1282
|
+
} from "@univerjs/core";
|
|
1283
|
+
import {
|
|
1284
|
+
ENGINE_FORMULA_PLUGIN_CONFIG_KEY,
|
|
1285
|
+
FormulaExecuteStageType,
|
|
1286
|
+
IFeatureCalculationManagerService,
|
|
1287
|
+
IFormulaCurrentConfigService,
|
|
1288
|
+
IFormulaDependencyGenerator,
|
|
1289
|
+
IFormulaRuntimeService,
|
|
1290
|
+
IOtherFormulaManagerService,
|
|
1291
|
+
SetFormulaCalculationResultMutation as SetFormulaCalculationResultMutation2
|
|
1292
|
+
} from "@univerjs/engine-formula";
|
|
1293
|
+
import { ExternalReferencePrefetchPlanner, ExternalReferencePrefetchService } from "@univerjs-pro/engine-formula";
|
|
1294
|
+
import { Subject } from "rxjs";
|
|
1295
|
+
var IRustCalculateFormulaService = createIdentifier(
|
|
1296
|
+
"engine-formula-rust.calculate-formula.service"
|
|
1297
|
+
), DEFAULT_INTERVAL_COUNT = 500, MAX_FEATURE_CALCULATION_PASSES = 8, MAX_EXTERNAL_REFERENCE_PASSES = 8, FORMULA_TREE_TYPE_NORMAL = 0, FORMULA_TREE_TYPE_OTHER = 1, FORMULA_TREE_TYPE_FEATURE = 2;
|
|
1298
|
+
function emitRustFormulaDebugEvent(event) {
|
|
1299
|
+
let hook = globalThis.__UNIVER_RUST_FORMULA_DEBUG_HOOK__;
|
|
1300
|
+
typeof hook == "function" && hook(event);
|
|
1301
|
+
}
|
|
1302
|
+
function firstResultBatchValue(output) {
|
|
1303
|
+
return output.resultBatches?.find((batch) => batch.values.length > 0)?.values[0];
|
|
1304
|
+
}
|
|
1305
|
+
function resultBatchSheetCounts(output) {
|
|
1306
|
+
let counts = {};
|
|
1307
|
+
for (let batch of output.resultBatches ?? []) {
|
|
1308
|
+
let key = `${batch.unitId}/${batch.sheetId}`;
|
|
1309
|
+
counts[key] = (counts[key] ?? 0) + batch.values.length;
|
|
1310
|
+
}
|
|
1311
|
+
return counts;
|
|
1312
|
+
}
|
|
1313
|
+
function rustExecutionOutputToCalculationResult(output) {
|
|
1314
|
+
let patch = rustExecutionOutputToFormulaCalculationPatch(output);
|
|
1315
|
+
return {
|
|
1316
|
+
unitData: patch.unitData,
|
|
1317
|
+
unitOtherData: patch.unitOtherData
|
|
1318
|
+
};
|
|
1319
|
+
}
|
|
1320
|
+
var RustCalculateFormulaService = class extends Disposable3 {
|
|
1321
|
+
constructor(_configService, _currentConfigService, _runtimeService, _formulaDependencyGenerator, _featureCalculationManagerService, _otherFormulaManagerService, _commandService, _rustEngineSyncController, _externalPrefetchPlanner, _externalPrefetchService) {
|
|
1322
|
+
super();
|
|
1323
|
+
this._configService = _configService;
|
|
1324
|
+
this._currentConfigService = _currentConfigService;
|
|
1325
|
+
this._runtimeService = _runtimeService;
|
|
1326
|
+
this._formulaDependencyGenerator = _formulaDependencyGenerator;
|
|
1327
|
+
this._featureCalculationManagerService = _featureCalculationManagerService;
|
|
1328
|
+
this._otherFormulaManagerService = _otherFormulaManagerService;
|
|
1329
|
+
this._commandService = _commandService;
|
|
1330
|
+
this._rustEngineSyncController = _rustEngineSyncController;
|
|
1331
|
+
this._externalPrefetchPlanner = _externalPrefetchPlanner;
|
|
1332
|
+
this._externalPrefetchService = _externalPrefetchService;
|
|
1333
|
+
this._commandService.hasCommand(SetFormulaCalculationResultMutation2.id) || this.disposeWithMe(this._commandService.registerCommand(SetFormulaCalculationResultMutation2));
|
|
1334
|
+
}
|
|
1335
|
+
_configService;
|
|
1336
|
+
_currentConfigService;
|
|
1337
|
+
_runtimeService;
|
|
1338
|
+
_formulaDependencyGenerator;
|
|
1339
|
+
_featureCalculationManagerService;
|
|
1340
|
+
_otherFormulaManagerService;
|
|
1341
|
+
_commandService;
|
|
1342
|
+
_rustEngineSyncController;
|
|
1343
|
+
_externalPrefetchPlanner;
|
|
1344
|
+
_externalPrefetchService;
|
|
1345
|
+
_executionInProgressListener$ = new Subject();
|
|
1346
|
+
executionInProgressListener$ = this._executionInProgressListener$.asObservable();
|
|
1347
|
+
_executionCompleteListener$ = new Subject();
|
|
1348
|
+
executionCompleteListener$ = this._executionCompleteListener$.asObservable();
|
|
1349
|
+
_executeLock = new AsyncLock();
|
|
1350
|
+
_nativeLoaded = !1;
|
|
1351
|
+
_syncedSnapshotEpoch = -1;
|
|
1352
|
+
_syncedDependencyInvalidationEpoch = -1;
|
|
1353
|
+
_externalFormulaDatasetConfig;
|
|
1354
|
+
dispose() {
|
|
1355
|
+
super.dispose(), this._executionInProgressListener$.complete(), this._executionCompleteListener$.complete();
|
|
1356
|
+
}
|
|
1357
|
+
stopFormulaExecution() {
|
|
1358
|
+
this._runtimeService.stopExecution();
|
|
1359
|
+
}
|
|
1360
|
+
setRuntimeFeatureCellData(featureId, featureData) {
|
|
1361
|
+
this._runtimeService.setRuntimeFeatureCellData(featureId, featureData);
|
|
1362
|
+
}
|
|
1363
|
+
setRuntimeFeatureRange(featureId, featureRange) {
|
|
1364
|
+
this._runtimeService.setRuntimeFeatureRange(featureId, featureRange);
|
|
1365
|
+
}
|
|
1366
|
+
async execute(formulaDatasetConfig) {
|
|
1367
|
+
this._nativeLoaded || (await loadNativeBinding(), this._nativeLoaded = !0), await this._rustEngineSyncController.waitForProjectionLoad(), this._externalFormulaDatasetConfig = formulaDatasetConfig, await this._prefetchStaticExternalReferences(formulaDatasetConfig), this._runtimeService.setFormulaExecuteStage(FormulaExecuteStageType.START), this._executionInProgressListener$.next(this._runtimeService.getRuntimeState()), this._currentConfigService.load(formulaDatasetConfig), this._runtimeService.reset();
|
|
1368
|
+
let cycleReferenceCount = Math.max(formulaDatasetConfig.maxIteration || 1, 1);
|
|
1369
|
+
await this._executeLock.acquire("FORMULA_EXECUTION_LOCK", async () => {
|
|
1370
|
+
this._runtimeService.setFormulaCycleIndex(0), await this._executeStep(cycleReferenceCount) > 0 ? this._runtimeService.markedAsSuccessfullyExecuted() : this._runtimeService.markedAsNoFunctionsExecuted(), this._runtimeService.setFormulaExecuteStage(FormulaExecuteStageType.CALCULATION_COMPLETED), this._executionInProgressListener$.next(this._runtimeService.getRuntimeState()), this._executionCompleteListener$.next(this._runtimeService.getAllRuntimeData()), this._runtimeService.reset();
|
|
1371
|
+
});
|
|
1372
|
+
}
|
|
1373
|
+
async _executeStep(maxIteration) {
|
|
1374
|
+
let syncedFeatures = this._syncRustFormulaDependencies(), previousFeatureSignatures = this._featureSignatureMap(syncedFeatures), executeStartedAt = performance.now(), outputJson = executeDirtyFormulasOnRust(maxIteration, !1, !1, !0), nativeAndSerializeMs = performance.now() - executeStartedAt, parseStartedAt = performance.now(), output = JSON.parse(outputJson), calculatedNodeCount = output.calculatedNodeCount, parseMs = performance.now() - parseStartedAt;
|
|
1375
|
+
output = await this._resolveExternalReferenceNeeds(output, maxIteration);
|
|
1376
|
+
let applyStartedAt = performance.now(), applyBreakdown = await this._applyRustDependencyOutput(output), applyMs = performance.now() - applyStartedAt;
|
|
1377
|
+
if (emitRustFormulaDebugEvent({
|
|
1378
|
+
type: "executeDirtyFormulas",
|
|
1379
|
+
payload: {
|
|
1380
|
+
calculatedNodeCount: output.calculatedNodeCount,
|
|
1381
|
+
hasCycle: output.hasCycle,
|
|
1382
|
+
cycleIterationCount: output.cycleIterationCount,
|
|
1383
|
+
parallelBatchCount: output.parallelBatchCount,
|
|
1384
|
+
parallelNodeCount: output.parallelNodeCount,
|
|
1385
|
+
errorCount: output.errors.length,
|
|
1386
|
+
resultBatchCount: output.resultBatches?.length ?? 0,
|
|
1387
|
+
firstResultBatchValue: firstResultBatchValue(output),
|
|
1388
|
+
resultBatchSheetCounts: resultBatchSheetCounts(output),
|
|
1389
|
+
timings: output.timings,
|
|
1390
|
+
functionProfile: output.functionProfile,
|
|
1391
|
+
bridgeTimings: {
|
|
1392
|
+
nativeAndSerializeMs,
|
|
1393
|
+
outputBytes: outputJson.length,
|
|
1394
|
+
parseMs,
|
|
1395
|
+
applyMs,
|
|
1396
|
+
applyConvertMs: applyBreakdown.convertMs,
|
|
1397
|
+
applyCommandMs: applyBreakdown.commandMs
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
}), syncedFeatures.length > 0)
|
|
1401
|
+
for (let pass = 0; pass < MAX_FEATURE_CALCULATION_PASSES; pass++) {
|
|
1402
|
+
let refreshedFeatures = this._syncRustFormulaDependencyDefinitions(), changedFeatures = refreshedFeatures.filter(
|
|
1403
|
+
(feature) => previousFeatureSignatures.get(this._featureKey(feature)) !== feature.signature
|
|
1404
|
+
);
|
|
1405
|
+
if (changedFeatures.length === 0)
|
|
1406
|
+
break;
|
|
1407
|
+
this._markRustFormulaDirty(
|
|
1408
|
+
this._currentConfigService.getDirtyData(),
|
|
1409
|
+
this._dirtyFeatureMapFor(changedFeatures)
|
|
1410
|
+
), executeStartedAt = performance.now(), outputJson = executeDirtyFormulasOnRust(maxIteration, !1, !1, !0), nativeAndSerializeMs = performance.now() - executeStartedAt, parseStartedAt = performance.now(), output = JSON.parse(outputJson), calculatedNodeCount += output.calculatedNodeCount, parseMs = performance.now() - parseStartedAt, output = await this._resolveExternalReferenceNeeds(output, maxIteration), applyStartedAt = performance.now(), applyBreakdown = await this._applyRustDependencyOutput(output), applyMs = performance.now() - applyStartedAt, emitRustFormulaDebugEvent({
|
|
1411
|
+
type: "executeDirtyFormulas",
|
|
1412
|
+
payload: {
|
|
1413
|
+
calculatedNodeCount: output.calculatedNodeCount,
|
|
1414
|
+
hasCycle: output.hasCycle,
|
|
1415
|
+
cycleIterationCount: output.cycleIterationCount,
|
|
1416
|
+
parallelBatchCount: output.parallelBatchCount,
|
|
1417
|
+
parallelNodeCount: output.parallelNodeCount,
|
|
1418
|
+
errorCount: output.errors.length,
|
|
1419
|
+
resultBatchCount: output.resultBatches?.length ?? 0,
|
|
1420
|
+
firstResultBatchValue: firstResultBatchValue(output),
|
|
1421
|
+
resultBatchSheetCounts: resultBatchSheetCounts(output),
|
|
1422
|
+
timings: output.timings,
|
|
1423
|
+
functionProfile: output.functionProfile,
|
|
1424
|
+
bridgeTimings: {
|
|
1425
|
+
nativeAndSerializeMs,
|
|
1426
|
+
outputBytes: outputJson.length,
|
|
1427
|
+
parseMs,
|
|
1428
|
+
applyMs,
|
|
1429
|
+
applyConvertMs: applyBreakdown.convertMs,
|
|
1430
|
+
applyCommandMs: applyBreakdown.commandMs
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
}), previousFeatureSignatures = this._featureSignatureMap(refreshedFeatures);
|
|
1434
|
+
}
|
|
1435
|
+
return calculatedNodeCount;
|
|
1436
|
+
}
|
|
1437
|
+
async _prefetchStaticExternalReferences(config) {
|
|
1438
|
+
let requests = this._externalPrefetchPlanner.plan(config);
|
|
1439
|
+
if (requests.length === 0) return;
|
|
1440
|
+
let result = await this._externalPrefetchService.prefetch(requests, config);
|
|
1441
|
+
result.dirtyRanges.length > 0 && this._rustEngineSyncController.upsertReferenceData(config, result.dirtyRanges);
|
|
1442
|
+
}
|
|
1443
|
+
async _resolveExternalReferenceNeeds(initialOutput, maxIteration) {
|
|
1444
|
+
let config = this._externalFormulaDatasetConfig;
|
|
1445
|
+
if (!config) return initialOutput;
|
|
1446
|
+
let output = initialOutput;
|
|
1447
|
+
for (let pass = 0; pass < MAX_EXTERNAL_REFERENCE_PASSES; pass++) {
|
|
1448
|
+
let needs = output.needsData ?? [];
|
|
1449
|
+
if (needs.length === 0) break;
|
|
1450
|
+
let requests = /* @__PURE__ */ new Map();
|
|
1451
|
+
for (let [hostUnitId, references] of this._groupExternalReferenceNeeds(config, needs))
|
|
1452
|
+
for (let request of this._externalPrefetchPlanner.planDynamic(hostUnitId, references))
|
|
1453
|
+
requests.set(`${request.hostUnitId}\0${request.bindingSlot}`, request);
|
|
1454
|
+
if (requests.size === 0) break;
|
|
1455
|
+
let result = await this._externalPrefetchService.prefetch(Array.from(requests.values()), config), upsertCount = this._rustEngineSyncController.upsertReferenceData(config, needs);
|
|
1456
|
+
if (result.dirtyRanges.length === 0 || upsertCount === 0) break;
|
|
1457
|
+
output = JSON.parse(executeDirtyFormulasOnRust(maxIteration, !1, !1, !0));
|
|
1458
|
+
}
|
|
1459
|
+
return output;
|
|
1460
|
+
}
|
|
1461
|
+
_groupExternalReferenceNeeds(config, needs) {
|
|
1462
|
+
let grouped = /* @__PURE__ */ new Map();
|
|
1463
|
+
for (let need of needs) {
|
|
1464
|
+
let hostUnitId = this._hostUnitIdFromSynthetic(need.unitId);
|
|
1465
|
+
if (!hostUnitId) continue;
|
|
1466
|
+
let sheetNameMap = config.unitSheetNameMap?.[need.unitId] ?? {}, sheetName = Object.entries(sheetNameMap).find(([, sheetId]) => sheetId === need.sheetId)?.[0] ?? need.sheetId, references = grouped.get(hostUnitId) ?? [];
|
|
1467
|
+
references.push({ unitId: need.unitId, sheetName, range: need.range }), grouped.set(hostUnitId, references);
|
|
1468
|
+
}
|
|
1469
|
+
return grouped;
|
|
1470
|
+
}
|
|
1471
|
+
_hostUnitIdFromSynthetic(unitId) {
|
|
1472
|
+
if (!unitId.startsWith("external:")) return;
|
|
1473
|
+
let separator = unitId.lastIndexOf(":");
|
|
1474
|
+
if (!(separator <= 9 || !/^\d+$/.test(unitId.slice(separator + 1))))
|
|
1475
|
+
try {
|
|
1476
|
+
return decodeURIComponent(unitId.slice(9, separator));
|
|
1477
|
+
} catch {
|
|
1478
|
+
return;
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
_buildRustInput() {
|
|
1482
|
+
let unitData = this._currentConfigService.getUnitData(), formulaData = this._currentConfigService.getFormulaData(), dirtyRanges = this._currentConfigService.getDirtyRanges(), config = this._configService.getConfig(ENGINE_FORMULA_PLUGIN_CONFIG_KEY);
|
|
1483
|
+
return {
|
|
1484
|
+
config: {
|
|
1485
|
+
maxIteration: config?.maxIteration ?? 1,
|
|
1486
|
+
intervalCount: config?.intervalCount ?? DEFAULT_INTERVAL_COUNT
|
|
1487
|
+
},
|
|
1488
|
+
formulaData: this._serializeFormulaData(formulaData),
|
|
1489
|
+
unitData: this._serializeUnitData(unitData),
|
|
1490
|
+
dirtyRanges: dirtyRanges || [],
|
|
1491
|
+
definedNames: {}
|
|
1492
|
+
};
|
|
1493
|
+
}
|
|
1494
|
+
_syncRustFormulaDependencies(dirtyUnitFeatureMapOverride) {
|
|
1495
|
+
let syncState = getRustEngineSyncState(), rebuildSheetFormulas = this._syncedSnapshotEpoch !== syncState.snapshotEpoch || this._syncedDependencyInvalidationEpoch !== syncState.dependencyInvalidationEpoch, collectStartedAt = performance.now(), state = this._collectRustFormulaDependencySyncState(), collectMs = performance.now() - collectStartedAt;
|
|
1496
|
+
if (!(rebuildSheetFormulas || state.featureCalculations.length > 0 || state.otherFormulas.length > 0))
|
|
1497
|
+
return emitRustFormulaDebugEvent({
|
|
1498
|
+
type: "syncDependencies",
|
|
1499
|
+
payload: {
|
|
1500
|
+
rebuildSheetFormulas,
|
|
1501
|
+
skipped: !0,
|
|
1502
|
+
featureCalculationCount: 0,
|
|
1503
|
+
otherFormulaCount: 0,
|
|
1504
|
+
syncedFeatureCount: 0,
|
|
1505
|
+
timings: {
|
|
1506
|
+
collectMs,
|
|
1507
|
+
stringifyMs: 0,
|
|
1508
|
+
nativeMs: 0,
|
|
1509
|
+
parseMs: 0,
|
|
1510
|
+
totalMs: collectMs
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1513
|
+
}), this._markRustFormulaDirty(state.dirtyData, dirtyUnitFeatureMapOverride, rebuildSheetFormulas), state.syncedFeatures;
|
|
1514
|
+
let stringifyStartedAt = performance.now(), inputJson = JSON.stringify({
|
|
1515
|
+
rebuildSheetFormulas,
|
|
1516
|
+
featureCalculations: state.featureCalculations,
|
|
1517
|
+
otherFormulas: state.otherFormulas
|
|
1518
|
+
}), stringifyMs = performance.now() - stringifyStartedAt, nativeStartedAt = performance.now(), outputJson = syncRustFormulaDependenciesOnRust(inputJson), nativeMs = performance.now() - nativeStartedAt, parseStartedAt = performance.now(), output = JSON.parse(outputJson), parseMs = performance.now() - parseStartedAt;
|
|
1519
|
+
return emitRustFormulaDebugEvent({
|
|
1520
|
+
type: "syncDependencies",
|
|
1521
|
+
payload: {
|
|
1522
|
+
rebuildSheetFormulas,
|
|
1523
|
+
skipped: !1,
|
|
1524
|
+
featureCalculationCount: state.featureCalculations.length,
|
|
1525
|
+
otherFormulaCount: state.otherFormulas.length,
|
|
1526
|
+
syncedFeatureCount: state.syncedFeatures.length,
|
|
1527
|
+
timings: {
|
|
1528
|
+
collectMs,
|
|
1529
|
+
stringifyMs,
|
|
1530
|
+
nativeMs,
|
|
1531
|
+
parseMs,
|
|
1532
|
+
totalMs: collectMs + stringifyMs + nativeMs + parseMs,
|
|
1533
|
+
rust: output.timings
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
}), rebuildSheetFormulas && (this._syncedSnapshotEpoch = syncState.snapshotEpoch, this._syncedDependencyInvalidationEpoch = syncState.dependencyInvalidationEpoch), this._markRustFormulaDirty(state.dirtyData, dirtyUnitFeatureMapOverride, rebuildSheetFormulas), state.syncedFeatures;
|
|
1537
|
+
}
|
|
1538
|
+
_syncRustFormulaDependencyDefinitions() {
|
|
1539
|
+
let state = this._collectRustFormulaDependencySyncState();
|
|
1540
|
+
return syncRustFormulaDependenciesOnRust(
|
|
1541
|
+
JSON.stringify({
|
|
1542
|
+
rebuildSheetFormulas: !1,
|
|
1543
|
+
featureCalculations: state.featureCalculations,
|
|
1544
|
+
otherFormulas: state.otherFormulas
|
|
1545
|
+
})
|
|
1546
|
+
), state.syncedFeatures;
|
|
1547
|
+
}
|
|
1548
|
+
_collectRustFormulaDependencySyncState() {
|
|
1549
|
+
let featureCalculations = [], syncedFeatures = [], dirtyData = this._currentConfigService.getDirtyData(), runtimeData = this._runtimeService.getAllRuntimeData();
|
|
1550
|
+
this._featureCalculationManagerService.getReferenceExecutorMap().forEach((sheetMap) => {
|
|
1551
|
+
sheetMap.forEach((featureMap) => {
|
|
1552
|
+
featureMap.forEach((params, featureId) => {
|
|
1553
|
+
let { runtimeCellData, dirtyRanges: featureDirtyRanges } = params.getDirtyData(
|
|
1554
|
+
dirtyData,
|
|
1555
|
+
runtimeData
|
|
1556
|
+
), serializedDirtyRanges = this._serializeFeatureDirtyRanges(featureDirtyRanges), serializedRuntimeCellData = this._serializeRuntimeFeatureCellData(runtimeCellData);
|
|
1557
|
+
this._runtimeService.setRuntimeFeatureCellData(featureId, runtimeCellData), this._runtimeService.setRuntimeFeatureRange(featureId, featureDirtyRanges), featureCalculations.push({
|
|
1558
|
+
unitId: params.unitId,
|
|
1559
|
+
sheetId: params.subUnitId,
|
|
1560
|
+
featureId,
|
|
1561
|
+
dependencyRanges: params.dependencyRanges.map((range) => ({
|
|
1562
|
+
unitId: range.unitId,
|
|
1563
|
+
sheetId: range.sheetId,
|
|
1564
|
+
startRow: range.range.startRow,
|
|
1565
|
+
endRow: range.range.endRow,
|
|
1566
|
+
startColumn: range.range.startColumn,
|
|
1567
|
+
endColumn: range.range.endColumn
|
|
1568
|
+
})),
|
|
1569
|
+
dirtyRanges: serializedDirtyRanges,
|
|
1570
|
+
runtimeCellData: serializedRuntimeCellData
|
|
1571
|
+
}), syncedFeatures.push({
|
|
1572
|
+
unitId: params.unitId,
|
|
1573
|
+
sheetId: params.subUnitId,
|
|
1574
|
+
featureId,
|
|
1575
|
+
signature: JSON.stringify({
|
|
1576
|
+
dirtyRanges: serializedDirtyRanges,
|
|
1577
|
+
runtimeCellData: serializedRuntimeCellData
|
|
1578
|
+
})
|
|
1579
|
+
});
|
|
1580
|
+
});
|
|
1581
|
+
});
|
|
1582
|
+
});
|
|
1583
|
+
let otherFormulas = [], otherFormulaData = this._otherFormulaManagerService.getOtherFormulaData();
|
|
1584
|
+
return Object.entries(otherFormulaData).forEach(([unitId, sheetMap]) => {
|
|
1585
|
+
sheetMap && Object.entries(sheetMap).forEach(([sheetId, formulaMap]) => {
|
|
1586
|
+
formulaMap && Object.entries(formulaMap).forEach(([formulaId, item]) => {
|
|
1587
|
+
item && otherFormulas.push({
|
|
1588
|
+
unitId,
|
|
1589
|
+
sheetId,
|
|
1590
|
+
formulaId,
|
|
1591
|
+
formula: item.f,
|
|
1592
|
+
ranges: item.ranges
|
|
1593
|
+
});
|
|
1594
|
+
});
|
|
1595
|
+
});
|
|
1596
|
+
}), { dirtyData, featureCalculations, otherFormulas, syncedFeatures };
|
|
1597
|
+
}
|
|
1598
|
+
_markRustFormulaDirty(dirtyData, dirtyUnitFeatureMapOverride, forceCalculationOverride = !1) {
|
|
1599
|
+
let payload = {
|
|
1600
|
+
forceCalculation: forceCalculationOverride || dirtyData.forceCalculation,
|
|
1601
|
+
includeDirtyNodes: !1,
|
|
1602
|
+
includeCalculationOrder: !1,
|
|
1603
|
+
dirtyRanges: (dirtyData.dirtyRanges ?? []).map((range) => ({
|
|
1604
|
+
unitId: range.unitId,
|
|
1605
|
+
sheetId: range.sheetId,
|
|
1606
|
+
startRow: range.range.startRow,
|
|
1607
|
+
endRow: range.range.endRow,
|
|
1608
|
+
startColumn: range.range.startColumn,
|
|
1609
|
+
endColumn: range.range.endColumn
|
|
1610
|
+
})),
|
|
1611
|
+
dirtyUnitFeatureMap: dirtyUnitFeatureMapOverride ?? dirtyData.dirtyUnitFeatureMap,
|
|
1612
|
+
dirtyUnitOtherFormulaMap: dirtyData.dirtyUnitOtherFormulaMap,
|
|
1613
|
+
dirtyNameMap: dirtyData.dirtyNameMap,
|
|
1614
|
+
dirtyDefinedNameMap: dirtyData.dirtyDefinedNameMap
|
|
1615
|
+
}, stringifyStartedAt = performance.now(), inputJson = JSON.stringify(payload), stringifyMs = performance.now() - stringifyStartedAt, nativeStartedAt = performance.now(), outputJson = markRustFormulaDirtyOnRust(inputJson), nativeMs = performance.now() - nativeStartedAt, rustTimings;
|
|
1616
|
+
try {
|
|
1617
|
+
rustTimings = JSON.parse(outputJson).timings;
|
|
1618
|
+
} catch {
|
|
1619
|
+
rustTimings = void 0;
|
|
1620
|
+
}
|
|
1621
|
+
emitRustFormulaDebugEvent({
|
|
1622
|
+
type: "markDirty",
|
|
1623
|
+
payload: {
|
|
1624
|
+
...payload,
|
|
1625
|
+
timings: {
|
|
1626
|
+
stringifyMs,
|
|
1627
|
+
nativeMs,
|
|
1628
|
+
totalMs: stringifyMs + nativeMs
|
|
1629
|
+
},
|
|
1630
|
+
rustTimings
|
|
1631
|
+
}
|
|
1632
|
+
});
|
|
1633
|
+
}
|
|
1634
|
+
_dirtyFeatureMapFor(features) {
|
|
1635
|
+
let dirtyMap = {};
|
|
1636
|
+
return features.forEach(({ unitId, sheetId, featureId }) => {
|
|
1637
|
+
dirtyMap[unitId] = dirtyMap[unitId] ?? {}, dirtyMap[unitId][sheetId] = dirtyMap[unitId][sheetId] ?? {}, dirtyMap[unitId][sheetId][featureId] = !0;
|
|
1638
|
+
}), dirtyMap;
|
|
1639
|
+
}
|
|
1640
|
+
_featureKey(feature) {
|
|
1641
|
+
return `${feature.unitId}\0${feature.sheetId}\0${feature.featureId}`;
|
|
1642
|
+
}
|
|
1643
|
+
_featureSignatureMap(features) {
|
|
1644
|
+
return new Map(features.map((feature) => [this._featureKey(feature), feature.signature]));
|
|
1645
|
+
}
|
|
1646
|
+
_serializeFeatureDirtyRanges(dirtyRanges) {
|
|
1647
|
+
let serialized = [];
|
|
1648
|
+
return Object.entries(dirtyRanges).forEach(([unitId, sheetMap]) => {
|
|
1649
|
+
sheetMap && Object.entries(sheetMap).forEach(([sheetId, ranges]) => {
|
|
1650
|
+
ranges && ranges.forEach((range) => {
|
|
1651
|
+
serialized.push({
|
|
1652
|
+
unitId,
|
|
1653
|
+
sheetId,
|
|
1654
|
+
startRow: range.startRow,
|
|
1655
|
+
endRow: range.endRow,
|
|
1656
|
+
startColumn: range.startColumn,
|
|
1657
|
+
endColumn: range.endColumn
|
|
1658
|
+
});
|
|
1659
|
+
});
|
|
1660
|
+
});
|
|
1661
|
+
}), serialized;
|
|
1662
|
+
}
|
|
1663
|
+
_serializeRuntimeFeatureCellData(runtimeCellData) {
|
|
1664
|
+
let result = {};
|
|
1665
|
+
return Object.entries(runtimeCellData ?? {}).forEach(([unitId, sheetMap]) => {
|
|
1666
|
+
if (!sheetMap) return;
|
|
1667
|
+
let unitData = {};
|
|
1668
|
+
result[unitId] = unitData, Object.entries(sheetMap).forEach(([sheetId, matrix]) => {
|
|
1669
|
+
if (!matrix) return;
|
|
1670
|
+
let sheetData = {};
|
|
1671
|
+
unitData[sheetId] = sheetData, matrix.forValue((row, column, cell) => {
|
|
1672
|
+
let rowData = sheetData[row] ??= {};
|
|
1673
|
+
rowData[column] = cell == null ? null : {
|
|
1674
|
+
v: cell.v,
|
|
1675
|
+
...typeof cell.t == "number" ? { t: cell.t } : {},
|
|
1676
|
+
...cell.p != null ? { p: cell.p } : {},
|
|
1677
|
+
...typeof cell.f == "string" ? { f: cell.f } : {},
|
|
1678
|
+
...typeof cell.si == "string" ? { si: cell.si } : {},
|
|
1679
|
+
...typeof cell.ref == "string" ? { ref: cell.ref } : {},
|
|
1680
|
+
...typeof cell.xf == "string" ? { xf: cell.xf } : {},
|
|
1681
|
+
...cell.s != null ? { s: cell.s } : {}
|
|
1682
|
+
};
|
|
1683
|
+
});
|
|
1684
|
+
});
|
|
1685
|
+
}), result;
|
|
1686
|
+
}
|
|
1687
|
+
_serializeFormulaData(formulaData) {
|
|
1688
|
+
let result = {};
|
|
1689
|
+
if (!formulaData || typeof formulaData != "object") return result;
|
|
1690
|
+
for (let [unitId, sheets] of Object.entries(formulaData))
|
|
1691
|
+
if (!(!sheets || typeof sheets != "object")) {
|
|
1692
|
+
result[unitId] = {};
|
|
1693
|
+
for (let [sheetId, rows] of Object.entries(sheets))
|
|
1694
|
+
if (!(!rows || typeof rows != "object")) {
|
|
1695
|
+
result[unitId][sheetId] = {};
|
|
1696
|
+
for (let [rowStr, cols] of Object.entries(rows)) {
|
|
1697
|
+
if (!cols || typeof cols != "object")
|
|
1698
|
+
continue;
|
|
1699
|
+
let row = Number(rowStr);
|
|
1700
|
+
result[unitId][sheetId][row] = {};
|
|
1701
|
+
for (let [colStr, item] of Object.entries(cols)) {
|
|
1702
|
+
let col = Number(colStr);
|
|
1703
|
+
if (typeof item == "string")
|
|
1704
|
+
result[unitId][sheetId][row][col] = item;
|
|
1705
|
+
else if (item && typeof item == "object" && typeof item.f == "string") {
|
|
1706
|
+
let formulaItem = item;
|
|
1707
|
+
result[unitId][sheetId][row][col] = {
|
|
1708
|
+
f: formulaItem.f,
|
|
1709
|
+
si: typeof formulaItem.si == "string" ? formulaItem.si : void 0,
|
|
1710
|
+
ref: typeof formulaItem.ref == "string" ? formulaItem.ref : void 0,
|
|
1711
|
+
x: typeof formulaItem.x == "number" ? formulaItem.x : void 0,
|
|
1712
|
+
y: typeof formulaItem.y == "number" ? formulaItem.y : void 0
|
|
1713
|
+
};
|
|
1714
|
+
}
|
|
1715
|
+
}
|
|
1716
|
+
}
|
|
1717
|
+
}
|
|
1718
|
+
}
|
|
1719
|
+
return result;
|
|
1720
|
+
}
|
|
1721
|
+
_serializeUnitData(unitData) {
|
|
1722
|
+
let result = {};
|
|
1723
|
+
if (!unitData) return result;
|
|
1724
|
+
for (let [unitId, sheets] of Object.entries(unitData)) {
|
|
1725
|
+
result[unitId] = {};
|
|
1726
|
+
for (let [sheetId, sheet] of Object.entries(sheets))
|
|
1727
|
+
result[unitId][sheetId] = {
|
|
1728
|
+
cellData: this._serializeCellData(sheet.cellData),
|
|
1729
|
+
rowCount: sheet.rowCount ?? 0,
|
|
1730
|
+
columnCount: sheet.columnCount ?? 0
|
|
1731
|
+
};
|
|
1732
|
+
}
|
|
1733
|
+
return result;
|
|
1734
|
+
}
|
|
1735
|
+
_serializeCellData(cellData) {
|
|
1736
|
+
let result = {};
|
|
1737
|
+
if (!cellData || typeof cellData != "object") return result;
|
|
1738
|
+
let data = typeof cellData.getMatrix == "function" ? cellData.getMatrix() : cellData;
|
|
1739
|
+
for (let [rowStr, cols] of Object.entries(data)) {
|
|
1740
|
+
let row = Number(rowStr);
|
|
1741
|
+
if (Number.isFinite(row)) {
|
|
1742
|
+
result[row] = {};
|
|
1743
|
+
for (let [colStr, cell] of Object.entries(cols)) {
|
|
1744
|
+
let col = Number(colStr);
|
|
1745
|
+
Number.isFinite(col) && (result[row][col] = {
|
|
1746
|
+
v: cell?.v ?? null,
|
|
1747
|
+
t: cell?.t ?? void 0,
|
|
1748
|
+
p: cell?.p ?? void 0,
|
|
1749
|
+
f: cell?.f ?? void 0,
|
|
1750
|
+
s: cell?.s ?? void 0
|
|
1751
|
+
});
|
|
1752
|
+
}
|
|
1753
|
+
}
|
|
1754
|
+
}
|
|
1755
|
+
return result;
|
|
1756
|
+
}
|
|
1757
|
+
_applyRustOutput(_output) {
|
|
1758
|
+
}
|
|
1759
|
+
async _applyRustDependencyOutput(output) {
|
|
1760
|
+
let convertStartedAt = performance.now(), result = rustExecutionOutputToCalculationResult(output), convertMs = performance.now() - convertStartedAt, commandStartedAt = performance.now();
|
|
1761
|
+
return await this._commandService.executeCommand(SetFormulaCalculationResultMutation2.id, result, {
|
|
1762
|
+
onlyLocal: !0,
|
|
1763
|
+
fromRustFormulaEngine: !0
|
|
1764
|
+
}), {
|
|
1765
|
+
convertMs,
|
|
1766
|
+
commandMs: performance.now() - commandStartedAt
|
|
1767
|
+
};
|
|
1768
|
+
}
|
|
1769
|
+
async calculate(formulaString) {
|
|
1770
|
+
this._nativeLoaded || (await loadNativeBinding(), this._nativeLoaded = !0);
|
|
1771
|
+
let unitId = "__rust_formula_calculate__", sheetId = "__sheet__", input = {
|
|
1772
|
+
config: { maxIteration: 1, intervalCount: DEFAULT_INTERVAL_COUNT },
|
|
1773
|
+
formulaData: {
|
|
1774
|
+
[unitId]: {
|
|
1775
|
+
[sheetId]: {
|
|
1776
|
+
0: { 0: formulaString }
|
|
1777
|
+
}
|
|
1778
|
+
}
|
|
1779
|
+
},
|
|
1780
|
+
unitData: {
|
|
1781
|
+
[unitId]: {
|
|
1782
|
+
[sheetId]: {
|
|
1783
|
+
rowCount: 1,
|
|
1784
|
+
columnCount: 1,
|
|
1785
|
+
cellData: {}
|
|
1786
|
+
}
|
|
1787
|
+
}
|
|
1788
|
+
},
|
|
1789
|
+
dirtyRanges: [],
|
|
1790
|
+
definedNames: {}
|
|
1791
|
+
};
|
|
1792
|
+
return JSON.parse(executeOnRust(JSON.stringify(input))).runtimeData?.[unitId]?.[sheetId]?.[0]?.[0] ?? null;
|
|
1793
|
+
}
|
|
1794
|
+
async executeFormulas(formulas, rowData) {
|
|
1795
|
+
this._nativeLoaded || (await loadNativeBinding(), this._nativeLoaded = !0), this._currentConfigService.loadDataLite(rowData);
|
|
1796
|
+
let unitData = this._currentConfigService.getUnitData(), formulaData = this._formulaStringMapToFormulaData(formulas), input = {
|
|
1797
|
+
config: { maxIteration: 1, intervalCount: DEFAULT_INTERVAL_COUNT },
|
|
1798
|
+
formulaData,
|
|
1799
|
+
unitData: this._serializeUnitData(unitData),
|
|
1800
|
+
dirtyRanges: [],
|
|
1801
|
+
definedNames: {}
|
|
1802
|
+
}, output = JSON.parse(executeOnRust(JSON.stringify(input)));
|
|
1803
|
+
return this._formulaExecutionOutputToResultMap(formulas, output);
|
|
1804
|
+
}
|
|
1805
|
+
async getAllDependencyJson(_rowData) {
|
|
1806
|
+
this._nativeLoaded || (await loadNativeBinding(), this._nativeLoaded = !0), this._syncRustFormulaDependencyDefinitions();
|
|
1807
|
+
let graph = this._getRustDependencyGraph(), inspect = this._getRustInspectGraph();
|
|
1808
|
+
return this._rustAllDependencyJson(graph, inspect);
|
|
1809
|
+
}
|
|
1810
|
+
async getCellDependencyJson(unitId, sheetId, row, column, _rowData) {
|
|
1811
|
+
this._nativeLoaded || (await loadNativeBinding(), this._nativeLoaded = !0), this._syncRustFormulaDependencyDefinitions();
|
|
1812
|
+
let graph = this._getRustDependencyGraph(unitId), all = this._rustGraphDependencyJson(graph), current = all.find(
|
|
1813
|
+
(item) => item.unitId === unitId && item.subUnitId === sheetId && item.row === row && item.column === column
|
|
1814
|
+
);
|
|
1815
|
+
if (!current)
|
|
1816
|
+
return;
|
|
1817
|
+
let byId = new Map(all.map((item) => [item.treeId, item]));
|
|
1818
|
+
return {
|
|
1819
|
+
...current,
|
|
1820
|
+
children: current.children.map((id) => byId.get(id)).filter(isFormulaDependencyTreeJson),
|
|
1821
|
+
parents: current.parents.map((id) => byId.get(id)).filter(isFormulaDependencyTreeJson)
|
|
1822
|
+
};
|
|
1823
|
+
}
|
|
1824
|
+
async getRangeDependents(unitRanges) {
|
|
1825
|
+
this._nativeLoaded || (await loadNativeBinding(), this._nativeLoaded = !0), this._syncRustFormulaDependencyDefinitions();
|
|
1826
|
+
let graph = this._getRustDependencyGraph(), graphItems = this._rustGraphDependencyJson(graph), graphByCell = this._rustDependencyJsonByCell(graphItems), dirty = JSON.parse(
|
|
1827
|
+
getRustDirtyDependenciesOnRust(JSON.stringify(this._serializeUnitRanges(unitRanges)))
|
|
1828
|
+
);
|
|
1829
|
+
return this._uniqueDependencyJson(
|
|
1830
|
+
(dirty.direct ?? dirty.affected ?? []).map((cell) => graphByCell.get(this._cellKey(cell))).filter(Boolean)
|
|
1831
|
+
);
|
|
1832
|
+
}
|
|
1833
|
+
async getInRangeFormulas(unitRanges) {
|
|
1834
|
+
return this._nativeLoaded || (await loadNativeBinding(), this._nativeLoaded = !0), this._syncRustFormulaDependencyDefinitions(), this._rustGraphDependencyJson(this._getRustDependencyGraph()).filter(
|
|
1835
|
+
(item) => this._cellInUnitRanges(item.unitId, item.subUnitId, item.row, item.column, unitRanges)
|
|
1836
|
+
);
|
|
1837
|
+
}
|
|
1838
|
+
async getDependentsAndInRangeFormulas(unitRanges) {
|
|
1839
|
+
let [dependents, inRanges] = await Promise.all([
|
|
1840
|
+
this.getRangeDependents(unitRanges),
|
|
1841
|
+
this.getInRangeFormulas(unitRanges)
|
|
1842
|
+
]);
|
|
1843
|
+
return { dependents, inRanges };
|
|
1844
|
+
}
|
|
1845
|
+
_formulaStringMapToFormulaData(formulas) {
|
|
1846
|
+
let formulaData = {};
|
|
1847
|
+
return Object.entries(formulas).forEach(([unitId, sheetMap]) => {
|
|
1848
|
+
sheetMap && (formulaData[unitId] = {}, Object.entries(sheetMap).forEach(([sheetId, rowMap]) => {
|
|
1849
|
+
rowMap && (formulaData[unitId][sheetId] = {}, Object.entries(rowMap).forEach(([rowKey, colMap]) => {
|
|
1850
|
+
if (!colMap) return;
|
|
1851
|
+
let row = Number(rowKey);
|
|
1852
|
+
formulaData[unitId][sheetId][row] = {}, Object.entries(colMap).forEach(([colKey, formulaList]) => {
|
|
1853
|
+
let formula = Array.isArray(formulaList) ? formulaList[0] : void 0;
|
|
1854
|
+
typeof formula == "string" && (formulaData[unitId][sheetId][row][Number(colKey)] = formula);
|
|
1855
|
+
});
|
|
1856
|
+
}));
|
|
1857
|
+
}));
|
|
1858
|
+
}), formulaData;
|
|
1859
|
+
}
|
|
1860
|
+
_formulaExecutionOutputToResultMap(formulas, output) {
|
|
1861
|
+
let result = {};
|
|
1862
|
+
return Object.entries(formulas).forEach(([unitId, sheetMap]) => {
|
|
1863
|
+
sheetMap && (result[unitId] = {}, Object.entries(sheetMap).forEach(([sheetId, rowMap]) => {
|
|
1864
|
+
rowMap && (result[unitId][sheetId] = {}, Object.entries(rowMap).forEach(([rowKey, colMap]) => {
|
|
1865
|
+
if (!colMap) return;
|
|
1866
|
+
let row = Number(rowKey);
|
|
1867
|
+
result[unitId][sheetId][row] = {}, Object.entries(colMap).forEach(([colKey, formulaList]) => {
|
|
1868
|
+
let col = Number(colKey), formulasForCell = Array.isArray(formulaList) ? formulaList : [], value = normalizeFormulaResultValue(
|
|
1869
|
+
output.runtimeData?.[unitId]?.[sheetId]?.[row]?.[col]
|
|
1870
|
+
);
|
|
1871
|
+
result[unitId][sheetId][row][col] = formulasForCell.map((formula) => ({ formula, value }));
|
|
1872
|
+
});
|
|
1873
|
+
}));
|
|
1874
|
+
}));
|
|
1875
|
+
}), result;
|
|
1876
|
+
}
|
|
1877
|
+
_getRustDependencyGraph(unitId) {
|
|
1878
|
+
return JSON.parse(buildRustDependencyGraphOnRust(unitId));
|
|
1879
|
+
}
|
|
1880
|
+
_getRustInspectGraph() {
|
|
1881
|
+
return JSON.parse(inspectRustFormulaDependencyGraphOnRust());
|
|
1882
|
+
}
|
|
1883
|
+
_rustAllDependencyJson(graph, inspect) {
|
|
1884
|
+
let cellItems = this._rustGraphDependencyJson(graph), seen = new Set(cellItems.map((item) => item.treeId)), nonCellItems = (inspect.nodes ?? []).filter((item) => item.node.nodeType !== "cellFormula" && !seen.has(item.index)).map((item) => this._rustFormulaNodeToDependencyJson(item.index, item.node));
|
|
1885
|
+
return this._uniqueDependencyJson([...cellItems, ...nonCellItems]);
|
|
1886
|
+
}
|
|
1887
|
+
_rustGraphDependencyJson(graph) {
|
|
1888
|
+
return (graph.nodes ?? []).map((node) => this._rustDependencyNodeToJson(node));
|
|
1889
|
+
}
|
|
1890
|
+
_rustDependencyNodeToJson(node) {
|
|
1891
|
+
return {
|
|
1892
|
+
children: node.children ?? [],
|
|
1893
|
+
parents: node.parents ?? [],
|
|
1894
|
+
treeId: node.id,
|
|
1895
|
+
formula: node.formula,
|
|
1896
|
+
row: node.row,
|
|
1897
|
+
column: node.column,
|
|
1898
|
+
unitId: node.unitId,
|
|
1899
|
+
subUnitId: node.sheetId,
|
|
1900
|
+
refOffsetX: node.offsetX ?? 0,
|
|
1901
|
+
refOffsetY: node.offsetY ?? 0,
|
|
1902
|
+
rangeList: (node.precedentRanges ?? []).map((range) => this._rustRangeToUnitRange(range)),
|
|
1903
|
+
refTreeId: void 0,
|
|
1904
|
+
formulaId: node.formulaId ?? null,
|
|
1905
|
+
featureId: null,
|
|
1906
|
+
type: FORMULA_TREE_TYPE_NORMAL
|
|
1907
|
+
};
|
|
1908
|
+
}
|
|
1909
|
+
_rustFormulaNodeToDependencyJson(index, node) {
|
|
1910
|
+
return {
|
|
1911
|
+
children: [],
|
|
1912
|
+
parents: [],
|
|
1913
|
+
treeId: index,
|
|
1914
|
+
formula: "",
|
|
1915
|
+
row: node.row ?? -1,
|
|
1916
|
+
column: node.column ?? -1,
|
|
1917
|
+
unitId: node.unitId ?? "",
|
|
1918
|
+
subUnitId: node.sheetId ?? "",
|
|
1919
|
+
refOffsetX: node.refOffsetX ?? 0,
|
|
1920
|
+
refOffsetY: node.refOffsetY ?? 0,
|
|
1921
|
+
rangeList: [],
|
|
1922
|
+
refTreeId: void 0,
|
|
1923
|
+
formulaId: node.formulaId ?? null,
|
|
1924
|
+
featureId: node.featureId ?? null,
|
|
1925
|
+
type: node.nodeType === "featureCalculation" ? FORMULA_TREE_TYPE_FEATURE : FORMULA_TREE_TYPE_OTHER
|
|
1926
|
+
};
|
|
1927
|
+
}
|
|
1928
|
+
_rustRangeToUnitRange(range) {
|
|
1929
|
+
return {
|
|
1930
|
+
unitId: range.unitId,
|
|
1931
|
+
sheetId: range.sheetId,
|
|
1932
|
+
range: {
|
|
1933
|
+
startRow: range.startRow,
|
|
1934
|
+
endRow: range.endRow,
|
|
1935
|
+
startColumn: range.startColumn,
|
|
1936
|
+
endColumn: range.endColumn
|
|
1937
|
+
}
|
|
1938
|
+
};
|
|
1939
|
+
}
|
|
1940
|
+
_serializeUnitRanges(unitRanges) {
|
|
1941
|
+
return unitRanges.map((unitRange) => ({
|
|
1942
|
+
unitId: unitRange.unitId,
|
|
1943
|
+
sheetId: unitRange.sheetId,
|
|
1944
|
+
startRow: unitRange.range.startRow,
|
|
1945
|
+
endRow: unitRange.range.endRow,
|
|
1946
|
+
startColumn: unitRange.range.startColumn,
|
|
1947
|
+
endColumn: unitRange.range.endColumn
|
|
1948
|
+
}));
|
|
1949
|
+
}
|
|
1950
|
+
_rustDependencyJsonByCell(items) {
|
|
1951
|
+
return new Map(
|
|
1952
|
+
items.map((item) => [
|
|
1953
|
+
this._cellKey({
|
|
1954
|
+
unitId: item.unitId,
|
|
1955
|
+
sheetId: item.subUnitId,
|
|
1956
|
+
row: item.row,
|
|
1957
|
+
column: item.column
|
|
1958
|
+
}),
|
|
1959
|
+
item
|
|
1960
|
+
])
|
|
1961
|
+
);
|
|
1962
|
+
}
|
|
1963
|
+
_cellKey(cell) {
|
|
1964
|
+
return `${cell.unitId}\0${cell.sheetId}\0${cell.row}\0${cell.column}`;
|
|
1965
|
+
}
|
|
1966
|
+
_cellInUnitRanges(unitId, sheetId, row, column, unitRanges) {
|
|
1967
|
+
return unitRanges.some(
|
|
1968
|
+
(unitRange) => unitRange.unitId === unitId && unitRange.sheetId === sheetId && row >= unitRange.range.startRow && row <= unitRange.range.endRow && column >= unitRange.range.startColumn && column <= unitRange.range.endColumn
|
|
1969
|
+
);
|
|
1970
|
+
}
|
|
1971
|
+
_uniqueDependencyJson(items) {
|
|
1972
|
+
let seen = /* @__PURE__ */ new Set(), result = [];
|
|
1973
|
+
return items.forEach((item) => {
|
|
1974
|
+
!item || seen.has(item.treeId) || (seen.add(item.treeId), result.push(item));
|
|
1975
|
+
}), result;
|
|
1976
|
+
}
|
|
1977
|
+
};
|
|
1978
|
+
setDependencies3(RustCalculateFormulaService, [
|
|
1979
|
+
IConfigService,
|
|
1980
|
+
IFormulaCurrentConfigService,
|
|
1981
|
+
IFormulaRuntimeService,
|
|
1982
|
+
IFormulaDependencyGenerator,
|
|
1983
|
+
IFeatureCalculationManagerService,
|
|
1984
|
+
IOtherFormulaManagerService,
|
|
1985
|
+
ICommandService3,
|
|
1986
|
+
RustEngineSyncController,
|
|
1987
|
+
ExternalReferencePrefetchPlanner,
|
|
1988
|
+
ExternalReferencePrefetchService
|
|
1989
|
+
]);
|
|
1990
|
+
function isFormulaDependencyTreeJson(value) {
|
|
1991
|
+
return value !== void 0;
|
|
1992
|
+
}
|
|
1993
|
+
function normalizeFormulaResultValue(value) {
|
|
1994
|
+
return value == null || typeof value == "number" || typeof value == "string" || typeof value == "boolean" || Array.isArray(value) && value.every(isFormulaResultRow) ? value : null;
|
|
1995
|
+
}
|
|
1996
|
+
function isFormulaResultRow(value) {
|
|
1997
|
+
return Array.isArray(value) && value.every(
|
|
1998
|
+
(item) => item == null || typeof item == "number" || typeof item == "string" || typeof item == "boolean"
|
|
1999
|
+
);
|
|
2000
|
+
}
|
|
2001
|
+
|
|
2002
|
+
// src/plugin.ts
|
|
2003
|
+
var DEFAULT_RUST_FORMULA_PLUGIN_CONFIG = {}, UniverRustFormulaEnginePlugin = class extends UniverProFormulaEnginePlugin {
|
|
2004
|
+
constructor(_config = DEFAULT_RUST_FORMULA_PLUGIN_CONFIG, _injector, _configService) {
|
|
2005
|
+
super(_config, _injector, _configService);
|
|
2006
|
+
this._config = _config;
|
|
2007
|
+
this._injector = _injector;
|
|
2008
|
+
this._configService = _configService;
|
|
2009
|
+
}
|
|
2010
|
+
_config;
|
|
2011
|
+
_injector;
|
|
2012
|
+
_configService;
|
|
2013
|
+
static packageName = name;
|
|
2014
|
+
static version = version;
|
|
2015
|
+
onReady() {
|
|
2016
|
+
super.onReady(), !this._config?.notExecuteFormula && this._config?.useRustEngine !== !1 && touchDependencies(this._injector, [[RustEngineSyncController], [RustSameRuntimeProjectionController]]);
|
|
2017
|
+
}
|
|
2018
|
+
/**
|
|
2019
|
+
* UniverProFormulaEnginePlugin invokes this hook before its single DI
|
|
2020
|
+
* registration pass.
|
|
2021
|
+
*/
|
|
2022
|
+
_extendFormulaExecutionDependencies(dependencies) {
|
|
2023
|
+
if (this._config?.useRustEngine !== !1 && !this._config?.notExecuteFormula) {
|
|
2024
|
+
let calculateServiceIndex = dependencies.findIndex(
|
|
2025
|
+
(dependency) => Array.isArray(dependency) && dependency[0] === ICalculateFormulaService
|
|
2026
|
+
), rustDependencies = [
|
|
2027
|
+
[RustEngineSyncController],
|
|
2028
|
+
[RustSameRuntimeProjectionController],
|
|
2029
|
+
[IRustCalculateFormulaService, { useClass: RustCalculateFormulaService }],
|
|
2030
|
+
// eslint-disable-next-line react/no-unnecessary-use-prefix
|
|
2031
|
+
[ICalculateFormulaService, { useFactory: () => this._injector.get(IRustCalculateFormulaService) }]
|
|
2032
|
+
];
|
|
2033
|
+
calculateServiceIndex >= 0 && dependencies.splice(calculateServiceIndex, 1), dependencies.push(...rustDependencies);
|
|
2034
|
+
}
|
|
2035
|
+
}
|
|
2036
|
+
};
|
|
2037
|
+
setDependencies4(UniverRustFormulaEnginePlugin, [Injector, IConfigService2], 1);
|
|
2038
|
+
|
|
2039
|
+
// src/services/workbook-snapshot-materializer.ts
|
|
2040
|
+
import { Buffer } from "node:buffer";
|
|
2041
|
+
async function materializeWorkbookSnapshot(workbook, unitID, rev, dirtyInput) {
|
|
2042
|
+
await loadNativeBinding();
|
|
2043
|
+
let result = await materializeWorkbookSnapshotOnRust(
|
|
2044
|
+
Buffer.from(JSON.stringify(workbook)),
|
|
2045
|
+
unitID,
|
|
2046
|
+
rev,
|
|
2047
|
+
dirtyInput == null ? void 0 : JSON.stringify(dirtyInput)
|
|
2048
|
+
), draft = JSON.parse(result.snapshotDraftJson.toString("utf8")), encoder = new TextEncoder(), sheets = Object.fromEntries(
|
|
2049
|
+
Object.entries(draft.workbook.sheets).map(([sheetID, sheet]) => {
|
|
2050
|
+
let { originalMetaJson: originalMetaJson2, ...meta } = sheet;
|
|
2051
|
+
return [sheetID, { ...meta, originalMeta: encoder.encode(originalMetaJson2) }];
|
|
2052
|
+
})
|
|
2053
|
+
), { originalMetaJson, ...workbookMeta } = draft.workbook;
|
|
2054
|
+
return {
|
|
2055
|
+
snapshot: {
|
|
2056
|
+
unitID: draft.unitID,
|
|
2057
|
+
type: draft.type,
|
|
2058
|
+
rev: draft.rev,
|
|
2059
|
+
workbook: {
|
|
2060
|
+
...workbookMeta,
|
|
2061
|
+
sheets,
|
|
2062
|
+
originalMeta: encoder.encode(originalMetaJson)
|
|
2063
|
+
},
|
|
2064
|
+
doc: void 0,
|
|
2065
|
+
slide: void 0,
|
|
2066
|
+
board: void 0
|
|
2067
|
+
},
|
|
2068
|
+
sheetBlocks: Object.fromEntries(result.sheetBlocks.map(({ sheetId, blocks }) => [sheetId, blocks])),
|
|
2069
|
+
warnings: JSON.parse(result.warningsJson.toString("utf8")),
|
|
2070
|
+
calculationStats: JSON.parse(result.calculationStatsJson.toString("utf8"))
|
|
2071
|
+
};
|
|
2072
|
+
}
|
|
2073
|
+
export {
|
|
2074
|
+
IRustCalculateFormulaService,
|
|
2075
|
+
RUST_FORMULA_RELEVANT_MUTATIONS,
|
|
2076
|
+
RUST_INCREMENTAL_DEPENDENCY_MUTATIONS,
|
|
2077
|
+
RUST_UPSERT_REFERENCE_DATA_MUTATION_ID,
|
|
2078
|
+
RustCalculateFormulaService,
|
|
2079
|
+
RustEngineSyncController,
|
|
2080
|
+
RustFormulaProjectionService,
|
|
2081
|
+
UniverRustFormulaEnginePlugin,
|
|
2082
|
+
analyzeNumberFormatBatch,
|
|
2083
|
+
applyMutationOnRust,
|
|
2084
|
+
buildLexerTreeOnRust,
|
|
2085
|
+
buildRustDependencyGraphOnRust,
|
|
2086
|
+
buildSequenceNodesOnRust,
|
|
2087
|
+
checkIfAddBracketOnRust,
|
|
2088
|
+
clearRustFormulaDependenciesOnRust,
|
|
2089
|
+
clearRustFormulaDirtyOnRust,
|
|
2090
|
+
createFormulaProjectionDesyncSignal,
|
|
2091
|
+
disposeAllWorkbooksOnRust,
|
|
2092
|
+
disposeWorkbookOnRust,
|
|
2093
|
+
executeOnRust,
|
|
2094
|
+
formatNumberBatch,
|
|
2095
|
+
getNativeBindingSource,
|
|
2096
|
+
getRustCellOnRust,
|
|
2097
|
+
getRustDirtyDependenciesOnRust,
|
|
2098
|
+
getRustFormulaDataOnRust,
|
|
2099
|
+
getRustModelStats,
|
|
2100
|
+
getRustSheetStateOnRust,
|
|
2101
|
+
isRustFormulaRelevantMutation,
|
|
2102
|
+
isRustIncrementalDependencyMutation,
|
|
2103
|
+
loadNativeBinding,
|
|
2104
|
+
loadSnapshotOnRust,
|
|
2105
|
+
markRustFormulaDirtyOnRust,
|
|
2106
|
+
materializeWorkbookSnapshot,
|
|
2107
|
+
materializeWorkbookSnapshotOnRust,
|
|
2108
|
+
parseNumberFormatBatch,
|
|
2109
|
+
parseNumberFormatMatrixBatch,
|
|
2110
|
+
rustExecutionOutputToFormulaCalculationPatch,
|
|
2111
|
+
serializeRuntimeWorkbookSnapshot,
|
|
2112
|
+
serializeRuntimeWorkbookSnapshots,
|
|
2113
|
+
syncRustFormulaDependenciesOnRust
|
|
2114
|
+
};
|