Skip to content

Commit

Permalink
Add support for destructuring pattern on member access of (re)exporte…
Browse files Browse the repository at this point in the history
…d symbol
  • Loading branch information
webpro committed Apr 18, 2024
1 parent 73aacf2 commit 933dd35
Show file tree
Hide file tree
Showing 10 changed files with 65 additions and 13 deletions.
5 changes: 5 additions & 0 deletions packages/knip/fixtures/re-exports-ns-member/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import * as NS from './sub3';

const { memberA, memberB } = NS.sub;

const { memberC, memberD } = NS.pseudo;
2 changes: 2 additions & 0 deletions packages/knip/fixtures/re-exports-ns-member/member-ab.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const memberA = 1;
export const memberB = 1;
2 changes: 2 additions & 0 deletions packages/knip/fixtures/re-exports-ns-member/member-cd.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const memberC = 1;
export const memberD = 1;
3 changes: 3 additions & 0 deletions packages/knip/fixtures/re-exports-ns-member/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"name": "@fixtures/re-exports-ns-member"
}
2 changes: 2 additions & 0 deletions packages/knip/fixtures/re-exports-ns-member/sub1.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './member-ab';
export * from './member-cd';
4 changes: 4 additions & 0 deletions packages/knip/fixtures/re-exports-ns-member/sub2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * as sub from './sub1';

import * as pseudo from './sub1';
export { pseudo };
1 change: 1 addition & 0 deletions packages/knip/fixtures/re-exports-ns-member/sub3.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './sub2';
4 changes: 2 additions & 2 deletions packages/knip/fixtures/workspaces-pnpm/apps/a/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import defaultA, { usedExportFromLibA } from '@scoped/lib-a';
import defaultB, { usedExportFromLibB } from '@scoped/lib-b';
import defaultA, { usedExportFromLibA } from '@workspaces-pnpm/lib-a';
import defaultB, { usedExportFromLibB } from '@workspaces-pnpm/lib-b';
import { c } from 'unlisted';

defaultA;
Expand Down
34 changes: 23 additions & 11 deletions packages/knip/src/typescript/getImportsAndExports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -298,17 +298,29 @@ const getImportsAndExports = (
const symbol = sourceFile.locals?.get(String(node.escapedText));
if (symbol) {
if (importedInternalSymbols.has(symbol)) {
let members: string[] = [];
let current: ts.Node = node.parent;
while (current) {
const ms = getMemberStringLiterals(typeChecker, current);
if (!ms) break;
members = members.concat(
ms.flatMap(id => (members.length === 0 ? id : members.map(ns => `${ns}.${id}`)))
);
current = current.parent;
if (
ts.isVariableDeclarationList(node.parent.parent.parent) &&
ts.isVariableDeclaration(node.parent.parent) &&
ts.isObjectBindingPattern(node.parent.parent.name) &&
ts.isPropertyAccessExpression(node.parent)
) {
const ns = String(symbol.escapedName);
const key = String(node.parent.name.escapedText);
const members = node.parent.parent.name.elements.map(element => `${key}.${element.name.getText()}`);
maybeAddAccessExpressionAsNsImport(ns, key);
maybeAddAccessExpressionAsNsImport(ns, members);
} else {
let members: string[] = [];
let current: ts.Node = node.parent;
while (current) {
const ms = getMemberStringLiterals(typeChecker, current);
if (!ms) break;
const joinIds = (id: string) => (members.length === 0 ? id : members.map(ns => `${ns}.${id}`));
members = members.concat(ms.flatMap(joinIds));
current = current.parent;
}
maybeAddAccessExpressionAsNsImport(String(node.escapedText), members);
}
maybeAddAccessExpressionAsNsImport(String(node.escapedText), members);
}
}
} else if (
Expand All @@ -331,7 +343,7 @@ const getImportsAndExports = (
if (symbol) {
const importedSymbolFilePath = importedInternalSymbols.get(symbol);
if (importedSymbolFilePath) {
const members = node.parent.name.elements.flatMap(decl => decl.name.getText());
const members = node.parent.name.elements.map(element => element.name.getText());
maybeAddAccessExpressionAsNsImport(String(node.escapedText), members);
}
}
Expand Down
21 changes: 21 additions & 0 deletions packages/knip/test/re-exports-ns-member.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { test } from 'bun:test';
import assert from 'node:assert/strict';
import { main } from '../src/index.js';
import { resolve } from '../src/util/path.js';
import baseArguments from './helpers/baseArguments.js';
import baseCounters from './helpers/baseCounters.js';

const cwd = resolve('fixtures/re-exports-ns-member');

test('Find destructured props of member-accessed imported symbol', async () => {
const { counters } = await main({
...baseArguments,
cwd,
});

assert.deepEqual(counters, {
...baseCounters,
processed: 6,
total: 6,
});
});

0 comments on commit 933dd35

Please sign in to comment.