eslint-plugin-simple-import-sort
Advanced tools
Comparing version 10.0.0 to 11.0.0
@@ -38,3 +38,3 @@ "use strict"; | ||
"Program:exit": () => { | ||
const sourceCode = context.getSourceCode(); | ||
const sourceCode = shared.getSourceCode(context); | ||
for (const parent of parents) { | ||
@@ -54,3 +54,3 @@ for (const chunk of shared.extractChunks(parent, (node, lastNode) => | ||
function maybeReportChunkSorting(chunk, context) { | ||
const sourceCode = context.getSourceCode(); | ||
const sourceCode = shared.getSourceCode(context); | ||
const items = shared.getImportExportItems( | ||
@@ -72,3 +72,3 @@ chunk, | ||
node, | ||
context.getSourceCode(), | ||
shared.getSourceCode(context), | ||
getSpecifiers | ||
@@ -75,0 +75,0 @@ ); |
@@ -19,2 +19,4 @@ "use strict"; | ||
["^\\."], | ||
// TypeScript import assignments. | ||
["^\\u0001", "^\\u0002"], | ||
]; | ||
@@ -60,3 +62,3 @@ | ||
return { | ||
ImportDeclaration: (node) => { | ||
"ImportDeclaration,TSImportEqualsDeclaration": (node) => { | ||
parents.add(node.parent); | ||
@@ -80,3 +82,3 @@ }, | ||
function maybeReportChunkSorting(chunk, context, outerGroups) { | ||
const sourceCode = context.getSourceCode(); | ||
const sourceCode = shared.getSourceCode(context); | ||
const items = shared.getImportExportItems( | ||
@@ -103,10 +105,12 @@ chunk, | ||
const { originalSource } = item.source; | ||
const source = item.isSideEffectImport | ||
? `\0${originalSource}` | ||
: item.source.kind !== "value" | ||
? `${originalSource}\0` | ||
: originalSource; | ||
const sourceWithControlCharacter = getSourceWithControlCharacter( | ||
originalSource, | ||
item | ||
); | ||
const [matchedGroup] = shared | ||
.flatMap(itemGroups, (groups) => | ||
groups.map((group) => [group, group.regex.exec(source)]) | ||
groups.map((group) => [ | ||
group, | ||
group.regex.exec(sourceWithControlCharacter), | ||
]) | ||
) | ||
@@ -137,5 +141,29 @@ .reduce( | ||
function getSourceWithControlCharacter(originalSource, item) { | ||
if (item.isSideEffectImport) { | ||
return `\0${originalSource}`; | ||
} | ||
switch (item.source.kind) { | ||
case shared.KIND_VALUE: | ||
return originalSource; | ||
case shared.KIND_TS_IMPORT_ASSIGNMENT_REQUIRE: | ||
return `\u0001${originalSource}`; | ||
case shared.KIND_TS_IMPORT_ASSIGNMENT_NAMESPACE: | ||
return `\u0002${originalSource}`; | ||
default: // `type` and `typeof`. | ||
return `${originalSource}\u0000`; | ||
} | ||
} | ||
// Exclude "ImportDefaultSpecifier" – the "def" in `import def, {a, b}`. | ||
function getSpecifiers(importNode) { | ||
return importNode.specifiers.filter((node) => isImportSpecifier(node)); | ||
switch (importNode.type) { | ||
case "ImportDeclaration": | ||
return importNode.specifiers.filter((node) => isImportSpecifier(node)); | ||
case "TSImportEqualsDeclaration": | ||
return []; | ||
// istanbul ignore next | ||
default: | ||
throw new Error(`Unsupported import node type: ${importNode.type}`); | ||
} | ||
} | ||
@@ -145,3 +173,6 @@ | ||
function isImport(node) { | ||
return node.type === "ImportDeclaration"; | ||
return ( | ||
node.type === "ImportDeclaration" || | ||
node.type === "TSImportEqualsDeclaration" | ||
); | ||
} | ||
@@ -159,7 +190,19 @@ | ||
function isSideEffectImport(importNode, sourceCode) { | ||
return ( | ||
importNode.specifiers.length === 0 && | ||
(!importNode.importKind || importNode.importKind === "value") && | ||
!shared.isPunctuator(sourceCode.getFirstToken(importNode, { skip: 1 }), "{") | ||
); | ||
switch (importNode.type) { | ||
case "ImportDeclaration": | ||
return ( | ||
importNode.specifiers.length === 0 && | ||
(!importNode.importKind || | ||
importNode.importKind === shared.KIND_VALUE) && | ||
!shared.isPunctuator( | ||
sourceCode.getFirstToken(importNode, { skip: 1 }), | ||
"{" | ||
) | ||
); | ||
case "TSImportEqualsDeclaration": | ||
return false; | ||
// istanbul ignore next | ||
default: | ||
throw new Error(`Unsupported import node type: ${importNode.type}`); | ||
} | ||
} |
@@ -7,2 +7,6 @@ "use strict"; | ||
module.exports = { | ||
meta: { | ||
name: "eslint-plugin-simple-import-sort", | ||
version: "11.0.0", | ||
}, | ||
rules: { | ||
@@ -9,0 +13,0 @@ imports: importsRule, |
{ | ||
"name": "eslint-plugin-simple-import-sort", | ||
"version": "10.0.0", | ||
"version": "11.0.0", | ||
"license": "MIT", | ||
@@ -5,0 +5,0 @@ "author": "Simon Lydell", |
@@ -5,3 +5,3 @@ # eslint-plugin-simple-import-sort | ||
- ✅️ Runs via `eslint --fix` – no new tooling | ||
- ✅️ Runs via [`eslint --fix`][eslint-fix] – no new tooling | ||
- ✅️ Also sorts exports where possible | ||
@@ -12,2 +12,3 @@ - ✅️ Handles comments | ||
- ✅️ [Prettier] friendly | ||
- ✅️ [dprint] friendly ([with configuration][dprint-configuration]) | ||
- ✅️ [eslint-plugin-import] friendly | ||
@@ -19,5 +20,8 @@ - ✅️ `git diff` friendly | ||
This is for those who use `eslint --fix` (autofix) a lot and want to completely forget about sorting imports! | ||
This is for those who use [`eslint --fix`][eslint-fix] (autofix) a lot and want to completely forget about sorting imports! | ||
[@typescript-eslint/parser]: https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/parser | ||
[dprint-configuration]: https://github.com/lydell/eslint-plugin-simple-import-sort/#how-do-i-use-this-with-dprint | ||
[dprint]: https://dprint.dev/ | ||
[eslint-fix]: https://eslint.org/docs/user-guide/command-line-interface#--fix | ||
[eslint-plugin-import]: https://github.com/import-js/eslint-plugin-import/ | ||
@@ -24,0 +28,0 @@ [no-require]: https://github.com/lydell/eslint-plugin-simple-import-sort/#does-it-support-require |
100
shared.js
@@ -47,3 +47,3 @@ "use strict"; | ||
function maybeReportSorting(context, sorted, start, end) { | ||
const sourceCode = context.getSourceCode(); | ||
const sourceCode = getSourceCode(context); | ||
const original = sourceCode.getText().slice(start, end); | ||
@@ -168,3 +168,3 @@ if (original !== sorted) { | ||
const source = getSource(node); | ||
const source = getSource(sourceCode, node); | ||
@@ -800,4 +800,4 @@ return { | ||
function getSource(node) { | ||
const source = node.source.value; | ||
function getSource(sourceCode, node) { | ||
const [source, kind] = getSourceTextAndKind(sourceCode, node); | ||
@@ -812,3 +812,3 @@ return { | ||
.replace(/^[./]*\/$/, "$&,") | ||
// Make `.` and `/` sort before any other punctation. | ||
// Make `.` and `/` sort before any other punctuation. | ||
// The default order is: _ - , x x x . x x x / x x x | ||
@@ -832,12 +832,81 @@ // We’re changing it to: . / , x x x _ x x x - x x x | ||
originalSource: source, | ||
kind: getImportExportKind(node), | ||
kind, | ||
}; | ||
} | ||
function getSourceTextAndKind(sourceCode, node) { | ||
switch (node.type) { | ||
case "ImportDeclaration": | ||
case "ExportNamedDeclaration": | ||
case "ExportAllDeclaration": | ||
return [node.source.value, getImportExportKind(node)]; | ||
case "TSImportEqualsDeclaration": | ||
return getSourceTextAndKindFromModuleReference( | ||
sourceCode, | ||
node.moduleReference | ||
); | ||
// istanbul ignore next | ||
default: | ||
throw new Error(`Unsupported import/export node type: ${node.type}`); | ||
} | ||
} | ||
const KIND_VALUE = "value"; | ||
const KIND_TS_IMPORT_ASSIGNMENT_REQUIRE = "z_require"; | ||
const KIND_TS_IMPORT_ASSIGNMENT_NAMESPACE = "z_namespace"; | ||
function getSourceTextAndKindFromModuleReference(sourceCode, node) { | ||
switch (node.type) { | ||
case "TSExternalModuleReference": | ||
// Only string literals inside `require()` are allowed by | ||
// TypeScript, but the parser supports anything. Sorting | ||
// is defined for string literals only. For other expressions, | ||
// we just make sure not to crash. | ||
switch (node.expression.type) { | ||
case "Literal": | ||
return [ | ||
typeof node.expression.value === "string" | ||
? node.expression.value | ||
: node.expression.raw, | ||
KIND_TS_IMPORT_ASSIGNMENT_REQUIRE, | ||
]; | ||
default: { | ||
const [start, end] = node.expression.range; | ||
return [ | ||
sourceCode.text.slice(start, end), | ||
KIND_TS_IMPORT_ASSIGNMENT_REQUIRE, | ||
]; | ||
} | ||
} | ||
case "TSQualifiedName": | ||
return [ | ||
getSourceTextFromTSQualifiedName(sourceCode, node), | ||
KIND_TS_IMPORT_ASSIGNMENT_NAMESPACE, | ||
]; | ||
case "Identifier": | ||
return [node.name, KIND_TS_IMPORT_ASSIGNMENT_NAMESPACE]; | ||
// istanbul ignore next | ||
default: | ||
throw new Error(`Unsupported module reference node type: ${node.type}`); | ||
} | ||
} | ||
function getSourceTextFromTSQualifiedName(sourceCode, node) { | ||
switch (node.left.type) { | ||
case "Identifier": | ||
return `${node.left.name}.${node.right.name}`; | ||
case "TSQualifiedName": | ||
return `${getSourceTextFromTSQualifiedName(sourceCode, node.left)}.${ | ||
node.right.name | ||
}`; | ||
// istanbul ignore next | ||
default: | ||
throw new Error(`Unsupported TS qualified name node type: ${node.type}`); | ||
} | ||
} | ||
function getImportExportKind(node) { | ||
// `type` and `typeof` imports, as well as `type` exports (there are no | ||
// `typeof` exports). In Flow, import specifiers can also have a kind. Default | ||
// to "value" (like TypeScript) to make regular imports/exports come after the | ||
// type imports/exports. | ||
return node.importKind || node.exportKind || "value"; | ||
// `typeof` exports). | ||
return node.importKind || node.exportKind || KIND_VALUE; | ||
} | ||
@@ -862,2 +931,9 @@ | ||
function getSourceCode(context) { | ||
// `.getSourceCode()` is deprecated in favor of `.sourceCode`. | ||
// We support both for now. | ||
// istanbul ignore next | ||
return context.sourceCode || context.getSourceCode(); | ||
} | ||
module.exports = { | ||
@@ -867,3 +943,7 @@ extractChunks, | ||
getImportExportItems, | ||
getSourceCode, | ||
isPunctuator, | ||
KIND_TS_IMPORT_ASSIGNMENT_NAMESPACE, | ||
KIND_TS_IMPORT_ASSIGNMENT_REQUIRE, | ||
KIND_VALUE, | ||
maybeReportSorting, | ||
@@ -870,0 +950,0 @@ printSortedItems, |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Deprecated
MaintenanceThe maintainer of the package marked it as deprecated. This could indicate that a single version should not be used, or that the package is no longer maintained and any new vulnerabilities will not be fixed.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
41387
1126
31
1