Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ark/attest/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ark/attest",
"version": "0.46.0",
"version": "0.47.0",
"license": "MIT",
"author": {
"name": "David Blass",
Expand Down
2 changes: 1 addition & 1 deletion ark/fs/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ark/fs",
"version": "0.46.0",
"version": "0.47.0",
"license": "MIT",
"author": {
"name": "David Blass",
Expand Down
36 changes: 3 additions & 33 deletions ark/repo/scratch.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,5 @@
import { type } from "arktype"
const ark: { foo?: string } = {}

const original = type({
id: "string",
name: "string",
"favoriteColor?": "string"
})
ark.foo &&= `${ark.foo}1`

const updateSchema = original.map(prop =>
prop.key === "name" ?
{
...prop,
// update key name if needed
key: `prefix${prop.key}` as const,
// update optionality if needed
kind: "optional",
// update value if needed
value: prop.value.or(type.null)
}
: prop
)

type Result = {
id: string
favoriteColor?: string
prefixname?: string | null
}

/* updateSchema:
{
id: "string",
"name?": "string"
"favoriteColor?": "string | null"
}
*/
console.log(ark.foo)
3 changes: 2 additions & 1 deletion ark/schema/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ $ark.config ??= {}
export const configureSchema = (config: ArkSchemaConfig): ArkSchemaConfig => {
const result = Object.assign($ark.config, mergeConfigs($ark.config, config))

$ark.resolvedConfig &&= mergeConfigs($ark.resolvedConfig, result)
if ($ark.resolvedConfig)
$ark.resolvedConfig = mergeConfigs($ark.resolvedConfig, result)

return result
}
Expand Down
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.46.0",
"version": "0.47.0",
"license": "MIT",
"author": {
"name": "David Blass",
Expand Down
11 changes: 10 additions & 1 deletion ark/schema/roots/root.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export abstract class BaseRoot<
out d extends InternalRootDeclaration = InternalRootDeclaration
>
extends BaseNode<d>
implements StandardSchemaV1
implements StandardSchemaV1.WithJSONSchemaSource
{
declare readonly [arkKind]: "root"
declare readonly [inferred]: unknown
Expand All @@ -92,6 +92,15 @@ export abstract class BaseRoot<
const out = this(input)
if (out instanceof ArkErrors) return out
return { value: out }
},
toJSONSchema: opts => {
if (opts.target && opts.target !== "draft-2020-12") {
return throwParseError(
`JSONSchema target '${opts.target}' is not supported (must be "draft-2020-12")`
)
}
if (opts.io === "input") return this.in.toJsonSchema() as never
return this.out.toJsonSchema() as never
Comment on lines +102 to +103

Copilot AI Sep 2, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using as never type assertions hides potential type mismatches. Consider returning the proper type or using a more specific type assertion that matches the expected return type Record<string, unknown>.

Suggested change
if (opts.io === "input") return this.in.toJsonSchema() as never
return this.out.toJsonSchema() as never
if (opts.io === "input") return this.in.toJsonSchema() as Record<string, unknown>
return this.out.toJsonSchema() as Record<string, unknown>

Copilot uses AI. Check for mistakes.
}
}
}
Expand Down
56 changes: 55 additions & 1 deletion ark/schema/shared/standardSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ export declare namespace StandardSchemaV1 {
}

export interface ArkTypeProps<Input = unknown, Output = Input>
extends Props<Input, Output> {
extends Props<Input, Output>,
StandardJSONSchemaSourceV1.Props {
readonly vendor: "arktype"
}

Expand Down Expand Up @@ -121,6 +122,59 @@ export declare namespace StandardSchemaV1 {
Schema["~standard"]["types"]
>["output"]

/**
* A Standard Schema that implements the Standard JSON Schema Source interface.
* */
export interface WithJSONSchemaSource<Input = unknown, Output = Input> {
"~standard": StandardJSONSchemaSourceV1.PropsWithStandardSchema<
Input,
Output
>
}

// biome-ignore lint/complexity/noUselessEmptyExport: needed for granular visibility control of TS namespace
export {}
}

/**
* The Standard JSON Schema Source interface. A standard interface to be implemented by any object/instance that can be converted to JSON Schema.
*/
export interface StandardJSONSchemaSourceV1 {
"~standard": StandardJSONSchemaSourceV1.Props
}

export declare namespace StandardJSONSchemaSourceV1 {
export interface Props {
/**
* Converts the Standard Schema to a JSON Schema.
* @param params - The options for the toJSONSchema method.
*
* @returns The JSON Schema.
*/
readonly toJSONSchema: (
params: StandardJSONSchemaSourceV1.Options
) => Record<string, unknown>
}

export interface PropsWithStandardSchema<Input = unknown, Output = Input>
extends Props,
StandardSchemaV1.Props<Input, Output> {}

/** The target version of the JSON Schema spec. */
export type Target =
| "draft-04"
| "draft-06"
| "draft-07"
| "draft-2019-09"
| "draft-2020-12"

export type IO = "input" | "output"

/** The options for the ~toJSONSchema method. */
export interface Options {
/** @ Specifies whether the generated JSON Schema should reflect the expected input or output values. */

Copilot AI Sep 2, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment contains an invalid character '@'. Should be '/**' followed by the description.

Suggested change
/** @ Specifies whether the generated JSON Schema should reflect the expected input or output values. */
/** Specifies whether the generated JSON Schema should reflect the expected input or output values. */

Copilot uses AI. Check for mistakes.
readonly io: IO
/** Specifies the target version of the JSON Schema spec. Support for all versions is on a best-effort basis. If a given version is not supported, the library should throw. When unspecified, implementers should target "draft-2020-12". */
readonly target?: Target
}
}
6 changes: 6 additions & 0 deletions ark/type/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# arktype

## 2.1.21

### ~standard `toJSONSchema` support

Adds support for the upcoming StandardJSONSchemaSourceV1 spec (standardschema.dev)

## 2.1.20

### `toJsonSchema` config
Expand Down
14 changes: 13 additions & 1 deletion ark/type/__tests__/standardSchema.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { attest, contextualize } from "@ark/attest"
import type { StandardSchemaV1 } from "@ark/schema"
import type { StandardJSONSchemaSourceV1, StandardSchemaV1 } from "@ark/schema"
import type { promisable } from "@ark/util"
import { type } from "arktype"

Expand All @@ -25,4 +25,16 @@ contextualize(() => {
"foo must be a string (was a number)"
)
})

it("toJSONSchema", () => {
const T = type({ foo: "string" })
const standard: StandardJSONSchemaSourceV1 = T
const jsonSchema = standard["~standard"].toJSONSchema({ io: "input" })
attest(jsonSchema).snap({
$schema: "https://json-schema.org/draft/2020-12/schema",
type: "object",
properties: { foo: { type: "string" } },
required: ["foo"]
})
})
})
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.1.20",
"version": "2.1.21",
"license": "MIT",
"repository": {
"type": "git",
Expand Down
2 changes: 1 addition & 1 deletion ark/util/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ark/util",
"version": "0.46.0",
"version": "0.47.0",
"license": "MIT",
"author": {
"name": "David Blass",
Expand Down
2 changes: 1 addition & 1 deletion ark/util/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { FileConstructor, objectKindOf } from "./objectKinds.ts"
// recent node versions (https://nodejs.org/api/esm.html#json-modules).

// For now, we assert this matches the package.json version via a unit test.
export const arkUtilVersion = "0.46.0"
export const arkUtilVersion = "0.47.0"

export const initialRegistryContents = {
version: arkUtilVersion,
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
"ts": "node ./ark/repo/ts.js",
"testRepoWithVersionsAndBenches": "pnpm typecheckRepo && pnpm testRepo && pnpm bench && pnpm testTsVersions",
"typecheckRepo": "pnpm tsc",
"testRepo": "pnpm test && pnpm testV8 && pnpm -r --filter \"arktype\" testIntegration && pnpm -r --filter \"@ark/attest\" test",
"testRepo": "pnpm test && pnpm testV8 && pnpm testIntegration && pnpm -r --filter \"@ark/attest\" test",
"testIntegration": "pnpm -r --filter \"arktype\" testIntegration",
"testV8": "node --allow-natives-syntax ./ark/repo/testV8.js",
"testTsVersions": "pnpm testTyped --tsconfig null --tsVersions \"*\" --compilerOptions \"{ \\\"module\\\": \\\"NodeNext\\\", \\\"moduleResolution\\\": \\\"NodeNext\\\", \\\"strictNullChecks\\\": true, \\\"exactOptionalPropertyTypes\\\": true }\"",
"bench": " ATTEST_benchErrorOnThresholdExceeded=\"\\\"types\\\"\" pnpm benchOperand && pnpm benchOperator && pnpm benchNary && pnpm benchObject && pnpm benchMatch && pnpm benchCyclic",
Expand Down
Loading