@voxgig/sdkgen 4.22.0 → 4.24.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 +18 -2
- package/dist/action/doctor.d.ts +1 -1
- package/dist/action/doctor.js +12 -10
- package/dist/action/doctor.js.map +1 -1
- package/dist/action/edition.js +4 -0
- package/dist/action/edition.js.map +1 -1
- package/dist/action/feature.js +5 -1
- package/dist/action/feature.js.map +1 -1
- package/dist/action/remove.d.ts +16 -0
- package/dist/action/remove.js +345 -0
- package/dist/action/remove.js.map +1 -0
- package/dist/action/target.js +6 -1
- package/dist/action/target.js.map +1 -1
- package/dist/cmp/ReadmeTop.js +1 -1
- package/dist/cmp/ReadmeTop.js.map +1 -1
- package/dist/cmp/ReadmeUnions.js +1 -1
- package/dist/cmp/ReadmeUnions.js.map +1 -1
- package/dist/cmp/Test.js +1 -1
- package/dist/cmp/Test.js.map +1 -1
- package/dist/helpers/buildIdNames.d.ts +3 -1
- package/dist/helpers/buildIdNames.js +15 -7
- package/dist/helpers/buildIdNames.js.map +1 -1
- package/dist/helpers/canonSpec.js +2 -2
- package/dist/helpers/canonSpec.js.map +1 -1
- package/dist/helpers/getMatchEntries.js +2 -2
- package/dist/helpers/getMatchEntries.js.map +1 -1
- package/dist/helpers/modelNames.js +5 -1
- package/dist/helpers/modelNames.js.map +1 -1
- package/dist/helpers/opShape.js +33 -33
- package/dist/helpers/opShape.js.map +1 -1
- package/dist/helpers/pointPath.js +5 -10
- package/dist/helpers/pointPath.js.map +1 -1
- package/dist/helpers/resolved.js +2 -29
- package/dist/helpers/resolved.js.map +1 -1
- package/dist/sdkgen.d.ts +2 -2
- package/dist/sdkgen.js +5 -3
- package/dist/sdkgen.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utility.js +15 -7
- package/dist/utility.js.map +1 -1
- package/package.json +3 -3
- package/project/.sdk/src/cmp/c/EntityTypes_c.ts +4 -4
- package/project/.sdk/src/cmp/c/ReadmeEntity_c.ts +3 -3
- package/project/.sdk/src/cmp/c/ReadmeModel_c.ts +3 -3
- package/project/.sdk/src/cmp/c/ReadmeRef_c.ts +5 -5
- package/project/.sdk/src/cmp/c/Schema_c.ts +1 -1
- package/project/.sdk/src/cmp/c/TestDirect_c.ts +12 -12
- package/project/.sdk/src/cmp/clojure/ReadmeEntity_clojure.ts +3 -3
- package/project/.sdk/src/cmp/clojure/ReadmeModel_clojure.ts +3 -3
- package/project/.sdk/src/cmp/clojure/ReadmeRef_clojure.ts +5 -5
- package/project/.sdk/src/cmp/clojure/Schema_clojure.ts +1 -1
- package/project/.sdk/src/cmp/cpp/EntityTypes_cpp.ts +3 -3
- package/project/.sdk/src/cmp/cpp/ReadmeEntity_cpp.ts +3 -3
- package/project/.sdk/src/cmp/cpp/ReadmeModel_cpp.ts +3 -3
- package/project/.sdk/src/cmp/cpp/ReadmeRef_cpp.ts +5 -5
- package/project/.sdk/src/cmp/cpp/Schema_cpp.ts +1 -1
- package/project/.sdk/src/cmp/cpp/TestDirect_cpp.ts +14 -14
- package/project/.sdk/src/cmp/cpp/TestEntity_cpp.ts +51 -50
- package/project/.sdk/src/cmp/csharp/EntityTypes_csharp.ts +4 -4
- package/project/.sdk/src/cmp/csharp/ReadmeEntity_csharp.ts +3 -3
- package/project/.sdk/src/cmp/csharp/ReadmeModel_csharp.ts +3 -3
- package/project/.sdk/src/cmp/csharp/ReadmeRef_csharp.ts +5 -5
- package/project/.sdk/src/cmp/csharp/Schema_csharp.ts +1 -1
- package/project/.sdk/src/cmp/csharp/TestDirect_csharp.ts +30 -30
- package/project/.sdk/src/cmp/csharp/TestEntity_csharp.ts +66 -65
- package/project/.sdk/src/cmp/elixir/EntityTypes_elixir.ts +4 -4
- package/project/.sdk/src/cmp/elixir/ReadmeEntity_elixir.ts +3 -3
- package/project/.sdk/src/cmp/elixir/ReadmeModel_elixir.ts +3 -3
- package/project/.sdk/src/cmp/elixir/ReadmeRef_elixir.ts +4 -4
- package/project/.sdk/src/cmp/elixir/Schema_elixir.ts +1 -1
- package/project/.sdk/src/cmp/go/EntityTypes_go.ts +4 -4
- package/project/.sdk/src/cmp/go/ReadmeEntity_go.ts +3 -3
- package/project/.sdk/src/cmp/go/ReadmeModel_go.ts +3 -3
- package/project/.sdk/src/cmp/go/ReadmeRef_go.ts +5 -5
- package/project/.sdk/src/cmp/go/Schema_go.ts +1 -1
- package/project/.sdk/src/cmp/go/TestDirect_go.ts +38 -38
- package/project/.sdk/src/cmp/go/TestEntity_go.ts +75 -74
- package/project/.sdk/src/cmp/go/utility_go.ts +5 -5
- package/project/.sdk/src/cmp/java/EntityTypes_java.ts +4 -4
- package/project/.sdk/src/cmp/java/ReadmeEntity_java.ts +3 -3
- package/project/.sdk/src/cmp/java/ReadmeModel_java.ts +3 -3
- package/project/.sdk/src/cmp/java/ReadmeRef_java.ts +5 -5
- package/project/.sdk/src/cmp/java/Schema_java.ts +1 -1
- package/project/.sdk/src/cmp/java/TestDirect_java.ts +30 -30
- package/project/.sdk/src/cmp/java/TestEntity_java.ts +69 -68
- package/project/.sdk/src/cmp/js/EntityTypes_js.ts +5 -5
- package/project/.sdk/src/cmp/js/ReadmeEntity_js.ts +3 -3
- package/project/.sdk/src/cmp/js/ReadmeModel_js.ts +3 -3
- package/project/.sdk/src/cmp/js/ReadmeRef_js.ts +5 -5
- package/project/.sdk/src/cmp/js/Schema_js.ts +1 -1
- package/project/.sdk/src/cmp/js/TestDirect_js.ts +27 -27
- package/project/.sdk/src/cmp/js/TestEntity_js.ts +66 -69
- package/project/.sdk/src/cmp/js/TestLive_js.ts +3 -3
- package/project/.sdk/src/cmp/js/utility_js.ts +5 -5
- package/project/.sdk/src/cmp/kotlin/EntityTypes_kotlin.ts +4 -4
- package/project/.sdk/src/cmp/kotlin/ReadmeEntity_kotlin.ts +3 -3
- package/project/.sdk/src/cmp/kotlin/ReadmeModel_kotlin.ts +3 -3
- package/project/.sdk/src/cmp/kotlin/ReadmeRef_kotlin.ts +5 -5
- package/project/.sdk/src/cmp/kotlin/Schema_kotlin.ts +1 -1
- package/project/.sdk/src/cmp/kotlin/TestDirect_kotlin.ts +30 -30
- package/project/.sdk/src/cmp/kotlin/TestEntity_kotlin.ts +67 -66
- package/project/.sdk/src/cmp/lua/EntityTypes_lua.ts +5 -5
- package/project/.sdk/src/cmp/lua/ReadmeEntity_lua.ts +3 -3
- package/project/.sdk/src/cmp/lua/ReadmeModel_lua.ts +3 -3
- package/project/.sdk/src/cmp/lua/ReadmeQuick_lua.ts +4 -4
- package/project/.sdk/src/cmp/lua/ReadmeRef_lua.ts +5 -5
- package/project/.sdk/src/cmp/lua/Schema_lua.ts +1 -1
- package/project/.sdk/src/cmp/lua/TestDirect_lua.ts +25 -25
- package/project/.sdk/src/cmp/lua/TestEntity_lua.ts +66 -65
- package/project/.sdk/src/cmp/ocaml/ReadmeEntity_ocaml.ts +3 -3
- package/project/.sdk/src/cmp/ocaml/ReadmeModel_ocaml.ts +3 -3
- package/project/.sdk/src/cmp/ocaml/ReadmeRef_ocaml.ts +5 -5
- package/project/.sdk/src/cmp/ocaml/Schema_ocaml.ts +1 -1
- package/project/.sdk/src/cmp/perl/ReadmeEntity_perl.ts +3 -3
- package/project/.sdk/src/cmp/perl/ReadmeModel_perl.ts +3 -3
- package/project/.sdk/src/cmp/perl/ReadmeRef_perl.ts +5 -5
- package/project/.sdk/src/cmp/perl/Schema_perl.ts +1 -1
- package/project/.sdk/src/cmp/perl/TestDirect_perl.ts +25 -25
- package/project/.sdk/src/cmp/perl/TestEntity_perl.ts +60 -59
- package/project/.sdk/src/cmp/php/EntityTypes_php.ts +4 -4
- package/project/.sdk/src/cmp/php/ReadmeEntity_php.ts +3 -3
- package/project/.sdk/src/cmp/php/ReadmeModel_php.ts +3 -3
- package/project/.sdk/src/cmp/php/ReadmeQuick_php.ts +4 -4
- package/project/.sdk/src/cmp/php/ReadmeRef_php.ts +5 -5
- package/project/.sdk/src/cmp/php/Schema_php.ts +1 -1
- package/project/.sdk/src/cmp/php/TestDirect_php.ts +25 -25
- package/project/.sdk/src/cmp/php/TestEntity_php.ts +66 -65
- package/project/.sdk/src/cmp/py/EntityTypes_py.ts +4 -4
- package/project/.sdk/src/cmp/py/ReadmeEntity_py.ts +3 -3
- package/project/.sdk/src/cmp/py/ReadmeModel_py.ts +3 -3
- package/project/.sdk/src/cmp/py/ReadmeRef_py.ts +5 -5
- package/project/.sdk/src/cmp/py/Schema_py.ts +1 -1
- package/project/.sdk/src/cmp/py/TestDirect_py.ts +25 -25
- package/project/.sdk/src/cmp/py/TestEntity_py.ts +66 -65
- package/project/.sdk/src/cmp/py-data/Main_py-data.ts +4 -4
- package/project/.sdk/src/cmp/rb/EntityTypes_rb.ts +4 -4
- package/project/.sdk/src/cmp/rb/ReadmeEntity_rb.ts +3 -3
- package/project/.sdk/src/cmp/rb/ReadmeModel_rb.ts +3 -3
- package/project/.sdk/src/cmp/rb/ReadmeQuick_rb.ts +4 -4
- package/project/.sdk/src/cmp/rb/ReadmeRef_rb.ts +5 -5
- package/project/.sdk/src/cmp/rb/Schema_rb.ts +1 -1
- package/project/.sdk/src/cmp/rb/TestDirect_rb.ts +25 -25
- package/project/.sdk/src/cmp/rb/TestEntity_rb.ts +66 -65
- package/project/.sdk/src/cmp/rust/EntityTypes_rust.ts +4 -4
- package/project/.sdk/src/cmp/rust/ReadmeEntity_rust.ts +3 -3
- package/project/.sdk/src/cmp/rust/ReadmeModel_rust.ts +3 -3
- package/project/.sdk/src/cmp/rust/ReadmeRef_rust.ts +5 -5
- package/project/.sdk/src/cmp/rust/Schema_rust.ts +1 -1
- package/project/.sdk/src/cmp/rust/TestDirect_rust.ts +18 -18
- package/project/.sdk/src/cmp/rust/TestEntity_rust.ts +63 -62
- package/project/.sdk/src/cmp/scala/EntityTypes_scala.ts +4 -4
- package/project/.sdk/src/cmp/scala/ReadmeEntity_scala.ts +3 -3
- package/project/.sdk/src/cmp/scala/ReadmeModel_scala.ts +3 -3
- package/project/.sdk/src/cmp/scala/ReadmeRef_scala.ts +5 -5
- package/project/.sdk/src/cmp/scala/Schema_scala.ts +1 -1
- package/project/.sdk/src/cmp/scala/TestDirect_scala.ts +14 -14
- package/project/.sdk/src/cmp/scala/TestEntity_scala.ts +60 -59
- package/project/.sdk/src/cmp/swift/EntityTypes_swift.ts +4 -4
- package/project/.sdk/src/cmp/swift/ReadmeEntity_swift.ts +3 -3
- package/project/.sdk/src/cmp/swift/ReadmeModel_swift.ts +3 -3
- package/project/.sdk/src/cmp/swift/ReadmeRef_swift.ts +5 -5
- package/project/.sdk/src/cmp/swift/Schema_swift.ts +1 -1
- package/project/.sdk/src/cmp/ts/EntityTypes_ts.ts +5 -5
- package/project/.sdk/src/cmp/ts/ReadmeEntity_ts.ts +3 -3
- package/project/.sdk/src/cmp/ts/ReadmeModel_ts.ts +3 -3
- package/project/.sdk/src/cmp/ts/ReadmeQuick_ts.ts +1 -1
- package/project/.sdk/src/cmp/ts/ReadmeRef_ts.ts +5 -5
- package/project/.sdk/src/cmp/ts/Schema_ts.ts +1 -1
- package/project/.sdk/src/cmp/ts/TestDirect_ts.ts +40 -40
- package/project/.sdk/src/cmp/ts/TestEntity_ts.ts +72 -75
- package/project/.sdk/src/cmp/ts/TestLive_ts.ts +3 -3
- package/project/.sdk/src/cmp/ts/utility_ts.ts +5 -5
- package/project/.sdk/src/cmp/zig/ReadmeEntity_zig.ts +3 -3
- package/project/.sdk/src/cmp/zig/ReadmeModel_zig.ts +3 -3
- package/project/.sdk/src/cmp/zig/ReadmeRef_zig.ts +5 -5
- package/project/.sdk/src/cmp/zig/Schema_zig.ts +1 -1
- package/project/.sdk/tm/c/core/context.c +3 -1
- package/project/.sdk/tm/c/feature/paging.c +37 -3
- package/project/.sdk/tm/c/feature/test.c +71 -31
- package/project/.sdk/tm/c/utility/prepare_query.c +2 -1
- package/project/.sdk/tm/c/utility/transform_request.c +25 -3
- package/project/.sdk/tm/clojure/src/sdk/core.clj +21 -7
- package/project/.sdk/tm/clojure/src/sdk/features.clj +74 -22
- package/project/.sdk/tm/cpp/core/types.hpp +1 -1
- package/project/.sdk/tm/cpp/feature/paging.hpp +36 -3
- package/project/.sdk/tm/cpp/feature/test.hpp +58 -19
- package/project/.sdk/tm/cpp/utility/pipeline.hpp +16 -4
- package/project/.sdk/tm/csharp/core/Context.cs +1 -1
- package/project/.sdk/tm/csharp/feature/PagingFeature.cs +58 -4
- package/project/.sdk/tm/csharp/feature/TestFeature.cs +23 -25
- package/project/.sdk/tm/csharp/utility/Fetcher.cs +19 -12
- package/project/.sdk/tm/csharp/utility/PrepareQuery.cs +1 -1
- package/project/.sdk/tm/csharp/utility/TransformRequest.cs +23 -3
- package/project/.sdk/tm/elixir/lib/projectname/context.ex +1 -1
- package/project/.sdk/tm/elixir/lib/projectname/feature/paging.ex +52 -10
- package/project/.sdk/tm/elixir/lib/projectname/feature/test.ex +58 -22
- package/project/.sdk/tm/elixir/lib/projectname/utility.ex +30 -9
- package/project/.sdk/tm/go/core/context.go +13 -13
- package/project/.sdk/tm/go/feature/paging_feature.go +40 -2
- package/project/.sdk/tm/go/feature/test_feature.go +3 -15
- package/project/.sdk/tm/go/test/feature_corpus_test.go +1 -0
- package/project/.sdk/tm/go/test/feature_test.go +54 -0
- package/project/.sdk/tm/go/utility/fetcher.go +41 -20
- package/project/.sdk/tm/go/utility/prepare_query.go +1 -1
- package/project/.sdk/tm/go/utility/transform_request.go +22 -3
- package/project/.sdk/tm/java/core/Context.java +2 -1
- package/project/.sdk/tm/java/feature/PagingFeature.java +46 -4
- package/project/.sdk/tm/java/feature/TestFeature.java +21 -19
- package/project/.sdk/tm/java/test/FeatureCorpusTest.java +3 -0
- package/project/.sdk/tm/java/test/FeatureTest.java +42 -0
- package/project/.sdk/tm/java/utility/Fetcher.java +36 -28
- package/project/.sdk/tm/java/utility/PrepareQuery.java +1 -1
- package/project/.sdk/tm/java/utility/TransformRequest.java +18 -3
- package/project/.sdk/tm/js/src/Context.js +7 -2
- package/project/.sdk/tm/js/src/feature/paging/PagingFeature.js +24 -6
- package/project/.sdk/tm/js/src/feature/test/TestFeature.js +7 -5
- package/project/.sdk/tm/js/src/utility/PrepareQueryUtility.js +1 -1
- package/project/.sdk/tm/js/test/feature/Corpus.test.js +4 -0
- package/project/.sdk/tm/js/test/live-entity.js +29 -29
- package/project/.sdk/tm/js/test/live-scenarios.js +4 -4
- package/project/.sdk/tm/kotlin/core/Context.kt +1 -1
- package/project/.sdk/tm/kotlin/feature/PagingFeature.kt +36 -4
- package/project/.sdk/tm/kotlin/feature/TestFeature.kt +19 -18
- package/project/.sdk/tm/kotlin/utility/Fetcher.kt +33 -24
- package/project/.sdk/tm/kotlin/utility/Prepare.kt +1 -1
- package/project/.sdk/tm/kotlin/utility/ResultTransform.kt +18 -3
- package/project/.sdk/tm/lua/core/context.lua +8 -1
- package/project/.sdk/tm/lua/core/control.lua +3 -0
- package/project/.sdk/tm/lua/feature/paging_feature.lua +44 -5
- package/project/.sdk/tm/lua/feature/test_feature.lua +32 -14
- package/project/.sdk/tm/lua/utility/prepare_query.lua +2 -1
- package/project/.sdk/tm/lua/utility/transform_request.lua +19 -3
- package/project/.sdk/tm/ocaml/sdk_features.ml +78 -25
- package/project/.sdk/tm/ocaml/sdk_runtime.ml +23 -8
- package/project/.sdk/tm/perl/core/context.pm +2 -1
- package/project/.sdk/tm/perl/feature/paging_feature.pm +31 -5
- package/project/.sdk/tm/perl/feature/test_feature.pm +52 -20
- package/project/.sdk/tm/perl/feature/timeout_feature.pm +17 -13
- package/project/.sdk/tm/perl/t/feature_corpus.t +14 -1
- package/project/.sdk/tm/perl/utility/fetcher.pm +15 -1
- package/project/.sdk/tm/perl/utility/prepare_query.pm +1 -0
- package/project/.sdk/tm/perl/utility/transform_request.pm +13 -3
- package/project/.sdk/tm/php/core/Context.php +5 -1
- package/project/.sdk/tm/php/core/Control.php +5 -0
- package/project/.sdk/tm/php/feature/PagingFeature.php +26 -5
- package/project/.sdk/tm/php/feature/TestFeature.php +27 -42
- package/project/.sdk/tm/php/test/FeatureCorpusTest.php +17 -1
- package/project/.sdk/tm/php/test/FeatureTest.php +44 -0
- package/project/.sdk/tm/php/utility/Fetcher.php +17 -3
- package/project/.sdk/tm/php/utility/PrepareQuery.php +1 -1
- package/project/.sdk/tm/php/utility/TransformRequest.php +15 -3
- package/project/.sdk/tm/py/pkg/core/context.py +2 -1
- package/project/.sdk/tm/py/pkg/feature/paging_feature.py +29 -4
- package/project/.sdk/tm/py/pkg/feature/test_feature.py +29 -12
- package/project/.sdk/tm/py/pkg/utility/fetcher.py +63 -65
- package/project/.sdk/tm/py/pkg/utility/prepare_query.py +2 -1
- package/project/.sdk/tm/py/pkg/utility/transform_request.py +11 -3
- package/project/.sdk/tm/py/test/test_feature.py +27 -0
- package/project/.sdk/tm/py/test/test_feature_corpus.py +11 -1
- package/project/.sdk/tm/rb/core/context.rb +1 -1
- package/project/.sdk/tm/rb/feature/paging_feature.rb +27 -5
- package/project/.sdk/tm/rb/feature/test_feature.rb +39 -11
- package/project/.sdk/tm/rb/test/feature_corpus_test.rb +12 -1
- package/project/.sdk/tm/rb/test/feature_test.rb +38 -0
- package/project/.sdk/tm/rb/utility/fetcher.rb +49 -3
- package/project/.sdk/tm/rb/utility/prepare_query.rb +1 -1
- package/project/.sdk/tm/rb/utility/transform_request.rb +10 -3
- package/project/.sdk/tm/rust/core/context.rs +2 -6
- package/project/.sdk/tm/rust/feature/paging.rs +44 -3
- package/project/.sdk/tm/rust/feature/secrets.rs +1 -1
- package/project/.sdk/tm/rust/feature/test.rs +74 -37
- package/project/.sdk/tm/rust/utility/fetcher.rs +41 -14
- package/project/.sdk/tm/rust/utility/prepare_query.rs +1 -1
- package/project/.sdk/tm/rust/utility/transform_request.rs +31 -5
- package/project/.sdk/tm/scala/core/Context.scala +2 -1
- package/project/.sdk/tm/scala/feature/PagingFeature.scala +41 -4
- package/project/.sdk/tm/scala/feature/TestFeature.scala +21 -18
- package/project/.sdk/tm/scala/utility/Fetcher.scala +34 -13
- package/project/.sdk/tm/scala/utility/Prepare.scala +1 -1
- package/project/.sdk/tm/scala/utility/Transform.scala +19 -3
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/core/Context.swift +1 -1
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/feature/PagingFeature.swift +31 -4
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/feature/TestFeature.swift +22 -15
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/Fetcher.swift +22 -3
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/Prepare.swift +1 -1
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/ResultUtil.swift +14 -3
- package/project/.sdk/tm/ts/src/Context.ts +7 -2
- package/project/.sdk/tm/ts/src/feature/paging/PagingFeature.ts +19 -3
- package/project/.sdk/tm/ts/src/feature/test/TestFeature.ts +3 -0
- package/project/.sdk/tm/ts/src/utility/PrepareQueryUtility.ts +1 -1
- package/project/.sdk/tm/ts/test/feature/Corpus.test.ts +1 -0
- package/project/.sdk/tm/ts/test/live-entity.ts +26 -26
- package/project/.sdk/tm/ts/test/live-scenarios.ts +3 -3
- package/project/.sdk/tm/zig/core/context.zig +1 -1
- package/project/.sdk/tm/zig/core/utility.zig +19 -5
- package/project/.sdk/tm/zig/feature/paging.zig +34 -4
- package/project/.sdk/tm/zig/feature/test.zig +65 -30
- package/project/sdkgen-package.json +1 -1
- package/src/action/doctor.ts +12 -9
- package/src/action/edition.ts +8 -0
- package/src/action/feature.ts +7 -1
- package/src/action/remove.ts +492 -0
- package/src/action/target.ts +8 -1
- package/src/cmp/ReadmeTop.ts +1 -1
- package/src/cmp/ReadmeUnions.ts +1 -1
- package/src/cmp/Test.ts +1 -1
- package/src/helpers/buildIdNames.ts +17 -7
- package/src/helpers/canonSpec.ts +2 -2
- package/src/helpers/getMatchEntries.ts +2 -2
- package/src/helpers/modelNames.ts +6 -1
- package/src/helpers/opShape.ts +33 -33
- package/src/helpers/pointPath.ts +5 -10
- package/src/helpers/resolved.ts +3 -14
- package/src/sdkgen.ts +3 -1
- package/src/utility.ts +16 -7
|
@@ -109,18 +109,23 @@ public class TestFeature extends BaseFeature {
|
|
|
109
109
|
return data;
|
|
110
110
|
}
|
|
111
111
|
String spec = (String) restf;
|
|
112
|
-
//
|
|
113
|
-
//
|
|
112
|
+
// Rebuild whatever nesting the transform unwraps. Multi-segment on purpose:
|
|
113
|
+
// GraphQL ops unwrap `body.data.<field>`, not just one envelope property.
|
|
114
114
|
if (!spec.startsWith("`body.") || !spec.endsWith("`") || spec.length() < 8) {
|
|
115
115
|
return data;
|
|
116
116
|
}
|
|
117
117
|
String inner = spec.substring(6, spec.length() - 1);
|
|
118
|
-
if (inner.isEmpty()
|
|
118
|
+
if (inner.isEmpty()) {
|
|
119
119
|
return data;
|
|
120
120
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
121
|
+
String[] segs = inner.split("\\.", -1);
|
|
122
|
+
Object out = data;
|
|
123
|
+
for (int i = segs.length - 1; 0 <= i; i--) {
|
|
124
|
+
Map<String, Object> wrapped = new LinkedHashMap<>();
|
|
125
|
+
wrapped.put(segs[i], out);
|
|
126
|
+
out = wrapped;
|
|
127
|
+
}
|
|
128
|
+
return out;
|
|
124
129
|
}
|
|
125
130
|
|
|
126
131
|
private Map<String, Object> respond(Context ctx, int status, Object data, Map<String, Object> extra) {
|
|
@@ -223,19 +228,12 @@ public class TestFeature extends BaseFeature {
|
|
|
223
228
|
Object args = buildArgs(ctx, op, updateMatch);
|
|
224
229
|
List<Object> found = Struct.select(entmap, args);
|
|
225
230
|
Object ent = Struct.getelem(found, 0);
|
|
226
|
-
if (ent == null && entmap != null) {
|
|
227
|
-
for (Object e : entmap.values()) {
|
|
228
|
-
if (e instanceof Map) {
|
|
229
|
-
ent = e;
|
|
230
|
-
break;
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
231
|
if (ent == null) {
|
|
232
|
+
// update miss: 404, never another record
|
|
235
233
|
return respond(ctx, 404, null, extra("statusText", "Not found"));
|
|
236
234
|
}
|
|
237
235
|
if (ent instanceof Map && ctx.reqdata != null) {
|
|
238
|
-
((
|
|
236
|
+
Struct.merge(Struct.jt(ent, ctx.reqdata));
|
|
239
237
|
}
|
|
240
238
|
Struct.delprop(ent, "$KEY");
|
|
241
239
|
Object out = Struct.clone(ent);
|
|
@@ -369,10 +367,14 @@ public class TestFeature extends BaseFeature {
|
|
|
369
367
|
}
|
|
370
368
|
}
|
|
371
369
|
|
|
372
|
-
//
|
|
373
|
-
|
|
374
|
-
Object
|
|
375
|
-
|
|
370
|
+
// Path AND query: a path-only read misses a query-addressed record
|
|
371
|
+
// (e.g. GET /result?trace_id=), which has no path param at all.
|
|
372
|
+
List<Object> reqdArgs = Struct.jt();
|
|
373
|
+
for (String kind : new String[] { "params", "query" }) {
|
|
374
|
+
Object argsPath = Struct.getpath(point, List.of("args", kind));
|
|
375
|
+
reqdArgs.addAll(Struct.select(argsPath, Struct.jm("reqd", true)));
|
|
376
|
+
}
|
|
377
|
+
Object reqd = Struct.transform(reqdArgs,
|
|
376
378
|
Struct.jt("`$EACH`", "", "`$KEY.name`"));
|
|
377
379
|
|
|
378
380
|
List<Object> qand = Struct.jt();
|
|
@@ -405,6 +405,9 @@ public class FeatureCorpusTest {
|
|
|
405
405
|
ProjectNameSDK probe = buildClient(Map.of("feature",
|
|
406
406
|
List.of(Map.of("name", name, "active", true))));
|
|
407
407
|
if (null == record(probe, name)) {
|
|
408
|
+
// The one line every runner prints for an inert section.
|
|
409
|
+
System.err.println(String.format(
|
|
410
|
+
"feature.%s: inert (this SDK does not generate the feature)", name));
|
|
408
411
|
continue;
|
|
409
412
|
}
|
|
410
413
|
|
|
@@ -867,6 +867,48 @@ public class FeatureTest {
|
|
|
867
867
|
assertEquals(true, res.result.paging.get("hasMore"), "expected hasMore");
|
|
868
868
|
}
|
|
869
869
|
|
|
870
|
+
@Test
|
|
871
|
+
public void paging_snakeCaseSignalsAndCtrlWriteBack() {
|
|
872
|
+
assumeFeatures("paging");
|
|
873
|
+
FhRecorder rec = new FhRecorder();
|
|
874
|
+
rec.reply = (n, fetchdef) -> 1 == n
|
|
875
|
+
? fhResponse(200, fhMap("has_more", true, "next_cursor", "c2"), null)
|
|
876
|
+
: fhResponse(200, fhMap("has_more", false), null);
|
|
877
|
+
FhHarness h = fhMake(rec::fetch, fhF(new PagingFeature(), null));
|
|
878
|
+
Map<String, Object> pg = new LinkedHashMap<>();
|
|
879
|
+
Map<String, Object> ctrl = fhMap("paging", pg);
|
|
880
|
+
FhOpResult res = h.op(fhOp("list").path("/w").ctrl(ctrl));
|
|
881
|
+
assertEquals(true, res.result.paging.get("hasMore"), "expected has_more read");
|
|
882
|
+
assertEquals("c2", res.result.paging.get("cursor"), "expected next_cursor read");
|
|
883
|
+
assertEquals("c2", pg.get("cursor"), "expected record written back into ctrl");
|
|
884
|
+
assertEquals(true, pg.get("hasMore"), "expected record written back into ctrl");
|
|
885
|
+
h.op(fhOp("list").path("/w").ctrl(ctrl));
|
|
886
|
+
assertTrue(rec.url(1).contains("cursor=c2"),
|
|
887
|
+
"expected written-back cursor sent: " + rec.url(1));
|
|
888
|
+
assertEquals(false, pg.get("hasMore"), "expected ctrl to carry the last record");
|
|
889
|
+
assertNull(pg.get("cursor"), "expected ctrl to carry the last record");
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
@Test
|
|
893
|
+
public void paging_continuesFromWrittenBackNextPage() {
|
|
894
|
+
assumeFeatures("paging");
|
|
895
|
+
FhRecorder rec = new FhRecorder();
|
|
896
|
+
rec.reply = (n, fetchdef) -> fhResponse(200,
|
|
897
|
+
1 == n ? fhMap("next_page", 2) : fhMap(),
|
|
898
|
+
fhMap("x-page", String.valueOf(n)));
|
|
899
|
+
FhHarness h = fhMake(rec::fetch, fhF(new PagingFeature(), null));
|
|
900
|
+
Map<String, Object> pg = new LinkedHashMap<>();
|
|
901
|
+
Map<String, Object> ctrl = fhMap("paging", pg);
|
|
902
|
+
h.op(fhOp("list").path("/w").ctrl(ctrl));
|
|
903
|
+
assertEquals(1, pg.get("page"), "expected x-page written back");
|
|
904
|
+
assertEquals(2, pg.get("nextPage"), "expected next_page written back");
|
|
905
|
+
assertEquals(true, pg.get("hasMore"), "expected hasMore inferred from next_page");
|
|
906
|
+
h.op(fhOp("list").path("/w").ctrl(ctrl));
|
|
907
|
+
assertTrue(rec.url(1).contains("page=2"),
|
|
908
|
+
"expected written-back next page sent: " + rec.url(1));
|
|
909
|
+
assertEquals(false, pg.get("hasMore"), "expected no more pages");
|
|
910
|
+
}
|
|
911
|
+
|
|
870
912
|
@Test
|
|
871
913
|
public void paging_nonListNotPaged() {
|
|
872
914
|
assumeFeatures("paging");
|
|
@@ -9,6 +9,7 @@ import java.net.http.HttpResponse;
|
|
|
9
9
|
import java.util.LinkedHashMap;
|
|
10
10
|
import java.util.List;
|
|
11
11
|
import java.util.Map;
|
|
12
|
+
import java.util.concurrent.ConcurrentHashMap;
|
|
12
13
|
import java.util.function.BiFunction;
|
|
13
14
|
import java.util.function.Supplier;
|
|
14
15
|
|
|
@@ -20,6 +21,40 @@ final class Fetcher {
|
|
|
20
21
|
|
|
21
22
|
private Fetcher() {}
|
|
22
23
|
|
|
24
|
+
// Clients keyed by redirect policy and proxy. Each HttpClient owns a
|
|
25
|
+
// connection pool and a selector thread, so one per request reused
|
|
26
|
+
// nothing; one per key pools across calls.
|
|
27
|
+
private static final ConcurrentHashMap<String, HttpClient> CLIENTS =
|
|
28
|
+
new ConcurrentHashMap<>();
|
|
29
|
+
|
|
30
|
+
private static HttpClient clientFor(Map<String, Object> fetchdef) {
|
|
31
|
+
// "manual" (set by the station feature's middleware under a hosts
|
|
32
|
+
// policy) returns a 3xx like any other response: an automatic follow
|
|
33
|
+
// would carry injected credentials to a host no policy approved.
|
|
34
|
+
final HttpClient.Redirect redirectPolicy =
|
|
35
|
+
"manual".equals(fetchdef.get("redirect"))
|
|
36
|
+
? HttpClient.Redirect.NEVER
|
|
37
|
+
: HttpClient.Redirect.NORMAL;
|
|
38
|
+
|
|
39
|
+
Object praw = fetchdef.get("proxy");
|
|
40
|
+
final String proxy = praw instanceof String ? (String) praw : "";
|
|
41
|
+
|
|
42
|
+
return CLIENTS.computeIfAbsent(redirectPolicy + "|" + proxy, key -> {
|
|
43
|
+
HttpClient.Builder clientb = HttpClient.newBuilder().followRedirects(redirectPolicy);
|
|
44
|
+
if (!"".equals(proxy)) {
|
|
45
|
+
try {
|
|
46
|
+
URI proxyUri = URI.create(proxy);
|
|
47
|
+
int port = proxyUri.getPort() < 0 ? 80 : proxyUri.getPort();
|
|
48
|
+
clientb.proxy(ProxySelector.of(new InetSocketAddress(proxyUri.getHost(), port)));
|
|
49
|
+
}
|
|
50
|
+
catch (RuntimeException e) {
|
|
51
|
+
// Unparseable proxy target: direct connection, as the go transport.
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return clientb.build();
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
23
58
|
static Map<String, Object> defaultHttpFetch(String fullurl, Map<String, Object> fetchdef) {
|
|
24
59
|
String method = fetchdef.get("method") instanceof String
|
|
25
60
|
? (String) fetchdef.get("method") : "";
|
|
@@ -59,36 +94,9 @@ final class Fetcher {
|
|
|
59
94
|
reqb.setHeader("User-Agent", "Mozilla/5.0 (compatible; ProjectNameSDK/1.0)");
|
|
60
95
|
}
|
|
61
96
|
|
|
62
|
-
// Honour a redirect annotation on the fetch definition (set by the
|
|
63
|
-
// station feature's middleware under a hosts policy): "manual" returns
|
|
64
|
-
// a 3xx like any other response instead of following it — the ts
|
|
65
|
-
// donor's fetch honours the same key natively, and an automatic follow
|
|
66
|
-
// would carry injected credentials to a host no policy approved.
|
|
67
|
-
HttpClient.Redirect redirectPolicy =
|
|
68
|
-
"manual".equals(fetchdef.get("redirect"))
|
|
69
|
-
? HttpClient.Redirect.NEVER
|
|
70
|
-
: HttpClient.Redirect.NORMAL;
|
|
71
|
-
|
|
72
|
-
// Honour a proxy annotation on the fetch definition (set by the proxy
|
|
73
|
-
// feature): route the request through a proxied HttpClient.
|
|
74
|
-
HttpClient.Builder clientb = HttpClient.newBuilder()
|
|
75
|
-
.followRedirects(redirectPolicy);
|
|
76
|
-
Object proxy = fetchdef.get("proxy");
|
|
77
|
-
if (proxy instanceof String && !"".equals(proxy)) {
|
|
78
|
-
try {
|
|
79
|
-
URI proxyUri = URI.create((String) proxy);
|
|
80
|
-
int port = proxyUri.getPort() < 0 ? 80 : proxyUri.getPort();
|
|
81
|
-
clientb.proxy(ProxySelector.of(new InetSocketAddress(proxyUri.getHost(), port)));
|
|
82
|
-
}
|
|
83
|
-
catch (RuntimeException e) {
|
|
84
|
-
// Unparseable proxy target: fall through to a direct connection,
|
|
85
|
-
// mirroring the go transport (bad proxy URL is ignored).
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
97
|
HttpResponse<String> resp;
|
|
90
98
|
try {
|
|
91
|
-
resp =
|
|
99
|
+
resp = clientFor(fetchdef).send(reqb.build(), HttpResponse.BodyHandlers.ofString());
|
|
92
100
|
}
|
|
93
101
|
catch (Exception e) {
|
|
94
102
|
throw new RuntimeException("fetch: " + e.getMessage(), e);
|
|
@@ -35,7 +35,7 @@ final class PrepareQuery {
|
|
|
35
35
|
for (List<Object> item : Struct.items(reqmatch)) {
|
|
36
36
|
String key = item.get(0) instanceof String ? (String) item.get(0) : "";
|
|
37
37
|
Object val = item.get(1);
|
|
38
|
-
if (val != null && !containsStr(params, key)) {
|
|
38
|
+
if (val != null && !"$action".equals(key) && !containsStr(params, key)) {
|
|
39
39
|
out.put(key, val);
|
|
40
40
|
}
|
|
41
41
|
}
|
|
@@ -19,17 +19,32 @@ final class TransformRequest {
|
|
|
19
19
|
Map<String, Object> transform =
|
|
20
20
|
Helpers.toMapAny(Struct.getprop(ctx.point, "transform"));
|
|
21
21
|
if (transform == null) {
|
|
22
|
-
return ctx.reqdata;
|
|
22
|
+
return stripAction(ctx.reqdata);
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
Object reqform = Struct.getprop(transform, "req", null);
|
|
26
26
|
if (reqform == null) {
|
|
27
|
-
return ctx.reqdata;
|
|
27
|
+
return stripAction(ctx.reqdata);
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
Map<String, Object> data = new LinkedHashMap<>();
|
|
31
31
|
data.put("reqdata", ctx.reqdata);
|
|
32
32
|
|
|
33
|
-
return Struct.transform(data, reqform);
|
|
33
|
+
return stripAction(Struct.transform(data, reqform));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// `$action` selects the point (see MakePoint); it is never an API field, so
|
|
37
|
+
// the body is a copy without it. The caller's map is left untouched.
|
|
38
|
+
private static Object stripAction(Object reqdata) {
|
|
39
|
+
if (!(reqdata instanceof Map) || !((Map<?, ?>) reqdata).containsKey("$action")) {
|
|
40
|
+
return reqdata;
|
|
41
|
+
}
|
|
42
|
+
Map<String, Object> body = new LinkedHashMap<>();
|
|
43
|
+
for (Map.Entry<?, ?> e : ((Map<?, ?>) reqdata).entrySet()) {
|
|
44
|
+
if (!"$action".equals(e.getKey())) {
|
|
45
|
+
body.put(String.valueOf(e.getKey()), e.getValue());
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return body;
|
|
34
49
|
}
|
|
35
50
|
}
|
|
@@ -57,7 +57,13 @@ class Context {
|
|
|
57
57
|
this.client = getprop(ctxmap, 'client', getprop(basectx, 'client'))
|
|
58
58
|
this.utility = getprop(ctxmap, 'utility', getprop(basectx, 'utility'))
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
// An operation gets its OWN control unless the caller passed one: a
|
|
61
|
+
// paging cursor left on the client's control would otherwise be picked
|
|
62
|
+
// up by the next, unrelated call. A context with no opname is not an
|
|
63
|
+
// operation, so it still shares (an entity's, with the client's).
|
|
64
|
+
const opname = getprop(ctxmap, 'opname')
|
|
65
|
+
const basectrl = null == opname ? getprop(basectx, 'ctrl', this.ctrl) : this.ctrl
|
|
66
|
+
this.ctrl = getprop(ctxmap, 'ctrl', basectrl)
|
|
61
67
|
this.meta = getprop(ctxmap, 'meta', getprop(basectx, 'meta', this.meta))
|
|
62
68
|
|
|
63
69
|
this.config = getprop(ctxmap, 'config', getprop(basectx, 'config'))
|
|
@@ -78,7 +84,6 @@ class Context {
|
|
|
78
84
|
this.result = getprop(ctxmap, 'result', getprop(basectx, 'result'))
|
|
79
85
|
this.response = getprop(ctxmap, 'response', getprop(basectx, 'response'))
|
|
80
86
|
|
|
81
|
-
const opname = getprop(ctxmap, 'opname')
|
|
82
87
|
this.op = this.resolveOp(opname)
|
|
83
88
|
}
|
|
84
89
|
|
|
@@ -7,8 +7,9 @@ const { BaseFeature } = require('../base/BaseFeature')
|
|
|
7
7
|
// stamps page/limit (or a cursor) into the request query; on the way back
|
|
8
8
|
// (PreResult) it reads the server's pagination signals — a `Link:
|
|
9
9
|
// rel="next"` header, `X-Next-Page`/`X-Total-Count` headers, or `next`/
|
|
10
|
-
// `cursor`/`hasMore` fields in the body
|
|
11
|
-
// `ctx.result.paging
|
|
10
|
+
// `cursor`/`hasMore` fields in the body (snake_case forms too) — and
|
|
11
|
+
// records them on `ctx.result.paging` and the caller's `ctrl.paging`.
|
|
12
|
+
// Generated SDKs build auto-iteration on top of this
|
|
12
13
|
// (advance the cursor/page and re-issue the list call until `hasMore` is
|
|
13
14
|
// false). Parameter names and page size are configurable.
|
|
14
15
|
class PagingFeature extends BaseFeature {
|
|
@@ -28,7 +29,7 @@ class PagingFeature extends BaseFeature {
|
|
|
28
29
|
|
|
29
30
|
|
|
30
31
|
PreRequest(ctx) {
|
|
31
|
-
if (!this._isList(ctx)) {
|
|
32
|
+
if (!this.active || !this._isList(ctx)) {
|
|
32
33
|
return
|
|
33
34
|
}
|
|
34
35
|
const spec = ctx.spec
|
|
@@ -58,7 +59,10 @@ class PagingFeature extends BaseFeature {
|
|
|
58
59
|
spec.query[cursorParam] = paging.cursor
|
|
59
60
|
}
|
|
60
61
|
else if (null == spec.query[pageParam]) {
|
|
61
|
-
|
|
62
|
+
// A record written back by PreResult holds the page just fetched as
|
|
63
|
+
// `page` and the one to fetch as `nextPage`, so nextPage wins.
|
|
64
|
+
spec.query[pageParam] = null != paging.nextPage ? paging.nextPage :
|
|
65
|
+
null != paging.page ? paging.page : (this._options.startPage || 1)
|
|
62
66
|
}
|
|
63
67
|
|
|
64
68
|
if (null != this._options.limit && null == spec.query[limitParam]) {
|
|
@@ -68,7 +72,7 @@ class PagingFeature extends BaseFeature {
|
|
|
68
72
|
|
|
69
73
|
|
|
70
74
|
PreResult(ctx) {
|
|
71
|
-
if (!this._isList(ctx)) {
|
|
75
|
+
if (!this.active || !this._isList(ctx)) {
|
|
72
76
|
return
|
|
73
77
|
}
|
|
74
78
|
const result = ctx.result
|
|
@@ -124,11 +128,20 @@ class PagingFeature extends BaseFeature {
|
|
|
124
128
|
}
|
|
125
129
|
}
|
|
126
130
|
|
|
127
|
-
// Body-level
|
|
131
|
+
// Body-level signals; snake_case forms are read first so camelCase wins.
|
|
128
132
|
if (body && 'object' === typeof body) {
|
|
129
133
|
if (null != body.next) { paging.next = paging.next || body.next }
|
|
134
|
+
if (null != body.next_cursor) { paging.cursor = body.next_cursor }
|
|
130
135
|
if (null != body.cursor) { paging.cursor = body.cursor }
|
|
131
136
|
if (null != body.nextCursor) { paging.cursor = body.nextCursor }
|
|
137
|
+
if (null == paging.nextPage) {
|
|
138
|
+
const np = null != body.nextPage ? body.nextPage : body.next_page
|
|
139
|
+
if ('number' === typeof np || 'string' === typeof np) { paging.nextPage = np }
|
|
140
|
+
}
|
|
141
|
+
if ('boolean' === typeof body.has_more) {
|
|
142
|
+
paging.hasMore = body.has_more
|
|
143
|
+
explicitMore = true
|
|
144
|
+
}
|
|
132
145
|
if ('boolean' === typeof body.hasMore) {
|
|
133
146
|
paging.hasMore = body.hasMore
|
|
134
147
|
explicitMore = true
|
|
@@ -147,6 +160,11 @@ class PagingFeature extends BaseFeature {
|
|
|
147
160
|
|
|
148
161
|
result.paging = paging
|
|
149
162
|
|
|
163
|
+
// ctx.ctrl is the caller's own object, so the record reaches them.
|
|
164
|
+
if (null != ctx.ctrl) {
|
|
165
|
+
ctx.ctrl.paging = paging
|
|
166
|
+
}
|
|
167
|
+
|
|
150
168
|
const client = this._client
|
|
151
169
|
client._paging = { last: paging }
|
|
152
170
|
}
|
|
@@ -148,6 +148,7 @@ class TestFeature extends BaseFeature {
|
|
|
148
148
|
const found = select(entmap, args)
|
|
149
149
|
const ent = getelem(found, 0)
|
|
150
150
|
if (null == ent) {
|
|
151
|
+
// update miss: 404, never another record
|
|
151
152
|
return respond(404, undefined, { statusText: S_NOT_FOUND })
|
|
152
153
|
}
|
|
153
154
|
else {
|
|
@@ -161,13 +162,12 @@ class TestFeature extends BaseFeature {
|
|
|
161
162
|
const args = self.buildArgs(ctx, op, ctx.reqmatch)
|
|
162
163
|
const found = select(entmap, args)
|
|
163
164
|
const ent = getelem(found, 0)
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
else {
|
|
165
|
+
// Remove only the first matched entity. If nothing matches,
|
|
166
|
+
// succeed as a no-op rather than erroring.
|
|
167
|
+
if (null != ent) {
|
|
168
168
|
delprop(entmap, getprop(ent, 'id'))
|
|
169
|
-
return respond(200)
|
|
170
169
|
}
|
|
170
|
+
return respond(200)
|
|
171
171
|
}
|
|
172
172
|
else if ('create' === op.name) {
|
|
173
173
|
const args = self.buildArgs(ctx, op, ctx.reqdata)
|
|
@@ -183,6 +183,8 @@ class TestFeature extends BaseFeature {
|
|
|
183
183
|
const out = clone(ent)
|
|
184
184
|
return respond(200, out)
|
|
185
185
|
}
|
|
186
|
+
|
|
187
|
+
return respond(404, undefined, { statusText: 'Unknown operation' })
|
|
186
188
|
}
|
|
187
189
|
|
|
188
190
|
// Optional network behaviour simulation over the mock transport. Enable
|
|
@@ -254,6 +254,10 @@ describe('FeatureCorpus', () => {
|
|
|
254
254
|
|
|
255
255
|
const probe = makeClient({})
|
|
256
256
|
if (!probe._rootctx.config.hasFeature(name)) {
|
|
257
|
+
// The one line every runner prints for a section that names a
|
|
258
|
+
// feature this SDK does not generate, so an inert section is
|
|
259
|
+
// visible in the output rather than inferred from a green tick.
|
|
260
|
+
t.diagnostic(`feature.${name}: inert (this SDK does not generate the feature)`)
|
|
257
261
|
return t.skip(`this SDK was generated without the ${name} feature`)
|
|
258
262
|
}
|
|
259
263
|
|
|
@@ -10,26 +10,26 @@ const live_runner_1 = require("./live-runner");
|
|
|
10
10
|
const utility_1 = require("./utility");
|
|
11
11
|
// The offline flow keeps its deterministic fixture assertions. Live flows
|
|
12
12
|
// resolve real prerequisites per operation and collect failures until done.
|
|
13
|
-
async function runLiveEntity(setup, entity, flow, accessor) {
|
|
13
|
+
async function runLiveEntity(setup, entity, flow, accessor, facts = {}) {
|
|
14
14
|
const { client, transport } = setup;
|
|
15
|
-
const steps = flow.step || [];
|
|
15
|
+
const steps = (flow.step || []).filter((step) => false !== step.a);
|
|
16
16
|
const created = new Map();
|
|
17
17
|
const listed = [];
|
|
18
18
|
const marks = new Map();
|
|
19
19
|
const idField = entity.id?.field || 'id';
|
|
20
20
|
const copy = (value) => JSON.parse(JSON.stringify(value ?? {}));
|
|
21
|
-
const hasCreate = steps.some(step => step.
|
|
21
|
+
const hasCreate = steps.some(step => step.o === 'create');
|
|
22
22
|
const report = await (0, live_runner_1.runLiveSteps)(steps.map((step, index) => {
|
|
23
|
-
const ref = step.
|
|
24
|
-
const op = step.
|
|
23
|
+
const ref = step.i?.ref || entity.name + '_ref01';
|
|
24
|
+
const op = step.o;
|
|
25
25
|
const excluded = (0, utility_1.isControlSkipped)('entityOp', entity.name + '.' + op, 'live');
|
|
26
26
|
return {
|
|
27
27
|
id: entity.name + '.' + op + '.' + index,
|
|
28
|
-
cleanup: op === 'remove' || (step.
|
|
28
|
+
cleanup: op === 'remove' || (step.v || []).some((v) => v.apply === 'ItemNotExists'),
|
|
29
29
|
excluded: excluded.skip ? excluded.reason || 'Excluded by test control' : undefined,
|
|
30
30
|
run: async (context) => {
|
|
31
31
|
transport.enter(context);
|
|
32
|
-
const points = entity.op?.[op]?.points || [];
|
|
32
|
+
const points = (entity.op?.[op]?.points || []).filter((point) => false !== point.a);
|
|
33
33
|
if (!points.length)
|
|
34
34
|
throw new live_runner_1.LiveBlocked('No modelled operation point');
|
|
35
35
|
const record = created.get(ref);
|
|
@@ -48,7 +48,7 @@ async function runLiveEntity(setup, entity, flow, accessor) {
|
|
|
48
48
|
}
|
|
49
49
|
let input = op === 'create'
|
|
50
50
|
? copy(setup.data.new?.[entity.name]?.[ref]) : {};
|
|
51
|
-
for (const [name, binding] of Object.entries({ ...step.
|
|
51
|
+
for (const [name, binding] of Object.entries({ ...step.m, ...step.d })) {
|
|
52
52
|
const value = setup.idmap[binding] ?? setup.idmap[name];
|
|
53
53
|
if (undefined !== value)
|
|
54
54
|
input[name] = value;
|
|
@@ -66,22 +66,22 @@ async function runLiveEntity(setup, entity, flow, accessor) {
|
|
|
66
66
|
let selected;
|
|
67
67
|
const missing = new Set();
|
|
68
68
|
for (const point of points) {
|
|
69
|
-
if (point.
|
|
69
|
+
if (point.q?.$action !== input.$action)
|
|
70
70
|
continue;
|
|
71
71
|
const candidate = { ...input };
|
|
72
72
|
let viable = true;
|
|
73
|
-
const params = point.
|
|
74
|
-
const query = (point.
|
|
73
|
+
const params = point.g?.params || [];
|
|
74
|
+
const query = (point.g?.query || []).filter((arg) => arg.r);
|
|
75
75
|
for (const arg of [...params, ...query]) {
|
|
76
|
-
if (undefined !== candidate[arg.
|
|
76
|
+
if (undefined !== candidate[arg.n] && null !== candidate[arg.n])
|
|
77
77
|
continue;
|
|
78
|
-
const key = arg.
|
|
79
|
-
const value = setup.idmap[key] ?? setup.idmap[arg.
|
|
78
|
+
const key = arg.n === 'id' ? entity.name + '01' : arg.n.replace(/_id$/, '') + '01';
|
|
79
|
+
const value = setup.idmap[key] ?? setup.idmap[arg.n] ?? loaded?.[arg.n] ?? arg.ex;
|
|
80
80
|
if (undefined !== value && null !== value)
|
|
81
|
-
candidate[arg.
|
|
82
|
-
else if (arg.
|
|
81
|
+
candidate[arg.n] = value;
|
|
82
|
+
else if (arg.r !== false) {
|
|
83
83
|
viable = false;
|
|
84
|
-
missing.add(arg.
|
|
84
|
+
missing.add(arg.n);
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
if (viable) {
|
|
@@ -93,22 +93,22 @@ async function runLiveEntity(setup, entity, flow, accessor) {
|
|
|
93
93
|
if (!resolved)
|
|
94
94
|
throw new live_runner_1.LiveBlocked('No usable route; missing arguments: ' + [...missing].join(', '));
|
|
95
95
|
input = resolved;
|
|
96
|
-
if (op === 'create' && selected.
|
|
97
|
-
const
|
|
98
|
-
const request = (0, live_contract_1.requestContract)(
|
|
96
|
+
if (op === 'create' && facts[selected.m + ' ' + selected.o]) {
|
|
97
|
+
const selectedFacts = facts[selected.m + ' ' + selected.o];
|
|
98
|
+
const request = (0, live_contract_1.requestContract)(selectedFacts);
|
|
99
99
|
if (request.schema)
|
|
100
|
-
input = { ...(0, live_contract_1.synthesizeInput)(request.schema,
|
|
101
|
-
else if (
|
|
100
|
+
input = { ...(0, live_contract_1.synthesizeInput)(request.schema, selected.li?.input ?? request.example) };
|
|
101
|
+
else if (selectedFacts.protocol === 'http')
|
|
102
102
|
input = {};
|
|
103
|
-
for (const arg of selected.
|
|
104
|
-
if (resolved[arg.
|
|
105
|
-
input[arg.
|
|
103
|
+
for (const arg of selected.g?.params || [])
|
|
104
|
+
if (resolved[arg.n] !== undefined)
|
|
105
|
+
input[arg.n] = resolved[arg.n];
|
|
106
106
|
}
|
|
107
107
|
let intendedMark;
|
|
108
108
|
if (op === 'update') {
|
|
109
|
-
for (const spec of step.
|
|
110
|
-
if (spec.apply === 'TextFieldMark' && step.
|
|
111
|
-
const mark = { name: step.
|
|
109
|
+
for (const spec of step.s || []) {
|
|
110
|
+
if (spec.apply === 'TextFieldMark' && step.i?.textfield) {
|
|
111
|
+
const mark = { name: step.i.textfield, value: spec.def.mark + '_' + setup.now };
|
|
112
112
|
input[mark.name] = mark.value;
|
|
113
113
|
intendedMark = mark;
|
|
114
114
|
}
|
|
@@ -127,7 +127,7 @@ async function runLiveEntity(setup, entity, flow, accessor) {
|
|
|
127
127
|
});
|
|
128
128
|
listed.splice(0, listed.length, ...data);
|
|
129
129
|
context.publish(data);
|
|
130
|
-
for (const validation of step.
|
|
130
|
+
for (const validation of step.v || []) {
|
|
131
131
|
const previous = created.get(validation.def?.ref);
|
|
132
132
|
const id = previous?.[idField] ?? previous?.id;
|
|
133
133
|
if (undefined === id)
|
|
@@ -64,10 +64,10 @@ async function runLiveScenarios(SDK, plan, envPrefix, liveDefaults = {}) {
|
|
|
64
64
|
let input = request.schema ? (0, live_contract_1.synthesizeInput)(request.schema, explicit) : explicit ?? {};
|
|
65
65
|
for (const kind of ['params', 'query', 'header', 'cookie'])
|
|
66
66
|
for (const arg of point.args?.[kind] || []) {
|
|
67
|
-
if (arg.
|
|
68
|
-
if (arg.
|
|
69
|
-
throw new live_runner_1.LiveBlocked('Missing required argument: ' + arg.
|
|
70
|
-
input[arg.
|
|
67
|
+
if (arg.r && input[arg.n] === undefined) {
|
|
68
|
+
if (arg.ex === undefined)
|
|
69
|
+
throw new live_runner_1.LiveBlocked('Missing required argument: ' + arg.n);
|
|
70
|
+
input[arg.n] = arg.ex;
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
73
|
const role = hint.auth || (point.facts.security?.length === 0 || point.facts.securitySource === 'unspecified' ? 'public' : 'account');
|
|
@@ -76,7 +76,7 @@ class Context(ctxmap: MutableMap<String, Any?>?, basectx: Context?) {
|
|
|
76
76
|
} else if (cv is Control) {
|
|
77
77
|
this.ctrl = cv
|
|
78
78
|
}
|
|
79
|
-
} else if (basectx != null) {
|
|
79
|
+
} else if (basectx != null && Helpers.getCtxProp(ctxmap, "opname") == null) {
|
|
80
80
|
this.ctrl = basectx.ctrl
|
|
81
81
|
}
|
|
82
82
|
|
|
@@ -8,8 +8,9 @@ import KOTLINPACKAGE.utility.struct.Struct
|
|
|
8
8
|
|
|
9
9
|
// Pagination support for list operations. On the way out (PreRequest) it
|
|
10
10
|
// stamps page/limit (or a cursor) into the request query; on the way back
|
|
11
|
-
// (PreResult) it reads the server's pagination signals and
|
|
12
|
-
// `ctx.result.paging
|
|
11
|
+
// (PreResult) it reads the server's pagination signals (camelCase and
|
|
12
|
+
// snake_case body forms) and records them on `ctx.result.paging` and the
|
|
13
|
+
// caller's `ctrl.paging`.
|
|
13
14
|
@Suppress("UNCHECKED_CAST")
|
|
14
15
|
class PagingFeature : BaseFeature("paging", "0.0.1", true) {
|
|
15
16
|
|
|
@@ -53,7 +54,9 @@ class PagingFeature : BaseFeature("paging", "0.0.1", true) {
|
|
|
53
54
|
if (cursor != null) {
|
|
54
55
|
spec.query[cursorParam] = cursor
|
|
55
56
|
} else if (spec.query[pageParam] == null) {
|
|
56
|
-
|
|
57
|
+
// A record written back by preResult holds the page just fetched as
|
|
58
|
+
// "page" and the one to fetch as "nextPage", so nextPage wins.
|
|
59
|
+
val page = paging["nextPage"] ?: paging["page"]
|
|
57
60
|
if (page != null) {
|
|
58
61
|
spec.query[pageParam] = page
|
|
59
62
|
} else {
|
|
@@ -166,18 +169,33 @@ class PagingFeature : BaseFeature("paging", "0.0.1", true) {
|
|
|
166
169
|
}
|
|
167
170
|
}
|
|
168
171
|
|
|
169
|
-
// Body-level
|
|
172
|
+
// Body-level signals; snake_case forms are read first so camelCase wins.
|
|
170
173
|
if (body is MutableMap<*, *>) {
|
|
171
174
|
val bm = body as MutableMap<String, Any?>
|
|
172
175
|
if (bm["next"] != null && paging["next"] == null) {
|
|
173
176
|
paging["next"] = bm["next"]
|
|
174
177
|
}
|
|
178
|
+
if (bm["next_cursor"] != null) {
|
|
179
|
+
paging["cursor"] = bm["next_cursor"]
|
|
180
|
+
}
|
|
175
181
|
if (bm["cursor"] != null) {
|
|
176
182
|
paging["cursor"] = bm["cursor"]
|
|
177
183
|
}
|
|
178
184
|
if (bm["nextCursor"] != null) {
|
|
179
185
|
paging["cursor"] = bm["nextCursor"]
|
|
180
186
|
}
|
|
187
|
+
if (paging["nextPage"] == null) {
|
|
188
|
+
val np = bm["nextPage"] ?: bm["next_page"]
|
|
189
|
+
if (np is Number) {
|
|
190
|
+
paging["nextPage"] = np.toInt()
|
|
191
|
+
} else if (np is String) {
|
|
192
|
+
paging["nextPage"] = np
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
if (bm["has_more"] is Boolean) {
|
|
196
|
+
paging["hasMore"] = bm["has_more"]
|
|
197
|
+
explicitMore = true
|
|
198
|
+
}
|
|
181
199
|
if (bm["hasMore"] is Boolean) {
|
|
182
200
|
paging["hasMore"] = bm["hasMore"]
|
|
183
201
|
explicitMore = true
|
|
@@ -197,6 +215,20 @@ class PagingFeature : BaseFeature("paging", "0.0.1", true) {
|
|
|
197
215
|
|
|
198
216
|
result.paging = paging
|
|
199
217
|
this.last = paging
|
|
218
|
+
|
|
219
|
+
// The Context shares the caller's paging map by reference, so refill it
|
|
220
|
+
// in place; an immutable map falls back to replacing the reference.
|
|
221
|
+
val shared = ctx.ctrl.paging
|
|
222
|
+
if (shared == null) {
|
|
223
|
+
ctx.ctrl.paging = paging
|
|
224
|
+
} else {
|
|
225
|
+
try {
|
|
226
|
+
shared.clear()
|
|
227
|
+
shared.putAll(paging)
|
|
228
|
+
} catch (e: UnsupportedOperationException) {
|
|
229
|
+
ctx.ctrl.paging = paging
|
|
230
|
+
}
|
|
231
|
+
}
|
|
200
232
|
}
|
|
201
233
|
|
|
202
234
|
private fun isList(ctx: Context): Boolean {
|