@voxgig/sdkgen-langpack 0.0.1

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 (300) hide show
  1. package/.sdk/model/target/dart.aon +63 -0
  2. package/.sdk/model/target/haskell.aon +72 -0
  3. package/.sdk/model/target/lean.aon +91 -0
  4. package/.sdk/src/cmp/dart/Config_dart.ts +248 -0
  5. package/.sdk/src/cmp/dart/EntityBase_dart.ts +34 -0
  6. package/.sdk/src/cmp/dart/EntityOperation_dart.ts +43 -0
  7. package/.sdk/src/cmp/dart/EntityTypes_dart.ts +207 -0
  8. package/.sdk/src/cmp/dart/Entity_dart.ts +87 -0
  9. package/.sdk/src/cmp/dart/Gitignore_dart.ts +34 -0
  10. package/.sdk/src/cmp/dart/MainEntity_dart.ts +33 -0
  11. package/.sdk/src/cmp/dart/Main_dart.ts +178 -0
  12. package/.sdk/src/cmp/dart/Package_dart.ts +82 -0
  13. package/.sdk/src/cmp/dart/ReadmeEntity_dart.ts +177 -0
  14. package/.sdk/src/cmp/dart/ReadmeExamplesTest_dart.ts +238 -0
  15. package/.sdk/src/cmp/dart/ReadmeExplanation_dart.ts +53 -0
  16. package/.sdk/src/cmp/dart/ReadmeHowto_dart.ts +152 -0
  17. package/.sdk/src/cmp/dart/ReadmeInstall_dart.ts +59 -0
  18. package/.sdk/src/cmp/dart/ReadmeIntro_dart.ts +65 -0
  19. package/.sdk/src/cmp/dart/ReadmeModel_dart.ts +151 -0
  20. package/.sdk/src/cmp/dart/ReadmeOptions_dart.ts +63 -0
  21. package/.sdk/src/cmp/dart/ReadmeQuick_dart.ts +225 -0
  22. package/.sdk/src/cmp/dart/ReadmeRef_dart.ts +397 -0
  23. package/.sdk/src/cmp/dart/ReadmeTopHowto_dart.ts +24 -0
  24. package/.sdk/src/cmp/dart/ReadmeTopQuick_dart.ts +106 -0
  25. package/.sdk/src/cmp/dart/ReadmeTopTest_dart.ts +78 -0
  26. package/.sdk/src/cmp/dart/SdkError_dart.ts +42 -0
  27. package/.sdk/src/cmp/dart/TestDirect_dart.ts +516 -0
  28. package/.sdk/src/cmp/dart/TestEntity_dart.ts +628 -0
  29. package/.sdk/src/cmp/dart/Test_dart.ts +138 -0
  30. package/.sdk/src/cmp/dart/fragment/Config.data.fragment.dart +98 -0
  31. package/.sdk/src/cmp/dart/fragment/Config.fragment.dart +70 -0
  32. package/.sdk/src/cmp/dart/fragment/Direct.test.fragment.dart +25 -0
  33. package/.sdk/src/cmp/dart/fragment/Entity.fragment.dart +29 -0
  34. package/.sdk/src/cmp/dart/fragment/Entity.test.fragment.dart +28 -0
  35. package/.sdk/src/cmp/dart/fragment/EntityBase.fragment.dart +302 -0
  36. package/.sdk/src/cmp/dart/fragment/EntityCreateOp.fragment.dart +98 -0
  37. package/.sdk/src/cmp/dart/fragment/EntityListOp.fragment.dart +90 -0
  38. package/.sdk/src/cmp/dart/fragment/EntityLoadOp.fragment.dart +102 -0
  39. package/.sdk/src/cmp/dart/fragment/EntityRemoveOp.fragment.dart +108 -0
  40. package/.sdk/src/cmp/dart/fragment/EntityUpdateOp.fragment.dart +102 -0
  41. package/.sdk/src/cmp/dart/fragment/Main.fragment.dart +339 -0
  42. package/.sdk/src/cmp/dart/fragment/SdkError.fragment.dart +26 -0
  43. package/.sdk/src/cmp/dart/tsconfig.json +15 -0
  44. package/.sdk/src/cmp/dart/utility_dart.ts +155 -0
  45. package/.sdk/src/cmp/haskell/Config_haskell.ts +98 -0
  46. package/.sdk/src/cmp/haskell/Entity_haskell.ts +13 -0
  47. package/.sdk/src/cmp/haskell/Gitignore_haskell.ts +27 -0
  48. package/.sdk/src/cmp/haskell/Main_haskell.ts +123 -0
  49. package/.sdk/src/cmp/haskell/Package_haskell.ts +60 -0
  50. package/.sdk/src/cmp/haskell/ReadmeEntity_haskell.ts +186 -0
  51. package/.sdk/src/cmp/haskell/ReadmeExamplesTest_haskell.ts +135 -0
  52. package/.sdk/src/cmp/haskell/ReadmeExplanation_haskell.ts +48 -0
  53. package/.sdk/src/cmp/haskell/ReadmeHowto_haskell.ts +168 -0
  54. package/.sdk/src/cmp/haskell/ReadmeInstall_haskell.ts +51 -0
  55. package/.sdk/src/cmp/haskell/ReadmeIntro_haskell.ts +67 -0
  56. package/.sdk/src/cmp/haskell/ReadmeModel_haskell.ts +162 -0
  57. package/.sdk/src/cmp/haskell/ReadmeOptions_haskell.ts +74 -0
  58. package/.sdk/src/cmp/haskell/ReadmeQuick_haskell.ts +241 -0
  59. package/.sdk/src/cmp/haskell/ReadmeRef_haskell.ts +408 -0
  60. package/.sdk/src/cmp/haskell/ReadmeTopHowto_haskell.ts +31 -0
  61. package/.sdk/src/cmp/haskell/ReadmeTopQuick_haskell.ts +104 -0
  62. package/.sdk/src/cmp/haskell/ReadmeTopTest_haskell.ts +80 -0
  63. package/.sdk/src/cmp/haskell/Test_haskell.ts +297 -0
  64. package/.sdk/src/cmp/haskell/tsconfig.json +15 -0
  65. package/.sdk/src/cmp/haskell/utility_haskell.ts +166 -0
  66. package/.sdk/src/cmp/lean/Config_lean.ts +93 -0
  67. package/.sdk/src/cmp/lean/Entity_lean.ts +9 -0
  68. package/.sdk/src/cmp/lean/Gitignore_lean.ts +18 -0
  69. package/.sdk/src/cmp/lean/Main_lean.ts +120 -0
  70. package/.sdk/src/cmp/lean/Package_lean.ts +93 -0
  71. package/.sdk/src/cmp/lean/ReadmeEntity_lean.ts +29 -0
  72. package/.sdk/src/cmp/lean/ReadmeExplanation_lean.ts +19 -0
  73. package/.sdk/src/cmp/lean/ReadmeHowto_lean.ts +25 -0
  74. package/.sdk/src/cmp/lean/ReadmeInstall_lean.ts +39 -0
  75. package/.sdk/src/cmp/lean/ReadmeIntro_lean.ts +25 -0
  76. package/.sdk/src/cmp/lean/ReadmeModel_lean.ts +24 -0
  77. package/.sdk/src/cmp/lean/ReadmeOptions_lean.ts +22 -0
  78. package/.sdk/src/cmp/lean/ReadmeQuick_lean.ts +50 -0
  79. package/.sdk/src/cmp/lean/ReadmeRef_lean.ts +40 -0
  80. package/.sdk/src/cmp/lean/ReadmeTopHowto_lean.ts +16 -0
  81. package/.sdk/src/cmp/lean/ReadmeTopQuick_lean.ts +23 -0
  82. package/.sdk/src/cmp/lean/ReadmeTopTest_lean.ts +19 -0
  83. package/.sdk/src/cmp/lean/Test_lean.ts +261 -0
  84. package/.sdk/src/cmp/lean/utility_lean.ts +129 -0
  85. package/.sdk/tm/dart/LICENSE +22 -0
  86. package/.sdk/tm/dart/Makefile +50 -0
  87. package/.sdk/tm/dart/lib/Context.dart +150 -0
  88. package/.sdk/tm/dart/lib/Control.dart +15 -0
  89. package/.sdk/tm/dart/lib/Operation.dart +31 -0
  90. package/.sdk/tm/dart/lib/Point.dart +51 -0
  91. package/.sdk/tm/dart/lib/Response.dart +32 -0
  92. package/.sdk/tm/dart/lib/Result.dart +39 -0
  93. package/.sdk/tm/dart/lib/Spec.dart +49 -0
  94. package/.sdk/tm/dart/lib/feature/audit/AuditFeature.dart +103 -0
  95. package/.sdk/tm/dart/lib/feature/base/BaseFeature.dart +76 -0
  96. package/.sdk/tm/dart/lib/feature/cache/CacheFeature.dart +152 -0
  97. package/.sdk/tm/dart/lib/feature/clienttrack/ClienttrackFeature.dart +104 -0
  98. package/.sdk/tm/dart/lib/feature/cost/CostFeature.dart +446 -0
  99. package/.sdk/tm/dart/lib/feature/debug/DebugFeature.dart +153 -0
  100. package/.sdk/tm/dart/lib/feature/idempotency/IdempotencyFeature.dart +92 -0
  101. package/.sdk/tm/dart/lib/feature/log/LogFeature.dart +85 -0
  102. package/.sdk/tm/dart/lib/feature/metrics/MetricsFeature.dart +103 -0
  103. package/.sdk/tm/dart/lib/feature/netsim/NetsimFeature.dart +186 -0
  104. package/.sdk/tm/dart/lib/feature/paging/PagingFeature.dart +240 -0
  105. package/.sdk/tm/dart/lib/feature/proxy/ProxyFeature.dart +118 -0
  106. package/.sdk/tm/dart/lib/feature/ratelimit/RatelimitFeature.dart +103 -0
  107. package/.sdk/tm/dart/lib/feature/rbac/RbacFeature.dart +121 -0
  108. package/.sdk/tm/dart/lib/feature/retry/RetryFeature.dart +155 -0
  109. package/.sdk/tm/dart/lib/feature/secrets/SecretsFeature.dart +649 -0
  110. package/.sdk/tm/dart/lib/feature/secrets/plugin/capability.dart +105 -0
  111. package/.sdk/tm/dart/lib/feature/secrets/plugin/catalog.dart +46 -0
  112. package/.sdk/tm/dart/lib/feature/secrets/plugin/config.dart +297 -0
  113. package/.sdk/tm/dart/lib/feature/secrets/plugin/depend.dart +198 -0
  114. package/.sdk/tm/dart/lib/feature/secrets/plugin/env.dart +144 -0
  115. package/.sdk/tm/dart/lib/feature/secrets/plugin/export.dart +58 -0
  116. package/.sdk/tm/dart/lib/feature/secrets/plugin/graph.dart +160 -0
  117. package/.sdk/tm/dart/lib/feature/secrets/plugin/host.dart +1067 -0
  118. package/.sdk/tm/dart/lib/feature/secrets/plugin/order.dart +172 -0
  119. package/.sdk/tm/dart/lib/feature/secrets/plugin/plugin.dart +23 -0
  120. package/.sdk/tm/dart/lib/feature/secrets/plugin/point.dart +117 -0
  121. package/.sdk/tm/dart/lib/feature/secrets/plugin/ref.dart +105 -0
  122. package/.sdk/tm/dart/lib/feature/secrets/plugin/resolve.dart +58 -0
  123. package/.sdk/tm/dart/lib/feature/secrets/plugin/types.dart +201 -0
  124. package/.sdk/tm/dart/lib/feature/secrets/plugin/version.dart +116 -0
  125. package/.sdk/tm/dart/lib/feature/secrets/sekreto/plugins/aws.dart +285 -0
  126. package/.sdk/tm/dart/lib/feature/secrets/sekreto/plugins/azuresecrets.dart +178 -0
  127. package/.sdk/tm/dart/lib/feature/secrets/sekreto/plugins/boru.dart +145 -0
  128. package/.sdk/tm/dart/lib/feature/secrets/sekreto/plugins/crypto.dart +194 -0
  129. package/.sdk/tm/dart/lib/feature/secrets/sekreto/plugins/doppler.dart +101 -0
  130. package/.sdk/tm/dart/lib/feature/secrets/sekreto/plugins/gcpsecrets.dart +143 -0
  131. package/.sdk/tm/dart/lib/feature/secrets/sekreto/plugins/hashicorp.dart +190 -0
  132. package/.sdk/tm/dart/lib/feature/secrets/sekreto/plugins/httpjson.dart +363 -0
  133. package/.sdk/tm/dart/lib/feature/secrets/sekreto/plugins/infisical.dart +149 -0
  134. package/.sdk/tm/dart/lib/feature/secrets/sekreto/plugins/onepassword.dart +146 -0
  135. package/.sdk/tm/dart/lib/feature/secrets/sekreto/plugins/secretspec.dart +116 -0
  136. package/.sdk/tm/dart/lib/feature/secrets/sekreto/plugins/sigv4.dart +237 -0
  137. package/.sdk/tm/dart/lib/feature/secrets/sekreto/src/addr.dart +138 -0
  138. package/.sdk/tm/dart/lib/feature/secrets/sekreto/src/json.dart +276 -0
  139. package/.sdk/tm/dart/lib/feature/secrets/sekreto/src/provider.dart +31 -0
  140. package/.sdk/tm/dart/lib/feature/secrets/sekreto/src/providers.dart +243 -0
  141. package/.sdk/tm/dart/lib/feature/secrets/sekreto/src/sekreto.dart +730 -0
  142. package/.sdk/tm/dart/lib/feature/secrets/sekreto/src/spec.dart +200 -0
  143. package/.sdk/tm/dart/lib/feature/secrets/sekreto/src/support.dart +217 -0
  144. package/.sdk/tm/dart/lib/feature/streaming/StreamingFeature.dart +97 -0
  145. package/.sdk/tm/dart/lib/feature/telemetry/TelemetryFeature.dart +136 -0
  146. package/.sdk/tm/dart/lib/feature/test/TestFeature.dart +328 -0
  147. package/.sdk/tm/dart/lib/feature/timeout/TimeoutFeature.dart +104 -0
  148. package/.sdk/tm/dart/lib/utility/CleanUtility.dart +12 -0
  149. package/.sdk/tm/dart/lib/utility/DoneUtility.dart +18 -0
  150. package/.sdk/tm/dart/lib/utility/ErrUtility.dart +46 -0
  151. package/.sdk/tm/dart/lib/utility/FeatureAddUtility.dart +35 -0
  152. package/.sdk/tm/dart/lib/utility/FeatureHookUtility.dart +20 -0
  153. package/.sdk/tm/dart/lib/utility/FeatureInitUtility.dart +9 -0
  154. package/.sdk/tm/dart/lib/utility/FetcherUtility.dart +104 -0
  155. package/.sdk/tm/dart/lib/utility/GraphqlUtility.dart +162 -0
  156. package/.sdk/tm/dart/lib/utility/MakeContextUtility.dart +6 -0
  157. package/.sdk/tm/dart/lib/utility/MakeErrorUtility.dart +71 -0
  158. package/.sdk/tm/dart/lib/utility/MakeFetchDefUtility.dart +42 -0
  159. package/.sdk/tm/dart/lib/utility/MakeOptionsUtility.dart +233 -0
  160. package/.sdk/tm/dart/lib/utility/MakePointUtility.dart +130 -0
  161. package/.sdk/tm/dart/lib/utility/MakeRequestUtility.dart +66 -0
  162. package/.sdk/tm/dart/lib/utility/MakeResponseUtility.dart +59 -0
  163. package/.sdk/tm/dart/lib/utility/MakeResultUtility.dart +49 -0
  164. package/.sdk/tm/dart/lib/utility/MakeSpecUtility.dart +77 -0
  165. package/.sdk/tm/dart/lib/utility/MakeUrlUtility.dart +51 -0
  166. package/.sdk/tm/dart/lib/utility/ParamUtility.dart +56 -0
  167. package/.sdk/tm/dart/lib/utility/PrepareAuthUtility.dart +46 -0
  168. package/.sdk/tm/dart/lib/utility/PrepareBodyUtility.dart +19 -0
  169. package/.sdk/tm/dart/lib/utility/PrepareHeadersUtility.dart +11 -0
  170. package/.sdk/tm/dart/lib/utility/PrepareMethodUtility.dart +30 -0
  171. package/.sdk/tm/dart/lib/utility/PrepareParamsUtility.dart +23 -0
  172. package/.sdk/tm/dart/lib/utility/PreparePathUtility.dart +9 -0
  173. package/.sdk/tm/dart/lib/utility/PrepareQueryUtility.dart +18 -0
  174. package/.sdk/tm/dart/lib/utility/ResultBasicUtility.dart +29 -0
  175. package/.sdk/tm/dart/lib/utility/ResultBodyUtility.dart +15 -0
  176. package/.sdk/tm/dart/lib/utility/ResultHeadersUtility.dart +18 -0
  177. package/.sdk/tm/dart/lib/utility/StructUtility.dart +127 -0
  178. package/.sdk/tm/dart/lib/utility/TransformRequestUtility.dart +28 -0
  179. package/.sdk/tm/dart/lib/utility/TransformResponseUtility.dart +44 -0
  180. package/.sdk/tm/dart/lib/utility/Utility.dart +239 -0
  181. package/.sdk/tm/dart/lib/utility/voxgig_struct.dart +2462 -0
  182. package/.sdk/tm/dart/src/feature/README.md +3 -0
  183. package/.sdk/tm/dart/src/feature/audit/.gitkeep +0 -0
  184. package/.sdk/tm/dart/src/feature/base/.gitkeep +0 -0
  185. package/.sdk/tm/dart/src/feature/cache/.gitkeep +0 -0
  186. package/.sdk/tm/dart/src/feature/clienttrack/.gitkeep +0 -0
  187. package/.sdk/tm/dart/src/feature/cost/.gitkeep +0 -0
  188. package/.sdk/tm/dart/src/feature/debug/.gitkeep +0 -0
  189. package/.sdk/tm/dart/src/feature/idempotency/.gitkeep +0 -0
  190. package/.sdk/tm/dart/src/feature/log/.gitkeep +0 -0
  191. package/.sdk/tm/dart/src/feature/metrics/.gitkeep +0 -0
  192. package/.sdk/tm/dart/src/feature/netsim/.gitkeep +0 -0
  193. package/.sdk/tm/dart/src/feature/paging/.gitkeep +0 -0
  194. package/.sdk/tm/dart/src/feature/proxy/.gitkeep +0 -0
  195. package/.sdk/tm/dart/src/feature/ratelimit/.gitkeep +0 -0
  196. package/.sdk/tm/dart/src/feature/rbac/.gitkeep +0 -0
  197. package/.sdk/tm/dart/src/feature/retry/.gitkeep +0 -0
  198. package/.sdk/tm/dart/src/feature/secrets/.gitkeep +0 -0
  199. package/.sdk/tm/dart/src/feature/streaming/.gitkeep +0 -0
  200. package/.sdk/tm/dart/src/feature/telemetry/.gitkeep +0 -0
  201. package/.sdk/tm/dart/src/feature/test/.gitkeep +0 -0
  202. package/.sdk/tm/dart/src/feature/timeout/.gitkeep +0 -0
  203. package/.sdk/tm/dart/test/custom_test.dart +65 -0
  204. package/.sdk/tm/dart/test/exists_test.dart +12 -0
  205. package/.sdk/tm/dart/test/feature/harness.dart +347 -0
  206. package/.sdk/tm/dart/test/feature/secrets/secrets_test.dart +1107 -0
  207. package/.sdk/tm/dart/test/feature_test.dart +1193 -0
  208. package/.sdk/tm/dart/test/harness.dart +153 -0
  209. package/.sdk/tm/dart/test/netsim_test.dart +48 -0
  210. package/.sdk/tm/dart/test/omni.dart +520 -0
  211. package/.sdk/tm/dart/test/omni_smoke_test.dart +143 -0
  212. package/.sdk/tm/dart/test/pipeline_test.dart +608 -0
  213. package/.sdk/tm/dart/test/primary_test.dart +476 -0
  214. package/.sdk/tm/dart/test/sdk-test-control.json +19 -0
  215. package/.sdk/tm/dart/test/struct_test.dart +468 -0
  216. package/.sdk/tm/dart/test/utility.dart +198 -0
  217. package/.sdk/tm/dart/test/vendor/omni/omni.dart +7 -0
  218. package/.sdk/tm/dart/test/vendor/omni/runner.dart +653 -0
  219. package/.sdk/tm/dart/test/vendor/omni/util.dart +232 -0
  220. package/.sdk/tm/haskell/LICENSE +21 -0
  221. package/.sdk/tm/haskell/Makefile +22 -0
  222. package/.sdk/tm/haskell/VERSION +1 -0
  223. package/.sdk/tm/haskell/src/SdkFeatures.hs +1440 -0
  224. package/.sdk/tm/haskell/src/SdkHelpers.hs +337 -0
  225. package/.sdk/tm/haskell/src/SdkJson.hs +111 -0
  226. package/.sdk/tm/haskell/src/SdkRuntime.hs +1279 -0
  227. package/.sdk/tm/haskell/src/SdkTypes.hs +195 -0
  228. package/.sdk/tm/haskell/src/VoxgigStruct.hs +2299 -0
  229. package/.sdk/tm/haskell/src/Vregex.hs +237 -0
  230. package/.sdk/tm/haskell/src/feature/README.md +5 -0
  231. package/.sdk/tm/haskell/src/feature/audit/.gitkeep +0 -0
  232. package/.sdk/tm/haskell/src/feature/base/.gitkeep +0 -0
  233. package/.sdk/tm/haskell/src/feature/cache/.gitkeep +0 -0
  234. package/.sdk/tm/haskell/src/feature/clienttrack/.gitkeep +0 -0
  235. package/.sdk/tm/haskell/src/feature/debug/.gitkeep +0 -0
  236. package/.sdk/tm/haskell/src/feature/idempotency/.gitkeep +0 -0
  237. package/.sdk/tm/haskell/src/feature/log/.gitkeep +0 -0
  238. package/.sdk/tm/haskell/src/feature/metrics/.gitkeep +0 -0
  239. package/.sdk/tm/haskell/src/feature/netsim/.gitkeep +0 -0
  240. package/.sdk/tm/haskell/src/feature/paging/.gitkeep +0 -0
  241. package/.sdk/tm/haskell/src/feature/proxy/.gitkeep +0 -0
  242. package/.sdk/tm/haskell/src/feature/ratelimit/.gitkeep +0 -0
  243. package/.sdk/tm/haskell/src/feature/rbac/.gitkeep +0 -0
  244. package/.sdk/tm/haskell/src/feature/retry/.gitkeep +0 -0
  245. package/.sdk/tm/haskell/src/feature/streaming/.gitkeep +0 -0
  246. package/.sdk/tm/haskell/src/feature/telemetry/.gitkeep +0 -0
  247. package/.sdk/tm/haskell/src/feature/test/.gitkeep +0 -0
  248. package/.sdk/tm/haskell/src/feature/timeout/.gitkeep +0 -0
  249. package/.sdk/tm/haskell/test/Harness.hs +281 -0
  250. package/.sdk/tm/haskell/test/OmniResolver.hs +252 -0
  251. package/.sdk/tm/haskell/test/Runner.hs +49 -0
  252. package/.sdk/tm/haskell/test/StructCorpus.hs +449 -0
  253. package/.sdk/tm/haskell/test/TCustomUtility.hs +38 -0
  254. package/.sdk/tm/haskell/test/TFeature.hs +794 -0
  255. package/.sdk/tm/haskell/test/TNetsim.hs +50 -0
  256. package/.sdk/tm/haskell/test/TPipeline.hs +334 -0
  257. package/.sdk/tm/haskell/test/TPrimaryCorpus.hs +263 -0
  258. package/.sdk/tm/haskell/test/TPrimaryUtility.hs +386 -0
  259. package/.sdk/tm/haskell/test/Testutil.hs +59 -0
  260. package/.sdk/tm/haskell/test/vendor/omni/Omni.hs +1147 -0
  261. package/.sdk/tm/lean/LICENSE +21 -0
  262. package/.sdk/tm/lean/Makefile +32 -0
  263. package/.sdk/tm/lean/VERSION +1 -0
  264. package/.sdk/tm/lean/src/SdkFeature.lean +171 -0
  265. package/.sdk/tm/lean/src/SdkFeatures.lean +787 -0
  266. package/.sdk/tm/lean/src/SdkJson.lean +134 -0
  267. package/.sdk/tm/lean/src/SdkRuntime.lean +374 -0
  268. package/.sdk/tm/lean/src/SdkUtility.lean +809 -0
  269. package/.sdk/tm/lean/src/VoxgigStruct.lean +2880 -0
  270. package/.sdk/tm/lean/src/Vregex.lean +412 -0
  271. package/.sdk/tm/lean/src/feature/README.md +5 -0
  272. package/.sdk/tm/lean/src/feature/audit/.gitkeep +0 -0
  273. package/.sdk/tm/lean/src/feature/base/.gitkeep +0 -0
  274. package/.sdk/tm/lean/src/feature/cache/.gitkeep +0 -0
  275. package/.sdk/tm/lean/src/feature/clienttrack/.gitkeep +0 -0
  276. package/.sdk/tm/lean/src/feature/cost/.gitkeep +0 -0
  277. package/.sdk/tm/lean/src/feature/debug/.gitkeep +0 -0
  278. package/.sdk/tm/lean/src/feature/idempotency/.gitkeep +0 -0
  279. package/.sdk/tm/lean/src/feature/log/.gitkeep +0 -0
  280. package/.sdk/tm/lean/src/feature/metrics/.gitkeep +0 -0
  281. package/.sdk/tm/lean/src/feature/netsim/.gitkeep +0 -0
  282. package/.sdk/tm/lean/src/feature/paging/.gitkeep +0 -0
  283. package/.sdk/tm/lean/src/feature/proxy/.gitkeep +0 -0
  284. package/.sdk/tm/lean/src/feature/ratelimit/.gitkeep +0 -0
  285. package/.sdk/tm/lean/src/feature/rbac/.gitkeep +0 -0
  286. package/.sdk/tm/lean/src/feature/retry/.gitkeep +0 -0
  287. package/.sdk/tm/lean/src/feature/streaming/.gitkeep +0 -0
  288. package/.sdk/tm/lean/src/feature/telemetry/.gitkeep +0 -0
  289. package/.sdk/tm/lean/src/feature/test/.gitkeep +0 -0
  290. package/.sdk/tm/lean/src/feature/timeout/.gitkeep +0 -0
  291. package/.sdk/tm/lean/test/OmniResolver.lean +358 -0
  292. package/.sdk/tm/lean/test/OmniSmoke.lean +174 -0
  293. package/.sdk/tm/lean/test/StructCorpus.lean +368 -0
  294. package/.sdk/tm/lean/test/TFeature.lean +281 -0
  295. package/.sdk/tm/lean/test/TPrimaryUtility.lean +227 -0
  296. package/.sdk/tm/lean/test/vendor/omni/Omni.lean +997 -0
  297. package/LICENSE +21 -0
  298. package/README.md +104 -0
  299. package/package.json +78 -0
  300. package/sdkgen-package.json +22 -0
@@ -0,0 +1,1147 @@
1
+ -- VENDORED: @voxgig/omni sdk-20260908-1556-0 (haskell/src/Omni.hs)
2
+ -- Source: https://github.com/voxgig/omni @ 274708cc2d12b21707d975543953f845f8444be0 [tag: sdk-20260908-1556-0]
3
+ -- License: MIT (c) voxgig - see repository LICENSE. Do not edit: resync from upstream.
4
+ -- | Omni: the shared multi-language test runner (Haskell port).
5
+ --
6
+ -- A test spec is plain JSON. The same spec file drives the same tests in
7
+ -- every language that ships an omni port.
8
+ --
9
+ -- Port of the canonical TypeScript implementation
10
+ -- (typescript/src/Runner.ts). Behaviour must match, case for case.
11
+ --
12
+ -- Self-contained by design: the runner carries its own JSON value model,
13
+ -- parser and regex engine, so that it can test *any* library - including
14
+ -- one that provides those same operations - and adds no dependencies
15
+ -- beyond base.
16
+
17
+ module Omni
18
+ ( Json (..),
19
+ Flags (..),
20
+ Provider (..),
21
+ RunPack (..),
22
+ Subject,
23
+ SubjectArgs,
24
+ OmniError (..),
25
+ nullmark,
26
+ undefmark,
27
+ existsmark,
28
+ specversion,
29
+ capabilities,
30
+ defaultFlags,
31
+ nonullFlags,
32
+ emptyProvider,
33
+ ismap,
34
+ islist,
35
+ isnode,
36
+ isabsent,
37
+ isnull,
38
+ isnone,
39
+ isnum,
40
+ isstr,
41
+ asnum,
42
+ asstr,
43
+ aslist,
44
+ asmap,
45
+ jget,
46
+ jhas,
47
+ jset,
48
+ parse,
49
+ loadspec,
50
+ resolvespec,
51
+ clone,
52
+ deepequal,
53
+ getpath,
54
+ walk,
55
+ jsonstr,
56
+ stringify,
57
+ numstr,
58
+ pathify,
59
+ fixjson,
60
+ errify,
61
+ providerErrify,
62
+ errmessage,
63
+ matchval,
64
+ nullmodifier,
65
+ regexFind,
66
+ makeRunner,
67
+ makeRunnerSpec,
68
+ )
69
+ where
70
+
71
+ import Control.Exception (Exception, SomeException, displayException, fromException, throwIO, try)
72
+ import Data.Char (isAlphaNum, isDigit, isSpace, toLower)
73
+ import Data.List (isInfixOf, isPrefixOf, sortBy)
74
+ import Data.Maybe (fromMaybe, isJust)
75
+ import Numeric (showHex)
76
+ import Text.Printf (printf)
77
+
78
+ -- ---- the JSON value model -------------------------------------------
79
+
80
+ -- | A JSON value. 'Absent' is the marker for "no value at all", as
81
+ -- distinct from 'Null'.
82
+ data Json
83
+ = Absent
84
+ | Null
85
+ | Bool Bool
86
+ | Num Double
87
+ | Str String
88
+ | JList [Json]
89
+ | JMap [(String, Json)]
90
+ deriving (Show)
91
+
92
+ nullmark :: String
93
+ nullmark = "__NULL__" -- Value is JSON null.
94
+
95
+ undefmark :: String
96
+ undefmark = "__UNDEF__" -- Value is not present.
97
+
98
+ existsmark :: String
99
+ existsmark = "__EXISTS__" -- Value exists (not undefined).
100
+
101
+ ismap :: Json -> Bool
102
+ ismap (JMap _) = True
103
+ ismap _ = False
104
+
105
+ islist :: Json -> Bool
106
+ islist (JList _) = True
107
+ islist _ = False
108
+
109
+ isnode :: Json -> Bool
110
+ isnode value = ismap value || islist value
111
+
112
+ isabsent :: Json -> Bool
113
+ isabsent Absent = True
114
+ isabsent _ = False
115
+
116
+ isnull :: Json -> Bool
117
+ isnull Null = True
118
+ isnull _ = False
119
+
120
+ isnone :: Json -> Bool
121
+ isnone value = isabsent value || isnull value
122
+
123
+ isnum :: Json -> Bool
124
+ isnum (Num _) = True
125
+ isnum _ = False
126
+
127
+ isstr :: Json -> Bool
128
+ isstr (Str _) = True
129
+ isstr _ = False
130
+
131
+ asnum :: Json -> Maybe Double
132
+ asnum (Num value) = Just value
133
+ asnum _ = Nothing
134
+
135
+ asstr :: Json -> Maybe String
136
+ asstr (Str value) = Just value
137
+ asstr _ = Nothing
138
+
139
+ aslist :: Json -> Maybe [Json]
140
+ aslist (JList value) = Just value
141
+ aslist _ = Nothing
142
+
143
+ asmap :: Json -> Maybe [(String, Json)]
144
+ asmap (JMap value) = Just value
145
+ asmap _ = Nothing
146
+
147
+ -- | Read a map entry. Returns 'Absent' when missing.
148
+ jget :: Json -> String -> Json
149
+ jget (JMap entries) key = fromMaybe Absent (lookup key entries)
150
+ jget _ _ = Absent
151
+
152
+ -- | Is a map key present at all (even with a null value)?
153
+ jhas :: Json -> String -> Bool
154
+ jhas (JMap entries) key = isJust (lookup key entries)
155
+ jhas _ _ = False
156
+
157
+ -- | A copy of a map with one entry set (no-op for non-maps).
158
+ jset :: Json -> String -> Json -> Json
159
+ jset (JMap entries) key entry =
160
+ if isJust (lookup key entries)
161
+ then JMap (map (\(k, e) -> if k == key then (k, entry) else (k, e)) entries)
162
+ else JMap (entries ++ [(key, entry)])
163
+ jset other _ _ = other
164
+
165
+ -- ---- errors ----------------------------------------------------------
166
+
167
+ -- | A test failure (or a malformed spec). Distinct from an exception
168
+ -- thrown by the subject under test, which is a candidate for an @err@
169
+ -- expectation.
170
+ newtype OmniError = OmniError String
171
+
172
+ instance Show OmniError where
173
+ show (OmniError message) = message
174
+
175
+ instance Exception OmniError
176
+
177
+ -- ---- number and string rendering ------------------------------------
178
+
179
+ -- | Render a number the same way in every port: 5.0 prints as 5.
180
+ numstr :: Double -> String
181
+ numstr value
182
+ | isNaN value || isInfinite value = "null"
183
+ | value == fromIntegral rounded && abs value < 9007199254740992.0 = show rounded
184
+ | otherwise = trimzeros (printf "%.17g" value)
185
+ where
186
+ rounded = truncate value :: Integer
187
+
188
+ trimzeros text =
189
+ if '.' `elem` text && 'e' `notElem` text && 'E' `notElem` text
190
+ then reverse (dropdot (dropWhile (== '0') (reverse text)))
191
+ else text
192
+
193
+ dropdot ('.' : rest) = rest
194
+ dropdot rest = rest
195
+
196
+ -- | Render a string as a JSON string literal.
197
+ quote :: String -> String
198
+ quote value = "\"" ++ concatMap escape value ++ "\""
199
+ where
200
+ escape ch = case ch of
201
+ '"' -> "\\\""
202
+ '\\' -> "\\\\"
203
+ '\n' -> "\\n"
204
+ '\r' -> "\\r"
205
+ '\t' -> "\\t"
206
+ _ ->
207
+ if fromEnum ch < 0x20
208
+ then "\\u" ++ pad (showHex (fromEnum ch) "")
209
+ else [ch]
210
+
211
+ pad text = replicate (4 - length text) '0' ++ text
212
+
213
+ -- | Compact JSON text with map keys sorted, identical in every port.
214
+ jsonstr :: Json -> String
215
+ jsonstr Absent = "undefined"
216
+ jsonstr Null = "null"
217
+ jsonstr (Bool flag) = if flag then "true" else "false"
218
+ jsonstr (Num value) = numstr value
219
+ jsonstr (Str text) = quote text
220
+ jsonstr (JList entries) = "[" ++ joinwith "," (map jsonstr entries) ++ "]"
221
+ jsonstr (JMap entries) =
222
+ "{" ++ joinwith "," (map render sorted) ++ "}"
223
+ where
224
+ sorted = sortBy (\(a, _) (b, _) -> compare a b) entries
225
+ render (key, entry) = quote key ++ ":" ++ jsonstr entry
226
+
227
+ -- | Strings verbatim, everything else as compact JSON.
228
+ stringify :: Json -> String
229
+ stringify (Str text) = text
230
+ stringify other = jsonstr other
231
+
232
+ joinwith :: String -> [String] -> String
233
+ joinwith _ [] = ""
234
+ joinwith _ [single] = single
235
+ joinwith sep (head' : rest) = head' ++ sep ++ joinwith sep rest
236
+
237
+ -- | Render a path as a dotted string.
238
+ pathify :: [String] -> String
239
+ pathify = joinwith "."
240
+
241
+ -- ---- json parser -----------------------------------------------------
242
+
243
+ -- | Parse JSON text into the omni value model.
244
+ parse :: String -> Either String Json
245
+ parse text = case parseValue (skipws text) of
246
+ Left message -> Left message
247
+ Right (value, rest) ->
248
+ if null (skipws rest)
249
+ then Right value
250
+ else Left "omni: trailing JSON content"
251
+
252
+ skipws :: String -> String
253
+ skipws = dropWhile isSpace
254
+
255
+ parseValue :: String -> Either String (Json, String)
256
+ parseValue [] = Left "omni: unexpected end of JSON"
257
+ parseValue text@(ch : rest)
258
+ | '{' == ch = parseMap (skipws rest) []
259
+ | '[' == ch = parseList (skipws rest) []
260
+ | '"' == ch = fmap (\(value, more) -> (Str value, more)) (parseString rest "")
261
+ | "true" `isPrefixOf` text = Right (Bool True, drop 4 text)
262
+ | "false" `isPrefixOf` text = Right (Bool False, drop 5 text)
263
+ | "null" `isPrefixOf` text = Right (Null, drop 4 text)
264
+ | otherwise = parseNumber text
265
+
266
+ parseMap :: String -> [(String, Json)] -> Either String (Json, String)
267
+ parseMap ('}' : rest) entries = Right (JMap (reverse entries), rest)
268
+ parseMap text entries = parseMapPair text entries
269
+
270
+ -- A comma must be followed by another pair: no trailing commas.
271
+ parseMapPair :: String -> [(String, Json)] -> Either String (Json, String)
272
+ parseMapPair text entries = do
273
+ (key, afterkey) <- case skipws text of
274
+ '"' : more -> parseString more ""
275
+ _ -> Left "omni: expected string key"
276
+
277
+ aftercolon <- case skipws afterkey of
278
+ ':' : more -> Right more
279
+ _ -> Left "omni: expected ':'"
280
+
281
+ (value, aftervalue) <- parseValue (skipws aftercolon)
282
+
283
+ -- A duplicate key overrides the earlier value (last wins), as in the
284
+ -- canonical implementation.
285
+ let entries' =
286
+ if isJust (lookup key entries)
287
+ then map (\(k, e) -> if k == key then (k, value) else (k, e)) entries
288
+ else (key, value) : entries
289
+
290
+ case skipws aftervalue of
291
+ ',' : more -> parseMapPair (skipws more) entries'
292
+ '}' : more -> Right (JMap (reverse entries'), more)
293
+ _ -> Left "omni: expected ',' or '}'"
294
+
295
+ parseList :: String -> [Json] -> Either String (Json, String)
296
+ parseList (']' : rest) entries = Right (JList (reverse entries), rest)
297
+ parseList text entries = parseListItem text entries
298
+
299
+ -- A comma must be followed by another element: no trailing commas.
300
+ parseListItem :: String -> [Json] -> Either String (Json, String)
301
+ parseListItem text entries = do
302
+ (value, aftervalue) <- parseValue (skipws text)
303
+
304
+ case skipws aftervalue of
305
+ ',' : more -> parseListItem (skipws more) (value : entries)
306
+ ']' : more -> Right (JList (reverse (value : entries)), more)
307
+ _ -> Left "omni: expected ',' or ']'"
308
+
309
+ parseString :: String -> String -> Either String (String, String)
310
+ parseString [] _ = Left "omni: unterminated JSON string"
311
+ parseString ('"' : rest) out = Right (reverse out, rest)
312
+ parseString ('\\' : escape : rest) out = case escape of
313
+ '"' -> parseString rest ('"' : out)
314
+ '\\' -> parseString rest ('\\' : out)
315
+ '/' -> parseString rest ('/' : out)
316
+ 'b' -> parseString rest ('\b' : out)
317
+ 'f' -> parseString rest ('\f' : out)
318
+ 'n' -> parseString rest ('\n' : out)
319
+ 'r' -> parseString rest ('\r' : out)
320
+ 't' -> parseString rest ('\t' : out)
321
+ 'u' ->
322
+ -- Exactly four hex digits: anything else is a parse error, not
323
+ -- garbage arithmetic on arbitrary characters.
324
+ let (hex, more) = splitAt 4 rest
325
+ in if 4 == length hex && all ishex hex
326
+ then parseString more (toEnum (readhex hex) : out)
327
+ else Left "omni: bad JSON unicode escape"
328
+ _ -> Left "omni: bad JSON escape"
329
+ where
330
+ ishex ch = isDigit ch || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')
331
+ readhex = foldl (\acc ch -> acc * 16 + digit ch) 0
332
+ digit ch
333
+ | isDigit ch = fromEnum ch - fromEnum '0'
334
+ | ch >= 'a' && ch <= 'f' = fromEnum ch - fromEnum 'a' + 10
335
+ | otherwise = fromEnum ch - fromEnum 'A' + 10
336
+ parseString (ch : rest) out = parseString rest (ch : out)
337
+
338
+ parseNumber :: String -> Either String (Json, String)
339
+ parseNumber text =
340
+ let (sign, afterSign) = span (\ch -> '-' == ch || '+' == ch) text
341
+ (digits, rest) = span (\ch -> isDigit ch || '.' == ch || 'e' == ch || 'E' == ch || '-' == ch || '+' == ch) afterSign
342
+ span' = sign ++ digits
343
+ in if null digits
344
+ then Left "omni: bad JSON number"
345
+ else case reads (fixup span') :: [(Double, String)] of
346
+ [(value, "")] -> Right (Num value, rest)
347
+ _ -> Left ("omni: bad JSON number [" ++ span' ++ "]")
348
+ where
349
+ -- Haskell's `reads` wants a digit before the point and no leading '+'.
350
+ fixup ('+' : more) = fixup more
351
+ fixup ('-' : '.' : more) = "-0." ++ more
352
+ fixup ('.' : more) = "0." ++ more
353
+ fixup other = other
354
+
355
+ -- | Load a spec: a path to a JSON file.
356
+ loadspec :: String -> IO Json
357
+ loadspec path = do
358
+ text <- readFile path
359
+ case parse text of
360
+ Right value -> pure value
361
+ Left message -> throwIO (OmniError ("omni: cannot parse spec: " ++ path ++ ": " ++ message))
362
+
363
+ -- ---- util ------------------------------------------------------------
364
+
365
+ -- | Deep copy a JSON value (the value model is immutable).
366
+ clone :: Json -> Json
367
+ clone = id
368
+
369
+ -- | Read a value by path. Returns 'Absent' when any step is missing.
370
+ getpath :: Json -> [String] -> Json
371
+ getpath value [] = value
372
+ getpath value (part : rest) =
373
+ let next = case value of
374
+ JList entries -> case readIndex part of
375
+ Just index | index >= 0 && index < length entries -> entries !! index
376
+ _ -> Absent
377
+ JMap _ -> jget value part
378
+ _ -> Absent
379
+ in if isabsent next then Absent else getpath next rest
380
+ where
381
+ readIndex text = case reads text :: [(Int, String)] of
382
+ [(index, "")] -> Just index
383
+ _ -> Nothing
384
+
385
+ -- | Depth-first walk: children first, then the containing node.
386
+ walk :: Json -> (Json -> [String] -> Json) -> [String] -> Json
387
+ walk value apply path = apply next path
388
+ where
389
+ next = case value of
390
+ JList entries ->
391
+ JList (zipWith (\index entry -> walk entry apply (path ++ [show index])) [0 :: Int ..] entries)
392
+ JMap entries -> JMap (map (\(key, entry) -> (key, walk entry apply (path ++ [key]))) entries)
393
+ other -> other
394
+
395
+ -- | Deep structural equality: numbers by value, bools never numbers.
396
+ deepequal :: Json -> Json -> Bool
397
+ deepequal Absent Absent = True
398
+ deepequal Null Null = True
399
+ deepequal (Bool x) (Bool y) = x == y
400
+ deepequal (Num x) (Num y) = x == y || (isNaN x && isNaN y)
401
+ deepequal (Str x) (Str y) = x == y
402
+ deepequal (JList x) (JList y) = length x == length y && and (zipWith deepequal x y)
403
+ deepequal (JMap x) (JMap y) =
404
+ length x == length y
405
+ && all (\(key, entry) -> maybe False (deepequal entry) (lookup key y)) x
406
+ deepequal _ _ = False
407
+
408
+ -- ---- regex engine ----------------------------------------------------
409
+
410
+ -- Omni specs match error messages with @/pattern/@ expectations, so every
411
+ -- port needs a regex. Haskell has none in base, so omni carries this
412
+ -- engine, a direct port of the Rust one (rust/src/regex.rs).
413
+
414
+ data ClassItem
415
+ = IChar Char
416
+ | IRange Char Char
417
+ | IDigit Bool
418
+ | IWord Bool
419
+ | ISpace Bool
420
+
421
+ data Node
422
+ = RChar Char
423
+ | RAny
424
+ | RClass [ClassItem] Bool
425
+ | RStart
426
+ | REnd
427
+ | RSeq [Node]
428
+ | RAlt [Node]
429
+ | RRepeat Node Int (Maybe Int) Bool
430
+
431
+ regexParse :: String -> Maybe Node
432
+ regexParse pattern = case parseAlt pattern of
433
+ Just (node, "") -> Just node
434
+ _ -> Nothing
435
+
436
+ parseAlt :: String -> Maybe (Node, String)
437
+ parseAlt text = do
438
+ (first, rest) <- parseSeq text
439
+ branches rest [first]
440
+ where
441
+ branches ('|' : more) acc = do
442
+ (branch, rest) <- parseSeq more
443
+ branches rest (branch : acc)
444
+ branches rest acc =
445
+ Just (if 1 == length acc then head acc else RAlt (reverse acc), rest)
446
+
447
+ parseSeq :: String -> Maybe (Node, String)
448
+ parseSeq = collect []
449
+ where
450
+ collect acc text
451
+ | null text || '|' == head text || ')' == head text = Just (RSeq (reverse acc), text)
452
+ | otherwise = do
453
+ (atom, rest) <- parseAtom text
454
+ (node, more) <- parseRepeat atom rest
455
+ collect (node : acc) more
456
+
457
+ parseRepeat :: Node -> String -> Maybe (Node, String)
458
+ parseRepeat atom text = case text of
459
+ '*' : rest -> greedy atom 0 Nothing rest
460
+ '+' : rest -> greedy atom 1 Nothing rest
461
+ '?' : rest -> greedy atom 0 (Just 1) rest
462
+ '{' : _ -> case parseCount text of
463
+ Just (low, high, rest) -> greedy atom low high rest
464
+ Nothing -> Just (atom, text)
465
+ _ -> Just (atom, text)
466
+ where
467
+ greedy inner low high ('?' : rest) = Just (RRepeat inner low high False, rest)
468
+ greedy inner low high rest = Just (RRepeat inner low high True, rest)
469
+
470
+ parseCount :: String -> Maybe (Int, Maybe Int, String)
471
+ parseCount ('{' : rest) =
472
+ let (lowtext, afterlow) = span isDigit rest
473
+ in if null lowtext
474
+ then Nothing
475
+ else case afterlow of
476
+ '}' : more -> Just (read lowtext, Just (read lowtext), more)
477
+ ',' : more ->
478
+ let (hightext, afterhigh) = span isDigit more
479
+ in case afterhigh of
480
+ '}' : final ->
481
+ Just (read lowtext, if null hightext then Nothing else Just (read hightext), final)
482
+ _ -> Nothing
483
+ _ -> Nothing
484
+ parseCount _ = Nothing
485
+
486
+ parseAtom :: String -> Maybe (Node, String)
487
+ parseAtom [] = Nothing
488
+ parseAtom ('(' : rest) = do
489
+ let inner = if "?:" `isPrefixOf` rest then drop 2 rest else rest
490
+ (node, more) <- parseAlt inner
491
+ case more of
492
+ ')' : final -> Just (node, final)
493
+ _ -> Nothing
494
+ parseAtom ('[' : rest) = parseClass rest
495
+ parseAtom ('.' : rest) = Just (RAny, rest)
496
+ parseAtom ('^' : rest) = Just (RStart, rest)
497
+ parseAtom ('$' : rest) = Just (REnd, rest)
498
+ parseAtom ('\\' : escape : rest) = Just (escapeNode escape, rest)
499
+ parseAtom (ch : rest) = Just (RChar ch, rest)
500
+
501
+ escapeNode :: Char -> Node
502
+ escapeNode escape = case escape of
503
+ 'd' -> RClass [IDigit False] False
504
+ 'D' -> RClass [IDigit False] True
505
+ 'w' -> RClass [IWord False] False
506
+ 'W' -> RClass [IWord False] True
507
+ 's' -> RClass [ISpace False] False
508
+ 'S' -> RClass [ISpace False] True
509
+ 'n' -> RChar '\n'
510
+ 'r' -> RChar '\r'
511
+ 't' -> RChar '\t'
512
+ other -> RChar other
513
+
514
+ parseClass :: String -> Maybe (Node, String)
515
+ parseClass text =
516
+ let (negated, rest) = case text of
517
+ '^' : more -> (True, more)
518
+ _ -> (False, text)
519
+ in collect [] True negated rest
520
+ where
521
+ collect _ _ _ [] = Nothing
522
+ collect acc first negated (']' : rest)
523
+ | not first = Just (RClass (reverse acc) negated, rest)
524
+ | otherwise = collect (IChar ']' : acc) False negated rest
525
+ collect acc _ negated ('\\' : escape : rest) =
526
+ collect (classEscape escape : acc) False negated rest
527
+ collect acc _ negated (from : '-' : to : rest)
528
+ | ']' /= to = collect (IRange from to : acc) False negated rest
529
+ collect acc _ negated (ch : rest) = collect (IChar ch : acc) False negated rest
530
+
531
+ classEscape escape = case escape of
532
+ 'd' -> IDigit False
533
+ 'w' -> IWord False
534
+ 's' -> ISpace False
535
+ 'n' -> IChar '\n'
536
+ 'r' -> IChar '\r'
537
+ 't' -> IChar '\t'
538
+ other -> IChar other
539
+
540
+ isWordChar :: Char -> Bool
541
+ isWordChar ch = isAlphaNum ch || '_' == ch
542
+
543
+ classMatch :: [ClassItem] -> Bool -> Char -> Bool
544
+ classMatch items negated ch = hit /= negated
545
+ where
546
+ hit = any check items
547
+ check item = case item of
548
+ IChar want -> ch == want
549
+ IRange from to -> from <= ch && ch <= to
550
+ IDigit invert -> isDigit ch /= invert
551
+ IWord invert -> isWordChar ch /= invert
552
+ ISpace invert -> isSpace ch /= invert
553
+
554
+ matchNode :: Node -> String -> Int -> Int -> (Int -> Bool) -> Bool
555
+ matchNode node text len pos cont = case node of
556
+ RChar want -> pos < len && (text !! pos) == want && cont (pos + 1)
557
+ RAny -> pos < len && cont (pos + 1)
558
+ RClass items negated -> pos < len && classMatch items negated (text !! pos) && cont (pos + 1)
559
+ RStart -> 0 == pos && cont pos
560
+ REnd -> len == pos && cont pos
561
+ RSeq nodes -> matchSeq nodes text len pos cont
562
+ RAlt branches -> any (\branch -> matchNode branch text len pos cont) branches
563
+ RRepeat inner low high greedy -> matchRepeat inner low high greedy 0 text len pos cont
564
+
565
+ matchSeq :: [Node] -> String -> Int -> Int -> (Int -> Bool) -> Bool
566
+ matchSeq [] _ _ pos cont = cont pos
567
+ matchSeq (node : rest) text len pos cont =
568
+ matchNode node text len pos (\next -> matchSeq rest text len next cont)
569
+
570
+ matchRepeat :: Node -> Int -> Maybe Int -> Bool -> Int -> String -> Int -> Int -> (Int -> Bool) -> Bool
571
+ matchRepeat inner low high greedy count text len pos cont =
572
+ if greedy then takemore || stopnow else stopnow || takemore
573
+ where
574
+ canmore = maybe True (count <) high
575
+
576
+ takemore =
577
+ canmore
578
+ && matchNode
579
+ inner
580
+ text
581
+ len
582
+ pos
583
+ -- A zero-width repeat would loop forever.
584
+ (\next -> next > pos && matchRepeat inner low high greedy (count + 1) text len next cont)
585
+
586
+ stopnow = count >= low && cont pos
587
+
588
+ -- | Is the pattern found anywhere in the text?
589
+ regexFind :: String -> String -> Bool
590
+ regexFind pattern text = case regexParse pattern of
591
+ Nothing -> False
592
+ Just root -> any (\start -> matchNode root text len start (const True)) [0 .. len]
593
+ where
594
+ len = length text
595
+
596
+ -- ---- runner ----------------------------------------------------------
597
+
598
+ -- | The function under test. Arguments arrive as JSON values; failure is
599
+ -- reported by throwing.
600
+ type Subject = [Json] -> IO Json
601
+
602
+ -- | A subject that may REPLACE its arguments, which @match.args@ can then
603
+ -- assert on. @minor/setpath@ is the case in point: eight of its nine entries
604
+ -- assert that the store was rewritten in place, and @merge/integrity@ all six.
605
+ --
606
+ -- Haskell's 'Json' is immutable, so a consumer holding a converted copy has no
607
+ -- way to write through the argument list even when its own nodes are mutable
608
+ -- (struct/haskell keeps them in 'IORef' cells). Returning the arguments
609
+ -- alongside the result is the only channel there is.
610
+ --
611
+ -- Separate from 'Subject' rather than replacing it: a signature change would
612
+ -- break every consumer for a capability most subjects do not need. omni-rust,
613
+ -- omni-cpp, omni-ocaml and omni-elixir carry the same pair, for the same
614
+ -- reason.
615
+ type SubjectArgs = [Json] -> IO ([Json], Json)
616
+
617
+ -- | Run-time options for a set of test entries.
618
+ data Flags = Flags {flagNull :: Bool, flagName :: Maybe String}
619
+
620
+ defaultFlags :: Flags
621
+ defaultFlags = Flags {flagNull = True, flagName = Nothing}
622
+
623
+ nonullFlags :: Flags
624
+ nonullFlags = Flags {flagNull = False, flagName = Nothing}
625
+
626
+ -- | The host of the system under test. Every hook is optional.
627
+ data Provider = Provider
628
+ { providerSubject :: Maybe (String -> Maybe Subject),
629
+ providerClient :: Maybe (Json -> Provider),
630
+ providerContextify :: Maybe (Json -> Json),
631
+ providerInject :: Maybe (Json -> Json -> Json),
632
+ -- | Build the @match.err@ base from the failure, REPLACING 'errify'.
633
+ --
634
+ -- Haskell reaches this point with a message and nothing else, so a
635
+ -- library whose errors carry a code has no other way to put one in
636
+ -- the base. The hook receives that message and returns the base,
637
+ -- letting a spec assert @match: {err: {code: "x"}}@ instead of
638
+ -- pattern-matching prose.
639
+ providerErrify :: Maybe (String -> Json)
640
+ }
641
+
642
+ emptyProvider :: Provider
643
+ emptyProvider =
644
+ Provider
645
+ { providerSubject = Nothing,
646
+ providerClient = Nothing,
647
+ providerContextify = Nothing,
648
+ providerInject = Nothing,
649
+ providerErrify = Nothing
650
+ }
651
+
652
+ -- | What a runner returns for one named spec section.
653
+ data RunPack = RunPack
654
+ { packSpec :: Json,
655
+ packSet :: String -> Json,
656
+ runset :: Json -> Maybe Subject -> IO (),
657
+ runsetFlags :: Json -> Flags -> Maybe Subject -> IO (),
658
+ -- | Everything 'runsetFlags' does, for a subject that may replace its
659
+ -- arguments. See 'SubjectArgs'.
660
+ runsetFlagsArgs :: Json -> Flags -> SubjectArgs -> IO (),
661
+ packSubject :: Maybe Subject,
662
+ packClient :: Provider
663
+ }
664
+
665
+ -- | The newest spec format version this runner understands. A spec with
666
+ -- no OMNI block is version 0: the original, lenient format, frozen
667
+ -- forever. Version 1 turns on strict entry validation (see checkentry).
668
+ specversion :: Int
669
+ specversion = 1
670
+
671
+ -- | Capability strings this runner supports beyond the version baseline.
672
+ -- A spec's OMNI.requires list is checked against this: an unknown
673
+ -- capability refuses the spec loudly at load time, instead of a lagging
674
+ -- port silently mis-running it. (Empty today; future format features
675
+ -- mint a string here.)
676
+ capabilities :: [String]
677
+ capabilities = []
678
+
679
+ -- | The complete set of fields an entry may carry. Under version 1
680
+ -- anything else is an error: an unrecognised key is almost always a
681
+ -- typo'd assertion, and a typo'd assertion is a test that silently
682
+ -- stopped testing.
683
+ entryfields :: [String]
684
+ entryfields = ["in", "args", "ctx", "out", "err", "match", "client", "id", "doc"]
685
+
686
+ -- | Read the spec's format version from its optional top-level OMNI
687
+ -- block, and refuse a spec this runner cannot faithfully run: a version
688
+ -- newer than specversion, or a required capability not in capabilities.
689
+ resolveversion :: Json -> IO Int
690
+ resolveversion alltests
691
+ -- A present-but-null (or otherwise non-map) OMNI block is malformed;
692
+ -- only a genuinely absent key is legacy version 0 - presence, not
693
+ -- definedness, is the test.
694
+ | not (jhas alltests "OMNI") = pure 0
695
+ | otherwise = do
696
+ let meta = jget alltests "OMNI"
697
+
698
+ version <- case (asmap meta, asnum (jget meta "version")) of
699
+ (Just _, Just num)
700
+ | num == fromIntegral (truncate num :: Integer) -> pure (round num :: Int)
701
+ _ -> throwIO (OmniError "omni: malformed OMNI version block")
702
+
703
+ if version < 0 || specversion < version
704
+ then throwIO (OmniError ("omni: unsupported spec version: " ++ show version))
705
+ else pure ()
706
+
707
+ -- `requires` present but null (or otherwise not a list) is
708
+ -- malformed; a genuinely absent key skips the check.
709
+ if jhas meta "requires"
710
+ then case aslist (jget meta "requires") of
711
+ Nothing -> throwIO (OmniError "omni: malformed OMNI requires list")
712
+ Just caps -> mapM_ checkcap caps
713
+ else pure ()
714
+
715
+ pure version
716
+ where
717
+ checkcap cap = case asstr cap of
718
+ Just text | text `elem` capabilities -> pure ()
719
+ _ -> throwIO (OmniError ("omni: spec requires unsupported capability: " ++ stringify cap))
720
+
721
+ -- | Strict entry validation, applied when the spec declares version 1 or
722
+ -- later. The lenient format converts each of these mistakes into a
723
+ -- silent pass or a dead field; here they fail with the entry named.
724
+ checkentry :: String -> Int -> Json -> IO ()
725
+ checkentry label index entry
726
+ | not (ismap entry) = throwIO (failure label index entry "entry is not a map" Nothing Nothing)
727
+ | otherwise = do
728
+ mapM_ checkfield (map fst (fromMaybe [] (asmap entry)))
729
+
730
+ let argsources = length (filter (jhas entry) ["in", "args", "ctx"])
731
+ if 1 < argsources
732
+ then throwIO (failure label index entry "entry has more than one of in, args, ctx" Nothing Nothing)
733
+ else pure ()
734
+
735
+ if not (isnone (jget entry "err")) && jhas entry "out"
736
+ then throwIO (failure label index entry "entry has both err and out" Nothing Nothing)
737
+ else pure ()
738
+
739
+ -- Presence, not definedness: an authored `id: null` must fail here,
740
+ -- before null-normalisation can rewrite it into a sentinel string.
741
+ let entryid = jget entry "id"
742
+ if not (isabsent entryid) && not (isJust (asstr entryid))
743
+ then throwIO (failure label index entry "entry id is not a string" Nothing Nothing)
744
+ else pure ()
745
+ where
746
+ checkfield key =
747
+ if key `elem` entryfields
748
+ then pure ()
749
+ else throwIO (failure label index entry ("unknown entry field: " ++ key) Nothing Nothing)
750
+
751
+ -- | Validate a version-1 group up front, against the AUTHORED entries -
752
+ -- null-normalisation would otherwise rewrite an authored null (e.g.
753
+ -- id: null) into a sentinel string and hide it from validation. A
754
+ -- malformed spec is a spec error, not a test result, so it fails before
755
+ -- any subject runs.
756
+ checkset :: String -> Json -> [Json] -> IO ()
757
+ checkset label testspec normalset = do
758
+ let origset = case (asmap testspec, aslist (jget testspec "set")) of
759
+ (Just _, Just list) -> list
760
+ _ -> normalset
761
+
762
+ isemptymarked = case jget testspec "empty" of
763
+ Bool True -> True
764
+ _ -> False
765
+
766
+ if null origset && not isemptymarked
767
+ then throwIO (OmniError ("omni: empty test set: " ++ label))
768
+ else pure ()
769
+
770
+ mapM_ (\(index, entry) -> checkentry label index entry) (zip [0 :: Int ..] origset)
771
+
772
+ -- | Find @primary.\<name\>@, then @\<name\>@, then the whole spec.
773
+ resolvespec :: String -> Json -> Json
774
+ resolvespec name alltests
775
+ | null name = alltests
776
+ | not (isabsent primary) = primary
777
+ | not (isabsent section) = section
778
+ | otherwise = alltests
779
+ where
780
+ primary = jget (jget alltests "primary") name
781
+ section = jget alltests name
782
+
783
+ -- | Nulls (and absent values) become NULLMARK. Always a fresh copy.
784
+ fixjson :: Json -> Bool -> Json
785
+ fixjson value donull
786
+ -- Canonical returns the value UNCHANGED when donull is false
787
+ -- (typescript/src/Runner.ts): absent stays absent and null stays null.
788
+ -- Answering Null for both collapsed two states the corpus distinguishes,
789
+ -- so a subject that correctly returned nothing was compared against null
790
+ -- and marked wrong. Same defect the other ports carried (#17, #23, #25,
791
+ -- #26, #27); this one was missed because no consumer had exercised it.
792
+ | isnone value = if donull then Str nullmark else value
793
+ | otherwise = case value of
794
+ JList entries -> JList (map (`fixjson` donull) entries)
795
+ JMap entries -> JMap (map (\(key, entry) -> (key, fixjson entry donull)) entries)
796
+ other -> other
797
+
798
+ -- | The JSON form of an error: always at least {name,message}.
799
+ errify :: String -> Json
800
+ errify message = JMap [("name", Str "Error"), ("message", Str message)]
801
+
802
+ -- | The message an @err@ expectation matches.
803
+ errmessage :: SomeException -> String
804
+ errmessage = displayException
805
+
806
+ -- | Match one leaf: \/regex\/ or case-insensitive substring for strings.
807
+ matchval :: Json -> Json -> Bool
808
+ matchval check base
809
+ | deepequal check base = True
810
+ | isnone want = isnone base || asstr base == Just nullmark
811
+ | otherwise = case asstr want of
812
+ -- An empty want is not a wildcard: the empty string is a substring of
813
+ -- everything, so `match:{out:""}` (or `err:""`) would accept any value.
814
+ Just "" -> asstr base == Just ""
815
+ Just text ->
816
+ let basestr = stringify base
817
+ in if length text > 2 && "/" `isPrefixOf` text && "/" == [last text]
818
+ then regexFind (init (drop 1 text)) basestr
819
+ else map toLower text `isInfixOf` map toLower basestr
820
+ Nothing -> deepequal want base
821
+ where
822
+ want = case asstr check of
823
+ Just text | text == undefmark || text == nullmark -> Null
824
+ _ -> check
825
+
826
+ -- | Convert NULLMARK sentinels back into real nulls.
827
+ nullmodifier :: Json -> Json
828
+ nullmodifier value = case asstr value of
829
+ Just text | text == nullmark -> Null
830
+ Just text -> Str (replace nullmark "null" text)
831
+ Nothing -> value
832
+ where
833
+ replace _ _ [] = []
834
+ replace from to text@(ch : rest)
835
+ | from `isPrefixOf` text = to ++ replace from to (drop (length from) text)
836
+ | otherwise = ch : replace from to rest
837
+
838
+ -- The spec-defined part of an entry (drop runner bookkeeping).
839
+ entrysummary :: Json -> Json
840
+ entrysummary (JMap entries) =
841
+ JMap (filter (\(key, _) -> key /= "res" && key /= "thrown" && key /= "ctx") entries)
842
+ entrysummary other = other
843
+
844
+ -- The label of one entry, for failure messages.
845
+ entryref :: String -> Int -> Json -> String
846
+ entryref label index entry = label ++ "[" ++ show index ++ "]" ++ idpart
847
+ where
848
+ entryid = jget entry "id"
849
+ idpart = if isabsent entryid then "" else " (" ++ stringify entryid ++ ")"
850
+
851
+ failure :: String -> Int -> Json -> String -> Maybe String -> Maybe String -> OmniError
852
+ failure label index entry reason expected actual =
853
+ OmniError
854
+ ( "omni: "
855
+ ++ entryref label index entry
856
+ ++ ": "
857
+ ++ reason
858
+ ++ maybe "" ("\n expected: " ++) expected
859
+ ++ maybe "" ("\n actual: " ++) actual
860
+ ++ "\n entry: "
861
+ ++ stringify (entrysummary entry)
862
+ )
863
+
864
+ -- Check that every leaf of `check` is present, and matches, in `base`.
865
+ matchcheck :: String -> Int -> Json -> Json -> Json -> [String] -> IO ()
866
+ matchcheck label index entry check base path = case check of
867
+ JList entries ->
868
+ mapM_
869
+ (\(at, subcheck) -> matchcheck label index entry subcheck base (path ++ [show at]))
870
+ (zip [0 :: Int ..] entries)
871
+ JMap entries ->
872
+ mapM_
873
+ (\(key, subcheck) -> matchcheck label index entry subcheck base (path ++ [key]))
874
+ entries
875
+ leaf -> checkleaf leaf
876
+ where
877
+ place = if null path then "<root>" else pathify path
878
+ baseval = getpath base path
879
+
880
+ bad reason expected actual =
881
+ throwIO (failure label index entry (reason ++ place) (Just expected) (Just actual))
882
+
883
+ -- The sentinels are tested BEFORE the identity check below.
884
+ -- Otherwise a subject returning the literal string "__UNDEF__"
885
+ -- satisfies an assertion that the key is absent - two mutually
886
+ -- exclusive states passing one check. A sentinel that accepts its own
887
+ -- literal is not a sentinel. (NULLMARK still accepts NULLMARK: under
888
+ -- the default null flag a real null has already been normalised to
889
+ -- it, so the two are genuinely indistinguishable here - that one
890
+ -- needs a raw-value escape, not an ordering change.)
891
+ checkleaf leaf
892
+ -- Explicitly absent: satisfied only by a genuinely missing key,
893
+ -- never by a present null (the distinction the sentinels keep).
894
+ | asstr leaf == Just undefmark =
895
+ if isabsent baseval
896
+ then pure ()
897
+ else bad "expected absent at " "absent" (stringify baseval)
898
+ -- Explicitly null: satisfied only by a present null.
899
+ | asstr leaf == Just nullmark =
900
+ if isnull baseval || asstr baseval == Just nullmark
901
+ then pure ()
902
+ else bad "expected null at " "null" (stringify baseval)
903
+ -- Explicitly present: any present value, including null.
904
+ | asstr leaf == Just existsmark =
905
+ if not (isabsent baseval)
906
+ then pure ()
907
+ else bad "expected present at " "present" "absent"
908
+ -- Identical values match. This sits below the sentinel branches on
909
+ -- purpose - see the note above.
910
+ | deepequal leaf baseval = pure ()
911
+ -- A concrete expectation never matches a missing key - a match
912
+ -- leaf against an absent value must fail, not substring-match
913
+ -- "undefined".
914
+ | isabsent baseval = bad "match failed at " (stringify leaf) "absent"
915
+ | matchval leaf baseval = pure ()
916
+ | otherwise = bad "match failed at " (stringify leaf) (stringify baseval)
917
+
918
+ checkresult :: String -> Int -> Json -> [Json] -> Json -> IO ()
919
+ checkresult label index entry args res = do
920
+ let entryerr = jget entry "err"
921
+
922
+ if not (isnone entryerr)
923
+ then
924
+ throwIO
925
+ ( failure
926
+ label
927
+ index
928
+ entry
929
+ "expected error did not occur"
930
+ (Just (stringify entryerr))
931
+ (Just (stringify res))
932
+ )
933
+ else pure ()
934
+
935
+ let check = jget entry "match"
936
+ matched = not (isnone check)
937
+
938
+ if matched
939
+ then
940
+ matchcheck
941
+ label
942
+ index
943
+ entry
944
+ check
945
+ ( JMap
946
+ [ ("in", jget entry "in"),
947
+ ("args", JList args),
948
+ ("out", jget entry "res"),
949
+ ("ctx", jget entry "ctx")
950
+ ]
951
+ )
952
+ []
953
+ else pure ()
954
+
955
+ let out = jget entry "out"
956
+
957
+ if deepequal res out
958
+ then pure ()
959
+ else
960
+ -- NOTE: a match with no explicit out is a complete check on its own.
961
+ if matched && (isnone out || asstr out == Just nullmark)
962
+ then pure ()
963
+ else
964
+ throwIO
965
+ (failure label index entry "result mismatch" (Just (stringify out)) (Just (stringify res)))
966
+
967
+ -- | The error base a @match.err@ sees: the provider's own, when it has one.
968
+ errbase :: String -> Provider -> Json
969
+ errbase message provider = case providerErrify provider of
970
+ Just hook -> hook message
971
+ Nothing -> errify message
972
+
973
+ handleerror :: String -> Int -> Json -> String -> Provider -> IO ()
974
+ handleerror label index entry message provider = do
975
+ let entryerr = jget entry "err"
976
+
977
+ if isnone entryerr
978
+ then throwIO (failure label index entry "unexpected error" Nothing (Just message))
979
+ else do
980
+ let istrue = case entryerr of
981
+ Bool True -> True
982
+ _ -> False
983
+
984
+ if istrue || matchval entryerr (Str message)
985
+ then do
986
+ let check = jget entry "match"
987
+ if not (isnone check)
988
+ then
989
+ matchcheck
990
+ label
991
+ index
992
+ entry
993
+ check
994
+ ( JMap
995
+ [ ("in", jget entry "in"),
996
+ ("out", jget entry "res"),
997
+ ("ctx", jget entry "ctx"),
998
+ ("err", errbase message provider)
999
+ ]
1000
+ )
1001
+ []
1002
+ else pure ()
1003
+ else
1004
+ throwIO
1005
+ ( failure
1006
+ label
1007
+ index
1008
+ entry
1009
+ "error mismatch"
1010
+ (Just (stringify entryerr))
1011
+ (Just message)
1012
+ )
1013
+
1014
+ -- | Make a runner for a spec value and a provider.
1015
+ makeRunnerSpec :: Json -> Provider -> String -> IO RunPack
1016
+ makeRunnerSpec alltests provider name = do
1017
+ -- Resolved once, immediately after the spec is available - fail fast on
1018
+ -- an unsupported version rather than mid-run.
1019
+ specver <- resolveversion alltests
1020
+
1021
+ let spec = resolvespec name alltests
1022
+
1023
+ clients = case (asmap (jget (jget spec "DEF") "client"), providerClient provider) of
1024
+ (Just entries, Just clientmaker) ->
1025
+ map
1026
+ ( \(clientname, cdef) ->
1027
+ let copts = jget (jget cdef "test") "options"
1028
+ in (clientname, clientmaker (if isabsent copts then JMap [] else copts))
1029
+ )
1030
+ entries
1031
+ _ -> []
1032
+
1033
+ defsubject = case providerSubject provider of
1034
+ Just resolve | not (null name) -> resolve name
1035
+ _ -> Nothing
1036
+
1037
+ runsetflags testspec flags testsubject =
1038
+ drive testspec flags testsubject Nothing
1039
+
1040
+ runsetflagsargs testspec flags argsubject =
1041
+ drive testspec flags Nothing (Just argsubject)
1042
+
1043
+ drive testspec flags testsubject argsubject = do
1044
+ let label = fromMaybe (if null name then "set" else name) (flagName flags)
1045
+
1046
+ subject <- case (argsubject, testsubject, defsubject) of
1047
+ (Just _, _, _) -> pure Nothing
1048
+ (Nothing, Just found, _) -> pure (Just found)
1049
+ (Nothing, Nothing, Just found) -> pure (Just found)
1050
+ _ -> throwIO (OmniError ("omni: no test subject for: " ++ label))
1051
+
1052
+ let testspecmap = fixjson testspec (flagNull flags)
1053
+
1054
+ testset <- case aslist (jget testspecmap "set") of
1055
+ Just entries -> pure entries
1056
+ Nothing -> throwIO (OmniError ("omni: test spec has no set: " ++ label))
1057
+
1058
+ if 1 <= specver
1059
+ then checkset label testspec testset
1060
+ else pure ()
1061
+
1062
+ mapM_ (runentry label subject argsubject clients flags) (zip [0 ..] testset)
1063
+
1064
+ runentry label subject argsubject clients' flags (index, rawentry) = do
1065
+ if not (ismap rawentry)
1066
+ then throwIO (OmniError ("omni: " ++ label ++ "[" ++ show index ++ "]: entry is not a map"))
1067
+ else pure ()
1068
+
1069
+ -- An entry with no `out` expects a null (or absent) result.
1070
+ let entry0 =
1071
+ if flagNull flags && isnone (jget rawentry "out")
1072
+ then jset rawentry "out" (Str nullmark)
1073
+ else rawentry
1074
+
1075
+ entrysubject <- case (subject, asstr (jget entry0 "client")) of
1076
+ (Nothing, _) -> pure Nothing
1077
+ (Just found, Just clientname) -> case lookup clientname clients' of
1078
+ Nothing -> throwIO (OmniError ("omni: unknown client: " ++ clientname))
1079
+ Just client -> case providerSubject client of
1080
+ Just resolve -> pure (Just (fromMaybe found (resolve name)))
1081
+ Nothing -> pure (Just found)
1082
+ (Just found, Nothing) -> pure (Just found)
1083
+
1084
+ -- Build the argument list: `ctx`, `args`, or `in`.
1085
+ let hasctx = jhas entry0 "ctx"
1086
+ hasargs = jhas entry0 "args"
1087
+
1088
+ args0
1089
+ | hasctx = [jget entry0 "ctx"]
1090
+ | hasargs = fromMaybe [jget entry0 "args"] (aslist (jget entry0 "args"))
1091
+ | otherwise = [clone (jget entry0 "in")]
1092
+
1093
+ (args, entry) =
1094
+ if (hasctx || hasargs) && not (null args0) && ismap (head args0)
1095
+ then
1096
+ let contextified = case providerContextify provider of
1097
+ Just contextify -> contextify (head args0)
1098
+ Nothing -> head args0
1099
+ -- The resolved client is a live Provider (closures
1100
+ -- over the system under test), and this port's Json
1101
+ -- carries no host-object variant to hold one - so
1102
+ -- canonical's `first.client = testpack.client`
1103
+ -- becomes presence, not identity: enough for a
1104
+ -- subject to prove the runner attached a client.
1105
+ first = jset contextified "client" (Bool True)
1106
+ in (first : tail args0, jset entry0 "ctx" first)
1107
+ else (args0, entry0)
1108
+
1109
+ -- An args-subject returns its arguments alongside the result, so
1110
+ -- `match.args` sees what the subject actually did with them.
1111
+ let invoke = case (argsubject, entrysubject) of
1112
+ (Just call, _) -> call args
1113
+ (Nothing, Just call) -> (,) args <$> call args
1114
+ (Nothing, Nothing) ->
1115
+ throwIO (OmniError ("omni: no test subject for: " ++ label))
1116
+
1117
+ outcome <- try invoke
1118
+
1119
+ case outcome of
1120
+ Right (callargs, rawres) -> do
1121
+ let res = fixjson rawres (flagNull flags)
1122
+ checkresult label index (jset entry "res" res) callargs res
1123
+ Left err -> case fromOmni err of
1124
+ Just omnierr -> throwIO omnierr
1125
+ Nothing -> handleerror label index entry (errmessage err) provider
1126
+
1127
+ pure
1128
+ RunPack
1129
+ { packSpec = spec,
1130
+ packSet = jget spec,
1131
+ runset = \testspec testsubject -> runsetflags testspec defaultFlags testsubject,
1132
+ runsetFlags = runsetflags,
1133
+ runsetFlagsArgs = runsetflagsargs,
1134
+ packSubject = defsubject,
1135
+ packClient = provider
1136
+ }
1137
+
1138
+ -- An OmniError raised inside a subject is a runner failure, not a
1139
+ -- candidate for an `err` expectation.
1140
+ fromOmni :: SomeException -> Maybe OmniError
1141
+ fromOmni = fromException
1142
+
1143
+ -- | Make a runner for a spec file path and a provider.
1144
+ makeRunner :: String -> Provider -> String -> IO RunPack
1145
+ makeRunner path provider name = do
1146
+ alltests <- loadspec path
1147
+ makeRunnerSpec alltests provider name