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