Skip to content

Commit

Permalink
fix: ensure nested morph intersections preserve normalized type struc…
Browse files Browse the repository at this point in the history
…ture (#1180)
  • Loading branch information
ssalbdivad authored Oct 16, 2024
1 parent bfbb7ad commit 5e821fe
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 27 deletions.
4 changes: 3 additions & 1 deletion ark/repo/scratch.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { type } from "arktype"

const t = type("string.numeric.parse")
const t = type({
foo: "string"
})
2 changes: 1 addition & 1 deletion ark/schema/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ark/schema",
"version": "0.18.0",
"version": "0.19.0",
"license": "MIT",
"author": {
"name": "David Blass",
Expand Down
20 changes: 10 additions & 10 deletions ark/schema/roots/morph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,16 +129,16 @@ const implementation: nodeImplementationOf<Morph.Declaration> =
)
},
...defineRightwardIntersections("morph", (l, r, ctx) => {
const inTersection = intersectOrPipeNodes(l.in, r, ctx)
return inTersection instanceof Disjoint ? inTersection : (
inTersection.distribute(
branch => ({
...l.inner,
in: branch
}),
ctx.$.parseSchema
)
)
const inTersection =
l.inner.in ? intersectOrPipeNodes(l.inner.in, r, ctx) : r
return (
inTersection instanceof Disjoint ? inTersection
: inTersection.equals(l.inner.in) ? l
: ctx.$.node("morph", {
...l.inner,
in: inTersection
})
)
})
}
})
Expand Down
22 changes: 8 additions & 14 deletions ark/schema/shared/intersections.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,24 +73,18 @@ export const intersectOrPipeNodes: InternalNodeIntersection<IntersectionContext>

if (isPureIntersection && l.equals(r)) return l

let result: BaseNode | Disjoint | null

if (isPureIntersection) {
if (l.equals(r)) return l
result = _intersectNodes(l, r, ctx)
} else {
result =
l.hasKindIn(...rootKinds) ?
// if l is a RootNode, r will be as well
_pipeNodes(l, r as never, ctx)
: _intersectNodes(l, r, ctx)
}
let result =
isPureIntersection ? _intersectNodes(l, r, ctx)
: l.hasKindIn(...rootKinds) ?
// if l is a RootNode, r will be as well
_pipeNodes(l, r as never, ctx)
: _intersectNodes(l, r, ctx)

if (isNode(result)) {
// if the result equals one of the operands, preserve its metadata by
// returning the original reference
if (l.equals(result)) result = l as never
else if (r.equals(result)) result = r as never
if (l.equals(result)) result = l
else if (r.equals(result)) result = r
}

intersectionCache[lrCacheKey] = result
Expand Down
15 changes: 15 additions & 0 deletions ark/type/__tests__/realWorld.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1009,4 +1009,19 @@ nospace must be matched by ^\\S*$ (was "One space")`)

attest(EitherInput(["str"])).snap(["str"])
})

it("intersecting unknown with piped type preserves identity", () => {
const base = type({
foo: type("string").pipe(() => 123)
})
.pipe(c => c)
.to({
foo: "123"
})

const identity = base.and("unknown")

attest(base.json).equals(identity.json)
attest(base.internal.id).equals(identity.internal.id)
})
})
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-rc.16",
"version": "2.0.0-rc.17",
"license": "MIT",
"author": {
"name": "David Blass",
Expand Down

0 comments on commit 5e821fe

Please sign in to comment.