@voxgig/sdkgen 3.5.1 → 3.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (255) hide show
  1. package/bin/voxgig-sdkgen +1 -1
  2. package/dist/cmp/AgentGuideTop.js +17 -0
  3. package/dist/cmp/AgentGuideTop.js.map +1 -1
  4. package/dist/cmp/ExternalTarget.js +1 -1
  5. package/dist/cmp/ExternalTarget.js.map +1 -1
  6. package/dist/cmp/Readme.js +2 -0
  7. package/dist/cmp/Readme.js.map +1 -1
  8. package/dist/cmp/ReadmeStation.d.ts +2 -0
  9. package/dist/cmp/ReadmeStation.js +57 -0
  10. package/dist/cmp/ReadmeStation.js.map +1 -0
  11. package/dist/helpers/naming.d.ts +6 -1
  12. package/dist/helpers/naming.js +156 -5
  13. package/dist/helpers/naming.js.map +1 -1
  14. package/dist/helpers/opShape.js +72 -0
  15. package/dist/helpers/opShape.js.map +1 -1
  16. package/dist/helpers/packageMeta.d.ts +2 -1
  17. package/dist/helpers/packageMeta.js +57 -20
  18. package/dist/helpers/packageMeta.js.map +1 -1
  19. package/dist/sdkgen.d.ts +3 -3
  20. package/dist/sdkgen.js +63 -18
  21. package/dist/sdkgen.js.map +1 -1
  22. package/dist/testkit.d.ts +39 -0
  23. package/dist/testkit.js +663 -0
  24. package/dist/testkit.js.map +1 -0
  25. package/dist/tsconfig.tsbuildinfo +1 -1
  26. package/dist/utility.d.ts +1 -1
  27. package/dist/utility.js +16 -2
  28. package/dist/utility.js.map +1 -1
  29. package/package.json +32 -8
  30. package/project/.sdk/src/cmp/c/Config_c.ts +34 -13
  31. package/project/.sdk/src/cmp/c/Test_c.ts +5 -7
  32. package/project/.sdk/src/cmp/clojure/Test_clojure.ts +3 -7
  33. package/project/.sdk/src/cmp/cpp/Config_cpp.ts +9 -46
  34. package/project/.sdk/src/cmp/cpp/Test_cpp.ts +4 -7
  35. package/project/.sdk/src/cmp/csharp/Config_csharp.ts +7 -1
  36. package/project/.sdk/src/cmp/csharp/Package_csharp.ts +1 -1
  37. package/project/.sdk/src/cmp/csharp/Test_csharp.ts +5 -7
  38. package/project/.sdk/src/cmp/dart/Config_dart.ts +14 -2
  39. package/project/.sdk/src/cmp/dart/Test_dart.ts +3 -4
  40. package/project/.sdk/src/cmp/dart/fragment/Config.data.fragment.dart +5 -0
  41. package/project/.sdk/src/cmp/dart/fragment/Config.fragment.dart +6 -0
  42. package/project/.sdk/src/cmp/dart/fragment/Main.fragment.dart +13 -4
  43. package/project/.sdk/src/cmp/elixir/Config_elixir.ts +12 -2
  44. package/project/.sdk/src/cmp/elixir/Package_elixir.ts +42 -3
  45. package/project/.sdk/src/cmp/elixir/Test_elixir.ts +5 -6
  46. package/project/.sdk/src/cmp/go/Config_go.ts +8 -1
  47. package/project/.sdk/src/cmp/go/EntityTypes_go.ts +1 -1
  48. package/project/.sdk/src/cmp/go/Entity_go.ts +1 -1
  49. package/project/.sdk/src/cmp/go/Gitignore_go.ts +6 -0
  50. package/project/.sdk/src/cmp/go/Main_go.ts +2 -2
  51. package/project/.sdk/src/cmp/go/Package_go.ts +1 -1
  52. package/project/.sdk/src/cmp/go/ReadmeExamplesTest_go.ts +59 -6
  53. package/project/.sdk/src/cmp/go/ReadmeExplanation_go.ts +1 -1
  54. package/project/.sdk/src/cmp/go/ReadmeHowto_go.ts +1 -1
  55. package/project/.sdk/src/cmp/go/ReadmeInstall_go.ts +1 -1
  56. package/project/.sdk/src/cmp/go/ReadmeModel_go.ts +1 -1
  57. package/project/.sdk/src/cmp/go/ReadmeQuick_go.ts +1 -1
  58. package/project/.sdk/src/cmp/go/ReadmeTopQuick_go.ts +1 -1
  59. package/project/.sdk/src/cmp/go/ReadmeTopTest_go.ts +1 -1
  60. package/project/.sdk/src/cmp/go/Test_go.ts +6 -8
  61. package/project/.sdk/src/cmp/go-cli/Main_go-cli.ts +6 -2
  62. package/project/.sdk/src/cmp/go-mcp/Main_go-mcp.ts +6 -2
  63. package/project/.sdk/src/cmp/java/Config_java.ts +8 -1
  64. package/project/.sdk/src/cmp/java/Test_java.ts +4 -7
  65. package/project/.sdk/src/cmp/js/Config_js.ts +9 -1
  66. package/project/.sdk/src/cmp/js/Package_js.ts +1 -1
  67. package/project/.sdk/src/cmp/js/Test_js.ts +4 -7
  68. package/project/.sdk/src/cmp/js/fragment/Config.data.fragment.js +7 -0
  69. package/project/.sdk/src/cmp/js/fragment/Config.fragment.js +8 -0
  70. package/project/.sdk/src/cmp/js/fragment/Main.fragment.js +33 -5
  71. package/project/.sdk/src/cmp/kotlin/Config_kotlin.ts +8 -1
  72. package/project/.sdk/src/cmp/kotlin/Test_kotlin.ts +4 -7
  73. package/project/.sdk/src/cmp/lean/Test_lean.ts +3 -3
  74. package/project/.sdk/src/cmp/lua/Config_lua.ts +11 -2
  75. package/project/.sdk/src/cmp/lua/Package_lua.ts +26 -3
  76. package/project/.sdk/src/cmp/lua/Test_lua.ts +5 -7
  77. package/project/.sdk/src/cmp/ocaml/Test_ocaml.ts +3 -7
  78. package/project/.sdk/src/cmp/perl/Config_perl.ts +8 -60
  79. package/project/.sdk/src/cmp/perl/Package_perl.ts +1 -1
  80. package/project/.sdk/src/cmp/perl/Test_perl.ts +5 -7
  81. package/project/.sdk/src/cmp/php/Config_php.ts +11 -2
  82. package/project/.sdk/src/cmp/php/EntityTypes_php.ts +13 -2
  83. package/project/.sdk/src/cmp/php/Main_php.ts +25 -0
  84. package/project/.sdk/src/cmp/php/Package_php.ts +2 -2
  85. package/project/.sdk/src/cmp/php/Test_php.ts +5 -7
  86. package/project/.sdk/src/cmp/php/fragment/Main.fragment.php +23 -6
  87. package/project/.sdk/src/cmp/py/Config_py.ts +11 -2
  88. package/project/.sdk/src/cmp/py/Main_py.ts +17 -7
  89. package/project/.sdk/src/cmp/py/Package_py.ts +2 -2
  90. package/project/.sdk/src/cmp/py/Test_py.ts +5 -7
  91. package/project/.sdk/src/cmp/py/fragment/Main.fragment.py +23 -6
  92. package/project/.sdk/src/cmp/py-data/Main_py-data.ts +14 -19
  93. package/project/.sdk/src/cmp/rb/Config_rb.ts +7 -1
  94. package/project/.sdk/src/cmp/rb/Package_rb.ts +3 -3
  95. package/project/.sdk/src/cmp/rb/ReadmeInstall_rb.ts +1 -1
  96. package/project/.sdk/src/cmp/rb/Test_rb.ts +5 -7
  97. package/project/.sdk/src/cmp/rust/Config_rust.ts +5 -2
  98. package/project/.sdk/src/cmp/rust/Test_rust.ts +5 -7
  99. package/project/.sdk/src/cmp/scala/Test_scala.ts +5 -2
  100. package/project/.sdk/src/cmp/seneca-provider/Gitignore_seneca-provider.ts +161 -0
  101. package/project/.sdk/src/cmp/seneca-provider/Main_seneca-provider.ts +20 -11
  102. package/project/.sdk/src/cmp/swift/Config_swift.ts +8 -54
  103. package/project/.sdk/src/cmp/swift/Package_swift.ts +52 -10
  104. package/project/.sdk/src/cmp/swift/Test_swift.ts +5 -7
  105. package/project/.sdk/src/cmp/ts/Config_ts.ts +9 -1
  106. package/project/.sdk/src/cmp/ts/EntityTypes_ts.ts +5 -2
  107. package/project/.sdk/src/cmp/ts/Entity_ts.ts +8 -2
  108. package/project/.sdk/src/cmp/ts/Package_ts.ts +1 -1
  109. package/project/.sdk/src/cmp/ts/Test_ts.ts +8 -7
  110. package/project/.sdk/src/cmp/ts/fragment/Config.data.fragment.ts +7 -0
  111. package/project/.sdk/src/cmp/ts/fragment/Config.fragment.ts +8 -0
  112. package/project/.sdk/src/cmp/ts/fragment/Entity.fragment.ts +1 -1
  113. package/project/.sdk/src/cmp/ts/fragment/Main.fragment.ts +12 -4
  114. package/project/.sdk/src/cmp/zig/Test_zig.ts +3 -7
  115. package/project/.sdk/tm/c/Makefile +6 -1
  116. package/project/.sdk/tm/c/utility/make_options.c +12 -1
  117. package/project/.sdk/tm/c/utility/make_point.c +64 -3
  118. package/project/.sdk/tm/clojure/src/sdk/core.clj +49 -14
  119. package/project/.sdk/tm/cpp/utility/pipeline.hpp +64 -4
  120. package/project/.sdk/tm/csharp/feature/TestFeature.cs +36 -2
  121. package/project/.sdk/tm/csharp/utility/Fetcher.cs +23 -5
  122. package/project/.sdk/tm/csharp/utility/MakeOptions.cs +13 -0
  123. package/project/.sdk/tm/csharp/utility/MakePoint.cs +65 -2
  124. package/project/.sdk/tm/dart/lib/feature/test/TestFeature.dart +34 -4
  125. package/project/.sdk/tm/dart/lib/utility/FetcherUtility.dart +9 -0
  126. package/project/.sdk/tm/dart/lib/utility/MakeOptionsUtility.dart +17 -0
  127. package/project/.sdk/tm/dart/lib/utility/MakePointUtility.dart +48 -2
  128. package/project/.sdk/tm/elixir/lib/projectname/utility.ex +109 -13
  129. package/project/.sdk/tm/elixir/test/feature_test.exs +19 -0
  130. package/project/.sdk/tm/elixir/test/primary_utility_test.exs +72 -0
  131. package/project/.sdk/tm/go/feature/test_feature.go +34 -2
  132. package/project/.sdk/tm/go/test/primary_utility_test.go +42 -20
  133. package/project/.sdk/tm/go/test/runner_test.go +1 -1
  134. package/project/.sdk/tm/go/utility/fetcher.go +14 -0
  135. package/project/.sdk/tm/go/utility/make_options.go +31 -4
  136. package/project/.sdk/tm/go/utility/make_point.go +66 -2
  137. package/project/.sdk/tm/java/feature/TestFeature.java +42 -2
  138. package/project/.sdk/tm/java/utility/Fetcher.java +11 -1
  139. package/project/.sdk/tm/java/utility/MakeOptions.java +11 -0
  140. package/project/.sdk/tm/java/utility/MakePoint.java +61 -2
  141. package/project/.sdk/tm/js/src/feature/test/TestFeature.js +22 -3
  142. package/project/.sdk/tm/js/src/utility/MakeOptionsUtility.js +20 -2
  143. package/project/.sdk/tm/js/src/utility/MakePointUtility.js +72 -2
  144. package/project/.sdk/tm/kotlin/feature/TestFeature.kt +31 -2
  145. package/project/.sdk/tm/kotlin/utility/Fetcher.kt +10 -1
  146. package/project/.sdk/tm/kotlin/utility/MakeOptions.kt +11 -0
  147. package/project/.sdk/tm/kotlin/utility/MakePoint.kt +58 -2
  148. package/project/.sdk/tm/lean/src/SdkUtility.lean +28 -0
  149. package/project/.sdk/tm/lean/test/TPrimaryUtility.lean +13 -2
  150. package/project/.sdk/tm/lua/utility/make_options.lua +44 -0
  151. package/project/.sdk/tm/lua/utility/make_point.lua +65 -2
  152. package/project/.sdk/tm/ocaml/sdk_runtime.ml +40 -2
  153. package/project/.sdk/tm/perl/utility/fetcher.pm +10 -1
  154. package/project/.sdk/tm/perl/utility/make_options.pm +36 -0
  155. package/project/.sdk/tm/perl/utility/make_point.pm +55 -2
  156. package/project/.sdk/tm/php/feature/TestFeature.php +30 -1
  157. package/project/.sdk/tm/php/test/PipelineTest.php +20 -0
  158. package/project/.sdk/tm/php/utility/Fetcher.php +12 -1
  159. package/project/.sdk/tm/php/utility/MakeOptions.php +58 -0
  160. package/project/.sdk/tm/php/utility/MakePoint.php +49 -1
  161. package/project/.sdk/tm/py/pkg/utility/fetcher.py +13 -1
  162. package/project/.sdk/tm/py/pkg/utility/make_options.py +23 -0
  163. package/project/.sdk/tm/py/pkg/utility/make_point.py +56 -2
  164. package/project/.sdk/tm/rb/utility/make_options.rb +18 -0
  165. package/project/.sdk/tm/rb/utility/make_point.rb +42 -2
  166. package/project/.sdk/tm/rust/tests/common/mod.rs +1 -1
  167. package/project/.sdk/tm/rust/tests/feature_test.rs +27 -0
  168. package/project/.sdk/tm/rust/utility/fetcher.rs +8 -0
  169. package/project/.sdk/tm/rust/utility/make_options.rs +15 -0
  170. package/project/.sdk/tm/rust/utility/make_point.rs +69 -2
  171. package/project/.sdk/tm/scala/feature/TestFeature.scala +36 -1
  172. package/project/.sdk/tm/scala/utility/Make.scala +57 -3
  173. package/project/.sdk/tm/swift/Sources/ProjectNameSDK/feature/TestFeature.swift +29 -1
  174. package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/Fetcher.swift +24 -1
  175. package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/Make.swift +51 -2
  176. package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/MakeOptions.swift +12 -0
  177. package/project/.sdk/tm/ts/src/feature/test/TestFeature.ts +22 -3
  178. package/project/.sdk/tm/ts/src/utility/MakeOptionsUtility.ts +20 -2
  179. package/project/.sdk/tm/ts/src/utility/MakePointUtility.ts +72 -2
  180. package/project/.sdk/tm/ts/test/utility/Corpus.test.ts +85 -0
  181. package/project/.sdk/tm/ts/test/utility/PrimaryUtility.test.ts +10 -17
  182. package/project/.sdk/tm/zig/core/utility.zig +66 -3
  183. package/project/sdkgen-package.json +1 -2
  184. package/src/cmp/AgentGuideTop.ts +18 -0
  185. package/src/cmp/ExternalTarget.ts +1 -1
  186. package/src/cmp/Readme.ts +2 -0
  187. package/src/cmp/ReadmeStation.ts +69 -0
  188. package/src/helpers/naming.ts +172 -5
  189. package/src/helpers/opShape.ts +85 -0
  190. package/src/helpers/packageMeta.ts +59 -20
  191. package/src/sdkgen.ts +70 -20
  192. package/src/testkit.ts +863 -0
  193. package/src/utility.ts +17 -2
  194. package/testkit.d.ts +3 -0
  195. package/testkit.js +12 -0
  196. package/project/.sdk/model/target/haskell.aontu +0 -72
  197. package/project/.sdk/src/cmp/haskell/Config_haskell.ts +0 -98
  198. package/project/.sdk/src/cmp/haskell/Entity_haskell.ts +0 -13
  199. package/project/.sdk/src/cmp/haskell/Gitignore_haskell.ts +0 -27
  200. package/project/.sdk/src/cmp/haskell/Main_haskell.ts +0 -123
  201. package/project/.sdk/src/cmp/haskell/Package_haskell.ts +0 -60
  202. package/project/.sdk/src/cmp/haskell/ReadmeEntity_haskell.ts +0 -186
  203. package/project/.sdk/src/cmp/haskell/ReadmeExamplesTest_haskell.ts +0 -135
  204. package/project/.sdk/src/cmp/haskell/ReadmeExplanation_haskell.ts +0 -48
  205. package/project/.sdk/src/cmp/haskell/ReadmeHowto_haskell.ts +0 -168
  206. package/project/.sdk/src/cmp/haskell/ReadmeInstall_haskell.ts +0 -51
  207. package/project/.sdk/src/cmp/haskell/ReadmeIntro_haskell.ts +0 -67
  208. package/project/.sdk/src/cmp/haskell/ReadmeModel_haskell.ts +0 -162
  209. package/project/.sdk/src/cmp/haskell/ReadmeOptions_haskell.ts +0 -74
  210. package/project/.sdk/src/cmp/haskell/ReadmeQuick_haskell.ts +0 -241
  211. package/project/.sdk/src/cmp/haskell/ReadmeRef_haskell.ts +0 -408
  212. package/project/.sdk/src/cmp/haskell/ReadmeTopHowto_haskell.ts +0 -31
  213. package/project/.sdk/src/cmp/haskell/ReadmeTopQuick_haskell.ts +0 -104
  214. package/project/.sdk/src/cmp/haskell/ReadmeTopTest_haskell.ts +0 -80
  215. package/project/.sdk/src/cmp/haskell/Test_haskell.ts +0 -300
  216. package/project/.sdk/src/cmp/haskell/tsconfig.json +0 -15
  217. package/project/.sdk/src/cmp/haskell/utility_haskell.ts +0 -166
  218. package/project/.sdk/tm/haskell/LICENSE +0 -21
  219. package/project/.sdk/tm/haskell/Makefile +0 -22
  220. package/project/.sdk/tm/haskell/VERSION +0 -1
  221. package/project/.sdk/tm/haskell/src/SdkFeatures.hs +0 -1440
  222. package/project/.sdk/tm/haskell/src/SdkHelpers.hs +0 -337
  223. package/project/.sdk/tm/haskell/src/SdkJson.hs +0 -111
  224. package/project/.sdk/tm/haskell/src/SdkRuntime.hs +0 -1219
  225. package/project/.sdk/tm/haskell/src/SdkTypes.hs +0 -195
  226. package/project/.sdk/tm/haskell/src/VoxgigStruct.hs +0 -2299
  227. package/project/.sdk/tm/haskell/src/Vregex.hs +0 -237
  228. package/project/.sdk/tm/haskell/src/feature/README.md +0 -5
  229. package/project/.sdk/tm/haskell/src/feature/audit/.gitkeep +0 -0
  230. package/project/.sdk/tm/haskell/src/feature/base/.gitkeep +0 -0
  231. package/project/.sdk/tm/haskell/src/feature/cache/.gitkeep +0 -0
  232. package/project/.sdk/tm/haskell/src/feature/clienttrack/.gitkeep +0 -0
  233. package/project/.sdk/tm/haskell/src/feature/debug/.gitkeep +0 -0
  234. package/project/.sdk/tm/haskell/src/feature/idempotency/.gitkeep +0 -0
  235. package/project/.sdk/tm/haskell/src/feature/log/.gitkeep +0 -0
  236. package/project/.sdk/tm/haskell/src/feature/metrics/.gitkeep +0 -0
  237. package/project/.sdk/tm/haskell/src/feature/netsim/.gitkeep +0 -0
  238. package/project/.sdk/tm/haskell/src/feature/paging/.gitkeep +0 -0
  239. package/project/.sdk/tm/haskell/src/feature/proxy/.gitkeep +0 -0
  240. package/project/.sdk/tm/haskell/src/feature/ratelimit/.gitkeep +0 -0
  241. package/project/.sdk/tm/haskell/src/feature/rbac/.gitkeep +0 -0
  242. package/project/.sdk/tm/haskell/src/feature/retry/.gitkeep +0 -0
  243. package/project/.sdk/tm/haskell/src/feature/streaming/.gitkeep +0 -0
  244. package/project/.sdk/tm/haskell/src/feature/telemetry/.gitkeep +0 -0
  245. package/project/.sdk/tm/haskell/src/feature/test/.gitkeep +0 -0
  246. package/project/.sdk/tm/haskell/src/feature/timeout/.gitkeep +0 -0
  247. package/project/.sdk/tm/haskell/test/Harness.hs +0 -281
  248. package/project/.sdk/tm/haskell/test/Runner.hs +0 -47
  249. package/project/.sdk/tm/haskell/test/StructCorpus.hs +0 -449
  250. package/project/.sdk/tm/haskell/test/TCustomUtility.hs +0 -38
  251. package/project/.sdk/tm/haskell/test/TFeature.hs +0 -794
  252. package/project/.sdk/tm/haskell/test/TNetsim.hs +0 -50
  253. package/project/.sdk/tm/haskell/test/TPipeline.hs +0 -334
  254. package/project/.sdk/tm/haskell/test/TPrimaryUtility.hs +0 -386
  255. package/project/.sdk/tm/haskell/test/Testutil.hs +0 -59
@@ -3,9 +3,8 @@ import {
3
3
  Content,
4
4
  File,
5
5
  cmp,
6
+ configDefinition,
6
7
  each,
7
- isAuthActive,
8
- resolveAuthPrefix,
9
8
  } from '@voxgig/sdkgen'
10
9
 
11
10
 
@@ -16,11 +15,6 @@ import {
16
15
  } from '@voxgig/apidef'
17
16
 
18
17
 
19
- import {
20
- clean,
21
- } from './utility_swift'
22
-
23
-
24
18
  // Generates core/Config.swift: the SdkConfig enum holding the generated model
25
19
  // config (makeConfig, materialised at runtime by parsing an embedded JSON
26
20
  // literal - pure data, so a JSON round-trip is faithful and avoids emitting
@@ -32,59 +26,19 @@ const Config = cmp(async function Config(props: any) {
32
26
 
33
27
  const model: Model = ctx$.model
34
28
 
35
- const entity = getModelPath(model, `main.${KIT}.entity`)
36
29
  const feature = getModelPath(model, `main.${KIT}.feature`)
37
30
 
38
- const headers = getModelPath(model, `main.${KIT}.config.headers`) || {}
39
-
40
- const authActive = isAuthActive(model)
41
- const authPrefix = resolveAuthPrefix(model)
42
-
43
- let baseUrl = ''
44
- try { baseUrl = getModelPath(model, `main.${KIT}.info.servers.0.url`) } catch (_e) { }
45
-
46
- // Assemble the config object (pure JSON data).
47
- const featureConfigs: any = {}
48
- each(feature, (f: any) => {
49
- featureConfigs[f.name] = f.config || {}
50
- })
51
-
52
- const optionsEntity: any = {}
53
- each(entity, (ent: any) => {
54
- optionsEntity[ent.name] = {}
55
- })
56
-
57
- const entityDefs: any = {}
58
- each(entity, (ent: any) => {
59
- entityDefs[ent.name] = clean({
60
- fields: ent.fields,
61
- name: ent.name,
62
- op: ent.op,
63
- relations: ent.relations,
64
- }, true)
65
- })
66
-
67
- const options: any = {
68
- base: baseUrl,
69
- headers,
70
- entity: optionsEntity,
71
- }
72
- if (authActive) {
73
- options.auth = { prefix: authPrefix }
74
- }
75
-
76
- const configObj = {
77
- main: { name: model.const.Name },
78
- feature: featureConfigs,
79
- options,
80
- entity: entityDefs,
81
- }
31
+ // The config as data, built by the shared helper so every target embeds
32
+ // the same model by construction. Passing target.name opts this target
33
+ // into main.slug / main.version / main.target (the three station
34
+ // descriptor identity fields, station design §4); swift has only the
35
+ // JSON-literal rep, so that one call covers every rep this target emits.
36
+ const { json } = configDefinition(model, target.name)
82
37
 
83
38
  // Model-data defaults may carry the ProjectName placeholder (e.g. the
84
39
  // clienttrack clientName); resolve it to the API name so the embedded JSON
85
40
  // matches the token-replaced runtime.
86
- const configJson = JSON.stringify(configObj, null, 2)
87
- .replace(/ProjectName/g, model.const.Name)
41
+ const configJson = json.replace(/ProjectName/g, model.const.Name)
88
42
 
89
43
  File({ name: 'Config.' + target.ext }, () => {
90
44
 
@@ -17,8 +17,30 @@ import type {
17
17
  // under Sources/ProjectNameSDK (the copied runtime + generated sources); the
18
18
  // test target compiles Tests/ProjectNameSDKTests. Directory names are the
19
19
  // verbatim copied paths (Copy does not rewrite path components); the target
20
- // NAMES carry the API name. Runtime is dependency-free (Foundation + the
21
- // vendored struct); target/feature deps, when declared, become SwiftPM deps.
20
+ // NAMES carry the API name.
21
+ //
22
+ // Dependencies: the runtime itself is dependency-free (Foundation + the
23
+ // vendored struct), but declared target/feature deps flow into the manifest
24
+ // via collectDeps. SwiftPM cannot name a package by product alone, so a
25
+ // swift deps entry carries its coordinates in a documented convention:
26
+ //
27
+ // deps: swift: {
28
+ // 'VoxgigStation': { active: true, version: '0.0.1', kind: prod,
29
+ // url: 'https://github.com/voxgig/station-swift' }
30
+ // }
31
+ //
32
+ // - the entry KEY is the SwiftPM PRODUCT name (also the module the
33
+ // generated source imports);
34
+ // - the extra `url` field is the git repository SwiftPM resolves
35
+ // (`.package(url:from:)`); the package identity SwiftPM derives from it
36
+ // is the URL's last path component (minus any .git), which is what the
37
+ // `.product(name:package:)` reference must use;
38
+ // - `version` feeds `from:` - a plain semver (any leading range operator
39
+ // like '>=' is stripped, since `from:` already means >=).
40
+ //
41
+ // An entry WITHOUT a `url` is not expressible in a SwiftPM manifest (no
42
+ // registry-less by-name dependencies), so it is skipped - unadorned entries
43
+ // keep today's zero-dependency output.
22
44
  const Package = cmp(async function Package(props: any) {
23
45
  const ctx$ = props.ctx$
24
46
  const target = props.target
@@ -27,28 +49,48 @@ const Package = cmp(async function Package(props: any) {
27
49
 
28
50
  const Name = model.const.Name
29
51
 
30
- const deps: Record<string, string> = {}
52
+ type SwiftDep = { product: string, url: string, from: string, identity: string }
53
+ const deps: SwiftDep[] = []
31
54
  for (const d of collectDeps(model, target.name, target.deps, ctx$.log)) {
32
- deps[d.name] = d.source === 'target' ? (d.version || '0.0.0') : d.version
55
+ const url = 'string' === typeof (d.raw as any)?.url ? (d.raw as any).url : ''
56
+ if ('' === url) {
57
+ continue
58
+ }
59
+ const from = (d.version || '0.0.0').replace(/^[^0-9]+/, '')
60
+ const identity = (url.split('/').pop() || '').replace(/\.git$/, '')
61
+ deps.push({ product: d.name, url, from, identity })
33
62
  }
34
- // Vendored, dependency-free by design; declared deps (if any) are ignored
35
- // here since the runtime imports only Foundation + the in-tree struct.
63
+
64
+ const pkgdeps = 0 === deps.length ? '' :
65
+ '\n dependencies: [\n' +
66
+ deps.map((d) =>
67
+ ` .package(url: "${d.url}", from: "${d.from}"),\n`).join('') +
68
+ ' ],'
69
+
70
+ const targetdeps = 0 === deps.length ? '' :
71
+ '\n dependencies: [\n' +
72
+ deps.map((d) =>
73
+ ` .product(name: "${d.product}", package: "${d.identity}"),\n`)
74
+ .join('') +
75
+ ' ],'
36
76
 
37
77
  File({ name: 'Package.swift' }, () => {
38
78
  Content(`// swift-tools-version:5.9
39
79
  //
40
- // ${Name} SDK - SwiftPM manifest. Zero runtime dependencies (Foundation +
41
- // the vendored Voxgig Struct port under Sources/ProjectNameSDK/Struct).
80
+ // ${Name} SDK - SwiftPM manifest. The runtime itself is dependency-free
81
+ // (Foundation + the vendored Voxgig Struct port under
82
+ // Sources/ProjectNameSDK/Struct); declared feature/target deps (if any)
83
+ // appear below.
42
84
  import PackageDescription
43
85
 
44
86
  let package = Package(
45
87
  name: "${Name}Sdk",
46
88
  products: [
47
89
  .library(name: "${Name}Sdk", targets: ["${Name}Sdk"]),
48
- ],
90
+ ],${pkgdeps}
49
91
  targets: [
50
92
  .target(
51
- name: "${Name}Sdk",
93
+ name: "${Name}Sdk",${targetdeps}
52
94
  path: "Sources/ProjectNameSDK"),
53
95
  .testTarget(
54
96
  name: "${Name}SdkTests",
@@ -1,14 +1,9 @@
1
1
 
2
- import {
3
- KIT,
4
- getModelPath
5
- } from '@voxgig/apidef'
6
-
7
2
  import type {
8
3
  ModelEntity
9
4
  } from '@voxgig/apidef'
10
5
 
11
- import { cmp, each, Folder } from '@voxgig/sdkgen'
6
+ import { cmp, each, Folder, entityCollection } from '@voxgig/sdkgen'
12
7
 
13
8
 
14
9
  import { TestEntity } from './TestEntity_swift'
@@ -26,7 +21,10 @@ const Test = cmp(function Test(props: any) {
26
21
  // are generated here.
27
22
  Folder({ name: 'Tests' }, () => {
28
23
  Folder({ name: 'ProjectNameSDKTests' }, () => {
29
- each(getModelPath(model, `main.${KIT}.entity`), (entity: ModelEntity) => {
24
+ const entity = each(entityCollection(model))
25
+ .filter((e: any) => false !== e.active)
26
+
27
+ each(entity, (entity: ModelEntity) => {
30
28
  TestEntity({ target, entity })
31
29
  TestDirect({ target, entity })
32
30
  })
@@ -81,7 +81,7 @@ const Config = cmp(async function Config(props: any) {
81
81
  // literal and the data that replaces it above the threshold are the same
82
82
  // config by construction. The JSON is what the threshold is measured on -
83
83
  // emitted source size varies by language, the model does not.
84
- const { json: configJson } = configDefinition(model)
84
+ const { def: configDef, json: configJson } = configDefinition(model, target.name)
85
85
  const asData = isConfigData(configJson, configReprSetting(model))
86
86
 
87
87
  File({ name: 'Config.' + target.ext }, () => {
@@ -128,6 +128,14 @@ const Config = cmp(async function Config(props: any) {
128
128
  `'./feature/${f.name}/${nom(f, 'Name')}Feature'`)
129
129
  }),
130
130
 
131
+ // Values from configDefinition's def, not re-derived here, so the
132
+ // literal rep and the data rep cannot disagree on identity.
133
+ '// #MainMeta': () => {
134
+ Line(` slug: ${JSON.stringify(configDef.main.slug)},`)
135
+ Line(` version: ${JSON.stringify(configDef.main.version)},`)
136
+ Line(` target: ${JSON.stringify(configDef.main.target)},`)
137
+ },
138
+
131
139
  '// #FeatureClasses': () => each(feature, (f: any) => {
132
140
  // Trailing comma: the map has one entry per feature, so entries
133
141
  // must be comma-separated (a single feature hid this until now).
@@ -21,7 +21,7 @@ import {
21
21
  File, Content,
22
22
  } from '@voxgig/sdkgen'
23
23
 
24
- import { canonToType, opTypeName, opRequestShape, warnEntityTypeCollisions , deriveEntityNames, opActions } from '@voxgig/sdkgen'
24
+ import { canonToType, opTypeName, opRequestShape, warnEntityTypeCollisions , deriveEntityNames, opActions, tsSafeTypeName } from '@voxgig/sdkgen'
25
25
 
26
26
  import {
27
27
  KIT,
@@ -74,11 +74,14 @@ const EntityTypes = cmp(function EntityTypes(props: any) {
74
74
 
75
75
  entityList.forEach((ent: any) => {
76
76
  const Name = ent.Name
77
+ // A TS/JS global (Record, Array, Promise, ...) would shadow itself
78
+ // for the rest of the file — see tsSafeTypeName.
79
+ const TypeName = tsSafeTypeName(Name)
77
80
  const fields = (ent.fields ? each(ent.fields) : [])
78
81
  .filter((f: any) => f.active !== false)
79
82
 
80
83
  // Entity data model: one property per field, `req:false` -> optional.
81
- Content(`export interface ${Name} {
84
+ Content(`export interface ${TypeName} {
82
85
  `)
83
86
  fields.forEach((f: any) => {
84
87
  const opt = false === f.req ? '?' : ''
@@ -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, entityCollection,
7
+ opTypeName, entityClassName, entityCollection, tsSafeTypeName,
8
8
  } from '@voxgig/sdkgen'
9
9
 
10
10
  import {
@@ -33,9 +33,14 @@ const Entity = cmp(function Entity(props: any) {
33
33
 
34
34
  names(entrep, entity.Name, 'EntityName')
35
35
 
36
+ // A TS/JS global (Record, Array, Promise, ...) would shadow itself for
37
+ // the rest of the file — see tsSafeTypeName. The runtime `this.Name`
38
+ // string stays entity.Name; only the TYPE reference is ever renamed.
39
+ const dataType = tsSafeTypeName(entity.Name)
40
+
36
41
  // Import exactly the typed models this entity references: its data type plus
37
42
  // one request type per ACTIVE op (matches what EntityTypes_ts.ts emits).
38
- const typeNames = [entity.Name]
43
+ const typeNames = [dataType]
39
44
  const opnamesAll = Object.keys(entity.op || {})
40
45
  ;['load', 'list', 'create', 'update', 'remove'].forEach((opname: string) => {
41
46
  if (opnamesAll.includes(opname)) {
@@ -69,6 +74,7 @@ const Entity = cmp(function Entity(props: any) {
69
74
  entityname: entity.name,
70
75
  SdkName: model.const.Name,
71
76
  EntityName: entity.Name,
77
+ EntityDataType: dataType,
72
78
 
73
79
  // Class token decoupled from the EntityName data-type token in
74
80
  // Entity.fragment.ts so the class can be renamed independently.
@@ -61,7 +61,7 @@ const Package = cmp(async function Package(props: any) {
61
61
  const { repoUrl, issuesUrl } = repoInfo(model)
62
62
 
63
63
  const pkg = {
64
- name: packageName(model, 'npm'),
64
+ name: packageName(model, target.name),
65
65
  version: packageVersion(model, target.name),
66
66
  description: pkgDescription(model, target.name),
67
67
  keywords: keywords(model),
@@ -1,14 +1,9 @@
1
1
 
2
- import {
3
- KIT,
4
- getModelPath
5
- } from '@voxgig/apidef'
6
-
7
2
  import type {
8
3
  ModelEntity
9
4
  } from '@voxgig/apidef'
10
5
 
11
- import { cmp, each, Folder } from '@voxgig/sdkgen'
6
+ import { cmp, each, Folder, entityCollection } from '@voxgig/sdkgen'
12
7
 
13
8
 
14
9
  // import { Quick } from './Quick_ts'
@@ -31,7 +26,13 @@ const Test = cmp(function Test(props: any) {
31
26
  ReadmeExamplesTest({ target })
32
27
 
33
28
  Folder({ name: 'entity' }, () => {
34
- each(model.main[KIT].entity, (entity: ModelEntity) => {
29
+ // entityCollection is the cached, UNFILTERED collection (AGENTS.md), so
30
+ // the active filter the raw model read this replaced never applied is
31
+ // written out here. Tests follow Main: an inactive entity has no source.
32
+ const entity = each(entityCollection(model))
33
+ .filter((e: any) => false !== e.active)
34
+
35
+ each(entity, (entity: ModelEntity) => {
35
36
  TestEntity({ target, entity })
36
37
  TestDirect({ target, entity })
37
38
  })
@@ -34,6 +34,13 @@ class Config {
34
34
  return fi
35
35
  }
36
36
 
37
+ // False for a feature added at runtime via options.extend (station's
38
+ // adopt path) - the constructor uses this to skip makeFeature for names
39
+ // no generated class backs.
40
+ hasFeature(this: any, fn: string) {
41
+ return null != FEATURE_CLASS[fn]
42
+ }
43
+
37
44
  }
38
45
 
39
46
 
@@ -17,9 +17,17 @@ class Config {
17
17
  return fi
18
18
  }
19
19
 
20
+ // False for a feature added at runtime via options.extend (station's
21
+ // adopt path) - the constructor uses this to skip makeFeature for names
22
+ // no generated class backs.
23
+ hasFeature(this: any, fn: string) {
24
+ return null != FEATURE_CLASS[fn]
25
+ }
26
+
20
27
 
21
28
  main = {
22
29
  name: '$$const.Name$$',
30
+ // #MainMeta
23
31
  }
24
32
 
25
33
 
@@ -18,7 +18,7 @@ import type {
18
18
 
19
19
 
20
20
  // TODO: needs Entity superclass
21
- class EntyClass extends ProjectNameEntityBase<EntityName> {
21
+ class EntyClass extends ProjectNameEntityBase<EntityDataType> {
22
22
 
23
23
  constructor(client: ProjectNameSDK, entopts: any) {
24
24
  super(client, entopts)
@@ -52,18 +52,26 @@ class ProjectNameSDK {
52
52
  // the `test` feature installs the base mock transport and the transport
53
53
  // features (retry/cache/netsim/proxy/ratelimit) wrap whatever is current,
54
54
  // so `test` must be added before them to sit at the base of the chain.
55
+ const extend = this._options.extend || []
56
+
55
57
  const featureorder = getpath(this._options, '__derived__.featureorder') || []
56
58
  for (const fname of featureorder) {
57
59
  const fopts = this._options.feature[fname] || {}
58
60
  if (fopts.active) {
61
+ // An active name with no generated class is legal when an
62
+ // extend-supplied instance carries that name (station's adopt
63
+ // path): the instance is added below, positioned by its own
64
+ // __after__ entry, so skip it here rather than fail construction.
65
+ if (!this._rootctx.config.hasFeature(fname) &&
66
+ extend.some((f: any) => fname === f.name)) {
67
+ continue
68
+ }
59
69
  featureAdd(this._rootctx, this._rootctx.config.makeFeature(fname))
60
70
  }
61
71
  }
62
72
 
63
- if (null != this._options.extend) {
64
- for (let f of this._options.extend) {
65
- featureAdd(this._rootctx, f)
66
- }
73
+ for (let f of extend) {
74
+ featureAdd(this._rootctx, f)
67
75
  }
68
76
 
69
77
  for (let f of this._features) {
@@ -1,14 +1,9 @@
1
1
 
2
- import {
3
- KIT,
4
- getModelPath
5
- } from '@voxgig/apidef'
6
-
7
2
  import type {
8
3
  ModelEntity
9
4
  } from '@voxgig/apidef'
10
5
 
11
- import { cmp, each, Folder, File, Content } from '@voxgig/sdkgen'
6
+ import { cmp, each, Folder, File, Content, entityCollection } from '@voxgig/sdkgen'
12
7
 
13
8
  import { TestEntity } from './TestEntity_zig'
14
9
  import { TestDirect } from './TestDirect_zig'
@@ -30,7 +25,8 @@ const Test = cmp(function Test(props: any) {
30
25
  const { model } = props.ctx$
31
26
  const { target } = props
32
27
 
33
- const entity = getModelPath(model, `main.${KIT}.entity`)
28
+ const entity = each(entityCollection(model))
29
+ .filter((e: any) => false !== e.active)
34
30
 
35
31
  Folder({ name: 'test' }, () => {
36
32
  File({ name: 'generated_test.' + target.ext }, () => {
@@ -7,7 +7,12 @@ CFLAGS ?= -std=c11 -Wall -Wextra -Wno-unused-parameter -D_GNU_SOURCE -O0 -g
7
7
  INC := -I core -I utility/struct
8
8
  LDLIBS := -lm
9
9
 
10
- LIB_SRCS := $(wildcard core/*.c utility/*.c utility/struct/*.c feature/*.c entity/*.c)
10
+ # feature/*/*.c: a feature may carry a vendored library payload in its own
11
+ # subdirectory (the station feature vendors voxgig_station there - C has no
12
+ # package registry, so tier-C libraries ride the feature source; see
13
+ # utility/struct/ for the same precedent at the utility level). Empty when
14
+ # no feature ships one.
15
+ LIB_SRCS := $(wildcard core/*.c utility/*.c utility/struct/*.c feature/*.c feature/*/*.c entity/*.c)
11
16
  LIB_OBJS := $(LIB_SRCS:.c=.o)
12
17
 
13
18
  TEST_SRCS := $(wildcard tests/*.c)
@@ -166,8 +166,19 @@ voxgig_value* make_options_util(Context* ctx) {
166
166
  if (has_test) {
167
167
  voxgig_list_push(voxgig_as_list(feature_order), v_str("test"));
168
168
  }
169
+ // Station special case, mirroring test's: its transport wrap must
170
+ // sit immediately outside the base transport (inside retry/cache/
171
+ // netsim), so map-form activation hoists it to just after test -
172
+ // or first, when no test entry exists. Without this the sorted
173
+ // default would init station last and wrap OUTSIDE the recording
174
+ // features, turning its wire-truth events into fiction.
169
175
  for (size_t i = 0; i < fn; i++) {
170
- if (strcmp(names[i], "test") != 0) {
176
+ if (strcmp(names[i], "station") == 0) {
177
+ voxgig_list_push(voxgig_as_list(feature_order), v_str("station"));
178
+ }
179
+ }
180
+ for (size_t i = 0; i < fn; i++) {
181
+ if (strcmp(names[i], "test") != 0 && strcmp(names[i], "station") != 0) {
171
182
  voxgig_list_push(voxgig_as_list(feature_order), v_str(names[i]));
172
183
  }
173
184
  }
@@ -13,6 +13,29 @@ static voxgig_value* get_elem_i(voxgig_value* list, int64_t i) {
13
13
  return r ? r : voxgig_new_undef();
14
14
  }
15
15
 
16
+ // How many path segments a point has.
17
+ static size_t parts_len(voxgig_value* point) {
18
+ voxgig_value* parts = getp(point, "parts");
19
+ return voxgig_is_list(parts) ? voxgig_as_list(parts)->len : 0;
20
+ }
21
+
22
+ // Does this point's path end in a parameter? A record route ends in the
23
+ // record's identifier (/boards/{id}); a cross-reference that also returns
24
+ // the entity ends in the relationship's name (/posts/{id}/author). That,
25
+ // then fewest segments, is what tells the entity's own route from a
26
+ // cross-reference. The same rule runs at generation time, in
27
+ // helpers/opShape.ts — both sides must move together.
28
+ static bool terminal_param(voxgig_value* point) {
29
+ voxgig_value* parts = getp(point, "parts");
30
+ if (!voxgig_is_list(parts)) return false;
31
+ voxgig_list* pl = voxgig_as_list(parts);
32
+ if (0 == pl->len) return false;
33
+ voxgig_value* last = pl->items[pl->len - 1];
34
+ if (!voxgig_is_string(last)) return false;
35
+ const char* s = voxgig_as_string(last);
36
+ return NULL != s && '{' == s[0];
37
+ }
38
+
16
39
  voxgig_value* make_point_util(Context* ctx, PNError** err) {
17
40
  *err = NULL;
18
41
 
@@ -58,9 +81,10 @@ voxgig_value* make_point_util(Context* ctx, PNError** err) {
58
81
  voxgig_value* selector = is_data ? ctx->data : ctx->mtch;
59
82
 
60
83
  voxgig_value* point = voxgig_new_undef();
84
+ bool matched = false;
61
85
  for (int64_t i = 0; i < plen; i++) {
62
- point = get_elem_i(points, i);
63
- voxgig_value* select_def = to_map(getp(point, "select"));
86
+ voxgig_value* cand = get_elem_i(points, i);
87
+ voxgig_value* select_def = to_map(getp(cand, "select"));
64
88
  bool found = true;
65
89
 
66
90
  if (!v_is_noval(selector) && !v_is_noval(select_def)) {
@@ -85,7 +109,44 @@ voxgig_value* make_point_util(Context* ctx, PNError** err) {
85
109
  if (!v_eq(req_action, select_action)) found = false;
86
110
  }
87
111
 
88
- if (found) break;
112
+ if (found) {
113
+ point = cand;
114
+ matched = true;
115
+ break;
116
+ }
117
+ }
118
+
119
+ // select.exist can list more than the params needed to pick a point, so
120
+ // nothing matches — fall back to the entity's own route rather than
121
+ // whichever point came last.
122
+ if (!matched) {
123
+ // A request naming an action reaches here only because that action's
124
+ // own point failed its exist test, so it is unbuildable whatever we
125
+ // pick. Refuse it BEFORE choosing a fallback: the guard below compares
126
+ // the chosen point's $action and would wave the request through
127
+ // whenever the fallback lands on the action point itself.
128
+ voxgig_value* unmatched_action = getp(reqselector, "$action");
129
+ if (!v_is_noval(unmatched_action)) {
130
+ char* actstr = voxgig_stringify(unmatched_action, -1);
131
+ char buf[512];
132
+ snprintf(buf, sizeof(buf), "Operation \"%s\" action \"%s\" is not valid.",
133
+ op->name, actstr ? actstr : "");
134
+ *err = context_make_error(ctx, "point_action_invalid", buf);
135
+ return NULL;
136
+ }
137
+
138
+ point = get_elem_i(points, 0);
139
+ for (int64_t i = 0; i < plen; i++) {
140
+ voxgig_value* cand = get_elem_i(points, i);
141
+ bool cand_term = terminal_param(cand);
142
+ bool best_term = terminal_param(point);
143
+ if (cand_term != best_term) {
144
+ if (cand_term) point = cand;
145
+ }
146
+ else if (parts_len(cand) < parts_len(point)) {
147
+ point = cand;
148
+ }
149
+ }
89
150
  }
90
151
 
91
152
  voxgig_value* req_action = getp(reqselector, "$action");
@@ -641,21 +641,56 @@
641
641
  sa (vs/getprop select-def "$action")]
642
642
  (when (not= ra sa) (reset! found false))))
643
643
  @found))
644
- ;; "first matching point, else the last point" (mirrors the
645
- ;; reference loop that keeps the last-visited point).
646
- chosen (loop [ps (vec (op-points op)) last nil]
647
- (if (empty? ps) last
648
- (let [p (first ps)]
649
- (if (point-matches? p) p (recur (rest ps) p)))))
644
+ ;; How many path segments a point has, and whether its path
645
+ ;; ends in a parameter. A record route ends in the record's
646
+ ;; identifier (/boards/{id}); a cross-reference that also
647
+ ;; returns the entity ends in the relationship's name
648
+ ;; (/posts/{id}/author). That, then fewest segments, is what
649
+ ;; tells the entity's own route from a cross-reference. The
650
+ ;; same rule runs at generation time, in helpers/opShape.ts —
651
+ ;; both sides must move together.
652
+ parts-len (fn [p]
653
+ (let [parts (vs/getprop p "parts")]
654
+ (if (vs/islist parts) (vs/size parts) 0)))
655
+ terminal-param? (fn [p]
656
+ (let [parts (vs/getprop p "parts")]
657
+ (and (vs/islist parts)
658
+ (pos? (vs/size parts))
659
+ (let [last-part (vs/getelem parts (dec (vs/size parts)))]
660
+ (and (string? last-part)
661
+ (str/starts-with? last-part "{"))))))
662
+ own-point (fn [ps]
663
+ (reduce (fn [best cand]
664
+ (let [ct (terminal-param? cand)
665
+ bt (terminal-param? best)]
666
+ (if (not= ct bt)
667
+ (if ct cand best)
668
+ (if (< (parts-len cand) (parts-len best)) cand best))))
669
+ (first ps) ps))
670
+ matched (first (filter point-matches? (vec (op-points op))))
650
671
  req-action (vs/getprop reqselector "$action")]
651
- (if (and reqselector req-action chosen)
652
- (let [point-select (to-map (vs/getprop chosen "select"))
653
- point-action (vs/getprop point-select "$action")]
654
- (if (not= req-action point-action)
655
- [nil (ctx-error ctx "point_action_invalid"
656
- (str "Operation \"" (op-name op) "\" action \"" (vs/stringify req-action) "\" is not valid."))]
657
- (do (oset! ctx :point chosen) [(oget ctx :point) nil])))
658
- (do (oset! ctx :point chosen) [(oget ctx :point) nil]))))))))
672
+ (cond
673
+ ;; select.exist can list more than the params needed to pick a
674
+ ;; point, so nothing matches. A request naming an action reaches
675
+ ;; here only because that action's own point failed its exist
676
+ ;; test, so it is unbuildable whatever we pick — refuse it
677
+ ;; BEFORE falling back, since the guard below compares the
678
+ ;; chosen point's $action and would wave the request through
679
+ ;; whenever the fallback lands on the action point itself.
680
+ (and (nil? matched) reqselector req-action)
681
+ [nil (ctx-error ctx "point_action_invalid"
682
+ (str "Operation \"" (op-name op) "\" action \"" (vs/stringify req-action) "\" is not valid."))]
683
+
684
+ :else
685
+ (let [chosen (or matched (own-point (vec (op-points op))))]
686
+ (if (and reqselector req-action chosen)
687
+ (let [point-select (to-map (vs/getprop chosen "select"))
688
+ point-action (vs/getprop point-select "$action")]
689
+ (if (not= req-action point-action)
690
+ [nil (ctx-error ctx "point_action_invalid"
691
+ (str "Operation \"" (op-name op) "\" action \"" (vs/stringify req-action) "\" is not valid."))]
692
+ (do (oset! ctx :point chosen) [(oget ctx :point) nil])))
693
+ (do (oset! ctx :point chosen) [(oget ctx :point) nil]))))))))))
659
694
 
660
695
  (defn u-make-spec [ctx]
661
696
  (if (some? (out-get ctx "spec"))