Skip to content

Commit

Permalink
feat: add support for inferring schema input types
Browse files Browse the repository at this point in the history
  • Loading branch information
thetutlage committed Mar 28, 2024
1 parent 3d59dad commit df27df8
Show file tree
Hide file tree
Showing 28 changed files with 621 additions and 61 deletions.
6 changes: 5 additions & 1 deletion src/schema/accepted/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ import type { FieldOptions, Validation } from '../../types.js'
/**
* VineAccepted represents a checkbox input that must be checked
*/
export class VineAccepted extends BaseLiteralType<true, true> {
export class VineAccepted extends BaseLiteralType<
'on' | '1' | 'yes' | 'true' | true | 1,
true,
true
> {
/**
* Default collection of accepted rules
*/
Expand Down
2 changes: 1 addition & 1 deletion src/schema/any/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import type { FieldOptions, Validation } from '../../types.js'
/**
* VineAny represents a value that can be anything
*/
export class VineAny extends BaseLiteralType<any, any> {
export class VineAny extends BaseLiteralType<any, any, any> {
constructor(options?: Partial<FieldOptions>, validations?: Validation<any>[]) {
super(options, validations)
}
Expand Down
3 changes: 2 additions & 1 deletion src/schema/array/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import camelcase from 'camelcase'
import { RefsStore, ArrayNode } from '@vinejs/compiler/types'

import { BaseType } from '../base/main.js'
import { OTYPE, COTYPE, PARSE, UNIQUE_NAME, IS_OF_TYPE } from '../../symbols.js'
import { ITYPE, OTYPE, COTYPE, PARSE, UNIQUE_NAME, IS_OF_TYPE } from '../../symbols.js'
import type { FieldOptions, ParserOptions, SchemaTypes, Validation } from '../../types.js'

import {
Expand All @@ -28,6 +28,7 @@ import {
* pipeline
*/
export class VineArray<Schema extends SchemaTypes> extends BaseType<
Schema[typeof ITYPE][],
Schema[typeof OTYPE][],
Schema[typeof COTYPE][]
> {
Expand Down
24 changes: 16 additions & 8 deletions src/schema/base/literal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import camelcase from 'camelcase'
import Macroable from '@poppinss/macroable'
import type { LiteralNode, RefsStore } from '@vinejs/compiler/types'

import { OTYPE, COTYPE, PARSE, VALIDATION } from '../../symbols.js'
import { OTYPE, COTYPE, PARSE, VALIDATION, ITYPE } from '../../symbols.js'
import type {
Parser,
Validation,
Expand All @@ -31,9 +31,9 @@ import { helpers } from '../../vine/helpers.js'
/**
* Base schema type with only modifiers applicable on all the schema types.
*/
abstract class BaseModifiersType<Output, CamelCaseOutput>
abstract class BaseModifiersType<Input, Output, CamelCaseOutput>
extends Macroable
implements ConstructableSchema<Output, CamelCaseOutput>
implements ConstructableSchema<Input, Output, CamelCaseOutput>
{
/**
* Each subtype should implement the compile method that returns
Expand All @@ -46,6 +46,11 @@ abstract class BaseModifiersType<Output, CamelCaseOutput>
*/
abstract clone(): this

/**
* Define the input type of the schema
*/
declare [ITYPE]: Input;

/**
* The output value of the field. The property points to a type only
* and not the real value.
Expand Down Expand Up @@ -86,7 +91,8 @@ abstract class BaseModifiersType<Output, CamelCaseOutput>
/**
* Modifies the schema type to allow null values
*/
class NullableModifier<Schema extends BaseModifiersType<any, any>> extends BaseModifiersType<
class NullableModifier<Schema extends BaseModifiersType<any, any, any>> extends BaseModifiersType<
Schema[typeof ITYPE] | null,
Schema[typeof OTYPE] | null,
Schema[typeof COTYPE] | null
> {
Expand Down Expand Up @@ -118,7 +124,8 @@ class NullableModifier<Schema extends BaseModifiersType<any, any>> extends BaseM
/**
* Modifies the schema type to allow undefined values
*/
class OptionalModifier<Schema extends BaseModifiersType<any, any>> extends BaseModifiersType<
class OptionalModifier<Schema extends BaseModifiersType<any, any, any>> extends BaseModifiersType<
Schema[typeof ITYPE] | undefined | null,
Schema[typeof OTYPE] | undefined,
Schema[typeof COTYPE] | undefined
> {
Expand Down Expand Up @@ -328,9 +335,9 @@ class OptionalModifier<Schema extends BaseModifiersType<any, any>> extends BaseM
* Modifies the schema type to allow custom transformed values
*/
class TransformModifier<
Schema extends BaseModifiersType<any, any>,
Schema extends BaseModifiersType<any, any, any>,
Output,
> extends BaseModifiersType<Output, Output> {
> extends BaseModifiersType<Schema[typeof ITYPE], Output, Output> {
/**
* The output value of the field. The property points to a type only
* and not the real value.
Expand Down Expand Up @@ -369,7 +376,8 @@ class TransformModifier<
* The base type for creating a custom literal type. Literal type
* is a schema type that has no children elements.
*/
export abstract class BaseLiteralType<Output, CamelCaseOutput> extends BaseModifiersType<
export abstract class BaseLiteralType<Input, Output, CamelCaseOutput> extends BaseModifiersType<
Input,
Output,
CamelCaseOutput
> {
Expand Down
20 changes: 14 additions & 6 deletions src/schema/base/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

import type { CompilerNodes, RefsStore } from '@vinejs/compiler/types'

import { OTYPE, COTYPE, PARSE, VALIDATION } from '../../symbols.js'
import { ITYPE, OTYPE, COTYPE, PARSE, VALIDATION } from '../../symbols.js'
import type {
Parser,
Validation,
Expand All @@ -23,9 +23,9 @@ import Macroable from '@poppinss/macroable'
/**
* Base schema type with only modifiers applicable on all the schema types.
*/
export abstract class BaseModifiersType<Output, CamelCaseOutput>
export abstract class BaseModifiersType<Input, Output, CamelCaseOutput>
extends Macroable
implements ConstructableSchema<Output, CamelCaseOutput>
implements ConstructableSchema<Input, Output, CamelCaseOutput>
{
/**
* Each subtype should implement the compile method that returns
Expand All @@ -38,6 +38,11 @@ export abstract class BaseModifiersType<Output, CamelCaseOutput>
*/
abstract clone(): this

/**
* Define the input type of the schema
*/
declare [ITYPE]: Input;

/**
* The output value of the field. The property points to a type only
* and not the real value.
Expand Down Expand Up @@ -68,7 +73,8 @@ export abstract class BaseModifiersType<Output, CamelCaseOutput>
/**
* Modifies the schema type to allow null values
*/
class NullableModifier<Schema extends BaseModifiersType<any, any>> extends BaseModifiersType<
class NullableModifier<Schema extends BaseModifiersType<any, any, any>> extends BaseModifiersType<
Schema[typeof ITYPE] | null,
Schema[typeof OTYPE] | null,
Schema[typeof COTYPE] | null
> {
Expand Down Expand Up @@ -102,7 +108,8 @@ class NullableModifier<Schema extends BaseModifiersType<any, any>> extends BaseM
/**
* Modifies the schema type to allow undefined values
*/
class OptionalModifier<Schema extends BaseModifiersType<any, any>> extends BaseModifiersType<
class OptionalModifier<Schema extends BaseModifiersType<any, any, any>> extends BaseModifiersType<
Schema[typeof ITYPE] | undefined | null,
Schema[typeof OTYPE] | undefined,
Schema[typeof COTYPE] | undefined
> {
Expand Down Expand Up @@ -137,7 +144,8 @@ class OptionalModifier<Schema extends BaseModifiersType<any, any>> extends BaseM
* The BaseSchema class abstracts the repetitive parts of creating
* a custom schema type.
*/
export abstract class BaseType<Output, CamelCaseOutput> extends BaseModifiersType<
export abstract class BaseType<Input, Output, CamelCaseOutput> extends BaseModifiersType<
Input,
Output,
CamelCaseOutput
> {
Expand Down
2 changes: 1 addition & 1 deletion src/schema/boolean/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import type { FieldOptions, Validation } from '../../types.js'
/**
* VineBoolean represents a boolean value in the validation schema.
*/
export class VineBoolean extends BaseLiteralType<boolean, boolean> {
export class VineBoolean extends BaseLiteralType<boolean | string | number, boolean, boolean> {
/**
* Default collection of boolean rules
*/
Expand Down
8 changes: 6 additions & 2 deletions src/schema/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import Macroable from '@poppinss/macroable'

import { VineAny } from './any/main.js'
import { VineEnum } from './enum/main.js'
import { VineDate } from './date/main.js'
import { union } from './union/builder.js'
import { VineTuple } from './tuple/main.js'
import { VineArray } from './array/main.js'
Expand All @@ -25,9 +26,8 @@ import { VineAccepted } from './accepted/main.js'
import { group } from './object/group_builder.js'
import { VineNativeEnum } from './enum/native_enum.js'
import { VineUnionOfTypes } from './union_of_types/main.js'
import { OTYPE, COTYPE, IS_OF_TYPE, UNIQUE_NAME } from '../symbols.js'
import { ITYPE, OTYPE, COTYPE, IS_OF_TYPE, UNIQUE_NAME } from '../symbols.js'
import type { DateFieldOptions, EnumLike, FieldContext, SchemaTypes } from '../types.js'
import { VineDate } from './date/main.js'

/**
* Schema builder exposes methods to construct a Vine schema. You may
Expand Down Expand Up @@ -94,6 +94,9 @@ export class SchemaBuilder extends Macroable {
object<Properties extends Record<string, SchemaTypes>>(properties: Properties) {
return new VineObject<
Properties,
{
[K in keyof Properties]: Properties[K][typeof ITYPE]
},
{
[K in keyof Properties]: Properties[K][typeof OTYPE]
},
Expand All @@ -117,6 +120,7 @@ export class SchemaBuilder extends Macroable {
tuple<Schema extends SchemaTypes[]>(schemas: [...Schema]) {
return new VineTuple<
Schema,
{ [K in keyof Schema]: Schema[K][typeof ITYPE] },
{ [K in keyof Schema]: Schema[K][typeof OTYPE] },
{ [K in keyof Schema]: Schema[K][typeof COTYPE] }
>(schemas)
Expand Down
2 changes: 1 addition & 1 deletion src/schema/date/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import type {
* VineDate represents a Date object created by parsing a
* string or number value as a date.
*/
export class VineDate extends BaseLiteralType<Date, Date> {
export class VineDate extends BaseLiteralType<string | number, Date, Date> {
/**
* Available VineDate rules
*/
Expand Down
1 change: 1 addition & 0 deletions src/schema/enum/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import type { FieldContext, FieldOptions, Validation } from '../../types.js'
* against a pre-defined choices list.
*/
export class VineEnum<const Values extends readonly unknown[]> extends BaseLiteralType<
Values[number],
Values[number],
Values[number]
> {
Expand Down
1 change: 1 addition & 0 deletions src/schema/enum/native_enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import type { EnumLike, FieldOptions, Validation } from '../../types.js'
* object
*/
export class VineNativeEnum<Values extends EnumLike> extends BaseLiteralType<
Values[keyof Values],
Values[keyof Values],
Values[keyof Values]
> {
Expand Down
2 changes: 1 addition & 1 deletion src/schema/literal/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import type { FieldOptions, Validation } from '../../types.js'
/**
* VineLiteral represents a type that matches an exact value
*/
export class VineLiteral<Value> extends BaseLiteralType<Value, Value> {
export class VineLiteral<Value> extends BaseLiteralType<Value, Value, Value> {
/**
* Default collection of literal rules
*/
Expand Down
2 changes: 1 addition & 1 deletion src/schema/number/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import {
/**
* VineNumber represents a numeric value in the validation schema.
*/
export class VineNumber extends BaseLiteralType<number, number> {
export class VineNumber extends BaseLiteralType<string | number, number, number> {
protected declare options: FieldOptions & { strict?: boolean }

/**
Expand Down
4 changes: 3 additions & 1 deletion src/schema/object/conditional.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

import type { ConditionalFn, ObjectGroupNode, RefsStore } from '@vinejs/compiler/types'

import { OTYPE, COTYPE, PARSE } from '../../symbols.js'
import { OTYPE, COTYPE, PARSE, ITYPE } from '../../symbols.js'
import type { ParserOptions, SchemaTypes } from '../../types.js'

/**
Expand All @@ -18,9 +18,11 @@ import type { ParserOptions, SchemaTypes } from '../../types.js'
*/
export class GroupConditional<
Properties extends Record<string, SchemaTypes>,
Input,
Output,
CamelCaseOutput,
> {
declare [ITYPE]: Input;
declare [OTYPE]: Output;
declare [COTYPE]: CamelCaseOutput

Expand Down
5 changes: 3 additions & 2 deletions src/schema/object/group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,16 @@ import { ObjectGroupNode, RefsStore } from '@vinejs/compiler/types'

import { messages } from '../../defaults.js'
import { GroupConditional } from './conditional.js'
import { OTYPE, COTYPE, PARSE } from '../../symbols.js'
import { ITYPE, OTYPE, COTYPE, PARSE } from '../../symbols.js'
import type { ParserOptions, UnionNoMatchCallback } from '../../types.js'

/**
* Object group represents a group with multiple conditionals, where each
* condition returns a set of object properties to merge into the
* existing object.
*/
export class ObjectGroup<Conditional extends GroupConditional<any, any, any>> {
export class ObjectGroup<Conditional extends GroupConditional<any, any, any, any>> {
declare [ITYPE]: Conditional[typeof ITYPE];
declare [OTYPE]: Conditional[typeof OTYPE];
declare [COTYPE]: Conditional[typeof COTYPE]

Expand Down
10 changes: 8 additions & 2 deletions src/schema/object/group_builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@
*/

import { ObjectGroup } from './group.js'
import { OTYPE, COTYPE } from '../../symbols.js'
import { CamelCase } from '../camelcase_types.js'
import { GroupConditional } from './conditional.js'
import { OTYPE, COTYPE, ITYPE } from '../../symbols.js'
import type { FieldContext, SchemaTypes } from '../../types.js'

/**
* Create an object group. Groups are used to conditionally merge properties
* to an existing object.
*/
export function group<Conditional extends GroupConditional<any, any, any>>(
export function group<Conditional extends GroupConditional<any, any, any, any>>(
conditionals: Conditional[]
) {
return new ObjectGroup<Conditional>(conditionals)
Expand All @@ -32,6 +32,9 @@ group.if = function groupIf<Properties extends Record<string, SchemaTypes>>(
) {
return new GroupConditional<
Properties,
{
[K in keyof Properties]: Properties[K][typeof ITYPE]
},
{
[K in keyof Properties]: Properties[K][typeof OTYPE]
},
Expand All @@ -49,6 +52,9 @@ group.else = function groupElse<Properties extends Record<string, SchemaTypes>>(
) {
return new GroupConditional<
Properties,
{
[K in keyof Properties]: Properties[K][typeof ITYPE]
},
{
[K in keyof Properties]: Properties[K][typeof OTYPE]
},
Expand Down
Loading

0 comments on commit df27df8

Please sign in to comment.