Description
When a file declares a class with extends and references its own name internally (e.g. Object.setPrototypeOf(this, SystemError.prototype)), unimport incorrectly injects an import for that class, causing an "Identifier has already been declared" error.
Root cause
The RE_EXCLUDE class regex in src/regexp.ts:10 is:
/\bclass\s*([\w$]+)\s*\{/g
This matches class Foo { but not class Foo extends Bar { — the extends Bar part breaks the pattern since it expects \s*\{ immediately after the class name.
As a result, the class name is not removed from the occurrenceMap in detect-regex.ts, and any self-reference within the class body gets auto-imported.
Reproduction
Failing unit test against current main:
it('should not inject import for class with extends that references itself', async () => {
const { injectImports } = createUnimport({
imports: [{ name: 'SystemError', from: 'test-id' }],
})
const code = `export class SystemError extends Error {
constructor(message) {
super(message);
Object.setPrototypeOf(this, SystemError.prototype);
}
}`
expect((await injectImports(code)).code).toBe(code)
})
Expected: no import injected (class is locally declared)
Actual: import { SystemError } from 'test-id'; is injected at the top
Suggested fix
Simplify the regex to only capture the class name without requiring the opening brace:
This correctly handles extends, implements, generics, multiline declarations, etc. since we only need the name.
Downstream
Reported in nuxt/nuxt#26516
Description
When a file declares a class with
extendsand references its own name internally (e.g.Object.setPrototypeOf(this, SystemError.prototype)), unimport incorrectly injects an import for that class, causing an "Identifier has already been declared" error.Root cause
The
RE_EXCLUDEclass regex insrc/regexp.ts:10is:This matches
class Foo {but notclass Foo extends Bar {— theextends Barpart breaks the pattern since it expects\s*\{immediately after the class name.As a result, the class name is not removed from the
occurrenceMapindetect-regex.ts, and any self-reference within the class body gets auto-imported.Reproduction
Failing unit test against current
main:Expected: no import injected (class is locally declared)
Actual:
import { SystemError } from 'test-id';is injected at the topSuggested fix
Simplify the regex to only capture the class name without requiring the opening brace:
/\bclass\s+([\w$]+)/gThis correctly handles
extends,implements, generics, multiline declarations, etc. since we only need the name.Downstream
Reported in nuxt/nuxt#26516