-
-
Notifications
You must be signed in to change notification settings - Fork 216
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
17 changed files
with
1,021 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { describe, expectTypeOf, test } from 'vitest'; | ||
import type { InferInput, InferIssue, InferOutput } from '../../types/index.ts'; | ||
import { | ||
codePoints, | ||
type CodePointsAction, | ||
type CodePointsIssue, | ||
} from './codePoints.ts'; | ||
|
||
describe('codePoints', () => { | ||
describe('should return action object', () => { | ||
test('with undefined message', () => { | ||
type Action = CodePointsAction<string, 10, undefined>; | ||
expectTypeOf(codePoints<string, 10>(10)).toEqualTypeOf<Action>(); | ||
expectTypeOf( | ||
codePoints<string, 10, undefined>(10, undefined) | ||
).toEqualTypeOf<Action>(); | ||
}); | ||
|
||
test('with string message', () => { | ||
expectTypeOf( | ||
codePoints<string, 10, 'message'>(10, 'message') | ||
).toEqualTypeOf<CodePointsAction<string, 10, 'message'>>(); | ||
}); | ||
|
||
test('with function message', () => { | ||
expectTypeOf( | ||
codePoints<string, 10, () => string>(10, () => 'message') | ||
).toEqualTypeOf<CodePointsAction<string, 10, () => string>>(); | ||
}); | ||
}); | ||
|
||
describe('should infer correct types', () => { | ||
type Input = 'example string'; | ||
type Action = CodePointsAction<Input, 5, undefined>; | ||
|
||
test('of input', () => { | ||
expectTypeOf<InferInput<Action>>().toEqualTypeOf<Input>(); | ||
}); | ||
|
||
test('of output', () => { | ||
expectTypeOf<InferOutput<Action>>().toEqualTypeOf<Input>(); | ||
}); | ||
|
||
test('of issue', () => { | ||
expectTypeOf<InferIssue<Action>>().toEqualTypeOf< | ||
CodePointsIssue<Input, 5> | ||
>(); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
import { describe, expect, test } from 'vitest'; | ||
import type { StringIssue } from '../../schemas/index.ts'; | ||
import { _getCodePointCount } from '../../utils/index.ts'; | ||
import { expectActionIssue, expectNoActionIssue } from '../../vitest/index.ts'; | ||
import { | ||
codePoints, | ||
type CodePointsAction, | ||
type CodePointsIssue, | ||
} from './codePoints.ts'; | ||
|
||
describe('graphemes', () => { | ||
describe('should return action object', () => { | ||
const baseAction: Omit<CodePointsAction<string, 5, never>, 'message'> = { | ||
kind: 'validation', | ||
type: 'code_points', | ||
reference: codePoints, | ||
expects: '5', | ||
requirement: 5, | ||
async: false, | ||
'~validate': expect.any(Function), | ||
}; | ||
|
||
test('with undefined message', () => { | ||
const action: CodePointsAction<string, 5, undefined> = { | ||
...baseAction, | ||
message: undefined, | ||
}; | ||
expect(codePoints(5)).toStrictEqual(action); | ||
expect(codePoints(5, undefined)).toStrictEqual(action); | ||
}); | ||
|
||
test('with string message', () => { | ||
expect(codePoints(5, 'message')).toStrictEqual({ | ||
...baseAction, | ||
message: 'message', | ||
} satisfies CodePointsAction<string, 5, string>); | ||
}); | ||
|
||
test('with function message', () => { | ||
const message = () => 'message'; | ||
expect(codePoints(5, message)).toStrictEqual({ | ||
...baseAction, | ||
message, | ||
} satisfies CodePointsAction<string, 5, typeof message>); | ||
}); | ||
}); | ||
|
||
describe('should return dataset without issues', () => { | ||
const action = codePoints(5); | ||
|
||
test('for untyped inputs', () => { | ||
const issues: [StringIssue] = [ | ||
{ | ||
kind: 'schema', | ||
type: 'string', | ||
input: null, | ||
expected: 'string', | ||
received: 'null', | ||
message: 'message', | ||
}, | ||
]; | ||
expect( | ||
action['~validate']({ typed: false, value: null, issues }, {}) | ||
).toStrictEqual({ | ||
typed: false, | ||
value: null, | ||
issues, | ||
}); | ||
}); | ||
|
||
test('for valid strings', () => { | ||
expectNoActionIssue(action, ['12345', '12 45', '1234 ', 'hello']); | ||
}); | ||
|
||
test('for valid emoji', () => { | ||
expectNoActionIssue(action, ['👨🏽👩🏽', '😶🌫️😀', '😡👍😁😂😀', '0️⃣㊙️']); | ||
}); | ||
|
||
test('for valid non-latin', () => { | ||
expectNoActionIssue(action, ['あ𛀙よろし', '𠮷野家で𩸽', '葛󠄀城市!']); | ||
}); | ||
}); | ||
|
||
describe('should return dataset with issues', () => { | ||
const action = codePoints(5, 'message'); | ||
const baseIssue: Omit<CodePointsIssue<string, 5>, 'input' | 'received'> = { | ||
kind: 'validation', | ||
type: 'code_points', | ||
expected: '5', | ||
message: 'message', | ||
requirement: 5, | ||
}; | ||
|
||
test('for invalid strings', () => { | ||
expectActionIssue( | ||
action, | ||
baseIssue, | ||
['', ' ', '1', '1234', '123 ', '123456', '12 456', '123456789'], | ||
(value) => `${_getCodePointCount(value)}` | ||
); | ||
}); | ||
|
||
test('for invalid emoji', () => { | ||
expectActionIssue( | ||
action, | ||
baseIssue, | ||
['😀👋🏼🧩👩🏻🏫🫥', '㊙️㊙️0️⃣1️⃣2️⃣'], | ||
(value) => `${_getCodePointCount(value)}` | ||
); | ||
}); | ||
|
||
test('for invalid non-latin', () => { | ||
expectActionIssue( | ||
action, | ||
baseIssue, | ||
['竈門禰󠄀豆子', '葛󠄀城市'], | ||
(value) => `${_getCodePointCount(value)}` | ||
); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
import type { | ||
BaseIssue, | ||
BaseValidation, | ||
ErrorMessage, | ||
} from '../../types/index.ts'; | ||
import { _addIssue, _getCodePointCount } from '../../utils/index.ts'; | ||
|
||
/** | ||
* CodePoints issue type. | ||
*/ | ||
export interface CodePointsIssue< | ||
TInput extends string, | ||
TRequirement extends number, | ||
> extends BaseIssue<TInput> { | ||
/** | ||
* The issue kind. | ||
*/ | ||
readonly kind: 'validation'; | ||
/** | ||
* The issue type. | ||
*/ | ||
readonly type: 'code_points'; | ||
/** | ||
* The expected property. | ||
*/ | ||
readonly expected: `${TRequirement}`; | ||
/** | ||
* The received property. | ||
*/ | ||
readonly received: `${number}`; | ||
/** | ||
* The required codePoints. | ||
*/ | ||
readonly requirement: TRequirement; | ||
} | ||
|
||
/** | ||
* CodePoints action type. | ||
*/ | ||
export interface CodePointsAction< | ||
TInput extends string, | ||
TRequirement extends number, | ||
TMessage extends | ||
| ErrorMessage<CodePointsIssue<TInput, TRequirement>> | ||
| undefined, | ||
> extends BaseValidation<TInput, TInput, CodePointsIssue<TInput, TRequirement>> { | ||
/** | ||
* The action type. | ||
*/ | ||
readonly type: 'code_points'; | ||
/** | ||
* The action reference. | ||
*/ | ||
readonly reference: typeof codePoints; | ||
/** | ||
* The expected property. | ||
*/ | ||
readonly expects: `${TRequirement}`; | ||
/** | ||
* The required code points. | ||
*/ | ||
readonly requirement: TRequirement; | ||
/** | ||
* The error message. | ||
*/ | ||
readonly message: TMessage; | ||
} | ||
|
||
/** | ||
* Creates a code points validation action. | ||
* | ||
* @param requirement The required code points. | ||
* | ||
* @returns A code points action. | ||
*/ | ||
export function codePoints< | ||
TInput extends string, | ||
const TRequirement extends number, | ||
>(requirement: TRequirement): CodePointsAction<TInput, TRequirement, undefined>; | ||
|
||
/** | ||
* Creates a code points validation action. | ||
* | ||
* @param requirement The required code points. | ||
* @param message The error message. | ||
* | ||
* @returns A code points action. | ||
*/ | ||
export function codePoints< | ||
TInput extends string, | ||
const TRequirement extends number, | ||
const TMessage extends | ||
| ErrorMessage<CodePointsIssue<TInput, TRequirement>> | ||
| undefined, | ||
>( | ||
requirement: TRequirement, | ||
message: TMessage | ||
): CodePointsAction<TInput, TRequirement, TMessage>; | ||
|
||
export function codePoints( | ||
requirement: number, | ||
message?: ErrorMessage<CodePointsIssue<string, number>> | ||
): CodePointsAction< | ||
string, | ||
number, | ||
ErrorMessage<CodePointsIssue<string, number>> | undefined | ||
> { | ||
return { | ||
kind: 'validation', | ||
type: 'code_points', | ||
reference: codePoints, | ||
async: false, | ||
expects: `${requirement}`, | ||
requirement, | ||
message, | ||
'~validate'(dataset, config) { | ||
if (dataset.typed) { | ||
const count = _getCodePointCount(dataset.value); | ||
if (count !== this.requirement) { | ||
_addIssue(this, 'codePoints', dataset, config, { | ||
received: `${count}`, | ||
}); | ||
} | ||
} | ||
return dataset; | ||
}, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './codePoints.ts'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './maxCodePoints.ts'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { describe, expectTypeOf, test } from 'vitest'; | ||
import type { InferInput, InferIssue, InferOutput } from '../../types/index.ts'; | ||
import { | ||
maxCodePoints, | ||
type MaxCodePointsAction, | ||
type MaxCodePointsIssue, | ||
} from './maxCodePoints.ts'; | ||
|
||
describe('maxCodePoints', () => { | ||
describe('should return action object', () => { | ||
test('with undefined message', () => { | ||
type Action = MaxCodePointsAction<string, 10, undefined>; | ||
expectTypeOf(maxCodePoints<string, 10>(10)).toEqualTypeOf<Action>(); | ||
expectTypeOf( | ||
maxCodePoints<string, 10, undefined>(10, undefined) | ||
).toEqualTypeOf<Action>(); | ||
}); | ||
|
||
test('with string message', () => { | ||
expectTypeOf( | ||
maxCodePoints<string, 10, 'message'>(10, 'message') | ||
).toEqualTypeOf<MaxCodePointsAction<string, 10, 'message'>>(); | ||
}); | ||
|
||
test('with function message', () => { | ||
expectTypeOf( | ||
maxCodePoints<string, 10, () => string>(10, () => 'message') | ||
).toEqualTypeOf<MaxCodePointsAction<string, 10, () => string>>(); | ||
}); | ||
}); | ||
|
||
describe('should infer correct types', () => { | ||
type Input = 'example string'; | ||
type Action = MaxCodePointsAction<Input, 10, undefined>; | ||
|
||
test('of input', () => { | ||
expectTypeOf<InferInput<Action>>().toEqualTypeOf<Input>(); | ||
}); | ||
|
||
test('of output', () => { | ||
expectTypeOf<InferOutput<Action>>().toEqualTypeOf<Input>(); | ||
}); | ||
|
||
test('of issue', () => { | ||
expectTypeOf<InferIssue<Action>>().toEqualTypeOf< | ||
MaxCodePointsIssue<Input, 10> | ||
>(); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.