@voxgig/sdkgen 4.6.0 → 4.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/voxgig-sdkgen +1 -1
- package/dist/cmp/Feature.js +5 -0
- package/dist/cmp/Feature.js.map +1 -1
- package/dist/cmp/TestControl.d.ts +4 -0
- package/dist/cmp/TestControl.js +51 -0
- package/dist/cmp/TestControl.js.map +1 -0
- package/dist/helpers/featureSource.d.ts +3 -1
- package/dist/helpers/featureSource.js +105 -0
- package/dist/helpers/featureSource.js.map +1 -1
- package/dist/helpers/opShape.js +8 -11
- package/dist/helpers/opShape.js.map +1 -1
- package/dist/helpers/pointPath.d.ts +10 -0
- package/dist/helpers/pointPath.js +54 -0
- package/dist/helpers/pointPath.js.map +1 -0
- package/dist/sdkgen.d.ts +6 -3
- package/dist/sdkgen.js +14 -4
- package/dist/sdkgen.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utility.d.ts +2 -1
- package/dist/utility.js +78 -1
- package/dist/utility.js.map +1 -1
- package/model/sdkgen.aon +58 -0
- package/package.json +2 -2
- package/project/.sdk/model/feature/secrets.aon +82 -0
- package/project/.sdk/src/cmp/c/Config_c.ts +7 -8
- package/project/.sdk/src/cmp/c/TestDirect_c.ts +4 -3
- package/project/.sdk/src/cmp/cpp/Main_cpp.ts +2 -1
- package/project/.sdk/src/cmp/cpp/TestDirect_cpp.ts +4 -3
- package/project/.sdk/src/cmp/cpp/Test_cpp.ts +5 -1
- package/project/.sdk/src/cmp/csharp/Main_csharp.ts +2 -1
- package/project/.sdk/src/cmp/csharp/TestDirect_csharp.ts +34 -9
- package/project/.sdk/src/cmp/csharp/TestEntity_csharp.ts +29 -5
- package/project/.sdk/src/cmp/csharp/Test_csharp.ts +5 -1
- package/project/.sdk/src/cmp/dart/Config_dart.ts +7 -8
- package/project/.sdk/src/cmp/dart/Main_dart.ts +2 -1
- package/project/.sdk/src/cmp/dart/TestDirect_dart.ts +28 -10
- package/project/.sdk/src/cmp/dart/TestEntity_dart.ts +28 -7
- package/project/.sdk/src/cmp/dart/Test_dart.ts +5 -1
- package/project/.sdk/src/cmp/elixir/Config_elixir.ts +9 -8
- package/project/.sdk/src/cmp/go/Config_go.ts +1 -7
- package/project/.sdk/src/cmp/go/Main_go.ts +2 -1
- package/project/.sdk/src/cmp/go/TestDirect_go.ts +5 -4
- package/project/.sdk/src/cmp/go/Test_go.ts +5 -1
- package/project/.sdk/src/cmp/java/Config_java.ts +7 -7
- package/project/.sdk/src/cmp/java/Main_java.ts +2 -1
- package/project/.sdk/src/cmp/java/TestDirect_java.ts +5 -4
- package/project/.sdk/src/cmp/java/Test_java.ts +5 -1
- package/project/.sdk/src/cmp/js/Config_js.ts +7 -8
- package/project/.sdk/src/cmp/js/Main_js.ts +2 -1
- package/project/.sdk/src/cmp/js/TestDirect_js.ts +34 -8
- package/project/.sdk/src/cmp/js/TestEntity_js.ts +35 -5
- package/project/.sdk/src/cmp/js/Test_js.ts +5 -1
- package/project/.sdk/src/cmp/js/fragment/Direct.test.fragment.js +7 -1
- package/project/.sdk/src/cmp/js/fragment/Entity.test.fragment.js +7 -1
- package/project/.sdk/src/cmp/kotlin/Config_kotlin.ts +7 -7
- package/project/.sdk/src/cmp/kotlin/Main_kotlin.ts +2 -1
- package/project/.sdk/src/cmp/kotlin/TestDirect_kotlin.ts +5 -4
- package/project/.sdk/src/cmp/kotlin/Test_kotlin.ts +5 -1
- package/project/.sdk/src/cmp/lean/Config_lean.ts +9 -8
- package/project/.sdk/src/cmp/lua/Config_lua.ts +1 -7
- package/project/.sdk/src/cmp/lua/Main_lua.ts +2 -1
- package/project/.sdk/src/cmp/lua/TestDirect_lua.ts +32 -7
- package/project/.sdk/src/cmp/lua/TestEntity_lua.ts +24 -4
- package/project/.sdk/src/cmp/lua/Test_lua.ts +5 -1
- package/project/.sdk/src/cmp/ocaml/Gitignore_ocaml.ts +1 -0
- package/project/.sdk/src/cmp/perl/Main_perl.ts +2 -1
- package/project/.sdk/src/cmp/perl/TestDirect_perl.ts +29 -7
- package/project/.sdk/src/cmp/perl/TestEntity_perl.ts +24 -4
- package/project/.sdk/src/cmp/perl/Test_perl.ts +5 -1
- package/project/.sdk/src/cmp/perl/utility_perl.ts +10 -0
- package/project/.sdk/src/cmp/php/Config_php.ts +1 -7
- package/project/.sdk/src/cmp/php/Main_php.ts +2 -1
- package/project/.sdk/src/cmp/php/TestDirect_php.ts +28 -8
- package/project/.sdk/src/cmp/php/TestEntity_php.ts +28 -4
- package/project/.sdk/src/cmp/php/Test_php.ts +5 -1
- package/project/.sdk/src/cmp/py/Config_py.ts +1 -7
- package/project/.sdk/src/cmp/py/Main_py.ts +2 -1
- package/project/.sdk/src/cmp/py/TestDirect_py.ts +5 -4
- package/project/.sdk/src/cmp/py/Test_py.ts +5 -1
- package/project/.sdk/src/cmp/rb/Config_rb.ts +1 -7
- package/project/.sdk/src/cmp/rb/Main_rb.ts +2 -1
- package/project/.sdk/src/cmp/rb/TestDirect_rb.ts +28 -8
- package/project/.sdk/src/cmp/rb/TestEntity_rb.ts +24 -4
- package/project/.sdk/src/cmp/rb/Test_rb.ts +5 -1
- package/project/.sdk/src/cmp/rb/utility_rb.ts +3 -1
- package/project/.sdk/src/cmp/rust/Main_rust.ts +2 -1
- package/project/.sdk/src/cmp/rust/TestDirect_rust.ts +35 -7
- package/project/.sdk/src/cmp/rust/TestEntity_rust.ts +37 -4
- package/project/.sdk/src/cmp/rust/Test_rust.ts +5 -1
- package/project/.sdk/src/cmp/scala/Config_scala.ts +9 -7
- package/project/.sdk/src/cmp/scala/Main_scala.ts +2 -1
- package/project/.sdk/src/cmp/scala/TestDirect_scala.ts +4 -3
- package/project/.sdk/src/cmp/scala/Test_scala.ts +5 -1
- package/project/.sdk/src/cmp/seneca-provider/Extras_seneca-provider.ts +3 -1
- package/project/.sdk/src/cmp/seneca-provider/Main_seneca-provider.ts +9 -5
- package/project/.sdk/src/cmp/ts/Config_ts.ts +57 -16
- package/project/.sdk/src/cmp/ts/Main_ts.ts +10 -2
- package/project/.sdk/src/cmp/ts/TestDirect_ts.ts +15 -7
- package/project/.sdk/src/cmp/ts/TestEntity_ts.ts +11 -3
- package/project/.sdk/src/cmp/ts/Test_ts.ts +5 -1
- package/project/.sdk/tm/csharp/test/Runner.cs +45 -0
- package/project/.sdk/tm/dart/test/utility.dart +39 -0
- package/project/.sdk/tm/js/test/sdk-test-control.json +19 -0
- package/project/.sdk/tm/js/test/utility.js +91 -1
- package/project/.sdk/tm/lua/test/runner.lua +40 -0
- package/project/.sdk/tm/ocaml/test/harness.ml +14 -4
- package/project/.sdk/tm/perl/t/runner.pm +30 -0
- package/project/.sdk/tm/php/test/Runner.php +36 -0
- package/project/.sdk/tm/rb/test/runner.rb +25 -0
- package/project/.sdk/tm/rust/tests/common/mod.rs +32 -0
- package/project/.sdk/tm/rust/utility/make_options.rs +1 -1
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/Sekreto.ts +8 -2
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/Sigv4.ts +29 -5
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/index.ts +30 -21
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/Registry.ts +90 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/addr.ts +48 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/aws.ts +219 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/azuresecrets.ts +144 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/boru.ts +113 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/doppler.ts +77 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/dotenv.ts +51 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/env.ts +31 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/file.ts +54 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/gcpsecrets.ts +118 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/hashicorp.ts +159 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/http.ts +66 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/infisical.ts +107 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/memory.ts +33 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/onepassword.ts +120 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/support.ts +176 -0
- package/project/.sdk/tm/ts/test/vendor/omni/Runner.ts +15 -13
- package/project/.sdk/tm/ts/test/vendor/omni/Util.ts +25 -19
- package/project/.sdk/tm/ts/test/vendor/omni/compat.ts +1 -1
- package/project/.sdk/tm/ts/test/vendor/omni/index.ts +1 -1
- package/project/.sdk/tm/zig/core/utility.zig +1 -1
- package/project/sdkgen-package.json +1 -1
- package/src/cmp/Feature.ts +5 -0
- package/src/cmp/TestControl.ts +64 -0
- package/src/helpers/featureSource.ts +130 -0
- package/src/helpers/opShape.ts +9 -14
- package/src/helpers/pointPath.ts +88 -0
- package/src/sdkgen.ts +18 -0
- package/src/utility.ts +92 -1
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/Providers.ts +0 -1221
|
@@ -30,7 +30,11 @@ import {
|
|
|
30
30
|
cmp,
|
|
31
31
|
each,
|
|
32
32
|
isAuthActive,
|
|
33
|
-
|
|
33
|
+
serverVarEnv,
|
|
34
|
+
serverVariables,
|
|
35
|
+
entityDataIdField, envName, envToken,
|
|
36
|
+
jsKey,
|
|
37
|
+
jsProp
|
|
34
38
|
} from '@voxgig/sdkgen'
|
|
35
39
|
|
|
36
40
|
|
|
@@ -63,13 +67,32 @@ const TestEntity = cmp(function TestEntity(props: any) {
|
|
|
63
67
|
const ENTENVNAME = envToken(entity.name)
|
|
64
68
|
const authActive = isAuthActive(model)
|
|
65
69
|
const apikeyEnvEntry = authActive
|
|
66
|
-
? `\n '${PROJENVNAME}_APIKEY': '
|
|
70
|
+
? `\n '${PROJENVNAME}_APIKEY': '',`
|
|
67
71
|
: ''
|
|
68
72
|
const apikeyLiveField = authActive
|
|
69
73
|
? `
|
|
70
74
|
apikey: env.${PROJENVNAME}_APIKEY,`
|
|
71
75
|
: ''
|
|
72
76
|
|
|
77
|
+
// A templated server URL (OpenAPI server variables) makes a LIVE client
|
|
78
|
+
// impossible to construct without values: makeOptions raises rather than
|
|
79
|
+
// request a URL with a literal `{account_id}` in it. So the live suite
|
|
80
|
+
// takes them from the environment the same way it takes the apikey.
|
|
81
|
+
//
|
|
82
|
+
// Keys are quoted and the env read is bracketed via jsKey/jsProp: a server
|
|
83
|
+
// variable name is spec-derived and need not be a JS identifier — the URL
|
|
84
|
+
// grammar admits a leading digit ({2fa}), and a declared-but-unreferenced
|
|
85
|
+
// variable ({edge-zone}) is not constrained at all. Bare `name:` and
|
|
86
|
+
// `env.PROJ_SERVER_EDGE-ZONE` are both syntax errors.
|
|
87
|
+
const svars = serverVariables(model)
|
|
88
|
+
const serverEnvEntry = svars
|
|
89
|
+
.map((v: any) => `\n '${serverVarEnv(PROJENVNAME, v.name)}': ${JSON.stringify(v.dflt)},`).join('')
|
|
90
|
+
const serverLiveField = 0 === svars.length ? '' : `
|
|
91
|
+
server: {${svars
|
|
92
|
+
.map((v: any) => `
|
|
93
|
+
${jsKey(v.name)}: ${jsProp('env', serverVarEnv(PROJENVNAME, v.name))},`).join('')}
|
|
94
|
+
},`
|
|
95
|
+
|
|
73
96
|
// TODO: should be a utility function
|
|
74
97
|
const ff = projectPath('src/cmp/js/fragment/')
|
|
75
98
|
|
|
@@ -143,16 +166,23 @@ function basicSetup(extra) {
|
|
|
143
166
|
const env = envOverride({
|
|
144
167
|
'${PROJENVNAME}_TEST_${ENTENVNAME}_ENTID': idmap,
|
|
145
168
|
'${PROJENVNAME}_TEST_LIVE': 'FALSE',
|
|
146
|
-
'${PROJENVNAME}_TEST_EXPLAIN': 'FALSE',${apikeyEnvEntry}
|
|
169
|
+
'${PROJENVNAME}_TEST_EXPLAIN': 'FALSE',${apikeyEnvEntry}${serverEnvEntry}
|
|
147
170
|
})
|
|
148
171
|
|
|
149
172
|
idmap = env['${PROJENVNAME}_TEST_${ENTENVNAME}_ENTID']
|
|
150
173
|
|
|
151
174
|
if ('TRUE' === env.${PROJENVNAME}_TEST_LIVE) {
|
|
152
175
|
client = new ${model.Name}SDK(merge([
|
|
153
|
-
|
|
176
|
+
// FIRST, so the generated fields below win: sdk-test-control.json's
|
|
177
|
+
// test.client.options adds to the live client, it does not redirect it.
|
|
178
|
+
liveClientOptions(),
|
|
179
|
+
{${apikeyLiveField}${serverLiveField}
|
|
154
180
|
},
|
|
155
|
-
extra
|
|
181
|
+
// 'extra || {}', not a bare 'extra': struct.merge returns UNDEFINED when
|
|
182
|
+
// the last entry is undefined, and basicSetup is normally called with no
|
|
183
|
+
// argument at all - so a bare 'extra' silently discarded the apikey and
|
|
184
|
+
// server values above and handed the SDK undefined.
|
|
185
|
+
extra || {}
|
|
156
186
|
]))
|
|
157
187
|
}
|
|
158
188
|
|
|
@@ -3,7 +3,8 @@ import type {
|
|
|
3
3
|
ModelEntity
|
|
4
4
|
} from '@voxgig/apidef'
|
|
5
5
|
|
|
6
|
-
import { cmp, each, Folder, entityCollection
|
|
6
|
+
import { cmp, each, Folder, entityCollection,
|
|
7
|
+
TestControl } from '@voxgig/sdkgen'
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
import { TestDirect } from './TestDirect_js'
|
|
@@ -16,6 +17,9 @@ const Test = cmp(function Test(props: any) {
|
|
|
16
17
|
|
|
17
18
|
Folder({ name: 'test' }, () => {
|
|
18
19
|
|
|
20
|
+
// Write-once: a project's edited control file survives regeneration.
|
|
21
|
+
TestControl({ target, dir: 'test' })
|
|
22
|
+
|
|
19
23
|
Folder({ name: 'entity' }, () => {
|
|
20
24
|
const entity = each(entityCollection(model))
|
|
21
25
|
.filter((e: any) => false !== e.active)
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
const envlocal = __dirname + '/../../../.env.local'
|
|
3
3
|
require('dotenv').config({ quiet: true, path: [envlocal] })
|
|
4
4
|
|
|
5
|
-
const { test, describe } = require('node:test')
|
|
5
|
+
const { test, describe, afterEach } = require('node:test')
|
|
6
6
|
const assert = require('node:assert')
|
|
7
7
|
|
|
8
8
|
|
|
@@ -10,11 +10,17 @@ const { ProjectNameSDK } = require('../../..')
|
|
|
10
10
|
|
|
11
11
|
const {
|
|
12
12
|
envOverride,
|
|
13
|
+
liveClientOptions,
|
|
14
|
+
liveDelay,
|
|
13
15
|
} = require('../../utility')
|
|
14
16
|
|
|
15
17
|
|
|
16
18
|
describe('EntityNameDirect', async () => {
|
|
17
19
|
|
|
20
|
+
// Per-test live pacing. Delay is read from sdk-test-control.json's
|
|
21
|
+
// `test.live.delayMs`; only sleeps when PROJECTENV_TEST_LIVE=TRUE.
|
|
22
|
+
afterEach(liveDelay('PROJECTENV_TEST_LIVE'))
|
|
23
|
+
|
|
18
24
|
test('direct-exists', async () => {
|
|
19
25
|
const sdk = new ProjectNameSDK({
|
|
20
26
|
// Concrete base: a live construction must satisfy any server
|
|
@@ -5,7 +5,7 @@ require('dotenv').config({ quiet: true, path: [envlocal] })
|
|
|
5
5
|
const Path = require('node:path')
|
|
6
6
|
const Fs = require('node:fs')
|
|
7
7
|
|
|
8
|
-
const { test, describe } = require('node:test')
|
|
8
|
+
const { test, describe, afterEach } = require('node:test')
|
|
9
9
|
const assert = require('node:assert')
|
|
10
10
|
|
|
11
11
|
|
|
@@ -13,6 +13,8 @@ const { ProjectNameSDK, BaseFeature, stdutil, config } = require('../../..')
|
|
|
13
13
|
|
|
14
14
|
const {
|
|
15
15
|
envOverride,
|
|
16
|
+
liveClientOptions,
|
|
17
|
+
liveDelay,
|
|
16
18
|
makeCtrl,
|
|
17
19
|
makeMatch,
|
|
18
20
|
makeReqdata,
|
|
@@ -23,6 +25,10 @@ const {
|
|
|
23
25
|
|
|
24
26
|
describe('EntityNameEntity', async () => {
|
|
25
27
|
|
|
28
|
+
// Per-test live pacing. Delay is read from sdk-test-control.json's
|
|
29
|
+
// `test.live.delayMs`; only sleeps when PROJECTENV_TEST_LIVE=TRUE.
|
|
30
|
+
afterEach(liveDelay('PROJECTENV_TEST_LIVE'))
|
|
31
|
+
|
|
26
32
|
test('instance', async () => {
|
|
27
33
|
const testsdk = ProjectNameSDK.test()
|
|
28
34
|
const ent = testsdk.EntityName()
|
|
@@ -79,13 +79,13 @@ const Config = cmp(async function Config(props: any) {
|
|
|
79
79
|
options.headers = headers
|
|
80
80
|
options.entity = optionsEntity
|
|
81
81
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
82
|
+
// configDefinition's `def.entity` verbatim, NOT rebuilt here. This reduce
|
|
83
|
+
// was one of fourteen copies of that function's entityDefs loop, and when
|
|
84
|
+
// configDefinition started reconstructing a point's `parts` from apidef's
|
|
85
|
+
// segment vector (its ADR-003), only the copies that read `configDef` got
|
|
86
|
+
// it — this target's literal config emitted paths with no parts at all
|
|
87
|
+
// while its data config had them. One rule, one place.
|
|
88
|
+
const entityConfig = configDef.entity
|
|
89
89
|
|
|
90
90
|
const config = {
|
|
91
91
|
main: configDef.main,
|
|
@@ -4,6 +4,7 @@ import * as Path from 'node:path'
|
|
|
4
4
|
import {
|
|
5
5
|
cmp, each,
|
|
6
6
|
File, Copy, Folder, Fragment,
|
|
7
|
+
TEST_CONTROL_EXCLUDE
|
|
7
8
|
} from '@voxgig/sdkgen'
|
|
8
9
|
|
|
9
10
|
|
|
@@ -47,7 +48,7 @@ const Main = cmp(async function Main(props: any) {
|
|
|
47
48
|
// token used throughout the templates (package/import statements).
|
|
48
49
|
Copy({
|
|
49
50
|
from: 'tm/' + target.name,
|
|
50
|
-
exclude: [/src
|
|
51
|
+
exclude: [/src\//, TEST_CONTROL_EXCLUDE],
|
|
51
52
|
replace: {
|
|
52
53
|
...props.ctx$.stdrep,
|
|
53
54
|
KOTLINPACKAGE: kotlinpackage,
|
|
@@ -11,7 +11,8 @@ import {
|
|
|
11
11
|
File,
|
|
12
12
|
cmp,
|
|
13
13
|
snakify,
|
|
14
|
-
isAuthActive, envName, envToken
|
|
14
|
+
isAuthActive, envName, envToken,
|
|
15
|
+
pointParts,
|
|
15
16
|
} from '@voxgig/sdkgen'
|
|
16
17
|
|
|
17
18
|
|
|
@@ -84,10 +85,10 @@ const TestDirect = cmp(function TestDirect(props: any) {
|
|
|
84
85
|
const listOp = entity.op?.list
|
|
85
86
|
|
|
86
87
|
const loadPoint = loadOp?.points?.[0]
|
|
87
|
-
const loadPath = loadPoint ? normalizePathParams(loadPoint
|
|
88
|
+
const loadPath = loadPoint ? normalizePathParams(pointParts(loadPoint), loadPoint?.args?.params || [], loadPoint?.rename?.param) : ''
|
|
88
89
|
const allLoadParams = loadPoint?.args?.params || []
|
|
89
90
|
const _pathPlaceholders = new Set<string>()
|
|
90
|
-
for (const part of (loadPoint
|
|
91
|
+
for (const part of pointParts(loadPoint)) {
|
|
91
92
|
if (typeof part === 'string' && part.startsWith('{') && part.endsWith('}')) {
|
|
92
93
|
_pathPlaceholders.add(part.slice(1, -1))
|
|
93
94
|
}
|
|
@@ -104,7 +105,7 @@ const TestDirect = cmp(function TestDirect(props: any) {
|
|
|
104
105
|
_renamedPlaceholders.has(p.name) || _renamedPlaceholders.has(p.orig))
|
|
105
106
|
|
|
106
107
|
const listPoint = listOp?.points?.[0]
|
|
107
|
-
const listPath = listPoint ? normalizePathParams(listPoint
|
|
108
|
+
const listPath = listPoint ? normalizePathParams(pointParts(listPoint), listPoint?.args?.params || [], listPoint?.rename?.param) : ''
|
|
108
109
|
const listParams = listPoint?.args?.params || []
|
|
109
110
|
|
|
110
111
|
const loadQuery = loadPoint?.args?.query || []
|
|
@@ -3,7 +3,8 @@ import type {
|
|
|
3
3
|
ModelEntity
|
|
4
4
|
} from '@voxgig/apidef'
|
|
5
5
|
|
|
6
|
-
import { cmp, each, Folder, entityCollection
|
|
6
|
+
import { cmp, each, Folder, entityCollection,
|
|
7
|
+
TestControl } from '@voxgig/sdkgen'
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
import { TestEntity } from './TestEntity_kotlin'
|
|
@@ -20,6 +21,9 @@ const Test = cmp(function Test(props: any) {
|
|
|
20
21
|
|
|
21
22
|
Folder({ name: 'test' }, () => {
|
|
22
23
|
|
|
24
|
+
// Write-once: a project's edited control file survives regeneration.
|
|
25
|
+
TestControl({ target, dir: 'test' })
|
|
26
|
+
|
|
23
27
|
// The shared test infrastructure (RunnerSupport, FeatureHarness,
|
|
24
28
|
// PipelineTest, FeatureTest, NetsimTest, PrimaryUtilityTest,
|
|
25
29
|
// CustomUtilityTest, StructRunner/StructCorpusTest, ExistsTest and
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
isAuthActive,
|
|
7
7
|
resolveAuthPrefix,
|
|
8
8
|
targetFeatures,
|
|
9
|
+
configDefinition,
|
|
9
10
|
} from '@voxgig/sdkgen'
|
|
10
11
|
|
|
11
12
|
import {
|
|
@@ -15,7 +16,6 @@ import {
|
|
|
15
16
|
} from '@voxgig/apidef'
|
|
16
17
|
|
|
17
18
|
import {
|
|
18
|
-
clean,
|
|
19
19
|
leanString,
|
|
20
20
|
} from './utility_lean'
|
|
21
21
|
|
|
@@ -30,6 +30,7 @@ const Config = cmp(async function Config(props: any) {
|
|
|
30
30
|
const model: Model = ctx$.model
|
|
31
31
|
|
|
32
32
|
const entity = getModelPath(model, `main.${KIT}.entity`)
|
|
33
|
+
const { def: configDef } = configDefinition(model, target.name)
|
|
33
34
|
// Gated by the applicability tags, so this target never imports or
|
|
34
35
|
// registers a feature it has no source for. One rule, one place:
|
|
35
36
|
// helpers/applicability.
|
|
@@ -57,13 +58,13 @@ const Config = cmp(async function Config(props: any) {
|
|
|
57
58
|
options.auth = { prefix: authPrefix }
|
|
58
59
|
}
|
|
59
60
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
61
|
+
// configDefinition's `def.entity` verbatim, NOT rebuilt here. This reduce
|
|
62
|
+
// was one of fourteen copies of that function's entityDefs loop, and when
|
|
63
|
+
// configDefinition started reconstructing a point's `parts` from apidef's
|
|
64
|
+
// segment vector (its ADR-003), only the copies that read `configDef` got
|
|
65
|
+
// it — this target's literal config emitted paths with no parts at all
|
|
66
|
+
// while its data config had them. One rule, one place.
|
|
67
|
+
const entityConfig = configDef.entity
|
|
67
68
|
|
|
68
69
|
const config = {
|
|
69
70
|
main: { name: model.const.Name },
|
|
@@ -28,7 +28,6 @@ import {
|
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
import {
|
|
31
|
-
clean,
|
|
32
31
|
formatLuaTable,
|
|
33
32
|
luaLongString,
|
|
34
33
|
} from './utility_lua'
|
|
@@ -160,12 +159,7 @@ ${serverBlock}${authBlock} headers = ${formatLuaTable(headers, 3)},
|
|
|
160
159
|
Content(` },
|
|
161
160
|
},
|
|
162
161
|
entity = ${formatLuaTable(
|
|
163
|
-
|
|
164
|
-
fields: n.fields,
|
|
165
|
-
name: n.name,
|
|
166
|
-
op: n.op,
|
|
167
|
-
relations: n.relations,
|
|
168
|
-
}, true), a), {}), 2)},
|
|
162
|
+
configDef.entity, 2)},
|
|
169
163
|
}
|
|
170
164
|
end
|
|
171
165
|
`)
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
cmp, each, names, cmap,
|
|
6
6
|
List, File, Content, Copy, Folder, Fragment, Line, FeatureHook,
|
|
7
7
|
targetFeatures,
|
|
8
|
+
TEST_CONTROL_EXCLUDE
|
|
8
9
|
} from '@voxgig/sdkgen'
|
|
9
10
|
|
|
10
11
|
|
|
@@ -44,7 +45,7 @@ const Main = cmp(async function Main(props: any) {
|
|
|
44
45
|
// Copy tm/lua files with replacements
|
|
45
46
|
Copy({
|
|
46
47
|
from: 'tm/' + target.name,
|
|
47
|
-
exclude: [/src
|
|
48
|
+
exclude: [/src\//, TEST_CONTROL_EXCLUDE],
|
|
48
49
|
replace: {
|
|
49
50
|
...props.ctx$.stdrep,
|
|
50
51
|
}
|
|
@@ -11,9 +11,14 @@ import {
|
|
|
11
11
|
File,
|
|
12
12
|
cmp,
|
|
13
13
|
snakify,
|
|
14
|
-
isAuthActive, envName, envToken
|
|
14
|
+
isAuthActive, envName, envToken,
|
|
15
|
+
serverVarEnv,
|
|
16
|
+
serverVariables,
|
|
17
|
+
pointParts,
|
|
15
18
|
} from '@voxgig/sdkgen'
|
|
16
19
|
|
|
20
|
+
import { formatLuaValue } from './utility_lua'
|
|
21
|
+
|
|
17
22
|
|
|
18
23
|
function normalizePathParams(
|
|
19
24
|
parts: string[],
|
|
@@ -64,12 +69,25 @@ const TestDirect = cmp(function TestDirect(props: any) {
|
|
|
64
69
|
|
|
65
70
|
const authActive = isAuthActive(model)
|
|
66
71
|
const apikeyEnvEntry = authActive
|
|
67
|
-
? `\n ["${PROJECTNAME}_APIKEY"] = "
|
|
72
|
+
? `\n ["${PROJECTNAME}_APIKEY"] = "",`
|
|
68
73
|
: ''
|
|
69
74
|
const apikeyLiveField = authActive
|
|
70
75
|
? `\n apikey = env["${PROJECTNAME}_APIKEY"],`
|
|
71
76
|
: ''
|
|
72
77
|
|
|
78
|
+
// A templated server URL (OpenAPI server variables) makes a LIVE client
|
|
79
|
+
// impossible to construct without values: makeOptions raises rather than
|
|
80
|
+
// request a URL with a literal `{account_id}` in it. So the live suite
|
|
81
|
+
// takes them from the environment the same way it takes the apikey.
|
|
82
|
+
const svars = serverVariables(model)
|
|
83
|
+
const serverEnvEntry = svars
|
|
84
|
+
.map((v: any) => `\n ["${serverVarEnv(PROJECTNAME, v.name)}"] = ${formatLuaValue(v.dflt)},`).join('')
|
|
85
|
+
const serverLiveField = 0 === svars.length ? '' : `
|
|
86
|
+
server = {${svars
|
|
87
|
+
.map((v: any) => `
|
|
88
|
+
["${v.name}"] = env["${serverVarEnv(PROJECTNAME, v.name)}"],`).join('')}
|
|
89
|
+
},`
|
|
90
|
+
|
|
73
91
|
const opnames = Object.keys(entity.op || {})
|
|
74
92
|
const hasLoad = opnames.includes('load')
|
|
75
93
|
const hasList = opnames.includes('list')
|
|
@@ -82,7 +100,7 @@ const TestDirect = cmp(function TestDirect(props: any) {
|
|
|
82
100
|
const listOp = entity.op?.list
|
|
83
101
|
|
|
84
102
|
const loadPoint = loadOp?.points?.[0]
|
|
85
|
-
const loadPath = loadPoint ? normalizePathParams(loadPoint
|
|
103
|
+
const loadPath = loadPoint ? normalizePathParams(pointParts(loadPoint), loadPoint?.args?.params || [], loadPoint?.rename?.param) : ''
|
|
86
104
|
const allLoadParams = loadPoint?.args?.params || []
|
|
87
105
|
// Some upstream OpenAPI specs declare a parameter as `in: path` even when
|
|
88
106
|
// that path has no `{name}` placeholder for it. Only path params that
|
|
@@ -90,7 +108,7 @@ const TestDirect = cmp(function TestDirect(props: any) {
|
|
|
90
108
|
// setup and URL-substitution asserts; otherwise the SDK silently drops
|
|
91
109
|
// them and the URL-includes assert fails.
|
|
92
110
|
const _pathPlaceholders = new Set<string>()
|
|
93
|
-
for (const part of (loadPoint
|
|
111
|
+
for (const part of pointParts(loadPoint)) {
|
|
94
112
|
if (typeof part === 'string' && part.startsWith('{') && part.endsWith('}')) {
|
|
95
113
|
_pathPlaceholders.add(part.slice(1, -1))
|
|
96
114
|
}
|
|
@@ -107,7 +125,7 @@ const TestDirect = cmp(function TestDirect(props: any) {
|
|
|
107
125
|
_renamedPlaceholders.has(p.name) || _renamedPlaceholders.has(p.orig))
|
|
108
126
|
|
|
109
127
|
const listPoint = listOp?.points?.[0]
|
|
110
|
-
const listPath = listPoint ? normalizePathParams(listPoint
|
|
128
|
+
const listPath = listPoint ? normalizePathParams(pointParts(listPoint), listPoint?.args?.params || [], listPoint?.rename?.param) : ''
|
|
111
129
|
const listParams = listPoint?.args?.params || []
|
|
112
130
|
|
|
113
131
|
// Required query params with spec-provided examples — needed in live mode.
|
|
@@ -350,14 +368,21 @@ function ${entity.name}_direct_setup(mockres)
|
|
|
350
368
|
|
|
351
369
|
local env = runner.env_override({
|
|
352
370
|
["${entidEnvVar}"] = {},
|
|
353
|
-
["${PROJECTNAME}_TEST_LIVE"] = "FALSE",${apikeyEnvEntry}
|
|
371
|
+
["${PROJECTNAME}_TEST_LIVE"] = "FALSE",${apikeyEnvEntry}${serverEnvEntry}
|
|
354
372
|
})
|
|
355
373
|
|
|
356
374
|
local live = env["${PROJECTNAME}_TEST_LIVE"] == "TRUE"
|
|
357
375
|
|
|
358
376
|
if live then
|
|
359
|
-
local merged_opts = {${apikeyLiveField}
|
|
377
|
+
local merged_opts = {${apikeyLiveField}${serverLiveField}
|
|
360
378
|
}
|
|
379
|
+
-- sdk-test-control.json's test.client.options goes UNDER the generated
|
|
380
|
+
-- fields: it adds to the live client, it does not redirect it.
|
|
381
|
+
for _k, _v in pairs(runner.live_client_options()) do
|
|
382
|
+
if merged_opts[_k] == nil then
|
|
383
|
+
merged_opts[_k] = _v
|
|
384
|
+
end
|
|
385
|
+
end
|
|
361
386
|
local client = sdk.new(merged_opts)
|
|
362
387
|
return {
|
|
363
388
|
client = client,
|
|
@@ -24,9 +24,13 @@ import {
|
|
|
24
24
|
buildIdNames,
|
|
25
25
|
getMatchEntries,
|
|
26
26
|
isAuthActive,
|
|
27
|
-
entityDataIdField, envName, envToken
|
|
27
|
+
entityDataIdField, envName, envToken,
|
|
28
|
+
serverVarEnv,
|
|
29
|
+
serverVariables
|
|
28
30
|
} from '@voxgig/sdkgen'
|
|
29
31
|
|
|
32
|
+
import { formatLuaValue } from './utility_lua'
|
|
33
|
+
|
|
30
34
|
|
|
31
35
|
// See TestEntity_ts.ts for the GenCtx/OpGen contract.
|
|
32
36
|
type GenCtx = {
|
|
@@ -62,12 +66,25 @@ const TestEntity = cmp(function TestEntity(props: any) {
|
|
|
62
66
|
|
|
63
67
|
const authActive = isAuthActive(model)
|
|
64
68
|
const apikeyEnvEntry = authActive
|
|
65
|
-
? `\n ["${PROJUPPER}_APIKEY"] = "
|
|
69
|
+
? `\n ["${PROJUPPER}_APIKEY"] = "",`
|
|
66
70
|
: ''
|
|
67
71
|
const apikeyLiveField = authActive
|
|
68
72
|
? `\n apikey = env["${PROJUPPER}_APIKEY"],`
|
|
69
73
|
: ''
|
|
70
74
|
|
|
75
|
+
// A templated server URL (OpenAPI server variables) makes a LIVE client
|
|
76
|
+
// impossible to construct without values: makeOptions raises rather than
|
|
77
|
+
// request a URL with a literal `{account_id}` in it. So the live suite
|
|
78
|
+
// takes them from the environment the same way it takes the apikey.
|
|
79
|
+
const svars = serverVariables(model)
|
|
80
|
+
const serverEnvEntry = svars
|
|
81
|
+
.map((v: any) => `\n ["${serverVarEnv(PROJUPPER, v.name)}"] = ${formatLuaValue(v.dflt)},`).join('')
|
|
82
|
+
const serverLiveField = 0 === svars.length ? '' : `
|
|
83
|
+
server = {${svars
|
|
84
|
+
.map((v: any) => `
|
|
85
|
+
["${v.name}"] = env["${serverVarEnv(PROJUPPER, v.name)}"],`).join('')}
|
|
86
|
+
},`
|
|
87
|
+
|
|
71
88
|
const idnames = buildIdNames(entity, basicflow)
|
|
72
89
|
const idnamesStr = idnames.map(n => `"${n}"`).join(', ')
|
|
73
90
|
|
|
@@ -241,7 +258,7 @@ end)
|
|
|
241
258
|
local env = runner.env_override({
|
|
242
259
|
["${PROJUPPER}_TEST_${envToken(entity.name)}_ENTID"] = idmap,
|
|
243
260
|
["${PROJUPPER}_TEST_LIVE"] = "FALSE",
|
|
244
|
-
["${PROJUPPER}_TEST_EXPLAIN"] = "FALSE",${apikeyEnvEntry}
|
|
261
|
+
["${PROJUPPER}_TEST_EXPLAIN"] = "FALSE",${apikeyEnvEntry}${serverEnvEntry}
|
|
245
262
|
})
|
|
246
263
|
|
|
247
264
|
local idmap_resolved = helpers.to_map(
|
|
@@ -262,7 +279,10 @@ end)
|
|
|
262
279
|
Content(`
|
|
263
280
|
if env["${PROJUPPER}_TEST_LIVE"] == "TRUE" then
|
|
264
281
|
local merged_opts = vs.merge({
|
|
265
|
-
|
|
282
|
+
-- FIRST, so the generated fields below win: sdk-test-control.json's
|
|
283
|
+
-- test.client.options adds to the live client, it does not redirect it.
|
|
284
|
+
runner.live_client_options(),
|
|
285
|
+
{${apikeyLiveField}${serverLiveField}
|
|
266
286
|
},
|
|
267
287
|
extra or {},
|
|
268
288
|
})
|
|
@@ -3,7 +3,8 @@ import type {
|
|
|
3
3
|
ModelEntity
|
|
4
4
|
} from '@voxgig/apidef'
|
|
5
5
|
|
|
6
|
-
import { cmp, each, Folder, File, Content, entityCollection
|
|
6
|
+
import { cmp, each, Folder, File, Content, entityCollection,
|
|
7
|
+
TestControl } from '@voxgig/sdkgen'
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
import { TestEntity } from './TestEntity_lua'
|
|
@@ -17,6 +18,9 @@ const Test = cmp(function Test(props: any) {
|
|
|
17
18
|
|
|
18
19
|
Folder({ name: 'test' }, () => {
|
|
19
20
|
|
|
21
|
+
// Write-once: a project's edited control file survives regeneration.
|
|
22
|
+
TestControl({ target, dir: 'test' })
|
|
23
|
+
|
|
20
24
|
// Generate exists test
|
|
21
25
|
File({ name: 'exists_test.' + target.ext }, () => {
|
|
22
26
|
Content(`-- ${model.const.Name} SDK exists test
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
cmp, each, names,
|
|
6
6
|
File, Content, Copy, Folder, Fragment,
|
|
7
7
|
targetFeatures,
|
|
8
|
+
TEST_CONTROL_EXCLUDE
|
|
8
9
|
} from '@voxgig/sdkgen'
|
|
9
10
|
|
|
10
11
|
|
|
@@ -49,7 +50,7 @@ const Main = cmp(async function Main(props: any) {
|
|
|
49
50
|
// Copy tm/perl files with replacements
|
|
50
51
|
Copy({
|
|
51
52
|
from: 'tm/' + target.name,
|
|
52
|
-
exclude: [/src
|
|
53
|
+
exclude: [/src\//, TEST_CONTROL_EXCLUDE],
|
|
53
54
|
replace: {
|
|
54
55
|
...props.ctx$.stdrep,
|
|
55
56
|
}
|
|
@@ -11,9 +11,14 @@ import {
|
|
|
11
11
|
File,
|
|
12
12
|
cmp,
|
|
13
13
|
snakify,
|
|
14
|
-
isAuthActive, envName, envToken
|
|
14
|
+
isAuthActive, envName, envToken,
|
|
15
|
+
serverVarEnv,
|
|
16
|
+
serverVariables,
|
|
17
|
+
pointParts,
|
|
15
18
|
} from '@voxgig/sdkgen'
|
|
16
19
|
|
|
20
|
+
import { perlStringLiteral } from './utility_perl'
|
|
21
|
+
|
|
17
22
|
|
|
18
23
|
function normalizePathParams(
|
|
19
24
|
parts: string[],
|
|
@@ -74,12 +79,25 @@ const TestDirect = cmp(function TestDirect(props: any) {
|
|
|
74
79
|
|
|
75
80
|
const authActive = isAuthActive(model)
|
|
76
81
|
const apikeyEnvEntry = authActive
|
|
77
|
-
? `\n '${PROJECTNAME}_APIKEY' => '
|
|
82
|
+
? `\n '${PROJECTNAME}_APIKEY' => '',`
|
|
78
83
|
: ''
|
|
79
84
|
const apikeyLiveField = authActive
|
|
80
85
|
? `\n 'apikey' => $env->{'${PROJECTNAME}_APIKEY'},`
|
|
81
86
|
: ''
|
|
82
87
|
|
|
88
|
+
// A templated server URL (OpenAPI server variables) makes a LIVE client
|
|
89
|
+
// impossible to construct without values: makeOptions raises rather than
|
|
90
|
+
// request a URL with a literal `{account_id}` in it. So the live suite
|
|
91
|
+
// takes them from the environment the same way it takes the apikey.
|
|
92
|
+
const svars = serverVariables(model)
|
|
93
|
+
const serverEnvEntry = svars
|
|
94
|
+
.map((v: any) => `\n '${serverVarEnv(PROJECTNAME, v.name)}' => ${perlStringLiteral(v.dflt)},`).join('')
|
|
95
|
+
const serverLiveField = 0 === svars.length ? '' : `
|
|
96
|
+
'server' => {${svars
|
|
97
|
+
.map((v: any) => `
|
|
98
|
+
'${v.name}' => $env->{'${serverVarEnv(PROJECTNAME, v.name)}'},`).join('')}
|
|
99
|
+
},`
|
|
100
|
+
|
|
83
101
|
const opnames = Object.keys(entity.op || {})
|
|
84
102
|
const hasLoad = opnames.includes('load')
|
|
85
103
|
const hasList = opnames.includes('list')
|
|
@@ -92,12 +110,12 @@ const TestDirect = cmp(function TestDirect(props: any) {
|
|
|
92
110
|
const listOp = entity.op?.list
|
|
93
111
|
|
|
94
112
|
const loadPoint = loadOp?.points?.[0]
|
|
95
|
-
const loadPath = loadPoint ? normalizePathParams(loadPoint
|
|
113
|
+
const loadPath = loadPoint ? normalizePathParams(pointParts(loadPoint), loadPoint?.args?.params || [], loadPoint?.rename?.param) : ''
|
|
96
114
|
const allLoadParams = loadPoint?.args?.params || []
|
|
97
115
|
// Only path params that actually appear in the URL template drive direct-
|
|
98
116
|
// test path-param setup and URL-substitution asserts (see TestDirect_rb).
|
|
99
117
|
const _pathPlaceholders = new Set<string>()
|
|
100
|
-
for (const part of (loadPoint
|
|
118
|
+
for (const part of pointParts(loadPoint)) {
|
|
101
119
|
if (typeof part === 'string' && part.startsWith('{') && part.endsWith('}')) {
|
|
102
120
|
_pathPlaceholders.add(part.slice(1, -1))
|
|
103
121
|
}
|
|
@@ -114,7 +132,7 @@ const TestDirect = cmp(function TestDirect(props: any) {
|
|
|
114
132
|
_renamedPlaceholders.has(p.name) || _renamedPlaceholders.has(p.orig))
|
|
115
133
|
|
|
116
134
|
const listPoint = listOp?.points?.[0]
|
|
117
|
-
const listPath = listPoint ? normalizePathParams(listPoint
|
|
135
|
+
const listPath = listPoint ? normalizePathParams(pointParts(listPoint), listPoint?.args?.params || [], listPoint?.rename?.param) : ''
|
|
118
136
|
const listParams = listPoint?.args?.params || []
|
|
119
137
|
|
|
120
138
|
// Required query params with spec-provided examples - needed in live mode.
|
|
@@ -377,13 +395,17 @@ sub ${entity.name}_direct_setup {
|
|
|
377
395
|
|
|
378
396
|
my $env = ${N}TestRunner::env_override({
|
|
379
397
|
'${entidEnvVar}' => {},
|
|
380
|
-
'${PROJECTNAME}_TEST_LIVE' => 'FALSE',${apikeyEnvEntry}
|
|
398
|
+
'${PROJECTNAME}_TEST_LIVE' => 'FALSE',${apikeyEnvEntry}${serverEnvEntry}
|
|
381
399
|
});
|
|
382
400
|
|
|
383
401
|
my $live = ((($env->{'${PROJECTNAME}_TEST_LIVE'}) || '') eq 'TRUE') ? 1 : 0;
|
|
384
402
|
|
|
385
403
|
if ($live) {
|
|
386
|
-
|
|
404
|
+
# live_client_options() FIRST so the generated fields below win:
|
|
405
|
+
# sdk-test-control.json's test.client.options adds to the live client,
|
|
406
|
+
# it does not redirect it (a later key wins in a Perl hash literal).
|
|
407
|
+
my $client = ${N}SDK->new({
|
|
408
|
+
%{ ${N}TestRunner::live_client_options() },${apikeyLiveField}${serverLiveField}
|
|
387
409
|
});
|
|
388
410
|
return {
|
|
389
411
|
'client' => $client,
|