@voxgig/sdkgen 2.0.1 → 3.0.0

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 (394) hide show
  1. package/bin/voxgig-sdkgen +22 -2
  2. package/dist/action/doctor.d.ts +14 -0
  3. package/dist/action/doctor.js +296 -0
  4. package/dist/action/doctor.js.map +1 -0
  5. package/dist/action/feature.js +48 -9
  6. package/dist/action/feature.js.map +1 -1
  7. package/dist/action/target.d.ts +6 -1
  8. package/dist/action/target.js +134 -22
  9. package/dist/action/target.js.map +1 -1
  10. package/dist/cmp/Entity.js +5 -0
  11. package/dist/cmp/Entity.js.map +1 -1
  12. package/dist/cmp/Feature.js +2 -1
  13. package/dist/cmp/Feature.js.map +1 -1
  14. package/dist/cmp/Main.js +5 -1
  15. package/dist/cmp/Main.js.map +1 -1
  16. package/dist/cmp/ReadmeExplanation.js +1 -1
  17. package/dist/cmp/ReadmeExplanation.js.map +1 -1
  18. package/dist/cmp/ReadmeTop.js +16 -6
  19. package/dist/cmp/ReadmeTop.js.map +1 -1
  20. package/dist/cmp/Registered.d.ts +7 -0
  21. package/dist/cmp/Registered.js +70 -0
  22. package/dist/cmp/Registered.js.map +1 -0
  23. package/dist/cmp/Test.js +3 -1
  24. package/dist/cmp/Test.js.map +1 -1
  25. package/dist/helpers/dryrun.d.ts +10 -0
  26. package/dist/helpers/dryrun.js +35 -0
  27. package/dist/helpers/dryrun.js.map +1 -0
  28. package/dist/helpers/featureSource.d.ts +13 -0
  29. package/dist/helpers/featureSource.js +156 -0
  30. package/dist/helpers/featureSource.js.map +1 -0
  31. package/dist/helpers/naming.d.ts +9 -1
  32. package/dist/helpers/naming.js +66 -2
  33. package/dist/helpers/naming.js.map +1 -1
  34. package/dist/helpers/opExample.js +23 -3
  35. package/dist/helpers/opExample.js.map +1 -1
  36. package/dist/helpers/opShape.d.ts +11 -1
  37. package/dist/helpers/opShape.js +51 -0
  38. package/dist/helpers/opShape.js.map +1 -1
  39. package/dist/helpers/packageMeta.d.ts +8 -1
  40. package/dist/helpers/packageMeta.js +141 -10
  41. package/dist/helpers/packageMeta.js.map +1 -1
  42. package/dist/helpers/stdrep.d.ts +3 -0
  43. package/dist/helpers/stdrep.js +47 -0
  44. package/dist/helpers/stdrep.js.map +1 -0
  45. package/dist/helpers/testPolicy.d.ts +2 -0
  46. package/dist/helpers/testPolicy.js +46 -0
  47. package/dist/helpers/testPolicy.js.map +1 -0
  48. package/dist/sdkgen.d.ts +15 -6
  49. package/dist/sdkgen.js +45 -4
  50. package/dist/sdkgen.js.map +1 -1
  51. package/dist/tsconfig.tsbuildinfo +1 -1
  52. package/model/sdkgen.aontu +125 -0
  53. package/package.json +8 -5
  54. package/project/.sdk/model/target/c.aontu +28 -3
  55. package/project/.sdk/model/target/clojure.aontu +24 -3
  56. package/project/.sdk/model/target/cpp.aontu +25 -3
  57. package/project/.sdk/model/target/csharp.aontu +25 -3
  58. package/project/.sdk/model/target/dart.aontu +15 -3
  59. package/project/.sdk/model/target/elixir.aontu +15 -3
  60. package/project/.sdk/model/target/go-cli.aontu +17 -1
  61. package/project/.sdk/model/target/go-mcp.aontu +17 -1
  62. package/project/.sdk/model/target/go.aontu +14 -4
  63. package/project/.sdk/model/target/haskell.aontu +24 -3
  64. package/project/.sdk/model/target/java.aontu +26 -3
  65. package/project/.sdk/model/target/js.aontu +15 -3
  66. package/project/.sdk/model/target/kotlin.aontu +26 -3
  67. package/project/.sdk/model/target/lean.aontu +25 -3
  68. package/project/.sdk/model/target/lua.aontu +15 -3
  69. package/project/.sdk/model/target/ocaml.aontu +24 -3
  70. package/project/.sdk/model/target/perl.aontu +15 -3
  71. package/project/.sdk/model/target/php.aontu +15 -3
  72. package/project/.sdk/model/target/py-data.aontu +16 -3
  73. package/project/.sdk/model/target/py.aontu +15 -3
  74. package/project/.sdk/model/target/rb.aontu +15 -3
  75. package/project/.sdk/model/target/rust.aontu +25 -3
  76. package/project/.sdk/model/target/scala.aontu +25 -3
  77. package/project/.sdk/model/target/swift.aontu +25 -3
  78. package/project/.sdk/model/target/ts.aontu +15 -3
  79. package/project/.sdk/model/target/zig.aontu +26 -3
  80. package/project/.sdk/src/cmp/c/Config_c.ts +10 -11
  81. package/project/.sdk/src/cmp/c/Entity_c.ts +5 -1
  82. package/project/.sdk/src/cmp/c/fragment/Entity.fragment.c +23 -5
  83. package/project/.sdk/src/cmp/c/fragment/EntityCreateOp.fragment.c +9 -2
  84. package/project/.sdk/src/cmp/c/fragment/EntityListOp.fragment.c +19 -2
  85. package/project/.sdk/src/cmp/c/fragment/EntityLoadOp.fragment.c +9 -2
  86. package/project/.sdk/src/cmp/c/fragment/EntityRemoveOp.fragment.c +12 -2
  87. package/project/.sdk/src/cmp/c/fragment/EntityUpdateOp.fragment.c +9 -2
  88. package/project/.sdk/src/cmp/c/fragment/Main.fragment.c +1 -0
  89. package/project/.sdk/src/cmp/clojure/TestEntity_clojure.ts +6 -3
  90. package/project/.sdk/src/cmp/clojure/fragment/Entity.fragment.clj +18 -1
  91. package/project/.sdk/src/cmp/clojure/fragment/EntityCreateOp.fragment.clj +2 -2
  92. package/project/.sdk/src/cmp/clojure/fragment/EntityLoadOp.fragment.clj +2 -2
  93. package/project/.sdk/src/cmp/clojure/fragment/EntityRemoveOp.fragment.clj +12 -8
  94. package/project/.sdk/src/cmp/clojure/fragment/EntityUpdateOp.fragment.clj +2 -2
  95. package/project/.sdk/src/cmp/cpp/Entity_cpp.ts +5 -1
  96. package/project/.sdk/src/cmp/cpp/TestEntity_cpp.ts +24 -11
  97. package/project/.sdk/src/cmp/cpp/fragment/EntityCreateOp.fragment.cpp +8 -2
  98. package/project/.sdk/src/cmp/cpp/fragment/EntityListOp.fragment.cpp +18 -2
  99. package/project/.sdk/src/cmp/cpp/fragment/EntityLoadOp.fragment.cpp +8 -2
  100. package/project/.sdk/src/cmp/cpp/fragment/EntityRemoveOp.fragment.cpp +11 -2
  101. package/project/.sdk/src/cmp/cpp/fragment/EntityUpdateOp.fragment.cpp +8 -2
  102. package/project/.sdk/src/cmp/csharp/Package_csharp.ts +2 -1
  103. package/project/.sdk/src/cmp/csharp/TestDirect_csharp.ts +3 -3
  104. package/project/.sdk/src/cmp/csharp/TestEntity_csharp.ts +6 -6
  105. package/project/.sdk/src/cmp/csharp/fragment/EntityBase.fragment.cs +38 -1
  106. package/project/.sdk/src/cmp/csharp/fragment/Main.fragment.cs +42 -33
  107. package/project/.sdk/src/cmp/dart/Config_dart.ts +6 -0
  108. package/project/.sdk/src/cmp/dart/Package_dart.ts +2 -1
  109. package/project/.sdk/src/cmp/dart/ReadmeEntity_dart.ts +13 -2
  110. package/project/.sdk/src/cmp/dart/ReadmeHowto_dart.ts +2 -1
  111. package/project/.sdk/src/cmp/dart/ReadmeInstall_dart.ts +3 -3
  112. package/project/.sdk/src/cmp/dart/ReadmeModel_dart.ts +1 -1
  113. package/project/.sdk/src/cmp/dart/ReadmeQuick_dart.ts +17 -6
  114. package/project/.sdk/src/cmp/dart/ReadmeRef_dart.ts +13 -2
  115. package/project/.sdk/src/cmp/dart/ReadmeTopQuick_dart.ts +13 -2
  116. package/project/.sdk/src/cmp/dart/TestDirect_dart.ts +3 -3
  117. package/project/.sdk/src/cmp/dart/TestEntity_dart.ts +8 -8
  118. package/project/.sdk/src/cmp/dart/fragment/EntityBase.fragment.dart +18 -1
  119. package/project/.sdk/src/cmp/dart/fragment/EntityCreateOp.fragment.dart +9 -1
  120. package/project/.sdk/src/cmp/dart/fragment/EntityLoadOp.fragment.dart +9 -1
  121. package/project/.sdk/src/cmp/dart/fragment/EntityRemoveOp.fragment.dart +15 -1
  122. package/project/.sdk/src/cmp/dart/fragment/EntityUpdateOp.fragment.dart +9 -1
  123. package/project/.sdk/src/cmp/dart/fragment/SdkError.fragment.dart +8 -0
  124. package/project/.sdk/src/cmp/elixir/Package_elixir.ts +3 -1
  125. package/project/.sdk/src/cmp/elixir/ReadmeInstall_elixir.ts +2 -2
  126. package/project/.sdk/src/cmp/elixir/ReadmeTopQuick_elixir.ts +7 -4
  127. package/project/.sdk/src/cmp/elixir/TestEntity_elixir.ts +11 -2
  128. package/project/.sdk/src/cmp/elixir/fragment/EntityCreateOp.fragment.ex +2 -1
  129. package/project/.sdk/src/cmp/elixir/fragment/EntityListOp.fragment.ex +1 -0
  130. package/project/.sdk/src/cmp/elixir/fragment/EntityLoadOp.fragment.ex +2 -1
  131. package/project/.sdk/src/cmp/elixir/fragment/EntityRemoveOp.fragment.ex +4 -1
  132. package/project/.sdk/src/cmp/elixir/fragment/EntityUpdateOp.fragment.ex +2 -1
  133. package/project/.sdk/src/cmp/go/EntityTypes_go.ts +38 -8
  134. package/project/.sdk/src/cmp/go/Entity_go.ts +2 -2
  135. package/project/.sdk/src/cmp/go/Main_go.ts +4 -5
  136. package/project/.sdk/src/cmp/go/Package_go.ts +8 -5
  137. package/project/.sdk/src/cmp/go/ReadmeExplanation_go.ts +2 -2
  138. package/project/.sdk/src/cmp/go/ReadmeHowto_go.ts +2 -2
  139. package/project/.sdk/src/cmp/go/ReadmeInstall_go.ts +4 -2
  140. package/project/.sdk/src/cmp/go/ReadmeModel_go.ts +2 -2
  141. package/project/.sdk/src/cmp/go/ReadmeQuick_go.ts +2 -2
  142. package/project/.sdk/src/cmp/go/ReadmeTopQuick_go.ts +2 -2
  143. package/project/.sdk/src/cmp/go/ReadmeTopTest_go.ts +2 -2
  144. package/project/.sdk/src/cmp/go/TestDirect_go.ts +21 -15
  145. package/project/.sdk/src/cmp/go/TestEntity_go.ts +9 -9
  146. package/project/.sdk/src/cmp/go/Test_go.ts +2 -2
  147. package/project/.sdk/src/cmp/go/fragment/Entity.fragment.go +42 -1
  148. package/project/.sdk/src/cmp/go-cli/Main_go-cli.ts +4 -4
  149. package/project/.sdk/src/cmp/go-mcp/Main_go-mcp.ts +4 -4
  150. package/project/.sdk/src/cmp/haskell/Package_haskell.ts +2 -1
  151. package/project/.sdk/src/cmp/haskell/ReadmeEntity_haskell.ts +10 -5
  152. package/project/.sdk/src/cmp/haskell/ReadmeModel_haskell.ts +10 -8
  153. package/project/.sdk/src/cmp/haskell/ReadmeQuick_haskell.ts +14 -10
  154. package/project/.sdk/src/cmp/haskell/ReadmeRef_haskell.ts +21 -18
  155. package/project/.sdk/src/cmp/haskell/ReadmeTopQuick_haskell.ts +4 -4
  156. package/project/.sdk/src/cmp/haskell/Test_haskell.ts +23 -11
  157. package/project/.sdk/src/cmp/java/Package_java.ts +2 -1
  158. package/project/.sdk/src/cmp/java/ReadmeHowto_java.ts +2 -1
  159. package/project/.sdk/src/cmp/java/ReadmeInstall_java.ts +2 -2
  160. package/project/.sdk/src/cmp/java/ReadmeModel_java.ts +1 -1
  161. package/project/.sdk/src/cmp/java/ReadmeQuick_java.ts +3 -3
  162. package/project/.sdk/src/cmp/java/TestDirect_java.ts +3 -3
  163. package/project/.sdk/src/cmp/java/TestEntity_java.ts +6 -6
  164. package/project/.sdk/src/cmp/java/fragment/EntityBase.fragment.java +34 -1
  165. package/project/.sdk/src/cmp/java/fragment/SdkError.fragment.java +12 -0
  166. package/project/.sdk/src/cmp/js/Main_js.ts +4 -1
  167. package/project/.sdk/src/cmp/js/Package_js.ts +7 -1
  168. package/project/.sdk/src/cmp/js/ReadmeEntity_js.ts +13 -2
  169. package/project/.sdk/src/cmp/js/ReadmeHowto_js.ts +2 -1
  170. package/project/.sdk/src/cmp/js/ReadmeQuick_js.ts +13 -2
  171. package/project/.sdk/src/cmp/js/ReadmeTopQuick_js.ts +13 -2
  172. package/project/.sdk/src/cmp/js/ReadmeTopTest_js.ts +2 -1
  173. package/project/.sdk/src/cmp/js/TestDirect_js.ts +3 -3
  174. package/project/.sdk/src/cmp/js/TestEntity_js.ts +8 -8
  175. package/project/.sdk/src/cmp/js/fragment/EntityBase.fragment.js +22 -1
  176. package/project/.sdk/src/cmp/js/fragment/EntityCreateOp.fragment.js +9 -1
  177. package/project/.sdk/src/cmp/js/fragment/EntityLoadOp.fragment.js +9 -1
  178. package/project/.sdk/src/cmp/js/fragment/EntityRemoveOp.fragment.js +15 -1
  179. package/project/.sdk/src/cmp/js/fragment/EntityUpdateOp.fragment.js +9 -1
  180. package/project/.sdk/src/cmp/js/fragment/SdkError.fragment.js +13 -0
  181. package/project/.sdk/src/cmp/kotlin/Package_kotlin.ts +2 -1
  182. package/project/.sdk/src/cmp/kotlin/ReadmeHowto_kotlin.ts +2 -1
  183. package/project/.sdk/src/cmp/kotlin/ReadmeInstall_kotlin.ts +2 -2
  184. package/project/.sdk/src/cmp/kotlin/ReadmeModel_kotlin.ts +1 -1
  185. package/project/.sdk/src/cmp/kotlin/ReadmeQuick_kotlin.ts +3 -3
  186. package/project/.sdk/src/cmp/kotlin/TestDirect_kotlin.ts +3 -3
  187. package/project/.sdk/src/cmp/kotlin/TestEntity_kotlin.ts +6 -6
  188. package/project/.sdk/src/cmp/kotlin/fragment/EntityBase.fragment.kt +32 -1
  189. package/project/.sdk/src/cmp/lean/Package_lean.ts +3 -1
  190. package/project/.sdk/src/cmp/lean/Test_lean.ts +75 -21
  191. package/project/.sdk/src/cmp/lua/MainEntity_lua.ts +9 -4
  192. package/project/.sdk/src/cmp/lua/Package_lua.ts +4 -3
  193. package/project/.sdk/src/cmp/lua/ReadmeModel_lua.ts +11 -3
  194. package/project/.sdk/src/cmp/lua/ReadmeQuick_lua.ts +1 -1
  195. package/project/.sdk/src/cmp/lua/TestDirect_lua.ts +3 -3
  196. package/project/.sdk/src/cmp/lua/TestEntity_lua.ts +9 -9
  197. package/project/.sdk/src/cmp/lua/fragment/Entity.fragment.lua +37 -1
  198. package/project/.sdk/src/cmp/lua/fragment/SdkError.fragment.lua +12 -0
  199. package/project/.sdk/src/cmp/ocaml/EntityOperation_ocaml.ts +30 -3
  200. package/project/.sdk/src/cmp/ocaml/Entity_ocaml.ts +11 -5
  201. package/project/.sdk/src/cmp/ocaml/Package_ocaml.ts +3 -1
  202. package/project/.sdk/src/cmp/ocaml/ReadmeEntity_ocaml.ts +10 -5
  203. package/project/.sdk/src/cmp/ocaml/ReadmeHowto_ocaml.ts +6 -2
  204. package/project/.sdk/src/cmp/ocaml/ReadmeModel_ocaml.ts +10 -8
  205. package/project/.sdk/src/cmp/ocaml/ReadmeQuick_ocaml.ts +14 -13
  206. package/project/.sdk/src/cmp/ocaml/ReadmeRef_ocaml.ts +20 -18
  207. package/project/.sdk/src/cmp/ocaml/ReadmeTopQuick_ocaml.ts +4 -4
  208. package/project/.sdk/src/cmp/ocaml/ReadmeTopTest_ocaml.ts +8 -2
  209. package/project/.sdk/src/cmp/ocaml/TestEntity_ocaml.ts +8 -5
  210. package/project/.sdk/src/cmp/perl/ReadmeHowto_perl.ts +2 -1
  211. package/project/.sdk/src/cmp/perl/ReadmeModel_perl.ts +1 -1
  212. package/project/.sdk/src/cmp/perl/ReadmeQuick_perl.ts +3 -3
  213. package/project/.sdk/src/cmp/perl/ReadmeTopQuick_perl.ts +1 -1
  214. package/project/.sdk/src/cmp/perl/TestDirect_perl.ts +3 -3
  215. package/project/.sdk/src/cmp/perl/TestEntity_perl.ts +6 -6
  216. package/project/.sdk/src/cmp/perl/fragment/Entity.fragment.pm +36 -1
  217. package/project/.sdk/src/cmp/php/MainEntity_php.ts +21 -16
  218. package/project/.sdk/src/cmp/php/Package_php.ts +2 -2
  219. package/project/.sdk/src/cmp/php/ReadmeEntity_php.ts +6 -6
  220. package/project/.sdk/src/cmp/php/ReadmeHowto_php.ts +4 -3
  221. package/project/.sdk/src/cmp/php/ReadmeIntro_php.ts +2 -2
  222. package/project/.sdk/src/cmp/php/ReadmeModel_php.ts +1 -1
  223. package/project/.sdk/src/cmp/php/ReadmeQuick_php.ts +12 -12
  224. package/project/.sdk/src/cmp/php/ReadmeRef_php.ts +6 -6
  225. package/project/.sdk/src/cmp/php/ReadmeTopQuick_php.ts +4 -4
  226. package/project/.sdk/src/cmp/php/ReadmeTopTest_php.ts +2 -2
  227. package/project/.sdk/src/cmp/php/TestDirect_php.ts +3 -3
  228. package/project/.sdk/src/cmp/php/TestEntity_php.ts +17 -15
  229. package/project/.sdk/src/cmp/php/fragment/Entity.fragment.php +20 -1
  230. package/project/.sdk/src/cmp/php/fragment/SdkError.fragment.php +11 -0
  231. package/project/.sdk/src/cmp/py/Package_py.ts +4 -3
  232. package/project/.sdk/src/cmp/py/ReadmeEntity_py.ts +13 -2
  233. package/project/.sdk/src/cmp/py/ReadmeHowto_py.ts +2 -1
  234. package/project/.sdk/src/cmp/py/ReadmeModel_py.ts +1 -1
  235. package/project/.sdk/src/cmp/py/ReadmeQuick_py.ts +17 -6
  236. package/project/.sdk/src/cmp/py/ReadmeRef_py.ts +14 -3
  237. package/project/.sdk/src/cmp/py/ReadmeTopQuick_py.ts +13 -2
  238. package/project/.sdk/src/cmp/py/TestDirect_py.ts +3 -3
  239. package/project/.sdk/src/cmp/py/TestEntity_py.ts +9 -9
  240. package/project/.sdk/src/cmp/py/Test_py.ts +4 -1
  241. package/project/.sdk/src/cmp/py/fragment/Entity.fragment.py +29 -1
  242. package/project/.sdk/src/cmp/py/fragment/SdkError.fragment.py +11 -0
  243. package/project/.sdk/src/cmp/py-data/Main_py-data.ts +2 -1
  244. package/project/.sdk/src/cmp/rb/Package_rb.ts +4 -3
  245. package/project/.sdk/src/cmp/rb/ReadmeEntity_rb.ts +1 -1
  246. package/project/.sdk/src/cmp/rb/ReadmeHowto_rb.ts +2 -1
  247. package/project/.sdk/src/cmp/rb/ReadmeQuick_rb.ts +5 -5
  248. package/project/.sdk/src/cmp/rb/ReadmeTopQuick_rb.ts +1 -1
  249. package/project/.sdk/src/cmp/rb/TestDirect_rb.ts +3 -3
  250. package/project/.sdk/src/cmp/rb/TestEntity_rb.ts +9 -9
  251. package/project/.sdk/src/cmp/rb/fragment/Entity.fragment.rb +31 -1
  252. package/project/.sdk/src/cmp/rb/fragment/SdkError.fragment.rb +10 -1
  253. package/project/.sdk/src/cmp/rust/Entity_rust.ts +5 -1
  254. package/project/.sdk/src/cmp/rust/Main_rust.ts +21 -0
  255. package/project/.sdk/src/cmp/rust/Package_rust.ts +2 -1
  256. package/project/.sdk/src/cmp/rust/TestDirect_rust.ts +3 -3
  257. package/project/.sdk/src/cmp/rust/TestEntity_rust.ts +12 -12
  258. package/project/.sdk/src/cmp/rust/fragment/Entity.fragment.rs +18 -0
  259. package/project/.sdk/src/cmp/rust/fragment/EntityCreateOp.fragment.rs +8 -2
  260. package/project/.sdk/src/cmp/rust/fragment/EntityListOp.fragment.rs +20 -3
  261. package/project/.sdk/src/cmp/rust/fragment/EntityLoadOp.fragment.rs +8 -2
  262. package/project/.sdk/src/cmp/rust/fragment/EntityRemoveOp.fragment.rs +10 -2
  263. package/project/.sdk/src/cmp/rust/fragment/EntityUpdateOp.fragment.rs +8 -2
  264. package/project/.sdk/src/cmp/rust/fragment/SdkError.fragment.rs +10 -0
  265. package/project/.sdk/src/cmp/scala/ReadmeHowto_scala.ts +2 -1
  266. package/project/.sdk/src/cmp/scala/ReadmeInstall_scala.ts +3 -3
  267. package/project/.sdk/src/cmp/scala/ReadmeModel_scala.ts +1 -1
  268. package/project/.sdk/src/cmp/scala/ReadmeQuick_scala.ts +3 -3
  269. package/project/.sdk/src/cmp/scala/TestEntity_scala.ts +3 -3
  270. package/project/.sdk/src/cmp/scala/fragment/EntityBase.fragment.scala +27 -1
  271. package/project/.sdk/src/cmp/swift/ReadmeHowto_swift.ts +2 -1
  272. package/project/.sdk/src/cmp/swift/ReadmeInstall_swift.ts +3 -3
  273. package/project/.sdk/src/cmp/swift/ReadmeModel_swift.ts +1 -1
  274. package/project/.sdk/src/cmp/swift/ReadmeQuick_swift.ts +3 -3
  275. package/project/.sdk/src/cmp/swift/fragment/EntityBase.fragment.swift +34 -1
  276. package/project/.sdk/src/cmp/ts/EntityOperation_ts.ts +9 -1
  277. package/project/.sdk/src/cmp/ts/EntityTypes_ts.ts +18 -1
  278. package/project/.sdk/src/cmp/ts/Gitignore_ts.ts +5 -2
  279. package/project/.sdk/src/cmp/ts/Main_ts.ts +4 -1
  280. package/project/.sdk/src/cmp/ts/Package_ts.ts +10 -1
  281. package/project/.sdk/src/cmp/ts/ReadmeEntity_ts.ts +13 -2
  282. package/project/.sdk/src/cmp/ts/ReadmeHowto_ts.ts +2 -1
  283. package/project/.sdk/src/cmp/ts/ReadmeQuick_ts.ts +21 -6
  284. package/project/.sdk/src/cmp/ts/ReadmeRef_ts.ts +52 -2
  285. package/project/.sdk/src/cmp/ts/ReadmeTopQuick_ts.ts +14 -3
  286. package/project/.sdk/src/cmp/ts/ReadmeTopTest_ts.ts +34 -2
  287. package/project/.sdk/src/cmp/ts/TestDirect_ts.ts +64 -43
  288. package/project/.sdk/src/cmp/ts/TestEntity_ts.ts +8 -8
  289. package/project/.sdk/src/cmp/ts/fragment/Direct.test.fragment.ts +2 -2
  290. package/project/.sdk/src/cmp/ts/fragment/Entity.test.fragment.ts +2 -2
  291. package/project/.sdk/src/cmp/ts/fragment/EntityBase.fragment.ts +25 -1
  292. package/project/.sdk/src/cmp/ts/fragment/EntityCreateOp.fragment.ts +10 -2
  293. package/project/.sdk/src/cmp/ts/fragment/EntityListOp.fragment.ts +1 -1
  294. package/project/.sdk/src/cmp/ts/fragment/EntityLoadOp.fragment.ts +10 -2
  295. package/project/.sdk/src/cmp/ts/fragment/EntityRemoveOp.fragment.ts +27 -3
  296. package/project/.sdk/src/cmp/ts/fragment/EntityUpdateOp.fragment.ts +10 -2
  297. package/project/.sdk/src/cmp/ts/fragment/SdkError.fragment.ts +15 -0
  298. package/project/.sdk/src/cmp/zig/Entity_zig.ts +5 -1
  299. package/project/.sdk/src/cmp/zig/Package_zig.ts +3 -1
  300. package/project/.sdk/src/cmp/zig/fragment/Entity.fragment.zig +39 -0
  301. package/project/.sdk/src/cmp/zig/fragment/EntityCreateOp.fragment.zig +2 -2
  302. package/project/.sdk/src/cmp/zig/fragment/EntityListOp.fragment.zig +21 -2
  303. package/project/.sdk/src/cmp/zig/fragment/EntityLoadOp.fragment.zig +2 -2
  304. package/project/.sdk/src/cmp/zig/fragment/EntityRemoveOp.fragment.zig +5 -2
  305. package/project/.sdk/src/cmp/zig/fragment/EntityUpdateOp.fragment.zig +2 -2
  306. package/project/.sdk/tm/c/VERSION +1 -1
  307. package/project/.sdk/tm/c/core/helpers.c +1 -0
  308. package/project/.sdk/tm/c/core/sdk.h +22 -6
  309. package/project/.sdk/tm/c/tests/feature_harness.h +1 -0
  310. package/project/.sdk/tm/c/tests/primary_utility_test.c +4 -1
  311. package/project/.sdk/tm/c/utility/graphql.c +1 -1
  312. package/project/.sdk/tm/c/utility/make_url.c +1 -0
  313. package/project/.sdk/tm/c/utility/param.c +1 -0
  314. package/project/.sdk/tm/clojure/VERSION +1 -1
  315. package/project/.sdk/tm/cpp/VERSION +1 -1
  316. package/project/.sdk/tm/cpp/core/types.hpp +33 -8
  317. package/project/.sdk/tm/cpp/test/pipeline_test.cpp +5 -0
  318. package/project/.sdk/tm/cpp/test/runner_support.hpp +4 -4
  319. package/project/.sdk/tm/csharp/VERSION +1 -1
  320. package/project/.sdk/tm/csharp/core/Types.cs +6 -0
  321. package/project/.sdk/tm/csharp/test/FeatureHarness.cs +396 -0
  322. package/project/.sdk/tm/csharp/test/FeatureTest.cs +7 -385
  323. package/project/.sdk/tm/csharp/test/Runner.cs +4 -4
  324. package/project/.sdk/tm/dart/lib/utility/MakeErrorUtility.dart +4 -0
  325. package/project/.sdk/tm/dart/test/utility.dart +4 -4
  326. package/project/.sdk/tm/elixir/VERSION +1 -1
  327. package/project/.sdk/tm/elixir/lib/projectname/entity_base.ex +26 -0
  328. package/project/.sdk/tm/go/VERSION +1 -1
  329. package/project/.sdk/tm/go/core/types.go +6 -0
  330. package/project/.sdk/tm/go/test/feature_harness_test.go +361 -0
  331. package/project/.sdk/tm/go/test/feature_test.go +7 -350
  332. package/project/.sdk/tm/go/test/pipeline_test.go +6 -0
  333. package/project/.sdk/tm/go/test/runner_test.go +16 -4
  334. package/project/.sdk/tm/haskell/VERSION +1 -1
  335. package/project/.sdk/tm/haskell/src/SdkFeatures.hs +28 -5
  336. package/project/.sdk/tm/haskell/src/SdkTypes.hs +14 -5
  337. package/project/.sdk/tm/java/VERSION +1 -1
  338. package/project/.sdk/tm/java/test/RunnerSupport.java +4 -4
  339. package/project/.sdk/tm/java/utility/MakeError.java +4 -0
  340. package/project/.sdk/tm/js/src/utility/MakeErrorUtility.js +4 -0
  341. package/project/.sdk/tm/js/test/utility.js +3 -3
  342. package/project/.sdk/tm/kotlin/VERSION +1 -1
  343. package/project/.sdk/tm/kotlin/core/Utility.kt +2 -0
  344. package/project/.sdk/tm/kotlin/test/RunnerSupport.kt +3 -3
  345. package/project/.sdk/tm/lean/Makefile +25 -0
  346. package/project/.sdk/tm/lean/VERSION +1 -1
  347. package/project/.sdk/tm/lean/src/SdkUtility.lean +11 -9
  348. package/project/.sdk/tm/lean/test/TFeature.lean +27 -14
  349. package/project/.sdk/tm/lean/test/TPrimaryUtility.lean +5 -2
  350. package/project/.sdk/tm/lua/test/runner.lua +4 -4
  351. package/project/.sdk/tm/lua/utility/make_error.lua +4 -0
  352. package/project/.sdk/tm/ocaml/VERSION +1 -1
  353. package/project/.sdk/tm/ocaml/sdk_types.ml +14 -5
  354. package/project/.sdk/tm/ocaml/test/t_pipeline.ml +5 -2
  355. package/project/.sdk/tm/perl/t/runner.pm +4 -4
  356. package/project/.sdk/tm/php/VERSION +1 -1
  357. package/project/.sdk/tm/php/test/Runner.php +4 -4
  358. package/project/.sdk/tm/php/utility/MakeError.php +5 -0
  359. package/project/.sdk/tm/py/pkg/utility/make_error.py +4 -0
  360. package/project/.sdk/tm/py/test/runner.py +19 -4
  361. package/project/.sdk/tm/rb/test/runner.rb +4 -4
  362. package/project/.sdk/tm/rb/utility/make_error.rb +4 -0
  363. package/project/.sdk/tm/rust/VERSION +1 -1
  364. package/project/.sdk/tm/rust/core/types.rs +22 -6
  365. package/project/.sdk/tm/rust/tests/common/mod.rs +6 -6
  366. package/project/.sdk/tm/rust/tests/pipeline_test.rs +6 -0
  367. package/project/.sdk/tm/rust/utility/make_error.rs +4 -0
  368. package/project/.sdk/tm/scala/VERSION +1 -1
  369. package/project/.sdk/tm/swift/VERSION +1 -1
  370. package/project/.sdk/tm/ts/src/tsconfig.json +1 -0
  371. package/project/.sdk/tm/ts/src/utility/MakeErrorUtility.ts +4 -0
  372. package/project/.sdk/tm/ts/test/tsconfig.json +1 -0
  373. package/project/.sdk/tm/ts/test/utility.ts +3 -3
  374. package/project/.sdk/tm/zig/VERSION +1 -1
  375. package/src/action/doctor.ts +410 -0
  376. package/src/action/feature.ts +54 -16
  377. package/src/action/target.ts +174 -25
  378. package/src/cmp/Entity.ts +7 -0
  379. package/src/cmp/Feature.ts +3 -1
  380. package/src/cmp/Main.ts +7 -1
  381. package/src/cmp/ReadmeExplanation.ts +2 -2
  382. package/src/cmp/ReadmeTop.ts +22 -9
  383. package/src/cmp/Registered.ts +100 -0
  384. package/src/cmp/Test.ts +4 -1
  385. package/src/helpers/dryrun.ts +57 -0
  386. package/src/helpers/featureSource.ts +208 -0
  387. package/src/helpers/naming.ts +73 -2
  388. package/src/helpers/opExample.ts +19 -2
  389. package/src/helpers/opShape.ts +65 -0
  390. package/src/helpers/packageMeta.ts +163 -10
  391. package/src/helpers/stdrep.ts +56 -0
  392. package/src/helpers/testPolicy.ts +52 -0
  393. package/src/sdkgen.ts +70 -4
  394. package/project/.sdk/tm/rust/feature/mod.rs +0 -24
@@ -0,0 +1,410 @@
1
+ // `voxgig-sdkgen doctor` — does this project's `.sdk/` still match the
2
+ // scaffold?
3
+ //
4
+ // WHY THIS EXISTS
5
+ //
6
+ // Nothing told a project that its `.sdk/` had drifted. `target add`
7
+ // OVERWRITES the vendored components and template masters, so any hand-edit
8
+ // there is silently reverted on the next run — and any file the scaffold has
9
+ // since stopped shipping just stays, compiling into the output forever. In
10
+ // voxgig-solardemo-sdk two such orphans broke the Go build in a single
11
+ // session: `utility/make_target.go` (replaced upstream by `make_point.go`,
12
+ // leaving a duplicate symbol) and `utility/struct/go.mod` (a nested module
13
+ // that made `utility/struct` unimportable).
14
+ //
15
+ // Every divergence in that repo was found by hand-diffing. Without a check,
16
+ // fixing it once guarantees nothing about next month.
17
+ //
18
+ // WHY A NAIVE `diff -r` DOES NOT WORK
19
+ //
20
+ // `target add` writes template masters with substitution PARTLY applied, and
21
+ // inconsistently: `tm/go/core/error.go` arrives substituted (`SolardemoError`
22
+ // where the scaffold says `ProjectNameError`), `tm/ts/test/utility.ts` arrives
23
+ // raw (its placeholders are substituted later, at generate time), and
24
+ // `tm/go/LICENSE` has the year filled in. A plain `diff -r` against the
25
+ // scaffold reported 20 edited files in that repo; 19 were substitution
26
+ // artefacts and exactly ONE was a real hand-edit.
27
+ //
28
+ // Only sdkgen knows which replacements it applied to which files, which is
29
+ // why this check belongs here and cannot be scripted downstream. It re-runs
30
+ // the same substitution before comparing, so what it reports is real.
31
+
32
+ import Path from 'node:path'
33
+
34
+ import { template } from 'jostraca'
35
+
36
+ import {
37
+ KIT
38
+ } from '../types'
39
+
40
+ import type {
41
+ ActionContext,
42
+ ActionResult,
43
+ } from '../types'
44
+
45
+ import { SdkGenError } from '../utility'
46
+
47
+ import { templateReplacements } from '../helpers/stdrep'
48
+
49
+ import {
50
+ resolveTarget,
51
+ trimFeatures,
52
+ } from './target'
53
+
54
+
55
+ // jostraca's Copy walk skips these (IGNORED_RE in CopyOp) — editor backups and
56
+ // deliberately-disabled templates never reach a project, so they are not drift.
57
+ const IGNORED_RE = /(~|-jostraca-off)$/
58
+
59
+ // Extensions jostraca copies byte-for-byte. Comparing them as text would
60
+ // report spurious differences, so they are compared by raw bytes.
61
+ const BINARY_RE = /\.(png|jpg|jpeg|gif|ico|pdf|zip|gz|woff2?|ttf|eot|wasm)$/i
62
+
63
+
64
+ // Root-level components sdkgen provides, and what a project loses by not
65
+ // wiring one in. A project's `Root.ts` / `Top.ts` come from create-sdkgen at
66
+ // init and are then FROZEN — `target add` never touches them — so a
67
+ // capability added to sdkgen afterwards is invisible to every existing
68
+ // project. solardemo's `Top.ts`, written before `ReadmeTop` existed, kept
69
+ // hand-rolling a 9-line stub root README with an empty mermaid diagram for
70
+ // months, and no number of `target add` runs would ever have said so.
71
+ //
72
+ // Not wiring one in is a legitimate choice, so this is REPORTED, never a
73
+ // failure.
74
+ const ROOT_COMPONENTS: [string, string][] = [
75
+ ['ReadmeTop', 'the assembled root README (quickstart, howto, test, package table)'],
76
+ ['AgentGuideTop', 'the root AGENTS.md / CLAUDE.md agent guides'],
77
+ ['License', 'the root LICENSE'],
78
+ ['Security', 'the root SECURITY.md'],
79
+ ['Changelog', 'the root CHANGELOG.md'],
80
+ ['Deploy', 'the release/publish recipes'],
81
+ ]
82
+
83
+
84
+ // What the check found, by category. Categories 1-3 are drift; `additive` is
85
+ // the project's own work and is reported separately, never as a problem.
86
+ type DoctorReport = {
87
+ // `.sdk/src/cmp/**` that differs from the scaffold. `target add` will
88
+ // silently revert every one of these.
89
+ forked: string[]
90
+
91
+ // `.sdk/tm/**` that differs from the scaffold AFTER the same substitution
92
+ // `target add` applies.
93
+ edited: string[]
94
+
95
+ // Present in the project, but `target add` would no longer write it. Stale
96
+ // output — the category that broke the Go build twice.
97
+ stale: string[]
98
+
99
+ // `target add` would write it and the project does not have it.
100
+ missing: string[]
101
+
102
+ // Project-owned components the scaffold never shipped. NOT drift.
103
+ additive: string[]
104
+
105
+ // Root-level components this sdkgen provides that the project's root
106
+ // wiring never calls. Informational: opting out is legitimate.
107
+ unwired: string[]
108
+
109
+ // True when nothing in the first four categories was found.
110
+ ok: boolean
111
+ }
112
+
113
+
114
+ const CMD_MAP: any = {
115
+ check: cmd_doctor_check,
116
+ }
117
+
118
+
119
+ async function action_doctor(args: string[], actx: ActionContext): Promise<ActionResult> {
120
+ // `doctor` with no subcommand is the check — the command exists to be run
121
+ // in CI without anyone remembering a verb.
122
+ const cmdname = args[1]
123
+ const cmd = null == cmdname ? cmd_doctor_check : CMD_MAP[cmdname]
124
+
125
+ if (null == cmd) {
126
+ throw new SdkGenError('Unknown doctor cmd: ' + cmdname)
127
+ }
128
+
129
+ return await cmd(args, actx)
130
+ }
131
+
132
+
133
+ async function cmd_doctor_check(_args: string[], actx: ActionContext): Promise<ActionResult> {
134
+ return doctor(actx)
135
+ }
136
+
137
+
138
+ // Code API. Returns the report; the CLI turns a non-ok report into a
139
+ // non-zero exit so this can gate CI.
140
+ async function doctor(actx: ActionContext): Promise<ActionResult> {
141
+ const log = actx.log
142
+ const fs = actx.fs()
143
+ const model = actx.model
144
+ const root = actx.folder
145
+
146
+ const report: DoctorReport = {
147
+ forked: [], edited: [], stale: [], missing: [], additive: [],
148
+ unwired: [], ok: true,
149
+ }
150
+
151
+ const targets = Object.keys(model?.main?.[KIT]?.target ?? {})
152
+
153
+ log.info({ point: 'doctor-start', targets: targets.length })
154
+
155
+ for (const tname of targets) {
156
+ const declared = (model as any)?.main?.[KIT]?.target?.[tname]
157
+
158
+ // The target model records where it came from (`base`, written by
159
+ // `target add`). Fall back to the bundled scaffold.
160
+ const tref = (declared && declared.base) ?
161
+ Path.join(declared.base, '..', tname) : tname
162
+
163
+ let resolved: any
164
+ try {
165
+ resolved = resolveTarget(tref, { folder: root, fs: () => fs })
166
+ }
167
+ catch (err: any) {
168
+ log.warn({
169
+ point: 'doctor-target-unresolved', target: tname, err: err.message,
170
+ note: tname + ': cannot find its scaffold (' + err.message + ')'
171
+ })
172
+ continue
173
+ }
174
+
175
+ if (null != resolved) {
176
+ checkTarget(actx, resolved, report)
177
+ }
178
+ }
179
+
180
+ checkWiring(actx, report)
181
+
182
+ report.ok = 0 === report.forked.length + report.edited.length +
183
+ report.stale.length + report.missing.length
184
+
185
+ for (const [kind, note] of [
186
+ ['forked', 'FORKED (will be reverted by `target add`)'],
187
+ ['edited', 'EDITED template master'],
188
+ ['stale', 'STALE (no longer written by `target add`)'],
189
+ ['missing', 'MISSING (would be written by `target add`)'],
190
+ ['additive', 'additive (project-owned, not drift)'],
191
+ ['unwired', 'NOT WIRED IN (root capability this project is missing)'],
192
+ ] as [keyof DoctorReport, string][]) {
193
+ for (const file of (report[kind] as string[])) {
194
+ log.info({ point: 'doctor-finding', kind, file, note: note + ': ' + file })
195
+ }
196
+ }
197
+
198
+ log.info({
199
+ point: 'doctor-end',
200
+ ok: report.ok,
201
+ forked: report.forked.length,
202
+ edited: report.edited.length,
203
+ stale: report.stale.length,
204
+ missing: report.missing.length,
205
+ additive: report.additive.length,
206
+ unwired: report.unwired.length,
207
+ note: report.ok ?
208
+ ('.sdk matches the scaffold (' + report.additive.length + ' additive)') :
209
+ ('.sdk has drifted: ' + report.forked.length + ' forked, ' +
210
+ report.edited.length + ' edited, ' + report.stale.length + ' stale, ' +
211
+ report.missing.length + ' missing')
212
+ })
213
+
214
+ return { report } as any
215
+ }
216
+
217
+
218
+ // Which root-level components the project's own wiring calls. The wiring is
219
+ // hand-written TypeScript (Root.ts / Top.ts / BuildSDK.ts), so this is a
220
+ // reference check, not a diff: sdkgen has no reference copy of a file it does
221
+ // not ship.
222
+ function checkWiring(actx: ActionContext, report: DoctorReport) {
223
+ const fs = actx.fs()
224
+ const src = Path.join(actx.folder, 'src')
225
+
226
+ if (!fs.existsSync(src)) {
227
+ return
228
+ }
229
+
230
+ // Everything except cmp/, which is the per-target layer target add owns.
231
+ const wiring = walk(fs, src)
232
+ .filter((rel) => !rel.startsWith('cmp/') && rel.endsWith('.ts'))
233
+ .map((rel) => fs.readFileSync(Path.join(src, rel), 'utf8'))
234
+ .join('\n')
235
+
236
+ if ('' === wiring) {
237
+ return
238
+ }
239
+
240
+ for (const [name, what] of ROOT_COMPONENTS) {
241
+ // A bare identifier reference: imported and called, or at least named.
242
+ if (!new RegExp('\\b' + name + '\\b').test(wiring)) {
243
+ report.unwired.push(name + ' — ' + what)
244
+ }
245
+ }
246
+ }
247
+
248
+
249
+ function checkTarget(actx: ActionContext, resolved: any, report: DoctorReport) {
250
+ const { tname, tfolder, torigname } = resolved
251
+ const fs = actx.fs()
252
+ const model = actx.model
253
+ const root = actx.folder
254
+
255
+ // The two trees `target add` owns, and the substitution it applies to each.
256
+ //
257
+ // src/cmp — copied verbatim, so a byte compare is the truth.
258
+ // tm — copied through jostraca's template(), with ProjectName.
259
+ const trees: {
260
+ project: string, scaffold: string, replace: any, kind: 'forked' | 'edited',
261
+ }[] = [
262
+ {
263
+ project: Path.join(root, 'src', 'cmp', tname),
264
+ scaffold: Path.join(tfolder, 'src', 'cmp', torigname),
265
+ replace: {},
266
+ kind: 'forked',
267
+ },
268
+ {
269
+ project: Path.join(root, 'tm', tname),
270
+ scaffold: Path.join(tfolder, 'tm', torigname),
271
+ replace: templateReplacements(model, tname),
272
+ kind: 'edited',
273
+ },
274
+ ]
275
+
276
+ // The feature set `target add` would select right now. A project that
277
+ // added its targets before feature trimming existed carries source for
278
+ // features its model never declared — expected here as STALE, which is
279
+ // exactly what it is.
280
+ const featuremodel: any = model?.main?.[KIT]?.feature ?? {}
281
+ const features = Array.from(new Set([
282
+ 'test',
283
+ ...Object.keys(featuremodel).filter((n: string) => false !== featuremodel[n]?.active),
284
+ ]))
285
+
286
+ const excludes: RegExp[] = trimFeatures(
287
+ { log: quietLog(actx.log), fs: () => fs }, tfolder, torigname, tname, features)
288
+
289
+ for (const tree of trees) {
290
+ // Findings are reported at project-relative paths, the way a maintainer
291
+ // would type them.
292
+ const label = Path.relative(root, tree.project).split(Path.sep).join('/') + '/'
293
+
294
+ const expected = 'edited' === tree.kind ?
295
+ walk(fs, tree.scaffold).filter((rel) => !excluded(rel, excludes)) :
296
+ walk(fs, tree.scaffold)
297
+
298
+ const actual = walk(fs, tree.project)
299
+
300
+ const expectedSet = new Set(expected)
301
+ const actualSet = new Set(actual)
302
+
303
+ for (const rel of expected) {
304
+ if (!actualSet.has(rel)) {
305
+ report.missing.push(label + rel)
306
+ continue
307
+ }
308
+
309
+ if (differs(fs, Path.join(tree.scaffold, rel), Path.join(tree.project, rel),
310
+ model, tree.replace)) {
311
+ report[tree.kind].push(label + rel)
312
+ }
313
+ }
314
+
315
+ for (const rel of actual) {
316
+ if (expectedSet.has(rel)) {
317
+ continue
318
+ }
319
+
320
+ // A component the scaffold has NEVER shipped is the project's own —
321
+ // the supported way to add a per-target component. Anything else under
322
+ // a tree `target add` owns is stale output.
323
+ const known = fs.existsSync(Path.join(tree.scaffold, rel))
324
+ if ('forked' === tree.kind && !known) {
325
+ report.additive.push(label + rel)
326
+ }
327
+ else {
328
+ report.stale.push(label + rel)
329
+ }
330
+ }
331
+ }
332
+ }
333
+
334
+
335
+ // Every file under `dir`, as forward-slash paths relative to it, sorted.
336
+ // Missing directory -> no files (a target that was never added).
337
+ function walk(fs: any, dir: string): string[] {
338
+ const out: string[] = []
339
+
340
+ if (!fs.existsSync(dir)) {
341
+ return out
342
+ }
343
+
344
+ const descend = (rel: string) => {
345
+ const abs = '' === rel ? dir : Path.join(dir, rel)
346
+ for (const entry of fs.readdirSync(abs).sort()) {
347
+ if (IGNORED_RE.test(entry)) {
348
+ continue
349
+ }
350
+ const entryrel = '' === rel ? entry : rel + '/' + entry
351
+ if (fs.statSync(Path.join(dir, entryrel)).isDirectory()) {
352
+ descend(entryrel)
353
+ }
354
+ else {
355
+ out.push(entryrel)
356
+ }
357
+ }
358
+ }
359
+
360
+ descend('')
361
+
362
+ return out.sort()
363
+ }
364
+
365
+
366
+ function excluded(rel: string, excludes: RegExp[]): boolean {
367
+ for (const re of excludes) {
368
+ if (re.test(rel)) {
369
+ return true
370
+ }
371
+ }
372
+ return false
373
+ }
374
+
375
+
376
+ // Compare a scaffold file with a project file, applying the SAME substitution
377
+ // `target add` applied on the way in. Without this the comparison reports
378
+ // every substituted placeholder as an edit.
379
+ function differs(
380
+ fs: any, scaffoldPath: string, projectPath: string, model: any, replace: any,
381
+ ): boolean {
382
+ if (BINARY_RE.test(scaffoldPath)) {
383
+ return !fs.readFileSync(scaffoldPath).equals(fs.readFileSync(projectPath))
384
+ }
385
+
386
+ const src = fs.readFileSync(scaffoldPath, 'utf8')
387
+ const expected = 0 === Object.keys(replace).length ? src :
388
+ template(src, model, { replace })
389
+
390
+ return expected !== fs.readFileSync(projectPath, 'utf8')
391
+ }
392
+
393
+
394
+ // trimFeatures logs its decisions; doctor is a report, not a run.
395
+ function quietLog(log: any): any {
396
+ const noop = () => { }
397
+ const quiet: any = { info: noop, debug: noop, warn: log.warn.bind(log), error: noop, trace: noop, fatal: noop }
398
+ quiet.child = () => quiet
399
+ return quiet
400
+ }
401
+
402
+
403
+ export type {
404
+ DoctorReport,
405
+ }
406
+
407
+ export {
408
+ action_doctor,
409
+ doctor,
410
+ }
@@ -12,6 +12,8 @@ import {
12
12
 
13
13
  import { showChanges } from '@voxgig/util'
14
14
 
15
+ import { showDryrun } from '../helpers/dryrun'
16
+
15
17
  import {
16
18
  KIT
17
19
  } from '../types'
@@ -23,6 +25,8 @@ import type {
23
25
 
24
26
  import { SdkGenError } from '../utility'
25
27
 
28
+ import { findFeatureSources } from '../helpers/featureSource'
29
+
26
30
 
27
31
  import {
28
32
  UpdateIndex,
@@ -74,7 +78,17 @@ async function feature_add(features: string[], actx: ActionContext): Promise<Act
74
78
  url: actx.url,
75
79
  content: loadContent(actx, 'feature')
76
80
  },
77
- model: actx.model
81
+ model: actx.model,
82
+ // Dry run must be passed per-call, not left to the Jostraca instance.
83
+ // jostraca's `generate` runs its own options through OptionsShape FIRST,
84
+ // which fills in `control.dryrun: false`, and only then merges
85
+ // `deep({}, gOpts.control, opts.control)` — so the shape default silently
86
+ // OVERRIDES the instance-level flag. `-y target add ts` printed
87
+ // ** DRY RUN ** and wrote every file. (Same trap as the `existing` FIX
88
+ // note in jostraca.js.)
89
+ control: {
90
+ dryrun: !!actx.opts.dryrun
91
+ },
78
92
  }
79
93
 
80
94
  opts.log.info({
@@ -86,6 +100,10 @@ async function feature_add(features: string[], actx: ActionContext): Promise<Act
86
100
 
87
101
  showChanges(opts.log, 'feature-result', jres)
88
102
 
103
+ if (actx.opts.dryrun) {
104
+ showDryrun(opts.log, 'feature-result', jres, actx.folder)
105
+ }
106
+
89
107
  opts.log.info({
90
108
  point: 'feature-end',
91
109
  note: (actx.opts.dryrun ? '** DRY RUN **' : '')
@@ -101,6 +119,7 @@ const FeatureRoot = cmp(function FeatureRoot(props: any) {
101
119
  const { ctx$, features } = props
102
120
  const { model, log } = ctx$
103
121
 
122
+ const fs = ctx$.fs()
104
123
  const target = model.main[KIT].target
105
124
 
106
125
  Project({}, () => {
@@ -127,22 +146,41 @@ const FeatureRoot = cmp(function FeatureRoot(props: any) {
127
146
  }))
128
147
  })
129
148
 
130
- each(target, (t) =>
131
- Folder({ name: 'tm/' + t.name + '/src/feature/' + fname }, () => {
132
- const from = Path.join(
133
- (t.base || Path.join(BASE, '/project/.sdk')),
134
- 'tm',
135
- t.name,
136
- '/src/feature/',
137
- fname
138
- )
139
-
140
- Copy({
141
- // from: BASE + '/project/.sdk/tm/' + target.name + '/src/feature/' + name,
142
- from,
143
- exclude: true
149
+ // Bring in the feature's source for every target already in the model.
150
+ // Where that source lives is language-specific — `src/feature/<name>/`
151
+ // for ts and js, `feature/<name>_feature.go` for go,
152
+ // `lib/feature/<name>/` for dart, and so on — so discover it in the
153
+ // target's template tree instead of assuming one layout. Assuming
154
+ // `src/feature/<name>` meant `feature add` silently added nothing for
155
+ // every target that keeps feature source elsewhere.
156
+ each(target, (t) => {
157
+ const sdkfolder = t.base || Path.join(BASE, 'project/.sdk')
158
+ const tmfolder = Path.join(sdkfolder, 'tm', t.name)
159
+
160
+ const sources = findFeatureSources(fs, tmfolder, [fname])
161
+
162
+ if (0 === sources.length) {
163
+ log.warn({
164
+ point: 'feature-source-missing', feature: fname, target: t.name,
165
+ folder: tmfolder,
166
+ note: 'no ' + fname + ' source found for target ' + t.name
144
167
  })
145
- }))
168
+ return
169
+ }
170
+
171
+ for (const source of sources) {
172
+ // A folder source IS the destination folder; a file source goes
173
+ // into the folder that holds it.
174
+ const dest = source.folder ? source.path : Path.dirname(source.path)
175
+
176
+ Folder({ name: 'tm/' + t.name + '/' + dest }, () => {
177
+ Copy({
178
+ from: Path.join(tmfolder, source.path),
179
+ exclude: true
180
+ })
181
+ })
182
+ }
183
+ })
146
184
 
147
185
  log.info({
148
186
  point: 'feature-done', feature: fname,