@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.
Files changed (34) hide show
  1. package/dist/cmp/ReadmeTop.js +10 -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 +10 -2
  7. package/dist/sdkgen.js.map +1 -1
  8. package/dist/tsconfig.tsbuildinfo +1 -1
  9. package/dist/utility.d.ts +12 -1
  10. package/dist/utility.js +206 -1
  11. package/dist/utility.js.map +1 -1
  12. package/model/sdkgen.aontu +11 -0
  13. package/package.json +1 -1
  14. package/project/.sdk/src/cmp/c/Config_c.ts +45 -0
  15. package/project/.sdk/src/cmp/c/utility_c.ts +36 -0
  16. package/project/.sdk/src/cmp/go/Config_go.ts +86 -2
  17. package/project/.sdk/src/cmp/js/Config_js.ts +49 -1
  18. package/project/.sdk/src/cmp/js/fragment/Config.data.fragment.js +50 -0
  19. package/project/.sdk/src/cmp/js/fragment/Config.fragment.js +1 -1
  20. package/project/.sdk/src/cmp/lua/Config_lua.ts +51 -1
  21. package/project/.sdk/src/cmp/lua/utility_lua.ts +21 -0
  22. package/project/.sdk/src/cmp/php/Config_php.ts +86 -0
  23. package/project/.sdk/src/cmp/py/Config_py.ts +47 -1
  24. package/project/.sdk/src/cmp/rb/Config_rb.ts +46 -2
  25. package/project/.sdk/src/cmp/rust/Config_rust.ts +50 -35
  26. package/project/.sdk/src/cmp/rust/utility_rust.ts +17 -0
  27. package/project/.sdk/src/cmp/ts/Config_ts.ts +49 -1
  28. package/project/.sdk/src/cmp/ts/fragment/Config.data.fragment.ts +50 -0
  29. package/project/.sdk/src/cmp/ts/fragment/Config.fragment.ts +1 -1
  30. package/project/.sdk/src/cmp/zig/Config_zig.ts +47 -40
  31. package/src/cmp/ReadmeTop.ts +10 -1
  32. package/src/helpers/opExample.ts +11 -1
  33. package/src/sdkgen.ts +11 -1
  34. package/src/utility.ts +226 -1
package/dist/utility.js CHANGED
@@ -3,13 +3,21 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.SdkGenError = void 0;
6
+ exports.CONFIG_REPR_VALUES = exports.CONFIG_DATA_THRESHOLD = exports.SdkGenError = void 0;
7
7
  exports.resolvePath = resolvePath;
8
8
  exports.requirePath = requirePath;
9
9
  exports.isAuthActive = isAuthActive;
10
10
  exports.resolveAuthPrefix = resolveAuthPrefix;
11
+ exports.isConfigData = isConfigData;
12
+ exports.configRepr = configRepr;
13
+ exports.configReprSetting = configReprSetting;
14
+ exports.configDefinition = configDefinition;
15
+ exports.clean = clean;
16
+ exports.rawStringLiteral = rawStringLiteral;
11
17
  const node_path_1 = __importDefault(require("node:path"));
18
+ const jostraca_1 = require("jostraca");
12
19
  const apidef_1 = require("@voxgig/apidef");
20
+ const serverVars_1 = require("./helpers/serverVars");
13
21
  // Where a per-target component is loaded from: `<project>/.sdk/dist/<path>`.
14
22
  //
15
23
  // `ctx$.folder` is jostraca's OUTPUT folder, which is the project for an
@@ -79,4 +87,201 @@ class SdkGenError extends Error {
79
87
  }
80
88
  }
81
89
  exports.SdkGenError = SdkGenError;
90
+ // CONFIG REPRESENTATION (design rung L1, threshold from design Q7).
91
+ //
92
+ // Above a size threshold the API model is emitted as DATA - a JSON string
93
+ // constant parsed once - rather than as a composite literal. Below it the
94
+ // literal stays, because for a small model the literal is smaller, simpler,
95
+ // faster to load and far easier to debug, and a symbol table would be pure
96
+ // complexity.
97
+ //
98
+ // The threshold is on the JSON, not the emitted source, because the emitted
99
+ // source size varies by language while the model does not. It is measured in
100
+ // UTF-8 BYTES rather than string length: `.length` counts UTF-16 code units,
101
+ // so a CJK-heavy model would read as roughly a third of its real size and
102
+ // stay on the expensive literal path well past the point where it hurts.
103
+ //
104
+ // Measured on the real gitlab model (923.5 KB of JSON), Go, cold cache,
105
+ // recompiling only the config package:
106
+ //
107
+ // composite literal JSON string constant
108
+ // compile+link wall 30.80 s 0.34 s 91x faster
109
+ // peak compiler RSS 2.49 GB 0.06 GB 39x less
110
+ // binary 7.44 MB 3.51 MB 2.1x smaller
111
+ //
112
+ // The reader side is unchanged either way: make_config returns the same map,
113
+ // so nothing downstream can tell which representation it got.
114
+ const CONFIG_DATA_THRESHOLD = 256 * 1024;
115
+ exports.CONFIG_DATA_THRESHOLD = CONFIG_DATA_THRESHOLD;
116
+ // Should this model be emitted as data rather than as a literal?
117
+ //
118
+ // `repr` is the per-SDK override from `main.kit.config.repr`: 'auto' (the
119
+ // default) decides by size, 'data' and 'literal' pin it. The override is what
120
+ // lets a small fixture exercise the data path - by size alone no test model
121
+ // comes near the threshold, so the branch every large SDK depends on would
122
+ // never be generated, compiled or run in CI.
123
+ const CONFIG_REPR_VALUES = ['auto', 'data', 'literal'];
124
+ exports.CONFIG_REPR_VALUES = CONFIG_REPR_VALUES;
125
+ function isConfigData(configJson, repr) {
126
+ // An unknown value is REJECTED, not ignored. The aontu declaration
127
+ // documents the closed set but does not enforce it here, and silently
128
+ // treating `repr: 'date'` as `auto` would quietly restore the compile cost
129
+ // this exists to remove - the failure mode being a slow build nobody
130
+ // connects to a typo.
131
+ if (null != repr && '' !== repr && !CONFIG_REPR_VALUES.includes(repr)) {
132
+ throw new SdkGenError('sdkgen: main.kit.config.repr must be one of ' +
133
+ CONFIG_REPR_VALUES.join(', ') + ' (got: ' + repr + ')', {});
134
+ }
135
+ if ('data' === repr) {
136
+ return true;
137
+ }
138
+ if ('literal' === repr) {
139
+ return false;
140
+ }
141
+ return CONFIG_DATA_THRESHOLD < Buffer.byteLength(configJson, 'utf8');
142
+ }
143
+ // The chosen representation, as a word - for generation logs and for the
144
+ // per-SDK reporting the fleet regen needs, so a model crossing the threshold
145
+ // is visible rather than showing up as an unexplained whole-file diff.
146
+ function configRepr(configJson, repr) {
147
+ return isConfigData(configJson, repr) ? 'data' : 'literal';
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
+ }
82
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":";;;;;;QA+FE,WAAW;QACX,WAAW;QACX,YAAY;QACZ,iBAAiB;QAIjB,YAAY;QACZ,UAAU;QACV,iBAAiB;QACjB,gBAAgB;QAChB,KAAK;QACL,gBAAgB;AA1GlB,0DAA4B;AAE5B,uCAA+C;AAE/C,2CAAkD;AAElD,qDAAsD;AAGtD,6EAA6E;AAC7E,EAAE;AACF,yEAAyE;AACzE,0EAA0E;AAC1E,wEAAwE;AACxE,qEAAqE;AACrE,6EAA6E;AAC7E,oEAAoE;AACpE,SAAS,WAAW,CAAC,IAAS,EAAE,IAAY;IAC1C,MAAM,IAAI,GAAG,IAAI,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAA;IAClE,MAAM,QAAQ,GAAG,mBAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,CAAA;IACtD,OAAO,QAAQ,CAAA;AACjB,CAAC;AAGD,sEAAsE;AACtE,uEAAuE;AACvE,mDAAmD;AACnD,6EAA6E;AAC7E,0CAA0C;AAC1C,SAAS,YAAY,CAAC,KAAU;IAC9B,MAAM,IAAI,GAAG,IAAA,qBAAY,EAAC,KAAK,EAAE,QAAQ,YAAG,OAAO,EACjD,EAAE,WAAW,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAA;IAC1C,IAAI,IAAI,IAAI,KAAK,KAAK,IAAI,CAAC,IAAI;QAAE,OAAO,KAAK,CAAA;IAE7C,MAAM,IAAI,GAAG,IAAA,qBAAY,EAAC,KAAK,EAAE,QAAQ,YAAG,cAAc,EACxD,EAAE,WAAW,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAA;IAC1C,OAAO,IAAI,IAAI,IAAI,IAAI,KAAK,KAAK,IAAI,CAAC,MAAM,CAAA;AAC9C,CAAC;AAGD,wEAAwE;AACxE,kBAAkB;AAClB,6DAA6D;AAC7D,2EAA2E;AAC3E,2DAA2D;AAC3D,6DAA6D;AAC7D,yEAAyE;AACzE,0EAA0E;AAC1E,gEAAgE;AAChE,SAAS,iBAAiB,CAAC,KAAU;IACnC,MAAM,IAAI,GAAG,IAAA,qBAAY,EAAC,KAAK,EAAE,QAAQ,YAAG,cAAc,EACxD,EAAE,WAAW,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAA;IAC1C,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC,MAAM;QAAE,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IAEnE,MAAM,QAAQ,GAAG,IAAA,qBAAY,EAAC,KAAK,EAAE,QAAQ,YAAG,gBAAgB,EAC9D,EAAE,WAAW,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAA;IAC1C,IAAI,IAAI,IAAI,QAAQ,IAAI,IAAI,IAAI,QAAQ,CAAC,MAAM;QAAE,OAAO,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;IAE/E,OAAO,QAAQ,CAAA;AACjB,CAAC;AAGD,SAAS,WAAW,CAAC,IAAS,EAAE,IAAY,EAAE,KAA4B;IACxE,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;IACxC,MAAM,MAAM,GAAG,IAAI,IAAI,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAA;IAE3D,kEAAkE;IAClE,sEAAsE;IACtE,qEAAqE;IACrE,wEAAwE;IACxE,qCAAqC;IACrC,IAAI,MAAM,EAAE,CAAC;QACX,IAAI,CAAC;YACH,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;QAC3B,CAAC;QACD,OAAO,GAAQ,EAAE,CAAC;YAChB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,iBAAiB,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;YAC7D,OAAO,SAAS,CAAA;QAClB,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC,QAAQ,CAAC,CAAA;AAC1B,CAAC;AAGD,MAAM,WAAY,SAAQ,KAAK;IAC7B,YAAY,GAAG,IAAW;QACxB,KAAK,CAAC,GAAG,IAAI,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,aAAa,CAAA;IAC3B,CAAC;CACF;QAQC,WAAW;AAYb,oEAAoE;AACpE,EAAE;AACF,0EAA0E;AAC1E,0EAA0E;AAC1E,4EAA4E;AAC5E,2EAA2E;AAC3E,cAAc;AACd,EAAE;AACF,4EAA4E;AAC5E,6EAA6E;AAC7E,6EAA6E;AAC7E,0EAA0E;AAC1E,yEAAyE;AACzE,EAAE;AACF,wEAAwE;AACxE,uCAAuC;AACvC,EAAE;AACF,iEAAiE;AACjE,wEAAwE;AACxE,sEAAsE;AACtE,0EAA0E;AAC1E,EAAE;AACF,6EAA6E;AAC7E,8DAA8D;AAC9D,MAAM,qBAAqB,GAAG,GAAG,GAAG,IAAI,CAAA;QAnCtC,qBAAqB;AAsCvB,iEAAiE;AACjE,EAAE;AACF,0EAA0E;AAC1E,8EAA8E;AAC9E,4EAA4E;AAC5E,2EAA2E;AAC3E,6CAA6C;AAC7C,MAAM,kBAAkB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,CAAA;QA5CpD,kBAAkB;AA8CpB,SAAS,YAAY,CAAC,UAAkB,EAAE,IAAa;IACrD,mEAAmE;IACnE,sEAAsE;IACtE,2EAA2E;IAC3E,qEAAqE;IACrE,sBAAsB;IACtB,IAAI,IAAI,IAAI,IAAI,IAAI,EAAE,KAAK,IAAI,IAAI,CAAC,kBAAkB,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACtE,MAAM,IAAI,WAAW,CACnB,8CAA8C;YAC9C,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,SAAS,GAAG,IAAI,GAAG,GAAG,EAAE,EAAE,CAAC,CAAA;IAC/D,CAAC;IACD,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QACpB,OAAO,IAAI,CAAA;IACb,CAAC;IACD,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;QACvB,OAAO,KAAK,CAAA;IACd,CAAC;IACD,OAAO,qBAAqB,GAAG,MAAM,CAAC,UAAU,CAAC,UAAU,EAAE,MAAM,CAAC,CAAA;AACtE,CAAC;AAGD,yEAAyE;AACzE,6EAA6E;AAC7E,uEAAuE;AACvE,SAAS,UAAU,CAAC,UAAkB,EAAE,IAAa;IACnD,OAAO,YAAY,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAA;AAC5D,CAAC;AAGD,2EAA2E;AAC3E,0EAA0E;AAC1E,SAAS,iBAAiB,CAAC,KAAU;IACnC,IAAI,CAAC;QACH,OAAO,IAAA,qBAAY,EAAC,KAAK,EAAE,QAAQ,YAAG,cAAc,CAAC,IAAI,MAAM,CAAA;IACjE,CAAC;IACD,OAAO,EAAE,EAAE,CAAC;QACV,OAAO,MAAM,CAAA;IACf,CAAC;AACH,CAAC;AAGD,kEAAkE;AAClE,EAAE;AACF,kEAAkE;AAClE,EAAE;AACF,+EAA+E;AAC/E,4EAA4E;AAC5E,yEAAyE;AACzE,+EAA+E;AAC/E,iDAAiD;AACjD,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,oEAAoE;AACpE,EAAE;AACF,2EAA2E;AAC3E,+EAA+E;AAC/E,gFAAgF;AAChF,+EAA+E;AAC/E,0EAA0E;AAC1E,MAAM,UAAU,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;AAE7C,MAAM,cAAc,GAAwB;IAC1C,MAAM,EAAE,IAAI;IACZ,GAAG,EAAE,KAAK;IACV,IAAI,EAAE,KAAK;CACZ,CAAA;AAED,MAAM,YAAY,GAAG,CAAC,SAAS,EAAE,SAAS,EAAE,UAAU,CAAC,CAAA;AAEvD,SAAS,KAAK,CAAC,CAAM,EAAE,YAAsB;IAC3C,yEAAyE;IACzE,2EAA2E;IAC3E,sBAAsB;IACtB,MAAM,KAAK,GAAG,CAAC,IAAS,EAAE,QAAiB,EAAO,EAAE;QAClD,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAA;QACxE,IAAI,IAAI,IAAI,IAAI,IAAI,QAAQ,KAAK,OAAO,IAAI,EAAE,CAAC;YAC7C,MAAM,GAAG,GAAQ,EAAE,CAAA;YACnB,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBAClC,IAAI,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC;oBAAE,SAAQ;gBACpC,uEAAuE;gBACvE,EAAE;gBACF,oEAAoE;gBACpE,mEAAmE;gBACnE,iEAAiE;gBACjE,2DAA2D;gBAC3D,kEAAkE;gBAClE,iEAAiE;gBACjE,wDAAwD;gBACxD,IAAI,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC;oBAAE,SAAQ;gBACnC,IAAI,QAAQ,IAAI,CAAC,IAAI,cAAc,IAAI,cAAc,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC;oBAAE,SAAQ;gBAC9E,GAAG,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,QAAQ,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAA;YAChE,CAAC;YACD,OAAO,GAAG,CAAA;QACZ,CAAC;QACD,OAAO,IAAI,CAAA;IACb,CAAC,CAAA;IACD,OAAO,KAAK,CAAC,CAAC,EAAE,IAAI,KAAK,YAAY,CAAC,CAAA;AACxC,CAAC;AAGD,yEAAyE;AACzE,6EAA6E;AAC7E,4CAA4C;AAC5C,EAAE;AACF,6EAA6E;AAC7E,+EAA+E;AAC/E,yEAAyE;AACzE,8EAA8E;AAC9E,6EAA6E;AAC7E,0DAA0D;AAC1D,SAAS,gBAAgB,CAAC,CAAS;IACjC,OAAO,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,GAAG,CAAA;AAClE,CAAC;AAGD,0EAA0E;AAC1E,EAAE;AACF,0EAA0E;AAC1E,wEAAwE;AACxE,8EAA8E;AAC9E,4EAA4E;AAC5E,6EAA6E;AAC7E,8BAA8B;AAC9B,EAAE;AACF,2EAA2E;AAC3E,oDAAoD;AACpD,SAAS,gBAAgB,CAAC,KAAU;IAClC,MAAM,MAAM,GAAG,IAAA,qBAAY,EAAC,KAAK,EAAE,QAAQ,YAAG,SAAS,CAAC,CAAA;IACxD,MAAM,OAAO,GAAG,IAAA,qBAAY,EAAC,KAAK,EAAE,QAAQ,YAAG,UAAU,CAAC,CAAA;IAC1D,MAAM,OAAO,GAAG,IAAA,qBAAY,EAAC,KAAK,EAAE,QAAQ,YAAG,iBAAiB,CAAC,IAAI,EAAE,CAAA;IAEvE,MAAM,UAAU,GAAG,YAAY,CAAC,KAAK,CAAC,CAAA;IACtC,MAAM,UAAU,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAA;IAE3C,IAAI,OAAO,GAAG,EAAE,CAAA;IAChB,IAAI,CAAC;QAAC,OAAO,GAAG,IAAA,qBAAY,EAAC,KAAK,EAAE,QAAQ,YAAG,qBAAqB,CAAC,CAAA;IAAC,CAAC;IAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;IAEtF,MAAM,KAAK,GAAG,IAAA,4BAAe,EAAC,KAAK,CAAC,CAAA;IAEpC,MAAM,UAAU,GAAQ,EAAE,CAAA;IAC1B,MAAM,WAAW,GAAQ,EAAE,CAAA;IAC3B,IAAA,eAAI,EAAC,MAAM,EAAE,CAAC,CAAM,EAAE,EAAE;QACtB,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;YACzB,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,EAAE,EAAE,CAAC,CAAC,EAAE;YACR,SAAS,EAAE,CAAC,CAAC,SAAS;SACvB,EAAE,IAAI,CAAC,CAAA;QACR,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAA;IAC1B,CAAC,CAAC,CAAA;IAEF,MAAM,WAAW,GAAQ,EAAE,CAAA;IAC3B,IAAA,eAAI,EAAC,OAAO,EAAE,CAAC,CAAM,EAAE,EAAE;QACvB,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,IAAI,EAAE,CAAA;IACtC,CAAC,CAAC,CAAA;IAEF,MAAM,OAAO,GAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,CAAA;IACtC,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;QACrB,OAAO,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAM,EAAE,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;IAChF,CAAC;IACD,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,CAAA;IACvC,CAAC;IACD,OAAO,CAAC,OAAO,GAAG,OAAO,CAAA;IACzB,OAAO,CAAC,MAAM,GAAG,WAAW,CAAA;IAE5B,MAAM,GAAG,GAAG;QACV,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE;QAChC,OAAO,EAAE,WAAW;QACpB,OAAO;QACP,MAAM,EAAE,UAAU;KACnB,CAAA;IAED,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAA;AAC3C,CAAC"}
@@ -13,6 +13,17 @@ main: def: {
13
13
  # `<sdk>/.sdk/model/config.aontu`.
14
14
  main: kit: config: docs_order: *['ts','py','php','go','rb','lua'] | [&: string]
15
15
 
16
+ # How the API model is embedded in a generated SDK (design rung L1).
17
+ #
18
+ # auto by size - data above the threshold, literal below (the default)
19
+ # literal always a composite literal, whatever the size
20
+ # data always a parsed JSON constant, whatever the size
21
+ #
22
+ # Declared as a closed set so a typo is REJECTED at model-compile time rather
23
+ # than silently falling through to `auto`, which would quietly restore the
24
+ # compile cost this exists to remove.
25
+ main: kit: config: repr: *'auto' | 'literal' | 'data'
26
+
16
27
  # How the generated test suites behave.
17
28
  main: kit: test: {
18
29
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voxgig/sdkgen",
3
- "version": "3.4.3",
3
+ "version": "3.4.6",
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,
@@ -9,7 +9,11 @@ import {
9
9
  Line,
10
10
  cmp,
11
11
  each,
12
+ clean,
13
+ configDefinition,
14
+ configReprSetting,
12
15
  isAuthActive,
16
+ isConfigData,
13
17
  resolveAuthPrefix,
14
18
  serverVariables,
15
19
  } from '@voxgig/sdkgen'
@@ -24,7 +28,6 @@ import {
24
28
 
25
29
 
26
30
  import {
27
- clean,
28
31
  formatGoMap,
29
32
  goFeatureName,
30
33
  } from './utility_go'
@@ -62,9 +65,87 @@ const Config = cmp(async function Config(props: any) {
62
65
  },\n`
63
66
  : ''
64
67
 
65
- // Config is now in core/ package
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
+
66
75
  File({ name: 'config.' + target.ext }, () => {
67
76
 
77
+ // ABOVE THE THRESHOLD: emit the model as DATA.
78
+ //
79
+ // A composite literal makes the compiler walk every node of the model;
80
+ // a string constant is one token. On the real gitlab model that is 30.8 s
81
+ // and 2.49 GB of compiler memory versus 0.34 s and 0.06 GB, and a binary
82
+ // 2.1x smaller. MakeConfig still returns the same map, so nothing
83
+ // downstream can tell which representation it got.
84
+ //
85
+ // JSON.stringify output is a valid Go interpreted string literal: JSON
86
+ // escapes are a subset of Go's, and Go source is UTF-8 so non-ASCII needs
87
+ // no escaping. A raw (backtick) literal could NOT be used - the model
88
+ // contains backticks in values like `$STRING`.
89
+ if (asData) {
90
+ Content(`package core
91
+
92
+ import (
93
+ "encoding/json"
94
+ "math"
95
+ "sync"
96
+ )
97
+
98
+ // The API model, emitted as data rather than as a composite literal: see
99
+ // sdkgen rung L1. Parsed by MakeConfig, and parsed once by SharedConfig.
100
+ const configJSON = ${JSON.stringify(configJson)}
101
+
102
+ // json.Unmarshal decodes EVERY JSON number as float64, but the literal
103
+ // representation emits an integer token as an untyped constant that lands in
104
+ // map[string]any as an int. MakeConfig is public API and consumers type-assert
105
+ // against it, so the two representations must not disagree about the type of
106
+ // a whole number just because the model crossed a size threshold.
107
+ //
108
+ // Whole values become int; anything fractional, or too large to be exact in a
109
+ // float64, stays float64 - which is what the literal branch does too.
110
+ func configNormalise(val any) any {
111
+ switch v := val.(type) {
112
+ case map[string]any:
113
+ for k, c := range v {
114
+ v[k] = configNormalise(c)
115
+ }
116
+ return v
117
+ case []any:
118
+ for i, c := range v {
119
+ v[i] = configNormalise(c)
120
+ }
121
+ return v
122
+ case float64:
123
+ if v == math.Trunc(v) && math.Abs(v) <= 1<<53 {
124
+ return int(v)
125
+ }
126
+ return v
127
+ }
128
+ return val
129
+ }
130
+
131
+ // MakeConfig parses a fresh, fully materialised config map. Every call
132
+ // re-parses, so prefer SharedConfig unless you need a private copy you
133
+ // intend to mutate.
134
+ func MakeConfig() map[string]any {
135
+ var out map[string]any
136
+ if err := json.Unmarshal([]byte(configJSON), &out); err != nil {
137
+ // Unreachable: the constant is generated by json.Marshal's
138
+ // counterpart and never edited by hand. Panic rather than return a
139
+ // silently empty config, which would fail far from the cause.
140
+ panic("${model.const.Name}: embedded config is not valid JSON: " + err.Error())
141
+ }
142
+ out, _ = configNormalise(out).(map[string]any)
143
+ return out
144
+ }
145
+ `)
146
+ }
147
+ else {
148
+
68
149
  Content(`package core
69
150
 
70
151
  import (
@@ -113,7 +194,10 @@ ${serverBlock}${authBlock} "headers": ${formatGoMap(headers, 3)},
113
194
  }, true), a), {}), 2)},
114
195
  }
115
196
  }
197
+ `)
198
+ }
116
199
 
200
+ Content(`
117
201
  var (
118
202
  sharedConfigOnce sync.Once
119
203
  sharedConfigVal map[string]any
@@ -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