@voxgig/sdkgen 0.34.10 → 0.35.0

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/bin/voxgig-sdkgen CHANGED
@@ -8,7 +8,7 @@ const { Gubu, Fault, One } = require('gubu')
8
8
 
9
9
  const { SdkGen } = require('../dist/sdkgen.js')
10
10
 
11
- const VERSION = '0.34.10'
11
+ const VERSION = '0.35.0'
12
12
  const KONSOLE = console
13
13
 
14
14
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voxgig/sdkgen",
3
- "version": "0.34.10",
3
+ "version": "0.35.0",
4
4
  "main": "dist/sdkgen.js",
5
5
  "type": "commonjs",
6
6
  "types": "dist/sdkgen.d.ts",
@@ -1,6 +1,7 @@
1
1
 
2
2
  import {
3
3
  nom,
4
+ depluralize,
4
5
  } from '@voxgig/apidef'
5
6
 
6
7
 
@@ -11,6 +12,7 @@ import {
11
12
  Fragment,
12
13
  Slot,
13
14
  cmp,
15
+ snakify,
14
16
  } from '@voxgig/sdkgen'
15
17
 
16
18
 
@@ -127,14 +129,14 @@ function generateDirectLoad(model: any, entity: any) {
127
129
  return
128
130
  }
129
131
 
130
- const loadPath = (loadPoint.parts || []).join('/')
131
132
  const loadParams = loadPoint.args?.params || []
133
+ const loadPath = normalizePathParams(loadPoint.parts || [], loadParams, loadPoint.rename?.param)
132
134
 
133
135
  // Get list info for live mode bootstrapping
134
136
  const listOp = entity.op.list
135
137
  const listPoint = listOp?.points?.[0]
136
- const listPath = listPoint ? (listPoint.parts || []).join('/') : ''
137
138
  const listParams = listPoint?.args?.params || []
139
+ const listPath = listPoint ? normalizePathParams(listPoint.parts || [], listParams, listPoint.rename?.param) : ''
138
140
  const hasList = null != listPoint
139
141
 
140
142
  // Ancestor params (not 'id') for live mode
@@ -224,8 +226,8 @@ function generateDirectList(model: any, entity: any) {
224
226
  return
225
227
  }
226
228
 
227
- const listPath = (listPoint.parts || []).join('/')
228
229
  const listParams = listPoint.args?.params || []
230
+ const listPath = normalizePathParams(listPoint.parts || [], listParams, listPoint.rename?.param)
229
231
 
230
232
  // Build live params
231
233
  const liveParams = listParams.map((p: any) => {
@@ -283,6 +285,52 @@ ${paramAsserts} }
283
285
  }
284
286
 
285
287
 
288
+ // Replace raw OpenAPI parameter names in path parts with model parameter names.
289
+ // Path parts may have e.g. {subBreed} while model params use sub_breed.
290
+ // When a rename mapping exists (e.g. closureId -> id), path parts contain the
291
+ // renamed form {id} but params still use the original name closure_id.
292
+ // The rename mapping is used to reverse-lookup the original param name.
293
+ function normalizePathParams(
294
+ parts: string[],
295
+ params: any[],
296
+ rename?: Record<string, string>
297
+ ): string {
298
+ return parts.map((part: string) => {
299
+ // Replace each {paramName} occurrence within the part.
300
+ // Handles both simple parts like "{id}" and compound parts like
301
+ // "{outputFields}.{format}" that contain multiple parameters.
302
+ return part.replace(/\{([^}]+)\}/g, (match: string, rawName: string) => {
303
+ const snaked = snakify(rawName)
304
+ const depluralized = depluralize(snaked)
305
+ const param = params.find((p: any) =>
306
+ p.orig === snaked || p.name === snaked ||
307
+ p.orig === depluralized || p.name === depluralized
308
+ )
309
+ if (param) return '{' + param.name + '}'
310
+
311
+ // Reverse-lookup through rename mapping: if rawName is a renamed value
312
+ // (e.g. "id"), find the original camelCase key (e.g. "closureId"),
313
+ // snakify+depluralize it (e.g. "closure_id"), and match against params.
314
+ if (rename) {
315
+ for (const [origCamel, renamedTo] of Object.entries(rename)) {
316
+ if (renamedTo === rawName) {
317
+ const origSnaked = snakify(origCamel)
318
+ const origDepluralized = depluralize(origSnaked)
319
+ const renamedParam = params.find(
320
+ (p: any) => p.orig === origSnaked || p.name === origSnaked ||
321
+ p.orig === origDepluralized || p.name === origDepluralized
322
+ )
323
+ if (renamedParam) return '{' + renamedParam.name + '}'
324
+ }
325
+ }
326
+ }
327
+
328
+ return match
329
+ })
330
+ }).join('/')
331
+ }
332
+
333
+
286
334
  export {
287
335
  TestDirect
288
336
  }
@@ -78,9 +78,9 @@ const TestEntity = cmp(function TestEntity(props: any) {
78
78
  const indent = 2
79
79
 
80
80
  const idlist = flatten([
81
- '${entity.name}01',
82
- '${entity.name}02',
83
- '${entity.name}03',
81
+ entity.name + '01',
82
+ entity.name + '02',
83
+ entity.name + '03',
84
84
  flatten(items(entity.relations.ancestors, (ap: any) =>
85
85
  items(ap[1], (a: any) =>
86
86
  items(['01', '02', '03'], (n: any) =>
@@ -156,6 +156,10 @@ function basicSetup(extra?: any) {
156
156
 
157
157
 
158
158
  Slot({ name: 'basic' }, () => {
159
+ const flowHasCreate = Object.values(basicflow.step).some(
160
+ (s: any) => s.op === 'create'
161
+ )
162
+
159
163
  Content(`
160
164
  const setup = basicSetup()
161
165
  const client = setup.client
@@ -166,6 +170,15 @@ function basicSetup(extra?: any) {
166
170
 
167
171
  `)
168
172
 
173
+ // When the flow has no create step, bootstrap the entity data variable
174
+ // from existing test data so that subsequent update/load/remove steps
175
+ // can reference it.
176
+ if (!flowHasCreate) {
177
+ const ref01 = entity.name + '_ref01'
178
+ Content(` let ${ref01}_data = Object.values(setup.data.existing.${entity.name})[0] as any
179
+ `)
180
+ }
181
+
169
182
  each(basicflow.step, (step: any, index: any) => {
170
183
  const opgen: OpGen = GENERATE_OP[step.op]
171
184
  opgen(model, entity, basicflow, step, index)
@@ -191,7 +204,7 @@ const generateCreate: OpGen = (
191
204
 
192
205
  const priorSteps = Object.values(flow.step).slice(0, Number(index))
193
206
  const needsEnt = !priorSteps.some((s: any) =>
194
- ['create', 'list', 'load', 'remove'].includes(s.op))
207
+ ['create', 'list', 'load', 'update', 'remove'].includes(s.op))
195
208
 
196
209
  const hasDatvar = priorSteps.some((s: any) => {
197
210
  if ('create' === s.op) {
@@ -243,7 +256,7 @@ const generateList: OpGen = (
243
256
 
244
257
  const priorSteps = Object.values(flow.step).slice(0, Number(index))
245
258
  const needsEnt = !priorSteps.some((s: any) =>
246
- ['create', 'list', 'load', 'remove'].includes(s.op))
259
+ ['create', 'list', 'load', 'update', 'remove'].includes(s.op))
247
260
 
248
261
  Content(`
249
262
  // LIST
@@ -298,9 +311,18 @@ const generateUpdate: OpGen = (
298
311
  const markdefvar = step.input.markdefvar ?? (ref + '_markdef' + (step.input.suffix ?? ''))
299
312
  const srcdatavar = step.input.srcdatavar ?? (ref + '_data' + (step.input.suffix ?? ''))
300
313
 
314
+ const priorSteps = Object.values(flow.step).slice(0, Number(index))
315
+ const needsEnt = !priorSteps.some((s: any) =>
316
+ ['create', 'list', 'load', 'update', 'remove'].includes(s.op))
317
+
301
318
  Content(`
302
319
  // UPDATE
303
- const ${datavar}: any = {}
320
+ `)
321
+ if (needsEnt) {
322
+ Content(` const ${entvar} = client.${nom(entity, 'Name')}()
323
+ `)
324
+ }
325
+ Content(` const ${datavar}: any = {}
304
326
  ${datavar}.id = ${srcdatavar}.id
305
327
  `)
306
328
 
@@ -331,7 +353,7 @@ const generateUpdate: OpGen = (
331
353
 
332
354
  for (let sI = 0; sI < step.spec.length; sI++) {
333
355
  const spec = step.spec[sI]
334
- if ('TextFieldMark' === spec.apply) {
356
+ if ('TextFieldMark' === spec.apply && null != step.input.textfield) {
335
357
  Content(`
336
358
  assert(${resdatavar}[${markdefvar}.name] === ${markdefvar}.value)
337
359
  `)
@@ -356,14 +378,31 @@ const generateLoad: OpGen = (
356
378
 
357
379
  const priorSteps = Object.values(flow.step).slice(0, Number(index))
358
380
  const hasEntVar = priorSteps.some((s: any) =>
359
- ['create', 'list', 'load', 'remove'].includes(s.op))
381
+ ['create', 'list', 'load', 'update', 'remove'].includes(s.op))
382
+
383
+ // Check if srcdatavar was declared by a prior create step or by the
384
+ // preamble bootstrap (which runs when the flow has no create step)
385
+ const flowHasCreate = Object.values(flow.step).some((s: any) => s.op === 'create')
386
+ const preambleRef = entity.name + '_ref01'
387
+ const hasSrcData = (!flowHasCreate && srcdatavar === preambleRef + '_data') ||
388
+ priorSteps.some((s: any) => {
389
+ if ('create' === s.op) {
390
+ const priorRef = s.input?.ref ?? entity.name + '_ref01'
391
+ const priorDatvar = s.input?.datavar ?? (priorRef + '_data' + (s.input?.suffix ?? ''))
392
+ return priorDatvar === srcdatavar
393
+ }
394
+ return false
395
+ })
360
396
 
361
397
  Content(`
362
398
  // LOAD
363
399
  `)
364
400
  if (!hasEntVar) {
365
401
  Content(` const ${entvar} = client.${nom(entity, 'Name')}()
366
- const ${srcdatavar} = Object.values(setup.data.existing.${entity.name})[0] as any
402
+ `)
403
+ }
404
+ if (!hasSrcData) {
405
+ Content(` const ${srcdatavar} = Object.values(setup.data.existing.${entity.name})[0] as any
367
406
  `)
368
407
  }
369
408
  Content(` const ${matchvar}: any = {}
@@ -388,7 +427,7 @@ const generateRemove: OpGen = (
388
427
 
389
428
  const priorSteps = Object.values(flow.step).slice(0, Number(index))
390
429
  const needsEnt = !priorSteps.some((s: any) =>
391
- ['create', 'list', 'load', 'remove'].includes(s.op))
430
+ ['create', 'list', 'load', 'update', 'remove'].includes(s.op))
392
431
 
393
432
  Content(`
394
433
  // REMOVE