-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Commit
* feat(eslint-plugin): added no-reference-import rule * docs: added docs for no-reference-import * fix(eslint-plugin): collect references when visiting the program node * feat(eslint-plugin): updated rule to cover more reference directives * fix(eslint-plugin): deprecated rule and added coverage * Update README.md
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 `/// <reference path="" />`, `/// <reference types="" />`, or `/// <reference lib="" />` directives. | ||
|
||
Consider using this rule in place of [`no-triple-slash-reference`](./no-triple-slash-reference.md) which has been deprecated. | ||
|
||
## Rule Details | ||
|
||
With `{ "path": "never", "types": "never", "lib": "never" }` options set, the following will all be **incorrect** usage: | ||
|
||
```ts | ||
/// <reference path="foo" /> | ||
/// <reference types="bar" /> | ||
/// <reference lib="baz" /> | ||
``` | ||
|
||
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 | ||
/// <reference types="foo" /> | ||
import * as foo from 'foo'; | ||
``` | ||
|
||
```ts | ||
/// <reference types="foo" /> | ||
import foo = require('foo'); | ||
``` | ||
|
||
With `{ "path": "always", "types": "always", "lib": "always" }` options set, the following will all be **correct** usage: | ||
|
||
```ts | ||
/// <reference path="foo" /> | ||
/// <reference types="bar" /> | ||
/// <reference lib="baz" /> | ||
``` | ||
|
||
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/) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<Options, MessageIds>({ | ||
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', | ||
}, | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
bradzacher
Member
|
||
], | ||
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*<reference\s*(types|path|lib)\s*=\s*["|'](.*)["|']/; | ||
const commentsBefore = sourceCode.getCommentsBefore(programNode); | ||
|
||
commentsBefore.forEach(comment => { | ||
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] }); | ||
} | ||
} | ||
}); | ||
}, | ||
}; | ||
}, | ||
}); |
Could anyone explain why these defaults were chosen and not, for example, never/never/never, please?