|
1 | | -use std::path::Path; |
2 | | - |
3 | 1 | use ast_grep_config::{GlobalRules, RuleConfig, from_yaml_string}; |
4 | 2 | use ast_grep_core::replacer::Replacer; |
5 | 3 | use ast_grep_language::{LanguageExt, SupportLang}; |
6 | | -use serde_json::Value; |
7 | | -use tokio::fs; |
| 4 | +use serde_json::{Map, Value}; |
8 | 5 | use vite_error::Error; |
9 | 6 |
|
10 | 7 | /// load script rules from yaml file |
11 | | -async fn load_ast_grep_rules(yaml_path: &Path) -> Result<Vec<RuleConfig<SupportLang>>, Error> { |
12 | | - let yaml = fs::read_to_string(yaml_path).await?; |
| 8 | +fn load_ast_grep_rules(yaml: &str) -> Result<Vec<RuleConfig<SupportLang>>, Error> { |
13 | 9 | let globals = GlobalRules::default(); |
14 | 10 | let rules: Vec<RuleConfig<SupportLang>> = from_yaml_string::<SupportLang>(&yaml, &globals)?; |
15 | 11 | Ok(rules) |
@@ -59,46 +55,55 @@ fn rewrite_script(script: &str, rules: &[RuleConfig<SupportLang>]) -> String { |
59 | 55 | current |
60 | 56 | } |
61 | 57 |
|
62 | | -/// rewrite scripts in package.json using rules from rules_yaml_path |
63 | | -pub async fn rewrite_package_json_scripts( |
64 | | - package_json_path: &Path, |
65 | | - rules_yaml_path: &Path, |
66 | | -) -> Result<bool, Error> { |
67 | | - let content = fs::read_to_string(package_json_path).await?; |
68 | | - let mut json: Value = serde_json::from_str(&content)?; |
69 | | - let rules = load_ast_grep_rules(rules_yaml_path).await?; |
| 58 | +/// rewrite scripts json content using rules from rules_yaml |
| 59 | +pub fn rewrite_scripts(scripts_json: &str, rules_yaml: &str) -> Result<Option<String>, Error> { |
| 60 | + let mut scripts: Map<String, Value> = serde_json::from_str(scripts_json)?; |
| 61 | + let rules = load_ast_grep_rules(rules_yaml)?; |
70 | 62 |
|
71 | 63 | let mut updated = false; |
72 | 64 | // get scripts field (object) |
73 | | - if let Some(scripts) = json.get_mut("scripts").and_then(Value::as_object_mut) { |
74 | | - let keys: Vec<String> = scripts.keys().cloned().collect(); |
75 | | - for key in keys { |
76 | | - if let Some(Value::String(script)) = scripts.get(&key) { |
77 | | - let new_script = rewrite_script(script, &rules); |
78 | | - if new_script != *script { |
| 65 | + // let keys: Vec<String> = scripts.keys().cloned().collect(); |
| 66 | + for value in scripts.values_mut() { |
| 67 | + if value.is_array() { |
| 68 | + // lint-staged scripts can be an array of strings |
| 69 | + // https://github.com/lint-staged/lint-staged?tab=readme-ov-file#packagejson-example |
| 70 | + if let Some(sub_scripts) = value.as_array_mut() { |
| 71 | + for sub_script in sub_scripts.iter_mut() { |
| 72 | + if sub_script.is_string() |
| 73 | + && let Some(raw_script) = sub_script.as_str() |
| 74 | + { |
| 75 | + let new_script = rewrite_script(raw_script, &rules); |
| 76 | + if new_script != raw_script { |
| 77 | + updated = true; |
| 78 | + *sub_script = Value::String(new_script); |
| 79 | + } |
| 80 | + } |
| 81 | + } |
| 82 | + } |
| 83 | + } else if value.is_string() { |
| 84 | + if let Some(raw_script) = value.as_str() { |
| 85 | + let new_script = rewrite_script(raw_script, &rules); |
| 86 | + if new_script != raw_script { |
79 | 87 | updated = true; |
80 | | - scripts.insert(key.clone(), Value::String(new_script)); |
| 88 | + *value = Value::String(new_script); |
81 | 89 | } |
82 | 90 | } |
83 | 91 | } |
84 | 92 | } |
85 | 93 |
|
86 | 94 | if updated { |
87 | | - // write back to file |
88 | | - let new_content = serde_json::to_string_pretty(&json)?; |
89 | | - fs::write(package_json_path, new_content).await?; |
| 95 | + let new_content = serde_json::to_string_pretty(&scripts)?; |
| 96 | + Ok(Some(new_content)) |
| 97 | + } else { |
| 98 | + Ok(None) |
90 | 99 | } |
91 | | - |
92 | | - Ok(updated) |
93 | 100 | } |
94 | 101 |
|
95 | 102 | #[cfg(test)] |
96 | 103 | mod tests { |
97 | 104 | use super::*; |
98 | 105 |
|
99 | | - #[test] |
100 | | - fn test_rewrite_script() { |
101 | | - let yaml = r#" |
| 106 | + const RULES_YAML: &str = r#" |
102 | 107 | # vite => vite dev |
103 | 108 | --- |
104 | 109 | id: replace-vite-alone |
@@ -148,10 +153,13 @@ language: bash |
148 | 153 | rule: |
149 | 154 | pattern: oxlint $$$ARGS |
150 | 155 | fix: vite lint $$$ARGS |
151 | | -"#; |
| 156 | + "#; |
| 157 | + |
| 158 | + #[test] |
| 159 | + fn test_rewrite_script() { |
152 | 160 | let globals = GlobalRules::default(); |
153 | 161 | let rules: Vec<RuleConfig<SupportLang>> = |
154 | | - from_yaml_string::<SupportLang>(&yaml, &globals).unwrap(); |
| 162 | + from_yaml_string::<SupportLang>(&RULES_YAML, &globals).unwrap(); |
155 | 163 | // vite commands |
156 | 164 | assert_eq!(rewrite_script("vite", &rules), "vite dev"); |
157 | 165 | assert_eq!(rewrite_script("vite dev", &rules), "vite dev"); |
@@ -230,4 +238,63 @@ fix: vite lint $$$ARGS |
230 | 238 | "npm run type-check && vite lint --type-aware" |
231 | 239 | ); |
232 | 240 | } |
| 241 | + |
| 242 | + #[test] |
| 243 | + fn test_rewrite_package_json_scripts_success() { |
| 244 | + let package_json_scripts = r#" |
| 245 | +{ |
| 246 | + "dev": "vite" |
| 247 | +} |
| 248 | + "#; |
| 249 | + let updated = rewrite_scripts(package_json_scripts, &RULES_YAML) |
| 250 | + .expect("failed to rewrite package.json scripts"); |
| 251 | + assert!(updated.is_some()); |
| 252 | + assert_eq!( |
| 253 | + updated.unwrap(), |
| 254 | + r#" |
| 255 | +{ |
| 256 | + "dev": "vite dev" |
| 257 | +} |
| 258 | + "# |
| 259 | + .trim() |
| 260 | + ); |
| 261 | + } |
| 262 | + |
| 263 | + #[test] |
| 264 | + fn test_rewrite_package_json_scripts_lint_staged() { |
| 265 | + let package_json_scripts = r#" |
| 266 | + { |
| 267 | + "*.js": ["oxlint --fix --type-aware", "oxfmt --fix"], |
| 268 | + "*.ts": "oxfmt --fix" |
| 269 | + } |
| 270 | + "#; |
| 271 | + let updated = rewrite_scripts(package_json_scripts, &RULES_YAML) |
| 272 | + .expect("failed to rewrite package.json scripts"); |
| 273 | + assert!(updated.is_some()); |
| 274 | + assert_eq!( |
| 275 | + updated.unwrap(), |
| 276 | + r#" |
| 277 | +{ |
| 278 | + "*.js": [ |
| 279 | + "vite lint --fix --type-aware", |
| 280 | + "oxfmt --fix" |
| 281 | + ], |
| 282 | + "*.ts": "oxfmt --fix" |
| 283 | +} |
| 284 | + "# |
| 285 | + .trim() |
| 286 | + ); |
| 287 | + } |
| 288 | + |
| 289 | + #[test] |
| 290 | + fn test_rewrite_package_json_scripts_no_update() { |
| 291 | + let package_json_scripts = r#" |
| 292 | + { |
| 293 | + "foo": "bar" |
| 294 | + } |
| 295 | + "#; |
| 296 | + let updated = rewrite_scripts(package_json_scripts, &RULES_YAML) |
| 297 | + .expect("failed to rewrite package.json scripts"); |
| 298 | + assert!(updated.is_none()); |
| 299 | + } |
233 | 300 | } |
0 commit comments