summaryrefslogtreecommitdiff
path: root/node_modules/autoprefixer/lib/selector.js
diff options
context:
space:
mode:
authorPhilipp Tanlak <philipp.tanlak@gmail.com>2025-11-24 20:54:57 +0100
committerPhilipp Tanlak <philipp.tanlak@gmail.com>2025-11-24 20:57:48 +0100
commitb1e2c8fd5cb5dfa46bc440a12eafaf56cd844b1c (patch)
tree49d360fd6cbc6a2754efe93524ac47ff0fbe0f7d /node_modules/autoprefixer/lib/selector.js
Docs
Diffstat (limited to 'node_modules/autoprefixer/lib/selector.js')
-rw-r--r--node_modules/autoprefixer/lib/selector.js150
1 files changed, 150 insertions, 0 deletions
diff --git a/node_modules/autoprefixer/lib/selector.js b/node_modules/autoprefixer/lib/selector.js
new file mode 100644
index 0000000..ff53449
--- /dev/null
+++ b/node_modules/autoprefixer/lib/selector.js
@@ -0,0 +1,150 @@
+let { list } = require('postcss')
+
+let OldSelector = require('./old-selector')
+let Prefixer = require('./prefixer')
+let Browsers = require('./browsers')
+let utils = require('./utils')
+
+class Selector extends Prefixer {
+ constructor(name, prefixes, all) {
+ super(name, prefixes, all)
+ this.regexpCache = new Map()
+ }
+
+ /**
+ * 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)
+ }
+
+ /**
+ * 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
+ }
+
+ /**
+ * Is rule selectors need to be prefixed
+ */
+ check(rule) {
+ if (rule.selector.includes(this.name)) {
+ return !!rule.selector.match(this.regexp())
+ }
+
+ return false
+ }
+
+ /**
+ * Return function to fast find prefixed selector
+ */
+ old(prefix) {
+ return new OldSelector(this, prefix)
+ }
+
+ /**
+ * All possible prefixes
+ */
+ possible() {
+ return Browsers.prefixes()
+ }
+
+ /**
+ * Return prefixed version of selector
+ */
+ prefixed(prefix) {
+ return this.name.replace(/^(\W*)/, `$1${prefix}`)
+ }
+
+ /**
+ * 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
+ }
+
+ /**
+ * 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)
+ }
+
+ /**
+ * Replace selectors by prefixed one
+ */
+ replace(selector, prefix) {
+ return selector.replace(this.regexp(), `$1${this.prefixed(prefix)}`)
+ }
+}
+
+module.exports = Selector