@voxgig/sdkgen 1.2.1 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/voxgig-sdkgen +2 -2
- package/dist/action/action.d.ts +2 -1
- package/dist/action/action.js +15 -9
- package/dist/action/action.js.map +1 -1
- package/dist/action/feature.js +6 -3
- package/dist/action/feature.js.map +1 -1
- package/dist/action/target.d.ts +7 -1
- package/dist/action/target.js +13 -6
- package/dist/action/target.js.map +1 -1
- package/dist/cmp/Changelog.d.ts +2 -0
- package/dist/cmp/Changelog.js +30 -0
- package/dist/cmp/Changelog.js.map +1 -0
- package/dist/cmp/Deploy.d.ts +2 -0
- package/dist/cmp/Deploy.js +227 -0
- package/dist/cmp/Deploy.js.map +1 -0
- package/dist/cmp/FeatureHook.js +5 -6
- package/dist/cmp/FeatureHook.js.map +1 -1
- package/dist/cmp/License.d.ts +2 -0
- package/dist/cmp/License.js +44 -0
- package/dist/cmp/License.js.map +1 -0
- package/dist/cmp/Readme.js +2 -0
- package/dist/cmp/Readme.js.map +1 -1
- package/dist/cmp/ReadmeErrors.d.ts +2 -0
- package/dist/cmp/ReadmeErrors.js +210 -0
- package/dist/cmp/ReadmeErrors.js.map +1 -0
- package/dist/cmp/ReadmeExplanation.js +213 -223
- package/dist/cmp/ReadmeExplanation.js.map +1 -1
- package/dist/cmp/ReadmeModel.js +6 -1
- package/dist/cmp/ReadmeModel.js.map +1 -1
- package/dist/cmp/ReadmeTop.js +389 -82
- package/dist/cmp/ReadmeTop.js.map +1 -1
- package/dist/cmp/Security.d.ts +2 -0
- package/dist/cmp/Security.js +36 -0
- package/dist/cmp/Security.js.map +1 -0
- package/dist/helpers/canonType.d.ts +7 -0
- package/dist/helpers/canonType.js +74 -0
- package/dist/helpers/canonType.js.map +1 -0
- package/dist/helpers/collectDeps.d.ts +3 -2
- package/dist/helpers/collectDeps.js.map +1 -1
- package/dist/helpers/naming.d.ts +3 -0
- package/dist/helpers/naming.js +51 -0
- package/dist/helpers/naming.js.map +1 -0
- package/dist/helpers/opExample.d.ts +13 -0
- package/dist/helpers/opExample.js +149 -0
- package/dist/helpers/opExample.js.map +1 -0
- package/dist/helpers/opShape.d.ts +18 -0
- package/dist/helpers/opShape.js +193 -0
- package/dist/helpers/opShape.js.map +1 -0
- package/dist/helpers/packageMeta.d.ts +27 -0
- package/dist/helpers/packageMeta.js +224 -0
- package/dist/helpers/packageMeta.js.map +1 -0
- package/dist/sdkgen.d.ts +11 -1
- package/dist/sdkgen.js +57 -18
- package/dist/sdkgen.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types.d.ts +65 -2
- package/dist/types.js.map +1 -1
- package/dist/utility.js +20 -11
- package/dist/utility.js.map +1 -1
- package/model/sdkgen.aontu +137 -0
- package/package.json +11 -5
- package/project/.sdk/model/target/go-cli.jsonic +47 -0
- package/project/.sdk/model/target/go-mcp.jsonic +41 -0
- package/project/.sdk/model/target/go.jsonic +9 -3
- package/project/.sdk/model/target/js.jsonic +13 -0
- package/project/.sdk/model/target/lua.jsonic +13 -0
- package/project/.sdk/model/target/php.jsonic +13 -0
- package/project/.sdk/model/target/py.jsonic +13 -0
- package/project/.sdk/model/target/rb.jsonic +13 -0
- package/project/.sdk/model/target/ts.jsonic +13 -0
- package/project/.sdk/src/cmp/go/EntityOperation_go.ts +1 -0
- package/project/.sdk/src/cmp/go/EntityTypes_go.ts +197 -0
- package/project/.sdk/src/cmp/go/Entity_go.ts +2 -1
- package/project/.sdk/src/cmp/go/MainEntity_go.ts +6 -0
- package/project/.sdk/src/cmp/go/Main_go.ts +23 -3
- package/project/.sdk/src/cmp/go/Package_go.ts +1 -1
- package/project/.sdk/src/cmp/go/ReadmeEntity_go.ts +18 -6
- package/project/.sdk/src/cmp/go/ReadmeExamplesTest_go.ts +684 -0
- package/project/.sdk/src/cmp/go/ReadmeExplanation_go.ts +1 -1
- package/project/.sdk/src/cmp/go/ReadmeHowto_go.ts +48 -8
- package/project/.sdk/src/cmp/go/ReadmeInstall_go.ts +11 -6
- package/project/.sdk/src/cmp/go/ReadmeIntro_go.ts +40 -1
- package/project/.sdk/src/cmp/go/ReadmeModel_go.ts +63 -17
- package/project/.sdk/src/cmp/go/ReadmeOptions_go.ts +4 -3
- package/project/.sdk/src/cmp/go/ReadmeQuick_go.ts +124 -115
- package/project/.sdk/src/cmp/go/ReadmeRef_go.ts +28 -15
- package/project/.sdk/src/cmp/go/ReadmeTopQuick_go.ts +33 -9
- package/project/.sdk/src/cmp/go/ReadmeTopTest_go.ts +35 -5
- package/project/.sdk/src/cmp/go/TestEntity_go.ts +1 -1
- package/project/.sdk/src/cmp/go/Test_go.ts +5 -1
- package/project/.sdk/src/cmp/go/fragment/Entity.fragment.go +21 -0
- package/project/.sdk/src/cmp/go/fragment/EntityCreateOp.fragment.go +11 -0
- package/project/.sdk/src/cmp/go/fragment/EntityListOp.fragment.go +11 -0
- package/project/.sdk/src/cmp/go/fragment/EntityLoadOp.fragment.go +11 -0
- package/project/.sdk/src/cmp/go/fragment/EntityRemoveOp.fragment.go +11 -0
- package/project/.sdk/src/cmp/go/fragment/EntityUpdateOp.fragment.go +11 -0
- package/project/.sdk/src/cmp/go-cli/Main_go-cli.ts +195 -0
- package/project/.sdk/src/cmp/go-cli/fragment/main.fragment.go +106 -0
- package/project/.sdk/src/cmp/go-cli/fragment/words.fragment.go +132 -0
- package/project/.sdk/src/cmp/go-mcp/Main_go-mcp.ts +184 -0
- package/project/.sdk/src/cmp/go-mcp/fragment/main.fragment.go +68 -0
- package/project/.sdk/src/cmp/go-mcp/fragment/tools.fragment.go +114 -0
- package/project/.sdk/src/cmp/js/EntityTypes_js.ts +111 -0
- package/project/.sdk/src/cmp/js/MainEntity_js.ts +1 -0
- package/project/.sdk/src/cmp/js/Main_js.ts +3 -0
- package/project/.sdk/src/cmp/js/Package_js.ts +16 -7
- package/project/.sdk/src/cmp/js/ReadmeEntity_js.ts +13 -7
- package/project/.sdk/src/cmp/js/ReadmeExplanation_js.ts +2 -2
- package/project/.sdk/src/cmp/js/ReadmeHowto_js.ts +52 -11
- package/project/.sdk/src/cmp/js/ReadmeIntro_js.ts +39 -1
- package/project/.sdk/src/cmp/js/ReadmeModel_js.ts +50 -18
- package/project/.sdk/src/cmp/js/ReadmeOptions_js.ts +4 -3
- package/project/.sdk/src/cmp/js/ReadmeQuick_js.ts +45 -19
- package/project/.sdk/src/cmp/js/ReadmeRef_js.ts +24 -13
- package/project/.sdk/src/cmp/js/ReadmeTopHowto_js.ts +3 -0
- package/project/.sdk/src/cmp/js/ReadmeTopQuick_js.ts +28 -12
- package/project/.sdk/src/cmp/js/ReadmeTopTest_js.ts +23 -3
- package/project/.sdk/src/cmp/js/fragment/EntityCreateOp.fragment.js +5 -0
- package/project/.sdk/src/cmp/js/fragment/EntityListOp.fragment.js +5 -0
- package/project/.sdk/src/cmp/js/fragment/EntityLoadOp.fragment.js +5 -0
- package/project/.sdk/src/cmp/js/fragment/EntityRemoveOp.fragment.js +5 -0
- package/project/.sdk/src/cmp/js/fragment/EntityUpdateOp.fragment.js +5 -0
- package/project/.sdk/src/cmp/js/utility_js.ts +57 -0
- package/project/.sdk/src/cmp/lua/EntityTypes_lua.ts +113 -0
- package/project/.sdk/src/cmp/lua/MainEntity_lua.ts +8 -0
- package/project/.sdk/src/cmp/lua/Main_lua.ts +4 -0
- package/project/.sdk/src/cmp/lua/Package_lua.ts +23 -4
- package/project/.sdk/src/cmp/lua/ReadmeEntity_lua.ts +12 -10
- package/project/.sdk/src/cmp/lua/ReadmeExamplesTest_lua.ts +293 -0
- package/project/.sdk/src/cmp/lua/ReadmeHowto_lua.ts +46 -8
- package/project/.sdk/src/cmp/lua/ReadmeInstall_lua.ts +19 -3
- package/project/.sdk/src/cmp/lua/ReadmeIntro_lua.ts +38 -1
- package/project/.sdk/src/cmp/lua/ReadmeModel_lua.ts +51 -16
- package/project/.sdk/src/cmp/lua/ReadmeOptions_lua.ts +4 -3
- package/project/.sdk/src/cmp/lua/ReadmeQuick_lua.ts +79 -18
- package/project/.sdk/src/cmp/lua/ReadmeRef_lua.ts +25 -20
- package/project/.sdk/src/cmp/lua/ReadmeTopQuick_lua.ts +17 -9
- package/project/.sdk/src/cmp/lua/ReadmeTopTest_lua.ts +32 -5
- package/project/.sdk/src/cmp/lua/Test_lua.ts +4 -0
- package/project/.sdk/src/cmp/lua/fragment/EntityCreateOp.fragment.lua +4 -0
- package/project/.sdk/src/cmp/lua/fragment/EntityListOp.fragment.lua +4 -0
- package/project/.sdk/src/cmp/lua/fragment/EntityLoadOp.fragment.lua +4 -0
- package/project/.sdk/src/cmp/lua/fragment/EntityRemoveOp.fragment.lua +4 -0
- package/project/.sdk/src/cmp/lua/fragment/EntityUpdateOp.fragment.lua +4 -0
- package/project/.sdk/src/cmp/php/EntityTypes_php.ts +142 -0
- package/project/.sdk/src/cmp/php/MainEntity_php.ts +18 -1
- package/project/.sdk/src/cmp/php/Main_php.ts +4 -0
- package/project/.sdk/src/cmp/php/Package_php.ts +18 -7
- package/project/.sdk/src/cmp/php/ReadmeEntity_php.ts +15 -11
- package/project/.sdk/src/cmp/php/ReadmeExamplesTest_php.ts +401 -0
- package/project/.sdk/src/cmp/php/ReadmeHowto_php.ts +56 -13
- package/project/.sdk/src/cmp/php/ReadmeInstall_php.ts +15 -3
- package/project/.sdk/src/cmp/php/ReadmeIntro_php.ts +40 -1
- package/project/.sdk/src/cmp/php/ReadmeModel_php.ts +26 -8
- package/project/.sdk/src/cmp/php/ReadmeOptions_php.ts +4 -3
- package/project/.sdk/src/cmp/php/ReadmeQuick_php.ts +80 -22
- package/project/.sdk/src/cmp/php/ReadmeRef_php.ts +51 -42
- package/project/.sdk/src/cmp/php/ReadmeTopHowto_php.ts +1 -1
- package/project/.sdk/src/cmp/php/ReadmeTopQuick_php.ts +19 -11
- package/project/.sdk/src/cmp/php/ReadmeTopTest_php.ts +41 -11
- package/project/.sdk/src/cmp/php/TestDirect_php.ts +9 -9
- package/project/.sdk/src/cmp/php/TestEntity_php.ts +6 -12
- package/project/.sdk/src/cmp/php/Test_php.ts +4 -0
- package/project/.sdk/src/cmp/php/fragment/Entity.fragment.php +13 -1
- package/project/.sdk/src/cmp/php/fragment/EntityCreateOp.fragment.php +10 -1
- package/project/.sdk/src/cmp/php/fragment/EntityListOp.fragment.php +10 -1
- package/project/.sdk/src/cmp/php/fragment/EntityLoadOp.fragment.php +10 -1
- package/project/.sdk/src/cmp/php/fragment/EntityRemoveOp.fragment.php +10 -1
- package/project/.sdk/src/cmp/php/fragment/EntityUpdateOp.fragment.php +10 -1
- package/project/.sdk/src/cmp/php/fragment/Main.fragment.php +22 -14
- package/project/.sdk/src/cmp/py/EntityTypes_py.ts +184 -0
- package/project/.sdk/src/cmp/py/Entity_py.ts +27 -0
- package/project/.sdk/src/cmp/py/MainEntity_py.ts +2 -1
- package/project/.sdk/src/cmp/py/Main_py.ts +35 -0
- package/project/.sdk/src/cmp/py/Package_py.ts +24 -3
- package/project/.sdk/src/cmp/py/ReadmeEntity_py.ts +27 -11
- package/project/.sdk/src/cmp/py/ReadmeExamplesTest_py.ts +626 -0
- package/project/.sdk/src/cmp/py/ReadmeHowto_py.ts +53 -14
- package/project/.sdk/src/cmp/py/ReadmeInstall_py.ts +19 -3
- package/project/.sdk/src/cmp/py/ReadmeIntro_py.ts +48 -1
- package/project/.sdk/src/cmp/py/ReadmeModel_py.ts +28 -10
- package/project/.sdk/src/cmp/py/ReadmeOptions_py.ts +4 -3
- package/project/.sdk/src/cmp/py/ReadmeQuick_py.ts +73 -24
- package/project/.sdk/src/cmp/py/ReadmeRef_py.ts +57 -37
- package/project/.sdk/src/cmp/py/ReadmeTopHowto_py.ts +1 -1
- package/project/.sdk/src/cmp/py/ReadmeTopQuick_py.ts +19 -11
- package/project/.sdk/src/cmp/py/ReadmeTopTest_py.ts +30 -5
- package/project/.sdk/src/cmp/py/TestDirect_py.ts +7 -9
- package/project/.sdk/src/cmp/py/TestEntity_py.ts +6 -14
- package/project/.sdk/src/cmp/py/Test_py.ts +4 -0
- package/project/.sdk/src/cmp/py/fragment/Entity.fragment.py +5 -2
- package/project/.sdk/src/cmp/py/fragment/EntityCreateOp.fragment.py +1 -1
- package/project/.sdk/src/cmp/py/fragment/EntityListOp.fragment.py +5 -1
- package/project/.sdk/src/cmp/py/fragment/EntityLoadOp.fragment.py +6 -1
- package/project/.sdk/src/cmp/py/fragment/EntityRemoveOp.fragment.py +6 -1
- package/project/.sdk/src/cmp/py/fragment/EntityUpdateOp.fragment.py +1 -1
- package/project/.sdk/src/cmp/py/fragment/Main.fragment.py +17 -10
- package/project/.sdk/src/cmp/rb/EntityTypes_rb.ts +136 -0
- package/project/.sdk/src/cmp/rb/MainEntity_rb.ts +1 -0
- package/project/.sdk/src/cmp/rb/Main_rb.ts +4 -0
- package/project/.sdk/src/cmp/rb/Package_rb.ts +34 -7
- package/project/.sdk/src/cmp/rb/ReadmeEntity_rb.ts +26 -10
- package/project/.sdk/src/cmp/rb/ReadmeExamplesTest_rb.ts +289 -0
- package/project/.sdk/src/cmp/rb/ReadmeHowto_rb.ts +72 -21
- package/project/.sdk/src/cmp/rb/ReadmeInstall_rb.ts +16 -4
- package/project/.sdk/src/cmp/rb/ReadmeIntro_rb.ts +40 -1
- package/project/.sdk/src/cmp/rb/ReadmeModel_rb.ts +29 -12
- package/project/.sdk/src/cmp/rb/ReadmeOptions_rb.ts +4 -3
- package/project/.sdk/src/cmp/rb/ReadmeQuick_rb.ts +85 -22
- package/project/.sdk/src/cmp/rb/ReadmeRef_rb.ts +56 -37
- package/project/.sdk/src/cmp/rb/ReadmeTopHowto_rb.ts +1 -1
- package/project/.sdk/src/cmp/rb/ReadmeTopQuick_rb.ts +19 -11
- package/project/.sdk/src/cmp/rb/ReadmeTopTest_rb.ts +43 -11
- package/project/.sdk/src/cmp/rb/TestDirect_rb.ts +9 -9
- package/project/.sdk/src/cmp/rb/TestEntity_rb.ts +6 -12
- package/project/.sdk/src/cmp/rb/Test_rb.ts +4 -0
- package/project/.sdk/src/cmp/rb/fragment/Entity.fragment.rb +2 -0
- package/project/.sdk/src/cmp/rb/fragment/EntityCreateOp.fragment.rb +5 -0
- package/project/.sdk/src/cmp/rb/fragment/EntityListOp.fragment.rb +20 -2
- package/project/.sdk/src/cmp/rb/fragment/EntityLoadOp.fragment.rb +8 -1
- package/project/.sdk/src/cmp/rb/fragment/EntityRemoveOp.fragment.rb +6 -1
- package/project/.sdk/src/cmp/rb/fragment/EntityUpdateOp.fragment.rb +5 -0
- package/project/.sdk/src/cmp/rb/fragment/Main.fragment.rb +24 -8
- package/project/.sdk/src/cmp/ts/EntityTypes_ts.ts +105 -0
- package/project/.sdk/src/cmp/ts/Entity_ts.ts +17 -1
- package/project/.sdk/src/cmp/ts/MainEntity_ts.ts +1 -0
- package/project/.sdk/src/cmp/ts/Main_ts.ts +6 -0
- package/project/.sdk/src/cmp/ts/Package_ts.ts +14 -7
- package/project/.sdk/src/cmp/ts/ReadmeEntity_ts.ts +13 -7
- package/project/.sdk/src/cmp/ts/ReadmeExampleTest_ts.ts +81 -0
- package/project/.sdk/src/cmp/ts/ReadmeExamplesTest_ts.ts +446 -0
- package/project/.sdk/src/cmp/ts/ReadmeExplanation_ts.ts +2 -2
- package/project/.sdk/src/cmp/ts/ReadmeHowto_ts.ts +57 -11
- package/project/.sdk/src/cmp/ts/ReadmeInstall_ts.ts +19 -6
- package/project/.sdk/src/cmp/ts/ReadmeIntro_ts.ts +39 -1
- package/project/.sdk/src/cmp/ts/ReadmeModel_ts.ts +50 -18
- package/project/.sdk/src/cmp/ts/ReadmeOptions_ts.ts +4 -3
- package/project/.sdk/src/cmp/ts/ReadmeQuick_ts.ts +95 -40
- package/project/.sdk/src/cmp/ts/ReadmeRef_ts.ts +24 -13
- package/project/.sdk/src/cmp/ts/ReadmeTopHowto_ts.ts +3 -0
- package/project/.sdk/src/cmp/ts/ReadmeTopQuick_ts.ts +44 -12
- package/project/.sdk/src/cmp/ts/ReadmeTopTest_ts.ts +23 -3
- package/project/.sdk/src/cmp/ts/TestEntity_ts.ts +2 -2
- package/project/.sdk/src/cmp/ts/Test_ts.ts +5 -0
- package/project/.sdk/src/cmp/ts/fragment/Entity.fragment.ts +3 -1
- package/project/.sdk/src/cmp/ts/fragment/EntityBase.fragment.ts +10 -5
- package/project/.sdk/src/cmp/ts/fragment/EntityCreateOp.fragment.ts +4 -2
- package/project/.sdk/src/cmp/ts/fragment/EntityListOp.fragment.ts +4 -2
- package/project/.sdk/src/cmp/ts/fragment/EntityLoadOp.fragment.ts +4 -2
- package/project/.sdk/src/cmp/ts/fragment/EntityRemoveOp.fragment.ts +4 -2
- package/project/.sdk/src/cmp/ts/fragment/EntityUpdateOp.fragment.ts +4 -2
- package/project/.sdk/src/cmp/ts/utility_ts.ts +59 -0
- package/project/.sdk/tm/go/LICENSE +1 -1
- package/project/.sdk/tm/go/Makefile +36 -1
- package/project/.sdk/tm/go/VERSION +1 -0
- package/project/.sdk/tm/go/core/context.go +12 -7
- package/project/.sdk/tm/go-cli/src/feature/README.md +6 -0
- package/project/.sdk/tm/go-cli/src/feature/base/.gitkeep +0 -0
- package/project/.sdk/tm/go-cli/src/feature/log/.gitkeep +0 -0
- package/project/.sdk/tm/go-cli/src/feature/test/.gitkeep +0 -0
- package/project/.sdk/tm/go-mcp/src/feature/README.md +6 -0
- package/project/.sdk/tm/go-mcp/src/feature/base/.gitkeep +0 -0
- package/project/.sdk/tm/go-mcp/src/feature/log/.gitkeep +0 -0
- package/project/.sdk/tm/go-mcp/src/feature/test/.gitkeep +0 -0
- package/project/.sdk/tm/js/LICENSE +1 -1
- package/project/.sdk/tm/js/Makefile +41 -0
- package/project/.sdk/tm/lua/LICENSE +1 -1
- package/project/.sdk/tm/lua/Makefile +40 -1
- package/project/.sdk/tm/lua/core/context.lua +13 -8
- package/project/.sdk/tm/php/LICENSE +1 -1
- package/project/.sdk/tm/php/Makefile +31 -1
- package/project/.sdk/tm/php/VERSION +1 -0
- package/project/.sdk/tm/php/core/Context.php +12 -6
- package/project/.sdk/tm/php/test/PrimaryUtilityTest.php +13 -4
- package/project/.sdk/tm/php/utility/Done.php +2 -2
- package/project/.sdk/tm/php/utility/MakeError.php +3 -3
- package/project/.sdk/tm/py/LICENSE +1 -1
- package/project/.sdk/tm/py/Makefile +34 -1
- package/project/.sdk/tm/py/core/context.py +12 -7
- package/project/.sdk/tm/py/test/test_primary_utility.py +15 -4
- package/project/.sdk/tm/py/utility/done.py +3 -1
- package/project/.sdk/tm/py/utility/make_error.py +2 -2
- package/project/.sdk/tm/rb/LICENSE +1 -1
- package/project/.sdk/tm/rb/Makefile +33 -1
- package/project/.sdk/tm/rb/core/context.rb +8 -3
- package/project/.sdk/tm/rb/test/primary_utility_test.rb +2 -2
- package/project/.sdk/tm/rb/utility/done.rb +3 -1
- package/project/.sdk/tm/rb/utility/make_error.rb +5 -2
- package/project/.sdk/tm/ts/LICENSE +1 -1
- package/project/.sdk/tm/ts/Makefile +42 -0
- package/project/.sdk/tm/ts/src/Context.ts +8 -3
- package/src/action/action.ts +17 -10
- package/src/action/feature.ts +8 -6
- package/src/action/target.ts +17 -8
- package/src/cmp/Changelog.ts +34 -0
- package/src/cmp/Deploy.ts +258 -0
- package/src/cmp/FeatureHook.ts +6 -8
- package/src/cmp/License.ts +49 -0
- package/src/cmp/Readme.ts +2 -0
- package/src/cmp/ReadmeErrors.ts +257 -0
- package/src/cmp/ReadmeExplanation.ts +250 -230
- package/src/cmp/ReadmeModel.ts +7 -2
- package/src/cmp/ReadmeTop.ts +411 -95
- package/src/cmp/Security.ts +41 -0
- package/src/helpers/canonType.ts +89 -0
- package/src/helpers/collectDeps.ts +5 -3
- package/src/helpers/naming.ts +59 -0
- package/src/helpers/opExample.ts +170 -0
- package/src/helpers/opShape.ts +236 -0
- package/src/helpers/packageMeta.ts +236 -0
- package/src/sdkgen.ts +87 -20
- package/src/tsconfig.json +1 -0
- package/src/types.ts +85 -2
- package/src/utility.ts +22 -11
- package/README.md +0 -2
- package/dist/action/lang.d.ts +0 -2
- package/dist/action/lang.js +0 -68
- package/dist/action/lang.js.map +0 -1
- package/dist/cmp/Hook.d.ts +0 -2
- package/dist/cmp/Hook.js +0 -10
- package/dist/cmp/Hook.js.map +0 -1
- package/dist/cmp/Top.d.ts +0 -2
- package/dist/cmp/Top.js +0 -23
- package/dist/cmp/Top.js.map +0 -1
- package/dist/prepare-openapi.d.ts +0 -2
- package/dist/prepare-openapi.js +0 -37
- package/dist/prepare-openapi.js.map +0 -1
- package/model/sdkgen.jsonic +0 -74
- package/project/.sdk/tm/go/utility/struct/go.mod +0 -3
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
|
|
2
|
+
import { cmp, Content, File } from '@voxgig/sdkgen'
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
// Generates ts/test/ReadmeExample.test.ts — a test that reads the
|
|
6
|
+
// repo's top-level README.md at runtime, extracts the first TS code
|
|
7
|
+
// block under "## Quickstart", transforms `new <Name>SDK(...)`
|
|
8
|
+
// to `<Name>SDK.test()` so it runs offline, evaluates the rest, and
|
|
9
|
+
// asserts no error. Catches drift between the README quickstart and
|
|
10
|
+
// the real SDK API.
|
|
11
|
+
const ReadmeExampleTest = cmp(function ReadmeExampleTest(props: any) {
|
|
12
|
+
const { ctx$: { model } } = props
|
|
13
|
+
const Name = model.const.Name
|
|
14
|
+
|
|
15
|
+
File({ name: 'ReadmeExample.test.ts' }, () => {
|
|
16
|
+
Content(`// Verifies the README's lead-language quickstart still runs.
|
|
17
|
+
|
|
18
|
+
import { describe, it } from 'node:test'
|
|
19
|
+
import assert from 'node:assert'
|
|
20
|
+
import * as Fs from 'node:fs'
|
|
21
|
+
import * as Path from 'node:path'
|
|
22
|
+
|
|
23
|
+
import { ${Name}SDK } from '..'
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
function findFirstTsBlock(md: string, sectionHeading: string): string | null {
|
|
27
|
+
const escapedHeading = sectionHeading.replace(/[.*+?^\${}()|[\\]\\\\]/g, '\\\\$&')
|
|
28
|
+
const re = new RegExp('##\\\\s+' + escapedHeading + '[\\\\s\\\\S]*?\`\`\`ts\\\\n([\\\\s\\\\S]*?)\`\`\`')
|
|
29
|
+
const m = md.match(re)
|
|
30
|
+
return m ? m[1] : null
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
function transformForTestMode(code: string, name: string): string {
|
|
35
|
+
// Strip import lines — symbols come from the test's outer scope.
|
|
36
|
+
let out = code.replace(/^\\s*import\\s+[^;\\n]+;?\\s*$/gm, '')
|
|
37
|
+
// Swap real client construction for test mode (no network, no auth).
|
|
38
|
+
out = out.replace(new RegExp('new\\\\s+' + name + 'SDK\\\\([^)]*\\\\)', 'g'), name + 'SDK.test()')
|
|
39
|
+
return out
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
describe('README example', () => {
|
|
44
|
+
it('lead-language quickstart runs in test mode', async () => {
|
|
45
|
+
const readmePath = Path.join(__dirname, '..', '..', 'README.md')
|
|
46
|
+
const md = Fs.readFileSync(readmePath, 'utf8')
|
|
47
|
+
|
|
48
|
+
const block = findFirstTsBlock(md, 'Quickstart')
|
|
49
|
+
assert(block, 'No TypeScript code block found under "## Quickstart" in README.md')
|
|
50
|
+
|
|
51
|
+
const code = transformForTestMode(block, '${Name}')
|
|
52
|
+
|
|
53
|
+
// Run the (transformed) example. Async, so wrap in AsyncFunction.
|
|
54
|
+
const AsyncFunction = Object.getPrototypeOf(async function () {}).constructor
|
|
55
|
+
const silentConsole = { log: () => {}, error: () => {}, warn: () => {} }
|
|
56
|
+
const runner = new AsyncFunction('${Name}SDK', 'console', code)
|
|
57
|
+
|
|
58
|
+
// The example should at least parse and have a valid call shape
|
|
59
|
+
// (every method exists on the SDK and accepts the args shown). A
|
|
60
|
+
// "Not found" / 404 from test mode means the SDK accepted the call
|
|
61
|
+
// but there's no fixture for that match — that's a test-data gap,
|
|
62
|
+
// not a README bug, so it's OK. Everything else (TypeError,
|
|
63
|
+
// ReferenceError, SyntaxError) means the README example is out of
|
|
64
|
+
// sync with the real SDK API and the test should fail.
|
|
65
|
+
try {
|
|
66
|
+
await runner(${Name}SDK, silentConsole)
|
|
67
|
+
} catch (err: any) {
|
|
68
|
+
const msg = String(err?.message ?? err)
|
|
69
|
+
if (/\\b(404|Not found)\\b/i.test(msg)) return
|
|
70
|
+
throw err
|
|
71
|
+
}
|
|
72
|
+
})
|
|
73
|
+
})
|
|
74
|
+
`)
|
|
75
|
+
})
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
export {
|
|
80
|
+
ReadmeExampleTest
|
|
81
|
+
}
|
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
|
|
2
|
+
import { cmp, Content, File } from '@voxgig/sdkgen'
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
KIT,
|
|
6
|
+
getModelPath,
|
|
7
|
+
} from '@voxgig/apidef'
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
// Generates ts/test/readme_examples.test.ts — a COMPLETENESS GATE that
|
|
11
|
+
// guarantees every fenced \`\`\`ts code example across all THREE docs (the
|
|
12
|
+
// repo root README.md, this target's per-language README.md, and its
|
|
13
|
+
// REFERENCE.md) is unit-tested. Every block from every doc is:
|
|
14
|
+
//
|
|
15
|
+
// (1) TYPE-CHECKED against the real SDK types with the repo's local
|
|
16
|
+
// \`tsc --noEmit\`. To stay robust against tsc suppressing all semantic
|
|
17
|
+
// diagnostics program-wide whenever one file has a syntax error, blocks
|
|
18
|
+
// are compiled one-file-per-block in a fixpoint: compile the batch, drop
|
|
19
|
+
// the ones that error, recompile the rest, until a pass is clean — so a
|
|
20
|
+
// real type bug can never hide behind a neighbouring illustration's
|
|
21
|
+
// syntax error.
|
|
22
|
+
// (2) EXECUTED, if RUNNABLE (constructs \`new <Sdk>SDK\` / \`<Sdk>SDK.test\`
|
|
23
|
+
// or drives \`client.\`), by rewriting it to a seeded test-mode client
|
|
24
|
+
// and running it offline. A programming error (undefined method, wrong
|
|
25
|
+
// arity, bad symbol) fails; only a 404 / "Not found" domain error for an
|
|
26
|
+
// unseeded id is tolerated. This now runs for ALL THREE docs (previously
|
|
27
|
+
// only the root README executed).
|
|
28
|
+
// (3) PARTITIONED into exactly one of { executed, typechecked-only,
|
|
29
|
+
// illustration } with the counts asserted to sum to the total. A block
|
|
30
|
+
// that does NOT type-check is only allowed if it matches the NARROW
|
|
31
|
+
// illustration allowlist (bare method-signature \`?:\`, \`/* placeholder */\`
|
|
32
|
+
// value, or a type-SHAPE block). Any other non-type-checking block FAILS
|
|
33
|
+
// the test, quoting the block — it is NEVER silently skipped. A per-doc
|
|
34
|
+
// summary line makes the coverage visible in the test output.
|
|
35
|
+
const ReadmeExamplesTest = cmp(function ReadmeExamplesTest(props: any) {
|
|
36
|
+
const { ctx$: { model } } = props
|
|
37
|
+
const Name = model.const.Name
|
|
38
|
+
|
|
39
|
+
// Seed a fixture for every active entity so list()/load() resolve
|
|
40
|
+
// offline in test mode with no network. Keyed by the entity's model
|
|
41
|
+
// name (the same key the test-mode transport looks up).
|
|
42
|
+
const entity = getModelPath(model, `main.${KIT}.entity`)
|
|
43
|
+
const seedEntities: Record<string, any> = {}
|
|
44
|
+
Object.values(entity).forEach((e: any) => {
|
|
45
|
+
if (e && false !== e.active && 'string' === typeof e.name) {
|
|
46
|
+
seedEntities[e.name] = { test01: { id: 'test01' } }
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
const seedLiteral = JSON.stringify({ entity: seedEntities })
|
|
50
|
+
|
|
51
|
+
File({ name: 'readme_examples.test.ts' }, () => {
|
|
52
|
+
Content(`// Completeness gate over every TypeScript example in this SDK's docs.
|
|
53
|
+
//
|
|
54
|
+
// Covers all THREE documentation files — the repo root README.md, this
|
|
55
|
+
// target's README.md, and its REFERENCE.md. Every fenced \`\`\`ts block in
|
|
56
|
+
// every one is put through the same pipeline:
|
|
57
|
+
//
|
|
58
|
+
// (1) TYPE-CHECK — every block is compiled with the repo's local
|
|
59
|
+
// \`tsc --noEmit\` against the real SDK types. A block that misuses the
|
|
60
|
+
// SDK types (e.g. \`.data\` on a \`list()\` array, or a string id where a
|
|
61
|
+
// number is required) is a compile error.
|
|
62
|
+
// (2) EXECUTE — every RUNNABLE block (one that constructs the SDK or
|
|
63
|
+
// drives \`client.\`) is rewritten to seeded test mode, transpiled to
|
|
64
|
+
// JS, and run offline. A programming error (undefined method,
|
|
65
|
+
// wrong-arg-count, bad symbol) fails the test; only an expected domain
|
|
66
|
+
// error (a 404 / "Not found" for an unseeded id) is tolerated.
|
|
67
|
+
// (3) COMPLETENESS — every block is partitioned into exactly one of
|
|
68
|
+
// { executed, typechecked-only, illustration } and the counts must sum
|
|
69
|
+
// to the total. A block that does NOT type-check is allowed ONLY if it
|
|
70
|
+
// matches the NARROW illustration allowlist (a bare method signature
|
|
71
|
+
// \`?:\`, a \`/* placeholder */\` value, or a type-SHAPE block). Any other
|
|
72
|
+
// non-type-checking block FAILS the test, quoting the block — it is
|
|
73
|
+
// never silently skipped.
|
|
74
|
+
//
|
|
75
|
+
// Generated by @voxgig/sdkgen — do not edit by hand.
|
|
76
|
+
|
|
77
|
+
import { describe, it } from 'node:test'
|
|
78
|
+
import assert from 'node:assert'
|
|
79
|
+
import * as Fs from 'node:fs'
|
|
80
|
+
import * as Path from 'node:path'
|
|
81
|
+
import { createRequire } from 'node:module'
|
|
82
|
+
import { spawnSync } from 'node:child_process'
|
|
83
|
+
|
|
84
|
+
import { ${Name}SDK } from '..'
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
const SDK_NAME = '${Name}SDK'
|
|
88
|
+
|
|
89
|
+
// A fixture for every entity, so list()/load() resolve offline with no
|
|
90
|
+
// network. Snippet client construction is rewritten to seed this.
|
|
91
|
+
const TEST_SEED = ${seedLiteral}
|
|
92
|
+
const SEED_ARG = JSON.stringify(TEST_SEED)
|
|
93
|
+
const SEEDED_CTOR = SDK_NAME + '.test(' + SEED_ARG + ')'
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
// The three docs this gate covers, resolved relative to dist-test/.
|
|
97
|
+
const DOCS: Array<{ label: string; key: string; path: string }> = [
|
|
98
|
+
{ label: 'root README.md', key: 'root_readme', path: Path.join(__dirname, '..', '..', 'README.md') },
|
|
99
|
+
{ label: 'ts/README.md', key: 'lang_readme', path: Path.join(__dirname, '..', 'README.md') },
|
|
100
|
+
{ label: 'ts/REFERENCE.md', key: 'reference', path: Path.join(__dirname, '..', 'REFERENCE.md') },
|
|
101
|
+
]
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
// Pull out the body of every \`\`\`ts fenced code block.
|
|
105
|
+
function extractTsBlocks(md: string): string[] {
|
|
106
|
+
const blocks: string[] = []
|
|
107
|
+
const re = /\`\`\`ts\\n([\\s\\S]*?)\`\`\`/g
|
|
108
|
+
let m: RegExpExecArray | null
|
|
109
|
+
while ((m = re.exec(md)) !== null) {
|
|
110
|
+
blocks.push(m[1])
|
|
111
|
+
}
|
|
112
|
+
return blocks
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
// Snippet import lines reference the published package name, which is not
|
|
117
|
+
// resolvable from inside the repo; the SDK symbol is supplied by the one
|
|
118
|
+
// module-level import we emit / inject instead.
|
|
119
|
+
function stripImports(code: string): string {
|
|
120
|
+
return code.replace(/^\\s*import\\s+[^\\n]*$/gm, '')
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
// A block is an ILLUSTRATION shape — documentation, not runnable code — if
|
|
125
|
+
// it matches this NARROW allowlist. These are the ONLY shapes a
|
|
126
|
+
// non-type-checking block is allowed to be; anything else that fails to
|
|
127
|
+
// type-check is a real bug and fails the gate. Three shapes:
|
|
128
|
+
// 1. a bare method / constructor signature with a typed-parameter
|
|
129
|
+
// signature ("?:", e.g. \`options?: { base?: string }\`);
|
|
130
|
+
// 2. a placeholder-comment value ("/*", e.g. \`field: /* string */\`);
|
|
131
|
+
// 3. a type-SHAPE block that lists fields as \`name: TypeKeyword\` with the
|
|
132
|
+
// type standing alone as the value — e.g. the DirectResult / FetchDef
|
|
133
|
+
// shape \`{ ok: boolean; status: number; ... }\`. Those bare keywords
|
|
134
|
+
// are undeclared VALUES (TS2693 "only refers to a type"). Matched
|
|
135
|
+
// only at the START of a line, so a genuine annotation inside runnable
|
|
136
|
+
// code (e.g. \`(ctx: any) => ...\`) is NOT matched.
|
|
137
|
+
const SHAPE_ILLUSTRATION =
|
|
138
|
+
/^\\s*[A-Za-z_$][\\w$]*\\??\\s*:\\s*(?:boolean|number|string|object|any|unknown|never|void|symbol|bigint|Record<|Partial<|Array<|Map<|Set<)/m
|
|
139
|
+
function isIllustrationShape(code: string): boolean {
|
|
140
|
+
if (code.includes('?:')) {
|
|
141
|
+
return true
|
|
142
|
+
}
|
|
143
|
+
if (code.includes('/*')) {
|
|
144
|
+
return true
|
|
145
|
+
}
|
|
146
|
+
if (SHAPE_ILLUSTRATION.test(code)) {
|
|
147
|
+
return true
|
|
148
|
+
}
|
|
149
|
+
return false
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
// A block is RUNNABLE if it constructs the SDK (\`new <Sdk>SDK\` /
|
|
154
|
+
// \`<Sdk>SDK.test\`) or drives a \`client.\` — those are the blocks the execute
|
|
155
|
+
// gate rewrites to seeded test mode and runs.
|
|
156
|
+
function isRunnable(code: string): boolean {
|
|
157
|
+
return (
|
|
158
|
+
/new\\s+${Name}SDK\\b/.test(code) ||
|
|
159
|
+
/\\b${Name}SDK\\.test\\b/.test(code) ||
|
|
160
|
+
/\\bclient\\s*\\./.test(code)
|
|
161
|
+
)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
// Wrap ONE block as a self-contained temp module: the block goes in its own
|
|
166
|
+
// scope inside an async function with a shared seeded \`client\`.
|
|
167
|
+
function buildSnippetModule(block: string): string {
|
|
168
|
+
const inner = stripImports(block).split('\\n').map((l) => ' ' + l).join('\\n')
|
|
169
|
+
return [
|
|
170
|
+
"import { " + SDK_NAME + " } from '..'",
|
|
171
|
+
'',
|
|
172
|
+
'async function __ex() {',
|
|
173
|
+
// Shared client for snippets that reference \`client\` without constructing
|
|
174
|
+
// one (e.g. the direct() example).
|
|
175
|
+
' const client = ' + SDK_NAME + '.test()',
|
|
176
|
+
' void client',
|
|
177
|
+
' {',
|
|
178
|
+
inner,
|
|
179
|
+
' }',
|
|
180
|
+
'}',
|
|
181
|
+
'void __ex',
|
|
182
|
+
'',
|
|
183
|
+
].join('\\n')
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
// Compile a batch of blocks in ONE tsc pass — one temp file per block, so
|
|
188
|
+
// each is an isolated program entry — and return which snippet indices
|
|
189
|
+
// errored. NOTE: tsc suppresses ALL semantic diagnostics program-wide as
|
|
190
|
+
// soon as any file has a SYNTAX error, so a single batch cannot be trusted;
|
|
191
|
+
// \`typeCheckBlocks\` drives this in a fixpoint that removes erroring blocks
|
|
192
|
+
// and recompiles the rest until a pass is clean.
|
|
193
|
+
function compileBatch(indices: number[], blocks: string[], key: string): {
|
|
194
|
+
errored: Set<number>; raw: string; unattributed: boolean
|
|
195
|
+
} {
|
|
196
|
+
const tsDir = Path.join(__dirname, '..')
|
|
197
|
+
const testDir = Path.join(tsDir, 'test')
|
|
198
|
+
// Leading dot: TypeScript wildcard includes skip dot-files, so these temp
|
|
199
|
+
// files are never swept into the normal build.
|
|
200
|
+
const files: string[] = []
|
|
201
|
+
|
|
202
|
+
try {
|
|
203
|
+
for (const i of indices) {
|
|
204
|
+
const f = Path.join(testDir, '.examples_' + key + '_snippet' + i + '.gen.ts')
|
|
205
|
+
Fs.writeFileSync(f, buildSnippetModule(blocks[i]), 'utf8')
|
|
206
|
+
files.push(f)
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const requireFrom = createRequire(__filename)
|
|
210
|
+
const tsc = requireFrom.resolve('typescript/bin/tsc')
|
|
211
|
+
|
|
212
|
+
const res = spawnSync(process.execPath, [
|
|
213
|
+
tsc,
|
|
214
|
+
'--noEmit',
|
|
215
|
+
'--strict',
|
|
216
|
+
'--pretty', 'false',
|
|
217
|
+
'--target', 'ES2022',
|
|
218
|
+
'--module', 'nodenext',
|
|
219
|
+
'--moduleResolution', 'nodenext',
|
|
220
|
+
'--esModuleInterop',
|
|
221
|
+
'--resolveJsonModule',
|
|
222
|
+
'--skipLibCheck',
|
|
223
|
+
'--types', 'node',
|
|
224
|
+
...files,
|
|
225
|
+
], { cwd: tsDir, encoding: 'utf8' })
|
|
226
|
+
|
|
227
|
+
const raw = ((res.stdout || '') + (res.stderr || '')).trim()
|
|
228
|
+
const errored = new Set<number>()
|
|
229
|
+
let unattributed = false
|
|
230
|
+
|
|
231
|
+
if (0 !== res.status) {
|
|
232
|
+
for (const line of raw.split('\\n')) {
|
|
233
|
+
const m = /_snippet(\\d+)\\.gen\\.ts\\(\\d+,\\d+\\):\\s*error/.exec(line)
|
|
234
|
+
if (null == m) {
|
|
235
|
+
// A genuine error diagnostic not attributable to a snippet file
|
|
236
|
+
// (e.g. inside the SDK itself) is an anomaly.
|
|
237
|
+
if (/:\\s*error\\s+TS\\d+/.test(line)) {
|
|
238
|
+
unattributed = true
|
|
239
|
+
}
|
|
240
|
+
continue
|
|
241
|
+
}
|
|
242
|
+
errored.add(parseInt(m[1], 10))
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return { errored, raw, unattributed }
|
|
247
|
+
} finally {
|
|
248
|
+
for (const f of files) {
|
|
249
|
+
Fs.rmSync(f, { force: true })
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
// Determine, robustly, which of a doc's blocks fail to type-check. Because
|
|
256
|
+
// one syntax error suppresses semantic diagnostics for the whole batch, we
|
|
257
|
+
// iterate: compile the still-unresolved blocks, record the ones that
|
|
258
|
+
// errored, drop them, and recompile the rest — until a pass reports no
|
|
259
|
+
// errors. Each erroring pass strictly shrinks the working set, so this
|
|
260
|
+
// terminates. \`globalError\` flags an unattributable tsc error, surfaced
|
|
261
|
+
// verbatim by the caller.
|
|
262
|
+
function typeCheckBlocks(blocks: string[], key: string): {
|
|
263
|
+
failing: Set<number>; raw: string; globalError: boolean
|
|
264
|
+
} {
|
|
265
|
+
const failing = new Set<number>()
|
|
266
|
+
const raws: string[] = []
|
|
267
|
+
let globalError = false
|
|
268
|
+
let remaining = blocks.map((_b, i) => i)
|
|
269
|
+
|
|
270
|
+
// Guard: at most one pass per block plus a final clean pass.
|
|
271
|
+
for (let pass = 0; pass <= blocks.length && 0 < remaining.length; pass++) {
|
|
272
|
+
const { errored, raw, unattributed } = compileBatch(remaining, blocks, key)
|
|
273
|
+
raws.push(raw)
|
|
274
|
+
if (unattributed) {
|
|
275
|
+
globalError = true
|
|
276
|
+
}
|
|
277
|
+
if (0 === errored.size) {
|
|
278
|
+
break
|
|
279
|
+
}
|
|
280
|
+
for (const i of errored) {
|
|
281
|
+
failing.add(i)
|
|
282
|
+
}
|
|
283
|
+
remaining = remaining.filter((i) => !errored.has(i))
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
return { failing, raw: raws.filter(Boolean).join('\\n'), globalError }
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
// Turn a documented snippet into an offline-runnable one: strip imports,
|
|
291
|
+
// rewrite real client construction (\`new <Sdk>SDK(...)\` and any
|
|
292
|
+
// \`<Sdk>SDK.test(...)\`) to a seeded test-mode client, and give snippets
|
|
293
|
+
// that reference \`client\` without constructing one a shared seeded client.
|
|
294
|
+
function rewriteForRun(code: string): string {
|
|
295
|
+
let out = stripImports(code)
|
|
296
|
+
out = out.replace(/new\\s+${Name}SDK\\s*\\([^)]*\\)/g, () => SEEDED_CTOR)
|
|
297
|
+
out = out.replace(/${Name}SDK\\.test\\s*\\([^)]*\\)/g, () => SEEDED_CTOR)
|
|
298
|
+
if (/\\bclient\\b/.test(out) && !/\\b(?:const|let|var)\\s+client\\b/.test(out)) {
|
|
299
|
+
out = 'const client = ' + SEEDED_CTOR + '\\n' + out
|
|
300
|
+
}
|
|
301
|
+
return out
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
// Run every runnable, non-illustration block from a doc offline in seeded
|
|
306
|
+
// test mode. Returns a list of failure descriptions (empty === all passed).
|
|
307
|
+
async function executeBlocks(blocks: string[]): Promise<string[]> {
|
|
308
|
+
const requireFrom = createRequire(__filename)
|
|
309
|
+
const ts = requireFrom('typescript')
|
|
310
|
+
|
|
311
|
+
const AsyncFunction = Object.getPrototypeOf(async function () {}).constructor
|
|
312
|
+
const silentConsole = { log() {}, error() {}, warn() {}, info() {} }
|
|
313
|
+
|
|
314
|
+
const failures: string[] = []
|
|
315
|
+
|
|
316
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
317
|
+
// Illustration shapes are documentation, not runnable code.
|
|
318
|
+
if (!isRunnable(blocks[i]) || isIllustrationShape(blocks[i])) {
|
|
319
|
+
continue
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
const src = rewriteForRun(blocks[i])
|
|
323
|
+
if ('' === src.trim()) {
|
|
324
|
+
continue
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// Compile the snippet to JS (strips type annotations) so it runs under
|
|
328
|
+
// node exactly as a real caller would.
|
|
329
|
+
const js = ts.transpileModule(src, {
|
|
330
|
+
compilerOptions: {
|
|
331
|
+
target: ts.ScriptTarget.ES2020,
|
|
332
|
+
module: ts.ModuleKind.ESNext,
|
|
333
|
+
},
|
|
334
|
+
}).outputText
|
|
335
|
+
|
|
336
|
+
let runner: any
|
|
337
|
+
try {
|
|
338
|
+
runner = new AsyncFunction(SDK_NAME, 'console', js)
|
|
339
|
+
} catch (err: any) {
|
|
340
|
+
failures.push('snippet ' + i + ' failed to compile as runnable JS: ' +
|
|
341
|
+
String((err && err.message) || err))
|
|
342
|
+
continue
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
try {
|
|
346
|
+
await runner(${Name}SDK, silentConsole)
|
|
347
|
+
} catch (err: any) {
|
|
348
|
+
const msg = String((err && err.message) || err)
|
|
349
|
+
// Tolerate the one expected domain error: no fixture seeded for the
|
|
350
|
+
// requested id (a 404 / "Not found" from test mode). A programming
|
|
351
|
+
// error (undefined method/symbol, wrong arg count) is a real doc bug
|
|
352
|
+
// and is NOT tolerated.
|
|
353
|
+
if (/\\b(?:404|not found)\\b/i.test(msg)) {
|
|
354
|
+
continue
|
|
355
|
+
}
|
|
356
|
+
failures.push('snippet ' + i + ' threw at runtime: ' + msg)
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
return failures
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
function indentBlock(code: string): string {
|
|
365
|
+
return code.replace(/^/gm, ' ').replace(/\\s+$/, '')
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
describe('README examples', () => {
|
|
370
|
+
for (const doc of DOCS) {
|
|
371
|
+
it(doc.label + ' — every example type-checks or is a known illustration', () => {
|
|
372
|
+
// A target without this doc has nothing to check.
|
|
373
|
+
if (!Fs.existsSync(doc.path)) {
|
|
374
|
+
return
|
|
375
|
+
}
|
|
376
|
+
const md = Fs.readFileSync(doc.path, 'utf8')
|
|
377
|
+
const blocks = extractTsBlocks(md)
|
|
378
|
+
assert(blocks.length > 0, 'No TypeScript code blocks found in ' + doc.label)
|
|
379
|
+
|
|
380
|
+
const { failing, raw, globalError } = typeCheckBlocks(blocks, doc.key)
|
|
381
|
+
assert(!globalError,
|
|
382
|
+
'tsc reported an error outside any snippet in ' + doc.label +
|
|
383
|
+
' — the harness could not attribute it:\\n\\n' + raw + '\\n')
|
|
384
|
+
|
|
385
|
+
let executed = 0
|
|
386
|
+
let typecheckedOnly = 0
|
|
387
|
+
let illustration = 0
|
|
388
|
+
const unrecognized: string[] = []
|
|
389
|
+
|
|
390
|
+
blocks.forEach((b, i) => {
|
|
391
|
+
const typechecks = !failing.has(i)
|
|
392
|
+
const shape = isIllustrationShape(b)
|
|
393
|
+
const runnable = isRunnable(b) && !shape
|
|
394
|
+
|
|
395
|
+
if (!typechecks && shape) {
|
|
396
|
+
illustration++
|
|
397
|
+
} else if (!typechecks && !shape) {
|
|
398
|
+
unrecognized.push(' snippet ' + i + ':\\n' + indentBlock(b))
|
|
399
|
+
} else if (typechecks && runnable) {
|
|
400
|
+
executed++
|
|
401
|
+
} else {
|
|
402
|
+
typecheckedOnly++
|
|
403
|
+
}
|
|
404
|
+
})
|
|
405
|
+
|
|
406
|
+
// Emit the coverage summary FIRST so it is always visible, even when
|
|
407
|
+
// an assertion below fails.
|
|
408
|
+
console.log('README examples [' + doc.label + ']: total=' + blocks.length +
|
|
409
|
+
' executed=' + executed + ' typechecked=' + typecheckedOnly +
|
|
410
|
+
' illustration=' + illustration)
|
|
411
|
+
|
|
412
|
+
assert.strictEqual(unrecognized.length, 0,
|
|
413
|
+
'These ' + doc.label + ' \`\`\`ts blocks neither type-check nor match the ' +
|
|
414
|
+
'illustration allowlist. Fix the snippet (or the SDK), or — if it is ' +
|
|
415
|
+
'genuinely illustrative — reshape it to the allowlist:\\n\\n' +
|
|
416
|
+
unrecognized.join('\\n\\n') + '\\n\\ntsc output:\\n' + raw + '\\n')
|
|
417
|
+
|
|
418
|
+
assert.strictEqual(blocks.length, executed + typecheckedOnly + illustration,
|
|
419
|
+
'completeness partition mismatch for ' + doc.label + ': ' + blocks.length +
|
|
420
|
+
' total != ' + executed + ' executed + ' + typecheckedOnly +
|
|
421
|
+
' typechecked + ' + illustration + ' illustration')
|
|
422
|
+
})
|
|
423
|
+
|
|
424
|
+
it(doc.label + ' — every runnable example executes in test mode', async () => {
|
|
425
|
+
if (!Fs.existsSync(doc.path)) {
|
|
426
|
+
return
|
|
427
|
+
}
|
|
428
|
+
const md = Fs.readFileSync(doc.path, 'utf8')
|
|
429
|
+
const blocks = extractTsBlocks(md)
|
|
430
|
+
assert(blocks.length > 0, 'No TypeScript code blocks found in ' + doc.label)
|
|
431
|
+
|
|
432
|
+
const failures = await executeBlocks(blocks)
|
|
433
|
+
assert.strictEqual(failures.length, 0,
|
|
434
|
+
doc.label + ' runnable TypeScript snippets failed to run in test mode:\\n\\n' +
|
|
435
|
+
failures.join('\\n') + '\\n')
|
|
436
|
+
})
|
|
437
|
+
}
|
|
438
|
+
})
|
|
439
|
+
`)
|
|
440
|
+
})
|
|
441
|
+
})
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
export {
|
|
445
|
+
ReadmeExamplesTest
|
|
446
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
import { cmp, Content } from '@voxgig/sdkgen'
|
|
2
|
+
import { cmp, Content, packageName } from '@voxgig/sdkgen'
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
const ReadmeExplanation = cmp(function ReadmeExplanation(props: any) {
|
|
@@ -21,7 +21,7 @@ ${model.name}/
|
|
|
21
21
|
Import the SDK from the package root:
|
|
22
22
|
|
|
23
23
|
\`\`\`ts
|
|
24
|
-
import { ${model.Name}SDK } from '${model.name}'
|
|
24
|
+
import { ${model.Name}SDK } from '${packageName(model, target.name)}'
|
|
25
25
|
\`\`\`
|
|
26
26
|
|
|
27
27
|
`)
|
|
@@ -1,21 +1,64 @@
|
|
|
1
1
|
|
|
2
|
-
import { cmp, Content, isAuthActive } from '@voxgig/sdkgen'
|
|
2
|
+
import { cmp, Content, isAuthActive, envName, entityIdField, entityDataIdField, entityPrimaryOp, opRequestShape, safeVarName } from '@voxgig/sdkgen'
|
|
3
3
|
|
|
4
4
|
import {
|
|
5
5
|
KIT,
|
|
6
6
|
getModelPath,
|
|
7
|
+
nom,
|
|
7
8
|
} from '@voxgig/apidef'
|
|
8
9
|
|
|
10
|
+
import { exampleValue } from './utility_ts'
|
|
11
|
+
|
|
9
12
|
|
|
10
13
|
const ReadmeHowto = cmp(function ReadmeHowto(props: any) {
|
|
11
14
|
const { target, ctx$: { model } } = props
|
|
12
15
|
|
|
16
|
+
const entity = getModelPath(model, `main.${KIT}.entity`)
|
|
17
|
+
const exampleEntity = Object.values(entity || {}).find((e: any) => e && e.active !== false) as any
|
|
18
|
+
const eName = exampleEntity ? nom(exampleEntity, 'Name') : 'Entity'
|
|
19
|
+
// Variable-safe lowercase name (a `Delete` entity must not bind `delete`).
|
|
20
|
+
const eVar = safeVarName(eName.toLowerCase(), 'ts')
|
|
21
|
+
|
|
22
|
+
// Drive the test-mode / stateful examples off the entity's PRIMARY op — an op
|
|
23
|
+
// it actually exposes — never a hardcoded `load` a create-only entity lacks.
|
|
24
|
+
const primaryOp = exampleEntity ? (entityPrimaryOp(exampleEntity) || 'load') : 'load'
|
|
25
|
+
const primaryOpDef = exampleEntity && exampleEntity.op && exampleEntity.op[primaryOp]
|
|
26
|
+
const isMatchOp = 'load' === primaryOp || 'remove' === primaryOp
|
|
27
|
+
// Model-driven id key: `idF` is the entity's id-like MATCH field name, or null
|
|
28
|
+
// when it has none. `dataIdF` is the id on the RETURNED record's data type —
|
|
29
|
+
// reading `.id` off a record whose data type has none is a TS2339.
|
|
30
|
+
const idF = exampleEntity ? entityIdField(exampleEntity) : null
|
|
31
|
+
const dataIdF = exampleEntity ? entityDataIdField(exampleEntity) : null
|
|
32
|
+
|
|
33
|
+
// A type-correct, language-idiomatic argument for the primary op call.
|
|
34
|
+
const primaryArg = (idPlaceholder: string): string => {
|
|
35
|
+
if (!exampleEntity) return ''
|
|
36
|
+
if ('list' === primaryOp) return ''
|
|
37
|
+
if (isMatchOp) {
|
|
38
|
+
return idF ? `{ ${idF}: ${exampleValue(exampleEntity, primaryOpDef, idF, idPlaceholder)} }` : ''
|
|
39
|
+
}
|
|
40
|
+
// create / update: a body of the required writable fields.
|
|
41
|
+
const items = opRequestShape(exampleEntity, primaryOp).items
|
|
42
|
+
.filter((it: any) => it.name !== idF && it.name !== 'id')
|
|
43
|
+
const required = items.filter((it: any) => !it.optional)
|
|
44
|
+
const chosen = required.length ? required : items.slice(0, 3)
|
|
45
|
+
const pairs = chosen.map((it: any) =>
|
|
46
|
+
`${it.name}: ${exampleValue(exampleEntity, primaryOpDef, it.name, 'example_' + it.name)}`)
|
|
47
|
+
return `{ ${pairs.join(', ')} }`
|
|
48
|
+
}
|
|
49
|
+
const testCallArg = primaryArg('test01')
|
|
50
|
+
const stateCallArg = primaryArg('example')
|
|
51
|
+
// Only read `.id` off the returned record when its data type carries one.
|
|
52
|
+
const stateDataLine = dataIdF
|
|
53
|
+
? `console.log(data.${dataIdF})`
|
|
54
|
+
: `console.log(data)`
|
|
55
|
+
|
|
13
56
|
const authActive = isAuthActive(model)
|
|
14
57
|
const apikeyTesterCtor = authActive
|
|
15
58
|
? `new ${model.const.Name}SDK({ apikey: '...' })`
|
|
16
59
|
: `new ${model.const.Name}SDK()`
|
|
17
60
|
const apikeyExtendField = authActive ? `\n apikey: '...',` : ''
|
|
18
|
-
const apikeyEnvLine = authActive ? `\n${model
|
|
61
|
+
const apikeyEnvLine = authActive ? `\n${envName(model)}_APIKEY=<your-key>` : ''
|
|
19
62
|
|
|
20
63
|
Content(`### Make a direct HTTP request
|
|
21
64
|
|
|
@@ -28,6 +71,9 @@ const result = await client.direct({
|
|
|
28
71
|
params: { id: 'example' },
|
|
29
72
|
})
|
|
30
73
|
|
|
74
|
+
if (result instanceof Error) {
|
|
75
|
+
throw result
|
|
76
|
+
}
|
|
31
77
|
if (result.ok) {
|
|
32
78
|
console.log(result.status) // 200
|
|
33
79
|
console.log(result.data) // response body
|
|
@@ -56,9 +102,9 @@ Create a mock client for unit testing \u2014 no server required:
|
|
|
56
102
|
\`\`\`ts
|
|
57
103
|
const client = ${model.const.Name}SDK.test()
|
|
58
104
|
|
|
59
|
-
const
|
|
60
|
-
//
|
|
61
|
-
|
|
105
|
+
const ${eVar} = await client.${eName}().${primaryOp}(${testCallArg})
|
|
106
|
+
// ${eVar} is a bare entity populated with mock response data
|
|
107
|
+
console.log(${eVar})
|
|
62
108
|
\`\`\`
|
|
63
109
|
|
|
64
110
|
You can also use the instance method:
|
|
@@ -73,14 +119,14 @@ const testClient = client.tester()
|
|
|
73
119
|
Entity instances remember their last match and data:
|
|
74
120
|
|
|
75
121
|
\`\`\`ts
|
|
76
|
-
const entity = client
|
|
122
|
+
const entity = client.${eName}()
|
|
77
123
|
|
|
78
|
-
// First call
|
|
79
|
-
await entity
|
|
124
|
+
// First call runs the operation and stores its result
|
|
125
|
+
await entity.${primaryOp}(${stateCallArg})
|
|
80
126
|
|
|
81
|
-
// Subsequent calls reuse the stored
|
|
127
|
+
// Subsequent calls reuse the stored state
|
|
82
128
|
const data = entity.data()
|
|
83
|
-
|
|
129
|
+
${stateDataLine}
|
|
84
130
|
\`\`\`
|
|
85
131
|
|
|
86
132
|
### Add custom middleware
|
|
@@ -109,7 +155,7 @@ const client = new ${model.const.Name}SDK({${apikeyExtendField}
|
|
|
109
155
|
Create a \`.env.local\` file at the project root:
|
|
110
156
|
|
|
111
157
|
\`\`\`
|
|
112
|
-
${model
|
|
158
|
+
${envName(model)}_TEST_LIVE=TRUE${apikeyEnvLine}
|
|
113
159
|
\`\`\`
|
|
114
160
|
|
|
115
161
|
Then run:
|