@jsreport/jsreport-cli 3.0.0 → 3.1.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 (35) hide show
  1. package/README.md +13 -1
  2. package/cli.js +3 -3
  3. package/index.js +0 -2
  4. package/lib/cliExtension.js +2 -2
  5. package/lib/{createCommandParser.js → commander/createCommandParser.js} +2 -3
  6. package/lib/commander/createCustomCommandBuilder.js +150 -0
  7. package/lib/commander/createLogger.js +51 -0
  8. package/lib/commander/executeCommand.js +37 -0
  9. package/lib/commander/getCommandEventName.js +4 -0
  10. package/lib/commander/index.js +279 -0
  11. package/lib/commander/jsreportInstance.js +98 -0
  12. package/lib/commander/registerCommand.js +91 -0
  13. package/lib/commander/startCommand.js +234 -0
  14. package/lib/commander/startProcessing.js +208 -0
  15. package/lib/commands/_initializeApp.js +0 -2
  16. package/lib/commands/configure.js +1 -3
  17. package/lib/commands/help.js +7 -8
  18. package/lib/commands/init.js +4 -5
  19. package/lib/commands/kill.js +4 -5
  20. package/lib/commands/render.js +37 -35
  21. package/lib/commands/repair.js +4 -5
  22. package/lib/commands/start.js +0 -2
  23. package/lib/commands/win-install.js +0 -2
  24. package/lib/commands/win-uninstall.js +0 -2
  25. package/lib/daemonHandler.js +2 -2
  26. package/lib/daemonInstance.js +5 -5
  27. package/lib/{registerExtensionsCommands.js → detectAndRegisterExtensionsCommands.js} +1 -1
  28. package/lib/keepAliveProcess.js +3 -3
  29. package/lib/{errorUtils.js → utils/error.js} +23 -1
  30. package/lib/{getTempPaths.js → utils/getTempPaths.js} +0 -0
  31. package/lib/{normalizePathOptionOrArg.js → utils/normalizePathOptionOrArg.js} +0 -0
  32. package/lib/{normalizeSocketPath.js → utils/normalizeSocketPath.js} +0 -0
  33. package/lib/{startSocketServer.js → utils/startSocketServer.js} +1 -1
  34. package/package.json +12 -12
  35. package/lib/commander.js +0 -1108
package/README.md CHANGED
@@ -7,6 +7,18 @@ See http://jsreport.net/learn/cli for documentation
7
7
 
8
8
  ## Changelog
9
9
 
10
+ ### 3.1.2
11
+
12
+ - update deps to fix npm audit
13
+
14
+ ### 3.1.1
15
+
16
+ - update deps to fix npm audit
17
+
18
+ ### 3.1.0
19
+
20
+ internal refactor (use latest version of yargs)
21
+
10
22
  ### 3.0.0-beta.1
11
23
 
12
- Adaptations for the v3 APIs
24
+ Adaptations for the v3 APIs
package/cli.js CHANGED
@@ -19,7 +19,7 @@ if (!semver.satisfies(process.versions.node, cliPackageJson.engines.node)) {
19
19
  const path = require('path')
20
20
  const Liftoff = require('liftoff')
21
21
  const commander = require('./lib/commander')
22
- const { printError } = require('./lib/errorUtils')
22
+ const { printError } = require('./lib/utils/error')
23
23
  const help = require('./lib/commands/help')
24
24
  const init = require('./lib/commands/init')
25
25
  const repair = require('./lib/commands/repair')
@@ -73,7 +73,7 @@ function initCLI (env) {
73
73
  globalCliHandler.start(args)
74
74
  } else {
75
75
  if (isCLIDev) {
76
- localCommander = require(path.join(cwd, 'lib/commander.js'))(cwd, { cliName: 'jsreport' })
76
+ localCommander = require(path.join(cwd, 'lib/commander'))(cwd, { cliName: 'jsreport' })
77
77
  } else {
78
78
  // Check for semver difference between global cli and local installation
79
79
  if (semver.gt(cliPackageJson.version, env.modulePackage.version)) {
@@ -82,7 +82,7 @@ function initCLI (env) {
82
82
  console.log('Local jsreport-cli is', env.modulePackage.version)
83
83
  }
84
84
 
85
- localCommander = require(path.join(path.dirname(env.modulePath), 'lib/commander.js'))(cwd, {
85
+ localCommander = require(path.join(path.dirname(env.modulePath), 'lib/commander'))(cwd, {
86
86
  cliName: 'jsreport'
87
87
  })
88
88
  }
package/index.js CHANGED
@@ -1,5 +1,3 @@
1
- 'use strict'
2
-
3
1
  const commander = require('./lib/commander')
4
2
  const main = require('./lib/cliExtension')
5
3
  const keepAliveProcess = require('./lib/keepAliveProcess')
@@ -1,7 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  const path = require('path')
4
- const searchExtensionsCommands = require('./registerExtensionsCommands')
4
+ const detectAndRegisterExtensionsCommands = require('./detectAndRegisterExtensionsCommands')
5
5
 
6
6
  module.exports = (reporter, definition) => {
7
7
  if (reporter.compilation) {
@@ -12,7 +12,7 @@ module.exports = (reporter, definition) => {
12
12
 
13
13
  reporter.cli = {
14
14
  findCommandsInExtensions: async () => {
15
- const extensionsCommands = await searchExtensionsCommands(
15
+ const extensionsCommands = await detectAndRegisterExtensionsCommands(
16
16
  reporter.extensionsManager.extensions,
17
17
  { registerCommand: () => {} }
18
18
  )
@@ -1,9 +1,8 @@
1
- 'use strict'
2
-
3
1
  const yargs = require('yargs')
4
2
 
5
- module.exports = function createCommandParser (instance, cliName) {
3
+ module.exports = function createCommandParser (instance, _cliName) {
6
4
  let cli = instance || yargs([])
5
+ const cliName = _cliName || 'jsreport'
7
6
  const commandHelp = 'To show more information about a command, type: jsreport <command> -h'
8
7
 
9
8
  if (cliName != null && cliName !== '') {
@@ -0,0 +1,150 @@
1
+ const getCommandEventName = require('./getCommandEventName')
2
+
3
+ // wrapping builder to allow some customizations in the api for commands
4
+ module.exports = (commander, {
5
+ commandName,
6
+ commandDescription,
7
+ commandBuilder,
8
+ commandConfig,
9
+ globalOptions
10
+ }) => (yargs) => {
11
+ let shouldGenerateUsage = true
12
+ let originalUsageFn
13
+ let originalCheckFn
14
+ let originalOptionFn
15
+ let originalOptionsFn
16
+ let commandCheckFn
17
+
18
+ if (typeof yargs.usage === 'function') {
19
+ originalUsageFn = yargs.usage
20
+
21
+ // we expose .usage but just for the message case
22
+ yargs.usage = (msg) => {
23
+ shouldGenerateUsage = false
24
+ return originalUsageFn.apply(yargs, [msg])
25
+ }
26
+ }
27
+
28
+ if (typeof yargs.check === 'function') {
29
+ originalCheckFn = yargs.check
30
+
31
+ yargs.check = (fn) => {
32
+ commandCheckFn = fn
33
+ return yargs
34
+ }
35
+ }
36
+
37
+ if (typeof yargs.option === 'function') {
38
+ originalOptionFn = yargs.option
39
+
40
+ // default options to be global: false
41
+ yargs.option = (key, opt) => {
42
+ if (opt && opt.global == null) {
43
+ opt.global = false
44
+ }
45
+
46
+ return originalOptionFn.apply(yargs, [key, opt])
47
+ }
48
+ }
49
+
50
+ if (typeof yargs.options === 'function') {
51
+ originalOptionsFn = yargs.options
52
+
53
+ // default options to be global: false
54
+ yargs.options = (keyOrOpts, opt) => {
55
+ if (keyOrOpts && opt == null) {
56
+ Object.entries(keyOrOpts).forEach(([key, keyConf]) => {
57
+ if (keyConf && keyConf.global == null) {
58
+ keyConf.global = false
59
+ }
60
+ })
61
+ }
62
+
63
+ if (opt && opt.global == null) {
64
+ opt.global = false
65
+ }
66
+
67
+ return originalOptionFn.apply(yargs, [keyOrOpts, opt])
68
+ }
69
+ }
70
+
71
+ const modYargs = commandBuilder(yargs)
72
+
73
+ if (typeof yargs.usage === 'function') {
74
+ yargs.usage = originalUsageFn
75
+ modYargs.usage = originalUsageFn
76
+
77
+ if (shouldGenerateUsage) {
78
+ modYargs.usage(commandDescription + '\n\nUsage:\n\njsreport ' + commandName)
79
+ }
80
+ }
81
+
82
+ if (typeof yargs.check === 'function') {
83
+ yargs.check = originalCheckFn
84
+ modYargs.check = originalCheckFn
85
+ }
86
+
87
+ if (typeof yargs.option === 'function') {
88
+ yargs.option = originalOptionFn
89
+ modYargs.option = originalOptionFn
90
+ }
91
+
92
+ if (typeof yargs.options === 'function') {
93
+ yargs.options = originalOptionsFn
94
+ modYargs.options = originalOptionsFn
95
+ }
96
+
97
+ modYargs.check((...args) => {
98
+ const argv = args[0]
99
+
100
+ const unsupportedGlobalOptions = globalOptions.options.filter((opt) => {
101
+ return commandConfig.globalOptions.indexOf(opt) === -1
102
+ })
103
+
104
+ unsupportedGlobalOptions.forEach((opt) => {
105
+ if (argv[opt]) {
106
+ throw new Error(opt + ' global option is not supported in this command')
107
+ }
108
+ })
109
+
110
+ if (commandCheckFn) {
111
+ return commandCheckFn.apply(undefined, args)
112
+ }
113
+
114
+ return true
115
+ }, false)
116
+
117
+ if (typeof modYargs.fail === 'function') {
118
+ // making command strict and registering a generalized fail function
119
+ modYargs.fail((msg, err) => {
120
+ // do nothing when error comes from command promise itself,
121
+ // the propagation of error will be done automatically by promise chain
122
+ if (msg == null) {
123
+ return
124
+ }
125
+
126
+ let errForEvent = err
127
+
128
+ if (errForEvent == null) {
129
+ errForEvent = new Error(msg)
130
+ }
131
+
132
+ commander.emit('command.error', commandName, errForEvent)
133
+ commander.emit(getCommandEventName(commandName, 'error'), errForEvent)
134
+
135
+ const defaultErr = new Error(`${commandName} command error:\n${msg}\ntype jsreport ${commandName} -h to get help about usage and available options`)
136
+
137
+ defaultErr.cleanState = true
138
+
139
+ throw defaultErr
140
+ })
141
+ }
142
+
143
+ if (commandConfig.disableStrictOptions !== true) {
144
+ modYargs.strict()
145
+ } else {
146
+ modYargs.strict(false)
147
+ }
148
+
149
+ return modYargs
150
+ }
@@ -0,0 +1,51 @@
1
+
2
+ module.exports = function createLogger (verboseMode) {
3
+ const logs = []
4
+
5
+ const logger = {
6
+ debug: (...messages) => {
7
+ const msg = messages.join(' ')
8
+
9
+ if (verboseMode) {
10
+ logs.push({
11
+ type: 'debug',
12
+ message: msg
13
+ })
14
+
15
+ console.log(...messages)
16
+ }
17
+ },
18
+ info: (...messages) => {
19
+ const msg = messages.join(' ')
20
+
21
+ logs.push({
22
+ type: 'info',
23
+ message: msg
24
+ })
25
+
26
+ console.log(...messages)
27
+ },
28
+ warn: (...messages) => {
29
+ const msg = messages.join(' ')
30
+
31
+ logs.push({
32
+ type: 'warn',
33
+ message: msg
34
+ })
35
+
36
+ console.error(...messages)
37
+ },
38
+ error: (...messages) => {
39
+ const msg = messages.join(' ')
40
+
41
+ logs.push({
42
+ type: 'error',
43
+ message: msg
44
+ })
45
+
46
+ console.error(...messages)
47
+ }
48
+ }
49
+
50
+ return { logger, getLogs: () => logs }
51
+ }
@@ -0,0 +1,37 @@
1
+ const getCommandEventName = require('./getCommandEventName')
2
+
3
+ module.exports = async function executeCommand (commander, commandName, argv) {
4
+ const command = commander._commands[commandName]
5
+
6
+ if (!command) {
7
+ throw new Error(`"${commandName}" command is not a valid command`)
8
+ }
9
+
10
+ if (typeof command.handler !== 'function') {
11
+ throw new Error(`"${commandName}" command doesn't have a valid handler`)
12
+ }
13
+
14
+ const commandHandler = command.handler
15
+
16
+ commander.emit('command.init', commandName, argv)
17
+ commander.emit(getCommandEventName(commandName, 'init'), argv)
18
+
19
+ let resolveValue
20
+
21
+ try {
22
+ resolveValue = await commandHandler(argv)
23
+
24
+ commander.emit('command.success', commandName, resolveValue)
25
+ commander.emit(getCommandEventName(commandName, 'success'), resolveValue)
26
+
27
+ return resolveValue
28
+ } catch (errorInCommand) {
29
+ commander.emit('command.error', commandName, errorInCommand)
30
+ commander.emit(getCommandEventName(commandName, 'error'), errorInCommand)
31
+ // propagating error
32
+ throw errorInCommand
33
+ } finally {
34
+ commander.emit('command.finish', commandName)
35
+ commander.emit(getCommandEventName(commandName, 'finish'))
36
+ }
37
+ }
@@ -0,0 +1,4 @@
1
+
2
+ module.exports = function getCommandEventName (command, event) {
3
+ return `command.${command}.${event}`
4
+ }
@@ -0,0 +1,279 @@
1
+ // eslint-disable-next-line no-var
2
+ var semver = require('semver')
3
+ // eslint-disable-next-line no-var
4
+ var cliPackageJson = require('../../package.json')
5
+
6
+ if (!semver.satisfies(process.versions.node, cliPackageJson.engines.node)) {
7
+ console.error(
8
+ 'jsreport cli requires to have installed a nodejs version of at least ' +
9
+ cliPackageJson.engines.node +
10
+ ' but you have installed version ' + process.versions.node + '. please update your nodejs version and try again'
11
+ )
12
+
13
+ process.exit(1)
14
+ }
15
+
16
+ const events = require('events')
17
+ const isAbsoluteUrl = require('is-absolute-url')
18
+ const createLogger = require('./createLogger')
19
+ const createCommandParser = require('./createCommandParser')
20
+ const registerCommand = require('./registerCommand')
21
+ const executeCommand = require('./executeCommand')
22
+ const startProcessing = require('./startProcessing')
23
+ const daemonHandler = require('../daemonHandler')
24
+ const keepAliveProcess = require('../keepAliveProcess')
25
+ const getTempPaths = require('../utils/getTempPaths')
26
+ const { printError } = require('../utils/error')
27
+
28
+ const helpCmd = require('../commands/help')
29
+ const initCmd = require('../commands/init')
30
+ const repairCmd = require('../commands/repair')
31
+ const winInstallCmd = require('../commands/win-install')
32
+ const winUninstallCmd = require('../commands/win-uninstall')
33
+ const configureCmd = require('../commands/configure')
34
+ const startCmd = require('../commands/start')
35
+ const renderCmd = require('../commands/render')
36
+ const killCmd = require('../commands/kill')
37
+
38
+ let BUILT_IN_COMMAND_MODULES = {
39
+ help: helpCmd,
40
+ init: initCmd,
41
+ repair: repairCmd,
42
+ 'win-install': winInstallCmd,
43
+ 'win-uninstall': winUninstallCmd,
44
+ configure: configureCmd,
45
+ start: startCmd,
46
+ render: renderCmd,
47
+ kill: killCmd
48
+ }
49
+
50
+ const AVAILABLE_GLOBAL_OPTIONS = {
51
+ options: [
52
+ 'context',
53
+ 'verbose',
54
+ // tempDirectory was added just for compatibility with jsreport.exe
55
+ 'tempDirectory',
56
+ 'serverUrl',
57
+ 'user',
58
+ 'password'
59
+ ],
60
+ alwaysGlobal: ['context', 'verbose', 'tempDirectory']
61
+ }
62
+
63
+ BUILT_IN_COMMAND_MODULES = Object.keys(BUILT_IN_COMMAND_MODULES).map((key) => BUILT_IN_COMMAND_MODULES[key])
64
+
65
+ const tempPaths = getTempPaths()
66
+ const CLI_PATH = tempPaths.cliPath
67
+ const MAIN_SOCK_PATH = tempPaths.mainSockPath
68
+ const WORKER_SOCK_PATH = tempPaths.workerSockPath
69
+
70
+ tempPaths.createPaths()
71
+
72
+ class Commander extends events.EventEmitter {
73
+ constructor (cwd, options = {}) {
74
+ super()
75
+
76
+ let cliHandler
77
+
78
+ this.cwd = cwd || process.cwd()
79
+
80
+ this.execution = options.execution
81
+
82
+ this.context = {
83
+ cwd: this.cwd,
84
+ sockPath: MAIN_SOCK_PATH,
85
+ workerSockPath: WORKER_SOCK_PATH,
86
+ staticPaths: options.staticPaths || {},
87
+ daemonHandler,
88
+ keepAliveProcess,
89
+ appInfo: options.appInfo
90
+ }
91
+
92
+ if (this.execution) {
93
+ if (!this.context.staticPaths.nssm) {
94
+ this.context.staticPaths.nssm = process.arch === 'x64' ? this.execution.resourceTempPath('nssm64.exe') : this.execution.resourceTempPath('nssm.exe')
95
+ }
96
+ }
97
+
98
+ this._commands = {}
99
+ this._commandModules = {}
100
+ this._commandNames = []
101
+ this._commandsConfig = {}
102
+
103
+ if (options.builtInCommands) {
104
+ this._builtInCommands = options.builtInCommands
105
+ } else {
106
+ this._builtInCommands = BUILT_IN_COMMAND_MODULES
107
+ }
108
+
109
+ if (options.disabledCommands) {
110
+ this._disabledCommands = options.disabledCommands
111
+ } else {
112
+ this._disabledCommands = []
113
+ }
114
+
115
+ this._globalOptions = AVAILABLE_GLOBAL_OPTIONS
116
+
117
+ this._builtInCommandNames = this._builtInCommands.map((cmdModule) => cmdModule.command)
118
+
119
+ this._showHelpWhenNoCommand = options.showHelpWhenNoCommand != null ? Boolean(options.showHelpWhenNoCommand) : true
120
+
121
+ // this option tell us that we should use this value as the instance
122
+ // and not try to look up for it
123
+ this._jsreportInstance = options.instance
124
+
125
+ // reference to the jsreport instance initiated, this variable will be set
126
+ // when the CLI has initialized a jsreport instance successfully
127
+ this.jsreportInstanceInitiated = null
128
+
129
+ // this option tell us that we should use this value as the instance version
130
+ // and not try to look up for it
131
+ this._jsreportVersion = options.jsreportVersion
132
+
133
+ // this option tell us that we should use this path as the executable
134
+ // to spawn when we need to use a daemonized process
135
+ this._daemonExecPath = options.daemonExecPath
136
+
137
+ // optional path to script being run in the daemonized process
138
+ this._daemonExecScriptPath = options.daemonExecScriptPath
139
+
140
+ // this option tell us that we should additionally pass this arguments
141
+ // to the executable when we need to use a daemonized process
142
+ this._daemonExecArgs = options.daemonExecArgs
143
+
144
+ // this option tell us that we should additionally pass this options
145
+ // to child_process.spawn when we need to use a daemonized process
146
+ this._daemonExecOpts = options.daemonExecOpts
147
+
148
+ if (this.execution) {
149
+ if (this._daemonExecOpts == null || this._daemonExecOpts.WinRunPath == null) {
150
+ this._daemonExecOpts = this._daemonExecOpts || {}
151
+ this._daemonExecOpts.WinRunPath = this.execution.resourceTempPath('WinRun.exe')
152
+ }
153
+ }
154
+
155
+ // lazy initialization of cli handler, commands will be activated when
156
+ // starting the parsing of cliHandler
157
+ if (options.cli) {
158
+ cliHandler = createCommandParser(options.cli, options.cliName)
159
+ } else {
160
+ cliHandler = (
161
+ createCommandParser(undefined, options.cliName)
162
+ .option('verbose', {
163
+ global: false,
164
+ alias: 'b',
165
+ description: 'Enables verbose mode',
166
+ type: 'boolean'
167
+ })
168
+ .option('tempDirectory', {
169
+ global: false,
170
+ description: 'Specifies the temp directory that will be used to store temp files and resources',
171
+ type: 'string'
172
+ })
173
+ .option('serverUrl', {
174
+ global: false,
175
+ alias: 's',
176
+ description: 'Specifies a url to a remote jsreport server, that server will be the target of the command (only if command support this mode)',
177
+ type: 'string',
178
+ requiresArg: true
179
+ })
180
+ .option('user', {
181
+ global: false,
182
+ alias: 'u',
183
+ description: 'Specifies a username for authentication against a jsreport server (Use if some command needs authentication information)',
184
+ type: 'string',
185
+ requiresArg: true
186
+ })
187
+ .option('password', {
188
+ global: false,
189
+ alias: 'p',
190
+ description: 'Specifies a password for authentication against a jsreport server (Use if some command needs authentication information)'
191
+ })
192
+ .check((argv, hash) => {
193
+ if (argv.serverUrl != null && !isAbsoluteUrl(argv.serverUrl)) {
194
+ const error = new Error('serverUrl option must be a valid absolute url')
195
+ error.cleanState = true
196
+ throw error
197
+ }
198
+
199
+ return true
200
+ })
201
+ .strict()
202
+ )
203
+ }
204
+
205
+ this._cli = cliHandler
206
+
207
+ this.cliName = this._cli.$0
208
+
209
+ // registering built-in commands
210
+ this._builtInCommands.forEach((commandModule) => this.registerCommand(commandModule))
211
+
212
+ setImmediate(() => this.emit('initialized'))
213
+
214
+ return this
215
+ }
216
+
217
+ getCommands () {
218
+ return this._commandNames
219
+ }
220
+
221
+ registerCommand (commandModule) {
222
+ registerCommand(this, commandModule)
223
+ return this
224
+ }
225
+
226
+ async executeCommand (commandName, argv) {
227
+ return executeCommand(this, commandName, argv)
228
+ }
229
+
230
+ start (args) {
231
+ const verboseMode = args.includes('--verbose') || args.includes('-b')
232
+ const { logger } = createLogger(verboseMode)
233
+
234
+ startProcessing(this, logger, args).then((resultInfo) => {
235
+ const commandHandled = resultInfo != null ? resultInfo.command : undefined
236
+ const disableExit = commandHandled != null && this._commandsConfig[commandHandled] ? this._commandsConfig[commandHandled].disableProcessExit === true : false
237
+
238
+ if (disableExit !== true) {
239
+ process.exit(0)
240
+ }
241
+ }).catch((err) => {
242
+ if (err.exitDirectly) {
243
+ return process.exit(1)
244
+ }
245
+
246
+ printError(err, logger)
247
+
248
+ if (err.disabledExit !== true) {
249
+ process.exit(1)
250
+ }
251
+ })
252
+ }
253
+
254
+ async startAndWait (args) {
255
+ const verboseMode = args != null && (args.includes('--verbose') || args.includes('-b'))
256
+ const { logger, getLogs } = createLogger(verboseMode)
257
+ let error
258
+
259
+ try {
260
+ await startProcessing(this, logger, args)
261
+ } catch (e) {
262
+ error = e
263
+
264
+ if (e.exitDirectly !== true) {
265
+ printError(e, logger)
266
+ }
267
+ }
268
+
269
+ const logs = getLogs()
270
+
271
+ return { error, logs }
272
+ }
273
+ }
274
+
275
+ module.exports = (cwd, options = {}) => new Commander(cwd, options)
276
+
277
+ module.exports.cliPath = CLI_PATH
278
+ module.exports.mainSockPath = MAIN_SOCK_PATH
279
+ module.exports.workerSockPath = WORKER_SOCK_PATH