@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.
Files changed (35) hide show
  1. package/dist/cmp/ReadmeTop.js +5 -1
  2. package/dist/cmp/ReadmeTop.js.map +1 -1
  3. package/dist/helpers/opExample.js +10 -1
  4. package/dist/helpers/opExample.js.map +1 -1
  5. package/dist/sdkgen.d.ts +2 -2
  6. package/dist/sdkgen.js +6 -2
  7. package/dist/sdkgen.js.map +1 -1
  8. package/dist/tsconfig.tsbuildinfo +1 -1
  9. package/dist/utility.d.ts +8 -1
  10. package/dist/utility.js +144 -0
  11. package/dist/utility.js.map +1 -1
  12. package/package.json +1 -1
  13. package/project/.sdk/src/cmp/c/Config_c.ts +45 -0
  14. package/project/.sdk/src/cmp/c/utility_c.ts +36 -0
  15. package/project/.sdk/src/cmp/dart/Config_dart.ts +15 -0
  16. package/project/.sdk/src/cmp/dart/fragment/Config.fragment.dart +1 -1
  17. package/project/.sdk/src/cmp/go/Config_go.ts +9 -52
  18. package/project/.sdk/src/cmp/js/Config_js.ts +49 -1
  19. package/project/.sdk/src/cmp/js/fragment/Config.data.fragment.js +50 -0
  20. package/project/.sdk/src/cmp/js/fragment/Config.fragment.js +1 -1
  21. package/project/.sdk/src/cmp/lua/Config_lua.ts +51 -1
  22. package/project/.sdk/src/cmp/lua/utility_lua.ts +21 -0
  23. package/project/.sdk/src/cmp/php/Config_php.ts +86 -0
  24. package/project/.sdk/src/cmp/py/Config_py.ts +47 -1
  25. package/project/.sdk/src/cmp/rb/Config_rb.ts +46 -2
  26. package/project/.sdk/src/cmp/rust/Config_rust.ts +50 -35
  27. package/project/.sdk/src/cmp/rust/utility_rust.ts +17 -0
  28. package/project/.sdk/src/cmp/ts/Config_ts.ts +10 -50
  29. package/project/.sdk/src/cmp/zig/Config_zig.ts +47 -40
  30. package/project/.sdk/src/cmp/zig/fragment/Main.fragment.zig +28 -17
  31. package/project/.sdk/tm/zig/test/gotcha_test.zig +8 -8
  32. package/src/cmp/ReadmeTop.ts +6 -1
  33. package/src/helpers/opExample.ts +11 -1
  34. package/src/sdkgen.ts +6 -1
  35. 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
@@ -1 +1 @@
1
- {"version":3,"file":"utility.js","sourceRoot":"","sources":["../src/utility.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"utility.js","sourceRoot":"","sources":["../src/utility.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voxgig/sdkgen",
3
- "version": "3.4.5",
3
+ "version": "3.4.7",
4
4
  "main": "dist/sdkgen.js",
5
5
  "type": "commonjs",
6
6
  "engines": {
@@ -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),
@@ -25,7 +25,7 @@ class Config {
25
25
  };
26
26
 
27
27
  final Map<String, dynamic> options = <String, dynamic>{
28
- 'base': '$$main.kit.info.servers.0.url$$',
28
+ 'base': 'BASEURL',
29
29
 
30
30
  'AUTHBLOCK''headers': 'HEADERS',
31
31
 
@@ -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
- // Config is now in core/ package
67
- // The same config as an OBJECT. Built regardless of which representation
68
- // wins, because the JSON is what the threshold is measured on - the emitted
69
- // source size varies by language, the model does not.
70
- const entityDefs: any = {}
71
- each(entity, (e: any) => {
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
+ }
@@ -29,7 +29,7 @@ class Config {
29
29
 
30
30
 
31
31
  options = {
32
- base: '$$main.kit.info.servers.0.url$$',
32
+ base: 'BASEURL',
33
33
 
34
34
  'SERVERBLOCK''AUTHBLOCK'headers: 'HEADERS',
35
35
 
@@ -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
- -- Build a fresh, fully materialised config table. Every call rebuilds the
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")