@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
|
@@ -7,7 +7,12 @@ import {
|
|
|
7
7
|
|
|
8
8
|
import {
|
|
9
9
|
KIT,
|
|
10
|
+
Model,
|
|
11
|
+
ModelEntity,
|
|
12
|
+
ModelEntityFlow,
|
|
13
|
+
ModelEntityFlowStep,
|
|
10
14
|
getModelPath,
|
|
15
|
+
nom,
|
|
11
16
|
} from '@voxgig/apidef'
|
|
12
17
|
|
|
13
18
|
|
|
@@ -18,34 +23,43 @@ import {
|
|
|
18
23
|
each,
|
|
19
24
|
buildIdNames,
|
|
20
25
|
getMatchEntries,
|
|
26
|
+
isAuthActive,
|
|
21
27
|
} from '@voxgig/sdkgen'
|
|
22
28
|
|
|
23
29
|
|
|
24
|
-
|
|
25
|
-
|
|
30
|
+
// See TestEntity_ts.ts for the GenCtx/OpGen contract.
|
|
26
31
|
type GenCtx = {
|
|
27
|
-
model:
|
|
28
|
-
entity:
|
|
29
|
-
flow:
|
|
32
|
+
model: Model
|
|
33
|
+
entity: ModelEntity
|
|
34
|
+
flow: ModelEntityFlow
|
|
30
35
|
PROJUPPER: string
|
|
31
36
|
}
|
|
32
37
|
|
|
38
|
+
type OpGen = (ctx: GenCtx, step: ModelEntityFlowStep, index: number) => void
|
|
39
|
+
|
|
33
40
|
|
|
34
41
|
const TestEntity = cmp(function TestEntity(props: any) {
|
|
35
42
|
const ctx$ = props.ctx$
|
|
36
|
-
const model = ctx$.model
|
|
43
|
+
const model: Model = ctx$.model
|
|
37
44
|
|
|
38
45
|
const target = props.target
|
|
39
|
-
const entity = props.entity
|
|
46
|
+
const entity: ModelEntity = props.entity
|
|
40
47
|
|
|
41
|
-
const basicflow
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
if (!dobasic) {
|
|
48
|
+
const basicflow: ModelEntityFlow | undefined =
|
|
49
|
+
getModelPath(model, `main.${KIT}.flow.Basic${nom(entity, 'Name')}Flow`)
|
|
50
|
+
if (null == basicflow || true !== basicflow.active) {
|
|
45
51
|
return
|
|
46
52
|
}
|
|
47
53
|
|
|
48
|
-
const PROJUPPER = model.const
|
|
54
|
+
const PROJUPPER = nom(model.const, 'Name').toUpperCase().replace(/[^A-Z_]/g, '_')
|
|
55
|
+
|
|
56
|
+
const authActive = isAuthActive(model)
|
|
57
|
+
const apikeyEnvEntry = authActive
|
|
58
|
+
? `\n "${PROJUPPER}_APIKEY" => "NONE",`
|
|
59
|
+
: ''
|
|
60
|
+
const apikeyLiveField = authActive
|
|
61
|
+
? `\n "apikey" => env["${PROJUPPER}_APIKEY"],`
|
|
62
|
+
: ''
|
|
49
63
|
|
|
50
64
|
const idnames = buildIdNames(entity, basicflow)
|
|
51
65
|
const idnamesStr = idnames.map(n => `"${n}"`).join(', ')
|
|
@@ -77,6 +91,21 @@ class ${entity.Name}EntityTest < Minitest::Test
|
|
|
77
91
|
|
|
78
92
|
def test_basic_flow
|
|
79
93
|
setup = ${entity.name}_basic_setup(nil)
|
|
94
|
+
# Per-op sdk-test-control.json skip.
|
|
95
|
+
_live = setup[:live] || false
|
|
96
|
+
[${(Array.from(new Set((allSteps as any[]).map((s: any) => s.op).filter(Boolean)))).map(o => `"${o}"`).join(', ')}].each do |_op|
|
|
97
|
+
_should_skip, _reason = Runner.is_control_skipped("entityOp", "${entity.name}." + _op, _live ? "live" : "unit")
|
|
98
|
+
if _should_skip
|
|
99
|
+
skip(_reason || "skipped via sdk-test-control.json")
|
|
100
|
+
return
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
# The basic flow consumes synthetic IDs from the fixture. In live mode
|
|
104
|
+
# without an *_ENTID env override, those IDs hit the live API and 4xx.
|
|
105
|
+
if setup[:synthetic_only]
|
|
106
|
+
skip "live entity test uses synthetic IDs from fixture — set ${PROJUPPER}_TEST_${entity.name.toUpperCase().replace(/[^A-Z_]/g, '_')}_ENTID JSON to run live"
|
|
107
|
+
return
|
|
108
|
+
end
|
|
80
109
|
client = setup[:client]
|
|
81
110
|
|
|
82
111
|
`)
|
|
@@ -138,11 +167,16 @@ end
|
|
|
138
167
|
|
|
139
168
|
`)
|
|
140
169
|
|
|
141
|
-
Content(` env
|
|
170
|
+
Content(` # Detect ENTID env override before envOverride consumes it. When live
|
|
171
|
+
# mode is on without a real override, the basic test runs against synthetic
|
|
172
|
+
# IDs from the fixture and 4xx's. Surface this so the test can skip.
|
|
173
|
+
entid_env_raw = ENV["${PROJUPPER}_TEST_${entity.name.toUpperCase().replace(/[^A-Z_]/g, '_')}_ENTID"]
|
|
174
|
+
idmap_overridden = !entid_env_raw.nil? && entid_env_raw.strip.start_with?("{")
|
|
175
|
+
|
|
176
|
+
env = Runner.env_override({
|
|
142
177
|
"${PROJUPPER}_TEST_${entity.name.toUpperCase().replace(/[^A-Z_]/g, '_')}_ENTID" => idmap,
|
|
143
178
|
"${PROJUPPER}_TEST_LIVE" => "FALSE",
|
|
144
|
-
"${PROJUPPER}_TEST_EXPLAIN" => "FALSE"
|
|
145
|
-
"${PROJUPPER}_APIKEY" => "NONE",
|
|
179
|
+
"${PROJUPPER}_TEST_EXPLAIN" => "FALSE",${apikeyEnvEntry}
|
|
146
180
|
})
|
|
147
181
|
|
|
148
182
|
idmap_resolved = Helpers.to_map(
|
|
@@ -163,20 +197,22 @@ end
|
|
|
163
197
|
Content(`
|
|
164
198
|
if env["${PROJUPPER}_TEST_LIVE"] == "TRUE"
|
|
165
199
|
merged_opts = Vs.merge([
|
|
166
|
-
{
|
|
167
|
-
"apikey" => env["${PROJUPPER}_APIKEY"],
|
|
200
|
+
{${apikeyLiveField}
|
|
168
201
|
},
|
|
169
202
|
extra || {},
|
|
170
203
|
])
|
|
171
204
|
client = ${model.const.Name}SDK.new(Helpers.to_map(merged_opts))
|
|
172
205
|
end
|
|
173
206
|
|
|
207
|
+
live = env["${PROJUPPER}_TEST_LIVE"] == "TRUE"
|
|
174
208
|
{
|
|
175
209
|
client: client,
|
|
176
210
|
data: entity_data,
|
|
177
211
|
idmap: idmap_resolved,
|
|
178
212
|
env: env,
|
|
179
213
|
explain: env["${PROJUPPER}_TEST_EXPLAIN"] == "TRUE",
|
|
214
|
+
live: live,
|
|
215
|
+
synthetic_only: live && !idmap_overridden,
|
|
180
216
|
now: (Time.now.to_f * 1000).to_i,
|
|
181
217
|
}
|
|
182
218
|
end
|
|
@@ -187,9 +223,9 @@ end
|
|
|
187
223
|
|
|
188
224
|
const generateCreate: OpGen = (ctx, step, index) => {
|
|
189
225
|
const { entity, flow } = ctx
|
|
190
|
-
const ref = step.input
|
|
191
|
-
const entvar = step.input
|
|
192
|
-
const datavar = step.input
|
|
226
|
+
const ref = step.input.ref ?? entity.name + '_ref01'
|
|
227
|
+
const entvar = step.input.entvar ?? ref + '_ent'
|
|
228
|
+
const datavar = step.input.datavar ?? (ref + '_data' + (step.input.suffix ?? ''))
|
|
193
229
|
|
|
194
230
|
const priorSteps = Object.values(flow.step).slice(0, Number(index)) as any[]
|
|
195
231
|
const needsEnt = !priorSteps.some((s: any) =>
|
|
@@ -197,8 +233,8 @@ const generateCreate: OpGen = (ctx, step, index) => {
|
|
|
197
233
|
|
|
198
234
|
const hasDatvar = priorSteps.some((s: any) => {
|
|
199
235
|
if ('create' === s.op) {
|
|
200
|
-
const priorRef = s.input
|
|
201
|
-
const priorDatvar = s.input
|
|
236
|
+
const priorRef = s.input.ref ?? entity.name + '_ref01'
|
|
237
|
+
const priorDatvar = s.input.datavar ?? (priorRef + '_data' + (s.input.suffix ?? ''))
|
|
202
238
|
return priorDatvar === datavar
|
|
203
239
|
}
|
|
204
240
|
return false
|
|
@@ -232,17 +268,20 @@ const generateCreate: OpGen = (ctx, step, index) => {
|
|
|
232
268
|
assert_nil err
|
|
233
269
|
${datavar} = Helpers.to_map(${datavar}_result)
|
|
234
270
|
assert !${datavar}.nil?
|
|
235
|
-
assert !${datavar}["id"].nil?
|
|
236
271
|
`)
|
|
272
|
+
if (null != ctx.entity.id) {
|
|
273
|
+
Content(` assert !${datavar}["id"].nil?
|
|
274
|
+
`)
|
|
275
|
+
}
|
|
237
276
|
}
|
|
238
277
|
|
|
239
278
|
|
|
240
279
|
const generateList: OpGen = (ctx, step, index) => {
|
|
241
280
|
const { entity, flow } = ctx
|
|
242
|
-
const ref = step.input
|
|
243
|
-
const entvar = step.input
|
|
244
|
-
const matchvar = step.input
|
|
245
|
-
const listvar = step.input
|
|
281
|
+
const ref = step.input.ref ?? entity.name + '_ref01'
|
|
282
|
+
const entvar = step.input.entvar ?? ref + '_ent'
|
|
283
|
+
const matchvar = step.input.matchvar ?? (ref + '_match' + (step.input.suffix ?? ''))
|
|
284
|
+
const listvar = step.input.listvar ?? (ref + '_list' + (step.input.suffix ?? ''))
|
|
246
285
|
|
|
247
286
|
const priorSteps = Object.values(flow.step).slice(0, Number(index)) as any[]
|
|
248
287
|
const needsEnt = !priorSteps.some((s: any) =>
|
|
@@ -282,7 +321,7 @@ const generateList: OpGen = (ctx, step, index) => {
|
|
|
282
321
|
for (const validator of step.valid) {
|
|
283
322
|
const validRef = validator.def?.ref
|
|
284
323
|
const hasRefData = validRef && allSteps.some((s: any) => 'create' === s.op &&
|
|
285
|
-
((s.input
|
|
324
|
+
((s.input.ref ?? entity.name + '_ref01') === validRef))
|
|
286
325
|
|
|
287
326
|
if ('ItemExists' === validator.apply && hasRefData) {
|
|
288
327
|
const refDataVar = validRef + '_data'
|
|
@@ -308,17 +347,19 @@ const generateList: OpGen = (ctx, step, index) => {
|
|
|
308
347
|
|
|
309
348
|
const generateUpdate: OpGen = (ctx, step, index) => {
|
|
310
349
|
const { entity, flow } = ctx
|
|
311
|
-
const ref = step.input
|
|
312
|
-
const entvar = step.input
|
|
313
|
-
const datavar = step.input
|
|
314
|
-
const resdatavar = step.input
|
|
315
|
-
const markdefvar = step.input
|
|
316
|
-
const srcdatavar = step.input
|
|
350
|
+
const ref = step.input.ref ?? entity.name + '_ref01'
|
|
351
|
+
const entvar = step.input.entvar ?? ref + '_ent'
|
|
352
|
+
const datavar = step.input.datavar ?? (ref + '_data' + (step.input.suffix ?? ''))
|
|
353
|
+
const resdatavar = step.input.resdatavar ?? (ref + '_resdata' + (step.input.suffix ?? ''))
|
|
354
|
+
const markdefvar = step.input.markdefvar ?? (ref + '_markdef' + (step.input.suffix ?? ''))
|
|
355
|
+
const srcdatavar = step.input.srcdatavar ?? (ref + '_data' + (step.input.suffix ?? ''))
|
|
317
356
|
|
|
318
357
|
const priorSteps = Object.values(flow.step).slice(0, Number(index)) as any[]
|
|
319
358
|
const needsEnt = !priorSteps.some((s: any) =>
|
|
320
359
|
['create', 'list', 'load', 'update', 'remove'].includes(s.op))
|
|
321
360
|
|
|
361
|
+
const hasEntIdU = null != entity.id
|
|
362
|
+
|
|
322
363
|
Content(` # UPDATE
|
|
323
364
|
`)
|
|
324
365
|
if (needsEnt) {
|
|
@@ -326,8 +367,11 @@ const generateUpdate: OpGen = (ctx, step, index) => {
|
|
|
326
367
|
`)
|
|
327
368
|
}
|
|
328
369
|
Content(` ${datavar}_up = {
|
|
329
|
-
"id" => ${srcdatavar}["id"],
|
|
330
370
|
`)
|
|
371
|
+
if (hasEntIdU) {
|
|
372
|
+
Content(` "id" => ${srcdatavar}["id"],
|
|
373
|
+
`)
|
|
374
|
+
}
|
|
331
375
|
|
|
332
376
|
if (step.data) {
|
|
333
377
|
const dataEntries = Object.entries(step.data).filter(([k]: any) => k !== 'id' && !k.endsWith('$'))
|
|
@@ -342,7 +386,7 @@ const generateUpdate: OpGen = (ctx, step, index) => {
|
|
|
342
386
|
|
|
343
387
|
if (step.spec) {
|
|
344
388
|
for (const spec of step.spec) {
|
|
345
|
-
if ('TextFieldMark' === spec.apply && null != step.input
|
|
389
|
+
if ('TextFieldMark' === spec.apply && null != step.input.textfield) {
|
|
346
390
|
const fieldname = step.input.textfield
|
|
347
391
|
const fieldvalue = spec.def?.mark ?? `Mark01-${ref}`
|
|
348
392
|
Content(`
|
|
@@ -359,12 +403,15 @@ const generateUpdate: OpGen = (ctx, step, index) => {
|
|
|
359
403
|
assert_nil err
|
|
360
404
|
${resdatavar} = Helpers.to_map(${resdatavar}_result)
|
|
361
405
|
assert !${resdatavar}.nil?
|
|
362
|
-
assert_equal ${resdatavar}["id"], ${datavar}_up["id"]
|
|
363
406
|
`)
|
|
407
|
+
if (hasEntIdU) {
|
|
408
|
+
Content(` assert_equal ${resdatavar}["id"], ${datavar}_up["id"]
|
|
409
|
+
`)
|
|
410
|
+
}
|
|
364
411
|
|
|
365
412
|
if (step.spec) {
|
|
366
413
|
for (const spec of step.spec) {
|
|
367
|
-
if ('TextFieldMark' === spec.apply && null != step.input
|
|
414
|
+
if ('TextFieldMark' === spec.apply && null != step.input.textfield) {
|
|
368
415
|
Content(` assert_equal ${resdatavar}[${markdefvar}_name], ${markdefvar}_value
|
|
369
416
|
`)
|
|
370
417
|
}
|
|
@@ -375,11 +422,11 @@ const generateUpdate: OpGen = (ctx, step, index) => {
|
|
|
375
422
|
|
|
376
423
|
const generateLoad: OpGen = (ctx, step, index) => {
|
|
377
424
|
const { entity, flow } = ctx
|
|
378
|
-
const ref = step.input
|
|
379
|
-
const entvar = step.input
|
|
380
|
-
const matchvar = step.input
|
|
381
|
-
const datavar = step.input
|
|
382
|
-
const srcdatavar = step.input
|
|
425
|
+
const ref = step.input.ref ?? entity.name + '_ref01'
|
|
426
|
+
const entvar = step.input.entvar ?? ref + '_ent'
|
|
427
|
+
const matchvar = step.input.matchvar ?? (ref + '_match' + (step.input.suffix ?? ''))
|
|
428
|
+
const datavar = step.input.datavar ?? (ref + '_data' + (step.input.suffix ?? ''))
|
|
429
|
+
const srcdatavar = step.input.srcdatavar ?? (ref + '_data' + (step.input.suffix ?? ''))
|
|
383
430
|
|
|
384
431
|
const priorSteps = Object.values(flow.step).slice(0, Number(index)) as any[]
|
|
385
432
|
const hasEntVar = priorSteps.some((s: any) =>
|
|
@@ -390,20 +437,22 @@ const generateLoad: OpGen = (ctx, step, index) => {
|
|
|
390
437
|
const hasSrcData = (!flowHasCreate && srcdatavar === (preambleRef + '_data')) ||
|
|
391
438
|
priorSteps.some((s: any) => {
|
|
392
439
|
if ('create' === s.op) {
|
|
393
|
-
const priorRef = s.input
|
|
394
|
-
const priorDatvar = s.input
|
|
440
|
+
const priorRef = s.input.ref ?? entity.name + '_ref01'
|
|
441
|
+
const priorDatvar = s.input.datavar ?? (priorRef + '_data' + (s.input.suffix ?? ''))
|
|
395
442
|
return priorDatvar === srcdatavar
|
|
396
443
|
}
|
|
397
444
|
return false
|
|
398
445
|
})
|
|
399
446
|
|
|
447
|
+
const hasEntId = null != entity.id
|
|
448
|
+
|
|
400
449
|
Content(` # LOAD
|
|
401
450
|
`)
|
|
402
451
|
if (!hasEntVar) {
|
|
403
452
|
Content(` ${entvar} = client.${entity.Name}(nil)
|
|
404
453
|
`)
|
|
405
454
|
}
|
|
406
|
-
if (!hasSrcData) {
|
|
455
|
+
if (!hasSrcData && hasEntId) {
|
|
407
456
|
Content(` ${srcdatavar}_raw = Vs.items(Helpers.to_map(
|
|
408
457
|
Vs.getpath(setup[:data], "existing.${entity.name}")))
|
|
409
458
|
${srcdatavar} = nil
|
|
@@ -412,7 +461,8 @@ const generateLoad: OpGen = (ctx, step, index) => {
|
|
|
412
461
|
end
|
|
413
462
|
`)
|
|
414
463
|
}
|
|
415
|
-
|
|
464
|
+
if (hasEntId) {
|
|
465
|
+
Content(` ${matchvar} = {
|
|
416
466
|
"id" => ${srcdatavar}["id"],
|
|
417
467
|
}
|
|
418
468
|
${datavar}_loaded, err = ${entvar}.load(${matchvar}, nil)
|
|
@@ -421,32 +471,50 @@ const generateLoad: OpGen = (ctx, step, index) => {
|
|
|
421
471
|
assert !${datavar}_load_result.nil?
|
|
422
472
|
assert_equal ${datavar}_load_result["id"], ${srcdatavar}["id"]
|
|
423
473
|
`)
|
|
474
|
+
}
|
|
475
|
+
else {
|
|
476
|
+
Content(` ${matchvar} = {}
|
|
477
|
+
${datavar}_loaded, err = ${entvar}.load(${matchvar}, nil)
|
|
478
|
+
assert_nil err
|
|
479
|
+
assert !${datavar}_loaded.nil?
|
|
480
|
+
`)
|
|
481
|
+
}
|
|
424
482
|
}
|
|
425
483
|
|
|
426
484
|
|
|
427
485
|
const generateRemove: OpGen = (ctx, step, index) => {
|
|
428
486
|
const { entity, flow } = ctx
|
|
429
|
-
const ref = step.input
|
|
430
|
-
const entvar = step.input
|
|
431
|
-
const matchvar = step.input
|
|
432
|
-
const srcdatavar = step.input
|
|
487
|
+
const ref = step.input.ref ?? entity.name + '_ref01'
|
|
488
|
+
const entvar = step.input.entvar ?? ref + '_ent'
|
|
489
|
+
const matchvar = step.input.matchvar ?? (ref + '_match' + (step.input.suffix ?? ''))
|
|
490
|
+
const srcdatavar = step.input.srcdatavar ?? (ref + '_data')
|
|
433
491
|
|
|
434
492
|
const priorSteps = Object.values(flow.step).slice(0, Number(index)) as any[]
|
|
435
493
|
const needsEnt = !priorSteps.some((s: any) =>
|
|
436
494
|
['create', 'list', 'load', 'update', 'remove'].includes(s.op))
|
|
437
495
|
|
|
496
|
+
const hasEntIdR = null != entity.id
|
|
497
|
+
|
|
438
498
|
Content(` # REMOVE
|
|
439
499
|
`)
|
|
440
500
|
if (needsEnt) {
|
|
441
501
|
Content(` ${entvar} = client.${entity.Name}(nil)
|
|
442
502
|
`)
|
|
443
503
|
}
|
|
444
|
-
|
|
504
|
+
if (hasEntIdR) {
|
|
505
|
+
Content(` ${matchvar} = {
|
|
445
506
|
"id" => ${srcdatavar}["id"],
|
|
446
507
|
}
|
|
447
508
|
_, err = ${entvar}.remove(${matchvar}, nil)
|
|
448
509
|
assert_nil err
|
|
449
510
|
`)
|
|
511
|
+
}
|
|
512
|
+
else {
|
|
513
|
+
Content(` ${matchvar} = {}
|
|
514
|
+
_, err = ${entvar}.remove(${matchvar}, nil)
|
|
515
|
+
assert_nil err
|
|
516
|
+
`)
|
|
517
|
+
}
|
|
450
518
|
}
|
|
451
519
|
|
|
452
520
|
|
|
@@ -164,14 +164,30 @@ class ProjectNameSDK
|
|
|
164
164
|
|
|
165
165
|
if fetched.is_a?(Hash)
|
|
166
166
|
status = ProjectNameHelpers.to_int(VoxgigStruct.getprop(fetched, "status"))
|
|
167
|
+
headers = VoxgigStruct.getprop(fetched, "headers") || {}
|
|
168
|
+
|
|
169
|
+
# No-body responses (204, 304) and explicit zero content-length must
|
|
170
|
+
# skip JSON parsing — calling json() on an empty body errors.
|
|
171
|
+
content_length = headers.is_a?(Hash) ? headers["content-length"] : nil
|
|
172
|
+
no_body = status == 204 || status == 304 || content_length.to_s == "0"
|
|
173
|
+
|
|
167
174
|
json_data = nil
|
|
168
|
-
|
|
169
|
-
|
|
175
|
+
unless no_body
|
|
176
|
+
jf = VoxgigStruct.getprop(fetched, "json")
|
|
177
|
+
if jf.is_a?(Proc)
|
|
178
|
+
begin
|
|
179
|
+
json_data = jf.call
|
|
180
|
+
rescue StandardError
|
|
181
|
+
# Non-JSON body — leave data nil, keep status/headers.
|
|
182
|
+
json_data = nil
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
170
186
|
|
|
171
187
|
return {
|
|
172
188
|
"ok" => status >= 200 && status < 300,
|
|
173
189
|
"status" => status,
|
|
174
|
-
"headers" =>
|
|
190
|
+
"headers" => headers,
|
|
175
191
|
"data" => json_data,
|
|
176
192
|
}, nil
|
|
177
193
|
end
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
cmp,
|
|
11
11
|
each,
|
|
12
12
|
indent,
|
|
13
|
+
isAuthActive,
|
|
13
14
|
} from '@voxgig/sdkgen'
|
|
14
15
|
|
|
15
16
|
|
|
@@ -40,6 +41,21 @@ const Config = cmp(async function Config(props: any) {
|
|
|
40
41
|
|
|
41
42
|
const headers = getModelPath(model, `main.${KIT}.config.headers`) || {}
|
|
42
43
|
|
|
44
|
+
const authActive = isAuthActive(model)
|
|
45
|
+
let authPrefix = 'Bearer'
|
|
46
|
+
try {
|
|
47
|
+
const v = getModelPath(model, `main.${KIT}.config.auth.prefix`,
|
|
48
|
+
{ only_active: false, required: false })
|
|
49
|
+
if (null != v) authPrefix = v
|
|
50
|
+
} catch (_e) { /* ignore */ }
|
|
51
|
+
const authBlock = authActive
|
|
52
|
+
? `auth: {
|
|
53
|
+
prefix: '${authPrefix}',
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
`
|
|
57
|
+
: ''
|
|
58
|
+
|
|
43
59
|
File({ name: 'Config.' + target.ext }, () => {
|
|
44
60
|
|
|
45
61
|
Fragment({
|
|
@@ -47,6 +63,8 @@ const Config = cmp(async function Config(props: any) {
|
|
|
47
63
|
|
|
48
64
|
replace: {
|
|
49
65
|
|
|
66
|
+
"'AUTHBLOCK'": authBlock,
|
|
67
|
+
|
|
50
68
|
"'HEADERS'": indent(JSON.stringify(headers, null, 2), 4).trim(),
|
|
51
69
|
|
|
52
70
|
'// #ImportFeatures': () => each(feature, (f: any) => {
|
|
@@ -57,7 +57,7 @@ const Package = cmp(async function Package(props: any) {
|
|
|
57
57
|
type: 'commonjs',
|
|
58
58
|
types: `dist/${SdkName}SDK.d.ts`,
|
|
59
59
|
scripts: {
|
|
60
|
-
'test': 'node --enable-source-maps --test \'dist-test/**/*.test.js\'',
|
|
60
|
+
'test': 'node --enable-source-maps --test-concurrency=1 --test \'dist-test/**/*.test.js\'',
|
|
61
61
|
'test-some': 'node --enable-source-maps --experimental-test-isolation=none ' +
|
|
62
62
|
'--test-name-pattern=\"$TEST_PATTERN\" --test \'dist-test/**/*.test.js\'',
|
|
63
63
|
'test-utility': 'node --enable-source-maps --test test/utility/*.test.ts',
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
|
|
2
|
+
import { cmp, each, Content } from '@voxgig/sdkgen'
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
KIT,
|
|
6
|
+
getModelPath,
|
|
7
|
+
} from '@voxgig/apidef'
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
// Operation method spelling differs between Go and other languages — Go
|
|
11
|
+
// uses PascalCase methods with explicit ctrl arg, others use lowercase
|
|
12
|
+
// methods with optional ctrl. The op descriptions are language-agnostic.
|
|
13
|
+
const OP_DESC: Record<string, { method: string, desc: string }> = {
|
|
14
|
+
load: { method: 'load(match)', desc: 'Load a single entity by match criteria.' },
|
|
15
|
+
list: { method: 'list(match)', desc: 'List entities matching the criteria.' },
|
|
16
|
+
create: { method: 'create(data)', desc: 'Create a new entity with the given data.' },
|
|
17
|
+
update: { method: 'update(data)', desc: 'Update an existing entity.' },
|
|
18
|
+
remove: { method: 'remove(match)', desc: 'Remove the matching entity.' },
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
const ReadmeEntity = cmp(function ReadmeEntity(props: any) {
|
|
23
|
+
const { target } = props
|
|
24
|
+
const { model } = props.ctx$
|
|
25
|
+
|
|
26
|
+
const entity = getModelPath(model, `main.${KIT}.entity`)
|
|
27
|
+
|
|
28
|
+
const publishedEntities = each(entity)
|
|
29
|
+
.filter((entity: any) => entity.active !== false)
|
|
30
|
+
|
|
31
|
+
if (0 === publishedEntities.length) {
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
Content(`
|
|
36
|
+
|
|
37
|
+
## Entities
|
|
38
|
+
|
|
39
|
+
`)
|
|
40
|
+
|
|
41
|
+
publishedEntities.map((entity: any) => {
|
|
42
|
+
const opnames = Object.keys(entity.op || {})
|
|
43
|
+
const fields = entity.fields || []
|
|
44
|
+
|
|
45
|
+
Content(`
|
|
46
|
+
### ${entity.Name}
|
|
47
|
+
|
|
48
|
+
`)
|
|
49
|
+
|
|
50
|
+
if (entity.short) {
|
|
51
|
+
Content(`${entity.short}
|
|
52
|
+
|
|
53
|
+
`)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
Content(`Create an instance: \`const ${entity.name} = client.${entity.Name}()\`
|
|
57
|
+
|
|
58
|
+
`)
|
|
59
|
+
|
|
60
|
+
if (opnames.length > 0) {
|
|
61
|
+
Content(`#### Operations
|
|
62
|
+
|
|
63
|
+
| Method | Description |
|
|
64
|
+
| --- | --- |
|
|
65
|
+
`)
|
|
66
|
+
opnames.map((opname: string) => {
|
|
67
|
+
const info = OP_DESC[opname]
|
|
68
|
+
if (info) {
|
|
69
|
+
Content(`| \`${info.method}\` | ${info.desc} |
|
|
70
|
+
`)
|
|
71
|
+
}
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
Content(`
|
|
75
|
+
`)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (fields.length > 0) {
|
|
79
|
+
Content(`#### Fields
|
|
80
|
+
|
|
81
|
+
| Field | Type | Description |
|
|
82
|
+
| --- | --- | --- |
|
|
83
|
+
`)
|
|
84
|
+
|
|
85
|
+
each(fields, (field: any) => {
|
|
86
|
+
const desc = field.short || ''
|
|
87
|
+
Content(`| \`${field.name}\` | \`${field.type || 'any'}\` | ${desc} |
|
|
88
|
+
`)
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
Content(`
|
|
92
|
+
`)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (opnames.includes('load')) {
|
|
96
|
+
Content(`#### Example: Load
|
|
97
|
+
|
|
98
|
+
\`\`\`ts
|
|
99
|
+
const ${entity.name} = await client.${entity.Name}().load({ id: '${entity.name}_id' })
|
|
100
|
+
\`\`\`
|
|
101
|
+
|
|
102
|
+
`)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (opnames.includes('list')) {
|
|
106
|
+
Content(`#### Example: List
|
|
107
|
+
|
|
108
|
+
\`\`\`ts
|
|
109
|
+
const ${entity.name}s = await client.${entity.Name}().list()
|
|
110
|
+
\`\`\`
|
|
111
|
+
|
|
112
|
+
`)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (opnames.includes('create')) {
|
|
116
|
+
Content(`#### Example: Create
|
|
117
|
+
|
|
118
|
+
\`\`\`ts
|
|
119
|
+
const ${entity.name} = await client.${entity.Name}().create({
|
|
120
|
+
`)
|
|
121
|
+
each(fields, (field: any) => {
|
|
122
|
+
if ('id' !== field.name && field.req) {
|
|
123
|
+
Content(` ${field.name}: /* ${field.type || 'value'} */,
|
|
124
|
+
`)
|
|
125
|
+
}
|
|
126
|
+
})
|
|
127
|
+
Content(`})
|
|
128
|
+
\`\`\`
|
|
129
|
+
|
|
130
|
+
`)
|
|
131
|
+
}
|
|
132
|
+
})
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
export {
|
|
137
|
+
ReadmeEntity
|
|
138
|
+
}
|
|
@@ -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,
|
|
@@ -10,6 +10,13 @@ import {
|
|
|
10
10
|
const ReadmeHowto = cmp(function ReadmeHowto(props: any) {
|
|
11
11
|
const { target, ctx$: { model } } = props
|
|
12
12
|
|
|
13
|
+
const authActive = isAuthActive(model)
|
|
14
|
+
const apikeyTesterCtor = authActive
|
|
15
|
+
? `new ${model.const.Name}SDK({ apikey: '...' })`
|
|
16
|
+
: `new ${model.const.Name}SDK()`
|
|
17
|
+
const apikeyExtendField = authActive ? `\n apikey: '...',` : ''
|
|
18
|
+
const apikeyEnvLine = authActive ? `\n${model.NAME}_APIKEY=<your-key>` : ''
|
|
19
|
+
|
|
13
20
|
Content(`### Make a direct HTTP request
|
|
14
21
|
|
|
15
22
|
For endpoints not covered by entity methods:
|
|
@@ -57,7 +64,7 @@ const result = await client.Planet().load({ id: 'test01' })
|
|
|
57
64
|
You can also use the instance method:
|
|
58
65
|
|
|
59
66
|
\`\`\`ts
|
|
60
|
-
const client =
|
|
67
|
+
const client = ${apikeyTesterCtor}
|
|
61
68
|
const testClient = client.tester()
|
|
62
69
|
\`\`\`
|
|
63
70
|
|
|
@@ -92,8 +99,7 @@ const logger = {
|
|
|
92
99
|
},
|
|
93
100
|
}
|
|
94
101
|
|
|
95
|
-
const client = new ${model.const.Name}SDK({
|
|
96
|
-
apikey: '...',
|
|
102
|
+
const client = new ${model.const.Name}SDK({${apikeyExtendField}
|
|
97
103
|
extend: [logger],
|
|
98
104
|
})
|
|
99
105
|
\`\`\`
|
|
@@ -103,8 +109,7 @@ const client = new ${model.const.Name}SDK({
|
|
|
103
109
|
Create a \`.env.local\` file at the project root:
|
|
104
110
|
|
|
105
111
|
\`\`\`
|
|
106
|
-
${model.NAME}_TEST_LIVE=TRUE
|
|
107
|
-
${model.NAME}_APIKEY=<your-key>
|
|
112
|
+
${model.NAME}_TEST_LIVE=TRUE${apikeyEnvLine}
|
|
108
113
|
\`\`\`
|
|
109
114
|
|
|
110
115
|
Then run:
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
|
|
2
|
+
import { cmp, Content } from '@voxgig/sdkgen'
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
const ReadmeIntro = cmp(function ReadmeIntro(props: any) {
|
|
6
|
+
const { target, ctx$: { model } } = props
|
|
7
|
+
|
|
8
|
+
Content(`# ${model.Name} ${target.title} SDK
|
|
9
|
+
|
|
10
|
+
The ${target.title} SDK for the ${model.Name} API. Provides a type-safe, entity-oriented interface with full async/await support.
|
|
11
|
+
|
|
12
|
+
`)
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
export {
|
|
17
|
+
ReadmeIntro
|
|
18
|
+
}
|