diff --git a/cli/src/main/groovy/com/jessebrault/ssg/StaticSiteGeneratorCli.groovy b/cli/src/main/groovy/com/jessebrault/ssg/StaticSiteGeneratorCli.groovy index aa08d1c..af42ba2 100644 --- a/cli/src/main/groovy/com/jessebrault/ssg/StaticSiteGeneratorCli.groovy +++ b/cli/src/main/groovy/com/jessebrault/ssg/StaticSiteGeneratorCli.groovy @@ -11,6 +11,7 @@ import com.jessebrault.ssg.specialpage.SpecialPageType import com.jessebrault.ssg.template.GspTemplateRenderer import com.jessebrault.ssg.template.TemplateFileTemplatesProvider import com.jessebrault.ssg.template.TemplateType +import com.jessebrault.ssg.text.MarkdownExcerptGetter import com.jessebrault.ssg.text.MarkdownFrontMatterGetter import com.jessebrault.ssg.text.MarkdownTextRenderer import com.jessebrault.ssg.text.TextFileTextsProvider @@ -85,7 +86,7 @@ class StaticSiteGeneratorCli implements Callable { context.updateLoggers() // Configure - def markdownText = new TextType(['.md'], new MarkdownTextRenderer(), new MarkdownFrontMatterGetter()) + def markdownText = new TextType(['.md'], new MarkdownTextRenderer(), new MarkdownFrontMatterGetter(), new MarkdownExcerptGetter()) def gspTemplate = new TemplateType(['.gsp'], new GspTemplateRenderer()) def gspPart = new PartType(['.gsp'], new GspPartRenderer()) def gspSpecialPage = new SpecialPageType(['.gsp'], new GspSpecialPageRenderer()) diff --git a/lib/src/main/groovy/com/jessebrault/ssg/text/EmbeddableText.groovy b/lib/src/main/groovy/com/jessebrault/ssg/text/EmbeddableText.groovy index ae7546b..ebea25c 100644 --- a/lib/src/main/groovy/com/jessebrault/ssg/text/EmbeddableText.groovy +++ b/lib/src/main/groovy/com/jessebrault/ssg/text/EmbeddableText.groovy @@ -30,7 +30,18 @@ class EmbeddableText { def result = this.text.type.frontMatterGetter.get(this.text) if (result.v1.size() > 0) { this.onDiagnostics.call(result.v1) - new FrontMatter([:]) + new FrontMatter(this.text, [:]) + } else { + result.v2 + } + } + + @Memoized + String getExcerpt(int limit) { + def result = this.text.type.excerptGetter.getExcerpt(this.text, limit) + if (result.v1.size() > 0) { + this.onDiagnostics.call(result.v1) + '' } else { result.v2 } diff --git a/lib/src/main/groovy/com/jessebrault/ssg/text/ExcerptGetter.groovy b/lib/src/main/groovy/com/jessebrault/ssg/text/ExcerptGetter.groovy new file mode 100644 index 0000000..5771785 --- /dev/null +++ b/lib/src/main/groovy/com/jessebrault/ssg/text/ExcerptGetter.groovy @@ -0,0 +1,7 @@ +package com.jessebrault.ssg.text + +import com.jessebrault.ssg.Diagnostic + +interface ExcerptGetter { + Tuple2, String> getExcerpt(Text text, int limit) +} \ No newline at end of file diff --git a/lib/src/main/groovy/com/jessebrault/ssg/text/MarkdownExcerptGetter.groovy b/lib/src/main/groovy/com/jessebrault/ssg/text/MarkdownExcerptGetter.groovy new file mode 100644 index 0000000..0cf4b9d --- /dev/null +++ b/lib/src/main/groovy/com/jessebrault/ssg/text/MarkdownExcerptGetter.groovy @@ -0,0 +1,54 @@ +package com.jessebrault.ssg.text + +import com.jessebrault.ssg.Diagnostic +import org.commonmark.ext.front.matter.YamlFrontMatterExtension +import org.commonmark.node.AbstractVisitor +import org.commonmark.parser.Parser + +class MarkdownExcerptGetter implements ExcerptGetter { + + private static class ExcerptVisitor extends AbstractVisitor { + + final int limit + List words = [] + + ExcerptVisitor(int limit) { + this.limit = limit + } + + @Override + void visit(org.commonmark.node.Text text) { + if (this.words.size() <= limit) { + def textWords = text.literal.split('\\s+').toList() + def taken = textWords.take(this.limit - this.words.size()) + this.words.addAll(taken) + } + } + + String getResult() { + this.words.take(this.limit).join(' ') + } + + } + + private static final Parser parser = Parser.builder() + .extensions([YamlFrontMatterExtension.create()]) + .build() + + @Override + Tuple2, String> getExcerpt(Text text, int limit) { + try { + def node = parser.parse(text.text) + def visitor = new ExcerptVisitor(limit) + node.accept(visitor) + new Tuple2<>([], visitor.result) + } catch (Exception e) { + def diagnostic = new Diagnostic( + "There was an exception while getting the excerpt for ${ text }:\n${ e }", + e + ) + new Tuple2<>([diagnostic], '') + } + } + +} diff --git a/lib/src/main/groovy/com/jessebrault/ssg/text/TextType.groovy b/lib/src/main/groovy/com/jessebrault/ssg/text/TextType.groovy index 5b722ac..1280d91 100644 --- a/lib/src/main/groovy/com/jessebrault/ssg/text/TextType.groovy +++ b/lib/src/main/groovy/com/jessebrault/ssg/text/TextType.groovy @@ -12,10 +12,11 @@ class TextType { Collection ids TextRenderer renderer FrontMatterGetter frontMatterGetter + ExcerptGetter excerptGetter @Override String toString() { - "TextType(ids: ${ this.ids }, renderer: ${ this.renderer }, frontMatterGetter: ${ this.renderer })" + "TextType(ids: ${ this.ids }, renderer: ${ this.renderer }, frontMatterGetter: ${ this.renderer }, excerptGetter: ${ this.excerptGetter })" } } diff --git a/lib/src/test/groovy/com/jessebrault/ssg/SimpleStaticSiteGeneratorIntegrationTests.groovy b/lib/src/test/groovy/com/jessebrault/ssg/SimpleStaticSiteGeneratorIntegrationTests.groovy index 5a7c19d..6180ff2 100644 --- a/lib/src/test/groovy/com/jessebrault/ssg/SimpleStaticSiteGeneratorIntegrationTests.groovy +++ b/lib/src/test/groovy/com/jessebrault/ssg/SimpleStaticSiteGeneratorIntegrationTests.groovy @@ -9,6 +9,7 @@ import com.jessebrault.ssg.specialpage.SpecialPageType import com.jessebrault.ssg.template.GspTemplateRenderer import com.jessebrault.ssg.template.TemplateFileTemplatesProvider import com.jessebrault.ssg.template.TemplateType +import com.jessebrault.ssg.text.MarkdownExcerptGetter import com.jessebrault.ssg.text.MarkdownFrontMatterGetter import com.jessebrault.ssg.text.MarkdownTextRenderer import com.jessebrault.ssg.text.TextFileTextsProvider @@ -35,7 +36,7 @@ class SimpleStaticSiteGeneratorIntegrationTests { this.partsDir = File.createTempDir() this.specialPagesDir = File.createTempDir() - def markdownTextType = new TextType(['.md'], new MarkdownTextRenderer(), new MarkdownFrontMatterGetter()) + def markdownTextType = new TextType(['.md'], new MarkdownTextRenderer(), new MarkdownFrontMatterGetter(), new MarkdownExcerptGetter()) def gspTemplateType = new TemplateType(['.gsp'], new GspTemplateRenderer()) def gspPartType = new PartType(['.gsp'], new GspPartRenderer()) def gspSpecialPageType = new SpecialPageType(['.gsp'], new GspSpecialPageRenderer()) diff --git a/lib/src/test/groovy/com/jessebrault/ssg/specialpage/GspSpecialPageRendererTests.groovy b/lib/src/test/groovy/com/jessebrault/ssg/specialpage/GspSpecialPageRendererTests.groovy index cfd36f7..15c3b20 100644 --- a/lib/src/test/groovy/com/jessebrault/ssg/specialpage/GspSpecialPageRendererTests.groovy +++ b/lib/src/test/groovy/com/jessebrault/ssg/specialpage/GspSpecialPageRendererTests.groovy @@ -4,6 +4,7 @@ import com.jessebrault.ssg.part.Part import com.jessebrault.ssg.part.PartRenderer import com.jessebrault.ssg.part.PartType import com.jessebrault.ssg.text.FrontMatterGetter +import com.jessebrault.ssg.text.MarkdownExcerptGetter import com.jessebrault.ssg.text.Text import com.jessebrault.ssg.text.TextRenderer import com.jessebrault.ssg.text.TextType @@ -59,7 +60,7 @@ class GspSpecialPageRendererTests { @Test void rendersText(@Mock TextRenderer textRenderer, @Mock FrontMatterGetter frontMatterGetter) { when(textRenderer.render(any(), any())).thenReturn(new Tuple2<>([], '

Hello, World!

\n')) - def textType = new TextType([], textRenderer, frontMatterGetter) + def textType = new TextType([], textRenderer, frontMatterGetter, new MarkdownExcerptGetter()) def text = new Text('', 'test', textType) def specialPage = new SpecialPage("<%= texts.find { it.path == 'test' }.render() %>", null, null) diff --git a/lib/src/test/groovy/com/jessebrault/ssg/text/ExcerptGetterTests.groovy b/lib/src/test/groovy/com/jessebrault/ssg/text/ExcerptGetterTests.groovy new file mode 100644 index 0000000..7f8abc1 --- /dev/null +++ b/lib/src/test/groovy/com/jessebrault/ssg/text/ExcerptGetterTests.groovy @@ -0,0 +1,43 @@ +package com.jessebrault.ssg.text + +import org.junit.jupiter.api.Test + +import static org.junit.jupiter.api.Assertions.assertEquals + +class ExcerptGetterTests { + + ExcerptGetter excerptGetter = new MarkdownExcerptGetter() + + @Test + void takesAllIfTextLessThanLimit() { + def text = new Text('One Two Three Four Five', null, null) + def result = this.excerptGetter.getExcerpt(text, 10) + assertEquals(0, result.v1.size()) + assertEquals('One Two Three Four Five', result.v2) + } + + @Test + void takesTheLimit() { + def text = new Text('One Two Three Four Five', null, null) + def result = this.excerptGetter.getExcerpt(text, 2) + assertEquals(0, result.v1.size()) + assertEquals('One Two', result.v2) + } + + @Test + void worksWithHeading() { + def text = new Text('# Heading\nOne Two Three', null, null) + def result = this.excerptGetter.getExcerpt(text, 1) + assertEquals(0, result.v1.size()) + assertEquals('Heading', result.v2) + } + + @Test + void worksWithFrontMatter() { + def text = new Text('---\ntest: hello\n---\nOne Two Three', null, null) + def result = this.excerptGetter.getExcerpt(text, 1) + assertEquals(0, result.v1.size()) + assertEquals('One', result.v2) + } + +} diff --git a/lib/src/test/groovy/com/jessebrault/ssg/text/TextFileTextsProviderTests.groovy b/lib/src/test/groovy/com/jessebrault/ssg/text/TextFileTextsProviderTests.groovy index 6092a25..b862a10 100644 --- a/lib/src/test/groovy/com/jessebrault/ssg/text/TextFileTextsProviderTests.groovy +++ b/lib/src/test/groovy/com/jessebrault/ssg/text/TextFileTextsProviderTests.groovy @@ -7,7 +7,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals class TextFileTextsProviderTests { - private static final TextType markdownType = new TextType(['.md'], null, null) + private static final TextType markdownType = new TextType(['.md'], null, null, null) private File textsDir private TextsProvider textsProvider