@voxgig/sdkgen 1.3.18 → 1.3.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/dist/cmp/Deploy.js +16 -16
  2. package/dist/cmp/Deploy.js.map +1 -1
  3. package/dist/cmp/ReadmeTop.js +13 -11
  4. package/dist/cmp/ReadmeTop.js.map +1 -1
  5. package/dist/helpers/naming.d.ts +3 -1
  6. package/dist/helpers/naming.js +65 -0
  7. package/dist/helpers/naming.js.map +1 -1
  8. package/dist/helpers/serverVars.d.ts +10 -0
  9. package/dist/helpers/serverVars.js +87 -0
  10. package/dist/helpers/serverVars.js.map +1 -0
  11. package/dist/sdkgen.d.ts +3 -2
  12. package/dist/sdkgen.js +6 -1
  13. package/dist/sdkgen.js.map +1 -1
  14. package/dist/tsconfig.tsbuildinfo +1 -1
  15. package/package.json +1 -1
  16. package/project/.sdk/model/target/go-cli.aontu +2 -2
  17. package/project/.sdk/src/cmp/csharp/TestEntity_csharp.ts +22 -15
  18. package/project/.sdk/src/cmp/go/Config_go.ts +10 -1
  19. package/project/.sdk/src/cmp/go-cli/Main_go-cli.ts +54 -35
  20. package/project/.sdk/src/cmp/go-cli/fragment/main.fragment.go +7 -7
  21. package/project/.sdk/src/cmp/go-cli/fragment/words.fragment.go +21 -18
  22. package/project/.sdk/src/cmp/js/Config_js.ts +11 -0
  23. package/project/.sdk/src/cmp/js/fragment/Config.fragment.js +2 -2
  24. package/project/.sdk/src/cmp/js/fragment/Direct.test.fragment.js +4 -0
  25. package/project/.sdk/src/cmp/lua/Config_lua.ts +10 -1
  26. package/project/.sdk/src/cmp/php/Config_php.ts +13 -2
  27. package/project/.sdk/src/cmp/py/Config_py.ts +10 -1
  28. package/project/.sdk/src/cmp/rb/Config_rb.ts +12 -1
  29. package/project/.sdk/src/cmp/rust/TestEntity_rust.ts +25 -18
  30. package/project/.sdk/src/cmp/swift/EntityTypes_swift.ts +10 -3
  31. package/project/.sdk/src/cmp/ts/Config_ts.ts +11 -0
  32. package/project/.sdk/src/cmp/ts/fragment/Config.fragment.ts +2 -2
  33. package/project/.sdk/src/cmp/ts/fragment/Direct.test.fragment.ts +4 -0
  34. package/project/.sdk/tm/csharp/Makefile +6 -6
  35. package/project/.sdk/tm/dart/Makefile +3 -3
  36. package/project/.sdk/tm/go/Makefile +6 -6
  37. package/project/.sdk/tm/go/test/primary_utility_test.go +5 -0
  38. package/project/.sdk/tm/go/utility/make_options.go +48 -0
  39. package/project/.sdk/tm/java/Makefile +6 -6
  40. package/project/.sdk/tm/js/Makefile +6 -6
  41. package/project/.sdk/tm/js/src/utility/MakeOptionsUtility.js +39 -1
  42. package/project/.sdk/tm/js/test/utility/PrimaryUtility.test.js +5 -0
  43. package/project/.sdk/tm/kotlin/Makefile +6 -6
  44. package/project/.sdk/tm/lua/Makefile +7 -7
  45. package/project/.sdk/tm/lua/feature/test_feature.lua +29 -1
  46. package/project/.sdk/tm/lua/test/primary_utility_test.lua +4 -0
  47. package/project/.sdk/tm/lua/utility/make_options.lua +39 -0
  48. package/project/.sdk/tm/perl/Makefile +6 -6
  49. package/project/.sdk/tm/php/Makefile +6 -6
  50. package/project/.sdk/tm/php/feature/TestFeature.php +30 -2
  51. package/project/.sdk/tm/php/test/PrimaryUtilityTest.php +5 -0
  52. package/project/.sdk/tm/php/utility/MakeOptions.php +44 -0
  53. package/project/.sdk/tm/py/Makefile +6 -6
  54. package/project/.sdk/tm/py/test/test_primary_utility.py +5 -0
  55. package/project/.sdk/tm/py/utility/make_options.py +42 -0
  56. package/project/.sdk/tm/rb/Makefile +6 -6
  57. package/project/.sdk/tm/rb/test/primary_utility_test.rb +4 -0
  58. package/project/.sdk/tm/rb/utility/make_options.rb +37 -0
  59. package/project/.sdk/tm/rust/Makefile +6 -6
  60. package/project/.sdk/tm/swift/Makefile +6 -6
  61. package/project/.sdk/tm/ts/Makefile +6 -6
  62. package/project/.sdk/tm/ts/src/utility/MakeOptionsUtility.ts +39 -1
  63. package/project/.sdk/tm/ts/test/utility/PrimaryUtility.test.ts +4 -0
  64. package/src/cmp/Deploy.ts +16 -16
  65. package/src/cmp/ReadmeTop.ts +13 -11
  66. package/src/helpers/naming.ts +71 -0
  67. package/src/helpers/serverVars.ts +105 -0
  68. package/src/sdkgen.ts +6 -1
@@ -16,18 +16,32 @@ import {
16
16
  } from '@voxgig/apidef'
17
17
 
18
18
 
19
- // Published aql/eng/go version. Tagged at aql-lang/aql under
20
- // eng/go/v<X.Y.Z>. Bump here when adopting a newer engine.
21
- const AQL_ENG_VERSION = 'v0.0.1'
22
-
23
- // go.sum entries for AQL_ENG_VERSION and its transitive deps. The sibling
19
+ // Published boru/eng/go version. The engine module
20
+ // github.com/boru-lang/boru/eng/go is not yet tagged under the boru path (the
21
+ // eng/go/v0.0.1 tag predates the aql->boru rename and still declares the old
22
+ // aql-lang/aql module path), so we pin a commit pseudo-version. Bump here —
23
+ // to a real eng/go/v<X.Y.Z> once one is published, or a newer pseudo-version
24
+ // when adopting a newer engine.
25
+ const BORU_ENG_VERSION = 'v0.0.2-0.20260804163932-0d66b55c5110'
26
+
27
+ // go.sum entries for BORU_ENG_VERSION and its transitive deps. The sibling
24
28
  // SDK dep needs no entry (path replace). Deterministic because the version
25
29
  // is pinned above — regenerate with `go mod tidy` and update BOTH constants
26
- // together when bumping AQL_ENG_VERSION.
27
- const AQL_ENG_GOSUM = `github.com/aql-lang/aql/eng/go v0.0.1 h1:qvopmpIX5xL6cpAC4otSUO7fUDA46x/y+2lT2zoxTaA=
28
- github.com/aql-lang/aql/eng/go v0.0.1/go.mod h1:7LmNG+pASY2jlPZB0iFAt/ZNdmc8qxvaf+njVmaSFks=
29
- github.com/jsonicjs/jsonic/go v0.1.6 h1:oUw4vxCK6tqa7SGN87vjCtx3sCpeHXdqfl25hx5LKP0=
30
- github.com/jsonicjs/jsonic/go v0.1.6/go.mod h1:ObNKlCG7esWoi4AHCpdgkILvPINV8bpvkbCd4llGGUg=
30
+ // together when bumping BORU_ENG_VERSION.
31
+ const BORU_ENG_GOSUM = `github.com/boru-lang/boru/eng/go v0.0.2-0.20260804163932-0d66b55c5110 h1:iwMbEPhByhVhJgt6xhyhT+jXMiARvbG4wHIrc4OPcvU=
32
+ github.com/boru-lang/boru/eng/go v0.0.2-0.20260804163932-0d66b55c5110/go.mod h1:KQLjjCq4QVAfdSuhmQ58ZFA9JK7LV2+A/aLRb3m4s5k=
33
+ github.com/cockroachdb/apd/v3 v3.2.3 h1:4Zx+I3R35bFXMnltzmjP79i2cravE4jTRL6ps9Aux80=
34
+ github.com/cockroachdb/apd/v3 v3.2.3/go.mod h1:klXJcjp+FffLTHlhIG69tezTDvdP065naDsHzKhYSqc=
35
+ github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw=
36
+ github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
37
+ github.com/tabnas/debug/go v0.2.3 h1:cptiwHcHKw+lqtZuKp6gX7yY1NunJLS5PHD7ykVcIvM=
38
+ github.com/tabnas/debug/go v0.2.3/go.mod h1:EXSNFdN6Ct9pcAUk8ZGozNbIltb3Hw0wcne+5vWQyns=
39
+ github.com/tabnas/json/go v0.4.0 h1:1BxLHyCullkKXkvui/SuZ4s6OMrFVDuEB13IX/5S1eM=
40
+ github.com/tabnas/json/go v0.4.0/go.mod h1:MJzyziKcvZk3OZCaSDxhMdf/Wkq2UJ0uLGWFtp9zsJs=
41
+ github.com/tabnas/jsonic/go v0.4.0 h1:y5k/P21C3q3jWaA+VxEhXxzZ8xJgpgAehMBEseDN31g=
42
+ github.com/tabnas/jsonic/go v0.4.0/go.mod h1:eDpkddhkuTFuIXMkSqTZl7cU7M23swbMpkXR1W5bApQ=
43
+ github.com/tabnas/parser/go v0.4.0 h1:M8+qRT4KaCtr4OCpg9NDNUXJIdbbweqeqbpEpVGNEqU=
44
+ github.com/tabnas/parser/go v0.4.0/go.mod h1:WrlfEVyZ1QjEIowWiyEu3K1iHj7wxuPut5zoH9Trehk=
31
45
  `
32
46
 
33
47
 
@@ -64,7 +78,7 @@ const Main = cmp(function Main(props: any) {
64
78
  // EVERYTHING here is MODEL-DRIVEN: verbs, examples and how-to sections are
65
79
  // gated on whether an active entity actually exposes that op
66
80
  // (op.<name>.active !== false) — never document an operation no entity
67
- // supports. The CLI implements three AQL words (list / load / update; see
81
+ // supports. The CLI implements three boru words (list / load / update; see
68
82
  // words.fragment.go + runOp).
69
83
  // ==========================================================================
70
84
  const bin = `${model.name}-cli`
@@ -129,7 +143,7 @@ const Main = cmp(function Main(props: any) {
129
143
  ex.push('# 3. Provide credentials once, via the environment')
130
144
  ex.push(`export ${apiKeyEnv}=sk_live_xxx`)
131
145
  ex.push('')
132
- ex.push('# 4. Each command line is ONE AQL expression, run against the API:')
146
+ ex.push('# 4. Each command line is ONE boru expression, run against the API:')
133
147
  if (firstHas('list')) ex.push(`./${bin} list ${firstEntity}`)
134
148
  if (firstHas('load')) {
135
149
  ex.push(`./${bin} load 1 ${firstEntity} # {id:1} shorthand`)
@@ -158,7 +172,7 @@ const Main = cmp(function Main(props: any) {
158
172
  \`\`\`
159
173
 
160
174
  \`list <entity>\` returns the first page of records. \`<entity>\` is a bareword —
161
- it is auto-quoted as an AQL atom, so no quotes are needed.`)
175
+ it is auto-quoted as an boru atom, so no quotes are needed.`)
162
176
 
163
177
  if (firstHas('load')) howtos.push(`### Load a single record
164
178
 
@@ -194,7 +208,7 @@ Both are injectable by a secrets vault, so the key never has to be typed inline.
194
208
  howtos.push(`### Explore interactively with the REPL
195
209
 
196
210
  Run with no arguments to open a REPL (prompt \`${model.name}>\`). Each line is
197
- evaluated as its own AQL expression:
211
+ evaluated as its own boru expression:
198
212
 
199
213
  \`\`\`text
200
214
  $ ./${bin}
@@ -218,10 +232,10 @@ below — this SDK exposes ${entityCount} ${entityNoun}.`)
218
232
 
219
233
  File({ name: 'README.md' }, () => Content(`# ${model.name}-cli
220
234
 
221
- AQL-driven command-line client **and** interactive REPL for the ${model.Name}
222
- SDK. Each command line is parsed as a single [AQL](https://github.com/aql-lang/aql)
235
+ boru-driven command-line client **and** interactive REPL for the ${model.Name}
236
+ SDK. Each command line is parsed as a single [boru](https://github.com/boru-lang/boru)
223
237
  expression and evaluated against the live API; run it with no arguments to drop
224
- into a REPL. Built on \`github.com/aql-lang/aql/eng/go\` and the sibling Go SDK
238
+ into a REPL. Built on \`github.com/boru-lang/boru/eng/go\` and the sibling Go SDK
225
239
  at \`../go\`.
226
240
 
227
241
  ## Examples
@@ -248,7 +262,7 @@ ${exampleBlock}
248
262
  export ${apiKeyEnv}=sk_live_xxx
249
263
  \`\`\`
250
264
 
251
- 3. **Run a query.** Evaluate an AQL expression against the API (or run with no
265
+ 3. **Run a query.** Evaluate an boru expression against the API (or run with no
252
266
  arguments to open the REPL):
253
267
 
254
268
  \`\`\`sh
@@ -258,7 +272,7 @@ ${exampleBlock}
258
272
  4. **Go interactive.** Run the binary with no arguments to open the REPL, then
259
273
  type \`/help\` for the word and entity lists and \`/quit\` to leave.
260
274
 
261
- That is the whole loop: *build → set key → evaluate AQL expressions*.
275
+ That is the whole loop: *build → set key → evaluate boru expressions*.
262
276
 
263
277
  ## How-to guides
264
278
 
@@ -268,13 +282,13 @@ ${howtoBlock}
268
282
 
269
283
  ### Words
270
284
 
271
- The CLI registers these AQL words, each bound to the SDK:
285
+ The CLI registers these boru words, each bound to the SDK:
272
286
 
273
287
  | Word | Signatures | Returns |
274
288
  |----------|-----------------------------------------------|--------------------------------|
275
289
  ${verbRows}
276
290
 
277
- - \`<entity>\` is a bareword, auto-quoted as an AQL atom (e.g. \`${firstEntity}\`).
291
+ - \`<entity>\` is a bareword, auto-quoted as an boru atom (e.g. \`${firstEntity}\`).
278
292
  - \`<query>\` is either a **Map** (\`{id:1}\`) or a **Scalar** (\`1\`, treated as
279
293
  \`{id:1}\`). A scalar is always wrapped as \`{id:<value>}\`.
280
294
 
@@ -293,7 +307,7 @@ Unset variables fall back to the SDK's built-in defaults.
293
307
 
294
308
  ### REPL commands
295
309
 
296
- Meta-commands use the \`/\` prefix (everything else on a line is evaluated as AQL):
310
+ Meta-commands use the \`/\` prefix (everything else on a line is evaluated as boru):
297
311
 
298
312
  - \`/quit\` / \`/q\` / \`/exit\` — exit the REPL
299
313
  - \`/help\` / \`/h\` / \`/?\` — show the word list, entity list and meta commands
@@ -321,25 +335,25 @@ ${entityList}
321
335
 
322
336
  ## Explanation
323
337
 
324
- ### Why AQL?
338
+ ### Why boru?
325
339
 
326
- The whole command line is one [AQL](https://github.com/aql-lang/aql) expression,
340
+ The whole command line is one [boru](https://github.com/boru-lang/boru) expression,
327
341
  not a fixed \`verb --flag\` grammar. That means the same binary works one-shot
328
342
  (\`./${bin} <expr>\`) and interactively (the REPL), and expressions compose the
329
- same way in both. \`list\` / \`load\` / \`update\` are ordinary AQL *words* bound to
343
+ same way in both. \`list\` / \`load\` / \`update\` are ordinary boru *words* bound to
330
344
  the SDK — adding SDK operations is adding words, not re-parsing flags.
331
345
 
332
346
  ### How it is wired
333
347
 
334
348
  \`main.go\` builds the SDK client (configured from the environment), creates an
335
- AQL registry, and \`words.go\` registers \`list\` / \`load\` / \`update\` as native
349
+ boru registry, and \`words.go\` registers \`list\` / \`load\` / \`update\` as native
336
350
  words that dispatch on the entity atom and call the sibling Go SDK at \`../go\`.
337
351
  Results are unwrapped from their \`Entity\` wrappers to plain data before being
338
352
  printed.
339
353
 
340
354
  ### Output format
341
355
 
342
- Each result value is printed as its AQL string form (a JSON-like rendering of
356
+ Each result value is printed as its boru string form (a JSON-like rendering of
343
357
  the record or list of records). One-shot mode prints to stdout; errors go to
344
358
  stderr with a non-zero exit code.
345
359
 
@@ -350,25 +364,30 @@ this repo, or upstream at
350
364
  \`github.com/voxgig/sdkgen/project/.sdk/src/cmp/go-cli/\`.
351
365
  `))
352
366
 
353
- // go.mod — sibling SDK via relative replace; aql/eng/go from the
354
- // public Go module proxy. The go directive must be >= aql/eng/go's own
355
- // (go 1.24.7 at eng/go/v0.0.1) — keep in step with AQL_ENG_VERSION.
367
+ // go.mod — sibling SDK via relative replace; boru/eng/go from the
368
+ // public Go module proxy. The go directive must be >= boru/eng/go's own
369
+ // (go 1.24.7) — keep in step with BORU_ENG_VERSION.
356
370
  File({ name: 'go.mod' }, () => Content(`module ${cliModule}
357
371
 
358
372
  go 1.24.7
359
373
 
360
374
  require ${sdkModule} v0.0.0
361
- require github.com/aql-lang/aql/eng/go ${AQL_ENG_VERSION}
375
+ require github.com/boru-lang/boru/eng/go ${BORU_ENG_VERSION}
362
376
 
363
- require github.com/jsonicjs/jsonic/go v0.1.6 // indirect
377
+ require (
378
+ github.com/cockroachdb/apd/v3 v3.2.3 // indirect
379
+ github.com/tabnas/json/go v0.4.0 // indirect
380
+ github.com/tabnas/jsonic/go v0.4.0 // indirect
381
+ github.com/tabnas/parser/go v0.4.0 // indirect
382
+ )
364
383
 
365
384
  replace ${sdkModule} => ../go
366
385
  `))
367
386
 
368
- // go.sum — required for `go build` to accept the aql/eng/go dependency
387
+ // go.sum — required for `go build` to accept the boru/eng/go dependency
369
388
  // (the path-replaced sibling SDK needs no entry). Pinned alongside
370
- // AQL_ENG_VERSION above.
371
- File({ name: 'go.sum' }, () => Content(AQL_ENG_GOSUM))
389
+ // BORU_ENG_VERSION above.
390
+ File({ name: 'go.sum' }, () => Content(BORU_ENG_GOSUM))
372
391
 
373
392
  // Makefile — `make build` for the current machine, `make build-all` to
374
393
  // cross-compile for the three desktop OSes (linux, darwin, windows) on
@@ -1,6 +1,6 @@
1
1
  // Command ProjectName-cli is a CLI + REPL for the ProjectName SDK,
2
- // built on the AQL engine. Positional arguments are joined into a
3
- // single AQL expression and evaluated; with no arguments, falls into
2
+ // built on the boru engine. Positional arguments are joined into a
3
+ // single boru expression and evaluated; with no arguments, falls into
4
4
  // a REPL. Generated by sdkgen go-cli target.
5
5
  package main
6
6
 
@@ -11,8 +11,8 @@ import (
11
11
  "os"
12
12
  "strings"
13
13
 
14
- eng "github.com/aql-lang/aql/eng/go"
15
- "github.com/aql-lang/aql/eng/go/parser"
14
+ eng "github.com/boru-lang/boru/eng/go"
15
+ "github.com/boru-lang/boru/eng/go/parser"
16
16
  sdk "GOMODULE"
17
17
  )
18
18
 
@@ -28,10 +28,10 @@ func main() {
28
28
 
29
29
  // usage prints the CLI help (for --help / -h). No client or network setup.
30
30
  func usage(out io.Writer) {
31
- fmt.Fprintf(out, "%s-cli — AQL-driven CLI + REPL for the %s SDK\n\n", prompt, prompt)
31
+ fmt.Fprintf(out, "%s-cli — boru-driven CLI + REPL for the %s SDK\n\n", prompt, prompt)
32
32
  fmt.Fprintln(out, "Usage:")
33
- fmt.Fprintf(out, " %s-cli [--help] [<AQL expression>]\n\n", prompt)
34
- fmt.Fprintln(out, "With arguments, they are joined into a single AQL expression and")
33
+ fmt.Fprintf(out, " %s-cli [--help] [<boru expression>]\n\n", prompt)
34
+ fmt.Fprintln(out, "With arguments, they are joined into a single boru expression and")
35
35
  fmt.Fprintln(out, "evaluated against the API. With no arguments, starts an interactive REPL.")
36
36
  fmt.Fprintln(out)
37
37
  fmt.Fprintln(out, "Words: list / load / update <query?> <entity>")
@@ -5,11 +5,11 @@ import (
5
5
  "fmt"
6
6
  "strings"
7
7
 
8
- eng "github.com/aql-lang/aql/eng/go"
8
+ eng "github.com/boru-lang/boru/eng/go"
9
9
  sdk "GOMODULE"
10
10
  )
11
11
 
12
- // registerSDKWords installs three native AQL words bound to the SDK:
12
+ // registerSDKWords installs three native boru words bound to the SDK:
13
13
  // list / load / update. Each is declared with two overloads matching
14
14
  // the signature [query?:(Node or Scalar) entity:atom]:
15
15
  //
@@ -18,31 +18,34 @@ import (
18
18
  // `load {id:1} book`, `load 1 book`)
19
19
  //
20
20
  // The entity slot is /q-quoted so a bareword `book` parses as the
21
- // Atom "book" rather than dispatching as an undefined word.
21
+ // Atom "book" rather than dispatching as an undefined word. Both
22
+ // overloads are all-forward (BarrierAllForward), so args are collected
23
+ // from the tokens following the word.
22
24
  func registerSDKWords(r *eng.Registry, client *sdk.ProjectNameSDK) {
23
25
  for _, op := range []string{"list", "load", "update"} {
24
26
  op := op
25
- single := eng.NativeSig{
27
+ single := eng.Signature{
26
28
  Args: []*eng.Type{eng.TAtom},
27
29
  QuoteArgs: map[int]bool{0: true},
28
- Handler: func(args []eng.Value, _ map[string]eng.Value, _ []eng.Value, _ *eng.Registry) ([]eng.Value, error) {
30
+ Impl: eng.Go(func(args []eng.Value, _ map[string]eng.Value, _ []eng.Value, _ *eng.Registry) ([]eng.Value, error) {
29
31
  return runOp(client, op, nil, args[0])
30
- },
31
- Returns: []*eng.Type{eng.TAny},
32
+ }),
33
+ Returns: []*eng.Type{eng.TAny},
34
+ BarrierPos: eng.BarrierAllForward,
32
35
  }
33
- dual := eng.NativeSig{
36
+ dual := eng.Signature{
34
37
  Args: []*eng.Type{eng.TAny, eng.TAtom},
35
38
  QuoteArgs: map[int]bool{1: true},
36
- Handler: func(args []eng.Value, _ map[string]eng.Value, _ []eng.Value, _ *eng.Registry) ([]eng.Value, error) {
39
+ Impl: eng.Go(func(args []eng.Value, _ map[string]eng.Value, _ []eng.Value, _ *eng.Registry) ([]eng.Value, error) {
37
40
  q := args[0]
38
41
  return runOp(client, op, &q, args[1])
39
- },
40
- Returns: []*eng.Type{eng.TAny},
42
+ }),
43
+ Returns: []*eng.Type{eng.TAny},
44
+ BarrierPos: eng.BarrierAllForward,
41
45
  }
42
46
  r.RegisterNativeFunc(eng.NativeFunc{
43
- Name: op,
44
- ForwardArgs: true,
45
- Signatures: []eng.NativeSig{single, dual},
47
+ Name: op,
48
+ Signatures: []eng.Signature{single, dual},
46
49
  })
47
50
  }
48
51
  }
@@ -91,22 +94,22 @@ func entityFor(client *sdk.ProjectNameSDK, name string) (sdk.ProjectNameEntity,
91
94
  return nil, fmt.Errorf("unknown entity %q", name)
92
95
  }
93
96
 
94
- // queryToMap converts an AQL Value (Map or Scalar) into the
97
+ // queryToMap converts a boru Value (Map or Scalar) into the
95
98
  // `map[string]any` shape the SDK expects. Maps are unwrapped via
96
99
  // eng.ToNative. Scalars are wrapped as {"id": <value>} so the
97
100
  // shorthand `load 1 book` becomes `load {id:1} book`.
98
101
  func queryToMap(v eng.Value) (map[string]any, error) {
99
- if v.VType.Matches(eng.TMap) {
102
+ if v.Parent.ConformsTo(eng.TMap) {
100
103
  m, ok := eng.ToNative(v).(map[string]any)
101
104
  if !ok {
102
105
  return nil, fmt.Errorf("query map could not be unwrapped")
103
106
  }
104
107
  return m, nil
105
108
  }
106
- if v.VType.Matches(eng.TScalar) {
109
+ if v.Parent.ConformsTo(eng.TScalar) {
107
110
  return map[string]any{"id": eng.ToNative(v)}, nil
108
111
  }
109
- return nil, fmt.Errorf("query must be a Map or Scalar, got %s", v.VType)
112
+ return nil, fmt.Errorf("query must be a Map or Scalar, got %s", v.Parent)
110
113
  }
111
114
 
112
115
  // extractData walks an SDK result and replaces any sdk.Entity wrapper
@@ -12,6 +12,7 @@ import {
12
12
  indent,
13
13
  isAuthActive,
14
14
  resolveAuthPrefix,
15
+ serverVariables,
15
16
  } from '@voxgig/sdkgen'
16
17
 
17
18
 
@@ -53,6 +54,14 @@ const Config = cmp(async function Config(props: any) {
53
54
  `
54
55
  : ''
55
56
 
57
+ // Templated server URL: emit the spec's server-variable defaults so the
58
+ // runtime can substitute {name} placeholders in base (see makeOptions).
59
+ const svars = serverVariables(model)
60
+ const serverBlock = 0 === svars.length ? '' :
61
+ 'server: {\n' +
62
+ svars.map((v: any) => ` ${JSON.stringify(v.name)}: ${JSON.stringify(v.dflt)},\n`).join('') +
63
+ ' },\n\n '
64
+
56
65
  File({ name: 'Config.' + target.ext }, () => {
57
66
 
58
67
  Fragment({
@@ -60,6 +69,8 @@ const Config = cmp(async function Config(props: any) {
60
69
 
61
70
  replace: {
62
71
 
72
+ "'SERVERBLOCK'": serverBlock,
73
+
63
74
  "'AUTHBLOCK'": authBlock,
64
75
 
65
76
  "'HEADERS'": indent(JSON.stringify(headers, null, 2), 4).trim(),
@@ -19,7 +19,7 @@ class Config {
19
19
 
20
20
 
21
21
  main = {
22
- name: 'ProjectName',
22
+ name: '$$const.Name$$',
23
23
  }
24
24
 
25
25
 
@@ -31,7 +31,7 @@ class Config {
31
31
  options = {
32
32
  base: '$$main.kit.info.servers.0.url$$',
33
33
 
34
- 'AUTHBLOCK'headers: 'HEADERS',
34
+ 'SERVERBLOCK''AUTHBLOCK'headers: 'HEADERS',
35
35
 
36
36
  entity: {
37
37
  // #EntityConfigs
@@ -17,6 +17,10 @@ describe('EntityNameDirect', async () => {
17
17
 
18
18
  test('direct-exists', async () => {
19
19
  const sdk = new ProjectNameSDK({
20
+ // Concrete base: a live construction must satisfy any server
21
+ // variables a templated base URL declares; overriding base with a
22
+ // literal (as the direct flow tests do) sidesteps the requirement.
23
+ base: 'http://localhost:8080',
20
24
  system: { fetch: async () => ({}) }
21
25
  })
22
26
  assert('function' === typeof sdk.direct)
@@ -11,6 +11,7 @@ import {
11
11
  each,
12
12
  isAuthActive,
13
13
  resolveAuthPrefix,
14
+ serverVariables,
14
15
  } from '@voxgig/sdkgen'
15
16
 
16
17
 
@@ -46,6 +47,14 @@ const Config = cmp(async function Config(props: any) {
46
47
  let baseUrl = ''
47
48
  try { baseUrl = getModelPath(model, `main.${KIT}.info.servers.0.url`) } catch (_e) { }
48
49
 
50
+ // Templated server URL: emit the spec's server-variable defaults so the
51
+ // runtime can substitute {name} placeholders in base (see make_options).
52
+ const svars = serverVariables(model)
53
+ const serverBlock = 0 === svars.length ? '' :
54
+ ' server = {\n' +
55
+ svars.map((v: any) => ` [${JSON.stringify(v.name)}] = ${JSON.stringify(v.dflt)},\n`).join('') +
56
+ ' },\n'
57
+
49
58
  const authBlock = authActive
50
59
  ? ` auth = {
51
60
  prefix = "${authPrefix}",
@@ -73,7 +82,7 @@ local function make_config()
73
82
  Content(` },
74
83
  options = {
75
84
  base = "${baseUrl}",
76
- ${authBlock} headers = ${formatLuaTable(headers, 3)},
85
+ ${serverBlock}${authBlock} headers = ${formatLuaTable(headers, 3)},
77
86
  entity = {
78
87
  `)
79
88
 
@@ -11,6 +11,7 @@ import {
11
11
  each,
12
12
  isAuthActive,
13
13
  resolveAuthPrefix,
14
+ serverVariables,
14
15
  } from '@voxgig/sdkgen'
15
16
 
16
17
 
@@ -46,6 +47,16 @@ const Config = cmp(async function Config(props: any) {
46
47
  let baseUrl = ''
47
48
  try { baseUrl = getModelPath(model, `main.${KIT}.info.servers.0.url`) } catch (_e) { }
48
49
 
50
+ // Templated server URL: emit the spec's server-variable defaults so the
51
+ // runtime can substitute {name} placeholders in base (see MakeOptions).
52
+ // `$` is escaped so a default can never open a PHP interpolation.
53
+ const svars = serverVariables(model)
54
+ const phps = (s: string) => JSON.stringify(s).replace(/\$/g, '\\$')
55
+ const serverBlock = 0 === svars.length ? '' :
56
+ ' "server" => [\n' +
57
+ svars.map((v: any) => ` ${phps(v.name)} => ${phps(v.dflt)},\n`).join('') +
58
+ ' ],\n'
59
+
49
60
  const authBlock = authActive
50
61
  ? ` "auth" => [
51
62
  "prefix" => "${authPrefix}",
@@ -84,7 +95,7 @@ class ${model.const.Name}Config
84
95
  Content(` ],
85
96
  "options" => [
86
97
  "base" => "${baseUrl}",
87
- ${authBlock} "headers" => ${formatPhpArray(headers, 4)},
98
+ ${serverBlock}${authBlock} "headers" => ${formatPhpArray(headers, 4)},
88
99
  "entity" => (object)[],
89
100
  ],
90
101
  "entity" => (object)[],
@@ -94,7 +105,7 @@ ${authBlock} "headers" => ${formatPhpArray(headers, 4)},
94
105
  Content(` ],
95
106
  "options" => [
96
107
  "base" => "${baseUrl}",
97
- ${authBlock} "headers" => ${formatPhpArray(headers, 4)},
108
+ ${serverBlock}${authBlock} "headers" => ${formatPhpArray(headers, 4)},
98
109
  "entity" => [
99
110
  `)
100
111
 
@@ -11,6 +11,7 @@ import {
11
11
  each,
12
12
  isAuthActive,
13
13
  resolveAuthPrefix,
14
+ serverVariables,
14
15
  } from '@voxgig/sdkgen'
15
16
 
16
17
 
@@ -46,6 +47,14 @@ const Config = cmp(async function Config(props: any) {
46
47
  let baseUrl = ''
47
48
  try { baseUrl = getModelPath(model, `main.${KIT}.info.servers.0.url`) } catch (_e) { }
48
49
 
50
+ // Templated server URL: emit the spec's server-variable defaults so the
51
+ // runtime can substitute {name} placeholders in base (see make_options).
52
+ const svars = serverVariables(model)
53
+ const serverBlock = 0 === svars.length ? '' :
54
+ ' "server": {\n' +
55
+ svars.map((v: any) => ` ${JSON.stringify(v.name)}: ${JSON.stringify(v.dflt)},\n`).join('') +
56
+ ' },\n'
57
+
49
58
  const authBlock = authActive
50
59
  ? ` "auth": {
51
60
  "prefix": "${authPrefix}",
@@ -74,7 +83,7 @@ def make_config():
74
83
  Content(` },
75
84
  "options": {
76
85
  "base": "${baseUrl}",
77
- ${authBlock} "headers": ${formatPyDict(headers, 3)},
86
+ ${serverBlock}${authBlock} "headers": ${formatPyDict(headers, 3)},
78
87
  "entity": {
79
88
  `)
80
89
 
@@ -11,6 +11,7 @@ import {
11
11
  each,
12
12
  isAuthActive,
13
13
  resolveAuthPrefix,
14
+ serverVariables,
14
15
  } from '@voxgig/sdkgen'
15
16
 
16
17
 
@@ -46,6 +47,16 @@ const Config = cmp(async function Config(props: any) {
46
47
  let baseUrl = ''
47
48
  try { baseUrl = getModelPath(model, `main.${KIT}.info.servers.0.url`) } catch (_e) { }
48
49
 
50
+ // Templated server URL: emit the spec's server-variable defaults so the
51
+ // runtime can substitute {name} placeholders in base (see make_options).
52
+ // `#` is escaped so a default can never open a Ruby interpolation.
53
+ const svars = serverVariables(model)
54
+ const rbs = (s: string) => JSON.stringify(s).replace(/#/g, '\\#')
55
+ const serverBlock = 0 === svars.length ? '' :
56
+ ' "server" => {\n' +
57
+ svars.map((v: any) => ` ${rbs(v.name)} => ${rbs(v.dflt)},\n`).join('') +
58
+ ' },\n'
59
+
49
60
  const authBlock = authActive
50
61
  ? ` "auth" => {
51
62
  "prefix" => "${authPrefix}",
@@ -74,7 +85,7 @@ module ${model.const.Name}Config
74
85
  Content(` },
75
86
  "options" => {
76
87
  "base" => "${baseUrl}",
77
- ${authBlock} "headers" => ${formatRubyHash(headers, 4)},
88
+ ${serverBlock}${authBlock} "headers" => ${formatRubyHash(headers, 4)},
78
89
  "entity" => {
79
90
  `)
80
91
 
@@ -75,8 +75,30 @@ const TestEntity = cmp(function TestEntity(props: any) {
75
75
 
76
76
  const genCtx: GenCtx = { model, entity, rustcrate, flow: basicflow, PROJUPPER }
77
77
 
78
- const opsList = Array.from(new Set(allSteps.map((s: any) => s.op).filter(Boolean)))
79
- .map(o => `"${o}"`).join(', ')
78
+ const opNames = Array.from(new Set(allSteps.map((s: any) => s.op).filter(Boolean)))
79
+ const opsList = opNames.map(o => `"${o}"`).join(', ')
80
+
81
+ // Same hazard as the csharp target: an entity whose basic flow has no ops
82
+ // would emit `for op in []`, and rustc cannot infer the element type of an
83
+ // empty array literal — E0282, type annotations needed. The loop is dead
84
+ // code in that case, and so is the `mode` binding only it reads (which
85
+ // would then warn as unused). Emit neither.
86
+ const skipBlock = 0 === opNames.length ? '' : ` // Per-op sdk-test-control.json skip — the basic test exercises a flow
87
+ // with multiple ops; skipping any op skips the whole flow.
88
+ let mode = if setup.live { "live" } else { "unit" };
89
+ for op in [${opsList}] {
90
+ let (skip, reason) = is_control_skipped("entityOp", &format!("${entity.name}.{}", op), mode);
91
+ if skip {
92
+ let reason = if reason.is_empty() {
93
+ "skipped via sdk-test-control.json".to_string()
94
+ } else {
95
+ reason
96
+ };
97
+ eprintln!("skip: {}", reason);
98
+ return;
99
+ }
100
+ }
101
+ `
80
102
 
81
103
  const method = rustVarName(entity.name)
82
104
  const evar = rustVarName(entity.name)
@@ -158,22 +180,7 @@ fn ${evar}_entity_stream() {
158
180
  #[test]
159
181
  fn ${evar}_entity_basic() {
160
182
  let setup = ${evar}_basic_setup(Value::Noval);
161
- // Per-op sdk-test-control.json skip the basic test exercises a flow
162
- // with multiple ops; skipping any op skips the whole flow.
163
- let mode = if setup.live { "live" } else { "unit" };
164
- for op in [${opsList}] {
165
- let (skip, reason) = is_control_skipped("entityOp", &format!("${entity.name}.{}", op), mode);
166
- if skip {
167
- let reason = if reason.is_empty() {
168
- "skipped via sdk-test-control.json".to_string()
169
- } else {
170
- reason
171
- };
172
- eprintln!("skip: {}", reason);
173
- return;
174
- }
175
- }
176
- // The basic flow consumes synthetic IDs from the fixture. In live mode
183
+ ${skipBlock} // The basic flow consumes synthetic IDs from the fixture. In live mode
177
184
  // without an *_ENTID env override, those IDs hit the live API and 4xx.
178
185
  if setup.synthetic_only {
179
186
  eprintln!("skip: live entity test uses synthetic IDs from fixture — set ${PROJUPPER}_TEST_${ENTUPPER}_ENTID JSON to run live");
@@ -25,7 +25,7 @@ import {
25
25
  File, Content, Folder,
26
26
  } from '@voxgig/sdkgen'
27
27
 
28
- import { canonToType, opTypeName, opRequestShape, warnEntityTypeCollisions , deriveEntityNames } from '@voxgig/sdkgen'
28
+ import { canonToType, opTypeName, opRequestShape, warnEntityTypeCollisions , deriveEntityNames, swiftSafeTypeName } from '@voxgig/sdkgen'
29
29
 
30
30
  import {
31
31
  KIT,
@@ -114,9 +114,16 @@ import Foundation
114
114
  .filter((f: any) => f.active !== false)
115
115
 
116
116
  // Entity data model: one property per field. req:false -> optional.
117
+ //
118
+ // Swift has no intra-module namespacing, so a spec schema named
119
+ // after one of our own runtime types (e.g. `Response`) would be a
120
+ // redeclaration and fail the build. swiftSafeTypeName appends
121
+ // `Type` on collision only — `Response` -> `ResponseType` — so
122
+ // non-colliding SDKs generate byte-identical output to before.
123
+ const TypeName = swiftSafeTypeName(Name)
117
124
  emitStruct(
118
- `/// ${Name} is the typed data model for the ${ent.name} entity.`,
119
- Name,
125
+ `/// ${TypeName} is the typed data model for the ${ent.name} entity.`,
126
+ TypeName,
120
127
  fields.map((f: any) => ({ name: f.name, type: f.type, optional: false === f.req }))
121
128
  )
122
129
 
@@ -12,6 +12,7 @@ import {
12
12
  indent,
13
13
  isAuthActive,
14
14
  resolveAuthPrefix,
15
+ serverVariables,
15
16
  } from '@voxgig/sdkgen'
16
17
 
17
18
 
@@ -53,6 +54,14 @@ const Config = cmp(async function Config(props: any) {
53
54
  `
54
55
  : ''
55
56
 
57
+ // Templated server URL: emit the spec's server-variable defaults so the
58
+ // runtime can substitute {name} placeholders in base (see makeOptions).
59
+ const svars = serverVariables(model)
60
+ const serverBlock = 0 === svars.length ? '' :
61
+ 'server: {\n' +
62
+ svars.map((v: any) => ` ${JSON.stringify(v.name)}: ${JSON.stringify(v.dflt)},\n`).join('') +
63
+ ' },\n\n '
64
+
56
65
  File({ name: 'Config.' + target.ext }, () => {
57
66
 
58
67
  Fragment({
@@ -60,6 +69,8 @@ const Config = cmp(async function Config(props: any) {
60
69
 
61
70
  replace: {
62
71
 
72
+ "'SERVERBLOCK'": serverBlock,
73
+
63
74
  "'AUTHBLOCK'": authBlock,
64
75
 
65
76
  "'HEADERS'": indent(JSON.stringify(headers, null, 2), 4).trim(),