@devp0nt/error0 1.0.0-next.48 → 1.0.0-next.49

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.
Files changed (57) hide show
  1. package/dist/cjs/index.cjs +158 -85
  2. package/dist/cjs/index.cjs.map +1 -1
  3. package/dist/cjs/index.d.cts +44 -16
  4. package/dist/cjs/plugins/cause-serialize.cjs +4 -1
  5. package/dist/cjs/plugins/cause-serialize.cjs.map +1 -1
  6. package/dist/cjs/plugins/cause-serialize.d.cts +3 -1
  7. package/dist/cjs/plugins/expected.cjs +7 -2
  8. package/dist/cjs/plugins/expected.cjs.map +1 -1
  9. package/dist/cjs/plugins/expected.d.cts +3 -1
  10. package/dist/cjs/plugins/message-merge.cjs +5 -2
  11. package/dist/cjs/plugins/message-merge.cjs.map +1 -1
  12. package/dist/cjs/plugins/message-merge.d.cts +4 -1
  13. package/dist/cjs/plugins/meta.cjs +7 -2
  14. package/dist/cjs/plugins/meta.cjs.map +1 -1
  15. package/dist/cjs/plugins/meta.d.cts +3 -1
  16. package/dist/cjs/plugins/stack-merge.cjs +6 -3
  17. package/dist/cjs/plugins/stack-merge.cjs.map +1 -1
  18. package/dist/cjs/plugins/stack-merge.d.cts +4 -1
  19. package/dist/cjs/plugins/tags.cjs +7 -2
  20. package/dist/cjs/plugins/tags.cjs.map +1 -1
  21. package/dist/cjs/plugins/tags.d.cts +3 -1
  22. package/dist/esm/index.d.ts +44 -16
  23. package/dist/esm/index.js +158 -85
  24. package/dist/esm/index.js.map +1 -1
  25. package/dist/esm/plugins/cause-serialize.d.ts +3 -1
  26. package/dist/esm/plugins/cause-serialize.js +4 -1
  27. package/dist/esm/plugins/cause-serialize.js.map +1 -1
  28. package/dist/esm/plugins/expected.d.ts +3 -1
  29. package/dist/esm/plugins/expected.js +7 -2
  30. package/dist/esm/plugins/expected.js.map +1 -1
  31. package/dist/esm/plugins/message-merge.d.ts +4 -1
  32. package/dist/esm/plugins/message-merge.js +5 -2
  33. package/dist/esm/plugins/message-merge.js.map +1 -1
  34. package/dist/esm/plugins/meta.d.ts +3 -1
  35. package/dist/esm/plugins/meta.js +7 -2
  36. package/dist/esm/plugins/meta.js.map +1 -1
  37. package/dist/esm/plugins/stack-merge.d.ts +4 -1
  38. package/dist/esm/plugins/stack-merge.js +6 -3
  39. package/dist/esm/plugins/stack-merge.js.map +1 -1
  40. package/dist/esm/plugins/tags.d.ts +3 -1
  41. package/dist/esm/plugins/tags.js +7 -2
  42. package/dist/esm/plugins/tags.js.map +1 -1
  43. package/package.json +1 -1
  44. package/src/index.test.ts +79 -21
  45. package/src/index.ts +216 -101
  46. package/src/plugins/cause-serialize.test.ts +6 -4
  47. package/src/plugins/cause-serialize.ts +13 -9
  48. package/src/plugins/expected.test.ts +4 -4
  49. package/src/plugins/expected.ts +16 -10
  50. package/src/plugins/message-merge.test.ts +3 -3
  51. package/src/plugins/message-merge.ts +17 -13
  52. package/src/plugins/meta.test.ts +2 -2
  53. package/src/plugins/meta.ts +28 -22
  54. package/src/plugins/stack-merge.test.ts +4 -4
  55. package/src/plugins/stack-merge.ts +18 -14
  56. package/src/plugins/tags.test.ts +2 -2
  57. package/src/plugins/tags.ts +24 -18
@@ -99,45 +99,87 @@ class PluginError0 {
99
99
  });
100
100
  }
101
101
  }
102
+ const OWN_SYMBOL = Symbol("Error0.own");
102
103
  class Error0 extends Error {
103
104
  static __pluginsMap;
104
105
  __pluginsMap;
106
+ static MAX_CAUSES_DEPTH = 99;
105
107
  static _plugins = [];
108
+ static _resolvedPlugin;
106
109
  static _emptyPlugin = {
107
110
  props: {},
108
111
  methods: {},
109
112
  adapt: [],
110
113
  stack: void 0,
111
114
  cause: void 0,
112
- message: void 0
115
+ message: void 0,
116
+ propKeys: [],
117
+ propEntries: [],
118
+ methodEntries: []
113
119
  };
120
+ static _indexResolvedPlugin(resolved) {
121
+ return {
122
+ ...resolved,
123
+ propKeys: Object.keys(resolved.props),
124
+ propEntries: Object.entries(resolved.props),
125
+ methodEntries: Object.entries(resolved.methods)
126
+ };
127
+ }
128
+ static _applyPlugin(resolved, plugin) {
129
+ if (plugin.props && "stack" in plugin.props) {
130
+ throw new Error(RESERVED_STACK_PROP_ERROR);
131
+ }
132
+ if (plugin.props && "message" in plugin.props) {
133
+ throw new Error(RESERVED_MESSAGE_PROP_ERROR);
134
+ }
135
+ Object.assign(resolved.props, plugin.props ?? this._emptyPlugin.props);
136
+ Object.assign(resolved.methods, plugin.methods ?? this._emptyPlugin.methods);
137
+ resolved.adapt.push(...plugin.adapt ?? this._emptyPlugin.adapt);
138
+ if (typeof plugin.stack !== "undefined") {
139
+ resolved.stack = plugin.stack;
140
+ }
141
+ if (typeof plugin.cause !== "undefined") {
142
+ resolved.cause = plugin.cause;
143
+ }
144
+ if (typeof plugin.message !== "undefined") {
145
+ resolved.message = plugin.message;
146
+ }
147
+ }
148
+ static _mergeResolvedPlugin(base, plugin) {
149
+ const merged = {
150
+ props: { ...base.props },
151
+ methods: { ...base.methods },
152
+ adapt: [...base.adapt],
153
+ stack: base.stack,
154
+ cause: base.cause,
155
+ message: base.message
156
+ };
157
+ this._applyPlugin(merged, plugin);
158
+ return this._indexResolvedPlugin(merged);
159
+ }
114
160
  static _getResolvedPlugin() {
161
+ if (Object.prototype.hasOwnProperty.call(this, "_resolvedPlugin") && this._resolvedPlugin) {
162
+ return this._resolvedPlugin;
163
+ }
115
164
  const resolved = {
116
165
  props: {},
117
166
  methods: {},
118
- adapt: []
167
+ adapt: [],
168
+ propKeys: [],
169
+ propEntries: [],
170
+ methodEntries: []
119
171
  };
120
172
  for (const plugin of this._plugins) {
121
- if (plugin.props && "stack" in plugin.props) {
122
- throw new Error(RESERVED_STACK_PROP_ERROR);
123
- }
124
- if (plugin.props && "message" in plugin.props) {
125
- throw new Error(RESERVED_MESSAGE_PROP_ERROR);
126
- }
127
- Object.assign(resolved.props, plugin.props ?? this._emptyPlugin.props);
128
- Object.assign(resolved.methods, plugin.methods ?? this._emptyPlugin.methods);
129
- resolved.adapt.push(...plugin.adapt ?? this._emptyPlugin.adapt);
130
- if (typeof plugin.stack !== "undefined") {
131
- resolved.stack = plugin.stack;
132
- }
133
- if (typeof plugin.cause !== "undefined") {
134
- resolved.cause = plugin.cause;
135
- }
136
- if (typeof plugin.message !== "undefined") {
137
- resolved.message = plugin.message;
138
- }
173
+ this._applyPlugin(resolved, plugin);
139
174
  }
140
- return resolved;
175
+ const indexed = this._indexResolvedPlugin(resolved);
176
+ Object.defineProperty(this, "_resolvedPlugin", {
177
+ value: indexed,
178
+ writable: true,
179
+ enumerable: false,
180
+ configurable: true
181
+ });
182
+ return indexed;
141
183
  }
142
184
  constructor(...args) {
143
185
  const [first, second] = args;
@@ -146,37 +188,43 @@ class Error0 extends Error {
146
188
  this.name = "Error0";
147
189
  const ctor = this.constructor;
148
190
  const plugin = ctor._getResolvedPlugin();
149
- for (const [key, prop] of Object.entries(plugin.props)) {
191
+ const ownStore = /* @__PURE__ */ Object.create(null);
192
+ Object.defineProperty(this, OWN_SYMBOL, { value: ownStore, writable: true, enumerable: false, configurable: true });
193
+ for (const [key, prop] of plugin.propEntries) {
150
194
  if (key === "stack") {
151
195
  continue;
152
196
  }
197
+ Object.defineProperty(this, key, {
198
+ get: () => prop.resolve({
199
+ own: ownStore[key],
200
+ flow: this.flow(key),
201
+ error: this
202
+ }),
203
+ set: (value) => {
204
+ ownStore[key] = value;
205
+ },
206
+ enumerable: true,
207
+ configurable: true
208
+ });
153
209
  if (key in input) {
154
210
  const ownValue = input[key];
155
- if (typeof prop.init === "function") {
156
- ;
157
- this[key] = prop.init(ownValue);
158
- } else {
159
- ;
160
- this[key] = ownValue;
161
- }
162
- } else {
163
- Object.defineProperty(this, key, {
164
- get: () => prop.resolve({ own: void 0, flow: this.flow(key), error: this }),
165
- set: (value) => {
166
- Object.defineProperty(this, key, {
167
- value,
168
- writable: true,
169
- enumerable: true,
170
- configurable: true
171
- });
172
- },
173
- enumerable: true,
174
- configurable: true
175
- });
211
+ ownStore[key] = typeof prop.init === "function" ? prop.init(ownValue) : ownValue;
176
212
  }
177
213
  }
178
214
  }
179
- static isSelfProperty = (object, key) => {
215
+ static _getOwnStore(object) {
216
+ const record = object;
217
+ const existing = record[OWN_SYMBOL];
218
+ if (existing && typeof existing === "object") {
219
+ return existing;
220
+ }
221
+ return void 0;
222
+ }
223
+ static isOwnProperty = (object, key) => {
224
+ const ownStore = this._getOwnStore(object);
225
+ if (ownStore && Object.prototype.hasOwnProperty.call(ownStore, key)) {
226
+ return true;
227
+ }
180
228
  const d = Object.getOwnPropertyDescriptor(object, key);
181
229
  if (!d) return false;
182
230
  if (typeof d.get === "function" || typeof d.set === "function") {
@@ -189,22 +237,29 @@ class Error0 extends Error {
189
237
  return true;
190
238
  };
191
239
  static _ownByKey(error, key) {
192
- if (this.isSelfProperty(error, key)) {
240
+ const ownStore = this._getOwnStore(error);
241
+ if (ownStore && Object.prototype.hasOwnProperty.call(ownStore, key)) {
242
+ return ownStore[key];
243
+ }
244
+ if (this.isOwnProperty(error, key)) {
193
245
  return error[key];
194
246
  }
195
247
  return void 0;
196
248
  }
197
249
  static _flowByKey(error, key) {
198
- return this.causes(error, true).map((cause) => {
199
- return this._ownByKey(cause, key);
200
- });
250
+ const causes = this.causes(error, true);
251
+ const values = new Array(causes.length);
252
+ for (let i = 0; i < causes.length; i += 1) {
253
+ values[i] = this._ownByKey(causes[i], key);
254
+ }
255
+ return values;
201
256
  }
202
257
  static own(error, key) {
203
258
  const error0 = this.from(error);
204
259
  if (key === void 0) {
205
260
  const ownValues = {};
206
261
  const plugin = this._getResolvedPlugin();
207
- for (const ownKey of Object.keys(plugin.props)) {
262
+ for (const ownKey of plugin.propKeys) {
208
263
  ownValues[ownKey] = this._ownByKey(error0, ownKey);
209
264
  }
210
265
  return ownValues;
@@ -226,29 +281,34 @@ class Error0 extends Error {
226
281
  const ctor = this.constructor;
227
282
  return ctor._flowByKey(this, key);
228
283
  }
284
+ static _resolveByKey(error, key, plugin) {
285
+ try {
286
+ const options = {
287
+ get own() {
288
+ return error.own(key);
289
+ },
290
+ get flow() {
291
+ return error.flow(key);
292
+ },
293
+ error
294
+ };
295
+ const prop = plugin.props[key];
296
+ const resolver = prop.resolve;
297
+ if (!resolver) {
298
+ return error[key];
299
+ }
300
+ return resolver(options);
301
+ } catch {
302
+ console.error(`Error0: failed to resolve property ${key}`, error);
303
+ return void 0;
304
+ }
305
+ }
229
306
  static resolve(error) {
230
307
  const error0 = this.from(error);
231
308
  const resolved = {};
232
309
  const plugin = this._getResolvedPlugin();
233
- for (const [key, prop] of Object.entries(plugin.props)) {
234
- try {
235
- const options = Object.defineProperties(
236
- {
237
- error: error0
238
- },
239
- {
240
- own: {
241
- get: () => error0.own(key)
242
- },
243
- flow: {
244
- get: () => error0.flow(key)
245
- }
246
- }
247
- );
248
- resolved[key] = prop.resolve(options);
249
- } catch {
250
- console.error(`Error0: failed to resolve property ${key}`, error0);
251
- }
310
+ for (const key of plugin.propKeys) {
311
+ resolved[key] = this._resolveByKey(error0, key, plugin);
252
312
  }
253
313
  return resolved;
254
314
  }
@@ -259,9 +319,9 @@ class Error0 extends Error {
259
319
  static causes(error, instancesOnly) {
260
320
  const causes = [];
261
321
  let current = error;
262
- const maxDepth = 99;
263
322
  const seen = /* @__PURE__ */ new Set();
264
- for (let depth = 0; depth < maxDepth; depth += 1) {
323
+ let depth = 0;
324
+ while (depth < this.MAX_CAUSES_DEPTH) {
265
325
  if (seen.has(current)) {
266
326
  break;
267
327
  }
@@ -273,6 +333,7 @@ class Error0 extends Error {
273
333
  break;
274
334
  }
275
335
  current = current.cause;
336
+ depth += 1;
276
337
  }
277
338
  return causes;
278
339
  }
@@ -319,8 +380,7 @@ class Error0 extends Error {
319
380
  const errorRecord = error;
320
381
  const recreated = new this(message);
321
382
  const plugin = this._getResolvedPlugin();
322
- const propsEntries = Object.entries(plugin.props);
323
- for (const [key, prop] of propsEntries) {
383
+ for (const [key, prop] of plugin.propEntries) {
324
384
  if (prop.deserialize === false) {
325
385
  continue;
326
386
  }
@@ -328,7 +388,7 @@ class Error0 extends Error {
328
388
  continue;
329
389
  }
330
390
  try {
331
- const value = prop.deserialize({ value: errorRecord[key], serialized: errorRecord });
391
+ const value = prop.deserialize({ value: errorRecord[key], record: errorRecord });
332
392
  recreated[key] = value;
333
393
  } catch {
334
394
  console.error(`Error0: failed to deserialize property ${key}`, errorRecord);
@@ -371,8 +431,9 @@ class Error0 extends Error {
371
431
  const Error0Extended = class Error0 extends Base {
372
432
  };
373
433
  Error0Extended._plugins = [...Base._plugins, plugin];
374
- const resolved = Error0Extended._getResolvedPlugin();
375
- for (const [key, method] of Object.entries(resolved.methods)) {
434
+ const resolved = this._mergeResolvedPlugin(Base._getResolvedPlugin(), plugin);
435
+ Error0Extended._resolvedPlugin = resolved;
436
+ for (const [key, method] of resolved.methodEntries) {
376
437
  Object.defineProperty(Error0Extended.prototype, key, {
377
438
  value: function(...args) {
378
439
  return method(this, ...args);
@@ -471,9 +532,8 @@ class Error0 extends Error {
471
532
  }
472
533
  static serialize(error, isPublic = true) {
473
534
  const error0 = this.from(error);
474
- const resolvedProps = this.resolve(error0);
475
- const resolvedRecord = resolvedProps;
476
535
  const plugin = this._getResolvedPlugin();
536
+ const resolveByKey = (targetError, key, targetPlugin) => this._resolveByKey(targetError, key, targetPlugin);
477
537
  const messagePlugin = plugin.message;
478
538
  let serializedMessage = error0.message;
479
539
  try {
@@ -485,24 +545,37 @@ class Error0 extends Error {
485
545
  serializedMessage = error0.message;
486
546
  }
487
547
  const json = {
488
- name: error0.name,
489
- message: serializedMessage
548
+ name: error0.name
490
549
  // we do not serialize causes, it is enough that we have floated props and adapt helper
491
550
  // cause: error0.cause,
492
551
  };
493
- const propsEntries = Object.entries(plugin.props);
494
- for (const [key, prop] of propsEntries) {
552
+ if (serializedMessage !== void 0) {
553
+ json.message = serializedMessage;
554
+ }
555
+ for (const [key, prop] of plugin.propEntries) {
495
556
  if (prop.serialize === false) {
496
557
  continue;
497
558
  }
498
559
  try {
499
- const value = resolvedRecord[key];
500
- const jsonValue = prop.serialize({ value, error: error0, isPublic });
560
+ const options = {
561
+ get own() {
562
+ return error0.own(key);
563
+ },
564
+ get flow() {
565
+ return error0.flow(key);
566
+ },
567
+ get resolved() {
568
+ return resolveByKey(error0, key, plugin);
569
+ },
570
+ error: error0,
571
+ isPublic
572
+ };
573
+ const jsonValue = prop.serialize(options);
501
574
  if (jsonValue !== void 0) {
502
575
  json[key] = jsonValue;
503
576
  }
504
577
  } catch {
505
- console.error(`Error0: failed to serialize property ${key}`, resolvedRecord);
578
+ console.error(`Error0: failed to serialize property ${key}`, error0);
506
579
  }
507
580
  }
508
581
  const stackPlugin = plugin.stack;
@@ -534,7 +607,7 @@ class Error0 extends Error {
534
607
  console.error("Error0: failed to serialize cause", error0);
535
608
  }
536
609
  }
537
- return Object.fromEntries(Object.entries(json).filter(([, value]) => value !== void 0));
610
+ return json;
538
611
  }
539
612
  serialize(isPublic = true) {
540
613
  const ctor = this.constructor;