UNPKG

3.13 kBJavaScriptView Raw
1let Browsers = require('./browsers')
2let vendor = require('./vendor')
3let utils = require('./utils')
4
5/**
6 * Recursively clone objects
7 */
8function clone(obj, parent) {
9 let cloned = new obj.constructor()
10
11 for (let i of Object.keys(obj || {})) {
12 let value = obj[i]
13 if (i === 'parent' && typeof value === 'object') {
14 if (parent) {
15 cloned[i] = parent
16 }
17 } else if (i === 'source' || i === null) {
18 cloned[i] = value
19 } else if (Array.isArray(value)) {
20 cloned[i] = value.map(x => clone(x, cloned))
21 } else if (
22 i !== '_autoprefixerPrefix' &&
23 i !== '_autoprefixerValues' &&
24 i !== 'proxyCache'
25 ) {
26 if (typeof value === 'object' && value !== null) {
27 value = clone(value, cloned)
28 }
29 cloned[i] = value
30 }
31 }
32
33 return cloned
34}
35
36class Prefixer {
37 /**
38 * Add hack to selected names
39 */
40 static hack(klass) {
41 if (!this.hacks) {
42 this.hacks = {}
43 }
44 return klass.names.map(name => {
45 this.hacks[name] = klass
46 return this.hacks[name]
47 })
48 }
49
50 /**
51 * Load hacks for some names
52 */
53 static load(name, prefixes, all) {
54 let Klass = this.hacks && this.hacks[name]
55 if (Klass) {
56 return new Klass(name, prefixes, all)
57 } else {
58 return new this(name, prefixes, all)
59 }
60 }
61
62 /**
63 * Clone node and clean autprefixer custom caches
64 */
65 static clone(node, overrides) {
66 let cloned = clone(node)
67 for (let name in overrides) {
68 cloned[name] = overrides[name]
69 }
70 return cloned
71 }
72
73 constructor(name, prefixes, all) {
74 this.prefixes = prefixes
75 this.name = name
76 this.all = all
77 }
78
79 /**
80 * Find prefix in node parents
81 */
82 parentPrefix(node) {
83 let prefix
84
85 if (typeof node._autoprefixerPrefix !== 'undefined') {
86 prefix = node._autoprefixerPrefix
87 } else if (node.type === 'decl' && node.prop[0] === '-') {
88 prefix = vendor.prefix(node.prop)
89 } else if (node.type === 'root') {
90 prefix = false
91 } else if (
92 node.type === 'rule' &&
93 node.selector.includes(':-') &&
94 /:(-\w+-)/.test(node.selector)
95 ) {
96 prefix = node.selector.match(/:(-\w+-)/)[1]
97 } else if (node.type === 'atrule' && node.name[0] === '-') {
98 prefix = vendor.prefix(node.name)
99 } else {
100 prefix = this.parentPrefix(node.parent)
101 }
102
103 if (!Browsers.prefixes().includes(prefix)) {
104 prefix = false
105 }
106
107 node._autoprefixerPrefix = prefix
108
109 return node._autoprefixerPrefix
110 }
111
112 /**
113 * Clone node with prefixes
114 */
115 process(node, result) {
116 if (!this.check(node)) {
117 return undefined
118 }
119
120 let parent = this.parentPrefix(node)
121
122 let prefixes = this.prefixes.filter(
123 prefix => !parent || parent === utils.removeNote(prefix)
124 )
125
126 let added = []
127 for (let prefix of prefixes) {
128 if (this.add(node, prefix, added.concat([prefix]), result)) {
129 added.push(prefix)
130 }
131 }
132
133 return added
134 }
135
136 /**
137 * Shortcut for Prefixer.clone
138 */
139 clone(node, overrides) {
140 return Prefixer.clone(node, overrides)
141 }
142}
143
144module.exports = Prefixer