Skip to content

Commit 2764ddd

Browse files
authored
feat: upgrade oxlint to ^1.53.0 and oxfmt to ^0.38.0, remove temp config files (#776)
oxlint@1.53 and oxfmt@0.38 support `-c vite.config.ts` directly, so the temp file workaround (.vite-plus-lint.tmp.mts / .vite-plus-fmt.tmp.json) is no longer needed. This removes ~150 lines of temp file creation and cleanup machinery from SubcommandResolver. - Bump oxfmt ^0.36.0 → ^0.38.0, oxlint ^1.51.0 → ^1.53.0 - Remove write_temp_ts_config_import, write_temp_json_config_file, cleanup_temp_files methods and all call sites - Pass `-c vite.config.ts` directly to oxlint/oxfmt - Rename snap tests to reflect new behavior and enhance them to actually verify config takes effect (lint-vite-config-rules, fmt-check-with-vite-config) - Fix oxlint-typeaware test (add lint: {} for auto-discovery) - Add type: module to fmt test package.json files closes [VP-158](https://linear.app/voidzero/issue/VP-158/add-basedir-field-at-oxlint-and-oxfmt-configuration)
1 parent bb28909 commit 2764ddd

70 files changed

Lines changed: 431 additions & 382 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

packages/cli/binding/src/cli.rs

Lines changed: 8 additions & 148 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
//! It handles argument parsing, command dispatching, and orchestration of the task execution.
55
66
use std::{
7-
borrow::Cow, env, ffi::OsStr, future::Future, io::IsTerminal, iter, path::PathBuf, pin::Pin,
8-
process::Stdio, sync::Arc, time::Instant,
7+
borrow::Cow, env, ffi::OsStr, future::Future, io::IsTerminal, iter, pin::Pin, process::Stdio,
8+
sync::Arc, time::Instant,
99
};
1010

1111
use clap::{
@@ -15,7 +15,6 @@ use clap::{
1515
use owo_colors::OwoColorize;
1616
use rustc_hash::FxHashMap;
1717
use serde::{Deserialize, Serialize};
18-
use tokio::fs::write;
1918
use vite_error::Error;
2019
use vite_path::{AbsolutePath, AbsolutePathBuf};
2120
use vite_shared::{PrependOptions, output, prepend_to_path_env};
@@ -185,144 +184,27 @@ impl ResolvedSubcommand {
185184
pub struct SubcommandResolver {
186185
cli_options: Option<CliOptions>,
187186
workspace_path: Arc<AbsolutePath>,
188-
/// Track temporary config files created during resolution for cleanup
189-
temp_config_files: Vec<AbsolutePathBuf>,
190187
}
191188

192189
impl std::fmt::Debug for SubcommandResolver {
193190
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
194191
f.debug_struct("SubcommandResolver")
195192
.field("has_cli_options", &self.cli_options.is_some())
196193
.field("workspace_path", &self.workspace_path)
197-
.field("temp_config_files_count", &self.temp_config_files.len())
198194
.finish()
199195
}
200196
}
201197

202198
impl SubcommandResolver {
203199
pub fn new(workspace_path: Arc<AbsolutePath>) -> Self {
204-
Self { cli_options: None, workspace_path, temp_config_files: Vec::new() }
200+
Self { cli_options: None, workspace_path }
205201
}
206202

207203
pub fn with_cli_options(mut self, cli_options: CliOptions) -> Self {
208204
self.cli_options = Some(cli_options);
209205
self
210206
}
211207

212-
/// Clean up temporary config files created during resolution.
213-
/// Should be called after command execution completes (success or failure).
214-
pub async fn cleanup_temp_files(&mut self) {
215-
for path in self.temp_config_files.drain(..) {
216-
if let Err(e) = tokio::fs::remove_file(&path).await {
217-
if e.kind() != std::io::ErrorKind::NotFound {
218-
tracing::warn!(
219-
"Failed to cleanup temp config file {}: {}",
220-
path.as_path().display(),
221-
e
222-
);
223-
}
224-
}
225-
}
226-
}
227-
228-
/// Write a temporary TS config file that re-exports a field from vite.config.
229-
/// The temp file imports the vite config and re-exports the specified field,
230-
/// so the tool (e.g. oxlint) picks it up via `-c <path>`.
231-
/// The `config_file_path` must be an absolute path.
232-
async fn write_temp_ts_config_import(
233-
&mut self,
234-
config_file_path: &str,
235-
temp_filename: &str,
236-
field_name: &str,
237-
args: &mut Vec<String>,
238-
) -> anyhow::Result<()> {
239-
let path = PathBuf::from(config_file_path);
240-
if !path.is_absolute() {
241-
anyhow::bail!("config_file_path must be an absolute path, got: {config_file_path}");
242-
}
243-
244-
let config_basename = path
245-
.file_name()
246-
.and_then(|n| n.to_str())
247-
.ok_or_else(|| {
248-
anyhow::anyhow!("Failed to get file name of config file: {config_file_path}")
249-
})?
250-
.to_string();
251-
252-
let config_dir = AbsolutePathBuf::new(path)
253-
.and_then(|p| p.parent().map(|p| p.to_absolute_path_buf()))
254-
.ok_or_else(|| {
255-
anyhow::anyhow!("Failed to get parent directory of config file: {config_file_path}")
256-
})?;
257-
258-
let config_path = config_dir.join(temp_filename);
259-
let content = format!(
260-
"import {{ defineConfig }} from 'vite-plus/lint';\nimport viteConfig from './{config_basename}';\nexport default defineConfig(viteConfig.{field_name} as any);\n"
261-
);
262-
write(&config_path, content).await?;
263-
264-
self.temp_config_files.push(config_path.clone());
265-
266-
let config_path_str = config_path
267-
.as_path()
268-
.to_str()
269-
.ok_or_else(|| anyhow::anyhow!("config path is not valid UTF-8"))?;
270-
args.insert(0, config_path_str.to_string());
271-
args.insert(0, "-c".to_string());
272-
// Prevent oxlint from linting the temp config file itself
273-
args.push("--ignore-pattern".to_string());
274-
args.push(temp_filename.to_string());
275-
Ok(())
276-
}
277-
278-
/// Write a temporary JSON config file and prepend `-c <path>` to args.
279-
/// The file will be tracked for cleanup after command execution.
280-
/// The `config_file_path` must be an absolute path.
281-
async fn write_temp_json_config_file(
282-
&mut self,
283-
config: &serde_json::Value,
284-
config_file_path: &str,
285-
temp_filename: &str,
286-
args: &mut Vec<String>,
287-
) -> anyhow::Result<()> {
288-
let mut config = config.clone();
289-
290-
// Add temp file to ignorePatterns to prevent self-checking
291-
if let Some(obj) = config.as_object_mut() {
292-
if let Some(patterns) = obj.get_mut("ignorePatterns") {
293-
if let Some(array) = patterns.as_array_mut() {
294-
array.push(serde_json::json!(temp_filename));
295-
}
296-
} else {
297-
obj.insert("ignorePatterns".to_string(), serde_json::json!([temp_filename]));
298-
}
299-
}
300-
301-
let path = PathBuf::from(config_file_path);
302-
if !path.is_absolute() {
303-
anyhow::bail!("config_file_path must be an absolute path, got: {config_file_path}");
304-
}
305-
306-
let config_dir = AbsolutePathBuf::new(path)
307-
.and_then(|p| p.parent().map(|p| p.to_absolute_path_buf()))
308-
.ok_or_else(|| {
309-
anyhow::anyhow!("Failed to get parent directory of config file: {config_file_path}")
310-
})?;
311-
312-
let config_path = config_dir.join(temp_filename);
313-
write(&config_path, serde_json::to_string(&config)?).await?;
314-
315-
self.temp_config_files.push(config_path.clone());
316-
317-
let config_path_str = config_path
318-
.as_path()
319-
.to_str()
320-
.ok_or_else(|| anyhow::anyhow!("config path is not valid UTF-8"))?;
321-
args.insert(0, config_path_str.to_string());
322-
args.insert(0, "-c".to_string());
323-
Ok(())
324-
}
325-
326208
/// Resolve a synthesizable subcommand to a concrete program, args, cache config, and envs.
327209
async fn resolve(
328210
&mut self,
@@ -358,13 +240,8 @@ impl SubcommandResolver {
358240
if let (Some(_), Some(config_file)) =
359241
(&resolved_vite_config.lint, &resolved_vite_config.config_file)
360242
{
361-
self.write_temp_ts_config_import(
362-
config_file,
363-
".vite-plus-lint.tmp.mts",
364-
"lint",
365-
&mut args,
366-
)
367-
.await?;
243+
args.insert(0, "-c".to_string());
244+
args.insert(1, config_file.clone());
368245
}
369246

370247
Ok(ResolvedSubcommand {
@@ -405,16 +282,11 @@ impl SubcommandResolver {
405282
tracing::error!("Failed to parse vite config: {vite_config_json}");
406283
})?;
407284

408-
if let (Some(fmt_config), Some(config_file)) =
285+
if let (Some(_), Some(config_file)) =
409286
(&resolved_vite_config.fmt, &resolved_vite_config.config_file)
410287
{
411-
self.write_temp_json_config_file(
412-
fmt_config,
413-
config_file,
414-
".vite-plus-fmt.tmp.json",
415-
&mut args,
416-
)
417-
.await?;
288+
args.insert(0, "-c".to_string());
289+
args.insert(1, config_file.clone());
418290
}
419291

420292
Ok(ResolvedSubcommand {
@@ -649,10 +521,6 @@ impl VitePlusCommandHandler {
649521
pub fn new(resolver: SubcommandResolver) -> Self {
650522
Self { resolver }
651523
}
652-
653-
pub async fn cleanup_temp_files(&mut self) {
654-
self.resolver.cleanup_temp_files().await;
655-
}
656524
}
657525

658526
#[async_trait::async_trait(?Send)]
@@ -1053,7 +921,6 @@ async fn execute_direct_subcommand(
1053921
print_summary_line(
1054922
"`vp check` did not run because both `--no-fmt` and `--no-lint` were set",
1055923
);
1056-
resolver.cleanup_temp_files().await;
1057924
return Ok(ExitStatus(1));
1058925
}
1059926

@@ -1130,7 +997,6 @@ async fn execute_direct_subcommand(
1130997
);
1131998
}
1132999
if status != ExitStatus::SUCCESS {
1133-
resolver.cleanup_temp_files().await;
11341000
return Ok(status);
11351001
}
11361002
}
@@ -1206,7 +1072,6 @@ async fn execute_direct_subcommand(
12061072
}
12071073
}
12081074
if status != ExitStatus::SUCCESS {
1209-
resolver.cleanup_temp_files().await;
12101075
return Ok(status);
12111076
}
12121077
}
@@ -1242,7 +1107,6 @@ async fn execute_direct_subcommand(
12421107
print_stdout_block(&combined_output);
12431108
}
12441109
print_summary_line("Formatting failed after lint fixes were applied");
1245-
resolver.cleanup_temp_files().await;
12461110
return Ok(status);
12471111
}
12481112
if let Some(started) = fmt_fix_started {
@@ -1275,8 +1139,6 @@ async fn execute_direct_subcommand(
12751139
}
12761140
};
12771141

1278-
resolver.cleanup_temp_files().await;
1279-
12801142
Ok(status)
12811143
}
12821144

@@ -1321,8 +1183,6 @@ async fn execute_vite_task_command(
13211183
// Main execution (consumes session)
13221184
let result = session.main(command).await.map_err(|e| Error::Anyhow(e));
13231185

1324-
command_handler.cleanup_temp_files().await;
1325-
13261186
result
13271187
}
13281188

packages/cli/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,8 @@
120120
},
121121
"./test/config": {
122122
"types": "./dist/test/config.d.ts",
123-
"require": "./dist/test/config.cjs",
124-
"default": "./dist/test/config.js"
123+
"default": "./dist/test/config.js",
124+
"require": "./dist/test/config.cjs"
125125
},
126126
"./test/coverage": {
127127
"types": "./dist/test/coverage.d.ts",

packages/cli/snap-tests-global/command-staged-with-config/vite.config.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
export default {
2+
lint: {
3+
rules: {
4+
'no-eval': 'error',
5+
},
6+
},
7+
fmt: {},
28
staged: {
39
'*.ts': 'vp check --fix',
410
'*.js': 'vp lint',

packages/cli/snap-tests-global/create-missing-typecheck/snap.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export default defineConfig({
66
staged: {
77
"*": "vp check --fix",
88
},
9+
fmt: {},
910
lint: { options: { typeAware: true, typeCheck: true } },
1011
});
1112

@@ -17,6 +18,7 @@ export default defineConfig({
1718
staged: {
1819
"*": "vp check --fix",
1920
},
21+
fmt: {},
2022
lint: { options: { typeAware: true, typeCheck: true } },
2123
});
2224

packages/cli/snap-tests-global/migration-baseurl-tsconfig/snap.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export default defineConfig({
1515
staged: {
1616
"*": "vp check --fix"
1717
},
18+
fmt: {},
1819
lint: {
1920
"rules": {
2021
"no-unused-vars": "error"

packages/cli/snap-tests-global/migration-chained-lint-staged-pre-commit/snap.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ VITE+ - The Unified Toolchain for the Web
3030
import { defineConfig } from 'vite-plus';
3131

3232
export default defineConfig({
33+
fmt: {},
3334
lint: {"options":{"typeAware":true,"typeCheck":true}},
3435
staged: {
3536
"*.js": "vp lint --fix"

packages/cli/snap-tests-global/migration-env-prefix-lint-staged/snap.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ VITE+ - The Unified Toolchain for the Web
3030
import { defineConfig } from 'vite-plus';
3131

3232
export default defineConfig({
33+
fmt: {},
3334
lint: {"options":{"typeAware":true,"typeCheck":true}},
3435
staged: {
3536
"*.js": "vp lint --fix"

packages/cli/snap-tests-global/migration-eslint-lint-staged/snap.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ VITE+ - The Unified Toolchain for the Web
3030
import { defineConfig } from 'vite-plus';
3131

3232
export default defineConfig({
33+
fmt: {},
3334
lint: {
3435
"plugins": [
3536
"oxc",

packages/cli/snap-tests-global/migration-eslint-lintstagedrc/snap.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ cat: .lintstagedrc.json: No such file or directory
3333
import { defineConfig } from 'vite-plus';
3434

3535
export default defineConfig({
36+
fmt: {},
3637
lint: {
3738
"plugins": [
3839
"oxc",

packages/cli/snap-tests-global/migration-eslint/snap.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export default defineConfig({
3939
staged: {
4040
"*": "vp check --fix"
4141
},
42+
fmt: {},
4243
lint: {
4344
"plugins": [
4445
"oxc",

0 commit comments

Comments
 (0)