@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
@@ -27,21 +27,53 @@ function collectDeps(
27
27
  model: SdkModel,
28
28
  targetName: string,
29
29
  targetDeps: Record<string, ModelDep> | undefined,
30
+ log?: any,
30
31
  ): DepEntry[] {
31
32
  const out: DepEntry[] = []
32
33
  const feature = getModelPath(model, `main.${KIT}.feature`)
33
34
 
35
+ // Deduplicate by package name. Two features can require the same package
36
+ // (or a feature and the target itself can), and every Package_<lang>.ts
37
+ // renders one manifest line per entry — a duplicate key is a hard parse
38
+ // error in go.mod and Cargo.toml, and silently last-wins in package.json.
39
+ // FIRST occurrence wins, so the deterministic (sorted-key) feature order
40
+ // decides; a conflicting version is reported rather than silently dropped.
41
+ const seen: Record<string, DepEntry> = {}
42
+
43
+ const add = (dep: any, source: 'feature' | 'target', owner: string) => {
44
+ const name = dep.key$
45
+ if (null == name) return
46
+
47
+ const prev = seen[name]
48
+ if (null != prev) {
49
+ if (log?.warn && prev.version !== dep.version) {
50
+ log.warn({
51
+ point: 'dep-version-conflict', target: targetName, dep: name,
52
+ kept: prev.version, dropped: dep.version, from: owner,
53
+ note: `${targetName}: dependency ${name} declared twice with ` +
54
+ `different versions — keeping ${prev.version} (${prev.source}), ` +
55
+ `ignoring ${dep.version} (${source} ${owner})`,
56
+ })
57
+ }
58
+ return
59
+ }
60
+
61
+ const entry: DepEntry = {
62
+ name,
63
+ version: dep.version,
64
+ source,
65
+ raw: dep,
66
+ }
67
+ seen[name] = entry
68
+ out.push(entry)
69
+ }
70
+
34
71
  each(feature, (f: any) => {
35
72
  const langDeps = f?.deps?.[targetName]
36
73
  if (!langDeps) return
37
74
  each(langDeps, (dep: any) => {
38
75
  if (dep?.active) {
39
- out.push({
40
- name: dep.key$,
41
- version: dep.version,
42
- source: 'feature',
43
- raw: dep,
44
- })
76
+ add(dep, 'feature', f.name)
45
77
  }
46
78
  })
47
79
  })
@@ -49,12 +81,7 @@ function collectDeps(
49
81
  if (targetDeps) {
50
82
  each(targetDeps, (dep: any) => {
51
83
  if (dep?.active !== false) {
52
- out.push({
53
- name: dep.key$,
54
- version: dep.version,
55
- source: 'target',
56
- raw: dep,
57
- })
84
+ add(dep, 'target', targetName)
58
85
  }
59
86
  })
60
87
  }
@@ -69,6 +69,63 @@ const RESERVED: Record<string, Set<string>> = {
69
69
  }
70
70
 
71
71
 
72
+ // Ruby CORE CONSTANTS — a different hazard from the keyword sets above.
73
+ //
74
+ // The keyword sets guard local-variable BINDINGS. This set guards generated
75
+ // top-level CONSTANTS. Ruby constants share one namespace with the core
76
+ // classes, and reassigning one is not an error — it silently replaces it:
77
+ //
78
+ // File = Struct.new(:name) # ::File is now a Struct
79
+ // File.join('a', 'b') # NoMethodError — every later caller breaks
80
+ //
81
+ // The typed model emits `<Name> = Struct.new(...)` per entity, so an API with
82
+ // a `/files` collection (entity `File`) used to clobber Ruby's File class and
83
+ // take the whole SDK down with it — the generated test runner calls
84
+ // `File.join` to locate `.env.local`, so `rb` failed at require time.
85
+ //
86
+ // Only names Ruby itself defines at top level are listed: reassigning any of
87
+ // them breaks working code somewhere. Names that merely LOOK builtin but are
88
+ // not core constants (e.g. `Response`, `Record`) are safe and stay untouched,
89
+ // which keeps the rename off every SDK that does not actually collide.
90
+ const RB_CORE_CONSTANTS = new Set<string>([
91
+ // classes an entity name plausibly lands on
92
+ 'Array', 'Binding', 'Class', 'Comparable', 'Complex', 'Data', 'Dir',
93
+ 'Encoding', 'Enumerator', 'Exception', 'Fiber', 'File', 'Float', 'Hash',
94
+ 'IO', 'Integer', 'Method', 'Module', 'Mutex', 'Numeric', 'Object', 'Proc',
95
+ 'Queue', 'Random', 'Range', 'Rational', 'Regexp', 'Set', 'Signal', 'String',
96
+ 'Struct', 'Symbol', 'Thread', 'Time', 'UnboundMethod',
97
+ // modules / singletons
98
+ 'Enumerable', 'GC', 'Kernel', 'Marshal', 'Math', 'ObjectSpace', 'Process',
99
+ 'Warning',
100
+ // the rest of the exception hierarchy an API might name an entity after
101
+ 'ArgumentError', 'IndexError', 'IOError', 'KeyError', 'NameError',
102
+ 'NotImplementedError', 'RangeError', 'RuntimeError', 'StandardError',
103
+ 'StopIteration', 'SystemExit', 'TypeError', 'ZeroDivisionError',
104
+ // literal singletons
105
+ 'FalseClass', 'NilClass', 'TrueClass',
106
+ ])
107
+
108
+
109
+ // Is `Name` a constant Ruby already defines at top level?
110
+ function isRbCoreConstant(Name: string): boolean {
111
+ return RB_CORE_CONSTANTS.has(Name)
112
+ }
113
+
114
+
115
+ // A top-level-safe Ruby constant name for a generated type: the name
116
+ // unchanged, unless Ruby core already owns it, in which case `Type` is
117
+ // appended (`File` -> `FileType`). Applied ONLY to the bare entity data type
118
+ // — the per-op type names always carry a suffix (`FileCreateData`,
119
+ // `FileLoadMatch`), which no core constant matches.
120
+ //
121
+ // The entity ACCESSOR keeps its original name (`client.File(...)`): methods
122
+ // and constants live in separate namespaces in Ruby, so the accessor never
123
+ // collided and the public surface is unchanged.
124
+ function rbSafeTypeName(Name: string): string {
125
+ return isRbCoreConstant(Name) ? Name + 'Type' : Name
126
+ }
127
+
128
+
72
129
  // Is `name` a reserved word (an illegal identifier) in the target language?
73
130
  function isReservedName(name: string, lang: string): boolean {
74
131
  const set = RESERVED[lang]
@@ -130,6 +187,8 @@ export {
130
187
  isReservedName,
131
188
  safeVarName,
132
189
  exampleVarName,
190
+ isRbCoreConstant,
191
+ rbSafeTypeName,
133
192
  jsProp,
134
193
  jsOptProp,
135
194
  jsKey,
@@ -26,7 +26,60 @@
26
26
  // flag) and render them in the target language's struct/interface/TypedDict
27
27
  // syntax; the policy itself is language-neutral and tested in isolation.
28
28
 
29
- import { each } from 'jostraca'
29
+ import { each, names } from 'jostraca'
30
+ import { KIT, getModelPath } from '@voxgig/apidef'
31
+
32
+
33
+ // THE entity collection for a model — resolved once, with a stable identity.
34
+ //
35
+ // Two problems this solves, both caused by every component calling
36
+ // `getModelPath(model, 'main.<KIT>.entity')` for itself:
37
+ //
38
+ // * CORRECTNESS. getModelPath drops `active: false` entries by default, but
39
+ // the consumer scaffold (create-sdkgen Root.ts) generates entity code for
40
+ // EVERY entity and every EntityTypes_<lang> emits data types with
41
+ // `only_active: false`. Class-name assignment done against the filtered
42
+ // view cannot see the inactive entities whose data types it must avoid.
43
+ // This resolver always returns the unfiltered collection.
44
+ //
45
+ // * PERFORMANCE. getModelPath REBUILDS the container object on every call
46
+ // when filtering, so the WeakMap memos below never hit across callers —
47
+ // the O(n·ops) class-name assignment re-ran per entity per target. At 500
48
+ // entities x 22 targets that was ~15s of pure recomputation; caching the
49
+ // resolved collection on the model makes it ~3ms.
50
+ const _entityCollCache = new WeakMap<object, any>()
51
+
52
+ function entityCollection(model: any): any {
53
+ if (null == model || 'object' !== typeof model) {
54
+ return {}
55
+ }
56
+ const cached = _entityCollCache.get(model)
57
+ if (null != cached) {
58
+ return cached
59
+ }
60
+ const coll = getModelPath(model, `main.${KIT}.entity`,
61
+ { only_active: false, required: false }) || {}
62
+ deriveEntityNames(coll)
63
+ _entityCollCache.set(model, coll)
64
+ return coll
65
+ }
66
+
67
+
68
+ // Derive the PascalCase `Name` on every entity in a collection.
69
+ //
70
+ // `Name` is injected LAZILY by jostraca's names(), historically by whichever
71
+ // component happened to run first (create-sdkgen Root.ts, or an EntityTypes
72
+ // emitter). Anything reading `e.Name` before that ran saw `undefined` — and
73
+ // because the helpers below MEMOISE, one early read poisoned the result for
74
+ // the whole run (`undefinedEntity` class names; a permanently empty collision
75
+ // list). The helpers therefore derive `Name` themselves, up front, so they
76
+ // never depend on component ordering. Idempotent: names() is only called for
77
+ // an entity that lacks `Name`.
78
+ function deriveEntityNames(entityColl: any): any[] {
79
+ const ents = each(entityColl).filter((e: any) => e && null != e.name)
80
+ ents.forEach((e: any) => { if (null == e.Name) names(e, e.name) })
81
+ return ents
82
+ }
30
83
 
31
84
 
32
85
  // The five ops, and whether their request payload is a `Match` (query/id) or
@@ -156,8 +209,21 @@ function opRequestShape(ent: any, opname: string):
156
209
  return { items: [], fromParams: false }
157
210
  }
158
211
 
212
+ // Ops that carry a BODY are the exception to "op-declared params win":
213
+ // their request payload is BOTH. `PUT /v1/todo/item/{id}` declares the path
214
+ // param `id`, which the SDK resolves out of reqdata (see the param
215
+ // utility's reqmatch -> match -> reqdata search), while the fields the
216
+ // caller wants to change come from the entity. Params alone produced
217
+ // `<Name>UpdateData = { id }` — no way to send anything to update.
218
+ //
219
+ // The param stays in the payload because the path needs it; keeping it out
220
+ // of the request BODY is the model's job, via the op's `transform.req`
221
+ // (@voxgig/apidef restricts the body to a closed request schema's declared
222
+ // properties).
223
+ const isbodyop = 'create' === opname || 'update' === opname || 'patch' === opname
224
+
159
225
  const params = opParams(op)
160
- if (0 < params.length) {
226
+ if (0 < params.length && !isbodyop) {
161
227
  const items = params.map((p: any) => ({
162
228
  name: p.name,
163
229
  type: p.type,
@@ -166,15 +232,25 @@ function opRequestShape(ent: any, opname: string):
166
232
  return { items, fromParams: true }
167
233
  }
168
234
 
235
+ const paramItems = isbodyop ? params.map((p: any) => ({
236
+ name: p.name,
237
+ type: p.type,
238
+ optional: false === p.reqd,
239
+ })) : []
240
+ const paramNames = new Set(paramItems.map((p: any) => p.name))
241
+
169
242
  const fields = (ent.fields ? each(ent.fields) : [])
170
243
  .filter((f: any) => f.active !== false)
171
244
  .filter((f: any) => fieldInOp(f, opname))
172
245
 
173
- const items = fields.map((f: any) => ({
174
- name: f.name,
175
- type: f.type,
176
- optional: fieldOptional(f, opname),
177
- }))
246
+ const items = paramItems.concat(
247
+ fields
248
+ .filter((f: any) => !paramNames.has(f.name))
249
+ .map((f: any) => ({
250
+ name: f.name,
251
+ type: f.type,
252
+ optional: fieldOptional(f, opname),
253
+ })))
178
254
 
179
255
  return { items, fromParams: false }
180
256
  }
@@ -250,6 +326,16 @@ function entityPrimaryOp(ent: any): string | null {
250
326
  // … The DATA type keeps its canonical `<Name>` — only the suffixed class
251
327
  // yields. Deterministic (sorted-key iteration) and stable across runs.
252
328
  //
329
+ // Covers EVERY entity, active or not: the consumer scaffold (create-sdkgen
330
+ // Root.ts) iterates the RAW entity collection, and every EntityTypes_<lang>
331
+ // emits with `only_active: false`, so an inactive entity still contributes a
332
+ // generated data type AND still needs a class name. Filtering to actives here
333
+ // left inactive entities on the un-deduped `<Name>Entity` fallback and left
334
+ // their data types out of `taken` — so an ACTIVE entity's class could collide
335
+ // with an INACTIVE entity's emitted data type (e.g. active `project` ->
336
+ // class `ProjectEntity` vs inactive `project-entity` -> type `ProjectEntity`,
337
+ // a redeclaration in Go).
338
+ //
253
339
  // Memoised per entity-collection object so the O(n) assignment runs once.
254
340
  const _classNameCache = new WeakMap<object, Record<string, string>>()
255
341
 
@@ -259,7 +345,7 @@ function entityClassNames(entityColl: any): Record<string, string> {
259
345
  return cached
260
346
  }
261
347
 
262
- const ents = each(entityColl).filter((e: any) => e && e.active !== false)
348
+ const ents = deriveEntityNames(entityColl)
263
349
 
264
350
  // 1. Every top-level DATA-type name the target emits.
265
351
  const taken: Record<string, boolean> = {}
@@ -314,8 +400,8 @@ function entityClassName(ent: any, entityColl: any): string {
314
400
  // merging in ts. The names cannot be auto-renamed here — the generated
315
401
  // entity classes and op fragments reference them by token — so the guard
316
402
  // surfaces the collision loudly instead. Returns the sorted duplicate names
317
- // (empty when clean). Callers must have derived `Name` on each entity
318
- // (every EntityTypes emitter does).
403
+ // (empty when clean). `Name` is derived here (deriveEntityNames), so the
404
+ // guard cannot be silently disabled by running before an emitter.
319
405
  //
320
406
  // Memoised per entity-collection object, like entityClassNames.
321
407
  const _typeCollisionCache = new WeakMap<object, string[]>()
@@ -329,8 +415,7 @@ function entityTypeCollisions(entityColl: any): string[] {
329
415
  const counts: Record<string, number> = {}
330
416
  const bump = (n: string) => { counts[n] = (counts[n] || 0) + 1 }
331
417
 
332
- each(entityColl)
333
- .filter((e: any) => e && null != e.name && null != e.Name)
418
+ deriveEntityNames(entityColl)
334
419
  .forEach((e: any) => {
335
420
  bump(e.Name)
336
421
  for (const op of ['load', 'list', 'create', 'update', 'remove']) {
@@ -444,6 +529,8 @@ function entityDataIdField(ent: any): string | null {
444
529
 
445
530
  export {
446
531
  OP_SUFFIX,
532
+ deriveEntityNames,
533
+ entityCollection,
447
534
  opTypeName,
448
535
  opParams,
449
536
  opRequestShape,
package/src/sdkgen.ts CHANGED
@@ -5,7 +5,7 @@ import Path from 'node:path'
5
5
 
6
6
  import { prettyPino, Pino } from '@voxgig/util'
7
7
 
8
- import { Jsonic } from 'jsonic'
8
+ import { Jsonic } from '@tabnas/jsonic'
9
9
  import * as JostracaModule from 'jostraca'
10
10
  import { Aontu } from 'aontu'
11
11
 
@@ -51,8 +51,8 @@ import { getMatchEntries } from './helpers/getMatchEntries'
51
51
  import { collectDeps } from './helpers/collectDeps'
52
52
  import type { DepEntry } from './helpers/collectDeps'
53
53
  import { canonToType, canonKey } from './helpers/canonType'
54
- import { OP_SUFFIX, opTypeName, opParams, opRequestShape, entityIdField, entityDataIdField, entityOps, entityPrimaryOp, pickExampleEntity, entityClassName, entityTypeCollisions, warnEntityTypeCollisions } from './helpers/opShape'
55
- import { isReservedName, safeVarName, exampleVarName, jsProp, jsOptProp, jsKey } from './helpers/naming'
54
+ import { OP_SUFFIX, opTypeName, opParams, opRequestShape, entityIdField, entityDataIdField, entityOps, entityPrimaryOp, pickExampleEntity, entityClassName, entityTypeCollisions, warnEntityTypeCollisions, deriveEntityNames, entityCollection } from './helpers/opShape'
55
+ import { isReservedName, safeVarName, exampleVarName, isRbCoreConstant, rbSafeTypeName, jsProp, jsOptProp, jsKey } from './helpers/naming'
56
56
  import {
57
57
  packageName,
58
58
  installCommand,
@@ -473,9 +473,13 @@ export {
473
473
  entityClassName,
474
474
  entityTypeCollisions,
475
475
  warnEntityTypeCollisions,
476
+ deriveEntityNames,
477
+ entityCollection,
476
478
  isReservedName,
477
479
  safeVarName,
478
480
  exampleVarName,
481
+ isRbCoreConstant,
482
+ rbSafeTypeName,
479
483
  jsProp,
480
484
  jsOptProp,
481
485
  jsKey,