typia 3.7.5-dev.20230413 → 3.7.6

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