@voxgig/apidef 8.11.0 → 8.12.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.
Files changed (79) hide show
  1. package/dist/apidef.d.ts +4 -1
  2. package/dist/apidef.js +12 -34
  3. package/dist/apidef.js.map +1 -1
  4. package/dist/builder/entity/entity.js +0 -33
  5. package/dist/builder/entity/entity.js.map +1 -1
  6. package/dist/builder/entity/info.js +0 -4
  7. package/dist/builder/entity/info.js.map +1 -1
  8. package/dist/builder/flow.d.ts +4 -1
  9. package/dist/builder/flow.js +36 -27
  10. package/dist/builder/flow.js.map +1 -1
  11. package/dist/guide/graphql01.js +0 -55
  12. package/dist/guide/graphql01.js.map +1 -1
  13. package/dist/guide/guide.js +3 -126
  14. package/dist/guide/guide.js.map +1 -1
  15. package/dist/guide/heuristic01.js +40 -181
  16. package/dist/guide/heuristic01.js.map +1 -1
  17. package/dist/parse/graphql.js +0 -25
  18. package/dist/parse/graphql.js.map +1 -1
  19. package/dist/parse.js +51 -56
  20. package/dist/parse.js.map +1 -1
  21. package/dist/resolved.d.ts +23 -0
  22. package/dist/resolved.js +92 -0
  23. package/dist/resolved.js.map +1 -0
  24. package/dist/resolver.js +0 -2
  25. package/dist/resolver.js.map +1 -1
  26. package/dist/transform/args.js +2 -25
  27. package/dist/transform/args.js.map +1 -1
  28. package/dist/transform/casecollide.d.ts +3 -0
  29. package/dist/transform/casecollide.js +67 -0
  30. package/dist/transform/casecollide.js.map +1 -0
  31. package/dist/transform/contract.js +43 -38
  32. package/dist/transform/contract.js.map +1 -1
  33. package/dist/transform/entity.js +0 -56
  34. package/dist/transform/entity.js.map +1 -1
  35. package/dist/transform/field.js +1 -368
  36. package/dist/transform/field.js.map +1 -1
  37. package/dist/transform/flowstep.js +0 -49
  38. package/dist/transform/flowstep.js.map +1 -1
  39. package/dist/transform/graphql.js +0 -36
  40. package/dist/transform/graphql.js.map +1 -1
  41. package/dist/transform/operation.js +0 -23
  42. package/dist/transform/operation.js.map +1 -1
  43. package/dist/transform/top.js +1 -128
  44. package/dist/transform/top.js.map +1 -1
  45. package/dist/transform.js.map +1 -1
  46. package/dist/tsconfig.tsbuildinfo +1 -1
  47. package/dist/types.d.ts +2 -0
  48. package/dist/types.js.map +1 -1
  49. package/dist/utility.d.ts +2 -1
  50. package/dist/utility.js +17 -316
  51. package/dist/utility.js.map +1 -1
  52. package/model/apidef.aon +20 -113
  53. package/model/guide.aon +1 -32
  54. package/package.json +5 -5
  55. package/src/apidef.ts +22 -33
  56. package/src/builder/entity/entity.ts +0 -33
  57. package/src/builder/entity/info.ts +0 -4
  58. package/src/builder/flow.ts +39 -24
  59. package/src/desc.ts +0 -22
  60. package/src/guide/graphql01.ts +0 -75
  61. package/src/guide/guide.ts +5 -127
  62. package/src/guide/heuristic01.ts +47 -182
  63. package/src/model.ts +6 -85
  64. package/src/parse/graphql.ts +0 -25
  65. package/src/parse.ts +61 -56
  66. package/src/resolved.ts +136 -0
  67. package/src/resolver.ts +0 -2
  68. package/src/transform/args.ts +2 -25
  69. package/src/transform/casecollide.ts +80 -0
  70. package/src/transform/contract.ts +44 -34
  71. package/src/transform/entity.ts +0 -56
  72. package/src/transform/field.ts +2 -368
  73. package/src/transform/flowstep.ts +0 -49
  74. package/src/transform/graphql.ts +0 -36
  75. package/src/transform/operation.ts +0 -23
  76. package/src/transform/top.ts +1 -131
  77. package/src/transform.ts +0 -1
  78. package/src/types.ts +4 -13
  79. package/src/utility.ts +18 -314
@@ -29,6 +29,7 @@ import {
29
29
  import {
30
30
  getdlog,
31
31
  debugpath,
32
+ debugpathOn,
32
33
  formatJSONIC,
33
34
  relativizePath,
34
35
  } from '../utility'
@@ -45,27 +46,6 @@ const aontu = new Aontu()
45
46
 
46
47
 
47
48
 
48
- // MIGRATE, DO NOT ABANDON. The guide is the one model file the user owns —
49
- // entity renames, hides, method overrides, response transforms. Reading
50
- // `guide.aon` without this would find nothing in any project created before
51
- // the extension rename, silently discarding every customization in the 660
52
- // generated repos that carry a guide.aontu.
53
- //
54
- // RENAMING THE FILE IS NOT ENOUGH, and doing only that was worse than doing
55
- // nothing: a legacy guide `@`-includes two files BY THE OLD EXTENSION —
56
- // `@voxgig/apidef/model/guide.aontu`, which this package no longer ships, and
57
- // its sibling `<prefix>base-guide.aontu`, which is now written as `.aon`.
58
- // Carried across byte-for-byte, both dangle, and every build of such a
59
- // project dies on
60
- //
61
- // [aontu/multisource_not_found]: source not found:
62
- // @voxgig/apidef/model/guide.aontu
63
- //
64
- // — which is what apidef-validate hit on all 14 of its real-world specs. So
65
- // the two includes the rename invalidates are rewritten with it. Nothing else
66
- // is touched: the rest of the file is the user's.
67
- //
68
- // Returns true when a migration actually happened.
69
49
  function migrateLegacyGuide(fs: any, folder: string, guideprefix: string): boolean {
70
50
  const guidepath = Path.join(folder, 'guide', guideprefix + 'guide.aon')
71
51
  const legacyguide = Path.join(folder, 'guide', guideprefix + 'guide.aontu')
@@ -74,14 +54,6 @@ function migrateLegacyGuide(fs: any, folder: string, guideprefix: string): boole
74
54
  return false
75
55
  }
76
56
 
77
- // EXACTLY the two includes the rename invalidates, and no others.
78
- //
79
- // The sibling is `<guideprefix>base-guide`, because that is the only
80
- // base-guide this build writes. Matching any `*base-guide.aontu` instead
81
- // would rewrite a user's own `@"shared-base-guide.aontu"` — a file nothing
82
- // renamed — into a path that does not exist, breaking the guide while
83
- // deleting the original. A plain split/join keeps the prefix a literal, so
84
- // a prefix containing regex metacharacters cannot widen the match either.
85
57
  const legacysrc = String(fs.readFileSync(legacyguide, 'utf8'))
86
58
  const migrated = legacysrc
87
59
  .replace(/@"@voxgig\/apidef\/model\/guide\.aontu"/g,
@@ -95,24 +67,6 @@ function migrateLegacyGuide(fs: any, folder: string, guideprefix: string): boole
95
67
  return true
96
68
  }
97
69
 
98
- // Give the guide's sibling include a `./`, in place, once.
99
- //
100
- // `guide.aon` is PROJECT-OWNED — the scaffold writes it at init and never
101
- // again, because it is two includes a user rarely edits. So the scaffold
102
- // template gaining a `./` reaches new projects only, and every existing one
103
- // keeps `@"base-guide.aon"`, which aontu 0.65 refuses: a bare single-segment
104
- // include now names a PACKAGE (ADR-039).
105
- //
106
- // A file the toolchain writes and the toolchain then refuses to read has to
107
- // be migrated by the toolchain. `migrateLegacyGuide` above does exactly this
108
- // for the `.aontu` -> `.aon` rename; this is the same move for the same file.
109
- //
110
- // THE SIBLING ONLY, matched as a whole include with the prefix absent. The
111
- // package include beside it (`@"@voxgig/apidef/model/guide.aon"`) is a real
112
- // package reference and must stay bare, and a user's own `@"./something"` is
113
- // already correct. Anything else in the file is the user's.
114
- //
115
- // Returns true when a migration actually happened.
116
70
  function migrateGuideIncludePrefix(
117
71
  fs: any, guidepath: string, guideprefix: string
118
72
  ): boolean {
@@ -136,12 +90,6 @@ function migrateGuideIncludePrefix(
136
90
 
137
91
 
138
92
 
139
- // The first unresolved merge-conflict marker in a source, or null.
140
- //
141
- // Anchored at line start and requiring exactly the conventional seven
142
- // characters: a guide legitimately contains `>>>>>>> GENERATED` inside the
143
- // jostraca provenance comments it writes about itself, and `====` shows up in
144
- // prose. Only a real marker at column zero counts.
145
93
  function findConflict(src: string): { line: number, text: string } | null {
146
94
  const lines = String(src || '').split('\n')
147
95
 
@@ -202,27 +150,6 @@ async function buildGuide(ctx: ApiDefContext): Promise<any> {
202
150
 
203
151
  handleErrors(ctx, errs)
204
152
 
205
- // A MERGE CONFLICT IN A GUIDE IS SAID OUT LOUD, HERE.
206
- //
207
- // The guide is 3-way merged: apidef regenerates the base guide from the
208
- // spec and merges it over what the project already had. Change the spec
209
- // enough — swap a 5-path definition for the API's whole 722-path one — and
210
- // an edit the project made can no longer be reconciled, so the merge
211
- // writes ordinary `<<<<<<<` / `=======` / `>>>>>>>` markers into the file.
212
- //
213
- // Nothing then read the file until aontu did, and aontu reports what it
214
- // sees: `unexpected character(s): <<<<<<<`, thousands of lines into a
215
- // generated file, with no hint that this is a merge conflict or which edit
216
- // caused it. That cost a long detour — the failure was read as apidef
217
- // hanging, and the real cause (one conflicted rename) sat two lines away
218
- // from a marker nobody had looked for.
219
- //
220
- // The guide is a file apidef itself writes, so apidef is the right place to
221
- // recognise its own merge output before handing it on.
222
- // BOTH FILES, and the base guide is the one that usually has it: `guide.aon`
223
- // is two @-includes a user rarely edits, while `base-guide.aon` is what
224
- // apidef regenerates and merges. Checking only the top-level file found
225
- // nothing and left aontu to report the marker.
226
153
  const basepath = Path.join(folder, 'guide', guideprefix + 'base-guide.aon')
227
154
  for (const checkpath of [guidepath, basepath]) {
228
155
  let checksrc = ''
@@ -266,35 +193,10 @@ async function buildGuide(ctx: ApiDefContext): Promise<any> {
266
193
  errs,
267
194
  }
268
195
 
269
- // Only forward a *genuinely injected* fs.
270
- //
271
- // aontu resolves `@`-includes through @tabnas/multisource, which does:
272
- // const P = null != ctx.meta?.fs ? Path.posix : Path
273
- // i.e. it switches to POSIX path semantics whenever an fs is present, on
274
- // the assumption that an injected fs is memfs keyed by POSIX paths.
275
- //
276
- // apidef defaults ctx.fs to the real node:fs (`opts.fs || Fs`), so
277
- // forwarding it unconditionally made multisource parse *Windows* paths
278
- // with Path.posix. 'D:\...\guide\x-guide.aontu' contains no '/', so the
279
- // include base resolved to '' and sibling includes were looked up against
280
- // the cwd instead of the guide folder — every build failed on Windows
281
- // with `source not found: <prefix>base-guide.aontu`. Linux and macOS were
282
- // unaffected because there Path and Path.posix are the same module.
283
- //
284
- // Callers that supply a real memfs (e.g. apidef-validate) still get it,
285
- // and still get the POSIX semantics they need.
286
- //
287
- // Uses the explicit ctx.fsInjected flag rather than `Fs !== ctx.fs`:
288
- // esModuleInterop compiles `import * as Fs` to __importStar(), which
289
- // builds a fresh wrapper per module, so identity comparison across
290
- // modules is always false.
291
196
  if (ctx.fsInjected) {
292
197
  opts.fs = ctx.fs
293
198
  }
294
199
 
295
- // Record what was actually handed to aontu, not what we intended to hand
296
- // it, so the regression test fails if this block is ever changed back to
297
- // an unconditional assignment.
298
200
  ctx.work.guideAontuFs = undefined !== opts.fs
299
201
 
300
202
  const guideModel = aontu.generate(src, opts)
@@ -358,7 +260,6 @@ async function buildBaseGuide(ctx: ApiDefContext) {
358
260
 
359
261
  const metrics = baseguide.metrics
360
262
 
361
- // TODO: these should influence the IS_ENTCMP_METHOD_RATE etc. values
362
263
  const epr =
363
264
  0 < metrics.count.path ? (metrics.count.entity / metrics.count.path).toFixed(3) : -1
364
265
  const emr =
@@ -404,8 +305,10 @@ async function buildBaseGuide(ctx: ApiDefContext) {
404
305
  path: GuidePath
405
306
  ) => {
406
307
  {
407
- debugpath(entrykey, null, 'BASE-GUIDE', entname, entrykey,
408
- formatJSONIC(path, { hsepd: 0, $: true, color: true }))
308
+ if (debugpathOn()) {
309
+ debugpath(entrykey, null, 'BASE-GUIDE', entname, entrykey,
310
+ formatJSONIC(path, { hsepd: 0, $: true, color: true }))
311
+ }
409
312
 
410
313
  guideBlocks.push(` ${branch}: ${qs(entrykey)}: {` +
411
314
  sw(0 < path.why_path.length ?
@@ -435,21 +338,10 @@ async function buildBaseGuide(ctx: ApiDefContext) {
435
338
  if (null != op.optype) {
436
339
  guideBlocks.push(` op: ${opname}: optype: *${op.optype}`)
437
340
  }
438
- // Each transform is emitted only when set, and each on its own terms.
439
- // (An earlier req-GUARDED block pushed a second res line built from
440
- // op.transform.res — emitting `transform: res: *undefined` whenever a
441
- // request was wrapped but the response was not. Hence the separate
442
- // null checks below rather than one shared guard.)
443
341
  if (null != op.transform.res) {
444
342
  guideBlocks.push(
445
343
  ` op: ${opname}: transform: res: *${qt(op.transform.res)}|top`)
446
344
  }
447
- // The req transform is a MAP of body property -> source expression
448
- // (see closedBodyTransform), so it takes one line per property. THE
449
- // SERIALISED GUIDE IS WHAT THE TRANSFORM STEP READS: a transform not
450
- // written here never reaches the model, which is why restricting a
451
- // closed request body had no effect until this existed. Only the map
452
- // form is representable as aontu paths; a scalar req is left alone.
453
345
  const reqmap: any = op.transform.req
454
346
  if (null != reqmap && 'object' === typeof reqmap) {
455
347
  items(reqmap).map(([bodykey, source]: [string, any]) => {
@@ -470,16 +362,6 @@ async function buildBaseGuide(ctx: ApiDefContext) {
470
362
  guideBlocks.push(`
471
363
  entity: ${entname}: {`)
472
364
 
473
- // An entity the heuristic deactivated (today: an access-token exchange,
474
- // which is credential plumbing rather than a resource) is EMITTED, not
475
- // dropped, so the classification is visible and reversible in guide.aon
476
- // — the only correction surface (ADR-002).
477
- //
478
- // `*false` — a DEFAULT, not a concrete value. aontu conflicts two
479
- // concrete values rather than letting one win, so a concrete `active:
480
- // false` here would make a user's `guide: entity: <name>: active: true`
481
- // in guide.aon fail to unify instead of overriding it. That is the same
482
- // trap the `method: *POST` entries above avoid.
483
365
  if (false === entity.active) {
484
366
  const why = (entity as any).why_inactive
485
367
  guideBlocks.push(
@@ -530,10 +412,6 @@ async function buildBaseGuide(ctx: ApiDefContext) {
530
412
 
531
413
 
532
414
 
533
- // GraphQL coverage guard: every Query/Mutation root field must either be
534
- // assigned to an entity op or be deliberately excluded by the classifier
535
- // (machinery types, scalar returns). Mirrors the REST PATH MISMATCH check —
536
- // silence about an unclassified field is how an API silently loses surface.
537
415
  function validateGraphqlBaseGuide(ctx: ApiDefContext, baseguide: any) {
538
416
  const covered: Record<string, boolean> = {}
539
417