@voxgig/apidef 1.9.0 → 2.0.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/dist/apidef.d.ts +3 -29
- package/dist/apidef.js +65 -186
- package/dist/apidef.js.map +1 -1
- package/dist/builder/entity/apiEntity.d.ts +3 -0
- package/dist/builder/entity/apiEntity.js +51 -0
- package/dist/builder/entity/apiEntity.js.map +1 -0
- package/dist/builder/entity/def.d.ts +3 -0
- package/dist/builder/entity/def.js +19 -0
- package/dist/builder/entity/def.js.map +1 -0
- package/dist/builder/entity.d.ts +2 -0
- package/dist/builder/entity.js +30 -0
- package/dist/builder/entity.js.map +1 -0
- package/dist/builder/flow/flowHeuristic01.d.ts +2 -0
- package/dist/builder/flow/flowHeuristic01.js +153 -0
- package/dist/builder/flow/flowHeuristic01.js.map +1 -0
- package/dist/builder/flow.d.ts +2 -0
- package/dist/builder/flow.js +41 -0
- package/dist/builder/flow.js.map +1 -0
- package/dist/guide/heuristic01.d.ts +2 -0
- package/dist/guide/heuristic01.js +119 -0
- package/dist/guide/heuristic01.js.map +1 -0
- package/dist/guide.d.ts +2 -0
- package/dist/guide.js +60 -0
- package/dist/guide.js.map +1 -0
- package/dist/parse.d.ts +1 -1
- package/dist/parse.js +5 -4
- package/dist/parse.js.map +1 -1
- package/dist/resolver.d.ts +2 -0
- package/dist/resolver.js +62 -0
- package/dist/resolver.js.map +1 -0
- package/dist/transform/entity.js +25 -4
- package/dist/transform/entity.js.map +1 -1
- package/dist/transform/field.js +4 -84
- package/dist/transform/field.js.map +1 -1
- package/dist/transform/operation.d.ts +2 -2
- package/dist/transform/operation.js +60 -30
- package/dist/transform/operation.js.map +1 -1
- package/dist/transform/top.d.ts +2 -2
- package/dist/transform/top.js +5 -4
- package/dist/transform/top.js.map +1 -1
- package/dist/transform.d.ts +1 -1
- package/dist/transform.js +20 -10
- package/dist/transform.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types.d.ts +691 -0
- package/dist/types.js +39 -0
- package/dist/types.js.map +1 -0
- package/dist/utility.d.ts +5 -0
- package/dist/utility.js +84 -0
- package/dist/utility.js.map +1 -0
- package/model/apidef.jsonic +28 -24
- package/package.json +9 -7
- package/src/apidef.ts +94 -271
- package/src/builder/entity/apiEntity.ts +88 -0
- package/src/builder/entity/def.ts +44 -0
- package/src/builder/entity.ts +54 -0
- package/src/builder/flow/flowHeuristic01.ts +200 -0
- package/src/builder/flow.ts +61 -0
- package/src/guide/heuristic01.ts +178 -0
- package/src/guide.ts +87 -0
- package/src/parse.ts +6 -4
- package/src/resolver.ts +91 -0
- package/src/transform/entity.ts +36 -10
- package/src/transform/field.ts +9 -92
- package/src/transform/operation.ts +112 -46
- package/src/transform/top.ts +11 -9
- package/src/transform.ts +22 -11
- package/src/types.ts +89 -0
- package/src/utility.ts +161 -0
- package/dist/transform/manual.d.ts +0 -3
- package/dist/transform/manual.js +0 -12
- package/dist/transform/manual.js.map +0 -1
- package/src/transform/manual.ts +0 -29
package/src/parse.ts
CHANGED
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
import { bundleFromString, createConfig } from '@redocly/openapi-core'
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
|
|
7
|
+
// Parse an API definition source into a JSON sructure.
|
|
8
|
+
async function parse(kind: string, source: any, meta?: any) {
|
|
7
9
|
if ('OpenAPI' === kind) {
|
|
8
|
-
return parseOpenAPI(source)
|
|
10
|
+
return parseOpenAPI(source, meta)
|
|
9
11
|
}
|
|
10
12
|
else {
|
|
11
13
|
throw new Error('@voxgig/apidef-parse: unknown kind: ' + kind)
|
|
@@ -13,8 +15,8 @@ async function parse(kind: string, source: any) {
|
|
|
13
15
|
}
|
|
14
16
|
|
|
15
17
|
|
|
16
|
-
async function parseOpenAPI(source: any) {
|
|
17
|
-
const config = await createConfig({})
|
|
18
|
+
async function parseOpenAPI(source: any, meta?: any) {
|
|
19
|
+
const config = await createConfig(meta?.config || {})
|
|
18
20
|
let bundle
|
|
19
21
|
|
|
20
22
|
bundle = await bundleFromString({
|
package/src/resolver.ts
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/* Copyright (c) 2024-2025 Voxgig, MIT License */
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
import Path from 'node:path'
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
async function resolveElements(
|
|
8
|
+
ctx: any,
|
|
9
|
+
kind: string,
|
|
10
|
+
subkind: string,
|
|
11
|
+
standard: Record<string, any>
|
|
12
|
+
) {
|
|
13
|
+
|
|
14
|
+
const { log, model } = ctx
|
|
15
|
+
|
|
16
|
+
// TODO: model access should be via a utility that generates
|
|
17
|
+
// useful errors when the target is missing
|
|
18
|
+
const control = model.main.api.guide.control[kind][subkind]
|
|
19
|
+
|
|
20
|
+
const target = kind + '.' + subkind
|
|
21
|
+
|
|
22
|
+
const elementNames = control.order
|
|
23
|
+
.split(/\s*,\s*/)
|
|
24
|
+
.map((t: string) => t.trim())
|
|
25
|
+
.filter((elem: string) => '' != elem)
|
|
26
|
+
|
|
27
|
+
log.info({
|
|
28
|
+
point: 'element', note: target + ': order: ' + elementNames.join(';'),
|
|
29
|
+
order: elementNames
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
const elementResults: any = []
|
|
33
|
+
|
|
34
|
+
for (const en of elementNames) {
|
|
35
|
+
log.debug({ point: 'element', note: target + ': ' + en })
|
|
36
|
+
const element = await resolveElement(en, control, target, standard, ctx)
|
|
37
|
+
const result = await element(ctx)
|
|
38
|
+
elementResults.push(result)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return elementResults
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
async function resolveElement(
|
|
46
|
+
en: string,
|
|
47
|
+
control: any,
|
|
48
|
+
target: string,
|
|
49
|
+
standard: Record<string, any>,
|
|
50
|
+
ctx: any
|
|
51
|
+
) {
|
|
52
|
+
const { log } = ctx
|
|
53
|
+
|
|
54
|
+
let element = standard[en]
|
|
55
|
+
if (element) {
|
|
56
|
+
return element
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const elemdef = control.element[en]
|
|
60
|
+
if (null == elemdef) {
|
|
61
|
+
const err = new Error('Unknown element: ' + en)
|
|
62
|
+
log.error({ what: 'element', element: target + ': ' + en, fail: 'unknown', err })
|
|
63
|
+
throw err
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (!en.startsWith('custom')) {
|
|
67
|
+
const err =
|
|
68
|
+
new Error('Custom element name must start with "custom": ' + en)
|
|
69
|
+
log.error({ what: 'element', element: target + ': ' + en, fail: 'prefix', err })
|
|
70
|
+
throw err
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const customtpath = Path.join(ctx.defpath, elemdef.load)
|
|
74
|
+
try {
|
|
75
|
+
const elementModule = require(customtpath)
|
|
76
|
+
element = elementModule[en]
|
|
77
|
+
}
|
|
78
|
+
catch (e: any) {
|
|
79
|
+
const err = new Error('Custom element not found: ' +
|
|
80
|
+
customtpath + ': ' + e.message)
|
|
81
|
+
log.error({ what: 'element', element: target + ': ' + en, fail: 'require', err })
|
|
82
|
+
throw err
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return element
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
export {
|
|
90
|
+
resolveElements,
|
|
91
|
+
}
|
package/src/transform/entity.ts
CHANGED
|
@@ -1,38 +1,47 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
|
-
import { each } from 'jostraca'
|
|
3
|
+
import { each, snakify } from 'jostraca'
|
|
4
4
|
|
|
5
|
-
import type {
|
|
5
|
+
import type { TransformResult, Transform } from '../transform'
|
|
6
6
|
|
|
7
7
|
import { fixName } from '../transform'
|
|
8
8
|
|
|
9
|
+
import { depluralize } from '../utility'
|
|
10
|
+
|
|
9
11
|
|
|
10
12
|
const entityTransform: Transform = async function(
|
|
11
|
-
ctx:
|
|
12
|
-
guide: Guide,
|
|
13
|
-
tspec: TransformSpec,
|
|
14
|
-
model: any,
|
|
15
|
-
def: any
|
|
13
|
+
ctx: any,
|
|
14
|
+
// guide: Guide,
|
|
15
|
+
// // tspec: TransformSpec,
|
|
16
|
+
// model: any,
|
|
17
|
+
// def: any
|
|
16
18
|
): Promise<TransformResult> {
|
|
19
|
+
const { apimodel, model, def } = ctx
|
|
20
|
+
const guide = model.main.api.guide
|
|
21
|
+
|
|
17
22
|
let msg = ''
|
|
18
23
|
|
|
19
24
|
each(guide.entity, (guideEntity: any) => {
|
|
20
25
|
const entityName = guideEntity.key$
|
|
21
26
|
ctx.log.debug({ point: 'guide-entity', note: entityName })
|
|
22
27
|
|
|
23
|
-
const entityModel: any =
|
|
28
|
+
const entityModel: any = apimodel.main.api.entity[entityName] = {
|
|
24
29
|
op: {},
|
|
25
30
|
field: {},
|
|
26
31
|
cmd: {},
|
|
27
32
|
id: {
|
|
28
33
|
name: 'id',
|
|
29
34
|
field: 'id',
|
|
30
|
-
}
|
|
35
|
+
},
|
|
36
|
+
ancestors: []
|
|
31
37
|
}
|
|
32
38
|
|
|
33
39
|
fixName(entityModel, guideEntity.key$)
|
|
34
40
|
|
|
35
|
-
|
|
41
|
+
let ancestors: string[] = []
|
|
42
|
+
let ancestorsDone = false
|
|
43
|
+
|
|
44
|
+
each(guideEntity.path, (guidePath: any, pathStr: string) => {
|
|
36
45
|
const path = guidePath.key$
|
|
37
46
|
const pathdef = def.paths[path]
|
|
38
47
|
|
|
@@ -47,8 +56,25 @@ const entityTransform: Transform = async function(
|
|
|
47
56
|
.filter((p: string) => p.startsWith('{'))
|
|
48
57
|
.map((p: string) => p.substring(1, p.length - 1))
|
|
49
58
|
|
|
59
|
+
if (!ancestorsDone) {
|
|
60
|
+
// Find all path sections matching /foo/{..param..} and build ancestors array
|
|
61
|
+
const paramRegex = /\/([a-zA-Z0-9_-]+)\/\{[a-zA-Z0-9_-]+\}/g
|
|
62
|
+
let m
|
|
63
|
+
while ((m = paramRegex.exec(pathStr)) !== null) {
|
|
64
|
+
// Skip if this is the last section (the entity itself)
|
|
65
|
+
const remainingPath = pathStr.substring(m.index + m[0].length)
|
|
66
|
+
if (remainingPath.length > 0) {
|
|
67
|
+
const ancestorName = depluralize(snakify(m[1]))
|
|
68
|
+
ancestors.push(ancestorName)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
ancestorsDone = true
|
|
73
|
+
}
|
|
50
74
|
})
|
|
51
75
|
|
|
76
|
+
entityModel.ancestors = ancestors
|
|
77
|
+
|
|
52
78
|
msg += guideEntity.name + ' '
|
|
53
79
|
})
|
|
54
80
|
|
package/src/transform/field.ts
CHANGED
|
@@ -2,25 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|
import { each, getx } from 'jostraca'
|
|
4
4
|
|
|
5
|
-
import type {
|
|
5
|
+
import type { TransformResult, Transform } from '../transform'
|
|
6
6
|
|
|
7
7
|
import { fixName } from '../transform'
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
const fieldTransform: Transform = async function(
|
|
12
|
-
ctx:
|
|
13
|
-
guide: Guide,
|
|
14
|
-
tspec: TransformSpec,
|
|
15
|
-
model: any,
|
|
16
|
-
def: any
|
|
12
|
+
ctx: any,
|
|
13
|
+
// guide: Guide,
|
|
14
|
+
// // tspec: TransformSpec,
|
|
15
|
+
// model: any,
|
|
16
|
+
// def: any
|
|
17
17
|
): Promise<TransformResult> {
|
|
18
|
+
const { apimodel, model, def } = ctx
|
|
19
|
+
const guide = model.main.api.guide
|
|
18
20
|
|
|
19
21
|
let msg = 'fields: '
|
|
20
22
|
|
|
21
23
|
each(guide.entity, (guideEntity: any) => {
|
|
22
24
|
const entityName = guideEntity.key$
|
|
23
|
-
const entityModel =
|
|
25
|
+
const entityModel = apimodel.main.api.entity[entityName]
|
|
24
26
|
|
|
25
27
|
let fieldCount = 0
|
|
26
28
|
each(guideEntity.path, (guidePath: any) => {
|
|
@@ -96,88 +98,3 @@ export {
|
|
|
96
98
|
fieldTransform
|
|
97
99
|
}
|
|
98
100
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
/*
|
|
103
|
-
|
|
104
|
-
# API Specification Transform Guide
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
@"@voxgig/apidef/model/guide.jsonic"
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
guide: control: transform: openapi: order: `
|
|
111
|
-
|
|
112
|
-
top,
|
|
113
|
-
entity,
|
|
114
|
-
operation,
|
|
115
|
-
field,
|
|
116
|
-
customField,
|
|
117
|
-
|
|
118
|
-
`
|
|
119
|
-
|
|
120
|
-
guide: transform: customField: {
|
|
121
|
-
load: 'customField.js'
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
guide: entity: {
|
|
126
|
-
pet: path: {
|
|
127
|
-
'/pet/{petId}': {
|
|
128
|
-
op:{ load: 'get', create: 'post', update: 'put' }
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
pet: test: {
|
|
132
|
-
quick: {
|
|
133
|
-
active: true,
|
|
134
|
-
create: { id: 1, name:'Rex' },
|
|
135
|
-
load: { id: 1 },
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
# direct custom definition
|
|
140
|
-
pet: def: {}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
const { each, getx } = require('jostraca')
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
async function customField(ctx, tspec, model, def) {
|
|
150
|
-
const { spec, util: {fixName} } = ctx
|
|
151
|
-
|
|
152
|
-
const nameField = {
|
|
153
|
-
name: 'name',
|
|
154
|
-
type: 'string',
|
|
155
|
-
short: 'Name of pet'
|
|
156
|
-
}
|
|
157
|
-
fixName(nameField, nameField.name)
|
|
158
|
-
fixName(nameField, nameField.type, 'type')
|
|
159
|
-
|
|
160
|
-
const ageField = {
|
|
161
|
-
name: 'age',
|
|
162
|
-
type: 'number',
|
|
163
|
-
short: 'Age of pet'
|
|
164
|
-
}
|
|
165
|
-
fixName(ageField, ageField.name)
|
|
166
|
-
fixName(ageField, ageField.type, 'type')
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
Object.assign(model.main.api.entity.pet.field, {
|
|
170
|
-
name: nameField,
|
|
171
|
-
age: ageField,
|
|
172
|
-
})
|
|
173
|
-
|
|
174
|
-
return { ok: true }
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
module.exports = {
|
|
179
|
-
customField
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
*/
|
|
@@ -2,58 +2,85 @@
|
|
|
2
2
|
|
|
3
3
|
import { each, getx } from 'jostraca'
|
|
4
4
|
|
|
5
|
-
import type {
|
|
5
|
+
import type { TransformResult } from '../transform'
|
|
6
6
|
|
|
7
7
|
import { fixName, OPKIND } from '../transform'
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
const operationTransform = async function(
|
|
12
|
-
ctx:
|
|
13
|
-
guide: Guide,
|
|
14
|
-
tspec: TransformSpec,
|
|
15
|
-
model: any,
|
|
16
|
-
def: any
|
|
12
|
+
ctx: any,
|
|
13
|
+
// guide: Guide,
|
|
14
|
+
// // tspec: TransformSpec,
|
|
15
|
+
// model: any,
|
|
16
|
+
// def: any
|
|
17
17
|
): Promise<TransformResult> {
|
|
18
|
+
const { apimodel, model, def } = ctx
|
|
19
|
+
const guide = model.main.api.guide
|
|
18
20
|
|
|
19
21
|
let msg = 'operations: '
|
|
20
22
|
|
|
21
|
-
const paramBuilder = (
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
const paramBuilder = (
|
|
24
|
+
paramMap: any,
|
|
25
|
+
paramDef: any,
|
|
26
|
+
opModel: any,
|
|
27
|
+
entityModel: any,
|
|
28
|
+
pathdef: any,
|
|
29
|
+
op: any,
|
|
30
|
+
path: any,
|
|
31
|
+
entity: any,
|
|
32
|
+
model: any
|
|
33
|
+
) => {
|
|
24
34
|
|
|
25
|
-
paramMap[paramDef.name] = {
|
|
35
|
+
const paramSpec: any = paramMap[paramDef.name] = {
|
|
26
36
|
required: paramDef.required
|
|
27
37
|
}
|
|
28
|
-
fixName(
|
|
38
|
+
fixName(paramSpec, paramDef.name)
|
|
29
39
|
|
|
30
40
|
const type = paramDef.schema ? paramDef.schema.type : paramDef.type
|
|
31
|
-
fixName(
|
|
41
|
+
fixName(paramSpec, type, 'type')
|
|
42
|
+
|
|
43
|
+
// Path params are always required.
|
|
44
|
+
opModel.validate.params[paramDef.name] = `\`$${paramSpec.TYPE}\``
|
|
32
45
|
}
|
|
33
46
|
|
|
34
47
|
|
|
35
|
-
const queryBuilder = (
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
48
|
+
const queryBuilder = (
|
|
49
|
+
queryMap: any,
|
|
50
|
+
queryDef: any,
|
|
51
|
+
opModel: any,
|
|
52
|
+
entityModel: any,
|
|
53
|
+
pathdef: any,
|
|
54
|
+
op: any,
|
|
55
|
+
path: any,
|
|
56
|
+
entity: any,
|
|
57
|
+
model: any
|
|
58
|
+
) => {
|
|
59
|
+
const querySpec: any = queryMap[queryDef.name] = {
|
|
39
60
|
required: queryDef.required
|
|
40
61
|
}
|
|
41
62
|
fixName(queryMap[queryDef.name], queryDef.name)
|
|
42
63
|
|
|
43
64
|
const type = queryDef.schema ? queryDef.schema.type : queryDef.type
|
|
44
65
|
fixName(queryMap[queryDef.name], type, 'type')
|
|
66
|
+
|
|
67
|
+
if (queryDef.required) {
|
|
68
|
+
opModel.validate.params[queryDef.name] = `\`$${querySpec.TYPE}\``
|
|
69
|
+
}
|
|
45
70
|
}
|
|
46
71
|
|
|
47
72
|
|
|
48
73
|
// Resolve the JSON structure of the request or response.
|
|
49
74
|
// NOTE: uses heuristics.
|
|
50
75
|
const resolveTransform = (
|
|
76
|
+
entityModel: any,
|
|
51
77
|
op: any,
|
|
52
78
|
kind: 'res' | 'req',
|
|
53
79
|
direction: 'resform' | 'reqform',
|
|
54
80
|
pathdef: any
|
|
55
81
|
) => {
|
|
56
82
|
let out
|
|
83
|
+
let why = 'none'
|
|
57
84
|
|
|
58
85
|
if (null != op.transform?.[direction]) {
|
|
59
86
|
out = op.transform[direction]
|
|
@@ -64,46 +91,60 @@ const operationTransform = async function(
|
|
|
64
91
|
const mdef = pathdef[method]
|
|
65
92
|
|
|
66
93
|
// TODO: fix getx
|
|
67
|
-
const content = 'res' === kind ?
|
|
94
|
+
// const content = 'res' === kind ?
|
|
95
|
+
const content = 'resform' === direction ?
|
|
68
96
|
(getx(mdef, 'responses.200.content') ||
|
|
69
97
|
getx(mdef, 'responses.201.content')) :
|
|
70
98
|
getx(mdef, 'requestBody.content')
|
|
71
99
|
|
|
100
|
+
if (content) {
|
|
72
101
|
|
|
73
|
-
|
|
102
|
+
const schema = content['application/json']?.schema
|
|
74
103
|
|
|
75
|
-
|
|
104
|
+
const propkeys = null == schema?.properties ? [] : Object.keys(schema.properties)
|
|
76
105
|
|
|
77
|
-
|
|
78
|
-
|
|
106
|
+
const resolveDirectionTransform =
|
|
107
|
+
'resform' === direction ? resolveResponseTransform : resolveRequestTransform
|
|
79
108
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
109
|
+
//const [transform, why]
|
|
110
|
+
;[out, why]
|
|
111
|
+
= resolveDirectionTransform(
|
|
112
|
+
entityModel,
|
|
113
|
+
op,
|
|
114
|
+
kind,
|
|
115
|
+
direction,
|
|
116
|
+
method,
|
|
117
|
+
mdef,
|
|
118
|
+
content,
|
|
119
|
+
schema,
|
|
120
|
+
propkeys
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
// out = JSON.stringify(transform)
|
|
124
|
+
// out = transform
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
out = 'res' === kind ? '`body`' : '`reqdata`'
|
|
128
|
+
}
|
|
92
129
|
}
|
|
93
130
|
|
|
94
|
-
|
|
131
|
+
|
|
132
|
+
return [out, why]
|
|
95
133
|
}
|
|
96
134
|
|
|
97
135
|
|
|
98
136
|
const resolveResponseTransform = (
|
|
137
|
+
entityModel: any,
|
|
99
138
|
op: any,
|
|
100
139
|
kind: 'res' | 'req',
|
|
140
|
+
direction: 'resform' | 'reqform',
|
|
101
141
|
method: string,
|
|
102
142
|
mdef: any,
|
|
103
143
|
content: any,
|
|
104
144
|
schema: any,
|
|
105
145
|
propkeys: any
|
|
106
146
|
) => {
|
|
147
|
+
let why = 'default'
|
|
107
148
|
let transform: any = '`body`'
|
|
108
149
|
|
|
109
150
|
if (null == content || null == schema || null == propkeys) {
|
|
@@ -115,12 +156,14 @@ const operationTransform = async function(
|
|
|
115
156
|
if ('list' === opname) {
|
|
116
157
|
if ('array' !== schema.type) {
|
|
117
158
|
if (1 === propkeys.length) {
|
|
159
|
+
why = 'list-single-prop:' + propkeys[0]
|
|
118
160
|
transform = '`body.' + propkeys[0] + '`'
|
|
119
161
|
}
|
|
120
162
|
else {
|
|
121
163
|
// Use sub property that is an array
|
|
122
164
|
for (let pk of propkeys) {
|
|
123
165
|
if ('array' === schema.properties[pk]?.type) {
|
|
166
|
+
why = 'list-single-array:' + pk
|
|
124
167
|
transform = '`body.' + pk + '`'
|
|
125
168
|
break
|
|
126
169
|
}
|
|
@@ -132,11 +175,13 @@ const operationTransform = async function(
|
|
|
132
175
|
if ('object' === schema.type) {
|
|
133
176
|
if (null == schema.properties.id) {
|
|
134
177
|
if (1 === propkeys.length) {
|
|
178
|
+
why = 'map-single-prop:' + propkeys[0]
|
|
135
179
|
transform = '`body.' + propkeys[0] + '`'
|
|
136
180
|
}
|
|
137
181
|
else {
|
|
138
182
|
for (let pk of propkeys) {
|
|
139
183
|
if (schema.properties[pk].properties?.id) {
|
|
184
|
+
why = 'map-sub-prop:' + pk
|
|
140
185
|
transform = '`body.' + pk + '`'
|
|
141
186
|
break
|
|
142
187
|
}
|
|
@@ -146,13 +191,15 @@ const operationTransform = async function(
|
|
|
146
191
|
}
|
|
147
192
|
}
|
|
148
193
|
|
|
149
|
-
return transform
|
|
194
|
+
return [transform, why]
|
|
150
195
|
}
|
|
151
196
|
|
|
152
197
|
|
|
153
198
|
const resolveRequestTransform = (
|
|
199
|
+
entityModel: any,
|
|
154
200
|
op: any,
|
|
155
201
|
kind: 'res' | 'req',
|
|
202
|
+
direction: 'resform' | 'reqform',
|
|
156
203
|
method: string,
|
|
157
204
|
mdef: any,
|
|
158
205
|
content: any,
|
|
@@ -160,6 +207,7 @@ const operationTransform = async function(
|
|
|
160
207
|
propkeys: any
|
|
161
208
|
) => {
|
|
162
209
|
let transform: any = '`data`'
|
|
210
|
+
let why = 'default'
|
|
163
211
|
|
|
164
212
|
if (null == content || null == schema || null == propkeys) {
|
|
165
213
|
return transform
|
|
@@ -170,12 +218,14 @@ const operationTransform = async function(
|
|
|
170
218
|
if ('list' === opname) {
|
|
171
219
|
if ('array' !== schema.type) {
|
|
172
220
|
if (1 === propkeys.length) {
|
|
221
|
+
why = 'list-single-prop:' + propkeys[0]
|
|
173
222
|
transform = { [propkeys[0]]: '`data`' }
|
|
174
223
|
}
|
|
175
224
|
else {
|
|
176
225
|
// Use sub property that is an array
|
|
177
226
|
for (let pk of propkeys) {
|
|
178
227
|
if ('array' === schema.properties[pk]?.type) {
|
|
228
|
+
why = 'list-single-array:' + pk
|
|
179
229
|
transform = { [pk]: '`data`' }
|
|
180
230
|
break
|
|
181
231
|
}
|
|
@@ -187,11 +237,13 @@ const operationTransform = async function(
|
|
|
187
237
|
if ('object' === schema.type) {
|
|
188
238
|
if (null == schema.properties.id) {
|
|
189
239
|
if (1 === propkeys.length) {
|
|
240
|
+
why = 'map-single-prop:' + propkeys[0]
|
|
190
241
|
transform = { [propkeys[0]]: '`data`' }
|
|
191
242
|
}
|
|
192
243
|
else {
|
|
193
244
|
for (let pk of propkeys) {
|
|
194
245
|
if (schema.properties[pk].properties?.id) {
|
|
246
|
+
why = 'map-sub-prop:' + pk
|
|
195
247
|
transform = { [pk]: '`data`' }
|
|
196
248
|
break
|
|
197
249
|
}
|
|
@@ -201,7 +253,7 @@ const operationTransform = async function(
|
|
|
201
253
|
}
|
|
202
254
|
}
|
|
203
255
|
|
|
204
|
-
return transform
|
|
256
|
+
return [transform, why]
|
|
205
257
|
}
|
|
206
258
|
|
|
207
259
|
|
|
@@ -211,26 +263,39 @@ const operationTransform = async function(
|
|
|
211
263
|
const method = op.method
|
|
212
264
|
const kind = OPKIND[opname]
|
|
213
265
|
|
|
214
|
-
const
|
|
266
|
+
const [resform, resform_COMMENT] =
|
|
267
|
+
resolveTransform(entityModel, op, kind, 'resform', pathdef)
|
|
268
|
+
|
|
269
|
+
const [reqform, reqform_COMMENT] =
|
|
270
|
+
resolveTransform(entityModel, op, kind, 'reqform', pathdef)
|
|
271
|
+
|
|
272
|
+
const opModel = entityModel.op[opname] = {
|
|
215
273
|
path: path.key$,
|
|
216
274
|
method,
|
|
217
275
|
kind,
|
|
218
276
|
param: {},
|
|
219
277
|
query: {},
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
278
|
+
|
|
279
|
+
resform_COMMENT: 'derivation: ' + resform_COMMENT,
|
|
280
|
+
resform,
|
|
281
|
+
|
|
282
|
+
reqform_COMMENT: 'derivation: ' + reqform_COMMENT,
|
|
283
|
+
reqform,
|
|
284
|
+
|
|
285
|
+
validate: {
|
|
286
|
+
params: { '`$OPEN`': true }
|
|
287
|
+
}
|
|
224
288
|
}
|
|
225
289
|
|
|
226
|
-
fixName(
|
|
290
|
+
fixName(opModel, op.key$)
|
|
227
291
|
|
|
228
292
|
// Params are in the path
|
|
229
293
|
if (0 < path.params$.length) {
|
|
230
294
|
let params = getx(pathdef[method], 'parameters?in=path') || []
|
|
231
295
|
if (Array.isArray(params)) {
|
|
232
296
|
params.reduce((a: any, p: any) =>
|
|
233
|
-
|
|
297
|
+
(paramBuilder(a, p, opModel, entityModel,
|
|
298
|
+
pathdef, op, path, entity, model), a), opModel.param)
|
|
234
299
|
}
|
|
235
300
|
}
|
|
236
301
|
|
|
@@ -238,10 +303,11 @@ const operationTransform = async function(
|
|
|
238
303
|
let queries = getx(pathdef[op.val$], 'parameters?in!=path') || []
|
|
239
304
|
if (Array.isArray(queries)) {
|
|
240
305
|
queries.reduce((a: any, p: any) =>
|
|
241
|
-
|
|
306
|
+
(queryBuilder(a, p, opModel, entityModel,
|
|
307
|
+
pathdef, op, path, entity, model), a), opModel.query)
|
|
242
308
|
}
|
|
243
309
|
|
|
244
|
-
return
|
|
310
|
+
return opModel
|
|
245
311
|
},
|
|
246
312
|
|
|
247
313
|
|
|
@@ -270,7 +336,7 @@ const operationTransform = async function(
|
|
|
270
336
|
|
|
271
337
|
each(guide.entity, (guideEntity: any) => {
|
|
272
338
|
let opcount = 0
|
|
273
|
-
const entityModel =
|
|
339
|
+
const entityModel = apimodel.main.api.entity[guideEntity.key$]
|
|
274
340
|
each(guideEntity.path, (guidePath: any) => {
|
|
275
341
|
const pathdef = def.paths[guidePath.key$]
|
|
276
342
|
|
package/src/transform/top.ts
CHANGED
|
@@ -1,22 +1,24 @@
|
|
|
1
1
|
|
|
2
2
|
import { each, getx } from 'jostraca'
|
|
3
3
|
|
|
4
|
-
import type {
|
|
4
|
+
import type { TransformResult } from '../transform'
|
|
5
5
|
|
|
6
6
|
import { fixName } from '../transform'
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
const topTransform = async function(
|
|
10
|
-
ctx:
|
|
11
|
-
guide: Guide,
|
|
12
|
-
tspec: TransformSpec,
|
|
13
|
-
model: any,
|
|
14
|
-
def: any
|
|
10
|
+
ctx: any,
|
|
11
|
+
// guide: Guide,
|
|
12
|
+
// // tspec: TransformSpec,
|
|
13
|
+
// model: any,
|
|
14
|
+
// def: any
|
|
15
15
|
): Promise<TransformResult> {
|
|
16
|
-
const {
|
|
16
|
+
const { apimodel, def } = ctx
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
// const { spec } = ctx
|
|
19
|
+
|
|
20
|
+
apimodel.main.def.info = def.info
|
|
21
|
+
apimodel.main.def.servers = def.servers
|
|
20
22
|
|
|
21
23
|
return { ok: true, msg: 'top' }
|
|
22
24
|
}
|