Skip to content

Commit

Permalink
fix namespace imports
Browse files Browse the repository at this point in the history
  • Loading branch information
florianbgt committed Nov 9, 2024
1 parent a725bc2 commit a891f5b
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 35 deletions.
1 change: 1 addition & 0 deletions packages/cli/src/helper/cleanup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ export function cleanupUnusedFiles(
source: string;
importSpecifierIdentifiers: Parser.SyntaxNode[];
importIdentifier?: Parser.SyntaxNode;
namespaceImport?: Parser.SyntaxNode;
}[];
if (language.name === "javascript") {
dependencies = getJavascriptImports(parser, tree.rootNode);
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/helper/dependencyTree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export function getDependencyTree(filePath: string): DependencyTree {
source: string;
importSpecifierIdentifiers: Parser.SyntaxNode[];
importIdentifier?: Parser.SyntaxNode;
namespaceImport?: Parser.SyntaxNode;
}[];
if (language.name === "javascript") {
imports = getJavascriptImports(parser, tree.rootNode);
Expand Down
38 changes: 37 additions & 1 deletion packages/cli/src/helper/languages/javascript/cleanup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,10 +227,32 @@ export function cleanupUnusedJavascriptImports(
}
}

let removeNameSpaceImport = false;
if (depImport.namespaceImport) {
let usages = isTypescript
? getTypescriptImportIdentifierUsage(
parser,
tree.rootNode,
depImport.namespaceImport,
)
: getJavascriptImportIdentifierUsage(
parser,
tree.rootNode,
depImport.namespaceImport,
);
usages = usages.filter((usage) => {
return usage.id !== depImport.importIdentifier?.id;
});
if (usages.length === 0) {
removeNameSpaceImport = true;
}
}

if (
importSpecifierToRemove.length ===
depImport.importSpecifierIdentifiers.length &&
(removeDefaultImport || !depImport.importIdentifier)
(removeDefaultImport || !depImport.importIdentifier) &&
(removeNameSpaceImport || !depImport.namespaceImport)
) {
indexesToRemove.push({
startIndex: depImport.node.startIndex,
Expand All @@ -243,6 +265,20 @@ export function cleanupUnusedJavascriptImports(
endIndex: importSpecifier.endIndex,
});
});

if (removeDefaultImport && depImport.importIdentifier) {
indexesToRemove.push({
startIndex: depImport.importIdentifier.startIndex,
endIndex: depImport.importIdentifier.endIndex,
});
}

if (removeNameSpaceImport && depImport.namespaceImport) {
indexesToRemove.push({
startIndex: depImport.namespaceImport.startIndex,
endIndex: depImport.namespaceImport.endIndex,
});
}
}
});

Expand Down
14 changes: 6 additions & 8 deletions packages/cli/src/helper/languages/javascript/imports.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import { test1, test2 } from './test';
expect(imports[1].importSpecifierIdentifiers[1].text).toBe("test2");
});

it("Should extract import identifier", () => {
it("Should extract import identifier and namespace import", () => {
const parser = new Parser();
parser.setLanguage(Javascript);

Expand All @@ -44,18 +44,16 @@ import * as test from './test';
expect(imports.length).toBe(2);

expect(imports[0].source).toBe("@nestjs/common");

expect(imports[0].importIdentifier).not.toBe(undefined);
expect(imports[0].importIdentifier?.text).toBe("common");

expect(imports[0].namespaceImport).toBe(undefined);
expect(imports[0].importSpecifierIdentifiers.length).toBe(0);

expect(imports[1].source).toBe("./test");

expect(imports[1].importIdentifier).not.toBe(undefined);
expect(imports[1].importIdentifier?.text).toBe("test");

expect(imports[0].importSpecifierIdentifiers.length).toBe(0);
expect(imports[1].importIdentifier).toBe(undefined);
expect(imports[1].namespaceImport).not.toBe(undefined);
expect(imports[1].namespaceImport?.text).toBe("test");
expect(imports[1].importSpecifierIdentifiers.length).toBe(0);
});

it("Should work with require import", () => {
Expand Down
60 changes: 42 additions & 18 deletions packages/cli/src/helper/languages/javascript/imports.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import Parser from "tree-sitter";

function getFromImportStatements(parser: Parser, node: Parser.SyntaxNode) {
function getImportStatements(parser: Parser, node: Parser.SyntaxNode) {
const imports: {
node: Parser.SyntaxNode;
source: string;
importSpecifierIdentifiers: Parser.SyntaxNode[];
importIdentifier?: Parser.SyntaxNode;
namespaceImport?: Parser.SyntaxNode;
}[] = [];

const importStatementQuery = new Parser.Query(
Expand Down Expand Up @@ -53,16 +54,9 @@ function getFromImportStatements(parser: Parser, node: Parser.SyntaxNode) {
const importClauseIdentifierQuery = new Parser.Query(
parser.getLanguage(),
`
([
(import_clause
(identifier) @identifier
)
(import_clause
(namespace_import
(identifier) @identifier
)
)
])
(import_clause
(identifier) @identifier
)
`,
);
const importClauseIdentifierCaptures = importClauseIdentifierQuery.captures(
Expand All @@ -75,26 +69,44 @@ function getFromImportStatements(parser: Parser, node: Parser.SyntaxNode) {
? importClauseIdentifierCaptures[0].node
: undefined;

const nameSpaceimportClauseIdentifierQuery = new Parser.Query(
parser.getLanguage(),
`
(import_clause
(namespace_import
(identifier) @identifier
)
)
`,
);
const nameSpaceimportClauseIdentifierCaptures =
nameSpaceimportClauseIdentifierQuery.captures(capture.node);
if (nameSpaceimportClauseIdentifierCaptures.length > 1) {
throw new Error("Found multiple namespace import clause identifier");
}
const namespaceImport = nameSpaceimportClauseIdentifierCaptures.length
? nameSpaceimportClauseIdentifierCaptures[0].node
: undefined;

imports.push({
node: capture.node,
source,
importSpecifierIdentifiers,
importIdentifier,
namespaceImport,
});
});

return imports;
}

function getFromRequireAndDynamicImports(
parser: Parser,
node: Parser.SyntaxNode,
) {
function getRequireAndDynamicImports(parser: Parser, node: Parser.SyntaxNode) {
const imports: {
node: Parser.SyntaxNode;
source: string;
importSpecifierIdentifiers: Parser.SyntaxNode[];
importIdentifier?: Parser.SyntaxNode;
namespaceImport?: undefined;
}[] = [];

const requireStatementQuery = new Parser.Query(
Expand Down Expand Up @@ -230,15 +242,16 @@ function getFromRequireAndDynamicImports(
source,
importSpecifierIdentifiers,
importIdentifier,
namespaceImport: undefined,
});
});

return imports;
}

export function getJavascriptImports(parser: Parser, node: Parser.SyntaxNode) {
const imports = getFromImportStatements(parser, node);
imports.push(...getFromRequireAndDynamicImports(parser, node));
const imports = getImportStatements(parser, node);
imports.push(...getRequireAndDynamicImports(parser, node));

return imports;
}
Expand All @@ -255,7 +268,10 @@ export function getJavascriptImportIdentifierUsage(
isTypescript
? `
(
([(identifier) (type_identifier)]) @identifier
([
(identifier)
(type_identifier)
]) @identifier
(#eq? @identifier "${identifier.text}")
)
`
Expand All @@ -278,6 +294,14 @@ export function getJavascriptImportIdentifierUsage(
if (targetNode.parent && targetNode.parent.type === "array") {
break;
}

if (
targetNode.parent &&
targetNode.parent.type === "expression_statement"
) {
break;
}

// TODO: add more cases as we encounter them

if (!targetNode.parent) {
Expand Down
12 changes: 5 additions & 7 deletions packages/cli/src/helper/languages/typescript/imports.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,16 @@ import * as test from './test';
expect(imports.length).toBe(2);

expect(imports[0].source).toBe("@nestjs/common");

expect(imports[0].importIdentifier).not.toBe(undefined);
expect(imports[0].importIdentifier?.text).toBe("common");

expect(imports[0].namespaceImport).toBe(undefined);
expect(imports[0].importSpecifierIdentifiers.length).toBe(0);

expect(imports[1].source).toBe("./test");

expect(imports[1].importIdentifier).not.toBe(undefined);
expect(imports[1].importIdentifier?.text).toBe("test");

expect(imports[0].importSpecifierIdentifiers.length).toBe(0);
expect(imports[1].importIdentifier).toBe(undefined);
expect(imports[1].namespaceImport).not.toBe(undefined);
expect(imports[1].namespaceImport?.text).toBe("test");
expect(imports[1].importSpecifierIdentifiers.length).toBe(0);
});

it("Should work with require import", () => {
Expand Down
1 change: 0 additions & 1 deletion packages/cli/src/helper/split.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ export async function createSplit(
outputDirectory,
groupMapIndex.toString(),
);

files.forEach((file) => {
const relativeFileNamePath = path.relative(targetDir, file.path);
const destinationPath = path.join(
Expand Down

0 comments on commit a891f5b

Please sign in to comment.