@bilig/workbook 0.42.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/LICENSE +1 -0
- package/README.md +346 -0
- package/dist/check.d.ts +26 -0
- package/dist/check.js +158 -0
- package/dist/check.js.map +1 -0
- package/dist/describe.d.ts +153 -0
- package/dist/describe.js +210 -0
- package/dist/describe.js.map +1 -0
- package/dist/find.d.ts +99 -0
- package/dist/find.js +353 -0
- package/dist/find.js.map +1 -0
- package/dist/formula.d.ts +25 -0
- package/dist/formula.js +135 -0
- package/dist/formula.js.map +1 -0
- package/dist/guards.d.ts +5 -0
- package/dist/guards.js +659 -0
- package/dist/guards.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/input.d.ts +22 -0
- package/dist/input.js +231 -0
- package/dist/input.js.map +1 -0
- package/dist/model.d.ts +116 -0
- package/dist/model.js +331 -0
- package/dist/model.js.map +1 -0
- package/dist/ops.d.ts +283 -0
- package/dist/ops.js +2 -0
- package/dist/ops.js.map +1 -0
- package/dist/readback.d.ts +35 -0
- package/dist/readback.js +232 -0
- package/dist/readback.js.map +1 -0
- package/dist/requirements.d.ts +34 -0
- package/dist/requirements.js +223 -0
- package/dist/requirements.js.map +1 -0
- package/dist/result.d.ts +63 -0
- package/dist/result.js +39 -0
- package/dist/result.js.map +1 -0
- package/dist/run.d.ts +21 -0
- package/dist/run.js +514 -0
- package/dist/run.js.map +1 -0
- package/dist/verify.d.ts +33 -0
- package/dist/verify.js +439 -0
- package/dist/verify.js.map +1 -0
- package/package.json +52 -0
package/LICENSE
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
MIT
|
package/README.md
ADDED
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
# @bilig/workbook
|
|
2
|
+
|
|
3
|
+
Agent-first workbook model API and transport-neutral workbook operation language for bilig.
|
|
4
|
+
|
|
5
|
+
Build `@bilig/workbook` so an agent would love using it: simple, generic,
|
|
6
|
+
predictable, inspectable, verifiable, and never dependent on hardcoded business
|
|
7
|
+
models or human spreadsheet UI assumptions.
|
|
8
|
+
|
|
9
|
+
Use this package when a consumer needs to describe workbook work without taking a
|
|
10
|
+
dependency on the engine, app server, transport, or replica-state implementation.
|
|
11
|
+
|
|
12
|
+
The public surface stays generic:
|
|
13
|
+
|
|
14
|
+
- `defineModel`
|
|
15
|
+
- `buildWorkbookActionPlan`
|
|
16
|
+
- `planWorkbookAction`
|
|
17
|
+
- `inspectModel`
|
|
18
|
+
- `collectWorkbookRefs`
|
|
19
|
+
- `findTable`, `findColumn`, `findRange`, `findName`, `findRows`
|
|
20
|
+
- `find`
|
|
21
|
+
- `check`
|
|
22
|
+
- `describeModel`
|
|
23
|
+
- `describeRef`
|
|
24
|
+
- `describePlan`
|
|
25
|
+
- `describePlanResult`
|
|
26
|
+
- `describeRunResult`
|
|
27
|
+
- `describeRuntimeRequirements`
|
|
28
|
+
- `verifyPlan`
|
|
29
|
+
- `verifyModel`
|
|
30
|
+
- `runWorkbookPlan`
|
|
31
|
+
- `runWorkbookAction`
|
|
32
|
+
- `verifyWorkbookReadbacks`
|
|
33
|
+
- `normalizeWorkbookActionInputDescription`
|
|
34
|
+
- `workbookPlanIssueCodes`
|
|
35
|
+
- `isWorkbookPlanIssueCode`
|
|
36
|
+
- `workbookReadbackIssueCodes`
|
|
37
|
+
- `isWorkbookReadbackIssueCode`
|
|
38
|
+
- `workbookRunErrorCodes`
|
|
39
|
+
- `isWorkbookRunErrorCode`
|
|
40
|
+
- `formula`
|
|
41
|
+
- `workbook.addOp(op, { target?, message? })` inside model actions
|
|
42
|
+
- `WorkbookModel`
|
|
43
|
+
- `WorkbookAction`
|
|
44
|
+
- `WorkbookActionConfig`
|
|
45
|
+
- `WorkbookActionDefinition`
|
|
46
|
+
- `WorkbookActionContext`
|
|
47
|
+
- `WorkbookCheckContext`
|
|
48
|
+
- `WorkbookFindWorkbook`
|
|
49
|
+
- `WorkbookCheckWorkbook`
|
|
50
|
+
- `WorkbookActionWorkbook`
|
|
51
|
+
- `WorkbookModelWorkbook`
|
|
52
|
+
- `WorkbookFindNamespace`
|
|
53
|
+
- `WorkbookActionInput`
|
|
54
|
+
- `WorkbookActionInputDescription`
|
|
55
|
+
- `WorkbookActionInputDescriptionKind`
|
|
56
|
+
- `WorkbookActionInspection`
|
|
57
|
+
- `WorkbookAddOpOptions`
|
|
58
|
+
- `WorkbookActionPlanResult`
|
|
59
|
+
- `WorkbookModelDescription`
|
|
60
|
+
- `WorkbookRefDescription`
|
|
61
|
+
- `WorkbookActionPlanDescription`
|
|
62
|
+
- `WorkbookActionPlanResultDescription`
|
|
63
|
+
- `WorkbookRunResultDescription`
|
|
64
|
+
- `WorkbookUndoRefDescription`
|
|
65
|
+
- `WorkbookAppliedSummaryDescription`
|
|
66
|
+
- `WorkbookRuntimeRequirements`
|
|
67
|
+
- `WorkbookRuntimeRequirement`
|
|
68
|
+
- `WorkbookRuntimeCapability`
|
|
69
|
+
- `WorkbookRuntimeMaterialization`
|
|
70
|
+
- `WorkbookRuntimePreview`
|
|
71
|
+
- `WorkbookPlanVerification`
|
|
72
|
+
- `WorkbookPlanIssue`
|
|
73
|
+
- `WorkbookPlanIssueCode`
|
|
74
|
+
- `WorkbookModelVerification`
|
|
75
|
+
- `WorkbookModelActionVerification`
|
|
76
|
+
- `WorkbookModelVerificationOptions`
|
|
77
|
+
- `WorkbookRunAdapter`
|
|
78
|
+
- `WorkbookRunApplyResult`
|
|
79
|
+
- `WorkbookCellReadback`
|
|
80
|
+
- `WorkbookRunReadback`
|
|
81
|
+
- `WorkbookReadbackVerification`
|
|
82
|
+
- `WorkbookReadbackIssue`
|
|
83
|
+
- `WorkbookReadbackIssueCode`
|
|
84
|
+
- `WorkbookCheckExpectation`
|
|
85
|
+
- `WorkbookCheckExpectationDescription`
|
|
86
|
+
- `WorkbookCustomCheckOptions`
|
|
87
|
+
- `WorkbookReadbackCheckOptions`
|
|
88
|
+
- `WorkbookRawFormulaOptions`
|
|
89
|
+
- `WorkbookRunResult`
|
|
90
|
+
- `WorkbookAppliedSummary`
|
|
91
|
+
- `WorkbookRunError`
|
|
92
|
+
- `WorkbookRunErrorCode`
|
|
93
|
+
- `WorkbookCheckResult`
|
|
94
|
+
|
|
95
|
+
The low-level operation language remains available:
|
|
96
|
+
|
|
97
|
+
- `WorkbookOp`
|
|
98
|
+
- `WorkbookTxn`
|
|
99
|
+
- `EngineOp`
|
|
100
|
+
- `EngineOpBatch`
|
|
101
|
+
- `isEngineOpBatch`
|
|
102
|
+
|
|
103
|
+
Formula helpers create portable formula expressions with `@bilig/formula`.
|
|
104
|
+
Calculation and workbook execution stay in `@bilig/core` and the app runtime.
|
|
105
|
+
Use `planWorkbookAction` when an action name comes from an agent or user input;
|
|
106
|
+
it returns `planned` or structured `failed` results instead of requiring
|
|
107
|
+
exception control flow.
|
|
108
|
+
Actions can also accept a JSON-safe input:
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
import { defineModel } from '@bilig/workbook'
|
|
112
|
+
|
|
113
|
+
export const model = defineModel({
|
|
114
|
+
name: 'custom-writer',
|
|
115
|
+
|
|
116
|
+
find(workbook) {
|
|
117
|
+
return {
|
|
118
|
+
output: workbook.findRange({ sheetName: 'Sheet1', address: 'B2' }),
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
|
|
122
|
+
actions: {
|
|
123
|
+
write({ refs, workbook, input }) {
|
|
124
|
+
if (typeof input !== 'object' || input === null || Array.isArray(input)) {
|
|
125
|
+
throw new Error('input object required')
|
|
126
|
+
}
|
|
127
|
+
const value = input.value
|
|
128
|
+
if (typeof value !== 'number') {
|
|
129
|
+
throw new Error('numeric value required')
|
|
130
|
+
}
|
|
131
|
+
workbook.writeValue(refs.output, value)
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
})
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
`planWorkbookAction(model, "write", { value: 12 })` clones and canonicalizes
|
|
138
|
+
that input into the plan so an agent can inspect exactly what was requested.
|
|
139
|
+
Inputs must be plain JSON values: strings, finite numbers, booleans, `null`,
|
|
140
|
+
arrays without holes, and plain objects. When an action object declares input
|
|
141
|
+
metadata, `planWorkbookAction` validates the provided value against the declared
|
|
142
|
+
JSON kind, required fields, and array item kind before `find`, `checks`, or the
|
|
143
|
+
action body run. This stays intentionally small: it is a dependency-free guard
|
|
144
|
+
for agent handoff, not a model-specific schema framework.
|
|
145
|
+
Use `verifyModel(model, { inputs: { write: { value: 12 } } })` when whole-model
|
|
146
|
+
verification needs parameters for specific actions.
|
|
147
|
+
|
|
148
|
+
Actions can also be plain action objects when an agent needs a richer manifest
|
|
149
|
+
without running workbook code:
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
actions: {
|
|
153
|
+
write: {
|
|
154
|
+
description: 'Write a consumer-provided value',
|
|
155
|
+
input: {
|
|
156
|
+
kind: 'object',
|
|
157
|
+
fields: {
|
|
158
|
+
value: { kind: 'number', required: true },
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
run({ refs, workbook, input }) {
|
|
162
|
+
if (typeof input !== 'object' || input === null || Array.isArray(input)) {
|
|
163
|
+
throw new Error('input object required')
|
|
164
|
+
}
|
|
165
|
+
const value = input.value
|
|
166
|
+
if (typeof value !== 'number') {
|
|
167
|
+
throw new Error('numeric value required')
|
|
168
|
+
}
|
|
169
|
+
workbook.writeValue(refs.output, value)
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Input descriptions support boring JSON kinds: `json`, `object`, `array`,
|
|
176
|
+
`string`, `number`, `boolean`, and `null`. `object` descriptions may list sorted
|
|
177
|
+
`fields`; `array` descriptions may list `items`; any description may be marked
|
|
178
|
+
`required`. `normalizeWorkbookActionInputDescription` trims text, rejects
|
|
179
|
+
malformed metadata, returns frozen data, and keeps the package free of `zod`,
|
|
180
|
+
`effect`, or model-specific validators.
|
|
181
|
+
|
|
182
|
+
Formula expressions also keep their workbook inputs separate from their formula
|
|
183
|
+
text. A planned `writeFormula` command includes both the parseable formula
|
|
184
|
+
string and the generic model refs it used, so an agent can inspect what the
|
|
185
|
+
action depends on without reverse-parsing placeholder names.
|
|
186
|
+
For formulas outside the small helper set, use
|
|
187
|
+
`formula.raw(source, { inputs })`; the source stays parseable while the
|
|
188
|
+
declared refs remain inspectable and verifiable. These inputs are a declared
|
|
189
|
+
dependency contract for agents, not parser-discovered proof that every formula
|
|
190
|
+
reference has been mapped to a model ref.
|
|
191
|
+
|
|
192
|
+
Known single-cell `workbook.format(ref, { numberFormat })` actions compile to
|
|
193
|
+
concrete `setCellFormat` ops. Use `numberFormat: null` to plan an explicit
|
|
194
|
+
format clear. Style patches remain high-level intent until the runtime resolves
|
|
195
|
+
style ids.
|
|
196
|
+
Use `workbook.addOp(op, { target?, message? })` inside model actions when a
|
|
197
|
+
consumer needs the existing low-level workbook operation language directly. The
|
|
198
|
+
op is runtime-guarded with `isWorkbookOp`, cloned into `plan.ops`, and kept in
|
|
199
|
+
the command log so agents can inspect it without depending on `@bilig/core`.
|
|
200
|
+
When a `target` is supplied for an address or range op, `verifyPlan` checks that
|
|
201
|
+
the op touches the same range. For op kinds without an inferable range, `target`
|
|
202
|
+
is still useful for logs and approvals but cannot prove the affected cells by
|
|
203
|
+
itself.
|
|
204
|
+
|
|
205
|
+
Action plans expose `refsUsed`, a flat deduped list of workbook refs found in
|
|
206
|
+
the consumer-defined `refs` object. Use `collectWorkbookRefs` directly when an
|
|
207
|
+
agent needs to inspect refs from any nested consumer shape.
|
|
208
|
+
Use `findTable`, `findColumn`, `findRange`, `findName`, and `findRows` directly
|
|
209
|
+
when an agent or test needs the same generic refs outside a model callback. The
|
|
210
|
+
same helpers are also available as a frozen `find` namespace with short aliases
|
|
211
|
+
such as `find.table(...)`, `find.range(...)`, and `find.rows(...)`.
|
|
212
|
+
Selector helpers trim text, canonicalize cell addresses, and reject empty table
|
|
213
|
+
names, column names, named ranges, headers, invalid range addresses, invalid row
|
|
214
|
+
operators, and non-finite row predicate values before a plan reaches runtime.
|
|
215
|
+
`findRows` refs include the predicate value in their stable id so two
|
|
216
|
+
consumer-defined row selectors do not collapse during dedupe, while labels stay
|
|
217
|
+
human-readable for agent logs.
|
|
218
|
+
Refs are frozen data objects. Ergonomic helpers like `table.column()` and
|
|
219
|
+
`rows.column()` remain available, but they are non-enumerable so JSON
|
|
220
|
+
inspection, object keys, and plan descriptions stay data-first.
|
|
221
|
+
For table-backed rows, use `rows.column("Amount")` to target only that column in
|
|
222
|
+
the matching rows. Runtime adapters can materialize row-filtered columns into
|
|
223
|
+
the exact cells to read, write, format, clear, or use as row-wise formula inputs
|
|
224
|
+
without hardcoding a business model.
|
|
225
|
+
Use `check.exists(ref)` and `check.noFormulaErrors(ref)` directly when an agent
|
|
226
|
+
or test needs the same generic planned checks outside a model callback.
|
|
227
|
+
Use `check.valueEquals(ref, value)` and `check.formulaEquals(ref, formula)` for
|
|
228
|
+
single-cell readback expectations. Use `check.valuesEqual(ref, rows)` and
|
|
229
|
+
`check.formulasEqual(ref, rows)` when the target may resolve to a range, table
|
|
230
|
+
column, or row-filtered column. `formulaEquals` stores normalized formula text
|
|
231
|
+
plus explicit model refs used by that formula, so an agent can inspect the
|
|
232
|
+
post-action proof target without depending on a rendered spreadsheet UI.
|
|
233
|
+
Use `check.custom({ kind, message, target, refs })` for consumer-defined
|
|
234
|
+
invariants; the package does not need to know what the model means. `target`
|
|
235
|
+
names the main ref, and `refs` names any supporting refs the invariant depends
|
|
236
|
+
on so agents can describe and verify the full check contract.
|
|
237
|
+
|
|
238
|
+
Model callback phases are deliberately scoped. `find(workbook)` receives only
|
|
239
|
+
the find API; `checks({ workbook })` receives find helpers plus `workbook.check`;
|
|
240
|
+
actions receive find helpers, checks, and mutation planning methods. That keeps
|
|
241
|
+
discovery and proof declaration separate from workbook mutation intent.
|
|
242
|
+
|
|
243
|
+
Use `describeModel` when an agent needs a JSON-safe manifest of model name,
|
|
244
|
+
model description, sorted action names, per-action descriptions, optional input
|
|
245
|
+
descriptions, and whether model-level checks exist without running `find`,
|
|
246
|
+
checks, or actions.
|
|
247
|
+
Use `describeRef` and `describePlan` when an agent needs JSON-safe intent for
|
|
248
|
+
logs, comparisons, approvals, or runtime handoff. Descriptions keep the same
|
|
249
|
+
generic action input, refs, commands, checks, changes, and ops, but omit
|
|
250
|
+
consumer-private `refs` object shape and helper functions such as
|
|
251
|
+
`table.column()`.
|
|
252
|
+
Use `describePlanResult` when the same JSON-safe handoff is needed for either
|
|
253
|
+
planned or failed action planning.
|
|
254
|
+
Use `describeRunResult` after execution when an agent needs the same JSON-safe
|
|
255
|
+
shape for `done` or `failed` run results. It preserves changed summaries,
|
|
256
|
+
checks, errors, and undo ops, but describes workbook refs without helper
|
|
257
|
+
functions such as `table.column()` or `rows.column()`.
|
|
258
|
+
Run errors use a stable `WorkbookRunErrorCode` union rather than arbitrary
|
|
259
|
+
strings. Use the frozen `workbookRunErrorCodes` list and `isWorkbookRunErrorCode`
|
|
260
|
+
guard when an adapter, logger, or approval layer needs to branch on known
|
|
261
|
+
failure classes. Runtime adapters should use `apply_failed` for apply
|
|
262
|
+
exceptions and `runtime_rejected` for intentional runtime refusal with a
|
|
263
|
+
specific message instead of inventing new public codes.
|
|
264
|
+
Planning and readback failures expose the same kind of boring machine contract:
|
|
265
|
+
use `workbookPlanIssueCodes` with `isWorkbookPlanIssueCode`, and
|
|
266
|
+
`workbookReadbackIssueCodes` with `isWorkbookReadbackIssueCode`, when an agent
|
|
267
|
+
needs to branch before or after runtime handoff without guessing string values.
|
|
268
|
+
Use `describeRuntimeRequirements(plan)` before runtime handoff when an agent
|
|
269
|
+
needs to inspect what the adapter must do. It returns a JSON-safe list of
|
|
270
|
+
generic `apply`, `read`, and `verify` requirements with boring capabilities
|
|
271
|
+
such as `writeFormula`, `writeValue`, `format`, `clear`, `applyOp`, `read`, and
|
|
272
|
+
`verifyCheck`. Apply requirements also say whether the command is already backed
|
|
273
|
+
by a concrete op, is a provided low-level op, or needs runtime materialization.
|
|
274
|
+
Every requirement has a stable `path` such as `commands[0]`, `checks[2]`, or
|
|
275
|
+
`ops[1]`; read requirements include the machine-readable expectation. It does
|
|
276
|
+
not execute anything and it does not import the engine.
|
|
277
|
+
|
|
278
|
+
Use `verifyPlan` before runtime handoff when an agent needs to prove a planned
|
|
279
|
+
action is internally consistent. It checks for non-JSON-safe action input,
|
|
280
|
+
unresolved refs, unparsable formulas, duplicate resolved refs, and missing
|
|
281
|
+
concrete ops for write, clear, and number-format commands that already target a
|
|
282
|
+
known single cell. Custom check targets and supporting refs must also resolve
|
|
283
|
+
through the model's `refsUsed` contract. Formula readback expectation inputs
|
|
284
|
+
must also resolve through `refsUsed`, and expectation formulas must be parseable.
|
|
285
|
+
Checks must start as `planned`; consumer code cannot mark a check passed or
|
|
286
|
+
failed before runtime proof.
|
|
287
|
+
Low-level `addOp` commands must contain valid `WorkbookOp` values, must still
|
|
288
|
+
appear in `plan.ops`, and must match their declared `target` when the op exposes
|
|
289
|
+
a concrete address or range.
|
|
290
|
+
Use `verifyModel` to plan and verify every action in a consumer-defined model
|
|
291
|
+
with one JSON-safe result. Pass `inputs` when specific actions require
|
|
292
|
+
parameters.
|
|
293
|
+
|
|
294
|
+
Use `runWorkbookPlan(plan, adapter)` or
|
|
295
|
+
`runWorkbookAction(model, actionName, adapter, input)` when an agent needs a
|
|
296
|
+
generic apply-and-prove loop. The adapter owns runtime execution and semantic
|
|
297
|
+
readback:
|
|
298
|
+
|
|
299
|
+
```ts
|
|
300
|
+
const result = await runWorkbookAction(model, 'write', {
|
|
301
|
+
apply(plan) {
|
|
302
|
+
return runtime.apply(plan.ops)
|
|
303
|
+
},
|
|
304
|
+
read(targets) {
|
|
305
|
+
return runtime.read(targets)
|
|
306
|
+
},
|
|
307
|
+
})
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
`runWorkbookAction` plans the action, runs `verifyPlan`, calls
|
|
311
|
+
optional `adapter.preview(plan)`, calls `adapter.apply(plan)`, then evaluates
|
|
312
|
+
`valueEquals`, `valuesEqual`, `formulaEquals`, and `formulasEqual` checks
|
|
313
|
+
against `adapter.read(targets, plan)`.
|
|
314
|
+
It never imports the engine, headless runtime, app server, or UI. If static
|
|
315
|
+
verification fails, the apply adapter is not called. If preview is available,
|
|
316
|
+
successful results include an `applied` summary with the materialized op count
|
|
317
|
+
and ops that the adapter preview produced. If a readback expectation is missing,
|
|
318
|
+
duplicated, or mismatched, the returned `WorkbookRunResult` is `failed` with
|
|
319
|
+
deterministic error codes such as `readback_missing`, `duplicate_readback`,
|
|
320
|
+
`value_mismatch`, `values_mismatch`, `formula_mismatch`, or
|
|
321
|
+
`formulas_mismatch`; errors preserve structured `path`, `target`, `check`,
|
|
322
|
+
`expected`, and `actual` fields where available.
|
|
323
|
+
Runtime outputs are validated too: malformed preview, apply, or readback
|
|
324
|
+
payloads fail as `invalid_runtime_result` instead of being treated as proof.
|
|
325
|
+
Formula readbacks are exact: adapters should return formula text in the same
|
|
326
|
+
normalized no-leading-`=` form produced by `formula.source`.
|
|
327
|
+
`adapter.apply` only applies the plan and may return an undo ref; it cannot
|
|
328
|
+
drop, replace, or prove checks.
|
|
329
|
+
Adapters provide `verifyChecks(checks, plan)` to prove non-readback checks such
|
|
330
|
+
as `exists`, `noFormulaErrors`, and consumer-defined `custom` invariants. The
|
|
331
|
+
verifier must return the same checks in the same order and may only change
|
|
332
|
+
`status`; changing `kind`, `target`, `refs`, `expectation`, or `message` fails
|
|
333
|
+
the run as `invalid_check_verification`. If any verified check is `failed`, the
|
|
334
|
+
run returns `failed` with `check_failed`. If any check remains `planned` after
|
|
335
|
+
readback and adapter verification, the run returns `failed` with
|
|
336
|
+
`check_not_verified`; `status: "done"` means every planned check has proof.
|
|
337
|
+
|
|
338
|
+
When running against Bilig's engine, use `createWorkbookRunAdapter(engine)` from
|
|
339
|
+
`@bilig/core`. The adapter materializes generic `plan.commands` into engine
|
|
340
|
+
operations, previews the exact materialized ops, applies additional `plan.ops`
|
|
341
|
+
that are not already represented by materialized commands, reads single-cell and
|
|
342
|
+
multi-cell expectation targets, and verifies generic `exists` and
|
|
343
|
+
`noFormulaErrors` checks
|
|
344
|
+
without adding workbook-specific business models to this package. If the engine
|
|
345
|
+
captures undo, the run result includes `undo.ops` in the same portable
|
|
346
|
+
operation language.
|
package/dist/check.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type LiteralInput } from '@bilig/protocol';
|
|
2
|
+
import type { WorkbookRef } from './find.js';
|
|
3
|
+
import { type WorkbookFormulaOperand } from './formula.js';
|
|
4
|
+
import type { WorkbookCheckResult } from './result.js';
|
|
5
|
+
export interface WorkbookCustomCheckOptions {
|
|
6
|
+
readonly kind: string;
|
|
7
|
+
readonly message: string;
|
|
8
|
+
readonly target?: WorkbookRef;
|
|
9
|
+
readonly refs?: readonly WorkbookRef[];
|
|
10
|
+
}
|
|
11
|
+
export interface WorkbookReadbackCheckOptions {
|
|
12
|
+
readonly message?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface WorkbookCheckApi {
|
|
15
|
+
readonly exists: (target: WorkbookRef) => WorkbookCheckResult;
|
|
16
|
+
readonly noFormulaErrors: (target: WorkbookRef) => WorkbookCheckResult;
|
|
17
|
+
readonly valueEquals: (target: WorkbookRef, value: LiteralInput, options?: WorkbookReadbackCheckOptions) => WorkbookCheckResult;
|
|
18
|
+
readonly valuesEqual: (target: WorkbookRef, values: readonly (readonly LiteralInput[])[], options?: WorkbookReadbackCheckOptions) => WorkbookCheckResult;
|
|
19
|
+
readonly formulaEquals: (target: WorkbookRef, value: WorkbookFormulaOperand, options?: WorkbookReadbackCheckOptions) => WorkbookCheckResult;
|
|
20
|
+
readonly formulasEqual: (target: WorkbookRef, formulas: readonly (readonly (string | null)[])[], options?: WorkbookReadbackCheckOptions) => WorkbookCheckResult;
|
|
21
|
+
readonly custom: (options: WorkbookCustomCheckOptions) => WorkbookCheckResult;
|
|
22
|
+
}
|
|
23
|
+
export declare function createWorkbookCheckResult(kind: string, target: WorkbookRef, message: string): WorkbookCheckResult;
|
|
24
|
+
export declare function createWorkbookCustomCheck(options: WorkbookCustomCheckOptions): WorkbookCheckResult;
|
|
25
|
+
export declare function createWorkbookCheckApi(record?: (check: WorkbookCheckResult) => void): WorkbookCheckApi;
|
|
26
|
+
export declare const check: WorkbookCheckApi;
|
package/dist/check.js
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { isLiteralInput } from '@bilig/protocol';
|
|
2
|
+
import { formula } from './formula.js';
|
|
3
|
+
export function createWorkbookCheckResult(kind, target, message) {
|
|
4
|
+
return createWorkbookCustomCheck({ kind, target, message });
|
|
5
|
+
}
|
|
6
|
+
function requiredText(value, name) {
|
|
7
|
+
const trimmed = value.trim();
|
|
8
|
+
if (trimmed === '') {
|
|
9
|
+
throw new Error(`Workbook check ${name} cannot be empty`);
|
|
10
|
+
}
|
|
11
|
+
return trimmed;
|
|
12
|
+
}
|
|
13
|
+
function checkedLiteralInput(value) {
|
|
14
|
+
if (!isLiteralInput(value)) {
|
|
15
|
+
throw new Error('Workbook readback value must be a finite JSON literal');
|
|
16
|
+
}
|
|
17
|
+
return value;
|
|
18
|
+
}
|
|
19
|
+
function checkedLiteralMatrix(values) {
|
|
20
|
+
if (!Array.isArray(values)) {
|
|
21
|
+
throw new Error('Workbook readback values must be an array of rows');
|
|
22
|
+
}
|
|
23
|
+
let width;
|
|
24
|
+
return Object.freeze(values.map((row, rowIndex) => {
|
|
25
|
+
if (!Array.isArray(row)) {
|
|
26
|
+
throw new Error(`Workbook readback values row ${rowIndex.toString()} must be an array`);
|
|
27
|
+
}
|
|
28
|
+
width ??= row.length;
|
|
29
|
+
if (row.length !== width) {
|
|
30
|
+
throw new Error('Workbook readback values must be rectangular');
|
|
31
|
+
}
|
|
32
|
+
return Object.freeze(row.map(checkedLiteralInput));
|
|
33
|
+
}));
|
|
34
|
+
}
|
|
35
|
+
function checkedFormulaMatrix(formulas) {
|
|
36
|
+
if (!Array.isArray(formulas)) {
|
|
37
|
+
throw new Error('Workbook readback formulas must be an array of rows');
|
|
38
|
+
}
|
|
39
|
+
let width;
|
|
40
|
+
return Object.freeze(formulas.map((row, rowIndex) => {
|
|
41
|
+
if (!Array.isArray(row)) {
|
|
42
|
+
throw new Error(`Workbook readback formulas row ${rowIndex.toString()} must be an array`);
|
|
43
|
+
}
|
|
44
|
+
width ??= row.length;
|
|
45
|
+
if (row.length !== width) {
|
|
46
|
+
throw new Error('Workbook readback formulas must be rectangular');
|
|
47
|
+
}
|
|
48
|
+
return Object.freeze(row.map((formulaText) => {
|
|
49
|
+
if (formulaText !== null && typeof formulaText !== 'string') {
|
|
50
|
+
throw new Error('Workbook readback formula must be a string or null');
|
|
51
|
+
}
|
|
52
|
+
return formulaText;
|
|
53
|
+
}));
|
|
54
|
+
}));
|
|
55
|
+
}
|
|
56
|
+
function refKey(ref) {
|
|
57
|
+
return `${ref.kind}:${ref.id}`;
|
|
58
|
+
}
|
|
59
|
+
function uniqueRefs(refs) {
|
|
60
|
+
if (refs === undefined) {
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
const seen = new Set();
|
|
64
|
+
const unique = [];
|
|
65
|
+
for (const ref of refs) {
|
|
66
|
+
const key = refKey(ref);
|
|
67
|
+
if (seen.has(key)) {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
seen.add(key);
|
|
71
|
+
unique.push(ref);
|
|
72
|
+
}
|
|
73
|
+
return unique.length === 0 ? undefined : unique;
|
|
74
|
+
}
|
|
75
|
+
function createWorkbookCheck(options) {
|
|
76
|
+
const refs = uniqueRefs(options.refs);
|
|
77
|
+
return {
|
|
78
|
+
status: 'planned',
|
|
79
|
+
kind: requiredText(options.kind, 'kind'),
|
|
80
|
+
...(options.target !== undefined ? { target: options.target } : {}),
|
|
81
|
+
...(refs !== undefined ? { refs } : {}),
|
|
82
|
+
message: requiredText(options.message, 'message'),
|
|
83
|
+
...(options.expectation !== undefined ? { expectation: options.expectation } : {}),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
export function createWorkbookCustomCheck(options) {
|
|
87
|
+
return createWorkbookCheck(options);
|
|
88
|
+
}
|
|
89
|
+
export function createWorkbookCheckApi(record) {
|
|
90
|
+
function planned(options) {
|
|
91
|
+
const check = createWorkbookCheck(options);
|
|
92
|
+
record?.(check);
|
|
93
|
+
return check;
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
exists(target) {
|
|
97
|
+
return planned({ kind: 'exists', target, message: `${target.label} exists` });
|
|
98
|
+
},
|
|
99
|
+
noFormulaErrors(target) {
|
|
100
|
+
return planned({ kind: 'noFormulaErrors', target, message: `${target.label} has no formula errors` });
|
|
101
|
+
},
|
|
102
|
+
valueEquals(target, value, options = {}) {
|
|
103
|
+
const expected = checkedLiteralInput(value);
|
|
104
|
+
return planned({
|
|
105
|
+
kind: 'valueEquals',
|
|
106
|
+
target,
|
|
107
|
+
message: options.message ?? `${target.label} equals ${JSON.stringify(expected)}`,
|
|
108
|
+
expectation: {
|
|
109
|
+
kind: 'valueEquals',
|
|
110
|
+
value: expected,
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
},
|
|
114
|
+
valuesEqual(target, values, options = {}) {
|
|
115
|
+
const expected = checkedLiteralMatrix(values);
|
|
116
|
+
return planned({
|
|
117
|
+
kind: 'valuesEqual',
|
|
118
|
+
target,
|
|
119
|
+
message: options.message ?? `${target.label} values equal ${JSON.stringify(expected)}`,
|
|
120
|
+
expectation: {
|
|
121
|
+
kind: 'valuesEqual',
|
|
122
|
+
values: expected,
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
},
|
|
126
|
+
formulaEquals(target, value, options = {}) {
|
|
127
|
+
const source = formula.source(value);
|
|
128
|
+
const inputs = formula.inputs(value);
|
|
129
|
+
return planned({
|
|
130
|
+
kind: 'formulaEquals',
|
|
131
|
+
target,
|
|
132
|
+
message: options.message ?? `${target.label} formula equals ${source}`,
|
|
133
|
+
expectation: {
|
|
134
|
+
kind: 'formulaEquals',
|
|
135
|
+
formula: source,
|
|
136
|
+
inputs,
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
},
|
|
140
|
+
formulasEqual(target, formulas, options = {}) {
|
|
141
|
+
const expected = checkedFormulaMatrix(formulas);
|
|
142
|
+
return planned({
|
|
143
|
+
kind: 'formulasEqual',
|
|
144
|
+
target,
|
|
145
|
+
message: options.message ?? `${target.label} formulas equal ${JSON.stringify(expected)}`,
|
|
146
|
+
expectation: {
|
|
147
|
+
kind: 'formulasEqual',
|
|
148
|
+
formulas: expected,
|
|
149
|
+
},
|
|
150
|
+
});
|
|
151
|
+
},
|
|
152
|
+
custom(options) {
|
|
153
|
+
return planned(options);
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
export const check = createWorkbookCheckApi();
|
|
158
|
+
//# sourceMappingURL=check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.js","sourceRoot":"","sources":["../src/check.ts"],"names":[],"mappings":"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"}
|