mirror of
https://github.com/tenrok/OverlayScrollbars.git
synced 2026-05-17 13:39:40 +03:00
Code improvements for options and cache
This commit is contained in:
@@ -39,6 +39,7 @@ module.exports = {
|
||||
'no-empty': ['error', { allowEmptyCatch: true }],
|
||||
'no-cond-assign': ['error', 'except-parens'],
|
||||
camelcase: ['error', { allow: ['^__', '^UNSAFE_'] }],
|
||||
'prefer-destructuring': 'off',
|
||||
'consistent-return': 'off',
|
||||
'import/prefer-default-export': 'off',
|
||||
'import/no-extraneous-dependencies': 'off',
|
||||
|
||||
@@ -9,6 +9,7 @@ const testServerLoaderPath = path.resolve(__dirname, './config/jest-test-server.
|
||||
// https://jestjs.io/docs/en/configuration.html
|
||||
|
||||
const base = {
|
||||
cache: false,
|
||||
clearMocks: true,
|
||||
collectCoverage: true,
|
||||
coverageDirectory: './.coverage',
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import {
|
||||
optionsTemplateTypes as oTypes,
|
||||
transform,
|
||||
OptionsTemplate,
|
||||
transformOptions,
|
||||
OptionsTemplateValue,
|
||||
OptionsAndOptionsTemplateValue,
|
||||
OptionsAndOptionsTemplate,
|
||||
OptionsWithOptionsTemplateValue,
|
||||
OptionsWithOptionsTemplate,
|
||||
Func,
|
||||
} from 'support/options';
|
||||
import { ResizeBehavior, OverflowBehavior, VisibilityBehavior, AutoHideBehavior, Options } from 'options';
|
||||
@@ -13,9 +12,9 @@ const classNameAllowedValues: OptionsTemplateValue<string | null> = [oTypes.stri
|
||||
const numberAllowedValues: OptionsTemplateValue<number> = oTypes.number;
|
||||
const booleanNullAllowedValues: OptionsTemplateValue<boolean | null> = [oTypes.boolean, oTypes.null];
|
||||
const stringArrayNullAllowedValues: OptionsTemplateValue<string | Array<string> | null> = [oTypes.string, oTypes.array, oTypes.null];
|
||||
const booleanTrueTemplate: OptionsAndOptionsTemplateValue<boolean> = [true, oTypes.boolean];
|
||||
const booleanFalseTemplate: OptionsAndOptionsTemplateValue<boolean> = [false, oTypes.boolean];
|
||||
const callbackTemplate: OptionsAndOptionsTemplateValue<Func | null> = [null, [oTypes.function, oTypes.null]];
|
||||
const booleanTrueTemplate: OptionsWithOptionsTemplateValue<boolean> = [true, oTypes.boolean];
|
||||
const booleanFalseTemplate: OptionsWithOptionsTemplateValue<boolean> = [false, oTypes.boolean];
|
||||
const callbackTemplate: OptionsWithOptionsTemplateValue<Func | null> = [null, [oTypes.function, oTypes.null]];
|
||||
const resizeAllowedValues: OptionsTemplateValue<ResizeBehavior> = 'none both horizontal vertical';
|
||||
const overflowBehaviorAllowedValues: OptionsTemplateValue<OverflowBehavior> = 'visible-hidden visible-scroll scroll hidden';
|
||||
const scrollbarsVisibilityAllowedValues: OptionsTemplateValue<VisibilityBehavior> = 'visible hidden auto';
|
||||
@@ -36,7 +35,7 @@ const scrollbarsAutoHideAllowedValues: OptionsTemplateValue<AutoHideBehavior> =
|
||||
* Property "a" has a default value of 'default' and it can be a string or null
|
||||
* Property "b" has a default value of 250 and it can be number
|
||||
*/
|
||||
const defaultOptionsWithTemplate: OptionsAndOptionsTemplate<Required<Options>> = {
|
||||
const defaultOptionsWithTemplate: OptionsWithOptionsTemplate<Required<Options>> = {
|
||||
className: ['os-theme-dark', classNameAllowedValues], // null || string
|
||||
resize: ['none', resizeAllowedValues], // none || both || horizontal || vertical || n || b || h || v
|
||||
sizeAutoCapable: booleanTrueTemplate, // true || false
|
||||
@@ -84,5 +83,4 @@ const defaultOptionsWithTemplate: OptionsAndOptionsTemplate<Required<Options>> =
|
||||
},
|
||||
};
|
||||
|
||||
export const optionsTemplate: OptionsTemplate<Required<Options>> = transform(defaultOptionsWithTemplate, true);
|
||||
export const defaultOptions: Options = transform(defaultOptionsWithTemplate);
|
||||
export const { _template: optionsTemplate, _options: defaultOptions } = transformOptions(defaultOptionsWithTemplate);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { validate, assignDeep } from 'support';
|
||||
import { validateOptions, assignDeep } from 'support';
|
||||
import { Options, optionsTemplate } from 'options';
|
||||
import { TargetElement } from 'overlayscrollbars';
|
||||
import { Environment } from 'environment';
|
||||
@@ -32,11 +32,11 @@ export class OverlayScrollbars {
|
||||
#instanceVars: OverlayScrollbarsInstanceVars = {
|
||||
_setOptions(newOptions: Options): Options {
|
||||
const { _currentOptions } = this;
|
||||
const { validated } = validate(newOptions, optionsTemplate, _currentOptions, true);
|
||||
const { _validated } = validateOptions(newOptions, optionsTemplate, _currentOptions, true);
|
||||
|
||||
this._currentOptions = assignDeep({}, _currentOptions, validated);
|
||||
this._currentOptions = assignDeep({}, _currentOptions, _validated);
|
||||
|
||||
return validated;
|
||||
return _validated;
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -10,6 +10,11 @@ import {
|
||||
TRBL,
|
||||
equalTRBL,
|
||||
createCache,
|
||||
optionsTemplateTypes as oTypes,
|
||||
transformOptions,
|
||||
validateOptions,
|
||||
OptionsTemplateValue,
|
||||
assignDeep,
|
||||
} from 'support';
|
||||
import { Lifecycle } from 'overlayscrollbars/lifecycles';
|
||||
import { getEnvironment, Environment } from 'environment';
|
||||
@@ -18,17 +23,25 @@ import { createTrinsicObserver } from 'overlayscrollbars/observers/TrinsicObserv
|
||||
|
||||
export type OverflowBehavior = 'hidden' | 'scroll' | 'visible-hidden' | 'visible-scroll';
|
||||
export interface StructureLifecycleOptions {
|
||||
_paddingAbsolute?: boolean;
|
||||
_overflowBehavior?: {
|
||||
x: OverflowBehavior;
|
||||
y: OverflowBehavior;
|
||||
paddingAbsolute?: boolean;
|
||||
overflowBehavior?: {
|
||||
x?: OverflowBehavior;
|
||||
y?: OverflowBehavior;
|
||||
};
|
||||
}
|
||||
|
||||
interface StructureLifecycleCache {
|
||||
padding: TRBL;
|
||||
}
|
||||
|
||||
const overflowBehaviorAllowedValues: OptionsTemplateValue<OverflowBehavior> = 'visible-hidden visible-scroll scroll hidden';
|
||||
const { _template: optionsTemplate, _options: defaultOptions } = transformOptions<Required<StructureLifecycleOptions>>({
|
||||
paddingAbsolute: [false, oTypes.boolean],
|
||||
overflowBehavior: {
|
||||
x: ['scroll', overflowBehaviorAllowedValues],
|
||||
y: ['scroll', overflowBehaviorAllowedValues],
|
||||
},
|
||||
});
|
||||
|
||||
const classNameHost = 'os-host';
|
||||
const classNameViewport = 'os-viewport';
|
||||
const classNameContent = 'os-content';
|
||||
@@ -37,7 +50,13 @@ const classNameViewportScrollbarStyling = `${classNameViewport}-scrollbar-styled
|
||||
const cssMarginEnd = cssProperty('margin-inline-end');
|
||||
const cssBorderEnd = cssProperty('border-inline-end');
|
||||
|
||||
export const createStructureLifecycle = (target: HTMLElement, options?: StructureLifecycleOptions): Lifecycle<StructureLifecycleOptions> => {
|
||||
export const createStructureLifecycle = (target: HTMLElement, initialOptions?: StructureLifecycleOptions): Lifecycle<StructureLifecycleOptions> => {
|
||||
const options: Required<StructureLifecycleOptions> = assignDeep(
|
||||
{},
|
||||
defaultOptions,
|
||||
validateOptions<StructureLifecycleOptions>(initialOptions || {}, optionsTemplate)._validated
|
||||
);
|
||||
|
||||
const destructFns: (() => any)[] = [];
|
||||
const env: Environment = getEnvironment();
|
||||
const scrollbarsOverlaid = env._nativeScrollbarIsOverlaid;
|
||||
@@ -69,9 +88,13 @@ export const createStructureLifecycle = (target: HTMLElement, options?: Structur
|
||||
destructFns.push(createTrinsicObserver(target, onTrinsicChanged));
|
||||
|
||||
return {
|
||||
_options() {
|
||||
_options(newOptions?: StructureLifecycleOptions) {
|
||||
// eslint-disable-next-line
|
||||
console.log('_options');
|
||||
console.log('_options', newOptions);
|
||||
},
|
||||
_update(force?: boolean) {
|
||||
// eslint-disable-next-line
|
||||
console.log('_options', force);
|
||||
},
|
||||
_destruct() {
|
||||
runEach(destructFns);
|
||||
|
||||
@@ -2,5 +2,6 @@ import { PlainObject } from 'typings';
|
||||
|
||||
export interface Lifecycle<T = PlainObject> {
|
||||
_options(options?: T): void;
|
||||
_update(force?: boolean): void;
|
||||
_destruct(): void;
|
||||
}
|
||||
|
||||
+5
-3
@@ -19,7 +19,7 @@ export type CacheUpdateFunction<T, P extends keyof T> = (current?: T[P], previou
|
||||
export type CacheEqualFunction<T, P extends keyof T> = (a?: T[P], b?: T[P]) => boolean;
|
||||
|
||||
export type CacheChanged<T> = {
|
||||
[P in keyof T]: boolean;
|
||||
[P in keyof T]?: T[P];
|
||||
};
|
||||
|
||||
export type CacheUpdateInfo<T> = {
|
||||
@@ -42,7 +42,7 @@ export type CacheUpdateInfo<T> = {
|
||||
* If no equal function is passed a shallow comparison is carried out between the values.
|
||||
*
|
||||
* @returns A function which can be called with wither one ar an array of properties which shall be updated. Optionally it can be called with the force param.
|
||||
* This function returns a object which contains all cache properties as booleans which indicate whether the corresponding cache values really changed or not.
|
||||
* This function returns a object which contains all changed cache properties, if a property isn't in this object it means that it didn't change.
|
||||
*/
|
||||
export const createCache = <T>(cacheUpdateInfo: CacheUpdateInfo<T>): ((propsToUpdate?: PropsToUpdate<T>, force?: boolean) => CacheChanged<T>) => {
|
||||
const cache: Cache<T> = {} as T;
|
||||
@@ -64,7 +64,9 @@ export const createCache = <T>(cacheUpdateInfo: CacheUpdateInfo<T>): ((propsToUp
|
||||
const result: CacheChanged<T> = {} as CacheChanged<T>;
|
||||
|
||||
each(allProps, (prop: keyof T) => {
|
||||
result[prop] = !!(cache[prop]._changed || force);
|
||||
if (cache[prop]._changed || force) {
|
||||
result[prop] = cache[prop]._current;
|
||||
}
|
||||
cache[prop]._changed = false;
|
||||
});
|
||||
|
||||
|
||||
@@ -20,16 +20,16 @@ export type OptionsTemplate<T extends Required<T>> = {
|
||||
: never;
|
||||
};
|
||||
export type OptionsValidatedResult<T> = {
|
||||
readonly foreign: PlainObject;
|
||||
readonly validated: T;
|
||||
readonly _foreign: PlainObject;
|
||||
readonly _validated: T;
|
||||
};
|
||||
// Options With Options Template Typings:
|
||||
export type OptionsAndOptionsTemplateValue<T extends OptionsTemplateNativeTypes> = [T, OptionsTemplateValue<T>];
|
||||
export type OptionsAndOptionsTemplate<T extends Required<T>> = {
|
||||
export type OptionsWithOptionsTemplateValue<T extends OptionsTemplateNativeTypes> = [T, OptionsTemplateValue<T>];
|
||||
export type OptionsWithOptionsTemplate<T extends Required<T>> = {
|
||||
[P in keyof T]: PlainObject extends T[P]
|
||||
? OptionsAndOptionsTemplate<Required<T[P]>>
|
||||
? OptionsWithOptionsTemplate<Required<T[P]>>
|
||||
: T[P] extends OptionsTemplateNativeTypes
|
||||
? OptionsAndOptionsTemplateValue<T[P]>
|
||||
? OptionsWithOptionsTemplateValue<T[P]>
|
||||
: never;
|
||||
};
|
||||
type OptionsTemplateTypeMap = {
|
||||
|
||||
@@ -1,32 +1,37 @@
|
||||
import { OptionsTemplate, OptionsAndOptionsTemplate, OptionsTemplateTypes } from 'support/options';
|
||||
import { OptionsTemplate, OptionsWithOptionsTemplate, OptionsTemplateTypes } from 'support/options';
|
||||
import { PlainObject } from 'typings';
|
||||
import { isArray, isObject } from 'support/utils/types';
|
||||
import { isArray } from 'support/utils/types';
|
||||
import { each, keys } from 'support/utils';
|
||||
|
||||
export interface OptionsWithOptionsTemplateTransformation<T extends Required<T>> {
|
||||
_template: OptionsTemplate<T>;
|
||||
_options: T;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms the given OptionsAndOptionsTemplate<T> object to its corresponding generic (T) Object or its corresponding Template object.
|
||||
* @param optionsWithOptionsTemplate The OptionsAndOptionsTemplate<T> object which shall be converted.
|
||||
* @param toTemplate True if the given OptionsAndOptionsTemplate<T> shall be converted to its corresponding Template object.
|
||||
* Transforms the given OptionsWithOptionsTemplate<T> object to its corresponding generic (T) Object or its corresponding Template object.
|
||||
* @param optionsWithOptionsTemplate The OptionsWithOptionsTemplate<T> object which shall be converted.
|
||||
* @param toTemplate True if the given OptionsWithOptionsTemplate<T> shall be converted to its corresponding Template object.
|
||||
*/
|
||||
export function transform<T extends Required<T>>(optionsWithOptionsTemplate: OptionsAndOptionsTemplate<T>): T;
|
||||
export function transform<T extends Required<T>>(
|
||||
optionsWithOptionsTemplate: OptionsAndOptionsTemplate<T>,
|
||||
toTemplate: true | void
|
||||
): OptionsTemplate<T>;
|
||||
export function transform<T extends Required<T>>(
|
||||
optionsWithOptionsTemplate: OptionsAndOptionsTemplate<T>,
|
||||
toTemplate?: true | void
|
||||
): OptionsTemplate<T> | T {
|
||||
const result: any = {};
|
||||
export function transformOptions<T extends Required<T>>(
|
||||
optionsWithOptionsTemplate: OptionsWithOptionsTemplate<T>
|
||||
): OptionsWithOptionsTemplateTransformation<T> {
|
||||
const result: any = {
|
||||
_template: {},
|
||||
_options: {},
|
||||
};
|
||||
|
||||
each(keys(optionsWithOptionsTemplate), (key: Extract<keyof T, string>) => {
|
||||
const val: PlainObject | OptionsTemplateTypes | Array<OptionsTemplateTypes> = optionsWithOptionsTemplate[key];
|
||||
|
||||
/* istanbul ignore else */
|
||||
if (isArray(val)) {
|
||||
result[key] = val[toTemplate ? 1 : 0];
|
||||
} else if (isObject(val)) {
|
||||
result[key] = transform(val as OptionsAndOptionsTemplate<typeof val>, toTemplate);
|
||||
result._template[key] = val[1];
|
||||
result._options[key] = val[0];
|
||||
} else {
|
||||
// if (isObject(val))
|
||||
const tmpResult = transformOptions(val as OptionsWithOptionsTemplate<typeof val>);
|
||||
result._template[key] = tmpResult._template;
|
||||
result._options[key] = tmpResult._options;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -61,8 +61,8 @@ const validateRecursive = <T extends PlainObject>(
|
||||
// if the template has a object as value, it means that the options are complex (verschachtelt)
|
||||
if (templateIsComplex && isPlainObject(optionsValue)) {
|
||||
const validatedResult = validateRecursive(optionsValue, templateValue as PlainObject, optionsDiffValue, doWriteErrors, propPrefix + prop);
|
||||
validatedOptions[prop] = validatedResult.validated;
|
||||
optionsCopy[prop] = validatedResult.foreign as any;
|
||||
validatedOptions[prop] = validatedResult._validated;
|
||||
optionsCopy[prop] = validatedResult._foreign as any;
|
||||
|
||||
each([optionsCopy, validatedOptions], (value) => {
|
||||
if (isEmptyObject(value[prop])) {
|
||||
@@ -118,8 +118,8 @@ const validateRecursive = <T extends PlainObject>(
|
||||
});
|
||||
|
||||
return {
|
||||
foreign: optionsCopy,
|
||||
validated: validatedOptions,
|
||||
_foreign: optionsCopy,
|
||||
_validated: validatedOptions,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -140,7 +140,7 @@ const validateRecursive = <T extends PlainObject>(
|
||||
* Without the optionsDiff object the returned validated object would be: { a: 'a', b: 'b', c: 'c' }
|
||||
* @param doWriteErrors True if errors shall be logged into the console, false otherwise.
|
||||
*/
|
||||
const validate = <T extends PlainObject>(
|
||||
const validateOptions = <T extends PlainObject>(
|
||||
options: T,
|
||||
template: OptionsTemplate<Required<T>>,
|
||||
optionsDiff?: T,
|
||||
@@ -158,7 +158,7 @@ const validate = <T extends PlainObject>(
|
||||
return validateRecursive<T>(options, template, optionsDiff || ({} as T), doWriteErrors || false);
|
||||
};
|
||||
|
||||
export { validate, optionsTemplateTypes };
|
||||
export { validateOptions, optionsTemplateTypes };
|
||||
|
||||
type OptionsTemplateTypesDictionary = {
|
||||
readonly boolean: OptionsTemplateType<boolean>;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { validate } from 'support/options';
|
||||
import { validateOptions } from 'support/options';
|
||||
import { defaultOptions, optionsTemplate } from 'options';
|
||||
|
||||
describe('options', () => {
|
||||
test('default options matching the options template', () => {
|
||||
const { validated } = validate(defaultOptions, optionsTemplate);
|
||||
expect(validated).toEqual(defaultOptions);
|
||||
const { _validated } = validateOptions(defaultOptions, optionsTemplate);
|
||||
expect(_validated).toEqual(defaultOptions);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,45 +15,51 @@ const createUpdater = <T>(updaterReturn: (i: number) => T) => {
|
||||
describe('cache', () => {
|
||||
describe('createCache', () => {
|
||||
test('creates and updates simple cache', () => {
|
||||
interface Test {
|
||||
number: number;
|
||||
boolean: boolean;
|
||||
string: string;
|
||||
object: {};
|
||||
}
|
||||
const [updateNumberFn, updateNumber] = createUpdater<number>((i) => i);
|
||||
const [updateBooleanFn, updateBoolean] = createUpdater<boolean>((i) => !!(i % 2));
|
||||
const [updateStringFn, updateString] = createUpdater<string>((i) => `${i}`);
|
||||
const [updateObjFn, updateObj] = createUpdater<object>((i) => ({ [i]: i }));
|
||||
|
||||
const updateCache = createCache({
|
||||
const updateCache = createCache<Test>({
|
||||
number: updateNumber,
|
||||
boolean: updateBoolean,
|
||||
string: updateString,
|
||||
object: updateObj,
|
||||
});
|
||||
|
||||
expect(updateCache('number').number).toBe(true);
|
||||
expect(updateCache('number').number).toBe(1);
|
||||
expect(updateNumberFn).toHaveBeenCalledTimes(1);
|
||||
expect(updateNumberFn).toHaveBeenCalledWith(undefined, undefined);
|
||||
|
||||
expect(updateCache('number').number).toBe(true);
|
||||
expect(updateCache('number').number).toBe(2);
|
||||
expect(updateNumberFn).toHaveBeenCalledTimes(2);
|
||||
expect(updateNumberFn).toHaveBeenCalledWith(1, undefined);
|
||||
|
||||
expect(updateCache('number').number).toBe(true);
|
||||
expect(updateCache('number').number).toBe(3);
|
||||
expect(updateNumberFn).toHaveBeenCalledTimes(3);
|
||||
expect(updateNumberFn).toHaveBeenCalledWith(2, 1);
|
||||
|
||||
let { string, boolean, object, number } = updateCache('number');
|
||||
expect(string).toBe(false);
|
||||
expect(boolean).toBe(false);
|
||||
expect(object).toBe(false);
|
||||
expect(number).toBe(true);
|
||||
expect(string).toBe(undefined);
|
||||
expect(boolean).toBe(undefined);
|
||||
expect(object).toBe(undefined);
|
||||
expect(number).toBe(4);
|
||||
|
||||
expect(updateBooleanFn).not.toHaveBeenCalled();
|
||||
expect(updateStringFn).not.toHaveBeenCalled();
|
||||
expect(updateObjFn).not.toHaveBeenCalled();
|
||||
|
||||
({ string, boolean, object, number } = updateCache(['string', 'boolean', 'object']));
|
||||
expect(string).toBe(true);
|
||||
expect(boolean).toBe(true);
|
||||
expect(object).toBe(true);
|
||||
expect(number).toBe(false);
|
||||
expect(string).toBe('1');
|
||||
expect(boolean).toBe(!!(1 % 2));
|
||||
expect(object).toEqual({ 1: 1 });
|
||||
expect(number).toBe(undefined);
|
||||
|
||||
expect(updateBooleanFn).toHaveBeenCalledTimes(1);
|
||||
expect(updateBooleanFn).toHaveBeenCalledWith(undefined, undefined);
|
||||
@@ -86,10 +92,10 @@ describe('cache', () => {
|
||||
|
||||
updateCache(['string', 'boolean', 'object']);
|
||||
({ string, boolean, object, number } = updateCache());
|
||||
expect(string).toBe(true);
|
||||
expect(boolean).toBe(true);
|
||||
expect(object).toBe(true);
|
||||
expect(number).toBe(true);
|
||||
expect(string).toBe('5');
|
||||
expect(boolean).toBe(!!(5 % 2));
|
||||
expect(object).toEqual({ 5: 5 });
|
||||
expect(number).toBe(5);
|
||||
|
||||
expect(updateBooleanFn).toHaveBeenCalledTimes(5);
|
||||
expect(updateStringFn).toHaveBeenCalledTimes(5);
|
||||
@@ -103,14 +109,17 @@ describe('cache', () => {
|
||||
number: updateNumber,
|
||||
});
|
||||
|
||||
expect(updateCache('number').number).toBe(true);
|
||||
expect(updateCache('number').number).toBe(0);
|
||||
expect(updateNumberFn).toHaveBeenCalledWith(undefined, undefined);
|
||||
|
||||
expect(updateCache('number').number).toBe(false);
|
||||
expect(updateCache('number').number).toBe(undefined);
|
||||
expect(updateNumberFn).toHaveBeenCalledWith(0, undefined);
|
||||
|
||||
expect(updateCache('number').number).toBe(false);
|
||||
expect(updateCache('number').number).toBe(undefined);
|
||||
expect(updateNumberFn).toHaveBeenCalledWith(0, 0);
|
||||
|
||||
const changed = updateCache('number');
|
||||
expect(Object.prototype.hasOwnProperty.call(changed, 'changed')).toBe(false);
|
||||
});
|
||||
|
||||
test('doesnt update if nothing changes with non primitives', () => {
|
||||
@@ -127,26 +136,29 @@ describe('cache', () => {
|
||||
],
|
||||
});
|
||||
|
||||
expect(updateCache('constObj').constObj).toBe(true);
|
||||
expect(updateCache('constObj').constObj).toBe(constObj);
|
||||
expect(updateConstObjFn).toHaveBeenCalledWith(undefined, undefined);
|
||||
expect(updateCache('constObj').constObj).toBe(false);
|
||||
expect(updateCache('constObj').constObj).toBe(undefined);
|
||||
expect(updateConstObjFn).toHaveBeenCalledWith(constObj, undefined);
|
||||
expect(updateCache('constObj').constObj).toBe(false);
|
||||
expect(updateCache('constObj').constObj).toBe(undefined);
|
||||
expect(updateConstObjFn).toHaveBeenCalledWith(constObj, constObj);
|
||||
expect(Object.prototype.hasOwnProperty.call(updateCache('constObj'), 'constObj')).toBe(false);
|
||||
|
||||
expect(updateCache('similarObj').similarObj).toBe(true);
|
||||
expect(updateCache('similarObj').similarObj).toEqual(constObj);
|
||||
expect(updateSimilarObjFn).toHaveBeenCalledWith(undefined, undefined);
|
||||
expect(updateCache('similarObj').similarObj).toBe(true);
|
||||
expect(updateCache('similarObj').similarObj).toEqual(constObj);
|
||||
expect(updateSimilarObjFn).toHaveBeenCalledWith(constObj, undefined);
|
||||
expect(updateCache('similarObj').similarObj).toBe(true);
|
||||
expect(updateCache('similarObj').similarObj).toEqual(constObj);
|
||||
expect(updateSimilarObjFn).toHaveBeenCalledWith(constObj, constObj);
|
||||
expect(Object.prototype.hasOwnProperty.call(updateCache('similarObj'), 'similarObj')).toBe(true);
|
||||
|
||||
expect(updateCache('comparisonObj').comparisonObj).toBe(true);
|
||||
expect(updateCache('comparisonObj').comparisonObj).toEqual(constObj);
|
||||
expect(updateComparisonObjFn).toHaveBeenCalledWith(undefined, undefined);
|
||||
expect(updateCache('comparisonObj').comparisonObj).toBe(false);
|
||||
expect(updateCache('comparisonObj').comparisonObj).toBe(undefined);
|
||||
expect(updateComparisonObjFn).toHaveBeenCalledWith(constObj, undefined);
|
||||
expect(updateCache('comparisonObj').comparisonObj).toBe(false);
|
||||
expect(updateCache('comparisonObj').comparisonObj).toBe(undefined);
|
||||
expect(updateComparisonObjFn).toHaveBeenCalledWith(constObj, constObj);
|
||||
expect(Object.prototype.hasOwnProperty.call(updateCache('comparisonObj'), 'comparisonObj')).toBe(false);
|
||||
});
|
||||
|
||||
test('updates definitely with force', () => {
|
||||
@@ -155,13 +167,13 @@ describe('cache', () => {
|
||||
number: updateNumber,
|
||||
});
|
||||
|
||||
expect(updateCache('number', true).number).toBe(true);
|
||||
expect(updateCache('number', true).number).toBe(0);
|
||||
expect(updateNumberFn).toHaveBeenCalledWith(undefined, undefined);
|
||||
|
||||
expect(updateCache('number', true).number).toBe(true);
|
||||
expect(updateCache('number', true).number).toBe(0);
|
||||
expect(updateNumberFn).toHaveBeenCalledWith(0, undefined);
|
||||
|
||||
expect(updateCache('number', true).number).toBe(true);
|
||||
expect(updateCache('number', true).number).toBe(0);
|
||||
expect(updateNumberFn).toHaveBeenCalledWith(0, 0);
|
||||
});
|
||||
|
||||
@@ -173,19 +185,21 @@ describe('cache', () => {
|
||||
number: [updateNumber, () => true],
|
||||
});
|
||||
|
||||
expect(updateCache('string').string).toBe(true);
|
||||
expect(updateCache('string').string).toBe('hi');
|
||||
expect(updateStringFn).toHaveBeenCalledWith(undefined, undefined);
|
||||
expect(updateCache('string').string).toBe(true);
|
||||
expect(updateCache('string').string).toBe('hi');
|
||||
expect(updateStringFn).toHaveBeenCalledWith('hi', undefined);
|
||||
expect(updateCache('string').string).toBe(true);
|
||||
expect(updateCache('string').string).toBe('hi');
|
||||
expect(updateStringFn).toHaveBeenCalledWith('hi', 'hi');
|
||||
expect(Object.prototype.hasOwnProperty.call(updateCache('string'), 'string')).toBe(true);
|
||||
|
||||
expect(updateCache('number').number).toBe(false);
|
||||
expect(updateCache('number').number).toBe(undefined);
|
||||
expect(updateNumberFn).toHaveBeenCalledWith(undefined, undefined);
|
||||
expect(updateCache('number').number).toBe(false);
|
||||
expect(updateCache('number').number).toBe(undefined);
|
||||
expect(updateNumberFn).toHaveBeenCalledWith(1, undefined);
|
||||
expect(updateCache('number').number).toBe(false);
|
||||
expect(updateCache('number').number).toBe(undefined);
|
||||
expect(updateNumberFn).toHaveBeenCalledWith(2, 1);
|
||||
expect(Object.prototype.hasOwnProperty.call(updateCache('number'), 'number')).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { PlainObject } from 'typings';
|
||||
import { optionsTemplateTypes as oTypes, transform, OptionsTemplate, OptionsAndOptionsTemplate } from 'support/options';
|
||||
import { optionsTemplateTypes as oTypes, transformOptions, OptionsTemplate, OptionsWithOptionsTemplate } from 'support/options';
|
||||
|
||||
type TestOptionsObj = { propA: 'propA'; null: null };
|
||||
type TestOptionsEnum = 'A' | 'B' | 'C';
|
||||
@@ -51,7 +51,7 @@ const optionsTemplate: OptionsTemplate<Required<TestOptions>> = {
|
||||
func: oTypes.function,
|
||||
};
|
||||
|
||||
const optionsAndOptionsTemplate: OptionsAndOptionsTemplate<Required<TestOptions>> = {
|
||||
const TestOptionsWithOptionsTemplate: OptionsWithOptionsTemplate<Required<TestOptions>> = {
|
||||
str: [options.str, optionsTemplate.str],
|
||||
strArrNull: [options.strArrNull, optionsTemplate.strArrNull],
|
||||
nullbool: [options.nullbool, optionsTemplate.nullbool],
|
||||
@@ -68,10 +68,10 @@ const optionsAndOptionsTemplate: OptionsAndOptionsTemplate<Required<TestOptions>
|
||||
|
||||
describe('options and options template object transformation', () => {
|
||||
test('transforms correctly into options object', () => {
|
||||
expect(transform(optionsAndOptionsTemplate)).toEqual(options);
|
||||
expect(transformOptions(TestOptionsWithOptionsTemplate)._options).toEqual(options);
|
||||
});
|
||||
|
||||
test('transforms correctly into template object', () => {
|
||||
expect(transform(optionsAndOptionsTemplate, true)).toEqual(optionsTemplate);
|
||||
expect(transformOptions(TestOptionsWithOptionsTemplate)._template).toEqual(optionsTemplate);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { validate, optionsTemplateTypes as oTypes, OptionsTemplate } from 'support/options';
|
||||
import { validateOptions, optionsTemplateTypes as oTypes, OptionsTemplate } from 'support/options';
|
||||
import { assignDeep, isEmptyObject } from 'support/utils';
|
||||
|
||||
type TestOptionsObj = { propA: 'propA'; null: null };
|
||||
@@ -56,41 +56,41 @@ describe('options validation', () => {
|
||||
foreignDeep: { a: 'A', b: 'B' },
|
||||
};
|
||||
const modifiedOptions = assignDeep({}, options, { nested: foreignObj }, foreignObj);
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { validated } = result;
|
||||
const result = validateOptions(modifiedOptions, template);
|
||||
const { _validated } = result;
|
||||
|
||||
expect(validated).toEqual(options);
|
||||
expect(_validated).toEqual(options);
|
||||
});
|
||||
|
||||
test('passed objects arent mutated', () => {
|
||||
const clonedOptions = assignDeep({}, options);
|
||||
validate(clonedOptions, template, clonedOptions);
|
||||
validateOptions(clonedOptions, template, clonedOptions);
|
||||
|
||||
expect(clonedOptions).toEqual(options);
|
||||
});
|
||||
|
||||
test('passed object isnt returned object', () => {
|
||||
const clonedOptions = assignDeep({}, options);
|
||||
const result = validate(clonedOptions, template);
|
||||
const result = validateOptions(clonedOptions, template);
|
||||
|
||||
expect(result.validated).not.toBe(clonedOptions);
|
||||
expect(result._validated).not.toBe(clonedOptions);
|
||||
});
|
||||
});
|
||||
|
||||
describe('foreign property return', () => {
|
||||
test('return no foreign property', () => {
|
||||
const result = validate(options, template);
|
||||
const result = validateOptions(options, template);
|
||||
|
||||
expect(isEmptyObject(result.foreign)).toBe(true);
|
||||
expect(isEmptyObject(result._foreign)).toBe(true);
|
||||
});
|
||||
|
||||
test('return signle non-object foreign property', () => {
|
||||
const foreignObj = { foreignProp: 'foreign' };
|
||||
const modifiedOptions = assignDeep({}, options, foreignObj);
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { foreign } = result;
|
||||
const result = validateOptions(modifiedOptions, template);
|
||||
const { _foreign } = result;
|
||||
|
||||
expect(foreign).toEqual(foreignObj);
|
||||
expect(_foreign).toEqual(foreignObj);
|
||||
});
|
||||
|
||||
test('return complex foreign properties', () => {
|
||||
@@ -99,10 +99,10 @@ describe('options validation', () => {
|
||||
foreignDeep: { a: 'A', b: 'B' },
|
||||
};
|
||||
const modifiedOptions = assignDeep({}, options, foreignObj);
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { foreign } = result;
|
||||
const result = validateOptions(modifiedOptions, template);
|
||||
const { _foreign } = result;
|
||||
|
||||
expect(foreign).toEqual(foreignObj);
|
||||
expect(_foreign).toEqual(foreignObj);
|
||||
});
|
||||
|
||||
test('return nested complex foreign properties', () => {
|
||||
@@ -111,24 +111,24 @@ describe('options validation', () => {
|
||||
foreignDeep: { a: 'A', b: 'B' },
|
||||
};
|
||||
const modifiedOptions = assignDeep({}, options, { nested: foreignObj }, foreignObj);
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { foreign } = result;
|
||||
const result = validateOptions(modifiedOptions, template);
|
||||
const { _foreign } = result;
|
||||
|
||||
expect(foreign.nested).toEqual(foreignObj);
|
||||
delete foreign.nested;
|
||||
expect(foreign).toEqual(foreignObj);
|
||||
expect(_foreign.nested).toEqual(foreignObj);
|
||||
delete _foreign.nested;
|
||||
expect(_foreign).toEqual(foreignObj);
|
||||
});
|
||||
});
|
||||
|
||||
describe('diff property return', () => {
|
||||
test('one value changed', () => {
|
||||
const modifiedOptions = assignDeep({}, options, { str: 'newvaluetest' });
|
||||
const result = validate(modifiedOptions, template, options);
|
||||
const { validated } = result;
|
||||
const result = validateOptions(modifiedOptions, template, options);
|
||||
const { _validated } = result;
|
||||
|
||||
expect(validated.str).toBe('newvaluetest');
|
||||
delete validated.str;
|
||||
expect(isEmptyObject(validated)).toBe(true);
|
||||
expect(_validated.str).toBe('newvaluetest');
|
||||
delete _validated.str;
|
||||
expect(isEmptyObject(_validated)).toBe(true);
|
||||
});
|
||||
|
||||
test('multiple values changed', () => {
|
||||
@@ -136,42 +136,42 @@ describe('options validation', () => {
|
||||
str: 'newvaluetest',
|
||||
nullbool: null,
|
||||
});
|
||||
const result = validate(modifiedOptions, template, options);
|
||||
const { validated } = result;
|
||||
const result = validateOptions(modifiedOptions, template, options);
|
||||
const { _validated } = result;
|
||||
|
||||
expect(validated.str).toBe('newvaluetest');
|
||||
expect(validated.nullbool).toBe(null);
|
||||
delete validated.str;
|
||||
delete validated.nullbool;
|
||||
expect(isEmptyObject(validated)).toBe(true);
|
||||
expect(_validated.str).toBe('newvaluetest');
|
||||
expect(_validated.nullbool).toBe(null);
|
||||
delete _validated.str;
|
||||
delete _validated.nullbool;
|
||||
expect(isEmptyObject(_validated)).toBe(true);
|
||||
});
|
||||
|
||||
test('one nested value changed', () => {
|
||||
const modifiedOptions = assignDeep({}, options, { nested: { num: -1293 } });
|
||||
const result = validate(modifiedOptions, template, options);
|
||||
const { validated } = result;
|
||||
const result = validateOptions(modifiedOptions, template, options);
|
||||
const { _validated } = result;
|
||||
|
||||
expect(validated.nested?.num).toBe(-1293);
|
||||
delete validated.nested?.num;
|
||||
expect(isEmptyObject(validated.nested)).toBe(true);
|
||||
delete validated.nested;
|
||||
expect(isEmptyObject(validated)).toBe(true);
|
||||
expect(_validated.nested?.num).toBe(-1293);
|
||||
delete _validated.nested?.num;
|
||||
expect(isEmptyObject(_validated.nested)).toBe(true);
|
||||
delete _validated.nested;
|
||||
expect(isEmptyObject(_validated)).toBe(true);
|
||||
});
|
||||
|
||||
test('multiple nested values changed', () => {
|
||||
const modifiedOptions = assignDeep({}, options, {
|
||||
nested: { num: -1293, abc: 'C' },
|
||||
});
|
||||
const result = validate(modifiedOptions, template, options);
|
||||
const { validated } = result;
|
||||
const result = validateOptions(modifiedOptions, template, options);
|
||||
const { _validated } = result;
|
||||
|
||||
expect(validated.nested?.num).toBe(-1293);
|
||||
expect(validated.nested?.abc).toBe('C');
|
||||
delete validated.nested?.num;
|
||||
delete validated.nested?.abc;
|
||||
expect(isEmptyObject(validated.nested)).toBe(true);
|
||||
delete validated.nested;
|
||||
expect(isEmptyObject(validated)).toBe(true);
|
||||
expect(_validated.nested?.num).toBe(-1293);
|
||||
expect(_validated.nested?.abc).toBe('C');
|
||||
delete _validated.nested?.num;
|
||||
delete _validated.nested?.abc;
|
||||
expect(isEmptyObject(_validated.nested)).toBe(true);
|
||||
delete _validated.nested;
|
||||
expect(isEmptyObject(_validated)).toBe(true);
|
||||
});
|
||||
|
||||
test('various values changed', () => {
|
||||
@@ -182,22 +182,22 @@ describe('options validation', () => {
|
||||
abc: 'C',
|
||||
nested: { num: -1293, abc: 'C' },
|
||||
});
|
||||
const result = validate(modifiedOptions, template, options);
|
||||
const { validated } = result;
|
||||
const result = validateOptions(modifiedOptions, template, options);
|
||||
const { _validated } = result;
|
||||
|
||||
expect(validated.str).toBe('newstrvalue');
|
||||
expect(validated.func).toBe(newFunc);
|
||||
expect(validated.abc).toBe('C');
|
||||
delete validated.str;
|
||||
delete validated.func;
|
||||
delete validated.abc;
|
||||
expect(validated.nested?.num).toBe(-1293);
|
||||
expect(validated.nested?.abc).toBe('C');
|
||||
delete validated.nested?.num;
|
||||
delete validated.nested?.abc;
|
||||
expect(isEmptyObject(validated.nested)).toBe(true);
|
||||
delete validated.nested;
|
||||
expect(isEmptyObject(validated)).toBe(true);
|
||||
expect(_validated.str).toBe('newstrvalue');
|
||||
expect(_validated.func).toBe(newFunc);
|
||||
expect(_validated.abc).toBe('C');
|
||||
delete _validated.str;
|
||||
delete _validated.func;
|
||||
delete _validated.abc;
|
||||
expect(_validated.nested?.num).toBe(-1293);
|
||||
expect(_validated.nested?.abc).toBe('C');
|
||||
delete _validated.nested?.num;
|
||||
delete _validated.nested?.abc;
|
||||
expect(isEmptyObject(_validated.nested)).toBe(true);
|
||||
delete _validated.nested;
|
||||
expect(isEmptyObject(_validated)).toBe(true);
|
||||
});
|
||||
|
||||
test('various values changed with foreign properties', () => {
|
||||
@@ -218,40 +218,40 @@ describe('options validation', () => {
|
||||
foreignObj,
|
||||
{ nested: foreignObj }
|
||||
);
|
||||
const result = validate(modifiedOptions, template, options);
|
||||
const { validated } = result;
|
||||
const result = validateOptions(modifiedOptions, template, options);
|
||||
const { _validated } = result;
|
||||
|
||||
expect(validated.str).toBe('newstrvalue');
|
||||
expect(validated.func).toBe(newFunc);
|
||||
expect(validated.abc).toBe('C');
|
||||
delete validated.str;
|
||||
delete validated.func;
|
||||
delete validated.abc;
|
||||
expect(validated.nested?.num).toBe(-1293);
|
||||
expect(validated.nested?.abc).toBe('C');
|
||||
delete validated.nested?.num;
|
||||
delete validated.nested?.abc;
|
||||
expect(isEmptyObject(validated.nested)).toBe(true);
|
||||
delete validated.nested;
|
||||
expect(isEmptyObject(validated)).toBe(true);
|
||||
expect(_validated.str).toBe('newstrvalue');
|
||||
expect(_validated.func).toBe(newFunc);
|
||||
expect(_validated.abc).toBe('C');
|
||||
delete _validated.str;
|
||||
delete _validated.func;
|
||||
delete _validated.abc;
|
||||
expect(_validated.nested?.num).toBe(-1293);
|
||||
expect(_validated.nested?.abc).toBe('C');
|
||||
delete _validated.nested?.num;
|
||||
delete _validated.nested?.abc;
|
||||
expect(isEmptyObject(_validated.nested)).toBe(true);
|
||||
delete _validated.nested;
|
||||
expect(isEmptyObject(_validated)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('value validity', () => {
|
||||
test('single value doesnt match template', () => {
|
||||
const modifiedOptions = assignDeep({}, options, { str: 1 });
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { validated } = result;
|
||||
const result = validateOptions(modifiedOptions, template);
|
||||
const { _validated } = result;
|
||||
|
||||
expect(validated).not.toHaveProperty('str');
|
||||
expect(_validated).not.toHaveProperty('str');
|
||||
});
|
||||
|
||||
test('single enum value doesnt match template', () => {
|
||||
const modifiedOptions = assignDeep({}, options, { abc: 'testval' });
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { validated } = result;
|
||||
const result = validateOptions(modifiedOptions, template);
|
||||
const { _validated } = result;
|
||||
|
||||
expect(validated).not.toHaveProperty('abc');
|
||||
expect(_validated).not.toHaveProperty('abc');
|
||||
});
|
||||
|
||||
test('multiple values dont match template', () => {
|
||||
@@ -260,51 +260,51 @@ describe('options validation', () => {
|
||||
abc: 'testval',
|
||||
nullbool: 'string',
|
||||
});
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { validated } = result;
|
||||
const result = validateOptions(modifiedOptions, template);
|
||||
const { _validated } = result;
|
||||
|
||||
expect(validated).not.toHaveProperty('str');
|
||||
expect(validated).not.toHaveProperty('abc');
|
||||
expect(validated).not.toHaveProperty('nullbool');
|
||||
expect(_validated).not.toHaveProperty('str');
|
||||
expect(_validated).not.toHaveProperty('abc');
|
||||
expect(_validated).not.toHaveProperty('nullbool');
|
||||
});
|
||||
|
||||
test('single nested value dont match template', () => {
|
||||
const modifiedOptions = assignDeep({}, options, { nested: { num: 'hi' } });
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { validated } = result;
|
||||
const result = validateOptions(modifiedOptions, template);
|
||||
const { _validated } = result;
|
||||
|
||||
expect(validated.nested).not.toHaveProperty('num');
|
||||
expect(_validated.nested).not.toHaveProperty('num');
|
||||
});
|
||||
|
||||
test('single nested enum value dont match template', () => {
|
||||
const modifiedOptions = assignDeep({}, options, {
|
||||
nested: { abc: 'testabc' },
|
||||
});
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { validated } = result;
|
||||
const result = validateOptions(modifiedOptions, template);
|
||||
const { _validated } = result;
|
||||
|
||||
expect(validated.nested).not.toHaveProperty('abc');
|
||||
expect(_validated.nested).not.toHaveProperty('abc');
|
||||
});
|
||||
|
||||
test('multiple nested values dont match template', () => {
|
||||
const modifiedOptions = assignDeep({}, options, {
|
||||
nested: { num: 'hi', abc: 'testabc' },
|
||||
});
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { validated } = result;
|
||||
const result = validateOptions(modifiedOptions, template);
|
||||
const { _validated } = result;
|
||||
|
||||
expect(validated.nested).not.toHaveProperty('num');
|
||||
expect(validated.nested).not.toHaveProperty('abc');
|
||||
expect(_validated.nested).not.toHaveProperty('num');
|
||||
expect(_validated.nested).not.toHaveProperty('abc');
|
||||
});
|
||||
|
||||
test('all nested values dont match template', () => {
|
||||
const modifiedOptions = assignDeep({}, options, {
|
||||
nested: { num: 'hi', abc: 'testabc', switch: 1 },
|
||||
});
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { validated } = result;
|
||||
const result = validateOptions(modifiedOptions, template);
|
||||
const { _validated } = result;
|
||||
|
||||
expect(validated).not.toHaveProperty('nested');
|
||||
expect(_validated).not.toHaveProperty('nested');
|
||||
});
|
||||
|
||||
test('all nested values dont match template with foreign property', () => {
|
||||
@@ -316,10 +316,10 @@ describe('options validation', () => {
|
||||
switch: 1,
|
||||
},
|
||||
});
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { validated } = result;
|
||||
const result = validateOptions(modifiedOptions, template);
|
||||
const { _validated } = result;
|
||||
|
||||
expect(validated).not.toHaveProperty('nested');
|
||||
expect(_validated).not.toHaveProperty('nested');
|
||||
});
|
||||
|
||||
test('various values dont match template', () => {
|
||||
@@ -329,13 +329,13 @@ describe('options validation', () => {
|
||||
abc: 'testest',
|
||||
func: {},
|
||||
});
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { validated } = result;
|
||||
const result = validateOptions(modifiedOptions, template);
|
||||
const { _validated } = result;
|
||||
|
||||
expect(validated.nested).not.toHaveProperty('switch');
|
||||
expect(validated).not.toHaveProperty('obj');
|
||||
expect(validated).not.toHaveProperty('abc');
|
||||
expect(validated).not.toHaveProperty('func');
|
||||
expect(_validated.nested).not.toHaveProperty('switch');
|
||||
expect(_validated).not.toHaveProperty('obj');
|
||||
expect(_validated).not.toHaveProperty('abc');
|
||||
expect(_validated).not.toHaveProperty('func');
|
||||
});
|
||||
|
||||
test('various values dont match template with foreign properties', () => {
|
||||
@@ -355,42 +355,42 @@ describe('options validation', () => {
|
||||
foreignObj,
|
||||
{ nested: foreignObj }
|
||||
);
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { validated, foreign } = result;
|
||||
const result = validateOptions(modifiedOptions, template);
|
||||
const { _validated, _foreign } = result;
|
||||
|
||||
expect(foreign.nested).toEqual(foreignObj);
|
||||
delete foreign.nested;
|
||||
expect(foreign).toEqual(foreignObj);
|
||||
expect(_foreign.nested).toEqual(foreignObj);
|
||||
delete _foreign.nested;
|
||||
expect(_foreign).toEqual(foreignObj);
|
||||
|
||||
expect(validated.nested).not.toHaveProperty('switch');
|
||||
expect(validated).not.toHaveProperty('obj');
|
||||
expect(validated).not.toHaveProperty('abc');
|
||||
expect(validated).not.toHaveProperty('func');
|
||||
expect(_validated.nested).not.toHaveProperty('switch');
|
||||
expect(_validated).not.toHaveProperty('obj');
|
||||
expect(_validated).not.toHaveProperty('abc');
|
||||
expect(_validated).not.toHaveProperty('func');
|
||||
});
|
||||
|
||||
test('nested object is string', () => {
|
||||
const modifiedOptions = assignDeep({}, options, { nested: 'string' });
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { validated } = result;
|
||||
const result = validateOptions(modifiedOptions, template);
|
||||
const { _validated } = result;
|
||||
|
||||
expect(validated).not.toHaveProperty('nested');
|
||||
expect(_validated).not.toHaveProperty('nested');
|
||||
});
|
||||
|
||||
test('nested object is null', () => {
|
||||
const modifiedOptions = assignDeep({}, options, { nested: null });
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { validated } = result;
|
||||
const result = validateOptions(modifiedOptions, template);
|
||||
const { _validated } = result;
|
||||
|
||||
expect(validated).not.toHaveProperty('nested');
|
||||
expect(_validated).not.toHaveProperty('nested');
|
||||
});
|
||||
|
||||
test('nested object is undefined', () => {
|
||||
const modifiedOptions = assignDeep({}, options);
|
||||
modifiedOptions.nested = undefined;
|
||||
const result = validate(modifiedOptions, template);
|
||||
const { validated } = result;
|
||||
const result = validateOptions(modifiedOptions, template);
|
||||
const { _validated } = result;
|
||||
|
||||
expect(validated).not.toHaveProperty('nested');
|
||||
expect(_validated).not.toHaveProperty('nested');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -399,7 +399,7 @@ describe('options validation', () => {
|
||||
const { warn } = console;
|
||||
console.warn = jest.fn();
|
||||
|
||||
validate(options, template, {}, true);
|
||||
validateOptions(options, template, {}, true);
|
||||
expect(console.warn).not.toBeCalled();
|
||||
|
||||
console.warn = warn;
|
||||
@@ -410,7 +410,7 @@ describe('options validation', () => {
|
||||
console.warn = jest.fn();
|
||||
|
||||
const modifiedOptions = assignDeep({}, options, { str: 1 });
|
||||
validate(modifiedOptions, template, {}, false);
|
||||
validateOptions(modifiedOptions, template, {}, false);
|
||||
expect(console.warn).not.toBeCalled();
|
||||
|
||||
console.warn = warn;
|
||||
@@ -421,15 +421,15 @@ describe('options validation', () => {
|
||||
console.warn = jest.fn();
|
||||
|
||||
// str must be string
|
||||
validate(assignDeep({}, options, { str: 1 }), template, {}, true);
|
||||
validateOptions(assignDeep({}, options, { str: 1 }), template, {}, true);
|
||||
expect(console.warn).toBeCalledTimes(1);
|
||||
|
||||
// abc must be A | B | C
|
||||
validate(assignDeep({}, options, { abc: 'some string' }), template, {}, true);
|
||||
validateOptions(assignDeep({}, options, { abc: 'some string' }), template, {}, true);
|
||||
expect(console.warn).toBeCalledTimes(2);
|
||||
|
||||
// everthing OK
|
||||
validate(assignDeep({}, options, { abc: 'C' }), template, {}, true);
|
||||
validateOptions(assignDeep({}, options, { abc: 'C' }), template, {}, true);
|
||||
expect(console.warn).toBeCalledTimes(2);
|
||||
|
||||
console.warn = warn;
|
||||
|
||||
@@ -13,9 +13,9 @@ export declare type OptionsValidatedResult<T> = {
|
||||
readonly foreign: PlainObject;
|
||||
readonly validated: T;
|
||||
};
|
||||
export declare type OptionsAndOptionsTemplateValue<T extends OptionsTemplateNativeTypes> = [T, OptionsTemplateValue<T>];
|
||||
export declare type OptionsAndOptionsTemplate<T extends Required<T>> = {
|
||||
[P in keyof T]: PlainObject extends T[P] ? OptionsAndOptionsTemplate<Required<T[P]>> : T[P] extends OptionsTemplateNativeTypes ? OptionsAndOptionsTemplateValue<T[P]> : never;
|
||||
export declare type OptionsWithOptionsTemplateValue<T extends OptionsTemplateNativeTypes> = [T, OptionsTemplateValue<T>];
|
||||
export declare type OptionsWithOptionsTemplate<T extends Required<T>> = {
|
||||
[P in keyof T]: PlainObject extends T[P] ? OptionsWithOptionsTemplate<Required<T[P]>> : T[P] extends OptionsTemplateNativeTypes ? OptionsWithOptionsTemplateValue<T[P]> : never;
|
||||
};
|
||||
declare type OptionsTemplateTypeMap = {
|
||||
__TPL_boolean_TYPE__: boolean;
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import { OptionsTemplate, OptionsAndOptionsTemplate } from 'support/options';
|
||||
export declare function transform<T extends Required<T>>(optionsWithOptionsTemplate: OptionsAndOptionsTemplate<T>): T;
|
||||
export declare function transform<T extends Required<T>>(optionsWithOptionsTemplate: OptionsAndOptionsTemplate<T>, toTemplate: true | void): OptionsTemplate<T>;
|
||||
import { OptionsTemplate, OptionsWithOptionsTemplate } from 'support/options';
|
||||
export declare function transform<T extends Required<T>>(optionsWithOptionsTemplate: OptionsWithOptionsTemplate<T>): T;
|
||||
export declare function transform<T extends Required<T>>(optionsWithOptionsTemplate: OptionsWithOptionsTemplate<T>, toTemplate: true | void): OptionsTemplate<T>;
|
||||
|
||||
Reference in New Issue
Block a user