Major refactoring and api changes.

This commit is contained in:
JesseBrault0709 2023-01-08 17:31:26 -06:00
parent 829ec4698e
commit 27ae22d5eb
26 changed files with 309 additions and 136 deletions

View File

@ -102,10 +102,22 @@ class StaticSiteGeneratorCli implements Callable<Integer> {
// Generate // Generate
def ssg = new SimpleStaticSiteGenerator(config) def ssg = new SimpleStaticSiteGenerator(config)
ssg.generate(new File('build'), globals) def result = ssg.generate(globals)
// Exit if (result.v1.size() > 0) {
return 0 result.v1.each {
logger.error(it.message)
}
return 1
} else {
def buildDir = new File('build')
result.v2.each {
def target = new File(buildDir, it.path + '.html')
target.createParentDirectories()
target.write(it.html)
}
return 0
}
} }
} }

View File

@ -19,6 +19,9 @@ dependencies {
// https://mvnrepository.com/artifact/org.commonmark/commonmark-ext-yaml-front-matter // https://mvnrepository.com/artifact/org.commonmark/commonmark-ext-yaml-front-matter
implementation 'org.commonmark:commonmark-ext-yaml-front-matter:0.21.0' implementation 'org.commonmark:commonmark-ext-yaml-front-matter:0.21.0'
/**
* Logging
*/
// https://mvnrepository.com/artifact/org.slf4j/slf4j-api // https://mvnrepository.com/artifact/org.slf4j/slf4j-api
implementation 'org.slf4j:slf4j-api:1.7.36' implementation 'org.slf4j:slf4j-api:1.7.36'

View File

@ -0,0 +1,18 @@
package com.jessebrault.ssg
import groovy.transform.EqualsAndHashCode
import groovy.transform.TupleConstructor
@TupleConstructor
@EqualsAndHashCode
class Diagnostic {
String message
Exception exception
@Override
String toString() {
"Diagnostic(message: ${ this.message }, exception: ${ this.exception })"
}
}

View File

@ -0,0 +1,20 @@
package com.jessebrault.ssg
import groovy.transform.EqualsAndHashCode
import groovy.transform.NullCheck
import groovy.transform.TupleConstructor
@TupleConstructor(includeFields = true, defaults = false)
@NullCheck
@EqualsAndHashCode
class GeneratedPage {
String path
String html
@Override
String toString() {
"GeneratedPage(path: ${ this.path })"
}
}

View File

@ -1,5 +1,6 @@
package com.jessebrault.ssg package com.jessebrault.ssg
import com.jessebrault.ssg.text.FrontMatter
import groovy.transform.EqualsAndHashCode import groovy.transform.EqualsAndHashCode
import groovy.transform.NullCheck import groovy.transform.NullCheck
import groovy.transform.TupleConstructor import groovy.transform.TupleConstructor
@ -20,8 +21,8 @@ class SimpleStaticSiteGenerator implements StaticSiteGenerator {
private final Config config private final Config config
@Override @Override
void generate(File buildDir, Map globals) { Tuple2<Collection<Diagnostic>, Collection<GeneratedPage>> generate(Map globals) {
logger.trace(enter, 'buildDir: {}, globals: {}', buildDir, globals) logger.trace(enter, 'globals: {}', globals)
// Get all texts, templates, parts, and specialPages // Get all texts, templates, parts, and specialPages
def texts = this.config.textProviders.collectMany { it.getTextFiles() } def texts = this.config.textProviders.collectMany { it.getTextFiles() }
@ -31,64 +32,91 @@ class SimpleStaticSiteGenerator implements StaticSiteGenerator {
logger.debug('\n\ttexts: {}\n\ttemplates: {}\n\tparts: {}\n\tspecialPages: {}', texts, templates, parts, specialPages) logger.debug('\n\ttexts: {}\n\ttemplates: {}\n\tparts: {}\n\tspecialPages: {}', texts, templates, parts, specialPages)
// Define output function Collection<Diagnostic> diagnostics = []
def outputPage = { String path, String result -> Collection<GeneratedPage> generatedPages = []
def outFile = new File(buildDir, path + '.html')
if (outFile.exists()) {
logger.info('outFile {} already exists, deleting', outFile)
outFile.delete()
}
outFile.createParentDirectories()
logger.info('writing result to {}', outFile)
outFile.write(result)
}
// Generate pages from each text // Generate pages from each text
texts.each { texts.each {
logger.trace(enter, 'text: {}', it)
logger.info('processing text: {}', it.path) logger.info('processing text: {}', it.path)
// Render the text (i.e., transform text to html) // Render the text (i.e., transform text to html)
def renderedText = it.type.renderer.render(it.text, globals) def textRenderResult = it.type.renderer.render(it, globals)
String renderedText
if (textRenderResult.v1.size() > 0) {
logger.debug('diagnostics for rendering {}: {}', it.path, textRenderResult.v1)
diagnostics.addAll(textRenderResult.v1)
logger.trace(exit, '')
return
} else {
renderedText = textRenderResult.v2
logger.debug('renderedText: {}', renderedText)
}
// Extract frontMatter from text // Extract frontMatter from text
def frontMatter = it.type.frontMatterGetter.get(it.text) def frontMatterResult = it.type.frontMatterGetter.get(it)
logger.debug('frontMatter: {}', frontMatter) FrontMatter frontMatter
if (frontMatterResult.v1.size() > 0) {
logger.debug('diagnostics for getting frontMatter for {}: {}', it.path, frontMatterResult.v1)
diagnostics.addAll(frontMatterResult.v1)
logger.trace(exit, '')
return
} else {
frontMatter = frontMatterResult.v2
logger.debug('frontMatter: {}', frontMatter)
}
// Find the appropriate template from the frontMatter // Find the appropriate template from the frontMatter
def desiredTemplate = frontMatter['template'] def desiredTemplate = frontMatter['template']
logger.debug('desiredTemplate name: {}', desiredTemplate) logger.debug('desiredTemplate name: {}', desiredTemplate)
if (desiredTemplate == null) { if (desiredTemplate == null || desiredTemplate.isEmpty() || desiredTemplate.isBlank()) {
throw new IllegalArgumentException('in text ' + it.path + ' frontMatter.template must not be null') diagnostics << new Diagnostic('in textFile ' + it.path + ' frontMatter.template must not be empty, blank, or missing', null)
logger.trace(exit, '')
return
} }
if (desiredTemplate.isEmpty() || desiredTemplate.isBlank()) { def template = templates.find { it.path == desiredTemplate }
throw new IllegalArgumentException('in text ' + it.path + ' frontMatter.template must not be empty, blank, or missing')
}
def template = templates.find {
it.relativePath == desiredTemplate
}
logger.debug('template: {}', template)
if (template == null) { if (template == null) {
throw new IllegalArgumentException('in textFile' + it.path + ' unknown template: ' + desiredTemplate) diagnostics << new Diagnostic('in textFile' + it.path + ' frontMatter.template references an unknown template: ' + desiredTemplate, null)
logger.trace(exit, '')
return
} }
logger.debug('found template: {}', template)
// Render the template using the result of rendering the text earlier // Render the template using the result of rendering the text earlier
def result = template.type.renderer.render(template, frontMatter, renderedText, parts, globals) def templateRenderResult = template.type.renderer.render(template, frontMatter, renderedText, parts, globals)
String renderedTemplate
if (templateRenderResult.v1.size() > 0) {
diagnostics.addAll(templateRenderResult.v1)
logger.trace(exit, '')
return
} else {
renderedTemplate = templateRenderResult.v2
}
// Output the result to the outfile, an .html file // Create a GeneratedPage
outputPage(it.path, result) generatedPages << new GeneratedPage(it.path, renderedTemplate)
} }
// Generate special pages // Generate special pages
specialPages.each { specialPages.each {
logger.info('processing specialPage: {}', it) logger.info('processing specialPage: {}', it.path)
def result = it.type.renderer.render(it.text, texts, parts, globals) def specialPageRenderResult = it.type.renderer.render(it, texts, parts, globals)
String renderedSpecialPage
if (specialPageRenderResult.v1.size() > 0) {
diagnostics.addAll(specialPageRenderResult.v1)
logger.trace(exit, '')
return
} else {
renderedSpecialPage = specialPageRenderResult.v2
}
// Output result to file // Create a GeneratedPage
outputPage(it.path, result) generatedPages << new GeneratedPage(it.path, renderedSpecialPage)
} }
logger.trace(exit, '') logger.trace(exit, '\n\tdiagnostics: {}\n\tgeneratedPages: {}', diagnostics, generatedPages)
new Tuple2<>(diagnostics, generatedPages)
} }
@Override @Override

View File

@ -1,5 +1,5 @@
package com.jessebrault.ssg package com.jessebrault.ssg
interface StaticSiteGenerator { interface StaticSiteGenerator {
void generate(File buildDir, Map globals) Tuple2<Collection<Diagnostic>, Collection<GeneratedPage>> generate(Map globals)
} }

View File

@ -11,9 +11,16 @@ class EmbeddablePart {
private final Part part private final Part part
private final Map globals private final Map globals
private final Closure onDiagnostics
String render(Map binding = [:]) { String render(Map binding = [:]) {
part.type.renderer.render(this.part.text, binding, this.globals) def result = part.type.renderer.render(this.part, binding, this.globals)
if (result.v1.size() > 0) {
this.onDiagnostics.call(result.v1)
''
} else {
result.v2
}
} }
@Override @Override

View File

@ -1,17 +1,18 @@
package com.jessebrault.ssg.part package com.jessebrault.ssg.part
import groovy.transform.EqualsAndHashCode import groovy.transform.EqualsAndHashCode
import groovy.transform.NullCheck
@NullCheck
@EqualsAndHashCode(includeFields = true) @EqualsAndHashCode(includeFields = true)
class EmbeddablePartsMap { class EmbeddablePartsMap {
@Delegate @Delegate
private final Map<String, EmbeddablePart> partsMap = [:] private final Map<String, EmbeddablePart> partsMap = [:]
EmbeddablePartsMap(Collection<Part> parts, Map globals) { EmbeddablePartsMap(Collection<Part> parts, Map globals, Closure onDiagnostics) {
Objects.requireNonNull(parts)
parts.each { parts.each {
this.put(it.path, new EmbeddablePart(it, globals)) this.put(it.path, new EmbeddablePart(it, globals, onDiagnostics))
} }
} }

View File

@ -1,5 +1,6 @@
package com.jessebrault.ssg.part package com.jessebrault.ssg.part
import com.jessebrault.ssg.Diagnostic
import groovy.text.GStringTemplateEngine import groovy.text.GStringTemplateEngine
import groovy.text.TemplateEngine import groovy.text.TemplateEngine
import groovy.transform.EqualsAndHashCode import groovy.transform.EqualsAndHashCode
@ -10,11 +11,16 @@ class GspPartRenderer implements PartRenderer {
private static final TemplateEngine engine = new GStringTemplateEngine() private static final TemplateEngine engine = new GStringTemplateEngine()
@Override @Override
String render(String partText, Map binding, Map globals) { Tuple2<Collection<Diagnostic>, String> render(Part part, Map binding, Map globals) {
engine.createTemplate(partText).make([ try {
binding: binding, def result = engine.createTemplate(part.text).make([
globals: globals binding: binding,
]) globals: globals
])
new Tuple2<>([], result.toString())
} catch (Exception e) {
new Tuple2<>([new Diagnostic("An exception occurred while rendering part ${ part.path }:\n${ e }", e)], '')
}
} }
@Override @Override

View File

@ -1,5 +1,7 @@
package com.jessebrault.ssg.part package com.jessebrault.ssg.part
import com.jessebrault.ssg.Diagnostic
interface PartRenderer { interface PartRenderer {
String render(String partText, Map binding, Map globals) Tuple2<Collection<Diagnostic>, String> render(Part part, Map binding, Map globals)
} }

View File

@ -1,5 +1,6 @@
package com.jessebrault.ssg.specialpage package com.jessebrault.ssg.specialpage
import com.jessebrault.ssg.Diagnostic
import com.jessebrault.ssg.part.Part import com.jessebrault.ssg.part.Part
import com.jessebrault.ssg.part.EmbeddablePartsMap import com.jessebrault.ssg.part.EmbeddablePartsMap
import com.jessebrault.ssg.text.EmbeddableTextsCollection import com.jessebrault.ssg.text.EmbeddableTextsCollection
@ -7,24 +8,31 @@ import com.jessebrault.ssg.text.Text
import groovy.text.GStringTemplateEngine import groovy.text.GStringTemplateEngine
import groovy.text.TemplateEngine import groovy.text.TemplateEngine
import groovy.transform.EqualsAndHashCode import groovy.transform.EqualsAndHashCode
import groovy.transform.NullCheck
@NullCheck
@EqualsAndHashCode @EqualsAndHashCode
class GspSpecialPageRenderer implements SpecialPageRenderer { class GspSpecialPageRenderer implements SpecialPageRenderer {
private static final TemplateEngine engine = new GStringTemplateEngine() private static final TemplateEngine engine = new GStringTemplateEngine()
@Override @Override
String render(String text, Collection<Text> texts, Collection<Part> parts, Map globals) { Tuple2<Collection<Diagnostic>, String> render(SpecialPage specialPage, Collection<Text> texts, Collection<Part> parts, Map globals) {
Objects.requireNonNull(text) try {
Objects.requireNonNull(texts) Collection<Diagnostic> diagnostics = []
Objects.requireNonNull(parts) def result = engine.createTemplate(specialPage.text).make([
Objects.requireNonNull(globals) globals: globals,
parts: new EmbeddablePartsMap(parts, globals, { Collection<Diagnostic> partDiagnostics ->
engine.createTemplate(text).make([ diagnostics.addAll(partDiagnostics)
globals: globals, }),
parts: new EmbeddablePartsMap(parts, globals), texts: new EmbeddableTextsCollection(texts, globals, { Collection<Diagnostic> textDiagnostics ->
texts: new EmbeddableTextsCollection(texts, globals) diagnostics.addAll(textDiagnostics)
]) })
])
new Tuple2<>(diagnostics, result.toString())
} catch (Exception e) {
new Tuple2<>([new Diagnostic("An exception occurred while rendering specialPage ${ specialPage.path }:\n${ e }", e)], '')
}
} }
@Override @Override

View File

@ -1,12 +1,13 @@
package com.jessebrault.ssg.specialpage package com.jessebrault.ssg.specialpage
import com.jessebrault.ssg.Diagnostic
import com.jessebrault.ssg.part.Part import com.jessebrault.ssg.part.Part
import com.jessebrault.ssg.text.Text import com.jessebrault.ssg.text.Text
interface SpecialPageRenderer { interface SpecialPageRenderer {
String render( Tuple2<Collection<Diagnostic>, String> render(
String text, SpecialPage specialPage,
Collection<Text> texts, Collection<Text> texts,
Collection <Part> parts, Collection <Part> parts,
Map globals Map globals

View File

@ -1,31 +1,42 @@
package com.jessebrault.ssg.template package com.jessebrault.ssg.template
import com.jessebrault.ssg.Diagnostic
import com.jessebrault.ssg.part.Part import com.jessebrault.ssg.part.Part
import com.jessebrault.ssg.part.EmbeddablePartsMap import com.jessebrault.ssg.part.EmbeddablePartsMap
import com.jessebrault.ssg.text.FrontMatter import com.jessebrault.ssg.text.FrontMatter
import groovy.text.GStringTemplateEngine import groovy.text.GStringTemplateEngine
import groovy.text.TemplateEngine import groovy.text.TemplateEngine
import groovy.transform.EqualsAndHashCode import groovy.transform.EqualsAndHashCode
import groovy.transform.NullCheck
@NullCheck
@EqualsAndHashCode @EqualsAndHashCode
class GspTemplateRenderer implements TemplateRenderer { class GspTemplateRenderer implements TemplateRenderer {
private static final TemplateEngine engine = new GStringTemplateEngine() private static final TemplateEngine engine = new GStringTemplateEngine()
@Override @Override
String render( Tuple2<Collection<Diagnostic>, String> render(
Template template, Template template,
FrontMatter frontMatter, FrontMatter frontMatter,
String text, String text,
Collection<Part> parts, Collection<Part> parts,
Map globals Map globals
) { ) {
engine.createTemplate(template.text).make([ try {
frontMatter: frontMatter, Collection<Diagnostic> diagnostics = []
globals: globals, def result = engine.createTemplate(template.text).make([
parts: new EmbeddablePartsMap(parts, globals), frontMatter: frontMatter,
text: text globals: globals,
]) parts: new EmbeddablePartsMap(parts, globals, { Collection<Diagnostic> partDiagnostics ->
diagnostics.addAll(partDiagnostics)
}),
text: text
])
new Tuple2<>(diagnostics, result.toString())
} catch (Exception e) {
new Tuple2<>([new Diagnostic("An exception occurred while rendering Template ${ template.path }:\n${ e }", e)], '')
}
} }
@Override @Override

View File

@ -10,12 +10,12 @@ import groovy.transform.TupleConstructor
class Template { class Template {
String text String text
String relativePath String path
TemplateType type TemplateType type
@Override @Override
String toString() { String toString() {
"Template(path: ${ this.relativePath }, type: ${ this.type })" "Template(path: ${ this.path }, type: ${ this.type })"
} }
} }

View File

@ -1,11 +1,12 @@
package com.jessebrault.ssg.template package com.jessebrault.ssg.template
import com.jessebrault.ssg.Diagnostic
import com.jessebrault.ssg.part.Part import com.jessebrault.ssg.part.Part
import com.jessebrault.ssg.text.FrontMatter import com.jessebrault.ssg.text.FrontMatter
interface TemplateRenderer { interface TemplateRenderer {
String render( Tuple2<Collection<Diagnostic>, String> render(
Template template, Template template,
FrontMatter frontMatter, FrontMatter frontMatter,
String text, String text,

View File

@ -8,19 +8,32 @@ import groovy.transform.TupleConstructor
@TupleConstructor(includeFields = true, defaults = false) @TupleConstructor(includeFields = true, defaults = false)
@NullCheck @NullCheck
@EqualsAndHashCode(includeFields = true) @EqualsAndHashCode(includeFields = true)
class EmbeddableText { class EmbeddableText {
private final Text text private final Text text
private final Map globals private final Map globals
private final Closure onDiagnostics
@Memoized @Memoized
String render() { String render() {
this.text.type.renderer.render(this.text.text, globals) def result = this.text.type.renderer.render(this.text, globals)
if (result.v1.size() > 0) {
this.onDiagnostics.call(result.v1)
''
} else {
result.v2
}
} }
@Memoized @Memoized
FrontMatter getFrontMatter() { FrontMatter getFrontMatter() {
this.text.type.frontMatterGetter.get(this.text.text) def result = this.text.type.frontMatterGetter.get(this.text)
if (result.v1.size() > 0) {
this.onDiagnostics.call(result.v1)
new FrontMatter([:])
} else {
result.v2
}
} }
String getPath() { String getPath() {

View File

@ -1,16 +1,18 @@
package com.jessebrault.ssg.text package com.jessebrault.ssg.text
import groovy.transform.EqualsAndHashCode import groovy.transform.EqualsAndHashCode
import groovy.transform.NullCheck
@NullCheck
@EqualsAndHashCode(includeFields = true) @EqualsAndHashCode(includeFields = true)
class EmbeddableTextsCollection { class EmbeddableTextsCollection {
@Delegate @Delegate
private final Collection<EmbeddableText> embeddableTexts = [] private final Collection<EmbeddableText> embeddableTexts = []
EmbeddableTextsCollection(Collection<Text> texts, Map globals) { EmbeddableTextsCollection(Collection<Text> texts, Map globals, Closure onDiagnostics) {
Objects.requireNonNull(texts).each { Objects.requireNonNull(texts).each {
this << new EmbeddableText(it, globals) this << new EmbeddableText(it, globals, onDiagnostics)
} }
} }

View File

@ -1,5 +1,7 @@
package com.jessebrault.ssg.text package com.jessebrault.ssg.text
import com.jessebrault.ssg.Diagnostic
interface FrontMatterGetter { interface FrontMatterGetter {
FrontMatter get(String text) Tuple2<Collection<Diagnostic>, FrontMatter> get(Text text)
} }

View File

@ -1,10 +1,13 @@
package com.jessebrault.ssg.text package com.jessebrault.ssg.text
import com.jessebrault.ssg.Diagnostic
import groovy.transform.EqualsAndHashCode import groovy.transform.EqualsAndHashCode
import groovy.transform.NullCheck
import org.commonmark.ext.front.matter.YamlFrontMatterExtension import org.commonmark.ext.front.matter.YamlFrontMatterExtension
import org.commonmark.ext.front.matter.YamlFrontMatterVisitor import org.commonmark.ext.front.matter.YamlFrontMatterVisitor
import org.commonmark.parser.Parser import org.commonmark.parser.Parser
@NullCheck
@EqualsAndHashCode @EqualsAndHashCode
class MarkdownFrontMatterGetter implements FrontMatterGetter { class MarkdownFrontMatterGetter implements FrontMatterGetter {
@ -13,11 +16,15 @@ class MarkdownFrontMatterGetter implements FrontMatterGetter {
.build() .build()
@Override @Override
FrontMatter get(String text) { Tuple2<Collection<Diagnostic>, FrontMatter> get(Text text) {
def node = parser.parse(text) try {
def v = new YamlFrontMatterVisitor() def node = parser.parse(text.text)
node.accept(v) def v = new YamlFrontMatterVisitor()
new FrontMatter(v.data) node.accept(v)
new Tuple2([], new FrontMatter(v.data))
} catch (Exception e) {
new Tuple2<>([new Diagnostic("An exception occured while parsing frontMatter for ${ text.path }:\n${ e }", e)], new FrontMatter([:]))
}
} }
@Override @Override

View File

@ -1,10 +1,13 @@
package com.jessebrault.ssg.text package com.jessebrault.ssg.text
import com.jessebrault.ssg.Diagnostic
import groovy.transform.EqualsAndHashCode import groovy.transform.EqualsAndHashCode
import groovy.transform.NullCheck
import org.commonmark.ext.front.matter.YamlFrontMatterExtension import org.commonmark.ext.front.matter.YamlFrontMatterExtension
import org.commonmark.parser.Parser import org.commonmark.parser.Parser
import org.commonmark.renderer.html.HtmlRenderer import org.commonmark.renderer.html.HtmlRenderer
@NullCheck
@EqualsAndHashCode @EqualsAndHashCode
class MarkdownTextRenderer implements TextRenderer { class MarkdownTextRenderer implements TextRenderer {
@ -14,8 +17,12 @@ class MarkdownTextRenderer implements TextRenderer {
private static final HtmlRenderer htmlRenderer = HtmlRenderer.builder().build() private static final HtmlRenderer htmlRenderer = HtmlRenderer.builder().build()
@Override @Override
String render(String text, Map globals) { Tuple2<Collection<Diagnostic>, String> render(Text text, Map globals) {
htmlRenderer.render(parser.parse(text)) try {
new Tuple2<>([], htmlRenderer.render(parser.parse(text.text)))
} catch (Exception e) {
new Tuple2<>([new Diagnostic("There was an exception while rendering ${ text.path }:\n${ e }", e)], '')
}
} }
@Override @Override

View File

@ -1,13 +1,7 @@
package com.jessebrault.ssg.text package com.jessebrault.ssg.text
import com.jessebrault.ssg.Diagnostic
interface TextRenderer { interface TextRenderer {
Tuple2<Collection<Diagnostic>, String> render(Text text, Map globals)
/**
* Renders the text from its raw form to html.
*
* @param text in raw form
* @return the rendered text in html
*/
String render(String text, Map globals)
} }

View File

@ -14,12 +14,13 @@ import com.jessebrault.ssg.text.MarkdownTextRenderer
import com.jessebrault.ssg.text.TextFileTextsProvider import com.jessebrault.ssg.text.TextFileTextsProvider
import com.jessebrault.ssg.text.TextType import com.jessebrault.ssg.text.TextType
import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Disabled
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import static org.junit.jupiter.api.Assertions.assertEquals import static org.junit.jupiter.api.Assertions.assertEquals
import static org.junit.jupiter.api.Assertions.assertTrue import static org.junit.jupiter.api.Assertions.assertTrue
class StaticSiteGeneratorTests { class SimpleStaticSiteGeneratorIntegrationTests {
private File partsDir private File partsDir
private File templatesDir private File templatesDir
@ -59,12 +60,14 @@ class StaticSiteGeneratorTests {
new File(this.textsDir, 'test.md').write('---\ntemplate: test.gsp\n---\n**Hello, World!**') new File(this.textsDir, 'test.md').write('---\ntemplate: test.gsp\n---\n**Hello, World!**')
new File(this.templatesDir, 'test.gsp').write('<%= text %>') new File(this.templatesDir, 'test.gsp').write('<%= text %>')
def buildDir = File.createTempDir() def result = this.ssg.generate([:])
this.ssg.generate(buildDir, [:])
def outFile = new File(buildDir, 'test.html') assertTrue(result.v1.size() == 0)
assertTrue(outFile.exists()) assertTrue(result.v2.size() == 1)
assertEquals('<p><strong>Hello, World!</strong></p>\n', outFile.text)
def p0 = result.v2[0]
assertEquals('test', p0.path)
assertEquals('<p><strong>Hello, World!</strong></p>\n', p0.html)
} }
@Test @Test
@ -77,26 +80,31 @@ class StaticSiteGeneratorTests {
new File(this.templatesDir, 'nested.gsp').write('<%= text %>') new File(this.templatesDir, 'nested.gsp').write('<%= text %>')
def buildDir = File.createTempDir() def result = this.ssg.generate([:])
this.ssg.generate(buildDir, [:])
def outFile = new File(new File(buildDir, 'nested'), 'nested.html') assertTrue(result.v1.size() == 0)
assertTrue(outFile.exists()) assertTrue(result.v2.size() == 1)
assertEquals('<p><strong>Hello, World!</strong></p>\n', outFile.text)
def p0 = result.v2[0]
assertEquals('nested/nested', p0.path)
assertEquals('<p><strong>Hello, World!</strong></p>\n', p0.html)
} }
@Test @Test
@Disabled('have to figure out what to do when we need just a plain text for a special page')
void outputsSpecialPage() { void outputsSpecialPage() {
new FileTreeBuilder(this.specialPagesDir).file('special.gsp', $/<%= texts.find { it.path == 'test' }.render() %>/$) new FileTreeBuilder(this.specialPagesDir).file('special.gsp', $/<%= texts.find { it.path == 'test' }.render() %>/$)
new FileTreeBuilder(this.templatesDir).file('template.gsp', '<%= 1 + 1 %>') new FileTreeBuilder(this.templatesDir).file('template.gsp', '<%= 1 + 1 %>')
new FileTreeBuilder(this.textsDir).file('test.md', '---\ntemplate: template.gsp\n---\nHello, World!') new FileTreeBuilder(this.textsDir).file('test.md', 'Hello, World!')
def buildDir = File.createTempDir() def result = this.ssg.generate([:])
this.ssg.generate(buildDir, [:])
def outFile = new File(buildDir, 'special.html') assertEquals(0, result.v1.size())
assertTrue(outFile.exists()) assertEquals(2, result.v2.size())
assertEquals('<p>Hello, World!</p>\n', outFile.text)
def p0 = result.v2[0]
assertEquals('special', p0.path)
assertEquals('<p>Hello, World!</p>\n', p0.html)
} }
} }

View File

@ -3,6 +3,7 @@ package com.jessebrault.ssg.part
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import static org.junit.jupiter.api.Assertions.assertEquals import static org.junit.jupiter.api.Assertions.assertEquals
import static org.junit.jupiter.api.Assertions.assertTrue
class GspPartRendererTests { class GspPartRendererTests {
@ -10,20 +11,26 @@ class GspPartRendererTests {
@Test @Test
void rendersWithNoBindingOrGlobals() { void rendersWithNoBindingOrGlobals() {
def r = this.renderer.render('Hello, World!', [:], [:]) def part = new Part('', null, 'Hello, World!')
assertEquals('Hello, World!', r) def r = this.renderer.render(part, [:], [:])
assertTrue(r.v1.size() == 0)
assertEquals('Hello, World!', r.v2)
} }
@Test @Test
void rendersWithBinding() { void rendersWithBinding() {
def r = this.renderer.render("<%= binding['greeting'] %>", [greeting: 'Hello, World!'], [:]) def part = new Part('', null, "<%= binding['greeting'] %>")
assertEquals('Hello, World!', r) def r = this.renderer.render(part, [greeting: 'Hello, World!'], [:])
assertTrue(r.v1.size() == 0)
assertEquals('Hello, World!', r.v2)
} }
@Test @Test
void rendersWithGlobals() { void rendersWithGlobals() {
def r = this.renderer.render("<%= globals['greeting'] %>", [:], [greeting: 'Hello, World!']) def part = new Part(null, null, "<%= globals['greeting'] %>")
assertEquals('Hello, World!', r) def r = this.renderer.render(part, [:], [greeting: 'Hello, World!'])
assertTrue(r.v1.size() == 0)
assertEquals('Hello, World!', r.v2)
} }
} }

View File

@ -13,6 +13,7 @@ import org.mockito.Mock
import org.mockito.junit.jupiter.MockitoExtension import org.mockito.junit.jupiter.MockitoExtension
import static org.junit.jupiter.api.Assertions.assertEquals import static org.junit.jupiter.api.Assertions.assertEquals
import static org.junit.jupiter.api.Assertions.assertTrue
import static org.mockito.ArgumentMatchers.any import static org.mockito.ArgumentMatchers.any
import static org.mockito.ArgumentMatchers.argThat import static org.mockito.ArgumentMatchers.argThat
import static org.mockito.Mockito.when import static org.mockito.Mockito.when
@ -24,39 +25,47 @@ class GspSpecialPageRendererTests {
@Test @Test
void rendersGlobal() { void rendersGlobal() {
def specialPage = new SpecialPage("<%= globals['greeting'] %>", null, null)
def globals = [greeting: 'Hello, World!'] def globals = [greeting: 'Hello, World!']
def r = this.renderer.render("<%= globals['greeting'] %>", [], [], globals) def r = this.renderer.render(specialPage, [], [], globals)
assertEquals('Hello, World!', r) assertTrue(r.v1.size() == 0)
assertEquals('Hello, World!', r.v2)
} }
@Test @Test
void rendersPartWithNoBinding(@Mock PartRenderer partRenderer) { void rendersPartWithNoBinding(@Mock PartRenderer partRenderer) {
when(partRenderer.render(any(), any(), any())).thenReturn('Hello, World!') when(partRenderer.render(any(), any(), any())).thenReturn(new Tuple2<>([], 'Hello, World!'))
def partType = new PartType([], partRenderer) def partType = new PartType([], partRenderer)
def part = new Part('test', partType , '') def part = new Part('test', partType , '')
def r = this.renderer.render("<%= parts['test'].render() %>", [], [part], [:]) def specialPage = new SpecialPage("<%= parts['test'].render() %>", null, null)
assertEquals('Hello, World!', r) def r = this.renderer.render(specialPage, [], [part], [:])
assertTrue(r.v1.size() == 0)
assertEquals('Hello, World!', r.v2)
} }
@Test @Test
void rendersPartWithBinding(@Mock PartRenderer partRenderer) { void rendersPartWithBinding(@Mock PartRenderer partRenderer) {
when(partRenderer.render(any(), argThat { Map m -> m.get('greeting') == 'Hello, World!'}, any())).thenReturn('Hello, World!') when(partRenderer.render(any(), argThat { Map m -> m.get('greeting') == 'Hello, World!'}, any())).thenReturn(new Tuple2<>([], 'Hello, World!'))
def partType = new PartType([], partRenderer) def partType = new PartType([], partRenderer)
def part = new Part('test', partType, '') def part = new Part('test', partType, '')
def r = this.renderer.render("<%= parts['test'].render([greeting: 'Hello, World!'])", [], [part], [:]) def specialPage = new SpecialPage("<%= parts['test'].render([greeting: 'Hello, World!'])", null, null)
assertEquals('Hello, World!', r) def r = this.renderer.render(specialPage, [], [part], [:])
assertTrue(r.v1.size() == 0)
assertEquals('Hello, World!', r.v2)
} }
@Test @Test
void rendersText(@Mock TextRenderer textRenderer, @Mock FrontMatterGetter frontMatterGetter) { void rendersText(@Mock TextRenderer textRenderer, @Mock FrontMatterGetter frontMatterGetter) {
when(textRenderer.render(any(), any())).thenReturn('<p><strong>Hello, World!</strong></p>\n') when(textRenderer.render(any(), any())).thenReturn(new Tuple2<>([], '<p><strong>Hello, World!</strong></p>\n'))
def textType = new TextType([], textRenderer, frontMatterGetter) def textType = new TextType([], textRenderer, frontMatterGetter)
def text = new Text('', 'test', textType) def text = new Text('', 'test', textType)
def r = this.renderer.render("<%= texts.find { it.path == 'test' }.render() %>", [text], [], [:]) def specialPage = new SpecialPage("<%= texts.find { it.path == 'test' }.render() %>", null, null)
assertEquals('<p><strong>Hello, World!</strong></p>\n', r) def r = this.renderer.render(specialPage, [text], [], [:])
assertTrue(r.v1.size() == 0)
assertEquals('<p><strong>Hello, World!</strong></p>\n', r.v2)
} }
} }

View File

@ -10,6 +10,7 @@ import org.mockito.Mock
import org.mockito.junit.jupiter.MockitoExtension import org.mockito.junit.jupiter.MockitoExtension
import static org.junit.jupiter.api.Assertions.assertEquals import static org.junit.jupiter.api.Assertions.assertEquals
import static org.junit.jupiter.api.Assertions.assertTrue
import static org.mockito.ArgumentMatchers.any import static org.mockito.ArgumentMatchers.any
import static org.mockito.ArgumentMatchers.argThat import static org.mockito.ArgumentMatchers.argThat
import static org.mockito.Mockito.when import static org.mockito.Mockito.when
@ -27,12 +28,13 @@ class GspTemplateRendererTests {
null null
) )
when(partRenderer.render(any(), any(), any())).thenReturn('Hello, World!') when(partRenderer.render(any(), any(), any())).thenReturn(new Tuple2<>([], 'Hello, World!'))
def partType = new PartType([], partRenderer) def partType = new PartType([], partRenderer)
def part = new Part('test', partType, null) def part = new Part('test', partType, null)
def r = this.renderer.render(template, new FrontMatter([:]), '', [part], [:]) def r = this.renderer.render(template, new FrontMatter([:]), '', [part], [:])
assertEquals('Hello, World!', r) assertTrue(r.v1.size() == 0)
assertEquals('Hello, World!', r.v2)
} }
@Test @Test
@ -43,33 +45,37 @@ class GspTemplateRendererTests {
null null
) )
when(partRenderer.render(any(), argThat { Map m -> m.get('person') == 'World' }, any())).thenReturn('Hello, World!') when(partRenderer.render(any(), argThat { Map m -> m.get('person') == 'World' }, any())).thenReturn(new Tuple2<>([], 'Hello, World!'))
def partType = new PartType([], partRenderer) def partType = new PartType([], partRenderer)
def part = new Part('greeting', partType, null) def part = new Part('greeting', partType, null)
def r = this.renderer.render(template, new FrontMatter([:]), '', [part], [:]) def r = this.renderer.render(template, new FrontMatter([:]), '', [part], [:])
assertEquals('Hello, World!', r) assertTrue(r.v1.size() == 0)
assertEquals('Hello, World!', r.v2)
} }
@Test @Test
void rendersFrontMatter() { void rendersFrontMatter() {
def template = new Template("<%= frontMatter['title'] %>", null, null) def template = new Template("<%= frontMatter['title'] %>", null, null)
def r = this.renderer.render(template, new FrontMatter([title: ['Hello!']]), '', [], [:]) def r = this.renderer.render(template, new FrontMatter([title: ['Hello!']]), '', [], [:])
assertEquals('Hello!', r) assertTrue(r.v1.size() == 0)
assertEquals('Hello!', r.v2)
} }
@Test @Test
void rendersGlobal() { void rendersGlobal() {
def template = new Template("<%= globals['test'] %>", null, null) def template = new Template("<%= globals['test'] %>", null, null)
def r = this.renderer.render(template, new FrontMatter([:]), '', [], [test: 'Hello, World!']) def r = this.renderer.render(template, new FrontMatter([:]), '', [], [test: 'Hello, World!'])
assertEquals('Hello, World!', r) assertTrue(r.v1.size() == 0)
assertEquals('Hello, World!', r.v2)
} }
@Test @Test
void rendersText() { void rendersText() {
def template = new Template('<%= text %>', null, null) def template = new Template('<%= text %>', null, null)
def r = this.renderer.render(template, new FrontMatter([:]), 'Hello, World!', [], [:]) def r = this.renderer.render(template, new FrontMatter([:]), 'Hello, World!', [], [:])
assertEquals('Hello, World!', r) assertTrue(r.v1.size() == 0)
assertEquals('Hello, World!', r.v2)
} }
} }

View File

@ -25,7 +25,7 @@ class PageTemplatesProviderTests {
def r = this.templatesProvider.getTemplates() def r = this.templatesProvider.getTemplates()
assertEquals(1, r.size()) assertEquals(1, r.size())
def t0 = r[0] def t0 = r[0]
assertEquals('test.gsp', t0.relativePath) assertEquals('test.gsp', t0.path)
assertEquals('<% out << text %>', t0.text) assertEquals('<% out << text %>', t0.text)
assertEquals(gspType, t0.type) assertEquals(gspType, t0.type)
} }
@ -41,7 +41,7 @@ class PageTemplatesProviderTests {
def r = this.templatesProvider.getTemplates() def r = this.templatesProvider.getTemplates()
assertEquals(1, r.size()) assertEquals(1, r.size())
def t0 = r[0] def t0 = r[0]
assertEquals('nested/nested.gsp', t0.relativePath) assertEquals('nested/nested.gsp', t0.path)
assertEquals('<%= text %>', t0.text) assertEquals('<%= text %>', t0.text)
assertEquals(gspType, t0.type) assertEquals(gspType, t0.type)
} }