Skip to content

Commit

Permalink
docs: fix twoslash hover styling, improve error examples
Browse files Browse the repository at this point in the history
  • Loading branch information
ssalbdivad committed Jun 13, 2024
1 parent a2fe439 commit 8865337
Show file tree
Hide file tree
Showing 10 changed files with 97 additions and 52 deletions.
13 changes: 9 additions & 4 deletions ark/docs/src/components/shiki.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,17 @@ export const twoslash = transformerTwoslash({
}
if (node.text.startsWith(twoslashPropertyPrefix)) {
const expression = node.text.slice(twoslashPropertyPrefix.length)
return (
if (expression.startsWith("RuntimeErrors.summary") && node.docs) {
// this shows error summary in JSDoc
expression.startsWith("RuntimeErrors.summary") ||
// re-add spaces stripped out during processing
node.docs = node.docs.replaceAll("•", " •")
return true
}
if (expression === `platform: "android" | "ios"`) {
// this helps demonstrate narrowing on discrimination
expression === `platform: "android" | "ios"`
)
return true
}
return false
}
return false
case "error":
Expand Down
3 changes: 1 addition & 2 deletions ark/docs/src/content/docs/betterErrors.twoslash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,8 @@ const out = user({

if (out instanceof type.errors) {
// ---cut-start---
// just a trick to display the runtime error
if (!narrowMessage(out)) throw new Error()
// ---cut-end---
// hover out.summary to see validation errors
// hover summary to see validation errors
console.error(out.summary)
}
56 changes: 43 additions & 13 deletions ark/docs/src/content/docs/intro/adding-constraints.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -64,33 +64,63 @@ const contacts = contact.array().atLeastLength(1)
Structured constraints like divisors and ranges will only take us so far. Luckily, they integrate seamlessly with whatever custom validation logic you need.

```ts
import { type, type Type } from "arktype"
import { type } from "arktype"

const _contact = type({
email: "email",
// ---cut---
const palindromicEmail = type("email").narrow((address, ctx) => {
if (address === [...address].reverse().join("")) {
// congratulations! your email is somehow a palindrome
return true
}
// add a customizable error and return false
return ctx.mustBe("a palindrome")
})

const palindromicContact = type({
email: palindromicEmail,
score: "integer < 100"
})
```

type _Contact = typeof _contact.t
We can invoke `palindromicContact` anywhere to get validated data or a list of errors with a user-friendly summary.

interface Contact extends _Contact {}
```ts
import { ArkErrors, type } from "arktype"

export const contact: Type<Contact> = _contact
// ---cut---
const goodContact = contact.narrow((data, ctx) => {
if (data.score > 75 || data.email.endsWith("@arktype.io")) {
const palindromicEmail = type("email").narrow((address, ctx) => {
if (address === [...address].reverse().join("")) {
// congratulations! your email is somehow a palindrome
return true
}
// add a customizable error and return false
return ctx.mustBe("a better contact")
return ctx.mustBe("a palindrome")
})

const out = goodContact({
email: "[email protected]",
score: 60
const palindromicContact = type({
email: palindromicEmail,
score: "integer < 100"
})

interface RuntimeErrors extends ArkErrors {
/**email must be a palindrome (was "[email protected]")
score (133.7) must be...
• an integer
• less than 100*/
summary: string
}

const narrowMessage = (e: ArkErrors): e is RuntimeErrors => true
// ---cut---
const out = palindromicContact({
email: "[email protected]",
score: 133.7
})

if (out instanceof type.errors) {
// ---cut-start---
if (!narrowMessage(out)) throw new Error()
// ---cut-end---
// hover summary to see validation errors
console.error(out.summary)
} else {
console.log(out.email)
Expand Down
2 changes: 2 additions & 0 deletions ark/docs/src/content/docs/intro/your-first-type.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ Suppose we want to move `platform` and `version` from our original type to a new
```ts
import { type } from "arktype"

// ---cut---
const user = type({
name: "string",
// nested definitions don't need to be wrapped
Expand All @@ -61,6 +62,7 @@ To decouple `device` from `user`, just move it to its own type and reference it.
```ts
import { type } from "arktype"

// ---cut---
const device = type({
platform: "'android' | 'ios'",
"versions?": "(number | string)[]"
Expand Down
13 changes: 4 additions & 9 deletions ark/docs/src/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -104,20 +104,15 @@ starlight-theme-select,
background: url("/src/assets/errorSquiggle.svg") repeat-x bottom left;
}

.twoslash .twoslash-popup-code,
.twoslash .twoslash-popup-error,
.twoslash .twoslash-popup-docs {
padding: 0px !important;
}

/* avoid double padding + border */
.twoslash .twoslash-popup-code pre {
padding: 0.5rem;
margin: -6px -8px !important;
border-width: 0px;
}

.twoslash .twoslash-hover:hover .twoslash-popup-container,
.twoslash .twoslash-hover .twoslash-popup-container,
.twoslash .twoslash-completion-cursor .twoslash-completion-list {
border-radius: 1rem;
opacity: 1;
background: #001323aa;
backdrop-filter: blur(8px);
box-shadow: var(--hover-glow);
Expand Down
44 changes: 28 additions & 16 deletions ark/repo/scratch.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,43 @@
import { type, type Type } from "arktype"
import { ArkErrors, type } from "arktype"

const _contact = type({
email: "email",
score: "integer < 100"
})

type _Contact = typeof _contact.t
interface RuntimeErrors extends ArkErrors {
/**
```
email must be a palindrome (was "[email protected]")
score (133.7) must be...
• an integer
• less than 100
```*/
summary: string
}

interface Contact extends _Contact {}
const narrowMessage = (e: ArkErrors): e is RuntimeErrors => true

export const contact: Type<Contact> = _contact
// ---cut---
const goodContact = contact.narrow((data, ctx) => {
if (data.score > 75 || data.email.endsWith("@arktype.io")) {
const palindromicEmail = type("email").narrow((address, ctx) => {
if (address === [...address].reverse().join("")) {
// congratulations! your email is somehow a palindrome
return true
}
// add a customizable error and return false
return ctx.mustBe("a better contact")
return ctx.mustBe("a palindrome")
})

const palindromicContact = type({
email: palindromicEmail,
score: "integer < 100"
})

const out = goodContact({
email: "david@gmail.com",
score: 60
const out = palindromicContact({
email: "david@arktype.io",
score: 133.7
})

if (out instanceof type.errors) {
// ---cut-start---
if (!narrowMessage(out)) throw new Error()
// ---cut-end---
console.error(out.summary)
} else {
console.log(`${out.email}: ${out.score}`)
console.log(out.email)
}
8 changes: 6 additions & 2 deletions ark/repo/tsconfig.esm.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"rootDir": "."
}
"rootDir": ".",
"outDir": "out",
"noEmit": false,
"paths": {}
},
"exclude": ["out", "__tests__"]
}
2 changes: 1 addition & 1 deletion ark/schema/roots/intersection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ export const intersectionImplementation: nodeImplementationOf<IntersectionDeclar
node.children.map(child => child.description).join(" and "),
expected: source =>
` • ${source.errors.map(e => e.expected).join("\n • ")}`,
problem: ctx => `${ctx.actual} must be...\n${ctx.expected}`
problem: ctx => `(${ctx.actual}) must be...\n${ctx.expected}`
},
intersections: {
intersection: (l, r, ctx) => intersectIntersections(l, r, ctx),
Expand Down
8 changes: 3 additions & 5 deletions ark/type/__tests__/traverse.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,16 +129,14 @@ contextualize(() => {

it("multi", () => {
const naturalNumber = type("integer>0")
attest(naturalNumber(-1.2).toString()).snap(
`-1.2 must be...
attest(naturalNumber(-1.2).toString()).snap(`(-1.2) must be...
• an integer
• more than 0`
)
• more than 0`)
const naturalAtPath = type({
natural: naturalNumber
})
attest(naturalAtPath({ natural: -0.1 }).toString()).snap(
`natural -0.1 must be...
`natural (-0.1) must be...
• an integer
• more than 0`
)
Expand Down
File renamed without changes.

0 comments on commit 8865337

Please sign in to comment.