typia 3.6.10 → 3.7.0-dev.20230331

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 (260) hide show
  1. package/lib/factories/MetadataTagFactory.js +140 -132
  2. package/lib/factories/MetadataTagFactory.js.map +1 -1
  3. package/lib/functional/$dictionary.d.ts +1 -0
  4. package/lib/functional/$dictionary.js +14 -0
  5. package/lib/functional/$dictionary.js.map +1 -0
  6. package/lib/functional/$is_custom.d.ts +2 -0
  7. package/lib/functional/$is_custom.js +12 -0
  8. package/lib/functional/$is_custom.js.map +1 -0
  9. package/lib/functional/Namespace.js +2 -0
  10. package/lib/functional/Namespace.js.map +1 -1
  11. package/lib/module.d.ts +25 -0
  12. package/lib/module.js +12 -1
  13. package/lib/module.js.map +1 -1
  14. package/lib/programmers/CheckerProgrammer.d.ts +2 -2
  15. package/lib/programmers/CheckerProgrammer.js +22 -22
  16. package/lib/programmers/CheckerProgrammer.js.map +1 -1
  17. package/lib/programmers/CloneProgrammer.js +2 -2
  18. package/lib/programmers/CloneProgrammer.js.map +1 -1
  19. package/lib/programmers/FeatureProgrammer.d.ts +3 -2
  20. package/lib/programmers/FeatureProgrammer.js +5 -5
  21. package/lib/programmers/FeatureProgrammer.js.map +1 -1
  22. package/lib/programmers/IsProgrammer.d.ts +1 -1
  23. package/lib/programmers/IsProgrammer.js +2 -2
  24. package/lib/programmers/IsProgrammer.js.map +1 -1
  25. package/lib/programmers/PruneProgrammer.js +2 -2
  26. package/lib/programmers/PruneProgrammer.js.map +1 -1
  27. package/lib/programmers/StringifyProgrammer.js +6 -6
  28. package/lib/programmers/StringifyProgrammer.js.map +1 -1
  29. package/lib/programmers/helpers/UnionExplorer.d.ts +7 -7
  30. package/lib/programmers/helpers/UnionExplorer.js +6 -6
  31. package/lib/programmers/helpers/UnionExplorer.js.map +1 -1
  32. package/lib/programmers/internal/check_array.js +36 -7
  33. package/lib/programmers/internal/check_array.js.map +1 -1
  34. package/lib/programmers/internal/check_bigint.d.ts +3 -1
  35. package/lib/programmers/internal/check_bigint.js +90 -61
  36. package/lib/programmers/internal/check_bigint.js.map +1 -1
  37. package/lib/programmers/internal/check_custom.d.ts +4 -0
  38. package/lib/programmers/internal/check_custom.js +30 -0
  39. package/lib/programmers/internal/check_custom.js.map +1 -0
  40. package/lib/programmers/internal/check_number.js +104 -75
  41. package/lib/programmers/internal/check_number.js.map +1 -1
  42. package/lib/programmers/internal/check_string.js +4 -3
  43. package/lib/programmers/internal/check_string.js.map +1 -1
  44. package/lib/programmers/internal/check_union_array_like.d.ts +2 -2
  45. package/lib/programmers/internal/check_union_array_like.js +4 -4
  46. package/lib/programmers/internal/check_union_array_like.js.map +1 -1
  47. package/lib/programmers/internal/check_union_tuple.js +2 -2
  48. package/lib/programmers/internal/check_union_tuple.js.map +1 -1
  49. package/lib/programmers/internal/feature_object_entries.js +1 -1
  50. package/lib/programmers/internal/feature_object_entries.js.map +1 -1
  51. package/lib/typings/Customizable.d.ts +7 -0
  52. package/lib/typings/Customizable.js +3 -0
  53. package/lib/typings/Customizable.js.map +1 -0
  54. package/package.json +1 -1
  55. package/src/IRandomGenerator.ts +17 -17
  56. package/src/IValidation.ts +21 -21
  57. package/src/Primitive.ts +104 -104
  58. package/src/TypeGuardError.ts +36 -36
  59. package/src/executable/TypiaGenerateWizard.ts +87 -87
  60. package/src/executable/TypiaSetupWizard.ts +152 -152
  61. package/src/executable/setup/ArgumentParser.ts +91 -91
  62. package/src/executable/setup/CommandExecutor.ts +8 -8
  63. package/src/executable/setup/FileRetriever.ts +33 -33
  64. package/src/executable/setup/PackageManager.ts +92 -92
  65. package/src/executable/setup/PluginConfigurator.ts +99 -99
  66. package/src/executable/typia.ts +38 -38
  67. package/src/factories/CommentFactory.ts +10 -10
  68. package/src/factories/ExpressionFactory.ts +77 -77
  69. package/src/factories/IdentifierFactory.ts +73 -73
  70. package/src/factories/LiteralFactory.ts +44 -44
  71. package/src/factories/MetadataCollection.ts +122 -122
  72. package/src/factories/MetadataFactory.ts +51 -51
  73. package/src/factories/MetadataTagFactory.ts +302 -276
  74. package/src/factories/StatementFactory.ts +60 -60
  75. package/src/factories/TemplateFactory.ts +56 -56
  76. package/src/factories/TypeFactory.ts +129 -129
  77. package/src/factories/TypiaFileFactory.ts +120 -120
  78. package/src/factories/ValueFactory.ts +12 -12
  79. package/src/factories/internal/metadata/MetadataHelper.ts +12 -12
  80. package/src/factories/internal/metadata/emplace_metadata_object.ts +142 -142
  81. package/src/factories/internal/metadata/explore_metadata.ts +92 -92
  82. package/src/factories/internal/metadata/iterate_metadata.ts +80 -80
  83. package/src/factories/internal/metadata/iterate_metadata_array.ts +29 -29
  84. package/src/factories/internal/metadata/iterate_metadata_atomic.ts +59 -59
  85. package/src/factories/internal/metadata/iterate_metadata_coalesce.ts +33 -33
  86. package/src/factories/internal/metadata/iterate_metadata_constant.ts +58 -58
  87. package/src/factories/internal/metadata/iterate_metadata_map.ts +41 -41
  88. package/src/factories/internal/metadata/iterate_metadata_native.ts +222 -222
  89. package/src/factories/internal/metadata/iterate_metadata_object.ts +48 -48
  90. package/src/factories/internal/metadata/iterate_metadata_resolve.ts +27 -27
  91. package/src/factories/internal/metadata/iterate_metadata_set.ts +33 -33
  92. package/src/factories/internal/metadata/iterate_metadata_template.ts +38 -38
  93. package/src/factories/internal/metadata/iterate_metadata_tuple.ts +45 -45
  94. package/src/factories/internal/metadata/iterate_metadata_union.ts +59 -59
  95. package/src/functional/$any.ts +3 -3
  96. package/src/functional/$dictionary.ts +17 -0
  97. package/src/functional/$every.ts +11 -11
  98. package/src/functional/$guard.ts +35 -35
  99. package/src/functional/$is_between.ts +7 -7
  100. package/src/functional/$is_custom.ts +14 -0
  101. package/src/functional/$is_date.ts +4 -4
  102. package/src/functional/$is_datetime.ts +3 -3
  103. package/src/functional/$is_email.ts +5 -5
  104. package/src/functional/$is_ipv4.ts +5 -5
  105. package/src/functional/$is_ipv6.ts +5 -5
  106. package/src/functional/$is_url.ts +5 -5
  107. package/src/functional/$is_uuid.ts +5 -5
  108. package/src/functional/$join.ts +50 -50
  109. package/src/functional/$number.ts +12 -12
  110. package/src/functional/$report.ts +15 -15
  111. package/src/functional/$rest.ts +3 -3
  112. package/src/functional/$string.ts +37 -37
  113. package/src/functional/$tail.ts +6 -6
  114. package/src/functional/Namespace.ts +127 -125
  115. package/src/index.ts +4 -4
  116. package/src/metadata/IJsDocTagInfo.ts +10 -10
  117. package/src/metadata/IMetadata.ts +25 -25
  118. package/src/metadata/IMetadataApplication.ts +7 -7
  119. package/src/metadata/IMetadataConstant.ts +16 -16
  120. package/src/metadata/IMetadataEntry.ts +6 -6
  121. package/src/metadata/IMetadataObject.ts +29 -29
  122. package/src/metadata/IMetadataProperty.ts +11 -11
  123. package/src/metadata/IMetadataTag.ts +105 -105
  124. package/src/metadata/Metadata.ts +534 -534
  125. package/src/metadata/MetadataConstant.ts +3 -3
  126. package/src/metadata/MetadataObject.ts +131 -131
  127. package/src/metadata/MetadataProperty.ts +64 -64
  128. package/src/module.ts +1986 -1946
  129. package/src/programmers/ApplicationProgrammer.ts +55 -55
  130. package/src/programmers/AssertCloneProgrammer.ts +70 -70
  131. package/src/programmers/AssertParseProgrammer.ts +65 -65
  132. package/src/programmers/AssertProgrammer.ts +232 -232
  133. package/src/programmers/AssertPruneProgrammer.ts +67 -67
  134. package/src/programmers/AssertStringifyProgrammer.ts +71 -71
  135. package/src/programmers/CheckerProgrammer.ts +923 -893
  136. package/src/programmers/CloneProgrammer.ts +388 -386
  137. package/src/programmers/FeatureProgrammer.ts +512 -505
  138. package/src/programmers/IsCloneProgrammer.ts +80 -80
  139. package/src/programmers/IsParseProgrammer.ts +74 -74
  140. package/src/programmers/IsProgrammer.ts +201 -200
  141. package/src/programmers/IsPruneProgrammer.ts +75 -75
  142. package/src/programmers/IsStringifyProgrammer.ts +81 -81
  143. package/src/programmers/PruneProgrammer.ts +343 -341
  144. package/src/programmers/RandomProgrammer.ts +388 -388
  145. package/src/programmers/StringifyProgrammer.ts +801 -795
  146. package/src/programmers/ValidateCloneProgrammer.ts +90 -90
  147. package/src/programmers/ValidateParseProgrammer.ts +69 -69
  148. package/src/programmers/ValidateProgrammer.ts +266 -266
  149. package/src/programmers/ValidatePruneProgrammer.ts +83 -83
  150. package/src/programmers/ValidateStringifyProgrammer.ts +89 -89
  151. package/src/programmers/helpers/AtomicPredicator.ts +31 -31
  152. package/src/programmers/helpers/CloneJoiner.ts +134 -134
  153. package/src/programmers/helpers/FunctionImporeter.ts +55 -55
  154. package/src/programmers/helpers/IExpressionEntry.ts +12 -12
  155. package/src/programmers/helpers/OptionPredicator.ts +19 -19
  156. package/src/programmers/helpers/PruneJoiner.ts +52 -52
  157. package/src/programmers/helpers/RandomJoiner.ts +149 -149
  158. package/src/programmers/helpers/RandomRanger.ts +216 -216
  159. package/src/programmers/helpers/StringifyJoinder.ts +114 -114
  160. package/src/programmers/helpers/StringifyPredicator.ts +18 -18
  161. package/src/programmers/helpers/UnionExplorer.ts +281 -274
  162. package/src/programmers/helpers/UnionPredicator.ts +81 -81
  163. package/src/programmers/internal/application_array.ts +37 -37
  164. package/src/programmers/internal/application_boolean.ts +17 -17
  165. package/src/programmers/internal/application_constant.ts +29 -29
  166. package/src/programmers/internal/application_default.ts +17 -17
  167. package/src/programmers/internal/application_default_string.ts +32 -32
  168. package/src/programmers/internal/application_native.ts +29 -29
  169. package/src/programmers/internal/application_number.ts +73 -73
  170. package/src/programmers/internal/application_object.ts +153 -153
  171. package/src/programmers/internal/application_schema.ts +184 -184
  172. package/src/programmers/internal/application_string.ts +45 -45
  173. package/src/programmers/internal/application_templates.ts +27 -27
  174. package/src/programmers/internal/application_tuple.ts +29 -29
  175. package/src/programmers/internal/check_array.ts +31 -22
  176. package/src/programmers/internal/check_array_length.ts +44 -44
  177. package/src/programmers/internal/check_bigint.ts +84 -64
  178. package/src/programmers/internal/check_custom.ts +32 -0
  179. package/src/programmers/internal/check_dynamic_properties.ts +197 -197
  180. package/src/programmers/internal/check_everything.ts +28 -28
  181. package/src/programmers/internal/check_native.ts +21 -21
  182. package/src/programmers/internal/check_number.ts +155 -145
  183. package/src/programmers/internal/check_object.ts +48 -48
  184. package/src/programmers/internal/check_string.ts +30 -24
  185. package/src/programmers/internal/check_string_tags.ts +63 -63
  186. package/src/programmers/internal/check_template.ts +50 -50
  187. package/src/programmers/internal/check_union_array_like.ts +265 -260
  188. package/src/programmers/internal/check_union_tuple.ts +35 -33
  189. package/src/programmers/internal/decode_union_object.ts +73 -73
  190. package/src/programmers/internal/feature_object_entries.ts +60 -59
  191. package/src/programmers/internal/metadata_to_pattern.ts +31 -31
  192. package/src/programmers/internal/prune_object_properties.ts +60 -60
  193. package/src/programmers/internal/stringify_dynamic_properties.ts +165 -165
  194. package/src/programmers/internal/stringify_native.ts +8 -8
  195. package/src/programmers/internal/stringify_regular_properties.ts +81 -81
  196. package/src/programmers/internal/template_to_pattern.ts +15 -15
  197. package/src/schemas/IJsonApplication.ts +9 -9
  198. package/src/schemas/IJsonComponents.ts +26 -26
  199. package/src/schemas/IJsonSchema.ts +121 -121
  200. package/src/transform.ts +21 -21
  201. package/src/transformers/CallExpressionTransformer.ts +172 -172
  202. package/src/transformers/ExpressionWithArgumentTransformer.ts +66 -66
  203. package/src/transformers/FileTransformer.ts +49 -49
  204. package/src/transformers/IProject.ts +11 -11
  205. package/src/transformers/ITransformOptions.ts +62 -62
  206. package/src/transformers/ImportTransformer.ts +60 -60
  207. package/src/transformers/NodeTransformer.ts +19 -19
  208. package/src/transformers/features/miscellaneous/ApplicationTransformer.ts +120 -120
  209. package/src/transformers/features/miscellaneous/AssertCloneTransformer.ts +9 -9
  210. package/src/transformers/features/miscellaneous/AssertPruneTransformer.ts +9 -9
  211. package/src/transformers/features/miscellaneous/CloneTransformer.ts +9 -9
  212. package/src/transformers/features/miscellaneous/CreateAssertCloneTransformer.ts +9 -9
  213. package/src/transformers/features/miscellaneous/CreateAssertPruneTransformer.ts +9 -9
  214. package/src/transformers/features/miscellaneous/CreateCloneTransformer.ts +9 -9
  215. package/src/transformers/features/miscellaneous/CreateIsCloneTransformer.ts +9 -9
  216. package/src/transformers/features/miscellaneous/CreateIsPruneTransformer.ts +9 -9
  217. package/src/transformers/features/miscellaneous/CreatePruneTransformer.ts +9 -9
  218. package/src/transformers/features/miscellaneous/CreateRandomGenerator.ts +42 -42
  219. package/src/transformers/features/miscellaneous/CreateValidateCloneTransformer.ts +9 -9
  220. package/src/transformers/features/miscellaneous/CreateValidatePruneTransformer.ts +9 -9
  221. package/src/transformers/features/miscellaneous/IsCloneTransformer.ts +9 -9
  222. package/src/transformers/features/miscellaneous/IsPruneTransformer.ts +9 -9
  223. package/src/transformers/features/miscellaneous/MetadataTransformer.ts +55 -55
  224. package/src/transformers/features/miscellaneous/PruneTransformer.ts +9 -9
  225. package/src/transformers/features/miscellaneous/RandomTransformer.ts +48 -48
  226. package/src/transformers/features/miscellaneous/ValidateCloneTransformer.ts +9 -9
  227. package/src/transformers/features/miscellaneous/ValidatePruneTransformer.ts +9 -9
  228. package/src/transformers/features/parsers/AssertParseTransformer.ts +9 -9
  229. package/src/transformers/features/parsers/CreateAssertParseTransformer.ts +9 -9
  230. package/src/transformers/features/parsers/CreateIsParseTransformer.ts +9 -9
  231. package/src/transformers/features/parsers/CreateValidateParseTransformer.ts +9 -9
  232. package/src/transformers/features/parsers/IsParseTransformer.ts +9 -9
  233. package/src/transformers/features/parsers/ValidateParseTransformer.ts +9 -9
  234. package/src/transformers/features/stringifiers/AssertStringifyTransformer.ts +10 -10
  235. package/src/transformers/features/stringifiers/CreateAssertStringifyTransformer.ts +9 -9
  236. package/src/transformers/features/stringifiers/CreateIsStringifyTransformer.ts +9 -9
  237. package/src/transformers/features/stringifiers/CreateStringifyTransformer.ts +9 -9
  238. package/src/transformers/features/stringifiers/CreateValidateStringifyProgrammer.ts +11 -11
  239. package/src/transformers/features/stringifiers/IsStringifyTransformer.ts +9 -9
  240. package/src/transformers/features/stringifiers/StringifyTransformer.ts +9 -9
  241. package/src/transformers/features/stringifiers/ValidateStringifyTransformer.ts +10 -10
  242. package/src/transformers/features/validators/AssertTransformer.ts +11 -11
  243. package/src/transformers/features/validators/CreateAssertTransformer.ts +12 -12
  244. package/src/transformers/features/validators/CreateIsTransformer.ts +10 -10
  245. package/src/transformers/features/validators/CreateValidateTransformer.ts +12 -12
  246. package/src/transformers/features/validators/IsTransformer.ts +10 -10
  247. package/src/transformers/features/validators/ValidateTransformer.ts +11 -11
  248. package/src/transformers/internal/GenericTransformer.ts +99 -99
  249. package/src/typings/Atomic.ts +17 -17
  250. package/src/typings/ClassProperties.ts +5 -5
  251. package/src/typings/Customizable.ts +7 -0
  252. package/src/typings/OmitNever.ts +3 -3
  253. package/src/typings/SpecialFields.ts +3 -3
  254. package/src/typings/Writable.ts +11 -11
  255. package/src/utils/ArrayUtil.ts +49 -49
  256. package/src/utils/Escaper.ts +50 -50
  257. package/src/utils/MapUtil.ts +14 -14
  258. package/src/utils/PatternUtil.ts +30 -30
  259. package/src/utils/RandomGenerator.ts +96 -96
  260. package/src/utils/Singleton.ts +17 -17
@@ -1,795 +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
- 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
+ ),
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.";