Skip to content
This repository has been archived by the owner on Mar 25, 2021. It is now read-only.

Commit

Permalink
no-duplicate-imports: Allow duplicate imports from separate ambient m…
Browse files Browse the repository at this point in the history
…odule declarations (#3398)
  • Loading branch information
Andy authored and ajafff committed Oct 26, 2017
1 parent a17cef5 commit 0176122
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 7 deletions.
26 changes: 19 additions & 7 deletions src/rules/noDuplicateImportsRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* limitations under the License.
*/

import { findImports, ImportKind } from "tsutils";
import { isImportDeclaration, isLiteralExpression, isModuleDeclaration } from "tsutils";
import * as ts from "typescript";
import * as Lint from "../index";

Expand Down Expand Up @@ -44,13 +44,25 @@ export class Rule extends Lint.Rules.AbstractRule {
}
}

function walk(ctx: Lint.WalkContext<void>) {
const seen = new Set<string>();
for (const {text, parent} of findImports(ctx.sourceFile, ImportKind.ImportDeclaration)) {
if (seen.has(text)) {
ctx.addFailureAtNode(parent!, Rule.FAILURE_STRING(text));
} else {
function walk(ctx: Lint.WalkContext<void>): void {
walkWorker(ctx, ctx.sourceFile.statements, new Set());
}

function walkWorker(ctx: Lint.WalkContext<void>, statements: ReadonlyArray<ts.Statement>, seen: Set<string>): void {
for (const statement of statements) {
if (isImportDeclaration(statement) && isLiteralExpression(statement.moduleSpecifier)) {
const { text } = statement.moduleSpecifier;
if (seen.has(text)) {
ctx.addFailureAtNode(statement, Rule.FAILURE_STRING(text));
}
seen.add(text);
}

if (isModuleDeclaration(statement) && statement.body !== undefined && statement.name.kind === ts.SyntaxKind.StringLiteral) {
// If this is a module augmentation, re-use `seen` since those imports could be moved outside.
// If this is an ambient module, create a fresh `seen`
// because they should have separate imports to avoid becoming augmentations.
walkWorker(ctx, (statement.body as ts.ModuleBlock).statements, ts.isExternalModule(ctx.sourceFile) ? seen : new Set());
}
}
}
8 changes: 8 additions & 0 deletions test/rules/no-duplicate-imports/test2.d.ts.lint
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
declare module 'a' {
import foo from 'foo';
}

declare module 'b' {
// No error -- this is a separate ambient module declaration.
import foo from 'foo';
}
11 changes: 11 additions & 0 deletions test/rules/no-duplicate-imports/test3.d.ts.lint
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export {};

declare module 'a' {
import foo from 'foo';
}

declare module 'b' {
// Error because these imports could be combined in an outer scope.
import foo from 'foo';
~~~~~~~~~~~~~~~~~~~~~~ [Multiple imports from 'foo' can be combined into one.]
}

0 comments on commit 0176122

Please sign in to comment.