@voxgig/sdkgen 4.0.1 → 4.2.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.
- package/bin/voxgig-sdkgen +1 -1
- package/package.json +1 -1
- package/project/.sdk/src/cmp/scala/TestDirect_scala.ts +1 -1
- package/project/.sdk/src/cmp/scala/TestEntity_scala.ts +1 -1
- package/project/.sdk/tm/c/feature/test.c +50 -12
- package/project/.sdk/tm/clojure/src/sdk/features.clj +21 -3
- package/project/.sdk/tm/cpp/Makefile +11 -1
- package/project/.sdk/tm/cpp/feature/test.hpp +34 -11
- package/project/.sdk/tm/csharp/feature/TestFeature.cs +28 -2
- package/project/.sdk/tm/dart/lib/feature/test/TestFeature.dart +38 -10
- package/project/.sdk/tm/elixir/lib/projectname/feature/test.ex +40 -13
- package/project/.sdk/tm/java/feature/TestFeature.java +46 -12
- package/project/.sdk/tm/kotlin/feature/TestFeature.kt +29 -11
- package/project/.sdk/tm/lean/src/SdkRuntime.lean +19 -1
- package/project/.sdk/tm/lean/src/SdkUtility.lean +2 -2
- package/project/.sdk/tm/ocaml/sdk_features.ml +31 -12
- package/project/.sdk/tm/perl/feature/test_feature.pm +34 -12
- package/project/.sdk/tm/py-data/test/conftest.py +24 -0
- package/project/.sdk/tm/rust/feature/test.rs +41 -16
- package/project/.sdk/tm/scala/feature/TestFeature.scala +35 -12
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/feature/TestFeature.swift +33 -12
- package/project/.sdk/tm/zig/feature/test.zig +39 -12
- package/project/sdkgen-package.json +1 -1
|
@@ -40,8 +40,31 @@ class TestFeature extends BaseFeature("test", "0.0.1", true) {
|
|
|
40
40
|
else ctx.utility.fetcher = makeNetsim(net, testFetcher)
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
// THE MOCK HAS TO AGREE WITH THE MODEL. A point carrying
|
|
44
|
+
// `transform.res: `body.item`` describes an API that answers {"item": {...}}
|
|
45
|
+
// and the response transform unwraps that key on the way back. Returning the
|
|
46
|
+
// bare payload means the transform unwraps a property that is not there and
|
|
47
|
+
// the caller gets nothing. Mirrors the go/ts/lua/php mocks.
|
|
48
|
+
private def envelope(ctx: Context, data: Object): Object = {
|
|
49
|
+
if (data == null || ctx == null || ctx.point == null) return data
|
|
50
|
+
val tm = Struct.getprop(ctx.point, "transform")
|
|
51
|
+
Struct.getprop(tm, "res") match {
|
|
52
|
+
case spec: String =>
|
|
53
|
+
// Exactly `body.<key>`; a deeper path is not an envelope this mock
|
|
54
|
+
// can synthesise, so it is left alone rather than guessed at.
|
|
55
|
+
if (!spec.startsWith("`body.") || !spec.endsWith("`") || spec.length < 8) return data
|
|
56
|
+
val inner = spec.substring(6, spec.length - 1)
|
|
57
|
+
if (inner.isEmpty || inner.contains(".")) return data
|
|
58
|
+
val wrapped = new java.util.LinkedHashMap[String, Object]()
|
|
59
|
+
wrapped.put(inner, data)
|
|
60
|
+
wrapped
|
|
61
|
+
case _ => data
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
private def respond(ctx: Context, status: Int, data: Object, extra: JMap[String, Object]): JMap[String, Object] = {
|
|
66
|
+
val payload = envelope(ctx, data)
|
|
67
|
+
val js: Supplier[Object] = () => payload
|
|
45
68
|
val out = new LinkedHashMap[String, Object]()
|
|
46
69
|
out.put("status", java.lang.Integer.valueOf(status))
|
|
47
70
|
out.put("statusText", "OK")
|
|
@@ -85,18 +108,18 @@ class TestFeature extends BaseFeature("test", "0.0.1", true) {
|
|
|
85
108
|
val args = buildArgs(ctx, op, resolveMatch(ctx, ctx.reqmatch))
|
|
86
109
|
val found = Struct.select(entmap, args)
|
|
87
110
|
val ent = Struct.getelem(found, java.lang.Integer.valueOf(0))
|
|
88
|
-
if (ent == null) return respond(404, null, extra("statusText", "Not found"))
|
|
111
|
+
if (ent == null) return respond(ctx, 404, null, extra("statusText", "Not found"))
|
|
89
112
|
Struct.delprop(ent, "$KEY")
|
|
90
113
|
val out = Struct.clone(ent)
|
|
91
|
-
respond(200, out, null)
|
|
114
|
+
respond(ctx, 200, out, null)
|
|
92
115
|
} else if ("list" == op.name) {
|
|
93
116
|
val args = buildArgs(ctx, op, ctx.reqmatch)
|
|
94
117
|
val found = Struct.select(entmap, args)
|
|
95
|
-
if (found == null) return respond(404, null, extra("statusText", "Not found"))
|
|
118
|
+
if (found == null) return respond(ctx, 404, null, extra("statusText", "Not found"))
|
|
96
119
|
val it = found.iterator()
|
|
97
120
|
while (it.hasNext) Struct.delprop(it.next(), "$KEY")
|
|
98
121
|
val out = Struct.clone(found)
|
|
99
|
-
respond(200, out, null)
|
|
122
|
+
respond(ctx, 200, out, null)
|
|
100
123
|
} else if ("update" == op.name) {
|
|
101
124
|
var updateMatch = new LinkedHashMap[String, Object]()
|
|
102
125
|
if (ctx.reqdata != null) {
|
|
@@ -119,11 +142,11 @@ class TestFeature extends BaseFeature("test", "0.0.1", true) {
|
|
|
119
142
|
vit.next() match { case e: JMap[_, _] => ent = e; brk = true; case _ => }
|
|
120
143
|
}
|
|
121
144
|
}
|
|
122
|
-
if (ent == null) return respond(404, null, extra("statusText", "Not found"))
|
|
145
|
+
if (ent == null) return respond(ctx, 404, null, extra("statusText", "Not found"))
|
|
123
146
|
ent match { case m: JMap[_, _] if ctx.reqdata != null => m.asInstanceOf[JMap[String, Object]].putAll(ctx.reqdata); case _ => }
|
|
124
147
|
Struct.delprop(ent, "$KEY")
|
|
125
148
|
val out = Struct.clone(ent)
|
|
126
|
-
respond(200, out, null)
|
|
149
|
+
respond(ctx, 200, out, null)
|
|
127
150
|
} else if ("remove" == op.name) {
|
|
128
151
|
val args = buildArgs(ctx, op, resolveMatch(ctx, ctx.reqmatch))
|
|
129
152
|
val found = Struct.select(entmap, args)
|
|
@@ -134,7 +157,7 @@ class TestFeature extends BaseFeature("test", "0.0.1", true) {
|
|
|
134
157
|
Struct.delprop(entmap, id)
|
|
135
158
|
case _ =>
|
|
136
159
|
}
|
|
137
|
-
respond(200, null, null)
|
|
160
|
+
respond(ctx, 200, null, null)
|
|
138
161
|
} else if ("create" == op.name) {
|
|
139
162
|
buildArgs(ctx, op, ctx.reqdata)
|
|
140
163
|
var id = ctx.utility.param(ctx, "id")
|
|
@@ -153,11 +176,11 @@ class TestFeature extends BaseFeature("test", "0.0.1", true) {
|
|
|
153
176
|
id match { case s: String => entmap.put(s, entm); case _ => }
|
|
154
177
|
Struct.delprop(entm, "$KEY")
|
|
155
178
|
val out = Struct.clone(entm)
|
|
156
|
-
respond(200, out, null)
|
|
157
|
-
case _ => respond(200, ent, null)
|
|
179
|
+
respond(ctx, 200, out, null)
|
|
180
|
+
case _ => respond(ctx, 200, ent, null)
|
|
158
181
|
}
|
|
159
182
|
} else {
|
|
160
|
-
respond(404, null, extra("statusText", "Unknown operation"))
|
|
183
|
+
respond(ctx, 404, null, extra("statusText", "Unknown operation"))
|
|
161
184
|
}
|
|
162
185
|
}
|
|
163
186
|
|
|
@@ -5,11 +5,32 @@
|
|
|
5
5
|
|
|
6
6
|
import Foundation
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
// THE MOCK HAS TO AGREE WITH THE MODEL. A point carrying
|
|
9
|
+
// `transform.res: `body.item`` describes an API that answers {"item": {...}},
|
|
10
|
+
// and the response transform unwraps that key on the way back. Returning the
|
|
11
|
+
// bare payload means the transform unwraps a property that is not there and
|
|
12
|
+
// the caller gets nothing. Mirrors the go/ts/lua/php mocks.
|
|
13
|
+
private func testEnvelope(_ ctx: Context, _ data: Value) -> Value {
|
|
14
|
+
if case .noval = data { return data }
|
|
15
|
+
if case .null = data { return data }
|
|
16
|
+
guard let point = ctx.point else { return data }
|
|
17
|
+
guard case .map(let tm)? = point.entries["transform"] else { return data }
|
|
18
|
+
guard case .string(let spec)? = tm.entries["res"] else { return data }
|
|
19
|
+
// Exactly `body.<key>`; a deeper path is not an envelope this mock can
|
|
20
|
+
// synthesise, so it is left alone rather than guessed at.
|
|
21
|
+
guard spec.hasPrefix("`body."), spec.hasSuffix("`"), spec.count >= 8 else { return data }
|
|
22
|
+
let inner = String(spec.dropFirst(6).dropLast(1))
|
|
23
|
+
guard !inner.isEmpty, !inner.contains(".") else { return data }
|
|
24
|
+
let wrapped = VMap()
|
|
25
|
+
wrapped.entries[inner] = data
|
|
26
|
+
return .map(wrapped)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
private func testRespond(_ ctx: Context, _ status: Int, _ data: Value, _ extra: VMap?) -> Value {
|
|
9
30
|
let res = VMap()
|
|
10
31
|
res.entries["status"] = .int(Int64(status))
|
|
11
32
|
res.entries["statusText"] = .string("OK")
|
|
12
|
-
let captured = data
|
|
33
|
+
let captured = testEnvelope(ctx, data)
|
|
13
34
|
res.entries["json"] = .nat({ () -> Value in captured } as NativeCall0)
|
|
14
35
|
res.entries["body"] = .string("not-used")
|
|
15
36
|
if let extra = extra {
|
|
@@ -151,22 +172,22 @@ public final class TestFeature: BaseFeature {
|
|
|
151
172
|
if isNil(ent) {
|
|
152
173
|
let extra = VMap()
|
|
153
174
|
extra.entries["statusText"] = .string("Not found")
|
|
154
|
-
return testRespond(404, .noval, extra)
|
|
175
|
+
return testRespond(ctx2, 404, .noval, extra)
|
|
155
176
|
}
|
|
156
177
|
delprop(ent, .string("$KEY"))
|
|
157
|
-
return testRespond(200, clone(ent), nil)
|
|
178
|
+
return testRespond(ctx2, 200, clone(ent), nil)
|
|
158
179
|
} else if op.name == "list" {
|
|
159
180
|
let args = testBuildArgs(ctx2, op, ctx2.reqmatch)
|
|
160
181
|
let found = select(.map(entmap), args)
|
|
161
182
|
if isNil(found) {
|
|
162
183
|
let extra = VMap()
|
|
163
184
|
extra.entries["statusText"] = .string("Not found")
|
|
164
|
-
return testRespond(404, .noval, extra)
|
|
185
|
+
return testRespond(ctx2, 404, .noval, extra)
|
|
165
186
|
}
|
|
166
187
|
if let fl = found.asList {
|
|
167
188
|
for item in fl.items { delprop(item, .string("$KEY")) }
|
|
168
189
|
}
|
|
169
|
-
return testRespond(200, clone(found), nil)
|
|
190
|
+
return testRespond(ctx2, 200, clone(found), nil)
|
|
170
191
|
} else if op.name == "update" {
|
|
171
192
|
var updateMatch = VMap()
|
|
172
193
|
if let idv = ctx2.reqdata.entries["id"] {
|
|
@@ -188,13 +209,13 @@ public final class TestFeature: BaseFeature {
|
|
|
188
209
|
if isNil(ent) {
|
|
189
210
|
let extra = VMap()
|
|
190
211
|
extra.entries["statusText"] = .string("Not found")
|
|
191
|
-
return testRespond(404, .noval, extra)
|
|
212
|
+
return testRespond(ctx2, 404, .noval, extra)
|
|
192
213
|
}
|
|
193
214
|
if let entm = ent.asMap {
|
|
194
215
|
for (k, v) in ctx2.reqdata.entries { entm.entries[k] = v }
|
|
195
216
|
}
|
|
196
217
|
delprop(ent, .string("$KEY"))
|
|
197
|
-
return testRespond(200, clone(ent), nil)
|
|
218
|
+
return testRespond(ctx2, 200, clone(ent), nil)
|
|
198
219
|
} else if op.name == "remove" {
|
|
199
220
|
let args = testBuildArgs(ctx2, op, testResolveMatch(ctx2, ctx2.reqmatch))
|
|
200
221
|
let found = select(.map(entmap), args)
|
|
@@ -203,7 +224,7 @@ public final class TestFeature: BaseFeature {
|
|
|
203
224
|
let id = gp(entm2, "id")
|
|
204
225
|
delprop(.map(entmap), id)
|
|
205
226
|
}
|
|
206
|
-
return testRespond(200, .noval, nil)
|
|
227
|
+
return testRespond(ctx2, 200, .noval, nil)
|
|
207
228
|
} else if op.name == "create" {
|
|
208
229
|
_ = testBuildArgs(ctx2, op, ctx2.reqdata)
|
|
209
230
|
var id = ctx2.utility!.param(ctx2, .string("id"))
|
|
@@ -218,14 +239,14 @@ public final class TestFeature: BaseFeature {
|
|
|
218
239
|
entm.entries["id"] = id
|
|
219
240
|
if let idStr = id.asString { entmap.entries[idStr] = .map(entm) }
|
|
220
241
|
delprop(.map(entm), .string("$KEY"))
|
|
221
|
-
return testRespond(200, clone(.map(entm)), nil)
|
|
242
|
+
return testRespond(ctx2, 200, clone(.map(entm)), nil)
|
|
222
243
|
}
|
|
223
|
-
return testRespond(200, ent, nil)
|
|
244
|
+
return testRespond(ctx2, 200, ent, nil)
|
|
224
245
|
}
|
|
225
246
|
|
|
226
247
|
let extra = VMap()
|
|
227
248
|
extra.entries["statusText"] = .string("Unknown operation")
|
|
228
|
-
return testRespond(404, .noval, extra)
|
|
249
|
+
return testRespond(ctx2, 404, .noval, extra)
|
|
229
250
|
}
|
|
230
251
|
|
|
231
252
|
// Optional network behaviour simulation over the mock transport.
|
|
@@ -93,11 +93,38 @@ fn fixIds(_: Allocator, key: ?[]const u8, val: Value, _: Value, path: []const []
|
|
|
93
93
|
return val;
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
|
|
96
|
+
// THE MOCK HAS TO AGREE WITH THE MODEL.
|
|
97
|
+
//
|
|
98
|
+
// A point carrying `transform.res: `body.item`` describes an API that answers
|
|
99
|
+
// {"item": {...}}, and the response transform unwraps that key on the way
|
|
100
|
+
// back. Handing back the bare payload means the transform unwraps a property
|
|
101
|
+
// that is not there and the caller gets nothing — a mock that only ever
|
|
102
|
+
// simulates APIs whose responses happen to be unwrapped.
|
|
103
|
+
//
|
|
104
|
+
// univec's list op declares `body.data`, so every list returned zero items
|
|
105
|
+
// while the fixture plainly held two. Mirrors the go/ts/lua/php mocks, which
|
|
106
|
+
// already wrap; rust, c and zig were the three that did not.
|
|
107
|
+
fn envelope(ctx: *Context, data: Value) Value {
|
|
108
|
+
if (data == .undef or data == .null) return data;
|
|
109
|
+
const restf = h.getpath(&.{ "transform", "res" }, ctx.point);
|
|
110
|
+
if (restf != .string) return data;
|
|
111
|
+
const spec = restf.string;
|
|
112
|
+
// Exactly `body.<key>`; a deeper path is not an envelope this mock can
|
|
113
|
+
// synthesise, so it is left alone rather than guessed at.
|
|
114
|
+
if (spec.len < 8) return data;
|
|
115
|
+
if (!std.mem.startsWith(u8, spec, "`body.")) return data;
|
|
116
|
+
if (!std.mem.endsWith(u8, spec, "`")) return data;
|
|
117
|
+
const inner = spec[6 .. spec.len - 1];
|
|
118
|
+
if (inner.len == 0) return data;
|
|
119
|
+
if (std.mem.indexOfScalar(u8, inner, '.') != null) return data;
|
|
120
|
+
return h.jo(&.{.{ inner, data }});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
fn respond(ctx: *Context, status: i64, data: Value, extra: []const h.Pair) Value {
|
|
97
124
|
const out = h.jo(&.{
|
|
98
125
|
.{ "status", h.vnum(status) },
|
|
99
126
|
.{ "statusText", h.vstr("OK") },
|
|
100
|
-
.{ "json", h.json_thunk(data) },
|
|
127
|
+
.{ "json", h.json_thunk(envelope(ctx, data)) },
|
|
101
128
|
.{ "body", h.vstr("not-used") },
|
|
102
129
|
});
|
|
103
130
|
for (extra) |kv| h.setp(out, kv[0], kv[1]);
|
|
@@ -182,20 +209,20 @@ fn test_fetch(entity: Value, ctx: *Context, _: []const u8, _: Value) err.E!Value
|
|
|
182
209
|
const found = vs.select(h.A(), entmap, args) catch h.olist();
|
|
183
210
|
const ent = h.get_elem(found, h.vnum(0), h.vnull());
|
|
184
211
|
if (h.is_noval(ent)) {
|
|
185
|
-
return respond(404, h.vnull(), &.{.{ "statusText", h.vstr("Not found") }});
|
|
212
|
+
return respond(ctx, 404, h.vnull(), &.{.{ "statusText", h.vstr("Not found") }});
|
|
186
213
|
}
|
|
187
214
|
h.del_prop(ent, h.vstr("$KEY"));
|
|
188
|
-
return respond(200, h.clone(ent), &.{});
|
|
215
|
+
return respond(ctx, 200, h.clone(ent), &.{});
|
|
189
216
|
} else if (std.mem.eql(u8, op.name, "list")) {
|
|
190
217
|
const args = build_args(ctx, ctx.reqmatch);
|
|
191
218
|
const found = vs.select(h.A(), entmap, args) catch h.olist();
|
|
192
219
|
if (h.is_noval(found)) {
|
|
193
|
-
return respond(404, h.vnull(), &.{.{ "statusText", h.vstr("Not found") }});
|
|
220
|
+
return respond(ctx, 404, h.vnull(), &.{.{ "statusText", h.vstr("Not found") }});
|
|
194
221
|
}
|
|
195
222
|
if (found == .array) {
|
|
196
223
|
for (found.array.data.items) |item| h.del_prop(item, h.vstr("$KEY"));
|
|
197
224
|
}
|
|
198
|
-
return respond(200, h.clone(found), &.{});
|
|
225
|
+
return respond(ctx, 200, h.clone(found), &.{});
|
|
199
226
|
} else if (std.mem.eql(u8, op.name, "update")) {
|
|
200
227
|
const reqdata = ctx.reqdata;
|
|
201
228
|
var update_match = h.omap();
|
|
@@ -221,14 +248,14 @@ fn test_fetch(entity: Value, ctx: *Context, _: []const u8, _: Value) err.E!Value
|
|
|
221
248
|
}
|
|
222
249
|
}
|
|
223
250
|
if (h.is_noval(ent)) {
|
|
224
|
-
return respond(404, h.vnull(), &.{.{ "statusText", h.vstr("Not found") }});
|
|
251
|
+
return respond(ctx, 404, h.vnull(), &.{.{ "statusText", h.vstr("Not found") }});
|
|
225
252
|
}
|
|
226
253
|
if (ent == .object and reqdata == .object) {
|
|
227
254
|
var it = reqdata.object.iterator();
|
|
228
255
|
while (it.next()) |kv| h.setp(ent, kv.key_ptr.*, kv.value_ptr.*);
|
|
229
256
|
}
|
|
230
257
|
h.del_prop(ent, h.vstr("$KEY"));
|
|
231
|
-
return respond(200, h.clone(ent), &.{});
|
|
258
|
+
return respond(ctx, 200, h.clone(ent), &.{});
|
|
232
259
|
} else if (std.mem.eql(u8, op.name, "remove")) {
|
|
233
260
|
const m = resolve_match(ctx, ctx.reqmatch);
|
|
234
261
|
const args = build_args(ctx, m);
|
|
@@ -238,7 +265,7 @@ fn test_fetch(entity: Value, ctx: *Context, _: []const u8, _: Value) err.E!Value
|
|
|
238
265
|
const id = h.getp(ent, "id");
|
|
239
266
|
h.del_prop(entmap, id);
|
|
240
267
|
}
|
|
241
|
-
return respond(200, h.vnull(), &.{});
|
|
268
|
+
return respond(ctx, 200, h.vnull(), &.{});
|
|
242
269
|
} else if (std.mem.eql(u8, op.name, "create")) {
|
|
243
270
|
_ = build_args(ctx, ctx.reqdata);
|
|
244
271
|
var id = ctx.util().param(ctx, h.vstr("id"));
|
|
@@ -255,12 +282,12 @@ fn test_fetch(entity: Value, ctx: *Context, _: []const u8, _: Value) err.E!Value
|
|
|
255
282
|
h.setp(ent, "id", id);
|
|
256
283
|
if (id == .string) h.setp(entmap, id.string, ent);
|
|
257
284
|
h.del_prop(ent, h.vstr("$KEY"));
|
|
258
|
-
return respond(200, h.clone(ent), &.{});
|
|
285
|
+
return respond(ctx, 200, h.clone(ent), &.{});
|
|
259
286
|
}
|
|
260
|
-
return respond(200, ent, &.{});
|
|
287
|
+
return respond(ctx, 200, ent, &.{});
|
|
261
288
|
}
|
|
262
289
|
|
|
263
|
-
return respond(404, h.vnull(), &.{.{ "statusText", h.vstr("Unknown operation") }});
|
|
290
|
+
return respond(ctx, 404, h.vnull(), &.{.{ "statusText", h.vstr("Unknown operation") }});
|
|
264
291
|
}
|
|
265
292
|
|
|
266
293
|
// make_netsim (test-local): counter-driven latency / first-N failures /
|