From 85ad08ea3c22b8dec7e709f1aaa2533e8f4b7691 Mon Sep 17 00:00:00 2001 From: branchseer Date: Thu, 5 Feb 2026 11:51:14 +0800 Subject: [PATCH 1/4] feat: allow comments (JSONC) in vite-task.json Use jsonc-parser to parse vite-task.json, enabling // line comments, /* */ block comments, and trailing commas. Add comments to several test fixture files to exercise this. Co-Authored-By: Claude Opus 4.5 --- Cargo.lock | 10 ++++++++++ Cargo.toml | 1 + .../fixtures/vite-task-smoke/vite-task.json | 1 + crates/vite_task_graph/Cargo.toml | 1 + crates/vite_task_graph/src/loader.rs | 4 +++- .../fixtures/cache-scripts-enabled/vite-task.json | 1 + .../fixtures/comprehensive-task-graph/vite-task.json | 1 + .../workspace-root-no-package-json/vite-task.json | 2 ++ 8 files changed, 20 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 7c4b8a5c..040ee3a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1502,6 +1502,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "jsonc-parser" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eb0774546269185d38da823d8583e94448ba0e158e3f50759d9c79aba946ca5" +dependencies = [ + "serde_json", +] + [[package]] name = "konst" version = "0.2.19" @@ -3338,6 +3347,7 @@ dependencies = [ "anyhow", "async-trait", "clap", + "jsonc-parser", "monostate", "petgraph", "pretty_assertions", diff --git a/Cargo.toml b/Cargo.toml index 4595da9f..6ca05928 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -75,6 +75,7 @@ fspy_test_utils = { path = "crates/fspy_test_utils" } futures = "0.3.31" futures-util = "0.3.31" insta = "1.44.3" +jsonc-parser = { version = "0.29.0", features = ["serde"] } libc = "0.2.172" memmap2 = "0.9.7" monostate = "1.0.2" diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/vite-task-smoke/vite-task.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/vite-task-smoke/vite-task.json index 1d0fe9f2..43bed5d7 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/vite-task-smoke/vite-task.json +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/vite-task-smoke/vite-task.json @@ -1,3 +1,4 @@ { + // Smoke test: enables caching for all package.json scripts. "cacheScripts": true } diff --git a/crates/vite_task_graph/Cargo.toml b/crates/vite_task_graph/Cargo.toml index 17fc8225..4d906d05 100644 --- a/crates/vite_task_graph/Cargo.toml +++ b/crates/vite_task_graph/Cargo.toml @@ -10,6 +10,7 @@ rust-version.workspace = true anyhow = { workspace = true } async-trait = { workspace = true } clap = { workspace = true, features = ["derive"] } +jsonc-parser = { workspace = true } monostate = { workspace = true } petgraph = { workspace = true } serde = { workspace = true, features = ["derive"] } diff --git a/crates/vite_task_graph/src/loader.rs b/crates/vite_task_graph/src/loader.rs index 8a192fdc..37b56071 100644 --- a/crates/vite_task_graph/src/loader.rs +++ b/crates/vite_task_graph/src/loader.rs @@ -33,7 +33,9 @@ impl UserConfigLoader for JsonUserConfigLoader { } Err(err) => return Err(err.into()), }; - let user_config: UserRunConfig = serde_json::from_str(&config_content)?; + let json_value = jsonc_parser::parse_to_serde_value(&config_content, &Default::default())? + .unwrap_or_default(); + let user_config: UserRunConfig = serde_json::from_value(json_value)?; Ok(Some(user_config)) } } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-enabled/vite-task.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-enabled/vite-task.json index 1d0fe9f2..e9f7182a 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-enabled/vite-task.json +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-enabled/vite-task.json @@ -1,3 +1,4 @@ { + // Enables caching for all package.json scripts in the workspace. "cacheScripts": true } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/comprehensive-task-graph/vite-task.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/comprehensive-task-graph/vite-task.json index 1d0fe9f2..e9f7182a 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/comprehensive-task-graph/vite-task.json +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/comprehensive-task-graph/vite-task.json @@ -1,3 +1,4 @@ { + // Enables caching for all package.json scripts in the workspace. "cacheScripts": true } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace-root-no-package-json/vite-task.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace-root-no-package-json/vite-task.json index f07f1a9c..e79ab80a 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace-root-no-package-json/vite-task.json +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace-root-no-package-json/vite-task.json @@ -1,4 +1,6 @@ { + // This workspace root has no package.json — only pnpm-workspace.yaml. + // vite-task.json should still be loaded and applied. "cacheScripts": true, "tasks": { "deploy": { From 5a8817fde29ed46297fb57d21a23fdcc5f409111 Mon Sep 17 00:00:00 2001 From: branchseer Date: Thu, 5 Feb 2026 14:34:43 +0800 Subject: [PATCH 2/4] chore: move JsonUserConfigLoader from vite_task_graph to vite_task_bin JsonUserConfigLoader is only instantiated in vite_task_bin, so it belongs there rather than in the core graph crate. This also removes the tokio dependency from vite_task_graph. Co-Authored-By: Claude Opus 4.5 --- Cargo.lock | 2 ++ crates/vite_task_bin/Cargo.toml | 2 ++ crates/vite_task_bin/src/lib.rs | 30 +++++++++++++++++++++++++++- crates/vite_task_graph/Cargo.toml | 1 - crates/vite_task_graph/src/loader.rs | 27 ------------------------- 5 files changed, 33 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 040ee3a7..9fd2b0db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3328,8 +3328,10 @@ dependencies = [ "copy_dir", "cow-utils", "insta", + "jsonc-parser", "regex", "serde", + "serde_json", "tempfile", "tokio", "toml", diff --git a/crates/vite_task_bin/Cargo.toml b/crates/vite_task_bin/Cargo.toml index 879a468b..29c22a15 100644 --- a/crates/vite_task_bin/Cargo.toml +++ b/crates/vite_task_bin/Cargo.toml @@ -14,6 +14,8 @@ path = "src/main.rs" anyhow = { workspace = true } async-trait = { workspace = true } clap = { workspace = true, features = ["derive"] } +jsonc-parser = { workspace = true } +serde_json = { workspace = true } tokio = { workspace = true, features = ["full"] } vite_path = { workspace = true } vite_str = { workspace = true } diff --git a/crates/vite_task_bin/src/lib.rs b/crates/vite_task_bin/src/lib.rs index 1284f415..535ffd22 100644 --- a/crates/vite_task_bin/src/lib.rs +++ b/crates/vite_task_bin/src/lib.rs @@ -135,10 +135,38 @@ impl vite_task::TaskSynthesizer for TaskSynthesizer { } } +/// A `UserConfigLoader` implementation that only loads `vite-task.json`. +/// +/// This is mainly for examples and testing as it does not require Node.js environment. +#[derive(Default, Debug)] +pub struct JsonUserConfigLoader(()); + +#[async_trait::async_trait(?Send)] +impl vite_task::loader::UserConfigLoader for JsonUserConfigLoader { + async fn load_user_config_file( + &self, + package_path: &AbsolutePath, + ) -> anyhow::Result> { + let config_path = package_path.join("vite-task.json"); + let config_content = match tokio::fs::read_to_string(&config_path).await { + Ok(content) => content, + Err(err) if err.kind() == std::io::ErrorKind::NotFound => { + return Ok(None); + } + Err(err) => return Err(err.into()), + }; + let json_value = + jsonc_parser::parse_to_serde_value(&config_content, &Default::default())? + .unwrap_or_default(); + let user_config: vite_task::config::UserRunConfig = serde_json::from_value(json_value)?; + Ok(Some(user_config)) + } +} + #[derive(Default)] pub struct OwnedSessionCallbacks { task_synthesizer: TaskSynthesizer, - user_config_loader: vite_task::loader::JsonUserConfigLoader, + user_config_loader: JsonUserConfigLoader, } impl OwnedSessionCallbacks { diff --git a/crates/vite_task_graph/Cargo.toml b/crates/vite_task_graph/Cargo.toml index 4d906d05..b3330814 100644 --- a/crates/vite_task_graph/Cargo.toml +++ b/crates/vite_task_graph/Cargo.toml @@ -16,7 +16,6 @@ petgraph = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } thiserror = { workspace = true } -tokio = { workspace = true, features = ["fs"] } vec1 = { workspace = true, features = ["smallvec-v1"] } vite_graph_ser = { workspace = true } vite_path = { workspace = true } diff --git a/crates/vite_task_graph/src/loader.rs b/crates/vite_task_graph/src/loader.rs index 37b56071..d00f2dfe 100644 --- a/crates/vite_task_graph/src/loader.rs +++ b/crates/vite_task_graph/src/loader.rs @@ -12,30 +12,3 @@ pub trait UserConfigLoader: Debug + Send + Sync { package_path: &AbsolutePath, ) -> anyhow::Result>; } - -/// A `UserConfigLoader` implementation that only loads `vite-task.json`. -/// -/// This is mainly for examples and testing as it does not require Node.js environment. -#[derive(Default, Debug)] -pub struct JsonUserConfigLoader(()); - -#[async_trait::async_trait(?Send)] -impl UserConfigLoader for JsonUserConfigLoader { - async fn load_user_config_file( - &self, - package_path: &AbsolutePath, - ) -> anyhow::Result> { - let config_path = package_path.join("vite-task.json"); - let config_content = match tokio::fs::read_to_string(&config_path).await { - Ok(content) => content, - Err(err) if err.kind() == std::io::ErrorKind::NotFound => { - return Ok(None); - } - Err(err) => return Err(err.into()), - }; - let json_value = jsonc_parser::parse_to_serde_value(&config_content, &Default::default())? - .unwrap_or_default(); - let user_config: UserRunConfig = serde_json::from_value(json_value)?; - Ok(Some(user_config)) - } -} From 4a56d3e9cad799e6c0ab62305ce99eb6427360f7 Mon Sep 17 00:00:00 2001 From: branchseer Date: Thu, 5 Feb 2026 14:38:02 +0800 Subject: [PATCH 3/4] cargo sheer --- crates/vite_task_graph/Cargo.toml | 2 -- 1 file changed, 2 deletions(-) diff --git a/crates/vite_task_graph/Cargo.toml b/crates/vite_task_graph/Cargo.toml index b3330814..36b32dc8 100644 --- a/crates/vite_task_graph/Cargo.toml +++ b/crates/vite_task_graph/Cargo.toml @@ -10,7 +10,6 @@ rust-version.workspace = true anyhow = { workspace = true } async-trait = { workspace = true } clap = { workspace = true, features = ["derive"] } -jsonc-parser = { workspace = true } monostate = { workspace = true } petgraph = { workspace = true } serde = { workspace = true, features = ["derive"] } @@ -24,7 +23,6 @@ vite_workspace = { workspace = true } [dev-dependencies] pretty_assertions = { workspace = true } -tokio = { workspace = true, features = ["fs", "rt-multi-thread"] } ts-rs = { workspace = true } vite_path = { workspace = true, features = ["ts-rs"] } vite_str = { workspace = true, features = ["ts-rs"] } From fe2387f7e2231bf5355b313b8069b51ed0340b74 Mon Sep 17 00:00:00 2001 From: branchseer Date: Thu, 5 Feb 2026 14:39:46 +0800 Subject: [PATCH 4/4] cargo fmt --- crates/vite_task_bin/src/lib.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/crates/vite_task_bin/src/lib.rs b/crates/vite_task_bin/src/lib.rs index 535ffd22..49fd6a06 100644 --- a/crates/vite_task_bin/src/lib.rs +++ b/crates/vite_task_bin/src/lib.rs @@ -155,9 +155,8 @@ impl vite_task::loader::UserConfigLoader for JsonUserConfigLoader { } Err(err) => return Err(err.into()), }; - let json_value = - jsonc_parser::parse_to_serde_value(&config_content, &Default::default())? - .unwrap_or_default(); + let json_value = jsonc_parser::parse_to_serde_value(&config_content, &Default::default())? + .unwrap_or_default(); let user_config: vite_task::config::UserRunConfig = serde_json::from_value(json_value)?; Ok(Some(user_config)) }