@voxgig/apidef 2.4.1 → 3.0.2

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 (96) hide show
  1. package/dist/apidef.d.ts +5 -1
  2. package/dist/apidef.js +197 -112
  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 +29 -4
  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 +89 -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 +1120 -234
  28. package/dist/guide/heuristic01.js.map +1 -1
  29. package/dist/model.d.ts +55 -0
  30. package/dist/model.js +4 -0
  31. package/dist/model.js.map +1 -0
  32. package/dist/parse.d.ts +1 -2
  33. package/dist/parse.js +8 -47
  34. package/dist/parse.js.map +1 -1
  35. package/dist/transform/args.d.ts +3 -0
  36. package/dist/transform/args.js +58 -0
  37. package/dist/transform/args.js.map +1 -0
  38. package/dist/transform/clean.js +27 -3
  39. package/dist/transform/clean.js.map +1 -1
  40. package/dist/transform/entity.d.ts +11 -3
  41. package/dist/transform/entity.js +57 -41
  42. package/dist/transform/entity.js.map +1 -1
  43. package/dist/transform/field.d.ts +3 -3
  44. package/dist/transform/field.js +90 -65
  45. package/dist/transform/field.js.map +1 -1
  46. package/dist/transform/operation.d.ts +1 -1
  47. package/dist/transform/operation.js +94 -296
  48. package/dist/transform/operation.js.map +1 -1
  49. package/dist/transform/select.d.ts +3 -0
  50. package/dist/transform/select.js +44 -0
  51. package/dist/transform/select.js.map +1 -0
  52. package/dist/transform/top.d.ts +9 -0
  53. package/dist/transform/top.js +11 -2
  54. package/dist/transform/top.js.map +1 -1
  55. package/dist/transform.js +4 -0
  56. package/dist/transform.js.map +1 -1
  57. package/dist/tsconfig.tsbuildinfo +1 -1
  58. package/dist/types.d.ts +112 -19
  59. package/dist/types.js +4 -2
  60. package/dist/types.js.map +1 -1
  61. package/dist/utility.d.ts +30 -2
  62. package/dist/utility.js +381 -6
  63. package/dist/utility.js.map +1 -1
  64. package/model/apidef.jsonic +75 -1
  65. package/model/guide.jsonic +14 -44
  66. package/package.json +17 -14
  67. package/src/apidef.ts +264 -121
  68. package/src/builder/entity/{apiEntity.ts → entity.ts} +18 -11
  69. package/src/builder/entity/info.ts +53 -0
  70. package/src/builder/entity.ts +9 -35
  71. package/src/builder/flow/flowHeuristic01.ts +46 -12
  72. package/src/builder/flow.ts +39 -5
  73. package/src/def.ts +91 -0
  74. package/src/desc.ts +143 -0
  75. package/src/guide/guide.ts +207 -134
  76. package/src/guide/heuristic01.ts +1651 -272
  77. package/src/model.ts +98 -0
  78. package/src/parse.ts +5 -61
  79. package/src/schematron.ts.off +317 -0
  80. package/src/transform/args.ts +102 -0
  81. package/src/transform/clean.ts +43 -8
  82. package/src/transform/entity.ts +100 -51
  83. package/src/transform/field.ts +150 -71
  84. package/src/transform/operation.ts +118 -414
  85. package/src/transform/select.ts +90 -0
  86. package/src/transform/top.ts +76 -3
  87. package/src/transform.ts +4 -0
  88. package/src/types.ts +185 -5
  89. package/src/utility.ts +481 -9
  90. package/dist/builder/entity/apiEntity.d.ts +0 -3
  91. package/dist/builder/entity/apiEntity.js.map +0 -1
  92. package/dist/builder/entity/def.d.ts +0 -3
  93. package/dist/builder/entity/def.js +0 -19
  94. package/dist/builder/entity/def.js.map +0 -1
  95. package/src/builder/entity/def.ts +0 -44
  96. package/src/guide.ts.off +0 -136
package/package.json CHANGED
@@ -1,14 +1,16 @@
1
1
  {
2
2
  "name": "@voxgig/apidef",
3
- "version": "2.4.1",
3
+ "version": "3.0.2",
4
4
  "main": "dist/apidef.js",
5
5
  "type": "commonjs",
6
6
  "types": "dist/apidef.d.ts",
7
7
  "description": "Voxgig SDK Generator.",
8
8
  "homepage": "https://github.com/voxgig/voxgig-apidef",
9
9
  "keywords": [
10
- "voxgig-apidef",
11
- "voxgig-apidef"
10
+ "voxgig",
11
+ "apidef",
12
+ "api",
13
+ "sdk"
12
14
  ],
13
15
  "author": "Richard Rodger (http://richardrodger.com)",
14
16
  "repository": {
@@ -20,7 +22,7 @@
20
22
  },
21
23
  "scripts": {
22
24
  "test": "node --enable-source-maps --test \"dist-test/**/*.test.js\"",
23
- "test-some": "node --enable-source-maps --test-name-pattern=\"$npm_config_pattern\" --test \"dist-test/**/*.test.js\"",
25
+ "test-some": "node --enable-source-maps --test-name-pattern=\"$TEST_PATTERN\" --test \"dist-test/**/*.test.js\"",
24
26
  "watch": "tsc --build src test -w",
25
27
  "build": "tsc --build src test",
26
28
  "clean": "rm -rf dist dist-test node_modules yarn.lock package-lock.json",
@@ -40,24 +42,25 @@
40
42
  "devDependencies": {
41
43
  "@hapi/code": "^9.0.3",
42
44
  "@types/js-yaml": "^4.0.9",
43
- "@types/node": "24.3.0",
45
+ "@types/node": "25.0.2",
44
46
  "json-schema-to-ts": "^3.1.1",
45
- "typescript": "^5.9.2"
47
+ "typescript": "^5.9.3"
46
48
  },
47
49
  "peerDependencies": {
48
- "aontu": ">=0.28",
49
- "memfs": ">=4.36.3"
50
+ "aontu": ">=0.33.2",
51
+ "memfs": ">=4.51.1"
50
52
  },
51
53
  "dependencies": {
52
54
  "@redocly/openapi-core": "1.34.5",
53
55
  "@voxgig/struct": "^0.0.9",
54
- "@voxgig/util": "^0.2.0",
55
- "chokidar": "^4.0.3",
56
+ "@voxgig/util": "^0.2.1",
57
+ "chokidar": "^5.0.0",
58
+ "decircular": "^1.0.0",
56
59
  "diff": "^8.0.2",
57
60
  "gubu": "^9.0.0",
58
- "jostraca": "^0.24.1",
59
- "pino": "^9.9.0",
60
- "pino-pretty": "^13.1.1",
61
- "sonic-boom": "^4.2.0"
61
+ "jostraca": "^0.25.1",
62
+ "ordu": "^4.1.1",
63
+ "pino": "^10.1.0",
64
+ "pino-pretty": "^13.1.3"
62
65
  }
63
66
  }
package/src/apidef.ts CHANGED
@@ -1,13 +1,18 @@
1
1
  /* Copyright (c) 2024-2025 Voxgig, MIT License */
2
2
 
3
+
3
4
  import * as Fs from 'node:fs'
4
5
  import Path from 'node:path'
5
- import { inspect } from 'node:util'
6
6
 
7
- import { Jostraca, Project, names } from 'jostraca'
7
+
8
+ import {
9
+ Jostraca, JostracaResult, Project, names
10
+ } from 'jostraca'
8
11
 
9
12
  import { prettyPino } from '@voxgig/util'
10
13
 
14
+ import decircular from 'decircular'
15
+
11
16
 
12
17
  import type {
13
18
  ApiDefOptions,
@@ -18,10 +23,14 @@ import type {
18
23
  ApiModel,
19
24
  } from './types'
20
25
 
26
+
21
27
  import {
28
+ KIT,
29
+
22
30
  OpenModelShape,
23
31
  OpenBuildShape,
24
32
  OpenControlShape,
33
+ ApiDefContext,
25
34
  } from './types'
26
35
 
27
36
 
@@ -32,7 +41,6 @@ import {
32
41
 
33
42
  import {
34
43
  parse,
35
- rewrite,
36
44
  } from './parse'
37
45
 
38
46
 
@@ -49,11 +57,17 @@ import {
49
57
  import {
50
58
  loadFile,
51
59
  getdlog,
60
+ makeWarner,
61
+ formatJSONIC,
62
+ writeFileSyncWarn,
52
63
  } from './utility'
53
64
 
65
+
54
66
  import { topTransform } from './transform/top'
55
67
  import { entityTransform } from './transform/entity'
56
68
  import { operationTransform } from './transform/operation'
69
+ import { argsTransform } from './transform/args'
70
+ import { selectTransform } from './transform/select'
57
71
  import { fieldTransform } from './transform/field'
58
72
  import { cleanTransform } from './transform/clean'
59
73
 
@@ -66,168 +80,263 @@ const dlog = getdlog('apidef', __filename)
66
80
 
67
81
  function ApiDef(opts: ApiDefOptions) {
68
82
 
69
-
70
83
  // TODO: gubu opts!
71
84
  const fs = opts.fs || Fs
72
85
  const pino = prettyPino('apidef', opts)
73
86
  const log = pino.child({ cmp: 'apidef' })
87
+ const warn = makeWarner({ point: 'warning', log })
74
88
 
75
89
  opts.strategy = opts.strategy || 'heuristic01'
76
90
 
77
-
78
91
  async function generate(spec: any): Promise<ApiDefResult> {
79
92
  const start = Date.now()
80
93
  const steps: string[] = []
81
- // dlog('start')
82
94
 
83
- const ctrl: Control = OpenControlShape(spec.ctrl || {})
84
- const model: Model = OpenModelShape(spec.model || {})
85
- const build: Build = OpenBuildShape(spec.build || {})
95
+ let ctx: ApiDefContext | undefined = undefined
96
+ let ctrl: Control | undefined = undefined
97
+ let jres: JostracaResult | undefined = undefined
86
98
 
87
- // Step: parse (API spec).
88
- if (!ctrl.step.parse) {
89
- return { ok: false, steps, start, end: Date.now(), ctrl }
90
- }
99
+ try {
100
+ ctrl = OpenControlShape(spec.ctrl || {}) as Control
91
101
 
92
- names(model, model.name)
102
+ const model: Model = OpenModelShape(spec.model || {})
103
+ const build: Build = OpenBuildShape(spec.build || {})
93
104
 
94
- const apimodel: ApiModel = {
95
- main: {
96
- api: {
97
- entity: {}
105
+ // Step: parse (API spec).
106
+ if (!ctrl.step.parse) {
107
+ return { ok: true, steps, start, end: Date.now(), ctrl }
108
+ }
109
+
110
+ names(model, model.name)
111
+
112
+ const apimodel: ApiModel = {
113
+ main: {
114
+ api: {},
115
+ [KIT]: {
116
+ info: {},
117
+ entity: {},
118
+ flow: {},
119
+ },
120
+ def: {},
98
121
  },
99
- def: {},
100
- },
101
- }
122
+ }
102
123
 
103
- const buildspec = build.spec
104
-
105
- let defpath = model.def
106
-
107
- // TOOD: defpath should be independently defined
108
- defpath = Path.join(buildspec.base, '..', 'def', defpath)
109
-
110
- log.info({
111
- point: 'generate-start',
112
- note: defpath.replace(process.cwd(), '.'), defpath, start
113
- })
114
-
115
- // TODO: Validate spec
116
- const ctx = {
117
- fs,
118
- log,
119
- spec,
120
- opts,
121
- util: { fixName },
122
- defpath: Path.dirname(defpath),
123
- model,
124
- apimodel,
125
- guide: {},
126
- def: undefined,
127
- note: {}
128
- }
124
+ const buildspec = build.spec
129
125
 
130
- const defsrc = loadFile(defpath, 'def', fs, log)
126
+ let defpath = model.def
131
127
 
132
- let def = await parse('OpenAPI', defsrc, { file: defpath })
128
+ // TOOD: defpath should be independently defined
129
+ defpath = Path.join(buildspec.base, '..', 'def', defpath)
133
130
 
134
- def = rewrite(def)
131
+ log.info({
132
+ point: 'generate-start',
133
+ note: defpath.replace(process.cwd(), '.'),
134
+ defpath,
135
+ start
136
+ })
135
137
 
136
- fs.writeFileSync(defpath + '.full.json', JSON.stringify(def, null, 2))
138
+ // TODO: Validate spec
139
+ ctx = {
140
+ fs,
141
+ log,
142
+ spec,
143
+ opts,
144
+ util: { fixName },
145
+ defpath: Path.dirname(defpath),
146
+ model,
147
+ apimodel,
148
+ guide: {},
149
+ def: undefined,
150
+ note: {},
151
+ warn,
152
+
153
+ // TODO: remove (moved to guide)
154
+ metrics: {
155
+ count: {
156
+ path: 0,
157
+ method: 0,
158
+ origcmprefs: {},
159
+ cmp: 0,
160
+ tag: 0,
161
+ entity: 0,
162
+ },
163
+ found: {
164
+ cmp: {},
165
+ tag: {}
166
+ }
167
+ },
137
168
 
138
- ctx.def = def
169
+ work: {}
170
+ }
139
171
 
140
- steps.push('parse')
172
+ const defsrc = loadFile(defpath, 'def', fs, log)
141
173
 
174
+ const def = await parse('OpenAPI', defsrc, { file: defpath })
175
+ const defkeys = Object.keys(def)
142
176
 
143
- // Step: guide (derive).
144
- if (!ctrl.step.guide) {
145
- return { ok: false, steps, start, end: Date.now(), ctrl }
146
- }
177
+ log.info({
178
+ point: 'root-keys',
179
+ defpath,
180
+ note: defkeys.join(', ')
181
+ })
147
182
 
148
- const guideModel = await buildGuide(ctx)
149
- ctx.guide = guideModel.guide
183
+ const safedef = decircular(def)
184
+ const fullsrc = JSON.stringify(safedef, null, 2)
150
185
 
151
- steps.push('guide')
186
+ fs.writeFileSync(defpath + '.full.json', fullsrc)
152
187
 
188
+ ctx.def = safedef
153
189
 
154
- // Step: transformers (transform spec and guide into core structures).
155
- if (!ctrl.step.transformers) {
156
- return { ok: false, steps, start, end: Date.now(), ctrl, guide: ctx.guide }
157
- }
190
+ steps.push('parse')
158
191
 
159
- // const transformSpec = await resolveTransforms(ctx)
160
- const transforms = await resolveElements(ctx, 'transform', 'openapi', {
161
- top: topTransform,
162
- entity: entityTransform,
163
- operation: operationTransform,
164
- field: fieldTransform,
165
- clean: cleanTransform,
166
- })
192
+ // Step: guide (derive).
193
+ if (!ctrl.step.guide) {
194
+ return { ok: false, steps, start, end: Date.now(), ctrl }
195
+ }
167
196
 
168
- steps.push('transformers')
197
+ const guideModel = await buildGuide(ctx)
198
+ if (null == guideModel) {
199
+ throw new Error('Unable to build guide.')
200
+ }
169
201
 
170
- // Step: builders (build generated sub models).
171
- if (!ctrl.step.builders) {
172
- return { ok: false, steps, start, end: Date.now(), ctrl, guide: ctx.guide }
173
- }
202
+ ctx.guide = guideModel.guide
174
203
 
175
- const builders = await resolveElements(ctx, 'builder', 'standard', {
176
- entity: makeEntityBuilder,
177
- flow: makeFlowBuilder,
178
- })
204
+ steps.push('guide')
179
205
 
180
- steps.push('builders')
181
206
 
207
+ // Step: transformers (transform spec and guide into core structures).
208
+ if (!ctrl.step.transformers) {
209
+ return { ok: true, steps, start, end: Date.now(), ctrl, guide: ctx.guide }
210
+ }
182
211
 
183
- // Step: generate (generate model files).
184
- if (!ctrl.step.generate) {
185
- return { ok: false, steps, start, end: Date.now(), ctrl, guide: ctx.guide }
186
- }
187
212
 
188
- const jostraca = Jostraca({
189
- now: spec.now,
190
- fs: () => fs,
191
- log,
192
- })
213
+ /*
214
+ const transres = await resolveElements(ctx, 'transform', 'openapi', {
215
+ top: topTransform,
216
+ entity: entityTransform,
217
+ operation: operationTransform,
218
+ args: argsTransform,
219
+ field: fieldTransform,
220
+ clean: cleanTransform,
221
+ })
222
+ */
223
+
224
+ // const transformResult = await runTransform(ctx)
225
+ // if (null == transformResult) {
226
+ // throw new Error('Unable to run Transform.')
227
+ // }
193
228
 
194
- const jmodel = {}
229
+ await topTransform(ctx)
230
+ await entityTransform(ctx)
231
+ await operationTransform(ctx)
232
+ await argsTransform(ctx)
233
+ await selectTransform(ctx)
234
+ await fieldTransform(ctx)
235
+ await cleanTransform(ctx)
195
236
 
196
- const root = () => Project({ folder: '.' }, async () => {
197
- for (let builder of builders) {
198
- builder()
237
+
238
+ steps.push('transformers')
239
+
240
+ // Step: builders (build generated sub models).
241
+ if (!ctrl.step.builders) {
242
+ return { ok: true, steps, start, end: Date.now(), ctrl, guide: ctx.guide }
199
243
  }
200
- })
201
-
202
- const jres = await jostraca.generate({
203
- // folder: Path.dirname(opts.folder as string),
204
- folder: opts.folder,
205
- model: jmodel,
206
- existing: { txt: { merge: true } }
207
- }, root)
208
-
209
- const dlogs = dlog.log()
210
- if (0 < dlogs.length) {
211
- for (let dlogentry of dlogs) {
212
- log.debug({ point: 'generate-warning', dlogentry, note: String(dlogentry) })
244
+
245
+ const builders = [
246
+ await makeEntityBuilder(ctx),
247
+
248
+ // TODO: move to sdkgen
249
+ await makeFlowBuilder(ctx),
250
+ ]
251
+
252
+ steps.push('builders')
253
+
254
+
255
+ // Step: generate (generate model files).
256
+ if (!ctrl.step.generate) {
257
+ return { ok: true, steps, start, end: Date.now(), ctrl, guide: ctx.guide }
258
+ }
259
+
260
+ const jostraca = Jostraca({
261
+ now: spec.now,
262
+ fs: () => fs,
263
+ log,
264
+ })
265
+
266
+ const jmodel = {}
267
+
268
+ const root = () => Project({ folder: '.' }, async () => {
269
+ for (let builder of builders) {
270
+ builder()
271
+ }
272
+ })
273
+
274
+ jres = await jostraca.generate({
275
+ // folder: Path.dirname(opts.folder as string),
276
+ folder: opts.folder,
277
+ model: jmodel,
278
+ existing: { txt: { merge: true } }
279
+ }, root)
280
+
281
+ const dlogs = dlog.log()
282
+ if (0 < dlogs.length) {
283
+ for (let dlogentry of dlogs) {
284
+ log.debug({ point: 'generate-debug', dlogentry, note: String(dlogentry) })
285
+ }
213
286
  }
214
- }
215
287
 
216
- steps.push('generate')
288
+ steps.push('generate')
217
289
 
218
- log.info({ point: 'generate-end', note: 'success', break: true })
290
+ const hasWarnings = 0 < warn.history.length
291
+ const endnote =
292
+ hasWarnings ? `PARTIAL BUILD! There were ${warn.history.length} warnings (see above).` :
293
+ 'success'
294
+ log[hasWarnings ? 'warn' : 'info']({ point: 'generate-end', note: endnote, break: true })
295
+
296
+ if (hasWarnings) {
297
+ writeFileSyncWarn(warn, fs, './apidef-warnings.txt',
298
+ warn.history.map(n => formatJSONIC(n)).join('\n\n'))
299
+ }
219
300
 
220
- return {
221
- ok: true,
222
- start,
223
- end: Date.now(),
224
- steps,
225
- ctrl,
301
+ return {
302
+ ok: true,
303
+ err: null,
304
+ start,
305
+ end: Date.now(),
306
+ steps,
307
+ ctrl,
308
+ guide: ctx.guide,
309
+ apimodel: ctx.apimodel,
310
+ ctx,
311
+ jres,
312
+ }
313
+ }
314
+ catch (err: any) {
315
+ const endnote = '!! BUILD FAILED !! ' + err.message
316
+ log.error({ point: 'generate-end', err, note: endnote, break: true })
317
+
318
+ warn.history.push({
319
+ point: warn.point,
320
+ when: Date.now(),
321
+ err,
322
+ note: endnote
323
+ })
226
324
 
227
- guide: ctx.guide,
228
- apimodel,
229
- ctx,
230
- jres,
325
+ writeFileSyncWarn(warn, fs, './apidef-warnings.txt',
326
+ warn.history.map(n => formatJSONIC(n)).join('\n\n'))
327
+
328
+ return {
329
+ ok: false,
330
+ err,
331
+ start,
332
+ end: Date.now(),
333
+ steps,
334
+ ctrl,
335
+ guide: ctx?.guide,
336
+ apimodel: ctx?.apimodel,
337
+ ctx,
338
+ jres,
339
+ }
231
340
  }
232
341
  }
233
342
 
@@ -258,6 +367,7 @@ ApiDef.makeBuild = async function(opts: ApiDefOptions) {
258
367
  outprefix: opts.outprefix,
259
368
  strategy: opts.strategy,
260
369
  pino: build.log,
370
+ why: opts.why,
261
371
  })
262
372
  }
263
373
 
@@ -280,8 +390,41 @@ export type {
280
390
  ApiDefOptions,
281
391
  }
282
392
 
393
+ export type {
394
+ PathDef,
395
+ MethodDef,
396
+ ServerDef,
397
+ ServerVariableDef,
398
+ ParameterDef,
399
+ SchemaDef,
400
+ } from './def'
401
+
402
+ export type {
403
+ CmpDesc,
404
+ BasicMethodDesc,
405
+ MethodDesc,
406
+ MethodEntityDesc,
407
+ EntityDesc,
408
+ EntityPathDesc,
409
+ PathDesc,
410
+ OpDesc,
411
+ } from './desc'
412
+
413
+ export type {
414
+ OpName,
415
+ ModelEntityRelations,
416
+ ModelOpMap,
417
+ ModelFieldOp,
418
+ ModelField,
419
+ ModelArg,
420
+ ModelAlt,
421
+ ModelOp,
422
+ ModelEntity,
423
+ } from './model'
424
+
283
425
 
284
426
  export {
285
427
  ApiDef,
286
428
  parse,
429
+ formatJSONIC,
287
430
  }
@@ -6,38 +6,45 @@ import { each, File, Folder, Content } from 'jostraca'
6
6
 
7
7
 
8
8
  import type {
9
+ KitModel,
9
10
  ApiDefOptions,
10
11
  } from '../../types'
11
12
 
12
13
  import {
13
- formatJsonSrc,
14
+ KIT
15
+ } from '../../types'
16
+
17
+ import {
18
+ formatJSONIC,
14
19
  } from '../../utility'
15
20
 
16
21
 
17
22
 
18
- function resolveApiEntity(
23
+ function resolveEntity(
19
24
  apimodel: any,
20
25
  opts: ApiDefOptions,
21
26
  ) {
27
+ const kit: KitModel = apimodel.main[KIT]
28
+
22
29
  const barrel = [
23
30
  '# Entity Models\n'
24
31
  ]
25
32
 
26
33
  const entityFiles: { name: string, src: string }[] = []
27
34
 
28
- each(apimodel.main.api.entity, ((entity: any, entityName: string) => {
35
+ each(kit.entity, ((entity: any, entityName: string) => {
29
36
  const entityFile = (null == opts.outprefix ? '' : opts.outprefix) + entityName + '.jsonic'
30
37
 
31
- const entityJSON =
32
- JSON.stringify(entity, null, 2)
38
+ let entityJSONIC = formatJSONIC(entity).trim()
39
+ entityJSONIC = entityJSONIC.substring(1, entityJSONIC.length - 1)
33
40
 
34
41
  const fieldAliasesSrc = fieldAliases(entity)
35
42
 
36
43
  const entitySrc =
37
44
  `# Entity: ${entity.name}\n\n` +
38
- `main: api: entity: ${entity.name}: {\n\n` +
45
+ `main: ${KIT}: entity: ${entity.name}: {\n\n` +
39
46
  ` alias: field: ${fieldAliasesSrc}\n` +
40
- formatJsonSrc(entityJSON.substring(1, entityJSON.length - 1)) +
47
+ entityJSONIC +
41
48
  '\n\n}\n'
42
49
 
43
50
  entityFiles.push({ name: entityFile, src: entitySrc })
@@ -45,10 +52,10 @@ function resolveApiEntity(
45
52
  barrel.push(`@"${Path.basename(entityFile)}"`)
46
53
  }))
47
54
 
48
- const indexFile = (null == opts.outprefix ? '' : opts.outprefix) + 'api-entity-index.jsonic'
55
+ const indexFile = (null == opts.outprefix ? '' : opts.outprefix) + 'entity-index.jsonic'
49
56
 
50
57
  return function apiEntityBuilder() {
51
- Folder({ name: 'api' }, () => {
58
+ Folder({ name: 'entity' }, () => {
52
59
  each(entityFiles, (entityFile) => {
53
60
  File({ name: entityFile.name }, () => Content(entityFile.src))
54
61
  })
@@ -56,9 +63,9 @@ function resolveApiEntity(
56
63
  File({ name: indexFile }, () => Content(barrel.join('\n')))
57
64
  })
58
65
  }
59
-
60
66
  }
61
67
 
68
+
62
69
  function fieldAliases(entity: any) {
63
70
  // HEURISTIC: id may be name_id or nameId
64
71
  const fieldAliases =
@@ -84,5 +91,5 @@ function fieldAliases(entity: any) {
84
91
 
85
92
 
86
93
  export {
87
- resolveApiEntity
94
+ resolveEntity
88
95
  }
@@ -0,0 +1,53 @@
1
+ /* Copyright (c) 2025 Voxgig, MIT License */
2
+
3
+
4
+ import { formatJSONIC } from '../../utility'
5
+
6
+
7
+ import type {
8
+ KitModel,
9
+
10
+ ApiDefOptions,
11
+ ApiModel,
12
+ } from '../../types'
13
+
14
+ import {
15
+ KIT
16
+ } from '../../types'
17
+
18
+ import {
19
+ File,
20
+ Folder,
21
+ Content
22
+ } from 'jostraca'
23
+
24
+
25
+ function resolveInfo(
26
+ apimodel: any,
27
+ opts: ApiDefOptions,
28
+ ) {
29
+ const kit: KitModel = apimodel.main[KIT]
30
+
31
+ const infoFile =
32
+ (null == opts.outprefix ? '' : opts.outprefix) + 'api-info.jsonic'
33
+
34
+ const modelInfo = { main: { info: kit.info } }
35
+
36
+ let modelDefSrc = formatJSONIC(modelInfo)
37
+
38
+ modelDefSrc =
39
+ '# API Information\n\n' +
40
+ modelDefSrc.substring(1, modelDefSrc.length - 1).replace(/\n /g, '\n')
41
+
42
+ return function infoBuilder() {
43
+ Folder({ name: 'api' }, () => {
44
+ File({ name: infoFile }, () => Content(modelDefSrc))
45
+ })
46
+ }
47
+
48
+ }
49
+
50
+
51
+ export {
52
+ resolveInfo
53
+ }