@voxgig/apidef 2.0.0 → 2.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.
@@ -20,30 +20,53 @@ const operationTransform = async function(
20
20
 
21
21
  let msg = 'operations: '
22
22
 
23
- const paramBuilder = (paramMap: any, paramDef: any,
24
- entityModel: any, pathdef: any,
25
- op: any, path: any, entity: any, model: any) => {
23
+ const paramBuilder = (
24
+ paramMap: any,
25
+ paramDef: any,
26
+ opModel: any,
27
+ entityModel: any,
28
+ pathdef: any,
29
+ op: any,
30
+ path: any,
31
+ entity: any,
32
+ model: any
33
+ ) => {
26
34
 
27
- paramMap[paramDef.name] = {
35
+ const paramSpec: any = paramMap[paramDef.name] = {
28
36
  required: paramDef.required
29
37
  }
30
- fixName(paramMap[paramDef.name], paramDef.name)
38
+ fixName(paramSpec, paramDef.name)
31
39
 
32
40
  const type = paramDef.schema ? paramDef.schema.type : paramDef.type
33
- fixName(paramMap[paramDef.name], type, 'type')
41
+ fixName(paramSpec, type, 'type')
42
+
43
+ // Path params are always required.
44
+ opModel.validate.params[paramDef.name] = `\`$${paramSpec.TYPE}\``
34
45
  }
35
46
 
36
47
 
37
- const queryBuilder = (queryMap: any, queryDef: any,
38
- entityModel: any, pathdef: any,
39
- op: any, path: any, entity: any, model: any) => {
40
- queryMap[queryDef.name] = {
48
+ const queryBuilder = (
49
+ queryMap: any,
50
+ queryDef: any,
51
+ opModel: any,
52
+ entityModel: any,
53
+ pathdef: any,
54
+ op: any,
55
+ path: any,
56
+ entity: any,
57
+ model: any
58
+ ) => {
59
+ const querySpec: any = queryMap[queryDef.name] = {
41
60
  required: queryDef.required
42
61
  }
43
62
  fixName(queryMap[queryDef.name], queryDef.name)
44
63
 
45
64
  const type = queryDef.schema ? queryDef.schema.type : queryDef.type
46
65
  fixName(queryMap[queryDef.name], type, 'type')
66
+
67
+ if (queryDef.required) {
68
+ opModel.validate.params[queryDef.name] = `\`$${querySpec.TYPE}\``
69
+ }
47
70
  }
48
71
 
49
72
 
@@ -57,6 +80,7 @@ const operationTransform = async function(
57
80
  pathdef: any
58
81
  ) => {
59
82
  let out
83
+ let why = 'none'
60
84
 
61
85
  if (null != op.transform?.[direction]) {
62
86
  out = op.transform[direction]
@@ -67,16 +91,12 @@ const operationTransform = async function(
67
91
  const mdef = pathdef[method]
68
92
 
69
93
  // TODO: fix getx
70
- const content = 'res' === kind ?
94
+ // const content = 'res' === kind ?
95
+ const content = 'resform' === direction ?
71
96
  (getx(mdef, 'responses.200.content') ||
72
97
  getx(mdef, 'responses.201.content')) :
73
98
  getx(mdef, 'requestBody.content')
74
99
 
75
- // console.log(entityModel)
76
- // console.log(mdef)
77
- // console.log(getx(mdef, 'responses.200.content'))
78
- // console.log(kind, method, pathdef, content)
79
-
80
100
  if (content) {
81
101
 
82
102
  const schema = content['application/json']?.schema
@@ -86,18 +106,22 @@ const operationTransform = async function(
86
106
  const resolveDirectionTransform =
87
107
  'resform' === direction ? resolveResponseTransform : resolveRequestTransform
88
108
 
89
- const transform = resolveDirectionTransform(
90
- op,
91
- kind,
92
- method,
93
- mdef,
94
- content,
95
- schema,
96
- propkeys
97
- )
109
+ //const [transform, why]
110
+ ;[out, why]
111
+ = resolveDirectionTransform(
112
+ entityModel,
113
+ op,
114
+ kind,
115
+ direction,
116
+ method,
117
+ mdef,
118
+ content,
119
+ schema,
120
+ propkeys
121
+ )
98
122
 
99
123
  // out = JSON.stringify(transform)
100
- out = transform
124
+ // out = transform
101
125
  }
102
126
  else {
103
127
  out = 'res' === kind ? '`body`' : '`reqdata`'
@@ -105,19 +129,22 @@ const operationTransform = async function(
105
129
  }
106
130
 
107
131
 
108
- return out
132
+ return [out, why]
109
133
  }
110
134
 
111
135
 
112
136
  const resolveResponseTransform = (
137
+ entityModel: any,
113
138
  op: any,
114
139
  kind: 'res' | 'req',
140
+ direction: 'resform' | 'reqform',
115
141
  method: string,
116
142
  mdef: any,
117
143
  content: any,
118
144
  schema: any,
119
145
  propkeys: any
120
146
  ) => {
147
+ let why = 'default'
121
148
  let transform: any = '`body`'
122
149
 
123
150
  if (null == content || null == schema || null == propkeys) {
@@ -129,12 +156,14 @@ const operationTransform = async function(
129
156
  if ('list' === opname) {
130
157
  if ('array' !== schema.type) {
131
158
  if (1 === propkeys.length) {
159
+ why = 'list-single-prop:' + propkeys[0]
132
160
  transform = '`body.' + propkeys[0] + '`'
133
161
  }
134
162
  else {
135
163
  // Use sub property that is an array
136
164
  for (let pk of propkeys) {
137
165
  if ('array' === schema.properties[pk]?.type) {
166
+ why = 'list-single-array:' + pk
138
167
  transform = '`body.' + pk + '`'
139
168
  break
140
169
  }
@@ -146,11 +175,13 @@ const operationTransform = async function(
146
175
  if ('object' === schema.type) {
147
176
  if (null == schema.properties.id) {
148
177
  if (1 === propkeys.length) {
178
+ why = 'map-single-prop:' + propkeys[0]
149
179
  transform = '`body.' + propkeys[0] + '`'
150
180
  }
151
181
  else {
152
182
  for (let pk of propkeys) {
153
183
  if (schema.properties[pk].properties?.id) {
184
+ why = 'map-sub-prop:' + pk
154
185
  transform = '`body.' + pk + '`'
155
186
  break
156
187
  }
@@ -160,13 +191,15 @@ const operationTransform = async function(
160
191
  }
161
192
  }
162
193
 
163
- return transform
194
+ return [transform, why]
164
195
  }
165
196
 
166
197
 
167
198
  const resolveRequestTransform = (
199
+ entityModel: any,
168
200
  op: any,
169
201
  kind: 'res' | 'req',
202
+ direction: 'resform' | 'reqform',
170
203
  method: string,
171
204
  mdef: any,
172
205
  content: any,
@@ -174,6 +207,7 @@ const operationTransform = async function(
174
207
  propkeys: any
175
208
  ) => {
176
209
  let transform: any = '`data`'
210
+ let why = 'default'
177
211
 
178
212
  if (null == content || null == schema || null == propkeys) {
179
213
  return transform
@@ -184,12 +218,14 @@ const operationTransform = async function(
184
218
  if ('list' === opname) {
185
219
  if ('array' !== schema.type) {
186
220
  if (1 === propkeys.length) {
221
+ why = 'list-single-prop:' + propkeys[0]
187
222
  transform = { [propkeys[0]]: '`data`' }
188
223
  }
189
224
  else {
190
225
  // Use sub property that is an array
191
226
  for (let pk of propkeys) {
192
227
  if ('array' === schema.properties[pk]?.type) {
228
+ why = 'list-single-array:' + pk
193
229
  transform = { [pk]: '`data`' }
194
230
  break
195
231
  }
@@ -201,11 +237,13 @@ const operationTransform = async function(
201
237
  if ('object' === schema.type) {
202
238
  if (null == schema.properties.id) {
203
239
  if (1 === propkeys.length) {
240
+ why = 'map-single-prop:' + propkeys[0]
204
241
  transform = { [propkeys[0]]: '`data`' }
205
242
  }
206
243
  else {
207
244
  for (let pk of propkeys) {
208
245
  if (schema.properties[pk].properties?.id) {
246
+ why = 'map-sub-prop:' + pk
209
247
  transform = { [pk]: '`data`' }
210
248
  break
211
249
  }
@@ -215,7 +253,7 @@ const operationTransform = async function(
215
253
  }
216
254
  }
217
255
 
218
- return transform
256
+ return [transform, why]
219
257
  }
220
258
 
221
259
 
@@ -225,26 +263,39 @@ const operationTransform = async function(
225
263
  const method = op.method
226
264
  const kind = OPKIND[opname]
227
265
 
228
- const em = entityModel.op[opname] = {
266
+ const [resform, resform_COMMENT] =
267
+ resolveTransform(entityModel, op, kind, 'resform', pathdef)
268
+
269
+ const [reqform, reqform_COMMENT] =
270
+ resolveTransform(entityModel, op, kind, 'reqform', pathdef)
271
+
272
+ const opModel = entityModel.op[opname] = {
229
273
  path: path.key$,
230
274
  method,
231
275
  kind,
232
276
  param: {},
233
277
  query: {},
234
- // transform: {
235
- resform: resolveTransform(entityModel, op, kind, 'resform', pathdef),
236
- reqform: resolveTransform(entityModel, op, kind, 'reqform', pathdef),
237
- // }
278
+
279
+ resform_COMMENT: 'derivation: ' + resform_COMMENT,
280
+ resform,
281
+
282
+ reqform_COMMENT: 'derivation: ' + reqform_COMMENT,
283
+ reqform,
284
+
285
+ validate: {
286
+ params: { '`$OPEN`': true }
287
+ }
238
288
  }
239
289
 
240
- fixName(em, op.key$)
290
+ fixName(opModel, op.key$)
241
291
 
242
292
  // Params are in the path
243
293
  if (0 < path.params$.length) {
244
294
  let params = getx(pathdef[method], 'parameters?in=path') || []
245
295
  if (Array.isArray(params)) {
246
296
  params.reduce((a: any, p: any) =>
247
- (paramBuilder(a, p, entityModel, pathdef, op, path, entity, model), a), em.param)
297
+ (paramBuilder(a, p, opModel, entityModel,
298
+ pathdef, op, path, entity, model), a), opModel.param)
248
299
  }
249
300
  }
250
301
 
@@ -252,10 +303,11 @@ const operationTransform = async function(
252
303
  let queries = getx(pathdef[op.val$], 'parameters?in!=path') || []
253
304
  if (Array.isArray(queries)) {
254
305
  queries.reduce((a: any, p: any) =>
255
- (queryBuilder(a, p, entityModel, pathdef, op, path, entity, model), a), em.query)
306
+ (queryBuilder(a, p, opModel, entityModel,
307
+ pathdef, op, path, entity, model), a), opModel.query)
256
308
  }
257
309
 
258
- return em
310
+ return opModel
259
311
  },
260
312
 
261
313
 
package/src/transform.ts CHANGED
@@ -106,7 +106,6 @@ async function resolveTransforms(ctx: TransformCtx): Promise<TransformSpec> {
106
106
  }
107
107
  }
108
108
  catch (err: any) {
109
- console.log(err)
110
109
  throw err
111
110
  }
112
111
 
@@ -181,7 +180,7 @@ async function processTransforms(
181
180
  }
182
181
  catch (err: any) {
183
182
  // TODO: fix: this error does not get printed
184
- console.log(err)
183
+ console.error(err)
185
184
 
186
185
  pres.ok = false
187
186
  pres.msg += transform.name + ': ' + err.message + '\n'
package/src/types.ts CHANGED
@@ -29,11 +29,12 @@ const ModelShape = Gubu({
29
29
  sdk: {},
30
30
  def: {},
31
31
  api: {
32
- guide: {}
32
+ guide: {},
33
+ entity: {},
33
34
  },
34
35
  }
35
36
  })
36
- const OpenModelShape = Gubu(Open(ModelShape))
37
+ const OpenModelShape = Gubu(Open(ModelShape), { name: 'Model' })
37
38
 
38
39
  type Model = ReturnType<typeof ModelShape>
39
40
 
package/src/utility.ts CHANGED
@@ -24,9 +24,84 @@ function formatJsonSrc(jsonsrc: string) {
24
24
  return jsonsrc
25
25
  .replace(/"([a-zA-Z_][a-zA-Z_0-9]*)": /g, '$1: ')
26
26
  .replace(/},/g, '}\n')
27
+ // .replace(/([a-zA-Z_][a-zA-Z_0-9]*)_COMMENT:/g, '# $1')
28
+ .replace(/\n(\s*)([a-zA-Z_][a-zA-Z_0-9]*)_COMMENT:\s*"(.*)",/g, '\n\n$1# $2 $3')
27
29
  }
28
30
 
29
31
 
32
+ function depluralize(word: string): string {
33
+ if (!word || word.length === 0) {
34
+ return word
35
+ }
36
+
37
+ // Common irregular plurals
38
+ const irregulars: Record<string, string> = {
39
+ 'children': 'child',
40
+ 'men': 'man',
41
+ 'women': 'woman',
42
+ 'teeth': 'tooth',
43
+ 'feet': 'foot',
44
+ 'geese': 'goose',
45
+ 'mice': 'mouse',
46
+ 'people': 'person',
47
+ 'data': 'datum',
48
+ 'criteria': 'criterion',
49
+ 'phenomena': 'phenomenon',
50
+ 'indices': 'index',
51
+ 'matrices': 'matrix',
52
+ 'vertices': 'vertex',
53
+ 'analyses': 'analysis',
54
+ 'axes': 'axis',
55
+ 'crises': 'crisis',
56
+ 'diagnoses': 'diagnosis',
57
+ 'oases': 'oasis',
58
+ 'theses': 'thesis',
59
+ 'appendices': 'appendix'
60
+ }
61
+
62
+ if (irregulars[word]) {
63
+ return irregulars[word]
64
+ }
65
+
66
+ // Rules for regular plurals (applied in order)
67
+
68
+ // -ies -> -y (cities -> city)
69
+ if (word.endsWith('ies') && word.length > 3) {
70
+ return word.slice(0, -3) + 'y'
71
+ }
72
+
73
+ // -ves -> -f or -fe (wolves -> wolf, knives -> knife)
74
+ if (word.endsWith('ves')) {
75
+ const stem = word.slice(0, -3)
76
+ // Check if it should be -fe (like knife, wife, life)
77
+ if (['kni', 'wi', 'li'].includes(stem)) {
78
+ return stem + 'fe'
79
+ }
80
+ return stem + 'f'
81
+ }
82
+
83
+ // -oes -> -o (potatoes -> potato)
84
+ if (word.endsWith('oes')) {
85
+ return word.slice(0, -2)
86
+ }
87
+
88
+ // -ses, -xes, -zes, -shes, -ches -> remove -es (boxes -> box)
89
+ if (word.endsWith('ses') || word.endsWith('xes') || word.endsWith('zes') ||
90
+ word.endsWith('shes') || word.endsWith('ches')) {
91
+ return word.slice(0, -2)
92
+ }
93
+
94
+ // -s -> remove -s (cats -> cat)
95
+ if (word.endsWith('s') && !word.endsWith('ss')) {
96
+ return word.slice(0, -1)
97
+ }
98
+
99
+ // If none of the rules apply, return as is
100
+ return word
101
+ }
102
+
103
+
104
+ /*
30
105
  function writeChanged(
31
106
  point: string, path: string, content: string,
32
107
  fs: FsUtil, log: Log,
@@ -74,10 +149,13 @@ function writeChanged(
74
149
  throw err
75
150
  }
76
151
  }
152
+ */
77
153
 
78
154
 
79
155
  export {
80
156
  loadFile,
81
- formatJsonSrc
157
+ formatJsonSrc,
158
+ depluralize,
159
+
82
160
  // writeChanged,
83
161
  }
@@ -1,45 +0,0 @@
1
-
2
-
3
- import { each, snakify, names } from 'jostraca'
4
-
5
-
6
-
7
- async function flowHeuristic01(ctx: any): Promise<any[]> {
8
- let entity = ctx.model.main.api.guide.entity
9
-
10
- const flows: any[] = []
11
-
12
- each(entity, (entity: any) => {
13
- flows.push(resolveBasicEntityFlow(ctx, entity))
14
- })
15
-
16
- return flows
17
- }
18
-
19
-
20
-
21
-
22
- function resolveBasicEntityFlow(ctx: any, entity: any) {
23
- const apiEntity = ctx.apimodel.main.api.entity[entity.name]
24
-
25
- const flow: any = {
26
- name: 'Basic' + apiEntity.Name
27
- }
28
-
29
- flow.model = ({
30
- name: flow.Name,
31
- param: {},
32
- test: { entity: { [apiEntity.Name]: {} } },
33
- step: []
34
- } as any)
35
-
36
- names(flow, flow.name)
37
-
38
- return flow
39
- }
40
-
41
-
42
-
43
- export {
44
- flowHeuristic01
45
- }