diff --git a/src/ObjectSchema.js b/src/ObjectSchema.js index dc94852..a709361 100644 --- a/src/ObjectSchema.js +++ b/src/ObjectSchema.js @@ -45,10 +45,11 @@ const ObjectSchema = ({ schema = initialState, ...options } = {}) => { * @param {string} id - an #id **/ id: id => { - if (!id) + if (!id) { throw new FluentSchemaError( - `id should not be an empty fragment <#> or an empty string <> (e.g. #myId)` + 'id should not be an empty fragment <#> or an empty string <> (e.g. #myId)' ) + } return options.factory({ schema: { ...schema, $id: id }, ...options }) }, /** diff --git a/src/ObjectSchema.test.js b/src/ObjectSchema.test.js index 674d860..bd6dd86 100644 --- a/src/ObjectSchema.test.js +++ b/src/ObjectSchema.test.js @@ -229,7 +229,7 @@ describe('ObjectSchema', () => { .valueOf() ).toEqual({ $id: id, - properties: {'prop': {}}, + properties: { prop: {} }, type: 'object' }) }) diff --git a/types/FluentJSONSchema.d.ts b/types/FluentJSONSchema.d.ts index 0f40a09..f5495cd 100644 --- a/types/FluentJSONSchema.d.ts +++ b/types/FluentJSONSchema.d.ts @@ -1,247 +1,250 @@ -export interface BaseSchema { - id: (id: string) => T - title: (title: string) => T - description: (description: string) => T - examples: (examples: Array) => T - ref: (ref: string) => T - enum: (values: Array) => T - const: (value: any) => T - default: (value: any) => T - required: (fields?: string[]) => T - ifThen: (ifClause: JSONSchema, thenClause: JSONSchema) => T - ifThenElse: ( - ifClause: JSONSchema, - thenClause: JSONSchema, - elseClause: JSONSchema - ) => T - not: (schema: JSONSchema) => T - anyOf: (schema: Array) => T - allOf: (schema: Array) => T - oneOf: (schema: Array) => T - readOnly: (isReadOnly?: boolean) => T - writeOnly: (isWriteOnly?: boolean) => T - deprecated: (isDeprecated?: boolean) => T - isFluentSchema: boolean - isFluentJSONSchema: boolean - raw: (fragment: any) => T -} +declare namespace fluentSchema { + export type TYPE = + | "string" + | "number" + | "boolean" + | "integer" + | "object" + | "array" + | "null"; -export type TYPE = - | 'string' - | 'number' - | 'boolean' - | 'integer' - | 'object' - | 'array' - | 'null' + type FORMATS = { + RELATIVE_JSON_POINTER: "relative-json-pointer"; + JSON_POINTER: "json-pointer"; + UUID: "uuid"; + REGEX: "regex"; + IPV6: "ipv6"; + IPV4: "ipv4"; + HOSTNAME: "hostname"; + EMAIL: "email"; + URL: "url"; + URI_TEMPLATE: "uri-template"; + URI_REFERENCE: "uri-reference"; + URI: "uri"; + TIME: "time"; + DATE: "date"; + DATE_TIME: "date-time"; + }; -type FORMATS = { - RELATIVE_JSON_POINTER: 'relative-json-pointer' - JSON_POINTER: 'json-pointer' - UUID: 'uuid' - REGEX: 'regex' - IPV6: 'ipv6' - IPV4: 'ipv4' - HOSTNAME: 'hostname' - EMAIL: 'email' - URL: 'url' - URI_TEMPLATE: 'uri-template' - URI_REFERENCE: 'uri-reference' - URI: 'uri' - TIME: 'time' - DATE: 'date' - DATE_TIME: 'date-time' -} + type InferSchemaMap = { + string: fluentSchema.StringSchema; + number: fluentSchema.NumberSchema; + boolean: fluentSchema.BooleanSchema; + integer: fluentSchema.IntegerSchema; + object: fluentSchema.ObjectSchema; + array: fluentSchema.ArraySchema; + null: fluentSchema.NullSchema; + }; -export type JSONSchema = - | ObjectSchema - | StringSchema - | NumberSchema - | ArraySchema - | IntegerSchema - | BooleanSchema - | NullSchema - | ExtendedSchema + type MixedSchema1 = T extends [infer U] + ? InferSchemaMap[U extends TYPE ? U : never] + : never; + type MixedSchema2 = T extends [infer U, infer V] + ? InferSchemaMap[U extends TYPE ? U : never] & + InferSchemaMap[V extends TYPE ? V : never] + : never; + type MixedSchema3 = T extends [infer U, infer V, infer W] + ? InferSchemaMap[U extends TYPE ? U : never] & + InferSchemaMap[V extends TYPE ? V : never] & + InferSchemaMap[W extends TYPE ? W : never] + : never; + type MixedSchema4 = T extends [infer U, infer V, infer W, infer X] + ? InferSchemaMap[U extends TYPE ? U : never] & + InferSchemaMap[V extends TYPE ? V : never] & + InferSchemaMap[W extends TYPE ? W : never] & + InferSchemaMap[X extends TYPE ? X : never] + : never; + type MixedSchema5 = T extends [infer U, infer V, infer W, infer X, infer Y] + ? InferSchemaMap[U extends TYPE ? U : never] & + InferSchemaMap[V extends TYPE ? V : never] & + InferSchemaMap[W extends TYPE ? W : never] & + InferSchemaMap[X extends TYPE ? X : never] & + InferSchemaMap[Y extends TYPE ? Y : never] + : never; + type MixedSchema6 = T extends [ + infer U, + infer V, + infer W, + infer X, + infer Y, + infer Z + ] + ? InferSchemaMap[U extends TYPE ? U : never] & + InferSchemaMap[V extends TYPE ? V : never] & + InferSchemaMap[W extends TYPE ? W : never] & + InferSchemaMap[X extends TYPE ? X : never] & + InferSchemaMap[Y extends TYPE ? Y : never] & + InferSchemaMap[Z extends TYPE ? Z : never] + : never; + type MixedSchema7 = T extends [ + infer U, + infer V, + infer W, + infer X, + infer Y, + infer Z, + infer A + ] + ? InferSchemaMap[U extends TYPE ? U : never] & + InferSchemaMap[V extends TYPE ? V : never] & + InferSchemaMap[W extends TYPE ? W : never] & + InferSchemaMap[X extends TYPE ? X : never] & + InferSchemaMap[Y extends TYPE ? Y : never] & + InferSchemaMap[Z extends TYPE ? Z : never] & + InferSchemaMap[A extends TYPE ? A : never] + : never; -export class FluentSchemaError extends Error { - name: string -} - -export interface SchemaOptions { - schema: object - generateIds: boolean -} + export type MixedSchema = + | MixedSchema1 + | MixedSchema2 + | MixedSchema3 + | MixedSchema4 + | MixedSchema5 + | MixedSchema6 + | MixedSchema7; -export interface StringSchema extends BaseSchema { - minLength: (min: number) => StringSchema - maxLength: (min: number) => StringSchema - format: (format: FORMATS[keyof FORMATS]) => StringSchema - pattern: (pattern: string | RegExp) => StringSchema - contentEncoding: (encoding: string) => StringSchema - contentMediaType: (mediaType: string) => StringSchema -} + type Key = keyof T | (string & {}); -export interface NullSchema { - null: () => StringSchema -} + type DependentSchemaOptions>> = + Partial>; -export interface BooleanSchema extends BaseSchema { - boolean: () => BooleanSchema -} + type DependentRequiredOptions>> = + Partial>; -export interface NumberSchema extends BaseSchema { - minimum: (min: number) => NumberSchema - exclusiveMinimum: (min: number) => NumberSchema - maximum: (max: number) => NumberSchema - exclusiveMaximum: (max: number) => NumberSchema - multipleOf: (multiple: number) => NumberSchema -} + type ObjectPlaceholder = Record; -export interface IntegerSchema extends BaseSchema { - minimum: (min: number) => IntegerSchema - exclusiveMinimum: (min: number) => IntegerSchema - maximum: (max: number) => IntegerSchema - exclusiveMaximum: (max: number) => IntegerSchema - multipleOf: (multiple: number) => IntegerSchema -} + export class FluentSchemaError extends Error { + name: string; + } -export interface ArraySchema extends BaseSchema { - items: (items: JSONSchema | Array) => ArraySchema - additionalItems: (items: Array | boolean) => ArraySchema - contains: (value: JSONSchema | boolean) => ArraySchema - uniqueItems: (boolean: boolean) => ArraySchema - minItems: (min: number) => ArraySchema - maxItems: (max: number) => ArraySchema -} + export type JSONSchema = + | ObjectSchema + | StringSchema + | NumberSchema + | ArraySchema + | IntegerSchema + | BooleanSchema + | NullSchema + | ExtendedSchema; -export interface ObjectSchema = Record> extends BaseSchema> { - definition: (name: Key, props?: JSONSchema) => ObjectSchema - prop: (name: Key, props?: JSONSchema) => ObjectSchema - additionalProperties: (value: JSONSchema | boolean) => ObjectSchema - maxProperties: (max: number) => ObjectSchema - minProperties: (min: number) => ObjectSchema - patternProperties: (options: PatternPropertiesOptions) => ObjectSchema - dependencies: (options: DependenciesOptions) => ObjectSchema - propertyNames: (value: JSONSchema) => ObjectSchema - extend: (schema: ObjectSchema | ExtendedSchema) => ExtendedSchema - only: (properties: string[]) => ObjectSchema - without: (properties: string[]) => ObjectSchema - dependentRequired: (options: DependentRequiredOptions) => ObjectSchema - dependentSchemas: (options: DependentSchemaOptions) => ObjectSchema -} + export interface BaseSchema { + id: (id: string) => T; + title: (title: string) => T; + description: (description: string) => T; + examples: (examples: Array) => T; + ref: (ref: string) => T; + enum: (values: Array) => T; + const: (value: any) => T; + default: (value: any) => T; + required: (fields?: string[]) => T; + ifThen: (ifClause: JSONSchema, thenClause: JSONSchema) => T; + ifThenElse: ( + ifClause: JSONSchema, + thenClause: JSONSchema, + elseClause: JSONSchema + ) => T; + not: (schema: JSONSchema) => T; + anyOf: (schema: Array) => T; + allOf: (schema: Array) => T; + oneOf: (schema: Array) => T; + readOnly: (isReadOnly?: boolean) => T; + writeOnly: (isWriteOnly?: boolean) => T; + deprecated: (isDeprecated?: boolean) => T; + isFluentSchema: boolean; + isFluentJSONSchema: boolean; + raw: (fragment: any) => T; + } -export type ExtendedSchema = Pick + export interface SchemaOptions { + schema: object; + generateIds: boolean; + } -type InferSchemaMap = { - string: StringSchema - number: NumberSchema - boolean: BooleanSchema - integer: IntegerSchema - object: ObjectSchema - array: ArraySchema - null: NullSchema -} + export interface PatternPropertiesOptions { + [key: string]: JSONSchema; + } -type MixedSchema1 = T extends [infer U] - ? InferSchemaMap[U extends TYPE ? U : never] - : never -type MixedSchema2 = T extends [infer U, infer V] - ? InferSchemaMap[U extends TYPE ? U : never] & - InferSchemaMap[V extends TYPE ? V : never] - : never -type MixedSchema3 = T extends [infer U, infer V, infer W] - ? InferSchemaMap[U extends TYPE ? U : never] & - InferSchemaMap[V extends TYPE ? V : never] & - InferSchemaMap[W extends TYPE ? W : never] - : never -type MixedSchema4 = T extends [infer U, infer V, infer W, infer X] - ? InferSchemaMap[U extends TYPE ? U : never] & - InferSchemaMap[V extends TYPE ? V : never] & - InferSchemaMap[W extends TYPE ? W : never] & - InferSchemaMap[X extends TYPE ? X : never] - : never -type MixedSchema5 = T extends [infer U, infer V, infer W, infer X, infer Y] - ? InferSchemaMap[U extends TYPE ? U : never] & - InferSchemaMap[V extends TYPE ? V : never] & - InferSchemaMap[W extends TYPE ? W : never] & - InferSchemaMap[X extends TYPE ? X : never] & - InferSchemaMap[Y extends TYPE ? Y : never] - : never -type MixedSchema6 = T extends [ - infer U, - infer V, - infer W, - infer X, - infer Y, - infer Z -] - ? InferSchemaMap[U extends TYPE ? U : never] & - InferSchemaMap[V extends TYPE ? V : never] & - InferSchemaMap[W extends TYPE ? W : never] & - InferSchemaMap[X extends TYPE ? X : never] & - InferSchemaMap[Y extends TYPE ? Y : never] & - InferSchemaMap[Z extends TYPE ? Z : never] - : never -type MixedSchema7 = T extends [ - infer U, - infer V, - infer W, - infer X, - infer Y, - infer Z, - infer A -] - ? InferSchemaMap[U extends TYPE ? U : never] & - InferSchemaMap[V extends TYPE ? V : never] & - InferSchemaMap[W extends TYPE ? W : never] & - InferSchemaMap[X extends TYPE ? X : never] & - InferSchemaMap[Y extends TYPE ? Y : never] & - InferSchemaMap[Z extends TYPE ? Z : never] & - InferSchemaMap[A extends TYPE ? A : never] - : never + export interface DependenciesOptions { + [key: string]: JSONSchema[]; + } -export type MixedSchema = - | MixedSchema1 - | MixedSchema2 - | MixedSchema3 - | MixedSchema4 - | MixedSchema5 - | MixedSchema6 - | MixedSchema7 -interface SchemaOptions { - schema: object - generateIds: boolean -} + export interface SchemaOptions { + schema: object; + generateIds: boolean; + } -interface PatternPropertiesOptions { - [key: string]: JSONSchema -} + export interface StringSchema extends fluentSchema.BaseSchema { + minLength: (min: number) => StringSchema; + maxLength: (min: number) => StringSchema; + format: (format: FORMATS[keyof FORMATS]) => StringSchema; + pattern: (pattern: string | RegExp) => StringSchema; + contentEncoding: (encoding: string) => StringSchema; + contentMediaType: (mediaType: string) => StringSchema; + } -interface DependenciesOptions { - [key: string]: JSONSchema[] -} + export interface NullSchema { + null: () => StringSchema; + } -type Key = keyof T | (string & {}) + export interface BooleanSchema extends fluentSchema.BaseSchema { + boolean: () => BooleanSchema; + } -type DependentSchemaOptions>> = Partial> + export interface NumberSchema extends fluentSchema.BaseSchema { + minimum: (min: number) => NumberSchema; + exclusiveMinimum: (min: number) => NumberSchema; + maximum: (max: number) => NumberSchema; + exclusiveMaximum: (max: number) => NumberSchema; + multipleOf: (multiple: number) => NumberSchema; + } -type DependentRequiredOptions>> = Partial> + export interface IntegerSchema extends fluentSchema.BaseSchema { + minimum: (min: number) => IntegerSchema; + exclusiveMinimum: (min: number) => IntegerSchema; + maximum: (max: number) => IntegerSchema; + exclusiveMaximum: (max: number) => IntegerSchema; + multipleOf: (multiple: number) => IntegerSchema; + } -export function withOptions(options: SchemaOptions): T + export interface ArraySchema extends fluentSchema.BaseSchema { + items: (items: JSONSchema | Array) => ArraySchema; + additionalItems: (items: Array | boolean) => ArraySchema; + contains: (value: JSONSchema | boolean) => ArraySchema; + uniqueItems: (boolean: boolean) => ArraySchema; + minItems: (min: number) => ArraySchema; + maxItems: (max: number) => ArraySchema; + } -type ObjectPlaceholder = Record; + export interface ObjectSchema = Record> + extends fluentSchema.BaseSchema> { + definition: (name: Key, props?: JSONSchema) => ObjectSchema; + prop: (name: Key, props?: JSONSchema) => ObjectSchema; + additionalProperties: (value: JSONSchema | boolean) => ObjectSchema; + maxProperties: (max: number) => ObjectSchema; + minProperties: (min: number) => ObjectSchema; + patternProperties: (options: PatternPropertiesOptions) => ObjectSchema; + dependencies: (options: DependenciesOptions) => ObjectSchema; + propertyNames: (value: JSONSchema) => ObjectSchema; + extend: (schema: ObjectSchema | ExtendedSchema) => ExtendedSchema; + only: (properties: string[]) => ObjectSchema; + without: (properties: string[]) => ObjectSchema; + dependentRequired: (options: DependentRequiredOptions) => ObjectSchema; + dependentSchemas: (options: DependentSchemaOptions) => ObjectSchema; + } -export interface S extends BaseSchema { - string: () => StringSchema - number: () => NumberSchema - integer: () => IntegerSchema - boolean: () => BooleanSchema - array: () => ArraySchema - object: () => ObjectSchema - null: () => NullSchema - mixed: < - T extends + export interface S extends BaseSchema { + string: () => StringSchema; + number: () => NumberSchema; + integer: () => IntegerSchema; + boolean: () => BooleanSchema; + array: () => ArraySchema; + object: < + T extends ObjectPlaceholder = ObjectPlaceholder + >() => ObjectSchema; + null: () => NullSchema; + mixed: < + T extends | [TYPE] | [TYPE, TYPE] | [TYPE, TYPE, TYPE] @@ -249,13 +252,19 @@ export interface S extends BaseSchema { | [TYPE, TYPE, TYPE, TYPE, TYPE] | [TYPE, TYPE, TYPE, TYPE, TYPE, TYPE] | [TYPE, TYPE, TYPE, TYPE, TYPE, TYPE, TYPE] - >( - types: T - ) => MixedSchema - raw: (fragment: any) => S - FORMATS: FORMATS -} + >( + types: T + ) => MixedSchema; + raw: (fragment: any) => S; + FORMATS: FORMATS; + } + + export type ExtendedSchema = Pick; -export declare var S: S + export function withOptions(options: SchemaOptions): T; + + const FluentSchema: S; + export { FluentSchema as default }; +} -export default S +export = fluentSchema;