@devp0nt/error0 1.0.0-next.53 → 1.0.0-next.55

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/src/index.ts CHANGED
@@ -54,7 +54,7 @@ type ErrorPluginPropOptionsWithoutInit<
54
54
  > = ErrorPluginPropOptionsBase<TOutputValue, TError, TResolveValue> & {
55
55
  init?: undefined
56
56
  }
57
- export type ErrorPluginPropOptions<
57
+ type ErrorPluginPropOptions<
58
58
  TInputValue = undefined,
59
59
  TOutputValue = unknown,
60
60
  TError extends Error0 = Error0,
@@ -62,49 +62,83 @@ export type ErrorPluginPropOptions<
62
62
  > =
63
63
  | ErrorPluginPropOptionsWithInit<TInputValue, TOutputValue, TError, TResolveValue>
64
64
  | ErrorPluginPropOptionsWithoutInit<TOutputValue, TError, TResolveValue>
65
- export type ErrorPluginMethodFn<TOutputValue, TArgs extends unknown[] = unknown[], TError extends Error0 = Error0> = (
65
+
66
+ type ErrorPluginPropOptionsBaseDefinition<
67
+ TOutputValue,
68
+ TError extends Error0,
69
+ TResolveValue extends TOutputValue | undefined,
70
+ > = {
71
+ resolve?: ((options: ErrorPluginPropOptionsResolveOptions<TOutputValue, TError>) => TResolveValue) | boolean
72
+ serialize?: ErrorPluginPropSerialize<TOutputValue, TError, TResolveValue>
73
+ deserialize?: ErrorPluginPropDeserialize<TOutputValue>
74
+ }
75
+ type ErrorPluginPropOptionsWithInitDefinition<
76
+ TInputValue,
77
+ TOutputValue,
78
+ TError extends Error0,
79
+ TResolveValue extends TOutputValue | undefined,
80
+ > = ErrorPluginPropOptionsBaseDefinition<TOutputValue, TError, TResolveValue> & {
81
+ init: ErrorPluginPropInit<TInputValue, TOutputValue>
82
+ }
83
+ type ErrorPluginPropOptionsWithoutInitDefinition<
84
+ TOutputValue,
85
+ TError extends Error0,
86
+ TResolveValue extends TOutputValue | undefined,
87
+ > = ErrorPluginPropOptionsBaseDefinition<TOutputValue, TError, TResolveValue> & {
88
+ init?: undefined
89
+ }
90
+ type ErrorPluginPropOptionsDefinition<
91
+ TInputValue = undefined,
92
+ TOutputValue = unknown,
93
+ TError extends Error0 = Error0,
94
+ TResolveValue extends TOutputValue | undefined = TOutputValue | undefined,
95
+ > =
96
+ | ErrorPluginPropOptionsWithInitDefinition<TInputValue, TOutputValue, TError, TResolveValue>
97
+ | ErrorPluginPropOptionsWithoutInitDefinition<TOutputValue, TError, TResolveValue>
98
+
99
+ type ErrorPluginMethodFn<TOutputValue, TArgs extends unknown[] = unknown[], TError extends Error0 = Error0> = (
66
100
  error: TError,
67
101
  ...args: TArgs
68
102
  ) => TOutputValue
69
103
  type ErrorPluginAnyMethodFn = (error: any, ...args: any[]) => any
70
- export type ErrorPluginAdaptResult<TOutputProps extends Record<string, unknown>> = Partial<TOutputProps> | undefined
71
- export type ErrorPluginAdaptFn<
104
+ type ErrorPluginAdaptResult<TOutputProps extends Record<string, unknown>> = Partial<TOutputProps> | undefined
105
+ type ErrorPluginAdaptFn<
72
106
  TError extends Error0 = Error0,
73
107
  TOutputProps extends Record<string, unknown> = Record<never, never>,
74
108
  > = ((error: TError) => void) | ((error: TError) => ErrorPluginAdaptResult<TOutputProps>)
75
- export type ErrorPluginStackSerialize<TError extends Error0> = (options: {
109
+ type ErrorPluginStackSerialize<TError extends Error0> = (options: {
76
110
  value: string | undefined
77
111
  error: TError
78
112
  isPublic: boolean
79
113
  }) => unknown
80
- export type ErrorPluginStack<TError extends Error0 = Error0> = { serialize: ErrorPluginStackSerialize<TError> }
81
- export type ErrorPluginCauseSerialize<TError extends Error0> = (options: {
114
+ type ErrorPluginStack<TError extends Error0 = Error0> = { serialize: ErrorPluginStackSerialize<TError> }
115
+ type ErrorPluginCauseSerialize<TError extends Error0> = (options: {
82
116
  cause: unknown
83
117
  error: TError
84
118
  isPublic: boolean
85
119
  is: (cause: unknown) => boolean
86
120
  serialize: (cause: unknown) => Record<string, unknown>
87
121
  }) => unknown
88
- export type ErrorPluginCauseDeserialize = (options: {
122
+ type ErrorPluginCauseDeserialize = (options: {
89
123
  cause: unknown
90
124
  error: Record<string, unknown>
91
125
  isSerialized: (serializedCause: unknown) => boolean
92
126
  fromSerialized: (serializedCause: unknown) => Error0
93
127
  }) => unknown
94
- export type ErrorPluginCause<TError extends Error0 = Error0> = {
128
+ type ErrorPluginCause<TError extends Error0 = Error0> = {
95
129
  serialize: ErrorPluginCauseSerialize<TError>
96
130
  deserialize: ErrorPluginCauseDeserialize
97
131
  }
98
- export type ErrorPluginMessageSerialize<TError extends Error0> = (options: {
132
+ type ErrorPluginMessageSerialize<TError extends Error0> = (options: {
99
133
  value: string
100
134
  error: TError
101
135
  isPublic: boolean
102
136
  }) => unknown
103
- export type ErrorPluginMessage<TError extends Error0 = Error0> = { serialize: ErrorPluginMessageSerialize<TError> }
137
+ type ErrorPluginMessage<TError extends Error0 = Error0> = { serialize: ErrorPluginMessageSerialize<TError> }
104
138
  type ErrorMethodRecord = { fn: ErrorPluginAnyMethodFn }
105
139
 
106
- export type ErrorPluginProps = { [key: string]: ErrorPluginPropOptions<any, any> }
107
- export type ErrorPluginMethods = { [key: string]: ErrorPluginAnyMethodFn }
140
+ type ErrorPluginProps = { [key: string]: ErrorPluginPropOptions<any, any> }
141
+ type ErrorPluginMethods = { [key: string]: ErrorPluginAnyMethodFn }
108
142
 
109
143
  export type ErrorPlugin<
110
144
  TProps extends ErrorPluginProps = Record<never, never>,
@@ -134,12 +168,12 @@ type PluginOutputProps<TProps extends ErrorPluginProps> = {
134
168
  ? TResolveValue
135
169
  : never
136
170
  }
137
- export type ErrorPluginsMap = {
171
+ type ErrorPluginsMap = {
138
172
  props: Record<string, { init: unknown; output: unknown; resolve: unknown }>
139
173
  methods: Record<string, ErrorMethodRecord>
140
174
  }
141
- export type IsEmptyObject<T> = keyof T extends never ? true : false
142
- export type ErrorInputBase = {
175
+ type IsEmptyObject<T> = keyof T extends never ? true : false
176
+ type ErrorInputBase = {
143
177
  cause?: unknown
144
178
  }
145
179
  type ErrorInputPluginProps<TPluginsMap extends ErrorPluginsMap> = {
@@ -147,7 +181,7 @@ type ErrorInputPluginProps<TPluginsMap extends ErrorPluginsMap> = {
147
181
  ? never
148
182
  : TKey]?: TPluginsMap['props'][TKey]['init']
149
183
  }
150
- export type ErrorInput<TPluginsMap extends ErrorPluginsMap> =
184
+ type ErrorInput<TPluginsMap extends ErrorPluginsMap> =
151
185
  IsEmptyObject<TPluginsMap['props']> extends true
152
186
  ? ErrorInputBase
153
187
  : ErrorInputBase & ErrorInputPluginProps<TPluginsMap>
@@ -158,16 +192,19 @@ type ErrorResolvedProps<TPluginsMap extends ErrorPluginsMap> = {
158
192
  type ErrorOwnProps<TPluginsMap extends ErrorPluginsMap> = {
159
193
  [TKey in keyof TPluginsMap['props']]: TPluginsMap['props'][TKey]['output'] | undefined
160
194
  }
161
- type ErrorOwnMethods<TPluginsMap extends ErrorPluginsMap> = {
162
- own: {
163
- (): ErrorOwnProps<TPluginsMap>
164
- <TKey extends keyof TPluginsMap['props'] & string>(key: TKey): ErrorOwnProps<TPluginsMap>[TKey]
165
- }
166
- flow: <TKey extends keyof TPluginsMap['props'] & string>(key: TKey) => Array<ErrorOwnProps<TPluginsMap>[TKey]>
167
- }
168
195
  type ErrorResolveMethods<TPluginsMap extends ErrorPluginsMap> = {
169
196
  resolve: () => ErrorResolvedProps<TPluginsMap>
170
197
  }
198
+ type Error0ResolvedInstance<TPluginsMap extends ErrorPluginsMap> = Error0 &
199
+ ErrorResolved<TPluginsMap> &
200
+ ErrorResolveMethods<TPluginsMap>
201
+ type ErrorOwnMethods<TPluginsMap extends ErrorPluginsMap> = {
202
+ own?: Partial<ErrorOwnProps<TPluginsMap>>
203
+ flow: <TKey extends keyof TPluginsMap['props'] & string>(key: TKey) => Array<ErrorOwnProps<TPluginsMap>[TKey]>
204
+ assign: (props: Partial<ErrorOwnProps<TPluginsMap>>) => Error0ResolvedInstance<TPluginsMap>
205
+ }
206
+ export type InstanceError0<TPluginsMap extends ErrorPluginsMap> = Error0ResolvedInstance<TPluginsMap> &
207
+ ErrorOwnMethods<TPluginsMap> & { readonly __pluginsMap?: TPluginsMap }
171
208
  // type BindInstanceMethod<TMethod> = TMethod extends {
172
209
  // (error: any, ...args: infer TArgs1): infer TOutput1
173
210
  // (error: any, ...args: infer TArgs2): infer TOutput2
@@ -243,8 +280,7 @@ type BindStaticMethod<TMethod> = TMethod extends (error: any, ...args: infer TAr
243
280
  type ErrorMethods<TPluginsMap extends ErrorPluginsMap> = {
244
281
  [TKey in keyof TPluginsMap['methods']]: BindInstanceMethod<TPluginsMap['methods'][TKey]['fn']>
245
282
  }
246
- export type ErrorResolved<TPluginsMap extends ErrorPluginsMap> = ErrorResolvedProps<TPluginsMap> &
247
- ErrorMethods<TPluginsMap>
283
+ type ErrorResolved<TPluginsMap extends ErrorPluginsMap> = ErrorResolvedProps<TPluginsMap> & ErrorMethods<TPluginsMap>
248
284
 
249
285
  type ErrorStaticMethods<TPluginsMap extends ErrorPluginsMap> = {
250
286
  [TKey in keyof TPluginsMap['methods']]: BindStaticMethod<TPluginsMap['methods'][TKey]['fn']>
@@ -269,6 +305,29 @@ type ErrorPluginResolved = {
269
305
  const RESERVED_STACK_PROP_ERROR = 'Error0: "stack" is a reserved prop key. Use .stack(...) plugin API instead'
270
306
  const RESERVED_MESSAGE_PROP_ERROR = 'Error0: "message" is a reserved prop key. Use .message(...) plugin API instead'
271
307
 
308
+ const fromPropOptionsDefinition = (
309
+ options: ErrorPluginPropOptionsDefinition<any, any, any, any>,
310
+ ): ErrorPluginPropOptions<any, any, any, any> => {
311
+ let resolver: ErrorPluginPropOptions<unknown>['resolve']
312
+ if (!options.resolve) {
313
+ resolver = (options: ErrorPluginPropOptionsResolveOptions<any, any>) => options.own
314
+ } else if (options.resolve === true) {
315
+ resolver = (options: ErrorPluginPropOptionsResolveOptions<any, any>) => options.flow.find((v) => v !== undefined)
316
+ } else if (typeof options.resolve === 'function') {
317
+ resolver = options.resolve
318
+ } else {
319
+ throw new Error('Invalid resolve option')
320
+ }
321
+ const serializer: ErrorPluginPropOptions<unknown>['serialize'] = options.serialize ?? false
322
+ const deserializer: ErrorPluginPropOptions<unknown>['deserialize'] = options.deserialize ?? false
323
+ return {
324
+ ...options,
325
+ resolve: resolver,
326
+ serialize: serializer,
327
+ deserialize: deserializer,
328
+ }
329
+ }
330
+
272
331
  type PluginPropsMapOf<TPlugin extends ErrorPlugin> = {
273
332
  [TKey in keyof NonNullable<TPlugin['props']>]: NonNullable<TPlugin['props']>[TKey] extends ErrorPluginPropOptions<
274
333
  any,
@@ -329,16 +388,10 @@ type PluginsMapFromParts<
329
388
  TProps extends ErrorPluginProps,
330
389
  TMethods extends ErrorPluginMethods,
331
390
  > = ErrorPluginsMapOfPlugin<ErrorPlugin<TProps, TMethods>>
332
- type ErrorInstanceOfMap<TMap extends ErrorPluginsMap> = Error0 &
333
- ErrorResolved<TMap> &
334
- ErrorOwnMethods<TMap> &
335
- ErrorResolveMethods<TMap> & { readonly __pluginsMap?: TMap }
336
- type BuilderError0<TProps extends ErrorPluginProps, TMethods extends ErrorPluginMethods> = Error0 &
337
- ErrorResolved<PluginsMapFromParts<TProps, TMethods>> &
338
- ErrorOwnMethods<PluginsMapFromParts<TProps, TMethods>> &
339
- ErrorResolveMethods<PluginsMapFromParts<TProps, TMethods>> & {
340
- readonly __pluginsMap?: PluginsMapFromParts<TProps, TMethods>
341
- }
391
+ type ErrorInstanceOfMap<TMap extends ErrorPluginsMap> = InstanceError0<TMap>
392
+ type BuilderError0<TProps extends ErrorPluginProps, TMethods extends ErrorPluginMethods> = InstanceError0<
393
+ PluginsMapFromParts<TProps, TMethods>
394
+ >
342
395
 
343
396
  type PluginOfBuilder<TBuilder> =
344
397
  TBuilder extends PluginError0<infer TProps, infer TMethods> ? ErrorPlugin<TProps, TMethods> : never
@@ -372,7 +425,7 @@ export class PluginError0<
372
425
  TResolveValue extends TOutputValue | undefined = TOutputValue | undefined,
373
426
  >(
374
427
  key: TKey,
375
- value: ErrorPluginPropOptions<TInputValue, TOutputValue, BuilderError0<TProps, TMethods>, TResolveValue>,
428
+ value: ErrorPluginPropOptionsDefinition<TInputValue, TOutputValue, BuilderError0<TProps, TMethods>, TResolveValue>,
376
429
  ): PluginError0<AddPropToPluginProps<TProps, TKey, TInputValue, TOutputValue, TResolveValue>, TMethods> {
377
430
  return this.use('prop', key, value)
378
431
  }
@@ -410,7 +463,7 @@ export class PluginError0<
410
463
  >(
411
464
  kind: 'prop',
412
465
  key: TKey,
413
- value: ErrorPluginPropOptions<TInputValue, TOutputValue, BuilderError0<TProps, TMethods>, TResolveValue>,
466
+ value: ErrorPluginPropOptionsDefinition<TInputValue, TOutputValue, BuilderError0<TProps, TMethods>, TResolveValue>,
414
467
  ): PluginError0<AddPropToPluginProps<TProps, TKey, TInputValue, TOutputValue, TResolveValue>, TMethods>
415
468
  use<TKey extends string, TMethod extends (error: BuilderError0<TProps, TMethods>, ...args: any[]) => any>(
416
469
  kind: 'method',
@@ -427,7 +480,7 @@ export class PluginError0<
427
480
  use(
428
481
  kind: 'prop' | 'method' | 'adapt' | 'stack' | 'cause' | 'message',
429
482
  keyOrValue: unknown,
430
- value?: ErrorPluginPropOptions<unknown, unknown, any> | ErrorPluginMethodFn<unknown, unknown[], any>,
483
+ value?: ErrorPluginPropOptionsDefinition<unknown, unknown, any> | ErrorPluginMethodFn<unknown, unknown[], any>,
431
484
  ): PluginError0<any, any> {
432
485
  const nextProps: ErrorPluginProps = { ...(this._plugin.props ?? {}) }
433
486
  const nextMethods: ErrorPluginMethods = { ...(this._plugin.methods ?? {}) }
@@ -446,7 +499,7 @@ export class PluginError0<
446
499
  if (value === undefined) {
447
500
  throw new Error('PluginError0.use("prop", key, value) requires value')
448
501
  }
449
- nextProps[key] = value as ErrorPluginPropOptions<any, any>
502
+ nextProps[key] = fromPropOptionsDefinition(value as ErrorPluginPropOptionsDefinition<any, any>)
450
503
  } else if (kind === 'method') {
451
504
  const key = keyOrValue as string
452
505
  if (value === undefined) {
@@ -473,41 +526,27 @@ export class PluginError0<
473
526
  }
474
527
  }
475
528
 
476
- const OWN_SYMBOL: unique symbol = Symbol('Error0.own')
477
529
  type ErrorOwnStore = Record<string, unknown>
478
530
 
479
531
  export type ClassError0<TPluginsMap extends ErrorPluginsMap = EmptyPluginsMap> = {
480
532
  MAX_CAUSES_DEPTH: number
481
- new (
482
- message: string,
483
- input?: ErrorInput<TPluginsMap>,
484
- ): Error0 &
485
- ErrorResolved<TPluginsMap> &
486
- ErrorOwnMethods<TPluginsMap> &
487
- ErrorResolveMethods<TPluginsMap> & { readonly __pluginsMap?: TPluginsMap }
488
- new (
489
- input: { message: string } & ErrorInput<TPluginsMap>,
490
- ): Error0 &
491
- ErrorResolved<TPluginsMap> &
492
- ErrorOwnMethods<TPluginsMap> &
493
- ErrorResolveMethods<TPluginsMap> & { readonly __pluginsMap?: TPluginsMap }
533
+ new (message: string, input?: ErrorInput<TPluginsMap>): InstanceError0<TPluginsMap>
534
+ new (input: { message: string } & ErrorInput<TPluginsMap>): InstanceError0<TPluginsMap>
494
535
  readonly __pluginsMap?: TPluginsMap
495
- from: (
496
- error: unknown,
497
- ) => Error0 & ErrorResolved<TPluginsMap> & ErrorOwnMethods<TPluginsMap> & ErrorResolveMethods<TPluginsMap>
498
- round: (
499
- error: unknown,
500
- isPublic?: boolean,
501
- ) => Error0 & ErrorResolved<TPluginsMap> & ErrorOwnMethods<TPluginsMap> & ErrorResolveMethods<TPluginsMap>
536
+ from: <TThis extends ClassError0<any>>(this: TThis, error: unknown) => InstanceType<TThis>
537
+ round: <TThis extends ClassError0<any>>(this: TThis, error: unknown, isPublic?: boolean) => InstanceType<TThis>
538
+ // flat: <TThis extends ClassError0<any>>(this: TThis, error: unknown, keepCauses?: boolean) => InstanceType<TThis>
502
539
  causes: {
503
540
  (error: unknown, instancesOnly?: false): unknown[]
504
- (
505
- error: unknown,
506
- instancesOnly: true,
507
- ): Array<Error0 & ErrorResolved<TPluginsMap> & ErrorOwnMethods<TPluginsMap> & ErrorResolveMethods<TPluginsMap>>
541
+ (error: unknown, instancesOnly: true): Array<InstanceError0<TPluginsMap>>
508
542
  }
509
543
  resolve: (error: unknown) => ErrorResolvedProps<TPluginsMap>
510
544
  serialize: (error: unknown, isPublic?: boolean) => Record<string, unknown>
545
+ assign: <TThis extends ClassError0<any>>(
546
+ this: TThis,
547
+ error: unknown,
548
+ props: Partial<ErrorOwnProps<PluginsMapOf<TThis>>>,
549
+ ) => InstanceError0<PluginsMapOf<TThis>>
511
550
  own: {
512
551
  (error: object): ErrorOwnProps<TPluginsMap>
513
552
  <TKey extends keyof TPluginsMap['props'] & string>(error: object, key: TKey): ErrorOwnProps<TPluginsMap>[TKey]
@@ -516,24 +555,6 @@ export type ClassError0<TPluginsMap extends ErrorPluginsMap = EmptyPluginsMap> =
516
555
  error: object,
517
556
  key: TKey,
518
557
  ) => Array<ErrorOwnProps<TPluginsMap>[TKey]>
519
- // prop: <
520
- // TKey extends string,
521
- // TInputValue = undefined,
522
- // TOutputValue = unknown,
523
- // TResolveValue extends TOutputValue | undefined = TOutputValue | undefined,
524
- // >(
525
- // key: TKey,
526
- // value: ErrorPluginPropOptions<TInputValue, TOutputValue, ErrorInstanceOfMap<TPluginsMap>, TResolveValue>,
527
- // ) => ClassError0<ExtendErrorPluginsMapWithProp<TPluginsMap, TKey, TInputValue, TOutputValue, TResolveValue>>
528
- // method: <TKey extends string, TMethod extends (error: ErrorInstanceOfMap<TPluginsMap>, ...args: any[]) => any>(
529
- // key: TKey,
530
- // value: TMethod,
531
- // ) => ClassError0<ExtendErrorPluginsMapWithMethod<TPluginsMap, TKey, TMethod>>
532
- // adapt: (
533
- // value: ErrorPluginAdaptFn<ErrorInstanceOfMap<TPluginsMap>, ErrorResolvedProps<TPluginsMap>>,
534
- // ) => ClassError0<TPluginsMap>
535
- // stack: (value: ErrorPluginStack<ErrorInstanceOfMap<TPluginsMap>>) => ClassError0<TPluginsMap>
536
- // cause: (value: ErrorPluginCause<ErrorInstanceOfMap<TPluginsMap>>) => ClassError0<TPluginsMap>
537
558
  use: {
538
559
  <TBuilder extends PluginError0>(
539
560
  plugin: TBuilder,
@@ -566,10 +587,11 @@ export type ClassError0<TPluginsMap extends ErrorPluginsMap = EmptyPluginsMap> =
566
587
 
567
588
  export class Error0 extends Error {
568
589
  static readonly __pluginsMap?: EmptyPluginsMap
569
- readonly __pluginsMap?: EmptyPluginsMap
590
+ declare readonly __pluginsMap?: EmptyPluginsMap
570
591
  static MAX_CAUSES_DEPTH = 99
571
592
  protected static _plugins: ErrorPlugin[] = []
572
593
  protected static _resolvedPlugin?: ErrorPluginResolved
594
+ declare own?: ErrorOwnStore
573
595
 
574
596
  private static readonly _emptyPlugin: ErrorPluginResolved = {
575
597
  props: {},
@@ -675,63 +697,43 @@ export class Error0 extends Error {
675
697
 
676
698
  const ctor = this.constructor as typeof Error0
677
699
  const plugin = ctor._getResolvedPlugin()
678
- const ownStore = Object.create(null) as ErrorOwnStore
679
- Object.defineProperty(this, OWN_SYMBOL, { value: ownStore, writable: true, enumerable: false, configurable: true })
700
+ // const ownStore = Object.create(null) as ErrorOwnStore
701
+ // Object.defineProperty(this, OWN_SYMBOL, { value: ownStore, writable: true, enumerable: false, configurable: true })
680
702
 
681
703
  for (const [key, prop] of plugin.propEntries) {
682
704
  if (key === 'stack') {
683
705
  continue
684
706
  }
685
707
  Object.defineProperty(this, key, {
686
- get: () =>
687
- prop.resolve({
688
- own: ownStore[key],
689
- flow: this.flow(key as never),
690
- error: this,
691
- }),
708
+ get: () => this._resolveByKey(key, plugin),
692
709
  set: (value) => {
693
- ownStore[key] = value
710
+ this.assign({ [key]: value } as never)
694
711
  },
695
712
  enumerable: true,
696
713
  configurable: true,
697
714
  })
698
715
  if (key in input) {
699
- const ownValue = (input as Record<string, unknown>)[key]
700
- ownStore[key] = typeof prop.init === 'function' ? prop.init(ownValue) : ownValue
716
+ const inputValue = (input as Record<string, unknown>)[key]
717
+ const ownValue = typeof prop.init === 'function' ? prop.init(inputValue) : inputValue
718
+ this.assign({ [key]: ownValue } as never)
701
719
  }
702
720
  }
721
+ Error0.fixStack(input.cause)
703
722
  }
704
723
 
705
- private static _getOwnStore(object: object): ErrorOwnStore | undefined {
706
- const record = object as Record<string | symbol, unknown>
707
- const existing = record[OWN_SYMBOL]
708
- if (existing && typeof existing === 'object') {
709
- return existing as ErrorOwnStore
710
- }
711
- return undefined
712
- }
713
-
714
- private static readonly isOwnProperty = (object: object, key: string): boolean => {
715
- const ownStore = this._getOwnStore(object)
716
- if (ownStore) {
717
- return Object.prototype.hasOwnProperty.call(ownStore, key)
718
- }
719
- return !!Object.getOwnPropertyDescriptor(object, key)
720
- }
721
- private static _ownByKey(error: object, key: string): unknown {
722
- const ownStore = this._getOwnStore(error)
723
- if (ownStore) {
724
- return ownStore[key]
725
- }
726
- return (error as Record<string, unknown>)[key]
727
- }
728
- private static _flowByKey(error: object, key: string): unknown[] {
729
- const causes = this.causes(error, true)
730
- const values = new Array<unknown>(causes.length)
731
- for (let i = 0; i < causes.length; i += 1) {
732
- values[i] = this._ownByKey(causes[i], key)
733
- }
734
- return values
724
+ private static fixStack(cause: unknown): void {
725
+ try {
726
+ if (process.env.NODE_ENV !== 'production') {
727
+ let nextCause = cause
728
+ let depth = 0
729
+ const maxDepth = 99
730
+ while (nextCause && depth < maxDepth) {
731
+ ;(globalThis as any).__ERROR0_FIX_STACKTRACE__(nextCause)
732
+ nextCause = (nextCause as any).cause
733
+ depth++
734
+ }
735
+ }
736
+ } catch {}
735
737
  }
736
738
 
737
739
  static own<TThis extends typeof Error0>(this: TThis, error: unknown): ErrorOwnProps<PluginsMapOf<TThis>>
@@ -743,26 +745,9 @@ export class Error0 extends Error {
743
745
  static own(error: unknown, key?: string): unknown {
744
746
  const error0 = this.from(error)
745
747
  if (key === undefined) {
746
- const ownValues: Record<string, unknown> = {}
747
- const plugin = this._getResolvedPlugin()
748
- for (const ownKey of plugin.propKeys) {
749
- ownValues[ownKey] = this._ownByKey(error0, ownKey)
750
- }
751
- return ownValues
752
- }
753
- return this._ownByKey(error0, key)
754
- }
755
- own<TThis extends Error0>(this: TThis): ErrorOwnProps<PluginsMapOfInstance<TThis>>
756
- own<TThis extends Error0, TKey extends keyof PluginsMapOfInstance<TThis>['props'] & string>(
757
- this: TThis,
758
- key: TKey,
759
- ): ErrorOwnProps<PluginsMapOfInstance<TThis>>[TKey]
760
- own(key?: string): unknown {
761
- const ctor = this.constructor as typeof Error0
762
- if (key === undefined) {
763
- return ctor.own(this)
748
+ return error0.own ?? {}
764
749
  }
765
- return ctor._ownByKey(this, key)
750
+ return error0.own?.[key]
766
751
  }
767
752
 
768
753
  static flow<TThis extends typeof Error0, TKey extends keyof PluginsMapOf<TThis>['props'] & string>(
@@ -772,57 +757,68 @@ export class Error0 extends Error {
772
757
  ): Array<ErrorOwnProps<PluginsMapOf<TThis>>[TKey]>
773
758
  static flow(error: unknown, key: string): unknown[] {
774
759
  const error0 = this.from(error)
775
- return this._flowByKey(error0, key)
760
+ return error0.flow(key as never)
776
761
  }
777
762
  flow<TThis extends Error0, TKey extends keyof PluginsMapOfInstance<TThis>['props'] & string>(
778
763
  this: TThis,
779
764
  key: TKey,
780
765
  ): Array<ErrorOwnProps<PluginsMapOfInstance<TThis>>[TKey]>
781
766
  flow(key: string): unknown[] {
782
- const ctor = this.constructor as typeof Error0
783
- return ctor._flowByKey(this, key)
767
+ const causes = this.causes(true)
768
+ const values = new Array<unknown>(causes.length)
769
+ for (let i = 0; i < causes.length; i += 1) {
770
+ values[i] = causes[i].own?.[key]
771
+ }
772
+ return values
784
773
  }
785
774
 
786
- static _resolveByKey(error: Error0, key: string, plugin: ErrorPluginResolved): unknown {
787
- try {
788
- const options = {
789
- get own() {
790
- return error.own(key as never)
791
- },
792
- get flow() {
793
- return error.flow(key as never)
794
- },
795
- error,
796
- }
797
- const prop = plugin.props[key]
798
- const resolver = prop.resolve
799
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
800
- if (!resolver) {
801
- return (error as any)[key]
802
- }
803
- return resolver(options as ErrorPluginPropOptionsResolveOptions<any, any>)
804
- } catch {
805
- // eslint-disable-next-line no-console
806
- console.error(`Error0: failed to resolve property ${key}`, error)
807
- return undefined
775
+ private readonly _resolveByKeyCache = new Map<string, unknown>()
776
+ private _resolveByKey(key: string, plugin: ErrorPluginResolved): unknown {
777
+ // eslint-disable-next-line consistent-this, @typescript-eslint/no-this-alias
778
+ const error = this
779
+ if (this._resolveByKeyCache.has(key)) {
780
+ return this._resolveByKeyCache.get(key)
808
781
  }
782
+ const value = (() => {
783
+ try {
784
+ const options = {
785
+ get flow() {
786
+ return error.flow(key as never)
787
+ },
788
+ own: error.own?.[key],
789
+ error,
790
+ }
791
+ const prop = plugin.props[key]
792
+ const resolver = prop.resolve
793
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
794
+ if (!resolver) {
795
+ return (error as any)[key]
796
+ }
797
+ return resolver(options as ErrorPluginPropOptionsResolveOptions<any, any>)
798
+ } catch {
799
+ // eslint-disable-next-line no-console
800
+ console.error(`Error0: failed to resolve property ${key}`, error)
801
+ return undefined
802
+ }
803
+ })()
804
+ this._resolveByKeyCache.set(key, value)
805
+ return value
809
806
  }
810
807
 
811
808
  static resolve<TThis extends typeof Error0>(this: TThis, error: unknown): ErrorResolvedProps<PluginsMapOf<TThis>>
812
809
  static resolve(error: unknown): Record<string, unknown>
813
810
  static resolve(error: unknown): Record<string, unknown> {
814
- const error0 = this.from(error)
815
- const resolved: Record<string, unknown> = {}
816
- const plugin = this._getResolvedPlugin()
817
- for (const key of plugin.propKeys) {
818
- resolved[key] = this._resolveByKey(error0, key, plugin)
819
- }
820
- return resolved
811
+ return this.from(error).resolve()
821
812
  }
822
813
  resolve<TThis extends Error0>(this: TThis): ErrorResolvedProps<PluginsMapOfInstance<TThis>>
823
814
  resolve(): Record<string, unknown> {
824
815
  const ctor = this.constructor as typeof Error0
825
- return ctor.resolve(this)
816
+ const plugin = ctor._getResolvedPlugin()
817
+ const resolved: Record<string, unknown> = {}
818
+ for (const key of plugin.propKeys) {
819
+ resolved[key] = this._resolveByKey(key, plugin)
820
+ }
821
+ return resolved
826
822
  }
827
823
 
828
824
  static causes(error: unknown, instancesOnly?: false): unknown[]
@@ -866,6 +862,7 @@ export class Error0 extends Error {
866
862
  return !this.is(error) && typeof error === 'object' && error !== null && 'name' in error && error.name === 'Error0'
867
863
  }
868
864
 
865
+ static from<TThis extends typeof Error0>(this: TThis, error: unknown): InstanceType<TThis>
869
866
  static from(error: unknown): Error0 {
870
867
  if (this.is(error)) {
871
868
  return error
@@ -876,8 +873,61 @@ export class Error0 extends Error {
876
873
  return this._fromNonError0(error)
877
874
  }
878
875
 
876
+ static round<TThis extends typeof Error0>(this: TThis, error: unknown, isPublic?: boolean): InstanceType<TThis>
879
877
  static round(error: unknown, isPublic = false): Error0 {
880
- return this.from(this.serialize(error, isPublic))
878
+ return this.from(error).round(isPublic)
879
+ }
880
+ round<TThis extends Error0>(this: TThis, isPublic = true): TThis {
881
+ const ctor = this.constructor as typeof Error0
882
+ return ctor.from(this.serialize(isPublic)) as TThis
883
+ }
884
+
885
+ // static flat<TThis extends typeof Error0>(this: TThis, error: unknown, keepCauses?: boolean): InstanceType<TThis>
886
+ // static flat(error: unknown, keepCauses = false): Error0 {
887
+ // return this.from(error).flat(keepCauses)
888
+ // }
889
+ // flat<TThis extends Error0>(this: TThis, keepCauses = false): TThis {
890
+ // const ctor = this.constructor as typeof Error0
891
+ // // eslint-disable-next-line new-cap
892
+ // const error = new ctor(this.message) as TThis
893
+ // if (keepCauses) {
894
+ // error.cause = this.cause
895
+ // }
896
+ // error.assign({
897
+ // // ...this.own,
898
+ // ...this.resolve(),
899
+ // } as never)
900
+ // error.stack =
901
+ // this.causes()
902
+ // .map((cause, index) => {
903
+ // return cause instanceof Error && cause.stack && typeof cause.stack === 'string'
904
+ // ? index === 0
905
+ // ? cause.stack
906
+ // : cause.stack.split('\n').slice(1).join('\n')
907
+ // : undefined
908
+ // })
909
+ // .join('\n') || undefined
910
+ // return error
911
+ // }
912
+
913
+ static assign<TThis extends typeof Error0>(
914
+ this: TThis,
915
+ error: unknown,
916
+ props: Partial<ErrorOwnProps<PluginsMapOf<TThis>>>,
917
+ ): InstanceType<TThis>
918
+ static assign(error: unknown, props: Record<string, unknown>): Error0 {
919
+ const error0 = this.from(error)
920
+ return error0.assign(props)
921
+ }
922
+ assign<TThis extends Error0>(this: TThis, props: Partial<ErrorOwnProps<PluginsMapOfInstance<TThis>>>): TThis
923
+ assign(props: Record<string, unknown>): this {
924
+ this.own = Object.assign(this.own ?? {}, props)
925
+ this._resolveByKeyCache.clear()
926
+ // const values = Object.values(props)
927
+ // if (values.every((value) => value === undefined)) {
928
+ // this.own = undefined
929
+ // }
930
+ return this
881
931
  }
882
932
 
883
933
  private static _applyAdapt(error: Error0): Error0 {
@@ -885,7 +935,7 @@ export class Error0 extends Error {
885
935
  for (const adapt of plugin.adapt) {
886
936
  const adapted = adapt(error as any)
887
937
  if (adapted && typeof adapted === 'object') {
888
- Object.assign(error as unknown as Record<string, unknown>, adapted)
938
+ error.assign(adapted)
889
939
  }
890
940
  }
891
941
  return error
@@ -994,49 +1044,6 @@ export class Error0 extends Error {
994
1044
  }
995
1045
  }
996
1046
 
997
- // static prop<
998
- // TThis extends typeof Error0,
999
- // TKey extends string,
1000
- // TInputValue = undefined,
1001
- // TOutputValue = unknown,
1002
- // TResolveValue extends TOutputValue | undefined = TOutputValue | undefined,
1003
- // >(
1004
- // this: TThis,
1005
- // key: TKey,
1006
- // value: ErrorPluginPropOptions<TInputValue, TOutputValue, ErrorInstanceOfMap<PluginsMapOf<TThis>>, TResolveValue>,
1007
- // ): ClassError0<ExtendErrorPluginsMapWithProp<PluginsMapOf<TThis>, TKey, TInputValue, TOutputValue, TResolveValue>> {
1008
- // return this.use('prop', key, value)
1009
- // }
1010
-
1011
- // static method<TThis extends typeof Error0, TKey extends string, TMethod extends (error: ErrorInstanceOfMap<PluginsMapOf<TThis>>, ...args: any[]) => any>(
1012
- // this: TThis,
1013
- // key: TKey,
1014
- // value: TMethod,
1015
- // ): ClassError0<ExtendErrorPluginsMapWithMethod<PluginsMapOf<TThis>, TKey, TMethod>> {
1016
- // return this.use('method', key, value)
1017
- // }
1018
-
1019
- // static adapt<TThis extends typeof Error0>(
1020
- // this: TThis,
1021
- // value: ErrorPluginAdaptFn<ErrorInstanceOfMap<PluginsMapOf<TThis>>, ErrorResolvedProps<PluginsMapOf<TThis>>>,
1022
- // ): ClassError0<PluginsMapOf<TThis>> {
1023
- // return this.use('adapt', value)
1024
- // }
1025
-
1026
- // static stack<TThis extends typeof Error0>(
1027
- // this: TThis,
1028
- // value: ErrorPluginStack<ErrorInstanceOfMap<PluginsMapOf<TThis>>>,
1029
- // ): ClassError0<PluginsMapOf<TThis>> {
1030
- // return this.use('stack', value)
1031
- // }
1032
-
1033
- // static cause<TThis extends typeof Error0>(
1034
- // this: TThis,
1035
- // value: ErrorPluginCause<ErrorInstanceOfMap<PluginsMapOf<TThis>>>,
1036
- // ): ClassError0<PluginsMapOf<TThis>> {
1037
- // return this.use('cause', value)
1038
- // }
1039
-
1040
1047
  static use<TThis extends typeof Error0, TBuilder extends PluginError0>(
1041
1048
  this: TThis,
1042
1049
  plugin: TBuilder,
@@ -1051,7 +1058,12 @@ export class Error0 extends Error {
1051
1058
  this: TThis,
1052
1059
  kind: 'prop',
1053
1060
  key: TKey,
1054
- value: ErrorPluginPropOptions<TInputValue, TOutputValue, ErrorInstanceOfMap<PluginsMapOf<TThis>>, TResolveValue>,
1061
+ value: ErrorPluginPropOptionsDefinition<
1062
+ TInputValue,
1063
+ TOutputValue,
1064
+ ErrorInstanceOfMap<PluginsMapOf<TThis>>,
1065
+ TResolveValue
1066
+ >,
1055
1067
  ): ClassError0<ExtendErrorPluginsMapWithProp<PluginsMapOf<TThis>, TKey, TInputValue, TOutputValue, TResolveValue>>
1056
1068
  static use<
1057
1069
  TThis extends typeof Error0,
@@ -1087,8 +1099,8 @@ export class Error0 extends Error {
1087
1099
  this: typeof Error0,
1088
1100
  first: PluginError0 | 'prop' | 'method' | 'adapt' | 'stack' | 'cause' | 'message',
1089
1101
  key?: unknown,
1090
- value?: ErrorPluginPropOptions<unknown> | ErrorPluginMethodFn<unknown>,
1091
- ): ClassError0 {
1102
+ value?: ErrorPluginPropOptionsDefinition<unknown> | ErrorPluginMethodFn<unknown>,
1103
+ ): ClassError0<any> {
1092
1104
  if (first instanceof PluginError0) {
1093
1105
  return this._useWithPlugin(this._pluginFromBuilder(first))
1094
1106
  }
@@ -1150,7 +1162,7 @@ export class Error0 extends Error {
1150
1162
  throw new Error(RESERVED_MESSAGE_PROP_ERROR)
1151
1163
  }
1152
1164
  return this._useWithPlugin({
1153
- props: { [key]: value as ErrorPluginPropOptions<unknown> },
1165
+ props: { [key]: fromPropOptionsDefinition(value as ErrorPluginPropOptionsDefinition<any, any>) },
1154
1166
  })
1155
1167
  }
1156
1168
  return this._useWithPlugin({
@@ -1163,10 +1175,14 @@ export class Error0 extends Error {
1163
1175
  }
1164
1176
 
1165
1177
  static serialize(error: unknown, isPublic = true): Record<string, unknown> {
1166
- const error0 = this.from(error)
1167
- const plugin = this._getResolvedPlugin()
1168
- const resolveByKey = (targetError: Error0, key: string, targetPlugin: ErrorPluginResolved): unknown =>
1169
- this._resolveByKey(targetError, key, targetPlugin)
1178
+ return this.from(error).serialize(isPublic)
1179
+ }
1180
+
1181
+ serialize(isPublic = true): Record<string, unknown> {
1182
+ // eslint-disable-next-line consistent-this, @typescript-eslint/no-this-alias
1183
+ const error0 = this
1184
+ const ctor = error0.constructor as typeof Error0
1185
+ const plugin = ctor._getResolvedPlugin()
1170
1186
  const messagePlugin = plugin.message
1171
1187
  let serializedMessage: unknown = error0.message
1172
1188
  try {
@@ -1191,15 +1207,13 @@ export class Error0 extends Error {
1191
1207
  }
1192
1208
  try {
1193
1209
  const options = {
1194
- get own() {
1195
- return error0.own(key as never)
1196
- },
1197
1210
  get flow() {
1198
1211
  return error0.flow(key as never)
1199
1212
  },
1200
1213
  get resolved() {
1201
- return resolveByKey(error0, key, plugin)
1214
+ return error0._resolveByKey(key, plugin)
1202
1215
  },
1216
+ own: error0.own?.[key],
1203
1217
  error: error0,
1204
1218
  isPublic,
1205
1219
  }
@@ -1234,8 +1248,8 @@ export class Error0 extends Error {
1234
1248
  cause: (error0 as { cause?: unknown }).cause,
1235
1249
  error: error0,
1236
1250
  isPublic,
1237
- is: (cause) => this.is(cause),
1238
- serialize: (cause) => this.serialize(cause, isPublic),
1251
+ is: (cause) => ctor.is(cause),
1252
+ serialize: (cause) => ctor.serialize(cause, isPublic),
1239
1253
  })
1240
1254
  if (serializedCause !== undefined) {
1241
1255
  json.cause = serializedCause
@@ -1247,14 +1261,4 @@ export class Error0 extends Error {
1247
1261
  }
1248
1262
  return json
1249
1263
  }
1250
-
1251
- serialize(isPublic = true): Record<string, unknown> {
1252
- const ctor = this.constructor as typeof Error0
1253
- return ctor.serialize(this, isPublic)
1254
- }
1255
-
1256
- round<TThis extends Error0>(this: TThis, isPublic = true): TThis {
1257
- const ctor = this.constructor as typeof Error0
1258
- return ctor.round(this, isPublic) as TThis
1259
- }
1260
1264
  }