Skip to content

Commit fc43c0b

Browse files
committed
Print Derived Configuration Report (bcoe#516)
feat: print derived config variables feat: print derived config variables in json test: 12 new unit tests to support features test: 1 skipped unit test for discovered bug in yargs with reports param
1 parent 5e18365 commit fc43c0b

File tree

7 files changed

+973
-3385
lines changed

7 files changed

+973
-3385
lines changed

c8-ascii-art.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/* ________/\\\\\\\\\_ _____/\\\\\\\\\____ */
2+
/* _____/\\\////////__ ___/\\\///////\\\__ */
3+
/* ___/\\\/___________ __\/\\\_____\/\\\__ */
4+
/* __/\\\_____________ __\///\\\\\\\\\/___ */
5+
/* _\/\\\_____________ ___/\\\///////\\\__ */
6+
/* _\//\\\____________ __/\\\______\//\\\_ */
7+
/* __\///\\\__________ _\//\\\______/\\\__ */
8+
/* ____\////\\\\\\\\\_ __\///\\\\\\\\\/___ */
9+
/* _______\/////////__ ____\/////////_____ */

lib/parse-args.js

Lines changed: 154 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,17 @@ function buildYargs (withCommands = false) {
158158
describe: 'supplying --merge-async will merge all v8 coverage reports asynchronously and incrementally. ' +
159159
'This is to avoid OOM issues with Node.js runtime.'
160160
})
161+
.options('print-config', {
162+
default: false,
163+
type: 'boolean',
164+
describe: 'Print the derived configuration between command line parameters and loaded configuration file'
165+
})
166+
.options('print-config-format', {
167+
default: 'text',
168+
type: 'string',
169+
describe: 'Format to print the configuration in. Accepted formats are either text or json'
170+
})
161171
.pkgConf('c8')
162-
.demandCommand(1)
163172
.check((argv) => {
164173
if (!argv.tempDirectory) {
165174
argv.tempDirectory = resolve(argv.reportsDir, 'tmp')
@@ -181,6 +190,38 @@ function buildYargs (withCommands = false) {
181190
// }
182191
// })
183192

193+
const argv = process.argv.slice(2)
194+
const checkArgs = parser(argv)
195+
196+
let shouldPrint = false
197+
198+
if (Object.keys(checkArgs).includes('print-config')) {
199+
// checkArgs['print-config'] could contain a boolean or a string
200+
// representing a boolean.
201+
if (typeof checkArgs['print-config'] === 'boolean') {
202+
shouldPrint = checkArgs['print-config']
203+
} else if (typeof checkArgs['print-config'] === 'string') {
204+
shouldPrint = JSON.parse(checkArgs['print-config'])
205+
}
206+
}
207+
208+
if (shouldPrint) {
209+
const commandExecutedReference = 'c8 ' + argv.join(' ')
210+
const args = yargs.parse(hideInstrumenteeArgs())
211+
const cleanArgs = cleanUpArgumentArray(args)
212+
213+
if (args.printConfigFormat === 'text') {
214+
printConfigText(cleanArgs, commandExecutedReference)
215+
} else if (checkArgs.printConfigFormat === 'json') {
216+
const jsonYargs = JSON.stringify(cleanArgs, 2)
217+
console.log(jsonYargs)
218+
}
219+
220+
process.exit()
221+
}
222+
223+
yargs.demandCommand(1)
224+
184225
const checkCoverage = require('./commands/check-coverage')
185226
const report = require('./commands/report')
186227
if (withCommands) {
@@ -217,6 +258,118 @@ function hideInstrumenteeArgs () {
217258
return argv
218259
}
219260

261+
function cleanUpArgumentArray (args) {
262+
// exclude certain temporary values and duplicates from printing
263+
// the same variable will be included twice with different keys
264+
// for example args['temp-directory'] && args['tempDirectory']
265+
// are essentially the same variable
266+
const argsToPrint = {}
267+
Object.keys(args).forEach(v => {
268+
if (v && v.length > 1 && v !== '_' && v !== '$0') {
269+
const matches = [...v.matchAll(/([A-Z])/g)]
270+
if (matches.length > 0) {
271+
matches.forEach(m => {
272+
const newKey = m.input.replace(/([A-Z])/g, '-$1').toLowerCase()
273+
if (!args[newKey]) {
274+
argsToPrint[newKey] = args[v]
275+
} else if (!args[v]) {
276+
argsToPrint[newKey] = args[newKey]
277+
}
278+
})
279+
} else {
280+
argsToPrint[v] = args[v]
281+
}
282+
}
283+
})
284+
285+
return argsToPrint
286+
}
287+
288+
function printConfigText (argsv, commandExecutedReference) {
289+
const banner = readFileSync('./c8-ascii-art.txt', 'utf-8')
290+
console.log('\n\n')
291+
console.log(banner)
292+
console.log('\n\n')
293+
console.log('Command Issued: ' + commandExecutedReference)
294+
console.log('Config File Loaded: ' + argsv.config + '\n\n\n')
295+
console.log('Derived Configuration from CLI options and configuration file')
296+
console.log('------------------------------------------------------------------------------')
297+
298+
const addSpace = (numOfSpace) => {
299+
let space = ''
300+
for (let i = 0; i < numOfSpace; i++) space += ' '
301+
const s = space
302+
return s
303+
}
304+
305+
// Including some formatting variable
306+
// to make out the output readable
307+
let output = ''
308+
let spaceLength = Object.keys(argsv)
309+
.map(v => String(v).length)
310+
.reduce((p, c) => {
311+
return (p >= c) ? p : c
312+
})
313+
spaceLength += 10
314+
315+
Object.keys(argsv).forEach(v => {
316+
const fillSpace = addSpace(spaceLength - v.length)
317+
const enumSpace = addSpace(spaceLength)
318+
const value = formatPrintVariable(argsv[v], enumSpace)
319+
output += String(v) + ':' + fillSpace + value + '\n'
320+
})
321+
console.log(output)
322+
}
323+
324+
function formatPrintVariable (variable, space) {
325+
let value
326+
327+
if (Array.isArray(variable) || typeof variable === 'object') {
328+
let varLength = 0
329+
let openingChar = ''
330+
let closingChar = ''
331+
332+
if (typeof variable === 'object' && Object.keys(variable).length > 0) {
333+
openingChar = '{'
334+
closingChar = '}'
335+
varLength = Object.keys(variable).length
336+
}
337+
338+
if (Array.isArray(variable) && variable.length > 0) {
339+
openingChar = '['
340+
closingChar = ']'
341+
varLength = variable.length
342+
}
343+
344+
if (varLength > 0) {
345+
value = JSON.stringify(variable, null, '\t')
346+
.replaceAll(
347+
openingChar + ',\n\t"',
348+
space + openingChar + ',\n\n\t"'
349+
).replaceAll(
350+
closingChar,
351+
space + ' ' + closingChar
352+
)
353+
.replaceAll(
354+
'\n\t"',
355+
'\n' + space + ' "'
356+
)
357+
} else {
358+
value = JSON.stringify(variable, null, '\t')
359+
}
360+
} else if (typeof variable === 'string') {
361+
if (variable) {
362+
value = "'" + variable + "'"
363+
} else {
364+
value = "''"
365+
}
366+
} else {
367+
value = variable
368+
}
369+
370+
return value
371+
}
372+
220373
module.exports = {
221374
buildYargs,
222375
hideInstrumenterArgs,

0 commit comments

Comments
 (0)