@voxgig/sdkgen 4.2.1 → 4.2.2

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.
package/bin/voxgig-sdkgen CHANGED
@@ -8,7 +8,7 @@ const { Shape, One, Skip } = require('shape')
8
8
 
9
9
  const { SdkGen } = require('../dist/sdkgen.js')
10
10
 
11
- const VERSION = '4.2.1'
11
+ const VERSION = '4.2.2'
12
12
  const KONSOLE = console
13
13
 
14
14
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voxgig/sdkgen",
3
- "version": "4.2.1",
3
+ "version": "4.2.2",
4
4
  "main": "dist/sdkgen.js",
5
5
  "type": "commonjs",
6
6
  "engines": {
@@ -382,18 +382,21 @@ const generateList: OpGen = (ctx, step, index) => {
382
382
  const hasRefData = validRef && allSteps.some(s => 'create' === s.op &&
383
383
  ((s.input.ref ?? entity.name + '_ref01') === validRef))
384
384
 
385
- // Entities in the list are entity instances; select over their data maps.
385
+ // listvar is ALREADY a list of data maps the list call above maps
386
+ // .data() over the entity instances. Mapping .data() a second time here
387
+ // called it on a plain Map and every entity test died at runtime with
388
+ // "Class '_Map<String, dynamic>' has no instance method 'data'".
386
389
  if ('ItemExists' === validator.apply && hasRefData) {
387
390
  Content(`
388
391
  ok(!isempty(select(
389
- (${listvar} as List).map((e) => e.data()).toList(),
392
+ ${listvar},
390
393
  {'id': ${validRef}_data['id']})));
391
394
  `)
392
395
  }
393
396
  else if ('ItemNotExists' === validator.apply && hasRefData) {
394
397
  Content(`
395
398
  ok(isempty(select(
396
- (${listvar} as List).map((e) => e.data()).toList(),
399
+ ${listvar},
397
400
  {'id': ${validRef}_data['id']})));
398
401
  `)
399
402
  }
@@ -55,9 +55,21 @@ function normalizePathParams(
55
55
 
56
56
 
57
57
  // Render a JSON value as a Java literal for query examples.
58
+ // A Java source literal for an example value from the model.
59
+ //
60
+ // An integer beyond Java's int range needs the L suffix: javac rejects a bare
61
+ // 120615523104 outright ("integer number too large"), so one large id in a
62
+ // spec's example makes the whole generated test package fail to compile.
63
+ // A non-integral double is fine unsuffixed.
58
64
  function javaLiteral(v: any): string {
59
65
  if (null == v) return 'null'
60
- if ('number' === typeof v || 'boolean' === typeof v) return String(v)
66
+ if ('boolean' === typeof v) return String(v)
67
+ if ('number' === typeof v) {
68
+ if (Number.isInteger(v) && (v > 2147483647 || v < -2147483648)) {
69
+ return String(v) + 'L'
70
+ }
71
+ return String(v)
72
+ }
61
73
  return JSON.stringify(String(v))
62
74
  }
63
75
 
@@ -158,7 +158,7 @@ class ${entity.Name}DirectTest {
158
158
  : []
159
159
  const listSkipBlock = listLiveIdKeys.length > 0
160
160
  ? ` if (setup.live) {
161
- for (liveKey in arrayOf(${listLiveIdKeys.map((k: string) => `"${k}"`).join(', ')})) {
161
+ for (liveKey in arrayOf<String>(${listLiveIdKeys.map((k: string) => `"${k}"`).join(', ')})) {
162
162
  Assumptions.assumeTrue(setup.idmap[liveKey] != null,
163
163
  "live test needs " + liveKey + " via *_ENTID env var (synthetic IDs only)")
164
164
  }
@@ -265,7 +265,7 @@ ${listSkipBlock} val client = setup.client
265
265
  }
266
266
  const loadSkipBlock = loadLiveIdKeys.length > 0
267
267
  ? ` if (setup.live) {
268
- for (liveKey in arrayOf(${loadLiveIdKeys.map(k => `"${k}"`).join(', ')})) {
268
+ for (liveKey in arrayOf<String>(${loadLiveIdKeys.map(k => `"${k}"`).join(', ')})) {
269
269
  Assumptions.assumeTrue(setup.idmap[liveKey] != null,
270
270
  "live test needs " + liveKey + " via *_ENTID env var (synthetic IDs only)")
271
271
  }
@@ -114,7 +114,7 @@ class ${entity.Name}EntityTest {
114
114
  val setup = ${accessor}BasicSetup(null)
115
115
  // Per-op sdk-test-control.json skip.
116
116
  val mode = if (setup.live) "live" else "unit"
117
- for (op in arrayOf(${stepOps.map(o => `"${o}"`).join(', ')})) {
117
+ for (op in arrayOf<String>(${stepOps.map(o => `"${o}"`).join(', ')})) {
118
118
  val reason = RunnerSupport.skipReason("entityOp", "${entity.name}.\$op", mode)
119
119
  Assumptions.assumeTrue(
120
120
  reason == null,
@@ -70,6 +70,11 @@ const TestEntity = cmp(function TestEntity(props: any) {
70
70
  : []
71
71
  const aliases = updateData.map(([k, v]: any) => [k, v])
72
72
 
73
+ // An entity whose basic flow has no steps yields an EMPTY list, and Perl's
74
+ // `for my $x () {` is a syntax error (unlike `for my $x (()) {`, which is a
75
+ // valid empty loop) — the whole test file then fails to compile. The loop
76
+ // below therefore wraps this in a second pair of parens, which is a no-op
77
+ // for a non-empty list because Perl flattens it.
73
78
  const opsList = Array.from(new Set(
74
79
  (allSteps as any[]).map((s: any) => s.op).filter(Boolean)))
75
80
  .map(o => `'${o}'`).join(', ')
@@ -101,7 +106,7 @@ BASIC_FLOW: {
101
106
  my $setup = ${entity.name}_basic_setup(undef);
102
107
  my $_live = $setup->{live} ? 1 : 0;
103
108
  # Per-op sdk-test-control.json skip.
104
- for my $_op (${opsList}) {
109
+ for my $_op ((${opsList})) {
105
110
  my ($_should_skip, $_reason) = ${N}TestRunner::is_control_skipped(
106
111
  'entityOp', "${entity.name}." . $_op, $_live ? 'live' : 'unit');
107
112
  if ($_should_skip) {
@@ -20,7 +20,14 @@ const RUST_RESERVED = new Set<string>([
20
20
 
21
21
  // A collision-free snake_case rust identifier for a model name.
22
22
  function rustVarName(name: string): string {
23
- const snake = name.replace(/[^a-zA-Z0-9_]/g, '_').toLowerCase()
23
+ let snake = name.replace(/[^a-zA-Z0-9_]/g, '_').toLowerCase()
24
+ // No Rust identifier may begin with a digit. A `3d_id` field became
25
+ // `pub 3_d_id: String`, which does not compile ("expected identifier, found
26
+ // `3_d_id`") and took the whole crate with it. Prefixed with an underscore,
27
+ // the convention cmp/c/utility_c.ts already applies.
28
+ if (/^[0-9]/.test(snake)) {
29
+ snake = '_' + snake
30
+ }
24
31
  return RUST_RESERVED.has(snake) ? snake + '_' : snake
25
32
  }
26
33
 
@@ -22,13 +22,27 @@ function projectPath(suffix?: string): string {
22
22
  function swiftVarName(name: string): string {
23
23
  const pascal = camelify(name)
24
24
  const lower = pascal.charAt(0).toLowerCase() + pascal.slice(1)
25
- return SWIFT_RESERVED.has(lower) ? lower + '_' : lower
25
+ if (SWIFT_RESERVED.has(lower)) {
26
+ return lower + '_'
27
+ }
28
+ return leadingDigitSafe(lower)
29
+ }
30
+
31
+
32
+ // No Swift identifier may begin with a digit, but a model field may: a
33
+ // `3d_id` field camelifies to `3DId`, and `public var 3DId: String` does not
34
+ // merely fail to bind — the compiler reads it as a malformed number and the
35
+ // whole module dies on "'D' is not a valid digit in integer literal", naming
36
+ // nothing that leads back to the field. Prefixed with an underscore, the same
37
+ // convention cmp/c/utility_c.ts already applies.
38
+ function leadingDigitSafe(ident: string): string {
39
+ return /^[0-9]/.test(ident) ? '_' + ident : ident
26
40
  }
27
41
 
28
42
 
29
43
  // A PascalCase Swift identifier for a snake_case model name.
30
44
  function swiftPascalName(name: string): string {
31
- return camelify(name)
45
+ return leadingDigitSafe(camelify(name))
32
46
  }
33
47
 
34
48
 
@@ -50,14 +50,26 @@ defmodule Voxgig.Struct do
50
50
  id
51
51
  end
52
52
 
53
+ # ensure_heap here too, not only in alloc. A named ETS table belongs to the
54
+ # process that created it and dies with it — and ExUnit runs each test in its
55
+ # own process, so a table created by an alloc in one test is gone by the
56
+ # next. hget then raised ArgumentError ("the table identifier does not refer
57
+ # to an existing ETS table") from whichever unrelated test happened to run
58
+ # second, which is why this surfaced as a pipeline/netsim failure rather than
59
+ # as anything to do with the heap.
53
60
  defp hget(id) do
61
+ ensure_heap()
62
+
54
63
  case :ets.lookup(@heap, id) do
55
64
  [{_, c}] -> c
56
65
  _ -> nil
57
66
  end
58
67
  end
59
68
 
60
- defp hset(id, contents), do: :ets.insert(@heap, {id, contents})
69
+ defp hset(id, contents) do
70
+ ensure_heap()
71
+ :ets.insert(@heap, {id, contents})
72
+ end
61
73
 
62
74
  defp vmap_new(pairs), do: {:vmap, alloc(pairs)}
63
75
  defp vlist_new(items), do: {:vlist, alloc(items)}
@@ -3,7 +3,7 @@
3
3
  "package": 1
4
4
  },
5
5
  "name": "@voxgig/sdkgen",
6
- "version": "4.2.1",
6
+ "version": "4.2.2",
7
7
  "provides": {
8
8
  "target": [
9
9
  "c",