Skip to content

Commit f422e6a

Browse files
committed
chore(changeset): declare the core action-key inventory as a minor
Also drops the last `no-explicit-any` lint warning from the pin test's zod walk — `Record<string, unknown>` with a narrowing helper reads the same internals without the escape hatch. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Rvv6qysks2dRLaGfpTdgEy
1 parent a6df727 commit f422e6a

2 files changed

Lines changed: 43 additions & 4 deletions

File tree

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
---
2+
"@object-ui/core": minor
3+
---
4+
5+
feat(core): inventory `ActionDef`'s keys and warn on the ones nothing reads — objectstack#4075 step 1
6+
7+
`ActionDef` ends with `[key: string]: any`, so it accepts any key of any type.
8+
Deleting `ActionDef.execute` produced **zero** compile errors even though the
9+
field had just been removed (objectui#2990), and stale metadata still authoring
10+
`execute: 'markDone'` type-checks today. The same deletion against
11+
`@object-ui/types`' `ActionSchema` — which has no index signature — correctly
12+
produced `TS2353` at the authoring site. One of the two readers can catch a
13+
retired key; the other is structurally incapable, which is how a typo (`targt`)
14+
and a tombstoned key both reach a runner that then silently does nothing.
15+
16+
This is the non-breaking first step of the staged narrowing: it makes the key set
17+
**visible** and warns on anything outside it, without changing a single type.
18+
19+
New exports from `@object-ui/core`:
20+
21+
- `ACTION_DEF_KEYS`, `SPEC_ACTION_KEYS`, `NAVIGATION_ALIAS_KEYS`,
22+
`RETIRED_ACTION_KEYS`, `KNOWN_ACTION_KEYS` — the inventory.
23+
- `classifyActionKeys(action)` — splits an action's own keys into `unknown` and
24+
`retired`.
25+
- `warnOnUnknownActionKeys(action)` — dev-mode only, warn-once. Called by
26+
`ActionRunner.execute`, so no consumer wiring is needed.
27+
28+
A retired key gets a louder, more specific warning than an unknown one: an
29+
unknown key is probably a typo, a retired key is metadata that used to work.
30+
`execute` is not simply gone from the spec — it is a live **tombstone**, still
31+
present in `ActionSchema` so the parser can reject it by name with the rename
32+
prescription.
33+
34+
Nothing is rejected and no types changed, so existing metadata behaves exactly as
35+
before. Promoting the legitimate keys to explicit optional fields, then removing
36+
the index signature so `tsc` catches both typos and retired keys, are steps 2 and
37+
3 of objectstack#4075.

packages/core/src/actions/__tests__/actionKeys.pin.test.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,13 @@ function specActionKeys(): string[] {
5656
const walk = (schema: unknown, depth = 0): string[] | null => {
5757
if (!schema || depth > 8 || seen.has(schema)) return null;
5858
seen.add(schema);
59-
const s = schema as Record<string, any>;
60-
if (s.shape) return Object.keys(s.shape);
61-
const def = s._def ?? s.def;
59+
const s = schema as Record<string, unknown>;
60+
const shapeOf = (v: unknown): string[] | null =>
61+
v && typeof v === 'object' ? Object.keys(v as object) : null;
62+
if (s.shape) return shapeOf(s.shape);
63+
const def = (s._def ?? s.def) as Record<string, unknown> | undefined;
6264
if (!def) return null;
63-
if (def.shape) return Object.keys(def.shape);
65+
if (def.shape) return shapeOf(def.shape);
6466
for (const key of ['in', 'out', 'innerType', 'schema', 'left', 'right']) {
6567
const found = def[key] ? walk(def[key], depth + 1) : null;
6668
if (found) return found;

0 commit comments

Comments
 (0)