Skip to content

Commit 6a25536

Browse files
author
Sebastian Bär
authored
#280: Ignore requirement in Markdown code blocks (#433)
* #280: Inside Markdown code blocks requirements are now ignored (see https://github.github.com/gfm/#fenced-code-blocks for specification).
1 parent 159a20e commit 6a25536

File tree

6 files changed

+97
-2
lines changed

6 files changed

+97
-2
lines changed

doc/changes/changes.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Changes
22

3+
* [4.2.0](changes_4.2.0.md)
34
* [4.1.0](changes_4.1.0.md)
45
* [4.0.2](changes_4.0.2.md)
56
* [4.0.1](changes_4.0.1.md)

doc/changes/changes_4.2.0.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# OpenFastTrace 4.2.0, released ???
2+
3+
Code name: Markdown code blocks
4+
5+
## Summary
6+
7+
In this release we changed the behavior of the Markdown importer, so that if we are inside a code block, no OFT specification items are found. This is a corner case, but we think that this behavior is what users would expect (#480).
8+
9+
## Features
10+
11+
* #480: Ignore specification items inside Markdown code blocks

importer/lightweightmarkup/src/main/java/org/itsallcode/openfasttrace/importer/lightweightmarkup/statemachine/LineParserState.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ public enum LineParserState
2929
TITLE,
3030
/** Found tags */
3131
TAGS,
32+
/** Code block */
33+
CODE_BLOCK,
3234
/** Reached the end of the file */
3335
EOF
3436
}

importer/markdown/src/main/java/org/itsallcode/openfasttrace/importer/markdown/MarkdownImporter.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ protected Transition[] configureTransitions()
4242
transition(START , SPEC_ITEM , MdPattern.ID , this::beginItem ),
4343
transition(START , TITLE , SECTION_TITLE , this::rememberTitle ),
4444
transition(START , START , MdPattern.FORWARD , this::forward ),
45+
transition(START , CODE_BLOCK , MdPattern.CODE_BEGIN , () -> {} ),
4546
transition(START , START , MdPattern.EVERYTHING , () -> {} ),
4647

4748
transition(TITLE , SPEC_ITEM , MdPattern.ID , this::beginItem ),
@@ -99,7 +100,6 @@ protected Transition[] configureTransitions()
99100
transition(COMMENT , TAGS , MdPattern.TAGS , () -> {} ),
100101
transition(COMMENT , COMMENT , MdPattern.EVERYTHING , this::appendComment ),
101102

102-
103103
// [impl->dsn~md.covers-list~1]
104104
transition(COVERS , SPEC_ITEM , MdPattern.ID , this::beginItem ),
105105
transition(COVERS , TITLE , SECTION_TITLE , () -> {endItem(); rememberTitle();}),
@@ -156,7 +156,9 @@ protected Transition[] configureTransitions()
156156
transition(TAGS , COVERS , MdPattern.COVERS , () -> {} ),
157157
transition(TAGS , TAGS , MdPattern.TAGS , () -> {} ),
158158
transition(TAGS , TAGS , MdPattern.TAGS_INT , this::addTag ),
159-
transition(TAGS , START , MdPattern.FORWARD , () -> {endItem(); forward();} )
159+
transition(TAGS , START , MdPattern.FORWARD , () -> {endItem(); forward();} ),
160+
161+
transition(CODE_BLOCK , START , MdPattern.CODE_END , () -> {} )
160162
};
161163
// @formatter:on
162164
}

importer/markdown/src/main/java/org/itsallcode/openfasttrace/importer/markdown/MdPattern.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ enum MdPattern
1515
// [impl->dsn~md.artifact-forwarding-notation~1]
1616

1717
// @formatter:off
18+
CODE_BEGIN(" *[`~]{3,30}\\w*\\s*"),
19+
CODE_END(" *[`~]{3,30}\\s*"),
1820
COMMENT("Comment:\\s*"),
1921
COVERS("Covers:\\s*"),
2022
COVERS_REF(PatternConstants.REFERENCE_AFTER_BULLET),

importer/markdown/src/test/java/org/itsallcode/openfasttrace/importer/markdown/TestMarkdownMarkupImporter.java

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.itsallcode.openfasttrace.importer.markdown;
22

3+
import static org.hamcrest.Matchers.emptyIterable;
34
import static org.itsallcode.matcher.auto.AutoMatcher.contains;
45
import static org.itsallcode.openfasttrace.testutil.core.ItemBuilderFactory.item;
56

@@ -8,6 +9,7 @@
89
import org.itsallcode.openfasttrace.testutil.importer.lightweightmarkup.AbstractLightWeightMarkupImporterTest;
910
import org.junit.jupiter.api.Test;
1011
import org.junit.jupiter.params.ParameterizedTest;
12+
import org.junit.jupiter.params.provider.CsvSource;
1113
import org.junit.jupiter.params.provider.ValueSource;
1214

1315
class TestMarkdownMarkupImporter extends AbstractLightWeightMarkupImporterTest
@@ -138,4 +140,79 @@ void testLessThenThreeUnderliningCharactersAreNotDetectedAsTitleUnderlines()
138140
.location("z", 3)
139141
.build()));
140142
}
143+
144+
@ParameterizedTest
145+
@CsvSource(
146+
{
147+
"```,```",
148+
"``` ,``` ",
149+
"``` ,```",
150+
"````, ````",
151+
" ```, ```",
152+
" ```, ```",
153+
" ```, ```",
154+
"```java, ```",
155+
"```java , ``` ",
156+
"~~~, ~~~",
157+
"~~~java, ~~~",
158+
" ~~~~java, ~~~~ "
159+
})
160+
void testWhenInsideMarkdownCodeBlockThenNoSpecificationItemMustBeDetected(final String startMarker,
161+
final String endMarker)
162+
{
163+
assertImport("file_with_code_block.md", """
164+
%s
165+
This is a code block, the following requirement must be ignored.
166+
167+
req~example~1
168+
%s
169+
""".formatted(startMarker, endMarker),
170+
emptyIterable());
171+
}
172+
173+
@ParameterizedTest
174+
@CsvSource(
175+
{
176+
"`,`",
177+
"``,``",
178+
" ``', ``",
179+
"`` ,`` ",
180+
"``java,``",
181+
"~~,~~",
182+
})
183+
void testWhenNotInsideMarkdownCodeBlockThenSpecificationItemMustBeDetected(final String startMarker,
184+
final String endMarker)
185+
{
186+
assertImport("file_without_code_block.md", """
187+
%s
188+
This is not a code block, the following requirement must be detected.
189+
190+
req~example~1
191+
%s
192+
""".formatted(startMarker, endMarker),
193+
contains(item()
194+
.id(SpecificationItemId.parseId("req~example~1"))
195+
.location("file_without_code_block.md", 4)
196+
.description(endMarker) // End marker looks like part of the description in this case.
197+
.build()));
198+
}
199+
200+
@Test
201+
void testWhenCodeBlockIsInsideCommentSectionThenItIsImportedAsPartOfComment()
202+
{
203+
assertImport("file_with_code_block_in_comment.md", """
204+
req~comment_with_code_block~1
205+
Comment:
206+
207+
```
208+
This is a code block inside a comment.
209+
```
210+
""",
211+
contains(item()
212+
.id(SpecificationItemId.createId("req", "comment_with_code_block", 1))
213+
.comment("```" + System.lineSeparator()+ "This is a code block inside a comment."
214+
+ System.lineSeparator() + "```")
215+
.location("file_with_code_block_in_comment.md", 1)
216+
.build()));
217+
}
141218
}

0 commit comments

Comments
 (0)