@voxgig/sdkgen 0.44.0 → 1.0.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 +1 -1
- package/dist/cmp/ReadmeEntity.js +9 -153
- package/dist/cmp/ReadmeEntity.js.map +1 -1
- package/dist/cmp/ReadmeIntro.js +9 -14
- package/dist/cmp/ReadmeIntro.js.map +1 -1
- package/dist/cmp/ReadmeModel.js +6 -4
- package/dist/cmp/ReadmeModel.js.map +1 -1
- package/dist/cmp/ReadmeOptions.js +9 -61
- package/dist/cmp/ReadmeOptions.js.map +1 -1
- package/dist/cmp/ReadmeRef.js +10 -1328
- package/dist/cmp/ReadmeRef.js.map +1 -1
- package/dist/sdkgen.d.ts +2 -2
- package/dist/sdkgen.js +2 -1
- package/dist/sdkgen.js.map +1 -1
- package/dist/utility.d.ts +2 -1
- package/dist/utility.js +9 -0
- package/dist/utility.js.map +1 -1
- package/package.json +3 -3
- package/project/.sdk/src/cmp/go/Config_go.ts +9 -4
- package/project/.sdk/src/cmp/go/Entity_go.ts +2 -2
- package/project/.sdk/src/cmp/go/Main_go.ts +8 -4
- package/project/.sdk/src/cmp/go/Package_go.ts +2 -2
- package/project/.sdk/src/cmp/go/ReadmeEntity_go.ts +138 -0
- package/project/.sdk/src/cmp/go/ReadmeExplanation_go.ts +2 -2
- package/project/.sdk/src/cmp/go/ReadmeHowto_go.ts +8 -5
- package/project/.sdk/src/cmp/go/ReadmeInstall_go.ts +2 -2
- package/project/.sdk/src/cmp/go/ReadmeIntro_go.ts +18 -0
- package/project/.sdk/src/cmp/go/ReadmeModel_go.ts +8 -5
- package/project/.sdk/src/cmp/go/ReadmeOptions_go.ts +58 -0
- package/project/.sdk/src/cmp/go/ReadmeQuick_go.ts +13 -9
- package/project/.sdk/src/cmp/go/ReadmeRef_go.ts +354 -0
- package/project/.sdk/src/cmp/go/ReadmeTopQuick_go.ts +8 -6
- package/project/.sdk/src/cmp/go/ReadmeTopTest_go.ts +2 -2
- package/project/.sdk/src/cmp/go/TestDirect_go.ts +222 -41
- package/project/.sdk/src/cmp/go/TestEntity_go.ts +142 -60
- package/project/.sdk/src/cmp/go/Test_go.ts +2 -2
- package/project/.sdk/src/cmp/go/fragment/Main.fragment.go +21 -4
- package/project/.sdk/src/cmp/js/Config_js.ts +18 -0
- package/project/.sdk/src/cmp/js/ReadmeEntity_js.ts +138 -0
- package/project/.sdk/src/cmp/js/ReadmeHowto_js.ts +11 -6
- package/project/.sdk/src/cmp/js/ReadmeIntro_js.ts +18 -0
- package/project/.sdk/src/cmp/js/ReadmeModel_js.ts +6 -3
- package/project/.sdk/src/cmp/js/ReadmeOptions_js.ts +58 -0
- package/project/.sdk/src/cmp/js/ReadmeQuick_js.ts +6 -4
- package/project/.sdk/src/cmp/js/ReadmeRef_js.ts +384 -0
- package/project/.sdk/src/cmp/js/ReadmeTopQuick_js.ts +6 -4
- package/project/.sdk/src/cmp/js/TestDirect_js.ts +23 -12
- package/project/.sdk/src/cmp/js/TestEntity_js.ts +107 -74
- package/project/.sdk/src/cmp/js/fragment/Config.fragment.js +1 -5
- package/project/.sdk/src/cmp/lua/Config_lua.ts +9 -4
- package/project/.sdk/src/cmp/lua/Package_lua.ts +9 -2
- package/project/.sdk/src/cmp/lua/ReadmeEntity_lua.ts +138 -0
- package/project/.sdk/src/cmp/lua/ReadmeHowto_lua.ts +6 -3
- package/project/.sdk/src/cmp/lua/ReadmeIntro_lua.ts +18 -0
- package/project/.sdk/src/cmp/lua/ReadmeModel_lua.ts +6 -3
- package/project/.sdk/src/cmp/lua/ReadmeOptions_lua.ts +58 -0
- package/project/.sdk/src/cmp/lua/ReadmeQuick_lua.ts +6 -4
- package/project/.sdk/src/cmp/lua/ReadmeRef_lua.ts +360 -0
- package/project/.sdk/src/cmp/lua/ReadmeTopQuick_lua.ts +6 -4
- package/project/.sdk/src/cmp/lua/TestDirect_lua.ts +172 -29
- package/project/.sdk/src/cmp/lua/TestEntity_lua.ts +120 -52
- package/project/.sdk/src/cmp/lua/fragment/Main.fragment.lua +20 -4
- package/project/.sdk/src/cmp/php/Config_php.ts +10 -8
- package/project/.sdk/src/cmp/php/Package_php.ts +7 -1
- package/project/.sdk/src/cmp/php/ReadmeEntity_php.ts +138 -0
- package/project/.sdk/src/cmp/php/ReadmeHowto_php.ts +6 -3
- package/project/.sdk/src/cmp/php/ReadmeIntro_php.ts +18 -0
- package/project/.sdk/src/cmp/php/ReadmeModel_php.ts +6 -3
- package/project/.sdk/src/cmp/php/ReadmeOptions_php.ts +58 -0
- package/project/.sdk/src/cmp/php/ReadmeQuick_php.ts +6 -4
- package/project/.sdk/src/cmp/php/ReadmeRef_php.ts +358 -0
- package/project/.sdk/src/cmp/php/ReadmeTopQuick_php.ts +6 -4
- package/project/.sdk/src/cmp/php/TestDirect_php.ts +171 -28
- package/project/.sdk/src/cmp/php/TestEntity_php.ts +126 -55
- package/project/.sdk/src/cmp/php/fragment/Main.fragment.php +17 -3
- package/project/.sdk/src/cmp/py/Config_py.ts +9 -4
- package/project/.sdk/src/cmp/py/Package_py.ts +8 -1
- package/project/.sdk/src/cmp/py/ReadmeEntity_py.ts +138 -0
- package/project/.sdk/src/cmp/py/ReadmeHowto_py.ts +6 -3
- package/project/.sdk/src/cmp/py/ReadmeIntro_py.ts +18 -0
- package/project/.sdk/src/cmp/py/ReadmeModel_py.ts +6 -3
- package/project/.sdk/src/cmp/py/ReadmeOptions_py.ts +58 -0
- package/project/.sdk/src/cmp/py/ReadmeQuick_py.ts +9 -6
- package/project/.sdk/src/cmp/py/ReadmeRef_py.ts +356 -0
- package/project/.sdk/src/cmp/py/ReadmeTopQuick_py.ts +9 -6
- package/project/.sdk/src/cmp/py/TestDirect_py.ts +164 -27
- package/project/.sdk/src/cmp/py/TestEntity_py.ts +125 -51
- package/project/.sdk/src/cmp/py/fragment/Main.fragment.py +19 -4
- package/project/.sdk/src/cmp/rb/Config_rb.ts +9 -4
- package/project/.sdk/src/cmp/rb/Package_rb.ts +9 -2
- package/project/.sdk/src/cmp/rb/ReadmeEntity_rb.ts +138 -0
- package/project/.sdk/src/cmp/rb/ReadmeHowto_rb.ts +6 -3
- package/project/.sdk/src/cmp/rb/ReadmeIntro_rb.ts +18 -0
- package/project/.sdk/src/cmp/rb/ReadmeModel_rb.ts +6 -3
- package/project/.sdk/src/cmp/rb/ReadmeOptions_rb.ts +58 -0
- package/project/.sdk/src/cmp/rb/ReadmeQuick_rb.ts +6 -4
- package/project/.sdk/src/cmp/rb/ReadmeRef_rb.ts +361 -0
- package/project/.sdk/src/cmp/rb/ReadmeTopQuick_rb.ts +6 -4
- package/project/.sdk/src/cmp/rb/TestDirect_rb.ts +172 -29
- package/project/.sdk/src/cmp/rb/TestEntity_rb.ts +120 -52
- package/project/.sdk/src/cmp/rb/fragment/Main.fragment.rb +19 -3
- package/project/.sdk/src/cmp/ts/Config_ts.ts +18 -0
- package/project/.sdk/src/cmp/ts/Package_ts.ts +1 -1
- package/project/.sdk/src/cmp/ts/ReadmeEntity_ts.ts +138 -0
- package/project/.sdk/src/cmp/ts/ReadmeHowto_ts.ts +11 -6
- package/project/.sdk/src/cmp/ts/ReadmeIntro_ts.ts +18 -0
- package/project/.sdk/src/cmp/ts/ReadmeModel_ts.ts +9 -5
- package/project/.sdk/src/cmp/ts/ReadmeOptions_ts.ts +58 -0
- package/project/.sdk/src/cmp/ts/ReadmeQuick_ts.ts +6 -4
- package/project/.sdk/src/cmp/ts/ReadmeRef_ts.ts +384 -0
- package/project/.sdk/src/cmp/ts/ReadmeTopQuick_ts.ts +6 -4
- package/project/.sdk/src/cmp/ts/TestDirect_ts.ts +213 -42
- package/project/.sdk/src/cmp/ts/TestEntity_ts.ts +168 -75
- package/project/.sdk/src/cmp/ts/fragment/Config.fragment.ts +1 -5
- package/project/.sdk/src/cmp/ts/fragment/Direct.test.fragment.ts +8 -1
- package/project/.sdk/src/cmp/ts/fragment/Entity.test.fragment.ts +8 -2
- package/project/.sdk/src/cmp/ts/fragment/Main.fragment.ts +21 -1
- package/project/.sdk/tm/go/feature/test_feature.go +51 -3
- package/project/.sdk/tm/go/test/runner_test.go +106 -6
- package/project/.sdk/tm/go/test/sdk-test-control.json +19 -0
- package/project/.sdk/tm/go/utility/fetcher.go +10 -0
- package/project/.sdk/tm/go/utility/make_url.go +12 -0
- package/project/.sdk/tm/go/utility/prepare_auth.go +15 -1
- package/project/.sdk/tm/js/src/utility/PrepareAuthUtility.js +7 -1
- package/project/.sdk/tm/lua/feature/test_feature.lua +41 -3
- package/project/.sdk/tm/lua/test/runner.lua +74 -0
- package/project/.sdk/tm/lua/test/sdk-test-control.json +19 -0
- package/project/.sdk/tm/lua/utility/fetcher.lua +13 -0
- package/project/.sdk/tm/lua/utility/make_url.lua +16 -0
- package/project/.sdk/tm/lua/utility/prepare_auth.lua +9 -1
- package/project/.sdk/tm/php/feature/TestFeature.php +185 -43
- package/project/.sdk/tm/php/test/Runner.php +62 -0
- package/project/.sdk/tm/php/test/sdk-test-control.json +19 -0
- package/project/.sdk/tm/php/utility/Fetcher.php +132 -9
- package/project/.sdk/tm/php/utility/MakeUrl.php +16 -0
- package/project/.sdk/tm/php/utility/PrepareAuth.php +11 -1
- package/project/.sdk/tm/py/feature/test_feature.py +35 -3
- package/project/.sdk/tm/py/test/runner.py +60 -0
- package/project/.sdk/tm/py/test/sdk-test-control.json +19 -0
- package/project/.sdk/tm/py/utility/fetcher.py +13 -0
- package/project/.sdk/tm/py/utility/make_url.py +13 -0
- package/project/.sdk/tm/py/utility/prepare_auth.py +10 -1
- package/project/.sdk/tm/rb/feature/test_feature.rb +36 -3
- package/project/.sdk/tm/rb/test/runner.rb +46 -0
- package/project/.sdk/tm/rb/test/sdk-test-control.json +19 -0
- package/project/.sdk/tm/rb/utility/fetcher.rb +49 -28
- package/project/.sdk/tm/rb/utility/make_url.rb +16 -0
- package/project/.sdk/tm/rb/utility/prepare_auth.rb +8 -1
- package/project/.sdk/tm/ts/src/utility/MakeUrlUtility.ts +7 -8
- package/project/.sdk/tm/ts/src/utility/PrepareAuthUtility.ts +7 -1
- package/project/.sdk/tm/ts/test/sdk-test-control.json +19 -0
- package/project/.sdk/tm/ts/test/utility.ts +120 -2
- package/src/cmp/ReadmeEntity.ts +11 -178
- package/src/cmp/ReadmeIntro.ts +11 -25
- package/src/cmp/ReadmeModel.ts +7 -5
- package/src/cmp/ReadmeOptions.ts +12 -74
- package/src/cmp/ReadmeRef.ts +11 -1372
- package/src/sdkgen.ts +2 -1
- package/src/utility.ts +12 -0
- /package/project/.sdk/tm/go/utility/{make_target.go → make_point.go} +0 -0
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
|
|
2
|
+
import { cmp, each, Content, File, isAuthActive } from '@voxgig/sdkgen'
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
KIT,
|
|
6
|
+
getModelPath,
|
|
7
|
+
} from '@voxgig/apidef'
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
const OP_SIGNATURES: Record<string, { sig: string, returns: string, desc: string }> = {
|
|
11
|
+
load: {
|
|
12
|
+
sig: 'load(reqmatch, ctrl = nil) -> result, err',
|
|
13
|
+
returns: 'result, err',
|
|
14
|
+
desc: 'Load a single entity matching the given criteria.',
|
|
15
|
+
},
|
|
16
|
+
list: {
|
|
17
|
+
sig: 'list(reqmatch, ctrl = nil) -> result, err',
|
|
18
|
+
returns: 'result, err',
|
|
19
|
+
desc: 'List entities matching the given criteria. Returns an array.',
|
|
20
|
+
},
|
|
21
|
+
create: {
|
|
22
|
+
sig: 'create(reqdata, ctrl = nil) -> result, err',
|
|
23
|
+
returns: 'result, err',
|
|
24
|
+
desc: 'Create a new entity with the given data.',
|
|
25
|
+
},
|
|
26
|
+
update: {
|
|
27
|
+
sig: 'update(reqdata, ctrl = nil) -> result, err',
|
|
28
|
+
returns: 'result, err',
|
|
29
|
+
desc: 'Update an existing entity. The data must include the entity `id`.',
|
|
30
|
+
},
|
|
31
|
+
remove: {
|
|
32
|
+
sig: 'remove(reqmatch, ctrl = nil) -> result, err',
|
|
33
|
+
returns: 'result, err',
|
|
34
|
+
desc: 'Remove the entity matching the given criteria.',
|
|
35
|
+
},
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
const ReadmeRef = cmp(function ReadmeRef(props: any) {
|
|
40
|
+
const { target } = props
|
|
41
|
+
const { model } = props.ctx$
|
|
42
|
+
|
|
43
|
+
const entity = getModelPath(model, `main.${KIT}.entity`)
|
|
44
|
+
const feature = getModelPath(model, `main.${KIT}.feature`)
|
|
45
|
+
|
|
46
|
+
const publishedEntities = each(entity).filter((e: any) => e.active !== false)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
File({ name: 'REFERENCE.md' }, () => {
|
|
50
|
+
|
|
51
|
+
Content(`# ${model.Name} ${target.title} SDK Reference
|
|
52
|
+
|
|
53
|
+
Complete API reference for the ${model.Name} ${target.title} SDK.
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
## ${model.Name}SDK
|
|
57
|
+
|
|
58
|
+
### Constructor
|
|
59
|
+
|
|
60
|
+
`)
|
|
61
|
+
|
|
62
|
+
Content(`\`\`\`ruby
|
|
63
|
+
require_relative '${model.name}_sdk'
|
|
64
|
+
|
|
65
|
+
client = ${model.const.Name}SDK.new(options)
|
|
66
|
+
\`\`\`
|
|
67
|
+
|
|
68
|
+
Create a new SDK client instance.
|
|
69
|
+
|
|
70
|
+
**Parameters:**
|
|
71
|
+
|
|
72
|
+
| Name | Type | Description |
|
|
73
|
+
| --- | --- | --- |
|
|
74
|
+
| \`options\` | \`Hash\` | SDK configuration options. |
|
|
75
|
+
| \`options["apikey"]\` | \`String\` | API key for authentication. |
|
|
76
|
+
| \`options["base"]\` | \`String\` | Base URL for API requests. |
|
|
77
|
+
| \`options["prefix"]\` | \`String\` | URL prefix appended after base. |
|
|
78
|
+
| \`options["suffix"]\` | \`String\` | URL suffix appended after path. |
|
|
79
|
+
| \`options["headers"]\` | \`Hash\` | Custom headers for all requests. |
|
|
80
|
+
| \`options["feature"]\` | \`Hash\` | Feature configuration. |
|
|
81
|
+
| \`options["system"]\` | \`Hash\` | System overrides (e.g. custom fetch). |
|
|
82
|
+
|
|
83
|
+
`)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
Content(`
|
|
87
|
+
### Static Methods
|
|
88
|
+
|
|
89
|
+
`)
|
|
90
|
+
|
|
91
|
+
Content(`#### \`${model.const.Name}SDK.test(testopts = nil, sdkopts = nil)\`
|
|
92
|
+
|
|
93
|
+
Create a test client with mock features active. Both arguments may be \`nil\`.
|
|
94
|
+
|
|
95
|
+
\`\`\`ruby
|
|
96
|
+
client = ${model.const.Name}SDK.test
|
|
97
|
+
\`\`\`
|
|
98
|
+
|
|
99
|
+
`)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
Content(`
|
|
103
|
+
### Instance Methods
|
|
104
|
+
|
|
105
|
+
`)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
// Entity factory methods
|
|
109
|
+
publishedEntities.map((ent: any) => {
|
|
110
|
+
Content(`#### \`${ent.Name}(data = nil)\`
|
|
111
|
+
|
|
112
|
+
Create a new \`${ent.Name}\` entity instance. Pass \`nil\` for no initial data.
|
|
113
|
+
|
|
114
|
+
`)
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
Content(`#### \`options_map -> Hash\`
|
|
119
|
+
|
|
120
|
+
Return a deep copy of the current SDK options.
|
|
121
|
+
|
|
122
|
+
#### \`get_utility -> Utility\`
|
|
123
|
+
|
|
124
|
+
Return a copy of the SDK utility object.
|
|
125
|
+
|
|
126
|
+
#### \`direct(fetchargs = {}) -> Hash, err\`
|
|
127
|
+
|
|
128
|
+
Make a direct HTTP request to any API endpoint.
|
|
129
|
+
|
|
130
|
+
**Parameters:**
|
|
131
|
+
|
|
132
|
+
| Name | Type | Description |
|
|
133
|
+
| --- | --- | --- |
|
|
134
|
+
| \`fetchargs["path"]\` | \`String\` | URL path with optional \`{param}\` placeholders. |
|
|
135
|
+
| \`fetchargs["method"]\` | \`String\` | HTTP method (default: \`"GET"\`). |
|
|
136
|
+
| \`fetchargs["params"]\` | \`Hash\` | Path parameter values for \`{param}\` substitution. |
|
|
137
|
+
| \`fetchargs["query"]\` | \`Hash\` | Query string parameters. |
|
|
138
|
+
| \`fetchargs["headers"]\` | \`Hash\` | Request headers (merged with defaults). |
|
|
139
|
+
| \`fetchargs["body"]\` | \`any\` | Request body (hashes are JSON-serialized). |
|
|
140
|
+
| \`fetchargs["ctrl"]\` | \`Hash\` | Control options (e.g. \`{ "explain" => true }\`). |
|
|
141
|
+
|
|
142
|
+
**Returns:** \`Hash, err\`
|
|
143
|
+
|
|
144
|
+
#### \`prepare(fetchargs = {}) -> Hash, err\`
|
|
145
|
+
|
|
146
|
+
Prepare a fetch definition without sending the request. Accepts the
|
|
147
|
+
same parameters as \`direct()\`.
|
|
148
|
+
|
|
149
|
+
**Returns:** \`Hash, err\`
|
|
150
|
+
|
|
151
|
+
`)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
// Entity reference sections
|
|
155
|
+
publishedEntities.map((ent: any) => {
|
|
156
|
+
const opnames = Object.keys(ent.op || {})
|
|
157
|
+
const fields = ent.fields || []
|
|
158
|
+
|
|
159
|
+
Content(`
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## ${ent.Name}Entity
|
|
163
|
+
|
|
164
|
+
`)
|
|
165
|
+
|
|
166
|
+
if (ent.short) {
|
|
167
|
+
Content(`${ent.short}
|
|
168
|
+
|
|
169
|
+
`)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
Content(`\`\`\`ruby
|
|
173
|
+
${ent.name} = client.${ent.Name}
|
|
174
|
+
\`\`\`
|
|
175
|
+
|
|
176
|
+
`)
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
// Field schema
|
|
180
|
+
if (fields.length > 0) {
|
|
181
|
+
Content(`### Fields
|
|
182
|
+
|
|
183
|
+
| Field | Type | Required | Description |
|
|
184
|
+
| --- | --- | --- | --- |
|
|
185
|
+
`)
|
|
186
|
+
each(fields, (field: any) => {
|
|
187
|
+
const req = field.req ? 'Yes' : 'No'
|
|
188
|
+
const desc = field.short || ''
|
|
189
|
+
Content(`| \`${field.name}\` | \`${field.type || 'any'}\` | ${req} | ${desc} |
|
|
190
|
+
`)
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
Content(`
|
|
194
|
+
`)
|
|
195
|
+
|
|
196
|
+
// Field operations breakdown
|
|
197
|
+
const hasFieldOps = fields.some((f: any) => f.op && Object.keys(f.op).length > 0)
|
|
198
|
+
if (hasFieldOps) {
|
|
199
|
+
Content(`### Field Usage by Operation
|
|
200
|
+
|
|
201
|
+
| Field | load | list | create | update | remove |
|
|
202
|
+
| --- | --- | --- | --- | --- | --- |
|
|
203
|
+
`)
|
|
204
|
+
each(fields, (field: any) => {
|
|
205
|
+
const fops = field.op || {}
|
|
206
|
+
const cols = ['load', 'list', 'create', 'update', 'remove'].map((op: string) => {
|
|
207
|
+
if (!opnames.includes(op)) return '-'
|
|
208
|
+
const fop = fops[op]
|
|
209
|
+
if (null == fop) return '-'
|
|
210
|
+
if (fop.active === false) return '-'
|
|
211
|
+
return 'Yes'
|
|
212
|
+
})
|
|
213
|
+
Content(`| \`${field.name}\` | ${cols.join(' | ')} |
|
|
214
|
+
`)
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
Content(`
|
|
218
|
+
`)
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
// Operation details
|
|
224
|
+
if (opnames.length > 0) {
|
|
225
|
+
Content(`### Operations
|
|
226
|
+
|
|
227
|
+
`)
|
|
228
|
+
|
|
229
|
+
opnames.map((opname: string) => {
|
|
230
|
+
const info = OP_SIGNATURES[opname]
|
|
231
|
+
if (!info) return
|
|
232
|
+
|
|
233
|
+
Content(`#### \`${info.sig}\`
|
|
234
|
+
|
|
235
|
+
${info.desc}
|
|
236
|
+
|
|
237
|
+
`)
|
|
238
|
+
|
|
239
|
+
// Show example
|
|
240
|
+
if ('load' === opname || 'remove' === opname) {
|
|
241
|
+
Content(`\`\`\`ruby
|
|
242
|
+
result, err = client.${ent.Name}.${opname}({ "id" => "${ent.name}_id" })
|
|
243
|
+
\`\`\`
|
|
244
|
+
|
|
245
|
+
`)
|
|
246
|
+
}
|
|
247
|
+
else if ('list' === opname) {
|
|
248
|
+
Content(`\`\`\`ruby
|
|
249
|
+
results, err = client.${ent.Name}.list(nil)
|
|
250
|
+
\`\`\`
|
|
251
|
+
|
|
252
|
+
`)
|
|
253
|
+
}
|
|
254
|
+
else if ('create' === opname) {
|
|
255
|
+
Content(`\`\`\`ruby
|
|
256
|
+
result, err = client.${ent.Name}.create({
|
|
257
|
+
`)
|
|
258
|
+
each(fields, (field: any) => {
|
|
259
|
+
if ('id' !== field.name && field.req) {
|
|
260
|
+
Content(` "${field.name}" => # ${field.type || 'value'},
|
|
261
|
+
`)
|
|
262
|
+
}
|
|
263
|
+
})
|
|
264
|
+
Content(`})
|
|
265
|
+
\`\`\`
|
|
266
|
+
|
|
267
|
+
`)
|
|
268
|
+
}
|
|
269
|
+
else if ('update' === opname) {
|
|
270
|
+
Content(`\`\`\`ruby
|
|
271
|
+
result, err = client.${ent.Name}.update({
|
|
272
|
+
"id" => "${ent.name}_id",
|
|
273
|
+
# Fields to update
|
|
274
|
+
})
|
|
275
|
+
\`\`\`
|
|
276
|
+
|
|
277
|
+
`)
|
|
278
|
+
}
|
|
279
|
+
})
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
// Common methods
|
|
284
|
+
Content(`### Common Methods
|
|
285
|
+
|
|
286
|
+
#### \`data_get -> Hash\`
|
|
287
|
+
|
|
288
|
+
Get the entity data. Returns a copy of the current data.
|
|
289
|
+
|
|
290
|
+
#### \`data_set(data)\`
|
|
291
|
+
|
|
292
|
+
Set the entity data.
|
|
293
|
+
|
|
294
|
+
#### \`match_get -> Hash\`
|
|
295
|
+
|
|
296
|
+
Get the entity match criteria.
|
|
297
|
+
|
|
298
|
+
#### \`match_set(match)\`
|
|
299
|
+
|
|
300
|
+
Set the entity match criteria.
|
|
301
|
+
|
|
302
|
+
#### \`make -> Entity\`
|
|
303
|
+
|
|
304
|
+
Create a new \`${ent.Name}Entity\` instance with the same client and
|
|
305
|
+
options.
|
|
306
|
+
|
|
307
|
+
#### \`get_name -> String\`
|
|
308
|
+
|
|
309
|
+
Return the entity name.
|
|
310
|
+
|
|
311
|
+
`)
|
|
312
|
+
})
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
// Features section
|
|
316
|
+
const activeFeatures = each(feature).filter((f: any) => f.active)
|
|
317
|
+
if (activeFeatures.length > 0) {
|
|
318
|
+
Content(`
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
## Features
|
|
322
|
+
|
|
323
|
+
| Feature | Version | Description |
|
|
324
|
+
| --- | --- | --- |
|
|
325
|
+
`)
|
|
326
|
+
|
|
327
|
+
activeFeatures.map((f: any) => {
|
|
328
|
+
Content(`| \`${f.name}\` | ${f.version || '0.0.1'} | ${f.title || ''} |
|
|
329
|
+
`)
|
|
330
|
+
})
|
|
331
|
+
|
|
332
|
+
Content(`
|
|
333
|
+
|
|
334
|
+
Features are activated via the \`feature\` option:
|
|
335
|
+
|
|
336
|
+
`)
|
|
337
|
+
|
|
338
|
+
Content(`\`\`\`ruby
|
|
339
|
+
client = ${model.const.Name}SDK.new({
|
|
340
|
+
"feature" => {
|
|
341
|
+
`)
|
|
342
|
+
activeFeatures.map((f: any) => {
|
|
343
|
+
Content(` "${f.name}" => { "active" => true },
|
|
344
|
+
`)
|
|
345
|
+
})
|
|
346
|
+
Content(` },
|
|
347
|
+
})
|
|
348
|
+
\`\`\`
|
|
349
|
+
|
|
350
|
+
`)
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
})
|
|
354
|
+
})
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
export {
|
|
360
|
+
ReadmeRef
|
|
361
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
import { cmp, Content } from '@voxgig/sdkgen'
|
|
2
|
+
import { cmp, Content, isAuthActive } from '@voxgig/sdkgen'
|
|
3
3
|
|
|
4
4
|
import {
|
|
5
5
|
KIT,
|
|
@@ -15,12 +15,14 @@ const ReadmeTopQuick = cmp(function ReadmeTopQuick(props: any) {
|
|
|
15
15
|
|
|
16
16
|
const exampleEntity = Object.values(entity).find((e: any) => e.active !== false) as any
|
|
17
17
|
|
|
18
|
+
const apikeyArg = isAuthActive(model)
|
|
19
|
+
? `\n "apikey" => ENV["${model.NAME}_APIKEY"],\n`
|
|
20
|
+
: ''
|
|
21
|
+
|
|
18
22
|
Content(`\`\`\`ruby
|
|
19
23
|
require_relative "${model.const.Name}_sdk"
|
|
20
24
|
|
|
21
|
-
client = ${model.const.Name}SDK.new({
|
|
22
|
-
"apikey" => ENV["${model.NAME}_APIKEY"],
|
|
23
|
-
})
|
|
25
|
+
client = ${model.const.Name}SDK.new({${apikeyArg}})
|
|
24
26
|
|
|
25
27
|
`)
|
|
26
28
|
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
|
|
2
2
|
import {
|
|
3
|
+
Model,
|
|
4
|
+
ModelEntity,
|
|
5
|
+
nom,
|
|
3
6
|
depluralize,
|
|
4
7
|
} from '@voxgig/apidef'
|
|
5
8
|
|
|
@@ -8,6 +11,7 @@ import {
|
|
|
8
11
|
File,
|
|
9
12
|
cmp,
|
|
10
13
|
snakify,
|
|
14
|
+
isAuthActive,
|
|
11
15
|
} from '@voxgig/sdkgen'
|
|
12
16
|
|
|
13
17
|
|
|
@@ -51,12 +55,20 @@ function normalizePathParams(
|
|
|
51
55
|
|
|
52
56
|
const TestDirect = cmp(function TestDirect(props: any) {
|
|
53
57
|
const ctx$ = props.ctx$
|
|
54
|
-
const model = ctx$.model
|
|
58
|
+
const model: Model = ctx$.model
|
|
55
59
|
|
|
56
60
|
const target = props.target
|
|
57
|
-
const entity = props.entity
|
|
61
|
+
const entity: ModelEntity = props.entity
|
|
58
62
|
|
|
59
|
-
const PROJECTNAME = model
|
|
63
|
+
const PROJECTNAME = nom(model, 'Name').toUpperCase().replace(/[^A-Z_]/g, '_')
|
|
64
|
+
|
|
65
|
+
const authActive = isAuthActive(model)
|
|
66
|
+
const apikeyEnvEntry = authActive
|
|
67
|
+
? `\n "${PROJECTNAME}_APIKEY" => "NONE",`
|
|
68
|
+
: ''
|
|
69
|
+
const apikeyLiveField = authActive
|
|
70
|
+
? `\n "apikey" => env["${PROJECTNAME}_APIKEY"],`
|
|
71
|
+
: ''
|
|
60
72
|
|
|
61
73
|
const opnames = Object.keys(entity.op)
|
|
62
74
|
const hasLoad = opnames.includes('load')
|
|
@@ -71,13 +83,49 @@ const TestDirect = cmp(function TestDirect(props: any) {
|
|
|
71
83
|
|
|
72
84
|
const loadPoint = loadOp?.points?.[0]
|
|
73
85
|
const loadPath = loadPoint ? normalizePathParams(loadPoint.parts || [], loadPoint?.args?.params || [], loadPoint?.rename?.param) : ''
|
|
74
|
-
const
|
|
86
|
+
const allLoadParams = loadPoint?.args?.params || []
|
|
87
|
+
// Some upstream OpenAPI specs declare a parameter as `in: path` even when
|
|
88
|
+
// that path has no `{name}` placeholder for it. Only path params that
|
|
89
|
+
// actually appear in the URL template should drive direct-test path-param
|
|
90
|
+
// setup and URL-substitution asserts; otherwise the SDK silently drops
|
|
91
|
+
// them and the URL-includes assert fails.
|
|
92
|
+
const _pathPlaceholders = new Set<string>()
|
|
93
|
+
for (const part of (loadPoint?.parts || [])) {
|
|
94
|
+
if (typeof part === 'string' && part.startsWith('{') && part.endsWith('}')) {
|
|
95
|
+
_pathPlaceholders.add(part.slice(1, -1))
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const _renameMap = (loadPoint?.rename?.param || {}) as Record<string, string>
|
|
99
|
+
const _renamedPlaceholders = new Set<string>()
|
|
100
|
+
for (const ph of _pathPlaceholders) {
|
|
101
|
+
_renamedPlaceholders.add(ph)
|
|
102
|
+
for (const [orig, renamed] of Object.entries(_renameMap)) {
|
|
103
|
+
if (renamed === ph) _renamedPlaceholders.add(orig)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
const loadParams = allLoadParams.filter((p: any) =>
|
|
107
|
+
_renamedPlaceholders.has(p.name) || _renamedPlaceholders.has(p.orig))
|
|
75
108
|
|
|
76
109
|
const listPoint = listOp?.points?.[0]
|
|
77
110
|
const listPath = listPoint ? normalizePathParams(listPoint.parts || [], listPoint?.args?.params || [], listPoint?.rename?.param) : ''
|
|
78
111
|
const listParams = listPoint?.args?.params || []
|
|
79
112
|
|
|
80
|
-
|
|
113
|
+
// Required query params with spec-provided examples — needed in live mode.
|
|
114
|
+
const loadQuery = loadPoint?.args?.query || []
|
|
115
|
+
const loadLiveQueryEntries = loadQuery
|
|
116
|
+
.filter((q: any) => q.reqd && undefined !== q.example && null !== q.example)
|
|
117
|
+
const loadLiveQueryLines = loadLiveQueryEntries
|
|
118
|
+
.map((q: any) => ` query["${q.name}"] = ${JSON.stringify(q.example)}`)
|
|
119
|
+
.join('\n')
|
|
120
|
+
|
|
121
|
+
const loadAllHaveExamples =
|
|
122
|
+
loadParams.length > 0 &&
|
|
123
|
+
loadParams.every((p: any) => undefined !== p.example && null !== p.example)
|
|
124
|
+
const loadExampleLines = loadAllHaveExamples
|
|
125
|
+
? loadParams.map((p: any) => ` params["${p.name}"] = ${JSON.stringify(p.example)}`).join('\n')
|
|
126
|
+
: ''
|
|
127
|
+
|
|
128
|
+
const entidEnvVar = `${PROJECTNAME}_TEST_${nom(entity, 'NAME').replace(/[^A-Z_]/g, '_')}_ENTID`
|
|
81
129
|
|
|
82
130
|
File({ name: entity.name + '_direct_test.' + target.ext }, () => {
|
|
83
131
|
|
|
@@ -92,12 +140,33 @@ class ${entity.Name}DirectTest < Minitest::Test
|
|
|
92
140
|
`)
|
|
93
141
|
|
|
94
142
|
if (hasList && listPoint) {
|
|
143
|
+
const listLiveIdKeys: string[] = listParams.map((lp: any) => {
|
|
144
|
+
return lp.name === 'id'
|
|
145
|
+
? entity.name + '01'
|
|
146
|
+
: lp.name.replace(/_id$/, '') + '01'
|
|
147
|
+
})
|
|
148
|
+
const listSkipBlock = listLiveIdKeys.length > 0
|
|
149
|
+
? ` if setup[:live]
|
|
150
|
+
[${listLiveIdKeys.map(k => `"${k}"`).join(', ')}].each do |_live_key|
|
|
151
|
+
if setup[:idmap][_live_key].nil?
|
|
152
|
+
skip "live test needs #{_live_key} via *_ENTID env var (synthetic IDs only)"
|
|
153
|
+
return
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
`
|
|
158
|
+
: ''
|
|
95
159
|
Content(` def test_direct_list_${entity.name}
|
|
96
160
|
setup = ${entity.name}_direct_setup([
|
|
97
161
|
{ "id" => "direct01" },
|
|
98
162
|
{ "id" => "direct02" },
|
|
99
163
|
])
|
|
100
|
-
|
|
164
|
+
_should_skip, _reason = Runner.is_control_skipped("direct", "direct-list-${entity.name}", setup[:live] ? "live" : "unit")
|
|
165
|
+
if _should_skip
|
|
166
|
+
skip(_reason || "skipped via sdk-test-control.json")
|
|
167
|
+
return
|
|
168
|
+
end
|
|
169
|
+
${listSkipBlock} client = setup[:client]
|
|
101
170
|
|
|
102
171
|
`)
|
|
103
172
|
|
|
@@ -132,11 +201,27 @@ class ${entity.Name}DirectTest < Minitest::Test
|
|
|
132
201
|
`)
|
|
133
202
|
}
|
|
134
203
|
|
|
135
|
-
Content(`
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
204
|
+
Content(` if setup[:live]
|
|
205
|
+
# Live mode is lenient: synthetic IDs frequently 4xx and the list-
|
|
206
|
+
# response shape varies wildly across public APIs. Skip rather than
|
|
207
|
+
# fail when the call doesn't return a usable list.
|
|
208
|
+
if !err.nil?
|
|
209
|
+
skip("list call failed (likely synthetic IDs against live API): #{err}")
|
|
210
|
+
return
|
|
211
|
+
end
|
|
212
|
+
unless result["ok"]
|
|
213
|
+
skip("list call not ok (likely synthetic IDs against live API)")
|
|
214
|
+
return
|
|
215
|
+
end
|
|
216
|
+
status = Helpers.to_int(result["status"])
|
|
217
|
+
if status < 200 || status >= 300
|
|
218
|
+
skip("expected 2xx status, got #{status}")
|
|
219
|
+
return
|
|
220
|
+
end
|
|
221
|
+
else
|
|
222
|
+
assert_nil err
|
|
223
|
+
assert result["ok"]
|
|
224
|
+
assert_equal 200, Helpers.to_int(result["status"])
|
|
140
225
|
assert result["data"].is_a?(Array)
|
|
141
226
|
assert_equal 2, result["data"].length
|
|
142
227
|
assert_equal 1, setup[:calls].length
|
|
@@ -147,22 +232,65 @@ class ${entity.Name}DirectTest < Minitest::Test
|
|
|
147
232
|
}
|
|
148
233
|
|
|
149
234
|
if (hasLoad && loadPoint) {
|
|
235
|
+
// Skip live direct-load only when we can't fill path params:
|
|
236
|
+
// no spec examples and no list-bootstrap. Spec examples win first.
|
|
237
|
+
const loadSkipBlock = (loadParams.length > 0 && !loadAllHaveExamples)
|
|
238
|
+
? ` if setup[:live]
|
|
239
|
+
skip "live direct-load needs real ID — set *_ENTID env var with real IDs to run"
|
|
240
|
+
return
|
|
241
|
+
end
|
|
242
|
+
`
|
|
243
|
+
: ''
|
|
150
244
|
Content(` def test_direct_load_${entity.name}
|
|
151
245
|
setup = ${entity.name}_direct_setup({ "id" => "direct01" })
|
|
152
|
-
|
|
246
|
+
_should_skip, _reason = Runner.is_control_skipped("direct", "direct-load-${entity.name}", setup[:live] ? "live" : "unit")
|
|
247
|
+
if _should_skip
|
|
248
|
+
skip(_reason || "skipped via sdk-test-control.json")
|
|
249
|
+
return
|
|
250
|
+
end
|
|
251
|
+
${loadSkipBlock} client = setup[:client]
|
|
153
252
|
|
|
154
253
|
`)
|
|
155
254
|
|
|
156
|
-
|
|
255
|
+
const needsQuery = loadParams.length > 0 || loadLiveQueryLines !== ''
|
|
256
|
+
if (needsQuery) {
|
|
157
257
|
Content(` params = {}
|
|
158
|
-
|
|
258
|
+
query = {}
|
|
159
259
|
`)
|
|
160
|
-
|
|
161
|
-
Content(`
|
|
260
|
+
if (loadAllHaveExamples) {
|
|
261
|
+
Content(` if setup[:live]
|
|
162
262
|
`)
|
|
163
|
-
|
|
164
|
-
|
|
263
|
+
if (loadLiveQueryLines) Content(loadLiveQueryLines + '\n')
|
|
264
|
+
Content(loadExampleLines + '\n')
|
|
265
|
+
Content(` else
|
|
165
266
|
`)
|
|
267
|
+
for (let i = 0; i < loadParams.length; i++) {
|
|
268
|
+
Content(` params["${loadParams[i].name}"] = "direct0${i + 1}"
|
|
269
|
+
`)
|
|
270
|
+
}
|
|
271
|
+
Content(` end
|
|
272
|
+
`)
|
|
273
|
+
} else if (loadParams.length > 0) {
|
|
274
|
+
if (loadLiveQueryLines) {
|
|
275
|
+
Content(` if setup[:live]
|
|
276
|
+
${loadLiveQueryLines}
|
|
277
|
+
end
|
|
278
|
+
`)
|
|
279
|
+
}
|
|
280
|
+
Content(` unless setup[:live]
|
|
281
|
+
`)
|
|
282
|
+
for (let i = 0; i < loadParams.length; i++) {
|
|
283
|
+
Content(` params["${loadParams[i].name}"] = "direct0${i + 1}"
|
|
284
|
+
`)
|
|
285
|
+
}
|
|
286
|
+
Content(` end
|
|
287
|
+
`)
|
|
288
|
+
} else if (loadLiveQueryLines) {
|
|
289
|
+
Content(` if setup[:live]
|
|
290
|
+
${loadLiveQueryLines}
|
|
291
|
+
end
|
|
292
|
+
`)
|
|
293
|
+
}
|
|
166
294
|
}
|
|
167
295
|
|
|
168
296
|
Content(`
|
|
@@ -170,20 +298,37 @@ class ${entity.Name}DirectTest < Minitest::Test
|
|
|
170
298
|
"path" => "${loadPath}",
|
|
171
299
|
"method" => "GET",
|
|
172
300
|
`)
|
|
173
|
-
if (
|
|
301
|
+
if (needsQuery) {
|
|
174
302
|
Content(` "params" => params,
|
|
303
|
+
"query" => query,
|
|
175
304
|
`)
|
|
176
305
|
} else {
|
|
177
306
|
Content(` "params" => {},
|
|
178
307
|
`)
|
|
179
308
|
}
|
|
180
309
|
Content(` })
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
310
|
+
if setup[:live]
|
|
311
|
+
# Live mode is lenient: synthetic IDs frequently 4xx. Skip rather
|
|
312
|
+
# than fail when the load endpoint isn't reachable with the IDs
|
|
313
|
+
# we can construct from setup.idmap.
|
|
314
|
+
if !err.nil?
|
|
315
|
+
skip("load call failed (likely synthetic IDs against live API): #{err}")
|
|
316
|
+
return
|
|
317
|
+
end
|
|
318
|
+
unless result["ok"]
|
|
319
|
+
skip("load call not ok (likely synthetic IDs against live API)")
|
|
320
|
+
return
|
|
321
|
+
end
|
|
322
|
+
status = Helpers.to_int(result["status"])
|
|
323
|
+
if status < 200 || status >= 300
|
|
324
|
+
skip("expected 2xx status, got #{status}")
|
|
325
|
+
return
|
|
326
|
+
end
|
|
327
|
+
else
|
|
328
|
+
assert_nil err
|
|
329
|
+
assert result["ok"]
|
|
330
|
+
assert_equal 200, Helpers.to_int(result["status"])
|
|
331
|
+
assert !result["data"].nil?
|
|
187
332
|
if result["data"].is_a?(Hash)
|
|
188
333
|
assert_equal "direct01", result["data"]["id"]
|
|
189
334
|
end
|
|
@@ -204,15 +349,13 @@ def ${entity.name}_direct_setup(mockres)
|
|
|
204
349
|
|
|
205
350
|
env = Runner.env_override({
|
|
206
351
|
"${entidEnvVar}" => {},
|
|
207
|
-
"${PROJECTNAME}_TEST_LIVE" => "FALSE"
|
|
208
|
-
"${PROJECTNAME}_APIKEY" => "NONE",
|
|
352
|
+
"${PROJECTNAME}_TEST_LIVE" => "FALSE",${apikeyEnvEntry}
|
|
209
353
|
})
|
|
210
354
|
|
|
211
355
|
live = env["${PROJECTNAME}_TEST_LIVE"] == "TRUE"
|
|
212
356
|
|
|
213
357
|
if live
|
|
214
|
-
merged_opts = {
|
|
215
|
-
"apikey" => env["${PROJECTNAME}_APIKEY"],
|
|
358
|
+
merged_opts = {${apikeyLiveField}
|
|
216
359
|
}
|
|
217
360
|
client = ${model.const.Name}SDK.new(merged_opts)
|
|
218
361
|
return {
|