@antora/playbook-builder 3.2.0-alpha.8 → 3.2.0-rc.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/lib/build-playbook.js +67 -8
- package/lib/config/schema.js +6 -1
- package/lib/solitary-convict.js +69 -30
- package/package.json +4 -4
package/lib/build-playbook.js
CHANGED
|
@@ -4,6 +4,7 @@ const convict = require('./solitary-convict')
|
|
|
4
4
|
const defaultSchema = require('./config/schema')
|
|
5
5
|
const fs = require('node:fs')
|
|
6
6
|
const ospath = require('node:path')
|
|
7
|
+
const yaml = require('js-yaml')
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Builds a playbook object according to the provided schema from the specified
|
|
@@ -28,8 +29,22 @@ const ospath = require('node:path')
|
|
|
28
29
|
* marked in the schema as preserve, all keys in the playbook are camelCased.
|
|
29
30
|
*/
|
|
30
31
|
function buildPlaybook (args = [], env = process.env, schema = defaultSchema, beforeValidate = undefined) {
|
|
31
|
-
const
|
|
32
|
-
const
|
|
32
|
+
const parsedArgs = args.length ? parseArgs(args) : {}
|
|
33
|
+
const opts = { args: [], env: {} }
|
|
34
|
+
const config = Object.assign(convict(schema, opts), { getModel, getSchema })
|
|
35
|
+
Object.assign(opts, { args, env })
|
|
36
|
+
let playbook
|
|
37
|
+
if ('playbook' in schema) {
|
|
38
|
+
const playbookEnv = schema.playbook.env
|
|
39
|
+
if (playbookEnv != null) playbook = env[playbookEnv]
|
|
40
|
+
const playbookArg = schema.playbook.arg
|
|
41
|
+
if (playbookArg != null) playbook = parsedArgs[playbookArg] ?? playbook
|
|
42
|
+
if (playbook === undefined) {
|
|
43
|
+
if (config.has('playbook')) playbook = config.get('playbook')
|
|
44
|
+
} else {
|
|
45
|
+
config.set('playbook', playbook)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
33
48
|
let absPlaybookPath
|
|
34
49
|
if (playbook) {
|
|
35
50
|
if (ospath.extname((absPlaybookPath = ospath.resolve(playbook)))) {
|
|
@@ -50,10 +65,11 @@ function buildPlaybook (args = [], env = process.env, schema = defaultSchema, be
|
|
|
50
65
|
}
|
|
51
66
|
}
|
|
52
67
|
try {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
68
|
+
Object.assign(opts, { args: [] })
|
|
69
|
+
playbook ? config.loadFile(absPlaybookPath) : config.load({})
|
|
70
|
+
importArguments(config, parsedArgs)
|
|
71
|
+
Object.assign(opts, { args })
|
|
72
|
+
if (playbook && playbook !== absPlaybookPath) config.set('playbook', absPlaybookPath)
|
|
57
73
|
const beforeValidateFromSchema = config._def[Symbol.for('convict.beforeValidate')]
|
|
58
74
|
if (beforeValidateFromSchema) beforeValidateFromSchema(config)
|
|
59
75
|
if (beforeValidate) beforeValidate(config)
|
|
@@ -82,9 +98,8 @@ function camelCaseKeys (o, stopPaths = [], p = '') {
|
|
|
82
98
|
function getModel (name) {
|
|
83
99
|
let config = this
|
|
84
100
|
const data = config.get(name)
|
|
85
|
-
|
|
101
|
+
const schema = config.getSchema(name)
|
|
86
102
|
if (name) {
|
|
87
|
-
schema = name.split('.').reduce((accum, key) => accum._cvtProperties[key], schema)
|
|
88
103
|
config = Object.assign(convict(name.split('.').reduce((def, key) => def[key], config._def)), { _instance: data })
|
|
89
104
|
}
|
|
90
105
|
config.validate({ allowed: 'strict' })
|
|
@@ -97,6 +112,10 @@ function getModel (name) {
|
|
|
97
112
|
return model
|
|
98
113
|
}
|
|
99
114
|
|
|
115
|
+
function getSchema (name) {
|
|
116
|
+
return name ? name.split('.').reduce((accum, key) => accum._cvtProperties[key], this._schema) : this._schema
|
|
117
|
+
}
|
|
118
|
+
|
|
100
119
|
function getStopPaths (schemaProperties, schemaPath = [], stopPaths = []) {
|
|
101
120
|
for (const [key, { preserve, _cvtProperties }] of Object.entries(schemaProperties)) {
|
|
102
121
|
if (preserve) {
|
|
@@ -110,9 +129,49 @@ function getStopPaths (schemaProperties, schemaPath = [], stopPaths = []) {
|
|
|
110
129
|
return stopPaths
|
|
111
130
|
}
|
|
112
131
|
|
|
132
|
+
function importArguments (config, args) {
|
|
133
|
+
for (const [argName, configKey] of Object.entries(config._argv)) {
|
|
134
|
+
const argVal = args[argName]
|
|
135
|
+
if (argVal === undefined) continue
|
|
136
|
+
const argFormat = config.getSchema(configKey).format
|
|
137
|
+
let argValStr = argVal
|
|
138
|
+
if (argFormat === 'map' || argFormat === 'primitive-map') {
|
|
139
|
+
const dumpOpts = { condenseFlow: true, flowLevel: 0, noCompatMode: true, quotingType: '"' }
|
|
140
|
+
argValStr = yaml.dump(Array.isArray(argVal) ? argVal : [argVal], dumpOpts)
|
|
141
|
+
} else if (Array.isArray(argVal)) {
|
|
142
|
+
argValStr = argVal.join(',')
|
|
143
|
+
}
|
|
144
|
+
config.set(configKey, argValStr)
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
113
148
|
function getDetails (playbook, absPlaybookPath) {
|
|
114
149
|
if (playbook === absPlaybookPath) return ''
|
|
115
150
|
return ` (${ospath.isAbsolute(playbook) ? '' : 'cwd: ' + process.cwd() + ', '}playbook: ${playbook})`
|
|
116
151
|
}
|
|
117
152
|
|
|
153
|
+
function parseArgs (args) {
|
|
154
|
+
let currentOptionName
|
|
155
|
+
return Object.assign(
|
|
156
|
+
args.reduce((accum, it) => {
|
|
157
|
+
if (it.startsWith('--') && it !== '--') {
|
|
158
|
+
if (currentOptionName) accum[currentOptionName] = true
|
|
159
|
+
currentOptionName = it.substring(2)
|
|
160
|
+
} else if (currentOptionName) {
|
|
161
|
+
const currentOptionValue = accum[currentOptionName]
|
|
162
|
+
if (currentOptionValue == null || currentOptionValue === true) {
|
|
163
|
+
accum[currentOptionName] = it
|
|
164
|
+
} else if (currentOptionValue.constructor === Array) {
|
|
165
|
+
currentOptionValue.push(it)
|
|
166
|
+
} else {
|
|
167
|
+
accum[currentOptionName] = [currentOptionValue, it]
|
|
168
|
+
}
|
|
169
|
+
currentOptionName = undefined
|
|
170
|
+
}
|
|
171
|
+
return accum
|
|
172
|
+
}, {}),
|
|
173
|
+
currentOptionName ? { [currentOptionName]: true } : undefined
|
|
174
|
+
)
|
|
175
|
+
}
|
|
176
|
+
|
|
118
177
|
module.exports = Object.assign(buildPlaybook, { defaultSchema })
|
package/lib/config/schema.js
CHANGED
|
@@ -86,6 +86,11 @@ module.exports = {
|
|
|
86
86
|
format: 'array-or-string',
|
|
87
87
|
default: undefined,
|
|
88
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
|
+
},
|
|
89
94
|
},
|
|
90
95
|
ui: {
|
|
91
96
|
bundle: {
|
|
@@ -245,7 +250,7 @@ module.exports = {
|
|
|
245
250
|
log: {
|
|
246
251
|
level: {
|
|
247
252
|
doc: 'Set the minimum log level of messages that get logged.',
|
|
248
|
-
format: ['all', 'debug', 'info', 'warn', 'error', 'fatal', 'silent'],
|
|
253
|
+
format: ['all', 'trace', 'debug', 'info', 'warn', 'error', 'fatal', 'silent'],
|
|
249
254
|
default: 'warn',
|
|
250
255
|
arg: 'log-level',
|
|
251
256
|
env: 'ANTORA_LOG_LEVEL',
|
package/lib/solitary-convict.js
CHANGED
|
@@ -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
|
|
@@ -43,6 +44,14 @@ function registerFormats (convict) {
|
|
|
43
44
|
}
|
|
44
45
|
},
|
|
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
|
+
})
|
|
46
55
|
convict.addFormat({
|
|
47
56
|
name: 'map',
|
|
48
57
|
validate: (val) => {
|
|
@@ -51,16 +60,23 @@ function registerFormats (convict) {
|
|
|
51
60
|
coerce: (val, config, name) => {
|
|
52
61
|
if (config == null) return val
|
|
53
62
|
const accum = config.has(name) ? config.get(name) : {}
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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.substring(0, equalsIdx))) continue
|
|
70
|
+
v = entry.substring(equalsIdx + 1)
|
|
71
|
+
}
|
|
59
72
|
let parsed = v
|
|
60
|
-
if (
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
73
|
+
if (v) {
|
|
74
|
+
const match = v.match(YAML_PREFIX_RX)
|
|
75
|
+
if (match) {
|
|
76
|
+
try {
|
|
77
|
+
parsed = yaml.load(match[1] === 'auto' ? v.substring(7) : v, { schema: yaml.CORE_SCHEMA })
|
|
78
|
+
} catch {}
|
|
79
|
+
}
|
|
64
80
|
}
|
|
65
81
|
accum[k] = parsed
|
|
66
82
|
}
|
|
@@ -83,20 +99,26 @@ function registerFormats (convict) {
|
|
|
83
99
|
coerce: (val, config, name) => {
|
|
84
100
|
if (config == null) return val
|
|
85
101
|
const accum = config.has(name) ? config.get(name) : {}
|
|
86
|
-
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
if (
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
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.substring(0, equalsIdx))) continue
|
|
109
|
+
v = entry.substring(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.substring(7) : v, { schema: yaml.CORE_SCHEMA })
|
|
117
|
+
if (parsed && !~PRIMITIVE_TYPES.indexOf(parsed.constructor)) parsed = v
|
|
118
|
+
} catch {}
|
|
97
119
|
}
|
|
98
|
-
accum[~k.indexOf('-') ? k.replace(/-/g, '_') : k] = parsed
|
|
99
120
|
}
|
|
121
|
+
accum[~k.indexOf('-') ? k.replace(/-/g, '_') : k] = parsed
|
|
100
122
|
}
|
|
101
123
|
return accum
|
|
102
124
|
},
|
|
@@ -108,16 +130,30 @@ function registerFormats (convict) {
|
|
|
108
130
|
},
|
|
109
131
|
coerce: (val, config, name) => {
|
|
110
132
|
const accum = config?.has(name) ? config.get(name) : []
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
133
|
+
const byId = {}
|
|
134
|
+
const byRequire = {}
|
|
135
|
+
let orderIdx = 0
|
|
136
|
+
const order = new Map()
|
|
137
|
+
for (const [idx, it] of accum.entries()) {
|
|
138
|
+
const ext = it.constructor === Object ? it : (accum[idx] = { require: it })
|
|
139
|
+
byRequire[ext.require] ??= ext
|
|
140
|
+
if ('id' in ext) byId[ext.id] ??= ext
|
|
141
|
+
order.set(it, orderIdx++)
|
|
142
|
+
}
|
|
143
|
+
for (let request of val.split(',')) {
|
|
144
|
+
const enable = request.charAt() === '!' ? (request = request.substring(1)) == null : true
|
|
145
|
+
let match
|
|
146
|
+
if ((match = byId[request] ?? byRequire[request])) {
|
|
147
|
+
if ((match.enabled ?? true) !== enable) match.enabled = enable
|
|
116
148
|
} else {
|
|
117
|
-
accum.push(
|
|
149
|
+
accum.push((match = byRequire[request] = { require: request }))
|
|
150
|
+
if (!enable) match.enabled = false
|
|
118
151
|
}
|
|
119
|
-
|
|
152
|
+
if ((match.order ?? 'auto') === 'auto') order.set(match, orderIdx++)
|
|
153
|
+
}
|
|
120
154
|
return accum
|
|
155
|
+
.sort((a, b) => order.get(a) - order.get(b))
|
|
156
|
+
.map((it) => (Object.keys(it).length === 1 && 'require' in it ? it.require : it))
|
|
121
157
|
},
|
|
122
158
|
})
|
|
123
159
|
convict.addFormat({
|
|
@@ -166,7 +202,10 @@ function registerFormats (convict) {
|
|
|
166
202
|
}
|
|
167
203
|
if (~parsedUrl.pathname.indexOf('%20')) throw new Error('pathname segment must not contain spaces')
|
|
168
204
|
},
|
|
169
|
-
coerce: (val) =>
|
|
205
|
+
coerce: (val) => {
|
|
206
|
+
if (!val || val === '~') return null
|
|
207
|
+
return val.length > 1 && val.charAt(val.length - 1) === '/' ? val.substring(0, val.length - 1) : val
|
|
208
|
+
},
|
|
170
209
|
})
|
|
171
210
|
}
|
|
172
211
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@antora/playbook-builder",
|
|
3
|
-
"version": "3.2.0-
|
|
3
|
+
"version": "3.2.0-rc.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)",
|
|
@@ -29,11 +29,11 @@
|
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@iarna/toml": "~2.2",
|
|
31
31
|
"convict": "~6.2",
|
|
32
|
-
"js-yaml": "~4.
|
|
32
|
+
"js-yaml": "~4.2",
|
|
33
33
|
"json5": "~2.2"
|
|
34
34
|
},
|
|
35
35
|
"engines": {
|
|
36
|
-
"node": ">=
|
|
36
|
+
"node": ">=20.0.0"
|
|
37
37
|
},
|
|
38
38
|
"files": [
|
|
39
39
|
"lib/"
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"web publishing"
|
|
48
48
|
],
|
|
49
49
|
"scripts": {
|
|
50
|
-
"test": "
|
|
50
|
+
"test": "node --test",
|
|
51
51
|
"prepublishOnly": "npx -y downdoc@latest --prepublish",
|
|
52
52
|
"postpublish": "npx -y downdoc@latest --postpublish"
|
|
53
53
|
}
|