@voxgig/sdkgen 2.0.0 → 2.0.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 +1 -1
- package/package.json +10 -9
- package/project/.sdk/src/cmp/cpp/TestEntity_cpp.ts +12 -2
- package/project/.sdk/src/cmp/dart/Config_dart.ts +6 -0
- package/project/.sdk/src/cmp/elixir/ReadmeTopQuick_elixir.ts +7 -4
- package/project/.sdk/src/cmp/lean/Test_lean.ts +75 -21
- package/project/.sdk/src/cmp/py/Test_py.ts +4 -1
- package/project/.sdk/tm/c/utility/graphql.c +1 -1
- package/project/.sdk/tm/kotlin/core/Utility.kt +2 -0
- package/project/.sdk/tm/lean/Makefile +25 -0
- package/project/.sdk/tm/lean/src/SdkUtility.lean +11 -9
- package/project/.sdk/tm/lean/test/TPrimaryUtility.lean +5 -2
package/bin/voxgig-sdkgen
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voxgig/sdkgen",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.2",
|
|
4
4
|
"main": "dist/sdkgen.js",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"engines": {
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"test": "node --enable-source-maps --test dist-test/**/*.test.js",
|
|
26
26
|
"test-some": "node --enable-source-maps --test-name-pattern=\"$npm_config_pattern\" --test dist-test/**/*.test.js",
|
|
27
27
|
"watch": "tsc --build src test -w",
|
|
28
|
-
"build": "tsc --build src test && npm run check-scaffold",
|
|
28
|
+
"build": "tsc --build src test && npm run check-scaffold && npm run stage-scaffold",
|
|
29
29
|
"clean": "rm -rf dist dist-test node_modules yarn.lock package-lock.json",
|
|
30
30
|
"reset": "npm run clean && npm i && npm run build && npm test",
|
|
31
31
|
"embed-version": "node build/version.js",
|
|
@@ -38,7 +38,8 @@
|
|
|
38
38
|
"repo-publish-quick-dry": "npm run build && npm run test && ( npm stage publish --dry-run --registry https://registry.npmjs.org --access=public || echo \"[dry-run] npm stage publish refused (see npm error above) - usually the version is already published; bump package.json before a real release\" )",
|
|
39
39
|
"repo-release": "npm run repo-publish && npm run repo-tag",
|
|
40
40
|
"repo-release-dry": "npm run repo-publish-quick-dry && npm run repo-tag-dry",
|
|
41
|
-
"check-scaffold": "tsc -p tsconfig.scaffold.json"
|
|
41
|
+
"check-scaffold": "tsc -p tsconfig.scaffold.json",
|
|
42
|
+
"stage-scaffold": "node build/scaffold-stage.js && tsc -p tsconfig.scaffold-emit.json"
|
|
42
43
|
},
|
|
43
44
|
"license": "MIT",
|
|
44
45
|
"files": [
|
|
@@ -59,12 +60,12 @@
|
|
|
59
60
|
},
|
|
60
61
|
"peerDependencies": {
|
|
61
62
|
"@tabnas/jsonic": "0.6.0",
|
|
62
|
-
"@voxgig/apidef": ">=
|
|
63
|
-
"@voxgig/struct": ">=0
|
|
64
|
-
"@voxgig/util": ">=0
|
|
65
|
-
"aontu": ">=0
|
|
66
|
-
"jostraca": ">=0
|
|
67
|
-
"shape": ">=
|
|
63
|
+
"@voxgig/apidef": ">=0",
|
|
64
|
+
"@voxgig/struct": ">=0",
|
|
65
|
+
"@voxgig/util": ">=0",
|
|
66
|
+
"aontu": ">=0",
|
|
67
|
+
"jostraca": ">=0",
|
|
68
|
+
"shape": ">=0",
|
|
68
69
|
"@tabnas/parser": "0.8.0"
|
|
69
70
|
}
|
|
70
71
|
}
|
|
@@ -148,6 +148,14 @@ static void ${evar}_entity_instance() {
|
|
|
148
148
|
ASSERT_EQ(ent->getName(), std::string("${entity.name}"), "entity name");
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
+
`)
|
|
152
|
+
|
|
153
|
+
// The stream test drives the list op; only emit it when the entity has a
|
|
154
|
+
// list op (a create/load-only entity has no list endpoint, so
|
|
155
|
+
// stream("list") throws "Operation \"list\" has no endpoint definitions").
|
|
156
|
+
const flowHasList = allSteps.some((s: any) => 'list' === s.op)
|
|
157
|
+
if (flowHasList) {
|
|
158
|
+
Content(`
|
|
151
159
|
static void ${evar}_entity_stream() {
|
|
152
160
|
// stream() runs the list op through the full pipeline and returns the
|
|
153
161
|
// result items. Seed two entities via test mode; with the streaming feature
|
|
@@ -169,7 +177,10 @@ static void ${evar}_entity_stream() {
|
|
|
169
177
|
std::vector<Value> pitems = pe->stream("list", Value::undef(), Value::undef());
|
|
170
178
|
ASSERT_EQ((int)pitems.size(), 2, "fallback stream yields both items");
|
|
171
179
|
}
|
|
180
|
+
`)
|
|
181
|
+
}
|
|
172
182
|
|
|
183
|
+
Content(`
|
|
173
184
|
static void ${evar}_entity_basic() {
|
|
174
185
|
auto setup = ${evar}_basic_setup(Value::undef());
|
|
175
186
|
std::string mode = setup.live ? "live" : "unit";
|
|
@@ -212,8 +223,7 @@ static void ${evar}_entity_basic() {
|
|
|
212
223
|
|
|
213
224
|
int main() {
|
|
214
225
|
T_RUN(${evar}_entity_instance);
|
|
215
|
-
T_RUN(${evar}_entity_stream);
|
|
216
|
-
T_RUN(${evar}_entity_basic);
|
|
226
|
+
${flowHasList ? ` T_RUN(${evar}_entity_stream);\n` : ''} T_RUN(${evar}_entity_basic);
|
|
217
227
|
return sdktest::summary("${entity.name}_entity_test");
|
|
218
228
|
}
|
|
219
229
|
`)
|
|
@@ -58,6 +58,12 @@ const Config = cmp(async function Config(props: any) {
|
|
|
58
58
|
|
|
59
59
|
replace: {
|
|
60
60
|
|
|
61
|
+
// Config.fragment.dart carries `'name': 'ProjectName'` — without the
|
|
62
|
+
// standard replacements the generated SDK reports "ProjectName" as its
|
|
63
|
+
// own name at runtime. Every sibling dart component already spreads
|
|
64
|
+
// these; this one did not.
|
|
65
|
+
...ctx$.stdrep,
|
|
66
|
+
|
|
61
67
|
"'AUTHBLOCK'": authBlock,
|
|
62
68
|
|
|
63
69
|
"'HEADERS'": dartValue(headers, 2),
|
|
@@ -55,14 +55,17 @@ IO.inspect(records)
|
|
|
55
55
|
.filter((it: any) => !it.optional || it.name === idF)
|
|
56
56
|
.sort((a: any, b: any) =>
|
|
57
57
|
(a.name === idF ? 0 : 1) - (b.name === idF ? 0 : 1))
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
// No required match keys (a singleton endpoint like /current) means no
|
|
59
|
+
// second argument at all — `load(ent, )` is a syntax error, and
|
|
60
|
+
// reqmatch defaults to nil, so load/1 is the correct call.
|
|
61
|
+
const loadArgs = 0 < loadItems.length
|
|
62
|
+
? `${eVar}, H.deep(%{${loadItems.map((it: any) =>
|
|
60
63
|
`"${it.name}" => ${elixirLit(it.type,
|
|
61
64
|
it.name === idF ? 'example_id' : 'example_' + it.name)}`).join(', ')}})`
|
|
62
|
-
:
|
|
65
|
+
: eVar
|
|
63
66
|
Content(`
|
|
64
67
|
# Load a specific ${eName.toLowerCase()} (returns the record, raises on error)
|
|
65
|
-
record = ${Name}.Entity.${eName}.load(${
|
|
68
|
+
record = ${Name}.Entity.${eName}.load(${loadArgs})
|
|
66
69
|
IO.inspect(record)
|
|
67
70
|
`)
|
|
68
71
|
}
|
|
@@ -26,6 +26,21 @@ function hasParamFreePoint(op: any): boolean {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
|
|
29
|
+
// True when an op selects a single record by path params — i.e. loading it by
|
|
30
|
+
// id is meaningful. A load whose every point is param-free is a singleton
|
|
31
|
+
// endpoint (`/current`): passing it an id matches no point at all, and the
|
|
32
|
+
// runtime raises `has no matching endpoint`.
|
|
33
|
+
function selectsByParams(op: any): boolean {
|
|
34
|
+
if (null == op) return false
|
|
35
|
+
const points = op.points || []
|
|
36
|
+
for (const pt of points) {
|
|
37
|
+
const params = ((pt.args || {}).params) || []
|
|
38
|
+
if (0 < params.length) return true
|
|
39
|
+
}
|
|
40
|
+
return false
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
|
|
29
44
|
// Synthesize a create payload from the entity's required non-id fields.
|
|
30
45
|
function synthData(fields: any): any {
|
|
31
46
|
const o: any = {}
|
|
@@ -64,30 +79,44 @@ const Test = cmp(async function Test(props: any) {
|
|
|
64
79
|
const Name = e.Name || (e.name.charAt(0).toUpperCase() + e.name.slice(1))
|
|
65
80
|
const ops = e.op || {}
|
|
66
81
|
if (!ops.list && !ops.load) return
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
-- list returns every seeded entity
|
|
82
|
+
|
|
83
|
+
// Only call the ops the entity actually declares. `Entity.create` is not
|
|
84
|
+
// generated for a load-only entity, so emitting the create/remove block
|
|
85
|
+
// unconditionally fails the build with "Unknown identifier X.create".
|
|
86
|
+
// Value's constructors are spelled out (`Value.list`, not `.list`) — the
|
|
87
|
+
// expected type is not known at the match scrutinee, and Lean reports the
|
|
88
|
+
// dotted form as ambiguous against Std's own `.list`.
|
|
89
|
+
let body = ''
|
|
90
|
+
|
|
91
|
+
if (ops.list) {
|
|
92
|
+
body += ` -- list returns every seeded entity
|
|
78
93
|
let items ← ${ns}.list tclient (← emptyMap) (← emptyMap)
|
|
79
|
-
let n ← (match items with | .list lid => do pure (← listItems lid).size | _ => pure 0)
|
|
94
|
+
let n ← (match items with | Value.list lid => do pure (← listItems lid).size | _ => pure 0)
|
|
80
95
|
if n == ids.size then pass s!"${e.name}.list offline -> {n} seeded"
|
|
81
96
|
else fail s!"${e.name}.list offline: got {n}, want {ids.size}"
|
|
82
|
-
|
|
97
|
+
`
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (ops.load && selectsByParams(ops.load)) {
|
|
101
|
+
body += ` -- load the first seeded entity by id
|
|
83
102
|
if ids.size > 0 then do
|
|
84
103
|
let wid := ids[0]!
|
|
85
|
-
let m ← newMap #[("id", .str wid)]
|
|
104
|
+
let m ← newMap #[("id", Value.str wid)]
|
|
86
105
|
let got ← ${ns}.load tclient m (← emptyMap)
|
|
87
106
|
let gid ← SdkRuntime.gpS got "id"
|
|
88
107
|
if gid == wid then pass s!"${e.name}.load offline (id={wid})"
|
|
89
108
|
else fail s!"${e.name}.load offline: got {gid}, want {wid}"
|
|
90
|
-
|
|
109
|
+
`
|
|
110
|
+
}
|
|
111
|
+
// A singleton load (`/current`, `/slack`) is deliberately NOT asserted
|
|
112
|
+
// here. The offline lane answers from a store keyed by entity id, so a
|
|
113
|
+
// load carrying no id has nothing to look up — the only honest assertion
|
|
114
|
+
// would need the model-driven match data the other targets build in their
|
|
115
|
+
// TestEntity components. Until this lane is model-driven too, such an
|
|
116
|
+
// entity contributes no offline block rather than a misleading one.
|
|
117
|
+
|
|
118
|
+
if (ops.create && ops.load && ops.remove) {
|
|
119
|
+
body += ` -- create -> load back -> remove, all in the store
|
|
91
120
|
let newmap ← SdkRuntime.gp (← SdkRuntime.gp seed "new") "${e.name}"
|
|
92
121
|
let nks ← keysof newmap
|
|
93
122
|
if nks.size > 0 then do
|
|
@@ -95,7 +124,7 @@ const Test = cmp(async function Test(props: any) {
|
|
|
95
124
|
let created ← ${ns}.create tclient payload (← emptyMap)
|
|
96
125
|
let cid ← SdkRuntime.gpS created "id"
|
|
97
126
|
if cid == "" then fail "${e.name}.create offline returned no id" else do
|
|
98
|
-
let m2 ← newMap #[("id", .str cid)]
|
|
127
|
+
let m2 ← newMap #[("id", Value.str cid)]
|
|
99
128
|
let back ← ${ns}.load tclient m2 (← emptyMap)
|
|
100
129
|
if (← SdkRuntime.gpS back "id") == cid then
|
|
101
130
|
pass s!"${e.name}.create/load offline (id={cid})"
|
|
@@ -103,8 +132,26 @@ const Test = cmp(async function Test(props: any) {
|
|
|
103
132
|
let _ ← ${ns}.remove tclient m2 (← emptyMap)
|
|
104
133
|
let gone ← ${ns}.load tclient m2 (← emptyMap)
|
|
105
134
|
match gone with
|
|
106
|
-
| .map _ => fail s!"${e.name}.remove offline: still present"
|
|
107
|
-
| _ => pass s!"${e.name}.remove offline (id={cid})"
|
|
135
|
+
| Value.map _ => fail s!"${e.name}.remove offline: still present"
|
|
136
|
+
| _ => pass s!"${e.name}.remove offline (id={cid})"
|
|
137
|
+
`
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Nothing to assert (an entity whose only op needs path params we cannot
|
|
141
|
+
// synthesise) — skip the block rather than emit an empty `do`.
|
|
142
|
+
if ('' === body) return
|
|
143
|
+
|
|
144
|
+
offline += ` -- ${e.name}: offline (test-mode) entity behaviour
|
|
145
|
+
(do
|
|
146
|
+
let seedPath := "../.sdk/test/entity/${e.name}/${Name}TestData.json"
|
|
147
|
+
if !(← System.FilePath.pathExists seedPath) then
|
|
148
|
+
IO.println s!"skip - ${e.name}: no seed at {seedPath}"
|
|
149
|
+
else do
|
|
150
|
+
let seed ← SdkJson.jsonRead (← IO.FS.readFile seedPath)
|
|
151
|
+
let tclient ← Sdk.testSdk0 seed
|
|
152
|
+
let existing ← SdkRuntime.gp (← SdkRuntime.gp seed "existing") "${e.name}"
|
|
153
|
+
let ids ← keysof existing
|
|
154
|
+
${body})
|
|
108
155
|
`
|
|
109
156
|
})
|
|
110
157
|
|
|
@@ -121,7 +168,7 @@ const Test = cmp(async function Test(props: any) {
|
|
|
121
168
|
(do
|
|
122
169
|
let items ← ${ns}.list client (← emptyMap) (← emptyMap)
|
|
123
170
|
match items with
|
|
124
|
-
| .list lid => pass s!"${e.name}.list -> {(← listItems lid).size} items"
|
|
171
|
+
| Value.list lid => pass s!"${e.name}.list -> {(← listItems lid).size} items"
|
|
125
172
|
| _ => fail "${e.name}.list did not return a list")
|
|
126
173
|
`
|
|
127
174
|
}
|
|
@@ -151,6 +198,13 @@ const Test = cmp(async function Test(props: any) {
|
|
|
151
198
|
// The live lane nests two levels deeper than the offline lane.
|
|
152
199
|
const liveBlocks = blocks.split('\n').map((l) => l ? ' ' + l : l).join('\n')
|
|
153
200
|
|
|
201
|
+
// A `do` block whose last statement is a `let` is a type error in Lean
|
|
202
|
+
// ("the rest of the do block has monadic result type"), and an entirely
|
|
203
|
+
// empty one does not parse at all. An API whose entities offer no op these
|
|
204
|
+
// lanes can drive leaves both empty, so terminate them explicitly.
|
|
205
|
+
const offlineBody = '' === offline ? ' pure ()\n' : offline
|
|
206
|
+
const liveBody = '' === blocks ? ' pure ()\n' : liveBlocks
|
|
207
|
+
|
|
154
208
|
Folder({ name: 'test' }, () => {
|
|
155
209
|
File({ name: 'Runner.' + target.ext }, () => {
|
|
156
210
|
Content(`-- ${model.const.Name} SDK test runner (generated by @voxgig/sdkgen).
|
|
@@ -183,14 +237,14 @@ def main : IO UInt32 := do
|
|
|
183
237
|
let liveBase ← IO.getEnv "SDK_TEST_BASE"
|
|
184
238
|
let ctx ← mkCtx
|
|
185
239
|
let offline : SIO Unit := do
|
|
186
|
-
${
|
|
240
|
+
${offlineBody} offline.run ctx
|
|
187
241
|
match liveBase with
|
|
188
242
|
| none => IO.println "skip - live lane (set SDK_TEST_BASE to enable)"
|
|
189
243
|
| some base => do
|
|
190
244
|
let live : SIO Unit := do
|
|
191
245
|
let opts ← newMap #[("base", .str base)]
|
|
192
246
|
let client ← Sdk.newSdk opts
|
|
193
|
-
${
|
|
247
|
+
${liveBody} live.run ctx
|
|
194
248
|
let p ← npass.get
|
|
195
249
|
let f ← nfail.get
|
|
196
250
|
IO.println ""
|
|
@@ -29,7 +29,10 @@ const Test = cmp(function Test(props: any) {
|
|
|
29
29
|
|
|
30
30
|
// Generate exists test
|
|
31
31
|
File({ name: 'test_exists.' + target.ext }, () => {
|
|
32
|
-
|
|
32
|
+
// The header names the SDK like every other line here — a literal
|
|
33
|
+
// `ProjectName` is the raw placeholder, not a substituted value: Content
|
|
34
|
+
// does not apply the standard replacements.
|
|
35
|
+
Content(`# ${model.const.Name} SDK exists test
|
|
33
36
|
|
|
34
37
|
import pytest
|
|
35
38
|
from ${model.const.Name.toLowerCase()}_sdk import ${model.const.Name}SDK
|
|
@@ -72,7 +72,7 @@ const char* graphql_error_code(voxgig_value* gqlerr) {
|
|
|
72
72
|
// generated create/update call look exactly like its REST equivalent.
|
|
73
73
|
voxgig_value* graphql_body_util(Context* ctx) {
|
|
74
74
|
voxgig_value* gql = getp(ctx->point, "graphql");
|
|
75
|
-
if (!voxgig_is_map(gql)) return
|
|
75
|
+
if (!voxgig_is_map(gql)) return voxgig_new_undef();
|
|
76
76
|
|
|
77
77
|
// reqmatch/reqdata hold the caller's arguments for THIS call; data/match
|
|
78
78
|
// hold the entity's current state. Which pair depends on whether the op
|
|
@@ -82,6 +82,8 @@ class Utility private constructor(register: Boolean) {
|
|
|
82
82
|
u.prepareParams = this.prepareParams
|
|
83
83
|
u.preparePath = this.preparePath
|
|
84
84
|
u.prepareQuery = this.prepareQuery
|
|
85
|
+
u.graphqlBody = this.graphqlBody
|
|
86
|
+
u.graphqlErrors = this.graphqlErrors
|
|
85
87
|
u.resultBasic = this.resultBasic
|
|
86
88
|
u.resultBody = this.resultBody
|
|
87
89
|
u.resultHeaders = this.resultHeaders
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
.PHONY: test build lint clean corpus
|
|
2
|
+
|
|
3
|
+
# Build every lean_lib and lean_exe declared in lakefile.toml.
|
|
4
|
+
build:
|
|
5
|
+
lake build
|
|
6
|
+
|
|
7
|
+
# Run the four generated test executables. `runner` drives the SDK pipeline
|
|
8
|
+
# and the generated entity/direct tests, `feature` the feature suite,
|
|
9
|
+
# `primary` the shared primary-utility corpus, and `structcorpus` the
|
|
10
|
+
# vendored voxgig/struct corpus. Any one exiting non-zero fails the target.
|
|
11
|
+
test:
|
|
12
|
+
lake exe runner
|
|
13
|
+
lake exe feature
|
|
14
|
+
lake exe primary
|
|
15
|
+
lake exe structcorpus
|
|
16
|
+
|
|
17
|
+
corpus:
|
|
18
|
+
lake exe structcorpus
|
|
19
|
+
|
|
20
|
+
# "Lint": a clean build means the code type-checks.
|
|
21
|
+
lint:
|
|
22
|
+
lake build
|
|
23
|
+
|
|
24
|
+
clean:
|
|
25
|
+
rm -rf .lake
|
|
@@ -231,13 +231,13 @@ def prepareQuery (ctx : Value) : SIO Value := do
|
|
|
231
231
|
if !(isNov v) && !(names.contains k) then sp out k v
|
|
232
232
|
pure out
|
|
233
233
|
|
|
234
|
+
/-- Assemble the path template from `point.parts`. This is `struct.join` with
|
|
235
|
+
the url flag — NOT a plain intercalate: empty segments are dropped (a doubled
|
|
236
|
+
slash changes the URL and 404s on strict routers) and there is no leading
|
|
237
|
+
slash, because makeUrl joins base/prefix/path/suffix with `joinurl`. -/
|
|
234
238
|
def preparePath (ctx : Value) : SIO String := do
|
|
235
239
|
let point ← gp ctx "point"
|
|
236
|
-
|
|
237
|
-
| .list i => do
|
|
238
|
-
let segs := (← listItems i).map vs
|
|
239
|
-
pure ("/" ++ String.intercalate "/" segs.toList)
|
|
240
|
-
| _ => pure ""
|
|
240
|
+
join (← gp point "parts") (sep := .str "/") (url := true)
|
|
241
241
|
|
|
242
242
|
/-- The API definition is authoritative: a POST-only or PATCH-based API
|
|
243
243
|
exposes `update` as POST or PATCH, not the PUT the op name implies. Only
|
|
@@ -396,9 +396,11 @@ def graphqlBody (ctx : Value) : SIO Value := do
|
|
|
396
396
|
match spec with
|
|
397
397
|
| .map _ => do
|
|
398
398
|
let name ← gpS spec "name"
|
|
399
|
-
|
|
399
|
+
-- `from` is a Lean keyword, so the binding cannot take the field's
|
|
400
|
+
-- own name.
|
|
401
|
+
let varFrom ← gpS spec "from"
|
|
400
402
|
if name != "" then
|
|
401
|
-
if
|
|
403
|
+
if varFrom == "" then do
|
|
402
404
|
-- The input object IS the request body. Strip the action
|
|
403
405
|
-- selector, which is an SDK-side point discriminator, not an API
|
|
404
406
|
-- field.
|
|
@@ -409,8 +411,8 @@ def graphqlBody (ctx : Value) : SIO Value := do
|
|
|
409
411
|
else do
|
|
410
412
|
-- Only send variables the caller actually supplied: sending an
|
|
411
413
|
-- explicit null would clear a field on many APIs.
|
|
412
|
-
let v0 ← gp reqsrc
|
|
413
|
-
let v ← if isNullish v0 then gp datasrc
|
|
414
|
+
let v0 ← gp reqsrc varFrom
|
|
415
|
+
let v ← if isNullish v0 then gp datasrc varFrom else pure v0
|
|
414
416
|
if !(isNullish v) then sp variables name v
|
|
415
417
|
| _ => pure ()
|
|
416
418
|
newMap #[("query", ← gp gql "doc"), ("variables", variables)]
|
|
@@ -306,9 +306,12 @@ def main : IO UInt32 := do
|
|
|
306
306
|
-- The remaining corpus sections. They carry no cases in this project's
|
|
307
307
|
-- corpus, but are driven here so any future fixture runs against Lean too.
|
|
308
308
|
|
|
309
|
+
-- clean takes (ctx, val), so the fixture supplies `args`, not `in` —
|
|
310
|
+
-- same shape as param/makeError above.
|
|
309
311
|
runset "clean" (← getSpec primary #["clean", "basic"]) fun entry => do
|
|
310
|
-
let
|
|
311
|
-
|
|
312
|
+
let args ← SdkUtility.gp entry "args"
|
|
313
|
+
let ctx ← mapCtx entry (← argAt args 0) opts config
|
|
314
|
+
pure ((← SdkUtility.clean ctx (← argAt args 1)), none)
|
|
312
315
|
|
|
313
316
|
runset "makeResult" (← getSpec primary #["makeResult", "basic"]) fun entry => do
|
|
314
317
|
pure ((← SdkUtility.makeResult (← entryCtx entry opts config)), none)
|