@voxgig/sdkgen 0.32.2 → 0.33.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 (56) hide show
  1. package/bin/voxgig-sdkgen +1 -1
  2. package/dist/cmp/Readme.js +10 -0
  3. package/dist/cmp/Readme.js.map +1 -1
  4. package/dist/cmp/ReadmeEntity.js +91 -8
  5. package/dist/cmp/ReadmeEntity.js.map +1 -1
  6. package/dist/cmp/ReadmeIntro.js +24 -2
  7. package/dist/cmp/ReadmeIntro.js.map +1 -1
  8. package/dist/cmp/ReadmeModel.js +93 -16
  9. package/dist/cmp/ReadmeModel.js.map +1 -1
  10. package/dist/cmp/ReadmeOptions.js +30 -5
  11. package/dist/cmp/ReadmeOptions.js.map +1 -1
  12. package/dist/cmp/ReadmeRef.d.ts +2 -0
  13. package/dist/cmp/ReadmeRef.js +334 -0
  14. package/dist/cmp/ReadmeRef.js.map +1 -0
  15. package/dist/sdkgen.d.ts +2 -1
  16. package/dist/sdkgen.js +3 -1
  17. package/dist/sdkgen.js.map +1 -1
  18. package/dist/tsconfig.tsbuildinfo +1 -1
  19. package/package.json +2 -3
  20. package/project/.sdk/src/cmp/go/TestDirect_go.ts +2 -2
  21. package/project/.sdk/src/cmp/go/TestEntity_go.ts +3 -3
  22. package/project/.sdk/src/cmp/js/Config_js.ts +62 -23
  23. package/project/.sdk/src/cmp/js/EntityOperation_js.ts +49 -0
  24. package/project/.sdk/src/cmp/js/Entity_js.ts +21 -50
  25. package/project/.sdk/src/cmp/js/MainEntity_js.ts +1 -1
  26. package/project/.sdk/src/cmp/js/Main_js.ts +53 -44
  27. package/project/.sdk/src/cmp/js/Package_js.ts +39 -12
  28. package/project/.sdk/src/cmp/js/Quick_js.ts +6 -10
  29. package/project/.sdk/src/cmp/js/ReadmeQuick_js.ts +101 -5
  30. package/project/.sdk/src/cmp/js/SdkError_js.ts +42 -0
  31. package/project/.sdk/src/cmp/js/TestDirect_js.ts +288 -0
  32. package/project/.sdk/src/cmp/js/TestEntity_js.ts +352 -2
  33. package/project/.sdk/src/cmp/js/TestMain_js.ts +0 -3
  34. package/project/.sdk/src/cmp/js/Test_js.ts +20 -8
  35. package/project/.sdk/src/cmp/js/fragment/Config.fragment.js +55 -0
  36. package/project/.sdk/src/cmp/js/fragment/Direct.test.fragment.js +30 -0
  37. package/project/.sdk/src/cmp/js/fragment/Entity.fragment.js +119 -28
  38. package/project/.sdk/src/cmp/js/fragment/Entity.test.fragment.js +39 -0
  39. package/project/.sdk/src/cmp/js/fragment/EntityCreateOp.fragment.js +89 -45
  40. package/project/.sdk/src/cmp/js/fragment/EntityListOp.fragment.js +92 -41
  41. package/project/.sdk/src/cmp/js/fragment/EntityLoadOp.fragment.js +95 -45
  42. package/project/.sdk/src/cmp/js/fragment/EntityRemoveOp.fragment.js +95 -43
  43. package/project/.sdk/src/cmp/js/fragment/EntityUpdateOp.fragment.js +95 -43
  44. package/project/.sdk/src/cmp/js/fragment/Main.fragment.js +150 -65
  45. package/project/.sdk/src/cmp/js/fragment/SdkError.fragment.js +22 -0
  46. package/project/.sdk/src/cmp/js/utility_js.ts +64 -0
  47. package/project/.sdk/src/cmp/ts/ReadmeQuick_ts.ts +102 -5
  48. package/project/.sdk/src/cmp/ts/TestDirect_ts.ts +2 -2
  49. package/project/.sdk/src/cmp/ts/TestEntity_ts.ts +11 -8
  50. package/src/cmp/Readme.ts +12 -0
  51. package/src/cmp/ReadmeEntity.ts +105 -9
  52. package/src/cmp/ReadmeIntro.ts +30 -2
  53. package/src/cmp/ReadmeModel.ts +101 -18
  54. package/src/cmp/ReadmeOptions.ts +35 -6
  55. package/src/cmp/ReadmeRef.ts +369 -0
  56. package/src/sdkgen.ts +2 -0
@@ -1,68 +1,105 @@
1
1
 
2
- const { Config } = require('./Config')
2
+ const { inspect } = require('node:util')
3
+
4
+ const { config } = require('./Config')
3
5
  const { Utility } = require('./utility/Utility')
4
6
 
5
7
 
6
- class NameSDK {
7
- #options
8
- #features
9
- #utility = Utility
10
-
8
+ const { BaseFeature } = require('./feature/base/BaseFeature')
9
+
10
+
11
+ const stdutil = new Utility()
12
+
13
+
14
+ class ProjectNameSDK {
15
+ _mode = 'live'
16
+ _options
17
+ _utility = new Utility()
18
+ _features
19
+ _rootctx
20
+
11
21
  constructor(options) {
12
22
 
13
- this.#options = this.#utility.makeOptions({
23
+ this._rootctx = this._utility.makeContext({
14
24
  client: this,
15
- utility: this.#utility,
16
- config: Config,
25
+ utility: this._utility,
26
+ config,
17
27
  options,
28
+ shared: new WeakMap()
18
29
  })
19
30
 
20
- // #FeatureOptions
31
+ this._options = this._utility.makeOptions(this._rootctx)
21
32
 
22
- this.#features = {
23
- // #BuildFeature
33
+ const struct = this._utility.struct
34
+ const getpath = struct.getpath
35
+ const items = struct.items
36
+
37
+ if (true === getpath(this._options.feature, 'test.active')) {
38
+ this._mode = 'test'
24
39
  }
25
40
 
26
- // #PostConstruct-Hook
27
- }
41
+ this._rootctx.options = this._options
28
42
 
43
+ this._features = []
29
44
 
30
- options() {
31
- return { ...this.#options }
32
- }
45
+ const featureAdd = this._utility.featureAdd
46
+ const featureInit = this._utility.featureInit
33
47
 
34
- features() {
35
- return { ...this.#features }
36
- }
48
+ items(this._options.feature, (fitem) => {
49
+ const fname = fitem[0]
50
+ const fopts = fitem[1]
51
+ if (fopts.active) {
52
+ featureAdd(this._rootctx, this._rootctx.config.makeFeature(fname))
53
+ }
54
+ })
37
55
 
38
- utility() {
39
- return { ...this.#utility }
56
+ if (null != this._options.extend) {
57
+ for (let f of this._options.extend) {
58
+ featureAdd(this._rootctx, f)
59
+ }
60
+ }
61
+
62
+ for (let f of this._features) {
63
+ featureInit(this._rootctx, f)
64
+ }
65
+
66
+ const featureHook = this._utility.featureHook
67
+ featureHook(this._rootctx, 'PostConstruct')
40
68
  }
41
69
 
42
70
 
43
- static test(opts) {
44
- return new NameSDK({
45
- // #TestOptions
46
- ...(opts || {})
47
- })
71
+ options() {
72
+ return this._utility.struct.clone(this._options)
48
73
  }
49
74
 
50
- test(opts) {
51
- return new NameSDK({
52
- // #TestOptions
53
- ...(opts || this.#options || {})
54
- })
75
+
76
+ utility() {
77
+ return this._utility.struct.clone(this._utility)
55
78
  }
56
79
 
57
-
80
+
58
81
  async prepare(fetchargs) {
59
- const utility = this.#utility
60
- const { headers, auth, fullurl } = utility
82
+ const utility = this._utility
83
+ const struct = utility.struct
84
+ const clone = struct.clone
85
+
86
+ const {
87
+ makeContext,
88
+ makeFetchDef,
89
+ prepareHeaders,
90
+ prepareAuth,
91
+ } = utility
61
92
 
62
93
  fetchargs = fetchargs || {}
63
94
 
64
- const options = this.options()
95
+ let ctx = makeContext({
96
+ opname: 'prepare',
97
+ ctrl: fetchargs.ctrl || {},
98
+ }, this._rootctx)
99
+
100
+ const options = this._options
65
101
 
102
+ // Build spec directly from SDK options + user-provided fetch args.
66
103
  const spec = {
67
104
  base: options.base,
68
105
  prefix: options.prefix,
@@ -71,12 +108,13 @@ class NameSDK {
71
108
  method: fetchargs.method || 'GET',
72
109
  params: fetchargs.params || {},
73
110
  query: fetchargs.query || {},
74
- headers: headers({ client: this, utility }),
111
+ headers: prepareHeaders(ctx),
75
112
  body: fetchargs.body,
76
113
  step: 'start',
77
- alias: {},
78
114
  }
79
115
 
116
+ ctx.spec = spec
117
+
80
118
  // Merge user-provided headers over SDK defaults.
81
119
  if (fetchargs.headers) {
82
120
  const uheaders = fetchargs.headers
@@ -85,51 +123,48 @@ class NameSDK {
85
123
  }
86
124
  }
87
125
 
88
- // Apply SDK auth.
89
- const ctx = { client: this, op: { params: [] }, spec, utility }
90
- auth(ctx)
91
-
92
- // Build URL.
93
- const url = fullurl(ctx)
94
-
95
- const fetchdef = {
96
- url,
97
- method: spec.method,
98
- headers: { ...spec.headers },
126
+ // Apply SDK auth (apikey, auth prefix, etc.)
127
+ const authResult = prepareAuth(ctx)
128
+ if (authResult instanceof Error) {
129
+ return authResult
99
130
  }
100
131
 
101
- if (null != spec.body) {
102
- fetchdef.body =
103
- 'object' === typeof spec.body ? JSON.stringify(spec.body) : spec.body
104
- }
105
-
106
- return fetchdef
132
+ return makeFetchDef(ctx)
107
133
  }
108
134
 
109
135
 
110
136
  async direct(fetchargs) {
137
+ const utility = this._utility
138
+ const fetcher = utility.fetcher
139
+ const makeContext = utility.makeContext
140
+
111
141
  const fetchdef = await this.prepare(fetchargs)
112
142
  if (fetchdef instanceof Error) {
113
143
  return fetchdef
114
144
  }
115
145
 
116
- const options = this.options()
117
- const fetch = options.system.fetch
146
+ let ctx = makeContext({
147
+ opname: 'direct',
148
+ ctrl: (fetchargs || {}).ctrl || {},
149
+ }, this._rootctx)
118
150
 
119
151
  try {
120
- const response = await fetch(fetchdef.url, fetchdef)
152
+ const fetched = await fetcher(ctx, fetchdef.url, fetchdef)
121
153
 
122
- if (null == response) {
123
- return { ok: false, err: new Error('response: undefined') }
154
+ if (null == fetched) {
155
+ return { ok: false, err: ctx.error('direct_no_response', 'response: undefined') }
156
+ }
157
+ else if (fetched instanceof Error) {
158
+ return { ok: false, err: fetched }
124
159
  }
125
160
 
126
- const status = response.status
127
- const json = 'function' === typeof response.json ? await response.json() : response.json
161
+ const status = fetched.status
162
+ const json = 'function' === typeof fetched.json ? await fetched.json() : fetched.json
128
163
 
129
164
  return {
130
165
  ok: status >= 200 && status < 300,
131
166
  status,
132
- headers: response.headers,
167
+ headers: fetched.headers,
133
168
  data: json,
134
169
  }
135
170
  }
@@ -140,12 +175,62 @@ class NameSDK {
140
175
 
141
176
 
142
177
  // <[SLOT]>
178
+
179
+
180
+ static test(testoptsarg, sdkoptsarg) {
181
+ const struct = stdutil.struct
182
+ const setpath = struct.setpath
183
+ const getdef = struct.getdef
184
+ const clone = struct.clone
185
+ const setprop = struct.setprop
186
+
187
+ const sdkopts = getdef(clone(sdkoptsarg), {})
188
+ const testopts = getdef(clone(testoptsarg), {})
189
+ setprop(testopts, 'active', true)
190
+ setpath(sdkopts, 'feature.test', testopts)
191
+
192
+ const testsdk = new ProjectNameSDK(sdkopts)
193
+ testsdk._mode = 'test'
194
+
195
+ return testsdk
196
+ }
197
+
198
+
199
+ tester(testopts, sdkopts) {
200
+ return ProjectNameSDK.test(testopts, sdkopts)
201
+ }
202
+
203
+
204
+ toJSON() {
205
+ return { name: 'ProjectName' }
206
+ }
207
+
208
+ toString() {
209
+ return 'ProjectName ' + this._utility.struct.jsonify(this.toJSON())
210
+ }
211
+
212
+ [inspect.custom]() {
213
+ return this.toString()
214
+ }
215
+
216
+ }
217
+
218
+
219
+ class ProjectNameEntity {
220
+
143
221
  }
144
222
 
145
223
 
146
- const SDK = NameSDK
224
+ const SDK = ProjectNameSDK
225
+
147
226
 
148
227
  module.exports = {
149
- NameSDK,
228
+ stdutil,
229
+
230
+ BaseFeature,
231
+ ProjectNameEntity,
232
+
233
+ ProjectNameSDK,
150
234
  SDK,
151
235
  }
236
+
@@ -0,0 +1,22 @@
1
+
2
+ const { Context } = require('./Context')
3
+
4
+
5
+ class ProjectNameError extends Error {
6
+
7
+ isProjectNameError = true
8
+
9
+ sdk = 'ProjectName'
10
+
11
+ constructor(code, msg, ctx) {
12
+ super(msg)
13
+ this.code = code
14
+ this.ctx = ctx
15
+ }
16
+
17
+ }
18
+
19
+ module.exports = {
20
+ ProjectNameError
21
+ }
22
+
@@ -0,0 +1,64 @@
1
+
2
+ import * as Path from 'node:path'
3
+
4
+
5
+ import {
6
+ clone,
7
+ walk,
8
+ } from '@voxgig/struct'
9
+
10
+
11
+ function projectPath(suffix?: string): string {
12
+ return Path.normalize(Path.join(__dirname, '../../..', suffix ?? ''))
13
+ }
14
+
15
+
16
+ function formatJSONSrc(jsonsrc: string) {
17
+ return jsonsrc
18
+ .replace(/([{:\[,])/g, '$1 ')
19
+ .replace(/([}\]])/g, ' $1')
20
+ }
21
+
22
+
23
+ function formatJson(obj: any, flags?: { line?: boolean, margin?: number }): string {
24
+ const marginSize = flags?.margin ?? 0
25
+ const marginStr = ' '.repeat(marginSize)
26
+
27
+ let json: string
28
+
29
+ if (flags?.line) {
30
+ // One line with spaces for clarity
31
+ json = JSON.stringify(obj)
32
+ .replace(/([{:\[,])/g, '$1 ')
33
+ .replace(/([}\]])/g, ' $1')
34
+ }
35
+ else {
36
+ // Pretty printed with 2-space indentation
37
+ json = JSON.stringify(obj, null, 2)
38
+ }
39
+
40
+ // Add margin to the left of every line
41
+ if (marginSize > 0) {
42
+ json = json.split('\n').map(line => marginStr + line).join('\n')
43
+ }
44
+
45
+ return json
46
+ }
47
+
48
+
49
+ function clean(o: any) {
50
+ return walk(clone(o), (k: any, v: any, p: any) => {
51
+ if (null != k && k.endsWith('$')) {
52
+ delete p[k]
53
+ }
54
+ return v
55
+ })
56
+ }
57
+
58
+
59
+ export {
60
+ clean,
61
+ formatJSONSrc,
62
+ formatJson,
63
+ projectPath,
64
+ }
@@ -1,20 +1,117 @@
1
1
 
2
- import { cmp, Content } from '@voxgig/sdkgen'
2
+ import { cmp, each, Content } from '@voxgig/sdkgen'
3
+
4
+ import {
5
+ KIT,
6
+ getModelPath,
7
+ nom,
8
+ } from '@voxgig/apidef'
3
9
 
4
10
 
5
11
  const ReadmeQuick = cmp(function ReadmeQuick(props: any) {
6
12
  const { target, ctx$: { model } } = props
7
13
 
8
- Content('```ts')
14
+ const entity = getModelPath(model, `main.${KIT}.entity`)
15
+
16
+ // Find the first published entity for examples
17
+ const exampleEntity = Object.values(entity).find((e: any) => e.publish) as any
18
+
9
19
  Content(`
10
- const { ${model.const.Name}SDK } = require('${target.module.name}')
20
+ ### Create a Client
21
+
22
+ \`\`\`ts
23
+ import { ${model.const.Name}SDK } from '${target.module.name}'
11
24
 
12
- const client = ${model.const.Name}SDK.make({
25
+ const client = new ${model.const.Name}SDK({
13
26
  apikey: process.env.${model.NAME}_APIKEY,
14
27
  })
28
+ \`\`\`
29
+ `)
30
+
31
+
32
+ if (exampleEntity) {
33
+ const eName = nom(exampleEntity, 'Name')
34
+ const opnames = Object.keys(exampleEntity.op || {})
35
+
36
+ if (opnames.includes('load')) {
37
+ Content(`
38
+ ### Load a ${eName}
39
+
40
+ \`\`\`ts
41
+ const ${exampleEntity.name} = await client.${eName}().load({ id: '${exampleEntity.name}_id' })
42
+ console.log(${exampleEntity.name})
43
+ \`\`\`
44
+ `)
45
+ }
46
+
47
+ if (opnames.includes('list')) {
48
+ Content(`
49
+ ### List ${eName} Records
50
+
51
+ \`\`\`ts
52
+ const ${exampleEntity.name}s = await client.${eName}().list()
53
+ console.log(${exampleEntity.name}s)
54
+ \`\`\`
55
+ `)
56
+ }
57
+
58
+ if (opnames.includes('create')) {
59
+ Content(`
60
+ ### Create a ${eName}
61
+
62
+ \`\`\`ts
63
+ const created = await client.${eName}().create({
64
+ // Provide ${exampleEntity.name} fields
65
+ })
66
+ console.log(created)
67
+ \`\`\`
68
+ `)
69
+ }
70
+
71
+ if (opnames.includes('update')) {
72
+ Content(`
73
+ ### Update a ${eName}
74
+
75
+ \`\`\`ts
76
+ const updated = await client.${eName}().update({
77
+ id: '${exampleEntity.name}_id',
78
+ // Fields to update
79
+ })
80
+ console.log(updated)
81
+ \`\`\`
82
+ `)
83
+ }
84
+
85
+ if (opnames.includes('remove')) {
86
+ Content(`
87
+ ### Remove a ${eName}
88
+
89
+ \`\`\`ts
90
+ await client.${eName}().remove({ id: '${exampleEntity.name}_id' })
91
+ \`\`\`
92
+ `)
93
+ }
94
+ }
95
+
96
+
97
+ Content(`
98
+ ### Direct API Access
99
+
100
+ Use \`client.direct()\` to call any API endpoint directly:
101
+
102
+ \`\`\`ts
103
+ const result = await client.direct({
104
+ path: '/custom/endpoint/{id}',
105
+ method: 'GET',
106
+ params: { id: 'abc123' },
107
+ })
108
+
109
+ if (result.ok) {
110
+ console.log(result.data)
111
+ }
112
+ \`\`\`
15
113
 
16
114
  `)
17
- Content('```')
18
115
 
19
116
  })
20
117
 
@@ -29,8 +29,8 @@ const TestDirect = cmp(function TestDirect(props: any) {
29
29
 
30
30
  const ff = projectPath('src/cmp/ts/fragment/')
31
31
 
32
- const PROJECTNAME = model.Name.toUpperCase()
33
- const entidEnvVar = `${PROJECTNAME}_TEST_${entity.Name.toUpperCase()}_ENTID`
32
+ const PROJECTNAME = model.Name.toUpperCase().replace(/[^A-Z_]/g, '_')
33
+ const entidEnvVar = `${PROJECTNAME}_TEST_${entity.Name.toUpperCase().replace(/[^A-Z_]/g, '_')}_ENTID`
34
34
 
35
35
  const opnames = Object.keys(entity.op)
36
36
  const hasLoad = opnames.includes('load')
@@ -48,6 +48,9 @@ const TestEntity = cmp(function TestEntity(props: any) {
48
48
  const target = props.target
49
49
  const entity = props.entity
50
50
 
51
+ const PROJENVNAME = nom(model.const, 'NAME').replace(/[^A-Z_]/g, '_')
52
+ const ENTENVNAME = nom(entity, 'NAME').replace(/[^A-Z_]/g, '_')
53
+
51
54
  // TODO: should be a utility function
52
55
  const ff = projectPath('src/cmp/ts/fragment/')
53
56
 
@@ -118,18 +121,18 @@ function basicSetup(extra?: any) {
118
121
  })
119
122
 
120
123
  const env = envOverride({
121
- '${nom(model.const, 'NAME')}_TEST_${nom(entity, 'NAME')}_ENTID': idmap,
122
- '${nom(model.const, 'NAME')}_TEST_LIVE': 'FALSE',
123
- '${nom(model.const, 'NAME')}_TEST_EXPLAIN': 'FALSE',
124
- '${nom(model.const, 'NAME')}_APIKEY': 'NONE',
124
+ '${PROJENVNAME}_TEST_${ENTENVNAME}_ENTID': idmap,
125
+ '${PROJENVNAME}_TEST_LIVE': 'FALSE',
126
+ '${PROJENVNAME}_TEST_EXPLAIN': 'FALSE',
127
+ '${PROJENVNAME}_APIKEY': 'NONE',
125
128
  })
126
129
 
127
- idmap = env['${nom(model.const, 'NAME')}_TEST_${nom(entity, 'NAME')}_ENTID']
130
+ idmap = env['${PROJENVNAME}_TEST_${ENTENVNAME}_ENTID']
128
131
 
129
- if ('TRUE' === env.${model.NAME}_TEST_LIVE) {
132
+ if ('TRUE' === env.${PROJENVNAME}_TEST_LIVE) {
130
133
  client = new ${model.Name}SDK(merge([
131
134
  {
132
- apikey: env.${nom(model.const, 'NAME')}_APIKEY,
135
+ apikey: env.${PROJENVNAME}_APIKEY,
133
136
  },
134
137
  extra
135
138
  ]))
@@ -142,7 +145,7 @@ function basicSetup(extra?: any) {
142
145
  client,
143
146
  struct,
144
147
  data: entityData,
145
- explain: 'TRUE' === env.${nom(model.const, 'NAME')}_TEST_EXPLAIN,
148
+ explain: 'TRUE' === env.${PROJENVNAME}_TEST_EXPLAIN,
146
149
  now: Date.now(),
147
150
  }
148
151
 
package/src/cmp/Readme.ts CHANGED
@@ -8,6 +8,7 @@ import { ReadmeQuick } from './ReadmeQuick'
8
8
  import { ReadmeModel } from './ReadmeModel'
9
9
  import { ReadmeOptions } from './ReadmeOptions'
10
10
  import { ReadmeEntity } from './ReadmeEntity'
11
+ import { ReadmeRef } from './ReadmeRef'
11
12
 
12
13
 
13
14
  const Readme = cmp(function Readme(props: any) {
@@ -26,7 +27,18 @@ const Readme = cmp(function Readme(props: any) {
26
27
  ReadmeModel({ target })
27
28
  ReadmeOptions({ target })
28
29
  ReadmeEntity({ target })
30
+
31
+ Content(`
32
+ ## Reference
33
+
34
+ See [REFERENCE.md](REFERENCE.md) for complete API reference
35
+ documentation including all method signatures, entity field schemas,
36
+ and detailed usage examples.
37
+ `)
29
38
  })
39
+
40
+ // Generate separate reference documentation
41
+ ReadmeRef({ target })
30
42
  })
31
43
 
32
44