Comparing version
10
cli.js
@@ -23,3 +23,3 @@ #!/usr/bin/env node | ||
description: 'Autoprefixer-like browser criteria.', | ||
default: browserslist.defaults.join(', ') | ||
default: null | ||
}) | ||
@@ -77,3 +77,3 @@ .string('b') | ||
argv.browsers = argv.browsers.split(',').map(function (s) { return s.trim() }) | ||
argv.browsers && (argv.browsers = argv.browsers.split(',').map(function (s) { return s.trim() })) | ||
argv.ignore = argv.ignore.split(',').map(function (s) { return s.trim() }) | ||
@@ -129,5 +129,5 @@ // Informational output | ||
fs.createReadStream(file) | ||
.pipe(doiuse({ browsers: argv.browsers, ignore: argv.ignore }, file)) | ||
.on('error', function (err) { console.error(err) }) | ||
.pipe(out) | ||
.pipe(doiuse({ browsers: argv.browsers, ignore: argv.ignore }, file)) | ||
.on('error', function (err) { console.error(err) }) | ||
.pipe(out) | ||
}) | ||
@@ -134,0 +134,0 @@ } else { |
@@ -380,3 +380,2 @@ var list = require('postcss/lib/list') | ||
'font-unicode-range': { | ||
atrules: ['font-face'], | ||
properties: ['unicode-range'] | ||
@@ -383,0 +382,0 @@ }, |
// Generated by CoffeeScript 2.0.0-beta8 | ||
'use strict'; | ||
var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })(); | ||
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
var browserslist = require('browserslist'); | ||
var _ = require('lodash'); | ||
module.exports = (function () { | ||
function BrowserSelection(query, from) { | ||
_classCallCheck(this, BrowserSelection); | ||
module.exports = class BrowserSelection { | ||
constructor(query, from) { | ||
this.browsersRequest = query; | ||
this._list = browserslist(this.browsersRequest, from ? { path: from } : {}).map(s => s.split(' ')); | ||
} | ||
this.browsersRequest = query; | ||
this._list = browserslist(this.browsersRequest, { from: from }).map(function (s) { | ||
return s.split(' '); | ||
test(browser, version) { | ||
version = version.split('-'); | ||
if (version.length === 1) version.push(version[0]); | ||
return _.find(this._list, ([b, v]) => { | ||
return b === browser && v >= version[0] && v <= version[1]; | ||
}); | ||
} | ||
_createClass(BrowserSelection, [{ | ||
key: 'test', | ||
value: function test(browser, version) { | ||
version = version.split('-'); | ||
if (version.length === 1) version.push(version[0]); | ||
return _.find(this._list, function (_ref) { | ||
var _ref2 = _slicedToArray(_ref, 2); | ||
var b = _ref2[0]; | ||
var v = _ref2[1]; | ||
return b === browser && v >= version[0] && v <= version[1]; | ||
}); | ||
} | ||
}, { | ||
key: 'list', | ||
value: function list() { | ||
return this._list.slice(); | ||
} | ||
}]); | ||
return BrowserSelection; | ||
})(); | ||
list() { | ||
return this._list.slice(); | ||
} | ||
}; |
@@ -1,15 +0,7 @@ | ||
'use strict'; | ||
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); | ||
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } } | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
var _ = require('lodash'); | ||
var features = require('../data/features'); | ||
var PLUGIN_OPTION_COMMENT = 'doiuse-'; | ||
var DISABLE_FEATURE_COMMENT = PLUGIN_OPTION_COMMENT + 'disable'; | ||
var ENABLE_FEATURE_COMMENT = PLUGIN_OPTION_COMMENT + 'enable'; | ||
const PLUGIN_OPTION_COMMENT = 'doiuse-'; | ||
const DISABLE_FEATURE_COMMENT = PLUGIN_OPTION_COMMENT + 'disable'; | ||
const ENABLE_FEATURE_COMMENT = PLUGIN_OPTION_COMMENT + 'enable'; | ||
@@ -53,6 +45,4 @@ /* | ||
*/ | ||
module.exports = (function () { | ||
function Detector(featureList) { | ||
_classCallCheck(this, Detector); | ||
module.exports = class Detector { | ||
constructor(featureList) { | ||
this.features = _.pick(features, featureList); | ||
@@ -62,106 +52,93 @@ this.ignore = []; | ||
_createClass(Detector, [{ | ||
key: 'decl', | ||
value: function decl(_decl, cb) { | ||
for (var feat in this.features) { | ||
var properties = this.features[feat].properties || []; | ||
var values = this.features[feat].values; | ||
if (properties.filter(isFoundIn(_decl.prop)).length > 0) { | ||
if (!values || values.filter(isFoundIn(_decl.value)).length > 0) { | ||
cb({ usage: _decl, feature: feat, ignore: this.ignore }); | ||
} | ||
decl(decl, cb) { | ||
for (let feat in this.features) { | ||
const properties = this.features[feat].properties || []; | ||
const values = this.features[feat].values; | ||
if (properties.filter(isFoundIn(decl.prop)).length > 0) { | ||
if (!values || values.filter(isFoundIn(decl.value)).length > 0) { | ||
const result = { usage: decl, feature: feat, ignore: this.ignore }; | ||
cb(result); | ||
} | ||
} | ||
} | ||
}, { | ||
key: 'rule', | ||
value: function rule(_rule, cb) { | ||
for (var feat in this.features) { | ||
var selectors = this.features[feat].selectors || []; | ||
if (selectors.filter(isFoundIn(_rule.selector)).length > 0) { | ||
cb({ usage: _rule, feature: feat, ignore: this.ignore }); | ||
} | ||
} | ||
} | ||
this.node(_rule, cb); | ||
} | ||
}, { | ||
key: 'atrule', | ||
value: function atrule(_atrule, cb) { | ||
for (var feat in this.features) { | ||
var atrules = this.features[feat].atrules || []; | ||
var params = this.features[feat].params; | ||
if (atrules.filter(isFoundIn(_atrule.name)).length > 0) { | ||
if (!params || params.filter(isFoundIn(_atrule.params)).length > 0) { | ||
cb({ usage: _atrule, feature: feat, ignore: this.ignore }); | ||
} | ||
} | ||
rule(rule, cb) { | ||
for (let feat in this.features) { | ||
const selectors = this.features[feat].selectors || []; | ||
if (selectors.filter(isFoundIn(rule.selector)).length > 0) { | ||
const result = { usage: rule, feature: feat, ignore: this.ignore }; | ||
cb(result); | ||
} | ||
this.node(_atrule, cb); | ||
} | ||
}, { | ||
key: 'comment', | ||
value: function comment(_comment, cb) { | ||
var text = _comment.text.toLowerCase(); | ||
if (_.startsWith(text, PLUGIN_OPTION_COMMENT)) { | ||
var option = text.split(' ', 1)[0]; | ||
var value = text.replace(option, '').trim(); | ||
this.node(rule, cb); | ||
} | ||
switch (option) { | ||
case DISABLE_FEATURE_COMMENT: | ||
if (value === '') { | ||
this.ignore = _.keysIn(this.features); | ||
} else { | ||
this.ignore = _.uniq([].concat(_toConsumableArray(this.ignore), _toConsumableArray(value.split(',').map(function (feat) { | ||
return feat.trim(); | ||
})))); | ||
} | ||
break; | ||
case ENABLE_FEATURE_COMMENT: | ||
if (value === '') { | ||
this.ignore = []; | ||
} else { | ||
this.ignore = _.without.apply(_, [this.ignore].concat(_toConsumableArray(value.split(',').map(function (feat) { | ||
return feat.trim(); | ||
})))); | ||
} | ||
break; | ||
atrule(atrule, cb) { | ||
for (let feat in this.features) { | ||
const atrules = this.features[feat].atrules || []; | ||
const params = this.features[feat].params; | ||
if (atrules.filter(isFoundIn(atrule.name)).length > 0) { | ||
if (!params || params.filter(isFoundIn(atrule.params)).length > 0) { | ||
const result = { usage: atrule, feature: feat, ignore: this.ignore }; | ||
cb(result); | ||
} | ||
} | ||
} | ||
}, { | ||
key: 'node', | ||
value: function node(_node, cb) { | ||
var _this = this; | ||
_node.each(function (child) { | ||
switch (child.type) { | ||
case 'rule': | ||
_this.rule(child, cb); | ||
break; | ||
case 'decl': | ||
_this.decl(child, cb); | ||
break; | ||
case 'atrule': | ||
_this.atrule(child, cb); | ||
break; | ||
case 'comment': | ||
_this.comment(child, cb); | ||
} | ||
}); | ||
} | ||
}, { | ||
key: 'process', | ||
value: function process(node, cb) { | ||
// Reset ignoring rules specified by inline comments per each file | ||
this.ignore = []; | ||
this.node(atrule, cb); | ||
} | ||
// Recursively walk nodes in file | ||
this.node(node, cb); | ||
comment(comment, cb) { | ||
const text = comment.text.toLowerCase(); | ||
if (_.startsWith(text, PLUGIN_OPTION_COMMENT)) { | ||
const option = text.split(' ', 1)[0]; | ||
const value = text.replace(option, '').trim(); | ||
switch (option) { | ||
case DISABLE_FEATURE_COMMENT: | ||
if (value === '') { | ||
this.ignore = _.keysIn(this.features); | ||
} else { | ||
this.ignore = _.uniq([...this.ignore, ...value.split(',').map(feat => feat.trim())]); | ||
} | ||
break; | ||
case ENABLE_FEATURE_COMMENT: | ||
if (value === '') { | ||
this.ignore = []; | ||
} else { | ||
this.ignore = _.without(this.ignore, ...value.split(',').map(feat => feat.trim())); | ||
} | ||
break; | ||
} | ||
} | ||
}]); | ||
} | ||
return Detector; | ||
})(); | ||
node(node, cb) { | ||
node.each(child => { | ||
switch (child.type) { | ||
case 'rule': | ||
this.rule(child, cb); | ||
break; | ||
case 'decl': | ||
this.decl(child, cb); | ||
break; | ||
case 'atrule': | ||
this.atrule(child, cb); | ||
break; | ||
case 'comment': | ||
this.comment(child, cb); | ||
} | ||
}); | ||
} | ||
process(node, cb) { | ||
// Reset ignoring rules specified by inline comments per each file | ||
this.ignore = []; | ||
// Recursively walk nodes in file | ||
this.node(node, cb); | ||
} | ||
}; |
@@ -1,23 +0,12 @@ | ||
'use strict'; | ||
let _ = require('lodash'); | ||
let missingSupport = require('./missing-support'); | ||
let Detector = require('./detect-feature-use'); | ||
let Multimatch = require('multimatch'); | ||
var _ = require('lodash'); | ||
var missingSupport = require('./missing-support'); | ||
var Detector = require('./detect-feature-use'); | ||
var Multimatch = require('multimatch'); | ||
function doiuse(options) { | ||
var browserQuery = options.browsers; | ||
var onFeatureUsage = options.onFeatureUsage; | ||
var ignoreOptions = options.ignore; | ||
var ignoreFiles = options.ignoreFiles; | ||
let { browsers: browserQuery, onFeatureUsage, ignore: ignoreOptions, ignoreFiles } = options; | ||
return { | ||
info: function info() { | ||
var opts = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; | ||
var _missingSupport = missingSupport(browserQuery, opts.from); | ||
var browsers = _missingSupport.browsers; | ||
var features = _missingSupport.features; | ||
info(opts = {}) { | ||
let { browsers, features } = missingSupport(browserQuery, opts.from); | ||
return { | ||
@@ -29,18 +18,10 @@ browsers: browsers, | ||
postcss: function postcss(css, result) { | ||
var from = undefined; | ||
postcss(css, result) { | ||
let from; | ||
if (css.source && css.source.input) { | ||
from = css.source.input.file; | ||
} | ||
var _missingSupport2 = missingSupport(browserQuery, from); | ||
var features = _missingSupport2.features; | ||
var detector = new Detector(_.keys(features)); | ||
return detector.process(css, function (_ref) { | ||
var feature = _ref.feature; | ||
var usage = _ref.usage; | ||
var ignore = _ref.ignore; | ||
let { features } = missingSupport(browserQuery, from); | ||
let detector = new Detector(_.keys(features)); | ||
return detector.process(css, function ({ feature, usage, ignore }) { | ||
if (ignore && ignore.indexOf(feature) !== -1) { | ||
@@ -57,3 +38,3 @@ return; | ||
var messages = []; | ||
let messages = []; | ||
if (features[feature].missing) { | ||
@@ -66,3 +47,3 @@ messages.push('not supported by: ' + features[feature].missing); | ||
var message = features[feature].title + ' ' + messages.join(' and ') + ' (' + feature + ')'; | ||
let message = features[feature].title + ' ' + messages.join(' and ') + ' (' + feature + ')'; | ||
@@ -72,3 +53,3 @@ result.warn(message, { node: usage, plugin: 'doiuse' }); | ||
if (onFeatureUsage) { | ||
var loc = usage.source; | ||
let loc = usage.source; | ||
loc.original = css.source.input.map ? { | ||
@@ -75,0 +56,0 @@ start: css.source.input.map.consumer().originalPositionFor(loc.start), |
@@ -1,15 +0,13 @@ | ||
'use strict'; | ||
let features = require('../data/features'); | ||
let BrowserSelection = require('./browsers'); | ||
let _ = require('lodash'); | ||
let formatBrowserName = require('./util').formatBrowserName; | ||
var features = require('../data/features'); | ||
var BrowserSelection = require('./browsers'); | ||
var _ = require('lodash'); | ||
var formatBrowserName = require('./util').formatBrowserName; | ||
let caniuse = require('caniuse-lite'); | ||
var caniuse = require('caniuse-lite'); | ||
function filterStats(browsers, stats) { | ||
return _.reduce(stats, function (resultStats, versionData, browser) { | ||
// filter only versions of selected browsers that don't fully support this feature | ||
var feature = _.reduce(versionData, function (result, support, ver) { | ||
var selected = browsers.test(browser, ver); | ||
const feature = _.reduce(versionData, function (result, support, ver) { | ||
const selected = browsers.test(browser, ver); | ||
if (selected) { | ||
@@ -19,3 +17,3 @@ // check if browser is NOT fully (i.e., don't have 'y' in their stats) supported | ||
// when it's not partially supported ('a'), it's missing | ||
var testprop = /(^|\s)a($|\s)/.test(support) ? 'partial' : 'missing'; | ||
const testprop = /(^|\s)a($|\s)/.test(support) ? 'partial' : 'missing'; | ||
if (!result[testprop]) { | ||
@@ -77,13 +75,13 @@ result[testprop] = {}; | ||
function missing(browserRequest, from) { | ||
var browsers = new BrowserSelection(browserRequest, from); | ||
var result = {}; | ||
const browsers = new BrowserSelection(browserRequest, from); | ||
let result = {}; | ||
Object.keys(features).forEach(function (feature) { | ||
var featureData = caniuse.feature(caniuse.features[feature]); | ||
var lackData = filterStats(browsers, featureData.stats); | ||
var missingData = lackData.missing; | ||
var partialData = lackData.partial; | ||
const featureData = caniuse.feature(caniuse.features[feature]); | ||
const lackData = filterStats(browsers, featureData.stats); | ||
const missingData = lackData.missing; | ||
const partialData = lackData.partial; | ||
// browsers with missing or partial support for this feature | ||
var missing = lackingBrowsers(missingData); | ||
var partial = lackingBrowsers(partialData); | ||
const missing = lackingBrowsers(missingData); | ||
const partial = lackingBrowsers(partialData); | ||
@@ -90,0 +88,0 @@ if (missing.length > 0 || partial.length > 0) { |
@@ -1,8 +0,6 @@ | ||
'use strict'; | ||
let agents = require('caniuse-lite').agents; | ||
var agents = require('caniuse-lite').agents; | ||
module.exports = { | ||
formatBrowserName: function formatBrowserName(browserKey, versions) { | ||
var browserName = (agents[browserKey] || {}).browser; | ||
formatBrowserName: function (browserKey, versions) { | ||
let browserName = (agents[browserKey] || {}).browser; | ||
if (!versions) { | ||
@@ -9,0 +7,0 @@ return browserName; |
{ | ||
"name": "doiuse", | ||
"version": "4.0.0", | ||
"description": "Lint CSS for browser support against caniuse database.", | ||
"version": "4.1.0", | ||
"description": "Lint CSS for browser support against caniuse database", | ||
"main": "lib/doiuse.js", | ||
"scripts": { | ||
"test": "standard && tape test/*.js", | ||
"babel": "babel -d lib/ src/", | ||
"pretest": "npm run babel", | ||
"prepublish": "npm run babel" | ||
}, | ||
"bin": "./cli.js", | ||
@@ -24,2 +18,5 @@ "repository": { | ||
"author": "Anand Thakker", | ||
"contributors": [ | ||
"Piotr Kuczynski <piotr.kuczynski@gmail.com> (https://github.com/pkuczynski)" | ||
], | ||
"license": "MIT", | ||
@@ -31,4 +28,4 @@ "bugs": { | ||
"dependencies": { | ||
"browserslist": "^2.1.2", | ||
"caniuse-lite": "^1.0.30000669", | ||
"browserslist": "^3.2.1", | ||
"caniuse-lite": "^1.0.30000819", | ||
"css-rule-stream": "^1.1.0", | ||
@@ -46,6 +43,7 @@ "duplexer2": "0.0.2", | ||
"devDependencies": { | ||
"babel": "^5.2.13", | ||
"babel-cli": "^6.26.0", | ||
"eslint": "^4.19.1", | ||
"mock-fs": "^4.3.0", | ||
"postcss-import": "^10.0.0", | ||
"standard": "^8.1.0", | ||
"standard": "^11.0.1", | ||
"tape": "^4.0.0" | ||
@@ -57,3 +55,9 @@ }, | ||
] | ||
}, | ||
"scripts": { | ||
"test": "standard && tape test/*.js", | ||
"build": "babel -d lib/ src/", | ||
"pretest": "npm run build", | ||
"prepare": "npm run build" | ||
} | ||
} |
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
68040
58.03%19
58.33%6
20%898
-5.77%1
Infinity%+ Added
- Removed
Updated
Updated