@jsreport/jsreport-cli 3.0.0-beta.2 → 3.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.
Files changed (41) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +16 -12
  3. package/cli.js +93 -93
  4. package/example.config.json +43 -43
  5. package/example.server.js +14 -14
  6. package/index.js +20 -22
  7. package/jsreport.config.js +8 -8
  8. package/lib/cliExtension.js +59 -59
  9. package/lib/{createCommandParser.js → commander/createCommandParser.js} +44 -45
  10. package/lib/commander/createCustomCommandBuilder.js +150 -0
  11. package/lib/commander/createLogger.js +51 -0
  12. package/lib/commander/executeCommand.js +37 -0
  13. package/lib/commander/getCommandEventName.js +4 -0
  14. package/lib/commander/index.js +279 -0
  15. package/lib/commander/jsreportInstance.js +98 -0
  16. package/lib/commander/registerCommand.js +91 -0
  17. package/lib/commander/startCommand.js +234 -0
  18. package/lib/commander/startProcessing.js +208 -0
  19. package/lib/commands/_initializeApp.js +206 -208
  20. package/lib/commands/configure.js +393 -395
  21. package/lib/commands/help.js +453 -454
  22. package/lib/commands/init.js +76 -77
  23. package/lib/commands/kill.js +85 -86
  24. package/lib/commands/render.js +490 -488
  25. package/lib/commands/repair.js +55 -56
  26. package/lib/commands/start.js +72 -74
  27. package/lib/commands/win-install.js +124 -126
  28. package/lib/commands/win-uninstall.js +100 -102
  29. package/lib/daemonHandler.js +164 -164
  30. package/lib/daemonInstance.js +225 -225
  31. package/lib/{registerExtensionsCommands.js → detectAndRegisterExtensionsCommands.js} +74 -74
  32. package/lib/instanceHandler.js +316 -316
  33. package/lib/keepAliveProcess.js +205 -205
  34. package/lib/{errorUtils.js → utils/error.js} +149 -127
  35. package/lib/{getTempPaths.js → utils/getTempPaths.js} +39 -39
  36. package/lib/{normalizePathOptionOrArg.js → utils/normalizePathOptionOrArg.js} +41 -41
  37. package/lib/{normalizeSocketPath.js → utils/normalizeSocketPath.js} +9 -9
  38. package/lib/{startSocketServer.js → utils/startSocketServer.js} +53 -53
  39. package/package.json +105 -106
  40. package/test/testUtils.js +197 -198
  41. package/lib/commander.js +0 -1108
package/lib/commander.js DELETED
@@ -1,1108 +0,0 @@
1
- 'use strict'
2
-
3
- // eslint-disable-next-line no-var
4
- var semver = require('semver')
5
- // eslint-disable-next-line no-var
6
- var cliPackageJson = require('../package.json')
7
-
8
- if (!semver.satisfies(process.versions.node, cliPackageJson.engines.node)) {
9
- console.error(
10
- 'jsreport cli requires to have installed a nodejs version of at least ' +
11
- cliPackageJson.engines.node +
12
- ' but you have installed version ' + process.versions.node + '. please update your nodejs version and try again'
13
- )
14
-
15
- process.exit(1)
16
- }
17
-
18
- const events = require('events')
19
- const nanoid = require('nanoid')
20
- const isAbsoluteUrl = require('is-absolute-url')
21
- const yargs = require('yargs')
22
- const Yargs = require('yargs/yargs')
23
- const prompt = require('prompt-tmp')
24
- const packageJson = require('../package.json')
25
- const createCommandParser = require('./createCommandParser')
26
- const registerExtensionsCommands = require('./registerExtensionsCommands')
27
- const daemonHandler = require('./daemonHandler')
28
- const keepAliveProcess = require('./keepAliveProcess')
29
- const instanceHandler = require('./instanceHandler')
30
- const getTempPaths = require('./getTempPaths')
31
- const { printError } = require('./errorUtils')
32
- const helpCmd = require('./commands/help')
33
- const initCmd = require('./commands/init')
34
- const repairCmd = require('./commands/repair')
35
- const winInstallCmd = require('./commands/win-install')
36
- const winUninstallCmd = require('./commands/win-uninstall')
37
- const configureCmd = require('./commands/configure')
38
- const startCmd = require('./commands/start')
39
- const renderCmd = require('./commands/render')
40
- const killCmd = require('./commands/kill')
41
-
42
- let BUILT_IN_COMMAND_MODULES = {
43
- help: helpCmd,
44
- init: initCmd,
45
- repair: repairCmd,
46
- 'win-install': winInstallCmd,
47
- 'win-uninstall': winUninstallCmd,
48
- configure: configureCmd,
49
- start: startCmd,
50
- render: renderCmd,
51
- kill: killCmd
52
- }
53
-
54
- const AVAILABLE_GLOBAL_OPTIONS = {
55
- options: [
56
- 'context',
57
- 'verbose',
58
- // tempDirectory was added just for compatibility with jsreport.exe
59
- 'tempDirectory',
60
- 'serverUrl',
61
- 'user',
62
- 'password'
63
- ],
64
- alwaysGlobal: ['context', 'verbose', 'tempDirectory']
65
- }
66
-
67
- BUILT_IN_COMMAND_MODULES = Object.keys(BUILT_IN_COMMAND_MODULES).map((key) => BUILT_IN_COMMAND_MODULES[key])
68
-
69
- const tempPaths = getTempPaths()
70
- const CLI_PATH = tempPaths.cliPath
71
- const MAIN_SOCK_PATH = tempPaths.mainSockPath
72
- const WORKER_SOCK_PATH = tempPaths.workerSockPath
73
-
74
- tempPaths.createPaths()
75
-
76
- class Commander extends events.EventEmitter {
77
- constructor (cwd, options = {}) {
78
- super()
79
-
80
- let cliHandler
81
-
82
- events.EventEmitter.call(this)
83
-
84
- this.cwd = cwd || process.cwd()
85
-
86
- this.execution = options.execution
87
-
88
- this.context = {
89
- cwd: this.cwd,
90
- sockPath: MAIN_SOCK_PATH,
91
- workerSockPath: WORKER_SOCK_PATH,
92
- staticPaths: options.staticPaths || {},
93
- daemonHandler,
94
- keepAliveProcess,
95
- appInfo: options.appInfo
96
- }
97
-
98
- if (this.execution) {
99
- if (!this.context.staticPaths.nssm) {
100
- this.context.staticPaths.nssm = process.arch === 'x64' ? this.execution.resourceTempPath('nssm64.exe') : this.execution.resourceTempPath('nssm.exe')
101
- }
102
- }
103
-
104
- this._commands = {}
105
- this._commandHandlers = {}
106
- this._commandNames = []
107
- this._commandsConfig = {}
108
-
109
- if (options.builtInCommands) {
110
- this._builtInCommands = options.builtInCommands
111
- } else {
112
- this._builtInCommands = BUILT_IN_COMMAND_MODULES
113
- }
114
-
115
- if (options.disabledCommands) {
116
- this._disabledCommands = options.disabledCommands
117
- } else {
118
- this._disabledCommands = []
119
- }
120
-
121
- this._builtInCommandNames = this._builtInCommands.map((cmdModule) => cmdModule.command)
122
-
123
- this._showHelpWhenNoCommand = options.showHelpWhenNoCommand != null ? Boolean(options.showHelpWhenNoCommand) : true
124
-
125
- // this option tell us that we should use this value as the instance
126
- // and not try to look up for it
127
- this._jsreportInstance = options.instance
128
-
129
- // reference to the jsreport instance initiated, this variable will be set
130
- // when the CLI has initialized a jsreport instance successfully
131
- this.jsreportInstanceInitiated = null
132
-
133
- // this option tell us that we should use this value as the instance version
134
- // and not try to look up for it
135
- this._jsreportVersion = options.jsreportVersion
136
-
137
- // this option tell us that we should use this path as the executable
138
- // to spawn when we need to use a daemonized process
139
- this._daemonExecPath = options.daemonExecPath
140
-
141
- // optional path to script being run in the daemonized process
142
- this._daemonExecScriptPath = options.daemonExecScriptPath
143
-
144
- // this option tell us that we should additionally pass this arguments
145
- // to the executable when we need to use a daemonized process
146
- this._daemonExecArgs = options.daemonExecArgs
147
-
148
- // this option tell us that we should additionally pass this options
149
- // to child_process.spawn when we need to use a daemonized process
150
- this._daemonExecOpts = options.daemonExecOpts
151
-
152
- if (this.execution) {
153
- if (this._daemonExecOpts == null || this._daemonExecOpts.WinRunPath == null) {
154
- this._daemonExecOpts = this._daemonExecOpts || {}
155
- this._daemonExecOpts.WinRunPath = this.execution.resourceTempPath('WinRun.exe')
156
- }
157
- }
158
-
159
- // lazy initialization of cli handler, commands will be activated when
160
- // doing cliHandler.parse()
161
- if (options.cli) {
162
- cliHandler = createCommandParser(options.cli, options.cliName)
163
- } else {
164
- cliHandler = (
165
- createCommandParser(undefined, options.cliName)
166
- .option('verbose', {
167
- global: false,
168
- alias: 'b',
169
- description: 'Enables verbose mode',
170
- type: 'boolean'
171
- })
172
- .option('tempDirectory', {
173
- global: false,
174
- description: 'Specifies the temp directory that will be used to store temp files and resources',
175
- type: 'string'
176
- })
177
- .option('serverUrl', {
178
- global: false,
179
- alias: 's',
180
- description: 'Specifies a url to a remote jsreport server, that server will be the target of the command (only if command support this mode)',
181
- type: 'string',
182
- requiresArg: true,
183
- coerce: (value) => {
184
- if (!isAbsoluteUrl(value)) {
185
- const error = new Error('serverUrl option must be a valid absolute url')
186
- error.cleanState = true
187
- throw error
188
- }
189
-
190
- return value
191
- }
192
- })
193
- .option('user', {
194
- global: false,
195
- alias: 'u',
196
- description: 'Specifies a username for authentication against a jsreport server (Use if some command needs authentication information)',
197
- type: 'string',
198
- requiresArg: true
199
- })
200
- .option('password', {
201
- global: false,
202
- alias: 'p',
203
- description: 'Specifies a password for authentication against a jsreport server (Use if some command needs authentication information)'
204
- })
205
- .strict()
206
- )
207
- }
208
-
209
- this._cli = cliHandler
210
-
211
- this.cliName = this._cli.$0
212
-
213
- // registering built-in commands
214
- this._builtInCommands.forEach((commandModule) => this.registerCommand(commandModule))
215
-
216
- setImmediate(() => this.emit('initialized'))
217
-
218
- return this
219
- }
220
-
221
- getCommands () {
222
- return this._commandNames
223
- }
224
-
225
- async executeCommand (commandName, argv) {
226
- const command = this._commands[commandName]
227
-
228
- if (!command) {
229
- throw new Error('"' + commandName + '" command is not a valid command')
230
- }
231
-
232
- if (typeof command.handler !== 'function') {
233
- throw new Error('"' + commandName + '" command doesn\'t have a valid handler')
234
- }
235
-
236
- const commandHandler = command.handler
237
-
238
- this.emit('command.init', commandName, argv)
239
- this.emit(getCommandEventName(commandName, 'init'), argv)
240
-
241
- let resolveValue
242
-
243
- try {
244
- resolveValue = await commandHandler(argv)
245
- this.emit('command.success', commandName, resolveValue)
246
- this.emit(getCommandEventName(commandName, 'success'), resolveValue)
247
-
248
- return resolveValue
249
- } catch (errorInCommand) {
250
- this.emit('command.error', commandName, errorInCommand)
251
- this.emit(getCommandEventName(commandName, 'error'), errorInCommand)
252
- // propagating error
253
- throw errorInCommand
254
- } finally {
255
- this.emit('command.finish', commandName)
256
- this.emit(getCommandEventName(commandName, 'finish'))
257
- }
258
- }
259
-
260
- registerCommand (commandModule) {
261
- const commandBuilder = commandModule.builder || ((yargs) => (yargs))
262
- const commandConfiguration = Object.assign({}, commandModule.configuration)
263
- let commandGlobalOptions = Object.assign([], commandConfiguration.globalOptions)
264
-
265
- if (typeof commandModule.command !== 'string' || !commandModule.command) {
266
- throw new Error('command module must have a .command property of type string')
267
- }
268
-
269
- // we do this because .command can include positional arguments like "command <regiredArg> [optionalArg]"
270
- const commandName = commandModule.command.split(' ')[0].trim()
271
-
272
- if (typeof commandModule.description !== 'string') {
273
- throw new Error('command module must have a .description property of type string')
274
- }
275
-
276
- if (typeof commandModule.handler !== 'function') {
277
- throw new Error('command module must have a .handler property of type function')
278
- }
279
-
280
- if (commandBuilder != null && typeof commandBuilder !== 'function') {
281
- throw new Error('command module .builder property must be a function')
282
- }
283
-
284
- if (this._disabledCommands.indexOf(commandName) !== -1) {
285
- return
286
- }
287
-
288
- if (commandGlobalOptions) {
289
- commandGlobalOptions = commandGlobalOptions.map((opt) => {
290
- if (AVAILABLE_GLOBAL_OPTIONS.options.indexOf(opt) === -1) {
291
- return null
292
- }
293
-
294
- return opt
295
- })
296
-
297
- // removing invalid options
298
- commandGlobalOptions.filter(Boolean)
299
-
300
- // always add some options to global
301
- AVAILABLE_GLOBAL_OPTIONS.alwaysGlobal.forEach((opt) => {
302
- if (commandGlobalOptions.indexOf(opt) === -1) {
303
- commandGlobalOptions.unshift(opt)
304
- }
305
- })
306
- } else {
307
- // always add some options to global
308
- commandGlobalOptions = AVAILABLE_GLOBAL_OPTIONS.alwaysGlobal
309
- }
310
-
311
- commandConfiguration.globalOptions = commandGlobalOptions
312
-
313
- // wrapping builder to allow some customizations
314
- const newBuilder = (yargs) => {
315
- const commandConfig = this._commandsConfig[commandName]
316
- let shouldGenerateUsage = true
317
- let originalUsageFn
318
- let originalCheckFn
319
- let originalOptionFn
320
- let originalOptionsFn
321
- let commandCheckFn
322
-
323
- if (typeof yargs.usage === 'function') {
324
- originalUsageFn = yargs.usage
325
-
326
- // we expose .usage but just for the message case
327
- yargs.usage = (msg) => {
328
- shouldGenerateUsage = false
329
- return originalUsageFn.apply(yargs, [msg])
330
- }
331
- }
332
-
333
- if (typeof yargs.check === 'function') {
334
- originalCheckFn = yargs.check
335
-
336
- yargs.check = (fn) => {
337
- commandCheckFn = fn
338
- return yargs
339
- }
340
- }
341
-
342
- if (typeof yargs.option === 'function') {
343
- originalOptionFn = yargs.option
344
-
345
- // default options to be global: false
346
- yargs.option = (key, opt) => {
347
- if (opt && opt.global == null) {
348
- opt.global = false
349
- }
350
-
351
- return originalOptionFn.apply(yargs, [key, opt])
352
- }
353
- }
354
-
355
- if (typeof yargs.options === 'function') {
356
- originalOptionsFn = yargs.options
357
-
358
- // default options to be global: false
359
- yargs.options = (keyOrOpts, opt) => {
360
- if (keyOrOpts && opt == null) {
361
- Object.entries(keyOrOpts).forEach(([key, keyConf]) => {
362
- if (keyConf && keyConf.global == null) {
363
- keyConf.global = false
364
- }
365
- })
366
- }
367
-
368
- if (opt && opt.global == null) {
369
- opt.global = false
370
- }
371
-
372
- return originalOptionFn.apply(yargs, [keyOrOpts, opt])
373
- }
374
- }
375
-
376
- const modYargs = commandBuilder(yargs)
377
-
378
- if (typeof yargs.usage === 'function') {
379
- yargs.usage = originalUsageFn
380
- modYargs.usage = originalUsageFn
381
-
382
- if (shouldGenerateUsage) {
383
- modYargs.usage(commandModule.description + '\n\nUsage:\n\njsreport ' + commandName)
384
- }
385
- }
386
-
387
- if (typeof yargs.check === 'function') {
388
- yargs.check = originalCheckFn
389
- modYargs.check = originalCheckFn
390
- }
391
-
392
- if (typeof yargs.option === 'function') {
393
- yargs.option = originalOptionFn
394
- modYargs.option = originalOptionFn
395
- }
396
-
397
- if (typeof yargs.options === 'function') {
398
- yargs.options = originalOptionsFn
399
- modYargs.options = originalOptionsFn
400
- }
401
-
402
- modYargs.check((...args) => {
403
- const argv = args[0]
404
- const commandConfig = this._commandsConfig[commandName]
405
-
406
- const unsupportedGlobalOptions = AVAILABLE_GLOBAL_OPTIONS.options.filter((opt) => {
407
- return commandConfig.globalOptions.indexOf(opt) === -1
408
- })
409
-
410
- unsupportedGlobalOptions.forEach((opt) => {
411
- if (argv[opt]) {
412
- throw new Error(opt + ' global option is not supported in this command')
413
- }
414
- })
415
-
416
- if (commandCheckFn) {
417
- return commandCheckFn.apply(undefined, args)
418
- }
419
-
420
- return true
421
- }, false)
422
-
423
- if (typeof modYargs.fail === 'function') {
424
- // making command strict and registering a generalized fail function
425
- modYargs.fail((msg, err) => {
426
- // do nothing when error comes from command promise itself,
427
- // the propagation of error will be done automatically by promise chain
428
- if (msg == null) {
429
- return
430
- }
431
-
432
- this.emit('command.error', commandName, err)
433
- this.emit(getCommandEventName(commandName, 'error'), err)
434
-
435
- const defaultErr = new Error(`${commandName} command error:\n${msg}\ntype jsreport ${commandName} -h to get help about usage and available options`)
436
-
437
- defaultErr.cleanState = true
438
-
439
- throw defaultErr
440
- })
441
- }
442
-
443
- if (commandConfig.disableStrictOptions !== true) {
444
- modYargs.strict()
445
- } else {
446
- modYargs.strict(false)
447
- }
448
-
449
- return modYargs
450
- }
451
-
452
- const bindedHandler = this.executeCommand.bind(this, commandName)
453
-
454
- this._commandsConfig[commandName] = commandConfiguration
455
-
456
- const commandHandler = Object.assign({}, commandModule, {
457
- builder: newBuilder,
458
- handler: (argv) => {
459
- const commandConfig = this._commandsConfig[commandName]
460
- const disableExit = commandConfig.disableProcessExit === true
461
-
462
- const commandPromise = bindedHandler(argv)
463
- .then(() => {
464
- return undefined
465
- })
466
- .catch(function (err) {
467
- err.disableExit = disableExit
468
- throw err
469
- })
470
-
471
- argv.commandPromise = commandPromise
472
-
473
- return commandPromise
474
- }
475
- })
476
-
477
- this._cli.command(commandHandler)
478
-
479
- this._commands[commandName] = commandModule
480
- this._commandHandlers[commandName] = commandHandler
481
- this._commandNames.push(commandName)
482
-
483
- this.emit('command.register', commandName, commandModule)
484
-
485
- return this
486
- }
487
-
488
- start (args) {
489
- const verboseMode = args.includes('--verbose') || args.includes('-b')
490
- const { logger } = createLogger(verboseMode)
491
-
492
- startProccesing(this, logger, args).then((resultInfo) => {
493
- const commandHandled = resultInfo != null ? resultInfo.command : undefined
494
- const disableExit = commandHandled != null && this._commandsConfig[commandHandled] ? this._commandsConfig[commandHandled].disableProcessExit === true : false
495
-
496
- if (disableExit !== true) {
497
- process.exit(0)
498
- }
499
- }).catch((err) => {
500
- if (err.exitDirectly) {
501
- return process.exit(1)
502
- }
503
-
504
- printError(err, logger)
505
-
506
- if (err.disabledExit !== true) {
507
- process.exit(1)
508
- }
509
- })
510
- }
511
-
512
- async startAndWait (args) {
513
- const verboseMode = args != null && (args.includes('--verbose') || args.includes('-b'))
514
- const { logger, getLogs } = createLogger(verboseMode)
515
- let error
516
-
517
- try {
518
- await startProccesing(this, logger, args)
519
- } catch (e) {
520
- error = e
521
-
522
- if (e.exitDirectly !== true) {
523
- printError(e, logger)
524
- }
525
- }
526
-
527
- const logs = getLogs()
528
-
529
- return { error, logs }
530
- }
531
- }
532
-
533
- module.exports = (cwd, options = {}) => new Commander(cwd, options)
534
-
535
- module.exports.cliPath = CLI_PATH
536
- module.exports.mainSockPath = MAIN_SOCK_PATH
537
- module.exports.workerSockPath = WORKER_SOCK_PATH
538
-
539
- function createLogger (verboseMode) {
540
- const logs = []
541
-
542
- const logger = {
543
- debug: (...messages) => {
544
- const msg = messages.join(' ')
545
-
546
- if (verboseMode) {
547
- logs.push({
548
- type: 'debug',
549
- message: msg
550
- })
551
-
552
- console.log(...messages)
553
- }
554
- },
555
- info: (...messages) => {
556
- const msg = messages.join(' ')
557
-
558
- logs.push({
559
- type: 'info',
560
- message: msg
561
- })
562
-
563
- console.log(...messages)
564
- },
565
- warn: (...messages) => {
566
- const msg = messages.join(' ')
567
-
568
- logs.push({
569
- type: 'warn',
570
- message: msg
571
- })
572
-
573
- console.error(...messages)
574
- },
575
- error: (...messages) => {
576
- const msg = messages.join(' ')
577
-
578
- logs.push({
579
- type: 'error',
580
- message: msg
581
- })
582
-
583
- console.error(...messages)
584
- }
585
- }
586
-
587
- return { logger, getLogs: () => logs }
588
- }
589
-
590
- async function startProccesing (commander, logger, args) {
591
- process.env.JSREPORT_CLI = true
592
-
593
- if (!Array.isArray(args) && typeof args !== 'string') {
594
- throw new Error('args must be an array or string')
595
- }
596
-
597
- commander.emit('starting')
598
-
599
- const userArgv = yargs([]).help(false).version(false).parse(args)
600
-
601
- const versionRequired = userArgv.version || userArgv.v
602
- const helpRequired = userArgv.help || userArgv.h
603
- const needsPassword = userArgv.password || userArgv.p
604
- const verboseMode = userArgv.verbose || userArgv.b
605
-
606
- if (userArgv._.length === 0) {
607
- const willShowHelpExplicitly = commander._showHelpWhenNoCommand && !versionRequired && !helpRequired
608
-
609
- commander.emit('started', null, { handled: versionRequired || helpRequired || willShowHelpExplicitly, mainCommand: null })
610
-
611
- commander.emit('parsing', args, commander.context)
612
-
613
- let instance
614
-
615
- try {
616
- instance = await getInstance(commander, commander._jsreportInstance, () => {}, commander.cwd)
617
- } catch (e) {}
618
-
619
- if (instance && (helpRequired || willShowHelpExplicitly)) {
620
- await findAndLoadExtensionsCommands(instance, commander, verboseMode)
621
- }
622
-
623
- let parsed = false
624
-
625
- // activating CLI
626
- try {
627
- let output = await new Promise((resolve, reject) => {
628
- commander._cli.parse(args, (error, argv, output) => {
629
- if (error) {
630
- if (output != null && output !== '') {
631
- logger.error(output)
632
- }
633
-
634
- error.exitDirectly = true
635
-
636
- return reject(error)
637
- }
638
-
639
- resolve(output)
640
- })
641
- })
642
-
643
- commander.emit('parsed', null, args, commander.context)
644
-
645
- parsed = true
646
-
647
- if (versionRequired) {
648
- return handleVersionOption(
649
- commander._jsreportVersion
650
- ? {
651
- version: commander._jsreportVersion
652
- }
653
- : (typeof instance === 'function' ? instance() : instance),
654
- logger
655
- )
656
- }
657
-
658
- if (
659
- willShowHelpExplicitly &&
660
- !args.includes('--help') &&
661
- !args.includes('-h')
662
- ) {
663
- output = await new Promise((resolve, reject) => {
664
- const newArgs = [...args, '--help']
665
-
666
- commander._cli.parse(newArgs, (error, argv, output) => {
667
- if (error) {
668
- return reject(error)
669
- }
670
-
671
- resolve(output)
672
- })
673
- })
674
- }
675
-
676
- if (output != null && output !== '') {
677
- logger.info(output)
678
- }
679
- } catch (e) {
680
- if (!parsed) {
681
- commander.emit('parsed', e, args, commander.context)
682
- }
683
-
684
- throw e
685
- }
686
-
687
- return
688
- }
689
-
690
- const mainCommandReceived = userArgv._[0]
691
-
692
- const startInmediatly = (
693
- // if command is built-in and version or help options is activated
694
- (commander._builtInCommandNames.indexOf(mainCommandReceived) !== -1 && (versionRequired || helpRequired))
695
- )
696
-
697
- const optionsForStart = {
698
- startInmediatly,
699
- logger,
700
- verbose: verboseMode
701
- }
702
-
703
- const commandConfiguration = commander._commandsConfig[mainCommandReceived] || {}
704
-
705
- let beforeCLIParseCbCalled = false
706
-
707
- const onBeforeCLIParse = (err) => {
708
- if (beforeCLIParseCbCalled) {
709
- return
710
- }
711
-
712
- beforeCLIParseCbCalled = true
713
-
714
- const isSupportedCommand = commander._commandNames.indexOf(mainCommandReceived) !== -1
715
-
716
- if (err) {
717
- return commander.emit('started', err, null)
718
- }
719
-
720
- commander.emit('started', null, {
721
- handled: isSupportedCommand || versionRequired || (isSupportedCommand && helpRequired),
722
- mainCommand: mainCommandReceived
723
- })
724
- }
725
-
726
- if (
727
- needsPassword &&
728
- commandConfiguration.globalOptions &&
729
- commandConfiguration.globalOptions.indexOf('password') !== -1
730
- ) {
731
- if (typeof needsPassword === 'string') {
732
- // we add middleware to pre-define the "p/password" option to
733
- commander._cli.middleware((argv) => {
734
- argv.p = needsPassword
735
- argv.password = needsPassword
736
- }, true)
737
- } else {
738
- await new Promise((resolve, reject) => {
739
- prompt.start()
740
-
741
- prompt.message = ''
742
-
743
- prompt.get([{
744
- name: 'password',
745
- description: 'Password',
746
- message: 'Password can\'t be empty',
747
- type: 'string',
748
- hidden: true,
749
- required: true
750
- }], (err, result) => {
751
- if (err) {
752
- const errorToReject = new Error('No value for password option')
753
- errorToReject.cleanState = true
754
-
755
- commander.emit('started', errorToReject, null)
756
-
757
- return reject(errorToReject)
758
- }
759
-
760
- // we add middleware to pre-define the "p/password" option to
761
- commander._cli.middleware((argv) => {
762
- argv.p = result.password
763
- argv.password = result.password
764
- }, true)
765
-
766
- resolve()
767
- })
768
- })
769
- }
770
- }
771
-
772
- await handleCommand(commander, mainCommandReceived, args, optionsForStart, onBeforeCLIParse)
773
-
774
- return { command: mainCommandReceived }
775
- }
776
-
777
- // check the command to see if we should handle jsreport instance
778
- // initialization first or just delegate the command to cli handler
779
- async function handleCommand (commander, commandName, args, options, onBeforeCLIParse) {
780
- const logger = options.logger
781
- const verbose = options.verbose
782
- // creating a new context based on properties of commander's context
783
- const context = Object.assign({}, commander.context)
784
- const startInmediatly = options.startInmediatly === true || commander._commands[commandName] != null
785
-
786
- // we need to handle the help option directly since there is a conflict
787
- // in yargs when a custom command is called the same that the option used in .help()
788
- // (that option registers an implicit command with the same name that the option passed)
789
- if (commandName === 'help') {
790
- // disable the implicit help command when the main command to execute is "help",
791
- // this allows our custom command to run
792
- commander._cli.help(false)
793
- }
794
-
795
- context.logger = logger
796
-
797
- context.getCommandHelp = async (command) => {
798
- let customYargs
799
- let out
800
-
801
- if (!commander._commands[command]) {
802
- let instance
803
-
804
- try {
805
- const instanceOrFn = await context.getInstance()
806
- instance = typeof instanceOrFn === 'function' ? instanceOrFn() : instanceOrFn
807
- } catch (e) {}
808
-
809
- if (instance) {
810
- await findAndLoadExtensionsCommands(instance, commander, verbose)
811
- }
812
- }
813
-
814
- const commandHandler = commander._commandHandlers[command]
815
-
816
- if (commandHandler) {
817
- customYargs = createCommandParser(Yargs([]), commander.cliName).command(commandHandler)
818
- }
819
-
820
- if (customYargs) {
821
- let helpArg = '-h'
822
-
823
- if (commandName === 'help') {
824
- const randomHelpArg = nanoid(5)
825
- customYargs.help(randomHelpArg).hide(randomHelpArg)
826
- helpArg = randomHelpArg
827
- }
828
-
829
- parseCLI(customYargs, [command, helpArg], context, (err, result) => {
830
- if (err) {
831
- throw err
832
- }
833
-
834
- out = result
835
- })
836
- } else {
837
- const error = new Error(`"${command}" command not available to inspect information, to get the list of commands supported on your installation run "jsreport -h" and try again with a supported command`)
838
- error.cleanState = true
839
- error.notFound = true
840
- throw error
841
- }
842
-
843
- return out
844
- }
845
-
846
- if (commander._daemonExecPath || commander._daemonExecArgs || commander._daemonExecOpts || commander._daemonExecScriptPath) {
847
- context.daemonExec = {}
848
-
849
- if (commander._daemonExecPath) {
850
- context.daemonExec.path = commander._daemonExecPath
851
- }
852
-
853
- if (commander._daemonExecArgs) {
854
- context.daemonExec.args = commander._daemonExecArgs
855
- }
856
-
857
- if (commander._daemonExecOpts) {
858
- context.daemonExec.opts = commander._daemonExecOpts
859
- }
860
-
861
- if (commander._daemonExecScriptPath) {
862
- context.daemonExec.scriptPath = commander._daemonExecScriptPath
863
- }
864
- }
865
-
866
- if (startInmediatly) {
867
- // passing getInstance and initInstance as context
868
- // to commands when they should ignore the entry point
869
- context.getInstance = getInstance(commander, commander._jsreportInstance, logger.debug)
870
- context.initInstance = initInstance(commander, verbose)
871
-
872
- throwIfCommandIsNotValid(commander, context, commandName, onBeforeCLIParse)
873
-
874
- const commandConfig = commander._commandsConfig[commandName]
875
-
876
- if (commandConfig && commandConfig.globalOptions) {
877
- commandConfig.globalOptions.forEach((optName) => {
878
- commander._cli.global(optName)
879
- })
880
- }
881
-
882
- onBeforeCLIParse()
883
-
884
- // delegating the command to the CLI and activating it
885
- await startCLI(logger, commander, args, context)
886
-
887
- return
888
- }
889
-
890
- // at this point command was not found so we need to get jsreport instance and
891
- // read extensions and look if any of those define the command
892
- try {
893
- logger.debug(`Searching for command "${commandName}" in extensions`)
894
-
895
- const getInstanceAsync = commander._jsreportInstance
896
- ? (
897
- Promise.resolve(commander._jsreportInstance)
898
- )
899
- : getInstance(commander, null, logger.debug, commander.cwd)
900
-
901
- const instanceOrFn = await getInstanceAsync
902
- const instance = typeof instanceOrFn === 'function' ? instanceOrFn() : instanceOrFn
903
-
904
- context.getInstance = getInstance(commander, instance, logger.debug)
905
- context.initInstance = initInstance(commander, verbose)
906
-
907
- await findAndLoadExtensionsCommands(instance, commander, verbose)
908
-
909
- throwIfCommandIsNotValid(commander, context, commandName, onBeforeCLIParse)
910
-
911
- const commandConfig = commander._commandsConfig[commandName]
912
-
913
- if (commandConfig && commandConfig.globalOptions) {
914
- commandConfig.globalOptions.forEach((optName) => {
915
- commander._cli.global(optName)
916
- })
917
- }
918
-
919
- onBeforeCLIParse()
920
- } catch (e) {
921
- onBeforeCLIParse(e)
922
- throw e
923
- }
924
-
925
- await startCLI(logger, commander, args, context)
926
- }
927
-
928
- async function startCLI (logger, commander, args, context) {
929
- const cli = commander._cli
930
-
931
- await new Promise((resolve, reject) => {
932
- try {
933
- commander.emit('parsing', args, context)
934
-
935
- parseCLI(cli, args, context, (error, { argv, context, output }) => {
936
- if (error) {
937
- commander.emit('parsed', error, args, context)
938
-
939
- if (output != null && output !== '') {
940
- logger.error(output)
941
- }
942
-
943
- error.exitDirectly = true
944
-
945
- return reject(error)
946
- }
947
-
948
- commander.emit('parsed', null, args, context)
949
-
950
- if (output != null && output !== '') {
951
- logger.info(output)
952
- }
953
-
954
- if (argv.commandPromise && typeof argv.commandPromise.then === 'function') {
955
- resolve(argv.commandPromise)
956
- } else {
957
- resolve()
958
- }
959
- })
960
- } catch (e) {
961
- commander.emit('parsed', e, args, context)
962
-
963
- const error = new Error('An error ocurred while trying to execute a command')
964
- error.originalError = e
965
-
966
- throw error
967
- }
968
- })
969
- }
970
-
971
- function parseCLI (cli, args, context, cb) {
972
- cli.parse(args, { context }, (error, argv, output) => {
973
- if (error) {
974
- cb(error, { args, context, output })
975
- return
976
- }
977
-
978
- cb(null, { args, argv, context, output })
979
- })
980
- }
981
-
982
- function getInstance (commander, prevInstance, log, cwd) {
983
- const args = Array.prototype.slice.call(arguments)
984
-
985
- if (args.length === 3) {
986
- return _getInstance_.bind(undefined, commander, prevInstance, log)
987
- }
988
-
989
- return _getInstance_(commander, prevInstance, log, cwd)
990
-
991
- function _getInstance_ (commander, prevInstance, log, cwd) {
992
- if (prevInstance) {
993
- log('using jsreport instance passed from options')
994
-
995
- return Promise.resolve(prevInstance)
996
- }
997
-
998
- commander.emit('instance.lookup')
999
-
1000
- if (cwd == null) {
1001
- cwd = commander.cwd
1002
- }
1003
-
1004
- return (
1005
- instanceHandler
1006
- .find(cwd)
1007
- .then((instanceInfo) => {
1008
- if (instanceInfo.isDefault) {
1009
- commander.emit('instance.default', instanceInfo.instance)
1010
-
1011
- log(
1012
- 'no entry point was found, creating a default instance ' +
1013
- 'using: require("' + instanceInfo.from + '")()'
1014
- )
1015
- } else {
1016
- commander.emit('instance.found', instanceInfo.instance)
1017
-
1018
- log('using jsreport instance found in: ' + instanceInfo.entryPoint)
1019
- }
1020
-
1021
- return instanceInfo.instance
1022
- })
1023
- )
1024
- }
1025
- }
1026
-
1027
- function initInstance (commander, verbose, instance) {
1028
- const args = Array.prototype.slice.call(arguments)
1029
-
1030
- if (args.length === 2) {
1031
- return _initInstance_.bind(undefined, commander, verbose)
1032
- }
1033
-
1034
- return _initInstance_(commander, verbose, instance)
1035
-
1036
- function _initInstance_ (commander, verbose, instance, forceVerbose) {
1037
- let verboseMode = verbose
1038
-
1039
- commander.emit('instance.initializing')
1040
-
1041
- if (forceVerbose === true) {
1042
- verboseMode = forceVerbose
1043
- }
1044
-
1045
- return (
1046
- instanceHandler.initialize(instance, verboseMode)
1047
- .then((result) => {
1048
- commander.jsreportInstanceInitiated = instance
1049
-
1050
- commander.emit('instance.initialized', result)
1051
-
1052
- return result
1053
- })
1054
- )
1055
- }
1056
- }
1057
-
1058
- async function findAndLoadExtensionsCommands (instance, commander, verbose) {
1059
- if (!instance || !instance.extensionsLoad) {
1060
- return
1061
- }
1062
-
1063
- if (!verbose) {
1064
- if (instance.options.logger) {
1065
- instance.options.logger.silent = true
1066
- } else {
1067
- instance.options.logger = {
1068
- silent: true
1069
- }
1070
- }
1071
- }
1072
-
1073
- await instance.extensionsLoad({ onlyLocation: true })
1074
-
1075
- await registerExtensionsCommands(instance.extensionsManager.extensions, commander)
1076
- }
1077
-
1078
- function getCommandEventName (command, event) {
1079
- return 'command' + '.' + command + '.' + event
1080
- }
1081
-
1082
- function handleVersionOption (instance, logger) {
1083
- let versionOutput = 'cli version: ' + packageJson.version
1084
-
1085
- if (instance) {
1086
- versionOutput = 'jsreport version: ' + instance.version + '\n' + versionOutput
1087
- }
1088
-
1089
- logger.info(versionOutput)
1090
- }
1091
-
1092
- function throwIfCommandIsNotValid (commander, context, commandName, onBeforeThrow) {
1093
- if (!commander._commands[commandName]) {
1094
- const error = new Error(
1095
- '"' + commandName + '" command not found in this installation, ' +
1096
- 'check that you are writing the command correctly or check if the command ' +
1097
- 'is available in your installation, use "jsreport -h" to see the list of available commands'
1098
- )
1099
-
1100
- error.cleanState = true
1101
-
1102
- if (onBeforeThrow) {
1103
- onBeforeThrow(error)
1104
- }
1105
-
1106
- throw error
1107
- }
1108
- }