diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e103387d..4c561e723 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). This change log adheres to standards from [Keep a CHANGELOG](http://keepachangelog.com). ## [Unreleased] - +### Added +- Add `filePath` into `parserOptions` passed to `parser` ([#839], thanks [@sompylasar]) ## [2.5.0] - 2017-06-22 @@ -152,8 +153,7 @@ Yanked due to critical issue in eslint-module-utils with cache key resulting fro - Something horrible happened during `npm prepublish` of 1.10.1. Several `rm -rf node_modules && npm i` and `gulp clean && npm prepublish`s later, it is rebuilt and republished as 1.10.2. Thanks [@rhettlivingston] for noticing and reporting! -## [1.10.1] - 2016-07-02 [ -ED] +## [1.10.1] - 2016-07-02 [YANKED] ### Added - Officially support ESLint 3.x. (peerDependencies updated to `2.x - 3.x`) diff --git a/tests/files/foo-bar-resolver-no-version.js b/tests/files/foo-bar-resolver-no-version.js new file mode 100644 index 000000000..89d4eb13e --- /dev/null +++ b/tests/files/foo-bar-resolver-no-version.js @@ -0,0 +1,14 @@ +var path = require('path') + +exports.resolveImport = function (modulePath, sourceFile, config) { + var sourceFileName = path.basename(sourceFile) + if (sourceFileName === 'foo.js') { + return path.join(__dirname, 'bar.jsx') + } + else if (sourceFileName === 'exception.js') { + throw new Error('foo-bar-resolver-v1 resolveImport test exception') + } + else { + return undefined + } +} diff --git a/tests/files/foo-bar-resolver-v1.js b/tests/files/foo-bar-resolver-v1.js new file mode 100644 index 000000000..8aafe7aa4 --- /dev/null +++ b/tests/files/foo-bar-resolver-v1.js @@ -0,0 +1,16 @@ +var path = require('path') + +exports.resolveImport = function (modulePath, sourceFile, config) { + var sourceFileName = path.basename(sourceFile) + if (sourceFileName === 'foo.js') { + return path.join(__dirname, 'bar.jsx') + } + else if (sourceFileName === 'exception.js') { + throw new Error('foo-bar-resolver-v1 resolveImport test exception') + } + else { + return undefined + } +} + +exports.interfaceVersion = 1 diff --git a/tests/files/foo-bar-resolver-v2.js b/tests/files/foo-bar-resolver-v2.js new file mode 100644 index 000000000..9bb68171b --- /dev/null +++ b/tests/files/foo-bar-resolver-v2.js @@ -0,0 +1,16 @@ +var path = require('path') + +exports.resolve = function (modulePath, sourceFile, config) { + var sourceFileName = path.basename(sourceFile) + if (sourceFileName === 'foo.js') { + return { found: true, path: path.join(__dirname, 'bar.jsx') } + } + else if (sourceFileName === 'exception.js') { + throw new Error('foo-bar-resolver-v2 resolve test exception') + } + else { + return { found: false } + } +} + +exports.interfaceVersion = 2 diff --git a/tests/files/foo-bar-resolver.js b/tests/files/foo-bar-resolver.js deleted file mode 100644 index 92421ba26..000000000 --- a/tests/files/foo-bar-resolver.js +++ /dev/null @@ -1,7 +0,0 @@ -var path = require('path'); - -exports.resolve = function(source, file) { - return { found: true, path: path.join(__dirname, 'bar.jsx') }; -}; - -exports.interfaceVersion = 2; diff --git a/tests/files/ignore.invalid.extension b/tests/files/ignore.invalid.extension new file mode 100644 index 000000000..e69de29bb diff --git a/tests/src/core/getExports.js b/tests/src/core/getExports.js index 62513d442..c3da17fe7 100644 --- a/tests/src/core/getExports.js +++ b/tests/src/core/getExports.js @@ -13,7 +13,7 @@ describe('ExportMap', function () { parserPath: 'babel-eslint', } - it('should handle ExportAllDeclaration', function () { + it('handles ExportAllDeclaration', function () { var imports expect(function () { imports = ExportMap.get('./export-all', fakeContext) @@ -24,12 +24,12 @@ describe('ExportMap', function () { }) - it('should return a cached copy on subsequent requests', function () { + it('returns a cached copy on subsequent requests', function () { expect(ExportMap.get('./named-exports', fakeContext)) .to.exist.and.equal(ExportMap.get('./named-exports', fakeContext)) }) - it('should not return a cached copy after modification', (done) => { + it('does not return a cached copy after modification', (done) => { const firstAccess = ExportMap.get('./mutator', fakeContext) expect(firstAccess).to.exist @@ -42,7 +42,7 @@ describe('ExportMap', function () { }) }) - it('should not return a cached copy with different settings', () => { + it('does not return a cached copy with different settings', () => { const firstAccess = ExportMap.get('./named-exports', fakeContext) expect(firstAccess).to.exist @@ -56,7 +56,7 @@ describe('ExportMap', function () { .not.to.equal(firstAccess) }) - it('should not throw for a missing file', function () { + it('does not throw for a missing file', function () { var imports expect(function () { imports = ExportMap.get('./does-not-exist', fakeContext) @@ -66,7 +66,7 @@ describe('ExportMap', function () { }) - it('should export explicit names for a missing file in exports', function () { + it('exports explicit names for a missing file in exports', function () { var imports expect(function () { imports = ExportMap.get('./exports-missing', fakeContext) diff --git a/tests/src/core/hash.js b/tests/src/core/hash.js new file mode 100644 index 000000000..f8dd4b49a --- /dev/null +++ b/tests/src/core/hash.js @@ -0,0 +1,76 @@ +import { expect } from 'chai' + +import hashify, { hashArray, hashObject } from 'eslint-module-utils/hash' + +const createHash = require('crypto').createHash + +function expectHash(actualHash, expectedString) { + const expectedHash = createHash('sha256') + expectedHash.update(expectedString) + expect(actualHash.digest('hex'), 'to be a hex digest of sha256 hash of string <' + expectedString + '>').to.equal(expectedHash.digest('hex')) +} + +describe('hash', function () { + describe('hashify', function () { + it('handles null', function () { + expectHash(hashify(null), 'null') + }) + + it('handles undefined', function () { + expectHash(hashify(undefined), 'undefined') + }) + + it('handles numbers', function () { + expectHash(hashify(123.456), '123.456') + }) + + it('handles strings', function () { + expectHash(hashify('a string'), '"a string"') + }) + + it('handles Array instances', function () { + expectHash(hashify([ 'a string' ]), '["a string",]') + }) + + it('handles empty Array instances', function () { + expectHash(hashify([]), '[]') + }) + + it('handles Object instances', function () { + expectHash(hashify({ foo: 123.456, 'a key': 'a value' }), '{"a key":"a value","foo":123.456,}') + }) + + it('handles nested Object instances', function () { + expectHash(hashify({ foo: 123.456, 'a key': 'a value', obj: { abc: { def: 'ghi' } } }), '{"a key":"a value","foo":123.456,"obj":{"abc":{"def":"ghi",},},}') + }) + + it('handles nested Object and Array instances', function () { + expectHash(hashify({ foo: 123.456, 'a key': 'a value', obj: { arr: [ { def: 'ghi' } ] } }), '{"a key":"a value","foo":123.456,"obj":{"arr":[{"def":"ghi",},],},}') + }) + }) + + describe('hashArray', function () { + it('handles Array instances', function () { + expectHash(hashArray([ 'a string' ]), '["a string",]') + }) + + it('handles empty Array instances', function () { + expectHash(hashArray([]), '[]') + }) + }) + + describe('hashObject', function () { + it('handles Object instances', function () { + expectHash(hashObject({ foo: 123.456, 'a key': 'a value' }), '{"a key":"a value","foo":123.456,}') + }) + + it('handles nested Object instances', function () { + expectHash(hashObject({ foo: 123.456, 'a key': 'a value', obj: { abc: { def: 'ghi' } } }), '{"a key":"a value","foo":123.456,"obj":{"abc":{"def":"ghi",},},}') + }) + + it('handles nested Object and Array instances', function () { + expectHash(hashObject({ foo: 123.456, 'a key': 'a value', obj: { arr: [ { def: 'ghi' } ] } }), '{"a key":"a value","foo":123.456,"obj":{"arr":[{"def":"ghi",},],},}') + }) + }) + +}) diff --git a/tests/src/core/ignore.js b/tests/src/core/ignore.js new file mode 100644 index 000000000..cc89f8454 --- /dev/null +++ b/tests/src/core/ignore.js @@ -0,0 +1,58 @@ +import { expect } from 'chai' + +import isIgnored, { hasValidExtension } from 'eslint-module-utils/ignore' + +import * as utils from '../utils' + +describe('ignore', function () { + describe('isIgnored', function () { + it('ignores paths with extensions other than .js', function () { + const testContext = utils.testContext({}) + + expect(isIgnored('../files/foo.js', testContext)).to.equal(false) + + expect(isIgnored('../files/bar.jsx', testContext)).to.equal(true) + + expect(isIgnored('../files/typescript.ts', testContext)).to.equal(true) + + expect(isIgnored('../files/ignore.invalid.extension', testContext)).to.equal(true) + }) + + it('ignores paths with invalid extensions when configured with import/extensions', function () { + const testContext = utils.testContext({ 'import/extensions': [ '.js', '.jsx', '.ts' ] }) + + expect(isIgnored('../files/foo.js', testContext)).to.equal(false) + + expect(isIgnored('../files/bar.jsx', testContext)).to.equal(false) + + expect(isIgnored('../files/typescript.ts', testContext)).to.equal(false) + + expect(isIgnored('../files/ignore.invalid.extension', testContext)).to.equal(true) + }) + }) + + describe('hasValidExtension', function () { + it('assumes only .js as valid by default', function () { + const testContext = utils.testContext({}) + + expect(hasValidExtension('../files/foo.js', testContext)).to.equal(true) + + expect(hasValidExtension('../files/foo.jsx', testContext)).to.equal(false) + + expect(hasValidExtension('../files/foo.css', testContext)).to.equal(false) + + expect(hasValidExtension('../files/foo.invalid.extension', testContext)).to.equal(false) + }) + + it('can be configured with import/extensions', function () { + const testContext = utils.testContext({ 'import/extensions': [ '.foo', '.bar' ] }) + + expect(hasValidExtension('../files/foo.foo', testContext)).to.equal(true) + + expect(hasValidExtension('../files/foo.bar', testContext)).to.equal(true) + + expect(hasValidExtension('../files/foo.js', testContext)).to.equal(false) + }) + }) + +}) diff --git a/tests/src/core/parse.js b/tests/src/core/parse.js index 2feea07ae..9cc153ae3 100644 --- a/tests/src/core/parse.js +++ b/tests/src/core/parse.js @@ -41,15 +41,15 @@ describe('parse(content, { settings, ecmaFeatures })', function () { expect(parseSpy.args[0][1], 'custom parser to get parserOptions.filePath equal to the full path of the source file').to.have.property('filePath', path) }) - it('should throw on context == null', function () { + it('throws on context == null', function () { expect(parse.bind(null, path, content, null)).to.throw(Error) }) - it('should throw on unable to resolve parserPath', function () { + it('throws on unable to resolve parserPath', function () { expect(parse.bind(null, path, content, { settings: {}, parserPath: null })).to.throw(Error) }) - it('should take the alternate parser specified in settings', function () { + it('takes the alternate parser specified in settings', function () { const parseSpy = sinon.spy() const parserOptions = { ecmaFeatures: { jsx: true } } parseStubParser.parse = parseSpy diff --git a/tests/src/core/resolve.js b/tests/src/core/resolve.js index e8f255f34..bfff7935c 100644 --- a/tests/src/core/resolve.js +++ b/tests/src/core/resolve.js @@ -7,24 +7,114 @@ import * as fs from 'fs' import * as utils from '../utils' describe('resolve', function () { - it('should throw on bad parameters.', function () { + it('throws on bad parameters', function () { expect(resolve.bind(null, null, null)).to.throw(Error) }) - it('loads a custom resolver path', function () { - var file = resolve( '../files/foo' - , utils.testContext({ 'import/resolver': './foo-bar-resolver'}) - ) + it('resolves via a custom resolver with interface version 1', function () { + const testContext = utils.testContext({ 'import/resolver': './foo-bar-resolver-v1' }) - expect(file).to.equal(utils.testFilePath('./bar.jsx')) + expect(resolve( '../files/foo' + , Object.assign({}, testContext, { getFilename: function () { return utils.getFilename('foo.js') } }) + )).to.equal(utils.testFilePath('./bar.jsx')) + + expect(resolve( '../files/exception' + , Object.assign({}, testContext, { getFilename: function () { return utils.getFilename('exception.js') } }) + )).to.equal(undefined) + + expect(resolve( '../files/not-found' + , Object.assign({}, testContext, { getFilename: function () { return utils.getFilename('not-found.js') } }) + )).to.equal(undefined) + }) + + it('resolves via a custom resolver with interface version 1 assumed if not specified', function () { + const testContext = utils.testContext({ 'import/resolver': './foo-bar-resolver-no-version' }) + + expect(resolve( '../files/foo' + , Object.assign({}, testContext, { getFilename: function () { return utils.getFilename('foo.js') } }) + )).to.equal(utils.testFilePath('./bar.jsx')) + + expect(resolve( '../files/exception' + , Object.assign({}, testContext, { getFilename: function () { return utils.getFilename('exception.js') } }) + )).to.equal(undefined) + + expect(resolve( '../files/not-found' + , Object.assign({}, testContext, { getFilename: function () { return utils.getFilename('not-found.js') } }) + )).to.equal(undefined) + }) + + it('resolves via a custom resolver with interface version 2', function () { + const testContext = utils.testContext({ 'import/resolver': './foo-bar-resolver-v2' }) + const testContextReports = [] + testContext.report = function (reportInfo) { + testContextReports.push(reportInfo) + } + + expect(resolve( '../files/foo' + , Object.assign({}, testContext, { getFilename: function () { return utils.getFilename('foo.js') } }) + )).to.equal(utils.testFilePath('./bar.jsx')) + + testContextReports.length = 0 + expect(resolve( '../files/exception' + , Object.assign({}, testContext, { getFilename: function () { return utils.getFilename('exception.js') } }) + )).to.equal(undefined) + expect(testContextReports[0]).to.be.an('object') + expect(testContextReports[0].message).to.equal('Resolve error: foo-bar-resolver-v2 resolve test exception') + expect(testContextReports[0].loc).to.eql({ line: 1, column: 0 }) + + testContextReports.length = 0 + expect(resolve( '../files/not-found' + , Object.assign({}, testContext, { getFilename: function () { return utils.getFilename('not-found.js') } }) + )).to.equal(undefined) + expect(testContextReports.length).to.equal(0) + }) + + it('respects import/resolver as array of strings', function () { + const testContext = utils.testContext({ 'import/resolver': [ './foo-bar-resolver-v2', './foo-bar-resolver-v1' ] }) + + expect(resolve( '../files/foo' + , Object.assign({}, testContext, { getFilename: function () { return utils.getFilename('foo.js') } }) + )).to.equal(utils.testFilePath('./bar.jsx')) + }) + + it('respects import/resolver as object', function () { + const testContext = utils.testContext({ 'import/resolver': { './foo-bar-resolver-v2': {} } }) + + expect(resolve( '../files/foo' + , Object.assign({}, testContext, { getFilename: function () { return utils.getFilename('foo.js') } }) + )).to.equal(utils.testFilePath('./bar.jsx')) + }) + + it('respects import/resolver as array of objects', function () { + const testContext = utils.testContext({ 'import/resolver': [ { './foo-bar-resolver-v2': {} }, { './foo-bar-resolver-v1': {} } ] }) + + expect(resolve( '../files/foo' + , Object.assign({}, testContext, { getFilename: function () { return utils.getFilename('foo.js') } }) + )).to.equal(utils.testFilePath('./bar.jsx')) + }) + + it('reports invalid import/resolver config', function () { + const testContext = utils.testContext({ 'import/resolver': 123.456 }) + const testContextReports = [] + testContext.report = function (reportInfo) { + testContextReports.push(reportInfo) + } + + testContextReports.length = 0 + expect(resolve( '../files/foo' + , Object.assign({}, testContext, { getFilename: function () { return utils.getFilename('foo.js') } }) + )).to.equal(undefined) + expect(testContextReports[0]).to.be.an('object') + expect(testContextReports[0].message).to.equal('Resolve error: invalid resolver config') + expect(testContextReports[0].loc).to.eql({ line: 1, column: 0 }) }) it('respects import/resolve extensions', function () { - var file = resolve( './jsx/MyCoolComponent' - , utils.testContext({ 'import/resolve': { 'extensions': ['.jsx'] }}) - ) + const testContext = utils.testContext({ 'import/resolve': { 'extensions': ['.jsx'] }}) - expect(file).to.equal(utils.testFilePath('./jsx/MyCoolComponent.jsx')) + expect(resolve( './jsx/MyCoolComponent' + , testContext + )).to.equal(utils.testFilePath('./jsx/MyCoolComponent.jsx')) }) const caseDescribe = (!CASE_SENSITIVE_FS ? describe : describe.skip) diff --git a/tests/src/utils.js b/tests/src/utils.js index 144ae5498..7a13ed432 100644 --- a/tests/src/utils.js +++ b/tests/src/utils.js @@ -87,4 +87,10 @@ export const SYNTAX_CASES = [ test({ code: 'import * as a from "./commonjs-namespace/a"; a.b', }), - ] + + // ignore invalid extensions + test({ + code: 'import { foo } from "./ignore.invalid.extension"', + }), + +]