@voxgig/sdkgen 3.4.5 → 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/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/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/src/helpers/opExample.ts +11 -1
- package/src/sdkgen.ts +6 -1
- package/src/utility.ts +157 -1
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
|
//
|
|
@@ -100,6 +102,10 @@ export {
|
|
|
100
102
|
CONFIG_REPR_VALUES,
|
|
101
103
|
isConfigData,
|
|
102
104
|
configRepr,
|
|
105
|
+
configReprSetting,
|
|
106
|
+
configDefinition,
|
|
107
|
+
clean,
|
|
108
|
+
rawStringLiteral,
|
|
103
109
|
}
|
|
104
110
|
|
|
105
111
|
|
|
@@ -166,3 +172,153 @@ function isConfigData(configJson: string, repr?: string): boolean {
|
|
|
166
172
|
function configRepr(configJson: string, repr?: string): string {
|
|
167
173
|
return isConfigData(configJson, repr) ? 'data' : 'literal'
|
|
168
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) }
|
|
324
|
+
}
|