| | |
| | | var CONFIG_PATTERN = /^browserslist-config-/ |
| | | var SCOPED_CONFIG__PATTERN = /@[^/]+\/browserslist-config(-|$|\/)/ |
| | | var TIME_TO_UPDATE_CANIUSE = 6 * 30 * 24 * 60 * 60 * 1000 |
| | | var FORMAT = 'Browserslist config should be a string or an array ' + |
| | | 'of strings with browser queries' |
| | | var FORMAT = |
| | | 'Browserslist config should be a string or an array ' + |
| | | 'of strings with browser queries' |
| | | |
| | | var dataTimeChecked = false |
| | | var filenessCache = { } |
| | | var configCache = { } |
| | | function checkExtend (name) { |
| | | var filenessCache = {} |
| | | var configCache = {} |
| | | function checkExtend(name) { |
| | | var use = ' Use `dangerousExtend` option to disable.' |
| | | if (!CONFIG_PATTERN.test(name) && !SCOPED_CONFIG__PATTERN.test(name)) { |
| | | throw new BrowserslistError( |
| | | 'Browserslist config needs `browserslist-config-` prefix. ' + use) |
| | | 'Browserslist config needs `browserslist-config-` prefix. ' + use |
| | | ) |
| | | } |
| | | if (name.replace(/^@[^/]+\//, '').indexOf('.') !== -1) { |
| | | throw new BrowserslistError( |
| | | '`.` not allowed in Browserslist config name. ' + use) |
| | | '`.` not allowed in Browserslist config name. ' + use |
| | | ) |
| | | } |
| | | if (name.indexOf('node_modules') !== -1) { |
| | | throw new BrowserslistError( |
| | | '`node_modules` not allowed in Browserslist config.' + use) |
| | | '`node_modules` not allowed in Browserslist config.' + use |
| | | ) |
| | | } |
| | | } |
| | | |
| | | function isFile (file) { |
| | | function isFile(file) { |
| | | if (file in filenessCache) { |
| | | return filenessCache[file] |
| | | } |
| | |
| | | return result |
| | | } |
| | | |
| | | function eachParent (file, callback) { |
| | | function eachParent(file, callback) { |
| | | var dir = isFile(file) ? path.dirname(file) : file |
| | | var loc = path.resolve(dir) |
| | | do { |
| | |
| | | return undefined |
| | | } |
| | | |
| | | function check (section) { |
| | | function check(section) { |
| | | if (Array.isArray(section)) { |
| | | for (var i = 0; i < section.length; i++) { |
| | | if (typeof section[i] !== 'string') { |
| | |
| | | } |
| | | } |
| | | |
| | | function pickEnv (config, opts) { |
| | | function pickEnv(config, opts) { |
| | | if (typeof config !== 'object') return config |
| | | |
| | | var name |
| | |
| | | name = 'production' |
| | | } |
| | | |
| | | if (opts.throwOnMissing) { |
| | | if (name && name !== 'defaults' && !config[name]) { |
| | | throw new BrowserslistError( |
| | | 'Missing config for Browserslist environment `' + name + '`' |
| | | ) |
| | | } |
| | | } |
| | | |
| | | return config[name] || config.defaults |
| | | } |
| | | |
| | | function parsePackage (file) { |
| | | function parsePackage(file) { |
| | | var config = JSON.parse(fs.readFileSync(file)) |
| | | if (config.browserlist && !config.browserslist) { |
| | | throw new BrowserslistError( |
| | |
| | | return list |
| | | } |
| | | |
| | | function latestReleaseTime (agents) { |
| | | function latestReleaseTime(agents) { |
| | | var latest = 0 |
| | | for (var name in agents) { |
| | | var dates = agents[name].releaseDate || { } |
| | | var dates = agents[name].releaseDate || {} |
| | | for (var key in dates) { |
| | | if (latest < dates[key]) { |
| | | latest = dates[key] |
| | |
| | | return latest * 1000 |
| | | } |
| | | |
| | | function normalizeStats (data, stats) { |
| | | function normalizeStats(data, stats) { |
| | | if (!data) { |
| | | data = {} |
| | | } |
| | |
| | | |
| | | if (typeof stats !== 'object') return undefined |
| | | |
| | | var normalized = { } |
| | | var normalized = {} |
| | | for (var i in stats) { |
| | | var versions = Object.keys(stats[i]) |
| | | if ( |
| | | versions.length === 1 && |
| | | data[i] && |
| | | data[i].versions.length === 1 |
| | | ) { |
| | | if (versions.length === 1 && data[i] && data[i].versions.length === 1) { |
| | | var normal = data[i].versions[0] |
| | | normalized[i] = { } |
| | | normalized[i] = {} |
| | | normalized[i][normal] = stats[i][versions[0]] |
| | | } else { |
| | | normalized[i] = stats[i] |
| | |
| | | return normalized |
| | | } |
| | | |
| | | function normalizeUsageData (usageData, data) { |
| | | function normalizeUsageData(usageData, data) { |
| | | for (var browser in usageData) { |
| | | var browserUsage = usageData[browser] |
| | | // eslint-disable-next-line max-len |
| | |
| | | } |
| | | |
| | | module.exports = { |
| | | loadQueries: function loadQueries (ctx, name) { |
| | | loadQueries: function loadQueries(ctx, name) { |
| | | if (!ctx.dangerousExtend && !process.env.BROWSERSLIST_DANGEROUS_EXTEND) { |
| | | checkExtend(name) |
| | | } |
| | | // eslint-disable-next-line security/detect-non-literal-require |
| | | var queries = require(require.resolve(name, { paths: ['.'] })) |
| | | var queries = require(require.resolve(name, { paths: ['.', ctx.path] })) |
| | | if (queries) { |
| | | if (Array.isArray(queries)) { |
| | | return queries |
| | |
| | | } |
| | | } |
| | | throw new BrowserslistError( |
| | | '`' + name + '` config exports not an array of queries' + |
| | | ' or an object of envs' |
| | | '`' + |
| | | name + |
| | | '` config exports not an array of queries' + |
| | | ' or an object of envs' |
| | | ) |
| | | }, |
| | | |
| | | loadStat: function loadStat (ctx, name, data) { |
| | | loadStat: function loadStat(ctx, name, data) { |
| | | if (!ctx.dangerousExtend && !process.env.BROWSERSLIST_DANGEROUS_EXTEND) { |
| | | checkExtend(name) |
| | | } |
| | | // eslint-disable-next-line security/detect-non-literal-require |
| | | var stats = require( |
| | | require.resolve( |
| | | path.join(name, 'browserslist-stats.json'), |
| | | { paths: ['.'] } |
| | | ) |
| | | ) |
| | | var stats = require(require.resolve( |
| | | path.join(name, 'browserslist-stats.json'), |
| | | { paths: ['.'] } |
| | | )) |
| | | return normalizeStats(data, stats) |
| | | }, |
| | | |
| | | getStat: function getStat (opts, data) { |
| | | getStat: function getStat(opts, data) { |
| | | var stats |
| | | if (opts.stats) { |
| | | stats = opts.stats |
| | |
| | | try { |
| | | stats = JSON.parse(fs.readFileSync(stats)) |
| | | } catch (e) { |
| | | throw new BrowserslistError('Can\'t read ' + stats) |
| | | throw new BrowserslistError("Can't read " + stats) |
| | | } |
| | | } |
| | | return normalizeStats(data, stats) |
| | | }, |
| | | |
| | | loadConfig: function loadConfig (opts) { |
| | | loadConfig: function loadConfig(opts) { |
| | | if (process.env.BROWSERSLIST) { |
| | | return process.env.BROWSERSLIST |
| | | } else if (opts.config || process.env.BROWSERSLIST_CONFIG) { |
| | |
| | | } |
| | | }, |
| | | |
| | | loadCountry: function loadCountry (usage, country, data) { |
| | | loadCountry: function loadCountry(usage, country, data) { |
| | | var code = country.replace(/[^\w-]/g, '') |
| | | if (!usage[code]) { |
| | | // eslint-disable-next-line security/detect-non-literal-require |
| | | var compressed = require('caniuse-lite/data/regions/' + code + '.js') |
| | | var usageData = region(compressed) |
| | | normalizeUsageData(usageData, data) |
| | | usage[country] = { } |
| | | usage[country] = {} |
| | | for (var i in usageData) { |
| | | for (var j in usageData[i]) { |
| | | usage[country][i + ' ' + j] = usageData[i][j] |
| | |
| | | } |
| | | }, |
| | | |
| | | loadFeature: function loadFeature (features, name) { |
| | | loadFeature: function loadFeature(features, name) { |
| | | name = name.replace(/[^\w-]/g, '') |
| | | if (features[name]) return |
| | | |
| | | // eslint-disable-next-line security/detect-non-literal-require |
| | | var compressed = require('caniuse-lite/data/features/' + name + '.js') |
| | | var stats = feature(compressed).stats |
| | | features[name] = { } |
| | | features[name] = {} |
| | | for (var i in stats) { |
| | | for (var j in stats[i]) { |
| | | features[name][i + ' ' + j] = stats[i][j] |
| | |
| | | } |
| | | }, |
| | | |
| | | parseConfig: function parseConfig (string) { |
| | | parseConfig: function parseConfig(string) { |
| | | var result = { defaults: [] } |
| | | var sections = ['defaults'] |
| | | |
| | | string.toString() |
| | | string |
| | | .toString() |
| | | .replace(/#[^\n]*/g, '') |
| | | .split(/\n|,/) |
| | | .map(function (line) { |
| | |
| | | return result |
| | | }, |
| | | |
| | | readConfig: function readConfig (file) { |
| | | readConfig: function readConfig(file) { |
| | | if (!isFile(file)) { |
| | | throw new BrowserslistError('Can\'t read ' + file + ' config') |
| | | throw new BrowserslistError("Can't read " + file + ' config') |
| | | } |
| | | return module.exports.parseConfig(fs.readFileSync(file)) |
| | | }, |
| | | |
| | | findConfig: function findConfig (from) { |
| | | findConfig: function findConfig(from) { |
| | | from = path.resolve(from) |
| | | |
| | | var passed = [] |
| | |
| | | return resolved |
| | | }, |
| | | |
| | | clearCaches: function clearCaches () { |
| | | clearCaches: function clearCaches() { |
| | | dataTimeChecked = false |
| | | filenessCache = { } |
| | | configCache = { } |
| | | filenessCache = {} |
| | | configCache = {} |
| | | |
| | | this.cache = { } |
| | | this.cache = {} |
| | | }, |
| | | |
| | | oldDataWarning: function oldDataWarning (agentsObj) { |
| | | oldDataWarning: function oldDataWarning(agentsObj) { |
| | | if (dataTimeChecked) return |
| | | dataTimeChecked = true |
| | | if (process.env.BROWSERSLIST_IGNORE_OLD_DATA) return |
| | |
| | | if (latest !== 0 && latest < halfYearAgo) { |
| | | console.warn( |
| | | 'Browserslist: caniuse-lite is outdated. Please run:\n' + |
| | | ' npx browserslist@latest --update-db\n' + |
| | | ' Why you should do it regularly: ' + |
| | | 'https://github.com/browserslist/browserslist#browsers-data-updating' |
| | | ' npx browserslist@latest --update-db\n' + |
| | | ' Why you should do it regularly: ' + |
| | | 'https://github.com/browserslist/browserslist#browsers-data-updating' |
| | | ) |
| | | } |
| | | }, |
| | | |
| | | currentNode: function currentNode () { |
| | | currentNode: function currentNode() { |
| | | return 'node ' + process.versions.node |
| | | } |
| | | } |