@voxgig/sdkgen 1.3.17 → 1.3.19

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 (267) hide show
  1. package/bin/voxgig-sdkgen +1 -1
  2. package/dist/cmp/Deploy.js +16 -16
  3. package/dist/cmp/Deploy.js.map +1 -1
  4. package/dist/cmp/Entity.js +5 -1
  5. package/dist/cmp/Entity.js.map +1 -1
  6. package/dist/cmp/Feature.js +2 -1
  7. package/dist/cmp/Feature.js.map +1 -1
  8. package/dist/cmp/ReadmeTop.js +13 -11
  9. package/dist/cmp/ReadmeTop.js.map +1 -1
  10. package/dist/helpers/canonType.js +8 -3
  11. package/dist/helpers/canonType.js.map +1 -1
  12. package/dist/helpers/collectDeps.d.ts +1 -1
  13. package/dist/helpers/collectDeps.js +36 -13
  14. package/dist/helpers/collectDeps.js.map +1 -1
  15. package/dist/helpers/naming.d.ts +5 -1
  16. package/dist/helpers/naming.js +118 -0
  17. package/dist/helpers/naming.js.map +1 -1
  18. package/dist/helpers/opShape.d.ts +3 -1
  19. package/dist/helpers/opShape.js +87 -8
  20. package/dist/helpers/opShape.js.map +1 -1
  21. package/dist/helpers/serverVars.d.ts +10 -0
  22. package/dist/helpers/serverVars.js +87 -0
  23. package/dist/helpers/serverVars.js.map +1 -0
  24. package/dist/sdkgen.d.ts +4 -3
  25. package/dist/sdkgen.js +11 -2
  26. package/dist/sdkgen.js.map +1 -1
  27. package/dist/tsconfig.tsbuildinfo +1 -1
  28. package/package.json +15 -10
  29. package/project/.sdk/model/target/cpp.aontu +4 -4
  30. package/project/.sdk/model/target/go-cli.aontu +17 -17
  31. package/project/.sdk/model/target/go-mcp.aontu +11 -11
  32. package/project/.sdk/model/target/go.aontu +1 -1
  33. package/project/.sdk/model/target/java.aontu +4 -4
  34. package/project/.sdk/model/target/kotlin.aontu +4 -4
  35. package/project/.sdk/model/target/lean.aontu +51 -0
  36. package/project/.sdk/model/target/scala.aontu +4 -4
  37. package/project/.sdk/src/cmp/c/EntityTypes_c.ts +3 -4
  38. package/project/.sdk/src/cmp/c/Entity_c.ts +3 -3
  39. package/project/.sdk/src/cmp/c/ReadmeExamplesTest_c.ts +24 -7
  40. package/project/.sdk/src/cmp/c/TestDirect_c.ts +3 -3
  41. package/project/.sdk/src/cmp/c/TestEntity_c.ts +1 -1
  42. package/project/.sdk/src/cmp/clojure/Entity_clojure.ts +1 -1
  43. package/project/.sdk/src/cmp/clojure/ReadmeExamplesTest_clojure.ts +19 -8
  44. package/project/.sdk/src/cmp/cpp/EntityTypes_cpp.ts +2 -2
  45. package/project/.sdk/src/cmp/cpp/Entity_cpp.ts +3 -3
  46. package/project/.sdk/src/cmp/cpp/MainEntity_cpp.ts +2 -2
  47. package/project/.sdk/src/cmp/cpp/ReadmeExamplesTest_cpp.ts +136 -0
  48. package/project/.sdk/src/cmp/cpp/TestDirect_cpp.ts +3 -3
  49. package/project/.sdk/src/cmp/cpp/Test_cpp.ts +4 -0
  50. package/project/.sdk/src/cmp/csharp/EntityTypes_csharp.ts +2 -3
  51. package/project/.sdk/src/cmp/csharp/Entity_csharp.ts +3 -3
  52. package/project/.sdk/src/cmp/csharp/MainEntity_csharp.ts +2 -2
  53. package/project/.sdk/src/cmp/csharp/Package_csharp.ts +1 -1
  54. package/project/.sdk/src/cmp/csharp/ReadmeExamplesTest_csharp.ts +13 -1
  55. package/project/.sdk/src/cmp/csharp/TestDirect_csharp.ts +3 -3
  56. package/project/.sdk/src/cmp/csharp/TestEntity_csharp.ts +22 -15
  57. package/project/.sdk/src/cmp/dart/EntityTypes_dart.ts +2 -3
  58. package/project/.sdk/src/cmp/dart/Entity_dart.ts +3 -3
  59. package/project/.sdk/src/cmp/dart/MainEntity_dart.ts +2 -2
  60. package/project/.sdk/src/cmp/dart/Main_dart.ts +3 -3
  61. package/project/.sdk/src/cmp/dart/Package_dart.ts +1 -1
  62. package/project/.sdk/src/cmp/dart/TestDirect_dart.ts +4 -4
  63. package/project/.sdk/src/cmp/elixir/EntityTypes_elixir.ts +2 -3
  64. package/project/.sdk/src/cmp/elixir/Entity_elixir.ts +1 -1
  65. package/project/.sdk/src/cmp/elixir/ReadmeExamplesTest_elixir.ts +21 -3
  66. package/project/.sdk/src/cmp/go/Config_go.ts +14 -2
  67. package/project/.sdk/src/cmp/go/EntityTypes_go.ts +110 -18
  68. package/project/.sdk/src/cmp/go/Entity_go.ts +3 -3
  69. package/project/.sdk/src/cmp/go/Main_go.ts +7 -6
  70. package/project/.sdk/src/cmp/go/Package_go.ts +1 -1
  71. package/project/.sdk/src/cmp/go/TestDirect_go.ts +3 -3
  72. package/project/.sdk/src/cmp/go/TestEntity_go.ts +1 -1
  73. package/project/.sdk/src/cmp/go/utility_go.ts +25 -0
  74. package/project/.sdk/src/cmp/go-cli/Main_go-cli.ts +62 -35
  75. package/project/.sdk/src/cmp/go-cli/fragment/main.fragment.go +7 -7
  76. package/project/.sdk/src/cmp/go-cli/fragment/words.fragment.go +21 -18
  77. package/project/.sdk/src/cmp/go-mcp/Main_go-mcp.ts +9 -1
  78. package/project/.sdk/src/cmp/haskell/ReadmeExamplesTest_haskell.ts +28 -18
  79. package/project/.sdk/src/cmp/java/EntityTypes_java.ts +2 -3
  80. package/project/.sdk/src/cmp/java/Entity_java.ts +3 -3
  81. package/project/.sdk/src/cmp/java/MainEntity_java.ts +2 -2
  82. package/project/.sdk/src/cmp/java/Package_java.ts +1 -1
  83. package/project/.sdk/src/cmp/java/ReadmeExamplesTest_java.ts +23 -1
  84. package/project/.sdk/src/cmp/java/TestDirect_java.ts +3 -3
  85. package/project/.sdk/src/cmp/js/Config_js.ts +11 -0
  86. package/project/.sdk/src/cmp/js/EntityTypes_js.ts +2 -3
  87. package/project/.sdk/src/cmp/js/Entity_js.ts +3 -3
  88. package/project/.sdk/src/cmp/js/MainEntity_js.ts +2 -2
  89. package/project/.sdk/src/cmp/js/Main_js.ts +2 -2
  90. package/project/.sdk/src/cmp/js/TestDirect_js.ts +4 -4
  91. package/project/.sdk/src/cmp/js/fragment/Config.fragment.js +2 -2
  92. package/project/.sdk/src/cmp/js/fragment/Direct.test.fragment.js +4 -0
  93. package/project/.sdk/src/cmp/kotlin/EntityTypes_kotlin.ts +2 -3
  94. package/project/.sdk/src/cmp/kotlin/Entity_kotlin.ts +3 -3
  95. package/project/.sdk/src/cmp/kotlin/MainEntity_kotlin.ts +2 -2
  96. package/project/.sdk/src/cmp/kotlin/Package_kotlin.ts +1 -1
  97. package/project/.sdk/src/cmp/kotlin/ReadmeExamplesTest_kotlin.ts +27 -2
  98. package/project/.sdk/src/cmp/kotlin/TestDirect_kotlin.ts +3 -3
  99. package/project/.sdk/src/cmp/lean/Config_lean.ts +88 -0
  100. package/project/.sdk/src/cmp/lean/Entity_lean.ts +9 -0
  101. package/project/.sdk/src/cmp/lean/Gitignore_lean.ts +18 -0
  102. package/project/.sdk/src/cmp/lean/Main_lean.ts +120 -0
  103. package/project/.sdk/src/cmp/lean/Package_lean.ts +68 -0
  104. package/project/.sdk/src/cmp/lean/ReadmeEntity_lean.ts +29 -0
  105. package/project/.sdk/src/cmp/lean/ReadmeExplanation_lean.ts +19 -0
  106. package/project/.sdk/src/cmp/lean/ReadmeHowto_lean.ts +25 -0
  107. package/project/.sdk/src/cmp/lean/ReadmeInstall_lean.ts +38 -0
  108. package/project/.sdk/src/cmp/lean/ReadmeIntro_lean.ts +25 -0
  109. package/project/.sdk/src/cmp/lean/ReadmeModel_lean.ts +24 -0
  110. package/project/.sdk/src/cmp/lean/ReadmeOptions_lean.ts +22 -0
  111. package/project/.sdk/src/cmp/lean/ReadmeQuick_lean.ts +50 -0
  112. package/project/.sdk/src/cmp/lean/ReadmeRef_lean.ts +16 -0
  113. package/project/.sdk/src/cmp/lean/ReadmeTopHowto_lean.ts +16 -0
  114. package/project/.sdk/src/cmp/lean/ReadmeTopQuick_lean.ts +23 -0
  115. package/project/.sdk/src/cmp/lean/ReadmeTopTest_lean.ts +18 -0
  116. package/project/.sdk/src/cmp/lean/Test_lean.ts +207 -0
  117. package/project/.sdk/src/cmp/lean/utility_lean.ts +78 -0
  118. package/project/.sdk/src/cmp/lua/Config_lua.ts +10 -1
  119. package/project/.sdk/src/cmp/lua/EntityTypes_lua.ts +2 -3
  120. package/project/.sdk/src/cmp/lua/Entity_lua.ts +3 -3
  121. package/project/.sdk/src/cmp/lua/Package_lua.ts +1 -1
  122. package/project/.sdk/src/cmp/lua/TestDirect_lua.ts +3 -3
  123. package/project/.sdk/src/cmp/lua/TestEntity_lua.ts +1 -1
  124. package/project/.sdk/src/cmp/ocaml/ReadmeExamplesTest_ocaml.ts +29 -14
  125. package/project/.sdk/src/cmp/perl/Entity_perl.ts +3 -3
  126. package/project/.sdk/src/cmp/perl/MainEntity_perl.ts +2 -2
  127. package/project/.sdk/src/cmp/perl/Package_perl.ts +1 -1
  128. package/project/.sdk/src/cmp/perl/TestDirect_perl.ts +3 -3
  129. package/project/.sdk/src/cmp/php/Config_php.ts +13 -2
  130. package/project/.sdk/src/cmp/php/EntityTypes_php.ts +2 -3
  131. package/project/.sdk/src/cmp/php/Entity_php.ts +3 -3
  132. package/project/.sdk/src/cmp/php/MainEntity_php.ts +2 -2
  133. package/project/.sdk/src/cmp/php/Package_php.ts +1 -1
  134. package/project/.sdk/src/cmp/php/TestDirect_php.ts +3 -3
  135. package/project/.sdk/src/cmp/php/TestEntity_php.ts +1 -1
  136. package/project/.sdk/src/cmp/py/Config_py.ts +10 -1
  137. package/project/.sdk/src/cmp/py/EntityTypes_py.ts +2 -3
  138. package/project/.sdk/src/cmp/py/Entity_py.ts +3 -3
  139. package/project/.sdk/src/cmp/py/MainEntity_py.ts +2 -2
  140. package/project/.sdk/src/cmp/py/Main_py.ts +2 -2
  141. package/project/.sdk/src/cmp/py/Package_py.ts +1 -1
  142. package/project/.sdk/src/cmp/py/TestDirect_py.ts +3 -3
  143. package/project/.sdk/src/cmp/py/TestEntity_py.ts +1 -1
  144. package/project/.sdk/src/cmp/rb/Config_rb.ts +12 -1
  145. package/project/.sdk/src/cmp/rb/EntityTypes_rb.ts +15 -5
  146. package/project/.sdk/src/cmp/rb/Entity_rb.ts +3 -3
  147. package/project/.sdk/src/cmp/rb/MainEntity_rb.ts +2 -2
  148. package/project/.sdk/src/cmp/rb/Package_rb.ts +2 -2
  149. package/project/.sdk/src/cmp/rb/TestDirect_rb.ts +3 -3
  150. package/project/.sdk/src/cmp/rb/TestEntity_rb.ts +1 -1
  151. package/project/.sdk/src/cmp/rust/EntityBase_rust.ts +2 -2
  152. package/project/.sdk/src/cmp/rust/EntityTypes_rust.ts +3 -4
  153. package/project/.sdk/src/cmp/rust/Entity_rust.ts +3 -3
  154. package/project/.sdk/src/cmp/rust/MainEntity_rust.ts +2 -2
  155. package/project/.sdk/src/cmp/rust/Package_rust.ts +1 -1
  156. package/project/.sdk/src/cmp/rust/ReadmeExamplesTest_rust.ts +22 -10
  157. package/project/.sdk/src/cmp/rust/TestDirect_rust.ts +3 -3
  158. package/project/.sdk/src/cmp/rust/TestEntity_rust.ts +25 -18
  159. package/project/.sdk/src/cmp/scala/EntityTypes_scala.ts +2 -3
  160. package/project/.sdk/src/cmp/scala/Entity_scala.ts +3 -3
  161. package/project/.sdk/src/cmp/scala/MainEntity_scala.ts +2 -2
  162. package/project/.sdk/src/cmp/scala/ReadmeExamplesTest_scala.ts +22 -3
  163. package/project/.sdk/src/cmp/scala/TestDirect_scala.ts +3 -3
  164. package/project/.sdk/src/cmp/scala/Test_scala.ts +1 -1
  165. package/project/.sdk/src/cmp/swift/EntityTypes_swift.ts +12 -6
  166. package/project/.sdk/src/cmp/swift/Entity_swift.ts +3 -3
  167. package/project/.sdk/src/cmp/swift/MainEntity_swift.ts +2 -2
  168. package/project/.sdk/src/cmp/swift/Package_swift.ts +1 -1
  169. package/project/.sdk/src/cmp/swift/ReadmeExamplesTest_swift.ts +18 -1
  170. package/project/.sdk/src/cmp/swift/TestDirect_swift.ts +1 -1
  171. package/project/.sdk/src/cmp/ts/Config_ts.ts +11 -0
  172. package/project/.sdk/src/cmp/ts/EntityTypes_ts.ts +2 -3
  173. package/project/.sdk/src/cmp/ts/Entity_ts.ts +3 -3
  174. package/project/.sdk/src/cmp/ts/MainEntity_ts.ts +2 -2
  175. package/project/.sdk/src/cmp/ts/Main_ts.ts +2 -2
  176. package/project/.sdk/src/cmp/ts/TestDirect_ts.ts +4 -4
  177. package/project/.sdk/src/cmp/ts/fragment/Config.fragment.ts +2 -2
  178. package/project/.sdk/src/cmp/ts/fragment/Direct.test.fragment.ts +4 -0
  179. package/project/.sdk/src/cmp/zig/Entity_zig.ts +3 -3
  180. package/project/.sdk/src/cmp/zig/MainEntity_zig.ts +2 -2
  181. package/project/.sdk/src/cmp/zig/Package_zig.ts +10 -2
  182. package/project/.sdk/tm/cpp/test/primary_utility_test.cpp +8 -16
  183. package/project/.sdk/tm/csharp/Makefile +6 -6
  184. package/project/.sdk/tm/csharp/test/PrimaryUtilityTest.cs +10 -28
  185. package/project/.sdk/tm/dart/Makefile +3 -3
  186. package/project/.sdk/tm/dart/test/primary_test.dart +7 -0
  187. package/project/.sdk/tm/go/Makefile +6 -6
  188. package/project/.sdk/tm/go/feature/test_feature.go +33 -1
  189. package/project/.sdk/tm/go/test/primary_utility_test.go +46 -42
  190. package/project/.sdk/tm/go/test/runner_test.go +30 -1
  191. package/project/.sdk/tm/go/utility/make_options.go +48 -0
  192. package/project/.sdk/tm/java/Makefile +6 -6
  193. package/project/.sdk/tm/java/test/PrimaryUtilityTest.java +7 -24
  194. package/project/.sdk/tm/js/Makefile +6 -6
  195. package/project/.sdk/tm/js/src/feature/test/TestFeature.js +18 -1
  196. package/project/.sdk/tm/js/src/utility/MakeOptionsUtility.js +39 -1
  197. package/project/.sdk/tm/js/test/utility/PrimaryUtility.test.js +13 -0
  198. package/project/.sdk/tm/kotlin/Makefile +6 -6
  199. package/project/.sdk/tm/kotlin/test/PrimaryUtilityTest.kt +7 -20
  200. package/project/.sdk/tm/lean/LICENSE +21 -0
  201. package/project/.sdk/tm/lean/VERSION +1 -0
  202. package/project/.sdk/tm/lean/src/SdkFeature.lean +171 -0
  203. package/project/.sdk/tm/lean/src/SdkFeatures.lean +602 -0
  204. package/project/.sdk/tm/lean/src/SdkJson.lean +134 -0
  205. package/project/.sdk/tm/lean/src/SdkRuntime.lean +356 -0
  206. package/project/.sdk/tm/lean/src/SdkUtility.lean +617 -0
  207. package/project/.sdk/tm/lean/src/VoxgigStruct.lean +2880 -0
  208. package/project/.sdk/tm/lean/src/Vregex.lean +412 -0
  209. package/project/.sdk/tm/lean/src/feature/README.md +5 -0
  210. package/project/.sdk/tm/lean/src/feature/audit/.gitkeep +0 -0
  211. package/project/.sdk/tm/lean/src/feature/base/.gitkeep +0 -0
  212. package/project/.sdk/tm/lean/src/feature/cache/.gitkeep +0 -0
  213. package/project/.sdk/tm/lean/src/feature/clienttrack/.gitkeep +0 -0
  214. package/project/.sdk/tm/lean/src/feature/debug/.gitkeep +0 -0
  215. package/project/.sdk/tm/lean/src/feature/idempotency/.gitkeep +0 -0
  216. package/project/.sdk/tm/lean/src/feature/log/.gitkeep +0 -0
  217. package/project/.sdk/tm/lean/src/feature/metrics/.gitkeep +0 -0
  218. package/project/.sdk/tm/lean/src/feature/netsim/.gitkeep +0 -0
  219. package/project/.sdk/tm/lean/src/feature/paging/.gitkeep +0 -0
  220. package/project/.sdk/tm/lean/src/feature/proxy/.gitkeep +0 -0
  221. package/project/.sdk/tm/lean/src/feature/ratelimit/.gitkeep +0 -0
  222. package/project/.sdk/tm/lean/src/feature/rbac/.gitkeep +0 -0
  223. package/project/.sdk/tm/lean/src/feature/retry/.gitkeep +0 -0
  224. package/project/.sdk/tm/lean/src/feature/streaming/.gitkeep +0 -0
  225. package/project/.sdk/tm/lean/src/feature/telemetry/.gitkeep +0 -0
  226. package/project/.sdk/tm/lean/src/feature/test/.gitkeep +0 -0
  227. package/project/.sdk/tm/lean/src/feature/timeout/.gitkeep +0 -0
  228. package/project/.sdk/tm/lean/test/StructCorpus.lean +697 -0
  229. package/project/.sdk/tm/lean/test/TFeature.lean +268 -0
  230. package/project/.sdk/tm/lean/test/TPrimaryUtility.lean +349 -0
  231. package/project/.sdk/tm/lua/Makefile +7 -7
  232. package/project/.sdk/tm/lua/feature/test_feature.lua +29 -1
  233. package/project/.sdk/tm/lua/test/primary_utility_test.lua +14 -8
  234. package/project/.sdk/tm/lua/utility/make_options.lua +39 -0
  235. package/project/.sdk/tm/perl/Makefile +6 -6
  236. package/project/.sdk/tm/perl/t/primary_utility.t +8 -17
  237. package/project/.sdk/tm/php/Makefile +6 -6
  238. package/project/.sdk/tm/php/feature/TestFeature.php +30 -2
  239. package/project/.sdk/tm/php/test/PrimaryUtilityTest.php +14 -7
  240. package/project/.sdk/tm/php/utility/MakeOptions.php +44 -0
  241. package/project/.sdk/tm/py/Makefile +6 -6
  242. package/project/.sdk/tm/py/feature/test_feature.py +28 -1
  243. package/project/.sdk/tm/py/test/test_primary_utility.py +18 -18
  244. package/project/.sdk/tm/py/utility/make_options.py +42 -0
  245. package/project/.sdk/tm/rb/Makefile +6 -6
  246. package/project/.sdk/tm/rb/feature/test_feature.rb +24 -1
  247. package/project/.sdk/tm/rb/test/primary_utility_test.rb +11 -8
  248. package/project/.sdk/tm/rb/utility/make_options.rb +37 -0
  249. package/project/.sdk/tm/rust/Makefile +6 -6
  250. package/project/.sdk/tm/rust/tests/common/mod.rs +37 -1
  251. package/project/.sdk/tm/rust/tests/primary_utility_test.rs +12 -26
  252. package/project/.sdk/tm/swift/Makefile +6 -6
  253. package/project/.sdk/tm/swift/Tests/ProjectNameSDKTests/PrimaryUtilityTest.swift +7 -8
  254. package/project/.sdk/tm/ts/Makefile +6 -6
  255. package/project/.sdk/tm/ts/src/feature/test/TestFeature.ts +18 -1
  256. package/project/.sdk/tm/ts/src/utility/MakeOptionsUtility.ts +39 -1
  257. package/project/.sdk/tm/ts/test/utility/PrimaryUtility.test.ts +69 -21
  258. package/src/cmp/Deploy.ts +16 -16
  259. package/src/cmp/Entity.ts +5 -1
  260. package/src/cmp/Feature.ts +2 -1
  261. package/src/cmp/ReadmeTop.ts +13 -11
  262. package/src/helpers/canonType.ts +8 -3
  263. package/src/helpers/collectDeps.ts +39 -12
  264. package/src/helpers/naming.ts +130 -0
  265. package/src/helpers/opShape.ts +99 -12
  266. package/src/helpers/serverVars.ts +105 -0
  267. package/src/sdkgen.ts +12 -3
@@ -59,7 +59,7 @@ const TestEntity = cmp(function TestEntity(props: any) {
59
59
  // it only applies to entities that declare a list op. Others (e.g. Batch =
60
60
  // create/load) have no list endpoint — make_point errors and the stream
61
61
  // yields nothing — so skip the stream test for them.
62
- const hasList = !!(entity.op && (entity.op as any).list)
62
+ const hasList = !!(entity.op && (entity.op as any)?.list)
63
63
 
64
64
  const basicflow: ModelEntityFlow | undefined =
65
65
  getModelPath(model, `main.${KIT}.flow.Basic${nom(entity, 'Name')}Flow`)
@@ -7,6 +7,7 @@ import {
7
7
  canonKey,
8
8
  each,
9
9
  exampleVarName,
10
+ names,
10
11
  } from '@voxgig/sdkgen'
11
12
 
12
13
  import {
@@ -149,7 +150,31 @@ function clean(o: any) {
149
150
  }
150
151
 
151
152
 
153
+
154
+ // The Go identifier fragment for a feature's generated constructor
155
+ // (New<Fname>Feature / New<Fname>FeatureFunc).
156
+ //
157
+ // SHARED because the identifier is DECLARED in Main_go.ts (registry.go and the
158
+ // root init()) and REFERENCED in Config_go.ts (makeFeature). Two copies of the
159
+ // derivation is a latent undefined-identifier bug in the generated SDK: they
160
+ // were both `name.charAt(0).toUpperCase() + name.slice(1)`, consistently wrong
161
+ // for a name needing real normalisation but at least agreeing, until one side
162
+ // was fixed alone and `rate_limit` became NewRateLimitFeatureFunc in the
163
+ // registry and NewRate_limitFeatureFunc in config.
164
+ //
165
+ // Uses the jostraca-derived PascalCase `Name` (deriving it if absent), which is
166
+ // what Main_ts.ts uses, so a hyphenated or underscored feature name yields a
167
+ // legal Go identifier instead of `NewRate-limitFeatureFunc`.
168
+ function goFeatureName(feat: any): string {
169
+ if (null == feat.Name) {
170
+ names(feat, feat.name)
171
+ }
172
+ return feat.Name
173
+ }
174
+
175
+
152
176
  export {
177
+ goFeatureName,
153
178
  clean,
154
179
  exampleValue,
155
180
  formatGoMap,
@@ -2,7 +2,7 @@
2
2
  import * as Path from 'node:path'
3
3
 
4
4
  import {
5
- cmp, each,
5
+ cmp, each, deriveEntityNames,
6
6
  File, Content, Fragment, Slot,
7
7
  } from '@voxgig/sdkgen'
8
8
 
@@ -16,18 +16,32 @@ import {
16
16
  } from '@voxgig/apidef'
17
17
 
18
18
 
19
- // Published aql/eng/go version. Tagged at aql-lang/aql under
20
- // eng/go/v<X.Y.Z>. Bump here when adopting a newer engine.
21
- const AQL_ENG_VERSION = 'v0.0.1'
19
+ // Published boru/eng/go version. The engine module
20
+ // github.com/boru-lang/boru/eng/go is not yet tagged under the boru path (the
21
+ // eng/go/v0.0.1 tag predates the aql->boru rename and still declares the old
22
+ // aql-lang/aql module path), so we pin a commit pseudo-version. Bump here —
23
+ // to a real eng/go/v<X.Y.Z> once one is published, or a newer pseudo-version —
24
+ // when adopting a newer engine.
25
+ const BORU_ENG_VERSION = 'v0.0.2-0.20260804163932-0d66b55c5110'
22
26
 
23
- // go.sum entries for AQL_ENG_VERSION and its transitive deps. The sibling
27
+ // go.sum entries for BORU_ENG_VERSION and its transitive deps. The sibling
24
28
  // SDK dep needs no entry (path replace). Deterministic because the version
25
29
  // is pinned above — regenerate with `go mod tidy` and update BOTH constants
26
- // together when bumping AQL_ENG_VERSION.
27
- const AQL_ENG_GOSUM = `github.com/aql-lang/aql/eng/go v0.0.1 h1:qvopmpIX5xL6cpAC4otSUO7fUDA46x/y+2lT2zoxTaA=
28
- github.com/aql-lang/aql/eng/go v0.0.1/go.mod h1:7LmNG+pASY2jlPZB0iFAt/ZNdmc8qxvaf+njVmaSFks=
29
- github.com/jsonicjs/jsonic/go v0.1.6 h1:oUw4vxCK6tqa7SGN87vjCtx3sCpeHXdqfl25hx5LKP0=
30
- github.com/jsonicjs/jsonic/go v0.1.6/go.mod h1:ObNKlCG7esWoi4AHCpdgkILvPINV8bpvkbCd4llGGUg=
30
+ // together when bumping BORU_ENG_VERSION.
31
+ const BORU_ENG_GOSUM = `github.com/boru-lang/boru/eng/go v0.0.2-0.20260804163932-0d66b55c5110 h1:iwMbEPhByhVhJgt6xhyhT+jXMiARvbG4wHIrc4OPcvU=
32
+ github.com/boru-lang/boru/eng/go v0.0.2-0.20260804163932-0d66b55c5110/go.mod h1:KQLjjCq4QVAfdSuhmQ58ZFA9JK7LV2+A/aLRb3m4s5k=
33
+ github.com/cockroachdb/apd/v3 v3.2.3 h1:4Zx+I3R35bFXMnltzmjP79i2cravE4jTRL6ps9Aux80=
34
+ github.com/cockroachdb/apd/v3 v3.2.3/go.mod h1:klXJcjp+FffLTHlhIG69tezTDvdP065naDsHzKhYSqc=
35
+ github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw=
36
+ github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
37
+ github.com/tabnas/debug/go v0.2.3 h1:cptiwHcHKw+lqtZuKp6gX7yY1NunJLS5PHD7ykVcIvM=
38
+ github.com/tabnas/debug/go v0.2.3/go.mod h1:EXSNFdN6Ct9pcAUk8ZGozNbIltb3Hw0wcne+5vWQyns=
39
+ github.com/tabnas/json/go v0.4.0 h1:1BxLHyCullkKXkvui/SuZ4s6OMrFVDuEB13IX/5S1eM=
40
+ github.com/tabnas/json/go v0.4.0/go.mod h1:MJzyziKcvZk3OZCaSDxhMdf/Wkq2UJ0uLGWFtp9zsJs=
41
+ github.com/tabnas/jsonic/go v0.4.0 h1:y5k/P21C3q3jWaA+VxEhXxzZ8xJgpgAehMBEseDN31g=
42
+ github.com/tabnas/jsonic/go v0.4.0/go.mod h1:eDpkddhkuTFuIXMkSqTZl7cU7M23swbMpkXR1W5bApQ=
43
+ github.com/tabnas/parser/go v0.4.0 h1:M8+qRT4KaCtr4OCpg9NDNUXJIdbbweqeqbpEpVGNEqU=
44
+ github.com/tabnas/parser/go v0.4.0/go.mod h1:WrlfEVyZ1QjEIowWiyEu3K1iHj7wxuPut5zoH9Trehk=
31
45
  `
32
46
 
33
47
 
@@ -40,6 +54,14 @@ const Main = cmp(function Main(props: any) {
40
54
  const cliModule = `github.com/${org}/${model.name}-sdk/go-cli`
41
55
 
42
56
  const entityMap: any = getModelPath(model, `main.${KIT}.entity`)
57
+ // Derive each entity's PascalCase `Name` here rather than relying on another
58
+ // TARGET having run first. This target sets `phase.entity: { active: false }`
59
+ // (see model/target/go-{cli,mcp}.aontu), so create-sdkgen's Root.ts never
60
+ // calls names() for it — the accessor emitted below used to read `Name` off
61
+ // objects the `go` target happened to have named as a side effect, which
62
+ // yields `client.undefined(nil)` whenever this target is generated without
63
+ // `go`, or before it in target order.
64
+ deriveEntityNames(entityMap)
43
65
  const entityNames = Object.keys(entityMap).map(n => n.toLowerCase())
44
66
 
45
67
  const FRAGMENT = Path.normalize(__dirname + '/../../../src/cmp/go-cli/fragment')
@@ -56,7 +78,7 @@ const Main = cmp(function Main(props: any) {
56
78
  // EVERYTHING here is MODEL-DRIVEN: verbs, examples and how-to sections are
57
79
  // gated on whether an active entity actually exposes that op
58
80
  // (op.<name>.active !== false) — never document an operation no entity
59
- // supports. The CLI implements three AQL words (list / load / update; see
81
+ // supports. The CLI implements three boru words (list / load / update; see
60
82
  // words.fragment.go + runOp).
61
83
  // ==========================================================================
62
84
  const bin = `${model.name}-cli`
@@ -121,7 +143,7 @@ const Main = cmp(function Main(props: any) {
121
143
  ex.push('# 3. Provide credentials once, via the environment')
122
144
  ex.push(`export ${apiKeyEnv}=sk_live_xxx`)
123
145
  ex.push('')
124
- ex.push('# 4. Each command line is ONE AQL expression, run against the API:')
146
+ ex.push('# 4. Each command line is ONE boru expression, run against the API:')
125
147
  if (firstHas('list')) ex.push(`./${bin} list ${firstEntity}`)
126
148
  if (firstHas('load')) {
127
149
  ex.push(`./${bin} load 1 ${firstEntity} # {id:1} shorthand`)
@@ -150,7 +172,7 @@ const Main = cmp(function Main(props: any) {
150
172
  \`\`\`
151
173
 
152
174
  \`list <entity>\` returns the first page of records. \`<entity>\` is a bareword —
153
- it is auto-quoted as an AQL atom, so no quotes are needed.`)
175
+ it is auto-quoted as an boru atom, so no quotes are needed.`)
154
176
 
155
177
  if (firstHas('load')) howtos.push(`### Load a single record
156
178
 
@@ -186,7 +208,7 @@ Both are injectable by a secrets vault, so the key never has to be typed inline.
186
208
  howtos.push(`### Explore interactively with the REPL
187
209
 
188
210
  Run with no arguments to open a REPL (prompt \`${model.name}>\`). Each line is
189
- evaluated as its own AQL expression:
211
+ evaluated as its own boru expression:
190
212
 
191
213
  \`\`\`text
192
214
  $ ./${bin}
@@ -210,10 +232,10 @@ below — this SDK exposes ${entityCount} ${entityNoun}.`)
210
232
 
211
233
  File({ name: 'README.md' }, () => Content(`# ${model.name}-cli
212
234
 
213
- AQL-driven command-line client **and** interactive REPL for the ${model.Name}
214
- SDK. Each command line is parsed as a single [AQL](https://github.com/aql-lang/aql)
235
+ boru-driven command-line client **and** interactive REPL for the ${model.Name}
236
+ SDK. Each command line is parsed as a single [boru](https://github.com/boru-lang/boru)
215
237
  expression and evaluated against the live API; run it with no arguments to drop
216
- into a REPL. Built on \`github.com/aql-lang/aql/eng/go\` and the sibling Go SDK
238
+ into a REPL. Built on \`github.com/boru-lang/boru/eng/go\` and the sibling Go SDK
217
239
  at \`../go\`.
218
240
 
219
241
  ## Examples
@@ -240,7 +262,7 @@ ${exampleBlock}
240
262
  export ${apiKeyEnv}=sk_live_xxx
241
263
  \`\`\`
242
264
 
243
- 3. **Run a query.** Evaluate an AQL expression against the API (or run with no
265
+ 3. **Run a query.** Evaluate an boru expression against the API (or run with no
244
266
  arguments to open the REPL):
245
267
 
246
268
  \`\`\`sh
@@ -250,7 +272,7 @@ ${exampleBlock}
250
272
  4. **Go interactive.** Run the binary with no arguments to open the REPL, then
251
273
  type \`/help\` for the word and entity lists and \`/quit\` to leave.
252
274
 
253
- That is the whole loop: *build → set key → evaluate AQL expressions*.
275
+ That is the whole loop: *build → set key → evaluate boru expressions*.
254
276
 
255
277
  ## How-to guides
256
278
 
@@ -260,13 +282,13 @@ ${howtoBlock}
260
282
 
261
283
  ### Words
262
284
 
263
- The CLI registers these AQL words, each bound to the SDK:
285
+ The CLI registers these boru words, each bound to the SDK:
264
286
 
265
287
  | Word | Signatures | Returns |
266
288
  |----------|-----------------------------------------------|--------------------------------|
267
289
  ${verbRows}
268
290
 
269
- - \`<entity>\` is a bareword, auto-quoted as an AQL atom (e.g. \`${firstEntity}\`).
291
+ - \`<entity>\` is a bareword, auto-quoted as an boru atom (e.g. \`${firstEntity}\`).
270
292
  - \`<query>\` is either a **Map** (\`{id:1}\`) or a **Scalar** (\`1\`, treated as
271
293
  \`{id:1}\`). A scalar is always wrapped as \`{id:<value>}\`.
272
294
 
@@ -285,7 +307,7 @@ Unset variables fall back to the SDK's built-in defaults.
285
307
 
286
308
  ### REPL commands
287
309
 
288
- Meta-commands use the \`/\` prefix (everything else on a line is evaluated as AQL):
310
+ Meta-commands use the \`/\` prefix (everything else on a line is evaluated as boru):
289
311
 
290
312
  - \`/quit\` / \`/q\` / \`/exit\` — exit the REPL
291
313
  - \`/help\` / \`/h\` / \`/?\` — show the word list, entity list and meta commands
@@ -313,25 +335,25 @@ ${entityList}
313
335
 
314
336
  ## Explanation
315
337
 
316
- ### Why AQL?
338
+ ### Why boru?
317
339
 
318
- The whole command line is one [AQL](https://github.com/aql-lang/aql) expression,
340
+ The whole command line is one [boru](https://github.com/boru-lang/boru) expression,
319
341
  not a fixed \`verb --flag\` grammar. That means the same binary works one-shot
320
342
  (\`./${bin} <expr>\`) and interactively (the REPL), and expressions compose the
321
- same way in both. \`list\` / \`load\` / \`update\` are ordinary AQL *words* bound to
343
+ same way in both. \`list\` / \`load\` / \`update\` are ordinary boru *words* bound to
322
344
  the SDK — adding SDK operations is adding words, not re-parsing flags.
323
345
 
324
346
  ### How it is wired
325
347
 
326
348
  \`main.go\` builds the SDK client (configured from the environment), creates an
327
- AQL registry, and \`words.go\` registers \`list\` / \`load\` / \`update\` as native
349
+ boru registry, and \`words.go\` registers \`list\` / \`load\` / \`update\` as native
328
350
  words that dispatch on the entity atom and call the sibling Go SDK at \`../go\`.
329
351
  Results are unwrapped from their \`Entity\` wrappers to plain data before being
330
352
  printed.
331
353
 
332
354
  ### Output format
333
355
 
334
- Each result value is printed as its AQL string form (a JSON-like rendering of
356
+ Each result value is printed as its boru string form (a JSON-like rendering of
335
357
  the record or list of records). One-shot mode prints to stdout; errors go to
336
358
  stderr with a non-zero exit code.
337
359
 
@@ -342,25 +364,30 @@ this repo, or upstream at
342
364
  \`github.com/voxgig/sdkgen/project/.sdk/src/cmp/go-cli/\`.
343
365
  `))
344
366
 
345
- // go.mod — sibling SDK via relative replace; aql/eng/go from the
346
- // public Go module proxy. The go directive must be >= aql/eng/go's own
347
- // (go 1.24.7 at eng/go/v0.0.1) — keep in step with AQL_ENG_VERSION.
367
+ // go.mod — sibling SDK via relative replace; boru/eng/go from the
368
+ // public Go module proxy. The go directive must be >= boru/eng/go's own
369
+ // (go 1.24.7) — keep in step with BORU_ENG_VERSION.
348
370
  File({ name: 'go.mod' }, () => Content(`module ${cliModule}
349
371
 
350
372
  go 1.24.7
351
373
 
352
374
  require ${sdkModule} v0.0.0
353
- require github.com/aql-lang/aql/eng/go ${AQL_ENG_VERSION}
375
+ require github.com/boru-lang/boru/eng/go ${BORU_ENG_VERSION}
354
376
 
355
- require github.com/jsonicjs/jsonic/go v0.1.6 // indirect
377
+ require (
378
+ github.com/cockroachdb/apd/v3 v3.2.3 // indirect
379
+ github.com/tabnas/json/go v0.4.0 // indirect
380
+ github.com/tabnas/jsonic/go v0.4.0 // indirect
381
+ github.com/tabnas/parser/go v0.4.0 // indirect
382
+ )
356
383
 
357
384
  replace ${sdkModule} => ../go
358
385
  `))
359
386
 
360
- // go.sum — required for `go build` to accept the aql/eng/go dependency
387
+ // go.sum — required for `go build` to accept the boru/eng/go dependency
361
388
  // (the path-replaced sibling SDK needs no entry). Pinned alongside
362
- // AQL_ENG_VERSION above.
363
- File({ name: 'go.sum' }, () => Content(AQL_ENG_GOSUM))
389
+ // BORU_ENG_VERSION above.
390
+ File({ name: 'go.sum' }, () => Content(BORU_ENG_GOSUM))
364
391
 
365
392
  // Makefile — `make build` for the current machine, `make build-all` to
366
393
  // cross-compile for the three desktop OSes (linux, darwin, windows) on
@@ -1,6 +1,6 @@
1
1
  // Command ProjectName-cli is a CLI + REPL for the ProjectName SDK,
2
- // built on the AQL engine. Positional arguments are joined into a
3
- // single AQL expression and evaluated; with no arguments, falls into
2
+ // built on the boru engine. Positional arguments are joined into a
3
+ // single boru expression and evaluated; with no arguments, falls into
4
4
  // a REPL. Generated by sdkgen go-cli target.
5
5
  package main
6
6
 
@@ -11,8 +11,8 @@ import (
11
11
  "os"
12
12
  "strings"
13
13
 
14
- eng "github.com/aql-lang/aql/eng/go"
15
- "github.com/aql-lang/aql/eng/go/parser"
14
+ eng "github.com/boru-lang/boru/eng/go"
15
+ "github.com/boru-lang/boru/eng/go/parser"
16
16
  sdk "GOMODULE"
17
17
  )
18
18
 
@@ -28,10 +28,10 @@ func main() {
28
28
 
29
29
  // usage prints the CLI help (for --help / -h). No client or network setup.
30
30
  func usage(out io.Writer) {
31
- fmt.Fprintf(out, "%s-cli — AQL-driven CLI + REPL for the %s SDK\n\n", prompt, prompt)
31
+ fmt.Fprintf(out, "%s-cli — boru-driven CLI + REPL for the %s SDK\n\n", prompt, prompt)
32
32
  fmt.Fprintln(out, "Usage:")
33
- fmt.Fprintf(out, " %s-cli [--help] [<AQL expression>]\n\n", prompt)
34
- fmt.Fprintln(out, "With arguments, they are joined into a single AQL expression and")
33
+ fmt.Fprintf(out, " %s-cli [--help] [<boru expression>]\n\n", prompt)
34
+ fmt.Fprintln(out, "With arguments, they are joined into a single boru expression and")
35
35
  fmt.Fprintln(out, "evaluated against the API. With no arguments, starts an interactive REPL.")
36
36
  fmt.Fprintln(out)
37
37
  fmt.Fprintln(out, "Words: list / load / update <query?> <entity>")
@@ -5,11 +5,11 @@ import (
5
5
  "fmt"
6
6
  "strings"
7
7
 
8
- eng "github.com/aql-lang/aql/eng/go"
8
+ eng "github.com/boru-lang/boru/eng/go"
9
9
  sdk "GOMODULE"
10
10
  )
11
11
 
12
- // registerSDKWords installs three native AQL words bound to the SDK:
12
+ // registerSDKWords installs three native boru words bound to the SDK:
13
13
  // list / load / update. Each is declared with two overloads matching
14
14
  // the signature [query?:(Node or Scalar) entity:atom]:
15
15
  //
@@ -18,31 +18,34 @@ import (
18
18
  // `load {id:1} book`, `load 1 book`)
19
19
  //
20
20
  // The entity slot is /q-quoted so a bareword `book` parses as the
21
- // Atom "book" rather than dispatching as an undefined word.
21
+ // Atom "book" rather than dispatching as an undefined word. Both
22
+ // overloads are all-forward (BarrierAllForward), so args are collected
23
+ // from the tokens following the word.
22
24
  func registerSDKWords(r *eng.Registry, client *sdk.ProjectNameSDK) {
23
25
  for _, op := range []string{"list", "load", "update"} {
24
26
  op := op
25
- single := eng.NativeSig{
27
+ single := eng.Signature{
26
28
  Args: []*eng.Type{eng.TAtom},
27
29
  QuoteArgs: map[int]bool{0: true},
28
- Handler: func(args []eng.Value, _ map[string]eng.Value, _ []eng.Value, _ *eng.Registry) ([]eng.Value, error) {
30
+ Impl: eng.Go(func(args []eng.Value, _ map[string]eng.Value, _ []eng.Value, _ *eng.Registry) ([]eng.Value, error) {
29
31
  return runOp(client, op, nil, args[0])
30
- },
31
- Returns: []*eng.Type{eng.TAny},
32
+ }),
33
+ Returns: []*eng.Type{eng.TAny},
34
+ BarrierPos: eng.BarrierAllForward,
32
35
  }
33
- dual := eng.NativeSig{
36
+ dual := eng.Signature{
34
37
  Args: []*eng.Type{eng.TAny, eng.TAtom},
35
38
  QuoteArgs: map[int]bool{1: true},
36
- Handler: func(args []eng.Value, _ map[string]eng.Value, _ []eng.Value, _ *eng.Registry) ([]eng.Value, error) {
39
+ Impl: eng.Go(func(args []eng.Value, _ map[string]eng.Value, _ []eng.Value, _ *eng.Registry) ([]eng.Value, error) {
37
40
  q := args[0]
38
41
  return runOp(client, op, &q, args[1])
39
- },
40
- Returns: []*eng.Type{eng.TAny},
42
+ }),
43
+ Returns: []*eng.Type{eng.TAny},
44
+ BarrierPos: eng.BarrierAllForward,
41
45
  }
42
46
  r.RegisterNativeFunc(eng.NativeFunc{
43
- Name: op,
44
- ForwardArgs: true,
45
- Signatures: []eng.NativeSig{single, dual},
47
+ Name: op,
48
+ Signatures: []eng.Signature{single, dual},
46
49
  })
47
50
  }
48
51
  }
@@ -91,22 +94,22 @@ func entityFor(client *sdk.ProjectNameSDK, name string) (sdk.ProjectNameEntity,
91
94
  return nil, fmt.Errorf("unknown entity %q", name)
92
95
  }
93
96
 
94
- // queryToMap converts an AQL Value (Map or Scalar) into the
97
+ // queryToMap converts a boru Value (Map or Scalar) into the
95
98
  // `map[string]any` shape the SDK expects. Maps are unwrapped via
96
99
  // eng.ToNative. Scalars are wrapped as {"id": <value>} so the
97
100
  // shorthand `load 1 book` becomes `load {id:1} book`.
98
101
  func queryToMap(v eng.Value) (map[string]any, error) {
99
- if v.VType.Matches(eng.TMap) {
102
+ if v.Parent.ConformsTo(eng.TMap) {
100
103
  m, ok := eng.ToNative(v).(map[string]any)
101
104
  if !ok {
102
105
  return nil, fmt.Errorf("query map could not be unwrapped")
103
106
  }
104
107
  return m, nil
105
108
  }
106
- if v.VType.Matches(eng.TScalar) {
109
+ if v.Parent.ConformsTo(eng.TScalar) {
107
110
  return map[string]any{"id": eng.ToNative(v)}, nil
108
111
  }
109
- return nil, fmt.Errorf("query must be a Map or Scalar, got %s", v.VType)
112
+ return nil, fmt.Errorf("query must be a Map or Scalar, got %s", v.Parent)
110
113
  }
111
114
 
112
115
  // extractData walks an SDK result and replaces any sdk.Entity wrapper
@@ -2,7 +2,7 @@
2
2
  import * as Path from 'node:path'
3
3
 
4
4
  import {
5
- cmp, each,
5
+ cmp, each, deriveEntityNames,
6
6
  File, Content, Fragment, Slot,
7
7
  } from '@voxgig/sdkgen'
8
8
 
@@ -54,6 +54,14 @@ const Main = cmp(function Main(props: any) {
54
54
  const mcpModule = `github.com/${org}/${model.name}-sdk/go-mcp`
55
55
 
56
56
  const entityMap: any = getModelPath(model, `main.${KIT}.entity`)
57
+ // Derive each entity's PascalCase `Name` here rather than relying on another
58
+ // TARGET having run first. This target sets `phase.entity: { active: false }`
59
+ // (see model/target/go-{cli,mcp}.aontu), so create-sdkgen's Root.ts never
60
+ // calls names() for it — the accessor emitted below used to read `Name` off
61
+ // objects the `go` target happened to have named as a side effect, which
62
+ // yields `client.undefined(nil)` whenever this target is generated without
63
+ // `go`, or before it in target order.
64
+ deriveEntityNames(entityMap)
57
65
  const entityNames = Object.keys(entityMap).map(n => n.toLowerCase())
58
66
  const entityHelp = entityNames.length > 0 ? entityNames.join(' | ') : '(none)'
59
67
 
@@ -67,35 +67,44 @@ readDoc path = do
67
67
  pure (either (const "") id r)
68
68
 
69
69
 
70
- -- Extract the body of every fenced Haskell block from markdown. The fence
71
- -- marker (three backticks) is built from its char code so this source stays
72
- -- backtick-free.
73
- haskellBlocks :: String -> [String]
70
+ -- Extract the body of every fenced Haskell block from markdown. Returns
71
+ -- (blocks, allClosed) where allClosed is False when a fence was opened but
72
+ -- never closed before EOF — a malformed doc that must fail rather than pass
73
+ -- silently on the unterminated block. The fence marker (three backticks) is
74
+ -- built from its char code so this source stays backtick-free.
75
+ haskellBlocks :: String -> ([String], Bool)
74
76
  haskellBlocks src = go (lines src)
75
77
  where
76
78
  fence3 = replicate 3 (toEnum 96 :: Char)
77
79
  fenceHs = fence3 ++ "haskell"
78
- go [] = []
80
+ go [] = ([], True)
79
81
  go (l : ls)
80
82
  | trimWs l == fenceHs =
81
- let (blk, rest) = break (\\x -> trimWs x == fence3) ls
82
- in unlines blk : go (drop 1 rest)
83
+ case break (\\x -> trimWs x == fence3) ls of
84
+ (blk, []) -> ([unlines blk], False)
85
+ (blk, _ : rest) -> let (bs, ok) = go rest in (unlines blk : bs, ok)
83
86
  | otherwise = go ls
84
87
 
85
88
 
86
- -- Balanced (), [], {} ignoring the contents of double-quoted string literals.
87
- -- The generated snippets never embed an escaped quote inside a string.
89
+ -- Balanced (), [], {} outside of double-quoted string literals, with each
90
+ -- closer matching the most-recent opener via a stack (so "([)]" is rejected,
91
+ -- not merely counted). The generated snippets never embed an escaped quote
92
+ -- inside a string.
88
93
  balanced :: String -> Bool
89
- balanced = go False (0 :: Int)
94
+ balanced = go False []
90
95
  where
91
- go inStr d [] = not inStr && d == 0
92
- go inStr d (c : cs)
93
- | c == '"' = go (not inStr) d cs
94
- | inStr = go inStr d cs
95
- | c == '(' || c == '[' || c == '{' = go inStr (d + 1) cs
96
+ go inStr stack [] = not inStr && null stack
97
+ go inStr stack (c : cs)
98
+ | c == '"' = go (not inStr) stack cs
99
+ | inStr = go inStr stack cs
100
+ | c == '(' = go inStr (')' : stack) cs
101
+ | c == '[' = go inStr (']' : stack) cs
102
+ | c == '{' = go inStr ('}' : stack) cs
96
103
  | c == ')' || c == ']' || c == '}' =
97
- if d <= 0 then False else go inStr (d - 1) cs
98
- | otherwise = go inStr d cs
104
+ case stack of
105
+ (top : rest) | top == c -> go inStr rest cs
106
+ _ -> False
107
+ | otherwise = go inStr stack cs
99
108
 
100
109
 
101
110
  -- The three documents held to the gate, tagged by human label.
@@ -111,7 +120,8 @@ tests :: Counters -> IO ()
111
120
  tests c =
112
121
  forM_ docs (\\(label, path) -> do
113
122
  src <- readDoc path
114
- let blocks = haskellBlocks src
123
+ let (blocks, closed) = haskellBlocks src
124
+ runTest c (label ++ " haskell fences closed") (pure closed)
115
125
  forM_ (zip [1 :: Int ..] blocks) (\\(i, blk) ->
116
126
  runTest c (label ++ " haskell block " ++ show i ++ " well-formed")
117
127
  (pure (not (null (trimWs blk)) && balanced blk))))
@@ -37,7 +37,7 @@ import {
37
37
  File, Content,
38
38
  } from '@voxgig/sdkgen'
39
39
 
40
- import { canonToType, opTypeName, opRequestShape, warnEntityTypeCollisions } from '@voxgig/sdkgen'
40
+ import { canonToType, opTypeName, opRequestShape, warnEntityTypeCollisions , deriveEntityNames } from '@voxgig/sdkgen'
41
41
 
42
42
  import {
43
43
  KIT,
@@ -134,11 +134,10 @@ const EntityTypes = cmp(function EntityTypes(props: any) {
134
134
  // filter, so inactive entities still get class files referencing these
135
135
  // typed names. Filter on `name` (always present), NOT `active` — parity
136
136
  // with the go emitter's fix.
137
- const entityList = each(entity).filter((e: any) => e && null != e.name)
137
+ const entityList = deriveEntityNames(entity)
138
138
  // Derive the PascalCase Name up-front — it is set LAZILY by names(), so an
139
139
  // entity not yet named (e.g. a fieldless placeholder) would otherwise read
140
140
  // `Name = undefined` below. Parity with the go/py/csharp emitter's fix.
141
- entityList.forEach((e: any) => { if (null == e.Name) names(e, e.name) })
142
141
 
143
142
  // Surface duplicate generated type names (two entities with the same
144
143
  // PascalCase Name) — they would redeclare a type in statically-typed
@@ -4,7 +4,7 @@ import * as Path from 'node:path'
4
4
  import {
5
5
  cmp, camelify, names,
6
6
  File, Content, Folder, Fragment,
7
- entityClassName,
7
+ entityClassName, entityCollection,
8
8
  } from '@voxgig/sdkgen'
9
9
 
10
10
  import {
@@ -25,7 +25,7 @@ const Entity = cmp(function Entity(props: any) {
25
25
  // Collision-free entity CLASS name (see entityClassName): normally
26
26
  // `<Name>Entity`, but disambiguated (e.g. `<Name>EntityClient`) when it
27
27
  // would clash with another entity's data-type name.
28
- const entityColl = getModelPath(model, `main.${KIT}.entity`)
28
+ const entityColl = entityCollection(model)
29
29
  const cls = entityClassName(entity, entityColl)
30
30
 
31
31
  const entrep = {
@@ -42,7 +42,7 @@ const Entity = cmp(function Entity(props: any) {
42
42
 
43
43
  File({ name: cls + '.' + target.ext }, () => {
44
44
 
45
- const opnames = Object.keys(entity.op)
45
+ const opnames = Object.keys(entity.op || {})
46
46
 
47
47
  // For each CRUD op: if the spec defines it, splice in the real
48
48
  // implementation. Otherwise emit a stub that satisfies the SdkEntity
@@ -1,6 +1,6 @@
1
1
 
2
2
 
3
- import { cmp, Content, entityClassName } from '@voxgig/sdkgen'
3
+ import { cmp, Content, entityClassName, entityCollection } from '@voxgig/sdkgen'
4
4
 
5
5
  import {
6
6
  KIT,
@@ -18,7 +18,7 @@ const MainEntity = cmp(async function MainEntity(props: any) {
18
18
  const { model } = props.ctx$
19
19
 
20
20
  const javapackage = javaPackage(model)
21
- const entityColl = getModelPath(model, `main.${KIT}.entity`)
21
+ const entityColl = entityCollection(model)
22
22
  const cls = entityClassName(entity, entityColl)
23
23
  const accessor = javaVarName(entity.name)
24
24
 
@@ -31,7 +31,7 @@ const Package = cmp(async function Package(props: any) {
31
31
 
32
32
  // Dep name convention: "groupId:artifactId" with an explicit version.
33
33
  const deps: { groupId: string, artifactId: string, version: string, kind: string }[] = []
34
- for (const d of collectDeps(model, target.name, target.deps)) {
34
+ for (const d of collectDeps(model, target.name, target.deps, ctx$.log)) {
35
35
  const [dgroup, dartifact] = String(d.name).split(':')
36
36
  if (dgroup && dartifact && d.version) {
37
37
  deps.push({
@@ -95,6 +95,23 @@ public class ReadmeExamplesTest {
95
95
  return blocks;
96
96
  }
97
97
 
98
+ // A well-formed doc has an even number of triple-backtick fence markers:
99
+ // every opening fence has a matching close. An odd count means a fence was
100
+ // opened but never closed — a truncated or malformed generated doc. The
101
+ // split-based javaBlocks() would silently treat the unterminated tail as a
102
+ // complete block, so this must be checked explicitly.
103
+ private static boolean fencesClosed(String text) {
104
+ String fence = String.valueOf((char) 96).repeat(3);
105
+ int count = 0;
106
+ int from = 0;
107
+ int idx;
108
+ while ((idx = text.indexOf(fence, from)) >= 0) {
109
+ count++;
110
+ from = idx + fence.length();
111
+ }
112
+ return count % 2 == 0;
113
+ }
114
+
98
115
  private static String readDoc(Path path, String label) {
99
116
  assertTrue(Files.exists(path), label + " not found: " + path);
100
117
  try {
@@ -158,7 +175,12 @@ public class ReadmeExamplesTest {
158
175
  if (!Files.exists(path)) {
159
176
  continue;
160
177
  }
161
- List<String> blocks = javaBlocks(readDoc(path, doc[0]));
178
+ String src = readDoc(path, doc[0]);
179
+ if (!fencesClosed(src)) {
180
+ failures.add(doc[0] +
181
+ " has an unclosed code fence (opened but never closed)");
182
+ }
183
+ List<String> blocks = javaBlocks(src);
162
184
  int balancedCount = 0;
163
185
  for (int i = 0; i < blocks.size(); i++) {
164
186
  if (balanced(blocks.get(i))) {
@@ -75,7 +75,7 @@ const TestDirect = cmp(function TestDirect(props: any) {
75
75
 
76
76
  const authActive = isAuthActive(model)
77
77
 
78
- const opnames = Object.keys(entity.op)
78
+ const opnames = Object.keys(entity.op || {})
79
79
  const hasLoad = opnames.includes('load')
80
80
  const hasList = opnames.includes('list')
81
81
 
@@ -83,8 +83,8 @@ const TestDirect = cmp(function TestDirect(props: any) {
83
83
  return
84
84
  }
85
85
 
86
- const loadOp = entity.op.load
87
- const listOp = entity.op.list
86
+ const loadOp = entity.op?.load
87
+ const listOp = entity.op?.list
88
88
 
89
89
  // Get load point info
90
90
  const loadPoint = loadOp?.points?.[0]