Skip to content

Commit 3806ece

Browse files
committed
feat: add 'shouldValidate' option
1 parent 7597f6e commit 3806ece

File tree

3 files changed

+153
-15
lines changed

3 files changed

+153
-15
lines changed

README.md

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,19 +50,25 @@ const parsedParameters = parameters.parse({
5050
//=> { TOKEN: 'xxxx', FIREBASE_CONFIG: { apiKey: 'xxxx' } }
5151
```
5252

53-
### API
53+
## API
5454

5555
see `test/index.spec.ts`.
5656

57-
```ts
58-
import { createTypedParameters } from 'construct-typed-parameters';
57+
### createTypedParameters
5958

60-
// type ParameterValidate<T> = (value: T) => string | string[] | null;
59+
```ts
60+
import {
61+
createTypedParameters,
62+
TypedParametersConstruct,
63+
} from 'construct-typed-parameters';
6164

62-
const parameters = createTypedParameters(pt => ({
65+
const parameters: TypedParametersConstruct<T> = createTypedParameters(pt => ({
6366
stringValue: pt.String({
67+
// required: boolean
6468
required: true,
69+
// defaultValue?: T1
6570
defaultValue: 'xxxx',
71+
// validate?: (value: T1) => string | string[] | null;
6672
validate: v => (v.includes('x') ? null : 'the value must contain x'),
6773
}),
6874
unionStringValue: pt.UnionString<'v1' | 'v2'>({
@@ -99,6 +105,28 @@ const parameters = createTypedParameters(pt => ({
99105
}));
100106
```
101107

108+
### TypedParametersConstruct#parse
109+
110+
```ts
111+
const parameters: TypedParametersConstruct<T> = createTypedParameters(pt => ({ ... }));
112+
113+
parameters.parse(
114+
stringifiedParameters: Partial<StringifiedParameters<T>>,
115+
shouldValidate = true
116+
) : ParsedParameters<T>
117+
```
118+
119+
### TypedParametersConstruct#stringify
120+
121+
```ts
122+
const parameters: TypedParametersConstruct<T> = createTypedParameters(pt => ({ ... }));
123+
124+
parameters.stringify(
125+
parsedParameters: Partial<ParsedParameters<T>>,
126+
shouldValidate = true
127+
) : StringifiedParameters<T>
128+
```
129+
102130
[build-img]: https://github.com/masahirompp/construct-typed-parameters/actions/workflows/release.yml/badge.svg
103131
[build-url]: https://github.com/masahirompp/construct-typed-parameters/actions/workflows/release.yml
104132
[downloads-img]: https://img.shields.io/npm/dt/construct-typed-parameters

src/index.ts

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -136,14 +136,17 @@ const ParameterType = {
136136
class TypedParameters<T extends Record<string, ParameterConstruct<any>>> {
137137
constructor(private parametersConstruct: T) {}
138138

139-
parse(serializedParameters: Partial<StringifiedParameters<T>>) {
139+
parse(
140+
stringifiedParameters: Partial<StringifiedParameters<T>>,
141+
shouldValidate = true
142+
) {
140143
const requiredErrorParameters: string[] = [];
141144
const validationErrorParameterMap: Record<string, string[]> = {};
142145
const result = Object.entries(this.parametersConstruct).reduce<
143146
ParsedParameters<T>
144147
>((payload, [parameterName, construct]) => {
145148
const value = (() => {
146-
const serialized = serializedParameters[parameterName];
149+
const serialized = stringifiedParameters[parameterName];
147150
const parsedValue =
148151
typeof serialized === 'string'
149152
? construct.parse(serialized)
@@ -156,13 +159,17 @@ class TypedParameters<T extends Record<string, ParameterConstruct<any>>> {
156159
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
157160
return construct.defaultValue;
158161
}
159-
if (construct.required) {
162+
if (shouldValidate && construct.required) {
160163
requiredErrorParameters.push(parameterName);
161164
}
162165
return undefined;
163166
})();
164167

165-
if (value != null && typeof construct.validate === 'function') {
168+
if (
169+
shouldValidate &&
170+
value != null &&
171+
typeof construct.validate === 'function'
172+
) {
166173
const validationError = construct.validate(value);
167174
if (validationError) {
168175
if (Array.isArray(validationError)) {
@@ -188,23 +195,30 @@ class TypedParameters<T extends Record<string, ParameterConstruct<any>>> {
188195
throw new ParameterError(
189196
requiredErrorParameters,
190197
validationErrorParameterMap,
191-
serializedParameters,
198+
stringifiedParameters,
192199
result
193200
);
194201
}
195202
return result;
196203
}
197204

198-
stringify(parameters: Partial<ParsedParameters<T>>) {
205+
stringify(
206+
parsedParameters: Partial<ParsedParameters<T>>,
207+
shouldValidate = true
208+
) {
199209
const requiredErrorParameters: string[] = [];
200210
const validationErrorParameterMap: Record<string, string[]> = {};
201211
const result = Object.entries(this.parametersConstruct).reduce<
202212
StringifiedParameters<T>
203213
>((payload, [parameterName, construct]) => {
204214
const serialized = (() => {
205-
const value = parameters[parameterName];
215+
const value = parsedParameters[parameterName];
206216

207-
if (value != null && typeof construct.validate === 'function') {
217+
if (
218+
shouldValidate &&
219+
value != null &&
220+
typeof construct.validate === 'function'
221+
) {
208222
const validationError = construct.validate(value);
209223
if (validationError) {
210224
if (Array.isArray(validationError)) {
@@ -230,7 +244,7 @@ class TypedParameters<T extends Record<string, ParameterConstruct<any>>> {
230244
return serializedDefaultValue;
231245
}
232246
}
233-
if (construct.required) {
247+
if (shouldValidate && construct.required) {
234248
requiredErrorParameters.push(parameterName);
235249
}
236250
return undefined;
@@ -250,7 +264,7 @@ class TypedParameters<T extends Record<string, ParameterConstruct<any>>> {
250264
requiredErrorParameters,
251265
validationErrorParameterMap,
252266
result,
253-
parameters
267+
parsedParameters
254268
);
255269
}
256270
return result;

test/index.spec.ts

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ describe('index', () => {
4141
);
4242
});
4343

44+
it('parse required error but should not validate', () => {
45+
expect(parameters.parse({}, false)).toEqual({});
46+
});
47+
4448
it('stringify', () => {
4549
expect(
4650
parameters.stringify({
@@ -69,6 +73,10 @@ describe('index', () => {
6973
'stringValue is required, unionStringValue is required, numberValue is required, unionNumberValue is required, booleanValue is required, jsonValue is required, arrayValue is required.'
7074
);
7175
});
76+
77+
it('stringify required error but should not validate', () => {
78+
expect(parameters.stringify({}, false)).toEqual({});
79+
});
7280
});
7381

7482
describe('all required with defaultValue.', () => {
@@ -401,6 +409,33 @@ describe('index', () => {
401409
);
402410
});
403411

412+
it('parse validation error but should not validate', () => {
413+
expect(
414+
parameters.parse(
415+
{
416+
stringValue: 'yyyy',
417+
unionStringValue: 'v3',
418+
numberValue: '0',
419+
unionNumberValue: '-1',
420+
booleanValue: 'false',
421+
jsonValue: '{"apiKey":""}',
422+
arrayValue: '[]',
423+
},
424+
false
425+
)
426+
).toEqual({
427+
arrayValue: [],
428+
booleanValue: false,
429+
jsonValue: {
430+
apiKey: '',
431+
},
432+
numberValue: 0,
433+
stringValue: 'yyyy',
434+
unionNumberValue: -1,
435+
unionStringValue: 'v3',
436+
});
437+
});
438+
404439
it('parse required error and validation error', () => {
405440
expect(() =>
406441
parameters.parse({
@@ -414,6 +449,25 @@ describe('index', () => {
414449
);
415450
});
416451

452+
it('parse required error and validation error, but should not validaet', () => {
453+
expect(
454+
parameters.parse(
455+
{
456+
stringValue: 'yyyy',
457+
numberValue: '0',
458+
booleanValue: 'false',
459+
arrayValue: '[]',
460+
},
461+
false
462+
)
463+
).toEqual({
464+
stringValue: 'yyyy',
465+
numberValue: 0,
466+
booleanValue: false,
467+
arrayValue: [],
468+
});
469+
});
470+
417471
it('stringify', () => {
418472
expect(
419473
parameters.stringify({
@@ -463,6 +517,31 @@ describe('index', () => {
463517
);
464518
});
465519

520+
it('stringify validation error but should not validate', () => {
521+
expect(
522+
parameters.stringify(
523+
{
524+
stringValue: 'yyyy',
525+
unionStringValue: 'v3' as never,
526+
numberValue: 0,
527+
unionNumberValue: -1 as never,
528+
booleanValue: false,
529+
jsonValue: { apiKey: '' },
530+
arrayValue: [],
531+
},
532+
false
533+
)
534+
).toEqual({
535+
stringValue: 'yyyy',
536+
unionStringValue: 'v3',
537+
numberValue: '0',
538+
unionNumberValue: '-1',
539+
booleanValue: 'false',
540+
jsonValue: '{"apiKey":""}',
541+
arrayValue: '[]',
542+
});
543+
});
544+
466545
it('stringify required error and validation error', () => {
467546
expect(() =>
468547
parameters.stringify({
@@ -474,5 +553,22 @@ describe('index', () => {
474553
'stringValue is required, numberValue is required, booleanValue is required, arrayValue is required. unionStringValue: the value must be v1 or v2, unionNumberValue: the value must be 0 or 1, jsonValue: apiKey must be specified.'
475554
);
476555
});
556+
557+
it('stringify required error and validation error, but should not validate', () => {
558+
expect(
559+
parameters.stringify(
560+
{
561+
unionStringValue: 'v3' as never,
562+
unionNumberValue: -1 as never,
563+
jsonValue: { apiKey: '' },
564+
},
565+
false
566+
)
567+
).toEqual({
568+
unionStringValue: 'v3',
569+
unionNumberValue: '-1',
570+
jsonValue: '{"apiKey":""}',
571+
});
572+
});
477573
});
478574
});

0 commit comments

Comments
 (0)