massimo-cli 0.0.1 → 0.1.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.
- package/LICENSE +201 -0
- package/NOTICE +13 -0
- package/README.md +13 -0
- package/eslint.config.js +3 -0
- package/help/help.txt +79 -0
- package/index.d.ts +18 -0
- package/index.js +537 -0
- package/index.test-d.ts +15 -0
- package/lib/errors.js +6 -0
- package/lib/frontend-openapi-generator.js +450 -0
- package/lib/get-type.js +146 -0
- package/lib/graphql-generator.js +136 -0
- package/lib/openapi-common.js +281 -0
- package/lib/openapi-generator.js +153 -0
- package/lib/responses-writer.js +91 -0
- package/lib/utils.js +119 -0
- package/package.json +77 -8
package/index.js
ADDED
|
@@ -0,0 +1,537 @@
|
|
|
1
|
+
#! /usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { access, mkdir, readFile, rm, writeFile } from 'fs/promises'
|
|
4
|
+
import graphql from 'graphql'
|
|
5
|
+
import helpMe from 'help-me'
|
|
6
|
+
import parseArgs from 'minimist'
|
|
7
|
+
import { join } from 'path'
|
|
8
|
+
import pino from 'pino'
|
|
9
|
+
import pinoPretty from 'pino-pretty'
|
|
10
|
+
import { getGlobalDispatcher, interceptors, request } from 'undici'
|
|
11
|
+
import YAML from 'yaml'
|
|
12
|
+
import { processFrontendOpenAPI } from './lib/frontend-openapi-generator.js'
|
|
13
|
+
import { processGraphQL } from './lib/graphql-generator.js'
|
|
14
|
+
import { processOpenAPI } from './lib/openapi-generator.js'
|
|
15
|
+
|
|
16
|
+
function parseFile (content) {
|
|
17
|
+
let parsed = false
|
|
18
|
+
const toTry = [JSON.parse, YAML.parse]
|
|
19
|
+
for (const fn of toTry) {
|
|
20
|
+
try {
|
|
21
|
+
parsed = fn(content)
|
|
22
|
+
} catch (err) {
|
|
23
|
+
// do nothing
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return parsed
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function isFileAccessible (filename) {
|
|
30
|
+
try {
|
|
31
|
+
await access(filename)
|
|
32
|
+
return true
|
|
33
|
+
} catch (err) {
|
|
34
|
+
return false
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export async function createDirectory (path, empty = false) {
|
|
39
|
+
if (empty) {
|
|
40
|
+
await rm(path, { force: true, recursive: true })
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return mkdir(path, { recursive: true, maxRetries: 10, retryDelay: 1000 })
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async function writeOpenAPIClient (
|
|
47
|
+
folder,
|
|
48
|
+
name,
|
|
49
|
+
text,
|
|
50
|
+
generateImplementation,
|
|
51
|
+
typesOnly,
|
|
52
|
+
fullRequest,
|
|
53
|
+
fullResponse,
|
|
54
|
+
optionalHeaders,
|
|
55
|
+
validateResponse,
|
|
56
|
+
isFrontend,
|
|
57
|
+
language,
|
|
58
|
+
typesComment,
|
|
59
|
+
logger,
|
|
60
|
+
withCredentials,
|
|
61
|
+
propsOptional
|
|
62
|
+
) {
|
|
63
|
+
await createDirectory(folder)
|
|
64
|
+
|
|
65
|
+
// TODO deal with yaml
|
|
66
|
+
const schema = parseFile(text)
|
|
67
|
+
if (!schema) {
|
|
68
|
+
throw new Error('Cannot parse OpenAPI file. Please make sure is a JSON or a YAML file.')
|
|
69
|
+
}
|
|
70
|
+
if (!typesOnly) {
|
|
71
|
+
await writeFile(join(folder, `${name}.openapi.json`), JSON.stringify(schema, null, 2))
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (isFrontend) {
|
|
75
|
+
const { types, implementation } = processFrontendOpenAPI({
|
|
76
|
+
schema,
|
|
77
|
+
name,
|
|
78
|
+
fullRequest,
|
|
79
|
+
fullResponse,
|
|
80
|
+
language,
|
|
81
|
+
logger,
|
|
82
|
+
withCredentials,
|
|
83
|
+
propsOptional
|
|
84
|
+
})
|
|
85
|
+
await writeFile(join(folder, `${name}-types.d.ts`), types)
|
|
86
|
+
if (generateImplementation) {
|
|
87
|
+
const extension = language === 'js' ? 'js' : 'ts'
|
|
88
|
+
await writeFile(join(folder, `${name}.${extension}`), implementation)
|
|
89
|
+
}
|
|
90
|
+
} else {
|
|
91
|
+
const { types, implementation } = processOpenAPI({
|
|
92
|
+
schema,
|
|
93
|
+
name,
|
|
94
|
+
fullResponse,
|
|
95
|
+
fullRequest,
|
|
96
|
+
optionalHeaders,
|
|
97
|
+
validateResponse,
|
|
98
|
+
typesComment,
|
|
99
|
+
propsOptional
|
|
100
|
+
})
|
|
101
|
+
await writeFile(join(folder, `${name}.d.ts`), types)
|
|
102
|
+
if (generateImplementation) {
|
|
103
|
+
await writeFile(join(folder, `${name}.js`), implementation)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (!typesOnly) {
|
|
107
|
+
await writeFile(join(folder, 'package.json'), getPackageJSON({ name, generateImplementation }))
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async function writeGraphQLClient (folder, name, schema, url, generateImplementation) {
|
|
113
|
+
await createDirectory(folder, { recursive: true })
|
|
114
|
+
const { types, implementation } = processGraphQL({ schema, name, folder, url })
|
|
115
|
+
const clientSchema = graphql.buildClientSchema(schema)
|
|
116
|
+
const sdl = graphql.printSchema(clientSchema)
|
|
117
|
+
await writeFile(join(folder, `${name}.schema.graphql`), sdl)
|
|
118
|
+
await writeFile(join(folder, `${name}.d.ts`), types)
|
|
119
|
+
if (generateImplementation) {
|
|
120
|
+
await writeFile(join(folder, `${name}.js`), implementation)
|
|
121
|
+
}
|
|
122
|
+
await writeFile(join(folder, 'package.json'), getPackageJSON({ name, generateImplementation }))
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async function downloadAndWriteOpenAPI (
|
|
126
|
+
logger,
|
|
127
|
+
url,
|
|
128
|
+
folder,
|
|
129
|
+
name,
|
|
130
|
+
generateImplementation,
|
|
131
|
+
typesOnly,
|
|
132
|
+
fullRequest,
|
|
133
|
+
fullResponse,
|
|
134
|
+
optionalHeaders,
|
|
135
|
+
validateResponse,
|
|
136
|
+
isFrontend,
|
|
137
|
+
language,
|
|
138
|
+
urlAuthHeaders,
|
|
139
|
+
typesComment,
|
|
140
|
+
withCredentials,
|
|
141
|
+
propsOptional,
|
|
142
|
+
retryTimeoutMs
|
|
143
|
+
) {
|
|
144
|
+
logger.debug(`Trying to download OpenAPI schema from ${url}`)
|
|
145
|
+
let requestOptions
|
|
146
|
+
if (urlAuthHeaders) {
|
|
147
|
+
try {
|
|
148
|
+
requestOptions = { headers: JSON.parse(urlAuthHeaders) }
|
|
149
|
+
} catch (err) {
|
|
150
|
+
logger.error(err)
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const dispatcher = retryTimeoutMs
|
|
155
|
+
? getGlobalDispatcher().compose([interceptors.retry({ minTimeout: retryTimeoutMs })])
|
|
156
|
+
: undefined
|
|
157
|
+
const res = await request(url, { ...requestOptions, dispatcher })
|
|
158
|
+
if (res.statusCode === 200) {
|
|
159
|
+
// we are OpenAPI
|
|
160
|
+
const text = await res.body.text()
|
|
161
|
+
try {
|
|
162
|
+
await writeOpenAPIClient(
|
|
163
|
+
folder,
|
|
164
|
+
name,
|
|
165
|
+
text,
|
|
166
|
+
generateImplementation,
|
|
167
|
+
typesOnly,
|
|
168
|
+
fullRequest,
|
|
169
|
+
fullResponse,
|
|
170
|
+
optionalHeaders,
|
|
171
|
+
validateResponse,
|
|
172
|
+
isFrontend,
|
|
173
|
+
language,
|
|
174
|
+
typesComment,
|
|
175
|
+
logger,
|
|
176
|
+
withCredentials,
|
|
177
|
+
propsOptional
|
|
178
|
+
)
|
|
179
|
+
/* c8 ignore next 3 */
|
|
180
|
+
} catch (err) {
|
|
181
|
+
logger.error(err)
|
|
182
|
+
return false
|
|
183
|
+
}
|
|
184
|
+
return 'openapi'
|
|
185
|
+
}
|
|
186
|
+
res.body.resume()
|
|
187
|
+
|
|
188
|
+
return false
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
async function downloadAndWriteGraphQL (logger, url, folder, name, generateImplementation) {
|
|
192
|
+
logger.debug(`Trying to download GraphQL schema from ${url}`)
|
|
193
|
+
const query = graphql.getIntrospectionQuery()
|
|
194
|
+
const res = await request(url, {
|
|
195
|
+
method: 'POST',
|
|
196
|
+
headers: {
|
|
197
|
+
'content-type': 'application/json'
|
|
198
|
+
},
|
|
199
|
+
body: JSON.stringify({
|
|
200
|
+
query
|
|
201
|
+
})
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
const text = await res.body.text()
|
|
205
|
+
|
|
206
|
+
if (res.statusCode !== 200) {
|
|
207
|
+
return false
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const { data: schema } = JSON.parse(text)
|
|
211
|
+
await writeGraphQLClient(folder, name, schema, url, generateImplementation)
|
|
212
|
+
return 'graphql'
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
async function readFromFileAndWrite (
|
|
216
|
+
logger,
|
|
217
|
+
file,
|
|
218
|
+
folder,
|
|
219
|
+
name,
|
|
220
|
+
generateImplementation,
|
|
221
|
+
typesOnly,
|
|
222
|
+
fullRequest,
|
|
223
|
+
fullResponse,
|
|
224
|
+
optionalHeaders,
|
|
225
|
+
validateResponse,
|
|
226
|
+
isFrontend,
|
|
227
|
+
language,
|
|
228
|
+
typesComment,
|
|
229
|
+
withCredentials,
|
|
230
|
+
propsOptional
|
|
231
|
+
) {
|
|
232
|
+
logger.info(`Trying to read schema from file ${file}`)
|
|
233
|
+
const text = await readFile(file, 'utf8')
|
|
234
|
+
// try OpenAPI first
|
|
235
|
+
try {
|
|
236
|
+
await writeOpenAPIClient(
|
|
237
|
+
folder,
|
|
238
|
+
name,
|
|
239
|
+
text,
|
|
240
|
+
generateImplementation,
|
|
241
|
+
typesOnly,
|
|
242
|
+
fullRequest,
|
|
243
|
+
fullResponse,
|
|
244
|
+
optionalHeaders,
|
|
245
|
+
validateResponse,
|
|
246
|
+
isFrontend,
|
|
247
|
+
language,
|
|
248
|
+
typesComment,
|
|
249
|
+
logger,
|
|
250
|
+
withCredentials,
|
|
251
|
+
propsOptional
|
|
252
|
+
)
|
|
253
|
+
return 'openapi'
|
|
254
|
+
} catch (err) {
|
|
255
|
+
logger.error(err, `Error parsing OpenAPI definition: "${err.message}". Trying with GraphQL`)
|
|
256
|
+
// try GraphQL
|
|
257
|
+
const schema = graphql.buildSchema(text)
|
|
258
|
+
const introspectionResult = graphql.introspectionFromSchema(schema)
|
|
259
|
+
|
|
260
|
+
// dummy URL
|
|
261
|
+
await writeGraphQLClient(folder, name, introspectionResult, 'http://localhost:3042/graphql', generateImplementation)
|
|
262
|
+
return 'graphql'
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
async function downloadAndProcess (options) {
|
|
266
|
+
const {
|
|
267
|
+
url,
|
|
268
|
+
name,
|
|
269
|
+
folder,
|
|
270
|
+
logger,
|
|
271
|
+
typesOnly,
|
|
272
|
+
fullRequest,
|
|
273
|
+
fullResponse,
|
|
274
|
+
optionalHeaders,
|
|
275
|
+
validateResponse,
|
|
276
|
+
isFrontend,
|
|
277
|
+
language,
|
|
278
|
+
type,
|
|
279
|
+
urlAuthHeaders,
|
|
280
|
+
typesComment,
|
|
281
|
+
withCredentials,
|
|
282
|
+
propsOptional,
|
|
283
|
+
retryTimeoutMs
|
|
284
|
+
} = options
|
|
285
|
+
|
|
286
|
+
const generateImplementation = options.generateImplementation
|
|
287
|
+
|
|
288
|
+
let found = false
|
|
289
|
+
const toTry = []
|
|
290
|
+
if (url.startsWith('http')) {
|
|
291
|
+
if (type === 'openapi') {
|
|
292
|
+
toTry.push(
|
|
293
|
+
downloadAndWriteOpenAPI.bind(
|
|
294
|
+
null,
|
|
295
|
+
logger,
|
|
296
|
+
url + '/documentation/json',
|
|
297
|
+
folder,
|
|
298
|
+
name,
|
|
299
|
+
generateImplementation,
|
|
300
|
+
typesOnly,
|
|
301
|
+
fullRequest,
|
|
302
|
+
fullResponse,
|
|
303
|
+
optionalHeaders,
|
|
304
|
+
validateResponse,
|
|
305
|
+
isFrontend,
|
|
306
|
+
language,
|
|
307
|
+
urlAuthHeaders,
|
|
308
|
+
typesComment,
|
|
309
|
+
withCredentials,
|
|
310
|
+
propsOptional,
|
|
311
|
+
retryTimeoutMs
|
|
312
|
+
)
|
|
313
|
+
)
|
|
314
|
+
toTry.push(
|
|
315
|
+
downloadAndWriteOpenAPI.bind(
|
|
316
|
+
null,
|
|
317
|
+
logger,
|
|
318
|
+
url,
|
|
319
|
+
folder,
|
|
320
|
+
name,
|
|
321
|
+
generateImplementation,
|
|
322
|
+
typesOnly,
|
|
323
|
+
fullRequest,
|
|
324
|
+
fullResponse,
|
|
325
|
+
optionalHeaders,
|
|
326
|
+
validateResponse,
|
|
327
|
+
isFrontend,
|
|
328
|
+
language,
|
|
329
|
+
urlAuthHeaders,
|
|
330
|
+
typesComment,
|
|
331
|
+
withCredentials,
|
|
332
|
+
propsOptional,
|
|
333
|
+
retryTimeoutMs
|
|
334
|
+
)
|
|
335
|
+
)
|
|
336
|
+
} else if (options.type === 'graphql') {
|
|
337
|
+
toTry.push(
|
|
338
|
+
downloadAndWriteGraphQL.bind(null, logger, url + '/graphql', folder, name, generateImplementation, typesOnly)
|
|
339
|
+
)
|
|
340
|
+
toTry.push(downloadAndWriteGraphQL.bind(null, logger, url, folder, name, generateImplementation, typesOnly))
|
|
341
|
+
} else {
|
|
342
|
+
// add download functions only if it's an URL
|
|
343
|
+
toTry.push(
|
|
344
|
+
downloadAndWriteOpenAPI.bind(
|
|
345
|
+
null,
|
|
346
|
+
logger,
|
|
347
|
+
url + '/documentation/json',
|
|
348
|
+
folder,
|
|
349
|
+
name,
|
|
350
|
+
generateImplementation,
|
|
351
|
+
typesOnly,
|
|
352
|
+
fullRequest,
|
|
353
|
+
fullResponse,
|
|
354
|
+
optionalHeaders,
|
|
355
|
+
validateResponse,
|
|
356
|
+
isFrontend,
|
|
357
|
+
language,
|
|
358
|
+
urlAuthHeaders,
|
|
359
|
+
typesComment,
|
|
360
|
+
withCredentials,
|
|
361
|
+
propsOptional,
|
|
362
|
+
retryTimeoutMs
|
|
363
|
+
)
|
|
364
|
+
)
|
|
365
|
+
toTry.push(
|
|
366
|
+
downloadAndWriteGraphQL.bind(null, logger, url + '/graphql', folder, name, generateImplementation, typesOnly)
|
|
367
|
+
)
|
|
368
|
+
toTry.push(
|
|
369
|
+
downloadAndWriteOpenAPI.bind(
|
|
370
|
+
null,
|
|
371
|
+
logger,
|
|
372
|
+
url,
|
|
373
|
+
folder,
|
|
374
|
+
name,
|
|
375
|
+
generateImplementation,
|
|
376
|
+
typesOnly,
|
|
377
|
+
fullRequest,
|
|
378
|
+
fullResponse,
|
|
379
|
+
optionalHeaders,
|
|
380
|
+
validateResponse,
|
|
381
|
+
isFrontend,
|
|
382
|
+
language,
|
|
383
|
+
urlAuthHeaders,
|
|
384
|
+
typesComment,
|
|
385
|
+
withCredentials,
|
|
386
|
+
propsOptional,
|
|
387
|
+
retryTimeoutMs
|
|
388
|
+
)
|
|
389
|
+
)
|
|
390
|
+
toTry.push(downloadAndWriteGraphQL.bind(null, logger, url, folder, name, generateImplementation, typesOnly))
|
|
391
|
+
}
|
|
392
|
+
} else {
|
|
393
|
+
// add readFromFileAndWrite to the functions only if it's not an URL
|
|
394
|
+
toTry.push(
|
|
395
|
+
readFromFileAndWrite.bind(
|
|
396
|
+
null,
|
|
397
|
+
logger,
|
|
398
|
+
url,
|
|
399
|
+
folder,
|
|
400
|
+
name,
|
|
401
|
+
generateImplementation,
|
|
402
|
+
typesOnly,
|
|
403
|
+
fullRequest,
|
|
404
|
+
fullResponse,
|
|
405
|
+
optionalHeaders,
|
|
406
|
+
validateResponse,
|
|
407
|
+
isFrontend,
|
|
408
|
+
language,
|
|
409
|
+
typesComment,
|
|
410
|
+
withCredentials,
|
|
411
|
+
propsOptional
|
|
412
|
+
)
|
|
413
|
+
)
|
|
414
|
+
}
|
|
415
|
+
for (const fn of toTry) {
|
|
416
|
+
found = await fn()
|
|
417
|
+
if (found) {
|
|
418
|
+
break
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
/* c8 ignore next 3 */
|
|
422
|
+
if (!found) {
|
|
423
|
+
throw new Error(`Could not find a valid OpenAPI or GraphQL schema at ${url}`)
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
function getPackageJSON ({ name, generateImplementation }) {
|
|
428
|
+
const obj = {
|
|
429
|
+
name,
|
|
430
|
+
types: `./${name}.d.ts`
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
if (generateImplementation) {
|
|
434
|
+
obj.main = `./${name}.js`
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
return JSON.stringify(obj, null, 2)
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
export async function command (argv) {
|
|
441
|
+
const help = helpMe({
|
|
442
|
+
dir: join(import.meta.dirname, 'help'),
|
|
443
|
+
// the default
|
|
444
|
+
ext: '.txt'
|
|
445
|
+
})
|
|
446
|
+
const {
|
|
447
|
+
_: [url],
|
|
448
|
+
...options
|
|
449
|
+
} = parseArgs(argv, {
|
|
450
|
+
string: ['name', 'folder', 'optional-headers', 'language', 'type', 'url-auth-headers', 'types-comment'],
|
|
451
|
+
boolean: [
|
|
452
|
+
'typescript',
|
|
453
|
+
'full-response',
|
|
454
|
+
'types-only',
|
|
455
|
+
'full-request',
|
|
456
|
+
'full',
|
|
457
|
+
'frontend',
|
|
458
|
+
'validate-response',
|
|
459
|
+
'props-optional',
|
|
460
|
+
'skip-config-update'
|
|
461
|
+
],
|
|
462
|
+
default: {
|
|
463
|
+
typescript: false,
|
|
464
|
+
language: 'js',
|
|
465
|
+
full: true
|
|
466
|
+
},
|
|
467
|
+
alias: {
|
|
468
|
+
n: 'name',
|
|
469
|
+
f: 'folder',
|
|
470
|
+
t: 'typescript',
|
|
471
|
+
c: 'config',
|
|
472
|
+
F: 'full',
|
|
473
|
+
h: 'help'
|
|
474
|
+
}
|
|
475
|
+
})
|
|
476
|
+
|
|
477
|
+
if (options.full || options.F) {
|
|
478
|
+
// force both fullRequest and fullResponse
|
|
479
|
+
options['full-request'] = true
|
|
480
|
+
options['full-response'] = true
|
|
481
|
+
}
|
|
482
|
+
const stream = pinoPretty({
|
|
483
|
+
translateTime: 'SYS:HH:MM:ss',
|
|
484
|
+
ignore: 'hostname,pid',
|
|
485
|
+
minimumLevel: 'debug',
|
|
486
|
+
sync: true
|
|
487
|
+
})
|
|
488
|
+
|
|
489
|
+
const logger = pino(stream)
|
|
490
|
+
|
|
491
|
+
if (!url || options.help) {
|
|
492
|
+
await help.toStdout()
|
|
493
|
+
process.exit(1)
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
try {
|
|
497
|
+
options.isFrontend = !!options.frontend
|
|
498
|
+
if (options['types-only']) {
|
|
499
|
+
options.generateImplementation = false
|
|
500
|
+
options.typesOnly = true
|
|
501
|
+
} else {
|
|
502
|
+
options.generateImplementation = options.isFrontend ? true : !options.config
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
options.fullRequest = options['full-request']
|
|
506
|
+
options.fullResponse = options['full-response']
|
|
507
|
+
options.propsOptional = options['props-optional'] ?? true
|
|
508
|
+
|
|
509
|
+
options.optionalHeaders = options['optional-headers']
|
|
510
|
+
? options['optional-headers'].split(',').map(h => h.trim())
|
|
511
|
+
: []
|
|
512
|
+
|
|
513
|
+
options.validateResponse = options['validate-response']
|
|
514
|
+
|
|
515
|
+
if (!options.name) {
|
|
516
|
+
options.name = options.isFrontend ? 'api' : 'client'
|
|
517
|
+
}
|
|
518
|
+
options.folder = options.folder || join(process.cwd(), options.name)
|
|
519
|
+
options.urlAuthHeaders = options['url-auth-headers']
|
|
520
|
+
options.typesComment = options['types-comment']
|
|
521
|
+
options.withCredentials = options['with-credentials']
|
|
522
|
+
options.skipConfigUpdate = options['skip-config-update'] ?? true
|
|
523
|
+
options.retryTimeoutMs = options['retry-timeout-ms']
|
|
524
|
+
await downloadAndProcess({ url, ...options, logger })
|
|
525
|
+
logger.info(`Client generated successfully into ${options.folder}`)
|
|
526
|
+
logger.info('Check out the docs to know more: https://docs.platformatic.dev/docs/service/overview')
|
|
527
|
+
} catch (err) {
|
|
528
|
+
logger.error(err.message)
|
|
529
|
+
process.exit(1)
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
if (import.meta.main) {
|
|
534
|
+
command(process.argv.slice(2))
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
export * as errors from './lib/errors.js'
|
package/index.test-d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { expectError, expectType } from 'tsd'
|
|
2
|
+
import { command, errors } from '.'
|
|
3
|
+
import { FastifyError } from '@fastify/error'
|
|
4
|
+
|
|
5
|
+
// command
|
|
6
|
+
expectType<Promise<void>>(command([]))
|
|
7
|
+
expectType<Promise<void>>(command(['foo', 'bar']))
|
|
8
|
+
expectError<Promise<void>>(command(false))
|
|
9
|
+
expectError<Promise<void>>(command([4, 2]))
|
|
10
|
+
|
|
11
|
+
// errors
|
|
12
|
+
expectType<FastifyError>(errors.TypeNotSupportedError('someType'))
|
|
13
|
+
expectType<FastifyError>(errors.UnknownTypeError('otherType'))
|
|
14
|
+
expectError<FastifyError>(errors.TypeNotSupportedError())
|
|
15
|
+
expectError<FastifyError>(errors.UnknownTypeError())
|
package/lib/errors.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import createError from '@fastify/error'
|
|
2
|
+
|
|
3
|
+
export const ERROR_PREFIX = 'PLT_MASSIMO_CLI'
|
|
4
|
+
|
|
5
|
+
export const UnknownTypeError = createError(`${ERROR_PREFIX}_UNKNOWN_TYPE`, 'Unknown type %s')
|
|
6
|
+
export const TypeNotSupportedError = createError(`${ERROR_PREFIX}_TYPE_NOT_SUPPORTED`, 'Type %s not supported')
|