diff --git a/packages/eslint-plugin/README.md b/packages/eslint-plugin/README.md
index 4d3e4c308e8..05d0a88ebcd 100644
--- a/packages/eslint-plugin/README.md
+++ b/packages/eslint-plugin/README.md
@@ -157,7 +157,6 @@ Then you should add `airbnb` (or `airbnb-base`) to your `extends` section of `.e
| [`@typescript-eslint/no-non-null-assertion`](./docs/rules/no-non-null-assertion.md) | Disallows non-null assertions using the `!` postfix operator | :heavy_check_mark: | | |
| [`@typescript-eslint/no-object-literal-type-assertion`](./docs/rules/no-object-literal-type-assertion.md) | Forbids an object literal to appear in a type assertion expression | :heavy_check_mark: | | |
| [`@typescript-eslint/no-parameter-properties`](./docs/rules/no-parameter-properties.md) | Disallow the use of parameter properties in class constructors | :heavy_check_mark: | | |
-| [`@typescript-eslint/no-reference-import`](./docs/rules/no-reference-import.md) | Disallow simultaneous use of `/// ` comments and ES6 style imports for the same module | | | |
| [`@typescript-eslint/no-require-imports`](./docs/rules/no-require-imports.md) | Disallows invocation of `require()` | | | |
| [`@typescript-eslint/no-this-alias`](./docs/rules/no-this-alias.md) | Disallow aliasing `this` | | | |
| [`@typescript-eslint/no-triple-slash-reference`](./docs/rules/no-triple-slash-reference.md) | Disallow `/// ` comments | :heavy_check_mark: | | |
@@ -178,6 +177,7 @@ Then you should add `airbnb` (or `airbnb-base`) to your `extends` section of `.e
| [`@typescript-eslint/require-array-sort-compare`](./docs/rules/require-array-sort-compare.md) | Enforce giving `compare` argument to `Array#sort` | | | :thought_balloon: |
| [`@typescript-eslint/restrict-plus-operands`](./docs/rules/restrict-plus-operands.md) | When adding two variables, operands must both be of type number or of type string | | | :thought_balloon: |
| [`@typescript-eslint/semi`](./docs/rules/semi.md) | Require or disallow semicolons instead of ASI | | :wrench: | |
+| [`@typescript-eslint/triple-slash-reference`](./docs/rules/triple-slash-reference.md) | Sets preference level for triple slash directives versus ES6-style import declarations | | | |
| [`@typescript-eslint/type-annotation-spacing`](./docs/rules/type-annotation-spacing.md) | Require consistent spacing around type annotations | :heavy_check_mark: | :wrench: | |
| [`@typescript-eslint/unbound-method`](./docs/rules/unbound-method.md) | Enforces unbound methods are called with their expected scope | | | :thought_balloon: |
| [`@typescript-eslint/unified-signatures`](./docs/rules/unified-signatures.md) | Warns for any two overloads that could be unified into one by using a union or an optional/rest parameter | | | |
diff --git a/packages/eslint-plugin/docs/rules/no-reference-import.md b/packages/eslint-plugin/docs/rules/no-reference-import.md
deleted file mode 100644
index 05a7db9dcae..00000000000
--- a/packages/eslint-plugin/docs/rules/no-reference-import.md
+++ /dev/null
@@ -1,37 +0,0 @@
-# Disallow simultaneous use of `/// ` comments and ES6 style imports for the same module. (no-reference-import)
-
-Use of triple-slash directives is discouraged in favor of the newer `import` style. In cases where both styles might occur, this rule prevents use of triple-slash references for modules which are otherwise imported.
-
-Use `no-triple-slash-reference` instead if you intend to ban triple slash directives entirely.
-
-## Rule Details
-
-Examples of **incorrect** code for this rule:
-
-```ts
-///
-import * as foo from 'foo';
-```
-
-```ts
-///
-import foo = require('foo');
-```
-
-Examples of **correct** code for this rule:
-
-```ts
-import * as foo from 'foo';
-```
-
-```ts
-import foo = require('foo');
-```
-
-## When To Use It
-
-Any time you might use triple-slash directives and ES6 import declarations in the same file.
-
-## When Not To Use It
-
-If you intend to ban triple slash directives entirely.
diff --git a/packages/eslint-plugin/docs/rules/triple-slash-reference.md b/packages/eslint-plugin/docs/rules/triple-slash-reference.md
new file mode 100644
index 00000000000..b09fc741097
--- /dev/null
+++ b/packages/eslint-plugin/docs/rules/triple-slash-reference.md
@@ -0,0 +1,58 @@
+# Sets preference level for triple slash directives versus ES6-style import declarations. (triple-slash-reference)
+
+Use of triple-slash reference type directives is discouraged in favor of the newer `import` style. This rule allows you to ban use of `/// `, `/// `, or `/// ` directives.
+
+If you use the `no-triple-slash-reference` rule, consider using this rule instead.
+
+## Rule Details
+
+With `{ "path": "never", "types": "never", "lib": "never" }` options set, the following will all be **incorrect** usage:
+
+```ts
+///
+///
+///
+```
+
+Examples of **incorrect** code for the `{ "types": "prefer-import" }` option. Note that these are only errors when **both** stlyes are used for the **same** module:
+
+```ts
+///
+import * as foo from 'foo';
+```
+
+```ts
+///
+import foo = require('foo');
+```
+
+With `{ "path": "always", "types": "always", "lib": "always" }` options set, the following will all be **correct** usage:
+
+```ts
+///
+///
+///
+```
+
+Examples of **correct** code for the `{ "types": "prefer-import" }` option:
+
+```ts
+import * as foo from 'foo';
+```
+
+```ts
+import foo = require('foo');
+```
+
+## When To Use It
+
+If you want to ban use of one or all of the triple slash reference directives, or any time you might use triple-slash type reference directives and ES6 import declarations in the same file.
+
+## When Not To Use It
+
+If you want to use all flavors of triple slash reference directives.
+
+## Compatibility
+
+- TSLint: [no-reference](http://palantir.github.io/tslint/rules/no-reference/)
+- TSLint: [no-reference-import](https://palantir.github.io/tslint/rules/no-reference-import/)
diff --git a/packages/eslint-plugin/src/rules/index.ts b/packages/eslint-plugin/src/rules/index.ts
index d12e6542a10..2c16956758f 100644
--- a/packages/eslint-plugin/src/rules/index.ts
+++ b/packages/eslint-plugin/src/rules/index.ts
@@ -31,7 +31,6 @@ import noNamespace from './no-namespace';
import noNonNullAssertion from './no-non-null-assertion';
import noObjectLiteralTypeAssertion from './no-object-literal-type-assertion';
import noParameterProperties from './no-parameter-properties';
-import noReferenceImport from './no-reference-import';
import noRequireImports from './no-require-imports';
import noThisAlias from './no-this-alias';
import noTripleSlashReference from './no-triple-slash-reference';
@@ -53,6 +52,7 @@ import promiseFunctionAsync from './promise-function-async';
import requireArraySortCompare from './require-array-sort-compare';
import restrictPlusOperands from './restrict-plus-operands';
import semi from './semi';
+import tripleSlashReference from './triple-slash-reference';
import typeAnnotationSpacing from './type-annotation-spacing';
import unboundMethod from './unbound-method';
import unifiedSignatures from './unified-signatures';
@@ -91,7 +91,6 @@ export default {
'no-non-null-assertion': noNonNullAssertion,
'no-object-literal-type-assertion': noObjectLiteralTypeAssertion,
'no-parameter-properties': noParameterProperties,
- 'no-reference-import': noReferenceImport,
'no-require-imports': noRequireImports,
'no-this-alias': noThisAlias,
'no-triple-slash-reference': noTripleSlashReference,
@@ -113,6 +112,7 @@ export default {
'require-array-sort-compare': requireArraySortCompare,
'restrict-plus-operands': restrictPlusOperands,
semi: semi,
+ 'triple-slash-reference': tripleSlashReference,
'type-annotation-spacing': typeAnnotationSpacing,
'unbound-method': unboundMethod,
'unified-signatures': unifiedSignatures,
diff --git a/packages/eslint-plugin/src/rules/no-reference-import.ts b/packages/eslint-plugin/src/rules/no-reference-import.ts
deleted file mode 100644
index 7a7fee23a22..00000000000
--- a/packages/eslint-plugin/src/rules/no-reference-import.ts
+++ /dev/null
@@ -1,78 +0,0 @@
-import * as util from '../util';
-import {
- Literal,
- Node,
- TSExternalModuleReference,
-} from '@typescript-eslint/typescript-estree/dist/ts-estree/ts-estree';
-import { TSESTree } from '@typescript-eslint/typescript-estree';
-
-export default util.createRule({
- name: 'no-reference-import',
- meta: {
- type: 'suggestion',
- docs: {
- description:
- 'Disallow simultaneous use of `/// ` comments and ES6 style imports for the same module',
- category: 'Best Practices',
- recommended: false,
- },
- schema: [],
- messages: {
- noReferenceImport: 'Do not reference {{module}} if importing it anyway.',
- },
- },
- defaultOptions: [],
- create(context) {
- let programNode: Node;
- const sourceCode = context.getSourceCode();
- const references: ({
- comment: TSESTree.Comment;
- importName: string;
- })[] = [];
-
- function hasMatchingReference(source: Literal) {
- references.forEach(reference => {
- if (reference.importName === source.value) {
- context.report({
- node: reference.comment,
- messageId: 'noReferenceImport',
- data: {
- module: reference.importName,
- },
- });
- }
- });
- }
- return {
- ImportDeclaration(node) {
- if (programNode) {
- const source = node.source as Literal;
- hasMatchingReference(source);
- }
- },
- TSImportEqualsDeclaration(node) {
- if (programNode) {
- const source = (node.moduleReference as TSExternalModuleReference)
- .expression as Literal;
- hasMatchingReference(source);
- }
- },
- Program(node) {
- programNode = node;
- const referenceRegExp = /^\/\s* {
- if (comment.type !== 'Line') {
- return;
- }
- const referenceResult = referenceRegExp.exec(comment.value);
-
- if (referenceResult && referenceResult[1]) {
- references.push({ comment, importName: referenceResult[1] });
- }
- });
- },
- };
- },
-});
diff --git a/packages/eslint-plugin/src/rules/no-triple-slash-reference.ts b/packages/eslint-plugin/src/rules/no-triple-slash-reference.ts
index c7780a99bf3..5d24bb48e2c 100644
--- a/packages/eslint-plugin/src/rules/no-triple-slash-reference.ts
+++ b/packages/eslint-plugin/src/rules/no-triple-slash-reference.ts
@@ -11,7 +11,7 @@ export default util.createRule({
},
schema: [],
messages: {
- tripleSlashReference: 'Do not use a triple slash reference.',
+ noTripleSlashReference: 'Do not use a triple slash reference.',
},
},
defaultOptions: [],
@@ -30,7 +30,7 @@ export default util.createRule({
if (referenceRegExp.test(comment.value)) {
context.report({
node: comment,
- messageId: 'tripleSlashReference',
+ messageId: 'noTripleSlashReference',
});
}
});
diff --git a/packages/eslint-plugin/src/rules/triple-slash-reference.ts b/packages/eslint-plugin/src/rules/triple-slash-reference.ts
new file mode 100644
index 00000000000..286f445c966
--- /dev/null
+++ b/packages/eslint-plugin/src/rules/triple-slash-reference.ts
@@ -0,0 +1,129 @@
+import * as util from '../util';
+import {
+ Literal,
+ Node,
+ TSExternalModuleReference,
+} from '@typescript-eslint/typescript-estree/dist/ts-estree/ts-estree';
+import { TSESTree } from '@typescript-eslint/typescript-estree';
+
+type Options = [
+ {
+ lib?: 'always' | 'never';
+ path?: 'always' | 'never';
+ types?: 'always' | 'never' | 'prefer-import';
+ }
+];
+type MessageIds = 'tripleSlashReference';
+
+export default util.createRule({
+ name: 'triple-slash-reference',
+ meta: {
+ type: 'suggestion',
+ docs: {
+ description:
+ 'Sets preference level for triple slash directives versus ES6-style import declarations',
+ category: 'Best Practices',
+ recommended: false,
+ },
+ messages: {
+ tripleSlashReference:
+ 'Do not use a triple slash reference for {{module}}, use `import` style instead.',
+ },
+ schema: [
+ {
+ type: 'object',
+ properties: {
+ lib: {
+ enum: ['always', 'never'],
+ },
+ path: {
+ enum: ['always', 'never'],
+ },
+ types: {
+ enum: ['always', 'never', 'prefer-import'],
+ },
+ },
+ additionalProperties: false,
+ },
+ ],
+ },
+ defaultOptions: [
+ {
+ lib: 'always',
+ path: 'never',
+ types: 'prefer-import',
+ },
+ ],
+ create(context, [{ lib, path, types }]) {
+ let programNode: Node;
+ const sourceCode = context.getSourceCode();
+ const references: ({
+ comment: TSESTree.Comment;
+ importName: string;
+ })[] = [];
+
+ function hasMatchingReference(source: Literal) {
+ references.forEach(reference => {
+ if (reference.importName === source.value) {
+ context.report({
+ node: reference.comment,
+ messageId: 'tripleSlashReference',
+ data: {
+ module: reference.importName,
+ },
+ });
+ }
+ });
+ }
+ return {
+ ImportDeclaration(node) {
+ if (programNode) {
+ const source = node.source as Literal;
+ hasMatchingReference(source);
+ }
+ },
+ TSImportEqualsDeclaration(node) {
+ if (programNode) {
+ const source = (node.moduleReference as TSExternalModuleReference)
+ .expression as Literal;
+ hasMatchingReference(source);
+ }
+ },
+ Program(node) {
+ if (lib === 'always' && path === 'always' && types == 'always') {
+ return;
+ }
+ programNode = node;
+ const referenceRegExp = /^\/\s* {
+ if (comment.type !== 'Line') {
+ return;
+ }
+ const referenceResult = referenceRegExp.exec(comment.value);
+
+ if (referenceResult) {
+ if (
+ (referenceResult[1] === 'types' && types === 'never') ||
+ (referenceResult[1] === 'path' && path === 'never') ||
+ (referenceResult[1] === 'lib' && lib === 'never')
+ ) {
+ context.report({
+ node: comment,
+ messageId: 'tripleSlashReference',
+ data: {
+ module: referenceResult[2],
+ },
+ });
+ return;
+ }
+ if (referenceResult[1] === 'types' && types === 'prefer-import') {
+ references.push({ comment, importName: referenceResult[2] });
+ }
+ }
+ });
+ },
+ };
+ },
+});
diff --git a/packages/eslint-plugin/tests/rules/no-reference-import.test.ts b/packages/eslint-plugin/tests/rules/no-reference-import.test.ts
deleted file mode 100644
index 20ddd2b94c6..00000000000
--- a/packages/eslint-plugin/tests/rules/no-reference-import.test.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-import rule from '../../src/rules/no-reference-import';
-import { RuleTester } from '../RuleTester';
-
-const ruleTester = new RuleTester({
- parserOptions: {
- sourceType: 'module',
- },
- parser: '@typescript-eslint/parser',
-});
-
-ruleTester.run('no-reference-import', rule, {
- valid: [
- `///
- var foo = require("foo");`,
- `///
- import * as foo from "foo"`,
- ],
- invalid: [
- {
- code: `
-///
-import * as foo from "foo"
- `,
-
- parser: '@typescript-eslint/parser',
- errors: [
- {
- messageId: 'noReferenceImport',
- line: 2,
- column: 1,
- },
- ],
- },
- {
- code: `
-///
-import foo = require("foo");
- `,
- parser: '@typescript-eslint/parser',
- errors: [
- {
- messageId: 'noReferenceImport',
- line: 2,
- column: 1,
- },
- ],
- },
- ],
-});
diff --git a/packages/eslint-plugin/tests/rules/no-triple-slash-reference.test.ts b/packages/eslint-plugin/tests/rules/no-triple-slash-reference.test.ts
index 5beaf104e52..f120d526243 100644
--- a/packages/eslint-plugin/tests/rules/no-triple-slash-reference.test.ts
+++ b/packages/eslint-plugin/tests/rules/no-triple-slash-reference.test.ts
@@ -22,7 +22,7 @@ let a
code: '/// ',
errors: [
{
- messageId: 'tripleSlashReference',
+ messageId: 'noTripleSlashReference',
line: 1,
column: 1,
},
@@ -36,7 +36,7 @@ let a
parser: '@typescript-eslint/parser',
errors: [
{
- messageId: 'tripleSlashReference',
+ messageId: 'noTripleSlashReference',
line: 2,
column: 1,
},
diff --git a/packages/eslint-plugin/tests/rules/triple-slash-reference.test.ts b/packages/eslint-plugin/tests/rules/triple-slash-reference.test.ts
new file mode 100644
index 00000000000..2e235f1751c
--- /dev/null
+++ b/packages/eslint-plugin/tests/rules/triple-slash-reference.test.ts
@@ -0,0 +1,122 @@
+import rule from '../../src/rules/triple-slash-reference';
+import { RuleTester } from '../RuleTester';
+
+const ruleTester = new RuleTester({
+ parserOptions: {
+ sourceType: 'module',
+ },
+ parser: '@typescript-eslint/parser',
+});
+
+ruleTester.run('triple-slash-reference', rule, {
+ valid: [
+ {
+ code: `
+ ///
+ import * as foo from "foo"
+ `,
+ options: [{ path: 'always' }],
+ },
+ {
+ code: `
+ ///
+ import * as foo from "foo"
+ `,
+ options: [{ types: 'always' }],
+ },
+ {
+ code: `
+ ///
+ import * as foo from "foo"
+ `,
+ options: [{ lib: 'always' }],
+ },
+ {
+ code: `
+ import * as foo from "foo"
+ `,
+ options: [{ path: 'never' }],
+ },
+ {
+ code: `
+ import * as foo from "foo"
+ `,
+ options: [{ types: 'never' }],
+ },
+ {
+ code: `
+ import * as foo from "foo"
+ `,
+ options: [{ lib: 'never' }],
+ },
+ {
+ code: `
+ import * as foo from "foo"
+ `,
+ options: [{ types: 'prefer-import' }],
+ },
+ ],
+ invalid: [
+ {
+ code: `
+///
+import * as foo from "foo"
+ `,
+ options: [{ types: 'prefer-import' }],
+ errors: [
+ {
+ messageId: 'tripleSlashReference',
+ line: 2,
+ column: 1,
+ },
+ ],
+ },
+ {
+ code: `
+///
+import foo = require("foo");
+ `,
+ options: [{ types: 'prefer-import' }],
+ errors: [
+ {
+ messageId: 'tripleSlashReference',
+ line: 2,
+ column: 1,
+ },
+ ],
+ },
+ {
+ code: `/// `,
+ options: [{ path: 'never' }],
+ errors: [
+ {
+ messageId: 'tripleSlashReference',
+ line: 1,
+ column: 1,
+ },
+ ],
+ },
+ {
+ code: `/// `,
+ options: [{ types: 'never' }],
+ errors: [
+ {
+ messageId: 'tripleSlashReference',
+ line: 1,
+ column: 1,
+ },
+ ],
+ },
+ {
+ code: `/// `,
+ options: [{ lib: 'never' }],
+ errors: [
+ {
+ messageId: 'tripleSlashReference',
+ line: 1,
+ column: 1,
+ },
+ ],
+ },
+ ],
+});