@voxgig/sdkgen 4.30.3 → 4.31.1
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/dist/action/package.d.ts +2 -1
- package/dist/action/package.js +8 -1
- package/dist/action/package.js.map +1 -1
- package/dist/cmp/ReadmeTop.js +6 -5
- package/dist/cmp/ReadmeTop.js.map +1 -1
- package/dist/helpers/definitionPlan.d.ts +27 -0
- package/dist/helpers/definitionPlan.js +219 -0
- package/dist/helpers/definitionPlan.js.map +1 -0
- package/dist/sdkgen.d.ts +2 -1
- package/dist/sdkgen.js +5 -3
- package/dist/sdkgen.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/project/.sdk/src/cmp/c/PrepareAuth_c.ts +5 -3
- package/project/.sdk/src/cmp/clojure/PrepareAuth_clojure.ts +7 -5
- package/project/.sdk/src/cmp/cpp/PrepareAuth_cpp.ts +5 -3
- package/project/.sdk/src/cmp/csharp/PrepareAuth_csharp.ts +6 -4
- package/project/.sdk/src/cmp/elixir/PrepareAuth_elixir.ts +8 -6
- package/project/.sdk/src/cmp/go/PrepareAuth_go.ts +7 -9
- package/project/.sdk/src/cmp/java/PrepareAuth_java.ts +5 -3
- package/project/.sdk/src/cmp/js/PrepareAuth_js.ts +6 -4
- package/project/.sdk/src/cmp/js/ReadmeInstall_js.ts +22 -5
- package/project/.sdk/src/cmp/js/TestDefinition_js.ts +40 -0
- package/project/.sdk/src/cmp/js/Test_js.ts +2 -0
- package/project/.sdk/src/cmp/kotlin/PrepareAuth_kotlin.ts +5 -3
- package/project/.sdk/src/cmp/lua/PrepareAuth_lua.ts +7 -3
- package/project/.sdk/src/cmp/ocaml/PrepareAuth_ocaml.ts +7 -5
- package/project/.sdk/src/cmp/perl/PrepareAuth_perl.ts +6 -3
- package/project/.sdk/src/cmp/php/PrepareAuth_php.ts +5 -3
- package/project/.sdk/src/cmp/php/ReadmeInstall_php.ts +11 -5
- package/project/.sdk/src/cmp/py/PrepareAuth_py.ts +5 -3
- package/project/.sdk/src/cmp/rb/PrepareAuth_rb.ts +5 -3
- package/project/.sdk/src/cmp/rb/ReadmeInstall_rb.ts +14 -4
- package/project/.sdk/src/cmp/rust/PrepareAuth_rust.ts +5 -3
- package/project/.sdk/src/cmp/scala/PrepareAuth_scala.ts +5 -3
- package/project/.sdk/src/cmp/swift/PrepareAuth_swift.ts +5 -3
- package/project/.sdk/src/cmp/ts/PrepareAuth_ts.ts +6 -4
- package/project/.sdk/src/cmp/ts/ReadmeInstall_ts.ts +10 -4
- package/project/.sdk/src/cmp/ts/TestDefinition_ts.ts +40 -0
- package/project/.sdk/src/cmp/ts/Test_ts.ts +2 -0
- package/project/.sdk/src/cmp/zig/PrepareAuth_zig.ts +5 -3
- package/project/.sdk/tm/c/utility/prepare_query.c +34 -2
- package/project/.sdk/tm/clojure/src/sdk/core.clj +20 -2
- package/project/.sdk/tm/cpp/utility/pipeline.hpp +31 -2
- package/project/.sdk/tm/csharp/utility/PrepareQuery.cs +32 -4
- package/project/.sdk/tm/elixir/lib/projectname/utility.ex +35 -1
- package/project/.sdk/tm/go/utility/prepare_query.go +31 -1
- package/project/.sdk/tm/java/utility/PrepareQuery.java +29 -5
- package/project/.sdk/tm/js/src/utility/PrepareQueryUtility.js +16 -2
- package/project/.sdk/tm/js/test/definition-runner.js +161 -0
- package/project/.sdk/tm/js/test/pipeline.test.js +43 -3
- package/project/.sdk/tm/js/test/sdk-test-control.json +4 -1
- package/project/.sdk/tm/kotlin/utility/Prepare.kt +29 -5
- package/project/.sdk/tm/lua/utility/prepare_query.lua +31 -2
- package/project/.sdk/tm/ocaml/sdk_runtime.ml +22 -1
- package/project/.sdk/tm/perl/utility/prepare_query.pm +25 -2
- package/project/.sdk/tm/php/utility/PrepareQuery.php +28 -1
- package/project/.sdk/tm/py/pkg/utility/prepare_query.py +23 -2
- package/project/.sdk/tm/rb/utility/prepare_query.rb +24 -2
- package/project/.sdk/tm/rust/utility/prepare_query.rs +34 -2
- package/project/.sdk/tm/scala/utility/Prepare.scala +31 -4
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/Prepare.swift +23 -5
- package/project/.sdk/tm/ts/src/utility/PrepareQueryUtility.ts +16 -2
- package/project/.sdk/tm/ts/test/definition-runner.ts +179 -0
- package/project/.sdk/tm/ts/test/pipeline.test.ts +43 -3
- package/project/.sdk/tm/ts/test/sdk-test-control.json +4 -1
- package/project/.sdk/tm/ts/test/utility.ts +3 -2
- package/project/.sdk/tm/zig/core/utility.zig +29 -1
- package/project/sdkgen-package.json +1 -1
- package/src/action/package.ts +10 -1
- package/src/cmp/ReadmeTop.ts +7 -6
- package/src/helpers/definitionPlan.ts +265 -0
- package/src/sdkgen.ts +2 -0
|
@@ -148,9 +148,11 @@ function basicBlock(spec: AuthSpec): string {
|
|
|
148
148
|
if (!spec.basic) return ''
|
|
149
149
|
|
|
150
150
|
return `
|
|
151
|
-
// True HTTP Basic Auth
|
|
151
|
+
// True HTTP Basic Auth joins the two credentials, base64-encoded - a single
|
|
152
152
|
// token in the header (the branch below) can never authenticate against
|
|
153
153
|
// an API that actually checks \`Authorization: Basic base64(user:pass)\`.
|
|
154
|
+
// The password may be empty (RFC 7617): Lob, for one, documents the key as
|
|
155
|
+
// the user with a blank password (\`curl -u key:\`).
|
|
154
156
|
if true == gpath(options, "auth", "basic").asBool {
|
|
155
157
|
let secret = getprop(.map(options), .string(optionSecret), .string(notFound))
|
|
156
158
|
|
|
@@ -159,12 +161,12 @@ function basicBlock(spec: AuthSpec): string {
|
|
|
159
161
|
noSecret = true
|
|
160
162
|
}
|
|
161
163
|
|
|
162
|
-
if skip
|
|
164
|
+
if skip {
|
|
163
165
|
headers.entries.removeValue(forKey: headerAuth)
|
|
164
166
|
} else {
|
|
165
167
|
var authPrefix = ""
|
|
166
168
|
if let ap = gpath(options, "auth", "prefix").asString { authPrefix = ap }
|
|
167
|
-
let joined = (apikey.asString ?? "") + ":" + (secret.asString ?? "")
|
|
169
|
+
let joined = (apikey.asString ?? "") + ":" + (noSecret ? "" : (secret.asString ?? ""))
|
|
168
170
|
let b64 = Data(joined.utf8).base64EncodedString()
|
|
169
171
|
// Empty prefix (raw credential) must not add a leading space.
|
|
170
172
|
headers.entries[headerAuth] = .string(authPrefix == "" ? b64 : authPrefix + " " + b64)
|
|
@@ -108,19 +108,21 @@ ${cookieHelper(spec.where)}
|
|
|
108
108
|
// query parameter or a cookie, so the branch is emitted only where it
|
|
109
109
|
// can mean something.
|
|
110
110
|
const basicBlock = (spec.basic && 'header' === spec.where) ? `
|
|
111
|
-
// True HTTP Basic Auth
|
|
111
|
+
// True HTTP Basic Auth joins the two credentials, base64-encoded - a single
|
|
112
112
|
// token in the header (the branch below) can never authenticate against
|
|
113
113
|
// an API that actually checks \`Authorization: Basic base64(user:pass)\`.
|
|
114
|
+
// The password may be empty (RFC 7617): Lob, for one, documents the key as
|
|
115
|
+
// the user with a blank password (\`curl -u key:\`).
|
|
114
116
|
if (true === options.auth.basic) {
|
|
115
117
|
const secret = getprop(options, OPTION_secret, NOTFOUND)
|
|
116
118
|
const noApikey = NOTFOUND === apikey || null == apikey || '' === apikey
|
|
117
|
-
const
|
|
119
|
+
const pass = NOTFOUND === secret || null == secret ? '' : secret
|
|
118
120
|
|
|
119
|
-
if (noApikey
|
|
121
|
+
if (noApikey) {
|
|
120
122
|
delprop(headers, CRED_name)
|
|
121
123
|
}
|
|
122
124
|
else {
|
|
123
|
-
const b64 = Buffer.from(apikey + ':' +
|
|
125
|
+
const b64 = Buffer.from(apikey + ':' + pass).toString('base64')
|
|
124
126
|
setprop(headers, CRED_name, prefix ? prefix + ' ' + b64 : b64)
|
|
125
127
|
}
|
|
126
128
|
|
|
@@ -16,12 +16,18 @@ ${installCommand(model, target.name)}
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
// Publish pending: the package is not yet on npm, so install from the
|
|
19
|
-
// git release tag instead of a `npm install` that would 404.
|
|
20
|
-
|
|
19
|
+
// git release tag instead of a `npm install` that would 404. A repository
|
|
20
|
+
// may have no tag at all, and npm cannot install a subdirectory of a git
|
|
21
|
+
// URL, so a clone is always offered too. It carries the compiled dist/.
|
|
22
|
+
const { releasesUrl, repoUrl, repo } = repoInfo(model)
|
|
21
23
|
Content(`This package is not yet published to npm. Install it from the GitHub
|
|
22
|
-
release tag (\`${target.name}/vX.Y.Z
|
|
24
|
+
release tag (\`${target.name}/vX.Y.Z\`, see [Releases](${releasesUrl})), or from a
|
|
25
|
+
clone, which carries the compiled \`dist/\`:
|
|
23
26
|
|
|
24
|
-
|
|
27
|
+
\`\`\`bash
|
|
28
|
+
git clone ${repoUrl}
|
|
29
|
+
npm install ./${repo}/${target.name}
|
|
30
|
+
\`\`\`
|
|
25
31
|
|
|
26
32
|
`)
|
|
27
33
|
})
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { cmp, File, Content, definitionPlan } from '@voxgig/sdkgen'
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
// Every operation checked against the API definition, offline, in the SDK's
|
|
5
|
+
// own suite: see test/definition-runner.
|
|
6
|
+
const TestDefinition = cmp(function TestDefinition(props: any) {
|
|
7
|
+
const plan = definitionPlan(props.ctx$)
|
|
8
|
+
if (0 === plan.length) return
|
|
9
|
+
|
|
10
|
+
File({ name: 'definition.test.ts' }, () => Content(`import { describe, test } from 'node:test'
|
|
11
|
+
import { SDK } from '..'
|
|
12
|
+
import { runDefinitionPoint } from './definition-runner'
|
|
13
|
+
import { isControlSkipped } from './utility'
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
// Generated from the API definition, not from the model this SDK was built
|
|
17
|
+
// from: the route, the declared query parameters, the credential the security
|
|
18
|
+
// scheme names, and the definition's own response example.
|
|
19
|
+
const PLAN: any[] = ${JSON.stringify(plan, null, 2)}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
describe('definition', () => {
|
|
23
|
+
for (const point of PLAN) {
|
|
24
|
+
test(point.entity + '.' + point.op + ' ' + point.method + ' ' + point.path, async (t) => {
|
|
25
|
+
const control = isControlSkipped('entityOp', point.entity + '.' + point.op, 'definition')
|
|
26
|
+
if (control.skip) {
|
|
27
|
+
t.skip(control.reason || 'skipped via sdk-test-control.json')
|
|
28
|
+
return
|
|
29
|
+
}
|
|
30
|
+
await runDefinitionPoint(SDK, point)
|
|
31
|
+
})
|
|
32
|
+
}
|
|
33
|
+
})
|
|
34
|
+
`))
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
export {
|
|
39
|
+
TestDefinition
|
|
40
|
+
}
|
|
@@ -8,6 +8,7 @@ import { cmp, each, Folder, entityCollection,
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
import { TestLive } from './TestLive_ts'
|
|
11
|
+
import { TestDefinition } from './TestDefinition_ts'
|
|
11
12
|
import { TestDirect } from './TestDirect_ts'
|
|
12
13
|
import { TestEntity } from './TestEntity_ts'
|
|
13
14
|
import { ReadmeExampleTest } from './ReadmeExampleTest_ts'
|
|
@@ -23,6 +24,7 @@ const Test = cmp(function Test(props: any) {
|
|
|
23
24
|
// Write-once: a project's edited control file survives regeneration.
|
|
24
25
|
TestControl({ target, dir: 'test' })
|
|
25
26
|
TestLive({ target })
|
|
27
|
+
TestDefinition({ target })
|
|
26
28
|
|
|
27
29
|
ReadmeExampleTest({ target })
|
|
28
30
|
ReadmeExamplesTest({ target })
|
|
@@ -330,9 +330,11 @@ fn base64_std(text: []const u8) []const u8 {
|
|
|
330
330
|
// something — and only when the model says the scheme IS basic.
|
|
331
331
|
function basicBlock(): string {
|
|
332
332
|
return `
|
|
333
|
-
// True HTTP Basic Auth
|
|
333
|
+
// True HTTP Basic Auth joins the two credentials, base64-encoded - a single
|
|
334
334
|
// token in the header (the branch below) can never authenticate against
|
|
335
335
|
// an API that actually checks \`Authorization: Basic base64(user:pass)\`.
|
|
336
|
+
// The password may be empty (RFC 7617): Lob, for one, documents the key as
|
|
337
|
+
// the user with a blank password (\`curl -u key:\`).
|
|
336
338
|
if (is_true(h.getpath(&.{ "auth", "basic" }, options))) {
|
|
337
339
|
const secret = vs.getprop(h.A(), options, h.vstr(OPTION_SECRET), h.vstr(NOT_FOUND)) catch h.vstr(NOT_FOUND);
|
|
338
340
|
|
|
@@ -342,7 +344,7 @@ function basicBlock(): string {
|
|
|
342
344
|
else => false,
|
|
343
345
|
};
|
|
344
346
|
|
|
345
|
-
if (skip
|
|
347
|
+
if (skip) {
|
|
346
348
|
h.del_prop(headers, h.vstr(CRED_NAME));
|
|
347
349
|
} else {
|
|
348
350
|
const basic_prefix: []const u8 = switch (h.getpath(&.{ "auth", "prefix" }, options)) {
|
|
@@ -353,7 +355,7 @@ function basicBlock(): string {
|
|
|
353
355
|
.string => |s| s,
|
|
354
356
|
else => "",
|
|
355
357
|
};
|
|
356
|
-
const secret_val: []const u8 = switch (secret) {
|
|
358
|
+
const secret_val: []const u8 = if (no_secret) "" else switch (secret) {
|
|
357
359
|
.string => |s| s,
|
|
358
360
|
else => "",
|
|
359
361
|
};
|
|
@@ -15,12 +15,44 @@ static bool params_contains(voxgig_value* params, const char* key) {
|
|
|
15
15
|
return false;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
// A path parameter travels in the path. The generated config lists them as
|
|
19
|
+
// args.params, which prepare_params reads; params is the older list of names.
|
|
20
|
+
static bool args_params_contains(voxgig_value* aparams, const char* key) {
|
|
21
|
+
if (voxgig_is_list(aparams)) {
|
|
22
|
+
voxgig_list* pl = voxgig_as_list(aparams);
|
|
23
|
+
for (size_t i = 0; i < pl->len; i++) {
|
|
24
|
+
voxgig_value* name = getp(pl->items[i], "name");
|
|
25
|
+
if (voxgig_is_string(name) && strcmp(voxgig_as_string(name), key) == 0) return true;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// A query parameter travels under the name the definition gives it, its orig,
|
|
32
|
+
// which the model may have renamed for the caller.
|
|
33
|
+
static const char* query_wire_name(voxgig_value* aquery, const char* key) {
|
|
34
|
+
if (voxgig_is_list(aquery)) {
|
|
35
|
+
voxgig_list* ql = voxgig_as_list(aquery);
|
|
36
|
+
for (size_t i = 0; i < ql->len; i++) {
|
|
37
|
+
voxgig_value* name = getp(ql->items[i], "name");
|
|
38
|
+
voxgig_value* orig = getp(ql->items[i], "orig");
|
|
39
|
+
if (voxgig_is_string(name) && voxgig_is_string(orig) &&
|
|
40
|
+
strcmp(voxgig_as_string(name), key) == 0 && voxgig_as_string(orig)[0] != '\0') {
|
|
41
|
+
return voxgig_as_string(orig);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return key;
|
|
46
|
+
}
|
|
47
|
+
|
|
18
48
|
voxgig_value* prepare_query_util(Context* ctx) {
|
|
19
49
|
voxgig_value* point = ctx->point;
|
|
20
50
|
voxgig_value* reqmatch = voxgig_is_map(ctx->reqmatch) ? ctx->reqmatch : voxgig_new_map();
|
|
21
51
|
|
|
22
52
|
voxgig_value* params = getp(point, "params");
|
|
23
53
|
if (!voxgig_is_list(params)) params = voxgig_new_list();
|
|
54
|
+
voxgig_value* aparams = getpath2(point, "args", "params");
|
|
55
|
+
voxgig_value* aquery = getpath2(point, "args", "query");
|
|
24
56
|
|
|
25
57
|
voxgig_value* out = voxgig_new_map();
|
|
26
58
|
if (voxgig_is_map(reqmatch)) {
|
|
@@ -29,8 +61,8 @@ voxgig_value* prepare_query_util(Context* ctx) {
|
|
|
29
61
|
const char* key = rm->entries[i].key;
|
|
30
62
|
voxgig_value* val = rm->entries[i].value;
|
|
31
63
|
if (!v_is_noval(val) && !v_is_null(val) && strcmp(key, "$action") != 0 &&
|
|
32
|
-
!params_contains(params, key)) {
|
|
33
|
-
setp(out, key, v_share(val));
|
|
64
|
+
!params_contains(params, key) && !args_params_contains(aparams, key)) {
|
|
65
|
+
setp(out, query_wire_name(aquery, key), v_share(val));
|
|
34
66
|
}
|
|
35
67
|
}
|
|
36
68
|
}
|
|
@@ -500,12 +500,30 @@
|
|
|
500
500
|
(let [point (oget ctx :point)
|
|
501
501
|
reqmatch (or (oget ctx :reqmatch) (vs/jm))
|
|
502
502
|
params (let [p (when point (vs/getprop point "params"))] (if (vs/islist p) p (vs/jt)))
|
|
503
|
-
|
|
503
|
+
;; A path parameter travels in the path. The generated config lists
|
|
504
|
+
;; them as args.params, which u-prepare-params reads; params is the
|
|
505
|
+
;; older list of names.
|
|
506
|
+
aparams (let [args (when point (vs/getprop point "args"))
|
|
507
|
+
p (when (vs/ismap args) (vs/getprop args "params"))]
|
|
508
|
+
(if (vs/islist p) p (vs/jt)))
|
|
509
|
+
pset (into (into #{} (vec params))
|
|
510
|
+
(keep (fn [pd] (when (vs/ismap pd) (vs/getprop pd "name"))) (vec aparams)))
|
|
511
|
+
;; A query parameter travels under the name the definition gives it,
|
|
512
|
+
;; its orig, which the model may have renamed for the caller.
|
|
513
|
+
aquery (let [args (when point (vs/getprop point "args"))
|
|
514
|
+
q (when (vs/ismap args) (vs/getprop args "query"))]
|
|
515
|
+
(if (vs/islist q) q (vs/jt)))
|
|
516
|
+
wire (into {}
|
|
517
|
+
(keep (fn [qd]
|
|
518
|
+
(when (vs/ismap qd)
|
|
519
|
+
(let [n (vs/getprop qd "name") o (vs/getprop qd "orig")]
|
|
520
|
+
(when (and (string? n) (string? o) (not= "" o)) [n o]))))
|
|
521
|
+
(vec aquery)))
|
|
504
522
|
out (vs/jm)]
|
|
505
523
|
(doseq [item (or (vs/items reqmatch) [])]
|
|
506
524
|
(let [k (vs/getprop item 0) v (vs/getprop item 1)]
|
|
507
525
|
(when (and (some? v) (string? k) (not= "$action" k) (not (contains? pset k)))
|
|
508
|
-
(.put ^java.util.Map out k v))))
|
|
526
|
+
(.put ^java.util.Map out (get wire k k) v))))
|
|
509
527
|
out))
|
|
510
528
|
|
|
511
529
|
;; `$action` selects the point (see u-make-point); it is never an API field,
|
|
@@ -1022,12 +1022,41 @@ inline Value prepareQuery(CtxPtr ctx) {
|
|
|
1022
1022
|
return false;
|
|
1023
1023
|
};
|
|
1024
1024
|
|
|
1025
|
+
// A path parameter travels in the path. The generated config lists them as
|
|
1026
|
+
// args.params, which prepareParams reads; params is the older list of names.
|
|
1027
|
+
Value aparams = point.is_map() ? getp(getp(point, "args"), "params") : Value::undef();
|
|
1028
|
+
auto in_args = [&](const std::string& s) {
|
|
1029
|
+
if (!aparams.is_list()) return false;
|
|
1030
|
+
for (const auto& pd : *aparams.as_list()) {
|
|
1031
|
+
Value name = getp(pd, "name");
|
|
1032
|
+
if (name.is_string() && name.as_string() == s) return true;
|
|
1033
|
+
}
|
|
1034
|
+
return false;
|
|
1035
|
+
};
|
|
1036
|
+
|
|
1037
|
+
// A query parameter travels under the name the definition gives it, its
|
|
1038
|
+
// orig, which the model may have renamed for the caller.
|
|
1039
|
+
Value aquery = point.is_map() ? getp(getp(point, "args"), "query") : Value::undef();
|
|
1040
|
+
auto wire_name = [&](const std::string& s) {
|
|
1041
|
+
if (aquery.is_list()) {
|
|
1042
|
+
for (const auto& qd : *aquery.as_list()) {
|
|
1043
|
+
Value name = getp(qd, "name");
|
|
1044
|
+
Value orig = getp(qd, "orig");
|
|
1045
|
+
if (name.is_string() && orig.is_string() && name.as_string() == s &&
|
|
1046
|
+
!orig.as_string().empty()) {
|
|
1047
|
+
return orig.as_string();
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
return s;
|
|
1052
|
+
};
|
|
1053
|
+
|
|
1025
1054
|
Value out = vmap();
|
|
1026
1055
|
for (const auto& item : Struct::items(reqmatch)) {
|
|
1027
1056
|
std::string key = as_str(pair_key(item));
|
|
1028
1057
|
Value val = pair_val(item);
|
|
1029
|
-
if (!is_nullish(val) && "$action" != key && !contains_str(params, key)) {
|
|
1030
|
-
map_put(out, key, val);
|
|
1058
|
+
if (!is_nullish(val) && "$action" != key && !contains_str(params, key) && !in_args(key)) {
|
|
1059
|
+
map_put(out, wire_name(key), val);
|
|
1031
1060
|
}
|
|
1032
1061
|
}
|
|
1033
1062
|
return out;
|
|
@@ -12,12 +12,40 @@ public static partial class SdkUtility
|
|
|
12
12
|
var point = ctx.Point;
|
|
13
13
|
var reqmatch = ctx.Reqmatch ?? new Dictionary<string, object?>();
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
var paramnames = new List<object?>();
|
|
16
16
|
if (point != null && StructUtils.GetProp(point, "params") is List<object?> pl)
|
|
17
17
|
{
|
|
18
|
-
paramnames
|
|
18
|
+
paramnames.AddRange(pl);
|
|
19
|
+
}
|
|
20
|
+
// A path parameter travels in the path. The generated config lists them
|
|
21
|
+
// as args.params, which PrepareParams reads; params is the older list.
|
|
22
|
+
if (point != null &&
|
|
23
|
+
StructUtils.GetPath(point, StructUtils.Jt("args", "params")) is List<object?> apl)
|
|
24
|
+
{
|
|
25
|
+
foreach (var pd in apl)
|
|
26
|
+
{
|
|
27
|
+
if (StructUtils.GetProp(pd, "name") is string name)
|
|
28
|
+
{
|
|
29
|
+
paramnames.Add(name);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// A query parameter travels under the name the definition gives it,
|
|
35
|
+
// its orig, which the model may have renamed for the caller.
|
|
36
|
+
var wire = new Dictionary<string, string>();
|
|
37
|
+
if (point != null &&
|
|
38
|
+
StructUtils.GetPath(point, StructUtils.Jt("args", "query")) is List<object?> aql)
|
|
39
|
+
{
|
|
40
|
+
foreach (var qd in aql)
|
|
41
|
+
{
|
|
42
|
+
if (StructUtils.GetProp(qd, "name") is string qname &&
|
|
43
|
+
StructUtils.GetProp(qd, "orig") is string qorig && qorig != "")
|
|
44
|
+
{
|
|
45
|
+
wire[qname] = qorig;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
19
48
|
}
|
|
20
|
-
paramnames ??= new List<object?>();
|
|
21
49
|
|
|
22
50
|
var query = new Dictionary<string, object?>();
|
|
23
51
|
foreach (var item in StructUtils.Items(reqmatch))
|
|
@@ -26,7 +54,7 @@ public static partial class SdkUtility
|
|
|
26
54
|
var val = item[1];
|
|
27
55
|
if (val != null && "$action" != key && !ContainsStr(paramnames, key))
|
|
28
56
|
{
|
|
29
|
-
query[key] = val;
|
|
57
|
+
query[wire.TryGetValue(key, out var wkey) ? wkey : key] = val;
|
|
30
58
|
}
|
|
31
59
|
}
|
|
32
60
|
|
|
@@ -1206,12 +1206,46 @@ defmodule ProjectName.Utility do
|
|
|
1206
1206
|
Enum.map(0..(S.size(params) - 1), fn i -> S.getelem(params, i) end)
|
|
1207
1207
|
end
|
|
1208
1208
|
|
|
1209
|
+
# A path parameter travels in the path. The generated config lists them
|
|
1210
|
+
# as args.params, which prepare_params reads; params is the older list.
|
|
1211
|
+
aparams = if point != nil, do: S.getpath(point, "args.params"), else: nil
|
|
1212
|
+
|
|
1213
|
+
arg_strs =
|
|
1214
|
+
if S.islist(aparams) and S.size(aparams) > 0 do
|
|
1215
|
+
Enum.map(0..(S.size(aparams) - 1), fn i ->
|
|
1216
|
+
S.getprop(S.getelem(aparams, i), "name")
|
|
1217
|
+
end)
|
|
1218
|
+
else
|
|
1219
|
+
[]
|
|
1220
|
+
end
|
|
1221
|
+
|
|
1222
|
+
param_strs = param_strs ++ arg_strs
|
|
1223
|
+
|
|
1224
|
+
# A query parameter travels under the name the definition gives it, its
|
|
1225
|
+
# orig, which the model may have renamed for the caller.
|
|
1226
|
+
aquery = if point != nil, do: S.getpath(point, "args.query"), else: nil
|
|
1227
|
+
|
|
1228
|
+
wire =
|
|
1229
|
+
if S.islist(aquery) and S.size(aquery) > 0 do
|
|
1230
|
+
Enum.reduce(0..(S.size(aquery) - 1), %{}, fn i, acc ->
|
|
1231
|
+
qd = S.getelem(aquery, i)
|
|
1232
|
+
name = S.getprop(qd, "name")
|
|
1233
|
+
orig = S.getprop(qd, "orig")
|
|
1234
|
+
|
|
1235
|
+
if is_binary(name) and is_binary(orig) and orig != "",
|
|
1236
|
+
do: Map.put(acc, name, orig),
|
|
1237
|
+
else: acc
|
|
1238
|
+
end)
|
|
1239
|
+
else
|
|
1240
|
+
%{}
|
|
1241
|
+
end
|
|
1242
|
+
|
|
1209
1243
|
out = S.jm([])
|
|
1210
1244
|
|
|
1211
1245
|
Enum.each(H.entries(reqmatch), fn {key, val} ->
|
|
1212
1246
|
if val != nil and is_binary(key) and key != "$action" and
|
|
1213
1247
|
not Enum.member?(param_strs, key) do
|
|
1214
|
-
S.setprop(out, key, val)
|
|
1248
|
+
S.setprop(out, Map.get(wire, key, key), val)
|
|
1215
1249
|
end
|
|
1216
1250
|
end)
|
|
1217
1251
|
|
|
@@ -17,7 +17,7 @@ func prepareQueryUtil(ctx *core.Context) map[string]any {
|
|
|
17
17
|
if point != nil {
|
|
18
18
|
if p := vs.GetProp(point, "params"); p != nil {
|
|
19
19
|
if pl, ok := p.([]any); ok {
|
|
20
|
-
params = pl
|
|
20
|
+
params = append([]any{}, pl...)
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
}
|
|
@@ -25,11 +25,41 @@ func prepareQueryUtil(ctx *core.Context) map[string]any {
|
|
|
25
25
|
params = []any{}
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
// A path parameter travels in the path. The generated config lists them as
|
|
29
|
+
// args.params, which prepareParams reads; params is the older list of names.
|
|
30
|
+
if point != nil {
|
|
31
|
+
if pl, ok := vs.GetPath(point, []any{"args", "params"}).([]any); ok {
|
|
32
|
+
for _, pd := range pl {
|
|
33
|
+
if name, ok := vs.GetProp(pd, "name").(string); ok {
|
|
34
|
+
params = append(params, name)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// A query parameter travels under the name the definition gives it, its
|
|
41
|
+
// orig, which the model may have renamed for the caller.
|
|
42
|
+
wire := map[string]string{}
|
|
43
|
+
if point != nil {
|
|
44
|
+
if ql, ok := vs.GetPath(point, []any{"args", "query"}).([]any); ok {
|
|
45
|
+
for _, qd := range ql {
|
|
46
|
+
name, _ := vs.GetProp(qd, "name").(string)
|
|
47
|
+
orig, _ := vs.GetProp(qd, "orig").(string)
|
|
48
|
+
if "" != name && "" != orig {
|
|
49
|
+
wire[name] = orig
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
28
55
|
out := map[string]any{}
|
|
29
56
|
for _, item := range vs.Items(reqmatch) {
|
|
30
57
|
key, _ := item[0].(string)
|
|
31
58
|
val := item[1]
|
|
32
59
|
if val != nil && key != "$action" && !containsStr(params, key) {
|
|
60
|
+
if orig, ok := wire[key]; ok {
|
|
61
|
+
key = orig
|
|
62
|
+
}
|
|
33
63
|
out[key] = val
|
|
34
64
|
}
|
|
35
65
|
}
|
|
@@ -20,15 +20,39 @@ final class PrepareQuery {
|
|
|
20
20
|
reqmatch = new LinkedHashMap<>();
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
List<Object> params =
|
|
23
|
+
List<Object> params = new ArrayList<>();
|
|
24
24
|
if (point != null) {
|
|
25
25
|
Object p = Struct.getprop(point, "params");
|
|
26
26
|
if (p instanceof List) {
|
|
27
|
-
params
|
|
27
|
+
params.addAll((List<Object>) p);
|
|
28
|
+
}
|
|
29
|
+
// A path parameter travels in the path. The generated config lists them
|
|
30
|
+
// as args.params, which prepareParams reads; params is the older list.
|
|
31
|
+
Object pl = Struct.getpath(point, List.of("args", "params"));
|
|
32
|
+
if (pl instanceof List) {
|
|
33
|
+
for (Object pd : (List<Object>) pl) {
|
|
34
|
+
Object name = Struct.getprop(pd, "name");
|
|
35
|
+
if (name instanceof String) {
|
|
36
|
+
params.add(name);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
28
39
|
}
|
|
29
40
|
}
|
|
30
|
-
|
|
31
|
-
|
|
41
|
+
|
|
42
|
+
// A query parameter travels under the name the definition gives it, its
|
|
43
|
+
// orig, which the model may have renamed for the caller.
|
|
44
|
+
Map<String, String> wire = new LinkedHashMap<>();
|
|
45
|
+
if (point != null) {
|
|
46
|
+
Object ql = Struct.getpath(point, List.of("args", "query"));
|
|
47
|
+
if (ql instanceof List) {
|
|
48
|
+
for (Object qd : (List<Object>) ql) {
|
|
49
|
+
Object name = Struct.getprop(qd, "name");
|
|
50
|
+
Object orig = Struct.getprop(qd, "orig");
|
|
51
|
+
if (name instanceof String && orig instanceof String && !((String) orig).isEmpty()) {
|
|
52
|
+
wire.put((String) name, (String) orig);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
32
56
|
}
|
|
33
57
|
|
|
34
58
|
Map<String, Object> out = new LinkedHashMap<>();
|
|
@@ -36,7 +60,7 @@ final class PrepareQuery {
|
|
|
36
60
|
String key = item.get(0) instanceof String ? (String) item.get(0) : "";
|
|
37
61
|
Object val = item.get(1);
|
|
38
62
|
if (val != null && !"$action".equals(key) && !containsStr(params, key)) {
|
|
39
|
-
out.put(key, val);
|
|
63
|
+
out.put(wire.getOrDefault(key, key), val);
|
|
40
64
|
}
|
|
41
65
|
}
|
|
42
66
|
|
|
@@ -11,10 +11,24 @@ function prepareQuery(ctx) {
|
|
|
11
11
|
params = params || []
|
|
12
12
|
reqmatch = reqmatch || {}
|
|
13
13
|
|
|
14
|
+
// A path parameter travels in the path. The generated config lists them as
|
|
15
|
+
// args.params, which prepareParams reads; params is the older list of names.
|
|
16
|
+
const inpath = params.concat(
|
|
17
|
+
((point.args && point.args.params) || []).map((p) => p && p.name))
|
|
18
|
+
|
|
19
|
+
// A query parameter travels under the name the definition gives it, its
|
|
20
|
+
// orig, which the model may have renamed for the caller.
|
|
21
|
+
const wire = Object.create(null)
|
|
22
|
+
for (const q of ((point.args && point.args.query) || [])) {
|
|
23
|
+
if (q && 'string' === typeof q.name && 'string' === typeof q.orig && '' !== q.orig) {
|
|
24
|
+
wire[q.name] = q.orig
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
14
28
|
const out = {}
|
|
15
29
|
for (let [key, val] of items(reqmatch)) {
|
|
16
|
-
if (null != val && '$action' !== key && !
|
|
17
|
-
out[key] = val
|
|
30
|
+
if (null != val && '$action' !== key && !inpath.includes(key)) {
|
|
31
|
+
out[null == wire[key] ? key : wire[key]] = val
|
|
18
32
|
}
|
|
19
33
|
}
|
|
20
34
|
|