UNPKG

eslint-plugin-import

Version:
1,349 lines (1,092 loc) 160 kB
'use strict';var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {return typeof obj;} : function (obj) {return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;};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 _minimatch = require('minimatch');var _minimatch2 = _interopRequireDefault(_minimatch); var _arrayIncludes = require('array-includes');var _arrayIncludes2 = _interopRequireDefault(_arrayIncludes); var _object = require('object.groupby');var _object2 = _interopRequireDefault(_object); var _contextCompat = require('eslint-module-utils/contextCompat'); var _stringPrototype = require('string.prototype.trimend');var _stringPrototype2 = _interopRequireDefault(_stringPrototype); var _importType = require('../core/importType');var _importType2 = _interopRequireDefault(_importType); var _staticRequire = require('../core/staticRequire');var _staticRequire2 = _interopRequireDefault(_staticRequire); var _docsUrl = require('../docsUrl');var _docsUrl2 = _interopRequireDefault(_docsUrl);function _interopRequireDefault(obj) {return obj && obj.__esModule ? obj : { 'default': obj };} var categories = { named: 'named', 'import': 'import', exports: 'exports' }; var defaultGroups = ['builtin', 'external', 'parent', 'sibling', 'index']; // REPORTING AND FIXING function reverse(array) { return array.map(function (v) {return Object.assign({}, v, { rank: -v.rank });}).reverse(); } function getTokensOrCommentsAfter(sourceCode, node, count) { var currentNodeOrToken = node; var result = []; for (var i = 0; i < count; i++) { currentNodeOrToken = sourceCode.getTokenOrCommentAfter(currentNodeOrToken); if (currentNodeOrToken == null) { break; } result.push(currentNodeOrToken); } return result; } function getTokensOrCommentsBefore(sourceCode, node, count) { var currentNodeOrToken = node; var result = []; for (var i = 0; i < count; i++) { currentNodeOrToken = sourceCode.getTokenOrCommentBefore(currentNodeOrToken); if (currentNodeOrToken == null) { break; } result.push(currentNodeOrToken); } return result.reverse(); } function takeTokensAfterWhile(sourceCode, node, condition) { var tokens = getTokensOrCommentsAfter(sourceCode, node, 100); var result = []; for (var i = 0; i < tokens.length; i++) { if (condition(tokens[i])) { result.push(tokens[i]); } else { break; } } return result; } function takeTokensBeforeWhile(sourceCode, node, condition) { var tokens = getTokensOrCommentsBefore(sourceCode, node, 100); var result = []; for (var i = tokens.length - 1; i >= 0; i--) { if (condition(tokens[i])) { result.push(tokens[i]); } else { break; } } return result.reverse(); } function findOutOfOrder(imported) { if (imported.length === 0) { return []; } var maxSeenRankNode = imported[0]; return imported.filter(function (importedModule) { var res = importedModule.rank < maxSeenRankNode.rank; if (maxSeenRankNode.rank < importedModule.rank) { maxSeenRankNode = importedModule; } return res; }); } function findRootNode(node) { var parent = node; while (parent.parent != null && parent.parent.body == null) { parent = parent.parent; } return parent; } function commentOnSameLineAs(node) { return function (token) {return (token.type === 'Block' || token.type === 'Line') && token.loc.start.line === token.loc.end.line && token.loc.end.line === node.loc.end.line;}; } function findEndOfLineWithComments(sourceCode, node) { var tokensToEndOfLine = takeTokensAfterWhile(sourceCode, node, commentOnSameLineAs(node)); var endOfTokens = tokensToEndOfLine.length > 0 ? tokensToEndOfLine[tokensToEndOfLine.length - 1].range[1] : node.range[1]; var result = endOfTokens; for (var i = endOfTokens; i < sourceCode.text.length; i++) { if (sourceCode.text[i] === '\n') { result = i + 1; break; } if (sourceCode.text[i] !== ' ' && sourceCode.text[i] !== '\t' && sourceCode.text[i] !== '\r') { break; } result = i + 1; } return result; } function findStartOfLineWithComments(sourceCode, node) { var tokensToEndOfLine = takeTokensBeforeWhile(sourceCode, node, commentOnSameLineAs(node)); var startOfTokens = tokensToEndOfLine.length > 0 ? tokensToEndOfLine[0].range[0] : node.range[0]; var result = startOfTokens; for (var i = startOfTokens - 1; i > 0; i--) { if (sourceCode.text[i] !== ' ' && sourceCode.text[i] !== '\t') { break; } result = i; } return result; } function findSpecifierStart(sourceCode, node) { var token = void 0; do { token = sourceCode.getTokenBefore(node); } while (token.value !== ',' && token.value !== '{'); return token.range[1]; } function findSpecifierEnd(sourceCode, node) { var token = void 0; do { token = sourceCode.getTokenAfter(node); } while (token.value !== ',' && token.value !== '}'); return token.range[0]; } function isRequireExpression(expr) { return expr != null && expr.type === 'CallExpression' && expr.callee != null && expr.callee.name === 'require' && expr.arguments != null && expr.arguments.length === 1 && expr.arguments[0].type === 'Literal'; } function isSupportedRequireModule(node) { if (node.type !== 'VariableDeclaration') { return false; } if (node.declarations.length !== 1) { return false; } var decl = node.declarations[0]; var isPlainRequire = decl.id && ( decl.id.type === 'Identifier' || decl.id.type === 'ObjectPattern') && isRequireExpression(decl.init); var isRequireWithMemberExpression = decl.id && ( decl.id.type === 'Identifier' || decl.id.type === 'ObjectPattern') && decl.init != null && decl.init.type === 'CallExpression' && decl.init.callee != null && decl.init.callee.type === 'MemberExpression' && isRequireExpression(decl.init.callee.object); return isPlainRequire || isRequireWithMemberExpression; } function isPlainImportModule(node) { return node.type === 'ImportDeclaration' && node.specifiers != null && node.specifiers.length > 0; } function isPlainImportEquals(node) { return node.type === 'TSImportEqualsDeclaration' && node.moduleReference.expression; } function isCJSExports(context, node) { if ( node.type === 'MemberExpression' && node.object.type === 'Identifier' && node.property.type === 'Identifier' && node.object.name === 'module' && node.property.name === 'exports') { return (0, _contextCompat.getScope)(context, node).variables.findIndex(function (variable) {return variable.name === 'module';}) === -1; } if ( node.type === 'Identifier' && node.name === 'exports') { return (0, _contextCompat.getScope)(context, node).variables.findIndex(function (variable) {return variable.name === 'exports';}) === -1; } } function getNamedCJSExports(context, node) { if (node.type !== 'MemberExpression') { return; } var result = []; var root = node; var parent = null; while (root.type === 'MemberExpression') { if (root.property.type !== 'Identifier') { return; } result.unshift(root.property.name); parent = root; root = root.object; } if (isCJSExports(context, root)) { return result; } if (isCJSExports(context, parent)) { return result.slice(1); } } function canCrossNodeWhileReorder(node) { return isSupportedRequireModule(node) || isPlainImportModule(node) || isPlainImportEquals(node); } function canReorderItems(firstNode, secondNode) { var parent = firstNode.parent;var _sort = [ parent.body.indexOf(firstNode), parent.body.indexOf(secondNode)]. sort(),_sort2 = _slicedToArray(_sort, 2),firstIndex = _sort2[0],secondIndex = _sort2[1]; var nodesBetween = parent.body.slice(firstIndex, secondIndex + 1);var _iteratorNormalCompletion = true;var _didIteratorError = false;var _iteratorError = undefined;try { for (var _iterator = nodesBetween[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {var nodeBetween = _step.value; if (!canCrossNodeWhileReorder(nodeBetween)) { return false; } }} catch (err) {_didIteratorError = true;_iteratorError = err;} finally {try {if (!_iteratorNormalCompletion && _iterator['return']) {_iterator['return']();}} finally {if (_didIteratorError) {throw _iteratorError;}}} return true; } function makeImportDescription(node) { if (node.type === 'export') { if (node.node.exportKind === 'type') { return 'type export'; } return 'export'; } if (node.node.importKind === 'type') { return 'type import'; } if (node.node.importKind === 'typeof') { return 'typeof import'; } return 'import'; } function fixOutOfOrder(context, firstNode, secondNode, order, category) { var isNamed = category === categories.named; var isExports = category === categories.exports; var sourceCode = (0, _contextCompat.getSourceCode)(context);var _ref = isNamed ? { firstRoot: firstNode.node, secondRoot: secondNode.node } : { firstRoot: findRootNode(firstNode.node), secondRoot: findRootNode(secondNode.node) },firstRoot = _ref.firstRoot,secondRoot = _ref.secondRoot;var _ref2 = isNamed ? { firstRootStart: findSpecifierStart(sourceCode, firstRoot), firstRootEnd: findSpecifierEnd(sourceCode, firstRoot), secondRootStart: findSpecifierStart(sourceCode, secondRoot), secondRootEnd: findSpecifierEnd(sourceCode, secondRoot) } : { firstRootStart: findStartOfLineWithComments(sourceCode, firstRoot), firstRootEnd: findEndOfLineWithComments(sourceCode, firstRoot), secondRootStart: findStartOfLineWithComments(sourceCode, secondRoot), secondRootEnd: findEndOfLineWithComments(sourceCode, secondRoot) },firstRootStart = _ref2.firstRootStart,firstRootEnd = _ref2.firstRootEnd,secondRootStart = _ref2.secondRootStart,secondRootEnd = _ref2.secondRootEnd; if (firstNode.displayName === secondNode.displayName) { if (firstNode.alias) { firstNode.displayName = String(firstNode.displayName) + ' as ' + String(firstNode.alias); } if (secondNode.alias) { secondNode.displayName = String(secondNode.displayName) + ' as ' + String(secondNode.alias); } } var firstImport = String(makeImportDescription(firstNode)) + ' of `' + String(firstNode.displayName) + '`'; var secondImport = '`' + String(secondNode.displayName) + '` ' + String(makeImportDescription(secondNode)); var message = secondImport + ' should occur ' + String(order) + ' ' + firstImport; if (isNamed) { var firstCode = sourceCode.text.slice(firstRootStart, firstRoot.range[1]); var firstTrivia = sourceCode.text.slice(firstRoot.range[1], firstRootEnd); var secondCode = sourceCode.text.slice(secondRootStart, secondRoot.range[1]); var secondTrivia = sourceCode.text.slice(secondRoot.range[1], secondRootEnd); if (order === 'before') { var trimmedTrivia = (0, _stringPrototype2['default'])(secondTrivia); var gapCode = sourceCode.text.slice(firstRootEnd, secondRootStart - 1); var whitespaces = secondTrivia.slice(trimmedTrivia.length); context.report({ node: secondNode.node, message: message, fix: function () {function fix(fixer) {return fixer.replaceTextRange( [firstRootStart, secondRootEnd], String( secondCode) + ',' + String(trimmedTrivia) + String(firstCode) + String(firstTrivia) + String(gapCode) + String(whitespaces));}return fix;}() }); } else if (order === 'after') { var _trimmedTrivia = (0, _stringPrototype2['default'])(firstTrivia); var _gapCode = sourceCode.text.slice(secondRootEnd + 1, firstRootStart); var _whitespaces = firstTrivia.slice(_trimmedTrivia.length); context.report({ node: secondNode.node, message: message, fix: function () {function fix(fixes) {return fixes.replaceTextRange( [secondRootStart, firstRootEnd], '' + String( _gapCode) + String(firstCode) + ',' + String(_trimmedTrivia) + String(secondCode) + String(_whitespaces));}return fix;}() }); } } else { var canFix = isExports || canReorderItems(firstRoot, secondRoot); var newCode = sourceCode.text.substring(secondRootStart, secondRootEnd); if (newCode[newCode.length - 1] !== '\n') { newCode = String(newCode) + '\n'; } if (order === 'before') { context.report({ node: secondNode.node, message: message, fix: canFix && function (fixer) {return fixer.replaceTextRange( [firstRootStart, secondRootEnd], newCode + sourceCode.text.substring(firstRootStart, secondRootStart));} }); } else if (order === 'after') { context.report({ node: secondNode.node, message: message, fix: canFix && function (fixer) {return fixer.replaceTextRange( [secondRootStart, firstRootEnd], sourceCode.text.substring(secondRootEnd, firstRootEnd) + newCode);} }); } } } function reportOutOfOrder(context, imported, outOfOrder, order, category) { outOfOrder.forEach(function (imp) { var found = imported.find(function () {function hasHigherRank(importedItem) { return importedItem.rank > imp.rank; }return hasHigherRank;}()); fixOutOfOrder(context, found, imp, order, category); }); } function makeOutOfOrderReport(context, imported, category) { var outOfOrder = findOutOfOrder(imported); if (!outOfOrder.length) { return; } // There are things to report. Try to minimize the number of reported errors. var reversedImported = reverse(imported); var reversedOrder = findOutOfOrder(reversedImported); if (reversedOrder.length < outOfOrder.length) { reportOutOfOrder(context, reversedImported, reversedOrder, 'after', category); return; } reportOutOfOrder(context, imported, outOfOrder, 'before', category); } var compareString = function compareString(a, b) { if (a < b) { return -1; } if (a > b) { return 1; } return 0; }; /** Some parsers (languages without types) don't provide ImportKind */ var DEFAULT_IMPORT_KIND = 'value'; var getNormalizedValue = function getNormalizedValue(node, toLowerCase) { var value = node.value; return toLowerCase ? String(value).toLowerCase() : value; }; function getSorter(alphabetizeOptions) { var multiplier = alphabetizeOptions.order === 'asc' ? 1 : -1; var orderImportKind = alphabetizeOptions.orderImportKind; var multiplierImportKind = orderImportKind !== 'ignore' && ( alphabetizeOptions.orderImportKind === 'asc' ? 1 : -1); return function () {function importsSorter(nodeA, nodeB) { var importA = getNormalizedValue(nodeA, alphabetizeOptions.caseInsensitive); var importB = getNormalizedValue(nodeB, alphabetizeOptions.caseInsensitive); var result = 0; if (!(0, _arrayIncludes2['default'])(importA, '/') && !(0, _arrayIncludes2['default'])(importB, '/')) { result = compareString(importA, importB); } else { var A = importA.split('/'); var B = importB.split('/'); var a = A.length; var b = B.length; for (var i = 0; i < Math.min(a, b); i++) { // Skip comparing the first path segment, if they are relative segments for both imports if (i === 0 && (A[i] === '.' || A[i] === '..') && (B[i] === '.' || B[i] === '..')) { // If one is sibling and the other parent import, no need to compare at all, since the paths belong in different groups if (A[i] !== B[i]) {break;} continue; } result = compareString(A[i], B[i]); if (result) {break;} } if (!result && a !== b) { result = a < b ? -1 : 1; } } result = result * multiplier; // In case the paths are equal (result === 0), sort them by importKind if (!result && multiplierImportKind) { result = multiplierImportKind * compareString( nodeA.node.importKind || DEFAULT_IMPORT_KIND, nodeB.node.importKind || DEFAULT_IMPORT_KIND); } return result; }return importsSorter;}(); } function mutateRanksToAlphabetize(imported, alphabetizeOptions) { var groupedByRanks = (0, _object2['default'])(imported, function (item) {return item.rank;}); var sorterFn = getSorter(alphabetizeOptions); // sort group keys so that they can be iterated on in order var groupRanks = Object.keys(groupedByRanks).sort(function (a, b) { return a - b; }); // sort imports locally within their group groupRanks.forEach(function (groupRank) { groupedByRanks[groupRank].sort(sorterFn); }); // assign globally unique rank to each import var newRank = 0; var alphabetizedRanks = groupRanks.reduce(function (acc, groupRank) { groupedByRanks[groupRank].forEach(function (importedItem) { acc[String(importedItem.value) + '|' + String(importedItem.node.importKind)] = parseInt(groupRank, 10) + newRank; newRank += 1; }); return acc; }, {}); // mutate the original group-rank with alphabetized-rank imported.forEach(function (importedItem) { importedItem.rank = alphabetizedRanks[String(importedItem.value) + '|' + String(importedItem.node.importKind)]; }); } // DETECTING function computePathRank(ranks, pathGroups, path, maxPosition) { for (var i = 0, l = pathGroups.length; i < l; i++) {var _pathGroups$i = pathGroups[i],pattern = _pathGroups$i.pattern,patternOptions = _pathGroups$i.patternOptions,group = _pathGroups$i.group,_pathGroups$i$positio = _pathGroups$i.position,position = _pathGroups$i$positio === undefined ? 1 : _pathGroups$i$positio; if ((0, _minimatch2['default'])(path, pattern, patternOptions || { nocomment: true })) { return ranks[group] + position / maxPosition; } } } function computeRank(context, ranks, importEntry, excludedImportTypes, isSortingTypesGroup) { var impType = void 0; var rank = void 0; var isTypeGroupInGroups = ranks.omittedTypes.indexOf('type') === -1; var isTypeOnlyImport = importEntry.node.importKind === 'type'; var isExcludedFromPathRank = isTypeOnlyImport && isTypeGroupInGroups && excludedImportTypes.has('type'); if (importEntry.type === 'import:object') { impType = 'object'; } else if (isTypeOnlyImport && isTypeGroupInGroups && !isSortingTypesGroup) { impType = 'type'; } else { impType = (0, _importType2['default'])(importEntry.value, context); } if (!excludedImportTypes.has(impType) && !isExcludedFromPathRank) { rank = computePathRank(ranks.groups, ranks.pathGroups, importEntry.value, ranks.maxPosition); } if (typeof rank === 'undefined') { rank = ranks.groups[impType]; if (typeof rank === 'undefined') { return -1; } } if (isTypeOnlyImport && isSortingTypesGroup) { rank = ranks.groups.type + rank / 10; } if (importEntry.type !== 'import' && !importEntry.type.startsWith('import:')) { rank += 100; } return rank; } function registerNode(context, importEntry, ranks, imported, excludedImportTypes, isSortingTypesGroup) { var rank = computeRank(context, ranks, importEntry, excludedImportTypes, isSortingTypesGroup); if (rank !== -1) { var importNode = importEntry.node; if (importEntry.type === 'require' && importNode.parent.parent.type === 'VariableDeclaration') { importNode = importNode.parent.parent; } imported.push(Object.assign({}, importEntry, { rank: rank, isMultiline: importNode.loc.end.line !== importNode.loc.start.line })); } } function getRequireBlock(node) { var n = node; // Handle cases like `const baz = require('foo').bar.baz` // and `const foo = require('foo')()` while ( n.parent.type === 'MemberExpression' && n.parent.object === n || n.parent.type === 'CallExpression' && n.parent.callee === n) { n = n.parent; } if ( n.parent.type === 'VariableDeclarator' && n.parent.parent.type === 'VariableDeclaration' && n.parent.parent.parent.type === 'Program') { return n.parent.parent.parent; } } var types = ['builtin', 'external', 'internal', 'unknown', 'parent', 'sibling', 'index', 'object', 'type']; /** * Creates an object with type-rank pairs. * * Example: { index: 0, sibling: 1, parent: 1, external: 1, builtin: 2, internal: 2 } */ function convertGroupsToRanks(groups) { var rankObject = groups.reduce(function (res, group, index) { [].concat(group).forEach(function (groupItem) { res[groupItem] = index * 2; }); return res; }, {}); var omittedTypes = types.filter(function (type) { return typeof rankObject[type] === 'undefined'; }); var ranks = omittedTypes.reduce(function (res, type) { res[type] = groups.length * 2; return res; }, rankObject); return { groups: ranks, omittedTypes: omittedTypes }; } function convertPathGroupsForRanks(pathGroups) { var after = {}; var before = {}; var transformed = pathGroups.map(function (pathGroup, index) {var group = pathGroup.group,positionString = pathGroup.position; var position = 0; if (positionString === 'after') { if (!after[group]) { after[group] = 1; } position = after[group]++; } else if (positionString === 'before') { if (!before[group]) { before[group] = []; } before[group].push(index); } return Object.assign({}, pathGroup, { position: position }); }); var maxPosition = 1; Object.keys(before).forEach(function (group) { var groupLength = before[group].length; before[group].forEach(function (groupIndex, index) { transformed[groupIndex].position = -1 * (groupLength - index); }); maxPosition = Math.max(maxPosition, groupLength); }); Object.keys(after).forEach(function (key) { var groupNextPosition = after[key]; maxPosition = Math.max(maxPosition, groupNextPosition - 1); }); return { pathGroups: transformed, maxPosition: maxPosition > 10 ? Math.pow(10, Math.ceil(Math.log10(maxPosition))) : 10 }; } function fixNewLineAfterImport(context, previousImport) { var prevRoot = findRootNode(previousImport.node); var tokensToEndOfLine = takeTokensAfterWhile( (0, _contextCompat.getSourceCode)(context), prevRoot, commentOnSameLineAs(prevRoot)); var endOfLine = prevRoot.range[1]; if (tokensToEndOfLine.length > 0) { endOfLine = tokensToEndOfLine[tokensToEndOfLine.length - 1].range[1]; } return function (fixer) {return fixer.insertTextAfterRange([prevRoot.range[0], endOfLine], '\n');}; } function removeNewLineAfterImport(context, currentImport, previousImport) { var sourceCode = (0, _contextCompat.getSourceCode)(context); var prevRoot = findRootNode(previousImport.node); var currRoot = findRootNode(currentImport.node); var rangeToRemove = [ findEndOfLineWithComments(sourceCode, prevRoot), findStartOfLineWithComments(sourceCode, currRoot)]; if (/^\s*$/.test(sourceCode.text.substring(rangeToRemove[0], rangeToRemove[1]))) { return function (fixer) {return fixer.removeRange(rangeToRemove);}; } return undefined; } function makeNewlinesBetweenReport(context, imported, newlinesBetweenImports_, newlinesBetweenTypeOnlyImports_, distinctGroup, isSortingTypesGroup, isConsolidatingSpaceBetweenImports) { var getNumberOfEmptyLinesBetween = function getNumberOfEmptyLinesBetween(currentImport, previousImport) { var linesBetweenImports = (0, _contextCompat.getSourceCode)(context).lines.slice( previousImport.node.loc.end.line, currentImport.node.loc.start.line - 1); return linesBetweenImports.filter(function (line) {return !line.trim().length;}).length; }; var getIsStartOfDistinctGroup = function getIsStartOfDistinctGroup(currentImport, previousImport) {return currentImport.rank - 1 >= previousImport.rank;}; var previousImport = imported[0]; imported.slice(1).forEach(function (currentImport) { var emptyLinesBetween = getNumberOfEmptyLinesBetween( currentImport, previousImport); var isStartOfDistinctGroup = getIsStartOfDistinctGroup( currentImport, previousImport); var isTypeOnlyImport = currentImport.node.importKind === 'type'; var isPreviousImportTypeOnlyImport = previousImport.node.importKind === 'type'; var isNormalImportNextToTypeOnlyImportAndRelevant = isTypeOnlyImport !== isPreviousImportTypeOnlyImport && isSortingTypesGroup; var isTypeOnlyImportAndRelevant = isTypeOnlyImport && isSortingTypesGroup; // In the special case where newlinesBetweenImports and consolidateIslands // want the opposite thing, consolidateIslands wins var newlinesBetweenImports = isSortingTypesGroup && isConsolidatingSpaceBetweenImports && ( previousImport.isMultiline || currentImport.isMultiline) && newlinesBetweenImports_ === 'never' ? 'always-and-inside-groups' : newlinesBetweenImports_; // In the special case where newlinesBetweenTypeOnlyImports and // consolidateIslands want the opposite thing, consolidateIslands wins var newlinesBetweenTypeOnlyImports = isSortingTypesGroup && isConsolidatingSpaceBetweenImports && ( isNormalImportNextToTypeOnlyImportAndRelevant || previousImport.isMultiline || currentImport.isMultiline) && newlinesBetweenTypeOnlyImports_ === 'never' ? 'always-and-inside-groups' : newlinesBetweenTypeOnlyImports_; var isNotIgnored = isTypeOnlyImportAndRelevant && newlinesBetweenTypeOnlyImports !== 'ignore' || !isTypeOnlyImportAndRelevant && newlinesBetweenImports !== 'ignore'; if (isNotIgnored) { var shouldAssertNewlineBetweenGroups = (isTypeOnlyImportAndRelevant || isNormalImportNextToTypeOnlyImportAndRelevant) && ( newlinesBetweenTypeOnlyImports === 'always' || newlinesBetweenTypeOnlyImports === 'always-and-inside-groups') || !isTypeOnlyImportAndRelevant && !isNormalImportNextToTypeOnlyImportAndRelevant && ( newlinesBetweenImports === 'always' || newlinesBetweenImports === 'always-and-inside-groups'); var shouldAssertNoNewlineWithinGroup = (isTypeOnlyImportAndRelevant || isNormalImportNextToTypeOnlyImportAndRelevant) && newlinesBetweenTypeOnlyImports !== 'always-and-inside-groups' || !isTypeOnlyImportAndRelevant && !isNormalImportNextToTypeOnlyImportAndRelevant && newlinesBetweenImports !== 'always-and-inside-groups'; var shouldAssertNoNewlineBetweenGroup = !isSortingTypesGroup || !isNormalImportNextToTypeOnlyImportAndRelevant || newlinesBetweenTypeOnlyImports === 'never'; var isTheNewlineBetweenImportsInTheSameGroup = distinctGroup && currentImport.rank === previousImport.rank || !distinctGroup && !isStartOfDistinctGroup; // Let's try to cut down on linting errors sent to the user var alreadyReported = false; if (shouldAssertNewlineBetweenGroups) { if (currentImport.rank !== previousImport.rank && emptyLinesBetween === 0) { if (distinctGroup || isStartOfDistinctGroup) { alreadyReported = true; context.report({ node: previousImport.node, message: 'There should be at least one empty line between import groups', fix: fixNewLineAfterImport(context, previousImport) }); } } else if (emptyLinesBetween > 0 && shouldAssertNoNewlineWithinGroup) { if (isTheNewlineBetweenImportsInTheSameGroup) { alreadyReported = true; context.report({ node: previousImport.node, message: 'There should be no empty line within import group', fix: removeNewLineAfterImport(context, currentImport, previousImport) }); } } } else if (emptyLinesBetween > 0 && shouldAssertNoNewlineBetweenGroup) { alreadyReported = true; context.report({ node: previousImport.node, message: 'There should be no empty line between import groups', fix: removeNewLineAfterImport(context, currentImport, previousImport) }); } if (!alreadyReported && isConsolidatingSpaceBetweenImports) { if (emptyLinesBetween === 0 && currentImport.isMultiline) { context.report({ node: previousImport.node, message: 'There should be at least one empty line between this import and the multi-line import that follows it', fix: fixNewLineAfterImport(context, previousImport) }); } else if (emptyLinesBetween === 0 && previousImport.isMultiline) { context.report({ node: previousImport.node, message: 'There should be at least one empty line between this multi-line import and the import that follows it', fix: fixNewLineAfterImport(context, previousImport) }); } else if ( emptyLinesBetween > 0 && !previousImport.isMultiline && !currentImport.isMultiline && isTheNewlineBetweenImportsInTheSameGroup) { context.report({ node: previousImport.node, message: 'There should be no empty lines between this single-line import and the single-line import that follows it', fix: removeNewLineAfterImport(context, currentImport, previousImport) }); } } } previousImport = currentImport; }); } function getAlphabetizeConfig(options) { var alphabetize = options.alphabetize || {}; var order = alphabetize.order || 'ignore'; var orderImportKind = alphabetize.orderImportKind || 'ignore'; var caseInsensitive = alphabetize.caseInsensitive || false; return { order: order, orderImportKind: orderImportKind, caseInsensitive: caseInsensitive }; } // TODO, semver-major: Change the default of "distinctGroup" from true to false var defaultDistinctGroup = true; module.exports = { meta: { type: 'suggestion', docs: { category: 'Style guide', description: 'Enforce a convention in module import order.', url: (0, _docsUrl2['default'])('order') }, fixable: 'code', schema: [ { type: 'object', properties: { groups: { type: 'array', uniqueItems: true, items: { oneOf: [ { 'enum': types }, { type: 'array', uniqueItems: true, items: { 'enum': types } }] } }, pathGroupsExcludedImportTypes: { type: 'array' }, distinctGroup: { type: 'boolean', 'default': defaultDistinctGroup }, pathGroups: { type: 'array', items: { type: 'object', properties: { pattern: { type: 'string' }, patternOptions: { type: 'object' }, group: { type: 'string', 'enum': types }, position: { type: 'string', 'enum': ['after', 'before'] } }, additionalProperties: false, required: ['pattern', 'group'] } }, 'newlines-between': { 'enum': [ 'ignore', 'always', 'always-and-inside-groups', 'never'] }, 'newlines-between-types': { 'enum': [ 'ignore', 'always', 'always-and-inside-groups', 'never'] }, consolidateIslands: { 'enum': [ 'inside-groups', 'never'] }, sortTypesGroup: { type: 'boolean', 'default': false }, named: { 'default': false, oneOf: [{ type: 'boolean' }, { type: 'object', properties: { enabled: { type: 'boolean' }, 'import': { type: 'boolean' }, 'export': { type: 'boolean' }, require: { type: 'boolean' }, cjsExports: { type: 'boolean' }, types: { type: 'string', 'enum': [ 'mixed', 'types-first', 'types-last'] } }, additionalProperties: false }] }, alphabetize: { type: 'object', properties: { caseInsensitive: { type: 'boolean', 'default': false }, order: { 'enum': ['ignore', 'asc', 'desc'], 'default': 'ignore' }, orderImportKind: { 'enum': ['ignore', 'asc', 'desc'], 'default': 'ignore' } }, additionalProperties: false }, warnOnUnassignedImports: { type: 'boolean', 'default': false } }, additionalProperties: false, dependencies: { sortTypesGroup: { oneOf: [ { // When sortTypesGroup is true, groups must NOT be an array that does not contain 'type' properties: { sortTypesGroup: { 'enum': [true] }, groups: { not: { type: 'array', uniqueItems: true, items: { oneOf: [ { 'enum': types.filter(function (t) {return t !== 'type';}) }, { type: 'array', uniqueItems: true, items: { 'enum': types.filter(function (t) {return t !== 'type';}) } }] } } } }, required: ['groups'] }, { properties: { sortTypesGroup: { 'enum': [false] } } }] }, 'newlines-between-types': { properties: { sortTypesGroup: { 'enum': [true] } }, required: ['sortTypesGroup'] }, consolidateIslands: { oneOf: [ { properties: { consolidateIslands: { 'enum': ['inside-groups'] } }, anyOf: [ { properties: { 'newlines-between': { 'enum': ['always-and-inside-groups'] } }, required: ['newlines-between'] }, { properties: { 'newlines-between-types': { 'enum': ['always-and-inside-groups'] } }, required: ['newlines-between-types'] }] }, { properties: { consolidateIslands: { 'enum': ['never'] } } }] } } }] }, create: function () {function create(context) { var options = context.options[0] || {}; var newlinesBetweenImports = options['newlines-between'] || 'ignore'; var newlinesBetweenTypeOnlyImports = options['newlines-between-types'] || newlinesBetweenImports; var pathGroupsExcludedImportTypes = new Set(options.pathGroupsExcludedImportTypes || ['builtin', 'external', 'object']); var sortTypesGroup = options.sortTypesGroup; var consolidateIslands = options.consolidateIslands || 'never'; var named = Object.assign({ types: 'mixed' }, _typeof(options.named) === 'object' ? Object.assign({}, options.named, { 'import': 'import' in options.named ? options.named['import'] : options.named.enabled, 'export': 'export' in options.named ? options.named['export'] : options.named.enabled, require: 'require' in options.named ? options.named.require : options.named.enabled, cjsExports: 'cjsExports' in options.named ? options.named.cjsExports : options.named.enabled }) : { 'import': options.named, 'export': options.named, require: options.named, cjsExports: options.named }); var namedGroups = named.types === 'mixed' ? [] : named.types === 'types-last' ? ['value'] : ['type']; var alphabetize = getAlphabetizeConfig(options); var distinctGroup = options.distinctGroup == null ? defaultDistinctGroup : !!options.distinctGroup; var ranks = void 0; try {var _convertPathGroupsFor = convertPathGroupsForRanks(options.pathGroups || []),pathGroups = _convertPathGroupsFor.pathGroups,maxPosition = _convertPathGroupsFor.maxPosition;var _convertGroupsToRanks = convertGroupsToRanks(options.groups || defaultGroups),groups = _convertGroupsToRanks.groups,omittedTypes = _convertGroupsToRanks.omittedTypes; ranks = { groups: groups, omittedTypes: omittedTypes, pathGroups: pathGroups, maxPosition: maxPosition }; } catch (error) { // Malformed configuration return { Program: function () {function Program(node) { context.report(node, error.message); }return Program;}() }; } var importMap = new Map(); var exportMap = new Map(); var isTypeGroupInGroups = ranks.omittedTypes.indexOf('type') === -1; var isSortingTypesGroup = isTypeGroupInGroups && sortTypesGroup; function getBlockImports(node) { if (!importMap.has(node)) { importMap.set(node, []); } return importMap.get(node); } function getBlockExports(node) { if (!exportMap.has(node)) { exportMap.set(node, []); } return exportMap.get(node); } function makeNamedOrderReport(context, namedImports) { if (namedImports.length > 1) { var imports = namedImports.map( function (namedImport) { var kind = namedImport.kind || 'value'; var rank = namedGroups.findIndex(function (entry) {return [].concat(entry).indexOf(kind) > -1;}); return Object.assign({ displayName: namedImport.value, rank: rank === -1 ? namedGroups.length : rank }, namedImport, { value: String(namedImport.value) + ':' + String(namedImport.alias || '') }); }); if (alphabetize.order !== 'ignore') { mutateRanksToAlphabetize(imports, alphabetize); } makeOutOfOrderReport(context, imports, categories.named); } } return Object.assign({ ImportDeclaration: function () {function ImportDeclaration(node) { // Ignoring unassigned imports unless warnOnUnassignedImports is set if (node.specifiers.length || options.warnOnUnassignedImports) { var name = node.source.value; registerNode( context, { node: node, value: name, displayName: name, type: 'import' }, ranks, getBlockImports(node.parent), pathGroupsExcludedImportTypes, isSortingTypesGroup); if (named['import']) { makeNamedOrderReport( context, node.specifiers.filter( function (specifier) {return specifier.type === 'ImportSpecifier';}).map( function (specifier) {return Object.assign({ node: specifier, value: specifier.imported.name, type: 'import', kind: specifier.importKind }, specifier.local.range[0] !== specifier.imported.range[0] && { alias: specifier.local.name });})); } } }return ImportDeclaration;}(), TSImportEqualsDeclaration: function () {function TSImportEqualsDeclaration(node) { // skip "export import"s if (node.isExport) { return; } var displayName = void 0; var value = void 0; var type = void 0; if (node.moduleReference.type === 'TSExternalModuleReference') { value = node.moduleReference.expression.value; displayName = value; type = 'import'; } else { value = ''; displayName = (0, _contextCompat.getSourceCode)(context).getText(node.moduleReference); type = 'import:object'; } registerNode( context, { node: node, value: value, displayName: displayName, type: type }, ranks, getBlockImports(node.parent), pathGroupsExcludedImportTypes, isSortingTypesGroup); }return TSImportEqualsDeclaration;}(), CallExpression: function () {function CallExpression(node) { if (!(0, _staticRequire2['default'])(node)) { return; } var block = getRequireBlock(node); if (!block) { return; } var name = node.arguments[0].value; registerNode( context, { node: node, value: name, displayName: name, type: 'require' }, ranks, getBlockImports(block), pathGroupsExcludedImportTypes, isSortingTypesGroup); }return CallExpression;}() }, named.require && { VariableDeclarator: function () {function VariableDeclarator(node) { if (node.id.type === 'ObjectPattern' && isRequireExpression(node.init)) { for (var i = 0; i < node.id.properties.length; i++) { if ( node.id.properties[i].key.type !== 'Identifier' || node.id.properties[i].value.type !== 'Identifier') { return; } } makeNamedOrderReport( context, node.id.properties.map(function (prop) {return Object.assign({ node: prop, value: prop.key.name, type: 'require' }, prop.key.range[0] !== prop.value.range[0] && { alias: prop.value.name });})); } }return VariableDeclarator;}() }, named['export'] && { ExportNamedDeclaration: function () {function ExportNamedDeclaration(node) { makeNamedOrderReport( context, node.specifiers.map(function (specifier) {return Object.assign({ node: specifier, value: specifier.local.name, type: 'export', kind: specifier.exportKind }, specifier.local.range[0] !== specifier.exported.range[0] && { alias: specifier.exported.name });})); }return ExportNamedDeclaration;}() }, named.cjsExports && { AssignmentExpression: function () {function AssignmentExpression(node) { if (node.parent.type === 'ExpressionStatement') { if (isCJSExports(context, node.left)) { if (node.right.type === 'ObjectExpression') { for (var i = 0; i < node.right.properties.length; i++) { if ( !node.right.properties[i].key || node.right.properties[i].key.type !== 'Identifier' || !node.right.properties[i].value || node.right.properties[i].value.type !== 'Identifier') { return; } } makeNamedOrderReport( context, node.right.properties.map(function (prop) {return Object.assign({ node: prop, value: prop.key.name, type: 'export' }, prop.key.range[0] !== prop.value.range[0] && { alias: prop.value.name });})); } } else { var nameParts = getNamedCJSExports(context, node.left); if (nameParts && nameParts.length > 0) { var name = nameParts.join('.'); getBlockExports(node.parent.parent).push({ node: node, value: name, displayName: name, type: 'export', rank: 0 }); } } } }return AssignmentExpression;}() }, { 'Program:exit': function () {function ProgramExit() { importMap.forEach(function (imported) { if (newlinesBetweenImports !== 'ignore' || newlinesBetweenTypeOnlyImports !== 'ignore') { makeNewlinesBetweenReport( context, imported, newlinesBetweenImports, newlinesBetweenTypeOnlyImports, distinctGroup, isSortingTypesGroup, consolidateIslands === 'inside-groups' && ( newlinesBetweenImports === 'always-and-inside-groups' || newlinesBetweenTypeOnlyImports === 'always-and-inside-groups')); } if (alphabetize.order !== 'ignore') { mutateRanksToAlphabetize(imported, alphabetize); } makeOutOfOrderReport(context, imported, categories['import']); }); exportMap.forEach(function (exported) { if (alphabetize.order !== 'ignore') { mutateRanksToAlphabetize(exported, alphabetize); makeOutOfOrderReport(context, exported, categories.exports); } }); importMap.clear(); exportMap.clear(); }return ProgramExit;}() }); }return create;}() }; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9ydWxlcy9vcmRlci5qcyJdLCJuYW1lcyI6WyJjYXRlZ29yaWVzIiwibmFtZWQiLCJleHBvcnRzIiwiZGVmYXVsdEdyb3VwcyIsInJldmVyc2UiLCJhcnJheSIsIm1hcCIsInYiLCJyYW5rIiwiZ2V0VG9rZW5zT3JDb21tZW50c0FmdGVyIiwic291cmNlQ29kZSIsIm5vZGUiLCJjb3VudCIsImN1cnJlbnROb2RlT3JUb2tlbiIsInJlc3VsdCIsImkiLCJnZXRUb2tlbk9yQ29tbWVudEFmdGVyIiwicHVzaCIsImdldFRva2Vuc09yQ29tbWVudHNCZWZvcmUiLCJnZXRUb2tlbk9yQ29tbWVudEJlZm9yZSIsInRha2VUb2tlbnNBZnRlcldoaWxlIiwiY29uZGl0aW9uIiwidG9rZW5zIiwibGVuZ3RoIiwidGFrZVRva2Vuc0JlZm9yZVdoaWxlIiwiZmluZE91dE9mT3JkZXIiLCJpbXBvcnRlZCIsIm1heFNlZW5SYW5rTm9kZSIsImZpbHRlciIsImltcG9ydGVkTW9kdWxlIiwicmVzIiwiZmluZFJvb3ROb2RlIiwicGFyZW50IiwiYm9keSIsImNvbW1lbnRPblNhbWVMaW5lQXMiLCJ0b2tlbiIsInR5cGUiLCJsb2MiLCJzdGFydCIsImxpbmUiLCJlbmQiLCJmaW5kRW5kT2ZMaW5lV2l0aENvbW1lbnRzIiwidG9rZW5zVG9FbmRPZkxpbmUiLCJlbmRPZlRva2VucyIsInJhbmdlIiwidGV4dCIsImZpbmRTdGFydE9mTGluZVdpdGhDb21tZW50cyIsInN0YXJ0T2ZUb2tlbnMiLCJmaW5kU3BlY2lmaWVyU3RhcnQiLCJnZXRUb2tlbkJlZm9yZSIsInZhbHVlIiwiZmluZFNwZWNpZmllckVuZCIsImdldFRva2VuQWZ0ZXIiLCJpc1JlcXVpcmVFeHByZXNzaW9uIiwiZXhwciIsImNhbGxlZSIsIm5hbWUiLCJhcmd1bWVudHMiLCJpc1N1cHBvcnRlZFJlcXVpcmVNb2R1bGUiLCJkZWNsYXJhdGlvbnMiLCJkZWNsIiwiaXNQbGFpblJlcXVpcmUiLCJpZCIsImluaXQiLCJpc1JlcXVpcmVXaXRoTWVtYmVyRXhwcmVzc2lvbiIsIm9iamVjdCIsImlzUGxhaW5JbXBvcnRNb2R1bGUiLCJzcGVjaWZpZXJzIiwiaXNQbGFpbkltcG9ydEVxdWFscyIsIm1vZHVsZVJlZmVyZW5jZSIsImV4cHJlc3Npb24iLCJpc0NKU0V4cG9ydHMiLCJjb250ZXh0IiwicHJvcGVydHkiLCJ2YXJpYWJsZXMiLCJmaW5kSW5kZXgiLCJ2YXJpYWJsZSIsImdldE5hbWVkQ0pTRXhwb3J0cyIsInJvb3QiLCJ1bnNoaWZ0Iiwic2xpY2UiLCJjYW5Dcm9zc05vZGVXaGlsZVJlb3JkZXIiLCJjYW5SZW9yZGVySXRlbXMiLCJmaXJzdE5vZGUiLCJzZWNvbmROb2RlIiwiaW5kZXhPZiIsInNvcnQiLCJmaXJzdEluZGV4Iiwic2Vjb25kSW5kZXgiLCJub2Rlc0JldHdlZW4iLCJub2RlQmV0d2VlbiIsIm1ha2VJbXBvcnREZXNjcmlwdGlvbiIsImV4cG9ydEtpbmQiLCJpbXBvcnRLaW5kIiwiZml4T3V0T2ZPcmRlciIsIm9yZGVyIiwiY2F0ZWdvcnkiLCJpc05hbWVkIiwiaXNFeHBvcnRzIiwiZmlyc3RSb290Iiwic2Vjb25kUm9vdCIsImZpcnN0Um9vdFN0YXJ0IiwiZmlyc3RSb290RW5kIiwic2Vjb25kUm9vdFN0YXJ0Iiwic2Vjb25kUm9vdEVuZCIsImRpc3BsYXlOYW1lIiwiYWxpYXMiLCJmaXJzdEltcG9ydCIsInNlY29uZEltcG9ydCIsIm1lc3NhZ2UiLCJmaXJzdENvZGUiLCJmaXJzdFRyaXZpYSIsInNlY29uZENvZGUiLCJzZWNvbmRUcml2aWEiLCJ0cmltbWVkVHJpdmlhIiwiZ2FwQ29kZSIsIndoaXRlc3BhY2VzIiwicmVwb3J0IiwiZml4IiwiZml4ZXIiLCJyZXBsYWNlVGV4dFJhbmdlIiwiZml4ZXMiLCJjYW5GaXgiLCJuZXdDb2RlIiwic3Vic3RyaW5nIiwicmVwb3J0T3V0T2ZPcmRlciIsIm91dE9mT3JkZXIiLCJmb3JFYWNoIiwiaW1wIiwiZm91bmQiLCJmaW5kIiwiaGFzSGlnaGVyUmFuayIsImltcG9ydGVkSXRlbSIsIm1ha2VPdXRPZk9yZGVyUmVwb3J0IiwicmV2ZXJzZWRJbXBvcnRlZCIsInJldmVyc2VkT3JkZXIiLCJjb21wYXJlU3RyaW5nIiwiYSIsImIiLCJERUZBVUxUX0lNUE9SVF9LSU5EIiwiZ2V0Tm9ybWFsaXplZFZhbHVlIiwidG9Mb3dlckNhc2UiLCJTdHJpbmciLCJnZXRTb3J0ZXIiLCJhbHBoYWJldGl6ZU9wdGlvbnMiLCJtdWx0aXBsaWVyIiwib3JkZXJJbXBvcnRLaW5kIiwibXVsdGlwbGllckltcG9ydEtpbmQiLCJpbXBvcnRzU29ydGVyIiwibm9kZUEiLCJub2RlQiIsImltcG9ydEEiLCJjYXNlSW5zZW5zaXRpdmUiLCJpbXBvcnRCIiwiQSIsInNwbGl0IiwiQiIsIk1hdGgiLCJtaW4iLCJtdXRhdGVSYW5rc1RvQWxwaGFiZXRpemUiLCJncm91cGVkQnlSYW5rcyIsIml0ZW0iLCJzb3J0ZXJGbiIsImdyb3VwUmFua3MiLCJPYmplY3QiLCJrZXlzIiwiZ3JvdXBSYW5rIiwibmV3UmFuayIsImFscGhhYmV0aXplZFJhbmtzIiwicmVkdWN