@voxgig/sdkgen 1.2.1 → 1.3.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 (329) hide show
  1. package/bin/voxgig-sdkgen +2 -2
  2. package/dist/action/action.d.ts +2 -1
  3. package/dist/action/action.js +15 -9
  4. package/dist/action/action.js.map +1 -1
  5. package/dist/action/feature.js +6 -3
  6. package/dist/action/feature.js.map +1 -1
  7. package/dist/action/target.d.ts +7 -1
  8. package/dist/action/target.js +13 -6
  9. package/dist/action/target.js.map +1 -1
  10. package/dist/cmp/Changelog.d.ts +2 -0
  11. package/dist/cmp/Changelog.js +30 -0
  12. package/dist/cmp/Changelog.js.map +1 -0
  13. package/dist/cmp/Deploy.d.ts +2 -0
  14. package/dist/cmp/Deploy.js +227 -0
  15. package/dist/cmp/Deploy.js.map +1 -0
  16. package/dist/cmp/FeatureHook.js +5 -6
  17. package/dist/cmp/FeatureHook.js.map +1 -1
  18. package/dist/cmp/License.d.ts +2 -0
  19. package/dist/cmp/License.js +44 -0
  20. package/dist/cmp/License.js.map +1 -0
  21. package/dist/cmp/Readme.js +2 -0
  22. package/dist/cmp/Readme.js.map +1 -1
  23. package/dist/cmp/ReadmeErrors.d.ts +2 -0
  24. package/dist/cmp/ReadmeErrors.js +210 -0
  25. package/dist/cmp/ReadmeErrors.js.map +1 -0
  26. package/dist/cmp/ReadmeExplanation.js +213 -223
  27. package/dist/cmp/ReadmeExplanation.js.map +1 -1
  28. package/dist/cmp/ReadmeModel.js +6 -1
  29. package/dist/cmp/ReadmeModel.js.map +1 -1
  30. package/dist/cmp/ReadmeTop.js +389 -82
  31. package/dist/cmp/ReadmeTop.js.map +1 -1
  32. package/dist/cmp/Security.d.ts +2 -0
  33. package/dist/cmp/Security.js +36 -0
  34. package/dist/cmp/Security.js.map +1 -0
  35. package/dist/helpers/canonType.d.ts +7 -0
  36. package/dist/helpers/canonType.js +74 -0
  37. package/dist/helpers/canonType.js.map +1 -0
  38. package/dist/helpers/collectDeps.d.ts +3 -2
  39. package/dist/helpers/collectDeps.js.map +1 -1
  40. package/dist/helpers/naming.d.ts +3 -0
  41. package/dist/helpers/naming.js +51 -0
  42. package/dist/helpers/naming.js.map +1 -0
  43. package/dist/helpers/opExample.d.ts +13 -0
  44. package/dist/helpers/opExample.js +149 -0
  45. package/dist/helpers/opExample.js.map +1 -0
  46. package/dist/helpers/opShape.d.ts +18 -0
  47. package/dist/helpers/opShape.js +193 -0
  48. package/dist/helpers/opShape.js.map +1 -0
  49. package/dist/helpers/packageMeta.d.ts +27 -0
  50. package/dist/helpers/packageMeta.js +224 -0
  51. package/dist/helpers/packageMeta.js.map +1 -0
  52. package/dist/sdkgen.d.ts +11 -1
  53. package/dist/sdkgen.js +57 -18
  54. package/dist/sdkgen.js.map +1 -1
  55. package/dist/tsconfig.tsbuildinfo +1 -1
  56. package/dist/types.d.ts +65 -2
  57. package/dist/types.js.map +1 -1
  58. package/dist/utility.js +20 -11
  59. package/dist/utility.js.map +1 -1
  60. package/model/sdkgen.aontu +137 -0
  61. package/package.json +11 -5
  62. package/project/.sdk/model/target/go-cli.jsonic +47 -0
  63. package/project/.sdk/model/target/go-mcp.jsonic +41 -0
  64. package/project/.sdk/model/target/go.jsonic +9 -3
  65. package/project/.sdk/model/target/js.jsonic +13 -0
  66. package/project/.sdk/model/target/lua.jsonic +13 -0
  67. package/project/.sdk/model/target/php.jsonic +13 -0
  68. package/project/.sdk/model/target/py.jsonic +13 -0
  69. package/project/.sdk/model/target/rb.jsonic +13 -0
  70. package/project/.sdk/model/target/ts.jsonic +13 -0
  71. package/project/.sdk/src/cmp/go/EntityOperation_go.ts +1 -0
  72. package/project/.sdk/src/cmp/go/EntityTypes_go.ts +197 -0
  73. package/project/.sdk/src/cmp/go/Entity_go.ts +2 -1
  74. package/project/.sdk/src/cmp/go/MainEntity_go.ts +6 -0
  75. package/project/.sdk/src/cmp/go/Main_go.ts +23 -3
  76. package/project/.sdk/src/cmp/go/Package_go.ts +1 -1
  77. package/project/.sdk/src/cmp/go/ReadmeEntity_go.ts +18 -6
  78. package/project/.sdk/src/cmp/go/ReadmeExamplesTest_go.ts +684 -0
  79. package/project/.sdk/src/cmp/go/ReadmeExplanation_go.ts +1 -1
  80. package/project/.sdk/src/cmp/go/ReadmeHowto_go.ts +48 -8
  81. package/project/.sdk/src/cmp/go/ReadmeInstall_go.ts +11 -6
  82. package/project/.sdk/src/cmp/go/ReadmeIntro_go.ts +40 -1
  83. package/project/.sdk/src/cmp/go/ReadmeModel_go.ts +63 -17
  84. package/project/.sdk/src/cmp/go/ReadmeOptions_go.ts +4 -3
  85. package/project/.sdk/src/cmp/go/ReadmeQuick_go.ts +124 -115
  86. package/project/.sdk/src/cmp/go/ReadmeRef_go.ts +28 -15
  87. package/project/.sdk/src/cmp/go/ReadmeTopQuick_go.ts +33 -9
  88. package/project/.sdk/src/cmp/go/ReadmeTopTest_go.ts +35 -5
  89. package/project/.sdk/src/cmp/go/TestEntity_go.ts +1 -1
  90. package/project/.sdk/src/cmp/go/Test_go.ts +5 -1
  91. package/project/.sdk/src/cmp/go/fragment/Entity.fragment.go +21 -0
  92. package/project/.sdk/src/cmp/go/fragment/EntityCreateOp.fragment.go +11 -0
  93. package/project/.sdk/src/cmp/go/fragment/EntityListOp.fragment.go +11 -0
  94. package/project/.sdk/src/cmp/go/fragment/EntityLoadOp.fragment.go +11 -0
  95. package/project/.sdk/src/cmp/go/fragment/EntityRemoveOp.fragment.go +11 -0
  96. package/project/.sdk/src/cmp/go/fragment/EntityUpdateOp.fragment.go +11 -0
  97. package/project/.sdk/src/cmp/go-cli/Main_go-cli.ts +195 -0
  98. package/project/.sdk/src/cmp/go-cli/fragment/main.fragment.go +106 -0
  99. package/project/.sdk/src/cmp/go-cli/fragment/words.fragment.go +132 -0
  100. package/project/.sdk/src/cmp/go-mcp/Main_go-mcp.ts +184 -0
  101. package/project/.sdk/src/cmp/go-mcp/fragment/main.fragment.go +68 -0
  102. package/project/.sdk/src/cmp/go-mcp/fragment/tools.fragment.go +114 -0
  103. package/project/.sdk/src/cmp/js/EntityTypes_js.ts +111 -0
  104. package/project/.sdk/src/cmp/js/MainEntity_js.ts +1 -0
  105. package/project/.sdk/src/cmp/js/Main_js.ts +3 -0
  106. package/project/.sdk/src/cmp/js/Package_js.ts +16 -7
  107. package/project/.sdk/src/cmp/js/ReadmeEntity_js.ts +13 -7
  108. package/project/.sdk/src/cmp/js/ReadmeExplanation_js.ts +2 -2
  109. package/project/.sdk/src/cmp/js/ReadmeHowto_js.ts +52 -11
  110. package/project/.sdk/src/cmp/js/ReadmeIntro_js.ts +39 -1
  111. package/project/.sdk/src/cmp/js/ReadmeModel_js.ts +50 -18
  112. package/project/.sdk/src/cmp/js/ReadmeOptions_js.ts +4 -3
  113. package/project/.sdk/src/cmp/js/ReadmeQuick_js.ts +45 -19
  114. package/project/.sdk/src/cmp/js/ReadmeRef_js.ts +24 -13
  115. package/project/.sdk/src/cmp/js/ReadmeTopHowto_js.ts +3 -0
  116. package/project/.sdk/src/cmp/js/ReadmeTopQuick_js.ts +28 -12
  117. package/project/.sdk/src/cmp/js/ReadmeTopTest_js.ts +23 -3
  118. package/project/.sdk/src/cmp/js/fragment/EntityCreateOp.fragment.js +5 -0
  119. package/project/.sdk/src/cmp/js/fragment/EntityListOp.fragment.js +5 -0
  120. package/project/.sdk/src/cmp/js/fragment/EntityLoadOp.fragment.js +5 -0
  121. package/project/.sdk/src/cmp/js/fragment/EntityRemoveOp.fragment.js +5 -0
  122. package/project/.sdk/src/cmp/js/fragment/EntityUpdateOp.fragment.js +5 -0
  123. package/project/.sdk/src/cmp/js/utility_js.ts +57 -0
  124. package/project/.sdk/src/cmp/lua/EntityTypes_lua.ts +113 -0
  125. package/project/.sdk/src/cmp/lua/MainEntity_lua.ts +8 -0
  126. package/project/.sdk/src/cmp/lua/Main_lua.ts +4 -0
  127. package/project/.sdk/src/cmp/lua/Package_lua.ts +23 -4
  128. package/project/.sdk/src/cmp/lua/ReadmeEntity_lua.ts +12 -10
  129. package/project/.sdk/src/cmp/lua/ReadmeExamplesTest_lua.ts +293 -0
  130. package/project/.sdk/src/cmp/lua/ReadmeHowto_lua.ts +46 -8
  131. package/project/.sdk/src/cmp/lua/ReadmeInstall_lua.ts +19 -3
  132. package/project/.sdk/src/cmp/lua/ReadmeIntro_lua.ts +38 -1
  133. package/project/.sdk/src/cmp/lua/ReadmeModel_lua.ts +51 -16
  134. package/project/.sdk/src/cmp/lua/ReadmeOptions_lua.ts +4 -3
  135. package/project/.sdk/src/cmp/lua/ReadmeQuick_lua.ts +79 -18
  136. package/project/.sdk/src/cmp/lua/ReadmeRef_lua.ts +25 -20
  137. package/project/.sdk/src/cmp/lua/ReadmeTopQuick_lua.ts +17 -9
  138. package/project/.sdk/src/cmp/lua/ReadmeTopTest_lua.ts +32 -5
  139. package/project/.sdk/src/cmp/lua/Test_lua.ts +4 -0
  140. package/project/.sdk/src/cmp/lua/fragment/EntityCreateOp.fragment.lua +4 -0
  141. package/project/.sdk/src/cmp/lua/fragment/EntityListOp.fragment.lua +4 -0
  142. package/project/.sdk/src/cmp/lua/fragment/EntityLoadOp.fragment.lua +4 -0
  143. package/project/.sdk/src/cmp/lua/fragment/EntityRemoveOp.fragment.lua +4 -0
  144. package/project/.sdk/src/cmp/lua/fragment/EntityUpdateOp.fragment.lua +4 -0
  145. package/project/.sdk/src/cmp/php/EntityTypes_php.ts +142 -0
  146. package/project/.sdk/src/cmp/php/MainEntity_php.ts +18 -1
  147. package/project/.sdk/src/cmp/php/Main_php.ts +4 -0
  148. package/project/.sdk/src/cmp/php/Package_php.ts +18 -7
  149. package/project/.sdk/src/cmp/php/ReadmeEntity_php.ts +15 -11
  150. package/project/.sdk/src/cmp/php/ReadmeExamplesTest_php.ts +401 -0
  151. package/project/.sdk/src/cmp/php/ReadmeHowto_php.ts +56 -13
  152. package/project/.sdk/src/cmp/php/ReadmeInstall_php.ts +15 -3
  153. package/project/.sdk/src/cmp/php/ReadmeIntro_php.ts +40 -1
  154. package/project/.sdk/src/cmp/php/ReadmeModel_php.ts +26 -8
  155. package/project/.sdk/src/cmp/php/ReadmeOptions_php.ts +4 -3
  156. package/project/.sdk/src/cmp/php/ReadmeQuick_php.ts +80 -22
  157. package/project/.sdk/src/cmp/php/ReadmeRef_php.ts +51 -42
  158. package/project/.sdk/src/cmp/php/ReadmeTopHowto_php.ts +1 -1
  159. package/project/.sdk/src/cmp/php/ReadmeTopQuick_php.ts +19 -11
  160. package/project/.sdk/src/cmp/php/ReadmeTopTest_php.ts +41 -11
  161. package/project/.sdk/src/cmp/php/TestDirect_php.ts +9 -9
  162. package/project/.sdk/src/cmp/php/TestEntity_php.ts +6 -12
  163. package/project/.sdk/src/cmp/php/Test_php.ts +4 -0
  164. package/project/.sdk/src/cmp/php/fragment/Entity.fragment.php +13 -1
  165. package/project/.sdk/src/cmp/php/fragment/EntityCreateOp.fragment.php +10 -1
  166. package/project/.sdk/src/cmp/php/fragment/EntityListOp.fragment.php +10 -1
  167. package/project/.sdk/src/cmp/php/fragment/EntityLoadOp.fragment.php +10 -1
  168. package/project/.sdk/src/cmp/php/fragment/EntityRemoveOp.fragment.php +10 -1
  169. package/project/.sdk/src/cmp/php/fragment/EntityUpdateOp.fragment.php +10 -1
  170. package/project/.sdk/src/cmp/php/fragment/Main.fragment.php +22 -14
  171. package/project/.sdk/src/cmp/py/EntityTypes_py.ts +184 -0
  172. package/project/.sdk/src/cmp/py/Entity_py.ts +27 -0
  173. package/project/.sdk/src/cmp/py/MainEntity_py.ts +2 -1
  174. package/project/.sdk/src/cmp/py/Main_py.ts +35 -0
  175. package/project/.sdk/src/cmp/py/Package_py.ts +24 -3
  176. package/project/.sdk/src/cmp/py/ReadmeEntity_py.ts +27 -11
  177. package/project/.sdk/src/cmp/py/ReadmeExamplesTest_py.ts +626 -0
  178. package/project/.sdk/src/cmp/py/ReadmeHowto_py.ts +53 -14
  179. package/project/.sdk/src/cmp/py/ReadmeInstall_py.ts +19 -3
  180. package/project/.sdk/src/cmp/py/ReadmeIntro_py.ts +48 -1
  181. package/project/.sdk/src/cmp/py/ReadmeModel_py.ts +28 -10
  182. package/project/.sdk/src/cmp/py/ReadmeOptions_py.ts +4 -3
  183. package/project/.sdk/src/cmp/py/ReadmeQuick_py.ts +73 -24
  184. package/project/.sdk/src/cmp/py/ReadmeRef_py.ts +57 -37
  185. package/project/.sdk/src/cmp/py/ReadmeTopHowto_py.ts +1 -1
  186. package/project/.sdk/src/cmp/py/ReadmeTopQuick_py.ts +19 -11
  187. package/project/.sdk/src/cmp/py/ReadmeTopTest_py.ts +30 -5
  188. package/project/.sdk/src/cmp/py/TestDirect_py.ts +7 -9
  189. package/project/.sdk/src/cmp/py/TestEntity_py.ts +6 -14
  190. package/project/.sdk/src/cmp/py/Test_py.ts +4 -0
  191. package/project/.sdk/src/cmp/py/fragment/Entity.fragment.py +5 -2
  192. package/project/.sdk/src/cmp/py/fragment/EntityCreateOp.fragment.py +1 -1
  193. package/project/.sdk/src/cmp/py/fragment/EntityListOp.fragment.py +5 -1
  194. package/project/.sdk/src/cmp/py/fragment/EntityLoadOp.fragment.py +6 -1
  195. package/project/.sdk/src/cmp/py/fragment/EntityRemoveOp.fragment.py +6 -1
  196. package/project/.sdk/src/cmp/py/fragment/EntityUpdateOp.fragment.py +1 -1
  197. package/project/.sdk/src/cmp/py/fragment/Main.fragment.py +17 -10
  198. package/project/.sdk/src/cmp/rb/EntityTypes_rb.ts +136 -0
  199. package/project/.sdk/src/cmp/rb/MainEntity_rb.ts +1 -0
  200. package/project/.sdk/src/cmp/rb/Main_rb.ts +4 -0
  201. package/project/.sdk/src/cmp/rb/Package_rb.ts +34 -7
  202. package/project/.sdk/src/cmp/rb/ReadmeEntity_rb.ts +26 -10
  203. package/project/.sdk/src/cmp/rb/ReadmeExamplesTest_rb.ts +289 -0
  204. package/project/.sdk/src/cmp/rb/ReadmeHowto_rb.ts +72 -21
  205. package/project/.sdk/src/cmp/rb/ReadmeInstall_rb.ts +16 -4
  206. package/project/.sdk/src/cmp/rb/ReadmeIntro_rb.ts +40 -1
  207. package/project/.sdk/src/cmp/rb/ReadmeModel_rb.ts +29 -12
  208. package/project/.sdk/src/cmp/rb/ReadmeOptions_rb.ts +4 -3
  209. package/project/.sdk/src/cmp/rb/ReadmeQuick_rb.ts +85 -22
  210. package/project/.sdk/src/cmp/rb/ReadmeRef_rb.ts +56 -37
  211. package/project/.sdk/src/cmp/rb/ReadmeTopHowto_rb.ts +1 -1
  212. package/project/.sdk/src/cmp/rb/ReadmeTopQuick_rb.ts +19 -11
  213. package/project/.sdk/src/cmp/rb/ReadmeTopTest_rb.ts +43 -11
  214. package/project/.sdk/src/cmp/rb/TestDirect_rb.ts +9 -9
  215. package/project/.sdk/src/cmp/rb/TestEntity_rb.ts +6 -12
  216. package/project/.sdk/src/cmp/rb/Test_rb.ts +4 -0
  217. package/project/.sdk/src/cmp/rb/fragment/Entity.fragment.rb +2 -0
  218. package/project/.sdk/src/cmp/rb/fragment/EntityCreateOp.fragment.rb +5 -0
  219. package/project/.sdk/src/cmp/rb/fragment/EntityListOp.fragment.rb +20 -2
  220. package/project/.sdk/src/cmp/rb/fragment/EntityLoadOp.fragment.rb +8 -1
  221. package/project/.sdk/src/cmp/rb/fragment/EntityRemoveOp.fragment.rb +6 -1
  222. package/project/.sdk/src/cmp/rb/fragment/EntityUpdateOp.fragment.rb +5 -0
  223. package/project/.sdk/src/cmp/rb/fragment/Main.fragment.rb +24 -8
  224. package/project/.sdk/src/cmp/ts/EntityTypes_ts.ts +105 -0
  225. package/project/.sdk/src/cmp/ts/Entity_ts.ts +17 -1
  226. package/project/.sdk/src/cmp/ts/MainEntity_ts.ts +1 -0
  227. package/project/.sdk/src/cmp/ts/Main_ts.ts +6 -0
  228. package/project/.sdk/src/cmp/ts/Package_ts.ts +14 -7
  229. package/project/.sdk/src/cmp/ts/ReadmeEntity_ts.ts +13 -7
  230. package/project/.sdk/src/cmp/ts/ReadmeExampleTest_ts.ts +81 -0
  231. package/project/.sdk/src/cmp/ts/ReadmeExamplesTest_ts.ts +446 -0
  232. package/project/.sdk/src/cmp/ts/ReadmeExplanation_ts.ts +2 -2
  233. package/project/.sdk/src/cmp/ts/ReadmeHowto_ts.ts +57 -11
  234. package/project/.sdk/src/cmp/ts/ReadmeInstall_ts.ts +19 -6
  235. package/project/.sdk/src/cmp/ts/ReadmeIntro_ts.ts +39 -1
  236. package/project/.sdk/src/cmp/ts/ReadmeModel_ts.ts +50 -18
  237. package/project/.sdk/src/cmp/ts/ReadmeOptions_ts.ts +4 -3
  238. package/project/.sdk/src/cmp/ts/ReadmeQuick_ts.ts +95 -40
  239. package/project/.sdk/src/cmp/ts/ReadmeRef_ts.ts +24 -13
  240. package/project/.sdk/src/cmp/ts/ReadmeTopHowto_ts.ts +3 -0
  241. package/project/.sdk/src/cmp/ts/ReadmeTopQuick_ts.ts +44 -12
  242. package/project/.sdk/src/cmp/ts/ReadmeTopTest_ts.ts +23 -3
  243. package/project/.sdk/src/cmp/ts/TestEntity_ts.ts +2 -2
  244. package/project/.sdk/src/cmp/ts/Test_ts.ts +5 -0
  245. package/project/.sdk/src/cmp/ts/fragment/Entity.fragment.ts +3 -1
  246. package/project/.sdk/src/cmp/ts/fragment/EntityBase.fragment.ts +10 -5
  247. package/project/.sdk/src/cmp/ts/fragment/EntityCreateOp.fragment.ts +4 -2
  248. package/project/.sdk/src/cmp/ts/fragment/EntityListOp.fragment.ts +4 -2
  249. package/project/.sdk/src/cmp/ts/fragment/EntityLoadOp.fragment.ts +4 -2
  250. package/project/.sdk/src/cmp/ts/fragment/EntityRemoveOp.fragment.ts +4 -2
  251. package/project/.sdk/src/cmp/ts/fragment/EntityUpdateOp.fragment.ts +4 -2
  252. package/project/.sdk/src/cmp/ts/utility_ts.ts +59 -0
  253. package/project/.sdk/tm/go/LICENSE +1 -1
  254. package/project/.sdk/tm/go/Makefile +36 -1
  255. package/project/.sdk/tm/go/VERSION +1 -0
  256. package/project/.sdk/tm/go/core/context.go +12 -7
  257. package/project/.sdk/tm/go-cli/src/feature/README.md +6 -0
  258. package/project/.sdk/tm/go-cli/src/feature/base/.gitkeep +0 -0
  259. package/project/.sdk/tm/go-cli/src/feature/log/.gitkeep +0 -0
  260. package/project/.sdk/tm/go-cli/src/feature/test/.gitkeep +0 -0
  261. package/project/.sdk/tm/go-mcp/src/feature/README.md +6 -0
  262. package/project/.sdk/tm/go-mcp/src/feature/base/.gitkeep +0 -0
  263. package/project/.sdk/tm/go-mcp/src/feature/log/.gitkeep +0 -0
  264. package/project/.sdk/tm/go-mcp/src/feature/test/.gitkeep +0 -0
  265. package/project/.sdk/tm/js/LICENSE +1 -1
  266. package/project/.sdk/tm/js/Makefile +41 -0
  267. package/project/.sdk/tm/lua/LICENSE +1 -1
  268. package/project/.sdk/tm/lua/Makefile +40 -1
  269. package/project/.sdk/tm/lua/core/context.lua +13 -8
  270. package/project/.sdk/tm/php/LICENSE +1 -1
  271. package/project/.sdk/tm/php/Makefile +31 -1
  272. package/project/.sdk/tm/php/VERSION +1 -0
  273. package/project/.sdk/tm/php/core/Context.php +12 -6
  274. package/project/.sdk/tm/php/test/PrimaryUtilityTest.php +13 -4
  275. package/project/.sdk/tm/php/utility/Done.php +2 -2
  276. package/project/.sdk/tm/php/utility/MakeError.php +3 -3
  277. package/project/.sdk/tm/py/LICENSE +1 -1
  278. package/project/.sdk/tm/py/Makefile +34 -1
  279. package/project/.sdk/tm/py/core/context.py +12 -7
  280. package/project/.sdk/tm/py/test/test_primary_utility.py +15 -4
  281. package/project/.sdk/tm/py/utility/done.py +3 -1
  282. package/project/.sdk/tm/py/utility/make_error.py +2 -2
  283. package/project/.sdk/tm/rb/LICENSE +1 -1
  284. package/project/.sdk/tm/rb/Makefile +33 -1
  285. package/project/.sdk/tm/rb/core/context.rb +8 -3
  286. package/project/.sdk/tm/rb/test/primary_utility_test.rb +2 -2
  287. package/project/.sdk/tm/rb/utility/done.rb +3 -1
  288. package/project/.sdk/tm/rb/utility/make_error.rb +5 -2
  289. package/project/.sdk/tm/ts/LICENSE +1 -1
  290. package/project/.sdk/tm/ts/Makefile +42 -0
  291. package/project/.sdk/tm/ts/src/Context.ts +8 -3
  292. package/src/action/action.ts +17 -10
  293. package/src/action/feature.ts +8 -6
  294. package/src/action/target.ts +17 -8
  295. package/src/cmp/Changelog.ts +34 -0
  296. package/src/cmp/Deploy.ts +258 -0
  297. package/src/cmp/FeatureHook.ts +6 -8
  298. package/src/cmp/License.ts +49 -0
  299. package/src/cmp/Readme.ts +2 -0
  300. package/src/cmp/ReadmeErrors.ts +257 -0
  301. package/src/cmp/ReadmeExplanation.ts +250 -230
  302. package/src/cmp/ReadmeModel.ts +7 -2
  303. package/src/cmp/ReadmeTop.ts +411 -95
  304. package/src/cmp/Security.ts +41 -0
  305. package/src/helpers/canonType.ts +89 -0
  306. package/src/helpers/collectDeps.ts +5 -3
  307. package/src/helpers/naming.ts +59 -0
  308. package/src/helpers/opExample.ts +170 -0
  309. package/src/helpers/opShape.ts +236 -0
  310. package/src/helpers/packageMeta.ts +236 -0
  311. package/src/sdkgen.ts +87 -20
  312. package/src/tsconfig.json +1 -0
  313. package/src/types.ts +85 -2
  314. package/src/utility.ts +22 -11
  315. package/README.md +0 -2
  316. package/dist/action/lang.d.ts +0 -2
  317. package/dist/action/lang.js +0 -68
  318. package/dist/action/lang.js.map +0 -1
  319. package/dist/cmp/Hook.d.ts +0 -2
  320. package/dist/cmp/Hook.js +0 -10
  321. package/dist/cmp/Hook.js.map +0 -1
  322. package/dist/cmp/Top.d.ts +0 -2
  323. package/dist/cmp/Top.js +0 -23
  324. package/dist/cmp/Top.js.map +0 -1
  325. package/dist/prepare-openapi.d.ts +0 -2
  326. package/dist/prepare-openapi.js +0 -37
  327. package/dist/prepare-openapi.js.map +0 -1
  328. package/model/sdkgen.jsonic +0 -74
  329. package/project/.sdk/tm/go/utility/struct/go.mod +0 -3
@@ -0,0 +1,626 @@
1
+
2
+ import { cmp, each, File, Content } from '@voxgig/sdkgen'
3
+
4
+ import {
5
+ KIT,
6
+ getModelPath,
7
+ nom,
8
+ } from '@voxgig/apidef'
9
+
10
+
11
+ // Emits py/test/test_readme_examples.py — a pytest COMPLETENESS GATE over
12
+ // every ```python fenced block in the repository ROOT README.md, in the
13
+ // per-language py/README.md, AND in the per-language py/REFERENCE.md.
14
+ //
15
+ // The gate GUARANTEES every documented python example is unit-tested. For each
16
+ // of the three docs it:
17
+ // 1. extracts every ```python block (tagged by source doc + index);
18
+ // 2. ast.parse + compile()s EVERY block -> SYNTAX gate;
19
+ // 3. EXECUTEs every RUNNABLE block (one that constructs the SDK, or drives a
20
+ // `client`/`sdk` the narrative built earlier) in a seeded, offline
21
+ // TEST-mode subprocess. A PROGRAMMING error
22
+ // (Name/Attribute/Type/Key/Index/Import/Syntax) FAILS; ONLY a
23
+ // not-found/404 domain error is tolerated. Any other error also FAILS;
24
+ // 4. asserts COMPLETENESS: it partitions every block into exactly one of
25
+ // {executed, compiled-nonrunnable, illustration} and asserts
26
+ // total == executed + compiled + illustration. "illustration" is a NARROW
27
+ // explicit class (a non-runnable block that is only imports / signature
28
+ // stubs / bare references / literal assignments — a pure signature/table
29
+ // snippet) and can NEVER absorb a runnable example. A block that looks
30
+ // runnable (references the SDK/client) but was not executed FAILS the
31
+ // test; a block that fails to compile FAILS the test. A per-doc summary
32
+ // (total/executed/compiled/illustration) is printed.
33
+ //
34
+ // If mypy is importable it also type-checks the concatenated ROOT README blocks
35
+ // (the SDK ships py.typed + TypedDicts) — a bonus TYPE gate over the primary
36
+ // EXECUTE gate.
37
+ //
38
+ // The emitted Python is written WITHOUT backticks or backslashes (chr(96) is
39
+ // the fence marker, chr(10) is newline) so this TS template literal stays
40
+ // clean — the only interpolations are the SDK module/class names and the
41
+ // generated entity map.
42
+ const ReadmeExamplesTest = cmp(function ReadmeExamplesTest(props: any) {
43
+ const { target, ctx$: { model } } = props
44
+
45
+ const Name = model.const.Name
46
+ const sdkModule = Name.toLowerCase() + '_sdk'
47
+ const sdkClass = Name + 'SDK'
48
+
49
+ // The API's capitalised semantic entities, mapped to their lowercase
50
+ // fixture key: { "Fact": "fact", "User": "user" }. Used at runtime to seed
51
+ // a mock record for every entity a README block references.
52
+ const entities = each(getModelPath(model, `main.${KIT}.entity`))
53
+ .filter((e: any) => e.active !== false)
54
+ const entitiesLiteral = 0 === entities.length
55
+ ? '{}'
56
+ : '{\n' + entities
57
+ .map((e: any) => ` "${nom(e, 'Name')}": "${e.name}",`)
58
+ .join('\n') + '\n}'
59
+
60
+ File({ name: 'test_readme_examples.' + target.ext }, () => {
61
+ Content(`# ${Name} SDK — documentation python-examples COMPLETENESS gate.
62
+ #
63
+ # GUARANTEE: every python example in the docs is unit-tested. This module is a
64
+ # completeness gate over every python fenced code block in three documents:
65
+ # - the repository ROOT README.md (one directory above the py/ package),
66
+ # - the per-language py/README.md (tutorial, how-to, error-handling,
67
+ # testing and entity-op examples — in the package root),
68
+ # - the per-language py/REFERENCE.md (in the package root).
69
+ # It exists to keep the documented examples honest as the generator evolves:
70
+ # no runnable example may be silently skipped, and no block may be dropped.
71
+ #
72
+ # Checks, in order, PER DOCUMENT:
73
+ #
74
+ # 1. COMPILE: every python block is parsed with ast.parse + compile(). This
75
+ # catches syntax errors in the docs (e.g. a dict key with no value, or a
76
+ # hyphenated import module name that is not valid Python).
77
+ #
78
+ # 2. EXECUTE (the primary safety net): every RUNNABLE block is run offline in
79
+ # a seeded TEST-mode subprocess. A block is RUNNABLE when it constructs the
80
+ # SDK (mentions ${sdkClass}) OR drives a client/sdk variable the narrative
81
+ # built earlier ("client." / "sdk."). A constructing block is rewritten so
82
+ # both ${sdkClass}(...) and ${sdkClass}.test(...) become
83
+ # ${sdkClass}.test({"entity": {...}}) seeding one mock record (id "test01")
84
+ # per referenced entity; a client-driving block gets that seeded test
85
+ # client injected first, then runs verbatim. Any PROGRAMMING error
86
+ # (NameError / AttributeError / TypeError / KeyError / IndexError /
87
+ # ImportError / SyntaxError / IndentationError) FAILS the test. ONLY a
88
+ # not-found / 404 domain error is tolerated (it proves the snippet is
89
+ # structurally valid Python that drives the SDK against an unseeded id).
90
+ # Any other runtime error also FAILS. This surfaces real bugs — a snippet
91
+ # calling a method that does not exist raises AttributeError; indexing
92
+ # result["err"] on a direct() envelope with no err key raises KeyError.
93
+ #
94
+ # 3. COMPLETENESS: every block is partitioned into exactly one of
95
+ # {executed, compiled-nonrunnable, illustration} and the test asserts
96
+ # total == executed + compiled + illustration. "illustration" is a NARROW
97
+ # explicit class — a non-runnable block whose every top-level statement is
98
+ # an import, a signature stub, a bare reference, or a literal assignment (a
99
+ # pure signature/table snippet). It can never absorb a runnable example: a
100
+ # block that references the SDK/client is classified RUNNABLE first and
101
+ # MUST execute. If a runnable block is not executed, the test FAILS. A
102
+ # per-doc summary line (total/executed/compiled/illustration) is printed.
103
+ #
104
+ # 4. TYPECHECK (only if mypy is importable): the ROOT README blocks are
105
+ # concatenated and type-checked with mypy as a bonus gate over the primary
106
+ # EXECUTE gate. Only errors mypy attributes to the snippet file fail;
107
+ # import-resolution noise is inconclusive.
108
+
109
+ import ast
110
+ import os
111
+ import subprocess
112
+ import sys
113
+ import tempfile
114
+
115
+ import pytest
116
+
117
+
118
+ _TEST_DIR = os.path.dirname(os.path.abspath(__file__))
119
+ _PY_ROOT = os.path.dirname(_TEST_DIR) # the py/ package root
120
+ _README = os.path.abspath(os.path.join(_PY_ROOT, "..", "README.md")) # repo root
121
+ _REFERENCE = os.path.join(_PY_ROOT, "REFERENCE.md") # per-language reference
122
+ _LOCAL_README = os.path.join(_PY_ROOT, "README.md") # per-language README
123
+
124
+ _FENCE = chr(96) * 3 # the triple-backtick markdown code fence
125
+ _NL = chr(10) # newline
126
+ _WS = (chr(32), chr(9), chr(13), chr(10)) # space, tab, CR, LF
127
+
128
+ _SDK_MODULE = "${sdkModule}"
129
+ _SDK_CLASS = "${sdkClass}"
130
+
131
+ # The variable names the generated narrative examples bind the client to. A doc
132
+ # reads as a sequence: an early snippet builds the client, later snippets drive
133
+ # it. A block that uses "client." or "sdk." without building one gets a seeded
134
+ # test client injected under those names so it runs standalone.
135
+ _CLIENT_VARS = ("client", "sdk")
136
+
137
+ # The API's capitalised semantic entities -> lowercase fixture key.
138
+ _ENTITIES = ${entitiesLiteral}
139
+
140
+ # The three documents held to the gate, tagged by human label.
141
+ _DOCS = (
142
+ ("root README", _README),
143
+ ("py README.md", _LOCAL_README),
144
+ ("py REFERENCE.md", _REFERENCE),
145
+ )
146
+
147
+
148
+ def _read_doc(path, label):
149
+ if not os.path.exists(path):
150
+ pytest.skip(label + " not found: " + path)
151
+ with open(path, "r", encoding="utf-8") as fh:
152
+ return fh.read()
153
+
154
+
155
+ def _blocks_in(text):
156
+ # Split on the code fence: odd-indexed segments are the inside of a fenced
157
+ # block (an info string on the first line, then the code). No regex, no
158
+ # backslashes — keeps this robust and generator-friendly. Only fences whose
159
+ # info string is exactly "python" are returned, so signature/markdown
160
+ # tables (plain text or other fences) are skipped.
161
+ parts = text.split(_FENCE)
162
+ blocks = []
163
+ for i in range(1, len(parts), 2):
164
+ seg = parts[i]
165
+ lines = seg.split(_NL)
166
+ info = lines[0].strip()
167
+ if info == "python":
168
+ blocks.append(_NL.join(lines[1:]))
169
+ return blocks
170
+
171
+
172
+ def _python_blocks():
173
+ return _blocks_in(_read_doc(_README, "root README"))
174
+
175
+
176
+ def _reference_blocks():
177
+ return _blocks_in(_read_doc(_REFERENCE, "py REFERENCE.md"))
178
+
179
+
180
+ def _local_readme_blocks():
181
+ return _blocks_in(_read_doc(_LOCAL_README, "py README.md"))
182
+
183
+
184
+ # ----------------------------------------------------------------------------
185
+ # Presence + COMPILE (syntax) gate
186
+ # ----------------------------------------------------------------------------
187
+
188
+ def test_readme_has_python_blocks():
189
+ assert len(_python_blocks()) > 0, "expected at least one python block in the root README"
190
+
191
+
192
+ def test_reference_has_python_blocks():
193
+ assert len(_reference_blocks()) > 0, "expected at least one python block in py/REFERENCE.md"
194
+
195
+
196
+ def test_local_readme_has_python_blocks():
197
+ assert len(_local_readme_blocks()) > 0, "expected at least one python block in py/README.md"
198
+
199
+
200
+ def _assert_blocks_compile(blocks, label):
201
+ # Syntax gate: every documented python block must parse and compile. Catches
202
+ # a bad constructor import such as a hyphenated module name
203
+ # ("from my-slug_sdk import ...") which is a Python SyntaxError.
204
+ for i, block in enumerate(blocks):
205
+ try:
206
+ ast.parse(block)
207
+ compile(block, "<" + label + "-block-" + str(i) + ">", "exec")
208
+ except SyntaxError as err:
209
+ pytest.fail(
210
+ label + " python block #" + str(i)
211
+ + " is not valid Python: " + str(err) + _NL + _NL + block
212
+ )
213
+
214
+
215
+ def test_readme_python_blocks_compile():
216
+ _assert_blocks_compile(_python_blocks(), "root README")
217
+
218
+
219
+ def test_reference_python_blocks_compile():
220
+ _assert_blocks_compile(_reference_blocks(), "py REFERENCE.md")
221
+
222
+
223
+ def test_local_readme_python_blocks_compile():
224
+ _assert_blocks_compile(_local_readme_blocks(), "py README.md")
225
+
226
+
227
+ # ----------------------------------------------------------------------------
228
+ # TYPECHECK (bonus, root README only, if mypy is importable)
229
+ # ----------------------------------------------------------------------------
230
+
231
+ def _mypy_available():
232
+ try:
233
+ import mypy # noqa: F401
234
+ return True
235
+ except Exception:
236
+ return False
237
+
238
+
239
+ def test_readme_python_blocks_typecheck():
240
+ # Type gate: concatenate the blocks and run mypy over them. Only fails on
241
+ # errors mypy attributes to our snippet file; environmental import noise is
242
+ # inconclusive (skipped). When mypy is unavailable the execute gate below
243
+ # is the safety net.
244
+ if not _mypy_available():
245
+ pytest.skip("mypy not importable — covered by the execute gate")
246
+
247
+ source = (_NL + _NL).join(_python_blocks()) + _NL
248
+
249
+ with tempfile.TemporaryDirectory() as td:
250
+ snippet_path = os.path.join(td, "readme_snippets.py")
251
+ with open(snippet_path, "w", encoding="utf-8") as fh:
252
+ fh.write(source)
253
+
254
+ env = dict(os.environ)
255
+ env["PYTHONDONTWRITEBYTECODE"] = "1"
256
+ # Resolve "from _SDK_MODULE import _SDK_CLASS" against the package root.
257
+ env["MYPYPATH"] = _PY_ROOT + os.pathsep + env.get("MYPYPATH", "")
258
+
259
+ proc = subprocess.run(
260
+ [
261
+ sys.executable, "-m", "mypy",
262
+ "--no-error-summary",
263
+ "--no-color-output",
264
+ "--follow-imports=silent", # use SDK types, silence SDK-internal errors
265
+ "--ignore-missing-imports",
266
+ snippet_path,
267
+ ],
268
+ cwd=_PY_ROOT,
269
+ env=env,
270
+ capture_output=True,
271
+ text=True,
272
+ )
273
+
274
+ base = os.path.basename(snippet_path)
275
+ output = (proc.stdout or "") + (proc.stderr or "")
276
+ errors = []
277
+ for line in output.split(_NL):
278
+ if base in line and ": error:" in line:
279
+ if "Cannot find implementation or library stub" in line:
280
+ continue
281
+ if "Skipping analyzing" in line:
282
+ continue
283
+ errors.append(line)
284
+
285
+ if errors:
286
+ pytest.fail(
287
+ "mypy found type errors in the root README python snippets:"
288
+ + _NL + _NL.join(errors) + _NL + _NL + "--- snippets ---" + _NL + source
289
+ )
290
+
291
+
292
+ # ----------------------------------------------------------------------------
293
+ # Classification: runnable / illustration / compiled-nonrunnable
294
+ # ----------------------------------------------------------------------------
295
+
296
+ def _uses_var(block, var):
297
+ # True if the block reads an attribute off the whole-word variable "var"
298
+ # (i.e. contains "var." with a non-identifier char, or nothing, before it).
299
+ # This distinguishes a client-driving "sdk." from the "_sdk." tail of an
300
+ # import module name.
301
+ needle = var + "."
302
+ start = 0
303
+ while True:
304
+ j = block.find(needle, start)
305
+ if j < 0:
306
+ return False
307
+ ok_before = True
308
+ if j > 0:
309
+ ch = block[j - 1]
310
+ if ch.isalnum() or ch == "_":
311
+ ok_before = False
312
+ if ok_before:
313
+ return True
314
+ start = j + 1
315
+
316
+
317
+ def _is_runnable(block):
318
+ # A block is RUNNABLE — and therefore MUST be executed — when it constructs
319
+ # the SDK (mentions the class) or drives a client/sdk the narrative built.
320
+ if _SDK_CLASS in block:
321
+ return True
322
+ for var in _CLIENT_VARS:
323
+ if _uses_var(block, var):
324
+ return True
325
+ return False
326
+
327
+
328
+ def _is_literalish(value):
329
+ # A right-hand side that performs no function call (a literal, name, or
330
+ # collection display). Keeps the "illustration" class narrow.
331
+ for sub in ast.walk(value):
332
+ if isinstance(sub, ast.Call):
333
+ return False
334
+ return True
335
+
336
+
337
+ def _is_illustration_node(node):
338
+ # A single "shape only" statement: an import, a bare reference/literal
339
+ # (not a call), a signature stub (def/class whose body is only pass /
340
+ # docstring / ...), or a literal assignment.
341
+ if isinstance(node, (ast.Import, ast.ImportFrom)):
342
+ return True
343
+ if isinstance(node, ast.Expr):
344
+ return not isinstance(node.value, ast.Call)
345
+ if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)):
346
+ for b in node.body:
347
+ if isinstance(b, ast.Pass):
348
+ continue
349
+ if isinstance(b, ast.Expr) and isinstance(b.value, ast.Constant):
350
+ continue
351
+ return False
352
+ return True
353
+ if isinstance(node, ast.AnnAssign):
354
+ return node.value is None or _is_literalish(node.value)
355
+ if isinstance(node, ast.Assign):
356
+ return _is_literalish(node.value)
357
+ return False
358
+
359
+
360
+ def _is_illustration(block):
361
+ # NARROW, explicit: a non-runnable block whose every top-level statement is
362
+ # a benign "shape" node — an import, a bare reference/literal, a signature
363
+ # stub, or a literal assignment (a pure signature/table snippet). Anything
364
+ # that does work (a call, a loop, a with/try) is NOT an illustration; it
365
+ # falls to the compiled-nonrunnable bucket. A runnable block (references the
366
+ # SDK/client) is never an illustration, so this class can never silently
367
+ # absorb a runnable example.
368
+ if _is_runnable(block):
369
+ return False
370
+ try:
371
+ tree = ast.parse(block)
372
+ except SyntaxError:
373
+ return False
374
+ if not tree.body:
375
+ return True
376
+ for node in tree.body:
377
+ if not _is_illustration_node(node):
378
+ return False
379
+ return True
380
+
381
+
382
+ def _classify(block):
383
+ if _is_runnable(block):
384
+ return "runnable"
385
+ if _is_illustration(block):
386
+ return "illustration"
387
+ return "compiled"
388
+
389
+
390
+ # ----------------------------------------------------------------------------
391
+ # EXECUTE gate
392
+ # ----------------------------------------------------------------------------
393
+
394
+ # Exception TYPE names that signal a programming (not domain) error. Matched
395
+ # against the last line of a failed subprocess's traceback.
396
+ _PROGRAMMING_ERROR_NAMES = frozenset([
397
+ "SyntaxError", "IndentationError", "NameError", "AttributeError",
398
+ "TypeError", "KeyError", "IndexError", "ImportError", "ModuleNotFoundError",
399
+ ])
400
+
401
+
402
+ def _seed_literal(block):
403
+ # Build a test() fixture seeding one mock record (id "test01") for every
404
+ # entity the block references, so list()/load() resolve offline. Detection
405
+ # is by the "client.<Entity>(" factory call the generated examples use.
406
+ seeded = {}
407
+ for cap, key in _ENTITIES.items():
408
+ if ("." + cap + "(") in block:
409
+ seeded[key] = {"test01": {"id": "test01"}}
410
+ return {"entity": seeded}
411
+
412
+
413
+ def _rewrite_to_test_mode(block):
414
+ # Force every client construction into offline test mode with seeded
415
+ # fixtures: both _SDK_CLASS(...) (live) and _SDK_CLASS.test(...) become
416
+ # _SDK_CLASS.test({"entity": {...}}). Balanced-paren aware, so a
417
+ # multi-line constructor argument is consumed whole. A bare mention of the
418
+ # class name (e.g. in an import) is left untouched.
419
+ seed = repr(_seed_literal(block))
420
+ replacement = _SDK_CLASS + ".test(" + seed + ")"
421
+ out = []
422
+ i = 0
423
+ n = len(block)
424
+ while True:
425
+ j = block.find(_SDK_CLASS, i)
426
+ if j < 0:
427
+ out.append(block[i:])
428
+ break
429
+ out.append(block[i:j])
430
+ k = j + len(_SDK_CLASS)
431
+ if block[k:k + 5] == ".test":
432
+ k += 5
433
+ while k < n and block[k] in _WS:
434
+ k += 1
435
+ if k < n and block[k] == "(":
436
+ depth = 0
437
+ m = k
438
+ while m < n:
439
+ c = block[m]
440
+ if c == "(":
441
+ depth += 1
442
+ elif c == ")":
443
+ depth -= 1
444
+ if depth == 0:
445
+ m += 1
446
+ break
447
+ m += 1
448
+ out.append(replacement)
449
+ i = m
450
+ else:
451
+ # Not a construction (e.g. "from ..._sdk import _SDK_CLASS") —
452
+ # keep the original text verbatim.
453
+ out.append(block[j:k])
454
+ i = k
455
+ return "".join(out)
456
+
457
+
458
+ def _build_exec_source(block):
459
+ # Return runnable python source for a RUNNABLE block, else None. A block
460
+ # that constructs the SDK is rewritten into seeded test mode; a block that
461
+ # only drives a client/sdk gets a seeded test client injected under those
462
+ # names first, then runs verbatim. The set of blocks for which this returns
463
+ # a source is exactly the set _is_runnable() flags — the completeness gate
464
+ # asserts that, so no runnable block is ever silently skipped.
465
+ preamble = "import os" + _NL + "from " + _SDK_MODULE + " import " + _SDK_CLASS + _NL
466
+ if _SDK_CLASS in block:
467
+ return preamble + _rewrite_to_test_mode(block)
468
+ inject = ""
469
+ used = False
470
+ seed = repr(_seed_literal(block))
471
+ for var in _CLIENT_VARS:
472
+ if _uses_var(block, var):
473
+ inject += var + " = " + _SDK_CLASS + ".test(" + seed + ")" + _NL
474
+ used = True
475
+ if used:
476
+ return preamble + inject + block
477
+ return None
478
+
479
+
480
+ def _is_not_found_error(last):
481
+ # The ONLY tolerated domain error: a not-found / 404 raised because a
482
+ # referenced id was not seeded. Detected by the SDK error message text.
483
+ low = last.lower()
484
+ return ("404" in last) or ("not found" in low) or ("notfound" in low)
485
+
486
+
487
+ def _run_source(source, label, index):
488
+ # Run one rewritten block in a subprocess. Returns None when it exits 0 or
489
+ # fails with the single tolerated not-found/404 domain error; otherwise
490
+ # returns a failure message (a programming error, or any other runtime
491
+ # error — both fail the gate).
492
+ env = dict(os.environ)
493
+ env["PYTHONDONTWRITEBYTECODE"] = "1"
494
+ env["PYTHONPATH"] = _PY_ROOT + os.pathsep + env.get("PYTHONPATH", "")
495
+
496
+ proc = subprocess.run(
497
+ [sys.executable, "-c", source],
498
+ cwd=_PY_ROOT,
499
+ env=env,
500
+ capture_output=True,
501
+ text=True,
502
+ )
503
+ if proc.returncode == 0:
504
+ return None
505
+
506
+ stderr = proc.stderr or ""
507
+ errlines = [ln for ln in stderr.split(_NL) if ln.strip()]
508
+ last = errlines[-1] if errlines else ""
509
+ # Traceback's final line is "ExceptionType: message"; the type may be
510
+ # dotted (module-qualified) so compare the short name.
511
+ exc_type = last.split(":", 1)[0].strip().split(".")[-1]
512
+
513
+ detail = (
514
+ label + " python block #" + str(index) + ": " + last + _NL + _NL
515
+ + "--- executed source ---" + _NL + source
516
+ + _NL + _NL + "--- stderr ---" + _NL + stderr
517
+ )
518
+
519
+ if exc_type in _PROGRAMMING_ERROR_NAMES:
520
+ return "PROGRAMMING ERROR in " + detail
521
+ if _is_not_found_error(last):
522
+ return None # tolerated domain error
523
+ return "UNEXPECTED (non not-found/404) ERROR in " + detail
524
+
525
+
526
+ # ----------------------------------------------------------------------------
527
+ # COMPLETENESS gate (the guarantee)
528
+ # ----------------------------------------------------------------------------
529
+
530
+ def _completeness_gate(label, blocks):
531
+ # Partition every block, execute every runnable one, and assert the
532
+ # partition is complete. Returns the per-doc stats dict.
533
+ total = len(blocks)
534
+ executed = 0
535
+ runnable = 0
536
+ illustration = 0
537
+ compiled = 0
538
+ failures = []
539
+
540
+ for i, block in enumerate(blocks):
541
+ kind = _classify(block)
542
+ if kind == "runnable":
543
+ runnable += 1
544
+ source = _build_exec_source(block)
545
+ if source is None:
546
+ # Should be impossible: _is_runnable and _build_exec_source key
547
+ # off the same markers. If it ever happens a runnable example
548
+ # would be silently skipped — fail loudly.
549
+ failures.append(
550
+ label + " python block #" + str(i) + " is runnable-looking "
551
+ "(references the SDK/client) but produced no executable "
552
+ "source; it would be silently skipped:" + _NL + _NL + block
553
+ )
554
+ continue
555
+ executed += 1
556
+ msg = _run_source(source, label, i)
557
+ if msg is not None:
558
+ failures.append(msg)
559
+ elif kind == "illustration":
560
+ illustration += 1
561
+ else:
562
+ compiled += 1
563
+
564
+ print(
565
+ _NL + "[readme-examples] " + label + " python blocks: total="
566
+ + str(total) + " executed=" + str(executed) + " compiled="
567
+ + str(compiled) + " illustration=" + str(illustration)
568
+ )
569
+
570
+ if failures:
571
+ pytest.fail(
572
+ label + ": " + str(len(failures))
573
+ + " documented python example(s) failed the completeness gate:"
574
+ + _NL + _NL + (_NL + _NL).join(failures)
575
+ )
576
+
577
+ # Every runnable (SDK/client-referencing) block MUST have executed.
578
+ assert executed == runnable, (
579
+ label + ": " + str(runnable - executed) + " runnable python block(s) "
580
+ "were not executed — a documented example that drives the SDK/client "
581
+ "must run, never be silently skipped (executed=" + str(executed)
582
+ + ", runnable=" + str(runnable) + ")"
583
+ )
584
+ # Every block is accounted for by exactly one bucket.
585
+ assert total == executed + compiled + illustration, (
586
+ label + ": python-block accounting does not add up — total=" + str(total)
587
+ + " but executed+compiled+illustration="
588
+ + str(executed + compiled + illustration)
589
+ + ". Every block must be executed, compiled-nonrunnable, or a narrow "
590
+ "illustration; none may be dropped."
591
+ )
592
+ return {
593
+ "total": total,
594
+ "executed": executed,
595
+ "compiled": compiled,
596
+ "illustration": illustration,
597
+ }
598
+
599
+
600
+ def test_readme_completeness_gate():
601
+ stats = _completeness_gate("root README", _python_blocks())
602
+ assert stats["executed"] > 0, (
603
+ "expected at least one runnable python block in the root README to execute"
604
+ )
605
+
606
+
607
+ def test_local_readme_completeness_gate():
608
+ stats = _completeness_gate("py README.md", _local_readme_blocks())
609
+ assert stats["executed"] > 0, (
610
+ "expected at least one runnable python block in py/README.md to execute"
611
+ )
612
+
613
+
614
+ def test_reference_completeness_gate():
615
+ stats = _completeness_gate("py REFERENCE.md", _reference_blocks())
616
+ assert stats["executed"] > 0, (
617
+ "expected at least one runnable python block in py/REFERENCE.md to execute"
618
+ )
619
+ `)
620
+ })
621
+ })
622
+
623
+
624
+ export {
625
+ ReadmeExamplesTest
626
+ }