agent-spreadsheet-sdk 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,226 @@
1
+ # agent-spreadsheet-sdk
2
+
3
+ **`agent-spreadsheet-sdk` is the JavaScript integration layer for agent-spreadsheet — the tool interaction service for agent-based spreadsheet work.**
4
+
5
+ It lets one application target multiple spreadsheet backends behind a consistent API:
6
+ - **MCP backend** for remote/stateful workflows
7
+ - **WASM/session backend** for embedded or in-process workflows
8
+
9
+ The goal is not “another transport wrapper.”
10
+ The goal is **one app-facing spreadsheet interaction model** for agent systems.
11
+
12
+ ---
13
+
14
+ ## Install
15
+
16
+ ```bash
17
+ npm i agent-spreadsheet-sdk
18
+ ```
19
+
20
+ Node: `>=18`
21
+
22
+ ---
23
+
24
+ ## What this SDK normalizes
25
+
26
+ - shared method names across backends
27
+ - tolerance for common input aliases (`camelCase` / `snake_case`)
28
+ - top-level output normalization
29
+ - capability checks for backend-specific flows
30
+ - typed errors for unsupported features and backend failures
31
+
32
+ ---
33
+
34
+ ## Backends
35
+
36
+ ### `McpBackend`
37
+ Use when your app talks to a running `agent-spreadsheet-mcp` server or MCP client transport.
38
+
39
+ Best for:
40
+ - multi-turn agent workflows
41
+ - remote/stateful spreadsheet execution
42
+ - fork lifecycle and staged changes
43
+
44
+ ### `WasmBackend`
45
+ Use when your app embeds a WASM/session runtime.
46
+
47
+ Best for:
48
+ - local/in-process execution
49
+ - browser or embedded app scenarios
50
+ - session-oriented workflows without MCP transport
51
+
52
+ ---
53
+
54
+ ## Quick start
55
+
56
+ ```js
57
+ const { McpBackend, WasmBackend } = require("agent-spreadsheet-sdk")
58
+
59
+ const mcp = new McpBackend({ transport: myMcpTransport })
60
+ const wasm = new WasmBackend({ bindings: myWasmBindings })
61
+
62
+ async function sharedReadFlow(backend, ctx) {
63
+ const workbook = await backend.describeWorkbook(ctx)
64
+ const sheets = await backend.listSheets(ctx)
65
+ const overview = await backend.sheetOverview({ ...ctx, sheetName: sheets[0] })
66
+ const page = await backend.sheetPage({
67
+ ...ctx,
68
+ sheetName: sheets[0],
69
+ startRow: 1,
70
+ pageSize: 50,
71
+ format: "compact"
72
+ })
73
+
74
+ return { workbook, sheets, overview, page }
75
+ }
76
+ ```
77
+
78
+ Typical context identity:
79
+ - MCP: `{ workbookId: "..." }`
80
+ - WASM/session: `{ sessionId: "..." }`
81
+ - higher-level helper code may use `{ contextId: "..." }`
82
+
83
+ ---
84
+
85
+ ## Shared methods
86
+
87
+ ### Read / inspection
88
+ - `describeWorkbook(input)`
89
+ - `listSheets(input)`
90
+ - `sheetOverview(input)`
91
+ - `namedRanges(input)`
92
+ - `rangeValues(input)`
93
+ - `readTable(input)`
94
+ - `sheetPage(input)`
95
+ - `findValue(input)`
96
+ - `gridExport(input)`
97
+
98
+ ### Write
99
+ - `transformBatch(input)`
100
+
101
+ ### Verification helpers
102
+ - `verifyWorkbook(input)`
103
+ - `verifyTargets(input)`
104
+ - `verifyErrors(input)`
105
+
106
+ ### Backend-specific lifecycle
107
+ - MCP-oriented: `createFork`, `listForks`, `saveFork`, `discardFork`, staged-change methods
108
+ - WASM/session-oriented: `createSession`, `exportWorkbook`, `disposeSession`
109
+
110
+ Always branch on capabilities before using backend-specific methods.
111
+
112
+ ---
113
+
114
+ ## Capability model
115
+
116
+ ```js
117
+ const caps = backend.getCapabilities()
118
+
119
+ if (caps.supportsForkLifecycle) {
120
+ // MCP path
121
+ }
122
+
123
+ if (caps.supportsVerification) {
124
+ // verifyWorkbook / verifyTargets / verifyErrors
125
+ }
126
+
127
+ if (caps.supportsSessionLifecycle) {
128
+ // WASM/session path
129
+ }
130
+ ```
131
+
132
+ Unsupported backend-specific calls throw `CapabilityError` with code:
133
+ - `UNSUPPORTED_CAPABILITY`
134
+
135
+ This is a feature, not a footgun: **capabilities are the contract for mixed-backend safety**.
136
+
137
+ ---
138
+
139
+ ## Error model
140
+
141
+ SDK exports:
142
+ - `SpreadsheetSdkError`
143
+ - `CapabilityError`
144
+ - `BackendOperationError`
145
+
146
+ Common normalized codes:
147
+ - `INVALID_ARGUMENT`
148
+ - `INVALID_RESPONSE`
149
+ - `UNSUPPORTED_CAPABILITY`
150
+ - backend-provided machine codes when available
151
+
152
+ ---
153
+
154
+ ## MCP transport contract
155
+
156
+ `McpBackend` accepts either:
157
+ - a generic `invoke(operation, params)` transport
158
+ - or transport objects with per-operation methods
159
+
160
+ Example:
161
+
162
+ ```js
163
+ const backend = new McpBackend({
164
+ transport: {
165
+ async invoke(operation, params) {
166
+ return client.callTool(operation, params)
167
+ }
168
+ }
169
+ })
170
+ ```
171
+
172
+ ---
173
+
174
+ ## WASM bindings contract
175
+
176
+ `WasmBackend` expects bindings shaped like:
177
+ - `createSession`
178
+ - `describeWorkbook`
179
+ - `namedRanges`
180
+ - `sheetOverview`
181
+ - `listSheets`
182
+ - `rangeValues`
183
+ - `findValue`
184
+ - `readTable`
185
+ - `sheetPage`
186
+ - `gridExport`
187
+ - `transformBatch`
188
+ - `exportWorkbook`
189
+ - `disposeSession`
190
+
191
+ These map to the in-repo `agent-spreadsheet-wasm` work.
192
+
193
+ ---
194
+
195
+ ## When to use this SDK
196
+
197
+ Use `agent-spreadsheet-sdk` when you are building:
198
+ - an app that may swap between MCP and embedded execution
199
+ - a higher-level agent workflow system that should not care about transport details
200
+ - a UI or service that needs one normalized spreadsheet interaction model
201
+
202
+ Use the CLI directly when you only need shell/file workflows.
203
+ Use MCP directly when your system already lives entirely inside an MCP runtime.
204
+
205
+ ---
206
+
207
+ ## Release lanes
208
+
209
+ This package is published from `sdk-vX.Y.Z` tags.
210
+
211
+ Dist-tag policy:
212
+ - stable -> `latest`
213
+ - `-rc.N` -> `rc`
214
+ - `-beta.N` -> `beta`
215
+ - `-alpha.N` -> `alpha`
216
+
217
+ ---
218
+
219
+ ## Related packages
220
+
221
+ - `agent-spreadsheet` — npm CLI wrapper
222
+ - `agent-spreadsheet` — Rust semantic core
223
+ - `agent-spreadsheet-mcp` — MCP server
224
+ - `agent-spreadsheet-wasm` — in-repo WASM-facing crate
225
+
226
+ Repo: <https://github.com/PSU3D0/agent-spreadsheet>
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "agent-spreadsheet-sdk",
3
+ "version": "0.12.0",
4
+ "description": "Backend-agnostic JavaScript SDK for agent-spreadsheet surfaces (MCP and WASM)",
5
+ "license": "Apache-2.0",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/PSU3D0/agent-spreadsheet.git",
9
+ "directory": "npm/agent-spreadsheet-sdk"
10
+ },
11
+ "homepage": "https://github.com/PSU3D0/agent-spreadsheet",
12
+ "bugs": {
13
+ "url": "https://github.com/PSU3D0/agent-spreadsheet/issues"
14
+ },
15
+ "keywords": [
16
+ "spreadsheet",
17
+ "xlsx",
18
+ "sdk",
19
+ "mcp",
20
+ "wasm"
21
+ ],
22
+ "main": "src/index.js",
23
+ "files": [
24
+ "src",
25
+ "README.md"
26
+ ],
27
+ "scripts": {
28
+ "test": "node --test"
29
+ },
30
+ "engines": {
31
+ "node": ">=18"
32
+ },
33
+ "publishConfig": {
34
+ "access": "public"
35
+ }
36
+ }
package/src/backend.js ADDED
@@ -0,0 +1,388 @@
1
+ const { CapabilityError, SpreadsheetSdkError } = require("./errors")
2
+
3
+ /**
4
+ * @typedef {import("./capabilities").BackendCapabilities} BackendCapabilities
5
+ */
6
+
7
+ /**
8
+ * @typedef {object} SpreadsheetBackend
9
+ * @property {"mcp"|"wasm"} kind
10
+ * @property {() => Readonly<BackendCapabilities>} getCapabilities
11
+ * @property {(input: Record<string, unknown>) => Promise<string[]>} listSheets
12
+ * @property {(input: Record<string, unknown>) => Promise<{ sheetName: string, values: unknown[] }>} rangeValues
13
+ */
14
+
15
+ /**
16
+ * @param {{ kind: string, getCapabilities: () => Record<string, boolean> }} backend
17
+ * @param {string} capability
18
+ * @param {string} method
19
+ */
20
+ function requireCapability(backend, capability, method) {
21
+ const capabilities = backend.getCapabilities()
22
+ if (!capabilities[capability]) {
23
+ throw new CapabilityError({
24
+ backend: backend.kind,
25
+ capability,
26
+ method
27
+ })
28
+ }
29
+ }
30
+
31
+ /**
32
+ * @param {unknown} value
33
+ * @param {string} name
34
+ */
35
+ function requiredString(value, name) {
36
+ if (typeof value !== "string" || value.length === 0) {
37
+ throw new SpreadsheetSdkError(`missing required field '${name}'`, {
38
+ code: "INVALID_ARGUMENT"
39
+ })
40
+ }
41
+ return value
42
+ }
43
+
44
+ /**
45
+ * @param {unknown} result
46
+ * @param {string} fallbackSheetName
47
+ */
48
+ function normalizeSheetPageResult(result, fallbackSheetName) {
49
+ if (!result || typeof result !== "object") {
50
+ throw new SpreadsheetSdkError("invalid sheetPage response", {
51
+ code: "INVALID_RESPONSE"
52
+ })
53
+ }
54
+
55
+ return {
56
+ workbookId: typeof result.workbookId === "string"
57
+ ? result.workbookId
58
+ : typeof result.workbook_id === "string"
59
+ ? result.workbook_id
60
+ : undefined,
61
+ sheetName: typeof result.sheetName === "string"
62
+ ? result.sheetName
63
+ : typeof result.sheet_name === "string"
64
+ ? result.sheet_name
65
+ : fallbackSheetName,
66
+ rows: Array.isArray(result.rows) ? result.rows : [],
67
+ nextStartRow: typeof result.nextStartRow === "number"
68
+ ? result.nextStartRow
69
+ : typeof result.next_start_row === "number"
70
+ ? result.next_start_row
71
+ : undefined,
72
+ headerRow: result.headerRow ?? result.header_row,
73
+ compact: result.compact,
74
+ valuesOnly: result.valuesOnly ?? result.values_only,
75
+ format: result.format
76
+ }
77
+ }
78
+
79
+ /**
80
+ * @param {unknown} result
81
+ */
82
+ function normalizeGridExportResult(result) {
83
+ if (!result || typeof result !== "object") {
84
+ throw new SpreadsheetSdkError("invalid gridExport response", {
85
+ code: "INVALID_RESPONSE"
86
+ })
87
+ }
88
+ return {
89
+ sheet: result.sheet,
90
+ anchor: result.anchor,
91
+ columns: result.columns,
92
+ merges: result.merges,
93
+ rows: result.rows
94
+ }
95
+ }
96
+
97
+ /**
98
+ * @param {unknown} result
99
+ */
100
+ function normalizeTransformBatchResult(result) {
101
+ if (!result || typeof result !== "object") {
102
+ throw new SpreadsheetSdkError("invalid transformBatch response", {
103
+ code: "INVALID_RESPONSE"
104
+ })
105
+ }
106
+ return {
107
+ opsApplied: result.opsApplied ?? result.ops_applied,
108
+ cellsTouched: result.cellsTouched ?? result.cells_touched,
109
+ cellsValueSet: result.cellsValueSet ?? result.cells_value_set,
110
+ cellsFormulaSet: result.cellsFormulaSet ?? result.cells_formula_set,
111
+ cellsFormulaCleared: result.cellsFormulaCleared ?? result.cells_formula_cleared,
112
+ cellsSkippedKeepFormulas: result.cellsSkippedKeepFormulas ?? result.cells_skipped_keep_formulas,
113
+ formulaParseDiagnostics: result.formulaParseDiagnostics ?? result.formula_parse_diagnostics
114
+ }
115
+ }
116
+
117
+ /**
118
+ * @param {unknown} result
119
+ * @param {string | undefined} fallbackWorkbookId
120
+ */
121
+ function normalizeDescribeWorkbookResult(result, fallbackWorkbookId) {
122
+ if (!result || typeof result !== "object") {
123
+ throw new SpreadsheetSdkError("invalid describeWorkbook response", {
124
+ code: "INVALID_RESPONSE"
125
+ })
126
+ }
127
+
128
+ return {
129
+ workbookId: result.workbookId ?? result.workbook_id ?? fallbackWorkbookId,
130
+ shortId: result.shortId ?? result.short_id,
131
+ slug: result.slug,
132
+ path: result.path,
133
+ clientPath: result.clientPath ?? result.client_path,
134
+ bytes: result.bytes,
135
+ sheetCount: result.sheetCount ?? result.sheet_count,
136
+ definedNames: result.definedNames ?? result.defined_names,
137
+ tables: result.tables,
138
+ macrosPresent: result.macrosPresent ?? result.macros_present,
139
+ lastModified: result.lastModified ?? result.last_modified,
140
+ revisionId: result.revisionId ?? result.revision_id,
141
+ caps: result.caps
142
+ }
143
+ }
144
+
145
+ /**
146
+ * @param {unknown} result
147
+ * @param {string | undefined} fallbackWorkbookId
148
+ */
149
+ function normalizeNamedRangesResult(result, fallbackWorkbookId) {
150
+ if (!result || typeof result !== "object") {
151
+ throw new SpreadsheetSdkError("invalid namedRanges response", {
152
+ code: "INVALID_RESPONSE"
153
+ })
154
+ }
155
+
156
+ return {
157
+ workbookId: result.workbookId ?? result.workbook_id ?? fallbackWorkbookId,
158
+ items: Array.isArray(result.items) ? result.items : []
159
+ }
160
+ }
161
+
162
+ /**
163
+ * @param {unknown} result
164
+ * @param {string} fallbackSheetName
165
+ * @param {string | undefined} fallbackWorkbookId
166
+ */
167
+ function normalizeSheetOverviewResult(result, fallbackSheetName, fallbackWorkbookId) {
168
+ if (!result || typeof result !== "object") {
169
+ throw new SpreadsheetSdkError("invalid sheetOverview response", {
170
+ code: "INVALID_RESPONSE"
171
+ })
172
+ }
173
+
174
+ return {
175
+ workbookId: result.workbookId ?? result.workbook_id ?? fallbackWorkbookId,
176
+ sheetName: result.sheetName ?? result.sheet_name ?? fallbackSheetName,
177
+ narrative: result.narrative,
178
+ regions: Array.isArray(result.regions) ? result.regions : [],
179
+ detectedRegions: result.detectedRegions ?? result.detected_regions ?? [],
180
+ detectedRegionCount: result.detectedRegionCount ?? result.detected_region_count,
181
+ detectedRegionsTruncated: result.detectedRegionsTruncated ?? result.detected_regions_truncated,
182
+ keyRanges: result.keyRanges ?? result.key_ranges ?? [],
183
+ formulaRatio: result.formulaRatio ?? result.formula_ratio,
184
+ notableFeatures: result.notableFeatures ?? result.notable_features ?? [],
185
+ notes: Array.isArray(result.notes) ? result.notes : []
186
+ }
187
+ }
188
+
189
+ /**
190
+ * @param {unknown} result
191
+ * @param {string | undefined} fallbackWorkbookId
192
+ */
193
+ function normalizeFindValueResult(result, fallbackWorkbookId) {
194
+ if (!result || typeof result !== "object") {
195
+ throw new SpreadsheetSdkError("invalid findValue response", {
196
+ code: "INVALID_RESPONSE"
197
+ })
198
+ }
199
+
200
+ return {
201
+ workbookId: result.workbookId ?? result.workbook_id ?? fallbackWorkbookId,
202
+ matches: Array.isArray(result.matches) ? result.matches : [],
203
+ nextOffset: result.nextOffset ?? result.next_offset
204
+ }
205
+ }
206
+
207
+ /**
208
+ * @param {unknown} result
209
+ * @param {string | undefined} fallbackWorkbookId
210
+ * @param {string | undefined} fallbackSheetName
211
+ */
212
+ function normalizeReadTableResult(result, fallbackWorkbookId, fallbackSheetName) {
213
+ if (!result || typeof result !== "object") {
214
+ throw new SpreadsheetSdkError("invalid readTable response", {
215
+ code: "INVALID_RESPONSE"
216
+ })
217
+ }
218
+
219
+ return {
220
+ workbookId: result.workbookId ?? result.workbook_id ?? fallbackWorkbookId,
221
+ sheetName: result.sheetName ?? result.sheet_name ?? fallbackSheetName,
222
+ tableName: result.tableName ?? result.table_name,
223
+ warnings: Array.isArray(result.warnings) ? result.warnings : [],
224
+ headers: Array.isArray(result.headers) ? result.headers : [],
225
+ rows: Array.isArray(result.rows) ? result.rows : [],
226
+ values: result.values,
227
+ types: result.types,
228
+ csv: result.csv,
229
+ totalRows: result.totalRows ?? result.total_rows ?? 0,
230
+ nextOffset: result.nextOffset ?? result.next_offset
231
+ }
232
+ }
233
+
234
+ /**
235
+ * @param {unknown} result
236
+ */
237
+ function normalizeStructureBatchResult(result) {
238
+ if (!result || typeof result !== "object") {
239
+ throw new SpreadsheetSdkError("invalid structureBatch response", {
240
+ code: "INVALID_RESPONSE"
241
+ })
242
+ }
243
+ return {
244
+ forkId: result.forkId ?? result.fork_id,
245
+ mode: result.mode,
246
+ changeId: result.changeId ?? result.change_id,
247
+ opsApplied: result.opsApplied ?? result.ops_applied,
248
+ summary: result.summary,
249
+ formulaParseDiagnostics: result.formulaParseDiagnostics ?? result.formula_parse_diagnostics,
250
+ impactReport: result.impactReport ?? result.impact_report,
251
+ formulaDeltaPreview: result.formulaDeltaPreview ?? result.formula_delta_preview
252
+ }
253
+ }
254
+
255
+ /**
256
+ * @param {unknown} result
257
+ */
258
+ function normalizeReplaceInFormulasResult(result) {
259
+ if (!result || typeof result !== "object") {
260
+ throw new SpreadsheetSdkError("invalid replaceInFormulas response", {
261
+ code: "INVALID_RESPONSE"
262
+ })
263
+ }
264
+ return {
265
+ forkId: result.forkId ?? result.fork_id,
266
+ mode: result.mode,
267
+ changeId: result.changeId ?? result.change_id,
268
+ formulasChecked: result.formulasChecked ?? result.formulas_checked ?? 0,
269
+ formulasChanged: result.formulasChanged ?? result.formulas_changed ?? 0,
270
+ recalcNeeded: result.recalcNeeded ?? result.recalc_needed ?? false,
271
+ samples: Array.isArray(result.samples) ? result.samples : [],
272
+ warnings: Array.isArray(result.warnings) ? result.warnings : [],
273
+ formulaParseDiagnostics: result.formulaParseDiagnostics ?? result.formula_parse_diagnostics
274
+ }
275
+ }
276
+
277
+ /**
278
+ * @param {unknown} result
279
+ * @param {string | undefined} fallbackBaseline
280
+ * @param {string | undefined} fallbackCurrent
281
+ */
282
+ function normalizeVerifyWorkbookResult(result, fallbackBaseline, fallbackCurrent) {
283
+ if (!result || typeof result !== "object") {
284
+ throw new SpreadsheetSdkError("invalid verifyWorkbook response", {
285
+ code: "INVALID_RESPONSE"
286
+ })
287
+ }
288
+
289
+ const targetClassificationCounts = result.summary?.targetClassificationCounts
290
+ ?? result.summary?.target_classification_counts
291
+ ?? {}
292
+
293
+ return {
294
+ baselineRef: result.baselineRef ?? result.baseline_ref ?? result.baseline ?? fallbackBaseline,
295
+ currentRef: result.currentRef ?? result.current_ref ?? result.current ?? fallbackCurrent,
296
+ targetDeltas: Array.isArray(result.targetDeltas)
297
+ ? result.targetDeltas
298
+ : Array.isArray(result.target_deltas)
299
+ ? result.target_deltas.map((item) => ({
300
+ address: item.address,
301
+ before: item.before,
302
+ after: item.after,
303
+ beforeFormula: item.beforeFormula ?? item.before_formula,
304
+ afterFormula: item.afterFormula ?? item.after_formula,
305
+ classification: item.classification,
306
+ changed: item.changed
307
+ }))
308
+ : [],
309
+ newErrors: Array.isArray(result.newErrors)
310
+ ? result.newErrors
311
+ : Array.isArray(result.new_errors)
312
+ ? result.new_errors.map((item) => ({
313
+ address: item.address,
314
+ beforeError: item.beforeError ?? item.before_error,
315
+ afterError: item.afterError ?? item.after_error,
316
+ beforeFormula: item.beforeFormula ?? item.before_formula,
317
+ afterFormula: item.afterFormula ?? item.after_formula
318
+ }))
319
+ : [],
320
+ resolvedErrors: Array.isArray(result.resolvedErrors)
321
+ ? result.resolvedErrors
322
+ : Array.isArray(result.resolved_errors)
323
+ ? result.resolved_errors.map((item) => ({
324
+ address: item.address,
325
+ beforeError: item.beforeError ?? item.before_error,
326
+ afterError: item.afterError ?? item.after_error,
327
+ beforeFormula: item.beforeFormula ?? item.before_formula,
328
+ afterFormula: item.afterFormula ?? item.after_formula
329
+ }))
330
+ : [],
331
+ preexistingErrors: Array.isArray(result.preexistingErrors)
332
+ ? result.preexistingErrors
333
+ : Array.isArray(result.preexisting_errors)
334
+ ? result.preexisting_errors.map((item) => ({
335
+ address: item.address,
336
+ beforeError: item.beforeError ?? item.before_error,
337
+ afterError: item.afterError ?? item.after_error,
338
+ beforeFormula: item.beforeFormula ?? item.before_formula,
339
+ afterFormula: item.afterFormula ?? item.after_formula
340
+ }))
341
+ : [],
342
+ namedRangeDeltas: Array.isArray(result.namedRangeDeltas)
343
+ ? result.namedRangeDeltas
344
+ : Array.isArray(result.named_range_deltas)
345
+ ? result.named_range_deltas.map((item) => ({
346
+ name: item.name,
347
+ scopeKind: item.scopeKind ?? item.scope_kind,
348
+ scopeSheetName: item.scopeSheetName ?? item.scope_sheet_name,
349
+ change: item.change,
350
+ beforeRefersTo: item.beforeRefersTo ?? item.before_refers_to,
351
+ afterRefersTo: item.afterRefersTo ?? item.after_refers_to,
352
+ beforeKind: item.beforeKind ?? item.before_kind,
353
+ afterKind: item.afterKind ?? item.after_kind
354
+ }))
355
+ : [],
356
+ summary: {
357
+ targetCount: result.summary?.targetCount ?? result.summary?.target_count ?? 0,
358
+ changedTargets: result.summary?.changedTargets ?? result.summary?.changed_targets ?? 0,
359
+ newErrorCount: result.summary?.newErrorCount ?? result.summary?.new_error_count ?? 0,
360
+ resolvedErrorCount: result.summary?.resolvedErrorCount ?? result.summary?.resolved_error_count ?? 0,
361
+ preexistingErrorCount: result.summary?.preexistingErrorCount ?? result.summary?.preexisting_error_count ?? 0,
362
+ namedRangeDeltaCount: result.summary?.namedRangeDeltaCount ?? result.summary?.named_range_delta_count ?? 0,
363
+ targetClassificationCounts: {
364
+ unchanged: targetClassificationCounts.unchanged ?? 0,
365
+ directEdit: targetClassificationCounts.directEdit ?? targetClassificationCounts.direct_edit ?? 0,
366
+ recalcResult: targetClassificationCounts.recalcResult ?? targetClassificationCounts.recalc_result ?? 0,
367
+ formulaShift: targetClassificationCounts.formulaShift ?? targetClassificationCounts.formula_shift ?? 0,
368
+ newError: targetClassificationCounts.newError ?? targetClassificationCounts.new_error ?? 0
369
+ }
370
+ }
371
+ }
372
+ }
373
+
374
+ module.exports = {
375
+ requireCapability,
376
+ requiredString,
377
+ normalizeSheetPageResult,
378
+ normalizeGridExportResult,
379
+ normalizeTransformBatchResult,
380
+ normalizeStructureBatchResult,
381
+ normalizeReplaceInFormulasResult,
382
+ normalizeVerifyWorkbookResult,
383
+ normalizeDescribeWorkbookResult,
384
+ normalizeNamedRangesResult,
385
+ normalizeSheetOverviewResult,
386
+ normalizeFindValueResult,
387
+ normalizeReadTableResult
388
+ }