@voxgig/sdkgen 3.4.3 → 3.4.6
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/cmp/ReadmeTop.js +10 -1
- package/dist/cmp/ReadmeTop.js.map +1 -1
- package/dist/helpers/opExample.js +10 -1
- package/dist/helpers/opExample.js.map +1 -1
- package/dist/sdkgen.d.ts +2 -2
- package/dist/sdkgen.js +10 -2
- package/dist/sdkgen.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utility.d.ts +12 -1
- package/dist/utility.js +206 -1
- package/dist/utility.js.map +1 -1
- package/model/sdkgen.aontu +11 -0
- package/package.json +1 -1
- package/project/.sdk/src/cmp/c/Config_c.ts +45 -0
- package/project/.sdk/src/cmp/c/utility_c.ts +36 -0
- package/project/.sdk/src/cmp/go/Config_go.ts +86 -2
- package/project/.sdk/src/cmp/js/Config_js.ts +49 -1
- package/project/.sdk/src/cmp/js/fragment/Config.data.fragment.js +50 -0
- package/project/.sdk/src/cmp/js/fragment/Config.fragment.js +1 -1
- package/project/.sdk/src/cmp/lua/Config_lua.ts +51 -1
- package/project/.sdk/src/cmp/lua/utility_lua.ts +21 -0
- package/project/.sdk/src/cmp/php/Config_php.ts +86 -0
- package/project/.sdk/src/cmp/py/Config_py.ts +47 -1
- package/project/.sdk/src/cmp/rb/Config_rb.ts +46 -2
- package/project/.sdk/src/cmp/rust/Config_rust.ts +50 -35
- package/project/.sdk/src/cmp/rust/utility_rust.ts +17 -0
- package/project/.sdk/src/cmp/ts/Config_ts.ts +49 -1
- package/project/.sdk/src/cmp/ts/fragment/Config.data.fragment.ts +50 -0
- package/project/.sdk/src/cmp/ts/fragment/Config.fragment.ts +1 -1
- package/project/.sdk/src/cmp/zig/Config_zig.ts +47 -40
- package/src/cmp/ReadmeTop.ts +10 -1
- package/src/helpers/opExample.ts +11 -1
- package/src/sdkgen.ts +11 -1
- package/src/utility.ts +226 -1
|
@@ -3,9 +3,11 @@ import {
|
|
|
3
3
|
Content,
|
|
4
4
|
File,
|
|
5
5
|
cmp,
|
|
6
|
+
configDefinition,
|
|
7
|
+
configReprSetting,
|
|
6
8
|
each,
|
|
7
9
|
isAuthActive,
|
|
8
|
-
|
|
10
|
+
isConfigData,
|
|
9
11
|
} from '@voxgig/sdkgen'
|
|
10
12
|
|
|
11
13
|
|
|
@@ -17,7 +19,6 @@ import {
|
|
|
17
19
|
|
|
18
20
|
|
|
19
21
|
import {
|
|
20
|
-
clean,
|
|
21
22
|
formatZigValue,
|
|
22
23
|
} from './utility_zig'
|
|
23
24
|
|
|
@@ -31,52 +32,57 @@ const Config = cmp(async function Config(props: any) {
|
|
|
31
32
|
|
|
32
33
|
const model: Model = ctx$.model
|
|
33
34
|
|
|
34
|
-
const entity = getModelPath(model, `main.${KIT}.entity`)
|
|
35
35
|
const feature = getModelPath(model, `main.${KIT}.feature`)
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
// The canonical config OBJECT and its JSON, from the shared helper. Both
|
|
38
|
+
// representations render from the same `def`, so they cannot describe
|
|
39
|
+
// different configs - and this target picks up `options.server` (the
|
|
40
|
+
// OpenAPI server-variable defaults), which the hand-rolled build here
|
|
41
|
+
// omitted entirely.
|
|
42
|
+
const { def: config, json: configJson } = configDefinition(model)
|
|
43
|
+
const asData = isConfigData(configJson, configReprSetting(model))
|
|
38
44
|
|
|
39
|
-
|
|
40
|
-
const authPrefix = resolveAuthPrefix(model)
|
|
45
|
+
File({ name: 'config.' + target.ext }, () => {
|
|
41
46
|
|
|
42
|
-
|
|
43
|
-
|
|
47
|
+
// ABOVE THE THRESHOLD: emit the model as DATA.
|
|
48
|
+
//
|
|
49
|
+
// The literal is one nested expression that Zig's comptime evaluator has
|
|
50
|
+
// to walk in full at every build; a string constant is one token, and
|
|
51
|
+
// `json_parse` (std.json at the boundary, then fromStdJson) builds the
|
|
52
|
+
// same Value at runtime.
|
|
53
|
+
//
|
|
54
|
+
// The escaping is JSON.stringify's, which is valid Zig: it escapes every
|
|
55
|
+
// backslash, so the JSON's own `\uXXXX` reaches the file as `\\uXXXX` and
|
|
56
|
+
// no Zig escape sequence is ever formed from it.
|
|
57
|
+
if (asData) {
|
|
58
|
+
Content(`// Generated API configuration (mirrors go/rust core/config).
|
|
44
59
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
60
|
+
const std = @import("std");
|
|
61
|
+
const h = @import("helpers.zig");
|
|
62
|
+
const types = @import("types.zig");
|
|
63
|
+
const jsonparse = @import("../utility/jsonparse.zig");
|
|
64
|
+
const Value = h.Value;
|
|
65
|
+
const Feature = types.Feature;
|
|
49
66
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
67
|
+
/// THE API MODEL, EMBEDDED AS DATA (sdkgen rung L1).
|
|
68
|
+
///
|
|
69
|
+
/// Emitted only above a size threshold, or when \`main.kit.config.repr\` pins
|
|
70
|
+
/// it: for a small model the literal is smaller and far easier to read when
|
|
71
|
+
/// debugging.
|
|
72
|
+
const CONFIG_DATA: []const u8 = ${JSON.stringify(configJson)};
|
|
54
73
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const entityConfig = Object.values(entity || {}).reduce((a: any, n: any) => (
|
|
65
|
-
a[n.name] = clean({
|
|
66
|
-
fields: n.fields,
|
|
67
|
-
name: n.name,
|
|
68
|
-
op: n.op,
|
|
69
|
-
relations: n.relations,
|
|
70
|
-
}, true), a), {})
|
|
71
|
-
|
|
72
|
-
const config = {
|
|
73
|
-
main: { name: model.const.Name },
|
|
74
|
-
feature: featureConfig,
|
|
75
|
-
options,
|
|
76
|
-
entity: entityConfig,
|
|
77
|
-
}
|
|
74
|
+
pub fn make_config() Value {
|
|
75
|
+
// Unreachable on error: the constant is generated by a JSON serialiser and
|
|
76
|
+
// never edited by hand. Panicking beats returning an empty config, which
|
|
77
|
+
// would fail far from the cause.
|
|
78
|
+
return jsonparse.json_parse(CONFIG_DATA) catch
|
|
79
|
+
@panic("${model.const.Name}: embedded config is not valid JSON");
|
|
80
|
+
}
|
|
78
81
|
|
|
79
|
-
|
|
82
|
+
pub fn make_feature(name: []const u8) Feature {
|
|
83
|
+
`)
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
80
86
|
|
|
81
87
|
Content(`// Generated API configuration (mirrors go/rust core/config).
|
|
82
88
|
|
|
@@ -92,6 +98,7 @@ pub fn make_config() Value {
|
|
|
92
98
|
|
|
93
99
|
pub fn make_feature(name: []const u8) Feature {
|
|
94
100
|
`)
|
|
101
|
+
}
|
|
95
102
|
|
|
96
103
|
// The factory must be able to instantiate any built-in feature by name,
|
|
97
104
|
// not just the ones the current API model configures — a caller can enable
|
package/src/cmp/ReadmeTop.ts
CHANGED
|
@@ -577,7 +577,16 @@ The OpenAPI spec(s) this SDK was generated from are kept in the
|
|
|
577
577
|
|
|
578
578
|
`)
|
|
579
579
|
if (upstreamUrl) {
|
|
580
|
-
|
|
580
|
+
// A per-tenant server URL carries an OpenAPI server variable —
|
|
581
|
+
// `https://{instance}.dreamapply.com/api` — and is the right thing to
|
|
582
|
+
// SHOW, because it tells the reader the host is theirs to fill in. It is
|
|
583
|
+
// not a thing to LINK: the braces are not a resolvable address, so a
|
|
584
|
+
// markdown link renders as clickable and dead. Show it as code instead.
|
|
585
|
+
const templated = /[{}]/.test(upstreamUrl)
|
|
586
|
+
Content(templated
|
|
587
|
+
? `- Upstream API: \`${upstreamUrl}\`
|
|
588
|
+
`
|
|
589
|
+
: `- Upstream API: [${upstreamUrl}](${upstreamUrl})
|
|
581
590
|
`)
|
|
582
591
|
}
|
|
583
592
|
if (docsUrl && docsUrl !== upstreamUrl) {
|
package/src/helpers/opExample.ts
CHANGED
|
@@ -116,8 +116,18 @@ function matchArg(
|
|
|
116
116
|
// `key: value` pairs (capped) in the target language's object syntax. Ensures
|
|
117
117
|
// the body satisfies a typed CreateData/UpdateData (required fields present).
|
|
118
118
|
function dataArg(lang: ExampleLang, ent: any, op: string, idF: string | null): string {
|
|
119
|
+
// The id is normally server-assigned on create, so it is dropped from the
|
|
120
|
+
// example body. But it is only safe to drop when the request shape says it is
|
|
121
|
+
// OPTIONAL: an op whose id comes from a PATH PARAMETER requires it, and a
|
|
122
|
+
// typed CreateData then rejects a body without it.
|
|
123
|
+
//
|
|
124
|
+
// Conecto's `/integrations/{slug}/actions/{action}/run/` is the case — the
|
|
125
|
+
// guide renames the `action` param to `id`, so ActionCreateData is
|
|
126
|
+
// `{id, slug, ok}` and the generated snippet emitted only `{slug, ok}`,
|
|
127
|
+
// failing to compile with "Property 'id' is missing".
|
|
119
128
|
const items = opRequestShape(ent, op).items
|
|
120
|
-
.filter((it: any) =>
|
|
129
|
+
.filter((it: any) =>
|
|
130
|
+
(it.name !== idF && it.name !== 'id') || !it.optional)
|
|
121
131
|
const required = items.filter((it: any) => !it.optional)
|
|
122
132
|
// ALL required fields must appear (a typed CreateData rejects a partial); cap
|
|
123
133
|
// only the optional fallback used when the op declares no required field.
|
package/src/sdkgen.ts
CHANGED
|
@@ -19,7 +19,9 @@ import type {
|
|
|
19
19
|
ActionResult,
|
|
20
20
|
} from './types'
|
|
21
21
|
|
|
22
|
-
import { SdkGenError, requirePath, isAuthActive, resolveAuthPrefix
|
|
22
|
+
import { SdkGenError, requirePath, isAuthActive, resolveAuthPrefix,
|
|
23
|
+
CONFIG_DATA_THRESHOLD, CONFIG_REPR_VALUES, isConfigData, configRepr,
|
|
24
|
+
configReprSetting, configDefinition, clean, rawStringLiteral } from './utility'
|
|
23
25
|
|
|
24
26
|
import { Main } from './cmp/Main'
|
|
25
27
|
import { ExternalTarget } from './cmp/ExternalTarget'
|
|
@@ -776,6 +778,14 @@ export {
|
|
|
776
778
|
requirePath,
|
|
777
779
|
isAuthActive,
|
|
778
780
|
resolveAuthPrefix,
|
|
781
|
+
CONFIG_DATA_THRESHOLD,
|
|
782
|
+
CONFIG_REPR_VALUES,
|
|
783
|
+
isConfigData,
|
|
784
|
+
configRepr,
|
|
785
|
+
configReprSetting,
|
|
786
|
+
configDefinition,
|
|
787
|
+
clean,
|
|
788
|
+
rawStringLiteral,
|
|
779
789
|
|
|
780
790
|
// Scaffold components need this to fail a generation with an actionable
|
|
781
791
|
// message rather than a bare Error (py-data guards on its sibling `py`).
|
package/src/utility.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
|
|
2
2
|
import Path from 'node:path'
|
|
3
3
|
|
|
4
|
-
import { JostracaResult } from 'jostraca'
|
|
4
|
+
import { JostracaResult, each } from 'jostraca'
|
|
5
5
|
|
|
6
6
|
import { KIT, getModelPath } from '@voxgig/apidef'
|
|
7
7
|
|
|
8
|
+
import { serverVariables } from './helpers/serverVars'
|
|
9
|
+
|
|
8
10
|
|
|
9
11
|
// Where a per-target component is loaded from: `<project>/.sdk/dist/<path>`.
|
|
10
12
|
//
|
|
@@ -96,4 +98,227 @@ export {
|
|
|
96
98
|
isAuthActive,
|
|
97
99
|
resolveAuthPrefix,
|
|
98
100
|
SdkGenError,
|
|
101
|
+
CONFIG_DATA_THRESHOLD,
|
|
102
|
+
CONFIG_REPR_VALUES,
|
|
103
|
+
isConfigData,
|
|
104
|
+
configRepr,
|
|
105
|
+
configReprSetting,
|
|
106
|
+
configDefinition,
|
|
107
|
+
clean,
|
|
108
|
+
rawStringLiteral,
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
// CONFIG REPRESENTATION (design rung L1, threshold from design Q7).
|
|
113
|
+
//
|
|
114
|
+
// Above a size threshold the API model is emitted as DATA - a JSON string
|
|
115
|
+
// constant parsed once - rather than as a composite literal. Below it the
|
|
116
|
+
// literal stays, because for a small model the literal is smaller, simpler,
|
|
117
|
+
// faster to load and far easier to debug, and a symbol table would be pure
|
|
118
|
+
// complexity.
|
|
119
|
+
//
|
|
120
|
+
// The threshold is on the JSON, not the emitted source, because the emitted
|
|
121
|
+
// source size varies by language while the model does not. It is measured in
|
|
122
|
+
// UTF-8 BYTES rather than string length: `.length` counts UTF-16 code units,
|
|
123
|
+
// so a CJK-heavy model would read as roughly a third of its real size and
|
|
124
|
+
// stay on the expensive literal path well past the point where it hurts.
|
|
125
|
+
//
|
|
126
|
+
// Measured on the real gitlab model (923.5 KB of JSON), Go, cold cache,
|
|
127
|
+
// recompiling only the config package:
|
|
128
|
+
//
|
|
129
|
+
// composite literal JSON string constant
|
|
130
|
+
// compile+link wall 30.80 s 0.34 s 91x faster
|
|
131
|
+
// peak compiler RSS 2.49 GB 0.06 GB 39x less
|
|
132
|
+
// binary 7.44 MB 3.51 MB 2.1x smaller
|
|
133
|
+
//
|
|
134
|
+
// The reader side is unchanged either way: make_config returns the same map,
|
|
135
|
+
// so nothing downstream can tell which representation it got.
|
|
136
|
+
const CONFIG_DATA_THRESHOLD = 256 * 1024
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
// Should this model be emitted as data rather than as a literal?
|
|
140
|
+
//
|
|
141
|
+
// `repr` is the per-SDK override from `main.kit.config.repr`: 'auto' (the
|
|
142
|
+
// default) decides by size, 'data' and 'literal' pin it. The override is what
|
|
143
|
+
// lets a small fixture exercise the data path - by size alone no test model
|
|
144
|
+
// comes near the threshold, so the branch every large SDK depends on would
|
|
145
|
+
// never be generated, compiled or run in CI.
|
|
146
|
+
const CONFIG_REPR_VALUES = ['auto', 'data', 'literal']
|
|
147
|
+
|
|
148
|
+
function isConfigData(configJson: string, repr?: string): boolean {
|
|
149
|
+
// An unknown value is REJECTED, not ignored. The aontu declaration
|
|
150
|
+
// documents the closed set but does not enforce it here, and silently
|
|
151
|
+
// treating `repr: 'date'` as `auto` would quietly restore the compile cost
|
|
152
|
+
// this exists to remove - the failure mode being a slow build nobody
|
|
153
|
+
// connects to a typo.
|
|
154
|
+
if (null != repr && '' !== repr && !CONFIG_REPR_VALUES.includes(repr)) {
|
|
155
|
+
throw new SdkGenError(
|
|
156
|
+
'sdkgen: main.kit.config.repr must be one of ' +
|
|
157
|
+
CONFIG_REPR_VALUES.join(', ') + ' (got: ' + repr + ')', {})
|
|
158
|
+
}
|
|
159
|
+
if ('data' === repr) {
|
|
160
|
+
return true
|
|
161
|
+
}
|
|
162
|
+
if ('literal' === repr) {
|
|
163
|
+
return false
|
|
164
|
+
}
|
|
165
|
+
return CONFIG_DATA_THRESHOLD < Buffer.byteLength(configJson, 'utf8')
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
// The chosen representation, as a word - for generation logs and for the
|
|
170
|
+
// per-SDK reporting the fleet regen needs, so a model crossing the threshold
|
|
171
|
+
// is visible rather than showing up as an unexplained whole-file diff.
|
|
172
|
+
function configRepr(configJson: string, repr?: string): string {
|
|
173
|
+
return isConfigData(configJson, repr) ? 'data' : 'literal'
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
// The per-SDK override, or 'auto'. `main.kit.config.repr` is optional, and
|
|
178
|
+
// getModelPath throws rather than returning undefined for an absent path.
|
|
179
|
+
function configReprSetting(model: any): string {
|
|
180
|
+
try {
|
|
181
|
+
return getModelPath(model, `main.${KIT}.config.repr`) || 'auto'
|
|
182
|
+
}
|
|
183
|
+
catch (_e) {
|
|
184
|
+
return 'auto'
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
// L0 NORMALISATION: strip what the emitted config must not carry.
|
|
190
|
+
//
|
|
191
|
+
// Three kinds of noise, and the distinction between them matters:
|
|
192
|
+
//
|
|
193
|
+
// MODEL_META jostraca's `each` injects index$/key$/val$ into every node
|
|
194
|
+
// it iterates. Pure bookkeeping, and it leaked into every
|
|
195
|
+
// generated SDK for years (5,231 occurrences in gitlab
|
|
196
|
+
// alone) because this helper deleted keys during a walk that
|
|
197
|
+
// assigned them straight back.
|
|
198
|
+
//
|
|
199
|
+
// CONFIG_DEFAULT a key whose value equals the default the reader already
|
|
200
|
+
// applies. Emitting it is pure bulk. Only these three names
|
|
201
|
+
// are dropped, and only at their default value - `entity$`
|
|
202
|
+
// is real Seneca data, so no blanket suffix rule.
|
|
203
|
+
//
|
|
204
|
+
// PAYLOAD_KEYS the boundary. Under `default`/`example`/`examples` the
|
|
205
|
+
// value is API DATA, not config, and an example that happens
|
|
206
|
+
// to contain `active: true` must survive intact. Below one of
|
|
207
|
+
// these keys default-dropping stops; metadata stripping does
|
|
208
|
+
// not, because jostraca's bookkeeping is never payload.
|
|
209
|
+
const MODEL_META = ['index$', 'key$', 'val$']
|
|
210
|
+
|
|
211
|
+
const CONFIG_DEFAULT: Record<string, any> = {
|
|
212
|
+
active: true,
|
|
213
|
+
req: false,
|
|
214
|
+
reqd: false,
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const PAYLOAD_KEYS = ['default', 'example', 'examples']
|
|
218
|
+
|
|
219
|
+
function clean(o: any, dropDefaults?: boolean): any {
|
|
220
|
+
// Rebuild rather than delete in place: the caller's model is shared with
|
|
221
|
+
// every other component, and mutating it here would strip metadata a later
|
|
222
|
+
// target still needs.
|
|
223
|
+
const prune = (node: any, defaults: boolean): any => {
|
|
224
|
+
if (Array.isArray(node)) return node.map((n: any) => prune(n, defaults))
|
|
225
|
+
if (null != node && 'object' === typeof node) {
|
|
226
|
+
const out: any = {}
|
|
227
|
+
for (const k of Object.keys(node)) {
|
|
228
|
+
if (MODEL_META.includes(k)) continue
|
|
229
|
+
// An ABSENT optional member, dropped rather than carried as undefined.
|
|
230
|
+
//
|
|
231
|
+
// Callers build `{fields, name, op, relations}` from an entity, and
|
|
232
|
+
// `op` and `relations` are optional - so the key exists with value
|
|
233
|
+
// undefined. JSON.stringify silently omits such a key, while the
|
|
234
|
+
// literal formatters emit it as None/nil/null, and the two
|
|
235
|
+
// representations would describe different configs for any entity
|
|
236
|
+
// without an `op`. Dropping it here fixes both branches at once,
|
|
237
|
+
// because both reach the emitter through this function.
|
|
238
|
+
if (undefined === node[k]) continue
|
|
239
|
+
if (defaults && k in CONFIG_DEFAULT && CONFIG_DEFAULT[k] === node[k]) continue
|
|
240
|
+
out[k] = prune(node[k], defaults && !PAYLOAD_KEYS.includes(k))
|
|
241
|
+
}
|
|
242
|
+
return out
|
|
243
|
+
}
|
|
244
|
+
return node
|
|
245
|
+
}
|
|
246
|
+
return prune(o, true === dropDefaults)
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
// The JSON as a source-level string literal, for a language whose SINGLE
|
|
251
|
+
// quoted literal neither interpolates nor processes escapes beyond the quote
|
|
252
|
+
// and the backslash - Ruby, PHP, Perl, Lua.
|
|
253
|
+
//
|
|
254
|
+
// Reproducing the JSON text VERBATIM is all that is needed, because the JSON
|
|
255
|
+
// already encodes control characters and non-ASCII itself. That is why this is
|
|
256
|
+
// preferred over the double-quoted form in those languages: Ruby and PHP
|
|
257
|
+
// interpolate (`#{...}`, `$var`) and Lua does not understand `\uXXXX` at all,
|
|
258
|
+
// so a double-quoted literal would need a language-specific escape table and
|
|
259
|
+
// would get it wrong for exactly the inputs nobody tests.
|
|
260
|
+
function rawStringLiteral(s: string): string {
|
|
261
|
+
return "'" + s.replace(/\\/g, '\\\\').replace(/'/g, "\\'") + "'"
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
// THE CANONICAL CONFIG OBJECT, and the JSON the threshold is measured on.
|
|
266
|
+
//
|
|
267
|
+
// Every target builds its config from this one function, so the literal a
|
|
268
|
+
// target emits and the data that replaces it above the threshold cannot
|
|
269
|
+
// describe different configs - which is the entire promise of rung L1. Before
|
|
270
|
+
// this existed each target assembled its own, and they had already drifted:
|
|
271
|
+
// `feature.<name>` came out as `{}` in Go and as nothing at all in ts when a
|
|
272
|
+
// feature declared no config.
|
|
273
|
+
//
|
|
274
|
+
// Key order is `each`'s order, which is sorted, so the JSON is byte-stable
|
|
275
|
+
// across runs exactly like the literal it replaces.
|
|
276
|
+
function configDefinition(model: any): { def: any, json: string } {
|
|
277
|
+
const entity = getModelPath(model, `main.${KIT}.entity`)
|
|
278
|
+
const feature = getModelPath(model, `main.${KIT}.feature`)
|
|
279
|
+
const headers = getModelPath(model, `main.${KIT}.config.headers`) || {}
|
|
280
|
+
|
|
281
|
+
const authActive = isAuthActive(model)
|
|
282
|
+
const authPrefix = resolveAuthPrefix(model)
|
|
283
|
+
|
|
284
|
+
let baseUrl = ''
|
|
285
|
+
try { baseUrl = getModelPath(model, `main.${KIT}.info.servers.0.url`) } catch (_e) { }
|
|
286
|
+
|
|
287
|
+
const svars = serverVariables(model)
|
|
288
|
+
|
|
289
|
+
const entityDefs: any = {}
|
|
290
|
+
const entityStubs: any = {}
|
|
291
|
+
each(entity, (e: any) => {
|
|
292
|
+
entityDefs[e.name] = clean({
|
|
293
|
+
fields: e.fields,
|
|
294
|
+
name: e.name,
|
|
295
|
+
op: e.op,
|
|
296
|
+
relations: e.relations,
|
|
297
|
+
}, true)
|
|
298
|
+
entityStubs[e.name] = {}
|
|
299
|
+
})
|
|
300
|
+
|
|
301
|
+
const featureDefs: any = {}
|
|
302
|
+
each(feature, (f: any) => {
|
|
303
|
+
featureDefs[f.name] = f.config || {}
|
|
304
|
+
})
|
|
305
|
+
|
|
306
|
+
const options: any = { base: baseUrl }
|
|
307
|
+
if (0 < svars.length) {
|
|
308
|
+
options.server = svars.reduce((a: any, v: any) => (a[v.name] = v.dflt, a), {})
|
|
309
|
+
}
|
|
310
|
+
if (authActive) {
|
|
311
|
+
options.auth = { prefix: authPrefix }
|
|
312
|
+
}
|
|
313
|
+
options.headers = headers
|
|
314
|
+
options.entity = entityStubs
|
|
315
|
+
|
|
316
|
+
const def = {
|
|
317
|
+
main: { name: model.const.Name },
|
|
318
|
+
feature: featureDefs,
|
|
319
|
+
options,
|
|
320
|
+
entity: entityDefs,
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
return { def, json: JSON.stringify(def) }
|
|
99
324
|
}
|