Skip to content

Releases: jquense/yup

v1 Because I finally got around to it

08 Feb 14:30
Compare
Choose a tag to compare

v1.0.0-beta.7

22 Aug 14:16
Compare
Choose a tag to compare
v1.0.0-beta.7 Pre-release
Pre-release

Fixes published artifacts for the main field

v1.0.0-beta.5 - partial fixes and cast migration path

22 Aug 14:16
Compare
Choose a tag to compare

Beta 5 fixes partial and deepPartial making it work correctly with lazy schema. Specifically the optionality is added after lazy is evaluated but before any other when conditions are added. This makes it consistent with other conditional schema, where runtime conditions always supersede previous schema configuration. This allows for optional overrides if necessary.

const person = object({
  name: string().required(),
  age: number().required(),
  legalGuardian:  string().when('age', {
    is: (age) => age != null && age < 18,
    then: (schema) => schema.required(),
  }),
});

const optionalPerson = person.partial()

person.cast({name: 'James', age: 6 }) // => TypeError legalGuardian required

// age is still required b/c it's applied after the `partial`
optionalPerson.cast({name: 'James',  age: 6 }) // => TypeError legalGuardian required

This works slightly differently for lazy which have no schema to "start" with:

const config = object({
  nameOrIdNumber:  lazy((value) => {
     if (typeof value === 'number') return number().required()
     return string().required()
  }),
});

const opti = config.partial()

config.cast({}) // => TypeError nameOrIdNumber is required

config.partial().cast({}) // => {}

Cast optionality migration path

A larger breaking change in v1 is the assertion of optionality during cast, making previous patterns like string().nullable().required() no longer possible. Generally this pattern is used when deserialized data is not valid to start, but will become valid through user input such as with an HTML form. v1 no longer allows this, but in order to make migration easier we've added an option to cast that mimics the previous behavior (not exactly but closely).

const name = string().required()

name.cast(null, { assert: 'ignore-optionality'}) // => null

We recommend updating your schema to new patterns where possible but this allows for incremental upgrades

What's Changed

New Contributors

Full Changelog: v1.0.0-beta.4...v1.0.0-beta.5

v1.0.0-beta.4

22 Aug 13:48
Compare
Choose a tag to compare
v1.0.0-beta.4 Pre-release
Pre-release

What's Changed

Full Changelog: v1.0.0-beta.3...v1.0.0-beta.4

Fix object.partial(), `required` changes

09 Mar 21:46
Compare
Choose a tag to compare

This release fixes a bug with object().partial where required() schema we're still failing validation. Now they will no longer do that. To enable this fix we made a breaking change to the way that required is implemented.

  • schema.required no longer adds a test named 'required', this state can be determined via the schema spec or describe() metadata
  • String schema now override required directly to add their length check (this test is called required for some ease of back compat)

Tuple types

21 Jan 15:01
Compare
Choose a tag to compare
Tuple types Pre-release
Pre-release

Beta.2 adds core tuple type support, see the docs for more: https://github.com/jquense/yup#tuple

v1.0.0-beta.1 Flat bundles

03 Jan 17:14
Compare
Choose a tag to compare
Pre-release

1.0.0-beta.1 (2022-01-03)

Features

  • flat bundles and size reductions (753abdf)
  • Refactors a number of internal APIs for Schema type implementers, making it easier to consistently create subclasses of Schema.

BREAKING CHANGES

  • Yup now compiles to a flat bundle using rollup, this gives us faster to parse and smaller code, as well as clearer size insights (10.26kb gzipped!). The possible breaking change is around cherry picking imports, if you are cherry picking imports from yup import string from 'yup/lib/string' this will no longer work. This pattern has not been supported for a long time and could cause larger than necessary bundles.

v1.0.0-beta.0

29 Dec 19:16
Compare
Choose a tag to compare
v1.0.0-beta.0 Pre-release
Pre-release

1.0.0-beta.0 (2021-12-29)

  • feat!: add json() method and remove default object/array coercion (94b73c4)

Features

  • Make Array generic consistent with others (a82353f)

BREAKING CHANGES

  • types only, ArraySchema initial generic is the array type not the type of the array element. array<T>() is still the inner type.
  • object and array schema no longer parse JSON strings by default, nor do they return null for invalid casts.
object().json().cast('{}')
array().json().cast('[]')

to mimic the previous behavior

API pruning

29 Dec 18:29
Compare
Choose a tag to compare
API pruning Pre-release
Pre-release

Bug Fixes

Features

BREAKING CHANGES

  • mixed schema are no longer treated as the base class for other schema types. It hasn't been for a while, but we've done some nasty prototype slinging to make it behave like it was. Now typescript types should be 1 to 1 with the actual classes yup exposes.

In general this should not affect anything unless you are extending (via addMethod or otherwise) mixed prototype.

import {
-  mixed,
+  Schema,
} from 'yup';

- addMethod(mixed, 'method', impl)
+ addMethod(Schema, 'method', impl)
  • concat works shallowly now. Previously concat functioned like a deep merge for object, which produced confusing behavior with incompatible concat'ed schema. Now concat for objects works similar to how it works for other types, the provided schema is applied on top of the existing schema, producing a new schema that is the same as calling each builder method in order
  • The function version of when() has been changed to make it easier to type. values are always passed as an array and schema, and options always the second and third argument. this is no longer set to the schema instance. and all functions must return a schema to be type safe
 string()
-   .when('other', function (other) => {
-      if (other) return this.required()
+   .when('other', ([other], schema) => {
+     return other ? schema.required() : schema
  })

Better, Faster, Stronger...generics

29 Dec 18:19
Compare
Choose a tag to compare
Pre-release

Changes the object generics to store the derived type instead of the object shape. This imposes a few limitations on type accuracy at the edges, but dramatically speeds up the type processing by tsc on the command line and in editor. It also removes the need for the SchemaOf helper which worked...poorly.

Instead the ObjectSchema class accepts a plain type as its first generic:

interface Folder {
  id: ObjectId,
  label: string,
  files?: File[]
}

- const folder: SchemaOf<Folder, ObjectId | File> = object({
-   id: mixed<ObjectId>().defined(),
-   label: string().defined(), 
-   files: array(mixed<File>().defined()) 
- })
+ const folder: ObjectSchema<Folder> = object({ 
+  id: mixed<ObjectId>().defined(),
+  label: string().defined(), 
+  files: array(mixed<File>().defined())
+ })

It's a small diff, but big improvement in type accuracy and usability, especially with custom schema for class instances.

Note that the generics on the object() factory method are still the "object shape, meaning object<Folder>() won't work as expected. This is a compromise between the two strategies for handling generics and allows for an accurate type on object().getDefault()

A number of the improvements here are made possible by simplifications to yup's API and logic, this introduces a few breaking changes though most are small and easily migrated from.

Nullability and presence

This is the largest, and likely most disruptive change. Prior yup allowed for patterns like:

const nullableRequiredString = string().nullable().required()

nullableRequiredString.cast(null) // -> null

nullableRequiredString.validate(null) // ValidationError("this is required and cannot be null")

This may seem unintuitive behavior (and it is) but allowed for a common client side validation case, where we want to use a single schema to parse server data, as well as validate user input. In other words, a server might return invalid "default" values that should still fail when trying to submit.

Now, nullable(), defined and required are all mutually dependent methods. Meaning string().nullable().defined().required() produces a schema where the value must be a string, and not null or undefined. The effect of this is that the type of a cast() is now accurate and the same as the type returned from validate.