Skip to main content

ast_grep_config/
rewriter.rs

1use ast_grep_core::language::Language;
2use schemars::JsonSchema;
3use serde::{Deserialize, Serialize};
4use std::collections::HashSet;
5use thiserror::Error;
6
7use crate::check_var::check_rewriter_fix;
8use crate::fixer::{Fixer, FixerError, SerializableFixer};
9use crate::rule::DeserializeEnv;
10use crate::{RuleCore, RuleCoreError, SerializableRuleCore};
11
12pub struct Rewriter {
13  pub matcher: RuleCore,
14  pub fixer: Vec<Fixer>,
15}
16#[derive(Debug, Error)]
17#[error("Rewriter `{id}` has invalid configuration.")]
18pub struct RewriterError {
19  pub id: String,
20  #[source]
21  pub reason: RewriterErrorReason,
22}
23
24#[derive(Debug, Error)]
25pub enum RewriterErrorReason {
26  #[error(transparent)]
27  Core(#[from] RuleCoreError),
28  #[error("Rewriter rule must have `fix`.")]
29  NoFixInRewriter,
30  #[error("`fix` pattern is invalid.")]
31  Fixer(#[from] FixerError),
32}
33
34#[derive(Serialize, Deserialize, Clone, JsonSchema)]
35pub struct SerializableRewriter {
36  /// Unique, descriptive identifier, e.g., no-unused-variable
37  pub id: String,
38  /// A pattern string or a FixConfig object to auto fix the issue.
39  /// It can reference metavariables appeared in rule.
40  /// See details in fix [object reference](https://ast-grep.github.io/reference/yaml/fix.html#fixconfig).
41  pub fix: SerializableFixer,
42  #[serde(flatten)]
43  pub core: SerializableRuleCore,
44}
45
46impl SerializableRewriter {
47  pub fn try_parse_rewriter<L: Language>(
48    &self,
49    upper_vars: &HashSet<&str>,
50    env: &DeserializeEnv<L>,
51  ) -> Result<Rewriter, RewriterError> {
52    let attach_id = |e| RewriterError {
53      id: self.id.clone(),
54      reason: e,
55    };
56    let rewriter = self
57      .core
58      .get_matcher(env.clone())
59      .map_err(|e| attach_id(e.into()))?;
60    let fixer =
61      Fixer::parse(&self.fix, env, &self.core.transform).map_err(|e| attach_id(e.into()))?;
62    if fixer.is_empty() {
63      return Err(attach_id(RewriterErrorReason::NoFixInRewriter));
64    }
65    check_rewriter_fix(&rewriter, &fixer, upper_vars).map_err(|e| attach_id(e.into()))?;
66    Ok(Rewriter {
67      matcher: rewriter,
68      fixer,
69    })
70  }
71}