withastro / astro · Issue No. 18102
Astro v7.3.1
Node v24.14.1
System macOS (arm64)
Package Manager pnpm
Output static
Adapter none
Integrations @astrojs/mdx
@astrojs/preact
No response
Since @astrojs/language-server 2.17.0, the source.organizeImports code action duplicates the last import statement in every .astro file whose frontmatter ends with an import (typical for pages and layouts). With source.organizeImports enabled on save, the file grows by one import per save and stops compiling after the second save.
Example file:
---
import Hello from '../components/Hello.astro'
import Layout from '../layouts/Layout.astro'
---
<Layout title="Demo">
<Hello />
</Layout>
After one Organize Imports:
---
import Hello from '../components/Hello.astro';
import Layout from '../layouts/Layout.astro';
import Layout from '../layouts/Layout.astro'
---
What happens, as far as I could trace it:
@astrojs/astro2tsx (0.1.0). It emits ;{};<Fragment> directly after the frontmatter, where @astrojs/compiler's convertToTSX used to emit {};<Fragment>.; (virtual TSX 4:0-6:1 instead of 4:0-5:0 with 2.16.16).; has no source mapping, so the delete edit cannot be mapped back and is dropped. The replace edit is kept, so the last import is inserted a second time.Edits as returned by the server for the file above (from a minimal LSP client, see the reproduction):
@astrojs/language-server 2.17.0, typescript 6.0.3
edits sent to the client (mapped to the .astro file):
1:0-2:0 "import Hello from '../components/Hello.astro';\nimport Layout from '../layouts/Layout.astro';\n"
original TypeScript edits (virtual TSX):
3:0-4:0 "import Hello from '../components/Hello.astro';\nimport Layout from '../layouts/Layout.astro';\n"
4:0-6:1 ""
@astrojs/language-server 2.16.16, typescript 6.0.3
edits sent to the client (mapped to the .astro file):
1:0-2:0 "import Hello from '../components/Hello.astro';\nimport Layout from '../layouts/Layout.astro';\n"
2:0-3:0 ""
original TypeScript edits (virtual TSX):
3:0-4:0 "import Hello from '../components/Hello.astro';\nimport Layout from '../layouts/Layout.astro';\n"
4:0-5:0 ""
2.16.13, 2.16.14 and 2.16.16 all return the correct pair of edits with the same TypeScript version, so this is separate from #17811 (fixed in #17820) and specific to 2.17.0.
Files whose frontmatter continues after the imports (e.g. a type Props = … block) are not affected, because the delete range then ends at mapped source text.
Organize Imports removes the old import statements and inserts the sorted list once, as in 2.16.16. Either the generated TSX should not start the template marker with an unmapped ; right after the frontmatter, or edits whose end falls into generated text should be clipped to the mapped region instead of being dropped.
https://github.com/ausminternet/astro-duplicated-organized-imports
Relay reads this issue against the repository's contribution signals: the files it is likely to touch, how the maintainers triage work this size, and what the first contribution would exercise.
The full analysis for this issue is still being assembled. Until then, the description above and the thread on GitHub are the most reliable context.