@adobe/data-ai 0.10.2 → 0.10.6
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.
|
@@ -195,7 +195,7 @@ export const createTodo = (
|
|
|
195
195
|
return { entities: new Map(state.entities).set(id, { name, complete: false, order }) };
|
|
196
196
|
};
|
|
197
197
|
|
|
198
|
-
export const cases = Conformance.cases(createTodo,
|
|
198
|
+
export const cases = /*@__PURE__*/ Conformance.cases(createTodo,
|
|
199
199
|
{ name: "adds the first todo",
|
|
200
200
|
before: {}, // empty delta — the default State.create() (empty entities)
|
|
201
201
|
args: { name: "a", analytics: AnalyticsService.createFake() },
|
|
@@ -217,7 +217,10 @@ export const cases = Conformance.cases(createTodo,
|
|
|
217
217
|
injected service, etc. into it, never as a third positional. A transition that takes
|
|
218
218
|
**no** args omits `args` from each case entirely (the shared `Case` type makes
|
|
219
219
|
`args` optional exactly then). **Guard no-ops by returning an empty patch `{}`**
|
|
220
|
-
(or the unchanged slice), never throw
|
|
220
|
+
(or the unchanged slice), never throw for an ordinary "nothing to do here"
|
|
221
|
+
condition. Reserve `throw` for a genuine precondition violation the case wants
|
|
222
|
+
to name (see "A case that expects a throw" below) — the rare exception, not the
|
|
223
|
+
default guard style.
|
|
221
224
|
- **A composer merges sub-patches explicitly.** A transition built from smaller
|
|
222
225
|
ones spreads them — `return { ...s, ...sub(s) }` — so each sub-patch's writes
|
|
223
226
|
layer in; a transition that merely **delegates** to one sub-transition returns
|
|
@@ -227,6 +230,22 @@ export const cases = Conformance.cases(createTodo,
|
|
|
227
230
|
any barrel member) in a top-level `cases` literal dead-locks the import cycle.
|
|
228
231
|
Import the concrete helper directly (`import { create } from "./create.js"`) or
|
|
229
232
|
inline full-`State` literals.
|
|
233
|
+
- **Always write the call as `/*@__PURE__*/ Conformance.cases(fn, …)`** (same for
|
|
234
|
+
`Conformance.derivations`) — the annotation is not optional style, it is what
|
|
235
|
+
makes the co-location safe. `@adobe/data-testing`'s `sideEffects: false` only
|
|
236
|
+
lets a bundler drop an unused *import* of the package; `Conformance.cases(fn,
|
|
237
|
+
…)` is still an ordinary function call happening in *this* file, and an
|
|
238
|
+
unannotated call is conservatively kept even when the `cases` export it
|
|
239
|
+
initializes is never read — because the transition function `fn` is legitimately
|
|
240
|
+
used elsewhere, this module is very much reachable, so the unused `cases` const
|
|
241
|
+
is the only thing tree-shaking has to remove, and it can't without the hint.
|
|
242
|
+
Verified against this repo's actual Vite/Rollup production build: a transition
|
|
243
|
+
whose `cases` call lacked the annotation shipped the full case-fixture data
|
|
244
|
+
(and the builder's inlined logic) into the bundle; adding `/*@__PURE__*/`
|
|
245
|
+
removed it completely while leaving the transition function itself intact. A
|
|
246
|
+
linter/codemod catching a bare `Conformance.cases(`/`Conformance.derivations(`
|
|
247
|
+
call (missing the leading comment) in a `data/state/*.ts` file would catch this
|
|
248
|
+
by construction — worth adding if these calls keep getting hand-authored.
|
|
230
249
|
- **`Conformance.cases(fn, ...cases)`** (the builder above) derives each case's
|
|
231
250
|
types from `fn`'s own signature — pass the transition function and cases can't drift
|
|
232
251
|
from what it accepts. **`before` is a delta over `State.create()`** — list only
|
|
@@ -295,6 +314,32 @@ export const cases = Conformance.cases(createTodo,
|
|
|
295
314
|
and isn't a `(state,args)=>state` transform, so `runSpec` skips it: **keep its own
|
|
296
315
|
sibling `*.test.ts`** rather than deleting it and losing coverage.
|
|
297
316
|
|
|
317
|
+
### A case that expects a throw
|
|
318
|
+
|
|
319
|
+
A case is normally `{ name, before, args?, after, effects? }`. When a transition
|
|
320
|
+
must reject its input outright — not the "guard no-op, return `{}`" case above,
|
|
321
|
+
but a genuine precondition violation the spec wants to name — declare `throws`
|
|
322
|
+
instead of `after`/`effects`:
|
|
323
|
+
|
|
324
|
+
```ts
|
|
325
|
+
export const cases = Conformance.cases(withdrawFunds,
|
|
326
|
+
{ name: "rejects a withdrawal over the balance",
|
|
327
|
+
before: { balance: 10 },
|
|
328
|
+
args: { amount: 11 },
|
|
329
|
+
throws: "insufficient funds" }, // substring the thrown Error.message must contain
|
|
330
|
+
);
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
`throws: true` accepts any thrown error; a string narrows to one whose message
|
|
334
|
+
**contains** it. A case can declare `after`/`effects` **or** `throws`, never
|
|
335
|
+
both — the shared `Case` type makes them mutually exclusive, and there is
|
|
336
|
+
nothing to compare against `after` once a call never returns a patch. The same
|
|
337
|
+
case runs against the pure transform (`runSpec`) **and** the paired ecs
|
|
338
|
+
transaction/action (`runFeature`/`runTransactions`/`runActions`), so a `throws`
|
|
339
|
+
case proves both sides reject the same input the same way. Reach for this only
|
|
340
|
+
when throwing is the transition's actual contract — most invalid input should
|
|
341
|
+
still no-op per the rule above.
|
|
342
|
+
|
|
298
343
|
## Injected services and side effects
|
|
299
344
|
|
|
300
345
|
A transform that needs an outside capability injects it with **`Pick<Services,
|
|
@@ -165,7 +165,11 @@ It discovers every file exporting `cases`, enforces the two-exports rule, and
|
|
|
165
165
|
dispatches on case shape (transition → state + effects, derivation →
|
|
166
166
|
`fn(input) ≡ value`), seeding each case's `before`/`input` as a delta over
|
|
167
167
|
`State.create()`. On the ECS side it resolves the reference args a case's `args`
|
|
168
|
-
schema marks; the pure side reads them plain.
|
|
168
|
+
schema marks; the pure side reads them plain. A transition case may declare
|
|
169
|
+
`throws` instead of `after`/`effects` to assert the call rejects its input —
|
|
170
|
+
see `../../data/state.md` ("A case that expects a throw"). `runSpec`,
|
|
171
|
+
`runTransactions`, and `runActions` all honor it identically, so the same case
|
|
172
|
+
proves the pure transform and its paired ecs op fail the same way.
|
|
169
173
|
|
|
170
174
|
## The exception — a per-surface `userId`, via the lower-level runners
|
|
171
175
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe/data-ai",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.6",
|
|
4
4
|
"description": "Cross-agent architecture skills for @adobe/data — installable as a Claude Code plugin or copied into any Agent-Skills-compatible agent (Cursor, Codex).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -29,12 +29,12 @@
|
|
|
29
29
|
"skills"
|
|
30
30
|
],
|
|
31
31
|
"peerDependencies": {
|
|
32
|
-
"@adobe/data": "0.10.
|
|
32
|
+
"@adobe/data": "0.10.6"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"typescript": "^5.8.3",
|
|
36
36
|
"vitest": "^1.6.0",
|
|
37
|
-
"@adobe/data": "0.10.
|
|
37
|
+
"@adobe/data": "0.10.6"
|
|
38
38
|
},
|
|
39
39
|
"license": "MIT",
|
|
40
40
|
"scripts": {
|