@voxgig/apidef 2.0.2 → 2.2.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.js +14 -1
- package/dist/apidef.js.map +1 -1
- package/dist/guide/heuristic01.js +189 -50
- package/dist/guide/heuristic01.js.map +1 -1
- package/dist/guide.js +36 -8
- package/dist/guide.js.map +1 -1
- package/dist/parse.d.ts +2 -1
- package/dist/parse.js +81 -3
- package/dist/parse.js.map +1 -1
- package/dist/transform/clean.d.ts +3 -0
- package/dist/transform/clean.js +16 -0
- package/dist/transform/clean.js.map +1 -0
- package/dist/transform/field.js +24 -1
- package/dist/transform/field.js.map +1 -1
- package/dist/transform/operation.js +88 -23
- package/dist/transform/operation.js.map +1 -1
- package/dist/transform.d.ts +1 -8
- package/dist/transform.js +121 -94
- package/dist/transform.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utility.d.ts +6 -1
- package/dist/utility.js +42 -14
- package/dist/utility.js.map +1 -1
- package/model/apidef.jsonic +1 -0
- package/package.json +9 -10
- package/src/apidef.ts +24 -3
- package/src/guide/heuristic01.ts +263 -59
- package/src/guide.ts +48 -9
- package/src/parse.ts +106 -4
- package/src/transform/clean.ts +28 -0
- package/src/transform/field.ts +27 -1
- package/src/transform/operation.ts +118 -31
- package/src/transform.ts +28 -21
- package/src/utility.ts +48 -14
package/dist/utility.js
CHANGED
|
@@ -1,8 +1,25 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getdlog = getdlog;
|
|
3
7
|
exports.loadFile = loadFile;
|
|
4
8
|
exports.formatJsonSrc = formatJsonSrc;
|
|
5
9
|
exports.depluralize = depluralize;
|
|
10
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
11
|
+
function getdlog(tagin, filepath) {
|
|
12
|
+
const tag = tagin || '-';
|
|
13
|
+
const file = node_path_1.default.basename(filepath || '-');
|
|
14
|
+
const g = global;
|
|
15
|
+
g.__dlog__ = (g.__dlog__ || []);
|
|
16
|
+
const dlog = (...args) => g.__dlog__.push([tag, file, Date.now(), ...args]);
|
|
17
|
+
dlog.tag = tag;
|
|
18
|
+
dlog.file = file;
|
|
19
|
+
dlog.log = (filepath, f) => (f = null == filepath ? null : node_path_1.default.basename(filepath),
|
|
20
|
+
g.__dlog__.filter((n) => n[0] === tag && (null == f || n[2] === f)));
|
|
21
|
+
return dlog;
|
|
22
|
+
}
|
|
6
23
|
function loadFile(path, what, fs, log) {
|
|
7
24
|
try {
|
|
8
25
|
const source = fs.readFileSync(path, 'utf8');
|
|
@@ -26,32 +43,43 @@ function depluralize(word) {
|
|
|
26
43
|
}
|
|
27
44
|
// Common irregular plurals
|
|
28
45
|
const irregulars = {
|
|
46
|
+
'analyses': 'analysis',
|
|
47
|
+
'appendices': 'appendix',
|
|
48
|
+
'axes': 'axis',
|
|
29
49
|
'children': 'child',
|
|
30
|
-
'
|
|
31
|
-
'
|
|
32
|
-
'
|
|
50
|
+
'courses': 'course',
|
|
51
|
+
'crises': 'crisis',
|
|
52
|
+
'criteria': 'criterion',
|
|
53
|
+
'data': 'datum',
|
|
54
|
+
'diagnoses': 'diagnosis',
|
|
33
55
|
'feet': 'foot',
|
|
56
|
+
'furnace': 'furnaces',
|
|
34
57
|
'geese': 'goose',
|
|
35
|
-
'
|
|
36
|
-
'
|
|
37
|
-
'data': 'datum',
|
|
38
|
-
'criteria': 'criterion',
|
|
39
|
-
'phenomena': 'phenomenon',
|
|
58
|
+
'horses': 'horse',
|
|
59
|
+
'house': 'houses',
|
|
40
60
|
'indices': 'index',
|
|
61
|
+
'license': 'licenses',
|
|
41
62
|
'matrices': 'matrix',
|
|
42
|
-
'
|
|
43
|
-
'
|
|
44
|
-
'
|
|
45
|
-
'crises': 'crisis',
|
|
46
|
-
'diagnoses': 'diagnosis',
|
|
63
|
+
'men': 'man',
|
|
64
|
+
'mice': 'mouse',
|
|
65
|
+
'notice': 'notices',
|
|
47
66
|
'oases': 'oasis',
|
|
67
|
+
'people': 'person',
|
|
68
|
+
'phenomena': 'phenomenon',
|
|
69
|
+
'practice': 'practices',
|
|
70
|
+
'promise': 'promises',
|
|
71
|
+
'teeth': 'tooth',
|
|
48
72
|
'theses': 'thesis',
|
|
49
|
-
'
|
|
73
|
+
'vertices': 'vertex',
|
|
74
|
+
'women': 'woman',
|
|
50
75
|
};
|
|
51
76
|
if (irregulars[word]) {
|
|
52
77
|
return irregulars[word];
|
|
53
78
|
}
|
|
54
79
|
// Rules for regular plurals (applied in order)
|
|
80
|
+
if (word.endsWith('ies') && word.length > 3) {
|
|
81
|
+
return word.slice(0, -3) + 'y';
|
|
82
|
+
}
|
|
55
83
|
// -ies -> -y (cities -> city)
|
|
56
84
|
if (word.endsWith('ies') && word.length > 3) {
|
|
57
85
|
return word.slice(0, -3) + 'y';
|
package/dist/utility.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utility.js","sourceRoot":"","sources":["../src/utility.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"utility.js","sourceRoot":"","sources":["../src/utility.ts"],"names":[],"mappings":"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"}
|
package/model/apidef.jsonic
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voxgig/apidef",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"main": "dist/apidef.js",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"types": "dist/apidef.d.ts",
|
|
@@ -41,23 +41,22 @@
|
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@hapi/code": "^9.0.3",
|
|
43
43
|
"@types/js-yaml": "^4.0.9",
|
|
44
|
-
"@types/node": "24.0
|
|
44
|
+
"@types/node": "24.1.0",
|
|
45
45
|
"aontu": "^0.28.0",
|
|
46
|
-
"esbuild": "^0.25.6",
|
|
47
46
|
"json-schema-to-ts": "^3.1.1",
|
|
48
|
-
"memfs": "^4.
|
|
47
|
+
"memfs": "^4.25.1",
|
|
49
48
|
"patch-package": "^8.0.0",
|
|
50
|
-
"typescript": "^5.
|
|
49
|
+
"typescript": "^5.9.2"
|
|
51
50
|
},
|
|
52
51
|
"dependencies": {
|
|
53
|
-
"@redocly/openapi-core": "^1.34.
|
|
54
|
-
"@voxgig/struct": "^0.0.
|
|
55
|
-
"@voxgig/util": "^0.0
|
|
52
|
+
"@redocly/openapi-core": "^1.34.5",
|
|
53
|
+
"@voxgig/struct": "^0.0.6",
|
|
54
|
+
"@voxgig/util": "^0.2.0",
|
|
56
55
|
"chokidar": "^4.0.3",
|
|
57
56
|
"gubu": "^9.0.0",
|
|
58
|
-
"jostraca": "^0.
|
|
57
|
+
"jostraca": "^0.24.0",
|
|
59
58
|
"pino": "^9.7.0",
|
|
60
|
-
"pino-pretty": "^13.
|
|
59
|
+
"pino-pretty": "^13.1.1",
|
|
61
60
|
"sonic-boom": "^4.2.0"
|
|
62
61
|
}
|
|
63
62
|
}
|
package/src/apidef.ts
CHANGED
|
@@ -28,7 +28,8 @@ import {
|
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
import {
|
|
31
|
-
parse
|
|
31
|
+
parse,
|
|
32
|
+
rewrite,
|
|
32
33
|
} from './parse'
|
|
33
34
|
|
|
34
35
|
|
|
@@ -44,20 +45,25 @@ import {
|
|
|
44
45
|
|
|
45
46
|
import {
|
|
46
47
|
loadFile,
|
|
48
|
+
getdlog,
|
|
47
49
|
} from './utility'
|
|
48
50
|
|
|
49
|
-
|
|
50
51
|
import { topTransform } from './transform/top'
|
|
51
52
|
import { entityTransform } from './transform/entity'
|
|
52
53
|
import { operationTransform } from './transform/operation'
|
|
53
54
|
import { fieldTransform } from './transform/field'
|
|
55
|
+
import { cleanTransform } from './transform/clean'
|
|
54
56
|
|
|
55
57
|
import { makeEntityBuilder } from './builder/entity'
|
|
56
58
|
import { makeFlowBuilder } from './builder/flow'
|
|
57
59
|
|
|
60
|
+
// Log non-fatal wierdness.
|
|
61
|
+
const dlog = getdlog('apidef', __filename)
|
|
62
|
+
|
|
58
63
|
|
|
59
64
|
function ApiDef(opts: ApiDefOptions) {
|
|
60
65
|
|
|
66
|
+
|
|
61
67
|
// TODO: gubu opts!
|
|
62
68
|
const fs = opts.fs || Fs
|
|
63
69
|
const pino = prettyPino('apidef', opts)
|
|
@@ -68,6 +74,7 @@ function ApiDef(opts: ApiDefOptions) {
|
|
|
68
74
|
|
|
69
75
|
async function generate(spec: any) {
|
|
70
76
|
const start = Date.now()
|
|
77
|
+
// dlog('start')
|
|
71
78
|
|
|
72
79
|
const model: Model = OpenModelShape(spec.model)
|
|
73
80
|
const build: Build = OpenBuildShape(spec.build)
|
|
@@ -110,9 +117,15 @@ function ApiDef(opts: ApiDefOptions) {
|
|
|
110
117
|
|
|
111
118
|
const defsrc = loadFile(defpath, 'def', fs, log)
|
|
112
119
|
|
|
113
|
-
|
|
120
|
+
let def = await parse('OpenAPI', defsrc, { file: defpath })
|
|
121
|
+
|
|
122
|
+
def = rewrite(def)
|
|
123
|
+
|
|
124
|
+
fs.writeFileSync(defpath + '.full.json', JSON.stringify(def, null, 2))
|
|
125
|
+
|
|
114
126
|
ctx.def = def
|
|
115
127
|
|
|
128
|
+
|
|
116
129
|
const guideBuilder = await resolveGuide(ctx)
|
|
117
130
|
|
|
118
131
|
|
|
@@ -122,6 +135,7 @@ function ApiDef(opts: ApiDefOptions) {
|
|
|
122
135
|
entity: entityTransform,
|
|
123
136
|
operation: operationTransform,
|
|
124
137
|
field: fieldTransform,
|
|
138
|
+
clean: cleanTransform,
|
|
125
139
|
})
|
|
126
140
|
|
|
127
141
|
const builders = await resolveElements(ctx, 'builder', 'standard', {
|
|
@@ -155,6 +169,13 @@ function ApiDef(opts: ApiDefOptions) {
|
|
|
155
169
|
existing: { txt: { merge: true } }
|
|
156
170
|
}, root)
|
|
157
171
|
|
|
172
|
+
const dlogs = dlog.log()
|
|
173
|
+
if (0 < dlogs.length) {
|
|
174
|
+
for (let dlogentry of dlogs) {
|
|
175
|
+
log.debug({ point: 'generate-warning', dlogentry, note: String(dlogentry) })
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
158
179
|
log.info({ point: 'generate-end', note: 'success', break: true })
|
|
159
180
|
|
|
160
181
|
return {
|
package/src/guide/heuristic01.ts
CHANGED
|
@@ -2,8 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
import { each, snakify, names } from 'jostraca'
|
|
4
4
|
|
|
5
|
+
import { size } from '@voxgig/struct'
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
depluralize,
|
|
10
|
+
getdlog
|
|
11
|
+
} from '../utility'
|
|
7
12
|
|
|
8
13
|
|
|
9
14
|
type EntityDesc = {
|
|
@@ -19,10 +24,12 @@ type EntityPathDesc = {
|
|
|
19
24
|
op: Record<string, any>
|
|
20
25
|
}
|
|
21
26
|
|
|
27
|
+
// Log non-fatal wierdness.
|
|
28
|
+
const dlog = getdlog('apidef', __filename)
|
|
29
|
+
|
|
22
30
|
async function heuristic01(ctx: any): Promise<Record<string, any>> {
|
|
23
31
|
let guide = ctx.model.main.api.guide
|
|
24
32
|
|
|
25
|
-
|
|
26
33
|
const entityDescs = resolveEntityDescs(ctx)
|
|
27
34
|
|
|
28
35
|
// console.log('entityDescs')
|
|
@@ -33,10 +40,16 @@ async function heuristic01(ctx: any): Promise<Record<string, any>> {
|
|
|
33
40
|
entity: entityDescs,
|
|
34
41
|
}
|
|
35
42
|
|
|
43
|
+
// console.log('GUIDE')
|
|
44
|
+
// console.dir(guide, { depth: null })
|
|
45
|
+
|
|
36
46
|
return guide
|
|
37
47
|
}
|
|
38
48
|
|
|
39
49
|
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
40
53
|
const METHOD_IDOP: Record<string, string> = {
|
|
41
54
|
get: 'load',
|
|
42
55
|
post: 'create',
|
|
@@ -51,24 +64,52 @@ function resolveEntityDescs(ctx: any) {
|
|
|
51
64
|
const paths = ctx.def.paths
|
|
52
65
|
|
|
53
66
|
// Analyze paths ending in .../foo/{foo}
|
|
54
|
-
each(paths, (
|
|
67
|
+
each(paths, (pathDef: any, pathStr: string) => {
|
|
55
68
|
|
|
56
69
|
// Look for rightmmost /entname/{entid}.
|
|
57
|
-
|
|
70
|
+
let m = pathStr.match(/\/([a-zA-Z0-1_-]+)(\/\{([a-zA-Z0-1_-]+)\})?$/)
|
|
71
|
+
// const m = pathStr.match(/\/([a-zA-Z0-1_-]+)\/\{([a-zA-Z0-1_-]+)\}$/)
|
|
58
72
|
if (m) {
|
|
59
|
-
const entdesc = resolveEntity(entityDescs,
|
|
73
|
+
// const entdesc = resolveEntity(entityDescs, pathStr, m[1], m[2])
|
|
60
74
|
|
|
75
|
+
each(pathDef, (methodDef: any, methodStr: string) => {
|
|
76
|
+
methodStr = methodStr.toLowerCase()
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
if (!METHOD_IDOP[methodStr]) {
|
|
80
|
+
return
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const entdesc = resolveEntity(entityDescs, pathDef, pathStr, methodDef, methodStr)
|
|
84
|
+
|
|
85
|
+
if (null == entdesc) {
|
|
86
|
+
console.log(
|
|
87
|
+
'WARNING: unable to resolve entity for method ' + methodStr +
|
|
88
|
+
' path ' + pathStr)
|
|
89
|
+
return
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// if (pathStr.includes('courses')) {
|
|
93
|
+
// console.log('ENTRES', pathStr, methodStr)
|
|
94
|
+
// console.dir(ent2, { depth: null })
|
|
95
|
+
// }
|
|
96
|
+
|
|
97
|
+
let opname = resolveOpName(methodStr, methodDef, pathStr, entdesc)
|
|
98
|
+
|
|
99
|
+
if (null == opname) {
|
|
100
|
+
console.log(
|
|
101
|
+
'WARNING: unable to resolve operation for method ' + methodStr +
|
|
102
|
+
' path ' + pathStr)
|
|
103
|
+
return
|
|
104
|
+
}
|
|
61
105
|
|
|
62
|
-
each(pathdef, (mdef, method) => {
|
|
63
|
-
const opname = METHOD_IDOP[method]
|
|
64
|
-
if (null == opname) return;
|
|
65
106
|
|
|
66
107
|
const transform: Record<string, any> = {
|
|
67
108
|
// reqform: '`reqdata`',
|
|
68
109
|
// resform: '`body`',
|
|
69
110
|
}
|
|
70
111
|
|
|
71
|
-
const resokdef =
|
|
112
|
+
const resokdef = methodDef.responses[200] || methodDef.responses[201]
|
|
72
113
|
const resbody = resokdef?.content?.['application/json']?.schema
|
|
73
114
|
if (resbody) {
|
|
74
115
|
if (resbody[entdesc.origname]) {
|
|
@@ -79,7 +120,7 @@ function resolveEntityDescs(ctx: any) {
|
|
|
79
120
|
}
|
|
80
121
|
}
|
|
81
122
|
|
|
82
|
-
const reqdef =
|
|
123
|
+
const reqdef = methodDef.requestBody?.content?.['application/json']?.schema?.properties
|
|
83
124
|
if (reqdef) {
|
|
84
125
|
if (reqdef[entdesc.origname]) {
|
|
85
126
|
transform.reqform = { [entdesc.origname]: '`reqdata`' }
|
|
@@ -90,89 +131,252 @@ function resolveEntityDescs(ctx: any) {
|
|
|
90
131
|
|
|
91
132
|
}
|
|
92
133
|
|
|
93
|
-
const op = entdesc.path[
|
|
134
|
+
const op = entdesc.path[pathStr].op
|
|
94
135
|
|
|
95
136
|
op[opname] = {
|
|
96
137
|
// TODO: in actual guide, remove "standard" method ops since redundant
|
|
97
|
-
method,
|
|
138
|
+
method: methodStr,
|
|
98
139
|
}
|
|
99
140
|
|
|
100
141
|
if (0 < Object.entries(transform).length) {
|
|
101
142
|
op[opname].transform = transform
|
|
102
143
|
}
|
|
144
|
+
|
|
145
|
+
if ('/v2/users/{user_id}/enrollment' === pathStr) {
|
|
146
|
+
console.log('ENT')
|
|
147
|
+
console.dir(entdesc, { depth: null })
|
|
148
|
+
}
|
|
103
149
|
})
|
|
104
150
|
}
|
|
105
151
|
})
|
|
106
152
|
|
|
107
|
-
//
|
|
108
|
-
|
|
153
|
+
// console.log('USER')
|
|
154
|
+
// console.dir(entityDescs.user, { depth: null })
|
|
109
155
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
if (m) {
|
|
113
|
-
const entdesc = resolveEntity(entityDescs, pathstr, m[1])
|
|
156
|
+
return entityDescs
|
|
157
|
+
}
|
|
114
158
|
|
|
115
|
-
if (pathdef.get) {
|
|
116
|
-
const op: Record<string, any> = { list: { method: 'get' } }
|
|
117
|
-
entdesc.path[pathstr] = { op }
|
|
118
159
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
160
|
+
function resolveEntity(
|
|
161
|
+
entityDescs: Record<string, EntityDesc>,
|
|
162
|
+
pathDef: Record<string, any>,
|
|
163
|
+
pathStr: string,
|
|
164
|
+
methodDef: Record<string, any>,
|
|
165
|
+
methodStr: string,
|
|
166
|
+
): EntityDesc | undefined {
|
|
167
|
+
|
|
168
|
+
let entdesc: EntityDesc
|
|
169
|
+
let entname: string = ''
|
|
170
|
+
let origentname: string = ''
|
|
171
|
+
|
|
172
|
+
const m = pathStr.match(/\/([a-zA-Z0-1_-]+)(\/\{([a-zA-Z0-1_-]+)\})?$/)
|
|
173
|
+
if (m) {
|
|
174
|
+
let pathName = m[1]
|
|
175
|
+
origentname = snakify(pathName)
|
|
176
|
+
|
|
177
|
+
// Check schema
|
|
178
|
+
const compname = resolveComponentName(methodDef, methodStr)
|
|
179
|
+
if (compname) {
|
|
180
|
+
origentname = snakify(compname)
|
|
181
|
+
}
|
|
131
182
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
183
|
+
entname = depluralize(origentname)
|
|
184
|
+
|
|
185
|
+
entdesc = (entityDescs[entname] = entityDescs[entname] || {
|
|
186
|
+
name: entname,
|
|
187
|
+
id: Math.random(),
|
|
188
|
+
alias: {}
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
let pathParam = m[3]
|
|
192
|
+
if (null != pathParam) {
|
|
193
|
+
const pathParamCanon = snakify(pathParam)
|
|
194
|
+
if ('id' != pathParamCanon) {
|
|
195
|
+
entdesc.alias.id = pathParamCanon
|
|
196
|
+
entdesc.alias[pathParamCanon] = 'id'
|
|
135
197
|
}
|
|
136
198
|
}
|
|
137
|
-
}
|
|
199
|
+
}
|
|
138
200
|
|
|
139
|
-
|
|
140
|
-
|
|
201
|
+
// Can't figure out the entity
|
|
202
|
+
else {
|
|
203
|
+
console.log('NO ENTTIY', pathStr)
|
|
204
|
+
return
|
|
205
|
+
}
|
|
141
206
|
|
|
142
207
|
|
|
143
|
-
|
|
144
|
-
entityDescs: Record<string, EntityDesc>,
|
|
145
|
-
pathStr: string,
|
|
146
|
-
pathName: string,
|
|
147
|
-
pathParam?: string
|
|
148
|
-
)
|
|
149
|
-
: EntityDesc {
|
|
150
|
-
let origentname = snakify(pathName)
|
|
151
|
-
let entname = depluralize(origentname)
|
|
152
|
-
|
|
153
|
-
let entdesc = (entityDescs[entname] = entityDescs[entname] || { name: entname })
|
|
154
|
-
entdesc.plural = origentname
|
|
208
|
+
// entdesc.plural = origentname
|
|
155
209
|
entdesc.origname = origentname
|
|
156
210
|
|
|
157
211
|
names(entdesc, entname)
|
|
158
212
|
|
|
159
213
|
entdesc.alias = entdesc.alias || {}
|
|
160
214
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
215
|
+
entdesc.path = (entdesc.path || {})
|
|
216
|
+
entdesc.path[pathStr] = entdesc.path[pathStr] || {}
|
|
217
|
+
entdesc.path[pathStr].op = entdesc.path[pathStr].op || {}
|
|
218
|
+
|
|
219
|
+
return entdesc
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
const REQKIND: any = {
|
|
224
|
+
get: 'res',
|
|
225
|
+
post: 'req',
|
|
226
|
+
put: 'req',
|
|
227
|
+
patch: 'req',
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
function resolveComponentName(
|
|
232
|
+
methodDef: Record<string, any>,
|
|
233
|
+
methodStr: string,
|
|
234
|
+
): string | undefined {
|
|
235
|
+
const kind = REQKIND[methodStr]
|
|
236
|
+
let compname: string | undefined = undefined
|
|
237
|
+
|
|
238
|
+
const responses = methodDef.responses
|
|
239
|
+
const schemalist =
|
|
240
|
+
[
|
|
241
|
+
methodDef.requestBody?.content,
|
|
242
|
+
responses?.['201'],
|
|
243
|
+
responses?.['200'],
|
|
244
|
+
]
|
|
245
|
+
.filter(cmp => null != cmp)
|
|
246
|
+
.map(content => content['application/json']?.schema)
|
|
247
|
+
.filter(schema => null != schema)
|
|
248
|
+
.filter(schema => null != schema['x-ref'])
|
|
249
|
+
.map(schema => {
|
|
250
|
+
let xrefm = schema['x-ref'].match(/\/components\/schemas\/(.+)$/)
|
|
251
|
+
if (xrefm) {
|
|
252
|
+
schema['x-ref-cmp'] = xrefm[1]
|
|
253
|
+
}
|
|
254
|
+
return schema
|
|
255
|
+
})
|
|
256
|
+
.filter(schema => null != schema['x-ref-cmp'])
|
|
257
|
+
|
|
258
|
+
let schema = undefined
|
|
259
|
+
let splen = -1
|
|
260
|
+
|
|
261
|
+
for (let sI = 0; sI < schemalist.length; sI++) {
|
|
262
|
+
let nextschema = schemalist[sI]
|
|
263
|
+
let nsplen = nextschema.properties?.length || -1
|
|
264
|
+
|
|
265
|
+
// console.log('QQQ', splen, nsplen, schema?.['x-ref-cmp'], nextschema?.['x-ref-cmp'])
|
|
266
|
+
|
|
267
|
+
if (
|
|
268
|
+
// More properties probably means it is the full entity.
|
|
269
|
+
splen < nsplen ||
|
|
270
|
+
|
|
271
|
+
// Shorter name probably means it is the full entity (no suffix/prefix).
|
|
272
|
+
(schema && splen === nsplen && nextschema['x-ref-cmp'].length < schema['x-ref-cmp'].length)
|
|
273
|
+
|
|
274
|
+
) {
|
|
275
|
+
schema = nextschema
|
|
276
|
+
splen = nsplen
|
|
166
277
|
}
|
|
167
278
|
}
|
|
168
279
|
|
|
169
|
-
|
|
170
|
-
|
|
280
|
+
if (schema) {
|
|
281
|
+
let xref = schema['x-ref']
|
|
282
|
+
// console.log('RCN-XREF', methodStr, 'xref-0', xref)
|
|
283
|
+
|
|
284
|
+
if (null == xref) {
|
|
285
|
+
const properties = schema.properties || {}
|
|
286
|
+
each(properties, (prop) => {
|
|
287
|
+
if (null == xref) {
|
|
288
|
+
if (prop.type === 'array') {
|
|
289
|
+
xref = prop.items?.['x-ref']
|
|
290
|
+
// console.log('RCN', methodStr, 'xref-1', xref)
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
})
|
|
294
|
+
}
|
|
171
295
|
|
|
172
|
-
|
|
296
|
+
if (null != xref && 'string' === typeof xref) {
|
|
297
|
+
let xrefm = xref.match(/\/components\/schemas\/(.+)$/)
|
|
298
|
+
if (xrefm) {
|
|
299
|
+
compname = xrefm[1]
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
return compname
|
|
173
305
|
}
|
|
174
306
|
|
|
175
307
|
|
|
308
|
+
function resolveOpName(methodStr: string, methodDef: any, pathStr: string, entdesc: EntityDesc)
|
|
309
|
+
: string | undefined {
|
|
310
|
+
|
|
311
|
+
let opname = METHOD_IDOP[methodStr]
|
|
312
|
+
if (null == opname) return;
|
|
313
|
+
|
|
314
|
+
if ('load' === opname) {
|
|
315
|
+
const islist = isListResponse(methodDef, pathStr, entdesc)
|
|
316
|
+
opname = islist ? 'list' : opname
|
|
317
|
+
|
|
318
|
+
console.log('ISLIST', entdesc.name, methodStr, opname, pathStr)
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
return opname
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
function isListResponse(
|
|
326
|
+
methodDef: Record<string, any>,
|
|
327
|
+
pathStr: string,
|
|
328
|
+
entdesc: EntityDesc
|
|
329
|
+
): boolean {
|
|
330
|
+
const responses = methodDef.responses
|
|
331
|
+
const resdef = responses?.['201'] || responses?.['200']
|
|
332
|
+
const content = resdef?.content
|
|
333
|
+
|
|
334
|
+
let islist = false
|
|
335
|
+
|
|
336
|
+
if (null != content) {
|
|
337
|
+
const schema = content['application/json']?.schema
|
|
338
|
+
if (schema) {
|
|
339
|
+
if (schema.type === 'array') {
|
|
340
|
+
islist = true
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
if (!islist) {
|
|
344
|
+
const properties = schema.properties || {}
|
|
345
|
+
each(properties, (prop) => {
|
|
346
|
+
if (prop.type === 'array') {
|
|
347
|
+
|
|
348
|
+
if (
|
|
349
|
+
1 === size(properties) ||
|
|
350
|
+
prop.key$ === entdesc.name ||
|
|
351
|
+
prop.key$ === entdesc.origname ||
|
|
352
|
+
listedEntity(prop) === entdesc.name
|
|
353
|
+
) {
|
|
354
|
+
islist = true
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
if ('/v2/users' === pathStr) {
|
|
358
|
+
console.log('islistresponse', islist, pathStr, entdesc.name, listedEntity(prop), properties)
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
})
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
return islist
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
function listedEntity(prop: any) {
|
|
371
|
+
const xref = prop?.items?.['x-ref']
|
|
372
|
+
const m = 'string' === typeof xref && xref.match(/^#\/components\/schemas\/(.+)$/)
|
|
373
|
+
if (m) {
|
|
374
|
+
return depluralize(snakify(m[1]))
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
|
|
176
380
|
export {
|
|
177
381
|
heuristic01
|
|
178
382
|
}
|