/selective-option

A simple selective option resolver

Primary LanguageTypeScriptMIT LicenseMIT

Selective Option

CI NPM Version install size jsDelivr Libraries.io dependency status for GitHub repo Codecov Known Vulnerabilities

A simple selective option resolver

Version 0.1.0 is a complete rewrite. Please read the documentation before you consider to switch, many exports have been removed and new ones have been added. It is highly recommended to switch to 0.1.0, just read the documentation before you do.

In this page

Install

npm

npm install selective-option

yarn

yarn add selective-option

pnpm

pnpm add selective-option

CDN

jsDelivr

  • UMD
<script src="https://cdn.jsdelivr.net/npm/selective-option@latest/dist/umd/selective.umd.js"></script>
<script src="https://cdn.jsdelivr.net/npm/selective-option@latest/dist/umd/selective.umd.min.js"></script>
  • ES Module
<script type="module">
  import selective from "https://cdn.jsdelivr.net/npm/selective-option@latest/dist/esm/selective.mjs";
</script>
<script type="module">
  import selective from "https://cdn.jsdelivr.net/npm/selective-option@latest/dist/esm/selective.min.mjs";
</script>

more options...

unpkg

  • UMD
<script src="https://unpkg.com/selective-option@latest/dist/umd/selective.umd.js"></script>
<script src="https://unpkg.com/selective-option@latest/dist/umd/selective.umd.min.js"></script>
  • ES Module
<script type="module">
  import selective from "https://unpkg.com/selective-option@latest/dist/esm/selective.mjs";
</script>
<script type="module">
  import selective from "https://unpkg.com/selective-option@latest/dist/esm/selective.min.mjs";
</script>

more options...

API

function createValueBasedResolver

Creates a value based resolver. It resolves input as valid value (V), null, undefined, FunctionOption or ObjectOption. It internally uses createValueResolver, createFunctionResolver and createObjectResolver to create a Resolver using createResolver. See the examples for more info.

function createValueBasedResolver<K extends string, S extends string, V, O extends string, D = V>(
  keys: readonly K[],
  isValidValue: TypeCheckFunction<V>,
  defaultValue: D,
  overrideKey: O,
  special?: SpecialKeys<S, K> | null | undefined,
): ValueBasedResolver<K, S | O, V, D>;
  • Arguments
    • keys: An array of string to be used as keys in the final Resolved object. They will also be used to validate keys if input is an object.
    • isValidValue: A function which returns wether or not a value is valid.
    • defaultValue: A valid value to be used as default in case the value is nullish.
    • overrideKey: A string to be used to detect the override key if the input is an object.
    • special: An optional object mapping special keys to multiple regular keys. They can be used as keys if the input is an object.

See TypeCheckFunction, SpecialKeys and ValueBasedResolver.

  • Example
const resolveNumber = createValueBasedResolver(
  ['a', 'b', 'c'] as const,
  (value: unknown): value is number => typeof value === 'number',
  0,
  'override',
  { ac: ['a', 'c'] },
);

resolveNumber(18); // set value { a: 18, b: 18, c: 18 }
resolveNumber(true); // Throws because true doesn't pass the test
resolveNumber({}); // default value { a: 0, b: 0, c: 0 }
resolveNumber({ override: 40 }); // overridden value { a: 40, b: 40, c: 40 }
resolveNumber({ override: 'string' }); // Throws because 'string' doesn't pass the test
resolveNumber({ b: 40 }); // default + set value { a: 0, b: 40 c: 0 }
resolveNumber({ c: [] }); // Throws because [] doesn't pass the test
resolveNumber({ ac: 40 }); // default + special set value { a: 40, b: 0 c: 40 }
resolveNumber({ override: 40, a: 12 }); // overridden + set value { a: 12, b: 40, c: 40 }
resolveNumber({ override: 40, ac: 12 }); // overridden + special set value { a: 12, b: 40, c: 12 }
// ... you get the idea...

function createBoolBasedResolver

Creates a boolean based resolver. It resolves input as valid value (V), boolean, null, undefined, FunctionOption, KeyOption or ObjectOption. It internally uses createValueResolver, createFunctionResolver, createKeyResolver, createKeyListResolver and createObjectResolver to create a Resolver using createResolver. See the examples for more info.

function createBoolBasedResolver<K extends string, S extends string, V, O extends string, D = V>(
  keys: readonly K[],
  isValidValue: AllowNullish<TypeCheckFunction<V>>,
  defaultValue: D,
  overrideKey: O,
  special?: SpecialKeys<S, K> | null | undefined,
): BoolBasedResolver<K, S, V | boolean, O, D>;
  • Arguments
    • keys: An array of string to be used as keys in the final Resolved object. They will also be used to validate positive keys and negative keys if input is a string or an array, and to validate keys if input is an object.
    • isValidValue: A function which returns wether or not a value is valid. Note that this function doesn't need to test for boolean values as they will be included by default. If pass a nullish value it will only test for boolean values.
    • defaultValue: A valid value to be used as default in case the value is nullish.
    • overrideKey: A string to be used to detect the override key if the input is an object.
    • special: An optional object mapping special keys to multiple regular keys. They can be used as keys if the input is an object and as positive keys or negative keys if input is a string or an array.

See TypeCheckFunction, SpecialKeys and BoolBasedResolver.

  • Example
const resolve = createBoolBasedResolver(
  ['a', 'b', 'c'] as const,
  (value: unknown): value is ('yes' | 'not' | 'unknown') => {
    return ['yes', 'no', 'unknown'].includes(value as never);
  },
  'unknown',
  'default',
  { ab: ['a', 'b'] },
);

resolveEvenNumber(null); // default value { a: 'unknown', b: 'unknown', c: 'unknown' }
resolveEvenNumber('yes'); // set value { a: 'yes', b: 'yes', c: 'yes' }
resolveEvenNumber(17); // Throws because 17 doesn't pass the test
resolveEvenNumber('a'); // set key { a: true, b: false, c: false }
resolveEvenNumber('ab'); // set key { a: true, b: true, c: false }
resolveEvenNumber(['a', 'c']); // set key { a: true, b: false, c: true }
resolveEvenNumber(['a', 'b', 'c']); // set key { a: true, b: true, c: true }
resolveEvenNumber(['ab', 'c']); // set key { a: true, b: true, c: true }
resolveEvenNumber({}); // default value { a: 'unknown', b: 'unknown', c: 'unknown' }
resolveEvenNumber({ default: true }); // overridden value { a: true, b: true, c: true }
resolveEvenNumber({ default: 15 }); // Throws because 15 doesn't pass the test
resolveEvenNumber({ default: 'yes', a: true }); // overridden + set value { a: true, b: 'yes', c: 'yes' }
// ... you get the idea...

function createValueResolver

Creates a potential resolver function that resolves to the input value if it satisfies isValidValue function, or defaultValue if input is nullish. It returns undefined otherwise.

function createValueResolver<K extends string, V>(
  keys: readonly K[],
  isValidValue: TypeCheckFunction<V>,
  defaultValue: V,
): PotentialResolver<K, V>;
  • Arguments
    • keys: An array of string to be used as keys in the final Resolved object.
    • isValidValue: A function which returns wether or not a value is valid.
    • defaultValue: A valid value to be used as default in case the input value is nullish.

See TypeCheckFunction and PotentialResolver.

function createFunctionResolver

function createFunctionResolver<K extends string, V, D = V>(
  keys: readonly K[],
  isValidValue: TypeCheckFunction<V>,
  defaultValue: D,
): PotentialResolver<K, V | D>;

See TypeCheckFunction and PotentialResolver.

function createKeyResolver

Creates a potential resolver function that resolves if the input value is a string and is present in keys array, or if it is one of the special object keys. It also resolves if input follow the PositiveKey or NegativeKey format. It returns undefined otherwise.

This key determines the result. A positive key means "only that key". A negative key means "all other keys but that one". See example.

function createKeyResolver<K extends string, S extends string>(
  keys: KeyList<K>,
  special?: SpecialKeys<S, K> | null | undefined,
): PotentialResolver<K, boolean>;
  • Arguments
    • keys: An array of string to be used as keys in the final Resolved object. They will also be used to validate positive keys or negative keys.
    • special: An optional object mapping special keys to multiple regular keys. These special keys can also be used as positive keys or negative keys.

See KeyList, SpecialKeys and PotentialResolver.

  • Example
const resolve = createKeyResolver<'a' | 'b' | 'c', 'd'>(
  ['a', 'b', 'c'],
  { d: ['a', 'c'] },
);

resolve('c'); // Resolves to { a: false, b: false, c: true }
resolve('b'); // Resolves to { a: false, b: true, c: false }

resolve('a') // Resolves to { a: true, b: false, c: false } ::: Only "a" is set
resolve('!a') // Resolves to { a: false, b: true, c: true } ::: Everything but "a" is set

resolve('d'); // Resolves to { a: true, b: false, c: true } ::: Only "a" & "c" is set
resolve('!d'); // Resolves to { a: false, b: true, c: false } ::: Everything but "a" & "c" is set

function createKeyListResolver

Creates a potential resolver function that resolves if the input value is an array of string and every string is present in keys array, or if it is one of the special object keys. It also resolves if any of the string in the array follow the PositiveKey or NegativeKey format. It returns undefined otherwise.

The keys will be processed in the order they were added. The first key in the array will determine the default result, and the rest will mutate the result accordingly. A positive first key means "only that key". A negative first key means "all other keys but that one". See example.

function createKeyListResolver<K extends string, S extends string>(
  keys: KeyList<K>,
  special?: SpecialKeys<S, K> | null | undefined,
): PotentialResolver<K, boolean>;

See KeyList, SpecialKeys and PotentialResolver.

  • Example
const resolve = createKeyListResolver<'a' | 'b' | 'c', 'd'>(
  ['a', 'b', 'c'],
  { d: ['a', 'c'] },
);

resolve([]); // Resolves to { a: false, b: false, c: false }
resolve(['a', 'b']); // Resolves to { a: true, b: true, c: false }

// The first item sets the default
resolve(['a']) // Resolves to { a: true, b: false, c: false } ::: Only "a" is set
resolve(['!a']) // Resolves to { a: false, b: true, c: true } ::: Everything but "a" is set

// Watch the items order!!!

resolve(['a', '!a']) // Resolves to { a: false, b: false, c: false }
// because...
// step1 - 'a' => { a: true, b: false, c: false }
// step2 - '!a' => { ...step1, a: false }
// return step2

resolve(['!a', 'a']) // Resolves to { a: true, b: true, c: true }
// because...
// step1 - '!a' => { a: false, b: true, c: true }
// step2 - 'a' => { ...step1, a: true }
// return step2

resolve(['d', '!c']); // Resolves to { a: true, b: false, c: false }
// because...
// step1 = 'd' => { a: true, b: false, c: true }
// step2 = '!c' => { ...step1, c: false }
// return step2

resolve(['!c', 'd']); // Resolves to { a: true, b: true, c: true }
// because...
// step1 '!c' => { a: true, b: true, c: false }
// step2 'd' => { ...step1, a: true, c: true }
// return step2

function createObjectResolver

Creates a potential resolver function that resolves if the input value is an object and it follows the ObjectOption format. It returns undefined otherwise.

function createObjectResolver<K extends string, S extends string, V, O extends string>(
  keys: KeyList<K>,
  isValidValue: TypeCheckFunction<V>,
  defaultValue: V,
  overrideKey: O,
  special?: SpecialKeys<S, K> | null | undefined,
): PotentialResolver<K, V>;
  • Arguments
    • keys: An array of string to be used as keys in the final Resolved object. They will also be used to validate input object keys.
    • isValidValue: A function which returns wether or not a value is valid.
    • defaultValue: A valid value to be used as default in case the value is nullish.
    • overrideKey: A string to be used to detect the override key if the input is an object.
    • special: An optional object mapping special keys to multiple regular keys. They can also be used as keys in input object.

See KeyList, TypeCheckFunction, SpecialKeys and PotentialResolver.

function createResolver

Creates a resolver base on a series of potential resolvers. I will iterate through every potential resolver until one resolves and return the Resolved object result. It will throw if no potential resolver resolves.

function createResolver<K extends string, V, I = unknown>(
  ...resolvers: Array<PotentialResolver<K, V>>
): Resolver<K, V, I>;

See PotentialResolver and Resolver.

function createResult

Creates a Resolved object. Used internally in every potential resolver function. It is exported in case you need to write your own potential resolver function.

function createResult<K extends string, V>(
  keys: KeyList<K>,
  value: V,
  input?: Resolved<K, V>
): Resolved<K, V>;
  • Arguments
    • keys: An array of string to be used as keys in the Resolved object.
    • value: A value to be assigned to every key in the Resolved object.
    • input: An optional Resolved object to be used as base for the new Resolved object. This input object won't be modified, a new one will be created instead. If you pass an empty array as keys, the input object will be returned, unless input is nullish in which case a new empty object will be returned.

See KeyList and Resolved.

  • Example

Creating a Resolved object.

createResult(['a', 'b', 'c'], true); // { a: true, b: true, c: true }
createResult(['a', 'b', 'c'], 10); // { a: 10, b: 10, c: 10 }
  • Example

Extending a previously created Resolved object.

const base = createResult(['a', 'b', 'c'], 0); // base = { a: 0, b: 0, c: 0 }
createResult(['a', 'c'], 40, base); // { a: 40, b: 0, c: 40 }
createResult(['a', 'b'], 20, base); // { a: 20, b: 20, c: 0 }

Exported Types

type FunctionOption

A function to be called for every key in the the final Resolved object.

export type FunctionOption<K extends string, V> = (key: K) => V | null | undefined;

type SingleKeyOption

type SingleKeyOption<K extends string> = PositiveKey<K> | NegativeKey<K>;

See PositiveKey and NegativeKey. Used in type KeyListOption and KeyOption.

  • Example
function logKey(key: SingleKeyOption<'a' | 'b'>) {
  console.log(key);
}

logKey('a'); // OK
logKey('b'); // OK
logKey('!a'); // OK
logKey('!b'); // OK
logKey('-a'); // OK
logKey('-b'); // OK

logKey('x') // Type Error
logKey('z') // Type Error
logKey('!z') // Type Error

type KeyListOption

type KeyListOption<K extends string> = KeyList<SingleKeyOption<K>>;

See KeyList and SingleKeyOption. Used in type KeyOption.

  • Example
function logKeys(keys: KeyListOption<'a' | 'b'>) {
  console.log(keys);
}

logKeys(['a']); // OK
logKeys(['a', '!b']); // OK
logKeys(['b', '-a']); // OK
logKeys(['a', 'b', '-a']); // OK

logKeys(['x']) // Type Error
logKeys(['!z']) // Type Error
logKeys(['x', 'a']) // Type Error
logKeys(['a', '!z']) // Type Error

type KeyOption

type KeyOption<K extends string> = SingleKeyOption<K> | KeyListOption<K>;

See SingleKeyOption and KeyListOption. Used in type BoolBasedSelectiveOption.

  • Example
function logOption(option: KeyOption<'a' | 'b'>) {
  console.log(option);
}

logOption('a'); // OK
logOption('b'); // OK
logOption('!a'); // OK
logOption('-b'); // OK
logOption(['-b', 'a']); // OK
logOption(['-b', '!a']); // OK

logOption('z') // Type Error
logOption('!z') // Type Error
logOption(['!z']) // Type Error
logOption(['!z', 'a']) // Type Error

type ObjectOption

An object containing the keys defined by K | O and the values of V or nullish (null | undefined). It will be used by the PotentialResolver created by createObjectResolver in order to create a result using createResult.

type ObjectOption<K extends string, V> = Partial<Record<K, V | null | undefined>>;
  • Generics K: keys allowed in the input object. V: value type allowed inside input object.

Used in type ValueBasedSelectiveOption.

  • Example
function logOption(option: ObjectOption<'a' | 'b' | 'override', number>) {
  console.log(option);
}

logOption({}); // OK
logOption({ override: 10 }); // OK
logOption({ override: 10, a: 8 }); // OK
logOption({ a: 45 }); // OK
logOption({ a: 45, b: 10 }); // OK

logOption('z') // Type Error
logOption([]) // Type Error
logOption({ override: 'string' }) // Type Error
logOption({ override: 'string', b: 0 }) // Type Error
logOption({ a: 10, b: true }) // Type Error

type ValueBasedSelectiveOption

type ValueBasedSelectiveOption<K extends string, X extends string, V> =
  | V
  | null
  | undefined
  | ObjectOption<K | X, V>;
  • Generics K: keys allowed if the input is an object. V: value type allowed as input value and inside input if it's an object.

See ObjectOption. Used in type BoolBasedSelectiveOption and ValueBasedResolver.

type BoolBasedSelectiveOption

type BoolBasedSelectiveOption<K extends string, S extends string, V, O extends string> =
  | KeyOption<K | S>
  | ValueBasedSelectiveOption<K, S | O, V | boolean>;
  • Generics K: keys allowed as positive keys or negative keys, and as keys if input is an object. V: value type allowed as input value and inside input if it's an object. It will also allow boolean as valid value. O: key name allowed for the override key if input is an object.

See KeyOption and ValueBasedSelectiveOption. Used in type BoolBasedResolver.

type KeyList

An immutable list of keys.

type KeyList<K> = readonly K[];

Used in function createKeyResolver, createKeyListResolver, createObjectResolver, createResult and type SpecialKeys.

type SpecialKeys

An object mapping special keys to a list of regular keys.

type SpecialKeys<S extends string, K extends string> = Readonly<Record<S, KeyList<K>>>;

See type KeyList. Used in function createValueBasedResolver, createBoolBasedResolver, createKeyResolver, createKeyListResolver and createObjectResolver.

  • Example
type Country = 'american' | 'japanese';
type Car = 'chevrolet' | 'toyota' | 'suzuki' | 'ford';

const special: SpecialKeys<Country, Car> = {
  american: ['ford', 'chevrolet'],
  japanese: ['toyota', 'suzuki'],
};

type Resolved

type Resolved<K extends string, V> = Readonly<Record<K, V>>;

Used in function createResult and type PotentialResolver, Resolver.

type PotentialResolver

type PotentialResolver<K extends string, V> = (input: unknown) => Resolved<K, V> | void | undefined;

See Resolved. Used in function createValueResolver, createFunctionResolver, createKeyResolver, createKeyListResolver, createObjectResolver and createResolver.

type Resolver

type Resolver<K extends string, V, I> = (input: I) => Resolved<K, V>;

See Resolved. Used in function createResolver and type ValueBasedResolver and BoolBasedResolver.

type ValueBasedResolver

type ValueBasedResolver<K extends string, X extends string, V, D = V> = Resolver<K, V | D, ValueBasedSelectiveOption<K, X, V>>;

See Resolver and ValueBasedSelectiveOption. Used in function createValueBasedResolver.

type BoolBasedResolver

type BoolBasedResolver<K extends string, S extends string, V, O extends string, D = V> = Resolver<K, V | D | boolean, BoolBasedSelectiveOption<K, S, V, O>>;

See Resolver and BoolBasedSelectiveOption. Used in function createBoolBasedResolver.

Other Types

These are types which are not exported but help to understand some of the exported types.

type PositiveKey

A key name or a key name prefixed with a + sign.

type PositiveKey<K extends string> = K | `+${K}`;

Used in type SingleKeyOption.

type NegativeKey

A key name prefixed with a ! or - sign.

type NegativeKey<K extends string> = `!${K}` | `-${K}`;

Used in type SingleKeyOption.

type TypeCheckFunction

type TypeCheckFunction<V> = (input: unknown) => input is V;

Used in function createValueBasedResolver, createBoolBasedResolver, createValueResolver, createFunctionResolver and createObjectResolver.

  • Example
const isString: TypeCheckFunction<string> = (input) => {
  return typeof input === 'string';
};

const isRGB: TypeCheckFunction<'red' | 'green' | 'blue'> = (input) => {
  return ['red', 'green', 'blue'].includes(input as never);
}

License

MIT © 2020-2024 Manuel Fernández (@manferlo81)