@voxgig/sdkgen 4.5.3 → 4.7.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/dist/action/check.js +15 -0
- package/dist/action/check.js.map +1 -1
- package/dist/cmp/AgentGuide.js +1 -1
- package/dist/cmp/AgentGuide.js.map +1 -1
- package/dist/cmp/AgentGuideContent.d.ts +1 -1
- package/dist/cmp/AgentGuideContent.js +8 -2
- package/dist/cmp/AgentGuideContent.js.map +1 -1
- package/dist/cmp/Feature.js +22 -0
- package/dist/cmp/Feature.js.map +1 -1
- package/dist/cmp/FeatureDocs.d.ts +1 -1
- package/dist/cmp/FeatureDocs.js +6 -1
- package/dist/cmp/FeatureDocs.js.map +1 -1
- package/dist/cmp/ReadmeExplanation.js +3 -1
- package/dist/cmp/ReadmeExplanation.js.map +1 -1
- package/dist/cmp/ReadmeFeatures.js +1 -1
- package/dist/cmp/ReadmeFeatures.js.map +1 -1
- package/dist/cmp/ReadmeRefFeatures.js +1 -1
- package/dist/cmp/ReadmeRefFeatures.js.map +1 -1
- package/dist/cmp/TestControl.d.ts +4 -0
- package/dist/cmp/TestControl.js +51 -0
- package/dist/cmp/TestControl.js.map +1 -0
- package/dist/helpers/applicability.d.ts +6 -0
- package/dist/helpers/applicability.js +103 -0
- package/dist/helpers/applicability.js.map +1 -0
- package/dist/helpers/collectDeps.js +4 -2
- package/dist/helpers/collectDeps.js.map +1 -1
- package/dist/helpers/featureSource.d.ts +3 -1
- package/dist/helpers/featureSource.js +105 -0
- package/dist/helpers/featureSource.js.map +1 -1
- package/dist/helpers/serverVars.d.ts +2 -1
- package/dist/helpers/serverVars.js +17 -0
- package/dist/helpers/serverVars.js.map +1 -1
- package/dist/sdkgen.d.ts +5 -3
- package/dist/sdkgen.js +16 -4
- package/dist/sdkgen.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utility.d.ts +2 -1
- package/dist/utility.js +59 -1
- package/dist/utility.js.map +1 -1
- package/model/sdkgen.aon +97 -0
- package/package.json +1 -1
- package/project/.sdk/model/feature/feature-index.aon +1 -0
- package/project/.sdk/model/feature/secrets.aon +200 -0
- package/project/.sdk/model/target/ts.aon +8 -1
- package/project/.sdk/src/cmp/c/Config_c.ts +5 -1
- package/project/.sdk/src/cmp/cpp/Config_cpp.ts +5 -1
- package/project/.sdk/src/cmp/cpp/Main_cpp.ts +2 -1
- package/project/.sdk/src/cmp/cpp/Test_cpp.ts +5 -1
- package/project/.sdk/src/cmp/csharp/Config_csharp.ts +5 -1
- package/project/.sdk/src/cmp/csharp/Main_csharp.ts +2 -1
- package/project/.sdk/src/cmp/csharp/TestDirect_csharp.ts +30 -6
- package/project/.sdk/src/cmp/csharp/TestEntity_csharp.ts +29 -5
- package/project/.sdk/src/cmp/csharp/Test_csharp.ts +5 -1
- package/project/.sdk/src/cmp/dart/Config_dart.ts +5 -1
- package/project/.sdk/src/cmp/dart/Main_dart.ts +2 -1
- package/project/.sdk/src/cmp/dart/TestDirect_dart.ts +23 -6
- package/project/.sdk/src/cmp/dart/TestEntity_dart.ts +28 -7
- package/project/.sdk/src/cmp/dart/Test_dart.ts +5 -1
- package/project/.sdk/src/cmp/elixir/Config_elixir.ts +5 -1
- package/project/.sdk/src/cmp/elixir/Main_elixir.ts +5 -1
- package/project/.sdk/src/cmp/go/Config_go.ts +5 -1
- package/project/.sdk/src/cmp/go/Main_go.ts +8 -3
- package/project/.sdk/src/cmp/go/ReadmeQuick_go.ts +16 -3
- package/project/.sdk/src/cmp/go/ReadmeTopQuick_go.ts +16 -3
- package/project/.sdk/src/cmp/go/TestDirect_go.ts +28 -4
- package/project/.sdk/src/cmp/go/TestEntity_go.ts +43 -10
- package/project/.sdk/src/cmp/go/Test_go.ts +5 -1
- package/project/.sdk/src/cmp/go/fragment/Main.fragment.go +5 -5
- package/project/.sdk/src/cmp/java/Config_java.ts +22 -1
- package/project/.sdk/src/cmp/java/Main_java.ts +7 -2
- package/project/.sdk/src/cmp/java/ReadmeQuick_java.ts +17 -3
- package/project/.sdk/src/cmp/java/ReadmeTopQuick_java.ts +17 -3
- package/project/.sdk/src/cmp/java/TestDirect_java.ts +23 -4
- package/project/.sdk/src/cmp/java/TestEntity_java.ts +29 -4
- package/project/.sdk/src/cmp/java/Test_java.ts +5 -1
- package/project/.sdk/src/cmp/js/Config_js.ts +5 -1
- package/project/.sdk/src/cmp/js/Main_js.ts +7 -2
- package/project/.sdk/src/cmp/js/Package_js.ts +4 -1
- package/project/.sdk/src/cmp/js/TestDirect_js.ts +30 -5
- package/project/.sdk/src/cmp/js/TestEntity_js.ts +35 -5
- package/project/.sdk/src/cmp/js/Test_js.ts +5 -1
- package/project/.sdk/src/cmp/js/fragment/Direct.test.fragment.js +7 -1
- package/project/.sdk/src/cmp/js/fragment/Entity.test.fragment.js +7 -1
- package/project/.sdk/src/cmp/kotlin/Config_kotlin.ts +5 -1
- package/project/.sdk/src/cmp/kotlin/Main_kotlin.ts +2 -1
- package/project/.sdk/src/cmp/kotlin/Test_kotlin.ts +5 -1
- package/project/.sdk/src/cmp/lean/Config_lean.ts +5 -1
- package/project/.sdk/src/cmp/lua/Config_lua.ts +5 -1
- package/project/.sdk/src/cmp/lua/Main_lua.ts +7 -2
- package/project/.sdk/src/cmp/lua/Package_lua.ts +4 -1
- package/project/.sdk/src/cmp/lua/TestDirect_lua.ts +28 -4
- package/project/.sdk/src/cmp/lua/TestEntity_lua.ts +24 -4
- package/project/.sdk/src/cmp/lua/Test_lua.ts +5 -1
- package/project/.sdk/src/cmp/ocaml/Config_ocaml.ts +5 -1
- package/project/.sdk/src/cmp/ocaml/Gitignore_ocaml.ts +1 -0
- package/project/.sdk/src/cmp/perl/Main_perl.ts +7 -2
- package/project/.sdk/src/cmp/perl/TestDirect_perl.ts +25 -4
- package/project/.sdk/src/cmp/perl/TestEntity_perl.ts +24 -4
- package/project/.sdk/src/cmp/perl/Test_perl.ts +5 -1
- package/project/.sdk/src/cmp/perl/utility_perl.ts +10 -0
- package/project/.sdk/src/cmp/php/Config_php.ts +5 -1
- package/project/.sdk/src/cmp/php/Main_php.ts +7 -2
- package/project/.sdk/src/cmp/php/TestDirect_php.ts +24 -5
- package/project/.sdk/src/cmp/php/TestEntity_php.ts +28 -4
- package/project/.sdk/src/cmp/php/Test_php.ts +5 -1
- package/project/.sdk/src/cmp/py/Config_py.ts +5 -1
- package/project/.sdk/src/cmp/py/Main_py.ts +7 -2
- package/project/.sdk/src/cmp/py/ReadmeQuick_py.ts +16 -3
- package/project/.sdk/src/cmp/py/ReadmeTopQuick_py.ts +16 -3
- package/project/.sdk/src/cmp/py/TestDirect_py.ts +24 -5
- package/project/.sdk/src/cmp/py/TestEntity_py.ts +23 -3
- package/project/.sdk/src/cmp/py/Test_py.ts +5 -1
- package/project/.sdk/src/cmp/rb/Config_rb.ts +5 -1
- package/project/.sdk/src/cmp/rb/Main_rb.ts +7 -2
- package/project/.sdk/src/cmp/rb/TestDirect_rb.ts +24 -5
- package/project/.sdk/src/cmp/rb/TestEntity_rb.ts +24 -4
- package/project/.sdk/src/cmp/rb/Test_rb.ts +5 -1
- package/project/.sdk/src/cmp/rb/utility_rb.ts +3 -1
- package/project/.sdk/src/cmp/rust/Config_rust.ts +5 -1
- package/project/.sdk/src/cmp/rust/Main_rust.ts +7 -2
- package/project/.sdk/src/cmp/rust/TestDirect_rust.ts +31 -4
- package/project/.sdk/src/cmp/rust/TestEntity_rust.ts +37 -4
- package/project/.sdk/src/cmp/rust/Test_rust.ts +5 -1
- package/project/.sdk/src/cmp/scala/Config_scala.ts +5 -1
- package/project/.sdk/src/cmp/scala/Main_scala.ts +7 -2
- package/project/.sdk/src/cmp/scala/Test_scala.ts +5 -1
- package/project/.sdk/src/cmp/swift/Config_swift.ts +5 -1
- package/project/.sdk/src/cmp/ts/Config_ts.ts +55 -9
- package/project/.sdk/src/cmp/ts/Main_ts.ts +67 -3
- package/project/.sdk/src/cmp/ts/Package_ts.ts +4 -1
- package/project/.sdk/src/cmp/ts/ReadmeModel_ts.ts +15 -3
- package/project/.sdk/src/cmp/ts/ReadmeQuick_ts.ts +18 -5
- package/project/.sdk/src/cmp/ts/ReadmeTopQuick_ts.ts +19 -5
- package/project/.sdk/src/cmp/ts/TestDirect_ts.ts +75 -8
- package/project/.sdk/src/cmp/ts/TestEntity_ts.ts +36 -5
- package/project/.sdk/src/cmp/ts/Test_ts.ts +5 -1
- package/project/.sdk/src/cmp/ts/fragment/Direct.test.fragment.ts +9 -2
- package/project/.sdk/src/cmp/ts/fragment/Entity.test.fragment.ts +9 -2
- package/project/.sdk/src/cmp/ts/fragment/Main.fragment.ts +7 -0
- package/project/.sdk/src/cmp/zig/Config_zig.ts +5 -1
- package/project/.sdk/tm/c/utility/make_options.c +22 -0
- package/project/.sdk/tm/clojure/src/sdk/core.clj +18 -1
- package/project/.sdk/tm/cpp/utility/pipeline.hpp +23 -0
- package/project/.sdk/tm/csharp/test/CustomUtilityTest.cs +15 -0
- package/project/.sdk/tm/csharp/test/Runner.cs +45 -0
- package/project/.sdk/tm/csharp/utility/MakeOptions.cs +23 -0
- package/project/.sdk/tm/dart/lib/utility/MakeOptionsUtility.dart +22 -0
- package/project/.sdk/tm/dart/test/utility.dart +39 -0
- package/project/.sdk/tm/elixir/lib/projectname/utility.ex +19 -0
- package/project/.sdk/tm/go/core/context.go +1 -1
- package/project/.sdk/tm/go/feature/cost_feature.go +1 -1
- package/project/.sdk/tm/go/feature/paging_feature.go +5 -5
- package/project/.sdk/tm/go/feature/test_feature.go +12 -5
- package/project/.sdk/tm/go/test/custom_utility_test.go +15 -0
- package/project/.sdk/tm/go/test/feature_corpus_test.go +7 -0
- package/project/.sdk/tm/go/test/runner_test.go +46 -0
- package/project/.sdk/tm/go/test/struct_runner_test.go +7 -7
- package/project/.sdk/tm/go/test/struct_utility_test.go +63 -27
- package/project/.sdk/tm/go/utility/fetcher.go +2 -2
- package/project/.sdk/tm/go/utility/make_options.go +24 -5
- package/project/.sdk/tm/go/utility/make_point.go +1 -1
- package/project/.sdk/tm/go/utility/make_spec.go +17 -1
- package/project/.sdk/tm/go/utility/prepare_auth.go +1 -1
- package/project/.sdk/tm/go/utility/struct/voxgigstruct.go +370 -307
- package/project/.sdk/tm/go/utility/transform_request.go +29 -1
- package/project/.sdk/tm/go/utility/transform_response.go +20 -1
- package/project/.sdk/tm/java/test/CustomUtilityTest.java +10 -0
- package/project/.sdk/tm/java/test/FeatureCorpusTest.java +7 -0
- package/project/.sdk/tm/java/test/PrimaryUtilityTest.java +6 -0
- package/project/.sdk/tm/java/test/RunnerSupport.java +43 -0
- package/project/.sdk/tm/java/utility/MakeOptions.java +84 -1
- package/project/.sdk/tm/js/src/utility/MakeOptionsUtility.js +24 -0
- package/project/.sdk/tm/js/src/utility/StructUtility.js +2076 -1837
- package/project/.sdk/tm/js/test/feature/Corpus.test.js +9 -0
- package/project/.sdk/tm/js/test/sdk-test-control.json +19 -0
- package/project/.sdk/tm/js/test/utility.js +91 -1
- package/project/.sdk/tm/kotlin/utility/MakeOptions.kt +21 -0
- package/project/.sdk/tm/lean/src/SdkUtility.lean +12 -1
- package/project/.sdk/tm/lua/test/runner.lua +40 -0
- package/project/.sdk/tm/ocaml/sdk_runtime.ml +11 -0
- package/project/.sdk/tm/ocaml/test/harness.ml +14 -4
- package/project/.sdk/tm/perl/t/runner.pm +30 -0
- package/project/.sdk/tm/perl/utility/make_options.pm +18 -0
- package/project/.sdk/tm/php/test/FeatureCorpusTest.php +10 -1
- package/project/.sdk/tm/php/test/Runner.php +36 -0
- package/project/.sdk/tm/php/utility/MakeOptions.php +24 -0
- package/project/.sdk/tm/py/pkg/utility/make_options.py +20 -0
- package/project/.sdk/tm/py/test/runner.py +32 -0
- package/project/.sdk/tm/py/test/test_feature_corpus.py +10 -1
- package/project/.sdk/tm/rb/test/feature_corpus_test.rb +9 -1
- package/project/.sdk/tm/rb/test/runner.rb +25 -0
- package/project/.sdk/tm/rb/utility/make_options.rb +17 -0
- package/project/.sdk/tm/rust/tests/common/mod.rs +32 -0
- package/project/.sdk/tm/rust/utility/make_options.rs +26 -1
- package/project/.sdk/tm/scala/utility/Make.scala +17 -0
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/MakeOptions.swift +21 -0
- package/project/.sdk/tm/ts/src/feature/secrets/SecretsFeature.ts +419 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/Sekreto.ts +387 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/Sigv4.ts +175 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/index.ts +51 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/Registry.ts +90 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/addr.ts +48 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/aws.ts +219 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/azuresecrets.ts +144 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/boru.ts +113 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/doppler.ts +77 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/dotenv.ts +51 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/env.ts +31 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/file.ts +54 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/gcpsecrets.ts +118 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/hashicorp.ts +159 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/http.ts +66 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/infisical.ts +107 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/memory.ts +33 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/onepassword.ts +120 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/support.ts +176 -0
- package/project/.sdk/tm/ts/src/utility/MakeOptionsUtility.ts +18 -0
- package/project/.sdk/tm/ts/src/utility/StructUtility.ts +1321 -710
- package/project/.sdk/tm/ts/test/feature/Corpus.test.ts +9 -0
- package/project/.sdk/tm/ts/test/feature/secrets/Secrets.test.ts +764 -0
- package/project/.sdk/tm/ts/test/omni.test.ts +84 -0
- package/project/.sdk/tm/ts/test/omni.ts +86 -0
- package/project/.sdk/tm/ts/test/utility/PrimaryUtility.test.ts +6 -2
- package/project/.sdk/tm/ts/test/utility/StructUtility.test.ts +2 -2
- package/project/.sdk/tm/ts/test/utility.ts +122 -0
- package/project/.sdk/tm/ts/test/vendor/omni/Runner.ts +694 -0
- package/project/.sdk/tm/ts/test/vendor/omni/Util.ts +244 -0
- package/project/.sdk/tm/ts/test/vendor/omni/compat.ts +188 -0
- package/project/.sdk/tm/ts/test/vendor/omni/index.ts +38 -0
- package/project/.sdk/tm/zig/core/utility.zig +24 -1
- package/project/sdkgen-package.json +2 -1
- package/src/action/check.ts +18 -0
- package/src/cmp/AgentGuide.ts +1 -1
- package/src/cmp/AgentGuideContent.ts +9 -2
- package/src/cmp/Feature.ts +24 -0
- package/src/cmp/FeatureDocs.ts +7 -1
- package/src/cmp/ReadmeExplanation.ts +4 -1
- package/src/cmp/ReadmeFeatures.ts +1 -1
- package/src/cmp/ReadmeRefFeatures.ts +1 -1
- package/src/cmp/TestControl.ts +64 -0
- package/src/helpers/applicability.ts +123 -0
- package/src/helpers/collectDeps.ts +5 -1
- package/src/helpers/featureSource.ts +130 -0
- package/src/helpers/serverVars.ts +19 -0
- package/src/sdkgen.ts +16 -1
- package/src/utility.ts +71 -1
- package/project/.sdk/tm/ts/test/runner.ts +0 -425
|
@@ -143,6 +143,45 @@ bool skipIfMissingIds(T t, Map setup, List<String> requiredKeys) {
|
|
|
143
143
|
|
|
144
144
|
// Per-test live pacing delay (ms). Read from sdk-test-control.json
|
|
145
145
|
// `test.live.delayMs`; defaults to 500ms if absent or invalid.
|
|
146
|
+
// Extra SDK options every LIVE client is constructed with, read from
|
|
147
|
+
// sdk-test-control.json `test.client.options`.
|
|
148
|
+
//
|
|
149
|
+
// The generated live client knows two things: the base URL (from the spec)
|
|
150
|
+
// and the credential (from the environment). Everything else about how a
|
|
151
|
+
// particular API wants to be talked to - which features to switch on, and
|
|
152
|
+
// with what settings - is a property of THAT API, known to the project and
|
|
153
|
+
// to nothing in the toolchain.
|
|
154
|
+
//
|
|
155
|
+
// Merged UNDER the generated fields, so the suite's own base/apikey/server
|
|
156
|
+
// values win: this ADDS to the live client, it does not redirect it.
|
|
157
|
+
//
|
|
158
|
+
// Reserved fields are stripped HERE rather than at each merge site: the
|
|
159
|
+
// generated map only names a field when the model calls for one, so a
|
|
160
|
+
// 'base' in this block would face no competing value and would silently
|
|
161
|
+
// redirect the whole suite - credential included - to another host.
|
|
162
|
+
const List<String> liveReserved = [
|
|
163
|
+
'base', 'prefix', 'suffix', 'server', 'apikey', 'secret'
|
|
164
|
+
];
|
|
165
|
+
|
|
166
|
+
Map<String, dynamic> liveClientOptions() {
|
|
167
|
+
final ctrl = loadTestControl();
|
|
168
|
+
final t = ctrl['test'];
|
|
169
|
+
if (t is! Map) return <String, dynamic>{};
|
|
170
|
+
final c = t['client'];
|
|
171
|
+
if (c is! Map) return <String, dynamic>{};
|
|
172
|
+
final opts = c['options'];
|
|
173
|
+
if (opts is! Map) return <String, dynamic>{};
|
|
174
|
+
|
|
175
|
+
final out = <String, dynamic>{};
|
|
176
|
+
opts.forEach((k, v) {
|
|
177
|
+
if (!liveReserved.contains(k)) {
|
|
178
|
+
out['$k'] = v;
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
return out;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
|
|
146
185
|
int liveDelayMs() {
|
|
147
186
|
final ctrl = loadTestControl();
|
|
148
187
|
final t = ctrl['test'];
|
|
@@ -243,8 +243,24 @@ defmodule ProjectName.Utility do
|
|
|
243
243
|
end
|
|
244
244
|
end
|
|
245
245
|
|
|
246
|
+
# `auth` nil is the documented way to disable auth outright, and
|
|
247
|
+
# prepare_auth honours it before it ever reads the apikey. It cannot
|
|
248
|
+
# survive validate: a stored null reads as "no value", so the optspec's
|
|
249
|
+
# `auth` default fires and the suppression silently becomes "use default
|
|
250
|
+
# auth" - transmitting the credential the caller withheld. Withhold the
|
|
251
|
+
# key for validate, then put the nil back. Same fix as ts/js/go
|
|
252
|
+
# makeOptions.
|
|
253
|
+
#
|
|
254
|
+
# keysof rather than S.haskey: haskey is `getprop(...) != nil`, which
|
|
255
|
+
# collapses a stored null and so cannot tell an ABSENT auth from a
|
|
256
|
+
# suppressed one. keysof lists the key either way.
|
|
257
|
+
auth_suppressed =
|
|
258
|
+
S.ismap(options) and "auth" in S.keysof(options) and
|
|
259
|
+
S.getprop(options, "auth") == nil
|
|
260
|
+
|
|
246
261
|
opts0 = S.clone(options)
|
|
247
262
|
opts0 = if S.ismap(opts0), do: opts0, else: S.jm([])
|
|
263
|
+
if auth_suppressed, do: S.delprop(opts0, "auth")
|
|
248
264
|
|
|
249
265
|
# Feature add-order. options.feature may be given as an ordered LIST of
|
|
250
266
|
# {name, active, ...opts} entries (list position = add order) or a
|
|
@@ -329,6 +345,9 @@ defmodule ProjectName.Utility do
|
|
|
329
345
|
validated = S.validate(merged, optspec)
|
|
330
346
|
opts = if S.ismap(validated), do: validated, else: S.jm([])
|
|
331
347
|
|
|
348
|
+
# Restore the suppression the optspec default would otherwise erase.
|
|
349
|
+
if auth_suppressed, do: S.setprop(opts, "auth", nil)
|
|
350
|
+
|
|
332
351
|
# Resolve a templated base URL (e.g. https://{tenant_id}.hanko.io).
|
|
333
352
|
# Every placeholder must resolve to a non-empty value: from options.server
|
|
334
353
|
# (user), else the Config default. A placeholder that resolves to "" is a
|
|
@@ -245,7 +245,7 @@ func (ctx *Context) resolveOp(opname string) *Operation {
|
|
|
245
245
|
return NewOperation(map[string]any{})
|
|
246
246
|
}
|
|
247
247
|
|
|
248
|
-
opcfg := vs.GetPath([]any{"entity", entname, "op", opname}
|
|
248
|
+
opcfg := vs.GetPath(ctx.Config, []any{"entity", entname, "op", opname})
|
|
249
249
|
|
|
250
250
|
input := "match"
|
|
251
251
|
if opname == "update" || opname == "create" {
|
|
@@ -367,7 +367,7 @@ func (f *CostFeature) body(ctx *core.Context) (float64, bool) {
|
|
|
367
367
|
return 0, false
|
|
368
368
|
}
|
|
369
369
|
|
|
370
|
-
switch n := vs.GetPath(
|
|
370
|
+
switch n := vs.GetPath(ctx.Result.Body, path).(type) {
|
|
371
371
|
case int:
|
|
372
372
|
return float64(n) * f.perUnit(), true
|
|
373
373
|
case int64:
|
|
@@ -109,7 +109,7 @@ func (f *PagingFeature) graphqlPreRequest(ctx *core.Context, paging map[string]a
|
|
|
109
109
|
// Only bind variables the operation actually declares, or the server
|
|
110
110
|
// rejects the document.
|
|
111
111
|
declared := map[string]bool{}
|
|
112
|
-
if varlist, ok := vs.GetPath([]any{"graphql", "vars"}
|
|
112
|
+
if varlist, ok := vs.GetPath(ctx.Point, []any{"graphql", "vars"}).([]any); ok {
|
|
113
113
|
for _, v := range varlist {
|
|
114
114
|
if name, ok := vs.GetProp(v, "name").(string); ok {
|
|
115
115
|
declared[name] = true
|
|
@@ -160,7 +160,7 @@ func (f *PagingFeature) PreResult(ctx *core.Context) {
|
|
|
160
160
|
|
|
161
161
|
// Relay connections carry the cursor in pageInfo, at the path the model
|
|
162
162
|
// recorded for this op.
|
|
163
|
-
page := vs.GetPath([]any{"graphql", "page"}
|
|
163
|
+
page := vs.GetPath(ctx.Point, []any{"graphql", "page"})
|
|
164
164
|
if pm, ok := page.(map[string]any); ok {
|
|
165
165
|
if _, isMap := body.(map[string]any); isMap {
|
|
166
166
|
// `connpath` locates the connection object inside the response
|
|
@@ -168,18 +168,18 @@ func (f *PagingFeature) PreResult(ctx *core.Context) {
|
|
|
168
168
|
// to it.
|
|
169
169
|
conn := body
|
|
170
170
|
if cp, ok := pm["connpath"].(string); ok && cp != "" {
|
|
171
|
-
if sub := vs.GetPath(
|
|
171
|
+
if sub := vs.GetPath(body, cp); sub != nil {
|
|
172
172
|
conn = sub
|
|
173
173
|
}
|
|
174
174
|
}
|
|
175
175
|
|
|
176
176
|
if cp, ok := pm["cursor"].(string); ok && cp != "" {
|
|
177
|
-
if cursor := vs.GetPath(
|
|
177
|
+
if cursor := vs.GetPath(conn, cp); cursor != nil {
|
|
178
178
|
paging["cursor"] = cursor
|
|
179
179
|
}
|
|
180
180
|
}
|
|
181
181
|
if mp, ok := pm["more"].(string); ok && mp != "" {
|
|
182
|
-
if more, ok := vs.GetPath(
|
|
182
|
+
if more, ok := vs.GetPath(conn, mp).(bool); ok {
|
|
183
183
|
paging["hasMore"] = more
|
|
184
184
|
explicitMore = true
|
|
185
185
|
}
|
|
@@ -323,7 +323,7 @@ func (f *TestFeature) buildArgs(ctx *core.Context, op *core.Operation, args map[
|
|
|
323
323
|
// back to, so the seed-data query is built from the endpoint the request
|
|
324
324
|
// will actually be sent to: a terminal `{id}` marks a record route, and
|
|
325
325
|
// failing that the shallower path wins.
|
|
326
|
-
points := vs.GetPath([]any{"entity", ctx.Entity.GetName(), "op", opname, "points"}
|
|
326
|
+
points := vs.GetPath(ctx.Config, []any{"entity", ctx.Entity.GetName(), "op", opname, "points"})
|
|
327
327
|
point := vs.GetElem(points, 0)
|
|
328
328
|
if plist, ok := points.([]any); ok {
|
|
329
329
|
partsLen := func(p any) int {
|
|
@@ -355,12 +355,19 @@ func (f *TestFeature) buildArgs(ctx *core.Context, op *core.Operation, args map[
|
|
|
355
355
|
|
|
356
356
|
// Path AND query: a path-only read misses a query-addressed record
|
|
357
357
|
// (e.g. GET /result?trace_id=), which has no path param at all.
|
|
358
|
-
paramsPath := vs.GetPath([]any{"args", "params"}
|
|
358
|
+
paramsPath := vs.GetPath(point, []any{"args", "params"})
|
|
359
359
|
reqdParams := vs.Select(paramsPath, map[string]any{"reqd": true})
|
|
360
|
-
|
|
361
|
-
|
|
360
|
+
// The error return Transform gained in struct go 0.1.3 is discarded
|
|
361
|
+
// DELIBERATELY here, unlike in transform_request/response: these two
|
|
362
|
+
// transform a spec the SDK itself built from the point definition, not
|
|
363
|
+
// user data, so an error means a generator bug rather than something a
|
|
364
|
+
// caller can act on — and buildArgs has no error seam to route it
|
|
365
|
+
// through. An empty result is the conservative outcome: no required
|
|
366
|
+
// fields, which is what an absent spec already produces.
|
|
367
|
+
reqdFromParams, _ := vs.Transform(reqdParams, []any{"`$EACH`", "", "`$KEY.name`"})
|
|
368
|
+
queryPath := vs.GetPath(point, []any{"args", "query"})
|
|
362
369
|
reqdQuery := vs.Select(queryPath, map[string]any{"reqd": true})
|
|
363
|
-
reqdFromQuery := vs.Transform(reqdQuery, []any{"`$EACH`", "", "`$KEY.name`"})
|
|
370
|
+
reqdFromQuery, _ := vs.Transform(reqdQuery, []any{"`$EACH`", "", "`$KEY.name`"})
|
|
364
371
|
|
|
365
372
|
qand := []any{}
|
|
366
373
|
q := map[string]any{"`$AND`": &qand}
|
|
@@ -109,7 +109,12 @@ func TestCustomUtility(t *testing.T) {
|
|
|
109
109
|
// that was broken: a plain function literal in a map[string]any has the
|
|
110
110
|
// unnamed signature, so an override that only accepted the named type
|
|
111
111
|
// shelved it in Custom. Converting here would have hidden that.
|
|
112
|
+
// "test" is the OPTION, not the `test` FEATURE: it says "this client
|
|
113
|
+
// is not live", so a REQUIRED OpenAPI server variable resolves to a
|
|
114
|
+
// deterministic test-<name> instead of panicking at construction. It
|
|
115
|
+
// installs no transport, so the override under test still stands.
|
|
112
116
|
client := sdk.NewProjectNameSDK(map[string]any{
|
|
117
|
+
"test": map[string]any{"active": true},
|
|
113
118
|
"utility": map[string]any{"fetcher": scripted},
|
|
114
119
|
})
|
|
115
120
|
|
|
@@ -138,7 +143,12 @@ func TestCustomUtility(t *testing.T) {
|
|
|
138
143
|
// the subtest above, and broken by any fix that swaps one for the other.
|
|
139
144
|
t.Run("a converted fetcher is accepted too", func(t *testing.T) {
|
|
140
145
|
reached := 0
|
|
146
|
+
// "test" is the OPTION, not the `test` FEATURE: it says "this client
|
|
147
|
+
// is not live", so a REQUIRED OpenAPI server variable resolves to a
|
|
148
|
+
// deterministic test-<name> instead of panicking at construction. It
|
|
149
|
+
// installs no transport, so the override under test still stands.
|
|
141
150
|
client := sdk.NewProjectNameSDK(map[string]any{
|
|
151
|
+
"test": map[string]any{"active": true},
|
|
142
152
|
"utility": map[string]any{
|
|
143
153
|
"fetcher": sdk.FetcherFunc(func(
|
|
144
154
|
ctx *sdk.Context, fullurl string, fetchdef map[string]any,
|
|
@@ -171,7 +181,12 @@ func TestCustomUtility(t *testing.T) {
|
|
|
171
181
|
// An unknown key must still be attached rather than dropped, so the two
|
|
172
182
|
// halves cannot be satisfied by a switch that also swallows extras.
|
|
173
183
|
t.Run("an unknown key is still attached", func(t *testing.T) {
|
|
184
|
+
// "test" is the OPTION, not the `test` FEATURE: it says "this client
|
|
185
|
+
// is not live", so a REQUIRED OpenAPI server variable resolves to a
|
|
186
|
+
// deterministic test-<name> instead of panicking at construction. It
|
|
187
|
+
// installs no transport, so the override under test still stands.
|
|
174
188
|
client := sdk.NewProjectNameSDK(map[string]any{
|
|
189
|
+
"test": map[string]any{"active": true},
|
|
175
190
|
"utility": map[string]any{
|
|
176
191
|
"notAUtilityMember": func() string { return "EXTRA" },
|
|
177
192
|
},
|
|
@@ -114,7 +114,14 @@ func fcFetcher(res []any) sdk.FetcherFunc {
|
|
|
114
114
|
// REPLACES the transport, so a client in test mode would shadow the script.
|
|
115
115
|
func fcClient(kase map[string]any) *sdk.ProjectNameSDK {
|
|
116
116
|
res, _ := kase["res"].([]any)
|
|
117
|
+
// "test" here is the OPTION, not the `test` FEATURE. It says "this
|
|
118
|
+
// client is not live", which is what makes a REQUIRED OpenAPI server
|
|
119
|
+
// variable resolve to a deterministic test-<name> rather than panic at
|
|
120
|
+
// construction (see makeOptions). It installs no transport, so the
|
|
121
|
+
// scripted fetcher still stands — the FEATURE is transport: 'base' and
|
|
122
|
+
// would shadow it, which is why this cannot just turn the feature on.
|
|
117
123
|
opts := map[string]any{
|
|
124
|
+
"test": map[string]any{"active": true},
|
|
118
125
|
"utility": map[string]any{"fetcher": fcFetcher(res)},
|
|
119
126
|
}
|
|
120
127
|
if f, ok := kase["feature"]; ok {
|
|
@@ -156,6 +156,52 @@ func isControlSkipped(kind, name, mode string) (bool, string) {
|
|
|
156
156
|
}
|
|
157
157
|
|
|
158
158
|
// liveDelayMs returns the configured per-test live delay in ms; default 500.
|
|
159
|
+
// liveClientOptions returns the extra SDK options every LIVE client is
|
|
160
|
+
// constructed with, from sdk-test-control.json `test.client.options`.
|
|
161
|
+
//
|
|
162
|
+
// The generated live client knows two things: the base URL (from the spec)
|
|
163
|
+
// and the credential (from the environment). Everything else about how a
|
|
164
|
+
// particular API wants to be talked to - which features to switch on, and
|
|
165
|
+
// with what settings - is a property of THAT API, known to the project and
|
|
166
|
+
// to nothing in the toolchain.
|
|
167
|
+
//
|
|
168
|
+
// Merged UNDER the generated fields, so the suite's own base/apikey/server
|
|
169
|
+
// values win: this ADDS to the live client, it does not redirect it.
|
|
170
|
+
//
|
|
171
|
+
// That contract is enforced HERE rather than left to each merge site: the
|
|
172
|
+
// generated map only names a field when the model calls for one, so a
|
|
173
|
+
// "base" in this block would face no competing value and would silently
|
|
174
|
+
// redirect the whole suite - credential included - to another host.
|
|
175
|
+
var liveReserved = map[string]bool{
|
|
176
|
+
"base": true, "prefix": true, "suffix": true,
|
|
177
|
+
"server": true, "apikey": true, "secret": true,
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
func liveClientOptions() map[string]any {
|
|
181
|
+
ctrl := loadTestControl()
|
|
182
|
+
test, _ := ctrl["test"].(map[string]any)
|
|
183
|
+
if test == nil {
|
|
184
|
+
return map[string]any{}
|
|
185
|
+
}
|
|
186
|
+
client, _ := test["client"].(map[string]any)
|
|
187
|
+
if client == nil {
|
|
188
|
+
return map[string]any{}
|
|
189
|
+
}
|
|
190
|
+
opts, _ := client["options"].(map[string]any)
|
|
191
|
+
if opts == nil {
|
|
192
|
+
return map[string]any{}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
out := map[string]any{}
|
|
196
|
+
for k, v := range opts {
|
|
197
|
+
if !liveReserved[k] {
|
|
198
|
+
out[k] = v
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return out
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
|
|
159
205
|
func liveDelayMs() int {
|
|
160
206
|
ctrl := loadTestControl()
|
|
161
207
|
test, _ := ctrl["test"].(map[string]any)
|
|
@@ -33,7 +33,7 @@ type StructUtility struct {
|
|
|
33
33
|
IsNode func(val any) bool
|
|
34
34
|
Clone func(val any) any
|
|
35
35
|
CloneFlags func(val any, flags map[string]bool) any
|
|
36
|
-
GetPath func(
|
|
36
|
+
GetPath func(store any, path any, injdefs ...*voxgigstruct.Injection) any
|
|
37
37
|
Inject func(val any, store any, injdefs ...*voxgigstruct.Injection) any
|
|
38
38
|
Items func(val any) [][2]any
|
|
39
39
|
Stringify func(val any, maxlen ...int) string
|
|
@@ -65,7 +65,7 @@ type StructUtility struct {
|
|
|
65
65
|
Size func(val any) int
|
|
66
66
|
Slice func(val any, args ...any) any
|
|
67
67
|
StrKey func(key any) string
|
|
68
|
-
Transform func(data any, spec any, injdefs ...*voxgigstruct.Injection) any
|
|
68
|
+
Transform func(data any, spec any, injdefs ...*voxgigstruct.Injection) (any, error)
|
|
69
69
|
Typify func(value any) int
|
|
70
70
|
Typename func(t int) string
|
|
71
71
|
Validate func(data any, spec any, injdefs ...*voxgigstruct.Injection) (any, error)
|
|
@@ -73,8 +73,8 @@ type StructUtility struct {
|
|
|
73
73
|
SKIP any
|
|
74
74
|
DELETE any
|
|
75
75
|
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
Jm func(kv ...any) map[string]any
|
|
77
|
+
Jt func(v ...any) []any
|
|
78
78
|
|
|
79
79
|
CheckPlacement func(modes int, ijname string, parentTypes int, inj *voxgigstruct.Injection) bool
|
|
80
80
|
InjectorArgs func(argTypes []int, args []any) []any
|
|
@@ -681,7 +681,7 @@ func MatchNode(
|
|
|
681
681
|
scalar := !structUtil.IsNode(val)
|
|
682
682
|
|
|
683
683
|
if scalar {
|
|
684
|
-
baseval := structUtil.GetPath(
|
|
684
|
+
baseval := structUtil.GetPath(base, path)
|
|
685
685
|
if !MatchScalar(val, baseval, structUtil) {
|
|
686
686
|
pass = false
|
|
687
687
|
err = fmt.Errorf(
|
|
@@ -1058,8 +1058,8 @@ func NewStructSDK(opts map[string]any) *StructSDK {
|
|
|
1058
1058
|
SKIP: voxgigstruct.SKIP,
|
|
1059
1059
|
DELETE: voxgigstruct.DELETE,
|
|
1060
1060
|
|
|
1061
|
-
|
|
1062
|
-
|
|
1061
|
+
Jm: voxgigstruct.Jm,
|
|
1062
|
+
Jt: voxgigstruct.Jt,
|
|
1063
1063
|
|
|
1064
1064
|
CheckPlacement: voxgigstruct.CheckPlacement,
|
|
1065
1065
|
InjectorArgs: voxgigstruct.InjectorArgs,
|
|
@@ -159,20 +159,44 @@ func TestStructUtility(t *testing.T) {
|
|
|
159
159
|
})
|
|
160
160
|
|
|
161
161
|
t.Run("minor-escurl", func(t *testing.T) {
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
162
|
+
// Passed BARE, like every other minor subject. This used to wrap
|
|
163
|
+
// EscUrl in ReplaceAll(..., "+", "%20") because the vendored copy
|
|
164
|
+
// implemented it with net/url.QueryEscape, which form-encodes: a
|
|
165
|
+
// space became '+' rather than '%20'. The workaround made the
|
|
166
|
+
// shared corpus pass while make_url.go still emitted '+' into real
|
|
167
|
+
// paths and query strings. Upstream's EscUrl matches the reference
|
|
168
|
+
// encodeURIComponent exactly, so there is nothing left to paper over.
|
|
169
|
+
structRunSet(t, minorSpec["escurl"], voxgigstruct.EscUrl)
|
|
165
170
|
})
|
|
166
171
|
|
|
167
172
|
t.Run("minor-stringify", func(t *testing.T) {
|
|
168
173
|
structRunSet(t, minorSpec["stringify"], func(v any) any {
|
|
169
174
|
m := v.(map[string]any)
|
|
170
|
-
val := m["val"]
|
|
175
|
+
val, hasVal := m["val"]
|
|
171
176
|
|
|
172
177
|
if "__NULL__" == val {
|
|
173
178
|
val = "null"
|
|
174
179
|
}
|
|
175
180
|
|
|
181
|
+
// Go has no `undefined`. Upstream Stringify renders nil as
|
|
182
|
+
// "null" ON PURPOSE - in Go nil IS JSON null, and
|
|
183
|
+
// JSON.stringify(null) is "null" - so the corpus's two
|
|
184
|
+
// separate cases,
|
|
185
|
+
//
|
|
186
|
+
// {"val": null} -> "null" and {} -> ""
|
|
187
|
+
//
|
|
188
|
+
// both arrive here as a nil val and cannot be told apart by
|
|
189
|
+
// VALUE. They can be told apart by PRESENCE: the second case
|
|
190
|
+
// is the JavaScript stringify(undefined), and an absent key
|
|
191
|
+
// is the only thing Go has that means undefined.
|
|
192
|
+
//
|
|
193
|
+
// The runner is the right place for this: it is the seam
|
|
194
|
+
// between a language-neutral corpus and one language's type
|
|
195
|
+
// system, and it already bridges the same gap for pathify.
|
|
196
|
+
if !hasVal {
|
|
197
|
+
return ""
|
|
198
|
+
}
|
|
199
|
+
|
|
176
200
|
max, hasMax := m["max"]
|
|
177
201
|
if !hasMax || nil == max {
|
|
178
202
|
return voxgigstruct.Stringify(val)
|
|
@@ -585,9 +609,21 @@ func TestStructUtility(t *testing.T) {
|
|
|
585
609
|
} else {
|
|
586
610
|
ks = *k
|
|
587
611
|
}
|
|
612
|
+
|
|
613
|
+
// The ROOT node has no parent. The reference passes
|
|
614
|
+
// `undefined` there and logs `p=`; Go has only nil, which
|
|
615
|
+
// Stringify renders as "null" (its documented choice - see
|
|
616
|
+
// minor-stringify above). Rendering the absent parent as ""
|
|
617
|
+
// keeps the log identical to the reference's, which is what
|
|
618
|
+
// the corpus records.
|
|
619
|
+
ps := ""
|
|
620
|
+
if nil != p {
|
|
621
|
+
ps = voxgigstruct.Stringify(p)
|
|
622
|
+
}
|
|
623
|
+
|
|
588
624
|
entry := "k=" + voxgigstruct.Stringify(ks) +
|
|
589
625
|
", v=" + voxgigstruct.Stringify(v) +
|
|
590
|
-
", p=" +
|
|
626
|
+
", p=" + ps +
|
|
591
627
|
", t=" + voxgigstruct.Pathify(t)
|
|
592
628
|
return entry
|
|
593
629
|
}
|
|
@@ -840,7 +876,7 @@ func TestStructUtility(t *testing.T) {
|
|
|
840
876
|
path := m["path"]
|
|
841
877
|
store := m["store"]
|
|
842
878
|
|
|
843
|
-
return voxgigstruct.GetPath(
|
|
879
|
+
return voxgigstruct.GetPath(store, path)
|
|
844
880
|
})
|
|
845
881
|
})
|
|
846
882
|
|
|
@@ -862,7 +898,7 @@ func TestStructUtility(t *testing.T) {
|
|
|
862
898
|
Dpath: dpath,
|
|
863
899
|
}
|
|
864
900
|
|
|
865
|
-
return voxgigstruct.GetPath(
|
|
901
|
+
return voxgigstruct.GetPath(store, path, inj)
|
|
866
902
|
})
|
|
867
903
|
})
|
|
868
904
|
|
|
@@ -884,10 +920,10 @@ func TestStructUtility(t *testing.T) {
|
|
|
884
920
|
inj.Meta = metaMap
|
|
885
921
|
}
|
|
886
922
|
}
|
|
887
|
-
return voxgigstruct.GetPath(
|
|
923
|
+
return voxgigstruct.GetPath(store, path, inj)
|
|
888
924
|
}
|
|
889
925
|
|
|
890
|
-
return voxgigstruct.GetPath(
|
|
926
|
+
return voxgigstruct.GetPath(store, path)
|
|
891
927
|
})
|
|
892
928
|
})
|
|
893
929
|
|
|
@@ -947,14 +983,14 @@ func TestStructUtility(t *testing.T) {
|
|
|
947
983
|
data := inVal["data"]
|
|
948
984
|
spec := inVal["spec"]
|
|
949
985
|
outVal := subtest["out"]
|
|
950
|
-
result := voxgigstruct.Transform(data, spec)
|
|
986
|
+
result, _ := voxgigstruct.Transform(data, spec)
|
|
951
987
|
if !reflect.DeepEqual(result, outVal) {
|
|
952
988
|
t.Errorf("Expected: %v, Got: %v", outVal, result)
|
|
953
989
|
}
|
|
954
990
|
})
|
|
955
991
|
|
|
956
992
|
t.Run("transform-paths", func(t *testing.T) {
|
|
957
|
-
structRunSet(t, transformSpec["paths"], func(v any) any {
|
|
993
|
+
structRunSet(t, transformSpec["paths"], func(v any) (any, error) {
|
|
958
994
|
m := v.(map[string]any)
|
|
959
995
|
data := m["data"]
|
|
960
996
|
spec := m["spec"]
|
|
@@ -963,7 +999,7 @@ func TestStructUtility(t *testing.T) {
|
|
|
963
999
|
})
|
|
964
1000
|
|
|
965
1001
|
t.Run("transform-cmds", func(t *testing.T) {
|
|
966
|
-
structRunSet(t, transformSpec["cmds"], func(v any) any {
|
|
1002
|
+
structRunSet(t, transformSpec["cmds"], func(v any) (any, error) {
|
|
967
1003
|
m := v.(map[string]any)
|
|
968
1004
|
data := m["data"]
|
|
969
1005
|
spec := m["spec"]
|
|
@@ -972,7 +1008,7 @@ func TestStructUtility(t *testing.T) {
|
|
|
972
1008
|
})
|
|
973
1009
|
|
|
974
1010
|
t.Run("transform-each", func(t *testing.T) {
|
|
975
|
-
structRunSet(t, transformSpec["each"], func(v any) any {
|
|
1011
|
+
structRunSet(t, transformSpec["each"], func(v any) (any, error) {
|
|
976
1012
|
m := v.(map[string]any)
|
|
977
1013
|
data := m["data"]
|
|
978
1014
|
spec := m["spec"]
|
|
@@ -981,7 +1017,7 @@ func TestStructUtility(t *testing.T) {
|
|
|
981
1017
|
})
|
|
982
1018
|
|
|
983
1019
|
t.Run("transform-pack", func(t *testing.T) {
|
|
984
|
-
structRunSet(t, transformSpec["pack"], func(v any) any {
|
|
1020
|
+
structRunSet(t, transformSpec["pack"], func(v any) (any, error) {
|
|
985
1021
|
m := v.(map[string]any)
|
|
986
1022
|
data := m["data"]
|
|
987
1023
|
spec := m["spec"]
|
|
@@ -990,7 +1026,7 @@ func TestStructUtility(t *testing.T) {
|
|
|
990
1026
|
})
|
|
991
1027
|
|
|
992
1028
|
t.Run("transform-ref", func(t *testing.T) {
|
|
993
|
-
structRunSet(t, transformSpec["ref"], func(v any) any {
|
|
1029
|
+
structRunSet(t, transformSpec["ref"], func(v any) (any, error) {
|
|
994
1030
|
m := v.(map[string]any)
|
|
995
1031
|
data := m["data"]
|
|
996
1032
|
spec := m["spec"]
|
|
@@ -999,7 +1035,7 @@ func TestStructUtility(t *testing.T) {
|
|
|
999
1035
|
})
|
|
1000
1036
|
|
|
1001
1037
|
t.Run("transform-format", func(t *testing.T) {
|
|
1002
|
-
structRunSetFlags(t, transformSpec["format"], map[string]bool{"null": false}, func(v any) any {
|
|
1038
|
+
structRunSetFlags(t, transformSpec["format"], map[string]bool{"null": false}, func(v any) (any, error) {
|
|
1003
1039
|
m := v.(map[string]any)
|
|
1004
1040
|
data := m["data"]
|
|
1005
1041
|
spec := m["spec"]
|
|
@@ -1021,7 +1057,7 @@ func TestStructUtility(t *testing.T) {
|
|
|
1021
1057
|
})
|
|
1022
1058
|
|
|
1023
1059
|
t.Run("transform-edge-apply", func(t *testing.T) {
|
|
1024
|
-
result := voxgigstruct.Transform(
|
|
1060
|
+
result, _ := voxgigstruct.Transform(
|
|
1025
1061
|
map[string]any{},
|
|
1026
1062
|
[]any{"`$APPLY`", func(v any) any { return 1 + v.(int) }, 1},
|
|
1027
1063
|
)
|
|
@@ -1105,25 +1141,25 @@ func TestStructUtility(t *testing.T) {
|
|
|
1105
1141
|
t.Run("transform-funcval", func(t *testing.T) {
|
|
1106
1142
|
f0 := func() int { return 22 }
|
|
1107
1143
|
|
|
1108
|
-
result1 := voxgigstruct.Transform(map[string]any{}, map[string]any{"x": 1})
|
|
1144
|
+
result1, _ := voxgigstruct.Transform(map[string]any{}, map[string]any{"x": 1})
|
|
1109
1145
|
expected1 := map[string]any{"x": 1}
|
|
1110
1146
|
if !reflect.DeepEqual(expected1, result1) {
|
|
1111
1147
|
t.Errorf("Expected simple value transform result")
|
|
1112
1148
|
}
|
|
1113
1149
|
|
|
1114
|
-
result2 := voxgigstruct.Transform(map[string]any{}, map[string]any{"x": f0})
|
|
1150
|
+
result2, _ := voxgigstruct.Transform(map[string]any{}, map[string]any{"x": f0})
|
|
1115
1151
|
var fr0 = result2.(map[string]any)["x"].(func() int)
|
|
1116
1152
|
if f0() != fr0() {
|
|
1117
1153
|
t.Errorf("Expected x to be f0")
|
|
1118
1154
|
}
|
|
1119
1155
|
|
|
1120
|
-
result3 := voxgigstruct.Transform(map[string]any{"a": 1}, map[string]any{"x": "`a`"})
|
|
1156
|
+
result3, _ := voxgigstruct.Transform(map[string]any{"a": 1}, map[string]any{"x": "`a`"})
|
|
1121
1157
|
expected3 := map[string]any{"x": 1}
|
|
1122
1158
|
if !reflect.DeepEqual(expected3, result3) {
|
|
1123
1159
|
t.Errorf("Expected value lookup transform to work")
|
|
1124
1160
|
}
|
|
1125
1161
|
|
|
1126
|
-
result4 := voxgigstruct.Transform(map[string]any{"f0": f0}, map[string]any{"x": "`f0`"})
|
|
1162
|
+
result4, _ := voxgigstruct.Transform(map[string]any{"f0": f0}, map[string]any{"x": "`f0`"})
|
|
1127
1163
|
var fr4 = result4.(map[string]any)["x"].(func() int)
|
|
1128
1164
|
if 22 != fr4() {
|
|
1129
1165
|
t.Errorf("Expected function to be preserved")
|
|
@@ -1347,22 +1383,22 @@ func TestStructUtility(t *testing.T) {
|
|
|
1347
1383
|
|
|
1348
1384
|
t.Run("json-builder", func(t *testing.T) {
|
|
1349
1385
|
expected0 := "{\n \"a\": 1\n}"
|
|
1350
|
-
result0 := voxgigstruct.Jsonify(voxgigstruct.
|
|
1386
|
+
result0 := voxgigstruct.Jsonify(voxgigstruct.Jm("a", 1))
|
|
1351
1387
|
if result0 != expected0 {
|
|
1352
1388
|
t.Errorf("Expected: %v, Got: %v", expected0, result0)
|
|
1353
1389
|
}
|
|
1354
1390
|
|
|
1355
1391
|
expected1 := "[\n \"b\",\n 2\n]"
|
|
1356
|
-
result1 := voxgigstruct.Jsonify(voxgigstruct.
|
|
1392
|
+
result1 := voxgigstruct.Jsonify(voxgigstruct.Jt("b", 2))
|
|
1357
1393
|
if result1 != expected1 {
|
|
1358
1394
|
t.Errorf("Expected: %v, Got: %v", expected1, result1)
|
|
1359
1395
|
}
|
|
1360
1396
|
|
|
1361
1397
|
expected2 := "{\n \"c\": \"C\",\n \"d\": {\n \"x\": true\n },\n \"e\": [\n null,\n false\n ]\n}"
|
|
1362
|
-
result2 := voxgigstruct.Jsonify(voxgigstruct.
|
|
1398
|
+
result2 := voxgigstruct.Jsonify(voxgigstruct.Jm(
|
|
1363
1399
|
"c", "C",
|
|
1364
|
-
"d", voxgigstruct.
|
|
1365
|
-
"e", voxgigstruct.
|
|
1400
|
+
"d", voxgigstruct.Jm("x", true),
|
|
1401
|
+
"e", voxgigstruct.Jt(nil, false),
|
|
1366
1402
|
))
|
|
1367
1403
|
if result2 != expected2 {
|
|
1368
1404
|
t.Errorf("Expected:\n%v\nGot:\n%v", expected2, result2)
|
|
@@ -1397,7 +1433,7 @@ func TestStructUtility(t *testing.T) {
|
|
|
1397
1433
|
},
|
|
1398
1434
|
}
|
|
1399
1435
|
|
|
1400
|
-
return voxgigstruct.GetPath(
|
|
1436
|
+
return voxgigstruct.GetPath(store, path, inj)
|
|
1401
1437
|
})
|
|
1402
1438
|
})
|
|
1403
1439
|
}
|
|
@@ -118,13 +118,13 @@ func fetcherUtil(ctx *core.Context, fullurl string, fetchdef map[string]any) (an
|
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
options := ctx.Client.OptionsMap()
|
|
121
|
-
if vs.GetPath([]any{"feature", "test", "active"}
|
|
121
|
+
if vs.GetPath(options, []any{"feature", "test", "active"}) == true {
|
|
122
122
|
return nil, ctx.MakeError("fetch_test_block",
|
|
123
123
|
"Request blocked as test feature is active"+
|
|
124
124
|
" (URL was: \""+fullurl+"\")")
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
-
sysFetch := vs.GetPath([]any{"system", "fetch"}
|
|
127
|
+
sysFetch := vs.GetPath(options, []any{"system", "fetch"})
|
|
128
128
|
|
|
129
129
|
if sysFetch == nil {
|
|
130
130
|
return defaultHTTPFetch(fullurl, fetchdef)
|
|
@@ -36,6 +36,20 @@ func makeOptionsUtil(ctx *core.Context) map[string]any {
|
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
// `auth: nil` is the documented way to disable auth outright, and
|
|
40
|
+
// prepareAuth honours it before it ever reads the apikey. But validate
|
|
41
|
+
// treats a stored nil as "no value", so the optspec's `auth` default
|
|
42
|
+
// fires and the suppression silently becomes "use default auth" —
|
|
43
|
+
// transmitting a credential the caller explicitly asked not to send.
|
|
44
|
+
//
|
|
45
|
+
// Suppliedness cannot be recovered after validate, hence here. The
|
|
46
|
+
// two-value form is required: options["auth"] reads nil both when the
|
|
47
|
+
// key is ABSENT and when it is present and nil, and only the second is
|
|
48
|
+
// a suppression. (ts gets this for free — `null === options.auth` is
|
|
49
|
+
// false for an omitted key, since that reads undefined.)
|
|
50
|
+
authval, authgiven := options["auth"]
|
|
51
|
+
authsuppressed := authgiven && authval == nil
|
|
52
|
+
|
|
39
53
|
opts := vs.Clone(options).(map[string]any)
|
|
40
54
|
|
|
41
55
|
// Feature add-order (feature #2). options.feature may be given as an ordered
|
|
@@ -129,7 +143,7 @@ func makeOptionsUtil(ctx *core.Context) map[string]any {
|
|
|
129
143
|
|
|
130
144
|
// Preserve system.fetch before merge/validate.
|
|
131
145
|
var sysFetch any
|
|
132
|
-
if sf := vs.GetPath([]any{"system", "fetch"}
|
|
146
|
+
if sf := vs.GetPath(opts, []any{"system", "fetch"}); sf != nil {
|
|
133
147
|
sysFetch = sf
|
|
134
148
|
}
|
|
135
149
|
|
|
@@ -141,6 +155,11 @@ func makeOptionsUtil(ctx *core.Context) map[string]any {
|
|
|
141
155
|
validated, _ := vs.Validate(merged, optspec)
|
|
142
156
|
opts = validated.(map[string]any)
|
|
143
157
|
|
|
158
|
+
// Restore the suppression the optspec default would otherwise erase.
|
|
159
|
+
if authsuppressed {
|
|
160
|
+
opts["auth"] = nil
|
|
161
|
+
}
|
|
162
|
+
|
|
144
163
|
// Resolve a templated base URL (e.g. https://{tenant_id}.hanko.io).
|
|
145
164
|
// Every placeholder must resolve to a non-empty value: from
|
|
146
165
|
// options["server"] (user), else the config default. A placeholder that
|
|
@@ -151,15 +170,15 @@ func makeOptionsUtil(ctx *core.Context) map[string]any {
|
|
|
151
170
|
// PANICS (construction-time misconfiguration, as regexp.MustCompile).
|
|
152
171
|
if base, ok := opts["base"].(string); ok && strings.Contains(base, "{") {
|
|
153
172
|
testmode := false
|
|
154
|
-
if ta, ok := vs.GetPath([]any{"test", "active"}
|
|
173
|
+
if ta, ok := vs.GetPath(opts, []any{"test", "active"}).(bool); ok && ta {
|
|
155
174
|
testmode = true
|
|
156
175
|
}
|
|
157
|
-
if fa, ok := vs.GetPath([]any{"feature", "test", "active"}
|
|
176
|
+
if fa, ok := vs.GetPath(opts, []any{"feature", "test", "active"}).(bool); ok && fa {
|
|
158
177
|
testmode = true
|
|
159
178
|
}
|
|
160
179
|
server := core.ToMapAny(opts["server"])
|
|
161
180
|
sdkname := "SDK"
|
|
162
|
-
if mn, ok := vs.GetPath([]any{"main", "name"}
|
|
181
|
+
if mn, ok := vs.GetPath(config, []any{"main", "name"}).(string); ok && mn != "" {
|
|
163
182
|
sdkname = mn
|
|
164
183
|
}
|
|
165
184
|
resolved := serverVarRe.ReplaceAllStringFunc(base, func(ph string) string {
|
|
@@ -191,7 +210,7 @@ func makeOptionsUtil(ctx *core.Context) map[string]any {
|
|
|
191
210
|
|
|
192
211
|
// Derived clean config.
|
|
193
212
|
cleanKeys := "key,token,id"
|
|
194
|
-
if ck := vs.GetPath([]any{"clean", "keys"}
|
|
213
|
+
if ck := vs.GetPath(opts, []any{"clean", "keys"}); ck != nil {
|
|
195
214
|
if cks, ok := ck.(string); ok {
|
|
196
215
|
cleanKeys = cks
|
|
197
216
|
}
|