Something went wrong. Try again.
Mirror: CSS prefixing helpers in less than 1KB 🌈
Something went wrong. Try again.
4.5 kB · 133 lines
JavaScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134#!/usr/bin/env node
const prefixMap = require('inline-style-prefixer/lib/data').default.prefixMap;const mdnProperties = require('mdn-data/css/properties.json');
const PREFIX_MS = 'ms';const PREFIX_MOZ = 'Moz';const PREFIX_WEBKIT = 'Webkit';const prefixPropRe = /^-(ms|moz|webkit)-/;
/** A list of all properties that have to be prefixed */const properties = Object.keys(prefixMap) .map(prop => ({ // Convert inline-style-based name to CSS property name name: prop.replace(/[A-Z]/g, '-$&').toLowerCase(), // This describes what kind of prefixes are necessary: ms: !!prefixMap[prop].includes(PREFIX_MS), moz: !!prefixMap[prop].includes(PREFIX_MOZ), webkit: !!prefixMap[prop].includes(PREFIX_WEBKIT), })) // Omit CSS properties that are not listed by MDN or are obsolete .filter(({ name }) => ( mdnProperties[name] && mdnProperties[name].status !== 'obsolete' && // Skip some properties that aren't widely supported or don't need prefixing: name !== 'backdrop-filter' && name !== 'filter' && // Skip some properties that are obsolete: name !== 'scroll-snap-points-x' && name !== 'scroll-snap-points-y' && name !== 'scroll-snap-points-destination' && name !== 'scroll-snap-points-coordinate' && name !== 'flow-into' && name !== 'flow-from' && name !== 'wrap-flow' && name !== 'wrap-through' && name !== 'wrap-margin' ));
// See SUPPORT.md on background-clipproperties.push({ name: 'background-clip', ms: false, moz: false, webkit: true});
// These are supported in Firefox, Chrome, and Safari// NOTE: Their variants with before/after are not supported// by Firefox and should be avoidedproperties.push(...[ 'border-start', 'border-start-color', 'border-start-style', 'border-start-width', 'border-end', 'border-end-color', 'border-end-style', 'border-end-width', 'border-start-start-radius', 'border-start-end-radius', 'border-end-start-radius', 'border-end-end-radius',].map(name => ({ name, ms: false, moz: true, webkit: true })));
/** A list of stable, non-prefixable property names */const stablePropertyNames = Object.keys(mdnProperties) .filter(x => ( // Only include non-obsolete CSS properties mdnProperties[x].status !== 'obsolete' && x !== 'all' && x !== '--*' && // Skip some properties that aren't widely supported: x !== 'text-decoration-skip-ink' && x !== 'text-decoration-thickness' && // Exclude prefixed properties !prefixPropRe.test(x) && // Exclude properties that are to be prefixed (i.e. non-standard) !properties.some(({ name }) => name === x) ));
/** Finds the minimum starting substring that uniquely identifier a property out of all known CSS properties */const findMinimumSubstr = name => { for (let i = 2, l = name.length; i < l; i++) { const substr = name.slice(0, i); // Check for any name that conflicts with the substring in all known CSS properties if (stablePropertyNames.every(x => x === name || !x.startsWith(substr))) { return substr; } }
return name;};
/** Lists each prefixed property with the minimum substring that is needed to uniquely identity it */const prefixPatterns = properties.map(prop => ({ ...prop, name: findMinimumSubstr(prop.name)}));
/** For Webkit prefixes, these properties will need some values to be prefixed */const prefixValuePatterns = ['position', 'background-clip'].map(findMinimumSubstr);
/** Accepts a filter and builds a list of names in `prefixPatterns` */const reducePrefixes = (filter = x => !!x) => { const set = prefixPatterns.reduce((acc, prop) => { if (filter(prop)) acc.add(prop.name); return acc; }, new Set());
return [...set].sort((a, b) => { if (a.length === b.length) return a.localeCompare(b); return a.length - b.length; });};
/** Creates a regex matching property names */const buildRegex = groups => `^(${groups.join('|')})`;
// Create all prefix sets for each prefixconst msPrefixes = buildRegex(reducePrefixes(x => x.ms));const mozPrefixes = buildRegex(reducePrefixes(x => x.moz));const webkitPrefixes = buildRegex(reducePrefixes(x => x.webkit));
// Create a regex for webkit value transformsconst webkitValuePrefix = buildRegex(prefixValuePatterns);
module.exports = `var msPrefixRe = /${msPrefixes}/;var mozPrefixRe = /${mozPrefixes}/;var webkitPrefixRe = /${webkitPrefixes}/;var webkitValuePrefixRe = /${webkitValuePrefix}/;`.trim();