Skip to main content
Go to Latest
File
import { list } from "./deps.js";import OldSelector from "./old-selector.js";import Prefixer from "./prefixer.js";import Browsers from "./browsers.js";import * as utils from "./utils.js";
class Selector extends Prefixer { constructor(name, prefixes, all) { super(name, prefixes, all); this.regexpCache = new Map(); }
/** * Is rule selectors need to be prefixed */ check(rule) { if (rule.selector.includes(this.name)) { return !!rule.selector.match(this.regexp()); }
return false; }
/** * Return prefixed version of selector */ prefixed(prefix) { return this.name.replace(/^(\W*)/, `$1${prefix}`); }
/** * Lazy loadRegExp for name */ regexp(prefix) { if (!this.regexpCache.has(prefix)) { let name = prefix ? this.prefixed(prefix) : this.name; this.regexpCache.set( prefix, new RegExp(`(^|[^:"'=])${utils.escapeRegexp(name)}`, "gi"), ); }
return this.regexpCache.get(prefix); }
/** * All possible prefixes */ possible() { return Browsers.prefixes(); }
/** * Return all possible selector prefixes */ prefixeds(rule) { if (rule._autoprefixerPrefixeds) { if (rule._autoprefixerPrefixeds[this.name]) { return rule._autoprefixerPrefixeds; } } else { rule._autoprefixerPrefixeds = {}; }
let prefixeds = {}; if (rule.selector.includes(",")) { let ruleParts = list.comma(rule.selector); let toProcess = ruleParts.filter((el) => el.includes(this.name));
for (let prefix of this.possible()) { prefixeds[prefix] = toProcess .map((el) => this.replace(el, prefix)) .join(", "); } } else { for (let prefix of this.possible()) { prefixeds[prefix] = this.replace(rule.selector, prefix); } }
rule._autoprefixerPrefixeds[this.name] = prefixeds; return rule._autoprefixerPrefixeds; }
/** * Is rule already prefixed before */ already(rule, prefixeds, prefix) { let index = rule.parent.index(rule) - 1;
while (index >= 0) { let before = rule.parent.nodes[index];
if (before.type !== "rule") { return false; }
let some = false; for (let key in prefixeds[this.name]) { let prefixed = prefixeds[this.name][key]; if (before.selector === prefixed) { if (prefix === key) { return true; } else { some = true; break; } } } if (!some) { return false; }
index -= 1; }
return false; }
/** * Replace selectors by prefixed one */ replace(selector, prefix) { return selector.replace(this.regexp(), `$1${this.prefixed(prefix)}`); }
/** * Clone and add prefixes for at-rule */ add(rule, prefix) { let prefixeds = this.prefixeds(rule);
if (this.already(rule, prefixeds, prefix)) { return; }
let cloned = this.clone(rule, { selector: prefixeds[this.name][prefix] }); rule.parent.insertBefore(rule, cloned); }
/** * Return function to fast find prefixed selector */ old(prefix) { return new OldSelector(this, prefix); }}
export default Selector;