From 7029ba92a9261923081d9bb3eb1f441d167e0943 Mon Sep 17 00:00:00 2001 From: Junxiao Shi Date: Wed, 29 Jun 2022 13:31:18 +0000 Subject: [PATCH] feat: accept minOccurs and maxOccurs in parsers.array --- README.md | 4 ++-- src/parsers.test.ts | 47 +++++++++++++++++++++++++++++++++++++++++++++ src/parsers.ts | 22 +++++++++++++++++++-- 3 files changed, 69 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 4333a92..3ffb50c 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ to _your_ definition of valid. See [how to use it](#usage). - [`parsers.port(value: string): number`](#parsersportvalue-string-number) - [`parsers.whitelist(whitelistedValues: string[]): Parser`](#parserswhitelistwhitelistedvalues-string-parserstring) - [`parsers.regex(pattern: Regex): Parser`](#parsersregexpattern-regex-parserstring) - - [`parsers.array({ parser: Parser, separator?: string }): Parser`](#parsersarrayt-parser-parsert-separator-string--parsert) + - [`parsers.array({ parser: Parser, separator?: string, minOccurs?: number, maxOccurs?: number }): Parser`](#parsers-array) - [`parsers.positiveInteger(value: string): number`](#parserspositiveintegervalue-string-number) - [`parsers.nonPositiveInteger(value: string): number`](#parsersnonpositiveintegervalue-string-number) - [`parsers.negativeInteger(value: string): number`](#parsersnegativeintegervalue-string-number) @@ -227,7 +227,7 @@ const env = makeEnv({ }); ``` -#### `parsers.array({ parser: Parser, separator?: string }): Parser` +#### `parsers.array({ parser: Parser, separator?: string, minOccurs?: number, maxOccurs?: number }): Parser` Takes a parser and returns a parser that parses a list of values. The default value separator is `,`. diff --git a/src/parsers.test.ts b/src/parsers.test.ts index cdf3009..da896a1 100644 --- a/src/parsers.test.ts +++ b/src/parsers.test.ts @@ -208,6 +208,53 @@ describe('parsers.array', () => { expect(() => parser(serializedValue)).toThrow(); }); + + test('parses an array of values with minOccurs and maxOccurs', () => { + const values = ['test1', 'test2', 'test3']; + + const serializedValue = values.join(','); + const expectedValue = values; + + const parser = parsers.array({ + parser: parsers.string, + minOccurs: 1, + maxOccurs: 4, + }); + + expect(parser(serializedValue)).toEqual(expectedValue); + }); + + test('throws when minOccurs is violated', () => { + const values = ['test1', 'test2', 'test3']; + + const serializedValue = values.join(','); + + const parser = parsers.array({ + parser: parsers.string, + minOccurs: 4, + maxOccurs: 4, + }); + + expect(() => parser(serializedValue)).toThrow( + 'array has fewer than 4 items', + ); + }); + + test('throws when maxOccurs is violated', () => { + const values = ['test1', 'test2', 'test3']; + + const serializedValue = values.join(','); + + const parser = parsers.array({ + parser: parsers.string, + minOccurs: 1, + maxOccurs: 2, + }); + + expect(() => parser(serializedValue)).toThrow( + 'array has more than 2 items', + ); + }); }); describe('parsers.positiveInteger', () => { diff --git a/src/parsers.ts b/src/parsers.ts index 9ac65a8..d7ce2b7 100644 --- a/src/parsers.ts +++ b/src/parsers.ts @@ -161,6 +161,8 @@ export function regex(pattern: RegExp): Parser { export type ArrayParserArgs = Readonly<{ parser: Parser; separator?: string; + minOccurs?: number; + maxOccurs?: number; }>; const defaultArraySeparator = ','; @@ -171,15 +173,31 @@ const defaultArraySeparator = ','; export function array( args: ArrayParserArgs, ): Parser { - const separator = args.separator || defaultArraySeparator; + const { + parser, + separator = defaultArraySeparator, + minOccurs, + maxOccurs, + } = args; const arrayParser: Parser = (serializedArray) => { const serializedValues = serializedArray.split(separator); const values = serializedValues.map((serializedValue) => - args.parser(serializedValue), + parser(serializedValue), ); + if (minOccurs !== undefined && values.length < minOccurs) { + throw new EnvironmentVariableError( + `array has fewer than ${minOccurs} items`, + ); + } + if (maxOccurs !== undefined && values.length > maxOccurs) { + throw new EnvironmentVariableError( + `array has more than ${maxOccurs} items`, + ); + } + return values; };