-
Notifications
You must be signed in to change notification settings - Fork 29
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Lints to ensure link text for EIPs should match the EIP's number #99
base: master
Are you sure you want to change the base?
Changes from 1 commit
fd7cebb
011babb
2829f03
4930ed4
09d7de7
0df9027
cdfc4d0
8772403
04b0e07
47a8bbd
ad8e022
0da655d
680beea
1cbd715
eef80dd
550e0d2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,19 +7,19 @@ | |
use annotate_snippets::snippet::{Annotation, AnnotationType, Slice, Snippet}; | ||
|
||
use comrak::nodes::{Ast, NodeLink}; | ||
|
||
use crate::lints::{Context, Error, Lint}; | ||
use crate::tree::{self, Next, TraverseExt}; | ||
|
||
use regex::Regex; | ||
|
||
use serde::{Deserialize, Serialize}; | ||
|
||
use std::fmt::{Debug, Display}; | ||
|
||
#[derive(Debug, Serialize, Deserialize, Clone)] | ||
pub struct LinkEip<S>(pub S); | ||
|
||
impl<S> Lint for LinkEip<S> | ||
where | ||
S: Display + Debug + AsRef<str>, | ||
|
@@ -33,7 +33,10 @@ where | |
re, | ||
slug, | ||
link_depth: 0, | ||
current_link: Link { url: String::new(), text: String::new() }, | ||
current_link: Link { | ||
url: String::new(), | ||
text: String::new(), | ||
}, | ||
}; | ||
ctx.body().traverse().visit(&mut visitor)?; | ||
|
||
|
@@ -58,7 +61,10 @@ struct Visitor<'a, 'b, 'c> { | |
impl<'a, 'b, 'c> Visitor<'a, 'b, 'c> { | ||
fn extract_capture(&self, text: &str, re: &Regex, index: usize) -> Result<String, Error> { | ||
if let Some(captures) = re.captures(text) { | ||
Ok(captures.get(index).map(|m| m.as_str().to_string()).unwrap_or_default()) | ||
Ok(captures | ||
.get(index) | ||
.map(|m| m.as_str().to_string()) | ||
.unwrap_or_default()) | ||
} else { | ||
Ok(String::new()) | ||
} | ||
|
@@ -73,32 +79,45 @@ impl<'a, 'b, 'c> Visitor<'a, 'b, 'c> { | |
description | ||
} | ||
|
||
fn check(&self, ast: &Ast) -> Result<Next, Error> { | ||
fn check(&self, ast: &Ast) -> Result<Next, Error> { | ||
let url_eip_text = self.extract_capture(&self.current_link.url, &self.re, 1)?; | ||
let url_eip_number = self.extract_capture(&self.current_link.url, &self.re, 2)?; | ||
let url_section = self.extract_capture(&self.current_link.url, &self.re, 4)?; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
let dynamic_pattern = if url_section != "" { | ||
|
||
let dynamic_pattern = if url_section != "" { | ||
format!(r"^(EIP|ERC)-{}(\s*\S+)", regex::escape(&url_eip_number)) | ||
} else { | ||
format!(r"^(EIP|ERC)-{}$", regex::escape(&url_eip_number)) | ||
}; | ||
let text_re = Regex::new(&dynamic_pattern).map_err(Error::custom)?; | ||
|
||
if text_re.is_match(&self.current_link.text) { | ||
return Ok(Next::TraverseChildren); | ||
}; | ||
|
||
let expected = if url_section != "" { | ||
let section_description = Visitor::transform_section_description(&url_section); | ||
format!("[{}{}: {}]({})", url_eip_text.to_uppercase(), url_eip_number, section_description, &self.current_link.url) | ||
format!( | ||
"[{}{}: {}]({})", | ||
url_eip_text.to_uppercase(), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Weirdly enough, ERCs are still stored in files named like The correct way to solve this (reading the linked file) won't work for reasons outside
|
||
url_eip_number, | ||
section_description, | ||
&self.current_link.url | ||
) | ||
} else { | ||
format!("[{}{}]({})", url_eip_text.to_uppercase(), url_eip_number, &self.current_link.url) | ||
format!( | ||
"[{}{}]({})", | ||
url_eip_text.to_uppercase(), | ||
url_eip_number, | ||
&self.current_link.url | ||
) | ||
}; | ||
|
||
let footer_label = format!("use `{}` instead", expected); | ||
|
||
let source = self.ctx.source_for_text(ast.sourcepos.start.line, &self.current_link.text); | ||
let source = self | ||
.ctx | ||
.source_for_text(ast.sourcepos.start.line, &self.current_link.text); | ||
self.ctx.report(Snippet { | ||
title: Some(Annotation { | ||
annotation_type: self.ctx.annotation_type(), | ||
|
@@ -123,15 +142,18 @@ impl<'a, 'b, 'c> Visitor<'a, 'b, 'c> { | |
Ok(Next::TraverseChildren) | ||
} | ||
} | ||
|
||
impl<'a, 'b, 'c> tree::Visitor for Visitor<'a, 'b, 'c> { | ||
type Error = Error; | ||
|
||
fn enter_link(&mut self, _: &Ast, link: &NodeLink,) -> Result<Next, Self::Error> { | ||
if self.re.is_match(&link.url) { | ||
self.current_link = Link { url: link.url.to_owned(), text: String::new() }; | ||
self.link_depth += 1; | ||
} | ||
fn enter_link(&mut self, _: &Ast, link: &NodeLink) -> Result<Next, Self::Error> { | ||
if self.re.is_match(&link.url) { | ||
self.current_link = Link { | ||
url: link.url.to_owned(), | ||
text: String::new(), | ||
}; | ||
self.link_depth += 1; | ||
} | ||
Ok(Next::TraverseChildren) | ||
} | ||
|
||
|
@@ -145,8 +167,8 @@ impl<'a, 'b, 'c> tree::Visitor for Visitor<'a, 'b, 'c> { | |
fn enter_text(&mut self, ast: &Ast, txt: &str) -> Result<Next, Self::Error> { | ||
if self.link_depth > 0 { | ||
self.current_link.text = txt.to_owned(); | ||
self.check(ast)?; | ||
self.check(ast)?; | ||
} | ||
Ok(Next::SkipChildren) | ||
Ok(Next::SkipChildren) | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd say that if the regular expression has the wrong number of capture groups, we should inform the user instead of silently returning the empty string.
You can ignore my previous comment about simplifying, and use
Error::custom
and something like: