📄 no-redeclare.ts¶
📊 Analysis Summary¶
| Metric | Count |
|---|---|
| 🔧 Functions | 3 |
| 📦 Imports | 6 |
| 📊 Variables & Constants | 6 |
| 📑 Type Aliases | 2 |
📚 Table of Contents¶
🛠️ File Location:¶
📂 packages/eslint-plugin/src/rules/no-redeclare.ts
📦 Imports¶
| Name | Source |
|---|---|
TSESLint |
@typescript-eslint/utils |
TSESTree |
@typescript-eslint/utils |
ScopeType |
@typescript-eslint/scope-manager |
AST_NODE_TYPES |
@typescript-eslint/utils |
createRule |
../util |
getNameLocationInGlobalDirectiveComment |
../util |
Variables & Constants¶
| Name | Type | Kind | Value | Exported |
|---|---|---|---|---|
CLASS_DECLARATION_MERGE_NODES |
Set<AST_NODE_TYPES> |
const | `new Set |
|
| AST_NODE_TYPES.ClassDeclaration, | ||||
| AST_NODE_TYPES.TSInterfaceDeclaration, | ||||
| AST_NODE_TYPES.TSModuleDeclaration, | ||||
| ])` | ✗ | |||
FUNCTION_DECLARATION_MERGE_NODES |
Set<AST_NODE_TYPES> |
const | `new Set |
|
| AST_NODE_TYPES.FunctionDeclaration, | ||||
| AST_NODE_TYPES.TSModuleDeclaration, | ||||
| ])` | ✗ | |||
ENUM_DECLARATION_MERGE_NODES |
Set<AST_NODE_TYPES> |
const | `new Set |
|
| AST_NODE_TYPES.TSEnumDeclaration, | ||||
| AST_NODE_TYPES.TSModuleDeclaration, | ||||
| ])` | ✗ | |||
detailMessageId |
"redeclaredAsBuiltin" | "redeclaredBySyntax" |
const | `declaration.type === 'builtin' | |
| ? 'redeclaredAsBuiltin' | ||||
| : 'redeclaredBySyntax'` | ✗ | |||
data |
{ id: any; } |
const | { id: variable.name } |
✗ |
messageId |
"redeclaredAsBuiltin" | "redeclaredBySyntax" | "redeclared" |
const | type === declaration.type ? 'redeclared' : detailMessageId |
✗ |
Functions¶
`iterateDeclarations(variable: TSESLint.Scope.Variable): Generator<¶
{
loc?: TSESTree.SourceLocation;
node?: TSESTree.Comment | TSESTree.Identifier;
type: 'builtin' | 'comment' | 'syntax';
},
void
>`
Code
function* iterateDeclarations(variable: TSESLint.Scope.Variable): Generator<
{
loc?: TSESTree.SourceLocation;
node?: TSESTree.Comment | TSESTree.Identifier;
type: 'builtin' | 'comment' | 'syntax';
},
void
> {
if (
options.builtinGlobals &&
'eslintImplicitGlobalSetting' in variable &&
(variable.eslintImplicitGlobalSetting === 'readonly' ||
variable.eslintImplicitGlobalSetting === 'writable')
) {
yield { type: 'builtin' };
}
if (
'eslintExplicitGlobalComments' in variable &&
variable.eslintExplicitGlobalComments
) {
for (const comment of variable.eslintExplicitGlobalComments) {
yield {
loc: getNameLocationInGlobalDirectiveComment(
context.sourceCode,
comment,
variable.name,
),
node: comment,
type: 'comment',
};
}
}
const identifiers = variable.identifiers
.map(id => ({
identifier: id,
parent: id.parent,
}))
// ignore function declarations because TS will treat them as an overload
.filter(
({ parent }) => parent.type !== AST_NODE_TYPES.TSDeclareFunction,
);
if (options.ignoreDeclarationMerge && identifiers.length > 1) {
if (
// interfaces merging
identifiers.every(
({ parent }) =>
parent.type === AST_NODE_TYPES.TSInterfaceDeclaration,
)
) {
return;
}
if (
// namespace/module merging
identifiers.every(
({ parent }) => parent.type === AST_NODE_TYPES.TSModuleDeclaration,
)
) {
return;
}
if (
// class + interface/namespace merging
identifiers.every(({ parent }) =>
CLASS_DECLARATION_MERGE_NODES.has(parent.type),
)
) {
const classDecls = identifiers.filter(
({ parent }) => parent.type === AST_NODE_TYPES.ClassDeclaration,
);
if (classDecls.length === 1) {
// safe declaration merging
return;
}
// there's more than one class declaration, which needs to be reported
for (const { identifier } of classDecls) {
yield { loc: identifier.loc, node: identifier, type: 'syntax' };
}
return;
}
if (
// class + interface/namespace merging
identifiers.every(({ parent }) =>
FUNCTION_DECLARATION_MERGE_NODES.has(parent.type),
)
) {
const functionDecls = identifiers.filter(
({ parent }) => parent.type === AST_NODE_TYPES.FunctionDeclaration,
);
if (functionDecls.length === 1) {
// safe declaration merging
return;
}
// there's more than one function declaration, which needs to be reported
for (const { identifier } of functionDecls) {
yield { loc: identifier.loc, node: identifier, type: 'syntax' };
}
return;
}
if (
// enum + namespace merging
identifiers.every(({ parent }) =>
ENUM_DECLARATION_MERGE_NODES.has(parent.type),
)
) {
const enumDecls = identifiers.filter(
({ parent }) => parent.type === AST_NODE_TYPES.TSEnumDeclaration,
);
if (enumDecls.length === 1) {
// safe declaration merging
return;
}
// there's more than one enum declaration, which needs to be reported
for (const { identifier } of enumDecls) {
yield { loc: identifier.loc, node: identifier, type: 'syntax' };
}
return;
}
}
for (const { identifier } of identifiers) {
yield { loc: identifier.loc, node: identifier, type: 'syntax' };
}
}
- Parameters:
variable: TSESLint.Scope.Variable- Return Type:
Generator< { loc?: TSESTree.SourceLocation; node?: TSESTree.Comment | TSESTree.Identifier; type: 'builtin' | 'comment' | 'syntax'; }, void > - Calls:
getNameLocationInGlobalDirectiveComment (from ../util)variable.identifiers .map(id => ({ identifier: id, parent: id.parent, })) // ignore function declarations because TS will treat them as an overload .filteridentifiers.everyCLASS_DECLARATION_MERGE_NODES.hasidentifiers.filterFUNCTION_DECLARATION_MERGE_NODES.hasENUM_DECLARATION_MERGE_NODES.has- Internal Comments:
// interfaces merging (x3) // namespace/module merging (x3) // class + interface/namespace merging (x6) // safe declaration merging (x3) // there's more than one class declaration, which needs to be reported // there's more than one function declaration, which needs to be reported // enum + namespace merging (x3) // there's more than one enum declaration, which needs to be reported
findVariablesInScope(scope: TSESLint.Scope.Scope): void¶
Code
function findVariablesInScope(scope: TSESLint.Scope.Scope): void {
for (const variable of scope.variables) {
const [declaration, ...extraDeclarations] =
iterateDeclarations(variable);
if (extraDeclarations.length === 0) {
continue;
}
/*
* If the type of a declaration is different from the type of
* the first declaration, it shows the location of the first
* declaration.
*/
const detailMessageId =
declaration.type === 'builtin'
? 'redeclaredAsBuiltin'
: 'redeclaredBySyntax';
const data = { id: variable.name };
// Report extra declarations.
for (const { loc, node, type } of extraDeclarations) {
const messageId =
type === declaration.type ? 'redeclared' : detailMessageId;
if (node) {
context.report({ loc, node, messageId, data });
} else if (loc) {
context.report({ loc, messageId, data });
}
}
}
}
- Parameters:
scope: TSESLint.Scope.Scope- Return Type:
void - Calls:
iterateDeclarationscontext.report- Internal Comments:
checkForBlock(node: TSESTree.Node): void¶
Code
-
JSDoc:
-
Parameters:
node: TSESTree.Node- Return Type:
void - Calls:
context.sourceCode.getScopefindVariablesInScope- Internal Comments: