summaryrefslogtreecommitdiff
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
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>
-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
-rw-r--r--subplot.md50
5 files changed, 99 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.
diff --git a/subplot.md b/subplot.md
index cae70f6..269343b 100644
--- a/subplot.md
+++ b/subplot.md
@@ -1095,6 +1095,56 @@ bindings:
~~~
~~~~~~
+## Named code blocks must have an appropriate class
+
+_Requirement: Named code blocks must carry an appropriate class such as file or example_
+
+Justification: Eventually we may want to add other meanings to named blocks,
+currently the identifier cannot be used except to refer to the block as a named file,
+but we may want to in the future so this is here to try and prevent any future
+incompatibilities.
+
+~~~scenario
+given file named-code-blocks-appropriate.subplot
+given file named-code-blocks-appropriate.md
+given file b.yaml
+given an installed subplot
+when I try to run subplot docgen named-code-blocks-appropriate.subplot -o foo.html
+then command fails
+and stderr contains "#example-1 at named-code-blocks-appropriate.md:7:1"
+and stderr doesn't contain "example-2"
+and stderr doesn't contain "example-3"
+~~~
+
+~~~{#named-code-blocks-appropriate.subplot .file .yaml .numberLines}
+title: Named code blocks carry appropriate classes step
+markdowns:
+ - named-code-blocks-appropriate.md
+bindings:
+ - b.yaml
+~~~
+
+~~~~~~{#named-code-blocks-appropriate.md .file .markdown .numberLines}
+# This is a title
+
+~~~scenario
+given precondition
+~~~
+
+~~~{#example-1 .numberLines}
+This example is bad
+~~~
+
+~~~{#example-2 .file .numberLines}
+This example is OK because of .file
+~~~
+
+~~~{#example-3 .example .numberLines}
+This example is OK because of .example
+~~~
+
+~~~~~~
+
## No scenarios means codegen fails
If you attempt to `subplot codegen` on a document which contains no scenarios, the