@voxgig/sdkgen 0.40.1 → 0.40.2
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/helpers/buildIdNames.d.ts +11 -0
- package/dist/helpers/buildIdNames.js +56 -0
- package/dist/helpers/buildIdNames.js.map +1 -0
- package/dist/helpers/collectDeps.d.ts +9 -0
- package/dist/helpers/collectDeps.js +50 -0
- package/dist/helpers/collectDeps.js.map +1 -0
- package/dist/helpers/getMatchEntries.d.ts +2 -0
- package/dist/helpers/getMatchEntries.js +13 -0
- package/dist/helpers/getMatchEntries.js.map +1 -0
- package/dist/sdkgen.d.ts +6 -2
- package/dist/sdkgen.js +7 -1
- package/dist/sdkgen.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/project/.sdk/model/target/lua.jsonic +1 -1
- package/project/.sdk/model/target/php.jsonic +2 -3
- package/project/.sdk/model/target/py.jsonic +1 -1
- package/project/.sdk/src/cmp/go/Entity_go.ts +15 -3
- package/project/.sdk/src/cmp/go/Main_go.ts +3 -2
- package/project/.sdk/src/cmp/go/Package_go.ts +8 -29
- package/project/.sdk/src/cmp/go/TestDirect_go.ts +14 -7
- package/project/.sdk/src/cmp/go/TestEntity_go.ts +43 -30
- package/project/.sdk/src/cmp/js/TestDirect_js.ts +6 -3
- package/project/.sdk/src/cmp/lua/Package_lua.ts +5 -27
- package/project/.sdk/src/cmp/lua/TestDirect_lua.ts +6 -3
- package/project/.sdk/src/cmp/lua/TestEntity_lua.ts +5 -17
- package/project/.sdk/src/cmp/php/Config_php.ts +21 -0
- package/project/.sdk/src/cmp/php/MainEntity_php.ts +11 -1
- package/project/.sdk/src/cmp/php/Package_php.ts +5 -31
- package/project/.sdk/src/cmp/php/TestDirect_php.ts +6 -3
- package/project/.sdk/src/cmp/php/TestEntity_php.ts +25 -29
- package/project/.sdk/src/cmp/py/Main_py.ts +5 -5
- package/project/.sdk/src/cmp/py/Package_py.ts +11 -28
- package/project/.sdk/src/cmp/py/TestDirect_py.ts +9 -6
- package/project/.sdk/src/cmp/py/TestEntity_py.ts +7 -19
- package/project/.sdk/src/cmp/rb/Package_rb.ts +8 -47
- package/project/.sdk/src/cmp/rb/TestDirect_rb.ts +6 -3
- package/project/.sdk/src/cmp/rb/TestEntity_rb.ts +5 -17
- package/project/.sdk/src/cmp/ts/TestDirect_ts.ts +6 -3
- package/project/.sdk/tm/go/core/helpers.go +10 -0
- package/project/.sdk/tm/lua/Makefile +1 -1
- package/project/.sdk/tm/php/Makefile +1 -1
- package/src/helpers/buildIdNames.ts +70 -0
- package/src/helpers/collectDeps.ts +70 -0
- package/src/helpers/getMatchEntries.ts +14 -0
- package/src/sdkgen.ts +10 -0
|
@@ -3,14 +3,12 @@ import {
|
|
|
3
3
|
Content,
|
|
4
4
|
File,
|
|
5
5
|
cmp,
|
|
6
|
-
|
|
6
|
+
collectDeps,
|
|
7
7
|
} from '@voxgig/sdkgen'
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
import {
|
|
11
|
-
KIT,
|
|
10
|
+
import type {
|
|
12
11
|
Model,
|
|
13
|
-
getModelPath,
|
|
14
12
|
} from '@voxgig/apidef'
|
|
15
13
|
|
|
16
14
|
|
|
@@ -20,7 +18,8 @@ const Package = cmp(async function Package(props: any) {
|
|
|
20
18
|
|
|
21
19
|
const model: Model = ctx$.model
|
|
22
20
|
|
|
23
|
-
const
|
|
21
|
+
const versionOf = (d: { version: string; source: 'feature' | 'target' }) =>
|
|
22
|
+
d.source === 'target' ? (d.version || '0.0') : d.version
|
|
24
23
|
|
|
25
24
|
// Generate Gemfile
|
|
26
25
|
File({ name: 'Gemfile' }, () => {
|
|
@@ -30,28 +29,9 @@ gemspec
|
|
|
30
29
|
|
|
31
30
|
`)
|
|
32
31
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const rbDeps = f.deps?.rb
|
|
36
|
-
if (rbDeps) {
|
|
37
|
-
each(rbDeps, (dep: any) => {
|
|
38
|
-
if (dep.active) {
|
|
39
|
-
Content(`gem "${dep.key$}", "~> ${dep.version}"
|
|
40
|
-
`)
|
|
41
|
-
}
|
|
42
|
-
})
|
|
43
|
-
}
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
// Add target-level deps
|
|
47
|
-
const targetDeps = target.deps
|
|
48
|
-
if (targetDeps) {
|
|
49
|
-
each(targetDeps, (dep: any) => {
|
|
50
|
-
if (dep.active !== false) {
|
|
51
|
-
Content(`gem "${dep.key$}", "~> ${dep.version || '0.0'}"
|
|
32
|
+
for (const d of collectDeps(model, target.name, target.deps)) {
|
|
33
|
+
Content(`gem "${d.name}", "~> ${versionOf(d)}"
|
|
52
34
|
`)
|
|
53
|
-
}
|
|
54
|
-
})
|
|
55
35
|
}
|
|
56
36
|
})
|
|
57
37
|
|
|
@@ -73,28 +53,9 @@ gemspec
|
|
|
73
53
|
spec.add_dependency "json"
|
|
74
54
|
`)
|
|
75
55
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
const rbDeps = f.deps?.rb
|
|
79
|
-
if (rbDeps) {
|
|
80
|
-
each(rbDeps, (dep: any) => {
|
|
81
|
-
if (dep.active) {
|
|
82
|
-
Content(` spec.add_dependency "${dep.key$}", "~> ${dep.version}"
|
|
83
|
-
`)
|
|
84
|
-
}
|
|
85
|
-
})
|
|
86
|
-
}
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
// Add target-level deps
|
|
90
|
-
const targetDeps = target.deps
|
|
91
|
-
if (targetDeps) {
|
|
92
|
-
each(targetDeps, (dep: any) => {
|
|
93
|
-
if (dep.active !== false) {
|
|
94
|
-
Content(` spec.add_dependency "${dep.key$}", "~> ${dep.version || '0.0'}"
|
|
56
|
+
for (const d of collectDeps(model, target.name, target.deps)) {
|
|
57
|
+
Content(` spec.add_dependency "${d.name}", "~> ${versionOf(d)}"
|
|
95
58
|
`)
|
|
96
|
-
}
|
|
97
|
-
})
|
|
98
59
|
}
|
|
99
60
|
|
|
100
61
|
Content(`
|
|
@@ -20,10 +20,13 @@ function normalizePathParams(
|
|
|
20
20
|
return part.replace(/\{([^}]+)\}/g, (match: string, rawName: string) => {
|
|
21
21
|
const snaked = snakify(rawName)
|
|
22
22
|
const depluralized = depluralize(snaked)
|
|
23
|
+
// Prefer exact name match — orig matches can collide when one param's
|
|
24
|
+
// original name was renamed to another param's current name (e.g. badge
|
|
25
|
+
// load: param 'group_id' has orig 'id', and another param has name 'id').
|
|
23
26
|
const param = params.find((p: any) =>
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
+
p.name === snaked || p.name === depluralized) ||
|
|
28
|
+
params.find((p: any) =>
|
|
29
|
+
p.orig === snaked || p.orig === depluralized)
|
|
27
30
|
if (param) return '{' + param.name + '}'
|
|
28
31
|
|
|
29
32
|
if (rename) {
|
|
@@ -16,6 +16,8 @@ import {
|
|
|
16
16
|
File,
|
|
17
17
|
cmp,
|
|
18
18
|
each,
|
|
19
|
+
buildIdNames,
|
|
20
|
+
getMatchEntries,
|
|
19
21
|
} from '@voxgig/sdkgen'
|
|
20
22
|
|
|
21
23
|
|
|
@@ -45,15 +47,7 @@ const TestEntity = cmp(function TestEntity(props: any) {
|
|
|
45
47
|
|
|
46
48
|
const PROJUPPER = model.const.Name.toUpperCase().replace(/[^A-Z_]/g, '_')
|
|
47
49
|
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
// Build idmap names
|
|
51
|
-
const idnames: string[] = []
|
|
52
|
-
for (let i = 1; i <= 3; i++) idnames.push(`${entity.name}0${i}`)
|
|
53
|
-
for (const anc of ancestors) {
|
|
54
|
-
for (let i = 1; i <= 3; i++) idnames.push(`${anc}0${i}`)
|
|
55
|
-
}
|
|
56
|
-
|
|
50
|
+
const idnames = buildIdNames(entity, basicflow)
|
|
57
51
|
const idnamesStr = idnames.map(n => `"${n}"`).join(', ')
|
|
58
52
|
|
|
59
53
|
const allSteps = Object.values(basicflow.step) as any[]
|
|
@@ -92,7 +86,7 @@ class ${entity.Name}EntityTest < Minitest::Test
|
|
|
92
86
|
if (!flowHasCreate) {
|
|
93
87
|
Content(` # Bootstrap entity data from existing test data.
|
|
94
88
|
${entity.name}_ref01_data_raw = Vs.items(Helpers.to_map(
|
|
95
|
-
Vs.
|
|
89
|
+
Vs.getpath(setup[:data], "existing.${entity.name}")))
|
|
96
90
|
${entity.name}_ref01_data = nil
|
|
97
91
|
if ${entity.name}_ref01_data_raw.length > 0
|
|
98
92
|
${entity.name}_ref01_data = Helpers.to_map(${entity.name}_ref01_data_raw[0][1])
|
|
@@ -191,12 +185,6 @@ end
|
|
|
191
185
|
})
|
|
192
186
|
|
|
193
187
|
|
|
194
|
-
function getMatchEntries(step: any): [string, any][] {
|
|
195
|
-
if (!step?.match) return []
|
|
196
|
-
return Object.entries(step.match).filter(([k]: any) => !k.endsWith('$'))
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
|
|
200
188
|
const generateCreate: OpGen = (ctx, step, index) => {
|
|
201
189
|
const { entity, flow } = ctx
|
|
202
190
|
const ref = step.input?.ref ?? entity.name + '_ref01'
|
|
@@ -417,7 +405,7 @@ const generateLoad: OpGen = (ctx, step, index) => {
|
|
|
417
405
|
}
|
|
418
406
|
if (!hasSrcData) {
|
|
419
407
|
Content(` ${srcdatavar}_raw = Vs.items(Helpers.to_map(
|
|
420
|
-
Vs.
|
|
408
|
+
Vs.getpath(setup[:data], "existing.${entity.name}")))
|
|
421
409
|
${srcdatavar} = nil
|
|
422
410
|
if ${srcdatavar}_raw.length > 0
|
|
423
411
|
${srcdatavar} = Helpers.to_map(${srcdatavar}_raw[0][1])
|
|
@@ -302,10 +302,13 @@ function normalizePathParams(
|
|
|
302
302
|
return part.replace(/\{([^}]+)\}/g, (match: string, rawName: string) => {
|
|
303
303
|
const snaked = snakify(rawName)
|
|
304
304
|
const depluralized = depluralize(snaked)
|
|
305
|
+
// Prefer exact name match — orig matches can collide when one param's
|
|
306
|
+
// original name was renamed to another param's current name (e.g. badge
|
|
307
|
+
// load: param 'group_id' has orig 'id', and another param has name 'id').
|
|
305
308
|
const param = params.find((p: any) =>
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
+
p.name === snaked || p.name === depluralized) ||
|
|
310
|
+
params.find((p: any) =>
|
|
311
|
+
p.orig === snaked || p.orig === depluralized)
|
|
309
312
|
if (param) return '{' + param.name + '}'
|
|
310
313
|
|
|
311
314
|
// Reverse-lookup through rename mapping: if rawName is a renamed value
|
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
package core
|
|
2
2
|
|
|
3
|
+
import "fmt"
|
|
4
|
+
|
|
5
|
+
// UnsupportedOp is returned by entity stub methods for operations the
|
|
6
|
+
// underlying API spec doesn't define. The static ProjectNameEntity interface
|
|
7
|
+
// requires every CRUD method on every entity, so absent ops must still be
|
|
8
|
+
// callable — they error at runtime instead of failing to compile.
|
|
9
|
+
func UnsupportedOp(opname, entityname string) (any, error) {
|
|
10
|
+
return nil, fmt.Errorf("operation '%s' not supported by entity '%s'", opname, entityname)
|
|
11
|
+
}
|
|
12
|
+
|
|
3
13
|
func ToMapAny(v any) map[string]any {
|
|
4
14
|
if v == nil {
|
|
5
15
|
return nil
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// Build the list of placeholder ID names that the test setup populates into
|
|
2
|
+
// `setup.idmap`. The set is the union of:
|
|
3
|
+
// - the entity's own ids (`<entity>01..03`)
|
|
4
|
+
// - every ancestor entity's ids (`<anc>01..03`)
|
|
5
|
+
// - every literal string value referenced by `step.match` across the flow
|
|
6
|
+
// (e.g. path-parameter aliases like `year01` for `/{year}/domain` — apidef
|
|
7
|
+
// doesn't always populate `relations.ancestors` when the parent in the
|
|
8
|
+
// path is a bare parameter rather than an entity, so we have to mine the
|
|
9
|
+
// flow steps directly to avoid KeyError-ing the idmap from generated test
|
|
10
|
+
// code)
|
|
11
|
+
//
|
|
12
|
+
// Identical helper was previously inlined in TestEntity_{go,py,lua,rb,php}.ts.
|
|
13
|
+
|
|
14
|
+
const COUNT = 3 // 3 ids per name: <name>01, <name>02, <name>03
|
|
15
|
+
|
|
16
|
+
type FlowLike = {
|
|
17
|
+
step?: Record<string, any> | any[]
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
type EntityLike = {
|
|
21
|
+
name: string
|
|
22
|
+
relations?: {
|
|
23
|
+
ancestors?: any
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function buildIdNames(entity: EntityLike, flow: FlowLike): string[] {
|
|
28
|
+
const idnames: string[] = []
|
|
29
|
+
const seen = new Set<string>()
|
|
30
|
+
const push = (n: string) => {
|
|
31
|
+
if (!seen.has(n)) {
|
|
32
|
+
seen.add(n)
|
|
33
|
+
idnames.push(n)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
for (let i = 1; i <= COUNT; i++) push(`${entity.name}0${i}`)
|
|
38
|
+
|
|
39
|
+
const ancestors: string[] = (entity.relations?.ancestors || []).flat()
|
|
40
|
+
for (const anc of ancestors) {
|
|
41
|
+
for (let i = 1; i <= COUNT; i++) push(`${anc}0${i}`)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const steps = Array.isArray(flow?.step)
|
|
45
|
+
? flow.step
|
|
46
|
+
: Object.values(flow?.step || {})
|
|
47
|
+
for (const step of steps) {
|
|
48
|
+
if (step?.match) {
|
|
49
|
+
for (const v of Object.values(step.match)) {
|
|
50
|
+
if (typeof v === 'string' && v && !v.endsWith('$')) push(v)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// step.data values can also be aliased via setup (e.g. update step.data
|
|
54
|
+
// = {data_type_id: 'data_type01'} → setup adds idmap[data_type_id] =
|
|
55
|
+
// idmap[data_type01]). The right-hand side `data_type01` must be in the
|
|
56
|
+
// idmap or the alias resolves to undefined.
|
|
57
|
+
if (step?.data) {
|
|
58
|
+
for (const v of Object.values(step.data)) {
|
|
59
|
+
if (typeof v === 'string' && v && !v.endsWith('$')) push(v)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return idnames
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
export {
|
|
69
|
+
buildIdNames,
|
|
70
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// Collect target-language dependencies from features and from the target's
|
|
2
|
+
// own `deps` block, applying the active-flag semantics that every Package_*.ts
|
|
3
|
+
// template was hand-rolling identically:
|
|
4
|
+
//
|
|
5
|
+
// - feature deps : included when `dep.active === true` (default off)
|
|
6
|
+
// - target deps : included when `dep.active !== false` (default on)
|
|
7
|
+
//
|
|
8
|
+
// The two sources are kept distinct via the `source` field so callers can
|
|
9
|
+
// apply their own version defaults / formatting (e.g. go uses `v0.0.0`,
|
|
10
|
+
// python `0.0`). The original dep object is exposed as `raw` for callers that
|
|
11
|
+
// need extra fields like `dep.replace` (go module replace directives) or
|
|
12
|
+
// `dep.kind` (prod/dev/peer).
|
|
13
|
+
|
|
14
|
+
import { each } from 'jostraca'
|
|
15
|
+
import { KIT, getModelPath } from '@voxgig/apidef'
|
|
16
|
+
|
|
17
|
+
type DepEntry = {
|
|
18
|
+
name: string
|
|
19
|
+
version: string
|
|
20
|
+
source: 'feature' | 'target'
|
|
21
|
+
raw: any
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function collectDeps(
|
|
25
|
+
model: any,
|
|
26
|
+
targetName: string,
|
|
27
|
+
targetDeps: any,
|
|
28
|
+
): DepEntry[] {
|
|
29
|
+
const out: DepEntry[] = []
|
|
30
|
+
const feature = getModelPath(model, `main.${KIT}.feature`)
|
|
31
|
+
|
|
32
|
+
each(feature, (f: any) => {
|
|
33
|
+
const langDeps = f?.deps?.[targetName]
|
|
34
|
+
if (!langDeps) return
|
|
35
|
+
each(langDeps, (dep: any) => {
|
|
36
|
+
if (dep?.active) {
|
|
37
|
+
out.push({
|
|
38
|
+
name: dep.key$,
|
|
39
|
+
version: dep.version,
|
|
40
|
+
source: 'feature',
|
|
41
|
+
raw: dep,
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
})
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
if (targetDeps) {
|
|
48
|
+
each(targetDeps, (dep: any) => {
|
|
49
|
+
if (dep?.active !== false) {
|
|
50
|
+
out.push({
|
|
51
|
+
name: dep.key$,
|
|
52
|
+
version: dep.version,
|
|
53
|
+
source: 'target',
|
|
54
|
+
raw: dep,
|
|
55
|
+
})
|
|
56
|
+
}
|
|
57
|
+
})
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return out
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
export type {
|
|
65
|
+
DepEntry,
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export {
|
|
69
|
+
collectDeps,
|
|
70
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Return the user-facing entries of a flow step's `match` object. Keys ending
|
|
2
|
+
// in `$` are jostraca/aontu metadata sentinels and are skipped.
|
|
3
|
+
//
|
|
4
|
+
// Identical helper was previously inlined in TestEntity_*.ts and TestDirect_*.ts.
|
|
5
|
+
|
|
6
|
+
function getMatchEntries(step: any): [string, any][] {
|
|
7
|
+
if (!step?.match) return []
|
|
8
|
+
return Object.entries(step.match).filter(([k]: any) => !k.endsWith('$'))
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
export {
|
|
13
|
+
getMatchEntries,
|
|
14
|
+
}
|
package/src/sdkgen.ts
CHANGED
|
@@ -38,6 +38,11 @@ import { ReadmeExplanation } from './cmp/ReadmeExplanation'
|
|
|
38
38
|
import { ReadmeRef } from './cmp/ReadmeRef'
|
|
39
39
|
import { FeatureHook } from './cmp/FeatureHook'
|
|
40
40
|
|
|
41
|
+
import { buildIdNames } from './helpers/buildIdNames'
|
|
42
|
+
import { getMatchEntries } from './helpers/getMatchEntries'
|
|
43
|
+
import { collectDeps } from './helpers/collectDeps'
|
|
44
|
+
import type { DepEntry } from './helpers/collectDeps'
|
|
45
|
+
|
|
41
46
|
|
|
42
47
|
import {
|
|
43
48
|
action_target,
|
|
@@ -330,6 +335,7 @@ function clear(path: string) {
|
|
|
330
335
|
|
|
331
336
|
export type {
|
|
332
337
|
SdkGenOptions,
|
|
338
|
+
DepEntry,
|
|
333
339
|
}
|
|
334
340
|
|
|
335
341
|
|
|
@@ -389,4 +395,8 @@ export {
|
|
|
389
395
|
SdkGen,
|
|
390
396
|
|
|
391
397
|
requirePath,
|
|
398
|
+
|
|
399
|
+
buildIdNames,
|
|
400
|
+
getMatchEntries,
|
|
401
|
+
collectDeps,
|
|
392
402
|
}
|