@voxgig/sdkgen 1.3.17 → 1.3.18

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 (220) hide show
  1. package/bin/voxgig-sdkgen +1 -1
  2. package/dist/cmp/Entity.js +5 -1
  3. package/dist/cmp/Entity.js.map +1 -1
  4. package/dist/cmp/Feature.js +2 -1
  5. package/dist/cmp/Feature.js.map +1 -1
  6. package/dist/helpers/canonType.js +8 -3
  7. package/dist/helpers/canonType.js.map +1 -1
  8. package/dist/helpers/collectDeps.d.ts +1 -1
  9. package/dist/helpers/collectDeps.js +36 -13
  10. package/dist/helpers/collectDeps.js.map +1 -1
  11. package/dist/helpers/naming.d.ts +3 -1
  12. package/dist/helpers/naming.js +53 -0
  13. package/dist/helpers/naming.js.map +1 -1
  14. package/dist/helpers/opShape.d.ts +3 -1
  15. package/dist/helpers/opShape.js +87 -8
  16. package/dist/helpers/opShape.js.map +1 -1
  17. package/dist/sdkgen.d.ts +3 -3
  18. package/dist/sdkgen.js +6 -2
  19. package/dist/sdkgen.js.map +1 -1
  20. package/dist/tsconfig.tsbuildinfo +1 -1
  21. package/package.json +15 -10
  22. package/project/.sdk/model/target/cpp.aontu +4 -4
  23. package/project/.sdk/model/target/go-cli.aontu +17 -17
  24. package/project/.sdk/model/target/go-mcp.aontu +11 -11
  25. package/project/.sdk/model/target/go.aontu +1 -1
  26. package/project/.sdk/model/target/java.aontu +4 -4
  27. package/project/.sdk/model/target/kotlin.aontu +4 -4
  28. package/project/.sdk/model/target/lean.aontu +51 -0
  29. package/project/.sdk/model/target/scala.aontu +4 -4
  30. package/project/.sdk/src/cmp/c/EntityTypes_c.ts +3 -4
  31. package/project/.sdk/src/cmp/c/Entity_c.ts +3 -3
  32. package/project/.sdk/src/cmp/c/ReadmeExamplesTest_c.ts +24 -7
  33. package/project/.sdk/src/cmp/c/TestDirect_c.ts +3 -3
  34. package/project/.sdk/src/cmp/c/TestEntity_c.ts +1 -1
  35. package/project/.sdk/src/cmp/clojure/Entity_clojure.ts +1 -1
  36. package/project/.sdk/src/cmp/clojure/ReadmeExamplesTest_clojure.ts +19 -8
  37. package/project/.sdk/src/cmp/cpp/EntityTypes_cpp.ts +2 -2
  38. package/project/.sdk/src/cmp/cpp/Entity_cpp.ts +3 -3
  39. package/project/.sdk/src/cmp/cpp/MainEntity_cpp.ts +2 -2
  40. package/project/.sdk/src/cmp/cpp/ReadmeExamplesTest_cpp.ts +136 -0
  41. package/project/.sdk/src/cmp/cpp/TestDirect_cpp.ts +3 -3
  42. package/project/.sdk/src/cmp/cpp/Test_cpp.ts +4 -0
  43. package/project/.sdk/src/cmp/csharp/EntityTypes_csharp.ts +2 -3
  44. package/project/.sdk/src/cmp/csharp/Entity_csharp.ts +3 -3
  45. package/project/.sdk/src/cmp/csharp/MainEntity_csharp.ts +2 -2
  46. package/project/.sdk/src/cmp/csharp/Package_csharp.ts +1 -1
  47. package/project/.sdk/src/cmp/csharp/ReadmeExamplesTest_csharp.ts +13 -1
  48. package/project/.sdk/src/cmp/csharp/TestDirect_csharp.ts +3 -3
  49. package/project/.sdk/src/cmp/dart/EntityTypes_dart.ts +2 -3
  50. package/project/.sdk/src/cmp/dart/Entity_dart.ts +3 -3
  51. package/project/.sdk/src/cmp/dart/MainEntity_dart.ts +2 -2
  52. package/project/.sdk/src/cmp/dart/Main_dart.ts +3 -3
  53. package/project/.sdk/src/cmp/dart/Package_dart.ts +1 -1
  54. package/project/.sdk/src/cmp/dart/TestDirect_dart.ts +4 -4
  55. package/project/.sdk/src/cmp/elixir/EntityTypes_elixir.ts +2 -3
  56. package/project/.sdk/src/cmp/elixir/Entity_elixir.ts +1 -1
  57. package/project/.sdk/src/cmp/elixir/ReadmeExamplesTest_elixir.ts +21 -3
  58. package/project/.sdk/src/cmp/go/Config_go.ts +4 -1
  59. package/project/.sdk/src/cmp/go/EntityTypes_go.ts +110 -18
  60. package/project/.sdk/src/cmp/go/Entity_go.ts +3 -3
  61. package/project/.sdk/src/cmp/go/Main_go.ts +7 -6
  62. package/project/.sdk/src/cmp/go/Package_go.ts +1 -1
  63. package/project/.sdk/src/cmp/go/TestDirect_go.ts +3 -3
  64. package/project/.sdk/src/cmp/go/TestEntity_go.ts +1 -1
  65. package/project/.sdk/src/cmp/go/utility_go.ts +25 -0
  66. package/project/.sdk/src/cmp/go-cli/Main_go-cli.ts +9 -1
  67. package/project/.sdk/src/cmp/go-mcp/Main_go-mcp.ts +9 -1
  68. package/project/.sdk/src/cmp/haskell/ReadmeExamplesTest_haskell.ts +28 -18
  69. package/project/.sdk/src/cmp/java/EntityTypes_java.ts +2 -3
  70. package/project/.sdk/src/cmp/java/Entity_java.ts +3 -3
  71. package/project/.sdk/src/cmp/java/MainEntity_java.ts +2 -2
  72. package/project/.sdk/src/cmp/java/Package_java.ts +1 -1
  73. package/project/.sdk/src/cmp/java/ReadmeExamplesTest_java.ts +23 -1
  74. package/project/.sdk/src/cmp/java/TestDirect_java.ts +3 -3
  75. package/project/.sdk/src/cmp/js/EntityTypes_js.ts +2 -3
  76. package/project/.sdk/src/cmp/js/Entity_js.ts +3 -3
  77. package/project/.sdk/src/cmp/js/MainEntity_js.ts +2 -2
  78. package/project/.sdk/src/cmp/js/Main_js.ts +2 -2
  79. package/project/.sdk/src/cmp/js/TestDirect_js.ts +4 -4
  80. package/project/.sdk/src/cmp/kotlin/EntityTypes_kotlin.ts +2 -3
  81. package/project/.sdk/src/cmp/kotlin/Entity_kotlin.ts +3 -3
  82. package/project/.sdk/src/cmp/kotlin/MainEntity_kotlin.ts +2 -2
  83. package/project/.sdk/src/cmp/kotlin/Package_kotlin.ts +1 -1
  84. package/project/.sdk/src/cmp/kotlin/ReadmeExamplesTest_kotlin.ts +27 -2
  85. package/project/.sdk/src/cmp/kotlin/TestDirect_kotlin.ts +3 -3
  86. package/project/.sdk/src/cmp/lean/Config_lean.ts +88 -0
  87. package/project/.sdk/src/cmp/lean/Entity_lean.ts +9 -0
  88. package/project/.sdk/src/cmp/lean/Gitignore_lean.ts +18 -0
  89. package/project/.sdk/src/cmp/lean/Main_lean.ts +120 -0
  90. package/project/.sdk/src/cmp/lean/Package_lean.ts +68 -0
  91. package/project/.sdk/src/cmp/lean/ReadmeEntity_lean.ts +29 -0
  92. package/project/.sdk/src/cmp/lean/ReadmeExplanation_lean.ts +19 -0
  93. package/project/.sdk/src/cmp/lean/ReadmeHowto_lean.ts +25 -0
  94. package/project/.sdk/src/cmp/lean/ReadmeInstall_lean.ts +38 -0
  95. package/project/.sdk/src/cmp/lean/ReadmeIntro_lean.ts +25 -0
  96. package/project/.sdk/src/cmp/lean/ReadmeModel_lean.ts +24 -0
  97. package/project/.sdk/src/cmp/lean/ReadmeOptions_lean.ts +22 -0
  98. package/project/.sdk/src/cmp/lean/ReadmeQuick_lean.ts +50 -0
  99. package/project/.sdk/src/cmp/lean/ReadmeRef_lean.ts +16 -0
  100. package/project/.sdk/src/cmp/lean/ReadmeTopHowto_lean.ts +16 -0
  101. package/project/.sdk/src/cmp/lean/ReadmeTopQuick_lean.ts +23 -0
  102. package/project/.sdk/src/cmp/lean/ReadmeTopTest_lean.ts +18 -0
  103. package/project/.sdk/src/cmp/lean/Test_lean.ts +207 -0
  104. package/project/.sdk/src/cmp/lean/utility_lean.ts +78 -0
  105. package/project/.sdk/src/cmp/lua/EntityTypes_lua.ts +2 -3
  106. package/project/.sdk/src/cmp/lua/Entity_lua.ts +3 -3
  107. package/project/.sdk/src/cmp/lua/Package_lua.ts +1 -1
  108. package/project/.sdk/src/cmp/lua/TestDirect_lua.ts +3 -3
  109. package/project/.sdk/src/cmp/lua/TestEntity_lua.ts +1 -1
  110. package/project/.sdk/src/cmp/ocaml/ReadmeExamplesTest_ocaml.ts +29 -14
  111. package/project/.sdk/src/cmp/perl/Entity_perl.ts +3 -3
  112. package/project/.sdk/src/cmp/perl/MainEntity_perl.ts +2 -2
  113. package/project/.sdk/src/cmp/perl/Package_perl.ts +1 -1
  114. package/project/.sdk/src/cmp/perl/TestDirect_perl.ts +3 -3
  115. package/project/.sdk/src/cmp/php/EntityTypes_php.ts +2 -3
  116. package/project/.sdk/src/cmp/php/Entity_php.ts +3 -3
  117. package/project/.sdk/src/cmp/php/MainEntity_php.ts +2 -2
  118. package/project/.sdk/src/cmp/php/Package_php.ts +1 -1
  119. package/project/.sdk/src/cmp/php/TestDirect_php.ts +3 -3
  120. package/project/.sdk/src/cmp/php/TestEntity_php.ts +1 -1
  121. package/project/.sdk/src/cmp/py/EntityTypes_py.ts +2 -3
  122. package/project/.sdk/src/cmp/py/Entity_py.ts +3 -3
  123. package/project/.sdk/src/cmp/py/MainEntity_py.ts +2 -2
  124. package/project/.sdk/src/cmp/py/Main_py.ts +2 -2
  125. package/project/.sdk/src/cmp/py/Package_py.ts +1 -1
  126. package/project/.sdk/src/cmp/py/TestDirect_py.ts +3 -3
  127. package/project/.sdk/src/cmp/py/TestEntity_py.ts +1 -1
  128. package/project/.sdk/src/cmp/rb/EntityTypes_rb.ts +15 -5
  129. package/project/.sdk/src/cmp/rb/Entity_rb.ts +3 -3
  130. package/project/.sdk/src/cmp/rb/MainEntity_rb.ts +2 -2
  131. package/project/.sdk/src/cmp/rb/Package_rb.ts +2 -2
  132. package/project/.sdk/src/cmp/rb/TestDirect_rb.ts +3 -3
  133. package/project/.sdk/src/cmp/rb/TestEntity_rb.ts +1 -1
  134. package/project/.sdk/src/cmp/rust/EntityBase_rust.ts +2 -2
  135. package/project/.sdk/src/cmp/rust/EntityTypes_rust.ts +3 -4
  136. package/project/.sdk/src/cmp/rust/Entity_rust.ts +3 -3
  137. package/project/.sdk/src/cmp/rust/MainEntity_rust.ts +2 -2
  138. package/project/.sdk/src/cmp/rust/Package_rust.ts +1 -1
  139. package/project/.sdk/src/cmp/rust/ReadmeExamplesTest_rust.ts +22 -10
  140. package/project/.sdk/src/cmp/rust/TestDirect_rust.ts +3 -3
  141. package/project/.sdk/src/cmp/scala/EntityTypes_scala.ts +2 -3
  142. package/project/.sdk/src/cmp/scala/Entity_scala.ts +3 -3
  143. package/project/.sdk/src/cmp/scala/MainEntity_scala.ts +2 -2
  144. package/project/.sdk/src/cmp/scala/ReadmeExamplesTest_scala.ts +22 -3
  145. package/project/.sdk/src/cmp/scala/TestDirect_scala.ts +3 -3
  146. package/project/.sdk/src/cmp/scala/Test_scala.ts +1 -1
  147. package/project/.sdk/src/cmp/swift/EntityTypes_swift.ts +3 -4
  148. package/project/.sdk/src/cmp/swift/Entity_swift.ts +3 -3
  149. package/project/.sdk/src/cmp/swift/MainEntity_swift.ts +2 -2
  150. package/project/.sdk/src/cmp/swift/Package_swift.ts +1 -1
  151. package/project/.sdk/src/cmp/swift/ReadmeExamplesTest_swift.ts +18 -1
  152. package/project/.sdk/src/cmp/swift/TestDirect_swift.ts +1 -1
  153. package/project/.sdk/src/cmp/ts/EntityTypes_ts.ts +2 -3
  154. package/project/.sdk/src/cmp/ts/Entity_ts.ts +3 -3
  155. package/project/.sdk/src/cmp/ts/MainEntity_ts.ts +2 -2
  156. package/project/.sdk/src/cmp/ts/Main_ts.ts +2 -2
  157. package/project/.sdk/src/cmp/ts/TestDirect_ts.ts +4 -4
  158. package/project/.sdk/src/cmp/zig/Entity_zig.ts +3 -3
  159. package/project/.sdk/src/cmp/zig/MainEntity_zig.ts +2 -2
  160. package/project/.sdk/src/cmp/zig/Package_zig.ts +10 -2
  161. package/project/.sdk/tm/cpp/test/primary_utility_test.cpp +8 -16
  162. package/project/.sdk/tm/csharp/test/PrimaryUtilityTest.cs +10 -28
  163. package/project/.sdk/tm/dart/test/primary_test.dart +7 -0
  164. package/project/.sdk/tm/go/feature/test_feature.go +33 -1
  165. package/project/.sdk/tm/go/test/primary_utility_test.go +41 -42
  166. package/project/.sdk/tm/go/test/runner_test.go +30 -1
  167. package/project/.sdk/tm/java/test/PrimaryUtilityTest.java +7 -24
  168. package/project/.sdk/tm/js/src/feature/test/TestFeature.js +18 -1
  169. package/project/.sdk/tm/js/test/utility/PrimaryUtility.test.js +8 -0
  170. package/project/.sdk/tm/kotlin/test/PrimaryUtilityTest.kt +7 -20
  171. package/project/.sdk/tm/lean/LICENSE +21 -0
  172. package/project/.sdk/tm/lean/VERSION +1 -0
  173. package/project/.sdk/tm/lean/src/SdkFeature.lean +171 -0
  174. package/project/.sdk/tm/lean/src/SdkFeatures.lean +602 -0
  175. package/project/.sdk/tm/lean/src/SdkJson.lean +134 -0
  176. package/project/.sdk/tm/lean/src/SdkRuntime.lean +356 -0
  177. package/project/.sdk/tm/lean/src/SdkUtility.lean +617 -0
  178. package/project/.sdk/tm/lean/src/VoxgigStruct.lean +2880 -0
  179. package/project/.sdk/tm/lean/src/Vregex.lean +412 -0
  180. package/project/.sdk/tm/lean/src/feature/README.md +5 -0
  181. package/project/.sdk/tm/lean/src/feature/audit/.gitkeep +0 -0
  182. package/project/.sdk/tm/lean/src/feature/base/.gitkeep +0 -0
  183. package/project/.sdk/tm/lean/src/feature/cache/.gitkeep +0 -0
  184. package/project/.sdk/tm/lean/src/feature/clienttrack/.gitkeep +0 -0
  185. package/project/.sdk/tm/lean/src/feature/debug/.gitkeep +0 -0
  186. package/project/.sdk/tm/lean/src/feature/idempotency/.gitkeep +0 -0
  187. package/project/.sdk/tm/lean/src/feature/log/.gitkeep +0 -0
  188. package/project/.sdk/tm/lean/src/feature/metrics/.gitkeep +0 -0
  189. package/project/.sdk/tm/lean/src/feature/netsim/.gitkeep +0 -0
  190. package/project/.sdk/tm/lean/src/feature/paging/.gitkeep +0 -0
  191. package/project/.sdk/tm/lean/src/feature/proxy/.gitkeep +0 -0
  192. package/project/.sdk/tm/lean/src/feature/ratelimit/.gitkeep +0 -0
  193. package/project/.sdk/tm/lean/src/feature/rbac/.gitkeep +0 -0
  194. package/project/.sdk/tm/lean/src/feature/retry/.gitkeep +0 -0
  195. package/project/.sdk/tm/lean/src/feature/streaming/.gitkeep +0 -0
  196. package/project/.sdk/tm/lean/src/feature/telemetry/.gitkeep +0 -0
  197. package/project/.sdk/tm/lean/src/feature/test/.gitkeep +0 -0
  198. package/project/.sdk/tm/lean/src/feature/timeout/.gitkeep +0 -0
  199. package/project/.sdk/tm/lean/test/StructCorpus.lean +697 -0
  200. package/project/.sdk/tm/lean/test/TFeature.lean +268 -0
  201. package/project/.sdk/tm/lean/test/TPrimaryUtility.lean +349 -0
  202. package/project/.sdk/tm/lua/test/primary_utility_test.lua +10 -8
  203. package/project/.sdk/tm/perl/t/primary_utility.t +8 -17
  204. package/project/.sdk/tm/php/test/PrimaryUtilityTest.php +9 -7
  205. package/project/.sdk/tm/py/feature/test_feature.py +28 -1
  206. package/project/.sdk/tm/py/test/test_primary_utility.py +13 -18
  207. package/project/.sdk/tm/rb/feature/test_feature.rb +24 -1
  208. package/project/.sdk/tm/rb/test/primary_utility_test.rb +7 -8
  209. package/project/.sdk/tm/rust/tests/common/mod.rs +37 -1
  210. package/project/.sdk/tm/rust/tests/primary_utility_test.rs +12 -26
  211. package/project/.sdk/tm/swift/Tests/ProjectNameSDKTests/PrimaryUtilityTest.swift +7 -8
  212. package/project/.sdk/tm/ts/src/feature/test/TestFeature.ts +18 -1
  213. package/project/.sdk/tm/ts/test/utility/PrimaryUtility.test.ts +65 -21
  214. package/src/cmp/Entity.ts +5 -1
  215. package/src/cmp/Feature.ts +2 -1
  216. package/src/helpers/canonType.ts +8 -3
  217. package/src/helpers/collectDeps.ts +39 -12
  218. package/src/helpers/naming.ts +59 -0
  219. package/src/helpers/opShape.ts +99 -12
  220. package/src/sdkgen.ts +7 -3
@@ -1,5 +1,5 @@
1
1
 
2
- import { cmp, Content, entityClassName } from '@voxgig/sdkgen'
2
+ import { cmp, Content, entityClassName, entityCollection } from '@voxgig/sdkgen'
3
3
 
4
4
  import {
5
5
  KIT,
@@ -12,7 +12,7 @@ const MainEntity = cmp(async function MainEntity(props: any) {
12
12
  const { model } = props.ctx$
13
13
 
14
14
  // Collision-free entity CLASS name (see entityClassName).
15
- const entityColl = getModelPath(model, `main.${KIT}.entity`)
15
+ const entityColl = entityCollection(model)
16
16
  const cls = entityClassName(entity, entityColl)
17
17
 
18
18
  const Name = model.const.Name
@@ -28,7 +28,7 @@ const Package = cmp(async function Package(props: any) {
28
28
  const Name = model.const.Name
29
29
 
30
30
  const deps: Record<string, string> = {}
31
- for (const d of collectDeps(model, target.name, target.deps)) {
31
+ for (const d of collectDeps(model, target.name, target.deps, ctx$.log)) {
32
32
  deps[d.name] = d.source === 'target' ? (d.version || '0.0.0') : d.version
33
33
  }
34
34
  // Vendored, dependency-free by design; declared deps (if any) are ignored
@@ -43,7 +43,9 @@ const ReadmeExamplesTest = cmp(function ReadmeExamplesTest(props: any) {
43
43
  // Checks, PER DOCUMENT that exists:
44
44
  // 1. PRESENCE: the doc holds at least one swift block.
45
45
  // 2. STRUCTURE: every swift block's braces / parens / brackets balance, so a
46
- // truncated or malformed generated snippet fails loudly.
46
+ // truncated or malformed generated snippet fails loudly. An unclosed fence
47
+ // (odd number of fence markers) also fails, rather than silently absorbing
48
+ // the trailing text as a block.
47
49
  //
48
50
  // GENERATED by @voxgig/sdkgen — do not edit by hand.
49
51
 
@@ -94,6 +96,16 @@ final class ReadmeExamplesTest: XCTestCase {
94
96
  return blocks
95
97
  }
96
98
 
99
+ // True when the doc has a fence that was opened but never closed. A
100
+ // well-formed doc holds fence markers in open/close pairs, so an ODD number
101
+ // of markers means the final fence dangles — the split-based scan above would
102
+ // otherwise silently treat the truncated tail as a block. This is the
103
+ // structural analogue of an at-EOF "still inside a block" check.
104
+ private func hasUnclosedFence(_ text: String) -> Bool {
105
+ let fenceCount = text.components(separatedBy: fence).count - 1
106
+ return fenceCount % 2 != 0
107
+ }
108
+
97
109
  // True when every open/close delimiter balances, ignoring characters inside
98
110
  // string literals and line comments (a generated snippet never nests an
99
111
  // unbalanced delimiter outside those, and this catches truncation).
@@ -149,6 +161,11 @@ final class ReadmeExamplesTest: XCTestCase {
149
161
  var failures: [String] = []
150
162
  for doc in docs() {
151
163
  guard let text = read(doc.path) else { continue }
164
+ // A fence opened but never closed is a malformed doc — fail loudly rather
165
+ // than silently absorbing the unterminated tail as a block.
166
+ if hasUnclosedFence(text) {
167
+ failures.append(doc.label + " has an unclosed swift code fence")
168
+ }
152
169
  let blocks = swiftBlocks(text)
153
170
  var balancedCount = 0
154
171
  for (i, b) in blocks.enumerated() {
@@ -24,7 +24,7 @@ const TestDirect = cmp(function TestDirect(props: any) {
24
24
 
25
25
  const Name = model.const.Name
26
26
 
27
- const opnames = Object.keys(entity.op)
27
+ const opnames = Object.keys(entity.op || {})
28
28
  if (!opnames.includes('load') && !opnames.includes('list')) {
29
29
  return
30
30
  }
@@ -21,7 +21,7 @@ import {
21
21
  File, Content,
22
22
  } from '@voxgig/sdkgen'
23
23
 
24
- import { canonToType, opTypeName, opRequestShape, warnEntityTypeCollisions } from '@voxgig/sdkgen'
24
+ import { canonToType, opTypeName, opRequestShape, warnEntityTypeCollisions , deriveEntityNames } from '@voxgig/sdkgen'
25
25
 
26
26
  import {
27
27
  KIT,
@@ -51,11 +51,10 @@ const EntityTypes = cmp(function EntityTypes(props: any) {
51
51
  // filter, so inactive entities still get class files referencing these
52
52
  // typed names. Filter on `name` (always present), NOT `active` — parity
53
53
  // with the go emitter's fix.
54
- const entityList = each(entity).filter((e: any) => e && null != e.name)
54
+ const entityList = deriveEntityNames(entity)
55
55
  // Derive the PascalCase Name up-front — it is set LAZILY by names(), so an
56
56
  // entity not yet named (e.g. a fieldless placeholder) would otherwise read
57
57
  // `Name = undefined` below. Parity with the go emitter's fix.
58
- entityList.forEach((e: any) => { if (null == e.Name) names(e, e.name) })
59
58
 
60
59
  // Surface duplicate generated type names (two entities with the same
61
60
  // 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, each, camelify, names,
6
6
  File, Content, Folder, Fragment, Line, FeatureHook, Slot,
7
- opTypeName, entityClassName,
7
+ opTypeName, entityClassName, entityCollection,
8
8
  } from '@voxgig/sdkgen'
9
9
 
10
10
  import {
@@ -24,7 +24,7 @@ const Entity = cmp(function Entity(props: any) {
24
24
  // `<Name>Entity`, disambiguated when it would clash with another entity's
25
25
  // data-type name. The DATA type stays `<Name>`. The class file name and the
26
26
  // Main import path both use this, so they always agree.
27
- const entityColl = getModelPath(model, `main.${KIT}.entity`)
27
+ const entityColl = entityCollection(model)
28
28
  const cls = entityClassName(entity, entityColl)
29
29
 
30
30
  const entrep = {
@@ -52,7 +52,7 @@ const Entity = cmp(function Entity(props: any) {
52
52
 
53
53
  File({ name: cls + '.' + target.name }, () => {
54
54
 
55
- const opnames = Object.keys(entity.op)
55
+ const opnames = Object.keys(entity.op || {})
56
56
 
57
57
  const opfrags =
58
58
  (['load', 'list', 'create', 'update', 'remove']
@@ -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,
@@ -14,7 +14,7 @@ const MainEntity = cmp(async function MainEntity(props: any) {
14
14
 
15
15
  // Return the collision-free class TYPE (entityClassName); the accessor METHOD
16
16
  // name (entity.Name) is unchanged so callers still write client.<Name>().
17
- const cls = entityClassName(entity, getModelPath(model, `main.${KIT}.entity`))
17
+ const cls = entityClassName(entity, entityCollection(model))
18
18
 
19
19
  Content(`
20
20
  // Entity access: \`client.${entity.Name}().list()\` / \`client.${entity.Name}().load({ id })\`.
@@ -4,7 +4,7 @@ import * as Path from 'node:path'
4
4
  import {
5
5
  cmp, each, names, cmap,
6
6
  List, File, Content, Copy, Folder, Fragment, Line, FeatureHook,
7
- entityClassName,
7
+ entityClassName, entityCollection,
8
8
  } from '@voxgig/sdkgen'
9
9
 
10
10
 
@@ -57,7 +57,7 @@ const Main = cmp(async function Main(props: any) {
57
57
  Line(`// ${model.const.Name} ${target.Name} SDK\n`)
58
58
 
59
59
  List({ item: entity }, ({ item }: any) => {
60
- const cls = entityClassName(item, entity)
60
+ const cls = entityClassName(item, entityCollection(model))
61
61
  return Line(`import { ${cls} } from './entity/${cls}'`)
62
62
  })
63
63
 
@@ -49,7 +49,7 @@ const TestDirect = cmp(function TestDirect(props: any) {
49
49
  apikey: env.${PROJECTNAME}_APIKEY,`
50
50
  : ''
51
51
 
52
- const opnames = Object.keys(entity.op)
52
+ const opnames = Object.keys(entity.op || {})
53
53
  const hasLoad = opnames.includes('load')
54
54
  const hasList = opnames.includes('list')
55
55
 
@@ -151,7 +151,7 @@ function unwrapListData(data: any): any[] | null {
151
151
 
152
152
 
153
153
  function generateDirectLoad(model: Model, entity: ModelEntity) {
154
- const loadOp = entity.op.load
154
+ const loadOp = entity.op?.load
155
155
  const loadPoint: ModelPoint | undefined = loadOp?.points?.[0]
156
156
 
157
157
  if (null == loadPoint) {
@@ -198,7 +198,7 @@ function generateDirectLoad(model: Model, entity: ModelEntity) {
198
198
  .join('\n')
199
199
 
200
200
  // Get list info for live mode bootstrapping
201
- const listOp = entity.op.list
201
+ const listOp = entity.op?.list
202
202
  const listPoint = listOp?.points?.[0]
203
203
  const listParams = listPoint?.args?.params || []
204
204
  const listPath = listPoint ? normalizePathParams(listPoint.parts || [], listParams, listPoint.rename?.param) : ''
@@ -356,7 +356,7 @@ ${paramAsserts} }
356
356
 
357
357
 
358
358
  function generateDirectList(model: Model, entity: ModelEntity) {
359
- const listOp = entity.op.list
359
+ const listOp = entity.op?.list
360
360
  const listPoint: ModelPoint | undefined = listOp?.points?.[0]
361
361
 
362
362
  if (null == listPoint) {
@@ -4,7 +4,7 @@ import * as Path from 'node:path'
4
4
  import {
5
5
  cmp, camelify,
6
6
  File, Content, Folder, Fragment,
7
- entityClassName,
7
+ entityClassName, entityCollection,
8
8
  } from '@voxgig/sdkgen'
9
9
 
10
10
  import {
@@ -20,7 +20,7 @@ const Entity = cmp(function Entity(props: any) {
20
20
  const { model, stdrep } = props.ctx$
21
21
  const { target, entity } = props
22
22
 
23
- const entityColl = getModelPath(model, `main.${KIT}.entity`)
23
+ const entityColl = entityCollection(model)
24
24
  const cls = entityClassName(entity, entityColl)
25
25
 
26
26
  const entrep = {
@@ -34,7 +34,7 @@ const Entity = cmp(function Entity(props: any) {
34
34
 
35
35
  File({ name: zigVarName(entity.name) + '.' + target.ext }, () => {
36
36
 
37
- const opnames = Object.keys(entity.op)
37
+ const opnames = Object.keys(entity.op || {})
38
38
 
39
39
  // For each CRUD op: if the spec defines it, splice in the real
40
40
  // implementation. Otherwise emit a stub returning the unsupported_op
@@ -1,5 +1,5 @@
1
1
 
2
- import { cmp, Content, entityClassName } from '@voxgig/sdkgen'
2
+ import { cmp, Content, entityClassName, entityCollection } from '@voxgig/sdkgen'
3
3
 
4
4
  import {
5
5
  KIT,
@@ -16,7 +16,7 @@ const MainEntity = cmp(async function MainEntity(props: any) {
16
16
  const { entity } = props
17
17
  const { model } = props.ctx$
18
18
 
19
- const entityColl = getModelPath(model, `main.${KIT}.entity`)
19
+ const entityColl = entityCollection(model)
20
20
  const cls = entityClassName(entity, entityColl)
21
21
  const method = zigVarName(entity.name)
22
22
  const mod = zigVarName(entity.name)
@@ -23,8 +23,16 @@ import { zigModuleName } from './utility_zig'
23
23
  //
24
24
  // The `.paths` allow-list mirrors the (registry-less) template: it only
25
25
  // matters when packaging for a registry, which zig does not do, so it is kept
26
- // stable. `.name` is a plain string here (matching the target's zig toolchain
27
- // pin) rather than the newer enum-literal + fingerprint form.
26
+ // stable. `.name` is a plain string here rather than the newer enum-literal +
27
+ // fingerprint form.
28
+ //
29
+ // TOOLCHAIN PIN: the string form REQUIRES zig <= 0.13. Zig 0.14 rejects it
30
+ // outright — `build.zig.zon:2:13: error: expected enum literal` — so the
31
+ // generated SDK will not build at all on a newer toolchain. The consumer CI
32
+ // job pins 0.13.0 to match (create-sdkgen
33
+ // project/standard/.github/workflows/ci.yml). Moving to a newer zig means
34
+ // changing BOTH: `.name = .${name}` plus a `.fingerprint` here, and the CI
35
+ // pin there.
28
36
  const Package = cmp(async function Package(props: any) {
29
37
  const ctx$ = props.ctx$
30
38
  const model: Model = ctx$.model
@@ -669,23 +669,16 @@ static void prepareParamsBasic() {
669
669
  // --- preparePath ------------------------------------------------------------
670
670
 
671
671
  static void preparePathBasic() {
672
+ // Was hand-written cases that had drifted out of the shared corpus (the
673
+ // preparePath fixture shipped as an empty `set: []`).
672
674
  auto c = client();
673
675
  UtilityPtr utility = c->getUtility();
674
- CtxPtr ctx = makeTestFullCtx(c, utility);
675
- ctx->point = fhMap({
676
- {"parts", vlist({Value("api"), Value("planet"), Value("{id}")})},
677
- {"args", fhMap({{"params", vlist()}})}});
678
- ASSERT_EQ(utility->preparePath(ctx), std::string("api/planet/{id}"), "expected api/planet/{id}");
679
- }
680
-
681
- static void preparePathSingle() {
682
- auto c = client();
683
- UtilityPtr utility = c->getUtility();
684
- CtxPtr ctx = makeTestFullCtx(c, utility);
685
- ctx->point = fhMap({
686
- {"parts", vlist({Value("items")})},
687
- {"args", fhMap({{"params", vlist()}})}});
688
- ASSERT_EQ(utility->preparePath(ctx), std::string("items"), "expected items");
676
+ rs::runset("preparePath-basic", rs::get_spec(primary(), {"preparePath", "basic"}),
677
+ [&](const Value& entry) -> Value {
678
+ Value ctxmap = Helpers::toMapAny(getp(entry, "ctx"));
679
+ CtxPtr ctx = rs::make_ctx_from_map(ctxmap, c, utility);
680
+ return Value(utility->preparePath(ctx));
681
+ });
689
682
  }
690
683
 
691
684
  // --- prepareQuery -----------------------------------------------------------
@@ -830,7 +823,6 @@ int main() {
830
823
  T_RUN(prepareMethodBasic);
831
824
  T_RUN(prepareParamsBasic);
832
825
  T_RUN(preparePathBasic);
833
- T_RUN(preparePathSingle);
834
826
  T_RUN(prepareQueryBasic);
835
827
  T_RUN(resultBasicBasic);
836
828
  T_RUN(resultBodyBasic);
@@ -789,38 +789,20 @@ public class PrimaryUtilityTest
789
789
  });
790
790
  }
791
791
 
792
+ // Was two hand-written cases that had drifted out of the shared corpus
793
+ // (the preparePath fixture shipped as an empty `set: []`). Now driven by
794
+ // the corpus like every other section, so all ports assert the same
795
+ // separator / blank-segment behaviour.
792
796
  [Fact]
793
797
  public void PreparePathBasic()
794
798
  {
795
- var ctx = MakeTestFullCtx(_client, _utility);
796
- ctx.Point = new Dictionary<string, object?>
799
+ TestRunner.RunSet(TestRunner.GetSpec(_primary, "preparePath", "basic"), entry =>
797
800
  {
798
- ["parts"] = new List<object?> { "api", "planet", "{id}" },
799
- ["args"] = new Dictionary<string, object?>
800
- {
801
- ["params"] = new List<object?>(),
802
- },
803
- };
804
-
805
- var path = _utility.PreparePath(ctx);
806
- Assert.Equal("api/planet/{id}", path);
807
- }
808
-
809
- [Fact]
810
- public void PreparePathSingle()
811
- {
812
- var ctx = MakeTestFullCtx(_client, _utility);
813
- ctx.Point = new Dictionary<string, object?>
814
- {
815
- ["parts"] = new List<object?> { "items" },
816
- ["args"] = new Dictionary<string, object?>
817
- {
818
- ["params"] = new List<object?>(),
819
- },
820
- };
821
-
822
- var path = _utility.PreparePath(ctx);
823
- Assert.Equal("items", path);
801
+ var ctxmap = entry.TryGetValue("ctx", out var c)
802
+ ? c as Dictionary<string, object?> : null;
803
+ var ctx = TestRunner.MakeCtxFromMap(ctxmap, _client, _utility);
804
+ return _utility.PreparePath(ctx);
805
+ });
824
806
  }
825
807
 
826
808
  [Fact]
@@ -94,6 +94,13 @@ void tests() {
94
94
  await _runset(_g('prepareQuery.basic'), _utility.prepareQuery);
95
95
  });
96
96
 
97
+ // preparePath shipped as an empty `set: []`, so no port drove it and
98
+ // several kept private hand-written cases instead.
99
+ test('path-basic', (t) async {
100
+ await _setup();
101
+ await _runset(_g('preparePath.basic'), _utility.preparePath);
102
+ });
103
+
97
104
  test('body-basic', (t) async {
98
105
  await _setup();
99
106
  await _runset(_g('prepareBody.basic'), (dynamic ctx) {
@@ -3,12 +3,17 @@ package feature
3
3
  import (
4
4
  "fmt"
5
5
  "math/rand"
6
+ "regexp"
6
7
 
7
8
  vs "github.com/voxgig/struct"
8
9
 
9
10
  "GOMODULE/core"
10
11
  )
11
12
 
13
+ // The `body.<key>` form of an op's response transform: the mock wraps its
14
+ // payload in <key> so the transform can unwrap it again.
15
+ var envelopeResRe = regexp.MustCompile("^`body\\.([^`.]+)`$")
16
+
12
17
  type TestFeature struct {
13
18
  BaseFeature
14
19
  client *core.ProjectNameSDK
@@ -49,11 +54,38 @@ func (f *TestFeature) Init(ctx *core.Context, options map[string]any) {
49
54
  self := f
50
55
 
51
56
  testFetcher := func(ctx *core.Context, _fullurl string, _fetchdef map[string]any) (any, error) {
57
+ // Shape the mock payload the way the real API would, so the op's
58
+ // response transform recovers the entity from it. A point carrying
59
+ // `transform.res: ` + "`body.item`" + ` describes an API that answers
60
+ // {"item": {...}}; handing back the bare entity means the transform
61
+ // unwraps a property that is not there and the caller gets nil. The
62
+ // mock has to agree with the model, or it only ever simulates APIs
63
+ // whose responses happen to be unwrapped. Mirrors the ts mock.
64
+ envelope := func(data any) any {
65
+ if data == nil || ctx.Point == nil {
66
+ return data
67
+ }
68
+ tm, ok := ctx.Point["transform"].(map[string]any)
69
+ if !ok {
70
+ return data
71
+ }
72
+ restf, ok := tm["res"].(string)
73
+ if !ok {
74
+ return data
75
+ }
76
+ m := envelopeResRe.FindStringSubmatch(restf)
77
+ if m == nil {
78
+ return data
79
+ }
80
+ return map[string]any{m[1]: data}
81
+ }
82
+
52
83
  respond := func(status int, data any, extra map[string]any) map[string]any {
84
+ payload := envelope(data)
53
85
  out := map[string]any{
54
86
  "status": status,
55
87
  "statusText": "OK",
56
- "json": (func() any)(func() any { return data }),
88
+ "json": (func() any)(func() any { return payload }),
57
89
  "body": "not-used",
58
90
  }
59
91
  if extra != nil {