@antora/cli 3.0.0-alpha.9 → 3.0.0-beta.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/README.md CHANGED
@@ -3,9 +3,9 @@
3
3
  The command line interface (CLI) for Antora.
4
4
 
5
5
  [Antora](https://antora.org) is a modular static site generator designed for creating documentation sites from AsciiDoc documents.
6
- Its site generator pipeline aggregates documents from versioned content repositories and processes them using [Asciidoctor](https://asciidoctor.org).
6
+ Its site generator aggregates documents from versioned content repositories and processes them using [Asciidoctor](https://asciidoctor.org).
7
7
 
8
- To run Antora, you need both the CLI and a site generator pipeline.
8
+ To run Antora, you need both the CLI and a site generator.
9
9
  Once these packages are installed, you can use the `antora` command to generate your site.
10
10
 
11
11
  ## How to Install
package/lib/cli.js CHANGED
@@ -2,15 +2,13 @@
2
2
 
3
3
  'use strict'
4
4
 
5
+ const buildPlaybook = require('@antora/playbook-builder')
5
6
  const cli = require('./commander')
6
- // Q: can we ask the playbook builder for the config schema?
7
- const configSchema = require('@antora/playbook-builder/lib/config/schema')
8
7
  const convict = require('@antora/playbook-builder/lib/solitary-convict')
9
- const { finalizeLogger } = require('@antora/logger')
8
+ const { configureLogger, getLogger, finalizeLogger } = require('@antora/logger')
10
9
  const ospath = require('path')
11
10
  const userRequire = require('@antora/user-require-helper')
12
11
 
13
- const DEFAULT_GENERATOR = '@antora/site-generator-default'
14
12
  const { version: VERSION } = require('../package.json')
15
13
 
16
14
  async function run (argv = process.argv) {
@@ -18,47 +16,60 @@ async function run (argv = process.argv) {
18
16
  return cli.parseAsync(args.length ? args : ['help'], { from: 'user' })
19
17
  }
20
18
 
21
- function exitWithError (err, showStack, msg = undefined) {
19
+ function exitWithError (err, opts, msg = undefined) {
22
20
  if (!msg) msg = err.message || err
23
- if (showStack) {
24
- let stack
21
+ const name = msg.startsWith('asciidoctor: FAILED: ') ? (msg = msg.slice(21)) && 'asciidoctor' : cli.name()
22
+ const logger = getLogger(null)
23
+ ? getLogger(name)
24
+ : configureLogger({ format: 'pretty', level: opts.silent ? 'silent' : 'fatal', failureLevel: 'fatal' }).get(name)
25
+ if (opts.stacktrace) {
26
+ let loc, stack
25
27
  if ((stack = err.backtrace)) {
26
- msg = [`error: ${msg}`, ...stack.slice(1)].join('\n')
28
+ err = Object.assign(new Error(msg), { stack: ['Error', ...stack.slice(1)].join('\n') })
27
29
  } else if ((stack = err.stack)) {
28
- if (err instanceof SyntaxError) {
29
- let loc
30
- ;[loc, stack] = stack.split(/\n+(?=SyntaxError: )/)
31
- msg = stack.replace('\n', `\n at ${loc}\n`)
32
- } else if (stack.startsWith(`${err.name}: ${msg}\n`)) {
33
- msg = stack
34
- } else {
35
- msg = [msg, ...stack.split('\n').slice(1)].join('\n')
30
+ if (err instanceof SyntaxError && stack.includes('\nSyntaxError: ')) {
31
+ ;[loc, stack] = stack.split(/\n+SyntaxError: [^\n]+/)
32
+ err = Object.assign(new SyntaxError(msg), { stack: stack.replace('\n', `SyntaxError\n at ${loc}\n`) })
33
+ } else if (stack.startsWith(`${err.name}: ${msg}`)) {
34
+ stack = stack.replace(`${err.name}: ${msg}`, '').replace(/^\n/, '')
35
+ err = Object.assign(new err.constructor(msg), { stack: stack ? `${err.name}\n${stack}` : undefined })
36
36
  }
37
37
  } else {
38
- msg = `error: ${msg} (no stack)`
38
+ err = Object.assign(new Error(msg), { stack: undefined })
39
39
  }
40
- console.error(msg)
40
+ if ({}.propertyIsEnumerable.call(err, 'name')) Object.defineProperty(err, 'name', { enumerable: false })
41
+ err.stack = `Cause: ${err.stack || '(no stacktrace)'}`
42
+ logger.fatal(err, msg)
41
43
  } else {
42
- console.error(`error: ${msg}\nAdd the --stacktrace option to see the cause.`)
44
+ logger.fatal(msg + '\nAdd the --stacktrace option to see the cause of the error.')
43
45
  }
44
- process.exit(1)
46
+ return exit()
47
+ }
48
+
49
+ function exit () {
50
+ return finalizeLogger().then((failOnExit) => process.exit(failOnExit ? 1 : process.exitCode))
45
51
  }
46
52
 
47
53
  function getTTYColumns () {
48
54
  return process.env.COLUMNS || process.stdout.columns || 80
49
55
  }
50
56
 
57
+ function outputError (str, write) {
58
+ write(str.replace(/^error: /, cli.name() + ': '))
59
+ }
60
+
51
61
  cli
52
62
  .allowExcessArguments(false)
53
- .configureOutput({ getOutHelpWidth: getTTYColumns, getErrHelpWidth: getTTYColumns })
63
+ .configureOutput({ getOutHelpWidth: getTTYColumns, getErrHelpWidth: getTTYColumns, outputError })
54
64
  .storeOptionsAsProperties()
55
65
  .name('antora')
56
66
  .version(
57
67
  {
58
68
  toString () {
59
- const buffer = [`@antora/cli: ${VERSION}`]
69
+ const generator = cli._findCommand('generate').getOptionValue('generator')
70
+ const buffer = ['@antora/cli: ' + VERSION]
60
71
  let generatorVersion
61
- const generatorPackageJson = DEFAULT_GENERATOR + '/package.json'
72
+ const generatorPackageJson = generator + '/package.json'
62
73
  try {
63
74
  generatorVersion = require(generatorPackageJson).version
64
75
  } catch {
@@ -66,7 +77,7 @@ cli
66
77
  generatorVersion = require(require.resolve(generatorPackageJson, { paths: [''] })).version
67
78
  } catch {}
68
79
  }
69
- buffer.push(DEFAULT_GENERATOR + ': ' + (generatorVersion || 'not installed'))
80
+ buffer.push(generator + ': ' + (generatorVersion || 'not installed'))
70
81
  return buffer.join('\n')
71
82
  },
72
83
  },
@@ -76,69 +87,73 @@ cli
76
87
  .description('A modular, multi-repository documentation site generator for AsciiDoc.')
77
88
  .usage('[options] [[command] [args]]')
78
89
  .helpOption('-h, --help', 'Output usage information.')
79
- .addHelpText(
80
- 'after',
81
- function () {
82
- const name = this.name()
83
- return this.createHelp().wrap(
90
+ .addHelpText('after', () => {
91
+ const name = cli.name()
92
+ return cli
93
+ .createHelp()
94
+ .wrap(
84
95
  ` \nRun '${name} <command> --help' to see options and examples for a command (e.g., ${name} generate --help).`,
85
96
  getTTYColumns(),
86
97
  0
87
98
  )
88
- }.bind(cli)
89
- )
99
+ })
90
100
  .option('-r, --require <library>', 'Require library (aka node module) or script path before executing command.')
91
101
  .on('option:require', (requireRequest) => (cli.requireRequests = cli.requireRequests || []).push(requireRequest))
92
102
  .option('--stacktrace', 'Print the stacktrace to the console if the application fails.')
93
103
 
94
104
  cli
95
105
  .command('generate <playbook>', { isDefault: true })
96
- .description('Generate a documentation site specified in <playbook>.')
97
- .optionsFromConvict(convict(configSchema), { exclude: 'playbook' })
98
- .addOption(
99
- cli
100
- .createOption('--generator <library>', 'The site generator library.')
101
- .default(DEFAULT_GENERATOR, DEFAULT_GENERATOR)
102
- )
106
+ .description('Generate a documentation site as specified by <playbook>.')
107
+ .optionsFromConvict(convict(buildPlaybook.defaultSchema), { exclude: 'playbook' })
108
+ .trackOptions()
103
109
  .action(async (playbookFile, options, command) => {
104
- const dot = ospath.resolve(playbookFile, '..')
105
- const userRequireContext = { dot, paths: [dot, __dirname] }
110
+ const errorOpts = { stacktrace: cli.stacktrace, silent: command.silent }
111
+ const playbookDir = ospath.resolve(playbookFile, '..')
112
+ const userRequireContext = { dot: playbookDir, paths: [playbookDir, __dirname] }
106
113
  if (cli.requireRequests) {
107
114
  try {
108
115
  cli.requireRequests.forEach((requireRequest) => userRequire(requireRequest, userRequireContext))
109
116
  } catch (err) {
110
- exitWithError(err, cli.stacktrace)
117
+ return exitWithError(err, errorOpts)
111
118
  }
112
119
  }
113
- const generator = options.generator
120
+ const args = command.optionArgs.concat('--playbook', playbookFile)
121
+ let playbook
122
+ try {
123
+ playbook = buildPlaybook(args, process.env, buildPlaybook.defaultSchema, (config) => {
124
+ try {
125
+ configureLogger(config.getModel('runtime.log'), playbookDir)
126
+ } catch {}
127
+ })
128
+ } catch (err) {
129
+ return exitWithError(err, errorOpts)
130
+ }
131
+ const generator = playbook.antora.generator
114
132
  let generateSite
115
133
  try {
116
- generateSite = userRequire(generator, userRequireContext)
134
+ generateSite =
135
+ (generateSite = userRequire(generator, userRequireContext)).length === 1
136
+ ? generateSite.bind(null, playbook)
137
+ : generateSite.bind(null, args, process.env)
117
138
  } catch (err) {
118
139
  let msg = 'Generator not found or failed to load.'
119
140
  if (generator && generator.charAt() !== '.') msg += ` Try installing the '${generator}' package.`
120
- exitWithError(err, cli.stacktrace, msg)
141
+ return exitWithError(err, errorOpts, msg)
121
142
  }
122
- const args = cli.rawArgs.slice(cli.rawArgs.indexOf(command.name()) + 1)
123
- args.splice(args.indexOf(playbookFile), 0, '--playbook')
124
- // TODO support passing a preloaded convict config as third option; gets new args and env
125
- return generateSite(args, process.env)
126
- .then(finalizeLogger)
127
- .then((failOnExit) => process.exit(failOnExit ? 1 : process.exitCode))
128
- .catch((err) => finalizeLogger().then(() => exitWithError(err, cli.stacktrace)))
143
+ return generateSite()
144
+ .then(exit)
145
+ .catch((err) => exitWithError(err, errorOpts))
129
146
  })
130
147
  .options.sort((a, b) => a.long.localeCompare(b.long))
131
148
 
132
149
  cli.command('help [command]', { hidden: true }).action((name, options, command) => {
133
150
  if (name) {
134
- const helpCommand = cli.commands.find((candidate) => candidate.name() === name)
151
+ const helpCommand = cli._findCommand(name)
135
152
  if (helpCommand) {
136
153
  helpCommand.help()
137
154
  } else {
138
- console.error(
139
- `'${name}' is not a valid command in ${cli.name()}. See '${cli.name()} --help' for a list of commands.`
140
- )
141
- process.exit(1)
155
+ const message = `error: unknown command '${name}'. See '${cli.name()} --help' for a list of commands.`
156
+ cli._displayError(1, 'commander.unknownCommand', message)
142
157
  }
143
158
  } else {
144
159
  cli.help()
@@ -0,0 +1,14 @@
1
+ 'use strict'
2
+
3
+ const { Command } = require('commander')
4
+
5
+ Command.prototype.trackOptions = function () {
6
+ const optionArgs = (this.optionArgs = [])
7
+ for (const eventName of this.eventNames().filter((name) => name.startsWith('option:'))) {
8
+ this.on(eventName, function () {
9
+ optionArgs.push(`--${eventName.slice(7)}`)
10
+ if (arguments.length) optionArgs.push(arguments[0])
11
+ })
12
+ }
13
+ return this
14
+ }
package/lib/commander.js CHANGED
@@ -2,5 +2,6 @@
2
2
 
3
3
  const commander = require('commander')
4
4
  require('./commander/options-from-convict')
5
+ require('./commander/track-options')
5
6
 
6
7
  module.exports = commander
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@antora/cli",
3
- "version": "3.0.0-alpha.9",
3
+ "version": "3.0.0-beta.1",
4
4
  "description": "The command line interface for Antora.",
5
5
  "license": "MPL-2.0",
6
6
  "author": "OpenDevise Inc. (https://opendevise.com)",
@@ -18,18 +18,18 @@
18
18
  "antora": "bin/antora"
19
19
  },
20
20
  "dependencies": {
21
- "@antora/logger": "3.0.0-alpha.9",
22
- "@antora/playbook-builder": "3.0.0-alpha.9",
21
+ "@antora/logger": "3.0.0-beta.1",
22
+ "@antora/playbook-builder": "3.0.0-beta.1",
23
23
  "@antora/user-require-helper": "~2.0",
24
- "commander": "~7.2"
24
+ "commander": "~8.3"
25
25
  },
26
26
  "devDependencies": {
27
- "@antora/site-publisher": "3.0.0-alpha.9",
28
- "convict": "~6.1",
27
+ "@antora/site-publisher": "3.0.0-beta.1",
28
+ "convict": "~6.2",
29
29
  "kapok-js": "~0.10"
30
30
  },
31
31
  "engines": {
32
- "node": ">=10.17.0"
32
+ "node": ">=12.21.0"
33
33
  },
34
34
  "files": [
35
35
  "bin/",
@@ -43,5 +43,5 @@
43
43
  "static site",
44
44
  "web publishing"
45
45
  ],
46
- "gitHead": "a504d6889819b548e8a5416a7194cbb6f9a93e93"
46
+ "gitHead": "7c5ef1ea93dd489af533c80a936c736013c41769"
47
47
  }