Skip to content
Closed
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
238 changes: 127 additions & 111 deletions Cargo.lock

Large diffs are not rendered by default.

36 changes: 18 additions & 18 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -208,11 +208,11 @@ indexmap = "2.9.0"
indoc = "2.0.5"
infer = "0.19.0"
insta = "1.43.1"
itertools = "0.14.0"
itertools = "0.15.0"
itoa = "1.0.15"
json-escape-simd = "3"
json-strip-comments = "3"
jsonschema = { version = "0.46.5", default-features = false }
jsonschema = { version = "0.47.0", default-features = false }
junction = "1.4.1"
libtest-mimic = "0.8.2"
memchr = "2.7.4"
Expand Down Expand Up @@ -247,7 +247,7 @@ pnp = "0.12.9"
percent-encoding = "2.3.1"
petgraph = "0.8.2"
pretty_assertions = "1.4.1"
phf = "0.13.0"
phf = { version = "0.14.0", features = ["macros"] }
prettyplease = "0.2.32"
proc-macro2 = "1"
pty_terminal_test = { git = "https://github.com/voidzero-dev/vite-task.git", rev = "4003f65a3e5e3d957ff81b157e85e6ee41cc59fc" }
Expand Down Expand Up @@ -276,7 +276,7 @@ simdutf8 = "0.1.5"
smallvec = { version = "1.15.1", features = ["union"] }
snapshot_test = { git = "https://github.com/voidzero-dev/vite-task.git", rev = "4003f65a3e5e3d957ff81b157e85e6ee41cc59fc" }
string_cache = "0.9.0"
sugar_path = { version = "2.0.1", features = ["cached_current_dir"] }
sugar_path = { version = "3", features = ["cached_current_dir"] }
supports-color = "3"
syn = { version = "2", default-features = false }
tar = "0.4.43"
Expand Down Expand Up @@ -317,7 +317,7 @@ xxhash-rust = "0.8.15"
zip = { version = "7.2", default-features = false, features = ["deflate-flate2-zlib-rs"] }

# oxc crates with the same version
oxc = { version = "0.139.0", features = [
oxc = { version = "0.140.0", features = [
"ast_visit",
"transformer",
"minifier",
Expand All @@ -329,22 +329,22 @@ oxc = { version = "0.139.0", features = [
"regular_expression",
"cfg",
] }
oxc_allocator = { version = "0.139.0", features = ["pool"] }
oxc_ast = "0.139.0"
oxc_ecmascript = "0.139.0"
oxc_parser = "0.139.0"
oxc_span = "0.139.0"
oxc_napi = "0.139.0"
oxc_str = "0.139.0"
oxc_minify_napi = "0.139.0"
oxc_parser_napi = "0.139.0"
oxc_transform_napi = "0.139.0"
oxc_traverse = "0.139.0"
oxc_allocator = { version = "0.140.0", features = ["pool"] }
oxc_ast = "0.140.0"
oxc_ecmascript = "0.140.0"
oxc_parser = "0.140.0"
oxc_span = "0.140.0"
oxc_napi = "0.140.0"
oxc_str = "0.140.0"
oxc_minify_napi = "0.140.0"
oxc_parser_napi = "0.140.0"
oxc_transform_napi = "0.140.0"
oxc_traverse = "0.140.0"

# oxc crates in their own repos
oxc_index = { version = "5", features = ["rayon", "serde"] }
oxc_resolver = { version = "11.23.0", features = ["yarn_pnp"] }
oxc_resolver_napi = { version = "11.23.0", default-features = false, features = ["yarn_pnp"] }
oxc_resolver = { version = "11.24.2", features = ["yarn_pnp"] }
oxc_resolver_napi = { version = "11.24.2", default-features = false, features = ["yarn_pnp"] }
oxc_sourcemap = "8.1.0"

# rolldown crates
Expand Down
43 changes: 27 additions & 16 deletions packages/cli/binding/index.d.cts
Original file line number Diff line number Diff line change
Expand Up @@ -1631,11 +1631,16 @@ export declare class BindingDevEngine {
getBundleState(): Promise<BindingBundleState>;
ensureLatestBuildOutput(): Promise<BindingResult<undefined>>;
triggerFullBuild(): void;
invalidate(
caller: string,
firstInvalidatedBy?: string | undefined | null,
): Promise<BindingResult<Array<BindingClientHmrUpdate>>>;
registerModules(clientId: string, modules: Array<string>): Promise<void>;
/**
* Client-connect signal (the clientId hello): creates the per-client session
* with an empty ship map. Reconnects arrive as fresh clientIds.
*/
registerClient(clientId: string): Promise<void>;
/**
* Delivery notification from the serving middleware: the response for
* `filename` completed, so record its modules as shipped to that client.
*/
notifyPayloadDelivered(filename: string): Promise<void>;
removeClient(clientId: string): Promise<void>;
close(): Promise<void>;
/**
Expand All @@ -1645,7 +1650,7 @@ export declare class BindingDevEngine {
* The module was previously stubbed with a proxy, and now we need to compile the
* actual module and its dependencies.
*/
compileEntry(moduleId: string, clientId: string): Promise<string>;
compileEntry(moduleId: string, clientId: string): Promise<BindingLazyChunkOutput>;
}

export declare class BindingLoadPluginContext {
Expand Down Expand Up @@ -2355,19 +2360,18 @@ export interface BindingGeneratedCodeOptions {
preset?: string;
}

export interface BindingHmrBoundaryOutput {
boundary: string;
acceptedVia: string;
}

export type BindingHmrUpdate =
| {
type: 'Patch';
code: string;
filename: string;
sourcemap?: string;
sourcemapFilename?: string;
hmrBoundaries: Array<BindingHmrBoundaryOutput>;
sourcemapFilename?: string /**
* Stable ids of the changed modules — the `changedIds` of the push envelope.
* The client walks from these on its own graph.
*/;
changedIds: Array<string> /** Per-client envelope sequence number. */;
seq: number;
}
| { type: 'FullReload'; reason?: string }
| { type: 'Noop' };
Expand Down Expand Up @@ -2538,6 +2542,15 @@ export interface BindingJsWatchChangeEvent {
event: string;
}

/**
* The client-facing slice of a lazy-compile result. The carried modules and
* stamps stay server-side as the engine's pending-payload entry.
*/
export interface BindingLazyChunkOutput {
code: string;
filename: string;
}

export interface BindingLog {
message: string;
id?: string;
Expand Down Expand Up @@ -2843,8 +2856,7 @@ export declare const enum BindingPropertyWriteSideEffects {

export declare const enum BindingRebuildStrategy {
Always = 0,
Auto = 1,
Never = 2,
Never = 1,
}

export interface BindingReplacePluginConfig {
Expand Down Expand Up @@ -3189,7 +3201,6 @@ export interface JsOutputChunk {
map?: BindingSourcemap;
sourcemapFilename?: string;
preliminaryFilename: string;
preliminarySourcemapFilename?: string;
}

/** Error emitted from native side, it only contains kind and message, no stack trace. */
Expand Down
79 changes: 48 additions & 31 deletions packages/cli/src/migration/migrator/eslint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,39 +88,49 @@ export function detectEslintProject(

/**
* Run a `vp dlx @oxlint/migrate` step with graceful error handling.
* Returns true on success, false on failure (spawn error or non-zero exit).
*
* `migratePackages` lists candidate `@oxlint/migrate` specs to try in order,
* falling through to the next only when a candidate fails to run at all (spawn
* error or non-zero exit, e.g. the pinned version isn't published). This lets
* the caller prefer the bundled oxlint version while tolerating `@oxlint/migrate`
* lagging oxlint's publish cadence — oxlint X.Y.Z can ship before
* `@oxlint/migrate` X.Y.Z, which would otherwise 404 and abort the migration.
*
* Returns the spec that succeeded so the caller can reuse it for later steps,
* or `{ ok: false }` once every candidate has failed.
*/
async function runOxlintMigrateStep(
vpBin: string,
cwd: string,
migratePackage: string,
migratePackages: string[],
args: string[],
spinner: ReturnType<typeof getSpinner>,
failMessage: string,
manualHint: string,
): Promise<boolean> {
try {
const result = await runCommandSilently({
command: vpBin,
args: ['dlx', migratePackage, ...args],
cwd,
envs: process.env,
});
if (result.exitCode !== 0) {
spinner.stop(failMessage);
const stderr = result.stderr.toString().trim();
if (stderr) {
prompts.log.warn(`⚠ ${stderr}`);
): Promise<{ ok: true; migratePackage: string } | { ok: false }> {
let lastStderr = '';
for (const migratePackage of migratePackages) {
try {
const result = await runCommandSilently({
command: vpBin,
args: ['dlx', migratePackage, ...args],
cwd,
envs: process.env,
});
if (result.exitCode === 0) {
return { ok: true, migratePackage };
}
prompts.log.info(manualHint);
return false;
lastStderr = result.stderr.toString().trim();
} catch {
lastStderr = '';
}
return true;
} catch {
spinner.stop(failMessage);
prompts.log.info(manualHint);
return false;
}
spinner.stop(failMessage);
if (lastStderr) {
prompts.log.warn(`⚠ ${lastStderr}`);
}
prompts.log.info(manualHint);
return { ok: false };
}

export async function migrateEslintToOxlint(
Expand All @@ -147,10 +157,15 @@ export async function migrateEslintToOxlint(

// Steps 1-2: Only run @oxlint/migrate if there's an eslint config at root
if (eslintConfigFile) {
// Pin @oxlint/migrate to the bundled oxlint version.
// Prefer @oxlint/migrate at the bundled oxlint version so the generated
// rules stay aligned with the oxlint that lints them, but fall back to the
// latest published @oxlint/migrate when that exact version isn't on the
// registry yet (oxlint can publish ahead of @oxlint/migrate). It tracks
// oxlint's release train and never leads it, so `@latest` stays compatible.
// @ts-expect-error — resolved at runtime from dist/ → dist/versions.js
const { versions } = await import('../versions.js');
const migratePackage = `@oxlint/migrate@${versions.oxlint}`;
const migratePackagePinned = `@oxlint/migrate@${versions.oxlint}`;
const migratePackageCandidates = [migratePackagePinned, '@oxlint/migrate@latest'];
const migrateArgs = [
'--merge',
...(!hasBaseUrlInTsconfig(projectPath) ? ['--type-aware'] : []),
Expand All @@ -160,32 +175,34 @@ export async function migrateEslintToOxlint(

// Step 1: Generate .oxlintrc.json from ESLint config
spinner.start('Migrating ESLint config to Oxlint...');
const migrateOk = await runOxlintMigrateStep(
const migrateResult = await runOxlintMigrateStep(
vpBin,
projectPath,
migratePackage,
migratePackageCandidates,
migrateArgs,
spinner,
'ESLint migration failed',
`You can run \`vp dlx ${migratePackage} ${migrateArgs.join(' ')}\` manually later`,
`You can run \`vp dlx ${migratePackagePinned} ${migrateArgs.join(' ')}\` manually later`,
);
if (!migrateOk) {
if (!migrateResult.ok) {
return false;
}
// Reuse whichever @oxlint/migrate spec actually resolved for the follow-up.
const migratePackage = migrateResult.migratePackage;
spinner.stop('ESLint config migrated to .oxlintrc.json');

// Step 2: Replace eslint-disable comments with oxlint-disable
spinner.start('Replacing ESLint comments with Oxlint equivalents...');
const replaceOk = await runOxlintMigrateStep(
const replaceResult = await runOxlintMigrateStep(
vpBin,
projectPath,
migratePackage,
[migratePackage],
['--replace-eslint-comments'],
spinner,
'ESLint comment replacement failed',
`You can run \`vp dlx ${migratePackage} --replace-eslint-comments\` manually later`,
);
if (replaceOk) {
if (replaceResult.ok) {
spinner.stop('ESLint comments replaced');
}
// Continue with cleanup regardless — .oxlintrc.json was generated successfully
Expand Down
10 changes: 5 additions & 5 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@
"@oxc-project/runtime": "catalog:",
"@oxc-project/types": "catalog:",
"lightningcss": "catalog:",
"postcss": "^8.5.6",
"postcss": "catalog:",
"yuku-codegen": "^0.5.44",
"yuku-parser": "^0.5.44"
},
Expand All @@ -116,7 +116,7 @@
"@oxc-node/core": "catalog:",
"@tsdown/css": "catalog:",
"@tsdown/exe": "catalog:",
"@vitejs/devtools": "^0.4.0",
"@vitejs/devtools": "^0.4.1",
"es-module-lexer": "^1.7.0",
"hookable": "^6.0.1",
"magic-string": "^0.30.21",
Expand Down Expand Up @@ -214,8 +214,8 @@
"node": "^20.19.0 || ^22.18.0 || >=24.11.0"
},
"bundledVersions": {
"vite": "8.1.4",
"rolldown": "1.1.5",
"tsdown": "0.22.7"
"vite": "8.1.5",
"rolldown": "1.2.0",
"tsdown": "0.22.9"
}
}
4 changes: 2 additions & 2 deletions packages/tools/.upstream-versions.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
"rolldown": {
"repo": "https://github.com/rolldown/rolldown.git",
"branch": "main",
"hash": "f09947ab017d6df74299f691853dcfc4f4f0f86e"
"hash": "03e1e3422cd85495c9863ff3bc3b24212d9f4be2"
},
"vite": {
"repo": "https://github.com/vitejs/vite.git",
"branch": "main",
"hash": "a477454442eff649b430f9e3c6caf2500fcb7183"
"hash": "5e7fe129a4dde4f41934083b25e490059985f4e6"
}
}
Loading
Loading