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