@antora/playbook-builder 3.0.0-alpha.8 → 3.0.0-beta.3

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
@@ -4,7 +4,7 @@ The Playbook Builder is the configuration component for Antora.
4
4
  It's responsible for building a playbook object from user input that's 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
- Its site generator pipeline aggregates documents from versioned content repositories and processes them using [Asciidoctor](https://asciidoctor.org).
7
+ Its site generator aggregates documents from versioned content repositories and processes them using [Asciidoctor](https://asciidoctor.org).
8
8
 
9
9
  ## Copyright and License
10
10
 
@@ -1,8 +1,8 @@
1
1
  'use strict'
2
2
 
3
3
  const camelCaseKeys = require('camelcase-keys')
4
- const { configureLogger } = require('@antora/logger')
5
4
  const convict = require('./solitary-convict')
5
+ const defaultSchema = require('./config/schema')
6
6
  const fs = require('fs')
7
7
  const ospath = require('path')
8
8
 
@@ -21,92 +21,96 @@ const ospath = require('path')
21
21
  * option flags and switches. Should begin with the first flag or switch.
22
22
  * @param {Object} [env={}] - A map of environment variables.
23
23
  * @param {Object} [schema=undefined] - A convict configuration schema.
24
+ * @param {Function} [beforeValidate=undefined] - A function to invoke on the
25
+ * config before validating it.
24
26
  *
25
27
  * @returns {Object} A playbook object containing a hierarchical structure that
26
- * mirrors the configuration schema. With the exception of the top-level asciidoc
27
- * key and its descendants, all keys in the playbook are camelCased.
28
+ * mirrors the configuration schema. With the exception of keys and descendants
29
+ * marked in the schema as preserve, all keys in the playbook are camelCased.
28
30
  */
29
- function buildPlaybook (args = [], env = {}, schema = undefined) {
31
+ function buildPlaybook (args = [], env = {}, schema = undefined, beforeValidate = undefined) {
30
32
  const config = loadConvictConfig(args, env, schema)
31
- const relSpecFilePath = config.get('playbook')
32
- if (relSpecFilePath) {
33
- let absSpecFilePath = ospath.resolve(relSpecFilePath)
34
- if (ospath.extname(absSpecFilePath)) {
35
- if (!fs.existsSync(absSpecFilePath)) {
36
- let details = ''
37
- if (relSpecFilePath !== absSpecFilePath) {
38
- details = ` (path: ${relSpecFilePath}${ospath.isAbsolute(relSpecFilePath) ? '' : ', cwd: ' + process.cwd()})`
39
- }
40
- throw new Error(`playbook file not found at ${absSpecFilePath}${details}`)
33
+ const playbook = config.get('playbook')
34
+ let absPlaybookPath
35
+ if (playbook) {
36
+ if (ospath.extname((absPlaybookPath = ospath.resolve(playbook)))) {
37
+ if (!fs.existsSync(absPlaybookPath)) {
38
+ throw new Error(`playbook file not found at ${absPlaybookPath}${getDetails(playbook, absPlaybookPath)}`)
41
39
  }
42
- } else if (fs.existsSync(absSpecFilePath + '.yml')) {
43
- absSpecFilePath += '.yml'
44
- } else if (fs.existsSync(absSpecFilePath + '.json')) {
45
- absSpecFilePath += '.json'
46
- } else if (fs.existsSync(absSpecFilePath + '.toml')) {
47
- absSpecFilePath += '.toml'
40
+ } else if (fs.existsSync(absPlaybookPath + '.yml')) {
41
+ absPlaybookPath += '.yml'
42
+ } else if (fs.existsSync(absPlaybookPath + '.json')) {
43
+ absPlaybookPath += '.json'
44
+ } else if (fs.existsSync(absPlaybookPath + '.toml')) {
45
+ absPlaybookPath += '.toml'
48
46
  } else {
49
- const details = `(path: ${relSpecFilePath}${ospath.isAbsolute(relSpecFilePath) ? '' : ', cwd: ' + process.cwd()})`
50
47
  throw new Error(
51
- `playbook file not found at ${absSpecFilePath}.yml, ${absSpecFilePath}.json, or ${absSpecFilePath}.toml ` +
52
- details
48
+ `playbook file not found at ${absPlaybookPath}.yml, ${absPlaybookPath}.json, or ${absPlaybookPath}.toml` +
49
+ getDetails(playbook, absPlaybookPath)
53
50
  )
54
51
  }
55
- config.loadFile(absSpecFilePath)
56
- if (relSpecFilePath !== absSpecFilePath) config.set('playbook', absSpecFilePath)
57
52
  }
58
- config.validate({ allowed: 'strict' })
59
- return exportModel(config)
53
+ try {
54
+ if (playbook) {
55
+ config.loadFile(absPlaybookPath)
56
+ if (playbook !== absPlaybookPath) config.set('playbook', absPlaybookPath)
57
+ }
58
+ const beforeValidateFromSchema = config._def[Symbol.for('convict.beforeValidate')]
59
+ if (beforeValidateFromSchema) beforeValidateFromSchema(config)
60
+ if (beforeValidate) beforeValidate(config)
61
+ return config.getModel()
62
+ } catch (err) {
63
+ if (!playbook) throw err
64
+ const message = err.message.replace(/( in the schema)?$/m, (_, inTheSchema) => {
65
+ return `${inTheSchema ? inTheSchema + ' for' : ' in'} ${absPlaybookPath}${getDetails(playbook, absPlaybookPath)}`
66
+ })
67
+ throw Object.assign(err, { message })
68
+ }
60
69
  }
61
70
 
62
71
  function loadConvictConfig (args, env, customSchema) {
63
- return convict(customSchema || require('./config/schema'), { args, env })
72
+ return Object.assign(convict(customSchema || defaultSchema, { args, env }), { getModel })
64
73
  }
65
74
 
66
- function deepFreeze (o) {
67
- for (const v of Object.values(o)) Object.isFrozen(v) || deepFreeze(v)
68
- return Object.freeze(o)
69
- }
70
-
71
- function exportModel (config) {
72
- const schemaProperties = config._schema._cvtProperties
73
- const data = config.getProperties()
74
- if (
75
- 'site' in schemaProperties &&
76
- 'keys' in schemaProperties.site._cvtProperties &&
77
- '__private__google_analytics_key' in schemaProperties.site._cvtProperties
78
- ) {
79
- const site = data.site
80
- if (site.__private__google_analytics_key != null) site.keys.google_analytics = site.__private__google_analytics_key
81
- delete site.__private__google_analytics_key
75
+ function getModel (name = '') {
76
+ let config = this
77
+ const data = config.get(name)
78
+ let schema = config._schema
79
+ if (name) {
80
+ schema = name.split('.').reduce((accum, key) => accum._cvtProperties[key], schema)
81
+ config = Object.assign(convict(name.split('.').reduce((def, key) => def[key], config._def)), { _instance: data })
82
82
  }
83
- const playbook = camelCaseKeys(data, { deep: true, stopPaths: getStopPaths(schemaProperties) })
84
- playbook.dir = playbook.playbook ? ospath.dirname((playbook.file = playbook.playbook)) : process.cwd()
85
- Object.defineProperty(playbook, 'env', { value: config.getEnv() })
86
- const runtime = (playbook.runtime || false).constructor === Object && playbook.runtime
87
- if (runtime) {
88
- const log = (runtime.log || false).constructor === Object && runtime.log
89
- if (runtime.silent) {
90
- if (runtime.quiet === false) runtime.quiet = true
91
- if (log && 'level' in log) log.level = 'silent'
92
- }
93
- if (log) configureLogger(log, playbook.dir)
83
+ config.validate({ allowed: 'strict' })
84
+ const model = camelCaseKeys(data, { deep: true, stopPaths: getStopPaths(schema._cvtProperties) })
85
+ if (!name) {
86
+ Object.defineProperty(model, 'env', { value: config.getEnv() })
87
+ model.dir = model.playbook ? ospath.dirname((model.file = model.playbook)) : process.cwd()
88
+ delete model.playbook
94
89
  }
95
- delete playbook.playbook
96
- return deepFreeze(playbook)
90
+ return deepFreeze(model)
97
91
  }
98
92
 
99
- function getStopPaths (schemaProperties, schemaPath = []) {
100
- const stopPaths = []
93
+ function getStopPaths (schemaProperties, schemaPath = [], stopPaths = []) {
101
94
  for (const [key, { preserve, _cvtProperties }] of Object.entries(schemaProperties)) {
102
95
  if (preserve) {
103
- return Array.isArray(preserve)
104
- ? preserve.reduce((accum, it) => accum.concat(schemaPath.concat(key, it).join('.')), stopPaths)
105
- : stopPaths.concat(schemaPath.concat(key).join('.'))
96
+ Array.isArray(preserve)
97
+ ? preserve.forEach((it) => stopPaths.push(schemaPath.concat(key, it).join('.')))
98
+ : stopPaths.push(schemaPath.concat(key).join('.'))
99
+ } else if (_cvtProperties) {
100
+ stopPaths.push(...getStopPaths(_cvtProperties, schemaPath.concat(key)))
106
101
  }
107
- if (_cvtProperties) stopPaths.push(...getStopPaths(_cvtProperties, schemaPath.concat(key)))
108
102
  }
109
103
  return stopPaths
110
104
  }
111
105
 
112
- module.exports = buildPlaybook
106
+ function deepFreeze (o) {
107
+ for (const v of Object.values(o)) Object.isFrozen(v) || deepFreeze(v)
108
+ return Object.freeze(o)
109
+ }
110
+
111
+ function getDetails (playbook, absPlaybookPath) {
112
+ if (playbook === absPlaybookPath) return ''
113
+ return ` (${ospath.isAbsolute(playbook) ? '' : 'cwd: ' + process.cwd() + ', '}playbook: ${playbook})`
114
+ }
115
+
116
+ module.exports = Object.assign(buildPlaybook, { defaultSchema })
@@ -7,10 +7,16 @@ module.exports = {
7
7
  default: undefined,
8
8
  arg: 'playbook',
9
9
  },
10
- pipeline: {
10
+ antora: {
11
+ generator: {
12
+ doc: 'A require request for the generator package name or script to use.',
13
+ format: String,
14
+ default: '@antora/site-generator-default',
15
+ arg: 'generator',
16
+ },
11
17
  extensions: {
12
18
  doc:
13
- 'A list of extensions that listen for pipeline events. ' +
19
+ 'A list of extensions that listen for lifecycle events. ' +
14
20
  'Each extension is specified as a require request string or an object with a require key.',
15
21
  format: 'require-array',
16
22
  default: [],
@@ -65,7 +71,7 @@ module.exports = {
65
71
  branches: {
66
72
  doc: 'The default branch pattern to use when no specific pattern is provided.',
67
73
  format: Array,
68
- default: ['HEAD', 'v*'],
74
+ default: ['HEAD', 'v{0..9}*'],
69
75
  },
70
76
  edit_url: {
71
77
  doc: 'The default edit URL setting when no specific setting is provided.',
@@ -76,6 +82,7 @@ module.exports = {
76
82
  doc: 'The list of git repository urls, references, and start paths to use as content sources.',
77
83
  format: Array,
78
84
  default: [],
85
+ preserve: ['version'],
79
86
  },
80
87
  tags: {
81
88
  doc: 'The default tag pattern to use when no specific pattern is provided.',
@@ -161,6 +168,11 @@ module.exports = {
161
168
  format: Boolean,
162
169
  default: true,
163
170
  },
171
+ fetch_concurrency: {
172
+ doc: 'The maximum number of fetch or clone operations that are permitted to run at once. Use 0 for unlimited.',
173
+ format: 'int',
174
+ default: 0,
175
+ },
164
176
  plugins: {
165
177
  credential_manager: {
166
178
  doc: 'A require request for a plugin to replace the built-in credential manager used by the git client.',
@@ -275,7 +287,7 @@ module.exports = {
275
287
  },
276
288
  buffer_size: {
277
289
  doc: 'The size of the log buffer that must be exceeded before writing a chunk to the destination.',
278
- format: Number,
290
+ format: 'int',
279
291
  default: 0,
280
292
  },
281
293
  sync: {
@@ -310,7 +322,7 @@ module.exports = {
310
322
  },
311
323
  redirect_facility: {
312
324
  doc: 'The facility for handling page alias and start page redirections.',
313
- format: ['disabled', 'httpd', 'netlify', 'nginx', 'static'],
325
+ format: ['disabled', 'gitlab', 'httpd', 'netlify', 'nginx', 'static'],
314
326
  default: 'static',
315
327
  arg: 'redirect-facility',
316
328
  },
@@ -334,4 +346,15 @@ module.exports = {
334
346
  default: undefined,
335
347
  },
336
348
  },
349
+ [Symbol.for('convict.beforeValidate')]: ({ _schema: schema, _instance: data }) => {
350
+ const runtime = data.runtime
351
+ if (runtime.silent) {
352
+ if (runtime.quiet === false) runtime.quiet = true
353
+ if (runtime.log.level !== 'silent') runtime.log.level = 'silent'
354
+ }
355
+ const site = data.site
356
+ if (site.__private__google_analytics_key != null) site.keys.google_analytics = site.__private__google_analytics_key
357
+ delete site.__private__google_analytics_key
358
+ delete schema._cvtProperties.site._cvtProperties.__private__google_analytics_key
359
+ },
337
360
  }
@@ -27,7 +27,7 @@ function registerParsers (convict) {
27
27
  {
28
28
  extension: '*',
29
29
  parse: () => {
30
- throw new Error('Unexpected playbook file type (must be yml, json, or toml')
30
+ throw new Error('Unknown playbook file extension: must be .yml (or .yaml), .json, or .toml')
31
31
  },
32
32
  },
33
33
  ])
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@antora/playbook-builder",
3
- "version": "3.0.0-alpha.8",
3
+ "version": "3.0.0-beta.3",
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)",
@@ -16,15 +16,14 @@
16
16
  },
17
17
  "main": "lib/index.js",
18
18
  "dependencies": {
19
- "@antora/logger": "3.0.0-alpha.8",
20
19
  "@iarna/toml": "~2.2",
21
- "camelcase-keys": "~6.2",
22
- "convict": "~6.1",
20
+ "camelcase-keys": "~7.0",
21
+ "convict": "~6.2",
23
22
  "js-yaml": "~4.1",
24
23
  "json5": "~2.2"
25
24
  },
26
25
  "engines": {
27
- "node": ">=10.17.0"
26
+ "node": ">=12.21.0"
28
27
  },
29
28
  "files": [
30
29
  "lib/"
@@ -37,5 +36,5 @@
37
36
  "static site",
38
37
  "web publishing"
39
38
  ],
40
- "gitHead": "2e5695bea11fb5719989c329c97e66d36e29659f"
39
+ "gitHead": "45da95a2e2dea538379d2d9f42013d2208fb86c3"
41
40
  }