summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDaniel Silverstone <dsilvers@digital-scurf.org>2023-06-10 10:31:54 +0100
committerDaniel Silverstone <dsilvers@digital-scurf.org>2023-06-10 10:31:54 +0100
commit07c0e5d66920d4102f29245b0d96e725275271a6 (patch)
treeadce16c2f9a1aae6dc46c41c4208bfa4868d158a /src
parent5d6978497c7f875172a1907a203500e8a185bac4 (diff)
downloadsubplot-07c0e5d66920d4102f29245b0d96e725275271a6.tar.gz
feat: Warn when named codeblocks lack classes
To both improve debugability when writing scenarios, and also to protect against future incompatibilities which might occur if we add more classes which are appropriate for named code blocks, we require that named blocks have one of `file` or `example` as classes or else we warn. Signed-off-by: Daniel Silverstone <dsilvers@digital-scurf.org>
Diffstat (limited to 'src')
-rw-r--r--src/bin/subplot.rs1
-rw-r--r--src/doc.rs38
-rw-r--r--src/error.rs4
-rw-r--r--src/md.rs7
4 files changed, 49 insertions, 1 deletions
diff --git a/src/bin/subplot.rs b/src/bin/subplot.rs
index b23f858..ca1ef5d 100644
--- a/src/bin/subplot.rs
+++ b/src/bin/subplot.rs
@@ -397,6 +397,7 @@ fn load_linted_doc(
let template = template.to_string();
trace!("Template: {:#?}", template);
let mut warnings = Warnings::default();
+ doc.check_named_code_blocks_have_appropriate_class(&mut warnings)?;
doc.check_named_files_exist(&template, &mut warnings)?;
doc.check_matched_steps_have_impl(&template, &mut warnings);
doc.check_embedded_files_are_used(&template, &mut warnings)?;
diff --git a/src/doc.rs b/src/doc.rs
index fe263ad..e218020 100644
--- a/src/doc.rs
+++ b/src/doc.rs
@@ -38,6 +38,10 @@ static KNOWN_FILE_CLASSES: &[&str] = &["rust", "yaml", "python", "sh", "shell",
/// which we use to invert the default numberLines on .file blocks.
static KNOWN_BLOCK_CLASSES: &[&str] = &["numberLines", "noNumberLines"];
+/// The set of classes which subplot will recognise as being appropriate
+/// for having IDs.
+static ID_OK_CLASSES: &[&str] = &["file", "example"];
+
/// A parsed Subplot document.
///
/// # Example
@@ -340,6 +344,37 @@ impl Document {
set
}
+ /// Check labelled code blocks have some appropriate class
+ pub fn check_named_code_blocks_have_appropriate_class(
+ &self,
+ warnings: &mut Warnings,
+ ) -> Result<bool, SubplotError> {
+ let mut okay = true;
+ for md in self.markdowns.iter() {
+ for block in md.named_blocks() {
+ if !block.all_attrs().iter().any(|attr| {
+ attr.name() == "class"
+ && ID_OK_CLASSES
+ .iter()
+ .any(|class| attr.value() == Some(class))
+ }) {
+ // For now, named blocks must be files
+ warnings.push(Warning::MissingAppropriateClassOnNamedCodeBlock(
+ block
+ .attr("id")
+ .expect("Named blocks should have IDs")
+ .value()
+ .unwrap_or("(unknown-id)")
+ .to_string(),
+ block.location().to_string(),
+ ));
+ okay = false;
+ }
+ }
+ }
+ Ok(okay)
+ }
+
/// Check that all named files (in matched steps) are actually present in the
/// document.
pub fn check_named_files_exist(
@@ -563,7 +598,8 @@ pub fn codegen(
return Err(SubplotError::TemplateSupportNotPresent);
}
let mut warnings = Warnings::default();
- if !doc.check_named_files_exist(&template, &mut warnings)?
+ if !doc.check_named_code_blocks_have_appropriate_class(&mut warnings)?
+ || !doc.check_named_files_exist(&template, &mut warnings)?
|| !doc.check_matched_steps_have_impl(&template, &mut warnings)
|| !doc.check_embedded_files_are_used(&template, &mut warnings)?
{
diff --git a/src/error.rs b/src/error.rs
index 93a828a..6859aa4 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -379,6 +379,10 @@ pub enum Warning {
/// Plantuml failed during typesetting.
#[error("Markup using plantuml failed: {0}")]
Plantuml(String),
+
+ /// A code block has an identifier but is not marked as a file or example
+ #[error("Code block has identifier but lacks file or example class. Is this a mistake? #{0} at {1}")]
+ MissingAppropriateClassOnNamedCodeBlock(String, String),
}
/// A list of warnings.
diff --git a/src/md.rs b/src/md.rs
index 9b8e015..0ea4cc3 100644
--- a/src/md.rs
+++ b/src/md.rs
@@ -153,6 +153,13 @@ impl Markdown {
Ok(files)
}
+
+ /// Find all code blocks which have identifiers and return them
+ pub fn named_blocks(&self) -> impl Iterator<Item = &Element> {
+ Self::visit(&self.html)
+ .into_iter()
+ .filter(|e| e.tag() == ElementTag::Pre && e.attr("id").is_some())
+ }
}
// A structure element in the document: a heading or a scenario snippet.