@voxgig/sdkgen 3.4.5 → 3.4.7
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 +5 -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 +6 -2
- package/dist/sdkgen.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utility.d.ts +8 -1
- package/dist/utility.js +144 -0
- package/dist/utility.js.map +1 -1
- 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/dart/Config_dart.ts +15 -0
- package/project/.sdk/src/cmp/dart/fragment/Config.fragment.dart +1 -1
- package/project/.sdk/src/cmp/go/Config_go.ts +9 -52
- 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 +10 -50
- package/project/.sdk/src/cmp/zig/Config_zig.ts +47 -40
- package/project/.sdk/src/cmp/zig/fragment/Main.fragment.zig +28 -17
- package/project/.sdk/tm/zig/test/gotcha_test.zig +8 -8
- package/src/cmp/ReadmeTop.ts +6 -1
- package/src/helpers/opExample.ts +11 -1
- package/src/sdkgen.ts +6 -1
- package/src/utility.ts +157 -1
package/dist/utility.js
CHANGED
|
@@ -10,8 +10,14 @@ exports.isAuthActive = isAuthActive;
|
|
|
10
10
|
exports.resolveAuthPrefix = resolveAuthPrefix;
|
|
11
11
|
exports.isConfigData = isConfigData;
|
|
12
12
|
exports.configRepr = configRepr;
|
|
13
|
+
exports.configReprSetting = configReprSetting;
|
|
14
|
+
exports.configDefinition = configDefinition;
|
|
15
|
+
exports.clean = clean;
|
|
16
|
+
exports.rawStringLiteral = rawStringLiteral;
|
|
13
17
|
const node_path_1 = __importDefault(require("node:path"));
|
|
18
|
+
const jostraca_1 = require("jostraca");
|
|
14
19
|
const apidef_1 = require("@voxgig/apidef");
|
|
20
|
+
const serverVars_1 = require("./helpers/serverVars");
|
|
15
21
|
// Where a per-target component is loaded from: `<project>/.sdk/dist/<path>`.
|
|
16
22
|
//
|
|
17
23
|
// `ctx$.folder` is jostraca's OUTPUT folder, which is the project for an
|
|
@@ -140,4 +146,142 @@ function isConfigData(configJson, repr) {
|
|
|
140
146
|
function configRepr(configJson, repr) {
|
|
141
147
|
return isConfigData(configJson, repr) ? 'data' : 'literal';
|
|
142
148
|
}
|
|
149
|
+
// The per-SDK override, or 'auto'. `main.kit.config.repr` is optional, and
|
|
150
|
+
// getModelPath throws rather than returning undefined for an absent path.
|
|
151
|
+
function configReprSetting(model) {
|
|
152
|
+
try {
|
|
153
|
+
return (0, apidef_1.getModelPath)(model, `main.${apidef_1.KIT}.config.repr`) || 'auto';
|
|
154
|
+
}
|
|
155
|
+
catch (_e) {
|
|
156
|
+
return 'auto';
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
// L0 NORMALISATION: strip what the emitted config must not carry.
|
|
160
|
+
//
|
|
161
|
+
// Three kinds of noise, and the distinction between them matters:
|
|
162
|
+
//
|
|
163
|
+
// MODEL_META jostraca's `each` injects index$/key$/val$ into every node
|
|
164
|
+
// it iterates. Pure bookkeeping, and it leaked into every
|
|
165
|
+
// generated SDK for years (5,231 occurrences in gitlab
|
|
166
|
+
// alone) because this helper deleted keys during a walk that
|
|
167
|
+
// assigned them straight back.
|
|
168
|
+
//
|
|
169
|
+
// CONFIG_DEFAULT a key whose value equals the default the reader already
|
|
170
|
+
// applies. Emitting it is pure bulk. Only these three names
|
|
171
|
+
// are dropped, and only at their default value - `entity$`
|
|
172
|
+
// is real Seneca data, so no blanket suffix rule.
|
|
173
|
+
//
|
|
174
|
+
// PAYLOAD_KEYS the boundary. Under `default`/`example`/`examples` the
|
|
175
|
+
// value is API DATA, not config, and an example that happens
|
|
176
|
+
// to contain `active: true` must survive intact. Below one of
|
|
177
|
+
// these keys default-dropping stops; metadata stripping does
|
|
178
|
+
// not, because jostraca's bookkeeping is never payload.
|
|
179
|
+
const MODEL_META = ['index$', 'key$', 'val$'];
|
|
180
|
+
const CONFIG_DEFAULT = {
|
|
181
|
+
active: true,
|
|
182
|
+
req: false,
|
|
183
|
+
reqd: false,
|
|
184
|
+
};
|
|
185
|
+
const PAYLOAD_KEYS = ['default', 'example', 'examples'];
|
|
186
|
+
function clean(o, dropDefaults) {
|
|
187
|
+
// Rebuild rather than delete in place: the caller's model is shared with
|
|
188
|
+
// every other component, and mutating it here would strip metadata a later
|
|
189
|
+
// target still needs.
|
|
190
|
+
const prune = (node, defaults) => {
|
|
191
|
+
if (Array.isArray(node))
|
|
192
|
+
return node.map((n) => prune(n, defaults));
|
|
193
|
+
if (null != node && 'object' === typeof node) {
|
|
194
|
+
const out = {};
|
|
195
|
+
for (const k of Object.keys(node)) {
|
|
196
|
+
if (MODEL_META.includes(k))
|
|
197
|
+
continue;
|
|
198
|
+
// An ABSENT optional member, dropped rather than carried as undefined.
|
|
199
|
+
//
|
|
200
|
+
// Callers build `{fields, name, op, relations}` from an entity, and
|
|
201
|
+
// `op` and `relations` are optional - so the key exists with value
|
|
202
|
+
// undefined. JSON.stringify silently omits such a key, while the
|
|
203
|
+
// literal formatters emit it as None/nil/null, and the two
|
|
204
|
+
// representations would describe different configs for any entity
|
|
205
|
+
// without an `op`. Dropping it here fixes both branches at once,
|
|
206
|
+
// because both reach the emitter through this function.
|
|
207
|
+
if (undefined === node[k])
|
|
208
|
+
continue;
|
|
209
|
+
if (defaults && k in CONFIG_DEFAULT && CONFIG_DEFAULT[k] === node[k])
|
|
210
|
+
continue;
|
|
211
|
+
out[k] = prune(node[k], defaults && !PAYLOAD_KEYS.includes(k));
|
|
212
|
+
}
|
|
213
|
+
return out;
|
|
214
|
+
}
|
|
215
|
+
return node;
|
|
216
|
+
};
|
|
217
|
+
return prune(o, true === dropDefaults);
|
|
218
|
+
}
|
|
219
|
+
// The JSON as a source-level string literal, for a language whose SINGLE
|
|
220
|
+
// quoted literal neither interpolates nor processes escapes beyond the quote
|
|
221
|
+
// and the backslash - Ruby, PHP, Perl, Lua.
|
|
222
|
+
//
|
|
223
|
+
// Reproducing the JSON text VERBATIM is all that is needed, because the JSON
|
|
224
|
+
// already encodes control characters and non-ASCII itself. That is why this is
|
|
225
|
+
// preferred over the double-quoted form in those languages: Ruby and PHP
|
|
226
|
+
// interpolate (`#{...}`, `$var`) and Lua does not understand `\uXXXX` at all,
|
|
227
|
+
// so a double-quoted literal would need a language-specific escape table and
|
|
228
|
+
// would get it wrong for exactly the inputs nobody tests.
|
|
229
|
+
function rawStringLiteral(s) {
|
|
230
|
+
return "'" + s.replace(/\\/g, '\\\\').replace(/'/g, "\\'") + "'";
|
|
231
|
+
}
|
|
232
|
+
// THE CANONICAL CONFIG OBJECT, and the JSON the threshold is measured on.
|
|
233
|
+
//
|
|
234
|
+
// Every target builds its config from this one function, so the literal a
|
|
235
|
+
// target emits and the data that replaces it above the threshold cannot
|
|
236
|
+
// describe different configs - which is the entire promise of rung L1. Before
|
|
237
|
+
// this existed each target assembled its own, and they had already drifted:
|
|
238
|
+
// `feature.<name>` came out as `{}` in Go and as nothing at all in ts when a
|
|
239
|
+
// feature declared no config.
|
|
240
|
+
//
|
|
241
|
+
// Key order is `each`'s order, which is sorted, so the JSON is byte-stable
|
|
242
|
+
// across runs exactly like the literal it replaces.
|
|
243
|
+
function configDefinition(model) {
|
|
244
|
+
const entity = (0, apidef_1.getModelPath)(model, `main.${apidef_1.KIT}.entity`);
|
|
245
|
+
const feature = (0, apidef_1.getModelPath)(model, `main.${apidef_1.KIT}.feature`);
|
|
246
|
+
const headers = (0, apidef_1.getModelPath)(model, `main.${apidef_1.KIT}.config.headers`) || {};
|
|
247
|
+
const authActive = isAuthActive(model);
|
|
248
|
+
const authPrefix = resolveAuthPrefix(model);
|
|
249
|
+
let baseUrl = '';
|
|
250
|
+
try {
|
|
251
|
+
baseUrl = (0, apidef_1.getModelPath)(model, `main.${apidef_1.KIT}.info.servers.0.url`);
|
|
252
|
+
}
|
|
253
|
+
catch (_e) { }
|
|
254
|
+
const svars = (0, serverVars_1.serverVariables)(model);
|
|
255
|
+
const entityDefs = {};
|
|
256
|
+
const entityStubs = {};
|
|
257
|
+
(0, jostraca_1.each)(entity, (e) => {
|
|
258
|
+
entityDefs[e.name] = clean({
|
|
259
|
+
fields: e.fields,
|
|
260
|
+
name: e.name,
|
|
261
|
+
op: e.op,
|
|
262
|
+
relations: e.relations,
|
|
263
|
+
}, true);
|
|
264
|
+
entityStubs[e.name] = {};
|
|
265
|
+
});
|
|
266
|
+
const featureDefs = {};
|
|
267
|
+
(0, jostraca_1.each)(feature, (f) => {
|
|
268
|
+
featureDefs[f.name] = f.config || {};
|
|
269
|
+
});
|
|
270
|
+
const options = { base: baseUrl };
|
|
271
|
+
if (0 < svars.length) {
|
|
272
|
+
options.server = svars.reduce((a, v) => (a[v.name] = v.dflt, a), {});
|
|
273
|
+
}
|
|
274
|
+
if (authActive) {
|
|
275
|
+
options.auth = { prefix: authPrefix };
|
|
276
|
+
}
|
|
277
|
+
options.headers = headers;
|
|
278
|
+
options.entity = entityStubs;
|
|
279
|
+
const def = {
|
|
280
|
+
main: { name: model.const.Name },
|
|
281
|
+
feature: featureDefs,
|
|
282
|
+
options,
|
|
283
|
+
entity: entityDefs,
|
|
284
|
+
};
|
|
285
|
+
return { def, json: JSON.stringify(def) };
|
|
286
|
+
}
|
|
143
287
|
//# sourceMappingURL=utility.js.map
|
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/package.json
CHANGED
|
@@ -3,8 +3,11 @@ import {
|
|
|
3
3
|
Content,
|
|
4
4
|
File,
|
|
5
5
|
cmp,
|
|
6
|
+
configDefinition,
|
|
7
|
+
configReprSetting,
|
|
6
8
|
each,
|
|
7
9
|
isAuthActive,
|
|
10
|
+
isConfigData,
|
|
8
11
|
resolveAuthPrefix,
|
|
9
12
|
} from '@voxgig/sdkgen'
|
|
10
13
|
|
|
@@ -17,6 +20,7 @@ import {
|
|
|
17
20
|
|
|
18
21
|
|
|
19
22
|
import {
|
|
23
|
+
cStringLiteral,
|
|
20
24
|
clean,
|
|
21
25
|
formatCValue,
|
|
22
26
|
} from './utility_c'
|
|
@@ -75,8 +79,48 @@ const Config = cmp(async function Config(props: any) {
|
|
|
75
79
|
entity: entityConfig,
|
|
76
80
|
}
|
|
77
81
|
|
|
82
|
+
// The same config as an OBJECT, built by the shared helper so this target's
|
|
83
|
+
// literal and the data that replaces it above the threshold are the same
|
|
84
|
+
// config by construction. The JSON is what the threshold is measured on -
|
|
85
|
+
// emitted source size varies by language, the model does not.
|
|
86
|
+
const { json: configJson } = configDefinition(model)
|
|
87
|
+
const asData = isConfigData(configJson, configReprSetting(model))
|
|
88
|
+
|
|
78
89
|
File({ name: 'config.c' }, () => {
|
|
79
90
|
|
|
91
|
+
// ABOVE THE THRESHOLD: emit the model as DATA.
|
|
92
|
+
//
|
|
93
|
+
// The literal is a single nested `cmap(...)`/`clist(...)` expression. For a
|
|
94
|
+
// real model that is one function whose expression nests hundreds of
|
|
95
|
+
// thousands of calls deep - the shape that makes a C compiler's parser and
|
|
96
|
+
// register allocator quadratic, and the reason gcc can be seen taking
|
|
97
|
+
// minutes on a generated config. A string constant is one token, and
|
|
98
|
+
// `json_parse` (declared in sdk.h, reached through api.h) builds the same
|
|
99
|
+
// voxgig_value tree at runtime.
|
|
100
|
+
if (asData) {
|
|
101
|
+
Content(`// Generated API configuration (mirrors core/config.go).
|
|
102
|
+
|
|
103
|
+
#include "api.h"
|
|
104
|
+
|
|
105
|
+
#include <string.h>
|
|
106
|
+
|
|
107
|
+
// THE API MODEL, EMBEDDED AS DATA (sdkgen rung L1).
|
|
108
|
+
//
|
|
109
|
+
// Emitted only above a size threshold, or when \`main.kit.config.repr\` pins
|
|
110
|
+
// it: for a small model the cmap() literal is smaller and far easier to read
|
|
111
|
+
// when debugging.
|
|
112
|
+
static const char CONFIG_DATA[] =
|
|
113
|
+
${cStringLiteral(configJson)};
|
|
114
|
+
|
|
115
|
+
voxgig_value* make_config(void) {
|
|
116
|
+
return json_parse(CONFIG_DATA);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
Feature* make_feature(const char* name) {
|
|
120
|
+
`)
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
|
|
80
124
|
Content(`// Generated API configuration (mirrors core/config.go).
|
|
81
125
|
|
|
82
126
|
#include "api.h"
|
|
@@ -89,6 +133,7 @@ voxgig_value* make_config(void) {
|
|
|
89
133
|
|
|
90
134
|
Feature* make_feature(const char* name) {
|
|
91
135
|
`)
|
|
136
|
+
}
|
|
92
137
|
|
|
93
138
|
// Dispatch to the features the MODEL declares, and only those.
|
|
94
139
|
//
|
|
@@ -150,7 +150,43 @@ function clean(o: any, dropDefaults?: boolean): any {
|
|
|
150
150
|
}
|
|
151
151
|
|
|
152
152
|
|
|
153
|
+
|
|
154
|
+
// The JSON as a C string literal, split into ADJACENT literals.
|
|
155
|
+
//
|
|
156
|
+
// C99 only guarantees 4095 characters in a single string literal, and a real
|
|
157
|
+
// model runs to hundreds of kilobytes. Adjacent literals are concatenated by
|
|
158
|
+
// the translation phase before that limit applies, so this stays portable
|
|
159
|
+
// rather than relying on gcc/clang having no practical limit.
|
|
160
|
+
//
|
|
161
|
+
// Only `\` and `"` need escaping: JSON.stringify output contains no raw
|
|
162
|
+
// control characters (it writes them as the six TEXT characters \u00XX), and
|
|
163
|
+
// C string literals take UTF-8 bytes verbatim. Escaping the backslash also
|
|
164
|
+
// means no `\uXXXX` ever reaches the C lexer, which matters - a universal
|
|
165
|
+
// character name below 0xA0 is ill-formed C, so the JSON's own escapes would
|
|
166
|
+
// have been rejected if they had been passed through.
|
|
167
|
+
//
|
|
168
|
+
// Chunks are cut from the RAW text and escaped afterwards, so a cut can never
|
|
169
|
+
// land inside an escape sequence. Surrogate pairs are kept whole, or the cut
|
|
170
|
+
// would emit a lone surrogate as invalid UTF-8.
|
|
171
|
+
function cStringLiteral(json: string, chunkSize: number = 2000): string {
|
|
172
|
+
const parts: string[] = []
|
|
173
|
+
let i = 0
|
|
174
|
+
while (i < json.length) {
|
|
175
|
+
let end = Math.min(i + chunkSize, json.length)
|
|
176
|
+
const code = json.charCodeAt(end - 1)
|
|
177
|
+
if (end < json.length && 0xd800 <= code && code <= 0xdbff) {
|
|
178
|
+
end++
|
|
179
|
+
}
|
|
180
|
+
parts.push(json.slice(i, end))
|
|
181
|
+
i = end
|
|
182
|
+
}
|
|
183
|
+
return parts
|
|
184
|
+
.map((p) => ' "' + p.replace(/\\/g, '\\\\').replace(/"/g, '\\"') + '"')
|
|
185
|
+
.join('\n')
|
|
186
|
+
}
|
|
187
|
+
|
|
153
188
|
export {
|
|
189
|
+
cStringLiteral,
|
|
154
190
|
clean,
|
|
155
191
|
cIdent,
|
|
156
192
|
cName,
|
|
@@ -51,6 +51,19 @@ const Config = cmp(async function Config(props: any) {
|
|
|
51
51
|
`
|
|
52
52
|
: ''
|
|
53
53
|
|
|
54
|
+
// Read the base URL here rather than leaving it to a `$$...$$` stdrep
|
|
55
|
+
// placeholder in the fragment. stdrep can only substitute a path the model
|
|
56
|
+
// actually has: a model with no `info.servers` left the placeholder itself in
|
|
57
|
+
// the generated source, so `options.base` came out as the literal string
|
|
58
|
+
// '$main.kit.info.servers.0.url$'. Reading it explicitly yields '' in that
|
|
59
|
+
// case, which is what every other target already emits, and is identical to
|
|
60
|
+
// the old output whenever the model does define a server. Same defect, and
|
|
61
|
+
// same fix, as ts and js.
|
|
62
|
+
let baseUrl = ''
|
|
63
|
+
try {
|
|
64
|
+
baseUrl = getModelPath(model, `main.${KIT}.info.servers.0.url`)
|
|
65
|
+
} catch (_e) { }
|
|
66
|
+
|
|
54
67
|
File({ name: 'Config.' + target.ext }, () => {
|
|
55
68
|
|
|
56
69
|
Fragment({
|
|
@@ -64,6 +77,8 @@ const Config = cmp(async function Config(props: any) {
|
|
|
64
77
|
// these; this one did not.
|
|
65
78
|
...ctx$.stdrep,
|
|
66
79
|
|
|
80
|
+
"'BASEURL'": JSON.stringify(baseUrl),
|
|
81
|
+
|
|
67
82
|
"'AUTHBLOCK'": authBlock,
|
|
68
83
|
|
|
69
84
|
"'HEADERS'": dartValue(headers, 2),
|
|
@@ -9,6 +9,9 @@ import {
|
|
|
9
9
|
Line,
|
|
10
10
|
cmp,
|
|
11
11
|
each,
|
|
12
|
+
clean,
|
|
13
|
+
configDefinition,
|
|
14
|
+
configReprSetting,
|
|
12
15
|
isAuthActive,
|
|
13
16
|
isConfigData,
|
|
14
17
|
resolveAuthPrefix,
|
|
@@ -25,7 +28,6 @@ import {
|
|
|
25
28
|
|
|
26
29
|
|
|
27
30
|
import {
|
|
28
|
-
clean,
|
|
29
31
|
formatGoMap,
|
|
30
32
|
goFeatureName,
|
|
31
33
|
} from './utility_go'
|
|
@@ -63,57 +65,12 @@ const Config = cmp(async function Config(props: any) {
|
|
|
63
65
|
},\n`
|
|
64
66
|
: ''
|
|
65
67
|
|
|
66
|
-
//
|
|
67
|
-
//
|
|
68
|
-
//
|
|
69
|
-
// source size varies by language, the model does not.
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
entityDefs[e.name] = clean({
|
|
73
|
-
fields: e.fields,
|
|
74
|
-
name: e.name,
|
|
75
|
-
op: e.op,
|
|
76
|
-
relations: e.relations,
|
|
77
|
-
}, true)
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
const featureDefs: any = {}
|
|
81
|
-
each(feature, (f: any) => {
|
|
82
|
-
featureDefs[f.name] = f.config || {}
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
const entityStubs: any = {}
|
|
86
|
-
each(entity, (e: any) => {
|
|
87
|
-
entityStubs[e.name] = {}
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
const optionsDef: any = { base: baseUrl }
|
|
91
|
-
if (0 < svars.length) {
|
|
92
|
-
optionsDef.server = svars.reduce(
|
|
93
|
-
(a: any, v: any) => (a[v.name] = v.dflt, a), {})
|
|
94
|
-
}
|
|
95
|
-
if (authActive) {
|
|
96
|
-
optionsDef.auth = { prefix: authPrefix }
|
|
97
|
-
}
|
|
98
|
-
optionsDef.headers = headers
|
|
99
|
-
optionsDef.entity = entityStubs
|
|
100
|
-
|
|
101
|
-
// Key order here is the order `each` produced, which is sorted, so the
|
|
102
|
-
// emitted JSON is byte-stable across runs like the literal it replaces.
|
|
103
|
-
const configDef = {
|
|
104
|
-
main: { name: model.const.Name },
|
|
105
|
-
feature: featureDefs,
|
|
106
|
-
options: optionsDef,
|
|
107
|
-
entity: entityDefs,
|
|
108
|
-
}
|
|
109
|
-
const configJson = JSON.stringify(configDef)
|
|
110
|
-
|
|
111
|
-
// `auto` decides by size; 'data'/'literal' pin it for this SDK.
|
|
112
|
-
let configReprSetting = 'auto'
|
|
113
|
-
try {
|
|
114
|
-
configReprSetting = getModelPath(model, `main.${KIT}.config.repr`) || 'auto'
|
|
115
|
-
} catch (_e) { }
|
|
116
|
-
const asData = isConfigData(configJson, configReprSetting)
|
|
68
|
+
// The same config as an OBJECT, built by the shared helper so this target's
|
|
69
|
+
// literal and the data that replaces it above the threshold are the same
|
|
70
|
+
// config by construction. The JSON is what the threshold is measured on -
|
|
71
|
+
// emitted source size varies by language, the model does not.
|
|
72
|
+
const { json: configJson } = configDefinition(model)
|
|
73
|
+
const asData = isConfigData(configJson, configReprSetting(model))
|
|
117
74
|
|
|
118
75
|
File({ name: 'config.' + target.ext }, () => {
|
|
119
76
|
|
|
@@ -8,9 +8,13 @@ import {
|
|
|
8
8
|
Fragment,
|
|
9
9
|
Line,
|
|
10
10
|
cmp,
|
|
11
|
+
clean,
|
|
12
|
+
configDefinition,
|
|
13
|
+
configReprSetting,
|
|
11
14
|
each,
|
|
12
15
|
indent,
|
|
13
16
|
isAuthActive,
|
|
17
|
+
isConfigData,
|
|
14
18
|
resolveAuthPrefix,
|
|
15
19
|
serverVariables,
|
|
16
20
|
} from '@voxgig/sdkgen'
|
|
@@ -25,7 +29,6 @@ import {
|
|
|
25
29
|
|
|
26
30
|
|
|
27
31
|
import {
|
|
28
|
-
clean,
|
|
29
32
|
formatJson,
|
|
30
33
|
} from './utility_js'
|
|
31
34
|
|
|
@@ -62,13 +65,58 @@ const Config = cmp(async function Config(props: any) {
|
|
|
62
65
|
svars.map((v: any) => ` ${JSON.stringify(v.name)}: ${JSON.stringify(v.dflt)},\n`).join('') +
|
|
63
66
|
' },\n\n '
|
|
64
67
|
|
|
68
|
+
// Read the base URL here rather than leaving it to a `$$...$$` stdrep
|
|
69
|
+
// placeholder in the fragment. stdrep can only substitute a path the model
|
|
70
|
+
// actually has: a model with no `info.servers` left the placeholder itself in
|
|
71
|
+
// the generated source, so `options.base` came out as the literal string
|
|
72
|
+
// '$main.kit.info.servers.0.url$'. Reading it explicitly yields '' in that
|
|
73
|
+
// case, which is what every other target already emits, and is identical to
|
|
74
|
+
// the old output whenever the model does define a server.
|
|
75
|
+
let baseUrl = ''
|
|
76
|
+
try {
|
|
77
|
+
baseUrl = getModelPath(model, `main.${KIT}.info.servers.0.url`)
|
|
78
|
+
} catch (_e) { }
|
|
79
|
+
|
|
80
|
+
// The same config as an OBJECT, built by the shared helper so this target's
|
|
81
|
+
// literal and the data that replaces it above the threshold are the same
|
|
82
|
+
// config by construction. The JSON is what the threshold is measured on -
|
|
83
|
+
// emitted source size varies by language, the model does not.
|
|
84
|
+
const { json: configJson } = configDefinition(model)
|
|
85
|
+
const asData = isConfigData(configJson, configReprSetting(model))
|
|
86
|
+
|
|
65
87
|
File({ name: 'Config.' + target.ext }, () => {
|
|
66
88
|
|
|
89
|
+
if (asData) {
|
|
90
|
+
Fragment({
|
|
91
|
+
from: ff + 'Config.data.fragment.js',
|
|
92
|
+
|
|
93
|
+
replace: {
|
|
94
|
+
|
|
95
|
+
'// #ImportFeatures': () => each(feature, (f: any) => {
|
|
96
|
+
Line(`const { ${nom(f, 'Name')}Feature } = ` +
|
|
97
|
+
`require('./feature/${f.name}/${nom(f, 'Name')}Feature')`)
|
|
98
|
+
}),
|
|
99
|
+
|
|
100
|
+
'// #FeatureClasses': () => each(feature, (f: any) => {
|
|
101
|
+
Line(` ${f.name}: ${nom(f, 'Name')}Feature,`)
|
|
102
|
+
}),
|
|
103
|
+
|
|
104
|
+
// A JS string literal, so the JSON survives verbatim. JSON.stringify
|
|
105
|
+
// escapes the quotes and backslashes the model contains (values like
|
|
106
|
+
// `$STRING` carry backticks, which a template literal could not).
|
|
107
|
+
"'CONFIGJSON'": JSON.stringify(configJson),
|
|
108
|
+
}
|
|
109
|
+
})
|
|
110
|
+
return
|
|
111
|
+
}
|
|
112
|
+
|
|
67
113
|
Fragment({
|
|
68
114
|
from: ff + 'Config.fragment.js',
|
|
69
115
|
|
|
70
116
|
replace: {
|
|
71
117
|
|
|
118
|
+
"'BASEURL'": JSON.stringify(baseUrl),
|
|
119
|
+
|
|
72
120
|
"'SERVERBLOCK'": serverBlock,
|
|
73
121
|
|
|
74
122
|
"'AUTHBLOCK'": authBlock,
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
|
|
2
|
+
const { BaseFeature } = require('./feature/base/BaseFeature')
|
|
3
|
+
// #ImportFeatures
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
const FEATURE_CLASS = {
|
|
7
|
+
// #FeatureClasses
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
// THE API MODEL, EMBEDDED AS DATA (sdkgen rung L1).
|
|
12
|
+
//
|
|
13
|
+
// The literal form of this file declares the whole model as nested object
|
|
14
|
+
// literals on the class. For a large API that is megabytes of source the
|
|
15
|
+
// JavaScript engine must build node by node on every module load, and that
|
|
16
|
+
// every tool reading this file must parse.
|
|
17
|
+
//
|
|
18
|
+
// As a single string constant it is one token, and V8's JSON parser builds the
|
|
19
|
+
// object far faster than the equivalent literal - JSON.parse is the well-worn
|
|
20
|
+
// trick for exactly this shape of data.
|
|
21
|
+
//
|
|
22
|
+
// Emitted only above a size threshold, or when `main.kit.config.repr` pins it:
|
|
23
|
+
// for a small model the literal is smaller, loads no slower, and is far easier
|
|
24
|
+
// to read when debugging.
|
|
25
|
+
const CONFIG_DATA = 'CONFIGJSON'
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class Config {
|
|
29
|
+
|
|
30
|
+
makeFeature(fn) {
|
|
31
|
+
const fc = FEATURE_CLASS[fn]
|
|
32
|
+
const fi = new fc()
|
|
33
|
+
// TODO: errors etc
|
|
34
|
+
return fi
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
// Parsed ONCE, at module load, exactly like the literal form was built once.
|
|
41
|
+
//
|
|
42
|
+
// The parsed data is assigned onto an instance rather than replacing it, so
|
|
43
|
+
// `config.main` / `.feature` / `.options` / `.entity` read exactly as they did
|
|
44
|
+
// when they were field initialisers, and `makeFeature` stays where it was on
|
|
45
|
+
// the prototype. Callers cannot tell which representation they were given.
|
|
46
|
+
const config = Object.assign(new Config(), JSON.parse(CONFIG_DATA))
|
|
47
|
+
|
|
48
|
+
module.exports = {
|
|
49
|
+
config
|
|
50
|
+
}
|
|
@@ -8,8 +8,11 @@ import {
|
|
|
8
8
|
Fragment,
|
|
9
9
|
Line,
|
|
10
10
|
cmp,
|
|
11
|
+
configDefinition,
|
|
12
|
+
configReprSetting,
|
|
11
13
|
each,
|
|
12
14
|
isAuthActive,
|
|
15
|
+
isConfigData,
|
|
13
16
|
resolveAuthPrefix,
|
|
14
17
|
serverVariables,
|
|
15
18
|
} from '@voxgig/sdkgen'
|
|
@@ -26,6 +29,7 @@ import {
|
|
|
26
29
|
import {
|
|
27
30
|
clean,
|
|
28
31
|
formatLuaTable,
|
|
32
|
+
luaLongString,
|
|
29
33
|
} from './utility_lua'
|
|
30
34
|
|
|
31
35
|
|
|
@@ -61,11 +65,54 @@ const Config = cmp(async function Config(props: any) {
|
|
|
61
65
|
},\n`
|
|
62
66
|
: ''
|
|
63
67
|
|
|
68
|
+
// The same config as an OBJECT, built by the shared helper so this target's
|
|
69
|
+
// literal and the data that replaces it above the threshold are the same
|
|
70
|
+
// config by construction. The JSON is what the threshold is measured on -
|
|
71
|
+
// emitted source size varies by language, the model does not.
|
|
72
|
+
const { json: configJson } = configDefinition(model)
|
|
73
|
+
const asData = isConfigData(configJson, configReprSetting(model))
|
|
74
|
+
|
|
64
75
|
File({ name: 'config.' + target.ext }, () => {
|
|
65
76
|
|
|
66
77
|
Content(`-- ${model.const.Name} SDK configuration
|
|
67
78
|
|
|
68
|
-
|
|
79
|
+
`)
|
|
80
|
+
|
|
81
|
+
// ABOVE THE THRESHOLD: emit the model as DATA.
|
|
82
|
+
//
|
|
83
|
+
// A table constructor makes the Lua parser emit a SETTABLE per entry and
|
|
84
|
+
// the VM run them all on every load; a long-bracket string is one token,
|
|
85
|
+
// and dkjson's decoder builds the table from it.
|
|
86
|
+
//
|
|
87
|
+
// dkjson is already a runtime dependency - `utility/fetcher.lua` decodes
|
|
88
|
+
// every HTTP response with it - so this adds nothing to the SDK.
|
|
89
|
+
//
|
|
90
|
+
// Null handling agrees between the branches by construction: dkjson maps
|
|
91
|
+
// JSON null to nil, and assigning nil to a table key removes it, which is
|
|
92
|
+
// exactly what the literal branch does when `formatLuaTable` emits `nil`.
|
|
93
|
+
if (asData) {
|
|
94
|
+
Content(`local json = require("dkjson")
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
-- THE API MODEL, EMBEDDED AS DATA (sdkgen rung L1).
|
|
98
|
+
--
|
|
99
|
+
-- Emitted only above a size threshold, or when \`main.kit.config.repr\` pins
|
|
100
|
+
-- it: for a small model the table literal is smaller and far easier to read
|
|
101
|
+
-- when debugging.
|
|
102
|
+
local CONFIG_DATA = ${luaLongString(configJson)}
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
-- Parse a fresh, fully materialised config table. Every call re-parses, so
|
|
106
|
+
-- prefer require("config_shared") unless you need a private copy you intend
|
|
107
|
+
-- to mutate.
|
|
108
|
+
local function make_config()
|
|
109
|
+
return json.decode(CONFIG_DATA)
|
|
110
|
+
end
|
|
111
|
+
`)
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
|
|
115
|
+
Content(`-- Build a fresh, fully materialised config table. Every call rebuilds the
|
|
69
116
|
-- whole structure, so prefer require("config_shared") unless you need a
|
|
70
117
|
-- private copy you intend to mutate.
|
|
71
118
|
local function make_config()
|
|
@@ -105,7 +152,10 @@ ${serverBlock}${authBlock} headers = ${formatLuaTable(headers, 3)},
|
|
|
105
152
|
}, true), a), {}), 2)},
|
|
106
153
|
}
|
|
107
154
|
end
|
|
155
|
+
`)
|
|
156
|
+
}
|
|
108
157
|
|
|
158
|
+
Content(`
|
|
109
159
|
|
|
110
160
|
local function make_feature(name)
|
|
111
161
|
local features = require("features")
|