@leancodepl/validation 8.5.0 → 8.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,106 @@
1
+ # @leancodepl/validation
2
+
3
+ TypeScript library for handling validation errors in CQRS command responses with type-safe error code mapping.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @leancodepl/validation
9
+ # or
10
+ yarn add @leancodepl/validation
11
+ ```
12
+
13
+ ## API
14
+
15
+ ### `handleValidationErrors(validationErrors, errorCodesMap, validationResults)`
16
+
17
+ Creates a validation error handler that processes errors with type-safe error code mapping.
18
+
19
+ **Parameters:**
20
+
21
+ - `validationErrors: ValidationError<TAllErrors>[]` - Array of validation errors to process
22
+ - `errorCodesMap: TAllErrors` - Mapping of error names to numeric codes
23
+ - `validationResults?: TInResult[]` - Optional array of previous handler results
24
+
25
+ **Returns:** Handler with `handle`, `handleAll`, and `check` methods
26
+
27
+ ### `handleResponse(response, errorCodesMap)`
28
+
29
+ Handles CQRS command responses and transforms them into validation error handlers.
30
+
31
+ **Parameters:**
32
+
33
+ - `response: ApiResponse<CommandResult<TErrors>>` - API response containing command result
34
+ - `errorCodesMap: TErrors` - Mapping of error names to numeric codes
35
+
36
+ **Returns:** Validation error handler with success/failure support
37
+
38
+ ## Usage Examples
39
+
40
+ ### Basic Error Handling
41
+
42
+ ```typescript
43
+ import { handleValidationErrors } from "@leancodepl/validation"
44
+
45
+ const errorCodes = { EmailExists: 1, InvalidEmail: 2 } as const
46
+ const errors = [
47
+ { ErrorCode: 1, ErrorMessage: "Email exists", PropertyName: "Email", AttemptedValue: "user@example.com" },
48
+ ]
49
+
50
+ handleValidationErrors(errors, errorCodes)
51
+ .handle("EmailExists", () => console.log("Email already registered"))
52
+ .handle("InvalidEmail", () => console.log("Invalid email format"))
53
+ .check()
54
+ ```
55
+
56
+ ### Command Response Handling
57
+
58
+ ```typescript
59
+ import { handleResponse } from "@leancodepl/validation"
60
+
61
+ const errorCodes = { UserNotFound: 1 } as const
62
+ const response = await fetch("/api/users/123", { method: "PUT", body: JSON.stringify({ name: "John" }) })
63
+
64
+ handleResponse(response, errorCodes)
65
+ .handle("success", () => console.log("User updated"))
66
+ .handle("UserNotFound", () => console.log("User not found"))
67
+ .handle("failure", () => console.log("Request failed"))
68
+ .check()
69
+ ```
70
+
71
+ ### Multiple Error Handling
72
+
73
+ ```typescript
74
+ import { handleValidationErrors } from "@leancodepl/validation"
75
+
76
+ const errorCodes = { Required: 1, Invalid: 2 } as const
77
+ const errors = [
78
+ { ErrorCode: 1, PropertyName: "email", ErrorMessage: "Email required" },
79
+ { ErrorCode: 2, PropertyName: "name", ErrorMessage: "Invalid name" },
80
+ ]
81
+
82
+ handleValidationErrors(errors, errorCodes)
83
+ .handleAll(["Required", "Invalid"], errorGroups => {
84
+ errorGroups.forEach(({ errors }) => {
85
+ errors.forEach(error => console.log(`${error.PropertyName}: ${error.ErrorMessage}`))
86
+ })
87
+ })
88
+ .check()
89
+ ```
90
+
91
+ ### Success/Failure Result Processing
92
+
93
+ ```typescript
94
+ import { handleResponse } from "@leancodepl/validation"
95
+
96
+ const errorCodes = { InvalidData: 1 } as const
97
+ const response = await fetch("/api/data")
98
+
99
+ const isSuccess = handleResponse(response, errorCodes)
100
+ .handle("success", () => true)
101
+ .handle(["InvalidData", "failure"], () => false)
102
+ .check({
103
+ reducer: (prev, current) => prev && current,
104
+ initialValue: true,
105
+ })
106
+ ```
@@ -0,0 +1 @@
1
+ exports._default = require('./index.cjs.js').default;
package/index.cjs.js ADDED
@@ -0,0 +1,128 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Creates a validation error handler that processes errors with type-safe error code mapping.
5
+ *
6
+ * @template TAllErrors - Error codes map type extending Record<string, number>
7
+ * @template TInResult - Type of results accumulated from previous handlers
8
+ * @param validationErrors - Array of validation errors to process
9
+ * @param errorCodesMap - Mapping of error names to numeric codes
10
+ * @param validationResults - Optional array of previous handler results
11
+ * @returns Handler with handle, handleAll, and check methods
12
+ * @example
13
+ * ```typescript
14
+ * const errorCodes = { EmailExists: 1, InvalidEmail: 2 } as const;
15
+ * const errors = [{ ErrorCode: 1, ErrorMessage: 'Email exists', PropertyName: 'Email', AttemptedValue: 'test@example.com' }];
16
+ *
17
+ * handleValidationErrors(errors, errorCodes)
18
+ * .handle('EmailExists', () => console.warn('Email already registered'))
19
+ * .handle('InvalidEmail', () => console.warn('Invalid email format'))
20
+ * .check();
21
+ * ```
22
+ */ function handleValidationErrors(validationErrors, errorCodesMap, validationResults = []) {
23
+ const handle = (validationErrorsToHandle, handler)=>{
24
+ let result = undefined;
25
+ for (const validationErrorToHandle of Array.isArray(validationErrorsToHandle) ? validationErrorsToHandle : [
26
+ validationErrorsToHandle
27
+ ]){
28
+ const ve = validationErrors.find((ve)=>ve.ErrorCode === errorCodesMap[validationErrorToHandle]);
29
+ if (ve) {
30
+ result = handler(validationErrorToHandle, ve);
31
+ break;
32
+ }
33
+ }
34
+ let nextResult = validationResults;
35
+ if (result !== undefined) {
36
+ nextResult = [
37
+ ...nextResult,
38
+ result
39
+ ];
40
+ }
41
+ return handleValidationErrors(validationErrors, errorCodesMap, nextResult);
42
+ };
43
+ const handleAll = (_validationErrorsToHandle, handler)=>{
44
+ let result = undefined;
45
+ const validationErrorsToHandle = Array.isArray(_validationErrorsToHandle) ? _validationErrorsToHandle : [
46
+ _validationErrorsToHandle
47
+ ];
48
+ const foundErrors = validationErrorsToHandle.reduce((prev, cur)=>{
49
+ const ves = validationErrors.filter((ve)=>ve.ErrorCode === errorCodesMap[cur]);
50
+ if (ves.length === 0) {
51
+ return prev;
52
+ }
53
+ return [
54
+ ...prev,
55
+ {
56
+ errorName: cur,
57
+ errors: ves
58
+ }
59
+ ];
60
+ }, []);
61
+ if (foundErrors.length > 0) {
62
+ result = handler(foundErrors);
63
+ }
64
+ let nextResult = validationResults;
65
+ if (result !== undefined) {
66
+ nextResult = [
67
+ ...nextResult,
68
+ result
69
+ ];
70
+ }
71
+ return handleValidationErrors(validationErrors, errorCodesMap, nextResult);
72
+ };
73
+ return {
74
+ handle,
75
+ handleAll,
76
+ check: (reducer)=>{
77
+ if (reducer) {
78
+ return validationResults.reduce(reducer.reducer, reducer.initialValue);
79
+ }
80
+ return;
81
+ }
82
+ };
83
+ }
84
+
85
+ /**
86
+ * Handles CQRS command responses and transforms them into validation error handlers.
87
+ *
88
+ * @template TErrors - Error codes map type extending Record<string, number>
89
+ * @param response - API response containing command result
90
+ * @param errorCodesMap - Mapping of error names to numeric codes
91
+ * @returns Validation error handler with success/failure support
92
+ * @example
93
+ * ```typescript
94
+ * const errorCodes = { UserNotFound: 1 } as const;
95
+ * const response = await commandClient.execute(createUserCommand);
96
+ *
97
+ * handleResponse(response, errorCodes)
98
+ * .handle('success', () => console.log('User created'))
99
+ * .handle('failure', () => console.log('Network error'))
100
+ * .handle('UserNotFound', () => console.log('User not found'))
101
+ * .check();
102
+ * ```
103
+ */ function handleResponse(response, errorCodesMap) {
104
+ const newErrorCodesMap = {
105
+ ...errorCodesMap,
106
+ success: -1,
107
+ failure: -2
108
+ };
109
+ const validationErrors = response.isSuccess ? response.result.WasSuccessful ? [
110
+ {
111
+ AttemptedValue: "",
112
+ ErrorMessage: "",
113
+ PropertyName: "",
114
+ ErrorCode: -1
115
+ }
116
+ ] : response.result.ValidationErrors : [
117
+ {
118
+ AttemptedValue: "",
119
+ ErrorMessage: "",
120
+ PropertyName: "",
121
+ ErrorCode: -2
122
+ }
123
+ ];
124
+ return handleValidationErrors(validationErrors, newErrorCodesMap);
125
+ }
126
+
127
+ exports.handleResponse = handleResponse;
128
+ exports.handleValidationErrors = handleValidationErrors;
package/index.cjs.mjs ADDED
@@ -0,0 +1,2 @@
1
+ export * from './index.cjs.js';
2
+ export { _default as default } from './index.cjs.default.js';
package/index.d.ts ADDED
@@ -0,0 +1 @@
1
+ export * from "./src/index";
package/index.esm.js ADDED
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Creates a validation error handler that processes errors with type-safe error code mapping.
3
+ *
4
+ * @template TAllErrors - Error codes map type extending Record<string, number>
5
+ * @template TInResult - Type of results accumulated from previous handlers
6
+ * @param validationErrors - Array of validation errors to process
7
+ * @param errorCodesMap - Mapping of error names to numeric codes
8
+ * @param validationResults - Optional array of previous handler results
9
+ * @returns Handler with handle, handleAll, and check methods
10
+ * @example
11
+ * ```typescript
12
+ * const errorCodes = { EmailExists: 1, InvalidEmail: 2 } as const;
13
+ * const errors = [{ ErrorCode: 1, ErrorMessage: 'Email exists', PropertyName: 'Email', AttemptedValue: 'test@example.com' }];
14
+ *
15
+ * handleValidationErrors(errors, errorCodes)
16
+ * .handle('EmailExists', () => console.warn('Email already registered'))
17
+ * .handle('InvalidEmail', () => console.warn('Invalid email format'))
18
+ * .check();
19
+ * ```
20
+ */ function handleValidationErrors(validationErrors, errorCodesMap, validationResults = []) {
21
+ const handle = (validationErrorsToHandle, handler)=>{
22
+ let result = undefined;
23
+ for (const validationErrorToHandle of Array.isArray(validationErrorsToHandle) ? validationErrorsToHandle : [
24
+ validationErrorsToHandle
25
+ ]){
26
+ const ve = validationErrors.find((ve)=>ve.ErrorCode === errorCodesMap[validationErrorToHandle]);
27
+ if (ve) {
28
+ result = handler(validationErrorToHandle, ve);
29
+ break;
30
+ }
31
+ }
32
+ let nextResult = validationResults;
33
+ if (result !== undefined) {
34
+ nextResult = [
35
+ ...nextResult,
36
+ result
37
+ ];
38
+ }
39
+ return handleValidationErrors(validationErrors, errorCodesMap, nextResult);
40
+ };
41
+ const handleAll = (_validationErrorsToHandle, handler)=>{
42
+ let result = undefined;
43
+ const validationErrorsToHandle = Array.isArray(_validationErrorsToHandle) ? _validationErrorsToHandle : [
44
+ _validationErrorsToHandle
45
+ ];
46
+ const foundErrors = validationErrorsToHandle.reduce((prev, cur)=>{
47
+ const ves = validationErrors.filter((ve)=>ve.ErrorCode === errorCodesMap[cur]);
48
+ if (ves.length === 0) {
49
+ return prev;
50
+ }
51
+ return [
52
+ ...prev,
53
+ {
54
+ errorName: cur,
55
+ errors: ves
56
+ }
57
+ ];
58
+ }, []);
59
+ if (foundErrors.length > 0) {
60
+ result = handler(foundErrors);
61
+ }
62
+ let nextResult = validationResults;
63
+ if (result !== undefined) {
64
+ nextResult = [
65
+ ...nextResult,
66
+ result
67
+ ];
68
+ }
69
+ return handleValidationErrors(validationErrors, errorCodesMap, nextResult);
70
+ };
71
+ return {
72
+ handle,
73
+ handleAll,
74
+ check: (reducer)=>{
75
+ if (reducer) {
76
+ return validationResults.reduce(reducer.reducer, reducer.initialValue);
77
+ }
78
+ return;
79
+ }
80
+ };
81
+ }
82
+
83
+ /**
84
+ * Handles CQRS command responses and transforms them into validation error handlers.
85
+ *
86
+ * @template TErrors - Error codes map type extending Record<string, number>
87
+ * @param response - API response containing command result
88
+ * @param errorCodesMap - Mapping of error names to numeric codes
89
+ * @returns Validation error handler with success/failure support
90
+ * @example
91
+ * ```typescript
92
+ * const errorCodes = { UserNotFound: 1 } as const;
93
+ * const response = await commandClient.execute(createUserCommand);
94
+ *
95
+ * handleResponse(response, errorCodes)
96
+ * .handle('success', () => console.log('User created'))
97
+ * .handle('failure', () => console.log('Network error'))
98
+ * .handle('UserNotFound', () => console.log('User not found'))
99
+ * .check();
100
+ * ```
101
+ */ function handleResponse(response, errorCodesMap) {
102
+ const newErrorCodesMap = {
103
+ ...errorCodesMap,
104
+ success: -1,
105
+ failure: -2
106
+ };
107
+ const validationErrors = response.isSuccess ? response.result.WasSuccessful ? [
108
+ {
109
+ AttemptedValue: "",
110
+ ErrorMessage: "",
111
+ PropertyName: "",
112
+ ErrorCode: -1
113
+ }
114
+ ] : response.result.ValidationErrors : [
115
+ {
116
+ AttemptedValue: "",
117
+ ErrorMessage: "",
118
+ PropertyName: "",
119
+ ErrorCode: -2
120
+ }
121
+ ];
122
+ return handleValidationErrors(validationErrors, newErrorCodesMap);
123
+ }
124
+
125
+ export { handleResponse, handleValidationErrors };
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@leancodepl/validation",
3
- "version": "8.5.0",
3
+ "version": "8.5.1",
4
4
  "license": "Apache-2.0",
5
5
  "dependencies": {
6
- "@leancodepl/cqrs-client-base": "8.5.0"
6
+ "@leancodepl/cqrs-client-base": "8.5.1"
7
7
  },
8
8
  "devDependencies": {
9
9
  "sinon": "15.2.0"
@@ -38,11 +38,6 @@
38
38
  "name": "LeanCode",
39
39
  "url": "https://leancode.co"
40
40
  },
41
- "files": [
42
- "dist",
43
- "README.md",
44
- "CHANGELOG.md"
45
- ],
46
41
  "sideEffects": false,
47
42
  "exports": {
48
43
  "./package.json": "./package.json",
package/src/index.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from "./lib/handleResponse";
2
+ export * from "./lib/handleValidationErrors";
@@ -0,0 +1,28 @@
1
+ import { ApiResponse, CommandResult } from "@leancodepl/cqrs-client-base";
2
+ export type SuccessOrFailureMarker = {
3
+ success: -1;
4
+ failure: -2;
5
+ };
6
+ /**
7
+ * Handles CQRS command responses and transforms them into validation error handlers.
8
+ *
9
+ * @template TErrors - Error codes map type extending Record<string, number>
10
+ * @param response - API response containing command result
11
+ * @param errorCodesMap - Mapping of error names to numeric codes
12
+ * @returns Validation error handler with success/failure support
13
+ * @example
14
+ * ```typescript
15
+ * const errorCodes = { UserNotFound: 1 } as const;
16
+ * const response = await commandClient.execute(createUserCommand);
17
+ *
18
+ * handleResponse(response, errorCodes)
19
+ * .handle('success', () => console.log('User created'))
20
+ * .handle('failure', () => console.log('Network error'))
21
+ * .handle('UserNotFound', () => console.log('User not found'))
22
+ * .check();
23
+ * ```
24
+ */
25
+ export declare function handleResponse<TErrors extends Record<string, number>>(response: ApiResponse<CommandResult<TErrors>>, errorCodesMap: TErrors): import("./handleValidationErrors").ValidationErrorsHandler<TErrors & {
26
+ readonly success: -1;
27
+ readonly failure: -2;
28
+ }, never>;
@@ -0,0 +1,43 @@
1
+ import { ValidationError } from "@leancodepl/cqrs-client-base";
2
+ export type ReducerDescription<THandlerResult, TReturnValue = THandlerResult> = {
3
+ reducer: (prev: TReturnValue, cur: THandlerResult) => TReturnValue;
4
+ initialValue: TReturnValue;
5
+ };
6
+ export type SpecificValidationError<TErrors extends Record<string, number>, TError extends keyof TErrors> = ValidationError<Record<TError, TErrors[TError]>>;
7
+ export type ValidationErrorHandlerFunc<TErrorsToHandle extends Record<string, number>, THandledErrors extends keyof TErrorsToHandle, TResult> = (errorName: THandledErrors, error: SpecificValidationError<TErrorsToHandle, THandledErrors>) => TResult;
8
+ export type ValidationErrorsHandleFunc<TErrorsToHandle extends Record<string, number>, TInResult> = {
9
+ <THandledErrors extends keyof TErrorsToHandle, TResult>(validationErrors: THandledErrors | THandledErrors[], handler: ValidationErrorHandlerFunc<TErrorsToHandle, THandledErrors, TResult>): ValidationErrorsHandler<Omit<TErrorsToHandle, THandledErrors>, TInResult | TResult>;
10
+ };
11
+ export type ValidationErrorHandlerAllFunc<TErrorsToHandle extends Record<string, number>, THandledErrors extends keyof TErrorsToHandle, TResult> = (errors: {
12
+ errorName: THandledErrors;
13
+ errors: SpecificValidationError<TErrorsToHandle, THandledErrors>[];
14
+ }[]) => TResult;
15
+ export type ValidationErrorsHandleAllFunc<TErrorsToHandle extends Record<string, number>, TInResult> = {
16
+ <THandledErrors extends keyof TErrorsToHandle, TResult>(validationErrors: THandledErrors | THandledErrors[], handler: ValidationErrorHandlerAllFunc<TErrorsToHandle, THandledErrors, TResult>): ValidationErrorsHandler<Omit<TErrorsToHandle, THandledErrors>, TInResult | TResult>;
17
+ };
18
+ export interface ValidationErrorsHandler<TRemainingErrors extends Record<string, number>, TResult> {
19
+ handle: ValidationErrorsHandleFunc<TRemainingErrors, TResult>;
20
+ handleAll: ValidationErrorsHandleAllFunc<TRemainingErrors, TResult>;
21
+ check: object extends TRemainingErrors ? <TReturnValue = void>(reducer?: ReducerDescription<TResult, TReturnValue>) => TReturnValue : unknown;
22
+ }
23
+ /**
24
+ * Creates a validation error handler that processes errors with type-safe error code mapping.
25
+ *
26
+ * @template TAllErrors - Error codes map type extending Record<string, number>
27
+ * @template TInResult - Type of results accumulated from previous handlers
28
+ * @param validationErrors - Array of validation errors to process
29
+ * @param errorCodesMap - Mapping of error names to numeric codes
30
+ * @param validationResults - Optional array of previous handler results
31
+ * @returns Handler with handle, handleAll, and check methods
32
+ * @example
33
+ * ```typescript
34
+ * const errorCodes = { EmailExists: 1, InvalidEmail: 2 } as const;
35
+ * const errors = [{ ErrorCode: 1, ErrorMessage: 'Email exists', PropertyName: 'Email', AttemptedValue: 'test@example.com' }];
36
+ *
37
+ * handleValidationErrors(errors, errorCodes)
38
+ * .handle('EmailExists', () => console.warn('Email already registered'))
39
+ * .handle('InvalidEmail', () => console.warn('Invalid email format'))
40
+ * .check();
41
+ * ```
42
+ */
43
+ export declare function handleValidationErrors<TAllErrors extends Record<string, number>, TInResult = never>(validationErrors: ValidationError<TAllErrors>[], errorCodesMap: TAllErrors, validationResults?: TInResult[]): ValidationErrorsHandler<TAllErrors, TInResult>;