@antora/playbook-builder 3.2.0-alpha.6 → 3.2.0-alpha.9

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.
@@ -4,6 +4,8 @@ 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 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
@@ -28,8 +30,22 @@ const ospath = require('node: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})`
@@ -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
@@ -51,16 +52,23 @@ function registerFormats (convict) {
51
52
  coerce: (val, config, name) => {
52
53
  if (config == null) return val
53
54
  const accum = config.has(name) ? config.get(name) : {}
54
- let match
55
- const scanner = new RegExp(ARGS_SCANNER_RX)
56
- while ((match = scanner.exec(val))) {
57
- const [, k, v = ''] = match
58
- if (!k) continue
55
+ const entries = yaml.load(val, { schema: COERCE_SCHEMA })
56
+ for (const entry of Array.isArray(entries) ? entries : [entries]) {
57
+ let k = entry
58
+ let v = ''
59
+ const equalsIdx = entry.indexOf('=')
60
+ if (~equalsIdx) {
61
+ if (!(k = entry.slice(0, equalsIdx))) continue
62
+ v = entry.slice(equalsIdx + 1)
63
+ }
59
64
  let parsed = v
60
- if (parsed && parsed !== '-') {
61
- try {
62
- parsed = yaml.load(v, { schema: yaml.CORE_SCHEMA })
63
- } catch {}
65
+ if (v) {
66
+ const match = v.match(YAML_PREFIX_RX)
67
+ if (match) {
68
+ try {
69
+ parsed = yaml.load(match[1] === 'auto' ? v.slice(7) : v, { schema: yaml.CORE_SCHEMA })
70
+ } catch {}
71
+ }
64
72
  }
65
73
  accum[k] = parsed
66
74
  }
@@ -83,20 +91,26 @@ function registerFormats (convict) {
83
91
  coerce: (val, config, name) => {
84
92
  if (config == null) return val
85
93
  const accum = config.has(name) ? config.get(name) : {}
86
- let match
87
- const scanner = new RegExp(ARGS_SCANNER_RX)
88
- while ((match = scanner.exec(val))) {
89
- const [, k, v] = match
90
- if (k) {
91
- let parsed
92
- if (v && v !== '-') {
93
- parsed = yaml.load(v, { schema: yaml.CORE_SCHEMA })
94
- if (parsed && PRIMITIVE_TYPES.indexOf(parsed.constructor) < 0) parsed = v
95
- } else {
96
- parsed = v || ''
94
+ const entries = yaml.load(val, { schema: COERCE_SCHEMA })
95
+ for (const entry of Array.isArray(entries) ? entries : [entries]) {
96
+ let k = entry
97
+ let v = ''
98
+ const equalsIdx = entry.indexOf('=')
99
+ if (~equalsIdx) {
100
+ if (!(k = entry.slice(0, equalsIdx))) continue
101
+ v = entry.slice(equalsIdx + 1)
102
+ }
103
+ let parsed = v
104
+ if (v) {
105
+ const match = v.match(YAML_PREFIX_RX)
106
+ if (match) {
107
+ try {
108
+ parsed = yaml.load(match[1] === 'auto' ? v.slice(7) : v, { schema: yaml.CORE_SCHEMA })
109
+ if (parsed && !~PRIMITIVE_TYPES.indexOf(parsed.constructor)) parsed = v
110
+ } catch {}
97
111
  }
98
- accum[~k.indexOf('-') ? k.replace(/-/g, '_') : k] = parsed
99
112
  }
113
+ accum[~k.indexOf('-') ? k.replace(/-/g, '_') : k] = parsed
100
114
  }
101
115
  return accum
102
116
  },
@@ -107,16 +121,16 @@ function registerFormats (convict) {
107
121
  if (!Array.isArray(val)) throw new Error('must be an array')
108
122
  },
109
123
  coerce: (val, config, name) => {
110
- const accum = config && config.has(name) ? config.get(name) : []
111
- val.split(',').forEach((v) => {
112
- if (~accum.indexOf(v)) return
124
+ const accum = config?.has(name) ? config.get(name) : []
125
+ for (const v of val.split(',')) {
126
+ if (~accum.indexOf(v)) continue
113
127
  const match = accum.find((it) => it.constructor === Object && it.id === v)
114
128
  if (match) {
115
129
  if (match.enabled === false) match.enabled = true
116
130
  } else {
117
131
  accum.push(v)
118
132
  }
119
- })
133
+ }
120
134
  return accum
121
135
  },
122
136
  })
@@ -166,7 +180,10 @@ function registerFormats (convict) {
166
180
  }
167
181
  if (~parsedUrl.pathname.indexOf('%20')) throw new Error('pathname segment must not contain spaces')
168
182
  },
169
- coerce: (val) => (val.length > 1 && val.charAt(val.length - 1) === '/' ? val.slice(0, -1) : val),
183
+ coerce: (val) => {
184
+ if (!val || val === '~') return null
185
+ return val.length > 1 && val.charAt(val.length - 1) === '/' ? val.slice(0, -1) : val
186
+ },
170
187
  })
171
188
  }
172
189
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@antora/playbook-builder",
3
- "version": "3.2.0-alpha.6",
3
+ "version": "3.2.0-alpha.9",
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,7 +30,8 @@
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
37
  "node": ">=18.0.0"