@voxgig/apidef 1.8.0 → 2.0.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 +3 -29
- package/dist/apidef.js +84 -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 +125 -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 +178 -0
- package/dist/guide/heuristic01.js.map +1 -0
- package/dist/guide.d.ts +2 -0
- package/dist/guide.js +62 -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 +4 -2
- 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 +22 -11
- 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 +21 -10
- package/dist/transform.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types.d.ts +682 -0
- package/dist/types.js +38 -0
- package/dist/types.js.map +1 -0
- package/dist/utility.d.ts +4 -0
- package/dist/utility.js +59 -0
- package/dist/utility.js.map +1 -0
- package/model/apidef.jsonic +28 -24
- package/package.json +11 -9
- package/src/apidef.ts +117 -263
- 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 +165 -0
- package/src/builder/flow/flowHeuristic01.ts~ +45 -0
- package/src/builder/flow.ts +60 -0
- package/src/guide/heuristic01.ts +225 -0
- package/src/guide.ts +91 -0
- package/src/parse.ts +6 -4
- package/src/resolver.ts +91 -0
- package/src/transform/entity.ts +10 -7
- package/src/transform/field.ts +9 -92
- package/src/transform/operation.ts +39 -25
- package/src/transform/top.ts +11 -9
- package/src/transform.ts +23 -11
- package/src/types.ts +88 -0
- package/src/utility.ts +83 -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/dist/utility.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.loadFile = loadFile;
|
|
7
|
+
exports.formatJsonSrc = formatJsonSrc;
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
function loadFile(path, what, fs, log) {
|
|
10
|
+
try {
|
|
11
|
+
const source = fs.readFileSync(path, 'utf8');
|
|
12
|
+
return source;
|
|
13
|
+
}
|
|
14
|
+
catch (err) {
|
|
15
|
+
log.error({ load: 'fail', what, path, err });
|
|
16
|
+
throw err;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function formatJsonSrc(jsonsrc) {
|
|
20
|
+
return jsonsrc
|
|
21
|
+
.replace(/"([a-zA-Z_][a-zA-Z_0-9]*)": /g, '$1: ')
|
|
22
|
+
.replace(/},/g, '}\n');
|
|
23
|
+
}
|
|
24
|
+
function writeChanged(point, path, content, fs, log, flags) {
|
|
25
|
+
let exists = false;
|
|
26
|
+
let changed = false;
|
|
27
|
+
flags = flags || {};
|
|
28
|
+
flags.update = null == flags.update ? true : !!flags.update;
|
|
29
|
+
let action = '';
|
|
30
|
+
try {
|
|
31
|
+
let existingContent = '';
|
|
32
|
+
path = node_path_1.default.normalize(path);
|
|
33
|
+
exists = fs.existsSync(path);
|
|
34
|
+
if (exists) {
|
|
35
|
+
action = 'read';
|
|
36
|
+
existingContent = fs.readFileSync(path, 'utf8');
|
|
37
|
+
}
|
|
38
|
+
changed = existingContent !== content;
|
|
39
|
+
action = flags.update ? 'write' : 'skip';
|
|
40
|
+
log.info({
|
|
41
|
+
point: 'write-' + point,
|
|
42
|
+
note: (changed ? '' : 'not-') + 'changed ' + path,
|
|
43
|
+
write: 'file', skip: !changed, exists, changed,
|
|
44
|
+
contentLength: content.length, file: path
|
|
45
|
+
});
|
|
46
|
+
if (!exists || (changed && flags.update)) {
|
|
47
|
+
fs.writeFileSync(path, content);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
log.error({
|
|
52
|
+
fail: action, point, file: path, exists, changed,
|
|
53
|
+
contentLength: content.length, err
|
|
54
|
+
});
|
|
55
|
+
err.__logged__ = true;
|
|
56
|
+
throw err;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=utility.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utility.js","sourceRoot":"","sources":["../src/utility.ts"],"names":[],"mappings":";;;;;AA+EE,4BAAQ;AACR,sCAAa;AA/Ef,0DAA4B;AAS5B,SAAS,QAAQ,CAAC,IAAY,EAAE,IAAY,EAAE,EAAU,EAAE,GAAQ;IAChE,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;QAC5C,OAAO,MAAM,CAAA;IACf,CAAC;IACD,OAAO,GAAQ,EAAE,CAAC;QAChB,GAAG,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAA;QAC5C,MAAM,GAAG,CAAA;IACX,CAAC;AACH,CAAC;AAGD,SAAS,aAAa,CAAC,OAAe;IACpC,OAAO,OAAO;SACX,OAAO,CAAC,+BAA+B,EAAE,MAAM,CAAC;SAChD,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;AAC1B,CAAC;AAGD,SAAS,YAAY,CACnB,KAAa,EAAE,IAAY,EAAE,OAAe,EAC5C,EAAU,EAAE,GAAQ,EACpB,KAA4B;IAE5B,IAAI,MAAM,GAAG,KAAK,CAAA;IAClB,IAAI,OAAO,GAAG,KAAK,CAAA;IAEnB,KAAK,GAAG,KAAK,IAAI,EAAE,CAAA;IACnB,KAAK,CAAC,MAAM,GAAG,IAAI,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAA;IAE3D,IAAI,MAAM,GAAG,EAAE,CAAA;IACf,IAAI,CAAC;QACH,IAAI,eAAe,GAAW,EAAE,CAAA;QAChC,IAAI,GAAG,mBAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;QAE3B,MAAM,GAAG,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;QAE5B,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,GAAG,MAAM,CAAA;YACf,eAAe,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;QACjD,CAAC;QAED,OAAO,GAAG,eAAe,KAAK,OAAO,CAAA;QAErC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAA;QAExC,GAAG,CAAC,IAAI,CAAC;YACP,KAAK,EAAE,QAAQ,GAAG,KAAK;YACvB,IAAI,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,UAAU,GAAG,IAAI;YACjD,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO;YAC9C,aAAa,EAAE,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI;SAC1C,CAAC,CAAA;QAEF,IAAI,CAAC,MAAM,IAAI,CAAC,OAAO,IAAI,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;YACzC,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;QACjC,CAAC;IACH,CAAC;IACD,OAAO,GAAQ,EAAE,CAAC;QAChB,GAAG,CAAC,KAAK,CAAC;YACR,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO;YAChD,aAAa,EAAE,OAAO,CAAC,MAAM,EAAE,GAAG;SACnC,CAAC,CAAA;QACF,GAAG,CAAC,UAAU,GAAG,IAAI,CAAA;QACrB,MAAM,GAAG,CAAA;IACX,CAAC;AACH,CAAC"}
|
package/model/apidef.jsonic
CHANGED
|
@@ -1,33 +1,36 @@
|
|
|
1
1
|
|
|
2
|
-
main: api: guide: control:
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
main: api: guide: control: {
|
|
3
|
+
|
|
4
|
+
transform: openapi: {
|
|
5
|
+
order: *`
|
|
6
|
+
top,
|
|
7
|
+
entity,
|
|
8
|
+
operation,
|
|
9
|
+
field,
|
|
10
|
+
` | string,
|
|
11
|
+
|
|
12
|
+
element: {
|
|
13
|
+
top: {}
|
|
14
|
+
entity: {}
|
|
15
|
+
operation: {}
|
|
16
|
+
field: {}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
8
19
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
` | string
|
|
16
|
-
}
|
|
20
|
+
builder: standard: {
|
|
21
|
+
order: *`
|
|
22
|
+
entity,
|
|
23
|
+
flow,
|
|
24
|
+
` | string,
|
|
17
25
|
|
|
26
|
+
element: {
|
|
27
|
+
entity: {}
|
|
28
|
+
flow: {}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
18
31
|
|
|
19
|
-
main: api: guide: transform: &: {
|
|
20
|
-
name: .$KEY
|
|
21
|
-
load: string
|
|
22
32
|
}
|
|
23
33
|
|
|
24
|
-
main: api: guide: transform: {
|
|
25
|
-
top: {}
|
|
26
|
-
entity: {}
|
|
27
|
-
operation: {}
|
|
28
|
-
field: {}
|
|
29
|
-
manual: {}
|
|
30
|
-
}
|
|
31
34
|
|
|
32
35
|
|
|
33
36
|
main: api: guide: entity: &: {
|
|
@@ -46,3 +49,4 @@ main: api: guide: entity: &: {
|
|
|
46
49
|
|
|
47
50
|
|
|
48
51
|
|
|
52
|
+
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voxgig/apidef",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"main": "dist/apidef.js",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"types": "dist/apidef.d.ts",
|
|
@@ -19,13 +19,13 @@
|
|
|
19
19
|
"voxgig-apidef": "bin/voxgig-apidef"
|
|
20
20
|
},
|
|
21
21
|
"scripts": {
|
|
22
|
-
"test": "node --enable-source-maps --test dist-test",
|
|
23
|
-
"
|
|
24
|
-
"test-some": "node --enable-source-maps --test-name-pattern=\"$npm_config_pattern\" --test dist-test",
|
|
22
|
+
"test": "node --enable-source-maps --test \"dist-test/**/*.test.js\"",
|
|
23
|
+
"test-some": "node --enable-source-maps --test-name-pattern=\"$npm_config_pattern\" --test \"dist-test/**/*.test.js\"",
|
|
25
24
|
"watch": "tsc --build src test -w",
|
|
26
25
|
"build": "tsc --build src test",
|
|
27
26
|
"clean": "rm -rf dist dist-test node_modules yarn.lock package-lock.json",
|
|
28
27
|
"reset": "npm run clean && npm i && npm run build && npm test",
|
|
28
|
+
"postinstall": "patch-package",
|
|
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",
|
|
31
31
|
"repo-publish-quick": "npm run build && npm run test && npm run repo-tag && npm publish --registry https://registry.npmjs.org --access=public"
|
|
@@ -41,20 +41,22 @@
|
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@hapi/code": "^9.0.3",
|
|
43
43
|
"@types/js-yaml": "^4.0.9",
|
|
44
|
-
"@types/node": "
|
|
44
|
+
"@types/node": "24.0.7",
|
|
45
45
|
"aontu": "^0.28.0",
|
|
46
|
-
"esbuild": "^0.25.
|
|
46
|
+
"esbuild": "^0.25.5",
|
|
47
47
|
"json-schema-to-ts": "^3.1.1",
|
|
48
|
-
"memfs": "^4.17.
|
|
48
|
+
"memfs": "^4.17.2",
|
|
49
|
+
"patch-package": "^8.0.0",
|
|
49
50
|
"typescript": "^5.8.3"
|
|
50
51
|
},
|
|
51
52
|
"dependencies": {
|
|
52
53
|
"@redocly/openapi-core": "^1.34.3",
|
|
54
|
+
"@voxgig/struct": "^0.0.3",
|
|
53
55
|
"@voxgig/util": "^0.0.10",
|
|
54
56
|
"chokidar": "^4.0.3",
|
|
55
57
|
"gubu": "^9.0.0",
|
|
56
|
-
"jostraca": "^0.
|
|
57
|
-
"pino": "^9.
|
|
58
|
+
"jostraca": "^0.20.0",
|
|
59
|
+
"pino": "^9.7.0",
|
|
58
60
|
"pino-pretty": "^13.0.0",
|
|
59
61
|
"sonic-boom": "^4.2.0"
|
|
60
62
|
}
|
package/src/apidef.ts
CHANGED
|
@@ -1,13 +1,35 @@
|
|
|
1
|
-
/* Copyright (c) 2024 Voxgig, MIT License */
|
|
1
|
+
/* Copyright (c) 2024-2025 Voxgig, MIT License */
|
|
2
2
|
|
|
3
3
|
import * as Fs from 'node:fs'
|
|
4
4
|
import Path from 'node:path'
|
|
5
5
|
import { inspect } from 'node:util'
|
|
6
6
|
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
import {
|
|
10
|
-
|
|
7
|
+
import { Jostraca, Project, names } from 'jostraca'
|
|
8
|
+
|
|
9
|
+
import { prettyPino } from '@voxgig/util'
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
import type {
|
|
13
|
+
ApiDefOptions,
|
|
14
|
+
Model,
|
|
15
|
+
Build,
|
|
16
|
+
ApiModel,
|
|
17
|
+
} from './types'
|
|
18
|
+
|
|
19
|
+
import {
|
|
20
|
+
OpenModelShape,
|
|
21
|
+
OpenBuildShape,
|
|
22
|
+
} from './types'
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
import {
|
|
26
|
+
resolveGuide,
|
|
27
|
+
} from './guide'
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
import {
|
|
31
|
+
parse
|
|
32
|
+
} from './parse'
|
|
11
33
|
|
|
12
34
|
|
|
13
35
|
import {
|
|
@@ -17,76 +39,55 @@ import {
|
|
|
17
39
|
} from './transform'
|
|
18
40
|
|
|
19
41
|
|
|
20
|
-
type ApiDefOptions = {
|
|
21
|
-
def?: string
|
|
22
|
-
fs?: any
|
|
23
|
-
pino?: ReturnType<typeof Pino>
|
|
24
|
-
debug?: boolean | string
|
|
25
|
-
folder?: string
|
|
26
|
-
meta?: Record<string, any>
|
|
27
|
-
outprefix?: string
|
|
28
|
-
}
|
|
29
|
-
|
|
30
42
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
entity: Record<string, any>
|
|
35
|
-
}
|
|
36
|
-
def: Record<string, any>
|
|
37
|
-
}
|
|
38
|
-
}
|
|
43
|
+
import {
|
|
44
|
+
resolveElements
|
|
45
|
+
} from './resolver'
|
|
39
46
|
|
|
47
|
+
import {
|
|
48
|
+
loadFile,
|
|
49
|
+
} from './utility'
|
|
40
50
|
|
|
41
|
-
const ModelShape = Gubu({
|
|
42
|
-
def: String,
|
|
43
|
-
main: {
|
|
44
|
-
sdk: {},
|
|
45
|
-
def: {},
|
|
46
|
-
api: {},
|
|
47
|
-
}
|
|
48
|
-
})
|
|
49
|
-
const OpenModelShape = Gubu(Open(ModelShape))
|
|
50
|
-
|
|
51
|
-
type Model = ReturnType<typeof ModelShape>
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
const BuildShape = Gubu({
|
|
55
|
-
spec: {
|
|
56
|
-
base: '',
|
|
57
|
-
path: '',
|
|
58
|
-
debug: '',
|
|
59
|
-
use: {},
|
|
60
|
-
res: [],
|
|
61
|
-
require: '',
|
|
62
|
-
log: {},
|
|
63
|
-
fs: Any(),
|
|
64
|
-
watch: {
|
|
65
|
-
mod: true,
|
|
66
|
-
add: true,
|
|
67
|
-
rem: true,
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
})
|
|
71
|
-
const OpenBuildShape = Gubu(Open(BuildShape))
|
|
72
51
|
|
|
73
|
-
|
|
52
|
+
import { topTransform } from './transform/top'
|
|
53
|
+
import { entityTransform } from './transform/entity'
|
|
54
|
+
import { operationTransform } from './transform/operation'
|
|
55
|
+
import { fieldTransform } from './transform/field'
|
|
74
56
|
|
|
57
|
+
import { makeEntityBuilder } from './builder/entity'
|
|
58
|
+
import { makeFlowBuilder } from './builder/flow'
|
|
75
59
|
|
|
76
60
|
|
|
77
61
|
function ApiDef(opts: ApiDefOptions) {
|
|
62
|
+
|
|
63
|
+
// TODO: gubu opts!
|
|
78
64
|
const fs = opts.fs || Fs
|
|
79
65
|
const pino = prettyPino('apidef', opts)
|
|
80
|
-
|
|
81
66
|
const log = pino.child({ cmp: 'apidef' })
|
|
82
67
|
|
|
68
|
+
opts.strategy = opts.strategy || 'heuristic01'
|
|
69
|
+
|
|
83
70
|
|
|
84
71
|
async function generate(spec: any) {
|
|
85
72
|
const start = Date.now()
|
|
86
73
|
|
|
74
|
+
// console.log('APIDEF GENERATE')
|
|
75
|
+
// console.dir(spec, { depth: null })
|
|
76
|
+
|
|
87
77
|
const model: Model = OpenModelShape(spec.model)
|
|
88
78
|
const build: Build = OpenBuildShape(spec.build)
|
|
89
79
|
|
|
80
|
+
names(model, model.name)
|
|
81
|
+
|
|
82
|
+
const apimodel: ApiModel = {
|
|
83
|
+
main: {
|
|
84
|
+
api: {
|
|
85
|
+
entity: {}
|
|
86
|
+
},
|
|
87
|
+
def: {},
|
|
88
|
+
},
|
|
89
|
+
}
|
|
90
|
+
|
|
90
91
|
const buildspec = build.spec
|
|
91
92
|
|
|
92
93
|
let defpath = model.def
|
|
@@ -101,214 +102,96 @@ function ApiDef(opts: ApiDefOptions) {
|
|
|
101
102
|
|
|
102
103
|
// TODO: Validate spec
|
|
103
104
|
const ctx = {
|
|
105
|
+
fs,
|
|
104
106
|
log,
|
|
105
107
|
spec,
|
|
106
108
|
opts,
|
|
107
109
|
util: { fixName },
|
|
108
110
|
defpath: Path.dirname(defpath),
|
|
109
111
|
model,
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
const transformSpec = await resolveTransforms(ctx)
|
|
113
|
-
|
|
114
|
-
log.debug({
|
|
115
|
-
point: 'transform', spec: transformSpec,
|
|
116
|
-
note: log.levelVal <= 20 ? inspect(transformSpec) : ''
|
|
117
|
-
})
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
let source
|
|
121
|
-
try {
|
|
122
|
-
source = fs.readFileSync(defpath, 'utf8')
|
|
123
|
-
}
|
|
124
|
-
catch (err: any) {
|
|
125
|
-
log.error({ read: 'fail', what: 'def', file: defpath, err })
|
|
126
|
-
throw err
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
const config = await createConfig({})
|
|
131
|
-
let bundle
|
|
132
|
-
|
|
133
|
-
try {
|
|
134
|
-
bundle = await bundleFromString({
|
|
135
|
-
source,
|
|
136
|
-
config,
|
|
137
|
-
dereference: true,
|
|
138
|
-
})
|
|
139
|
-
}
|
|
140
|
-
catch (err: any) {
|
|
141
|
-
log.error({ parse: 'fail', what: 'openapi', file: defpath, err })
|
|
142
|
-
throw err
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
const apimodel: ApiModel = {
|
|
147
|
-
main: {
|
|
148
|
-
api: {
|
|
149
|
-
entity: {}
|
|
150
|
-
},
|
|
151
|
-
def: {},
|
|
152
|
-
},
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
const def = bundle.bundle.parsed
|
|
156
|
-
const processResult = await processTransforms(ctx, transformSpec, apimodel, def)
|
|
157
|
-
|
|
158
|
-
if (!processResult.ok) {
|
|
159
|
-
log.error({
|
|
160
|
-
fail: 'process', point: 'transform-result',
|
|
161
|
-
result: processResult, note: processResult.msg,
|
|
162
|
-
err: processResult.results[0]?.err
|
|
163
|
-
})
|
|
164
|
-
|
|
165
|
-
return { ok: false, name: 'apidef', processResult }
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
const modelPath = Path.normalize(spec.config.model)
|
|
170
|
-
|
|
171
|
-
buildModel_api(apimodel, modelPath)
|
|
172
|
-
buildModel_def(apimodel, modelPath)
|
|
173
|
-
buildModel_entity(apimodel, modelPath)
|
|
174
|
-
|
|
175
|
-
log.info({ point: 'generate-end', note: 'success', break: true })
|
|
176
|
-
|
|
177
|
-
return {
|
|
178
|
-
ok: true,
|
|
179
|
-
name: 'apidef',
|
|
180
112
|
apimodel,
|
|
113
|
+
def: undefined
|
|
181
114
|
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
function buildModel_api(apimodel: ApiModel, modelPath: string) {
|
|
186
|
-
const modelapi = { main: { api: apimodel.main.api } }
|
|
187
|
-
let modelSrc = JSON.stringify(modelapi, null, 2)
|
|
188
|
-
|
|
189
|
-
modelSrc =
|
|
190
|
-
'# GENERATED FILE - DO NOT EDIT\n\n' +
|
|
191
|
-
modelSrc.substring(1, modelSrc.length - 1).replace(/\n /g, '\n')
|
|
192
|
-
|
|
193
|
-
writeChanged('api-model', modelPath, modelSrc)
|
|
194
|
-
return modelPath
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
function buildModel_def(apimodel: ApiModel, modelPath: string) {
|
|
199
|
-
const modelBasePath = Path.dirname(modelPath)
|
|
200
|
-
const defFilePath = Path.join(modelBasePath,
|
|
201
|
-
(null == opts.outprefix ? '' : opts.outprefix) + 'def-generated.jsonic')
|
|
202
|
-
|
|
203
|
-
const modelDef = { main: { def: apimodel.main.def } }
|
|
204
|
-
let modelDefSrc = JSON.stringify(modelDef, null, 2)
|
|
205
|
-
|
|
206
|
-
modelDefSrc =
|
|
207
|
-
'# GENERATED FILE - DO NOT EDIT\n\n' +
|
|
208
|
-
modelDefSrc.substring(1, modelDefSrc.length - 1).replace(/\n /g, '\n')
|
|
209
|
-
|
|
210
|
-
writeChanged('def-model', defFilePath, modelDefSrc)
|
|
211
|
-
}
|
|
212
115
|
|
|
116
|
+
const defsrc = loadFile(defpath, 'def', fs, log)
|
|
213
117
|
|
|
214
|
-
|
|
215
|
-
|
|
118
|
+
const def = await parse('OpenAPI', defsrc, { file: defpath })
|
|
119
|
+
ctx.def = def
|
|
216
120
|
|
|
217
|
-
const
|
|
121
|
+
const guideBuilder = await resolveGuide(ctx)
|
|
218
122
|
|
|
219
|
-
each(apimodel.main.api.entity, ((entity: any) => {
|
|
220
|
-
entityIncludes.push(entity.name)
|
|
221
123
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
(entity.field[p.keys] ? null :
|
|
230
|
-
(p.key$.toLowerCase().includes(entity.name) ?
|
|
231
|
-
(a[p.key$] = 'id', a.id = p.key$) :
|
|
232
|
-
null)
|
|
233
|
-
|
|
234
|
-
, a), {})
|
|
124
|
+
// const transformSpec = await resolveTransforms(ctx)
|
|
125
|
+
const transforms = await resolveElements(ctx, 'transform', 'openapi', {
|
|
126
|
+
top: topTransform,
|
|
127
|
+
entity: entityTransform,
|
|
128
|
+
operation: operationTransform,
|
|
129
|
+
field: fieldTransform,
|
|
130
|
+
})
|
|
235
131
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
132
|
+
// log.debug({
|
|
133
|
+
// point: 'transform', spec: transformSpec,
|
|
134
|
+
// note: log.levelVal <= 20 ? inspect(transformSpec) : ''
|
|
135
|
+
// })
|
|
239
136
|
|
|
240
|
-
|
|
241
|
-
# Entity ${entity.name}
|
|
137
|
+
// const processResult = await processTransforms(ctx, transforms, apimodel, def)
|
|
242
138
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
139
|
+
// if (!processResult.ok) {
|
|
140
|
+
// log.error({
|
|
141
|
+
// fail: 'process', point: 'transform-result',
|
|
142
|
+
// result: processResult, note: processResult.msg,
|
|
143
|
+
// err: processResult.results[0]?.err
|
|
144
|
+
// })
|
|
246
145
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
(null == opts.outprefix ? '' : opts.outprefix) + entity.name + '.jsonic')
|
|
146
|
+
// return { ok: false, name: 'apidef', processResult }
|
|
147
|
+
// }
|
|
250
148
|
|
|
251
|
-
fs.mkdirSync(Path.dirname(entityFilePath), { recursive: true })
|
|
252
149
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
150
|
+
const builders = await resolveElements(ctx, 'builder', 'standard', {
|
|
151
|
+
entity: makeEntityBuilder,
|
|
152
|
+
flow: makeFlowBuilder,
|
|
153
|
+
})
|
|
256
154
|
|
|
257
155
|
|
|
258
|
-
modifyModel(
|
|
259
|
-
fs,
|
|
260
|
-
Path.join(
|
|
261
|
-
modelBasePath,
|
|
262
|
-
(null == opts.outprefix ? '' : opts.outprefix) + 'sdk.jsonic'),
|
|
263
|
-
entityIncludes
|
|
264
|
-
)
|
|
265
|
-
}
|
|
266
156
|
|
|
157
|
+
// const entityBuilder = resolveEntity(apimodel, spec, opts)
|
|
267
158
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
flags?: { update?: boolean }
|
|
271
|
-
) {
|
|
272
|
-
let exists = false
|
|
273
|
-
let changed = false
|
|
159
|
+
// const entityBuilder = await resolveEntity(ctx)
|
|
160
|
+
// const flowBuilder = await resolveFlows(ctx)
|
|
274
161
|
|
|
275
|
-
|
|
276
|
-
|
|
162
|
+
const jostraca = Jostraca({
|
|
163
|
+
now: spec.now,
|
|
164
|
+
fs: () => fs,
|
|
165
|
+
log,
|
|
166
|
+
})
|
|
277
167
|
|
|
278
|
-
|
|
279
|
-
try {
|
|
280
|
-
let existingContent: string = ''
|
|
281
|
-
path = Path.normalize(path)
|
|
168
|
+
const jmodel = {}
|
|
282
169
|
|
|
283
|
-
|
|
170
|
+
const root = () => Project({ folder: '.' }, async () => {
|
|
171
|
+
guideBuilder()
|
|
172
|
+
// entityBuilder()
|
|
173
|
+
// flowBuilder()
|
|
284
174
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
existingContent = fs.readFileSync(path, 'utf8')
|
|
175
|
+
for (let builder of builders) {
|
|
176
|
+
builder()
|
|
288
177
|
}
|
|
178
|
+
})
|
|
289
179
|
|
|
290
|
-
|
|
180
|
+
const jres = await jostraca.generate({
|
|
181
|
+
// folder: Path.dirname(opts.folder as string),
|
|
182
|
+
folder: opts.folder,
|
|
183
|
+
model: jmodel,
|
|
184
|
+
existing: { txt: { merge: true } }
|
|
185
|
+
}, root)
|
|
291
186
|
|
|
292
|
-
|
|
187
|
+
// console.log('JRES', jres)
|
|
293
188
|
|
|
294
|
-
|
|
295
|
-
point: 'write-' + point,
|
|
296
|
-
note: (changed ? '' : 'not-') + 'changed ' + path,
|
|
297
|
-
write: 'file', skip: !changed, exists, changed,
|
|
298
|
-
contentLength: content.length, file: path
|
|
299
|
-
})
|
|
189
|
+
log.info({ point: 'generate-end', note: 'success', break: true })
|
|
300
190
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
catch (err: any) {
|
|
306
|
-
log.error({
|
|
307
|
-
fail: action, point, file: path, exists, changed,
|
|
308
|
-
contentLength: content.length, err
|
|
309
|
-
})
|
|
310
|
-
err.__logged__ = true
|
|
311
|
-
throw err
|
|
191
|
+
return {
|
|
192
|
+
ok: true,
|
|
193
|
+
name: 'apidef',
|
|
194
|
+
apimodel,
|
|
312
195
|
}
|
|
313
196
|
}
|
|
314
197
|
|
|
@@ -318,17 +201,14 @@ main: sdk: entity: ${entity.name}: {
|
|
|
318
201
|
}
|
|
319
202
|
|
|
320
203
|
|
|
321
|
-
|
|
322
204
|
ApiDef.makeBuild = async function(opts: ApiDefOptions) {
|
|
323
205
|
let apidef: any = undefined
|
|
324
206
|
|
|
325
|
-
const outprefix = null == opts.outprefix ? '' : opts.outprefix
|
|
207
|
+
// const outprefix = null == opts.outprefix ? '' : opts.outprefix
|
|
326
208
|
|
|
327
209
|
const config = {
|
|
328
210
|
def: opts.def || 'no-def',
|
|
329
211
|
kind: 'openapi3',
|
|
330
|
-
model: opts.folder ?
|
|
331
|
-
(opts.folder + '/' + outprefix + 'api-generated.jsonic') : 'no-model',
|
|
332
212
|
meta: opts.meta || {},
|
|
333
213
|
}
|
|
334
214
|
|
|
@@ -351,41 +231,15 @@ ApiDef.makeBuild = async function(opts: ApiDefOptions) {
|
|
|
351
231
|
|
|
352
232
|
|
|
353
233
|
|
|
354
|
-
async function modifyModel(fs: any, path: string, entityIncludes: string[]) {
|
|
355
|
-
// TODO: This is a kludge.
|
|
356
|
-
// Aontu should provide option for as-is AST so that can be used
|
|
357
|
-
// to find injection point more reliably
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
let src = fs.existsSync(path) ? fs.readFileSync(path, 'utf8') :
|
|
361
|
-
'main: sdk: entity: {}\n'
|
|
362
|
-
|
|
363
|
-
let newsrc = '' + src
|
|
364
|
-
|
|
365
|
-
// Inject target file references into model
|
|
366
|
-
entityIncludes.sort().map((entname: string) => {
|
|
367
|
-
const lineRE =
|
|
368
|
-
new RegExp(`@"entity/${entname}.jsonic"`)
|
|
369
|
-
|
|
370
|
-
if (!src.match(lineRE)) {
|
|
371
|
-
newsrc = newsrc.replace(/(main:\s+sdk:\s+entity:\s+\{\s*\}\n)/, '$1' +
|
|
372
|
-
`@"entity/${entname}.jsonic"\n`)
|
|
373
|
-
}
|
|
374
|
-
})
|
|
375
|
-
|
|
376
|
-
if (newsrc.length !== src.length) {
|
|
377
|
-
fs.writeFileSync(path, newsrc)
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
234
|
|
|
381
235
|
|
|
382
236
|
|
|
383
237
|
export type {
|
|
384
238
|
ApiDefOptions,
|
|
385
|
-
// ApiDefSpec,
|
|
386
239
|
}
|
|
387
240
|
|
|
388
241
|
|
|
389
242
|
export {
|
|
390
243
|
ApiDef,
|
|
244
|
+
parse,
|
|
391
245
|
}
|