Skip to content

Commit

Permalink
fix(imports): Fix side-effect sort group with import = require()
Browse files Browse the repository at this point in the history
…syntax
  • Loading branch information
mskelton committed Mar 22, 2024
1 parent c9e1fec commit fa8de6e
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 9 deletions.
Binary file modified bun.lockb
Binary file not shown.
32 changes: 32 additions & 0 deletions src/__tests__/imports.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -917,6 +917,35 @@ createRuleTester({
},
],
},
{
name: "Sort groups - import = require()",
code: dedent`
import 'index.css'
import 'side-effect'
import a from "dependency-b"
import b from "dependency-c"
import type { A } from "dependency-a"
import c from "a.png"
import d from "b.jpg"
import e = require("a")
import f from "b"
import g from "c"
import h from "../b"
import i from "./b"
`,
options: [
{
groups: [
{ type: "side-effect", order: 10 },
{ type: "type", order: 30 },
{ regex: "\\.(png|jpg)$", order: 40 },
{ regex: "^\\.+\\/", order: 60 },
{ type: "dependency", order: 20 },
{ type: "other", order: 50 },
],
},
],
},
],
invalid: [
{
Expand Down Expand Up @@ -1051,6 +1080,7 @@ createRuleTester({
code: dedent`
import c from "a.png"
import h = require("../b")
import "./styles.css"
import b from "dependency-c"
import type { A } from "dependency-a"
import d = require("b.jpg")
Expand All @@ -1065,11 +1095,13 @@ createRuleTester({
import d = require("b.jpg")
import h = require("../b")
import i from "./b"
import "./styles.css"
`,
errors: [{ messageId: "unsorted" }],
options: [
{
groups: [
{ type: "side-effect", order: 60 },
{ type: "type", order: 30 },
{ regex: "\\.(png|jpg)$", order: 40 },
{ regex: "^\\.+\\/", order: 60 },
Expand Down
21 changes: 12 additions & 9 deletions src/rules/imports.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Rule, AST } from "eslint"
import { TSESTree } from "@typescript-eslint/experimental-utils"
import * as ESTree from "estree"
import { isResolved } from "../resolver.js"
import * as tsUtils from "../ts-utils.js"
import {
docsURL,
enumerate,
Expand All @@ -20,6 +22,8 @@ import {

const sortGroupsTypes = ["side-effect", "dependency", "type", "other"] as const

type Import = ESTree.ImportDeclaration | TSESTree.TSImportEqualsDeclaration

interface SortGroup {
order: number
type?: (typeof sortGroupsTypes)[number]
Expand All @@ -32,23 +36,25 @@ interface Options extends SorterOptions {
typeOrder?: TypeOrder
}

const getSortValue = (node: ESTree.ImportDeclaration) =>
const getSortValue = (node: Import) =>
node.type === "ImportDeclaration"
? getName(node.source)
: getName((node as any).moduleReference.expression)
: tsUtils.getName(node.moduleReference)

/**
* Returns the order of a given node based on the sort groups configured in the
* rule options. If no sort groups are configured (default), the order returned
* is always 0.
*/
function getSortGroup(sortGroups: SortGroup[], node: ESTree.ImportDeclaration) {
function getSortGroup(sortGroups: SortGroup[], node: Import) {
const source = getSortValue(node)

for (const { regex, type, order } of sortGroups) {
switch (type) {
case "side-effect":
if (!node.specifiers.length) return order
if (node.type === "ImportDeclaration" && !node.specifiers.length) {
return order
}
break

case "type": {
Expand All @@ -73,10 +79,7 @@ function getSortGroup(sortGroups: SortGroup[], node: ESTree.ImportDeclaration) {
return 0
}

function getImportKindWeight(
options: Options | undefined,
node: ESTree.ImportDeclaration
) {
function getImportKindWeight(options: Options | undefined, node: Import) {
const typeOrder = options?.typeOrder ?? "preserve"
const kind = (node as { importKind?: ImportOrExportKind }).importKind

Expand Down Expand Up @@ -136,7 +139,7 @@ export default {
// When sorting, the comments for the first node are not copied as
// we cannot determine if they are comments for the entire file or
// just the first import.
const isFirst = (node: ESTree.ImportDeclaration) => node === nodes[0]
const isFirst = (node: ESTree.Node) => node === nodes[0]

context.report({
node: firstUnsortedNode,
Expand Down
3 changes: 3 additions & 0 deletions src/ts-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import { getTextRange } from "./utils.js"
*/
export function getName(node?: TSESTree.Node): string {
switch (node?.type) {
case AST_NODE_TYPES.TSExternalModuleReference:
return getName(node.expression)

case AST_NODE_TYPES.Identifier:
return node.name

Expand Down

0 comments on commit fa8de6e

Please sign in to comment.