Skip to content

Commit

Permalink
Refactor path of nested issues and add tests
Browse files Browse the repository at this point in the history
Co-authored-by: Jussi Saurio <[email protected]>
Co-authored-by: Matti Lankinen <[email protected]>
  • Loading branch information
3 people committed Aug 22, 2023
1 parent 13fc38c commit 9de1771
Show file tree
Hide file tree
Showing 33 changed files with 932 additions and 477 deletions.
34 changes: 34 additions & 0 deletions library/src/schemas/array/array.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import {
includes,
} from '../../validations/index.ts';
import { number } from '../number/index.ts';
import { object } from '../object/object.ts';
import { string } from '../string/index.ts';
import { array } from './array.ts';

describe('array', () => {
Expand Down Expand Up @@ -60,6 +62,38 @@ describe('array', () => {
}
});

test('should return issue path', () => {
const schema1 = array(number());
const input1 = [1, 2, '3', 4];
const result1 = schema1._parse(input1);
expect(result1.issues?.[0].path).toEqual([
{
schema: 'array',
input: input1,
key: 2,
value: input1[2],
},
]);

const schema2 = array(object({ key: string() }));
const input2 = [{ key: '1' }, { key: 2 }, { key: '3' }];
const result2 = schema2._parse(input2);
expect(result2.issues?.[0].path).toEqual([
{
schema: 'array',
input: input2,
key: 1,
value: input2[1],
},
{
schema: 'object',
input: input2[1],
key: 'key',
value: input2[1].key,
},
]);
});

test('should execute pipe', () => {
const lengthError = 'Invalid length';
const contentError = 'Invalid content';
Expand Down
57 changes: 22 additions & 35 deletions library/src/schemas/array/array.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,7 @@
import type { Issues } from '../../error/index.ts';
import type { BaseSchema, Input, Output, Pipe } from '../../types.ts';
import {
executePipe,
getErrorAndPipe,
getIssue,
getPath,
getPathInfo,
} from '../../utils/index.ts';

/**
* Array path item type.
*/
export type ArrayPathItem = {
schema: 'array';
input: any[];
key: number;
value: any;
};
import { executePipe, getErrorAndPipe, getIssue } from '../../utils/index.ts';
import type { ArrayPathItem } from './types.ts';

/**
* Array schema type.
Expand Down Expand Up @@ -110,28 +95,30 @@ export function array<TArrayItem extends BaseSchema>(
const output: any[] = [];

// Parse schema of each array item
for (let index = 0; index < input.length; index++) {
const value = input[index];
const result = item._parse(
value,
getPathInfo(
info,
getPath(info?.path, {
schema: 'array',
input: input,
key: index,
value,
})
)
);
for (let key = 0; key < input.length; key++) {
const value = input[key];
const result = item._parse(value, info);

// If there are issues, capture them
if (result.issues) {
if (issues) {
for (const issue of result.issues) {
issues.push(issue);
// Create array path item
const pathItem: ArrayPathItem = {
schema: 'array',
input,
key,
value,
};

// Add modified result issues to issues
for (const issue of result.issues) {
if (issue.path) {
issue.path.unshift(pathItem);
} else {
issue.path = [pathItem];
}
} else {
issues?.push(issue);
}
if (!issues) {
issues = result.issues;
}

Expand Down
34 changes: 34 additions & 0 deletions library/src/schemas/array/arrayAsync.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import {
includes,
} from '../../validations/index.ts';
import { number, numberAsync } from '../number/index.ts';
import { object } from '../object/index.ts';
import { string } from '../string/index.ts';
import { arrayAsync } from './arrayAsync.ts';

describe('array', () => {
Expand Down Expand Up @@ -60,6 +62,38 @@ describe('array', () => {
}
});

test('should return issue path', async () => {
const schema1 = arrayAsync(number());
const input1 = [1, 2, '3', 4];
const result1 = await schema1._parse(input1);
expect(result1.issues?.[0].path).toEqual([
{
schema: 'array',
input: input1,
key: 2,
value: input1[2],
},
]);

const schema2 = arrayAsync(object({ key: string() }));
const input2 = [{ key: '1' }, { key: 2 }, { key: '3' }];
const result2 = await schema2._parse(input2);
expect(result2.issues?.[0].path).toEqual([
{
schema: 'array',
input: input2,
key: 1,
value: input2[1],
},
{
schema: 'object',
input: input2[1],
key: 'key',
value: input2[1].key,
},
]);
});

test('should execute pipe', async () => {
const lengthError = 'Invalid length';
const contentError = 'Invalid content';
Expand Down
37 changes: 19 additions & 18 deletions library/src/schemas/array/arrayAsync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@ import {
executePipeAsync,
getErrorAndPipe,
getIssue,
getPath,
getPathInfo,
} from '../../utils/index.ts';
import type { ArrayPathItem } from './types.ts';

/**
* Array schema async type.
Expand Down Expand Up @@ -111,28 +110,30 @@ export function arrayAsync<TArrayItem extends BaseSchema | BaseSchemaAsync>(
// If not aborted early, continue execution
if (!(info?.abortEarly && issues)) {
// Parse schema of array item
const result = await item._parse(
value,
getPathInfo(
info,
getPath(info?.path, {
schema: 'array',
input: input,
key,
value,
})
)
);
const result = await item._parse(value, info);

// If not aborted early, continue execution
if (!(info?.abortEarly && issues)) {
// If there are issues, capture them
if (result.issues) {
if (issues) {
for (const issue of result.issues) {
issues.push(issue);
// Create array path item
const pathItem: ArrayPathItem = {
schema: 'array',
input,
key,
value,
};

// Add modified result issues to issues
for (const issue of result.issues) {
if (issue.path) {
issue.path.unshift(pathItem);
} else {
issue.path = [pathItem];
}
} else {
issues?.push(issue);
}
if (!issues) {
issues = result.issues;
}

Expand Down
1 change: 1 addition & 0 deletions library/src/schemas/array/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './array.ts';
export * from './arrayAsync.ts';
export * from './types.ts';
9 changes: 9 additions & 0 deletions library/src/schemas/array/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* Array path item type.
*/
export type ArrayPathItem = {
schema: 'array';
input: any[];
key: number;
value: any;
};
64 changes: 62 additions & 2 deletions library/src/schemas/map/map.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import { describe, expect, test } from 'vitest';
import { type ValiError } from '../../error/index.ts';
import { parse } from '../../methods/index.ts';
import { maxSize, minSize, size } from '../../validations/index.ts';
import { map } from '../map/index.ts';
import { string } from '../string/index.ts';
import { date } from '../date/index.ts';
import { map } from '../map/index.ts';
import { number } from '../number/index.ts';
import { object } from '../object/index.ts';
import { string } from '../string/index.ts';

describe('map', () => {
test('should pass only maps', () => {
Expand Down Expand Up @@ -68,6 +69,65 @@ describe('map', () => {
}
});

test('should return issue path', () => {
const schema1 = map(string(), number());
const input1 = new Map().set('A', 1).set('B', 2).set('C', '3');
const result1 = schema1._parse(input1);
expect(result1.issues?.[0].path).toEqual([
{
schema: 'map',
input: input1,
key: 'C',
value: input1.get('C'),
},
]);

const schema2 = map(string(), object({ key: string() }));
const input2 = new Map()
.set('A', { key: '1' })
.set('B', { key: 2 })
.set('C', { key: '3' });
const result2 = schema2._parse(input2);
expect(result2.issues?.[0].origin).toBe('value');
expect(result2.issues?.[0].path).toEqual([
{
schema: 'map',
input: input2,
key: 'B',
value: input2.get('B'),
},
{
schema: 'object',
input: input2.get('B'),
key: 'key',
value: input2.get('B').key,
},
]);

const schema3 = map(object({ key: string() }), string());
const errorKey = { key: 2 };
const input3 = new Map()
.set({ key: '1' }, 'A')
.set(errorKey, 'B')
.set({ key: '3' }, 'C');
const result3 = schema3._parse(input3);
expect(result3.issues?.[0].origin).toBe('key');
expect(result3.issues?.[0].path).toEqual([
{
schema: 'map',
input: input3,
key: errorKey,
value: input3.get(errorKey),
},
{
schema: 'object',
input: errorKey,
key: 'key',
value: errorKey.key,
},
]);
});

test('should execute pipe', () => {
const sizeError = 'Invalid size';

Expand Down
Loading

0 comments on commit 9de1771

Please sign in to comment.