@voxgig/apidef 8.13.0 → 8.15.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-apidef +1 -174
- package/dist/apidef.d.ts +2 -2
- package/dist/apidef.js +2 -2
- package/dist/apidef.js.map +1 -1
- package/dist/builder/entity/entity.d.ts +5 -1
- package/dist/builder/entity/entity.js +17 -1
- package/dist/builder/entity/entity.js.map +1 -1
- package/dist/builder/flow/flowHeuristic01.js +14 -14
- package/dist/builder/flow/flowHeuristic01.js.map +1 -1
- package/dist/cli.d.ts +38 -0
- package/dist/cli.js +279 -0
- package/dist/cli.js.map +1 -0
- package/dist/guide/guide.js +8 -5
- package/dist/guide/guide.js.map +1 -1
- package/dist/model.d.ts +35 -33
- package/dist/resolved.d.ts +10 -6
- package/dist/resolved.js +65 -15
- package/dist/resolved.js.map +1 -1
- package/dist/transform/args.js +19 -19
- package/dist/transform/args.js.map +1 -1
- package/dist/transform/clean.js +4 -0
- package/dist/transform/clean.js.map +1 -1
- package/dist/transform/contract.d.ts +0 -2
- package/dist/transform/contract.js +6 -75
- package/dist/transform/contract.js.map +1 -1
- package/dist/transform/entity.d.ts +2 -1
- package/dist/transform/entity.js +13 -1
- package/dist/transform/entity.js.map +1 -1
- package/dist/transform/field.js +64 -64
- package/dist/transform/field.js.map +1 -1
- package/dist/transform/flowstep.js +42 -42
- package/dist/transform/flowstep.js.map +1 -1
- package/dist/transform/graphql.js +8 -8
- package/dist/transform/graphql.js.map +1 -1
- package/dist/transform/operation.js +9 -9
- package/dist/transform/operation.js.map +1 -1
- package/dist/transform/select.js +13 -13
- package/dist/transform/select.js.map +1 -1
- package/dist/transform/top.js +1 -1
- package/dist/transform/top.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/utility.d.ts +2 -1
- package/dist/utility.js +6 -1
- package/dist/utility.js.map +1 -1
- package/model/apidef.aon +128 -157
- package/model/guide.aon +3 -2
- package/package.json +5 -3
- package/src/apidef.ts +4 -3
- package/src/builder/entity/entity.ts +18 -1
- package/src/builder/flow/flowHeuristic01.ts +14 -14
- package/src/cli.ts +341 -0
- package/src/guide/guide.ts +8 -4
- package/src/model.ts +36 -37
- package/src/resolved.ts +62 -17
- package/src/transform/args.ts +20 -20
- package/src/transform/clean.ts +5 -0
- package/src/transform/contract.ts +6 -71
- package/src/transform/entity.ts +13 -1
- package/src/transform/field.ts +66 -69
- package/src/transform/flowstep.ts +42 -42
- package/src/transform/graphql.ts +8 -8
- package/src/transform/operation.ts +9 -9
- package/src/transform/select.ts +13 -13
- package/src/transform/top.ts +1 -1
- package/src/types.ts +1 -1
- package/src/utility.ts +8 -1
package/src/transform/field.ts
CHANGED
|
@@ -7,7 +7,7 @@ import type { TransformResult, Transform } from '../transform'
|
|
|
7
7
|
import {
|
|
8
8
|
validator, canonizeField, inferFieldType, normalizeFieldName, envelopeProp,
|
|
9
9
|
canonizeCmpName,
|
|
10
|
-
scanUntaggedUnion, firstSentence,
|
|
10
|
+
scanUntaggedUnion, firstSentence, humanTitle,
|
|
11
11
|
} from '../utility'
|
|
12
12
|
|
|
13
13
|
import { KIT } from '../types'
|
|
@@ -42,7 +42,6 @@ const fieldTransform: Transform = async function(
|
|
|
42
42
|
|
|
43
43
|
each(kit.entity, (ment: ModelEntity, _entname: string) => {
|
|
44
44
|
const fields = ment.fields
|
|
45
|
-
const seen: any = {}
|
|
46
45
|
|
|
47
46
|
for (let opname of opFieldPrecedence) {
|
|
48
47
|
const mop = ment.op[opname]
|
|
@@ -53,70 +52,63 @@ const fieldTransform: Transform = async function(
|
|
|
53
52
|
const opfields = resolveOpFields(ment, mop, mpoint, def)
|
|
54
53
|
|
|
55
54
|
for (let opfield of opfields) {
|
|
56
|
-
if (!
|
|
57
|
-
fields.
|
|
58
|
-
seen[opfield.name] = opfield
|
|
55
|
+
if (!Object.prototype.hasOwnProperty.call(fields, opfield.n)) {
|
|
56
|
+
fields[opfield.n] = opfield
|
|
59
57
|
}
|
|
60
58
|
else {
|
|
61
|
-
mergeField(mop,
|
|
59
|
+
mergeField(mop, fields[opfield.n], opfield)
|
|
62
60
|
}
|
|
63
61
|
}
|
|
64
62
|
}
|
|
65
63
|
}
|
|
66
64
|
}
|
|
67
65
|
|
|
68
|
-
fields.sort((a: ModelField, b: ModelField) => {
|
|
69
|
-
return a.name < b.name ? -1 : a.name > b.name ? 1 : 0
|
|
70
|
-
})
|
|
71
66
|
|
|
72
67
|
const gent = guide?.entity?.[ment.name]
|
|
73
68
|
const composite = compositeId(ment, gent, def)
|
|
74
69
|
|
|
75
|
-
const idField = fields.
|
|
70
|
+
const idField = fields.id
|
|
76
71
|
|
|
77
72
|
if (null != composite.parts && null != idField && !scalarStringField(idField)) {
|
|
78
73
|
const idf: any = idField
|
|
79
74
|
const apiname = String((model as any)?.name || 'api')
|
|
80
75
|
const keep = apiname + '_id'
|
|
81
76
|
|
|
82
|
-
if (!
|
|
77
|
+
if (!Object.prototype.hasOwnProperty.call(fields, keep)) {
|
|
83
78
|
// A DEEP COPY, because the move is followed by deletions on the
|
|
84
79
|
// original. A spread shares the `op` object, so clearing the stale
|
|
85
80
|
// per-op `type` off `id` cleared it off the preserved field too —
|
|
86
81
|
// the preservation preserved nothing for exactly the key it was
|
|
87
82
|
// added to keep.
|
|
88
|
-
fields
|
|
83
|
+
fields[keep] = JSON.parse(JSON.stringify({ ...idf, n: keep }))
|
|
89
84
|
|
|
90
85
|
const alias = ((ment as any).alias = (ment as any).alias || {})
|
|
91
86
|
alias.field = alias.field || {}
|
|
92
87
|
alias.field[keep] = 'id'
|
|
93
88
|
}
|
|
94
89
|
|
|
95
|
-
idf.
|
|
96
|
-
// The facts that described the moved type go with it: `
|
|
90
|
+
idf.t = '`$STRING`'
|
|
91
|
+
// The facts that described the moved type go with it: `fo: int64`
|
|
97
92
|
// beside a string, or a per-op `type` override still saying integer,
|
|
98
93
|
// is a model contradicting itself — and the op override is what a
|
|
99
94
|
// generator reads for that op.
|
|
100
|
-
delete idf.
|
|
95
|
+
delete idf.fo
|
|
101
96
|
for (const opname of Object.keys(idf.op || {})) {
|
|
102
97
|
delete idf.op[opname].type
|
|
103
98
|
}
|
|
104
99
|
|
|
105
|
-
fields.sort((a: ModelField, b: ModelField) =>
|
|
106
|
-
a.name < b.name ? -1 : a.name > b.name ? 1 : 0)
|
|
107
100
|
}
|
|
108
101
|
|
|
109
102
|
if (null != composite.parts && null == idField) {
|
|
110
103
|
// The FIELD as well as the descriptor, for the reason the branch below
|
|
111
104
|
// documents: a model that declares the descriptor without the field
|
|
112
105
|
// makes the generated type disagree with the generated test.
|
|
113
|
-
fields.
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
a.name < b.name ? -1 : a.name > b.name ? 1 : 0)
|
|
106
|
+
fields.id = {
|
|
107
|
+
n: 'id',
|
|
108
|
+
h: humanTitle('id'),
|
|
109
|
+
t: '`$STRING`',
|
|
110
|
+
r: false,
|
|
111
|
+
} as ModelField
|
|
120
112
|
}
|
|
121
113
|
|
|
122
114
|
const singleKey = (composite as any).single
|
|
@@ -126,30 +118,34 @@ const fieldTransform: Transform = async function(
|
|
|
126
118
|
// The guide disabled composite; the terminal parameter is the key, and
|
|
127
119
|
// the entity needs the field to carry it for the same reason the
|
|
128
120
|
// composite branch above does.
|
|
129
|
-
fields.
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
a.name < b.name ? -1 : a.name > b.name ? 1 : 0)
|
|
121
|
+
fields.id = {
|
|
122
|
+
n: 'id',
|
|
123
|
+
h: humanTitle('id'),
|
|
124
|
+
t: '`$STRING`',
|
|
125
|
+
r: false,
|
|
126
|
+
} as ModelField
|
|
136
127
|
}
|
|
137
128
|
|
|
138
129
|
if (idField || null != composite.parts || null != singleKey) {
|
|
139
130
|
ment.id = { name: 'id', field: 'id', ...composite }
|
|
140
131
|
}
|
|
141
132
|
else if (addressedById(ment)) {
|
|
142
|
-
fields.
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
a.name < b.name ? -1 : a.name > b.name ? 1 : 0)
|
|
133
|
+
fields.id = {
|
|
134
|
+
n: 'id',
|
|
135
|
+
h: humanTitle('id'),
|
|
136
|
+
t: '`$STRING`',
|
|
137
|
+
r: false,
|
|
138
|
+
} as ModelField
|
|
149
139
|
|
|
150
140
|
ment.id = { name: 'id', field: 'id', ...composite }
|
|
151
141
|
}
|
|
152
142
|
|
|
143
|
+
ment.fields = Object.fromEntries(Object.keys(fields).sort().map(n => {
|
|
144
|
+
const field = fields[n]
|
|
145
|
+
field.h = humanTitle(field.n)
|
|
146
|
+
return [n, field]
|
|
147
|
+
}))
|
|
148
|
+
|
|
153
149
|
msg += ment.name + ' '
|
|
154
150
|
})
|
|
155
151
|
|
|
@@ -174,7 +170,7 @@ const ID_OPS = ['load', 'update', 'patch', 'remove']
|
|
|
174
170
|
|
|
175
171
|
|
|
176
172
|
function trailingVars(point: any): string[] {
|
|
177
|
-
const segs = ((point?.
|
|
173
|
+
const segs = ((point?.s || []) as any[]).filter((s: any) => null != s)
|
|
178
174
|
const run: string[] = []
|
|
179
175
|
|
|
180
176
|
for (let i = segs.length - 1; 0 <= i; i--) {
|
|
@@ -199,7 +195,7 @@ function identityParams(ment: ModelEntity): string[] {
|
|
|
199
195
|
|
|
200
196
|
// Action points are verbs dispatched by `$action`, not addresses.
|
|
201
197
|
for (const pt of (mop.points || [])) {
|
|
202
|
-
if (null != pt?.
|
|
198
|
+
if (null != pt?.q?.['$action']) {
|
|
203
199
|
continue
|
|
204
200
|
}
|
|
205
201
|
const run = trailingVars(pt)
|
|
@@ -209,7 +205,7 @@ function identityParams(ment: ModelEntity): string[] {
|
|
|
209
205
|
cands.push({
|
|
210
206
|
run,
|
|
211
207
|
// Segments BEFORE the run: how much parent scope the route needs.
|
|
212
|
-
scope: ((pt.
|
|
208
|
+
scope: ((pt.s || []).length - run.length),
|
|
213
209
|
own: 'id' === run[run.length - 1] ||
|
|
214
210
|
(ment as any).name + '_id' === run[run.length - 1],
|
|
215
211
|
order: o,
|
|
@@ -289,12 +285,12 @@ function responseCandidates(ment: ModelEntity, def: any): any[] {
|
|
|
289
285
|
|
|
290
286
|
for (const mpoint of (mop?.points || [])) {
|
|
291
287
|
// An action point's response is not the entity.
|
|
292
|
-
if (null != mpoint?.
|
|
288
|
+
if (null != mpoint?.q?.['$action']) {
|
|
293
289
|
continue
|
|
294
290
|
}
|
|
295
291
|
|
|
296
|
-
const path = (def?.paths || {})[mpoint?.
|
|
297
|
-
const method = String(mpoint?.
|
|
292
|
+
const path = (def?.paths || {})[mpoint?.o]
|
|
293
|
+
const method = String(mpoint?.m || '').toLowerCase()
|
|
298
294
|
const responses = path?.[method]?.responses || {}
|
|
299
295
|
|
|
300
296
|
for (const code of Object.keys(responses)) {
|
|
@@ -384,15 +380,15 @@ function partAliases(ment: ModelEntity, part: string): string[] {
|
|
|
384
380
|
|
|
385
381
|
each((ment as any).op, (mop: any) => {
|
|
386
382
|
each(mop?.points, (mpoint: any) => {
|
|
387
|
-
const rename = mpoint?.
|
|
383
|
+
const rename = mpoint?.r?.param || {}
|
|
388
384
|
for (const orig of Object.keys(rename)) {
|
|
389
385
|
if (String(rename[orig]) === part) {
|
|
390
386
|
names.add(orig)
|
|
391
387
|
}
|
|
392
388
|
}
|
|
393
|
-
for (const arg of (mpoint?.
|
|
394
|
-
if (null != arg && arg.
|
|
395
|
-
names.add(String(arg.
|
|
389
|
+
for (const arg of (mpoint?.g?.params || [])) {
|
|
390
|
+
if (null != arg && arg.n === part && null != arg.or) {
|
|
391
|
+
names.add(String(arg.or))
|
|
396
392
|
}
|
|
397
393
|
}
|
|
398
394
|
})
|
|
@@ -482,7 +478,7 @@ function identityFrom(
|
|
|
482
478
|
// Is this model field declared as a string? A composite id is the parts
|
|
483
479
|
// joined, so the field that holds it has to be one.
|
|
484
480
|
function scalarStringField(f: any): boolean {
|
|
485
|
-
return String(f?.
|
|
481
|
+
return String(f?.t || '').toUpperCase().includes('STRING')
|
|
486
482
|
}
|
|
487
483
|
|
|
488
484
|
|
|
@@ -552,8 +548,8 @@ function addressedById(ment: ModelEntity): boolean {
|
|
|
552
548
|
let found = false
|
|
553
549
|
each((ment as any).op, (mop: any) => {
|
|
554
550
|
each(mop?.points, (mpoint: any) => {
|
|
555
|
-
each(mpoint?.
|
|
556
|
-
if (param && 'id' === param.
|
|
551
|
+
each(mpoint?.g?.params, (param: any) => {
|
|
552
|
+
if (param && 'id' === param.n) {
|
|
557
553
|
found = true
|
|
558
554
|
}
|
|
559
555
|
})
|
|
@@ -579,22 +575,23 @@ function resolveOpFields(
|
|
|
579
575
|
// items -> item, so the SDK read keys the server never sends.
|
|
580
576
|
const name = canonizeField(normalizeFieldName(fieldname))
|
|
581
577
|
const mfield: ModelField = {
|
|
582
|
-
name,
|
|
583
|
-
|
|
584
|
-
|
|
578
|
+
n: name,
|
|
579
|
+
h: humanTitle(name),
|
|
580
|
+
t: inferFieldType(name, validator(fielddef.type)),
|
|
581
|
+
r: !!fielddef.required,
|
|
585
582
|
op: {},
|
|
586
583
|
}
|
|
587
584
|
const fdesc = (fielddef as any).description
|
|
588
585
|
if ('string' === typeof fdesc && '' !== fdesc.trim()) {
|
|
589
586
|
const short = firstSentence(fdesc)
|
|
590
587
|
if ('' !== short) {
|
|
591
|
-
mfield.
|
|
588
|
+
mfield.sh = short
|
|
592
589
|
}
|
|
593
590
|
}
|
|
594
591
|
|
|
595
|
-
for (const flag of ['readOnly', 'writeOnly', 'deprecated'] as const) {
|
|
592
|
+
for (const [flag, attr] of [['readOnly', 'ro'], ['writeOnly', 'wo'], ['deprecated', 'de']] as const) {
|
|
596
593
|
if (true === (fielddef as any)[flag]) {
|
|
597
|
-
mfield[
|
|
594
|
+
mfield[attr] = true
|
|
598
595
|
}
|
|
599
596
|
}
|
|
600
597
|
|
|
@@ -603,7 +600,7 @@ function resolveOpFields(
|
|
|
603
600
|
// interpreted here. `password` is the one a generator acts on today.
|
|
604
601
|
const ffmt = (fielddef as any).format
|
|
605
602
|
if ('string' === typeof ffmt && '' !== ffmt.trim()) {
|
|
606
|
-
mfield.
|
|
603
|
+
mfield.fo = ffmt.trim()
|
|
607
604
|
}
|
|
608
605
|
|
|
609
606
|
// Record an untagged union under this field. The field is already typed
|
|
@@ -631,7 +628,7 @@ function findGraphqlFieldDefs(
|
|
|
631
628
|
mpoint: ModelPoint,
|
|
632
629
|
def: any
|
|
633
630
|
): SchemaDef[] {
|
|
634
|
-
const typeName = (mpoint.
|
|
631
|
+
const typeName = (mpoint.gq as any)?.entityType$ ??
|
|
635
632
|
(ment as any).orig$ ?? ''
|
|
636
633
|
const gtype = def.types?.[typeName]
|
|
637
634
|
|
|
@@ -698,18 +695,18 @@ function findFieldDefs(
|
|
|
698
695
|
mpoint: ModelPoint,
|
|
699
696
|
def: any
|
|
700
697
|
): SchemaDef[] {
|
|
701
|
-
if ('graphql' === mpoint.
|
|
698
|
+
if ('graphql' === mpoint.k) {
|
|
702
699
|
return findGraphqlFieldDefs(ment, mpoint, def)
|
|
703
700
|
}
|
|
704
701
|
|
|
705
702
|
// A verb, rather than an address: see the call site in the transform.
|
|
706
|
-
const isAction = null != (mpoint as any)?.
|
|
703
|
+
const isAction = null != (mpoint as any)?.q?.['$action']
|
|
707
704
|
|
|
708
705
|
const fielddefs: SchemaDef[] = []
|
|
709
706
|
|
|
710
|
-
const pathdef = def.paths[mpoint.
|
|
707
|
+
const pathdef = def.paths[mpoint.o]
|
|
711
708
|
|
|
712
|
-
const method = mpoint.
|
|
709
|
+
const method = mpoint.m.toLowerCase()
|
|
713
710
|
const opdef: any = (pathdef as any)?.[method]
|
|
714
711
|
|
|
715
712
|
if (opdef) {
|
|
@@ -912,18 +909,18 @@ function mergeField(
|
|
|
912
909
|
existingField: ModelField,
|
|
913
910
|
newField: ModelField
|
|
914
911
|
) {
|
|
915
|
-
if (newField.
|
|
912
|
+
if (newField.r !== existingField.r) {
|
|
916
913
|
existingField.op[mop.name] = {
|
|
917
|
-
req: newField.
|
|
918
|
-
type: newField.
|
|
914
|
+
req: newField.r,
|
|
915
|
+
type: newField.t,
|
|
919
916
|
}
|
|
920
917
|
}
|
|
921
918
|
|
|
922
|
-
if (null == existingField.
|
|
923
|
-
existingField.
|
|
919
|
+
if (null == existingField.sh && null != newField.sh) {
|
|
920
|
+
existingField.sh = newField.sh
|
|
924
921
|
}
|
|
925
922
|
|
|
926
|
-
for (const flag of ['
|
|
923
|
+
for (const flag of ['ro', 'wo', 'de', 'fo'] as const) {
|
|
927
924
|
if (null == existingField[flag] && null != newField[flag]) {
|
|
928
925
|
(existingField as any)[flag] = newField[flag]
|
|
929
926
|
}
|
|
@@ -12,19 +12,19 @@ import {
|
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
function isEntityIdParam(point: any, param: any, opname?: string): boolean {
|
|
15
|
-
if ('id' === param?.
|
|
16
|
-
const renameMap = point?.
|
|
17
|
-
if (renameMap && param?.
|
|
18
|
-
const camel = lcf(camelify(param.
|
|
15
|
+
if ('id' === param?.n) return true
|
|
16
|
+
const renameMap = point?.r?.param
|
|
17
|
+
if (renameMap && param?.n) {
|
|
18
|
+
const camel = lcf(camelify(param.n))
|
|
19
19
|
if ('id' === renameMap[camel]) return true
|
|
20
20
|
}
|
|
21
21
|
if ('update' === opname || 'load' === opname || 'remove' === opname) {
|
|
22
|
-
const segments: any[] = point?.
|
|
22
|
+
const segments: any[] = point?.s || []
|
|
23
23
|
let last: string | null = null
|
|
24
24
|
for (const s of segments) {
|
|
25
25
|
if (null != s?.var) last = s.var
|
|
26
26
|
}
|
|
27
|
-
if (last && last === param?.
|
|
27
|
+
if (last && last === param?.n) return true
|
|
28
28
|
}
|
|
29
29
|
return false
|
|
30
30
|
}
|
|
@@ -75,7 +75,7 @@ const flowstepTransform: Transform = async function(
|
|
|
75
75
|
{
|
|
76
76
|
input: {
|
|
77
77
|
ref: ref01,
|
|
78
|
-
textfield: firsttf?.
|
|
78
|
+
textfield: firsttf?.n,
|
|
79
79
|
suffix: '_up0',
|
|
80
80
|
srcdatavar: ref01 + '_data'
|
|
81
81
|
},
|
|
@@ -126,12 +126,12 @@ type MakeFlowStep =
|
|
|
126
126
|
|
|
127
127
|
function newFlowStep(opname: OpName, args: Record<string, any>): ModelEntityFlowStep {
|
|
128
128
|
return {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
129
|
+
o: opname,
|
|
130
|
+
i: args.input ?? {},
|
|
131
|
+
m: args.match ?? {},
|
|
132
|
+
d: args.data ?? {},
|
|
133
|
+
s: args.spec ?? [],
|
|
134
|
+
v: args.valid ?? [],
|
|
135
135
|
}
|
|
136
136
|
}
|
|
137
137
|
|
|
@@ -142,7 +142,7 @@ function newFlowStep(opname: OpName, args: Record<string, any>): ModelEntityFlow
|
|
|
142
142
|
// rename-to-id is recorded — the literal `id` then represents the entity's
|
|
143
143
|
// own id and createStep should skip it.
|
|
144
144
|
function originalSnakeNameOfRenamedId(point: any): string | null {
|
|
145
|
-
const renameMap = point?.
|
|
145
|
+
const renameMap = point?.r?.param || {}
|
|
146
146
|
for (const [src, dst] of Object.entries(renameMap)) {
|
|
147
147
|
if ('id' === dst) {
|
|
148
148
|
const srcStr = String(src)
|
|
@@ -165,17 +165,17 @@ const createStep: MakeFlowStep = (
|
|
|
165
165
|
const point = getelem(opmap.create.points, -1)
|
|
166
166
|
const step = newFlowStep('create', args)
|
|
167
167
|
|
|
168
|
-
each(point.
|
|
169
|
-
if ('id' === param.
|
|
168
|
+
each(point.g.params, (param: any) => {
|
|
169
|
+
if ('id' === param.n) {
|
|
170
170
|
const origName = originalSnakeNameOfRenamedId(point)
|
|
171
171
|
if (origName) {
|
|
172
|
-
step.
|
|
172
|
+
step.m[origName] = args.input?.[origName] ?? origName.replace(/_id/, '') + '01'
|
|
173
173
|
}
|
|
174
174
|
// If there's no rename-from, this is genuinely the entity's id — skip
|
|
175
175
|
// (the create call generates it).
|
|
176
176
|
return
|
|
177
177
|
}
|
|
178
|
-
step.
|
|
178
|
+
step.m[param.n] = args.input?.[param.n] ?? param.n.replace(/_id/, '') + '01'
|
|
179
179
|
})
|
|
180
180
|
|
|
181
181
|
seedRelatedOpParams(opmap, point, step)
|
|
@@ -191,14 +191,14 @@ function seedRelatedOpParams(opmap: any, createPoint: any, step: ModelEntityFlow
|
|
|
191
191
|
const op = opmap[opname]
|
|
192
192
|
if (!op?.points) continue
|
|
193
193
|
for (const point of op.points) {
|
|
194
|
-
const params: any[] = point?.
|
|
194
|
+
const params: any[] = point?.g?.params || []
|
|
195
195
|
for (const param of params) {
|
|
196
|
-
if (!param?.
|
|
196
|
+
if (!param?.n) continue
|
|
197
197
|
if (isEntityIdParam(point, param, opname as any)) continue
|
|
198
|
-
if (step.
|
|
199
|
-
if ('id' === param.
|
|
200
|
-
step.
|
|
201
|
-
param.
|
|
198
|
+
if (step.m[param.n] !== undefined) continue
|
|
199
|
+
if ('id' === param.n) continue
|
|
200
|
+
step.m[param.n] =
|
|
201
|
+
param.n.replace(/_id/, '') + '01'
|
|
202
202
|
}
|
|
203
203
|
}
|
|
204
204
|
}
|
|
@@ -216,15 +216,15 @@ const listStep: MakeFlowStep = (
|
|
|
216
216
|
const point = getelem(opmap.list.points, -1)
|
|
217
217
|
const step = newFlowStep('list', args)
|
|
218
218
|
|
|
219
|
-
each(point.
|
|
220
|
-
if ('id' === param.
|
|
219
|
+
each(point.g.params, (param: any) => {
|
|
220
|
+
if ('id' === param.n) {
|
|
221
221
|
const origName = originalSnakeNameOfRenamedId(point)
|
|
222
222
|
if (origName) {
|
|
223
|
-
step.
|
|
223
|
+
step.m[origName] = args.input?.[origName] ?? origName.replace(/_id/, '') + '01'
|
|
224
224
|
}
|
|
225
225
|
return
|
|
226
226
|
}
|
|
227
|
-
step.
|
|
227
|
+
step.m[param.n] = args.input?.[param.n] ?? param.n.replace(/_id/, '') + '01'
|
|
228
228
|
})
|
|
229
229
|
|
|
230
230
|
flow.step.push(step)
|
|
@@ -243,13 +243,13 @@ const updateStep: MakeFlowStep = (
|
|
|
243
243
|
const point = getelem(opmap.update.points, -1)
|
|
244
244
|
const step = newFlowStep('update', args)
|
|
245
245
|
|
|
246
|
-
each(point.
|
|
246
|
+
each(point.g.params, (param: any) => {
|
|
247
247
|
if (isEntityIdParam(point, param, 'update')) {
|
|
248
248
|
// Entity's own id — supplied at test time via the loaded/created
|
|
249
249
|
// entity's id field, not as a separate body parameter. Skip.
|
|
250
250
|
return
|
|
251
251
|
}
|
|
252
|
-
step.
|
|
252
|
+
step.d[param.n] = args.input?.[param.n] ?? param.n.replace(/_id/, '') + '01'
|
|
253
253
|
})
|
|
254
254
|
|
|
255
255
|
flow.step.push(step)
|
|
@@ -268,12 +268,12 @@ const loadStep: MakeFlowStep = (
|
|
|
268
268
|
const point = getelem(opmap.load.points, -1)
|
|
269
269
|
const step = newFlowStep('load', args)
|
|
270
270
|
|
|
271
|
-
each(point.
|
|
271
|
+
each(point.g.params, (param: any) => {
|
|
272
272
|
if (isEntityIdParam(point, param, 'load')) {
|
|
273
|
-
step.
|
|
273
|
+
step.m.id = args.input?.id ?? ent.name + '01'
|
|
274
274
|
}
|
|
275
275
|
else {
|
|
276
|
-
step.
|
|
276
|
+
step.m[param.n] = args.input?.[param.n] ?? param.n.replace(/_id/, '') + '01'
|
|
277
277
|
}
|
|
278
278
|
})
|
|
279
279
|
|
|
@@ -297,12 +297,12 @@ const removeStep: MakeFlowStep = (
|
|
|
297
297
|
const point = getelem(opmap.remove.points, -1)
|
|
298
298
|
const step = newFlowStep('remove', args)
|
|
299
299
|
|
|
300
|
-
each(point.
|
|
300
|
+
each(point.g.params, (param: any) => {
|
|
301
301
|
if (isEntityIdParam(point, param, 'remove')) {
|
|
302
|
-
step.
|
|
302
|
+
step.m.id = args.input?.id ?? ent.name + '01'
|
|
303
303
|
}
|
|
304
304
|
else {
|
|
305
|
-
step.
|
|
305
|
+
step.m[param.n] = args.input?.[param.n] ?? param.n.replace(/_id/, '') + '01'
|
|
306
306
|
}
|
|
307
307
|
})
|
|
308
308
|
|
|
@@ -314,14 +314,14 @@ const removeStep: MakeFlowStep = (
|
|
|
314
314
|
function firstTextField(ent: ModelEntity, op?: ModelOp) {
|
|
315
315
|
const paramNames: Record<string, boolean> = {}
|
|
316
316
|
each((op as any)?.points).forEach((pt: any) => {
|
|
317
|
-
each(pt?.
|
|
318
|
-
if (p && null != p.
|
|
319
|
-
paramNames[p.
|
|
317
|
+
each(pt?.g?.params).forEach((p: any) => {
|
|
318
|
+
if (p && null != p.n) {
|
|
319
|
+
paramNames[p.n] = true
|
|
320
320
|
}
|
|
321
321
|
})
|
|
322
322
|
})
|
|
323
323
|
|
|
324
|
-
const fields =
|
|
324
|
+
const fields = Object.keys(ent.fields).sort().map(n => ent.fields[n])
|
|
325
325
|
for (let fI = 0; fI < fields.length; fI++) {
|
|
326
326
|
const field = fields[fI]
|
|
327
327
|
// NOT A readOnly FIELD. The flow writes this one and then asserts the
|
|
@@ -329,8 +329,8 @@ function firstTextField(ent: ModelEntity, op?: ModelOp) {
|
|
|
329
329
|
// was chosen for. Fields are sorted by name, so which field this lands on
|
|
330
330
|
// is alphabetical accident: solar's planet, once its spec declared the
|
|
331
331
|
// server-assigned `forbidReason`, marked that instead of `kind`.
|
|
332
|
-
if ('`$STRING`' === field.
|
|
333
|
-
true !== field.
|
|
332
|
+
if ('`$STRING`' === field.t && 'id' !== field.n &&
|
|
333
|
+
true !== field.ro && true !== paramNames[field.n]) {
|
|
334
334
|
return field
|
|
335
335
|
}
|
|
336
336
|
}
|
package/src/transform/graphql.ts
CHANGED
|
@@ -177,7 +177,7 @@ const graphqlTransform: Transform = async function(
|
|
|
177
177
|
|
|
178
178
|
each(ment.op, (mop: ModelOp, opname: OpName) => {
|
|
179
179
|
each(mop.points, (mpoint: ModelPoint) => {
|
|
180
|
-
const rootfield = mpoint.
|
|
180
|
+
const rootfield = mpoint.o
|
|
181
181
|
|
|
182
182
|
const gfield: GuidePath | undefined = (gent as any)?.field?.[rootfield]
|
|
183
183
|
const optype = (gfield?.op?.[opname] as any)?.optype ?? 'query'
|
|
@@ -231,11 +231,11 @@ const graphqlTransform: Transform = async function(
|
|
|
231
231
|
const docname = pascal(entname) + pascal(opname) +
|
|
232
232
|
(null != actionName ? pascal(actionName) : '')
|
|
233
233
|
|
|
234
|
-
mpoint.
|
|
235
|
-
mpoint.
|
|
236
|
-
mpoint.
|
|
234
|
+
mpoint.k = 'graphql'
|
|
235
|
+
mpoint.m = 'POST'
|
|
236
|
+
mpoint.s = []
|
|
237
237
|
|
|
238
|
-
mpoint.
|
|
238
|
+
mpoint.gq = {
|
|
239
239
|
optype: optype as 'query' | 'mutation',
|
|
240
240
|
field: rootfield,
|
|
241
241
|
doc: renderDoc(docname, optype, rootfield, vars, selection,
|
|
@@ -246,10 +246,10 @@ const graphqlTransform: Transform = async function(
|
|
|
246
246
|
// Carried for the field transform, which derives entity fields from
|
|
247
247
|
// the same object type. The `$` suffix makes cleanTransform strip it
|
|
248
248
|
// from the emitted model — it is pipeline state, not wire data.
|
|
249
|
-
;(mpoint.
|
|
249
|
+
;(mpoint.gq as any).entityType$ = entityType
|
|
250
250
|
|
|
251
251
|
if ('connection' === ret.kind) {
|
|
252
|
-
mpoint.
|
|
252
|
+
mpoint.gq.page = {
|
|
253
253
|
style: 'relay',
|
|
254
254
|
nodes: ret.nodes ?? 'nodes',
|
|
255
255
|
cursor: 'pageInfo.endCursor',
|
|
@@ -257,7 +257,7 @@ const graphqlTransform: Transform = async function(
|
|
|
257
257
|
}
|
|
258
258
|
}
|
|
259
259
|
|
|
260
|
-
mpoint.
|
|
260
|
+
mpoint.t.res = '`' + respath + '`'
|
|
261
261
|
})
|
|
262
262
|
})
|
|
263
263
|
|
|
@@ -184,19 +184,19 @@ function resolveOp(opname: OpName, gent: GuideEntity): undefined | ModelOp {
|
|
|
184
184
|
const segments = p.segments
|
|
185
185
|
|
|
186
186
|
const mpoint: ModelPoint = {
|
|
187
|
-
|
|
188
|
-
segments,
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
187
|
+
o: p.orig,
|
|
188
|
+
s: segments,
|
|
189
|
+
r: p.rename,
|
|
190
|
+
m: p.method,
|
|
191
|
+
g: {},
|
|
192
|
+
t: { ...((p as any).op?.transform ?? {}) },
|
|
193
|
+
q: {
|
|
194
194
|
exist: []
|
|
195
195
|
}
|
|
196
196
|
}
|
|
197
197
|
|
|
198
|
-
mpoint.
|
|
199
|
-
mpoint.
|
|
198
|
+
mpoint.t.req = mpoint.t.req ?? '`reqdata`'
|
|
199
|
+
mpoint.t.res = mpoint.t.res ?? '`body`'
|
|
200
200
|
|
|
201
201
|
return mpoint
|
|
202
202
|
})
|