AK-21/Graphite-Industrial-Intelligence
0
1let { list } = require('postcss')2 3let Browsers = require('./browsers')4let OldSelector = require('./old-selector')5let Prefixer = require('./prefixer')6let utils = require('./utils')7 8class Selector extends Prefixer {9 constructor(name, prefixes, all) {10 super(name, prefixes, all)11 this.regexpCache = new Map()12 }13 14 /**15 * Clone and add prefixes for at-rule16 */17 add(rule, prefix) {18 let prefixeds = this.prefixeds(rule)19 20 if (this.already(rule, prefixeds, prefix)) {21 return22 }23 24 let cloned = this.clone(rule, { selector: prefixeds[this.name][prefix] })25 rule.parent.insertBefore(rule, cloned)26 }27 28 /**29 * Is rule already prefixed before30 */31 already(rule, prefixeds, prefix) {32 let index = rule.parent.index(rule) - 133 34 while (index >= 0) {35 let before = rule.parent.nodes[index]36 37 if (before.type !== 'rule') {38 return false39 }40 41 let some = false42 for (let key in prefixeds[this.name]) {43 let prefixed = prefixeds[this.name][key]44 if (before.selector === prefixed) {45 if (prefix === key) {46 return true47 } else {48 some = true49 break50 }51 }52 }53 if (!some) {54 return false55 }56 57 index -= 158 }59 60 return false61 }62 63 /**64 * Is rule selectors need to be prefixed65 */66 check(rule) {67 if (rule.selector.includes(this.name)) {68 return !!rule.selector.match(this.regexp())69 }70 71 return false72 }73 74 /**75 * Return function to fast find prefixed selector76 */77 old(prefix) {78 return new OldSelector(this, prefix)79 }80 81 /**82 * All possible prefixes83 */84 possible() {85 return Browsers.prefixes()86 }87 88 /**89 * Return prefixed version of selector90 */91 prefixed(prefix) {92 return this.name.replace(/^(\W*)/, `$1${prefix}`)93 }94 95 /**96 * Return all possible selector prefixes97 */98 prefixeds(rule) {99 if (rule._autoprefixerPrefixeds) {100 if (rule._autoprefixerPrefixeds[this.name]) {101 return rule._autoprefixerPrefixeds102 }103 } else {104 rule._autoprefixerPrefixeds = {}105 }106 107 let prefixeds = {}108 if (rule.selector.includes(',')) {109 let ruleParts = list.comma(rule.selector)110 let toProcess = ruleParts.filter(el => el.includes(this.name))111 112 for (let prefix of this.possible()) {113 prefixeds[prefix] = toProcess114 .map(el => this.replace(el, prefix))115 .join(', ')116 }117 } else {118 for (let prefix of this.possible()) {119 prefixeds[prefix] = this.replace(rule.selector, prefix)120 }121 }122 123 rule._autoprefixerPrefixeds[this.name] = prefixeds124 return rule._autoprefixerPrefixeds125 }126 127 /**128 * Lazy loadRegExp for name129 */130 regexp(prefix) {131 if (!this.regexpCache.has(prefix)) {132 let name = prefix ? this.prefixed(prefix) : this.name133 this.regexpCache.set(134 prefix,135 new RegExp(`(^|[^:"'=])${utils.escapeRegexp(name)}`, 'gi')136 )137 }138 139 return this.regexpCache.get(prefix)140 }141 142 /**143 * Replace selectors by prefixed one144 */145 replace(selector, prefix) {146 return selector.replace(this.regexp(), `$1${this.prefixed(prefix)}`)147 }148}149 150module.exports = Selector151 