@voxgig/sdkgen 3.5.1 → 3.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/cmp/AgentGuideTop.js +17 -0
- package/dist/cmp/AgentGuideTop.js.map +1 -1
- package/dist/cmp/ExternalTarget.js +1 -1
- package/dist/cmp/ExternalTarget.js.map +1 -1
- package/dist/cmp/Readme.js +2 -0
- package/dist/cmp/Readme.js.map +1 -1
- package/dist/cmp/ReadmeStation.d.ts +2 -0
- package/dist/cmp/ReadmeStation.js +57 -0
- package/dist/cmp/ReadmeStation.js.map +1 -0
- package/dist/helpers/naming.d.ts +6 -1
- package/dist/helpers/naming.js +156 -5
- package/dist/helpers/naming.js.map +1 -1
- package/dist/helpers/opShape.js +72 -0
- package/dist/helpers/opShape.js.map +1 -1
- package/dist/helpers/packageMeta.d.ts +2 -1
- package/dist/helpers/packageMeta.js +57 -20
- package/dist/helpers/packageMeta.js.map +1 -1
- package/dist/sdkgen.d.ts +3 -3
- package/dist/sdkgen.js +63 -18
- package/dist/sdkgen.js.map +1 -1
- package/dist/testkit.d.ts +39 -0
- package/dist/testkit.js +663 -0
- package/dist/testkit.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utility.d.ts +1 -1
- package/dist/utility.js +16 -2
- package/dist/utility.js.map +1 -1
- package/package.json +32 -8
- package/project/.sdk/src/cmp/c/Config_c.ts +34 -13
- package/project/.sdk/src/cmp/c/Test_c.ts +5 -7
- package/project/.sdk/src/cmp/clojure/Test_clojure.ts +3 -7
- package/project/.sdk/src/cmp/cpp/Config_cpp.ts +9 -46
- package/project/.sdk/src/cmp/cpp/Test_cpp.ts +4 -7
- package/project/.sdk/src/cmp/csharp/Config_csharp.ts +7 -1
- package/project/.sdk/src/cmp/csharp/Package_csharp.ts +1 -1
- package/project/.sdk/src/cmp/csharp/Test_csharp.ts +5 -7
- package/project/.sdk/src/cmp/dart/Config_dart.ts +14 -2
- package/project/.sdk/src/cmp/dart/Test_dart.ts +3 -4
- package/project/.sdk/src/cmp/dart/fragment/Config.data.fragment.dart +5 -0
- package/project/.sdk/src/cmp/dart/fragment/Config.fragment.dart +6 -0
- package/project/.sdk/src/cmp/dart/fragment/Main.fragment.dart +13 -4
- package/project/.sdk/src/cmp/elixir/Config_elixir.ts +12 -2
- package/project/.sdk/src/cmp/elixir/Package_elixir.ts +42 -3
- package/project/.sdk/src/cmp/elixir/Test_elixir.ts +5 -6
- package/project/.sdk/src/cmp/go/Config_go.ts +8 -1
- package/project/.sdk/src/cmp/go/EntityTypes_go.ts +1 -1
- package/project/.sdk/src/cmp/go/Entity_go.ts +1 -1
- package/project/.sdk/src/cmp/go/Gitignore_go.ts +6 -0
- package/project/.sdk/src/cmp/go/Main_go.ts +2 -2
- package/project/.sdk/src/cmp/go/Package_go.ts +1 -1
- package/project/.sdk/src/cmp/go/ReadmeExamplesTest_go.ts +59 -6
- package/project/.sdk/src/cmp/go/ReadmeExplanation_go.ts +1 -1
- package/project/.sdk/src/cmp/go/ReadmeHowto_go.ts +1 -1
- package/project/.sdk/src/cmp/go/ReadmeInstall_go.ts +1 -1
- package/project/.sdk/src/cmp/go/ReadmeModel_go.ts +1 -1
- package/project/.sdk/src/cmp/go/ReadmeQuick_go.ts +1 -1
- package/project/.sdk/src/cmp/go/ReadmeTopQuick_go.ts +1 -1
- package/project/.sdk/src/cmp/go/ReadmeTopTest_go.ts +1 -1
- package/project/.sdk/src/cmp/go/Test_go.ts +6 -8
- package/project/.sdk/src/cmp/go-cli/Main_go-cli.ts +6 -2
- package/project/.sdk/src/cmp/go-mcp/Main_go-mcp.ts +6 -2
- package/project/.sdk/src/cmp/java/Config_java.ts +8 -1
- package/project/.sdk/src/cmp/java/Test_java.ts +4 -7
- package/project/.sdk/src/cmp/js/Config_js.ts +9 -1
- package/project/.sdk/src/cmp/js/Package_js.ts +1 -1
- package/project/.sdk/src/cmp/js/Test_js.ts +4 -7
- package/project/.sdk/src/cmp/js/fragment/Config.data.fragment.js +7 -0
- package/project/.sdk/src/cmp/js/fragment/Config.fragment.js +8 -0
- package/project/.sdk/src/cmp/js/fragment/Main.fragment.js +33 -5
- package/project/.sdk/src/cmp/kotlin/Config_kotlin.ts +8 -1
- package/project/.sdk/src/cmp/kotlin/Test_kotlin.ts +4 -7
- package/project/.sdk/src/cmp/lean/Test_lean.ts +3 -3
- package/project/.sdk/src/cmp/lua/Config_lua.ts +11 -2
- package/project/.sdk/src/cmp/lua/Package_lua.ts +26 -3
- package/project/.sdk/src/cmp/lua/Test_lua.ts +5 -7
- package/project/.sdk/src/cmp/ocaml/Test_ocaml.ts +3 -7
- package/project/.sdk/src/cmp/perl/Config_perl.ts +8 -60
- package/project/.sdk/src/cmp/perl/Package_perl.ts +1 -1
- package/project/.sdk/src/cmp/perl/Test_perl.ts +5 -7
- package/project/.sdk/src/cmp/php/Config_php.ts +11 -2
- package/project/.sdk/src/cmp/php/EntityTypes_php.ts +13 -2
- package/project/.sdk/src/cmp/php/Main_php.ts +25 -0
- package/project/.sdk/src/cmp/php/Package_php.ts +2 -2
- package/project/.sdk/src/cmp/php/Test_php.ts +5 -7
- package/project/.sdk/src/cmp/php/fragment/Main.fragment.php +23 -6
- package/project/.sdk/src/cmp/py/Config_py.ts +11 -2
- package/project/.sdk/src/cmp/py/Main_py.ts +17 -7
- package/project/.sdk/src/cmp/py/Package_py.ts +2 -2
- package/project/.sdk/src/cmp/py/Test_py.ts +5 -7
- package/project/.sdk/src/cmp/py/fragment/Main.fragment.py +23 -6
- package/project/.sdk/src/cmp/py-data/Main_py-data.ts +14 -19
- package/project/.sdk/src/cmp/rb/Config_rb.ts +7 -1
- package/project/.sdk/src/cmp/rb/Package_rb.ts +3 -3
- package/project/.sdk/src/cmp/rb/ReadmeInstall_rb.ts +1 -1
- package/project/.sdk/src/cmp/rb/Test_rb.ts +5 -7
- package/project/.sdk/src/cmp/rust/Config_rust.ts +5 -2
- package/project/.sdk/src/cmp/rust/Test_rust.ts +5 -7
- package/project/.sdk/src/cmp/scala/Test_scala.ts +5 -2
- package/project/.sdk/src/cmp/seneca-provider/Gitignore_seneca-provider.ts +161 -0
- package/project/.sdk/src/cmp/seneca-provider/Main_seneca-provider.ts +20 -11
- package/project/.sdk/src/cmp/swift/Config_swift.ts +8 -54
- package/project/.sdk/src/cmp/swift/Package_swift.ts +52 -10
- package/project/.sdk/src/cmp/swift/Test_swift.ts +5 -7
- package/project/.sdk/src/cmp/ts/Config_ts.ts +9 -1
- package/project/.sdk/src/cmp/ts/EntityTypes_ts.ts +5 -2
- package/project/.sdk/src/cmp/ts/Entity_ts.ts +8 -2
- package/project/.sdk/src/cmp/ts/Package_ts.ts +1 -1
- package/project/.sdk/src/cmp/ts/Test_ts.ts +8 -7
- package/project/.sdk/src/cmp/ts/fragment/Config.data.fragment.ts +7 -0
- package/project/.sdk/src/cmp/ts/fragment/Config.fragment.ts +8 -0
- package/project/.sdk/src/cmp/ts/fragment/Entity.fragment.ts +1 -1
- package/project/.sdk/src/cmp/ts/fragment/Main.fragment.ts +12 -4
- package/project/.sdk/src/cmp/zig/Test_zig.ts +3 -7
- package/project/.sdk/tm/c/Makefile +6 -1
- package/project/.sdk/tm/c/utility/make_options.c +12 -1
- package/project/.sdk/tm/c/utility/make_point.c +64 -3
- package/project/.sdk/tm/clojure/src/sdk/core.clj +49 -14
- package/project/.sdk/tm/cpp/utility/pipeline.hpp +64 -4
- package/project/.sdk/tm/csharp/feature/TestFeature.cs +36 -2
- package/project/.sdk/tm/csharp/utility/Fetcher.cs +23 -5
- package/project/.sdk/tm/csharp/utility/MakeOptions.cs +13 -0
- package/project/.sdk/tm/csharp/utility/MakePoint.cs +65 -2
- package/project/.sdk/tm/dart/lib/feature/test/TestFeature.dart +34 -4
- package/project/.sdk/tm/dart/lib/utility/FetcherUtility.dart +9 -0
- package/project/.sdk/tm/dart/lib/utility/MakeOptionsUtility.dart +17 -0
- package/project/.sdk/tm/dart/lib/utility/MakePointUtility.dart +48 -2
- package/project/.sdk/tm/elixir/lib/projectname/utility.ex +109 -13
- package/project/.sdk/tm/elixir/test/feature_test.exs +19 -0
- package/project/.sdk/tm/elixir/test/primary_utility_test.exs +72 -0
- package/project/.sdk/tm/go/feature/test_feature.go +34 -2
- package/project/.sdk/tm/go/test/primary_utility_test.go +42 -20
- package/project/.sdk/tm/go/test/runner_test.go +1 -1
- package/project/.sdk/tm/go/utility/fetcher.go +14 -0
- package/project/.sdk/tm/go/utility/make_options.go +31 -4
- package/project/.sdk/tm/go/utility/make_point.go +66 -2
- package/project/.sdk/tm/java/feature/TestFeature.java +42 -2
- package/project/.sdk/tm/java/utility/Fetcher.java +11 -1
- package/project/.sdk/tm/java/utility/MakeOptions.java +11 -0
- package/project/.sdk/tm/java/utility/MakePoint.java +61 -2
- package/project/.sdk/tm/js/src/feature/test/TestFeature.js +22 -3
- package/project/.sdk/tm/js/src/utility/MakeOptionsUtility.js +20 -2
- package/project/.sdk/tm/js/src/utility/MakePointUtility.js +72 -2
- package/project/.sdk/tm/kotlin/feature/TestFeature.kt +31 -2
- package/project/.sdk/tm/kotlin/utility/Fetcher.kt +10 -1
- package/project/.sdk/tm/kotlin/utility/MakeOptions.kt +11 -0
- package/project/.sdk/tm/kotlin/utility/MakePoint.kt +58 -2
- package/project/.sdk/tm/lean/src/SdkUtility.lean +28 -0
- package/project/.sdk/tm/lean/test/TPrimaryUtility.lean +13 -2
- package/project/.sdk/tm/lua/utility/make_options.lua +44 -0
- package/project/.sdk/tm/lua/utility/make_point.lua +65 -2
- package/project/.sdk/tm/ocaml/sdk_runtime.ml +40 -2
- package/project/.sdk/tm/perl/utility/fetcher.pm +10 -1
- package/project/.sdk/tm/perl/utility/make_options.pm +36 -0
- package/project/.sdk/tm/perl/utility/make_point.pm +55 -2
- package/project/.sdk/tm/php/feature/TestFeature.php +30 -1
- package/project/.sdk/tm/php/test/PipelineTest.php +20 -0
- package/project/.sdk/tm/php/utility/Fetcher.php +12 -1
- package/project/.sdk/tm/php/utility/MakeOptions.php +58 -0
- package/project/.sdk/tm/php/utility/MakePoint.php +49 -1
- package/project/.sdk/tm/py/pkg/utility/fetcher.py +13 -1
- package/project/.sdk/tm/py/pkg/utility/make_options.py +23 -0
- package/project/.sdk/tm/py/pkg/utility/make_point.py +56 -2
- package/project/.sdk/tm/rb/utility/make_options.rb +18 -0
- package/project/.sdk/tm/rb/utility/make_point.rb +42 -2
- package/project/.sdk/tm/rust/tests/common/mod.rs +1 -1
- package/project/.sdk/tm/rust/tests/feature_test.rs +27 -0
- package/project/.sdk/tm/rust/utility/fetcher.rs +8 -0
- package/project/.sdk/tm/rust/utility/make_options.rs +15 -0
- package/project/.sdk/tm/rust/utility/make_point.rs +69 -2
- package/project/.sdk/tm/scala/feature/TestFeature.scala +36 -1
- package/project/.sdk/tm/scala/utility/Make.scala +57 -3
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/feature/TestFeature.swift +29 -1
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/Fetcher.swift +24 -1
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/Make.swift +51 -2
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/MakeOptions.swift +12 -0
- package/project/.sdk/tm/ts/src/feature/test/TestFeature.ts +22 -3
- package/project/.sdk/tm/ts/src/utility/MakeOptionsUtility.ts +20 -2
- package/project/.sdk/tm/ts/src/utility/MakePointUtility.ts +72 -2
- package/project/.sdk/tm/ts/test/utility/Corpus.test.ts +85 -0
- package/project/.sdk/tm/ts/test/utility/PrimaryUtility.test.ts +10 -17
- package/project/.sdk/tm/zig/core/utility.zig +66 -3
- package/project/sdkgen-package.json +1 -2
- package/src/cmp/AgentGuideTop.ts +18 -0
- package/src/cmp/ExternalTarget.ts +1 -1
- package/src/cmp/Readme.ts +2 -0
- package/src/cmp/ReadmeStation.ts +69 -0
- package/src/helpers/naming.ts +172 -5
- package/src/helpers/opShape.ts +85 -0
- package/src/helpers/packageMeta.ts +59 -20
- package/src/sdkgen.ts +70 -20
- package/src/testkit.ts +863 -0
- package/src/utility.ts +17 -2
- package/testkit.d.ts +3 -0
- package/testkit.js +12 -0
- package/project/.sdk/model/target/haskell.aontu +0 -72
- package/project/.sdk/src/cmp/haskell/Config_haskell.ts +0 -98
- package/project/.sdk/src/cmp/haskell/Entity_haskell.ts +0 -13
- package/project/.sdk/src/cmp/haskell/Gitignore_haskell.ts +0 -27
- package/project/.sdk/src/cmp/haskell/Main_haskell.ts +0 -123
- package/project/.sdk/src/cmp/haskell/Package_haskell.ts +0 -60
- package/project/.sdk/src/cmp/haskell/ReadmeEntity_haskell.ts +0 -186
- package/project/.sdk/src/cmp/haskell/ReadmeExamplesTest_haskell.ts +0 -135
- package/project/.sdk/src/cmp/haskell/ReadmeExplanation_haskell.ts +0 -48
- package/project/.sdk/src/cmp/haskell/ReadmeHowto_haskell.ts +0 -168
- package/project/.sdk/src/cmp/haskell/ReadmeInstall_haskell.ts +0 -51
- package/project/.sdk/src/cmp/haskell/ReadmeIntro_haskell.ts +0 -67
- package/project/.sdk/src/cmp/haskell/ReadmeModel_haskell.ts +0 -162
- package/project/.sdk/src/cmp/haskell/ReadmeOptions_haskell.ts +0 -74
- package/project/.sdk/src/cmp/haskell/ReadmeQuick_haskell.ts +0 -241
- package/project/.sdk/src/cmp/haskell/ReadmeRef_haskell.ts +0 -408
- package/project/.sdk/src/cmp/haskell/ReadmeTopHowto_haskell.ts +0 -31
- package/project/.sdk/src/cmp/haskell/ReadmeTopQuick_haskell.ts +0 -104
- package/project/.sdk/src/cmp/haskell/ReadmeTopTest_haskell.ts +0 -80
- package/project/.sdk/src/cmp/haskell/Test_haskell.ts +0 -300
- package/project/.sdk/src/cmp/haskell/tsconfig.json +0 -15
- package/project/.sdk/src/cmp/haskell/utility_haskell.ts +0 -166
- package/project/.sdk/tm/haskell/LICENSE +0 -21
- package/project/.sdk/tm/haskell/Makefile +0 -22
- package/project/.sdk/tm/haskell/VERSION +0 -1
- package/project/.sdk/tm/haskell/src/SdkFeatures.hs +0 -1440
- package/project/.sdk/tm/haskell/src/SdkHelpers.hs +0 -337
- package/project/.sdk/tm/haskell/src/SdkJson.hs +0 -111
- package/project/.sdk/tm/haskell/src/SdkRuntime.hs +0 -1219
- package/project/.sdk/tm/haskell/src/SdkTypes.hs +0 -195
- package/project/.sdk/tm/haskell/src/VoxgigStruct.hs +0 -2299
- package/project/.sdk/tm/haskell/src/Vregex.hs +0 -237
- package/project/.sdk/tm/haskell/src/feature/README.md +0 -5
- package/project/.sdk/tm/haskell/src/feature/audit/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/base/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/cache/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/clienttrack/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/debug/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/idempotency/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/log/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/metrics/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/netsim/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/paging/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/proxy/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/ratelimit/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/rbac/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/retry/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/streaming/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/telemetry/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/test/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/timeout/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/test/Harness.hs +0 -281
- package/project/.sdk/tm/haskell/test/Runner.hs +0 -47
- package/project/.sdk/tm/haskell/test/StructCorpus.hs +0 -449
- package/project/.sdk/tm/haskell/test/TCustomUtility.hs +0 -38
- package/project/.sdk/tm/haskell/test/TFeature.hs +0 -794
- package/project/.sdk/tm/haskell/test/TNetsim.hs +0 -50
- package/project/.sdk/tm/haskell/test/TPipeline.hs +0 -334
- package/project/.sdk/tm/haskell/test/TPrimaryUtility.hs +0 -386
- package/project/.sdk/tm/haskell/test/Testutil.hs +0 -59
|
@@ -3,9 +3,8 @@ import {
|
|
|
3
3
|
Content,
|
|
4
4
|
File,
|
|
5
5
|
cmp,
|
|
6
|
+
configDefinition,
|
|
6
7
|
each,
|
|
7
|
-
isAuthActive,
|
|
8
|
-
resolveAuthPrefix,
|
|
9
8
|
} from '@voxgig/sdkgen'
|
|
10
9
|
|
|
11
10
|
|
|
@@ -16,11 +15,6 @@ import {
|
|
|
16
15
|
} from '@voxgig/apidef'
|
|
17
16
|
|
|
18
17
|
|
|
19
|
-
import {
|
|
20
|
-
clean,
|
|
21
|
-
} from './utility_swift'
|
|
22
|
-
|
|
23
|
-
|
|
24
18
|
// Generates core/Config.swift: the SdkConfig enum holding the generated model
|
|
25
19
|
// config (makeConfig, materialised at runtime by parsing an embedded JSON
|
|
26
20
|
// literal - pure data, so a JSON round-trip is faithful and avoids emitting
|
|
@@ -32,59 +26,19 @@ const Config = cmp(async function Config(props: any) {
|
|
|
32
26
|
|
|
33
27
|
const model: Model = ctx$.model
|
|
34
28
|
|
|
35
|
-
const entity = getModelPath(model, `main.${KIT}.entity`)
|
|
36
29
|
const feature = getModelPath(model, `main.${KIT}.feature`)
|
|
37
30
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
try { baseUrl = getModelPath(model, `main.${KIT}.info.servers.0.url`) } catch (_e) { }
|
|
45
|
-
|
|
46
|
-
// Assemble the config object (pure JSON data).
|
|
47
|
-
const featureConfigs: any = {}
|
|
48
|
-
each(feature, (f: any) => {
|
|
49
|
-
featureConfigs[f.name] = f.config || {}
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
const optionsEntity: any = {}
|
|
53
|
-
each(entity, (ent: any) => {
|
|
54
|
-
optionsEntity[ent.name] = {}
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
const entityDefs: any = {}
|
|
58
|
-
each(entity, (ent: any) => {
|
|
59
|
-
entityDefs[ent.name] = clean({
|
|
60
|
-
fields: ent.fields,
|
|
61
|
-
name: ent.name,
|
|
62
|
-
op: ent.op,
|
|
63
|
-
relations: ent.relations,
|
|
64
|
-
}, true)
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
const options: any = {
|
|
68
|
-
base: baseUrl,
|
|
69
|
-
headers,
|
|
70
|
-
entity: optionsEntity,
|
|
71
|
-
}
|
|
72
|
-
if (authActive) {
|
|
73
|
-
options.auth = { prefix: authPrefix }
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const configObj = {
|
|
77
|
-
main: { name: model.const.Name },
|
|
78
|
-
feature: featureConfigs,
|
|
79
|
-
options,
|
|
80
|
-
entity: entityDefs,
|
|
81
|
-
}
|
|
31
|
+
// The config as data, built by the shared helper so every target embeds
|
|
32
|
+
// the same model by construction. Passing target.name opts this target
|
|
33
|
+
// into main.slug / main.version / main.target (the three station
|
|
34
|
+
// descriptor identity fields, station design §4); swift has only the
|
|
35
|
+
// JSON-literal rep, so that one call covers every rep this target emits.
|
|
36
|
+
const { json } = configDefinition(model, target.name)
|
|
82
37
|
|
|
83
38
|
// Model-data defaults may carry the ProjectName placeholder (e.g. the
|
|
84
39
|
// clienttrack clientName); resolve it to the API name so the embedded JSON
|
|
85
40
|
// matches the token-replaced runtime.
|
|
86
|
-
const configJson =
|
|
87
|
-
.replace(/ProjectName/g, model.const.Name)
|
|
41
|
+
const configJson = json.replace(/ProjectName/g, model.const.Name)
|
|
88
42
|
|
|
89
43
|
File({ name: 'Config.' + target.ext }, () => {
|
|
90
44
|
|
|
@@ -17,8 +17,30 @@ import type {
|
|
|
17
17
|
// under Sources/ProjectNameSDK (the copied runtime + generated sources); the
|
|
18
18
|
// test target compiles Tests/ProjectNameSDKTests. Directory names are the
|
|
19
19
|
// verbatim copied paths (Copy does not rewrite path components); the target
|
|
20
|
-
// NAMES carry the API name.
|
|
21
|
-
//
|
|
20
|
+
// NAMES carry the API name.
|
|
21
|
+
//
|
|
22
|
+
// Dependencies: the runtime itself is dependency-free (Foundation + the
|
|
23
|
+
// vendored struct), but declared target/feature deps flow into the manifest
|
|
24
|
+
// via collectDeps. SwiftPM cannot name a package by product alone, so a
|
|
25
|
+
// swift deps entry carries its coordinates in a documented convention:
|
|
26
|
+
//
|
|
27
|
+
// deps: swift: {
|
|
28
|
+
// 'VoxgigStation': { active: true, version: '0.0.1', kind: prod,
|
|
29
|
+
// url: 'https://github.com/voxgig/station-swift' }
|
|
30
|
+
// }
|
|
31
|
+
//
|
|
32
|
+
// - the entry KEY is the SwiftPM PRODUCT name (also the module the
|
|
33
|
+
// generated source imports);
|
|
34
|
+
// - the extra `url` field is the git repository SwiftPM resolves
|
|
35
|
+
// (`.package(url:from:)`); the package identity SwiftPM derives from it
|
|
36
|
+
// is the URL's last path component (minus any .git), which is what the
|
|
37
|
+
// `.product(name:package:)` reference must use;
|
|
38
|
+
// - `version` feeds `from:` - a plain semver (any leading range operator
|
|
39
|
+
// like '>=' is stripped, since `from:` already means >=).
|
|
40
|
+
//
|
|
41
|
+
// An entry WITHOUT a `url` is not expressible in a SwiftPM manifest (no
|
|
42
|
+
// registry-less by-name dependencies), so it is skipped - unadorned entries
|
|
43
|
+
// keep today's zero-dependency output.
|
|
22
44
|
const Package = cmp(async function Package(props: any) {
|
|
23
45
|
const ctx$ = props.ctx$
|
|
24
46
|
const target = props.target
|
|
@@ -27,28 +49,48 @@ const Package = cmp(async function Package(props: any) {
|
|
|
27
49
|
|
|
28
50
|
const Name = model.const.Name
|
|
29
51
|
|
|
30
|
-
|
|
52
|
+
type SwiftDep = { product: string, url: string, from: string, identity: string }
|
|
53
|
+
const deps: SwiftDep[] = []
|
|
31
54
|
for (const d of collectDeps(model, target.name, target.deps, ctx$.log)) {
|
|
32
|
-
|
|
55
|
+
const url = 'string' === typeof (d.raw as any)?.url ? (d.raw as any).url : ''
|
|
56
|
+
if ('' === url) {
|
|
57
|
+
continue
|
|
58
|
+
}
|
|
59
|
+
const from = (d.version || '0.0.0').replace(/^[^0-9]+/, '')
|
|
60
|
+
const identity = (url.split('/').pop() || '').replace(/\.git$/, '')
|
|
61
|
+
deps.push({ product: d.name, url, from, identity })
|
|
33
62
|
}
|
|
34
|
-
|
|
35
|
-
|
|
63
|
+
|
|
64
|
+
const pkgdeps = 0 === deps.length ? '' :
|
|
65
|
+
'\n dependencies: [\n' +
|
|
66
|
+
deps.map((d) =>
|
|
67
|
+
` .package(url: "${d.url}", from: "${d.from}"),\n`).join('') +
|
|
68
|
+
' ],'
|
|
69
|
+
|
|
70
|
+
const targetdeps = 0 === deps.length ? '' :
|
|
71
|
+
'\n dependencies: [\n' +
|
|
72
|
+
deps.map((d) =>
|
|
73
|
+
` .product(name: "${d.product}", package: "${d.identity}"),\n`)
|
|
74
|
+
.join('') +
|
|
75
|
+
' ],'
|
|
36
76
|
|
|
37
77
|
File({ name: 'Package.swift' }, () => {
|
|
38
78
|
Content(`// swift-tools-version:5.9
|
|
39
79
|
//
|
|
40
|
-
// ${Name} SDK - SwiftPM manifest.
|
|
41
|
-
// the vendored Voxgig Struct port under
|
|
80
|
+
// ${Name} SDK - SwiftPM manifest. The runtime itself is dependency-free
|
|
81
|
+
// (Foundation + the vendored Voxgig Struct port under
|
|
82
|
+
// Sources/ProjectNameSDK/Struct); declared feature/target deps (if any)
|
|
83
|
+
// appear below.
|
|
42
84
|
import PackageDescription
|
|
43
85
|
|
|
44
86
|
let package = Package(
|
|
45
87
|
name: "${Name}Sdk",
|
|
46
88
|
products: [
|
|
47
89
|
.library(name: "${Name}Sdk", targets: ["${Name}Sdk"]),
|
|
48
|
-
]
|
|
90
|
+
],${pkgdeps}
|
|
49
91
|
targets: [
|
|
50
92
|
.target(
|
|
51
|
-
name: "${Name}Sdk"
|
|
93
|
+
name: "${Name}Sdk",${targetdeps}
|
|
52
94
|
path: "Sources/ProjectNameSDK"),
|
|
53
95
|
.testTarget(
|
|
54
96
|
name: "${Name}SdkTests",
|
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
|
|
2
|
-
import {
|
|
3
|
-
KIT,
|
|
4
|
-
getModelPath
|
|
5
|
-
} from '@voxgig/apidef'
|
|
6
|
-
|
|
7
2
|
import type {
|
|
8
3
|
ModelEntity
|
|
9
4
|
} from '@voxgig/apidef'
|
|
10
5
|
|
|
11
|
-
import { cmp, each, Folder } from '@voxgig/sdkgen'
|
|
6
|
+
import { cmp, each, Folder, entityCollection } from '@voxgig/sdkgen'
|
|
12
7
|
|
|
13
8
|
|
|
14
9
|
import { TestEntity } from './TestEntity_swift'
|
|
@@ -26,7 +21,10 @@ const Test = cmp(function Test(props: any) {
|
|
|
26
21
|
// are generated here.
|
|
27
22
|
Folder({ name: 'Tests' }, () => {
|
|
28
23
|
Folder({ name: 'ProjectNameSDKTests' }, () => {
|
|
29
|
-
each(
|
|
24
|
+
const entity = each(entityCollection(model))
|
|
25
|
+
.filter((e: any) => false !== e.active)
|
|
26
|
+
|
|
27
|
+
each(entity, (entity: ModelEntity) => {
|
|
30
28
|
TestEntity({ target, entity })
|
|
31
29
|
TestDirect({ target, entity })
|
|
32
30
|
})
|
|
@@ -81,7 +81,7 @@ const Config = cmp(async function Config(props: any) {
|
|
|
81
81
|
// literal and the data that replaces it above the threshold are the same
|
|
82
82
|
// config by construction. The JSON is what the threshold is measured on -
|
|
83
83
|
// emitted source size varies by language, the model does not.
|
|
84
|
-
const { json: configJson } = configDefinition(model)
|
|
84
|
+
const { def: configDef, json: configJson } = configDefinition(model, target.name)
|
|
85
85
|
const asData = isConfigData(configJson, configReprSetting(model))
|
|
86
86
|
|
|
87
87
|
File({ name: 'Config.' + target.ext }, () => {
|
|
@@ -128,6 +128,14 @@ const Config = cmp(async function Config(props: any) {
|
|
|
128
128
|
`'./feature/${f.name}/${nom(f, 'Name')}Feature'`)
|
|
129
129
|
}),
|
|
130
130
|
|
|
131
|
+
// Values from configDefinition's def, not re-derived here, so the
|
|
132
|
+
// literal rep and the data rep cannot disagree on identity.
|
|
133
|
+
'// #MainMeta': () => {
|
|
134
|
+
Line(` slug: ${JSON.stringify(configDef.main.slug)},`)
|
|
135
|
+
Line(` version: ${JSON.stringify(configDef.main.version)},`)
|
|
136
|
+
Line(` target: ${JSON.stringify(configDef.main.target)},`)
|
|
137
|
+
},
|
|
138
|
+
|
|
131
139
|
'// #FeatureClasses': () => each(feature, (f: any) => {
|
|
132
140
|
// Trailing comma: the map has one entry per feature, so entries
|
|
133
141
|
// must be comma-separated (a single feature hid this until now).
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
File, Content,
|
|
22
22
|
} from '@voxgig/sdkgen'
|
|
23
23
|
|
|
24
|
-
import { canonToType, opTypeName, opRequestShape, warnEntityTypeCollisions , deriveEntityNames, opActions } from '@voxgig/sdkgen'
|
|
24
|
+
import { canonToType, opTypeName, opRequestShape, warnEntityTypeCollisions , deriveEntityNames, opActions, tsSafeTypeName } from '@voxgig/sdkgen'
|
|
25
25
|
|
|
26
26
|
import {
|
|
27
27
|
KIT,
|
|
@@ -74,11 +74,14 @@ const EntityTypes = cmp(function EntityTypes(props: any) {
|
|
|
74
74
|
|
|
75
75
|
entityList.forEach((ent: any) => {
|
|
76
76
|
const Name = ent.Name
|
|
77
|
+
// A TS/JS global (Record, Array, Promise, ...) would shadow itself
|
|
78
|
+
// for the rest of the file — see tsSafeTypeName.
|
|
79
|
+
const TypeName = tsSafeTypeName(Name)
|
|
77
80
|
const fields = (ent.fields ? each(ent.fields) : [])
|
|
78
81
|
.filter((f: any) => f.active !== false)
|
|
79
82
|
|
|
80
83
|
// Entity data model: one property per field, `req:false` -> optional.
|
|
81
|
-
Content(`export interface ${
|
|
84
|
+
Content(`export interface ${TypeName} {
|
|
82
85
|
`)
|
|
83
86
|
fields.forEach((f: any) => {
|
|
84
87
|
const opt = false === f.req ? '?' : ''
|
|
@@ -4,7 +4,7 @@ import * as Path from 'node:path'
|
|
|
4
4
|
import {
|
|
5
5
|
cmp, each, camelify, names,
|
|
6
6
|
File, Content, Folder, Fragment, Line, FeatureHook, Slot,
|
|
7
|
-
opTypeName, entityClassName, entityCollection,
|
|
7
|
+
opTypeName, entityClassName, entityCollection, tsSafeTypeName,
|
|
8
8
|
} from '@voxgig/sdkgen'
|
|
9
9
|
|
|
10
10
|
import {
|
|
@@ -33,9 +33,14 @@ const Entity = cmp(function Entity(props: any) {
|
|
|
33
33
|
|
|
34
34
|
names(entrep, entity.Name, 'EntityName')
|
|
35
35
|
|
|
36
|
+
// A TS/JS global (Record, Array, Promise, ...) would shadow itself for
|
|
37
|
+
// the rest of the file — see tsSafeTypeName. The runtime `this.Name`
|
|
38
|
+
// string stays entity.Name; only the TYPE reference is ever renamed.
|
|
39
|
+
const dataType = tsSafeTypeName(entity.Name)
|
|
40
|
+
|
|
36
41
|
// Import exactly the typed models this entity references: its data type plus
|
|
37
42
|
// one request type per ACTIVE op (matches what EntityTypes_ts.ts emits).
|
|
38
|
-
const typeNames = [
|
|
43
|
+
const typeNames = [dataType]
|
|
39
44
|
const opnamesAll = Object.keys(entity.op || {})
|
|
40
45
|
;['load', 'list', 'create', 'update', 'remove'].forEach((opname: string) => {
|
|
41
46
|
if (opnamesAll.includes(opname)) {
|
|
@@ -69,6 +74,7 @@ const Entity = cmp(function Entity(props: any) {
|
|
|
69
74
|
entityname: entity.name,
|
|
70
75
|
SdkName: model.const.Name,
|
|
71
76
|
EntityName: entity.Name,
|
|
77
|
+
EntityDataType: dataType,
|
|
72
78
|
|
|
73
79
|
// Class token decoupled from the EntityName data-type token in
|
|
74
80
|
// Entity.fragment.ts so the class can be renamed independently.
|
|
@@ -61,7 +61,7 @@ const Package = cmp(async function Package(props: any) {
|
|
|
61
61
|
const { repoUrl, issuesUrl } = repoInfo(model)
|
|
62
62
|
|
|
63
63
|
const pkg = {
|
|
64
|
-
name: packageName(model,
|
|
64
|
+
name: packageName(model, target.name),
|
|
65
65
|
version: packageVersion(model, target.name),
|
|
66
66
|
description: pkgDescription(model, target.name),
|
|
67
67
|
keywords: keywords(model),
|
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
|
|
2
|
-
import {
|
|
3
|
-
KIT,
|
|
4
|
-
getModelPath
|
|
5
|
-
} from '@voxgig/apidef'
|
|
6
|
-
|
|
7
2
|
import type {
|
|
8
3
|
ModelEntity
|
|
9
4
|
} from '@voxgig/apidef'
|
|
10
5
|
|
|
11
|
-
import { cmp, each, Folder } from '@voxgig/sdkgen'
|
|
6
|
+
import { cmp, each, Folder, entityCollection } from '@voxgig/sdkgen'
|
|
12
7
|
|
|
13
8
|
|
|
14
9
|
// import { Quick } from './Quick_ts'
|
|
@@ -31,7 +26,13 @@ const Test = cmp(function Test(props: any) {
|
|
|
31
26
|
ReadmeExamplesTest({ target })
|
|
32
27
|
|
|
33
28
|
Folder({ name: 'entity' }, () => {
|
|
34
|
-
|
|
29
|
+
// entityCollection is the cached, UNFILTERED collection (AGENTS.md), so
|
|
30
|
+
// the active filter the raw model read this replaced never applied is
|
|
31
|
+
// written out here. Tests follow Main: an inactive entity has no source.
|
|
32
|
+
const entity = each(entityCollection(model))
|
|
33
|
+
.filter((e: any) => false !== e.active)
|
|
34
|
+
|
|
35
|
+
each(entity, (entity: ModelEntity) => {
|
|
35
36
|
TestEntity({ target, entity })
|
|
36
37
|
TestDirect({ target, entity })
|
|
37
38
|
})
|
|
@@ -34,6 +34,13 @@ class Config {
|
|
|
34
34
|
return fi
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
// False for a feature added at runtime via options.extend (station's
|
|
38
|
+
// adopt path) - the constructor uses this to skip makeFeature for names
|
|
39
|
+
// no generated class backs.
|
|
40
|
+
hasFeature(this: any, fn: string) {
|
|
41
|
+
return null != FEATURE_CLASS[fn]
|
|
42
|
+
}
|
|
43
|
+
|
|
37
44
|
}
|
|
38
45
|
|
|
39
46
|
|
|
@@ -17,9 +17,17 @@ class Config {
|
|
|
17
17
|
return fi
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
// False for a feature added at runtime via options.extend (station's
|
|
21
|
+
// adopt path) - the constructor uses this to skip makeFeature for names
|
|
22
|
+
// no generated class backs.
|
|
23
|
+
hasFeature(this: any, fn: string) {
|
|
24
|
+
return null != FEATURE_CLASS[fn]
|
|
25
|
+
}
|
|
26
|
+
|
|
20
27
|
|
|
21
28
|
main = {
|
|
22
29
|
name: '$$const.Name$$',
|
|
30
|
+
// #MainMeta
|
|
23
31
|
}
|
|
24
32
|
|
|
25
33
|
|
|
@@ -18,7 +18,7 @@ import type {
|
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
// TODO: needs Entity superclass
|
|
21
|
-
class EntyClass extends ProjectNameEntityBase<
|
|
21
|
+
class EntyClass extends ProjectNameEntityBase<EntityDataType> {
|
|
22
22
|
|
|
23
23
|
constructor(client: ProjectNameSDK, entopts: any) {
|
|
24
24
|
super(client, entopts)
|
|
@@ -52,18 +52,26 @@ class ProjectNameSDK {
|
|
|
52
52
|
// the `test` feature installs the base mock transport and the transport
|
|
53
53
|
// features (retry/cache/netsim/proxy/ratelimit) wrap whatever is current,
|
|
54
54
|
// so `test` must be added before them to sit at the base of the chain.
|
|
55
|
+
const extend = this._options.extend || []
|
|
56
|
+
|
|
55
57
|
const featureorder = getpath(this._options, '__derived__.featureorder') || []
|
|
56
58
|
for (const fname of featureorder) {
|
|
57
59
|
const fopts = this._options.feature[fname] || {}
|
|
58
60
|
if (fopts.active) {
|
|
61
|
+
// An active name with no generated class is legal when an
|
|
62
|
+
// extend-supplied instance carries that name (station's adopt
|
|
63
|
+
// path): the instance is added below, positioned by its own
|
|
64
|
+
// __after__ entry, so skip it here rather than fail construction.
|
|
65
|
+
if (!this._rootctx.config.hasFeature(fname) &&
|
|
66
|
+
extend.some((f: any) => fname === f.name)) {
|
|
67
|
+
continue
|
|
68
|
+
}
|
|
59
69
|
featureAdd(this._rootctx, this._rootctx.config.makeFeature(fname))
|
|
60
70
|
}
|
|
61
71
|
}
|
|
62
72
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
featureAdd(this._rootctx, f)
|
|
66
|
-
}
|
|
73
|
+
for (let f of extend) {
|
|
74
|
+
featureAdd(this._rootctx, f)
|
|
67
75
|
}
|
|
68
76
|
|
|
69
77
|
for (let f of this._features) {
|
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
|
|
2
|
-
import {
|
|
3
|
-
KIT,
|
|
4
|
-
getModelPath
|
|
5
|
-
} from '@voxgig/apidef'
|
|
6
|
-
|
|
7
2
|
import type {
|
|
8
3
|
ModelEntity
|
|
9
4
|
} from '@voxgig/apidef'
|
|
10
5
|
|
|
11
|
-
import { cmp, each, Folder, File, Content } from '@voxgig/sdkgen'
|
|
6
|
+
import { cmp, each, Folder, File, Content, entityCollection } from '@voxgig/sdkgen'
|
|
12
7
|
|
|
13
8
|
import { TestEntity } from './TestEntity_zig'
|
|
14
9
|
import { TestDirect } from './TestDirect_zig'
|
|
@@ -30,7 +25,8 @@ const Test = cmp(function Test(props: any) {
|
|
|
30
25
|
const { model } = props.ctx$
|
|
31
26
|
const { target } = props
|
|
32
27
|
|
|
33
|
-
const entity =
|
|
28
|
+
const entity = each(entityCollection(model))
|
|
29
|
+
.filter((e: any) => false !== e.active)
|
|
34
30
|
|
|
35
31
|
Folder({ name: 'test' }, () => {
|
|
36
32
|
File({ name: 'generated_test.' + target.ext }, () => {
|
|
@@ -7,7 +7,12 @@ CFLAGS ?= -std=c11 -Wall -Wextra -Wno-unused-parameter -D_GNU_SOURCE -O0 -g
|
|
|
7
7
|
INC := -I core -I utility/struct
|
|
8
8
|
LDLIBS := -lm
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
# feature/*/*.c: a feature may carry a vendored library payload in its own
|
|
11
|
+
# subdirectory (the station feature vendors voxgig_station there - C has no
|
|
12
|
+
# package registry, so tier-C libraries ride the feature source; see
|
|
13
|
+
# utility/struct/ for the same precedent at the utility level). Empty when
|
|
14
|
+
# no feature ships one.
|
|
15
|
+
LIB_SRCS := $(wildcard core/*.c utility/*.c utility/struct/*.c feature/*.c feature/*/*.c entity/*.c)
|
|
11
16
|
LIB_OBJS := $(LIB_SRCS:.c=.o)
|
|
12
17
|
|
|
13
18
|
TEST_SRCS := $(wildcard tests/*.c)
|
|
@@ -166,8 +166,19 @@ voxgig_value* make_options_util(Context* ctx) {
|
|
|
166
166
|
if (has_test) {
|
|
167
167
|
voxgig_list_push(voxgig_as_list(feature_order), v_str("test"));
|
|
168
168
|
}
|
|
169
|
+
// Station special case, mirroring test's: its transport wrap must
|
|
170
|
+
// sit immediately outside the base transport (inside retry/cache/
|
|
171
|
+
// netsim), so map-form activation hoists it to just after test -
|
|
172
|
+
// or first, when no test entry exists. Without this the sorted
|
|
173
|
+
// default would init station last and wrap OUTSIDE the recording
|
|
174
|
+
// features, turning its wire-truth events into fiction.
|
|
169
175
|
for (size_t i = 0; i < fn; i++) {
|
|
170
|
-
if (strcmp(names[i], "
|
|
176
|
+
if (strcmp(names[i], "station") == 0) {
|
|
177
|
+
voxgig_list_push(voxgig_as_list(feature_order), v_str("station"));
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
for (size_t i = 0; i < fn; i++) {
|
|
181
|
+
if (strcmp(names[i], "test") != 0 && strcmp(names[i], "station") != 0) {
|
|
171
182
|
voxgig_list_push(voxgig_as_list(feature_order), v_str(names[i]));
|
|
172
183
|
}
|
|
173
184
|
}
|
|
@@ -13,6 +13,29 @@ static voxgig_value* get_elem_i(voxgig_value* list, int64_t i) {
|
|
|
13
13
|
return r ? r : voxgig_new_undef();
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
// How many path segments a point has.
|
|
17
|
+
static size_t parts_len(voxgig_value* point) {
|
|
18
|
+
voxgig_value* parts = getp(point, "parts");
|
|
19
|
+
return voxgig_is_list(parts) ? voxgig_as_list(parts)->len : 0;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Does this point's path end in a parameter? A record route ends in the
|
|
23
|
+
// record's identifier (/boards/{id}); a cross-reference that also returns
|
|
24
|
+
// the entity ends in the relationship's name (/posts/{id}/author). That,
|
|
25
|
+
// then fewest segments, is what tells the entity's own route from a
|
|
26
|
+
// cross-reference. The same rule runs at generation time, in
|
|
27
|
+
// helpers/opShape.ts — both sides must move together.
|
|
28
|
+
static bool terminal_param(voxgig_value* point) {
|
|
29
|
+
voxgig_value* parts = getp(point, "parts");
|
|
30
|
+
if (!voxgig_is_list(parts)) return false;
|
|
31
|
+
voxgig_list* pl = voxgig_as_list(parts);
|
|
32
|
+
if (0 == pl->len) return false;
|
|
33
|
+
voxgig_value* last = pl->items[pl->len - 1];
|
|
34
|
+
if (!voxgig_is_string(last)) return false;
|
|
35
|
+
const char* s = voxgig_as_string(last);
|
|
36
|
+
return NULL != s && '{' == s[0];
|
|
37
|
+
}
|
|
38
|
+
|
|
16
39
|
voxgig_value* make_point_util(Context* ctx, PNError** err) {
|
|
17
40
|
*err = NULL;
|
|
18
41
|
|
|
@@ -58,9 +81,10 @@ voxgig_value* make_point_util(Context* ctx, PNError** err) {
|
|
|
58
81
|
voxgig_value* selector = is_data ? ctx->data : ctx->mtch;
|
|
59
82
|
|
|
60
83
|
voxgig_value* point = voxgig_new_undef();
|
|
84
|
+
bool matched = false;
|
|
61
85
|
for (int64_t i = 0; i < plen; i++) {
|
|
62
|
-
|
|
63
|
-
voxgig_value* select_def = to_map(getp(
|
|
86
|
+
voxgig_value* cand = get_elem_i(points, i);
|
|
87
|
+
voxgig_value* select_def = to_map(getp(cand, "select"));
|
|
64
88
|
bool found = true;
|
|
65
89
|
|
|
66
90
|
if (!v_is_noval(selector) && !v_is_noval(select_def)) {
|
|
@@ -85,7 +109,44 @@ voxgig_value* make_point_util(Context* ctx, PNError** err) {
|
|
|
85
109
|
if (!v_eq(req_action, select_action)) found = false;
|
|
86
110
|
}
|
|
87
111
|
|
|
88
|
-
if (found)
|
|
112
|
+
if (found) {
|
|
113
|
+
point = cand;
|
|
114
|
+
matched = true;
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// select.exist can list more than the params needed to pick a point, so
|
|
120
|
+
// nothing matches — fall back to the entity's own route rather than
|
|
121
|
+
// whichever point came last.
|
|
122
|
+
if (!matched) {
|
|
123
|
+
// A request naming an action reaches here only because that action's
|
|
124
|
+
// own point failed its exist test, so it is unbuildable whatever we
|
|
125
|
+
// pick. Refuse it BEFORE choosing a fallback: the guard below compares
|
|
126
|
+
// the chosen point's $action and would wave the request through
|
|
127
|
+
// whenever the fallback lands on the action point itself.
|
|
128
|
+
voxgig_value* unmatched_action = getp(reqselector, "$action");
|
|
129
|
+
if (!v_is_noval(unmatched_action)) {
|
|
130
|
+
char* actstr = voxgig_stringify(unmatched_action, -1);
|
|
131
|
+
char buf[512];
|
|
132
|
+
snprintf(buf, sizeof(buf), "Operation \"%s\" action \"%s\" is not valid.",
|
|
133
|
+
op->name, actstr ? actstr : "");
|
|
134
|
+
*err = context_make_error(ctx, "point_action_invalid", buf);
|
|
135
|
+
return NULL;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
point = get_elem_i(points, 0);
|
|
139
|
+
for (int64_t i = 0; i < plen; i++) {
|
|
140
|
+
voxgig_value* cand = get_elem_i(points, i);
|
|
141
|
+
bool cand_term = terminal_param(cand);
|
|
142
|
+
bool best_term = terminal_param(point);
|
|
143
|
+
if (cand_term != best_term) {
|
|
144
|
+
if (cand_term) point = cand;
|
|
145
|
+
}
|
|
146
|
+
else if (parts_len(cand) < parts_len(point)) {
|
|
147
|
+
point = cand;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
89
150
|
}
|
|
90
151
|
|
|
91
152
|
voxgig_value* req_action = getp(reqselector, "$action");
|
|
@@ -641,21 +641,56 @@
|
|
|
641
641
|
sa (vs/getprop select-def "$action")]
|
|
642
642
|
(when (not= ra sa) (reset! found false))))
|
|
643
643
|
@found))
|
|
644
|
-
;;
|
|
645
|
-
;;
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
644
|
+
;; How many path segments a point has, and whether its path
|
|
645
|
+
;; ends in a parameter. A record route ends in the record's
|
|
646
|
+
;; identifier (/boards/{id}); a cross-reference that also
|
|
647
|
+
;; returns the entity ends in the relationship's name
|
|
648
|
+
;; (/posts/{id}/author). That, then fewest segments, is what
|
|
649
|
+
;; tells the entity's own route from a cross-reference. The
|
|
650
|
+
;; same rule runs at generation time, in helpers/opShape.ts —
|
|
651
|
+
;; both sides must move together.
|
|
652
|
+
parts-len (fn [p]
|
|
653
|
+
(let [parts (vs/getprop p "parts")]
|
|
654
|
+
(if (vs/islist parts) (vs/size parts) 0)))
|
|
655
|
+
terminal-param? (fn [p]
|
|
656
|
+
(let [parts (vs/getprop p "parts")]
|
|
657
|
+
(and (vs/islist parts)
|
|
658
|
+
(pos? (vs/size parts))
|
|
659
|
+
(let [last-part (vs/getelem parts (dec (vs/size parts)))]
|
|
660
|
+
(and (string? last-part)
|
|
661
|
+
(str/starts-with? last-part "{"))))))
|
|
662
|
+
own-point (fn [ps]
|
|
663
|
+
(reduce (fn [best cand]
|
|
664
|
+
(let [ct (terminal-param? cand)
|
|
665
|
+
bt (terminal-param? best)]
|
|
666
|
+
(if (not= ct bt)
|
|
667
|
+
(if ct cand best)
|
|
668
|
+
(if (< (parts-len cand) (parts-len best)) cand best))))
|
|
669
|
+
(first ps) ps))
|
|
670
|
+
matched (first (filter point-matches? (vec (op-points op))))
|
|
650
671
|
req-action (vs/getprop reqselector "$action")]
|
|
651
|
-
(
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
672
|
+
(cond
|
|
673
|
+
;; select.exist can list more than the params needed to pick a
|
|
674
|
+
;; point, so nothing matches. A request naming an action reaches
|
|
675
|
+
;; here only because that action's own point failed its exist
|
|
676
|
+
;; test, so it is unbuildable whatever we pick — refuse it
|
|
677
|
+
;; BEFORE falling back, since the guard below compares the
|
|
678
|
+
;; chosen point's $action and would wave the request through
|
|
679
|
+
;; whenever the fallback lands on the action point itself.
|
|
680
|
+
(and (nil? matched) reqselector req-action)
|
|
681
|
+
[nil (ctx-error ctx "point_action_invalid"
|
|
682
|
+
(str "Operation \"" (op-name op) "\" action \"" (vs/stringify req-action) "\" is not valid."))]
|
|
683
|
+
|
|
684
|
+
:else
|
|
685
|
+
(let [chosen (or matched (own-point (vec (op-points op))))]
|
|
686
|
+
(if (and reqselector req-action chosen)
|
|
687
|
+
(let [point-select (to-map (vs/getprop chosen "select"))
|
|
688
|
+
point-action (vs/getprop point-select "$action")]
|
|
689
|
+
(if (not= req-action point-action)
|
|
690
|
+
[nil (ctx-error ctx "point_action_invalid"
|
|
691
|
+
(str "Operation \"" (op-name op) "\" action \"" (vs/stringify req-action) "\" is not valid."))]
|
|
692
|
+
(do (oset! ctx :point chosen) [(oget ctx :point) nil])))
|
|
693
|
+
(do (oset! ctx :point chosen) [(oget ctx :point) nil]))))))))))
|
|
659
694
|
|
|
660
695
|
(defn u-make-spec [ctx]
|
|
661
696
|
(if (some? (out-get ctx "spec"))
|