typia 3.4.13 → 3.4.14

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 (157) hide show
  1. package/README.md +9 -8
  2. package/lib/factories/internal/iterate_metadata_object.js +4 -2
  3. package/lib/factories/internal/iterate_metadata_object.js.map +1 -1
  4. package/package.json +1 -1
  5. package/src/IValidation.ts +21 -21
  6. package/src/Primitive.ts +82 -82
  7. package/src/TypeGuardError.ts +36 -36
  8. package/src/executable/internal/CommandParser.ts +15 -15
  9. package/src/executable/internal/TypiaSetupWizard.ts +175 -175
  10. package/src/executable/typia.ts +46 -46
  11. package/src/factories/CommentFactory.ts +10 -10
  12. package/src/factories/ExpressionFactory.ts +66 -66
  13. package/src/factories/IdentifierFactory.ts +72 -72
  14. package/src/factories/LiteralFactory.ts +44 -44
  15. package/src/factories/MetadataCollection.ts +122 -122
  16. package/src/factories/MetadataFactory.ts +46 -46
  17. package/src/factories/MetadataTagFactory.ts +347 -347
  18. package/src/factories/StatementFactory.ts +60 -60
  19. package/src/factories/TemplateFactory.ts +56 -56
  20. package/src/factories/TypeFactory.ts +101 -101
  21. package/src/factories/ValueFactory.ts +12 -12
  22. package/src/factories/internal/MetadataHelper.ts +12 -12
  23. package/src/factories/internal/emplace_metadata_object.ts +140 -140
  24. package/src/factories/internal/explore_metadata.ts +91 -91
  25. package/src/factories/internal/iterate_metadata.ts +80 -80
  26. package/src/factories/internal/iterate_metadata_array.ts +29 -29
  27. package/src/factories/internal/iterate_metadata_atomic.ts +59 -59
  28. package/src/factories/internal/iterate_metadata_coalesce.ts +33 -33
  29. package/src/factories/internal/iterate_metadata_constant.ts +58 -58
  30. package/src/factories/internal/iterate_metadata_map.ts +41 -41
  31. package/src/factories/internal/iterate_metadata_native.ts +227 -227
  32. package/src/factories/internal/iterate_metadata_object.ts +48 -45
  33. package/src/factories/internal/iterate_metadata_resolve.ts +27 -27
  34. package/src/factories/internal/iterate_metadata_set.ts +33 -33
  35. package/src/factories/internal/iterate_metadata_template.ts +38 -38
  36. package/src/factories/internal/iterate_metadata_tuple.ts +45 -45
  37. package/src/factories/internal/iterate_metadata_union.ts +59 -59
  38. package/src/functional/$every.ts +11 -11
  39. package/src/functional/$guard.ts +35 -35
  40. package/src/functional/$is_email.ts +5 -5
  41. package/src/functional/$is_ipv4.ts +5 -5
  42. package/src/functional/$is_ipv6.ts +5 -5
  43. package/src/functional/$is_url.ts +5 -5
  44. package/src/functional/$is_uuid.ts +5 -5
  45. package/src/functional/$join.ts +50 -50
  46. package/src/functional/$number.ts +19 -19
  47. package/src/functional/$report.ts +15 -15
  48. package/src/functional/$rest.ts +3 -3
  49. package/src/functional/$string.ts +37 -37
  50. package/src/functional/$tail.ts +6 -6
  51. package/src/index.ts +4 -4
  52. package/src/metadata/IJsDocTagInfo.ts +10 -10
  53. package/src/metadata/IMetadata.ts +25 -25
  54. package/src/metadata/IMetadataApplication.ts +7 -7
  55. package/src/metadata/IMetadataConstant.ts +16 -16
  56. package/src/metadata/IMetadataEntry.ts +6 -6
  57. package/src/metadata/IMetadataObject.ts +29 -29
  58. package/src/metadata/IMetadataProperty.ts +11 -11
  59. package/src/metadata/IMetadataTag.ts +122 -122
  60. package/src/metadata/Metadata.ts +477 -477
  61. package/src/metadata/MetadataConstant.ts +3 -3
  62. package/src/metadata/MetadataObject.ts +131 -131
  63. package/src/metadata/MetadataProperty.ts +64 -64
  64. package/src/module.ts +1535 -1535
  65. package/src/programmers/ApplicationProgrammer.ts +55 -55
  66. package/src/programmers/AssertParseProgrammer.ts +45 -45
  67. package/src/programmers/AssertProgrammer.ts +444 -444
  68. package/src/programmers/AssertStringifyProgrammer.ts +45 -45
  69. package/src/programmers/CheckerProgrammer.ts +804 -804
  70. package/src/programmers/FeatureProgrammer.ts +327 -327
  71. package/src/programmers/IsParseProgrammer.ts +51 -51
  72. package/src/programmers/IsProgrammer.ts +172 -172
  73. package/src/programmers/IsStringifyProgrammer.ts +49 -49
  74. package/src/programmers/StringifyProgrammer.ts +756 -756
  75. package/src/programmers/ValidateParseProgrammer.ts +49 -49
  76. package/src/programmers/ValidateProgrammer.ts +236 -236
  77. package/src/programmers/ValidateStringifyProgrammer.ts +60 -60
  78. package/src/programmers/helpers/AtomicPredicator.ts +15 -15
  79. package/src/programmers/helpers/FunctionImporeter.ts +31 -31
  80. package/src/programmers/helpers/IExpressionEntry.ts +10 -10
  81. package/src/programmers/helpers/OptionPredicator.ts +11 -11
  82. package/src/programmers/helpers/StringifyJoinder.ts +111 -111
  83. package/src/programmers/helpers/StringifyPredicator.ts +18 -18
  84. package/src/programmers/helpers/UnionExplorer.ts +437 -437
  85. package/src/programmers/helpers/UnionPredicator.ts +81 -81
  86. package/src/programmers/internal/application_array.ts +45 -45
  87. package/src/programmers/internal/application_boolean.ts +17 -17
  88. package/src/programmers/internal/application_constant.ts +29 -29
  89. package/src/programmers/internal/application_default.ts +17 -17
  90. package/src/programmers/internal/application_default_string.ts +32 -32
  91. package/src/programmers/internal/application_native.ts +29 -29
  92. package/src/programmers/internal/application_number.ts +76 -76
  93. package/src/programmers/internal/application_object.ts +103 -103
  94. package/src/programmers/internal/application_schema.ts +221 -221
  95. package/src/programmers/internal/application_string.ts +49 -49
  96. package/src/programmers/internal/application_templates.ts +27 -27
  97. package/src/programmers/internal/application_tuple.ts +25 -25
  98. package/src/programmers/internal/check_array.ts +44 -44
  99. package/src/programmers/internal/check_dynamic_properties.ts +146 -146
  100. package/src/programmers/internal/check_everything.ts +25 -25
  101. package/src/programmers/internal/check_length.ts +46 -46
  102. package/src/programmers/internal/check_native.ts +9 -9
  103. package/src/programmers/internal/check_number.ts +178 -178
  104. package/src/programmers/internal/check_object.ts +42 -42
  105. package/src/programmers/internal/check_string.ts +24 -24
  106. package/src/programmers/internal/check_string_tags.ts +63 -63
  107. package/src/programmers/internal/check_template.ts +50 -50
  108. package/src/programmers/internal/decode_union_object.ts +73 -73
  109. package/src/programmers/internal/feature_object_entries.ts +49 -49
  110. package/src/programmers/internal/metadata_to_pattern.ts +31 -31
  111. package/src/programmers/internal/stringify_dynamic_properties.ts +164 -164
  112. package/src/programmers/internal/stringify_native.ts +8 -8
  113. package/src/programmers/internal/stringify_regular_properties.ts +81 -81
  114. package/src/programmers/internal/template_to_pattern.ts +15 -15
  115. package/src/schemas/IJsonApplication.ts +9 -9
  116. package/src/schemas/IJsonComponents.ts +24 -24
  117. package/src/schemas/IJsonSchema.ts +92 -92
  118. package/src/transform.ts +20 -20
  119. package/src/transformers/CallExpressionTransformer.ts +124 -124
  120. package/src/transformers/ExpressionWithArgumentTransformer.ts +66 -66
  121. package/src/transformers/FileTransformer.ts +49 -49
  122. package/src/transformers/IProject.ts +11 -11
  123. package/src/transformers/ITransformOptions.ts +4 -4
  124. package/src/transformers/NodeTransformer.ts +19 -19
  125. package/src/transformers/features/miscellaneous/ApplicationTransformer.ts +114 -114
  126. package/src/transformers/features/miscellaneous/CreateInstanceTransformer.ts +41 -41
  127. package/src/transformers/features/miscellaneous/MetadataTransformer.ts +55 -55
  128. package/src/transformers/features/parsers/AssertParseTransformer.ts +36 -36
  129. package/src/transformers/features/parsers/CreateAssertParseTransformer.ts +32 -32
  130. package/src/transformers/features/parsers/CreateIsParseTransformer.ts +32 -32
  131. package/src/transformers/features/parsers/CreateValidateParseTransformer.ts +32 -32
  132. package/src/transformers/features/parsers/IsParseTransformer.ts +36 -36
  133. package/src/transformers/features/parsers/ValidateParseTransformer.ts +36 -36
  134. package/src/transformers/features/stringifiers/AssertStringifyTransformer.ts +38 -38
  135. package/src/transformers/features/stringifiers/CreateAssertStringifyTransformer.ts +32 -32
  136. package/src/transformers/features/stringifiers/CreateIsStringifyTransformer.ts +32 -32
  137. package/src/transformers/features/stringifiers/CreateStringifyTransformer.ts +31 -31
  138. package/src/transformers/features/stringifiers/CreateValidateStringifyProgrammer.ts +32 -32
  139. package/src/transformers/features/stringifiers/IsStringifyTransformer.ts +38 -38
  140. package/src/transformers/features/stringifiers/StringifyTransformer.ts +36 -36
  141. package/src/transformers/features/stringifiers/ValidateStringifyTransformer.ts +38 -38
  142. package/src/transformers/features/validators/AssertTransformer.ts +43 -43
  143. package/src/transformers/features/validators/CreateAssertTransformer.ts +35 -35
  144. package/src/transformers/features/validators/CreateIsTransformer.ts +35 -35
  145. package/src/transformers/features/validators/CreateValidateTransformer.ts +35 -35
  146. package/src/transformers/features/validators/IsTransformer.ts +43 -43
  147. package/src/transformers/features/validators/ValidateTransformer.ts +43 -43
  148. package/src/typings/Atomic.ts +17 -17
  149. package/src/typings/ClassProperties.ts +5 -5
  150. package/src/typings/OmitNever.ts +3 -3
  151. package/src/typings/SpecialFields.ts +3 -3
  152. package/src/typings/Writable.ts +11 -11
  153. package/src/utils/ArrayUtil.ts +49 -49
  154. package/src/utils/Escaper.ts +50 -50
  155. package/src/utils/MapUtil.ts +14 -14
  156. package/src/utils/PatternUtil.ts +30 -30
  157. package/src/utils/Singleton.ts +17 -17
@@ -1,756 +1,756 @@
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 { ValueFactory } from "../factories/ValueFactory";
8
-
9
- import { IMetadataTag } from "../metadata/IMetadataTag";
10
- import { Metadata } from "../metadata/Metadata";
11
- import { MetadataObject } from "../metadata/MetadataObject";
12
-
13
- import { IProject } from "../transformers/IProject";
14
-
15
- import { ArrayUtil } from "../utils/ArrayUtil";
16
-
17
- import { FeatureProgrammer } from "./FeatureProgrammer";
18
- import { IsProgrammer } from "./IsProgrammer";
19
- import { AtomicPredicator } from "./helpers/AtomicPredicator";
20
- import { FunctionImporter } from "./helpers/FunctionImporeter";
21
- import { IExpressionEntry } from "./helpers/IExpressionEntry";
22
- import { OptionPredicator } from "./helpers/OptionPredicator";
23
- import { StringifyJoiner } from "./helpers/StringifyJoinder";
24
- import { StringifyPredicator } from "./helpers/StringifyPredicator";
25
- import { UnionExplorer } from "./helpers/UnionExplorer";
26
- import { decode_union_object } from "./internal/decode_union_object";
27
- import { feature_object_entries } from "./internal/feature_object_entries";
28
-
29
- export namespace StringifyProgrammer {
30
- /* -----------------------------------------------------------
31
- GENERATORS
32
- ----------------------------------------------------------- */
33
- export function generate(
34
- project: IProject,
35
- modulo: ts.LeftHandSideExpression,
36
- ) {
37
- const importer: FunctionImporter = new FunctionImporter();
38
- return FeatureProgrammer.generate(
39
- project,
40
- CONFIG(project, importer),
41
- importer,
42
- (collection) => {
43
- const isFunctors = IsProgrammer.generate_functors(
44
- project,
45
- importer,
46
- )(collection);
47
- const isUnioners = IsProgrammer.generate_unioners(
48
- project,
49
- importer,
50
- )(collection);
51
-
52
- return [
53
- ...importer.declare(modulo),
54
- ...isFunctors,
55
- ...isUnioners,
56
- ];
57
- },
58
- );
59
- }
60
-
61
- /* -----------------------------------------------------------
62
- DECODERS
63
- ----------------------------------------------------------- */
64
- const decode =
65
- (project: IProject, importer: FunctionImporter) =>
66
- (
67
- input: ts.Expression,
68
- meta: Metadata,
69
- explore: FeatureProgrammer.IExplore,
70
- tags: IMetadataTag[],
71
- ): ts.Expression => {
72
- // ANY TYPE
73
- if (meta.any === true)
74
- return wrap_required(
75
- input,
76
- meta,
77
- explore,
78
- )(
79
- wrap_functional(
80
- input,
81
- meta,
82
- explore,
83
- )(
84
- ts.factory.createCallExpression(
85
- ts.factory.createIdentifier("JSON.stringify"),
86
- undefined,
87
- [input],
88
- ),
89
- ),
90
- );
91
-
92
- // ONLY NULL OR UNDEFINED
93
- const size: number = meta.size();
94
- if (
95
- size === 0 &&
96
- (meta.required === false || meta.nullable === true)
97
- ) {
98
- if (meta.required === false && meta.nullable === true)
99
- return explore.from === "array"
100
- ? ts.factory.createStringLiteral("null")
101
- : ts.factory.createConditionalExpression(
102
- ts.factory.createStrictEquality(
103
- ts.factory.createNull(),
104
- input,
105
- ),
106
- undefined,
107
- ts.factory.createStringLiteral("null"),
108
- undefined,
109
- ts.factory.createIdentifier("undefined"),
110
- );
111
- else if (meta.required === false)
112
- return explore.from === "array"
113
- ? ts.factory.createStringLiteral("null")
114
- : ts.factory.createIdentifier("undefined");
115
- else return ts.factory.createStringLiteral("null");
116
- }
117
-
118
- //----
119
- // LIST UP UNION TYPES
120
- //----
121
- const unions: IUnion[] = [];
122
-
123
- // toJSON() METHOD
124
- if (meta.resolved !== null)
125
- if (size === 1)
126
- return decode_to_json(project, importer)(
127
- input,
128
- meta.resolved,
129
- explore,
130
- tags,
131
- );
132
- else
133
- unions.push({
134
- type: "resolved",
135
- is: () => IsProgrammer.decode_to_json(input),
136
- value: () =>
137
- decode_to_json(project, importer)(
138
- input,
139
- meta.resolved!,
140
- explore,
141
- tags,
142
- ),
143
- });
144
- else if (meta.functional === true)
145
- unions.push({
146
- type: "functional",
147
- is: () => IsProgrammer.decode_functional(input),
148
- value: () => decode_functional(explore),
149
- });
150
-
151
- // TEMPLATES
152
- if (
153
- meta.templates.length ||
154
- ArrayUtil.has(meta.constants, (c) => c.type === "string")
155
- )
156
- if (AtomicPredicator.template(meta)) {
157
- const partial = Metadata.initialize();
158
- partial.atomics.push("string"),
159
- unions.push({
160
- type: "template literal",
161
- is: () =>
162
- IsProgrammer.decode(project, importer)(
163
- input,
164
- partial,
165
- explore,
166
- [],
167
- ),
168
- value: () =>
169
- decode_atomic(project, importer)(
170
- input,
171
- "string",
172
- explore,
173
- tags,
174
- ),
175
- });
176
- }
177
-
178
- // CONSTANTS
179
- for (const constant of meta.constants)
180
- if (
181
- constant.type !== "string" &&
182
- AtomicPredicator.constant(meta)(constant.type)
183
- )
184
- unions.push({
185
- type: "atomic",
186
- is: () =>
187
- IsProgrammer.decode(project, importer)(
188
- input,
189
- (() => {
190
- const partial = Metadata.initialize();
191
- partial.atomics.push(constant.type);
192
- return partial;
193
- })(),
194
- explore,
195
- [],
196
- ),
197
- value: () =>
198
- decode_atomic(project, importer)(
199
- input,
200
- constant.type,
201
- explore,
202
- tags,
203
- ),
204
- });
205
- else if (meta.templates.length === 0)
206
- unions.push({
207
- type: "const string",
208
- is: () =>
209
- IsProgrammer.decode(project, importer)(
210
- input,
211
- (() => {
212
- const partial = Metadata.initialize();
213
- partial.atomics.push("string");
214
- return partial;
215
- })(),
216
- explore,
217
- [],
218
- ),
219
- value: () =>
220
- decode_constant_string(project, importer)(
221
- input,
222
- [...constant.values] as string[],
223
- explore,
224
- ),
225
- });
226
- for (const type of meta.atomics)
227
- unions.push({
228
- type: "atomic",
229
- is: () =>
230
- IsProgrammer.decode(project, importer)(
231
- input,
232
- (() => {
233
- const partial = Metadata.initialize();
234
- partial.atomics.push(type);
235
- return partial;
236
- })(),
237
- explore,
238
- [],
239
- ),
240
- value: () =>
241
- decode_atomic(project, importer)(
242
- input,
243
- type,
244
- explore,
245
- tags,
246
- ),
247
- });
248
-
249
- // TUPLES
250
- for (const tuple of meta.tuples) {
251
- for (const child of tuple)
252
- if (StringifyPredicator.undefindable(meta))
253
- throw new Error(
254
- `Error on typia.stringify(): tuple cannot contain undefined value - (${child.getName()}).`,
255
- );
256
- unions.push({
257
- type: "tuple",
258
- is: () =>
259
- IsProgrammer.decode(project, importer)(
260
- input,
261
- (() => {
262
- const partial = Metadata.initialize();
263
- partial.tuples.push(tuple);
264
- return partial;
265
- })(),
266
- explore,
267
- [],
268
- ),
269
- value: () =>
270
- decode_tuple(project, importer)(
271
- input,
272
- tuple,
273
- explore,
274
- tags,
275
- ),
276
- });
277
- }
278
-
279
- // ARRAYS
280
- if (meta.arrays.length) {
281
- for (const child of meta.arrays)
282
- if (StringifyPredicator.undefindable(child))
283
- throw new Error(
284
- `Error on typia.stringify(): array cannot contain undefined value (${child.getName()}).`,
285
- );
286
- const value: () => ts.Expression = meta.arrays.some(
287
- (elem) => elem.any,
288
- )
289
- ? () =>
290
- ts.factory.createCallExpression(
291
- ts.factory.createIdentifier("JSON.stringify"),
292
- undefined,
293
- [input],
294
- )
295
- : () =>
296
- explore_arrays(project, importer)(
297
- input,
298
- meta.arrays,
299
- {
300
- ...explore,
301
- from: "array",
302
- },
303
- [],
304
- );
305
-
306
- unions.push({
307
- type: "array",
308
- is: () => ExpressionFactory.isArray(input),
309
- value,
310
- });
311
- }
312
-
313
- // BUILT-IN CLASSES
314
- if (meta.natives.length)
315
- for (const native of meta.natives)
316
- unions.push({
317
- type: "object",
318
- is: () => ExpressionFactory.isInstanceOf(input, native),
319
- value: () => ts.factory.createStringLiteral("{}"),
320
- });
321
-
322
- // SETS
323
- if (meta.sets.length)
324
- unions.push({
325
- type: "object",
326
- is: () => ExpressionFactory.isInstanceOf(input, "Set"),
327
- value: () => ts.factory.createStringLiteral("{}"),
328
- });
329
-
330
- // MAPS
331
- if (meta.maps.length)
332
- unions.push({
333
- type: "object",
334
- is: () => ExpressionFactory.isInstanceOf(input, "Map"),
335
- value: () => ts.factory.createStringLiteral("{}"),
336
- });
337
-
338
- // OBJECTS
339
- if (meta.objects.length)
340
- unions.push({
341
- type: "object",
342
- is: () =>
343
- ExpressionFactory.isObject(input, {
344
- checkNull: true,
345
- checkArray: meta.objects.some((obj) =>
346
- obj.properties.every(
347
- (prop) =>
348
- !prop.key.isSoleLiteral() ||
349
- !prop.value.required,
350
- ),
351
- ),
352
- }),
353
- value: () =>
354
- meta.isParentResolved() === false &&
355
- meta.objects.length === 1 &&
356
- meta.objects[0]!._Is_simple()
357
- ? (() => {
358
- const obj: MetadataObject = meta.objects[0]!;
359
- const entries: IExpressionEntry[] =
360
- feature_object_entries({
361
- decoder: decode(project, importer),
362
- trace: false,
363
- path: false,
364
- })(obj)(input);
365
- return StringifyJoiner.object(importer)(
366
- entries,
367
- );
368
- })()
369
- : explore_objects(input, meta, {
370
- ...explore,
371
- from: "object",
372
- }),
373
- });
374
-
375
- //----
376
- // RETURNS
377
- //----
378
- // CHECK NULL AND UNDEFINED
379
- const wrapper = (output: ts.Expression) =>
380
- wrap_required(
381
- input,
382
- meta,
383
- explore,
384
- )(wrap_nullable(input, meta)(output));
385
-
386
- // DIRECT RETURN
387
- if (unions.length === 0)
388
- return ts.factory.createCallExpression(
389
- ts.factory.createIdentifier("JSON.stringify"),
390
- undefined,
391
- [input],
392
- );
393
- else if (unions.length === 1) return wrapper(unions[0]!.value());
394
-
395
- // RETURN WITH TYPE CHECKING
396
- return wrapper(
397
- ts.factory.createCallExpression(
398
- ts.factory.createArrowFunction(
399
- undefined,
400
- undefined,
401
- [],
402
- undefined,
403
- undefined,
404
- iterate(importer, input, unions, meta.getName()),
405
- ),
406
- undefined,
407
- undefined,
408
- ),
409
- );
410
- };
411
-
412
- const decode_array = (project: IProject, importer: FunctionImporter) =>
413
- FeatureProgrammer.decode_array(
414
- CONFIG(project, importer),
415
- importer,
416
- StringifyJoiner.array,
417
- );
418
-
419
- const decode_object = () =>
420
- FeatureProgrammer.decode_object({
421
- trace: false,
422
- path: false,
423
- functors: FUNCTORS,
424
- });
425
-
426
- const decode_tuple =
427
- (project: IProject, importer: FunctionImporter) =>
428
- (
429
- input: ts.Expression,
430
- tuple: Metadata[],
431
- explore: FeatureProgrammer.IExplore,
432
- tags: IMetadataTag[],
433
- ): ts.Expression => {
434
- const children: ts.Expression[] = tuple
435
- .filter((elem) => elem.rest === null)
436
- .map((elem, index) =>
437
- decode(project, importer)(
438
- ts.factory.createElementAccessExpression(input, index),
439
- elem,
440
- {
441
- ...explore,
442
- from: "array",
443
- },
444
- tags,
445
- ),
446
- );
447
- const rest = (() => {
448
- if (tuple.length === 0) return null;
449
- const last = tuple[tuple.length - 1]!;
450
- if (last.rest === null) return null;
451
-
452
- const code = decode(project, importer)(
453
- ts.factory.createCallExpression(
454
- IdentifierFactory.join(input, "slice"),
455
- undefined,
456
- [ts.factory.createNumericLiteral(tuple.length - 1)],
457
- ),
458
- (() => {
459
- const wrapper: Metadata = Metadata.initialize();
460
- wrapper.arrays.push(tuple[tuple.length - 1]!.rest!);
461
- return wrapper;
462
- })(),
463
- {
464
- ...explore,
465
- start: tuple.length - 1,
466
- },
467
- tags,
468
- );
469
- return ts.factory.createCallExpression(
470
- importer.use("rest"),
471
- undefined,
472
- [code],
473
- );
474
- })();
475
- return StringifyJoiner.tuple(children, rest);
476
- };
477
-
478
- const decode_atomic =
479
- (project: IProject, importer: FunctionImporter) =>
480
- (
481
- input: ts.Expression,
482
- type: string,
483
- explore: FeatureProgrammer.IExplore,
484
- tagList: IMetadataTag[],
485
- ) => {
486
- if (type === "string")
487
- if (tagList.find((tag) => tag.kind === "format") !== undefined)
488
- return [
489
- ts.factory.createStringLiteral('"'),
490
- input,
491
- ts.factory.createStringLiteral('"'),
492
- ].reduce((x, y) => ts.factory.createAdd(x, y));
493
- else
494
- return ts.factory.createCallExpression(
495
- importer.use("string"),
496
- undefined,
497
- [input],
498
- );
499
- else if (
500
- type === "number" &&
501
- OptionPredicator.numeric(project.options)
502
- )
503
- input = ts.factory.createCallExpression(
504
- importer.use("number"),
505
- undefined,
506
- [input],
507
- );
508
-
509
- return explore.from !== "top"
510
- ? input
511
- : ts.factory.createCallExpression(
512
- IdentifierFactory.join(input, "toString"),
513
- undefined,
514
- undefined,
515
- );
516
- };
517
-
518
- const decode_constant_string =
519
- (project: IProject, importer: FunctionImporter) =>
520
- (
521
- input: ts.Expression,
522
- values: string[],
523
- explore: FeatureProgrammer.IExplore,
524
- ): ts.Expression => {
525
- if (values.every((v) => !StringifyPredicator.require_escape(v)))
526
- return [
527
- ts.factory.createStringLiteral('"'),
528
- input,
529
- ts.factory.createStringLiteral('"'),
530
- ].reduce((x, y) => ts.factory.createAdd(x, y));
531
- else
532
- return decode_atomic(project, importer)(
533
- input,
534
- "string",
535
- explore,
536
- [],
537
- );
538
- };
539
-
540
- const decode_to_json =
541
- (project: IProject, importer: FunctionImporter) =>
542
- (
543
- input: ts.Expression,
544
- resolved: Metadata,
545
- explore: FeatureProgrammer.IExplore,
546
- tags: IMetadataTag[],
547
- ): ts.Expression => {
548
- return decode(project, importer)(
549
- ts.factory.createCallExpression(
550
- IdentifierFactory.join(input, "toJSON"),
551
- undefined,
552
- [],
553
- ),
554
- resolved,
555
- explore,
556
- tags,
557
- );
558
- };
559
-
560
- function decode_functional(explore: FeatureProgrammer.IExplore) {
561
- return explore.from === "array"
562
- ? ts.factory.createStringLiteral("null")
563
- : ts.factory.createIdentifier("undefined");
564
- }
565
-
566
- /* -----------------------------------------------------------
567
- EXPLORERS
568
- ----------------------------------------------------------- */
569
- const explore_arrays = (project: IProject, importer: FunctionImporter) =>
570
- UnionExplorer.array({
571
- checker: IsProgrammer.decode(project, importer),
572
- decoder: decode_array(project, importer),
573
- empty: ts.factory.createStringLiteral("[]"),
574
- success: ts.factory.createTrue(),
575
- failure: (input, expected) =>
576
- create_throw_error(importer, input, expected),
577
- });
578
-
579
- const explore_objects = (
580
- input: ts.Expression,
581
- meta: Metadata,
582
- explore: FeatureProgrammer.IExplore,
583
- ) => {
584
- if (meta.objects.length === 1)
585
- return decode_object()(input, meta.objects[0]!, explore);
586
-
587
- return ts.factory.createCallExpression(
588
- ts.factory.createIdentifier(`${UNIONERS}${meta.union_index!}`),
589
- undefined,
590
- [input],
591
- );
592
- };
593
-
594
- /* -----------------------------------------------------------
595
- RETURN SCRIPTS
596
- ----------------------------------------------------------- */
597
- function wrap_required(
598
- input: ts.Expression,
599
- meta: Metadata,
600
- explore: FeatureProgrammer.IExplore,
601
- ): (expression: ts.Expression) => ts.Expression {
602
- if (meta.required === true && meta.any === false)
603
- return (expression) => expression;
604
- return (expression) =>
605
- ts.factory.createConditionalExpression(
606
- ts.factory.createStrictInequality(
607
- ts.factory.createIdentifier("undefined"),
608
- input,
609
- ),
610
- undefined,
611
- expression,
612
- undefined,
613
- explore.from === "array"
614
- ? ts.factory.createStringLiteral("null")
615
- : ts.factory.createIdentifier("undefined"),
616
- );
617
- }
618
-
619
- function wrap_nullable(
620
- input: ts.Expression,
621
- meta: Metadata,
622
- ): (expression: ts.Expression) => ts.Expression {
623
- if (meta.nullable === false) return (expression) => expression;
624
- return (expression) =>
625
- ts.factory.createConditionalExpression(
626
- ts.factory.createStrictInequality(
627
- ts.factory.createNull(),
628
- input,
629
- ),
630
- undefined,
631
- expression,
632
- undefined,
633
- ts.factory.createStringLiteral("null"),
634
- );
635
- }
636
-
637
- function wrap_functional(
638
- input: ts.Expression,
639
- meta: Metadata,
640
- explore: FeatureProgrammer.IExplore,
641
- ): (expression: ts.Expression) => ts.Expression {
642
- if (meta.functional === false) return (expression) => expression;
643
- return (expression) =>
644
- ts.factory.createConditionalExpression(
645
- ts.factory.createStrictInequality(
646
- ts.factory.createStringLiteral("function"),
647
- ValueFactory.TYPEOF(input),
648
- ),
649
- undefined,
650
- expression,
651
- undefined,
652
- decode_functional(explore),
653
- );
654
- }
655
-
656
- const iterate = (
657
- importer: FunctionImporter,
658
- input: ts.Expression,
659
- unions: IUnion[],
660
- expected: string,
661
- ) =>
662
- ts.factory.createBlock(
663
- [
664
- ...unions.map((u) =>
665
- ts.factory.createIfStatement(
666
- u.is(),
667
- ts.factory.createReturnStatement(u.value()),
668
- ),
669
- ),
670
- create_throw_error(importer, input, expected),
671
- ],
672
- true,
673
- );
674
-
675
- /* -----------------------------------------------------------
676
- CONFIGURATIONS
677
- ----------------------------------------------------------- */
678
- const FUNCTORS = "$so";
679
- const UNIONERS = "$su";
680
-
681
- const CONFIG = (
682
- project: IProject,
683
- importer: FunctionImporter,
684
- ): FeatureProgrammer.IConfig => ({
685
- functors: FUNCTORS,
686
- unioners: UNIONERS,
687
- trace: false,
688
- path: false,
689
- initializer,
690
- decoder: decode(project, importer),
691
- objector: OBJECTOR(project, importer),
692
- });
693
-
694
- const initializer: FeatureProgrammer.Initializer = ({ checker }, type) => {
695
- const collection: MetadataCollection = new MetadataCollection();
696
- const meta: Metadata = MetadataFactory.generate(
697
- checker,
698
- collection,
699
- type,
700
- {
701
- resolve: true,
702
- constant: true,
703
- },
704
- );
705
- return [collection, meta];
706
- };
707
-
708
- const OBJECTOR = (
709
- project: IProject,
710
- importer: FunctionImporter,
711
- ): FeatureProgrammer.IConfig.IObjector => ({
712
- checker: IsProgrammer.decode(project, importer),
713
- decoder: decode_object(),
714
- joiner: StringifyJoiner.object(importer),
715
- unionizer: decode_union_object(IsProgrammer.decode_object())(
716
- decode_object(),
717
- )((exp) => exp)((value, expected) =>
718
- create_throw_error(importer, value, expected),
719
- ),
720
- failure: (input, expected) =>
721
- create_throw_error(importer, input, expected),
722
- is: (expr) => expr,
723
- required: (expr) => expr,
724
- });
725
-
726
- function create_throw_error(
727
- importer: FunctionImporter,
728
- value: ts.Expression,
729
- expected: string,
730
- ) {
731
- return ts.factory.createExpressionStatement(
732
- ts.factory.createCallExpression(
733
- importer.use("throws"),
734
- [],
735
- [
736
- ts.factory.createObjectLiteralExpression(
737
- [
738
- ts.factory.createPropertyAssignment(
739
- "expected",
740
- ts.factory.createStringLiteral(expected),
741
- ),
742
- ts.factory.createPropertyAssignment("value", value),
743
- ],
744
- true,
745
- ),
746
- ],
747
- ),
748
- );
749
- }
750
- }
751
-
752
- interface IUnion {
753
- type: string;
754
- is: () => ts.Expression;
755
- value: () => ts.Expression;
756
- }
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 { ValueFactory } from "../factories/ValueFactory";
8
+
9
+ import { IMetadataTag } from "../metadata/IMetadataTag";
10
+ import { Metadata } from "../metadata/Metadata";
11
+ import { MetadataObject } from "../metadata/MetadataObject";
12
+
13
+ import { IProject } from "../transformers/IProject";
14
+
15
+ import { ArrayUtil } from "../utils/ArrayUtil";
16
+
17
+ import { FeatureProgrammer } from "./FeatureProgrammer";
18
+ import { IsProgrammer } from "./IsProgrammer";
19
+ import { AtomicPredicator } from "./helpers/AtomicPredicator";
20
+ import { FunctionImporter } from "./helpers/FunctionImporeter";
21
+ import { IExpressionEntry } from "./helpers/IExpressionEntry";
22
+ import { OptionPredicator } from "./helpers/OptionPredicator";
23
+ import { StringifyJoiner } from "./helpers/StringifyJoinder";
24
+ import { StringifyPredicator } from "./helpers/StringifyPredicator";
25
+ import { UnionExplorer } from "./helpers/UnionExplorer";
26
+ import { decode_union_object } from "./internal/decode_union_object";
27
+ import { feature_object_entries } from "./internal/feature_object_entries";
28
+
29
+ export namespace StringifyProgrammer {
30
+ /* -----------------------------------------------------------
31
+ GENERATORS
32
+ ----------------------------------------------------------- */
33
+ export function generate(
34
+ project: IProject,
35
+ modulo: ts.LeftHandSideExpression,
36
+ ) {
37
+ const importer: FunctionImporter = new FunctionImporter();
38
+ return FeatureProgrammer.generate(
39
+ project,
40
+ CONFIG(project, importer),
41
+ importer,
42
+ (collection) => {
43
+ const isFunctors = IsProgrammer.generate_functors(
44
+ project,
45
+ importer,
46
+ )(collection);
47
+ const isUnioners = IsProgrammer.generate_unioners(
48
+ project,
49
+ importer,
50
+ )(collection);
51
+
52
+ return [
53
+ ...importer.declare(modulo),
54
+ ...isFunctors,
55
+ ...isUnioners,
56
+ ];
57
+ },
58
+ );
59
+ }
60
+
61
+ /* -----------------------------------------------------------
62
+ DECODERS
63
+ ----------------------------------------------------------- */
64
+ const decode =
65
+ (project: IProject, importer: FunctionImporter) =>
66
+ (
67
+ input: ts.Expression,
68
+ meta: Metadata,
69
+ explore: FeatureProgrammer.IExplore,
70
+ tags: IMetadataTag[],
71
+ ): ts.Expression => {
72
+ // ANY TYPE
73
+ if (meta.any === true)
74
+ return wrap_required(
75
+ input,
76
+ meta,
77
+ explore,
78
+ )(
79
+ wrap_functional(
80
+ input,
81
+ meta,
82
+ explore,
83
+ )(
84
+ ts.factory.createCallExpression(
85
+ ts.factory.createIdentifier("JSON.stringify"),
86
+ undefined,
87
+ [input],
88
+ ),
89
+ ),
90
+ );
91
+
92
+ // ONLY NULL OR UNDEFINED
93
+ const size: number = meta.size();
94
+ if (
95
+ size === 0 &&
96
+ (meta.required === false || meta.nullable === true)
97
+ ) {
98
+ if (meta.required === false && meta.nullable === true)
99
+ return explore.from === "array"
100
+ ? ts.factory.createStringLiteral("null")
101
+ : ts.factory.createConditionalExpression(
102
+ ts.factory.createStrictEquality(
103
+ ts.factory.createNull(),
104
+ input,
105
+ ),
106
+ undefined,
107
+ ts.factory.createStringLiteral("null"),
108
+ undefined,
109
+ ts.factory.createIdentifier("undefined"),
110
+ );
111
+ else if (meta.required === false)
112
+ return explore.from === "array"
113
+ ? ts.factory.createStringLiteral("null")
114
+ : ts.factory.createIdentifier("undefined");
115
+ else return ts.factory.createStringLiteral("null");
116
+ }
117
+
118
+ //----
119
+ // LIST UP UNION TYPES
120
+ //----
121
+ const unions: IUnion[] = [];
122
+
123
+ // toJSON() METHOD
124
+ if (meta.resolved !== null)
125
+ if (size === 1)
126
+ return decode_to_json(project, importer)(
127
+ input,
128
+ meta.resolved,
129
+ explore,
130
+ tags,
131
+ );
132
+ else
133
+ unions.push({
134
+ type: "resolved",
135
+ is: () => IsProgrammer.decode_to_json(input),
136
+ value: () =>
137
+ decode_to_json(project, importer)(
138
+ input,
139
+ meta.resolved!,
140
+ explore,
141
+ tags,
142
+ ),
143
+ });
144
+ else if (meta.functional === true)
145
+ unions.push({
146
+ type: "functional",
147
+ is: () => IsProgrammer.decode_functional(input),
148
+ value: () => decode_functional(explore),
149
+ });
150
+
151
+ // TEMPLATES
152
+ if (
153
+ meta.templates.length ||
154
+ ArrayUtil.has(meta.constants, (c) => c.type === "string")
155
+ )
156
+ if (AtomicPredicator.template(meta)) {
157
+ const partial = Metadata.initialize();
158
+ partial.atomics.push("string"),
159
+ unions.push({
160
+ type: "template literal",
161
+ is: () =>
162
+ IsProgrammer.decode(project, importer)(
163
+ input,
164
+ partial,
165
+ explore,
166
+ [],
167
+ ),
168
+ value: () =>
169
+ decode_atomic(project, importer)(
170
+ input,
171
+ "string",
172
+ explore,
173
+ tags,
174
+ ),
175
+ });
176
+ }
177
+
178
+ // CONSTANTS
179
+ for (const constant of meta.constants)
180
+ if (
181
+ constant.type !== "string" &&
182
+ AtomicPredicator.constant(meta)(constant.type)
183
+ )
184
+ unions.push({
185
+ type: "atomic",
186
+ is: () =>
187
+ IsProgrammer.decode(project, importer)(
188
+ input,
189
+ (() => {
190
+ const partial = Metadata.initialize();
191
+ partial.atomics.push(constant.type);
192
+ return partial;
193
+ })(),
194
+ explore,
195
+ [],
196
+ ),
197
+ value: () =>
198
+ decode_atomic(project, importer)(
199
+ input,
200
+ constant.type,
201
+ explore,
202
+ tags,
203
+ ),
204
+ });
205
+ else if (meta.templates.length === 0)
206
+ unions.push({
207
+ type: "const string",
208
+ is: () =>
209
+ IsProgrammer.decode(project, importer)(
210
+ input,
211
+ (() => {
212
+ const partial = Metadata.initialize();
213
+ partial.atomics.push("string");
214
+ return partial;
215
+ })(),
216
+ explore,
217
+ [],
218
+ ),
219
+ value: () =>
220
+ decode_constant_string(project, importer)(
221
+ input,
222
+ [...constant.values] as string[],
223
+ explore,
224
+ ),
225
+ });
226
+ for (const type of meta.atomics)
227
+ unions.push({
228
+ type: "atomic",
229
+ is: () =>
230
+ IsProgrammer.decode(project, importer)(
231
+ input,
232
+ (() => {
233
+ const partial = Metadata.initialize();
234
+ partial.atomics.push(type);
235
+ return partial;
236
+ })(),
237
+ explore,
238
+ [],
239
+ ),
240
+ value: () =>
241
+ decode_atomic(project, importer)(
242
+ input,
243
+ type,
244
+ explore,
245
+ tags,
246
+ ),
247
+ });
248
+
249
+ // TUPLES
250
+ for (const tuple of meta.tuples) {
251
+ for (const child of tuple)
252
+ if (StringifyPredicator.undefindable(meta))
253
+ throw new Error(
254
+ `Error on typia.stringify(): tuple cannot contain undefined value - (${child.getName()}).`,
255
+ );
256
+ unions.push({
257
+ type: "tuple",
258
+ is: () =>
259
+ IsProgrammer.decode(project, importer)(
260
+ input,
261
+ (() => {
262
+ const partial = Metadata.initialize();
263
+ partial.tuples.push(tuple);
264
+ return partial;
265
+ })(),
266
+ explore,
267
+ [],
268
+ ),
269
+ value: () =>
270
+ decode_tuple(project, importer)(
271
+ input,
272
+ tuple,
273
+ explore,
274
+ tags,
275
+ ),
276
+ });
277
+ }
278
+
279
+ // ARRAYS
280
+ if (meta.arrays.length) {
281
+ for (const child of meta.arrays)
282
+ if (StringifyPredicator.undefindable(child))
283
+ throw new Error(
284
+ `Error on typia.stringify(): array cannot contain undefined value (${child.getName()}).`,
285
+ );
286
+ const value: () => ts.Expression = meta.arrays.some(
287
+ (elem) => elem.any,
288
+ )
289
+ ? () =>
290
+ ts.factory.createCallExpression(
291
+ ts.factory.createIdentifier("JSON.stringify"),
292
+ undefined,
293
+ [input],
294
+ )
295
+ : () =>
296
+ explore_arrays(project, importer)(
297
+ input,
298
+ meta.arrays,
299
+ {
300
+ ...explore,
301
+ from: "array",
302
+ },
303
+ [],
304
+ );
305
+
306
+ unions.push({
307
+ type: "array",
308
+ is: () => ExpressionFactory.isArray(input),
309
+ value,
310
+ });
311
+ }
312
+
313
+ // BUILT-IN CLASSES
314
+ if (meta.natives.length)
315
+ for (const native of meta.natives)
316
+ unions.push({
317
+ type: "object",
318
+ is: () => ExpressionFactory.isInstanceOf(input, native),
319
+ value: () => ts.factory.createStringLiteral("{}"),
320
+ });
321
+
322
+ // SETS
323
+ if (meta.sets.length)
324
+ unions.push({
325
+ type: "object",
326
+ is: () => ExpressionFactory.isInstanceOf(input, "Set"),
327
+ value: () => ts.factory.createStringLiteral("{}"),
328
+ });
329
+
330
+ // MAPS
331
+ if (meta.maps.length)
332
+ unions.push({
333
+ type: "object",
334
+ is: () => ExpressionFactory.isInstanceOf(input, "Map"),
335
+ value: () => ts.factory.createStringLiteral("{}"),
336
+ });
337
+
338
+ // OBJECTS
339
+ if (meta.objects.length)
340
+ unions.push({
341
+ type: "object",
342
+ is: () =>
343
+ ExpressionFactory.isObject(input, {
344
+ checkNull: true,
345
+ checkArray: meta.objects.some((obj) =>
346
+ obj.properties.every(
347
+ (prop) =>
348
+ !prop.key.isSoleLiteral() ||
349
+ !prop.value.required,
350
+ ),
351
+ ),
352
+ }),
353
+ value: () =>
354
+ meta.isParentResolved() === false &&
355
+ meta.objects.length === 1 &&
356
+ meta.objects[0]!._Is_simple()
357
+ ? (() => {
358
+ const obj: MetadataObject = meta.objects[0]!;
359
+ const entries: IExpressionEntry[] =
360
+ feature_object_entries({
361
+ decoder: decode(project, importer),
362
+ trace: false,
363
+ path: false,
364
+ })(obj)(input);
365
+ return StringifyJoiner.object(importer)(
366
+ entries,
367
+ );
368
+ })()
369
+ : explore_objects(input, meta, {
370
+ ...explore,
371
+ from: "object",
372
+ }),
373
+ });
374
+
375
+ //----
376
+ // RETURNS
377
+ //----
378
+ // CHECK NULL AND UNDEFINED
379
+ const wrapper = (output: ts.Expression) =>
380
+ wrap_required(
381
+ input,
382
+ meta,
383
+ explore,
384
+ )(wrap_nullable(input, meta)(output));
385
+
386
+ // DIRECT RETURN
387
+ if (unions.length === 0)
388
+ return ts.factory.createCallExpression(
389
+ ts.factory.createIdentifier("JSON.stringify"),
390
+ undefined,
391
+ [input],
392
+ );
393
+ else if (unions.length === 1) return wrapper(unions[0]!.value());
394
+
395
+ // RETURN WITH TYPE CHECKING
396
+ return wrapper(
397
+ ts.factory.createCallExpression(
398
+ ts.factory.createArrowFunction(
399
+ undefined,
400
+ undefined,
401
+ [],
402
+ undefined,
403
+ undefined,
404
+ iterate(importer, input, unions, meta.getName()),
405
+ ),
406
+ undefined,
407
+ undefined,
408
+ ),
409
+ );
410
+ };
411
+
412
+ const decode_array = (project: IProject, importer: FunctionImporter) =>
413
+ FeatureProgrammer.decode_array(
414
+ CONFIG(project, importer),
415
+ importer,
416
+ StringifyJoiner.array,
417
+ );
418
+
419
+ const decode_object = () =>
420
+ FeatureProgrammer.decode_object({
421
+ trace: false,
422
+ path: false,
423
+ functors: FUNCTORS,
424
+ });
425
+
426
+ const decode_tuple =
427
+ (project: IProject, importer: FunctionImporter) =>
428
+ (
429
+ input: ts.Expression,
430
+ tuple: Metadata[],
431
+ explore: FeatureProgrammer.IExplore,
432
+ tags: IMetadataTag[],
433
+ ): ts.Expression => {
434
+ const children: ts.Expression[] = tuple
435
+ .filter((elem) => elem.rest === null)
436
+ .map((elem, index) =>
437
+ decode(project, importer)(
438
+ ts.factory.createElementAccessExpression(input, index),
439
+ elem,
440
+ {
441
+ ...explore,
442
+ from: "array",
443
+ },
444
+ tags,
445
+ ),
446
+ );
447
+ const rest = (() => {
448
+ if (tuple.length === 0) return null;
449
+ const last = tuple[tuple.length - 1]!;
450
+ if (last.rest === null) return null;
451
+
452
+ const code = decode(project, importer)(
453
+ ts.factory.createCallExpression(
454
+ IdentifierFactory.join(input, "slice"),
455
+ undefined,
456
+ [ts.factory.createNumericLiteral(tuple.length - 1)],
457
+ ),
458
+ (() => {
459
+ const wrapper: Metadata = Metadata.initialize();
460
+ wrapper.arrays.push(tuple[tuple.length - 1]!.rest!);
461
+ return wrapper;
462
+ })(),
463
+ {
464
+ ...explore,
465
+ start: tuple.length - 1,
466
+ },
467
+ tags,
468
+ );
469
+ return ts.factory.createCallExpression(
470
+ importer.use("rest"),
471
+ undefined,
472
+ [code],
473
+ );
474
+ })();
475
+ return StringifyJoiner.tuple(children, rest);
476
+ };
477
+
478
+ const decode_atomic =
479
+ (project: IProject, importer: FunctionImporter) =>
480
+ (
481
+ input: ts.Expression,
482
+ type: string,
483
+ explore: FeatureProgrammer.IExplore,
484
+ tagList: IMetadataTag[],
485
+ ) => {
486
+ if (type === "string")
487
+ if (tagList.find((tag) => tag.kind === "format") !== undefined)
488
+ return [
489
+ ts.factory.createStringLiteral('"'),
490
+ input,
491
+ ts.factory.createStringLiteral('"'),
492
+ ].reduce((x, y) => ts.factory.createAdd(x, y));
493
+ else
494
+ return ts.factory.createCallExpression(
495
+ importer.use("string"),
496
+ undefined,
497
+ [input],
498
+ );
499
+ else if (
500
+ type === "number" &&
501
+ OptionPredicator.numeric(project.options)
502
+ )
503
+ input = ts.factory.createCallExpression(
504
+ importer.use("number"),
505
+ undefined,
506
+ [input],
507
+ );
508
+
509
+ return explore.from !== "top"
510
+ ? input
511
+ : ts.factory.createCallExpression(
512
+ IdentifierFactory.join(input, "toString"),
513
+ undefined,
514
+ undefined,
515
+ );
516
+ };
517
+
518
+ const decode_constant_string =
519
+ (project: IProject, importer: FunctionImporter) =>
520
+ (
521
+ input: ts.Expression,
522
+ values: string[],
523
+ explore: FeatureProgrammer.IExplore,
524
+ ): ts.Expression => {
525
+ if (values.every((v) => !StringifyPredicator.require_escape(v)))
526
+ return [
527
+ ts.factory.createStringLiteral('"'),
528
+ input,
529
+ ts.factory.createStringLiteral('"'),
530
+ ].reduce((x, y) => ts.factory.createAdd(x, y));
531
+ else
532
+ return decode_atomic(project, importer)(
533
+ input,
534
+ "string",
535
+ explore,
536
+ [],
537
+ );
538
+ };
539
+
540
+ const decode_to_json =
541
+ (project: IProject, importer: FunctionImporter) =>
542
+ (
543
+ input: ts.Expression,
544
+ resolved: Metadata,
545
+ explore: FeatureProgrammer.IExplore,
546
+ tags: IMetadataTag[],
547
+ ): ts.Expression => {
548
+ return decode(project, importer)(
549
+ ts.factory.createCallExpression(
550
+ IdentifierFactory.join(input, "toJSON"),
551
+ undefined,
552
+ [],
553
+ ),
554
+ resolved,
555
+ explore,
556
+ tags,
557
+ );
558
+ };
559
+
560
+ function decode_functional(explore: FeatureProgrammer.IExplore) {
561
+ return explore.from === "array"
562
+ ? ts.factory.createStringLiteral("null")
563
+ : ts.factory.createIdentifier("undefined");
564
+ }
565
+
566
+ /* -----------------------------------------------------------
567
+ EXPLORERS
568
+ ----------------------------------------------------------- */
569
+ const explore_arrays = (project: IProject, importer: FunctionImporter) =>
570
+ UnionExplorer.array({
571
+ checker: IsProgrammer.decode(project, importer),
572
+ decoder: decode_array(project, importer),
573
+ empty: ts.factory.createStringLiteral("[]"),
574
+ success: ts.factory.createTrue(),
575
+ failure: (input, expected) =>
576
+ create_throw_error(importer, input, expected),
577
+ });
578
+
579
+ const explore_objects = (
580
+ input: ts.Expression,
581
+ meta: Metadata,
582
+ explore: FeatureProgrammer.IExplore,
583
+ ) => {
584
+ if (meta.objects.length === 1)
585
+ return decode_object()(input, meta.objects[0]!, explore);
586
+
587
+ return ts.factory.createCallExpression(
588
+ ts.factory.createIdentifier(`${UNIONERS}${meta.union_index!}`),
589
+ undefined,
590
+ [input],
591
+ );
592
+ };
593
+
594
+ /* -----------------------------------------------------------
595
+ RETURN SCRIPTS
596
+ ----------------------------------------------------------- */
597
+ function wrap_required(
598
+ input: ts.Expression,
599
+ meta: Metadata,
600
+ explore: FeatureProgrammer.IExplore,
601
+ ): (expression: ts.Expression) => ts.Expression {
602
+ if (meta.required === true && meta.any === false)
603
+ return (expression) => expression;
604
+ return (expression) =>
605
+ ts.factory.createConditionalExpression(
606
+ ts.factory.createStrictInequality(
607
+ ts.factory.createIdentifier("undefined"),
608
+ input,
609
+ ),
610
+ undefined,
611
+ expression,
612
+ undefined,
613
+ explore.from === "array"
614
+ ? ts.factory.createStringLiteral("null")
615
+ : ts.factory.createIdentifier("undefined"),
616
+ );
617
+ }
618
+
619
+ function wrap_nullable(
620
+ input: ts.Expression,
621
+ meta: Metadata,
622
+ ): (expression: ts.Expression) => ts.Expression {
623
+ if (meta.nullable === false) return (expression) => expression;
624
+ return (expression) =>
625
+ ts.factory.createConditionalExpression(
626
+ ts.factory.createStrictInequality(
627
+ ts.factory.createNull(),
628
+ input,
629
+ ),
630
+ undefined,
631
+ expression,
632
+ undefined,
633
+ ts.factory.createStringLiteral("null"),
634
+ );
635
+ }
636
+
637
+ function wrap_functional(
638
+ input: ts.Expression,
639
+ meta: Metadata,
640
+ explore: FeatureProgrammer.IExplore,
641
+ ): (expression: ts.Expression) => ts.Expression {
642
+ if (meta.functional === false) return (expression) => expression;
643
+ return (expression) =>
644
+ ts.factory.createConditionalExpression(
645
+ ts.factory.createStrictInequality(
646
+ ts.factory.createStringLiteral("function"),
647
+ ValueFactory.TYPEOF(input),
648
+ ),
649
+ undefined,
650
+ expression,
651
+ undefined,
652
+ decode_functional(explore),
653
+ );
654
+ }
655
+
656
+ const iterate = (
657
+ importer: FunctionImporter,
658
+ input: ts.Expression,
659
+ unions: IUnion[],
660
+ expected: string,
661
+ ) =>
662
+ ts.factory.createBlock(
663
+ [
664
+ ...unions.map((u) =>
665
+ ts.factory.createIfStatement(
666
+ u.is(),
667
+ ts.factory.createReturnStatement(u.value()),
668
+ ),
669
+ ),
670
+ create_throw_error(importer, input, expected),
671
+ ],
672
+ true,
673
+ );
674
+
675
+ /* -----------------------------------------------------------
676
+ CONFIGURATIONS
677
+ ----------------------------------------------------------- */
678
+ const FUNCTORS = "$so";
679
+ const UNIONERS = "$su";
680
+
681
+ const CONFIG = (
682
+ project: IProject,
683
+ importer: FunctionImporter,
684
+ ): FeatureProgrammer.IConfig => ({
685
+ functors: FUNCTORS,
686
+ unioners: UNIONERS,
687
+ trace: false,
688
+ path: false,
689
+ initializer,
690
+ decoder: decode(project, importer),
691
+ objector: OBJECTOR(project, importer),
692
+ });
693
+
694
+ const initializer: FeatureProgrammer.Initializer = ({ checker }, type) => {
695
+ const collection: MetadataCollection = new MetadataCollection();
696
+ const meta: Metadata = MetadataFactory.generate(
697
+ checker,
698
+ collection,
699
+ type,
700
+ {
701
+ resolve: true,
702
+ constant: true,
703
+ },
704
+ );
705
+ return [collection, meta];
706
+ };
707
+
708
+ const OBJECTOR = (
709
+ project: IProject,
710
+ importer: FunctionImporter,
711
+ ): FeatureProgrammer.IConfig.IObjector => ({
712
+ checker: IsProgrammer.decode(project, importer),
713
+ decoder: decode_object(),
714
+ joiner: StringifyJoiner.object(importer),
715
+ unionizer: decode_union_object(IsProgrammer.decode_object())(
716
+ decode_object(),
717
+ )((exp) => exp)((value, expected) =>
718
+ create_throw_error(importer, value, expected),
719
+ ),
720
+ failure: (input, expected) =>
721
+ create_throw_error(importer, input, expected),
722
+ is: (expr) => expr,
723
+ required: (expr) => expr,
724
+ });
725
+
726
+ function create_throw_error(
727
+ importer: FunctionImporter,
728
+ value: ts.Expression,
729
+ expected: string,
730
+ ) {
731
+ return ts.factory.createExpressionStatement(
732
+ ts.factory.createCallExpression(
733
+ importer.use("throws"),
734
+ [],
735
+ [
736
+ ts.factory.createObjectLiteralExpression(
737
+ [
738
+ ts.factory.createPropertyAssignment(
739
+ "expected",
740
+ ts.factory.createStringLiteral(expected),
741
+ ),
742
+ ts.factory.createPropertyAssignment("value", value),
743
+ ],
744
+ true,
745
+ ),
746
+ ],
747
+ ),
748
+ );
749
+ }
750
+ }
751
+
752
+ interface IUnion {
753
+ type: string;
754
+ is: () => ts.Expression;
755
+ value: () => ts.Expression;
756
+ }