fix: address Copilot review round 23 — inherited constants, branch null forms, test cast
- matchesConstants checks own-property presence before reading a supplied
value, so an absent argument legally named `constructor` no longer reads the
inherited one and rules out every branch pinning that name.
- anyOfAdmitsNull asks `admitsNull` about each composition-free branch instead
of testing `type` alone, so a branch spelling its nullability as
`{ const: null }` or `{ nullable: true }` is recognized. Refusing composed
branches is what bounds the recursion.
- Drop a double cast from the malformed-applicator fixture.
Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
0be450a911
commit
4cea4e1985
2 changed files with 57 additions and 11 deletions
|
|
@ -240,6 +240,9 @@ function matchesConstants(
|
|||
if (typeof schema !== "object" || schema === null) return true;
|
||||
const constValue = (schema as { const?: unknown }).const;
|
||||
if (constValue === undefined) return true;
|
||||
// `hasOwn`: an absent argument legally named `constructor` would otherwise
|
||||
// read the inherited one and rule out every branch that pins that name.
|
||||
if (!Object.hasOwn(params, name)) return true;
|
||||
const supplied = params[name];
|
||||
return supplied === undefined || supplied === String(constValue);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -433,17 +433,19 @@ function anyOfAdmitsNull(schema: NullableUnionSchema): boolean {
|
|||
if (!Array.isArray(branches)) return false;
|
||||
return branches.some((entry) => {
|
||||
const branch = toBranch(entry);
|
||||
if (branch === null || !typeNamesNull(branch.type)) {
|
||||
return false;
|
||||
}
|
||||
// A branch that names null can still admit nothing: `{ type: "null",
|
||||
// const: "x" }` is unsatisfiable, and a nested union or applicator inside
|
||||
// it is as opaque here as one on the wrapper.
|
||||
if (branch === null) return false;
|
||||
const branchSchema = branch as NullableUnionSchema;
|
||||
return (
|
||||
!nullExcludedBySiblings(branchSchema) &&
|
||||
!hasUnevaluatedComposition(branchSchema)
|
||||
);
|
||||
// A nested union or applicator inside a branch is as opaque here as one on
|
||||
// the wrapper, and refusing it also bounds this recursion: what remains is
|
||||
// a composition-free schema, which `admitsNull` answers without reaching
|
||||
// back into this function.
|
||||
if (hasUnevaluatedComposition(branchSchema)) return false;
|
||||
// Asked through `admitsNull` rather than by testing `type` alone, so a
|
||||
// branch spelling its nullability another way — `{ const: null }`,
|
||||
// `{ nullable: true }` — is recognized the same way the wrapper's own
|
||||
// forms are, and an unsatisfiable `{ type: "null", const: "x" }` is still
|
||||
// rejected by the sibling check inside it.
|
||||
return admitsNull(branchSchema);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue