Skip to content

Commit

Permalink
Add validate()
Browse files Browse the repository at this point in the history
  • Loading branch information
ehmicky committed Jan 23, 2022
1 parent 3f7f892 commit 8485a2a
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 78 deletions.
7 changes: 5 additions & 2 deletions src/config/normalize/check.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,11 @@ export const normalizeOptionalArray = function (value = []) {
return Array.isArray(value) ? [...new Set(value)] : [value]
}

export const checkArrayLength = function (value) {
assert(value.length !== 0, 'must not be an empty array')
export const checkEmptyArray = function (value) {
assert(
!Array.isArray(value) || value.length !== 0,
'must not be an empty array',
)
}

export const checkObject = function (value) {
Expand Down
12 changes: 11 additions & 1 deletion src/config/normalize/lib/definitions.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const getPathKey = function ({ key }) {

const applyDefinition = async function (
{ value, skipped },
{ condition, default: defaultValue, compute, transform },
{ condition, default: defaultValue, compute, validate, transform },
opts,
) {
if (await againstCondition(value, condition, opts)) {
Expand All @@ -47,6 +47,7 @@ const applyDefinition = async function (

const valueA = await addDefaultValue(value, defaultValue, opts)
const valueB = await computeValue(valueA, compute, opts)
await validateValue(valueB, validate, opts)
const valueC = await transformValue(valueB, transform, opts)
return { value: valueC, skipped: false }
}
Expand All @@ -70,6 +71,15 @@ const computeValue = async function (value, compute, opts) {
return compute === undefined ? value : await callUserFunc(compute, opts)
}

// Apply `validate(opts)` which throws on validation errors
const validateValue = async function (value, validate, opts) {
if (value === undefined || validate === undefined) {
return
}

await callValueFunc(validate, value, opts)
}

// Apply `transform(value)` which transforms the value set by the user
const transformValue = async function (value, transform, opts) {
if (value === undefined || transform === undefined) {
Expand Down
115 changes: 50 additions & 65 deletions src/config/normalize/prop_defs.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
checkInteger,
checkString,
normalizeOptionalArray,
checkArrayLength,
checkEmptyArray,
checkDefinedString,
checkJson,
checkObject,
Expand All @@ -41,87 +41,79 @@ const boundAmongCommands = function (

const config = {
condition: amongCommands(['dev', 'remove', 'run', 'show']),
async default() {
return await getDefaultConfig()
},
transform(value) {
return normalizeOptionalArray(value)
},
default: getDefaultConfig,
transform: normalizeOptionalArray,
}

const configAny = {
condition: amongCommands(['dev', 'remove', 'run', 'show']),
transform: checkDefinedString,
validate: checkDefinedString,
}

const colors = {
condition: amongCommands(['remove', 'run', 'show']),
transform: checkBoolean,
validate: checkBoolean,
}

const cwd = {
condition: amongCommands(['dev', 'remove', 'run', 'show']),
default() {
return getCwd()
},
default: getCwd,
validate: checkDefinedString,
transform(value, { name, context: { configInfos } }) {
checkDefinedString(value)
return normalizeConfigPath(value, name, configInfos)
},
}

const delta = {
condition: amongCommands(['remove', 'show']),
default: 1,
transform(value, { name }) {
return transformDelta(value, name)
},
transform: transformDelta,
}

const force = {
condition: amongCommands(['remove']),
default() {
return !isTtyInput()
},
transform: checkBoolean,
validate: checkBoolean,
}

const inputs = {
condition: amongCommands(['dev', 'run']),
default: {},
transform: checkObject,
validate: checkObject,
}

const inputsAny = {
condition: amongCommands(['dev', 'run']),
transform: checkJson,
validate: checkJson,
}

const limit = {
condition: amongCommands(['remove', 'run', 'show']),
validate(value, { name }) {
recurseConfigSelectors(value, name, checkInteger)
},
transform(value, { name }) {
return recurseConfigSelectors(value, name, (childValue, childName) => {
checkInteger(childValue)
return transformLimit(childValue, childName)
})
return recurseConfigSelectors(value, name, (childValue, childName) =>
transformLimit(childValue, childName),
)
},
}

const merge = {
condition: amongCommands(['run']),
default() {
return getDefaultId()
},
transform(value, { name }) {
default: getDefaultId,
validate(value) {
checkDefinedString(value)
validateMerge(value, name)
validateMerge(value)
},
}

const output = {
condition: amongCommands(['remove', 'run', 'show']),
validate: checkDefinedString,
transform(value, { name, context: { configInfos } }) {
checkDefinedString(value)
return isOutputPath(value)
? normalizeConfigPath(value, name, configInfos)
: value
Expand All @@ -131,25 +123,27 @@ const output = {
const outliers = {
condition: amongCommands(['run']),
default: false,
transform(value, { name }) {
validate(value, { name }) {
recurseConfigSelectors(value, name, checkBoolean)
},
}

const precision = {
condition: amongCommands(['run']),
default: 5,
validate(value, { name }) {
recurseConfigSelectors(value, name, checkInteger)
},
transform(value, { name }) {
return recurseConfigSelectors(value, name, (childValue, childName) => {
checkInteger(childValue)
return transformPrecision(childValue, childName)
})
return recurseConfigSelectors(value, name, (childValue, childName) =>
transformPrecision(childValue, childName),
)
},
}

const quiet = {
condition: amongCommands(['run']),
transform: checkBoolean,
validate: checkBoolean,
}

const reporter = [
Expand All @@ -170,13 +164,13 @@ const reporter = [

const reporterAny = {
condition: amongCommands(['remove', 'run', 'show']),
transform: checkDefinedString,
validate: checkDefinedString,
}

const reporterConfig = {
condition: amongCommands(['remove', 'run', 'show']),
default: {},
transform: checkObject,
validate: checkObject,
}

const runner = {
Expand All @@ -186,46 +180,41 @@ const runner = {
// file, instead of to an optional one. This makes behavior easier to
// understand for users and provides with better error messages.
default: ['node'],
transform(value) {
const valueA = normalizeOptionalArray(value)
checkArrayLength(valueA)
return valueA
},
validate: checkEmptyArray,
transform: normalizeOptionalArray,
}

const runnerAny = {
condition: amongCommands(['dev', 'run']),
transform: checkDefinedString,
validate: checkDefinedString,
}

const runnerConfig = {
condition: amongCommands(['dev', 'run']),
default: {},
transform: checkObject,
validate: checkObject,
}

const save = {
condition: amongCommands(['run']),
default: false,
transform: checkBoolean,
validate: checkBoolean,
}

const select = {
condition: amongCommands(['dev', 'remove', 'run', 'show']),
default: [],
transform(value) {
return normalizeOptionalArray(value)
},
transform: normalizeOptionalArray,
}

const selectAny = {
condition: amongCommands(['dev', 'remove', 'run', 'show']),
transform: checkString,
validate: checkString,
}

const showDiff = {
condition: amongCommands(['remove', 'run', 'show']),
transform(value, { name }) {
validate(value, { name }) {
recurseConfigSelectors(value, name, checkBoolean)
},
}
Expand All @@ -235,74 +224,70 @@ const showMetadata = {
default({ context: { command } }) {
return command !== 'run'
},
transform: checkBoolean,
validate: checkBoolean,
}

const showPrecision = {
condition: amongCommands(['remove', 'run', 'show']),
default: false,
transform(value, { name }) {
validate(value, { name }) {
recurseConfigSelectors(value, name, checkBoolean)
},
}

const showSystem = {
condition: amongCommands(['remove', 'run', 'show']),
transform: checkBoolean,
validate: checkBoolean,
}

const showTitles = {
condition: amongCommands(['remove', 'run', 'show']),
default: false,
transform(value, { name }) {
validate(value, { name }) {
recurseConfigSelectors(value, name, checkBoolean)
},
}

const since = {
condition: amongCommands(['remove', 'run', 'show']),
default: 1,
transform(value, { name }) {
return transformDelta(value, name)
},
transform: transformDelta,
}

const system = {
condition: amongCommands(['dev', 'run']),
default: {},
transform: checkObject,
validate: checkObject,
}

const systemAny = {
condition: amongCommands(['dev', 'run']),
transform: checkDefinedString,
validate: checkDefinedString,
}

const tasks = {
condition: amongCommands(['dev', 'run']),
default: [],
transform(value) {
return normalizeOptionalArray(value)
},
transform: normalizeOptionalArray,
}

const tasksAny = {
condition: amongCommands(['dev', 'run']),
validate: checkDefinedString,
async transform(value, { name, context: { configInfos } }) {
checkDefinedString(value)
return await normalizeConfigGlob(value, name, configInfos)
},
}

const titles = {
condition: amongCommands(['remove', 'run', 'show']),
default: {},
transform: checkObject,
validate: checkObject,
}

const titlesAny = {
condition: amongCommands(['remove', 'run', 'show']),
transform: checkDefinedString,
validate: checkDefinedString,
}

export const DEFINITIONS = {
Expand Down
2 changes: 1 addition & 1 deletion src/history/delta/transform.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { FORMATS } from './formats/main.js'
// Several configuration properties targets a previous rawResult using a delta,
// which can an integer, "first", date/time/duration, rawResult.id or git
// reference.
export const transformDelta = function (delta, name) {
export const transformDelta = function (delta, { name }) {
if (delta === '') {
const deltaProp = getDeltaProp(delta, name)
throw new UserError(`${deltaProp} must not be an empty string`)
Expand Down
16 changes: 7 additions & 9 deletions src/history/merge/id.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
import { inspect } from 'util'
// eslint-disable-next-line no-restricted-imports, node/no-restricted-import
import assert from 'assert'

import { v4 as uuidv4, validate as isUuid } from 'uuid'

import { UserError } from '../../error/main.js'

// Validate `merge` property
export const validateMerge = function (value, name) {
if (!isValidId(value) && value !== LAST_ID) {
throw new UserError(
`'${name}' must be "${LAST_ID}" or a UUID: ${inspect(value)}`,
)
}
export const validateMerge = function (value) {
assert(
isValidId(value) || value === LAST_ID,
`must be "${LAST_ID}" or a UUID`,
)
}

// Validate `result.id`.
Expand Down

0 comments on commit 8485a2a

Please sign in to comment.