Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Print Derived Configuration Report (#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
  • Loading branch information
mcknasty committed Jan 20, 2024
commit 1325a092200aba9d09675818fee80daa4eb06d21
9 changes: 9 additions & 0 deletions c8-ascii-art.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/* ________/\\\\\\\\\_ _____/\\\\\\\\\____ */
/* _____/\\\////////__ ___/\\\///////\\\__ */
/* ___/\\\/___________ __\/\\\_____\/\\\__ */
/* __/\\\_____________ __\///\\\\\\\\\/___ */
/* _\/\\\_____________ ___/\\\///////\\\__ */
/* _\//\\\____________ __/\\\______\//\\\_ */
/* __\///\\\__________ _\//\\\______/\\\__ */
/* ____\////\\\\\\\\\_ __\///\\\\\\\\\/___ */
/* _______\/////////__ ____\/////////_____ */
140 changes: 139 additions & 1 deletion lib/parse-args.js
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,17 @@ function buildYargs (withCommands = false) {
describe: 'supplying --merge-async will merge all v8 coverage reports asynchronously and incrementally. ' +
'This is to avoid OOM issues with Node.js runtime.'
})
.options('print-config', {
default: false,
type: 'boolean',
describe: 'Print the derived configuration between command line parameters and loaded configuration file'
})
.options('print-config-format', {
default: 'text',
type: 'string',
describe: 'Format to print the configuration in. Accepted formats are either text or json'
})
.pkgConf('c8')
.demandCommand(1)
.check((argv) => {
if (!argv.tempDirectory) {
argv.tempDirectory = resolve(argv.reportsDir, 'tmp')
Expand All @@ -181,6 +190,38 @@ function buildYargs (withCommands = false) {
// }
// })

const argv = process.argv.slice(2)
const checkArgs = parser(argv)

let shouldPrint = false

if (Object.keys(checkArgs).includes('print-config')) {
// checkArgs['print-config'] could contain a boolean or a string
// representing a boolean.
if (typeof checkArgs['print-config'] === 'boolean') {
shouldPrint = checkArgs['print-config']
} else if (typeof checkArgs['print-config'] === 'string') {
shouldPrint = JSON.parse(checkArgs['print-config'])
}
}

if (shouldPrint) {
const commandExecutedReference = 'c8 ' + argv.join(' ')
const args = yargs.parse(hideInstrumenteeArgs())
const cleanArgs = cleanUpArgumentArray(args)

if (args.printConfigFormat === 'text') {
printConfigText(cleanArgs, commandExecutedReference)
} else if (checkArgs.printConfigFormat === 'json') {
const jsonYargs = JSON.stringify(cleanArgs, 2)
console.log(jsonYargs)
}

process.exit()
}

yargs.demandCommand(1)

const checkCoverage = require('./commands/check-coverage')
const report = require('./commands/report')
if (withCommands) {
Expand Down Expand Up @@ -217,6 +258,103 @@ function hideInstrumenteeArgs () {
return argv
}

// Todo: Take a look at Optimizing this function
// exclude certain temporary values and duplicates from printing
// the same variable will be included twice with different keys
// for example args['temp-directory'] && args['tempDirectory']
// are essentially the same variable
function cleanUpArgumentArray (args) {
const argsToPrint = {}
Object.keys(args).forEach(v => {
if (v && v.length > 1 && v !== '_' && v !== '$0') {
// See if we are dealing with a Camel Case key string
const matches = [...v.matchAll(/([A-Z])/g)]
if (matches.length > 0) {
matches.forEach(m => {
// Derive Kebab Case string from Camel Case Key string
const newKey = m.input.replace(/([A-Z])/g, '-$1').toLowerCase()
// If the Kebab Case key is not assigned a value
if (!args[newKey]) {
// Then assigned it the Camel Case Variable
argsToPrint[newKey] = args[v]
} else if (!args[v]) {
// Other wise assign keep the Kebab Case key value
argsToPrint[newKey] = args[newKey]
}
})
} else {
// Just keep the value. Either Kebab case or otherwise
argsToPrint[v] = args[v]
}
}
})

return argsToPrint
}

function printConfigText (argsv, commandExecutedReference) {
const banner = readFileSync('./c8-ascii-art.txt', 'utf-8')
console.log('\n\n')
console.log(banner)
console.log('\n\n')
console.log('Command Issued: ' + commandExecutedReference)
console.log('Config File Loaded: ' + argsv.config + '\n\n\n')
console.log('Derived Configuration from CLI options and configuration file')
console.log('------------------------------------------------------------------------------')

const addSpace = (numOfSpace) => {
let space = ''
for (let i = 0; i < numOfSpace; i++) space += ' '
const s = space
return s
}

// Including some formatting variables
// for spacing to make the output more readable
let output = ''
let spaceLength = Object.keys(argsv)
.map(v => String(v).length)
.reduce((p, c) => {
return (p >= c) ? p : c
})
spaceLength += 10

// For each configuration value, print pretty
Object.keys(argsv).forEach(v => {
const fillSpace = addSpace(spaceLength - v.length)
const enumSpace = addSpace(spaceLength)
const value = formatPrintVariable(argsv[v], enumSpace)
output += String(v) + ':' + fillSpace + value + '\n'
})
console.log(output)
}

function formatPrintVariable (variable, space) {
let value

if (Array.isArray(variable) && variable.length > 0) {
value = stringifyObject(variable, space, ']')
} else if (typeof variable === 'object' && Object.keys(variable).length > 0) {
value = stringifyObject(variable, space, '}')
} else if (typeof variable === 'string' && variable) {
value = "'" + variable + "'"
} else if (typeof variable === 'string' && !variable) {
value = "''"
} else {
value = variable
}

return value
}

function stringifyObject (variable, space, closingChar) {
const closeReg = new RegExp('\n' + closingChar, 'g')
const out = JSON.stringify(variable, null, '\t\t\t\t ')
.replace(closeReg, '\n' + space + ' ' + closingChar)

return out
}

module.exports = {
buildYargs,
hideInstrumenterArgs,
Expand Down
Loading