@antora/playbook-builder 3.2.0-alpha.1 → 3.2.0-alpha.10

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
@@ -1,7 +1,7 @@
1
1
  # Antora Playbook Builder
2
2
 
3
3
  The Playbook Builder is the configuration component for Antora.
4
- It's responsible for building a playbook object from user input that's then used for configuring components in an Antora generator pipeline.
4
+ Its responsible for building a playbook object from user input thats then used for configuring components in an Antora generator pipeline.
5
5
 
6
6
  [Antora](https://antora.org) is a modular static site generator designed for creating documentation sites from AsciiDoc documents.
7
7
  Its site generator aggregates documents from versioned content repositories and processes them using [Asciidoctor](https://asciidoctor.org).
@@ -2,8 +2,10 @@
2
2
 
3
3
  const convict = require('./solitary-convict')
4
4
  const defaultSchema = require('./config/schema')
5
- const fs = require('fs')
6
- const ospath = require('path')
5
+ const fs = require('node:fs')
6
+ const ospath = require('node:path')
7
+ const parseArgs = require('yargs-parser')
8
+ const yaml = require('js-yaml')
7
9
 
8
10
  /**
9
11
  * Builds a playbook object according to the provided schema from the specified
@@ -11,7 +13,7 @@ const ospath = require('path')
11
13
  *
12
14
  * Accepts an array of command line arguments (in the form of option flags and
13
15
  * switches) and a map of environment variables and translates this data into a
14
- * playbook object according the the specified schema. If no schema is
16
+ * playbook object according the specified schema. If no schema is
15
17
  * specified, the default schema provided by this package is used.
16
18
  *
17
19
  * @memberof playbook-builder
@@ -28,8 +30,22 @@ const ospath = require('path')
28
30
  * marked in the schema as preserve, all keys in the playbook are camelCased.
29
31
  */
30
32
  function buildPlaybook (args = [], env = process.env, schema = defaultSchema, beforeValidate = undefined) {
31
- const config = Object.assign(convict(schema, { args, env }), { getModel })
32
- const playbook = config.has('playbook') && config.get('playbook')
33
+ const parsedArgs = parseArgs(args, { configuration: { 'dot-notation': false } })
34
+ const opts = { args: [], env: {} }
35
+ const config = Object.assign(convict(schema, opts), { getModel, getSchema })
36
+ Object.assign(opts, { args, env })
37
+ let playbook
38
+ if ('playbook' in schema) {
39
+ const playbookEnv = schema.playbook.env
40
+ if (playbookEnv != null) playbook = env[playbookEnv]
41
+ const playbookArg = schema.playbook.arg
42
+ if (playbookArg != null) playbook = parsedArgs[playbookArg] ?? playbook
43
+ if (playbook === undefined) {
44
+ if (config.has('playbook')) playbook = config.get('playbook')
45
+ } else {
46
+ config.set('playbook', playbook)
47
+ }
48
+ }
33
49
  let absPlaybookPath
34
50
  if (playbook) {
35
51
  if (ospath.extname((absPlaybookPath = ospath.resolve(playbook)))) {
@@ -50,10 +66,11 @@ function buildPlaybook (args = [], env = process.env, schema = defaultSchema, be
50
66
  }
51
67
  }
52
68
  try {
53
- if (playbook) {
54
- config.loadFile(absPlaybookPath)
55
- if (playbook !== absPlaybookPath) config.set('playbook', absPlaybookPath)
56
- }
69
+ Object.assign(opts, { args: [] })
70
+ playbook ? config.loadFile(absPlaybookPath) : config.load({})
71
+ importArguments(config, parsedArgs)
72
+ Object.assign(opts, { args })
73
+ if (playbook && playbook !== absPlaybookPath) config.set('playbook', absPlaybookPath)
57
74
  const beforeValidateFromSchema = config._def[Symbol.for('convict.beforeValidate')]
58
75
  if (beforeValidateFromSchema) beforeValidateFromSchema(config)
59
76
  if (beforeValidate) beforeValidate(config)
@@ -82,9 +99,8 @@ function camelCaseKeys (o, stopPaths = [], p = '') {
82
99
  function getModel (name) {
83
100
  let config = this
84
101
  const data = config.get(name)
85
- let schema = config._schema
102
+ const schema = config.getSchema(name)
86
103
  if (name) {
87
- schema = name.split('.').reduce((accum, key) => accum._cvtProperties[key], schema)
88
104
  config = Object.assign(convict(name.split('.').reduce((def, key) => def[key], config._def)), { _instance: data })
89
105
  }
90
106
  config.validate({ allowed: 'strict' })
@@ -97,6 +113,10 @@ function getModel (name) {
97
113
  return model
98
114
  }
99
115
 
116
+ function getSchema (name) {
117
+ return name ? name.split('.').reduce((accum, key) => accum._cvtProperties[key], this._schema) : this._schema
118
+ }
119
+
100
120
  function getStopPaths (schemaProperties, schemaPath = [], stopPaths = []) {
101
121
  for (const [key, { preserve, _cvtProperties }] of Object.entries(schemaProperties)) {
102
122
  if (preserve) {
@@ -110,6 +130,22 @@ function getStopPaths (schemaProperties, schemaPath = [], stopPaths = []) {
110
130
  return stopPaths
111
131
  }
112
132
 
133
+ function importArguments (config, args) {
134
+ for (const [argName, configKey] of Object.entries(config._argv)) {
135
+ const argVal = args[argName]
136
+ if (argVal === undefined) continue
137
+ const argFormat = config.getSchema(configKey).format
138
+ let argValStr = argVal
139
+ if (argFormat === 'map' || argFormat === 'primitive-map') {
140
+ const dumpOpts = { condenseFlow: true, flowLevel: 0, noCompatMode: true, quotingType: '"' }
141
+ argValStr = yaml.dump(Array.isArray(argVal) ? argVal : [argVal], dumpOpts)
142
+ } else if (Array.isArray(argVal)) {
143
+ argValStr = argVal.join(',')
144
+ }
145
+ config.set(configKey, argValStr)
146
+ }
147
+ }
148
+
113
149
  function getDetails (playbook, absPlaybookPath) {
114
150
  if (playbook === absPlaybookPath) return ''
115
151
  return ` (${ospath.isAbsolute(playbook) ? '' : 'cwd: ' + process.cwd() + ', '}playbook: ${playbook})`
@@ -17,7 +17,8 @@ module.exports = {
17
17
  extensions: {
18
18
  doc:
19
19
  'A list of extensions that listen for lifecycle events. ' +
20
- 'Each extension is specified as a require request string or an object with a require key.',
20
+ 'Each extension is specified as a require request string or an object with a require key. ' +
21
+ 'May be specified multiple times.',
21
22
  format: 'require-array',
22
23
  default: [],
23
24
  arg: 'extension',
@@ -66,7 +67,7 @@ module.exports = {
66
67
  content: {
67
68
  branches: {
68
69
  doc: 'The default branch pattern to use when no specific pattern is provided.',
69
- format: Array,
70
+ format: 'array-or-string',
70
71
  default: ['HEAD', 'v{0..9}*'],
71
72
  },
72
73
  edit_url: {
@@ -82,9 +83,14 @@ module.exports = {
82
83
  },
83
84
  tags: {
84
85
  doc: 'The default tag pattern to use when no specific pattern is provided.',
85
- format: Array,
86
+ format: 'array-or-string',
86
87
  default: undefined,
87
88
  },
89
+ worktrees: {
90
+ doc: 'The default worktrees pattern to use when no specific pattern is provided.',
91
+ format: 'boolean-or-array-or-string',
92
+ default: '.',
93
+ },
88
94
  },
89
95
  ui: {
90
96
  bundle: {
@@ -167,7 +173,12 @@ module.exports = {
167
173
  fetch_concurrency: {
168
174
  doc: 'The maximum number of fetch or clone operations that are permitted to run at once. Use 0 for unlimited.',
169
175
  format: 'int',
170
- default: 0,
176
+ default: 1,
177
+ },
178
+ fetch_depth: {
179
+ doc: 'Preferred number of commits to fetch from remote repository. 0 indicates full history.',
180
+ format: 'int',
181
+ default: 1,
171
182
  },
172
183
  plugins: {
173
184
  credential_manager: {
@@ -181,6 +192,11 @@ module.exports = {
181
192
  default: undefined,
182
193
  },
183
194
  },
195
+ read_concurrency: {
196
+ doc: 'The maximum number of git indexes that are read into memory at once. Use 0 for unlimited.',
197
+ format: 'int',
198
+ default: 0,
199
+ },
184
200
  },
185
201
  network: {
186
202
  http_proxy: {
@@ -253,23 +269,13 @@ module.exports = {
253
269
  arg: 'log-failure-level',
254
270
  env: 'ANTORA_LOG_FAILURE_LEVEL',
255
271
  },
256
- format: new Proxy(
257
- {
258
- doc: 'Set the format of log messages. Defaults to pretty if CI=true or stdout is a TTY, json otherwise.',
259
- format: ['json', 'pretty'],
260
- default: undefined,
261
- arg: 'log-format',
262
- env: 'ANTORA_LOG_FORMAT',
263
- },
264
- {
265
- get (target, property) {
266
- if (property !== 'default') return target[property]
267
- return process.env.CI === 'true' || (process.env.IS_TTY || String(process.stdout.isTTY)) === 'true'
268
- ? 'pretty'
269
- : 'json'
270
- },
271
- }
272
- ),
272
+ format: {
273
+ doc: 'Set the format of log messages. Defaults to pretty if CI=true or stdout is a TTY, json otherwise.',
274
+ format: ['json', 'pretty'],
275
+ default: 'auto',
276
+ arg: 'log-format',
277
+ env: 'ANTORA_LOG_FORMAT',
278
+ },
273
279
  destination: {
274
280
  file: {
275
281
  doc: 'Write log messages to this file or stream. Defaults to stderr if format is pretty, stdout otherwise.',
@@ -344,8 +350,13 @@ module.exports = {
344
350
  default: undefined,
345
351
  },
346
352
  },
347
- [Symbol.for('convict.beforeValidate')]: ({ _schema: schema, _instance: data }) => {
353
+ [Symbol.for('convict.beforeValidate')]: ({ getEnv, _instance: data, _schema: schema }) => {
348
354
  const runtime = data.runtime
355
+ const log = runtime.log
356
+ if (log.format === 'auto') {
357
+ const env = getEnv()
358
+ log.format = env.CI === 'true' || (env.IS_TTY || String(process.stdout.isTTY)) === 'true' ? 'pretty' : 'json'
359
+ }
349
360
  if (runtime.silent) {
350
361
  if (runtime.quiet === false) runtime.quiet = true
351
362
  if (runtime.log.level !== 'silent') runtime.log.level = 'silent'
@@ -5,9 +5,10 @@ const json = require('json5')
5
5
  const toml = require('@iarna/toml')
6
6
  const yaml = require('js-yaml')
7
7
 
8
- const ARGS_SCANNER_RX = /(?:([^=,]+)|(?==))(?:,|$|=(|("|').*?\3|[^,]+)(?:,|$))/g
9
8
  const PRIMITIVE_TYPES = [Boolean, Number, String]
9
+ const COERCE_SCHEMA = yaml.FAILSAFE_SCHEMA
10
10
  const YAML_SCHEMA = yaml.CORE_SCHEMA.extend({ implicit: [yaml.types.merge] })
11
+ const YAML_PREFIX_RX = new RegExp('!!((?:auto|str|bool|int|float|seq|map)(?= )|null(?=$))(?: |$)')
11
12
 
12
13
  /**
13
14
  * A convict function wrapper that registers custom formats and parsers and
@@ -35,6 +36,22 @@ function registerParsers (convict) {
35
36
  }
36
37
 
37
38
  function registerFormats (convict) {
39
+ convict.addFormat({
40
+ name: 'array-or-string',
41
+ validate: (val) => {
42
+ if (!(val == null || val.constructor === String || Array.isArray(val))) {
43
+ throw new Error('must be an array, string, or null')
44
+ }
45
+ },
46
+ })
47
+ convict.addFormat({
48
+ name: 'boolean-or-array-or-string',
49
+ validate: (val) => {
50
+ if (!(val == null || typeof val === 'boolean' || val.constructor === String || Array.isArray(val))) {
51
+ throw new Error('must be a boolean, array, string, or null')
52
+ }
53
+ },
54
+ })
38
55
  convict.addFormat({
39
56
  name: 'map',
40
57
  validate: (val) => {
@@ -43,11 +60,25 @@ function registerFormats (convict) {
43
60
  coerce: (val, config, name) => {
44
61
  if (config == null) return val
45
62
  const accum = config.has(name) ? config.get(name) : {}
46
- let match
47
- ARGS_SCANNER_RX.lastIndex = 0
48
- while ((match = ARGS_SCANNER_RX.exec(val))) {
49
- const [, k, v] = match
50
- if (k) accum[k] = v ? (v === '-' ? '-' : yaml.load(v, { schema: yaml.CORE_SCHEMA })) : ''
63
+ const entries = yaml.load(val, { schema: COERCE_SCHEMA })
64
+ for (const entry of Array.isArray(entries) ? entries : [entries]) {
65
+ let k = entry
66
+ let v = ''
67
+ const equalsIdx = entry.indexOf('=')
68
+ if (~equalsIdx) {
69
+ if (!(k = entry.slice(0, equalsIdx))) continue
70
+ v = entry.slice(equalsIdx + 1)
71
+ }
72
+ let parsed = v
73
+ if (v) {
74
+ const match = v.match(YAML_PREFIX_RX)
75
+ if (match) {
76
+ try {
77
+ parsed = yaml.load(match[1] === 'auto' ? v.slice(7) : v, { schema: yaml.CORE_SCHEMA })
78
+ } catch {}
79
+ }
80
+ }
81
+ accum[k] = parsed
51
82
  }
52
83
  return accum
53
84
  },
@@ -68,20 +99,26 @@ function registerFormats (convict) {
68
99
  coerce: (val, config, name) => {
69
100
  if (config == null) return val
70
101
  const accum = config.has(name) ? config.get(name) : {}
71
- let match
72
- ARGS_SCANNER_RX.lastIndex = 0
73
- while ((match = ARGS_SCANNER_RX.exec(val))) {
74
- const [, k, v] = match
75
- if (k) {
76
- let parsed
77
- if (v && v !== '-') {
78
- parsed = yaml.load(v, { schema: yaml.CORE_SCHEMA })
79
- if (parsed && PRIMITIVE_TYPES.indexOf(parsed.constructor) < 0) parsed = v
80
- } else {
81
- parsed = v || ''
102
+ const entries = yaml.load(val, { schema: COERCE_SCHEMA })
103
+ for (const entry of Array.isArray(entries) ? entries : [entries]) {
104
+ let k = entry
105
+ let v = ''
106
+ const equalsIdx = entry.indexOf('=')
107
+ if (~equalsIdx) {
108
+ if (!(k = entry.slice(0, equalsIdx))) continue
109
+ v = entry.slice(equalsIdx + 1)
110
+ }
111
+ let parsed = v
112
+ if (v) {
113
+ const match = v.match(YAML_PREFIX_RX)
114
+ if (match) {
115
+ try {
116
+ parsed = yaml.load(match[1] === 'auto' ? v.slice(7) : v, { schema: yaml.CORE_SCHEMA })
117
+ if (parsed && !~PRIMITIVE_TYPES.indexOf(parsed.constructor)) parsed = v
118
+ } catch {}
82
119
  }
83
- accum[~k.indexOf('-') ? k.replace(/-/g, '_') : k] = parsed
84
120
  }
121
+ accum[~k.indexOf('-') ? k.replace(/-/g, '_') : k] = parsed
85
122
  }
86
123
  return accum
87
124
  },
@@ -89,19 +126,19 @@ function registerFormats (convict) {
89
126
  convict.addFormat({
90
127
  name: 'require-array',
91
128
  validate: (val) => {
92
- if (!Array.isArray(val)) throw new Error('must be of type Array')
129
+ if (!Array.isArray(val)) throw new Error('must be an array')
93
130
  },
94
131
  coerce: (val, config, name) => {
95
- const accum = config && config.has(name) ? config.get(name) : []
96
- val.split(',').forEach((v) => {
97
- if (~accum.indexOf(v)) return
132
+ const accum = config?.has(name) ? config.get(name) : []
133
+ for (const v of val.split(',')) {
134
+ if (~accum.indexOf(v)) continue
98
135
  const match = accum.find((it) => it.constructor === Object && it.id === v)
99
136
  if (match) {
100
137
  if (match.enabled === false) match.enabled = true
101
138
  } else {
102
139
  accum.push(v)
103
140
  }
104
- })
141
+ }
105
142
  return accum
106
143
  },
107
144
  })
@@ -109,7 +146,7 @@ function registerFormats (convict) {
109
146
  name: 'boolean-or-string',
110
147
  validate: (val) => {
111
148
  if (!(val == null || val.constructor === String || val.constructor === Boolean)) {
112
- throw new Error('must be a boolean or string')
149
+ throw new Error('must be a boolean, string, or null')
113
150
  }
114
151
  },
115
152
  })
@@ -151,7 +188,10 @@ function registerFormats (convict) {
151
188
  }
152
189
  if (~parsedUrl.pathname.indexOf('%20')) throw new Error('pathname segment must not contain spaces')
153
190
  },
154
- coerce: (val) => (val.length > 1 && val.charAt(val.length - 1) === '/' ? val.slice(0, -1) : val),
191
+ coerce: (val) => {
192
+ if (!val || val === '~') return null
193
+ return val.length > 1 && val.charAt(val.length - 1) === '/' ? val.slice(0, -1) : val
194
+ },
155
195
  })
156
196
  }
157
197
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@antora/playbook-builder",
3
- "version": "3.2.0-alpha.1",
3
+ "version": "3.2.0-alpha.10",
4
4
  "description": "Builds a playbook object from user input for configuring successive documentation components in an Antora pipeline.",
5
5
  "license": "MPL-2.0",
6
6
  "author": "OpenDevise Inc. (https://opendevise.com)",
@@ -10,7 +10,11 @@
10
10
  "Hubert SABLONNIÈRE <hubert.sablonniere@gmail.com>"
11
11
  ],
12
12
  "homepage": "https://antora.org",
13
- "repository": "gitlab:antora/antora",
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://gitlab.com/antora/antora.git",
16
+ "directory": "packages/playbook-builder"
17
+ },
14
18
  "bugs": {
15
19
  "url": "https://gitlab.com/antora/antora/issues"
16
20
  },
@@ -26,10 +30,11 @@
26
30
  "@iarna/toml": "~2.2",
27
31
  "convict": "~6.2",
28
32
  "js-yaml": "~4.1",
29
- "json5": "~2.2"
33
+ "json5": "~2.2",
34
+ "yargs-parser": "~20.2"
30
35
  },
31
36
  "engines": {
32
- "node": ">=16.0.0"
37
+ "node": ">=18.0.0"
33
38
  },
34
39
  "files": [
35
40
  "lib/"
@@ -44,7 +49,7 @@
44
49
  ],
45
50
  "scripts": {
46
51
  "test": "_mocha",
47
- "prepublishOnly": "node $npm_config_local_prefix/npm/prepublishOnly.js",
48
- "postpublish": "node $npm_config_local_prefix/npm/postpublish.js"
52
+ "prepublishOnly": "npx -y downdoc@latest --prepublish",
53
+ "postpublish": "npx -y downdoc@latest --postpublish"
49
54
  }
50
55
  }