@elementor/utils 0.1.0 → 0.2.0

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.
@@ -0,0 +1,22 @@
1
+
2
+ > @elementor/utils@0.1.0 build
3
+ > tsup --config=../../tsup.build.ts
4
+
5
+ CLI Building entry: src/index.ts
6
+ CLI Using tsconfig: ../../../tsconfig.json
7
+ CLI tsup v7.2.0
8
+ CLI Using tsup config: /home/runner/work/elementor-packages/elementor-packages/tsup.build.ts
9
+ CLI Target: esnext
10
+ CLI Cleaning output folder
11
+ ESM Build start
12
+ CJS Build start
13
+ ESM dist/index.mjs 922.00 B
14
+ ESM dist/index.mjs.map 2.13 KB
15
+ ESM ⚡️ Build success in 114ms
16
+ CJS dist/index.js 1.97 KB
17
+ CJS dist/index.js.map 2.35 KB
18
+ CJS ⚡️ Build success in 115ms
19
+ DTS Build start
20
+ DTS ⚡️ Build success in 22795ms
21
+ DTS dist/index.d.mts 1.24 KB
22
+ DTS dist/index.d.ts 1.24 KB
package/CHANGELOG.md CHANGED
@@ -3,6 +3,12 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [0.2.0](https://github.com/elementor/elementor-packages/compare/@elementor/utils@0.1.0...@elementor/utils@0.2.0) (2024-07-28)
7
+
8
+ ### Features
9
+
10
+ - **utils/errors:** add `ensureError` function [EDS-291] ([#218](https://github.com/elementor/elementor-packages/issues/218)) ([915d521](https://github.com/elementor/elementor-packages/commit/915d5214831c249f308ba9344ad9eecdc2887fe4))
11
+
6
12
  # 0.1.0 (2024-07-24)
7
13
 
8
14
  ### Features
package/README.md CHANGED
@@ -1,20 +1,28 @@
1
1
  # Utils
2
2
  This package contains utility functions that are being used across the Elementor packages.
3
3
 
4
- ## Installation
5
- ```bash
6
- npm install @elementor/utils
7
- ```
8
-
9
- ### Errors
4
+ ## Errors
10
5
  This module contains a standard API for creating custom error classes in Elementor packages.
11
6
 
12
- #### Usage
7
+ ### `createError`
13
8
  To ensure consistency across the Elementor packages, we recommend creating a new error class that extends the
14
- `ElementorError` class, or using the `createError` function that does it for you.
9
+ `ElementorError` class using the `createError` function that does it for you.
15
10
 
16
- #### Creating a new error manually
17
- You can create a new error that extends the `ElementorError`.
11
+ #### Creating a new error type
12
+ For convenience, we've exposed a `createError` utility function that will create a custom error type for you.
13
+ This function will force your error code and message to be static (per our guidelines), and will shorten your code a little bit:
14
+
15
+ ```ts
16
+ // errors.ts
17
+ import { createError } from '@elementor/utils';
18
+
19
+ export const CannotRender = createError<{ id: string; }>( 'cannot-render', 'Cannot render element' );
20
+ export const CannotSave = createError<{ id: number; status: string; }>( 'cannot-save', 'Cannot save document' );
21
+ export const ElementNotFound = createError<{ id: string; }>( 'element-not-found', 'Element not found' );
22
+ ```
23
+
24
+ #### Creating a new error type manually
25
+ If you prefer to create a new error type manually, you can extend the `ElementorError` class.
18
26
 
19
27
  Inside your class, you'll need to define a unique error code and message that should be passed to the parent constructor.
20
28
 
@@ -44,30 +52,17 @@ class CannotRender extends ElementorError {
44
52
  }
45
53
  ```
46
54
 
47
- #### Using the `createError` function
48
- For convenience, we've exposed a `createError` utility function that will create a custom error for you.
49
- This function will force your error code and message to be static (per our guidelines), and will shorten your code a little bit:
50
-
51
- ```ts
52
- // errors.ts
53
- import { createError } from '@elementor/utils';
54
-
55
- export const CannotRender = createError<{ id: string; }>( 'cannot-render', 'Cannot render element' );
56
- export const CannotSave = createError<{ id: number; status: string; }>( 'cannot-save', 'Cannot save document' );
57
- export const ElementNotFound = createError<{ id: string; }>( 'element-not-found', 'Element not found' );
58
- ```
59
-
60
- #### Throwing an error
61
- After creating your custom error (as described above), you can throw it in your code:
55
+ #### Throwing your custom error type
56
+ After creating your custom error type (as described above), you can throw it in your code:
62
57
 
63
58
  Basic example:
64
59
  ```ts
65
60
  export const ElementNotFound = createError<{ id: string; }>( 'element-not-found', 'Element not found' );
66
61
 
67
- function renderElement(id: string): string {
68
- const element = findElementById(id);
62
+ function renderElement( id: string ): string {
63
+ const element = findElementById( id );
69
64
 
70
- if (!element) {
65
+ if ( ! element ) {
71
66
  throw new ElementNotFound({ context: { id } });
72
67
  }
73
68
 
@@ -80,8 +75,27 @@ Example with a cause:
80
75
  export const CannotSave = createError<{ id: number; status: string; }>( 'cannot-save', 'Cannot save document' );
81
76
 
82
77
  try {
83
- thirdPartyService.save(number);
84
- } catch (error) {
85
- throw new CannotSave({ context: { id: number, status: error.status }, cause: error });
78
+ thirdPartyService.save( id );
79
+ } catch ( error ) {
80
+ throw new CannotSave({ context: { id, status: error.status }, cause: error });
81
+ }
82
+ ```
83
+
84
+ ### `ensureError`
85
+ The `ensureError` function is a utility function that ensures that the given value is an error.
86
+ If the value is already an error, it will be returned as is.
87
+ If the value is not an error, it will be wrapped with an `Error` that includes the thrown value.
88
+
89
+ ```ts
90
+ import { ensureError } from '@elementor/utils';
91
+
92
+ const CannotUpdate = createError<{ id: number; }>( 'cannot-update', 'Cannot update document' );
93
+
94
+ try {
95
+ thirdPartyService.update( id );
96
+ } catch ( error ) {
97
+ const errorInstance = ensureError( error );
98
+
99
+ throw new CannotUpdate({ context: { id }, cause: errorInstance });
86
100
  }
87
101
  ```
package/dist/index.d.mts CHANGED
@@ -1,21 +1,21 @@
1
1
  type ElementorErrorOptions = {
2
- cause?: unknown;
2
+ cause?: Error['cause'];
3
3
  context?: Record<string, unknown> | null;
4
4
  code: string;
5
5
  };
6
6
  declare class ElementorError extends Error {
7
7
  readonly context: ElementorErrorOptions['context'];
8
- readonly code: string;
8
+ readonly code: ElementorErrorOptions['code'];
9
9
  constructor(message: string, { code, context, cause }: ElementorErrorOptions);
10
10
  }
11
11
 
12
12
  type CreateErrorParams = {
13
- code: string;
13
+ code: ElementorErrorOptions['code'];
14
14
  message: string;
15
15
  };
16
- declare const createError: <T extends Record<string, unknown>>({ code, message }: CreateErrorParams) => {
17
- new ({ cause, context }: {
18
- cause?: Error;
16
+ declare const createError: <T extends Record<string, unknown> | null | undefined>({ code, message }: CreateErrorParams) => {
17
+ new ({ cause, context }?: {
18
+ cause?: ElementorErrorOptions['cause'];
19
19
  context?: T;
20
20
  }): {
21
21
  readonly context: Record<string, unknown> | null | undefined;
@@ -30,4 +30,6 @@ declare const createError: <T extends Record<string, unknown>>({ code, message }
30
30
  stackTraceLimit: number;
31
31
  };
32
32
 
33
- export { CreateErrorParams, ElementorError, ElementorErrorOptions, createError };
33
+ declare const ensureError: (error: unknown) => Error;
34
+
35
+ export { CreateErrorParams, ElementorError, ElementorErrorOptions, createError, ensureError };
package/dist/index.d.ts CHANGED
@@ -1,21 +1,21 @@
1
1
  type ElementorErrorOptions = {
2
- cause?: unknown;
2
+ cause?: Error['cause'];
3
3
  context?: Record<string, unknown> | null;
4
4
  code: string;
5
5
  };
6
6
  declare class ElementorError extends Error {
7
7
  readonly context: ElementorErrorOptions['context'];
8
- readonly code: string;
8
+ readonly code: ElementorErrorOptions['code'];
9
9
  constructor(message: string, { code, context, cause }: ElementorErrorOptions);
10
10
  }
11
11
 
12
12
  type CreateErrorParams = {
13
- code: string;
13
+ code: ElementorErrorOptions['code'];
14
14
  message: string;
15
15
  };
16
- declare const createError: <T extends Record<string, unknown>>({ code, message }: CreateErrorParams) => {
17
- new ({ cause, context }: {
18
- cause?: Error;
16
+ declare const createError: <T extends Record<string, unknown> | null | undefined>({ code, message }: CreateErrorParams) => {
17
+ new ({ cause, context }?: {
18
+ cause?: ElementorErrorOptions['cause'];
19
19
  context?: T;
20
20
  }): {
21
21
  readonly context: Record<string, unknown> | null | undefined;
@@ -30,4 +30,6 @@ declare const createError: <T extends Record<string, unknown>>({ code, message }
30
30
  stackTraceLimit: number;
31
31
  };
32
32
 
33
- export { CreateErrorParams, ElementorError, ElementorErrorOptions, createError };
33
+ declare const ensureError: (error: unknown) => Error;
34
+
35
+ export { CreateErrorParams, ElementorError, ElementorErrorOptions, createError, ensureError };
package/dist/index.js CHANGED
@@ -21,7 +21,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var src_exports = {};
22
22
  __export(src_exports, {
23
23
  ElementorError: () => ElementorError,
24
- createError: () => createError
24
+ createError: () => createError,
25
+ ensureError: () => ensureError
25
26
  });
26
27
  module.exports = __toCommonJS(src_exports);
27
28
 
@@ -39,14 +40,31 @@ var ElementorError = class extends Error {
39
40
  // src/errors/create-error.ts
40
41
  var createError = ({ code, message }) => {
41
42
  return class extends ElementorError {
42
- constructor({ cause, context }) {
43
+ constructor({ cause, context } = {}) {
43
44
  super(message, { cause, code, context });
44
45
  }
45
46
  };
46
47
  };
48
+
49
+ // src/errors/ensure-error.ts
50
+ var ensureError = (error) => {
51
+ if (error instanceof Error) {
52
+ return error;
53
+ }
54
+ let message;
55
+ let cause = null;
56
+ try {
57
+ message = JSON.stringify(error);
58
+ } catch (e) {
59
+ cause = e;
60
+ message = "Unable to stringify the thrown value";
61
+ }
62
+ return new Error(`Unexpected non-error thrown: ${message}`, { cause });
63
+ };
47
64
  // Annotate the CommonJS export names for ESM import in node:
48
65
  0 && (module.exports = {
49
66
  ElementorError,
50
- createError
67
+ createError,
68
+ ensureError
51
69
  });
52
70
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/errors/elementor-error.ts","../src/errors/create-error.ts"],"sourcesContent":["export { ElementorError, createError } from './errors';\nexport type { ElementorErrorOptions, CreateErrorParams } from './errors';\n","export type ElementorErrorOptions = {\n\tcause?: unknown;\n\tcontext?: Record< string, unknown > | null;\n\tcode: string;\n};\n\nexport class ElementorError extends Error {\n\treadonly context: ElementorErrorOptions[ 'context' ];\n\treadonly code: string;\n\n\tconstructor( message: string, { code, context = null, cause = null }: ElementorErrorOptions ) {\n\t\tsuper( message, { cause } );\n\t\tthis.context = context;\n\t\tthis.code = code;\n\t}\n}\n","import { ElementorError } from './elementor-error';\n\nexport type CreateErrorParams = {\n\tcode: string;\n\tmessage: string;\n};\n\nexport const createError = < T extends Record< string, unknown > >( { code, message }: CreateErrorParams ) => {\n\treturn class extends ElementorError {\n\t\tconstructor( { cause, context }: { cause?: Error; context?: T } ) {\n\t\t\tsuper( message, { cause, code, context } );\n\t\t}\n\t};\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACMO,IAAM,iBAAN,cAA6B,MAAM;AAAA,EAChC;AAAA,EACA;AAAA,EAET,YAAa,SAAiB,EAAE,MAAM,UAAU,MAAM,QAAQ,KAAK,GAA2B;AAC7F,UAAO,SAAS,EAAE,MAAM,CAAE;AAC1B,SAAK,UAAU;AACf,SAAK,OAAO;AAAA,EACb;AACD;;;ACRO,IAAM,cAAc,CAAyC,EAAE,MAAM,QAAQ,MAA0B;AAC7G,SAAO,cAAc,eAAe;AAAA,IACnC,YAAa,EAAE,OAAO,QAAQ,GAAoC;AACjE,YAAO,SAAS,EAAE,OAAO,MAAM,QAAQ,CAAE;AAAA,IAC1C;AAAA,EACD;AACD;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/errors/elementor-error.ts","../src/errors/create-error.ts","../src/errors/ensure-error.ts"],"sourcesContent":["export { ElementorError, createError, ensureError } from './errors';\nexport type { ElementorErrorOptions, CreateErrorParams } from './errors';\n","export type ElementorErrorOptions = {\n\tcause?: Error[ 'cause' ];\n\tcontext?: Record< string, unknown > | null;\n\tcode: string;\n};\n\nexport class ElementorError extends Error {\n\treadonly context: ElementorErrorOptions[ 'context' ];\n\treadonly code: ElementorErrorOptions[ 'code' ];\n\n\tconstructor( message: string, { code, context = null, cause = null }: ElementorErrorOptions ) {\n\t\tsuper( message, { cause } );\n\t\tthis.context = context;\n\t\tthis.code = code;\n\t}\n}\n","import { ElementorError, ElementorErrorOptions } from './elementor-error';\n\nexport type CreateErrorParams = {\n\tcode: ElementorErrorOptions[ 'code' ];\n\tmessage: string;\n};\n\nexport const createError = < T extends ElementorErrorOptions[ 'context' ] >( { code, message }: CreateErrorParams ) => {\n\treturn class extends ElementorError {\n\t\tconstructor( { cause, context }: { cause?: ElementorErrorOptions[ 'cause' ]; context?: T } = {} ) {\n\t\t\tsuper( message, { cause, code, context } );\n\t\t}\n\t};\n};\n","export const ensureError = ( error: unknown ) => {\n\tif ( error instanceof Error ) {\n\t\treturn error;\n\t}\n\n\tlet message: string;\n\tlet cause: unknown = null;\n\n\ttry {\n\t\tmessage = JSON.stringify( error );\n\t} catch ( e ) {\n\t\tcause = e;\n\t\tmessage = 'Unable to stringify the thrown value';\n\t}\n\treturn new Error( `Unexpected non-error thrown: ${ message }`, { cause } );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACMO,IAAM,iBAAN,cAA6B,MAAM;AAAA,EAChC;AAAA,EACA;AAAA,EAET,YAAa,SAAiB,EAAE,MAAM,UAAU,MAAM,QAAQ,KAAK,GAA2B;AAC7F,UAAO,SAAS,EAAE,MAAM,CAAE;AAC1B,SAAK,UAAU;AACf,SAAK,OAAO;AAAA,EACb;AACD;;;ACRO,IAAM,cAAc,CAAkD,EAAE,MAAM,QAAQ,MAA0B;AACtH,SAAO,cAAc,eAAe;AAAA,IACnC,YAAa,EAAE,OAAO,QAAQ,IAA+D,CAAC,GAAI;AACjG,YAAO,SAAS,EAAE,OAAO,MAAM,QAAQ,CAAE;AAAA,IAC1C;AAAA,EACD;AACD;;;ACbO,IAAM,cAAc,CAAE,UAAoB;AAChD,MAAK,iBAAiB,OAAQ;AAC7B,WAAO;AAAA,EACR;AAEA,MAAI;AACJ,MAAI,QAAiB;AAErB,MAAI;AACH,cAAU,KAAK,UAAW,KAAM;AAAA,EACjC,SAAU,GAAI;AACb,YAAQ;AACR,cAAU;AAAA,EACX;AACA,SAAO,IAAI,MAAO,gCAAiC,OAAQ,IAAI,EAAE,MAAM,CAAE;AAC1E;","names":[]}
package/dist/index.mjs CHANGED
@@ -12,13 +12,30 @@ var ElementorError = class extends Error {
12
12
  // src/errors/create-error.ts
13
13
  var createError = ({ code, message }) => {
14
14
  return class extends ElementorError {
15
- constructor({ cause, context }) {
15
+ constructor({ cause, context } = {}) {
16
16
  super(message, { cause, code, context });
17
17
  }
18
18
  };
19
19
  };
20
+
21
+ // src/errors/ensure-error.ts
22
+ var ensureError = (error) => {
23
+ if (error instanceof Error) {
24
+ return error;
25
+ }
26
+ let message;
27
+ let cause = null;
28
+ try {
29
+ message = JSON.stringify(error);
30
+ } catch (e) {
31
+ cause = e;
32
+ message = "Unable to stringify the thrown value";
33
+ }
34
+ return new Error(`Unexpected non-error thrown: ${message}`, { cause });
35
+ };
20
36
  export {
21
37
  ElementorError,
22
- createError
38
+ createError,
39
+ ensureError
23
40
  };
24
41
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors/elementor-error.ts","../src/errors/create-error.ts"],"sourcesContent":["export type ElementorErrorOptions = {\n\tcause?: unknown;\n\tcontext?: Record< string, unknown > | null;\n\tcode: string;\n};\n\nexport class ElementorError extends Error {\n\treadonly context: ElementorErrorOptions[ 'context' ];\n\treadonly code: string;\n\n\tconstructor( message: string, { code, context = null, cause = null }: ElementorErrorOptions ) {\n\t\tsuper( message, { cause } );\n\t\tthis.context = context;\n\t\tthis.code = code;\n\t}\n}\n","import { ElementorError } from './elementor-error';\n\nexport type CreateErrorParams = {\n\tcode: string;\n\tmessage: string;\n};\n\nexport const createError = < T extends Record< string, unknown > >( { code, message }: CreateErrorParams ) => {\n\treturn class extends ElementorError {\n\t\tconstructor( { cause, context }: { cause?: Error; context?: T } ) {\n\t\t\tsuper( message, { cause, code, context } );\n\t\t}\n\t};\n};\n"],"mappings":";AAMO,IAAM,iBAAN,cAA6B,MAAM;AAAA,EAChC;AAAA,EACA;AAAA,EAET,YAAa,SAAiB,EAAE,MAAM,UAAU,MAAM,QAAQ,KAAK,GAA2B;AAC7F,UAAO,SAAS,EAAE,MAAM,CAAE;AAC1B,SAAK,UAAU;AACf,SAAK,OAAO;AAAA,EACb;AACD;;;ACRO,IAAM,cAAc,CAAyC,EAAE,MAAM,QAAQ,MAA0B;AAC7G,SAAO,cAAc,eAAe;AAAA,IACnC,YAAa,EAAE,OAAO,QAAQ,GAAoC;AACjE,YAAO,SAAS,EAAE,OAAO,MAAM,QAAQ,CAAE;AAAA,IAC1C;AAAA,EACD;AACD;","names":[]}
1
+ {"version":3,"sources":["../src/errors/elementor-error.ts","../src/errors/create-error.ts","../src/errors/ensure-error.ts"],"sourcesContent":["export type ElementorErrorOptions = {\n\tcause?: Error[ 'cause' ];\n\tcontext?: Record< string, unknown > | null;\n\tcode: string;\n};\n\nexport class ElementorError extends Error {\n\treadonly context: ElementorErrorOptions[ 'context' ];\n\treadonly code: ElementorErrorOptions[ 'code' ];\n\n\tconstructor( message: string, { code, context = null, cause = null }: ElementorErrorOptions ) {\n\t\tsuper( message, { cause } );\n\t\tthis.context = context;\n\t\tthis.code = code;\n\t}\n}\n","import { ElementorError, ElementorErrorOptions } from './elementor-error';\n\nexport type CreateErrorParams = {\n\tcode: ElementorErrorOptions[ 'code' ];\n\tmessage: string;\n};\n\nexport const createError = < T extends ElementorErrorOptions[ 'context' ] >( { code, message }: CreateErrorParams ) => {\n\treturn class extends ElementorError {\n\t\tconstructor( { cause, context }: { cause?: ElementorErrorOptions[ 'cause' ]; context?: T } = {} ) {\n\t\t\tsuper( message, { cause, code, context } );\n\t\t}\n\t};\n};\n","export const ensureError = ( error: unknown ) => {\n\tif ( error instanceof Error ) {\n\t\treturn error;\n\t}\n\n\tlet message: string;\n\tlet cause: unknown = null;\n\n\ttry {\n\t\tmessage = JSON.stringify( error );\n\t} catch ( e ) {\n\t\tcause = e;\n\t\tmessage = 'Unable to stringify the thrown value';\n\t}\n\treturn new Error( `Unexpected non-error thrown: ${ message }`, { cause } );\n};\n"],"mappings":";AAMO,IAAM,iBAAN,cAA6B,MAAM;AAAA,EAChC;AAAA,EACA;AAAA,EAET,YAAa,SAAiB,EAAE,MAAM,UAAU,MAAM,QAAQ,KAAK,GAA2B;AAC7F,UAAO,SAAS,EAAE,MAAM,CAAE;AAC1B,SAAK,UAAU;AACf,SAAK,OAAO;AAAA,EACb;AACD;;;ACRO,IAAM,cAAc,CAAkD,EAAE,MAAM,QAAQ,MAA0B;AACtH,SAAO,cAAc,eAAe;AAAA,IACnC,YAAa,EAAE,OAAO,QAAQ,IAA+D,CAAC,GAAI;AACjG,YAAO,SAAS,EAAE,OAAO,MAAM,QAAQ,CAAE;AAAA,IAC1C;AAAA,EACD;AACD;;;ACbO,IAAM,cAAc,CAAE,UAAoB;AAChD,MAAK,iBAAiB,OAAQ;AAC7B,WAAO;AAAA,EACR;AAEA,MAAI;AACJ,MAAI,QAAiB;AAErB,MAAI;AACH,cAAU,KAAK,UAAW,KAAM;AAAA,EACjC,SAAU,GAAI;AACb,YAAQ;AACR,cAAU;AAAA,EACX;AACA,SAAO,IAAI,MAAO,gCAAiC,OAAQ,IAAI,EAAE,MAAM,CAAE;AAC1E;","names":[]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@elementor/utils",
3
3
  "description": "This package contains utility functions that are being used across the Elementor packages",
4
- "version": "0.1.0",
4
+ "version": "0.2.0",
5
5
  "private": false,
6
6
  "author": "Elementor Team",
7
7
  "homepage": "https://elementor.com/",
@@ -32,5 +32,5 @@
32
32
  "build": "tsup --config=../../tsup.build.ts",
33
33
  "dev": "tsup --config=../../tsup.dev.ts"
34
34
  },
35
- "gitHead": "b622ed27c9abc265dcd14940b4cf5b5e372db898"
35
+ "gitHead": "c2f7a53e5af66a39640eb0849065d07efd554690"
36
36
  }
@@ -1,5 +1,6 @@
1
1
  import { createError } from '../create-error';
2
2
  import { ElementorError } from '../elementor-error';
3
+ import { ensureError } from '../ensure-error';
3
4
 
4
5
  describe( 'createError', () => {
5
6
  it( 'should return an error class with the correct code and message', () => {
@@ -27,3 +28,43 @@ describe( 'createError', () => {
27
28
  expect( error.cause ).toEqual( new Error( 'internal' ) );
28
29
  } );
29
30
  } );
31
+
32
+ describe( 'ensureError', () => {
33
+ it( 'should return the same error instance when the input is an error', () => {
34
+ // Arrange.
35
+ const TestError = createError( { code: 'test-error', message: 'This is a test error' } );
36
+ const error = new TestError();
37
+
38
+ // Act.
39
+ const result = ensureError( error );
40
+
41
+ // Assert.
42
+ expect( result ).toBe( error );
43
+ } );
44
+
45
+ it( 'should return an error with the stringified input in the error message when the input is not an error', () => {
46
+ // Arrange.
47
+ const errorObject = { message: 'test error' };
48
+ const expectedMessage = JSON.stringify( errorObject );
49
+
50
+ // Act.
51
+ const result = ensureError( errorObject );
52
+
53
+ // Assert.
54
+ expect( result ).toBeInstanceOf( Error );
55
+ expect( result.message ).toContain( expectedMessage );
56
+ } );
57
+
58
+ it( "should return an error when the input can't be stringified", () => {
59
+ // Arrange.
60
+ const errorObject = { circular: {} };
61
+ errorObject.circular = errorObject;
62
+
63
+ // Act.
64
+ const result = ensureError( errorObject );
65
+
66
+ // Assert.
67
+ expect( result ).toBeInstanceOf( Error );
68
+ expect( result.cause ).toBeInstanceOf( TypeError );
69
+ } );
70
+ } );
@@ -1,13 +1,13 @@
1
- import { ElementorError } from './elementor-error';
1
+ import { ElementorError, ElementorErrorOptions } from './elementor-error';
2
2
 
3
3
  export type CreateErrorParams = {
4
- code: string;
4
+ code: ElementorErrorOptions[ 'code' ];
5
5
  message: string;
6
6
  };
7
7
 
8
- export const createError = < T extends Record< string, unknown > >( { code, message }: CreateErrorParams ) => {
8
+ export const createError = < T extends ElementorErrorOptions[ 'context' ] >( { code, message }: CreateErrorParams ) => {
9
9
  return class extends ElementorError {
10
- constructor( { cause, context }: { cause?: Error; context?: T } ) {
10
+ constructor( { cause, context }: { cause?: ElementorErrorOptions[ 'cause' ]; context?: T } = {} ) {
11
11
  super( message, { cause, code, context } );
12
12
  }
13
13
  };
@@ -1,12 +1,12 @@
1
1
  export type ElementorErrorOptions = {
2
- cause?: unknown;
2
+ cause?: Error[ 'cause' ];
3
3
  context?: Record< string, unknown > | null;
4
4
  code: string;
5
5
  };
6
6
 
7
7
  export class ElementorError extends Error {
8
8
  readonly context: ElementorErrorOptions[ 'context' ];
9
- readonly code: string;
9
+ readonly code: ElementorErrorOptions[ 'code' ];
10
10
 
11
11
  constructor( message: string, { code, context = null, cause = null }: ElementorErrorOptions ) {
12
12
  super( message, { cause } );
@@ -0,0 +1,16 @@
1
+ export const ensureError = ( error: unknown ) => {
2
+ if ( error instanceof Error ) {
3
+ return error;
4
+ }
5
+
6
+ let message: string;
7
+ let cause: unknown = null;
8
+
9
+ try {
10
+ message = JSON.stringify( error );
11
+ } catch ( e ) {
12
+ cause = e;
13
+ message = 'Unable to stringify the thrown value';
14
+ }
15
+ return new Error( `Unexpected non-error thrown: ${ message }`, { cause } );
16
+ };
@@ -1,2 +1,3 @@
1
1
  export { ElementorError, type ElementorErrorOptions } from './elementor-error';
2
2
  export { createError, type CreateErrorParams } from './create-error';
3
+ export { ensureError } from './ensure-error';
package/src/index.ts CHANGED
@@ -1,2 +1,2 @@
1
- export { ElementorError, createError } from './errors';
1
+ export { ElementorError, createError, ensureError } from './errors';
2
2
  export type { ElementorErrorOptions, CreateErrorParams } from './errors';