browserslist
Advanced tools
+16
-7
@@ -402,5 +402,14 @@ var bbm = require('baseline-browser-mapping') | ||
| var cache = {} | ||
| var parseCache = {} | ||
| var CACHE_MAX_ENTRIES = 500 | ||
| function boundedCacheSet(map, key, value) { | ||
| if (map.size >= CACHE_MAX_ENTRIES) { | ||
| map.delete(map.keys().next().value) | ||
| } | ||
| map.set(key, value) | ||
| } | ||
| var cache = new Map() | ||
| var parseCache = new Map() | ||
| function browserslist(queries, opts) { | ||
@@ -436,3 +445,3 @@ opts = prepareOpts(opts) | ||
| var cacheKey = JSON.stringify([queries, context]) | ||
| if (cache[cacheKey]) return cache[cacheKey] | ||
| if (cache.has(cacheKey)) return cache.get(cacheKey) | ||
@@ -454,3 +463,3 @@ var result = uniq(resolve(queries, context)).sort(function (name1, name2) { | ||
| if (!env.env.BROWSERSLIST_DISABLE_CACHE) { | ||
| cache[cacheKey] = result | ||
| boundedCacheSet(cache, cacheKey, result) | ||
| } | ||
@@ -462,6 +471,6 @@ return result | ||
| var cacheKey = JSON.stringify(queries) | ||
| if (cacheKey in parseCache) return parseCache[cacheKey] | ||
| if (parseCache.has(cacheKey)) return parseCache.get(cacheKey) | ||
| var result = parseWithoutCache(QUERIES, queries) | ||
| if (!env.env.BROWSERSLIST_DISABLE_CACHE) { | ||
| parseCache[cacheKey] = result | ||
| boundedCacheSet(parseCache, cacheKey, result) | ||
| } | ||
@@ -830,3 +839,3 @@ return result | ||
| regexp: | ||
| /^baseline\s+(?:(\d+)|(newly|widely)\s+available(?:\s+on\s+(\d{4}-\d{2}-\d{2}))?)?(\s+with\s+downstream)?(\s+including\s+kaios)?$/i, | ||
| /^baseline\s+(?!\s)(?:(\d+)|(newly|widely)\s+(?!\s)available(?:\s+(?!\s)on\s+(?!\s)(\d{4}-\d{2}-\d{2}))?)?(\s+(?!\s)with\s+(?!\s)downstream)?(\s+(?!\s)including\s+(?!\s)kaios)?$/i, | ||
| select: function (context, node) { | ||
@@ -833,0 +842,0 @@ var baselineVersions |
+7
-5
@@ -10,3 +10,4 @@ var feature = require('caniuse-lite/dist/unpacker/feature').default | ||
| var CONFIG_PATTERN = /^browserslist-config-/ | ||
| var SCOPED_CONFIG__PATTERN = /@[^/]+(?:\/[^/]+)?\/browserslist-config(?:-|$|\/)/ | ||
| var SCOPED_CONFIG__PATTERN = | ||
| /^@[^/]+(?:\/[^/]+)?\/browserslist-config(?:-|$|\/)/ | ||
| var FORMAT = | ||
@@ -225,8 +226,9 @@ 'Browserslist config should be a string or an array ' + | ||
| var normalized = {} | ||
| var normalized = Object.create(null) | ||
| for (var i in stats) { | ||
| var versions = Object.keys(stats[i]) | ||
| if (versions.length === 1 && data[i] && data[i].versions.length === 1) { | ||
| var normal = data[i].versions[0] | ||
| normalized[i] = {} | ||
| var known = Object.prototype.hasOwnProperty.call(data, i) && data[i] | ||
| if (versions.length === 1 && known && known.versions.length === 1) { | ||
| var normal = known.versions[0] | ||
| normalized[i] = Object.create(null) | ||
| normalized[i][normal] = stats[i][versions[0]] | ||
@@ -233,0 +235,0 @@ } else { |
+4
-4
| { | ||
| "name": "browserslist", | ||
| "version": "4.28.6", | ||
| "version": "4.28.7", | ||
| "description": "Share target browsers between different front-end tools, like Autoprefixer, Stylelint and babel-env-preset", | ||
@@ -36,5 +36,5 @@ "keywords": [ | ||
| "dependencies": { | ||
| "baseline-browser-mapping": "^2.10.42", | ||
| "caniuse-lite": "^1.0.30001803", | ||
| "electron-to-chromium": "^1.5.389", | ||
| "baseline-browser-mapping": "^2.10.44", | ||
| "caniuse-lite": "^1.0.30001806", | ||
| "electron-to-chromium": "^1.5.393", | ||
| "node-releases": "^2.0.51", | ||
@@ -41,0 +41,0 @@ "update-browserslist-db": "^1.2.3" |
+94
-36
@@ -1,19 +0,20 @@ | ||
| var AND_REGEXP = /^\s+and\s+(.*)/i | ||
| var OR_REGEXP = /^(?:,\s*|\s+or\s+)(.*)/i | ||
| var SPACE = /\s/ | ||
| function flatten(array) { | ||
| if (!Array.isArray(array)) return [array] | ||
| return array.reduce(function (a, b) { | ||
| return a.concat(flatten(b)) | ||
| }, []) | ||
| } | ||
| function find(string, predicate) { | ||
| for (var max = string.length, n = 1; n <= max; n++) { | ||
| var parsed = string.substr(-n, n) | ||
| if (predicate(parsed, n, max)) { | ||
| return string.slice(0, -n) | ||
| // Iterative flatten: `reduce`+`concat` copies the accumulator on every step, | ||
| // which is O(n²) once a query resolves to many nodes. | ||
| var result = [] | ||
| var stack = [array] | ||
| while (stack.length) { | ||
| var item = stack.pop() | ||
| if (Array.isArray(item)) { | ||
| for (var i = item.length - 1; i >= 0; i--) { | ||
| stack.push(item[i]) | ||
| } | ||
| } else { | ||
| result.push(item) | ||
| } | ||
| } | ||
| return '' | ||
| return result | ||
| } | ||
@@ -44,23 +45,82 @@ | ||
| function matchBlock(all, string, qs) { | ||
| var node | ||
| return find(string, function (parsed, n, max) { | ||
| if (AND_REGEXP.test(parsed)) { | ||
| node = matchQuery(all, parsed.match(AND_REGEXP)[1]) | ||
| node.compose = 'and' | ||
| qs.unshift(node) | ||
| return true | ||
| } else if (OR_REGEXP.test(parsed)) { | ||
| node = matchQuery(all, parsed.match(OR_REGEXP)[1]) | ||
| node.compose = 'or' | ||
| qs.unshift(node) | ||
| return true | ||
| } else if (n === max) { | ||
| node = matchQuery(all, parsed.trim()) | ||
| node.compose = 'or' | ||
| qs.unshift(node) | ||
| return true | ||
| function pushClause(all, qs, text, compose) { | ||
| var node = matchQuery(all, text.trim()) | ||
| node.compose = compose | ||
| qs.push(node) | ||
| } | ||
| // Splits a query block into clauses on the `\s+and\s+`, `\s+or\s+` and `,\s*` | ||
| // delimiters in a single left-to-right pass. The previous implementation grew | ||
| // a suffix one character at a time and re-tested anchored `\s+…` regexps at | ||
| // every length, which backtracks across whitespace runs and is O(n²) — a | ||
| // small padded query could freeze the event loop for tens of seconds. | ||
| function parseBlock(all, block, qs) { | ||
| if (block.length === 0) return | ||
| var len = block.length | ||
| var clauseStart = 0 | ||
| // Compose for the clause currently being read; the leftmost clause is `or`. | ||
| var compose = 'or' | ||
| var i = 0 | ||
| while (i < len) { | ||
| var ch = block[i] | ||
| if (ch === ',') { | ||
| // `,\s*` delimiter. A delimiter at the very start (i === 0) has no left | ||
| // clause — the original never emits one there. | ||
| if (i !== 0) pushClause(all, qs, block.slice(clauseStart, i), compose) | ||
| i++ | ||
| while (i < len && SPACE.test(block[i])) i++ | ||
| compose = 'or' | ||
| clauseStart = i | ||
| continue | ||
| } | ||
| return false | ||
| }) | ||
| if (SPACE.test(ch)) { | ||
| // Possible `\s+and\s+` or `\s+or\s+`. Scan the whitespace run once | ||
| // (linear, no backtracking), then check the following keyword. | ||
| var q = i | ||
| while (q < len && SPACE.test(block[q])) q++ | ||
| if ( | ||
| q + 3 < len && | ||
| (block[q] === 'a' || block[q] === 'A') && | ||
| (block[q + 1] === 'n' || block[q + 1] === 'N') && | ||
| (block[q + 2] === 'd' || block[q + 2] === 'D') && | ||
| SPACE.test(block[q + 3]) | ||
| ) { | ||
| // The leading `\s+` of `\s+and\s+` absorbs whitespace at the block | ||
| // start, so a delimiter at i === 0 has no left clause. | ||
| if (i !== 0) pushClause(all, qs, block.slice(clauseStart, i), compose) | ||
| var afterAnd = q + 3 | ||
| while (afterAnd < len && SPACE.test(block[afterAnd])) afterAnd++ | ||
| compose = 'and' | ||
| i = afterAnd | ||
| clauseStart = afterAnd | ||
| continue | ||
| } else if ( | ||
| q + 2 < len && | ||
| (block[q] === 'o' || block[q] === 'O') && | ||
| (block[q + 1] === 'r' || block[q + 1] === 'R') && | ||
| SPACE.test(block[q + 2]) | ||
| ) { | ||
| if (i !== 0) pushClause(all, qs, block.slice(clauseStart, i), compose) | ||
| var afterOr = q + 2 | ||
| while (afterOr < len && SPACE.test(block[afterOr])) afterOr++ | ||
| compose = 'or' | ||
| i = afterOr | ||
| clauseStart = afterOr | ||
| continue | ||
| } else { | ||
| // Whitespace inside a clause; skip the run and keep reading. | ||
| i = q | ||
| continue | ||
| } | ||
| } | ||
| i++ | ||
| } | ||
| pushClause(all, qs, block.slice(clauseStart), compose) | ||
| } | ||
@@ -73,5 +133,3 @@ | ||
| var qs = [] | ||
| do { | ||
| block = matchBlock(all, block, qs) | ||
| } while (block) | ||
| parseBlock(all, block, qs) | ||
| return qs | ||
@@ -78,0 +136,0 @@ }) |
71482
3.64%2230
2.76%