@bilig/workbook 0.107.8 → 0.119.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.
Files changed (77) hide show
  1. package/README.md +39 -38
  2. package/dist/check.js +4 -1
  3. package/dist/check.js.map +1 -1
  4. package/dist/command-bundle.js +18 -3
  5. package/dist/command-bundle.js.map +1 -1
  6. package/dist/command-ops.js +93 -40
  7. package/dist/command-ops.js.map +1 -1
  8. package/dist/command-ranges.js +5 -1
  9. package/dist/command-ranges.js.map +1 -1
  10. package/dist/command-receipt-ranges.js +5 -1
  11. package/dist/command-receipt-ranges.js.map +1 -1
  12. package/dist/command-result-undo.js +6 -2
  13. package/dist/command-result-undo.js.map +1 -1
  14. package/dist/command-result.js +26 -3
  15. package/dist/command-result.js.map +1 -1
  16. package/dist/data-properties.d.ts +1 -0
  17. package/dist/data-properties.js +3 -0
  18. package/dist/data-properties.js.map +1 -1
  19. package/dist/describe.d.ts +6 -0
  20. package/dist/describe.js +10 -0
  21. package/dist/describe.js.map +1 -1
  22. package/dist/feature-plugin.d.ts +7 -1
  23. package/dist/feature-plugin.js +23 -1
  24. package/dist/feature-plugin.js.map +1 -1
  25. package/dist/features.d.ts +0 -6
  26. package/dist/features.js +17 -26
  27. package/dist/features.js.map +1 -1
  28. package/dist/find.js +94 -103
  29. package/dist/find.js.map +1 -1
  30. package/dist/formula.js +5 -2
  31. package/dist/formula.js.map +1 -1
  32. package/dist/index.d.ts +0 -1
  33. package/dist/index.js +0 -1
  34. package/dist/index.js.map +1 -1
  35. package/dist/model-action-validation.d.ts +2 -0
  36. package/dist/model-action-validation.js +71 -3
  37. package/dist/model-action-validation.js.map +1 -1
  38. package/dist/model.js +4 -1
  39. package/dist/model.js.map +1 -1
  40. package/dist/op-schema.js +555 -25
  41. package/dist/op-schema.js.map +1 -1
  42. package/dist/plan-data.js +184 -51
  43. package/dist/plan-data.js.map +1 -1
  44. package/dist/readback.js +44 -1
  45. package/dist/readback.js.map +1 -1
  46. package/dist/requirements.js +41 -3
  47. package/dist/requirements.js.map +1 -1
  48. package/dist/result.d.ts +7 -0
  49. package/dist/result.js.map +1 -1
  50. package/dist/run-apply.js +5 -2
  51. package/dist/run-apply.js.map +1 -1
  52. package/dist/run-command-receipts.js +133 -3
  53. package/dist/run-command-receipts.js.map +1 -1
  54. package/dist/run-data.js +6 -2
  55. package/dist/run-data.js.map +1 -1
  56. package/dist/run-description-noop.d.ts +2 -0
  57. package/dist/run-description-noop.js +330 -0
  58. package/dist/run-description-noop.js.map +1 -0
  59. package/dist/run-description.js +23 -2
  60. package/dist/run-description.js.map +1 -1
  61. package/dist/run-runtime-boundary.js +39 -5
  62. package/dist/run-runtime-boundary.js.map +1 -1
  63. package/dist/run.d.ts +1 -0
  64. package/dist/run.js.map +1 -1
  65. package/dist/schema-fragments.d.ts +16 -0
  66. package/dist/schema-fragments.js +246 -0
  67. package/dist/schema-fragments.js.map +1 -0
  68. package/dist/schema-noop.d.ts +9 -0
  69. package/dist/schema-noop.js +128 -0
  70. package/dist/schema-noop.js.map +1 -0
  71. package/dist/schema.js +227 -130
  72. package/dist/schema.js.map +1 -1
  73. package/dist/testing.js +19 -4
  74. package/dist/testing.js.map +1 -1
  75. package/dist/verify.js +34 -0
  76. package/dist/verify.js.map +1 -1
  77. package/package.json +12 -5
@@ -0,0 +1,128 @@
1
+ import { workbookOpSchema } from './op-schema.js';
2
+ const noopEffectCommandKinds = Object.freeze(['writeValue', 'writeFormula', 'clear', 'format', 'op']);
3
+ function isSchemaObject(value) {
4
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
5
+ }
6
+ function schemaConstKind(value) {
7
+ if (!isSchemaObject(value)) {
8
+ return undefined;
9
+ }
10
+ const properties = value['properties'];
11
+ if (!isSchemaObject(properties)) {
12
+ return undefined;
13
+ }
14
+ const kind = properties['kind'];
15
+ if (!isSchemaObject(kind)) {
16
+ return undefined;
17
+ }
18
+ const kindConst = kind['const'];
19
+ return typeof kindConst === 'string' ? kindConst : undefined;
20
+ }
21
+ function opNoopEffectSchemas(refs) {
22
+ if (!isSchemaObject(workbookOpSchema) || !Array.isArray(workbookOpSchema['oneOf'])) {
23
+ return [
24
+ {
25
+ type: 'object',
26
+ required: ['kind', 'opKind', 'op'],
27
+ additionalProperties: true,
28
+ properties: {
29
+ kind: { const: 'op' },
30
+ opKind: refs.exactString,
31
+ op: refs.engineOp,
32
+ },
33
+ },
34
+ ];
35
+ }
36
+ return workbookOpSchema['oneOf'].map((opSchema) => {
37
+ const opKind = schemaConstKind(opSchema);
38
+ return {
39
+ type: 'object',
40
+ required: ['kind', 'opKind', 'op'],
41
+ additionalProperties: true,
42
+ properties: {
43
+ kind: { const: 'op' },
44
+ opKind: opKind === undefined ? refs.exactString : { const: opKind },
45
+ op: opSchema,
46
+ },
47
+ };
48
+ });
49
+ }
50
+ function noopEffectCommandKindCondition(commandKind) {
51
+ return {
52
+ if: {
53
+ required: ['commandKind', 'noop'],
54
+ properties: {
55
+ commandKind: { const: commandKind },
56
+ },
57
+ },
58
+ // oxlint-disable-next-line eslint-plugin-unicorn(no-thenable) -- JSON Schema conditional schemas use the standard "then" keyword.
59
+ then: {
60
+ properties: {
61
+ noop: {
62
+ properties: {
63
+ proof: {
64
+ properties: {
65
+ commandKind: { const: commandKind },
66
+ effect: {
67
+ required: ['kind'],
68
+ properties: {
69
+ kind: { const: commandKind },
70
+ },
71
+ },
72
+ },
73
+ },
74
+ },
75
+ },
76
+ },
77
+ },
78
+ };
79
+ }
80
+ export function createNoopEffectSchema(refs) {
81
+ return {
82
+ oneOf: [
83
+ {
84
+ type: 'object',
85
+ required: ['kind', 'value'],
86
+ additionalProperties: true,
87
+ properties: {
88
+ kind: { const: 'writeValue' },
89
+ value: refs.literalInput,
90
+ },
91
+ },
92
+ {
93
+ type: 'object',
94
+ required: ['kind', 'formula'],
95
+ additionalProperties: true,
96
+ properties: {
97
+ kind: { const: 'writeFormula' },
98
+ formula: { type: 'string', minLength: 1 },
99
+ },
100
+ },
101
+ {
102
+ type: 'object',
103
+ required: ['kind', 'cleared'],
104
+ additionalProperties: true,
105
+ properties: {
106
+ kind: { const: 'clear' },
107
+ cleared: { const: true },
108
+ },
109
+ },
110
+ {
111
+ type: 'object',
112
+ required: ['kind'],
113
+ additionalProperties: true,
114
+ properties: {
115
+ kind: { const: 'format' },
116
+ style: refs.actionCellStylePatch,
117
+ numberFormat: { oneOf: [{ type: 'string' }, { type: 'null' }] },
118
+ },
119
+ anyOf: [{ required: ['style'] }, { required: ['numberFormat'] }],
120
+ },
121
+ ...opNoopEffectSchemas(refs),
122
+ ],
123
+ };
124
+ }
125
+ export function noopEffectCommandKindConditions() {
126
+ return noopEffectCommandKinds.map(noopEffectCommandKindCondition);
127
+ }
128
+ //# sourceMappingURL=schema-noop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-noop.js","sourceRoot":"","sources":["../src/schema-noop.ts"],"names":[],"mappings":"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"}
package/dist/schema.js CHANGED
@@ -1,6 +1,8 @@
1
1
  import { workbookRunErrorCodes } from './result.js';
2
2
  import { workbookActionInputDescriptionKinds } from './input.js';
3
3
  import { cellStylePatchSchema, literalInputSchema, workbookOpSchema } from './op-schema.js';
4
+ import { workbookActionCellStylePatchSchema, workbookCommandReceiptSchema, workbookRefDataDefSchemas, workbookRefDataSchemaRefs, workbookUndoRefSchema, } from './schema-fragments.js';
5
+ import { createNoopEffectSchema, noopEffectCommandKindConditions } from './schema-noop.js';
4
6
  export const workbookJsonSchemaVersion = 'bilig-workbook-json-schema-v1';
5
7
  export const workbookJsonSchemaNames = Object.freeze([
6
8
  'refData',
@@ -19,6 +21,16 @@ const cellRange = Object.freeze({ $ref: '#/$defs/cellRange' });
19
21
  const engineOp = Object.freeze({ $ref: '#/$defs/engineOp' });
20
22
  const actionInput = Object.freeze({ $ref: '#/$defs/actionInput' });
21
23
  const actionInputDescription = Object.freeze({ $ref: '#/$defs/actionInputDescription' });
24
+ const exactString = Object.freeze({
25
+ type: 'string',
26
+ minLength: 1,
27
+ pattern: '^(?!\\s)(?![\\s\\S]*\\s$)[\\s\\S]+$',
28
+ });
29
+ const nonNegativeSafeInteger = Object.freeze({
30
+ type: 'integer',
31
+ minimum: 0,
32
+ maximum: Number.MAX_SAFE_INTEGER,
33
+ });
22
34
  function defs(extra = {}) {
23
35
  return {
24
36
  jsonValue: {
@@ -50,11 +62,11 @@ function defs(extra = {}) {
50
62
  values: { type: 'array', minItems: 1, items: actionInput },
51
63
  min: { type: 'number' },
52
64
  max: { type: 'number' },
53
- minLength: { type: 'integer', minimum: 0 },
54
- maxLength: { type: 'integer', minimum: 0 },
65
+ minLength: nonNegativeSafeInteger,
66
+ maxLength: nonNegativeSafeInteger,
55
67
  pattern: { type: 'string' },
56
- minItems: { type: 'integer', minimum: 0 },
57
- maxItems: { type: 'integer', minimum: 0 },
68
+ minItems: nonNegativeSafeInteger,
69
+ maxItems: nonNegativeSafeInteger,
58
70
  additionalProperties: { type: 'boolean' },
59
71
  default: actionInput,
60
72
  examples: { type: 'array', minItems: 1, items: actionInput },
@@ -97,6 +109,7 @@ function defs(extra = {}) {
97
109
  },
98
110
  },
99
111
  cellStylePatch: cellStylePatchSchema,
112
+ actionCellStylePatch: workbookActionCellStylePatchSchema,
100
113
  formulaLabel: {
101
114
  type: 'object',
102
115
  required: ['name', 'ref'],
@@ -107,79 +120,9 @@ function defs(extra = {}) {
107
120
  },
108
121
  },
109
122
  engineOp: workbookOpSchema,
123
+ ...workbookRefDataDefSchemas,
110
124
  refData: {
111
- oneOf: [
112
- {
113
- type: 'object',
114
- required: ['kind', 'id', 'label', 'range'],
115
- additionalProperties: false,
116
- properties: {
117
- kind: { const: 'range' },
118
- id: { type: 'string', minLength: 1 },
119
- label: { type: 'string', minLength: 1 },
120
- range: { $ref: '#/$defs/cellRange' },
121
- },
122
- },
123
- {
124
- type: 'object',
125
- required: ['kind', 'id', 'label', 'name'],
126
- additionalProperties: false,
127
- properties: {
128
- kind: { const: 'name' },
129
- id: { type: 'string', minLength: 1 },
130
- label: { type: 'string', minLength: 1 },
131
- name: { type: 'string', minLength: 1 },
132
- },
133
- },
134
- {
135
- type: 'object',
136
- required: ['kind', 'id', 'label'],
137
- additionalProperties: false,
138
- properties: {
139
- kind: { const: 'table' },
140
- id: { type: 'string', minLength: 1 },
141
- label: { type: 'string', minLength: 1 },
142
- name: { type: 'string', minLength: 1 },
143
- sheetName: { type: 'string', minLength: 1 },
144
- headers: { type: 'array', items: { type: 'string' } },
145
- },
146
- },
147
- {
148
- type: 'object',
149
- required: ['kind', 'id', 'label', 'table', 'name'],
150
- additionalProperties: false,
151
- properties: {
152
- kind: { const: 'column' },
153
- id: { type: 'string', minLength: 1 },
154
- label: { type: 'string', minLength: 1 },
155
- table: { $ref: '#/$defs/refData' },
156
- rows: { $ref: '#/$defs/refData' },
157
- name: { type: 'string', minLength: 1 },
158
- },
159
- },
160
- {
161
- type: 'object',
162
- required: ['kind', 'id', 'label', 'where'],
163
- additionalProperties: false,
164
- properties: {
165
- kind: { const: 'rows' },
166
- id: { type: 'string', minLength: 1 },
167
- label: { type: 'string', minLength: 1 },
168
- sheetName: { type: 'string', minLength: 1 },
169
- table: { $ref: '#/$defs/refData' },
170
- where: {
171
- type: 'object',
172
- required: ['column', 'op', 'value'],
173
- additionalProperties: false,
174
- properties: {
175
- column: { type: 'string', minLength: 1 },
176
- op: { enum: ['eq', 'neq', 'contains', 'startsWith', 'gt', 'gte', 'lt', 'lte'] },
177
- value: { $ref: '#/$defs/jsonValue' },
178
- },
179
- },
180
- },
181
- },
182
- ],
125
+ oneOf: workbookRefDataSchemaRefs,
183
126
  },
184
127
  concreteRefData: {
185
128
  type: 'object',
@@ -262,15 +205,6 @@ const changeDataSchema = {
262
205
  message: { type: 'string', minLength: 1 },
263
206
  },
264
207
  };
265
- const undoDataSchema = {
266
- type: 'object',
267
- required: ['id'],
268
- additionalProperties: false,
269
- properties: {
270
- id: { type: 'string', minLength: 1 },
271
- ops: { type: 'array', items: engineOp },
272
- },
273
- };
274
208
  const unverifiedDataSchema = {
275
209
  type: 'object',
276
210
  required: ['kind', 'message'],
@@ -287,9 +221,9 @@ const runtimeRequirementSchema = {
287
221
  properties: {
288
222
  kind: { enum: ['apply', 'read', 'verify'] },
289
223
  capability: { enum: ['writeFormula', 'writeValue', 'format', 'clear', 'applyOp', 'read', 'verifyCheck'] },
290
- commandIndex: { type: 'integer', minimum: 0 },
291
- checkIndex: { type: 'integer', minimum: 0 },
292
- opIndex: { type: 'integer', minimum: 0 },
224
+ commandIndex: nonNegativeSafeInteger,
225
+ checkIndex: nonNegativeSafeInteger,
226
+ opIndex: nonNegativeSafeInteger,
293
227
  opKind: { type: 'string', minLength: 1 },
294
228
  checkKind: { type: 'string', minLength: 1 },
295
229
  target: refData,
@@ -321,8 +255,8 @@ const applySummarySchema = {
321
255
  properties: {
322
256
  matched: { oneOf: [{ type: 'boolean' }, { type: 'null' }] },
323
257
  planId: { type: 'string', minLength: 1 },
324
- baseRevision: { type: 'integer', minimum: 0 },
325
- revision: { type: 'integer', minimum: 0 },
258
+ baseRevision: nonNegativeSafeInteger,
259
+ revision: nonNegativeSafeInteger,
326
260
  previewOps: { type: 'array', items: engineOp },
327
261
  appliedOps: { type: 'array', items: engineOp },
328
262
  commandReceipts: { type: 'array', items: { $ref: '#/$defs/applyCommandReceipt' } },
@@ -334,11 +268,33 @@ const applyCommandReceiptSchema = {
334
268
  required: ['commandIndex', 'commandKind', 'commandDigest', 'previewOps', 'appliedOps'],
335
269
  additionalProperties: false,
336
270
  properties: {
337
- commandIndex: { type: 'integer', minimum: 0 },
271
+ commandIndex: nonNegativeSafeInteger,
338
272
  commandKind: { type: 'string', minLength: 1 },
339
273
  commandDigest: { type: 'string', minLength: 1 },
340
274
  previewOps: { type: 'array', items: engineOp },
341
275
  appliedOps: { type: 'array', items: engineOp },
276
+ noop: {
277
+ type: 'object',
278
+ required: ['reason', 'proof'],
279
+ additionalProperties: false,
280
+ properties: {
281
+ reason: { enum: ['already_satisfied'] },
282
+ message: { type: 'string', minLength: 1 },
283
+ proof: {
284
+ type: 'object',
285
+ required: ['source', 'evidence', 'opCount', 'commandKind', 'commandDigest', 'effect'],
286
+ additionalProperties: true,
287
+ properties: {
288
+ source: exactString,
289
+ evidence: exactString,
290
+ opCount: { const: 0 },
291
+ commandKind: exactString,
292
+ commandDigest: exactString,
293
+ effect: { $ref: '#/$defs/noopEffect' },
294
+ },
295
+ },
296
+ },
297
+ },
342
298
  resolvedRefs: { $ref: '#/$defs/commandResolvedRefs' },
343
299
  formulaLabels: {
344
300
  type: 'array',
@@ -354,6 +310,19 @@ const applyCommandReceiptSchema = {
354
310
  },
355
311
  proof: actionInput,
356
312
  },
313
+ allOf: [
314
+ {
315
+ if: { required: ['noop'] },
316
+ // oxlint-disable-next-line eslint-plugin-unicorn(no-thenable) -- JSON Schema conditional schemas use the standard "then" keyword.
317
+ then: {
318
+ properties: {
319
+ previewOps: { type: 'array', maxItems: 0, items: engineOp },
320
+ appliedOps: { type: 'array', maxItems: 0, items: engineOp },
321
+ },
322
+ },
323
+ },
324
+ ...noopEffectCommandKindConditions(),
325
+ ],
357
326
  };
358
327
  export const workbookJsonSchemas = deepFreeze({
359
328
  refData: schema('refData', {
@@ -415,9 +384,10 @@ export const workbookJsonSchemas = deepFreeze({
415
384
  properties: {
416
385
  kind: { const: 'format' },
417
386
  target: refData,
418
- style: { $ref: '#/$defs/cellStylePatch' },
387
+ style: { $ref: '#/$defs/actionCellStylePatch' },
419
388
  numberFormat: { oneOf: [{ type: 'string' }, { type: 'null' }] },
420
389
  },
390
+ anyOf: [{ required: ['style'] }, { required: ['numberFormat'] }],
421
391
  },
422
392
  {
423
393
  type: 'object',
@@ -474,8 +444,8 @@ export const workbookJsonSchemas = deepFreeze({
474
444
  required: ['featureId', 'commandId'],
475
445
  additionalProperties: false,
476
446
  properties: {
477
- featureId: { type: 'string', minLength: 1 },
478
- commandId: { type: 'string', minLength: 1 },
447
+ featureId: exactString,
448
+ commandId: exactString,
479
449
  category: { enum: ['command', 'operation', 'mutation'] },
480
450
  mode: { enum: ['preview', 'apply', 'applyAndVerify'] },
481
451
  input: actionInput,
@@ -489,21 +459,57 @@ export const workbookJsonSchemas = deepFreeze({
489
459
  additionalProperties: false,
490
460
  properties: {
491
461
  kind: { const: 'request' },
492
- id: { type: 'string', minLength: 1 },
462
+ id: exactString,
493
463
  touchedRanges: { type: 'array', items: cellRange },
494
464
  destructive: { type: 'boolean' },
495
465
  request: { $ref: '#/$defs/commandRequest' },
496
466
  },
467
+ allOf: [
468
+ {
469
+ if: {
470
+ properties: {
471
+ request: {
472
+ type: 'object',
473
+ properties: { category: { const: 'mutation' } },
474
+ required: ['category'],
475
+ },
476
+ },
477
+ required: ['request'],
478
+ },
479
+ // oxlint-disable-next-line eslint-plugin-unicorn(no-thenable) -- JSON Schema conditional schemas use the standard "then" keyword.
480
+ then: {
481
+ required: ['destructive'],
482
+ properties: { destructive: { const: true } },
483
+ },
484
+ },
485
+ {
486
+ if: {
487
+ properties: {
488
+ request: {
489
+ type: 'object',
490
+ properties: { mode: { enum: ['apply', 'applyAndVerify'] } },
491
+ required: ['mode'],
492
+ },
493
+ },
494
+ required: ['request'],
495
+ },
496
+ // oxlint-disable-next-line eslint-plugin-unicorn(no-thenable) -- JSON Schema conditional schemas use the standard "then" keyword.
497
+ then: {
498
+ required: ['destructive'],
499
+ properties: { destructive: { const: true } },
500
+ },
501
+ },
502
+ ],
497
503
  },
498
504
  {
499
505
  type: 'object',
500
- required: ['kind', 'op'],
506
+ required: ['kind', 'destructive', 'op'],
501
507
  additionalProperties: false,
502
508
  properties: {
503
509
  kind: { const: 'op' },
504
- id: { type: 'string', minLength: 1 },
510
+ id: exactString,
505
511
  touchedRanges: { type: 'array', items: cellRange },
506
- destructive: { type: 'boolean' },
512
+ destructive: { const: true },
507
513
  op: engineOp,
508
514
  },
509
515
  },
@@ -514,60 +520,151 @@ export const workbookJsonSchemas = deepFreeze({
514
520
  required: ['targetRevision', 'idempotencyKey', 'commands'],
515
521
  additionalProperties: false,
516
522
  properties: {
517
- id: { type: 'string', minLength: 1 },
518
- targetRevision: { type: 'integer', minimum: 0 },
519
- idempotencyKey: { type: 'string', minLength: 1 },
523
+ id: exactString,
524
+ targetRevision: nonNegativeSafeInteger,
525
+ idempotencyKey: exactString,
520
526
  scope: {
521
527
  type: 'object',
522
528
  additionalProperties: false,
523
- properties: { maxTouchedCells: { type: 'integer', minimum: 0 } },
529
+ properties: { maxTouchedCells: nonNegativeSafeInteger },
524
530
  },
525
531
  commands: { type: 'array', minItems: 1, items: { $ref: '#/$defs/bundleCommand' } },
526
532
  },
533
+ allOf: [
534
+ {
535
+ if: {
536
+ properties: {
537
+ scope: {
538
+ type: 'object',
539
+ required: ['maxTouchedCells'],
540
+ },
541
+ },
542
+ required: ['scope'],
543
+ },
544
+ // oxlint-disable-next-line eslint-plugin-unicorn(no-thenable) -- JSON Schema conditional schemas use the standard "then" keyword.
545
+ then: {
546
+ properties: {
547
+ commands: {
548
+ items: {
549
+ allOf: [
550
+ {
551
+ if: {
552
+ properties: { kind: { const: 'op' } },
553
+ required: ['kind'],
554
+ },
555
+ // oxlint-disable-next-line eslint-plugin-unicorn(no-thenable) -- JSON Schema conditional schemas use the standard "then" keyword.
556
+ then: {
557
+ required: ['touchedRanges'],
558
+ properties: { touchedRanges: { type: 'array', minItems: 1, items: cellRange } },
559
+ },
560
+ },
561
+ {
562
+ if: {
563
+ properties: {
564
+ kind: { const: 'request' },
565
+ request: {
566
+ type: 'object',
567
+ properties: { category: { const: 'mutation' } },
568
+ required: ['category'],
569
+ },
570
+ },
571
+ required: ['kind', 'request'],
572
+ },
573
+ // oxlint-disable-next-line eslint-plugin-unicorn(no-thenable) -- JSON Schema conditional schemas use the standard "then" keyword.
574
+ then: {
575
+ required: ['touchedRanges'],
576
+ properties: { touchedRanges: { type: 'array', minItems: 1, items: cellRange } },
577
+ },
578
+ },
579
+ {
580
+ if: {
581
+ properties: {
582
+ kind: { const: 'request' },
583
+ request: {
584
+ type: 'object',
585
+ properties: { mode: { enum: ['apply', 'applyAndVerify'] } },
586
+ required: ['mode'],
587
+ },
588
+ },
589
+ required: ['kind', 'request'],
590
+ },
591
+ // oxlint-disable-next-line eslint-plugin-unicorn(no-thenable) -- JSON Schema conditional schemas use the standard "then" keyword.
592
+ then: {
593
+ required: ['touchedRanges'],
594
+ properties: { touchedRanges: { type: 'array', minItems: 1, items: cellRange } },
595
+ },
596
+ },
597
+ ],
598
+ },
599
+ },
600
+ },
601
+ },
602
+ },
603
+ ],
527
604
  }),
528
605
  commandResult: schema('commandResult', {
529
606
  $defs: defs({
530
- receipt: {
531
- type: 'object',
532
- required: ['status', 'featureId', 'commandId', 'category'],
533
- properties: {
534
- status: { enum: ['previewed', 'applied', 'rejected', 'noop'] },
535
- featureId: { type: 'string', minLength: 1 },
536
- commandId: { type: 'string', minLength: 1 },
537
- category: { enum: ['command', 'operation', 'mutation'] },
538
- previewOps: { type: 'array', items: engineOp },
539
- appliedOps: { type: 'array', items: engineOp },
540
- undo: { type: 'object', additionalProperties: true },
541
- changedRanges: { type: 'array', items: cellRange },
542
- proof: actionInput,
543
- message: { type: 'string' },
544
- metadata: actionInput,
545
- errors: { type: 'array', items: { type: 'string' } },
546
- },
547
- additionalProperties: false,
548
- },
607
+ undo: workbookUndoRefSchema,
608
+ receipt: workbookCommandReceiptSchema,
549
609
  }),
550
610
  type: 'object',
551
611
  required: ['status', 'targetRevision', 'idempotencyKey', 'commandCount', 'touchedRanges', 'touchedCellCount'],
552
612
  additionalProperties: false,
553
613
  properties: {
554
614
  status: { enum: ['accepted', 'previewed', 'applied', 'rejected', 'noop'] },
555
- bundleId: { type: 'string', minLength: 1 },
556
- targetRevision: { type: 'integer', minimum: 0 },
557
- idempotencyKey: { type: 'string', minLength: 1 },
558
- commandCount: { type: 'integer', minimum: 0 },
615
+ bundleId: exactString,
616
+ targetRevision: nonNegativeSafeInteger,
617
+ idempotencyKey: exactString,
618
+ commandCount: nonNegativeSafeInteger,
559
619
  touchedRanges: { type: 'array', items: cellRange },
560
- touchedCellCount: { type: 'integer', minimum: 0 },
620
+ touchedCellCount: nonNegativeSafeInteger,
561
621
  receipts: { type: 'array', items: { $ref: '#/$defs/receipt' } },
562
622
  matched: { oneOf: [{ type: 'boolean' }, { type: 'null' }] },
563
623
  changedRanges: { type: 'array', items: cellRange },
564
- revision: { type: 'integer', minimum: 0 },
565
- undo: { type: 'object', additionalProperties: true },
566
- errors: { type: 'array', items: { type: 'string' } },
624
+ revision: nonNegativeSafeInteger,
625
+ undo: { $ref: '#/$defs/undo' },
626
+ errors: { type: 'array', items: exactString },
567
627
  },
628
+ allOf: [
629
+ {
630
+ if: { properties: { status: { const: 'accepted' } }, required: ['status'] },
631
+ // oxlint-disable-next-line eslint-plugin-unicorn(no-thenable) -- JSON Schema conditional schemas use the standard "then" keyword.
632
+ then: {
633
+ not: {
634
+ anyOf: [
635
+ { required: ['receipts'] },
636
+ { required: ['matched'] },
637
+ { required: ['changedRanges'] },
638
+ { required: ['revision'] },
639
+ { required: ['undo'] },
640
+ { required: ['errors'] },
641
+ ],
642
+ },
643
+ },
644
+ },
645
+ {
646
+ if: {
647
+ properties: { status: { enum: ['previewed', 'applied', 'rejected', 'noop'] } },
648
+ required: ['status'],
649
+ },
650
+ // oxlint-disable-next-line eslint-plugin-unicorn(no-thenable) -- JSON Schema conditional schemas use the standard "then" keyword.
651
+ then: {
652
+ required: ['receipts', 'matched', 'changedRanges'],
653
+ properties: {
654
+ receipts: { type: 'array', minItems: 1, items: { $ref: '#/$defs/receipt' } },
655
+ },
656
+ },
657
+ },
658
+ ],
568
659
  }),
569
660
  runResult: schema('runResult', {
570
661
  $defs: defs({
662
+ noopEffect: createNoopEffectSchema({
663
+ literalInput,
664
+ exactString,
665
+ engineOp,
666
+ actionCellStylePatch: { $ref: '#/$defs/actionCellStylePatch' },
667
+ }),
571
668
  checkExpectation: checkExpectationSchema,
572
669
  apply: applySummarySchema,
573
670
  applyCommandReceipt: applyCommandReceiptSchema,
@@ -584,7 +681,7 @@ export const workbookJsonSchemas = deepFreeze({
584
681
  issueCode: { type: 'string' },
585
682
  },
586
683
  },
587
- undo: undoDataSchema,
684
+ undo: workbookUndoRefSchema,
588
685
  unverified: unverifiedDataSchema,
589
686
  }),
590
687
  oneOf: [