From 513a488ea7b5fdbd6b5b42386307ef9110a1bc00 Mon Sep 17 00:00:00 2001 From: Daniele Zanni Date: Fri, 18 May 2018 12:32:33 +1000 Subject: [PATCH 01/50] Fixed flow types imports --- src/rules/named.js | 3 +++ tests/files/flowtypes.js | 3 +++ tests/src/rules/named.js | 8 ++++++++ 3 files changed, 14 insertions(+) diff --git a/src/rules/named.js b/src/rules/named.js index 8c2acd714e..f0151a89d8 100644 --- a/src/rules/named.js +++ b/src/rules/named.js @@ -30,6 +30,9 @@ module.exports = { node.specifiers.forEach(function (im) { if (im.type !== type) return + // ignore type imports + if(im.importKind === 'type') return + const deepLookup = imports.hasDeep(im[key].name) if (!deepLookup.found) { diff --git a/tests/files/flowtypes.js b/tests/files/flowtypes.js index 7ada3482b1..2df2471475 100644 --- a/tests/files/flowtypes.js +++ b/tests/files/flowtypes.js @@ -10,3 +10,6 @@ export type MyType = { export interface MyInterface {} export class MyClass {} + +export opaque type MyOpaqueType: string = string; + diff --git a/tests/src/rules/named.js b/tests/src/rules/named.js index 4fdd3434f9..fce5230933 100644 --- a/tests/src/rules/named.js +++ b/tests/src/rules/named.js @@ -72,6 +72,14 @@ ruleTester.run('named', rule, { code: 'import type { MissingType } from "./flowtypes"', parser: 'babel-eslint', }), + test({ + code: 'import type { MyOpaqueType } from "./flowtypes"', + parser: 'babel-eslint', + }), + test({ + code: 'import { type MyOpaqueType, MyClass } from "./flowtypes"', + parser: 'babel-eslint', + }), // TypeScript test({ From 96500b84518f2e2802a79f673da35e5625bb8c3a Mon Sep 17 00:00:00 2001 From: Daniele Zanni Date: Fri, 18 May 2018 18:39:01 +1000 Subject: [PATCH 02/50] Added missing space --- src/rules/named.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rules/named.js b/src/rules/named.js index f0151a89d8..57e4f1d9ef 100644 --- a/src/rules/named.js +++ b/src/rules/named.js @@ -31,7 +31,7 @@ module.exports = { if (im.type !== type) return // ignore type imports - if(im.importKind === 'type') return + if (im.importKind === 'type') return const deepLookup = imports.hasDeep(im[key].name) From 1d9ae51f9f305ed54c9b36d1c6a883392ea94d8e Mon Sep 17 00:00:00 2001 From: syymza Date: Fri, 18 May 2018 22:34:05 +1000 Subject: [PATCH 03/50] Added test for mixed flow imports --- tests/src/rules/named.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/src/rules/named.js b/tests/src/rules/named.js index fce5230933..cb1a5b843b 100644 --- a/tests/src/rules/named.js +++ b/tests/src/rules/named.js @@ -270,6 +270,12 @@ ruleTester.run('named', rule, { }], }), + test({ + code: 'import { type MyOpaqueType, MyMissingClass } from "./flowtypes"', + parser: 'babel-eslint', + errors: ["MyMissingClass not found in './flowtypes'"], + }), + // jsnext test({ code: '/*jsnext*/ import { createSnorlax } from "redux"', From 3b04d5fab6c095e7f0f99488665d90e285872271 Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Mon, 25 Jun 2018 14:33:43 -0700 Subject: [PATCH 04/50] [Refactor] add explicit support for RestElement alongside ExperimentalRestProperty --- src/rules/namespace.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/rules/namespace.js b/src/rules/namespace.js index 93e5891594..a1d5b6d813 100644 --- a/src/rules/namespace.js +++ b/src/rules/namespace.js @@ -58,7 +58,7 @@ module.exports = { return } - for (let specifier of declaration.specifiers) { + for (const specifier of declaration.specifiers) { switch (specifier.type) { case 'ImportNamespaceSpecifier': if (!imports.size) { @@ -160,8 +160,12 @@ module.exports = { if (pattern.type !== 'ObjectPattern') return - for (let property of pattern.properties) { - if (property.type === 'ExperimentalRestProperty' || !property.key) { + for (const property of pattern.properties) { + if ( + property.type === 'ExperimentalRestProperty' + || property.type === 'RestElement' + || !property.key + ) { continue } From 7abb1e1c9ec95dcad44bf4882e05b094b7f67400 Mon Sep 17 00:00:00 2001 From: Gajus Kuizinas Date: Tue, 26 Jun 2018 18:33:44 +0100 Subject: [PATCH 05/50] feat: make no-cycle ignore Flow imports --- src/rules/no-cycle.js | 4 ++++ tests/src/rules/no-cycle.js | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/rules/no-cycle.js b/src/rules/no-cycle.js index bbc251e388..ccf77dcf2e 100644 --- a/src/rules/no-cycle.js +++ b/src/rules/no-cycle.js @@ -30,6 +30,10 @@ module.exports = { function checkSourceValue(sourceNode, importer) { const imported = Exports.get(sourceNode.value, context) + if (sourceNode.parent.importKind === 'type') { + return // no Flow import resolution + } + if (imported == null) { return // no-unresolved territory } diff --git a/tests/src/rules/no-cycle.js b/tests/src/rules/no-cycle.js index ae45ba36ec..4ee4daacb6 100644 --- a/tests/src/rules/no-cycle.js +++ b/tests/src/rules/no-cycle.js @@ -36,6 +36,10 @@ ruleTester.run('no-cycle', rule, { code: 'import { foo } from "./depth-two"', options: [{ maxDepth: 1 }], }), + test({ + code: 'import type { FooType } from "./depth-one"', + parser: 'babel-eslint', + }), ], invalid: [ test({ From 60f65979fae29fc38d11cd79ade6336037a789ea Mon Sep 17 00:00:00 2001 From: Gajus Kuizinas Date: Tue, 26 Jun 2018 19:30:36 +0100 Subject: [PATCH 06/50] fix: handly possible undefined parent --- src/rules/no-cycle.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rules/no-cycle.js b/src/rules/no-cycle.js index ccf77dcf2e..a925f98713 100644 --- a/src/rules/no-cycle.js +++ b/src/rules/no-cycle.js @@ -30,7 +30,7 @@ module.exports = { function checkSourceValue(sourceNode, importer) { const imported = Exports.get(sourceNode.value, context) - if (sourceNode.parent.importKind === 'type') { + if (sourceNode.parent && sourceNode.parent.importKind === 'type') { return // no Flow import resolution } From 2c1886e0094159beefc7c6571db83872590b1590 Mon Sep 17 00:00:00 2001 From: Pirasis <1pete@users.noreply.github.com> Date: Fri, 29 Jun 2018 21:13:58 +0700 Subject: [PATCH 07/50] make rule `no-useless-path-segments` work with commonjs --- src/rules/no-useless-path-segments.js | 10 +++++ tests/src/rules/no-useless-path-segments.js | 47 +++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/src/rules/no-useless-path-segments.js b/src/rules/no-useless-path-segments.js index b9c4eedda0..5872b2d1c3 100644 --- a/src/rules/no-useless-path-segments.js +++ b/src/rules/no-useless-path-segments.js @@ -39,6 +39,16 @@ module.exports = { url: docsUrl('no-useless-path-segments'), }, + schema: [ + { + type: 'object', + properties: { + commonjs: { type: 'boolean' }, + }, + additionalProperties: false, + }, + ], + fixable: 'code', }, diff --git a/tests/src/rules/no-useless-path-segments.js b/tests/src/rules/no-useless-path-segments.js index 1f4229f5ee..ed20440012 100644 --- a/tests/src/rules/no-useless-path-segments.js +++ b/tests/src/rules/no-useless-path-segments.js @@ -7,6 +7,10 @@ const rule = require('rules/no-useless-path-segments') function runResolverTests(resolver) { ruleTester.run(`no-useless-path-segments (${resolver})`, rule, { valid: [ + // commonjs with default options + test({ code: 'require("./../files/malformed.js")' }), + + // esmodule test({ code: 'import "./malformed.js"' }), test({ code: 'import "./test-module"' }), test({ code: 'import "./bar/"' }), @@ -16,6 +20,49 @@ function runResolverTests(resolver) { ], invalid: [ + // commonjs + test({ + code: 'require("./../files/malformed.js")', + options: [{ commonjs: true }], + errors: [ 'Useless path segments for "./../files/malformed.js", should be "../files/malformed.js"'], + }), + test({ + code: 'require("./../files/malformed")', + options: [{ commonjs: true }], + errors: [ 'Useless path segments for "./../files/malformed", should be "../files/malformed"'], + }), + test({ + code: 'require("../files/malformed.js")', + options: [{ commonjs: true }], + errors: [ 'Useless path segments for "../files/malformed.js", should be "./malformed.js"'], + }), + test({ + code: 'require("../files/malformed")', + options: [{ commonjs: true }], + errors: [ 'Useless path segments for "../files/malformed", should be "./malformed"'], + }), + test({ + code: 'require("./test-module/")', + options: [{ commonjs: true }], + errors: [ 'Useless path segments for "./test-module/", should be "./test-module"'], + }), + test({ + code: 'require("./")', + options: [{ commonjs: true }], + errors: [ 'Useless path segments for "./", should be "."'], + }), + test({ + code: 'require("../")', + options: [{ commonjs: true }], + errors: [ 'Useless path segments for "../", should be ".."'], + }), + test({ + code: 'require("./deep//a")', + options: [{ commonjs: true }], + errors: [ 'Useless path segments for "./deep//a", should be "./deep/a"'], + }), + + // esmodule test({ code: 'import "./../files/malformed.js"', errors: [ 'Useless path segments for "./../files/malformed.js", should be "../files/malformed.js"'], From ce4b1af7c02aeb6097766786a1025d817663a54b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Berm=C3=BAdez=20Schettino?= Date: Wed, 11 Jul 2018 11:26:14 +0200 Subject: [PATCH 08/50] Fix format of changelog Updated version links. --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d384d5c390..2a7254bc70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -619,7 +619,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/v2.12.0...HEAD +[Unreleased]: https://github.com/benmosher/eslint-plugin-import/compare/v2.13.0...HEAD +[2.13.0]: https://github.com/benmosher/eslint-plugin-import/compare/v2.12.0...v2.13.0 [2.12.0]: https://github.com/benmosher/eslint-plugin-import/compare/v2.11.0...v2.12.0 [2.11.0]: https://github.com/benmosher/eslint-plugin-import/compare/v2.10.0...v2.11.0 [2.10.0]: https://github.com/benmosher/eslint-plugin-import/compare/v2.9.0...v2.10.0 From 81bf977ffc47980ed597e8bcba1315ccc5968226 Mon Sep 17 00:00:00 2001 From: Chris Lloyd Date: Wed, 11 Jul 2018 09:50:27 -0700 Subject: [PATCH 09/50] [no-relative-parent-imports] Resolve paths This changes the rule to resolve paths before emitting an error. While this means the error will trigger less often (before we could report an error even if the file didn't exist on disk yet) I think it's a fine tradeoff so that it can be useful in more situations. --- src/rules/no-relative-parent-imports.js | 20 ++++++++++++--- tests/src/rules/no-relative-parent-imports.js | 25 +++++++++++++++++++ 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/src/rules/no-relative-parent-imports.js b/src/rules/no-relative-parent-imports.js index 3153eeb784..6b58c97f5a 100644 --- a/src/rules/no-relative-parent-imports.js +++ b/src/rules/no-relative-parent-imports.js @@ -1,6 +1,7 @@ import moduleVisitor, { makeOptionsSchema } from 'eslint-module-utils/moduleVisitor' import docsUrl from '../docsUrl' -import { basename } from 'path' +import { basename, dirname, relative } from 'path' +import resolve from 'eslint-module-utils/resolve' import importType from '../core/importType' @@ -14,11 +15,24 @@ module.exports = { create: function noRelativePackages(context) { const myPath = context.getFilename() - if (myPath === '') return {} // can't cycle-check a non-file + if (myPath === '') return {} // can't check a non-file function checkSourceValue(sourceNode) { const depPath = sourceNode.value - if (importType(depPath, context) === 'parent') { + + if (importType(depPath, context) === 'external') { // ignore packages + return + } + + const absDepPath = resolve(depPath, context) + + if (!absDepPath) { // unable to resolve path + return + } + + const relDepPath = relative(dirname(myPath), absDepPath) + + if (importType(relDepPath, context) === 'parent') { context.report({ node: sourceNode, message: 'Relative imports from parent directories are not allowed. ' + diff --git a/tests/src/rules/no-relative-parent-imports.js b/tests/src/rules/no-relative-parent-imports.js index 6d7a2c2fae..8978230904 100644 --- a/tests/src/rules/no-relative-parent-imports.js +++ b/tests/src/rules/no-relative-parent-imports.js @@ -38,9 +38,18 @@ ruleTester.run('no-relative-parent-imports', rule, { test({ code: 'import("./app/index.js")', }), + test({ + code: 'import(".")', + }), + test({ + code: 'import("path")', + }), test({ code: 'import("package")', }), + test({ + code: 'import("@scope/package")', + }), ], invalid: [ @@ -69,5 +78,21 @@ ruleTester.run('no-relative-parent-imports', rule, { column: 8, } ], }), + test({ + code: 'import foo from "./../plugin.js"', + errors: [ { + message: 'Relative imports from parent directories are not allowed. Please either pass what you\'re importing through at runtime (dependency injection), move `index.js` to same directory as `./../plugin.js` or consider making `./../plugin.js` a package.', + line: 1, + column: 17 + }] + }), + test({ + code: 'import foo from "../../api/service"', + errors: [ { + message: 'Relative imports from parent directories are not allowed. Please either pass what you\'re importing through at runtime (dependency injection), move `index.js` to same directory as `../../api/service` or consider making `../../api/service` a package.', + line: 1, + column: 17 + }] + }) ], }) From 3b1a806c066832e43c5e86d8b506451c358fb4c5 Mon Sep 17 00:00:00 2001 From: Justin Anastos Date: Thu, 12 Jul 2018 16:54:35 -0400 Subject: [PATCH 10/50] test(order): Add failing test for typescript-eslint-parser --- tests/src/rules/order.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/src/rules/order.js b/tests/src/rules/order.js index fb3b788448..23487dac91 100644 --- a/tests/src/rules/order.js +++ b/tests/src/rules/order.js @@ -1260,5 +1260,21 @@ ruleTester.run('order', rule, { message: '`fs` import should occur before import of `async`', }], })), + // fix incorrect order with typescript-eslint-parser + test({ + code: ` + var async = require('async'); + var fs = require('fs'); + `, + output: ` + var fs = require('fs'); + var async = require('async'); + `, + parser: 'typescript-eslint-parser', + errors: [{ + ruleId: 'order', + message: '`fs` import should occur before import of `async`', + }], + }), ], }) From 8d02f323b6b828aed1e33fa303e9600c96b79d74 Mon Sep 17 00:00:00 2001 From: Justin Anastos Date: Thu, 12 Jul 2018 16:55:47 -0400 Subject: [PATCH 11/50] fix(rules/order): Use `.range` instead of `.start` and `.end` for autofixer `typescript-eslint-parser` does not add `.start` and `.end` to nodes like `babel-eslint`. They both include a `range` that can be used isntead. --- src/rules/order.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/rules/order.js b/src/rules/order.js index 81babd7fde..f925a20eb4 100644 --- a/src/rules/order.js +++ b/src/rules/order.js @@ -97,8 +97,8 @@ function findRootNode(node) { function findEndOfLineWithComments(sourceCode, node) { const tokensToEndOfLine = takeTokensAfterWhile(sourceCode, node, commentOnSameLineAs(node)) let endOfTokens = tokensToEndOfLine.length > 0 - ? tokensToEndOfLine[tokensToEndOfLine.length - 1].end - : node.end + ? tokensToEndOfLine[tokensToEndOfLine.length - 1].range[1] + : node.range[1] let result = endOfTokens for (let i = endOfTokens; i < sourceCode.text.length; i++) { if (sourceCode.text[i] === '\n') { @@ -121,7 +121,7 @@ function commentOnSameLineAs(node) { function findStartOfLineWithComments(sourceCode, node) { const tokensToEndOfLine = takeTokensBeforeWhile(sourceCode, node, commentOnSameLineAs(node)) - let startOfTokens = tokensToEndOfLine.length > 0 ? tokensToEndOfLine[0].start : node.start + let startOfTokens = tokensToEndOfLine.length > 0 ? tokensToEndOfLine[0].range[0] : node.range[0] let result = startOfTokens for (let i = startOfTokens - 1; i > 0; i--) { if (sourceCode.text[i] !== ' ' && sourceCode.text[i] !== '\t') { @@ -296,11 +296,11 @@ function fixNewLineAfterImport(context, previousImport) { const tokensToEndOfLine = takeTokensAfterWhile( context.getSourceCode(), prevRoot, commentOnSameLineAs(prevRoot)) - let endOfLine = prevRoot.end + let endOfLine = prevRoot.range[1] if (tokensToEndOfLine.length > 0) { - endOfLine = tokensToEndOfLine[tokensToEndOfLine.length - 1].end + endOfLine = tokensToEndOfLine[tokensToEndOfLine.length - 1].range[1] } - return (fixer) => fixer.insertTextAfterRange([prevRoot.start, endOfLine], '\n') + return (fixer) => fixer.insertTextAfterRange([prevRoot.range[0], endOfLine], '\n') } function removeNewLineAfterImport(context, currentImport, previousImport) { From 3feb54cfa20db3ed39b8a32e430b4ea3508eda8a Mon Sep 17 00:00:00 2001 From: Gajus Kuizinas Date: Sun, 29 Jul 2018 12:50:40 +0100 Subject: [PATCH 12/50] fix: add a workaround for ESLint < v5 --- src/rules/no-cycle.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/rules/no-cycle.js b/src/rules/no-cycle.js index a925f98713..1a70db2c70 100644 --- a/src/rules/no-cycle.js +++ b/src/rules/no-cycle.js @@ -34,6 +34,10 @@ module.exports = { return // no Flow import resolution } + if (sourceNode._babelType === 'Literal') { + return // no Flow import resolution, workaround for ESLint < 5.x + } + if (imported == null) { return // no-unresolved territory } From 2d4f651d6e2759e56e2826d874c697e008deaa9c Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Wed, 1 Aug 2018 23:13:23 -0700 Subject: [PATCH 13/50] [eslint-module-utils]: when parser settings are not an array, throw a better error message Fixes #1149. --- utils/ignore.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/utils/ignore.js b/utils/ignore.js index 88e4080dda..91cc731a81 100644 --- a/utils/ignore.js +++ b/utils/ignore.js @@ -24,8 +24,11 @@ function makeValidExtensionSet(settings) { // all alternate parser extensions are also valid if ('import/parsers' in settings) { for (let parser in settings['import/parsers']) { - settings['import/parsers'][parser] - .forEach(ext => exts.add(ext)) + const parserSettings = settings['import/parsers'][parser] + if (!Array.isArray(parserSettings)) { + throw new TypeError('"settings" for ' + parser + ' must be an array') + } + parserSettings.forEach(ext => exts.add(ext)) } } From f5bff7b14c52fdd91afe76865ecec955b1f96539 Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Thu, 9 Aug 2018 23:17:21 -0700 Subject: [PATCH 14/50] [fix] repeat fix from #797 for #717, in another place --- src/ExportMap.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/ExportMap.js b/src/ExportMap.js index 1cb5dc3e9c..66b212a211 100644 --- a/src/ExportMap.js +++ b/src/ExportMap.js @@ -38,7 +38,12 @@ export default class ExportMap { get size() { let size = this.namespace.size + this.reexports.size - this.dependencies.forEach(dep => size += dep().size) + this.dependencies.forEach(dep => { + const d = dep() + // CJS / ignored dependencies won't exist (#717) + if (d == null) return + size += d.size + }) return size } From 825234402a3dbe58138781c2f44c3933c59babfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Czap=20Bal=C3=A1zs?= Date: Tue, 31 Jul 2018 10:47:36 +0200 Subject: [PATCH 15/50] Add error to output when module loaded as resolver has invalid API --- tests/files/foo-bar-resolver-invalid.js | 1 + tests/src/core/resolve.js | 17 ++++++++++++++++- utils/resolve.js | 13 ++++++++++++- 3 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 tests/files/foo-bar-resolver-invalid.js diff --git a/tests/files/foo-bar-resolver-invalid.js b/tests/files/foo-bar-resolver-invalid.js new file mode 100644 index 0000000000..a6213d6678 --- /dev/null +++ b/tests/files/foo-bar-resolver-invalid.js @@ -0,0 +1 @@ +exports = {}; diff --git a/tests/src/core/resolve.js b/tests/src/core/resolve.js index 3c15303edf..b9a9063243 100644 --- a/tests/src/core/resolve.js +++ b/tests/src/core/resolve.js @@ -110,6 +110,22 @@ describe('resolve', function () { expect(testContextReports[0].loc).to.eql({ line: 1, column: 0 }) }) + it('reports loaded resolver with invalid interface', function () { + const resolverName = './foo-bar-resolver-invalid'; + const testContext = utils.testContext({ 'import/resolver': resolverName }); + 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: ${resolverName} with invalid interface loaded as resolver`) + expect(testContextReports[0].loc).to.eql({ line: 1, column: 0 }) + }) + it('respects import/resolve extensions', function () { const testContext = utils.testContext({ 'import/resolve': { 'extensions': ['.jsx'] }}) @@ -119,7 +135,6 @@ describe('resolve', function () { }) it('reports load exception in a user resolver', function () { - const testContext = utils.testContext({ 'import/resolver': './load-error-resolver' }) const testContextReports = [] testContext.report = function (reportInfo) { diff --git a/utils/resolve.js b/utils/resolve.js index b280ca2cfa..87a1eaea81 100644 --- a/utils/resolve.js +++ b/utils/resolve.js @@ -160,8 +160,19 @@ function requireResolver(name, sourceFile) { if (!resolver) { throw new Error(`unable to load resolver "${name}".`) + } + if (!isResolverValid(resolver)) { + throw new Error(`${name} with invalid interface loaded as resolver`) + } + + return resolver +} + +function isResolverValid(resolver) { + if (resolver.interfaceVersion === 2) { + return resolver.resolve && typeof resolver.resolve === 'function' } else { - return resolver; + return resolver.resolveImport && typeof resolver.resolveImport === 'function' } } From e30a7577bf46f8c44bb12118563e833fd1b69d06 Mon Sep 17 00:00:00 2001 From: Joshua Freedman Date: Thu, 2 Aug 2018 09:00:36 -0700 Subject: [PATCH 16/50] Add JSX check to namespace rule --- src/rules/namespace.js | 19 +++++++++++++++---- tests/src/rules/namespace.js | 21 +++++++++++++++++++++ 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/rules/namespace.js b/src/rules/namespace.js index a1d5b6d813..bbba2ce2ef 100644 --- a/src/rules/namespace.js +++ b/src/rules/namespace.js @@ -44,7 +44,7 @@ module.exports = { return { // pick up all imports at body entry time, to properly respect hoisting - 'Program': function ({ body }) { + Program: function ({ body }) { function processBodyStatement(declaration) { if (declaration.type !== 'ImportDeclaration') return @@ -83,7 +83,7 @@ module.exports = { }, // same as above, but does not add names to local map - 'ExportNamespaceSpecifier': function (namespace) { + ExportNamespaceSpecifier: function (namespace) { var declaration = importDeclaration(context) var imports = Exports.get(declaration.source.value, context) @@ -102,7 +102,7 @@ module.exports = { // todo: check for possible redefinition - 'MemberExpression': function (dereference) { + MemberExpression: function (dereference) { if (dereference.object.type !== 'Identifier') return if (!namespaces.has(dereference.object.name)) return @@ -146,7 +146,7 @@ module.exports = { }, - 'VariableDeclarator': function ({ id, init }) { + VariableDeclarator: function ({ id, init }) { if (init == null) return if (init.type !== 'Identifier') return if (!namespaces.has(init.name)) return @@ -193,6 +193,17 @@ module.exports = { testKey(id, namespaces.get(init.name)) }, + + JSXMemberExpression: function({object, property}) { + if (!namespaces.has(object.name)) return + var namespace = namespaces.get(object.name) + if (!namespace.has(property.name)) { + context.report({ + node: property, + message: makeMessage(property, [object.name]), + }) + } + }, } }, } diff --git a/tests/src/rules/namespace.js b/tests/src/rules/namespace.js index 1cfee2b54d..7fa8cfcdb9 100644 --- a/tests/src/rules/namespace.js +++ b/tests/src/rules/namespace.js @@ -104,6 +104,16 @@ const valid = [ parser: 'babel-eslint', }), + // JSX + test({ + code: 'import * as Names from "./named-exports"; const Foo = ', + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + }, + }), + ...SYNTAX_CASES, ] @@ -185,6 +195,17 @@ const invalid = [ errors: [`'default' not found in imported namespace 'ree'.`], }), + // JSX + test({ + code: 'import * as Names from "./named-exports"; const Foo = ', + errors: [error('e', 'Names')], + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + }, + }), + ] /////////////////////// From 59311419f0546a1f14929a6889a86ec4859486ae Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Mon, 13 Aug 2018 00:28:41 -0700 Subject: [PATCH 17/50] Changelog/package bumps --- CHANGELOG.md | 33 +++++++++++++++++++++++++++++++++ package.json | 2 +- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a7254bc70..3969ea3aac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,26 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel ## [Unreleased] +## [2.14.0] - 2018-08-13 +* 69e0187 (HEAD -> master, source/master, origin/master, origin/HEAD) Merge pull request #1151 from jf248/jsx +|\ +| * e30a757 (source/pr/1151, fork/jsx) Add JSX check to namespace rule +|/ +* 8252344 (source/pr/1148) Add error to output when module loaded as resolver has invalid API +### Added +- [`no-useless-path-segments`]: add commonJS (CJS) support ([#1128], thanks [@1pete]) +- [`namespace`]: add JSX check ([#1151], thanks [@jf248]) + +### Fixed +- [`no-cycle`]: ignore Flow imports ([#1126], thanks [@gajus]) +- fix Flow type imports ([#1106], thanks [@syymza]) +- [`no-relative-parent-imports`]: resolve paths ([#1135], thanks [@chrislloyd]) +- [`import/order`]: fix autofixer when using typescript-eslint-parser ([#1137], thanks [@justinanastos]) +- repeat fix from [#797] for [#717], in another place (thanks [@ljharb]) + +### Refactors +- add explicit support for RestElement alongside ExperimentalRestProperty (thanks [@ljharb]) + ## [2.13.0] - 2018-06-24 ### Added - Add ESLint 5 support ([#1122], thanks [@ai] and [@ljharb]) @@ -473,7 +493,13 @@ for info on changes for earlier releases. [`memo-parser`]: ./memo-parser/README.md +[#1151]: https://github.com/benmosher/eslint-plugin-import/pull/1151 +[#1137]: https://github.com/benmosher/eslint-plugin-import/pull/1137 +[#1135]: https://github.com/benmosher/eslint-plugin-import/pull/1135 +[#1128]: https://github.com/benmosher/eslint-plugin-import/pull/1128 +[#1126]: https://github.com/benmosher/eslint-plugin-import/pull/1126 [#1122]: https://github.com/benmosher/eslint-plugin-import/pull/1122 +[#1106]: https://github.com/benmosher/eslint-plugin-import/pull/1106 [#1093]: https://github.com/benmosher/eslint-plugin-import/pull/1093 [#1085]: https://github.com/benmosher/eslint-plugin-import/pull/1085 [#1068]: https://github.com/benmosher/eslint-plugin-import/pull/1068 @@ -486,6 +512,7 @@ for info on changes for earlier releases. [#858]: https://github.com/benmosher/eslint-plugin-import/pull/858 [#843]: https://github.com/benmosher/eslint-plugin-import/pull/843 [#871]: https://github.com/benmosher/eslint-plugin-import/pull/871 +[#797]: https://github.com/benmosher/eslint-plugin-import/pull/797 [#744]: https://github.com/benmosher/eslint-plugin-import/pull/744 [#742]: https://github.com/benmosher/eslint-plugin-import/pull/742 [#737]: https://github.com/benmosher/eslint-plugin-import/pull/737 @@ -558,6 +585,7 @@ for info on changes for earlier releases. [#842]: https://github.com/benmosher/eslint-plugin-import/issues/842 [#839]: https://github.com/benmosher/eslint-plugin-import/issues/839 [#720]: https://github.com/benmosher/eslint-plugin-import/issues/720 +[#717]: https://github.com/benmosher/eslint-plugin-import/issues/717 [#686]: https://github.com/benmosher/eslint-plugin-import/issues/686 [#671]: https://github.com/benmosher/eslint-plugin-import/issues/671 [#660]: https://github.com/benmosher/eslint-plugin-import/issues/660 @@ -734,3 +762,8 @@ for info on changes for earlier releases. [@hulkish]: https://github.com/hulkish [@chrislloyd]: https://github.com/chrislloyd [@ai]: https://github.com/ai +[@syymza]: https://github.com/syymza +[@justinanastos]: https://github.com/justinanastos +[@1pete]: https://github.com/1pete +[@gajus]: https://github.com/gajus +[@jf248]: https://github.com/jf248 diff --git a/package.json b/package.json index 7d39395a76..810084436e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eslint-plugin-import", - "version": "2.13.0", + "version": "2.14.0", "description": "Import with sanity.", "engines": { "node": ">=4" From b0b6125844e28e2b63752b590c50cd8fad262c74 Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Fri, 17 Aug 2018 13:30:00 -0700 Subject: [PATCH 18/50] [Fix] detect extraneous deps even when there are none in the first place Fixes #1161 --- src/rules/no-extraneous-dependencies.js | 6 +----- tests/src/rules/no-extraneous-dependencies.js | 10 ++++++++++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/rules/no-extraneous-dependencies.js b/src/rules/no-extraneous-dependencies.js index 9d51018e9a..ec9eedaa2d 100644 --- a/src/rules/no-extraneous-dependencies.js +++ b/src/rules/no-extraneous-dependencies.js @@ -176,11 +176,7 @@ module.exports = { create: function (context) { const options = context.options[0] || {} const filename = context.getFilename() - const deps = getDependencies(context, options.packageDir) - - if (!deps) { - return {} - } + const deps = getDependencies(context, options.packageDir) || extractDepFields({}) const depsOptions = { allowDevDeps: testConfig(options.devDependencies, filename) !== false, diff --git a/tests/src/rules/no-extraneous-dependencies.js b/tests/src/rules/no-extraneous-dependencies.js index 381b392cbf..10012f6b47 100644 --- a/tests/src/rules/no-extraneous-dependencies.js +++ b/tests/src/rules/no-extraneous-dependencies.js @@ -17,6 +17,7 @@ const packageFileWithSyntaxErrorMessage = (() => { const packageDirWithFlowTyped = path.join(__dirname, '../../files/with-flow-typed') const packageDirMonoRepoRoot = path.join(__dirname, '../../files/monorepo') const packageDirMonoRepoWithNested = path.join(__dirname, '../../files/monorepo/packages/nested-package') +const packageDirWithEmpty = path.join(__dirname, '../../files/empty') ruleTester.run('no-extraneous-dependencies', rule, { valid: [ @@ -263,5 +264,14 @@ ruleTester.run('no-extraneous-dependencies', rule, { message: "'react' should be listed in the project's dependencies. Run 'npm i -S react' to add it", }], }), + test({ + code: 'import "react";', + filename: path.join(packageDirWithEmpty, 'index.js'), + options: [{packageDir: packageDirWithEmpty}], + errors: [{ + ruleId: 'no-extraneous-dependencies', + message: "'react' should be listed in the project's dependencies. Run 'npm i -S react' to add it", + }], + }), ] }) From f7bd328f7b86c9f6d95c58c261b0b513df14bbd5 Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Fri, 17 Aug 2018 13:30:00 -0700 Subject: [PATCH 19/50] [Fix] detect extraneous deps even when there are none in the first place Fixes #1161 --- tests/files/empty/package.json | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 tests/files/empty/package.json diff --git a/tests/files/empty/package.json b/tests/files/empty/package.json new file mode 100644 index 0000000000..da86787ad3 --- /dev/null +++ b/tests/files/empty/package.json @@ -0,0 +1,4 @@ +{ + "name": "foo", + "version": "1.0.0" +} From 8d8c20a92d1255a0701f9f69d88309a5579cc228 Mon Sep 17 00:00:00 2001 From: st-sloth Date: Wed, 22 Aug 2018 23:55:21 +0500 Subject: [PATCH 20/50] fix(dynamic-import-chunkname): Add proper webpack comment parsing --- docs/rules/dynamic-import-chunkname.md | 19 +++ src/rules/dynamic-import-chunkname.js | 65 +++++++-- tests/src/rules/dynamic-import-chunkname.js | 141 ++++++++++++++++++-- 3 files changed, 204 insertions(+), 21 deletions(-) diff --git a/docs/rules/dynamic-import-chunkname.md b/docs/rules/dynamic-import-chunkname.md index 98b98871e8..b1757b4e52 100644 --- a/docs/rules/dynamic-import-chunkname.md +++ b/docs/rules/dynamic-import-chunkname.md @@ -28,6 +28,10 @@ import( /*webpackChunkName:"someModule"*/ 'someModule', ); +import( + /* webpackChunkName : "someModule" */ + 'someModule', +); // chunkname contains a 6 (forbidden by rule config) import( @@ -41,6 +45,12 @@ import( 'someModule', ); +// invalid syntax for webpack comment +import( + /* totally not webpackChunkName: "someModule" */ + 'someModule', +); + // single-line comment, not a block-style comment import( // webpackChunkName: "someModule" @@ -59,6 +69,15 @@ The following patterns are valid: /* webpackChunkName: "someOtherModule12345789" */ 'someModule', ); + import( + /* webpackChunkName: "someModule" */ + /* webpackPrefetch: true */ + 'someModule', + ); + import( + /* webpackChunkName: "someModule", webpackPrefetch: true */ + 'someModule', + ); ``` ## When Not To Use It diff --git a/src/rules/dynamic-import-chunkname.js b/src/rules/dynamic-import-chunkname.js index 867808f0b0..6f51ebbbd5 100644 --- a/src/rules/dynamic-import-chunkname.js +++ b/src/rules/dynamic-import-chunkname.js @@ -1,3 +1,4 @@ +import vm from 'vm' import docsUrl from '../docsUrl' module.exports = { @@ -27,8 +28,10 @@ module.exports = { const { importFunctions = [] } = config || {} const { webpackChunknameFormat = '[0-9a-zA-Z-_/.]+' } = config || {} - const commentFormat = ` webpackChunkName: "${webpackChunknameFormat}" ` - const commentRegex = new RegExp(commentFormat) + const paddedCommentRegex = /^ (\S[\s\S]+\S) $/ + const commentStyleRegex = /^( \w+: ("[^"]*"|\d+|false|true),?)+ $/ + const chunkSubstrFormat = ` webpackChunkName: "${webpackChunknameFormat}",? ` + const chunkSubstrRegex = new RegExp(chunkSubstrFormat) return { CallExpression(node) { @@ -40,7 +43,7 @@ module.exports = { const arg = node.arguments[0] const leadingComments = sourceCode.getComments(arg).leading - if (!leadingComments || leadingComments.length !== 1) { + if (!leadingComments || leadingComments.length === 0) { context.report({ node, message: 'dynamic imports require a leading comment with the webpack chunkname', @@ -48,20 +51,56 @@ module.exports = { return } - const comment = leadingComments[0] - if (comment.type !== 'Block') { - context.report({ - node, - message: 'dynamic imports require a /* foo */ style comment, not a // foo comment', - }) - return + let isChunknamePresent = false + + for (const comment of leadingComments) { + if (comment.type !== 'Block') { + context.report({ + node, + message: 'dynamic imports require a /* foo */ style comment, not a // foo comment', + }) + return + } + + if (!paddedCommentRegex.test(comment.value)) { + context.report({ + node, + message: `dynamic imports require a block comment padded with spaces - /* foo */`, + }) + return + } + + try { + // just like webpack itself does + vm.runInNewContext(`(function(){return {${comment.value}}})()`) + } + catch (error) { + context.report({ + node, + message: `dynamic imports require a "webpack" comment with valid syntax`, + }) + return + } + + if (!commentStyleRegex.test(comment.value)) { + context.report({ + node, + message: + `dynamic imports require a leading comment in the form /*${chunkSubstrFormat}*/`, + }) + return + } + + if (chunkSubstrRegex.test(comment.value)) { + isChunknamePresent = true + } } - const webpackChunkDefinition = comment.value - if (!webpackChunkDefinition.match(commentRegex)) { + if (!isChunknamePresent) { context.report({ node, - message: `dynamic imports require a leading comment in the form /*${commentFormat}*/`, + message: + `dynamic imports require a leading comment in the form /*${chunkSubstrFormat}*/`, }) } }, diff --git a/tests/src/rules/dynamic-import-chunkname.js b/tests/src/rules/dynamic-import-chunkname.js index 329401106a..6b0d448da9 100644 --- a/tests/src/rules/dynamic-import-chunkname.js +++ b/tests/src/rules/dynamic-import-chunkname.js @@ -18,8 +18,10 @@ const parser = 'babel-eslint' const noLeadingCommentError = 'dynamic imports require a leading comment with the webpack chunkname' const nonBlockCommentError = 'dynamic imports require a /* foo */ style comment, not a // foo comment' -const commentFormatError = `dynamic imports require a leading comment in the form /* webpackChunkName: "${commentFormat}" */` -const pickyCommentFormatError = `dynamic imports require a leading comment in the form /* webpackChunkName: "${pickyCommentFormat}" */` +const noPaddingCommentError = 'dynamic imports require a block comment padded with spaces - /* foo */' +const invalidSyntaxCommentError = 'dynamic imports require a "webpack" comment with valid syntax' +const commentFormatError = `dynamic imports require a leading comment in the form /* webpackChunkName: "${commentFormat}",? */` +const pickyCommentFormatError = `dynamic imports require a leading comment in the form /* webpackChunkName: "${pickyCommentFormat}",? */` ruleTester.run('dynamic-import-chunkname', rule, { valid: [ @@ -79,6 +81,56 @@ ruleTester.run('dynamic-import-chunkname', rule, { options, parser, }, + { + code: `import( + /* webpackChunkName: "someModule", webpackPrefetch: true */ + 'test' + )`, + options, + parser, + }, + { + code: `import( + /* webpackChunkName: "someModule", webpackPrefetch: true, */ + 'test' + )`, + options, + parser, + }, + { + code: `import( + /* webpackPrefetch: true, webpackChunkName: "someModule" */ + 'test' + )`, + options, + parser, + }, + { + code: `import( + /* webpackPrefetch: true, webpackChunkName: "someModule", */ + 'test' + )`, + options, + parser, + }, + { + code: `import( + /* webpackPrefetch: true */ + /* webpackChunkName: "someModule" */ + 'test' + )`, + options, + parser, + }, + { + code: `import( + /* webpackChunkName: "someModule" */ + /* webpackPrefetch: true */ + 'test' + )`, + options, + parser, + }, { code: `import( /* webpackChunkName: "someModule" */ @@ -124,7 +176,7 @@ ruleTester.run('dynamic-import-chunkname', rule, { options, parser, errors: [{ - message: commentFormatError, + message: invalidSyntaxCommentError, type: 'CallExpression', }], }, @@ -148,7 +200,7 @@ ruleTester.run('dynamic-import-chunkname', rule, { options, parser, errors: [{ - message: commentFormatError, + message: invalidSyntaxCommentError, type: 'CallExpression', }], }, @@ -164,6 +216,79 @@ ruleTester.run('dynamic-import-chunkname', rule, { type: 'CallExpression', }], }, + { + code: `import( + /*webpackChunkName: "someModule"*/ + 'someModule' + )`, + options, + parser, + errors: [{ + message: noPaddingCommentError, + type: 'CallExpression', + }], + }, + { + code: `import( + /* webpackChunkName : "someModule" */ + 'someModule' + )`, + options, + parser, + errors: [{ + message: commentFormatError, + type: 'CallExpression', + }], + }, + { + code: `import( + /* webpackChunkName: "someModule" ; */ + 'someModule' + )`, + options, + parser, + errors: [{ + message: invalidSyntaxCommentError, + type: 'CallExpression', + }], + }, + { + code: `import( + /* totally not webpackChunkName: "someModule" */ + 'someModule' + )`, + options, + parser, + errors: [{ + message: invalidSyntaxCommentError, + type: 'CallExpression', + }], + }, + { + code: `import( + /* webpackPrefetch: true */ + /* webpackChunk: "someModule" */ + 'someModule' + )`, + options, + parser, + errors: [{ + message: commentFormatError, + type: 'CallExpression', + }], + }, + { + code: `import( + /* webpackPrefetch: true, webpackChunk: "someModule" */ + 'someModule' + )`, + options, + parser, + errors: [{ + message: commentFormatError, + type: 'CallExpression', + }], + }, { code: `import( /* webpackChunkName: "someModule123" */ @@ -183,7 +308,7 @@ ruleTester.run('dynamic-import-chunkname', rule, { )`, options: multipleImportFunctionOptions, errors: [{ - message: commentFormatError, + message: invalidSyntaxCommentError, type: 'CallExpression', }], }, @@ -194,7 +319,7 @@ ruleTester.run('dynamic-import-chunkname', rule, { )`, options: multipleImportFunctionOptions, errors: [{ - message: commentFormatError, + message: invalidSyntaxCommentError, type: 'CallExpression', }], }, @@ -224,7 +349,7 @@ ruleTester.run('dynamic-import-chunkname', rule, { )`, options, errors: [{ - message: commentFormatError, + message: invalidSyntaxCommentError, type: 'CallExpression', }], }, @@ -246,7 +371,7 @@ ruleTester.run('dynamic-import-chunkname', rule, { )`, options, errors: [{ - message: commentFormatError, + message: invalidSyntaxCommentError, type: 'CallExpression', }], }, From 183aa0767ba74f48ab08f70fa2cadec4e2c3f0d2 Mon Sep 17 00:00:00 2001 From: Sandro Miguel Marques Date: Mon, 27 Aug 2018 19:42:29 +0100 Subject: [PATCH 21/50] Typo Changed segemnts to segments --- docs/rules/no-useless-path-segments.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/rules/no-useless-path-segments.md b/docs/rules/no-useless-path-segments.md index d0891ee187..b2ae82a3a7 100644 --- a/docs/rules/no-useless-path-segments.md +++ b/docs/rules/no-useless-path-segments.md @@ -1,6 +1,6 @@ # import/no-useless-path-segments -Use this rule to prevent unnecessary path segemnts in import and require statements. +Use this rule to prevent unnecessary path segments in import and require statements. ## Rule Details From 0764acd8ae31a25ea7679b77259c6051ec87c54f Mon Sep 17 00:00:00 2001 From: Steven Hargrove Date: Sun, 9 Sep 2018 15:21:10 -0400 Subject: [PATCH 22/50] use process.hrtime instead of Date.now (#1160) --- utils/ModuleCache.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/ModuleCache.js b/utils/ModuleCache.js index 19e6a21226..eba86d2585 100644 --- a/utils/ModuleCache.js +++ b/utils/ModuleCache.js @@ -14,7 +14,7 @@ class ModuleCache { * @param {[type]} result [description] */ set(cacheKey, result) { - this.map.set(cacheKey, { result, lastSeen: Date.now() }) + this.map.set(cacheKey, { result, lastSeen: process.hrtime() }) log('setting entry for', cacheKey) return result } @@ -23,7 +23,7 @@ class ModuleCache { if (this.map.has(cacheKey)) { const f = this.map.get(cacheKey) // check fresness - if (Date.now() - f.lastSeen < (settings.lifetime * 1000)) return f.result + if (process.hrtime(f.lastSeen)[0] < settings.lifetime) return f.result } else log('cache miss for', cacheKey) // cache miss return undefined From f04b7b6b0368f794f8dc0779d06f057aef4b8ff5 Mon Sep 17 00:00:00 2001 From: Fernando Maia Date: Sun, 9 Sep 2018 16:25:02 -0300 Subject: [PATCH 23/50] Add `no-named-export` + docs/tests (#1157) * Add `no-named-export` + docs/tests * Fix no-named-export docs missing quotes * Fix ruleId in no-named-export case test * Tighten no-named-export error message --- README.md | 2 + docs/rules/no-named-export.md | 77 +++++++++++++ src/index.js | 1 + src/rules/no-named-export.js | 33 ++++++ tests/src/rules/no-named-export.js | 179 +++++++++++++++++++++++++++++ 5 files changed, 292 insertions(+) create mode 100644 docs/rules/no-named-export.md create mode 100644 src/rules/no-named-export.js create mode 100644 tests/src/rules/no-named-export.js diff --git a/README.md b/README.md index 53b2640627..6f826a85b7 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,7 @@ This plugin intends to support linting of ES2015+ (ES6+) import/export syntax, a * Forbid unassigned imports ([`no-unassigned-import`]) * Forbid named default exports ([`no-named-default`]) * Forbid default exports ([`no-default-export`]) +* Forbid named exports ([`no-named-export`]) * Forbid anonymous values as default exports ([`no-anonymous-default-export`]) * Prefer named exports to be grouped together in a single export declaration ([`group-exports`]) * Enforce a leading comment with the webpackChunkName for dynamic imports ([`dynamic-import-chunkname`]) @@ -104,6 +105,7 @@ This plugin intends to support linting of ES2015+ (ES6+) import/export syntax, a [`no-anonymous-default-export`]: ./docs/rules/no-anonymous-default-export.md [`group-exports`]: ./docs/rules/group-exports.md [`no-default-export`]: ./docs/rules/no-default-export.md +[`no-named-export`]: ./docs/rules/no-named-export.md [`dynamic-import-chunkname`]: ./docs/rules/dynamic-import-chunkname.md ## Installation diff --git a/docs/rules/no-named-export.md b/docs/rules/no-named-export.md new file mode 100644 index 0000000000..b3a0ef8d63 --- /dev/null +++ b/docs/rules/no-named-export.md @@ -0,0 +1,77 @@ +# no-named-export + +Prohibit named exports. Mostly an inverse of [`no-default-export`]. + +[`no-default-export`]: ./no-default-export.md + +## Rule Details + +The following patterns are considered warnings: + +```javascript +// bad1.js + +// There is only a single module export and it's a named export. +export const foo = 'foo'; +``` + +```javascript +// bad2.js + +// There is more than one named export in the module. +export const foo = 'foo'; +export const bar = 'bar'; +``` + +```javascript +// bad3.js + +// There is more than one named export in the module. +const foo = 'foo'; +const bar = 'bar'; +export { foo, bar } +``` + +```javascript +// bad4.js + +// There is more than one named export in the module. +export * from './other-module' +``` + +```javascript +// bad5.js + +// There is a default and a named export. +export const foo = 'foo'; +const bar = 'bar'; +export default 'bar'; +``` + +The following patterns are not warnings: + +```javascript +// good1.js + +// There is only a single module export and it's a default export. +export default 'bar'; +``` + +```javascript +// good2.js + +// There is only a single module export and it's a default export. +const foo = 'foo'; +export { foo as default } +``` + +```javascript +// good3.js + +// There is only a single module export and it's a default export. +export default from './other-module'; +``` + +## When Not To Use It + +If you don't care if named imports are used, or if you prefer named imports over default imports. diff --git a/src/index.js b/src/index.js index 7df67867f5..f5794595d6 100644 --- a/src/index.js +++ b/src/index.js @@ -32,6 +32,7 @@ export const rules = { 'newline-after-import': require('./rules/newline-after-import'), 'prefer-default-export': require('./rules/prefer-default-export'), 'no-default-export': require('./rules/no-default-export'), + 'no-named-export': require('./rules/no-named-export'), 'no-dynamic-require': require('./rules/no-dynamic-require'), 'unambiguous': require('./rules/unambiguous'), 'no-unassigned-import': require('./rules/no-unassigned-import'), diff --git a/src/rules/no-named-export.js b/src/rules/no-named-export.js new file mode 100644 index 0000000000..2c9f68599c --- /dev/null +++ b/src/rules/no-named-export.js @@ -0,0 +1,33 @@ +import docsUrl from '../docsUrl' + +module.exports = { + meta: { + docs: { url: docsUrl('no-named-export') }, + }, + + create(context) { + // ignore non-modules + if (context.parserOptions.sourceType !== 'module') { + return {} + } + + const message = 'Named exports are not allowed.' + + return { + ExportAllDeclaration(node) { + context.report({node, message}) + }, + + ExportNamedDeclaration(node) { + if (node.specifiers.length === 0) { + return context.report({node, message}) + } + + const someNamed = node.specifiers.some(specifier => specifier.exported.name !== 'default') + if (someNamed) { + context.report({node, message}) + } + }, + } + }, +} diff --git a/tests/src/rules/no-named-export.js b/tests/src/rules/no-named-export.js new file mode 100644 index 0000000000..d8748d3f6b --- /dev/null +++ b/tests/src/rules/no-named-export.js @@ -0,0 +1,179 @@ +import { RuleTester } from 'eslint' +import { test } from '../utils' + +const ruleTester = new RuleTester() + , rule = require('rules/no-named-export') + +ruleTester.run('no-named-export', rule, { + valid: [ + test({ + code: 'export default function bar() {};', + }), + test({ + code: 'export { foo as default }', + }), + test({ + code: 'export default from "foo.js"', + parser: 'babel-eslint', + }), + + // no exports at all + test({ + code: `import * as foo from './foo';`, + }), + test({ + code: `import foo from './foo';`, + }), + test({ + code: `import {default as foo} from './foo';`, + }), + ], + invalid: [ + test({ + code: ` + export const foo = 'foo'; + export const bar = 'bar'; + `, + errors: [{ + ruleId: 'ExportNamedDeclaration', + message: 'Named exports are not allowed.', + }, { + ruleId: 'ExportNamedDeclaration', + message: 'Named exports are not allowed.', + }], + }), + test({ + code: ` + export const foo = 'foo'; + export default bar;`, + errors: [{ + ruleId: 'ExportNamedDeclaration', + message: 'Named exports are not allowed.', + }], + }), + test({ + code: ` + export const foo = 'foo'; + export function bar() {}; + `, + errors: [{ + ruleId: 'ExportNamedDeclaration', + message: 'Named exports are not allowed.', + }, { + ruleId: 'ExportNamedDeclaration', + message: 'Named exports are not allowed.', + }], + }), + test({ + code: `export const foo = 'foo';`, + errors: [{ + ruleId: 'ExportNamedDeclaration', + message: 'Named exports are not allowed.', + }], + }), + test({ + code: ` + const foo = 'foo'; + export { foo }; + `, + errors: [{ + ruleId: 'ExportNamedDeclaration', + message: 'Named exports are not allowed.', + }], + }), + test({ + code: `export { foo, bar }`, + errors: [{ + ruleId: 'ExportNamedDeclaration', + message: 'Named exports are not allowed.', + }], + }), + test({ + code: `export const { foo, bar } = item;`, + errors: [{ + ruleId: 'ExportNamedDeclaration', + message: 'Named exports are not allowed.', + }], + }), + test({ + code: `export const { foo, bar: baz } = item;`, + errors: [{ + ruleId: 'ExportNamedDeclaration', + message: 'Named exports are not allowed.', + }], + }), + test({ + code: `export const { foo: { bar, baz } } = item;`, + errors: [{ + ruleId: 'ExportNamedDeclaration', + message: 'Named exports are not allowed.', + }], + }), + test({ + code: ` + export const foo = item; + export { item }; + `, + errors: [{ + ruleId: 'ExportNamedDeclaration', + message: 'Named exports are not allowed.', + }, { + ruleId: 'ExportNamedDeclaration', + message: 'Named exports are not allowed.', + }], + }), + test({ + code: `export * from './foo';`, + errors: [{ + ruleId: 'ExportAllDeclaration', + message: 'Named exports are not allowed.', + }], + }), + test({ + code: `export const { foo } = { foo: "bar" };`, + errors: [{ + ruleId: 'ExportNamedDeclaration', + message: 'Named exports are not allowed.', + }], + }), + test({ + code: `export const { foo: { bar } } = { foo: { bar: "baz" } };`, + errors: [{ + ruleId: 'ExportNamedDeclaration', + message: 'Named exports are not allowed.', + }], + }), + test({ + code: 'export { a, b } from "foo.js"', + parser: 'babel-eslint', + errors: [{ + ruleId: 'ExportNamedDeclaration', + message: 'Named exports are not allowed.', + }], + }), + test({ + code: `export type UserId = number;`, + parser: 'babel-eslint', + errors: [{ + ruleId: 'ExportNamedDeclaration', + message: 'Named exports are not allowed.', + }], + }), + test({ + code: 'export foo from "foo.js"', + parser: 'babel-eslint', + errors: [{ + ruleId: 'ExportNamedDeclaration', + message: 'Named exports are not allowed.', + }], + }), + test({ + code: `export Memory, { MemoryValue } from './Memory'`, + parser: 'babel-eslint', + errors: [{ + ruleId: 'ExportNamedDeclaration', + message: 'Named exports are not allowed.', + }], + }), + ], +}) From e3a03deca3b78129b897ad53b4054eb09678258a Mon Sep 17 00:00:00 2001 From: wtgtybhertgeghgtwtg Date: Sun, 9 Sep 2018 12:34:23 -0700 Subject: [PATCH 24/50] Bump `pkg-dir`. (#1111) --- utils/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/package.json b/utils/package.json index d955c53680..360cc76132 100644 --- a/utils/package.json +++ b/utils/package.json @@ -26,6 +26,6 @@ "homepage": "https://github.com/benmosher/eslint-plugin-import#readme", "dependencies": { "debug": "^2.6.8", - "pkg-dir": "^1.0.0" + "pkg-dir": "^2.0.0" } } From e8954dbaacd9590a8c46e3fc8ba31056576302cd Mon Sep 17 00:00:00 2001 From: Pirasis Leelatanon <1pete@users.noreply.github.com> Date: Mon, 10 Sep 2018 02:43:44 +0700 Subject: [PATCH 25/50] make rule `no-relative-parent-imports` support windows (#1141) --- src/core/importType.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/importType.js b/src/core/importType.js index 62519d175d..89b162aad3 100644 --- a/src/core/importType.js +++ b/src/core/importType.js @@ -57,7 +57,7 @@ function isInternalModule(name, settings, path) { } function isRelativeToParent(name) { - return name.indexOf('../') === 0 + return /^\.\.[\\/]/.test(name) } const indexFiles = ['.', './', './index', './index.js'] @@ -66,7 +66,7 @@ function isIndex(name) { } function isRelativeToSibling(name) { - return name.indexOf('./') === 0 + return /^\.[\\/]/.test(name) } const typeTest = cond([ From d3a58f879bb5b1576ffee1054b4c99286999424c Mon Sep 17 00:00:00 2001 From: Paul Hine Date: Wed, 10 Oct 2018 13:58:06 +0200 Subject: [PATCH 26/50] Fix packageDir array support (#1176) --- CHANGELOG.md | 7 +++++++ src/rules/no-extraneous-dependencies.js | 7 +++++-- tests/files/monorepo/package.json | 3 +++ tests/src/rules/no-extraneous-dependencies.js | 16 ++++++++++++++++ 4 files changed, 31 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3969ea3aac..a0b8a590d9 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] +### Fixed +- [`no-extraneous-dependencies`]: `packageDir` option with array value was clobbering package deps instead of merging them ([#1175]/[#1176], thanks [@aravindet] & [@pzhine]) + ## [2.14.0] - 2018-08-13 * 69e0187 (HEAD -> master, source/master, origin/master, origin/HEAD) Merge pull request #1151 from jf248/jsx @@ -493,6 +496,7 @@ for info on changes for earlier releases. [`memo-parser`]: ./memo-parser/README.md +[#1176]: https://github.com/benmosher/eslint-plugin-import/pull/1176 [#1151]: https://github.com/benmosher/eslint-plugin-import/pull/1151 [#1137]: https://github.com/benmosher/eslint-plugin-import/pull/1137 [#1135]: https://github.com/benmosher/eslint-plugin-import/pull/1135 @@ -578,6 +582,7 @@ for info on changes for earlier releases. [#314]: https://github.com/benmosher/eslint-plugin-import/pull/314 [#912]: https://github.com/benmosher/eslint-plugin-import/pull/912 +[#1175]: https://github.com/benmosher/eslint-plugin-import/issues/1175 [#1058]: https://github.com/benmosher/eslint-plugin-import/issues/1058 [#931]: https://github.com/benmosher/eslint-plugin-import/issues/931 [#886]: https://github.com/benmosher/eslint-plugin-import/issues/886 @@ -767,3 +772,5 @@ for info on changes for earlier releases. [@1pete]: https://github.com/1pete [@gajus]: https://github.com/gajus [@jf248]: https://github.com/jf248 +[@aravindet]: https://github.com/aravindet +[@pzhine]: https://github.com/pzhine diff --git a/src/rules/no-extraneous-dependencies.js b/src/rules/no-extraneous-dependencies.js index ec9eedaa2d..528bb827ba 100644 --- a/src/rules/no-extraneous-dependencies.js +++ b/src/rules/no-extraneous-dependencies.js @@ -42,9 +42,12 @@ function getDependencies(context, packageDir) { if (!isEmpty(paths)) { // use rule config to find package.json paths.forEach(dir => { - Object.assign(packageContent, extractDepFields( + const _packageContent = extractDepFields( JSON.parse(fs.readFileSync(path.join(dir, 'package.json'), 'utf8')) - )) + ) + Object.keys(packageContent).forEach(depsKey => + Object.assign(packageContent[depsKey], _packageContent[depsKey]) + ) }) } else { // use closest package.json diff --git a/tests/files/monorepo/package.json b/tests/files/monorepo/package.json index 3ed889ddf5..cf0b87ffa6 100644 --- a/tests/files/monorepo/package.json +++ b/tests/files/monorepo/package.json @@ -1,5 +1,8 @@ { "private": true, + "dependencies": { + "right-pad": "^1.0.1" + }, "devDependencies": { "left-pad": "^1.2.0" } diff --git a/tests/src/rules/no-extraneous-dependencies.js b/tests/src/rules/no-extraneous-dependencies.js index 10012f6b47..c29c8e5bd0 100644 --- a/tests/src/rules/no-extraneous-dependencies.js +++ b/tests/src/rules/no-extraneous-dependencies.js @@ -90,6 +90,22 @@ ruleTester.run('no-extraneous-dependencies', rule, { code: 'import leftpad from "left-pad";', options: [{packageDir: packageDirMonoRepoRoot}], }), + test({ + code: 'import react from "react";', + options: [{packageDir: [packageDirMonoRepoRoot, packageDirMonoRepoWithNested]}], + }), + test({ + code: 'import leftpad from "left-pad";', + options: [{packageDir: [packageDirMonoRepoRoot, packageDirMonoRepoWithNested]}], + }), + test({ + code: 'import leftpad from "left-pad";', + options: [{packageDir: [packageDirMonoRepoWithNested, packageDirMonoRepoRoot]}], + }), + test({ + code: 'import rightpad from "right-pad";', + options: [{packageDir: [packageDirMonoRepoRoot, packageDirMonoRepoWithNested]}], + }), ], invalid: [ test({ From 78244fcc5dfa1d1d7987e26e7c560453bae328c0 Mon Sep 17 00:00:00 2001 From: Ben Mosher Date: Thu, 11 Oct 2018 07:25:10 -0400 Subject: [PATCH 27/50] note `__dirname` as a way to define `packageDir` fixes #1061 --- docs/rules/no-extraneous-dependencies.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/rules/no-extraneous-dependencies.md b/docs/rules/no-extraneous-dependencies.md index 5c3542ebd4..2b66aa25c0 100644 --- a/docs/rules/no-extraneous-dependencies.md +++ b/docs/rules/no-extraneous-dependencies.md @@ -29,10 +29,14 @@ You can also use an array of globs instead of literal booleans: When using an array of globs, the setting will be set to `true` (no errors reported) if the name of the file being linted matches a single glob in the array, and `false` otherwise. -Also there is one more option called `packageDir`, this option is to specify the path to the folder containing package.json and is relative to the current working directory. +Also there is one more option called `packageDir`, this option is to specify the path to the folder containing package.json. + +If provided as a relative path string, will be computed relative to the current working directory at linter execution time. If this is not ideal (does not work with some editor integrations), consider using `__dirname` to provide a path relative to your configuration. ```js "import/no-extraneous-dependencies": ["error", {"packageDir": './some-dir/'}] +// or +"import/no-extraneous-dependencies": ["error", {"packageDir": path.join(__dirname, 'some-dir')}] ``` It may also be an array of multiple paths, to support monorepos or other novel project From b4a2f11fcacc6b2f048da4b29cfc896e682f17d1 Mon Sep 17 00:00:00 2001 From: Ben Mosher Date: Thu, 11 Oct 2018 13:46:51 -0400 Subject: [PATCH 28/50] fix typescript build issue (#1180) * found: typescript resolver 1.1 requires tsconfig --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 810084436e..4f3722a950 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "cross-env": "^4.0.0", "eslint": "2.x - 5.x", "eslint-import-resolver-node": "file:./resolvers/node", - "eslint-import-resolver-typescript": "^1.0.2", + "eslint-import-resolver-typescript": "1.0.2", "eslint-import-resolver-webpack": "file:./resolvers/webpack", "eslint-module-utils": "file:./utils", "eslint-plugin-import": "2.x", @@ -66,7 +66,7 @@ "redux": "^3.0.4", "rimraf": "^2.6.2", "sinon": "^2.3.2", - "typescript": "^2.6.2", + "typescript": "~2.8.1", "typescript-eslint-parser": "^15.0.0" }, "peerDependencies": { From db471a85573a88e0bb9f4a1d53f40fed603651d1 Mon Sep 17 00:00:00 2001 From: Ivan Dudinov Date: Thu, 25 Oct 2018 13:57:33 +0300 Subject: [PATCH 29/50] Webpack Resolver fix for case config is an array of functions (#1220) * Added test for plugin-webpack-resolver: webpack config is an array of functions * plugin-webpack-resolver: handle case when webpack config is an array of functions * Updated Changelog * Updated call of webpack config function --- resolvers/webpack/CHANGELOG.md | 5 +++ resolvers/webpack/index.js | 10 ++++- resolvers/webpack/test/config.js | 11 +++++ .../files/webpack.function.config.multiple.js | 43 +++++++++++++++++++ 4 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 resolvers/webpack/test/files/webpack.function.config.multiple.js diff --git a/resolvers/webpack/CHANGELOG.md b/resolvers/webpack/CHANGELOG.md index 93246bf0b7..8ea232a3bd 100644 --- a/resolvers/webpack/CHANGELOG.md +++ b/resolvers/webpack/CHANGELOG.md @@ -4,6 +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 +### Fixed +- crash when webpack config is an array of functions ([#1219]/[#1220] by [@idudinov]) ## 0.10.1 - 2018-06-24 ### Fixed @@ -104,6 +106,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]). +[#1220]: https://github.com/benmosher/eslint-plugin-import/pull/1220 [#1091]: https://github.com/benmosher/eslint-plugin-import/pull/1091 [#969]: https://github.com/benmosher/eslint-plugin-import/pull/969 [#968]: https://github.com/benmosher/eslint-plugin-import/pull/968 @@ -121,6 +124,7 @@ 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 +[#1219]: https://github.com/benmosher/eslint-plugin-import/issues/1219 [#788]: https://github.com/benmosher/eslint-plugin-import/issues/788 [#767]: https://github.com/benmosher/eslint-plugin-import/issues/767 [#681]: https://github.com/benmosher/eslint-plugin-import/issues/681 @@ -147,3 +151,4 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel [@SkeLLLa]: https://github.com/SkeLLLa [@graingert]: https://github.com/graingert [@mattkrick]: https://github.com/mattkrick +[@idudinov]: https://github.com/idudinov diff --git a/resolvers/webpack/index.js b/resolvers/webpack/index.js index 4c9abc61d8..b1b0e45f67 100644 --- a/resolvers/webpack/index.js +++ b/resolvers/webpack/index.js @@ -87,10 +87,18 @@ exports.resolve = function (source, file, settings) { } if (typeof webpackConfig === 'function') { - webpackConfig = webpackConfig(env) + webpackConfig = webpackConfig(env, {}) } if (Array.isArray(webpackConfig)) { + webpackConfig = webpackConfig.map(cfg => { + if (typeof cfg === 'function') { + return cfg(env, {}) + } + + return cfg + }) + if (typeof configIndex !== 'undefined' && webpackConfig.length > configIndex) { webpackConfig = webpackConfig[configIndex] } diff --git a/resolvers/webpack/test/config.js b/resolvers/webpack/test/config.js index 2519daf8a8..16a4a6dda3 100644 --- a/resolvers/webpack/test/config.js +++ b/resolvers/webpack/test/config.js @@ -103,4 +103,15 @@ describe("config", function () { .and.equal(path.join(__dirname, 'files', 'some', 'goofy', 'path', 'bar.js')) }) + it('finds the config at option env when config is an array of functions', function() { + var settings = { + config: require(path.join(__dirname, './files/webpack.function.config.multiple.js')), + env: { + dummy: true, + }, + } + + expect(resolve('bar', file, settings)).to.have.property('path') + .and.equal(path.join(__dirname, 'files', 'some', 'goofy', 'path', 'bar.js')) + }) }) diff --git a/resolvers/webpack/test/files/webpack.function.config.multiple.js b/resolvers/webpack/test/files/webpack.function.config.multiple.js new file mode 100644 index 0000000000..4dbc94bbc9 --- /dev/null +++ b/resolvers/webpack/test/files/webpack.function.config.multiple.js @@ -0,0 +1,43 @@ +var path = require('path') +var pluginsTest = require('webpack-resolver-plugin-test') + +module.exports = [function(env) { + return { + resolve: { + alias: { + 'foo': path.join(__dirname, 'some', 'goofy', 'path', 'foo.js'), + 'bar': env ? path.join(__dirname, 'some', 'goofy', 'path', 'bar.js') : undefined, + 'some-alias': path.join(__dirname, 'some'), + }, + modules: [ + path.join(__dirname, 'src'), + path.join(__dirname, 'fallback'), + 'node_modules', + 'bower_components', + ], + modulesDirectories: ['node_modules', 'bower_components'], + root: path.join(__dirname, 'src'), + fallback: path.join(__dirname, 'fallback'), + }, + + externals: [ + { 'jquery': 'jQuery' }, + 'bootstrap', + function (context, request, callback) { + if (request === 'underscore') { + return callback(null, 'underscore') + } + callback() + }, + ], + + plugins: [ + new pluginsTest.ResolverPlugin([ + new pluginsTest.SimpleResolver( + path.join(__dirname, 'some', 'bar', 'bar.js'), + path.join(__dirname, 'some', 'bar') + ), + ]), + ], + } +}] From 64baa91bd934ffb072dd91e8408c2ce05912a715 Mon Sep 17 00:00:00 2001 From: Zhibin Liu Date: Thu, 15 Nov 2018 19:15:59 +0800 Subject: [PATCH 30/50] [import/named] fix destructuring assignemnt --- src/ExportMap.js | 4 ++++ tests/files/named-exports.js | 2 ++ tests/src/rules/named.js | 2 ++ 3 files changed, 8 insertions(+) diff --git a/src/ExportMap.js b/src/ExportMap.js index 66b212a211..563ff9e8c5 100644 --- a/src/ExportMap.js +++ b/src/ExportMap.js @@ -512,6 +512,10 @@ export function recursivePatternCapture(pattern, callback) { recursivePatternCapture(element, callback) }) break + + case 'AssignmentPattern': + callback(pattern.left) + break } } diff --git a/tests/files/named-exports.js b/tests/files/named-exports.js index 752092e0ad..f2881c10c5 100644 --- a/tests/files/named-exports.js +++ b/tests/files/named-exports.js @@ -14,6 +14,8 @@ export class ExportedClass { // destructuring exports export var { destructuredProp } = {} + , { destructingAssign = null } = {} + , { destructingAssign: destructingRenamedAssign = null } = {} , [ arrayKeyProp ] = [] , [ { deepProp } ] = [] , { arr: [ ,, deepSparseElement ] } = {} diff --git a/tests/src/rules/named.js b/tests/src/rules/named.js index cb1a5b843b..ed6dc9e049 100644 --- a/tests/src/rules/named.js +++ b/tests/src/rules/named.js @@ -22,6 +22,8 @@ ruleTester.run('named', rule, { test({code: 'import bar, { foo } from "./bar.js"'}), test({code: 'import {a, b, d} from "./named-exports"'}), test({code: 'import {ExportedClass} from "./named-exports"'}), + test({code: 'import { destructingAssign } from "./named-exports"'}), + test({code: 'import { destructingRenamedAssign } from "./named-exports"'}), test({code: 'import { ActionTypes } from "./qc"'}), test({code: 'import {a, b, c, d} from "./re-export"'}), From 9a13f811acfc375010c5d45e5655cc1538986904 Mon Sep 17 00:00:00 2001 From: Zhibin Liu Date: Fri, 16 Nov 2018 09:09:45 +0800 Subject: [PATCH 31/50] fix test --- tests/src/core/getExports.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/src/core/getExports.js b/tests/src/core/getExports.js index 3423fe3e11..3bda3d3db1 100644 --- a/tests/src/core/getExports.js +++ b/tests/src/core/getExports.js @@ -273,7 +273,7 @@ describe('ExportMap', function () { context('#size', function () { it('counts the names', () => expect(ExportMap.get('./named-exports', fakeContext)) - .to.have.property('size', 8)) + .to.have.property('size', 10)) it('includes exported namespace size', () => expect(ExportMap.get('./export-all', fakeContext)) .to.have.property('size', 1)) From 5101b73effbf3706495f62121a8719f0ea0e2c68 Mon Sep 17 00:00:00 2001 From: Zhibin Liu Date: Sun, 18 Nov 2018 23:09:52 +0800 Subject: [PATCH 32/50] [Rules] add meta.type for all rules --- src/rules/default.js | 1 + src/rules/dynamic-import-chunkname.js | 1 + src/rules/export.js | 1 + src/rules/exports-last.js | 1 + src/rules/extensions.js | 1 + src/rules/first.js | 3 ++- src/rules/group-exports.js | 1 + src/rules/max-dependencies.js | 1 + src/rules/named.js | 1 + src/rules/namespace.js | 1 + src/rules/newline-after-import.js | 1 + src/rules/no-absolute-path.js | 1 + src/rules/no-amd.js | 1 + src/rules/no-anonymous-default-export.js | 1 + src/rules/no-commonjs.js | 1 + src/rules/no-cycle.js | 1 + src/rules/no-default-export.js | 1 + src/rules/no-deprecated.js | 1 + src/rules/no-duplicates.js | 1 + src/rules/no-dynamic-require.js | 1 + src/rules/no-extraneous-dependencies.js | 1 + src/rules/no-internal-modules.js | 1 + src/rules/no-mutable-exports.js | 1 + src/rules/no-named-as-default-member.js | 1 + src/rules/no-named-as-default.js | 1 + src/rules/no-named-default.js | 1 + src/rules/no-named-export.js | 1 + src/rules/no-namespace.js | 1 + src/rules/no-nodejs-modules.js | 1 + src/rules/no-relative-parent-imports.js | 1 + src/rules/no-restricted-paths.js | 1 + src/rules/no-self-import.js | 1 + src/rules/no-unassigned-import.js | 1 + src/rules/no-unresolved.js | 1 + src/rules/no-useless-path-segments.js | 1 + src/rules/no-webpack-loader-syntax.js | 1 + src/rules/order.js | 1 + src/rules/prefer-default-export.js | 1 + src/rules/unambiguous.js | 1 + 39 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/rules/default.js b/src/rules/default.js index 83c0ea95e3..7e07800dae 100644 --- a/src/rules/default.js +++ b/src/rules/default.js @@ -3,6 +3,7 @@ import docsUrl from '../docsUrl' module.exports = { meta: { + type: 'problem', docs: { url: docsUrl('default'), }, diff --git a/src/rules/dynamic-import-chunkname.js b/src/rules/dynamic-import-chunkname.js index 6f51ebbbd5..44fb5611cc 100644 --- a/src/rules/dynamic-import-chunkname.js +++ b/src/rules/dynamic-import-chunkname.js @@ -3,6 +3,7 @@ import docsUrl from '../docsUrl' module.exports = { meta: { + type: 'suggestion', docs: { url: docsUrl('dynamic-import-chunkname'), }, diff --git a/src/rules/export.js b/src/rules/export.js index f6adf0ae83..db5c8c3c1b 100644 --- a/src/rules/export.js +++ b/src/rules/export.js @@ -3,6 +3,7 @@ import docsUrl from '../docsUrl' module.exports = { meta: { + type: 'problem', docs: { url: docsUrl('export'), }, diff --git a/src/rules/exports-last.js b/src/rules/exports-last.js index 2d74ab5f31..fc40cc8271 100644 --- a/src/rules/exports-last.js +++ b/src/rules/exports-last.js @@ -8,6 +8,7 @@ function isNonExportStatement({ type }) { module.exports = { meta: { + type: 'suggestion', docs: { url: docsUrl('exports-last'), }, diff --git a/src/rules/extensions.js b/src/rules/extensions.js index d50bd0ce8b..b72c91bad0 100644 --- a/src/rules/extensions.js +++ b/src/rules/extensions.js @@ -55,6 +55,7 @@ function buildProperties(context) { module.exports = { meta: { + type: 'suggestion', docs: { url: docsUrl('extensions'), }, diff --git a/src/rules/first.js b/src/rules/first.js index 7af7f330b3..7bcd1fa22e 100644 --- a/src/rules/first.js +++ b/src/rules/first.js @@ -2,6 +2,7 @@ import docsUrl from '../docsUrl' module.exports = { meta: { + type: 'suggestion', docs: { url: docsUrl('first'), }, @@ -105,7 +106,7 @@ module.exports = { insertSourceCode = insertSourceCode.trim() + insertSourceCode.match(/^(\s+)/)[0] } - insertFixer = lastLegalImp ? + insertFixer = lastLegalImp ? fixer.insertTextAfter(lastLegalImp, insertSourceCode) : fixer.insertTextBefore(body[0], insertSourceCode) const fixers = [insertFixer].concat(removeFixers) diff --git a/src/rules/group-exports.js b/src/rules/group-exports.js index 96fff24fed..d650fff877 100644 --- a/src/rules/group-exports.js +++ b/src/rules/group-exports.js @@ -1,6 +1,7 @@ import docsUrl from '../docsUrl' const meta = { + type: 'suggestion', docs: { url: docsUrl('group-exports'), }, diff --git a/src/rules/max-dependencies.js b/src/rules/max-dependencies.js index 9af8f7912e..7e1fdb1011 100644 --- a/src/rules/max-dependencies.js +++ b/src/rules/max-dependencies.js @@ -16,6 +16,7 @@ const countDependencies = (dependencies, lastNode, context) => { module.exports = { meta: { + type: 'suggestion', docs: { url: docsUrl('max-dependencies'), }, diff --git a/src/rules/named.js b/src/rules/named.js index 57e4f1d9ef..b1f261f32b 100644 --- a/src/rules/named.js +++ b/src/rules/named.js @@ -4,6 +4,7 @@ import docsUrl from '../docsUrl' module.exports = { meta: { + type: 'problem', docs: { url: docsUrl('named'), }, diff --git a/src/rules/namespace.js b/src/rules/namespace.js index bbba2ce2ef..598b530d02 100644 --- a/src/rules/namespace.js +++ b/src/rules/namespace.js @@ -5,6 +5,7 @@ import docsUrl from '../docsUrl' module.exports = { meta: { + type: 'problem', docs: { url: docsUrl('namespace'), }, diff --git a/src/rules/newline-after-import.js b/src/rules/newline-after-import.js index fda1bc7634..f5724ef4a3 100644 --- a/src/rules/newline-after-import.js +++ b/src/rules/newline-after-import.js @@ -45,6 +45,7 @@ function isClassWithDecorator(node) { module.exports = { meta: { + type: 'layout', docs: { url: docsUrl('newline-after-import'), }, diff --git a/src/rules/no-absolute-path.js b/src/rules/no-absolute-path.js index b66b8b203f..4b7a8fcc2a 100644 --- a/src/rules/no-absolute-path.js +++ b/src/rules/no-absolute-path.js @@ -4,6 +4,7 @@ import docsUrl from '../docsUrl' module.exports = { meta: { + type: 'suggestion', docs: { url: docsUrl('no-absolute-path'), }, diff --git a/src/rules/no-amd.js b/src/rules/no-amd.js index 3ccb2129de..df0d3aeb24 100644 --- a/src/rules/no-amd.js +++ b/src/rules/no-amd.js @@ -11,6 +11,7 @@ import docsUrl from '../docsUrl' module.exports = { meta: { + type: 'suggestion', docs: { url: docsUrl('no-amd'), }, diff --git a/src/rules/no-anonymous-default-export.js b/src/rules/no-anonymous-default-export.js index 34128a914a..1557404507 100644 --- a/src/rules/no-anonymous-default-export.js +++ b/src/rules/no-anonymous-default-export.js @@ -72,6 +72,7 @@ const defaults = Object.keys(defs) module.exports = { meta: { + type: 'suggestion', docs: { url: docsUrl('no-anonymous-default-export'), }, diff --git a/src/rules/no-commonjs.js b/src/rules/no-commonjs.js index 22939aa7bf..b6f11a7f0b 100644 --- a/src/rules/no-commonjs.js +++ b/src/rules/no-commonjs.js @@ -41,6 +41,7 @@ const schemaObject = { module.exports = { meta: { + type: 'suggestion', docs: { url: docsUrl('no-commonjs'), }, diff --git a/src/rules/no-cycle.js b/src/rules/no-cycle.js index 1a70db2c70..f769b862cc 100644 --- a/src/rules/no-cycle.js +++ b/src/rules/no-cycle.js @@ -10,6 +10,7 @@ import docsUrl from '../docsUrl' // todo: cache cycles / deep relationships for faster repeat evaluation module.exports = { meta: { + type: 'suggestion', docs: { url: docsUrl('no-cycle') }, schema: [makeOptionsSchema({ maxDepth:{ diff --git a/src/rules/no-default-export.js b/src/rules/no-default-export.js index 8d240ed6a1..e1c687c9f7 100644 --- a/src/rules/no-default-export.js +++ b/src/rules/no-default-export.js @@ -1,5 +1,6 @@ module.exports = { meta: { + type: 'suggestion', docs: {}, }, diff --git a/src/rules/no-deprecated.js b/src/rules/no-deprecated.js index ef96f41633..7a3130b20c 100644 --- a/src/rules/no-deprecated.js +++ b/src/rules/no-deprecated.js @@ -17,6 +17,7 @@ function getDeprecation(metadata) { module.exports = { meta: { + type: 'suggestion', docs: { url: docsUrl('no-deprecated'), }, diff --git a/src/rules/no-duplicates.js b/src/rules/no-duplicates.js index 72b305e677..4632ea0ec9 100644 --- a/src/rules/no-duplicates.js +++ b/src/rules/no-duplicates.js @@ -13,6 +13,7 @@ function checkImports(imported, context) { module.exports = { meta: { + type: 'problem', docs: { url: docsUrl('no-duplicates'), }, diff --git a/src/rules/no-dynamic-require.js b/src/rules/no-dynamic-require.js index 5726d72ca3..b9ccad27b3 100644 --- a/src/rules/no-dynamic-require.js +++ b/src/rules/no-dynamic-require.js @@ -15,6 +15,7 @@ function isStaticValue(arg) { module.exports = { meta: { + type: 'suggestion', docs: { url: docsUrl('no-dynamic-require'), }, diff --git a/src/rules/no-extraneous-dependencies.js b/src/rules/no-extraneous-dependencies.js index 528bb827ba..d2c7cac6ee 100644 --- a/src/rules/no-extraneous-dependencies.js +++ b/src/rules/no-extraneous-dependencies.js @@ -158,6 +158,7 @@ function testConfig(config, filename) { module.exports = { meta: { + type: 'problem', docs: { url: docsUrl('no-extraneous-dependencies'), }, diff --git a/src/rules/no-internal-modules.js b/src/rules/no-internal-modules.js index 3e28554faa..9987dfd5c5 100644 --- a/src/rules/no-internal-modules.js +++ b/src/rules/no-internal-modules.js @@ -7,6 +7,7 @@ import docsUrl from '../docsUrl' module.exports = { meta: { + type: 'suggestion', docs: { url: docsUrl('no-internal-modules'), }, diff --git a/src/rules/no-mutable-exports.js b/src/rules/no-mutable-exports.js index 6bd6941a79..0908162bd1 100644 --- a/src/rules/no-mutable-exports.js +++ b/src/rules/no-mutable-exports.js @@ -2,6 +2,7 @@ import docsUrl from '../docsUrl' module.exports = { meta: { + type: 'suggestion', docs: { url: docsUrl('no-mutable-exports'), }, diff --git a/src/rules/no-named-as-default-member.js b/src/rules/no-named-as-default-member.js index 17af25a6fe..b7c3c75827 100644 --- a/src/rules/no-named-as-default-member.js +++ b/src/rules/no-named-as-default-member.js @@ -14,6 +14,7 @@ import docsUrl from '../docsUrl' module.exports = { meta: { + type: 'suggestion', docs: { url: docsUrl('no-named-as-default-member'), }, diff --git a/src/rules/no-named-as-default.js b/src/rules/no-named-as-default.js index eb9769513f..ad6a8ee6d1 100644 --- a/src/rules/no-named-as-default.js +++ b/src/rules/no-named-as-default.js @@ -4,6 +4,7 @@ import docsUrl from '../docsUrl' module.exports = { meta: { + type: 'problem', docs: { url: docsUrl('no-named-as-default'), }, diff --git a/src/rules/no-named-default.js b/src/rules/no-named-default.js index e25cd49509..86f24ef6d1 100644 --- a/src/rules/no-named-default.js +++ b/src/rules/no-named-default.js @@ -2,6 +2,7 @@ import docsUrl from '../docsUrl' module.exports = { meta: { + type: 'suggestion', docs: { url: docsUrl('no-named-default'), }, diff --git a/src/rules/no-named-export.js b/src/rules/no-named-export.js index 2c9f68599c..2fa6392014 100644 --- a/src/rules/no-named-export.js +++ b/src/rules/no-named-export.js @@ -2,6 +2,7 @@ import docsUrl from '../docsUrl' module.exports = { meta: { + type: 'suggestion', docs: { url: docsUrl('no-named-export') }, }, diff --git a/src/rules/no-namespace.js b/src/rules/no-namespace.js index 76a11f92dc..3dbedca500 100644 --- a/src/rules/no-namespace.js +++ b/src/rules/no-namespace.js @@ -12,6 +12,7 @@ import docsUrl from '../docsUrl' module.exports = { meta: { + type: 'suggestion', docs: { url: docsUrl('no-namespace'), }, diff --git a/src/rules/no-nodejs-modules.js b/src/rules/no-nodejs-modules.js index e73ed379d0..125bb5f3f1 100644 --- a/src/rules/no-nodejs-modules.js +++ b/src/rules/no-nodejs-modules.js @@ -10,6 +10,7 @@ function reportIfMissing(context, node, allowed, name) { module.exports = { meta: { + type: 'suggestion', docs: { url: docsUrl('no-nodejs-modules'), }, diff --git a/src/rules/no-relative-parent-imports.js b/src/rules/no-relative-parent-imports.js index 6b58c97f5a..544525755e 100644 --- a/src/rules/no-relative-parent-imports.js +++ b/src/rules/no-relative-parent-imports.js @@ -7,6 +7,7 @@ import importType from '../core/importType' module.exports = { meta: { + type: 'suggestion', docs: { url: docsUrl('no-relative-parent-imports'), }, diff --git a/src/rules/no-restricted-paths.js b/src/rules/no-restricted-paths.js index 5b20c40d84..0d906f6318 100644 --- a/src/rules/no-restricted-paths.js +++ b/src/rules/no-restricted-paths.js @@ -7,6 +7,7 @@ import docsUrl from '../docsUrl' module.exports = { meta: { + type: 'problem', docs: { url: docsUrl('no-restricted-paths'), }, diff --git a/src/rules/no-self-import.js b/src/rules/no-self-import.js index 8a8620c9ae..b869d46e06 100644 --- a/src/rules/no-self-import.js +++ b/src/rules/no-self-import.js @@ -21,6 +21,7 @@ function isImportingSelf(context, node, requireName) { module.exports = { meta: { + type: 'problem', docs: { description: 'Forbid a module from importing itself', recommended: true, diff --git a/src/rules/no-unassigned-import.js b/src/rules/no-unassigned-import.js index ad081bd1be..5ea637e67b 100644 --- a/src/rules/no-unassigned-import.js +++ b/src/rules/no-unassigned-import.js @@ -54,6 +54,7 @@ function create(context) { module.exports = { create, meta: { + type: 'suggestion', docs: { url: docsUrl('no-unassigned-import'), }, diff --git a/src/rules/no-unresolved.js b/src/rules/no-unresolved.js index 2a5232a1cd..8436e4c92b 100644 --- a/src/rules/no-unresolved.js +++ b/src/rules/no-unresolved.js @@ -10,6 +10,7 @@ import docsUrl from '../docsUrl' module.exports = { meta: { + type: 'problem', docs: { url: docsUrl('no-unresolved'), }, diff --git a/src/rules/no-useless-path-segments.js b/src/rules/no-useless-path-segments.js index 5872b2d1c3..2ad207fada 100644 --- a/src/rules/no-useless-path-segments.js +++ b/src/rules/no-useless-path-segments.js @@ -35,6 +35,7 @@ const countRelParent = x => sumBy(x, v => v === '..') module.exports = { meta: { + type: 'suggestion', docs: { url: docsUrl('no-useless-path-segments'), }, diff --git a/src/rules/no-webpack-loader-syntax.js b/src/rules/no-webpack-loader-syntax.js index e89fc9c35c..723f472692 100644 --- a/src/rules/no-webpack-loader-syntax.js +++ b/src/rules/no-webpack-loader-syntax.js @@ -11,6 +11,7 @@ function reportIfNonStandard(context, node, name) { module.exports = { meta: { + type: 'problem', docs: { url: docsUrl('no-webpack-loader-syntax'), }, diff --git a/src/rules/order.js b/src/rules/order.js index f925a20eb4..5c68f1b310 100644 --- a/src/rules/order.js +++ b/src/rules/order.js @@ -362,6 +362,7 @@ function makeNewlinesBetweenReport (context, imported, newlinesBetweenImports) { module.exports = { meta: { + type: 'suggestion', docs: { url: docsUrl('order'), }, diff --git a/src/rules/prefer-default-export.js b/src/rules/prefer-default-export.js index f9cec8bf0b..0e31346f3b 100644 --- a/src/rules/prefer-default-export.js +++ b/src/rules/prefer-default-export.js @@ -4,6 +4,7 @@ import docsUrl from '../docsUrl' module.exports = { meta: { + type: 'suggestion', docs: { url: docsUrl('prefer-default-export'), }, diff --git a/src/rules/unambiguous.js b/src/rules/unambiguous.js index f89ebad9cf..7ec38c2cb2 100644 --- a/src/rules/unambiguous.js +++ b/src/rules/unambiguous.js @@ -8,6 +8,7 @@ import docsUrl from '../docsUrl' module.exports = { meta: { + type: 'suggestion', docs: { url: docsUrl('unambiguous'), }, From d290a87dd6e10227c5f352bd05dee0fb361cd5a6 Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Thu, 3 Jan 2019 11:19:03 -0800 Subject: [PATCH 33/50] [Dev Deps] update `babylon`, `coveralls`, `eslint-import-resolver-typescript`, `gulp`, `linklocal`, `nyc`, `redux`, `rimraf`, `sinon`, `typescript-eslint-parser` --- package.json | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 4f3722a950..7dfe80350d 100644 --- a/package.json +++ b/package.json @@ -48,26 +48,26 @@ "babel-plugin-istanbul": "^4.1.6", "babel-preset-es2015-argon": "latest", "babel-register": "^6.26.0", - "babylon": "6.15.0", + "babylon": "^6.15.0", "chai": "^3.5.0", - "coveralls": "^3.0.0", + "coveralls": "^3.0.2", "cross-env": "^4.0.0", "eslint": "2.x - 5.x", "eslint-import-resolver-node": "file:./resolvers/node", - "eslint-import-resolver-typescript": "1.0.2", + "eslint-import-resolver-typescript": "^1.0.2", "eslint-import-resolver-webpack": "file:./resolvers/webpack", "eslint-module-utils": "file:./utils", "eslint-plugin-import": "2.x", - "gulp": "^3.9.0", + "gulp": "^3.9.1", "gulp-babel": "6.1.2", - "linklocal": "^2.6.0", + "linklocal": "^2.8.2", "mocha": "^3.5.3", - "nyc": "^11.7.1", - "redux": "^3.0.4", - "rimraf": "^2.6.2", - "sinon": "^2.3.2", + "nyc": "^11.9.0", + "redux": "^3.7.2", + "rimraf": "^2.6.3", + "sinon": "^2.4.1", "typescript": "~2.8.1", - "typescript-eslint-parser": "^15.0.0" + "typescript-eslint-parser": "^21.0.2" }, "peerDependencies": { "eslint": "2.x - 5.x" From cf1f6f46f7d0fd6a9532c51d44d12ae08447cffd Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Thu, 3 Jan 2019 11:22:23 -0800 Subject: [PATCH 34/50] [Deps] update `debug`, `eslint-import-resolver-node`, `has`, `lodash`, `minimatch`, `resolve` --- package.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 7dfe80350d..dd54055335 100644 --- a/package.json +++ b/package.json @@ -74,15 +74,15 @@ }, "dependencies": { "contains-path": "^0.1.0", - "debug": "^2.6.8", + "debug": "^2.6.9", "doctrine": "1.5.0", - "eslint-import-resolver-node": "^0.3.1", + "eslint-import-resolver-node": "^0.3.2", "eslint-module-utils": "^2.2.0", - "has": "^1.0.1", - "lodash": "^4.17.4", - "minimatch": "^3.0.3", + "has": "^1.0.3", + "lodash": "^4.17.11", + "minimatch": "^3.0.4", "read-pkg-up": "^2.0.0", - "resolve": "^1.6.0" + "resolve": "^1.9.0" }, "nyc": { "require": [ From b686f9d823c417e98a824c4ff6bfd65c1582ec45 Mon Sep 17 00:00:00 2001 From: Ben Mosher Date: Mon, 14 Jan 2019 21:10:11 -0500 Subject: [PATCH 35/50] drop ESLint 2/3 from Travis/Appveyor because Typescript parser can't deal --- .travis.yml | 19 +++++++++++-------- appveyor.yml | 9 +++++---- package.json | 2 +- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/.travis.yml b/.travis.yml index ea8c60a593..03de81c6d4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,8 +10,8 @@ os: linux env: - ESLINT_VERSION=5 - ESLINT_VERSION=4 - - ESLINT_VERSION=3 - - ESLINT_VERSION=2 + # - ESLINT_VERSION=3 + # - ESLINT_VERSION=2 # osx backlog is often deep, so to be polite we can just hit these highlights matrix: @@ -38,12 +38,15 @@ matrix: - os: osx env: ESLINT_VERSION=4 node_js: 8 - - os: osx - env: ESLINT_VERSION=3 - node_js: 6 - - os: osx - env: ESLINT_VERSION=2 - node_js: 4 + + # the following combos fail TypeScript tests + # - os: osx + # env: ESLINT_VERSION=3 + # node_js: 6 + # - os: osx + # env: ESLINT_VERSION=2 + # node_js: 4 + exclude: - node_js: '4' env: ESLINT_VERSION=5 diff --git a/appveyor.yml b/appveyor.yml index 0176e12545..bb435695f5 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -3,13 +3,14 @@ environment: matrix: - nodejs_version: "10" - nodejs_version: "8" - - nodejs_version: "6" - - nodejs_version: "4" + # - nodejs_version: "6" + # - nodejs_version: "4" matrix: fast_finish: true - allow_failures: - - nodejs_version: "4" # for eslint 5 + + # allow_failures: + # - nodejs_version: "4" # for eslint 5 # platform: # - x86 diff --git a/package.json b/package.json index dd54055335..58618e2335 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,7 @@ "redux": "^3.7.2", "rimraf": "^2.6.3", "sinon": "^2.4.1", - "typescript": "~2.8.1", + "typescript": "^3.2.2", "typescript-eslint-parser": "^21.0.2" }, "peerDependencies": { From acfb6e926f9324210d71ce1c8d453d17d707a9bd Mon Sep 17 00:00:00 2001 From: Ben Mosher Date: Mon, 14 Jan 2019 21:54:12 -0500 Subject: [PATCH 36/50] jk, test against eslint 2/3 but skip Typescript tests. also bumped babel-eslint --- .travis.yml | 18 +-- package.json | 2 +- src/rules/no-amd.js | 44 +++--- tests/src/core/getExports.js | 5 +- tests/src/rules/named.js | 190 ++++++++++++------------ tests/src/rules/newline-after-import.js | 3 +- tests/src/utils.js | 11 ++ 7 files changed, 146 insertions(+), 127 deletions(-) diff --git a/.travis.yml b/.travis.yml index 03de81c6d4..75f2e67ade 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,8 +10,8 @@ os: linux env: - ESLINT_VERSION=5 - ESLINT_VERSION=4 - # - ESLINT_VERSION=3 - # - ESLINT_VERSION=2 + - ESLINT_VERSION=3 + - ESLINT_VERSION=2 # osx backlog is often deep, so to be polite we can just hit these highlights matrix: @@ -38,14 +38,12 @@ matrix: - os: osx env: ESLINT_VERSION=4 node_js: 8 - - # the following combos fail TypeScript tests - # - os: osx - # env: ESLINT_VERSION=3 - # node_js: 6 - # - os: osx - # env: ESLINT_VERSION=2 - # node_js: 4 + - os: osx + env: ESLINT_VERSION=3 + node_js: 6 + - os: osx + env: ESLINT_VERSION=2 + node_js: 4 exclude: - node_js: '4' diff --git a/package.json b/package.json index 58618e2335..fd0ead0c83 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ }, "homepage": "https://github.com/benmosher/eslint-plugin-import", "devDependencies": { - "babel-eslint": "8.0.x", + "babel-eslint": "^10.0.1", "babel-plugin-istanbul": "^4.1.6", "babel-preset-es2015-argon": "latest", "babel-register": "^6.26.0", diff --git a/src/rules/no-amd.js b/src/rules/no-amd.js index df0d3aeb24..394244341e 100644 --- a/src/rules/no-amd.js +++ b/src/rules/no-amd.js @@ -10,35 +10,35 @@ import docsUrl from '../docsUrl' //------------------------------------------------------------------------------ module.exports = { - meta: { - type: 'suggestion', - docs: { - url: docsUrl('no-amd'), - }, + meta: { + type: 'suggestion', + docs: { + url: docsUrl('no-amd'), }, + }, - create: function (context) { + create: function (context) { + return { + 'CallExpression': function (node) { + if (context.getScope().type !== 'module') return - return { + console.log("got scope", context.getScope().type) - 'CallExpression': function (node) { - if (context.getScope().type !== 'module') return + if (node.callee.type !== 'Identifier') return + if (node.callee.name !== 'require' && + node.callee.name !== 'define') return - if (node.callee.type !== 'Identifier') return - if (node.callee.name !== 'require' && - node.callee.name !== 'define') return + // todo: capture define((require, module, exports) => {}) form? + if (node.arguments.length !== 2) return - // todo: capture define((require, module, exports) => {}) form? - if (node.arguments.length !== 2) return + const modules = node.arguments[0] + if (modules.type !== 'ArrayExpression') return - const modules = node.arguments[0] - if (modules.type !== 'ArrayExpression') return + // todo: check second arg type? (identifier or callback) - // todo: check second arg type? (identifier or callback) + context.report(node, `Expected imports instead of AMD ${node.callee.name}().`) + }, + } - context.report(node, `Expected imports instead of AMD ${node.callee.name}().`) - }, - } - - }, + }, } diff --git a/tests/src/core/getExports.js b/tests/src/core/getExports.js index 3bda3d3db1..b33d548f01 100644 --- a/tests/src/core/getExports.js +++ b/tests/src/core/getExports.js @@ -3,7 +3,7 @@ import ExportMap from '../../../src/ExportMap' import * as fs from 'fs' -import { getFilename } from '../utils' +import { getFilename, skipESLints } from '../utils' import * as unambiguous from 'eslint-module-utils/unambiguous' describe('ExportMap', function () { @@ -310,7 +310,7 @@ describe('ExportMap', function () { }) - context('alternate parsers', function () { + skipESLints([2, 3])('alternate parsers', function () { const configs = [ // ['string form', { 'typescript-eslint-parser': '.ts' }], @@ -318,6 +318,7 @@ describe('ExportMap', function () { ] configs.forEach(([description, parserConfig]) => { + describe(description, function () { const context = Object.assign({}, fakeContext, { settings: { diff --git a/tests/src/rules/named.js b/tests/src/rules/named.js index ed6dc9e049..7ffd929e1b 100644 --- a/tests/src/rules/named.js +++ b/tests/src/rules/named.js @@ -1,4 +1,4 @@ -import { test, SYNTAX_CASES } from '../utils' +import { test, SYNTAX_CASES, skipESLints } from '../utils' import { RuleTester } from 'eslint' import { CASE_SENSITIVE_FS } from 'eslint-module-utils/resolve' @@ -83,70 +83,6 @@ ruleTester.run('named', rule, { parser: 'babel-eslint', }), - // TypeScript - test({ - code: 'import { MyType } from "./typescript"', - parser: 'typescript-eslint-parser', - settings: { - 'import/parsers': { 'typescript-eslint-parser': ['.ts'] }, - 'import/resolver': { 'eslint-import-resolver-typescript': true }, - }, - }), - test({ - code: 'import { Foo } from "./typescript"', - parser: 'typescript-eslint-parser', - settings: { - 'import/parsers': { 'typescript-eslint-parser': ['.ts'] }, - 'import/resolver': { 'eslint-import-resolver-typescript': true }, - }, - }), - test({ - code: 'import { Bar } from "./typescript"', - parser: 'typescript-eslint-parser', - settings: { - 'import/parsers': { 'typescript-eslint-parser': ['.ts'] }, - 'import/resolver': { 'eslint-import-resolver-typescript': true }, - }, - }), - test({ - code: 'import { getFoo } from "./typescript"', - parser: 'typescript-eslint-parser', - settings: { - 'import/parsers': { 'typescript-eslint-parser': ['.ts'] }, - 'import/resolver': { 'eslint-import-resolver-typescript': true }, - }, - }), - test({ - code: 'import { MyEnum } from "./typescript"', - parser: 'typescript-eslint-parser', - settings: { - 'import/parsers': { 'typescript-eslint-parser': ['.ts'] }, - 'import/resolver': { 'eslint-import-resolver-typescript': true }, - }, - }), - test({ - code: ` - import { MyModule } from "./typescript" - MyModule.ModuleFunction() - `, - parser: 'typescript-eslint-parser', - settings: { - 'import/parsers': { 'typescript-eslint-parser': ['.ts'] }, - 'import/resolver': { 'eslint-import-resolver-typescript': true }, - }, - }), - test({ - code: ` - import { MyNamespace } from "./typescript" - MyNamespace.NSModule.NSModuleFunction() - `, - parser: 'typescript-eslint-parser', - settings: { - 'import/parsers': { 'typescript-eslint-parser': ['.ts'] }, - 'import/resolver': { 'eslint-import-resolver-typescript': true }, - }, - }), - // jsnext test({ code: '/*jsnext*/ import { createStore } from "redux"', @@ -246,32 +182,6 @@ ruleTester.run('named', rule, { // }], // }), - // TypeScript - test({ - code: 'import { MissingType } from "./typescript"', - parser: 'typescript-eslint-parser', - settings: { - 'import/parsers': { 'typescript-eslint-parser': ['.ts'] }, - 'import/resolver': { 'eslint-import-resolver-typescript': true }, - }, - errors: [{ - message: "MissingType not found in './typescript'", - type: 'Identifier', - }], - }), - test({ - code: 'import { NotExported } from "./typescript"', - parser: 'typescript-eslint-parser', - settings: { - 'import/parsers': { 'typescript-eslint-parser': ['.ts'] }, - 'import/resolver': { 'eslint-import-resolver-typescript': true }, - }, - errors: [{ - message: "NotExported not found in './typescript'", - type: 'Identifier', - }], - }), - test({ code: 'import { type MyOpaqueType, MyMissingClass } from "./flowtypes"', parser: 'babel-eslint', @@ -342,3 +252,101 @@ ruleTester.run('named (export *)', rule, { }), ], }) + + +skipESLints([2, 3])("Typescript", function () { + // Typescript + ruleTester.run("named", rule, { + valid: [ + test({ + code: 'import { MyType } from "./typescript"', + parser: 'typescript-eslint-parser', + settings: { + 'import/parsers': { 'typescript-eslint-parser': ['.ts'] }, + 'import/resolver': { 'eslint-import-resolver-typescript': true }, + }, + }), + test({ + code: 'import { Foo } from "./typescript"', + parser: 'typescript-eslint-parser', + settings: { + 'import/parsers': { 'typescript-eslint-parser': ['.ts'] }, + 'import/resolver': { 'eslint-import-resolver-typescript': true }, + }, + }), + test({ + code: 'import { Bar } from "./typescript"', + parser: 'typescript-eslint-parser', + settings: { + 'import/parsers': { 'typescript-eslint-parser': ['.ts'] }, + 'import/resolver': { 'eslint-import-resolver-typescript': true }, + }, + }), + test({ + code: 'import { getFoo } from "./typescript"', + parser: 'typescript-eslint-parser', + settings: { + 'import/parsers': { 'typescript-eslint-parser': ['.ts'] }, + 'import/resolver': { 'eslint-import-resolver-typescript': true }, + }, + }), + test({ + code: 'import { MyEnum } from "./typescript"', + parser: 'typescript-eslint-parser', + settings: { + 'import/parsers': { 'typescript-eslint-parser': ['.ts'] }, + 'import/resolver': { 'eslint-import-resolver-typescript': true }, + }, + }), + test({ + code: ` + import { MyModule } from "./typescript" + MyModule.ModuleFunction() + `, + parser: 'typescript-eslint-parser', + settings: { + 'import/parsers': { 'typescript-eslint-parser': ['.ts'] }, + 'import/resolver': { 'eslint-import-resolver-typescript': true }, + }, + }), + test({ + code: ` + import { MyNamespace } from "./typescript" + MyNamespace.NSModule.NSModuleFunction() + `, + parser: 'typescript-eslint-parser', + settings: { + 'import/parsers': { 'typescript-eslint-parser': ['.ts'] }, + 'import/resolver': { 'eslint-import-resolver-typescript': true }, + }, + }), + ], + + invalid: [ + test({ + code: 'import { MissingType } from "./typescript"', + parser: 'typescript-eslint-parser', + settings: { + 'import/parsers': { 'typescript-eslint-parser': ['.ts'] }, + 'import/resolver': { 'eslint-import-resolver-typescript': true }, + }, + errors: [{ + message: "MissingType not found in './typescript'", + type: 'Identifier', + }], + }), + test({ + code: 'import { NotExported } from "./typescript"', + parser: 'typescript-eslint-parser', + settings: { + 'import/parsers': { 'typescript-eslint-parser': ['.ts'] }, + 'import/resolver': { 'eslint-import-resolver-typescript': true }, + }, + errors: [{ + message: "NotExported not found in './typescript'", + type: 'Identifier', + }], + }), + ] + }) +}) diff --git a/tests/src/rules/newline-after-import.js b/tests/src/rules/newline-after-import.js index 00ebfa432b..730cef3636 100644 --- a/tests/src/rules/newline-after-import.js +++ b/tests/src/rules/newline-after-import.js @@ -153,8 +153,9 @@ ruleTester.run('newline-after-import', require('rules/newline-after-import'), { }, { code: `//issue 592 + export default @SomeDecorator(require('./some-file')) - export default class App {} + class App {} `, parserOptions: { sourceType: 'module' }, parser: 'babel-eslint', diff --git a/tests/src/utils.js b/tests/src/utils.js index fe04d684e2..9ec1b3e48a 100644 --- a/tests/src/utils.js +++ b/tests/src/utils.js @@ -29,6 +29,17 @@ export function getFilename(file) { return path.join(__dirname, '..', 'files', file || 'foo.js') } +/** + * skip tests iff ESLINT_VERSION is in provided `versions` array + */ +export function skipESLints(versions) { + if (!versions.includes(+process.env.ESLINT_VERSION)) { + return describe + } else { + return describe.skip + } +} + /** * to be added as valid cases just to ensure no nullable fields are going * to crash at runtime From f16523728a32f185058e50c5f7348a9d0bf69d1f Mon Sep 17 00:00:00 2001 From: Ben Mosher Date: Mon, 14 Jan 2019 22:00:07 -0500 Subject: [PATCH 37/50] ah geez, bumping babel-eslint breaks no-amd/no-cjs also left my debug console in :-( --- package.json | 2 +- src/rules/no-amd.js | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/package.json b/package.json index fd0ead0c83..f13598aa8a 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ }, "homepage": "https://github.com/benmosher/eslint-plugin-import", "devDependencies": { - "babel-eslint": "^10.0.1", + "babel-eslint": "^8.2.6", "babel-plugin-istanbul": "^4.1.6", "babel-preset-es2015-argon": "latest", "babel-register": "^6.26.0", diff --git a/src/rules/no-amd.js b/src/rules/no-amd.js index 394244341e..bb7c8ed826 100644 --- a/src/rules/no-amd.js +++ b/src/rules/no-amd.js @@ -22,8 +22,6 @@ module.exports = { 'CallExpression': function (node) { if (context.getScope().type !== 'module') return - console.log("got scope", context.getScope().type) - if (node.callee.type !== 'Identifier') return if (node.callee.name !== 'require' && node.callee.name !== 'define') return From 10c981163c3970b5633c1fd4d812b8f65790f6d8 Mon Sep 17 00:00:00 2001 From: Ben Mosher Date: Mon, 14 Jan 2019 22:16:00 -0500 Subject: [PATCH 38/50] node 4 fix for test util --- tests/src/utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/src/utils.js b/tests/src/utils.js index 9ec1b3e48a..56e8ab72a2 100644 --- a/tests/src/utils.js +++ b/tests/src/utils.js @@ -33,7 +33,7 @@ export function getFilename(file) { * skip tests iff ESLINT_VERSION is in provided `versions` array */ export function skipESLints(versions) { - if (!versions.includes(+process.env.ESLINT_VERSION)) { + if (versions.indexOf(+process.env.ESLINT_VERSION) === -1) { return describe } else { return describe.skip From 05c3935048577bd7b025d6b833d8503807f02189 Mon Sep 17 00:00:00 2001 From: Ben Mosher Date: Wed, 16 Jan 2019 07:18:43 -0500 Subject: [PATCH 39/50] repair `no-deprecated` for ESLint* 5 * technically espree v5 - also technically it doesn't support comma-first anymore but that seems reasonable --- src/ExportMap.js | 48 +++++++++++++++++++++++++++++---------- tests/files/deprecated.js | 6 ++--- tests/src/core/parse.js | 2 ++ utils/parse.js | 6 +++-- 4 files changed, 45 insertions(+), 17 deletions(-) diff --git a/src/ExportMap.js b/src/ExportMap.js index 563ff9e8c5..c8335d9c8a 100644 --- a/src/ExportMap.js +++ b/src/ExportMap.js @@ -4,6 +4,8 @@ import doctrine from 'doctrine' import debug from 'debug' +import SourceCode from 'eslint/lib/util/source-code' + import parse from 'eslint-module-utils/parse' import resolve from 'eslint-module-utils/resolve' import isIgnored, { hasValidExtension } from 'eslint-module-utils/ignore' @@ -193,22 +195,28 @@ export default class ExportMap { * @param {...[type]} nodes [description] * @return {{doc: object}} */ -function captureDoc(docStyleParsers) { +function captureDoc(source, docStyleParsers) { const metadata = {} , nodes = Array.prototype.slice.call(arguments, 1) // 'some' short-circuits on first 'true' nodes.some(n => { - if (!n.leadingComments) return false - - for (let name in docStyleParsers) { - const doc = docStyleParsers[name](n.leadingComments) - if (doc) { - metadata.doc = doc + try { + // n.leadingComments is legacy `attachComments` behavior + let leadingComments = n.leadingComments || source.getCommentsBefore(n) + if (leadingComments.length === 0) return false + + for (let name in docStyleParsers) { + const doc = docStyleParsers[name](leadingComments) + if (doc) { + metadata.doc = doc + } } - } - return true + return true + } catch (err) { + return false + } }) return metadata @@ -338,6 +346,8 @@ ExportMap.parse = function (path, content, context) { docStyleParsers[style] = availableDocStyleParsers[style] }) + const source = makeSourceCode(content, ast) + // attempt to collect module doc if (ast.comments) { ast.comments.some(c => { @@ -405,7 +415,7 @@ ExportMap.parse = function (path, content, context) { ast.body.forEach(function (n) { if (n.type === 'ExportDefaultDeclaration') { - const exportMeta = captureDoc(docStyleParsers, n) + const exportMeta = captureDoc(source, docStyleParsers, n) if (n.declaration.type === 'Identifier') { addNamespace(exportMeta, n.declaration) } @@ -441,12 +451,12 @@ ExportMap.parse = function (path, content, context) { case 'TSInterfaceDeclaration': case 'TSAbstractClassDeclaration': case 'TSModuleDeclaration': - m.namespace.set(n.declaration.id.name, captureDoc(docStyleParsers, n)) + m.namespace.set(n.declaration.id.name, captureDoc(source, docStyleParsers, n)) break case 'VariableDeclaration': n.declaration.declarations.forEach((d) => recursivePatternCapture(d.id, - id => m.namespace.set(id.name, captureDoc(docStyleParsers, d, n)))) + id => m.namespace.set(id.name, captureDoc(source, docStyleParsers, d, n)))) break } } @@ -531,3 +541,17 @@ function childContext(path, context) { path, } } + + +/** + * sometimes legacy support isn't _that_ hard... right? + */ +function makeSourceCode(text, ast) { + if (SourceCode.length > 1) { + // ESLint 3 + return new SourceCode(text, ast) + } else { + // ESLint 4, 5 + return new SourceCode({ text, ast }) + } +} diff --git a/tests/files/deprecated.js b/tests/files/deprecated.js index 10e81dc912..f5229f59b8 100644 --- a/tests/files/deprecated.js +++ b/tests/files/deprecated.js @@ -27,18 +27,18 @@ export const MY_TERRIBLE_ACTION = "ugh" * @deprecated this chain is awful * @type {String} */ -export const CHAIN_A = "a" +export const CHAIN_A = "a", /** * @deprecated so awful * @type {String} */ - , CHAIN_B = "b" + CHAIN_B = "b", /** * @deprecated still terrible * @type {String} */ - , CHAIN_C = "C" + CHAIN_C = "C" /** * this one is fine diff --git a/tests/src/core/parse.js b/tests/src/core/parse.js index 9cc153ae3c..4b0f12c626 100644 --- a/tests/src/core/parse.js +++ b/tests/src/core/parse.js @@ -38,6 +38,8 @@ describe('parse(content, { settings, ecmaFeatures })', function () { .that.is.eql(parserOptions.ecmaFeatures) .and.is.not.equal(parserOptions.ecmaFeatures) expect(parseSpy.args[0][1], 'custom parser to get parserOptions.attachComment equal to true').to.have.property('attachComment', true) + expect(parseSpy.args[0][1], 'custom parser to get parserOptions.tokens equal to true').to.have.property('tokens', true) + expect(parseSpy.args[0][1], 'custom parser to get parserOptions.range equal to true').to.have.property('range', true) 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) }) diff --git a/utils/parse.js b/utils/parse.js index 5bafdba495..2946047ad5 100644 --- a/utils/parse.js +++ b/utils/parse.js @@ -19,12 +19,14 @@ exports.default = function parse(path, content, context) { parserOptions = Object.assign({}, parserOptions) parserOptions.ecmaFeatures = Object.assign({}, parserOptions.ecmaFeatures) - // always include and attach comments + // always include comments and tokens (for doc parsing) parserOptions.comment = true - parserOptions.attachComment = true + parserOptions.attachComment = true // keeping this for backward-compat with older parsers + parserOptions.tokens = true // attach node locations parserOptions.loc = true + parserOptions.range = true // provide the `filePath` like eslint itself does, in `parserOptions` // https://github.com/eslint/eslint/blob/3ec436ee/lib/linter.js#L637 From 73080d0ba88b55b0794d288f8ef4f476873c3367 Mon Sep 17 00:00:00 2001 From: Ben Mosher Date: Thu, 17 Jan 2019 06:09:54 -0500 Subject: [PATCH 40/50] dep-time-travel: use older versions of dependencies for tests against older ESLint versions. --- .travis.yml | 3 ++- tests/dep-time-travel.sh | 20 ++++++++++++++++++++ tests/src/core/getExports.js | 4 ++-- tests/src/rules/named.js | 4 ++-- tests/src/utils.js | 11 ----------- 5 files changed, 26 insertions(+), 16 deletions(-) create mode 100755 tests/dep-time-travel.sh diff --git a/.travis.yml b/.travis.yml index 75f2e67ade..c359e73713 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,6 +32,7 @@ matrix: node_js: 6 - env: PACKAGE=resolvers/webpack node_js: 4 + - os: osx env: ESLINT_VERSION=5 node_js: 10 @@ -54,7 +55,7 @@ before_install: - 'if [ -n "${PACKAGE-}" ]; then cd "${PACKAGE}"; fi' install: - npm install - - npm install --no-save eslint@$ESLINT_VERSION --ignore-scripts || true + - 'if [ -n "${ESLINT_VERSION}" ]; then ./tests/dep-time-travel.sh; fi' script: - 'npm test' diff --git a/tests/dep-time-travel.sh b/tests/dep-time-travel.sh new file mode 100755 index 0000000000..eae24998df --- /dev/null +++ b/tests/dep-time-travel.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +# expected: ESLINT_VERSION numeric env var + +npm install --no-save eslint@$ESLINT_VERSION --ignore-scripts || true + +# use these alternate typescript dependencies for ESLint < v4 +if [[ "$ESLINT_VERSION" -lt "4" ]]; then + echo "Downgrading babel-eslint..." + npm i --no-save babel-eslint@8.0.3 + + echo "Downgrading TypeScript dependencies..." + npm i --no-save typescript-eslint-parser@15 typescript@2.8.1 +fi + +# typescript-eslint-parser 1.1.1+ is not compatible with node 6 +if [[ "$TRAVIS_NODE_VERSION" -lt "8" ]]; then + echo "Downgrading eslint-import-resolver-typescript..." + npm i --no-save eslint-import-resolver-typescript@1.0.2 +fi diff --git a/tests/src/core/getExports.js b/tests/src/core/getExports.js index b33d548f01..8e01f62acf 100644 --- a/tests/src/core/getExports.js +++ b/tests/src/core/getExports.js @@ -3,7 +3,7 @@ import ExportMap from '../../../src/ExportMap' import * as fs from 'fs' -import { getFilename, skipESLints } from '../utils' +import { getFilename } from '../utils' import * as unambiguous from 'eslint-module-utils/unambiguous' describe('ExportMap', function () { @@ -310,7 +310,7 @@ describe('ExportMap', function () { }) - skipESLints([2, 3])('alternate parsers', function () { + context('alternate parsers', function () { const configs = [ // ['string form', { 'typescript-eslint-parser': '.ts' }], diff --git a/tests/src/rules/named.js b/tests/src/rules/named.js index 7ffd929e1b..92b3d9163e 100644 --- a/tests/src/rules/named.js +++ b/tests/src/rules/named.js @@ -1,4 +1,4 @@ -import { test, SYNTAX_CASES, skipESLints } from '../utils' +import { test, SYNTAX_CASES } from '../utils' import { RuleTester } from 'eslint' import { CASE_SENSITIVE_FS } from 'eslint-module-utils/resolve' @@ -254,7 +254,7 @@ ruleTester.run('named (export *)', rule, { }) -skipESLints([2, 3])("Typescript", function () { +context("Typescript", function () { // Typescript ruleTester.run("named", rule, { valid: [ diff --git a/tests/src/utils.js b/tests/src/utils.js index 56e8ab72a2..fe04d684e2 100644 --- a/tests/src/utils.js +++ b/tests/src/utils.js @@ -29,17 +29,6 @@ export function getFilename(file) { return path.join(__dirname, '..', 'files', file || 'foo.js') } -/** - * skip tests iff ESLINT_VERSION is in provided `versions` array - */ -export function skipESLints(versions) { - if (versions.indexOf(+process.env.ESLINT_VERSION) === -1) { - return describe - } else { - return describe.skip - } -} - /** * to be added as valid cases just to ensure no nullable fields are going * to crash at runtime From 64d9be7d76aa7a901d846f08a3342b98b0c3d809 Mon Sep 17 00:00:00 2001 From: Ben Mosher Date: Fri, 18 Jan 2019 20:03:36 -0500 Subject: [PATCH 41/50] allow_failures for dicey Node/ESLint intersection --- .travis.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.travis.yml b/.travis.yml index c359e73713..e8eaf9d967 100644 --- a/.travis.yml +++ b/.travis.yml @@ -49,6 +49,12 @@ matrix: exclude: - node_js: '4' env: ESLINT_VERSION=5 + + fast_finish: true + allow_failures: + # issues with typescript deps in this version intersection + - node_js: '4' + env: ESLINT_VERSION=4 before_install: - 'nvm install-latest-npm' From 548ea0244b8717567975fa5d8325c83340521a15 Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 22 Jan 2019 14:42:18 +0300 Subject: [PATCH 42/50] added support for argv parameter of webpack`s config-as-a-function (#1261) --- resolvers/webpack/index.js | 5 +++-- resolvers/webpack/test/config.js | 21 +++++++++++++++++++ .../test/files/webpack.function.config.js | 3 ++- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/resolvers/webpack/index.js b/resolvers/webpack/index.js index b1b0e45f67..146213a0ca 100644 --- a/resolvers/webpack/index.js +++ b/resolvers/webpack/index.js @@ -47,6 +47,7 @@ exports.resolve = function (source, file, settings) { var configPath = get(settings, 'config') , configIndex = get(settings, 'config-index') , env = get(settings, 'env') + , argv = get(settings, 'argv', {}) , packageDir log('Config path from settings:', configPath) @@ -87,13 +88,13 @@ exports.resolve = function (source, file, settings) { } if (typeof webpackConfig === 'function') { - webpackConfig = webpackConfig(env, {}) + webpackConfig = webpackConfig(env, argv) } if (Array.isArray(webpackConfig)) { webpackConfig = webpackConfig.map(cfg => { if (typeof cfg === 'function') { - return cfg(env, {}) + return cfg(env, argv) } return cfg diff --git a/resolvers/webpack/test/config.js b/resolvers/webpack/test/config.js index 16a4a6dda3..07c6350c56 100644 --- a/resolvers/webpack/test/config.js +++ b/resolvers/webpack/test/config.js @@ -114,4 +114,25 @@ describe("config", function () { expect(resolve('bar', file, settings)).to.have.property('path') .and.equal(path.join(__dirname, 'files', 'some', 'goofy', 'path', 'bar.js')) }) + + it('passes argv to config when it is a function', function() { + var settings = { + config: require(path.join(__dirname, './files/webpack.function.config.js')), + argv: { + mode: 'test' + } + } + + expect(resolve('baz', file, settings)).to.have.property('path') + .and.equal(path.join(__dirname, 'files', 'some', 'bar', 'bar.js')) + }) + + it('passes a default empty argv object to config when it is a function', function() { + var settings = { + config: require(path.join(__dirname, './files/webpack.function.config.js')), + argv: undefined + } + + expect(function () { resolve('baz', file, settings) }).to.not.throw(Error) + }) }) diff --git a/resolvers/webpack/test/files/webpack.function.config.js b/resolvers/webpack/test/files/webpack.function.config.js index ce87dd1b11..0dad14e067 100644 --- a/resolvers/webpack/test/files/webpack.function.config.js +++ b/resolvers/webpack/test/files/webpack.function.config.js @@ -1,12 +1,13 @@ var path = require('path') var pluginsTest = require('webpack-resolver-plugin-test') -module.exports = function(env) { +module.exports = function(env, argv) { return { resolve: { alias: { 'foo': path.join(__dirname, 'some', 'goofy', 'path', 'foo.js'), 'bar': env ? path.join(__dirname, 'some', 'goofy', 'path', 'bar.js') : undefined, + 'baz': argv.mode === 'test' ? path.join(__dirname, 'some', 'bar', 'bar.js') : undefined, 'some-alias': path.join(__dirname, 'some'), }, modules: [ From 1e4100d8c8e16045933c361c15a7ab1fbad31148 Mon Sep 17 00:00:00 2001 From: Ben Mosher Date: Tue, 22 Jan 2019 06:44:25 -0500 Subject: [PATCH 43/50] changelog note for #1261 --- resolvers/webpack/CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/resolvers/webpack/CHANGELOG.md b/resolvers/webpack/CHANGELOG.md index 8ea232a3bd..a1d0454302 100644 --- a/resolvers/webpack/CHANGELOG.md +++ b/resolvers/webpack/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 + +### Added +- support for `argv` parameter when config is a function. ([#1261], thanks [@keann]) + ### Fixed - crash when webpack config is an array of functions ([#1219]/[#1220] by [@idudinov]) @@ -106,6 +110,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]). +[#1261]: https://github.com/benmosher/eslint-plugin-import/pull/1261 [#1220]: https://github.com/benmosher/eslint-plugin-import/pull/1220 [#1091]: https://github.com/benmosher/eslint-plugin-import/pull/1091 [#969]: https://github.com/benmosher/eslint-plugin-import/pull/969 @@ -152,3 +157,4 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel [@graingert]: https://github.com/graingert [@mattkrick]: https://github.com/mattkrick [@idudinov]: https://github.com/idudinov +[@keann]: https://github.com/keann From 20a8f3b178377bb92e3310b21b3d91b8753fe3a3 Mon Sep 17 00:00:00 2001 From: Ben Mosher Date: Tue, 22 Jan 2019 06:58:34 -0500 Subject: [PATCH 44/50] bump utils to v2.3.0 --- package.json | 2 +- utils/CHANGELOG.md | 10 ++++++++++ utils/package.json | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index f13598aa8a..21c3757342 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ "debug": "^2.6.9", "doctrine": "1.5.0", "eslint-import-resolver-node": "^0.3.2", - "eslint-module-utils": "^2.2.0", + "eslint-module-utils": "^2.3.0", "has": "^1.0.3", "lodash": "^4.17.11", "minimatch": "^3.0.4", diff --git a/utils/CHANGELOG.md b/utils/CHANGELOG.md index 018fd30669..cb86dc2259 100644 --- a/utils/CHANGELOG.md +++ b/utils/CHANGELOG.md @@ -5,6 +5,10 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel ## Unreleased +## v2.3.0 - 2019-01-22 +### Fixed +- use `process.hrtime()` for cache dates ([#1160], thanks [@hulkish]) + ## v2.2.0 - 2018-03-29 ### Changed - `parse`: attach node locations by default. @@ -30,3 +34,9 @@ Yanked due to critical issue with cache key resulting from #839. ### Fixed - `unambiguous.test()` regex is now properly in multiline mode + + + +[#1160]: https://github.com/benmosher/eslint-plugin-import/pull/1160 + +[@hulkish]: https://github.com/hulkish diff --git a/utils/package.json b/utils/package.json index 360cc76132..c380b6e2b1 100644 --- a/utils/package.json +++ b/utils/package.json @@ -1,6 +1,6 @@ { "name": "eslint-module-utils", - "version": "2.2.0", + "version": "2.3.0", "description": "Core utilities to support eslint-plugin-import and other module-related plugins.", "engines": { "node": ">=4" From 038d668b0b03e3ea06091bc744f082397cff200c Mon Sep 17 00:00:00 2001 From: Ben Mosher Date: Tue, 22 Jan 2019 06:58:50 -0500 Subject: [PATCH 45/50] bump webpack resolver to v0.11.0 --- resolvers/webpack/CHANGELOG.md | 3 +++ resolvers/webpack/package.json | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/resolvers/webpack/CHANGELOG.md b/resolvers/webpack/CHANGELOG.md index a1d0454302..5526ca5401 100644 --- a/resolvers/webpack/CHANGELOG.md +++ b/resolvers/webpack/CHANGELOG.md @@ -5,6 +5,9 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel ## Unreleased + +## 0.11.0 - 2018-01-22 + ### Added - support for `argv` parameter when config is a function. ([#1261], thanks [@keann]) diff --git a/resolvers/webpack/package.json b/resolvers/webpack/package.json index a36a78e474..5985babe6c 100644 --- a/resolvers/webpack/package.json +++ b/resolvers/webpack/package.json @@ -1,6 +1,6 @@ { "name": "eslint-import-resolver-webpack", - "version": "0.10.1", + "version": "0.11.0", "description": "Resolve paths to dependencies, given a webpack.config.js. Plugin for eslint-plugin-import.", "main": "index.js", "scripts": { From 767f01a2f34b77d118edf762809c2f2046abe1b7 Mon Sep 17 00:00:00 2001 From: Ben Mosher Date: Tue, 22 Jan 2019 07:07:39 -0500 Subject: [PATCH 46/50] bump to v2.15.0 --- CHANGELOG.md | 23 ++++++++++++++++++++--- package.json | 2 +- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a0b8a590d9..1a0a3f5ac7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,15 +4,23 @@ This project adheres to [Semantic Versioning](http://semver.org/). This change log adheres to standards from [Keep a CHANGELOG](http://keepachangelog.com). ## [Unreleased] + + +## [2.15.0] - 2019-01-22 +### Added +- new rule: [`no-named-export`] ([#1157], thanks [@fsmaia]) + ### Fixed - [`no-extraneous-dependencies`]: `packageDir` option with array value was clobbering package deps instead of merging them ([#1175]/[#1176], thanks [@aravindet] & [@pzhine]) +- [`dynamic-import-chunkname`]: Add proper webpack comment parsing ([#1163], thanks [@st-sloth]) +- [`named`]: fix destructuring assignment ([#1232], thanks [@ljqx]) ## [2.14.0] - 2018-08-13 * 69e0187 (HEAD -> master, source/master, origin/master, origin/HEAD) Merge pull request #1151 from jf248/jsx -|\ +|\ | * e30a757 (source/pr/1151, fork/jsx) Add JSX check to namespace rule -|/ +|/ * 8252344 (source/pr/1148) Add error to output when module loaded as resolver has invalid API ### Added - [`no-useless-path-segments`]: add commonJS (CJS) support ([#1128], thanks [@1pete]) @@ -493,10 +501,15 @@ for info on changes for earlier releases. [`no-default-export`]: ./docs/rules/no-default-export.md [`no-useless-path-segments`]: ./docs/rules/no-useless-path-segments.md [`no-cycle`]: ./docs/rules/no-cycle.md +[`dynamic-import-chunkname`]: ./docs/rules/dynamic-import-chunkname.md +[`no-named-export`]: ./docs/rules/no-named-export.md [`memo-parser`]: ./memo-parser/README.md +[#1232]: https://github.com/benmosher/eslint-plugin-import/pull/1232 [#1176]: https://github.com/benmosher/eslint-plugin-import/pull/1176 +[#1163]: https://github.com/benmosher/eslint-plugin-import/pull/1163 +[#1157]: https://github.com/benmosher/eslint-plugin-import/pull/1157 [#1151]: https://github.com/benmosher/eslint-plugin-import/pull/1151 [#1137]: https://github.com/benmosher/eslint-plugin-import/pull/1137 [#1135]: https://github.com/benmosher/eslint-plugin-import/pull/1135 @@ -652,7 +665,9 @@ 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/v2.13.0...HEAD +[Unreleased]: https://github.com/benmosher/eslint-plugin-import/compare/v2.15.0...HEAD +[2.15.0]: https://github.com/benmosher/eslint-plugin-import/compare/v2.14.0...v2.15.0 +[2.14.0]: https://github.com/benmosher/eslint-plugin-import/compare/v2.13.0...v2.14.0 [2.13.0]: https://github.com/benmosher/eslint-plugin-import/compare/v2.12.0...v2.13.0 [2.12.0]: https://github.com/benmosher/eslint-plugin-import/compare/v2.11.0...v2.12.0 [2.11.0]: https://github.com/benmosher/eslint-plugin-import/compare/v2.10.0...v2.11.0 @@ -774,3 +789,5 @@ for info on changes for earlier releases. [@jf248]: https://github.com/jf248 [@aravindet]: https://github.com/aravindet [@pzhine]: https://github.com/pzhine +[@st-sloth]: https://github.com/st-sloth +[@ljqx]: https://github.com/ljqx diff --git a/package.json b/package.json index 21c3757342..39a8d5510f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eslint-plugin-import", - "version": "2.14.0", + "version": "2.15.0", "description": "Import with sanity.", "engines": { "node": ">=4" From 1ec80fa35fa1819e2d35a70e68fb6a149fb57c5e Mon Sep 17 00:00:00 2001 From: Kirill Konshin Date: Wed, 23 Jan 2019 04:29:47 -0800 Subject: [PATCH 47/50] Fix for #1256 (#1257) --- config/typescript.js | 22 ++++++++++++++++++++++ src/index.js | 1 + 2 files changed, 23 insertions(+) create mode 100644 config/typescript.js diff --git a/config/typescript.js b/config/typescript.js new file mode 100644 index 0000000000..d2d707c589 --- /dev/null +++ b/config/typescript.js @@ -0,0 +1,22 @@ +/** + * Adds `.jsx`, `.ts` and `.tsx` as an extension, and enables JSX/TSX parsing. + */ +var jsExtensions = ['.js', '.jsx']; +var tsExtensions = ['.ts', '.tsx']; +var allExtensions = jsExtensions.concat(tsExtensions); + +module.exports = { + + settings: { + 'import/extensions': allExtensions, + 'import/parsers': { + 'typescript-eslint-parser': tsExtensions + }, + 'import/resolver': { + 'node': { + 'extensions': allExtensions + } + } + } + +} diff --git a/src/index.js b/src/index.js index f5794595d6..6cbe0a6428 100644 --- a/src/index.js +++ b/src/index.js @@ -62,4 +62,5 @@ export const configs = { 'react': require('../config/react'), 'react-native': require('../config/react-native'), 'electron': require('../config/electron'), + 'typescript': require('../config/typescript'), } From e72a336e9b62174c77be79ff6252fb6d780dd238 Mon Sep 17 00:00:00 2001 From: Ben Mosher Date: Tue, 29 Jan 2019 05:45:05 -0500 Subject: [PATCH 48/50] fix #1266 by moving closure creation out of parsing scope (#1275) --- CHANGELOG.md | 9 +++++++++ docs/rules/no-deprecated.md | 4 ---- src/ExportMap.js | 28 +++++++++++++++++++++------- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a0a3f5ac7..f21cfeb2c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,11 @@ This project adheres to [Semantic Versioning](http://semver.org/). This change log adheres to standards from [Keep a CHANGELOG](http://keepachangelog.com). ## [Unreleased] +### Added +- `typescript` config ([#1257], thanks [@kirill-konshin]) +### Fixed +- Memory leak of `SourceCode` objects for all parsed dependencies, resolved. (issue [#1266], thanks [@asapach] and [@sergei-startsev] for digging in) ## [2.15.0] - 2019-01-22 ### Added @@ -506,6 +510,7 @@ for info on changes for earlier releases. [`memo-parser`]: ./memo-parser/README.md +[#1257]: https://github.com/benmosher/eslint-plugin-import/pull/1257 [#1232]: https://github.com/benmosher/eslint-plugin-import/pull/1232 [#1176]: https://github.com/benmosher/eslint-plugin-import/pull/1176 [#1163]: https://github.com/benmosher/eslint-plugin-import/pull/1163 @@ -595,6 +600,7 @@ for info on changes for earlier releases. [#314]: https://github.com/benmosher/eslint-plugin-import/pull/314 [#912]: https://github.com/benmosher/eslint-plugin-import/pull/912 +[#1266]: https://github.com/benmosher/eslint-plugin-import/issues/1266 [#1175]: https://github.com/benmosher/eslint-plugin-import/issues/1175 [#1058]: https://github.com/benmosher/eslint-plugin-import/issues/1058 [#931]: https://github.com/benmosher/eslint-plugin-import/issues/931 @@ -791,3 +797,6 @@ for info on changes for earlier releases. [@pzhine]: https://github.com/pzhine [@st-sloth]: https://github.com/st-sloth [@ljqx]: https://github.com/ljqx +[@kirill-konshin]: https://github.com/kirill-konshin +[@asapach]: https://github.com/asapach +[@sergei-startsev]: https://github.com/sergei-startsev diff --git a/docs/rules/no-deprecated.md b/docs/rules/no-deprecated.md index 7583651f31..fae7d8daf2 100644 --- a/docs/rules/no-deprecated.md +++ b/docs/rules/no-deprecated.md @@ -1,9 +1,5 @@ # import/no-deprecated -**Stage: 0** - -**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 or TomDoc `Deprecated: ` comment. diff --git a/src/ExportMap.js b/src/ExportMap.js index c8335d9c8a..38aedc6d6c 100644 --- a/src/ExportMap.js +++ b/src/ExportMap.js @@ -192,8 +192,6 @@ export default class ExportMap { /** * parse docs from the first node that has leading comments - * @param {...[type]} nodes [description] - * @return {{doc: object}} */ function captureDoc(source, docStyleParsers) { const metadata = {} @@ -202,9 +200,17 @@ function captureDoc(source, docStyleParsers) { // 'some' short-circuits on first 'true' nodes.some(n => { try { + + let leadingComments + // n.leadingComments is legacy `attachComments` behavior - let leadingComments = n.leadingComments || source.getCommentsBefore(n) - if (leadingComments.length === 0) return false + if ('leadingComments' in n) { + leadingComments = n.leadingComments + } else if (n.range) { + leadingComments = source.getCommentsBefore(n) + } + + if (!leadingComments || leadingComments.length === 0) return false for (let name in docStyleParsers) { const doc = docStyleParsers[name](leadingComments) @@ -346,8 +352,6 @@ ExportMap.parse = function (path, content, context) { docStyleParsers[style] = availableDocStyleParsers[style] }) - const source = makeSourceCode(content, ast) - // attempt to collect module doc if (ast.comments) { ast.comments.some(c => { @@ -400,7 +404,7 @@ ExportMap.parse = function (path, content, context) { const existing = m.imports.get(p) if (existing != null) return existing.getter - const getter = () => ExportMap.for(childContext(p, context)) + const getter = thunkFor(p, context) m.imports.set(p, { getter, source: { // capturing actual node reference holds full AST in memory! @@ -411,6 +415,7 @@ ExportMap.parse = function (path, content, context) { return getter } + const source = makeSourceCode(content, ast) ast.body.forEach(function (n) { @@ -496,6 +501,15 @@ ExportMap.parse = function (path, content, context) { return m } +/** + * The creation of this closure is isolated from other scopes + * to avoid over-retention of unrelated variables, which has + * caused memory leaks. See #1266. + */ +function thunkFor(p, context) { + return () => ExportMap.for(childContext(p, context)) +} + /** * Traverse a pattern/identifier node, calling 'callback' From d305f6ab7c8869dce80928f6a4d7cd3de10ee3f5 Mon Sep 17 00:00:00 2001 From: Ben Mosher Date: Tue, 29 Jan 2019 06:21:48 -0500 Subject: [PATCH 49/50] use proper rest arg instead of [].slice --- src/ExportMap.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ExportMap.js b/src/ExportMap.js index 38aedc6d6c..07120754c6 100644 --- a/src/ExportMap.js +++ b/src/ExportMap.js @@ -193,9 +193,8 @@ export default class ExportMap { /** * parse docs from the first node that has leading comments */ -function captureDoc(source, docStyleParsers) { +function captureDoc(source, docStyleParsers, ...nodes) { const metadata = {} - , nodes = Array.prototype.slice.call(arguments, 1) // 'some' short-circuits on first 'true' nodes.some(n => { From 9bac44e629105572ca78a532c968df202e5a18b8 Mon Sep 17 00:00:00 2001 From: Ben Mosher Date: Tue, 29 Jan 2019 06:23:58 -0500 Subject: [PATCH 50/50] bump to v2.16.0 --- CHANGELOG.md | 6 +++++- package.json | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f21cfeb2c9..d93839d76b 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] + + +## [2.16.0] - 2019-01-29 ### Added - `typescript` config ([#1257], thanks [@kirill-konshin]) @@ -671,7 +674,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/v2.15.0...HEAD +[Unreleased]: https://github.com/benmosher/eslint-plugin-import/compare/v2.16.0...HEAD +[2.16.0]: https://github.com/benmosher/eslint-plugin-import/compare/v2.15.0...v2.16.0 [2.15.0]: https://github.com/benmosher/eslint-plugin-import/compare/v2.14.0...v2.15.0 [2.14.0]: https://github.com/benmosher/eslint-plugin-import/compare/v2.13.0...v2.14.0 [2.13.0]: https://github.com/benmosher/eslint-plugin-import/compare/v2.12.0...v2.13.0 diff --git a/package.json b/package.json index 39a8d5510f..79f52e5930 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eslint-plugin-import", - "version": "2.15.0", + "version": "2.16.0", "description": "Import with sanity.", "engines": { "node": ">=4"