diff options
author | Daniel Silverstone <dsilvers@digital-scurf.org> | 2023-06-10 10:31:54 +0100 |
---|---|---|
committer | Daniel Silverstone <dsilvers@digital-scurf.org> | 2023-06-10 10:31:54 +0100 |
commit | 07c0e5d66920d4102f29245b0d96e725275271a6 (patch) | |
tree | adce16c2f9a1aae6dc46c41c4208bfa4868d158a /src | |
parent | 5d6978497c7f875172a1907a203500e8a185bac4 (diff) | |
download | subplot-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.rs | 1 | ||||
-rw-r--r-- | src/doc.rs | 38 | ||||
-rw-r--r-- | src/error.rs | 4 | ||||
-rw-r--r-- | src/md.rs | 7 |
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)?; @@ -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. @@ -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. |