@voxgig/apidef 3.1.1 → 3.3.1

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.
@@ -53,6 +53,8 @@ import type {
53
53
  } from '../utility'
54
54
 
55
55
 
56
+ const KONSOLE_LOG = console['log']
57
+
56
58
 
57
59
  // Log non - fatal wierdness.
58
60
  const dlog = getdlog('apidef', __filename)
@@ -63,7 +65,6 @@ const IS_ENTCMP_METHOD_RATE = 0.21
63
65
  const IS_ENTCMP_PATH_RATE = 0.41
64
66
 
65
67
 
66
-
67
68
  const METHOD_IDOP: Record<string, string> = {
68
69
  GET: 'load',
69
70
  POST: 'create',
@@ -88,6 +89,7 @@ const METHOD_CONSIDER_ORDER: Record<string, number> = {
88
89
 
89
90
  async function heuristic01(ctx: ApiDefContext): Promise<Guide> {
90
91
 
92
+ // TODO: Ordu needs better debug output to track task exec
91
93
  const analysis = new Ordu({ select: { sort: true } }).add([
92
94
  Prepare,
93
95
  {
@@ -120,22 +122,13 @@ async function heuristic01(ctx: ApiDefContext): Promise<Guide> {
120
122
 
121
123
  const guide = result.data.guide
122
124
 
123
- // console.log('WORK', result.data.work)
124
-
125
- // console.log('GUIDE')
126
- // console.dir(guide, { depth: null })
127
-
128
-
129
- // TODO: move to Ordu
130
- // warnOnError('reviewEntityDescs', ctx.warn, () => reviewEntityDescs(ctx, result))
131
-
132
125
  return guide
133
126
 
134
127
  }
135
128
 
136
129
 
137
130
  function ShowNode(spec: TaskSpec) {
138
- console.log('NODE', spec.node.key, spec.node.val)
131
+ KONSOLE_LOG('NODE', spec.node.key, spec.node.val)
139
132
  }
140
133
 
141
134
 
@@ -242,7 +235,6 @@ function selectCmpXrefs(_source: any, spec: TaskSpec) {
242
235
  const out = find(spec.ctx.def, 'x-ref')
243
236
  .filter(xref => xref.val.match(/\/(components\/schemas|definitions)\//))
244
237
 
245
- // console.log('selectCmpXrefs', out)
246
238
  return out
247
239
  }
248
240
 
@@ -271,9 +263,10 @@ function selectAllMethods(_source: any, spec: TaskSpec): MethodDesc[] {
271
263
  const ctx = spec.ctx
272
264
  // const paths = ctx.def.paths
273
265
 
266
+ /*
274
267
  let caught = capture(ctx.def, {
275
268
  paths:
276
- ['`$SELECT`', /.*/,
269
+ ['`$SELECT`', /.* /,
277
270
  ['`$SELECT`', /^get|post|put|patch|delete$/i,
278
271
  ['`$APPEND`', 'methods', {
279
272
  path: '`select$=key.paths`',
@@ -286,11 +279,35 @@ function selectAllMethods(_source: any, spec: TaskSpec): MethodDesc[] {
286
279
  }]
287
280
  ]
288
281
  ]
289
- })
282
+ })
290
283
 
291
- // TODO: capture should return these empty objects
292
- caught = caught ?? {}
293
- caught.methods = caught.methods ?? []
284
+ // TODO: capture should return these empty objects
285
+ caught = caught ?? {}
286
+ caught.methods = caught.methods ?? []
287
+
288
+ */
289
+
290
+ let caught: any = { methods: [] }
291
+
292
+ Object.entries(ctx.def.paths).map((n: any) => {
293
+ const path = n[0]
294
+ const pdef = n[1]
295
+
296
+ Object.entries(pdef).map((m: any) => {
297
+ const method = m[0].toUpperCase()
298
+ const mdef = m[1]
299
+
300
+ caught.methods.push({
301
+ path,
302
+ method,
303
+ summary: mdef.summary,
304
+ tags: mdef.tags,
305
+ parameters: mdef.parameters,
306
+ responses: mdef.responses,
307
+ requestBody: mdef.requestBody,
308
+ })
309
+ })
310
+ })
294
311
 
295
312
  caught.methods.sort((a: any, b: any) => {
296
313
  if (a.path < b.path) {
@@ -310,8 +327,6 @@ function selectAllMethods(_source: any, spec: TaskSpec): MethodDesc[] {
310
327
  }
311
328
  })
312
329
 
313
- // console.log(caught.methods.map((n: any) => n.path + ' ' + n.method))
314
-
315
330
  return caught.methods || []
316
331
  }
317
332
 
@@ -402,7 +417,7 @@ function ResolveEntityComponent(spec: TaskSpec) {
402
417
  const pcount = metrics.count.path
403
418
  const method_rate = (0 < mcount ? (cmprefs / mcount) : -1)
404
419
  const path_rate = (0 < pcount ? (cmprefs / pcount) : -1)
405
- // console.log('RCN', xref.cmp, cmprefs, mcount, method_rate, IS_ENTCMP_METHOD_RATE, method_rate < IS_ENTCMP_METHOD_RATE)
420
+
406
421
  const infrequent =
407
422
  method_rate < IS_ENTCMP_METHOD_RATE
408
423
  || path_rate < IS_ENTCMP_PATH_RATE
@@ -1036,8 +1051,6 @@ function ResolveTransform(spec: TaskSpec) {
1036
1051
  const resprops = getResponseSchema(resokdef)?.properties
1037
1052
  debugpath(pathStr, methodName, 'TRANSFORM-RES', keysof(resprops))
1038
1053
 
1039
- // console.log('APIDEF-resprops', resprops)
1040
-
1041
1054
  if (resprops) {
1042
1055
  if (resprops[entdesc.origname]) {
1043
1056
  transform.res = '`body.' + entdesc.origname + '`'
@@ -1067,8 +1080,6 @@ function ResolveTransform(spec: TaskSpec) {
1067
1080
 
1068
1081
  function BuildEntity(spec: TaskSpec) {
1069
1082
  const entdesc = spec.node.val
1070
- // console.log('BUILD-ENTITY')
1071
- // console.dir(entdesc, { depth: null })
1072
1083
 
1073
1084
  const guide: Guide = spec.data.guide
1074
1085
  guide.metrics.count.entity++
@@ -1078,7 +1089,6 @@ function BuildEntity(spec: TaskSpec) {
1078
1089
  const path: Record<string, GuidePath> = {}
1079
1090
 
1080
1091
  const rename_param = (pathdesc: any) => {
1081
- // console.log('RENAME-PATHDESC', pathdesc)
1082
1092
  const out: Record<string, GuideRenameParam> = {}
1083
1093
  each(pathdesc.rename.param, (item: any) => {
1084
1094
  out[item.key$] = {
@@ -1371,8 +1381,6 @@ function entityCmpMatch(
1371
1381
  pathish: true,
1372
1382
  }
1373
1383
 
1374
- // console.log('ECM-A', out, ment)
1375
-
1376
1384
  const cmpInfrequent = (
1377
1385
  ment.method_rate < IS_ENTCMP_METHOD_RATE
1378
1386
  || ment.path_rate < IS_ENTCMP_PATH_RATE
@@ -1431,8 +1439,6 @@ function entityCmpMatch(
1431
1439
  mdesc.method, entname + '->', out, why, ment,
1432
1440
  IS_ENTCMP_METHOD_RATE, IS_ENTCMP_PATH_RATE)
1433
1441
 
1434
- // console.log('ECM-Z', out, why, ment)
1435
-
1436
1442
  return out
1437
1443
  }
1438
1444
 
@@ -1647,7 +1653,6 @@ function findcmps(
1647
1653
 
1648
1654
 
1649
1655
  found.map((xref: { val: string }) => {
1650
- // console.log('FINDCMPS', pathStr, (md as any).key$, up, xref.val)
1651
1656
  let m = xref.val.match(/\/(components\/schemas|definitions)\/(.+)$/)
1652
1657
  if (m) {
1653
1658
  cmplist.push(m[2])
@@ -1656,7 +1661,7 @@ function findcmps(
1656
1661
  })
1657
1662
  })
1658
1663
  })
1659
- // console.log('FOUNDCMPS', cmps)
1664
+
1660
1665
  return (opts?.uniq ? Array.from(cmpset) : cmplist).map(n =>
1661
1666
  ({ cmp: canonize(n), origcmp: n }))
1662
1667
  }
@@ -1714,119 +1719,9 @@ function hasMethod(def: any, pathStr: string, methodName: string) {
1714
1719
  || null != pathDef[methodName.toUpperCase()]
1715
1720
  )
1716
1721
  )
1717
- console.log('hasMethod', pathStr, methodName, found)
1718
- return found
1719
- }
1720
-
1721
-
1722
-
1723
- /*
1724
- // Some decisions require the full list of potential entities.
1725
- function reviewEntityDescs(ctx: ApiDefContext, result: any) {
1726
- const guide: Guide = result.data.guide
1727
- const metrics = guide.metrics
1728
- const entityDescs = result.data.work.entmap
1729
-
1730
- if (0 < metrics.count.cmp) {
1731
- items(entityDescs).map(([entname, entdesc]: [string, EntityDesc]) => {
1732
-
1733
- // Entities with a single path and single op and no cmp are suspicious
1734
1722
 
1735
- const pathmap = entdesc.path
1736
- const pathcount = size(pathmap)
1737
- const hascmp = null != entdesc.cmp?.namedesc
1738
-
1739
- if (
1740
- 1 === pathcount
1741
- && !hascmp
1742
- ) {
1743
- let pathdesc: EntityPathDesc = each(pathmap)[0]
1744
- const pathStr = (pathdesc as any).key$
1745
-
1746
- if (1 === size(pathdesc.op)) {
1747
- let op = pathdesc.op
1748
-
1749
- // console.log('REVIEW', entdesc.name, pathcount, hascmp, op)
1750
-
1751
- if (op.create) {
1752
-
1753
- // Entities without "good" components
1754
- if (
1755
- entname.includes('_')
1756
- && pathdesc.pm.expr.endsWith('p/t/')
1757
- ) {
1758
- const lastpart = canonize(getelem(pathdesc.pm, -1))
1759
- const tgtent = entityDescs[lastpart]
1760
-
1761
- // console.log('REVIEW', entname, entdesc.cmp, size(pathmap), lastpart, realent)
1762
-
1763
- if (
1764
- null != tgtent
1765
- && tgtent.name !== entname
1766
- && (
1767
- null == tgtent.cmp
1768
- || lastpart == tgtent.cmp
1769
- )
1770
- ) {
1771
-
1772
- // Actually a known component
1773
- // console.dir(entdesc, { depth: null })
1774
-
1775
-
1776
- const realent = guide.entity[entname]
1777
- const realpathmap = realent.path
1778
- let realpath = realpathmap[pathStr]
1779
-
1780
- if (null == realpath) {
1781
- realpath = realpathmap[pathStr] = pathdesc
1782
- }
1783
- else if (null == realpath.op?.create) {
1784
- realpath.op = (realpath.op ?? {})
1785
- realpath.op.create = pathdesc.op.create
1786
- }
1787
-
1788
- realpath.op.create.why_op =
1789
- 'was/create/A:' + entname + ':' + realpath.op.create.why_op
1790
-
1791
- delete entityDescs[entname]
1792
-
1793
- // console.log('REPLACE', entname, realent.name, realpath)
1794
- }
1795
-
1796
- }
1797
- }
1798
-
1799
- else if (op.remove) {
1800
- const otherents: EntityDesc[] = each(entityDescs)
1801
- .filter((ed: EntityDesc) => ed !== entdesc && each(ed.path)
1802
- .filter(epd => epd.key$ === pathStr).length)
1803
-
1804
- const otherent = 1 === otherents.length ? otherents[0] : null
1805
-
1806
- // console.log('OTHERENT', pathStr, otherents.length, otherent)
1807
-
1808
- if (null != otherent && null != otherent.cmp) {
1809
- const otherpath = otherent.path[pathStr]
1810
-
1811
- if (null == otherpath.op.remove) {
1812
- otherpath.op.remove = op.remove
1813
- otherpath.op.remove.why_op =
1814
- 'was/delete/A:' + entname + ':' + op.remove.why_op
1815
- delete entityDescs[entname]
1816
- }
1817
- }
1818
- }
1819
-
1820
- debugpath(pathdesc.pm.path, null,
1821
- 'REVIEW-ENTITY', formatJSONIC(entdesc, { hsepd: 0, $: true, color: true }))
1822
-
1823
-
1824
- }
1825
- }
1826
- })
1827
- }
1723
+ return found
1828
1724
  }
1829
- */
1830
1725
 
1831
1726
 
1832
1727
  export {
package/src/model.ts CHANGED
@@ -10,6 +10,14 @@ type OpName = 'load' | 'list' | 'create' | 'update' | 'remove' | 'patch' | 'head
10
10
 
11
11
 
12
12
  type Model = {
13
+ name: string
14
+ origin?: string
15
+
16
+ const: {
17
+ // TODO: remove
18
+ Name: string
19
+ }
20
+
13
21
  main: {
14
22
  kit: {
15
23
  entity: Record<string, ModelEntity>
@@ -1,5 +1,5 @@
1
1
 
2
- import { joinurl } from '@voxgig/struct'
2
+ import { join } from '@voxgig/struct'
3
3
 
4
4
  import { KIT } from '../types'
5
5
 
@@ -47,7 +47,7 @@ const topTransform = async function(
47
47
  // Swagger 2.0
48
48
  if (def.host) {
49
49
  kit.info.servers.push({
50
- url: (def.schemes?.[0] ?? 'https') + '://' + joinurl([def.host, def.basePath])
50
+ url: (def.schemes?.[0] ?? 'https') + '://' + join([def.host, def.basePath], '/', true)
51
51
  })
52
52
  }
53
53
 
package/src/utility.ts CHANGED
@@ -6,7 +6,12 @@ import { snakify, camelify, kebabify, each } from 'jostraca'
6
6
  import { decircular } from '@voxgig/util'
7
7
 
8
8
  import {
9
- slice, merge, inject, clone, isnode, walk, transform, select
9
+ slice, merge, inject, clone, isnode, walk, transform, select,
10
+ Injection,
11
+ M_VAL,
12
+ M_KEYPRE,
13
+ M_KEYPOST,
14
+
10
15
  } from '@voxgig/struct'
11
16
 
12
17
 
@@ -17,6 +22,8 @@ import type {
17
22
  } from './types'
18
23
 
19
24
 
25
+ const KONSOLE_LOG = console['log']
26
+
20
27
 
21
28
  function makeWarner(spec: { point: string, log: Log }): Warner {
22
29
  const { point, log } = spec
@@ -222,26 +229,28 @@ function capture(data: any, shape: any): Record<string, any> {
222
229
  })
223
230
 
224
231
  if (0 < errs.length) {
225
- console.log('ERRS', errs)
232
+ KONSOLE_LOG('ERRS', errs)
226
233
  dlog(errs)
227
234
  }
228
235
  return meta.capture
229
236
  }
230
237
 
231
238
 
232
- function $CAPTURE(inj: any) {
239
+ function $CAPTURE(inj: Injection) {
233
240
  // Set prop foo with value at x: { x: { '`$CAPTURE`': 'foo' } }
234
- if ('key:pre' === inj.mode) {
241
+ if (M_KEYPRE === inj.mode) {
235
242
  const { val, prior } = inj
236
- const { dparent, key } = prior
237
- const dval = dparent?.[key]
238
- if (undefined !== dval) {
239
- inj.meta.capture[val] = dval
243
+ if (null != prior) {
244
+ const { dparent, key } = prior
245
+ const dval = dparent?.[key]
246
+ if (undefined !== dval) {
247
+ inj.meta.capture[val] = dval
248
+ }
240
249
  }
241
250
  }
242
251
 
243
252
  // Use key x as prop name: { x: '`$CAPTURE`': }
244
- else if ('val' === inj.mode) {
253
+ else if (M_VAL === inj.mode) {
245
254
  const { key, dparent } = inj
246
255
  const dval = dparent?.[key]
247
256
  if (undefined !== dval) {
@@ -251,22 +260,28 @@ function $CAPTURE(inj: any) {
251
260
  }
252
261
 
253
262
 
254
- function $APPEND(inj: any, val: any, ref: any, store: any) {
263
+ function $APPEND(inj: Injection, val: any, ref: any, store: any) {
255
264
  // Set prop foo with value at x: { x: { '`$CAPTURE`': 'foo' } }
256
- if ('key:pre' === inj.mode) {
265
+ if (M_KEYPRE === inj.mode) {
257
266
  const { val, prior } = inj
258
- const { dparent, key } = prior
259
- const dval = dparent?.[key]
260
- if (undefined !== dval) {
261
- inj.meta.capture[val] = (inj.meta.capture[val] || [])
262
- inj.meta.capture[val].push(dval)
267
+ if (null != prior) {
268
+ const { dparent, key } = prior
269
+ const dval = dparent?.[key]
270
+ if (undefined !== dval) {
271
+ inj.meta.capture[val] = (inj.meta.capture[val] || [])
272
+ inj.meta.capture[val].push(dval)
273
+ }
263
274
  }
264
275
  }
265
276
 
266
277
 
267
- else if ('val' === inj.mode) {
278
+ else if (M_VAL === inj.mode) {
268
279
  inj.keyI = inj.keys.length
269
280
 
281
+ if (null == inj.prior) {
282
+ return
283
+ }
284
+
270
285
  const [_, prop, xform] = inj.parent
271
286
  const { key, dparent } = inj.prior
272
287
  const dval = dparent?.[key]
@@ -291,28 +306,30 @@ function $APPEND(inj: any, val: any, ref: any, store: any) {
291
306
 
292
307
 
293
308
 
294
- function $ANY(inj: any, _val: any, _ref: any, store: any) {
295
- if ('key:pre' === inj.mode) {
309
+ function $ANY(inj: Injection, _val: any, _ref: any, store: any) {
310
+ if (M_KEYPRE === inj.mode) {
296
311
  const { prior } = inj
297
312
  const child = inj.parent[inj.key]
298
- const { dparent, key } = prior
299
- const dval = dparent?.[key]
300
- if (isnode(dval)) {
301
- for (let n of Object.entries(dval)) {
302
- let vstore = { ...store }
303
- vstore.$TOP = { [n[0]]: n[1] }
304
- inject(clone({ [n[0]]: child }), vstore, {
305
- meta: inj.meta,
306
- errs: inj.errs,
307
- })
313
+ if (null != prior) {
314
+ const { dparent, key } = prior
315
+ const dval = dparent?.[key]
316
+ if (isnode(dval)) {
317
+ for (let n of Object.entries(dval)) {
318
+ let vstore = { ...store }
319
+ vstore.$TOP = { [n[0]]: n[1] }
320
+ inject(clone({ [n[0]]: child }), vstore, {
321
+ meta: inj.meta,
322
+ errs: inj.errs,
323
+ })
324
+ }
308
325
  }
309
326
  }
310
327
  }
311
328
  }
312
329
 
313
330
 
314
- function $SELECT(inj: any, _val: any, _ref: any, store: any) {
315
- if ('val' === inj.mode) {
331
+ function $SELECT(inj: Injection, _val: any, _ref: any, store: any) {
332
+ if (M_VAL === inj.mode) {
316
333
  inj.keyI = inj.keys.length
317
334
 
318
335
  let [_, selector, descendor] = inj.parent
@@ -352,8 +369,12 @@ function $SELECT(inj: any, _val: any, _ref: any, store: any) {
352
369
  }
353
370
 
354
371
 
355
- function $RECASE(inj: any, val: any, ref: any, store: any) {
356
- if ('key:pre' === inj.mode) {
372
+ function $RECASE(inj: Injection, val: any, ref: any, store: any) {
373
+ if (
374
+ M_KEYPRE === inj.mode
375
+ && null != inj.prior
376
+ && null != inj.prior.prior
377
+ ) {
357
378
  const dval = inj.parent[inj.key]
358
379
 
359
380
  // TODO: handle paths more generally! use inj.prior?
@@ -727,19 +748,22 @@ function warnOnError(where: string, warn: Warner, fn: Function, result?: any) {
727
748
 
728
749
  function debugpath(pathStr: string, methodName: string | null | undefined, ...args: any[]): void {
729
750
  const apipath = process.env.APIDEF_DEBUG_PATH
730
- if (!apipath) return
731
751
 
732
- const [targetPath, targetMethod] = apipath.split(':')
752
+ if (null == apipath || '' === apipath) return
733
753
 
734
- // Check if path matches
735
- if (pathStr !== targetPath) return
754
+ if ('ALL' !== apipath) {
755
+ const [targetPath, targetMethod] = apipath.split(':')
736
756
 
737
- // If a method is specified in apipath and we have a method name, check if it matches
738
- if (targetMethod && methodName) {
739
- if (methodName.toLowerCase() !== targetMethod.toLowerCase()) return
757
+ // Check if path matches
758
+ if (pathStr !== targetPath) return
759
+
760
+ // If a method is specified in apipath and we have a method name, check if it matches
761
+ if (targetMethod && methodName) {
762
+ if (methodName.toLowerCase() !== targetMethod.toLowerCase()) return
763
+ }
740
764
  }
741
765
 
742
- console.log(methodName || '', ...args)
766
+ KONSOLE_LOG(methodName || '', ...args)
743
767
  }
744
768
 
745
769
 
@@ -807,12 +831,14 @@ function relativizePath(path: string): string {
807
831
  }
808
832
 
809
833
 
834
+ // NOTE: removes inactive items by default
810
835
  function getModelPath(
811
836
  model: any,
812
837
  path: string,
813
- flags?: { required?: boolean }
838
+ flags?: { required?: boolean, only_active?: boolean }
814
839
  ): any {
815
840
  const required = flags?.required ?? true
841
+ const only_active = flags?.only_active ?? true
816
842
 
817
843
  if (path === '') {
818
844
  if (required) {
@@ -876,6 +902,26 @@ function getModelPath(
876
902
  current = current[part]
877
903
  }
878
904
 
905
+ if (current && only_active) {
906
+ if (false === current.active) {
907
+ current = undefined
908
+ }
909
+ if ('object' === typeof current) {
910
+ const out: any = Array.isArray(current) ? [] : {}
911
+ Object.entries(current).map((n: any) => {
912
+ if (null != n[1] && false !== n[1].active) {
913
+ if (Array.isArray(out)) {
914
+ out.push(n[1])
915
+ }
916
+ else {
917
+ out[n[0]] = n[1]
918
+ }
919
+ }
920
+ })
921
+ current = out
922
+ }
923
+ }
924
+
879
925
  return current
880
926
  }
881
927