mirror of
https://github.com/oxc-project/oxc.git
synced 2026-09-14 19:36:11 +08:00
a9e76e9e1f
Follow-up to #25063. tsx-in-vue was supported in #25063 with a parse-retry (ts fails → retry as tsx), chosen to keep the common ts path single-parse. However, this leaves a hole: a `lang="tsx"` block without JSX parses fine as plain ts, so the retry never fires and the lone generic comma is removed: ```vue <script setup lang="tsx"> const identity = <T,>(x: T) => x; // → <T>(x: T) => x, breaks as TS17008 </script> ``` Since parse failure fundamentally cannot detect this, the only fix is to scan the `lang` declaration itself. The JS host now scans the SFC once per file and passes `_oxfmtVueScriptLang: "tsx"` down to `textToDoc()`. This makes the retry obsolete, so it is removed. This PR also settles the comma policy: keep it only where it is load-bearing. - JSX grammar (`<T>` would be a JSX opener) - and `.mts/.cts` (TS7060, #18928) and remove it everywhere else, keyed on the grammar, regardless of context. Deliberate divergence: Prettier keys on filepath and keeps the comma in ts-in-vue/svelte (while its own ts-in-md embed uses `dummy.ts` as `filepath` and removes it). Plain-TS sources now behave identically wherever they live.
53 lines
1.5 KiB
TypeScript
53 lines
1.5 KiB
TypeScript
/**
|
|
* Prettier plugin that uses `oxc_formatter` for (j|t)s-in-xxx part.
|
|
*
|
|
* When Prettier formats Vue/HTML (which can embed JS/TS code inside) files,
|
|
* it calls the `embed()` function for each block.
|
|
*
|
|
* By default, it uses the `babel` or `typescript` parser and `estree` printer.
|
|
* Therefore, by overriding these internally, we can use `oxc_formatter` instead.
|
|
* e.g. Now it's possible to apply our builtin sort-imports for JS/TS code inside Vue `<script>`.
|
|
*/
|
|
|
|
import { textToDoc } from "./text-to-doc";
|
|
import type { Parser, Printer, Doc, SupportOptions } from "prettier";
|
|
|
|
// NOTE: Custom options must be declared here,
|
|
// or Prettier's normalization drops them before they reach `textToDoc()`.
|
|
export const options: SupportOptions = {
|
|
_oxfmtPluginOptionsJson: {
|
|
category: "JavaScript",
|
|
type: "string",
|
|
default: "{}",
|
|
description: "Bundled JSON string for oxfmt-plugin options",
|
|
},
|
|
_oxfmtVueScriptLang: {
|
|
category: "JavaScript",
|
|
type: "string",
|
|
default: "",
|
|
description:
|
|
'Effective `lang` of Vue SFC `<script>` blocks when it needs disambiguation (currently only "tsx"), scanned by the host',
|
|
},
|
|
};
|
|
|
|
const oxfmtParser: Parser<Doc> = {
|
|
parse: textToDoc,
|
|
astFormat: "OXFMT",
|
|
// Not used but required
|
|
locStart: () => -1,
|
|
locEnd: () => -1,
|
|
};
|
|
|
|
export const parsers: Record<string, Parser> = {
|
|
// Override default JS/TS parsers
|
|
babel: oxfmtParser,
|
|
"babel-ts": oxfmtParser,
|
|
typescript: oxfmtParser,
|
|
};
|
|
|
|
export const printers: Record<string, Printer<Doc>> = {
|
|
OXFMT: {
|
|
print: ({ node }) => node,
|
|
},
|
|
};
|