Skip to content

source.organizeImports removes re-exports when wildcard and non-wildcard exports are mixed #62626

@tesaguri

Description

@tesaguri

🔎 Search Terms

organizeImports, Organize Imports, export, wildcard, glob, remove, delete

🕗 Version & Regression Information

$ tsc --version
Version 5.9.3
$ typescript-language-server --version
5.0.1

I haven't tried other versions.

I'm calling the code action via Neovim's LSP support this Ex command:

:lua for _, client in pairs(vim.lsp.get_clients({ bufnr = 0 })) do if vim.list_contains(client.server_capabilities.codeActionProvider.codeActionKinds, "source.organizeImports.ts") then client:exec_cmd({ command = "_typescript.
organizeImports", arguments = { vim.api.nvim_buf_get_name(0) } }) end end

Version of Neovim:

$ nvim -V1 -v
NVIM v0.11.4
Build type: Release
LuaJIT 2.1.1753364724

   system vimrc file: "$VIM/sysinit.vim"
  fall-back for $VIM: "/opt/homebrew/Cellar/neovim/0.11.4/share/nvim"

Run :checkhealth for more info

Result of :checkhealth vim.lsp:

vim.lsp:                                                                    ✅

- LSP log level : WARN
- Log path: /Users/tesaguri/.local/state/nvim/lsp.log
- Log size: 2650 KB

vim.lsp: Active Clients
- ts_ls (id: 1)
  - Version: ? (no serverInfo.version response)
  - Root directory: ~/workspace/tests/organize-imports-multi-exports
  - Command: { "typescript-language-server", "--stdio" }
  - Settings: {}
  - Attached buffers: 1, 3

I originally encountered the issue when using prettier-plugin-organize-imports@4.3.0 plugin of prettier@3.6.2, which uses the Language Service API.

⏯ Playground Link

https://www.typescriptlang.org/play/?#code/KYDwDg9gTgLgBAKjgQwM5wLYQCYFcA2wcAZlBBnAEQB0A9FnodQFaqUDcAUKJLHAN5wAKgE8wRAL4kyFGvRwFgLNuyA (index.ts only)

💻 Code

src/index.ts:

export * as module from "./module.js";
export { Type } from "./module.js";

src/module.ts:

export interface Type {}
export function fn() {}

tsconfig.json:

{
  "include": ["./src/"],
  "compilerOptions": {
    "rootDir": "./src",
    "outDir": "./dist",
    "strict": true
  }
}

🙁 Actual behavior

source.organizeImports removes the second export in index.ts, resulting in code like the following:

export * as module from "./module.js";

Note that this alters the public API of the module, removing Type from it.

🙂 Expected behavior

source.organizeImports should keep the second export:

export * as module from "./module.js";
export { Type } from "./module.js";

Additional information about the issue

When there is no wildcard export, the code action works as expected:

export { Type } from "./module.js";
export { fn } from "./module.js";

is organized into:

export { fn, Type } from "./module.js";

The export will not be removed when you add the type specifier to either of the exports, like so:

export type * as module from "./module.js";
export { Type } from "./module.js";

or

export * as module from "./module.js";
export type { Type } from "./module.js";

But if you add the type specifier to both of the exports, the issue reproduces again:

export type * as module from "./module.js";
export type { Type } from "./module.js"; // This line will be deleted.

This issue looks similar to #61588 in that the other issue also affects export statements when the code action shouldn't touch exports, but that issue doesn't seem to remove re-exports unlike this issue.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions