tidy/extra_checks/
rustdoc_js.rs

1//! Tidy check to ensure that rustdoc templates didn't forget a `{# #}` to strip extra whitespace
2//! characters.
3
4use std::ffi::OsStr;
5use std::io;
6use std::path::{Path, PathBuf};
7use std::process::{Child, Command};
8
9use build_helper::npm;
10use ignore::DirEntry;
11
12use crate::walk::walk_no_read;
13
14fn node_module_bin(outdir: &Path, name: &str) -> PathBuf {
15    outdir.join("node_modules/.bin").join(name)
16}
17
18fn spawn_cmd(cmd: &mut Command) -> Result<Child, io::Error> {
19    cmd.spawn().map_err(|err| {
20        eprintln!("unable to run {cmd:?} due to {err:?}");
21        err
22    })
23}
24
25/// install all js dependencies from package.json.
26pub(super) fn npm_install(root_path: &Path, outdir: &Path, npm: &Path) -> Result<(), super::Error> {
27    npm::install(root_path, outdir, npm)?;
28    Ok(())
29}
30
31fn rustdoc_js_files(librustdoc_path: &Path) -> Vec<PathBuf> {
32    let mut files = Vec::new();
33    walk_no_read(
34        &[&librustdoc_path.join("html/static/js")],
35        |path, is_dir| is_dir || path.extension().is_none_or(|ext| ext != OsStr::new("js")),
36        &mut |path: &DirEntry| {
37            files.push(path.path().into());
38        },
39    );
40    return files;
41}
42
43fn run_eslint(outdir: &Path, args: &[PathBuf], config_folder: PathBuf) -> Result<(), super::Error> {
44    let mut child = spawn_cmd(
45        Command::new(node_module_bin(outdir, "eslint"))
46            .arg("-c")
47            .arg(config_folder.join(".eslintrc.js"))
48            .args(args),
49    )?;
50    match child.wait() {
51        Ok(exit_status) => {
52            if exit_status.success() {
53                return Ok(());
54            }
55            Err(super::Error::FailedCheck("eslint command failed"))
56        }
57        Err(error) => Err(super::Error::Generic(format!("eslint command failed: {error:?}"))),
58    }
59}
60
61pub(super) fn lint(
62    outdir: &Path,
63    librustdoc_path: &Path,
64    tools_path: &Path,
65) -> Result<(), super::Error> {
66    let files_to_check = rustdoc_js_files(librustdoc_path);
67    println!("Running eslint on rustdoc JS files");
68    run_eslint(outdir, &files_to_check, librustdoc_path.join("html/static"))?;
69
70    run_eslint(outdir, &[tools_path.join("rustdoc-js/tester.js")], tools_path.join("rustdoc-js"))?;
71    run_eslint(
72        outdir,
73        &[tools_path.join("rustdoc-gui/tester.js")],
74        tools_path.join("rustdoc-gui"),
75    )?;
76    Ok(())
77}
78
79pub(super) fn typecheck(outdir: &Path, librustdoc_path: &Path) -> Result<(), super::Error> {
80    // use npx to ensure correct version
81    let mut child = spawn_cmd(
82        Command::new(node_module_bin(outdir, "tsc"))
83            .arg("-p")
84            .arg(librustdoc_path.join("html/static/js/tsconfig.json")),
85    )?;
86    match child.wait() {
87        Ok(exit_status) => {
88            if exit_status.success() {
89                return Ok(());
90            }
91            Err(super::Error::FailedCheck("tsc command failed"))
92        }
93        Err(error) => Err(super::Error::Generic(format!("tsc command failed: {error:?}"))),
94    }
95}
96
97pub(super) fn es_check(outdir: &Path, librustdoc_path: &Path) -> Result<(), super::Error> {
98    let files_to_check = rustdoc_js_files(librustdoc_path);
99    let mut cmd = Command::new(node_module_bin(outdir, "es-check"));
100    cmd.arg("es2019");
101    for f in files_to_check {
102        cmd.arg(f);
103    }
104    match spawn_cmd(&mut cmd)?.wait() {
105        Ok(exit_status) => {
106            if exit_status.success() {
107                return Ok(());
108            }
109            Err(super::Error::FailedCheck("es-check command failed"))
110        }
111        Err(error) => Err(super::Error::Generic(format!("es-check command failed: {error:?}"))),
112    }
113}