Skip to content

🐛 v5.86.0 seems confused about namespaces #1603

@Jym77

Description

@Jym77

Prerequisites

Reproduction url

https://codesandbox.io/p/devbox/4v8dfp

Reproduction access

  • I've made sure the reproduction is publicly accessible

Description of the issue

This seems to be a change from v5.85.0 to v5.86.0, although I couldn't identify it from the changelog.

I'm exporting values from inside (exported) namespaces that are imported as namespaces, and the values are used. In v5.85.0, knip wasn't flagging it (including false negatives with not flagging the unused one); in v5.86.0, knip is flagging everything, including false positives with flagging the used ones.


foo.ts:

export namespace Foo {
  export const foo = 1;
  export const unusedFoo = 2;

  export namespace Nested {
    export const innerFoo = 3;
    export const foo = 4;
  }
}

export namespace Bar {
  export const bar = 1;
  export const unusedBar = 2;

  export namespace Nested {
    export const innerBar = 3;
  }
}

export namespace Baz {
  export const baz = 1;
  export const unusedBaz = 2;

  export namespace Nested {
    export const innerBaz = 3;
  }
}

export const qux = 0;
export namespace Qux {
  export const qux = 1;

  export const unusedQux = 2;

  export namespace Nested {
    export const innerQux = 3;
  }
}

index.ts:

import { Foo, Bar } from "./foo.js";
import * as NS from "./foo.js";
import { qux, Qux } from "./foo.js";

console.log(Foo.foo + Foo.Nested.innerFoo);

const { Nested, bar } = Bar;
console.log(bar + Nested.innerBar);

console.log(NS.Baz.baz + NS.Baz.Nested.innerBaz);

console.log(qux + Qux.qux + Qux.Nested.innerQux);

knip output (v5.86.0):

Unused exports (11)
foo        NS  src/foo.ts:2:16 
unusedFoo  NS  src/foo.ts:3:16 
innerFoo   NS  src/foo.ts:6:18 
bar        NS  src/foo.ts:11:16
unusedBar  NS  src/foo.ts:12:16
innerBar   NS  src/foo.ts:15:18
baz        NS  src/foo.ts:20:16
unusedBaz  NS  src/foo.ts:21:16
innerBaz   NS  src/foo.ts:24:18
unusedQux  NS  src/foo.ts:32:16
innerQux   NS  src/foo.ts:35:18

Expected: only the unused* should be reported (plus Foo.Nested.foo) as all the rest is directly used.

At first, I thought it was something about accessing nested namespaces, hence the difference in usage between Foo and Bar.
Baz is here to have a "namespace import", maybe a more frequent pattern than exporting namespaces like I do here, inspired by this knip documentation page, but it doesn't change behaviour.

Qux is maybe the most interesting as qux is not reported. However, the Qux.qux pattern is the same as the other ones. I assume it is not reported (like Foo.foo is) only because the (non-fully qualified) name collides with the simple qux name, which is used. That belief is reinforced by the fact that knip outputs non-fully qualified names only (foo instead of Foo.foo, innerFoo instead of Foo.Nested.innerFoo, …), I guess for the sake of simplicity. And Foo.Nested.foo also has that collision (only one foo reported, and with line number corresponding to the first one, hence incorrect since the first one is used, but the second isn't).

I tried --include nsExports as it felt like it is related to namespace, but that didn't change anything.

When switching to v5.85.0, nothing is reported, not even the unused* that are truly unused.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions