@fncts/schema 0.0.15 → 0.0.17

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 (153) hide show
  1. package/AST.d.ts +19 -6
  2. package/ASTAnnotation.d.ts +10 -2
  3. package/ParseError/ParseError.d.ts +231 -0
  4. package/ParseError/ParseErrorFormatter.d.ts +2 -0
  5. package/ParseError/PathFormatter.d.ts +13 -0
  6. package/ParseError/TreeFormatter.d.ts +14 -0
  7. package/ParseError.d.ts +4 -144
  8. package/ParseResult.d.ts +1 -8
  9. package/Parser/interpreter.d.ts +0 -1
  10. package/Schema/api/conc.d.ts +0 -2
  11. package/Schema/api/hashMap.d.ts +0 -1
  12. package/Schema/api/hashSet.d.ts +0 -1
  13. package/Schema/api/immutableArray.d.ts +0 -1
  14. package/Schema/api/list.d.ts +1 -2
  15. package/Schema/api/map.d.ts +19 -0
  16. package/Schema/api/set.d.ts +19 -0
  17. package/Schema/api.d.ts +12 -2
  18. package/Schema/derivations.d.ts +1 -1
  19. package/Schema.d.ts +2 -0
  20. package/Show.d.ts +7 -3
  21. package/_cjs/AST.cjs +180 -113
  22. package/_cjs/AST.cjs.map +1 -1
  23. package/_cjs/ASTAnnotation.cjs +6 -1
  24. package/_cjs/ASTAnnotation.cjs.map +1 -1
  25. package/_cjs/Gen.cjs +24 -24
  26. package/_cjs/Gen.cjs.map +1 -1
  27. package/_cjs/ParseError/ParseError.cjs +260 -0
  28. package/_cjs/ParseError/ParseError.cjs.map +1 -0
  29. package/_cjs/ParseError/ParseErrorFormatter.cjs +6 -0
  30. package/_cjs/ParseError/ParseErrorFormatter.cjs.map +1 -0
  31. package/_cjs/ParseError/PathFormatter.cjs +94 -0
  32. package/_cjs/ParseError/PathFormatter.cjs.map +1 -0
  33. package/_cjs/ParseError/TreeFormatter.cjs +123 -0
  34. package/_cjs/ParseError/TreeFormatter.cjs.map +1 -0
  35. package/_cjs/ParseError.cjs +43 -289
  36. package/_cjs/ParseError.cjs.map +1 -1
  37. package/_cjs/ParseResult.cjs +1 -10
  38. package/_cjs/ParseResult.cjs.map +1 -1
  39. package/_cjs/Parser/api.cjs +2 -2
  40. package/_cjs/Parser/api.cjs.map +1 -1
  41. package/_cjs/Parser/definition.cjs +1 -1
  42. package/_cjs/Parser/interpreter.cjs +121 -117
  43. package/_cjs/Parser/interpreter.cjs.map +1 -1
  44. package/_cjs/Schema/api/conc.cjs +35 -45
  45. package/_cjs/Schema/api/conc.cjs.map +1 -1
  46. package/_cjs/Schema/api/either.cjs +24 -30
  47. package/_cjs/Schema/api/either.cjs.map +1 -1
  48. package/_cjs/Schema/api/hashMap.cjs +41 -101
  49. package/_cjs/Schema/api/hashMap.cjs.map +1 -1
  50. package/_cjs/Schema/api/hashSet.cjs +46 -106
  51. package/_cjs/Schema/api/hashSet.cjs.map +1 -1
  52. package/_cjs/Schema/api/immutableArray.cjs +22 -48
  53. package/_cjs/Schema/api/immutableArray.cjs.map +1 -1
  54. package/_cjs/Schema/api/list.cjs +35 -52
  55. package/_cjs/Schema/api/list.cjs.map +1 -1
  56. package/_cjs/Schema/api/map.cjs +97 -0
  57. package/_cjs/Schema/api/map.cjs.map +1 -0
  58. package/_cjs/Schema/api/maybe.cjs +24 -35
  59. package/_cjs/Schema/api/maybe.cjs.map +1 -1
  60. package/_cjs/Schema/api/set.cjs +76 -0
  61. package/_cjs/Schema/api/set.cjs.map +1 -0
  62. package/_cjs/Schema/api.cjs +21 -3
  63. package/_cjs/Schema/api.cjs.map +1 -1
  64. package/_cjs/Schema.cjs +22 -0
  65. package/_cjs/Schema.cjs.map +1 -1
  66. package/_cjs/Show.cjs +106 -89
  67. package/_cjs/Show.cjs.map +1 -1
  68. package/_cjs/utils.cjs +5 -0
  69. package/_cjs/utils.cjs.map +1 -1
  70. package/_mjs/AST.mjs +177 -112
  71. package/_mjs/AST.mjs.map +1 -1
  72. package/_mjs/ASTAnnotation.mjs +5 -0
  73. package/_mjs/ASTAnnotation.mjs.map +1 -1
  74. package/_mjs/Gen.mjs +24 -24
  75. package/_mjs/Gen.mjs.map +1 -1
  76. package/_mjs/ParseError/ParseError.mjs +228 -0
  77. package/_mjs/ParseError/ParseError.mjs.map +1 -0
  78. package/_mjs/ParseError/ParseErrorFormatter.mjs +2 -0
  79. package/_mjs/ParseError/ParseErrorFormatter.mjs.map +1 -0
  80. package/_mjs/ParseError/PathFormatter.mjs +86 -0
  81. package/_mjs/ParseError/PathFormatter.mjs.map +1 -0
  82. package/_mjs/ParseError/TreeFormatter.mjs +113 -0
  83. package/_mjs/ParseError/TreeFormatter.mjs.map +1 -0
  84. package/_mjs/ParseError.mjs +6 -270
  85. package/_mjs/ParseError.mjs.map +1 -1
  86. package/_mjs/ParseResult.mjs +1 -9
  87. package/_mjs/ParseResult.mjs.map +1 -1
  88. package/_mjs/Parser/api.mjs +2 -2
  89. package/_mjs/Parser/api.mjs.map +1 -1
  90. package/_mjs/Parser/definition.mjs +1 -1
  91. package/_mjs/Parser/interpreter.mjs +121 -117
  92. package/_mjs/Parser/interpreter.mjs.map +1 -1
  93. package/_mjs/Schema/api/conc.mjs +35 -44
  94. package/_mjs/Schema/api/conc.mjs.map +1 -1
  95. package/_mjs/Schema/api/either.mjs +24 -30
  96. package/_mjs/Schema/api/either.mjs.map +1 -1
  97. package/_mjs/Schema/api/hashMap.mjs +41 -101
  98. package/_mjs/Schema/api/hashMap.mjs.map +1 -1
  99. package/_mjs/Schema/api/hashSet.mjs +46 -106
  100. package/_mjs/Schema/api/hashSet.mjs.map +1 -1
  101. package/_mjs/Schema/api/immutableArray.mjs +23 -49
  102. package/_mjs/Schema/api/immutableArray.mjs.map +1 -1
  103. package/_mjs/Schema/api/list.mjs +35 -52
  104. package/_mjs/Schema/api/list.mjs.map +1 -1
  105. package/_mjs/Schema/api/map.mjs +88 -0
  106. package/_mjs/Schema/api/map.mjs.map +1 -0
  107. package/_mjs/Schema/api/maybe.mjs +24 -35
  108. package/_mjs/Schema/api/maybe.mjs.map +1 -1
  109. package/_mjs/Schema/api/set.mjs +67 -0
  110. package/_mjs/Schema/api/set.mjs.map +1 -0
  111. package/_mjs/Schema/api.mjs +19 -3
  112. package/_mjs/Schema/api.mjs.map +1 -1
  113. package/_mjs/Schema.mjs +2 -0
  114. package/_mjs/Schema.mjs.map +1 -1
  115. package/_mjs/Show.mjs +106 -90
  116. package/_mjs/Show.mjs.map +1 -1
  117. package/_mjs/utils.mjs +4 -0
  118. package/_mjs/utils.mjs.map +1 -1
  119. package/_src/AST.ts +144 -43
  120. package/_src/ASTAnnotation.ts +8 -1
  121. package/_src/Gen.ts +12 -9
  122. package/_src/ParseError/ParseError.ts +304 -0
  123. package/_src/ParseError/ParseErrorFormatter.ts +1 -0
  124. package/_src/ParseError/PathFormatter.ts +117 -0
  125. package/_src/ParseError/TreeFormatter.ts +127 -0
  126. package/_src/ParseError.ts +7 -331
  127. package/_src/ParseResult.ts +2 -9
  128. package/_src/Parser/api.ts +1 -1
  129. package/_src/Parser/interpreter.ts +98 -75
  130. package/_src/Schema/api/conc.ts +33 -42
  131. package/_src/Schema/api/either.ts +20 -30
  132. package/_src/Schema/api/hashMap.ts +40 -124
  133. package/_src/Schema/api/hashSet.ts +31 -117
  134. package/_src/Schema/api/immutableArray.ts +15 -45
  135. package/_src/Schema/api/list.ts +32 -55
  136. package/_src/Schema/api/map.ts +93 -0
  137. package/_src/Schema/api/maybe.ts +19 -34
  138. package/_src/Schema/api/set.ts +74 -0
  139. package/_src/Schema/api.ts +21 -3
  140. package/_src/Schema/derivations.ts +1 -1
  141. package/_src/Schema.ts +2 -0
  142. package/_src/Show.ts +156 -128
  143. package/_src/global.ts +0 -4
  144. package/_src/utils.ts +5 -0
  145. package/global.d.ts +0 -4
  146. package/package.json +2 -2
  147. package/utils.d.ts +1 -0
  148. package/ParseFailure.d.ts +0 -18
  149. package/_cjs/ParseFailure.cjs +0 -28
  150. package/_cjs/ParseFailure.cjs.map +0 -1
  151. package/_mjs/ParseFailure.mjs +0 -20
  152. package/_mjs/ParseFailure.mjs.map +0 -1
  153. package/_src/ParseFailure.ts +0 -18
@@ -5,11 +5,9 @@ import type { Check } from "@fncts/typelevel";
5
5
  * @tsplus getter fncts.schema.Schema maybe
6
6
  */
7
7
  export function maybe<A>(value: Schema<A>): Schema<Maybe<A>> {
8
- return Schema.declaration(
9
- Vector(value),
10
- maybeInline(value),
11
- maybeParser,
12
- ASTAnnotationMap.empty.annotate(ASTAnnotation.Identifier, "Maybe"),
8
+ return Schema.declaration(Vector(value), maybeParser(true), maybeParser(false)).annotate(
9
+ ASTAnnotation.Identifier,
10
+ `Maybe<${value.show()}>`,
13
11
  );
14
12
  }
15
13
 
@@ -36,33 +34,20 @@ export function deriveMaybe<A extends Maybe<any>>(
36
34
  return unsafeCoerce(maybeFromNullable(value));
37
35
  }
38
36
 
39
- function maybeParser<A>(value: Schema<A>): Parser<Maybe<A>> {
40
- const schema = maybe(value);
41
- return Parser.make((u, options) => {
42
- if (!Maybe.isMaybe(u)) {
43
- return ParseResult.fail(ParseError.TypeError(schema.ast, u));
44
- }
45
- Maybe.concrete(u);
46
- if (u.isNothing()) {
47
- return ParseResult.succeed(Nothing());
48
- } else {
49
- return value.decode(u.value, options).map((a) => Just(a));
50
- }
51
- });
52
- }
53
-
54
- function maybeInline<A>(value: Schema<A>): Schema<Maybe<A>> {
55
- return Schema.union(
56
- Schema.struct({
57
- _tag: Schema.literal("Nothing"),
58
- [Symbol.equals]: Schema.any,
59
- [Symbol.hash]: Schema.any,
60
- }),
61
- Schema.struct({
62
- _tag: Schema.literal("Just"),
63
- value,
64
- [Symbol.equals]: Schema.any,
65
- [Symbol.hash]: Schema.any,
66
- }),
67
- ) as unknown as Schema<Maybe<A>>;
37
+ function maybeParser(isDecoding: boolean) {
38
+ return <A>(value: Schema<A>): Parser<Maybe<unknown>> => {
39
+ const schema = maybe(value);
40
+ const parseValue = isDecoding ? value.decode : value.encode;
41
+ return Parser.make((u, options) => {
42
+ if (!Maybe.isMaybe(u)) {
43
+ return ParseResult.fail(ParseError.TypeError(schema.ast, u));
44
+ }
45
+ Maybe.concrete(u);
46
+ if (u.isNothing()) {
47
+ return ParseResult.succeed(Nothing());
48
+ } else {
49
+ return parseValue(u.value, options).map((a) => Just(a));
50
+ }
51
+ });
52
+ };
68
53
  }
@@ -0,0 +1,74 @@
1
+ import type { KeyError } from "@fncts/schema/ParseError";
2
+ import type { Sized } from "@fncts/test/control/Sized";
3
+
4
+ /**
5
+ * @tsplus static fncts.schema.SchemaOps map
6
+ */
7
+ export function set<V>(value: Schema<V>): Schema<Set<V>> {
8
+ return Schema.declaration(Vector(value), setParser(true), setParser(false))
9
+ .annotate(ASTAnnotation.Identifier, `Set<${value.show()}>`)
10
+ .annotate(ASTAnnotation.GenHook, gen);
11
+ }
12
+
13
+ /**
14
+ * @tsplus static fncts.schema.SchemaOps mapFromRecord
15
+ */
16
+ export function setFromArray<V>(value: Schema<V>): Schema<Set<V>> {
17
+ return Schema.array(value).transform(
18
+ set(value),
19
+ (input) => {
20
+ return new Set(input);
21
+ },
22
+ (input) => {
23
+ return Array.from(input);
24
+ },
25
+ );
26
+ }
27
+
28
+ /**
29
+ * @tsplus derive fncts.schema.Schema[fncts.Set]<_> 10
30
+ */
31
+ export function deriveSet<A extends Set<any>>(
32
+ ...[value]: [A] extends [Set<infer V>]
33
+ ? Check<Check.IsEqual<A, Set<V>>> extends Check.True
34
+ ? [value: Schema<V>]
35
+ : never
36
+ : never
37
+ ): Schema<A> {
38
+ return unsafeCoerce(setFromArray(value));
39
+ }
40
+
41
+ function setParser(isDecoding: boolean) {
42
+ return <A>(value: Schema<A>): Parser<Set<unknown>> => {
43
+ const schema = set(value);
44
+ const parseValue = isDecoding ? value.decode : value.encode;
45
+ return Parser.make((u, options) => {
46
+ if (!(u instanceof Set)) {
47
+ return ParseResult.fail(ParseError.TypeError(schema.ast, u));
48
+ }
49
+
50
+ const allErrors = options?.allErrors;
51
+ const errors = Vector.emptyPushable<KeyError>();
52
+ const out = new Set();
53
+ for (const v of u) {
54
+ const tv = parseValue(v, options);
55
+ Either.concrete(tv);
56
+ if (tv.isLeft()) {
57
+ errors.push(ParseError.KeyError(value.ast, value, tv.left));
58
+ if (!allErrors) {
59
+ return ParseResult.fail(ParseError.IterableError(schema.ast, u, errors));
60
+ }
61
+ continue;
62
+ }
63
+ out.add(tv.right);
64
+ }
65
+ return errors.isNonEmpty()
66
+ ? ParseResult.fail(ParseError.IterableError(schema.ast, u, errors))
67
+ : ParseResult.succeed(out);
68
+ });
69
+ };
70
+ }
71
+
72
+ function gen<V>(value: Gen<Sized, V>): Gen<Sized, Set<V>> {
73
+ return Gen.array(value).map((values) => new Set(values));
74
+ }
@@ -28,15 +28,15 @@ export function annotate<V>(annotation: ASTAnnotation<V>, value: V) {
28
28
  */
29
29
  export function declaration(
30
30
  typeParameters: Vector<Schema<any>>,
31
- type: Schema<any>,
32
31
  decode: (...typeParameters: ReadonlyArray<Schema<any>>) => Parser<any>,
32
+ encode: (...typeParameters: ReadonlyArray<Schema<any>>) => Parser<any>,
33
33
  annotations?: ASTAnnotationMap,
34
34
  ): Schema<any> {
35
35
  return Schema.fromAST(
36
36
  AST.createDeclaration(
37
37
  typeParameters.map((tp) => tp.ast),
38
- type.ast,
39
38
  (...typeParameters) => decode(...typeParameters.map(Schema.fromAST)),
39
+ (...typeParameters) => encode(...typeParameters.map(Schema.fromAST)),
40
40
  annotations,
41
41
  ),
42
42
  );
@@ -177,8 +177,8 @@ export const implicitDate: Schema<Date> = Schema.unknown.transformOrFail(
177
177
  );
178
178
 
179
179
  /**
180
- * @tsplus static fncts.schema.SchemaOps union
181
180
  * @tsplus derive fncts.schema.Schema<|> 30
181
+ * @tsplus static fncts.schema.SchemaOps union
182
182
  */
183
183
  export function union<A extends ReadonlyArray<unknown>>(
184
184
  ...members: {
@@ -541,3 +541,21 @@ export function transform<A, B>(
541
541
  );
542
542
  };
543
543
  }
544
+
545
+ /**
546
+ * @tsplus pipeable fncts.schema.Schema pick
547
+ */
548
+ export function pick<A, Keys extends ReadonlyArray<keyof A>>(...keys: Keys) {
549
+ return (self: Schema<A>): Schema<Pick<A, Keys[number]>> => {
550
+ return Schema.fromAST(self.ast.pick(Vector.from(keys)));
551
+ };
552
+ }
553
+
554
+ /**
555
+ * @tsplus pipeable fncts.schema.Schema omit
556
+ */
557
+ export function omit<A, Keys extends ReadonlyArray<keyof A>>(...keys: Keys) {
558
+ return (self: Schema<A>): Schema<Omit<A, Keys[number]>> => {
559
+ return Schema.fromAST(self.ast.omit(Vector.from(keys)));
560
+ };
561
+ }
@@ -51,7 +51,7 @@ export function deriveStruct<A extends Record<string, any>>(
51
51
  ? [optionalFields: {}]
52
52
  : [
53
53
  optionalFields: {
54
- [k in OptionalKeys<A>]: Schema<NonNullable<A[k]>>;
54
+ [k in OptionalKeys<A>]: Schema<A[k]>;
55
55
  },
56
56
  ]),
57
57
  ...([MaybeKeys<A>] extends [never]
package/_src/Schema.ts CHANGED
@@ -7,7 +7,9 @@ export * from "./Schema/api.js";
7
7
 
8
8
  /* eslint-disable simple-import-sort/exports */
9
9
  // codegen:start { preset: barrel, include: ./Schema/api/*.ts }
10
+ export * from "./Schema/api/set.js";
10
11
  export * from "./Schema/api/maybe.js";
12
+ export * from "./Schema/api/map.js";
11
13
  export * from "./Schema/api/list.js";
12
14
  export * from "./Schema/api/immutableArray.js";
13
15
  export * from "./Schema/api/hashSet.js";
package/_src/Show.ts CHANGED
@@ -1,169 +1,117 @@
1
- import type { TemplateLiteral, TemplateLiteralSpan } from "@fncts/schema/AST";
1
+ import type {
2
+ Element,
3
+ Refinement,
4
+ StringKeyword,
5
+ SymbolKeyword,
6
+ TemplateLiteral,
7
+ TemplateLiteralSpan,
8
+ Tuple,
9
+ TypeLiteral,
10
+ } from "@fncts/schema/AST";
2
11
 
3
12
  import { globalValue } from "@fncts/base/data/Global";
4
13
  import { ASTTag } from "@fncts/schema/AST";
5
- import { ASTAnnotation } from "@fncts/schema/ASTAnnotation";
6
- import { memoize } from "@fncts/schema/utils";
14
+ import { formatUnknown } from "@fncts/schema/utils";
7
15
 
8
- const showMemoMap = globalValue(Symbol.for("fncts.schema.Guard.showMemoMap"), () => new WeakMap<AST, Eval<string>>());
16
+ const showMemoMap = globalValue(Symbol.for("fncts.schema.Guard.showMemoMap"), () => new WeakMap<AST, string>());
17
+ const showMemoMapVerbose = globalValue(
18
+ Symbol.for("fncts.schema.Guard.showMemoMapVerbose"),
19
+ () => new WeakMap<AST, string>(),
20
+ );
9
21
 
10
- function goMemo(ast: AST): Eval<string> {
11
- const memo = showMemoMap.get(ast);
22
+ function goMemo(ast: AST, verbose: boolean): string {
23
+ const memoMap = verbose ? showMemoMapVerbose : showMemoMap;
24
+ const memo = memoMap.get(ast);
12
25
  if (memo) {
13
26
  return memo;
14
27
  }
15
- const s = go(ast);
16
- showMemoMap.set(ast, s);
28
+ const s = go(ast, verbose);
29
+ memoMap.set(ast, s);
17
30
  return s;
18
31
  }
19
32
 
20
33
  /**
21
- * @tsplus getter fncts.schema.Schema show
34
+ * @tsplus pipeable fncts.schema.Schema show
22
35
  */
23
- export function show<A>(self: Schema<A>): string {
24
- const ev = goMemo(self.ast);
25
- return ev.run;
36
+ export function show(verbose: boolean = false) {
37
+ return <A>(self: Schema<A>): string => goMemo(self.ast, verbose);
26
38
  }
27
39
 
28
- function go(ast: AST): Eval<string> {
40
+ /**
41
+ * @tsplus pipeable fncts.schema.AST show
42
+ */
43
+ export function showAST(verbose: boolean = false) {
44
+ return (self: AST): string => goMemo(self, verbose);
45
+ }
46
+
47
+ function go(ast: AST, verbose: boolean): string {
29
48
  AST.concrete(ast);
30
49
  switch (ast._tag) {
31
50
  case ASTTag.Declaration: {
32
- return ast.annotations.get(ASTAnnotation.Identifier).match(
33
- () => Eval.now("Unknown Type"),
34
- (id) => {
35
- return ast.typeParameters
36
- .traverse(Eval.Applicative)(goMemo)
37
- .map((ts) => {
38
- if (ts.length <= 0) {
39
- return id;
40
- } else {
41
- return `${id}<${ts.join(", ")}>`;
42
- }
43
- });
44
- },
45
- );
46
- }
47
- case ASTTag.Literal: {
48
- if (ast.literal === null) {
49
- return Eval.now("null");
50
- } else {
51
- return Eval.now(ast.literal.toString());
52
- }
51
+ return ast.getFormattedExpected(verbose).getOrElse("<declaration schema>");
53
52
  }
53
+ case ASTTag.Literal:
54
+ return ast.getFormattedExpected(verbose).getOrElse(formatUnknown(ast.literal));
54
55
  case ASTTag.UniqueSymbol:
55
- return Eval.now(ast.symbol.toString());
56
+ return ast.getFormattedExpected(verbose).getOrElse(formatUnknown(ast.symbol));
56
57
  case ASTTag.UndefinedKeyword:
57
- return Eval.now("undefined");
58
+ return ast.getFormattedExpected(verbose).getOrElse("undefined");
58
59
  case ASTTag.VoidKeyword:
59
- return Eval.now("void");
60
+ return ast.getFormattedExpected(verbose).getOrElse("void");
60
61
  case ASTTag.NeverKeyword:
61
- return Eval.now("never");
62
+ return ast.getFormattedExpected(verbose).getOrElse("never");
62
63
  case ASTTag.UnknownKeyword:
63
- return Eval.now("unknown");
64
+ return ast.getFormattedExpected(verbose).getOrElse("unknown");
64
65
  case ASTTag.AnyKeyword:
65
- return Eval.now("any");
66
+ return ast.getFormattedExpected(verbose).getOrElse("any");
66
67
  case ASTTag.StringKeyword:
67
- return Eval.now("string");
68
+ return ast.getFormattedExpected(verbose).getOrElse("string");
68
69
  case ASTTag.NumberKeyword:
69
- return Eval.now("number");
70
+ return ast.getFormattedExpected(verbose).getOrElse("number");
70
71
  case ASTTag.BooleanKeyword:
71
- return Eval.now("boolean");
72
+ return ast.getFormattedExpected(verbose).getOrElse("boolean");
72
73
  case ASTTag.BigIntKeyword:
73
- return Eval.now("bigint");
74
+ return ast.getFormattedExpected(verbose).getOrElse("bigint");
74
75
  case ASTTag.SymbolKeyword:
75
- return Eval.now("symbol");
76
+ return ast.getFormattedExpected(verbose).getOrElse("symbol");
76
77
  case ASTTag.ObjectKeyword:
77
- return Eval.now("object");
78
+ return ast.getFormattedExpected(verbose).getOrElse("object");
78
79
  case ASTTag.TemplateLiteral:
79
- return Eval.now("`" + formatTemplateLiteral(ast) + "`");
80
- case ASTTag.Tuple:
81
- return Do((Δ) => {
82
- const elements = Δ(ast.elements.traverse(Eval.Applicative)((element) => goMemo(element.type)));
83
- const restElements = Δ(
84
- ast.rest.match(
85
- () => Eval.now(Vector.empty<string>()),
86
- (rest) => rest.traverse(Eval.Applicative)(goMemo),
87
- ),
88
- );
89
-
90
- return Δ(
91
- Eval(() => {
92
- if (elements.length === 0 && restElements.length === 1) {
93
- if (ast.isReadonly) {
94
- return `ReadonlyArray<${restElements[0]}>`;
95
- } else {
96
- return `Array<${restElements[0]}>`;
97
- }
98
- }
99
-
100
- const prefix = (ast.isReadonly ? "readonly " : "") + "[" + elements.join(", ");
101
- const middle = restElements.length > 0 ? ", " : "";
102
- const suffix = restElements.map((s) => `...${s}`).join(", ") + "]";
103
- return prefix + middle + suffix;
104
- }),
105
- );
106
- });
107
- case ASTTag.TypeLiteral:
108
- return Do((Δ) => {
109
- const propertySignatures = Δ(ast.propertySignatures.traverse(Eval.Applicative)((ps) => goMemo(ps.type)));
110
- const indexSignatures = Δ(
111
- ast.indexSignatures.traverse(Eval.Applicative)((is) => goMemo(is.parameter).zip(goMemo(is.type))),
112
- );
113
-
114
- const required: Array<[PropertyKey, string]> = [];
115
- const optional: Array<[PropertyKey, string]> = [];
116
-
117
- ast.propertySignatures.forEachWithIndex((i, ps) => {
118
- const name = ps.name;
119
- if (!ps.isOptional) {
120
- required.push([name, propertySignatures[i]!]);
121
- } else {
122
- optional.push([name, propertySignatures[i]!]);
123
- }
124
- });
125
-
126
- const prefix = "{";
127
- const properties = required
128
- .concat(optional)
129
- .sort(([k1], [k2]) => k1.toLocaleString().localeCompare(k2.toLocaleString()))
130
- .map(([propertyKey, type]) => `${String(propertyKey)}: ${type}`)
131
- .join(", ");
132
- const index = indexSignatures.map(([param, type]) => `[x: ${param}]: ${type}`).join(", ");
133
- const suffix = "}";
134
-
135
- return prefix + " " + properties + (index.length === 0 ? "" : ", ") + index + " " + suffix;
136
- });
137
- case ASTTag.Union:
138
- return ast.types
139
- .traverse(Eval.Applicative)(goMemo)
140
- .map((ts) => ts.join(" | "));
80
+ return ast.getFormattedExpected(verbose).getOrElse(formatTemplateLiteral(ast));
81
+ case ASTTag.Tuple: {
82
+ return ast.getFormattedExpected(verbose).getOrElse(formatTuple(ast, verbose));
83
+ }
84
+ case ASTTag.TypeLiteral: {
85
+ return ast.getFormattedExpected(verbose).getOrElse(formatTypeLiteral(ast, verbose));
86
+ }
87
+ case ASTTag.Union: {
88
+ return ast.getFormattedExpected(verbose).getOrElse(ast.types.map((ast) => goMemo(ast, verbose)).join(" | "));
89
+ }
141
90
  case ASTTag.Lazy: {
142
- const f = () => goMemo(ast.getAST());
143
- const get = memoize<void, Eval<string>>(f);
144
- return Eval.defer(() => get());
91
+ return ast
92
+ .getFormattedExpected(verbose)
93
+ .orElse(Maybe.tryCatch(ast.getAST).flatMap((ast) => ast.getFormattedExpected(verbose)))
94
+ .getOrElse("<lazy schema>");
145
95
  }
146
96
  case ASTTag.Enum: {
147
- return Eval.now(ast.enums.map(([name]) => name).join(" | "));
97
+ return ast
98
+ .getFormattedExpected(verbose)
99
+ .getOrElse(
100
+ `<enum ${ast.enums.length} values(s): ${ast.enums.map(([_, value]) => JSON.stringify(value)).join(" | ")}`,
101
+ );
148
102
  }
149
103
  case ASTTag.Refinement: {
150
- return ast.annotations.get(ASTAnnotation.Identifier).match(
151
- () => goMemo(ast.from).map((from) => `Refined<${from}>`),
152
- (id) => Eval.now(id),
153
- );
104
+ return ast.getFormattedExpected(verbose).getOrElse(`{ ${goMemo(ast.from, verbose)} | filter }`);
105
+ }
106
+ case ASTTag.Transform: {
107
+ return ast
108
+ .getFormattedExpected(verbose)
109
+ .getOrElse(`(${goMemo(ast.from, verbose)} <-> ${goMemo(ast.to, verbose)})`);
154
110
  }
155
- case ASTTag.Transform:
156
- return goMemo(ast.to);
157
111
  case ASTTag.Validation: {
158
- return goMemo(ast.from).map((from) => {
159
- const validationNames = ast.validation.map((v) => v.name).join(" & ");
160
-
161
- if (validationNames.length <= 0) {
162
- return from;
163
- }
164
-
165
- return `${from} & ${validationNames}`;
166
- });
112
+ return ast
113
+ .getFormattedExpected(verbose)
114
+ .getOrElse(`${goMemo(ast.from, verbose)} (${ast.validation.map((v) => v.name).join(" & ")})`);
167
115
  }
168
116
  }
169
117
  }
@@ -178,5 +126,85 @@ function formatTemplateLiteralSpan(span: TemplateLiteralSpan): string {
178
126
  }
179
127
 
180
128
  function formatTemplateLiteral(ast: TemplateLiteral): string {
181
- return ast.head + ast.spans.map((span) => formatTemplateLiteralSpan(span) + span.literal).join("");
129
+ return "`" + ast.head + ast.spans.map((span) => formatTemplateLiteralSpan(span) + span.literal).join("") + "`";
130
+ }
131
+
132
+ function formatElement(ast: Element, verbose: boolean): string {
133
+ return goMemo(ast.type, verbose) + (ast.isOptional ? "?" : "");
134
+ }
135
+
136
+ function getParameterBase(
137
+ self: StringKeyword | SymbolKeyword | TemplateLiteral | Refinement,
138
+ ): StringKeyword | SymbolKeyword | TemplateLiteral {
139
+ switch (self._tag) {
140
+ case ASTTag.StringKeyword:
141
+ case ASTTag.SymbolKeyword:
142
+ case ASTTag.TemplateLiteral:
143
+ return self;
144
+ case ASTTag.Refinement:
145
+ return getParameterBase(self);
146
+ }
147
+ }
148
+
149
+ function formatTuple(ast: Tuple, verbose: boolean): string {
150
+ const formattedElements = ast.elements.map((element) => formatElement(element, verbose)).join(", ");
151
+ return ast.rest
152
+ .filter((rest) => rest.isNonEmpty())
153
+ .match(
154
+ () => `${ast.isReadonly ? "readonly " : ""}[${formattedElements}]`,
155
+ (rest) => {
156
+ const head = rest.unsafeHead!;
157
+ const tail = rest.tail;
158
+ const formattedHead = goMemo(head, verbose);
159
+ const wrappedHead = formattedHead.includes(" | ") ? `(${formattedHead})` : formattedHead;
160
+
161
+ if (tail.length > 0) {
162
+ const formattedTail = tail.map((ast) => goMemo(ast, verbose)).join(", ");
163
+ if (ast.elements.length > 0) {
164
+ return `${ast.isReadonly ? "readonly " : " "}[${formattedElements}, ...${wrappedHead}[], ${formattedTail}]`;
165
+ } else {
166
+ return `${ast.isReadonly ? "readonly " : " "}[...${wrappedHead}[], ${formattedTail}]`;
167
+ }
168
+ } else {
169
+ if (ast.elements.length > 0) {
170
+ return `${ast.isReadonly ? "readonly " : " "}[${formattedElements}, ...${wrappedHead}[]]`;
171
+ } else {
172
+ return `${ast.isReadonly ? "Readonly" : ""}Array<${formattedHead}>`;
173
+ }
174
+ }
175
+ },
176
+ );
177
+ }
178
+
179
+ function formatTypeLiteral(ast: TypeLiteral, verbose: boolean): string {
180
+ const formattedPropertySignatures = ast.propertySignatures
181
+ .map(
182
+ (ps) =>
183
+ (ps.isReadonly ? "readonly " : "") +
184
+ String(ps.name) +
185
+ (ps.isOptional ? "?" : "") +
186
+ ": " +
187
+ goMemo(ps.type, verbose),
188
+ )
189
+ .join("; ");
190
+ if (ast.indexSignatures.length > 0) {
191
+ const formattedIndexSignatures = ast.indexSignatures
192
+ .map(
193
+ (is) =>
194
+ (is.isReadonly ? "readonly " : "") +
195
+ `[x: ${goMemo(getParameterBase(is.parameter), verbose)}]: ${goMemo(is.type, verbose)}`,
196
+ )
197
+ .join("; ");
198
+ if (ast.propertySignatures.length > 0) {
199
+ return `{ ${formattedPropertySignatures}; ${formattedIndexSignatures} }`;
200
+ } else {
201
+ return `{ ${formattedIndexSignatures} }`;
202
+ }
203
+ } else {
204
+ if (ast.propertySignatures.length > 0) {
205
+ return `{ ${formattedPropertySignatures} }`;
206
+ } else {
207
+ return "{}";
208
+ }
209
+ }
182
210
  }
package/_src/global.ts CHANGED
@@ -39,10 +39,6 @@ import { ASTAnnotationMap } from "@fncts/schema/ASTAnnotationMap";
39
39
  * @tsplus global
40
40
  */
41
41
  import { ParseError } from "@fncts/schema/ParseError";
42
- /**
43
- * @tsplus global
44
- */
45
- import { ParseFailure } from "@fncts/schema/ParseFailure";
46
42
  /**
47
43
  * @tsplus global
48
44
  */
package/_src/utils.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import type { IndexSignature, TemplateLiteral } from "./AST";
2
2
 
3
3
  import { ASTTag } from "./AST.js";
4
+ import { showWithOptions } from "@fncts/base/data/Showable";
4
5
 
5
6
  export function memoize<A, B>(f: (a: A) => B): (a: A) => B {
6
7
  const cache = new Map();
@@ -46,3 +47,7 @@ export function getKeysForIndexSignature(
46
47
  return getKeysForIndexSignature(input, parameter.from as any);
47
48
  }
48
49
  }
50
+
51
+ export function formatUnknown(u: unknown): string {
52
+ return showWithOptions(u, {});
53
+ }
package/global.d.ts CHANGED
@@ -38,10 +38,6 @@ import { ASTAnnotationMap } from "@fncts/schema/ASTAnnotationMap";
38
38
  * @tsplus global
39
39
  */
40
40
  import { ParseError } from "@fncts/schema/ParseError";
41
- /**
42
- * @tsplus global
43
- */
44
- import { ParseFailure } from "@fncts/schema/ParseFailure";
45
41
  /**
46
42
  * @tsplus global
47
43
  */
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@fncts/schema",
3
- "version": "0.0.15",
3
+ "version": "0.0.17",
4
4
  "dependencies": {
5
- "@fncts/base": "0.0.35",
5
+ "@fncts/base": "0.0.36",
6
6
  "@fncts/typelevel": "0.0.18"
7
7
  },
8
8
  "exports": {
package/utils.d.ts CHANGED
@@ -6,3 +6,4 @@ export declare function getTemplateLiteralRegex(ast: TemplateLiteral): RegExp;
6
6
  export declare function getKeysForIndexSignature(input: {
7
7
  readonly [x: PropertyKey]: unknown;
8
8
  }, parameter: IndexSignature["parameter"]): Vector<string> | Vector<symbol>;
9
+ export declare function formatUnknown(u: unknown): string;
package/ParseFailure.d.ts DELETED
@@ -1,18 +0,0 @@
1
- import { Vector } from "@fncts/base/collection/immutable/Vector";
2
- import { ParseError } from "@fncts/schema/ParseError";
3
- export declare const ParseFailureTypeId: unique symbol;
4
- export type ParseFailureTypeId = typeof ParseFailureTypeId;
5
- /**
6
- * @tsplus type fncts.schema.ParseFailure
7
- * @tsplus companion fncts.schema.ParseFailureOps
8
- */
9
- export declare class ParseFailure {
10
- readonly errors: Vector<ParseError>;
11
- readonly [ParseFailureTypeId]: ParseFailureTypeId;
12
- constructor(errors: Vector<ParseError>);
13
- }
14
- /**
15
- * @tsplus static fncts.schema.ParseFailureOps __call
16
- * @tsplus location "@fncts/schema/ParseFailure"
17
- */
18
- export declare function make(errors: Vector<ParseError>): ParseFailure;
@@ -1,28 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.ParseFailureTypeId = exports.ParseFailure = void 0;
7
- exports.make = make;
8
- var _a;
9
- const ParseFailureTypeId = exports.ParseFailureTypeId = /*#__PURE__*/Symbol.for("fncts.schema.ParseFailure");
10
- /**
11
- * @tsplus type fncts.schema.ParseFailure
12
- * @tsplus companion fncts.schema.ParseFailureOps
13
- */
14
- class ParseFailure {
15
- constructor(errors) {
16
- this.errors = errors;
17
- this[_a] = ParseFailureTypeId;
18
- }
19
- }
20
- exports.ParseFailure = ParseFailure;
21
- _a = ParseFailureTypeId;
22
- /**
23
- * @tsplus static fncts.schema.ParseFailureOps __call
24
- */
25
- function make(errors) {
26
- return new ParseFailure(errors);
27
- }
28
- //# sourceMappingURL=ParseFailure.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ParseFailure.cjs","names":["ParseFailureTypeId","exports","Symbol","for","ParseFailure","constructor","errors","_a","make"],"sources":["../_src/ParseFailure.ts"],"sourcesContent":[null],"mappings":";;;;;;;;AAAO,MAAMA,kBAAkB,GAAAC,OAAA,CAAAD,kBAAA,gBAAGE,MAAM,CAACC,GAAG,CAAC,2BAA2B,CAAC;AAGzE;;;;AAIM,MAAOC,YAAY;EAEvBC,YAAqBC,MAA0B;IAA1B,KAAAA,MAAM,GAANA,MAAM;IADlB,KAAAC,EAAA,CAAoB,GAAuBP,kBAAkB;EACpB;;AACnDC,OAAA,CAAAG,YAAA,GAAAA,YAAA;KAFWJ,kBAAkB;AAI9B;;;AAGM,SAAUQ,IAAIA,CAACF,MAA0B;EAC7C,OAAO,IAAIF,YAAY,CAACE,MAAM,CAAC;AACjC"}
@@ -1,20 +0,0 @@
1
- var _a;
2
- export const ParseFailureTypeId = /*#__PURE__*/Symbol.for("fncts.schema.ParseFailure");
3
- /**
4
- * @tsplus type fncts.schema.ParseFailure
5
- * @tsplus companion fncts.schema.ParseFailureOps
6
- */
7
- export class ParseFailure {
8
- constructor(errors) {
9
- this.errors = errors;
10
- this[_a] = ParseFailureTypeId;
11
- }
12
- }
13
- _a = ParseFailureTypeId;
14
- /**
15
- * @tsplus static fncts.schema.ParseFailureOps __call
16
- */
17
- export function make(errors) {
18
- return new ParseFailure(errors);
19
- }
20
- //# sourceMappingURL=ParseFailure.mjs.map