Mirror: CSS prefixing helpers in less than 1KB 馃寛
at v1.1.2 4.1 kB view raw
1#!/usr/bin/env node 2 3const prefixMap = require('inline-style-prefixer/lib/data').default.prefixMap; 4const mdnProperties = require('mdn-data/css/properties.json'); 5 6const PREFIX_MS = 'ms'; 7const PREFIX_MOZ = 'Moz'; 8const PREFIX_WEBKIT = 'Webkit'; 9const prefixPropRe = /^-(ms|moz|webkit)-/; 10 11/** A list of all properties that have to be prefixed */ 12const properties = Object.keys(prefixMap) 13 .map(prop => ({ 14 // Convert inline-style-based name to CSS property name 15 name: prop.replace(/[A-Z]/g, '-$&').toLowerCase(), 16 // This describes what kind of prefixes are necessary: 17 ms: !!prefixMap[prop].includes(PREFIX_MS), 18 moz: !!prefixMap[prop].includes(PREFIX_MOZ), 19 webkit: !!prefixMap[prop].includes(PREFIX_WEBKIT), 20 })) 21 // Omit CSS properties that are not listed by MDN or are obsolete 22 .filter(({ name }) => ( 23 mdnProperties[name] && 24 mdnProperties[name].status !== 'obsolete' && 25 // Skip some properties that aren't widely supported or don't need prefixing: 26 name !== 'backdrop-filter' && 27 name !== 'filter' && 28 // Skip some properties that are obsolete: 29 name !== 'scroll-snap-points-x' && 30 name !== 'scroll-snap-points-y' && 31 name !== 'scroll-snap-points-destination' && 32 name !== 'scroll-snap-points-coordinate' && 33 name !== 'flow-into' && 34 name !== 'flow-from' && 35 name !== 'wrap-flow' && 36 name !== 'wrap-through' && 37 name !== 'wrap-margin' 38 )); 39 40// See SUPPORT.md on background-clip 41properties.push({ 42 name: 'background-clip', 43 ms: false, 44 moz: false, 45 webkit: true 46}); 47 48// These are supported in Firefox, Chrome, and Safari 49// NOTE: Their variants with before/after are not supported 50// by Firefox and should be avoided 51properties.push(...[ 52 'margin-start', 53 'margin-end', 54 'padding-start', 55 'padding-end', 56 'border-start', 57 'border-start-color', 58 'border-start-style', 59 'border-start-width', 60 'border-end', 61 'border-end-color', 62 'border-end-style', 63 'border-end-width', 64 'border-start-start-radius', 65 'border-start-end-radius', 66 'border-end-start-radius', 67 'border-end-end-radius', 68].map(name => ({ name, ms: false, moz: true, webkit: true }))); 69 70/** A list of stable, non-prefixable property names */ 71const stablePropertyNames = Object.keys(mdnProperties) 72 .filter(x => ( 73 // Only include non-obsolete CSS properties 74 mdnProperties[x].status !== 'obsolete' && 75 x !== 'all' && 76 x !== '--*' && 77 // Skip some properties that aren't widely supported: 78 x !== 'text-decoration-skip-ink' && 79 x !== 'text-decoration-thickness' && 80 // Exclude prefixed properties 81 !prefixPropRe.test(x) && 82 // Exclude properties that are to be prefixed (i.e. non-standard) 83 !properties.some(({ name }) => name === x) 84 )); 85 86/** Lists each prefixed property with the minimum substring that is needed to uniquely identity it */ 87const prefixPatterns = properties 88 .map(prop => { 89 let name = prop.name; 90 for (let i = 2, l = name.length; i < l; i++) { 91 const substr = name.slice(0, i); 92 // Check for any name that conflicts with the substring in all known CSS properties 93 if (stablePropertyNames.every(x => x === name || !x.startsWith(substr))) { 94 name = substr; 95 break; 96 } 97 } 98 99 return { ...prop, name }; 100 }); 101 102/** Accepts a filter and builds a list of names in `prefixPatterns` */ 103const reducePrefixes = (filter = x => !!x) => { 104 const set = prefixPatterns.reduce((acc, prop) => { 105 if (filter(prop)) acc.add(prop.name); 106 return acc; 107 }, new Set()); 108 109 return [...set].sort((a, b) => { 110 if (a.length === b.length) return a.localeCompare(b); 111 return a.length - b.length; 112 }); 113}; 114 115const buildRegex = groups => `^(${groups.join('|')})`; 116 117// Create all prefix sets for each prefix 118const msPrefixes = buildRegex(reducePrefixes(x => x.ms)); 119const mozPrefixes = buildRegex(reducePrefixes(x => x.moz)); 120const webkitPrefixes = buildRegex(reducePrefixes(x => x.webkit)); 121 122module.exports = ` 123var msPrefixRe = /${msPrefixes}/; 124var mozPrefixRe = /${mozPrefixes}/; 125var webkitPrefixRe = /${webkitPrefixes}/; 126`.trim();