UNPKG

xuxi

Version:

Dynamically utility for combining different types of values ​​into a single value.

317 lines 11.7 kB
(function(g,f){typeof exports==='object'&&typeof module!=='undefined'?f(exports):typeof define==='function'&&define.amd?define(['exports'],f):(g=typeof globalThis!=='undefined'?globalThis:g||self,f(g.Xuxi={}));})(this,(function(exports){'use strict';/** * A utility function for managing values based on variant configurations. * * This function simplifies the handling of value generation with support for variants, default values, and dynamic overrides. * @template T - The type of variant keys and their possible values. * @param {VariantRecord<T>} keys - The configuration object containing: * - `assign` (optional): A base value to always include. * - `variants`: An object defining variant keys and their possible values as classes. * - `defaultVariants` (optional): Default variant values for each variant key. * @returns {(result?: VariantResult<T>) => string} - A function that takes a `result` object to override default variants * and generates a class name string. * @example * @see {@link https://ilkhoeri.github.io/xuxi/variant Docs} */ function variant(keys) { return (result = {}) => { const mergedVariant = { ...keys.defaultVariants, ...result }; const variants = Object.keys(keys.variants) .map(key => { var _a; const variantKey = mergedVariant[key] || ((_a = keys.defaultVariants) === null || _a === undefined ? undefined : _a[key]); return variantKey ? keys.variants[key][variantKey] : undefined; }) .filter(Boolean) .join(' ') .trim(); return keys.assign ? [keys.assign, variants].join(' ').trim() : variants; }; }/** * Serializes a given value into a space-separated string. * @param v - The value to be processed. * @returns A space-separated string representation of the value. */ function sv(v) { let k, y, s = ''; if (typeof v === 'string' || typeof v === 'number' || typeof v === 'bigint' || v === null) { s += v; } else if (typeof v === 'object') { if (Array.isArray(v)) { let o = v.length; for (k = 0; k < o; k++) { if (v[k]) { if ((y = sv(v[k]))) { s && (s += ' '); s += y; } } } } else { for (y in v) { if (v[y]) { s && (s += ' '); s += y; } } } } else if (typeof v === 'function') { s += sv(v(s)); } return s; } /** * Recursively serializes objects into a key-value string format. * @param v - The value to be processed. * @returns A string representation of the object. */ function rv(v) { let k, y, s = ''; if (typeof v === 'object' && v !== null) { if (Array.isArray(v)) { let o = v.length; for (k = 0; k < o; k++) { if (v[k]) { if ((y = rv(v[k]))) { s && (s += ' '); s += y; } } } } else { for (y in v) { if (v[y]) { s && (s += ' '); s += `${y}:${typeof v[y] === 'object' ? rv(v[y]) : v[y]}`; } } for (const sym of Object.getOwnPropertySymbols(v)) { if (v[sym]) { s && (s += ' '); s += `${String(sym)}:${v[sym]}`; } } } } return s; } /** * Serializes instances of Date, Map, and Set objects into a string format. * @param v - The value to be processed. * @returns A string representation of the instance. */ function iv(v) { let k, y, s = ''; if (v instanceof Date) { s += v.toISOString(); } else if (v instanceof Map) { for (const [q, u] of v.entries()) { if (u) { s && (s += ' '); // concatenation s += `${q}:${u}`; } } } else if (v instanceof Set) { v.forEach(e => { if (e) { s && (s += ' '); s += e; } }); } else if (typeof v === 'object') { if (Array.isArray(v)) { var o = v.length; for (k = 0; k < o; k++) { if (v[k]) { if ((y = iv(v[k]))) { s && (s += ' '); s += y; } } } } } else if (typeof v === 'function') { s += iv(v(s)); } return s; } /** * Applies recursive transformation to the input values. * @param args - Input values. * @returns Transformed string. */ function recursiveFn(...args) { return rv(args); } /** * Applies instance-based transformation to the input values. * @param args - Input values. * @returns Transformed string. */ function instanceofFn(...args) { return iv(args); } /** * Converts input values into a space-separated string. * @param args - Input values. * @returns The formatted string. */ const string = (...args) => { let i = 0, t, x, s = '', o = args.length; for (; i < o; i++) { if ((t = args[i])) { if ((x = sv(t))) { s && (s += ' '); s += x; } } } return s; }; string.recursive = recursiveFn; string.instanceof = instanceofFn; string.variant = variant;/** * Checks if a given value is a plain object (i.e., not an array or null). * @param value - The value to check. * @returns True if the value is a plain object, otherwise false. */ function isPlainObject(value) { return value !== null && typeof value === 'object' && !Array.isArray(value); } /** * Merges multiple objects deeply, handling arrays and functions gracefully. * @template T - The base object type. * @param obj - One or more objects to merge. * @returns The deeply merged object. */ function baseObject(...obj) { const seen = new WeakMap(); // Use WeakMap to store processed objects function merge(acc, input) { if (!input) return acc; if (isPlainObject(input)) { if (seen.has(input)) return seen.get(input); // If there is one, use previous result. const newAcc = { ...acc }; // Copy acc so as not to change direct references seen.set(input, newAcc); // Mark objects as processed acc = newAcc; // Use copied version } if (Array.isArray(input)) return { ...acc, ...baseObject(...input) }; if (typeof input === 'function') { const result = input(acc); return isPlainObject(result) ? merge(acc, result) : { ...acc, ...baseObject(result) }; } if (isPlainObject(input)) { Reflect.ownKeys(input).forEach(key => { const value = input[key]; if (isPlainObject(value) && isPlainObject(acc[key])) { acc[key] = merge(acc[key], value); } else { acc[key] = value; } }); return acc; } return acc; } return obj.reduce((acc, input) => merge(acc, input), {}); } /** * Merges multiple objects deeply, handling arrays and functions gracefully **without overwriting**. * @template T - The base object type. * @param obj - One or more objects to merge. * @returns The deeply merged object **without overwriting** the value at the first key, only change the value if it does not exist. */ function preserveRoot(...obj) { const seen = new WeakMap(); function merge(acc, input) { if (!input) return acc; if (isPlainObject(input)) { if (seen.has(input)) return seen.get(input); const newAcc = { ...acc }; seen.set(input, newAcc); acc = newAcc; } if (Array.isArray(input)) return { ...acc, ...preserveRoot(...input) }; if (typeof input === 'function') { const result = input(acc); return isPlainObject(result) ? merge(acc, result) : { ...acc, ...preserveRoot(result) }; } if (isPlainObject(input)) { Reflect.ownKeys(input).forEach(key => { const value = input[key]; if (acc[key] === undefined) { acc[key] = value; // Only change the value if it does not exist } else if (isPlainObject(value) && isPlainObject(acc[key])) { acc[key] = merge(acc[key], value); } }); return acc; } return acc; } return obj.reduce((acc, input) => merge(acc, input), {}); } /** * Recursively removes falsy values from an object, except those specified in `exclude`. * @template T - The object type. * @param obj - The object to clean. * @param exclude - An array of values to be preserved even if they are falsy (default: `[]`). * @param seen - To detect cyclic references (default: `new WeakSet<object>()`). * @returns A new object without the falsy values. * @example * @see {@link https://ilkhoeri.github.io/xuxi/clean Docs} */ function clean(obj, exclude = [], seen = new WeakSet()) { const excludeSet = new Set(exclude); if (seen.has(obj)) return obj; // Avoid infinite loops seen.add(obj); // Mark object as visited return Reflect.ownKeys(obj).reduce((acc, key) => { const value = obj[key]; if (isPlainObject(value)) { const cleanedObject = clean(value, exclude, seen); // Clean objects recursively // Ensure the object is not empty before inserting if (Object.keys(cleanedObject).length > 0 || typeof key === 'symbol') acc[key] = cleanedObject; } else if (Array.isArray(value)) { // Clear every element in the array, remove empty objects const cleanedArray = value .map(item => (isPlainObject(item) ? clean(item, exclude, seen) : item)) .filter(item => (item && !(isPlainObject(item) && Object.keys(item).length === 0)) || excludeSet.has(item)); if (cleanedArray.length > 0) acc[key] = cleanedArray; } else if (value || excludeSet.has(value) || typeof key === 'symbol') { // Save the value if it is not falsy or belongs to `excludeSet` acc[key] = value; } return acc; }, {}); } /** * Recursively merge objects with support for arrays, dynamic functions, and non falsy properties into a single object. * * Provides a chaining: * - {@link baseObject raw} method to **get falsy values** from the result. * - {@link preserveRoot preserve} method to join **without overwriting** first value. * @example * @see {@link https://ilkhoeri.github.io/xuxi/?id=object Docs} */ const object = (...obj) => clean(baseObject(...obj), [0]); object.raw = baseObject; object.preserve = preserveRoot;var x=/*#__PURE__*/Object.freeze({__proto__:null,clean:clean,instanceof:instanceofFn,isPlainObject:isPlainObject,object:object,recursive:recursiveFn,string:string,variant:variant});exports.clean=clean;exports.default=x;exports.instanceof=instanceofFn;exports.isPlainObject=isPlainObject;exports.object=object;exports.recursive=recursiveFn;exports.string=string;exports.variant=variant;exports.x=x;Object.defineProperty(exports,'__esModule',{value:true});}));