Skip to content

Commit

Permalink
fix some shallowly discriminated unions (#984)
Browse files Browse the repository at this point in the history
  • Loading branch information
ssalbdivad committed May 29, 2024
1 parent e1f532f commit ebe3408
Show file tree
Hide file tree
Showing 10 changed files with 48 additions and 14 deletions.
5 changes: 5 additions & 0 deletions .changeset/foo-bar-baz.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@arktype/util": patch
---

- Throw an error immediately if multiple versions of `@arktype/util` are imported
3 changes: 3 additions & 0 deletions .changeset/giant-rivers-drop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
"@arktype/schema": patch
---
18 changes: 10 additions & 8 deletions ark/schema/shared/intersections.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,14 +138,16 @@ export const intersectNodes: InternalNodeIntersection<IntersectionContext> = (
const leftmostKind = l.precedence < r.precedence ? l.kind : r.kind
const implementation =
l.impl.intersections[r.kind] ?? r.impl.intersections[l.kind]
result =
implementation === undefined ?
// should be two ConstraintNodes that have no relation
// this could also happen if a user directly intersects a Type and a ConstraintNode,
// but that is not allowed by the external function signature
null
: leftmostKind === l.kind ? implementation(l, r, ctx)
: implementation(r, l, { ...ctx, invert: !ctx.invert })
if (implementation === undefined) {
// should be two ConstraintNodes that have no relation
// this could also happen if a user directly intersects a Type and a ConstraintNode,
// but that is not allowed by the external function signature
result = null
} else if (leftmostKind === l.kind) result = implementation(l, r, ctx)
else {
result = implementation(r, l, { ...ctx, invert: !ctx.invert })
if (result instanceof Disjoint) result = result.invert()
}
}

if (isNode(result)) {
Expand Down
4 changes: 4 additions & 0 deletions ark/type/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

- Error thrown by `.assert` or `out.throw()` is now an instance of [AggregateError](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AggregateError), with the cause being an `ArkErrors` array.

- Throw an error immediately if multiple versions of `arktype` are imported

- Fix an issue causing some discriminated unions including a prototype like `string | RegExp` to return incorrect validation results.

## 2.0.0-dev.16

- Fix an incorrect return value on pipe sequences like the following:
Expand Down
2 changes: 1 addition & 1 deletion ark/type/__tests__/divisor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ contextualize(

it("invalid literal", () => {
attest(() => type("number%3&8")).throws.snap(
"ParseError: Intersection of 8 and % 3 results in an unsatisfiable type"
"ParseError: Intersection of % 3 and 8 results in an unsatisfiable type"
)
})
}
Expand Down
2 changes: 1 addition & 1 deletion ark/type/__tests__/keyof.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ contextualize(() => {

it("union including non-object", () => {
attest(() => type({ a: "number" }).or("boolean").keyof()).throws.snap(
'ParseError: Intersection of "toString" | "valueOf" and "a" results in an unsatisfiable type'
'ParseError: Intersection of "a" and "toString" | "valueOf" results in an unsatisfiable type'
)
})

Expand Down
4 changes: 2 additions & 2 deletions ark/type/__tests__/pipe.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ contextualize(() => {

it("disjoint", () => {
attest(() => type("number>5").pipe(type("number<3"))).throws.snap(
"ParseError: Intersection of <3 and >5 results in an unsatisfiable type"
"ParseError: Intersection of >5 and <3 results in an unsatisfiable type"
)
})

Expand Down Expand Up @@ -80,7 +80,7 @@ contextualize(() => {

it("disjoint", () => {
attest(() => type("number>5").pipe(type("number<3"))).throws.snap(
"ParseError: Intersection of <3 and >5 results in an unsatisfiable type"
"ParseError: Intersection of >5 and <3 results in an unsatisfiable type"
)
})

Expand Down
12 changes: 12 additions & 0 deletions ark/type/__tests__/realWorld.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -430,4 +430,16 @@ nospace must be matched by ^\\S*$ (was "One space")`)

attest(out).snap([{ token: "lovelace", amount: "5000000n" }])
})
it("union with domain and proto", () => {
const t = type("RegExp | string")
attest(t.raw.assertHasKind("union").discriminantJson).snap({
kind: "domain",
path: [],
cases: { '"string"': true, '"object"': { proto: "RegExp" } }
})
attest(t.allows("es")).equals(true)
attest(t.allows(5)).equals(false)
attest(t("es")).equals("es")
attest(t(new Date()).toString()).snap("must be a RegExp (was Date)")
})
})
2 changes: 1 addition & 1 deletion ark/type/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "arktype",
"description": "TypeScript's 1:1 validator, optimized from editor to runtime",
"version": "2.0.0-dev.16",
"version": "2.0.0-dev.17",
"license": "MIT",
"author": {
"name": "David Blass",
Expand Down
10 changes: 9 additions & 1 deletion ark/util/registry.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { domainOf, hasDomain } from "./domain.js"
import { throwInternalError } from "./errors.js"
import { throwError, throwInternalError } from "./errors.js"
import { objectKindOf } from "./objectKinds.js"
import { serializePrimitive, type SerializablePrimitive } from "./primitive.js"

Expand All @@ -9,6 +9,14 @@ declare global {
export interface ArkRegistry {}
}

if ("$ark" in globalThis) {
throwError(
`Tried to initialize an $ark registry but one already existed.
This probably means you are depending on multiple versions of an arktype package.
Review package.json versions across your repo to ensure consistency.`
)
}

export const registry: Record<string, unknown> = {}
;(globalThis as any).$ark = registry

Expand Down

0 comments on commit ebe3408

Please sign in to comment.