From f5483d2a06abe58dbaba539a0264b33cd0b577eb Mon Sep 17 00:00:00 2001 From: Sergei Startsev Date: Fri, 18 Jan 2019 19:28:49 +0300 Subject: [PATCH] Fix #1259 for `no-unresolved`, add `caseSensitiveStrict` option --- docs/rules/no-unresolved.md | 16 ++++++++++++++++ src/rules/no-unresolved.js | 10 ++++++---- tests/src/core/resolve.js | 15 ++++++++++++--- tests/src/rules/no-unresolved.js | 17 ++++++++++++++++- utils/resolve.js | 6 +++--- 5 files changed, 53 insertions(+), 11 deletions(-) diff --git a/docs/rules/no-unresolved.md b/docs/rules/no-unresolved.md index 30cd8cb2b8..187205e75d 100644 --- a/docs/rules/no-unresolved.md +++ b/docs/rules/no-unresolved.md @@ -76,6 +76,22 @@ By default, this rule will report paths whose case do not match the underlying f const { default: x } = require('./foo') // reported if './foo' is actually './Foo' and caseSensitive: true ``` +#### `caseSensitiveStrict` + +`caseSensitive` option does not detect case for current working derectory, `caseSensitiveStrict` option allows to check `cwd` in resolved path. By default, the options is disabled. + + +```js +/*eslint import/no-unresolved: [2, { caseSensitiveStrict: true }]*/ + +// Absolute paths +import Foo from `/Users/fOo/bar/file.js` // reported, /Users/foo/bar/file.js +import Foo from `d:/fOo/bar/file.js` // reported, d:/foo/bar/file.js + +// Relative paths, cwd is Users/foo/ +import Foo from `./../fOo/bar/file.js` // reported +``` + ## When Not To Use It If you're using a module bundler other than Node or Webpack, you may end up with diff --git a/src/rules/no-unresolved.js b/src/rules/no-unresolved.js index 8436e4c92b..7145636103 100644 --- a/src/rules/no-unresolved.js +++ b/src/rules/no-unresolved.js @@ -17,14 +17,16 @@ module.exports = { schema: [ makeOptionsSchema({ caseSensitive: { type: 'boolean', default: true }, + caseSensitiveStrict: { type: 'boolean', default: false }, })], }, create: function (context) { + const options = context.options[0] || {} function checkSourceValue(source) { - const shouldCheckCase = !CASE_SENSITIVE_FS && - (!context.options[0] || context.options[0].caseSensitive !== false) + const shouldCheckCase = !CASE_SENSITIVE_FS && options.caseSensitive !== false + const caseSensitiveStrict = !CASE_SENSITIVE_FS && options.caseSensitiveStrict const resolvedPath = resolve(source.value, context) @@ -35,7 +37,7 @@ module.exports = { else if (shouldCheckCase) { const cacheSettings = ModuleCache.getSettings(context.settings) - if (!fileExistsWithCaseSync(resolvedPath, cacheSettings)) { + if (!fileExistsWithCaseSync(resolvedPath, cacheSettings, caseSensitiveStrict)) { context.report(source, `Casing of ${source.value} does not match the underlying filesystem.`) } @@ -43,7 +45,7 @@ module.exports = { } } - return moduleVisitor(checkSourceValue, context.options[0]) + return moduleVisitor(checkSourceValue, options) }, } diff --git a/tests/src/core/resolve.js b/tests/src/core/resolve.js index b9a9063243..b4f9a97fdf 100644 --- a/tests/src/core/resolve.js +++ b/tests/src/core/resolve.js @@ -152,7 +152,11 @@ describe('resolve', function () { const caseDescribe = (!CASE_SENSITIVE_FS ? describe : describe.skip) caseDescribe('case sensitivity', function () { let file - const testContext = utils.testContext({ 'import/resolve': { 'extensions': ['.jsx'] }}) + const testContext = utils.testContext({ + 'import/resolve': { 'extensions': ['.jsx'] }, + 'import/cache': { lifetime: 0 }, + }) + const testSettings = testContext.settings before('resolve', function () { file = resolve( // Note the case difference 'MyUncoolComponent' vs 'MyUnCoolComponent' @@ -162,14 +166,19 @@ describe('resolve', function () { expect(file, 'path to ./jsx/MyUncoolComponent').to.exist }) it('detects case does not match FS', function () { - expect(fileExistsWithCaseSync(file, ModuleCache.getSettings(testContext))) + expect(fileExistsWithCaseSync(file, testSettings)) .to.be.false }) it('detecting case does not include parent folder path (issue #720)', function () { const f = path.join(process.cwd().toUpperCase(), './tests/files/jsx/MyUnCoolComponent.jsx') - expect(fileExistsWithCaseSync(f, ModuleCache.getSettings(testContext), true)) + expect(fileExistsWithCaseSync(f, testSettings)) .to.be.true }) + it('detecting case should include parent folder path', function () { + const f = path.join(process.cwd().toUpperCase(), './tests/files/jsx/MyUnCoolComponent.jsx') + expect(fileExistsWithCaseSync(f, testSettings, true)) + .to.be.false + }) }) describe('rename cache correctness', function () { diff --git a/tests/src/rules/no-unresolved.js b/tests/src/rules/no-unresolved.js index 5b4f6ae53c..a8a6a7e354 100644 --- a/tests/src/rules/no-unresolved.js +++ b/tests/src/rules/no-unresolved.js @@ -15,7 +15,7 @@ function runResolverTests(resolver) { function rest(specs) { specs.settings = Object.assign({}, specs.settings, - { 'import/resolver': resolver } + { 'import/resolver': resolver, 'import/cache': { lifetime: 0 } } ) return test(specs) @@ -203,12 +203,21 @@ function runResolverTests(resolver) { }) if (!CASE_SENSITIVE_FS) { + const relativePath = './tests/files/jsx/MyUnCoolComponent.jsx' + const cwd = process.cwd() + const mismatchedPath = path.join(cwd.toUpperCase(), relativePath).replace(/\\/g, '/') + ruleTester.run('case sensitivity', rule, { valid: [ rest({ // test with explicit flag code: 'import foo from "./jsx/MyUncoolComponent.jsx"', options: [{ caseSensitive: false }], }), + // #1259 issue + rest({ // test with explicit flag + code: `import foo from "${mismatchedPath}"`, + options: [{ caseSensitive: true }], + }), ], invalid: [ @@ -221,6 +230,12 @@ function runResolverTests(resolver) { options: [{ caseSensitive: true }], errors: [`Casing of ./jsx/MyUncoolComponent.jsx does not match the underlying filesystem.`], }), + // #1259 issue + rest({ // test with explicit flag + code: `import foo from "${mismatchedPath}"`, + options: [{ caseSensitiveStrict: true }], + errors: [`Casing of ${mismatchedPath} does not match the underlying filesystem.`], + }), ], }) } diff --git a/utils/resolve.js b/utils/resolve.js index 87a1eaea81..7e63d42b09 100644 --- a/utils/resolve.js +++ b/utils/resolve.js @@ -29,13 +29,13 @@ function tryRequire(target) { } // http://stackoverflow.com/a/27382838 -exports.fileExistsWithCaseSync = function fileExistsWithCaseSync(filepath, cacheSettings) { +exports.fileExistsWithCaseSync = function fileExistsWithCaseSync(filepath, cacheSettings, strict) { // don't care if the FS is case-sensitive if (CASE_SENSITIVE_FS) return true // null means it resolved to a builtin if (filepath === null) return true - if (filepath.toLowerCase() === process.cwd().toLowerCase()) return true + if (filepath.toLowerCase() === process.cwd().toLowerCase() && !strict) return true const parsedPath = path.parse(filepath) , dir = parsedPath.dir @@ -50,7 +50,7 @@ exports.fileExistsWithCaseSync = function fileExistsWithCaseSync(filepath, cache if (filenames.indexOf(parsedPath.base) === -1) { result = false } else { - result = fileExistsWithCaseSync(dir, cacheSettings) + result = fileExistsWithCaseSync(dir, cacheSettings, strict) } } fileExistsCache.set(filepath, result)