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
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"rules": {
"no-console": "error"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "@test/lint-config-arg",
"version": "1.0.0",
"private": true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[[case]]
name = "lint_config_arg"
vp = "local"
steps = [
{ argv = ["vp", "lint", "-c", "custom.json"], comment = "Should apply lint from custom.json", continue-on-failure = true },
{ argv = ["vp", "lint", "-c=custom.json"], comment = "Should apply lint from custom.json", continue-on-failure = true },
{ argv = ["vp", "lint", "--config", "custom.json"], comment = "Should apply lint from custom.json", continue-on-failure = true },
{ argv = ["vp", "lint", "--config=custom.json"], comment = "Should apply lint from custom.json", continue-on-failure = true },
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# lint_config_arg

## `vp lint -c custom.json`

Should apply lint from custom.json

**Exit code:** 1

```

× eslint(no-console): Unexpected console statement.
╭─[src/invalid.js:2:3]
1 │ export function example() {
2 │ console.log('hello');
· ───────────
3 │ return 'hello';
╰────
help: Delete this console statement.

Found 0 warnings and 1 error.
Finished in <duration> on 3 files with <n> rules using <n> threads.
```

## `vp lint -c=custom.json`

Should apply lint from custom.json

**Exit code:** 1

```

× eslint(no-console): Unexpected console statement.
╭─[src/invalid.js:2:3]
1 │ export function example() {
2 │ console.log('hello');
· ───────────
3 │ return 'hello';
╰────
help: Delete this console statement.

Found 0 warnings and 1 error.
Finished in <duration> on 3 files with <n> rules using <n> threads.
```

## `vp lint --config custom.json`

Should apply lint from custom.json

**Exit code:** 1

```

× eslint(no-console): Unexpected console statement.
╭─[src/invalid.js:2:3]
1 │ export function example() {
2 │ console.log('hello');
· ───────────
3 │ return 'hello';
╰────
help: Delete this console statement.

Found 0 warnings and 1 error.
Finished in <duration> on 3 files with <n> rules using <n> threads.
```

## `vp lint --config=custom.json`

Should apply lint from custom.json

**Exit code:** 1

```

× eslint(no-console): Unexpected console statement.
╭─[src/invalid.js:2:3]
1 │ export function example() {
2 │ console.log('hello');
· ───────────
3 │ return 'hello';
╰────
help: Delete this console statement.

Found 0 warnings and 1 error.
Finished in <duration> on 3 files with <n> rules using <n> threads.
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export function example() {
console.log('hello');
return 'hello';
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function example() {
return 'hello';
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default {
lint: {
rules: {
'no-console': 'off',
},
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"rules": {
"no-console": "error"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"scripts": {
"lint": "oxlint -c .oxlintrc.json"
},
"devDependencies": {
"oxlint": "1.82.0"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[[case]]
name = "migration_oxlint_config_arg"
vp = "global"
steps = [
{ argv = ["vp", "migrate", "--no-interactive", "--no-hooks", "--no-agent", "--no-editor"], comment = "Migrate a project with an Oxlint config argument", continue-on-failure = true },
{ argv = ["vpt", "print-file", "package.json"], comment = "oxlint -c .oxlintrc.json should be rewritten to vp lint", continue-on-failure = true },
{ argv = ["vpt", "print-file", "vite.config.ts"], comment = ".oxlintrc.json should be merged into vite.config.ts", continue-on-failure = true },
{ argv = ["vpt", "stat-file", ".oxlintrc.json", "--assert-not", "file"], comment = "The merged .oxlintrc.json should be removed", continue-on-failure = true },
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# migration_oxlint_config_arg

## `vp migrate --no-interactive --no-hooks --no-agent --no-editor`

Migrate a project with an Oxlint config argument

```
VITE+ - The Unified Toolchain for the Web

◇ Migrated . to Vite+ <version>
• Node <version> pnpm <version>
• 2 config updates applied
```

## `vpt print-file package.json`

oxlint -c .oxlintrc.json should be rewritten to vp lint

```
{
"scripts": {
"lint": "vp lint"
},
"devDependencies": {
"vite": "catalog:",
"vite-plus": "catalog:"
},
"devEngines": {
"packageManager": {
"name": "pnpm",
"version": "<version>",
"onFail": "download"
}
}
}
```

## `vpt print-file vite.config.ts`

.oxlintrc.json should be merged into vite.config.ts

```
import { defineConfig } from 'vite-plus';

export default defineConfig({
fmt: {},
lint: {
"rules": {
"no-console": "error",
"vite-plus/prefer-vite-plus-imports": "error"
},
"options": {
"typeAware": true,
"typeCheck": true
},
"jsPlugins": [
{
"name": "vite-plus",
"specifier": "vite-plus/oxlint-plugin"
}
]
},
});
```

## `vpt stat-file .oxlintrc.json --assert-not file`

The merged .oxlintrc.json should be removed

```
.oxlintrc.json: missing
```
2 changes: 1 addition & 1 deletion crates/vp_migration/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub use import_rewriter::{
BatchRewriteResult, RewriteImportsOptions, rewrite_imports_in_directory,
rewrite_imports_in_directory_with_options,
};
pub use package::{rewrite_eslint, rewrite_prettier, rewrite_scripts};
pub use package::{rewrite_eslint, rewrite_oxlint, rewrite_prettier, rewrite_scripts};
pub use vite_config::{
MergeResult, has_config_key, merge_json_config, merge_tsdown_config, upsert_json_config,
wrap_lazy_plugins,
Expand Down
79 changes: 76 additions & 3 deletions crates/vp_migration/src/package.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,35 @@ use crate::{
ast_grep,
eslint::rewrite_eslint_script,
prettier::rewrite_prettier_script,
script_rewrite::{rewrite_bunx_commands, rewrite_pack_flags},
script_rewrite::{
ScriptRewriteConfig, rewrite_bunx_commands, rewrite_pack_flags,
rewrite_script_stripping_flags_with_matching_value,
},
};

// Marker to replace "cross-env " before ast-grep processing
// Using a fake env var assignment that won't match our rules
const CROSS_ENV_MARKER: &str = "__CROSS_ENV__=1 ";
const CROSS_ENV_REPLACEMENT: &str = "cross-env ";

/// Rewrite Oxlint commands and strip config arguments referencing the migrated config.
fn rewrite_oxlint_script(script: &str, oxlint_config_path: &str) -> String {
if !script.contains("oxlint") {
return script.to_owned();
}
rewrite_script_stripping_flags_with_matching_value(
script,
&ScriptRewriteConfig {
source_command: "oxlint",
target_subcommand: "lint",
boolean_flags: &[],
value_flags: &["-c", "--config"],
flag_conversions: &[],
},
oxlint_config_path,
)
}

/// rewrite a single script command string using rules
fn rewrite_script(script: &str, rules: &[RuleConfig<SupportLang>]) -> String {
// Only handle cross-env replacement if it's present in the script
Expand Down Expand Up @@ -100,10 +121,18 @@ pub fn rewrite_prettier(scripts_json: &str) -> Result<Option<String>, Error> {
transform_scripts_json(scripts_json, rewrite_prettier_script)
}

/// rewrite scripts json content using rules from `rules_yaml`
/// Rewrite Oxlint commands and strip config arguments referencing a config that will be merged.
pub fn rewrite_oxlint(
scripts_json: &str,
oxlint_config_path: &str,
) -> Result<Option<String>, Error> {
transform_scripts_json(scripts_json, |script| rewrite_oxlint_script(script, oxlint_config_path))
}

/// Rewrite scripts json content using rules from `rules_yaml`.
pub fn rewrite_scripts(scripts_json: &str, rules_yaml: &str) -> Result<Option<String>, Error> {
let rules = ast_grep::load_rules(rules_yaml)?;
transform_scripts_json(scripts_json, |raw_script| rewrite_script(raw_script, &rules))
transform_scripts_json(scripts_json, |script| rewrite_script(script, &rules))
}

#[cfg(test)]
Expand Down Expand Up @@ -392,6 +421,50 @@ fix: vp pack
assert_eq!(rewrite_script("husky || true", &rules), "husky || true");
}

#[test]
fn test_rewrite_script_with_oxlint_config() {
let rules = ast_grep::load_rules(RULES_YAML).unwrap();
for (input, expected) in [
// Basic cases
("oxlint -c .oxlintrc.json", "vp lint"),
("oxlint -c=.oxlintrc.json", "vp lint"),
("oxlint --config .oxlintrc.json", "vp lint"),
("oxlint --config=.oxlintrc.json", "vp lint"),
// With quotes
("oxlint -c \"./.oxlintrc.json\"", "vp lint"),
("oxlint -c=\"./.oxlintrc.json\"", "vp lint"),
("oxlint --config \"./.oxlintrc.json\"", "vp lint"),
("oxlint --config=\"./.oxlintrc.json\"", "vp lint"),
("oxlint -c './.oxlintrc.json'", "vp lint"),
("oxlint -c='./.oxlintrc.json'", "vp lint"),
("oxlint --config './.oxlintrc.json'", "vp lint"),
("oxlint --config='./.oxlintrc.json'", "vp lint"),
// With custom file
("oxlint -c custom.json", "vp lint -c custom.json"),
("oxlint -c=custom.json", "vp lint -c=custom.json"),
("oxlint --config custom.json", "vp lint --config custom.json"),
("oxlint --config=custom.json", "vp lint --config=custom.json"),
// With combined flags
("oxlint -c .oxlintrc.json --fix", "vp lint --fix"),
("oxlint -c .oxlintrc.json --type-aware", "vp lint --type-aware"),
("oxlint -c .oxlintrc.json --fix --type-aware", "vp lint --fix --type-aware"),
("oxlint --config .oxlintrc.json --fix", "vp lint --fix"),
("oxlint --config .oxlintrc.json --type-aware", "vp lint --type-aware"),
("oxlint --config .oxlintrc.json --fix --type-aware", "vp lint --fix --type-aware"),
// With combined commands
("oxlint -c .oxlintrc.json --fix && pnpm run test", "vp lint --fix && pnpm run test"),
("cross-env MODE=test oxlint -c .oxlintrc.json", "cross-env MODE=test vp lint"),
("bunx --bun oxlint --config=./.oxlintrc.json", "bunx --bun vp lint"),
// With a Windows path separator
("oxlint -c .\\.oxlintrc.json", "vp lint"),
] {
assert_eq!(
rewrite_script(&rewrite_oxlint_script(input, ".oxlintrc.json"), &rules),
expected
);
}
}

#[test]
fn test_rewrite_package_json_scripts_success() {
let package_json_scripts = r#"
Expand Down
Loading
Loading