Skip to content
Merged
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
211 changes: 105 additions & 106 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 0 additions & 2 deletions crates/vite_global_cli/src/help.rs
Original file line number Diff line number Diff line change
Expand Up @@ -722,8 +722,6 @@ fn delegated_help_doc(command: &str) -> Option<HelpDoc> {
row("--fix", "Auto-fix format and lint issues"),
row("--no-fmt", "Skip format check"),
row("--no-lint", "Skip lint check"),
row("--no-type-aware", "Disable type-aware linting"),
row("--no-type-check", "Disable TypeScript type checking"),
row("-h, --help", "Print help"),
],
),
Expand Down
8 changes: 7 additions & 1 deletion crates/vite_migration/src/package.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,13 @@ fn rewrite_script(script: &str, rules: &[RuleConfig<SupportLang>]) -> String {
let result = ast_grep::apply_loaded_rules(&preprocessed, rules);

// Step 3: Replace cross-env marker back with "cross-env " (only if we replaced it)
if has_cross_env { result.replace(CROSS_ENV_MARKER, CROSS_ENV_REPLACEMENT) } else { result }
let result = if has_cross_env {
result.replace(CROSS_ENV_MARKER, CROSS_ENV_REPLACEMENT)
} else {
result
};

result
}

/// Transform all script strings in a JSON object using the provided function.
Expand Down
69 changes: 67 additions & 2 deletions crates/vite_migration/src/vite_config.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use std::path::Path;
use std::{borrow::Cow, path::Path, sync::LazyLock};

use ast_grep_config::{GlobalRules, RuleConfig, from_yaml_string};
use ast_grep_language::{LanguageExt, SupportLang};
use regex::Regex;
use vite_error::Error;

use crate::ast_grep;
Expand Down Expand Up @@ -100,15 +101,33 @@ fn merge_json_config_content(
// Check if the config uses a function callback (for informational purposes)
let uses_function_callback = check_function_callback(vite_config_content)?;

// Strip "$schema" property — it's a JSON Schema annotation not valid in OxlintConfig
let ts_config = strip_schema_property(ts_config);

// Generate the ast-grep rules with the actual config
let rule_yaml = generate_merge_rule(ts_config, config_key);
let rule_yaml = generate_merge_rule(&ts_config, config_key);

// Apply the transformation
let (content, updated) = ast_grep::apply_rules(vite_config_content, &rule_yaml)?;

Ok(MergeResult { content, updated, uses_function_callback })
}

/// Regex to match `"$schema": "..."` lines (with optional trailing comma).
static RE_SCHEMA: LazyLock<Regex> =
LazyLock::new(|| Regex::new(r#"(?m)^\s*"\$schema"\s*:\s*"[^"]*"\s*,?\s*\n"#).unwrap());

/// Strip the `"$schema"` property from a JSON/JSONC config string.
///
/// JSON config files (`.oxlintrc.json`, `.oxfmtrc.json`) often contain a
/// `"$schema"` annotation that is meaningful only for editor validation.
/// When the JSON content is embedded into `vite.config.ts`, the `$schema`
/// property causes a TypeScript type error because it is not part of
/// `OxlintConfig` / `OxfmtConfig`.
fn strip_schema_property(config: &str) -> Cow<'_, str> {
RE_SCHEMA.replace_all(config, "")
}

/// Check if the vite config uses a function callback pattern
fn check_function_callback(vite_config_content: &str) -> Result<bool, Error> {
// Match both sync and async arrow functions
Expand Down Expand Up @@ -870,6 +889,52 @@ export default defineConfig({
);
}

#[test]
fn test_strip_schema_property() {
// With trailing comma
let input = r#"{
"$schema": "https://raw.githubusercontent.com/nicolo-ribaudo/tc39-proposal-json-schema/refs/heads/main/schema.json",
"rules": {
"no-console": "warn"
}
}"#;
let result = strip_schema_property(input);
assert!(!result.contains("$schema"));
assert!(result.contains(r#""no-console": "warn""#));

// Without trailing comma
let input = r#"{
"$schema": "https://example.com/schema.json"
}"#;
let result = strip_schema_property(input);
assert!(!result.contains("$schema"));

// No $schema - unchanged
let input = r#"{
"rules": {}
}"#;
assert_eq!(strip_schema_property(input), input);
}

#[test]
fn test_merge_json_config_content_strips_schema() {
let vite_config = r#"import { defineConfig } from 'vite';

export default defineConfig({});"#;

let oxlint_config = r#"{
"$schema": "https://raw.githubusercontent.com/nicolo-ribaudo/tc39-proposal-json-schema/refs/heads/main/schema.json",
"rules": {
"no-console": "warn"
}
}"#;

let result = merge_json_config_content(vite_config, oxlint_config, "lint").unwrap();
assert!(result.updated);
assert!(!result.content.contains("$schema"));
assert!(result.content.contains(r#""no-console": "warn""#));
}

#[test]
fn test_indent_multiline() {
// Single line - no change
Expand Down
2 changes: 1 addition & 1 deletion ecosystem-ci/repo.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"vue-mini": {
"repository": "https://github.com/vue-mini/vue-mini.git",
"branch": "master",
"hash": "c51332662993dde44f665822bdea94cd0abf368b"
"hash": "23df6ba49e29d3ea909ef55874f59b973916d177"
},
"vite-plugin-react": {
"repository": "https://github.com/vitejs/vite-plugin-react.git",
Expand Down
35 changes: 2 additions & 33 deletions packages/cli/binding/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,12 +115,6 @@ pub enum SynthesizableSubcommand {
/// Skip lint check
#[arg(long = "no-lint")]
no_lint: bool,
/// Disable type-aware linting
#[arg(long = "no-type-aware")]
no_type_aware: bool,
/// Disable TypeScript type checking
#[arg(long = "no-type-check")]
no_type_check: bool,
/// File paths to check (passed through to fmt and lint)
#[arg(trailing_var_arg = true)]
paths: Vec<String>,
Expand Down Expand Up @@ -1040,14 +1034,7 @@ async fn execute_direct_subcommand(
let cwd_arc: Arc<AbsolutePath> = cwd.clone().into();

let status = match subcommand {
SynthesizableSubcommand::Check {
fix,
no_fmt,
no_lint,
no_type_aware,
no_type_check,
paths,
} => {
SynthesizableSubcommand::Check { fix, no_fmt, no_lint, paths } => {
if no_fmt && no_lint {
output::error("No checks enabled");
print_summary_line(
Expand Down Expand Up @@ -1140,13 +1127,6 @@ async fn execute_direct_subcommand(
if fix {
args.push("--fix".to_string());
}
if !no_type_aware {
args.push("--type-aware".to_string());
// --type-check requires --type-aware as prerequisite
if !no_type_check {
args.push("--type-check".to_string());
}
}
if has_paths {
args.extend(paths.iter().cloned());
}
Expand All @@ -1171,18 +1151,7 @@ async fn execute_direct_subcommand(

match analyze_lint_output(&combined_output) {
Some(Ok(success)) => {
let type_checks_enabled = !no_type_aware && !no_type_check;
let issue_label = if type_checks_enabled {
if fix {
"Found no warnings, lint errors, or type errors"
} else {
"Found no warnings, lint errors, or type errors"
}
} else if fix {
"Found no warnings or lint errors"
} else {
"Found no warnings or lint errors"
};
let issue_label = "Found no warnings, lint errors, or type errors";

let message = format!(
"{issue_label} in {}",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{
"ignoredPlatforms": ["win32"],
"commands": ["vp dlx -s cowsay hello # should work without package.json"]
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"ignoredPlatforms": ["win32"],
"commands": [
{
"command": "cd scripts && vp create --no-interactive vite:application # from non-monorepo subdir",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ export default defineConfig({
lint: {
"rules": {
"no-unused-vars": "error"
},
"options": {
"typeAware": true,
"typeCheck": true
}
},
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"rules": {
"no-unused-vars": "error"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"devDependencies": {
"oxlint": "1"
}
}
57 changes: 57 additions & 0 deletions packages/cli/snap-tests-global/migration-baseurl-tsconfig/snap.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
> vp migrate --no-interactive # migration should skip typeAware/typeCheck when tsconfig has baseUrl
VITE+ - The Unified Toolchain for the Web


Using default package manager: pnpm

pnpm@latest installing...

pnpm@<semver> installed

✔ Created vite.config.ts in vite.config.ts

Skipped typeAware/typeCheck: tsconfig.json contains baseUrl which is not yet supported by the oxlint type checker.
Run `npx @andrewbranch/ts5to6 --fixBaseUrl .` to remove baseUrl from your tsconfig.

✔ Merged .oxlintrc.json into vite.config.ts

✔ Merged staged config into vite.config.ts

Wrote agent instructions to AGENTS.md
✔ Migration completed!


> cat vite.config.ts # check vite.config.ts — should NOT have typeAware or typeCheck
import { defineConfig } from 'vite-plus';

export default defineConfig({
staged: {
"*": "vp check --fix"
},
lint: {
"rules": {
"no-unused-vars": "error"
},
"options": {}
},
});

> cat .oxlintrc.json && exit 1 || true # check .oxlintrc.json is removed
cat: .oxlintrc.json: No such file or directory

> cat package.json # check package.json
{
"devDependencies": {
"vite-plus": "latest"
},
"pnpm": {
"overrides": {
"vite": "npm:@voidzero-dev/vite-plus-core@latest",
"vitest": "npm:@voidzero-dev/vite-plus-test@latest"
}
},
"packageManager": "pnpm@<semver>",
"scripts": {
"prepare": "vp config"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"commands": [
"vp migrate --no-interactive # migration should skip typeAware/typeCheck when tsconfig has baseUrl",
"cat vite.config.ts # check vite.config.ts — should NOT have typeAware or typeCheck",
"cat .oxlintrc.json && exit 1 || true # check .oxlintrc.json is removed",
"cat package.json # check package.json"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"compilerOptions": {
"target": "ES2023",
"module": "NodeNext",
"baseUrl": "."
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,15 @@ export default defineConfig({
"categories": {
"correctness": "warn"
},
"$schema": "./node_modules/oxlint/configuration_schema.json",
"env": {
"builtin": true
},
"rules": {
"no-unused-vars": "error"
},
"options": {
"typeAware": true,
"typeCheck": true
}
},
staged: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,15 @@ export default defineConfig({
"categories": {
"correctness": "warn"
},
"$schema": "./node_modules/oxlint/configuration_schema.json",
"env": {
"builtin": true
},
"rules": {
"no-unused-vars": "error"
},
"options": {
"typeAware": true,
"typeCheck": true
}
},
staged: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,15 @@ export default defineConfig({
"categories": {
"correctness": "warn"
},
"$schema": "./node_modules/oxlint/configuration_schema.json",
"env": {
"builtin": true
},
"rules": {
"no-unused-vars": "error"
},
"options": {
"typeAware": true,
"typeCheck": true
}
},

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,15 @@ export default defineConfig({
"categories": {
"correctness": "warn"
},
"$schema": "./node_modules/oxlint/configuration_schema.json",
"env": {
"builtin": true
},
"rules": {
"no-unused-vars": "error"
},
"options": {
"typeAware": true,
"typeCheck": true
}
},

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,15 @@ export default defineConfig({
"categories": {
"correctness": "warn"
},
"$schema": "./node_modules/oxlint/configuration_schema.json",
"env": {
"builtin": true
},
"rules": {
"no-unused-vars": "error"
},
"options": {
"typeAware": true,
"typeCheck": true
}
},

Expand Down
Loading
Loading