From 6ce065ea395d355ef3b32099a7bdf70ecd998da1 Mon Sep 17 00:00:00 2001 From: Lars Kappert Date: Sun, 24 Mar 2024 10:50:38 +0100 Subject: [PATCH] Fix `pos` for computed props in class members (closes #360) --- packages/knip/fixtures/class-members/index.ts | 2 ++ .../class-members/iterator-generator.ts | 23 +++++++++++++++++++ .../knip/fixtures/class-members/iterator.ts | 10 ++++++++ .../visitors/exports/exportKeyword.ts | 3 ++- packages/knip/test/class-members.test.ts | 14 ++++++----- 5 files changed, 45 insertions(+), 7 deletions(-) create mode 100644 packages/knip/fixtures/class-members/iterator-generator.ts create mode 100644 packages/knip/fixtures/class-members/iterator.ts diff --git a/packages/knip/fixtures/class-members/index.ts b/packages/knip/fixtures/class-members/index.ts index 17b94da53..a3a838e20 100644 --- a/packages/knip/fixtures/class-members/index.ts +++ b/packages/knip/fixtures/class-members/index.ts @@ -1,4 +1,6 @@ import { MyClass } from './members'; +import { AbstractClassGen, ExtendedClassGen } from './iterator-generator'; +import { AbstractClass, ExtendedClass } from './iterator'; const instance = new MyClass(); diff --git a/packages/knip/fixtures/class-members/iterator-generator.ts b/packages/knip/fixtures/class-members/iterator-generator.ts new file mode 100644 index 000000000..f1b16ee92 --- /dev/null +++ b/packages/knip/fixtures/class-members/iterator-generator.ts @@ -0,0 +1,23 @@ +export abstract class AbstractClassGen { + protected constructor() {} + + public abstract implemented(): AbstractClassGen; + + public abstract unimplemented(): AbstractClassGen; + + public abstract [Symbol.iterator](): Iterator; +} + +export class ExtendedClassGen extends AbstractClassGen { + public constructor() { + super(); + } + + public implemented(): AbstractClassGen { + return this; + } + + public *[Symbol.iterator](): Iterator { + yield this; + } +} diff --git a/packages/knip/fixtures/class-members/iterator.ts b/packages/knip/fixtures/class-members/iterator.ts new file mode 100644 index 000000000..46eb04cf9 --- /dev/null +++ b/packages/knip/fixtures/class-members/iterator.ts @@ -0,0 +1,10 @@ +export abstract class AbstractClass { + public abstract implemented(): AbstractClass; + public abstract [Symbol.toStringTag](): AbstractClass; +} + +export class ExtendedClass extends AbstractClass { + public implemented(): AbstractClass { + return this; + } +} diff --git a/packages/knip/src/typescript/visitors/exports/exportKeyword.ts b/packages/knip/src/typescript/visitors/exports/exportKeyword.ts index b33fd1cd4..46742cc13 100644 --- a/packages/knip/src/typescript/visitors/exports/exportKeyword.ts +++ b/packages/knip/src/typescript/visitors/exports/exportKeyword.ts @@ -97,7 +97,8 @@ export default visit( .map(member => ({ node: member, identifier: member.name.getText(), - pos: member.name.getStart(), + // Naive, but [does.the.job()] + pos: member.name.getStart() + (ts.isComputedPropertyName(member.name) ? 1 : 0), type: SymbolType.MEMBER, fix: undefined, })) diff --git a/packages/knip/test/class-members.test.ts b/packages/knip/test/class-members.test.ts index 30023e644..765737960 100644 --- a/packages/knip/test/class-members.test.ts +++ b/packages/knip/test/class-members.test.ts @@ -14,6 +14,7 @@ test('Find unused class members', async () => { }); assert.equal(Object.keys(issues.classMembers['members.ts']).length, 6); + assert(issues.classMembers['iterator-generator.ts']['unimplemented']); assert(issues.classMembers['members.ts']['bUnusedPublic']); assert(issues.classMembers['members.ts']['cUnusedProp']); assert(issues.classMembers['members.ts']['dUnusedMember']); @@ -23,9 +24,9 @@ test('Find unused class members', async () => { assert.deepEqual(counters, { ...baseCounters, - classMembers: 6, - processed: 2, - total: 2, + classMembers: 7, + processed: 4, + total: 4, }); }); @@ -37,6 +38,7 @@ test('Find unused class members (isIncludeEntryExports)', async () => { }); assert.equal(Object.keys(issues.classMembers['members.ts']).length, 6); + assert(issues.classMembers['iterator-generator.ts']['unimplemented']); assert(issues.classMembers['index.ts']['unusedMemberInEntry']); assert(issues.classMembers['members.ts']['bUnusedPublic']); assert(issues.classMembers['members.ts']['cUnusedProp']); @@ -47,8 +49,8 @@ test('Find unused class members (isIncludeEntryExports)', async () => { assert.deepEqual(counters, { ...baseCounters, - classMembers: 7, - processed: 2, - total: 2, + classMembers: 8, + processed: 4, + total: 4, }); });