183 lines
5.8 KiB
TypeScript
183 lines
5.8 KiB
TypeScript
import rule from "@effect/oxc/oxlint/rules/no-import-from-barrel-package"
|
|
import { describe, expect, it } from "vitest"
|
|
import { runRule } from "./utils.ts"
|
|
|
|
describe("no-import-from-barrel-package", () => {
|
|
const testOptions = {
|
|
filename: "/test/file.ts",
|
|
cwd: "/test",
|
|
ruleOptions: [{ checkPatterns: ["^effect$"] }]
|
|
}
|
|
|
|
const createImportDeclaration = (
|
|
source: string,
|
|
specifiers: Array<unknown>,
|
|
importKind?: "type" | "value"
|
|
) => {
|
|
const base = {
|
|
type: "ImportDeclaration" as const,
|
|
source: { value: source },
|
|
specifiers,
|
|
range: [0, 50] as [number, number]
|
|
}
|
|
return importKind !== undefined ? { ...base, importKind } : base
|
|
}
|
|
|
|
const createNamedSpecifier = (
|
|
name: string,
|
|
local?: string,
|
|
importKind?: "type" | "value"
|
|
) => {
|
|
const base = {
|
|
type: "ImportSpecifier" as const,
|
|
imported: { type: "Identifier" as const, name },
|
|
local: { name: local ?? name }
|
|
}
|
|
return importKind !== undefined ? { ...base, importKind } : base
|
|
}
|
|
|
|
it("should not report for imports from non-barrel packages", () => {
|
|
const node = createImportDeclaration("effect/Effect", [
|
|
createNamedSpecifier("Effect")
|
|
])
|
|
const errors = runRule(rule, "ImportDeclaration", node, testOptions)
|
|
expect(errors).toHaveLength(0)
|
|
})
|
|
|
|
it("should report for named imports from effect barrel", () => {
|
|
const node = createImportDeclaration("effect", [
|
|
createNamedSpecifier("Effect")
|
|
])
|
|
const errors = runRule(rule, "ImportDeclaration", node, testOptions)
|
|
expect(errors).toHaveLength(1)
|
|
expect(errors[0].message).toBe(
|
|
`Use import * as Effect from "effect/Effect" instead`
|
|
)
|
|
})
|
|
|
|
it("should report for multiple named imports from effect barrel", () => {
|
|
const node = createImportDeclaration("effect", [
|
|
createNamedSpecifier("Effect"),
|
|
createNamedSpecifier("Option"),
|
|
createNamedSpecifier("Either")
|
|
])
|
|
const errors = runRule(rule, "ImportDeclaration", node, testOptions)
|
|
expect(errors).toHaveLength(3)
|
|
})
|
|
|
|
it("should not report for type-only import declarations", () => {
|
|
const node = createImportDeclaration(
|
|
"effect",
|
|
[createNamedSpecifier("Effect")],
|
|
"type"
|
|
)
|
|
const errors = runRule(rule, "ImportDeclaration", node, testOptions)
|
|
expect(errors).toHaveLength(0)
|
|
})
|
|
|
|
it("should not report for type imports within named specifiers", () => {
|
|
const node = createImportDeclaration("effect", [
|
|
createNamedSpecifier("Effect", "Effect", "type")
|
|
])
|
|
const errors = runRule(rule, "ImportDeclaration", node, testOptions)
|
|
expect(errors).toHaveLength(0)
|
|
})
|
|
|
|
it("should handle aliased imports", () => {
|
|
const node = createImportDeclaration("effect", [
|
|
createNamedSpecifier("Effect", "Eff")
|
|
])
|
|
const errors = runRule(rule, "ImportDeclaration", node, testOptions)
|
|
expect(errors).toHaveLength(1)
|
|
expect(errors[0].message).toBe(
|
|
`Use import * as Eff from "effect/Effect" instead`
|
|
)
|
|
})
|
|
|
|
it("should report for namespace imports from barrel", () => {
|
|
const node = createImportDeclaration("effect", [
|
|
{
|
|
type: "ImportNamespaceSpecifier",
|
|
local: { name: "Effect" }
|
|
}
|
|
])
|
|
const errors = runRule(rule, "ImportDeclaration", node, testOptions)
|
|
expect(errors).toHaveLength(1)
|
|
expect(errors[0].message).toBe(
|
|
`Do not use namespace import from barrel file "effect", import from specific modules instead`
|
|
)
|
|
})
|
|
|
|
it("should not report for namespace imports from module paths", () => {
|
|
const node = createImportDeclaration("effect/Effect", [
|
|
{
|
|
type: "ImportNamespaceSpecifier",
|
|
local: { name: "Effect" }
|
|
}
|
|
])
|
|
const errors = runRule(rule, "ImportDeclaration", node, testOptions)
|
|
expect(errors).toHaveLength(0)
|
|
})
|
|
|
|
it("should not report for default imports", () => {
|
|
const node = createImportDeclaration("effect", [
|
|
{
|
|
type: "ImportDefaultSpecifier",
|
|
local: { name: "Effect" }
|
|
}
|
|
])
|
|
const errors = runRule(rule, "ImportDeclaration", node, testOptions)
|
|
expect(errors).toHaveLength(0)
|
|
})
|
|
|
|
describe("configuration", () => {
|
|
it("should match regex patterns", () => {
|
|
const node = createImportDeclaration("@myorg/utils", [
|
|
createNamedSpecifier("helper")
|
|
])
|
|
// No patterns configured - doesn't match
|
|
const defaultErrors = runRule(rule, "ImportDeclaration", node, testOptions)
|
|
expect(defaultErrors).toHaveLength(0)
|
|
|
|
// Pattern matches @myorg/*
|
|
const customErrors = runRule(rule, "ImportDeclaration", node, {
|
|
...testOptions,
|
|
ruleOptions: [{ checkPatterns: ["^@myorg/"] }]
|
|
})
|
|
expect(customErrors).toHaveLength(1)
|
|
})
|
|
|
|
it("should match exact package with pattern", () => {
|
|
const node = createImportDeclaration("lodash", [
|
|
createNamedSpecifier("map")
|
|
])
|
|
// No patterns - doesn't match
|
|
const defaultErrors = runRule(rule, "ImportDeclaration", node, testOptions)
|
|
expect(defaultErrors).toHaveLength(0)
|
|
|
|
// Exact match pattern
|
|
const customErrors = runRule(rule, "ImportDeclaration", node, {
|
|
...testOptions,
|
|
ruleOptions: [{ checkPatterns: ["^lodash$"] }]
|
|
})
|
|
expect(customErrors).toHaveLength(1)
|
|
})
|
|
|
|
it("should disable relative index checking when configured", () => {
|
|
const node = createImportDeclaration("./index.ts", [
|
|
createNamedSpecifier("foo")
|
|
])
|
|
// Default checks relative imports
|
|
const defaultErrors = runRule(rule, "ImportDeclaration", node, testOptions)
|
|
expect(defaultErrors).toHaveLength(1)
|
|
|
|
// Disabled relative checking
|
|
const customErrors = runRule(rule, "ImportDeclaration", node, {
|
|
...testOptions,
|
|
ruleOptions: [{ checkRelativeIndexImports: false }]
|
|
})
|
|
expect(customErrors).toHaveLength(0)
|
|
})
|
|
})
|
|
})
|