@voxgig/sdkgen 3.5.1 → 3.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/voxgig-sdkgen +1 -1
- package/dist/cmp/ExternalTarget.js +1 -1
- package/dist/cmp/ExternalTarget.js.map +1 -1
- package/dist/helpers/naming.d.ts +4 -1
- package/dist/helpers/naming.js +119 -5
- package/dist/helpers/naming.js.map +1 -1
- package/dist/helpers/opShape.js +72 -0
- package/dist/helpers/opShape.js.map +1 -1
- package/dist/helpers/packageMeta.d.ts +2 -1
- package/dist/helpers/packageMeta.js +57 -20
- package/dist/helpers/packageMeta.js.map +1 -1
- package/dist/sdkgen.d.ts +3 -3
- package/dist/sdkgen.js +61 -18
- package/dist/sdkgen.js.map +1 -1
- package/dist/testkit.d.ts +39 -0
- package/dist/testkit.js +663 -0
- package/dist/testkit.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +32 -8
- package/project/.sdk/src/cmp/c/Test_c.ts +5 -7
- package/project/.sdk/src/cmp/clojure/Test_clojure.ts +3 -7
- package/project/.sdk/src/cmp/cpp/Test_cpp.ts +4 -7
- package/project/.sdk/src/cmp/csharp/Package_csharp.ts +1 -1
- package/project/.sdk/src/cmp/csharp/Test_csharp.ts +5 -7
- package/project/.sdk/src/cmp/dart/Test_dart.ts +3 -4
- package/project/.sdk/src/cmp/elixir/Package_elixir.ts +1 -1
- package/project/.sdk/src/cmp/elixir/Test_elixir.ts +5 -6
- package/project/.sdk/src/cmp/go/EntityTypes_go.ts +1 -1
- package/project/.sdk/src/cmp/go/Entity_go.ts +1 -1
- package/project/.sdk/src/cmp/go/Gitignore_go.ts +6 -0
- package/project/.sdk/src/cmp/go/Main_go.ts +2 -2
- package/project/.sdk/src/cmp/go/Package_go.ts +1 -1
- package/project/.sdk/src/cmp/go/ReadmeExamplesTest_go.ts +59 -6
- package/project/.sdk/src/cmp/go/ReadmeExplanation_go.ts +1 -1
- package/project/.sdk/src/cmp/go/ReadmeHowto_go.ts +1 -1
- package/project/.sdk/src/cmp/go/ReadmeInstall_go.ts +1 -1
- package/project/.sdk/src/cmp/go/ReadmeModel_go.ts +1 -1
- package/project/.sdk/src/cmp/go/ReadmeQuick_go.ts +1 -1
- package/project/.sdk/src/cmp/go/ReadmeTopQuick_go.ts +1 -1
- package/project/.sdk/src/cmp/go/ReadmeTopTest_go.ts +1 -1
- package/project/.sdk/src/cmp/go/Test_go.ts +6 -8
- package/project/.sdk/src/cmp/go-cli/Main_go-cli.ts +6 -2
- package/project/.sdk/src/cmp/go-mcp/Main_go-mcp.ts +6 -2
- package/project/.sdk/src/cmp/java/Test_java.ts +4 -7
- package/project/.sdk/src/cmp/js/Package_js.ts +1 -1
- package/project/.sdk/src/cmp/js/Test_js.ts +4 -7
- package/project/.sdk/src/cmp/kotlin/Test_kotlin.ts +4 -7
- package/project/.sdk/src/cmp/lean/Test_lean.ts +3 -3
- package/project/.sdk/src/cmp/lua/Package_lua.ts +2 -2
- package/project/.sdk/src/cmp/lua/Test_lua.ts +5 -7
- package/project/.sdk/src/cmp/ocaml/Test_ocaml.ts +3 -7
- package/project/.sdk/src/cmp/perl/Package_perl.ts +1 -1
- package/project/.sdk/src/cmp/perl/Test_perl.ts +5 -7
- package/project/.sdk/src/cmp/php/EntityTypes_php.ts +13 -2
- package/project/.sdk/src/cmp/php/Package_php.ts +2 -2
- package/project/.sdk/src/cmp/php/Test_php.ts +5 -7
- package/project/.sdk/src/cmp/py/Package_py.ts +2 -2
- package/project/.sdk/src/cmp/py/Test_py.ts +5 -7
- package/project/.sdk/src/cmp/py-data/Main_py-data.ts +14 -19
- package/project/.sdk/src/cmp/rb/Package_rb.ts +3 -3
- package/project/.sdk/src/cmp/rb/ReadmeInstall_rb.ts +1 -1
- package/project/.sdk/src/cmp/rb/Test_rb.ts +5 -7
- package/project/.sdk/src/cmp/rust/Test_rust.ts +5 -7
- package/project/.sdk/src/cmp/scala/Test_scala.ts +5 -2
- package/project/.sdk/src/cmp/seneca-provider/Gitignore_seneca-provider.ts +161 -0
- package/project/.sdk/src/cmp/seneca-provider/Main_seneca-provider.ts +20 -11
- package/project/.sdk/src/cmp/swift/Test_swift.ts +5 -7
- package/project/.sdk/src/cmp/ts/Package_ts.ts +1 -1
- package/project/.sdk/src/cmp/ts/Test_ts.ts +8 -7
- package/project/.sdk/src/cmp/zig/Test_zig.ts +3 -7
- package/project/.sdk/tm/c/utility/make_point.c +64 -3
- package/project/.sdk/tm/clojure/src/sdk/core.clj +49 -14
- package/project/.sdk/tm/cpp/utility/pipeline.hpp +55 -3
- package/project/.sdk/tm/csharp/feature/TestFeature.cs +36 -2
- package/project/.sdk/tm/csharp/utility/MakePoint.cs +65 -2
- package/project/.sdk/tm/dart/lib/feature/test/TestFeature.dart +34 -4
- package/project/.sdk/tm/dart/lib/utility/MakePointUtility.dart +48 -2
- package/project/.sdk/tm/elixir/lib/projectname/utility.ex +70 -10
- package/project/.sdk/tm/go/feature/test_feature.go +34 -2
- package/project/.sdk/tm/go/utility/make_point.go +66 -2
- package/project/.sdk/tm/java/feature/TestFeature.java +42 -2
- package/project/.sdk/tm/java/utility/MakePoint.java +61 -2
- package/project/.sdk/tm/js/src/feature/test/TestFeature.js +22 -3
- package/project/.sdk/tm/js/src/utility/MakePointUtility.js +72 -2
- package/project/.sdk/tm/kotlin/feature/TestFeature.kt +31 -2
- package/project/.sdk/tm/kotlin/utility/MakePoint.kt +58 -2
- package/project/.sdk/tm/lean/src/SdkUtility.lean +28 -0
- package/project/.sdk/tm/lua/utility/make_point.lua +65 -2
- package/project/.sdk/tm/ocaml/sdk_runtime.ml +40 -2
- package/project/.sdk/tm/perl/utility/make_point.pm +55 -2
- package/project/.sdk/tm/php/feature/TestFeature.php +30 -1
- package/project/.sdk/tm/php/utility/MakePoint.php +49 -1
- package/project/.sdk/tm/py/pkg/utility/make_point.py +56 -2
- package/project/.sdk/tm/rb/utility/make_point.rb +42 -2
- package/project/.sdk/tm/rust/utility/make_point.rs +69 -2
- package/project/.sdk/tm/scala/feature/TestFeature.scala +36 -1
- package/project/.sdk/tm/scala/utility/Make.scala +57 -3
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/feature/TestFeature.swift +29 -1
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/Make.swift +51 -2
- package/project/.sdk/tm/ts/src/feature/test/TestFeature.ts +22 -3
- package/project/.sdk/tm/ts/src/utility/MakePointUtility.ts +72 -2
- package/project/.sdk/tm/zig/core/utility.zig +66 -3
- package/project/sdkgen-package.json +1 -2
- package/src/cmp/ExternalTarget.ts +1 -1
- package/src/helpers/naming.ts +129 -5
- package/src/helpers/opShape.ts +85 -0
- package/src/helpers/packageMeta.ts +59 -20
- package/src/sdkgen.ts +68 -20
- package/src/testkit.ts +863 -0
- package/testkit.d.ts +3 -0
- package/testkit.js +12 -0
- package/project/.sdk/model/target/haskell.aontu +0 -72
- package/project/.sdk/src/cmp/haskell/Config_haskell.ts +0 -98
- package/project/.sdk/src/cmp/haskell/Entity_haskell.ts +0 -13
- package/project/.sdk/src/cmp/haskell/Gitignore_haskell.ts +0 -27
- package/project/.sdk/src/cmp/haskell/Main_haskell.ts +0 -123
- package/project/.sdk/src/cmp/haskell/Package_haskell.ts +0 -60
- package/project/.sdk/src/cmp/haskell/ReadmeEntity_haskell.ts +0 -186
- package/project/.sdk/src/cmp/haskell/ReadmeExamplesTest_haskell.ts +0 -135
- package/project/.sdk/src/cmp/haskell/ReadmeExplanation_haskell.ts +0 -48
- package/project/.sdk/src/cmp/haskell/ReadmeHowto_haskell.ts +0 -168
- package/project/.sdk/src/cmp/haskell/ReadmeInstall_haskell.ts +0 -51
- package/project/.sdk/src/cmp/haskell/ReadmeIntro_haskell.ts +0 -67
- package/project/.sdk/src/cmp/haskell/ReadmeModel_haskell.ts +0 -162
- package/project/.sdk/src/cmp/haskell/ReadmeOptions_haskell.ts +0 -74
- package/project/.sdk/src/cmp/haskell/ReadmeQuick_haskell.ts +0 -241
- package/project/.sdk/src/cmp/haskell/ReadmeRef_haskell.ts +0 -408
- package/project/.sdk/src/cmp/haskell/ReadmeTopHowto_haskell.ts +0 -31
- package/project/.sdk/src/cmp/haskell/ReadmeTopQuick_haskell.ts +0 -104
- package/project/.sdk/src/cmp/haskell/ReadmeTopTest_haskell.ts +0 -80
- package/project/.sdk/src/cmp/haskell/Test_haskell.ts +0 -300
- package/project/.sdk/src/cmp/haskell/tsconfig.json +0 -15
- package/project/.sdk/src/cmp/haskell/utility_haskell.ts +0 -166
- package/project/.sdk/tm/haskell/LICENSE +0 -21
- package/project/.sdk/tm/haskell/Makefile +0 -22
- package/project/.sdk/tm/haskell/VERSION +0 -1
- package/project/.sdk/tm/haskell/src/SdkFeatures.hs +0 -1440
- package/project/.sdk/tm/haskell/src/SdkHelpers.hs +0 -337
- package/project/.sdk/tm/haskell/src/SdkJson.hs +0 -111
- package/project/.sdk/tm/haskell/src/SdkRuntime.hs +0 -1219
- package/project/.sdk/tm/haskell/src/SdkTypes.hs +0 -195
- package/project/.sdk/tm/haskell/src/VoxgigStruct.hs +0 -2299
- package/project/.sdk/tm/haskell/src/Vregex.hs +0 -237
- package/project/.sdk/tm/haskell/src/feature/README.md +0 -5
- package/project/.sdk/tm/haskell/src/feature/audit/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/base/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/cache/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/clienttrack/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/debug/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/idempotency/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/log/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/metrics/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/netsim/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/paging/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/proxy/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/ratelimit/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/rbac/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/retry/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/streaming/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/telemetry/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/test/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/src/feature/timeout/.gitkeep +0 -0
- package/project/.sdk/tm/haskell/test/Harness.hs +0 -281
- package/project/.sdk/tm/haskell/test/Runner.hs +0 -47
- package/project/.sdk/tm/haskell/test/StructCorpus.hs +0 -449
- package/project/.sdk/tm/haskell/test/TCustomUtility.hs +0 -38
- package/project/.sdk/tm/haskell/test/TFeature.hs +0 -794
- package/project/.sdk/tm/haskell/test/TNetsim.hs +0 -50
- package/project/.sdk/tm/haskell/test/TPipeline.hs +0 -334
- package/project/.sdk/tm/haskell/test/TPrimaryUtility.hs +0 -386
- package/project/.sdk/tm/haskell/test/Testutil.hs +0 -59
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import { cmp, File, Content } from '@voxgig/sdkgen'
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
// Emits test/TReadmeExamples.hs — a STRUCTURAL gate over every fenced
|
|
6
|
-
// Haskell code block in the three docs that ship Haskell examples:
|
|
7
|
-
// - the root README.md (top-level, multi-language quick start)
|
|
8
|
-
// - the per-language haskell/README.md
|
|
9
|
-
// - the per-language haskell/REFERENCE.md
|
|
10
|
-
//
|
|
11
|
-
// DESIGN NOTE vs the Python gate (ReadmeExamplesTest_py.ts): the Python
|
|
12
|
-
// version parses AND executes every block in a seeded test-mode subprocess.
|
|
13
|
-
// A faithful Haskell port would compile every snippet against the generated
|
|
14
|
-
// SDK — a throwaway module per block plus a GHC invocation — a large,
|
|
15
|
-
// environment-sensitive harness that cannot be authored safely without a build
|
|
16
|
-
// to validate it. This gate instead validates that every documented Haskell
|
|
17
|
-
// block is PRESENT, non-empty, and STRUCTURALLY well-formed (balanced
|
|
18
|
-
// delimiters). Missing docs are tolerated (a run may generate a subset of
|
|
19
|
-
// phases), and no blocks found records no failures — so this never breaks the
|
|
20
|
-
// shared runner. Upgrading it to a true compile gate is left as a follow-up.
|
|
21
|
-
//
|
|
22
|
-
// The emitted module exposes `tests :: Counters -> IO ()`; the generated
|
|
23
|
-
// SdkGenTests calls it, so it runs inside the standard Runner. The triple
|
|
24
|
-
// backtick fence marker is built from its char code (toEnum 96) so this
|
|
25
|
-
// component's Haskell source needs no backtick/backslash gymnastics.
|
|
26
|
-
const ReadmeExamplesTest = cmp(function ReadmeExamplesTest(props: any) {
|
|
27
|
-
const { target, ctx$: { model } } = props
|
|
28
|
-
|
|
29
|
-
const Name = model.const.Name
|
|
30
|
-
|
|
31
|
-
File({ name: 'TReadmeExamples.' + target.ext }, () => {
|
|
32
|
-
Content(`-- ${Name} SDK — documentation Haskell-examples structural gate.
|
|
33
|
-
--
|
|
34
|
-
-- Validates that every fenced Haskell code block in the SDK docs (the root
|
|
35
|
-
-- README.md, the per-language README.md, and REFERENCE.md) is present,
|
|
36
|
-
-- non-empty, and has balanced delimiters. Missing docs are tolerated (a run
|
|
37
|
-
-- may generate a subset of phases), so this gate never breaks the shared
|
|
38
|
-
-- runner. See ReadmeExamplesTest_haskell for why this is a structural gate
|
|
39
|
-
-- rather than a full compile harness. Generated by @voxgig/sdkgen.
|
|
40
|
-
|
|
41
|
-
{-# LANGUAGE ScopedTypeVariables #-}
|
|
42
|
-
|
|
43
|
-
module TReadmeExamples (tests) where
|
|
44
|
-
|
|
45
|
-
import Control.Exception (SomeException, evaluate, try)
|
|
46
|
-
import Control.Monad (forM_)
|
|
47
|
-
|
|
48
|
-
import Testutil (Counters, runTest)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
-- True for the whitespace characters we trim: space, tab, carriage return.
|
|
52
|
-
isWs :: Char -> Bool
|
|
53
|
-
isWs ch = let n = fromEnum ch in n == 32 || n == 9 || n == 13
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
-- Trim leading/trailing whitespace from a line.
|
|
57
|
-
trimWs :: String -> String
|
|
58
|
-
trimWs = f . f
|
|
59
|
-
where f = reverse . dropWhile isWs
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
-- Read a doc file, tolerating absence (returns "" when missing/unreadable).
|
|
63
|
-
readDoc :: FilePath -> IO String
|
|
64
|
-
readDoc path = do
|
|
65
|
-
r <- try (do s <- readFile path; _ <- evaluate (length s); pure s)
|
|
66
|
-
:: IO (Either SomeException String)
|
|
67
|
-
pure (either (const "") id r)
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
-- Extract the body of every fenced Haskell block from markdown. Returns
|
|
71
|
-
-- (blocks, allClosed) where allClosed is False when a fence was opened but
|
|
72
|
-
-- never closed before EOF — a malformed doc that must fail rather than pass
|
|
73
|
-
-- silently on the unterminated block. The fence marker (three backticks) is
|
|
74
|
-
-- built from its char code so this source stays backtick-free.
|
|
75
|
-
haskellBlocks :: String -> ([String], Bool)
|
|
76
|
-
haskellBlocks src = go (lines src)
|
|
77
|
-
where
|
|
78
|
-
fence3 = replicate 3 (toEnum 96 :: Char)
|
|
79
|
-
fenceHs = fence3 ++ "haskell"
|
|
80
|
-
go [] = ([], True)
|
|
81
|
-
go (l : ls)
|
|
82
|
-
| trimWs l == fenceHs =
|
|
83
|
-
case break (\\x -> trimWs x == fence3) ls of
|
|
84
|
-
(blk, []) -> ([unlines blk], False)
|
|
85
|
-
(blk, _ : rest) -> let (bs, ok) = go rest in (unlines blk : bs, ok)
|
|
86
|
-
| otherwise = go ls
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
-- Balanced (), [], {} outside of double-quoted string literals, with each
|
|
90
|
-
-- closer matching the most-recent opener via a stack (so "([)]" is rejected,
|
|
91
|
-
-- not merely counted). The generated snippets never embed an escaped quote
|
|
92
|
-
-- inside a string.
|
|
93
|
-
balanced :: String -> Bool
|
|
94
|
-
balanced = go False []
|
|
95
|
-
where
|
|
96
|
-
go inStr stack [] = not inStr && null stack
|
|
97
|
-
go inStr stack (c : cs)
|
|
98
|
-
| c == '"' = go (not inStr) stack cs
|
|
99
|
-
| inStr = go inStr stack cs
|
|
100
|
-
| c == '(' = go inStr (')' : stack) cs
|
|
101
|
-
| c == '[' = go inStr (']' : stack) cs
|
|
102
|
-
| c == '{' = go inStr ('}' : stack) cs
|
|
103
|
-
| c == ')' || c == ']' || c == '}' =
|
|
104
|
-
case stack of
|
|
105
|
-
(top : rest) | top == c -> go inStr rest cs
|
|
106
|
-
_ -> False
|
|
107
|
-
| otherwise = go inStr stack cs
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
-- The three documents held to the gate, tagged by human label.
|
|
111
|
-
docs :: [(String, FilePath)]
|
|
112
|
-
docs =
|
|
113
|
-
[ ("root README", "../README.md")
|
|
114
|
-
, ("${target.name} README", "README.md")
|
|
115
|
-
, ("${target.name} REFERENCE", "REFERENCE.md")
|
|
116
|
-
]
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
tests :: Counters -> IO ()
|
|
120
|
-
tests c =
|
|
121
|
-
forM_ docs (\\(label, path) -> do
|
|
122
|
-
src <- readDoc path
|
|
123
|
-
let (blocks, closed) = haskellBlocks src
|
|
124
|
-
runTest c (label ++ " haskell fences closed") (pure closed)
|
|
125
|
-
forM_ (zip [1 :: Int ..] blocks) (\\(i, blk) ->
|
|
126
|
-
runTest c (label ++ " haskell block " ++ show i ++ " well-formed")
|
|
127
|
-
(pure (not (null (trimWs blk)) && balanced blk))))
|
|
128
|
-
`)
|
|
129
|
-
})
|
|
130
|
-
})
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
export {
|
|
134
|
-
ReadmeExamplesTest
|
|
135
|
-
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import { cmp, Content } from '@voxgig/sdkgen'
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const ReadmeExplanation = cmp(function ReadmeExplanation(props: any) {
|
|
6
|
-
const { target, ctx$: { model } } = props
|
|
7
|
-
|
|
8
|
-
Content(`### Data as struct Values
|
|
9
|
-
|
|
10
|
-
The Haskell SDK models every API record as the dynamic \`Value\` type (from
|
|
11
|
-
the vendored \`VoxgigStruct\` module) rather than bespoke Haskell records.
|
|
12
|
-
This mirrors the dynamic nature of the API and keeps the SDK flexible — no
|
|
13
|
-
new datatypes or code generation are needed when the API schema changes.
|
|
14
|
-
|
|
15
|
-
Build request maps with \`jo [(key, value)]\` and read fields back with
|
|
16
|
-
\`getp value "field"\`; scalars are the \`VStr\` / \`VNum\` / \`VBool\`
|
|
17
|
-
constructors, and \`VNoval\` stands for an absent property.
|
|
18
|
-
|
|
19
|
-
### Module structure
|
|
20
|
-
|
|
21
|
-
\`\`\`
|
|
22
|
-
${target.name}/
|
|
23
|
-
├── src/
|
|
24
|
-
│ ├── VoxgigStruct.hs -- vendored dependency-free struct library (Value)
|
|
25
|
-
│ ├── Vregex.hs -- vendored regex support
|
|
26
|
-
│ ├── SdkTypes.hs -- core types (Client, Entity, Feature)
|
|
27
|
-
│ ├── SdkHelpers.hs -- helper functions (jo, getp, ...)
|
|
28
|
-
│ ├── SdkRuntime.hs -- the generic operation pipeline
|
|
29
|
-
│ ├── SdkFeatures.hs -- built-in features + makeEntity
|
|
30
|
-
│ ├── SdkConfig.hs -- generated API configuration + feature factory
|
|
31
|
-
│ └── SdkClient.hs -- generated public client (newSdk, entity accessors)
|
|
32
|
-
├── test/ -- test suites
|
|
33
|
-
├── Makefile -- stock-GHC build/test (no third-party deps)
|
|
34
|
-
└── ${model.const.Name.toLowerCase()}-sdk.cabal -- package manifest (for Hackage)
|
|
35
|
-
\`\`\`
|
|
36
|
-
|
|
37
|
-
The public module (\`SdkClient\`) exports the SDK constructors (\`newSdk\`,
|
|
38
|
-
\`testSdk\`) and one accessor per entity. Import \`VoxgigStruct\` for the
|
|
39
|
-
\`Value\` constructors and \`SdkHelpers\` for \`jo\` / \`getp\`.
|
|
40
|
-
|
|
41
|
-
`)
|
|
42
|
-
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
export {
|
|
47
|
-
ReadmeExplanation
|
|
48
|
-
}
|
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import { cmp, Content, isAuthActive, envName, canonKey, entityIdField, pickExampleEntity, opRequestShape } from '@voxgig/sdkgen'
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
KIT,
|
|
6
|
-
getModelPath,
|
|
7
|
-
nom,
|
|
8
|
-
} from '@voxgig/apidef'
|
|
9
|
-
|
|
10
|
-
import { hsVarName } from './utility_haskell'
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
// A type-correct Haskell `Value` literal for a field's canonical type.
|
|
14
|
-
function hsLit(type: any): string {
|
|
15
|
-
const k = canonKey(type)
|
|
16
|
-
if ('INTEGER' === k || 'NUMBER' === k) return 'VNum 1'
|
|
17
|
-
if ('BOOLEAN' === k) return 'VBool True'
|
|
18
|
-
if ('ARRAY' === k || 'OBJECT' === k) return 'VNoval'
|
|
19
|
-
return 'VStr "example"'
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const ReadmeHowto = cmp(function ReadmeHowto(props: any) {
|
|
24
|
-
const { target, ctx$: { model } } = props
|
|
25
|
-
|
|
26
|
-
const entity = getModelPath(model, `main.${KIT}.entity`)
|
|
27
|
-
// Pick an entity with a real op (prefer a read op). primaryOp is null only
|
|
28
|
-
// when NO entity exposes any op (a direct()-only SDK).
|
|
29
|
-
const { entity: exampleEntity, primaryOp } = pickExampleEntity(entity)
|
|
30
|
-
const eName = exampleEntity ? nom(exampleEntity, 'Name') : 'Entity'
|
|
31
|
-
const eFn = exampleEntity ? hsVarName(exampleEntity.name) : 'entity'
|
|
32
|
-
const idF = exampleEntity ? entityIdField(exampleEntity) : null
|
|
33
|
-
const isMatchOp = 'load' === primaryOp || 'remove' === primaryOp
|
|
34
|
-
let testArgExpr = 'emptyMap'
|
|
35
|
-
if (exampleEntity && isMatchOp) {
|
|
36
|
-
testArgExpr = idF ? `jo [("${idF}", VStr "test01")]` : 'emptyMap'
|
|
37
|
-
} else if (exampleEntity && ('create' === primaryOp || 'update' === primaryOp)) {
|
|
38
|
-
const items = opRequestShape(exampleEntity, primaryOp).items
|
|
39
|
-
.filter((it: any) => it.name !== idF && it.name !== 'id')
|
|
40
|
-
const required = items.filter((it: any) => !it.optional)
|
|
41
|
-
const chosen = required.length ? required : items.slice(0, 3)
|
|
42
|
-
testArgExpr = `jo [${chosen.map((it: any) => `("${it.name}", ${hsLit(it.type)})`).join(', ')}]`
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// The op-driven test-mode line, shown only when the SDK has an entity op.
|
|
46
|
-
const testModeExample = primaryOp
|
|
47
|
-
? ` ent <- Sdk.${eFn} sdk VNoval
|
|
48
|
-
arg <- ${testArgExpr}
|
|
49
|
-
ctrl <- emptyMap
|
|
50
|
-
-- Entity ops return the bare record and raise on error.
|
|
51
|
-
${eFn} <- Sdk.e${primaryOp.charAt(0).toUpperCase() + primaryOp.slice(1)} ent arg ctrl
|
|
52
|
-
print ${eFn}`
|
|
53
|
-
: ` args <- jo [("path", VStr "/api/resource"), ("method", VStr "GET")]
|
|
54
|
-
result <- F.direct sdk args
|
|
55
|
-
print result`
|
|
56
|
-
|
|
57
|
-
const apikeyEnvLine = isAuthActive(model)
|
|
58
|
-
? `\n${envName(model)}_APIKEY=<your-key>`
|
|
59
|
-
: ''
|
|
60
|
-
|
|
61
|
-
Content(`### Make a direct HTTP request
|
|
62
|
-
|
|
63
|
-
For endpoints not covered by entity accessors, use \`direct\` — it never
|
|
64
|
-
raises and returns a result \`Value\` you branch on via its \`ok\` field:
|
|
65
|
-
|
|
66
|
-
\`\`\`haskell
|
|
67
|
-
import qualified SdkClient as Sdk
|
|
68
|
-
import qualified SdkFeatures as F
|
|
69
|
-
import VoxgigStruct (Value (..))
|
|
70
|
-
import SdkHelpers (jo, getp)
|
|
71
|
-
|
|
72
|
-
main :: IO ()
|
|
73
|
-
main = do
|
|
74
|
-
sdk <- Sdk.newSdk0
|
|
75
|
-
params <- jo [("id", VStr "example")]
|
|
76
|
-
args <- jo [("path", VStr "/api/resource/{id}"), ("method", VStr "GET"), ("params", params)]
|
|
77
|
-
result <- F.direct sdk args
|
|
78
|
-
ok <- getp result "ok"
|
|
79
|
-
case ok of
|
|
80
|
-
VBool True -> do
|
|
81
|
-
status <- getp result "status" -- e.g. VNum 200
|
|
82
|
-
body <- getp result "data" -- the response body
|
|
83
|
-
print (status, body)
|
|
84
|
-
_ -> do
|
|
85
|
-
-- A non-2xx response carries status + data (the error body); a
|
|
86
|
-
-- transport-level failure carries err instead.
|
|
87
|
-
status <- getp result "status"
|
|
88
|
-
err <- getp result "err"
|
|
89
|
-
print (status, err)
|
|
90
|
-
\`\`\`
|
|
91
|
-
|
|
92
|
-
### Prepare a request without sending it
|
|
93
|
-
|
|
94
|
-
\`\`\`haskell
|
|
95
|
-
import qualified SdkClient as Sdk
|
|
96
|
-
import qualified SdkFeatures as F
|
|
97
|
-
import VoxgigStruct (Value (..))
|
|
98
|
-
import SdkHelpers (jo, getp)
|
|
99
|
-
|
|
100
|
-
main :: IO ()
|
|
101
|
-
main = do
|
|
102
|
-
sdk <- Sdk.newSdk0
|
|
103
|
-
params <- jo [("id", VStr "example")]
|
|
104
|
-
args <- jo [("path", VStr "/api/resource/{id}"), ("method", VStr "DELETE"), ("params", params)]
|
|
105
|
-
-- prepare returns the fetch definition and raises on error.
|
|
106
|
-
fetchdef <- F.prepare sdk args
|
|
107
|
-
url <- getp fetchdef "url"
|
|
108
|
-
method <- getp fetchdef "method"
|
|
109
|
-
print (url, method)
|
|
110
|
-
\`\`\`
|
|
111
|
-
|
|
112
|
-
### Use test mode
|
|
113
|
-
|
|
114
|
-
Create a mock client for unit testing — no server required:
|
|
115
|
-
|
|
116
|
-
\`\`\`haskell
|
|
117
|
-
import qualified SdkClient as Sdk
|
|
118
|
-
import qualified SdkFeatures as F
|
|
119
|
-
import VoxgigStruct (Value (..), emptyMap)
|
|
120
|
-
import SdkHelpers (jo)
|
|
121
|
-
|
|
122
|
-
main :: IO ()
|
|
123
|
-
main = do
|
|
124
|
-
sdk <- Sdk.testSdk0
|
|
125
|
-
${testModeExample}
|
|
126
|
-
\`\`\`
|
|
127
|
-
|
|
128
|
-
### Use a custom fetch function
|
|
129
|
-
|
|
130
|
-
Replace the HTTP transport with your own \`VFunc\` under \`system.fetch\`:
|
|
131
|
-
|
|
132
|
-
\`\`\`haskell
|
|
133
|
-
import qualified SdkClient as Sdk
|
|
134
|
-
import VoxgigStruct (Value (..))
|
|
135
|
-
import SdkHelpers (jo, jsonThunk)
|
|
136
|
-
|
|
137
|
-
customClient :: IO Sdk.Client
|
|
138
|
-
customClient = do
|
|
139
|
-
let mockFetch = VFunc (\\_ _ _ _ -> do
|
|
140
|
-
body <- jo [("id", VStr "mock01")]
|
|
141
|
-
jo [("status", VNum 200), ("statusText", VStr "OK"), ("json", jsonThunk body)])
|
|
142
|
-
sys <- jo [("fetch", mockFetch)]
|
|
143
|
-
opts <- jo [("base", VStr "http://localhost:8080"), ("system", sys)]
|
|
144
|
-
Sdk.newSdk opts
|
|
145
|
-
\`\`\`
|
|
146
|
-
|
|
147
|
-
### Run live tests
|
|
148
|
-
|
|
149
|
-
Create a \`.env.local\` file at the project root:
|
|
150
|
-
|
|
151
|
-
\`\`\`
|
|
152
|
-
${envName(model)}_TEST_LIVE=TRUE${apikeyEnvLine}
|
|
153
|
-
\`\`\`
|
|
154
|
-
|
|
155
|
-
Then run the suite (stock GHC, no third-party dependencies):
|
|
156
|
-
|
|
157
|
-
\`\`\`bash
|
|
158
|
-
cd ${target.name} && make test
|
|
159
|
-
\`\`\`
|
|
160
|
-
|
|
161
|
-
`)
|
|
162
|
-
|
|
163
|
-
})
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
export {
|
|
167
|
-
ReadmeHowto
|
|
168
|
-
}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import { cmp, Content, installCommand, isPublished, repoInfo } from '@voxgig/sdkgen'
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const ReadmeInstall = cmp(function ReadmeInstall(props: any) {
|
|
6
|
-
const { target, ctx$ } = props
|
|
7
|
-
const { model } = ctx$
|
|
8
|
-
|
|
9
|
-
if (isPublished(model, target.name)) {
|
|
10
|
-
Content(`\`\`\`bash
|
|
11
|
-
${installCommand(model, target.name)}
|
|
12
|
-
\`\`\`
|
|
13
|
-
|
|
14
|
-
Or build from a source checkout with the bundled Makefile (stock GHC, no
|
|
15
|
-
third-party dependencies — only the GHC boot libraries):
|
|
16
|
-
|
|
17
|
-
\`\`\`bash
|
|
18
|
-
cd ${target.name} && make test
|
|
19
|
-
\`\`\`
|
|
20
|
-
|
|
21
|
-
`)
|
|
22
|
-
return
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// Publish pending: not yet on Hackage. Build from the git release tag or
|
|
26
|
-
// from a local source checkout. The runtime is dependency-free, so no cabal
|
|
27
|
-
// solve is needed — the Makefile drives stock GHC directly.
|
|
28
|
-
const { releasesUrl } = repoInfo(model)
|
|
29
|
-
Content(`This package is not yet published to Hackage. Install it from the GitHub
|
|
30
|
-
release tag (\`${target.name}/vX.Y.Z\`, see [Releases](${releasesUrl})) or
|
|
31
|
-
from a source checkout. The runtime has no third-party dependencies (only the
|
|
32
|
-
GHC boot libraries: \`base\`, \`containers\`, \`array\`, \`time\`), so the
|
|
33
|
-
bundled Makefile drives stock GHC with no cabal solve:
|
|
34
|
-
|
|
35
|
-
\`\`\`bash
|
|
36
|
-
cd ${target.name} && make test
|
|
37
|
-
\`\`\`
|
|
38
|
-
|
|
39
|
-
A \`.cabal\` file is also generated for use with \`cabal\`/\`stack\`:
|
|
40
|
-
|
|
41
|
-
\`\`\`bash
|
|
42
|
-
cd ${target.name} && cabal build
|
|
43
|
-
\`\`\`
|
|
44
|
-
|
|
45
|
-
`)
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
export {
|
|
50
|
-
ReadmeInstall
|
|
51
|
-
}
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import { cmp, Content } from '@voxgig/sdkgen'
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
KIT,
|
|
6
|
-
getModelPath,
|
|
7
|
-
nom,
|
|
8
|
-
} from '@voxgig/apidef'
|
|
9
|
-
|
|
10
|
-
import { hsVarName } from './utility_haskell'
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const ReadmeIntro = cmp(function ReadmeIntro(props: any) {
|
|
14
|
-
const { target, ctx$: { model } } = props
|
|
15
|
-
const info = (model.main && model.main.kit && model.main.kit.info) || {}
|
|
16
|
-
const tagline = info.tagline || ''
|
|
17
|
-
|
|
18
|
-
Content(`# ${model.Name} ${target.title} SDK
|
|
19
|
-
|
|
20
|
-
${tagline}
|
|
21
|
-
|
|
22
|
-
The ${target.title} SDK for the ${model.Name} API — an entity-oriented client following idiomatic Haskell conventions (pure functions, explicit \`IO\`, and the dependency-free vendored \`Value\` struct model).
|
|
23
|
-
|
|
24
|
-
`)
|
|
25
|
-
|
|
26
|
-
// Emphasise the entity-oriented design: the SDK surfaces the API as
|
|
27
|
-
// capitalised, semantic Entities with a small, uniform verb set rather
|
|
28
|
-
// than raw URL paths and query strings. The example entity accessor is
|
|
29
|
-
// derived from the model, never hardcoded.
|
|
30
|
-
const entity = getModelPath(model, `main.${KIT}.entity`)
|
|
31
|
-
const exampleEntity = Object.values(entity || {})
|
|
32
|
-
.find((e: any) => e.active !== false) as any
|
|
33
|
-
const example = exampleEntity
|
|
34
|
-
? `for example \`${hsVarName(exampleEntity.name)} sdk VNoval\` — each`
|
|
35
|
-
: 'each'
|
|
36
|
-
|
|
37
|
-
// Model-driven op list — only the operations the active entities actually
|
|
38
|
-
// expose (a read-only entity has just list+load); never claim
|
|
39
|
-
// create/update/remove exist when no entity has them.
|
|
40
|
-
const CANON_OPS = ['list', 'load', 'create', 'update', 'remove']
|
|
41
|
-
const opSet = new Set<string>()
|
|
42
|
-
Object.values(entity || {}).forEach((e: any) => {
|
|
43
|
-
if (!e || e.active === false) return
|
|
44
|
-
Object.keys(e.op || {}).forEach((o: string) => {
|
|
45
|
-
if (e.op[o] && e.op[o].active !== false) opSet.add(o)
|
|
46
|
-
})
|
|
47
|
-
})
|
|
48
|
-
const opNames = CANON_OPS.filter((o) => opSet.has(o))
|
|
49
|
-
.concat([...opSet].filter((o) => !CANON_OPS.includes(o)))
|
|
50
|
-
const opList = (opNames.length ? opNames : ['list', 'load'])
|
|
51
|
-
.map((o) => '`e' + o.charAt(0).toUpperCase() + o.slice(1) + '`').join(', ')
|
|
52
|
-
|
|
53
|
-
Content(`The SDK exposes the API as capitalised, semantic **Entities** — ${example}
|
|
54
|
-
carrying a small, uniform set of operations (${opList}) instead of raw URL
|
|
55
|
-
paths and query strings. You work with named resources and verbs, which
|
|
56
|
-
keeps the cognitive load low.
|
|
57
|
-
|
|
58
|
-
> Other languages, the CLI, and MCP server live alongside this one — see
|
|
59
|
-
> the [top-level README](../README.md).
|
|
60
|
-
|
|
61
|
-
`)
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
export {
|
|
66
|
-
ReadmeIntro
|
|
67
|
-
}
|
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import { cmp, each, Content, isAuthActive } from '@voxgig/sdkgen'
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
KIT,
|
|
6
|
-
getModelPath,
|
|
7
|
-
} from '@voxgig/apidef'
|
|
8
|
-
|
|
9
|
-
import { hsVarName } from './utility_haskell'
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const ReadmeModel = cmp(function ReadmeModel(props: any) {
|
|
13
|
-
const { target, ctx$: { model } } = props
|
|
14
|
-
|
|
15
|
-
const entity = getModelPath(model, `main.${KIT}.entity`)
|
|
16
|
-
const entityList = each(entity).filter((e: any) => e.active !== false)
|
|
17
|
-
|
|
18
|
-
// Model-driven op rows for the shared entity record interface: emit a row
|
|
19
|
-
// only for operations at least one active entity actually exposes.
|
|
20
|
-
const opUnion = new Set<string>()
|
|
21
|
-
entityList.forEach((e: any) => Object.keys(e.op || {})
|
|
22
|
-
.forEach((o: string) => { if (e.op[o] && e.op[o].active !== false) opUnion.add(o) }))
|
|
23
|
-
const opRowDefs: Record<string, string> = {
|
|
24
|
-
load: '| `eLoad` | `Value -> Value -> IO Entity` | Load a single entity by match criteria. Resolves to the entity. Raises on error. |',
|
|
25
|
-
list: '| `eList` | `Value -> Value -> IO [Entity]` | List entities matching the criteria. Resolves to one entity per record. Raises on error. |',
|
|
26
|
-
create: '| `eCreate` | `Value -> Value -> IO Entity` | Create a new entity. Resolves to the entity. Raises on error. |',
|
|
27
|
-
update: '| `eUpdate` | `Value -> Value -> IO Entity` | Update an existing entity. Resolves to the entity. Raises on error. |',
|
|
28
|
-
remove: '| `eRemove` | `Value -> Value -> IO Entity` | Remove an entity. Resolves to the entity, marked deleted. Raises on error. |',
|
|
29
|
-
}
|
|
30
|
-
const opRows = ['load', 'list', 'create', 'update', 'remove']
|
|
31
|
-
.filter((o) => opUnion.has(o)).map((o) => opRowDefs[o]).join('\n')
|
|
32
|
-
|
|
33
|
-
const apikeyOptionRow = isAuthActive(model)
|
|
34
|
-
? '| `apikey` | `String` | API key for authentication. |\n'
|
|
35
|
-
: ''
|
|
36
|
-
|
|
37
|
-
Content(`### Client constructors
|
|
38
|
-
|
|
39
|
-
\`\`\`haskell
|
|
40
|
-
import qualified SdkClient as Sdk
|
|
41
|
-
import VoxgigStruct (Value (..))
|
|
42
|
-
import SdkHelpers (jo)
|
|
43
|
-
|
|
44
|
-
makeClient :: IO Sdk.Client
|
|
45
|
-
makeClient = do
|
|
46
|
-
opts <- jo [("base", VStr "https://api.example.com")]
|
|
47
|
-
Sdk.newSdk opts
|
|
48
|
-
\`\`\`
|
|
49
|
-
|
|
50
|
-
\`newSdk :: Value -> IO Client\` constructs a client from an options map;
|
|
51
|
-
\`newSdk0 :: IO Client\` is the no-argument convenience form.
|
|
52
|
-
|
|
53
|
-
| Option (map key) | Type | Description |
|
|
54
|
-
| --- | --- | --- |
|
|
55
|
-
${apikeyOptionRow}| \`base\` | \`String\` | Base URL of the API server. |
|
|
56
|
-
| \`prefix\` | \`String\` | URL path prefix prepended to all requests. |
|
|
57
|
-
| \`suffix\` | \`String\` | URL path suffix appended to all requests. |
|
|
58
|
-
| \`headers\` | \`Value\` | Custom headers for all requests. |
|
|
59
|
-
| \`feature\` | \`Value\` | Feature activation flags. |
|
|
60
|
-
| \`system\` | \`Value\` | System overrides (e.g. custom \`fetch\` function). |
|
|
61
|
-
|
|
62
|
-
### Test client
|
|
63
|
-
|
|
64
|
-
\`\`\`haskell
|
|
65
|
-
client <- Sdk.testSdk testopts sdkopts
|
|
66
|
-
\`\`\`
|
|
67
|
-
|
|
68
|
-
\`testSdk :: Value -> Value -> IO Client\` constructs a test-mode client with
|
|
69
|
-
mock transport (\`testSdk0 :: IO Client\` for the no-argument form). Pass
|
|
70
|
-
\`VNoval\` for defaults.
|
|
71
|
-
|
|
72
|
-
### Client functions
|
|
73
|
-
|
|
74
|
-
| Function | Signature | Description |
|
|
75
|
-
| --- | --- | --- |
|
|
76
|
-
| \`newSdk\` | \`Value -> IO Client\` | Construct a live client from options. |
|
|
77
|
-
| \`newSdk0\` | \`IO Client\` | Construct a live client with defaults. |
|
|
78
|
-
| \`testSdk\` | \`Value -> Value -> IO Client\` | Construct a test-mode client. |
|
|
79
|
-
| \`prepare\` | \`Client -> Value -> IO Value\` | Build an HTTP request definition without sending. Raises on error. |
|
|
80
|
-
| \`direct\` | \`Client -> Value -> IO Value\` | Build and send an HTTP request. Returns a result \`Value\` (branch on \`ok\`). |
|
|
81
|
-
`)
|
|
82
|
-
|
|
83
|
-
each(entityList, (ent: any) => {
|
|
84
|
-
const eFn = hsVarName(ent.name)
|
|
85
|
-
const article = /^[aeiou]/i.test(ent.Name) ? 'an' : 'a'
|
|
86
|
-
Content(`| \`${eFn}\` | \`Client -> Value -> IO Entity\` | Create ${article} ${ent.Name} entity instance. |
|
|
87
|
-
`)
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
Content(`
|
|
91
|
-
### Entity interface
|
|
92
|
-
|
|
93
|
-
All entities share the same record interface (fields of the \`Entity\` type).
|
|
94
|
-
|
|
95
|
-
| Field | Signature | Description |
|
|
96
|
-
| --- | --- | --- |
|
|
97
|
-
${opRows}
|
|
98
|
-
| \`eDataGet\` | \`IO Value\` | Get entity data. |
|
|
99
|
-
| \`eDataSet\` | \`Value -> IO ()\` | Set entity data. |
|
|
100
|
-
| \`eStream\` | \`String -> Value -> Value -> IO [Value]\` | Run an op as a lazy stream of items. |
|
|
101
|
-
| \`eMake\` | \`IO Entity\` | Create a new instance with the same options. |
|
|
102
|
-
| \`eName\` | \`String\` | The entity name. |
|
|
103
|
-
|
|
104
|
-
### Result shape
|
|
105
|
-
|
|
106
|
-
Entity operations resolve to the ENTITY, not the raw record \u2014 \`eList\` to
|
|
107
|
-
one entity per record \u2014 and raise on error. The record is reached through
|
|
108
|
-
\`eDataGet\`, which returns the entity's data container. \`eRemove\` resolves to
|
|
109
|
-
the entity marked deleted (\`eDeleted\`); it keeps the data it held. Wrap calls
|
|
110
|
-
in \`Control.Exception.try\` to handle failures.
|
|
111
|
-
|
|
112
|
-
The \`direct\` escape hatch never raises — it returns a result \`Value\`
|
|
113
|
-
you branch on via its \`ok\` field (read with \`getp result "ok"\`):
|
|
114
|
-
|
|
115
|
-
| Key | Type | Description |
|
|
116
|
-
| --- | --- | --- |
|
|
117
|
-
| \`ok\` | \`Bool\` | \`True\` if the HTTP status is 2xx. |
|
|
118
|
-
| \`status\` | \`Int\` | HTTP status code. |
|
|
119
|
-
| \`headers\` | \`Value\` | Response headers. |
|
|
120
|
-
| \`data\` | \`Value\` | Parsed JSON response body. |
|
|
121
|
-
|
|
122
|
-
On error, \`ok\` is \`False\` and \`err\` carries the error value.
|
|
123
|
-
|
|
124
|
-
`)
|
|
125
|
-
|
|
126
|
-
// Entities summary
|
|
127
|
-
Content(`### Entities
|
|
128
|
-
|
|
129
|
-
`)
|
|
130
|
-
each(entityList, (ent: any) => {
|
|
131
|
-
const fields = ent.fields || []
|
|
132
|
-
const opnames = Object.keys(ent.op || {})
|
|
133
|
-
const ops = ent.op || {}
|
|
134
|
-
const points = each(ops).map((op: any) =>
|
|
135
|
-
op.points ? each(op.points) : []
|
|
136
|
-
).flat()
|
|
137
|
-
const path = points.length > 0 ? (points[0] as any).orig || '' : ''
|
|
138
|
-
|
|
139
|
-
Content(`#### ${ent.Name}
|
|
140
|
-
|
|
141
|
-
| Field | Description |
|
|
142
|
-
| --- | --- |
|
|
143
|
-
`)
|
|
144
|
-
each(fields, (field: any) => {
|
|
145
|
-
Content(`| \`${field.name}\` | ${field.short || ''} |
|
|
146
|
-
`)
|
|
147
|
-
})
|
|
148
|
-
|
|
149
|
-
Content(`
|
|
150
|
-
Operations: ${opnames.map((n: string) => n.charAt(0).toUpperCase() + n.slice(1)).join(', ')}.
|
|
151
|
-
|
|
152
|
-
API path: \`${path}\`
|
|
153
|
-
|
|
154
|
-
`)
|
|
155
|
-
})
|
|
156
|
-
|
|
157
|
-
})
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
export {
|
|
161
|
-
ReadmeModel
|
|
162
|
-
}
|