@voxgig/apidef 2.3.0 → 2.4.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 (45) hide show
  1. package/dist/apidef.d.ts +2 -6
  2. package/dist/apidef.js +44 -11
  3. package/dist/apidef.js.map +1 -1
  4. package/dist/builder/flow/flowHeuristic01.js +1 -1
  5. package/dist/builder/flow/flowHeuristic01.js.map +1 -1
  6. package/dist/guide/guide.d.ts +2 -0
  7. package/dist/guide/guide.js +107 -0
  8. package/dist/guide/guide.js.map +1 -0
  9. package/dist/guide/heuristic01.js +149 -218
  10. package/dist/guide/heuristic01.js.map +1 -1
  11. package/dist/resolver.js +2 -2
  12. package/dist/resolver.js.map +1 -1
  13. package/dist/transform/entity.js +1 -2
  14. package/dist/transform/entity.js.map +1 -1
  15. package/dist/transform/field.js +1 -2
  16. package/dist/transform/field.js.map +1 -1
  17. package/dist/transform/operation.js +1 -2
  18. package/dist/transform/operation.js.map +1 -1
  19. package/dist/transform/top.js +0 -1
  20. package/dist/transform/top.js.map +1 -1
  21. package/dist/tsconfig.tsbuildinfo +1 -1
  22. package/dist/types.d.ts +297 -2
  23. package/dist/types.js +12 -1
  24. package/dist/types.js.map +1 -1
  25. package/dist/utility.d.ts +3 -1
  26. package/dist/utility.js +155 -0
  27. package/dist/utility.js.map +1 -1
  28. package/model/apidef.jsonic +1 -50
  29. package/model/guide.jsonic +53 -0
  30. package/package.json +6 -5
  31. package/src/apidef.ts +61 -15
  32. package/src/builder/flow/flowHeuristic01.ts +1 -1
  33. package/src/guide/guide.ts +274 -0
  34. package/src/guide/heuristic01.ts +173 -232
  35. package/src/{guide.ts → guide.ts.off} +8 -5
  36. package/src/resolver.ts +2 -2
  37. package/src/transform/entity.ts +1 -6
  38. package/src/transform/field.ts +1 -6
  39. package/src/transform/operation.ts +1 -2
  40. package/src/transform/top.ts +0 -6
  41. package/src/types.ts +31 -0
  42. package/src/utility.ts +184 -37
  43. package/dist/guide.d.ts +0 -2
  44. package/dist/guide.js +0 -95
  45. package/dist/guide.js.map +0 -1
package/src/utility.ts CHANGED
@@ -1,6 +1,8 @@
1
1
 
2
2
  import Path from 'node:path'
3
3
 
4
+ import { slice, merge, inject, clone, isnode, walk, transform, select } from '@voxgig/struct'
5
+
4
6
 
5
7
  import type {
6
8
  FsUtil,
@@ -27,6 +29,9 @@ function getdlog(
27
29
  return dlog
28
30
  }
29
31
 
32
+ // Log non-fatal wierdness.
33
+ const dlog = getdlog('apidef', __filename)
34
+
30
35
 
31
36
  function loadFile(path: string, what: string, fs: FsUtil, log: Log) {
32
37
  try {
@@ -123,7 +128,7 @@ function depluralize(word: string): string {
123
128
  if (word.endsWith('nses')) {
124
129
  return word.slice(0, -1)
125
130
  }
126
-
131
+
127
132
  // -ses, -xes, -zes, -shes, -ches -> remove -es (boxes -> box)
128
133
  if (word.endsWith('ses') || word.endsWith('xes') || word.endsWith('zes') ||
129
134
  word.endsWith('shes') || word.endsWith('ches')) {
@@ -140,55 +145,197 @@ function depluralize(word: string): string {
140
145
  }
141
146
 
142
147
 
143
- /*
144
- function writeChanged(
145
- point: string, path: string, content: string,
146
- fs: FsUtil, log: Log,
147
- flags?: { update?: boolean }
148
- ) {
149
- let exists = false
150
- let changed = false
148
+ function find(obj: any, qkey: string): any[] {
149
+ let vals: any[] = []
150
+ walk(obj, (key: any, val: any, _p: any, t: string[]) => {
151
+ if (qkey === key) {
152
+ vals.push({ key, val, path: t })
153
+ }
154
+ return val
155
+ })
156
+ return vals
157
+ }
151
158
 
152
- flags = flags || {}
153
- flags.update = null == flags.update ? true : !!flags.update
154
159
 
155
- let action = ''
156
- try {
157
- let existingContent: string = ''
158
- path = Path.normalize(path)
160
+ function capture(data: any, shape: any): Record<string, any> {
161
+ let meta = { capture: {} }
162
+ let errs: any[] = []
163
+
164
+ transform(data, shape, {
165
+ extra: {
166
+ $CAPTURE,
167
+ $APPEND,
168
+ $ANY,
169
+ $SELECT,
170
+ $LOWER,
171
+ },
172
+ errs,
173
+ meta
174
+ })
175
+
176
+ if (0 < errs.length) {
177
+ console.log('ERRS', errs)
178
+ dlog(errs)
179
+ }
180
+ return meta.capture
181
+ }
159
182
 
160
- exists = fs.existsSync(path)
161
183
 
162
- if (exists) {
163
- action = 'read'
164
- existingContent = fs.readFileSync(path, 'utf8')
184
+ function $CAPTURE(inj: any) {
185
+ // Set prop foo with value at x: { x: { '`$CAPTURE`': 'foo' } }
186
+ if ('key:pre' === inj.mode) {
187
+ const { val, prior } = inj
188
+ const { dparent, key } = prior
189
+ const dval = dparent?.[key]
190
+ if (undefined !== dval) {
191
+ inj.meta.capture[val] = dval
165
192
  }
193
+ }
166
194
 
167
- changed = existingContent !== content
195
+ // Use key x as prop name: { x: '`$CAPTURE`': }
196
+ else if ('val' === inj.mode) {
197
+ const { key, dparent } = inj
198
+ const dval = dparent?.[key]
199
+ if (undefined !== dval) {
200
+ inj.meta.capture[key] = dval
201
+ }
202
+ }
203
+ }
168
204
 
169
- action = flags.update ? 'write' : 'skip'
170
205
 
171
- log.info({
172
- point: 'write-' + point,
173
- note: (changed ? '' : 'not-') + 'changed ' + path,
174
- write: 'file', skip: !changed, exists, changed,
175
- contentLength: content.length, file: path
206
+ function $APPEND(inj: any, val: any, ref: any, store: any) {
207
+ // Set prop foo with value at x: { x: { '`$CAPTURE`': 'foo' } }
208
+ if ('key:pre' === inj.mode) {
209
+ const { val, prior } = inj
210
+ const { dparent, key } = prior
211
+ const dval = dparent?.[key]
212
+ if (undefined !== dval) {
213
+ inj.meta.capture[val] = (inj.meta.capture[val] || [])
214
+ inj.meta.capture[val].push(dval)
215
+ }
216
+ }
217
+
218
+
219
+ else if ('val' === inj.mode) {
220
+ inj.keyI = inj.keys.length
221
+
222
+ const [_, prop, xform] = inj.parent
223
+ const { key, dparent } = inj.prior
224
+ const dval = dparent?.[key]
225
+
226
+ const vstore = { ...store }
227
+ vstore.$TOP = { [key]: dval }
228
+
229
+ // const ptval = transform({ [key]: dval }, { [key]: xform }, {
230
+ const ptval = inject({ [key]: xform }, vstore, {
231
+ meta: { ...inj.meta },
232
+ errs: inj.errs,
176
233
  })
177
234
 
178
- if (!exists || (changed && flags.update)) {
179
- fs.writeFileSync(path, content)
235
+ const tval = ptval[key]
236
+
237
+ if (undefined !== tval) {
238
+ inj.meta.capture[prop] = (inj.meta.capture[prop] || [])
239
+ inj.meta.capture[prop].push(tval)
180
240
  }
181
241
  }
182
- catch (err: any) {
183
- log.error({
184
- fail: action, point, file: path, exists, changed,
185
- contentLength: content.length, err
242
+ }
243
+
244
+
245
+
246
+ function $ANY(inj: any, _val: any, _ref: any, store: any) {
247
+ if ('key:pre' === inj.mode) {
248
+ const { prior } = inj
249
+ const child = inj.parent[inj.key]
250
+ const { dparent, key } = prior
251
+ const dval = dparent?.[key]
252
+ if (isnode(dval)) {
253
+ for (let n of Object.entries(dval)) {
254
+ let vstore = { ...store }
255
+ vstore.$TOP = { [n[0]]: n[1] }
256
+ inject(clone({ [n[0]]: child }), vstore, {
257
+ meta: inj.meta,
258
+ errs: inj.errs,
259
+ })
260
+ }
261
+ }
262
+ }
263
+ }
264
+
265
+
266
+ function $SELECT(inj: any, _val: any, _ref: any, store: any) {
267
+ if ('val' === inj.mode) {
268
+ inj.keyI = inj.keys.length
269
+
270
+ let [_, selector, descendor] = inj.parent
271
+
272
+ const dparents =
273
+ Object.entries(inj.dparent || {})
274
+ .filter(n => isnode(n[1]))
275
+ .reduce((a, n) => (a[n[0]] = n[1], a), ({} as any))
276
+
277
+ // console.log('SELECT-FROM', dparents)
278
+
279
+ if (selector instanceof RegExp) {
280
+ selector = {
281
+ '$KEY': { '`$LIKE`': selector.toString() }
282
+ }
283
+ }
284
+
285
+ // TODO: select should be safe for scalars
286
+ const children = select(dparents, selector)
287
+
288
+ if (0 < children.length) {
289
+ for (let child of children) {
290
+ let vstore = { ...store }
291
+ vstore.$TOP = { [child.$KEY]: child }
292
+
293
+ inject(clone({ [child.$KEY]: descendor }), vstore, {
294
+ meta: merge([
295
+ inj.meta,
296
+
297
+ // TODO: need this hack as struct does not provide a way to get grandparent keys
298
+ // also, these capture actions are not preserving the path!
299
+ { select: { key: { [slice(inj.path, 1, -1).join('+')]: child.$KEY } } }
300
+ ]),
301
+ errs: inj.errs,
302
+ })
303
+ }
304
+ }
305
+ }
306
+ }
307
+
308
+
309
+ function $LOWER(inj: any, val: any, ref: any, store: any) {
310
+ if ('key:pre' === inj.mode) {
311
+ const dval = inj.parent[inj.key]
312
+
313
+ // TODO: handle paths more generally! use inj.prior?
314
+ // TODO: mkae this into a utility method on inj?
315
+ const dkey = inj.prior.key
316
+ const gkey = inj.prior.prior.key
317
+
318
+ const vstore = { ...store }
319
+ vstore.$TOP = { [gkey]: { [dkey]: inj.dparent?.[dkey] } }
320
+
321
+ const vspec = { [gkey]: { [dkey]: dval } }
322
+
323
+ const ptval = inject(vspec, vstore, {
324
+ meta: { ...inj.meta },
325
+ errs: inj.errs,
186
326
  })
187
- err.__logged__ = true
188
- throw err
327
+
328
+ let tval = ptval[gkey][dkey]
329
+
330
+ if ('string' === typeof tval) {
331
+ tval = tval.toLowerCase()
332
+ }
333
+
334
+ inj.setval(tval, 2)
189
335
  }
190
336
  }
191
- */
337
+
338
+
192
339
 
193
340
 
194
341
  export {
@@ -196,6 +343,6 @@ export {
196
343
  loadFile,
197
344
  formatJsonSrc,
198
345
  depluralize,
199
-
200
- // writeChanged,
346
+ find,
347
+ capture,
201
348
  }
package/dist/guide.d.ts DELETED
@@ -1,2 +0,0 @@
1
- declare function resolveGuide(ctx: any): Promise<() => void>;
2
- export { resolveGuide };
package/dist/guide.js DELETED
@@ -1,95 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.resolveGuide = resolveGuide;
7
- const node_path_1 = __importDefault(require("node:path"));
8
- const jostraca_1 = require("jostraca");
9
- const struct_1 = require("@voxgig/struct");
10
- const heuristic01_1 = require("./guide/heuristic01");
11
- const utility_1 = require("./utility");
12
- // Log non-fatal wierdness.
13
- const dlog = (0, utility_1.getdlog)('apidef', __filename);
14
- async function resolveGuide(ctx) {
15
- let baseguide = {};
16
- let override = ctx.model.main.api.guide;
17
- if ('heuristic01' === ctx.opts.strategy) {
18
- baseguide = await (0, heuristic01_1.heuristic01)(ctx);
19
- }
20
- else {
21
- throw new Error('Unknown guide strategy: ' + ctx.opts.strategy);
22
- }
23
- // Override generated base guide with custom hints
24
- let guide = (0, struct_1.merge)([{}, baseguide, override]);
25
- // TODO: this is a hack!!!
26
- // Instead, update @voxgig/model, so that builders can request a reload of the entire
27
- // model. This allows builders to modify the model for later buidlers
28
- // during a single generation pass.
29
- guide = cleanGuide(guide);
30
- // TODO: FIX: sdk.jsonic should have final version of guide
31
- if (ctx.model.main?.api) {
32
- ctx.model.main.api.guide = guide;
33
- }
34
- else {
35
- dlog('missing', 'ctx.model.main.api');
36
- }
37
- const guideFile = node_path_1.default.join(ctx.opts.folder, (null == ctx.opts.outprefix ? '' : ctx.opts.outprefix) + 'base-guide.jsonic');
38
- const guideBlocks = [
39
- '# Guide',
40
- '',
41
- 'main: api: guide: { ',
42
- ];
43
- guideBlocks.push(...(0, jostraca_1.each)(baseguide.entity, (entity, entityname) => {
44
- guideBlocks.push(`
45
- entity: ${entityname}: {` +
46
- (0 < entity.why_name.length ? ' # name:' + entity.why_name.join(';') : ''));
47
- (0, jostraca_1.each)(entity.path, (path, pathname) => {
48
- guideBlocks.push(` path: '${pathname}': op: {` +
49
- (0 < path.why_ent.length ? ' # ent:' + path.why_ent.join(';') : ''));
50
- (0, jostraca_1.each)(path.op, (op, opname) => {
51
- guideBlocks.push(` '${opname}': method: ${op.method}` +
52
- (0 < op.why_op.length ? ' # ' + op.why_op : ''));
53
- if (op.transform?.reqform) {
54
- guideBlocks.push(` '${opname}': transform: reqform: ${JSON.stringify(op.transform.reqform)}`);
55
- }
56
- });
57
- guideBlocks.push(` }`);
58
- });
59
- guideBlocks.push(`}`);
60
- }));
61
- guideBlocks.push('}');
62
- const guideSrc = guideBlocks.join('\n');
63
- return () => {
64
- // Save base guide for reference
65
- (0, jostraca_1.File)({ name: '../def/' + node_path_1.default.basename(guideFile) }, () => (0, jostraca_1.Content)(guideSrc));
66
- };
67
- }
68
- function cleanGuide(guide) {
69
- const clean = {
70
- control: guide.control,
71
- entity: {}
72
- };
73
- const exclude_entity = guide.exclude?.entity?.split(',') || [];
74
- const include_entity = guide.include?.entity?.split(',') || [];
75
- (0, jostraca_1.each)(guide.entity, (entity, name) => {
76
- if (exclude_entity.includes(name)) {
77
- return;
78
- }
79
- if (exclude_entity.includes('*')) {
80
- if (!include_entity.includes(name)) {
81
- return;
82
- }
83
- }
84
- let ent = clean.entity[name] = clean.entity[name] = {
85
- name,
86
- why_name: entity.why_name || [],
87
- path: {}
88
- };
89
- (0, jostraca_1.each)(entity.path, (path, pathname) => {
90
- ent.path[pathname] = path;
91
- });
92
- });
93
- return clean;
94
- }
95
- //# sourceMappingURL=guide.js.map
package/dist/guide.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"guide.js","sourceRoot":"","sources":["../src/guide.ts"],"names":[],"mappings":"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"}