|
| 1 | +--- |
| 2 | +"@objectstack/objectql": patch |
| 3 | +--- |
| 4 | + |
| 5 | +fix(objectql): drop the 135 `as any` that dodged `registerObject`'s old parameter type, and pin the authored shape (#5543) |
| 6 | + |
| 7 | +**Runtime behaviour is unchanged in both directions.** Nothing in this change |
| 8 | +adds, removes, or reorders a single runtime step: `registerObject` still runs no |
| 9 | +`parse`, still fills no zod defaults, and still warns rather than throws on a |
| 10 | +sparse object. What changes is what the compiler is allowed to see at the call. |
| 11 | + |
| 12 | +#5543 reported that `registerObject(schema: ServiceObject, …)` demanded the |
| 13 | +POST-parse object shape, so a perfectly legal authored literal — |
| 14 | + |
| 15 | +```ts |
| 16 | +ql.registerObject({ name: 'task', label: 'Task', fields: { title: { type: 'text', label: 'Title' } } }) |
| 17 | +``` |
| 18 | + |
| 19 | +— failed with TS2740 asking for ~9 keys (`searchable`, `required`, `multiple`, |
| 20 | +`unique`, …) that are zod `.default(...)` products, only exist after a parse the |
| 21 | +registry never runs, and that no author is supposed to write. |
| 22 | + |
| 23 | +The annotation itself is already fixed upstream: ADR-0122 phase 2 (#6083, |
| 24 | +`@objectstack/spec` 17.0.0) made the bare alias `ServiceObject` mean the |
| 25 | +**authored** (`z.input`) shape, so the existing `ServiceObject` annotation on |
| 26 | +both `ObjectQL.registerObject` and `SchemaRegistry.registerObject` now names |
| 27 | +exactly what the runtime accepts. No annotation in this package needed to move. |
| 28 | + |
| 29 | +What the flip left behind — and what this change removes — is the workaround it |
| 30 | +made obsolete: **135 `as any` casts** across 46 files in `packages/objectql`, |
| 31 | +every one of them written only to get an authored literal past the old |
| 32 | +parameter type. A blanket `as any` does not suppress one error, it suppresses |
| 33 | +all of them, so those casts were also hiding real mistakes. Deleting them |
| 34 | +surfaced four, now fixed: |
| 35 | + |
| 36 | +- `save-meta-response-conformance.test.ts` declared `primaryKey: true` on a |
| 37 | + field. There is no such Field key in the spec (it exists only on |
| 38 | + external-catalog remote columns) — inert metadata nothing ever read. |
| 39 | +- the same fixture typed a field `'longtext'`, which is not a field type; the |
| 40 | + spec spells it `'textarea'`. |
| 41 | +- two validation-rule fixtures in `registry.test.ts` omitted the required |
| 42 | + `name` and `message`. |
| 43 | + |
| 44 | +Two casts in `engine.ts` were load-bearing for a different reason — `registerApp` |
| 45 | +takes `manifest: any`, so its map branch widens object definitions to `unknown`. |
| 46 | +Those are replaced by stating the contract once on the entries |
| 47 | +(`as [string, ServiceObject][]`), which also lets the adjacent |
| 48 | +`(objDef as any).name = name` become a checked `objDef.name = name`. |
| 49 | + |
| 50 | +New `register-object-authored-shape.pin.ts` pins both halves of the contract so |
| 51 | +a re-flip cannot land quietly: the #5543 literal compiles with no cast, and an |
| 52 | +unknown key, a wrong field type, a missing `name`, and a bare-string field each |
| 53 | +still fail. It is a `.pin.ts` and not a test because this package's `tsconfig` |
| 54 | +excludes its tests, which would make a `@ts-expect-error` there a phantom check. |
| 55 | +A companion test registers the same literal for real and asserts the register |
| 56 | +path still materializes no defaults and still does not throw. |
0 commit comments