@voxgig/apidef 2.4.1 → 3.1.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.
Files changed (108) hide show
  1. package/dist/apidef.d.ts +7 -2
  2. package/dist/apidef.js +190 -114
  3. package/dist/apidef.js.map +1 -1
  4. package/dist/builder/entity/entity.d.ts +3 -0
  5. package/dist/builder/entity/{apiEntity.js → entity.js} +12 -9
  6. package/dist/builder/entity/entity.js.map +1 -0
  7. package/dist/builder/entity/info.d.ts +3 -0
  8. package/dist/builder/entity/info.js +22 -0
  9. package/dist/builder/entity/info.js.map +1 -0
  10. package/dist/builder/entity.js +7 -21
  11. package/dist/builder/entity.js.map +1 -1
  12. package/dist/builder/flow/flowHeuristic01.js +21 -11
  13. package/dist/builder/flow/flowHeuristic01.js.map +1 -1
  14. package/dist/builder/flow.d.ts +2 -1
  15. package/dist/builder/flow.js +39 -12
  16. package/dist/builder/flow.js.map +1 -1
  17. package/dist/def.d.ts +62 -0
  18. package/dist/def.js +4 -0
  19. package/dist/def.js.map +1 -0
  20. package/dist/desc.d.ts +87 -0
  21. package/dist/desc.js +4 -0
  22. package/dist/desc.js.map +1 -0
  23. package/dist/guide/guide.d.ts +2 -1
  24. package/dist/guide/guide.js +161 -30
  25. package/dist/guide/guide.js.map +1 -1
  26. package/dist/guide/heuristic01.d.ts +2 -1
  27. package/dist/guide/heuristic01.js +1122 -234
  28. package/dist/guide/heuristic01.js.map +1 -1
  29. package/dist/model.d.ts +90 -0
  30. package/dist/model.js +4 -0
  31. package/dist/model.js.map +1 -0
  32. package/dist/parse.d.ts +4 -3
  33. package/dist/parse.js +40 -46
  34. package/dist/parse.js.map +1 -1
  35. package/dist/resolver.js +2 -1
  36. package/dist/resolver.js.map +1 -1
  37. package/dist/transform/args.d.ts +3 -0
  38. package/dist/transform/args.js +54 -0
  39. package/dist/transform/args.js.map +1 -0
  40. package/dist/transform/clean.d.ts +2 -2
  41. package/dist/transform/clean.js +28 -3
  42. package/dist/transform/clean.js.map +1 -1
  43. package/dist/transform/entity.d.ts +9 -1
  44. package/dist/transform/entity.js +57 -41
  45. package/dist/transform/entity.js.map +1 -1
  46. package/dist/transform/field.d.ts +1 -1
  47. package/dist/transform/field.js +89 -65
  48. package/dist/transform/field.js.map +1 -1
  49. package/dist/transform/flow.d.ts +3 -0
  50. package/dist/transform/flow.js +26 -0
  51. package/dist/transform/flow.js.map +1 -0
  52. package/dist/transform/flowstep.d.ts +3 -0
  53. package/dist/transform/flowstep.js +145 -0
  54. package/dist/transform/flowstep.js.map +1 -0
  55. package/dist/transform/operation.d.ts +3 -3
  56. package/dist/transform/operation.js +101 -296
  57. package/dist/transform/operation.js.map +1 -1
  58. package/dist/transform/select.d.ts +3 -0
  59. package/dist/transform/select.js +65 -0
  60. package/dist/transform/select.js.map +1 -0
  61. package/dist/transform/top.js +24 -2
  62. package/dist/transform/top.js.map +1 -1
  63. package/dist/transform.d.ts +1 -1
  64. package/dist/transform.js +4 -0
  65. package/dist/transform.js.map +1 -1
  66. package/dist/tsconfig.tsbuildinfo +1 -1
  67. package/dist/types.d.ts +115 -14
  68. package/dist/types.js +4 -2
  69. package/dist/types.js.map +1 -1
  70. package/dist/utility.d.ts +34 -2
  71. package/dist/utility.js +444 -6
  72. package/dist/utility.js.map +1 -1
  73. package/model/apidef.jsonic +76 -1
  74. package/model/guide.jsonic +14 -44
  75. package/package.json +19 -16
  76. package/src/apidef.ts +258 -122
  77. package/src/builder/entity/{apiEntity.ts → entity.ts} +18 -11
  78. package/src/builder/entity/info.ts +53 -0
  79. package/src/builder/entity.ts +9 -35
  80. package/src/builder/flow/flowHeuristic01.ts +46 -12
  81. package/src/builder/flow.ts +54 -13
  82. package/src/def.ts +91 -0
  83. package/src/desc.ts +154 -0
  84. package/src/guide/guide.ts +208 -134
  85. package/src/guide/heuristic01.ts +1653 -272
  86. package/src/model.ts +143 -0
  87. package/src/parse.ts +50 -59
  88. package/src/resolver.ts +3 -1
  89. package/src/schematron.ts.off +317 -0
  90. package/src/transform/args.ts +98 -0
  91. package/src/transform/clean.ts +45 -11
  92. package/src/transform/entity.ts +96 -50
  93. package/src/transform/field.ts +136 -75
  94. package/src/transform/flow.ts +59 -0
  95. package/src/transform/flowstep.ts +242 -0
  96. package/src/transform/operation.ts +119 -419
  97. package/src/transform/select.ts +119 -0
  98. package/src/transform/top.ts +46 -4
  99. package/src/transform.ts +8 -4
  100. package/src/types.ts +181 -5
  101. package/src/utility.ts +567 -9
  102. package/dist/builder/entity/apiEntity.d.ts +0 -3
  103. package/dist/builder/entity/apiEntity.js.map +0 -1
  104. package/dist/builder/entity/def.d.ts +0 -3
  105. package/dist/builder/entity/def.js +0 -19
  106. package/dist/builder/entity/def.js.map +0 -1
  107. package/src/builder/entity/def.ts +0 -44
  108. package/src/guide.ts.off +0 -136
@@ -1,475 +1,175 @@
1
1
 
2
2
 
3
- import { each, getx, snakify } from 'jostraca'
3
+ import { each } from 'jostraca'
4
4
 
5
- import { transform, setprop, getprop } from '@voxgig/struct'
5
+ import type { TransformResult, Transform } from '../transform'
6
6
 
7
- import type { TransformResult } from '../transform'
8
7
 
9
- import { fixName, OPKIND } from '../transform'
8
+ import {
9
+ KIT,
10
+ GuideEntity,
11
+ GuidePathOp,
12
+ } from '../types'
10
13
 
11
- import { depluralize } from '../utility'
14
+ import type {
15
+ PathDesc,
16
+ } from '../desc'
12
17
 
18
+ import type {
19
+ OpName,
20
+ ModelOpMap,
21
+ ModelOp,
22
+ ModelAlt,
23
+ } from '../model'
13
24
 
14
- const operationTransform = async function(
15
- ctx: any,
16
- ): Promise<TransformResult> {
17
- const { apimodel, model, def, guide } = ctx
18
-
19
- let msg = 'operations: '
20
-
21
- const paramBuilder = (
22
- paramMap: any,
23
- paramDef: any,
24
- opModel: any,
25
- entityModel: any,
26
- pathdef: any,
27
- op: any,
28
- path: any,
29
- entity: any,
30
- model: any
31
- ) => {
32
- const paramSpec: any = paramMap[paramDef.name] = {
33
- required: paramDef.required
34
- }
35
- fixName(paramSpec, paramDef.name)
36
-
37
- const type = paramDef.schema ? paramDef.schema.type : paramDef.type
38
- fixName(paramSpec, type, 'type')
39
-
40
- // Path params are always required.
41
- opModel.validate.params[paramDef.name] = `\`$${paramSpec.TYPE}\``
42
- }
43
25
 
44
26
 
45
- const queryBuilder = (
46
- queryMap: any,
47
- queryDef: any,
48
- opModel: any,
49
- entityModel: any,
50
- pathdef: any,
51
- op: any,
52
- path: any,
53
- entity: any,
54
- model: any
55
- ) => {
56
- const querySpec: any = queryMap[queryDef.name] = {
57
- required: queryDef.required
58
- }
59
- fixName(queryMap[queryDef.name], queryDef.name)
60
-
61
- const type = queryDef.schema ? queryDef.schema.type : queryDef.type
62
- fixName(queryMap[queryDef.name], type, 'type')
63
-
64
- if (queryDef.required) {
65
- opModel.validate.params[queryDef.name] = `\`$${querySpec.TYPE}\``
66
- }
67
- }
27
+ const operationTransform: Transform = async function(
28
+ ctx: any,
29
+ ): Promise<TransformResult> {
30
+ const { apimodel, guide } = ctx
31
+ const kit = apimodel.main[KIT]
68
32
 
33
+ let msg = 'operation '
69
34
 
70
- // Resolve the JSON structure of the request or response.
71
- // NOTE: uses heuristics.
72
- const resolveTransform = (
73
- entityModel: any,
74
- op: any,
75
- kind: 'res' | 'req',
76
- direction: 'resform' | 'reqform',
77
- pathdef: any
78
- ) => {
79
- let out
80
- let why = 'none'
81
-
82
- if (null != op.transform?.[direction]) {
83
- out = op.transform[direction]
84
- }
35
+ each(guide.entity, (gent: GuideEntity, entname: string) => {
36
+ collectOps(gent)
85
37
 
86
- else {
87
- const method = op.method
88
- const mdef = pathdef[method]
89
-
90
- // TODO: fix getx
91
- // const content = 'res' === kind ?
92
- const content = 'resform' === direction ?
93
- (getx(mdef, 'responses.200.content') ||
94
- getx(mdef, 'responses.201.content')) :
95
- getx(mdef, 'requestBody.content')
96
-
97
- if (content) {
98
-
99
- const schema = content['application/json']?.schema
100
-
101
- const propkeys = null == schema?.properties ? [] : Object.keys(schema.properties)
102
-
103
- const resolveDirectionTransform =
104
- 'resform' === direction ? resolveResponseTransform : resolveRequestTransform
105
-
106
- //const [transform, why]
107
- ;[out, why]
108
- = resolveDirectionTransform(
109
- entityModel,
110
- op,
111
- kind,
112
- direction,
113
- method,
114
- mdef,
115
- content,
116
- schema,
117
- propkeys
118
- )
119
-
120
- // out = JSON.stringify(transform)
121
- // out = transform
122
- }
123
- else {
124
- out = 'res' === kind ? '`body`' : '`reqdata`'
125
- }
38
+ const opm: ModelOpMap = {
39
+ load: undefined,
40
+ list: undefined,
41
+ create: undefined,
42
+ update: undefined,
43
+ remove: undefined,
44
+ patch: undefined,
126
45
  }
127
46
 
47
+ resolveLoad(opm, gent)
48
+ resolveList(opm, gent)
49
+ resolveCreate(opm, gent)
50
+ resolveUpdate(opm, gent)
51
+ resolveRemove(opm, gent)
52
+ resolvePatch(opm, gent)
128
53
 
129
- return [out, why]
130
- }
131
-
54
+ kit.entity[entname].op = opm
132
55
 
133
- const resolveResponseTransform = (
134
- entityModel: any,
135
- op: any,
136
- kind: 'res' | 'req',
137
- direction: 'resform' | 'reqform',
138
- method: string,
139
- mdef: any,
140
- content: any,
141
- schema: any,
142
- propkeys: any
143
- ): [any, string] => {
144
- let why = 'default'
145
- let transform: any = '`body`'
146
- const properties = schema?.properties
147
-
148
- if (null == content || null == schema || null == propkeys || null == properties) {
149
- return [transform, why]
150
- }
56
+ msg += gent.name + ' '
57
+ })
151
58
 
152
- const opname = op.key$
59
+ return { ok: true, msg }
60
+ }
153
61
 
154
- if ('list' === opname) {
155
- if ('array' !== schema.type) {
156
- if (1 === propkeys.length) {
157
- why = 'list-single-prop:' + propkeys[0]
158
- transform = '`body.' + propkeys[0] + '`'
159
- }
160
- else {
161
- // Use sub property that is an array
162
- for (let pk of propkeys) {
163
- if ('array' === properties[pk]?.type) {
164
- why = 'list-single-array:' + pk
165
- transform = '`body.' + pk + '`'
166
62
 
167
- // TODO: if each item has prop === name of entity, use that, get with $EACH
63
+ function collectOps(gent: GuideEntity) {
64
+ ; (gent as any).opm$ = (gent as any).opm$ ?? {}
65
+ each((gent as any).paths$, (pathdesc: PathDesc) => {
66
+ each(pathdesc.op, (gop: GuidePathOp, opname: OpName) => {
67
+ ; (gent as any).opm$[opname] = (gent as any).opm$[opname] ?? { paths: [] }
168
68
 
169
- break
170
- }
171
- }
172
- }
173
- }
174
- }
175
- else {
176
- if ('object' === schema.type) {
177
- if (null == properties.id) {
178
- if (1 === propkeys.length) {
179
- why = 'map-single-prop:' + propkeys[0]
180
- transform = '`body.' + propkeys[0] + '`'
181
- }
182
- else {
183
- for (let pk of propkeys) {
184
- if (properties[pk]?.properties?.id) {
185
- why = 'map-sub-prop:' + pk
186
- transform = '`body.' + pk + '`'
187
- break
188
- }
189
- }
190
- }
191
- }
69
+ const oppathdesc: PathDesc = {
70
+ orig: pathdesc.orig,
71
+ parts: pathdesc.parts,
72
+ rename: pathdesc.rename,
73
+ method: gop.method as any,
74
+ op: gop as any,
75
+ def: pathdesc.def,
192
76
  }
193
- }
194
-
195
- return [transform, why]
196
- }
197
77
 
78
+ ; (gent as any).opm$[opname].paths.push(oppathdesc)
79
+ })
80
+ })
81
+ }
198
82
 
199
- const resolveRequestTransform = (
200
- entityModel: any,
201
- op: any,
202
- kind: 'res' | 'req',
203
- direction: 'resform' | 'reqform',
204
- method: string,
205
- mdef: any,
206
- content: any,
207
- schema: any,
208
- propkeys: any
209
- ): [any, string] => {
210
- let transform: any = '`reqdata`'
211
- let why = 'default'
212
- const properties = schema?.properties
213
-
214
- if (null == content || null == schema || null == propkeys || null == properties) {
215
- return [transform, why]
216
- }
217
-
218
- const opname = op.key$
219
83
 
220
- if ('list' === opname) {
221
- if ('array' !== schema.type) {
222
- if (1 === propkeys.length) {
223
- why = 'list-single-prop:' + propkeys[0]
224
- transform = { [propkeys[0]]: '`reqdata`' }
225
- }
226
- else {
227
- // Use sub property that is an array
228
- for (let pk of propkeys) {
229
- if ('array' === properties[pk]?.type) {
230
- why = 'list-single-array:' + pk
231
- transform = { [pk]: '`reqdata`' }
232
- break
233
- }
234
- }
235
- }
236
- }
237
- }
238
- else {
239
- if ('object' === schema.type) {
240
- if (null == properties.id) {
241
- if (1 === propkeys.length) {
242
- why = 'map-single-prop:' + propkeys[0]
243
- transform = { [propkeys[0]]: '`reqdata`' }
244
- }
245
- else {
246
- for (let pk of propkeys) {
247
- if (properties[pk]?.properties?.id) {
248
- why = 'map-sub-prop:' + pk
249
- transform = { [pk]: '`reqdata`' }
250
- break
251
- }
252
- }
253
- }
254
- }
255
- }
256
- }
257
84
 
258
- return [transform, why]
259
- }
260
85
 
261
86
 
262
- const opBuilder: any = {
263
- any: (
264
- entityModel: any,
265
- pathdef: any,
266
- guideOp: any,
267
- guidePath: any,
268
- guideEntity: any,
269
- model: any
270
- ) => {
271
- if (false === guidePath.active) {
272
- return
273
- }
87
+ function resolveLoad(opm: ModelOpMap, gent: GuideEntity): undefined | ModelOp {
88
+ const opdesc = opm.load = resolveOp('load', gent)
89
+ return opdesc
90
+ }
274
91
 
275
- const opname = guideOp.key$
276
- const method = guideOp.method
277
- const kind = OPKIND[opname]
278
92
 
279
- const existingOpModel = entityModel.op[opname]
280
- const existingParam = existingOpModel?.param
93
+ function resolveList(opm: ModelOpMap, gent: GuideEntity): undefined | ModelOp {
94
+ const opdesc = opm.list = resolveOp('list', gent)
95
+ return opdesc
96
+ }
281
97
 
282
- const [resform, resform_COMMENT] =
283
- resolveTransform(entityModel, guideOp, kind, 'resform', pathdef)
284
98
 
285
- const [reqform, reqform_COMMENT] =
286
- resolveTransform(entityModel, guideOp, kind, 'reqform', pathdef)
99
+ function resolveCreate(opm: ModelOpMap, gent: GuideEntity): undefined | ModelOp {
100
+ const opdesc = opm.create = resolveOp('create', gent)
101
+ return opdesc
102
+ }
287
103
 
288
- const opModel = {
289
- path: guidePath.key$,
290
- pathalt: ([] as any[]),
291
104
 
292
- method,
293
- kind,
294
- param: existingParam || {},
295
- query: {},
105
+ function resolveUpdate(opm: ModelOpMap, gent: GuideEntity): undefined | ModelOp {
106
+ const opdesc = opm.update = resolveOp('update', gent)
107
+ return opdesc
108
+ }
296
109
 
297
- resform_COMMENT: 'derivation: ' + resform_COMMENT,
298
- resform,
299
110
 
300
- reqform_COMMENT: 'derivation: ' + reqform_COMMENT,
301
- reqform,
111
+ function resolveRemove(opm: ModelOpMap, gent: GuideEntity): undefined | ModelOp {
112
+ const opdesc = opm.remove = resolveOp('remove', gent)
113
+ return opdesc
114
+ }
302
115
 
303
- validate: {
304
- params: { '`$OPEN`': true }
305
- }
306
- }
307
116
 
308
- fixName(opModel, guideOp.key$)
117
+ function resolvePatch(opm: ModelOpMap, gent: GuideEntity): undefined | ModelOp {
118
+ const opdesc = resolveOp('patch', gent)
309
119
 
310
- let params: any[] = []
120
+ // If patch is actually update, make it update!
121
+ if (null != opdesc && null == opm.update) {
122
+ opm.update = opdesc
123
+ opm.update.name = 'update'
124
+ }
125
+ else {
126
+ opm.patch = opdesc
127
+ }
311
128
 
312
- // Params are in the path
313
- if (0 < guidePath.params$.length) {
314
- let sharedparams = getx(pathdef, 'parameters?in=path') || []
315
- params = sharedparams.concat(
316
- getx(pathdef[method], 'parameters?in=path') || []
317
- )
129
+ return opdesc
130
+ }
318
131
 
319
- // if (Array.isArray(params)) {
320
- params.reduce((a: any, p: any) =>
321
- (paramBuilder(a, p, opModel, entityModel,
322
- pathdef, guideOp, guidePath, guideEntity, model), a), opModel.param)
323
- //}
324
- }
325
132
 
326
- // Queries are after the ?
327
- let sharedqueries = getx(pathdef, 'parameters?in!=path') || []
328
- let queries = sharedqueries.concat(getx(pathdef[method], 'parameters?in!=path') || [])
329
- queries.reduce((a: any, p: any) =>
330
- (queryBuilder(a, p, opModel, entityModel,
331
- pathdef, guideOp, guidePath, guideEntity, model), a), opModel.query)
332
-
333
- let pathalt: any[] = []
334
- const pathselector = makePathSelector(guidePath.key$)
335
-
336
- let before = false
337
-
338
- if (null != entityModel.op[opname]) {
339
- pathalt = entityModel.op[opname].pathalt
340
-
341
- // Ordering for pathalts: most to least paramrs, then alphanumberic
342
- for (let i = 0; i < pathalt.length; i++) {
343
- let current = pathalt[i]
344
- before =
345
- pathselector.pn$ > current.pn$ ||
346
- (pathselector.pn$ === current.pn$ &&
347
- pathselector.path <= current.path)
348
-
349
- if (before) {
350
- pathalt = [
351
- ...pathalt.slice(0, i),
352
- pathselector,
353
- ...pathalt.slice(i),
354
- ]
355
- break
133
+ function resolveOp(opname: OpName, gent: GuideEntity): undefined | ModelOp {
134
+ let mop: undefined | ModelOp = undefined
135
+ let opdesc = (gent as any).opm$[opname]
136
+ if (opdesc) {
137
+ mop = {
138
+ name: opname,
139
+ alts: opdesc.paths.map((p: PathDesc) => {
140
+ const parts = applyRename(p)
141
+
142
+ const malt: ModelAlt = {
143
+ orig: p.orig,
144
+ parts,
145
+ rename: p.rename,
146
+ method: p.method,
147
+ args: {},
148
+ transform: opdesc.transform ?? {},
149
+ select: {
150
+ exist: []
356
151
  }
357
152
  }
358
- }
359
-
360
- if (!before) {
361
- pathalt.push(pathselector)
362
- }
363
-
364
- opModel.path = pathalt[pathalt.length - 1].path
365
- opModel.pathalt = pathalt
366
-
367
- entityModel.op[opname] = opModel
368
-
369
- return opModel
370
- },
371
-
372
-
373
- list: (entityModel: any, pathdef: any, op: any, path: any, entity: any, model: any) => {
374
- return opBuilder.any(entityModel, pathdef, op, path, entity, model)
375
- },
376
-
377
- load: (entityModel: any, pathdef: any, op: any, path: any, entity: any, model: any) => {
378
- return opBuilder.any(entityModel, pathdef, op, path, entity, model)
379
- },
380
-
381
- create: (entityModel: any, pathdef: any, op: any, path: any, entity: any, model: any) => {
382
- return opBuilder.any(entityModel, pathdef, op, path, entity, model)
383
- },
384
153
 
385
- update: (entityModel: any, pathdef: any, op: any, path: any, entity: any, model: any) => {
386
- return opBuilder.any(entityModel, pathdef, op, path, entity, model)
387
- },
154
+ malt.transform.req = malt.transform.req ?? '`reqdata`'
155
+ malt.transform.res = malt.transform.res ?? '`body`'
388
156
 
389
- remove: (entityModel: any, pathdef: any, op: any, path: any, entity: any, model: any) => {
390
- return opBuilder.any(entityModel, pathdef, op, path, entity, model)
391
- },
392
-
393
- }
394
-
395
- /*
396
- console.dir(
397
- transform({ guide }, {
398
- entity: {
399
- '`$PACK`': ['guide.entity', {
400
- '`$KEY`': 'name',
401
- op: {
402
- // load: ['`$IF`', ['`$SELECT`',{path:{'`$ANY`':{op:{load:'`$EXISTS`'}}}}], {
403
- load: ['`$IF`', 'path.*.op.load', {
404
- path: () => 'foo'
405
- }]
406
- }
407
- }]
408
- }
409
- }), { depth: null })
410
- */
411
-
412
- each(guide.entity, (guideEntity: any) => {
413
- let opcount = 0
414
- const entityModel = apimodel.main.api.entity[guideEntity.key$]
415
- each(guideEntity.path, (guidePath: any) => {
416
- const pathdef = def.paths[guidePath.key$]
417
-
418
- each(guidePath.op, (guideOp: any) => {
419
- const opbuild = opBuilder[guideOp.key$]
420
-
421
- if (opbuild) {
422
- opbuild(entityModel, pathdef, guideOp, guidePath, guideEntity, model)
423
- opcount++
424
- }
157
+ return malt
425
158
  })
426
- })
427
-
428
- // Full list of params only know after all operations built.
429
- each(entityModel.op, (op: any) => {
430
- const params = Object.keys(op.param || {})
431
- const pathalt = op.pathalt || []
432
-
433
- // if ('course' === entityModel.name) {
434
- // console.log('PA', params, pathalt)
435
- // }
436
-
437
- for (const pa of pathalt) {
438
- for (const p of params) {
439
- pa[p] = pa[p] || false
440
- // if ('course' === entityModel.name) {
441
- // console.log('PA-SET', p, pa)
442
- // }
443
- }
444
- }
445
- })
446
-
447
- // if ('course' === entityModel.name) {
448
- // console.dir(entityModel, { depth: null })
449
- // }
450
-
451
- msg += guideEntity.name + '=' + opcount + ' '
452
- })
453
-
454
- return { ok: true, msg }
159
+ }
160
+ }
161
+ return mop
455
162
  }
456
163
 
457
164
 
458
- function makePathSelector(path: string) {
459
- let out: any = { path }
165
+ function applyRename(pathdesc: PathDesc): string[] {
166
+ const prn: Record<string, string> = pathdesc.rename?.param ?? {}
167
+ return pathdesc.parts.map(p => '{' === p[0] ? (prn[p.substring(1, p.length - 1)] ?? p) : p)
168
+ }
460
169
 
461
- let pn$ = 0
462
- for (const m of path.matchAll(/\/[^\/]+\/{([^}]+)\}/g)) {
463
- const paramName = depluralize(snakify(m[1]))
464
- out[paramName] = true
465
- pn$++
466
- }
467
- out.pn$ = pn$
468
170
 
469
- return out
470
- }
471
171
 
472
172
 
473
173
  export {
474
- operationTransform
174
+ operationTransform,
475
175
  }