Skip to content

Commit

Permalink
Fix import-js#1259 for no-unresolved, add caseSensitiveStrict option
Browse files Browse the repository at this point in the history
  • Loading branch information
sergei-startsev committed Jan 22, 2019
1 parent 767f01a commit fca6308
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 11 deletions.
16 changes: 16 additions & 0 deletions docs/rules/no-unresolved.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 6 additions & 4 deletions src/rules/no-unresolved.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -35,15 +37,15 @@ 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.`)
}

}
}

return moduleVisitor(checkSourceValue, context.options[0])
return moduleVisitor(checkSourceValue, options)

},
}
15 changes: 12 additions & 3 deletions tests/src/core/resolve.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -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 () {
Expand Down
17 changes: 16 additions & 1 deletion tests/src/rules/no-unresolved.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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: [
Expand All @@ -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.`],
}),
],
})
}
Expand Down
6 changes: 3 additions & 3 deletions utils/resolve.js
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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)
Expand Down

0 comments on commit fca6308

Please sign in to comment.