import { SimpleErrorReporter, SimpleMessagesProvider, ValidationError, helpers } from "./chunk-YXNUTVGP.js"; import { fields, messages } from "./chunk-M2DOTJGC.js"; import { __export } from "./chunk-MLKGABMK.js"; // src/vine/create_rule.ts function createRule(validator, metaData) { const rule = { validator, isAsync: metaData?.isAsync || validator.constructor.name === "AsyncFunction", implicit: metaData?.implicit ?? false }; return function(...options) { return { rule, options: options[0] }; }; } // src/schema/builder.ts import Macroable3 from "@poppinss/macroable"; // src/schema/base/literal.ts import camelcase from "camelcase"; import Macroable from "@poppinss/macroable"; // src/symbols.ts var symbols_exports = {}; __export(symbols_exports, { COTYPE: () => COTYPE, IS_OF_TYPE: () => IS_OF_TYPE, ITYPE: () => ITYPE, OTYPE: () => OTYPE, PARSE: () => PARSE, SUBTYPE: () => SUBTYPE, UNIQUE_NAME: () => UNIQUE_NAME, VALIDATION: () => VALIDATION }); var UNIQUE_NAME = Symbol.for("schema_name"); var IS_OF_TYPE = Symbol.for("is_of_type"); var PARSE = Symbol.for("parse"); var ITYPE = Symbol.for("opaque_input_type"); var OTYPE = Symbol.for("opaque_type"); var COTYPE = Symbol.for("camelcase_opaque_type"); var VALIDATION = Symbol.for("to_validation"); var SUBTYPE = Symbol.for("subtype"); // src/schema/base/rules.ts var requiredWhen = createRule( (_, checker, field) => { const shouldBeRequired = checker(field); if (!field.isDefined && shouldBeRequired) { field.report(messages.required, "required", field); } }, { implicit: true } ); // src/schema/base/literal.ts var BaseModifiersType = class extends Macroable { /** * Mark the field under validation as optional. An optional * field allows both null and undefined values. */ optional(validations) { return new OptionalModifier(this, validations); } /** * Mark the field under validation to be null. The null value will * be written to the output as well. * * If `optional` and `nullable` are used together, then both undefined * and null values will be allowed. */ nullable() { return new NullableModifier(this); } /** * Apply transform on the final validated value. The transform method may * convert the value to any new datatype. */ transform(transformer) { return new TransformModifier(transformer, this); } }; var NullableModifier = class _NullableModifier extends BaseModifiersType { #parent; constructor(parent) { super(); this.#parent = parent; } /** * Creates a fresh instance of the underlying schema type * and wraps it inside the nullable modifier */ clone() { return new _NullableModifier(this.#parent.clone()); } /** * Compiles to compiler node */ [PARSE](propertyName, refs, options) { const output = this.#parent[PARSE](propertyName, refs, options); output.allowNull = true; return output; } }; var OptionalModifier = class _OptionalModifier extends BaseModifiersType { #parent; /** * Optional modifier validations list */ validations; constructor(parent, validations) { super(); this.#parent = parent; this.validations = validations || []; } /** * Shallow clones the validations. Since, there are no API's to mutate * the validation options, we can safely copy them by reference. */ cloneValidations() { return this.validations.map((validation) => { return { options: validation.options, rule: validation.rule }; }); } /** * Compiles validations */ compileValidations(refs) { return this.validations.map((validation) => { return { ruleFnId: refs.track({ validator: validation.rule.validator, options: validation.options }), implicit: validation.rule.implicit, isAsync: validation.rule.isAsync }; }); } /** * Push a validation to the validations chain. */ use(validation) { this.validations.push(VALIDATION in validation ? validation[VALIDATION]() : validation); return this; } requiredWhen(otherField, operator, expectedValue) { if (typeof otherField === "function") { return this.use(requiredWhen(otherField)); } let checker; switch (operator) { case "=": checker = (value) => value === expectedValue; break; case "!=": checker = (value) => value !== expectedValue; break; case "in": checker = (value) => expectedValue.includes(value); break; case "notIn": checker = (value) => !expectedValue.includes(value); break; case ">": checker = (value) => value > expectedValue; break; case "<": checker = (value) => value < expectedValue; break; case ">=": checker = (value) => value >= expectedValue; break; case "<=": checker = (value) => value <= expectedValue; } return this.use( requiredWhen((field) => { const otherFieldValue = helpers.getNestedValue(otherField, field); return checker(otherFieldValue); }) ); } /** * Mark the field under validation as required when all * the other fields are present with value other * than `undefined` or `null`. */ requiredIfExists(fields2) { const fieldsToExist = Array.isArray(fields2) ? fields2 : [fields2]; return this.use( requiredWhen((field) => { return fieldsToExist.every( (otherField) => helpers.exists(helpers.getNestedValue(otherField, field)) ); }) ); } /** * Mark the field under validation as required when any * one of the other fields are present with non-nullable * value. */ requiredIfAnyExists(fields2) { return this.use( requiredWhen((field) => { return fields2.some( (otherField) => helpers.exists(helpers.getNestedValue(otherField, field)) ); }) ); } /** * Mark the field under validation as required when all * the other fields are missing or their value is * `undefined` or `null`. */ requiredIfMissing(fields2) { const fieldsToExist = Array.isArray(fields2) ? fields2 : [fields2]; return this.use( requiredWhen((field) => { return fieldsToExist.every( (otherField) => helpers.isMissing(helpers.getNestedValue(otherField, field)) ); }) ); } /** * Mark the field under validation as required when any * one of the other fields are missing. */ requiredIfAnyMissing(fields2) { return this.use( requiredWhen((field) => { return fields2.some( (otherField) => helpers.isMissing(helpers.getNestedValue(otherField, field)) ); }) ); } /** * Creates a fresh instance of the underlying schema type * and wraps it inside the optional modifier */ clone() { return new _OptionalModifier(this.#parent.clone(), this.cloneValidations()); } /** * Compiles to compiler node */ [PARSE](propertyName, refs, options) { const output = this.#parent[PARSE](propertyName, refs, options); output.isOptional = true; output.validations = output.validations.concat(this.compileValidations(refs)); return output; } }; var TransformModifier = class _TransformModifier extends BaseModifiersType { #parent; #transform; constructor(transform, parent) { super(); this.#transform = transform; this.#parent = parent; } /** * Creates a fresh instance of the underlying schema type * and wraps it inside the transform modifier. */ clone() { return new _TransformModifier(this.#transform, this.#parent.clone()); } /** * Compiles to compiler node */ [PARSE](propertyName, refs, options) { const output = this.#parent[PARSE](propertyName, refs, options); output.transformFnId = refs.trackTransformer(this.#transform); return output; } }; var BaseLiteralType = class extends BaseModifiersType { /** * Field options */ options; /** * Set of validations to run */ validations; constructor(options, validations) { super(); this.options = { bail: true, allowNull: false, isOptional: false, ...options }; this.validations = validations || []; } /** * Shallow clones the validations. Since, there are no API's to mutate * the validation options, we can safely copy them by reference. */ cloneValidations() { return this.validations.map((validation) => { return { options: validation.options, rule: validation.rule }; }); } /** * Shallow clones the options */ cloneOptions() { return { ...this.options }; } /** * Compiles validations */ compileValidations(refs) { return this.validations.map((validation) => { return { ruleFnId: refs.track({ validator: validation.rule.validator, options: validation.options }), implicit: validation.rule.implicit, isAsync: validation.rule.isAsync }; }); } /** * Define a method to parse the input value. The method * is invoked before any validation and hence you must * perform type-checking to know the value you are * working it. */ parse(callback) { this.options.parse = callback; return this; } /** * Push a validation to the validations chain. */ use(validation) { this.validations.push(VALIDATION in validation ? validation[VALIDATION]() : validation); return this; } /** * Enable/disable the bail mode. In bail mode, the field validations * are stopped after the first error. */ bail(state) { this.options.bail = state; return this; } /** * Compiles the schema type to a compiler node */ [PARSE](propertyName, refs, options) { return { type: "literal", subtype: this[SUBTYPE], fieldName: propertyName, propertyName: options.toCamelCase ? camelcase(propertyName) : propertyName, bail: this.options.bail, allowNull: this.options.allowNull, isOptional: this.options.isOptional, parseFnId: this.options.parse ? refs.trackParser(this.options.parse) : void 0, validations: this.compileValidations(refs) }; } }; // src/schema/any/main.ts var VineAny = class _VineAny extends BaseLiteralType { constructor(options, validations) { 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 */ clone() { return new _VineAny(this.cloneOptions(), this.cloneValidations()); } }; // src/schema/enum/rules.ts var enumRule = createRule((value, options, field) => { const choices = typeof options.choices === "function" ? options.choices(field) : options.choices; if (!choices.includes(value)) { field.report(messages.enum, "enum", field, { choices }); } }); // src/schema/enum/main.ts var VineEnum = class _VineEnum extends BaseLiteralType { /** * Default collection of enum rules */ static rules = { enum: enumRule }; #values; /** * The subtype of the literal schema field */ [SUBTYPE] = "enum"; /** * Returns the enum choices */ getChoices() { return this.#values; } constructor(values, options, validations) { super(options, validations || [enumRule({ choices: values })]); this.#values = values; } /** * Clones the VineEnum schema type. The applied options * and validations are copied to the new instance */ clone() { return new _VineEnum(this.#values, this.cloneOptions(), this.cloneValidations()); } }; // src/schema/date/main.ts import dayjs2 from "dayjs"; // src/schema/date/rules.ts import dayjs from "dayjs"; import isSameOrAfter from "dayjs/plugin/isSameOrAfter.js"; import isSameOrBefore from "dayjs/plugin/isSameOrBefore.js"; import customParseFormat from "dayjs/plugin/customParseFormat.js"; var DEFAULT_DATE_FORMATS = ["YYYY-MM-DD", "YYYY-MM-DD HH:mm:ss"]; dayjs.extend(customParseFormat); dayjs.extend(isSameOrAfter); dayjs.extend(isSameOrBefore); var dateRule = createRule((value, options, field) => { if (typeof value !== "string" && typeof value !== "number") { field.report(messages.date, "date", field); return; } let isTimestampAllowed = false; let isISOAllowed = false; let formats = options.formats || DEFAULT_DATE_FORMATS; if (Array.isArray(formats)) { formats = [...formats]; isTimestampAllowed = formats.includes("x"); isISOAllowed = formats.includes("iso8601"); } else if (typeof formats !== "string") { formats = { ...formats }; isTimestampAllowed = formats.format === "x"; isISOAllowed = formats.format === "iso"; } const valueAsNumber = isTimestampAllowed ? helpers.asNumber(value) : value; let dateTime; if (isTimestampAllowed && !Number.isNaN(valueAsNumber)) { dateTime = dayjs(valueAsNumber); } else { dateTime = dayjs(value, formats, true); } if (!dateTime.isValid() && isISOAllowed) { dateTime = dayjs(value); } if (!dateTime.isValid()) { field.report(messages.date, "date", field); return; } field.meta.$value = dateTime; field.meta.$formats = formats; field.mutate(dateTime.toDate(), field); }); var equalsRule = createRule((_, options, field) => { if (!field.meta.$value) { return; } const compare = options.compare || "day"; const format = options.format || DEFAULT_DATE_FORMATS; const dateTime = field.meta.$value; const expectedValue = typeof options.expectedValue === "function" ? options.expectedValue(field) : options.expectedValue; const expectedDateTime = dayjs(expectedValue, format, true); if (!expectedDateTime.isValid()) { throw new Error(`Invalid datetime value "${expectedValue}" provided to the equals rule`); } if (!dateTime.isSame(expectedDateTime, compare)) { field.report(messages["date.equals"], "date.equals", field, { expectedValue, compare }); } }); var afterRule = createRule((_, options, field) => { if (!field.meta.$value) { return; } const compare = options.compare || "day"; const format = options.format || DEFAULT_DATE_FORMATS; const dateTime = field.meta.$value; const expectedValue = typeof options.expectedValue === "function" ? options.expectedValue(field) : options.expectedValue; const expectedDateTime = expectedValue === "today" ? dayjs() : expectedValue === "tomorrow" ? dayjs().add(1, "day") : dayjs(expectedValue, format, true); if (!expectedDateTime.isValid()) { throw new Error(`Invalid datetime value "${expectedValue}" provided to the after rule`); } if (!dateTime.isAfter(expectedDateTime, compare)) { field.report(messages["date.after"], "date.after", field, { expectedValue, compare }); } }); var afterOrEqualRule = createRule((_, options, field) => { if (!field.meta.$value) { return; } const compare = options.compare || "day"; const format = options.format || DEFAULT_DATE_FORMATS; const dateTime = field.meta.$value; const expectedValue = typeof options.expectedValue === "function" ? options.expectedValue(field) : options.expectedValue; const expectedDateTime = expectedValue === "today" ? dayjs() : expectedValue === "tomorrow" ? dayjs().add(1, "day") : dayjs(expectedValue, format, true); if (!expectedDateTime.isValid()) { throw new Error(`Invalid datetime value "${expectedValue}" provided to the afterOrEqual rule`); } if (!dateTime.isSameOrAfter(expectedDateTime, compare)) { field.report(messages["date.afterOrEqual"], "date.afterOrEqual", field, { expectedValue, compare }); } }); var beforeRule = createRule((_, options, field) => { if (!field.meta.$value) { return; } const compare = options.compare || "day"; const format = options.format || DEFAULT_DATE_FORMATS; const dateTime = field.meta.$value; const expectedValue = typeof options.expectedValue === "function" ? options.expectedValue(field) : options.expectedValue; const expectedDateTime = expectedValue === "today" ? dayjs() : expectedValue === "yesterday" ? dayjs().subtract(1, "day") : dayjs(expectedValue, format, true); if (!expectedDateTime.isValid()) { throw new Error(`Invalid datetime value "${expectedValue}" provided to the before rule`); } if (!dateTime.isBefore(expectedDateTime, compare)) { field.report(messages["date.before"], "date.before", field, { expectedValue, compare }); } }); var beforeOrEqualRule = createRule((_, options, field) => { if (!field.meta.$value) { return; } const compare = options.compare || "day"; const format = options.format || DEFAULT_DATE_FORMATS; const dateTime = field.meta.$value; const expectedValue = typeof options.expectedValue === "function" ? options.expectedValue(field) : options.expectedValue; const expectedDateTime = expectedValue === "today" ? dayjs() : expectedValue === "yesterday" ? dayjs().subtract(1, "day") : dayjs(expectedValue, format, true); if (!expectedDateTime.isValid()) { throw new Error(`Invalid datetime value "${expectedValue}" provided to the beforeOrEqual rule`); } if (!dateTime.isSameOrBefore(expectedDateTime, compare)) { field.report(messages["date.beforeOrEqual"], "date.beforeOrEqual", field, { expectedValue, compare }); } }); var sameAsRule = createRule((_, options, field) => { if (!field.meta.$value) { return; } const compare = options.compare || "day"; const dateTime = field.meta.$value; const format = options.format || field.meta.$formats; const expectedValue = helpers.getNestedValue(options.otherField, field); const expectedDateTime = dayjs(expectedValue, format, true); if (!expectedDateTime.isValid()) { return; } if (!dateTime.isSame(expectedDateTime, compare)) { field.report(messages["date.sameAs"], "date.sameAs", field, { otherField: options.otherField, expectedValue, compare }); } }); var notSameAsRule = createRule((_, options, field) => { if (!field.meta.$value) { return; } const compare = options.compare || "day"; const dateTime = field.meta.$value; const format = options.format || field.meta.$formats; const expectedValue = helpers.getNestedValue(options.otherField, field); const expectedDateTime = dayjs(expectedValue, format, true); if (!expectedDateTime.isValid()) { return; } if (dateTime.isSame(expectedDateTime, compare)) { field.report(messages["date.notSameAs"], "date.notSameAs", field, { otherField: options.otherField, expectedValue, compare }); } }); var afterFieldRule = createRule((_, options, field) => { if (!field.meta.$value) { return; } const compare = options.compare || "day"; const dateTime = field.meta.$value; const format = options.format || field.meta.$formats; const expectedValue = helpers.getNestedValue(options.otherField, field); const expectedDateTime = dayjs(expectedValue, format, true); if (!expectedDateTime.isValid()) { return; } if (!dateTime.isAfter(expectedDateTime, compare)) { field.report(messages["date.afterField"], "date.afterField", field, { otherField: options.otherField, expectedValue, compare }); } }); var afterOrSameAsRule = createRule((_, options, field) => { if (!field.meta.$value) { return; } const compare = options.compare || "day"; const dateTime = field.meta.$value; const format = options.format || field.meta.$formats; const expectedValue = helpers.getNestedValue(options.otherField, field); const expectedDateTime = dayjs(expectedValue, format, true); if (!expectedDateTime.isValid()) { return; } if (!dateTime.isSameOrAfter(expectedDateTime, compare)) { field.report(messages["date.afterOrSameAs"], "date.afterOrSameAs", field, { otherField: options.otherField, expectedValue, compare }); } }); var beforeFieldRule = createRule((_, options, field) => { if (!field.meta.$value) { return; } const compare = options.compare || "day"; const dateTime = field.meta.$value; const format = options.format || field.meta.$formats; const expectedValue = helpers.getNestedValue(options.otherField, field); const expectedDateTime = dayjs(expectedValue, format, true); if (!expectedDateTime.isValid()) { return; } if (!dateTime.isBefore(expectedDateTime, compare)) { field.report(messages["date.beforeField"], "date.beforeField", field, { otherField: options.otherField, expectedValue, compare }); } }); var beforeOrSameAsRule = createRule((_, options, field) => { if (!field.meta.$value) { return; } const compare = options.compare || "day"; const dateTime = field.meta.$value; const format = options.format || field.meta.$formats; const expectedValue = helpers.getNestedValue(options.otherField, field); const expectedDateTime = dayjs(expectedValue, format, true); if (!expectedDateTime.isValid()) { return; } if (!dateTime.isSameOrBefore(expectedDateTime, compare)) { field.report(messages["date.beforeOrSameAs"], "date.beforeOrSameAs", field, { otherField: options.otherField, expectedValue, compare }); } }); var weekendRule = createRule((_, __, field) => { if (!field.meta.$value) { return; } const dateTime = field.meta.$value; const day = dateTime.day(); if (day !== 0 && day !== 6) { field.report(messages["date.weekend"], "date.weekend", field); } }); var weekdayRule = createRule((_, __, field) => { if (!field.meta.$value) { return; } const dateTime = field.meta.$value; const day = dateTime.day(); if (day === 0 || day === 6) { field.report(messages["date.weekday"], "date.weekday", field); } }); // src/schema/date/main.ts var VineDate = class _VineDate extends BaseLiteralType { /** * Available VineDate rules */ static rules = { equals: equalsRule, after: afterRule, afterOrEqual: afterOrEqualRule, before: beforeRule, beforeOrEqual: beforeOrEqualRule, sameAs: sameAsRule, notSameAs: notSameAsRule, afterField: afterFieldRule, afterOrSameAs: afterOrSameAsRule, beforeField: beforeFieldRule, beforeOrSameAs: beforeOrSameAsRule, weekend: weekendRule, weekday: weekdayRule }; /** * The property must be implemented for "unionOfTypes" */ [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" */ [IS_OF_TYPE] = (value) => { if (typeof value !== "string") { return false; } return dayjs2(value, this.options.formats || DEFAULT_DATE_FORMATS, true).isValid(); }; constructor(options, validations) { super(options, validations || [dateRule(options || {})]); } /** * The equals rule compares the input value to be same * as the expected value. * * By default, the comparions of day, month and years are performed. */ equals(expectedValue, options) { return this.use(equalsRule({ expectedValue, ...options })); } /** * The after rule compares the input value to be after * the expected value. * * By default, the comparions of day, month and years are performed. */ after(expectedValue, options) { return this.use(afterRule({ expectedValue, ...options })); } /** * The after or equal rule compares the input value to be * after or equal to the expected value. * * By default, the comparions of day, month and years are performed. */ afterOrEqual(expectedValue, options) { return this.use(afterOrEqualRule({ expectedValue, ...options })); } /** * The before rule compares the input value to be before * the expected value. * * By default, the comparions of day, month and years are performed. */ before(expectedValue, options) { return this.use(beforeRule({ expectedValue, ...options })); } /** * The before rule compares the input value to be before * the expected value. * * By default, the comparions of day, month and years are performed. */ beforeOrEqual(expectedValue, options) { return this.use(beforeOrEqualRule({ expectedValue, ...options })); } /** * The sameAs rule expects the input value to be same * as the value of the other field. * * By default, the comparions of day, month and years are performed */ sameAs(otherField, options) { return this.use(sameAsRule({ otherField, ...options })); } /** * The notSameAs rule expects the input value to be different * from the other field's value * * By default, the comparions of day, month and years are performed */ notSameAs(otherField, options) { return this.use(notSameAsRule({ otherField, ...options })); } /** * The afterField rule expects the input value to be after * the other field's value. * * By default, the comparions of day, month and years are performed */ afterField(otherField, options) { return this.use(afterFieldRule({ otherField, ...options })); } /** * The afterOrSameAs rule expects the input value to be after * or equal to the other field's value. * * By default, the comparions of day, month and years are performed */ afterOrSameAs(otherField, options) { return this.use(afterOrSameAsRule({ otherField, ...options })); } /** * The beforeField rule expects the input value to be before * the other field's value. * * By default, the comparions of day, month and years are performed */ beforeField(otherField, options) { return this.use(beforeFieldRule({ otherField, ...options })); } /** * The beforeOrSameAs rule expects the input value to be before * or same as the other field's value. * * By default, the comparions of day, month and years are performed */ beforeOrSameAs(otherField, options) { return this.use(beforeOrSameAsRule({ otherField, ...options })); } /** * The weekend rule ensures the date falls on a weekend */ weekend() { return this.use(weekendRule()); } /** * The weekday rule ensures the date falls on a weekday */ weekday() { return this.use(weekdayRule()); } /** * Clones the VineDate schema type. The applied options * and validations are copied to the new instance */ clone() { return new _VineDate(this.cloneOptions(), this.cloneValidations()); } }; // src/schema/union/main.ts import camelcase2 from "camelcase"; var VineUnion = class _VineUnion { #conditionals; #otherwiseCallback = (_, field) => { field.report(messages.union, "union", field); }; constructor(conditionals) { this.#conditionals = conditionals; } /** * Define a fallback method to invoke when all of the union conditions * fail. You may use this method to report an error. */ otherwise(callback) { this.#otherwiseCallback = callback; return this; } /** * Clones the VineUnion schema type. */ clone() { const cloned = new _VineUnion(this.#conditionals); cloned.otherwise(this.#otherwiseCallback); return cloned; } /** * Compiles to a union */ [PARSE](propertyName, refs, options) { return { type: "union", fieldName: propertyName, propertyName: options.toCamelCase ? camelcase2(propertyName) : propertyName, elseConditionalFnRefId: refs.trackConditional(this.#otherwiseCallback), conditions: this.#conditionals.map( (conditional) => conditional[PARSE](propertyName, refs, options) ) }; } }; // src/schema/union/conditional.ts var UnionConditional = class { /** * Properties to merge when conditonal is true */ #schema; /** * Conditional to evaluate */ #conditional; constructor(conditional, schema) { this.#schema = schema; this.#conditional = conditional; } /** * Compiles to a union conditional */ [PARSE](propertyName, refs, options) { return { conditionalFnRefId: refs.trackConditional(this.#conditional), schema: this.#schema[PARSE](propertyName, refs, options) }; } }; // src/schema/union/builder.ts function union(conditionals) { return new VineUnion(conditionals); } union.if = function unionIf(conditon, schema) { return new UnionConditional(conditon, schema); }; union.else = function unionElse(schema) { return new UnionConditional(() => true, schema); }; // src/schema/tuple/main.ts import camelcase3 from "camelcase"; // src/schema/base/main.ts import Macroable2 from "@poppinss/macroable"; var BaseModifiersType2 = class extends Macroable2 { /** * Mark the field under validation as optional. An optional * field allows both null and undefined values. */ optional() { return new OptionalModifier2(this); } /** * Mark the field under validation to be null. The null value will * be written to the output as well. * * If `optional` and `nullable` are used together, then both undefined * and null values will be allowed. */ nullable() { return new NullableModifier2(this); } }; var NullableModifier2 = class _NullableModifier extends BaseModifiersType2 { #parent; constructor(parent) { super(); this.#parent = parent; } /** * Creates a fresh instance of the underlying schema type * and wraps it inside the nullable modifier */ clone() { return new _NullableModifier(this.#parent.clone()); } /** * Compiles to compiler node */ [PARSE](propertyName, refs, options) { const output = this.#parent[PARSE](propertyName, refs, options); if (output.type !== "union") { output.allowNull = true; } return output; } }; var OptionalModifier2 = class _OptionalModifier extends BaseModifiersType2 { #parent; /** * Optional modifier validations list */ validations; constructor(parent, validations) { super(); this.#parent = parent; this.validations = validations || []; } /** * Shallow clones the validations. Since, there are no API's to mutate * the validation options, we can safely copy them by reference. */ cloneValidations() { return this.validations.map((validation) => { return { options: validation.options, rule: validation.rule }; }); } /** * Compiles validations */ compileValidations(refs) { return this.validations.map((validation) => { return { ruleFnId: refs.track({ validator: validation.rule.validator, options: validation.options }), implicit: validation.rule.implicit, isAsync: validation.rule.isAsync }; }); } /** * Push a validation to the validations chain. */ use(validation) { this.validations.push(VALIDATION in validation ? validation[VALIDATION]() : validation); return this; } requiredWhen(otherField, operator, expectedValue) { if (typeof otherField === "function") { return this.use(requiredWhen(otherField)); } let checker; switch (operator) { case "=": checker = (value) => value === expectedValue; break; case "!=": checker = (value) => value !== expectedValue; break; case "in": checker = (value) => expectedValue.includes(value); break; case "notIn": checker = (value) => !expectedValue.includes(value); break; case ">": checker = (value) => value > expectedValue; break; case "<": checker = (value) => value < expectedValue; break; case ">=": checker = (value) => value >= expectedValue; break; case "<=": checker = (value) => value <= expectedValue; } return this.use( requiredWhen((field) => { const otherFieldValue = helpers.getNestedValue(otherField, field); return checker(otherFieldValue); }) ); } /** * Mark the field under validation as required when all * the other fields are present with value other * than `undefined` or `null`. */ requiredIfExists(fields2) { const fieldsToExist = Array.isArray(fields2) ? fields2 : [fields2]; return this.use( requiredWhen((field) => { return fieldsToExist.every((otherField) => { return helpers.exists(helpers.getNestedValue(otherField, field)); }); }) ); } /** * Mark the field under validation as required when any * one of the other fields are present with non-nullable * value. */ requiredIfAnyExists(fields2) { return this.use( requiredWhen((field) => { return fields2.some( (otherField) => helpers.exists(helpers.getNestedValue(otherField, field)) ); }) ); } /** * Mark the field under validation as required when all * the other fields are missing or their value is * `undefined` or `null`. */ requiredIfMissing(fields2) { const fieldsToExist = Array.isArray(fields2) ? fields2 : [fields2]; return this.use( requiredWhen((field) => { return fieldsToExist.every( (otherField) => helpers.isMissing(helpers.getNestedValue(otherField, field)) ); }) ); } /** * Mark the field under validation as required when any * one of the other fields are missing. */ requiredIfAnyMissing(fields2) { return this.use( requiredWhen((field) => { return fields2.some( (otherField) => helpers.isMissing(helpers.getNestedValue(otherField, field)) ); }) ); } /** * Creates a fresh instance of the underlying schema type * and wraps it inside the optional modifier */ clone() { return new _OptionalModifier(this.#parent.clone(), this.cloneValidations()); } /** * Compiles to compiler node */ [PARSE](propertyName, refs, options) { const output = this.#parent[PARSE](propertyName, refs, options); if (output.type !== "union") { output.isOptional = true; output.validations = output.validations.concat(this.compileValidations(refs)); } return output; } }; var BaseType = class extends BaseModifiersType2 { /** * Field options */ options; /** * Set of validations to run */ validations; constructor(options, validations) { super(); this.options = options || { bail: true, allowNull: false, isOptional: false }; this.validations = validations || []; } /** * Shallow clones the validations. Since, there are no API's to mutate * the validation options, we can safely copy them by reference. */ cloneValidations() { return this.validations.map((validation) => { return { options: validation.options, rule: validation.rule }; }); } /** * Shallow clones the options */ cloneOptions() { return { ...this.options }; } /** * Compiles validations */ compileValidations(refs) { return this.validations.map((validation) => { return { ruleFnId: refs.track({ validator: validation.rule.validator, options: validation.options }), implicit: validation.rule.implicit, isAsync: validation.rule.isAsync }; }); } /** * Define a method to parse the input value. The method * is invoked before any validation and hence you must * perform type-checking to know the value you are * working it. */ parse(callback) { this.options.parse = callback; return this; } /** * Push a validation to the validations chain. */ use(validation) { this.validations.push(VALIDATION in validation ? validation[VALIDATION]() : validation); return this; } /** * Enable/disable the bail mode. In bail mode, the field validations * are stopped after the first error. */ bail(state) { this.options.bail = state; return this; } }; // src/schema/tuple/main.ts var VineTuple = class _VineTuple extends BaseType { #schemas; /** * Whether or not to allow unknown properties */ #allowUnknownProperties = false; /** * The property must be implemented for "unionOfTypes" */ [UNIQUE_NAME] = "vine.array"; /** * Checks if the value is of array type. The method must be * implemented for "unionOfTypes" */ [IS_OF_TYPE] = (value) => { return Array.isArray(value); }; constructor(schemas, options, validations) { super(options, validations); this.#schemas = schemas; } /** * Copy unknown properties to the final output. */ allowUnknownProperties() { this.#allowUnknownProperties = true; return this; } /** * Clone object */ clone() { const cloned = new _VineTuple( this.#schemas.map((schema) => schema.clone()), this.cloneOptions(), this.cloneValidations() ); if (this.#allowUnknownProperties) { cloned.allowUnknownProperties(); } return cloned; } /** * Compiles to array data type */ [PARSE](propertyName, refs, options) { return { type: "tuple", fieldName: propertyName, propertyName: options.toCamelCase ? camelcase3(propertyName) : propertyName, bail: this.options.bail, allowNull: this.options.allowNull, isOptional: this.options.isOptional, allowUnknownProperties: this.#allowUnknownProperties, parseFnId: this.options.parse ? refs.trackParser(this.options.parse) : void 0, validations: this.compileValidations(refs), properties: this.#schemas.map((schema, index) => schema[PARSE](String(index), refs, options)) }; } }; // src/schema/array/main.ts import camelcase4 from "camelcase"; // src/schema/array/rules.ts var minLengthRule = createRule((value, options, field) => { if (!field.isValid) { return; } if (value.length < options.min) { field.report(messages["array.minLength"], "array.minLength", field, options); } }); var maxLengthRule = createRule((value, options, field) => { if (!field.isValid) { return; } if (value.length > options.max) { field.report(messages["array.maxLength"], "array.maxLength", field, options); } }); var fixedLengthRule = createRule((value, options, field) => { if (!field.isValid) { return; } if (value.length !== options.size) { field.report(messages["array.fixedLength"], "array.fixedLength", field, options); } }); var notEmptyRule = createRule((value, _, field) => { if (!field.isValid) { return; } if (value.length <= 0) { field.report(messages.notEmpty, "notEmpty", field); } }); var distinctRule = createRule((value, options, field) => { if (!field.isValid) { return; } if (!helpers.isDistinct(value, options.fields)) { field.report(messages.distinct, "distinct", field, options); } }); var compactRule = createRule((value, _, field) => { if (!field.isValid) { return; } field.mutate( value.filter((item) => helpers.exists(item) && item !== ""), field ); }); // src/schema/array/main.ts var VineArray = class _VineArray extends BaseType { /** * Default collection of array rules */ static rules = { compact: compactRule, notEmpty: notEmptyRule, distinct: distinctRule, minLength: minLengthRule, maxLength: maxLengthRule, fixedLength: fixedLengthRule }; #schema; /** * The property must be implemented for "unionOfTypes" */ [UNIQUE_NAME] = "vine.array"; /** * Checks if the value is of array type. The method must be * implemented for "unionOfTypes" */ [IS_OF_TYPE] = (value) => { return Array.isArray(value); }; constructor(schema, options, validations) { super(options, validations); this.#schema = schema; } /** * Enforce a minimum length on an array field */ minLength(expectedLength) { return this.use(minLengthRule({ min: expectedLength })); } /** * Enforce a maximum length on an array field */ maxLength(expectedLength) { return this.use(maxLengthRule({ max: expectedLength })); } /** * Enforce a fixed length on an array field */ fixedLength(expectedLength) { return this.use(fixedLengthRule({ size: expectedLength })); } /** * Ensure the array is not empty */ notEmpty() { return this.use(notEmptyRule()); } /** * Ensure array elements are distinct/unique */ distinct(fields2) { return this.use(distinctRule({ fields: fields2 })); } /** * Removes empty strings, null and undefined values from the array */ compact() { return this.use(compactRule()); } /** * Clones the VineArray schema type. The applied options * and validations are copied to the new instance */ clone() { return new _VineArray(this.#schema.clone(), this.cloneOptions(), this.cloneValidations()); } /** * Compiles to array data type */ [PARSE](propertyName, refs, options) { return { type: "array", fieldName: propertyName, propertyName: options.toCamelCase ? camelcase4(propertyName) : propertyName, bail: this.options.bail, allowNull: this.options.allowNull, isOptional: this.options.isOptional, each: this.#schema[PARSE]("*", refs, options), parseFnId: this.options.parse ? refs.trackParser(this.options.parse) : void 0, validations: this.compileValidations(refs) }; } }; // src/schema/object/main.ts import camelcase5 from "camelcase"; var VineCamelCaseObject = class _VineCamelCaseObject extends BaseModifiersType2 { #schema; /** * The property must be implemented for "unionOfTypes" */ [UNIQUE_NAME] = "types.object"; /** * Checks if the value is of object type. The method must be * implemented for "unionOfTypes" */ [IS_OF_TYPE] = (value) => { return value !== null && typeof value === "object" && !Array.isArray(value); }; constructor(schema) { super(); this.#schema = schema; } /** * Clone object */ clone() { return new _VineCamelCaseObject(this.#schema.clone()); } /** * Compiles the schema type to a compiler node */ [PARSE](propertyName, refs, options) { options.toCamelCase = true; return this.#schema[PARSE](propertyName, refs, options); } }; var VineObject = class _VineObject extends BaseType { /** * Object properties */ #properties; /** * Object groups to merge based on conditionals */ #groups = []; /** * Whether or not to allow unknown properties */ #allowUnknownProperties = false; /** * The property must be implemented for "unionOfTypes" */ [UNIQUE_NAME] = "vine.object"; /** * Checks if the value is of object type. The method must be * implemented for "unionOfTypes" */ [IS_OF_TYPE] = (value) => { return value !== null && typeof value === "object" && !Array.isArray(value); }; constructor(properties, options, validations) { if (!properties) { throw new Error( 'Missing properties for "vine.object". Use an empty object if you do not want to validate any specific fields' ); } super(options, validations); this.#properties = properties; } /** * Returns a clone copy of the object properties. The object groups * are not copied to keep the implementations simple and easy to * reason about. */ getProperties() { return Object.keys(this.#properties).reduce((result, key) => { result[key] = this.#properties[key].clone(); return result; }, {}); } /** * Copy unknown properties to the final output. */ allowUnknownProperties() { this.#allowUnknownProperties = true; return this; } /** * Merge a union to the object groups. The union can be a "vine.union" * with objects, or a "vine.object.union" with properties. */ merge(group2) { this.#groups.push(group2); return this; } /** * Clone object */ clone() { const cloned = new _VineObject( this.getProperties(), this.cloneOptions(), this.cloneValidations() ); this.#groups.forEach((group2) => cloned.merge(group2)); if (this.#allowUnknownProperties) { cloned.allowUnknownProperties(); } return cloned; } /** * Applies camelcase transform */ toCamelCase() { return new VineCamelCaseObject(this); } /** * Compiles the schema type to a compiler node */ [PARSE](propertyName, refs, options) { return { type: "object", fieldName: propertyName, propertyName: options.toCamelCase ? camelcase5(propertyName) : propertyName, bail: this.options.bail, allowNull: this.options.allowNull, isOptional: this.options.isOptional, parseFnId: this.options.parse ? refs.trackParser(this.options.parse) : void 0, allowUnknownProperties: this.#allowUnknownProperties, validations: this.compileValidations(refs), properties: Object.keys(this.#properties).map((property) => { return this.#properties[property][PARSE](property, refs, options); }), groups: this.#groups.map((group2) => { return group2[PARSE](refs, options); }) }; } }; // src/schema/record/main.ts import camelcase6 from "camelcase"; // src/schema/record/rules.ts var minLengthRule2 = createRule((value, options, field) => { if (!field.isValid) { return; } if (Object.keys(value).length < options.min) { field.report(messages["record.minLength"], "record.minLength", field, options); } }); var maxLengthRule2 = createRule((value, options, field) => { if (!field.isValid) { return; } if (Object.keys(value).length > options.max) { field.report(messages["record.maxLength"], "record.maxLength", field, options); } }); var fixedLengthRule2 = createRule((value, options, field) => { if (!field.isValid) { return; } if (Object.keys(value).length !== options.size) { field.report(messages["record.fixedLength"], "record.fixedLength", field, options); } }); var validateKeysRule = createRule( (value, callback, field) => { if (!field.isValid) { return; } callback(Object.keys(value), field); } ); // src/schema/record/main.ts var VineRecord = class _VineRecord extends BaseType { /** * Default collection of record rules */ static rules = { maxLength: maxLengthRule2, minLength: minLengthRule2, fixedLength: fixedLengthRule2, validateKeys: validateKeysRule }; #schema; /** * The property must be implemented for "unionOfTypes" */ [UNIQUE_NAME] = "vine.object"; /** * Checks if the value is of object type. The method must be * implemented for "unionOfTypes" */ [IS_OF_TYPE] = (value) => { return value !== null && typeof value === "object" && !Array.isArray(value); }; constructor(schema, options, validations) { super(options, validations); this.#schema = schema; } /** * Enforce a minimum length on an object field */ minLength(expectedLength) { return this.use(minLengthRule2({ min: expectedLength })); } /** * Enforce a maximum length on an object field */ maxLength(expectedLength) { return this.use(maxLengthRule2({ max: expectedLength })); } /** * Enforce a fixed length on an object field */ fixedLength(expectedLength) { return this.use(fixedLengthRule2({ size: expectedLength })); } /** * Register a callback to validate the object keys */ validateKeys(...args) { return this.use(validateKeysRule(...args)); } /** * Clones the VineRecord schema type. The applied options * and validations are copied to the new instance */ clone() { return new _VineRecord( this.#schema.clone(), this.cloneOptions(), this.cloneValidations() ); } /** * Compiles to record data type */ [PARSE](propertyName, refs, options) { return { type: "record", fieldName: propertyName, propertyName: options.toCamelCase ? camelcase6(propertyName) : propertyName, bail: this.options.bail, allowNull: this.options.allowNull, isOptional: this.options.isOptional, each: this.#schema[PARSE]("*", refs, options), parseFnId: this.options.parse ? refs.trackParser(this.options.parse) : void 0, validations: this.compileValidations(refs) }; } }; // src/schema/string/rules.ts import camelcase7 from "camelcase"; import normalizeUrl from "normalize-url"; import escape from "validator/lib/escape.js"; import normalizeEmail from "validator/lib/normalizeEmail.js"; var stringRule = createRule((value, _, field) => { if (typeof value !== "string") { field.report(messages.string, "string", field); } }); var emailRule = createRule((value, options, field) => { if (!field.isValid) { return; } if (!helpers.isEmail(value, options)) { field.report(messages.email, "email", field); } }); var mobileRule = createRule((value, options, field) => { if (!field.isValid) { return; } const normalizedOptions = options && typeof options === "function" ? options(field) : options; const locales = normalizedOptions?.locale || "any"; if (!helpers.isMobilePhone(value, locales, normalizedOptions)) { field.report(messages.mobile, "mobile", field); } }); var ipAddressRule = createRule((value, options, field) => { if (!field.isValid) { return; } if (!helpers.isIP(value, options?.version)) { field.report(messages.ipAddress, "ipAddress", field); } }); var regexRule = createRule((value, expression, field) => { if (!field.isValid) { return; } if (!expression.test(value)) { field.report(messages.regex, "regex", field); } }); var hexCodeRule = createRule((value, _, field) => { if (!field.isValid) { return; } if (!helpers.isHexColor(value)) { field.report(messages.hexCode, "hexCode", field); } }); var urlRule = createRule((value, options, field) => { if (!field.isValid) { return; } if (!helpers.isURL(value, options)) { field.report(messages.url, "url", field); } }); var activeUrlRule = createRule(async (value, _, field) => { if (!field.isValid) { return; } if (!await helpers.isActiveURL(value)) { field.report(messages.activeUrl, "activeUrl", field); } }); var alphaRule = createRule((value, options, field) => { if (!field.isValid) { return; } let characterSet = "a-zA-Z"; if (options) { if (options.allowSpaces) { characterSet += "\\s"; } if (options.allowDashes) { characterSet += "-"; } if (options.allowUnderscores) { characterSet += "_"; } } const expression = new RegExp(`^[${characterSet}]+$`); if (!expression.test(value)) { field.report(messages.alpha, "alpha", field); } }); var alphaNumericRule = createRule( (value, options, field) => { if (!field.isValid) { return; } let characterSet = "a-zA-Z0-9"; if (options) { if (options.allowSpaces) { characterSet += "\\s"; } if (options.allowDashes) { characterSet += "-"; } if (options.allowUnderscores) { characterSet += "_"; } } const expression = new RegExp(`^[${characterSet}]+$`); if (!expression.test(value)) { field.report(messages.alphaNumeric, "alphaNumeric", field); } } ); var minLengthRule3 = createRule((value, options, field) => { if (!field.isValid) { return; } if (value.length < options.min) { field.report(messages.minLength, "minLength", field, options); } }); var maxLengthRule3 = createRule((value, options, field) => { if (!field.isValid) { return; } if (value.length > options.max) { field.report(messages.maxLength, "maxLength", field, options); } }); var fixedLengthRule3 = createRule((value, options, field) => { if (!field.isValid) { return; } if (value.length !== options.size) { field.report(messages.fixedLength, "fixedLength", field, options); } }); var endsWithRule = createRule((value, options, field) => { if (!field.isValid) { return; } if (!value.endsWith(options.substring)) { field.report(messages.endsWith, "endsWith", field, options); } }); var startsWithRule = createRule((value, options, field) => { if (!field.isValid) { return; } if (!value.startsWith(options.substring)) { field.report(messages.startsWith, "startsWith", field, options); } }); var sameAsRule2 = createRule((value, options, field) => { if (!field.isValid) { return; } const input = helpers.getNestedValue(options.otherField, field); if (input !== value) { field.report(messages.sameAs, "sameAs", field, options); return; } }); var notSameAsRule2 = createRule((value, options, field) => { if (!field.isValid) { return; } const input = helpers.getNestedValue(options.otherField, field); if (input === value) { field.report(messages.notSameAs, "notSameAs", field, options); return; } }); var confirmedRule = createRule( (value, options, field) => { if (!field.isValid) { return; } const otherField = options?.confirmationField || `${field.name}_confirmation`; const input = field.parent[otherField]; if (input !== value) { field.report(messages.confirmed, "confirmed", field, { otherField }); return; } } ); var trimRule = createRule((value, _, field) => { if (!field.isValid) { return; } field.mutate(value.trim(), field); }); var normalizeEmailRule = createRule( (value, options, field) => { if (!field.isValid) { return; } field.mutate(normalizeEmail.default(value, options), field); } ); var toUpperCaseRule = createRule( (value, locales, field) => { if (!field.isValid) { return; } field.mutate(value.toLocaleUpperCase(locales), field); } ); var toLowerCaseRule = createRule( (value, locales, field) => { if (!field.isValid) { return; } field.mutate(value.toLocaleLowerCase(locales), field); } ); var toCamelCaseRule = createRule((value, _, field) => { if (!field.isValid) { return; } field.mutate(camelcase7(value), field); }); var escapeRule = createRule((value, _, field) => { if (!field.isValid) { return; } field.mutate(escape.default(value), field); }); var normalizeUrlRule = createRule( (value, options, field) => { if (!field.isValid) { return; } field.mutate(normalizeUrl(value, options), field); } ); var inRule = createRule( (value, options, field) => { if (!field.isValid) { return; } const choices = typeof options.choices === "function" ? options.choices(field) : options.choices; if (!choices.includes(value)) { field.report(messages.in, "in", field, options); return; } } ); var notInRule = createRule( (value, options, field) => { if (!field.isValid) { return; } const list = typeof options.list === "function" ? options.list(field) : options.list; if (list.includes(value)) { field.report(messages.notIn, "notIn", field, options); return; } } ); var creditCardRule = createRule((value, options, field) => { if (!field.isValid) { return; } const providers = options ? typeof options === "function" ? options(field)?.provider || [] : options.provider : []; if (!providers.length) { if (!helpers.isCreditCard(value)) { field.report(messages.creditCard, "creditCard", field, { providersList: "credit" }); } } else { const matchesAnyProvider = providers.find( (provider) => helpers.isCreditCard(value, { provider }) ); if (!matchesAnyProvider) { field.report(messages.creditCard, "creditCard", field, { providers, providersList: providers.join("/") }); } } }); var passportRule = createRule((value, options, field) => { if (!field.isValid) { return; } const countryCodes = typeof options === "function" ? options(field).countryCode : options.countryCode; const matchesAnyCountryCode = countryCodes.find( (countryCode) => helpers.isPassportNumber(value, countryCode) ); if (!matchesAnyCountryCode) { field.report(messages.passport, "passport", field, { countryCodes }); } }); var postalCodeRule = createRule((value, options, field) => { if (!field.isValid) { return; } const countryCodes = options ? typeof options === "function" ? options(field)?.countryCode || [] : options.countryCode : []; if (!countryCodes.length) { if (!helpers.isPostalCode(value, "any")) { field.report(messages.postalCode, "postalCode", field); } } else { const matchesAnyCountryCode = countryCodes.find( (countryCode) => helpers.isPostalCode(value, countryCode) ); if (!matchesAnyCountryCode) { field.report(messages.postalCode, "postalCode", field, { countryCodes }); } } }); var uuidRule = createRule( (value, options, field) => { if (!field.isValid) { return; } if (!options || !options.version) { if (!helpers.isUUID(value)) { field.report(messages.uuid, "uuid", field); } } else { const matchesAnyVersion = options.version.find( (version) => helpers.isUUID(value, version) ); if (!matchesAnyVersion) { field.report(messages.uuid, "uuid", field, options); } } } ); var ulidRule = createRule((value, _, field) => { if (!field.isValid) { return; } if (!helpers.isULID(value)) { field.report(messages.ulid, "ulid", field); } }); var asciiRule = createRule((value, _, field) => { if (!field.isValid) { return; } if (!helpers.isAscii(value)) { field.report(messages.ascii, "ascii", field); } }); var ibanRule = createRule((value, _, field) => { if (!field.isValid) { return; } if (!helpers.isIBAN(value)) { field.report(messages.iban, "iban", field); } }); var jwtRule = createRule((value, _, field) => { if (!field.isValid) { return; } if (!helpers.isJWT(value)) { field.report(messages.jwt, "jwt", field); } }); var coordinatesRule = createRule((value, _, field) => { if (!field.isValid) { return; } if (!helpers.isLatLong(value)) { field.report(messages.coordinates, "coordinates", field); } }); // src/schema/string/main.ts var VineString = class _VineString extends BaseLiteralType { static rules = { in: inRule, jwt: jwtRule, url: urlRule, iban: ibanRule, uuid: uuidRule, ulid: ulidRule, trim: trimRule, email: emailRule, alpha: alphaRule, ascii: asciiRule, notIn: notInRule, regex: regexRule, escape: escapeRule, sameAs: sameAsRule2, mobile: mobileRule, string: stringRule, hexCode: hexCodeRule, passport: passportRule, endsWith: endsWithRule, confirmed: confirmedRule, activeUrl: activeUrlRule, minLength: minLengthRule3, notSameAs: notSameAsRule2, maxLength: maxLengthRule3, ipAddress: ipAddressRule, creditCard: creditCardRule, postalCode: postalCodeRule, startsWith: startsWithRule, toUpperCase: toUpperCaseRule, toLowerCase: toLowerCaseRule, toCamelCase: toCamelCaseRule, fixedLength: fixedLengthRule3, coordinates: coordinatesRule, normalizeUrl: normalizeUrlRule, alphaNumeric: alphaNumericRule, normalizeEmail: normalizeEmailRule }; /** * The subtype of the literal schema field */ [SUBTYPE] = "string"; /** * The property must be implemented for "unionOfTypes" */ [UNIQUE_NAME] = "vine.string"; /** * Checks if the value is of string type. The method must be * implemented for "unionOfTypes" */ [IS_OF_TYPE] = (value) => { return typeof value === "string"; }; constructor(options, validations) { super(options, validations || [stringRule()]); } /** * Validates the value to be a valid URL */ url(...args) { return this.use(urlRule(...args)); } /** * Validates the value to be an active URL */ activeUrl() { return this.use(activeUrlRule()); } /** * Validates the value to be a valid email address */ email(...args) { return this.use(emailRule(...args)); } /** * Validates the value to be a valid mobile number */ mobile(...args) { return this.use(mobileRule(...args)); } /** * Validates the value to be a valid IP address. */ ipAddress(version) { return this.use(ipAddressRule(version ? { version } : void 0)); } /** * Validates the value to be a valid hex color code */ hexCode() { return this.use(hexCodeRule()); } /** * Validates the value against a regular expression */ regex(expression) { return this.use(regexRule(expression)); } /** * Validates the value to contain only letters */ alpha(options) { return this.use(alphaRule(options)); } /** * Validates the value to contain only letters and * numbers */ alphaNumeric(options) { return this.use(alphaNumericRule(options)); } /** * Enforce a minimum length on a string field */ minLength(expectedLength) { return this.use(minLengthRule3({ min: expectedLength })); } /** * Enforce a maximum length on a string field */ maxLength(expectedLength) { return this.use(maxLengthRule3({ max: expectedLength })); } /** * Enforce a fixed length on a string field */ fixedLength(expectedLength) { return this.use(fixedLengthRule3({ size: expectedLength })); } /** * Ensure the field under validation is confirmed by * having another field with the same name. */ confirmed(options) { return this.use(confirmedRule(options)); } /** * Trims whitespaces around the string value */ trim() { return this.use(trimRule()); } /** * Normalizes the email address */ normalizeEmail(options) { return this.use(normalizeEmailRule(options)); } /** * Converts the field value to UPPERCASE. */ toUpperCase() { return this.use(toUpperCaseRule()); } /** * Converts the field value to lowercase. */ toLowerCase() { return this.use(toLowerCaseRule()); } /** * Converts the field value to camelCase. */ toCamelCase() { return this.use(toCamelCaseRule()); } /** * Escape string for HTML entities */ escape() { return this.use(escapeRule()); } /** * Normalize a URL */ normalizeUrl(...args) { return this.use(normalizeUrlRule(...args)); } /** * Ensure the value starts with the pre-defined substring */ startsWith(substring) { return this.use(startsWithRule({ substring })); } /** * Ensure the value ends with the pre-defined substring */ endsWith(substring) { return this.use(endsWithRule({ substring })); } /** * Ensure the value ends with the pre-defined substring */ sameAs(otherField) { return this.use(sameAsRule2({ otherField })); } /** * Ensure the value ends with the pre-defined substring */ notSameAs(otherField) { return this.use(notSameAsRule2({ otherField })); } /** * Ensure the field's value under validation is a subset of the pre-defined list. */ in(choices) { return this.use(inRule({ choices })); } /** * Ensure the field's value under validation is not inside the pre-defined list. */ notIn(list) { return this.use(notInRule({ list })); } /** * Validates the value to be a valid credit card number */ creditCard(...args) { return this.use(creditCardRule(...args)); } /** * Validates the value to be a valid passport number */ passport(...args) { return this.use(passportRule(...args)); } /** * Validates the value to be a valid postal code */ postalCode(...args) { return this.use(postalCodeRule(...args)); } /** * Validates the value to be a valid UUID */ uuid(...args) { return this.use(uuidRule(...args)); } /** * Validates the value to be a valid ULID */ ulid() { return this.use(ulidRule()); } /** * Validates the value contains ASCII characters only */ ascii() { return this.use(asciiRule()); } /** * Validates the value to be a valid IBAN number */ iban() { return this.use(ibanRule()); } /** * Validates the value to be a valid JWT token */ jwt() { return this.use(jwtRule()); } /** * Ensure the value is a string with latitude and longitude coordinates */ coordinates() { return this.use(coordinatesRule()); } /** * Clones the VineString schema type. The applied options * and validations are copied to the new instance */ clone() { return new _VineString(this.cloneOptions(), this.cloneValidations()); } }; // src/schema/number/rules.ts var numberRule = createRule((value, options, field) => { const valueAsNumber = options.strict ? value : helpers.asNumber(value); if (typeof valueAsNumber !== "number" || Number.isNaN(valueAsNumber) || valueAsNumber === Number.POSITIVE_INFINITY || valueAsNumber === Number.NEGATIVE_INFINITY) { field.report(messages.number, "number", field); return; } field.mutate(valueAsNumber, field); }); var minRule = createRule((value, options, field) => { if (!field.isValid) { return; } if (value < options.min) { field.report(messages.min, "min", field, options); } }); var maxRule = createRule((value, options, field) => { if (!field.isValid) { return; } if (value > options.max) { field.report(messages.max, "max", field, options); } }); var rangeRule = createRule((value, options, field) => { if (!field.isValid) { return; } if (value < options.min || value > options.max) { field.report(messages.range, "range", field, options); } }); var positiveRule = createRule((value, _, field) => { if (!field.isValid) { return; } if (value < 0) { field.report(messages.positive, "positive", field); } }); var negativeRule = createRule((value, _, field) => { if (!field.isValid) { return; } if (value >= 0) { field.report(messages.negative, "negative", field); } }); var decimalRule = createRule((value, options, field) => { if (!field.isValid) { return; } if (!helpers.isDecimal(String(value), { force_decimal: options.range[0] !== 0, decimal_digits: options.range.join(",") })) { field.report(messages.decimal, "decimal", field, { digits: options.range.join("-") }); } }); var withoutDecimalsRule = createRule((value, _, field) => { if (!field.isValid) { return; } if (!Number.isInteger(value)) { field.report(messages.withoutDecimals, "withoutDecimals", field); } }); var inRule2 = createRule((value, options, field) => { if (!field.isValid) { return; } if (!options.values.includes(value)) { field.report(messages["number.in"], "in", field, options); } }); // src/schema/number/main.ts var VineNumber = class _VineNumber extends BaseLiteralType { /** * Default collection of number rules */ static rules = { in: inRule2, max: maxRule, min: minRule, range: rangeRule, number: numberRule, decimal: decimalRule, negative: negativeRule, positive: positiveRule, withoutDecimals: withoutDecimalsRule }; /** * The subtype of the literal schema field */ [SUBTYPE] = "number"; /** * The property must be implemented for "unionOfTypes" */ [UNIQUE_NAME] = "vine.number"; /** * Checks if the value is of number type. The method must be * implemented for "unionOfTypes" */ [IS_OF_TYPE] = (value) => { const valueAsNumber = helpers.asNumber(value); return !Number.isNaN(valueAsNumber); }; constructor(options, validations) { super(options, validations || [numberRule(options || {})]); } /** * Enforce a minimum value for the number input */ min(value) { return this.use(minRule({ min: value })); } /** * Enforce a maximum value for the number input */ max(value) { return this.use(maxRule({ max: value })); } /** * Enforce value to be within the range of minimum and maximum output. */ range(value) { return this.use(rangeRule({ min: value[0], max: value[1] })); } /** * Enforce the value be a positive number */ positive() { return this.use(positiveRule()); } /** * Enforce the value be a negative number */ negative() { return this.use(negativeRule()); } /** * Enforce the value to have fixed or range * of decimal places */ decimal(range) { return this.use(decimalRule({ range: Array.isArray(range) ? range : [range] })); } /** * Enforce the value to be an integer (aka without decimals) */ withoutDecimals() { return this.use(withoutDecimalsRule()); } /** * Clones the VineNumber schema type. The applied options * and validations are copied to the new instance */ clone() { return new _VineNumber(this.cloneOptions(), this.cloneValidations()); } /** * Enforce the value to be in a list of allowed values */ in(values) { return this.use(inRule2({ values })); } }; // src/schema/boolean/rules.ts var booleanRule = createRule((value, options, field) => { const valueAsBoolean = options.strict === true ? value : helpers.asBoolean(value); if (typeof valueAsBoolean !== "boolean") { field.report(messages.boolean, "boolean", field); return; } field.mutate(valueAsBoolean, field); }); // src/schema/boolean/main.ts var VineBoolean = class _VineBoolean extends BaseLiteralType { /** * Default collection of boolean rules */ static rules = { boolean: booleanRule }; /** * The subtype of the literal schema field */ [SUBTYPE] = "boolean"; /** * The property must be implemented for "unionOfTypes" */ [UNIQUE_NAME] = "vine.boolean"; /** * Checks if the value is of boolean type. The method must be * implemented for "unionOfTypes" */ [IS_OF_TYPE] = (value) => { const valueAsBoolean = this.options.strict === true ? value : helpers.asBoolean(value); return typeof valueAsBoolean === "boolean"; }; constructor(options, validations) { super(options, validations || [booleanRule(options || {})]); } /** * Clones the VineBoolean schema type. The applied options * and validations are copied to the new instance */ clone() { return new _VineBoolean(this.cloneOptions(), this.cloneValidations()); } }; // src/schema/literal/rules.ts var equalsRule2 = createRule((value, options, field) => { let input = value; if (typeof options.expectedValue === "boolean") { input = helpers.asBoolean(value); } else if (typeof options.expectedValue === "number") { input = helpers.asNumber(value); } if (input !== options.expectedValue) { field.report(messages.literal, "literal", field, options); return; } field.mutate(input, field); }); // src/schema/literal/main.ts var VineLiteral = class _VineLiteral extends BaseLiteralType { /** * Default collection of literal rules */ static rules = { equals: equalsRule2 }; #value; /** * The subtype of the literal schema field */ [SUBTYPE] = "literal"; constructor(value, options, validations) { super(options, validations || [equalsRule2({ expectedValue: value })]); this.#value = value; } /** * Clones the VineLiteral schema type. The applied options * and validations are copied to the new instance */ clone() { return new _VineLiteral(this.#value, this.cloneOptions(), this.cloneValidations()); } }; // src/schema/accepted/rules.ts var ACCEPTED_VALUES = ["on", "1", "yes", "true", true, 1]; var acceptedRule = createRule((value, _, field) => { if (!ACCEPTED_VALUES.includes(value)) { field.report(messages.accepted, "accepted", field); } }); // src/schema/accepted/main.ts var VineAccepted = class _VineAccepted extends BaseLiteralType { /** * Default collection of accepted rules */ static rules = { accepted: acceptedRule }; /** * The subtype of the literal schema field */ [SUBTYPE] = "checkbox"; constructor(options, validations) { super(options, validations || [acceptedRule()]); } /** * Clones the VineAccepted schema type. The applied options * and validations are copied to the new instance */ clone() { return new _VineAccepted(this.cloneOptions(), this.cloneValidations()); } }; // src/schema/object/group.ts var ObjectGroup = class _ObjectGroup { #conditionals; #otherwiseCallback = (_, field) => { field.report(messages.unionGroup, "unionGroup", field); }; constructor(conditionals) { this.#conditionals = conditionals; } /** * Clones the ObjectGroup schema type. */ clone() { const cloned = new _ObjectGroup(this.#conditionals); cloned.otherwise(this.#otherwiseCallback); return cloned; } /** * Define a fallback method to invoke when all of the group conditions * fail. You may use this method to report an error. */ otherwise(callback) { this.#otherwiseCallback = callback; return this; } /** * Compiles the group */ [PARSE](refs, options) { return { type: "group", elseConditionalFnRefId: refs.trackConditional(this.#otherwiseCallback), conditions: this.#conditionals.map((conditional) => conditional[PARSE](refs, options)) }; } }; // src/schema/object/conditional.ts var GroupConditional = class { /** * Properties to merge when conditonal is true */ #properties; /** * Conditional to evaluate */ #conditional; constructor(conditional, properties) { this.#properties = properties; this.#conditional = conditional; } /** * Compiles to a union conditional */ [PARSE](refs, options) { return { schema: { type: "sub_object", properties: Object.keys(this.#properties).map((property) => { return this.#properties[property][PARSE](property, refs, options); }), groups: [] // Compiler allows nested groups, but we are not implementing it }, conditionalFnRefId: refs.trackConditional(this.#conditional) }; } }; // src/schema/object/group_builder.ts function group(conditionals) { return new ObjectGroup(conditionals); } group.if = function groupIf(conditon, properties) { return new GroupConditional(conditon, properties); }; group.else = function groupElse(properties) { return new GroupConditional(() => true, properties); }; // src/schema/enum/native_enum.ts var VineNativeEnum = class _VineNativeEnum extends BaseLiteralType { /** * Default collection of enum rules */ static rules = { enum: enumRule }; #values; /** * The subtype of the literal schema field */ [SUBTYPE] = "enum"; constructor(values, options, validations) { super(options, validations || [enumRule({ choices: Object.values(values) })]); this.#values = values; } /** * Clones the VineNativeEnum schema type. The applied options * and validations are copied to the new instance */ clone() { return new _VineNativeEnum(this.#values, this.cloneOptions(), this.cloneValidations()); } }; // src/schema/union_of_types/main.ts import camelcase8 from "camelcase"; var VineUnionOfTypes = class _VineUnionOfTypes { #schemas; #otherwiseCallback = (_, field) => { field.report(messages.unionOfTypes, "unionOfTypes", field); }; constructor(schemas) { this.#schemas = schemas; } /** * Define a fallback method to invoke when all of the union conditions * fail. You may use this method to report an error. */ otherwise(callback) { this.#otherwiseCallback = callback; return this; } /** * Clones the VineUnionOfTypes schema type. */ clone() { const cloned = new _VineUnionOfTypes(this.#schemas); cloned.otherwise(this.#otherwiseCallback); return cloned; } /** * Compiles to a union */ [PARSE](propertyName, refs, options) { return { type: "union", fieldName: propertyName, propertyName: options.toCamelCase ? camelcase8(propertyName) : propertyName, elseConditionalFnRefId: refs.trackConditional(this.#otherwiseCallback), conditions: this.#schemas.map((schema) => { return { conditionalFnRefId: refs.trackConditional((value, field) => { return schema[IS_OF_TYPE](value, field); }), schema: schema[PARSE](propertyName, refs, options) }; }) }; } }; // src/schema/builder.ts var SchemaBuilder = class extends Macroable3 { /** * Define a sub-object as a union */ group = group; /** * Define a union value */ union = union; /** * Define a string value */ string() { return new VineString(); } /** * Define a boolean value */ boolean(options) { return new VineBoolean(options); } /** * Validate a checkbox to be checked */ accepted() { return new VineAccepted(); } /** * Define a number value */ number(options) { return new VineNumber(options); } /** * Define a datetime value */ date(options) { return new VineDate(options); } /** * Define a schema type in which the input value * matches the pre-defined value */ literal(value) { return new VineLiteral(value); } /** * Define an object with known properties. You may call "allowUnknownProperties" * to merge unknown properties. */ object(properties) { return new VineObject(properties); } /** * Define an array field and validate its children elements. */ array(schema) { return new VineArray(schema); } /** * Define an array field with known length and each children * element may have its own schema. */ tuple(schemas) { return new VineTuple(schemas); } /** * Define an object field with key-value pair. The keys in * a record are unknown and values can be of a specific * schema type. */ record(schema) { return new VineRecord(schema); } enum(values) { if (Array.isArray(values) || typeof values === "function") { return new VineEnum(values); } return new VineNativeEnum(values); } /** * Allow the field value to be anything */ any() { return new VineAny(); } /** * Define a union of unique schema types. */ unionOfTypes(schemas) { const schemasInUse = /* @__PURE__ */ new Set(); schemas.forEach((schema) => { if (!schema[IS_OF_TYPE] || !schema[UNIQUE_NAME]) { throw new Error( `Cannot use "${schema.constructor.name}". The schema type is not compatible for use with "vine.unionOfTypes"` ); } if (schemasInUse.has(schema[UNIQUE_NAME])) { throw new Error( `Cannot use duplicate schema "${schema[UNIQUE_NAME]}". "vine.unionOfTypes" needs distinct schema types only` ); } schemasInUse.add(schema[UNIQUE_NAME]); }); schemasInUse.clear(); return new VineUnionOfTypes(schemas); } }; // src/vine/validator.ts import { Compiler, refsBuilder } from "@vinejs/compiler"; var COMPILER_ERROR_MESSAGES = { required: messages.required, array: messages.array, object: messages.object }; var VineValidator = class { /** * Reference to the compiled schema */ #compiled; /** * Messages provider to use on the validator */ messagesProvider; /** * Error reporter to use on the validator */ errorReporter; /** * Parses schema to compiler nodes. */ #parse(schema) { const refs = refsBuilder(); return { compilerNode: { type: "root", schema: schema[PARSE]("", refs, { toCamelCase: false }) }, refs: refs.toJSON() }; } constructor(schema, options) { const { compilerNode, refs } = this.#parse(schema); this.#compiled = { schema: compilerNode, refs }; const metaDataValidator = options.metaDataValidator; const validateFn = new Compiler(compilerNode, { convertEmptyStringsToNull: options.convertEmptyStringsToNull, messages: COMPILER_ERROR_MESSAGES }).compile(); this.errorReporter = options.errorReporter; this.messagesProvider = options.messagesProvider; if (metaDataValidator) { this.validate = (data, validateOptions) => { let normalizedOptions = validateOptions ?? {}; const meta = normalizedOptions.meta ?? {}; const errorReporter = normalizedOptions.errorReporter ?? this.errorReporter; const messagesProvider = normalizedOptions.messagesProvider ?? this.messagesProvider; metaDataValidator(meta); return validateFn(data, meta, refs, messagesProvider, errorReporter()); }; } else { this.validate = (data, validateOptions) => { let normalizedOptions = validateOptions ?? {}; const meta = normalizedOptions.meta ?? {}; const errorReporter = normalizedOptions.errorReporter ?? this.errorReporter; const messagesProvider = normalizedOptions.messagesProvider ?? this.messagesProvider; return validateFn(data, meta, refs, messagesProvider, errorReporter()); }; } } /** * Performs validation without throwing the validation * exception. Instead, the validation errors are * returned as the first argument. * * * ```ts * await validator.tryValidate(data) * await validator.tryValidate(data, { meta: {} }) * * await validator.tryValidate(data, { * meta: { userId: auth.user.id }, * errorReporter, * messagesProvider * }) * ``` * */ async tryValidate(data, ...[options]) { try { const result = await this.validate(data, options); return [null, result]; } catch (error) { if (error instanceof ValidationError) { return [error, null]; } throw error; } } /** * Returns the compiled schema and refs. */ toJSON() { const { schema, refs } = this.#compiled; return { schema: structuredClone(schema), refs }; } }; // src/vine/main.ts var Vine = class extends SchemaBuilder { /** * Messages provider to use on the validator */ messagesProvider = new SimpleMessagesProvider(messages, fields); /** * Error reporter to use on the validator */ errorReporter = () => new SimpleErrorReporter(); /** * Control whether or not to convert empty strings to null */ convertEmptyStringsToNull = false; /** * Helpers to perform type-checking or cast types keeping * HTML forms serialization behavior in mind. */ helpers = helpers; /** * Convert a validation function to a Vine schema rule */ createRule = createRule; /** * Pre-compiles a schema into a validation function. * * ```ts * const validate = vine.compile(schema) * await validate({ data }) * ``` */ compile(schema) { return new VineValidator(schema, { convertEmptyStringsToNull: this.convertEmptyStringsToNull, messagesProvider: this.messagesProvider, errorReporter: this.errorReporter }); } /** * Define a callback to validate the metadata given to the validator * at runtime */ withMetaData(callback) { return { compile: (schema) => { return new VineValidator(schema, { convertEmptyStringsToNull: this.convertEmptyStringsToNull, messagesProvider: this.messagesProvider, errorReporter: this.errorReporter, metaDataValidator: callback }); } }; } /** * Validate data against a schema. Optionally, you can define * error messages, fields, a custom messages provider, * or an error reporter. * * ```ts * await vine.validate({ schema, data }) * await vine.validate({ schema, data, messages, fields }) * * await vine.validate({ schema, data, messages, fields }, { * errorReporter * }) * ``` */ validate(options) { const validator = this.compile(options.schema); return validator.validate(options.data, options); } /** * Validate data against a schema without throwing the * "ValidationError" exception. Instead the validation * errors are returned within the return value. * * ```ts * await vine.tryValidate({ schema, data }) * await vine.tryValidate({ schema, data, messages, fields }) * * await vine.tryValidate({ schema, data, messages, fields }, { * errorReporter * }) * ``` */ tryValidate(options) { const validator = this.compile(options.schema); return validator.tryValidate(options.data, options); } }; // index.ts var vine = new Vine(); var index_default = vine; export { symbols_exports, BaseLiteralType, VineAny, VineEnum, VineDate, VineUnion, BaseModifiersType2 as BaseModifiersType, BaseType, VineTuple, VineArray, VineObject, VineRecord, VineString, VineNumber, VineBoolean, VineLiteral, VineAccepted, VineNativeEnum, VineValidator, Vine, index_default };