@voxgig/sdkgen 1.3.17 → 1.3.19
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/Deploy.js +16 -16
- package/dist/cmp/Deploy.js.map +1 -1
- package/dist/cmp/Entity.js +5 -1
- package/dist/cmp/Entity.js.map +1 -1
- package/dist/cmp/Feature.js +2 -1
- package/dist/cmp/Feature.js.map +1 -1
- package/dist/cmp/ReadmeTop.js +13 -11
- package/dist/cmp/ReadmeTop.js.map +1 -1
- package/dist/helpers/canonType.js +8 -3
- package/dist/helpers/canonType.js.map +1 -1
- package/dist/helpers/collectDeps.d.ts +1 -1
- package/dist/helpers/collectDeps.js +36 -13
- package/dist/helpers/collectDeps.js.map +1 -1
- package/dist/helpers/naming.d.ts +5 -1
- package/dist/helpers/naming.js +118 -0
- package/dist/helpers/naming.js.map +1 -1
- package/dist/helpers/opShape.d.ts +3 -1
- package/dist/helpers/opShape.js +87 -8
- package/dist/helpers/opShape.js.map +1 -1
- package/dist/helpers/serverVars.d.ts +10 -0
- package/dist/helpers/serverVars.js +87 -0
- package/dist/helpers/serverVars.js.map +1 -0
- package/dist/sdkgen.d.ts +4 -3
- package/dist/sdkgen.js +11 -2
- package/dist/sdkgen.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +15 -10
- package/project/.sdk/model/target/cpp.aontu +4 -4
- package/project/.sdk/model/target/go-cli.aontu +17 -17
- package/project/.sdk/model/target/go-mcp.aontu +11 -11
- package/project/.sdk/model/target/go.aontu +1 -1
- package/project/.sdk/model/target/java.aontu +4 -4
- package/project/.sdk/model/target/kotlin.aontu +4 -4
- package/project/.sdk/model/target/lean.aontu +51 -0
- package/project/.sdk/model/target/scala.aontu +4 -4
- package/project/.sdk/src/cmp/c/EntityTypes_c.ts +3 -4
- package/project/.sdk/src/cmp/c/Entity_c.ts +3 -3
- package/project/.sdk/src/cmp/c/ReadmeExamplesTest_c.ts +24 -7
- package/project/.sdk/src/cmp/c/TestDirect_c.ts +3 -3
- package/project/.sdk/src/cmp/c/TestEntity_c.ts +1 -1
- package/project/.sdk/src/cmp/clojure/Entity_clojure.ts +1 -1
- package/project/.sdk/src/cmp/clojure/ReadmeExamplesTest_clojure.ts +19 -8
- package/project/.sdk/src/cmp/cpp/EntityTypes_cpp.ts +2 -2
- package/project/.sdk/src/cmp/cpp/Entity_cpp.ts +3 -3
- package/project/.sdk/src/cmp/cpp/MainEntity_cpp.ts +2 -2
- package/project/.sdk/src/cmp/cpp/ReadmeExamplesTest_cpp.ts +136 -0
- package/project/.sdk/src/cmp/cpp/TestDirect_cpp.ts +3 -3
- package/project/.sdk/src/cmp/cpp/Test_cpp.ts +4 -0
- package/project/.sdk/src/cmp/csharp/EntityTypes_csharp.ts +2 -3
- package/project/.sdk/src/cmp/csharp/Entity_csharp.ts +3 -3
- package/project/.sdk/src/cmp/csharp/MainEntity_csharp.ts +2 -2
- package/project/.sdk/src/cmp/csharp/Package_csharp.ts +1 -1
- package/project/.sdk/src/cmp/csharp/ReadmeExamplesTest_csharp.ts +13 -1
- package/project/.sdk/src/cmp/csharp/TestDirect_csharp.ts +3 -3
- package/project/.sdk/src/cmp/csharp/TestEntity_csharp.ts +22 -15
- package/project/.sdk/src/cmp/dart/EntityTypes_dart.ts +2 -3
- package/project/.sdk/src/cmp/dart/Entity_dart.ts +3 -3
- package/project/.sdk/src/cmp/dart/MainEntity_dart.ts +2 -2
- package/project/.sdk/src/cmp/dart/Main_dart.ts +3 -3
- package/project/.sdk/src/cmp/dart/Package_dart.ts +1 -1
- package/project/.sdk/src/cmp/dart/TestDirect_dart.ts +4 -4
- package/project/.sdk/src/cmp/elixir/EntityTypes_elixir.ts +2 -3
- package/project/.sdk/src/cmp/elixir/Entity_elixir.ts +1 -1
- package/project/.sdk/src/cmp/elixir/ReadmeExamplesTest_elixir.ts +21 -3
- package/project/.sdk/src/cmp/go/Config_go.ts +14 -2
- package/project/.sdk/src/cmp/go/EntityTypes_go.ts +110 -18
- package/project/.sdk/src/cmp/go/Entity_go.ts +3 -3
- package/project/.sdk/src/cmp/go/Main_go.ts +7 -6
- package/project/.sdk/src/cmp/go/Package_go.ts +1 -1
- package/project/.sdk/src/cmp/go/TestDirect_go.ts +3 -3
- package/project/.sdk/src/cmp/go/TestEntity_go.ts +1 -1
- package/project/.sdk/src/cmp/go/utility_go.ts +25 -0
- package/project/.sdk/src/cmp/go-cli/Main_go-cli.ts +62 -35
- package/project/.sdk/src/cmp/go-cli/fragment/main.fragment.go +7 -7
- package/project/.sdk/src/cmp/go-cli/fragment/words.fragment.go +21 -18
- package/project/.sdk/src/cmp/go-mcp/Main_go-mcp.ts +9 -1
- package/project/.sdk/src/cmp/haskell/ReadmeExamplesTest_haskell.ts +28 -18
- package/project/.sdk/src/cmp/java/EntityTypes_java.ts +2 -3
- package/project/.sdk/src/cmp/java/Entity_java.ts +3 -3
- package/project/.sdk/src/cmp/java/MainEntity_java.ts +2 -2
- package/project/.sdk/src/cmp/java/Package_java.ts +1 -1
- package/project/.sdk/src/cmp/java/ReadmeExamplesTest_java.ts +23 -1
- package/project/.sdk/src/cmp/java/TestDirect_java.ts +3 -3
- package/project/.sdk/src/cmp/js/Config_js.ts +11 -0
- package/project/.sdk/src/cmp/js/EntityTypes_js.ts +2 -3
- package/project/.sdk/src/cmp/js/Entity_js.ts +3 -3
- package/project/.sdk/src/cmp/js/MainEntity_js.ts +2 -2
- package/project/.sdk/src/cmp/js/Main_js.ts +2 -2
- package/project/.sdk/src/cmp/js/TestDirect_js.ts +4 -4
- package/project/.sdk/src/cmp/js/fragment/Config.fragment.js +2 -2
- package/project/.sdk/src/cmp/js/fragment/Direct.test.fragment.js +4 -0
- package/project/.sdk/src/cmp/kotlin/EntityTypes_kotlin.ts +2 -3
- package/project/.sdk/src/cmp/kotlin/Entity_kotlin.ts +3 -3
- package/project/.sdk/src/cmp/kotlin/MainEntity_kotlin.ts +2 -2
- package/project/.sdk/src/cmp/kotlin/Package_kotlin.ts +1 -1
- package/project/.sdk/src/cmp/kotlin/ReadmeExamplesTest_kotlin.ts +27 -2
- package/project/.sdk/src/cmp/kotlin/TestDirect_kotlin.ts +3 -3
- package/project/.sdk/src/cmp/lean/Config_lean.ts +88 -0
- package/project/.sdk/src/cmp/lean/Entity_lean.ts +9 -0
- package/project/.sdk/src/cmp/lean/Gitignore_lean.ts +18 -0
- package/project/.sdk/src/cmp/lean/Main_lean.ts +120 -0
- package/project/.sdk/src/cmp/lean/Package_lean.ts +68 -0
- package/project/.sdk/src/cmp/lean/ReadmeEntity_lean.ts +29 -0
- package/project/.sdk/src/cmp/lean/ReadmeExplanation_lean.ts +19 -0
- package/project/.sdk/src/cmp/lean/ReadmeHowto_lean.ts +25 -0
- package/project/.sdk/src/cmp/lean/ReadmeInstall_lean.ts +38 -0
- package/project/.sdk/src/cmp/lean/ReadmeIntro_lean.ts +25 -0
- package/project/.sdk/src/cmp/lean/ReadmeModel_lean.ts +24 -0
- package/project/.sdk/src/cmp/lean/ReadmeOptions_lean.ts +22 -0
- package/project/.sdk/src/cmp/lean/ReadmeQuick_lean.ts +50 -0
- package/project/.sdk/src/cmp/lean/ReadmeRef_lean.ts +16 -0
- package/project/.sdk/src/cmp/lean/ReadmeTopHowto_lean.ts +16 -0
- package/project/.sdk/src/cmp/lean/ReadmeTopQuick_lean.ts +23 -0
- package/project/.sdk/src/cmp/lean/ReadmeTopTest_lean.ts +18 -0
- package/project/.sdk/src/cmp/lean/Test_lean.ts +207 -0
- package/project/.sdk/src/cmp/lean/utility_lean.ts +78 -0
- package/project/.sdk/src/cmp/lua/Config_lua.ts +10 -1
- package/project/.sdk/src/cmp/lua/EntityTypes_lua.ts +2 -3
- package/project/.sdk/src/cmp/lua/Entity_lua.ts +3 -3
- package/project/.sdk/src/cmp/lua/Package_lua.ts +1 -1
- package/project/.sdk/src/cmp/lua/TestDirect_lua.ts +3 -3
- package/project/.sdk/src/cmp/lua/TestEntity_lua.ts +1 -1
- package/project/.sdk/src/cmp/ocaml/ReadmeExamplesTest_ocaml.ts +29 -14
- package/project/.sdk/src/cmp/perl/Entity_perl.ts +3 -3
- package/project/.sdk/src/cmp/perl/MainEntity_perl.ts +2 -2
- package/project/.sdk/src/cmp/perl/Package_perl.ts +1 -1
- package/project/.sdk/src/cmp/perl/TestDirect_perl.ts +3 -3
- package/project/.sdk/src/cmp/php/Config_php.ts +13 -2
- package/project/.sdk/src/cmp/php/EntityTypes_php.ts +2 -3
- package/project/.sdk/src/cmp/php/Entity_php.ts +3 -3
- package/project/.sdk/src/cmp/php/MainEntity_php.ts +2 -2
- package/project/.sdk/src/cmp/php/Package_php.ts +1 -1
- package/project/.sdk/src/cmp/php/TestDirect_php.ts +3 -3
- package/project/.sdk/src/cmp/php/TestEntity_php.ts +1 -1
- package/project/.sdk/src/cmp/py/Config_py.ts +10 -1
- package/project/.sdk/src/cmp/py/EntityTypes_py.ts +2 -3
- package/project/.sdk/src/cmp/py/Entity_py.ts +3 -3
- package/project/.sdk/src/cmp/py/MainEntity_py.ts +2 -2
- package/project/.sdk/src/cmp/py/Main_py.ts +2 -2
- package/project/.sdk/src/cmp/py/Package_py.ts +1 -1
- package/project/.sdk/src/cmp/py/TestDirect_py.ts +3 -3
- package/project/.sdk/src/cmp/py/TestEntity_py.ts +1 -1
- package/project/.sdk/src/cmp/rb/Config_rb.ts +12 -1
- package/project/.sdk/src/cmp/rb/EntityTypes_rb.ts +15 -5
- package/project/.sdk/src/cmp/rb/Entity_rb.ts +3 -3
- package/project/.sdk/src/cmp/rb/MainEntity_rb.ts +2 -2
- package/project/.sdk/src/cmp/rb/Package_rb.ts +2 -2
- package/project/.sdk/src/cmp/rb/TestDirect_rb.ts +3 -3
- package/project/.sdk/src/cmp/rb/TestEntity_rb.ts +1 -1
- package/project/.sdk/src/cmp/rust/EntityBase_rust.ts +2 -2
- package/project/.sdk/src/cmp/rust/EntityTypes_rust.ts +3 -4
- package/project/.sdk/src/cmp/rust/Entity_rust.ts +3 -3
- package/project/.sdk/src/cmp/rust/MainEntity_rust.ts +2 -2
- package/project/.sdk/src/cmp/rust/Package_rust.ts +1 -1
- package/project/.sdk/src/cmp/rust/ReadmeExamplesTest_rust.ts +22 -10
- package/project/.sdk/src/cmp/rust/TestDirect_rust.ts +3 -3
- package/project/.sdk/src/cmp/rust/TestEntity_rust.ts +25 -18
- package/project/.sdk/src/cmp/scala/EntityTypes_scala.ts +2 -3
- package/project/.sdk/src/cmp/scala/Entity_scala.ts +3 -3
- package/project/.sdk/src/cmp/scala/MainEntity_scala.ts +2 -2
- package/project/.sdk/src/cmp/scala/ReadmeExamplesTest_scala.ts +22 -3
- package/project/.sdk/src/cmp/scala/TestDirect_scala.ts +3 -3
- package/project/.sdk/src/cmp/scala/Test_scala.ts +1 -1
- package/project/.sdk/src/cmp/swift/EntityTypes_swift.ts +12 -6
- package/project/.sdk/src/cmp/swift/Entity_swift.ts +3 -3
- package/project/.sdk/src/cmp/swift/MainEntity_swift.ts +2 -2
- package/project/.sdk/src/cmp/swift/Package_swift.ts +1 -1
- package/project/.sdk/src/cmp/swift/ReadmeExamplesTest_swift.ts +18 -1
- package/project/.sdk/src/cmp/swift/TestDirect_swift.ts +1 -1
- package/project/.sdk/src/cmp/ts/Config_ts.ts +11 -0
- package/project/.sdk/src/cmp/ts/EntityTypes_ts.ts +2 -3
- package/project/.sdk/src/cmp/ts/Entity_ts.ts +3 -3
- package/project/.sdk/src/cmp/ts/MainEntity_ts.ts +2 -2
- package/project/.sdk/src/cmp/ts/Main_ts.ts +2 -2
- package/project/.sdk/src/cmp/ts/TestDirect_ts.ts +4 -4
- package/project/.sdk/src/cmp/ts/fragment/Config.fragment.ts +2 -2
- package/project/.sdk/src/cmp/ts/fragment/Direct.test.fragment.ts +4 -0
- package/project/.sdk/src/cmp/zig/Entity_zig.ts +3 -3
- package/project/.sdk/src/cmp/zig/MainEntity_zig.ts +2 -2
- package/project/.sdk/src/cmp/zig/Package_zig.ts +10 -2
- package/project/.sdk/tm/cpp/test/primary_utility_test.cpp +8 -16
- package/project/.sdk/tm/csharp/Makefile +6 -6
- package/project/.sdk/tm/csharp/test/PrimaryUtilityTest.cs +10 -28
- package/project/.sdk/tm/dart/Makefile +3 -3
- package/project/.sdk/tm/dart/test/primary_test.dart +7 -0
- package/project/.sdk/tm/go/Makefile +6 -6
- package/project/.sdk/tm/go/feature/test_feature.go +33 -1
- package/project/.sdk/tm/go/test/primary_utility_test.go +46 -42
- package/project/.sdk/tm/go/test/runner_test.go +30 -1
- package/project/.sdk/tm/go/utility/make_options.go +48 -0
- package/project/.sdk/tm/java/Makefile +6 -6
- package/project/.sdk/tm/java/test/PrimaryUtilityTest.java +7 -24
- package/project/.sdk/tm/js/Makefile +6 -6
- package/project/.sdk/tm/js/src/feature/test/TestFeature.js +18 -1
- package/project/.sdk/tm/js/src/utility/MakeOptionsUtility.js +39 -1
- package/project/.sdk/tm/js/test/utility/PrimaryUtility.test.js +13 -0
- package/project/.sdk/tm/kotlin/Makefile +6 -6
- package/project/.sdk/tm/kotlin/test/PrimaryUtilityTest.kt +7 -20
- package/project/.sdk/tm/lean/LICENSE +21 -0
- package/project/.sdk/tm/lean/VERSION +1 -0
- package/project/.sdk/tm/lean/src/SdkFeature.lean +171 -0
- package/project/.sdk/tm/lean/src/SdkFeatures.lean +602 -0
- package/project/.sdk/tm/lean/src/SdkJson.lean +134 -0
- package/project/.sdk/tm/lean/src/SdkRuntime.lean +356 -0
- package/project/.sdk/tm/lean/src/SdkUtility.lean +617 -0
- package/project/.sdk/tm/lean/src/VoxgigStruct.lean +2880 -0
- package/project/.sdk/tm/lean/src/Vregex.lean +412 -0
- package/project/.sdk/tm/lean/src/feature/README.md +5 -0
- package/project/.sdk/tm/lean/src/feature/audit/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/base/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/cache/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/clienttrack/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/debug/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/idempotency/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/log/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/metrics/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/netsim/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/paging/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/proxy/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/ratelimit/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/rbac/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/retry/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/streaming/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/telemetry/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/test/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/timeout/.gitkeep +0 -0
- package/project/.sdk/tm/lean/test/StructCorpus.lean +697 -0
- package/project/.sdk/tm/lean/test/TFeature.lean +268 -0
- package/project/.sdk/tm/lean/test/TPrimaryUtility.lean +349 -0
- package/project/.sdk/tm/lua/Makefile +7 -7
- package/project/.sdk/tm/lua/feature/test_feature.lua +29 -1
- package/project/.sdk/tm/lua/test/primary_utility_test.lua +14 -8
- package/project/.sdk/tm/lua/utility/make_options.lua +39 -0
- package/project/.sdk/tm/perl/Makefile +6 -6
- package/project/.sdk/tm/perl/t/primary_utility.t +8 -17
- package/project/.sdk/tm/php/Makefile +6 -6
- package/project/.sdk/tm/php/feature/TestFeature.php +30 -2
- package/project/.sdk/tm/php/test/PrimaryUtilityTest.php +14 -7
- package/project/.sdk/tm/php/utility/MakeOptions.php +44 -0
- package/project/.sdk/tm/py/Makefile +6 -6
- package/project/.sdk/tm/py/feature/test_feature.py +28 -1
- package/project/.sdk/tm/py/test/test_primary_utility.py +18 -18
- package/project/.sdk/tm/py/utility/make_options.py +42 -0
- package/project/.sdk/tm/rb/Makefile +6 -6
- package/project/.sdk/tm/rb/feature/test_feature.rb +24 -1
- package/project/.sdk/tm/rb/test/primary_utility_test.rb +11 -8
- package/project/.sdk/tm/rb/utility/make_options.rb +37 -0
- package/project/.sdk/tm/rust/Makefile +6 -6
- package/project/.sdk/tm/rust/tests/common/mod.rs +37 -1
- package/project/.sdk/tm/rust/tests/primary_utility_test.rs +12 -26
- package/project/.sdk/tm/swift/Makefile +6 -6
- package/project/.sdk/tm/swift/Tests/ProjectNameSDKTests/PrimaryUtilityTest.swift +7 -8
- package/project/.sdk/tm/ts/Makefile +6 -6
- package/project/.sdk/tm/ts/src/feature/test/TestFeature.ts +18 -1
- package/project/.sdk/tm/ts/src/utility/MakeOptionsUtility.ts +39 -1
- package/project/.sdk/tm/ts/test/utility/PrimaryUtility.test.ts +69 -21
- package/src/cmp/Deploy.ts +16 -16
- package/src/cmp/Entity.ts +5 -1
- package/src/cmp/Feature.ts +2 -1
- package/src/cmp/ReadmeTop.ts +13 -11
- package/src/helpers/canonType.ts +8 -3
- package/src/helpers/collectDeps.ts +39 -12
- package/src/helpers/naming.ts +130 -0
- package/src/helpers/opShape.ts +99 -12
- package/src/helpers/serverVars.ts +105 -0
- package/src/sdkgen.ts +12 -3
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { cmp, Content } from '@voxgig/sdkgen'
|
|
2
|
+
|
|
3
|
+
const ReadmeExplanation = cmp(function ReadmeExplanation(_props: any) {
|
|
4
|
+
Content(`The SDK is **config-driven**: the API model is embedded as JSON in
|
|
5
|
+
\`SdkConfig.lean\` and parsed into a \`Value\` when a client is constructed. An
|
|
6
|
+
operation looks up its entity and op in that model, selects the matching
|
|
7
|
+
endpoint (a point whose \`select.exist\` keys are satisfied), builds the URL from
|
|
8
|
+
the point's path parts, applies the request transform, performs the call, then
|
|
9
|
+
applies the response transform. Because the pipeline is data-driven rather than
|
|
10
|
+
generated per entity, every entity and every API follow exactly the same path.
|
|
11
|
+
|
|
12
|
+
The HTTP transport shells out to \`curl\` via \`IO.Process\` — Lean 4 has no HTTP
|
|
13
|
+
library in its standard distribution, and this keeps the package free of Lake
|
|
14
|
+
dependencies.
|
|
15
|
+
|
|
16
|
+
`)
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
export { ReadmeExplanation }
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { cmp, Content } from '@voxgig/sdkgen'
|
|
2
|
+
|
|
3
|
+
const ReadmeHowto = cmp(function ReadmeHowto(_props: any) {
|
|
4
|
+
Content(`**Handle a missing record.** A \`load\` that finds nothing yields a
|
|
5
|
+
non-map value, so match on it:
|
|
6
|
+
|
|
7
|
+
\`\`\`lean
|
|
8
|
+
match (← Entity.load sdk m (← emptyMap)) with
|
|
9
|
+
| .map _ => IO.println "found"
|
|
10
|
+
| _ => IO.println "not found"
|
|
11
|
+
\`\`\`
|
|
12
|
+
|
|
13
|
+
**Test without a server.** \`Sdk.testSdk0\` takes seed data (the shape of the
|
|
14
|
+
generated \`<Entity>TestData.json\`) and answers operations from an in-memory
|
|
15
|
+
store, so entity behaviour can be exercised offline:
|
|
16
|
+
|
|
17
|
+
\`\`\`lean
|
|
18
|
+
let seed ← SdkJson.jsonRead (← IO.FS.readFile "../.sdk/test/entity/<e>/<E>TestData.json")
|
|
19
|
+
let sdk ← Sdk.testSdk0 seed
|
|
20
|
+
\`\`\`
|
|
21
|
+
|
|
22
|
+
`)
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
export { ReadmeHowto }
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { cmp, Content, isPublished, repoInfo } from '@voxgig/sdkgen'
|
|
2
|
+
|
|
3
|
+
const ReadmeInstall = cmp(function ReadmeInstall(props: any) {
|
|
4
|
+
const { target, ctx$ } = props
|
|
5
|
+
const { model } = ctx$
|
|
6
|
+
|
|
7
|
+
if (isPublished(model, target.name)) {
|
|
8
|
+
Content(`\`\`\`bash
|
|
9
|
+
cd ${target.name} && lake build
|
|
10
|
+
\`\`\`
|
|
11
|
+
|
|
12
|
+
`)
|
|
13
|
+
return
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const { releasesUrl } = repoInfo(model)
|
|
17
|
+
Content(`This package is not yet published to [Reservoir](https://reservoir.lean-lang.org).
|
|
18
|
+
Install it from the GitHub release tag (\`${target.name}/vX.Y.Z\`, see
|
|
19
|
+
[Releases](${releasesUrl})) or from a source checkout. The runtime is
|
|
20
|
+
dependency-free (only the Lean 4 prelude + Std; the HTTP transport shells out
|
|
21
|
+
to \`curl\`), so a plain Lake build is all that is needed:
|
|
22
|
+
|
|
23
|
+
\`\`\`bash
|
|
24
|
+
cd ${target.name} && lake build
|
|
25
|
+
\`\`\`
|
|
26
|
+
|
|
27
|
+
Run the offline struct-corpus test (no server needed) and the live entity
|
|
28
|
+
tests (point them at a server with \`SDK_TEST_BASE\`):
|
|
29
|
+
|
|
30
|
+
\`\`\`bash
|
|
31
|
+
lake exe structcorpus
|
|
32
|
+
SDK_TEST_BASE=http://localhost:8901 lake exe runner
|
|
33
|
+
\`\`\`
|
|
34
|
+
|
|
35
|
+
`)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
export { ReadmeInstall }
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { cmp, Content } from '@voxgig/sdkgen'
|
|
2
|
+
import { KIT, getModelPath } from '@voxgig/apidef'
|
|
3
|
+
|
|
4
|
+
const ReadmeIntro = cmp(function ReadmeIntro(props: any) {
|
|
5
|
+
const { target, ctx$: { model } } = props
|
|
6
|
+
const info = (model.main && model.main.kit && model.main.kit.info) || {}
|
|
7
|
+
const tagline = info.tagline || ''
|
|
8
|
+
|
|
9
|
+
Content(`# ${model.Name} ${target.title} SDK
|
|
10
|
+
|
|
11
|
+
${tagline}
|
|
12
|
+
|
|
13
|
+
The ${target.title} SDK for the ${model.Name} API — an entity-oriented client
|
|
14
|
+
for Lean 4. The API is surfaced as capitalised Entities with a small, uniform
|
|
15
|
+
verb set (\`list\`, \`load\`, \`create\`, \`update\`, \`remove\`); every operation is
|
|
16
|
+
driven by the embedded config through the dependency-free vendored voxgig
|
|
17
|
+
\`Value\` struct model, and runs in struct's \`SIO\` monad.
|
|
18
|
+
|
|
19
|
+
`)
|
|
20
|
+
|
|
21
|
+
// touch the model so a mis-shaped model surfaces here, not at render time.
|
|
22
|
+
getModelPath(model, `main.${KIT}.entity`)
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
export { ReadmeIntro }
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { cmp, Content } from '@voxgig/sdkgen'
|
|
2
|
+
|
|
3
|
+
const ReadmeModel = cmp(function ReadmeModel(_props: any) {
|
|
4
|
+
Content(`Every value crossing the SDK boundary — options, request payloads,
|
|
5
|
+
responses and results — is a vendored voxgig \`Value\` (see \`VoxgigStruct.lean\`):
|
|
6
|
+
a JSON-shaped, heap-backed node, the Lean equivalent of the \`map[string]any\`
|
|
7
|
+
the Go and Python SDKs pass around. Operations run in struct's \`SIO\` monad
|
|
8
|
+
(\`ReaderT Ctx IO\`), so a single \`mkCtx\` is threaded through a run:
|
|
9
|
+
|
|
10
|
+
\`\`\`lean
|
|
11
|
+
let ctx ← mkCtx
|
|
12
|
+
(do
|
|
13
|
+
let sdk ← Sdk.newSdk (← emptyMap)
|
|
14
|
+
...
|
|
15
|
+
).run ctx
|
|
16
|
+
\`\`\`
|
|
17
|
+
|
|
18
|
+
Build values with \`newMap\` / \`newList\`, read them with \`getprop\` / \`getpath\`,
|
|
19
|
+
and render them with \`stringify\` (debug) or \`jsonify\` (strict JSON).
|
|
20
|
+
|
|
21
|
+
`)
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
export { ReadmeModel }
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { cmp, Content } from '@voxgig/sdkgen'
|
|
2
|
+
|
|
3
|
+
const ReadmeOptions = cmp(function ReadmeOptions(_props: any) {
|
|
4
|
+
Content(`Options are a struct \`Value\` map passed to \`Sdk.newSdk\`:
|
|
5
|
+
|
|
6
|
+
| Option | Meaning |
|
|
7
|
+
| --- | --- |
|
|
8
|
+
| \`base\` | API base URL (overrides the built-in default) |
|
|
9
|
+
| \`prefix\` / \`suffix\` | Path fragments wrapped around every request path |
|
|
10
|
+
| \`headers\` | Default request headers (merged with per-request headers) |
|
|
11
|
+
| \`apikey\` | Bearer/api key, sent via the \`authorization\` header |
|
|
12
|
+
| \`entity\` | Per-entity option overrides, keyed by entity name |
|
|
13
|
+
|
|
14
|
+
\`\`\`lean
|
|
15
|
+
let opts ← newMap #[("base", .str "https://api.example.com"), ("apikey", .str key)]
|
|
16
|
+
let sdk ← Sdk.newSdk opts
|
|
17
|
+
\`\`\`
|
|
18
|
+
|
|
19
|
+
`)
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
export { ReadmeOptions }
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { cmp, Content, isAuthActive, envName } from '@voxgig/sdkgen'
|
|
2
|
+
import { KIT, getModelPath } from '@voxgig/apidef'
|
|
3
|
+
|
|
4
|
+
// A capitalised entity op namespace + a representative read op for the example.
|
|
5
|
+
function pickEntity(model: any): { ns: string, op: string } | null {
|
|
6
|
+
const entity = getModelPath(model, `main.${KIT}.entity`)
|
|
7
|
+
const ents = Object.values(entity || {}).filter((e: any) => e.active !== false)
|
|
8
|
+
for (const e of ents as any[]) {
|
|
9
|
+
const ops = Object.keys(e.op || {})
|
|
10
|
+
const op = ops.includes('list') ? 'list' : ops[0]
|
|
11
|
+
if (op) {
|
|
12
|
+
return { ns: e.name.charAt(0).toUpperCase() + e.name.slice(1), op }
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return null
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const ReadmeQuick = cmp(function ReadmeQuick(props: any) {
|
|
19
|
+
const { ctx$: { model } } = props
|
|
20
|
+
const pick = pickEntity(model)
|
|
21
|
+
const ns = pick ? pick.ns : 'Entity'
|
|
22
|
+
const op = pick ? pick.op : 'list'
|
|
23
|
+
const auth = isAuthActive(model)
|
|
24
|
+
const optLines = [`("base", .str "https://api.example.com")`]
|
|
25
|
+
if (auth) {
|
|
26
|
+
optLines.push(`("apikey", .str (← IO.getEnv "${envName(model)}").getD "")`)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
Content(`Construct a client with \`Sdk.newSdk\` and call an entity op. Everything runs
|
|
30
|
+
in struct's \`SIO\` monad, so wrap your calls and \`.run\` them on a fresh \`mkCtx\`:
|
|
31
|
+
|
|
32
|
+
\`\`\`lean
|
|
33
|
+
import SdkClient
|
|
34
|
+
|
|
35
|
+
open VoxgigStruct
|
|
36
|
+
|
|
37
|
+
def main : IO Unit := do
|
|
38
|
+
let ctx ← mkCtx
|
|
39
|
+
(do
|
|
40
|
+
let opts ← newMap #[${optLines.join(', ')}]
|
|
41
|
+
let sdk ← Sdk.newSdk opts
|
|
42
|
+
let result ← ${ns}.${op} sdk (← emptyMap) (← emptyMap)
|
|
43
|
+
IO.println s!"result: {← stringify result}"
|
|
44
|
+
).run ctx
|
|
45
|
+
\`\`\`
|
|
46
|
+
|
|
47
|
+
`)
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
export { ReadmeQuick }
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { cmp, Content } from '@voxgig/sdkgen'
|
|
2
|
+
|
|
3
|
+
const ReadmeRef = cmp(function ReadmeRef(_props: any) {
|
|
4
|
+
Content(`| Module | Purpose |
|
|
5
|
+
| --- | --- |
|
|
6
|
+
| \`SdkClient\` | \`Sdk.newSdk\` / \`Sdk.testSdk\` and the per-entity op namespaces |
|
|
7
|
+
| \`SdkConfig\` | the embedded API model (JSON) |
|
|
8
|
+
| \`SdkRuntime\` | the config-driven operation pipeline and curl transport |
|
|
9
|
+
| \`SdkUtility\` | request-shaping utilities (spec, url, params, transforms, result) |
|
|
10
|
+
| \`SdkJson\` | JSON text to struct \`Value\` |
|
|
11
|
+
| \`VoxgigStruct\` | the vendored voxgig struct value model |
|
|
12
|
+
|
|
13
|
+
`)
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
export { ReadmeRef }
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { cmp, Content } from '@voxgig/sdkgen'
|
|
2
|
+
|
|
3
|
+
// The Lean stanza of the top-level README how-to section.
|
|
4
|
+
const ReadmeTopHowto = cmp(function ReadmeTopHowto(props: any) {
|
|
5
|
+
const { target } = props
|
|
6
|
+
Content(`For Lean, point the client at another server with the \`base\` option,
|
|
7
|
+
and run the entity suite against it with \`SDK_TEST_BASE\`:
|
|
8
|
+
|
|
9
|
+
\`\`\`bash
|
|
10
|
+
cd ${target.name} && SDK_TEST_BASE=http://localhost:8901 lake exe runner
|
|
11
|
+
\`\`\`
|
|
12
|
+
|
|
13
|
+
`)
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
export { ReadmeTopHowto }
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { cmp, Content } from '@voxgig/sdkgen'
|
|
2
|
+
|
|
3
|
+
// The Lean stanza of the top-level (multi-language) README quick start.
|
|
4
|
+
const ReadmeTopQuick = cmp(function ReadmeTopQuick(props: any) {
|
|
5
|
+
const { target } = props
|
|
6
|
+
Content(`\`\`\`lean
|
|
7
|
+
import SdkClient
|
|
8
|
+
open VoxgigStruct
|
|
9
|
+
|
|
10
|
+
def main : IO Unit := do
|
|
11
|
+
let ctx ← mkCtx
|
|
12
|
+
(do
|
|
13
|
+
let sdk ← Sdk.newSdk (← emptyMap)
|
|
14
|
+
IO.println s!"client ready"
|
|
15
|
+
).run ctx
|
|
16
|
+
\`\`\`
|
|
17
|
+
|
|
18
|
+
Build it with \`cd ${target.name} && lake build\`.
|
|
19
|
+
|
|
20
|
+
`)
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
export { ReadmeTopQuick }
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { cmp, Content } from '@voxgig/sdkgen'
|
|
2
|
+
|
|
3
|
+
// The Lean stanza of the top-level README test section.
|
|
4
|
+
const ReadmeTopTest = cmp(function ReadmeTopTest(props: any) {
|
|
5
|
+
const { target } = props
|
|
6
|
+
Content(`\`\`\`bash
|
|
7
|
+
cd ${target.name}
|
|
8
|
+
lake build
|
|
9
|
+
lake exe primary # shared corpus: request-shaping utilities
|
|
10
|
+
lake exe feature # the feature catalog (retry, cache, rbac, netsim, …)
|
|
11
|
+
lake exe structcorpus # shared corpus: the vendored struct model
|
|
12
|
+
lake exe runner # entity behaviour (offline; add SDK_TEST_BASE for live)
|
|
13
|
+
\`\`\`
|
|
14
|
+
|
|
15
|
+
`)
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
export { ReadmeTopTest }
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Content,
|
|
3
|
+
File,
|
|
4
|
+
Folder,
|
|
5
|
+
cmp,
|
|
6
|
+
each,
|
|
7
|
+
} from '@voxgig/sdkgen'
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
KIT,
|
|
11
|
+
Model,
|
|
12
|
+
getModelPath,
|
|
13
|
+
} from '@voxgig/apidef'
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
// True when an op has at least one endpoint point that needs no path params
|
|
17
|
+
// (a top-level operation the live smoke test can call without an id).
|
|
18
|
+
function hasParamFreePoint(op: any): boolean {
|
|
19
|
+
if (null == op) return false
|
|
20
|
+
const points = op.points || []
|
|
21
|
+
for (const pt of points) {
|
|
22
|
+
const params = ((pt.args || {}).params) || []
|
|
23
|
+
if (params.length === 0) return true
|
|
24
|
+
}
|
|
25
|
+
return false
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
// Synthesize a create payload from the entity's required non-id fields.
|
|
30
|
+
function synthData(fields: any): any {
|
|
31
|
+
const o: any = {}
|
|
32
|
+
each(fields, (f: any) => {
|
|
33
|
+
if (f.req && f.name !== 'id') {
|
|
34
|
+
const t = String(f.type || '').toLowerCase()
|
|
35
|
+
o[f.name] =
|
|
36
|
+
(t.includes('number') || t.includes('integer') || t.includes('decimal')) ? 42
|
|
37
|
+
: t.includes('bool') ? true
|
|
38
|
+
: 'leantest'
|
|
39
|
+
}
|
|
40
|
+
})
|
|
41
|
+
return o
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
// The generated `test/Runner.lean` exe runs TWO lanes:
|
|
46
|
+
//
|
|
47
|
+
// - OFFLINE (always): a test-mode client seeded from the entity's generated
|
|
48
|
+
// `<Entity>TestData.json` answers operations from an in-memory store, so
|
|
49
|
+
// entity behaviour (list/load/create/load-back/remove) is verified with no
|
|
50
|
+
// server — the same guarantee the `test` feature gives the other targets.
|
|
51
|
+
// - LIVE (only when SDK_TEST_BASE is set): the same flow against a real
|
|
52
|
+
// server, exercising the curl transport end to end.
|
|
53
|
+
const Test = cmp(async function Test(props: any) {
|
|
54
|
+
const ctx$ = props.ctx$
|
|
55
|
+
const target = props.target
|
|
56
|
+
const model: Model = ctx$.model
|
|
57
|
+
|
|
58
|
+
const entity = getModelPath(model, `main.${KIT}.entity`)
|
|
59
|
+
|
|
60
|
+
// Per-entity OFFLINE (test-mode) blocks: seeded store, no server.
|
|
61
|
+
let offline = ''
|
|
62
|
+
each(entity, (e: any) => {
|
|
63
|
+
const ns = e.name.charAt(0).toUpperCase() + e.name.slice(1)
|
|
64
|
+
const Name = e.Name || (e.name.charAt(0).toUpperCase() + e.name.slice(1))
|
|
65
|
+
const ops = e.op || {}
|
|
66
|
+
if (!ops.list && !ops.load) return
|
|
67
|
+
offline += ` -- ${e.name}: offline (test-mode) entity behaviour
|
|
68
|
+
(do
|
|
69
|
+
let seedPath := "../.sdk/test/entity/${e.name}/${Name}TestData.json"
|
|
70
|
+
if !(← System.FilePath.pathExists seedPath) then
|
|
71
|
+
IO.println s!"skip - ${e.name}: no seed at {seedPath}"
|
|
72
|
+
else do
|
|
73
|
+
let seed ← SdkJson.jsonRead (← IO.FS.readFile seedPath)
|
|
74
|
+
let tclient ← Sdk.testSdk0 seed
|
|
75
|
+
let existing ← SdkRuntime.gp (← SdkRuntime.gp seed "existing") "${e.name}"
|
|
76
|
+
let ids ← keysof existing
|
|
77
|
+
-- list returns every seeded entity
|
|
78
|
+
let items ← ${ns}.list tclient (← emptyMap) (← emptyMap)
|
|
79
|
+
let n ← (match items with | .list lid => do pure (← listItems lid).size | _ => pure 0)
|
|
80
|
+
if n == ids.size then pass s!"${e.name}.list offline -> {n} seeded"
|
|
81
|
+
else fail s!"${e.name}.list offline: got {n}, want {ids.size}"
|
|
82
|
+
-- load the first seeded entity by id
|
|
83
|
+
if ids.size > 0 then do
|
|
84
|
+
let wid := ids[0]!
|
|
85
|
+
let m ← newMap #[("id", .str wid)]
|
|
86
|
+
let got ← ${ns}.load tclient m (← emptyMap)
|
|
87
|
+
let gid ← SdkRuntime.gpS got "id"
|
|
88
|
+
if gid == wid then pass s!"${e.name}.load offline (id={wid})"
|
|
89
|
+
else fail s!"${e.name}.load offline: got {gid}, want {wid}"
|
|
90
|
+
-- create -> load back -> remove, all in the store
|
|
91
|
+
let newmap ← SdkRuntime.gp (← SdkRuntime.gp seed "new") "${e.name}"
|
|
92
|
+
let nks ← keysof newmap
|
|
93
|
+
if nks.size > 0 then do
|
|
94
|
+
let payload ← SdkRuntime.gp newmap nks[0]!
|
|
95
|
+
let created ← ${ns}.create tclient payload (← emptyMap)
|
|
96
|
+
let cid ← SdkRuntime.gpS created "id"
|
|
97
|
+
if cid == "" then fail "${e.name}.create offline returned no id" else do
|
|
98
|
+
let m2 ← newMap #[("id", .str cid)]
|
|
99
|
+
let back ← ${ns}.load tclient m2 (← emptyMap)
|
|
100
|
+
if (← SdkRuntime.gpS back "id") == cid then
|
|
101
|
+
pass s!"${e.name}.create/load offline (id={cid})"
|
|
102
|
+
else fail s!"${e.name}.create/load offline mismatch"
|
|
103
|
+
let _ ← ${ns}.remove tclient m2 (← emptyMap)
|
|
104
|
+
let gone ← ${ns}.load tclient m2 (← emptyMap)
|
|
105
|
+
match gone with
|
|
106
|
+
| .map _ => fail s!"${e.name}.remove offline: still present"
|
|
107
|
+
| _ => pass s!"${e.name}.remove offline (id={cid})")
|
|
108
|
+
`
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
// Per-entity LIVE test blocks.
|
|
112
|
+
let blocks = ''
|
|
113
|
+
each(entity, (e: any) => {
|
|
114
|
+
const ns = e.name.charAt(0).toUpperCase() + e.name.slice(1)
|
|
115
|
+
const listOp = (e.op || {}).list
|
|
116
|
+
const createOp = (e.op || {}).create
|
|
117
|
+
const removeOp = (e.op || {}).remove
|
|
118
|
+
|
|
119
|
+
if (hasParamFreePoint(listOp)) {
|
|
120
|
+
blocks += ` -- ${e.name}: list smoke
|
|
121
|
+
(do
|
|
122
|
+
let items ← ${ns}.list client (← emptyMap) (← emptyMap)
|
|
123
|
+
match items with
|
|
124
|
+
| .list lid => pass s!"${e.name}.list -> {(← listItems lid).size} items"
|
|
125
|
+
| _ => fail "${e.name}.list did not return a list")
|
|
126
|
+
`
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Round-trip when create is param-free (creatable without an id); load and
|
|
130
|
+
// remove then use the id returned by create.
|
|
131
|
+
const loadOp = (e.op || {}).load
|
|
132
|
+
if (hasParamFreePoint(createOp) && loadOp && removeOp) {
|
|
133
|
+
const data = JSON.stringify(synthData(e.fields))
|
|
134
|
+
blocks += ` -- ${e.name}: create / load / remove round-trip
|
|
135
|
+
(do
|
|
136
|
+
let d ← SdkJson.jsonRead ${JSON.stringify(data)}
|
|
137
|
+
let created ← ${ns}.create client d (← emptyMap)
|
|
138
|
+
let nid ← SdkRuntime.gpS created "id"
|
|
139
|
+
if nid == "" then fail "${e.name}.create returned no id" else do
|
|
140
|
+
let m ← newMap #[("id", .str nid)]
|
|
141
|
+
let back ← ${ns}.load client m (← emptyMap)
|
|
142
|
+
let bid ← SdkRuntime.gpS back "id"
|
|
143
|
+
if bid == nid then pass s!"${e.name}.create/load round-trip (id={nid})"
|
|
144
|
+
else fail s!"${e.name}.load mismatch: {bid} != {nid}"
|
|
145
|
+
let _ ← ${ns}.remove client m (← emptyMap)
|
|
146
|
+
pass s!"${e.name}.remove (id={nid})")
|
|
147
|
+
`
|
|
148
|
+
}
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
// The live lane nests two levels deeper than the offline lane.
|
|
152
|
+
const liveBlocks = blocks.split('\n').map((l) => l ? ' ' + l : l).join('\n')
|
|
153
|
+
|
|
154
|
+
Folder({ name: 'test' }, () => {
|
|
155
|
+
File({ name: 'Runner.' + target.ext }, () => {
|
|
156
|
+
Content(`-- ${model.const.Name} SDK test runner (generated by @voxgig/sdkgen).
|
|
157
|
+
--
|
|
158
|
+
-- OFFLINE lane (always): a test-mode client seeded from the generated entity
|
|
159
|
+
-- test data answers operations from an in-memory store — no server needed.
|
|
160
|
+
-- LIVE lane (only when SDK_TEST_BASE is set): the same flow over real HTTP.
|
|
161
|
+
|
|
162
|
+
import VoxgigStruct
|
|
163
|
+
import SdkJson
|
|
164
|
+
import SdkRuntime
|
|
165
|
+
import SdkClient
|
|
166
|
+
|
|
167
|
+
open VoxgigStruct
|
|
168
|
+
|
|
169
|
+
initialize npass : IO.Ref Nat ← IO.mkRef 0
|
|
170
|
+
initialize nfail : IO.Ref Nat ← IO.mkRef 0
|
|
171
|
+
|
|
172
|
+
def pass (msg : String) : SIO Unit := do
|
|
173
|
+
npass.modify (· + 1)
|
|
174
|
+
IO.println s!"ok - {msg}"
|
|
175
|
+
|
|
176
|
+
def fail (msg : String) : SIO Unit := do
|
|
177
|
+
nfail.modify (· + 1)
|
|
178
|
+
IO.println s!"FAIL - {msg}"
|
|
179
|
+
|
|
180
|
+
def defaultBase : String := "http://localhost:8901"
|
|
181
|
+
|
|
182
|
+
def main : IO UInt32 := do
|
|
183
|
+
let liveBase ← IO.getEnv "SDK_TEST_BASE"
|
|
184
|
+
let ctx ← mkCtx
|
|
185
|
+
let offline : SIO Unit := do
|
|
186
|
+
${offline} offline.run ctx
|
|
187
|
+
match liveBase with
|
|
188
|
+
| none => IO.println "skip - live lane (set SDK_TEST_BASE to enable)"
|
|
189
|
+
| some base => do
|
|
190
|
+
let live : SIO Unit := do
|
|
191
|
+
let opts ← newMap #[("base", .str base)]
|
|
192
|
+
let client ← Sdk.newSdk opts
|
|
193
|
+
${liveBlocks} live.run ctx
|
|
194
|
+
let p ← npass.get
|
|
195
|
+
let f ← nfail.get
|
|
196
|
+
IO.println ""
|
|
197
|
+
IO.println s!"PASS {p} FAIL {f}"
|
|
198
|
+
if f > 0 then return 1 else return 0
|
|
199
|
+
`)
|
|
200
|
+
})
|
|
201
|
+
})
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
export {
|
|
206
|
+
Test
|
|
207
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import * as Path from 'node:path'
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
clone,
|
|
5
|
+
walk,
|
|
6
|
+
} from '@voxgig/struct'
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
function projectPath(suffix?: string): string {
|
|
10
|
+
return Path.normalize(Path.join(__dirname, '../../..', suffix ?? ''))
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
// A Lean 4 string literal. Lean strings are UTF-8, so non-ASCII passes through;
|
|
15
|
+
// only the structural characters need escaping. (Backticks are ordinary in Lean
|
|
16
|
+
// strings, so the config's `body`-style transform exprs embed verbatim.)
|
|
17
|
+
function leanString(s: string): string {
|
|
18
|
+
let out = '"'
|
|
19
|
+
for (const ch of String(s)) {
|
|
20
|
+
if (ch === '"') out += '\\"'
|
|
21
|
+
else if (ch === '\\') out += '\\\\'
|
|
22
|
+
else if (ch === '\n') out += '\\n'
|
|
23
|
+
else if (ch === '\t') out += '\\t'
|
|
24
|
+
else if (ch === '\r') out += '\\r'
|
|
25
|
+
else out += ch
|
|
26
|
+
}
|
|
27
|
+
return out + '"'
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
// Lean reserved words that cannot be bare identifiers.
|
|
32
|
+
const LEAN_RESERVED = new Set<string>([
|
|
33
|
+
'do', 'let', 'fun', 'match', 'with', 'if', 'then', 'else', 'by', 'end',
|
|
34
|
+
'namespace', 'section', 'open', 'import', 'def', 'partial', 'mutual',
|
|
35
|
+
'structure', 'inductive', 'class', 'instance', 'where', 'deriving', 'return',
|
|
36
|
+
'try', 'catch', 'for', 'in', 'while', 'have', 'show', 'from', 'set_option',
|
|
37
|
+
])
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
// A collision-free lower-camel Lean identifier for a model name.
|
|
41
|
+
function leanVarName(name: string): string {
|
|
42
|
+
let s = String(name).replace(/[^a-zA-Z0-9_]/g, '_')
|
|
43
|
+
if (s.length === 0) {
|
|
44
|
+
s = 'x'
|
|
45
|
+
}
|
|
46
|
+
s = s.charAt(0).toLowerCase() + s.slice(1)
|
|
47
|
+
if (!/^[a-z_]/.test(s)) {
|
|
48
|
+
s = 'e_' + s
|
|
49
|
+
}
|
|
50
|
+
return LEAN_RESERVED.has(s) ? s + '_' : s
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
// The lowercase-hyphenated package name (used for the lake package + repo).
|
|
55
|
+
function pkgName(model: any): string {
|
|
56
|
+
const org = (model.origin || 'voxgig-sdk').replace(/-sdk$/, '')
|
|
57
|
+
return `${org}-${model.name}-sdk`.toLowerCase().replace(/[^a-z0-9-]/g, '-')
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
// Remove `$`-suffixed model annotation keys (so the embedded config is clean).
|
|
62
|
+
function clean(o: any) {
|
|
63
|
+
return walk(clone(o), (k: any, v: any, p: any) => {
|
|
64
|
+
if (null != k && k.endsWith('$')) {
|
|
65
|
+
delete p[k]
|
|
66
|
+
}
|
|
67
|
+
return v
|
|
68
|
+
})
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
export {
|
|
73
|
+
clean,
|
|
74
|
+
leanString,
|
|
75
|
+
leanVarName,
|
|
76
|
+
pkgName,
|
|
77
|
+
projectPath,
|
|
78
|
+
}
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
each,
|
|
12
12
|
isAuthActive,
|
|
13
13
|
resolveAuthPrefix,
|
|
14
|
+
serverVariables,
|
|
14
15
|
} from '@voxgig/sdkgen'
|
|
15
16
|
|
|
16
17
|
|
|
@@ -46,6 +47,14 @@ const Config = cmp(async function Config(props: any) {
|
|
|
46
47
|
let baseUrl = ''
|
|
47
48
|
try { baseUrl = getModelPath(model, `main.${KIT}.info.servers.0.url`) } catch (_e) { }
|
|
48
49
|
|
|
50
|
+
// Templated server URL: emit the spec's server-variable defaults so the
|
|
51
|
+
// runtime can substitute {name} placeholders in base (see make_options).
|
|
52
|
+
const svars = serverVariables(model)
|
|
53
|
+
const serverBlock = 0 === svars.length ? '' :
|
|
54
|
+
' server = {\n' +
|
|
55
|
+
svars.map((v: any) => ` [${JSON.stringify(v.name)}] = ${JSON.stringify(v.dflt)},\n`).join('') +
|
|
56
|
+
' },\n'
|
|
57
|
+
|
|
49
58
|
const authBlock = authActive
|
|
50
59
|
? ` auth = {
|
|
51
60
|
prefix = "${authPrefix}",
|
|
@@ -73,7 +82,7 @@ local function make_config()
|
|
|
73
82
|
Content(` },
|
|
74
83
|
options = {
|
|
75
84
|
base = "${baseUrl}",
|
|
76
|
-
${authBlock} headers = ${formatLuaTable(headers, 3)},
|
|
85
|
+
${serverBlock}${authBlock} headers = ${formatLuaTable(headers, 3)},
|
|
77
86
|
entity = {
|
|
78
87
|
`)
|
|
79
88
|
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
File, Content,
|
|
22
22
|
} from '@voxgig/sdkgen'
|
|
23
23
|
|
|
24
|
-
import { canonToType, opTypeName, opRequestShape, warnEntityTypeCollisions } from '@voxgig/sdkgen'
|
|
24
|
+
import { canonToType, opTypeName, opRequestShape, warnEntityTypeCollisions , deriveEntityNames } from '@voxgig/sdkgen'
|
|
25
25
|
|
|
26
26
|
import {
|
|
27
27
|
KIT,
|
|
@@ -53,11 +53,10 @@ const EntityTypes = cmp(function EntityTypes(props: any) {
|
|
|
53
53
|
// filter, so inactive entities still get class files referencing these
|
|
54
54
|
// typed names. Filter on `name` (always present), NOT `active` — parity
|
|
55
55
|
// with the go emitter's fix.
|
|
56
|
-
const entityList =
|
|
56
|
+
const entityList = deriveEntityNames(entity)
|
|
57
57
|
// Derive the PascalCase Name up-front — it is set LAZILY by names(), so an
|
|
58
58
|
// entity not yet named (e.g. a fieldless placeholder) would otherwise read
|
|
59
59
|
// `Name = undefined` below. Parity with the go emitter's fix.
|
|
60
|
-
entityList.forEach((e: any) => { if (null == e.Name) names(e, e.name) })
|
|
61
60
|
|
|
62
61
|
// Surface duplicate generated type names (two entities with the same
|
|
63
62
|
// PascalCase Name) — they would redeclare a type in statically-typed
|
|
@@ -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
|
-
entityClassName,
|
|
7
|
+
entityClassName, entityCollection,
|
|
8
8
|
} from '@voxgig/sdkgen'
|
|
9
9
|
|
|
10
10
|
import {
|
|
@@ -24,7 +24,7 @@ const Entity = cmp(function Entity(props: any) {
|
|
|
24
24
|
// data-type name. The class is a module-local table (snake-cased file name),
|
|
25
25
|
// so this is used only for the local identifier — kept uniform with the other
|
|
26
26
|
// languages.
|
|
27
|
-
const entityColl =
|
|
27
|
+
const entityColl = entityCollection(model)
|
|
28
28
|
const cls = entityClassName(entity, entityColl)
|
|
29
29
|
|
|
30
30
|
const entrep = {
|
|
@@ -40,7 +40,7 @@ const Entity = cmp(function Entity(props: any) {
|
|
|
40
40
|
|
|
41
41
|
File({ name: entity.name + '_entity.' + target.ext }, () => {
|
|
42
42
|
|
|
43
|
-
const opnames = Object.keys(entity.op)
|
|
43
|
+
const opnames = Object.keys(entity.op || {})
|
|
44
44
|
|
|
45
45
|
const opfrags =
|
|
46
46
|
(['load', 'list', 'create', 'update', 'remove']
|
|
@@ -57,7 +57,7 @@ dependencies = {
|
|
|
57
57
|
`)
|
|
58
58
|
|
|
59
59
|
const seen = new Set<string>(['lua', 'dkjson'])
|
|
60
|
-
for (const d of collectDeps(model, target.name, target.deps)) {
|
|
60
|
+
for (const d of collectDeps(model, target.name, target.deps, ctx$.log)) {
|
|
61
61
|
if (seen.has(d.name)) continue
|
|
62
62
|
seen.add(d.name)
|
|
63
63
|
const v = d.source === 'target' ? (d.version || '0.0') : d.version
|