Skip to content

Commit

Permalink
feat: add subtype property to schema output
Browse files Browse the repository at this point in the history
Fixes: #64
  • Loading branch information
thetutlage committed Nov 29, 2024
1 parent 80acb98 commit 818fbf0
Show file tree
Hide file tree
Showing 29 changed files with 630 additions and 16 deletions.
8 changes: 7 additions & 1 deletion src/schema/accepted/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import { acceptedRule } from './rules.js'
import { BaseLiteralType } from '../base/literal.js'
import type { FieldOptions, Validation } from '../../types.js'
import { SUBTYPE } from '../../symbols.js'

/**
* VineAccepted represents a checkbox input that must be checked
Expand All @@ -24,7 +25,12 @@ export class VineAccepted extends BaseLiteralType<
*/
static rules = {
accepted: acceptedRule,
}
};

/**
* The subtype of the literal schema field
*/
[SUBTYPE] = 'checkbox'

constructor(options?: Partial<FieldOptions>, validations?: Validation<any>[]) {
super(options, validations || [acceptedRule()])
Expand Down
6 changes: 6 additions & 0 deletions src/schema/any/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import { BaseLiteralType } from '../base/literal.js'
import type { FieldOptions, Validation } from '../../types.js'
import { SUBTYPE } from '../../symbols.js'

/**
* VineAny represents a value that can be anything
Expand All @@ -18,6 +19,11 @@ export class VineAny extends BaseLiteralType<any, any, any> {
super(options, validations)
}

/**
* The subtype of the literal schema field
*/
[SUBTYPE] = 'any'

/**
* Clones the VineAny schema type. The applied options
* and validations are copied to the new instance
Expand Down
38 changes: 32 additions & 6 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, ITYPE } from '../../symbols.js'
import { OTYPE, COTYPE, PARSE, VALIDATION, ITYPE, SUBTYPE } from '../../symbols.js'
import type {
Parser,
Validation,
Expand Down Expand Up @@ -39,7 +39,11 @@ abstract class BaseModifiersType<Input, Output, CamelCaseOutput>
* Each subtype should implement the compile method that returns
* one of the known compiler nodes
*/
abstract [PARSE](propertyName: string, refs: RefsStore, options: ParserOptions): LiteralNode
abstract [PARSE](
propertyName: string,
refs: RefsStore,
options: ParserOptions
): LiteralNode & { subtype: string }

/**
* The child class must implement the clone method
Expand Down Expand Up @@ -116,7 +120,11 @@ export class NullableModifier<
/**
* Compiles to compiler node
*/
[PARSE](propertyName: string, refs: RefsStore, options: ParserOptions): LiteralNode {
[PARSE](
propertyName: string,
refs: RefsStore,
options: ParserOptions
): LiteralNode & { subtype: string } {
const output = this.#parent[PARSE](propertyName, refs, options)
output.allowNull = true
return output
Expand Down Expand Up @@ -327,7 +335,11 @@ export class OptionalModifier<
/**
* Compiles to compiler node
*/
[PARSE](propertyName: string, refs: RefsStore, options: ParserOptions): LiteralNode {
[PARSE](
propertyName: string,
refs: RefsStore,
options: ParserOptions
): LiteralNode & { subtype: string } {
const output = this.#parent[PARSE](propertyName, refs, options)
output.isOptional = true
output.validations = output.validations.concat(this.compileValidations(refs))
Expand Down Expand Up @@ -369,7 +381,11 @@ export class TransformModifier<
/**
* Compiles to compiler node
*/
[PARSE](propertyName: string, refs: RefsStore, options: ParserOptions): LiteralNode {
[PARSE](
propertyName: string,
refs: RefsStore,
options: ParserOptions
): LiteralNode & { subtype: string } {
const output = this.#parent[PARSE](propertyName, refs, options)
output.transformFnId = refs.trackTransformer(this.#transform)
return output
Expand All @@ -385,6 +401,11 @@ export abstract class BaseLiteralType<Input, Output, CamelCaseOutput> extends Ba
Output,
CamelCaseOutput
> {
/**
* Specify the subtype of the literal schema field
*/
abstract [SUBTYPE]: string

/**
* The child class must implement the clone method
*/
Expand Down Expand Up @@ -479,9 +500,14 @@ export abstract class BaseLiteralType<Input, Output, CamelCaseOutput> extends Ba
/**
* Compiles the schema type to a compiler node
*/
[PARSE](propertyName: string, refs: RefsStore, options: ParserOptions): LiteralNode {
[PARSE](
propertyName: string,
refs: RefsStore,
options: ParserOptions
): LiteralNode & { subtype: string } {
return {
type: 'literal',
subtype: this[SUBTYPE],
fieldName: propertyName,
propertyName: options.toCamelCase ? camelcase(propertyName) : propertyName,
bail: this.options.bail,
Expand Down
3 changes: 2 additions & 1 deletion src/schema/base/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@
* file that was distributed with this source code.
*/

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

import { ITYPE, OTYPE, COTYPE, PARSE, VALIDATION } from '../../symbols.js'
import type {
Parser,
Validation,
RuleBuilder,
FieldOptions,
CompilerNodes,
ParserOptions,
ConstructableSchema,
} from '../../types.js'
Expand Down
7 changes: 6 additions & 1 deletion src/schema/boolean/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import { booleanRule } from './rules.js'
import { helpers } from '../../vine/helpers.js'
import { BaseLiteralType } from '../base/literal.js'
import { IS_OF_TYPE, UNIQUE_NAME } from '../../symbols.js'
import { IS_OF_TYPE, SUBTYPE, UNIQUE_NAME } from '../../symbols.js'
import type { FieldOptions, Validation } from '../../types.js'

/**
Expand All @@ -26,6 +26,11 @@ export class VineBoolean extends BaseLiteralType<boolean | string | number, bool

declare protected options: FieldOptions & { strict?: boolean };

/**
* The subtype of the literal schema field
*/
[SUBTYPE] = 'boolean';

/**
* The property must be implemented for "unionOfTypes"
*/
Expand Down
7 changes: 6 additions & 1 deletion src/schema/date/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

import dayjs from 'dayjs'
import { BaseLiteralType } from '../base/literal.js'
import { IS_OF_TYPE, UNIQUE_NAME } from '../../symbols.js'
import { IS_OF_TYPE, SUBTYPE, UNIQUE_NAME } from '../../symbols.js'
import {
dateRule,
afterRule,
Expand Down Expand Up @@ -64,6 +64,11 @@ export class VineDate extends BaseLiteralType<string | number, Date, Date> {
*/
[UNIQUE_NAME] = 'vine.date';

/**
* The subtype of the literal schema field
*/
[SUBTYPE] = 'date';

/**
* Checks if the value is of date type. The method must be
* implemented for "unionOfTypes"
Expand Down
8 changes: 7 additions & 1 deletion src/schema/enum/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import { enumRule } from './rules.js'
import { BaseLiteralType } from '../base/literal.js'
import type { FieldContext, FieldOptions, Validation } from '../../types.js'
import { SUBTYPE } from '../../symbols.js'

/**
* VineEnum represents a enum data type that performs validation
Expand All @@ -27,7 +28,12 @@ export class VineEnum<const Values extends readonly unknown[]> extends BaseLiter
enum: enumRule,
}

#values: Values | ((field: FieldContext) => Values)
#values: Values | ((field: FieldContext) => Values);

/**
* The subtype of the literal schema field
*/
[SUBTYPE] = 'enum'

/**
* Returns the enum choices
Expand Down
8 changes: 7 additions & 1 deletion src/schema/enum/native_enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import { enumRule } from './rules.js'
import { BaseLiteralType } from '../base/literal.js'
import type { EnumLike, FieldOptions, Validation } from '../../types.js'
import { SUBTYPE } from '../../symbols.js'

/**
* VineNativeEnum represents a enum data type that performs validation
Expand All @@ -30,7 +31,12 @@ export class VineNativeEnum<Values extends EnumLike> extends BaseLiteralType<
enum: enumRule,
}

#values: Values
#values: Values;

/**
* The subtype of the literal schema field
*/
[SUBTYPE] = 'enum'

constructor(values: Values, options?: FieldOptions, validations?: Validation<any>[]) {
super(options, validations || [enumRule({ choices: Object.values(values) })])
Expand Down
8 changes: 7 additions & 1 deletion src/schema/literal/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import { equalsRule } from './rules.js'
import { BaseLiteralType } from '../base/literal.js'
import type { FieldOptions, Validation } from '../../types.js'
import { SUBTYPE } from '../../symbols.js'

/**
* VineLiteral represents a type that matches an exact value
Expand All @@ -22,7 +23,12 @@ export class VineLiteral<Value> extends BaseLiteralType<Value, Value, Value> {
equals: equalsRule,
}

#value: Value
#value: Value;

/**
* The subtype of the literal schema field
*/
[SUBTYPE] = 'literal'

constructor(value: Value, options?: FieldOptions, validations?: Validation<any>[]) {
super(options, validations || [equalsRule({ expectedValue: value })])
Expand Down
7 changes: 6 additions & 1 deletion src/schema/number/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import { helpers } from '../../vine/helpers.js'
import { BaseLiteralType } from '../base/literal.js'
import { FieldOptions, Validation } from '../../types.js'
import { IS_OF_TYPE, UNIQUE_NAME } from '../../symbols.js'
import { IS_OF_TYPE, SUBTYPE, UNIQUE_NAME } from '../../symbols.js'

import {
maxRule,
Expand Down Expand Up @@ -45,6 +45,11 @@ export class VineNumber extends BaseLiteralType<string | number, number, number>
withoutDecimals: withoutDecimalsRule,
};

/**
* The subtype of the literal schema field
*/
[SUBTYPE] = 'number';

/**
* The property must be implemented for "unionOfTypes"
*/
Expand Down
7 changes: 6 additions & 1 deletion src/schema/string/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
*/

import { BaseLiteralType } from '../base/literal.js'
import { IS_OF_TYPE, UNIQUE_NAME } from '../../symbols.js'
import { IS_OF_TYPE, SUBTYPE, UNIQUE_NAME } from '../../symbols.js'
import type {
Validation,
AlphaOptions,
Expand Down Expand Up @@ -100,6 +100,11 @@ export class VineString extends BaseLiteralType<string, string, string> {
normalizeEmail: normalizeEmailRule,
};

/**
* The subtype of the literal schema field
*/
[SUBTYPE] = 'string';

/**
* The property must be implemented for "unionOfTypes"
*/
Expand Down
5 changes: 5 additions & 0 deletions src/symbols.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,8 @@ export const COTYPE = Symbol.for('camelcase_opaque_type')
* The symbol to generate a validation rule from rule builder
*/
export const VALIDATION = Symbol.for('to_validation')

/**
* The symbol for the subtype of a literal field
*/
export const SUBTYPE = Symbol.for('subtype')
18 changes: 17 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,14 @@ import type { IsMobilePhoneOptions, MobilePhoneLocale } from 'validator/lib/isMo
import type {
ParseFn,
RefsStore,
TupleNode,
ArrayNode,
UnionNode,
RecordNode,
ObjectNode,
TransformFn,
LiteralNode,
FieldContext,
CompilerNodes,
MessagesProviderContact,
ErrorReporterContract as BaseReporter,
} from '@vinejs/compiler/types'
Expand All @@ -28,6 +33,17 @@ import type { helpers } from './vine/helpers.js'
import type { ValidationError } from './errors/validation_error.js'
import type { OTYPE, COTYPE, PARSE, VALIDATION, UNIQUE_NAME, IS_OF_TYPE, ITYPE } from './symbols.js'

/**
* Compiler nodes emitted by Vine
*/
export type CompilerNodes =
| (LiteralNode & { subtype: string })
| ObjectNode
| ArrayNode
| UnionNode
| RecordNode
| TupleNode

/**
* Options accepted by the mobile number validation
*/
Expand Down
3 changes: 3 additions & 0 deletions tests/integration/validator.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ test.group('Validator | toJSON', () => {
"isOptional": false,
"parseFnId": undefined,
"propertyName": "name",
"subtype": "string",
"type": "literal",
"validations": [
{
Expand All @@ -270,6 +271,7 @@ test.group('Validator | toJSON', () => {
"isOptional": false,
"parseFnId": undefined,
"propertyName": "email",
"subtype": "string",
"type": "literal",
"validations": [
{
Expand All @@ -291,6 +293,7 @@ test.group('Validator | toJSON', () => {
"isOptional": false,
"parseFnId": undefined,
"propertyName": "role",
"subtype": "string",
"type": "literal",
"validations": [
{
Expand Down
Loading

0 comments on commit 818fbf0

Please sign in to comment.