Skip to content

Commit

Permalink
FEAT: Add lint preventing EIP references in backticks (#93)
Browse files Browse the repository at this point in the history
* FEAT: Add lint preventing EIP references in backticks

* WIP:code updates

* Delete .vscode/launch.json

* update code for the lint-backticks and tests

* updates

* WIP: test passed valid_code_in_backticks

* cargo fmt

* Remove printlns

* Polish up no_backticks lint

---------

Co-authored-by: Sam Wilson <[email protected]>
Co-authored-by: Vickish <[email protected]>
Co-authored-by: Sam Wilson <[email protected]>
  • Loading branch information
4 people authored Aug 23, 2024
1 parent 97e667a commit 411b101
Show file tree
Hide file tree
Showing 10 changed files with 223 additions and 2 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
/target
.vscode
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,14 @@ error[preamble-order]: preamble header `description` must come after `title`
| `markdown-json-cite` | All `csl-json` code blocks adhere to the correct schema. |
| `markdown-link-first` | First mention of an EIP must be a link. |
| `markdown-link-status` | EIPs linked in the body have statuses further along than the current proposal. |
| `markdown-no-backticks` | No proposals are referenced inside backticks (eg. \`EIP-1234\`). |
| `markdown-order-section` | There are no extra sections and the sections are in the correct order. |
| `markdown-re-eip-dash` | Other EIPs are referenced using EIP-X, not EIPX or EIP X. |
| `markdown-re-erc-dash` | Other ERCs are referenced using ERC-X, not ERCX or ERC X. |
| `markdown-refs` | ERCs are referenced using ERC-X, while other proposals use EIP-X. |
| `markdown-rel-links` | All URLs in the page are relative. |
| `markdown-req-section` | Required sections are present in the body of the proposal. |
| `markdown-headings-space` | Headers have a space after the leading '#' characters |
| `markdown-headings-space` | Headers have a space after the leading '#' characters |
| `preamble-author` | The author header is correctly formatted, and there is at least one GitHub user listed. |
| `preamble-date-created` | The `created` header is a date. |
| `preamble-date-last-call-deadline` | The `last-call-deadline` header is a date. |
Expand Down
43 changes: 43 additions & 0 deletions docs/markdown-no-backticks/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>markdown-no-backticks</title>
<link rel="stylesheet" href="../main.css" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body>
<article>
<h1><code>markdown-no-backticks</code></h1>
<p>EIP references should not be in backticks.</p>

<section>
<h2>Examples</h2>

<pre>
error[markdown-no-backticks]: EIP references should not be in backticks
--> input.md
|
5 | `EIP-1234`
|
= info: the pattern in question: `EIP-[0-9]+`</pre
>
</section>
<section>
<h2>Explanation</h2>

<p>
<code>markdown-no-backticks</code> ensures that authors do not
circumvent EIP link requirements by putting EIP references in
backticks.
</p>

<p>
While references like <code>`ERC20`</code> or
<code>`IERC7777`</code> are valid as interface names,
<code>`EIP-7777`</code> should be rejected since it is not valid code.
</p>
</section>
</article>
</body>
</html>
6 changes: 6 additions & 0 deletions eipw-lint/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,12 @@ pub fn default_lints_enum() -> impl Iterator<Item = (&'static str, DefaultLint<&
pattern: markdown::LinkFirst(r"(?i)(?:eip|erc)-[0-9]+"),
}
),
(
"markdown-no-backticks",
MarkdownNoBackticks {
pattern: markdown::NoBackticks(r"(?i)(eip|erc)-[0-9]+"),
}
),
("markdown-rel-links", MarkdownRelativeLinks(markdown::RelativeLinks {
exceptions: vec![
"^https://(www\\.)?github\\.com/ethereum/consensus-specs/blob/[a-f0-9]{40}/.+$",
Expand Down
8 changes: 8 additions & 0 deletions eipw-lint/src/lints/known_lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ pub enum DefaultLint<S> {
MarkdownLinkFirst {
pattern: markdown::LinkFirst<S>,
},
MarkdownNoBackticks {
pattern: markdown::NoBackticks<S>,
},
MarkdownLinkStatus(markdown::LinkStatus<S>),
MarkdownProposalRef(markdown::ProposalRef<S>),
MarkdownRegex(markdown::Regex<S>),
Expand Down Expand Up @@ -103,6 +106,7 @@ where
Self::MarkdownHtmlComments(l) => Box::new(l),
Self::MarkdownJsonSchema(l) => Box::new(l),
Self::MarkdownLinkFirst { pattern } => Box::new(pattern),
Self::MarkdownNoBackticks { pattern } => Box::new(pattern),
Self::MarkdownLinkStatus(l) => Box::new(l),
Self::MarkdownProposalRef(l) => Box::new(l),
Self::MarkdownRegex(l) => Box::new(l),
Expand Down Expand Up @@ -142,6 +146,7 @@ where
Self::MarkdownHtmlComments(l) => l,
Self::MarkdownJsonSchema(l) => l,
Self::MarkdownLinkFirst { pattern } => pattern,
Self::MarkdownNoBackticks { pattern } => pattern,
Self::MarkdownLinkStatus(l) => l,
Self::MarkdownProposalRef(l) => l,
Self::MarkdownRegex(l) => l,
Expand Down Expand Up @@ -260,6 +265,9 @@ where
Self::MarkdownLinkFirst { pattern } => DefaultLint::MarkdownLinkFirst {
pattern: markdown::LinkFirst(pattern.0.as_ref()),
},
Self::MarkdownNoBackticks { pattern } => DefaultLint::MarkdownNoBackticks {
pattern: markdown::NoBackticks(pattern.0.as_ref()),
},
Self::MarkdownLinkStatus(l) => DefaultLint::MarkdownLinkStatus(markdown::LinkStatus {
prefix: l.prefix.as_ref(),
suffix: l.suffix.as_ref(),
Expand Down
2 changes: 2 additions & 0 deletions eipw-lint/src/lints/markdown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub mod html_comments;
pub mod json_schema;
pub mod link_first;
pub mod link_status;
pub mod no_backticks;
pub mod proposal_ref;
pub mod regex;
pub mod relative_links;
Expand All @@ -20,6 +21,7 @@ pub use self::html_comments::HtmlComments;
pub use self::json_schema::JsonSchema;
pub use self::link_first::LinkFirst;
pub use self::link_status::LinkStatus;
pub use self::no_backticks::NoBackticks;
pub use self::proposal_ref::ProposalRef;
pub use self::regex::Regex;
pub use self::relative_links::RelativeLinks;
Expand Down
89 changes: 89 additions & 0 deletions eipw-lint/src/lints/markdown/no_backticks.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

use annotate_snippets::snippet::{Annotation, AnnotationType, Slice, Snippet};

use comrak::nodes::{Ast, NodeCode};

use crate::lints::{Context, Error, Lint};
use crate::tree::{self, Next, TraverseExt};

use ::regex::Regex;

use serde::{Deserialize, Serialize};

// use std::collections::HashSet;
use std::fmt::{Debug, Display};

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
#[serde(transparent)]
pub struct NoBackticks<S>(pub S);

impl<S> Lint for NoBackticks<S>
where
S: Display + Debug + AsRef<str>,
{
fn lint<'a>(&self, slug: &'a str, ctx: &Context<'a, '_>) -> Result<(), Error> {
let pattern = self.0.as_ref();
let re = Regex::new(pattern).map_err(Error::custom)?;
let mut visitor = Visitor {
ctx,
re,
pattern,
slug,
};
ctx.body().traverse().visit(&mut visitor)?;
Ok(())
}
}

struct Visitor<'a, 'b, 'c> {
ctx: &'c Context<'a, 'b>,
re: Regex,
pattern: &'c str,
slug: &'c str,
}

impl<'a, 'b, 'c> Visitor<'a, 'b, 'c> {
fn check(&mut self, ast: &Ast, text: &str) -> Result<Next, Error> {
if !self.re.is_match(text) {
return Ok(Next::TraverseChildren);
}

let footer_label = format!("the pattern in question: `{}`", self.pattern);
let source = self.ctx.source_for_text(ast.sourcepos.start.line, text);
self.ctx.report(Snippet {
opt: Default::default(),
title: Some(Annotation {
annotation_type: self.ctx.annotation_type(),
id: Some(self.slug),
label: Some("EIP references should not be in backticks"),
}),
slices: vec![Slice {
fold: false,
line_start: ast.sourcepos.start.line,
origin: self.ctx.origin(),
source: &source,
annotations: vec![],
}],
footer: vec![Annotation {
annotation_type: AnnotationType::Info,
id: None,
label: Some(&footer_label),
}],
})?;

Ok(Next::SkipChildren)
}
}

impl<'a, 'b, 'c> tree::Visitor for Visitor<'a, 'b, 'c> {
type Error = Error;

fn enter_code(&mut self, ast: &Ast, code: &NodeCode) -> Result<Next, Self::Error> {
self.check(ast, &code.literal)
}
}
6 changes: 6 additions & 0 deletions eipw-lint/tests/eipv/markdown-malformed-eip/expected.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
error[markdown-no-backticks]: EIP references should not be in backticks
--> input.md
|
18 | This is the motivation for the EIP, which extends `ERC-721`.
|
= info: the pattern in question: `(?i)(eip|erc)-[0-9]+`
error[markdown-re-eip-dash]: proposals must be referenced with the form `EIP-N` (not `EIPN` or `EIP N`)
--> input.md
|
Expand Down
2 changes: 1 addition & 1 deletion eipw-lint/tests/eipv/markdown-proposal-ref/input.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ These are the backwards compatibility concerns for the `EIP1234`.
These are the test cases for the EIP.

## Reference Implementation
This is the implementation for the EIP, but `EIP-721` should be allowed.
This is the implementation for the EIP, but `EIP721` should be allowed.

## Security Considerations
These are the security considerations for the EIP.
Expand Down
65 changes: 65 additions & 0 deletions eipw-lint/tests/lint_markdown_no_backticks.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

use eipw_lint::lints::markdown::NoBackticks;
use eipw_lint::reporters::Text;
use eipw_lint::Linter;

#[tokio::test]
async fn eip_in_backticks() {
let src = r#"---
header: value1
---
hello
`EIP-1234`
"#;

let linter = Linter::<Text<String>>::default()
.clear_lints()
.deny("markdown-no-backticks", NoBackticks(r"EIP-[0-9]+"));

let reports = linter
.check_slice(None, src)
.run()
.await
.unwrap()
.into_inner();

assert_eq!(
reports,
r#"error[markdown-no-backticks]: EIP references should not be in backticks
|
7 | `EIP-1234`
|
= info: the pattern in question: `EIP-[0-9]+`
"#
);
}

#[tokio::test]
async fn valid_code_in_backticks() {
let src = r#"---
header: value1
---
hello
`ERC20` and `IERC7777`
"#;

let reports = Linter::<Text<String>>::default()
.clear_lints()
.deny("markdown-no-backticks", NoBackticks(r"EIP-[0-9]+"))
.check_slice(None, src)
.run()
.await
.unwrap()
.into_inner();

assert_eq!(reports, "");
}

0 comments on commit 411b101

Please sign in to comment.