typia 3.8.2 → 3.8.3

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