typia 5.0.4 → 5.0.5-dev.20230921

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 (291) hide show
  1. package/README.md +1 -1
  2. package/package.json +1 -1
  3. package/src/IRandomGenerator.ts +35 -35
  4. package/src/IValidation.ts +21 -21
  5. package/src/Primitive.ts +135 -135
  6. package/src/Resolved.ts +116 -116
  7. package/src/TypeGuardError.ts +36 -36
  8. package/src/executable/TypiaGenerateWizard.ts +85 -85
  9. package/src/executable/TypiaSetupWizard.ts +153 -153
  10. package/src/executable/setup/ArgumentParser.ts +45 -45
  11. package/src/executable/setup/CommandExecutor.ts +8 -8
  12. package/src/executable/setup/FileRetriever.ts +22 -22
  13. package/src/executable/setup/PackageManager.ts +71 -71
  14. package/src/executable/setup/PluginConfigurator.ts +70 -70
  15. package/src/executable/typia.ts +52 -52
  16. package/src/factories/CommentFactory.ts +84 -84
  17. package/src/factories/ExpressionFactory.ts +159 -159
  18. package/src/factories/IdentifierFactory.ts +74 -74
  19. package/src/factories/JsonMetadataFactory.ts +43 -43
  20. package/src/factories/LiteralFactory.ts +47 -47
  21. package/src/factories/MetadataCollection.ts +269 -269
  22. package/src/factories/MetadataCommentTagFactory.ts +629 -629
  23. package/src/factories/MetadataFactory.ts +214 -214
  24. package/src/factories/MetadataTypeTagFactory.ts +313 -313
  25. package/src/factories/NumericRangeFactory.ts +33 -33
  26. package/src/factories/ProtobufFactory.ts +272 -272
  27. package/src/factories/StatementFactory.ts +72 -72
  28. package/src/factories/TemplateFactory.ts +58 -58
  29. package/src/factories/TypeFactory.ts +119 -119
  30. package/src/factories/ValueFactory.ts +12 -12
  31. package/src/factories/internal/metadata/MetadataHelper.ts +12 -12
  32. package/src/factories/internal/metadata/emend_metadata_atomics.ts +40 -40
  33. package/src/factories/internal/metadata/emplace_metadata_alias.ts +41 -41
  34. package/src/factories/internal/metadata/emplace_metadata_array_type.ts +41 -41
  35. package/src/factories/internal/metadata/emplace_metadata_object.ts +150 -150
  36. package/src/factories/internal/metadata/emplace_metadata_tuple.ts +60 -60
  37. package/src/factories/internal/metadata/explore_metadata.ts +32 -32
  38. package/src/factories/internal/metadata/iterate_metadata.ts +101 -101
  39. package/src/factories/internal/metadata/iterate_metadata_alias.ts +35 -35
  40. package/src/factories/internal/metadata/iterate_metadata_array.ts +37 -37
  41. package/src/factories/internal/metadata/iterate_metadata_atomic.ts +62 -62
  42. package/src/factories/internal/metadata/iterate_metadata_coalesce.ts +33 -33
  43. package/src/factories/internal/metadata/iterate_metadata_collection.ts +141 -141
  44. package/src/factories/internal/metadata/iterate_metadata_comment_tags.ts +26 -26
  45. package/src/factories/internal/metadata/iterate_metadata_constant.ts +58 -58
  46. package/src/factories/internal/metadata/iterate_metadata_intersection.ts +197 -197
  47. package/src/factories/internal/metadata/iterate_metadata_map.ts +57 -57
  48. package/src/factories/internal/metadata/iterate_metadata_native.ts +210 -210
  49. package/src/factories/internal/metadata/iterate_metadata_object.ts +44 -44
  50. package/src/factories/internal/metadata/iterate_metadata_resolve.ts +52 -52
  51. package/src/factories/internal/metadata/iterate_metadata_set.ts +42 -42
  52. package/src/factories/internal/metadata/iterate_metadata_sort.ts +69 -69
  53. package/src/factories/internal/metadata/iterate_metadata_template.ts +47 -47
  54. package/src/factories/internal/metadata/iterate_metadata_tuple.ts +37 -37
  55. package/src/factories/internal/metadata/iterate_metadata_union.ts +27 -27
  56. package/src/functional/$ProtobufReader.ts +201 -201
  57. package/src/functional/$ProtobufSizer.ts +147 -147
  58. package/src/functional/$ProtobufWriter.ts +151 -151
  59. package/src/functional/$any.ts +4 -4
  60. package/src/functional/$clone.ts +4 -4
  61. package/src/functional/$dictionary.ts +25 -25
  62. package/src/functional/$every.ts +11 -11
  63. package/src/functional/$guard.ts +35 -35
  64. package/src/functional/$is_between.ts +2 -2
  65. package/src/functional/$join.ts +46 -46
  66. package/src/functional/$number.ts +13 -13
  67. package/src/functional/$report.ts +15 -15
  68. package/src/functional/$rest.ts +3 -3
  69. package/src/functional/$string.ts +50 -50
  70. package/src/functional/$strlen.ts +7 -7
  71. package/src/functional/$tail.ts +5 -5
  72. package/src/functional/$varint.ts +130 -130
  73. package/src/functional/$zigzag.ts +39 -39
  74. package/src/functional/IProtobufWriter.ts +18 -18
  75. package/src/functional/Namespace.ts +133 -133
  76. package/src/index.ts +4 -4
  77. package/src/json.ts +648 -648
  78. package/src/misc.ts +651 -651
  79. package/src/module.ts +656 -656
  80. package/src/programmers/AssertProgrammer.ts +317 -317
  81. package/src/programmers/CheckerProgrammer.ts +1137 -1137
  82. package/src/programmers/FeatureProgrammer.ts +478 -478
  83. package/src/programmers/IsProgrammer.ts +252 -252
  84. package/src/programmers/RandomProgrammer.ts +878 -878
  85. package/src/programmers/TypiaProgrammer.ts +163 -163
  86. package/src/programmers/ValidateProgrammer.ts +346 -346
  87. package/src/programmers/helpers/AtomicPredicator.ts +31 -31
  88. package/src/programmers/helpers/CloneJoiner.ts +144 -144
  89. package/src/programmers/helpers/FunctionImporeter.ts +91 -91
  90. package/src/programmers/helpers/ICheckEntry.ts +13 -13
  91. package/src/programmers/helpers/IExpressionEntry.ts +12 -12
  92. package/src/programmers/helpers/OptionPredicator.ts +15 -15
  93. package/src/programmers/helpers/ProtobufUtil.ts +125 -125
  94. package/src/programmers/helpers/ProtobufWire.ts +34 -34
  95. package/src/programmers/helpers/PruneJoiner.ts +143 -143
  96. package/src/programmers/helpers/RandomJoiner.ts +151 -151
  97. package/src/programmers/helpers/RandomRanger.ts +173 -173
  98. package/src/programmers/helpers/StringifyJoinder.ts +113 -113
  99. package/src/programmers/helpers/StringifyPredicator.ts +12 -12
  100. package/src/programmers/helpers/UnionExplorer.ts +305 -305
  101. package/src/programmers/helpers/UnionPredicator.ts +81 -81
  102. package/src/programmers/helpers/disable_function_importer_declare.ts +32 -32
  103. package/src/programmers/internal/JSON_SCHEMA_PREFIX.ts +1 -1
  104. package/src/programmers/internal/application_alias.ts +65 -65
  105. package/src/programmers/internal/application_array.ts +53 -53
  106. package/src/programmers/internal/application_boolean.ts +15 -15
  107. package/src/programmers/internal/application_constant.ts +26 -26
  108. package/src/programmers/internal/application_default.ts +17 -17
  109. package/src/programmers/internal/application_default_string.ts +37 -37
  110. package/src/programmers/internal/application_escaped.ts +55 -55
  111. package/src/programmers/internal/application_native.ts +39 -39
  112. package/src/programmers/internal/application_number.ts +88 -88
  113. package/src/programmers/internal/application_object.ts +162 -162
  114. package/src/programmers/internal/application_schema.ts +175 -175
  115. package/src/programmers/internal/application_string.ts +51 -51
  116. package/src/programmers/internal/application_templates.ts +25 -25
  117. package/src/programmers/internal/application_tuple.ts +58 -58
  118. package/src/programmers/internal/check_array_length.ts +41 -41
  119. package/src/programmers/internal/check_bigint.ts +45 -45
  120. package/src/programmers/internal/check_dynamic_properties.ts +194 -194
  121. package/src/programmers/internal/check_everything.ts +28 -28
  122. package/src/programmers/internal/check_native.ts +21 -21
  123. package/src/programmers/internal/check_number.ts +105 -105
  124. package/src/programmers/internal/check_object.ts +55 -55
  125. package/src/programmers/internal/check_string.ts +45 -45
  126. package/src/programmers/internal/check_template.ts +61 -61
  127. package/src/programmers/internal/check_union_array_like.ts +323 -323
  128. package/src/programmers/internal/decode_union_object.ts +84 -84
  129. package/src/programmers/internal/feature_object_entries.ts +58 -58
  130. package/src/programmers/internal/metadata_to_pattern.ts +34 -34
  131. package/src/programmers/internal/prune_object_properties.ts +60 -60
  132. package/src/programmers/internal/random_custom.ts +37 -37
  133. package/src/programmers/internal/stringify_dynamic_properties.ts +171 -171
  134. package/src/programmers/internal/stringify_native.ts +7 -7
  135. package/src/programmers/internal/stringify_regular_properties.ts +83 -83
  136. package/src/programmers/internal/template_to_pattern.ts +15 -15
  137. package/src/programmers/internal/wrap_metadata_rest_tuple.ts +20 -20
  138. package/src/programmers/json/JsonApplicationProgrammer.ts +50 -50
  139. package/src/programmers/json/JsonAssertParseProgrammer.ts +71 -71
  140. package/src/programmers/json/JsonAssertStringifyProgrammer.ts +66 -66
  141. package/src/programmers/json/JsonIsParseProgrammer.ts +77 -77
  142. package/src/programmers/json/JsonIsStringifyProgrammer.ts +76 -76
  143. package/src/programmers/json/JsonStringifyProgrammer.ts +964 -964
  144. package/src/programmers/json/JsonValidateParseProgrammer.ts +68 -68
  145. package/src/programmers/json/JsonValidateStringifyProgrammer.ts +84 -84
  146. package/src/programmers/misc/MiscAssertCloneProgrammer.ts +71 -71
  147. package/src/programmers/misc/MiscAssertPruneProgrammer.ts +68 -68
  148. package/src/programmers/misc/MiscCloneProgrammer.ts +774 -774
  149. package/src/programmers/misc/MiscIsCloneProgrammer.ts +78 -78
  150. package/src/programmers/misc/MiscIsPruneProgrammer.ts +73 -73
  151. package/src/programmers/misc/MiscLiteralsProgrammer.ts +69 -69
  152. package/src/programmers/misc/MiscPruneProgrammer.ts +550 -550
  153. package/src/programmers/misc/MiscValidateCloneProgrammer.ts +85 -85
  154. package/src/programmers/misc/MiscValidatePruneProgrammer.ts +78 -78
  155. package/src/programmers/protobuf/ProtobufAssertDecodeProgrammer.ts +75 -75
  156. package/src/programmers/protobuf/ProtobufAssertEncodeProgrammer.ts +66 -66
  157. package/src/programmers/protobuf/ProtobufDecodeProgrammer.ts +655 -655
  158. package/src/programmers/protobuf/ProtobufEncodeProgrammer.ts +883 -883
  159. package/src/programmers/protobuf/ProtobufIsDecodeProgrammer.ts +85 -85
  160. package/src/programmers/protobuf/ProtobufIsEncodeProgrammer.ts +76 -76
  161. package/src/programmers/protobuf/ProtobufMessageProgrammer.ts +165 -165
  162. package/src/programmers/protobuf/ProtobufValidateDecodeProgrammer.ts +75 -75
  163. package/src/programmers/protobuf/ProtobufValidateEncodeProgrammer.ts +86 -86
  164. package/src/protobuf.ts +881 -881
  165. package/src/schemas/json/IJsonApplication.ts +8 -8
  166. package/src/schemas/json/IJsonComponents.ts +33 -33
  167. package/src/schemas/json/IJsonSchema.ts +110 -110
  168. package/src/schemas/metadata/IJsDocTagInfo.ts +10 -10
  169. package/src/schemas/metadata/IMetadata.ts +34 -34
  170. package/src/schemas/metadata/IMetadataAlias.ts +12 -12
  171. package/src/schemas/metadata/IMetadataApplication.ts +7 -7
  172. package/src/schemas/metadata/IMetadataArray.ts +7 -7
  173. package/src/schemas/metadata/IMetadataArrayType.ts +10 -10
  174. package/src/schemas/metadata/IMetadataAtomic.ts +6 -6
  175. package/src/schemas/metadata/IMetadataCollection.ts +11 -11
  176. package/src/schemas/metadata/IMetadataConstant.ts +16 -16
  177. package/src/schemas/metadata/IMetadataDictionary.ts +14 -14
  178. package/src/schemas/metadata/IMetadataEntry.ts +6 -6
  179. package/src/schemas/metadata/IMetadataEscaped.ts +6 -6
  180. package/src/schemas/metadata/IMetadataObject.ts +18 -18
  181. package/src/schemas/metadata/IMetadataProperty.ts +9 -9
  182. package/src/schemas/metadata/IMetadataTuple.ts +7 -7
  183. package/src/schemas/metadata/IMetadataTupleType.ts +10 -10
  184. package/src/schemas/metadata/IMetadataTypeTag.ts +8 -8
  185. package/src/schemas/metadata/Metadata.ts +685 -685
  186. package/src/schemas/metadata/MetadataAlias.ts +61 -61
  187. package/src/schemas/metadata/MetadataArray.ts +49 -49
  188. package/src/schemas/metadata/MetadataArrayType.ts +57 -57
  189. package/src/schemas/metadata/MetadataAtomic.ts +42 -42
  190. package/src/schemas/metadata/MetadataConstant.ts +3 -3
  191. package/src/schemas/metadata/MetadataEscaped.ts +51 -51
  192. package/src/schemas/metadata/MetadataObject.ts +139 -139
  193. package/src/schemas/metadata/MetadataProperty.ts +59 -59
  194. package/src/schemas/metadata/MetadataTuple.ts +32 -32
  195. package/src/schemas/metadata/MetadataTupleType.ts +67 -67
  196. package/src/tags/ExclusiveMaximum.ts +13 -13
  197. package/src/tags/ExclusiveMinimum.ts +13 -13
  198. package/src/tags/Format.ts +30 -30
  199. package/src/tags/MaxItems.ts +9 -9
  200. package/src/tags/MaxLength.ts +9 -9
  201. package/src/tags/Maximum.ts +13 -13
  202. package/src/tags/MinItems.ts +9 -9
  203. package/src/tags/MinLength.ts +9 -9
  204. package/src/tags/Minimum.ts +13 -13
  205. package/src/tags/MultipleOf.ts +15 -15
  206. package/src/tags/Pattern.ts +8 -8
  207. package/src/tags/TagBase.ts +68 -68
  208. package/src/tags/Type.ts +27 -27
  209. package/src/tags/index.ts +13 -13
  210. package/src/transform.ts +35 -35
  211. package/src/transformers/CallExpressionTransformer.ts +243 -243
  212. package/src/transformers/FileTransformer.ts +57 -57
  213. package/src/transformers/IProject.ts +15 -15
  214. package/src/transformers/ITransformOptions.ts +62 -62
  215. package/src/transformers/ImportTransformer.ts +66 -66
  216. package/src/transformers/NodeTransformer.ts +13 -13
  217. package/src/transformers/TransformerError.ts +55 -55
  218. package/src/transformers/features/AssertTransformer.ts +11 -11
  219. package/src/transformers/features/CreateAssertTransformer.ts +13 -13
  220. package/src/transformers/features/CreateIsTransformer.ts +11 -11
  221. package/src/transformers/features/CreateRandomTransformer.ts +43 -43
  222. package/src/transformers/features/CreateValidateTransformer.ts +13 -13
  223. package/src/transformers/features/IsTransformer.ts +11 -11
  224. package/src/transformers/features/RandomTransformer.ts +46 -46
  225. package/src/transformers/features/ValidateTransformer.ts +11 -11
  226. package/src/transformers/features/json/JsonApplicationTransformer.ts +118 -118
  227. package/src/transformers/features/json/JsonAssertParseTransformer.ts +10 -10
  228. package/src/transformers/features/json/JsonAssertStringifyTransformer.ts +10 -10
  229. package/src/transformers/features/json/JsonCreateAssertParseTransformer.ts +10 -10
  230. package/src/transformers/features/json/JsonCreateAssertStringifyTransformer.ts +12 -12
  231. package/src/transformers/features/json/JsonCreateIsParseTransformer.ts +9 -9
  232. package/src/transformers/features/json/JsonCreateIsStringifyTransformer.ts +10 -10
  233. package/src/transformers/features/json/JsonCreateStringifyTransformer.ts +9 -9
  234. package/src/transformers/features/json/JsonCreateValidateParseTransformer.ts +10 -10
  235. package/src/transformers/features/json/JsonCreateValidateStringifyProgrammer.ts +12 -12
  236. package/src/transformers/features/json/JsonIsParseTransformer.ts +9 -9
  237. package/src/transformers/features/json/JsonIsStringifyTransformer.ts +10 -10
  238. package/src/transformers/features/json/JsonStringifyTransformer.ts +9 -9
  239. package/src/transformers/features/json/JsonValidateParseTransformer.ts +10 -10
  240. package/src/transformers/features/json/JsonValidateStringifyTransformer.ts +10 -10
  241. package/src/transformers/features/misc/MetadataTransformer.ts +61 -61
  242. package/src/transformers/features/misc/MiscAssertCloneTransformer.ts +10 -10
  243. package/src/transformers/features/misc/MiscAssertPruneTransformer.ts +10 -10
  244. package/src/transformers/features/misc/MiscCloneTransformer.ts +9 -9
  245. package/src/transformers/features/misc/MiscCreateAssertCloneTransformer.ts +10 -10
  246. package/src/transformers/features/misc/MiscCreateAssertPruneTransformer.ts +10 -10
  247. package/src/transformers/features/misc/MiscCreateCloneTransformer.ts +9 -9
  248. package/src/transformers/features/misc/MiscCreateIsCloneTransformer.ts +9 -9
  249. package/src/transformers/features/misc/MiscCreateIsPruneTransformer.ts +9 -9
  250. package/src/transformers/features/misc/MiscCreatePruneTransformer.ts +9 -9
  251. package/src/transformers/features/misc/MiscCreateValidateCloneTransformer.ts +10 -10
  252. package/src/transformers/features/misc/MiscCreateValidatePruneTransformer.ts +10 -10
  253. package/src/transformers/features/misc/MiscIsCloneTransformer.ts +9 -9
  254. package/src/transformers/features/misc/MiscIsPruneTransformer.ts +9 -9
  255. package/src/transformers/features/misc/MiscLiteralsTransformer.ts +32 -32
  256. package/src/transformers/features/misc/MiscPruneTransformer.ts +9 -9
  257. package/src/transformers/features/misc/MiscValidateCloneTransformer.ts +10 -10
  258. package/src/transformers/features/misc/MiscValidatePruneTransformer.ts +10 -10
  259. package/src/transformers/features/protobuf/CreateProtobufAssertDecodeTransformer.ts +12 -12
  260. package/src/transformers/features/protobuf/CreateProtobufAssertEncodeTransformer.ts +12 -12
  261. package/src/transformers/features/protobuf/CreateProtobufDecodeTransformer.ts +9 -9
  262. package/src/transformers/features/protobuf/CreateProtobufEncodeTransformer.ts +9 -9
  263. package/src/transformers/features/protobuf/CreateProtobufIsDecodeTransformer.ts +12 -12
  264. package/src/transformers/features/protobuf/CreateProtobufIsEncodeTransformer.ts +12 -12
  265. package/src/transformers/features/protobuf/CreateProtobufValidateDecodeTransformer.ts +12 -12
  266. package/src/transformers/features/protobuf/CreateProtobufValidateEncodeTransformer.ts +12 -12
  267. package/src/transformers/features/protobuf/ProtobufAssertDecodeTransformer.ts +10 -10
  268. package/src/transformers/features/protobuf/ProtobufAssertEncodeTransformer.ts +10 -10
  269. package/src/transformers/features/protobuf/ProtobufDecodeTransformer.ts +10 -10
  270. package/src/transformers/features/protobuf/ProtobufEncodeTransformer.ts +10 -10
  271. package/src/transformers/features/protobuf/ProtobufIsDecodeTransformer.ts +10 -10
  272. package/src/transformers/features/protobuf/ProtobufIsEncodeTransformer.ts +10 -10
  273. package/src/transformers/features/protobuf/ProtobufMessageTransformer.ts +33 -33
  274. package/src/transformers/features/protobuf/ProtobufValidateDecodeTransformer.ts +12 -12
  275. package/src/transformers/features/protobuf/ProtobufValidateEncodeTransformer.ts +12 -12
  276. package/src/transformers/internal/GenericTransformer.ts +104 -104
  277. package/src/typings/Atomic.ts +18 -18
  278. package/src/typings/ClassProperties.ts +5 -5
  279. package/src/typings/Customizable.ts +5 -5
  280. package/src/typings/OmitNever.ts +3 -3
  281. package/src/typings/ProtobufAtomic.ts +19 -19
  282. package/src/typings/SpecialFields.ts +3 -3
  283. package/src/typings/ValidationPipe.ts +9 -9
  284. package/src/typings/Writable.ts +11 -11
  285. package/src/utils/ArrayUtil.ts +45 -45
  286. package/src/utils/Escaper.ts +46 -46
  287. package/src/utils/MapUtil.ts +12 -12
  288. package/src/utils/NameEncoder.ts +32 -32
  289. package/src/utils/PatternUtil.ts +33 -33
  290. package/src/utils/RandomGenerator.ts +83 -83
  291. package/src/utils/Singleton.ts +17 -17
@@ -1,883 +1,883 @@
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 { NumericRangeFactory } from "../../factories/NumericRangeFactory";
7
- import { ProtobufFactory } from "../../factories/ProtobufFactory";
8
- import { StatementFactory } from "../../factories/StatementFactory";
9
- import { TypeFactory } from "../../factories/TypeFactory";
10
-
11
- import { Metadata } from "../../schemas/metadata/Metadata";
12
- import { MetadataArray } from "../../schemas/metadata/MetadataArray";
13
- import { MetadataAtomic } from "../../schemas/metadata/MetadataAtomic";
14
- import { MetadataObject } from "../../schemas/metadata/MetadataObject";
15
- import { MetadataProperty } from "../../schemas/metadata/MetadataProperty";
16
-
17
- import { IProject } from "../../transformers/IProject";
18
-
19
- import { ProtobufAtomic } from "../../typings/ProtobufAtomic";
20
-
21
- import { FeatureProgrammer } from "../FeatureProgrammer";
22
- import { IsProgrammer } from "../IsProgrammer";
23
- import { FunctionImporter } from "../helpers/FunctionImporeter";
24
- import { ProtobufUtil } from "../helpers/ProtobufUtil";
25
- import { ProtobufWire } from "../helpers/ProtobufWire";
26
- import { UnionPredicator } from "../helpers/UnionPredicator";
27
- import { decode_union_object } from "../internal/decode_union_object";
28
-
29
- export namespace ProtobufEncodeProgrammer {
30
- export const write =
31
- (project: IProject) =>
32
- (modulo: ts.LeftHandSideExpression) =>
33
- (type: ts.Type, name?: string): ts.ArrowFunction => {
34
- const importer = new FunctionImporter(modulo.getText());
35
- const collection = new MetadataCollection();
36
- const meta: Metadata = ProtobufFactory.metadata(modulo.getText())(
37
- project.checker,
38
- )(collection)(type);
39
-
40
- const callEncoder =
41
- (writer: string) => (factory: ts.NewExpression) =>
42
- StatementFactory.constant(
43
- writer,
44
- ts.factory.createCallExpression(
45
- ts.factory.createIdentifier("encoder"),
46
- undefined,
47
- [factory],
48
- ),
49
- );
50
-
51
- const block: ts.Statement[] = [
52
- StatementFactory.constant(
53
- "encoder",
54
- write_encoder(project)(importer)(collection)(meta),
55
- ),
56
- callEncoder("sizer")(
57
- ts.factory.createNewExpression(
58
- importer.use("Sizer"),
59
- undefined,
60
- [],
61
- ),
62
- ),
63
- callEncoder("writer")(
64
- ts.factory.createNewExpression(
65
- importer.use("Writer"),
66
- undefined,
67
- [ts.factory.createIdentifier("sizer")],
68
- ),
69
- ),
70
- ts.factory.createReturnStatement(
71
- ts.factory.createCallExpression(
72
- IdentifierFactory.access(WRITER())("buffer"),
73
- undefined,
74
- undefined,
75
- ),
76
- ),
77
- ];
78
-
79
- return ts.factory.createArrowFunction(
80
- undefined,
81
- undefined,
82
- [
83
- IdentifierFactory.parameter(
84
- "input",
85
- ts.factory.createTypeReferenceNode(
86
- name ??
87
- TypeFactory.getFullName(project.checker)(type),
88
- ),
89
- ),
90
- ],
91
- ts.factory.createTypeReferenceNode("Uint8Array"),
92
- undefined,
93
- ts.factory.createBlock(
94
- [...importer.declare(modulo, false), ...block],
95
- true,
96
- ),
97
- );
98
- };
99
-
100
- const write_encoder =
101
- (project: IProject) =>
102
- (importer: FunctionImporter) =>
103
- (collection: MetadataCollection) =>
104
- (meta: Metadata): ts.ArrowFunction => {
105
- const functors = collection
106
- .objects()
107
- .filter((obj) => ProtobufUtil.isStaticObject(obj))
108
- .map((obj) =>
109
- StatementFactory.constant(
110
- `${PREFIX}o${obj.index}`,
111
- write_object_function(project)(importer)(
112
- ts.factory.createIdentifier("input"),
113
- obj,
114
- {
115
- source: "function",
116
- from: "object",
117
- tracable: false,
118
- postfix: "",
119
- },
120
- ),
121
- ),
122
- );
123
- const main = decode(project)(importer)(null)(
124
- ts.factory.createIdentifier("input"),
125
- meta,
126
- {
127
- source: "top",
128
- from: "top",
129
- tracable: false,
130
- postfix: "",
131
- },
132
- );
133
- return ts.factory.createArrowFunction(
134
- undefined,
135
- undefined,
136
- [IdentifierFactory.parameter("writer")],
137
- TypeFactory.keyword("any"),
138
- undefined,
139
- ts.factory.createBlock(
140
- [
141
- ...importer.declareUnions(),
142
- ...functors,
143
- ...IsProgrammer.write_function_statements(project)(
144
- importer,
145
- )(collection),
146
- ...main.statements,
147
- ts.factory.createReturnStatement(
148
- ts.factory.createIdentifier("writer"),
149
- ),
150
- ],
151
- true,
152
- ),
153
- );
154
- };
155
-
156
- const write_object_function =
157
- (project: IProject) =>
158
- (importer: FunctionImporter) =>
159
- (
160
- input: ts.Expression,
161
- obj: MetadataObject,
162
- explore: FeatureProgrammer.IExplore,
163
- ): ts.ArrowFunction => {
164
- let index: number = 1;
165
- const body: ts.Statement[] = obj.properties
166
- .map((p) => {
167
- const block = decode(project)(importer)(index)(
168
- IdentifierFactory.access(input)(
169
- p.key.getSoleLiteral()!,
170
- ),
171
- p.value,
172
- explore,
173
- );
174
- index += ProtobufUtil.size(p.value);
175
- return [
176
- ts.factory.createExpressionStatement(
177
- ts.factory.createIdentifier(
178
- `// property "${p.key.getSoleLiteral()!}"`,
179
- ),
180
- ),
181
- ...block.statements,
182
- ];
183
- })
184
- .flat();
185
-
186
- return ts.factory.createArrowFunction(
187
- undefined,
188
- undefined,
189
- [IdentifierFactory.parameter("input")],
190
- TypeFactory.keyword("any"),
191
- undefined,
192
- ts.factory.createBlock(body, true),
193
- );
194
- };
195
-
196
- /* -----------------------------------------------------------
197
- DECODERS
198
- ----------------------------------------------------------- */
199
- const decode =
200
- (project: IProject) =>
201
- (importer: FunctionImporter) =>
202
- (index: number | null) =>
203
- (
204
- input: ts.Expression,
205
- meta: Metadata,
206
- explore: FeatureProgrammer.IExplore,
207
- ): ts.Block => {
208
- const wrapper: (block: ts.Block) => ts.Block =
209
- meta.isRequired() && meta.nullable === false
210
- ? (block) => block
211
- : meta.isRequired() === false && meta.nullable === true
212
- ? (block) =>
213
- ts.factory.createBlock(
214
- [
215
- ts.factory.createIfStatement(
216
- ts.factory.createLogicalAnd(
217
- ts.factory.createStrictInequality(
218
- ts.factory.createIdentifier(
219
- "undefined",
220
- ),
221
- input,
222
- ),
223
- ts.factory.createStrictInequality(
224
- ts.factory.createNull(),
225
- input,
226
- ),
227
- ),
228
- block,
229
- ),
230
- ],
231
- true,
232
- )
233
- : meta.isRequired() === false
234
- ? (block) =>
235
- ts.factory.createBlock(
236
- [
237
- ts.factory.createIfStatement(
238
- ts.factory.createStrictInequality(
239
- ts.factory.createIdentifier(
240
- "undefined",
241
- ),
242
- input,
243
- ),
244
- block,
245
- ),
246
- ],
247
- true,
248
- )
249
- : (block) =>
250
- ts.factory.createBlock(
251
- [
252
- ts.factory.createIfStatement(
253
- ts.factory.createStrictInequality(
254
- ts.factory.createNull(),
255
- input,
256
- ),
257
- block,
258
- ),
259
- ],
260
- true,
261
- );
262
-
263
- // STARTS FROM ATOMIC TYPES
264
- const unions: IUnion[] = [];
265
- const numbers = ProtobufUtil.getNumbers(meta);
266
- const bigints = ProtobufUtil.getBigints(meta);
267
-
268
- for (const atom of ProtobufUtil.getAtomics(meta))
269
- if (atom === "bool")
270
- unions.push({
271
- type: "bool",
272
- is: () =>
273
- ts.factory.createStrictEquality(
274
- ts.factory.createStringLiteral("boolean"),
275
- ts.factory.createTypeOfExpression(input),
276
- ),
277
- value: (index) => decode_bool(index)(input),
278
- });
279
- else if (
280
- atom === "int32" ||
281
- atom === "uint32" ||
282
- atom === "float" ||
283
- atom === "double"
284
- )
285
- unions.push(decode_number(project)(numbers)(atom)(input));
286
- else if (atom === "int64" || atom === "uint64")
287
- if (numbers.some((n) => n === atom))
288
- unions.push(
289
- decode_number(project)(numbers)(atom)(input),
290
- );
291
- else
292
- unions.push(
293
- decode_bigint(project)(bigints)(atom)(input),
294
- );
295
- else if (atom === "string")
296
- unions.push({
297
- type: "string",
298
- is: () =>
299
- ts.factory.createStrictEquality(
300
- ts.factory.createStringLiteral("string"),
301
- ts.factory.createTypeOfExpression(input),
302
- ),
303
- value: (index) => decode_bytes("string")(index!)(input),
304
- });
305
-
306
- // CONSIDER BYTES
307
- if (meta.natives.length)
308
- unions.push({
309
- type: "bytes",
310
- is: () =>
311
- ExpressionFactory.isInstanceOf("Uint8Array")(input),
312
- value: (index) => decode_bytes("bytes")(index!)(input),
313
- });
314
-
315
- // CONSIDER ARRAYS
316
- if (meta.arrays.length)
317
- unions.push({
318
- type: "array",
319
- is: () => ExpressionFactory.isArray(input),
320
- value: (index) =>
321
- decode_array(project)(importer)(index!)(
322
- input,
323
- meta.arrays[0]!,
324
- {
325
- ...explore,
326
- from: "array",
327
- },
328
- ),
329
- });
330
-
331
- // CONSIDER MAPS
332
- if (meta.maps.length)
333
- unions.push({
334
- type: "map",
335
- is: () => ExpressionFactory.isInstanceOf("Map")(input),
336
- value: (index) =>
337
- decode_map(project)(importer)(index!)(
338
- input,
339
- meta.maps[0]!,
340
- {
341
- ...explore,
342
- from: "array",
343
- },
344
- ),
345
- });
346
-
347
- // CONSIDER OBJECTS
348
- if (meta.objects.length)
349
- unions.push({
350
- type: "object",
351
- is: () =>
352
- ExpressionFactory.isObject({
353
- checkNull: true,
354
- checkArray: false,
355
- })(input),
356
- value: (index) =>
357
- explore_objects(project)(importer)(0)(index)(
358
- input,
359
- meta.objects,
360
- {
361
- ...explore,
362
- from: "object",
363
- },
364
- ),
365
- });
366
-
367
- // RETURNS
368
- // if (unions.length === 0) console.log(meta.getName());
369
- if (unions.length === 1) return wrapper(unions[0]!.value(index));
370
- else
371
- return wrapper(
372
- iterate(importer)(index)(unions)(meta.getName())(input),
373
- );
374
- };
375
-
376
- const iterate =
377
- (importer: FunctionImporter) =>
378
- (index: number | null) =>
379
- (unions: IUnion[]) =>
380
- (expected: string) =>
381
- (input: ts.Expression) =>
382
- ts.factory.createBlock(
383
- [
384
- unions
385
- .map((u, i) =>
386
- ts.factory.createIfStatement(
387
- u.is(),
388
- u.value(index ? index + i : null),
389
- i === unions.length - 1
390
- ? create_throw_error(importer)(expected)(
391
- input,
392
- )
393
- : undefined,
394
- ),
395
- )
396
- .reverse()
397
- .reduce((a, b) =>
398
- ts.factory.createIfStatement(
399
- b.expression,
400
- b.thenStatement,
401
- a,
402
- ),
403
- ),
404
- ],
405
- true,
406
- );
407
-
408
- const decode_map =
409
- (project: IProject) =>
410
- (importer: FunctionImporter) =>
411
- (index: number) =>
412
- (
413
- input: ts.Expression,
414
- map: Metadata.Entry,
415
- explore: FeatureProgrammer.IExplore,
416
- ): ts.Block => {
417
- const each: ts.Statement[] = [
418
- ts.factory.createExpressionStatement(
419
- decode_tag(ProtobufWire.LEN)(index),
420
- ),
421
- ts.factory.createExpressionStatement(
422
- ts.factory.createCallExpression(
423
- IdentifierFactory.access(WRITER())("fork"),
424
- undefined,
425
- undefined,
426
- ),
427
- ),
428
- ...decode(project)(importer)(1)(
429
- ts.factory.createIdentifier("key"),
430
- map.key,
431
- explore,
432
- ).statements,
433
- ...decode(project)(importer)(2)(
434
- ts.factory.createIdentifier("value"),
435
- map.value,
436
- explore,
437
- ).statements,
438
- ts.factory.createExpressionStatement(
439
- ts.factory.createCallExpression(
440
- IdentifierFactory.access(WRITER())("ldelim"),
441
- undefined,
442
- undefined,
443
- ),
444
- ),
445
- ];
446
- return ts.factory.createBlock(
447
- [
448
- ts.factory.createForOfStatement(
449
- undefined,
450
- StatementFactory.entry("key")("value"),
451
- input,
452
- ts.factory.createBlock(each),
453
- ),
454
- ],
455
- true,
456
- );
457
- };
458
-
459
- const decode_object =
460
- (project: IProject) =>
461
- (importer: FunctionImporter) =>
462
- (index: number | null) =>
463
- (
464
- input: ts.Expression,
465
- object: MetadataObject,
466
- explore: FeatureProgrammer.IExplore,
467
- ): ts.Block => {
468
- const top: MetadataProperty = object.properties[0]!;
469
- if (top.key.isSoleLiteral() === false)
470
- return decode_map(project)(importer)(index!)(
471
- ts.factory.createCallExpression(
472
- ts.factory.createIdentifier("Object.entries"),
473
- [],
474
- [input],
475
- ),
476
- MetadataProperty.create({
477
- ...top,
478
- key: (() => {
479
- const key: Metadata = Metadata.initialize();
480
- key.atomics.push(
481
- MetadataAtomic.create({
482
- type: "string",
483
- tags: [],
484
- }),
485
- );
486
- return key;
487
- })(),
488
- }),
489
- explore,
490
- );
491
- return ts.factory.createBlock(
492
- [
493
- ts.factory.createIdentifier(
494
- `//${index !== null ? ` ${index} -> ` : ""}${
495
- object.name
496
- }`,
497
- ),
498
- ...(index !== null
499
- ? [
500
- decode_tag(ProtobufWire.LEN)(index),
501
- ts.factory.createCallExpression(
502
- IdentifierFactory.access(WRITER())("fork"),
503
- undefined,
504
- undefined,
505
- ),
506
- ]
507
- : []),
508
- ts.factory.createCallExpression(
509
- ts.factory.createIdentifier(
510
- importer.useLocal(`${PREFIX}o${object.index}`),
511
- ),
512
- [],
513
- [input],
514
- ),
515
- ...(index !== null
516
- ? [
517
- ts.factory.createCallExpression(
518
- IdentifierFactory.access(WRITER())("ldelim"),
519
- undefined,
520
- undefined,
521
- ),
522
- ]
523
- : []),
524
- ].map((expr) => ts.factory.createExpressionStatement(expr)),
525
- true,
526
- );
527
- };
528
-
529
- const decode_array =
530
- (project: IProject) =>
531
- (importer: FunctionImporter) =>
532
- (index: number) =>
533
- (
534
- input: ts.Expression,
535
- array: MetadataArray,
536
- explore: FeatureProgrammer.IExplore,
537
- ): ts.Block => {
538
- const wire = get_standalone_wire(array.type.value);
539
- const forLoop = (index: number | null) =>
540
- ts.factory.createForOfStatement(
541
- undefined,
542
- ts.factory.createVariableDeclarationList(
543
- [ts.factory.createVariableDeclaration("elem")],
544
- ts.NodeFlags.Const,
545
- ),
546
- input,
547
- decode(project)(importer)(index)(
548
- ts.factory.createIdentifier("elem"),
549
- array.type.value,
550
- explore,
551
- ),
552
- );
553
- const length = (block: ts.Block) =>
554
- ts.factory.createBlock(
555
- [
556
- ts.factory.createIfStatement(
557
- ts.factory.createStrictInequality(
558
- ts.factory.createNumericLiteral(0),
559
- IdentifierFactory.access(input)("length"),
560
- ),
561
- block,
562
- ),
563
- ],
564
- true,
565
- );
566
-
567
- if (wire === ProtobufWire.LEN)
568
- return length(ts.factory.createBlock([forLoop(index)], true));
569
- return length(
570
- ts.factory.createBlock(
571
- [
572
- ts.factory.createExpressionStatement(
573
- decode_tag(ProtobufWire.LEN)(index),
574
- ),
575
- ts.factory.createExpressionStatement(
576
- ts.factory.createCallExpression(
577
- IdentifierFactory.access(WRITER())("fork"),
578
- undefined,
579
- undefined,
580
- ),
581
- ),
582
- forLoop(null),
583
- ts.factory.createExpressionStatement(
584
- ts.factory.createCallExpression(
585
- IdentifierFactory.access(WRITER())("ldelim"),
586
- undefined,
587
- undefined,
588
- ),
589
- ),
590
- ],
591
- true,
592
- ),
593
- );
594
- };
595
-
596
- const decode_bool = (index: number | null) => (input: ts.Expression) =>
597
- ts.factory.createBlock(
598
- [
599
- ...(index !== null
600
- ? [decode_tag(ProtobufWire.VARIANT)(index)]
601
- : []),
602
- ts.factory.createCallExpression(
603
- IdentifierFactory.access(WRITER())("bool"),
604
- undefined,
605
- [input],
606
- ),
607
- ].map((exp) => ts.factory.createExpressionStatement(exp)),
608
- true,
609
- );
610
-
611
- const decode_number =
612
- (project: IProject) =>
613
- (candidates: ProtobufAtomic.Numeric[]) =>
614
- (type: ProtobufAtomic.Numeric) =>
615
- (input: ts.Expression): IUnion => ({
616
- type,
617
- is: () =>
618
- candidates.length === 1
619
- ? ts.factory.createStrictEquality(
620
- ts.factory.createStringLiteral("number"),
621
- ts.factory.createTypeOfExpression(input),
622
- )
623
- : ts.factory.createLogicalAnd(
624
- ts.factory.createStrictEquality(
625
- ts.factory.createStringLiteral("number"),
626
- ts.factory.createTypeOfExpression(input),
627
- ),
628
- NumericRangeFactory.number(project.context)(type)(
629
- input,
630
- ),
631
- ),
632
- value: (index) =>
633
- ts.factory.createBlock(
634
- [
635
- ...(index !== null
636
- ? [decode_tag(get_numeric_wire(type))(index)]
637
- : []),
638
- ts.factory.createCallExpression(
639
- IdentifierFactory.access(WRITER())(type),
640
- undefined,
641
- [input],
642
- ),
643
- ].map((exp) => ts.factory.createExpressionStatement(exp)),
644
- true,
645
- ),
646
- });
647
-
648
- const decode_bigint =
649
- (project: IProject) =>
650
- (candidates: ProtobufAtomic.BigNumeric[]) =>
651
- (type: ProtobufAtomic.BigNumeric) =>
652
- (input: ts.Expression): IUnion => ({
653
- type,
654
- is: () =>
655
- candidates.length === 1
656
- ? ts.factory.createStrictEquality(
657
- ts.factory.createStringLiteral("bigint"),
658
- ts.factory.createTypeOfExpression(input),
659
- )
660
- : ts.factory.createLogicalAnd(
661
- ts.factory.createStrictEquality(
662
- ts.factory.createStringLiteral("bigint"),
663
- ts.factory.createTypeOfExpression(input),
664
- ),
665
- NumericRangeFactory.bigint(project.context)(type)(
666
- input,
667
- ),
668
- ),
669
- value: (index) =>
670
- ts.factory.createBlock(
671
- [
672
- ...(index !== null
673
- ? [decode_tag(ProtobufWire.VARIANT)(index)]
674
- : []),
675
- ts.factory.createCallExpression(
676
- IdentifierFactory.access(WRITER())(type),
677
- undefined,
678
- [input],
679
- ),
680
- ].map((exp) => ts.factory.createExpressionStatement(exp)),
681
- true,
682
- ),
683
- });
684
-
685
- const decode_bytes =
686
- (method: "bytes" | "string") =>
687
- (index: number) =>
688
- (input: ts.Expression): ts.Block =>
689
- ts.factory.createBlock(
690
- [
691
- decode_tag(ProtobufWire.LEN)(index),
692
- ts.factory.createCallExpression(
693
- IdentifierFactory.access(WRITER())(method),
694
- undefined,
695
- [input],
696
- ),
697
- ].map((expr) => ts.factory.createExpressionStatement(expr)),
698
- true,
699
- );
700
-
701
- const decode_tag =
702
- (wire: ProtobufWire) =>
703
- (index: number): ts.CallExpression =>
704
- ts.factory.createCallExpression(
705
- IdentifierFactory.access(WRITER())("uint32"),
706
- undefined,
707
- [ts.factory.createNumericLiteral((index << 3) | wire)],
708
- );
709
-
710
- const get_standalone_wire = (meta: Metadata): ProtobufWire => {
711
- if (
712
- meta.arrays.length ||
713
- meta.objects.length ||
714
- meta.maps.length ||
715
- meta.natives.length
716
- )
717
- return ProtobufWire.LEN;
718
-
719
- const v = ProtobufUtil.getAtomics(meta)[0]!;
720
- if (v === "string") return ProtobufWire.LEN;
721
- else if (
722
- v === "bool" ||
723
- v === "int32" ||
724
- v === "uint32" ||
725
- v === "int64" ||
726
- v === "uint64"
727
- )
728
- return ProtobufWire.VARIANT;
729
- else if (v === "float") return ProtobufWire.I32;
730
- return ProtobufWire.I64;
731
- };
732
-
733
- const get_numeric_wire = (type: ProtobufAtomic.Numeric) =>
734
- type === "double"
735
- ? ProtobufWire.I64
736
- : type === "float"
737
- ? ProtobufWire.I32
738
- : ProtobufWire.VARIANT;
739
-
740
- /* -----------------------------------------------------------
741
- EXPLORERS
742
- ----------------------------------------------------------- */
743
- const explore_objects =
744
- (project: IProject) =>
745
- (importer: FunctionImporter) =>
746
- (level: number) =>
747
- (index: number | null) =>
748
- (
749
- input: ts.Expression,
750
- targets: MetadataObject[],
751
- explore: FeatureProgrammer.IExplore,
752
- indexes?: Map<MetadataObject, number>,
753
- ): ts.Block => {
754
- if (targets.length === 1)
755
- return decode_object(project)(importer)(
756
- indexes ? indexes.get(targets[0]!)! : index,
757
- )(input, targets[0]!, explore);
758
-
759
- const expected: string = `(${targets
760
- .map((t) => t.name)
761
- .join(" | ")})`;
762
-
763
- // POSSIBLE TO SPECIALIZE?
764
- const specList = UnionPredicator.object(targets);
765
- indexes ??= new Map(targets.map((t, i) => [t, index! + i]));
766
-
767
- if (specList.length === 0) {
768
- const condition: ts.Expression = decode_union_object(
769
- IsProgrammer.decode_object(importer),
770
- )((i, o, e) =>
771
- ExpressionFactory.selfCall(
772
- decode_object(project)(importer)(indexes!.get(o)!)(
773
- i,
774
- o,
775
- e,
776
- ),
777
- ),
778
- )((expr) => expr)((value, expected) =>
779
- create_throw_error(importer)(expected)(value),
780
- )(input, targets, explore);
781
- return StatementFactory.block(condition);
782
- }
783
- const remained: MetadataObject[] = targets.filter(
784
- (t) => specList.find((s) => s.object === t) === undefined,
785
- );
786
-
787
- // DO SPECIALIZE
788
- const condition: ts.IfStatement = specList
789
- .filter((spec) => spec.property.key.getSoleLiteral() !== null)
790
- .map((spec, i, array) => {
791
- const key: string = spec.property.key.getSoleLiteral()!;
792
- const accessor: ts.Expression =
793
- IdentifierFactory.access(input)(key);
794
- const pred: ts.Expression = spec.neighbour
795
- ? IsProgrammer.decode(project)(importer)(
796
- accessor,
797
- spec.property.value,
798
- {
799
- ...explore,
800
- tracable: false,
801
- postfix: IdentifierFactory.postfix(key),
802
- },
803
- )
804
- : ExpressionFactory.isRequired(accessor);
805
- return ts.factory.createIfStatement(
806
- pred,
807
- ts.factory.createReturnStatement(
808
- ExpressionFactory.selfCall(
809
- decode_object(project)(importer)(
810
- indexes!.get(spec.object)!,
811
- )(input, spec.object, explore),
812
- ),
813
- ),
814
- i === array.length - 1
815
- ? remained.length
816
- ? ts.factory.createReturnStatement(
817
- ExpressionFactory.selfCall(
818
- explore_objects(project)(importer)(
819
- level + 1,
820
- )(index)(
821
- input,
822
- remained,
823
- explore,
824
- indexes!,
825
- ),
826
- ),
827
- )
828
- : create_throw_error(importer)(expected)(input)
829
- : undefined,
830
- );
831
- })
832
- .reverse()
833
- .reduce((a, b) =>
834
- ts.factory.createIfStatement(
835
- b.expression,
836
- b.thenStatement,
837
- a,
838
- ),
839
- );
840
-
841
- // RETURNS WITH CONDITIONS
842
- return ts.factory.createBlock([condition], true);
843
- };
844
-
845
- /* -----------------------------------------------------------
846
- CONFIGURATIONS
847
- ----------------------------------------------------------- */
848
- const PREFIX = "$pe";
849
-
850
- const create_throw_error =
851
- (importer: FunctionImporter) =>
852
- (expected: string) =>
853
- (value: ts.Expression) =>
854
- ts.factory.createExpressionStatement(
855
- ts.factory.createCallExpression(
856
- importer.use("throws"),
857
- [],
858
- [
859
- ts.factory.createObjectLiteralExpression(
860
- [
861
- ts.factory.createPropertyAssignment(
862
- "expected",
863
- ts.factory.createStringLiteral(expected),
864
- ),
865
- ts.factory.createPropertyAssignment(
866
- "value",
867
- value,
868
- ),
869
- ],
870
- true,
871
- ),
872
- ],
873
- ),
874
- );
875
- }
876
-
877
- const WRITER = () => ts.factory.createIdentifier("writer");
878
-
879
- interface IUnion {
880
- type: string;
881
- is: () => ts.Expression;
882
- value: (index: number | null) => ts.Block;
883
- }
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 { NumericRangeFactory } from "../../factories/NumericRangeFactory";
7
+ import { ProtobufFactory } from "../../factories/ProtobufFactory";
8
+ import { StatementFactory } from "../../factories/StatementFactory";
9
+ import { TypeFactory } from "../../factories/TypeFactory";
10
+
11
+ import { Metadata } from "../../schemas/metadata/Metadata";
12
+ import { MetadataArray } from "../../schemas/metadata/MetadataArray";
13
+ import { MetadataAtomic } from "../../schemas/metadata/MetadataAtomic";
14
+ import { MetadataObject } from "../../schemas/metadata/MetadataObject";
15
+ import { MetadataProperty } from "../../schemas/metadata/MetadataProperty";
16
+
17
+ import { IProject } from "../../transformers/IProject";
18
+
19
+ import { ProtobufAtomic } from "../../typings/ProtobufAtomic";
20
+
21
+ import { FeatureProgrammer } from "../FeatureProgrammer";
22
+ import { IsProgrammer } from "../IsProgrammer";
23
+ import { FunctionImporter } from "../helpers/FunctionImporeter";
24
+ import { ProtobufUtil } from "../helpers/ProtobufUtil";
25
+ import { ProtobufWire } from "../helpers/ProtobufWire";
26
+ import { UnionPredicator } from "../helpers/UnionPredicator";
27
+ import { decode_union_object } from "../internal/decode_union_object";
28
+
29
+ export namespace ProtobufEncodeProgrammer {
30
+ export const write =
31
+ (project: IProject) =>
32
+ (modulo: ts.LeftHandSideExpression) =>
33
+ (type: ts.Type, name?: string): ts.ArrowFunction => {
34
+ const importer = new FunctionImporter(modulo.getText());
35
+ const collection = new MetadataCollection();
36
+ const meta: Metadata = ProtobufFactory.metadata(modulo.getText())(
37
+ project.checker,
38
+ )(collection)(type);
39
+
40
+ const callEncoder =
41
+ (writer: string) => (factory: ts.NewExpression) =>
42
+ StatementFactory.constant(
43
+ writer,
44
+ ts.factory.createCallExpression(
45
+ ts.factory.createIdentifier("encoder"),
46
+ undefined,
47
+ [factory],
48
+ ),
49
+ );
50
+
51
+ const block: ts.Statement[] = [
52
+ StatementFactory.constant(
53
+ "encoder",
54
+ write_encoder(project)(importer)(collection)(meta),
55
+ ),
56
+ callEncoder("sizer")(
57
+ ts.factory.createNewExpression(
58
+ importer.use("Sizer"),
59
+ undefined,
60
+ [],
61
+ ),
62
+ ),
63
+ callEncoder("writer")(
64
+ ts.factory.createNewExpression(
65
+ importer.use("Writer"),
66
+ undefined,
67
+ [ts.factory.createIdentifier("sizer")],
68
+ ),
69
+ ),
70
+ ts.factory.createReturnStatement(
71
+ ts.factory.createCallExpression(
72
+ IdentifierFactory.access(WRITER())("buffer"),
73
+ undefined,
74
+ undefined,
75
+ ),
76
+ ),
77
+ ];
78
+
79
+ return ts.factory.createArrowFunction(
80
+ undefined,
81
+ undefined,
82
+ [
83
+ IdentifierFactory.parameter(
84
+ "input",
85
+ ts.factory.createTypeReferenceNode(
86
+ name ??
87
+ TypeFactory.getFullName(project.checker)(type),
88
+ ),
89
+ ),
90
+ ],
91
+ ts.factory.createTypeReferenceNode("Uint8Array"),
92
+ undefined,
93
+ ts.factory.createBlock(
94
+ [...importer.declare(modulo, false), ...block],
95
+ true,
96
+ ),
97
+ );
98
+ };
99
+
100
+ const write_encoder =
101
+ (project: IProject) =>
102
+ (importer: FunctionImporter) =>
103
+ (collection: MetadataCollection) =>
104
+ (meta: Metadata): ts.ArrowFunction => {
105
+ const functors = collection
106
+ .objects()
107
+ .filter((obj) => ProtobufUtil.isStaticObject(obj))
108
+ .map((obj) =>
109
+ StatementFactory.constant(
110
+ `${PREFIX}o${obj.index}`,
111
+ write_object_function(project)(importer)(
112
+ ts.factory.createIdentifier("input"),
113
+ obj,
114
+ {
115
+ source: "function",
116
+ from: "object",
117
+ tracable: false,
118
+ postfix: "",
119
+ },
120
+ ),
121
+ ),
122
+ );
123
+ const main = decode(project)(importer)(null)(
124
+ ts.factory.createIdentifier("input"),
125
+ meta,
126
+ {
127
+ source: "top",
128
+ from: "top",
129
+ tracable: false,
130
+ postfix: "",
131
+ },
132
+ );
133
+ return ts.factory.createArrowFunction(
134
+ undefined,
135
+ undefined,
136
+ [IdentifierFactory.parameter("writer")],
137
+ TypeFactory.keyword("any"),
138
+ undefined,
139
+ ts.factory.createBlock(
140
+ [
141
+ ...importer.declareUnions(),
142
+ ...functors,
143
+ ...IsProgrammer.write_function_statements(project)(
144
+ importer,
145
+ )(collection),
146
+ ...main.statements,
147
+ ts.factory.createReturnStatement(
148
+ ts.factory.createIdentifier("writer"),
149
+ ),
150
+ ],
151
+ true,
152
+ ),
153
+ );
154
+ };
155
+
156
+ const write_object_function =
157
+ (project: IProject) =>
158
+ (importer: FunctionImporter) =>
159
+ (
160
+ input: ts.Expression,
161
+ obj: MetadataObject,
162
+ explore: FeatureProgrammer.IExplore,
163
+ ): ts.ArrowFunction => {
164
+ let index: number = 1;
165
+ const body: ts.Statement[] = obj.properties
166
+ .map((p) => {
167
+ const block = decode(project)(importer)(index)(
168
+ IdentifierFactory.access(input)(
169
+ p.key.getSoleLiteral()!,
170
+ ),
171
+ p.value,
172
+ explore,
173
+ );
174
+ index += ProtobufUtil.size(p.value);
175
+ return [
176
+ ts.factory.createExpressionStatement(
177
+ ts.factory.createIdentifier(
178
+ `// property "${p.key.getSoleLiteral()!}"`,
179
+ ),
180
+ ),
181
+ ...block.statements,
182
+ ];
183
+ })
184
+ .flat();
185
+
186
+ return ts.factory.createArrowFunction(
187
+ undefined,
188
+ undefined,
189
+ [IdentifierFactory.parameter("input")],
190
+ TypeFactory.keyword("any"),
191
+ undefined,
192
+ ts.factory.createBlock(body, true),
193
+ );
194
+ };
195
+
196
+ /* -----------------------------------------------------------
197
+ DECODERS
198
+ ----------------------------------------------------------- */
199
+ const decode =
200
+ (project: IProject) =>
201
+ (importer: FunctionImporter) =>
202
+ (index: number | null) =>
203
+ (
204
+ input: ts.Expression,
205
+ meta: Metadata,
206
+ explore: FeatureProgrammer.IExplore,
207
+ ): ts.Block => {
208
+ const wrapper: (block: ts.Block) => ts.Block =
209
+ meta.isRequired() && meta.nullable === false
210
+ ? (block) => block
211
+ : meta.isRequired() === false && meta.nullable === true
212
+ ? (block) =>
213
+ ts.factory.createBlock(
214
+ [
215
+ ts.factory.createIfStatement(
216
+ ts.factory.createLogicalAnd(
217
+ ts.factory.createStrictInequality(
218
+ ts.factory.createIdentifier(
219
+ "undefined",
220
+ ),
221
+ input,
222
+ ),
223
+ ts.factory.createStrictInequality(
224
+ ts.factory.createNull(),
225
+ input,
226
+ ),
227
+ ),
228
+ block,
229
+ ),
230
+ ],
231
+ true,
232
+ )
233
+ : meta.isRequired() === false
234
+ ? (block) =>
235
+ ts.factory.createBlock(
236
+ [
237
+ ts.factory.createIfStatement(
238
+ ts.factory.createStrictInequality(
239
+ ts.factory.createIdentifier(
240
+ "undefined",
241
+ ),
242
+ input,
243
+ ),
244
+ block,
245
+ ),
246
+ ],
247
+ true,
248
+ )
249
+ : (block) =>
250
+ ts.factory.createBlock(
251
+ [
252
+ ts.factory.createIfStatement(
253
+ ts.factory.createStrictInequality(
254
+ ts.factory.createNull(),
255
+ input,
256
+ ),
257
+ block,
258
+ ),
259
+ ],
260
+ true,
261
+ );
262
+
263
+ // STARTS FROM ATOMIC TYPES
264
+ const unions: IUnion[] = [];
265
+ const numbers = ProtobufUtil.getNumbers(meta);
266
+ const bigints = ProtobufUtil.getBigints(meta);
267
+
268
+ for (const atom of ProtobufUtil.getAtomics(meta))
269
+ if (atom === "bool")
270
+ unions.push({
271
+ type: "bool",
272
+ is: () =>
273
+ ts.factory.createStrictEquality(
274
+ ts.factory.createStringLiteral("boolean"),
275
+ ts.factory.createTypeOfExpression(input),
276
+ ),
277
+ value: (index) => decode_bool(index)(input),
278
+ });
279
+ else if (
280
+ atom === "int32" ||
281
+ atom === "uint32" ||
282
+ atom === "float" ||
283
+ atom === "double"
284
+ )
285
+ unions.push(decode_number(project)(numbers)(atom)(input));
286
+ else if (atom === "int64" || atom === "uint64")
287
+ if (numbers.some((n) => n === atom))
288
+ unions.push(
289
+ decode_number(project)(numbers)(atom)(input),
290
+ );
291
+ else
292
+ unions.push(
293
+ decode_bigint(project)(bigints)(atom)(input),
294
+ );
295
+ else if (atom === "string")
296
+ unions.push({
297
+ type: "string",
298
+ is: () =>
299
+ ts.factory.createStrictEquality(
300
+ ts.factory.createStringLiteral("string"),
301
+ ts.factory.createTypeOfExpression(input),
302
+ ),
303
+ value: (index) => decode_bytes("string")(index!)(input),
304
+ });
305
+
306
+ // CONSIDER BYTES
307
+ if (meta.natives.length)
308
+ unions.push({
309
+ type: "bytes",
310
+ is: () =>
311
+ ExpressionFactory.isInstanceOf("Uint8Array")(input),
312
+ value: (index) => decode_bytes("bytes")(index!)(input),
313
+ });
314
+
315
+ // CONSIDER ARRAYS
316
+ if (meta.arrays.length)
317
+ unions.push({
318
+ type: "array",
319
+ is: () => ExpressionFactory.isArray(input),
320
+ value: (index) =>
321
+ decode_array(project)(importer)(index!)(
322
+ input,
323
+ meta.arrays[0]!,
324
+ {
325
+ ...explore,
326
+ from: "array",
327
+ },
328
+ ),
329
+ });
330
+
331
+ // CONSIDER MAPS
332
+ if (meta.maps.length)
333
+ unions.push({
334
+ type: "map",
335
+ is: () => ExpressionFactory.isInstanceOf("Map")(input),
336
+ value: (index) =>
337
+ decode_map(project)(importer)(index!)(
338
+ input,
339
+ meta.maps[0]!,
340
+ {
341
+ ...explore,
342
+ from: "array",
343
+ },
344
+ ),
345
+ });
346
+
347
+ // CONSIDER OBJECTS
348
+ if (meta.objects.length)
349
+ unions.push({
350
+ type: "object",
351
+ is: () =>
352
+ ExpressionFactory.isObject({
353
+ checkNull: true,
354
+ checkArray: false,
355
+ })(input),
356
+ value: (index) =>
357
+ explore_objects(project)(importer)(0)(index)(
358
+ input,
359
+ meta.objects,
360
+ {
361
+ ...explore,
362
+ from: "object",
363
+ },
364
+ ),
365
+ });
366
+
367
+ // RETURNS
368
+ // if (unions.length === 0) console.log(meta.getName());
369
+ if (unions.length === 1) return wrapper(unions[0]!.value(index));
370
+ else
371
+ return wrapper(
372
+ iterate(importer)(index)(unions)(meta.getName())(input),
373
+ );
374
+ };
375
+
376
+ const iterate =
377
+ (importer: FunctionImporter) =>
378
+ (index: number | null) =>
379
+ (unions: IUnion[]) =>
380
+ (expected: string) =>
381
+ (input: ts.Expression) =>
382
+ ts.factory.createBlock(
383
+ [
384
+ unions
385
+ .map((u, i) =>
386
+ ts.factory.createIfStatement(
387
+ u.is(),
388
+ u.value(index ? index + i : null),
389
+ i === unions.length - 1
390
+ ? create_throw_error(importer)(expected)(
391
+ input,
392
+ )
393
+ : undefined,
394
+ ),
395
+ )
396
+ .reverse()
397
+ .reduce((a, b) =>
398
+ ts.factory.createIfStatement(
399
+ b.expression,
400
+ b.thenStatement,
401
+ a,
402
+ ),
403
+ ),
404
+ ],
405
+ true,
406
+ );
407
+
408
+ const decode_map =
409
+ (project: IProject) =>
410
+ (importer: FunctionImporter) =>
411
+ (index: number) =>
412
+ (
413
+ input: ts.Expression,
414
+ map: Metadata.Entry,
415
+ explore: FeatureProgrammer.IExplore,
416
+ ): ts.Block => {
417
+ const each: ts.Statement[] = [
418
+ ts.factory.createExpressionStatement(
419
+ decode_tag(ProtobufWire.LEN)(index),
420
+ ),
421
+ ts.factory.createExpressionStatement(
422
+ ts.factory.createCallExpression(
423
+ IdentifierFactory.access(WRITER())("fork"),
424
+ undefined,
425
+ undefined,
426
+ ),
427
+ ),
428
+ ...decode(project)(importer)(1)(
429
+ ts.factory.createIdentifier("key"),
430
+ map.key,
431
+ explore,
432
+ ).statements,
433
+ ...decode(project)(importer)(2)(
434
+ ts.factory.createIdentifier("value"),
435
+ map.value,
436
+ explore,
437
+ ).statements,
438
+ ts.factory.createExpressionStatement(
439
+ ts.factory.createCallExpression(
440
+ IdentifierFactory.access(WRITER())("ldelim"),
441
+ undefined,
442
+ undefined,
443
+ ),
444
+ ),
445
+ ];
446
+ return ts.factory.createBlock(
447
+ [
448
+ ts.factory.createForOfStatement(
449
+ undefined,
450
+ StatementFactory.entry("key")("value"),
451
+ input,
452
+ ts.factory.createBlock(each),
453
+ ),
454
+ ],
455
+ true,
456
+ );
457
+ };
458
+
459
+ const decode_object =
460
+ (project: IProject) =>
461
+ (importer: FunctionImporter) =>
462
+ (index: number | null) =>
463
+ (
464
+ input: ts.Expression,
465
+ object: MetadataObject,
466
+ explore: FeatureProgrammer.IExplore,
467
+ ): ts.Block => {
468
+ const top: MetadataProperty = object.properties[0]!;
469
+ if (top.key.isSoleLiteral() === false)
470
+ return decode_map(project)(importer)(index!)(
471
+ ts.factory.createCallExpression(
472
+ ts.factory.createIdentifier("Object.entries"),
473
+ [],
474
+ [input],
475
+ ),
476
+ MetadataProperty.create({
477
+ ...top,
478
+ key: (() => {
479
+ const key: Metadata = Metadata.initialize();
480
+ key.atomics.push(
481
+ MetadataAtomic.create({
482
+ type: "string",
483
+ tags: [],
484
+ }),
485
+ );
486
+ return key;
487
+ })(),
488
+ }),
489
+ explore,
490
+ );
491
+ return ts.factory.createBlock(
492
+ [
493
+ ts.factory.createIdentifier(
494
+ `//${index !== null ? ` ${index} -> ` : ""}${
495
+ object.name
496
+ }`,
497
+ ),
498
+ ...(index !== null
499
+ ? [
500
+ decode_tag(ProtobufWire.LEN)(index),
501
+ ts.factory.createCallExpression(
502
+ IdentifierFactory.access(WRITER())("fork"),
503
+ undefined,
504
+ undefined,
505
+ ),
506
+ ]
507
+ : []),
508
+ ts.factory.createCallExpression(
509
+ ts.factory.createIdentifier(
510
+ importer.useLocal(`${PREFIX}o${object.index}`),
511
+ ),
512
+ [],
513
+ [input],
514
+ ),
515
+ ...(index !== null
516
+ ? [
517
+ ts.factory.createCallExpression(
518
+ IdentifierFactory.access(WRITER())("ldelim"),
519
+ undefined,
520
+ undefined,
521
+ ),
522
+ ]
523
+ : []),
524
+ ].map((expr) => ts.factory.createExpressionStatement(expr)),
525
+ true,
526
+ );
527
+ };
528
+
529
+ const decode_array =
530
+ (project: IProject) =>
531
+ (importer: FunctionImporter) =>
532
+ (index: number) =>
533
+ (
534
+ input: ts.Expression,
535
+ array: MetadataArray,
536
+ explore: FeatureProgrammer.IExplore,
537
+ ): ts.Block => {
538
+ const wire = get_standalone_wire(array.type.value);
539
+ const forLoop = (index: number | null) =>
540
+ ts.factory.createForOfStatement(
541
+ undefined,
542
+ ts.factory.createVariableDeclarationList(
543
+ [ts.factory.createVariableDeclaration("elem")],
544
+ ts.NodeFlags.Const,
545
+ ),
546
+ input,
547
+ decode(project)(importer)(index)(
548
+ ts.factory.createIdentifier("elem"),
549
+ array.type.value,
550
+ explore,
551
+ ),
552
+ );
553
+ const length = (block: ts.Block) =>
554
+ ts.factory.createBlock(
555
+ [
556
+ ts.factory.createIfStatement(
557
+ ts.factory.createStrictInequality(
558
+ ts.factory.createNumericLiteral(0),
559
+ IdentifierFactory.access(input)("length"),
560
+ ),
561
+ block,
562
+ ),
563
+ ],
564
+ true,
565
+ );
566
+
567
+ if (wire === ProtobufWire.LEN)
568
+ return length(ts.factory.createBlock([forLoop(index)], true));
569
+ return length(
570
+ ts.factory.createBlock(
571
+ [
572
+ ts.factory.createExpressionStatement(
573
+ decode_tag(ProtobufWire.LEN)(index),
574
+ ),
575
+ ts.factory.createExpressionStatement(
576
+ ts.factory.createCallExpression(
577
+ IdentifierFactory.access(WRITER())("fork"),
578
+ undefined,
579
+ undefined,
580
+ ),
581
+ ),
582
+ forLoop(null),
583
+ ts.factory.createExpressionStatement(
584
+ ts.factory.createCallExpression(
585
+ IdentifierFactory.access(WRITER())("ldelim"),
586
+ undefined,
587
+ undefined,
588
+ ),
589
+ ),
590
+ ],
591
+ true,
592
+ ),
593
+ );
594
+ };
595
+
596
+ const decode_bool = (index: number | null) => (input: ts.Expression) =>
597
+ ts.factory.createBlock(
598
+ [
599
+ ...(index !== null
600
+ ? [decode_tag(ProtobufWire.VARIANT)(index)]
601
+ : []),
602
+ ts.factory.createCallExpression(
603
+ IdentifierFactory.access(WRITER())("bool"),
604
+ undefined,
605
+ [input],
606
+ ),
607
+ ].map((exp) => ts.factory.createExpressionStatement(exp)),
608
+ true,
609
+ );
610
+
611
+ const decode_number =
612
+ (project: IProject) =>
613
+ (candidates: ProtobufAtomic.Numeric[]) =>
614
+ (type: ProtobufAtomic.Numeric) =>
615
+ (input: ts.Expression): IUnion => ({
616
+ type,
617
+ is: () =>
618
+ candidates.length === 1
619
+ ? ts.factory.createStrictEquality(
620
+ ts.factory.createStringLiteral("number"),
621
+ ts.factory.createTypeOfExpression(input),
622
+ )
623
+ : ts.factory.createLogicalAnd(
624
+ ts.factory.createStrictEquality(
625
+ ts.factory.createStringLiteral("number"),
626
+ ts.factory.createTypeOfExpression(input),
627
+ ),
628
+ NumericRangeFactory.number(project.context)(type)(
629
+ input,
630
+ ),
631
+ ),
632
+ value: (index) =>
633
+ ts.factory.createBlock(
634
+ [
635
+ ...(index !== null
636
+ ? [decode_tag(get_numeric_wire(type))(index)]
637
+ : []),
638
+ ts.factory.createCallExpression(
639
+ IdentifierFactory.access(WRITER())(type),
640
+ undefined,
641
+ [input],
642
+ ),
643
+ ].map((exp) => ts.factory.createExpressionStatement(exp)),
644
+ true,
645
+ ),
646
+ });
647
+
648
+ const decode_bigint =
649
+ (project: IProject) =>
650
+ (candidates: ProtobufAtomic.BigNumeric[]) =>
651
+ (type: ProtobufAtomic.BigNumeric) =>
652
+ (input: ts.Expression): IUnion => ({
653
+ type,
654
+ is: () =>
655
+ candidates.length === 1
656
+ ? ts.factory.createStrictEquality(
657
+ ts.factory.createStringLiteral("bigint"),
658
+ ts.factory.createTypeOfExpression(input),
659
+ )
660
+ : ts.factory.createLogicalAnd(
661
+ ts.factory.createStrictEquality(
662
+ ts.factory.createStringLiteral("bigint"),
663
+ ts.factory.createTypeOfExpression(input),
664
+ ),
665
+ NumericRangeFactory.bigint(project.context)(type)(
666
+ input,
667
+ ),
668
+ ),
669
+ value: (index) =>
670
+ ts.factory.createBlock(
671
+ [
672
+ ...(index !== null
673
+ ? [decode_tag(ProtobufWire.VARIANT)(index)]
674
+ : []),
675
+ ts.factory.createCallExpression(
676
+ IdentifierFactory.access(WRITER())(type),
677
+ undefined,
678
+ [input],
679
+ ),
680
+ ].map((exp) => ts.factory.createExpressionStatement(exp)),
681
+ true,
682
+ ),
683
+ });
684
+
685
+ const decode_bytes =
686
+ (method: "bytes" | "string") =>
687
+ (index: number) =>
688
+ (input: ts.Expression): ts.Block =>
689
+ ts.factory.createBlock(
690
+ [
691
+ decode_tag(ProtobufWire.LEN)(index),
692
+ ts.factory.createCallExpression(
693
+ IdentifierFactory.access(WRITER())(method),
694
+ undefined,
695
+ [input],
696
+ ),
697
+ ].map((expr) => ts.factory.createExpressionStatement(expr)),
698
+ true,
699
+ );
700
+
701
+ const decode_tag =
702
+ (wire: ProtobufWire) =>
703
+ (index: number): ts.CallExpression =>
704
+ ts.factory.createCallExpression(
705
+ IdentifierFactory.access(WRITER())("uint32"),
706
+ undefined,
707
+ [ts.factory.createNumericLiteral((index << 3) | wire)],
708
+ );
709
+
710
+ const get_standalone_wire = (meta: Metadata): ProtobufWire => {
711
+ if (
712
+ meta.arrays.length ||
713
+ meta.objects.length ||
714
+ meta.maps.length ||
715
+ meta.natives.length
716
+ )
717
+ return ProtobufWire.LEN;
718
+
719
+ const v = ProtobufUtil.getAtomics(meta)[0]!;
720
+ if (v === "string") return ProtobufWire.LEN;
721
+ else if (
722
+ v === "bool" ||
723
+ v === "int32" ||
724
+ v === "uint32" ||
725
+ v === "int64" ||
726
+ v === "uint64"
727
+ )
728
+ return ProtobufWire.VARIANT;
729
+ else if (v === "float") return ProtobufWire.I32;
730
+ return ProtobufWire.I64;
731
+ };
732
+
733
+ const get_numeric_wire = (type: ProtobufAtomic.Numeric) =>
734
+ type === "double"
735
+ ? ProtobufWire.I64
736
+ : type === "float"
737
+ ? ProtobufWire.I32
738
+ : ProtobufWire.VARIANT;
739
+
740
+ /* -----------------------------------------------------------
741
+ EXPLORERS
742
+ ----------------------------------------------------------- */
743
+ const explore_objects =
744
+ (project: IProject) =>
745
+ (importer: FunctionImporter) =>
746
+ (level: number) =>
747
+ (index: number | null) =>
748
+ (
749
+ input: ts.Expression,
750
+ targets: MetadataObject[],
751
+ explore: FeatureProgrammer.IExplore,
752
+ indexes?: Map<MetadataObject, number>,
753
+ ): ts.Block => {
754
+ if (targets.length === 1)
755
+ return decode_object(project)(importer)(
756
+ indexes ? indexes.get(targets[0]!)! : index,
757
+ )(input, targets[0]!, explore);
758
+
759
+ const expected: string = `(${targets
760
+ .map((t) => t.name)
761
+ .join(" | ")})`;
762
+
763
+ // POSSIBLE TO SPECIALIZE?
764
+ const specList = UnionPredicator.object(targets);
765
+ indexes ??= new Map(targets.map((t, i) => [t, index! + i]));
766
+
767
+ if (specList.length === 0) {
768
+ const condition: ts.Expression = decode_union_object(
769
+ IsProgrammer.decode_object(importer),
770
+ )((i, o, e) =>
771
+ ExpressionFactory.selfCall(
772
+ decode_object(project)(importer)(indexes!.get(o)!)(
773
+ i,
774
+ o,
775
+ e,
776
+ ),
777
+ ),
778
+ )((expr) => expr)((value, expected) =>
779
+ create_throw_error(importer)(expected)(value),
780
+ )(input, targets, explore);
781
+ return StatementFactory.block(condition);
782
+ }
783
+ const remained: MetadataObject[] = targets.filter(
784
+ (t) => specList.find((s) => s.object === t) === undefined,
785
+ );
786
+
787
+ // DO SPECIALIZE
788
+ const condition: ts.IfStatement = specList
789
+ .filter((spec) => spec.property.key.getSoleLiteral() !== null)
790
+ .map((spec, i, array) => {
791
+ const key: string = spec.property.key.getSoleLiteral()!;
792
+ const accessor: ts.Expression =
793
+ IdentifierFactory.access(input)(key);
794
+ const pred: ts.Expression = spec.neighbour
795
+ ? IsProgrammer.decode(project)(importer)(
796
+ accessor,
797
+ spec.property.value,
798
+ {
799
+ ...explore,
800
+ tracable: false,
801
+ postfix: IdentifierFactory.postfix(key),
802
+ },
803
+ )
804
+ : ExpressionFactory.isRequired(accessor);
805
+ return ts.factory.createIfStatement(
806
+ pred,
807
+ ts.factory.createReturnStatement(
808
+ ExpressionFactory.selfCall(
809
+ decode_object(project)(importer)(
810
+ indexes!.get(spec.object)!,
811
+ )(input, spec.object, explore),
812
+ ),
813
+ ),
814
+ i === array.length - 1
815
+ ? remained.length
816
+ ? ts.factory.createReturnStatement(
817
+ ExpressionFactory.selfCall(
818
+ explore_objects(project)(importer)(
819
+ level + 1,
820
+ )(index)(
821
+ input,
822
+ remained,
823
+ explore,
824
+ indexes!,
825
+ ),
826
+ ),
827
+ )
828
+ : create_throw_error(importer)(expected)(input)
829
+ : undefined,
830
+ );
831
+ })
832
+ .reverse()
833
+ .reduce((a, b) =>
834
+ ts.factory.createIfStatement(
835
+ b.expression,
836
+ b.thenStatement,
837
+ a,
838
+ ),
839
+ );
840
+
841
+ // RETURNS WITH CONDITIONS
842
+ return ts.factory.createBlock([condition], true);
843
+ };
844
+
845
+ /* -----------------------------------------------------------
846
+ CONFIGURATIONS
847
+ ----------------------------------------------------------- */
848
+ const PREFIX = "$pe";
849
+
850
+ const create_throw_error =
851
+ (importer: FunctionImporter) =>
852
+ (expected: string) =>
853
+ (value: ts.Expression) =>
854
+ ts.factory.createExpressionStatement(
855
+ ts.factory.createCallExpression(
856
+ importer.use("throws"),
857
+ [],
858
+ [
859
+ ts.factory.createObjectLiteralExpression(
860
+ [
861
+ ts.factory.createPropertyAssignment(
862
+ "expected",
863
+ ts.factory.createStringLiteral(expected),
864
+ ),
865
+ ts.factory.createPropertyAssignment(
866
+ "value",
867
+ value,
868
+ ),
869
+ ],
870
+ true,
871
+ ),
872
+ ],
873
+ ),
874
+ );
875
+ }
876
+
877
+ const WRITER = () => ts.factory.createIdentifier("writer");
878
+
879
+ interface IUnion {
880
+ type: string;
881
+ is: () => ts.Expression;
882
+ value: (index: number | null) => ts.Block;
883
+ }