eslint-plugin-compat
Version:
Lint browser compatibility of API used
178 lines (161 loc) • 5.02 kB
JavaScript
(function (global, factory) {
if (typeof define === "function" && define.amd) {
define(['exports', 'path', 'fs'], factory);
} else if (typeof exports !== "undefined") {
factory(exports, require('path'), require('fs'));
} else {
var mod = {
exports: {}
};
factory(mod.exports, global.path, global.fs);
global.CanIUseProvider = mod.exports;
}
})(this, function (exports, _path, _fs) {
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.targetMetadata = undefined;
exports.getUnsupportedTargets = getUnsupportedTargets;
var _path2 = _interopRequireDefault(_path);
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
var caniuseRecord = JSON.parse((0, _fs.readFileSync)(_path2.default.join(__dirname, './caniuse/fulldata-json/data-2.0.json')).toString());
// HACK: modern targets should be determined once at runtime
var targetMetadata = exports.targetMetadata = {
targets: ['chrome', 'firefox', 'opera', 'safari', 'android', 'ie', 'edge', 'ios_saf', 'op_mini', 'android', 'bb', 'op_mob', 'and_chr', 'and_ff', 'ie_mob', 'and_uc', 'samsung']
};
var targetNameMappings = {
chrome: 'Chrome',
firefox: 'Firefox',
opera: 'Opera',
safari: 'Safari',
android: 'Android Browser',
ie: 'IE',
edge: 'Edge',
ios_saf: 'iOS Safari',
op_mini: 'Opera Mini',
bb: 'Blackberry Browser',
op_mob: 'Opera Mobile',
and_chr: 'Android Chrome',
and_ff: 'Android Firefox',
ie_mob: 'IE Mobile',
and_uc: 'Android UC Browser',
samsung: 'Samsung Browser'
};
/**
* Take a target's id and return it's full name by using `targetNameMappings`
* ex. {target: and_ff, version: 40} => 'Android FireFox 40'
*/
function formatTargetNames(target) {
return targetNameMappings[target.target] + ' ' + target.version;
}
/**
* Return an array of all unsupported targets
*/
function getUnsupportedTargets(node, targets) {
var stats = caniuseRecord.data[node.id].stats;
return targets.filter(function (target) {
return stats[target.target][target.version].includes('n');
}).map(formatTargetNames);
}
function isValid(node, eslintNode, targets) {
// Filter non-matching objects and properties
switch (eslintNode.type) {
case 'CallExpression':
if (!eslintNode.callee) return true;
if (eslintNode.callee.name !== node.object) return true;
break;
case 'NewExpression':
if (!eslintNode.callee) return true;
if (eslintNode.callee.name !== node.object) return true;
break;
case 'MemberExpression':
// Pass tests if non-matching object or property
if (!eslintNode.object || !eslintNode.property) return true;
if (eslintNode.object.name !== node.object) return true;
// If the property is missing from the rule, it means that only the
// object is required to determine compatibility
if (!node.property) break;
if (eslintNode.property.name !== node.property) return true;
break;
default:
return true;
}
return getUnsupportedTargets(node, targets).length === 0;
}
//
// TODO: Refactor to separate module
// TODO: Refactor isValid(), remove from rules
//
var CanIUseProvider = [
// new ServiceWorker()
{
id: 'serviceworkers',
ASTNodeType: 'NewExpression',
object: 'ServiceWorker',
isValid: isValid,
getUnsupportedTargets: getUnsupportedTargets
}, {
id: 'serviceworkers',
ASTNodeType: 'MemberExpression',
object: 'navigator',
property: 'serviceWorker',
isValid: isValid,
getUnsupportedTargets: getUnsupportedTargets
},
// document.querySelector()
{
id: 'queryselector',
ASTNodeType: 'MemberExpression',
object: 'document',
property: 'querySelector',
isValid: isValid,
getUnsupportedTargets: getUnsupportedTargets
},
// WebAssembly
{
id: 'wasm',
ASTNodeType: 'MemberExpression',
object: 'WebAssembly',
isValid: isValid,
getUnsupportedTargets: getUnsupportedTargets
},
// IntersectionObserver
{
id: 'intersectionobserver',
ASTNodeType: 'NewExpression',
object: 'IntersectionObserver',
isValid: isValid,
getUnsupportedTargets: getUnsupportedTargets
},
// PaymentRequest
{
id: 'payment-request',
ASTNodeType: 'NewExpression',
object: 'PaymentRequest',
isValid: isValid,
getUnsupportedTargets: getUnsupportedTargets
},
// fetch
{
id: 'fetch',
ASTNodeType: 'CallExpression',
object: 'fetch',
isValid: isValid,
getUnsupportedTargets: getUnsupportedTargets
},
// document.currentScript()
{
id: 'document-currentscript',
ASTNodeType: 'MemberExpression',
object: 'document',
property: 'currentScript',
isValid: isValid,
getUnsupportedTargets: getUnsupportedTargets
}];
exports.default = CanIUseProvider;
});