Skip to content

Commit

Permalink
Use imperative code
Browse files Browse the repository at this point in the history
  • Loading branch information
ehmicky committed Jan 16, 2022
1 parent babadac commit 0819f80
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 114 deletions.
16 changes: 5 additions & 11 deletions src/config/check.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,29 @@ import isPlainObj from 'is-plain-obj'
import mapObj from 'map-obj'

import { UserError } from '../error/main.js'
import { curry, runNormalizer } from '../utils/functional.js'
import { runNormalizer } from '../utils/functional.js'

// Configuration validation helper functions
// eslint-disable-next-line max-params
export const checkArrayItems = function (checker, value, name, ...args) {
export const checkArrayItems = function (value, name, checker) {
checkArray(value, name)
return value.flatMap((item, index) =>
runNormalizer(checker, item, getIndexName(name, index, value), ...args),
runNormalizer(checker, item, getIndexName(name, index, value)),
)
}

export const cCheckArrayItems = curry(checkArrayItems)

// When array has a single item, it is possible that the value was arrified
const getIndexName = function (name, index, value) {
return value.length === 1 ? name : `${name}[${index}]`
}

// eslint-disable-next-line max-params
export const checkObjectProps = function (checker, value, name, ...args) {
export const checkObjectProps = function (value, name, checker) {
checkObject(value, name)
return mapObj(value, (childName, childValue) => [
childName,
runNormalizer(checker, childValue, `${name}.${childName}`, ...args),
runNormalizer(checker, childValue, `${name}.${childName}`),
])
}

export const cCheckObjectProps = curry(checkObjectProps)

export const checkBoolean = function (value, name) {
if (typeof value !== 'boolean') {
throw new UserError(`'${name}' must be true or false: ${inspect(value)}`)
Expand Down
4 changes: 2 additions & 2 deletions src/config/load/info.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ import { resolveConfigPath } from './resolve.js'
// the `config` top-level flag programmatically.
export const getConfigsInfos = async function (config, base) {
const configs = normalizeOptionalArray(config)
checkArrayItems(checkDefinedString, configs, 'config')
checkArrayItems(configs, 'config', checkDefinedString)
const configInfos = await Promise.all(
configs.map((configA) => getConfigInfos(configA, base)),
configs.map((configB) => getConfigInfos(configB, base)),
)
return configInfos.flat()
}
Expand Down
8 changes: 6 additions & 2 deletions src/config/plugin/config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { cleanObject } from '../../utils/clean.js'
import { pick } from '../../utils/pick.js'
import { checkObjectProps, cCheckObjectProps, checkJson } from '../check.js'
import { checkObjectProps, checkJson } from '../check.js'
import { mergeConfigs } from '../merge/main.js'

// Retrieve plugin configuration object.
Expand Down Expand Up @@ -47,12 +47,16 @@ export const addPluginsConfig = function ({
topProps,
}) {
const pluginsConfig = config[configProp]
checkObjectProps(cCheckObjectProps(checkJson), pluginsConfig, configProp)
checkObjectProps(pluginsConfig, configProp, checkPluginConfig)
return plugins.map((plugin) =>
addPluginConfig({ plugin, pluginsConfig, config, topProps }),
)
}

const checkPluginConfig = function (pluginConfig, configPropFull) {
checkObjectProps(pluginConfig, configPropFull, checkJson)
}

const addPluginConfig = function ({
plugin,
plugin: { id },
Expand Down
167 changes: 117 additions & 50 deletions src/config/properties.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,146 +4,213 @@ import { normalizeDelta } from '../history/delta/normalize.js'
import { validateMerge } from '../history/merge/id.js'
import { isOutputPath } from '../report/output.js'
import { normalizePrecision } from '../run/precision.js'
import { condition, composeNormalizers } from '../utils/functional.js'

import {
checkBoolean,
checkInteger,
checkString,
normalizeOptionalArray,
cCheckArrayItems,
checkArrayItems,
checkArrayLength,
cCheckObjectProps,
checkObjectProps,
checkDefinedString,
checkJson,
} from './check.js'
import { normalizeConfigPath, normalizeConfigGlob } from './path.js'
import { cRecurseConfigSelectors } from './select/normalize.js'
import { recurseConfigSelectors } from './select/normalize.js'

export const CONFIG_PROPS = {
colors: {
commands: 'report',
normalize: checkBoolean,
normalize(value, name) {
checkBoolean(value, name)
},
},
cwd: {
commands: 'all',
normalize: composeNormalizers(checkDefinedString, normalizeConfigPath),
normalize(value, name, configInfos) {
checkDefinedString(value, name)
return normalizeConfigPath(value, name, configInfos)
},
},
delta: {
commands: 'delta',
normalize: normalizeDelta,
normalize(value, name) {
return normalizeDelta(value, name)
},
},
force: {
commands: 'remove',
normalize: checkBoolean,
normalize(value, name) {
checkBoolean(value, name)
},
},
inputs: {
commands: 'combinations',
normalize: cCheckObjectProps(checkJson),
normalize(value, name) {
checkObjectProps(value, name, (childValue, childName) => {
checkJson(childValue, childName)
})
},
},
limit: {
commands: 'report',
normalize: cRecurseConfigSelectors(
composeNormalizers(checkInteger, normalizeLimit),
),
normalize(value, name) {
return recurseConfigSelectors(value, name, (childValue, childName) => {
checkInteger(childValue, childName)
return normalizeLimit(childValue, childName)
})
},
},
merge: {
commands: 'run',
normalize: composeNormalizers(checkDefinedString, validateMerge),
normalize(value, name) {
checkDefinedString(value, name)
validateMerge(value, name)
},
},
output: {
commands: 'report',
normalize: composeNormalizers(
checkDefinedString,
condition(normalizeConfigPath, isOutputPath),
),
normalize(value, name, configInfos) {
checkDefinedString(value, name)
return isOutputPath(value)
? normalizeConfigPath(value, name, configInfos)
: value
},
},
outliers: {
commands: 'run',
normalize: cRecurseConfigSelectors(checkBoolean),
normalize(value, name) {
recurseConfigSelectors(value, name, (childValue, childName) => {
checkBoolean(childValue, childName)
})
},
},
precision: {
commands: 'run',
normalize: cRecurseConfigSelectors(
composeNormalizers(checkInteger, normalizePrecision),
),
normalize(value, name) {
return recurseConfigSelectors(value, name, (childValue, childName) => {
checkInteger(childValue, childName)
return normalizePrecision(childValue, childName)
})
},
},
quiet: {
commands: 'run',
normalize: checkBoolean,
normalize(value, name) {
checkBoolean(value, name)
},
},
reporter: {
commands: 'report',
normalize: composeNormalizers(
normalizeOptionalArray,
cCheckArrayItems(checkDefinedString),
),
normalize(value, name) {
const valueA = normalizeOptionalArray(value)
checkArrayItems(valueA, name, (childValue, childName) => {
checkDefinedString(childValue, childName)
})
return valueA
},
},
reporterConfig: {
commands: 'report',
},
runner: {
commands: 'combinations',
normalize: composeNormalizers(
normalizeOptionalArray,
checkArrayLength,
cCheckArrayItems(checkDefinedString),
),
normalize(value, name) {
const valueA = normalizeOptionalArray(value)
checkArrayLength(valueA, name)
checkArrayItems(valueA, name, (childValue, childName) => {
checkDefinedString(childValue, childName)
})
return valueA
},
},
runnerConfig: {
commands: 'combinations',
},
save: {
commands: 'run',
normalize: checkBoolean,
normalize(value, name) {
checkBoolean(value, name)
},
},
select: {
commands: 'select',
normalize: composeNormalizers(
normalizeOptionalArray,
cCheckArrayItems(checkString),
),
normalize(value, name) {
const valueA = normalizeOptionalArray(value)
checkArrayItems(valueA, name, (childValue, childName) => {
checkString(childValue, childName)
})
return valueA
},
},
showDiff: {
commands: 'report',
normalize: cRecurseConfigSelectors(checkBoolean),
normalize(value, name) {
recurseConfigSelectors(value, name, (childValue, childName) => {
checkBoolean(childValue, childName)
})
},
},
showMetadata: {
commands: 'report',
normalize: checkBoolean,
normalize(value, name) {
checkBoolean(value, name)
},
},
showPrecision: {
commands: 'report',
normalize: cRecurseConfigSelectors(checkBoolean),
normalize(value, name) {
recurseConfigSelectors(value, name, (childValue, childName) => {
checkBoolean(childValue, childName)
})
},
},
showSystem: {
commands: 'report',
normalize: checkBoolean,
normalize(value, name) {
checkBoolean(value, name)
},
},
showTitles: {
commands: 'report',
normalize: cRecurseConfigSelectors(checkBoolean),
normalize(value, name) {
recurseConfigSelectors(value, name, (childValue, childName) => {
checkBoolean(childValue, childName)
})
},
},
since: {
commands: 'history',
normalize: normalizeDelta,
normalize(value, name) {
return normalizeDelta(value, name)
},
},
system: {
commands: 'combinations',
normalize: cCheckObjectProps(checkDefinedString),
normalize(value, name) {
checkObjectProps(value, name, (childValue, childName) => {
checkDefinedString(childValue, childName)
})
},
},
tasks: {
commands: 'combinations',
normalize: composeNormalizers(
normalizeOptionalArray,
cCheckArrayItems(
composeNormalizers(checkDefinedString, normalizeConfigGlob),
),
),
normalize(value, name, configInfos) {
const valueA = normalizeOptionalArray(value)
return checkArrayItems(valueA, name, (childValue, childName) => {
checkDefinedString(childValue, childName)
return normalizeConfigGlob(value, name, configInfos)
})
},
},
titles: {
commands: 'report',
normalize: cCheckObjectProps(checkDefinedString),
normalize(value, name) {
checkObjectProps(value, name, (childValue, childName) => {
checkDefinedString(childValue, childName)
})
},
},
}
/* eslint-enable max-lines */
10 changes: 3 additions & 7 deletions src/config/select/normalize.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,22 @@ import isPlainObj from 'is-plain-obj'
import mapObj from 'map-obj'

import { UserError } from '../../error/main.js'
import { curry } from '../../utils/functional.js'

// If a configuration property uses selectors, normalization must be applied
// recursively.
// eslint-disable-next-line max-params
const recurseConfigSelectors = function (callFunc, value, name, ...args) {
export const recurseConfigSelectors = function (value, name, callFunc) {
if (!isConfigSelectorShape(value)) {
return callFunc(value, name, ...args)
return callFunc(value, name)
}

validateConfigSelector(value, name)

return mapObj(value, (selector, childValue) => [
selector,
callFunc(childValue, `${name}.${selector}`, ...args),
callFunc(childValue, `${name}.${selector}`),
])
}

export const cRecurseConfigSelectors = curry(recurseConfigSelectors)

// We validate that at least one selector is named "default"
// - This ensures users understand that this selector is used as a fallback
// We recommend and document making it the last key
Expand Down
Loading

0 comments on commit 0819f80

Please sign in to comment.