@voxgig/apidef 1.4.0 → 1.5.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/dist/apidef.d.ts +9 -8
- package/dist/apidef.js +70 -13
- package/dist/apidef.js.map +1 -1
- package/dist/parse.js +0 -1
- package/dist/parse.js.map +1 -1
- package/dist/transform/entity.js +0 -4
- package/dist/transform/entity.js.map +1 -1
- package/dist/transform/field.js +0 -4
- package/dist/transform/field.js.map +1 -1
- package/dist/transform/manual.js +3 -3
- package/dist/transform/manual.js.map +1 -1
- package/dist/transform/operation.js +79 -41
- package/dist/transform/operation.js.map +1 -1
- package/dist/transform.d.ts +3 -0
- package/dist/transform.js +4 -26
- package/dist/transform.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/model/apidef.jsonic +10 -6
- package/package.json +9 -9
- package/src/apidef.ts +126 -19
- package/src/parse.ts +0 -2
- package/src/transform/entity.ts +0 -6
- package/src/transform/field.ts +0 -6
- package/src/transform/manual.ts +2 -2
- package/src/transform/operation.ts +119 -44
- package/src/transform.ts +4 -31
- package/dist/transform/fieldTransform.d.ts +0 -5
- package/dist/transform/fieldTransform.js +0 -55
- package/dist/transform/fieldTransform.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../src/apidef.ts","../src/parse.ts","../src/transform.ts","../src/transform/entity.ts","../src/transform/field.ts","../src/transform/manual.ts","../src/transform/operation.ts","../src/transform/top.ts"],"version":"5.7.
|
|
1
|
+
{"root":["../src/apidef.ts","../src/parse.ts","../src/transform.ts","../src/transform/entity.ts","../src/transform/field.ts","../src/transform/manual.ts","../src/transform/operation.ts","../src/transform/top.ts"],"version":"5.7.3"}
|
package/model/apidef.jsonic
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
|
|
2
|
-
main: guide: control: transform: &: {
|
|
2
|
+
main: api: guide: control: transform: &: {
|
|
3
3
|
order: string
|
|
4
4
|
}
|
|
5
5
|
|
|
6
|
-
main: guide: control: transform: openapi: {
|
|
6
|
+
main: api: guide: control: transform: openapi: {
|
|
7
7
|
order: *`
|
|
8
8
|
|
|
9
9
|
top,
|
|
@@ -16,12 +16,12 @@ main: guide: control: transform: openapi: {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
main: guide: transform: &: {
|
|
19
|
+
main: api: guide: transform: &: {
|
|
20
20
|
name: .$KEY
|
|
21
21
|
load: string
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
main: guide: transform: {
|
|
24
|
+
main: api: guide: transform: {
|
|
25
25
|
top: {}
|
|
26
26
|
entity: {}
|
|
27
27
|
operation: {}
|
|
@@ -30,12 +30,16 @@ main: guide: transform: {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
|
|
33
|
-
main: guide: entity: &: {
|
|
33
|
+
main: api: guide: entity: &: {
|
|
34
34
|
name: .$KEY
|
|
35
35
|
path: &: {
|
|
36
36
|
op: &: {
|
|
37
37
|
method: *'get' | string
|
|
38
|
-
|
|
38
|
+
transform: {
|
|
39
|
+
# TODO: make these work
|
|
40
|
+
# inward: *null | string | object
|
|
41
|
+
# outward: *null | string | object
|
|
42
|
+
}
|
|
39
43
|
}
|
|
40
44
|
}
|
|
41
45
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voxgig/apidef",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"main": "dist/apidef.js",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"types": "dist/apidef.d.ts",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"test-some": "node --enable-source-maps --test-name-pattern=\"$npm_config_pattern\" --test dist-test",
|
|
25
25
|
"watch": "tsc --build src test -w",
|
|
26
26
|
"build": "tsc --build src test",
|
|
27
|
-
"clean": "rm -rf node_modules yarn.lock package-lock.json",
|
|
27
|
+
"clean": "rm -rf dist dist-test node_modules yarn.lock package-lock.json",
|
|
28
28
|
"reset": "npm run clean && npm i && npm run build && npm test",
|
|
29
29
|
"repo-tag": "REPO_VERSION=`node -e \"console.log(require('./package').version)\"` && echo TAG: v$REPO_VERSION && git commit -a -m v$REPO_VERSION && git push && git tag v$REPO_VERSION && git push --tags;",
|
|
30
30
|
"repo-publish": "npm run clean && npm i && npm run repo-publish-quick",
|
|
@@ -41,20 +41,20 @@
|
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@hapi/code": "^9.0.3",
|
|
43
43
|
"@types/js-yaml": "^4.0.9",
|
|
44
|
-
"@types/node": "22.
|
|
45
|
-
"aontu": "^0.
|
|
46
|
-
"esbuild": "^0.
|
|
44
|
+
"@types/node": "22.13.4",
|
|
45
|
+
"aontu": "^0.28.0",
|
|
46
|
+
"esbuild": "^0.25.0",
|
|
47
47
|
"json-schema-to-ts": "^3.1.1",
|
|
48
|
-
"memfs": "^4.
|
|
49
|
-
"typescript": "^5.7.
|
|
48
|
+
"memfs": "^4.17.0",
|
|
49
|
+
"typescript": "^5.7.3"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@redocly/openapi-core": "^1.
|
|
52
|
+
"@redocly/openapi-core": "^1.30.0",
|
|
53
53
|
"@voxgig/util": "^0.0.9",
|
|
54
54
|
"chokidar": "^4.0.3",
|
|
55
55
|
"gubu": "^9.0.0",
|
|
56
56
|
"jostraca": "^0.15.1",
|
|
57
|
-
"pino": "^9.
|
|
57
|
+
"pino": "^9.6.0",
|
|
58
58
|
"pino-pretty": "^13.0.0",
|
|
59
59
|
"sonic-boom": "^4.2.0"
|
|
60
60
|
}
|
package/src/apidef.ts
CHANGED
|
@@ -5,9 +5,8 @@ import Path from 'node:path'
|
|
|
5
5
|
import { inspect } from 'node:util'
|
|
6
6
|
|
|
7
7
|
import { bundleFromString, createConfig } from '@redocly/openapi-core'
|
|
8
|
-
import { FSWatcher } from 'chokidar'
|
|
9
|
-
import { Aontu, Context } from 'aontu'
|
|
10
8
|
import { Gubu, Open, Any } from 'gubu'
|
|
9
|
+
import { each } from 'jostraca'
|
|
11
10
|
import { prettyPino, Pino } from '@voxgig/util'
|
|
12
11
|
|
|
13
12
|
|
|
@@ -29,10 +28,19 @@ type ApiDefOptions = {
|
|
|
29
28
|
}
|
|
30
29
|
|
|
31
30
|
|
|
31
|
+
type ApiModel = {
|
|
32
|
+
main: {
|
|
33
|
+
api: {
|
|
34
|
+
entity: Record<string, any>
|
|
35
|
+
}
|
|
36
|
+
def: Record<string, any>
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
|
|
32
41
|
const ModelShape = Gubu({
|
|
33
42
|
def: String,
|
|
34
43
|
main: {
|
|
35
|
-
guide: {},
|
|
36
44
|
sdk: {},
|
|
37
45
|
def: {},
|
|
38
46
|
api: {},
|
|
@@ -130,7 +138,7 @@ function ApiDef(opts: ApiDefOptions) {
|
|
|
130
138
|
}
|
|
131
139
|
|
|
132
140
|
|
|
133
|
-
const apimodel = {
|
|
141
|
+
const apimodel: ApiModel = {
|
|
134
142
|
main: {
|
|
135
143
|
api: {
|
|
136
144
|
entity: {}
|
|
@@ -152,6 +160,24 @@ function ApiDef(opts: ApiDefOptions) {
|
|
|
152
160
|
return { ok: false, name: 'apidef', processResult }
|
|
153
161
|
}
|
|
154
162
|
|
|
163
|
+
|
|
164
|
+
const modelPath = Path.normalize(spec.config.model)
|
|
165
|
+
|
|
166
|
+
buildModel_api(apimodel, modelPath)
|
|
167
|
+
buildModel_def(apimodel, modelPath)
|
|
168
|
+
buildModel_entity(apimodel, modelPath)
|
|
169
|
+
|
|
170
|
+
log.info({ point: 'generate-end', note: 'success', break: true })
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
ok: true,
|
|
174
|
+
name: 'apidef',
|
|
175
|
+
apimodel,
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
function buildModel_api(apimodel: ApiModel, modelPath: string) {
|
|
155
181
|
const modelapi = { main: { api: apimodel.main.api } }
|
|
156
182
|
let modelSrc = JSON.stringify(modelapi, null, 2)
|
|
157
183
|
|
|
@@ -159,14 +185,15 @@ function ApiDef(opts: ApiDefOptions) {
|
|
|
159
185
|
'# GENERATED FILE - DO NOT EDIT\n\n' +
|
|
160
186
|
modelSrc.substring(1, modelSrc.length - 1).replace(/\n /g, '\n')
|
|
161
187
|
|
|
162
|
-
const modelPath = Path.normalize(spec.config.model)
|
|
163
|
-
// console.log('modelPath', modelPath)
|
|
164
188
|
writeChanged('api-model', modelPath, modelSrc)
|
|
189
|
+
return modelPath
|
|
190
|
+
}
|
|
165
191
|
|
|
192
|
+
|
|
193
|
+
function buildModel_def(apimodel: ApiModel, modelPath: string) {
|
|
166
194
|
const modelBasePath = Path.dirname(modelPath)
|
|
167
|
-
const defFilePath =
|
|
168
|
-
|
|
169
|
-
(null == opts.outprefix ? '' : opts.outprefix) + 'def-generated.jsonic')
|
|
195
|
+
const defFilePath = Path.join(modelBasePath,
|
|
196
|
+
(null == opts.outprefix ? '' : opts.outprefix) + 'def-generated.jsonic')
|
|
170
197
|
|
|
171
198
|
const modelDef = { main: { def: apimodel.main.def } }
|
|
172
199
|
let modelDefSrc = JSON.stringify(modelDef, null, 2)
|
|
@@ -176,20 +203,73 @@ function ApiDef(opts: ApiDefOptions) {
|
|
|
176
203
|
modelDefSrc.substring(1, modelDefSrc.length - 1).replace(/\n /g, '\n')
|
|
177
204
|
|
|
178
205
|
writeChanged('def-model', defFilePath, modelDefSrc)
|
|
206
|
+
}
|
|
179
207
|
|
|
180
|
-
log.info({ point: 'generate-end', note: 'success', break: true })
|
|
181
208
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
209
|
+
function buildModel_entity(apimodel: ApiModel, modelPath: string) {
|
|
210
|
+
const modelBasePath = Path.dirname(modelPath)
|
|
211
|
+
|
|
212
|
+
const entityIncludes: string[] = []
|
|
213
|
+
|
|
214
|
+
each(apimodel.main.api.entity, ((entity: any) => {
|
|
215
|
+
entityIncludes.push(entity.name)
|
|
216
|
+
|
|
217
|
+
// HEURISTIC: id may be name_id or nameId
|
|
218
|
+
const fieldAliases =
|
|
219
|
+
each(entity.op, (op: any) =>
|
|
220
|
+
each(op.param))
|
|
221
|
+
.flat()
|
|
222
|
+
.reduce((a: any, p: any) =>
|
|
223
|
+
|
|
224
|
+
(entity.field[p.keys] ? null :
|
|
225
|
+
(p.key$.toLowerCase().includes(entity.name) ?
|
|
226
|
+
(a[p.key$] = 'id', a.id = p.key$) :
|
|
227
|
+
null)
|
|
228
|
+
|
|
229
|
+
, a), {})
|
|
230
|
+
|
|
231
|
+
const fieldAliasesSrc =
|
|
232
|
+
JSON.stringify(fieldAliases, null, 2)
|
|
233
|
+
.replace(/\n/g, '\n ')
|
|
234
|
+
|
|
235
|
+
const entityFileSrc = `
|
|
236
|
+
# Entity ${entity.name}
|
|
237
|
+
|
|
238
|
+
main: sdk: entity: ${entity.name}: {
|
|
239
|
+
alias: field: ${fieldAliasesSrc}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
`
|
|
243
|
+
const entityFilePath = Path.join(modelBasePath, 'entity',
|
|
244
|
+
(null == opts.outprefix ? '' : opts.outprefix) + entity.name + '.jsonic')
|
|
245
|
+
|
|
246
|
+
fs.mkdirSync(Path.dirname(entityFilePath), { recursive: true })
|
|
247
|
+
|
|
248
|
+
// TODO: diff merge
|
|
249
|
+
writeChanged('entity-model', entityFilePath, entityFileSrc, { update: false })
|
|
250
|
+
}))
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
modifyModel(
|
|
254
|
+
fs,
|
|
255
|
+
Path.join(
|
|
256
|
+
modelBasePath,
|
|
257
|
+
(null == opts.outprefix ? '' : opts.outprefix) + 'sdk.jsonic'),
|
|
258
|
+
entityIncludes
|
|
259
|
+
)
|
|
187
260
|
}
|
|
188
261
|
|
|
189
262
|
|
|
190
|
-
function writeChanged(
|
|
263
|
+
function writeChanged(
|
|
264
|
+
point: string, path: string, content: string,
|
|
265
|
+
flags?: { update?: boolean }
|
|
266
|
+
) {
|
|
191
267
|
let exists = false
|
|
192
268
|
let changed = false
|
|
269
|
+
|
|
270
|
+
flags = flags || {}
|
|
271
|
+
flags.update = null == flags.update ? true : !!flags.update
|
|
272
|
+
|
|
193
273
|
let action = ''
|
|
194
274
|
try {
|
|
195
275
|
let existingContent: string = ''
|
|
@@ -204,7 +284,7 @@ function ApiDef(opts: ApiDefOptions) {
|
|
|
204
284
|
|
|
205
285
|
changed = existingContent !== content
|
|
206
286
|
|
|
207
|
-
|
|
287
|
+
action = flags.update ? 'write' : 'skip'
|
|
208
288
|
|
|
209
289
|
log.info({
|
|
210
290
|
point: 'write-' + point,
|
|
@@ -213,8 +293,7 @@ function ApiDef(opts: ApiDefOptions) {
|
|
|
213
293
|
contentLength: content.length, file: path
|
|
214
294
|
})
|
|
215
295
|
|
|
216
|
-
if (changed) {
|
|
217
|
-
action = 'write'
|
|
296
|
+
if (!exists || (changed && flags.update)) {
|
|
218
297
|
fs.writeFileSync(path, content)
|
|
219
298
|
}
|
|
220
299
|
}
|
|
@@ -267,6 +346,34 @@ ApiDef.makeBuild = async function(opts: ApiDefOptions) {
|
|
|
267
346
|
|
|
268
347
|
|
|
269
348
|
|
|
349
|
+
async function modifyModel(fs: any, path: string, entityIncludes: string[]) {
|
|
350
|
+
// TODO: This is a kludge.
|
|
351
|
+
// Aontu should provide option for as-is AST so that can be used
|
|
352
|
+
// to find injection point more reliably
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
let src = fs.existsSync(path) ? fs.readFileSync(path, 'utf8') :
|
|
356
|
+
'main: sdk: entity: {}\n'
|
|
357
|
+
|
|
358
|
+
let newsrc = '' + src
|
|
359
|
+
|
|
360
|
+
// Inject target file references into model
|
|
361
|
+
entityIncludes.sort().map((entname: string) => {
|
|
362
|
+
const lineRE =
|
|
363
|
+
new RegExp(`@"entity/${entname}.jsonic"`)
|
|
364
|
+
|
|
365
|
+
if (!src.match(lineRE)) {
|
|
366
|
+
newsrc = newsrc.replace(/(main:\s+sdk:\s+entity:\s+\{\s*\}\n)/, '$1' +
|
|
367
|
+
`@"entity/${entname}.jsonic"\n`)
|
|
368
|
+
}
|
|
369
|
+
})
|
|
370
|
+
|
|
371
|
+
if (newsrc.length !== src.length) {
|
|
372
|
+
fs.writeFileSync(path, newsrc)
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
|
|
270
377
|
|
|
271
378
|
export type {
|
|
272
379
|
ApiDefOptions,
|
package/src/parse.ts
CHANGED
package/src/transform/entity.ts
CHANGED
|
@@ -16,9 +16,6 @@ const entityTransform: Transform = async function(
|
|
|
16
16
|
): Promise<TransformResult> {
|
|
17
17
|
let msg = ''
|
|
18
18
|
|
|
19
|
-
// console.log('DEF', def)
|
|
20
|
-
// console.log('GUIDE', guide)
|
|
21
|
-
|
|
22
19
|
each(guide.entity, (guideEntity: any) => {
|
|
23
20
|
const entityName = guideEntity.key$
|
|
24
21
|
ctx.log.debug({ point: 'guide-entity', note: entityName })
|
|
@@ -39,9 +36,6 @@ const entityTransform: Transform = async function(
|
|
|
39
36
|
const path = guidePath.key$
|
|
40
37
|
const pathdef = def.paths[path]
|
|
41
38
|
|
|
42
|
-
// console.log('APIDEF FIND PATH', guidePath.key$, Object.keys(def.paths),
|
|
43
|
-
// Object.keys(def.paths).includes(guidePath.key$))
|
|
44
|
-
|
|
45
39
|
if (null == pathdef) {
|
|
46
40
|
throw new Error('path not found in OpenAPI: ' + path +
|
|
47
41
|
' (entity: ' + guideEntity.name + ')')
|
package/src/transform/field.ts
CHANGED
|
@@ -47,7 +47,6 @@ const fieldTransform: Transform = async function(
|
|
|
47
47
|
function fieldbuild(
|
|
48
48
|
entityModel: any, pathdef: any, op: any, path: any, entity: any, model: any
|
|
49
49
|
) {
|
|
50
|
-
// console.log('FB-A', op, pathdef)
|
|
51
50
|
let fieldCount = 0
|
|
52
51
|
let fieldSets = getx(pathdef.get, 'responses 200 content "application/json" schema')
|
|
53
52
|
|
|
@@ -60,12 +59,8 @@ function fieldbuild(
|
|
|
60
59
|
}
|
|
61
60
|
}
|
|
62
61
|
|
|
63
|
-
// console.log('TRANSFORM-FIELDSETS', fieldSets)
|
|
64
|
-
|
|
65
62
|
each(fieldSets, (fieldSet: any) => {
|
|
66
63
|
each(fieldSet.properties, (property: any) => {
|
|
67
|
-
// console.log(property)
|
|
68
|
-
|
|
69
64
|
const field =
|
|
70
65
|
(entityModel.field[property.key$] = entityModel.field[property.key$] || {})
|
|
71
66
|
|
|
@@ -78,7 +73,6 @@ function fieldbuild(
|
|
|
78
73
|
field.short = property.description
|
|
79
74
|
|
|
80
75
|
fieldCount++
|
|
81
|
-
// console.log('FB-ID', field.name, entityModel.param)
|
|
82
76
|
})
|
|
83
77
|
})
|
|
84
78
|
|
package/src/transform/manual.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
import { Jsonic } from '
|
|
2
|
+
import { Jsonic } from 'jsonic'
|
|
3
3
|
|
|
4
4
|
import { each, getx } from 'jostraca'
|
|
5
5
|
|
|
@@ -16,7 +16,7 @@ const manualTransform = async function(
|
|
|
16
16
|
def: any
|
|
17
17
|
): Promise<TransformResult> {
|
|
18
18
|
|
|
19
|
-
const {
|
|
19
|
+
const { manual } = guide
|
|
20
20
|
|
|
21
21
|
deep(model, manual)
|
|
22
22
|
|
|
@@ -45,58 +45,83 @@ const operationTransform = async function(
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
|
|
48
|
-
// Resolve the JSON
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
48
|
+
// Resolve the JSON structure of the request or response.
|
|
49
|
+
// NOTE: uses heuristics.
|
|
50
|
+
const resolveTransform = (
|
|
51
|
+
op: any,
|
|
52
|
+
kind: 'res' | 'req',
|
|
53
|
+
direction: 'inward' | 'outward',
|
|
54
|
+
pathdef: any
|
|
55
|
+
) => {
|
|
56
|
+
let out
|
|
57
|
+
|
|
58
|
+
if (null != op.transform?.[direction]) {
|
|
59
|
+
out = op.transform[direction]
|
|
60
|
+
}
|
|
52
61
|
|
|
53
|
-
|
|
62
|
+
else {
|
|
63
|
+
const method = op.method
|
|
64
|
+
const mdef = pathdef[method]
|
|
54
65
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
66
|
+
// TODO: fix getx
|
|
67
|
+
const content = 'res' === kind ?
|
|
68
|
+
(getx(mdef, 'responses.200.content') ||
|
|
69
|
+
getx(mdef, 'responses.201.content')) :
|
|
70
|
+
getx(mdef, 'requestBody.content')
|
|
58
71
|
|
|
59
|
-
const method = op.method
|
|
60
|
-
const mdef = pathdef[method]
|
|
61
72
|
|
|
62
|
-
|
|
63
|
-
const content = 'res' === kind ?
|
|
64
|
-
(getx(mdef, 'responses.200.content') ||
|
|
65
|
-
getx(mdef, 'responses.201.content')) :
|
|
66
|
-
getx(mdef, 'requestBody.content')
|
|
73
|
+
const schema = content['application/json']?.schema
|
|
67
74
|
|
|
75
|
+
const propkeys = null == schema?.properties ? [] : Object.keys(schema.properties)
|
|
68
76
|
|
|
69
|
-
|
|
77
|
+
const resolveDirectionTransform =
|
|
78
|
+
'inward' === direction ? resolveInwardTransform : resolveOutwardTransform
|
|
70
79
|
|
|
71
|
-
|
|
72
|
-
|
|
80
|
+
const transform = resolveDirectionTransform(
|
|
81
|
+
op,
|
|
82
|
+
kind,
|
|
83
|
+
method,
|
|
84
|
+
mdef,
|
|
85
|
+
content,
|
|
86
|
+
schema,
|
|
87
|
+
propkeys
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
// out = JSON.stringify(transform)
|
|
91
|
+
out = transform
|
|
73
92
|
}
|
|
74
93
|
|
|
75
|
-
|
|
94
|
+
return out
|
|
95
|
+
}
|
|
96
|
+
|
|
76
97
|
|
|
77
|
-
|
|
98
|
+
const resolveInwardTransform = (
|
|
99
|
+
op: any,
|
|
100
|
+
kind: 'res' | 'req',
|
|
101
|
+
method: string,
|
|
102
|
+
mdef: any,
|
|
103
|
+
content: any,
|
|
104
|
+
schema: any,
|
|
105
|
+
propkeys: any
|
|
106
|
+
) => {
|
|
107
|
+
let transform: any = '`body`'
|
|
78
108
|
|
|
79
|
-
if (null == schema) {
|
|
80
|
-
return
|
|
109
|
+
if (null == content || null == schema || null == propkeys) {
|
|
110
|
+
return transform
|
|
81
111
|
}
|
|
82
112
|
|
|
113
|
+
const opname = op.key$
|
|
83
114
|
|
|
84
|
-
const propkeys = null == schema.properties ? [] : Object.keys(schema.properties)
|
|
85
|
-
|
|
86
|
-
// HEURISTIC: guess place
|
|
87
115
|
if ('list' === opname) {
|
|
88
|
-
if ('array'
|
|
89
|
-
place = ''
|
|
90
|
-
}
|
|
91
|
-
else {
|
|
116
|
+
if ('array' !== schema.type) {
|
|
92
117
|
if (1 === propkeys.length) {
|
|
93
|
-
|
|
118
|
+
transform = '`body.' + propkeys[0] + '`'
|
|
94
119
|
}
|
|
95
120
|
else {
|
|
96
121
|
// Use sub property that is an array
|
|
97
122
|
for (let pk of propkeys) {
|
|
98
123
|
if ('array' === schema.properties[pk]?.type) {
|
|
99
|
-
|
|
124
|
+
transform = '`body.' + pk + '`'
|
|
100
125
|
break
|
|
101
126
|
}
|
|
102
127
|
}
|
|
@@ -105,18 +130,69 @@ const operationTransform = async function(
|
|
|
105
130
|
}
|
|
106
131
|
else {
|
|
107
132
|
if ('object' === schema.type) {
|
|
108
|
-
if (schema.properties.id) {
|
|
109
|
-
|
|
133
|
+
if (null == schema.properties.id) {
|
|
134
|
+
if (1 === propkeys.length) {
|
|
135
|
+
transform = '`body.' + propkeys[0] + '`'
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
for (let pk of propkeys) {
|
|
139
|
+
if (schema.properties[pk].properties?.id) {
|
|
140
|
+
transform = '`body.' + pk + '`'
|
|
141
|
+
break
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return transform
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
const resolveOutwardTransform = (
|
|
154
|
+
op: any,
|
|
155
|
+
kind: 'res' | 'req',
|
|
156
|
+
method: string,
|
|
157
|
+
mdef: any,
|
|
158
|
+
content: any,
|
|
159
|
+
schema: any,
|
|
160
|
+
propkeys: any
|
|
161
|
+
) => {
|
|
162
|
+
let transform: any = '`data`'
|
|
163
|
+
|
|
164
|
+
if (null == content || null == schema || null == propkeys) {
|
|
165
|
+
return transform
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const opname = op.key$
|
|
169
|
+
|
|
170
|
+
if ('list' === opname) {
|
|
171
|
+
if ('array' !== schema.type) {
|
|
172
|
+
if (1 === propkeys.length) {
|
|
173
|
+
transform = { [propkeys[0]]: '`data`' }
|
|
110
174
|
}
|
|
111
175
|
else {
|
|
176
|
+
// Use sub property that is an array
|
|
177
|
+
for (let pk of propkeys) {
|
|
178
|
+
if ('array' === schema.properties[pk]?.type) {
|
|
179
|
+
transform = { [pk]: '`data`' }
|
|
180
|
+
break
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
if ('object' === schema.type) {
|
|
188
|
+
if (null == schema.properties.id) {
|
|
112
189
|
if (1 === propkeys.length) {
|
|
113
|
-
|
|
190
|
+
transform = { [propkeys[0]]: '`data`' }
|
|
114
191
|
}
|
|
115
192
|
else {
|
|
116
|
-
// Use sub property with an id
|
|
117
193
|
for (let pk of propkeys) {
|
|
118
194
|
if (schema.properties[pk].properties?.id) {
|
|
119
|
-
|
|
195
|
+
transform = { [pk]: '`data`' }
|
|
120
196
|
break
|
|
121
197
|
}
|
|
122
198
|
}
|
|
@@ -125,27 +201,26 @@ const operationTransform = async function(
|
|
|
125
201
|
}
|
|
126
202
|
}
|
|
127
203
|
|
|
128
|
-
|
|
129
|
-
return place
|
|
204
|
+
return transform
|
|
130
205
|
}
|
|
131
206
|
|
|
132
207
|
|
|
133
208
|
const opBuilder: any = {
|
|
134
209
|
any: (entityModel: any, pathdef: any, op: any, path: any, entity: any, model: any) => {
|
|
135
|
-
// console.log('OP', op, pathdef, path, entity)
|
|
136
210
|
const opname = op.key$
|
|
137
|
-
const method = op.
|
|
211
|
+
const method = op.method
|
|
138
212
|
const kind = OPKIND[opname]
|
|
139
213
|
|
|
140
|
-
// console.log('EM', entityModel.name)
|
|
141
|
-
|
|
142
214
|
const em = entityModel.op[opname] = {
|
|
143
215
|
path: path.key$,
|
|
144
|
-
method
|
|
216
|
+
method,
|
|
145
217
|
kind,
|
|
146
218
|
param: {},
|
|
147
219
|
query: {},
|
|
148
|
-
|
|
220
|
+
transform: {
|
|
221
|
+
inward: resolveTransform(op, kind, 'inward', pathdef),
|
|
222
|
+
outward: resolveTransform(op, kind, 'outward', pathdef),
|
|
223
|
+
}
|
|
149
224
|
}
|
|
150
225
|
|
|
151
226
|
fixName(em, op.key$)
|
package/src/transform.ts
CHANGED
|
@@ -70,30 +70,17 @@ const OPKIND: any = {
|
|
|
70
70
|
|
|
71
71
|
|
|
72
72
|
const GuideShape = Gubu({
|
|
73
|
-
/*
|
|
74
|
-
entity: Child({
|
|
75
|
-
key$: '',
|
|
76
|
-
name: String,
|
|
77
|
-
path: Child({
|
|
78
|
-
op: Child({
|
|
79
|
-
method: Exact('get', 'post', 'put', 'patch', 'delete'),
|
|
80
|
-
place: ''
|
|
81
|
-
})
|
|
82
|
-
})
|
|
83
|
-
}),
|
|
84
|
-
*/
|
|
85
73
|
entity: {},
|
|
86
74
|
control: {},
|
|
87
75
|
transform: {},
|
|
76
|
+
manual: {},
|
|
88
77
|
})
|
|
89
78
|
|
|
90
79
|
type Guide = ReturnType<typeof GuideShape>
|
|
91
80
|
|
|
92
81
|
|
|
93
82
|
async function resolveTransforms(ctx: TransformCtx): Promise<TransformSpec> {
|
|
94
|
-
const { log, model: { main: { guide } } } = ctx
|
|
95
|
-
|
|
96
|
-
// console.dir(api, { depth: null })
|
|
83
|
+
const { log, model: { main: { api: { guide } } } } = ctx
|
|
97
84
|
|
|
98
85
|
const tspec: TransformSpec = {
|
|
99
86
|
transform: []
|
|
@@ -117,17 +104,15 @@ async function resolveTransforms(ctx: TransformCtx): Promise<TransformSpec> {
|
|
|
117
104
|
tspec.transform.push(transform)
|
|
118
105
|
}
|
|
119
106
|
|
|
120
|
-
// console.log('TSPEC', tspec)
|
|
121
107
|
return tspec
|
|
122
108
|
}
|
|
123
109
|
|
|
124
110
|
|
|
125
111
|
async function resolveTransform(tn: string, ctx: TransformCtx) {
|
|
126
|
-
const { log, defpath, model: { guide } } = ctx
|
|
112
|
+
const { log, defpath, model: { main: { api: { guide } } } } = ctx
|
|
127
113
|
|
|
128
114
|
let transform = TRANSFORM[tn]
|
|
129
115
|
if (transform) {
|
|
130
|
-
// console.log('resolveTransform', tn, transform)
|
|
131
116
|
return transform
|
|
132
117
|
}
|
|
133
118
|
|
|
@@ -174,7 +159,7 @@ async function processTransforms(
|
|
|
174
159
|
results: []
|
|
175
160
|
}
|
|
176
161
|
|
|
177
|
-
const guide: Guide = GuideShape(ctx.model.main.guide)
|
|
162
|
+
const guide: Guide = GuideShape(ctx.model.main.api.guide)
|
|
178
163
|
|
|
179
164
|
|
|
180
165
|
for (let tI = 0; tI < spec.transform.length; tI++) {
|
|
@@ -202,18 +187,6 @@ async function processTransforms(
|
|
|
202
187
|
|
|
203
188
|
|
|
204
189
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
/*
|
|
208
|
-
function extractFields(properties: any) {
|
|
209
|
-
const fieldMap = each(properties)
|
|
210
|
-
.reduce((a: any, p: any) => (a[p.key$] =
|
|
211
|
-
{ name: p.key$, kind: camelify(p.type) }, a), {})
|
|
212
|
-
return fieldMap
|
|
213
|
-
}
|
|
214
|
-
*/
|
|
215
|
-
|
|
216
|
-
|
|
217
190
|
function fixName(base: any, name: string, prop = 'name') {
|
|
218
191
|
base[prop.toLowerCase()] = name.toLowerCase()
|
|
219
192
|
base[camelify(prop)] = camelify(name)
|