@fncts/schema 0.0.23 → 0.0.24

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 (56) hide show
  1. package/AST.d.ts +60 -29
  2. package/ASTAnnotationMap.d.ts +4 -1
  3. package/ParseError/ParseError.d.ts +28 -13
  4. package/_cjs/AST.cjs +279 -137
  5. package/_cjs/AST.cjs.map +1 -1
  6. package/_cjs/ASTAnnotation.cjs +5 -3
  7. package/_cjs/ASTAnnotation.cjs.map +1 -1
  8. package/_cjs/ASTAnnotationMap.cjs +18 -9
  9. package/_cjs/ASTAnnotationMap.cjs.map +1 -1
  10. package/_cjs/InvalidInterpretationError.cjs +1 -6
  11. package/_cjs/InvalidInterpretationError.cjs.map +1 -1
  12. package/_cjs/ParseError/ParseError.cjs +91 -14
  13. package/_cjs/ParseError/ParseError.cjs.map +1 -1
  14. package/_cjs/Schema/api/hashMap.cjs +1 -1
  15. package/_cjs/Schema/api/hashMap.cjs.map +1 -1
  16. package/_cjs/Schema/api/hashSet.cjs +1 -1
  17. package/_cjs/Schema/api/hashSet.cjs.map +1 -1
  18. package/_cjs/Schema/api/list.cjs +3 -1
  19. package/_cjs/Schema/api/list.cjs.map +1 -1
  20. package/_cjs/Schema/api/map.cjs +1 -1
  21. package/_cjs/Schema/api/map.cjs.map +1 -1
  22. package/_cjs/Schema/api/set.cjs +1 -1
  23. package/_cjs/Schema/api/set.cjs.map +1 -1
  24. package/_cjs/Schema/definition.cjs +3 -4
  25. package/_cjs/Schema/definition.cjs.map +1 -1
  26. package/_mjs/AST.mjs +277 -136
  27. package/_mjs/AST.mjs.map +1 -1
  28. package/_mjs/ASTAnnotation.mjs +5 -3
  29. package/_mjs/ASTAnnotation.mjs.map +1 -1
  30. package/_mjs/ASTAnnotationMap.mjs +18 -9
  31. package/_mjs/ASTAnnotationMap.mjs.map +1 -1
  32. package/_mjs/InvalidInterpretationError.mjs +1 -6
  33. package/_mjs/InvalidInterpretationError.mjs.map +1 -1
  34. package/_mjs/ParseError/ParseError.mjs +90 -14
  35. package/_mjs/ParseError/ParseError.mjs.map +1 -1
  36. package/_mjs/Schema/api/hashMap.mjs +1 -1
  37. package/_mjs/Schema/api/hashMap.mjs.map +1 -1
  38. package/_mjs/Schema/api/hashSet.mjs +1 -1
  39. package/_mjs/Schema/api/hashSet.mjs.map +1 -1
  40. package/_mjs/Schema/api/list.mjs +3 -1
  41. package/_mjs/Schema/api/list.mjs.map +1 -1
  42. package/_mjs/Schema/api/map.mjs +1 -1
  43. package/_mjs/Schema/api/map.mjs.map +1 -1
  44. package/_mjs/Schema/api/set.mjs +1 -1
  45. package/_mjs/Schema/api/set.mjs.map +1 -1
  46. package/_mjs/Schema/definition.mjs +2 -3
  47. package/_mjs/Schema/definition.mjs.map +1 -1
  48. package/_src/AST.ts +226 -28
  49. package/_src/ASTAnnotationMap.ts +14 -1
  50. package/_src/ParseError/ParseError.ts +128 -13
  51. package/_src/Schema/api/hashMap.ts +1 -1
  52. package/_src/Schema/api/hashSet.ts +1 -1
  53. package/_src/Schema/api/list.ts +3 -1
  54. package/_src/Schema/api/map.ts +1 -1
  55. package/_src/Schema/api/set.ts +1 -1
  56. package/package.json +3 -3
package/_src/AST.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { MutableVector } from "@fncts/base/collection/immutable/Vector";
2
2
  import type { Validation as ValidationType } from "@fncts/base/data/Branded";
3
+ import type { EqualsContext } from "@fncts/base/data/Equatable";
3
4
 
4
5
  import { show } from "@fncts/base/data/Showable";
5
6
  import { memoize } from "@fncts/schema/utils";
@@ -18,11 +19,13 @@ export abstract class Annotated {
18
19
  * @tsplus type fncts.schema.AST
19
20
  * @tsplus companion fncts.schema.ASTOps
20
21
  */
21
- export abstract class AST extends Annotated {
22
+ export abstract class AST extends Annotated implements Equatable {
22
23
  readonly [ASTTypeId]: ASTTypeId = ASTTypeId;
23
24
 
24
25
  abstract clone(newProperties: Partial<this>): AST;
25
26
 
27
+ abstract [Symbol.equals](that: unknown, context: EqualsContext): boolean;
28
+
26
29
  toString(verbose: boolean = false): string {
27
30
  return this.show(verbose);
28
31
  }
@@ -97,6 +100,14 @@ export function concrete(_: AST): asserts _ is Concrete {
97
100
  //
98
101
  }
99
102
 
103
+ export function isAST(u: unknown): u is AST {
104
+ return isObject(u) && ASTTypeId in u;
105
+ }
106
+
107
+ function hasTag<K extends Concrete["_tag"]>(u: unknown, tag: K): u is Extract<Concrete, { _tag: K }> {
108
+ return isAST(u) && (u as Concrete)._tag === tag;
109
+ }
110
+
100
111
  export function getAnnotations<V>(key: ASTAnnotation<V>) {
101
112
  return (self: Annotated): Maybe<V> => {
102
113
  return self.annotations.get(key);
@@ -110,7 +121,7 @@ export function getAnnotations<V>(key: ASTAnnotation<V>) {
110
121
  /**
111
122
  * @tsplus type fncts.schema.AST.Declaration
112
123
  */
113
- export class Declaration extends AST {
124
+ export class Declaration extends AST implements Equatable {
114
125
  readonly _tag = ASTTag.Declaration;
115
126
  constructor(
116
127
  readonly typeParameters: Vector<AST>,
@@ -133,6 +144,16 @@ export class Declaration extends AST {
133
144
  newProperties.annotations ?? this.annotations,
134
145
  );
135
146
  }
147
+
148
+ [Symbol.equals](that: unknown, context: EqualsContext): boolean {
149
+ return (
150
+ hasTag(that, ASTTag.Declaration) &&
151
+ context.comparator(this.typeParameters, that.typeParameters) &&
152
+ context.comparator(this.decode, that.decode) &&
153
+ context.comparator(this.encode, that.encode) &&
154
+ context.comparator(this.annotations, that.annotations)
155
+ );
156
+ }
136
157
  }
137
158
 
138
159
  /**
@@ -161,7 +182,7 @@ export function isDeclaration(self: AST): self is Declaration {
161
182
 
162
183
  export type LiteralValue = string | number | boolean | null | bigint;
163
184
 
164
- export class Literal extends AST {
185
+ export class Literal extends AST implements Equatable {
165
186
  readonly _tag = ASTTag.Literal;
166
187
  constructor(
167
188
  readonly literal: LiteralValue,
@@ -173,6 +194,14 @@ export class Literal extends AST {
173
194
  clone(newProperties: Partial<this>): AST {
174
195
  return new Literal(newProperties.literal ?? this.literal, newProperties.annotations ?? this.annotations);
175
196
  }
197
+
198
+ [Symbol.equals](that: unknown, context: EqualsContext): boolean {
199
+ return (
200
+ hasTag(that, ASTTag.Literal) &&
201
+ context.comparator(this.literal, that.literal) &&
202
+ context.comparator(this.annotations, that.annotations)
203
+ );
204
+ }
176
205
  }
177
206
 
178
207
  /**
@@ -194,7 +223,7 @@ export function isLiteral(self: AST): self is Literal {
194
223
  * UniqueSymbol
195
224
  */
196
225
 
197
- export class UniqueSymbol extends AST {
226
+ export class UniqueSymbol extends AST implements Equatable {
198
227
  readonly _tag = ASTTag.UniqueSymbol;
199
228
  constructor(
200
229
  readonly symbol: symbol,
@@ -206,6 +235,14 @@ export class UniqueSymbol extends AST {
206
235
  clone(newProperties: Partial<this>): AST {
207
236
  return new UniqueSymbol(newProperties.symbol ?? this.symbol, newProperties.annotations ?? this.annotations);
208
237
  }
238
+
239
+ [Symbol.equals](that: unknown, context: EqualsContext): boolean {
240
+ return (
241
+ hasTag(that, ASTTag.UniqueSymbol) &&
242
+ context.comparator(this.symbol, that.symbol) &&
243
+ context.comparator(this.annotations, that.annotations)
244
+ );
245
+ }
209
246
  }
210
247
 
211
248
  /**
@@ -230,7 +267,7 @@ export function isUniqueSymbol(self: AST): self is UniqueSymbol {
230
267
  * UndefinedKeyword
231
268
  */
232
269
 
233
- export class UndefinedKeyword extends AST {
270
+ export class UndefinedKeyword extends AST implements Equatable {
234
271
  readonly _tag = ASTTag.UndefinedKeyword;
235
272
  constructor(readonly annotations: ASTAnnotationMap = ASTAnnotationMap.empty) {
236
273
  super();
@@ -239,6 +276,10 @@ export class UndefinedKeyword extends AST {
239
276
  clone(newProperties: Partial<this>): AST {
240
277
  return new UndefinedKeyword(newProperties.annotations ?? this.annotations);
241
278
  }
279
+
280
+ [Symbol.equals](that: unknown, context: EqualsContext): boolean {
281
+ return hasTag(that, ASTTag.UndefinedKeyword) && context.comparator(this.annotations, that.annotations);
282
+ }
242
283
  }
243
284
 
244
285
  /**
@@ -252,7 +293,7 @@ export const undefinedKeyword: UndefinedKeyword = new UndefinedKeyword(
252
293
  * VoidKeyword
253
294
  */
254
295
 
255
- export class VoidKeyword extends AST {
296
+ export class VoidKeyword extends AST implements Equatable {
256
297
  readonly _tag = ASTTag.VoidKeyword;
257
298
  constructor(readonly annotations: ASTAnnotationMap = ASTAnnotationMap.empty) {
258
299
  super();
@@ -261,6 +302,10 @@ export class VoidKeyword extends AST {
261
302
  clone(newProperties: Partial<this>): AST {
262
303
  return new VoidKeyword(newProperties.annotations ?? this.annotations);
263
304
  }
305
+
306
+ [Symbol.equals](that: unknown, context: EqualsContext): boolean {
307
+ return hasTag(that, ASTTag.VoidKeyword) && context.comparator(this.annotations, that.annotations);
308
+ }
264
309
  }
265
310
 
266
311
  /**
@@ -272,7 +317,7 @@ export const voidKeyword: VoidKeyword = new VoidKeyword(ASTAnnotationMap.empty.a
272
317
  * NeverKeyword
273
318
  */
274
319
 
275
- export class NeverKeyword extends AST {
320
+ export class NeverKeyword extends AST implements Equatable {
276
321
  readonly _tag = ASTTag.NeverKeyword;
277
322
  constructor(readonly annotations: ASTAnnotationMap = ASTAnnotationMap.empty) {
278
323
  super();
@@ -281,6 +326,10 @@ export class NeverKeyword extends AST {
281
326
  clone(newProperties: Partial<this>): AST {
282
327
  return new NeverKeyword(newProperties.annotations ?? this.annotations);
283
328
  }
329
+
330
+ [Symbol.equals](that: unknown, context: EqualsContext): boolean {
331
+ return hasTag(that, ASTTag.NeverKeyword) && context.comparator(this.annotations, that.annotations);
332
+ }
284
333
  }
285
334
 
286
335
  /**
@@ -294,7 +343,7 @@ export const neverKeyword: NeverKeyword = new NeverKeyword(
294
343
  * UnknownKeyword
295
344
  */
296
345
 
297
- export class UnknownKeyword extends AST {
346
+ export class UnknownKeyword extends AST implements Equatable {
298
347
  readonly _tag = ASTTag.UnknownKeyword;
299
348
  constructor(readonly annotations: ASTAnnotationMap = ASTAnnotationMap.empty) {
300
349
  super();
@@ -303,6 +352,10 @@ export class UnknownKeyword extends AST {
303
352
  clone(newProperties: Partial<this>): AST {
304
353
  return new UnknownKeyword(newProperties.annotations ?? this.annotations);
305
354
  }
355
+
356
+ [Symbol.equals](that: unknown, context: EqualsContext): boolean {
357
+ return hasTag(that, ASTTag.UnknownKeyword) && context.comparator(this.annotations, that.annotations);
358
+ }
306
359
  }
307
360
 
308
361
  /**
@@ -316,7 +369,7 @@ export const unknownKeyword: UnknownKeyword = new UnknownKeyword(
316
369
  * AnyKeyword
317
370
  */
318
371
 
319
- export class AnyKeyword extends AST {
372
+ export class AnyKeyword extends AST implements Equatable {
320
373
  readonly _tag = ASTTag.AnyKeyword;
321
374
  constructor(readonly annotations: ASTAnnotationMap = ASTAnnotationMap.empty) {
322
375
  super();
@@ -325,6 +378,10 @@ export class AnyKeyword extends AST {
325
378
  clone(newProperties: Partial<this>): AST {
326
379
  return new AnyKeyword(newProperties.annotations ?? this.annotations);
327
380
  }
381
+
382
+ [Symbol.equals](that: unknown, context: EqualsContext): boolean {
383
+ return hasTag(that, ASTTag.AnyKeyword) && context.comparator(this.annotations, that.annotations);
384
+ }
328
385
  }
329
386
 
330
387
  /**
@@ -336,7 +393,7 @@ export const anyKeyword: AnyKeyword = new AnyKeyword(ASTAnnotationMap.empty.anno
336
393
  * StringKeyword
337
394
  */
338
395
 
339
- export class StringKeyword extends AST {
396
+ export class StringKeyword extends AST implements Equatable {
340
397
  readonly _tag = ASTTag.StringKeyword;
341
398
  constructor(readonly annotations: ASTAnnotationMap = ASTAnnotationMap.empty) {
342
399
  super();
@@ -345,6 +402,10 @@ export class StringKeyword extends AST {
345
402
  clone(newProperties: Partial<this>): AST {
346
403
  return new StringKeyword(newProperties.annotations ?? this.annotations);
347
404
  }
405
+
406
+ [Symbol.equals](that: unknown, context: EqualsContext): boolean {
407
+ return hasTag(that, ASTTag.StringKeyword) && context.comparator(this.annotations, that.annotations);
408
+ }
348
409
  }
349
410
 
350
411
  /**
@@ -366,7 +427,7 @@ export function isStringKeyword(self: AST): self is StringKeyword {
366
427
  * NumberKeyword
367
428
  */
368
429
 
369
- export class NumberKeyword extends AST {
430
+ export class NumberKeyword extends AST implements Equatable {
370
431
  readonly _tag = ASTTag.NumberKeyword;
371
432
  constructor(readonly annotations: ASTAnnotationMap = ASTAnnotationMap.empty) {
372
433
  super();
@@ -375,6 +436,10 @@ export class NumberKeyword extends AST {
375
436
  clone(newProperties: Partial<this>): AST {
376
437
  return new NumberKeyword(newProperties.annotations ?? this.annotations);
377
438
  }
439
+
440
+ [Symbol.equals](that: unknown, context: EqualsContext): boolean {
441
+ return hasTag(that, ASTTag.NumberKeyword) && context.comparator(this.annotations, that.annotations);
442
+ }
378
443
  }
379
444
 
380
445
  /**
@@ -396,7 +461,7 @@ export function isNumberKeyword(self: AST): self is NumberKeyword {
396
461
  * BooleanKeyword
397
462
  */
398
463
 
399
- export class BooleanKeyword extends AST {
464
+ export class BooleanKeyword extends AST implements Equatable {
400
465
  readonly _tag = ASTTag.BooleanKeyword;
401
466
  constructor(readonly annotations: ASTAnnotationMap = ASTAnnotationMap.empty) {
402
467
  super();
@@ -405,6 +470,10 @@ export class BooleanKeyword extends AST {
405
470
  clone(newProperties: Partial<this>): AST {
406
471
  return new BooleanKeyword(newProperties.annotations ?? this.annotations);
407
472
  }
473
+
474
+ [Symbol.equals](that: unknown, context: EqualsContext): boolean {
475
+ return hasTag(that, ASTTag.BooleanKeyword) && context.comparator(this.annotations, that.annotations);
476
+ }
408
477
  }
409
478
 
410
479
  /**
@@ -426,7 +495,7 @@ export function isBooleanKeyword(self: AST): self is BooleanKeyword {
426
495
  * BigIntKeyword
427
496
  */
428
497
 
429
- export class BigIntKeyword extends AST {
498
+ export class BigIntKeyword extends AST implements Equatable {
430
499
  readonly _tag = ASTTag.BigIntKeyword;
431
500
  constructor(readonly annotations: ASTAnnotationMap = ASTAnnotationMap.empty) {
432
501
  super();
@@ -435,6 +504,10 @@ export class BigIntKeyword extends AST {
435
504
  clone(newProperties: Partial<this>): AST {
436
505
  return new BigIntKeyword(newProperties.annotations ?? this.annotations);
437
506
  }
507
+
508
+ [Symbol.equals](that: unknown, context: EqualsContext): boolean {
509
+ return hasTag(that, ASTTag.BigIntKeyword) && context.comparator(this.annotations, that.annotations);
510
+ }
438
511
  }
439
512
 
440
513
  /**
@@ -456,7 +529,7 @@ export function isBigIntKeyword(self: AST): self is BigIntKeyword {
456
529
  * SymbolKeyword
457
530
  */
458
531
 
459
- export class SymbolKeyword extends AST {
532
+ export class SymbolKeyword extends AST implements Equatable {
460
533
  readonly _tag = ASTTag.SymbolKeyword;
461
534
  constructor(readonly annotations: ASTAnnotationMap = ASTAnnotationMap.empty) {
462
535
  super();
@@ -465,6 +538,10 @@ export class SymbolKeyword extends AST {
465
538
  clone(newProperties: Partial<this>): AST {
466
539
  return new SymbolKeyword(newProperties.annotations ?? this.annotations);
467
540
  }
541
+
542
+ [Symbol.equals](that: unknown, context: EqualsContext): boolean {
543
+ return hasTag(that, ASTTag.SymbolKeyword) && context.comparator(this.annotations, that.annotations);
544
+ }
468
545
  }
469
546
 
470
547
  /**
@@ -486,7 +563,7 @@ export function isSymbolKeyword(self: AST): self is SymbolKeyword {
486
563
  * ObjectKeyword
487
564
  */
488
565
 
489
- export class ObjectKeyword extends AST {
566
+ export class ObjectKeyword extends AST implements Equatable {
490
567
  readonly _tag = ASTTag.ObjectKeyword;
491
568
  constructor(readonly annotations: ASTAnnotationMap = ASTAnnotationMap.empty) {
492
569
  super();
@@ -495,6 +572,10 @@ export class ObjectKeyword extends AST {
495
572
  clone(newProperties: Partial<this>): AST {
496
573
  return new ObjectKeyword(newProperties.annotations ?? this.annotations);
497
574
  }
575
+
576
+ [Symbol.equals](that: unknown, context: EqualsContext): boolean {
577
+ return hasTag(that, ASTTag.ObjectKeyword) && context.comparator(this.annotations, that.annotations);
578
+ }
498
579
  }
499
580
 
500
581
  /**
@@ -508,7 +589,7 @@ export const objectKeyword: ObjectKeyword = new ObjectKeyword(
508
589
  * Enum
509
590
  */
510
591
 
511
- export class Enum extends AST {
592
+ export class Enum extends AST implements Equatable {
512
593
  readonly _tag = ASTTag.Enum;
513
594
  constructor(
514
595
  readonly enums: Vector<readonly [string, string | number]>,
@@ -520,6 +601,18 @@ export class Enum extends AST {
520
601
  clone(newProperties: Partial<this>): AST {
521
602
  return new Enum(newProperties.enums ?? this.enums, newProperties.annotations ?? this.annotations);
522
603
  }
604
+
605
+ [Symbol.equals](that: unknown, context: EqualsContext): boolean {
606
+ return (
607
+ hasTag(that, ASTTag.Enum) &&
608
+ this.enums.corresponds(
609
+ that.enums,
610
+ ([leftName, leftValue], [rightName, rightValue]) =>
611
+ context.comparator(leftName, rightName) && context.comparator(leftValue, rightValue),
612
+ ) &&
613
+ context.comparator(this.annotations, that.annotations)
614
+ );
615
+ }
523
616
  }
524
617
 
525
618
  /**
@@ -532,12 +625,20 @@ export function createEnum(
532
625
  return new Enum(enums, annotations);
533
626
  }
534
627
 
535
- export class TemplateLiteralSpan {
628
+ export class TemplateLiteralSpan implements Equatable {
536
629
  constructor(
537
630
  readonly type: StringKeyword | NumberKeyword,
538
631
  readonly literal: string,
539
632
  ) {}
540
633
 
634
+ [Symbol.equals](that: unknown, context: EqualsContext): boolean {
635
+ return (
636
+ that instanceof TemplateLiteralSpan &&
637
+ context.comparator(this.type, that.type) &&
638
+ context.comparator(this.literal, that.literal)
639
+ );
640
+ }
641
+
541
642
  toString() {
542
643
  switch (this.type._tag) {
543
644
  case ASTTag.StringKeyword:
@@ -552,7 +653,7 @@ export class TemplateLiteralSpan {
552
653
  * TemplateLiteral
553
654
  */
554
655
 
555
- export class TemplateLiteral extends AST {
656
+ export class TemplateLiteral extends AST implements Equatable {
556
657
  readonly _tag = ASTTag.TemplateLiteral;
557
658
  constructor(
558
659
  readonly head: string,
@@ -569,6 +670,15 @@ export class TemplateLiteral extends AST {
569
670
  newProperties.annotations ?? this.annotations,
570
671
  );
571
672
  }
673
+
674
+ [Symbol.equals](that: unknown, context: EqualsContext): boolean {
675
+ return (
676
+ hasTag(that, ASTTag.TemplateLiteral) &&
677
+ context.comparator(this.head, that.head) &&
678
+ context.comparator(this.spans, that.spans) &&
679
+ context.comparator(this.annotations, that.annotations)
680
+ );
681
+ }
572
682
  }
573
683
 
574
684
  /**
@@ -590,12 +700,20 @@ export function createTemplateLiteral(
590
700
  * Element
591
701
  */
592
702
 
593
- export class Element {
703
+ export class Element implements Equatable {
594
704
  constructor(
595
705
  readonly type: AST,
596
706
  readonly isOptional: boolean,
597
707
  ) {}
598
708
 
709
+ [Symbol.equals](that: unknown, context: EqualsContext): boolean {
710
+ return (
711
+ that instanceof Element &&
712
+ context.comparator(this.type, that.type) &&
713
+ context.comparator(this.isOptional, that.isOptional)
714
+ );
715
+ }
716
+
599
717
  toString() {
600
718
  return String(this.type) + (this.isOptional ? "?" : "");
601
719
  }
@@ -612,7 +730,7 @@ export function createElement(type: AST, isOptional: boolean): Element {
612
730
  * Tuple
613
731
  */
614
732
 
615
- export class Tuple extends AST {
733
+ export class Tuple extends AST implements Equatable {
616
734
  readonly _tag = ASTTag.Tuple;
617
735
  constructor(
618
736
  readonly elements: Vector<Element>,
@@ -631,6 +749,16 @@ export class Tuple extends AST {
631
749
  newProperties.annotations ?? this.annotations,
632
750
  );
633
751
  }
752
+
753
+ [Symbol.equals](that: unknown, context: EqualsContext): boolean {
754
+ return (
755
+ hasTag(that, ASTTag.Tuple) &&
756
+ context.comparator(this.elements, that.elements) &&
757
+ context.comparator(this.rest, that.rest) &&
758
+ context.comparator(this.isReadonly, that.isReadonly) &&
759
+ context.comparator(this.annotations, that.annotations)
760
+ );
761
+ }
634
762
  }
635
763
 
636
764
  /**
@@ -654,7 +782,7 @@ export const unknownArray = AST.createTuple(Vector.empty(), Just(Vector(AST.unkn
654
782
  * PropertySignature
655
783
  */
656
784
 
657
- export class PropertySignature {
785
+ export class PropertySignature implements Equatable {
658
786
  constructor(
659
787
  readonly name: PropertyKey,
660
788
  readonly type: AST,
@@ -672,6 +800,17 @@ export class PropertySignature {
672
800
  newProperties.annotations ?? this.annotations,
673
801
  );
674
802
  }
803
+
804
+ [Symbol.equals](that: unknown, context: EqualsContext): boolean {
805
+ return (
806
+ that instanceof PropertySignature &&
807
+ context.comparator(this.name, that.name) &&
808
+ context.comparator(this.type, that.type) &&
809
+ context.comparator(this.isOptional, that.isOptional) &&
810
+ context.comparator(this.isReadonly, that.isReadonly) &&
811
+ context.comparator(this.annotations, that.annotations)
812
+ );
813
+ }
675
814
  }
676
815
 
677
816
  /**
@@ -691,12 +830,21 @@ export function createPropertySignature(
691
830
  * IndexSignature
692
831
  */
693
832
 
694
- export class IndexSignature {
833
+ export class IndexSignature implements Equatable {
695
834
  constructor(
696
835
  readonly parameter: StringKeyword | SymbolKeyword | TemplateLiteral | NumberKeyword | Refinement,
697
836
  readonly type: AST,
698
837
  readonly isReadonly: boolean,
699
838
  ) {}
839
+
840
+ [Symbol.equals](that: unknown, context: EqualsContext): boolean {
841
+ return (
842
+ that instanceof IndexSignature &&
843
+ context.comparator(this.parameter, that.parameter) &&
844
+ context.comparator(this.type, that.type) &&
845
+ context.comparator(this.isReadonly, that.isReadonly)
846
+ );
847
+ }
700
848
  }
701
849
 
702
850
  /**
@@ -714,7 +862,7 @@ export function createIndexSignature(
714
862
  * TypeLiteral
715
863
  */
716
864
 
717
- export class TypeLiteral extends AST {
865
+ export class TypeLiteral extends AST implements Equatable {
718
866
  readonly _tag = ASTTag.TypeLiteral;
719
867
  readonly propertySignatures: Vector<PropertySignature>;
720
868
  readonly indexSignatures: Vector<IndexSignature>;
@@ -735,6 +883,15 @@ export class TypeLiteral extends AST {
735
883
  newProperties.annotations ?? this.annotations,
736
884
  );
737
885
  }
886
+
887
+ [Symbol.equals](that: unknown, context: EqualsContext): boolean {
888
+ return (
889
+ hasTag(that, ASTTag.TypeLiteral) &&
890
+ context.comparator(this.propertySignatures, that.propertySignatures) &&
891
+ context.comparator(this.indexSignatures, that.indexSignatures) &&
892
+ context.comparator(this.annotations, that.annotations)
893
+ );
894
+ }
738
895
  }
739
896
 
740
897
  /**
@@ -772,7 +929,7 @@ export const unknownRecord = AST.createTypeLiteral(
772
929
  * Union
773
930
  */
774
931
 
775
- export class Union extends AST {
932
+ export class Union extends AST implements Equatable {
776
933
  readonly _tag = ASTTag.Union;
777
934
  constructor(
778
935
  readonly types: Vector<AST>,
@@ -784,6 +941,14 @@ export class Union extends AST {
784
941
  clone(newProperties: Partial<this>): AST {
785
942
  return createUnion(newProperties.types ?? this.types, newProperties.annotations ?? this.annotations);
786
943
  }
944
+
945
+ [Symbol.equals](that: unknown, context: EqualsContext): boolean {
946
+ return (
947
+ hasTag(that, ASTTag.Union) &&
948
+ context.comparator(this.types, that.types) &&
949
+ context.comparator(this.annotations, that.annotations)
950
+ );
951
+ }
787
952
  }
788
953
 
789
954
  /**
@@ -813,7 +978,7 @@ export function createUnion(candidates: Vector<AST>, annotations: ASTAnnotationM
813
978
  * Lazy
814
979
  */
815
980
 
816
- export class Lazy extends AST {
981
+ export class Lazy extends AST implements Equatable {
817
982
  readonly _tag = ASTTag.Lazy;
818
983
  constructor(
819
984
  readonly getAST: () => AST,
@@ -825,6 +990,10 @@ export class Lazy extends AST {
825
990
  clone(newProperties: Partial<this>): AST {
826
991
  return new Lazy(newProperties.getAST ?? this.getAST, newProperties.annotations ?? this.annotations);
827
992
  }
993
+
994
+ [Symbol.equals](that: unknown): boolean {
995
+ return this === that;
996
+ }
828
997
  }
829
998
 
830
999
  /**
@@ -846,7 +1015,7 @@ export function isLazy(self: AST): self is Lazy {
846
1015
  * Refinement
847
1016
  */
848
1017
 
849
- export class Refinement extends AST {
1018
+ export class Refinement extends AST implements Equatable {
850
1019
  readonly _tag = ASTTag.Refinement;
851
1020
  constructor(
852
1021
  readonly from: AST,
@@ -867,6 +1036,15 @@ export class Refinement extends AST {
867
1036
  newProperties.annotations ?? this.annotations,
868
1037
  );
869
1038
  }
1039
+
1040
+ [Symbol.equals](that: unknown, context: EqualsContext): boolean {
1041
+ return (
1042
+ hasTag(that, ASTTag.Refinement) &&
1043
+ context.comparator(this.from, that.from) &&
1044
+ context.comparator(this.predicate, that.predicate) &&
1045
+ context.comparator(this.annotations, that.annotations)
1046
+ );
1047
+ }
870
1048
  }
871
1049
 
872
1050
  /**
@@ -894,7 +1072,7 @@ export interface ParseOptions {
894
1072
  * Transform
895
1073
  */
896
1074
 
897
- export class Transform extends AST {
1075
+ export class Transform extends AST implements Equatable {
898
1076
  readonly _tag = ASTTag.Transform;
899
1077
  constructor(
900
1078
  readonly from: AST,
@@ -915,6 +1093,17 @@ export class Transform extends AST {
915
1093
  newProperties.annotations ?? this.annotations,
916
1094
  );
917
1095
  }
1096
+
1097
+ [Symbol.equals](that: unknown, context: EqualsContext): boolean {
1098
+ return (
1099
+ hasTag(that, ASTTag.Transform) &&
1100
+ context.comparator(this.from, that.from) &&
1101
+ context.comparator(this.to, that.to) &&
1102
+ context.comparator(this.decode, that.decode) &&
1103
+ context.comparator(this.encode, that.encode) &&
1104
+ context.comparator(this.annotations, that.annotations)
1105
+ );
1106
+ }
918
1107
  }
919
1108
 
920
1109
  /**
@@ -934,7 +1123,7 @@ export function createTransform(
934
1123
  * Validation
935
1124
  */
936
1125
 
937
- export class Validation extends AST {
1126
+ export class Validation extends AST implements Equatable {
938
1127
  readonly _tag = ASTTag.Validation;
939
1128
  constructor(
940
1129
  readonly from: AST,
@@ -951,6 +1140,15 @@ export class Validation extends AST {
951
1140
  newProperties.annotations ?? this.annotations,
952
1141
  );
953
1142
  }
1143
+
1144
+ [Symbol.equals](that: unknown, context: EqualsContext): boolean {
1145
+ return (
1146
+ hasTag(that, ASTTag.Validation) &&
1147
+ context.comparator(this.from, that.from) &&
1148
+ context.comparator(this.validation, that.validation) &&
1149
+ context.comparator(this.annotations, that.annotations)
1150
+ );
1151
+ }
954
1152
  }
955
1153
 
956
1154
  /**
@@ -1,7 +1,20 @@
1
1
  import type { ASTAnnotation } from "./ASTAnnotation.js";
2
+ import type { EqualsContext } from "@fncts/base/data/Equatable";
2
3
 
3
- export class ASTAnnotationMap {
4
+ export class ASTAnnotationMap implements Equatable {
4
5
  constructor(readonly map: HashMap<ASTAnnotation<any>, any>) {}
6
+
7
+ [Symbol.equals](that: unknown, context: EqualsContext): boolean {
8
+ if (!(that instanceof ASTAnnotationMap) || this.map.size !== that.map.size) {
9
+ return false;
10
+ }
11
+
12
+ return this.map.corresponds(
13
+ that.map,
14
+ ([k1, v1], [k2, v2]) => context.comparator(k1, k2) && context.comparator(v1, v2),
15
+ );
16
+ }
17
+
5
18
  combine(that: ASTAnnotationMap): ASTAnnotationMap {
6
19
  return new ASTAnnotationMap(
7
20
  Conc.from(this.map)