vnopts
validate and normalize options
Changelog
Install
npm install vnopts
Usage
import * as vnopts from 'vnopts'
const schemas = [
vnopts.ChoiceSchema.create({
name: 'parser',
choices: ['babylon', 'flow', 'typescript'],
}),
vnopts.BooleanSchema.create({
name: 'useFlowParser',
deprecated: true,
redirect: value =>
!value ? undefined : { to: { key: 'parser', value: 'flow' } },
}),
]
vnopts.normalize({ useFlowParser: true }, schemas)
vnopts.normalize({ parser: 'none' }, schemas)
vnopts.normalize({ parserr: 'typescript' }, schemas)
API
Normalizer
function normalize(
options: object,
schemas: Schema[],
opts?: NormalizerOptions,
): object
class Normalizer {
constructor(schemas: Schema[], opts?: NormalizerOptions)
normalize(options: object): object
cleanHistory(): void
}
interface NormalizerOptions {
logger?: Logger | false
loggerPrintWidth?: number
descriptor?: Descriptor
unknown?: UnknownHandler
invalid?: InvalidHandler
deprecated?: DeprecatedHandler
missing?: IdentifyMissing
required?: IdentifyRequired
preprocess?: (options: Options, utils: Utils) => Options
postprocess?: (
options: Options,
utils: Utils,
) => typeof VALUE_UNCHANGED | { delete?: string[]; override?: Options }
}
Logger
Defaults to console
.
interface Logger {
warn(message: string): void
}
Descriptor
Defaults to apiDescriptor
.
interface Descriptor {
key: (key: string) => string
value: (value: any) => string
pair: (pair: { key: string; value: any }) => string
}
UnknownHandler
Defaults to levenUnknownHandler
.
type UnknownHandler = (key: string, value: any, utils: Utils) => void | object
The returned object will be merged into the output object (and validate its value if the key is known).
InvalidHandler
Defaults to commonInvalidHandler
.
type InvalidHandler = (
key: string,
value: OptionValue,
utils: Utils,
) => string | Error
Returns an error message or the error itself.
DeprecatedHandler
Defaults to commonDeprecatedHandler
.
type DeprecatedHandler = (
keyOrPair: string | { key: string; value: any },
redirectToKeyOrPair: undefined | string | { key: string; value: any },
utils: Utils,
) => string
Returns a deprecation warning.
IdentifyMissing
Defaults to () => false
.
type IdentifyMissing = (key: string, options: Options) => boolean
Returns a boolean to indicate if key
is missing in options
.
(!(key in options)
is always considered missing.)
IdentifyRequired
Defaults to () => false
.
type IdentifyRequired = (key: string) => boolean
Returns a boolean to indicate if key
is required in the output.
Schemas
AnySchema
interface AnySchemaParameters extends SchemaHandlers {
name: string
}
const schemas = [vnopts.AnySchema.create({ name: 'any' })]
vnopts.normalize({ any: 'hello world' }, schemas)
vnopts.normalize({ unknown: 'hello world' }, schemas)
BooleanSchema
interface BooleanSchemaParameters extends SchemaHandlers {
name: string
}
const schemas = [vnopts.BooleanSchema.create({ name: 'bool' })]
vnopts.normalize({ bool: true }, schemas)
vnopts.normalize({ bool: 'hello world' }, schemas)
NumberSchema
interface NumberSchemaParameters extends SchemaHandlers {
name: string
}
const schemas = [vnopts.NumberSchema.create({ name: 'num' })]
vnopts.normalize({ num: 1 }, schemas)
vnopts.normalize({ num: null }, schemas)
IntegerSchema
interface IntegerSchemaParameters extends SchemaHandlers {
name: string
}
const schemas = [vnopts.IntegerSchema.create({ name: 'int' })]
vnopts.normalize({ int: 1 }, schemas)
vnopts.normalize({ int: 1.5 }, schemas)
StringSchema
interface StringSchemaParameters extends SchemaHandlers {
name: string
}
const schemas = [vnopts.StringSchema.create({ name: 'str' })]
vnopts.normalize({ str: 'hi' }, schemas)
vnopts.normalize({ str: true }, schemas)
ChoiceSchema
interface ChoiceSchemaParameters extends SchemaHandlers {
name: string
choices: Array<
| undefined
| null
| boolean
| number
| string
| {
value: undefined | null | boolean | number | string
deprecated?: boolean
hidden?: boolean
redirect?: string | { key: string; value: any }
forward?: string | { key: string; value: any }
}
>
}
const schemas = [
vnopts.ChoiceSchema.create({ name: 'choice', choices: [2, false, 'hey'] }),
]
vnopts.normalize({ choice: 2 }, schemas)
vnopts.normalize({ choice: true }, schemas)
AliasSchema
AliasSchema
validates values using the validator from the source schema and redirects all the value to the source key.
interface AliasSchemaParameters extends SchemaHandlers {
name: string
sourceName: string
}
const schemas = [
vnopts.BooleanSchema.create({ name: 'source' }),
vnopts.AliasSchema.create({ name: 'alias', sourceName: 'source' }),
]
vnopts.normalize({ alias: true }, schemas)
vnopts.normalize({ alias: 'invalid' }, schemas)
ArraySchema
AliasSchema
validates values using the validator from the source schema and redirects all the value to the source key.
interface ArraySchemaParameters extends SchemaHandlers {
name?: string
valueSchema: Schema
}
const schemas = [
vnopts.ArraySchema.create({
valueSchema: vnopts.ChoiceSchema.create({
name: 'choices',
choices: [1, true, 'foo'],
}),
}),
]
vnopts.normalize({ choices: [1, 'foo'] }, schemas)
vnopts.normalize({ choices: 1 }, schemas)
Handlers
Every schema has its own handlers but you can still override/extend them.
interface SchemaHandlers {
default?: SchemaDefaultHandler
expected?: SchemaExpectedHandler
validate?: SchemaValidateHandler
deprecated?: SchemaDeprecateHandler
forward?: SchemaForwardHandler
redirect?: SchemaRedirectHandler
overlap?: SchemaOverlapHandler
preprocess?: SchemaPreprocessHandler
postprocess?: SchemaPostprocessHandler
}
default
type SchemaDefaultHandler =
| DefaultResult
| ((schema: Schema, utils: Utils) => DefaultResult)
type DefaultResult = undefined | { value?: any }
undefined
represents no default value,
default values are wrapped in an object's value
field
to avoid the ambiguity between missing and undefined
.
expected
type SchemaExpectedHandler =
| ExpectedResult
| ((schema: Schema, utils: Utils) => ExpectedResult)
type ExpectedResult =
| string
| { text: string }
| {
text?: string
list: {
title: string
values: ExpectedResult[]
}
}
Returns the description for the expected value in the form of text and/or list.
For example the following ExpectedResult
:
{
"list": {
"title": "one of the following values",
"values": ["foo", "bar", "baz"]
}
}
will produce the following message in commonInvalidHandler
:
Invalid `<key>` value. Expected `one of the following values`, but received `<value>`.
- `"foo"`
- `"bar"`
- `"baz"`
If both text
and list
are returned,
text
will be chosen if its width is the minimum one or its width is less than loggerPrintWidth
,
otherwise list
.
validate
type SchemaValidateHandler =
| ValidateResult
| ((value: unknown, schema: Schema, utils: Utils) => ValidateResult)
type ValidateResult = boolean | { value: unknown }
Returns a boolean represents if the entire value is valid,
or put the invalid value in an object's value
field if only part of the value is invalid,
this is useful for collection schema like ArraySchema
.
deprecated
type SchemaDeprecatedHandler =
| DeprecatedResult
| ((value: unknown, schema: Schema, utils: Utils) => DeprecatedResult)
type DeprecatedResult = boolean | { value: any } | Array<{ value: any }>
Returns true
if the entire key is deprecated, false
if it's not deprecated,
or (an array of) an object with value
field if only part of the value is deprecated,
one object corresponds to one deprecation warning.
forward
type SchemaForwardHandler =
| ForwardResult
| ((value: any, schema: Schema, utils: Utils) => ForwardResult)
type TransferTo = string | { key: string; value: any }
type TransferResult = TransferTo | { from?: any; to: TransferTo }
type ForwardResult = undefined | TransferResult | Array<TransferResult>
Returns a key or a key-value pair if the entire value needs to be forwarded there,
or (an array of) an object with from
/to
field if only part of the value needs to be forwarded.
redirect
type SchemaRedirectHandler =
| RedirectResult
| ((value: any, schema: Schema, utils: Utils) => RedirectResult)
type RedirectResult =
| ForwardResult
| {
remain?: any
redirect: ForwardResult
}
Similar to forward
but returns an object with remain
/redirect
field if not the entire value needs to be redirected.
overlap
type SchemaOverlapHandler = (
currentValue: any,
newValue: any,
schema: Schema,
utils: Utils,
) => any
Describes what should the normalizer do if there're multiple values assigned to the same key.
preprocess
type SchemaPreprocessHandler = (
value: unknown,
schema: Schema,
utils: Utils,
) => unknown
The preprocess before passing into the validator.
postprocess
type SchemaPostprocessHandler = (
value: unknown,
schema: Schema,
utils: Utils,
) => unknown
The postprocess after normalization.
Development
pnpm run lint
pnpm run build
pnpm run test
License
MIT © Ika