Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add JTDDataType to compile signature #1547

Merged
merged 2 commits into from
Apr 15, 2021
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
16 changes: 14 additions & 2 deletions lib/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export {KeywordCxt} from "./compile/validate"
export {DefinedError} from "./vocabularies/errors"
export {JSONType} from "./compile/rules"
export {JSONSchemaType} from "./types/json-schema"
export {JTDSchemaType} from "./types/jtd-schema"
export {JTDSchemaType, SomeJTDSchemaType, JTDDataType} from "./types/jtd-schema"
export {_, str, stringify, nil, Name, Code, CodeGen, CodeGenOptions} from "./compile/codegen"

import type {
Expand All @@ -50,7 +50,7 @@ import type {
AddedFormat,
} from "./types"
import type {JSONSchemaType} from "./types/json-schema"
import type {JTDSchemaType} from "./types/jtd-schema"
import type {JTDSchemaType, SomeJTDSchemaType, JTDDataType} from "./types/jtd-schema"
import ValidationError from "./runtime/validation_error"
import MissingRefError from "./compile/ref_error"
import {getRules, ValidationRules, Rule, RuleGroup, JSONType} from "./compile/rules"
Expand Down Expand Up @@ -313,6 +313,12 @@ export default class Ajv {
// Separated for type inference to work
// eslint-disable-next-line @typescript-eslint/unified-signatures
validate<T>(schema: JTDSchemaType<T>, data: unknown): data is T
// This overload is only intended for typescript inference, the first
// argument prevents manual type annotation from matching this overload
validate<N extends never, T extends SomeJTDSchemaType>(
schema: T,
data: unknown
): data is JTDDataType<T>
validate<T>(schema: AsyncSchema, data: unknown | T): Promise<T>
validate<T>(schemaKeyRef: AnySchema | string, data: unknown): data is T | Promise<T>
validate<T>(
Expand All @@ -338,6 +344,12 @@ export default class Ajv {
// Separated for type inference to work
// eslint-disable-next-line @typescript-eslint/unified-signatures
compile<T = unknown>(schema: JTDSchemaType<T>, _meta?: boolean): ValidateFunction<T>
// This overload is only intended for typescript inference, the first
// argument prevents manual type annotation from matching this overload
compile<N extends never, T extends SomeJTDSchemaType>(
schema: T,
_meta?: boolean
): ValidateFunction<JTDDataType<T>>
compile<T = unknown>(schema: AsyncSchema, _meta?: boolean): AsyncValidateFunction<T>
compile<T = unknown>(schema: AnySchema, _meta?: boolean): AnyValidateFunction<T>
compile<T = unknown>(schema: AnySchema, _meta?: boolean): AnyValidateFunction<T> {
Expand Down
4 changes: 2 additions & 2 deletions lib/jtd.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type {AnySchemaObject, SchemaObject, JTDParser} from "./types"
import type {JTDSchemaType, JTDDataType} from "./types/jtd-schema"
import type {JTDSchemaType, SomeJTDSchemaType, JTDDataType} from "./types/jtd-schema"
import AjvCore, {CurrentOptions} from "./core"
import jtdVocabulary from "./vocabularies/jtd"
import jtdMetaSchema from "./refs/jtd-schema"
Expand Down Expand Up @@ -125,5 +125,5 @@ export {KeywordCxt} from "./compile/validate"
export {JTDErrorObject} from "./vocabularies/jtd"
export {_, str, stringify, nil, Name, Code, CodeGen, CodeGenOptions} from "./compile/codegen"

export {JTDSchemaType, JTDDataType}
export {JTDSchemaType, SomeJTDSchemaType, JTDDataType}
export {JTDOptions}
52 changes: 45 additions & 7 deletions lib/types/jtd-schema.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,45 @@
/** numeric strings */
type NumberType = "float32" | "float64" | "int8" | "uint8" | "int16" | "uint16" | "int32" | "uint32"

/** string strings */
type StringType = "string" | "timestamp"

/** Generic JTD Schema without inference of the represented type */
export type SomeJTDSchemaType = (
| // ref
{ref: string}
// primitives
| {type: NumberType | StringType | "boolean"}
// enum
| {enum: string[]}
// elements
| {elements: SomeJTDSchemaType}
// values
| {values: SomeJTDSchemaType}
// properties
| {
properties: Record<string, SomeJTDSchemaType>
optionalProperties?: Record<string, SomeJTDSchemaType>
additionalProperties?: boolean
}
| {
properties?: Record<string, SomeJTDSchemaType>
optionalProperties: Record<string, SomeJTDSchemaType>
additionalProperties?: boolean
}
// discriminator
| {discriminator: string; mapping: Record<string, SomeJTDSchemaType>}
// empty
// NOTE see the end of
// https://github.com/typescript-eslint/typescript-eslint/issues/2063#issuecomment-675156492
// eslint-disable-next-line @typescript-eslint/ban-types
| {}
) & {
nullable?: boolean
metadata?: Record<string, unknown>
definitions?: Record<string, SomeJTDSchemaType>
}

/** required keys of an object, not undefined */
type RequiredKeys<T> = {
[K in keyof T]-?: undefined extends T[K] ? never : K
Expand Down Expand Up @@ -57,12 +99,6 @@ type IsRecord<T, Union extends boolean> = Union extends IsUnion<Exclude<T, null>
: true
: false

/** numeric strings */
type NumberType = "float32" | "float64" | "int8" | "uint8" | "int16" | "uint16" | "int32" | "uint32"

/** string strings */
type StringType = "string" | "timestamp"

/** actual schema */
export type JTDSchemaType<T, D extends Record<string, unknown> = Record<string, never>> = (
| // refs - where null wasn't specified, must match exactly
Expand Down Expand Up @@ -164,7 +200,9 @@ export type JTDSchemaType<T, D extends Record<string, unknown> = Record<string,
type JTDDataDef<S, D extends Record<string, unknown>> =
| (// ref
S extends {ref: string}
? JTDDataDef<D[S["ref"]], D>
? D extends {[K in S["ref"]]: infer V}
? JTDDataDef<V, D>
: never
: // type
S extends {type: NumberType}
? number
Expand Down
18 changes: 13 additions & 5 deletions spec/types/jtd-schema.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/no-empty-interface,no-void */
import _Ajv from "../ajv_jtd"
import type {JTDSchemaType, JTDDataType} from "../../dist/jtd"
import type {JTDSchemaType, SomeJTDSchemaType, JTDDataType} from "../../dist/jtd"
import chai from "../chai"
const should = chai.should()

Expand Down Expand Up @@ -353,16 +353,14 @@ describe("JTDDataType", () => {
},
} as const

type MyData1 = JTDDataType<typeof mySchema1>

const validate = ajv.compile<MyData1>(mySchema1)
const validate = ajv.compile(mySchema1)
const validData: unknown = {type: "a", a: 1}
if (validate(validData) && validData.type === "a") {
validData.a.should.equal(1)
}
should.not.exist(validate.errors)

if (ajv.validate<MyData1>(mySchema1, validData) && validData.type === "a") {
if (ajv.validate(mySchema1, validData) && validData.type === "a") {
validData.a.should.equal(1)
}
should.not.exist(ajv.errors)
Expand Down Expand Up @@ -492,3 +490,13 @@ describe("JTDDataType", () => {
void [empty]
})
})

describe("SomeJTDSchemaType", () => {
it("should allow setting unknowns", () => {
// This test is basically here to assert that we should be using `{}` in
// SomeJTDSchemaType
const schema: SomeJTDSchemaType = {}

void [schema]
})
})