diff --git a/CHANGELOG.md b/CHANGELOG.md index d3c399196..3522dda4c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,16 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel ## [Unreleased] +## [1.15.0] - 2016-09-12 +### Added +- Added an `allow` option to [`no-nodejs-modules`] to allow exceptions ([#452], [#509]). +- Added [`no-absolute-path`] rule ([#530], [#538]) +- [`max-dependencies`] for specifying the maximum number of dependencies (both `import` and `require`) a module can have. (see [#489], thanks [@tizmagik]) +- Added glob option to config for [`no-extraneous-dependencies`], after much bikeshedding. Thanks, [@knpwrs]! ([#527]) + +### Fixed +- [`no-named-as-default-member`] Allow default import to have a property named "default" ([#507]+[#508], thanks [@jquense] for both!) + ## [1.14.0] - 2016-08-22 ### Added - [`import/parsers` setting]: parse some dependencies (i.e. TypeScript!) with a different parser than the ESLint-configured parser. ([#503]) @@ -289,9 +299,16 @@ for info on changes for earlier releases. [`no-mutable-exports`]: ./docs/rules/no-mutable-exports.md [`prefer-default-export`]: ./docs/rules/prefer-default-export.md [`no-restricted-paths`]: ./docs/rules/no-restricted-paths.md +[`no-absolute-path`]: ./docs/rules/no-absolute-path.md +[`max-dependencies`]: ./docs/rules/max-dependencies.md +[#538]: https://github.com/benmosher/eslint-plugin-import/pull/538 +[#527]: https://github.com/benmosher/eslint-plugin-import/pull/527 +[#509]: https://github.com/benmosher/eslint-plugin-import/pull/509 +[#508]: https://github.com/benmosher/eslint-plugin-import/pull/508 [#503]: https://github.com/benmosher/eslint-plugin-import/pull/503 [#499]: https://github.com/benmosher/eslint-plugin-import/pull/499 +[#489]: https://github.com/benmosher/eslint-plugin-import/pull/489 [#461]: https://github.com/benmosher/eslint-plugin-import/pull/461 [#444]: https://github.com/benmosher/eslint-plugin-import/pull/444 [#428]: https://github.com/benmosher/eslint-plugin-import/pull/428 @@ -328,9 +345,12 @@ for info on changes for earlier releases. [#157]: https://github.com/benmosher/eslint-plugin-import/pull/157 [#314]: https://github.com/benmosher/eslint-plugin-import/pull/314 +[#530]: https://github.com/benmosher/eslint-plugin-import/issues/530 +[#507]: https://github.com/benmosher/eslint-plugin-import/issues/507 [#478]: https://github.com/benmosher/eslint-plugin-import/issues/478 [#456]: https://github.com/benmosher/eslint-plugin-import/issues/456 [#453]: https://github.com/benmosher/eslint-plugin-import/issues/453 +[#452]: https://github.com/benmosher/eslint-plugin-import/issues/452 [#441]: https://github.com/benmosher/eslint-plugin-import/issues/441 [#423]: https://github.com/benmosher/eslint-plugin-import/issues/423 [#416]: https://github.com/benmosher/eslint-plugin-import/issues/416 @@ -362,7 +382,8 @@ for info on changes for earlier releases. [#119]: https://github.com/benmosher/eslint-plugin-import/issues/119 [#89]: https://github.com/benmosher/eslint-plugin-import/issues/89 -[Unreleased]: https://github.com/benmosher/eslint-plugin-import/compare/v1.14.0...HEAD +[Unreleased]: https://github.com/benmosher/eslint-plugin-import/compare/v1.15.0...HEAD +[1.15.0]: https://github.com/benmosher/eslint-plugin-import/compare/v1.14.0...v1.15.0 [1.14.0]: https://github.com/benmosher/eslint-plugin-import/compare/v1.13.0...v1.14.0 [1.13.0]: https://github.com/benmosher/eslint-plugin-import/compare/v1.12.0...v1.13.0 [1.12.0]: https://github.com/benmosher/eslint-plugin-import/compare/v1.11.1...v1.12.0 @@ -422,3 +443,5 @@ for info on changes for earlier releases. [@zloirock]: https://github.com/zloirock [@rhys-vdw]: https://github.com/rhys-vdw [@wKich]: https://github.com/wKich +[@tizmagik]: https://github.com/tizmagik +[@knpwrs]: https://github.com/knpwrs diff --git a/README.md b/README.md index b396daf3b..97194dcfe 100644 --- a/README.md +++ b/README.md @@ -19,12 +19,14 @@ This plugin intends to support linting of ES2015+ (ES6+) import/export syntax, a * Ensure a default export is present, given a default import. ([`default`]) * Ensure imported namespaces contain dereferenced properties as they are dereferenced. ([`namespace`]) * Restrict which files can be imported in a given folder ([`no-restricted-paths`]) +* Forbid import of modules using absolute paths ([`no-absolute-path`]) [`no-unresolved`]: ./docs/rules/no-unresolved.md [`named`]: ./docs/rules/named.md [`default`]: ./docs/rules/default.md [`namespace`]: ./docs/rules/namespace.md [`no-restricted-paths`]: ./docs/rules/no-restricted-paths.md +[`no-absolute-path`]: ./docs/rules/no-absolute-path.md **Helpful warnings:** @@ -52,6 +54,7 @@ This plugin intends to support linting of ES2015+ (ES6+) import/export syntax, a [`no-amd`]: ./docs/rules/no-amd.md [`no-nodejs-modules`]: ./docs/rules/no-nodejs-modules.md + **Style guide:** * Ensure all imports appear before other statements ([`imports-first`]) @@ -61,6 +64,7 @@ This plugin intends to support linting of ES2015+ (ES6+) import/export syntax, a * Enforce a convention in module import order ([`order`]) * Enforce a newline after import statements ([`newline-after-import`]) * Prefer a default export if module exports a single name ([`prefer-default-export`]) +* Limit the maximum number of dependencies a module can have. ([`max-dependencies`]) [`imports-first`]: ./docs/rules/imports-first.md [`no-duplicates`]: ./docs/rules/no-duplicates.md @@ -69,7 +73,7 @@ This plugin intends to support linting of ES2015+ (ES6+) import/export syntax, a [`order`]: ./docs/rules/order.md [`newline-after-import`]: ./docs/rules/newline-after-import.md [`prefer-default-export`]: ./docs/rules/prefer-default-export.md - +[`max-dependencies`]: ./docs/rules/max-dependencies.md ## Installation diff --git a/docs/rules/max-dependencies.md b/docs/rules/max-dependencies.md new file mode 100644 index 000000000..f4aa2a57a --- /dev/null +++ b/docs/rules/max-dependencies.md @@ -0,0 +1,44 @@ +# max-dependencies + +Forbid modules to have too many dependencies (`import` or `require` statements). + +This is a useful rule because a module with too many dependencies is a code smell, and usually indicates the module is doing too much and/or should be broken up into smaller modules. + +Importing multiple named exports from a single module will only count once (e.g. `import {x, y, z} from './foo'` will only count as a single dependency). + +### Options + +This rule takes the following option: + +`max`: The maximum number of dependencies allowed. Anything over will trigger the rule. **Default is 10** if the rule is enabled and no `max` is specified. + +You can set the option like this: + +```js +"import/max-dependencies": ["error", {"max": 10}] +``` + + +## Example + +Given a max value of `{"max": 2}`: + +### Fail + +```js +import a from './a'; // 1 +const b = require('./b'); // 2 +import c from './c'; // 3 - exceeds max! +``` + +### Pass + +```js +import a from './a'; // 1 +const anotherA = require('./a'); // still 1 +import {x, y, z} from './foo'; // 2 +``` + +## When Not To Use It + +If you don't care how many dependencies a module has. diff --git a/docs/rules/no-absolute-path.md b/docs/rules/no-absolute-path.md new file mode 100644 index 000000000..9a4be74f8 --- /dev/null +++ b/docs/rules/no-absolute-path.md @@ -0,0 +1,27 @@ +# Forbid import of modules using absolute paths + +Node.js allows the import of modules using an absolute path such as `/home/xyz/file.js`. That is a bad practice as it ties the code using it to your computer, and therefore makes it unusable in packages distributed on `npm` for instance. + +## Rule Details + +### Fail + +```js +import f from '/foo'; +import f from '/some/path'; + +var f = require('/foo'); +var f = require('/some/path'); +``` + +### Pass + +```js +import _ from 'lodash'; +import foo from 'foo'; +import foo from './foo'; + +var _ = require('lodash'); +var foo = require('foo'); +var foo = require('./foo'); +``` diff --git a/docs/rules/no-extraneous-dependencies.md b/docs/rules/no-extraneous-dependencies.md index 7f57d9706..a15734589 100644 --- a/docs/rules/no-extraneous-dependencies.md +++ b/docs/rules/no-extraneous-dependencies.md @@ -19,6 +19,13 @@ You can set the options like this: "import/no-extraneous-dependencies": ["error", {"devDependencies": false, "optionalDependencies": false, "peerDependencies": false}] ``` +You can also use an array of globs instead of literal booleans: + +```js +"import/no-extraneous-dependencies": ["error", {"devDependencies": ['*.test.js', '*.spec.js']}] +``` + +When using an array of globs, the setting will be activated if the name of the file being linted matches a single glob in the array. ## Rule Details diff --git a/docs/rules/no-nodejs-modules.md b/docs/rules/no-nodejs-modules.md index df3c27e4e..59f1e3693 100644 --- a/docs/rules/no-nodejs-modules.md +++ b/docs/rules/no-nodejs-modules.md @@ -2,6 +2,12 @@ Forbid the use of Node.js builtin modules. Can be useful for client-side web projects that do not have access to those modules. +### Options + +This rule supports the following options: + +- `allow`: Array of names of allowed modules. Defaults to an empty array. + ## Rule Details ### Fail @@ -24,6 +30,9 @@ import foo from './foo'; var _ = require('lodash'); var foo = require('foo'); var foo = require('./foo'); + +/* eslint import/no-nodejs-modules: ["error", {"allow": ["path"]}] */ +import path from 'path'; ``` ## When Not To Use It diff --git a/docs/rules/prefer-default-export.md b/docs/rules/prefer-default-export.md index 560c98964..d3b6fbb0d 100644 --- a/docs/rules/prefer-default-export.md +++ b/docs/rules/prefer-default-export.md @@ -1,6 +1,6 @@ # prefer-default-export -When there is only a single export from a module prefer using default export over named export. +When there is only a single export from a module, prefer using default export over named export. ## Rule Details @@ -9,7 +9,7 @@ The following patterns are considered warnings: ```javascript // bad.js -// There is only a single module export and its a named export. +// There is only a single module export and it's a named export. export const foo = 'foo'; ``` @@ -28,7 +28,7 @@ export default 'bar'; ```javascript // good2.js -// There is more thank one named exports in the module. +// There is more than one named export in the module. export const foo = 'foo'; export const bar = 'bar'; ``` @@ -36,7 +36,7 @@ export const bar = 'bar'; ```javascript // good3.js -// There is more thank one named exports in the module +// There is more than one named export in the module const foo = 'foo'; const bar = 'bar'; export { foo, bar } diff --git a/package.json b/package.json index dde6e7578..c31672dea 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eslint-plugin-import", - "version": "1.14.0", + "version": "1.15.0", "description": "Import with sanity.", "main": "lib/index.js", "directories": { @@ -45,7 +45,7 @@ "homepage": "https://github.com/benmosher/eslint-plugin-import", "devDependencies": { "babel-eslint": "next", - "babel-plugin-istanbul": "^1.0.3", + "babel-plugin-istanbul": "^2.0.1", "babel-preset-es2015": "^6.6.0", "babel-preset-es2015-loose": "^7.0.0", "babel-register": "6.9.0", @@ -64,7 +64,7 @@ "redux": "^3.0.4", "rimraf": "2.5.2", "typescript": "^1.8.10", - "typescript-eslint-parser": "^0.1.1" + "typescript-eslint-parser": "^0.2.0" }, "peerDependencies": { "eslint": "2.x - 3.x" @@ -73,7 +73,7 @@ "builtin-modules": "^1.1.1", "contains-path": "^0.1.0", "debug": "^2.2.0", - "doctrine": "1.2.x", + "doctrine": "1.3.x", "es6-map": "^0.1.3", "es6-set": "^0.1.4", "eslint-import-resolver-node": "^0.2.0", @@ -81,6 +81,7 @@ "lodash.endswith": "^4.0.1", "lodash.find": "^4.3.0", "lodash.findindex": "^4.3.0", + "minimatch": "^3.0.3", "object-assign": "^4.0.1", "pkg-dir": "^1.0.0", "pkg-up": "^1.0.0" diff --git a/resolvers/webpack/README.md b/resolvers/webpack/README.md index f6542825e..1bd1c2e80 100644 --- a/resolvers/webpack/README.md +++ b/resolvers/webpack/README.md @@ -7,6 +7,19 @@ Webpack-literate module resolution plugin for [`eslint-plugin-import`](https://w Published separately to allow pegging to a specific version in case of breaking changes. +To use with `eslint-plugin-import`, run: + +``` +npm i eslint-import-resolver-webpack -g +``` + +or if you manage ESLint as a dev dependency: + +``` +# inside your project's working tree +npm install eslint-import-resolver-webpack --save-dev +``` + Will look for `webpack.config.js` as a sibling of the first ancestral `package.json`, or a `config` parameter may be provided with another filename/path either relative to the `package.json`, or a complete, absolute path. diff --git a/src/core/importType.js b/src/core/importType.js index 02edc0234..5236b1d2a 100644 --- a/src/core/importType.js +++ b/src/core/importType.js @@ -8,6 +8,10 @@ function constant(value) { return () => value } +function isAbsolute(name) { + return name.indexOf('/') === 0 +} + export function isBuiltIn(name, settings) { const extras = (settings && settings['import/core-modules']) || [] return builtinModules.indexOf(name) !== -1 || extras.indexOf(name) > -1 @@ -46,6 +50,7 @@ function isRelativeToSibling(name) { } const typeTest = cond([ + [isAbsolute, constant('absolute')], [isBuiltIn, constant('builtin')], [isExternalModule, constant('external')], [isScoped, constant('external')], diff --git a/src/index.js b/src/index.js index 52d5668c5..5f6077881 100644 --- a/src/index.js +++ b/src/index.js @@ -16,7 +16,9 @@ export const rules = { 'no-amd': require('./rules/no-amd'), 'no-duplicates': require('./rules/no-duplicates'), 'imports-first': require('./rules/imports-first'), + 'max-dependencies': require('./rules/max-dependencies'), 'no-extraneous-dependencies': require('./rules/no-extraneous-dependencies'), + 'no-absolute-path': require('./rules/no-absolute-path'), 'no-nodejs-modules': require('./rules/no-nodejs-modules'), 'order': require('./rules/order'), 'newline-after-import': require('./rules/newline-after-import'), diff --git a/src/rules/max-dependencies.js b/src/rules/max-dependencies.js new file mode 100644 index 000000000..396e21e54 --- /dev/null +++ b/src/rules/max-dependencies.js @@ -0,0 +1,49 @@ +import Set from 'es6-set' +import isStaticRequire from '../core/staticRequire' + +const DEFAULT_MAX = 10 + +const countDependencies = (dependencies, lastNode, context) => { + const {max} = context.options[0] || { max: DEFAULT_MAX } + + if (dependencies.size > max) { + context.report( + lastNode, + `Maximum number of dependencies (${max}) exceeded.` + ) + } +} + +module.exports = context => { + const dependencies = new Set() // keep track of dependencies + let lastNode // keep track of the last node to report on + + return { + ImportDeclaration(node) { + dependencies.add(node.source.value) + lastNode = node.source + }, + + CallExpression(node) { + if (isStaticRequire(node)) { + const [ requirePath ] = node.arguments + dependencies.add(requirePath.value) + lastNode = node + } + }, + + 'Program:exit': function () { + countDependencies(dependencies, lastNode, context) + }, + } +} + +module.exports.schema = [ + { + 'type': 'object', + 'properties': { + 'max': { 'type': 'number' }, + }, + 'additionalProperties': false, + }, +] diff --git a/src/rules/no-absolute-path.js b/src/rules/no-absolute-path.js new file mode 100644 index 000000000..08c8b80fe --- /dev/null +++ b/src/rules/no-absolute-path.js @@ -0,0 +1,21 @@ +import importType from '../core/importType' +import isStaticRequire from '../core/staticRequire' + +function reportIfMissing(context, node, name) { + if (importType(name, context) === 'absolute') { + context.report(node, 'Do not import modules using an absolute path') + } +} + +module.exports = function (context) { + return { + ImportDeclaration: function handleImports(node) { + reportIfMissing(context, node, node.source.value) + }, + CallExpression: function handleRequires(node) { + if (isStaticRequire(node)) { + reportIfMissing(context, node, node.arguments[0].value) + } + }, + } +} diff --git a/src/rules/no-extraneous-dependencies.js b/src/rules/no-extraneous-dependencies.js index 059307e04..65bdb27e5 100644 --- a/src/rules/no-extraneous-dependencies.js +++ b/src/rules/no-extraneous-dependencies.js @@ -1,5 +1,6 @@ import fs from 'fs' import pkgUp from 'pkg-up' +import minimatch from 'minimatch' import importType from '../core/importType' import isStaticRequire from '../core/staticRequire' @@ -71,8 +72,18 @@ function reportIfMissing(context, deps, depsOptions, node, name) { context.report(node, missingErrorMessage(packageName)) } +function testConfig(config, filename) { + // Simplest configuration first, either a boolean or nothing. + if (typeof config === 'boolean' || typeof config === 'undefined') { + return config + } + // Array of globs. + return config.some(c => minimatch(filename, c)) +} + module.exports = function (context) { const options = context.options[0] || {} + const filename = context.getFilename() const deps = getDependencies(context) if (!deps) { @@ -80,9 +91,9 @@ module.exports = function (context) { } const depsOptions = { - allowDevDeps: options.devDependencies !== false, - allowOptDeps: options.optionalDependencies !== false, - allowPeerDeps: options.peerDependencies !== false, + allowDevDeps: testConfig(options.devDependencies, filename) !== false, + allowOptDeps: testConfig(options.optionalDependencies, filename) !== false, + allowPeerDeps: testConfig(options.peerDependencies, filename) !== false, } // todo: use module visitor from module-utils core @@ -102,9 +113,9 @@ module.exports.schema = [ { 'type': 'object', 'properties': { - 'devDependencies': { 'type': 'boolean' }, - 'optionalDependencies': { 'type': 'boolean' }, - 'peerDependencies': { 'type': 'boolean' }, + 'devDependencies': { 'type': ['boolean', 'array'] }, + 'optionalDependencies': { 'type': ['boolean', 'array'] }, + 'peerDependencies': { 'type': ['boolean', 'array'] }, }, 'additionalProperties': false, }, diff --git a/src/rules/no-named-as-default-member.js b/src/rules/no-named-as-default-member.js index ba102e377..fc836a403 100644 --- a/src/rules/no-named-as-default-member.js +++ b/src/rules/no-named-as-default-member.js @@ -69,6 +69,10 @@ module.exports = function(context) { if (fileImport == null) return lookups.forEach(({propName, node}) => { + // the default import can have a "default" property + if (propName === 'default') { + return + } if (fileImport.exportMap.namespace.has(propName)) { context.report({ node, diff --git a/src/rules/no-nodejs-modules.js b/src/rules/no-nodejs-modules.js index 7cdb94ec9..9160b9e8d 100644 --- a/src/rules/no-nodejs-modules.js +++ b/src/rules/no-nodejs-modules.js @@ -1,20 +1,23 @@ import importType from '../core/importType' import isStaticRequire from '../core/staticRequire' -function reportIfMissing(context, node, name) { - if (importType(name, context) === 'builtin') { +function reportIfMissing(context, node, allowed, name) { + if (allowed.indexOf(name) === -1 && importType(name, context) === 'builtin') { context.report(node, 'Do not import Node.js builtin module "' + name + '"') } } module.exports = function (context) { + const options = context.options[0] || {} + const allowed = options.allow || [] + return { ImportDeclaration: function handleImports(node) { - reportIfMissing(context, node, node.source.value) + reportIfMissing(context, node, allowed, node.source.value) }, CallExpression: function handleRequires(node) { if (isStaticRequire(node)) { - reportIfMissing(context, node, node.arguments[0].value) + reportIfMissing(context, node, allowed, node.arguments[0].value) } }, } diff --git a/tests/files/default-export-default-property.js b/tests/files/default-export-default-property.js new file mode 100644 index 000000000..c453da57d --- /dev/null +++ b/tests/files/default-export-default-property.js @@ -0,0 +1,4 @@ + +export default { + default: 'baz' +} diff --git a/tests/src/core/importType.js b/tests/src/core/importType.js index 28a8d7f4e..5b63910af 100644 --- a/tests/src/core/importType.js +++ b/tests/src/core/importType.js @@ -8,6 +8,12 @@ import { testContext } from '../utils' describe('importType(name)', function () { const context = testContext() + it("should return 'absolute' for paths starting with a /", function() { + expect(importType('/', context)).to.equal('absolute') + expect(importType('/path', context)).to.equal('absolute') + expect(importType('/some/path', context)).to.equal('absolute') + }) + it("should return 'builtin' for node.js modules", function() { expect(importType('fs', context)).to.equal('builtin') expect(importType('path', context)).to.equal('builtin') @@ -47,7 +53,7 @@ describe('importType(name)', function () { expect(importType('./importType/index.js', context)).to.equal('sibling') }) - describe("should return 'index' for sibling index file", function() { + it("should return 'index' for sibling index file", function() { expect(importType('.', context)).to.equal('index') expect(importType('./', context)).to.equal('index') expect(importType('./index', context)).to.equal('index') @@ -55,7 +61,8 @@ describe('importType(name)', function () { }) it("should return 'unknown' for any unhandled cases", function() { - expect(importType('/malformed', context)).to.equal('unknown') + expect(importType('@malformed', context)).to.equal('unknown') + expect(importType(' /malformed', context)).to.equal('unknown') expect(importType(' foo', context)).to.equal('unknown') }) diff --git a/tests/src/rules/max-dependencies.js b/tests/src/rules/max-dependencies.js new file mode 100644 index 000000000..7377c1451 --- /dev/null +++ b/tests/src/rules/max-dependencies.js @@ -0,0 +1,78 @@ +import { test } from '../utils' + +import { RuleTester } from 'eslint' + +const ruleTester = new RuleTester() + , rule = require('rules/max-dependencies') + +ruleTester.run('max-dependencies', rule, { + valid: [ + test({ code: 'import "./foo.js"' }), + + test({ code: 'import "./foo.js"; import "./bar.js";', + options: [{ + max: 2, + }], + }), + + test({ code: 'import "./foo.js"; import "./bar.js"; const a = require("./foo.js"); const b = require("./bar.js");', + options: [{ + max: 2, + }], + }), + + test({ code: 'import {x, y, z} from "./foo"'}), + ], + invalid: [ + test({ + code: 'import { x } from \'./foo\'; import { y } from \'./foo\'; import {z} from \'./bar\';', + options: [{ + max: 1, + }], + errors: [ + 'Maximum number of dependencies (1) exceeded.', + ], + }), + + test({ + code: 'import { x } from \'./foo\'; import { y } from \'./bar\'; import { z } from \'./baz\';', + options: [{ + max: 2, + }], + errors: [ + 'Maximum number of dependencies (2) exceeded.', + ], + }), + + test({ + code: 'import { x } from \'./foo\'; require("./bar"); import { z } from \'./baz\';', + options: [{ + max: 2, + }], + errors: [ + 'Maximum number of dependencies (2) exceeded.', + ], + }), + + test({ + code: 'import { x } from \'./foo\'; import { z } from \'./foo\'; require("./bar"); const path = require("path");', + options: [{ + max: 2, + }], + errors: [ + 'Maximum number of dependencies (2) exceeded.', + ], + }), + + test({ + code: 'import type { x } from \'./foo\'; import type { y } from \'./bar\'', + parser: 'babel-eslint', + options: [{ + max: 1, + }], + errors: [ + 'Maximum number of dependencies (1) exceeded.', + ], + }), + ], +}) diff --git a/tests/src/rules/no-absolute-path.js b/tests/src/rules/no-absolute-path.js new file mode 100644 index 000000000..88951672b --- /dev/null +++ b/tests/src/rules/no-absolute-path.js @@ -0,0 +1,86 @@ +import { test } from '../utils' + +import { RuleTester } from 'eslint' + +const ruleTester = new RuleTester() + , rule = require('rules/no-absolute-path') + +const error = { + ruleId: 'no-absolute-path', + message: 'Do not import modules using an absolute path', +} + +ruleTester.run('no-absolute-path', rule, { + valid: [ + test({ code: 'import _ from "lodash"'}), + test({ code: 'import find from "lodash.find"'}), + test({ code: 'import foo from "./foo"'}), + test({ code: 'import foo from "../foo"'}), + test({ code: 'import foo from "foo"'}), + test({ code: 'import foo from "./"'}), + test({ code: 'import foo from "@scope/foo"'}), + test({ code: 'var _ = require("lodash")'}), + test({ code: 'var find = require("lodash.find")'}), + test({ code: 'var foo = require("./foo")'}), + test({ code: 'var foo = require("../foo")'}), + test({ code: 'var foo = require("foo")'}), + test({ code: 'var foo = require("./")'}), + test({ code: 'var foo = require("@scope/foo")'}), + test({ + code: 'import events from "events"', + options: [{ + allow: ['events'], + }], + }), + test({ + code: 'import path from "path"', + options: [{ + allow: ['path'], + }], + }), + test({ + code: 'var events = require("events")', + options: [{ + allow: ['events'], + }], + }), + test({ + code: 'var path = require("path")', + options: [{ + allow: ['path'], + }], + }), + test({ + code: 'import path from "path";import events from "events"', + options: [{ + allow: ['path', 'events'], + }], + }), + ], + invalid: [ + test({ + code: 'import f from "/foo"', + errors: [error], + }), + test({ + code: 'import f from "/foo/path"', + errors: [error], + }), + test({ + code: 'import f from "/some/path"', + errors: [error], + }), + test({ + code: 'var f = require("/foo")', + errors: [error], + }), + test({ + code: 'var f = require("/foo/path")', + errors: [error], + }), + test({ + code: 'var f = require("/some/path")', + errors: [error], + }), + ], +}) diff --git a/tests/src/rules/no-extraneous-dependencies.js b/tests/src/rules/no-extraneous-dependencies.js index f0b43b09b..4d739ee71 100644 --- a/tests/src/rules/no-extraneous-dependencies.js +++ b/tests/src/rules/no-extraneous-dependencies.js @@ -35,6 +35,16 @@ ruleTester.run('no-extraneous-dependencies', rule, { code: 'import "importType"', settings: { 'import/resolver': { node: { paths: [ path.join(__dirname, '../../files') ] } } }, }), + test({ + code: 'import chai from "chai"', + options: [{devDependencies: ['*.spec.js']}], + filename: 'foo.spec.js', + }), + test({ + code: 'import chai from "chai"', + options: [{devDependencies: ['*.test.js', '*.spec.js']}], + filename: 'foo.spec.js', + }), ], invalid: [ test({ @@ -89,6 +99,24 @@ ruleTester.run('no-extraneous-dependencies', rule, { message: '\'glob\' should be listed in the project\'s dependencies, not devDependencies.', }], }), + test({ + code: 'import chai from "chai"', + options: [{devDependencies: ['*.test.js']}], + filename: 'foo.tes.js', + errors: [{ + ruleId: 'no-extraneous-dependencies', + message: '\'chai\' should be listed in the project\'s dependencies, not devDependencies.', + }], + }), + test({ + code: 'import chai from "chai"', + options: [{devDependencies: ['*.test.js', '*.spec.js']}], + filename: 'foo.tes.js', + errors: [{ + ruleId: 'no-extraneous-dependencies', + message: '\'chai\' should be listed in the project\'s dependencies, not devDependencies.', + }], + }), test({ code: 'var eslint = require("lodash.isarray")', options: [{optionalDependencies: false}], diff --git a/tests/src/rules/no-named-as-default-member.js b/tests/src/rules/no-named-as-default-member.js index 559794b30..b5e294d19 100644 --- a/tests/src/rules/no-named-as-default-member.js +++ b/tests/src/rules/no-named-as-default-member.js @@ -10,6 +10,7 @@ ruleTester.run('no-named-as-default-member', rule, { test({code: 'import bar from "./bar"; const baz = bar.baz'}), test({code: 'import {foo} from "./bar"; const baz = foo.baz;'}), test({code: 'import * as named from "./named-exports"; const a = named.a'}), + test({code: 'import foo from "./default-export-default-property"; const a = foo.default'}), ...SYNTAX_CASES, ], diff --git a/tests/src/rules/no-nodejs-modules.js b/tests/src/rules/no-nodejs-modules.js index 826640e31..b5e55fafc 100644 --- a/tests/src/rules/no-nodejs-modules.js +++ b/tests/src/rules/no-nodejs-modules.js @@ -26,6 +26,36 @@ ruleTester.run('no-nodejs-modules', rule, { test({ code: 'var foo = require("foo")'}), test({ code: 'var foo = require("./")'}), test({ code: 'var foo = require("@scope/foo")'}), + test({ + code: 'import events from "events"', + options: [{ + allow: ['events'], + }], + }), + test({ + code: 'import path from "path"', + options: [{ + allow: ['path'], + }], + }), + test({ + code: 'var events = require("events")', + options: [{ + allow: ['events'], + }], + }), + test({ + code: 'var path = require("path")', + options: [{ + allow: ['path'], + }], + }), + test({ + code: 'import path from "path";import events from "events"', + options: [{ + allow: ['path', 'events'], + }], + }), ], invalid: [ test({ @@ -44,5 +74,12 @@ ruleTester.run('no-nodejs-modules', rule, { code: 'var fs = require("fs")', errors: [error('Do not import Node.js builtin module "fs"')], }), + test({ + code: 'import fs from "fs"', + options: [{ + allow: ['path'], + }], + errors: [error('Do not import Node.js builtin module "fs"')], + }), ], })