UNPKG

4.02 kBJavaScriptView Raw
1let browserslist = require('browserslist')
2let { agents } = require('caniuse-lite')
3let colorette = require('colorette')
4
5let Browsers = require('./browsers')
6let Prefixes = require('./prefixes')
7let data = require('../data/prefixes')
8let info = require('./info')
9
10const WARNING =
11 '\n' +
12 ' Replace Autoprefixer `browsers` option to Browserslist config.\n' +
13 ' Use `browserslist` key in `package.json` or `.browserslistrc` file.\n' +
14 '\n' +
15 ' Using `browsers` option can cause errors. Browserslist config can\n' +
16 ' be used for Babel, Autoprefixer, postcss-normalize and other tools.\n' +
17 '\n' +
18 ' If you really need to use option, rename it to `overrideBrowserslist`.\n' +
19 '\n' +
20 ' Learn more at:\n' +
21 ' https://github.com/browserslist/browserslist#readme\n' +
22 ' https://twitter.com/browserslist\n' +
23 '\n'
24
25function isPlainObject (obj) {
26 return Object.prototype.toString.apply(obj) === '[object Object]'
27}
28
29let cache = new Map()
30
31function timeCapsule (result, prefixes) {
32 if (prefixes.browsers.selected.length === 0) {
33 return
34 }
35 if (prefixes.add.selectors.length > 0) {
36 return
37 }
38 if (Object.keys(prefixes.add).length > 2) {
39 return
40 }
41
42 /* istanbul ignore next */
43 result.warn(
44 'Greetings, time traveller. ' +
45 'We are in the golden age of prefix-less CSS, ' +
46 'where Autoprefixer is no longer needed for your stylesheet.'
47 )
48}
49
50module.exports = (...reqs) => {
51 let options
52 if (reqs.length === 1 && isPlainObject(reqs[0])) {
53 options = reqs[0]
54 reqs = undefined
55 } else if (reqs.length === 0 || (reqs.length === 1 && !reqs[0])) {
56 reqs = undefined
57 } else if (reqs.length <= 2 && (Array.isArray(reqs[0]) || !reqs[0])) {
58 options = reqs[1]
59 reqs = reqs[0]
60 } else if (typeof reqs[reqs.length - 1] === 'object') {
61 options = reqs.pop()
62 }
63
64 if (!options) {
65 options = {}
66 }
67
68 if (options.browser) {
69 throw new Error(
70 'Change `browser` option to `overrideBrowserslist` in Autoprefixer'
71 )
72 } else if (options.browserslist) {
73 throw new Error(
74 'Change `browserslist` option to `overrideBrowserslist` in Autoprefixer'
75 )
76 }
77
78 if (options.overrideBrowserslist) {
79 reqs = options.overrideBrowserslist
80 } else if (options.browsers) {
81 if (typeof console !== 'undefined' && console.warn) {
82 if (colorette.red) {
83 console.warn(
84 colorette.red(
85 WARNING.replace(/`[^`]+`/g, i => colorette.yellow(i.slice(1, -1)))
86 )
87 )
88 } else {
89 console.warn(WARNING)
90 }
91 }
92 reqs = options.browsers
93 }
94
95 let brwlstOpts = {
96 ignoreUnknownVersions: options.ignoreUnknownVersions,
97 stats: options.stats,
98 env: options.env
99 }
100
101 function loadPrefixes (opts) {
102 let d = module.exports.data
103 let browsers = new Browsers(d.browsers, reqs, opts, brwlstOpts)
104 let key = browsers.selected.join(', ') + JSON.stringify(options)
105
106 if (!cache.has(key)) {
107 cache.set(key, new Prefixes(d.prefixes, browsers, options))
108 }
109
110 return cache.get(key)
111 }
112
113 return {
114 postcssPlugin: 'autoprefixer',
115
116 prepare (result) {
117 let prefixes = loadPrefixes({
118 from: result.opts.from,
119 env: options.env
120 })
121
122 return {
123 OnceExit (root) {
124 timeCapsule(result, prefixes)
125 if (options.remove !== false) {
126 prefixes.processor.remove(root, result)
127 }
128 if (options.add !== false) {
129 prefixes.processor.add(root, result)
130 }
131 }
132 }
133 },
134
135 info (opts) {
136 opts = opts || {}
137 opts.from = opts.from || process.cwd()
138 return info(loadPrefixes(opts))
139 },
140
141 options,
142 browsers: reqs
143 }
144}
145
146module.exports.postcss = true
147
148/**
149 * Autoprefixer data
150 */
151module.exports.data = { browsers: agents, prefixes: data }
152
153/**
154 * Autoprefixer default browsers
155 */
156module.exports.defaults = browserslist.defaults
157
158/**
159 * Inspect with default Autoprefixer
160 */
161module.exports.info = () => module.exports().info()