-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add sized array rule constructor
Fixes #1968 Add `sizedArrayRuleConstructor` to validate array size and items. * Implement `sizedArrayRuleConstructor` function in `src/ruleConstructors/sizedArrayRuleConstructor/sizedArrayRuleConstructor.ts` to validate array size and items. * Add tests for `sizedArrayRuleConstructor` in `src/ruleConstructors/sizedArrayRuleConstructor/sizedArrayRuleConstructor.test.ts`. * Document `sizedArrayRuleConstructor` in `src/ruleConstructors/sizedArrayRuleConstructor/readme.md`. * Update `readme.md` to include `sizedArrayRuleConstructor` under "Rule Constructors". * Export `sizedArrayRuleConstructor` in `src/rulr.ts`. --- For more details, open the [Copilot Workspace session](https://copilot-workspace.githubnext.com/ryasmi/rulr/issues/1968?shareId=XXXX-XXXX-XXXX-XXXX).
- Loading branch information
Showing
5 changed files
with
133 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
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,43 @@ | ||
# sizedArrayRuleConstructor | ||
|
||
[Back to root readme.md](../../../readme.md) | ||
|
||
This function can be used to construct rules that ensure an array input has a size within a specified range and that each item in the array satisfies a given rule. The function also generates an error class and a guard function. The rule should only throw errors with the generated error class. | ||
|
||
```ts | ||
import * as rulr from 'rulr' | ||
|
||
const exampleSymbol = Symbol() | ||
const [exampleArray, ExampleArrayError, exampleArrayGuard] = rulr.sizedArrayRuleConstructor(rulr.number, 1, 3, exampleSymbol) | ||
|
||
const constrainToExample = rulr.object({ | ||
required: { | ||
example: exampleArray, | ||
}, | ||
}) | ||
|
||
type Example = rulr.Static<typeof constrainToExample> | ||
// { | ||
// example: rulr.Constrained<typeof exampleSymbol, number[]> | ||
// } | ||
|
||
// Valid | ||
const example1: Example = constrainToExample({ | ||
example: [1, 2], | ||
}) | ||
|
||
// Invalid: Array size is less than minSize | ||
const example2: Example = constrainToExample({ | ||
example: [], | ||
}) | ||
|
||
// Invalid: Array size is greater than maxSize | ||
const example3: Example = constrainToExample({ | ||
example: [1, 2, 3, 4], | ||
}) | ||
|
||
// Invalid: Array contains invalid item | ||
const example4: Example = constrainToExample({ | ||
example: [1, '2'], | ||
}) | ||
``` |
37 changes: 37 additions & 0 deletions
37
src/ruleConstructors/sizedArrayRuleConstructor/sizedArrayRuleConstructor.test.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,37 @@ | ||
import * as assert from 'assert' | ||
import { sizedArrayRuleConstructor, Constrained } from '../../rulr' | ||
|
||
const ruleSymbol = Symbol() | ||
const [rule, InvalidValueError, guard] = sizedArrayRuleConstructor((input) => input, 1, 3, ruleSymbol) | ||
|
||
test('sizedArrayRuleConstructor rule should allow a valid array within size range', () => { | ||
const input = [1, 2] | ||
const output: Constrained<typeof ruleSymbol, unknown[]> = rule(input) | ||
assert.equal(guard(input), true) | ||
assert.deepStrictEqual(output, input) | ||
assert.ok(InvalidValueError) | ||
}) | ||
|
||
test('sizedArrayRuleConstructor rule should not allow an array smaller than minSize', () => { | ||
const input = [] | ||
assert.equal(guard(input), false) | ||
assert.throws(() => rule(input), InvalidValueError) | ||
}) | ||
|
||
test('sizedArrayRuleConstructor rule should not allow an array larger than maxSize', () => { | ||
const input = [1, 2, 3, 4] | ||
assert.equal(guard(input), false) | ||
assert.throws(() => rule(input), InvalidValueError) | ||
}) | ||
|
||
test('sizedArrayRuleConstructor rule should not allow an array with invalid items', () => { | ||
const input = [1, '2'] | ||
const [rule, InvalidValueError, guard] = sizedArrayRuleConstructor((input) => { | ||
if (typeof input === 'number') { | ||
return input | ||
} | ||
throw new Error('Invalid item') | ||
}, 1, 3, ruleSymbol) | ||
assert.equal(guard(input), false) | ||
assert.throws(() => rule(input), InvalidValueError) | ||
}) |
51 changes: 51 additions & 0 deletions
51
src/ruleConstructors/sizedArrayRuleConstructor/sizedArrayRuleConstructor.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,51 @@ | ||
import { BaseError } from 'make-error'; | ||
import { Constrained, Rule } from '../../core' | ||
import { array, InvalidArrayError } from '../../higherOrderRules/array/array' | ||
import { KeyedValidationError } from '../../errors/KeyedValidationError' | ||
import { ValidationErrors } from '../../errors/ValidationErrors' | ||
|
||
type Result<T extends symbol> = [ | ||
Rule<Constrained<T, unknown[]>>, | ||
typeof BaseError, | ||
(input: unknown) => input is Constrained<T, unknown[]> | ||
] | ||
|
||
export function sizedArrayRuleConstructor<T extends symbol>( | ||
itemRule: Rule<unknown>, | ||
minSize: number, | ||
maxSize: number, | ||
symbol: T, | ||
ruleName = 'valid array' | ||
): Result<T> { | ||
type SizedArray = Constrained<typeof symbol, unknown[]> | ||
|
||
function guard(input: unknown): input is SizedArray { | ||
if (!Array.isArray(input)) { | ||
return false | ||
} | ||
if (input.length < minSize || input.length > maxSize) { | ||
return false | ||
} | ||
try { | ||
array(itemRule)(input) | ||
return true | ||
} catch { | ||
return false | ||
} | ||
} | ||
|
||
class InvalidValueError extends BaseError { | ||
constructor() { | ||
super(`expected ${ruleName}`) | ||
} | ||
} | ||
|
||
function rule(input: unknown): SizedArray { | ||
if (guard(input)) { | ||
return input | ||
} | ||
throw new InvalidValueError() | ||
} | ||
|
||
return [rule, InvalidValueError, guard] | ||
} |
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