Skip to content

Commit 2b9683d

Browse files
committed
feat: [import/order] allow controlling intragroup spacing of type-only imports via newlines-between-types
1 parent 0c179cd commit 2b9683d

File tree

2 files changed

+465
-30
lines changed

2 files changed

+465
-30
lines changed

src/rules/order.js

Lines changed: 82 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -677,7 +677,7 @@ function removeNewLineAfterImport(context, currentImport, previousImport) {
677677
return undefined;
678678
}
679679

680-
function makeNewlinesBetweenReport(context, imported, newlinesBetweenImports, distinctGroup) {
680+
function makeNewlinesBetweenReport(context, imported, newlinesBetweenImports, newlinesBetweenTypeOnlyImports, distinctGroup, isSortingTypesAmongThemselves) {
681681
const getNumberOfEmptyLinesBetween = (currentImport, previousImport) => {
682682
const linesBetweenImports = getSourceCode(context).lines.slice(
683683
previousImport.node.loc.end.line,
@@ -690,35 +690,78 @@ function makeNewlinesBetweenReport(context, imported, newlinesBetweenImports, di
690690
let previousImport = imported[0];
691691

692692
imported.slice(1).forEach(function (currentImport) {
693-
const emptyLinesBetween = getNumberOfEmptyLinesBetween(currentImport, previousImport);
694-
const isStartOfDistinctGroup = getIsStartOfDistinctGroup(currentImport, previousImport);
695-
696-
if (newlinesBetweenImports === 'always'
697-
|| newlinesBetweenImports === 'always-and-inside-groups') {
698-
if (currentImport.rank !== previousImport.rank && emptyLinesBetween === 0) {
699-
if (distinctGroup || !distinctGroup && isStartOfDistinctGroup) {
700-
context.report({
701-
node: previousImport.node,
702-
message: 'There should be at least one empty line between import groups',
703-
fix: fixNewLineAfterImport(context, previousImport),
704-
});
705-
}
706-
} else if (emptyLinesBetween > 0
707-
&& newlinesBetweenImports !== 'always-and-inside-groups') {
708-
if (distinctGroup && currentImport.rank === previousImport.rank || !distinctGroup && !isStartOfDistinctGroup) {
709-
context.report({
710-
node: previousImport.node,
711-
message: 'There should be no empty line within import group',
712-
fix: removeNewLineAfterImport(context, currentImport, previousImport),
713-
});
693+
const emptyLinesBetween = getNumberOfEmptyLinesBetween(
694+
currentImport,
695+
previousImport
696+
);
697+
698+
const isStartOfDistinctGroup = getIsStartOfDistinctGroup(
699+
currentImport,
700+
previousImport
701+
);
702+
703+
const isTypeOnlyImport = currentImport.node.importKind === 'type';
704+
const isPreviousImportTypeOnlyImport = previousImport.node.importKind === 'type';
705+
706+
const isNormalImportFollowingTypeOnlyImportAndRelevant =
707+
!isTypeOnlyImport && isPreviousImportTypeOnlyImport && isSortingTypesAmongThemselves;
708+
709+
const isTypeOnlyImportAndRelevant =
710+
isTypeOnlyImport && isSortingTypesAmongThemselves;
711+
712+
const isNotIgnored =
713+
(isTypeOnlyImportAndRelevant &&
714+
newlinesBetweenTypeOnlyImports !== 'ignore') ||
715+
(!isTypeOnlyImportAndRelevant && newlinesBetweenImports !== 'ignore');
716+
717+
if(isNotIgnored) {
718+
const shouldAssertNewlineBetweenGroups =
719+
((isTypeOnlyImportAndRelevant || isNormalImportFollowingTypeOnlyImportAndRelevant) &&
720+
(newlinesBetweenTypeOnlyImports === 'always' ||
721+
newlinesBetweenTypeOnlyImports === 'always-and-inside-groups')) ||
722+
((!isTypeOnlyImportAndRelevant && !isNormalImportFollowingTypeOnlyImportAndRelevant) &&
723+
(newlinesBetweenImports === 'always' ||
724+
newlinesBetweenImports === 'always-and-inside-groups'));
725+
726+
const shouldAssertNoNewlineWithinGroup =
727+
((isTypeOnlyImportAndRelevant || isNormalImportFollowingTypeOnlyImportAndRelevant) &&
728+
(newlinesBetweenTypeOnlyImports !== 'always-and-inside-groups')) ||
729+
((!isTypeOnlyImportAndRelevant && !isNormalImportFollowingTypeOnlyImportAndRelevant) &&
730+
(newlinesBetweenImports !== 'always-and-inside-groups'));
731+
732+
const shouldAssertNoNewlineBetweenGroup =
733+
!isSortingTypesAmongThemselves ||
734+
!isNormalImportFollowingTypeOnlyImportAndRelevant ||
735+
newlinesBetweenTypeOnlyImports === 'never';
736+
737+
if (shouldAssertNewlineBetweenGroups) {
738+
if (currentImport.rank !== previousImport.rank && emptyLinesBetween === 0) {
739+
if (distinctGroup || !distinctGroup && isStartOfDistinctGroup) {
740+
context.report({
741+
node: previousImport.node,
742+
message: 'There should be at least one empty line between import groups',
743+
fix: fixNewLineAfterImport(context, previousImport),
744+
});
745+
}
746+
} else if (emptyLinesBetween > 0 && shouldAssertNoNewlineWithinGroup) {
747+
if (
748+
(distinctGroup && currentImport.rank === previousImport.rank) ||
749+
(!distinctGroup && !isStartOfDistinctGroup)
750+
) {
751+
context.report({
752+
node: previousImport.node,
753+
message: 'There should be no empty line within import group',
754+
fix: removeNewLineAfterImport(context, currentImport, previousImport)
755+
});
756+
}
714757
}
758+
} else if (emptyLinesBetween > 0 && shouldAssertNoNewlineBetweenGroup) {
759+
context.report({
760+
node: previousImport.node,
761+
message: 'There should be no empty line between import groups',
762+
fix: removeNewLineAfterImport(context, currentImport, previousImport),
763+
});
715764
}
716-
} else if (emptyLinesBetween > 0) {
717-
context.report({
718-
node: previousImport.node,
719-
message: 'There should be no empty line between import groups',
720-
fix: removeNewLineAfterImport(context, currentImport, previousImport),
721-
});
722765
}
723766

724767
previousImport = currentImport;
@@ -793,6 +836,14 @@ module.exports = {
793836
'never',
794837
],
795838
},
839+
'newlines-between-types': {
840+
enum: [
841+
'ignore',
842+
'always',
843+
'always-and-inside-groups',
844+
'never',
845+
],
846+
},
796847
sortTypesAmongThemselves: {
797848
type: 'boolean',
798849
default: false,
@@ -852,6 +903,7 @@ module.exports = {
852903
create(context) {
853904
const options = context.options[0] || {};
854905
const newlinesBetweenImports = options['newlines-between'] || 'ignore';
906+
const newlinesBetweenTypeOnlyImports = options['newlines-between-types'] || newlinesBetweenImports;
855907
const pathGroupsExcludedImportTypes = new Set(options.pathGroupsExcludedImportTypes || ['builtin', 'external', 'object']);
856908
const sortTypesAmongThemselves = options.sortTypesAmongThemselves;
857909

@@ -1115,8 +1167,8 @@ module.exports = {
11151167
},
11161168
'Program:exit'() {
11171169
importMap.forEach((imported) => {
1118-
if (newlinesBetweenImports !== 'ignore') {
1119-
makeNewlinesBetweenReport(context, imported, newlinesBetweenImports, distinctGroup);
1170+
if (newlinesBetweenImports !== 'ignore' || newlinesBetweenTypeOnlyImports !== 'ignore') {
1171+
makeNewlinesBetweenReport(context, imported, newlinesBetweenImports, newlinesBetweenTypeOnlyImports, distinctGroup, isSortingTypesAmongThemselves);
11201172
}
11211173

11221174
if (alphabetize.order !== 'ignore') {

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy