'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'; /* * str: string to search in. * searchfor: string or pattern to search for. */ function isFoundIn(str) { str = stripUrls(str); return function find(searchfor) { if (searchfor instanceof RegExp) return searchfor.test(str);else if (_.isFunction(searchfor)) return searchfor(str);else return str && str.indexOf(searchfor) >= 0; }; } /* * Strip the contents of url literals so they aren't matched * by our naive substring matching. */ function stripUrls(str) { return str.replace(/url\([^\)]*\)/g, 'url()'); } /** * Detect the use of any of a given list of CSS features. * ``` * var detector = new Detector(featureList) * detector.process(css, cb) * ``` * * `featureList`: an array of feature slugs (see caniuse-db) * `cb`: a callback that gets called for each usage of one of the given features, * called with an argument like: * ``` * { * usage: {} // postcss node where usage was found * feature: {} // caniuse-db feature slug * ignore: {} // caniuse-db feature to ignore in current file * } * ``` */ module.exports = (function () { function Detector(featureList) { _classCallCheck(this, Detector); this.features = _.pick(features, featureList); 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 }); } } } } }, { 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 }); } } } 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(); 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; } } } }, { 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); break; default: throw new Error('Unkonwn node type ' + child.type); } }); } }, { key: 'process', value: function process(node, cb) { // Reset ignoring rules specified by inline comments per each file this.ignore = []; // Recursively walk nodes in file this.node(node, cb); } }]); return Detector; })();