mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 14:02:21 -04:00
Add links.rs
for checking and building links
This commit is contained in:
parent
b61e90e995
commit
80264c3b56
4 changed files with 409 additions and 2 deletions
286
Cargo.lock
generated
286
Cargo.lock
generated
|
@ -72,6 +72,7 @@ dependencies = [
|
|||
"intl-memoizer",
|
||||
"itertools 0.10.1",
|
||||
"lazy_static",
|
||||
"linkcheck",
|
||||
"nom 7.0.0-alpha1",
|
||||
"num-integer",
|
||||
"num_enum",
|
||||
|
@ -84,7 +85,7 @@ dependencies = [
|
|||
"pulldown-cmark",
|
||||
"rand 0.8.4",
|
||||
"regex",
|
||||
"reqwest",
|
||||
"reqwest 0.11.3",
|
||||
"rusqlite",
|
||||
"scopeguard",
|
||||
"serde",
|
||||
|
@ -337,12 +338,39 @@ dependencies = [
|
|||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codespan"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3362992a0d9f1dd7c3d0e89e0ab2bb540b7a95fea8cd798090e758fda2899b5e"
|
||||
dependencies = [
|
||||
"codespan-reporting",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codespan-reporting"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"termcolor",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "constant_time_eq"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
|
||||
|
||||
[[package]]
|
||||
name = "convert_case"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.9.1"
|
||||
|
@ -398,6 +426,33 @@ dependencies = [
|
|||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cssparser"
|
||||
version = "0.27.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "754b69d351cdc2d8ee09ae203db831e005560fc6030da058f86ad60c92a9cb0a"
|
||||
dependencies = [
|
||||
"cssparser-macros",
|
||||
"dtoa-short",
|
||||
"itoa",
|
||||
"matches",
|
||||
"phf 0.8.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"smallvec",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cssparser-macros"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dfae75de57f2b2e85e8768c3ea840fd159c8f33e2b6522c7835b7abac81be16e"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ctor"
|
||||
version = "0.1.20"
|
||||
|
@ -419,6 +474,19 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_more"
|
||||
version = "0.99.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40eebddd2156ce1bb37b20bbe5151340a31828b1f2d22ba4141f3531710e38df"
|
||||
dependencies = [
|
||||
"convert_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustc_version",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.9.0"
|
||||
|
@ -449,6 +517,27 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dtoa"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0"
|
||||
|
||||
[[package]]
|
||||
name = "dtoa-short"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bde03329ae10e79ede66c9ce4dc930aa8599043b0743008548680f25b91502d6"
|
||||
dependencies = [
|
||||
"dtoa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dunce"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "453440c271cf5577fd2a40e4942540cb7d0d2f85e27c8d07dd0023c925a67541"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.6.1"
|
||||
|
@ -692,6 +781,15 @@ dependencies = [
|
|||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fxhash"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.4"
|
||||
|
@ -1080,6 +1178,18 @@ dependencies = [
|
|||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kuchiki"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ea8e9c6e031377cff82ee3001dc8026cdf431ed4e2e6b51f98ab8c73484a358"
|
||||
dependencies = [
|
||||
"cssparser",
|
||||
"html5ever",
|
||||
"matches",
|
||||
"selectors",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
|
@ -1116,6 +1226,37 @@ dependencies = [
|
|||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linkcheck"
|
||||
version = "0.4.1-alpha.0"
|
||||
source = "git+https://github.com/ankitects/linkcheck.git?rev=2f20798ce521cc594d510d4e417e76d5eac04d4b#2f20798ce521cc594d510d4e417e76d5eac04d4b"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"codespan",
|
||||
"dunce",
|
||||
"futures",
|
||||
"http",
|
||||
"kuchiki",
|
||||
"lazy_static",
|
||||
"linkify",
|
||||
"log",
|
||||
"pulldown-cmark",
|
||||
"regex",
|
||||
"reqwest 0.11.4",
|
||||
"serde",
|
||||
"thiserror",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linkify"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78d59d732ba6d7eeefc418aab8057dc8e3da4374bd5802ffa95bebc04b4d1dfb"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.4"
|
||||
|
@ -1482,6 +1623,15 @@ version = "2.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
|
||||
|
||||
[[package]]
|
||||
name = "pest"
|
||||
version = "2.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53"
|
||||
dependencies = [
|
||||
"ucd-trie",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "petgraph"
|
||||
version = "0.5.1"
|
||||
|
@ -1498,7 +1648,9 @@ version = "0.8.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12"
|
||||
dependencies = [
|
||||
"phf_macros 0.8.0",
|
||||
"phf_shared 0.8.0",
|
||||
"proc-macro-hack",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1507,7 +1659,7 @@ version = "0.9.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2ac8b67553a7ca9457ce0e526948cad581819238f4a9d1ea74545851fa24f37"
|
||||
dependencies = [
|
||||
"phf_macros",
|
||||
"phf_macros 0.9.0",
|
||||
"phf_shared 0.9.0",
|
||||
"proc-macro-hack",
|
||||
]
|
||||
|
@ -1542,6 +1694,20 @@ dependencies = [
|
|||
"rand 0.8.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_macros"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f6fde18ff429ffc8fe78e2bf7f8b7a5a5a6e2a8b58bc5a9ac69198bbda9189c"
|
||||
dependencies = [
|
||||
"phf_generator 0.8.0",
|
||||
"phf_shared 0.8.0",
|
||||
"proc-macro-hack",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_macros"
|
||||
version = "0.9.0"
|
||||
|
@ -1973,6 +2139,40 @@ dependencies = [
|
|||
"winreg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.11.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "246e9f61b9bb77df069a947682be06e31ac43ea37862e244a69f177694ea6d22"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bytes",
|
||||
"encoding_rs",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"hyper",
|
||||
"hyper-tls",
|
||||
"ipnet",
|
||||
"js-sys",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"mime",
|
||||
"native-tls",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"serde",
|
||||
"serde_urlencoded",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
"url",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
"winreg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.16.20"
|
||||
|
@ -2017,6 +2217,15 @@ version = "1.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee"
|
||||
dependencies = [
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.19.1"
|
||||
|
@ -2097,6 +2306,44 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "selectors"
|
||||
version = "0.22.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df320f1889ac4ba6bc0cdc9c9af7af4bd64bb927bccdf32d81140dc1f9be12fe"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cssparser",
|
||||
"derive_more",
|
||||
"fxhash",
|
||||
"log",
|
||||
"matches",
|
||||
"phf 0.8.0",
|
||||
"phf_codegen",
|
||||
"precomputed-hash",
|
||||
"servo_arc",
|
||||
"smallvec",
|
||||
"thin-slice",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6"
|
||||
dependencies = [
|
||||
"semver-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver-parser"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7"
|
||||
dependencies = [
|
||||
"pest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.126"
|
||||
|
@ -2183,6 +2430,16 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "servo_arc"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d98238b800e0d1576d8b6e3de32827c2d74bee68bb97748dcf5071fb53965432"
|
||||
dependencies = [
|
||||
"nodrop",
|
||||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha1"
|
||||
version = "0.6.0"
|
||||
|
@ -2422,6 +2679,12 @@ dependencies = [
|
|||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thin-slice"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c"
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.25"
|
||||
|
@ -2496,6 +2759,7 @@ dependencies = [
|
|||
"mio",
|
||||
"num_cpus",
|
||||
"pin-project-lite",
|
||||
"tokio-macros",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
|
@ -2508,6 +2772,17 @@ dependencies = [
|
|||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54473be61f4ebe4efd09cec9bd5d16fa51d70ea0192213d754d2d500457db110"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-native-tls"
|
||||
version = "0.3.0"
|
||||
|
@ -2611,6 +2886,12 @@ version = "1.13.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06"
|
||||
|
||||
[[package]]
|
||||
name = "ucd-trie"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
|
||||
|
||||
[[package]]
|
||||
name = "unic-char-property"
|
||||
version = "0.9.0"
|
||||
|
@ -2763,6 +3044,7 @@ dependencies = [
|
|||
"idna",
|
||||
"matches",
|
||||
"percent-encoding",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -18,6 +18,8 @@ prost-build = "0.7.0"
|
|||
|
||||
[dev-dependencies]
|
||||
env_logger = "0.8.4"
|
||||
linkcheck = { git = "https://github.com/ankitects/linkcheck.git", rev = "2f20798ce521cc594d510d4e417e76d5eac04d4b" }
|
||||
tokio = { version = "*", features = ["macros"] }
|
||||
|
||||
[dependencies]
|
||||
# pinned as any changes could invalidate sqlite indexes
|
||||
|
|
|
@ -18,6 +18,7 @@ pub mod error;
|
|||
pub mod findreplace;
|
||||
pub mod i18n;
|
||||
pub mod latex;
|
||||
pub mod links;
|
||||
pub mod log;
|
||||
mod markdown;
|
||||
pub mod media;
|
||||
|
|
122
rslib/src/links.rs
Normal file
122
rslib/src/links.rs
Normal file
|
@ -0,0 +1,122 @@
|
|||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
use strum::{Display, EnumIter, EnumString};
|
||||
|
||||
static HELP_SITE: &'static str = "https://docs.ankiweb.net/";
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Copy, Display, EnumIter, EnumString)]
|
||||
pub enum HelpPage {
|
||||
#[strum(serialize = "getting-started#note-types")]
|
||||
Notetype,
|
||||
#[strum(serialize = "browsing")]
|
||||
Browsing,
|
||||
#[strum(serialize = "browsing#find-and-replace")]
|
||||
BrowsingFindAndReplace,
|
||||
#[strum(serialize = "browsing#notes")]
|
||||
BrowsingNotesMenu,
|
||||
#[strum(serialize = "studying#keyboard-shortcuts")]
|
||||
KeyboardShortcuts,
|
||||
#[strum(serialize = "editing")]
|
||||
Editing,
|
||||
#[strum(serialize = "editing#adding-cards-and-notes")]
|
||||
AddingCardAndNote,
|
||||
#[strum(serialize = "editing#adding-a-note-type")]
|
||||
AddingNotetype,
|
||||
#[strum(serialize = "math#latex")]
|
||||
Latex,
|
||||
#[strum(serialize = "preferences")]
|
||||
Preferences,
|
||||
#[strum(serialize = "")]
|
||||
Index,
|
||||
#[strum(serialize = "templates/intro")]
|
||||
Templates,
|
||||
#[strum(serialize = "filtered-decks")]
|
||||
FilteredDeck,
|
||||
#[strum(serialize = "importing")]
|
||||
Importing,
|
||||
#[strum(serialize = "editing#customizing-fields")]
|
||||
CustomizingFields,
|
||||
#[strum(serialize = "deck-options")]
|
||||
DeckOptions,
|
||||
#[strum(serialize = "editing#features")]
|
||||
EditingFeatures,
|
||||
}
|
||||
|
||||
pub fn help_page_link(page: HelpPage) -> String {
|
||||
format!("{}{}", HELP_SITE, page)
|
||||
}
|
||||
|
||||
pub fn help_page_link_from_str(page: &str) -> String {
|
||||
format!("{}{}", HELP_SITE, page)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
use futures::StreamExt;
|
||||
use itertools::Itertools;
|
||||
use linkcheck::{
|
||||
validation::{check_web, Context, Reason},
|
||||
BasicContext,
|
||||
};
|
||||
use reqwest::Url;
|
||||
use std::iter;
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
/// Aggregates [`Outcome`]s by collecting the error messages of the invalid ones.
|
||||
#[derive(Default)]
|
||||
struct Outcomes(Vec<String>);
|
||||
|
||||
enum Outcome {
|
||||
Valid,
|
||||
Invalid(String),
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn check_links() {
|
||||
let ctx = BasicContext::default();
|
||||
let result = futures::stream::iter(HelpPage::iter())
|
||||
.map(|page| check_page(page, &ctx))
|
||||
.buffer_unordered(ctx.concurrency())
|
||||
.collect::<Outcomes>()
|
||||
.await;
|
||||
if result.0.len() > 0 {
|
||||
panic!(result.message());
|
||||
}
|
||||
}
|
||||
|
||||
async fn check_page(page: HelpPage, ctx: &BasicContext) -> Outcome {
|
||||
match Url::parse(&help_page_link(page)) {
|
||||
Ok(url) => match check_web(&url, ctx).await {
|
||||
Ok(()) => Outcome::Valid,
|
||||
Err(Reason::Dom) => {
|
||||
Outcome::Invalid(format!("'{}' not found on '{}'", page, HELP_SITE))
|
||||
}
|
||||
Err(Reason::Web(err)) => Outcome::Invalid(err.to_string()),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
Err(err) => Outcome::Invalid(err.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
impl Extend<Outcome> for Outcomes {
|
||||
fn extend<T: IntoIterator<Item = Outcome>>(&mut self, items: T) {
|
||||
for outcome in items {
|
||||
match outcome {
|
||||
Outcome::Valid => (),
|
||||
Outcome::Invalid(err) => self.0.push(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Outcomes {
|
||||
fn message(&self) -> String {
|
||||
iter::once(&format!("{} links could not be validated:", self.0.len()))
|
||||
.chain(self.0.iter())
|
||||
.join("\n - ")
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue