2019-07-11 13:57:06 +00:00
|
|
|
// import { BaseToneOptions } from "../Tone";
|
2019-06-18 01:52:02 +00:00
|
|
|
import { isDefined, isObject, isUndef } from "./TypeCheck";
|
2019-05-22 04:14:43 +00:00
|
|
|
|
2019-07-11 13:57:06 +00:00
|
|
|
type BaseToneOptions = import("../Tone").BaseToneOptions;
|
|
|
|
|
2019-05-22 04:14:43 +00:00
|
|
|
/**
|
|
|
|
* Recursively merge an object
|
|
|
|
* @param target the object to merge into
|
|
|
|
* @param sources the source objects to merge
|
|
|
|
*/
|
|
|
|
export function deepMerge<T>(target: T, ...sources: T[]): T {
|
|
|
|
if (!sources.length) { return target; }
|
|
|
|
const source = sources.shift();
|
|
|
|
|
|
|
|
if (isObject(target) && isObject(source)) {
|
|
|
|
for (const key in source) {
|
2019-07-23 21:09:11 +00:00
|
|
|
// values with the key 'value' are an exception
|
|
|
|
// they don't get deep merged
|
|
|
|
if (key === "value") {
|
|
|
|
target[key] = source[key];
|
|
|
|
} else if (isObject(source[key])) {
|
2019-05-22 04:14:43 +00:00
|
|
|
if (!target[key]) { Object.assign(target, { [key]: {} }); }
|
|
|
|
deepMerge(target[key], source[key] as any);
|
|
|
|
} else {
|
|
|
|
Object.assign(target, { [key]: source[key] as any });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return deepMerge(target, ...sources);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Convert an args array into an object.
|
|
|
|
*/
|
2019-07-22 20:15:55 +00:00
|
|
|
export function optionsFromArguments<T extends object>(
|
|
|
|
defaults: T,
|
|
|
|
argsArray: IArguments,
|
|
|
|
keys: string[] = [],
|
|
|
|
objKey?: string,
|
|
|
|
): T {
|
2019-05-22 04:14:43 +00:00
|
|
|
const opts: any = {};
|
|
|
|
const args = Array.from(argsArray);
|
2019-07-22 20:15:55 +00:00
|
|
|
// if the first argument is an object and has an object key
|
|
|
|
if (isObject(args[0]) && objKey && !Reflect.has(args[0], objKey)) {
|
|
|
|
// if it's not part of the defaults
|
|
|
|
const partOfDefaults = Object.keys(args[0]).some(key => Reflect.has(defaults, key));
|
|
|
|
if (!partOfDefaults) {
|
|
|
|
// merge that key
|
|
|
|
deepMerge(opts, {[objKey] : args[0]});
|
|
|
|
// remove the obj key from the keys
|
|
|
|
keys.splice(keys.indexOf(objKey), 1);
|
|
|
|
// shift the first argument off
|
|
|
|
args.shift();
|
|
|
|
}
|
|
|
|
}
|
2019-05-22 04:14:43 +00:00
|
|
|
if (args.length === 1 && isObject(args[0])) {
|
|
|
|
deepMerge(opts, args[0]);
|
|
|
|
} else {
|
|
|
|
for (let i = 0; i < keys.length; i++) {
|
|
|
|
if (isDefined(args[i])) {
|
|
|
|
opts[keys[i]] = args[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return deepMerge(defaults, opts);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return this instances default values by calling Constructor.getDefaults()
|
|
|
|
*/
|
|
|
|
export function getDefaultsFromInstance<T>(instance: T): BaseToneOptions {
|
|
|
|
type ToneClass = {
|
|
|
|
constructor: ToneClass;
|
|
|
|
getDefaults: () => BaseToneOptions;
|
|
|
|
} & T;
|
|
|
|
|
|
|
|
return (instance as ToneClass).constructor.getDefaults();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2019-06-18 01:52:02 +00:00
|
|
|
* Returns the fallback if the given object is undefined.
|
2019-05-22 04:14:43 +00:00
|
|
|
* Take an array of arguments and return a formatted options object.
|
|
|
|
*/
|
2019-06-18 01:52:02 +00:00
|
|
|
export function defaultArg<T>(given: T, fallback: T): T {
|
|
|
|
if (isUndef(given)) {
|
|
|
|
return fallback;
|
|
|
|
} else {
|
|
|
|
return given;
|
|
|
|
}
|
|
|
|
}
|
2019-07-18 18:06:10 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Remove all of the properties belonging to omit from obj.
|
|
|
|
*/
|
2019-07-19 16:32:42 +00:00
|
|
|
export function omitFromObject<T extends object, O extends string[]>(obj: T, omit: O): Omit<T, keyof O> {
|
|
|
|
omit.forEach(prop => {
|
2019-07-18 18:06:10 +00:00
|
|
|
if (Reflect.has(obj, prop)) {
|
|
|
|
delete obj[prop];
|
|
|
|
}
|
2019-07-19 16:32:42 +00:00
|
|
|
});
|
2019-07-18 18:06:10 +00:00
|
|
|
return obj;
|
|
|
|
}
|