@fncts/schema 0.0.5 → 0.0.6

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 (151) hide show
  1. package/AST.d.ts +528 -0
  2. package/ASTAnnotation.d.ts +82 -0
  3. package/ASTAnnotationMap.d.ts +14 -0
  4. package/Gen.d.ts +15 -0
  5. package/InvalidInterpretationError.d.ts +5 -0
  6. package/ParseError.d.ts +107 -0
  7. package/ParseResult.d.ts +24 -0
  8. package/Parser/api.d.ts +42 -0
  9. package/Parser/definition.d.ts +22 -0
  10. package/Parser/interpreter.d.ts +6 -0
  11. package/Parser.d.ts +2 -0
  12. package/Schema/api/conc.d.ts +18 -0
  13. package/Schema/api/hashMap.d.ts +21 -0
  14. package/Schema/api/immutableArray.d.ts +23 -0
  15. package/Schema/api/list.d.ts +23 -0
  16. package/Schema/api/maybe.d.ts +21 -0
  17. package/Schema/api.d.ts +243 -0
  18. package/Schema/definition.d.ts +29 -0
  19. package/Schema/derivations.d.ts +70 -0
  20. package/Schema.d.ts +2 -144
  21. package/_cjs/AST.cjs +1171 -0
  22. package/_cjs/AST.cjs.map +1 -0
  23. package/_cjs/ASTAnnotation.cjs +111 -0
  24. package/_cjs/ASTAnnotation.cjs.map +1 -0
  25. package/_cjs/ASTAnnotationMap.cjs +35 -0
  26. package/_cjs/ASTAnnotationMap.cjs.map +1 -0
  27. package/_cjs/Gen.cjs +185 -0
  28. package/_cjs/Gen.cjs.map +1 -0
  29. package/_cjs/InvalidInterpretationError.cjs +18 -0
  30. package/_cjs/InvalidInterpretationError.cjs.map +1 -0
  31. package/_cjs/ParseError.cjs +222 -0
  32. package/_cjs/ParseError.cjs.map +1 -0
  33. package/_cjs/{Decoder.cjs → ParseResult.cjs} +24 -22
  34. package/_cjs/ParseResult.cjs.map +1 -0
  35. package/_cjs/Parser/api.cjs +80 -0
  36. package/_cjs/Parser/api.cjs.map +1 -0
  37. package/_cjs/{Guard.cjs → Parser/definition.cjs} +17 -22
  38. package/_cjs/Parser/definition.cjs.map +1 -0
  39. package/_cjs/Parser/interpreter.cjs +409 -0
  40. package/_cjs/Parser/interpreter.cjs.map +1 -0
  41. package/_cjs/Parser.cjs +28 -0
  42. package/_cjs/Parser.cjs.map +1 -0
  43. package/_cjs/Schema/api/conc.cjs +84 -0
  44. package/_cjs/Schema/api/conc.cjs.map +1 -0
  45. package/_cjs/Schema/api/hashMap.cjs +161 -0
  46. package/_cjs/Schema/api/hashMap.cjs.map +1 -0
  47. package/_cjs/Schema/api/immutableArray.cjs +90 -0
  48. package/_cjs/Schema/api/immutableArray.cjs.map +1 -0
  49. package/_cjs/Schema/api/list.cjs +98 -0
  50. package/_cjs/Schema/api/list.cjs.map +1 -0
  51. package/_cjs/Schema/api/maybe.cjs +75 -0
  52. package/_cjs/Schema/api/maybe.cjs.map +1 -0
  53. package/_cjs/Schema/api.cjs +424 -0
  54. package/_cjs/Schema/api.cjs.map +1 -0
  55. package/_cjs/Schema/definition.cjs +26 -0
  56. package/_cjs/Schema/definition.cjs.map +1 -0
  57. package/_cjs/Schema/derivations.cjs +108 -0
  58. package/_cjs/Schema/derivations.cjs.map +1 -0
  59. package/_cjs/Schema.cjs +20 -237
  60. package/_cjs/Schema.cjs.map +1 -1
  61. package/_cjs/utils.cjs +52 -0
  62. package/_cjs/utils.cjs.map +1 -0
  63. package/_mjs/AST.mjs +1060 -0
  64. package/_mjs/AST.mjs.map +1 -0
  65. package/_mjs/ASTAnnotation.mjs +80 -0
  66. package/_mjs/ASTAnnotation.mjs.map +1 -0
  67. package/_mjs/ASTAnnotationMap.mjs +27 -0
  68. package/_mjs/ASTAnnotationMap.mjs.map +1 -0
  69. package/_mjs/Gen.mjs +176 -0
  70. package/_mjs/Gen.mjs.map +1 -0
  71. package/_mjs/InvalidInterpretationError.mjs +10 -0
  72. package/_mjs/InvalidInterpretationError.mjs.map +1 -0
  73. package/_mjs/ParseError.mjs +200 -0
  74. package/_mjs/ParseError.mjs.map +1 -0
  75. package/_mjs/ParseResult.mjs +21 -0
  76. package/_mjs/ParseResult.mjs.map +1 -0
  77. package/_mjs/Parser/api.mjs +67 -0
  78. package/_mjs/Parser/api.mjs.map +1 -0
  79. package/_mjs/Parser/definition.mjs +15 -0
  80. package/_mjs/Parser/definition.mjs.map +1 -0
  81. package/_mjs/Parser/interpreter.mjs +401 -0
  82. package/_mjs/Parser/interpreter.mjs.map +1 -0
  83. package/_mjs/Parser.mjs +4 -0
  84. package/_mjs/Parser.mjs.map +1 -0
  85. package/_mjs/Schema/api/conc.mjs +72 -0
  86. package/_mjs/Schema/api/conc.mjs.map +1 -0
  87. package/_mjs/Schema/api/hashMap.mjs +150 -0
  88. package/_mjs/Schema/api/hashMap.mjs.map +1 -0
  89. package/_mjs/Schema/api/immutableArray.mjs +79 -0
  90. package/_mjs/Schema/api/immutableArray.mjs.map +1 -0
  91. package/_mjs/Schema/api/list.mjs +87 -0
  92. package/_mjs/Schema/api/list.mjs.map +1 -0
  93. package/_mjs/Schema/api/maybe.mjs +64 -0
  94. package/_mjs/Schema/api/maybe.mjs.map +1 -0
  95. package/_mjs/Schema/api.mjs +367 -0
  96. package/_mjs/Schema/api.mjs.map +1 -0
  97. package/_mjs/Schema/definition.mjs +16 -0
  98. package/_mjs/Schema/definition.mjs.map +1 -0
  99. package/_mjs/Schema/derivations.mjs +94 -0
  100. package/_mjs/Schema/derivations.mjs.map +1 -0
  101. package/_mjs/Schema.mjs +3 -212
  102. package/_mjs/Schema.mjs.map +1 -1
  103. package/_mjs/utils.mjs +41 -0
  104. package/_mjs/utils.mjs.map +1 -0
  105. package/_src/AST.ts +1353 -0
  106. package/_src/ASTAnnotation.ts +98 -0
  107. package/_src/ASTAnnotationMap.ts +38 -0
  108. package/_src/Gen.ts +171 -0
  109. package/_src/InvalidInterpretationError.ts +6 -0
  110. package/_src/ParseError.ts +237 -0
  111. package/_src/ParseResult.ts +26 -0
  112. package/_src/Parser/api.ts +71 -0
  113. package/_src/Parser/definition.ts +24 -0
  114. package/_src/Parser/interpreter.ts +442 -0
  115. package/_src/Parser.ts +4 -0
  116. package/_src/Schema/api/conc.ts +78 -0
  117. package/_src/Schema/api/hashMap.ts +184 -0
  118. package/_src/Schema/api/immutableArray.ts +88 -0
  119. package/_src/Schema/api/list.ts +96 -0
  120. package/_src/Schema/api/maybe.ts +68 -0
  121. package/_src/Schema/api.ts +530 -0
  122. package/_src/Schema/definition.ts +32 -0
  123. package/_src/Schema/derivations.ts +185 -0
  124. package/_src/Schema.ts +4 -254
  125. package/_src/global.ts +53 -0
  126. package/_src/utils.ts +48 -0
  127. package/global.d.ts +52 -0
  128. package/package.json +2 -2
  129. package/utils.d.ts +8 -0
  130. package/Decoder.d.ts +0 -3
  131. package/Encoder.d.ts +0 -4
  132. package/Guard.d.ts +0 -3
  133. package/Schemable.d.ts +0 -39
  134. package/_cjs/Decoder.cjs.map +0 -1
  135. package/_cjs/Encoder.cjs +0 -45
  136. package/_cjs/Encoder.cjs.map +0 -1
  137. package/_cjs/Guard.cjs.map +0 -1
  138. package/_cjs/Schemable.cjs +0 -6
  139. package/_cjs/Schemable.cjs.map +0 -1
  140. package/_mjs/Decoder.mjs +0 -20
  141. package/_mjs/Decoder.mjs.map +0 -1
  142. package/_mjs/Encoder.mjs +0 -36
  143. package/_mjs/Encoder.mjs.map +0 -1
  144. package/_mjs/Guard.mjs +0 -20
  145. package/_mjs/Guard.mjs.map +0 -1
  146. package/_mjs/Schemable.mjs +0 -2
  147. package/_mjs/Schemable.mjs.map +0 -1
  148. package/_src/Decoder.ts +0 -20
  149. package/_src/Encoder.ts +0 -38
  150. package/_src/Guard.ts +0 -20
  151. package/_src/Schemable.ts +0 -46
@@ -0,0 +1,442 @@
1
+ import type { Literal } from "../AST.js";
2
+ import type { Hook } from "../ASTAnnotation.js";
3
+ import type { MutableVector } from "@fncts/base/collection/immutable/Vector";
4
+ import type { Validation } from "@fncts/base/data/Branded";
5
+
6
+ import {
7
+ isBigInt,
8
+ isBoolean,
9
+ isNumber,
10
+ isObject,
11
+ isRecord,
12
+ isString,
13
+ isSymbol,
14
+ isUndefined,
15
+ } from "@fncts/base/util/predicates";
16
+
17
+ import { ASTTag, concrete } from "../AST.js";
18
+ import { getKeysForIndexSignature, getTemplateLiteralRegex, memoize, ownKeys } from "../utils.js";
19
+
20
+ const go = memoize(function go(ast: AST): Parser<any> {
21
+ concrete(ast);
22
+ switch (ast._tag) {
23
+ case ASTTag.Declaration:
24
+ return Parser.make(ast.decode(...ast.typeParameters));
25
+ case ASTTag.Literal:
26
+ return Parser.fromRefinement(ast, (u): u is typeof ast.literal => u === ast.literal);
27
+ case ASTTag.UniqueSymbol:
28
+ return Parser.fromRefinement(ast, (u): u is typeof ast.symbol => u === ast.symbol);
29
+ case ASTTag.UndefinedKeyword:
30
+ case ASTTag.VoidKeyword:
31
+ return Parser.fromRefinement(ast, isUndefined);
32
+ case ASTTag.NeverKeyword:
33
+ return Parser.fromRefinement<any>(ast, (_): _ is never => false);
34
+ case ASTTag.UnknownKeyword:
35
+ case ASTTag.AnyKeyword:
36
+ return Parser.make(ParseResult.succeed);
37
+ case ASTTag.StringKeyword:
38
+ return Parser.fromRefinement(ast, isString);
39
+ case ASTTag.NumberKeyword:
40
+ return Parser.fromRefinement(ast, isNumber);
41
+ case ASTTag.BooleanKeyword:
42
+ return Parser.fromRefinement(ast, isBoolean);
43
+ case ASTTag.BigIntKeyword:
44
+ return Parser.fromRefinement(ast, isBigInt);
45
+ case ASTTag.SymbolKeyword:
46
+ return Parser.fromRefinement(ast, isSymbol);
47
+ case ASTTag.ObjectKeyword:
48
+ return Parser.fromRefinement(ast, isObject);
49
+ case ASTTag.Enum:
50
+ return Parser.fromRefinement(ast, (u): u is any => ast.enums.some(([_, value]) => value === u));
51
+ case ASTTag.TemplateLiteral: {
52
+ const regex = getTemplateLiteralRegex(ast);
53
+ return Parser.fromRefinement(ast, (u): u is any => isString(u) && regex.test(u));
54
+ }
55
+ case ASTTag.Tuple: {
56
+ const elements = ast.elements.map((e) => go(e.type));
57
+ const rest = ast.rest.map((rest) => rest.map(go));
58
+ return Parser.make((input, options) => {
59
+ if (!Array.isArray(input)) {
60
+ return ParseResult.fail(ParseError.TypeError(unknownArray, input));
61
+ }
62
+ const output: Array<any> = [];
63
+ const errors: MutableVector<ParseError> = Vector.emptyPushable();
64
+ const allErrors = options?.allErrors;
65
+ let i = 0;
66
+ for (; i < elements.length; i++) {
67
+ if (input.length < i + i) {
68
+ if (!ast.elements[i]!.isOptional) {
69
+ const e = ParseError.IndexError(i, Vector(ParseError.MissingError));
70
+ errors.push(e);
71
+ if (allErrors) {
72
+ continue;
73
+ } else {
74
+ return ParseResult.failures(errors);
75
+ }
76
+ } else {
77
+ const parser = elements[i]!;
78
+ const t = parser(input[i], options);
79
+ Either.concrete(t);
80
+ if (t.isLeft()) {
81
+ const e = ParseError.IndexError(i, t.left);
82
+ errors.push(e);
83
+ if (allErrors) {
84
+ continue;
85
+ } else {
86
+ return ParseResult.failures(errors);
87
+ }
88
+ }
89
+ output.push(t.right);
90
+ }
91
+ }
92
+ }
93
+ if (rest.isJust()) {
94
+ const head = rest.value.unsafeHead!;
95
+ const tail = rest.value.tail;
96
+ for (; i < input.length - tail.length; i++) {
97
+ const t = head(input[i], options);
98
+ Either.concrete(t);
99
+ if (t.isLeft()) {
100
+ const e = ParseError.IndexError(i, t.left);
101
+ errors.push(e);
102
+ if (allErrors) {
103
+ continue;
104
+ } else {
105
+ return ParseResult.failures(errors);
106
+ }
107
+ }
108
+ output.push(t.right);
109
+ }
110
+ for (let j = 0; j < tail.length; j++) {
111
+ i += j;
112
+ if (input.length < i + 1) {
113
+ errors.push(ParseError.IndexError(i, Vector(ParseError.MissingError)));
114
+ return ParseResult.failures(errors);
115
+ } else {
116
+ const t = tail[j]!(input[i], options);
117
+ Either.concrete(t);
118
+ if (t.isLeft()) {
119
+ const e = ParseError.IndexError(i, t.left);
120
+ errors.push(e);
121
+ if (allErrors) {
122
+ continue;
123
+ } else {
124
+ return ParseResult.failures(errors);
125
+ }
126
+ }
127
+ output.push(t.right);
128
+ }
129
+ }
130
+ } else {
131
+ const isUnexpectedAllowed = options?.isUnexpectedAllowed;
132
+ for (; i < input.length; i++) {
133
+ const e = ParseError.IndexError(i, Vector(ParseError.UnexpectedError(input[i])));
134
+ if (!isUnexpectedAllowed) {
135
+ errors.push(e);
136
+ if (allErrors) {
137
+ continue;
138
+ } else {
139
+ return ParseResult.failures(errors);
140
+ }
141
+ }
142
+ }
143
+ }
144
+ return errors.isNonEmpty() ? ParseResult.failures(errors) : ParseResult.succeed(output);
145
+ });
146
+ }
147
+ case ASTTag.TypeLiteral: {
148
+ if (ast.propertySignatures.length === 0 && ast.indexSignatures.length === 0) {
149
+ return Parser.fromRefinement(ast, (u): u is Exclude<typeof u, null> => u !== null);
150
+ }
151
+ const propertySignatureTypes = ast.propertySignatures.map((f) => go(f.type));
152
+ const indexSignatures = ast.indexSignatures.map((is) => [go(is.parameter), go(is.type)] as const);
153
+ return Parser.make((input, options) => {
154
+ if (!isRecord(input)) {
155
+ return ParseResult.fail(ParseError.TypeError(unknownRecord, input));
156
+ }
157
+ const output: any = {};
158
+ const expectedKeys: any = {};
159
+ const errors: MutableVector<ParseError> = Vector.emptyPushable();
160
+ const allErrors = options?.allErrors;
161
+
162
+ for (let i = 0; i < propertySignatureTypes.length; i++) {
163
+ const ps = ast.propertySignatures[i]!;
164
+ const parser = propertySignatureTypes[i]!;
165
+ const name = ps.name;
166
+ expectedKeys[name] = null;
167
+ if (!Object.prototype.hasOwnProperty.call(input, name)) {
168
+ if (!ps.isOptional) {
169
+ const e = ParseError.KeyError(AST.createKey(name), name, Vector(ParseError.MissingError));
170
+ errors.push(e);
171
+ if (allErrors) {
172
+ continue;
173
+ } else {
174
+ return ParseResult.failures(errors);
175
+ }
176
+ }
177
+ } else {
178
+ const t: ParseResult<unknown> = parser(input[name], options);
179
+ Either.concrete(t);
180
+ if (t.isLeft()) {
181
+ const e = ParseError.KeyError(AST.createKey(name), name, t.left);
182
+ errors.push(e);
183
+ if (allErrors) {
184
+ continue;
185
+ } else {
186
+ return ParseResult.failures(errors);
187
+ }
188
+ }
189
+ output[name] = t.right;
190
+ }
191
+ }
192
+
193
+ if (indexSignatures.length > 0) {
194
+ for (let i = 0; i < indexSignatures.length; i++) {
195
+ const [parameter, type] = indexSignatures[i]!;
196
+ const keys = getKeysForIndexSignature(input, ast.indexSignatures[i]!.parameter);
197
+ for (const key of keys) {
198
+ if (Object.prototype.hasOwnProperty.call(expectedKeys, key)) {
199
+ continue;
200
+ }
201
+
202
+ let t = parameter(key, options);
203
+ Either.concrete(t);
204
+ if (t.isLeft()) {
205
+ const e = ParseError.KeyError(AST.createKey(key), key, t.left);
206
+ errors.push(e);
207
+ if (allErrors) {
208
+ continue;
209
+ } else {
210
+ return ParseResult.failures(errors);
211
+ }
212
+ }
213
+
214
+ t = type(input[key], options);
215
+ Either.concrete(t);
216
+ if (t.isLeft()) {
217
+ const e = ParseError.KeyError(AST.createKey(key), key, t.left);
218
+ errors.push(e);
219
+ if (allErrors) {
220
+ continue;
221
+ } else {
222
+ return ParseResult.failures(errors);
223
+ }
224
+ }
225
+
226
+ output[key] = t.right;
227
+ }
228
+ }
229
+ } else {
230
+ const isUnexpectedAllowed = options?.isUnexpectedAllowed;
231
+ for (const key of ownKeys(input)) {
232
+ if (!Object.prototype.hasOwnProperty.call(expectedKeys, key)) {
233
+ const e = ParseError.KeyError(AST.createKey(key), key, Vector(ParseError.UnexpectedError(input[key])));
234
+ if (!isUnexpectedAllowed) {
235
+ errors.push(e);
236
+ if (allErrors) {
237
+ continue;
238
+ } else {
239
+ return ParseResult.failures(errors);
240
+ }
241
+ }
242
+ }
243
+ }
244
+ }
245
+
246
+ return errors.isNonEmpty() ? ParseResult.failures(errors) : ParseResult.succeed(output);
247
+ });
248
+ }
249
+ case ASTTag.Union: {
250
+ const searchTree = getSearchTree(ast.types);
251
+ const ownKeys = Reflect.ownKeys(searchTree.keys);
252
+ const len = ownKeys.length;
253
+ const otherwise = searchTree.otherwise;
254
+ const map = new Map<any, Parser<any>>();
255
+ ast.types.forEach((ast) => {
256
+ map.set(ast, go(ast));
257
+ });
258
+ return Parser.make((input, options) => {
259
+ const errors = Vector.emptyPushable<ParseError>();
260
+ if (len > 0) {
261
+ if (isRecord(input)) {
262
+ for (let i = 0; i < len; i++) {
263
+ const name = ownKeys[i]!;
264
+ const buckets = searchTree.keys[name]!.buckets;
265
+ if (Object.prototype.hasOwnProperty.call(input, name)) {
266
+ const literal = String(input[name]);
267
+ if (Object.prototype.hasOwnProperty.call(buckets, literal)) {
268
+ const bucket: ReadonlyArray<AST> = buckets[literal]!;
269
+ for (let i = 0; i < bucket.length; i++) {
270
+ const t = map.get(bucket[i])!(input, options);
271
+ Either.concrete(t);
272
+ if (t.isRight()) {
273
+ return t;
274
+ } else {
275
+ errors.push(ParseError.UnionMemberError(t.left));
276
+ }
277
+ }
278
+ } else {
279
+ errors.push(
280
+ ParseError.KeyError(
281
+ AST.createKey(name),
282
+ name,
283
+ Vector(ParseError.TypeError(searchTree.keys[name]!.ast, input[name])),
284
+ ),
285
+ );
286
+ }
287
+ } else {
288
+ errors.push(ParseError.KeyError(AST.createKey(name), name, Vector(ParseError.MissingError)));
289
+ }
290
+ }
291
+ } else {
292
+ errors.push(ParseError.TypeError(unknownRecord, input));
293
+ }
294
+ }
295
+ for (let i = 0; i < otherwise.length; i++) {
296
+ const t = map.get(otherwise[i])!(input, options);
297
+ Either.concrete(t);
298
+ if (t.isRight()) {
299
+ return t;
300
+ } else {
301
+ errors.push(ParseError.UnionMemberError(t.left));
302
+ }
303
+ }
304
+
305
+ return errors.isNonEmpty()
306
+ ? ParseResult.failures(errors)
307
+ : ParseResult.fail(ParseError.TypeError(AST.neverKeyword, input));
308
+ });
309
+ }
310
+ case ASTTag.Lazy: {
311
+ const f = () => go(ast.getAST());
312
+ const get = memoize<void, Parser<any>>(f);
313
+ return Parser.make((a, options) => get()(a, options));
314
+ }
315
+ case ASTTag.Refinement: {
316
+ const from = go(ast.from);
317
+ if (ast.isReversed) {
318
+ const to = go(ast.from.getTo);
319
+ return Parser.make((input, options) =>
320
+ to(input, options)
321
+ .flatMap((a) => ast.decode(a, options))
322
+ .flatMap((a) => from(a, options)),
323
+ );
324
+ }
325
+ return Parser.make((input, options) => from(input, options).flatMap((a) => ast.decode(a, options)));
326
+ }
327
+ case ASTTag.Transform: {
328
+ const from = go(ast.from);
329
+ if (ast.isReversed) {
330
+ const to = go(ast.to);
331
+ return Parser.make((input, options) =>
332
+ to(input, options)
333
+ .flatMap((a) => ast.encode(a, options))
334
+ .flatMap((a) => from(a, options)),
335
+ );
336
+ }
337
+ return Parser.make((input, options) => from(input, options).flatMap((a) => ast.decode(a, options)));
338
+ }
339
+ case ASTTag.Validation: {
340
+ return Parser.make((u, options) => {
341
+ const missedBrands = Vector.emptyPushable<Validation<any, string>>();
342
+ const allErrors = options?.allErrors;
343
+ for (const validation of ast.validation) {
344
+ if (!validation.validate(u)) {
345
+ missedBrands.push(validation);
346
+ if (allErrors) {
347
+ continue;
348
+ } else {
349
+ return ParseResult.fail(
350
+ ParseError.TypeError(AST.createValidation(ast.from, missedBrands, ast.annotations), u),
351
+ );
352
+ }
353
+ }
354
+ }
355
+ return missedBrands.length > 0
356
+ ? ParseResult.fail(ParseError.TypeError(AST.createValidation(ast.from, missedBrands, ast.annotations), u))
357
+ : ParseResult.succeed(u);
358
+ });
359
+ }
360
+ }
361
+ });
362
+
363
+ export function parserFor(ast: AST): Parser<any> {
364
+ return go(ast);
365
+ }
366
+
367
+ const unknownArray = AST.createTuple(Vector.empty(), Just(Vector(AST.unknownKeyword)), true);
368
+
369
+ const unknownRecord = AST.createTypeLiteral(
370
+ Vector.empty(),
371
+ Vector(
372
+ AST.createIndexSignature(AST.stringKeyword, AST.unknownKeyword, true),
373
+ AST.createIndexSignature(AST.symbolKeyword, AST.unknownKeyword, true),
374
+ ),
375
+ );
376
+
377
+ function getLiterals(ast: AST): ReadonlyArray<[PropertyKey, Literal]> {
378
+ AST.concrete(ast);
379
+ switch (ast._tag) {
380
+ case ASTTag.Declaration:
381
+ return getLiterals(ast.type);
382
+ case ASTTag.TypeLiteral: {
383
+ const out: Array<[PropertyKey, Literal]> = [];
384
+ for (let i = 0; i < ast.propertySignatures.length; i++) {
385
+ const propertySignature = ast.propertySignatures[i]!;
386
+ if (propertySignature.type.isLiteral() && !propertySignature.isOptional) {
387
+ out.push([propertySignature.name, propertySignature.type]);
388
+ }
389
+ }
390
+ return out;
391
+ }
392
+ case ASTTag.Refinement:
393
+ return getLiterals(ast.from);
394
+ case ASTTag.Transform:
395
+ return ast.isReversed ? getLiterals(ast.to) : getLiterals(ast.from.getFrom);
396
+ }
397
+ return [];
398
+ }
399
+
400
+ function getSearchTree(members: Vector<AST>): {
401
+ keys: {
402
+ readonly [key: PropertyKey]: {
403
+ buckets: { [literal: string]: ReadonlyArray<AST> };
404
+ ast: AST;
405
+ };
406
+ };
407
+ otherwise: ReadonlyArray<AST>;
408
+ } {
409
+ const keys: {
410
+ [key: PropertyKey]: {
411
+ buckets: { [literal: string]: Array<AST> };
412
+ ast: AST;
413
+ };
414
+ } = {};
415
+ const otherwise: Array<AST> = [];
416
+ for (let i = 0; i < members.length; i++) {
417
+ const member = members[i]!;
418
+ const tags = getLiterals(member);
419
+ if (tags.length > 0) {
420
+ for (let j = 0; j < tags.length; j++) {
421
+ const [key, literal] = tags[j]!;
422
+ const hash = String(literal.literal);
423
+ keys[key]! ||= { buckets: {}, ast: AST.neverKeyword };
424
+ const buckets = keys[key]!.buckets;
425
+ if (Object.prototype.hasOwnProperty.call(buckets, hash)) {
426
+ if (j < tags.length - 1) {
427
+ continue;
428
+ }
429
+ buckets[hash]!.push(member);
430
+ keys[key]!.ast = AST.createUnion(Vector(keys[key]!.ast, literal));
431
+ } else {
432
+ buckets[hash]! = [member];
433
+ keys[key]!.ast = AST.createUnion(Vector(keys[key]!.ast, literal));
434
+ break;
435
+ }
436
+ }
437
+ } else {
438
+ otherwise.push(member);
439
+ }
440
+ }
441
+ return { keys, otherwise };
442
+ }
package/_src/Parser.ts ADDED
@@ -0,0 +1,4 @@
1
+ // codegen:start { preset: barrel, include: ./Parser/*.ts }
2
+ export * from "./Parser/definition.js";
3
+ export * from "./Parser/interpreter.js";
4
+ // codegen:end
@@ -0,0 +1,78 @@
1
+ import type { Sized } from "@fncts/test/control/Sized";
2
+
3
+ import { ConcTypeId } from "@fncts/base/collection/immutable/Conc";
4
+
5
+ export function conc<A>(value: Schema<A>): Schema<Conc<A>> {
6
+ return Schema.declaration(
7
+ Vector(value),
8
+ inline(value),
9
+ concParser,
10
+ ASTAnnotationMap.empty.annotate(ASTAnnotation.Identifier, "Conc").annotate(ASTAnnotation.GenHook, gen),
11
+ );
12
+ }
13
+
14
+ /**
15
+ * @tsplus static fncts.schema.SchemaOps concFromArray
16
+ */
17
+ export function concFromArray<A>(value: Schema<A>): Schema<Conc<A>> {
18
+ return Schema.array(value).transform(
19
+ conc(value),
20
+ (input) => Conc.fromArray(input),
21
+ (input) => input.toArray,
22
+ );
23
+ }
24
+
25
+ /**
26
+ * @tsplus derive fncts.schema.Schema[fncts.Conc]<_> 10
27
+ */
28
+ export function deriveConc<A extends Conc<any>>(
29
+ ...[value]: [A] extends [Conc<infer _A>]
30
+ ? Check<Check.IsEqual<A, Conc<_A>>> extends Check.True
31
+ ? [value: Schema<_A>]
32
+ : never
33
+ : never
34
+ ): Schema<A> {
35
+ return unsafeCoerce(concFromArray(value));
36
+ }
37
+
38
+ export function concParser<A>(value: Schema<A>): Parser<Conc<A>> {
39
+ const schema = conc(value);
40
+ return Parser.make((u, options) => {
41
+ if (!Conc.is(u)) {
42
+ return ParseResult.fail(ParseError.TypeError(schema.ast, u));
43
+ }
44
+ const allErrors = options?.allErrors;
45
+ const errors = Vector.emptyPushable<ParseError>();
46
+ const out: Array<A> = [];
47
+ let i = 0;
48
+ for (const v of u) {
49
+ const t = value.decode(u);
50
+ Either.concrete(t);
51
+ if (t.isLeft()) {
52
+ errors.push(ParseError.IndexError(i, t.left));
53
+ if (!allErrors) {
54
+ return ParseResult.failures(errors);
55
+ }
56
+ } else {
57
+ out.push(t.right);
58
+ }
59
+ i++;
60
+ }
61
+ return errors.isNonEmpty() ? ParseResult.failures(errors) : ParseResult.succeed(Conc.fromArray(out));
62
+ });
63
+ }
64
+
65
+ function inline<A>(_value: Schema<A>): Schema<Conc<A>> {
66
+ return Schema.struct({
67
+ _A: Schema.any,
68
+ [ConcTypeId]: Schema.uniqueSymbol(ConcTypeId),
69
+ length: Schema.number,
70
+ [Symbol.iterator]: Schema.any,
71
+ [Symbol.hash]: Schema.any,
72
+ [Symbol.equals]: Schema.any,
73
+ });
74
+ }
75
+
76
+ function gen<A>(value: Gen<Sized, A>): Gen<Sized, Conc<A>> {
77
+ return Gen.conc(value);
78
+ }
@@ -0,0 +1,184 @@
1
+ import type {
2
+ ArrayNode,
3
+ CollisionNode,
4
+ EmptyNode,
5
+ IndexedNode,
6
+ LeafNode,
7
+ } from "@fncts/base/collection/immutable/HashMap/internal";
8
+ import type { Node } from "@fncts/base/collection/immutable/HashMap/internal";
9
+ import type { Sized } from "@fncts/test/control/Sized";
10
+ import type { Check } from "@fncts/typelevel";
11
+
12
+ import { HashMap } from "@fncts/base/collection/immutable/HashMap";
13
+ import { HashMapTypeId, HashMapVariance } from "@fncts/base/collection/immutable/HashMap";
14
+ import { ASTAnnotation } from "@fncts/schema/ASTAnnotation";
15
+
16
+ /**
17
+ * @tsplus static fncts.schema.SchemaOps hashMap
18
+ */
19
+ export function hashMap<K, V>(key: Schema<K>, value: Schema<V>): Schema<HashMap<K, V>> {
20
+ return Schema.declaration(
21
+ Vector(key, value),
22
+ inline(key, value),
23
+ hashMapParser,
24
+ ASTAnnotationMap.empty.annotate(ASTAnnotation.Identifier, "HashMap").annotate(ASTAnnotation.GenHook, gen),
25
+ );
26
+ }
27
+
28
+ /**
29
+ * @tsplus static fncts.schema.SchemaOps hashMapFromRecord
30
+ */
31
+ export function hashMapFromRecord<K extends string | symbol, V>(
32
+ key: Schema<K>,
33
+ value: Schema<V>,
34
+ ): Schema<HashMap<K, V>> {
35
+ return Schema.record(key, value).transform(
36
+ hashMap(key, value),
37
+ (input) => {
38
+ const out = HashMap.empty<K, V>().beginMutation;
39
+ for (const [k, v] of Object.entries(input)) {
40
+ out.set(k as K, v as V);
41
+ }
42
+ return out.endMutation;
43
+ },
44
+ (input) => {
45
+ const out = {} as Record<K, V>;
46
+ input.forEachWithIndex((k, v) => {
47
+ out[k] = v;
48
+ });
49
+ return out;
50
+ },
51
+ );
52
+ }
53
+
54
+ /**
55
+ * @tsplus derive fncts.schema.Schema[fncts.HashMap]<_> 10
56
+ */
57
+ export function deriveHashMap<A extends HashMap<any, any>>(
58
+ // @ts-expect-error
59
+ ...[key, value]: [A] extends [HashMap<infer K, infer V>]
60
+ ? Check<Check.IsEqual<A, HashMap<K, V>> & Check.Extends<K, string | symbol>> extends Check.True
61
+ ? [key: Schema<K>, value: Schema<V>]
62
+ : never
63
+ : never
64
+ ): Schema<A> {
65
+ return unsafeCoerce(hashMapFromRecord(key as Schema<string | symbol>, value));
66
+ }
67
+
68
+ function hashMapParser<K, V>(key: Schema<K>, value: Schema<V>): Parser<HashMap<K, V>> {
69
+ const schema = hashMap(key, value);
70
+ return Parser.make((u, options) => {
71
+ if (!HashMap.is(u)) {
72
+ return ParseResult.fail(ParseError.TypeError(schema.ast, u));
73
+ }
74
+ const allErrors = options?.allErrors;
75
+ const errors = Vector.emptyPushable<ParseError>();
76
+ const out = HashMap.empty<K, V>().beginMutation;
77
+ for (const [k, v] of u) {
78
+ const tk = key.decode(k, options);
79
+ Either.concrete(tk);
80
+ if (tk.isLeft()) {
81
+ errors.push(ParseError.KeyError(key.ast, k, tk.left));
82
+ if (!allErrors) {
83
+ return ParseResult.failures(errors);
84
+ }
85
+ }
86
+ const tv = value.decode(v, options);
87
+ Either.concrete(tv);
88
+ if (tv.isLeft()) {
89
+ errors.push(ParseError.KeyError(key.ast, k, tv.left));
90
+ if (!allErrors) {
91
+ return ParseResult.failures(errors);
92
+ }
93
+ }
94
+ if (tk.isLeft() || tv.isLeft()) {
95
+ continue;
96
+ }
97
+ out.set(tk.right, tv.right);
98
+ }
99
+ return errors.isNonEmpty() ? ParseResult.failures(errors) : ParseResult.succeed(out.endMutation);
100
+ });
101
+ }
102
+
103
+ function emptyNodeSchema<K, V>(_key: Schema<K>, _value: Schema<V>): Schema<EmptyNode<K, V>> {
104
+ return Schema.struct({
105
+ _tag: Schema.literal("EmptyNode"),
106
+ modify: Schema.any,
107
+ });
108
+ }
109
+
110
+ function leafNodeSchema<K, V>(key: Schema<K>, value: Schema<V>): Schema<LeafNode<K, V>> {
111
+ return Schema.struct({
112
+ _tag: Schema.literal("LeafNode"),
113
+ edit: Schema.number,
114
+ hash: Schema.number,
115
+ key,
116
+ value: value.maybe,
117
+ modify: Schema.any,
118
+ });
119
+ }
120
+
121
+ function collisionNodeSchema<K, V>(key: Schema<K>, value: Schema<V>): Schema<CollisionNode<K, V>> {
122
+ return Schema.lazy(() =>
123
+ Schema.struct({
124
+ _tag: Schema.literal("CollisionNode"),
125
+ edit: Schema.number,
126
+ hash: Schema.number,
127
+ children: nodeSchema(key, value).mutableArray,
128
+ modify: Schema.any,
129
+ }),
130
+ );
131
+ }
132
+
133
+ function indexedNodeSchema<K, V>(key: Schema<K>, value: Schema<V>): Schema<IndexedNode<K, V>> {
134
+ return Schema.lazy(() =>
135
+ Schema.struct({
136
+ _tag: Schema.literal("IndexedNode"),
137
+ edit: Schema.number,
138
+ mask: Schema.number,
139
+ children: nodeSchema(key, value).mutableArray,
140
+ modify: Schema.any,
141
+ }),
142
+ );
143
+ }
144
+
145
+ function arrayNodeSchema<K, V>(key: Schema<K>, value: Schema<V>): Schema<ArrayNode<K, V>> {
146
+ return Schema.lazy(() =>
147
+ Schema.struct({
148
+ _tag: Schema.literal("ArrayNode"),
149
+ edit: Schema.number,
150
+ size: Schema.number,
151
+ children: nodeSchema(key, value).mutableArray,
152
+ modify: Schema.any,
153
+ }),
154
+ );
155
+ }
156
+
157
+ function nodeSchema<K, V>(key: Schema<K>, value: Schema<V>): Schema<Node<K, V>> {
158
+ return Schema.union(
159
+ emptyNodeSchema(key, value),
160
+ leafNodeSchema(key, value),
161
+ collisionNodeSchema(key, value),
162
+ indexedNodeSchema(key, value),
163
+ arrayNodeSchema(key, value),
164
+ );
165
+ }
166
+
167
+ function inline<K, V>(key: Schema<K>, value: Schema<V>): Schema<HashMap<K, V>> {
168
+ return Schema.struct({
169
+ [HashMapTypeId]: Schema.uniqueSymbol(HashMapTypeId),
170
+ [HashMapVariance]: Schema.any,
171
+ editable: Schema.boolean,
172
+ edit: Schema.number,
173
+ config: Schema.any,
174
+ root: nodeSchema(key, value),
175
+ size: Schema.number,
176
+ [Symbol.iterator]: Schema.any,
177
+ [Symbol.hash]: Schema.any,
178
+ [Symbol.equals]: Schema.any,
179
+ });
180
+ }
181
+
182
+ function gen<K, V>(key: Gen<Sized, K>, value: Gen<Sized, V>): Gen<Sized, HashMap<K, V>> {
183
+ return Gen.array(Gen.tuple(key, value)).map((pairs) => HashMap.from(pairs));
184
+ }