From b01e27c6773c947b390a2f62bf1ff796e4866b65 Mon Sep 17 00:00:00 2001 From: Leonid Nikiforenko Date: Sat, 7 May 2016 07:05:14 +0300 Subject: [PATCH 01/29] Add ability to use resolvers with custom paths --- src/core/resolve.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/core/resolve.js b/src/core/resolve.js index 9479bd553b..5afd795d7e 100644 --- a/src/core/resolve.js +++ b/src/core/resolve.js @@ -145,7 +145,18 @@ function resolverReducer(resolvers, map) { function requireResolver(name) { try { - return require(`eslint-import-resolver-${name}`) + // Try to resolve package with absolute path (/Volumes/....) + if (path.isAbsolute(name)) { + return require(path.resolve(name)); + } + + try { + // Try to resolve package with custom name (@myorg/resolver-name) + return require(name) + } catch (err) { + // Try to resolve package with conventional name + return require(`eslint-import-resolver-${name}`) + } } catch (err) { throw new Error(`unable to load resolver "${name}".`) } From 830e74fc871ff05277787720c7f1d7efeac054f5 Mon Sep 17 00:00:00 2001 From: Leonid Nikiforenko Date: Sat, 7 May 2016 07:20:42 +0300 Subject: [PATCH 02/29] Add ability to require resolver with relative path --- package.json | 1 + src/core/resolve.js | 20 ++++++++++++++------ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 009426ebe4..5069ea12d6 100644 --- a/package.json +++ b/package.json @@ -71,6 +71,7 @@ "es6-set": "^0.1.4", "es6-symbol": "*", "eslint-import-resolver-node": "^0.2.0", + "find-root": "^1.0.0", "lodash.cond": "^4.3.0", "lodash.endswith": "^4.0.1", "lodash.find": "^4.3.0", diff --git a/src/core/resolve.js b/src/core/resolve.js index 5afd795d7e..8f99debccb 100644 --- a/src/core/resolve.js +++ b/src/core/resolve.js @@ -2,6 +2,7 @@ import 'es6-symbol/implement' import Map from 'es6-map' import Set from 'es6-set' import assign from 'object-assign' +import findRoot from 'find-root'; import fs from 'fs' import { dirname, basename, join } from 'path' @@ -106,7 +107,7 @@ export function relative(modulePath, sourceFile, settings) { const resolvers = resolverReducer(configResolvers, new Map()) for (let [name, config] of resolvers) { - const resolver = requireResolver(name) + const resolver = requireResolver(name, modulePath) let { path: fullPath, found } = withResolver(resolver, config) @@ -143,7 +144,7 @@ function resolverReducer(resolvers, map) { throw new Error('invalid resolver config') } -function requireResolver(name) { +function requireResolver(name, modulePath) { try { // Try to resolve package with absolute path (/Volumes/....) if (path.isAbsolute(name)) { @@ -151,11 +152,18 @@ function requireResolver(name) { } try { - // Try to resolve package with custom name (@myorg/resolver-name) - return require(name) + // Try to resolve package with path, relative to closest package.json + const packageDir = findRoot(path.resolve(modulePath)); + + return require(path.join(packageDir, name)); } catch (err) { - // Try to resolve package with conventional name - return require(`eslint-import-resolver-${name}`) + try { + // Try to resolve package with custom name (@myorg/resolver-name) + return require(name); + } catch (err) { + // Try to resolve package with conventional name + return require(`eslint-import-resolver-${name}`) + } } } catch (err) { throw new Error(`unable to load resolver "${name}".`) From 5db4e1804284d40e6d78caaf472579f66e6b17f5 Mon Sep 17 00:00:00 2001 From: Leonid Nikiforenko Date: Sun, 8 May 2016 01:12:37 +0300 Subject: [PATCH 03/29] Require module with absolute path without resolving --- src/core/resolve.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/resolve.js b/src/core/resolve.js index 8f99debccb..a90a6812a5 100644 --- a/src/core/resolve.js +++ b/src/core/resolve.js @@ -147,8 +147,8 @@ function resolverReducer(resolvers, map) { function requireResolver(name, modulePath) { try { // Try to resolve package with absolute path (/Volumes/....) - if (path.isAbsolute(name)) { - return require(path.resolve(name)); + if (isAbsolute(name)) { + return require(name) } try { From fa2a5ef8c7c68fe3c0dad9dce3a737826ee7d9b1 Mon Sep 17 00:00:00 2001 From: Leonid Nikiforenko Date: Sun, 8 May 2016 01:13:21 +0300 Subject: [PATCH 04/29] Use correct names of variables --- src/core/resolve.js | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/core/resolve.js b/src/core/resolve.js index a90a6812a5..4acc9a19cb 100644 --- a/src/core/resolve.js +++ b/src/core/resolve.js @@ -2,10 +2,13 @@ import 'es6-symbol/implement' import Map from 'es6-map' import Set from 'es6-set' import assign from 'object-assign' -import findRoot from 'find-root'; +import findRoot from 'find-root' +import isAbsoluteFallback from 'is-absolute' import fs from 'fs' -import { dirname, basename, join } from 'path' +import { dirname, basename, join, isAbsolute as isAbsoluteNode } from 'path' + +const isAbsolute = isAbsoluteNode || isAbsoluteFallback export const CASE_SENSITIVE_FS = !fs.existsSync(join(__dirname, 'reSOLVE.js')) @@ -153,14 +156,17 @@ function requireResolver(name, modulePath) { try { // Try to resolve package with path, relative to closest package.json - const packageDir = findRoot(path.resolve(modulePath)); + const packageDir = findRoot(resolve(modulePath)) - return require(path.join(packageDir, name)); + return require(join(packageDir, name)) } catch (err) { try { // Try to resolve package with custom name (@myorg/resolver-name) - return require(name); + return require(name) + /* eslint-disable no-shadow */ } catch (err) { + /* eslint-enable no-shadow */ + // Try to resolve package with conventional name return require(`eslint-import-resolver-${name}`) } From 2323ef1ed9f9d36cbbcbbc5bba3ef945532e394e Mon Sep 17 00:00:00 2001 From: Leonid Nikiforenko Date: Sun, 8 May 2016 01:13:34 +0300 Subject: [PATCH 05/29] Add is-absolute fallback --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 5069ea12d6..74426bfcce 100644 --- a/package.json +++ b/package.json @@ -72,6 +72,7 @@ "es6-symbol": "*", "eslint-import-resolver-node": "^0.2.0", "find-root": "^1.0.0", + "is-absolute": "^0.2.5", "lodash.cond": "^4.3.0", "lodash.endswith": "^4.0.1", "lodash.find": "^4.3.0", From 0cad4e7359de752d82ccbc30f1f5effb2da87776 Mon Sep 17 00:00:00 2001 From: Leonid Nikiforenko Date: Sun, 15 May 2016 21:38:53 +0300 Subject: [PATCH 06/29] Use inline `eslint-disable` comment --- src/core/resolve.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/core/resolve.js b/src/core/resolve.js index 4acc9a19cb..e27997ab9e 100644 --- a/src/core/resolve.js +++ b/src/core/resolve.js @@ -163,9 +163,7 @@ function requireResolver(name, modulePath) { try { // Try to resolve package with custom name (@myorg/resolver-name) return require(name) - /* eslint-disable no-shadow */ - } catch (err) { - /* eslint-enable no-shadow */ + } catch (err) { // eslint-disable-line no-shadow // Try to resolve package with conventional name return require(`eslint-import-resolver-${name}`) From d53e45ff92377a0a6ddc6ed9ddfe0273e6585795 Mon Sep 17 00:00:00 2001 From: Leonid Nikiforenko Date: Tue, 17 May 2016 16:49:44 +0300 Subject: [PATCH 07/29] Use `pkg-dir` instead of `findRoot` --- package.json | 2 +- src/core/resolve.js | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 74426bfcce..70e60164db 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "gulp-mocha": "^2.2.0", "istanbul": "^0.4.0", "mocha": "^2.2.1", + "pkg-dir": "^1.0.0", "redux": "^3.0.4", "rimraf": "2.5.2" }, @@ -71,7 +72,6 @@ "es6-set": "^0.1.4", "es6-symbol": "*", "eslint-import-resolver-node": "^0.2.0", - "find-root": "^1.0.0", "is-absolute": "^0.2.5", "lodash.cond": "^4.3.0", "lodash.endswith": "^4.0.1", diff --git a/src/core/resolve.js b/src/core/resolve.js index e27997ab9e..5e3191e062 100644 --- a/src/core/resolve.js +++ b/src/core/resolve.js @@ -2,7 +2,7 @@ import 'es6-symbol/implement' import Map from 'es6-map' import Set from 'es6-set' import assign from 'object-assign' -import findRoot from 'find-root' +import pkgDir from 'pkg-dir' import isAbsoluteFallback from 'is-absolute' import fs from 'fs' @@ -57,7 +57,6 @@ function fileExistsWithCaseSync(filepath, cacheSettings) { } export function relative(modulePath, sourceFile, settings) { - const sourceDir = dirname(sourceFile) , cacheKey = sourceDir + hashObject(settings) + modulePath @@ -83,10 +82,10 @@ export function relative(modulePath, sourceFile, settings) { function v1() { try { const path = resolver.resolveImport(modulePath, sourceFile, config) - if (path === undefined) return { found: false } - return { found: true, path } + if (path === undefined) return { found: false, path: null } + return { found: true, path: null } } catch (err) { - return { found: false } + return { found: false, path: null } } } @@ -156,7 +155,7 @@ function requireResolver(name, modulePath) { try { // Try to resolve package with path, relative to closest package.json - const packageDir = findRoot(resolve(modulePath)) + const packageDir = pkgDir.sync(resolve(modulePath)) return require(join(packageDir, name)) } catch (err) { From 7a2c9395339da3423a7cfd173bffa4b624fbac5d Mon Sep 17 00:00:00 2001 From: Leonid Nikiforenko Date: Tue, 17 May 2016 16:50:04 +0300 Subject: [PATCH 08/29] Update README.md --- README.md | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 63 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 37bdd861e7..ebbc84ed43 100644 --- a/README.md +++ b/README.md @@ -123,19 +123,77 @@ In the interest of supporting both of these, v0.11 introduces resolvers. Currently [Node] and [Webpack] resolution have been implemented, but the resolvers are just npm packages, so [third party packages are supported](https://github.com/benmosher/eslint-plugin-import/wiki/Resolvers) (and encouraged!). -Just install a resolver as `eslint-import-resolver-foo` and reference it as such: +You can reference resolvers in several ways(in order of precedence): +1. With an absolute path to resolver, used as a `computed property` name, which is supported since Node v4: + +`.eslintrc.js`: +```js +{ + settings: { + 'import/resolver': { + [path.resolve('../../../my-resolver')]: { someConfig: value } + } + } +} +``` + +2. With a path relative to the closest `package.json` file: + + +`.eslintrc.js`: +```js +{ + settings: { + 'import/resolver': { + './my-resolver': { someConfig: value } + } + } +} +``` + +`.eslintrc.yml`: ```yaml settings: - import/resolver: foo + import/resolver: './my-resolver' +``` + +3. With an npm module name, like `my-awesome-npm-module`: + +`.eslintrc.js`: +```js +{ + settings: { + 'import/resolver': { + 'my-awesome-npm-module': { someConfig: value } + } + } +} ``` -or with a config object: +`.eslintrc.yml`: +```yaml +settings: + import/resolver: 'my-awesome-npm-module' +``` +4. As a conventional `eslint-import-resolver` name, like `eslint-import-resolver-foo`: + +`.eslintrc.js`: +```js +{ + settings: { + 'import/resolver': { + foo: { someConfig: value } + } + } +} +``` + +`.eslintrc.yml`: ```yaml settings: - import/resolver: - foo: { someConfigKey: value } + import/resolver: foo ``` If you are interesting in writing a resolver, see the [spec](./resolvers/README.md) for more details. From abce6f97cffdfec99290b26a0ed15bf04118d009 Mon Sep 17 00:00:00 2001 From: Leonid Nikiforenko Date: Tue, 17 May 2016 16:50:11 +0300 Subject: [PATCH 09/29] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e8748980a..db723f4457 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel ## [Unreleased] ### Added - Added support for multiple webpack configs ([#181], thanks [@GreenGremlin]) +- Added support for custom resolvers ([#314] thanks [@le0nik]) ## [Unreleased] ### Fixed @@ -249,6 +250,7 @@ for info on changes for earlier releases. [#211]: https://github.com/benmosher/eslint-plugin-import/pull/211 [#164]: https://github.com/benmosher/eslint-plugin-import/pull/164 [#157]: https://github.com/benmosher/eslint-plugin-import/pull/157 +[#314]: https://github.com/benmosher/eslint-plugin-import/pull/314 [#328]: https://github.com/benmosher/eslint-plugin-import/issues/328 [#317]: https://github.com/benmosher/eslint-plugin-import/issues/317 @@ -307,3 +309,4 @@ for info on changes for earlier releases. [@borisyankov]: https://github.com/borisyankov [@gavriguy]: https://github.com/gavriguy [@jkimbo]: https://github.com/jkimbo +[@le0nik]: https://github.com/le0nik From 23b9d122222790773c8cfcd572af257ff049fe12 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Mon, 23 May 2016 10:07:55 -0700 Subject: [PATCH 10/29] Add TomDoc support to no-deprecated rule --- CHANGELOG.md | 1 + docs/rules/no-deprecated.md | 27 +++++++++- src/core/getExports.js | 84 ++++++++++++++++++++++++++------ tests/files/tomdoc-deprecated.js | 22 +++++++++ tests/src/rules/no-deprecated.js | 38 +++++++++++++++ 5 files changed, 156 insertions(+), 16 deletions(-) create mode 100644 tests/files/tomdoc-deprecated.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 2623abddd7..467c68dc66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel ## [Unreleased] ### Added - Added support for multiple webpack configs ([#181], thanks [@GreenGremlin]) +- Added support TomDoc comments to `no-deprecated` ([#321], thanks [@josh]) ## [Unreleased] ### Fixed diff --git a/docs/rules/no-deprecated.md b/docs/rules/no-deprecated.md index 7f73eab780..989534ac6d 100644 --- a/docs/rules/no-deprecated.md +++ b/docs/rules/no-deprecated.md @@ -5,7 +5,9 @@ **NOTE**: this rule is currently a work in progress. There may be "breaking" changes: most likely, additional cases that are flagged. Reports use of a deprecated name, as indicated by a JSDoc block with a `@deprecated` -tag, i.e. +tag or TomDoc `Deprecated: ` comment. + +using a JSDoc `@deprecated` tag: ```js // @file: ./answer.js @@ -30,6 +32,28 @@ function whatever(y, z) { } ``` +or using the TomDoc equivalent: + +```js +// Deprecated: This is what you get when you trust a mouse talk show, need to +// restart the experiment. +// +// Returns a Number nonsense +export function multiply(six, nine) { + return 42 +} +``` + +Only JSDoc is enabled by default. Other documentation styles can be enabled with +the `import/docstyle` setting. + + +```yaml +# .eslintrc.yml +settings: + import/docstyle: ['jsdoc', 'tomdoc'] +``` + ### Worklist - [x] report explicit imports on the import node @@ -39,4 +63,3 @@ function whatever(y, z) { - [x] mark module deprecated if file JSDoc has a @deprecated tag? - [ ] don't flag redeclaration of imported, deprecated names - [ ] flag destructuring - diff --git a/src/core/getExports.js b/src/core/getExports.js index befcc73d7a..f0cf676144 100644 --- a/src/core/getExports.js +++ b/src/core/getExports.js @@ -97,6 +97,12 @@ export default class ExportMap { return m // can't continue } + const docstyle = (context.settings && context.settings['import/docstyle']) || ['jsdoc'] + const docStyleParsers = {} + docstyle.forEach(style => { + docStyleParsers[style] = availableDocStyleParsers[style] + }) + // attempt to collect module doc ast.comments.some(c => { if (c.type !== 'Block') return false @@ -143,7 +149,7 @@ export default class ExportMap { ast.body.forEach(function (n) { if (n.type === 'ExportDefaultDeclaration') { - const exportMeta = captureDoc(n) + const exportMeta = captureDoc(docStyleParsers, n) if (n.declaration.type === 'Identifier') { addNamespace(exportMeta, n.declaration) } @@ -174,11 +180,12 @@ export default class ExportMap { case 'FunctionDeclaration': case 'ClassDeclaration': case 'TypeAlias': // flowtype with babel-eslint parser - m.namespace.set(n.declaration.id.name, captureDoc(n)) + m.namespace.set(n.declaration.id.name, captureDoc(docStyleParsers, n)) break case 'VariableDeclaration': n.declaration.declarations.forEach((d) => - recursivePatternCapture(d.id, id => m.namespace.set(id.name, captureDoc(d, n)))) + recursivePatternCapture(d.id, id => + m.namespace.set(id.name, captureDoc(docStyleParsers, d, n)))) break } } @@ -348,33 +355,82 @@ export default class ExportMap { } /** - * parse JSDoc from the first node that has leading comments + * parse docs from the first node that has leading comments * @param {...[type]} nodes [description] * @return {{doc: object}} */ -function captureDoc(...nodes) { +function captureDoc(docStyleParsers, ...nodes) { const metadata = {} // 'some' short-circuits on first 'true' nodes.some(n => { if (!n.leadingComments) return false - // capture XSDoc - n.leadingComments.forEach(comment => { - // skip non-block comments - if (comment.value.slice(0, 4) !== '*\n *') return - try { - metadata.doc = doctrine.parse(comment.value, { unwrap: true }) - } catch (err) { - /* don't care, for now? maybe add to `errors?` */ + for (let name in docStyleParsers) { + const doc = docStyleParsers[name](n.leadingComments) + if (doc) { + metadata.doc = doc } - }) + } + return true }) return metadata } +const availableDocStyleParsers = { + jsdoc: captureJsDoc, + tomdoc: captureTomDoc, +} + +/** + * parse JSDoc from leading comments + * @param {...[type]} comments [description] + * @return {{doc: object}} + */ +function captureJsDoc(comments) { + let doc + + // capture XSDoc + comments.forEach(comment => { + // skip non-block comments + if (comment.value.slice(0, 4) !== '*\n *') return + try { + doc = doctrine.parse(comment.value, { unwrap: true }) + } catch (err) { + /* don't care, for now? maybe add to `errors?` */ + } + }) + + return doc +} + +/** + * parse TomDoc section from comments + */ +function captureTomDoc(comments) { + // collect lines up to first paragraph break + const lines = [] + for (let i = 0; i < comments.length; i++) { + const comment = comments[i] + if (comment.value.match(/^\s*$/)) break + lines.push(comment.value.trim()) + } + + // return doctrine-like object + const statusMatch = lines.join(' ').match(/^(Public|Internal|Deprecated):\s*(.+)/) + if (statusMatch) { + return { + description: statusMatch[2], + tags: [{ + title: statusMatch[1].toLowerCase(), + description: statusMatch[2], + }], + } + } +} + /** * Traverse a pattern/identifier node, calling 'callback' * for each leaf identifier. diff --git a/tests/files/tomdoc-deprecated.js b/tests/files/tomdoc-deprecated.js new file mode 100644 index 0000000000..d7b8bb217f --- /dev/null +++ b/tests/files/tomdoc-deprecated.js @@ -0,0 +1,22 @@ +// Deprecated: This function is terrible. +// +// With another line comment in description. +export function fn() { return null } + +// Deprecated: this is awful, +// use NotAsBadClass. +// +// Some other description text. +export default class TerribleClass { + +} + +// Deprecated: Please stop sending/handling this action type. +export const MY_TERRIBLE_ACTION = "ugh" + +// Public: This one is fine. +// +// Returns a String "great!" +export function fine() { return "great!" } + +export function _undocumented() { return "sneaky!" } diff --git a/tests/src/rules/no-deprecated.js b/tests/src/rules/no-deprecated.js index 92660348b2..ef6912dd1e 100644 --- a/tests/src/rules/no-deprecated.js +++ b/tests/src/rules/no-deprecated.js @@ -13,6 +13,20 @@ ruleTester.run('no-deprecated', rule, { test({ code: "import { fine } from './deprecated'" }), test({ code: "import { _undocumented } from './deprecated'" }), + test({ + code: "import { fn } from './deprecated'", + settings: { 'import/docstyle': ['tomdoc'] } + }), + + test({ + code: "import { fine } from './tomdoc-deprecated'", + settings: { 'import/docstyle': ['tomdoc'] } + }), + test({ + code: "import { _undocumented } from './tomdoc-deprecated'", + settings: { 'import/docstyle': ['tomdoc'] } + }), + // naked namespace is fine test({ code: "import * as depd from './deprecated'" }), test({ code: "import * as depd from './deprecated'; console.log(depd.fine())" }), @@ -44,6 +58,30 @@ ruleTester.run('no-deprecated', rule, { errors: ['Deprecated: please stop sending/handling this action type.'], }), + test({ + code: "import { fn } from './deprecated'", + settings: { 'import/docstyle': ['jsdoc', 'tomdoc'] }, + errors: ["Deprecated: please use 'x' instead."], + }), + + test({ + code: "import { fn } from './tomdoc-deprecated'", + settings: { 'import/docstyle': ['tomdoc'] }, + errors: ["Deprecated: This function is terrible."], + }), + + test({ + code: "import TerribleClass from './tomdoc-deprecated'", + settings: { 'import/docstyle': ['tomdoc'] }, + errors: ['Deprecated: this is awful, use NotAsBadClass.'], + }), + + test({ + code: "import { MY_TERRIBLE_ACTION } from './tomdoc-deprecated'", + settings: { 'import/docstyle': ['tomdoc'] }, + errors: ['Deprecated: Please stop sending/handling this action type.'], + }), + // ignore redeclares test({ code: "import { MY_TERRIBLE_ACTION } from './deprecated'; function shadow(MY_TERRIBLE_ACTION) { console.log(MY_TERRIBLE_ACTION); }", From 92f7d655dbba9c0c169cd129baf1af4ecd8a2456 Mon Sep 17 00:00:00 2001 From: Scott Nonnenberg Date: Tue, 31 May 2016 03:47:44 -0700 Subject: [PATCH 11/29] prefer-default-export: Support 'export function foo() {}; export const x = 4;' (#359) * prefer-default-export: Add tests and else case * Add changelog message for #359 --- CHANGELOG.md | 5 +++++ src/rules/prefer-default-export.js | 4 ++++ tests/src/rules/prefer-default-export.js | 17 +++++++++++++++++ 3 files changed, 26 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b68d8b4e04..df247361e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). This change log adheres to standards from [Keep a CHANGELOG](http://keepachangelog.com). +## TBD +### Fixed +- [`prefer-default-export`] handles `export function` and `export const` in same file ([#359], thanks [@scottnonnenberg]) + ## resolvers/webpack/0.2.5 - 2016-05-23 ### Added - Added support for multiple webpack configs ([#181], thanks [@GreenGremlin]) @@ -225,6 +229,7 @@ for info on changes for earlier releases. [`no-mutable-exports`]: ./docs/rules/no-mutable-exports.md [`prefer-default-export`]: ./docs/rules/prefer-default-export.md +[#359]: https://github.com/benmosher/eslint-plugin-import/pull/359 [#343]: https://github.com/benmosher/eslint-plugin-import/pull/343 [#332]: https://github.com/benmosher/eslint-plugin-import/pull/332 [#322]: https://github.com/benmosher/eslint-plugin-import/pull/322 diff --git a/src/rules/prefer-default-export.js b/src/rules/prefer-default-export.js index 9e6ce7a8e9..2bd4783ebb 100644 --- a/src/rules/prefer-default-export.js +++ b/src/rules/prefer-default-export.js @@ -38,6 +38,10 @@ module.exports = function(context) { captureDeclaration(declaration.id) }) } + else { + // captures 'export function foo() {}' syntax + specifierExportCount++ + } namedExportNode = node }, diff --git a/tests/src/rules/prefer-default-export.js b/tests/src/rules/prefer-default-export.js index c38eff0449..33eee694d3 100644 --- a/tests/src/rules/prefer-default-export.js +++ b/tests/src/rules/prefer-default-export.js @@ -12,6 +12,15 @@ ruleTester.run('prefer-default-export', rule, { export const foo = 'foo'; export const bar = 'bar';`, }), + test({ + code: ` + export default function bar() {};`, + }), + test({ + code: ` + export const foo = 'foo'; + export function bar() {};`, + }), test({ code: ` export const foo = 'foo'; @@ -56,6 +65,14 @@ ruleTester.run('prefer-default-export', rule, { // ...SYNTAX_CASES, ], invalid: [ + test({ + code: ` + export function bar() {};`, + errors: [{ + ruleId: 'ExportNamedDeclaration', + message: 'Prefer default export.', + }], + }), test({ code: ` export const foo = 'foo';`, From 45c4de540981cb31b5b84418e4fe4c4781143e5f Mon Sep 17 00:00:00 2001 From: Ben Mosher Date: Wed, 1 Jun 2016 06:41:11 -0400 Subject: [PATCH 12/29] changelog tweak --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index df247361e9..d6f02d5be5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). This change log adheres to standards from [Keep a CHANGELOG](http://keepachangelog.com). -## TBD +## [Unreleased] ### Fixed - [`prefer-default-export`] handles `export function` and `export const` in same file ([#359], thanks [@scottnonnenberg]) From b72b5836f561360b57438ad46f4f9fd7d895eef1 Mon Sep 17 00:00:00 2001 From: Ben Mosher Date: Tue, 17 May 2016 07:36:14 -0400 Subject: [PATCH 13/29] first pass at enhanced-resolve as underlying Webpack resolver implementation --- CHANGELOG.md | 4 ++ resolvers/webpack/index.js | 125 +++++++++++++++++---------------- resolvers/webpack/package.json | 3 +- 3 files changed, 69 insertions(+), 63 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d6f02d5be5..3b2fff0db0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ This project adheres to [Semantic Versioning](http://semver.org/). This change log adheres to standards from [Keep a CHANGELOG](http://keepachangelog.com). ## [Unreleased] +### Changed +- webpack resolver: use enhanced-resolve to support additional plugins instead of + re-implementing aliases, etc. + ### Fixed - [`prefer-default-export`] handles `export function` and `export const` in same file ([#359], thanks [@scottnonnenberg]) diff --git a/resolvers/webpack/index.js b/resolvers/webpack/index.js index 8919ef3884..62061c73f9 100644 --- a/resolvers/webpack/index.js +++ b/resolvers/webpack/index.js @@ -1,14 +1,12 @@ var findRoot = require('find-root') , path = require('path') - , resolve = require('resolve') , get = require('lodash.get') , find = require('array-find') , interpret = require('interpret') // not available on 0.10.x , isAbsolute = path.isAbsolute || require('is-absolute') , fs = require('fs') - -var resolveAlias = require('./resolve-alias') + , coreLibs = require('node-libs-browser') exports.interfaceVersion = 2 @@ -30,7 +28,9 @@ exports.resolve = function (source, file, settings) { source = source.slice(finalBang + 1) } - if (resolve.isCore(source)) return { found: true, path: null } + if (source in coreLibs) { + return { found: true, path: coreLibs[source] } + } var webpackConfig @@ -108,49 +108,72 @@ exports.resolve = function (source, file, settings) { // externals if (findExternal(source, webpackConfig.externals)) return { found: true, path: null } - // replace alias if needed - source = resolveAlias(source, get(webpackConfig, ['resolve', 'alias'], {})) - - var paths = [] - - // root as first alternate path - var rootPath = get(webpackConfig, ['resolve', 'root']) - - if (rootPath) { - if (typeof rootPath === 'string') paths.push(rootPath) - else paths.push.apply(paths, rootPath) - } - - // set fallback paths - var fallbackPath = get(webpackConfig, ['resolve', 'fallback']) - if (fallbackPath) { - if (typeof fallbackPath === 'string') paths.push(fallbackPath) - else paths.push.apply(paths, fallbackPath) - } - - // otherwise, resolve "normally" + var resolver = createResolver(webpackConfig.resolve || {}) try { - - return { found: true, path: resolve.sync(source, { - basedir: path.dirname(file), - - // defined via http://webpack.github.io/docs/configuration.html#resolve-extensions - extensions: get(webpackConfig, ['resolve', 'extensions']) - || ['', '.webpack.js', '.web.js', '.js'], - - // http://webpack.github.io/docs/configuration.html#resolve-modulesdirectories - moduleDirectory: get(webpackConfig, ['resolve', 'modulesDirectories']) - || ['web_modules', 'node_modules'], - - paths: paths, - packageFilter: packageFilter.bind(null, webpackConfig), - }) } + return { found: true, path: resolver.resolveSync(path.dirname(file), source) } } catch (err) { return { found: false } } } +var Resolver = require('enhanced-resolve/lib/Resolver') + +var SyncNodeJsInputFileSystem = require('enhanced-resolve/lib/SyncNodeJsInputFileSystem') +var syncFS = new SyncNodeJsInputFileSystem() + +var ModuleAliasPlugin = require('enhanced-resolve/lib/ModuleAliasPlugin') +var ModulesInDirectoriesPlugin = require('enhanced-resolve/lib/ModulesInDirectoriesPlugin') +var ModulesInRootPlugin = require('enhanced-resolve/lib/ModulesInRootPlugin') +var ModuleAsFilePlugin = require('enhanced-resolve/lib/ModuleAsFilePlugin') +var ModuleAsDirectoryPlugin = require('enhanced-resolve/lib/ModuleAsDirectoryPlugin') +var DirectoryDescriptionFilePlugin = require('enhanced-resolve/lib/DirectoryDescriptionFilePlugin') +var DirectoryDefaultFilePlugin = require('enhanced-resolve/lib/DirectoryDefaultFilePlugin') +var FileAppendPlugin = require('enhanced-resolve/lib/FileAppendPlugin') +var ResultSymlinkPlugin = require('enhanced-resolve/lib/ResultSymlinkPlugin') +var DirectoryDescriptionFileFieldAliasPlugin = + require('enhanced-resolve/lib/DirectoryDescriptionFileFieldAliasPlugin') + +// adapted from tests & +// https://github.com/webpack/webpack/blob/v1.13.0/lib/WebpackOptionsApply.js#L322 +function createResolver(resolve) { + var resolver = new Resolver(syncFS) + + resolver.apply( + resolve.packageAlias + ? new DirectoryDescriptionFileFieldAliasPlugin('package.json', resolve.packageAlias) + : function() {}, + new ModuleAliasPlugin(resolve.alias || {}), + makeRootPlugin('module', resolve.root), + new ModulesInDirectoriesPlugin('module', resolve.modulesDirectories || ['web_modules', 'node_modules']), + makeRootPlugin('module', resolve.fallback), + new ModuleAsFilePlugin('module'), + new ModuleAsDirectoryPlugin('module'), + new DirectoryDescriptionFilePlugin('package.json', ['jsnext:main'].concat(resolve.packageMains || defaultMains)), + new DirectoryDefaultFilePlugin(['index']), + new FileAppendPlugin(resolve.extensions || ['', '.webpack.js', '.web.js', '.js']), + new ResultSymlinkPlugin() + ) + + return resolver +} + +/* eslint-disable */ +// from https://github.com/webpack/webpack/blob/v1.13.0/lib/WebpackOptionsApply.js#L365 +function makeRootPlugin(name, root) { + if(typeof root === "string") + return new ModulesInRootPlugin(name, root); + else if(Array.isArray(root)) { + return function() { + root.forEach(function(root) { + this.apply(new ModulesInRootPlugin(name, root)); + }, this); + }; + } + return function() {}; +} +/* eslint-enable */ + function findExternal(source, externals) { if (!externals) return false @@ -186,28 +209,6 @@ var defaultMains = [ 'webpack', 'browser', 'web', 'browserify', ['jam', 'main'], 'main', ] -function packageFilter(config, pkg) { - var altMain - - // check for rollup-style first - if (pkg['jsnext:main']) { - pkg['main'] = pkg['jsnext:main'] - } else { - // check for configured/default alternative main fields - altMain = find( - get(config, ['resolve', 'packageMains']) || defaultMains, - function (m) { return typeof get(pkg, m) === 'string' }) - - if (altMain) { - pkg['main'] = get(pkg, altMain) - } - } - - - return pkg -} - - function registerCompiler(moduleDescriptor) { if(moduleDescriptor) { if(typeof moduleDescriptor === 'string') { diff --git a/resolvers/webpack/package.json b/resolvers/webpack/package.json index 40bd4976f8..725b9346c6 100644 --- a/resolvers/webpack/package.json +++ b/resolvers/webpack/package.json @@ -25,11 +25,12 @@ "homepage": "https://github.com/benmosher/eslint-plugin-import#readme", "dependencies": { "array-find": "^1.0.0", + "enhanced-resolve": "~0.9.0", "find-root": "^0.1.1", "interpret": "^1.0.0", "is-absolute": "^0.2.3", "lodash.get": "^3.7.0", - "resolve": "^1.1.6" + "node-libs-browser": "^1.0.0" }, "peerDependencies": { "eslint-plugin-import": ">=1.4.0" From 18e628b33cdf6fbe0aee90e70687cfd80ba64082 Mon Sep 17 00:00:00 2001 From: Ben Mosher Date: Tue, 17 May 2016 07:40:28 -0400 Subject: [PATCH 14/29] removed hand-rolled resolve-alias --- resolvers/webpack/resolve-alias.js | 48 ------ resolvers/webpack/test/alias.js | 226 ++++++++++++++--------------- 2 files changed, 113 insertions(+), 161 deletions(-) delete mode 100644 resolvers/webpack/resolve-alias.js diff --git a/resolvers/webpack/resolve-alias.js b/resolvers/webpack/resolve-alias.js deleted file mode 100644 index 485b41eecf..0000000000 --- a/resolvers/webpack/resolve-alias.js +++ /dev/null @@ -1,48 +0,0 @@ -var path = require('path') - -// implements a rough version of -// http://webpack.github.io/docs/configuration.html#resolve-alias -module.exports = function resolveAlias(source, aliases) { - - for (var alias in aliases) { - var match = matchAlias(source, alias, aliases[alias]) - if (match) return match - } - - // fail out - return source -} - -// using '/' only for consistency with Webpack docs -var sep = '/' -function matchAlias(source, alias, value) { - var isExact = (alias[alias.length - 1] === '$') - , isFile = (path.extname(value) !== '') - , sourceSegments = source.split(sep) - , ptr = 0 - , aliasSegments - - if (isExact) alias = alias.slice(0, -1) - - aliasSegments = alias.split(sep) - - // look for a common prefix - while(sourceSegments[ptr] == aliasSegments[ptr] && ptr < sourceSegments.length && ptr < aliasSegments.length) { - ptr++; - } - - // the common prefix must be the entirety of the alias - if (ptr === aliasSegments.length) { - // always return exact match - if (sourceSegments.length === aliasSegments.length) return value - - // prefix match on exact match for file is an error - if (isFile && (isExact || !/^[./]/.test(value))) { - throw new Error('can\'t match file with exact alias prefix') - } - - // otherwise, prefix match is fine for non-file paths - if (!isExact && !isFile) return [value].concat(sourceSegments.slice(ptr)).join(sep) - } - -} diff --git a/resolvers/webpack/test/alias.js b/resolvers/webpack/test/alias.js index 4a120f05de..f8cd210e42 100644 --- a/resolvers/webpack/test/alias.js +++ b/resolvers/webpack/test/alias.js @@ -18,120 +18,120 @@ describe("resolve.alias", function () { }) }) -var resolveAlias = require('../resolve-alias') -describe("webpack alias spec", function () { - // from table: http://webpack.github.io/docs/configuration.html#resolve-alias - function tableLine(alias, xyz, xyzFile) { - describe(JSON.stringify(alias), function () { - it("xyz: " + xyz, function () { - expect(resolveAlias('xyz', alias)).to.equal(xyz) - }) - it("xyz/file: " + (xyzFile.name || xyzFile), function () { - if (xyzFile === Error) { - expect(resolveAlias.bind(null, 'xyz/file', alias)).to.throw(xyzFile) - } else { - expect(resolveAlias('xyz/file', alias)).to.equal(xyzFile) - } - }) - }) - } +// todo: reimplement with resolver function / config +// describe.skip("webpack alias spec", function () { +// // from table: http://webpack.github.io/docs/configuration.html#resolve-alias +// function tableLine(alias, xyz, xyzFile) { +// describe(JSON.stringify(alias), function () { +// it("xyz: " + xyz, function () { +// expect(resolveAlias('xyz', alias)).to.equal(xyz) +// }) +// it("xyz/file: " + (xyzFile.name || xyzFile), function () { +// if (xyzFile === Error) { +// expect(resolveAlias.bind(null, 'xyz/file', alias)).to.throw(xyzFile) +// } else { +// expect(resolveAlias('xyz/file', alias)).to.equal(xyzFile) +// } +// }) +// }) +// } + +// tableLine( {} +// , 'xyz', 'xyz/file' ) + +// tableLine( { xyz: "/absolute/path/to/file.js" } +// , '/absolute/path/to/file.js', 'xyz/file' ) + +// tableLine( { xyz$: "/absolute/path/to/file.js" } +// , "/absolute/path/to/file.js", Error ) + +// tableLine( { xyz: "./dir/file.js" } +// , './dir/file.js', 'xyz/file' ) + +// tableLine( { xyz$: "./dir/file.js" } +// , './dir/file.js', Error ) + +// tableLine( { xyz: "/some/dir" } +// , '/some/dir', '/some/dir/file' ) + +// tableLine( { xyz$: "/some/dir" } +// , '/some/dir', 'xyz/file' ) + +// tableLine( { xyz: "./dir" } +// , './dir', './dir/file' ) + +// tableLine( { xyz: "modu" } +// , 'modu', 'modu/file' ) + +// tableLine( { xyz$: "modu" } +// , 'modu', 'xyz/file' ) + +// tableLine( { xyz: "modu/some/file.js" } +// , 'modu/some/file.js', Error ) + +// tableLine( { xyz: "modu/dir" } +// , 'modu/dir', 'modu/dir/file' ) + +// tableLine( { xyz: "xyz/dir" } +// , 'xyz/dir', 'xyz/dir/file' ) + +// tableLine( { xyz$: "xyz/dir" } +// , 'xyz/dir', 'xyz/file' ) +// }) + +// describe.skip("nested module names", function () { +// // from table: http://webpack.github.io/docs/configuration.html#resolve-alias +// function nestedName(alias, xyz, xyzFile) { +// describe(JSON.stringify(alias), function () { +// it("top/xyz: " + xyz, function () { +// expect(resolveAlias('top/xyz', alias)).to.equal(xyz) +// }) +// it("top/xyz/file: " + (xyzFile.name || xyzFile), function () { +// if (xyzFile === Error) { +// expect(resolveAlias.bind(null, 'top/xyz/file', alias)).to.throw(xyzFile) +// } else { +// expect(resolveAlias('top/xyz/file', alias)).to.equal(xyzFile) +// } +// }) +// }) +// } + +// nestedName( { 'top/xyz': "/absolute/path/to/file.js" } +// , '/absolute/path/to/file.js', 'top/xyz/file' ) + +// nestedName( { 'top/xyz$': "/absolute/path/to/file.js" } +// , "/absolute/path/to/file.js", Error ) + +// nestedName( { 'top/xyz': "./dir/file.js" } +// , './dir/file.js', 'top/xyz/file' ) + +// nestedName( { 'top/xyz$': "./dir/file.js" } +// , './dir/file.js', Error ) + +// nestedName( { 'top/xyz': "/some/dir" } +// , '/some/dir', '/some/dir/file' ) + +// nestedName( { 'top/xyz$': "/some/dir" } +// , '/some/dir', 'top/xyz/file' ) + +// nestedName( { 'top/xyz': "./dir" } +// , './dir', './dir/file' ) + +// nestedName( { 'top/xyz': "modu" } +// , 'modu', 'modu/file' ) + +// nestedName( { 'top/xyz$': "modu" } +// , 'modu', 'top/xyz/file' ) - tableLine( {} - , 'xyz', 'xyz/file' ) +// nestedName( { 'top/xyz': "modu/some/file.js" } +// , 'modu/some/file.js', Error ) - tableLine( { xyz: "/absolute/path/to/file.js" } - , '/absolute/path/to/file.js', 'xyz/file' ) +// nestedName( { 'top/xyz': "modu/dir" } +// , 'modu/dir', 'modu/dir/file' ) - tableLine( { xyz$: "/absolute/path/to/file.js" } - , "/absolute/path/to/file.js", Error ) +// nestedName( { 'top/xyz': "top/xyz/dir" } +// , 'top/xyz/dir', 'top/xyz/dir/file' ) - tableLine( { xyz: "./dir/file.js" } - , './dir/file.js', 'xyz/file' ) - - tableLine( { xyz$: "./dir/file.js" } - , './dir/file.js', Error ) - - tableLine( { xyz: "/some/dir" } - , '/some/dir', '/some/dir/file' ) - - tableLine( { xyz$: "/some/dir" } - , '/some/dir', 'xyz/file' ) - - tableLine( { xyz: "./dir" } - , './dir', './dir/file' ) - - tableLine( { xyz: "modu" } - , 'modu', 'modu/file' ) - - tableLine( { xyz$: "modu" } - , 'modu', 'xyz/file' ) - - tableLine( { xyz: "modu/some/file.js" } - , 'modu/some/file.js', Error ) - - tableLine( { xyz: "modu/dir" } - , 'modu/dir', 'modu/dir/file' ) - - tableLine( { xyz: "xyz/dir" } - , 'xyz/dir', 'xyz/dir/file' ) - - tableLine( { xyz$: "xyz/dir" } - , 'xyz/dir', 'xyz/file' ) -}) - -describe("nested module names", function () { - // from table: http://webpack.github.io/docs/configuration.html#resolve-alias - function nestedName(alias, xyz, xyzFile) { - describe(JSON.stringify(alias), function () { - it("top/xyz: " + xyz, function () { - expect(resolveAlias('top/xyz', alias)).to.equal(xyz) - }) - it("top/xyz/file: " + (xyzFile.name || xyzFile), function () { - if (xyzFile === Error) { - expect(resolveAlias.bind(null, 'top/xyz/file', alias)).to.throw(xyzFile) - } else { - expect(resolveAlias('top/xyz/file', alias)).to.equal(xyzFile) - } - }) - }) - } - - nestedName( { 'top/xyz': "/absolute/path/to/file.js" } - , '/absolute/path/to/file.js', 'top/xyz/file' ) - - nestedName( { 'top/xyz$': "/absolute/path/to/file.js" } - , "/absolute/path/to/file.js", Error ) - - nestedName( { 'top/xyz': "./dir/file.js" } - , './dir/file.js', 'top/xyz/file' ) - - nestedName( { 'top/xyz$': "./dir/file.js" } - , './dir/file.js', Error ) - - nestedName( { 'top/xyz': "/some/dir" } - , '/some/dir', '/some/dir/file' ) - - nestedName( { 'top/xyz$': "/some/dir" } - , '/some/dir', 'top/xyz/file' ) - - nestedName( { 'top/xyz': "./dir" } - , './dir', './dir/file' ) - - nestedName( { 'top/xyz': "modu" } - , 'modu', 'modu/file' ) - - nestedName( { 'top/xyz$': "modu" } - , 'modu', 'top/xyz/file' ) - - nestedName( { 'top/xyz': "modu/some/file.js" } - , 'modu/some/file.js', Error ) - - nestedName( { 'top/xyz': "modu/dir" } - , 'modu/dir', 'modu/dir/file' ) - - nestedName( { 'top/xyz': "top/xyz/dir" } - , 'top/xyz/dir', 'top/xyz/dir/file' ) - - nestedName( { 'top/xyz$': "top/xyz/dir" } - , 'top/xyz/dir', 'top/xyz/file' ) -}) +// nestedName( { 'top/xyz$': "top/xyz/dir" } +// , 'top/xyz/dir', 'top/xyz/file' ) +// }) From 187014c6632d1811c0b095c309a42ed6ca806732 Mon Sep 17 00:00:00 2001 From: Ben Mosher Date: Mon, 23 May 2016 07:05:51 -0400 Subject: [PATCH 15/29] allow explicit file extensions in test files when using Webpack resolver. (how was this working before...?) --- tests/files/webpack.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/files/webpack.config.js b/tests/files/webpack.config.js index 93986f37a3..980c32425e 100644 --- a/tests/files/webpack.config.js +++ b/tests/files/webpack.config.js @@ -1,6 +1,6 @@ module.exports = { resolve: { - extensions: ['.js', '.jsx'], + extensions: ['', '.js', '.jsx'], root: __dirname, }, } From ff4568c0bb0ca32af9675cebc9e0b11a6ca7a45d Mon Sep 17 00:00:00 2001 From: Ben Mosher Date: Wed, 1 Jun 2016 06:47:47 -0400 Subject: [PATCH 16/29] moved webpack resolver change log to separate file --- CHANGELOG.md | 22 ------------------- resolvers/webpack/CHANGELOG.md | 40 ++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 22 deletions(-) create mode 100644 resolvers/webpack/CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b2fff0db0..117109bb33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,17 +4,9 @@ This project adheres to [Semantic Versioning](http://semver.org/). This change log adheres to standards from [Keep a CHANGELOG](http://keepachangelog.com). ## [Unreleased] -### Changed -- webpack resolver: use enhanced-resolve to support additional plugins instead of - re-implementing aliases, etc. - ### Fixed - [`prefer-default-export`] handles `export function` and `export const` in same file ([#359], thanks [@scottnonnenberg]) -## resolvers/webpack/0.2.5 - 2016-05-23 -### Added -- Added support for multiple webpack configs ([#181], thanks [@GreenGremlin]) - ## [1.8.1] - 2016-05-23 ### Fixed - `export * from 'foo'` now properly ignores a `default` export from `foo`, if any. ([#328]/[#332], thanks [@jkimbo]) @@ -46,10 +38,6 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel - [`extensions`]: fallback to source path for extension enforcement if imported module is not resolved. Also, never report for builtins (i.e. `path`). ([#296]) -## resolvers/webpack/0.2.4 - 2016-04-29 -### Changed -- automatically find webpack config with `interpret`-able extensions ([#287], thanks [@taion]) - ## [1.6.1] - 2016-04-28 ### Fixed - [`no-named-as-default-member`]: don't crash on rest props. ([#281], thanks [@SimenB]) @@ -57,16 +45,6 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel Thanks to [@strawbrary] for bringing this up ([#272]) and adding OSX support to the Travis config ([#288]). -## resolvers/webpack/0.2.3 - 2016-04-28 -### Fixed -- `interpret` dependency was declared in the wrong `package.json`. - Thanks [@jonboiser] for sleuthing ([#286]) and fixing ([#289]). - -## resolvers/webpack/0.2.2 - 2016-04-27 -### Added -- `interpret` configs (such as `.babel.js`). - Thanks to [@gausie] for the initial PR ([#164], ages ago! 😅) and [@jquense] for tests ([#278]). - ## [1.6.0] - 2016-04-25 ### Added - add [`no-named-as-default-member`] to `warnings` canned config diff --git a/resolvers/webpack/CHANGELOG.md b/resolvers/webpack/CHANGELOG.md new file mode 100644 index 0000000000..c22aa44b91 --- /dev/null +++ b/resolvers/webpack/CHANGELOG.md @@ -0,0 +1,40 @@ +# Change Log +All notable changes to this resolver will be documented in this file. +This project adheres to [Semantic Versioning](http://semver.org/). +This change log adheres to standards from [Keep a CHANGELOG](http://keepachangelog.com). + +## Unreleased +### Changed +- use `enhanced-resolve` to support additional plugins instead of re-implementing + aliases, etc. + +## 0.2.5 - 2016-05-23 +### Added +- Added support for multiple webpack configs ([#181], thanks [@GreenGremlin]) + +## 0.2.4 - 2016-04-29 +### Changed +- automatically find webpack config with `interpret`-able extensions ([#287], thanks [@taion]) + +## 0.2.3 - 2016-04-28 +### Fixed +- `interpret` dependency was declared in the wrong `package.json`. + Thanks [@jonboiser] for sleuthing ([#286]) and fixing ([#289]). + +## 0.2.2 - 2016-04-27 +### Added +- `interpret` configs (such as `.babel.js`). + Thanks to [@gausie] for the initial PR ([#164], ages ago! 😅) and [@jquense] for tests ([#278]). + +[#289]: https://github.com/benmosher/eslint-plugin-import/pull/289 +[#287]: https://github.com/benmosher/eslint-plugin-import/pull/287 +[#278]: https://github.com/benmosher/eslint-plugin-import/pull/278 +[#181]: https://github.com/benmosher/eslint-plugin-import/pull/181 +[#164]: https://github.com/benmosher/eslint-plugin-import/pull/164 + +[#286]: https://github.com/benmosher/eslint-plugin-import/issues/286 + +[@gausie]: https://github.com/gausie +[@jquense]: https://github.com/jquense +[@taion]: https://github.com/taion +[@GreenGremlin]: https://github.com/GreenGremlin From 05520a35359edf0a1a41ad63b3f4f58ef53b43c0 Mon Sep 17 00:00:00 2001 From: Ben Mosher Date: Wed, 1 Jun 2016 06:52:47 -0400 Subject: [PATCH 17/29] resolvers/webpack/v0.3.0 --- resolvers/webpack/CHANGELOG.md | 2 +- resolvers/webpack/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resolvers/webpack/CHANGELOG.md b/resolvers/webpack/CHANGELOG.md index c22aa44b91..cff7b2d033 100644 --- a/resolvers/webpack/CHANGELOG.md +++ b/resolvers/webpack/CHANGELOG.md @@ -3,7 +3,7 @@ All notable changes to this resolver will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). This change log adheres to standards from [Keep a CHANGELOG](http://keepachangelog.com). -## Unreleased +## 0.3.0 - 2016-06-01 ### Changed - use `enhanced-resolve` to support additional plugins instead of re-implementing aliases, etc. diff --git a/resolvers/webpack/package.json b/resolvers/webpack/package.json index 725b9346c6..ecd45dff0b 100644 --- a/resolvers/webpack/package.json +++ b/resolvers/webpack/package.json @@ -1,6 +1,6 @@ { "name": "eslint-import-resolver-webpack", - "version": "0.2.5", + "version": "0.3.0", "description": "Resolve paths to dependencies, given a webpack.config.js. Plugin for eslint-plugin-import.", "main": "index.js", "scripts": { From 9b9d905243f26ca94d17cd7050d0e19b5e6a263c Mon Sep 17 00:00:00 2001 From: Ben Mosher Date: Wed, 1 Jun 2016 07:10:42 -0400 Subject: [PATCH 18/29] flattened out resolver loading function --- src/core/resolve.js | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/src/core/resolve.js b/src/core/resolve.js index 5e3191e062..318103cdaa 100644 --- a/src/core/resolve.js +++ b/src/core/resolve.js @@ -147,30 +147,32 @@ function resolverReducer(resolvers, map) { } function requireResolver(name, modulePath) { - try { - // Try to resolve package with absolute path (/Volumes/....) - if (isAbsolute(name)) { + // Try to resolve package with absolute path (/Volumes/....) + if (isAbsolute(name)) { + try { return require(name) - } + } catch (err) { /* continue */ } + } - try { - // Try to resolve package with path, relative to closest package.json - const packageDir = pkgDir.sync(resolve(modulePath)) + // Try to resolve package with path, relative to closest package.json + try { + const packageDir = pkgDir.sync((modulePath)) - return require(join(packageDir, name)) - } catch (err) { - try { - // Try to resolve package with custom name (@myorg/resolver-name) - return require(name) - } catch (err) { // eslint-disable-line no-shadow + return require(join(packageDir, name)) + } catch (err) { /* continue */ } - // Try to resolve package with conventional name - return require(`eslint-import-resolver-${name}`) - } - } - } catch (err) { - throw new Error(`unable to load resolver "${name}".`) - } + // Try to resolve package with custom name (@myorg/resolver-name) + try { + return require(name) + } catch (err) { /* continue */ } + + // Try to resolve package with conventional name + try { + return require(`eslint-import-resolver-${name}`) + } catch (err) { /* continue */ } + + // all else failed + throw new Error(`unable to load resolver "${name}".`) } const erroredContexts = new Set() From 023bd05bea3aeb644e64b474b975181604d53dba Mon Sep 17 00:00:00 2001 From: Ben Mosher Date: Thu, 2 Jun 2016 07:15:05 -0400 Subject: [PATCH 19/29] added debug statements to webpack resolver (#300) --- resolvers/webpack/index.js | 96 ++++++++++++++++++++-------------- resolvers/webpack/package.json | 1 + 2 files changed, 58 insertions(+), 39 deletions(-) diff --git a/resolvers/webpack/index.js b/resolvers/webpack/index.js index 62061c73f9..717537d704 100644 --- a/resolvers/webpack/index.js +++ b/resolvers/webpack/index.js @@ -8,6 +8,8 @@ var findRoot = require('find-root') , fs = require('fs') , coreLibs = require('node-libs-browser') +const log = require('debug')('eslint-plugin-import:resolver:webpack') + exports.interfaceVersion = 2 /** @@ -34,15 +36,12 @@ exports.resolve = function (source, file, settings) { var webpackConfig - var extensions = Object.keys(interpret.extensions).sort(function(a, b) { - return a === '.js' ? -1 : b === '.js' ? 1 : a.length - b.length - }) - try { var configPath = get(settings, 'config') , configIndex = get(settings, 'config-index') , packageDir - , extension + + if (configPath) log('Config path from settings:', configPath) // see if we've got an absolute path if (!configPath || !isAbsolute(configPath)) { @@ -51,46 +50,17 @@ exports.resolve = function (source, file, settings) { if (!packageDir) throw new Error('package not found above ' + file) } - if (configPath) { - // extensions is not reused below, so safe to mutate it here. - extensions.reverse() - extensions.forEach(function (maybeExtension) { - if (extension) { - return - } - - if (configPath.substr(-maybeExtension.length) === maybeExtension) { - extension = maybeExtension - } - }) + configPath = findConfigPath(configPath, packageDir) - // see if we've got an absolute path - if (!isAbsolute(configPath)) { - configPath = path.join(packageDir, configPath) - } - } else { - extensions.forEach(function (maybeExtension) { - if (extension) { - return - } - - var maybePath = path.resolve( - path.join(packageDir, 'webpack.config' + maybeExtension) - ) - if (fs.existsSync(maybePath)) { - configPath = maybePath - extension = maybeExtension - } - }) - } - - registerCompiler(interpret.extensions[extension]) + log('Config path resolved to:', configPath) webpackConfig = require(configPath) if (webpackConfig && webpackConfig.default) { + log('Using ES6 module "default" key instead of module.exports.') webpackConfig = webpackConfig.default } } catch (err) { + log('Error during config lookup:', err) webpackConfig = {} } @@ -105,14 +75,18 @@ exports.resolve = function (source, file, settings) { } } + log('Using config: ', webpackConfig) + // externals if (findExternal(source, webpackConfig.externals)) return { found: true, path: null } + // otherwise, resolve "normally" var resolver = createResolver(webpackConfig.resolve || {}) try { return { found: true, path: resolver.resolveSync(path.dirname(file), source) } } catch (err) { + log('Error during module resolution:', err) return { found: false } } } @@ -209,6 +183,50 @@ var defaultMains = [ 'webpack', 'browser', 'web', 'browserify', ['jam', 'main'], 'main', ] +function findConfigPath(configPath, packageDir) { + var extensions = Object.keys(interpret.extensions).sort(function(a, b) { + return a === '.js' ? -1 : b === '.js' ? 1 : a.length - b.length + }) + , extension + + + if (configPath) { + // extensions is not reused below, so safe to mutate it here. + extensions.reverse() + extensions.forEach(function (maybeExtension) { + if (extension) { + return + } + + if (configPath.substr(-maybeExtension.length) === maybeExtension) { + extension = maybeExtension + } + }) + + // see if we've got an absolute path + if (!isAbsolute(configPath)) { + configPath = path.join(packageDir, configPath) + } + } else { + extensions.forEach(function (maybeExtension) { + if (extension) { + return + } + + var maybePath = path.resolve( + path.join(packageDir, 'webpack.config' + maybeExtension) + ) + if (fs.existsSync(maybePath)) { + configPath = maybePath + extension = maybeExtension + } + }) + } + + registerCompiler(interpret.extensions[extension]) + return configPath +} + function registerCompiler(moduleDescriptor) { if(moduleDescriptor) { if(typeof moduleDescriptor === 'string') { @@ -221,7 +239,7 @@ function registerCompiler(moduleDescriptor) { registerCompiler(moduleDescriptor[i]) break } catch(e) { - // do nothing + log('Failed to register compiler for moduleDescriptor[]:', i, moduleDescriptor) } } } diff --git a/resolvers/webpack/package.json b/resolvers/webpack/package.json index ecd45dff0b..d01fb294e5 100644 --- a/resolvers/webpack/package.json +++ b/resolvers/webpack/package.json @@ -25,6 +25,7 @@ "homepage": "https://github.com/benmosher/eslint-plugin-import#readme", "dependencies": { "array-find": "^1.0.0", + "debug": "^2.2.0", "enhanced-resolve": "~0.9.0", "find-root": "^0.1.1", "interpret": "^1.0.0", From b1d714c077b703d5cec4ed4cbd031ff78166a5f7 Mon Sep 17 00:00:00 2001 From: Ben Mosher Date: Thu, 2 Jun 2016 07:16:30 -0400 Subject: [PATCH 20/29] resolvers/webpack/v0.3.1 --- resolvers/webpack/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resolvers/webpack/package.json b/resolvers/webpack/package.json index d01fb294e5..c97ef339df 100644 --- a/resolvers/webpack/package.json +++ b/resolvers/webpack/package.json @@ -1,6 +1,6 @@ { "name": "eslint-import-resolver-webpack", - "version": "0.3.0", + "version": "0.3.1", "description": "Resolve paths to dependencies, given a webpack.config.js. Plugin for eslint-plugin-import.", "main": "index.js", "scripts": { From 6d447ff8204230b31b754397a4f368df39bf4575 Mon Sep 17 00:00:00 2001 From: Ben Mosher Date: Fri, 3 Jun 2016 06:30:51 -0400 Subject: [PATCH 21/29] changelog for 0.3.1 --- resolvers/webpack/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/resolvers/webpack/CHANGELOG.md b/resolvers/webpack/CHANGELOG.md index cff7b2d033..76c6ab5a1b 100644 --- a/resolvers/webpack/CHANGELOG.md +++ b/resolvers/webpack/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this resolver will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). This change log adheres to standards from [Keep a CHANGELOG](http://keepachangelog.com). +## 0.3.1 - 2016-06-02 +### Added +- debug logging. run with `DEBUG=eslint-plugin-import:*` to see log output. + ## 0.3.0 - 2016-06-01 ### Changed - use `enhanced-resolve` to support additional plugins instead of re-implementing From 3994d477f60810041f2b1b82536e738f39411d07 Mon Sep 17 00:00:00 2001 From: Ben Mosher Date: Fri, 3 Jun 2016 06:55:51 -0400 Subject: [PATCH 22/29] resolvers/webpack: strip resource query (fixes #357) --- resolvers/webpack/CHANGELOG.md | 6 ++++++ resolvers/webpack/index.js | 6 ++++++ resolvers/webpack/test/loaders.js | 35 +++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+) create mode 100644 resolvers/webpack/test/loaders.js diff --git a/resolvers/webpack/CHANGELOG.md b/resolvers/webpack/CHANGELOG.md index 76c6ab5a1b..5cd110c566 100644 --- a/resolvers/webpack/CHANGELOG.md +++ b/resolvers/webpack/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this resolver will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). This change log adheres to standards from [Keep a CHANGELOG](http://keepachangelog.com). +## Unreleased +### Fixed +- strip resource query (#357, thanks @daltones) + ## 0.3.1 - 2016-06-02 ### Added - debug logging. run with `DEBUG=eslint-plugin-import:*` to see log output. @@ -36,9 +40,11 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel [#181]: https://github.com/benmosher/eslint-plugin-import/pull/181 [#164]: https://github.com/benmosher/eslint-plugin-import/pull/164 +[#357]: https://github.com/benmosher/eslint-plugin-import/issues/357 [#286]: https://github.com/benmosher/eslint-plugin-import/issues/286 [@gausie]: https://github.com/gausie [@jquense]: https://github.com/jquense [@taion]: https://github.com/taion [@GreenGremlin]: https://github.com/GreenGremlin +[@daltones]: https://github.com/daltones diff --git a/resolvers/webpack/index.js b/resolvers/webpack/index.js index 717537d704..48b33035e8 100644 --- a/resolvers/webpack/index.js +++ b/resolvers/webpack/index.js @@ -30,6 +30,12 @@ exports.resolve = function (source, file, settings) { source = source.slice(finalBang + 1) } + // strip resource query + var finalQuestionMark = source.lastIndexOf('?') + if (finalQuestionMark >= 0) { + source = source.slice(0, finalQuestionMark) + } + if (source in coreLibs) { return { found: true, path: coreLibs[source] } } diff --git a/resolvers/webpack/test/loaders.js b/resolvers/webpack/test/loaders.js new file mode 100644 index 0000000000..1d588c77cd --- /dev/null +++ b/resolvers/webpack/test/loaders.js @@ -0,0 +1,35 @@ +var chai = require('chai') + , expect = chai.expect + , path = require('path') + +var resolve = require('../index').resolve + + +var file = path.join(__dirname, 'files', 'dummy.js') + +describe("inline loader syntax", function () { + + it("strips bang-loaders", function () { + expect(resolve('css-loader!./src/main-module', file)).to.have.property('path') + .and.equal(path.join(__dirname, 'files', 'src', 'main-module.js')) + }) + + it("strips loader query string", function () { + expect(resolve('some-loader?param=value!./src/main-module', file)).to.have.property('path') + .and.equal(path.join(__dirname, 'files', 'src', 'main-module.js')) + }) + + it("strips resource query string", function () { + expect(resolve('./src/main-module?otherParam=otherValue', file)) + .to.have.property('path') + .and.equal(path.join(__dirname, 'files', 'src', 'main-module.js')) + }) + + it("strips everything", function () { + expect(resolve('some-loader?param=value!./src/main-module?otherParam=otherValue', file)) + .to.have.property('path') + .and.equal(path.join(__dirname, 'files', 'src', 'main-module.js')) + }) + +}) + From 21cec5ab1f28e5419dfc3809f927dc243ec7527e Mon Sep 17 00:00:00 2001 From: Jordan Gensler Date: Wed, 1 Jun 2016 12:09:07 -0700 Subject: [PATCH 23/29] [webpack-resolver] Allowing externals to be a function (closes #363) --- resolvers/webpack/CHANGELOG.md | 5 ++++- resolvers/webpack/index.js | 10 +++++++++- resolvers/webpack/test/externals.js | 6 ++++++ resolvers/webpack/test/files/webpack.config.js | 6 ++++++ 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/resolvers/webpack/CHANGELOG.md b/resolvers/webpack/CHANGELOG.md index 5cd110c566..657ed5f9a2 100644 --- a/resolvers/webpack/CHANGELOG.md +++ b/resolvers/webpack/CHANGELOG.md @@ -5,7 +5,8 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel ## Unreleased ### Fixed -- strip resource query (#357, thanks @daltones) +- strip resource query ([#357], thanks [@daltones]) +- allow `externals` to be defined as a function ([#363], thanks [@kesne]) ## 0.3.1 - 2016-06-02 ### Added @@ -34,6 +35,7 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel - `interpret` configs (such as `.babel.js`). Thanks to [@gausie] for the initial PR ([#164], ages ago! 😅) and [@jquense] for tests ([#278]). +[#363]: https://github.com/benmosher/eslint-plugin-import/pull/363 [#289]: https://github.com/benmosher/eslint-plugin-import/pull/289 [#287]: https://github.com/benmosher/eslint-plugin-import/pull/287 [#278]: https://github.com/benmosher/eslint-plugin-import/pull/278 @@ -48,3 +50,4 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel [@taion]: https://github.com/taion [@GreenGremlin]: https://github.com/GreenGremlin [@daltones]: https://github.com/daltones +[@kesne]: https://github.com/kesne diff --git a/resolvers/webpack/index.js b/resolvers/webpack/index.js index 48b33035e8..2e2d8becd4 100644 --- a/resolvers/webpack/index.js +++ b/resolvers/webpack/index.js @@ -170,7 +170,15 @@ function findExternal(source, externals) { } if (typeof externals === 'function') { - throw new Error('unable to handle function externals') + var functionExternalFound = false + externals.call(null, null, source, function(err, value) { + if (err) { + functionExternalFound = false + } else { + functionExternalFound = findExternal(source, value) + } + }) + return functionExternalFound } // else, vanilla object diff --git a/resolvers/webpack/test/externals.js b/resolvers/webpack/test/externals.js index a9a97b87cc..e2e61fbe19 100644 --- a/resolvers/webpack/test/externals.js +++ b/resolvers/webpack/test/externals.js @@ -19,6 +19,12 @@ describe("externals", function () { expect(resolved).to.have.property('path', null) }) + it("works on a function", function () { + var resolved = webpack.resolve('underscore', file) + expect(resolved).to.have.property('found', true) + expect(resolved).to.have.property('path', null) + }) + it("returns null for core modules", function () { var resolved = webpack.resolve('fs', file) expect(resolved).to.have.property('found', true) diff --git a/resolvers/webpack/test/files/webpack.config.js b/resolvers/webpack/test/files/webpack.config.js index f1ab03c6c5..5bc10be97d 100644 --- a/resolvers/webpack/test/files/webpack.config.js +++ b/resolvers/webpack/test/files/webpack.config.js @@ -13,5 +13,11 @@ module.exports = { externals: [ { 'jquery': 'jQuery' }, 'bootstrap', + function (context, request, callback) { + if (request === 'underscore') { + return callback(null, 'underscore'); + }; + callback(); + } ], } From badb0704d94d1617f36e4e9da624da6a41b32ccd Mon Sep 17 00:00:00 2001 From: Ben Mosher Date: Fri, 3 Jun 2016 09:50:43 -0400 Subject: [PATCH 24/29] Partially revert "Use `pkg-dir` instead of `findRoot`". Fixes #366. Reverts broken v1 resolver integration and errantly added pkg-dir as a devDependency. This reverts commit d53e45ff92377a0a6ddc6ed9ddfe0273e6585795. # Conflicts: # src/core/resolve.js --- package.json | 2 +- src/core/resolve.js | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index a1c91f84cf..74fbf29754 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,6 @@ "gulp-mocha": "^2.2.0", "istanbul": "^0.4.0", "mocha": "^2.2.1", - "pkg-dir": "^1.0.0", "redux": "^3.0.4", "rimraf": "2.5.2" }, @@ -78,6 +77,7 @@ "lodash.find": "^4.3.0", "lodash.findindex": "^4.3.0", "object-assign": "^4.0.1", + "pkg-dir": "^1.0.0", "pkg-up": "^1.0.0" } } diff --git a/src/core/resolve.js b/src/core/resolve.js index 318103cdaa..a3fe7407ff 100644 --- a/src/core/resolve.js +++ b/src/core/resolve.js @@ -57,6 +57,7 @@ function fileExistsWithCaseSync(filepath, cacheSettings) { } export function relative(modulePath, sourceFile, settings) { + const sourceDir = dirname(sourceFile) , cacheKey = sourceDir + hashObject(settings) + modulePath @@ -82,10 +83,10 @@ export function relative(modulePath, sourceFile, settings) { function v1() { try { const path = resolver.resolveImport(modulePath, sourceFile, config) - if (path === undefined) return { found: false, path: null } - return { found: true, path: null } + if (path === undefined) return { found: false } + return { found: true, path } } catch (err) { - return { found: false, path: null } + return { found: false } } } @@ -157,7 +158,6 @@ function requireResolver(name, modulePath) { // Try to resolve package with path, relative to closest package.json try { const packageDir = pkgDir.sync((modulePath)) - return require(join(packageDir, name)) } catch (err) { /* continue */ } From c092e78de6141689ad6e0ed6c8dd1ecf7e05a3fb Mon Sep 17 00:00:00 2001 From: Ben Mosher Date: Fri, 3 Jun 2016 09:55:26 -0400 Subject: [PATCH 25/29] Require resolvers relative to _source_ package json, not import. (#367) --- src/core/resolve.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/resolve.js b/src/core/resolve.js index a3fe7407ff..93b39d10f1 100644 --- a/src/core/resolve.js +++ b/src/core/resolve.js @@ -110,7 +110,7 @@ export function relative(modulePath, sourceFile, settings) { const resolvers = resolverReducer(configResolvers, new Map()) for (let [name, config] of resolvers) { - const resolver = requireResolver(name, modulePath) + const resolver = requireResolver(name, sourceFile) let { path: fullPath, found } = withResolver(resolver, config) @@ -147,7 +147,7 @@ function resolverReducer(resolvers, map) { throw new Error('invalid resolver config') } -function requireResolver(name, modulePath) { +function requireResolver(name, sourceFile) { // Try to resolve package with absolute path (/Volumes/....) if (isAbsolute(name)) { try { @@ -157,7 +157,7 @@ function requireResolver(name, modulePath) { // Try to resolve package with path, relative to closest package.json try { - const packageDir = pkgDir.sync((modulePath)) + const packageDir = pkgDir.sync(sourceFile) return require(join(packageDir, name)) } catch (err) { /* continue */ } From d5ccad0148f208e6efb4ab247127d730e2447430 Mon Sep 17 00:00:00 2001 From: Ben Mosher Date: Fri, 3 Jun 2016 09:57:41 -0400 Subject: [PATCH 26/29] resolve sourceFile relative to CWD, first (#367) --- src/core/resolve.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/resolve.js b/src/core/resolve.js index 93b39d10f1..d4063db504 100644 --- a/src/core/resolve.js +++ b/src/core/resolve.js @@ -157,7 +157,7 @@ function requireResolver(name, sourceFile) { // Try to resolve package with path, relative to closest package.json try { - const packageDir = pkgDir.sync(sourceFile) + const packageDir = pkgDir.sync(resolve(sourceFile)) return require(join(packageDir, name)) } catch (err) { /* continue */ } From 888808b2834bb8d831e7309e28319b7652983675 Mon Sep 17 00:00:00 2001 From: Luke Page Date: Sun, 5 Jun 2016 13:10:17 +0200 Subject: [PATCH 27/29] do not resolve the source directory. Fixes #367 (#369) --- src/core/resolve.js | 2 +- tests/files/foo-bar-resolver.js | 7 +++++++ tests/src/core/resolve.js | 8 ++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 tests/files/foo-bar-resolver.js diff --git a/src/core/resolve.js b/src/core/resolve.js index d4063db504..93b39d10f1 100644 --- a/src/core/resolve.js +++ b/src/core/resolve.js @@ -157,7 +157,7 @@ function requireResolver(name, sourceFile) { // Try to resolve package with path, relative to closest package.json try { - const packageDir = pkgDir.sync(resolve(sourceFile)) + const packageDir = pkgDir.sync(sourceFile) return require(join(packageDir, name)) } catch (err) { /* continue */ } diff --git a/tests/files/foo-bar-resolver.js b/tests/files/foo-bar-resolver.js new file mode 100644 index 0000000000..92421ba26c --- /dev/null +++ b/tests/files/foo-bar-resolver.js @@ -0,0 +1,7 @@ +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/src/core/resolve.js b/tests/src/core/resolve.js index cc2f6bd536..95025b34d0 100644 --- a/tests/src/core/resolve.js +++ b/tests/src/core/resolve.js @@ -10,6 +10,14 @@ describe('resolve', 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'}) + ) + + expect(file).to.equal(utils.testFilePath('./bar.jsx')) + }) + it('respects import/resolve extensions', function () { var file = resolve( './jsx/MyCoolComponent' , utils.testContext({ 'import/resolve': { 'extensions': ['.jsx'] }}) From 1ce82718a4b4d00131e7a14eaaa7b2ad5deb2834 Mon Sep 17 00:00:00 2001 From: Ben Mosher Date: Thu, 9 Jun 2016 05:37:51 -0400 Subject: [PATCH 28/29] markdown fixes for readme resolver --- README.md | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index ebbc84ed43..0181a4275a 100644 --- a/README.md +++ b/README.md @@ -125,11 +125,11 @@ resolvers are just npm packages, so [third party packages are supported](https:/ You can reference resolvers in several ways(in order of precedence): -1. With an absolute path to resolver, used as a `computed property` name, which is supported since Node v4: +- with an absolute path to resolver, used as a `computed property` name, which is supported since Node v4: -`.eslintrc.js`: ```js -{ +// .eslintrc.js +module.exports = { settings: { 'import/resolver': { [path.resolve('../../../my-resolver')]: { someConfig: value } @@ -138,12 +138,11 @@ You can reference resolvers in several ways(in order of precedence): } ``` -2. With a path relative to the closest `package.json` file: - +- with a path relative to the closest `package.json` file: -`.eslintrc.js`: ```js -{ +// .eslintrc.js +module.exports = { settings: { 'import/resolver': { './my-resolver': { someConfig: value } @@ -152,17 +151,18 @@ You can reference resolvers in several ways(in order of precedence): } ``` -`.eslintrc.yml`: + ```yaml +# .eslintrc.yml settings: import/resolver: './my-resolver' ``` -3. With an npm module name, like `my-awesome-npm-module`: +- with an npm module name, like `my-awesome-npm-module`: -`.eslintrc.js`: ```js -{ +// .eslintrc.js +module.exports = { settings: { 'import/resolver': { 'my-awesome-npm-module': { someConfig: value } @@ -171,17 +171,19 @@ settings: } ``` -`.eslintrc.yml`: + ```yaml +# .eslintrc.yml settings: import/resolver: 'my-awesome-npm-module' ``` -4. As a conventional `eslint-import-resolver` name, like `eslint-import-resolver-foo`: +- as a conventional `eslint-import-resolver` name, like `eslint-import-resolver-foo`: + -`.eslintrc.js`: ```js -{ +// .eslintrc.js +module.exports = { settings: { 'import/resolver': { foo: { someConfig: value } From a36c576b345aca8a4a069398fb7688de906ac187 Mon Sep 17 00:00:00 2001 From: Ben Mosher Date: Thu, 9 Jun 2016 05:41:09 -0400 Subject: [PATCH 29/29] v1.9.0 bump --- CHANGELOG.md | 6 +++++- package.json | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 48a0d7505b..7fc2526f58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ This project adheres to [Semantic Versioning](http://semver.org/). This change log adheres to standards from [Keep a CHANGELOG](http://keepachangelog.com). ## [Unreleased] + + +## [1.9.0] - 2016-06-10 ### Added - Added support TomDoc comments to [`no-deprecated`]. ([#321], thanks [@josh]) - Added support for loading custom resolvers ([#314], thanks [@le0nik]) @@ -265,7 +268,8 @@ for info on changes for earlier releases. [#119]: https://github.com/benmosher/eslint-plugin-import/issues/119 [#89]: https://github.com/benmosher/eslint-plugin-import/issues/89 -[Unreleased]: https://github.com/benmosher/eslint-plugin-import/compare/v1.8.1...HEAD +[Unreleased]: https://github.com/benmosher/eslint-plugin-import/compare/v1.9.0...HEAD +[1.9.0]: https://github.com/benmosher/eslint-plugin-import/compare/v1.8.1...v1.9.0 [1.8.1]: https://github.com/benmosher/eslint-plugin-import/compare/v1.8.0...v1.8.1 [1.8.0]: https://github.com/benmosher/eslint-plugin-import/compare/v1.7.0...v1.8.0 [1.7.0]: https://github.com/benmosher/eslint-plugin-import/compare/v1.6.1...v1.7.0 diff --git a/package.json b/package.json index 74fbf29754..6eb459d0d9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eslint-plugin-import", - "version": "1.8.1", + "version": "1.9.0", "description": "Import with sanity.", "main": "lib/index.js", "directories": {