175 lines
21 KiB
JavaScript
175 lines
21 KiB
JavaScript
|
'use strict';
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
var _minimatch = require('minimatch');var _minimatch2 = _interopRequireDefault(_minimatch);
|
||
|
var _docsUrl = require('../docsUrl');var _docsUrl2 = _interopRequireDefault(_docsUrl);function _interopRequireDefault(obj) {return obj && obj.__esModule ? obj : { 'default': obj };}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
// Rule Definition
|
||
|
//------------------------------------------------------------------------------
|
||
|
/**
|
||
|
* @fileoverview Rule to disallow namespace import
|
||
|
* @author Radek Benkel
|
||
|
*/module.exports = { meta: { type: 'suggestion',
|
||
|
docs: {
|
||
|
category: 'Style guide',
|
||
|
description: 'Forbid namespace (a.k.a. "wildcard" `*`) imports.',
|
||
|
url: (0, _docsUrl2['default'])('no-namespace') },
|
||
|
|
||
|
fixable: 'code',
|
||
|
schema: [{
|
||
|
type: 'object',
|
||
|
properties: {
|
||
|
ignore: {
|
||
|
type: 'array',
|
||
|
items: {
|
||
|
type: 'string' },
|
||
|
|
||
|
uniqueItems: true } } }] },
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
create: function () {function create(context) {
|
||
|
var firstOption = context.options[0] || {};
|
||
|
var ignoreGlobs = firstOption.ignore;
|
||
|
|
||
|
return {
|
||
|
ImportNamespaceSpecifier: function () {function ImportNamespaceSpecifier(node) {
|
||
|
if (ignoreGlobs && ignoreGlobs.find(function (glob) {return (0, _minimatch2['default'])(node.parent.source.value, glob, { matchBase: true });})) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
var scopeVariables = context.getScope().variables;
|
||
|
var namespaceVariable = scopeVariables.find(function (variable) {return variable.defs[0].node === node;});
|
||
|
var namespaceReferences = namespaceVariable.references;
|
||
|
var namespaceIdentifiers = namespaceReferences.map(function (reference) {return reference.identifier;});
|
||
|
var canFix = namespaceIdentifiers.length > 0 && !usesNamespaceAsObject(namespaceIdentifiers);
|
||
|
|
||
|
context.report({
|
||
|
node: node,
|
||
|
message: 'Unexpected namespace import.',
|
||
|
fix: canFix && function (fixer) {
|
||
|
var scopeManager = context.getSourceCode().scopeManager;
|
||
|
var fixes = [];
|
||
|
|
||
|
// Pass 1: Collect variable names that are already in scope for each reference we want
|
||
|
// to transform, so that we can be sure that we choose non-conflicting import names
|
||
|
var importNameConflicts = {};
|
||
|
namespaceIdentifiers.forEach(function (identifier) {
|
||
|
var parent = identifier.parent;
|
||
|
if (parent && parent.type === 'MemberExpression') {
|
||
|
var importName = getMemberPropertyName(parent);
|
||
|
var localConflicts = getVariableNamesInScope(scopeManager, parent);
|
||
|
if (!importNameConflicts[importName]) {
|
||
|
importNameConflicts[importName] = localConflicts;
|
||
|
} else {
|
||
|
localConflicts.forEach(function (c) {return importNameConflicts[importName].add(c);});
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
// Choose new names for each import
|
||
|
var importNames = Object.keys(importNameConflicts);
|
||
|
var importLocalNames = generateLocalNames(
|
||
|
importNames,
|
||
|
importNameConflicts,
|
||
|
namespaceVariable.name);
|
||
|
|
||
|
|
||
|
// Replace the ImportNamespaceSpecifier with a list of ImportSpecifiers
|
||
|
var namedImportSpecifiers = importNames.map(function (importName) {return importName === importLocalNames[importName] ?
|
||
|
importName : String(
|
||
|
importName) + ' as ' + String(importLocalNames[importName]);});
|
||
|
|
||
|
fixes.push(fixer.replaceText(node, '{ ' + String(namedImportSpecifiers.join(', ')) + ' }'));
|
||
|
|
||
|
// Pass 2: Replace references to the namespace with references to the named imports
|
||
|
namespaceIdentifiers.forEach(function (identifier) {
|
||
|
var parent = identifier.parent;
|
||
|
if (parent && parent.type === 'MemberExpression') {
|
||
|
var importName = getMemberPropertyName(parent);
|
||
|
fixes.push(fixer.replaceText(parent, importLocalNames[importName]));
|
||
|
}
|
||
|
});
|
||
|
|
||
|
return fixes;
|
||
|
} });
|
||
|
|
||
|
}return ImportNamespaceSpecifier;}() };
|
||
|
|
||
|
}return create;}() };
|
||
|
|
||
|
|
||
|
/**
|
||
|
* @param {Identifier[]} namespaceIdentifiers
|
||
|
* @returns {boolean} `true` if the namespace variable is more than just a glorified constant
|
||
|
*/
|
||
|
function usesNamespaceAsObject(namespaceIdentifiers) {
|
||
|
return !namespaceIdentifiers.every(function (identifier) {
|
||
|
var parent = identifier.parent;
|
||
|
|
||
|
// `namespace.x` or `namespace['x']`
|
||
|
return (
|
||
|
parent &&
|
||
|
parent.type === 'MemberExpression' && (
|
||
|
parent.property.type === 'Identifier' || parent.property.type === 'Literal'));
|
||
|
|
||
|
});
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param {MemberExpression} memberExpression
|
||
|
* @returns {string} the name of the member in the object expression, e.g. the `x` in `namespace.x`
|
||
|
*/
|
||
|
function getMemberPropertyName(memberExpression) {
|
||
|
return memberExpression.property.type === 'Identifier' ?
|
||
|
memberExpression.property.name :
|
||
|
memberExpression.property.value;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param {ScopeManager} scopeManager
|
||
|
* @param {ASTNode} node
|
||
|
* @return {Set<string>}
|
||
|
*/
|
||
|
function getVariableNamesInScope(scopeManager, node) {
|
||
|
var currentNode = node;
|
||
|
var scope = scopeManager.acquire(currentNode);
|
||
|
while (scope == null) {
|
||
|
currentNode = currentNode.parent;
|
||
|
scope = scopeManager.acquire(currentNode, true);
|
||
|
}
|
||
|
return new Set(scope.variables.concat(scope.upper.variables).map(function (variable) {return variable.name;}));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
* @param {*} names
|
||
|
* @param {*} nameConflicts
|
||
|
* @param {*} namespaceName
|
||
|
*/
|
||
|
function generateLocalNames(names, nameConflicts, namespaceName) {
|
||
|
var localNames = {};
|
||
|
names.forEach(function (name) {
|
||
|
var localName = void 0;
|
||
|
if (!nameConflicts[name].has(name)) {
|
||
|
localName = name;
|
||
|
} else if (!nameConflicts[name].has(String(namespaceName) + '_' + String(name))) {
|
||
|
localName = String(namespaceName) + '_' + String(name);
|
||
|
} else {
|
||
|
for (var i = 1; i < Infinity; i++) {
|
||
|
if (!nameConflicts[name].has(String(namespaceName) + '_' + String(name) + '_' + String(i))) {
|
||
|
localName = String(namespaceName) + '_' + String(name) + '_' + String(i);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
localNames[name] = localName;
|
||
|
});
|
||
|
return localNames;
|
||
|
}
|
||
|
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9ydWxlcy9uby1uYW1lc3BhY2UuanMiXSwibmFtZXMiOlsibW9kdWxlIiwiZXhwb3J0cyIsIm1ldGEiLCJ0eXBlIiwiZG9jcyIsImNhdGVnb3J5IiwiZGVzY3JpcHRpb24iLCJ1cmwiLCJmaXhhYmxlIiwic2NoZW1hIiwicHJvcGVydGllcyIsImlnbm9yZSIsIml0ZW1zIiwidW5pcXVlSXRlbXMiLCJjcmVhdGUiLCJjb250ZXh0IiwiZmlyc3RPcHRpb24iLCJvcHRpb25zIiwiaWdub3JlR2xvYnMiLCJJbXBvcnROYW1lc3BhY2VTcGVjaWZpZXIiLCJub2RlIiwiZmluZCIsImdsb2IiLCJwYXJlbnQiLCJzb3VyY2UiLCJ2YWx1ZSIsIm1hdGNoQmFzZSIsInNjb3BlVmFyaWFibGVzIiwiZ2V0U2NvcGUiLCJ2YXJpYWJsZXMiLCJuYW1lc3BhY2VWYXJpYWJsZSIsInZhcmlhYmxlIiwiZGVmcyIsIm5hbWVzcGFjZVJlZmVyZW5jZXMiLCJyZWZlcmVuY2VzIiwibmFtZXNwYWNlSWRlbnRpZmllcnMiLCJtYXAiLCJyZWZlcmVuY2UiLCJpZGVudGlmaWVyIiwiY2FuRml4IiwibGVuZ3RoIiwidXNlc05hbWVzcGFjZUFzT2JqZWN0IiwicmVwb3J0IiwibWVzc2FnZSIsImZpeCIsImZpeGVyIiwic2NvcGVNYW5hZ2VyIiwiZ2V0U291cmNlQ29kZSIsImZpeGVzIiwiaW1wb3J0TmFtZUNvbmZsaWN0cyIsImZvckVhY2giLCJpbXBvcnROYW1lIiwiZ2V0TWVtYmVyUHJvcGVydHlOYW1lIiwibG9jYWxDb25mbGljdHMiLCJnZXRWYXJpYWJsZU5hbWVzSW5TY29wZSIsImMiLCJhZGQiLCJpbXBvcnROYW1lcyIsIk9iamVjdCIsImtleXMiLCJpbXBvcnRMb2NhbE5hbWVzIiwiZ2VuZXJhdGVMb2NhbE5hbWVzIiwibmFtZSIsIm5hbWVkSW1wb3J0U3BlY2lmaWVycyIsInB1c2giLCJyZXBsYWNlVGV4dCIsImpvaW4iLCJldmVyeSIsInByb3BlcnR5IiwibWVtYmVyRXhwcmVzc2lvbiIsImN1cnJlbnROb2RlIiwic2NvcGUiLCJhY3F1aXJlIiwiU2V0IiwiY29uY2F0IiwidXBwZXIiLCJuYW1lcyIsIm5hbWVDb25mbGljdHMiLCJuYW1lc3BhY2VOYW1lIiwibG9jYWxOYW1lcyIsImxvY2FsTmFtZSIsImhhcyIsImkiLCJJbmZpbml0eSJdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFLQSxzQztBQUNBLHFDOztBQUVBO0FBQ0E7QUFDQTtBQVZBOzs7R0FZQUEsT0FBT0MsT0FBUCxHQUFpQixFQUNmQyxNQUFNLEVBQ0pDLE1BQU0sWUFERjtBQUVKQyxVQUFNO0FBQ0pDLGdCQUFVLGFBRE47QUFFSkMsbUJBQWEsbURBRlQ7QUFHSkMsV0FBSywwQkFBUSxjQUFSLENBSEQsRUFGRjs7QUFPSkMsYUFBUyxNQVBMO0FBUUpDLFlBQVEsQ0FBQztBQUNQTixZQUFNLFFBREM7QUFFUE8sa0JBQVk7QUFDVkMsZ0JBQVE7QUFDTlIsZ0JBQU0sT0FEQTtBQUVOUyxpQkFBTztBQUNMVCxrQkFBTSxRQURELEVBRkQ7O0FBS05VLHVCQUFhLElBTFAsRUFERSxFQUZMLEVBQUQsQ0FSSixFQURTOzs7Ozs7QUF1QmZDLFFBdkJlLCtCQXVCUkMsT0F2QlEsRUF1QkM7QUFDZCxVQUFNQyxjQUFjRCxRQUFRRSxPQUFSLENBQWdCLENBQWhCLEtBQXNCLEVBQTFDO0FBQ0EsVUFBTUMsY0FBY0YsWUFBWUwsTUFBaEM7O0FBRUEsYUFBTztBQUNMUSxnQ0FESyxpREFDb0JDLElBRHBCLEVBQzBCO0FBQzdCLGdCQUFJRixlQUFlQSxZQUFZRyxJQUFaLENBQWlCLFVBQUNDLElBQUQsVUFBVSw0QkFBVUYsS0FBS0csTUFBTCxDQUFZQyxNQUFaLENBQW1CQyxLQUE3QixFQUFvQ0gsSUFBcEMsRUFBMEMsRUFBRUksV0FBVyxJQUFiLEVBQTFDLENBQVYsRUFBakIsQ0FBbkIsRUFBK0c7QUFDN0c7QUFDRDs7QUFFRCxnQkFBTUMsaUJBQWlCWixRQUFRYSxRQUFSLEdBQW1CQyxTQUExQztBQUNBLGdCQUFNQyxvQkFBb0JILGVBQWVOLElBQWYsQ0FBb0IsVUFBQ1UsUUFBRCxVQUFjQSxTQUFTQyxJQUFULENBQWMsQ0FBZCxFQUFpQlosSUFBakIsS0FBMEJBLElBQXhDLEVBQXBCLENBQTFCO0FBQ0EsZ0JBQU1hLHNCQUFzQkgsa0JBQWtCSSxVQUE5QztBQUNBLGdCQUFNQyx1QkFBdUJGLG9CQUFvQkcsR0FBcEIsQ0FBd0IsVUFBQ0MsU0FBRCxVQUFlQSxVQUFVQyxVQUF6QixFQUF4QixDQUE3QjtBQUNBLGdCQUFNQyxTQUFTSixxQkFBcUJLLE1BQXJCLEdBQThCLENBQTlCLElBQW1DLENBQUNDLHNCQUFzQk4sb0JBQXRCLENBQW5EOztBQUVBcEIsb0JBQVEyQixNQUFSLENBQWU7QUFDYnRCLHdCQURhO0FBRWJ1QixxREFGYTtBQUdiQyxtQkFBS0wsVUFBVyxVQUFDTSxLQUFELEVBQVc7QUFDekIsb0JBQU1DLGVBQWUvQixRQUFRZ0MsYUFBUixHQUF3QkQsWUFBN0M7QUFDQSxvQkFBTUUsUUFBUSxFQUFkOztBQUVBO0FBQ0E7QUFDQSxvQkFBTUMsc0JBQXNCLEVBQTVCO0FBQ0FkLHFDQUFxQmUsT0FBckIsQ0FBNkIsVUFBQ1osVUFBRCxFQUFnQjtBQUMzQyxzQkFBTWYsU0FBU2UsV0FBV2YsTUFBMUI7QUFDQSxzQkFBSUEsVUFBVUEsT0FBT3BCLElBQVAsS0FBZ0Isa0JBQTlCLEVBQWtEO0FBQ2hELHdCQUFNZ0QsYUFBYUMsc0JBQXNCN0IsTUFBdEIsQ0FBbkI7QUFDQSx3QkFBTThCLGlCQUFpQkMsd0JBQXdCUixZQUF4QixFQUFzQ3ZCLE1BQXRDLENBQXZCO0FBQ0Esd0JBQUksQ0FBQzBCLG9CQUFvQkUsVUFBcEIsQ0FBTCxFQUFzQztBQUNwQ0YsMENBQW9CRSxVQUFwQixJQUFrQ0UsY0FBbEM7QUFDRCxxQkFGRCxNQUVPO0FBQ0xBLHFDQUFlSCxPQUFmLENBQXVCLFVBQUNLLENBQUQsVUFBT04sb0JBQW9CRSxVQUFwQixFQUFnQ0ssR0FBaEMsQ0FBb0NELENBQXBDLENBQVAsRUFBdkI7QUFDRDtBQUNGO0FBQ0YsaUJBWEQ7O0FBYUE7QUFDQSxvQkFBTUUsY0FBY0MsT0FBT0MsSUFBUCxDQUFZVixtQkFBWixDQUFwQjtBQUNBLG9CQUFNVyxtQkFBbUJDO0FBQ3ZCSiwyQkFEdUI7QUFFdkJSLG1DQUZ1QjtBQUd2Qm5CLGtDQUFrQmdDLElBSEssQ0FBekI7OztBQU1BO0FBQ0Esb0JBQU1DLHdCQUF3Qk4sWUFBWXJCLEdBQVosQ0FBZ0IsVUFBQ2UsVUFBRCxVQUFnQkEsZUFBZVMsaUJBQWlCVCxVQUFqQixDQUFmO0FBQzFEQSw0QkFEMEQ7QUFFdkRBLDRCQUZ1RCxvQkFFdENTLGlCQUFpQlQsVUFBakIsQ0FGc0MsQ0FBaEIsRUFBaEIsQ0FBOUI7O0FBSUFILHNCQUFNZ0IsSUFBTixDQUFXbkIsTUF
|