diff --git a/.changeset/quick-hats-roll.md b/.changeset/quick-hats-roll.md new file mode 100644 index 000000000..7f4789cf3 --- /dev/null +++ b/.changeset/quick-hats-roll.md @@ -0,0 +1,5 @@ +--- +"eslint-plugin-import-x": minor +--- + +Improve windows support diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..6313b56c5 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=lf diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 11bd9b54f..b47772907 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ jobs: os: - macos-latest - ubuntu-latest - # - windows-latest + - windows-latest node: - 18 - 20 diff --git a/src/rules/no-extraneous-dependencies.ts b/src/rules/no-extraneous-dependencies.ts index fff4459bf..5124d3b08 100644 --- a/src/rules/no-extraneous-dependencies.ts +++ b/src/rules/no-extraneous-dependencies.ts @@ -335,7 +335,9 @@ function testConfig(config: string[] | boolean | undefined, filename: string) { } // Array of globs. return config.some( - c => minimatch(filename, c) || minimatch(filename, path.resolve(c)), + c => + minimatch(filename, c) || + minimatch(filename, path.resolve(c), { windowsPathsNoEscape: true }), ) } diff --git a/src/rules/no-restricted-paths.ts b/src/rules/no-restricted-paths.ts index d37cca3c6..aa810b2f6 100644 --- a/src/rules/no-restricted-paths.ts +++ b/src/rules/no-restricted-paths.ts @@ -14,7 +14,7 @@ const containsPath = (filepath: string, target: string) => { function isMatchingTargetPath(filename: string, targetPath: string) { if (isGlob(targetPath)) { - const mm = new Minimatch(targetPath) + const mm = new Minimatch(targetPath, { windowsPathsNoEscape: true }) return mm.match(filename) } @@ -171,13 +171,15 @@ export = createRule<[Options?], MessageId>({ ) { let isPathException: ((absoluteImportPath: string) => boolean) | undefined - const mm = new Minimatch(absoluteFrom) + const mm = new Minimatch(absoluteFrom, { windowsPathsNoEscape: true }) const isPathRestricted = (absoluteImportPath: string) => mm.match(absoluteImportPath) const hasValidExceptions = zoneExcept.every(it => isGlob(it)) if (hasValidExceptions) { - const exceptionsMm = zoneExcept.map(except => new Minimatch(except)) + const exceptionsMm = zoneExcept.map( + except => new Minimatch(except, { windowsPathsNoEscape: true }), + ) isPathException = (absoluteImportPath: string) => exceptionsMm.some(mm => mm.match(absoluteImportPath)) } diff --git a/src/rules/no-unassigned-import.ts b/src/rules/no-unassigned-import.ts index 71157ac98..02d3be51d 100644 --- a/src/rules/no-unassigned-import.ts +++ b/src/rules/no-unassigned-import.ts @@ -15,13 +15,14 @@ function testIsAllow( const filePath = // a node module - source[0] !== '.' && source[0] !== '/' + source[0] !== '.' && source[0] !== path.sep ? source : path.resolve(path.dirname(filename), source) // get source absolute path return globs.some( glob => - minimatch(filePath, glob) || minimatch(filePath, path.resolve(glob)), + minimatch(filePath, glob) || + minimatch(filePath, path.resolve(glob), { windowsPathsNoEscape: true }), ) } diff --git a/test/fixtures/node_modules/eslint-import-resolver-foo-v1/index.js b/test/fixtures/node_modules/eslint-import-resolver-foo-v1/index.js deleted file mode 120000 index 867bba70f..000000000 --- a/test/fixtures/node_modules/eslint-import-resolver-foo-v1/index.js +++ /dev/null @@ -1 +0,0 @@ -../../foo-bar-resolver-v1.js \ No newline at end of file diff --git a/test/fixtures/node_modules/eslint-import-resolver-foo-v1/index.js b/test/fixtures/node_modules/eslint-import-resolver-foo-v1/index.js new file mode 100644 index 000000000..2fb163cca --- /dev/null +++ b/test/fixtures/node_modules/eslint-import-resolver-foo-v1/index.js @@ -0,0 +1 @@ +module.exports = require('../../foo-bar-resolver-v1') diff --git a/test/fixtures/node_modules/eslint-import-resolver-foo-v2/index.js b/test/fixtures/node_modules/eslint-import-resolver-foo-v2/index.js deleted file mode 120000 index d194dba0d..000000000 --- a/test/fixtures/node_modules/eslint-import-resolver-foo-v2/index.js +++ /dev/null @@ -1 +0,0 @@ -../../foo-bar-resolver-v2.js \ No newline at end of file diff --git a/test/fixtures/node_modules/eslint-import-resolver-foo-v2/index.js b/test/fixtures/node_modules/eslint-import-resolver-foo-v2/index.js new file mode 100644 index 000000000..07cdc7dec --- /dev/null +++ b/test/fixtures/node_modules/eslint-import-resolver-foo-v2/index.js @@ -0,0 +1 @@ +module.exports = require('../../foo-bar-resolver-v2') diff --git a/test/rules/no-absolute-path.spec.ts b/test/rules/no-absolute-path.spec.ts index 9bb7449fe..2ff8edf9b 100644 --- a/test/rules/no-absolute-path.spec.ts +++ b/test/rules/no-absolute-path.spec.ts @@ -1,5 +1,3 @@ -import path from 'node:path' - import { RuleTester as TSESLintRuleTester } from '@typescript-eslint/rule-tester' import type { TestCaseError as TSESLintTestCaseError } from '@typescript-eslint/rule-tester' @@ -18,8 +16,6 @@ const ABSOLUTE_ERROR: TSESLintTestCaseError< messageId: 'absolute', } -const absolutePath = (testPath: string) => path.join(__dirname, testPath) - ruleTester.run('no-absolute-path', rule, { valid: [ tValid({ code: 'import _ from "lodash"' }), @@ -66,72 +62,72 @@ ruleTester.run('no-absolute-path', rule, { ], invalid: [ tInvalid({ - code: `import f from "${absolutePath('/foo')}"`, - filename: absolutePath('/foo/bar/index.js'), + code: `import f from "/foo"`, + filename: '/foo/bar/index.js', errors: [ABSOLUTE_ERROR], output: 'import f from ".."', }), tInvalid({ - code: `import f from "${absolutePath('/foo/bar/baz.js')}"`, - filename: absolutePath('/foo/bar/index.js'), + code: `import f from "/foo/bar/baz.js"`, + filename: '/foo/bar/index.js', errors: [ABSOLUTE_ERROR], output: 'import f from "./baz.js"', }), tInvalid({ - code: `import f from "${absolutePath('/foo/path')}"`, - filename: absolutePath('/foo/bar/index.js'), + code: `import f from "/foo/path"`, + filename: '/foo/bar/index.js', errors: [ABSOLUTE_ERROR], output: 'import f from "../path"', }), tInvalid({ - code: `import f from "${absolutePath('/some/path')}"`, - filename: absolutePath('/foo/bar/index.js'), + code: `import f from "/some/path"`, + filename: '/foo/bar/index.js', errors: [ABSOLUTE_ERROR], output: 'import f from "../../some/path"', }), tInvalid({ - code: `import f from "${absolutePath('/some/path')}"`, - filename: absolutePath('/foo/bar/index.js'), + code: `import f from "/some/path"`, + filename: '/foo/bar/index.js', options: [{ amd: true }], errors: [ABSOLUTE_ERROR], output: 'import f from "../../some/path"', }), tInvalid({ - code: `var f = require("${absolutePath('/foo')}")`, - filename: absolutePath('/foo/bar/index.js'), + code: `var f = require("/foo")`, + filename: '/foo/bar/index.js', errors: [ABSOLUTE_ERROR], output: 'var f = require("..")', }), tInvalid({ - code: `var f = require("${absolutePath('/foo/path')}")`, - filename: absolutePath('/foo/bar/index.js'), + code: `var f = require("/foo/path")`, + filename: '/foo/bar/index.js', errors: [ABSOLUTE_ERROR], output: 'var f = require("../path")', }), tInvalid({ - code: `var f = require("${absolutePath('/some/path')}")`, - filename: absolutePath('/foo/bar/index.js'), + code: `var f = require("/some/path")`, + filename: '/foo/bar/index.js', errors: [ABSOLUTE_ERROR], output: 'var f = require("../../some/path")', }), tInvalid({ - code: `var f = require("${absolutePath('/some/path')}")`, - filename: absolutePath('/foo/bar/index.js'), + code: `var f = require("/some/path")`, + filename: '/foo/bar/index.js', options: [{ amd: true }], errors: [ABSOLUTE_ERROR], output: 'var f = require("../../some/path")', }), // validate amd tInvalid({ - code: `require(["${absolutePath('/some/path')}"], function (f) { /* ... */ })`, - filename: absolutePath('/foo/bar/index.js'), + code: `require(["/some/path"], function (f) { /* ... */ })`, + filename: '/foo/bar/index.js', options: [{ amd: true }], errors: [ABSOLUTE_ERROR], output: 'require(["../../some/path"], function (f) { /* ... */ })', }), tInvalid({ - code: `define(["${absolutePath('/some/path')}"], function (f) { /* ... */ })`, - filename: absolutePath('/foo/bar/index.js'), + code: `define(["/some/path"], function (f) { /* ... */ })`, + filename: '/foo/bar/index.js', languageOptions: { parser: require(parsers.ESPREE) }, options: [{ amd: true }], errors: [ABSOLUTE_ERROR],