@antora/playbook-builder 3.0.0-alpha.6 → 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
@@ -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,10 +1,9 @@
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
- const { hasOwnProperty } = Object.prototype
8
7
  const ospath = require('path')
9
8
 
10
9
  /**
@@ -22,14 +21,15 @@ const ospath = require('path')
22
21
  * option flags and switches. Should begin with the first flag or switch.
23
22
  * @param {Object} [env={}] - A map of environment variables.
24
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.
25
26
  *
26
27
  * @returns {Object} A playbook object containing a hierarchical structure that
27
28
  * mirrors the configuration schema. With the exception of the top-level asciidoc
28
29
  * key and its descendants, all keys in the playbook are camelCased.
29
30
  */
30
- function buildPlaybook (args = [], env = {}, schema = undefined) {
31
+ function buildPlaybook (args = [], env = {}, schema = undefined, beforeValidate = undefined) {
31
32
  const config = loadConvictConfig(args, env, schema)
32
-
33
33
  const relSpecFilePath = config.get('playbook')
34
34
  if (relSpecFilePath) {
35
35
  let absSpecFilePath = ospath.resolve(relSpecFilePath)
@@ -57,40 +57,50 @@ function buildPlaybook (args = [], env = {}, schema = undefined) {
57
57
  config.loadFile(absSpecFilePath)
58
58
  if (relSpecFilePath !== absSpecFilePath) config.set('playbook', absSpecFilePath)
59
59
  }
60
-
61
- config.validate({ allowed: 'strict' })
62
-
63
- return exportModel(config)
60
+ const beforeValidateFromSchema = config._def[Symbol.for('convict.beforeValidate')]
61
+ if (beforeValidateFromSchema) beforeValidateFromSchema(config)
62
+ if (beforeValidate) beforeValidate(config)
63
+ return config.getModel()
64
64
  }
65
65
 
66
66
  function loadConvictConfig (args, env, customSchema) {
67
- return convict(customSchema || require('./config/schema'), { args, env })
67
+ return Object.assign(convict(customSchema || defaultSchema, { args, env }), { getModel })
68
68
  }
69
69
 
70
- function freeze (o) {
71
- let v
72
- for (const k in o) hasOwnProperty.call(o, k) && (Object.isFrozen((v = o[k])) || freeze(v))
73
- return Object.freeze(o)
70
+ function getModel (name = '') {
71
+ let config = this
72
+ const data = config.get(name)
73
+ let schema = config._schema
74
+ if (name) {
75
+ schema = name.split('.').reduce((accum, key) => accum._cvtProperties[key], schema)
76
+ config = Object.assign(convict(name.split('.').reduce((def, key) => def[key], config._def)), { _instance: data })
77
+ }
78
+ config.validate({ allowed: 'strict' })
79
+ const model = camelCaseKeys(data, { deep: true, stopPaths: getStopPaths(schema._cvtProperties) })
80
+ if (!name) {
81
+ Object.defineProperty(model, 'env', { value: config.getEnv() })
82
+ model.dir = model.playbook ? ospath.dirname((model.file = model.playbook)) : process.cwd()
83
+ delete model.playbook
84
+ }
85
+ return deepFreeze(model)
74
86
  }
75
87
 
76
- function exportModel (config) {
77
- const schemaProperties = config._schema._cvtProperties
78
- const data = config.getProperties()
79
- if (
80
- 'site' in schemaProperties &&
81
- 'keys' in schemaProperties.site._cvtProperties &&
82
- '__private__google_analytics_key' in schemaProperties.site._cvtProperties
83
- ) {
84
- const site = data.site
85
- if (site.__private__google_analytics_key != null) site.keys.google_analytics = site.__private__google_analytics_key
86
- delete site.__private__google_analytics_key
88
+ function getStopPaths (schemaProperties, schemaPath = [], stopPaths = []) {
89
+ for (const [key, { preserve, _cvtProperties }] of Object.entries(schemaProperties)) {
90
+ if (preserve) {
91
+ Array.isArray(preserve)
92
+ ? preserve.forEach((it) => stopPaths.push(schemaPath.concat(key, it).join('.')))
93
+ : stopPaths.push(schemaPath.concat(key).join('.'))
94
+ } else if (_cvtProperties) {
95
+ stopPaths.push(...getStopPaths(_cvtProperties, schemaPath.concat(key)))
96
+ }
87
97
  }
88
- const playbook = camelCaseKeys(data, { deep: true, stopPaths: ['asciidoc'] })
89
- playbook.dir = playbook.playbook ? ospath.dirname((playbook.file = playbook.playbook)) : process.cwd()
90
- delete playbook.playbook
91
- const log = (playbook.runtime || {}).log
92
- if (log) configureLogger(playbook.runtime.silent ? (log.level = 'silent') && log : log)
93
- return freeze(playbook)
98
+ return stopPaths
99
+ }
100
+
101
+ function deepFreeze (o) {
102
+ for (const v of Object.values(o)) Object.isFrozen(v) || deepFreeze(v)
103
+ return Object.freeze(o)
94
104
  }
95
105
 
96
- module.exports = buildPlaybook
106
+ module.exports = Object.assign(buildPlaybook, { defaultSchema })
@@ -7,6 +7,23 @@ module.exports = {
7
7
  default: undefined,
8
8
  arg: 'playbook',
9
9
  },
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
+ },
17
+ extensions: {
18
+ doc:
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.',
21
+ format: 'require-array',
22
+ default: [],
23
+ arg: 'extension',
24
+ preserve: ['data'],
25
+ },
26
+ },
10
27
  site: {
11
28
  start_page: {
12
29
  doc: 'The start page for the site, redirected from the site index.',
@@ -54,7 +71,7 @@ module.exports = {
54
71
  branches: {
55
72
  doc: 'The default branch pattern to use when no specific pattern is provided.',
56
73
  format: Array,
57
- default: ['HEAD', 'v*'],
74
+ default: ['HEAD', 'v{0..9}*'],
58
75
  },
59
76
  edit_url: {
60
77
  doc: 'The default edit URL setting when no specific setting is provided.',
@@ -62,9 +79,10 @@ module.exports = {
62
79
  default: true,
63
80
  },
64
81
  sources: {
65
- doc: 'The list of git repositories + branch patterns to use.',
82
+ doc: 'The list of git repository urls, references, and start paths to use as content sources.',
66
83
  format: Array,
67
84
  default: [],
85
+ preserve: ['version'],
68
86
  },
69
87
  tags: {
70
88
  doc: 'The default tag pattern to use when no specific pattern is provided.',
@@ -113,12 +131,21 @@ module.exports = {
113
131
  format: 'map',
114
132
  default: {},
115
133
  arg: 'attribute',
134
+ preserve: true,
116
135
  },
117
136
  extensions: {
118
- doc: 'A list of require paths for registering extensions per instance of the AsciiDoc processor.',
137
+ doc:
138
+ 'A list of extensions to register either globally or per instance of the AsciiDoc processor. ' +
139
+ 'Each extension is specified as a require request string.',
119
140
  format: Array,
120
141
  default: [],
121
142
  },
143
+ sourcemap: {
144
+ doc: 'Enables the sourcemap option on the AsciiDoc processor, which adds file and line information to blocks.',
145
+ format: Boolean,
146
+ default: false,
147
+ arg: 'asciidoc-sourcemap',
148
+ },
122
149
  },
123
150
  git: {
124
151
  credentials: {
@@ -141,6 +168,23 @@ module.exports = {
141
168
  format: Boolean,
142
169
  default: true,
143
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
+ },
176
+ plugins: {
177
+ credential_manager: {
178
+ doc: 'A require request for a plugin to replace the built-in credential manager used by the git client.',
179
+ format: String,
180
+ default: undefined,
181
+ },
182
+ http: {
183
+ doc: 'A require request for a plugin to replace the built-in HTTP client used by the git client.',
184
+ format: String,
185
+ default: undefined,
186
+ },
187
+ },
144
188
  },
145
189
  network: {
146
190
  http_proxy: {
@@ -199,31 +243,59 @@ module.exports = {
199
243
  arg: 'log-level',
200
244
  env: 'ANTORA_LOG_LEVEL',
201
245
  },
246
+ level_format: {
247
+ doc: 'Set the format to use for the log level in structured log messages.',
248
+ format: ['number', 'label'],
249
+ default: 'label',
250
+ arg: 'log-level-format',
251
+ env: 'ANTORA_LOG_LEVEL_FORMAT',
252
+ },
202
253
  failure_level: {
203
254
  doc: 'Set the log level tolerance that, when exceeded, will cause the application to fail on exit.',
204
- format: ['all', 'debug', 'info', 'warn', 'error', 'fatal', 'silent'],
205
- default: undefined,
206
- arg: 'failure-level',
255
+ format: ['warn', 'error', 'fatal', 'none'],
256
+ default: 'fatal',
257
+ arg: 'log-failure-level',
207
258
  env: 'ANTORA_LOG_FAILURE_LEVEL',
208
259
  },
209
260
  format: new Proxy(
210
261
  {
211
- doc: 'Set the format of log messages. (default: structured if CI=true, pretty otherwise)',
212
- format: ['pretty', 'structured', 'json'],
262
+ doc: 'Set the format of log messages. Defaults to json if CI=true, pretty otherwise.',
263
+ format: ['json', 'pretty'],
213
264
  default: undefined,
214
265
  arg: 'log-format',
215
266
  env: 'ANTORA_LOG_FORMAT',
216
267
  },
217
268
  {
218
269
  get (target, property) {
219
- return property === 'default'
220
- ? process.env.CI === 'true' || process.env.NODE_ENV === 'test'
221
- ? 'structured'
222
- : 'pretty'
223
- : target[property]
270
+ if (property !== 'default') return target[property]
271
+ return process.env.CI === 'true' || process.env.NODE_ENV === 'test' ? 'json' : 'pretty'
224
272
  },
225
273
  }
226
274
  ),
275
+ destination: {
276
+ file: {
277
+ doc: 'Write log messages to this file or stream. Defaults to stderr if format is pretty, stdout otherwise.',
278
+ format: String,
279
+ default: undefined,
280
+ arg: 'log-file',
281
+ env: 'ANTORA_LOG_FILE',
282
+ },
283
+ append: {
284
+ doc: 'Whether to append messages to the log file if it already exists.',
285
+ format: Boolean,
286
+ default: true,
287
+ },
288
+ buffer_size: {
289
+ doc: 'The size of the log buffer that must be exceeded before writing a chunk to the destination.',
290
+ format: 'int',
291
+ default: 0,
292
+ },
293
+ sync: {
294
+ doc: 'Whether to immediately flush messages to the destination when the buffer size is exceeded.',
295
+ format: Boolean,
296
+ default: true,
297
+ },
298
+ },
227
299
  },
228
300
  },
229
301
  urls: {
@@ -250,7 +322,7 @@ module.exports = {
250
322
  },
251
323
  redirect_facility: {
252
324
  doc: 'The facility for handling page alias and start page redirections.',
253
- format: ['disabled', 'httpd', 'netlify', 'nginx', 'static'],
325
+ format: ['disabled', 'gitlab', 'httpd', 'netlify', 'nginx', 'static'],
254
326
  default: 'static',
255
327
  arg: 'redirect-facility',
256
328
  },
@@ -274,4 +346,15 @@ module.exports = {
274
346
  default: undefined,
275
347
  },
276
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
+ },
277
360
  }
@@ -85,6 +85,25 @@ function registerFormats (convict) {
85
85
  return accum
86
86
  },
87
87
  })
88
+ convict.addFormat({
89
+ name: 'require-array',
90
+ validate: (val) => {
91
+ if (!Array.isArray(val)) throw new Error('must be of type Array')
92
+ },
93
+ coerce: (val, config, name) => {
94
+ const accum = config && config.has(name) ? config.get(name) : []
95
+ val.split(',').forEach((v) => {
96
+ if (~accum.indexOf(v)) return
97
+ const match = accum.find((it) => it.constructor === Object && it.id === v)
98
+ if (match) {
99
+ if (match.enabled === false) match.enabled = true
100
+ } else {
101
+ accum.push(v)
102
+ }
103
+ })
104
+ return accum
105
+ },
106
+ })
88
107
  convict.addFormat({
89
108
  name: 'boolean-or-string',
90
109
  validate: (val) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@antora/playbook-builder",
3
- "version": "3.0.0-alpha.6",
3
+ "version": "3.0.0-beta.1",
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.6",
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": "38ec002e88eede3ce5c401a6e226d1a0356945c5"
39
+ "gitHead": "7c5ef1ea93dd489af533c80a936c736013c41769"
41
40
  }