UNPKG

@fylgja/props-builder

Version:

Effortlessly generate Design Tokens (CSS custom properties) from JavaScript objects.

171 lines (147 loc) 4.11 kB
// Fylgja (fylgja.dev) // Licensed under MIT Open Source export const cssVarRegex = /var\(--([a-zA-Z0-9-]+)\)/g; export const tokenVarRegex = /\{([a-zA-Z0-9.-]+)\}/g; /** * Convert a string to kebab case. * * @param {string} string * @returns {string} kebab case string */ export function kebabCase(string) { return string.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase(); } /** * Check if the value is a string and does not contain special characters * * @param {*} value * @returns {boolean} */ export function isValidString(value) { const regex = /^[a-zA-Z0-9\s]+$/; return typeof value === "string" && regex.test(value); } /** * get the file type based on the file name. * * @param {string} filename * @returns {string} - file base type to work with */ export function isFileType(filename) { if ( filename.endsWith("figma-tokens.json") || filename.endsWith("figma-tokens.sync.json") ) { return "figma"; } if (filename.endsWith("style-dictionary-tokens.json")) { return "style-dictionary"; } if (filename.endsWith("tokens.json")) { return "tokens"; } if (filename.endsWith(".cjs")) { return "cjs"; } if (filename.endsWith(".js") || filename.endsWith(".mjs")) { return "mjs"; } return filename.split(/[.;+_]/).pop(); } /** * Flatten Object into a flat Object * * @param {Object} obj - object to flatten * @param {string} separator - separator to use for the combined keys * @returns {Object} - flattened object */ export const flattenObj = (obj, separator = "-") => { let result = {}; for (const i in obj) { if (typeof obj[i] === "object" && !Array.isArray(obj[i])) { const temp = flattenObj(obj[i]); for (const j in temp) { result[i + separator + j] = temp[j]; } } else { result[i] = obj[i]; } } return result; }; /** * Unwrap a nested Object by following a path of keys, dropping everything * above it. Useful for tokens files that wrap the actual tokens in * structural keys (e.g. `tokens.values`) that shouldn't end up in the * generated CSS variable names. * * @param {Object} obj - object to unwrap * @param {string|string[]} keyPath - dot/dash separated path, or array of keys, to unwrap * @returns {Object} - the object found at `keyPath`, or the original object if the path doesn't exist */ export const stripPrefixPath = (obj, keyPath) => { if (!keyPath) return obj; const keys = Array.isArray(keyPath) ? keyPath : keyPath.split(/[.-]/); let current = obj; for (const key of keys) { if ( current && typeof current === "object" && !Array.isArray(current) && Object.prototype.hasOwnProperty.call(current, key) ) { current = current[key]; } else { return obj; } } return current; }; /** * Recursively renames Object keys based on a lookup map. * Useful to align generated token names with a naming convention * (e.g. renaming a `colors` group to `color`). * * @param {Object} obj - object to rename keys in * @param {Object} renameMap - map of `{ [currentKey]: newKey }` * @returns {Object} - object with renamed keys */ export const renameKeys = (obj, renameMap) => { if (!renameMap || typeof obj !== "object" || obj === null || Array.isArray(obj)) { return obj; } return Object.fromEntries( Object.entries(obj).map(([key, value]) => { const newKey = Object.prototype.hasOwnProperty.call(renameMap, key) ? renameMap[key] : key; return [newKey, renameKeys(value, renameMap)]; }), ); }; /** * Turns a flat Object in to a deep nested Object, * based on the keys * * @param {Object} obj - object to unflatten * @param {string} separator - separator to use to detect the nested keys * @returns {Object} - nested object based on the separator */ export const unflattenObj = (obj, separator = "-") => { let result = {}; for (const i in obj) { const keys = i.split(separator); let current = result; keys.forEach((key, index) => { if (index === keys.length - 1) { current[key] = obj[i]; } else { if (!current[key]) { current[key] = {}; } current = current[key]; } }); } return result; };