@nfdi4plants/arctrl 1.0.0-alpha6

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 (277) hide show
  1. package/ARCtrl.js +257 -0
  2. package/Contract/Contract.js +95 -0
  3. package/Contracts/Contracts.ARCtrl.js +35 -0
  4. package/Contracts/Contracts.ArcAssay.js +65 -0
  5. package/Contracts/Contracts.ArcInvestigation.js +58 -0
  6. package/Contracts/Contracts.ArcStudy.js +65 -0
  7. package/Contracts/Contracts.Git.js +91 -0
  8. package/FileSystem/Commit.js +18 -0
  9. package/FileSystem/DefaultGitignore.js +3 -0
  10. package/FileSystem/FileSystem.js +53 -0
  11. package/FileSystem/FileSystemTree.js +223 -0
  12. package/FileSystem/Path.js +38 -0
  13. package/FileSystemTree.js +51 -0
  14. package/ISA/ISA/ArcTypes/ArcTable.js +744 -0
  15. package/ISA/ISA/ArcTypes/ArcTableAux.js +1142 -0
  16. package/ISA/ISA/ArcTypes/ArcTables.js +380 -0
  17. package/ISA/ISA/ArcTypes/ArcTypes.js +2018 -0
  18. package/ISA/ISA/ArcTypes/CompositeCell.js +180 -0
  19. package/ISA/ISA/ArcTypes/CompositeColumn.js +42 -0
  20. package/ISA/ISA/ArcTypes/CompositeHeader.js +358 -0
  21. package/ISA/ISA/ArcTypes/CompositeRow.js +111 -0
  22. package/ISA/ISA/ArcTypes/IdentifierSetters.js +26 -0
  23. package/ISA/ISA/Builder/Types.js +243 -0
  24. package/ISA/ISA/Fable.js +50 -0
  25. package/ISA/ISA/Helper.js +326 -0
  26. package/ISA/ISA/Identifier.js +76 -0
  27. package/ISA/ISA/JsonTypes/AnnotationValue.js +56 -0
  28. package/ISA/ISA/JsonTypes/Assay.js +620 -0
  29. package/ISA/ISA/JsonTypes/AssayMaterials.js +39 -0
  30. package/ISA/ISA/JsonTypes/ColumnIndex.js +246 -0
  31. package/ISA/ISA/JsonTypes/Comment.js +58 -0
  32. package/ISA/ISA/JsonTypes/CommentList.js +139 -0
  33. package/ISA/ISA/JsonTypes/Component.js +158 -0
  34. package/ISA/ISA/JsonTypes/Data.js +55 -0
  35. package/ISA/ISA/JsonTypes/DataFile.js +68 -0
  36. package/ISA/ISA/JsonTypes/Factor.js +128 -0
  37. package/ISA/ISA/JsonTypes/FactorValue.js +109 -0
  38. package/ISA/ISA/JsonTypes/Investigation.js +204 -0
  39. package/ISA/ISA/JsonTypes/Material.js +66 -0
  40. package/ISA/ISA/JsonTypes/MaterialAttribute.js +101 -0
  41. package/ISA/ISA/JsonTypes/MaterialAttributeValue.js +126 -0
  42. package/ISA/ISA/JsonTypes/MaterialType.js +41 -0
  43. package/ISA/ISA/JsonTypes/OntologyAnnotation.js +219 -0
  44. package/ISA/ISA/JsonTypes/OntologySourceReference.js +85 -0
  45. package/ISA/ISA/JsonTypes/Person.js +137 -0
  46. package/ISA/ISA/JsonTypes/Process.js +401 -0
  47. package/ISA/ISA/JsonTypes/ProcessInput.js +297 -0
  48. package/ISA/ISA/JsonTypes/ProcessOutput.js +263 -0
  49. package/ISA/ISA/JsonTypes/ProcessParameterValue.js +129 -0
  50. package/ISA/ISA/JsonTypes/ProcessSequence.js +255 -0
  51. package/ISA/ISA/JsonTypes/Protocol.js +277 -0
  52. package/ISA/ISA/JsonTypes/ProtocolParameter.js +101 -0
  53. package/ISA/ISA/JsonTypes/Publication.js +105 -0
  54. package/ISA/ISA/JsonTypes/Sample.js +71 -0
  55. package/ISA/ISA/JsonTypes/Source.js +54 -0
  56. package/ISA/ISA/JsonTypes/Study.js +942 -0
  57. package/ISA/ISA/JsonTypes/StudyMaterials.js +45 -0
  58. package/ISA/ISA/JsonTypes/URI.js +19 -0
  59. package/ISA/ISA/JsonTypes/Value.js +210 -0
  60. package/ISA/ISA/Regex.js +588 -0
  61. package/ISA/ISA.Json/Assay.js +123 -0
  62. package/ISA/ISA.Json/Comment.js +84 -0
  63. package/ISA/ISA.Json/ConverterOptions.js +33 -0
  64. package/ISA/ISA.Json/Data.js +271 -0
  65. package/ISA/ISA.Json/Decode.js +46 -0
  66. package/ISA/ISA.Json/Factor.js +194 -0
  67. package/ISA/ISA.Json/GEncode.js +15 -0
  68. package/ISA/ISA.Json/Investigation.js +132 -0
  69. package/ISA/ISA.Json/Material.js +233 -0
  70. package/ISA/ISA.Json/Ontology.js +204 -0
  71. package/ISA/ISA.Json/Person.js +204 -0
  72. package/ISA/ISA.Json/Process.js +291 -0
  73. package/ISA/ISA.Json/Protocol.js +242 -0
  74. package/ISA/ISA.Json/Publication.js +92 -0
  75. package/ISA/ISA.Json/Study.js +230 -0
  76. package/ISA/ISA.Json/Validation/Fable.js +69 -0
  77. package/ISA/ISA.Json/Validation/JsonSchemaValidation.js +88 -0
  78. package/ISA/ISA.Json/Validation/ValidationResult.js +45 -0
  79. package/ISA/ISA.Spreadsheet/AnnotationTable/ArcTable.js +137 -0
  80. package/ISA/ISA.Spreadsheet/AnnotationTable/CompositeCell.js +78 -0
  81. package/ISA/ISA.Spreadsheet/AnnotationTable/CompositeColumn.js +59 -0
  82. package/ISA/ISA.Spreadsheet/AnnotationTable/CompositeHeader.js +478 -0
  83. package/ISA/ISA.Spreadsheet/ArcAssay.js +150 -0
  84. package/ISA/ISA.Spreadsheet/ArcInvestigation.js +314 -0
  85. package/ISA/ISA.Spreadsheet/ArcStudy.js +67 -0
  86. package/ISA/ISA.Spreadsheet/CollectionAux.js +128 -0
  87. package/ISA/ISA.Spreadsheet/Metadata/Assays.js +81 -0
  88. package/ISA/ISA.Spreadsheet/Metadata/Comment.js +60 -0
  89. package/ISA/ISA.Spreadsheet/Metadata/Contacts.js +104 -0
  90. package/ISA/ISA.Spreadsheet/Metadata/Conversions.js +180 -0
  91. package/ISA/ISA.Spreadsheet/Metadata/DesignDescriptors.js +27 -0
  92. package/ISA/ISA.Spreadsheet/Metadata/Factors.js +85 -0
  93. package/ISA/ISA.Spreadsheet/Metadata/OntologyAnnotation.js +65 -0
  94. package/ISA/ISA.Spreadsheet/Metadata/OntologySourceReference.js +73 -0
  95. package/ISA/ISA.Spreadsheet/Metadata/Protocols.js +116 -0
  96. package/ISA/ISA.Spreadsheet/Metadata/Publication.js +96 -0
  97. package/ISA/ISA.Spreadsheet/Metadata/SparseTable.js +451 -0
  98. package/ISA/ISA.Spreadsheet/Metadata/Study.js +260 -0
  99. package/README.md +277 -0
  100. package/SemVer.js +60 -0
  101. package/Templates/Templates.Json.js +40 -0
  102. package/Templates/Templates.Spreadsheet.js +315 -0
  103. package/Templates/Templates.js +179 -0
  104. package/fable_modules/FsSpreadsheet.4.1.0/Cells/FsCell.fs +387 -0
  105. package/fable_modules/FsSpreadsheet.4.1.0/Cells/FsCell.fs.js +240 -0
  106. package/fable_modules/FsSpreadsheet.4.1.0/Cells/FsCellsCollection.fs +725 -0
  107. package/fable_modules/FsSpreadsheet.4.1.0/Cells/FsCellsCollection.fs.js +522 -0
  108. package/fable_modules/FsSpreadsheet.4.1.0/DSL/CellBuilder.fs +195 -0
  109. package/fable_modules/FsSpreadsheet.4.1.0/DSL/CellBuilder.fs.js +208 -0
  110. package/fable_modules/FsSpreadsheet.4.1.0/DSL/ColumnBuilder.fs +209 -0
  111. package/fable_modules/FsSpreadsheet.4.1.0/DSL/ColumnBuilder.fs.js +137 -0
  112. package/fable_modules/FsSpreadsheet.4.1.0/DSL/DSL.fs +61 -0
  113. package/fable_modules/FsSpreadsheet.4.1.0/DSL/DSL.fs.js +62 -0
  114. package/fable_modules/FsSpreadsheet.4.1.0/DSL/Expression.fs +24 -0
  115. package/fable_modules/FsSpreadsheet.4.1.0/DSL/Expression.fs.js +56 -0
  116. package/fable_modules/FsSpreadsheet.4.1.0/DSL/Operators.fs +102 -0
  117. package/fable_modules/FsSpreadsheet.4.1.0/DSL/Operators.fs.js +6 -0
  118. package/fable_modules/FsSpreadsheet.4.1.0/DSL/RowBuilder.fs +200 -0
  119. package/fable_modules/FsSpreadsheet.4.1.0/DSL/RowBuilder.fs.js +137 -0
  120. package/fable_modules/FsSpreadsheet.4.1.0/DSL/SheetBuilder.fs +139 -0
  121. package/fable_modules/FsSpreadsheet.4.1.0/DSL/SheetBuilder.fs.js +116 -0
  122. package/fable_modules/FsSpreadsheet.4.1.0/DSL/TableBuilder.fs +120 -0
  123. package/fable_modules/FsSpreadsheet.4.1.0/DSL/TableBuilder.fs.js +120 -0
  124. package/fable_modules/FsSpreadsheet.4.1.0/DSL/Transform.fs +229 -0
  125. package/fable_modules/FsSpreadsheet.4.1.0/DSL/Transform.fs.js +421 -0
  126. package/fable_modules/FsSpreadsheet.4.1.0/DSL/Types.fs +151 -0
  127. package/fable_modules/FsSpreadsheet.4.1.0/DSL/Types.fs.js +277 -0
  128. package/fable_modules/FsSpreadsheet.4.1.0/DSL/WorkbookBuilder.fs +114 -0
  129. package/fable_modules/FsSpreadsheet.4.1.0/DSL/WorkbookBuilder.fs.js +104 -0
  130. package/fable_modules/FsSpreadsheet.4.1.0/FsAddress.fs +177 -0
  131. package/fable_modules/FsSpreadsheet.4.1.0/FsAddress.fs.js +249 -0
  132. package/fable_modules/FsSpreadsheet.4.1.0/FsColumn.fs +200 -0
  133. package/fable_modules/FsSpreadsheet.4.1.0/FsColumn.fs.js +125 -0
  134. package/fable_modules/FsSpreadsheet.4.1.0/FsRow.fs +202 -0
  135. package/fable_modules/FsSpreadsheet.4.1.0/FsRow.fs.js +135 -0
  136. package/fable_modules/FsSpreadsheet.4.1.0/FsSpreadsheet.fableproj +58 -0
  137. package/fable_modules/FsSpreadsheet.4.1.0/FsWorkbook.fs +183 -0
  138. package/fable_modules/FsSpreadsheet.4.1.0/FsWorkbook.fs.js +138 -0
  139. package/fable_modules/FsSpreadsheet.4.1.0/FsWorksheet.fs +628 -0
  140. package/fable_modules/FsSpreadsheet.4.1.0/FsWorksheet.fs.js +398 -0
  141. package/fable_modules/FsSpreadsheet.4.1.0/Ranges/FsRange.fs +19 -0
  142. package/fable_modules/FsSpreadsheet.4.1.0/Ranges/FsRange.fs.js +41 -0
  143. package/fable_modules/FsSpreadsheet.4.1.0/Ranges/FsRangeAddress.fs +222 -0
  144. package/fable_modules/FsSpreadsheet.4.1.0/Ranges/FsRangeAddress.fs.js +235 -0
  145. package/fable_modules/FsSpreadsheet.4.1.0/Ranges/FsRangeBase.fs +93 -0
  146. package/fable_modules/FsSpreadsheet.4.1.0/Ranges/FsRangeBase.fs.js +91 -0
  147. package/fable_modules/FsSpreadsheet.4.1.0/Ranges/FsRangeColumn.fs +65 -0
  148. package/fable_modules/FsSpreadsheet.4.1.0/Ranges/FsRangeColumn.fs.js +74 -0
  149. package/fable_modules/FsSpreadsheet.4.1.0/Ranges/FsRangeRow.fs +22 -0
  150. package/fable_modules/FsSpreadsheet.4.1.0/Ranges/FsRangeRow.fs.js +40 -0
  151. package/fable_modules/FsSpreadsheet.4.1.0/SheetBuilder.fs +249 -0
  152. package/fable_modules/FsSpreadsheet.4.1.0/SheetBuilder.fs.js +325 -0
  153. package/fable_modules/FsSpreadsheet.4.1.0/Tables/FsTable.fs +455 -0
  154. package/fable_modules/FsSpreadsheet.4.1.0/Tables/FsTable.fs.js +310 -0
  155. package/fable_modules/FsSpreadsheet.4.1.0/Tables/FsTableField.fs +140 -0
  156. package/fable_modules/FsSpreadsheet.4.1.0/Tables/FsTableField.fs.js +173 -0
  157. package/fable_modules/FsSpreadsheet.4.1.0/Tables/FsTableRow.fs +6 -0
  158. package/fable_modules/FsSpreadsheet.4.1.0/Tables/FsTableRow.fs.js +17 -0
  159. package/fable_modules/FsSpreadsheet.4.1.0/obj/Debug/netstandard2.0/.NETStandard,Version=v2.0.AssemblyAttributes.fs +3 -0
  160. package/fable_modules/FsSpreadsheet.4.1.0/obj/Debug/netstandard2.0/FsSpreadsheet.AssemblyInfo.fs +19 -0
  161. package/fable_modules/FsSpreadsheet.4.1.0/obj/Release/netstandard2.0/.NETStandard,Version=v2.0.AssemblyAttributes.fs +3 -0
  162. package/fable_modules/FsSpreadsheet.4.1.0/obj/Release/netstandard2.0/FsSpreadsheet.AssemblyInfo.fs +19 -0
  163. package/fable_modules/Thoth.Json.10.1.0/Decode.fs +1366 -0
  164. package/fable_modules/Thoth.Json.10.1.0/Decode.fs.js +1798 -0
  165. package/fable_modules/Thoth.Json.10.1.0/Encode.fs +621 -0
  166. package/fable_modules/Thoth.Json.10.1.0/Encode.fs.js +472 -0
  167. package/fable_modules/Thoth.Json.10.1.0/Extra.fs +31 -0
  168. package/fable_modules/Thoth.Json.10.1.0/Extra.fs.js +8 -0
  169. package/fable_modules/Thoth.Json.10.1.0/Thoth.Json.fableproj +30 -0
  170. package/fable_modules/Thoth.Json.10.1.0/Types.fs +59 -0
  171. package/fable_modules/Thoth.Json.10.1.0/Types.fs.js +98 -0
  172. package/fable_modules/Thoth.Json.10.1.0/obj/Release/netstandard2.0/Thoth.Json.AssemblyInfo.fs +19 -0
  173. package/fable_modules/Thoth.Json.10.1.0/package.json +5 -0
  174. package/fable_modules/fable-library.4.1.4/Array.d.ts +120 -0
  175. package/fable_modules/fable-library.4.1.4/Array.js +1204 -0
  176. package/fable_modules/fable-library.4.1.4/Async.d.ts +32 -0
  177. package/fable_modules/fable-library.4.1.4/Async.js +158 -0
  178. package/fable_modules/fable-library.4.1.4/AsyncBuilder.d.ts +59 -0
  179. package/fable_modules/fable-library.4.1.4/AsyncBuilder.js +183 -0
  180. package/fable_modules/fable-library.4.1.4/BigInt.d.ts +115 -0
  181. package/fable_modules/fable-library.4.1.4/BigInt.js +282 -0
  182. package/fable_modules/fable-library.4.1.4/BitConverter.d.ts +27 -0
  183. package/fable_modules/fable-library.4.1.4/BitConverter.js +138 -0
  184. package/fable_modules/fable-library.4.1.4/Boolean.d.ts +3 -0
  185. package/fable_modules/fable-library.4.1.4/Boolean.js +21 -0
  186. package/fable_modules/fable-library.4.1.4/Char.d.ts +65 -0
  187. package/fable_modules/fable-library.4.1.4/Char.js +169 -0
  188. package/fable_modules/fable-library.4.1.4/Choice.d.ts +138 -0
  189. package/fable_modules/fable-library.4.1.4/Choice.js +227 -0
  190. package/fable_modules/fable-library.4.1.4/Date.d.ts +70 -0
  191. package/fable_modules/fable-library.4.1.4/Date.js +451 -0
  192. package/fable_modules/fable-library.4.1.4/DateOffset.d.ts +63 -0
  193. package/fable_modules/fable-library.4.1.4/DateOffset.js +268 -0
  194. package/fable_modules/fable-library.4.1.4/DateOnly.d.ts +18 -0
  195. package/fable_modules/fable-library.4.1.4/DateOnly.js +124 -0
  196. package/fable_modules/fable-library.4.1.4/Decimal.d.ts +45 -0
  197. package/fable_modules/fable-library.4.1.4/Decimal.js +212 -0
  198. package/fable_modules/fable-library.4.1.4/Double.d.ts +11 -0
  199. package/fable_modules/fable-library.4.1.4/Double.js +46 -0
  200. package/fable_modules/fable-library.4.1.4/Encoding.d.ts +12 -0
  201. package/fable_modules/fable-library.4.1.4/Encoding.js +173 -0
  202. package/fable_modules/fable-library.4.1.4/Event.d.ts +31 -0
  203. package/fable_modules/fable-library.4.1.4/Event.js +93 -0
  204. package/fable_modules/fable-library.4.1.4/FSharp.Collections.d.ts +7 -0
  205. package/fable_modules/fable-library.4.1.4/FSharp.Collections.js +27 -0
  206. package/fable_modules/fable-library.4.1.4/FSharp.Core.d.ts +17 -0
  207. package/fable_modules/fable-library.4.1.4/FSharp.Core.js +69 -0
  208. package/fable_modules/fable-library.4.1.4/Global.d.ts +24 -0
  209. package/fable_modules/fable-library.4.1.4/Global.js +8 -0
  210. package/fable_modules/fable-library.4.1.4/Guid.d.ts +10 -0
  211. package/fable_modules/fable-library.4.1.4/Guid.js +142 -0
  212. package/fable_modules/fable-library.4.1.4/Int32.d.ts +28 -0
  213. package/fable_modules/fable-library.4.1.4/Int32.js +135 -0
  214. package/fable_modules/fable-library.4.1.4/List.d.ts +143 -0
  215. package/fable_modules/fable-library.4.1.4/List.js +1273 -0
  216. package/fable_modules/fable-library.4.1.4/Long.d.ts +3 -0
  217. package/fable_modules/fable-library.4.1.4/Long.js +46 -0
  218. package/fable_modules/fable-library.4.1.4/MailboxProcessor.d.ts +25 -0
  219. package/fable_modules/fable-library.4.1.4/MailboxProcessor.js +93 -0
  220. package/fable_modules/fable-library.4.1.4/Map.d.ts +178 -0
  221. package/fable_modules/fable-library.4.1.4/Map.js +1396 -0
  222. package/fable_modules/fable-library.4.1.4/MapUtil.d.ts +10 -0
  223. package/fable_modules/fable-library.4.1.4/MapUtil.js +112 -0
  224. package/fable_modules/fable-library.4.1.4/MutableMap.d.ts +52 -0
  225. package/fable_modules/fable-library.4.1.4/MutableMap.js +326 -0
  226. package/fable_modules/fable-library.4.1.4/MutableSet.d.ts +39 -0
  227. package/fable_modules/fable-library.4.1.4/MutableSet.js +232 -0
  228. package/fable_modules/fable-library.4.1.4/Native.d.ts +2 -0
  229. package/fable_modules/fable-library.4.1.4/Native.js +8 -0
  230. package/fable_modules/fable-library.4.1.4/Numeric.d.ts +19 -0
  231. package/fable_modules/fable-library.4.1.4/Numeric.js +71 -0
  232. package/fable_modules/fable-library.4.1.4/Observable.d.ts +32 -0
  233. package/fable_modules/fable-library.4.1.4/Observable.js +113 -0
  234. package/fable_modules/fable-library.4.1.4/Option.d.ts +28 -0
  235. package/fable_modules/fable-library.4.1.4/Option.js +96 -0
  236. package/fable_modules/fable-library.4.1.4/README.md +3 -0
  237. package/fable_modules/fable-library.4.1.4/Random.d.ts +37 -0
  238. package/fable_modules/fable-library.4.1.4/Random.js +170 -0
  239. package/fable_modules/fable-library.4.1.4/Range.d.ts +12 -0
  240. package/fable_modules/fable-library.4.1.4/Range.js +45 -0
  241. package/fable_modules/fable-library.4.1.4/Reflection.d.ts +119 -0
  242. package/fable_modules/fable-library.4.1.4/Reflection.js +461 -0
  243. package/fable_modules/fable-library.4.1.4/RegExp.d.ts +10 -0
  244. package/fable_modules/fable-library.4.1.4/RegExp.js +132 -0
  245. package/fable_modules/fable-library.4.1.4/Seq.d.ts +165 -0
  246. package/fable_modules/fable-library.4.1.4/Seq.js +1379 -0
  247. package/fable_modules/fable-library.4.1.4/Seq2.d.ts +18 -0
  248. package/fable_modules/fable-library.4.1.4/Seq2.js +111 -0
  249. package/fable_modules/fable-library.4.1.4/Set.d.ts +190 -0
  250. package/fable_modules/fable-library.4.1.4/Set.js +1789 -0
  251. package/fable_modules/fable-library.4.1.4/String.d.ts +49 -0
  252. package/fable_modules/fable-library.4.1.4/String.js +540 -0
  253. package/fable_modules/fable-library.4.1.4/System.Collections.Generic.d.ts +71 -0
  254. package/fable_modules/fable-library.4.1.4/System.Collections.Generic.js +307 -0
  255. package/fable_modules/fable-library.4.1.4/System.Text.d.ts +30 -0
  256. package/fable_modules/fable-library.4.1.4/System.Text.js +110 -0
  257. package/fable_modules/fable-library.4.1.4/SystemException.d.ts +5 -0
  258. package/fable_modules/fable-library.4.1.4/SystemException.js +5 -0
  259. package/fable_modules/fable-library.4.1.4/TimeOnly.d.ts +15 -0
  260. package/fable_modules/fable-library.4.1.4/TimeOnly.js +122 -0
  261. package/fable_modules/fable-library.4.1.4/TimeSpan.d.ts +34 -0
  262. package/fable_modules/fable-library.4.1.4/TimeSpan.js +177 -0
  263. package/fable_modules/fable-library.4.1.4/Timer.d.ts +19 -0
  264. package/fable_modules/fable-library.4.1.4/Timer.js +67 -0
  265. package/fable_modules/fable-library.4.1.4/Types.d.ts +58 -0
  266. package/fable_modules/fable-library.4.1.4/Types.js +208 -0
  267. package/fable_modules/fable-library.4.1.4/Unicode.13.0.0.d.ts +2 -0
  268. package/fable_modules/fable-library.4.1.4/Unicode.13.0.0.js +4 -0
  269. package/fable_modules/fable-library.4.1.4/Uri.d.ts +29 -0
  270. package/fable_modules/fable-library.4.1.4/Uri.js +142 -0
  271. package/fable_modules/fable-library.4.1.4/Util.d.ts +187 -0
  272. package/fable_modules/fable-library.4.1.4/Util.js +662 -0
  273. package/fable_modules/fable-library.4.1.4/lib/big.d.ts +338 -0
  274. package/fable_modules/fable-library.4.1.4/lib/big.js +826 -0
  275. package/fable_modules/fable-library.4.1.4/package.json +23 -0
  276. package/fable_modules/project_cracked.json +1 -0
  277. package/package.json +22 -0
@@ -0,0 +1,1366 @@
1
+
2
+ namespace Thoth.Json
3
+ open System.Text.RegularExpressions
4
+
5
+ [<RequireQualifiedAccess>]
6
+ module Decode =
7
+
8
+ open System.Globalization
9
+ open Fable.Core
10
+ open Fable.Core.JsInterop
11
+
12
+ module Helpers =
13
+ [<Emit("typeof $0")>]
14
+ let jsTypeof (_ : JsonValue) : string = jsNative
15
+
16
+ [<Emit("$0 instanceof SyntaxError")>]
17
+ let isSyntaxError (_ : JsonValue) : bool = jsNative
18
+
19
+ let inline getField (fieldName: string) (o: JsonValue) = o?(fieldName)
20
+ let inline isString (o: JsonValue) : bool = o :? string
21
+
22
+ let inline isBoolean (o: JsonValue) : bool = o :? bool
23
+
24
+ let inline isNumber (o: JsonValue) : bool = jsTypeof o = "number"
25
+
26
+ let inline isArray (o: JsonValue) : bool = JS.Constructors.Array.isArray(o)
27
+
28
+ [<Emit("$0 === null ? false : (Object.getPrototypeOf($0 || false) === Object.prototype)")>]
29
+ let isObject (_ : JsonValue) : bool = jsNative
30
+
31
+ let inline isNaN (o: JsonValue) : bool = JS.Constructors.Number.isNaN(!!o)
32
+
33
+ let inline isNullValue (o: JsonValue): bool = isNull o
34
+
35
+ /// is the value an integer? This returns false for 1.1, NaN, Infinite, ...
36
+ [<Emit("isFinite($0) && Math.floor($0) === $0")>]
37
+ let isIntegralValue (_: JsonValue) : bool = jsNative
38
+
39
+ [<Emit("$1 <= $0 && $0 < $2")>]
40
+ let isBetweenInclusive(_v: JsonValue, _min: obj, _max: obj) = jsNative
41
+
42
+ [<Emit("isFinite($0) && !($0 % 1)")>]
43
+ let isIntFinite (_: JsonValue) : bool = jsNative
44
+
45
+ let isUndefined (o: JsonValue): bool = jsTypeof o = "undefined"
46
+
47
+ [<Emit("JSON.stringify($0, null, 4) + ''")>]
48
+ let anyToString (_: JsonValue) : string = jsNative
49
+
50
+ let inline isFunction (o: JsonValue) : bool = jsTypeof o = "function"
51
+
52
+ let inline objectKeys (o: JsonValue) : string seq = upcast JS.Constructors.Object.keys(o)
53
+ let inline asBool (o: JsonValue): bool = unbox o
54
+ let inline asInt (o: JsonValue): int = unbox o
55
+ let inline asFloat (o: JsonValue): float = unbox o
56
+ let inline asFloat32 (o: JsonValue): float32 = unbox o
57
+ let inline asString (o: JsonValue): string = unbox o
58
+ let inline asArray (o: JsonValue): JsonValue[] = unbox o
59
+
60
+ let private genericMsg msg value newLine =
61
+ try
62
+ "Expecting "
63
+ + msg
64
+ + " but instead got:"
65
+ + (if newLine then "\n" else " ")
66
+ + (Helpers.anyToString value)
67
+ with
68
+ | _ ->
69
+ "Expecting "
70
+ + msg
71
+ + " but decoder failed. Couldn't report given value due to circular structure."
72
+ + (if newLine then "\n" else " ")
73
+
74
+ let private errorToString (path : string, error) =
75
+ let reason =
76
+ match error with
77
+ | BadPrimitive (msg, value) ->
78
+ genericMsg msg value false
79
+ | BadType (msg, value) ->
80
+ genericMsg msg value true
81
+ | BadPrimitiveExtra (msg, value, reason) ->
82
+ genericMsg msg value false + "\nReason: " + reason
83
+ | BadField (msg, value) ->
84
+ genericMsg msg value true
85
+ | BadPath (msg, value, fieldName) ->
86
+ genericMsg msg value true + ("\nNode `" + fieldName + "` is unkown.")
87
+ | TooSmallArray (msg, value) ->
88
+ "Expecting " + msg + ".\n" + (Helpers.anyToString value)
89
+ | BadOneOf messages ->
90
+ "The following errors were found:\n\n" + String.concat "\n\n" messages
91
+ | FailMessage msg ->
92
+ "The following `failure` occurred with the decoder: " + msg
93
+
94
+ match error with
95
+ | BadOneOf _ ->
96
+ // Don't need to show the path here because each error case will show it's own path
97
+ reason
98
+ | _ ->
99
+ "Error at: `" + path + "`\n" + reason
100
+
101
+ ///////////////
102
+ // Runners ///
103
+ /////////////
104
+
105
+ /// <summary>
106
+ /// Runs the decoder against the given JSON value.
107
+ ///
108
+ /// If the decoder fails, it reports the error prefixed with the given path.
109
+ ///
110
+ /// </summary>
111
+ /// <example>
112
+ /// <code lang="fsharp">
113
+ /// module Decode =
114
+ /// let fromRootValue (decoder : Decoder&lt;'T&gt;) =
115
+ /// Decode.fromValue "$" decoder
116
+ /// </code>
117
+ /// </example>
118
+ /// <param name="path">Path used to report the error</param>
119
+ /// <param name="decoder">Decoder to apply</param>
120
+ /// <param name="value">JSON value to decoder</param>
121
+ /// <returns>
122
+ /// Returns <c>Ok</c> if the decoder succeeds, otherwise <c>Error</c> with the error message.
123
+ /// </returns>
124
+ let fromValue (path : string) (decoder : Decoder<'T>) =
125
+ fun value ->
126
+ match decoder path value with
127
+ | Ok success ->
128
+ Ok success
129
+ | Error error ->
130
+ Error (errorToString error)
131
+
132
+ /// <summary>
133
+ /// Parse the provided string in as JSON and then run the decoder against it.
134
+ /// </summary>
135
+ /// <param name="decoder">Decoder to apply</param>
136
+ /// <param name="value">JSON string to decode</param>
137
+ /// <returns>
138
+ /// Returns <c>Ok</c> if the decoder succeeds, otherwise <c>Error</c> with the error message.
139
+ /// </returns>
140
+ let fromString (decoder : Decoder<'T>) =
141
+ fun value ->
142
+ try
143
+ let json = JS.JSON.parse value
144
+ fromValue "$" decoder json
145
+ with
146
+ | ex when Helpers.isSyntaxError ex ->
147
+ Error("Given an invalid JSON: " + ex.Message)
148
+
149
+ /// <summary>
150
+ /// Parse the provided string in as JSON and then run the decoder against it.
151
+ /// </summary>
152
+ /// <param name="decoder">Decoder to apply</param>
153
+ /// <param name="value">JSON string to decode</param>
154
+ /// <returns>
155
+ /// Return the decoded value if the decoder succeeds, otherwise throws an exception.
156
+ /// </returns>
157
+ let unsafeFromString (decoder : Decoder<'T>) =
158
+ fun value ->
159
+ match fromString decoder value with
160
+ | Ok x -> x
161
+ | Error msg -> failwith msg
162
+
163
+ [<System.Obsolete("Please use fromValue instead")>]
164
+ let decodeValue (path : string) (decoder : Decoder<'T>) = fromValue path decoder
165
+
166
+ [<System.Obsolete("Please use fromString instead")>]
167
+ let decodeString (decoder : Decoder<'T>) = fromString decoder
168
+
169
+ //////////////////
170
+ // Primitives ///
171
+ ////////////////
172
+
173
+ let string : Decoder<string> =
174
+ fun path value ->
175
+ if Helpers.isString value then
176
+ Ok(Helpers.asString value)
177
+ else
178
+ (path, BadPrimitive("a string", value)) |> Error
179
+
180
+ let char : Decoder<char> =
181
+ fun path value ->
182
+ if Helpers.isString value then
183
+ let str = Helpers.asString value
184
+ if str.Length = 1 then
185
+ Ok(str.[0])
186
+ else
187
+ (path, BadPrimitive("a single character string", value)) |> Error
188
+ else
189
+ (path, BadPrimitive("a char", value)) |> Error
190
+
191
+ let guid : Decoder<System.Guid> =
192
+ fun path value ->
193
+ if Helpers.isString value then
194
+ match System.Guid.TryParse (Helpers.asString value) with
195
+ | true, x -> Ok x
196
+ | _ -> (path, BadPrimitive("a guid", value)) |> Error
197
+ else (path, BadPrimitive("a guid", value)) |> Error
198
+
199
+ let unit : Decoder<unit> =
200
+ fun path value ->
201
+ if Helpers.isNullValue value then
202
+ Ok ()
203
+ else
204
+ (path, BadPrimitive("null", value)) |> Error
205
+
206
+ let inline private integral
207
+ (name : string)
208
+ (tryParse : (string -> bool * 'T))
209
+ (min : unit->'T)
210
+ (max : unit->'T)
211
+ (conv : float -> 'T) : Decoder< 'T > =
212
+
213
+ fun path value ->
214
+ if Helpers.isNumber value then
215
+ let value : float = unbox value
216
+ if Helpers.isIntegralValue value then
217
+ if (float(min())) <= value && value <= (float(max())) then
218
+ Ok(conv value)
219
+ else
220
+ (path, BadPrimitiveExtra(name, value, "Value was either too large or too small for " + name)) |> Error
221
+ else
222
+ (path, BadPrimitiveExtra(name, value, "Value is not an integral value")) |> Error
223
+ elif Helpers.isString value then
224
+ match tryParse (Helpers.asString value) with
225
+ | true, x -> Ok x
226
+ | _ -> (path, BadPrimitive(name, value)) |> Error
227
+ else
228
+ (path, BadPrimitive(name, value)) |> Error
229
+
230
+ let sbyte : Decoder<sbyte> =
231
+ integral
232
+ "a sbyte"
233
+ System.SByte.TryParse
234
+ (fun () -> System.SByte.MinValue)
235
+ (fun () -> System.SByte.MaxValue)
236
+ sbyte
237
+
238
+ /// Alias to Decode.uint8
239
+ let byte : Decoder<byte> =
240
+ integral
241
+ "a byte"
242
+ System.Byte.TryParse
243
+ (fun () -> System.Byte.MinValue)
244
+ (fun () -> System.Byte.MaxValue)
245
+ byte
246
+
247
+ let int16 : Decoder<int16> =
248
+ integral
249
+ "an int16"
250
+ System.Int16.TryParse
251
+ (fun () -> System.Int16.MinValue)
252
+ (fun () -> System.Int16.MaxValue)
253
+ int16
254
+
255
+ let uint16 : Decoder<uint16> =
256
+ integral
257
+ "an uint16"
258
+ System.UInt16.TryParse
259
+ (fun () -> System.UInt16.MinValue)
260
+ (fun () -> System.UInt16.MaxValue)
261
+ uint16
262
+
263
+ let int : Decoder<int> =
264
+ integral
265
+ "an int"
266
+ System.Int32.TryParse
267
+ (fun () -> System.Int32.MinValue)
268
+ (fun () -> System.Int32.MaxValue)
269
+ int
270
+
271
+ let uint32 : Decoder<uint32> =
272
+ integral
273
+ "an uint32"
274
+ System.UInt32.TryParse
275
+ (fun () -> System.UInt32.MinValue)
276
+ (fun () -> System.UInt32.MaxValue)
277
+ uint32
278
+
279
+ let int64 : Decoder<int64> =
280
+ integral
281
+ "an int64"
282
+ System.Int64.TryParse
283
+ (fun () -> System.Int64.MinValue)
284
+ (fun () -> System.Int64.MaxValue)
285
+ int64
286
+
287
+ let uint64 : Decoder<uint64> =
288
+ integral
289
+ "an uint64"
290
+ System.UInt64.TryParse
291
+ (fun () -> System.UInt64.MinValue)
292
+ (fun () -> System.UInt64.MaxValue)
293
+ uint64
294
+
295
+ let bigint : Decoder<bigint> =
296
+ fun path value ->
297
+ if Helpers.isNumber value then
298
+ Helpers.asInt value |> bigint |> Ok
299
+ elif Helpers.isString value then
300
+ // TODO: BigInt.TryParse has been added in Fable 2.1.4
301
+ // Don't use it for now to support lower Fable versions
302
+ try
303
+ bigint.Parse (Helpers.asString value) |> Ok
304
+ with _ ->
305
+ (path, BadPrimitive("a bigint", value)) |> Error
306
+ else
307
+ (path, BadPrimitive("a bigint", value)) |> Error
308
+
309
+ let bool : Decoder<bool> =
310
+ fun path value ->
311
+ if Helpers.isBoolean value then
312
+ Ok(Helpers.asBool value)
313
+ else
314
+ (path, BadPrimitive("a boolean", value)) |> Error
315
+
316
+ let float : Decoder<float> =
317
+ fun path value ->
318
+ if Helpers.isNumber value then
319
+ Ok(Helpers.asFloat value)
320
+ else
321
+ (path, BadPrimitive("a float", value)) |> Error
322
+
323
+ let float32 : Decoder<float32> =
324
+ fun path value ->
325
+ if Helpers.isNumber value then
326
+ Ok(Helpers.asFloat32 value)
327
+ else
328
+ (path, BadPrimitive("a float32", value)) |> Error
329
+
330
+ let decimal : Decoder<decimal> =
331
+ fun path value ->
332
+ if Helpers.isNumber value then
333
+ Helpers.asFloat value |> decimal |> Ok
334
+ elif Helpers.isString value then
335
+ match System.Decimal.TryParse (Helpers.asString value) with
336
+ | true, x -> Ok x
337
+ | _ -> (path, BadPrimitive("a decimal", value)) |> Error
338
+ else
339
+ (path, BadPrimitive("a decimal", value)) |> Error
340
+
341
+ [<System.Obsolete("Please use datetimeUtc instead.")>]
342
+ let datetime : Decoder<System.DateTime> =
343
+ fun path value ->
344
+ if Helpers.isString value then
345
+ match System.DateTime.TryParse (Helpers.asString value) with
346
+ | true, x -> x.ToUniversalTime() |> Ok
347
+ | _ -> (path, BadPrimitive("a datetime", value)) |> Error
348
+ else
349
+ (path, BadPrimitive("a datetime", value)) |> Error
350
+
351
+ /// Decode a System.DateTime value using Sytem.DateTime.TryParse, then convert it to UTC.
352
+ let datetimeUtc : Decoder<System.DateTime> =
353
+ fun path value ->
354
+ if Helpers.isString value then
355
+ match System.DateTime.TryParse (Helpers.asString value) with
356
+ | true, x -> x.ToUniversalTime() |> Ok
357
+ | _ -> (path, BadPrimitive("a datetime", value)) |> Error
358
+ else
359
+ (path, BadPrimitive("a datetime", value)) |> Error
360
+
361
+ /// Decode a System.DateTime with DateTime.TryParse; uses default System.DateTimeStyles.
362
+ let datetimeLocal : Decoder<System.DateTime> =
363
+ fun path value ->
364
+ if Helpers.isString value then
365
+ match System.DateTime.TryParse (Helpers.asString value) with
366
+ | true, x -> x |> Ok
367
+ | _ -> (path, BadPrimitive("a datetime", value)) |> Error
368
+ else
369
+ (path, BadPrimitive("a datetime", value)) |> Error
370
+
371
+ let datetimeOffset : Decoder<System.DateTimeOffset> =
372
+ fun path value ->
373
+ if Helpers.isString value then
374
+ match System.DateTimeOffset.TryParse(Helpers.asString value) with
375
+ | true, x -> Ok x
376
+ | _ -> (path, BadPrimitive("a datetimeoffset", value)) |> Error
377
+ else
378
+ (path, BadPrimitive("a datetime", value)) |> Error
379
+
380
+ let timespan : Decoder<System.TimeSpan> =
381
+ fun path value ->
382
+ if Helpers.isString value then
383
+ match System.TimeSpan.TryParse(Helpers.asString value) with
384
+ | true, x -> Ok x
385
+ | _ -> (path, BadPrimitive("a timespan", value)) |> Error
386
+ else
387
+ (path, BadPrimitive("a timespan", value)) |> Error
388
+
389
+ /////////////////////////
390
+ // Object primitives ///
391
+ ///////////////////////
392
+
393
+ let private decodeMaybeNull path (decoder : Decoder<'T>) value =
394
+ // The decoder may be an option decoder so give it an opportunity to check null values
395
+
396
+ // We catch the null value case first to avoid executing the decoder logic
397
+ // Indeed, if the decoder logic try to access the value to do something with it,
398
+ // it can throw an exception about the value being null
399
+ if Helpers.isNullValue value then
400
+ Ok None
401
+ else
402
+ match decoder path value with
403
+ | Ok v -> Ok(Some v)
404
+ | Error er -> Error er
405
+
406
+ let optional (fieldName : string) (decoder : Decoder<'value>) : Decoder<'value option> =
407
+ fun path value ->
408
+ if Helpers.isObject value then
409
+ let fieldValue = Helpers.getField fieldName value
410
+ if Helpers.isUndefined fieldValue then Ok None
411
+ else decodeMaybeNull (path + "." + fieldName) decoder fieldValue
412
+ else
413
+ Error(path, BadType("an object", value))
414
+
415
+ let private badPathError fieldNames currentPath value =
416
+ let currentPath = defaultArg currentPath ("$"::fieldNames |> String.concat ".")
417
+ let msg = "an object with path `" + (String.concat "." fieldNames) + "`"
418
+ Error(currentPath, BadPath (msg, value, List.tryLast fieldNames |> Option.defaultValue ""))
419
+
420
+ let optionalAt (fieldNames : string list) (decoder : Decoder<'value>) : Decoder<'value option> =
421
+ fun firstPath firstValue ->
422
+ ((firstPath, firstValue, None), fieldNames)
423
+ ||> List.fold (fun (curPath, curValue, res) field ->
424
+ match res with
425
+ | Some _ -> curPath, curValue, res
426
+ | None ->
427
+ if Helpers.isNullValue curValue then
428
+ curPath, curValue, Some (Ok None)
429
+ elif Helpers.isObject curValue then
430
+ let curValue = Helpers.getField field curValue
431
+ curPath + "." + field, curValue, None
432
+ else
433
+ let res = Error(curPath, BadType("an object", curValue))
434
+ curPath, curValue, Some res)
435
+ |> function
436
+ | _, _, Some res -> res
437
+ | lastPath, lastValue, None ->
438
+ if Helpers.isUndefined lastValue then Ok None
439
+ else decodeMaybeNull lastPath decoder lastValue
440
+
441
+ let field (fieldName: string) (decoder : Decoder<'value>) : Decoder<'value> =
442
+ fun path value ->
443
+ if Helpers.isObject value then
444
+ let fieldValue = Helpers.getField fieldName value
445
+ if Helpers.isUndefined fieldValue then
446
+ Error(path, BadField ("an object with a field named `" + fieldName + "`", value))
447
+ else
448
+ decoder (path + "." + fieldName) fieldValue
449
+ else
450
+ Error(path, BadType("an object", value))
451
+
452
+ let at (fieldNames: string list) (decoder : Decoder<'value>) : Decoder<'value> =
453
+ fun firstPath firstValue ->
454
+ ((firstPath, firstValue, None), fieldNames)
455
+ ||> List.fold (fun (curPath, curValue, res) field ->
456
+ match res with
457
+ | Some _ -> curPath, curValue, res
458
+ | None ->
459
+ if Helpers.isNullValue curValue then
460
+ let res = badPathError fieldNames (Some curPath) firstValue
461
+ curPath, curValue, Some res
462
+ elif Helpers.isObject curValue then
463
+ let curValue = Helpers.getField field curValue
464
+ if Helpers.isUndefined curValue then
465
+ let res = badPathError fieldNames None firstValue
466
+ curPath, curValue, Some res
467
+ else
468
+ curPath + "." + field, curValue, None
469
+ else
470
+ let res = Error(curPath, BadType("an object", curValue))
471
+ curPath, curValue, Some res)
472
+ |> function
473
+ | _, _, Some res -> res
474
+ | lastPath, lastValue, None ->
475
+ decoder lastPath lastValue
476
+
477
+ let index (requestedIndex: int) (decoder : Decoder<'value>) : Decoder<'value> =
478
+ fun path value ->
479
+ let currentPath = path + ".[" + (Operators.string requestedIndex) + "]"
480
+ if Helpers.isArray value then
481
+ let vArray = Helpers.asArray value
482
+ if requestedIndex < vArray.Length then
483
+ decoder currentPath (vArray.[requestedIndex])
484
+ else
485
+ let msg =
486
+ "a longer array. Need index `"
487
+ + (requestedIndex.ToString())
488
+ + "` but there are only `"
489
+ + (vArray.Length.ToString())
490
+ + "` entries"
491
+
492
+ (currentPath, TooSmallArray(msg, value))
493
+ |> Error
494
+ else
495
+ (currentPath, BadPrimitive("an array", value))
496
+ |> Error
497
+
498
+ let option (decoder : Decoder<'value>) : Decoder<'value option> =
499
+ fun path value ->
500
+ if Helpers.isNullValue value then Ok None
501
+ else decoder path value |> Result.map Some
502
+
503
+ //////////////////////
504
+ // Data structure ///
505
+ ////////////////////
506
+
507
+ let list (decoder : Decoder<'value>) : Decoder<'value list> =
508
+ fun path value ->
509
+ if Helpers.isArray value then
510
+ let mutable i = -1
511
+ let tokens = Helpers.asArray value
512
+ (Ok [], tokens) ||> Array.fold (fun acc value ->
513
+ i <- i + 1
514
+ match acc with
515
+ | Error _ -> acc
516
+ | Ok acc ->
517
+ match decoder (path + ".[" + (i.ToString()) + "]") value with
518
+ | Error er -> Error er
519
+ | Ok value -> Ok (value::acc))
520
+ |> Result.map List.rev
521
+ else
522
+ (path, BadPrimitive ("a list", value))
523
+ |> Error
524
+
525
+ let seq (decoder : Decoder<'value>) : Decoder<'value seq> =
526
+ fun path value ->
527
+ if Helpers.isArray value then
528
+ let mutable i = -1
529
+ let tokens = Helpers.asArray value
530
+ (Ok (seq []), tokens) ||> Array.fold (fun acc value ->
531
+ i <- i + 1
532
+ match acc with
533
+ | Error _ -> acc
534
+ | Ok acc ->
535
+ match decoder (path + ".[" + (i.ToString()) + "]") value with
536
+ | Error er -> Error er
537
+ | Ok value -> Ok (Seq.append [value] acc))
538
+ |> Result.map Seq.rev
539
+ else
540
+ (path, BadPrimitive ("a seq", value))
541
+ |> Error
542
+
543
+ let array (decoder : Decoder<'value>) : Decoder<'value array> =
544
+ fun path value ->
545
+ if Helpers.isArray value then
546
+ let mutable i = -1
547
+ let tokens = Helpers.asArray value
548
+ let arr = Array.zeroCreate tokens.Length
549
+ (Ok arr, tokens) ||> Array.fold (fun acc value ->
550
+ i <- i + 1
551
+ match acc with
552
+ | Error _ -> acc
553
+ | Ok acc ->
554
+ match decoder (path + ".[" + (i.ToString()) + "]") value with
555
+ | Error er -> Error er
556
+ | Ok value -> acc.[i] <- value; Ok acc)
557
+ else
558
+ (path, BadPrimitive ("an array", value))
559
+ |> Error
560
+
561
+ let keys: Decoder<string list> =
562
+ fun path value ->
563
+ if Helpers.isObject value then
564
+ Helpers.objectKeys value |> List.ofSeq |> Ok
565
+ else
566
+ (path, BadPrimitive ("an object", value))
567
+ |> Error
568
+
569
+ let keyValuePairs (decoder : Decoder<'value>) : Decoder<(string * 'value) list> =
570
+ fun path value ->
571
+ match keys path value with
572
+ | Ok objectKeys ->
573
+ (Ok [], objectKeys) ||> List.fold (fun acc prop ->
574
+ match acc with
575
+ | Error _ -> acc
576
+ | Ok acc ->
577
+ match Helpers.getField prop value |> decoder path with
578
+ | Error er -> Error er
579
+ | Ok value -> (prop, value)::acc |> Ok)
580
+ |> Result.map List.rev
581
+ | Error e -> Error e
582
+
583
+ //////////////////////////////
584
+ // Inconsistent Structure ///
585
+ ////////////////////////////
586
+
587
+ let oneOf (decoders : Decoder<'value> list) : Decoder<'value> =
588
+ fun path value ->
589
+ let rec runner (decoders : Decoder<'value> list) (errors : string list) =
590
+ match decoders with
591
+ | head::tail ->
592
+ match fromValue path head value with
593
+ | Ok v ->
594
+ Ok v
595
+ | Error error -> runner tail (errors @ [error])
596
+ | [] -> (path, BadOneOf errors) |> Error
597
+
598
+ runner decoders []
599
+
600
+ //////////////////////
601
+ // Fancy decoding ///
602
+ ////////////////////
603
+
604
+ let nil (output : 'a) : Decoder<'a> =
605
+ fun path value ->
606
+ if Helpers.isNullValue value then
607
+ Ok output
608
+ else
609
+ (path, BadPrimitive("null", value)) |> Error
610
+
611
+ let value _ v = Ok v
612
+
613
+ let succeed (output : 'a) : Decoder<'a> =
614
+ fun _ _ ->
615
+ Ok output
616
+
617
+ let fail (msg: string) : Decoder<'a> =
618
+ fun path _ ->
619
+ (path, FailMessage msg) |> Error
620
+
621
+ let andThen (cb: 'a -> Decoder<'b>) (decoder : Decoder<'a>) : Decoder<'b> =
622
+ fun path value ->
623
+ match decoder path value with
624
+ | Error error -> Error error
625
+ | Ok result -> cb result path value
626
+
627
+ let all (decoders: Decoder<'a> list): Decoder<'a list> =
628
+ fun path value ->
629
+ let rec runner (decoders: Decoder<'a> list) (values: 'a list) =
630
+ match decoders with
631
+ | decoder :: tail ->
632
+ match decoder path value with
633
+ | Ok value -> runner tail (values @ [ value ])
634
+ | Error error -> Error error
635
+ | [] -> Ok values
636
+
637
+ runner decoders []
638
+
639
+ /////////////////////
640
+ // Map functions ///
641
+ ///////////////////
642
+
643
+ let map
644
+ (ctor : 'a -> 'value)
645
+ (d1 : Decoder<'a>) : Decoder<'value> =
646
+ fun path value ->
647
+ match d1 path value with
648
+ | Ok v1 -> Ok (ctor v1)
649
+ | Error er -> Error er
650
+
651
+ let map2
652
+ (ctor : 'a -> 'b -> 'value)
653
+ (d1 : Decoder<'a>)
654
+ (d2 : Decoder<'b>) : Decoder<'value> =
655
+ fun path value ->
656
+ match d1 path value, d2 path value with
657
+ | Ok v1, Ok v2 -> Ok (ctor v1 v2)
658
+ | Error er,_ -> Error er
659
+ | _,Error er -> Error er
660
+
661
+ let map3
662
+ (ctor : 'a -> 'b -> 'c -> 'value)
663
+ (d1 : Decoder<'a>)
664
+ (d2 : Decoder<'b>)
665
+ (d3 : Decoder<'c>) : Decoder<'value> =
666
+ fun path value ->
667
+ match d1 path value, d2 path value, d3 path value with
668
+ | Ok v1, Ok v2, Ok v3 -> Ok (ctor v1 v2 v3)
669
+ | Error er,_,_ -> Error er
670
+ | _,Error er,_ -> Error er
671
+ | _,_,Error er -> Error er
672
+
673
+ let map4
674
+ (ctor : 'a -> 'b -> 'c -> 'd -> 'value)
675
+ (d1 : Decoder<'a>)
676
+ (d2 : Decoder<'b>)
677
+ (d3 : Decoder<'c>)
678
+ (d4 : Decoder<'d>) : Decoder<'value> =
679
+ fun path value ->
680
+ match d1 path value, d2 path value, d3 path value, d4 path value with
681
+ | Ok v1, Ok v2, Ok v3, Ok v4 -> Ok (ctor v1 v2 v3 v4)
682
+ | Error er,_,_,_ -> Error er
683
+ | _,Error er,_,_ -> Error er
684
+ | _,_,Error er,_ -> Error er
685
+ | _,_,_,Error er -> Error er
686
+
687
+ let map5
688
+ (ctor : 'a -> 'b -> 'c -> 'd -> 'e -> 'value)
689
+ (d1 : Decoder<'a>)
690
+ (d2 : Decoder<'b>)
691
+ (d3 : Decoder<'c>)
692
+ (d4 : Decoder<'d>)
693
+ (d5 : Decoder<'e>) : Decoder<'value> =
694
+ fun path value ->
695
+ match d1 path value, d2 path value, d3 path value, d4 path value, d5 path value with
696
+ | Ok v1, Ok v2, Ok v3, Ok v4, Ok v5 -> Ok (ctor v1 v2 v3 v4 v5)
697
+ | Error er,_,_,_,_ -> Error er
698
+ | _,Error er,_,_,_ -> Error er
699
+ | _,_,Error er,_,_ -> Error er
700
+ | _,_,_,Error er,_ -> Error er
701
+ | _,_,_,_,Error er -> Error er
702
+
703
+ let map6
704
+ (ctor : 'a -> 'b -> 'c -> 'd -> 'e -> 'f -> 'value)
705
+ (d1 : Decoder<'a>)
706
+ (d2 : Decoder<'b>)
707
+ (d3 : Decoder<'c>)
708
+ (d4 : Decoder<'d>)
709
+ (d5 : Decoder<'e>)
710
+ (d6 : Decoder<'f>) : Decoder<'value> =
711
+ fun path value ->
712
+ match d1 path value, d2 path value, d3 path value, d4 path value, d5 path value, d6 path value with
713
+ | Ok v1, Ok v2, Ok v3, Ok v4, Ok v5, Ok v6 -> Ok (ctor v1 v2 v3 v4 v5 v6)
714
+ | Error er,_,_,_,_,_ -> Error er
715
+ | _,Error er,_,_,_,_ -> Error er
716
+ | _,_,Error er,_,_,_ -> Error er
717
+ | _,_,_,Error er,_,_ -> Error er
718
+ | _,_,_,_,Error er,_ -> Error er
719
+ | _,_,_,_,_,Error er -> Error er
720
+
721
+ let map7
722
+ (ctor : 'a -> 'b -> 'c -> 'd -> 'e -> 'f -> 'g -> 'value)
723
+ (d1 : Decoder<'a>)
724
+ (d2 : Decoder<'b>)
725
+ (d3 : Decoder<'c>)
726
+ (d4 : Decoder<'d>)
727
+ (d5 : Decoder<'e>)
728
+ (d6 : Decoder<'f>)
729
+ (d7 : Decoder<'g>) : Decoder<'value> =
730
+ fun path value ->
731
+ match d1 path value, d2 path value, d3 path value, d4 path value, d5 path value, d6 path value, d7 path value with
732
+ | Ok v1, Ok v2, Ok v3, Ok v4, Ok v5, Ok v6, Ok v7 -> Ok (ctor v1 v2 v3 v4 v5 v6 v7)
733
+ | Error er,_,_,_,_,_,_ -> Error er
734
+ | _,Error er,_,_,_,_,_ -> Error er
735
+ | _,_,Error er,_,_,_,_ -> Error er
736
+ | _,_,_,Error er,_,_,_ -> Error er
737
+ | _,_,_,_,Error er,_,_ -> Error er
738
+ | _,_,_,_,_,Error er,_ -> Error er
739
+ | _,_,_,_,_,_,Error er -> Error er
740
+
741
+ let map8
742
+ (ctor : 'a -> 'b -> 'c -> 'd -> 'e -> 'f -> 'g -> 'h -> 'value)
743
+ (d1 : Decoder<'a>)
744
+ (d2 : Decoder<'b>)
745
+ (d3 : Decoder<'c>)
746
+ (d4 : Decoder<'d>)
747
+ (d5 : Decoder<'e>)
748
+ (d6 : Decoder<'f>)
749
+ (d7 : Decoder<'g>)
750
+ (d8 : Decoder<'h>) : Decoder<'value> =
751
+ fun path value ->
752
+ match d1 path value, d2 path value, d3 path value, d4 path value, d5 path value, d6 path value, d7 path value, d8 path value with
753
+ | Ok v1, Ok v2, Ok v3, Ok v4, Ok v5, Ok v6, Ok v7, Ok v8 -> Ok (ctor v1 v2 v3 v4 v5 v6 v7 v8)
754
+ | Error er,_,_,_,_,_,_,_ -> Error er
755
+ | _,Error er,_,_,_,_,_,_ -> Error er
756
+ | _,_,Error er,_,_,_,_,_ -> Error er
757
+ | _,_,_,Error er,_,_,_,_ -> Error er
758
+ | _,_,_,_,Error er,_,_,_ -> Error er
759
+ | _,_,_,_,_,Error er,_,_ -> Error er
760
+ | _,_,_,_,_,_,Error er,_ -> Error er
761
+ | _,_,_,_,_,_,_,Error er -> Error er
762
+
763
+ //////////////////////
764
+ // Object builder ///
765
+ ////////////////////
766
+
767
+ /// <summary>
768
+ /// Allow to incrementally apply a decoder, for building large objects.
769
+ /// </summary>
770
+ /// <example>
771
+ /// <code lang="fsharp">
772
+ /// type Point =
773
+ /// {
774
+ /// X : float
775
+ /// Y : float
776
+ /// }
777
+ ///
778
+ /// module Point =
779
+ /// let create x y = { X = x; Y = y }
780
+ ///
781
+ /// let decode =
782
+ /// Decode.succeed create
783
+ /// |> Decode.andMap (Decode.field "x" Decode.float)
784
+ /// |> Decode.andMap (Decode.field "y" Decode.float)
785
+ /// </code>
786
+ /// </example>
787
+ let andMap<'a, 'b> : 'a Decoder -> ('a -> 'b) Decoder -> 'b Decoder =
788
+ map2 (|>)
789
+
790
+ type IRequiredGetter =
791
+ abstract Field : string -> Decoder<'a> -> 'a
792
+ abstract At : List<string> -> Decoder<'a> -> 'a
793
+ abstract Raw : Decoder<'a> -> 'a
794
+
795
+ type IOptionalGetter =
796
+ abstract Field : string -> Decoder<'a> -> 'a option
797
+ abstract At : List<string> -> Decoder<'a> -> 'a option
798
+ abstract Raw : Decoder<'a> -> 'a option
799
+
800
+ type IGetters =
801
+ abstract Required: IRequiredGetter
802
+ abstract Optional: IOptionalGetter
803
+
804
+ let private unwrapWith (errors: ResizeArray<DecoderError>) path (decoder: Decoder<'T>) value: 'T =
805
+ match decoder path value with
806
+ | Ok v -> v
807
+ | Error er -> errors.Add(er); Unchecked.defaultof<'T>
808
+
809
+ type Getters<'T>(path: string, v: 'T) =
810
+ let mutable errors = ResizeArray<DecoderError>()
811
+ let required =
812
+ { new IRequiredGetter with
813
+ member __.Field (fieldName : string) (decoder : Decoder<_>) =
814
+ unwrapWith errors path (field fieldName decoder) v
815
+ member __.At (fieldNames : string list) (decoder : Decoder<_>) =
816
+ unwrapWith errors path (at fieldNames decoder) v
817
+ member __.Raw (decoder: Decoder<_>) =
818
+ unwrapWith errors path decoder v }
819
+ let optional =
820
+ { new IOptionalGetter with
821
+ member __.Field (fieldName : string) (decoder : Decoder<_>) =
822
+ unwrapWith errors path (optional fieldName decoder) v
823
+ member __.At (fieldNames : string list) (decoder : Decoder<_>) =
824
+ unwrapWith errors path (optionalAt fieldNames decoder) v
825
+ member __.Raw (decoder: Decoder<_>) =
826
+ match decoder path v with
827
+ | Ok v -> Some v
828
+ | Error((_, reason) as error) ->
829
+ match reason with
830
+ | BadPrimitive(_,v)
831
+ | BadPrimitiveExtra(_,v,_)
832
+ | BadType(_,v) ->
833
+ if Helpers.isNullValue v then None
834
+ else errors.Add(error); Unchecked.defaultof<_>
835
+ | BadField _
836
+ | BadPath _ -> None
837
+ | TooSmallArray _
838
+ | FailMessage _
839
+ | BadOneOf _ -> errors.Add(error); Unchecked.defaultof<_> }
840
+ member __.Errors: _ list = Seq.toList errors
841
+ interface IGetters with
842
+ member __.Required = required
843
+ member __.Optional = optional
844
+
845
+ let object (builder: IGetters -> 'value) : Decoder<'value> =
846
+ fun path v ->
847
+ let getters = Getters(path, v)
848
+ let result = builder getters
849
+ match getters.Errors with
850
+ | [] -> Ok result
851
+ | fst::_ as errors ->
852
+ if errors.Length > 1 then
853
+ let errors = List.map errorToString errors
854
+ (path, BadOneOf errors) |> Error
855
+ else
856
+ Error fst
857
+
858
+ ///////////////////////
859
+ // Tuples decoders ///
860
+ ////////////////////
861
+
862
+ let tuple2 (decoder1: Decoder<'T1>) (decoder2: Decoder<'T2>) : Decoder<'T1 * 'T2> =
863
+ index 0 decoder1
864
+ |> andThen (fun v1 ->
865
+ index 1 decoder2
866
+ |> andThen (fun v2 ->
867
+ succeed (v1, v2)
868
+ )
869
+ )
870
+
871
+ let tuple3 (decoder1: Decoder<'T1>)
872
+ (decoder2: Decoder<'T2>)
873
+ (decoder3: Decoder<'T3>) : Decoder<'T1 * 'T2 * 'T3> =
874
+ index 0 decoder1
875
+ |> andThen (fun v1 ->
876
+ index 1 decoder2
877
+ |> andThen (fun v2 ->
878
+ index 2 decoder3
879
+ |> andThen (fun v3 ->
880
+ succeed (v1, v2, v3)
881
+ )
882
+ )
883
+ )
884
+
885
+ let tuple4 (decoder1: Decoder<'T1>)
886
+ (decoder2: Decoder<'T2>)
887
+ (decoder3: Decoder<'T3>)
888
+ (decoder4: Decoder<'T4>) : Decoder<'T1 * 'T2 * 'T3 * 'T4> =
889
+ index 0 decoder1
890
+ |> andThen (fun v1 ->
891
+ index 1 decoder2
892
+ |> andThen (fun v2 ->
893
+ index 2 decoder3
894
+ |> andThen (fun v3 ->
895
+ index 3 decoder4
896
+ |> andThen (fun v4 ->
897
+ succeed (v1, v2, v3, v4)
898
+ )
899
+ )
900
+ )
901
+ )
902
+
903
+ let tuple5 (decoder1: Decoder<'T1>)
904
+ (decoder2: Decoder<'T2>)
905
+ (decoder3: Decoder<'T3>)
906
+ (decoder4: Decoder<'T4>)
907
+ (decoder5: Decoder<'T5>) : Decoder<'T1 * 'T2 * 'T3 * 'T4 * 'T5> =
908
+ index 0 decoder1
909
+ |> andThen (fun v1 ->
910
+ index 1 decoder2
911
+ |> andThen (fun v2 ->
912
+ index 2 decoder3
913
+ |> andThen (fun v3 ->
914
+ index 3 decoder4
915
+ |> andThen (fun v4 ->
916
+ index 4 decoder5
917
+ |> andThen (fun v5 ->
918
+ succeed (v1, v2, v3, v4, v5)
919
+ )
920
+ )
921
+ )
922
+ )
923
+ )
924
+
925
+ let tuple6 (decoder1: Decoder<'T1>)
926
+ (decoder2: Decoder<'T2>)
927
+ (decoder3: Decoder<'T3>)
928
+ (decoder4: Decoder<'T4>)
929
+ (decoder5: Decoder<'T5>)
930
+ (decoder6: Decoder<'T6>) : Decoder<'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6> =
931
+ index 0 decoder1
932
+ |> andThen (fun v1 ->
933
+ index 1 decoder2
934
+ |> andThen (fun v2 ->
935
+ index 2 decoder3
936
+ |> andThen (fun v3 ->
937
+ index 3 decoder4
938
+ |> andThen (fun v4 ->
939
+ index 4 decoder5
940
+ |> andThen (fun v5 ->
941
+ index 5 decoder6
942
+ |> andThen (fun v6 ->
943
+ succeed (v1, v2, v3, v4, v5, v6)
944
+ )
945
+ )
946
+ )
947
+ )
948
+ )
949
+ )
950
+
951
+ let tuple7 (decoder1: Decoder<'T1>)
952
+ (decoder2: Decoder<'T2>)
953
+ (decoder3: Decoder<'T3>)
954
+ (decoder4: Decoder<'T4>)
955
+ (decoder5: Decoder<'T5>)
956
+ (decoder6: Decoder<'T6>)
957
+ (decoder7: Decoder<'T7>) : Decoder<'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7> =
958
+ index 0 decoder1
959
+ |> andThen (fun v1 ->
960
+ index 1 decoder2
961
+ |> andThen (fun v2 ->
962
+ index 2 decoder3
963
+ |> andThen (fun v3 ->
964
+ index 3 decoder4
965
+ |> andThen (fun v4 ->
966
+ index 4 decoder5
967
+ |> andThen (fun v5 ->
968
+ index 5 decoder6
969
+ |> andThen (fun v6 ->
970
+ index 6 decoder7
971
+ |> andThen (fun v7 ->
972
+ succeed (v1, v2, v3, v4, v5, v6, v7)
973
+ )
974
+ )
975
+ )
976
+ )
977
+ )
978
+ )
979
+ )
980
+
981
+ let tuple8 (decoder1: Decoder<'T1>)
982
+ (decoder2: Decoder<'T2>)
983
+ (decoder3: Decoder<'T3>)
984
+ (decoder4: Decoder<'T4>)
985
+ (decoder5: Decoder<'T5>)
986
+ (decoder6: Decoder<'T6>)
987
+ (decoder7: Decoder<'T7>)
988
+ (decoder8: Decoder<'T8>) : Decoder<'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8> =
989
+ index 0 decoder1
990
+ |> andThen (fun v1 ->
991
+ index 1 decoder2
992
+ |> andThen (fun v2 ->
993
+ index 2 decoder3
994
+ |> andThen (fun v3 ->
995
+ index 3 decoder4
996
+ |> andThen (fun v4 ->
997
+ index 4 decoder5
998
+ |> andThen (fun v5 ->
999
+ index 5 decoder6
1000
+ |> andThen (fun v6 ->
1001
+ index 6 decoder7
1002
+ |> andThen (fun v7 ->
1003
+ index 7 decoder8
1004
+ |> andThen (fun v8 ->
1005
+ succeed (v1, v2, v3, v4, v5, v6, v7, v8)
1006
+ )
1007
+ )
1008
+ )
1009
+ )
1010
+ )
1011
+ )
1012
+ )
1013
+ )
1014
+
1015
+ ///////////
1016
+ // Map ///
1017
+ /////////
1018
+
1019
+ let dict (decoder : Decoder<'value>) : Decoder<Map<string, 'value>> =
1020
+ map Map.ofList (keyValuePairs decoder)
1021
+
1022
+ let map' (keyDecoder : Decoder<'key>) (valueDecoder : Decoder<'value>) : Decoder<Map<'key, 'value>> =
1023
+ map Map.ofSeq (array (tuple2 keyDecoder valueDecoder))
1024
+
1025
+ ////////////
1026
+ // Enum ///
1027
+ /////////
1028
+
1029
+ #if !FABLE_REPL_LIB
1030
+ module Enum =
1031
+
1032
+ let inline byte<'TEnum when 'TEnum : enum<byte>> : Decoder<'TEnum> =
1033
+ byte
1034
+ |> andThen (fun value ->
1035
+ LanguagePrimitives.EnumOfValue<byte, 'TEnum> value
1036
+ |> succeed
1037
+ )
1038
+
1039
+ let inline sbyte<'TEnum when 'TEnum : enum<sbyte>> : Decoder<'TEnum> =
1040
+ sbyte
1041
+ |> andThen (fun value ->
1042
+ LanguagePrimitives.EnumOfValue<sbyte, 'TEnum> value
1043
+ |> succeed
1044
+ )
1045
+
1046
+ let inline int16<'TEnum when 'TEnum : enum<int16>> : Decoder<'TEnum> =
1047
+ int16
1048
+ |> andThen (fun value ->
1049
+ LanguagePrimitives.EnumOfValue<int16, 'TEnum> value
1050
+ |> succeed
1051
+ )
1052
+
1053
+ let inline uint16<'TEnum when 'TEnum : enum<uint16>> : Decoder<'TEnum> =
1054
+ uint16
1055
+ |> andThen (fun value ->
1056
+ LanguagePrimitives.EnumOfValue<uint16, 'TEnum> value
1057
+ |> succeed
1058
+ )
1059
+
1060
+ let inline int<'TEnum when 'TEnum : enum<int>> : Decoder<'TEnum> =
1061
+ int
1062
+ |> andThen (fun value ->
1063
+ LanguagePrimitives.EnumOfValue<int, 'TEnum> value
1064
+ |> succeed
1065
+ )
1066
+
1067
+ let inline uint32<'TEnum when 'TEnum : enum<uint32>> : Decoder<'TEnum> =
1068
+ uint32
1069
+ |> andThen (fun value ->
1070
+ LanguagePrimitives.EnumOfValue<uint32, 'TEnum> value
1071
+ |> succeed
1072
+ )
1073
+ #endif
1074
+
1075
+ //////////////////
1076
+ // Reflection ///
1077
+ ////////////////
1078
+
1079
+ open FSharp.Reflection
1080
+
1081
+ // As generics are erased by Fable, let's just do an unsafe cast for performance
1082
+ let inline boxDecoder (d: Decoder<'T>): BoxedDecoder =
1083
+ !!d // d >> Result.map box
1084
+
1085
+ let inline unboxDecoder (d: BoxedDecoder): Decoder<'T> =
1086
+ !!d // d >> Result.map unbox
1087
+
1088
+ // This is used to force Fable use a generic comparer for map keys
1089
+ let private toMap<'key, 'value when 'key: comparison> (xs: ('key*'value) seq) = Map.ofSeq xs
1090
+ let private toSet<'key when 'key: comparison> (xs: 'key seq) = Set.ofSeq xs
1091
+
1092
+ let private autoObject (decoderInfos: (string * BoxedDecoder)[]) (path : string) (value: JsonValue) =
1093
+ if not (Helpers.isObject value) then
1094
+ (path, BadPrimitive ("an object", value)) |> Error
1095
+ else
1096
+ (decoderInfos, Ok []) ||> Array.foldBack (fun (name, decoder) acc ->
1097
+ match acc with
1098
+ | Error _ -> acc
1099
+ | Ok result ->
1100
+ Helpers.getField name value
1101
+ |> decoder (path + "." + name)
1102
+ |> Result.map (fun v -> v::result))
1103
+
1104
+ let inline private enumDecoder<'UnderlineType when 'UnderlineType : equality>
1105
+ (decoder : Decoder<'UnderlineType>)
1106
+ (toString : 'UnderlineType -> string)
1107
+ (t: System.Type) =
1108
+
1109
+ fun path value ->
1110
+ match decoder path value with
1111
+ | Ok enumValue ->
1112
+ System.Enum.GetValues(t)
1113
+ |> Seq.cast<'UnderlineType>
1114
+ |> Seq.contains enumValue
1115
+ |> function
1116
+ | true ->
1117
+ System.Enum.Parse(t, toString enumValue)
1118
+ |> Ok
1119
+ | false ->
1120
+ (path, BadPrimitiveExtra(t.FullName, value, "Unkown value provided for the enum"))
1121
+ |> Error
1122
+ | Error msg ->
1123
+ Error msg
1124
+
1125
+ let private autoObject2 (keyDecoder: BoxedDecoder) (valueDecoder: BoxedDecoder) (path : string) (value: JsonValue) =
1126
+ if not (Helpers.isObject value) then
1127
+ (path, BadPrimitive ("an object", value)) |> Error
1128
+ else
1129
+ (Ok [], Helpers.objectKeys(value)) ||> Seq.fold (fun acc name ->
1130
+ match acc with
1131
+ | Error _ -> acc
1132
+ | Ok acc ->
1133
+ match keyDecoder path name with
1134
+ | Error er -> Error er
1135
+ | Ok k ->
1136
+ Helpers.getField name value
1137
+ |> valueDecoder (path + "." + name)
1138
+ |> function
1139
+ | Error er -> Error er
1140
+ | Ok v -> (k,v)::acc |> Ok)
1141
+
1142
+ let private mixedArray offset (decoders: BoxedDecoder[]) (path: string) (values: JsonValue[]): Result<JsonValue list, DecoderError> =
1143
+ let expectedLength = decoders.Length + offset
1144
+ if expectedLength <> values.Length then
1145
+ (path, sprintf "Expected array of length %i but got %i" expectedLength values.Length
1146
+ |> FailMessage) |> Error
1147
+ else
1148
+ let mutable result = Ok []
1149
+ for i = offset to values.Length - 1 do
1150
+ match result with
1151
+ | Error _ -> ()
1152
+ | Ok acc ->
1153
+ let path = sprintf "%s[%i]" path i
1154
+ let decoder = decoders.[i - offset]
1155
+ let value = values.[i]
1156
+ result <- decoder path value |> Result.map (fun v -> v::acc)
1157
+ result
1158
+ |> Result.map List.rev
1159
+
1160
+ let rec private makeUnion extra caseStrategy t name (path : string) (values: JsonValue[]) =
1161
+ let uci =
1162
+ FSharpType.GetUnionCases(t, allowAccessToPrivateRepresentation=true)
1163
+ |> Array.tryFind (fun x -> x.Name = name)
1164
+ match uci with
1165
+ | None -> (path, FailMessage("Cannot find case " + name + " in " + t.FullName)) |> Error
1166
+ | Some uci ->
1167
+ let decoders = uci.GetFields() |> Array.map (fun fi -> autoDecoder extra caseStrategy false fi.PropertyType)
1168
+ let values =
1169
+ if decoders.Length = 0 && values.Length <= 1 // First item is the case name
1170
+ then Ok []
1171
+ else mixedArray 1 decoders path values
1172
+ values |> Result.map (fun values -> FSharpValue.MakeUnion(uci, List.toArray values, allowAccessToPrivateRepresentation=true))
1173
+
1174
+ and private autoDecodeRecordsAndUnions extra (caseStrategy : CaseStrategy) (isOptional : bool) (t: System.Type) : BoxedDecoder =
1175
+ // Add the decoder to extra in case one of the fields is recursive
1176
+ let decoderRef = ref Unchecked.defaultof<_>
1177
+ let extra =
1178
+ // As of 3.7.17 Fable assigns empty name to anonymous record, we shouldn't add them to the map to avoid conflicts.
1179
+ // Anonymous records cannot be recursive anyways, see #144
1180
+ match t.FullName with
1181
+ | "" -> extra
1182
+ | fullName -> extra |> Map.add fullName decoderRef
1183
+ let decoder =
1184
+ if FSharpType.IsRecord(t, allowAccessToPrivateRepresentation=true) then
1185
+ let decoders =
1186
+ FSharpType.GetRecordFields(t, allowAccessToPrivateRepresentation=true)
1187
+ |> Array.map (fun fi ->
1188
+ let name = Util.Casing.convert caseStrategy fi.Name
1189
+ name, autoDecoder extra caseStrategy false fi.PropertyType)
1190
+ fun path value ->
1191
+ autoObject decoders path value
1192
+ |> Result.map (fun xs -> FSharpValue.MakeRecord(t, List.toArray xs, allowAccessToPrivateRepresentation=true))
1193
+
1194
+ elif FSharpType.IsUnion(t, allowAccessToPrivateRepresentation=true) then
1195
+ fun path (value: JsonValue) ->
1196
+ if Helpers.isString(value) then
1197
+ let name = Helpers.asString value
1198
+ makeUnion extra caseStrategy t name path [||]
1199
+ elif Helpers.isArray(value) then
1200
+ let values = Helpers.asArray value
1201
+ string (path + "[0]") values.[0]
1202
+ |> Result.bind (fun name -> makeUnion extra caseStrategy t name path values)
1203
+ else (path, BadPrimitive("a string or array", value)) |> Error
1204
+
1205
+ else
1206
+ if isOptional then
1207
+ // The error will only happen at runtime if the value is not null
1208
+ // See https://github.com/MangelMaxime/Thoth/pull/84#issuecomment-444837773
1209
+ boxDecoder(fun path value -> Error(path, BadType("an extra coder for " + t.FullName, value)))
1210
+ else
1211
+ // Don't use failwithf here, for some reason F#/Fable compiles it as a function
1212
+ // when the return type is a function too, so it doesn't fail immediately
1213
+ sprintf """Cannot generate auto decoder for %s. Please pass an extra decoder.
1214
+
1215
+ Documentation available at: https://thoth-org.github.io/Thoth.Json/documentation/auto/extra-coders.html#ready-to-use-extra-coders""" t.FullName |> failwith
1216
+ decoderRef.Value <- decoder
1217
+ decoder
1218
+
1219
+ and private autoDecoder (extra: Map<string, ref<BoxedDecoder>>) caseStrategy (isOptional : bool) (t: System.Type) : BoxedDecoder =
1220
+ let fullname = t.FullName
1221
+ match Map.tryFind fullname extra with
1222
+ | Some decoderRef -> fun path value -> decoderRef.contents path value
1223
+ | None ->
1224
+ if t.IsArray then
1225
+ let decoder = t.GetElementType() |> autoDecoder extra caseStrategy false
1226
+ array decoder |> boxDecoder
1227
+ elif t.IsEnum then
1228
+ let enumType = System.Enum.GetUnderlyingType(t).FullName
1229
+ if enumType = typeof<sbyte>.FullName then
1230
+ enumDecoder<sbyte> sbyte Operators.string t |> boxDecoder
1231
+ elif enumType = typeof<byte>.FullName then
1232
+ enumDecoder<byte> byte Operators.string t |> boxDecoder
1233
+ elif enumType = typeof<int16>.FullName then
1234
+ enumDecoder<int16> int16 Operators.string t |> boxDecoder
1235
+ elif enumType = typeof<uint16>.FullName then
1236
+ enumDecoder<uint16> uint16 Operators.string t |> boxDecoder
1237
+ elif enumType = typeof<int>.FullName then
1238
+ enumDecoder<int> int Operators.string t |> boxDecoder
1239
+ elif enumType = typeof<uint32>.FullName then
1240
+ enumDecoder<uint32> uint32 Operators.string t |> boxDecoder
1241
+ else
1242
+ failwithf
1243
+ """Cannot generate auto decoder for %s.
1244
+ Thoth.Json.Net only support the following enum types:
1245
+ - sbyte
1246
+ - byte
1247
+ - int16
1248
+ - uint16
1249
+ - int
1250
+ - uint32
1251
+ If you can't use one of these types, please pass an extra decoder.
1252
+ """ t.FullName
1253
+ elif t.IsGenericType then
1254
+ if FSharpType.IsTuple(t) then
1255
+ let decoders = FSharpType.GetTupleElements(t) |> Array.map (autoDecoder extra caseStrategy false)
1256
+ fun path value ->
1257
+ if Helpers.isArray value then
1258
+ mixedArray 0 decoders path (Helpers.asArray value)
1259
+ |> Result.map (fun xs -> FSharpValue.MakeTuple(List.toArray xs, t))
1260
+ else (path, BadPrimitive ("an array", value)) |> Error
1261
+ else
1262
+ let fullname = t.GetGenericTypeDefinition().FullName
1263
+ if fullname = typedefof<obj option>.FullName then
1264
+ t.GenericTypeArguments.[0] |> (autoDecoder extra caseStrategy true) |> option |> boxDecoder
1265
+ elif fullname = typedefof<obj list>.FullName then
1266
+ t.GenericTypeArguments.[0] |> (autoDecoder extra caseStrategy false) |> list |> boxDecoder
1267
+ elif fullname = typedefof<obj seq>.FullName then
1268
+ t.GenericTypeArguments.[0] |> (autoDecoder extra caseStrategy false) |> seq |> boxDecoder
1269
+ elif fullname = typedefof< Map<System.IComparable, obj> >.FullName then
1270
+ let keyDecoder = t.GenericTypeArguments.[0] |> autoDecoder extra caseStrategy false
1271
+ let valueDecoder = t.GenericTypeArguments.[1] |> autoDecoder extra caseStrategy false
1272
+ oneOf [
1273
+ autoObject2 keyDecoder valueDecoder
1274
+ list (tuple2 keyDecoder valueDecoder)
1275
+ ] |> map (fun ar -> toMap (unbox ar) |> box)
1276
+ elif fullname = typedefof< Set<string> >.FullName then
1277
+ let decoder = t.GenericTypeArguments.[0] |> autoDecoder extra caseStrategy false
1278
+ fun path value ->
1279
+ match array decoder path value with
1280
+ | Error er -> Error er
1281
+ | Ok ar -> toSet (unbox ar) |> box |> Ok
1282
+ else
1283
+ autoDecodeRecordsAndUnions extra caseStrategy isOptional t
1284
+ else
1285
+ if fullname = typeof<bool>.FullName then
1286
+ boxDecoder bool
1287
+ elif fullname = typedefof<unit>.FullName then
1288
+ boxDecoder unit
1289
+ elif fullname = typeof<string>.FullName then
1290
+ boxDecoder string
1291
+ elif fullname = typeof<char>.FullName then
1292
+ boxDecoder char
1293
+ elif fullname = typeof<sbyte>.FullName then
1294
+ boxDecoder sbyte
1295
+ elif fullname = typeof<byte>.FullName then
1296
+ boxDecoder byte
1297
+ elif fullname = typeof<int16>.FullName then
1298
+ boxDecoder int16
1299
+ elif fullname = typeof<uint16>.FullName then
1300
+ boxDecoder uint16
1301
+ elif fullname = typeof<int>.FullName then
1302
+ boxDecoder int
1303
+ elif fullname = typeof<uint32>.FullName then
1304
+ boxDecoder uint32
1305
+ elif fullname = typeof<float>.FullName then
1306
+ boxDecoder float
1307
+ elif fullname = typeof<float32>.FullName then
1308
+ boxDecoder float32
1309
+ // These number types require extra libraries in Fable. To prevent penalizing
1310
+ // all users, extra decoders (withInt64, etc) must be passed when they're needed.
1311
+
1312
+ // elif fullname = typeof<int64>.FullName then
1313
+ // boxDecoder int64
1314
+ // elif fullname = typeof<uint64>.FullName then
1315
+ // boxDecoder uint64
1316
+ // elif fullname = typeof<bigint>.FullName then
1317
+ // boxDecoder bigint
1318
+ // elif fullname = typeof<decimal>.FullName then
1319
+ // boxDecoder decimal
1320
+ elif fullname = typeof<System.DateTime>.FullName then
1321
+ boxDecoder datetimeUtc
1322
+ elif fullname = typeof<System.DateTimeOffset>.FullName then
1323
+ boxDecoder datetimeOffset
1324
+ elif fullname = typeof<System.TimeSpan>.FullName then
1325
+ boxDecoder timespan
1326
+ elif fullname = typeof<System.Guid>.FullName then
1327
+ boxDecoder guid
1328
+ elif fullname = typeof<obj>.FullName then
1329
+ fun _ v -> Ok v
1330
+ else autoDecodeRecordsAndUnions extra caseStrategy isOptional t
1331
+
1332
+ let private makeExtra (extra: ExtraCoders option) =
1333
+ match extra with
1334
+ | None -> Map.empty
1335
+ | Some e -> Map.map (fun _ (_,dec) -> ref dec) e.Coders
1336
+
1337
+ type Auto =
1338
+ static member generateBoxedDecoderCached(t: System.Type, ?caseStrategy : CaseStrategy, ?extra: ExtraCoders): BoxedDecoder =
1339
+ let caseStrategy = defaultArg caseStrategy PascalCase
1340
+
1341
+ let key =
1342
+ t.FullName
1343
+ |> (+) (Operators.string caseStrategy)
1344
+ |> (+) (extra |> Option.map (fun e -> e.Hash) |> Option.defaultValue "")
1345
+
1346
+ Util.CachedDecoders.GetOrAdd(key, fun _ -> autoDecoder (makeExtra extra) caseStrategy false t)
1347
+
1348
+ static member inline generateDecoderCached<'T>(?caseStrategy : CaseStrategy, ?extra: ExtraCoders): Decoder<'T> =
1349
+ Auto.generateBoxedDecoderCached(typeof<'T>, ?caseStrategy=caseStrategy, ?extra=extra) |> unboxDecoder
1350
+
1351
+ static member generateBoxedDecoder(t: System.Type, ?caseStrategy : CaseStrategy, ?extra: ExtraCoders): BoxedDecoder =
1352
+ let caseStrategy = defaultArg caseStrategy PascalCase
1353
+ autoDecoder (makeExtra extra) caseStrategy false t
1354
+
1355
+ static member inline generateDecoder<'T>(?caseStrategy : CaseStrategy, ?extra: ExtraCoders): Decoder<'T> =
1356
+ Auto.generateBoxedDecoder(typeof<'T>, ?caseStrategy=caseStrategy, ?extra=extra) |> unboxDecoder
1357
+
1358
+ static member inline fromString<'T>(json: string, ?caseStrategy : CaseStrategy, ?extra: ExtraCoders): Result<'T, string> =
1359
+ let decoder = Auto.generateDecoder<'T>(?caseStrategy=caseStrategy, ?extra=extra)
1360
+ fromString decoder json
1361
+
1362
+ static member inline unsafeFromString<'T>(json: string, ?caseStrategy : CaseStrategy, ?extra: ExtraCoders): 'T =
1363
+ let decoder = Auto.generateDecoder<'T>(?caseStrategy=caseStrategy, ?extra=extra)
1364
+ match fromString decoder json with
1365
+ | Ok x -> x
1366
+ | Error msg -> failwith msg