Skip to content

Commit

Permalink
feat: [import/order] collapse excess spacing for aesthetically pleasi…
Browse files Browse the repository at this point in the history
…ng imports via `consolidateIslands`
  • Loading branch information
Xunnamius committed Dec 23, 2024
1 parent d929108 commit 02507ca
Show file tree
Hide file tree
Showing 2 changed files with 1,284 additions and 67 deletions.
101 changes: 87 additions & 14 deletions src/rules/order.js
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,17 @@ function computeRank(context, ranks, importEntry, excludedImportTypes, isSorting
function registerNode(context, importEntry, ranks, imported, excludedImportTypes, isSortingTypesAmongThemselves) {
const rank = computeRank(context, ranks, importEntry, excludedImportTypes, isSortingTypesAmongThemselves);

Check warning on line 556 in src/rules/order.js

View check run for this annotation

Codecov / codecov/patch

src/rules/order.js#L555-L556

Added lines #L555 - L556 were not covered by tests
if (rank !== -1) {
imported.push({ ...importEntry, rank });
let importNode = importEntry.node;

Check warning on line 558 in src/rules/order.js

View check run for this annotation

Codecov / codecov/patch

src/rules/order.js#L558

Added line #L558 was not covered by tests

if(importEntry.type === 'require' && importNode.parent.parent.type === 'VariableDeclaration') {
importNode = importNode.parent.parent;

Check warning on line 561 in src/rules/order.js

View check run for this annotation

Codecov / codecov/patch

src/rules/order.js#L560-L561

Added lines #L560 - L561 were not covered by tests
}

imported.push({

Check warning on line 564 in src/rules/order.js

View check run for this annotation

Codecov / codecov/patch

src/rules/order.js#L564

Added line #L564 was not covered by tests
...importEntry,
rank,
isMultiline: importNode.loc.end.line !== importNode.loc.start.line
});
}
}

Expand Down Expand Up @@ -681,7 +691,7 @@ function removeNewLineAfterImport(context, currentImport, previousImport) {
return undefined;
}

function makeNewlinesBetweenReport(context, imported, newlinesBetweenImports, newlinesBetweenTypeOnlyImports, distinctGroup, isSortingTypesAmongThemselves) {
function makeNewlinesBetweenReport(context, imported, newlinesBetweenImports, newlinesBetweenTypeOnlyImports_, distinctGroup, isSortingTypesAmongThemselves, isConsolidatingSpaceBetweenImports) {

Check warning on line 694 in src/rules/order.js

View check run for this annotation

Codecov / codecov/patch

src/rules/order.js#L694

Added line #L694 was not covered by tests
const getNumberOfEmptyLinesBetween = (currentImport, previousImport) => {
const linesBetweenImports = getSourceCode(context).lines.slice(
previousImport.node.loc.end.line,
Expand All @@ -707,51 +717,68 @@ function makeNewlinesBetweenReport(context, imported, newlinesBetweenImports, ne
const isTypeOnlyImport = currentImport.node.importKind === 'type';
const isPreviousImportTypeOnlyImport = previousImport.node.importKind === 'type';

Check warning on line 718 in src/rules/order.js

View check run for this annotation

Codecov / codecov/patch

src/rules/order.js#L717-L718

Added lines #L717 - L718 were not covered by tests

const isNormalImportFollowingTypeOnlyImportAndRelevant =
!isTypeOnlyImport && isPreviousImportTypeOnlyImport && isSortingTypesAmongThemselves;
const isNormalImportNextToTypeOnlyImportAndRelevant =
isTypeOnlyImport !== isPreviousImportTypeOnlyImport && isSortingTypesAmongThemselves;

Check warning on line 721 in src/rules/order.js

View check run for this annotation

Codecov / codecov/patch

src/rules/order.js#L721

Added line #L721 was not covered by tests

const isTypeOnlyImportAndRelevant =
isTypeOnlyImport && isSortingTypesAmongThemselves;

Check warning on line 724 in src/rules/order.js

View check run for this annotation

Codecov / codecov/patch

src/rules/order.js#L724

Added line #L724 was not covered by tests

// In the special case where newlinesBetweenTypeOnlyImports and
// consolidateIslands want the opposite thing, consolidateIslands wins
const newlinesBetweenTypeOnlyImports =
newlinesBetweenTypeOnlyImports_ === 'never' &&
isConsolidatingSpaceBetweenImports &&
isSortingTypesAmongThemselves &&
(isNormalImportNextToTypeOnlyImportAndRelevant ||
previousImport.isMultiline ||
currentImport.isMultiline)
? 'always-and-inside-groups'
: newlinesBetweenTypeOnlyImports_;

Check warning on line 736 in src/rules/order.js

View check run for this annotation

Codecov / codecov/patch

src/rules/order.js#L729-L736

Added lines #L729 - L736 were not covered by tests

const isNotIgnored =
(isTypeOnlyImportAndRelevant &&
newlinesBetweenTypeOnlyImports !== 'ignore') ||
(!isTypeOnlyImportAndRelevant && newlinesBetweenImports !== 'ignore');

Check warning on line 741 in src/rules/order.js

View check run for this annotation

Codecov / codecov/patch

src/rules/order.js#L739-L741

Added lines #L739 - L741 were not covered by tests

if(isNotIgnored) {

Check warning on line 743 in src/rules/order.js

View check run for this annotation

Codecov / codecov/patch

src/rules/order.js#L743

Added line #L743 was not covered by tests
const shouldAssertNewlineBetweenGroups =
((isTypeOnlyImportAndRelevant || isNormalImportFollowingTypeOnlyImportAndRelevant) &&
((isTypeOnlyImportAndRelevant || isNormalImportNextToTypeOnlyImportAndRelevant) &&
(newlinesBetweenTypeOnlyImports === 'always' ||
newlinesBetweenTypeOnlyImports === 'always-and-inside-groups')) ||
((!isTypeOnlyImportAndRelevant && !isNormalImportFollowingTypeOnlyImportAndRelevant) &&
((!isTypeOnlyImportAndRelevant && !isNormalImportNextToTypeOnlyImportAndRelevant) &&
(newlinesBetweenImports === 'always' ||
newlinesBetweenImports === 'always-and-inside-groups'));

Check warning on line 750 in src/rules/order.js

View check run for this annotation

Codecov / codecov/patch

src/rules/order.js#L745-L750

Added lines #L745 - L750 were not covered by tests

const shouldAssertNoNewlineWithinGroup =
((isTypeOnlyImportAndRelevant || isNormalImportFollowingTypeOnlyImportAndRelevant) &&
((isTypeOnlyImportAndRelevant || isNormalImportNextToTypeOnlyImportAndRelevant) &&
(newlinesBetweenTypeOnlyImports !== 'always-and-inside-groups')) ||
((!isTypeOnlyImportAndRelevant && !isNormalImportFollowingTypeOnlyImportAndRelevant) &&
((!isTypeOnlyImportAndRelevant && !isNormalImportNextToTypeOnlyImportAndRelevant) &&
(newlinesBetweenImports !== 'always-and-inside-groups'));

Check warning on line 756 in src/rules/order.js

View check run for this annotation

Codecov / codecov/patch

src/rules/order.js#L753-L756

Added lines #L753 - L756 were not covered by tests

const shouldAssertNoNewlineBetweenGroup =
!isSortingTypesAmongThemselves ||
!isNormalImportFollowingTypeOnlyImportAndRelevant ||
!isNormalImportNextToTypeOnlyImportAndRelevant ||
newlinesBetweenTypeOnlyImports === 'never';

Check warning on line 761 in src/rules/order.js

View check run for this annotation

Codecov / codecov/patch

src/rules/order.js#L759-L761

Added lines #L759 - L761 were not covered by tests

const isTheNewlineBetweenImportsInTheSameGroup = (distinctGroup && currentImport.rank === previousImport.rank) ||
(!distinctGroup && !isStartOfDistinctGroup);

Check warning on line 764 in src/rules/order.js

View check run for this annotation

Codecov / codecov/patch

src/rules/order.js#L763-L764

Added lines #L763 - L764 were not covered by tests

// Let's try to cut down on linting errors sent to the user
let alreadyReported = false;

Check warning on line 767 in src/rules/order.js

View check run for this annotation

Codecov / codecov/patch

src/rules/order.js#L767

Added line #L767 was not covered by tests

if (shouldAssertNewlineBetweenGroups) {
if (currentImport.rank !== previousImport.rank && emptyLinesBetween === 0) {
if (distinctGroup || !distinctGroup && isStartOfDistinctGroup) {
alreadyReported = true;
context.report({

Check warning on line 773 in src/rules/order.js

View check run for this annotation

Codecov / codecov/patch

src/rules/order.js#L769-L773

Added lines #L769 - L773 were not covered by tests
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 (
(distinctGroup && currentImport.rank === previousImport.rank) ||
(!distinctGroup && !isStartOfDistinctGroup)
) {
if (isTheNewlineBetweenImportsInTheSameGroup) {
alreadyReported = true;
context.report({

Check warning on line 782 in src/rules/order.js

View check run for this annotation

Codecov / codecov/patch

src/rules/order.js#L779-L782

Added lines #L779 - L782 were not covered by tests
node: previousImport.node,
message: 'There should be no empty line within import group',
Expand All @@ -760,12 +787,41 @@ function makeNewlinesBetweenReport(context, imported, newlinesBetweenImports, ne
}
}
} else if (emptyLinesBetween > 0 && shouldAssertNoNewlineBetweenGroup) {
alreadyReported = true;
context.report({

Check warning on line 791 in src/rules/order.js

View check run for this annotation

Codecov / codecov/patch

src/rules/order.js#L789-L791

Added lines #L789 - L791 were not covered by tests
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) {

Check warning on line 799 in src/rules/order.js

View check run for this annotation

Codecov / codecov/patch

src/rules/order.js#L798-L799

Added lines #L798 - L799 were not covered by tests
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) {

Check warning on line 805 in src/rules/order.js

View check run for this annotation

Codecov / codecov/patch

src/rules/order.js#L805

Added line #L805 was not covered by tests
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

Check warning on line 815 in src/rules/order.js

View check run for this annotation

Codecov / codecov/patch

src/rules/order.js#L811-L815

Added lines #L811 - L815 were not covered by tests
) {
context.report({

Check warning on line 817 in src/rules/order.js

View check run for this annotation

Codecov / codecov/patch

src/rules/order.js#L817

Added line #L817 was not covered by tests
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;
Expand Down Expand Up @@ -848,6 +904,12 @@ module.exports = {
'never',
],
},
consolidateIslands: {
enum: [
'inside-groups',
'never',
],
},
sortTypesAmongThemselves: {
type: 'boolean',
default: false,
Expand Down Expand Up @@ -910,6 +972,7 @@ module.exports = {
const newlinesBetweenTypeOnlyImports = options['newlines-between-types'] || newlinesBetweenImports;

Check warning on line 972 in src/rules/order.js

View check run for this annotation

Codecov / codecov/patch

src/rules/order.js#L972

Added line #L972 was not covered by tests
const pathGroupsExcludedImportTypes = new Set(options.pathGroupsExcludedImportTypes || ['builtin', 'external', 'object']);
const sortTypesAmongThemselves = options.sortTypesAmongThemselves;
const consolidateIslands = options.consolidateIslands || 'never';

Check warning on line 975 in src/rules/order.js

View check run for this annotation

Codecov / codecov/patch

src/rules/order.js#L974-L975

Added lines #L974 - L975 were not covered by tests

const named = {
types: 'mixed',
Expand Down Expand Up @@ -1172,7 +1235,17 @@ module.exports = {
'Program:exit'() {
importMap.forEach((imported) => {
if (newlinesBetweenImports !== 'ignore' || newlinesBetweenTypeOnlyImports !== 'ignore') {
makeNewlinesBetweenReport(context, imported, newlinesBetweenImports, newlinesBetweenTypeOnlyImports, distinctGroup, isSortingTypesAmongThemselves);
makeNewlinesBetweenReport(

Check warning on line 1238 in src/rules/order.js

View check run for this annotation

Codecov / codecov/patch

src/rules/order.js#L1237-L1238

Added lines #L1237 - L1238 were not covered by tests
context,
imported,
newlinesBetweenImports,
newlinesBetweenTypeOnlyImports,
distinctGroup,
isSortingTypesAmongThemselves,
consolidateIslands === 'inside-groups' &&
(newlinesBetweenImports === 'always-and-inside-groups' ||
newlinesBetweenTypeOnlyImports === 'always-and-inside-groups')

Check warning on line 1247 in src/rules/order.js

View check run for this annotation

Codecov / codecov/patch

src/rules/order.js#L1245-L1247

Added lines #L1245 - L1247 were not covered by tests
);
}

if (alphabetize.order !== 'ignore') {
Expand Down
Loading

0 comments on commit 02507ca

Please sign in to comment.