Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jquense/yup
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v1.4.0
Choose a base ref
...
head repository: jquense/yup
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v1.5.0
Choose a head ref
  • 6 commits
  • 9 files changed
  • 5 contributors

Commits on Mar 6, 2024

  1. Update README.md

    jquense committed Mar 6, 2024
    Copy the full SHA
    0f2cad3 View commit details

Commits on Mar 15, 2024

  1. fix(readme): some typos and update CustomizingErrors doc (#2163)

    * fix(readme): some typos and update CustomizingErrors doc
    
    * fix(readme): update CustomizingErrors doc
    
    * Update README.md
    yjhtry authored Mar 15, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    5c77e0d View commit details

Commits on Jul 2, 2024

  1. let/const consistency in README: let preference (#2227)

    I noticed let and const are used interchangeably in README. For consistency, I'd like to propose to use either/or. The previous PR was about changing all `let`s to `const`s
    dearlordylord authored Jul 2, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    5a22c16 View commit details

Commits on Nov 25, 2024

  1. Fix ValidationError.formatError() clobbering path param (#2250)

    And export `AnyMessageParams`, `MessageParams` types.
    
    Co-authored-by: Shaun Grady <[email protected]>
    shaungrady and Shaun Grady authored Nov 25, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    87be159 View commit details

Commits on Dec 3, 2024

  1. feat: Add exact and stripUnknown method to object()

    jquense committed Dec 3, 2024
    Copy the full SHA
    adcdd8d View commit details
  2. Publish v1.5.0

    jquense committed Dec 3, 2024
    Copy the full SHA
    8ac18b6 View commit details
Showing with 120 additions and 45 deletions.
  1. +16 −0 CHANGELOG.md
  2. +51 −40 README.md
  3. +3 −2 package.json
  4. +4 −1 src/ValidationError.ts
  5. +4 −0 src/index.ts
  6. +3 −1 src/locale.ts
  7. +26 −1 src/object.ts
  8. +1 −0 src/types.ts
  9. +12 −0 test/object.ts
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
# [1.5.0](https://github.com/jquense/yup/compare/v1.4.0...v1.5.0) (2024-12-03)


### Bug Fixes

* **readme:** some typos and update CustomizingErrors doc ([#2163](https://github.com/jquense/yup/issues/2163)) ([5c77e0d](https://github.com/jquense/yup/commit/5c77e0d4f9373151bcf0cd558c95986b6e4800d7))


### Features

* Add exact and stripUnknown method to object() ([adcdd8d](https://github.com/jquense/yup/commit/adcdd8dd500c627b1efbe3595b6b37dec2847ad8))





# [1.4.0](https://github.com/jquense/yup/compare/v1.3.3...v1.4.0) (2024-03-06)


91 changes: 51 additions & 40 deletions README.md
Original file line number Diff line number Diff line change
@@ -29,7 +29,7 @@ let userSchema = object({
});

// parse and assert validity
const user = await userSchema.validate(await fetchUser());
let user = await userSchema.validate(await fetchUser());

type User = InferType<typeof userSchema>;
/* {
@@ -46,7 +46,7 @@ transform that value into more concrete and specific values, without making furt

```ts
// Attempts to coerce values to the correct type
const parsedUser = userSchema.cast({
let parsedUser = userSchema.cast({
name: 'jimmy',
age: '24',
createdOn: '2014-09-23T19:25:25Z',
@@ -59,7 +59,7 @@ of running parsing logic.

```ts
// ❌ ValidationError "age is not a number"
const parsedUser = await userSchema.validate(
let parsedUser = await userSchema.validate(
{
name: 'jimmy',
age: '24',
@@ -111,8 +111,8 @@ const parsedUser = await userSchema.validate(
- [`Schema.withMutation(builder: (current: Schema) => void): void`](#schemawithmutationbuilder-current-schema--void-void)
- [`Schema.default(value: any): Schema`](#schemadefaultvalue-any-schema)
- [`Schema.getDefault(options?: object): Any`](#schemagetdefaultoptions-object-any)
- [`Schema.nullable(message?: string | function): Schema`](#schemanullable-schema)
- [`Schema.nonNullable(message?: string | function): Schema`](#schemanonnullable-schema)
- [`Schema.nullable(message?: string | function): Schema`](#schemanullablemessage-string--function-schema)
- [`Schema.nonNullable(message?: string | function): Schema`](#schemanonnullablemessage-string--function-schema)
- [`Schema.defined(): Schema`](#schemadefined-schema)
- [`Schema.optional(): Schema`](#schemaoptional-schema)
- [`Schema.required(message?: string | function): Schema`](#schemarequiredmessage-string--function-schema)
@@ -190,9 +190,9 @@ Each built-in type implements basic type parsing, which comes in handy when pars
Additionally types implement type specific transforms that can be enabled.

```ts
const num = number().cast('1'); // 1
let num = number().cast('1'); // 1

const obj = object({
let obj = object({
firstName: string().lowercase().trim(),
})
.json()
@@ -203,7 +203,7 @@ const obj = object({
Custom transforms can be added

```ts
const reversedString = string()
let reversedString = string()
.transform((currentValue) => currentValue.split('').reverse().join(''))
.cast('dlrow olleh'); // "hello world"
```
@@ -230,7 +230,7 @@ string()
As with transforms, tests can be customized on the fly

```ts
const jamesSchema = string().test(
let jamesSchema = string().test(
'is-james',
(d) => `${d.path} is not James`,
(value) => value == null || value === 'James',
@@ -258,27 +258,27 @@ in the case of a nested validation.
Error messages can also be constructed on the fly to customize how the schema fails.

```ts
const order = object({
no: number().required().
let order = object({
no: number().required(),
sku: string().test({
name: 'is-sku',
skipAbsent: true,
test(value, ctx) {
if (!value.startsWith('s-')) {
return ctx.createError({ message: 'SKU missing correct prefix' })
return ctx.createError({ message: 'SKU missing correct prefix' });
}
if (!value.endsWith('-42a')) {
return ctx.createError({ message: 'SKU missing correct suffix' })
return ctx.createError({ message: 'SKU missing correct suffix' });
}
if (value.length < 10) {
return ctx.createError({ message: 'SKU is not the right length' })
return ctx.createError({ message: 'SKU is not the right length' });
}
return true
}
})
})
return true;
},
}),
});

order.validate({ no: 1234, sku: 's-1a45-14a' })
order.validate({ no: 1234, sku: 's-1a45-14a' });
```

### Composition and Reuse
@@ -287,11 +287,11 @@ Schema are immutable, each method call returns a new schema object. Reuse and pa
fear of mutating another instance.

```ts
const optionalString = string().optional();
let optionalString = string().optional();

const definedString = optionalString.defined();
let definedString = optionalString.defined();

const value = undefined;
let value = undefined;
optionalString.isValid(value); // true
definedString.isValid(value); // false
```
@@ -303,7 +303,7 @@ Yup schema produce static TypeScript interfaces. Use `InferType` to extract that
```ts
import * as yup from 'yup';

const personSchema = yup.object({
let personSchema = yup.object({
firstName: yup.string().defined(),
nickName: yup.string().default('').nullable(),
sex: yup
@@ -327,11 +327,11 @@ setting a default affects the output type of the schema, essentially marking it
```ts
import { string } from 'yup';

const value: string = string().default('hi').validate(undefined);
let value: string = string().default('hi').validate(undefined);

// vs

const value: string | undefined = string().validate(undefined);
let value: string | undefined = string().validate(undefined);
```

### Ensuring a schema matches an existing type
@@ -349,18 +349,17 @@ interface Person {
}

// will raise a compile-time type error if the schema does not produce a valid Person
const schema: ObjectSchema<Person> = object({
let schema: ObjectSchema<Person> = object({
name: string().defined(),
age: number().optional(),
sex: string<'male' | 'female' | 'other'>().nullable().defined(),
});

// ❌ errors:
// "Type 'number | undefined' is not assignable to type 'string'."
const badSchema: ObjectSchema<Person> = object({
let badSchema: ObjectSchema<Person> = object({
name: number(),
});

```

### Extending built-in schema with new methods
@@ -664,11 +663,11 @@ Collects schema details (like meta, labels, and active tests) into a serializabl
description object.

```ts
const schema = object({
let schema = object({
name: string().required(),
});

const description = schema.describe();
let description = schema.describe();
```

For schema with dynamic components (references, lazy, or conditions), describe requires
@@ -954,7 +953,7 @@ Indicates that `null` is a valid value for the schema. Without `nullable()`
`null` is treated as a different type and will fail `Schema.isType()` checks.

```ts
const schema = number().nullable();
let schema = number().nullable();

schema.cast(null); // null

@@ -967,7 +966,7 @@ The opposite of `nullable`, removes `null` from valid type values for the schema
**Schema are non nullable by default**.

```ts
const schema = number().nonNullable();
let schema = number().nonNullable();

schema.cast(null); // TypeError

@@ -979,7 +978,7 @@ InferType<typeof schema>; // number
Require a value for the schema. All field values apart from `undefined` meet this requirement.

```ts
const schema = string().defined();
let schema = string().defined();

schema.cast(undefined); // TypeError

@@ -991,7 +990,7 @@ InferType<typeof schema>; // string
The opposite of `defined()` allows `undefined` values for the given type.

```ts
const schema = string().optional();
let schema = string().optional();

schema.cast(undefined); // undefined

@@ -1610,7 +1609,7 @@ Object schema come with a default value already set, which "builds" out the obje
sets any defaults for fields:

```js
const schema = object({
let schema = object({
name: string().default(''),
});

@@ -1623,7 +1622,7 @@ one gotcha! though. For nested object schema that are optional but include non o
may fail in unexpected ways:

```js
const schema = object({
let schema = object({
id: string().required(),
names: object({
first: string().required(),
@@ -1685,13 +1684,13 @@ fields.
Create a new schema from a subset of the original's fields.

```js
const person = object({
let person = object({
age: number().default(30).required(),
name: string().default('pat').required(),
color: string().default('red').required(),
});

const nameAndAge = person.pick(['name', 'age']);
let nameAndAge = person.pick(['name', 'age']);
nameAndAge.getDefault(); // => { age: 30, name: 'pat'}
```

@@ -1700,13 +1699,13 @@ nameAndAge.getDefault(); // => { age: 30, name: 'pat'}
Create a new schema with fields omitted.

```js
const person = object({
let person = object({
age: number().default(30).required(),
name: string().default('pat').required(),
color: string().default('red').required(),
});

const nameAndAge = person.omit(['color']);
let nameAndAge = person.omit(['color']);
nameAndAge.getDefault(); // => { age: 30, name: 'pat'}
```

@@ -1725,11 +1724,23 @@ let schema = object({
schema.cast({ prop: 5, other: 6 }); // => { myProp: 5, other: 6, Other: 6 }
```

#### `object.exact(message?: string | function): Schema`

Validates that the object does not contain extra or unknown properties

#### `object.stripUnknown(): Schema`

The same as `object().validate(value, { stripUnknown: true})`, but as a transform method. When set
any unknown properties will be removed.

#### `object.noUnknown(onlyKnownKeys: boolean = true, message?: string | function): Schema`

Validate that the object value only contains keys specified in `shape`, pass `false` as the first
argument to disable the check. Restricting keys to known, also enables `stripUnknown` option, when not in strict mode.

> Watch Out!: this method performs a transform and a validation, which may produce unexpected results.
> For more explicit behavior use `object().stripUnknown` and `object().exact()`
#### `object.camelCase(): Schema`

Transforms all object keys to camelCase
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "yup",
"version": "1.4.0",
"version": "1.5.0",
"description": "Dead simple Object schema validation",
"main": "lib/index.js",
"module": "lib/index.esm.js",
@@ -105,5 +105,6 @@
"tiny-case": "^1.0.3",
"toposort": "^2.0.2",
"type-fest": "^2.19.0"
}
},
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
}
5 changes: 4 additions & 1 deletion src/ValidationError.ts
Original file line number Diff line number Diff line change
@@ -63,8 +63,11 @@ export default class ValidationError extends Error {
message: string | ((params: Params) => string) | unknown,
params: Params,
) {
// Attempt to make the path more friendly for error message interpolation.
const path = params.label || params.path || 'this';
if (path !== params.path) params = { ...params, path };
// Store the original path under `originalPath` so it isn't lost to custom
// message functions; e.g., ones provided in `setLocale()` calls.
params = { ...params, path, originalPath: params.path };

if (typeof message === 'string')
return message.replace(strReg, (_, key) => printValue(params[key]));
4 changes: 4 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -31,9 +31,11 @@ import Schema, {
CustomSchemaMetadata,
} from './schema';
import type {
AnyMessageParams,
InferType,
ISchema,
Message,
MessageParams,
ValidateOptions,
DefaultThunk,
} from './types';
@@ -65,11 +67,13 @@ export type AnyObjectSchema = ObjectSchema<any, any, any, any>;
export type CastOptions = Omit<BaseCastOptions, 'path' | 'resolved'>;

export type {
AnyMessageParams,
AnyObject,
InferType,
InferType as Asserts,
ISchema,
Message,
MessageParams,
AnySchema,
MixedOptions,
TypeGuard as MixedTypeGuard,
4 changes: 3 additions & 1 deletion src/locale.ts
Original file line number Diff line number Diff line change
@@ -44,7 +44,8 @@ export interface DateLocale {
}

export interface ObjectLocale {
noUnknown?: Message;
noUnknown?: Message<{ unknown: string[] }>;
exact?: Message<{ properties: string[] }>;
}

export interface ArrayLocale {
@@ -134,6 +135,7 @@ export let boolean: BooleanLocale = {

export let object: Required<ObjectLocale> = {
noUnknown: '${path} field has unspecified keys: ${unknown}',
exact: '${path} object contains unknown properties: ${properties}',
};

export let array: Required<ArrayLocale> = {
Loading