Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/tsc-rs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte-check': minor
---

feat: add `--tsc-rs` flag to use tsc-rs, a Rust port of the TypeScript 7 compiler, for TypeScript diagnostics
1 change: 1 addition & 0 deletions packages/svelte-check/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ npm install --save-dev typescript@~6 @typescript/native@npm:typescript@7
| `--threshold <error\|warning>` | Filters the diagnostics to display. `error` will output only errors while `warning` will output warnings and errors. |
| `--incremental` | Opts into TypeScript's incremental build cache, which speeds up subsequent runs. Saved within `.svelte-kit` or if not available within `.svelte-check`. This might result in slightly different type check outcomes, and certain patterns are not supported. Specifically, anything that is not in the root dir of your tsconfig.json and is a Svelte file will not be properly loaded and type-checked. |
| `--tsgo` | Use TypeScript's Go implementation. Needs to have `@typescript/native-preview` installed. Subject to the same limitations as `--incremental` |
| `--tsc-rs` | Use tsc-rs, a Rust port of TypeScript's Go implementation. Needs to have `tsc-rs` installed. Subject to the same limitations as `--incremental` |

### FAQ

Expand Down
1 change: 1 addition & 0 deletions packages/svelte-check/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"svelte": "^4.2.19",
"svelte-language-server": "workspace:*",
"svelte2tsx": "workspace:*",
"tsc-rs": "~0.7.0",
"typescript": "^6.0.3",
"vscode-languageserver": "8.0.2",
"vscode-languageserver-protocol": "3.17.2",
Expand Down
31 changes: 27 additions & 4 deletions packages/svelte-check/src/incremental.ts
Original file line number Diff line number Diff line change
Expand Up @@ -466,22 +466,27 @@ export function writeOverlayTsconfig(
}

/**
* Spawns a TypeScript compiler process (tsc or tsgo) to perform type-checking
* Spawns a TypeScript compiler process (tsc, tsgo or tsc-rs) to perform type-checking
* and collects the diagnostics from its output.
*
* @param tsconfigPath - Path to the tsconfig.json to use for compilation
* @param useTsgo - When true, uses the experimental native TypeScript compiler (tsgo)
* @param compiler - Which compiler to use: tsc, the native TypeScript compiler (tsgo) or its Rust port (tsc-rs)
* @param incremental - Whether to enable incremental compilation for faster subsequent runs
* @param cwd - Working directory for the TypeScript compiler process
* @returns Parsed diagnostics containing file paths, positions, severity, and messages
*/
export function runTypeScriptDiagnostics(
tsconfigPath: string,
useTsgo: boolean,
compiler: 'tsc' | 'tsgo' | 'tsc-rs',
incremental: boolean,
cwd: string
): Promise<ParsedDiagnostic[]> {
const binPath = useTsgo ? getTsGoBinPath(tsconfigPath) : require.resolve('typescript/bin/tsc');
const binPath =
compiler === 'tsc-rs'
? getTscRsBinPath(tsconfigPath)
: compiler === 'tsgo'
? getTsGoBinPath(tsconfigPath)
: require.resolve('typescript/bin/tsc');

if (!binPath || !fs.existsSync(binPath) || !fs.statSync(binPath).isFile()) {
throw new Error('Failed to locate TypeScript command-line executable.');
Expand Down Expand Up @@ -569,6 +574,24 @@ function getTsGoBinPath(tsconfigPath: string): string | undefined {
return binPathRelative ? path.join(path.dirname(pkg.path), binPathRelative) : undefined;
}

function getTscRsBinPath(tsconfigPath: string): string | undefined {
let pkgPath: string;
try {
pkgPath = require.resolve('tsc-rs/package.json', { paths: [tsconfigPath, __dirname] });
} catch (e) {
throw new Error(
'svelte-check --tsc-rs requires tsc-rs to be installed in the workspace. ' +
'You can install it via the following command.\n' +
'npm install --save-dev tsc-rs\n'
);
}

const bin = require(pkgPath).bin;
const binPathRelative = typeof bin === 'string' ? bin : bin?.['tsc-rs'];

return binPathRelative ? path.join(path.dirname(pkgPath), binPathRelative) : undefined;
}

/**
* Maps TypeScript CLI diagnostics back to their original Svelte source files.
* For Svelte files, uses source maps to translate positions from the generated
Expand Down
19 changes: 15 additions & 4 deletions packages/svelte-check/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -447,8 +447,11 @@ async function runWithVirtualFiles(
writer: Writer
): Promise<Result | null> {
if (!opts.tsconfig) {
throw new Error('`--incremental` / `--tsgo` requires a tsconfig/jsconfig file');
throw new Error(
'`--incremental` / `--tsgo` / `--tsc-rs` requires a tsconfig/jsconfig file'
);
}
const compiler = opts.tscRs ? 'tsc-rs' : opts.tsgo ? 'tsgo' : 'tsc';

const emitResult = await emitSvelteFiles(
opts.workspaceUri.fsPath,
Expand All @@ -460,12 +463,13 @@ async function runWithVirtualFiles(
opts.tsconfig,
emitResult,
opts.incremental,
opts.tsgo
// tsc-rs is a port of tsgo, so it needs the same overlay
compiler !== 'tsc'
);
const tsDiagnostics = mapCliDiagnosticsToLsp(
await runTypeScriptDiagnostics(
overlayTsconfig,
opts.tsgo,
compiler,
opts.incremental,
opts.workspaceUri.fsPath
),
Expand Down Expand Up @@ -600,6 +604,10 @@ parseOptions(async (opts) => {
watch: opts.watch
};

if (opts.tscRs && opts.tsgo) {
throw new Error('--tsc-rs cannot be used with --tsgo');
}

if (opts.tsgoExperimental) {
if (!opts.tsconfig) {
throw new Error('--tsgo-experimental-api requires a tsconfig/jsconfig file');
Expand All @@ -610,6 +618,9 @@ parseOptions(async (opts) => {
if (opts.tsgo) {
throw new Error('--tsgo-experimental-api cannot be used with --tsgo');
}
if (opts.tscRs) {
throw new Error('--tsgo-experimental-api cannot be used with --tsc-rs');
}
const pkg = tryParseTsGoVersion(opts.tsconfig);
if (!pkg) {
throw new Error(formatTsGoNotFoundError('--tsgo-experimental-api'));
Expand Down Expand Up @@ -642,7 +653,7 @@ parseOptions(async (opts) => {
svelteCheckOptions.experimental = { tsgo: { apiModule, astModule } };
}

const useVirtualFiles = opts.incremental || opts.tsgo;
const useVirtualFiles = opts.incremental || opts.tsgo || opts.tscRs;
if (useVirtualFiles && opts.watch) {
await watchWithVirtualFiles(opts, writer);
} else if (useVirtualFiles) {
Expand Down
9 changes: 8 additions & 1 deletion packages/svelte-check/src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export interface SvelteCheckCliOptions {
preserveWatchOutput: boolean;
incremental: boolean;
tsgo: boolean;
tscRs: boolean;
tsgoExperimental: boolean;
tsconfig?: string;
config?: string;
Expand Down Expand Up @@ -47,9 +48,14 @@ export function parseOptions(cb: (opts: SvelteCheckCliOptions) => any) {
'Use tsgo for TypeScript diagnostics. Requires writing transpiled Svelte files to disk (.svelte-kit if available, else .svelte-check)',
false
)
.option(
'--tsc-rs',
'Use tsc-rs (a Rust port of the TypeScript 7 compiler) for TypeScript diagnostics. Requires writing transpiled Svelte files to disk (.svelte-kit if available, else .svelte-check)',
false
)
.option(
'--tsgo-experimental-api',
'Use tsgo for TypeScript diagnostics with the experimental API. Cannot be used with --incremental or --tsgo. Experimental feature, might break without warning.',
'Use tsgo for TypeScript diagnostics with the experimental API. Cannot be used with --incremental, --tsgo or --tsc-rs. Experimental feature, might break without warning.',
false
)
.option(
Expand Down Expand Up @@ -106,6 +112,7 @@ export function parseOptions(cb: (opts: SvelteCheckCliOptions) => any) {
preserveWatchOutput: !!opts.preserveWatchOutput,
incremental: !!opts.incremental,
tsgo: !!opts.tsgo,
tscRs: !!opts['tsc-rs'],
tsconfig,
config,
filePathsToIgnore: opts.ignore?.split(',') || [],
Expand Down
17 changes: 17 additions & 0 deletions packages/svelte-check/test-sanity.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ let failed = 0;
* @param {boolean} [opts.incremental]
* @param {boolean} [opts.tsgoExp]
* @param {boolean} [opts.tsgo]
* @param {boolean} [opts.tscRs]
* @param {ExpectedError[]} [opts.errors]
*/
function test(name, opts) {
Expand All @@ -53,6 +54,9 @@ function test(name, opts) {
if (opts.tsgo) {
args.push('--tsgo');
}
if (opts.tscRs) {
args.push('--tsc-rs');
}

let stdout;
try {
Expand Down Expand Up @@ -249,6 +253,12 @@ test('clean project --tsgo', {
tsgo: true
});

test('clean project --tsc-rs', {
workspace: './test-success',
tsconfig: './tsconfig.json',
tscRs: true
});

const errors = [
{
file: 'Index.svelte',
Expand Down Expand Up @@ -335,6 +345,13 @@ test('project with errors --tsgo', {
errors
});

test('project with errors --tsc-rs', {
workspace: './test-error',
tsconfig: './tsconfig.json',
tscRs: true,
errors
});

// A compiler that dies must not look like a clean run, and one that dies after reporting
// some diagnostics must not look like a completed one.
testCrashedCompiler(
Expand Down
71 changes: 71 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.