Skip to content

Commit

Permalink
Merge pull request #103 from FlorianDevPhynix/main
Browse files Browse the repository at this point in the history
Fallback method
  • Loading branch information
fabian-hiller authored Aug 21, 2023
2 parents 59008c1 + e36dc9b commit 11d9fc7
Show file tree
Hide file tree
Showing 11 changed files with 185 additions and 9 deletions.
1 change: 1 addition & 0 deletions library/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ All notable changes to the library will be documented in this file.
- Add `getPipeInfo`, `getPathInfo` and `getIssue` util (pull request #46, #92, #93)
- Add support for `boolean`, `bigint` and `symbol` to `literal` (pull request #102)
- Add `fallback` and `fallbackAsync` method (pull request #103)
- Expand `flatten` so that issues are also accepted as first argument
- Change return type of `safeParse` and `safeParseAsync` method
- Change error handling and refactor library to improve performance
Expand Down
30 changes: 30 additions & 0 deletions library/src/methods/fallback/fallback.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { describe, expect, test } from 'vitest';
import { object, string } from '../../schemas/index.ts';
import { parse } from '../parse/index.ts';
import { fallback } from './fallback.ts';

describe('fallback', () => {
const schema1 = fallback(string(), 'test');
const schema2 = fallback(string(), () => 'test');
const schema3 = object({ key1: schema1, key2: schema2 });

test('should use default value', () => {
const output1 = parse(schema1, 123);
expect(output1).toBe('test');
const output2 = parse(schema2, 123);
expect(output2).toBe('test');
const output3 = parse(schema3, {});
expect(output3).toEqual({ key1: 'test', key2: 'test' });
});

test('should not use default value', () => {
const input1 = 'hello';
const output1 = parse(schema1, input1);
expect(output1).toBe(input1);
const output2 = parse(schema2, input1);
expect(output2).toBe(input1);
const input2 = { key1: 'hello', key2: 'hello' };
const output3 = parse(schema3, input2);
expect(output3).toEqual(input2);
});
});
41 changes: 41 additions & 0 deletions library/src/methods/fallback/fallback.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import type { BaseSchema, Output } from '../../types.ts';
import type { FallbackInfo } from './types.ts';

/**
* Returns a fallback value when validating the passed schema failed.
*
* @param schema The schema to catch.
* @param value The fallback value.
*
* @returns The passed schema.
*/
export function fallback<TSchema extends BaseSchema>(
schema: TSchema,
value: Output<TSchema> | ((info: FallbackInfo) => Output<TSchema>)
): TSchema {
return {
...schema,

/**
* Parses unknown input based on its schema.
*
* @param input The input to be parsed.
* @param info The parse info.
*
* @returns The parsed output.
*/
_parse(input, info) {
const result = schema._parse(input, info);
return {
output: result.issues
? typeof value === 'function'
? (value as (info: FallbackInfo) => Output<TSchema>)({
input,
issues: result.issues,
})
: value
: result.output,
};
},
};
}
30 changes: 30 additions & 0 deletions library/src/methods/fallback/fallbackAsync.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { describe, expect, test } from 'vitest';
import { objectAsync, string, stringAsync } from '../../schemas/index.ts';
import { parseAsync } from '../parse/index.ts';
import { fallbackAsync } from './fallbackAsync.ts';

describe('fallbackAsync', () => {
const schema1 = fallbackAsync(stringAsync(), 'test');
const schema2 = fallbackAsync(string(), () => 'test');
const schema3 = objectAsync({ key1: schema1, key2: schema2 });

test('should use default value', async () => {
const output1 = await parseAsync(schema1, 123);
expect(output1).toBe('test');
const output2 = await parseAsync(schema2, 123);
expect(output2).toBe('test');
const output3 = await parseAsync(schema3, {});
expect(output3).toEqual({ key1: 'test', key2: 'test' });
});

test('should not use default value', async () => {
const input1 = 'hello';
const output1 = await parseAsync(schema1, input1);
expect(output1).toBe(input1);
const output2 = await parseAsync(schema2, input1);
expect(output2).toBe(input1);
const input2 = { key1: 'hello', key2: 'hello' };
const output3 = await parseAsync(schema3, input2);
expect(output3).toEqual(input2);
});
});
41 changes: 41 additions & 0 deletions library/src/methods/fallback/fallbackAsync.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import type { BaseSchema, BaseSchemaAsync, Output } from '../../types.ts';
import type { FallbackInfo } from './types.ts';

/**
* Returns a fallback value when validating the passed schema failed.
*
* @param schema The schema to catch.
* @param value The fallback value.
*
* @returns The passed schema.
*/
export function fallbackAsync<TSchema extends BaseSchema | BaseSchemaAsync>(
schema: TSchema,
value: Output<TSchema> | ((info: FallbackInfo) => Output<TSchema>)
): TSchema {
return {
...schema,

/**
* Parses unknown input based on its schema.
*
* @param input The input to be parsed.
* @param info The parse info.
*
* @returns The parsed output.
*/
async _parse(input, info) {
const result = await schema._parse(input, info);
return {
output: result.issues
? typeof value === 'function'
? (value as (info: FallbackInfo) => Output<TSchema>)({
input,
issues: result.issues,
})
: value
: result.output,
};
},
};
}
2 changes: 2 additions & 0 deletions library/src/methods/fallback/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { fallback } from './fallback.ts';
export { fallbackAsync } from './fallbackAsync.ts';
9 changes: 9 additions & 0 deletions library/src/methods/fallback/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import type { Issues } from '../../error/index.ts';

/**
* Fallback info type.
*/
export type FallbackInfo = {
input: unknown;
issues: Issues;
};
1 change: 1 addition & 0 deletions library/src/methods/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from './brand/index.ts';
export * from './coerce/index.ts';
export * from './fallback/index.ts';
export * from './is/index.ts';
export * from './keyof/index.ts';
export * from './merge/index.ts';
Expand Down
21 changes: 12 additions & 9 deletions library/src/methods/withDefault/withDefault.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,22 @@ import { parse } from '../parse/index.ts';
import { withDefault } from './withDefault.ts';

describe('withDefault', () => {
const schema1 = withDefault(string(), 'test');
const schema2 = object({ test: schema1 });

test('should use default value', () => {
const schema1 = withDefault(string(), 'test');
const output1 = parse(schema1, undefined);
expect(output1).toBe('test');
const input1 = 'hello';
const output2 = parse(schema1, input1);
expect(output2).toBe(input1);
const output2 = parse(schema2, {});
expect(output2).toEqual({ test: 'test' });
});

const schema2 = object({ test: schema1 });
const output3 = parse(schema2, {});
expect(output3).toEqual({ test: 'test' });
test('should not use default value', () => {
const input1 = 'hello';
const output1 = parse(schema1, input1);
expect(output1).toBe(input1);
const input2 = { test: 'hello' };
const output4 = parse(schema2, input2);
expect(output4).toEqual(input2);
const output2 = parse(schema2, input2);
expect(output2).toEqual(input2);
});
});
7 changes: 7 additions & 0 deletions website/src/routes/api/(methods)/fallback/index.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
title: fallback
---

# fallback

> The content of this page is not yet ready. Until then just use the [source code](https://github.com/fabian-hiller/valibot/blob/main/library/src/methods/fallback/fallback.ts).
11 changes: 11 additions & 0 deletions website/src/routes/guides/(main-concepts)/methods/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,17 @@ const StringSchema = withDefault(string(), 'hello');
const stringOutput = parse(StringSchema, undefined); // 'hello'
```

### Fallback

If an issue occurs while validating your schema, you can catch it with <Link href="/api/fallback">`fallback`</Link> to return a predefined value instead.

```ts
import { parse, fallback, string } from 'valibot'; // 0.44 kB

const StringSchema = fallback(string(), 'hello');
const stringOutput = parse(StringSchema, 123); // 'hello'
```

## Object methods

My object methods make it easier for you to work with object schemas. They are strongly oriented towards the functionality of TypeScript.
Expand Down

0 comments on commit 11d9fc7

Please sign in to comment.