Socket
Socket
Sign inDemoInstall

arktype

Package Overview
Dependencies
Maintainers
1
Versions
100
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

arktype - npm Package Compare versions

Comparing version 1.1.0-dev-2 to 2.0.0-dev.0

__tests__/array.test.ts

16

main.ts

@@ -1,5 +0,7 @@

export { Problem, Problems } from "@arktype/schema"
export type { Out } from "@arktype/schema"
export type { Module, Scope } from "./scope.js"
export {
ArkErrors as ArkErrors,
type ArkTypeError as ArkTypeError
} from "@arktype/schema"
export type { Out, is } from "@arktype/schema"
export {
ark,

@@ -12,10 +14,6 @@ arktypes,

type,
when,
type Ark
} from "./scopes/ark.js"
export { jsObjects } from "./scopes/jsObjects.js"
export { tsGenerics } from "./scopes/tsGenerics.js"
export { tsKeywords } from "./scopes/tsKeywords.js"
export { validation } from "./scopes/validation.js"
} from "./ark.js"
export type { Module, Scope } from "./scope.js"
export { Type } from "./type.js"
export type { inferTypeRoot, validateTypeRoot } from "./type.js"
import type { Morph } from "@arktype/schema"
import type {
conform,
entryOf,
ErrorMessage,
evaluate,
Fn,
isDisjoint,
join,
paramsOf,
replaceKey,

@@ -19,37 +13,2 @@ returnOf,

type cedille = "¸"
type serializedWhentry<
k extends string,
v extends string
> = `[${k}${cedille}${v}]`
type parseWhentryKey<
s extends string,
$,
result = {}
> = s extends `${serializedWhentry<infer k, infer v>}${cedille}${infer tail}`
? validateTypeRoot<v, $> extends ErrorMessage<infer message>
? ErrorMessage<message>
: parseWhentryKey<tail, $, result & { [_ in k]: inferTypeRoot<v, $> }>
: s extends serializedWhentry<infer k, infer v>
? validateTypeRoot<v, $> extends ErrorMessage<infer message>
? ErrorMessage<message>
: evaluate<result & { [_ in k]: inferTypeRoot<v, $> }>
: validateTypeRoot<s, $> extends ErrorMessage<infer message>
? ErrorMessage<message>
: never
export type WhenParser<$> = <const def>(
def: validateTypeRoot<def, $>
) => join<
unionToTuple<`[${join<conform<entryOf<def>, [string, string]>, cedille>}]`>,
cedille
>
export const createWhenParser = <$>(scope: Scope): WhenParser<$> => {
const parser = (def: unknown) => new Type(def, scope).alias
return parser as never
}
type MatchContext = {

@@ -63,13 +22,43 @@ inConstraint: unknown

type validateCases<cases, ctx extends MatchContext> = {
// adding keyof $ explicitly provides key completions for aliases
[k in keyof cases | keyof ctx["$"]]?: k extends validateTypeRoot<k, ctx["$"]>
[k in keyof cases | keyof ctx["$"] | "default"]?: k extends "default"
? (In: ctx["inConstraint"]) => ctx["outConstraint"]
: k extends validateTypeRoot<k, ctx["$"]>
? (
In: ctx["inConstraint"] & inferTypeRoot<k, ctx["$"]>
) => ctx["outConstraint"]
: parseWhentryKey<k & string, ctx["$"]> extends ErrorMessage<infer message>
? ErrorMessage<message>
: (In: parseWhentryKey<k & string, ctx["$"]>) => ctx["outConstraint"]
: validateTypeRoot<k, ctx["$"]>
}
export type MatchParser<$> = {
type errorCases<cases, ctx extends MatchContext> = {
[k in keyof cases]?: k extends "default"
? (In: ctx["inConstraint"]) => ctx["outConstraint"]
: k extends validateTypeRoot<k, ctx["$"]>
? (
In: ctx["inConstraint"] & inferTypeRoot<k, ctx["$"]>
) => ctx["outConstraint"]
: validateTypeRoot<k, ctx["$"]>
} & {
[k in Exclude<keyof ctx["$"], keyof cases>]?: (
In: ctx["inConstraint"] & ctx["$"][k]
) => ctx["outConstraint"]
} & {
default?: (In: ctx["inConstraint"]) => ctx["outConstraint"]
}
export type CaseMatchParser<ctx extends MatchContext> = {
<cases>(
def: cases extends validateCases<cases, ctx>
? cases
: errorCases<cases, ctx>
): ChainableMatchParser<
replaceKey<ctx, "thens", [...ctx["thens"], ...unionToTuple<valueOf<cases>>]>
>
}
export type MatchParser<$> = CaseMatchParser<{
inConstraint: unknown
outConstraint: unknown
thens: []
$: $
}> & {
<In = unknown, Out = unknown>(): ChainableMatchParser<{

@@ -81,15 +70,4 @@ inConstraint: In

}>
} & CaseMatchParser<{
inConstraint: unknown
outConstraint: unknown
thens: []
$: $
}>
}
export type CaseMatchParser<ctx extends MatchContext> = <cases>(
def: conform<cases, validateCases<cases, ctx>>
) => ChainableMatchParser<
replaceKey<ctx, "thens", [...ctx["thens"], ...unionToTuple<valueOf<cases>>]>
>
export type WhenMatchParser<ctx extends MatchContext> = <

@@ -105,12 +83,14 @@ def,

export type MatchInvokation<ctx extends MatchContext> = <
export type MatchInvocation<ctx extends MatchContext> = <
data extends ctx["inConstraint"]
>(
In: data
data: data
) => {
[i in Extract<keyof ctx["thens"], `${number}`>]: isDisjoint<
data,
paramsOf<ctx["thens"][i]>[0]
> extends true
? never
[i in Extract<keyof ctx["thens"], `${number}`>]: ctx["thens"][i] extends Fn<
[infer In],
infer Out
>
? isDisjoint<data, In> extends true
? never
: Out
: returnOf<ctx["thens"][i]>

@@ -120,3 +100,3 @@ }[Extract<keyof ctx["thens"], `${number}`>]

export type ChainableMatchParser<ctx extends MatchContext> =
MatchInvokation<ctx> & {
MatchInvocation<ctx> & {
cases: CaseMatchParser<ctx>

@@ -127,3 +107,2 @@ when: WhenMatchParser<ctx>

export const createMatchParser = <$>(scope: Scope): MatchParser<$> => {
// TODO: move to match node, discrimination
const parser = (cases: Record<string, Morph>) => {

@@ -130,0 +109,0 @@ const caseArray = Object.entries(cases).map(([def, morph]) => ({

{
"name": "arktype",
"description": "TypeScript's 1:1 validator, optimized from editor to runtime",
"version": "1.1.0-dev-2",
"version": "2.0.0-dev.0",
"license": "MIT",

@@ -16,28 +16,26 @@ "author": {

"type": "module",
"main": "./out/main.js",
"types": "./out/main.d.ts",
"exports": {
".": {
"arktype-repo": "./main.js",
"types": "./dist/main.d.ts",
"default": "./dist/main.js"
"types": "./out/main.d.ts",
"default": "./out/main.js"
},
"./internal/*": {
"arktype-repo": "./*",
"types": "./dist/*",
"default": "./dist/*"
"default": "./out/*"
}
},
"files": [
"dist",
"**/*.ts",
"!**/*.tsBuildInfo",
"!__tests__"
"out",
"!__tests__",
"**/*.ts"
],
"scripts": {
"build": "tsc --build ./tsconfig.build.json",
"test": "ts ../repo/testPackage.ts"
"build": "tsx ../repo/build.ts",
"test": "tsx ../repo/testPackage.ts"
},
"dependencies": {
"@arktype/util": "0.0.5",
"@arktype/schema": "0.0.2"
"@arktype/util": "0.0.17",
"@arktype/schema": "0.0.3"
}
}

@@ -1,6 +0,6 @@

import { isNode, node, type Root } from "@arktype/schema"
import { isNode, schema, type TypeNode } from "@arktype/schema"
import {
isThunk,
objectKindOf,
stringify,
printable,
throwParseError,

@@ -20,4 +20,4 @@ type defined,

} from "@arktype/util"
import type { type } from "../ark.js"
import type { ParseContext } from "../scope.js"
import type { type } from "../scopes/ark.js"
import { Type } from "../type.js"

@@ -38,9 +38,12 @@ import {

export const parseObject = (def: object, ctx: ParseContext): Root => {
export const parseObject = (def: object, ctx: ParseContext): TypeNode => {
const objectKind = objectKindOf(def)
switch (objectKind) {
case undefined:
if (isNode(def)) {
return def as Root
if (def instanceof Type) {
return def.root
}
if (isNode(def) && def.isType()) {
return def
}
return parseObjectLiteral(def as Dict, ctx)

@@ -50,3 +53,3 @@ case "Array":

case "RegExp":
return node({ basis: "string", pattern: def as RegExp })
return schema({ basis: "string", pattern: def as RegExp })
case "Function":

@@ -60,3 +63,3 @@ const resolvedDef = isThunk(def) ? def() : def

return throwParseError(
writeBadDefinitionTypeMessage(objectKind ?? stringify(def))
writeBadDefinitionTypeMessage(objectKind ?? printable(def))
)

@@ -69,12 +72,12 @@ }

: def extends type.cast<infer t> | ThunkCast<infer t>
? t
: def extends string
? inferString<def, $, args>
: def extends readonly unknown[]
? inferTuple<def, $, args>
: def extends RegExp
? string
: def extends object
? inferObjectLiteral<def, $, args>
: never
? t
: def extends string
? inferString<def, $, args>
: def extends readonly unknown[]
? inferTuple<def, $, args>
: def extends RegExp
? string
: def extends object
? inferObjectLiteral<def, $, args>
: never

@@ -84,18 +87,18 @@ export type validateDefinition<def, $, args> = null extends undefined

: [def] extends [Terminal]
? unknown extends def
? // if def is any, never is the only way we can make validation fail
// since any would be assignable to a standard error message
never
: def
: def extends string
? validateString<def, $, args>
: def extends readonly unknown[]
? validateTuple<def, $, args>
: def extends BadDefinitionType
? writeBadDefinitionTypeMessage<objectKindOrDomainOf<def>>
: isUnknown<def> extends true
? // this allows the initial list of autocompletions to be populated when a user writes "type()",
// before having specified a definition
BaseCompletions<$, args> | {}
: validateObjectLiteral<def, $, args>
? unknown extends def
? // if def is any, never is the only way we can make validation fail
// since any would be assignable to a standard error message
never
: def
: def extends string
? validateString<def, $, args>
: def extends readonly unknown[]
? validateTuple<def, $, args>
: def extends BadDefinitionType
? writeBadDefinitionTypeMessage<objectKindOrDomainOf<def>>
: isUnknown<def> extends true
? // this allows the initial list of autocompletions to be populated when a user writes "type()",
// before having specified a definition
BaseCompletions<$, args> | {}
: validateObjectLiteral<def, $, args>

@@ -114,23 +117,23 @@ export type validateDeclared<declared, def, $, args> =

: def extends readonly unknown[]
? declared extends readonly unknown[]
? {
[i in keyof declared]: i extends keyof def
? validateInference<def[i], declared[i], $, args>
: unknown
}
: evaluate<declarationMismatch<def, declared, $, args>>
: def extends object
? evaluate<
{
[k in requiredKeyOf<declared>]: k extends keyof def
? validateInference<def[k], declared[k], $, args>
: unknown
} & {
[k in optionalKeyOf<declared> &
string as `${k}?`]: `${k}?` extends keyof def
? validateInference<def[`${k}?`], defined<declared[k]>, $, args>
: unknown
}
>
: validateShallowInference<def, declared, $, args>
? declared extends readonly unknown[]
? {
[i in keyof declared]: i extends keyof def
? validateInference<def[i], declared[i], $, args>
: unknown
}
: evaluate<declarationMismatch<def, declared, $, args>>
: def extends object
? evaluate<
{
[k in requiredKeyOf<declared>]: k extends keyof def
? validateInference<def[k], declared[k], $, args>
: unknown
} & {
[k in optionalKeyOf<declared> &
string as `${k}?`]: `${k}?` extends keyof def
? validateInference<def[`${k}?`], defined<declared[k]>, $, args>
: unknown
}
>
: validateShallowInference<def, declared, $, args>

@@ -137,0 +140,0 @@ type validateShallowInference<def, declared, $, args> = equals<

@@ -1,15 +0,4 @@

import type { Root } from "@arktype/schema"
import {
throwParseError,
type ErrorMessage,
type join,
type nominal
} from "@arktype/util"
import type { ParseContext } from "../scope.js"
import { DynamicState } from "./string/reduce/dynamic.js"
import { writeUnclosedGroupMessage } from "./string/reduce/shared.js"
import type { StaticState, state } from "./string/reduce/static.js"
import { throwParseError, type nominal } from "@arktype/util"
import { writeUnexpectedCharacterMessage } from "./string/shift/operator/operator.js"
import { Scanner } from "./string/shift/scanner.js"
import { parseUntilFinalizer } from "./string/string.js"

@@ -53,4 +42,4 @@ export type GenericDeclaration<

: nextNonWhitespace === ","
? [param, ...parseGenericParamsRecurse(scanner)]
: throwParseError(writeUnexpectedCharacterMessage(nextNonWhitespace, ","))
? [param, ...parseGenericParamsRecurse(scanner)]
: throwParseError(writeUnexpectedCharacterMessage(nextNonWhitespace, ","))
}

@@ -66,145 +55,16 @@

: lookahead extends Scanner.WhiteSpaceToken
? param extends ""
? // if the next char is whitespace and we aren't in the middle of a param, skip to the next one
parseParamsRecurse<Scanner.skipWhitespace<nextUnscanned>, "", result>
: Scanner.skipWhitespace<nextUnscanned> extends `${infer nextNonWhitespace}${infer rest}`
? nextNonWhitespace extends ","
? parseParamsRecurse<rest, "", [...result, param]>
: GenericParamsParseError<
writeUnexpectedCharacterMessage<nextNonWhitespace, ",">
>
: // params end with a single whitespace character, add the current token
[...result, param]
: parseParamsRecurse<nextUnscanned, `${param}${lookahead}`, result>
? param extends ""
? // if the next char is whitespace and we aren't in the middle of a param, skip to the next one
parseParamsRecurse<Scanner.skipWhitespace<nextUnscanned>, "", result>
: Scanner.skipWhitespace<nextUnscanned> extends `${infer nextNonWhitespace}${infer rest}`
? nextNonWhitespace extends ","
? parseParamsRecurse<rest, "", [...result, param]>
: GenericParamsParseError<
writeUnexpectedCharacterMessage<nextNonWhitespace, ",">
>
: // params end with a single whitespace character, add the current token
[...result, param]
: parseParamsRecurse<nextUnscanned, `${param}${lookahead}`, result>
: param extends ""
? result
: [...result, param]
export type ParsedArgs<
result extends unknown[] = unknown[],
unscanned extends string = string
> = {
result: result
unscanned: unscanned
}
export const parseGenericArgs = (
name: string,
params: string[],
unscanned: string,
ctx: ParseContext
) => parseGenericArgsRecurse(name, params, unscanned, ctx, [], [])
export type parseGenericArgs<
name extends string,
params extends string[],
unscanned extends string,
$,
args
> = parseGenericArgsRecurse<name, params, unscanned, $, args, [], []>
const parseGenericArgsRecurse = (
name: string,
params: string[],
unscanned: string,
ctx: ParseContext,
argDefs: string[],
argNodes: Root[]
): ParsedArgs<Root[]> => {
const s = parseUntilFinalizer(new DynamicState(unscanned, ctx))
// remove the finalizing token from the argDef
argDefs.push(s.scanner.scanned.slice(0, -1))
argNodes.push(s.root)
const nextUnscanned = s.scanner.unscanned
if (s.finalizer === ">") {
if (argNodes.length === params.length) {
return {
result: argNodes,
unscanned: nextUnscanned
}
} else {
return s.error(writeInvalidGenericArgsMessage(name, params, argDefs))
}
} else if (s.finalizer === ",") {
return parseGenericArgsRecurse(
name,
params,
nextUnscanned,
ctx,
argDefs,
argNodes
)
}
return s.error(writeUnclosedGroupMessage(">"))
}
type parseGenericArgsRecurse<
name extends string,
params extends string[],
unscanned extends string,
$,
args,
argDefs extends string[],
argAsts extends unknown[]
> = parseUntilFinalizer<
state.initialize<unscanned>,
$,
args
> extends infer finalArgState extends StaticState
? {
defs: [
...argDefs,
finalArgState["scanned"] extends `${infer def}${"," | ">"}`
? def
: finalArgState["scanned"]
]
asts: [...argAsts, finalArgState["root"]]
unscanned: finalArgState["unscanned"]
} extends {
defs: infer nextDefs extends string[]
asts: infer nextAsts extends unknown[]
unscanned: infer nextUnscanned extends string
}
? finalArgState["finalizer"] extends ">"
? nextAsts["length"] extends params["length"]
? ParsedArgs<nextAsts, nextUnscanned>
: state.error<writeInvalidGenericArgsMessage<name, params, nextDefs>>
: finalArgState["finalizer"] extends ","
? parseGenericArgsRecurse<
name,
params,
nextUnscanned,
$,
args,
nextDefs,
nextAsts
>
: finalArgState["finalizer"] extends ErrorMessage
? finalArgState
: state.error<writeUnclosedGroupMessage<">">>
: never
: never
export const writeInvalidGenericArgsMessage = <
name extends string,
params extends string[],
argDefs extends string[]
>(
name: name,
params: params,
argDefs: argDefs
) =>
`${name}<${params.join(", ")}> requires exactly ${params.length} args (got ${
argDefs.length
}${argDefs.length === 0 ? "" : ": " + argDefs.join(", ")})`
export type writeInvalidGenericArgsMessage<
name extends string,
params extends string[],
argDefs extends string[]
> = `${name}<${join<
params,
", "
>}> requires exactly ${params["length"]} args (got ${argDefs["length"]}${argDefs["length"] extends 0
? ""
: `: ${join<argDefs, ",">}`})`
? result
: [...result, param]

@@ -1,10 +0,14 @@

import { node, type Inner } from "@arktype/schema"
import { keywords, schema, type Inner, type TypeNode } from "@arktype/schema"
import {
stringify,
printable,
throwParseError,
type Dict,
type ErrorMessage,
type evaluate
type evaluate,
type merge
} from "@arktype/util"
import type { ParseContext } from "../scope.js"
import type { inferDefinition, validateDefinition } from "./definition.js"
import type { astToString } from "./semantic/utils.js"
import type { validateString } from "./semantic/validate.js"

@@ -24,11 +28,57 @@ import {

export const parseObjectLiteral = (def: Dict, ctx: ParseContext) => {
export const parseObjectLiteral = (def: Dict, ctx: ParseContext): TypeNode => {
const required: Inner<"required">[] = []
const optional: Inner<"optional">[] = []
for (const entry of stringAndSymbolicEntriesOf(def)) {
// We only allow a spread operator to be used as the first key in an object
// because to match JS behavior any keys before the spread are overwritten
// by the values in the target object, so there'd be no useful purpose in having it
// anywhere except for the beginning.
// Discussion in ArkType Discord:
// https://discord.com/channels/957797212103016458/1103023445035462678/1182814502471860334
let hasSeenFirstKey = false
const entries = stringAndSymbolicEntriesOf(def)
for (const entry of entries) {
const result = parseEntry(entry)
if (result.kind === "spread") {
if (hasSeenFirstKey) {
return throwParseError(
"Spread operator may only be used as the first key in an object"
)
}
const spreadNode = ctx.scope.parse(result.innerValue, ctx)
if (
spreadNode.kind !== "intersection" ||
!spreadNode.extends(keywords.object)
) {
return throwParseError(
writeInvalidSpreadTypeMessage(printable(result.innerValue))
)
}
// For each key on spreadNode, add it to our object.
// We filter out keys from the spreadNode that will be defined later on this same object
// because the currently parsed definition will overwrite them.
const requiredEntriesFromSpread = (spreadNode.required ?? []).filter(
(e) => !entries.some(([k]) => k === e.key)
)
const optionalEntriesFromSpread = (spreadNode.optional ?? []).filter(
(e) => !entries.some(([k]) => k === e.key)
)
required.push(...requiredEntriesFromSpread)
optional.push(...optionalEntriesFromSpread)
continue
}
ctx.path.push(
`${
typeof result.innerKey === "symbol"
? `[${stringify(result.innerKey)}]`
? `[${printable(result.innerKey)}]`
: result.innerKey

@@ -38,2 +88,3 @@ }`

const valueNode = ctx.scope.parse(result.innerValue, ctx)
if (result.kind === "optional") {

@@ -51,4 +102,7 @@ optional.push({

ctx.path.pop()
hasSeenFirstKey ||= true
}
return node({
return schema({
basis: "object",

@@ -60,20 +114,31 @@ required,

/**
* Infers the contents of an object literal, ignoring a spread definition
* You probably want to use {@link inferObjectLiteral} instead.
*/
type inferObjectLiteralInner<def extends object, $, args> = {
// since def is a const parameter, we remove the readonly modifier here
// support for builtin readonly tracked here:
// https://github.com/arktypeio/arktype/issues/808
-readonly [k in keyof def as nonOptionalKeyFrom<
k,
def[k],
$,
args
>]: inferDefinition<def[k], $, args>
} & {
-readonly [k in keyof def as optionalKeyFrom<k, def[k]>]?: inferDefinition<
def[k] extends OptionalValue<infer inner> ? inner : def[k],
$,
args
>
}
export type inferObjectLiteral<def extends object, $, args> = evaluate<
{
// since def is a const parameter, we remove the readonly modifier here
// support for builtin readonly tracked here:
// https://github.com/arktypeio/arktype/issues/808
-readonly [k in keyof def as nonOptionalKeyFrom<
k,
def[k],
$,
args
>]: inferDefinition<def[k], $, args>
} & {
-readonly [k in keyof def as optionalKeyFrom<k, def[k]>]?: inferDefinition<
def[k] extends OptionalValue<infer inner> ? inner : def[k],
$,
args
>
}
"..." extends keyof def
? merge<
inferDefinition<def["..."], $, args>,
inferObjectLiteralInner<def, $, args>
>
: inferObjectLiteralInner<def, $, args>
>

@@ -87,6 +152,10 @@

: inferDefinition<indexDef, $, args> extends PropertyKey
? // if the indexDef is syntactically and semantically valid,
// move on to the validating the value definition
validateDefinition<def[k], $, args>
: indexParseError<writeInvalidPropertyKeyMessage<indexDef>>
? // if the indexDef is syntactically and semantically valid,
// move on to the validating the value definition
validateDefinition<def[k], $, args>
: indexParseError<writeInvalidPropertyKeyMessage<indexDef>>
: k extends "..."
? inferDefinition<def[k], $, args> extends object
? validateDefinition<def[k], $, args>
: indexParseError<writeInvalidSpreadTypeMessage<astToString<def[k]>>>
: validateObjectValue<def[k], $, args>

@@ -102,4 +171,4 @@ }

: result["kind"] extends "indexed"
? inferDefinition<result["innerKey"], $, args> & PropertyKey
: never
? inferDefinition<result["innerKey"], $, args> & PropertyKey
: never
: never

@@ -127,1 +196,9 @@

`Indexed key definition '${indexDef}' must be a string, number or symbol`
export const writeInvalidSpreadTypeMessage = <def extends string>(
def: def
): writeInvalidSpreadTypeMessage<def> =>
`Spread operand must resolve to an object literal type (was ${def})`
type writeInvalidSpreadTypeMessage<def extends string> =
`Spread operand must resolve to an object literal type (was ${def})`

@@ -1,15 +0,14 @@

import type {
NumericallyBoundable,
writeUnboundableMessage
} from "@arktype/schema"
import type { NumericallyBoundable } from "@arktype/schema"
import type { ErrorMessage } from "@arktype/util"
import type { DateLiteral } from "../string/shift/operand/date.js"
import type {
BoundKind,
Comparator,
InvertedComparators,
LimitLiteral,
writeInvalidLimitMessage
LimitLiteral
} from "../string/reduce/shared.js"
import type {
BoundExpressionKind,
writeInvalidLimitMessage,
writeUnboundableMessage
} from "../string/shift/operator/bounds.js"
import type { inferAst } from "./semantic.js"
import type { inferAstBase } from "./semantic.js"
import type { astToString } from "./utils.js"

@@ -27,4 +26,4 @@ import type { validateAst } from "./validate.js"

: l extends [infer leftAst, Comparator, unknown]
? ErrorMessage<writeDoubleRightBoundMessage<astToString<leftAst>>>
: validateBound<l, comparator, r & LimitLiteral, "right", $, args>
? ErrorMessage<writeDoubleRightBoundMessage<astToString<leftAst>>>
: validateBound<l, comparator, r & LimitLiteral, "right", $, args>

@@ -35,6 +34,6 @@ export type validateBound<

limit extends LimitLiteral,
boundKind extends BoundKind,
boundKind extends BoundExpressionKind,
$,
args
> = inferAst<boundedAst, $, args> extends infer bounded
> = inferAstBase<boundedAst, $, args> extends infer bounded
? [bounded] extends [NumericallyBoundable]

@@ -45,14 +44,13 @@ ? limit extends number

: bounded extends Date
? limit extends DateLiteral
? validateAst<boundedAst, $, args>
: ErrorMessage<writeInvalidLimitMessage<comparator, limit, boundKind>>
: ErrorMessage<
writeUnboundableMessage<
astToString<
boundKind extends "left"
? boundedAst[0 & keyof boundedAst]
: boundedAst
>
? // allow numeric or date literal as a Date limit
validateAst<boundedAst, $, args>
: ErrorMessage<
writeUnboundableMessage<
astToString<
boundKind extends "left"
? boundedAst[0 & keyof boundedAst]
: boundedAst
>
>
>
>
: never

@@ -59,0 +57,0 @@

import type { writeIndivisibleMessage } from "@arktype/schema"
import type { ErrorMessage } from "@arktype/util"
import type { inferAst } from "./semantic.js"
import type { inferAstBase } from "./semantic.js"
import type { astToString } from "./utils.js"

@@ -8,3 +8,3 @@ import type { validateAst } from "./validate.js"

export type validateDivisor<l, $, args> = isDivisible<
inferAst<l, $, args>
inferAstBase<l, $, args>
> extends true

@@ -11,0 +11,0 @@ ? validateAst<l, $, args>

@@ -1,2 +0,2 @@

import type { Out } from "@arktype/schema"
import type { MorphAst, Out } from "@arktype/schema"
import {

@@ -10,3 +10,2 @@ Hkt,

} from "@arktype/util"
import type { MorphAst } from "../tuple.js"

@@ -16,18 +15,18 @@ export type inferIntersection<l, r> = [l] extends [never]

: [r] extends [never]
? never
: [l & r] extends [never]
? never
: isAny<l | r> extends true
? any
: l extends MorphAst<infer lIn, infer lOut>
? r extends MorphAst
? never
: (In: evaluate<lIn & r>) => Out<lOut>
: r extends MorphAst<infer rIn, infer rOut>
? (In: evaluate<rIn & l>) => Out<rOut>
: [l, r] extends [object, object]
? intersectObjects<l, r> extends infer result
? result
: never
: l & r
? never
: [l & r] extends [never]
? never
: isAny<l | r> extends true
? any
: l extends MorphAst<infer lIn, infer lOut>
? r extends MorphAst
? never
: (In: evaluate<lIn & r>) => Out<lOut>
: r extends MorphAst<infer rIn, infer rOut>
? (In: evaluate<rIn & l>) => Out<rOut>
: [l, r] extends [object, object]
? intersectObjects<l, r> extends infer result
? result
: never
: l & r

@@ -34,0 +33,0 @@ declare class MorphableIntersection extends Hkt.Kind {

@@ -1,3 +0,16 @@

import type { BigintLiteral, List, NumberLiteral } from "@arktype/util"
import type {
DateLiteral,
Refinements,
RegexLiteral,
distill,
is
} from "@arktype/schema"
import type {
BigintLiteral,
List,
NumberLiteral,
evaluate,
extend
} from "@arktype/util"
import type {
UnparsedScope,

@@ -9,14 +22,23 @@ resolve,

import type { inferDefinition } from "../definition.js"
import type { DateLiteral } from "../string/shift/operand/date.js"
import type { StringLiteral } from "../string/shift/operand/enclosed.js"
import type {
Comparator,
InvertedComparators,
LimitLiteral
} from "../string/shift/operator/bounds.js"
} from "../string/reduce/shared.js"
import type { StringLiteral } from "../string/shift/operand/enclosed.js"
import type { inferIntersection } from "./intersections.js"
export type inferAst<ast, $, args> = ast extends List
? inferExpression<ast, $, args>
: inferTerminal<ast, $, args>
export type inferAstRoot<ast, $, args> = inferAst<ast, $, args, {}>
export type inferAstBase<ast, $, args> = distill<inferAstRoot<ast, $, args>>
export type inferAst<
ast,
$,
args,
refinements extends Refinements
> = ast extends List
? inferExpression<ast, $, args, refinements>
: inferTerminal<ast, $, args, refinements>
export type GenericInstantiationAst<

@@ -30,3 +52,4 @@ g extends GenericProps = GenericProps,

$,
args
args,
refinements extends Refinements
> = ast extends GenericInstantiationAst

@@ -48,3 +71,4 @@ ? inferDefinition<

$,
args
args,
refinements
>

@@ -54,19 +78,26 @@ }

: ast[1] extends "[]"
? inferAst<ast[0], $, args>[]
: ast[1] extends "|"
? inferAst<ast[0], $, args> | inferAst<ast[2], $, args>
: ast[1] extends "&"
? inferIntersection<
inferAst<ast[0], $, args>,
inferAst<ast[2], $, args>
>
: ast[1] extends Comparator
? ast[0] extends LimitLiteral
? inferAst<ast[2], $, args>
: inferAst<ast[0], $, args>
: ast[1] extends "%"
? inferAst<ast[0], $, args>
: ast[0] extends "keyof"
? keyof inferAst<ast[1], $, args>
: never
? inferAst<ast[0], $, args, refinements>[]
: ast[1] extends "|"
?
| inferAst<ast[0], $, args, refinements>
| inferAst<ast[2], $, args, refinements>
: ast[1] extends "&"
? inferIntersection<
inferAst<ast[0], $, args, refinements>,
inferAst<ast[2], $, args, refinements>
>
: ast[1] extends Comparator
? ast[0] extends LimitLiteral
? inferAst<
ast[2],
$,
args,
refinements & { [_ in InvertedComparators[ast[1]]]: ast[0] }
>
: inferAst<ast[0], $, args, refinements & { [_ in ast[1]]: ast[2] }>
: ast[1] extends "%"
? inferAst<ast[0], $, args, refinements & { [k in `%${ast[2] & string}`]: 0 }>
: ast[0] extends "keyof"
? keyof inferAst<ast[1], $, args, refinements>
: never

@@ -95,18 +126,24 @@ export type PrefixOperator = "keyof" | "instanceof" | "===" | "node"

export type RegexLiteral<source extends string = string> = `/${source}/`
export type inferTerminal<token, $, args> = token extends keyof args | keyof $
? resolve<token, $, args>
: token extends StringLiteral<infer Text>
? Text
: token extends RegexLiteral
? string
: token extends DateLiteral
? Date
: token extends NumberLiteral<infer value>
? value
: token extends BigintLiteral<infer value>
? value
: // doing this last allows us to infer never if it isn't valid rather than check
// if it's a valid submodule reference ahead of time
tryInferSubmoduleReference<$, token>
export type inferTerminal<
token,
$,
args,
refinements extends Refinements
> = token extends keyof args | keyof $
? {} extends refinements
? resolve<token, $, args>
: is<resolve<token, $, args>, evaluate<refinements>>
: token extends StringLiteral<infer text>
? text
: token extends RegexLiteral
? is<string, extend<refinements, { [_ in token]: true }>>
: token extends DateLiteral
? is<Date, extend<refinements, { [_ in token]: true }>>
: token extends NumberLiteral<infer value>
? value
: token extends BigintLiteral<infer value>
? value
: // TODO: refinements
// doing this last allows us to infer never if it isn't valid rather than check
// if it's a valid submodule reference ahead of time
tryInferSubmoduleReference<$, token>
import type { List, Stringifiable } from "@arktype/util"
import type { Comparator } from "../string/shift/operator/bounds.js"
import type { Comparator } from "../string/reduce/shared.js"
import type { InfixExpression, PostfixExpression } from "./semantic.js"

@@ -15,8 +15,8 @@

: ast extends InfixExpression<infer operator, infer l, infer r>
? operator extends "&" | "|" | "%" | Comparator
? `${groupAst<l>}${operator}${groupAst<r>}`
: never
: ast extends Stringifiable
? `${ast extends bigint ? `${ast}n` : ast}`
: "..."
? operator extends "&" | "|" | "%" | Comparator
? `${groupAst<l>}${operator}${groupAst<r>}`
: never
: ast extends Stringifiable
? `${ast extends bigint ? `${ast}n` : ast}`
: "..."

@@ -23,0 +23,0 @@ type groupAst<ast> = ast extends List

@@ -0,1 +1,2 @@

import type { Refinements } from "@arktype/schema"
import type {

@@ -10,5 +11,5 @@ BigintLiteral,

import type { GenericProps } from "../../type.js"
import type { writeInvalidGenericArgsMessage } from "../generic.js"
import type { Comparator } from "../string/reduce/shared.js"
import type { writeInvalidGenericArgsMessage } from "../string/shift/operand/genericArgs.js"
import type { writeMissingSubmoduleAccessMessage } from "../string/shift/operand/unenclosed.js"
import type { Comparator } from "../string/shift/operator/bounds.js"
import type { parseString } from "../string/string.js"

@@ -27,18 +28,18 @@ import type { validateRange } from "./bounds.js"

: ast extends PostfixExpression<infer operator, infer operand>
? operator extends "[]"
? validateAst<operand, $, args>
: never
: ast extends InfixExpression<infer operator, infer l, infer r>
? operator extends "&" | "|"
? validateInfix<ast, $, args>
: operator extends Comparator
? validateRange<l, operator, r, $, args>
: operator extends "%"
? validateDivisor<l, $, args>
: undefined
: ast extends readonly ["keyof", infer operand]
? validateAst<operand, $, args>
: ast extends GenericInstantiationAst
? validateGenericArgs<ast["2"], $, args>
: ErrorMessage<writeUnexpectedExpressionMessage<astToString<ast>>>
? operator extends "[]"
? validateAst<operand, $, args>
: never
: ast extends InfixExpression<infer operator, infer l, infer r>
? operator extends "&" | "|"
? validateInfix<ast, $, args>
: operator extends Comparator
? validateRange<l, operator, r, $, args>
: operator extends "%"
? validateDivisor<l, $, args>
: undefined
: ast extends readonly ["keyof", infer operand]
? validateAst<operand, $, args>
: ast extends GenericInstantiationAst
? validateGenericArgs<ast["2"], $, args>
: ErrorMessage<writeUnexpectedExpressionMessage<astToString<ast>>>

@@ -72,18 +73,21 @@ type writeUnexpectedExpressionMessage<expression extends string> =

: def extends BigintLiteral<infer value>
? bigint extends value
? ErrorMessage<writeMalformedNumericLiteralMessage<def, "bigint">>
: undefined
: def extends keyof $
? // these problems would've been caught during a fullStringParse, but it's most
// efficient to check for them here in case the string was naively parsed
$[def] extends GenericProps
? ErrorMessage<
writeInvalidGenericArgsMessage<def, $[def]["parameters"], []>
>
: $[def] extends Module
? ErrorMessage<writeMissingSubmoduleAccessMessage<def>>
: undefined
: def extends ErrorMessage
? def
: undefined
? bigint extends value
? ErrorMessage<writeMalformedNumericLiteralMessage<def, "bigint">>
: undefined
: def extends keyof $
? $[def] extends null
? // handle any/never
def
: // these problems would've been caught during a fullStringParse, but it's most
// efficient to check for them here in case the string was naively parsed
$[def] extends GenericProps
? ErrorMessage<
writeInvalidGenericArgsMessage<def, $[def]["parameters"], []>
>
: $[def] extends Module
? ErrorMessage<writeMissingSubmoduleAccessMessage<def>>
: undefined
: def extends ErrorMessage
? def
: undefined

@@ -107,3 +111,3 @@ export type validateString<def extends string, $, args> = validateAst<

: validateAst<ast[2], $, args> extends ErrorMessage<infer message>
? ErrorMessage<message>
: undefined
? ErrorMessage<message>
: undefined

@@ -29,3 +29,3 @@ import type { extend } from "@arktype/util"

type ParsedKeyKind = "required" | "optional" | "indexed"
type ParsedKeyKind = "required" | "optional" | "indexed" | "spread"

@@ -77,2 +77,5 @@ type parsedEntry<result extends EntryParseResult> = result

// these methods are also used in tuple parsing, however the keys of a tuple will always be 0, 1,
// 2, etc and never be `...`, meaning `"spread"` as a kind will never occur in tuples
export const parseEntry = ([key, value]: DefinitionEntry): EntryParseResult => {

@@ -84,2 +87,6 @@ const keyParseResult: KeyParseResult =

: { innerKey: key.slice(0, -1), kind: "optional" }
: key === "..."
? { innerKey: "...", kind: "spread" }
: key === "\\..."
? { innerKey: "...", kind: "required" }
: { innerKey: key, kind: "required" }

@@ -94,4 +101,4 @@ const valueParseResult = getInnerValue(value)

: valueParseResult.kind === "optional"
? "optional"
: keyParseResult.kind
? "optional"
: keyParseResult.kind
}

@@ -131,16 +138,20 @@ }

}>
: k extends "..."
? parsedKey<{ kind: "spread"; innerKey: "..." }>
: k extends "\\..."
? parsedKey<{ kind: "required"; innerKey: "..." }>
: k extends IndexedKey<infer def>
? parsedKey<{
kind: "indexed"
innerKey: def
}>
: k extends `${Scanner.EscapeToken}${infer escapedIndexKey extends
IndexedKey}`
? parsedKey<{
kind: "required"
innerKey: escapedIndexKey
}>
: parsedKey<{
kind: "required"
innerKey: k & (string | symbol)
}>
? parsedKey<{
kind: "indexed"
innerKey: def
}>
: k extends `${Scanner.EscapeToken}${infer escapedIndexKey extends
IndexedKey}`
? parsedKey<{
kind: "required"
innerKey: escapedIndexKey
}>
: parsedKey<{
kind: "required"
innerKey: k & (string | symbol)
}>

@@ -1,2 +0,2 @@

import type { Root } from "@arktype/schema"
import type { TypeNode } from "@arktype/schema"
import {

@@ -9,10 +9,9 @@ isKeyOf,

import type { ParseContext } from "../../../scope.js"
import { parseOperand } from "../shift/operand/operand.js"
import { parseOperator } from "../shift/operator/operator.js"
import { Scanner } from "../shift/scanner.js"
import { parseUntilFinalizer } from "../string.js"
import {
invertedComparators,
minComparators,
type Comparator,
type LimitLiteral
} from "../shift/operator/bounds.js"
import { Scanner } from "../shift/scanner.js"
import {
writeMultipleLeftBoundsMessage,

@@ -23,2 +22,4 @@ writeOpenRangeMessage,

writeUnpairableComparatorMessage,
type Comparator,
type LimitLiteral,
type OpenLeftBound,

@@ -31,4 +32,4 @@ type StringifiablePrefixOperator

leftBound?: OpenLeftBound
"&"?: Root
"|"?: Root
"&"?: TypeNode
"|"?: TypeNode
}

@@ -40,3 +41,3 @@

readonly scanner: Scanner
root: Root | undefined
root: TypeNode | undefined
branches: BranchState = {

@@ -69,7 +70,7 @@ prefixes: []

constrainRoot(...args: Parameters<Root["constrain"]>) {
constrainRoot(...args: Parameters<TypeNode["constrain"]>) {
this.root = this.root!.constrain(...args)
}
setRoot(root: Root) {
setRoot(root: TypeNode) {
this.root = root

@@ -156,2 +157,16 @@ }

parseUntilFinalizer() {
return parseUntilFinalizer(
new DynamicState(this.scanner.unscanned, this.ctx)
)
}
parseOperator(this: DynamicStateWithRoot) {
return parseOperator(this)
}
parseOperand() {
return parseOperand(this)
}
private assertRangeUnset() {

@@ -158,0 +173,0 @@ if (this.branches.leftBound) {

@@ -1,11 +0,39 @@

import {
invertedComparators,
type Comparator,
type InvertedComparators,
type LimitLiteral,
type MinComparator
} from "../shift/operator/bounds.js"
import type { DateLiteral } from "@arktype/schema"
export type StringifiablePrefixOperator = "keyof"
export const minComparators = {
">": true,
">=": true
} as const
export type MinComparator = keyof typeof minComparators
export const maxComparators = {
"<": true,
"<=": true
} as const
export type MaxComparator = keyof typeof maxComparators
export const comparators = {
...minComparators,
...maxComparators,
"==": true
}
export type Comparator = keyof typeof comparators
export const invertedComparators = {
"<": ">",
">": "<",
"<=": ">=",
">=": "<=",
"==": "=="
} as const satisfies Record<Comparator, Comparator>
export type InvertedComparators = typeof invertedComparators
export type LimitLiteral = number | DateLiteral
export type OpenLeftBound = { limit: LimitLiteral; comparator: MinComparator }

@@ -12,0 +40,0 @@

import type { Completion, defined, ErrorMessage } from "@arktype/util"
import type { Scanner } from "../shift/scanner.js"
import type {

@@ -7,6 +8,3 @@ Comparator,

MaxComparator,
MinComparator
} from "../shift/operator/bounds.js"
import type { Scanner } from "../shift/scanner.js"
import type {
MinComparator,
OpenLeftBound,

@@ -234,11 +232,11 @@ StringifiablePrefixOperator,

: s["groups"] extends popGroup<infer stack, infer top>
? from<{
groups: stack
branches: top
root: mergeToUnion<s>
finalizer: s["finalizer"]
scanned: updateScanned<s["scanned"], s["unscanned"], unscanned>
unscanned: unscanned
}>
: state.error<writeUnmatchedGroupCloseMessage<unscanned>>
? from<{
groups: stack
branches: top
root: mergeToUnion<s>
finalizer: s["finalizer"]
scanned: updateScanned<s["scanned"], s["unscanned"], unscanned>
unscanned: unscanned
}>
: state.error<writeUnmatchedGroupCloseMessage<unscanned>>

@@ -280,11 +278,11 @@ export type reduceGroupOpen<

: s["branches"]["prefixes"] extends [
...unknown[],
infer tail extends string
]
? tail
: s["branches"]["&"] extends {}
? "&"
: s["branches"]["|"] extends {}
? "|"
: undefined
...unknown[],
infer tail extends string
]
? tail
: s["branches"]["&"] extends {}
? "&"
: s["branches"]["|"] extends {}
? "|"
: undefined

@@ -291,0 +289,0 @@ export type scanTo<s extends StaticState, unscanned extends string> = from<{

@@ -0,7 +1,4 @@

import type { DateLiteral } from "@arktype/schema"
import { throwParseError, tryParseNumber } from "@arktype/util"
export type DateLiteral<source extends string = string> =
| `d"${source}"`
| `d'${source}'`
export const isDateLiteral = (value: unknown): value is DateLiteral =>

@@ -8,0 +5,0 @@ typeof value === "string" &&

@@ -1,6 +0,5 @@

import { node } from "@arktype/schema"
import { schema, type RegexLiteral } from "@arktype/schema"
import { isKeyOf } from "@arktype/util"
import type { RegexLiteral } from "../../../semantic/semantic.js"
import type { DynamicState } from "../../reduce/dynamic.js"
import type { state, StaticState } from "../../reduce/static.js"
import type { StaticState, state } from "../../reduce/static.js"
import type { Scanner } from "../scanner.js"

@@ -34,8 +33,8 @@ import { tryParseDate, writeInvalidDateMessage } from "./date.js"

new RegExp(enclosed)
s.root = node({ basis: "string", pattern: token as RegexLiteral })
s.root = schema({ basis: "string", pattern: token as RegexLiteral })
} else if (isKeyOf(enclosing, enclosingQuote)) {
s.root = node({ is: enclosed })
s.root = schema({ unit: enclosed })
} else {
const date = tryParseDate(enclosed, writeInvalidDateMessage(enclosed))
s.root = node({ is: date, description: token })
s.root = schema({ unit: date, description: token })
}

@@ -42,0 +41,0 @@ }

@@ -18,12 +18,12 @@ import type { DynamicState } from "../../reduce/dynamic.js"

: s.scanner.lookahead === "("
? s.shiftedByOne().reduceGroupOpen()
: s.scanner.lookaheadIsIn(enclosingChar)
? parseEnclosed(s, s.scanner.shift())
: s.scanner.lookaheadIsIn(Scanner.whiteSpaceTokens)
? parseOperand(s.shiftedByOne())
: s.scanner.lookahead === "d"
? s.shiftedByOne().scanner.lookaheadIsIn(enclosingChar)
? parseEnclosed(s, `d${s.scanner.shift()}` as EnclosingStartToken)
: parseUnenclosed(s)
: parseUnenclosed(s)
? s.shiftedByOne().reduceGroupOpen()
: s.scanner.lookaheadIsIn(enclosingChar)
? parseEnclosed(s, s.scanner.shift())
: s.scanner.lookaheadIsIn(Scanner.whiteSpaceTokens)
? parseOperand(s.shiftedByOne())
: s.scanner.lookahead === "d"
? s.shiftedByOne().scanner.lookaheadIsIn(enclosingChar)
? parseEnclosed(s, `d${s.scanner.shift()}` as EnclosingStartToken)
: parseUnenclosed(s)
: parseUnenclosed(s)

@@ -38,13 +38,13 @@ export type parseOperand<

: lookahead extends EnclosingEndToken
? parseEnclosed<s, lookahead, unscanned>
: lookahead extends Scanner.WhiteSpaceToken
? parseOperand<state.scanTo<s, unscanned>, $, args>
: lookahead extends "d"
? unscanned extends Scanner.shift<
infer enclosing extends EnclosingQuote,
infer nextUnscanned
>
? parseEnclosed<s, `d${enclosing}`, nextUnscanned>
: parseUnenclosed<s, $, args>
: parseUnenclosed<s, $, args>
? parseEnclosed<s, lookahead, unscanned>
: lookahead extends Scanner.WhiteSpaceToken
? parseOperand<state.scanTo<s, unscanned>, $, args>
: lookahead extends "d"
? unscanned extends Scanner.shift<
infer enclosing extends EnclosingQuote,
infer nextUnscanned
>
? parseEnclosed<s, `d${enclosing}`, nextUnscanned>
: parseUnenclosed<s, $, args>
: parseUnenclosed<s, $, args>
: state.completion<`${s["scanned"]}${BaseCompletions<$, args>}`>

@@ -1,4 +0,4 @@

import { isNode, node, type Root } from "@arktype/schema"
import { BaseType, schema, type TypeNode } from "@arktype/schema"
import {
stringify,
printable,
throwParseError,

@@ -14,12 +14,4 @@ tryParseNumber,

import type { Module } from "../../../../scope.js"
import {
hasArkKind,
type Generic,
type GenericProps
} from "../../../../type.js"
import {
parseGenericArgs,
writeInvalidGenericArgsMessage,
type ParsedArgs
} from "../../../generic.js"
import type { Generic, GenericProps } from "../../../../type.js"
import { hasArkKind } from "../../../../util.js"
import type { GenericInstantiationAst } from "../../../semantic/semantic.js"

@@ -30,2 +22,7 @@ import type { DynamicState } from "../../reduce/dynamic.js"

import type { Scanner } from "../scanner.js"
import {
parseGenericArgs,
writeInvalidGenericArgsMessage,
type ParsedArgs
} from "./genericArgs.js"

@@ -51,16 +48,16 @@ export const parseUnenclosed = (s: DynamicState) => {

: tryResolve<s, token, $, args> extends infer result
? result extends ErrorMessage<infer message>
? state.error<message>
: result extends keyof $
? $[result] extends GenericProps
? parseGenericInstantiation<
token,
$[result],
state.scanTo<s, unscanned>,
$,
args
>
: state.setRoot<s, result, unscanned>
: state.setRoot<s, result, unscanned>
: never
? result extends ErrorMessage<infer message>
? state.error<message>
: result extends keyof $
? $[result] extends GenericProps
? parseGenericInstantiation<
token,
$[result],
state.scanTo<s, unscanned>,
$,
args
>
: state.setRoot<s, result, unscanned>
: state.setRoot<s, result, unscanned>
: never
: never

@@ -72,3 +69,3 @@

s: DynamicState
) => {
): TypeNode => {
s.scanner.shiftUntilNonWhitespace()

@@ -79,8 +76,3 @@ const lookahead = s.scanner.shift()

}
const parsedArgs = parseGenericArgs(
name,
g.parameters,
s.scanner.unscanned,
s.ctx
)
const parsedArgs = parseGenericArgs(name, g.parameters, s)
const remainingChars = parsedArgs.unscanned.length

@@ -91,3 +83,3 @@ // set the scanner position to where the args scanner left off

)
return g(...parsedArgs.result).root
return g(...parsedArgs.result).root as never
}

@@ -117,3 +109,3 @@

const unenclosedToNode = (s: DynamicState, token: string): Root =>
const unenclosedToNode = (s: DynamicState, token: string): TypeNode =>
maybeParseReference(s, token) ??

@@ -130,3 +122,3 @@ maybeParseUnenclosedLiteral(s, token) ??

token: string
): Root | undefined => {
): TypeNode | undefined => {
if (s.ctx.args?.[token]) {

@@ -136,3 +128,3 @@ return s.ctx.args[token]

const resolution = s.ctx.scope.maybeResolve(token)
if (isNode(resolution)) {
if (resolution instanceof BaseType) {
return resolution

@@ -146,3 +138,3 @@ }

}
return throwParseError(`Unexpected resolution ${stringify(resolution)}`)
return throwParseError(`Unexpected resolution ${printable(resolution)}`)
}

@@ -153,10 +145,10 @@

token: string
): Root | undefined => {
): TypeNode | undefined => {
const maybeNumber = tryParseNumber(token, { strict: true })
if (maybeNumber !== undefined) {
return node({ is: maybeNumber })
return schema({ unit: maybeNumber })
}
const maybeBigint = tryParseWellFormedBigint(token)
if (maybeBigint !== undefined) {
return node({ is: maybeBigint })
return schema({ unit: maybeBigint })
}

@@ -173,27 +165,21 @@ }

: token extends keyof args
? token
: token extends NumberLiteral
? token
: token extends BigintLiteral
? token
: token extends `${infer submodule extends keyof $ &
string}.${infer reference}`
? $[submodule] extends Module<infer r>
? reference extends keyof r["exports"]
? token
: unknown extends r["exports"]
? // not sure why I need the additional check here, but for now TS seems to
// hit this branch for a non-scope dot access rather than failing
// initially when we try to infer r. if this can be removed without breaking
// any submodule test cases, do it!
ErrorMessage<writeNonSubmoduleDotMessage<submodule>>
: unresolvableError<
s,
reference,
$[submodule],
args,
[submodule]
>
: ErrorMessage<writeNonSubmoduleDotMessage<submodule>>
: unresolvableError<s, token, $, args, []>
? token
: token extends NumberLiteral
? token
: token extends BigintLiteral
? token
: token extends `${infer submodule extends keyof $ &
string}.${infer reference}`
? $[submodule] extends Module<infer r>
? reference extends keyof r["exports"]
? token
: unknown extends r["exports"]
? // not sure why I need the additional check here, but for now TS seems to
// hit this branch for a non-scope dot access rather than failing
// initially when we try to infer r. if this can be removed without breaking
// any submodule test cases, do it!
ErrorMessage<writeNonSubmoduleDotMessage<submodule>>
: unresolvableError<s, reference, $[submodule], args, [submodule]>
: ErrorMessage<writeNonSubmoduleDotMessage<submodule>>
: unresolvableError<s, token, $, args, []>

@@ -203,6 +189,6 @@ export const writeNonSubmoduleDotMessage = <name extends string>(

): writeNonSubmoduleDotMessage<name> =>
`'${name}' must reference a scope to be accessed using dot syntax`
`'${name}' must reference a module to be accessed using dot syntax`
type writeNonSubmoduleDotMessage<name extends string> =
`'${name}' must reference a scope to be accessed using dot syntax`
`'${name}' must reference a module to be accessed using dot syntax`

@@ -209,0 +195,0 @@ export const writeMissingSubmoduleAccessMessage = <name extends string>(

@@ -1,3 +0,14 @@

import type { MinSchema } from "@arktype/schema"
import { isKeyOf, tryParseNumber, type keySet } from "@arktype/util"
import {
keywords,
type BoundKind,
type LimitSchemaValue,
type Schema,
type TypeNode
} from "@arktype/schema"
import {
isKeyOf,
throwParseError,
tryParseNumber,
type keySet
} from "@arktype/util"
import type { astToString } from "../../../semantic/utils.js"

@@ -9,12 +20,12 @@ import type {

import {
maxComparators,
writeUnpairableComparatorMessage,
type Comparator,
type LimitLiteral,
type MaxComparator,
type OpenLeftBound
} from "../../reduce/shared.js"
import type { StaticState, state } from "../../reduce/static.js"
import {
extractDateLiteralSource,
isDateLiteral,
type DateLiteral
} from "../operand/date.js"
import { parseOperand } from "../operand/operand.js"
import { extractDateLiteralSource, isDateLiteral } from "../operand/date.js"
import type { parseOperand } from "../operand/operand.js"
import type { Scanner } from "../scanner.js"

@@ -28,10 +39,10 @@

if (s.root.kind === "unit") {
if (typeof s.root.is === "number") {
if (typeof s.root.unit === "number") {
s.unsetRoot()
return s.reduceLeftBound(s.root.is, comparator)
return s.reduceLeftBound(s.root.unit, comparator)
}
if (s.root.is instanceof Date) {
if (s.root.unit instanceof Date) {
s.unsetRoot()
const literal = `d'${
s.root.description ?? s.root.is.toISOString()
s.root.description ?? s.root.unit.toISOString()
}'` as const

@@ -61,26 +72,2 @@ return s.reduceLeftBound(literal, comparator)

export const minComparators = {
">": true,
">=": true
} as const
export type MinComparator = keyof typeof minComparators
export const maxComparators = {
"<": true,
"<=": true
} as const
export type MaxComparator = keyof typeof maxComparators
export const comparators = {
...minComparators,
...maxComparators,
"==": true
}
export type Comparator = keyof typeof comparators
export type LimitLiteral = number | DateLiteral
const oneCharComparators = {

@@ -110,4 +97,4 @@ "<": true,

: isKeyOf(start, oneCharComparators)
? start
: s.error(singleEqualsMessage)
? start
: s.error(singleEqualsMessage)

@@ -120,10 +107,64 @@ type shiftComparator<

: start extends OneCharComparator
? [start, unscanned]
: state.error<singleEqualsMessage>
? [start, unscanned]
: state.error<singleEqualsMessage>
export const writeUnboundableMessage = <root extends string>(
root: root
): writeUnboundableMessage<root> =>
`Bounded expression ${root} must be a number, string, Array, or Date`
export type writeUnboundableMessage<root extends string> =
`Bounded expression ${root} must be a number, string, Array, or Date`
export const writeIncompatibleRangeMessage = (l: BoundKind, r: BoundKind) =>
`Bound kinds ${l} and ${r} are incompatible`
export const writeLimitMismatchMessage = (
root: string,
limitValue: LimitSchemaValue
) => `Limit '${limitValue}' cannot bound ${root}`
export const getBoundKinds = (
comparator: Comparator,
limit: LimitSchemaValue,
root: TypeNode
): BoundKind[] => {
if (root.extends(keywords.number)) {
if (typeof limit !== "number") {
return throwParseError(writeLimitMismatchMessage(root.toString(), limit))
}
return comparator === "=="
? ["min", "max"]
: comparator[0] === ">"
? ["min"]
: ["max"]
}
if (root.extends(keywords.string) || root.extends(keywords.Array)) {
if (typeof limit !== "number") {
return throwParseError(writeLimitMismatchMessage(root.toString(), limit))
}
return comparator === "=="
? ["minLength", "maxLength"]
: comparator[0] === ">"
? ["minLength"]
: ["maxLength"]
}
if (root.extends(keywords.Date)) {
// allow either numeric or date limits
return comparator === "=="
? ["after", "before"]
: comparator[0] === ">"
? ["after"]
: ["before"]
}
return throwParseError(writeUnboundableMessage(root.toString()))
}
export const singleEqualsMessage = `= is not a valid comparator. Use == to check for equality`
type singleEqualsMessage = typeof singleEqualsMessage
const openLeftBoundToSchema = (leftBound: OpenLeftBound): MinSchema => ({
min: isDateLiteral(leftBound.limit)
const openLeftBoundToSchema = (
leftBound: OpenLeftBound
): Schema<BoundKind> => ({
limit: isDateLiteral(leftBound.limit)
? extractDateLiteralSource(leftBound.limit)

@@ -134,3 +175,2 @@ : leftBound.limit,

// TODO: allow numeric limits for Dates?
export const parseRightBound = (

@@ -143,3 +183,3 @@ s: DynamicStateWithRoot,

const previousScannerIndex = s.scanner.location
parseOperand(s)
s.parseOperand()
// after parsing the next operand, use the locations to get the

@@ -159,9 +199,6 @@ // token from which it was parsed

const exclusive = comparator.length === 1
// if the comparator is ==, both max and min will be applied
if (comparator[0] !== ">") {
s.constrainRoot("max", { max: limit, exclusive })
// if the comparator is ==, both the min and max of that pair will be applied
for (const kind of getBoundKinds(comparator, limit, previousRoot)) {
s.constrainRoot(kind, { limit, exclusive })
}
if (comparator[0] !== "<") {
s.constrainRoot("min", { min: limit, exclusive })
}
if (!s.branches.leftBound) {

@@ -174,3 +211,11 @@ return

}
s.constrainRoot("min", openLeftBoundToSchema(s.branches.leftBound))
const lowerBoundKind = getBoundKinds(
s.branches.leftBound.comparator,
s.branches.leftBound.limit,
previousRoot
)
s.constrainRoot(
lowerBoundKind[0],
openLeftBoundToSchema(s.branches.leftBound)
)
delete s.branches.leftBound

@@ -210,3 +255,3 @@ }

limit extends string | number,
boundKind extends BoundKind
boundKind extends BoundExpressionKind
>(

@@ -224,3 +269,3 @@ comparator: comparator,

limit extends string | number,
boundKind extends BoundKind
boundKind extends BoundExpressionKind
> = `Comparator ${comparator} must be ${boundKind extends "left"

@@ -230,12 +275,2 @@ ? "preceded"

export type BoundKind = "left" | "right"
export const invertedComparators = {
"<": ">",
">": "<",
"<=": ">=",
">=": "<=",
"==": "=="
} as const satisfies Record<Comparator, Comparator>
export type InvertedComparators = typeof invertedComparators
export type BoundExpressionKind = "left" | "right"

@@ -17,18 +17,18 @@ import { isKeyOf } from "@arktype/util"

: lookahead === "["
? s.scanner.shift() === "]"
? s.setRoot(s.root.array())
: s.error(incompleteArrayTokenMessage)
: lookahead === "|" || lookahead === "&"
? s.pushRootToBranch(lookahead)
: lookahead === ")"
? s.finalizeGroup()
: Scanner.lookaheadIsFinalizing(lookahead, s.scanner.unscanned)
? s.finalize(lookahead)
: isKeyOf(lookahead, comparatorStartChars)
? parseBound(s, lookahead)
: lookahead === "%"
? parseDivisor(s)
: lookahead === " "
? parseOperator(s)
: s.error(writeUnexpectedCharacterMessage(lookahead))
? s.scanner.shift() === "]"
? s.setRoot(s.root.array())
: s.error(incompleteArrayTokenMessage)
: lookahead === "|" || lookahead === "&"
? s.pushRootToBranch(lookahead)
: lookahead === ")"
? s.finalizeGroup()
: Scanner.lookaheadIsFinalizing(lookahead, s.scanner.unscanned)
? s.finalize(lookahead)
: isKeyOf(lookahead, comparatorStartChars)
? parseBound(s, lookahead)
: lookahead === "%"
? parseDivisor(s)
: lookahead === " "
? parseOperator(s)
: s.error(writeUnexpectedCharacterMessage(lookahead))
}

@@ -46,17 +46,17 @@

: lookahead extends "|" | "&"
? state.reduceBranch<s, lookahead, unscanned>
: lookahead extends ")"
? state.finalizeGroup<s, unscanned>
: Scanner.lookaheadIsFinalizing<lookahead, unscanned> extends true
? state.finalize<
state.scanTo<s, unscanned>,
lookahead & Scanner.FinalizingLookahead
>
: lookahead extends ComparatorStartChar
? parseBound<s, lookahead, unscanned, $, args>
: lookahead extends "%"
? parseDivisor<s, unscanned>
: lookahead extends Scanner.WhiteSpaceToken
? parseOperator<state.scanTo<s, unscanned>, $, args>
: state.error<writeUnexpectedCharacterMessage<lookahead>>
? state.reduceBranch<s, lookahead, unscanned>
: lookahead extends ")"
? state.finalizeGroup<s, unscanned>
: Scanner.lookaheadIsFinalizing<lookahead, unscanned> extends true
? state.finalize<
state.scanTo<s, unscanned>,
lookahead & Scanner.FinalizingLookahead
>
: lookahead extends ComparatorStartChar
? parseBound<s, lookahead, unscanned, $, args>
: lookahead extends "%"
? parseDivisor<s, unscanned>
: lookahead extends Scanner.WhiteSpaceToken
? parseOperator<state.scanTo<s, unscanned>, $, args>
: state.error<writeUnexpectedCharacterMessage<lookahead>>
: state.finalize<s, "">

@@ -63,0 +63,0 @@

import { isKeyOf, type Dict } from "@arktype/util"
import type { Comparator } from "./operator/bounds.js"
import type { Comparator } from "../reduce/shared.js"

@@ -160,9 +160,9 @@ export class Scanner<Lookahead extends string = string> {

: Scanner.skipWhitespace<unscanned> extends
| ""
| `${TerminatingChar}${string}`
? true
: false
| ""
| `${TerminatingChar}${string}`
? true
: false
: lookahead extends ","
? true
: false
? true
: false

@@ -169,0 +169,0 @@ export type shift<

@@ -1,21 +0,17 @@

import type { Root } from "@arktype/schema"
import { throwParseError, type ErrorMessage } from "@arktype/util"
import type { ParseContext } from "../../scope.js"
import type { inferAst } from "../semantic/semantic.js"
import { writeUnsatisfiableExpressionError } from "../semantic/validate.js"
import { DynamicState, type DynamicStateWithRoot } from "./reduce/dynamic.js"
import type { TypeNode } from "@arktype/schema"
import {
throwInternalError,
throwParseError,
type ErrorMessage
} from "@arktype/util"
import type { inferAstRoot } from "../semantic/semantic.js"
import type { DynamicState, DynamicStateWithRoot } from "./reduce/dynamic.js"
import type { StringifiablePrefixOperator } from "./reduce/shared.js"
import type { StaticState, state } from "./reduce/static.js"
import { parseOperand } from "./shift/operand/operand.js"
import type { parseOperand } from "./shift/operand/operand.js"
import {
parseOperator,
writeUnexpectedCharacterMessage
writeUnexpectedCharacterMessage,
type parseOperator
} from "./shift/operator/operator.js"
export const parseString = (def: string, ctx: ParseContext): Root =>
ctx.scope.maybeResolveNode(def) ??
((def.endsWith("[]") &&
ctx.scope.maybeResolveNode(def.slice(0, -2))?.array()) ||
fullStringParse(def, ctx))
/**

@@ -30,8 +26,8 @@ * Try to parse the definition from right to left using the most common syntax.

: def extends `${infer child}[]`
? child extends keyof $
? [child, "[]"]
: fullStringParse<def, $, args>
: fullStringParse<def, $, args>
? child extends keyof $
? [child, "[]"]
: fullStringParse<state.initialize<def>, $, args>
: fullStringParse<state.initialize<def>, $, args>
export type inferString<def extends string, $, args> = inferAst<
export type inferString<def extends string, $, args> = inferAstRoot<
parseString<def, $, args>,

@@ -48,6 +44,10 @@ $,

export const fullStringParse = (def: string, ctx: ParseContext) => {
const s = new DynamicState(def, ctx)
parseOperand(s)
export const fullStringParse = (s: DynamicState): TypeNode => {
s.parseOperand()
const result = parseUntilFinalizer(s).root
if (!result) {
return throwInternalError(
`Root was unexpectedly unset after parsing string '${s.scanner.scanned}'`
)
}
s.scanner.shiftUntilNonWhitespace()

@@ -58,10 +58,7 @@ if (s.scanner.lookahead) {

}
// TODO: would this ever happen?
return result.isNever()
? throwParseError(writeUnsatisfiableExpressionError(def))
: result
return result
}
type fullStringParse<def extends string, $, args> = extractFinalizedResult<
parseUntilFinalizer<state.initialize<def>, $, args>
type fullStringParse<s extends StaticState, $, args> = extractFinalizedResult<
parseUntilFinalizer<s, $, args>
>

@@ -85,3 +82,3 @@

const next = (s: DynamicState) =>
s.hasRoot() ? parseOperator(s) : parseOperand(s)
s.hasRoot() ? s.parseOperator() : s.parseOperand()

@@ -96,3 +93,3 @@ type next<s extends StaticState, $, args> = s["root"] extends undefined

: s["finalizer"] extends ""
? s["root"]
: state.error<writeUnexpectedCharacterMessage<`${s["finalizer"]}`>>
? s["root"]
: state.error<writeUnexpectedCharacterMessage<`${s["finalizer"]}`>>
import {
builtins,
node,
type BaseAttributes,
keywords,
schema,
type BaseMeta,
type Morph,
type Out,
type Predicate,
type Root,
type Schema,
type TypeNode,
type ValidatorKind,
type extractIn,
type extractOut,
type inferMorphOut,

@@ -15,3 +19,3 @@ type inferNarrow

objectKindOrDomainOf,
stringify,
printable,
throwParseError,

@@ -27,3 +31,2 @@ type BuiltinObjectKind,

import type { ParseContext } from "../scope.js"
import type { extractIn, extractOut } from "../type.js"
import type { inferDefinition, validateDefinition } from "./definition.js"

@@ -44,3 +47,3 @@ import type { inferIntersection } from "./semantic/intersections.js"

export const parseTupleLiteral = (def: List, ctx: ParseContext): Root => {
export const parseTupleLiteral = (def: List, ctx: ParseContext): TypeNode => {
const props: unknown[] = []

@@ -65,3 +68,3 @@ let isVariadic = false

if (isVariadic) {
if (!value.extends(builtins.array)) {
if (!value.extends(keywords.Array)) {
return throwParseError(writeNonArrayRestMessage(elementDef))

@@ -75,3 +78,3 @@ }

// TODO: first variadic i
props.push({ key: builtins.number, value: elementType })
props.push({ key: keywords.number, value: elementType })
} else {

@@ -97,7 +100,7 @@ props.push({

// , ctx
value: node({ is: def.length })
value: schema({ unit: def.length })
})
}
// props , ctx
return node(Array)
return schema(Array)
}

@@ -108,8 +111,8 @@

ctx: ParseContext
): Root | undefined => {
): TypeNode | undefined => {
const tupleExpressionResult = isIndexOneExpression(def)
? indexOneParsers[def[1]](def as never, ctx)
: isIndexZeroExpression(def)
? prefixParsers[def[0]](def as never, ctx)
: undefined
? prefixParsers[def[0]](def as never, ctx)
: undefined
if (tupleExpressionResult) {

@@ -120,3 +123,3 @@ return tupleExpressionResult.isNever()

def
.map((def) => (typeof def === "string" ? def : stringify(def)))
.map((def) => (typeof def === "string" ? def : printable(def)))
.join(" ")

@@ -141,17 +144,13 @@ )

: def extends PostfixExpression
? validatePostfixExpression<def, $, args>
: def extends InfixExpression
? validateInfixExpression<def, $, args>
: def extends
| readonly ["", ...unknown[]]
| readonly [unknown, "", ...unknown[]]
? readonly [
def[0] extends ""
? BaseCompletions<$, args, IndexZeroOperator>
: def[0],
def[1] extends ""
? BaseCompletions<$, args, IndexOneOperator>
: def[1]
]
: validateTupleLiteral<def, $, args>
? validatePostfixExpression<def, $, args>
: def extends InfixExpression
? validateInfixExpression<def, $, args>
: def extends
| readonly ["", ...unknown[]]
| readonly [unknown, "", ...unknown[]]
? readonly [
def[0] extends "" ? BaseCompletions<$, args, IndexZeroOperator> : def[0],
def[1] extends "" ? BaseCompletions<$, args, IndexOneOperator> : def[1]
]
: validateTupleLiteral<def, $, args>

@@ -199,6 +198,6 @@ export type validateTupleLiteral<

: isAny<result> extends true
? writeNonArrayRestMessage<operand>
: result extends readonly unknown[]
? operand
: writeNonArrayRestMessage<operand>
? writeNonArrayRestMessage<operand>
: result extends readonly unknown[]
? operand
: writeNonArrayRestMessage<operand>
: never

@@ -273,24 +272,24 @@

: def[1] extends "&"
? inferIntersection<
inferDefinition<def[0], $, args>,
inferDefinition<def[2], $, args>
>
: def[1] extends "|"
? inferDefinition<def[0], $, args> | inferDefinition<def[2], $, args>
: def[1] extends ":"
? inferNarrow<inferDefinition<def[0], $, args>, def[2]>
: def[1] extends "=>"
? parseMorph<def[0], def[2], $, args>
: def[1] extends "@"
? inferDefinition<def[0], $, args>
: def extends readonly ["===", ...infer values]
? values[number]
: def extends readonly [
"instanceof",
...infer constructors extends Constructor[]
]
? InstanceType<constructors[number]>
: def[0] extends "keyof"
? inferKeyOfExpression<def[1], $, args>
: never
? inferIntersection<
inferDefinition<def[0], $, args>,
inferDefinition<def[2], $, args>
>
: def[1] extends "|"
? inferDefinition<def[0], $, args> | inferDefinition<def[2], $, args>
: def[1] extends ":"
? inferNarrow<inferDefinition<def[0], $, args>, def[2]>
: def[1] extends "=>"
? parseMorph<def[0], def[2], $, args>
: def[1] extends "@"
? inferDefinition<def[0], $, args>
: def extends readonly ["===", ...infer values]
? values[number]
: def extends readonly [
"instanceof",
...infer constructors extends Constructor[]
]
? InstanceType<constructors[number]>
: def[0] extends "keyof"
? inferKeyOfExpression<def[1], $, args>
: never

@@ -304,8 +303,8 @@ export type validatePrefixExpression<

: def[0] extends "keyof"
? readonly [def[0], validateDefinition<def[1], $, args>]
: def[0] extends "==="
? readonly [def[0], ...unknown[]]
: def[0] extends "instanceof"
? readonly [def[0], ...Constructor[]]
: never
? readonly [def[0], validateDefinition<def[1], $, args>]
: def[0] extends "==="
? readonly [def[0], ...unknown[]]
: def[0] extends "instanceof"
? readonly [def[0], ...Constructor[]]
: never

@@ -332,10 +331,10 @@ export type validatePostfixExpression<

: def[1] extends "&"
? validateDefinition<def[2], $, args>
: def[1] extends ":"
? Predicate<extractIn<inferDefinition<def[0], $, args>>>
: def[1] extends "=>"
? Morph<extractOut<inferDefinition<def[0], $, args>>, unknown>
: def[1] extends "@"
? BaseAttributes | string
: validateDefinition<def[2], $, args>
? validateDefinition<def[2], $, args>
: def[1] extends ":"
? Predicate<extractIn<inferDefinition<def[0], $, args>>>
: def[1] extends "=>"
? Morph<extractOut<inferDefinition<def[0], $, args>>, unknown>
: def[1] extends "@"
? BaseMeta | string
: validateDefinition<def[2], $, args>
]

@@ -372,3 +371,3 @@

ctx: ParseContext
) => Root
) => TypeNode

@@ -378,3 +377,3 @@ export type PrefixParser<token extends IndexZeroOperator> = (

ctx: ParseContext
) => Root
) => TypeNode

@@ -404,15 +403,9 @@ export type TupleExpression = IndexZeroExpression | IndexOneExpression

}
// TODO: fix
return ctx.scope.parse(def[0], ctx) //.constrain("morph", def[2] as Morph)
// TODO: nested morphs?
return schema({
in: ctx.scope.parse(def[0], ctx) as Schema<ValidatorKind>,
morph: def[2] as Morph
})
}
export type parseMorph<inDef, morph, $, args> = morph extends Morph
? (
// TODO: should this be extractOut
In: extractIn<inferDefinition<inDef, $, args>>
) => Out<inferMorphOut<ReturnType<morph>>>
: never
export type MorphAst<i = any, o = any> = (In: i) => Out<o>
export const writeMalformedFunctionalExpressionMessage = (

@@ -426,2 +419,8 @@ operator: FunctionalTupleOperator,

export type parseMorph<inDef, morph, $, args> = morph extends Morph
? (
In: extractIn<inferDefinition<inDef, $, args>>
) => Out<inferMorphOut<ReturnType<morph>>>
: never
export const parseNarrowTuple: PostfixParser<":"> = (def, ctx) => {

@@ -465,3 +464,3 @@ if (typeof def[2] !== "function") {

keyof: parseKeyOfTuple,
instanceof: (def, ctx) => {
instanceof: (def) => {
if (typeof def[1] !== "function") {

@@ -476,3 +475,3 @@ return throwParseError(

typeof ctor === "function"
? { basis: ctor as Constructor }
? { proto: ctor as Constructor }
: throwParseError(

@@ -482,5 +481,5 @@ writeInvalidConstructorMessage(objectKindOrDomainOf(ctor))

)
return node(...branches)
return schema(...branches)
},
"===": (def) => node({ is: def.slice(1) })
"===": (def) => schema.units(...def.slice(1))
}

@@ -495,2 +494,2 @@

actual: actual
) => `Expected a constructor following 'instanceof' operator (was ${actual}).`
) => `Expected a constructor following 'instanceof' operator (was ${actual})`

@@ -1,8 +0,16 @@

import { builtins, type ProblemCode, type Root } from "@arktype/schema"
import {
BaseType,
keywords,
type ArkErrorCode,
type KeyCheckKind,
type TypeNode,
type extractIn,
type extractOut
} from "@arktype/schema"
import {
domainOf,
hasDomain,
isThunk,
map,
throwParseError,
transform,
type Dict,

@@ -13,9 +21,5 @@ type evaluate,

} from "@arktype/util"
import type { type } from "./ark.js"
import { createMatchParser, type MatchParser } from "./match.js"
import {
createMatchParser,
createWhenParser,
type MatchParser,
type WhenParser
} from "./match.js"
import {
parseObject,

@@ -31,2 +35,3 @@ writeBadDefinitionTypeMessage,

} from "./parser/generic.js"
import { DynamicState } from "./parser/string/reduce/dynamic.js"
import {

@@ -37,22 +42,16 @@ writeMissingSubmoduleAccessMessage,

} from "./parser/string/shift/operand/unenclosed.js"
import { parseString } from "./parser/string/string.js"
import type { type } from "./scopes/ark.js"
import { fullStringParse } from "./parser/string/string.js"
import {
addArkKind,
Type,
createTypeParser,
generic,
hasArkKind,
Type,
validateUninstantiatedGeneric,
type arkKind,
type DeclarationParser,
type DefinitionParser,
type extractIn,
type extractOut,
type Generic,
type GenericProps,
type KeyCheckKind,
type TypeConfig,
type TypeParser
} from "./type.js"
import { addArkKind, hasArkKind, type arkKind } from "./util.js"

@@ -77,3 +76,3 @@ export type ScopeParser<parent, ambient> = {

ambient?: Scope | null
codes?: Record<ProblemCode, { mustBe?: string }>
codes?: Record<ArkErrorCode, { mustBe?: string }>
keys?: KeyCheckKind

@@ -89,14 +88,14 @@ }

: parseScopeKey<k>["params"] extends GenericParamsParseError
? // use the full nominal type here to avoid an overlap between the
// error message and a possible value for the property
parseScopeKey<k>["params"][0]
: validateDefinition<
def[k],
$ & bootstrap<def>,
{
// once we support constraints on generic parameters, we'd use
// the base type here: https://github.com/arktypeio/arktype/issues/796
[param in parseScopeKey<k>["params"][number]]: unknown
}
>
? // use the full nominal type here to avoid an overlap between the
// error message and a possible value for the property
parseScopeKey<k>["params"][0]
: validateDefinition<
def[k],
$ & bootstrap<def>,
{
// once we support constraints on generic parameters, we'd use
// the base type here: https://github.com/arktypeio/arktype/issues/796
[param in parseScopeKey<k>["params"][number]]: unknown
}
>
}

@@ -106,7 +105,2 @@

export const bindThis = () => ({
// TODO: fix
this: builtins.unknown
})
/** nominal type for an unparsed definition used during scope bootstrapping */

@@ -141,4 +135,4 @@ type Def<def = {}> = nominal<def, "unparsed">

: def[k] extends (() => infer thunkReturn extends PreparsedResolution)
? thunkReturn
: Def<def[k]>
? thunkReturn
: Def<def[k]>
} & {

@@ -156,6 +150,6 @@ [k in keyof def & GenericDeclaration as extractGenericName<k>]: Generic<

: r["exports"][name] extends GenericProps<infer params, infer def>
? // add the scope in which the generic was defined here
Generic<params, def, $<r>>
: // otherwise should be a submodule
r["exports"][name]
? // add the scope in which the generic was defined here
Generic<params, def, $<r>>
: // otherwise should be a submodule
r["exports"][name]
}>

@@ -186,6 +180,6 @@

: isAny<resolution> extends true
? any
: resolution extends Def<infer def>
? inferDefinition<def, $, args>
: resolution
? any
: resolution extends Def<infer def>
? inferDefinition<def, $, args>
: resolution
: never

@@ -216,6 +210,6 @@

: isAny<r["exports"][k]> extends true
? Type<any, $<r>>
: r["exports"][k] extends PreparsedResolution
? r["exports"][k]
: Type<r["exports"][k], $<r>>
? Type<any, $<r>>
: r["exports"][k] extends PreparsedResolution
? r["exports"][k]
: Type<r["exports"][k], $<r>>
: // set the nominal symbol's value to something validation won't care about

@@ -236,6 +230,6 @@ // since the inferred type will be omitted anyways

scope: Scope
args: Record<string, Root> | undefined
args: Record<string, TypeNode> | undefined
}
type MergedResolutions = Record<string, Root | Generic>
type MergedResolutions = Record<string, TypeNode | Generic>

@@ -250,3 +244,3 @@ type ParseContextInput = Pick<ParseContext, "baseName" | "args">

private parseCache: Record<string, Root> = {}
private parseCache: Record<string, TypeNode> = {}
private resolutions: MergedResolutions

@@ -259,3 +253,2 @@

private ambient: Scope | null
private references: Root[] = []

@@ -291,4 +284,2 @@ constructor(def: Dict, config: ScopeConfig) {

when: WhenParser<$<r>> = createWhenParser(this as never) as never
// TODO: decide if this API will be used for non-validated types

@@ -341,3 +332,3 @@ declare: DeclarationParser<$<r>> = () => ({ type: this.type }) as never

parse(def: unknown, ctx: ParseContext): Root {
parse(def: unknown, ctx: ParseContext): TypeNode {
if (typeof def === "string") {

@@ -347,6 +338,6 @@ if (ctx.args !== undefined) {

// resolutions like "this" or generic args
return parseString(def, ctx)
return this.parseString(def, ctx)
}
if (!this.parseCache[def]) {
this.parseCache[def] = parseString(def, ctx)
this.parseCache[def] = this.parseString(def, ctx)
}

@@ -360,3 +351,12 @@ return this.parseCache[def]

maybeResolve(name: string): Root | Generic | undefined {
parseString(def: string, ctx: ParseContext): TypeNode {
return (
this.maybeResolveNode(def) ??
((def.endsWith("[]") &&
this.maybeResolveNode(def.slice(0, -2))?.array()) ||
fullStringParse(new DynamicState(def, ctx)))
)
}
maybeResolve(name: string): TypeNode | Generic | undefined {
const cached = this.resolutions[name]

@@ -377,7 +377,7 @@ if (cached) {

: hasArkKind(def, "module")
? throwParseError(writeMissingSubmoduleAccessMessage(name))
: this.parseDefinition(
def,
this.createRootContext({ baseName: name, args: {} })
)
? throwParseError(writeMissingSubmoduleAccessMessage(name))
: this.parseDefinition(
def,
this.createRootContext({ baseName: name, args: {} })
)
this.resolutions[name] = resolution

@@ -412,5 +412,5 @@ return resolution

maybeResolveNode(name: string): Root | undefined {
maybeResolveNode(name: string): TypeNode | undefined {
const result = this.maybeResolve(name)
return hasArkKind(result, "node") ? (result as never) : undefined
return result instanceof BaseType ? (result as never) : undefined
}

@@ -422,7 +422,7 @@

r,
names extends [] ? keyof r["exports"] : names[number]
names extends [] ? keyof r["exports"] & string : names[number]
> {
return addArkKind(
transform(this.export(...names), ([alias, value]) => [
`#${alias as string}`,
map(this.export(...names) as Dict, (alias, value) => [
`#${alias}`,
value

@@ -437,3 +437,3 @@ ]) as never,

// this.export()
// const references: Set<TypeNode> = new Set()
// const references: Set<Root> = new Set()
// for (const k in this.exportedResolutions!) {

@@ -457,2 +457,7 @@ // const resolution = this.exportedResolutions[k]

bindThis() {
// TODO: fix
return { this: keywords.unknown }
}
private exportedResolutions: MergedResolutions | undefined

@@ -490,6 +495,3 @@ private exportCache: ExportCache | undefined

return addArkKind(
transform(namesToExport, ([, name]) => [
name,
this.exportCache![name]
]) as never,
map(namesToExport, (_, name) => [name, this.exportCache![name]]) as never,
"module"

@@ -508,6 +510,6 @@ ) as never

const innerResolutions = resolutionsOfModule(v as never)
const prefixedResolutions = transform(
innerResolutions,
([innerK, innerV]) => [`${k}.${innerK}`, innerV]
)
const prefixedResolutions = map(innerResolutions, (innerK, innerV) => [
`${k}.${innerK}`,
innerV
])
Object.assign(result, prefixedResolutions)

@@ -517,4 +519,3 @@ } else if (hasArkKind(v, "generic")) {

} else {
// TODO: needed?
result[k] = v.root as never
result[k] = (v as Type).root
}

@@ -521,0 +522,0 @@ }

import {
In,
TraversalState,
arkKind,
builtins,
inferred,
registry,
type BaseAttributes,
type CheckResult,
keywords,
type ArkResult,
type BaseMeta,
type KeyCheckKind,
type Morph,
type Out,
type Predicate,
type Root,
type UnknownNode,
type TypeNode,
type distill,
type extractIn,
type extractOut,
type includesMorphs,
type inferMorphOut,

@@ -19,9 +19,7 @@ type inferNarrow

import {
CompiledFunction,
transform,
type BuiltinObjectKind,
type BuiltinObjects,
Callable,
CastableBase,
map,
type Constructor,
type Json,
type Primitive,
type conform

@@ -42,6 +40,6 @@ } from "@arktype/util"

IndexZeroOperator,
MorphAst,
TupleInfixOperator
} from "./parser/tuple.js"
import { bindThis, type Module, type Scope } from "./scope.js"
import type { Scope, bindThis } from "./scope.js"
import { arkKind } from "./util.js"

@@ -59,20 +57,20 @@ export type TypeParser<$> = {

: zero extends "instanceof"
? conform<one, Constructor>
: zero extends "==="
? conform<one, unknown>
: conform<one, IndexOneOperator>,
? conform<one, Constructor>
: zero extends "==="
? conform<one, unknown>
: conform<one, IndexOneOperator>,
..._2: zero extends "==="
? rest
: zero extends "instanceof"
? conform<rest, readonly Constructor[]>
: one extends TupleInfixOperator
? one extends ":"
? [Predicate<extractIn<inferTypeRoot<zero, $>>>]
: one extends "=>"
? // TODO: centralize
[Morph<extractOut<inferTypeRoot<zero, $>>, unknown>]
: one extends "@"
? [string | BaseAttributes]
: [validateTypeRoot<rest[0], $>]
: []
? conform<rest, readonly Constructor[]>
: one extends TupleInfixOperator
? one extends ":"
? [Predicate<extractIn<inferTypeRoot<zero, $>>>]
: one extends "=>"
? // TODO: centralize
[Morph<extractOut<inferTypeRoot<zero, $>>, unknown>]
: one extends "@"
? [string | BaseMeta]
: [validateTypeRoot<rest[0], $>]
: []
): Type<inferTypeRoot<[zero, one, ...rest], $>, $>

@@ -125,26 +123,2 @@

export type ArkKinds = {
node: UnknownNode
generic: Generic
module: Module
}
export const addArkKind = <kind extends ArkKind>(
value: Omit<ArkKinds[kind], arkKind> & { [arkKind]?: kind },
kind: kind
): ArkKinds[kind] =>
Object.defineProperty(value, arkKind, {
value: kind,
enumerable: false
}) as never
export type arkKind = typeof arkKind
export type ArkKind = keyof ArkKinds
export const hasArkKind = <kind extends ArkKind>(
value: unknown,
kind: kind
): value is ArkKinds[kind] => (value as any)?.[arkKind] === kind
export type DefinitionParser<$> = <def>(

@@ -154,4 +128,2 @@ def: validateDefinition<def, $, bindThis<def>>

export type KeyCheckKind = "distilled" | "strict" | "loose"
export type TypeConfig = {

@@ -162,17 +134,13 @@ keys?: KeyCheckKind

registry().register(TraversalState, "state")
export class Type<t = unknown, $ = any> extends CompiledFunction<
(data: unknown) => CheckResult<extractOut<t>>
export class Type<t = unknown, $ = any> extends Callable<
(data: unknown) => ArkResult<distill<extractOut<t>>>
> {
declare [inferred]: t
declare inferMorph: t
declare infer: extractOut<t>
declare inferIn: extractIn<t>
// TODO: in/out?
declare infer: distill<extractOut<t>>
config: TypeConfig
root: Root<t>
condition = ""
alias: string
root: TypeNode<t>
allows: this["root"]["allows"]
expected: string
json: Json

@@ -184,15 +152,9 @@

) {
const root = parseTypeRoot(definition, scope) as Root<t>
super(In, `return true ? { data: ${In} } : { problems: [] } `)
// const state = new ${registry().reference("state")}();
// const morphs = [];
// for(let i = 0; i < morphs.length; i++) {
// morphs[i]()
// }
// return state.finalize(${In});
const root = parseTypeRoot(definition, scope) as TypeNode<t>
super(root.apply, root)
this.root = root
this.allows = root.allows
this.config = scope.config
this.json = this.root.json
this.alias = this.root.alias
this.json = root.json
this.expected = this.root.description
}

@@ -206,10 +168,6 @@

// TODO: should return out
from(literal: this["infer"]) {
from(literal: this["in"]["infer"]) {
return literal
}
fromIn(literal: this["inferIn"]) {
return literal
}
// TODO: Morph intersections, ordering

@@ -232,10 +190,11 @@ and<def>(

morph<morph extends Morph<extractOut<t>>>(
// TODO: standardize these
morph<morph extends Morph<this["infer"]>>(
morph: morph
): Type<(In: this["inferIn"]) => Out<inferMorphOut<ReturnType<morph>>>, $>
morph<morph extends Morph<extractOut<t>>, def>(
): Type<(In: this["in"]["infer"]) => Out<inferMorphOut<ReturnType<morph>>>, $>
morph<morph extends Morph<this["infer"]>, def>(
morph: morph,
outValidator: validateTypeRoot<def, $>
): Type<
(In: this["inferIn"]) => Out<
(In: this["in"]["infer"]) => Out<
// TODO: validate overlapping

@@ -262,3 +221,3 @@ // inferMorphOut<ReturnType<morph>> &

includesMorphs<t> extends true
? (In: this["inferIn"]) => Out<inferNarrow<this["infer"], def>>
? (In: this["in"]["infer"]) => Out<inferNarrow<this["infer"], def>>
: inferNarrow<this["infer"], def>,

@@ -274,23 +233,41 @@ $

keyof(): Type<keyof this["inferIn"], $> {
keyof(): Type<keyof this["in"]["infer"], $> {
return new Type(this.root.keyof(), this.scope) as never
}
assert(data: unknown): extractOut<t> {
assert(data: unknown): this["infer"] {
const result = this.call(null, data)
return result.problems ? result.problems.throw() : result.data
return result.errors ? result.errors.throw() : result.out
}
// TODO: parse these
equals<other>(other: Type<other>): this is Type<other, $> {
return this.root === (other.root as unknown)
equals<def>(
other: validateTypeRoot<def, $>
): this is Type<inferTypeRoot<def, $>, $> {
return this.root.equals(parseTypeRoot(other, this.scope))
}
extends<other>(other: Type<other>): this is Type<other, $> {
return this.root.extends(other.root)
extends<def>(
other: validateTypeRoot<def, $>
): this is Type<inferTypeRoot<def, $>, $> {
return this.root.extends(parseTypeRoot(other, this.scope))
}
private inCache?: Type<extractIn<t>, $>;
get in() {
this.inCache ??= new Type(this.root.in, this.scope) as never
return this.inCache
}
outCache?: Type<extractOut<t>, $>
get out() {
this.outCache ??= new Type(this.root.out, this.scope) as never
return this.outCache
}
}
const parseTypeRoot = (def: unknown, scope: Scope, args?: BoundArgs) =>
scope.parseDefinition(def, { args: args ?? bindThis(), baseName: "type" })
scope.parseDefinition(def, {
args: args ?? scope.bindThis(),
baseName: "type"
})

@@ -315,3 +292,3 @@ export type validateTypeRoot<def, $> = validateDefinition<def, $, bindThis<def>>

baseName: "generic",
args: transform(g.parameters, ([, name]) => [name, builtins.unknown])
args: map(g.parameters, (_, name) => [name, keywords.unknown])
}

@@ -329,3 +306,3 @@ )

(...args: unknown[]) => {
const argNodes = transform(parameters, ([i, param]) => [
const argNodes = map(parameters, (i, param) => [
param,

@@ -360,3 +337,3 @@ parseTypeRoot(args[i], scope)

export type BoundArgs = Record<string, Root>
export type BoundArgs = Record<string, TypeNode>

@@ -385,34 +362,1 @@ // TODO: Fix external reference (i.e. if this is attached to a scope, then args are defined using it)

}
export type extractIn<t> = includesMorphs<t> extends true
? extractMorphs<t, "in">
: t
export type extractOut<t> = includesMorphs<t> extends true
? extractMorphs<t, "out">
: t
type includesMorphs<t> = [
t,
extractMorphs<t, "in">,
t,
extractMorphs<t, "out">
] extends [extractMorphs<t, "in">, t, extractMorphs<t, "out">, t]
? false
: true
type extractMorphs<t, io extends "in" | "out"> = t extends MorphAst<
infer i,
infer o
>
? io extends "in"
? i
: o
: t extends TerminallyInferredObjectKind | Primitive
? t
: { [k in keyof t]: extractMorphs<t[k], io> }
/** Objects we don't want to expand during inference like Date or Promise */
type TerminallyInferredObjectKind =
| ReturnType<ArkConfig["preserve"]>
| BuiltinObjects[Exclude<BuiltinObjectKind, "Object" | "Array">]
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc