ast-grep-cli 0.9.2__tar.gz → 0.10.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/PKG-INFO +1 -1
  2. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/crates/cli/Cargo.lock +18 -18
  3. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/crates/cli/Cargo.toml +2 -2
  4. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/crates/cli/src/config.rs +50 -18
  5. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/crates/cli/src/error.rs +19 -3
  6. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/crates/cli/src/lib.rs +5 -0
  7. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/crates/cli/src/new.rs +33 -14
  8. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/crates/cli/src/print/cloud_print.rs +1 -1
  9. ast_grep_cli-0.10.0/crates/cli/src/print/colored_print/test.rs +281 -0
  10. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/crates/cli/src/print/colored_print.rs +97 -215
  11. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/crates/cli/src/print/interactive_print.rs +43 -4
  12. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/crates/cli/src/print/json_print.rs +208 -33
  13. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/crates/cli/src/print/mod.rs +1 -1
  14. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/crates/cli/src/run.rs +95 -81
  15. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/crates/cli/src/scan.rs +42 -62
  16. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/crates/cli/src/utils.rs +104 -49
  17. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/crates/cli/src/verify.rs +16 -11
  18. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-config/Cargo.toml +2 -2
  19. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-config/src/deserialize_env.rs +1 -1
  20. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-config/src/referent_rule.rs +3 -3
  21. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-config/src/rule.rs +1 -1
  22. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-config/src/rule_config.rs +3 -3
  23. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-core/Cargo.toml +1 -1
  24. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-core/src/lib.rs +3 -0
  25. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-core/src/match_tree.rs +1 -1
  26. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-core/src/node.rs +56 -17
  27. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-core/src/replacer/indent.rs +3 -3
  28. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-core/src/source.rs +1 -1
  29. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-dynamic/Cargo.toml +1 -1
  30. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-dynamic/src/lib.rs +1 -1
  31. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-language/Cargo.toml +4 -4
  32. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-language/src/parsers.rs +3 -3
  33. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-lsp/Cargo.toml +2 -2
  34. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-lsp/src/lib.rs +2 -2
  35. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/pyproject.toml +1 -1
  36. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/LICENSE +0 -0
  37. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/README.md +0 -0
  38. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/crates/cli/src/bin/ast-grep.rs +0 -0
  39. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/crates/cli/src/lang.rs +0 -0
  40. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/crates/cli/src/lsp.rs +0 -0
  41. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/crates/cli/src/main.rs +0 -0
  42. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/crates/cli/tests/common/mod.rs +0 -0
  43. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/crates/cli/tests/run_test.rs +0 -0
  44. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/crates/cli/tests/scan_test.rs +0 -0
  45. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/crates/cli/tests/verify_test.rs +0 -0
  46. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-config/src/constraints.rs +0 -0
  47. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-config/src/lib.rs +0 -0
  48. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-config/src/maybe.rs +0 -0
  49. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-config/src/relational_rule/mod.rs +0 -0
  50. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-config/src/relational_rule/stop_by.rs +0 -0
  51. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-config/src/rule_collection.rs +0 -0
  52. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-config/src/transform.rs +0 -0
  53. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-core/src/language.rs +0 -0
  54. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-core/src/matcher/kind.rs +0 -0
  55. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-core/src/matcher/node_match.rs +0 -0
  56. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-core/src/matcher/pattern.rs +0 -0
  57. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-core/src/matcher/text.rs +0 -0
  58. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-core/src/matcher.rs +0 -0
  59. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-core/src/meta_var.rs +0 -0
  60. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-core/src/ops.rs +0 -0
  61. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-core/src/pinned.rs +0 -0
  62. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-core/src/replacer/structural.rs +0 -0
  63. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-core/src/replacer/template.rs +0 -0
  64. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-core/src/replacer.rs +0 -0
  65. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-core/src/traversal.rs +0 -0
  66. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-language/src/cpp.rs +0 -0
  67. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-language/src/csharp.rs +0 -0
  68. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-language/src/css.rs +0 -0
  69. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-language/src/go.rs +0 -0
  70. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-language/src/json.rs +0 -0
  71. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-language/src/kotlin.rs +0 -0
  72. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-language/src/lib.rs +0 -0
  73. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-language/src/lua.rs +0 -0
  74. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-language/src/python.rs +0 -0
  75. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-language/src/rust.rs +0 -0
  76. {ast_grep_cli-0.9.2 → ast_grep_cli-0.10.0}/local_dependencies/ast-grep-language/src/scala.rs +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ast-grep-cli
3
- Version: 0.9.2
3
+ Version: 0.10.0
4
4
  Classifier: Development Status :: 3 - Alpha
5
5
  Classifier: Environment :: Console
6
6
  Classifier: Intended Audience :: Developers
@@ -98,7 +98,7 @@ dependencies = [
98
98
 
99
99
  [[package]]
100
100
  name = "ast-grep"
101
- version = "0.9.2"
101
+ version = "0.10.0"
102
102
  dependencies = [
103
103
  "ansi_term",
104
104
  "anyhow",
@@ -126,7 +126,7 @@ dependencies = [
126
126
 
127
127
  [[package]]
128
128
  name = "ast-grep-config"
129
- version = "0.9.2"
129
+ version = "0.10.0"
130
130
  dependencies = [
131
131
  "anyhow",
132
132
  "ast-grep-core",
@@ -142,7 +142,7 @@ dependencies = [
142
142
 
143
143
  [[package]]
144
144
  name = "ast-grep-core"
145
- version = "0.9.2"
145
+ version = "0.10.0"
146
146
  dependencies = [
147
147
  "bit-set",
148
148
  "regex",
@@ -153,7 +153,7 @@ dependencies = [
153
153
 
154
154
  [[package]]
155
155
  name = "ast-grep-dynamic"
156
- version = "0.9.2"
156
+ version = "0.10.0"
157
157
  dependencies = [
158
158
  "ast-grep-core",
159
159
  "ignore",
@@ -165,7 +165,7 @@ dependencies = [
165
165
 
166
166
  [[package]]
167
167
  name = "ast-grep-language"
168
- version = "0.9.2"
168
+ version = "0.10.0"
169
169
  dependencies = [
170
170
  "ast-grep-core",
171
171
  "ast-grep-tree-sitter-c-sharp",
@@ -193,7 +193,7 @@ dependencies = [
193
193
 
194
194
  [[package]]
195
195
  name = "ast-grep-lsp"
196
- version = "0.9.2"
196
+ version = "0.10.0"
197
197
  dependencies = [
198
198
  "ast-grep-config",
199
199
  "ast-grep-core",
@@ -205,7 +205,7 @@ dependencies = [
205
205
 
206
206
  [[package]]
207
207
  name = "ast-grep-napi"
208
- version = "0.9.2"
208
+ version = "0.10.0"
209
209
  dependencies = [
210
210
  "ast-grep-config",
211
211
  "ast-grep-core",
@@ -274,7 +274,7 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
274
274
 
275
275
  [[package]]
276
276
  name = "benches"
277
- version = "0.9.2"
277
+ version = "0.10.0"
278
278
  dependencies = [
279
279
  "ast-grep-config",
280
280
  "ast-grep-core",
@@ -747,9 +747,9 @@ dependencies = [
747
747
 
748
748
  [[package]]
749
749
  name = "globset"
750
- version = "0.4.11"
750
+ version = "0.4.12"
751
751
  source = "registry+https://github.com/rust-lang/crates.io-index"
752
- checksum = "1391ab1f92ffcc08911957149833e682aa3fe252b9f45f966d2ef972274c97df"
752
+ checksum = "aca8bbd8e0707c1887a8bbb7e6b40e228f251ff5d62c8220a4a7a53c73aff006"
753
753
  dependencies = [
754
754
  "aho-corasick",
755
755
  "bstr",
@@ -1437,9 +1437,9 @@ dependencies = [
1437
1437
 
1438
1438
  [[package]]
1439
1439
  name = "serde_json"
1440
- version = "1.0.103"
1440
+ version = "1.0.104"
1441
1441
  source = "registry+https://github.com/rust-lang/crates.io-index"
1442
- checksum = "d03b412469450d4404fe8499a268edd7f8b79fecb074b0d812ad64ca21f4031b"
1442
+ checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c"
1443
1443
  dependencies = [
1444
1444
  "indexmap",
1445
1445
  "itoa",
@@ -1776,9 +1776,9 @@ dependencies = [
1776
1776
 
1777
1777
  [[package]]
1778
1778
  name = "tree-sitter-c"
1779
- version = "0.20.3"
1779
+ version = "0.20.4"
1780
1780
  source = "registry+https://github.com/rust-lang/crates.io-index"
1781
- checksum = "4dc4f11ece4d78d5a62591fe2456e9ca76211f0a60939913852ff6dfa023cb07"
1781
+ checksum = "fa1bb73a4101c88775e4fefcd0543ee25e192034484a5bd45cb99eefb997dca9"
1782
1782
  dependencies = [
1783
1783
  "cc",
1784
1784
  "tree-sitter",
@@ -1786,9 +1786,9 @@ dependencies = [
1786
1786
 
1787
1787
  [[package]]
1788
1788
  name = "tree-sitter-cpp"
1789
- version = "0.20.1"
1789
+ version = "0.20.2"
1790
1790
  source = "registry+https://github.com/rust-lang/crates.io-index"
1791
- checksum = "0dbedbf4066bfab725b3f9e2a21530507419a7d2f98621d3c13213502b734ec0"
1791
+ checksum = "1c88fd925d0333e63ac64e521f5bd79c53019e569ffbbccfeef346a326f459e9"
1792
1792
  dependencies = [
1793
1793
  "cc",
1794
1794
  "tree-sitter",
@@ -1899,9 +1899,9 @@ dependencies = [
1899
1899
 
1900
1900
  [[package]]
1901
1901
  name = "tree-sitter-python"
1902
- version = "0.20.2"
1902
+ version = "0.20.3"
1903
1903
  source = "registry+https://github.com/rust-lang/crates.io-index"
1904
- checksum = "dda114f58048f5059dcf158aff691dffb8e113e6d2b50d94263fd68711975287"
1904
+ checksum = "f47ebd9cac632764b2f4389b08517bf2ef895431dd163eb562e3d2062cc23a14"
1905
1905
  dependencies = [
1906
1906
  "cc",
1907
1907
  "tree-sitter",
@@ -8,7 +8,7 @@ default-run = "sg"
8
8
  readme = "../../README.md"
9
9
  license-file = "../../LICENSE"
10
10
 
11
- version= "0.9.2"
11
+ version= "0.10.0"
12
12
  authors= ["Herrington Darkholme <2883231+HerringtonDarkholme@users.noreply.github.com>"]
13
13
  edition= "2021"
14
14
  # license.workspace = true
@@ -42,7 +42,7 @@ ignore= { version = "0.4.20" }
42
42
  inquire = "0.6.2"
43
43
  num_cpus = "1.16.0"
44
44
  serde= { version = "1.0", features = ["derive"] }
45
- serde_json = "1.0.103"
45
+ serde_json = "1.0.104"
46
46
  serde_yaml = "0.9.25"
47
47
  similar = { version = "2.2.1", features = ["inline"] }
48
48
  tokio = { version = "1", features = ["rt-multi-thread", "io-std"] }
@@ -7,6 +7,7 @@ use ast_grep_config::{
7
7
  };
8
8
  use ast_grep_language::config_file_type;
9
9
  use clap::ValueEnum;
10
+ use ignore::overrides::OverrideBuilder;
10
11
  use ignore::WalkBuilder;
11
12
  use serde::{Deserialize, Serialize};
12
13
  use std::collections::HashMap;
@@ -44,9 +45,7 @@ pub struct AstGrepConfig {
44
45
  pub util_dirs: Option<Vec<PathBuf>>,
45
46
  /// configuration for custom languages
46
47
  #[serde(skip_serializing_if = "Option::is_none")]
47
- pub custom_languages: Option<HashMap<String, CustomLang>>, // /// overriding config for rules
48
- // #[serde(skip_serializing_if="Option::is_none")]
49
- // pub rules: Option<Vec<()>>,
48
+ pub custom_languages: Option<HashMap<String, CustomLang>>,
50
49
  }
51
50
 
52
51
  pub fn find_rules(config_path: Option<PathBuf>) -> Result<RuleCollection<SgLang>> {
@@ -156,7 +155,7 @@ pub struct TestHarness {
156
155
  pub path_map: HashMap<String, PathBuf>,
157
156
  }
158
157
 
159
- pub fn find_tests(config_path: Option<PathBuf>) -> Result<TestHarness> {
158
+ pub fn find_tests(config_path: Option<PathBuf>, glob_filter: Option<&str>) -> Result<TestHarness> {
160
159
  let config_path =
161
160
  find_config_path_with_default(config_path, None).context(EC::ReadConfiguration)?;
162
161
  let config_str = read_to_string(&config_path).context(EC::ReadConfiguration)?;
@@ -173,7 +172,12 @@ pub fn find_tests(config_path: Option<PathBuf>) -> Result<TestHarness> {
173
172
  test_cases: new_cases,
174
173
  snapshots: new_snapshots,
175
174
  path_map: new_path_map,
176
- } = read_test_files(base_dir, &test.test_dir, test.snapshot_dir.as_deref())?;
175
+ } = read_test_files(
176
+ base_dir,
177
+ &test.test_dir,
178
+ test.snapshot_dir.as_deref(),
179
+ glob_filter,
180
+ )?;
177
181
  path_map.extend(new_path_map);
178
182
  test_cases.extend(new_cases);
179
183
  snapshots.extend(new_snapshots);
@@ -185,22 +189,46 @@ pub fn find_tests(config_path: Option<PathBuf>) -> Result<TestHarness> {
185
189
  })
186
190
  }
187
191
 
192
+ fn build_test_dir_walker(
193
+ test_path: &Path,
194
+ snapshot_dirname: &Path,
195
+ glob_filter: Option<&str>,
196
+ ) -> Result<ignore::Walk> {
197
+ let snapshot_glob = snapshot_dirname.join("*");
198
+
199
+ let glob_override = OverrideBuilder::new(test_path)
200
+ .add(glob_filter.unwrap_or("*"))?
201
+ .add(
202
+ snapshot_glob
203
+ .to_str()
204
+ .expect("snapshot glob should be valid utf-8"),
205
+ )?
206
+ .build()?;
207
+
208
+ let walker = WalkBuilder::new(test_path)
209
+ .types(config_file_type())
210
+ .overrides(glob_override)
211
+ .build();
212
+
213
+ Ok(walker)
214
+ }
215
+
188
216
  pub fn read_test_files(
189
217
  base_dir: &Path,
190
- test_dir: &Path,
191
- snapshot_dir: Option<&Path>,
218
+ test_dirname: &Path,
219
+ snapshot_dirname: Option<&Path>,
220
+ glob_filter: Option<&str>,
192
221
  ) -> Result<TestHarness> {
193
222
  let mut test_cases = vec![];
194
223
  let mut snapshots = HashMap::new();
195
224
  let mut path_map = HashMap::new();
196
- let dir_path = base_dir.join(test_dir);
197
- let snapshot_dir = snapshot_dir.unwrap_or_else(|| SNAPSHOT_DIR.as_ref());
198
- let snapshot_dir = dir_path.join(snapshot_dir);
199
- let walker = WalkBuilder::new(&dir_path)
200
- .types(config_file_type())
201
- .build();
225
+ let test_path = base_dir.join(test_dirname);
226
+ let snapshot_dirname = snapshot_dirname.unwrap_or_else(|| SNAPSHOT_DIR.as_ref());
227
+ let snapshot_path = test_path.join(snapshot_dirname);
228
+ let walker = build_test_dir_walker(&test_path, snapshot_dirname, glob_filter)
229
+ .with_context(|| EC::TestCaseGlobFilter)?;
202
230
  for dir in walker {
203
- let config_file = dir.with_context(|| EC::WalkRuleDir(dir_path.clone()))?;
231
+ let config_file = dir.with_context(|| EC::WalkRuleDir(test_path.clone()))?;
204
232
  // file_type is None only if it is stdin, safe to unwrap here
205
233
  if !config_file
206
234
  .file_type()
@@ -211,14 +239,14 @@ pub fn read_test_files(
211
239
  }
212
240
  let path = config_file.path();
213
241
  let yaml = read_to_string(path).with_context(|| EC::ReadRule(path.to_path_buf()))?;
214
- if path.starts_with(&snapshot_dir) {
242
+ if path.starts_with(&snapshot_path) {
215
243
  let snapshot: TestSnapshots =
216
244
  from_str(&yaml).with_context(|| EC::ParseTest(path.to_path_buf()))?;
217
245
  snapshots.insert(snapshot.id.clone(), snapshot);
218
246
  } else {
219
247
  let test_case: TestCase =
220
248
  from_str(&yaml).with_context(|| EC::ParseTest(path.to_path_buf()))?;
221
- path_map.insert(test_case.id.clone(), dir_path.join(SNAPSHOT_DIR));
249
+ path_map.insert(test_case.id.clone(), test_path.join(snapshot_dirname));
222
250
  test_cases.push(test_case);
223
251
  }
224
252
  }
@@ -229,14 +257,17 @@ pub fn read_test_files(
229
257
  })
230
258
  }
231
259
 
260
+ /// Returns the base_directory where config is and config object.
232
261
  pub fn read_config_from_dir<P: AsRef<Path>>(path: P) -> Result<Option<(PathBuf, AstGrepConfig)>> {
233
- let config_path =
262
+ let mut config_path =
234
263
  find_config_path_with_default(None, Some(path.as_ref())).context(EC::ReadConfiguration)?;
235
264
  if !config_path.is_file() {
236
265
  return Ok(None);
237
266
  }
238
267
  let config_str = read_to_string(&config_path).context(EC::ReadConfiguration)?;
239
268
  let sg_config = from_str(&config_str).context(EC::ParseConfiguration)?;
269
+ // remove sgconfig.yml from the path
270
+ config_path.pop(); // ./sg_config -> ./
240
271
  Ok(Some((config_path, sg_config)))
241
272
  }
242
273
 
@@ -268,12 +299,13 @@ fn find_config_path_with_default(
268
299
  }
269
300
  }
270
301
 
302
+ /// File types to ignore
271
303
  #[derive(Clone, Copy, Deserialize, Serialize, ValueEnum)]
272
304
  pub enum IgnoreFile {
273
305
  /// Search hidden files and directories. By default, hidden files and directories are skipped.
274
306
  Hidden,
275
307
  /// Don't respect .ignore files.
276
- /// This does *not* affect whether ripgrep will ignore files and directories whose names begin with a dot.
308
+ /// This does *not* affect whether ast-grep will ignore files and directories whose names begin with a dot.
277
309
  /// For that, use --no-ignore hidden.
278
310
  Dot,
279
311
  /// Don't respect ignore files that are manually configured for the repository such as git's '.git/info/exclude'.
@@ -4,8 +4,6 @@ use anyhow::{Error, Result};
4
4
  use std::fmt;
5
5
  use std::path::PathBuf;
6
6
 
7
- use crate::utils::ansi_link;
8
-
9
7
  const DOC_SITE_HOST: &str = "https://ast-grep.github.io";
10
8
  const PATTERN_GUIDE: Option<&str> = Some("/guide/pattern-syntax.html");
11
9
  const CONFIG_GUIDE: Option<&str> = Some("/guide/rule-config.html");
@@ -43,6 +41,7 @@ pub enum ErrorContext {
43
41
  WriteFile(PathBuf),
44
42
  // Test
45
43
  TestFail(String),
44
+ TestCaseGlobFilter,
46
45
  // New
47
46
  ProjectAlreadyExist,
48
47
  ProjectNotExist,
@@ -63,7 +62,8 @@ impl ErrorContext {
63
62
  NoTestDirConfigured | NoUtilDirConfigured => 4,
64
63
  ReadConfiguration | ReadRule(_) | WalkRuleDir(_) | WriteFile(_) => 5,
65
64
  StdInIsNotInteractive => 6,
66
- ParseTest(_) | ParseRule(_) | ParseConfiguration | GlobPattern | ParsePattern => 8,
65
+ ParseTest(_) | ParseRule(_) | ParseConfiguration | GlobPattern | ParsePattern
66
+ | TestCaseGlobFilter => 8,
67
67
  ProjectAlreadyExist | FileAlreadyExist(_) => 17,
68
68
  InsufficientCLIArgument(_) => 22,
69
69
  OpenEditor | StartLanguageServer => 126,
@@ -181,6 +181,11 @@ impl ErrorMessage {
181
181
  "You can use ast-grep playground to debug your rules and test cases.",
182
182
  PLAYGROUND,
183
183
  ),
184
+ TestCaseGlobFilter => Self::new(
185
+ "Cannot parse the test case glob pattern.",
186
+ "The pattern provided to filter test cases to run is not a valid glob. Please refer to the doc and fix the error.",
187
+ CLI_USAGE,
188
+ ),
184
189
  ProjectAlreadyExist => Self::new(
185
190
  "ast-grep project already exists.",
186
191
  "You are already inside a sub-folder of an ast-grep project. Try finding sgconfig.yml in ancestor directory?",
@@ -231,6 +236,17 @@ pub fn exit_with_error(error: Error) -> Result<()> {
231
236
  Err(error)
232
237
  }
233
238
 
239
+ // use raw ansi escape code to render links in terminal. references:
240
+ // https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda
241
+ // https://github.com/zkat/miette/blob/c25676cb1f4266c2607836e6359f15b9cbd8637e/src/handlers/graphical.rs#L186
242
+ fn ansi_link(url: String) -> String {
243
+ format!(
244
+ "\u{1b}]8;;{}\u{1b}\\{}\u{1b}]8;;\u{1b}\\",
245
+ url,
246
+ ansi_term::Color::Cyan.italic().paint(&url)
247
+ )
248
+ }
249
+
234
250
  struct ErrorFormat<'a> {
235
251
  context: &'a ErrorContext,
236
252
  inner: &'a Error,
@@ -158,6 +158,9 @@ mod test_cli {
158
158
  ok("run -p test dir1 dir2 dir3"); // multiple paths
159
159
  ok("run -p testm -r restm -U"); // update all
160
160
  ok("run -p testm -r restm --update-all"); // update all
161
+ ok("run -p test --json compact"); // argument after --json should not be parsed as JsonStyle
162
+ ok("run -p test --json=pretty dir");
163
+ ok("run -p test --json dir"); // arg after --json should not be parsed as JsonStyle
161
164
  error("run test");
162
165
  error("run --debug-query test"); // missing lang
163
166
  error("run -r Test dir");
@@ -185,6 +188,8 @@ mod test_cli {
185
188
  error("scan -f gitlab");
186
189
  error("scan -f github -i");
187
190
  error("scan -f local");
191
+ error("scan --json=dir"); // wrong json flag
192
+ error("scan --json= not-pretty"); // wrong json flag
188
193
  }
189
194
 
190
195
  #[test]
@@ -65,11 +65,10 @@ impl NewArg {
65
65
  }
66
66
 
67
67
  fn choose_language(&self) -> Result<SgLang> {
68
- if self.yes {
69
- self
70
- .lang
71
- .map(Ok)
72
- .unwrap_or_else(|| Err(anyhow::anyhow!(EC::InsufficientCLIArgument("lang"))))
68
+ if let Some(lang) = self.lang {
69
+ Ok(lang)
70
+ } else if self.yes {
71
+ Err(anyhow::anyhow!(EC::InsufficientCLIArgument("lang")))
73
72
  } else {
74
73
  Ok(inquire::Select::new("Choose rule's language", SgLang::all_langs()).prompt()?)
75
74
  }
@@ -119,12 +118,12 @@ pub fn run_create_new(mut arg: NewArg) -> Result<()> {
119
118
  }
120
119
  }
121
120
 
121
+ // base_dir, config
122
122
  type FoundConfig = (PathBuf, AstGrepConfig);
123
123
 
124
124
  fn run_create_entity(entity: Entity, arg: NewArg) -> Result<()> {
125
125
  // check if we are under a project dir
126
- if let Some(mut found) = read_config_from_dir(&arg.base_dir)? {
127
- found.0.pop(); // remove sgconfig.yml from the path
126
+ if let Some(found) = read_config_from_dir(&arg.base_dir)? {
128
127
  return do_create_entity(entity, found, arg);
129
128
  }
130
129
  // check if we creating a project
@@ -148,10 +147,10 @@ fn do_create_entity(entity: Entity, found: FoundConfig, arg: NewArg) -> Result<(
148
147
 
149
148
  fn ask_entity_type(arg: NewArg) -> Result<()> {
150
149
  // 1. check if we are under a sgconfig.yml
151
- if let Some(sg_config) = read_config_from_dir(&arg.base_dir)? {
150
+ if let Some(found) = read_config_from_dir(&arg.base_dir)? {
152
151
  // 2. ask users what to create if yes
153
152
  let entity = arg.ask_entity_type()?;
154
- do_create_entity(entity, sg_config, arg)
153
+ do_create_entity(entity, found, arg)
155
154
  } else {
156
155
  // 3. ask users to provide project info if no sgconfig found
157
156
  print!("No sgconfig.yml found. ");
@@ -192,7 +191,7 @@ fn default_rule(id: &str, lang: SgLang) -> String {
192
191
  format!(
193
192
  r#"id: {id}
194
193
  message: Add your rule message here....
195
- severity: error # error, warning, hint, info
194
+ severity: error # error, warning, info, hint
196
195
  language: {lang}
197
196
  rule:
198
197
  pattern: Your Rule Pattern here...
@@ -202,8 +201,7 @@ rule:
202
201
  }
203
202
 
204
203
  fn create_new_rule(found: FoundConfig, arg: NewArg) -> Result<()> {
205
- let base_dir = found.0;
206
- let sg_config = found.1;
204
+ let (base_dir, sg_config) = found;
207
205
  let name = arg.ask_name("rule")?;
208
206
  let rule_dir = if sg_config.rule_dirs.len() > 1 {
209
207
  let dirs = sg_config.rule_dirs.iter().map(|p| p.display()).collect();
@@ -279,8 +277,7 @@ rule:
279
277
  }
280
278
 
281
279
  fn create_new_util(found: FoundConfig, arg: NewArg) -> Result<()> {
282
- let base_dir = found.0;
283
- let sg_config = found.1;
280
+ let (base_dir, sg_config) = found;
284
281
  let Some(utils) = sg_config.util_dirs else {
285
282
  return Err(anyhow::anyhow!(EC::NoUtilDirConfigured));
286
283
  };
@@ -339,6 +336,19 @@ mod test {
339
336
  Ok(())
340
337
  }
341
338
 
339
+ fn create_util(temp: &Path) -> Result<()> {
340
+ let arg = NewArg {
341
+ entity: Some(Entity::Util),
342
+ name: Some("test-utils".into()),
343
+ lang: Some(SupportLang::Rust.into()),
344
+ yes: true,
345
+ base_dir: temp.to_path_buf(),
346
+ };
347
+ run_create_new(arg).unwrap();
348
+ assert!(temp.join("utils/test-utils.yml").exists());
349
+ Ok(())
350
+ }
351
+
342
352
  #[test]
343
353
  fn test_create_new() -> Result<()> {
344
354
  let dir = TempDir::new("sgtest")?;
@@ -347,4 +357,13 @@ mod test {
347
357
  drop(dir); // drop at the end since temp dir clean up is done in Drop
348
358
  Ok(())
349
359
  }
360
+
361
+ #[test]
362
+ fn test_create_util() -> Result<()> {
363
+ let dir = TempDir::new("sgtest")?;
364
+ create_project(dir.path())?;
365
+ create_util(dir.path())?;
366
+ drop(dir); // drop at the end since temp dir clean up is done in Drop
367
+ Ok(())
368
+ }
350
369
  }
@@ -5,7 +5,7 @@ use clap::ValueEnum;
5
5
 
6
6
  use anyhow::Result;
7
7
  use ast_grep_core::{NodeMatch as SgNodeMatch, StrDoc};
8
- pub use codespan_reporting::{files::SimpleFile, term::ColorArg};
8
+ use codespan_reporting::files::SimpleFile;
9
9
  use std::io::{Stdout, Write};
10
10
  use std::sync::Mutex;
11
11