194 lines
4.8 KiB
JavaScript
194 lines
4.8 KiB
JavaScript
const {
|
|
entries,
|
|
setPrototypeOf,
|
|
isFrozen,
|
|
getPrototypeOf,
|
|
getOwnPropertyDescriptor,
|
|
} = Object;
|
|
|
|
let { freeze, seal, create } = Object; // eslint-disable-line import/no-mutable-exports
|
|
let { apply, construct } = typeof Reflect !== 'undefined' && Reflect;
|
|
|
|
if (!freeze) {
|
|
freeze = function (x) {
|
|
return x;
|
|
};
|
|
}
|
|
|
|
if (!seal) {
|
|
seal = function (x) {
|
|
return x;
|
|
};
|
|
}
|
|
|
|
if (!apply) {
|
|
apply = function (fun, thisValue, args) {
|
|
return fun.apply(thisValue, args);
|
|
};
|
|
}
|
|
|
|
if (!construct) {
|
|
construct = function (Func, args) {
|
|
return new Func(...args);
|
|
};
|
|
}
|
|
|
|
const arrayForEach = unapply(Array.prototype.forEach);
|
|
const arrayIndexOf = unapply(Array.prototype.indexOf);
|
|
const arrayPop = unapply(Array.prototype.pop);
|
|
const arrayPush = unapply(Array.prototype.push);
|
|
const arraySlice = unapply(Array.prototype.slice);
|
|
|
|
const stringToLowerCase = unapply(String.prototype.toLowerCase);
|
|
const stringToString = unapply(String.prototype.toString);
|
|
const stringMatch = unapply(String.prototype.match);
|
|
const stringReplace = unapply(String.prototype.replace);
|
|
const stringIndexOf = unapply(String.prototype.indexOf);
|
|
const stringTrim = unapply(String.prototype.trim);
|
|
|
|
const regExpTest = unapply(RegExp.prototype.test);
|
|
|
|
const typeErrorCreate = unconstruct(TypeError);
|
|
|
|
/**
|
|
* Creates a new function that calls the given function with a specified thisArg and arguments.
|
|
*
|
|
* @param {Function} func - The function to be wrapped and called.
|
|
* @returns {Function} A new function that calls the given function with a specified thisArg and arguments.
|
|
*/
|
|
function unapply(func) {
|
|
return (thisArg, ...args) => apply(func, thisArg, args);
|
|
}
|
|
|
|
/**
|
|
* Creates a new function that constructs an instance of the given constructor function with the provided arguments.
|
|
*
|
|
* @param {Function} func - The constructor function to be wrapped and called.
|
|
* @returns {Function} A new function that constructs an instance of the given constructor function with the provided arguments.
|
|
*/
|
|
function unconstruct(func) {
|
|
return (...args) => construct(func, args);
|
|
}
|
|
|
|
/**
|
|
* Add properties to a lookup table
|
|
*
|
|
* @param {Object} set - The set to which elements will be added.
|
|
* @param {Array} array - The array containing elements to be added to the set.
|
|
* @param {Function} transformCaseFunc - An optional function to transform the case of each element before adding to the set.
|
|
* @returns {Object} The modified set with added elements.
|
|
*/
|
|
function addToSet(set, array, transformCaseFunc = stringToLowerCase) {
|
|
if (setPrototypeOf) {
|
|
// Make 'in' and truthy checks like Boolean(set.constructor)
|
|
// independent of any properties defined on Object.prototype.
|
|
// Prevent prototype setters from intercepting set as a this value.
|
|
setPrototypeOf(set, null);
|
|
}
|
|
|
|
let l = array.length;
|
|
while (l--) {
|
|
let element = array[l];
|
|
if (typeof element === 'string') {
|
|
const lcElement = transformCaseFunc(element);
|
|
if (lcElement !== element) {
|
|
// Config presets (e.g. tags.js, attrs.js) are immutable.
|
|
if (!isFrozen(array)) {
|
|
array[l] = lcElement;
|
|
}
|
|
|
|
element = lcElement;
|
|
}
|
|
}
|
|
|
|
set[element] = true;
|
|
}
|
|
|
|
return set;
|
|
}
|
|
|
|
/**
|
|
* Shallow clone an object
|
|
*
|
|
* @param {Object} object - The object to be cloned.
|
|
* @returns {Object} A new object that copies the original.
|
|
*/
|
|
export function clone(object) {
|
|
const newObject = create(null);
|
|
|
|
for (const [property, value] of entries(object)) {
|
|
if (getOwnPropertyDescriptor(object, property) !== undefined) {
|
|
newObject[property] = value;
|
|
}
|
|
}
|
|
|
|
return newObject;
|
|
}
|
|
|
|
/**
|
|
* This method automatically checks if the prop is function or getter and behaves accordingly.
|
|
*
|
|
* @param {Object} object - The object to look up the getter function in its prototype chain.
|
|
* @param {String} prop - The property name for which to find the getter function.
|
|
* @returns {Function} The getter function found in the prototype chain or a fallback function.
|
|
*/
|
|
function lookupGetter(object, prop) {
|
|
while (object !== null) {
|
|
const desc = getOwnPropertyDescriptor(object, prop);
|
|
|
|
if (desc) {
|
|
if (desc.get) {
|
|
return unapply(desc.get);
|
|
}
|
|
|
|
if (typeof desc.value === 'function') {
|
|
return unapply(desc.value);
|
|
}
|
|
}
|
|
|
|
object = getPrototypeOf(object);
|
|
}
|
|
|
|
function fallbackValue(element) {
|
|
console.warn('fallback value for', element);
|
|
return null;
|
|
}
|
|
|
|
return fallbackValue;
|
|
}
|
|
|
|
export {
|
|
// Array
|
|
arrayForEach,
|
|
arrayIndexOf,
|
|
arrayPop,
|
|
arrayPush,
|
|
arraySlice,
|
|
// Object
|
|
entries,
|
|
freeze,
|
|
getPrototypeOf,
|
|
getOwnPropertyDescriptor,
|
|
isFrozen,
|
|
setPrototypeOf,
|
|
seal,
|
|
create,
|
|
// RegExp
|
|
regExpTest,
|
|
// String
|
|
stringIndexOf,
|
|
stringMatch,
|
|
stringReplace,
|
|
stringToLowerCase,
|
|
stringToString,
|
|
stringTrim,
|
|
// Errors
|
|
typeErrorCreate,
|
|
// Other
|
|
lookupGetter,
|
|
addToSet,
|
|
// Reflect
|
|
unapply,
|
|
unconstruct,
|
|
};
|