@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,358 @@
|
|
|
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(array $reqmatch, ?array $ctrl = null): array',
|
|
13
|
+
returns: 'array [$result, $err]',
|
|
14
|
+
desc: 'Load a single entity matching the given criteria.',
|
|
15
|
+
},
|
|
16
|
+
list: {
|
|
17
|
+
sig: 'list(array $reqmatch, ?array $ctrl = null): array',
|
|
18
|
+
returns: 'array [$result, $err]',
|
|
19
|
+
desc: 'List entities matching the given criteria. Returns an array.',
|
|
20
|
+
},
|
|
21
|
+
create: {
|
|
22
|
+
sig: 'create(array $reqdata, ?array $ctrl = null): array',
|
|
23
|
+
returns: 'array [$result, $err]',
|
|
24
|
+
desc: 'Create a new entity with the given data.',
|
|
25
|
+
},
|
|
26
|
+
update: {
|
|
27
|
+
sig: 'update(array $reqdata, ?array $ctrl = null): array',
|
|
28
|
+
returns: 'array [$result, $err]',
|
|
29
|
+
desc: 'Update an existing entity. The data must include the entity `id`.',
|
|
30
|
+
},
|
|
31
|
+
remove: {
|
|
32
|
+
sig: 'remove(array $reqmatch, ?array $ctrl = null): array',
|
|
33
|
+
returns: 'array [$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(`\`\`\`php
|
|
63
|
+
require_once __DIR__ . '/${model.name}_sdk.php';
|
|
64
|
+
|
|
65
|
+
$client = new ${model.const.Name}SDK($options);
|
|
66
|
+
\`\`\`
|
|
67
|
+
|
|
68
|
+
Create a new SDK client instance.
|
|
69
|
+
|
|
70
|
+
**Parameters:**
|
|
71
|
+
|
|
72
|
+
| Name | Type | Description |
|
|
73
|
+
| --- | --- | --- |
|
|
74
|
+
| \`$options\` | \`array\` | 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"]\` | \`array\` | Custom headers for all requests. |
|
|
80
|
+
| \`$options["feature"]\` | \`array\` | Feature configuration. |
|
|
81
|
+
| \`$options["system"]\` | \`array\` | 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 = null, $sdkopts = null)\`
|
|
92
|
+
|
|
93
|
+
Create a test client with mock features active. Both arguments may be \`null\`.
|
|
94
|
+
|
|
95
|
+
\`\`\`php
|
|
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 = null)\`
|
|
111
|
+
|
|
112
|
+
Create a new \`${ent.Name}Entity\` instance. Pass \`null\` for no initial data.
|
|
113
|
+
|
|
114
|
+
`)
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
Content(`#### \`optionsMap(): array\`
|
|
119
|
+
|
|
120
|
+
Return a deep copy of the current SDK options.
|
|
121
|
+
|
|
122
|
+
#### \`getUtility(): ProjectNameUtility\`
|
|
123
|
+
|
|
124
|
+
Return a copy of the SDK utility object.
|
|
125
|
+
|
|
126
|
+
#### \`direct(array $fetchargs = []): array\`
|
|
127
|
+
|
|
128
|
+
Make a direct HTTP request to any API endpoint. Returns \`[$result, $err]\`.
|
|
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"]\` | \`array\` | Path parameter values for \`{param}\` substitution. |
|
|
137
|
+
| \`$fetchargs["query"]\` | \`array\` | Query string parameters. |
|
|
138
|
+
| \`$fetchargs["headers"]\` | \`array\` | Request headers (merged with defaults). |
|
|
139
|
+
| \`$fetchargs["body"]\` | \`mixed\` | Request body (arrays are JSON-serialized). |
|
|
140
|
+
| \`$fetchargs["ctrl"]\` | \`array\` | Control options. |
|
|
141
|
+
|
|
142
|
+
**Returns:** \`array [$result, $err]\`
|
|
143
|
+
|
|
144
|
+
#### \`prepare(array $fetchargs = []): array\`
|
|
145
|
+
|
|
146
|
+
Prepare a fetch definition without sending the request. Returns \`[$fetchdef, $err]\`.
|
|
147
|
+
|
|
148
|
+
`)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
// Entity reference sections
|
|
152
|
+
publishedEntities.map((ent: any) => {
|
|
153
|
+
const opnames = Object.keys(ent.op || {})
|
|
154
|
+
const fields = ent.fields || []
|
|
155
|
+
|
|
156
|
+
Content(`
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## ${ent.Name}Entity
|
|
160
|
+
|
|
161
|
+
`)
|
|
162
|
+
|
|
163
|
+
if (ent.short) {
|
|
164
|
+
Content(`${ent.short}
|
|
165
|
+
|
|
166
|
+
`)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
Content(`\`\`\`php
|
|
170
|
+
$${ent.name} = $client->${ent.Name}();
|
|
171
|
+
\`\`\`
|
|
172
|
+
|
|
173
|
+
`)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
// Field schema
|
|
177
|
+
if (fields.length > 0) {
|
|
178
|
+
Content(`### Fields
|
|
179
|
+
|
|
180
|
+
| Field | Type | Required | Description |
|
|
181
|
+
| --- | --- | --- | --- |
|
|
182
|
+
`)
|
|
183
|
+
each(fields, (field: any) => {
|
|
184
|
+
const req = field.req ? 'Yes' : 'No'
|
|
185
|
+
const desc = field.short || ''
|
|
186
|
+
Content(`| \`${field.name}\` | \`${field.type || 'any'}\` | ${req} | ${desc} |
|
|
187
|
+
`)
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
Content(`
|
|
191
|
+
`)
|
|
192
|
+
|
|
193
|
+
// Field operations breakdown
|
|
194
|
+
const hasFieldOps = fields.some((f: any) => f.op && Object.keys(f.op).length > 0)
|
|
195
|
+
if (hasFieldOps) {
|
|
196
|
+
Content(`### Field Usage by Operation
|
|
197
|
+
|
|
198
|
+
| Field | load | list | create | update | remove |
|
|
199
|
+
| --- | --- | --- | --- | --- | --- |
|
|
200
|
+
`)
|
|
201
|
+
each(fields, (field: any) => {
|
|
202
|
+
const fops = field.op || {}
|
|
203
|
+
const cols = ['load', 'list', 'create', 'update', 'remove'].map((op: string) => {
|
|
204
|
+
if (!opnames.includes(op)) return '-'
|
|
205
|
+
const fop = fops[op]
|
|
206
|
+
if (null == fop) return '-'
|
|
207
|
+
if (fop.active === false) return '-'
|
|
208
|
+
return 'Yes'
|
|
209
|
+
})
|
|
210
|
+
Content(`| \`${field.name}\` | ${cols.join(' | ')} |
|
|
211
|
+
`)
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
Content(`
|
|
215
|
+
`)
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
// Operation details
|
|
221
|
+
if (opnames.length > 0) {
|
|
222
|
+
Content(`### Operations
|
|
223
|
+
|
|
224
|
+
`)
|
|
225
|
+
|
|
226
|
+
opnames.map((opname: string) => {
|
|
227
|
+
const info = OP_SIGNATURES[opname]
|
|
228
|
+
if (!info) return
|
|
229
|
+
|
|
230
|
+
Content(`#### \`${info.sig}\`
|
|
231
|
+
|
|
232
|
+
${info.desc}
|
|
233
|
+
|
|
234
|
+
`)
|
|
235
|
+
|
|
236
|
+
// Show example
|
|
237
|
+
if ('load' === opname || 'remove' === opname) {
|
|
238
|
+
Content(`\`\`\`php
|
|
239
|
+
[$result, $err] = $client->${ent.Name}()->${opname}(["id" => "${ent.name}_id"]);
|
|
240
|
+
\`\`\`
|
|
241
|
+
|
|
242
|
+
`)
|
|
243
|
+
}
|
|
244
|
+
else if ('list' === opname) {
|
|
245
|
+
Content(`\`\`\`php
|
|
246
|
+
[$results, $err] = $client->${ent.Name}()->list([]);
|
|
247
|
+
\`\`\`
|
|
248
|
+
|
|
249
|
+
`)
|
|
250
|
+
}
|
|
251
|
+
else if ('create' === opname) {
|
|
252
|
+
Content(`\`\`\`php
|
|
253
|
+
[$result, $err] = $client->${ent.Name}()->create([
|
|
254
|
+
`)
|
|
255
|
+
each(fields, (field: any) => {
|
|
256
|
+
if ('id' !== field.name && field.req) {
|
|
257
|
+
Content(` "${field.name}" => /* ${field.type || 'value'} */,
|
|
258
|
+
`)
|
|
259
|
+
}
|
|
260
|
+
})
|
|
261
|
+
Content(`]);
|
|
262
|
+
\`\`\`
|
|
263
|
+
|
|
264
|
+
`)
|
|
265
|
+
}
|
|
266
|
+
else if ('update' === opname) {
|
|
267
|
+
Content(`\`\`\`php
|
|
268
|
+
[$result, $err] = $client->${ent.Name}()->update([
|
|
269
|
+
"id" => "${ent.name}_id",
|
|
270
|
+
// Fields to update
|
|
271
|
+
]);
|
|
272
|
+
\`\`\`
|
|
273
|
+
|
|
274
|
+
`)
|
|
275
|
+
}
|
|
276
|
+
})
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
// Common methods
|
|
281
|
+
Content(`### Common Methods
|
|
282
|
+
|
|
283
|
+
#### \`dataGet(): array\`
|
|
284
|
+
|
|
285
|
+
Get the entity data. Returns a copy of the current data.
|
|
286
|
+
|
|
287
|
+
#### \`dataSet($data): void\`
|
|
288
|
+
|
|
289
|
+
Set the entity data.
|
|
290
|
+
|
|
291
|
+
#### \`matchGet(): array\`
|
|
292
|
+
|
|
293
|
+
Get the entity match criteria.
|
|
294
|
+
|
|
295
|
+
#### \`matchSet($match): void\`
|
|
296
|
+
|
|
297
|
+
Set the entity match criteria.
|
|
298
|
+
|
|
299
|
+
#### \`make(): ${ent.Name}Entity\`
|
|
300
|
+
|
|
301
|
+
Create a new \`${ent.Name}Entity\` instance with the same client and
|
|
302
|
+
options.
|
|
303
|
+
|
|
304
|
+
#### \`getName(): string\`
|
|
305
|
+
|
|
306
|
+
Return the entity name.
|
|
307
|
+
|
|
308
|
+
`)
|
|
309
|
+
})
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
// Features section
|
|
313
|
+
const activeFeatures = each(feature).filter((f: any) => f.active)
|
|
314
|
+
if (activeFeatures.length > 0) {
|
|
315
|
+
Content(`
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
## Features
|
|
319
|
+
|
|
320
|
+
| Feature | Version | Description |
|
|
321
|
+
| --- | --- | --- |
|
|
322
|
+
`)
|
|
323
|
+
|
|
324
|
+
activeFeatures.map((f: any) => {
|
|
325
|
+
Content(`| \`${f.name}\` | ${f.version || '0.0.1'} | ${f.title || ''} |
|
|
326
|
+
`)
|
|
327
|
+
})
|
|
328
|
+
|
|
329
|
+
Content(`
|
|
330
|
+
|
|
331
|
+
Features are activated via the \`feature\` option:
|
|
332
|
+
|
|
333
|
+
`)
|
|
334
|
+
|
|
335
|
+
Content(`\`\`\`php
|
|
336
|
+
$client = new ${model.const.Name}SDK([
|
|
337
|
+
"feature" => [
|
|
338
|
+
`)
|
|
339
|
+
activeFeatures.map((f: any) => {
|
|
340
|
+
Content(` "${f.name}" => ["active" => true],
|
|
341
|
+
`)
|
|
342
|
+
})
|
|
343
|
+
Content(` ],
|
|
344
|
+
]);
|
|
345
|
+
\`\`\`
|
|
346
|
+
|
|
347
|
+
`)
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
})
|
|
351
|
+
})
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
export {
|
|
357
|
+
ReadmeRef
|
|
358
|
+
}
|
|
@@ -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,13 +15,15 @@ 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" => getenv("${model.NAME}_APIKEY"),\n`
|
|
20
|
+
: ''
|
|
21
|
+
|
|
18
22
|
Content(`\`\`\`php
|
|
19
23
|
<?php
|
|
20
24
|
require_once '${model.const.Name.toLowerCase()}_sdk.php';
|
|
21
25
|
|
|
22
|
-
$client = new ${model.const.Name}SDK([
|
|
23
|
-
"apikey" => getenv("${model.NAME}_APIKEY"),
|
|
24
|
-
]);
|
|
26
|
+
$client = new ${model.const.Name}SDK([${apikeyArg}]);
|
|
25
27
|
|
|
26
28
|
`)
|
|
27
29
|
|
|
@@ -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 + 'DirectTest.' + target.ext }, () => {
|
|
83
131
|
|
|
@@ -96,13 +144,34 @@ class ${entity.Name}DirectTest extends TestCase
|
|
|
96
144
|
`)
|
|
97
145
|
|
|
98
146
|
if (hasList && listPoint) {
|
|
147
|
+
const listLiveIdKeys: string[] = listParams.map((lp: any) => {
|
|
148
|
+
return lp.name === 'id'
|
|
149
|
+
? entity.name + '01'
|
|
150
|
+
: lp.name.replace(/_id$/, '') + '01'
|
|
151
|
+
})
|
|
152
|
+
const listSkipBlock = listLiveIdKeys.length > 0
|
|
153
|
+
? ` if ($setup["live"]) {
|
|
154
|
+
foreach ([${listLiveIdKeys.map(k => `"${k}"`).join(', ')}] as $_liveKey) {
|
|
155
|
+
if (!isset($setup["idmap"][$_liveKey]) || $setup["idmap"][$_liveKey] === null) {
|
|
156
|
+
$this->markTestSkipped("live test needs $_liveKey via *_ENTID env var (synthetic IDs only)");
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
`
|
|
162
|
+
: ''
|
|
99
163
|
Content(` public function test_direct_list_${entity.name}(): void
|
|
100
164
|
{
|
|
101
165
|
$setup = ${entity.name}_direct_setup([
|
|
102
166
|
["id" => "direct01"],
|
|
103
167
|
["id" => "direct02"],
|
|
104
168
|
]);
|
|
105
|
-
$
|
|
169
|
+
[$_shouldSkip, $_reason] = Runner::is_control_skipped("direct", "direct-list-${entity.name}", $setup["live"] ? "live" : "unit");
|
|
170
|
+
if ($_shouldSkip) {
|
|
171
|
+
$this->markTestSkipped($_reason ?? "skipped via sdk-test-control.json");
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
${listSkipBlock} $client = $setup["client"];
|
|
106
175
|
|
|
107
176
|
`)
|
|
108
177
|
|
|
@@ -137,11 +206,27 @@ class ${entity.Name}DirectTest extends TestCase
|
|
|
137
206
|
`)
|
|
138
207
|
}
|
|
139
208
|
|
|
140
|
-
Content(`
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
209
|
+
Content(` if ($setup["live"]) {
|
|
210
|
+
// Live mode is lenient: synthetic IDs frequently 4xx and the
|
|
211
|
+
// list-response shape varies wildly across public APIs. Skip
|
|
212
|
+
// rather than fail when the call doesn't return a usable list.
|
|
213
|
+
if ($err !== null) {
|
|
214
|
+
$this->markTestSkipped("list call failed (likely synthetic IDs against live API): " . (string)$err);
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
if (empty($result["ok"])) {
|
|
218
|
+
$this->markTestSkipped("list call not ok (likely synthetic IDs against live API)");
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
$status = Helpers::to_int($result["status"]);
|
|
222
|
+
if ($status < 200 || $status >= 300) {
|
|
223
|
+
$this->markTestSkipped("expected 2xx status, got " . $status);
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
} else {
|
|
227
|
+
$this->assertNull($err);
|
|
228
|
+
$this->assertTrue($result["ok"]);
|
|
229
|
+
$this->assertEquals(200, Helpers::to_int($result["status"]));
|
|
145
230
|
$this->assertIsArray($result["data"]);
|
|
146
231
|
$this->assertCount(2, $result["data"]);
|
|
147
232
|
$this->assertCount(1, $setup["calls"]);
|
|
@@ -152,23 +237,66 @@ class ${entity.Name}DirectTest extends TestCase
|
|
|
152
237
|
}
|
|
153
238
|
|
|
154
239
|
if (hasLoad && loadPoint) {
|
|
240
|
+
// Skip live direct-load only when there's no way to fill path params:
|
|
241
|
+
// no spec examples and no list-bootstrap. Spec examples win first.
|
|
242
|
+
const loadSkipBlock = (loadParams.length > 0 && !loadAllHaveExamples)
|
|
243
|
+
? ` if ($setup["live"]) {
|
|
244
|
+
$this->markTestSkipped("live direct-load needs real ID — set *_ENTID env var with real IDs to run");
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
`
|
|
248
|
+
: ''
|
|
155
249
|
Content(` public function test_direct_load_${entity.name}(): void
|
|
156
250
|
{
|
|
157
251
|
$setup = ${entity.name}_direct_setup(["id" => "direct01"]);
|
|
158
|
-
$
|
|
252
|
+
[$_shouldSkip, $_reason] = Runner::is_control_skipped("direct", "direct-load-${entity.name}", $setup["live"] ? "live" : "unit");
|
|
253
|
+
if ($_shouldSkip) {
|
|
254
|
+
$this->markTestSkipped($_reason ?? "skipped via sdk-test-control.json");
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
${loadSkipBlock} $client = $setup["client"];
|
|
159
258
|
|
|
160
259
|
`)
|
|
161
260
|
|
|
162
|
-
|
|
261
|
+
const needsQuery = loadParams.length > 0 || loadLiveQueryLines !== ''
|
|
262
|
+
if (needsQuery) {
|
|
163
263
|
Content(` $params = [];
|
|
164
|
-
|
|
264
|
+
$query = [];
|
|
265
|
+
`)
|
|
266
|
+
if (loadAllHaveExamples) {
|
|
267
|
+
Content(` if ($setup["live"]) {
|
|
268
|
+
`)
|
|
269
|
+
if (loadLiveQueryLines) Content(loadLiveQueryLines + '\n')
|
|
270
|
+
Content(loadExampleLines + '\n')
|
|
271
|
+
Content(` } else {
|
|
272
|
+
`)
|
|
273
|
+
for (let i = 0; i < loadParams.length; i++) {
|
|
274
|
+
Content(` $params["${loadParams[i].name}"] = "direct0${i + 1}";
|
|
275
|
+
`)
|
|
276
|
+
}
|
|
277
|
+
Content(` }
|
|
278
|
+
`)
|
|
279
|
+
} else if (loadParams.length > 0) {
|
|
280
|
+
if (loadLiveQueryLines) {
|
|
281
|
+
Content(` if ($setup["live"]) {
|
|
282
|
+
${loadLiveQueryLines}
|
|
283
|
+
}
|
|
284
|
+
`)
|
|
285
|
+
}
|
|
286
|
+
Content(` if (!$setup["live"]) {
|
|
165
287
|
`)
|
|
166
|
-
|
|
167
|
-
|
|
288
|
+
for (let i = 0; i < loadParams.length; i++) {
|
|
289
|
+
Content(` $params["${loadParams[i].name}"] = "direct0${i + 1}";
|
|
168
290
|
`)
|
|
291
|
+
}
|
|
292
|
+
Content(` }
|
|
293
|
+
`)
|
|
294
|
+
} else if (loadLiveQueryLines) {
|
|
295
|
+
Content(` if ($setup["live"]) {
|
|
296
|
+
${loadLiveQueryLines}
|
|
169
297
|
}
|
|
170
|
-
Content(` }
|
|
171
298
|
`)
|
|
299
|
+
}
|
|
172
300
|
}
|
|
173
301
|
|
|
174
302
|
Content(`
|
|
@@ -176,20 +304,37 @@ class ${entity.Name}DirectTest extends TestCase
|
|
|
176
304
|
"path" => "${loadPath}",
|
|
177
305
|
"method" => "GET",
|
|
178
306
|
`)
|
|
179
|
-
if (
|
|
307
|
+
if (needsQuery) {
|
|
180
308
|
Content(` "params" => $params,
|
|
309
|
+
"query" => $query,
|
|
181
310
|
`)
|
|
182
311
|
} else {
|
|
183
312
|
Content(` "params" => [],
|
|
184
313
|
`)
|
|
185
314
|
}
|
|
186
315
|
Content(` ]);
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
316
|
+
if ($setup["live"]) {
|
|
317
|
+
// Live mode is lenient: synthetic IDs frequently 4xx. Skip
|
|
318
|
+
// rather than fail when the load endpoint isn't reachable
|
|
319
|
+
// with the IDs we can construct from setup.idmap.
|
|
320
|
+
if ($err !== null) {
|
|
321
|
+
$this->markTestSkipped("load call failed (likely synthetic IDs against live API): " . (string)$err);
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
if (empty($result["ok"])) {
|
|
325
|
+
$this->markTestSkipped("load call not ok (likely synthetic IDs against live API)");
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
$status = Helpers::to_int($result["status"]);
|
|
329
|
+
if ($status < 200 || $status >= 300) {
|
|
330
|
+
$this->markTestSkipped("expected 2xx status, got " . $status);
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
} else {
|
|
334
|
+
$this->assertNull($err);
|
|
335
|
+
$this->assertTrue($result["ok"]);
|
|
336
|
+
$this->assertEquals(200, Helpers::to_int($result["status"]));
|
|
337
|
+
$this->assertNotNull($result["data"]);
|
|
193
338
|
if (is_array($result["data"]) && isset($result["data"]["id"])) {
|
|
194
339
|
$this->assertEquals("direct01", $result["data"]["id"]);
|
|
195
340
|
}
|
|
@@ -211,15 +356,13 @@ function ${entity.name}_direct_setup($mockres)
|
|
|
211
356
|
|
|
212
357
|
$env = Runner::env_override([
|
|
213
358
|
"${entidEnvVar}" => [],
|
|
214
|
-
"${PROJECTNAME}_TEST_LIVE" => "FALSE"
|
|
215
|
-
"${PROJECTNAME}_APIKEY" => "NONE",
|
|
359
|
+
"${PROJECTNAME}_TEST_LIVE" => "FALSE",${apikeyEnvEntry}
|
|
216
360
|
]);
|
|
217
361
|
|
|
218
362
|
$live = $env["${PROJECTNAME}_TEST_LIVE"] === "TRUE";
|
|
219
363
|
|
|
220
364
|
if ($live) {
|
|
221
|
-
$merged_opts = [
|
|
222
|
-
"apikey" => $env["${PROJECTNAME}_APIKEY"],
|
|
365
|
+
$merged_opts = [${apikeyLiveField}
|
|
223
366
|
];
|
|
224
367
|
$client = new ${model.const.Name}SDK($merged_opts);
|
|
225
368
|
return [
|