summaryrefslogtreecommitdiffstats
path: root/src/doc/reference/style-check
diff options
context:
space:
mode:
Diffstat (limited to 'src/doc/reference/style-check')
-rw-r--r--src/doc/reference/style-check/Cargo.lock62
-rw-r--r--src/doc/reference/style-check/Cargo.toml8
-rw-r--r--src/doc/reference/style-check/src/main.rs131
3 files changed, 201 insertions, 0 deletions
diff --git a/src/doc/reference/style-check/Cargo.lock b/src/doc/reference/style-check/Cargo.lock
new file mode 100644
index 000000000..1b6229001
--- /dev/null
+++ b/src/doc/reference/style-check/Cargo.lock
@@ -0,0 +1,62 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "bitflags"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
+
+[[package]]
+name = "getopts"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
+dependencies = [
+ "unicode-width",
+]
+
+[[package]]
+name = "memchr"
+version = "2.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
+
+[[package]]
+name = "pulldown-cmark"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8"
+dependencies = [
+ "bitflags",
+ "getopts",
+ "memchr",
+ "unicase",
+]
+
+[[package]]
+name = "style-check"
+version = "0.1.0"
+dependencies = [
+ "pulldown-cmark",
+]
+
+[[package]]
+name = "unicase"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
+dependencies = [
+ "version_check",
+]
+
+[[package]]
+name = "unicode-width"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
+
+[[package]]
+name = "version_check"
+version = "0.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
diff --git a/src/doc/reference/style-check/Cargo.toml b/src/doc/reference/style-check/Cargo.toml
new file mode 100644
index 000000000..d592f65d0
--- /dev/null
+++ b/src/doc/reference/style-check/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "style-check"
+version = "0.1.0"
+authors = ["steveklabnik <steve@steveklabnik.com>"]
+edition = "2021"
+
+[dependencies]
+pulldown-cmark = "0.8"
diff --git a/src/doc/reference/style-check/src/main.rs b/src/doc/reference/style-check/src/main.rs
new file mode 100644
index 000000000..2589cd620
--- /dev/null
+++ b/src/doc/reference/style-check/src/main.rs
@@ -0,0 +1,131 @@
+use std::env;
+use std::error::Error;
+use std::fs;
+use std::path::Path;
+
+macro_rules! style_error {
+ ($bad:expr, $path:expr, $($arg:tt)*) => {
+ *$bad = true;
+ eprint!("error in {}: ", $path.display());
+ eprintln!("{}", format_args!($($arg)*));
+ };
+}
+
+fn main() {
+ let arg = env::args().nth(1).unwrap_or_else(|| {
+ eprintln!("Please pass a src directory as the first argument");
+ std::process::exit(1);
+ });
+
+ let mut bad = false;
+ if let Err(e) = check_directory(&Path::new(&arg), &mut bad) {
+ eprintln!("error: {}", e);
+ std::process::exit(1);
+ }
+ if bad {
+ eprintln!("some style checks failed");
+ std::process::exit(1);
+ }
+ eprintln!("passed!");
+}
+
+fn check_directory(dir: &Path, bad: &mut bool) -> Result<(), Box<dyn Error>> {
+ for entry in fs::read_dir(dir)? {
+ let entry = entry?;
+ let path = entry.path();
+
+ if path.is_dir() {
+ check_directory(&path, bad)?;
+ continue;
+ }
+
+ if !matches!(
+ path.extension().and_then(|p| p.to_str()),
+ Some("md") | Some("html")
+ ) {
+ // This may be extended in the future if other file types are needed.
+ style_error!(bad, path, "expected only md or html in src");
+ }
+
+ let contents = fs::read_to_string(&path)?;
+ if contents.contains("#![feature") {
+ style_error!(bad, path, "#![feature] attributes are not allowed");
+ }
+ if contents.contains('\r') {
+ style_error!(
+ bad,
+ path,
+ "CR characters not allowed, must use LF line endings"
+ );
+ }
+ if contents.contains('\t') {
+ style_error!(bad, path, "tab characters not allowed, use spaces");
+ }
+ if !contents.ends_with('\n') {
+ style_error!(bad, path, "file must end with a newline");
+ }
+ for line in contents.lines() {
+ if line.ends_with(' ') {
+ style_error!(bad, path, "lines must not end with spaces");
+ }
+ }
+ cmark_check(&path, bad, &contents)?;
+ }
+ Ok(())
+}
+
+fn cmark_check(path: &Path, bad: &mut bool, contents: &str) -> Result<(), Box<dyn Error>> {
+ use pulldown_cmark::{BrokenLink, CodeBlockKind, Event, Options, Parser, Tag};
+
+ macro_rules! cmark_error {
+ ($bad:expr, $path:expr, $range:expr, $($arg:tt)*) => {
+ *$bad = true;
+ let lineno = contents[..$range.start].chars().filter(|&ch| ch == '\n').count() + 1;
+ eprint!("error in {} (line {}): ", $path.display(), lineno);
+ eprintln!("{}", format_args!($($arg)*));
+ }
+ }
+
+ let options = Options::all();
+ // Can't use `bad` because it would get captured in closure.
+ let mut link_err = false;
+ let mut cb = |link: BrokenLink<'_>| {
+ cmark_error!(
+ &mut link_err,
+ path,
+ link.span,
+ "broken {:?} link (reference `{}`)",
+ link.link_type,
+ link.reference
+ );
+ None
+ };
+ let parser = Parser::new_with_broken_link_callback(contents, options, Some(&mut cb));
+
+ for (event, range) in parser.into_offset_iter() {
+ match event {
+ Event::Start(Tag::CodeBlock(CodeBlockKind::Indented)) => {
+ cmark_error!(
+ bad,
+ path,
+ range,
+ "indented code blocks should use triple backtick-style \
+ with a language identifier"
+ );
+ }
+ Event::Start(Tag::CodeBlock(CodeBlockKind::Fenced(languages))) => {
+ if languages.is_empty() {
+ cmark_error!(
+ bad,
+ path,
+ range,
+ "code block should include an explicit language",
+ );
+ }
+ }
+ _ => {}
+ }
+ }
+ *bad |= link_err;
+ Ok(())
+}