typia 5.0.0-dev.20230823 → 5.0.0-dev.2023084

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 (217) hide show
  1. package/lib/Primitive.d.ts +14 -12
  2. package/lib/Resolved.d.ts +46 -0
  3. package/lib/{schemas/metadata/IMetadataResolved.js → Resolved.js} +1 -1
  4. package/lib/Resolved.js.map +1 -0
  5. package/lib/factories/MetadataFactory.d.ts +1 -1
  6. package/lib/factories/MetadataTagFactory.js +10 -8
  7. package/lib/factories/MetadataTagFactory.js.map +1 -1
  8. package/lib/factories/ProtobufFactory.js +4 -3
  9. package/lib/factories/ProtobufFactory.js.map +1 -1
  10. package/lib/factories/internal/metadata/emend_metadata_atomics.js +6 -6
  11. package/lib/factories/internal/metadata/emend_metadata_atomics.js.map +1 -1
  12. package/lib/factories/internal/metadata/explore_metadata.js +3 -3
  13. package/lib/factories/internal/metadata/explore_metadata.js.map +1 -1
  14. package/lib/factories/internal/metadata/iterate_metadata_atomic.js +1 -1
  15. package/lib/factories/internal/metadata/iterate_metadata_atomic.js.map +1 -1
  16. package/lib/factories/internal/metadata/iterate_metadata_collection.js +6 -6
  17. package/lib/factories/internal/metadata/iterate_metadata_collection.js.map +1 -1
  18. package/lib/factories/internal/metadata/iterate_metadata_native.js +2 -10
  19. package/lib/factories/internal/metadata/iterate_metadata_native.js.map +1 -1
  20. package/lib/factories/internal/metadata/iterate_metadata_resolve.js +6 -6
  21. package/lib/factories/internal/metadata/iterate_metadata_resolve.js.map +1 -1
  22. package/lib/factories/internal/metadata/iterate_metadata_sort.js +2 -2
  23. package/lib/factories/internal/metadata/iterate_metadata_sort.js.map +1 -1
  24. package/lib/functional/$ProtobufWriter.js.map +1 -1
  25. package/lib/json.d.ts +15 -15
  26. package/lib/misc.d.ts +42 -42
  27. package/lib/module.d.ts +18 -17
  28. package/lib/module.js +1 -0
  29. package/lib/module.js.map +1 -1
  30. package/lib/programmers/AssertProgrammer.js +1 -1
  31. package/lib/programmers/AssertProgrammer.js.map +1 -1
  32. package/lib/programmers/CheckerProgrammer.js +7 -7
  33. package/lib/programmers/CheckerProgrammer.js.map +1 -1
  34. package/lib/programmers/IsProgrammer.js +2 -2
  35. package/lib/programmers/IsProgrammer.js.map +1 -1
  36. package/lib/programmers/RandomProgrammer.js +311 -136
  37. package/lib/programmers/RandomProgrammer.js.map +1 -1
  38. package/lib/programmers/ValidateProgrammer.js +1 -1
  39. package/lib/programmers/ValidateProgrammer.js.map +1 -1
  40. package/lib/programmers/helpers/AtomicPredicator.js +2 -2
  41. package/lib/programmers/helpers/AtomicPredicator.js.map +1 -1
  42. package/lib/programmers/helpers/FunctionImporeter.d.ts +2 -0
  43. package/lib/programmers/helpers/FunctionImporeter.js +2 -1
  44. package/lib/programmers/helpers/FunctionImporeter.js.map +1 -1
  45. package/lib/programmers/helpers/ProtobufUtil.js +2 -2
  46. package/lib/programmers/helpers/ProtobufUtil.js.map +1 -1
  47. package/lib/programmers/helpers/StringifyPredicator.js +1 -2
  48. package/lib/programmers/helpers/StringifyPredicator.js.map +1 -1
  49. package/lib/programmers/helpers/disable_function_importer_declare.js +1 -0
  50. package/lib/programmers/helpers/disable_function_importer_declare.js.map +1 -1
  51. package/lib/programmers/internal/application_default_string.js +2 -2
  52. package/lib/programmers/internal/application_default_string.js.map +1 -1
  53. package/lib/programmers/internal/application_resolved.d.ts +2 -2
  54. package/lib/programmers/internal/application_resolved.js.map +1 -1
  55. package/lib/programmers/internal/application_schema.js +7 -7
  56. package/lib/programmers/internal/application_schema.js.map +1 -1
  57. package/lib/programmers/internal/metadata_to_pattern.js +4 -4
  58. package/lib/programmers/internal/metadata_to_pattern.js.map +1 -1
  59. package/lib/programmers/internal/stringify_dynamic_properties.js +2 -1
  60. package/lib/programmers/internal/stringify_dynamic_properties.js.map +1 -1
  61. package/lib/programmers/json/JsonStringifyProgrammer.js +20 -14
  62. package/lib/programmers/json/JsonStringifyProgrammer.js.map +1 -1
  63. package/lib/programmers/misc/MiscAssertCloneProgrammer.js +1 -1
  64. package/lib/programmers/misc/MiscAssertCloneProgrammer.js.map +1 -1
  65. package/lib/programmers/misc/MiscCloneProgrammer.js +114 -33
  66. package/lib/programmers/misc/MiscCloneProgrammer.js.map +1 -1
  67. package/lib/programmers/misc/MiscIsCloneProgrammer.js +1 -1
  68. package/lib/programmers/misc/MiscIsCloneProgrammer.js.map +1 -1
  69. package/lib/programmers/misc/MiscLiteralsProgrammer.js +3 -3
  70. package/lib/programmers/misc/MiscLiteralsProgrammer.js.map +1 -1
  71. package/lib/programmers/misc/MiscPruneProgrammer.js +2 -2
  72. package/lib/programmers/misc/MiscPruneProgrammer.js.map +1 -1
  73. package/lib/programmers/misc/MiscValidateCloneProgrammer.js +1 -1
  74. package/lib/programmers/misc/MiscValidateCloneProgrammer.js.map +1 -1
  75. package/lib/programmers/protobuf/ProtobufAssertDecodeProgrammer.js +3 -3
  76. package/lib/programmers/protobuf/ProtobufAssertDecodeProgrammer.js.map +1 -1
  77. package/lib/programmers/protobuf/ProtobufDecodeProgrammer.js +3 -3
  78. package/lib/programmers/protobuf/ProtobufDecodeProgrammer.js.map +1 -1
  79. package/lib/programmers/protobuf/ProtobufEncodeProgrammer.js +1 -1
  80. package/lib/programmers/protobuf/ProtobufEncodeProgrammer.js.map +1 -1
  81. package/lib/programmers/protobuf/ProtobufIsDecodeProgrammer.js +2 -2
  82. package/lib/programmers/protobuf/ProtobufIsDecodeProgrammer.js.map +1 -1
  83. package/lib/programmers/protobuf/ProtobufValidateDecodeProgrammer.js +1 -1
  84. package/lib/programmers/protobuf/ProtobufValidateDecodeProgrammer.js.map +1 -1
  85. package/lib/protobuf.d.ts +631 -10
  86. package/lib/protobuf.js +13 -13
  87. package/lib/protobuf.js.map +1 -1
  88. package/lib/schemas/metadata/IMetadata.d.ts +4 -4
  89. package/lib/schemas/metadata/IMetadataAtomic.d.ts +12 -0
  90. package/lib/schemas/metadata/IMetadataAtomic.js +3 -0
  91. package/lib/schemas/metadata/IMetadataAtomic.js.map +1 -0
  92. package/lib/schemas/metadata/{IMetadataResolved.d.ts → IMetadataEscaped.d.ts} +1 -1
  93. package/lib/schemas/metadata/IMetadataEscaped.js +3 -0
  94. package/lib/schemas/metadata/IMetadataEscaped.js.map +1 -0
  95. package/lib/schemas/metadata/Metadata.d.ts +4 -4
  96. package/lib/schemas/metadata/Metadata.js +64 -59
  97. package/lib/schemas/metadata/Metadata.js.map +1 -1
  98. package/lib/schemas/metadata/{MetadataResolved.d.ts → MetadataEscaped.d.ts} +3 -3
  99. package/lib/schemas/metadata/{MetadataResolved.js → MetadataEscaped.js} +11 -11
  100. package/lib/schemas/metadata/MetadataEscaped.js.map +1 -0
  101. package/lib/tags/ExclusiveMaximum.d.ts +8 -0
  102. package/lib/tags/ExclusiveMaximum.js +3 -0
  103. package/lib/tags/ExclusiveMaximum.js.map +1 -0
  104. package/lib/tags/ExclusiveMinimum.d.ts +8 -0
  105. package/lib/tags/ExclusiveMinimum.js +3 -0
  106. package/lib/tags/ExclusiveMinimum.js.map +1 -0
  107. package/lib/tags/Format.d.ts +8 -0
  108. package/lib/tags/Format.js +3 -0
  109. package/lib/tags/Format.js.map +1 -0
  110. package/lib/tags/MaxItems.d.ts +8 -0
  111. package/lib/tags/MaxItems.js +3 -0
  112. package/lib/tags/MaxItems.js.map +1 -0
  113. package/lib/tags/MaxLength.d.ts +8 -0
  114. package/lib/tags/MaxLength.js +3 -0
  115. package/lib/tags/MaxLength.js.map +1 -0
  116. package/lib/tags/Maximum.d.ts +8 -0
  117. package/lib/tags/Maximum.js +3 -0
  118. package/lib/tags/Maximum.js.map +1 -0
  119. package/lib/tags/MinItems.d.ts +8 -0
  120. package/lib/tags/MinItems.js +3 -0
  121. package/lib/tags/MinItems.js.map +1 -0
  122. package/lib/tags/MinLength.d.ts +8 -0
  123. package/lib/tags/MinLength.js +3 -0
  124. package/lib/tags/MinLength.js.map +1 -0
  125. package/lib/tags/Minimum.d.ts +8 -0
  126. package/lib/tags/Minimum.js +3 -0
  127. package/lib/tags/Minimum.js.map +1 -0
  128. package/lib/tags/MultipleOf.d.ts +8 -0
  129. package/lib/tags/MultipleOf.js +3 -0
  130. package/lib/tags/MultipleOf.js.map +1 -0
  131. package/lib/tags/Pattern.d.ts +8 -0
  132. package/lib/tags/Pattern.js +3 -0
  133. package/lib/tags/Pattern.js.map +1 -0
  134. package/lib/tags/TagBase.d.ts +10 -0
  135. package/lib/tags/TagBase.js +3 -0
  136. package/lib/tags/TagBase.js.map +1 -0
  137. package/lib/tags/Type.d.ts +13 -0
  138. package/lib/tags/Type.js +3 -0
  139. package/lib/tags/Type.js.map +1 -0
  140. package/lib/tags/index.d.ts +12 -0
  141. package/lib/tags/index.js +29 -0
  142. package/lib/tags/index.js.map +1 -0
  143. package/lib/transformers/features/json/JsonApplicationTransformer.js +2 -2
  144. package/lib/transformers/features/json/JsonApplicationTransformer.js.map +1 -1
  145. package/lib/transformers/features/misc/MetadataTransformer.js +1 -1
  146. package/lib/transformers/features/misc/MetadataTransformer.js.map +1 -1
  147. package/lib/utils/RandomGenerator.js +3 -2
  148. package/lib/utils/RandomGenerator.js.map +1 -1
  149. package/package.json +2 -1
  150. package/src/Primitive.ts +135 -131
  151. package/src/Resolved.ts +116 -0
  152. package/src/factories/MetadataFactory.ts +46 -46
  153. package/src/factories/MetadataTagFactory.ts +366 -364
  154. package/src/factories/ProtobufFactory.ts +268 -266
  155. package/src/factories/internal/metadata/emend_metadata_atomics.ts +35 -33
  156. package/src/factories/internal/metadata/explore_metadata.ts +38 -38
  157. package/src/factories/internal/metadata/iterate_metadata_atomic.ts +63 -59
  158. package/src/factories/internal/metadata/iterate_metadata_collection.ts +133 -133
  159. package/src/factories/internal/metadata/iterate_metadata_native.ts +210 -219
  160. package/src/factories/internal/metadata/iterate_metadata_resolve.ts +49 -49
  161. package/src/factories/internal/metadata/iterate_metadata_sort.ts +69 -69
  162. package/src/functional/$ProtobufWriter.ts +151 -151
  163. package/src/json.ts +648 -648
  164. package/src/misc.ts +651 -651
  165. package/src/module.ts +709 -708
  166. package/src/programmers/AssertProgrammer.ts +281 -279
  167. package/src/programmers/CheckerProgrammer.ts +1174 -1173
  168. package/src/programmers/IsProgrammer.ts +241 -239
  169. package/src/programmers/RandomProgrammer.ts +874 -578
  170. package/src/programmers/ValidateProgrammer.ts +307 -305
  171. package/src/programmers/helpers/AtomicPredicator.ts +31 -31
  172. package/src/programmers/helpers/FunctionImporeter.ts +91 -89
  173. package/src/programmers/helpers/ProtobufUtil.ts +29 -29
  174. package/src/programmers/helpers/StringifyPredicator.ts +12 -13
  175. package/src/programmers/helpers/disable_function_importer_declare.ts +32 -27
  176. package/src/programmers/internal/application_default_string.ts +37 -33
  177. package/src/programmers/internal/application_resolved.ts +55 -55
  178. package/src/programmers/internal/application_schema.ts +157 -157
  179. package/src/programmers/internal/metadata_to_pattern.ts +34 -34
  180. package/src/programmers/internal/stringify_dynamic_properties.ts +171 -171
  181. package/src/programmers/json/JsonStringifyProgrammer.ts +995 -987
  182. package/src/programmers/misc/MiscAssertCloneProgrammer.ts +71 -71
  183. package/src/programmers/misc/MiscCloneProgrammer.ts +775 -587
  184. package/src/programmers/misc/MiscIsCloneProgrammer.ts +78 -78
  185. package/src/programmers/misc/MiscLiteralsProgrammer.ts +64 -64
  186. package/src/programmers/misc/MiscPruneProgrammer.ts +544 -542
  187. package/src/programmers/misc/MiscValidateCloneProgrammer.ts +85 -85
  188. package/src/programmers/protobuf/ProtobufAssertDecodeProgrammer.ts +75 -66
  189. package/src/programmers/protobuf/ProtobufDecodeProgrammer.ts +673 -669
  190. package/src/programmers/protobuf/ProtobufEncodeProgrammer.ts +814 -814
  191. package/src/programmers/protobuf/ProtobufIsDecodeProgrammer.ts +85 -75
  192. package/src/programmers/protobuf/ProtobufValidateDecodeProgrammer.ts +75 -75
  193. package/src/protobuf.ts +881 -249
  194. package/src/schemas/metadata/IMetadata.ts +27 -28
  195. package/src/schemas/metadata/IMetadataAtomic.ts +13 -0
  196. package/src/schemas/metadata/{IMetadataResolved.ts → IMetadataEscaped.ts} +6 -6
  197. package/src/schemas/metadata/Metadata.ts +643 -637
  198. package/src/schemas/metadata/{MetadataResolved.ts → MetadataEscaped.ts} +51 -51
  199. package/src/tags/ExclusiveMaximum.ts +8 -0
  200. package/src/tags/ExclusiveMinimum.ts +8 -0
  201. package/src/tags/Format.ts +29 -0
  202. package/src/tags/MaxItems.ts +8 -0
  203. package/src/tags/MaxLength.ts +8 -0
  204. package/src/tags/Maximum.ts +8 -0
  205. package/src/tags/MinItems.ts +8 -0
  206. package/src/tags/MinLength.ts +8 -0
  207. package/src/tags/Minimum.ts +8 -0
  208. package/src/tags/MultipleOf.ts +10 -0
  209. package/src/tags/Pattern.ts +8 -0
  210. package/src/tags/TagBase.ts +17 -0
  211. package/src/tags/Type.ts +30 -0
  212. package/src/tags/index.ts +12 -0
  213. package/src/transformers/features/json/JsonApplicationTransformer.ts +111 -111
  214. package/src/transformers/features/misc/MetadataTransformer.ts +53 -53
  215. package/src/utils/RandomGenerator.ts +83 -81
  216. package/lib/schemas/metadata/IMetadataResolved.js.map +0 -1
  217. package/lib/schemas/metadata/MetadataResolved.js.map +0 -1
@@ -1,1173 +1,1174 @@
1
- import ts from "typescript";
2
-
3
- import { ExpressionFactory } from "../factories/ExpressionFactory";
4
- import { IdentifierFactory } from "../factories/IdentifierFactory";
5
- import { MetadataCollection } from "../factories/MetadataCollection";
6
- import { MetadataFactory } from "../factories/MetadataFactory";
7
- import { StatementFactory } from "../factories/StatementFactory";
8
- import { TypeFactory } from "../factories/TypeFactory";
9
- import { ValueFactory } from "../factories/ValueFactory";
10
-
11
- import { IJsDocTagInfo } from "../schemas/metadata/IJsDocTagInfo";
12
- import { IMetadataTag } from "../schemas/metadata/IMetadataTag";
13
- import { Metadata } from "../schemas/metadata/Metadata";
14
- import { MetadataArray } from "../schemas/metadata/MetadataArray";
15
- import { MetadataObject } from "../schemas/metadata/MetadataObject";
16
- import { MetadataTuple } from "../schemas/metadata/MetadataTuple";
17
-
18
- import { IProject } from "../transformers/IProject";
19
-
20
- import { FeatureProgrammer } from "./FeatureProgrammer";
21
- import { AtomicPredicator } from "./helpers/AtomicPredicator";
22
- import { FunctionImporter } from "./helpers/FunctionImporeter";
23
- import { ICheckEntry } from "./helpers/ICheckEntry";
24
- import { IExpressionEntry } from "./helpers/IExpressionEntry";
25
- import { OptionPredicator } from "./helpers/OptionPredicator";
26
- import { UnionExplorer } from "./helpers/UnionExplorer";
27
- import { check_array } from "./internal/check_array";
28
- import { check_array_length } from "./internal/check_array_length";
29
- import { check_bigint } from "./internal/check_bigint";
30
- import { check_native } from "./internal/check_native";
31
- import { check_number } from "./internal/check_number";
32
- import { check_string } from "./internal/check_string";
33
- import { check_template } from "./internal/check_template";
34
- import { decode_union_object } from "./internal/decode_union_object";
35
- import { wrap_metadata_rest_tuple } from "./internal/wrap_metadata_rest_tuple";
36
-
37
- export namespace CheckerProgrammer {
38
- export interface IConfig {
39
- prefix: string;
40
- path: boolean;
41
- trace: boolean;
42
- equals: boolean;
43
- numeric: boolean;
44
- addition?: () => ts.Statement[];
45
- decoder?: () => FeatureProgrammer.Decoder<Metadata, ts.Expression>;
46
- combiner: IConfig.Combiner;
47
- atomist: (
48
- explore: IExplore,
49
- ) => (check: ICheckEntry) => (input: ts.Expression) => ts.Expression;
50
- joiner: IConfig.IJoiner;
51
- success: ts.Expression;
52
- }
53
- export namespace IConfig {
54
- export interface Combiner {
55
- (explorer: IExplore): {
56
- (logic: "and" | "or"): {
57
- (
58
- input: ts.Expression,
59
- binaries: IBinary[],
60
- expected: string,
61
- ): ts.Expression;
62
- };
63
- };
64
- }
65
- export interface IJoiner {
66
- object(
67
- input: ts.Expression,
68
- entries: IExpressionEntry[],
69
- ): ts.Expression;
70
- array(input: ts.Expression, arrow: ts.ArrowFunction): ts.Expression;
71
- tuple?(exprs: ts.Expression[]): ts.Expression;
72
-
73
- failure(
74
- value: ts.Expression,
75
- expected: string,
76
- explore?: FeatureProgrammer.IExplore,
77
- ): ts.Expression;
78
- is?(expression: ts.Expression): ts.Expression;
79
- required?(exp: ts.Expression): ts.Expression;
80
- full?: (
81
- condition: ts.Expression,
82
- ) => (
83
- input: ts.Expression,
84
- expected: string,
85
- explore: IExplore,
86
- ) => ts.Expression;
87
- }
88
- }
89
- export type IExplore = FeatureProgrammer.IExplore;
90
-
91
- export interface IBinary {
92
- expression: ts.Expression;
93
- combined: boolean;
94
- }
95
-
96
- /* -----------------------------------------------------------
97
- WRITERS
98
- ----------------------------------------------------------- */
99
- export const write =
100
- (project: IProject) =>
101
- (config: IConfig) =>
102
- (importer: FunctionImporter) =>
103
- FeatureProgrammer.write(project)(
104
- configure(project)(config)(importer),
105
- )(importer);
106
-
107
- export const write_object_functions =
108
- (project: IProject) =>
109
- (config: IConfig) =>
110
- (importer: FunctionImporter) =>
111
- FeatureProgrammer.write_object_functions(
112
- configure(project)(config)(importer),
113
- )(importer);
114
-
115
- export const write_union_functions =
116
- (project: IProject) =>
117
- (config: IConfig) =>
118
- (importer: FunctionImporter) =>
119
- FeatureProgrammer.write_union_functions(
120
- configure(project)({ ...config, numeric: false })(importer),
121
- );
122
-
123
- export const write_array_functions =
124
- (project: IProject) =>
125
- (config: IConfig) =>
126
- (importer: FunctionImporter) =>
127
- (collection: MetadataCollection): ts.VariableStatement[] =>
128
- collection
129
- .arrays()
130
- .filter((a) => a.recursive)
131
- .map((array, i) =>
132
- StatementFactory.constant(
133
- `${config.prefix}a${i}`,
134
- ts.factory.createArrowFunction(
135
- undefined,
136
- undefined,
137
- FeatureProgrammer.parameterDeclarations(config)(
138
- TypeFactory.keyword("any"),
139
- )(ts.factory.createIdentifier("input")),
140
- TypeFactory.keyword("any"),
141
- undefined,
142
- decode_array_inline(project)(config)(importer)(
143
- ts.factory.createIdentifier("input"),
144
- array,
145
- {
146
- tracable: config.trace,
147
- source: "function",
148
- from: "array",
149
- postfix: "",
150
- },
151
- [],
152
- [],
153
- ),
154
- ),
155
- ),
156
- );
157
-
158
- export const write_tuple_functions =
159
- (project: IProject) =>
160
- (config: IConfig) =>
161
- (importer: FunctionImporter) =>
162
- (collection: MetadataCollection): ts.VariableStatement[] =>
163
- collection
164
- .tuples()
165
- .filter((t) => t.recursive)
166
- .map((tuple, i) =>
167
- StatementFactory.constant(
168
- `${config.prefix}t${i}`,
169
- ts.factory.createArrowFunction(
170
- undefined,
171
- undefined,
172
- FeatureProgrammer.parameterDeclarations(config)(
173
- TypeFactory.keyword("any"),
174
- )(ts.factory.createIdentifier("input")),
175
- TypeFactory.keyword("any"),
176
- undefined,
177
- decode_tuple_inline(project)(config)(importer)(
178
- ts.factory.createIdentifier("input"),
179
- tuple,
180
- {
181
- tracable: config.trace,
182
- source: "function",
183
- from: "array",
184
- postfix: "",
185
- },
186
- [],
187
- [],
188
- ),
189
- ),
190
- ),
191
- );
192
-
193
- const configure =
194
- (project: IProject) =>
195
- (config: IConfig) =>
196
- (importer: FunctionImporter): FeatureProgrammer.IConfig => ({
197
- types: {
198
- input: () => TypeFactory.keyword("any"),
199
- output: (type, name) =>
200
- ts.factory.createTypePredicateNode(
201
- undefined,
202
- "input",
203
- ts.factory.createTypeReferenceNode(
204
- name ??
205
- TypeFactory.getFullName(project.checker)(type),
206
- ),
207
- ),
208
- },
209
- trace: config.trace,
210
- path: config.path,
211
- prefix: config.prefix,
212
- initializer:
213
- ({ checker }) =>
214
- (type) => {
215
- const collection: MetadataCollection =
216
- new MetadataCollection();
217
- const meta: Metadata = MetadataFactory.analyze(checker)({
218
- resolve: false,
219
- constant: true,
220
- absorb: true,
221
- })(collection)(type);
222
- return [collection, meta];
223
- },
224
- addition: config.addition,
225
- decoder: () =>
226
- config.decoder?.() ?? decode(project)(config)(importer),
227
- objector: {
228
- checker: () =>
229
- config.decoder?.() ?? decode(project)(config)(importer),
230
- decoder: () => decode_object(config)(importer),
231
- joiner: config.joiner.object,
232
- unionizer: config.equals
233
- ? decode_union_object(decode_object(config)(importer))(
234
- (input, obj, explore) =>
235
- decode_object(config)(importer)(input, obj, {
236
- ...explore,
237
- tracable: true,
238
- }),
239
- )(config.joiner.is ?? ((expr) => expr))(
240
- (value, expected) =>
241
- ts.factory.createReturnStatement(
242
- config.joiner.failure(value, expected),
243
- ),
244
- )
245
- : (input, targets, explore) =>
246
- config.combiner(explore)("or")(
247
- input,
248
- targets.map((obj) => ({
249
- expression: decode_object(config)(importer)(
250
- input,
251
- obj,
252
- explore,
253
- ),
254
- combined: true,
255
- })),
256
- `(${targets.map((t) => t.name).join(" | ")})`,
257
- ),
258
- failure: (value, expected) =>
259
- ts.factory.createReturnStatement(
260
- config.joiner.failure(value, expected),
261
- ),
262
- is: config.joiner.is,
263
- required: config.joiner.required,
264
- full: config.joiner.full,
265
- type: TypeFactory.keyword("boolean"),
266
- },
267
- generator: {
268
- unions: config.numeric
269
- ? () =>
270
- FeatureProgrammer.write_union_functions(
271
- configure(project)({ ...config, numeric: false })(
272
- importer,
273
- ),
274
- )
275
- : undefined,
276
- arrays: () => write_array_functions(project)(config)(importer),
277
- tuples: () => write_tuple_functions(project)(config)(importer),
278
- },
279
- });
280
-
281
- /* -----------------------------------------------------------
282
- DECODERS
283
- ----------------------------------------------------------- */
284
- /**
285
- * @internal
286
- */
287
- export const decode =
288
- (project: IProject) =>
289
- (config: IConfig) =>
290
- (importer: FunctionImporter) =>
291
- (
292
- input: ts.Expression,
293
- meta: Metadata,
294
- explore: IExplore,
295
- metaTags: IMetadataTag[],
296
- jsDocTags: ts.JSDocTagInfo[],
297
- ): ts.Expression => {
298
- if (meta.any) return config.success;
299
-
300
- const top: IBinary[] = [];
301
- const binaries: IBinary[] = [];
302
- const add = create_add(binaries)(input);
303
- const getConstantValue = (
304
- value: number | string | bigint | boolean,
305
- ) =>
306
- typeof value === "string"
307
- ? ts.factory.createStringLiteral(value)
308
- : ts.factory.createIdentifier(value.toString());
309
-
310
- //----
311
- // CHECK OPTIONAL
312
- //----
313
- // @todo -> should be elaborated
314
- const checkOptional: boolean = meta.empty() || meta.isUnionBucket();
315
-
316
- // NULLABLE
317
- if (checkOptional || meta.nullable)
318
- (meta.nullable ? add : create_add(top)(input))(
319
- meta.nullable,
320
- ValueFactory.NULL(),
321
- );
322
-
323
- // UNDEFINDABLE
324
- if (checkOptional || !meta.isRequired())
325
- (meta.isRequired() ? create_add(top)(input) : add)(
326
- !meta.isRequired(),
327
- ValueFactory.UNDEFINED(),
328
- );
329
-
330
- // FUNCTIONAL
331
- if (meta.functional === true)
332
- if (
333
- OptionPredicator.functional(project.options) ||
334
- meta.size() !== 1
335
- )
336
- add(
337
- true,
338
- ts.factory.createStringLiteral("function"),
339
- ValueFactory.TYPEOF(input),
340
- );
341
- else
342
- binaries.push({
343
- combined: false,
344
- expression: config.success,
345
- });
346
-
347
- //----
348
- // VALUES
349
- //----
350
- // CONSTANT VALUES
351
- for (const constant of meta.constants)
352
- if (AtomicPredicator.constant(meta)(constant.type))
353
- for (const val of constant.values)
354
- add(true, getConstantValue(val));
355
-
356
- // ATOMIC VALUES
357
- for (const type of meta.atomics)
358
- if (AtomicPredicator.atomic(meta)(type) === false) continue;
359
- else if (type === "number")
360
- binaries.push({
361
- expression: config.atomist(explore)(
362
- check_number(project, config.numeric)(importer)(
363
- metaTags,
364
- )(jsDocTags)(input),
365
- )(input),
366
- combined: false,
367
- });
368
- else if (type === "bigint")
369
- binaries.push({
370
- expression: config.atomist(explore)(
371
- check_bigint(importer)(metaTags)(jsDocTags)(input),
372
- )(input),
373
- combined: false,
374
- });
375
- else if (type === "string")
376
- binaries.push({
377
- expression: config.atomist(explore)(
378
- check_string(importer)(metaTags)(jsDocTags)(input),
379
- )(input),
380
- combined: false,
381
- });
382
- else
383
- add(
384
- true,
385
- ts.factory.createStringLiteral(type),
386
- ValueFactory.TYPEOF(input),
387
- );
388
-
389
- // TEMPLATE LITERAL VALUES
390
- if (meta.templates.length)
391
- if (AtomicPredicator.template(meta))
392
- binaries.push({
393
- expression: config.atomist(explore)(
394
- check_template(importer)(metaTags)(jsDocTags)(
395
- meta.templates,
396
- )(input),
397
- )(input),
398
- combined: false,
399
- });
400
-
401
- // NATIVE CLASSES
402
- for (const native of meta.natives)
403
- binaries.push({
404
- expression: check_native(native)(input),
405
- combined: false,
406
- });
407
-
408
- //----
409
- // INSTANCES
410
- //----
411
- interface IInstance {
412
- pre: ts.Expression;
413
- body: ts.Expression | null;
414
- expected: string;
415
- }
416
- const instances: IInstance[] = [];
417
- const prepare =
418
- (pre: ts.Expression, expected: string) =>
419
- (body: ts.Expression | null) =>
420
- instances.push({
421
- pre,
422
- expected,
423
- body,
424
- });
425
-
426
- // SETS
427
- if (meta.sets.length) {
428
- const install = prepare(
429
- check_native("Set")(input),
430
- meta.sets
431
- .map((elem) => `Set<${elem.getName()}>`)
432
- .join(" | "),
433
- );
434
- if (meta.sets.some((elem) => elem.any)) install(null);
435
- else
436
- install(
437
- explore_sets(project)(config)(importer)(
438
- input,
439
- meta.sets,
440
- {
441
- ...explore,
442
- from: "array",
443
- },
444
- [],
445
- [],
446
- ),
447
- );
448
- }
449
-
450
- // MAPS
451
- if (meta.maps.length) {
452
- const install = prepare(
453
- check_native("Map")(input),
454
- meta.maps
455
- .map(({ key, value }) => `Map<${key}, ${value}>`)
456
- .join(" | "),
457
- );
458
- if (meta.maps.some((elem) => elem.key.any && elem.value.any))
459
- install(null);
460
- else
461
- install(
462
- explore_maps(project)(config)(importer)(
463
- input,
464
- meta.maps,
465
- {
466
- ...explore,
467
- from: "array",
468
- },
469
- metaTags,
470
- jsDocTags,
471
- ),
472
- );
473
- }
474
-
475
- // ARRAYS AND TUPLES
476
- if (meta.tuples.length + meta.arrays.length > 0) {
477
- const install = prepare(
478
- config.atomist(explore)(
479
- check_array(importer)(
480
- meta.tuples.length === 0 ? metaTags : [],
481
- )(jsDocTags)(input),
482
- )(input),
483
- [...meta.tuples, ...meta.arrays]
484
- .map((elem) => elem.name)
485
- .join(" | "),
486
- );
487
- if (meta.arrays.length === 0)
488
- if (meta.tuples.length === 1)
489
- install(
490
- decode_tuple(project)(config)(importer)(
491
- input,
492
- meta.tuples[0]!,
493
- {
494
- ...explore,
495
- from: "array",
496
- },
497
- metaTags,
498
- jsDocTags,
499
- ),
500
- );
501
- // TUPLE ONLY
502
- else
503
- install(
504
- explore_tuples(project)(config)(importer)(
505
- input,
506
- meta.tuples,
507
- {
508
- ...explore,
509
- from: "array",
510
- },
511
- metaTags,
512
- jsDocTags,
513
- ),
514
- );
515
- else if (meta.arrays.some((elem) => elem.value.any))
516
- install(null);
517
- else if (meta.tuples.length === 0)
518
- if (meta.arrays.length === 1)
519
- // ARRAY ONLY
520
- install(
521
- decode_array(project)(config)(importer)(
522
- input,
523
- meta.arrays[0]!,
524
- {
525
- ...explore,
526
- from: "array",
527
- },
528
- metaTags,
529
- jsDocTags,
530
- ),
531
- );
532
- else
533
- install(
534
- explore_arrays(project)(config)(importer)(
535
- input,
536
- meta.arrays,
537
- {
538
- ...explore,
539
- from: "array",
540
- },
541
- metaTags,
542
- jsDocTags,
543
- ),
544
- );
545
- else
546
- install(
547
- explore_arrays_and_tuples(project)(config)(importer)(
548
- input,
549
- [...meta.tuples, ...meta.arrays],
550
- explore,
551
- metaTags,
552
- jsDocTags,
553
- ),
554
- );
555
- }
556
-
557
- // OBJECT
558
- if (meta.objects.length > 0)
559
- prepare(
560
- ExpressionFactory.isObject({
561
- checkNull: true,
562
- checkArray: meta.objects.some((obj) =>
563
- obj.properties.every(
564
- (prop) =>
565
- !prop.key.isSoleLiteral() ||
566
- !prop.value.isRequired(),
567
- ),
568
- ),
569
- })(input),
570
- meta.objects.map((obj) => obj.name).join(" | "),
571
- )(
572
- explore_objects(config)(importer)(input, meta, {
573
- ...explore,
574
- from: "object",
575
- }),
576
- );
577
-
578
- if (instances.length) {
579
- const transformer =
580
- (
581
- merger: (
582
- x: ts.Expression,
583
- y: ts.Expression,
584
- ) => ts.Expression,
585
- ) =>
586
- (ins: IInstance) =>
587
- ins.body
588
- ? {
589
- expression: merger(ins.pre, ins.body),
590
- combined: true,
591
- }
592
- : {
593
- expression: ins.pre,
594
- combined: false,
595
- };
596
- if (instances.length === 1)
597
- binaries.push(
598
- transformer((pre, body) =>
599
- config.combiner(explore)("and")(
600
- input,
601
- [pre, body].map((expression) => ({
602
- expression,
603
- combined: expression !== pre,
604
- })),
605
- meta.getName(),
606
- ),
607
- )(instances[0]!),
608
- );
609
- else
610
- binaries.push({
611
- expression: config.combiner(explore)("or")(
612
- input,
613
- instances.map(
614
- transformer(ts.factory.createLogicalAnd),
615
- ),
616
- meta.getName(),
617
- ),
618
- combined: true,
619
- });
620
- }
621
-
622
- //----
623
- // COMBINE CONDITIONS
624
- //----
625
- return top.length && binaries.length
626
- ? config.combiner(explore)("and")(
627
- input,
628
- [
629
- ...top,
630
- {
631
- expression: config.combiner(explore)("or")(
632
- input,
633
- binaries,
634
- meta.getName(),
635
- ),
636
- combined: true,
637
- },
638
- ],
639
- meta.getName(),
640
- )
641
- : binaries.length
642
- ? config.combiner(explore)("or")(
643
- input,
644
- binaries,
645
- meta.getName(),
646
- )
647
- : config.success;
648
- };
649
-
650
- export const decode_object =
651
- (config: IConfig) => (importer: FunctionImporter) => {
652
- const func = FeatureProgrammer.decode_object(config)(importer);
653
- return (
654
- input: ts.Expression,
655
- obj: MetadataObject,
656
- explore: IExplore,
657
- ) => {
658
- obj.validated = true;
659
- return func(input, obj, explore);
660
- };
661
- };
662
-
663
- const decode_array =
664
- (project: IProject) =>
665
- (config: IConfig) =>
666
- (importer: FunctionImporter) =>
667
- (
668
- input: ts.Expression,
669
- array: MetadataArray,
670
- explore: IExplore,
671
- metaTags: IMetadataTag[],
672
- jsDocTags: IJsDocTagInfo[],
673
- ) => {
674
- if (array.recursive === false)
675
- return decode_array_inline(project)(config)(importer)(
676
- input,
677
- array,
678
- explore,
679
- metaTags,
680
- jsDocTags,
681
- );
682
-
683
- explore = {
684
- ...explore,
685
- source: "function",
686
- from: "array",
687
- };
688
- return ts.factory.createLogicalOr(
689
- ts.factory.createCallExpression(
690
- ts.factory.createIdentifier(
691
- importer.useLocal(`${config.prefix}a${array.index}`),
692
- ),
693
- undefined,
694
- FeatureProgrammer.argumentsArray(config)({
695
- ...explore,
696
- source: "function",
697
- from: "array",
698
- })(input),
699
- ),
700
- config.joiner.failure(input, array.name, explore),
701
- );
702
- };
703
-
704
- const decode_array_inline =
705
- (project: IProject) =>
706
- (config: IConfig) =>
707
- (importer: FunctionImporter) =>
708
- FeatureProgrammer.decode_array({
709
- prefix: config.prefix,
710
- trace: config.trace,
711
- path: config.path,
712
- decoder: () => decode(project)(config)(importer),
713
- })(importer)(config.joiner.array);
714
-
715
- const decode_tuple =
716
- (project: IProject) =>
717
- (config: IConfig) =>
718
- (importer: FunctionImporter) =>
719
- (
720
- input: ts.Expression,
721
- tuple: MetadataTuple,
722
- explore: IExplore,
723
- tagList: IMetadataTag[],
724
- jsDocTags: ts.JSDocTagInfo[],
725
- ): ts.Expression => {
726
- if (tuple.recursive === false)
727
- return decode_tuple_inline(project)(config)(importer)(
728
- input,
729
- tuple,
730
- explore,
731
- tagList,
732
- jsDocTags,
733
- );
734
- explore = {
735
- ...explore,
736
- source: "function",
737
- from: "array",
738
- };
739
- return ts.factory.createLogicalOr(
740
- ts.factory.createCallExpression(
741
- ts.factory.createIdentifier(
742
- importer.useLocal(`${config.prefix}t${tuple.index}`),
743
- ),
744
- undefined,
745
- FeatureProgrammer.argumentsArray(config)({
746
- ...explore,
747
- source: "function",
748
- })(input),
749
- ),
750
- config.joiner.failure(input, tuple.name, explore),
751
- );
752
- };
753
-
754
- const decode_tuple_inline =
755
- (project: IProject) =>
756
- (config: IConfig) =>
757
- (importer: FunctionImporter) =>
758
- (
759
- input: ts.Expression,
760
- tuple: MetadataTuple,
761
- explore: IExplore,
762
- tagList: IMetadataTag[],
763
- jsDocTags: ts.JSDocTagInfo[],
764
- ): ts.Expression => {
765
- const binaries: ts.Expression[] = tuple.elements
766
- .filter((meta) => meta.rest === null)
767
- .map((meta, index) =>
768
- decode(project)(config)(importer)(
769
- ts.factory.createElementAccessExpression(input, index),
770
- meta,
771
- {
772
- ...explore,
773
- from: "array",
774
- postfix: explore.postfix.length
775
- ? `${explore.postfix.slice(0, -1)}[${index}]"`
776
- : `"[${index}]"`,
777
- },
778
- tuple.of_map === true && index !== 1 ? [] : tagList,
779
- tuple.of_map === true && index !== 1 ? [] : jsDocTags,
780
- ),
781
- );
782
- const rest: ts.Expression | null =
783
- tuple.elements.length && tuple.elements.at(-1)!.rest !== null
784
- ? decode(project)(config)(importer)(
785
- ts.factory.createCallExpression(
786
- IdentifierFactory.access(input)("slice"),
787
- undefined,
788
- [
789
- ts.factory.createNumericLiteral(
790
- tuple.elements.length - 1,
791
- ),
792
- ],
793
- ),
794
- wrap_metadata_rest_tuple(
795
- tuple.elements.at(-1)!.rest!,
796
- ),
797
- {
798
- ...explore,
799
- start: tuple.elements.length - 1,
800
- },
801
- tagList,
802
- jsDocTags,
803
- )
804
- : null;
805
-
806
- const arrayLength = ts.factory.createPropertyAccessExpression(
807
- input,
808
- "length",
809
- );
810
- return config.combiner(explore)("and")(
811
- input,
812
- [
813
- ...(rest === null
814
- ? tuple.elements.every((t) => t.optional === false)
815
- ? [
816
- {
817
- combined: false,
818
- expression:
819
- ts.factory.createStrictEquality(
820
- arrayLength,
821
- ts.factory.createNumericLiteral(
822
- tuple.elements.length,
823
- ),
824
- ),
825
- },
826
- ]
827
- : [
828
- {
829
- combined: false,
830
- expression: ts.factory.createLogicalAnd(
831
- ts.factory.createLessThanEquals(
832
- ts.factory.createNumericLiteral(
833
- tuple.elements.filter(
834
- (t) =>
835
- t.optional === false,
836
- ).length,
837
- ),
838
- arrayLength,
839
- ),
840
- ts.factory.createGreaterThanEquals(
841
- ts.factory.createNumericLiteral(
842
- tuple.elements.length,
843
- ),
844
- arrayLength,
845
- ),
846
- ),
847
- },
848
- ]
849
- : []),
850
- ...(config.joiner.tuple
851
- ? [
852
- {
853
- expression: config.joiner.tuple(binaries),
854
- combined: true,
855
- },
856
- ]
857
- : binaries.map((expression) => ({
858
- expression,
859
- combined: true,
860
- }))),
861
- ...(rest !== null
862
- ? [
863
- {
864
- expression: rest,
865
- combined: true,
866
- },
867
- ]
868
- : []),
869
- ],
870
- `[${tuple.elements.map((t) => t.getName()).join(", ")}]`,
871
- );
872
- };
873
-
874
- /* -----------------------------------------------------------
875
- UNION TYPE EXPLORERS
876
- ----------------------------------------------------------- */
877
- const explore_sets =
878
- (project: IProject) =>
879
- (config: IConfig) =>
880
- (importer: FunctionImporter) =>
881
- (
882
- input: ts.Expression,
883
- sets: Metadata[],
884
- explore: IExplore,
885
- tags: IMetadataTag[],
886
- jsDocTags: IJsDocTagInfo[],
887
- ): ts.Expression =>
888
- ts.factory.createCallExpression(
889
- UnionExplorer.set({
890
- checker: decode(project)(config)(importer),
891
- decoder: decode_array(project)(config)(importer),
892
- empty: config.success,
893
- success: config.success,
894
- failure: (input, expected, explore) =>
895
- ts.factory.createReturnStatement(
896
- config.joiner.failure(input, expected, explore),
897
- ),
898
- })([])(input, sets, explore, tags, jsDocTags),
899
- undefined,
900
- undefined,
901
- );
902
-
903
- const explore_maps =
904
- (project: IProject) =>
905
- (config: IConfig) =>
906
- (importer: FunctionImporter) =>
907
- (
908
- input: ts.Expression,
909
- maps: Metadata.Entry[],
910
- explore: IExplore,
911
- tags: IMetadataTag[],
912
- jsDocTags: IJsDocTagInfo[],
913
- ): ts.Expression =>
914
- ts.factory.createCallExpression(
915
- UnionExplorer.map({
916
- checker: (input, entry, explore) => {
917
- const func = decode(project)(config)(importer);
918
- return ts.factory.createLogicalAnd(
919
- func(
920
- ts.factory.createElementAccessExpression(
921
- input,
922
- 0,
923
- ),
924
- entry[0],
925
- {
926
- ...explore,
927
- postfix: `${explore.postfix}[0]`,
928
- },
929
- [],
930
- [],
931
- ),
932
- func(
933
- ts.factory.createElementAccessExpression(
934
- input,
935
- 1,
936
- ),
937
- entry[1],
938
- {
939
- ...explore,
940
- postfix: `${explore.postfix}[1]`,
941
- },
942
- [],
943
- [],
944
- ),
945
- );
946
- },
947
- decoder: decode_array(project)(config)(importer),
948
- empty: config.success,
949
- success: config.success,
950
- failure: (input, expected, explore) =>
951
- ts.factory.createReturnStatement(
952
- config.joiner.failure(input, expected, explore),
953
- ),
954
- })([])(input, maps, explore, tags, jsDocTags),
955
- undefined,
956
- undefined,
957
- );
958
-
959
- const explore_tuples =
960
- (project: IProject) =>
961
- (config: IConfig) =>
962
- (importer: FunctionImporter) =>
963
- (
964
- input: ts.Expression,
965
- tuples: MetadataTuple[],
966
- explore: IExplore,
967
- tags: IMetadataTag[],
968
- jsDocTags: IJsDocTagInfo[],
969
- ): ts.Expression =>
970
- explore_array_like_union_types(config)(importer)(
971
- UnionExplorer.tuple({
972
- checker: decode_tuple(project)(config)(importer),
973
- decoder: decode_tuple(project)(config)(importer),
974
- empty: config.success,
975
- success: config.success,
976
- failure: (input, expected, explore) =>
977
- ts.factory.createReturnStatement(
978
- config.joiner.failure(input, expected, explore),
979
- ),
980
- }),
981
- )(input, tuples, explore, tags, jsDocTags);
982
-
983
- const explore_arrays =
984
- (project: IProject) =>
985
- (config: IConfig) =>
986
- (importer: FunctionImporter) =>
987
- (
988
- input: ts.Expression,
989
- arrays: MetadataArray[],
990
- explore: IExplore,
991
- tags: IMetadataTag[],
992
- jsDocTags: IJsDocTagInfo[],
993
- ): ts.Expression =>
994
- explore_array_like_union_types(config)(importer)(
995
- UnionExplorer.array({
996
- checker: decode(project)(config)(importer),
997
- decoder: decode_array(project)(config)(importer),
998
- empty: config.success,
999
- success: config.success,
1000
- failure: (input, expected, explore) =>
1001
- ts.factory.createReturnStatement(
1002
- config.joiner.failure(input, expected, explore),
1003
- ),
1004
- }),
1005
- )(input, arrays, explore, tags, jsDocTags);
1006
-
1007
- const explore_arrays_and_tuples =
1008
- (project: IProject) =>
1009
- (config: IConfig) =>
1010
- (importer: FunctionImporter) =>
1011
- (
1012
- input: ts.Expression,
1013
- elements: Array<MetadataArray | MetadataTuple>,
1014
- explore: IExplore,
1015
- tags: IMetadataTag[],
1016
- jsDocTags: IJsDocTagInfo[],
1017
- ): ts.Expression =>
1018
- explore_array_like_union_types(config)(importer)(
1019
- UnionExplorer.array_or_tuple({
1020
- checker: (front, target, explore, tags, jsDocTags, array) =>
1021
- target instanceof MetadataTuple
1022
- ? decode_tuple(project)(config)(importer)(
1023
- front,
1024
- target,
1025
- explore,
1026
- tags,
1027
- jsDocTags,
1028
- )
1029
- : config.atomist(explore)({
1030
- expression: decode(project)(config)(importer)(
1031
- front,
1032
- target,
1033
- explore,
1034
- tags,
1035
- jsDocTags,
1036
- ),
1037
- tags: check_array_length(tags)(array),
1038
- })(array),
1039
- decoder: (input, target, explore, tags, jsDocTags) =>
1040
- target instanceof MetadataTuple
1041
- ? decode_tuple(project)(config)(importer)(
1042
- input,
1043
- target,
1044
- explore,
1045
- tags,
1046
- jsDocTags,
1047
- )
1048
- : decode_array(project)(config)(importer)(
1049
- input,
1050
- target,
1051
- explore,
1052
- tags,
1053
- jsDocTags,
1054
- ),
1055
- empty: config.success,
1056
- success: config.success,
1057
- failure: (input, expected, explore) =>
1058
- ts.factory.createReturnStatement(
1059
- config.joiner.failure(input, expected, explore),
1060
- ),
1061
- }),
1062
- )(input, elements, explore, tags, jsDocTags);
1063
-
1064
- const explore_array_like_union_types =
1065
- (config: IConfig) =>
1066
- (importer: FunctionImporter) =>
1067
- <T extends MetadataArray | MetadataTuple>(
1068
- factory: (
1069
- parameters: ts.ParameterDeclaration[],
1070
- ) => (
1071
- input: ts.Expression,
1072
- elements: T[],
1073
- explore: IExplore,
1074
- tags: IMetadataTag[],
1075
- jsDocTags: IJsDocTagInfo[],
1076
- ) => ts.ArrowFunction,
1077
- ) =>
1078
- (
1079
- input: ts.Expression,
1080
- elements: T[],
1081
- explore: IExplore,
1082
- tags: IMetadataTag[],
1083
- jsDocTags: IJsDocTagInfo[],
1084
- ): ts.Expression => {
1085
- const arrow =
1086
- (parameters: ts.ParameterDeclaration[]) =>
1087
- (explore: IExplore) =>
1088
- (input: ts.Expression): ts.ArrowFunction =>
1089
- factory(parameters)(
1090
- input,
1091
- elements,
1092
- explore,
1093
- tags,
1094
- jsDocTags,
1095
- );
1096
- if (elements.every((e) => e.recursive === false))
1097
- ts.factory.createCallExpression(
1098
- arrow([])(explore)(input),
1099
- undefined,
1100
- [],
1101
- );
1102
- explore = {
1103
- ...explore,
1104
- source: "function",
1105
- from: "array",
1106
- };
1107
- return ts.factory.createLogicalOr(
1108
- ts.factory.createCallExpression(
1109
- ts.factory.createIdentifier(
1110
- importer.emplaceUnion(
1111
- config.prefix,
1112
- elements.map((e) => e.name).join(" | "),
1113
- () =>
1114
- arrow(
1115
- FeatureProgrammer.parameterDeclarations(
1116
- config,
1117
- )(TypeFactory.keyword("any"))(
1118
- ts.factory.createIdentifier("input"),
1119
- ),
1120
- )({
1121
- ...explore,
1122
- postfix: "",
1123
- })(ts.factory.createIdentifier("input")),
1124
- ),
1125
- ),
1126
- undefined,
1127
- FeatureProgrammer.argumentsArray(config)(explore)(input),
1128
- ),
1129
- config.joiner.failure(
1130
- input,
1131
- elements.map((e) => e.name).join(" | "),
1132
- explore,
1133
- ),
1134
- );
1135
- };
1136
-
1137
- const explore_objects =
1138
- (config: IConfig) =>
1139
- (importer: FunctionImporter) =>
1140
- (input: ts.Expression, meta: Metadata, explore: IExplore) =>
1141
- meta.objects.length === 1
1142
- ? decode_object(config)(importer)(
1143
- input,
1144
- meta.objects[0]!,
1145
- explore,
1146
- )
1147
- : ts.factory.createCallExpression(
1148
- ts.factory.createIdentifier(
1149
- importer.useLocal(
1150
- `${config.prefix}u${meta.union_index!}`,
1151
- ),
1152
- ),
1153
- undefined,
1154
- FeatureProgrammer.argumentsArray(config)(explore)(input),
1155
- );
1156
- }
1157
-
1158
- const create_add =
1159
- (binaries: CheckerProgrammer.IBinary[]) =>
1160
- (defaultInput: ts.Expression) =>
1161
- (
1162
- exact: boolean,
1163
- left: ts.Expression,
1164
- right: ts.Expression = defaultInput,
1165
- ) => {
1166
- const factory = exact
1167
- ? ts.factory.createStrictEquality
1168
- : ts.factory.createStrictInequality;
1169
- binaries.push({
1170
- expression: factory(left, right),
1171
- combined: false,
1172
- });
1173
- };
1
+ import ts from "typescript";
2
+
3
+ import { ExpressionFactory } from "../factories/ExpressionFactory";
4
+ import { IdentifierFactory } from "../factories/IdentifierFactory";
5
+ import { MetadataCollection } from "../factories/MetadataCollection";
6
+ import { MetadataFactory } from "../factories/MetadataFactory";
7
+ import { StatementFactory } from "../factories/StatementFactory";
8
+ import { TypeFactory } from "../factories/TypeFactory";
9
+ import { ValueFactory } from "../factories/ValueFactory";
10
+
11
+ import { IJsDocTagInfo } from "../schemas/metadata/IJsDocTagInfo";
12
+ import { IMetadataTag } from "../schemas/metadata/IMetadataTag";
13
+ import { Metadata } from "../schemas/metadata/Metadata";
14
+ import { MetadataArray } from "../schemas/metadata/MetadataArray";
15
+ import { MetadataObject } from "../schemas/metadata/MetadataObject";
16
+ import { MetadataTuple } from "../schemas/metadata/MetadataTuple";
17
+
18
+ import { IProject } from "../transformers/IProject";
19
+
20
+ import { FeatureProgrammer } from "./FeatureProgrammer";
21
+ import { AtomicPredicator } from "./helpers/AtomicPredicator";
22
+ import { FunctionImporter } from "./helpers/FunctionImporeter";
23
+ import { ICheckEntry } from "./helpers/ICheckEntry";
24
+ import { IExpressionEntry } from "./helpers/IExpressionEntry";
25
+ import { OptionPredicator } from "./helpers/OptionPredicator";
26
+ import { UnionExplorer } from "./helpers/UnionExplorer";
27
+ import { check_array } from "./internal/check_array";
28
+ import { check_array_length } from "./internal/check_array_length";
29
+ import { check_bigint } from "./internal/check_bigint";
30
+ import { check_native } from "./internal/check_native";
31
+ import { check_number } from "./internal/check_number";
32
+ import { check_string } from "./internal/check_string";
33
+ import { check_template } from "./internal/check_template";
34
+ import { decode_union_object } from "./internal/decode_union_object";
35
+ import { wrap_metadata_rest_tuple } from "./internal/wrap_metadata_rest_tuple";
36
+
37
+ export namespace CheckerProgrammer {
38
+ export interface IConfig {
39
+ prefix: string;
40
+ path: boolean;
41
+ trace: boolean;
42
+ equals: boolean;
43
+ numeric: boolean;
44
+ addition?: () => ts.Statement[];
45
+ decoder?: () => FeatureProgrammer.Decoder<Metadata, ts.Expression>;
46
+ combiner: IConfig.Combiner;
47
+ atomist: (
48
+ explore: IExplore,
49
+ ) => (check: ICheckEntry) => (input: ts.Expression) => ts.Expression;
50
+ joiner: IConfig.IJoiner;
51
+ success: ts.Expression;
52
+ }
53
+ export namespace IConfig {
54
+ export interface Combiner {
55
+ (explorer: IExplore): {
56
+ (logic: "and" | "or"): {
57
+ (
58
+ input: ts.Expression,
59
+ binaries: IBinary[],
60
+ expected: string,
61
+ ): ts.Expression;
62
+ };
63
+ };
64
+ }
65
+ export interface IJoiner {
66
+ object(
67
+ input: ts.Expression,
68
+ entries: IExpressionEntry[],
69
+ ): ts.Expression;
70
+ array(input: ts.Expression, arrow: ts.ArrowFunction): ts.Expression;
71
+ tuple?(exprs: ts.Expression[]): ts.Expression;
72
+
73
+ failure(
74
+ value: ts.Expression,
75
+ expected: string,
76
+ explore?: FeatureProgrammer.IExplore,
77
+ ): ts.Expression;
78
+ is?(expression: ts.Expression): ts.Expression;
79
+ required?(exp: ts.Expression): ts.Expression;
80
+ full?: (
81
+ condition: ts.Expression,
82
+ ) => (
83
+ input: ts.Expression,
84
+ expected: string,
85
+ explore: IExplore,
86
+ ) => ts.Expression;
87
+ }
88
+ }
89
+ export type IExplore = FeatureProgrammer.IExplore;
90
+
91
+ export interface IBinary {
92
+ expression: ts.Expression;
93
+ combined: boolean;
94
+ }
95
+
96
+ /* -----------------------------------------------------------
97
+ WRITERS
98
+ ----------------------------------------------------------- */
99
+ export const write =
100
+ (project: IProject) =>
101
+ (config: IConfig) =>
102
+ (importer: FunctionImporter) =>
103
+ FeatureProgrammer.write(project)(
104
+ configure(project)(config)(importer),
105
+ )(importer);
106
+
107
+ export const write_object_functions =
108
+ (project: IProject) =>
109
+ (config: IConfig) =>
110
+ (importer: FunctionImporter) =>
111
+ FeatureProgrammer.write_object_functions(
112
+ configure(project)(config)(importer),
113
+ )(importer);
114
+
115
+ export const write_union_functions =
116
+ (project: IProject) =>
117
+ (config: IConfig) =>
118
+ (importer: FunctionImporter) =>
119
+ FeatureProgrammer.write_union_functions(
120
+ configure(project)({ ...config, numeric: false })(importer),
121
+ );
122
+
123
+ export const write_array_functions =
124
+ (project: IProject) =>
125
+ (config: IConfig) =>
126
+ (importer: FunctionImporter) =>
127
+ (collection: MetadataCollection): ts.VariableStatement[] =>
128
+ collection
129
+ .arrays()
130
+ .filter((a) => a.recursive)
131
+ .map((array, i) =>
132
+ StatementFactory.constant(
133
+ `${config.prefix}a${i}`,
134
+ ts.factory.createArrowFunction(
135
+ undefined,
136
+ undefined,
137
+ FeatureProgrammer.parameterDeclarations(config)(
138
+ TypeFactory.keyword("any"),
139
+ )(ts.factory.createIdentifier("input")),
140
+ TypeFactory.keyword("any"),
141
+ undefined,
142
+ decode_array_inline(project)(config)(importer)(
143
+ ts.factory.createIdentifier("input"),
144
+ array,
145
+ {
146
+ tracable: config.trace,
147
+ source: "function",
148
+ from: "array",
149
+ postfix: "",
150
+ },
151
+ [],
152
+ [],
153
+ ),
154
+ ),
155
+ ),
156
+ );
157
+
158
+ export const write_tuple_functions =
159
+ (project: IProject) =>
160
+ (config: IConfig) =>
161
+ (importer: FunctionImporter) =>
162
+ (collection: MetadataCollection): ts.VariableStatement[] =>
163
+ collection
164
+ .tuples()
165
+ .filter((t) => t.recursive)
166
+ .map((tuple, i) =>
167
+ StatementFactory.constant(
168
+ `${config.prefix}t${i}`,
169
+ ts.factory.createArrowFunction(
170
+ undefined,
171
+ undefined,
172
+ FeatureProgrammer.parameterDeclarations(config)(
173
+ TypeFactory.keyword("any"),
174
+ )(ts.factory.createIdentifier("input")),
175
+ TypeFactory.keyword("any"),
176
+ undefined,
177
+ decode_tuple_inline(project)(config)(importer)(
178
+ ts.factory.createIdentifier("input"),
179
+ tuple,
180
+ {
181
+ tracable: config.trace,
182
+ source: "function",
183
+ from: "array",
184
+ postfix: "",
185
+ },
186
+ [],
187
+ [],
188
+ ),
189
+ ),
190
+ ),
191
+ );
192
+
193
+ const configure =
194
+ (project: IProject) =>
195
+ (config: IConfig) =>
196
+ (importer: FunctionImporter): FeatureProgrammer.IConfig => ({
197
+ types: {
198
+ input: () => TypeFactory.keyword("any"),
199
+ output: (type, name) =>
200
+ ts.factory.createTypePredicateNode(
201
+ undefined,
202
+ "input",
203
+ ts.factory.createTypeReferenceNode(
204
+ name ??
205
+ TypeFactory.getFullName(project.checker)(type),
206
+ ),
207
+ ),
208
+ },
209
+ trace: config.trace,
210
+ path: config.path,
211
+ prefix: config.prefix,
212
+ initializer:
213
+ ({ checker }) =>
214
+ (type) => {
215
+ const collection: MetadataCollection =
216
+ new MetadataCollection();
217
+ const meta: Metadata = MetadataFactory.analyze(checker)({
218
+ escape: false,
219
+ constant: true,
220
+ absorb: true,
221
+ })(collection)(type);
222
+ return [collection, meta];
223
+ },
224
+ addition: config.addition,
225
+ decoder: () =>
226
+ config.decoder?.() ?? decode(project)(config)(importer),
227
+ objector: {
228
+ checker: () =>
229
+ config.decoder?.() ?? decode(project)(config)(importer),
230
+ decoder: () => decode_object(config)(importer),
231
+ joiner: config.joiner.object,
232
+ unionizer: config.equals
233
+ ? decode_union_object(decode_object(config)(importer))(
234
+ (input, obj, explore) =>
235
+ decode_object(config)(importer)(input, obj, {
236
+ ...explore,
237
+ tracable: true,
238
+ }),
239
+ )(config.joiner.is ?? ((expr) => expr))(
240
+ (value, expected) =>
241
+ ts.factory.createReturnStatement(
242
+ config.joiner.failure(value, expected),
243
+ ),
244
+ )
245
+ : (input, targets, explore) =>
246
+ config.combiner(explore)("or")(
247
+ input,
248
+ targets.map((obj) => ({
249
+ expression: decode_object(config)(importer)(
250
+ input,
251
+ obj,
252
+ explore,
253
+ ),
254
+ combined: true,
255
+ })),
256
+ `(${targets.map((t) => t.name).join(" | ")})`,
257
+ ),
258
+ failure: (value, expected) =>
259
+ ts.factory.createReturnStatement(
260
+ config.joiner.failure(value, expected),
261
+ ),
262
+ is: config.joiner.is,
263
+ required: config.joiner.required,
264
+ full: config.joiner.full,
265
+ type: TypeFactory.keyword("boolean"),
266
+ },
267
+ generator: {
268
+ unions: config.numeric
269
+ ? () =>
270
+ FeatureProgrammer.write_union_functions(
271
+ configure(project)({ ...config, numeric: false })(
272
+ importer,
273
+ ),
274
+ )
275
+ : undefined,
276
+ arrays: () => write_array_functions(project)(config)(importer),
277
+ tuples: () => write_tuple_functions(project)(config)(importer),
278
+ },
279
+ });
280
+
281
+ /* -----------------------------------------------------------
282
+ DECODERS
283
+ ----------------------------------------------------------- */
284
+ /**
285
+ * @internal
286
+ */
287
+ export const decode =
288
+ (project: IProject) =>
289
+ (config: IConfig) =>
290
+ (importer: FunctionImporter) =>
291
+ (
292
+ input: ts.Expression,
293
+ meta: Metadata,
294
+ explore: IExplore,
295
+ metaTags: IMetadataTag[],
296
+ jsDocTags: ts.JSDocTagInfo[],
297
+ ): ts.Expression => {
298
+ if (meta.any) return config.success;
299
+
300
+ const top: IBinary[] = [];
301
+ const binaries: IBinary[] = [];
302
+ const add = create_add(binaries)(input);
303
+ const getConstantValue = (
304
+ value: number | string | bigint | boolean,
305
+ ) =>
306
+ typeof value === "string"
307
+ ? ts.factory.createStringLiteral(value)
308
+ : ts.factory.createIdentifier(value.toString());
309
+
310
+ //----
311
+ // CHECK OPTIONAL
312
+ //----
313
+ // @todo -> should be elaborated
314
+ const checkOptional: boolean = meta.empty() || meta.isUnionBucket();
315
+
316
+ // NULLABLE
317
+ if (checkOptional || meta.nullable)
318
+ (meta.nullable ? add : create_add(top)(input))(
319
+ meta.nullable,
320
+ ValueFactory.NULL(),
321
+ );
322
+
323
+ // UNDEFINDABLE
324
+ if (checkOptional || !meta.isRequired())
325
+ (meta.isRequired() ? create_add(top)(input) : add)(
326
+ !meta.isRequired(),
327
+ ValueFactory.UNDEFINED(),
328
+ );
329
+
330
+ // FUNCTIONAL
331
+ if (meta.functional === true)
332
+ if (
333
+ OptionPredicator.functional(project.options) ||
334
+ meta.size() !== 1
335
+ )
336
+ add(
337
+ true,
338
+ ts.factory.createStringLiteral("function"),
339
+ ValueFactory.TYPEOF(input),
340
+ );
341
+ else
342
+ binaries.push({
343
+ combined: false,
344
+ expression: config.success,
345
+ });
346
+
347
+ //----
348
+ // VALUES
349
+ //----
350
+ // CONSTANT VALUES
351
+ for (const constant of meta.constants)
352
+ if (AtomicPredicator.constant(meta)(constant.type))
353
+ for (const val of constant.values)
354
+ add(true, getConstantValue(val));
355
+
356
+ // ATOMIC VALUES
357
+ for (const atom of meta.atomics)
358
+ if (AtomicPredicator.atomic(meta)(atom.type) === false)
359
+ continue;
360
+ else if (atom.type === "number")
361
+ binaries.push({
362
+ expression: config.atomist(explore)(
363
+ check_number(project, config.numeric)(importer)(
364
+ metaTags,
365
+ )(jsDocTags)(input),
366
+ )(input),
367
+ combined: false,
368
+ });
369
+ else if (atom.type === "bigint")
370
+ binaries.push({
371
+ expression: config.atomist(explore)(
372
+ check_bigint(importer)(metaTags)(jsDocTags)(input),
373
+ )(input),
374
+ combined: false,
375
+ });
376
+ else if (atom.type === "string")
377
+ binaries.push({
378
+ expression: config.atomist(explore)(
379
+ check_string(importer)(metaTags)(jsDocTags)(input),
380
+ )(input),
381
+ combined: false,
382
+ });
383
+ else
384
+ add(
385
+ true,
386
+ ts.factory.createStringLiteral(atom.type),
387
+ ValueFactory.TYPEOF(input),
388
+ );
389
+
390
+ // TEMPLATE LITERAL VALUES
391
+ if (meta.templates.length)
392
+ if (AtomicPredicator.template(meta))
393
+ binaries.push({
394
+ expression: config.atomist(explore)(
395
+ check_template(importer)(metaTags)(jsDocTags)(
396
+ meta.templates,
397
+ )(input),
398
+ )(input),
399
+ combined: false,
400
+ });
401
+
402
+ // NATIVE CLASSES
403
+ for (const native of meta.natives)
404
+ binaries.push({
405
+ expression: check_native(native)(input),
406
+ combined: false,
407
+ });
408
+
409
+ //----
410
+ // INSTANCES
411
+ //----
412
+ interface IInstance {
413
+ pre: ts.Expression;
414
+ body: ts.Expression | null;
415
+ expected: string;
416
+ }
417
+ const instances: IInstance[] = [];
418
+ const prepare =
419
+ (pre: ts.Expression, expected: string) =>
420
+ (body: ts.Expression | null) =>
421
+ instances.push({
422
+ pre,
423
+ expected,
424
+ body,
425
+ });
426
+
427
+ // SETS
428
+ if (meta.sets.length) {
429
+ const install = prepare(
430
+ check_native("Set")(input),
431
+ meta.sets
432
+ .map((elem) => `Set<${elem.getName()}>`)
433
+ .join(" | "),
434
+ );
435
+ if (meta.sets.some((elem) => elem.any)) install(null);
436
+ else
437
+ install(
438
+ explore_sets(project)(config)(importer)(
439
+ input,
440
+ meta.sets,
441
+ {
442
+ ...explore,
443
+ from: "array",
444
+ },
445
+ [],
446
+ [],
447
+ ),
448
+ );
449
+ }
450
+
451
+ // MAPS
452
+ if (meta.maps.length) {
453
+ const install = prepare(
454
+ check_native("Map")(input),
455
+ meta.maps
456
+ .map(({ key, value }) => `Map<${key}, ${value}>`)
457
+ .join(" | "),
458
+ );
459
+ if (meta.maps.some((elem) => elem.key.any && elem.value.any))
460
+ install(null);
461
+ else
462
+ install(
463
+ explore_maps(project)(config)(importer)(
464
+ input,
465
+ meta.maps,
466
+ {
467
+ ...explore,
468
+ from: "array",
469
+ },
470
+ metaTags,
471
+ jsDocTags,
472
+ ),
473
+ );
474
+ }
475
+
476
+ // ARRAYS AND TUPLES
477
+ if (meta.tuples.length + meta.arrays.length > 0) {
478
+ const install = prepare(
479
+ config.atomist(explore)(
480
+ check_array(importer)(
481
+ meta.tuples.length === 0 ? metaTags : [],
482
+ )(jsDocTags)(input),
483
+ )(input),
484
+ [...meta.tuples, ...meta.arrays]
485
+ .map((elem) => elem.name)
486
+ .join(" | "),
487
+ );
488
+ if (meta.arrays.length === 0)
489
+ if (meta.tuples.length === 1)
490
+ install(
491
+ decode_tuple(project)(config)(importer)(
492
+ input,
493
+ meta.tuples[0]!,
494
+ {
495
+ ...explore,
496
+ from: "array",
497
+ },
498
+ metaTags,
499
+ jsDocTags,
500
+ ),
501
+ );
502
+ // TUPLE ONLY
503
+ else
504
+ install(
505
+ explore_tuples(project)(config)(importer)(
506
+ input,
507
+ meta.tuples,
508
+ {
509
+ ...explore,
510
+ from: "array",
511
+ },
512
+ metaTags,
513
+ jsDocTags,
514
+ ),
515
+ );
516
+ else if (meta.arrays.some((elem) => elem.value.any))
517
+ install(null);
518
+ else if (meta.tuples.length === 0)
519
+ if (meta.arrays.length === 1)
520
+ // ARRAY ONLY
521
+ install(
522
+ decode_array(project)(config)(importer)(
523
+ input,
524
+ meta.arrays[0]!,
525
+ {
526
+ ...explore,
527
+ from: "array",
528
+ },
529
+ metaTags,
530
+ jsDocTags,
531
+ ),
532
+ );
533
+ else
534
+ install(
535
+ explore_arrays(project)(config)(importer)(
536
+ input,
537
+ meta.arrays,
538
+ {
539
+ ...explore,
540
+ from: "array",
541
+ },
542
+ metaTags,
543
+ jsDocTags,
544
+ ),
545
+ );
546
+ else
547
+ install(
548
+ explore_arrays_and_tuples(project)(config)(importer)(
549
+ input,
550
+ [...meta.tuples, ...meta.arrays],
551
+ explore,
552
+ metaTags,
553
+ jsDocTags,
554
+ ),
555
+ );
556
+ }
557
+
558
+ // OBJECT
559
+ if (meta.objects.length > 0)
560
+ prepare(
561
+ ExpressionFactory.isObject({
562
+ checkNull: true,
563
+ checkArray: meta.objects.some((obj) =>
564
+ obj.properties.every(
565
+ (prop) =>
566
+ !prop.key.isSoleLiteral() ||
567
+ !prop.value.isRequired(),
568
+ ),
569
+ ),
570
+ })(input),
571
+ meta.objects.map((obj) => obj.name).join(" | "),
572
+ )(
573
+ explore_objects(config)(importer)(input, meta, {
574
+ ...explore,
575
+ from: "object",
576
+ }),
577
+ );
578
+
579
+ if (instances.length) {
580
+ const transformer =
581
+ (
582
+ merger: (
583
+ x: ts.Expression,
584
+ y: ts.Expression,
585
+ ) => ts.Expression,
586
+ ) =>
587
+ (ins: IInstance) =>
588
+ ins.body
589
+ ? {
590
+ expression: merger(ins.pre, ins.body),
591
+ combined: true,
592
+ }
593
+ : {
594
+ expression: ins.pre,
595
+ combined: false,
596
+ };
597
+ if (instances.length === 1)
598
+ binaries.push(
599
+ transformer((pre, body) =>
600
+ config.combiner(explore)("and")(
601
+ input,
602
+ [pre, body].map((expression) => ({
603
+ expression,
604
+ combined: expression !== pre,
605
+ })),
606
+ meta.getName(),
607
+ ),
608
+ )(instances[0]!),
609
+ );
610
+ else
611
+ binaries.push({
612
+ expression: config.combiner(explore)("or")(
613
+ input,
614
+ instances.map(
615
+ transformer(ts.factory.createLogicalAnd),
616
+ ),
617
+ meta.getName(),
618
+ ),
619
+ combined: true,
620
+ });
621
+ }
622
+
623
+ //----
624
+ // COMBINE CONDITIONS
625
+ //----
626
+ return top.length && binaries.length
627
+ ? config.combiner(explore)("and")(
628
+ input,
629
+ [
630
+ ...top,
631
+ {
632
+ expression: config.combiner(explore)("or")(
633
+ input,
634
+ binaries,
635
+ meta.getName(),
636
+ ),
637
+ combined: true,
638
+ },
639
+ ],
640
+ meta.getName(),
641
+ )
642
+ : binaries.length
643
+ ? config.combiner(explore)("or")(
644
+ input,
645
+ binaries,
646
+ meta.getName(),
647
+ )
648
+ : config.success;
649
+ };
650
+
651
+ export const decode_object =
652
+ (config: IConfig) => (importer: FunctionImporter) => {
653
+ const func = FeatureProgrammer.decode_object(config)(importer);
654
+ return (
655
+ input: ts.Expression,
656
+ obj: MetadataObject,
657
+ explore: IExplore,
658
+ ) => {
659
+ obj.validated = true;
660
+ return func(input, obj, explore);
661
+ };
662
+ };
663
+
664
+ const decode_array =
665
+ (project: IProject) =>
666
+ (config: IConfig) =>
667
+ (importer: FunctionImporter) =>
668
+ (
669
+ input: ts.Expression,
670
+ array: MetadataArray,
671
+ explore: IExplore,
672
+ metaTags: IMetadataTag[],
673
+ jsDocTags: IJsDocTagInfo[],
674
+ ) => {
675
+ if (array.recursive === false)
676
+ return decode_array_inline(project)(config)(importer)(
677
+ input,
678
+ array,
679
+ explore,
680
+ metaTags,
681
+ jsDocTags,
682
+ );
683
+
684
+ explore = {
685
+ ...explore,
686
+ source: "function",
687
+ from: "array",
688
+ };
689
+ return ts.factory.createLogicalOr(
690
+ ts.factory.createCallExpression(
691
+ ts.factory.createIdentifier(
692
+ importer.useLocal(`${config.prefix}a${array.index}`),
693
+ ),
694
+ undefined,
695
+ FeatureProgrammer.argumentsArray(config)({
696
+ ...explore,
697
+ source: "function",
698
+ from: "array",
699
+ })(input),
700
+ ),
701
+ config.joiner.failure(input, array.name, explore),
702
+ );
703
+ };
704
+
705
+ const decode_array_inline =
706
+ (project: IProject) =>
707
+ (config: IConfig) =>
708
+ (importer: FunctionImporter) =>
709
+ FeatureProgrammer.decode_array({
710
+ prefix: config.prefix,
711
+ trace: config.trace,
712
+ path: config.path,
713
+ decoder: () => decode(project)(config)(importer),
714
+ })(importer)(config.joiner.array);
715
+
716
+ const decode_tuple =
717
+ (project: IProject) =>
718
+ (config: IConfig) =>
719
+ (importer: FunctionImporter) =>
720
+ (
721
+ input: ts.Expression,
722
+ tuple: MetadataTuple,
723
+ explore: IExplore,
724
+ tagList: IMetadataTag[],
725
+ jsDocTags: ts.JSDocTagInfo[],
726
+ ): ts.Expression => {
727
+ if (tuple.recursive === false)
728
+ return decode_tuple_inline(project)(config)(importer)(
729
+ input,
730
+ tuple,
731
+ explore,
732
+ tagList,
733
+ jsDocTags,
734
+ );
735
+ explore = {
736
+ ...explore,
737
+ source: "function",
738
+ from: "array",
739
+ };
740
+ return ts.factory.createLogicalOr(
741
+ ts.factory.createCallExpression(
742
+ ts.factory.createIdentifier(
743
+ importer.useLocal(`${config.prefix}t${tuple.index}`),
744
+ ),
745
+ undefined,
746
+ FeatureProgrammer.argumentsArray(config)({
747
+ ...explore,
748
+ source: "function",
749
+ })(input),
750
+ ),
751
+ config.joiner.failure(input, tuple.name, explore),
752
+ );
753
+ };
754
+
755
+ const decode_tuple_inline =
756
+ (project: IProject) =>
757
+ (config: IConfig) =>
758
+ (importer: FunctionImporter) =>
759
+ (
760
+ input: ts.Expression,
761
+ tuple: MetadataTuple,
762
+ explore: IExplore,
763
+ tagList: IMetadataTag[],
764
+ jsDocTags: ts.JSDocTagInfo[],
765
+ ): ts.Expression => {
766
+ const binaries: ts.Expression[] = tuple.elements
767
+ .filter((meta) => meta.rest === null)
768
+ .map((meta, index) =>
769
+ decode(project)(config)(importer)(
770
+ ts.factory.createElementAccessExpression(input, index),
771
+ meta,
772
+ {
773
+ ...explore,
774
+ from: "array",
775
+ postfix: explore.postfix.length
776
+ ? `${explore.postfix.slice(0, -1)}[${index}]"`
777
+ : `"[${index}]"`,
778
+ },
779
+ tuple.of_map === true && index !== 1 ? [] : tagList,
780
+ tuple.of_map === true && index !== 1 ? [] : jsDocTags,
781
+ ),
782
+ );
783
+ const rest: ts.Expression | null =
784
+ tuple.elements.length && tuple.elements.at(-1)!.rest !== null
785
+ ? decode(project)(config)(importer)(
786
+ ts.factory.createCallExpression(
787
+ IdentifierFactory.access(input)("slice"),
788
+ undefined,
789
+ [
790
+ ts.factory.createNumericLiteral(
791
+ tuple.elements.length - 1,
792
+ ),
793
+ ],
794
+ ),
795
+ wrap_metadata_rest_tuple(
796
+ tuple.elements.at(-1)!.rest!,
797
+ ),
798
+ {
799
+ ...explore,
800
+ start: tuple.elements.length - 1,
801
+ },
802
+ tagList,
803
+ jsDocTags,
804
+ )
805
+ : null;
806
+
807
+ const arrayLength = ts.factory.createPropertyAccessExpression(
808
+ input,
809
+ "length",
810
+ );
811
+ return config.combiner(explore)("and")(
812
+ input,
813
+ [
814
+ ...(rest === null
815
+ ? tuple.elements.every((t) => t.optional === false)
816
+ ? [
817
+ {
818
+ combined: false,
819
+ expression:
820
+ ts.factory.createStrictEquality(
821
+ arrayLength,
822
+ ts.factory.createNumericLiteral(
823
+ tuple.elements.length,
824
+ ),
825
+ ),
826
+ },
827
+ ]
828
+ : [
829
+ {
830
+ combined: false,
831
+ expression: ts.factory.createLogicalAnd(
832
+ ts.factory.createLessThanEquals(
833
+ ts.factory.createNumericLiteral(
834
+ tuple.elements.filter(
835
+ (t) =>
836
+ t.optional === false,
837
+ ).length,
838
+ ),
839
+ arrayLength,
840
+ ),
841
+ ts.factory.createGreaterThanEquals(
842
+ ts.factory.createNumericLiteral(
843
+ tuple.elements.length,
844
+ ),
845
+ arrayLength,
846
+ ),
847
+ ),
848
+ },
849
+ ]
850
+ : []),
851
+ ...(config.joiner.tuple
852
+ ? [
853
+ {
854
+ expression: config.joiner.tuple(binaries),
855
+ combined: true,
856
+ },
857
+ ]
858
+ : binaries.map((expression) => ({
859
+ expression,
860
+ combined: true,
861
+ }))),
862
+ ...(rest !== null
863
+ ? [
864
+ {
865
+ expression: rest,
866
+ combined: true,
867
+ },
868
+ ]
869
+ : []),
870
+ ],
871
+ `[${tuple.elements.map((t) => t.getName()).join(", ")}]`,
872
+ );
873
+ };
874
+
875
+ /* -----------------------------------------------------------
876
+ UNION TYPE EXPLORERS
877
+ ----------------------------------------------------------- */
878
+ const explore_sets =
879
+ (project: IProject) =>
880
+ (config: IConfig) =>
881
+ (importer: FunctionImporter) =>
882
+ (
883
+ input: ts.Expression,
884
+ sets: Metadata[],
885
+ explore: IExplore,
886
+ tags: IMetadataTag[],
887
+ jsDocTags: IJsDocTagInfo[],
888
+ ): ts.Expression =>
889
+ ts.factory.createCallExpression(
890
+ UnionExplorer.set({
891
+ checker: decode(project)(config)(importer),
892
+ decoder: decode_array(project)(config)(importer),
893
+ empty: config.success,
894
+ success: config.success,
895
+ failure: (input, expected, explore) =>
896
+ ts.factory.createReturnStatement(
897
+ config.joiner.failure(input, expected, explore),
898
+ ),
899
+ })([])(input, sets, explore, tags, jsDocTags),
900
+ undefined,
901
+ undefined,
902
+ );
903
+
904
+ const explore_maps =
905
+ (project: IProject) =>
906
+ (config: IConfig) =>
907
+ (importer: FunctionImporter) =>
908
+ (
909
+ input: ts.Expression,
910
+ maps: Metadata.Entry[],
911
+ explore: IExplore,
912
+ tags: IMetadataTag[],
913
+ jsDocTags: IJsDocTagInfo[],
914
+ ): ts.Expression =>
915
+ ts.factory.createCallExpression(
916
+ UnionExplorer.map({
917
+ checker: (input, entry, explore) => {
918
+ const func = decode(project)(config)(importer);
919
+ return ts.factory.createLogicalAnd(
920
+ func(
921
+ ts.factory.createElementAccessExpression(
922
+ input,
923
+ 0,
924
+ ),
925
+ entry[0],
926
+ {
927
+ ...explore,
928
+ postfix: `${explore.postfix}[0]`,
929
+ },
930
+ [],
931
+ [],
932
+ ),
933
+ func(
934
+ ts.factory.createElementAccessExpression(
935
+ input,
936
+ 1,
937
+ ),
938
+ entry[1],
939
+ {
940
+ ...explore,
941
+ postfix: `${explore.postfix}[1]`,
942
+ },
943
+ [],
944
+ [],
945
+ ),
946
+ );
947
+ },
948
+ decoder: decode_array(project)(config)(importer),
949
+ empty: config.success,
950
+ success: config.success,
951
+ failure: (input, expected, explore) =>
952
+ ts.factory.createReturnStatement(
953
+ config.joiner.failure(input, expected, explore),
954
+ ),
955
+ })([])(input, maps, explore, tags, jsDocTags),
956
+ undefined,
957
+ undefined,
958
+ );
959
+
960
+ const explore_tuples =
961
+ (project: IProject) =>
962
+ (config: IConfig) =>
963
+ (importer: FunctionImporter) =>
964
+ (
965
+ input: ts.Expression,
966
+ tuples: MetadataTuple[],
967
+ explore: IExplore,
968
+ tags: IMetadataTag[],
969
+ jsDocTags: IJsDocTagInfo[],
970
+ ): ts.Expression =>
971
+ explore_array_like_union_types(config)(importer)(
972
+ UnionExplorer.tuple({
973
+ checker: decode_tuple(project)(config)(importer),
974
+ decoder: decode_tuple(project)(config)(importer),
975
+ empty: config.success,
976
+ success: config.success,
977
+ failure: (input, expected, explore) =>
978
+ ts.factory.createReturnStatement(
979
+ config.joiner.failure(input, expected, explore),
980
+ ),
981
+ }),
982
+ )(input, tuples, explore, tags, jsDocTags);
983
+
984
+ const explore_arrays =
985
+ (project: IProject) =>
986
+ (config: IConfig) =>
987
+ (importer: FunctionImporter) =>
988
+ (
989
+ input: ts.Expression,
990
+ arrays: MetadataArray[],
991
+ explore: IExplore,
992
+ tags: IMetadataTag[],
993
+ jsDocTags: IJsDocTagInfo[],
994
+ ): ts.Expression =>
995
+ explore_array_like_union_types(config)(importer)(
996
+ UnionExplorer.array({
997
+ checker: decode(project)(config)(importer),
998
+ decoder: decode_array(project)(config)(importer),
999
+ empty: config.success,
1000
+ success: config.success,
1001
+ failure: (input, expected, explore) =>
1002
+ ts.factory.createReturnStatement(
1003
+ config.joiner.failure(input, expected, explore),
1004
+ ),
1005
+ }),
1006
+ )(input, arrays, explore, tags, jsDocTags);
1007
+
1008
+ const explore_arrays_and_tuples =
1009
+ (project: IProject) =>
1010
+ (config: IConfig) =>
1011
+ (importer: FunctionImporter) =>
1012
+ (
1013
+ input: ts.Expression,
1014
+ elements: Array<MetadataArray | MetadataTuple>,
1015
+ explore: IExplore,
1016
+ tags: IMetadataTag[],
1017
+ jsDocTags: IJsDocTagInfo[],
1018
+ ): ts.Expression =>
1019
+ explore_array_like_union_types(config)(importer)(
1020
+ UnionExplorer.array_or_tuple({
1021
+ checker: (front, target, explore, tags, jsDocTags, array) =>
1022
+ target instanceof MetadataTuple
1023
+ ? decode_tuple(project)(config)(importer)(
1024
+ front,
1025
+ target,
1026
+ explore,
1027
+ tags,
1028
+ jsDocTags,
1029
+ )
1030
+ : config.atomist(explore)({
1031
+ expression: decode(project)(config)(importer)(
1032
+ front,
1033
+ target,
1034
+ explore,
1035
+ tags,
1036
+ jsDocTags,
1037
+ ),
1038
+ tags: check_array_length(tags)(array),
1039
+ })(array),
1040
+ decoder: (input, target, explore, tags, jsDocTags) =>
1041
+ target instanceof MetadataTuple
1042
+ ? decode_tuple(project)(config)(importer)(
1043
+ input,
1044
+ target,
1045
+ explore,
1046
+ tags,
1047
+ jsDocTags,
1048
+ )
1049
+ : decode_array(project)(config)(importer)(
1050
+ input,
1051
+ target,
1052
+ explore,
1053
+ tags,
1054
+ jsDocTags,
1055
+ ),
1056
+ empty: config.success,
1057
+ success: config.success,
1058
+ failure: (input, expected, explore) =>
1059
+ ts.factory.createReturnStatement(
1060
+ config.joiner.failure(input, expected, explore),
1061
+ ),
1062
+ }),
1063
+ )(input, elements, explore, tags, jsDocTags);
1064
+
1065
+ const explore_array_like_union_types =
1066
+ (config: IConfig) =>
1067
+ (importer: FunctionImporter) =>
1068
+ <T extends MetadataArray | MetadataTuple>(
1069
+ factory: (
1070
+ parameters: ts.ParameterDeclaration[],
1071
+ ) => (
1072
+ input: ts.Expression,
1073
+ elements: T[],
1074
+ explore: IExplore,
1075
+ tags: IMetadataTag[],
1076
+ jsDocTags: IJsDocTagInfo[],
1077
+ ) => ts.ArrowFunction,
1078
+ ) =>
1079
+ (
1080
+ input: ts.Expression,
1081
+ elements: T[],
1082
+ explore: IExplore,
1083
+ tags: IMetadataTag[],
1084
+ jsDocTags: IJsDocTagInfo[],
1085
+ ): ts.Expression => {
1086
+ const arrow =
1087
+ (parameters: ts.ParameterDeclaration[]) =>
1088
+ (explore: IExplore) =>
1089
+ (input: ts.Expression): ts.ArrowFunction =>
1090
+ factory(parameters)(
1091
+ input,
1092
+ elements,
1093
+ explore,
1094
+ tags,
1095
+ jsDocTags,
1096
+ );
1097
+ if (elements.every((e) => e.recursive === false))
1098
+ ts.factory.createCallExpression(
1099
+ arrow([])(explore)(input),
1100
+ undefined,
1101
+ [],
1102
+ );
1103
+ explore = {
1104
+ ...explore,
1105
+ source: "function",
1106
+ from: "array",
1107
+ };
1108
+ return ts.factory.createLogicalOr(
1109
+ ts.factory.createCallExpression(
1110
+ ts.factory.createIdentifier(
1111
+ importer.emplaceUnion(
1112
+ config.prefix,
1113
+ elements.map((e) => e.name).join(" | "),
1114
+ () =>
1115
+ arrow(
1116
+ FeatureProgrammer.parameterDeclarations(
1117
+ config,
1118
+ )(TypeFactory.keyword("any"))(
1119
+ ts.factory.createIdentifier("input"),
1120
+ ),
1121
+ )({
1122
+ ...explore,
1123
+ postfix: "",
1124
+ })(ts.factory.createIdentifier("input")),
1125
+ ),
1126
+ ),
1127
+ undefined,
1128
+ FeatureProgrammer.argumentsArray(config)(explore)(input),
1129
+ ),
1130
+ config.joiner.failure(
1131
+ input,
1132
+ elements.map((e) => e.name).join(" | "),
1133
+ explore,
1134
+ ),
1135
+ );
1136
+ };
1137
+
1138
+ const explore_objects =
1139
+ (config: IConfig) =>
1140
+ (importer: FunctionImporter) =>
1141
+ (input: ts.Expression, meta: Metadata, explore: IExplore) =>
1142
+ meta.objects.length === 1
1143
+ ? decode_object(config)(importer)(
1144
+ input,
1145
+ meta.objects[0]!,
1146
+ explore,
1147
+ )
1148
+ : ts.factory.createCallExpression(
1149
+ ts.factory.createIdentifier(
1150
+ importer.useLocal(
1151
+ `${config.prefix}u${meta.union_index!}`,
1152
+ ),
1153
+ ),
1154
+ undefined,
1155
+ FeatureProgrammer.argumentsArray(config)(explore)(input),
1156
+ );
1157
+ }
1158
+
1159
+ const create_add =
1160
+ (binaries: CheckerProgrammer.IBinary[]) =>
1161
+ (defaultInput: ts.Expression) =>
1162
+ (
1163
+ exact: boolean,
1164
+ left: ts.Expression,
1165
+ right: ts.Expression = defaultInput,
1166
+ ) => {
1167
+ const factory = exact
1168
+ ? ts.factory.createStrictEquality
1169
+ : ts.factory.createStrictInequality;
1170
+ binaries.push({
1171
+ expression: factory(left, right),
1172
+ combined: false,
1173
+ });
1174
+ };