Major refactoring and api changes.
This commit is contained in:
parent
829ec4698e
commit
27ae22d5eb
@ -102,10 +102,22 @@ class StaticSiteGeneratorCli implements Callable<Integer> {
|
||||
|
||||
// Generate
|
||||
def ssg = new SimpleStaticSiteGenerator(config)
|
||||
ssg.generate(new File('build'), globals)
|
||||
def result = ssg.generate(globals)
|
||||
|
||||
// Exit
|
||||
return 0
|
||||
if (result.v1.size() > 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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -19,6 +19,9 @@ dependencies {
|
||||
// https://mvnrepository.com/artifact/org.commonmark/commonmark-ext-yaml-front-matter
|
||||
implementation 'org.commonmark:commonmark-ext-yaml-front-matter:0.21.0'
|
||||
|
||||
/**
|
||||
* Logging
|
||||
*/
|
||||
// https://mvnrepository.com/artifact/org.slf4j/slf4j-api
|
||||
implementation 'org.slf4j:slf4j-api:1.7.36'
|
||||
|
||||
|
18
lib/src/main/groovy/com/jessebrault/ssg/Diagnostic.groovy
Normal file
18
lib/src/main/groovy/com/jessebrault/ssg/Diagnostic.groovy
Normal 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 })"
|
||||
}
|
||||
|
||||
}
|
20
lib/src/main/groovy/com/jessebrault/ssg/GeneratedPage.groovy
Normal file
20
lib/src/main/groovy/com/jessebrault/ssg/GeneratedPage.groovy
Normal 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 })"
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package com.jessebrault.ssg
|
||||
|
||||
import com.jessebrault.ssg.text.FrontMatter
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
import groovy.transform.TupleConstructor
|
||||
@ -20,8 +21,8 @@ class SimpleStaticSiteGenerator implements StaticSiteGenerator {
|
||||
private final Config config
|
||||
|
||||
@Override
|
||||
void generate(File buildDir, Map globals) {
|
||||
logger.trace(enter, 'buildDir: {}, globals: {}', buildDir, globals)
|
||||
Tuple2<Collection<Diagnostic>, Collection<GeneratedPage>> generate(Map globals) {
|
||||
logger.trace(enter, 'globals: {}', globals)
|
||||
|
||||
// Get all texts, templates, parts, and specialPages
|
||||
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)
|
||||
|
||||
// Define output function
|
||||
def outputPage = { String path, String result ->
|
||||
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)
|
||||
}
|
||||
Collection<Diagnostic> diagnostics = []
|
||||
Collection<GeneratedPage> generatedPages = []
|
||||
|
||||
// Generate pages from each text
|
||||
texts.each {
|
||||
logger.trace(enter, 'text: {}', it)
|
||||
logger.info('processing text: {}', it.path)
|
||||
|
||||
// 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
|
||||
def frontMatter = it.type.frontMatterGetter.get(it.text)
|
||||
logger.debug('frontMatter: {}', frontMatter)
|
||||
def frontMatterResult = it.type.frontMatterGetter.get(it)
|
||||
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
|
||||
def desiredTemplate = frontMatter['template']
|
||||
logger.debug('desiredTemplate name: {}', desiredTemplate)
|
||||
if (desiredTemplate == null) {
|
||||
throw new IllegalArgumentException('in text ' + it.path + ' frontMatter.template must not be null')
|
||||
if (desiredTemplate == null || desiredTemplate.isEmpty() || desiredTemplate.isBlank()) {
|
||||
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()) {
|
||||
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)
|
||||
def template = templates.find { it.path == desiredTemplate }
|
||||
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
|
||||
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
|
||||
outputPage(it.path, result)
|
||||
// Create a GeneratedPage
|
||||
generatedPages << new GeneratedPage(it.path, renderedTemplate)
|
||||
}
|
||||
|
||||
// Generate special pages
|
||||
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
|
||||
outputPage(it.path, result)
|
||||
// Create a GeneratedPage
|
||||
generatedPages << new GeneratedPage(it.path, renderedSpecialPage)
|
||||
}
|
||||
|
||||
logger.trace(exit, '')
|
||||
logger.trace(exit, '\n\tdiagnostics: {}\n\tgeneratedPages: {}', diagnostics, generatedPages)
|
||||
new Tuple2<>(diagnostics, generatedPages)
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,5 +1,5 @@
|
||||
package com.jessebrault.ssg
|
||||
|
||||
interface StaticSiteGenerator {
|
||||
void generate(File buildDir, Map globals)
|
||||
Tuple2<Collection<Diagnostic>, Collection<GeneratedPage>> generate(Map globals)
|
||||
}
|
||||
|
@ -11,9 +11,16 @@ class EmbeddablePart {
|
||||
|
||||
private final Part part
|
||||
private final Map globals
|
||||
private final Closure onDiagnostics
|
||||
|
||||
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
|
||||
|
@ -1,17 +1,18 @@
|
||||
package com.jessebrault.ssg.part
|
||||
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
|
||||
@NullCheck
|
||||
@EqualsAndHashCode(includeFields = true)
|
||||
class EmbeddablePartsMap {
|
||||
|
||||
@Delegate
|
||||
private final Map<String, EmbeddablePart> partsMap = [:]
|
||||
|
||||
EmbeddablePartsMap(Collection<Part> parts, Map globals) {
|
||||
Objects.requireNonNull(parts)
|
||||
EmbeddablePartsMap(Collection<Part> parts, Map globals, Closure onDiagnostics) {
|
||||
parts.each {
|
||||
this.put(it.path, new EmbeddablePart(it, globals))
|
||||
this.put(it.path, new EmbeddablePart(it, globals, onDiagnostics))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.jessebrault.ssg.part
|
||||
|
||||
import com.jessebrault.ssg.Diagnostic
|
||||
import groovy.text.GStringTemplateEngine
|
||||
import groovy.text.TemplateEngine
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
@ -10,11 +11,16 @@ class GspPartRenderer implements PartRenderer {
|
||||
private static final TemplateEngine engine = new GStringTemplateEngine()
|
||||
|
||||
@Override
|
||||
String render(String partText, Map binding, Map globals) {
|
||||
engine.createTemplate(partText).make([
|
||||
binding: binding,
|
||||
globals: globals
|
||||
])
|
||||
Tuple2<Collection<Diagnostic>, String> render(Part part, Map binding, Map globals) {
|
||||
try {
|
||||
def result = engine.createTemplate(part.text).make([
|
||||
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
|
||||
|
@ -1,5 +1,7 @@
|
||||
package com.jessebrault.ssg.part
|
||||
|
||||
import com.jessebrault.ssg.Diagnostic
|
||||
|
||||
interface PartRenderer {
|
||||
String render(String partText, Map binding, Map globals)
|
||||
Tuple2<Collection<Diagnostic>, String> render(Part part, Map binding, Map globals)
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.jessebrault.ssg.specialpage
|
||||
|
||||
import com.jessebrault.ssg.Diagnostic
|
||||
import com.jessebrault.ssg.part.Part
|
||||
import com.jessebrault.ssg.part.EmbeddablePartsMap
|
||||
import com.jessebrault.ssg.text.EmbeddableTextsCollection
|
||||
@ -7,24 +8,31 @@ import com.jessebrault.ssg.text.Text
|
||||
import groovy.text.GStringTemplateEngine
|
||||
import groovy.text.TemplateEngine
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
|
||||
@NullCheck
|
||||
@EqualsAndHashCode
|
||||
class GspSpecialPageRenderer implements SpecialPageRenderer {
|
||||
|
||||
private static final TemplateEngine engine = new GStringTemplateEngine()
|
||||
|
||||
@Override
|
||||
String render(String text, Collection<Text> texts, Collection<Part> parts, Map globals) {
|
||||
Objects.requireNonNull(text)
|
||||
Objects.requireNonNull(texts)
|
||||
Objects.requireNonNull(parts)
|
||||
Objects.requireNonNull(globals)
|
||||
|
||||
engine.createTemplate(text).make([
|
||||
globals: globals,
|
||||
parts: new EmbeddablePartsMap(parts, globals),
|
||||
texts: new EmbeddableTextsCollection(texts, globals)
|
||||
])
|
||||
Tuple2<Collection<Diagnostic>, String> render(SpecialPage specialPage, Collection<Text> texts, Collection<Part> parts, Map globals) {
|
||||
try {
|
||||
Collection<Diagnostic> diagnostics = []
|
||||
def result = engine.createTemplate(specialPage.text).make([
|
||||
globals: globals,
|
||||
parts: new EmbeddablePartsMap(parts, globals, { Collection<Diagnostic> partDiagnostics ->
|
||||
diagnostics.addAll(partDiagnostics)
|
||||
}),
|
||||
texts: new EmbeddableTextsCollection(texts, globals, { Collection<Diagnostic> textDiagnostics ->
|
||||
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
|
||||
|
@ -1,12 +1,13 @@
|
||||
package com.jessebrault.ssg.specialpage
|
||||
|
||||
import com.jessebrault.ssg.Diagnostic
|
||||
import com.jessebrault.ssg.part.Part
|
||||
import com.jessebrault.ssg.text.Text
|
||||
|
||||
interface SpecialPageRenderer {
|
||||
|
||||
String render(
|
||||
String text,
|
||||
Tuple2<Collection<Diagnostic>, String> render(
|
||||
SpecialPage specialPage,
|
||||
Collection<Text> texts,
|
||||
Collection <Part> parts,
|
||||
Map globals
|
||||
|
@ -1,31 +1,42 @@
|
||||
package com.jessebrault.ssg.template
|
||||
|
||||
import com.jessebrault.ssg.Diagnostic
|
||||
import com.jessebrault.ssg.part.Part
|
||||
import com.jessebrault.ssg.part.EmbeddablePartsMap
|
||||
import com.jessebrault.ssg.text.FrontMatter
|
||||
import groovy.text.GStringTemplateEngine
|
||||
import groovy.text.TemplateEngine
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
|
||||
@NullCheck
|
||||
@EqualsAndHashCode
|
||||
class GspTemplateRenderer implements TemplateRenderer {
|
||||
|
||||
private static final TemplateEngine engine = new GStringTemplateEngine()
|
||||
|
||||
@Override
|
||||
String render(
|
||||
Tuple2<Collection<Diagnostic>, String> render(
|
||||
Template template,
|
||||
FrontMatter frontMatter,
|
||||
String text,
|
||||
Collection<Part> parts,
|
||||
Map globals
|
||||
) {
|
||||
engine.createTemplate(template.text).make([
|
||||
frontMatter: frontMatter,
|
||||
globals: globals,
|
||||
parts: new EmbeddablePartsMap(parts, globals),
|
||||
text: text
|
||||
])
|
||||
try {
|
||||
Collection<Diagnostic> diagnostics = []
|
||||
def result = engine.createTemplate(template.text).make([
|
||||
frontMatter: frontMatter,
|
||||
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
|
||||
|
@ -10,12 +10,12 @@ import groovy.transform.TupleConstructor
|
||||
class Template {
|
||||
|
||||
String text
|
||||
String relativePath
|
||||
String path
|
||||
TemplateType type
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
"Template(path: ${ this.relativePath }, type: ${ this.type })"
|
||||
"Template(path: ${ this.path }, type: ${ this.type })"
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,11 +1,12 @@
|
||||
package com.jessebrault.ssg.template
|
||||
|
||||
import com.jessebrault.ssg.Diagnostic
|
||||
import com.jessebrault.ssg.part.Part
|
||||
import com.jessebrault.ssg.text.FrontMatter
|
||||
|
||||
interface TemplateRenderer {
|
||||
|
||||
String render(
|
||||
Tuple2<Collection<Diagnostic>, String> render(
|
||||
Template template,
|
||||
FrontMatter frontMatter,
|
||||
String text,
|
||||
|
@ -8,19 +8,32 @@ import groovy.transform.TupleConstructor
|
||||
@TupleConstructor(includeFields = true, defaults = false)
|
||||
@NullCheck
|
||||
@EqualsAndHashCode(includeFields = true)
|
||||
class EmbeddableText {
|
||||
class EmbeddableText {
|
||||
|
||||
private final Text text
|
||||
private final Map globals
|
||||
private final Closure onDiagnostics
|
||||
|
||||
@Memoized
|
||||
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
|
||||
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() {
|
||||
|
@ -1,16 +1,18 @@
|
||||
package com.jessebrault.ssg.text
|
||||
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
|
||||
@NullCheck
|
||||
@EqualsAndHashCode(includeFields = true)
|
||||
class EmbeddableTextsCollection {
|
||||
|
||||
@Delegate
|
||||
private final Collection<EmbeddableText> embeddableTexts = []
|
||||
|
||||
EmbeddableTextsCollection(Collection<Text> texts, Map globals) {
|
||||
EmbeddableTextsCollection(Collection<Text> texts, Map globals, Closure onDiagnostics) {
|
||||
Objects.requireNonNull(texts).each {
|
||||
this << new EmbeddableText(it, globals)
|
||||
this << new EmbeddableText(it, globals, onDiagnostics)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
package com.jessebrault.ssg.text
|
||||
|
||||
import com.jessebrault.ssg.Diagnostic
|
||||
|
||||
interface FrontMatterGetter {
|
||||
FrontMatter get(String text)
|
||||
Tuple2<Collection<Diagnostic>, FrontMatter> get(Text text)
|
||||
}
|
||||
|
@ -1,10 +1,13 @@
|
||||
package com.jessebrault.ssg.text
|
||||
|
||||
import com.jessebrault.ssg.Diagnostic
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
import org.commonmark.ext.front.matter.YamlFrontMatterExtension
|
||||
import org.commonmark.ext.front.matter.YamlFrontMatterVisitor
|
||||
import org.commonmark.parser.Parser
|
||||
|
||||
@NullCheck
|
||||
@EqualsAndHashCode
|
||||
class MarkdownFrontMatterGetter implements FrontMatterGetter {
|
||||
|
||||
@ -13,11 +16,15 @@ class MarkdownFrontMatterGetter implements FrontMatterGetter {
|
||||
.build()
|
||||
|
||||
@Override
|
||||
FrontMatter get(String text) {
|
||||
def node = parser.parse(text)
|
||||
def v = new YamlFrontMatterVisitor()
|
||||
node.accept(v)
|
||||
new FrontMatter(v.data)
|
||||
Tuple2<Collection<Diagnostic>, FrontMatter> get(Text text) {
|
||||
try {
|
||||
def node = parser.parse(text.text)
|
||||
def v = new YamlFrontMatterVisitor()
|
||||
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
|
||||
|
@ -1,10 +1,13 @@
|
||||
package com.jessebrault.ssg.text
|
||||
|
||||
import com.jessebrault.ssg.Diagnostic
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
import org.commonmark.ext.front.matter.YamlFrontMatterExtension
|
||||
import org.commonmark.parser.Parser
|
||||
import org.commonmark.renderer.html.HtmlRenderer
|
||||
|
||||
@NullCheck
|
||||
@EqualsAndHashCode
|
||||
class MarkdownTextRenderer implements TextRenderer {
|
||||
|
||||
@ -14,8 +17,12 @@ class MarkdownTextRenderer implements TextRenderer {
|
||||
private static final HtmlRenderer htmlRenderer = HtmlRenderer.builder().build()
|
||||
|
||||
@Override
|
||||
String render(String text, Map globals) {
|
||||
htmlRenderer.render(parser.parse(text))
|
||||
Tuple2<Collection<Diagnostic>, String> render(Text text, Map globals) {
|
||||
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
|
||||
|
@ -1,13 +1,7 @@
|
||||
package com.jessebrault.ssg.text
|
||||
|
||||
import com.jessebrault.ssg.Diagnostic
|
||||
|
||||
interface TextRenderer {
|
||||
|
||||
/**
|
||||
* 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)
|
||||
|
||||
Tuple2<Collection<Diagnostic>, String> render(Text text, Map globals)
|
||||
}
|
||||
|
@ -14,12 +14,13 @@ import com.jessebrault.ssg.text.MarkdownTextRenderer
|
||||
import com.jessebrault.ssg.text.TextFileTextsProvider
|
||||
import com.jessebrault.ssg.text.TextType
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Disabled
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue
|
||||
|
||||
class StaticSiteGeneratorTests {
|
||||
class SimpleStaticSiteGeneratorIntegrationTests {
|
||||
|
||||
private File partsDir
|
||||
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.templatesDir, 'test.gsp').write('<%= text %>')
|
||||
|
||||
def buildDir = File.createTempDir()
|
||||
this.ssg.generate(buildDir, [:])
|
||||
def result = this.ssg.generate([:])
|
||||
|
||||
def outFile = new File(buildDir, 'test.html')
|
||||
assertTrue(outFile.exists())
|
||||
assertEquals('<p><strong>Hello, World!</strong></p>\n', outFile.text)
|
||||
assertTrue(result.v1.size() == 0)
|
||||
assertTrue(result.v2.size() == 1)
|
||||
|
||||
def p0 = result.v2[0]
|
||||
assertEquals('test', p0.path)
|
||||
assertEquals('<p><strong>Hello, World!</strong></p>\n', p0.html)
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -77,26 +80,31 @@ class StaticSiteGeneratorTests {
|
||||
|
||||
new File(this.templatesDir, 'nested.gsp').write('<%= text %>')
|
||||
|
||||
def buildDir = File.createTempDir()
|
||||
this.ssg.generate(buildDir, [:])
|
||||
def result = this.ssg.generate([:])
|
||||
|
||||
def outFile = new File(new File(buildDir, 'nested'), 'nested.html')
|
||||
assertTrue(outFile.exists())
|
||||
assertEquals('<p><strong>Hello, World!</strong></p>\n', outFile.text)
|
||||
assertTrue(result.v1.size() == 0)
|
||||
assertTrue(result.v2.size() == 1)
|
||||
|
||||
def p0 = result.v2[0]
|
||||
assertEquals('nested/nested', p0.path)
|
||||
assertEquals('<p><strong>Hello, World!</strong></p>\n', p0.html)
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled('have to figure out what to do when we need just a plain text for a special page')
|
||||
void outputsSpecialPage() {
|
||||
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.textsDir).file('test.md', '---\ntemplate: template.gsp\n---\nHello, World!')
|
||||
new FileTreeBuilder(this.textsDir).file('test.md', 'Hello, World!')
|
||||
|
||||
def buildDir = File.createTempDir()
|
||||
this.ssg.generate(buildDir, [:])
|
||||
def result = this.ssg.generate([:])
|
||||
|
||||
def outFile = new File(buildDir, 'special.html')
|
||||
assertTrue(outFile.exists())
|
||||
assertEquals('<p>Hello, World!</p>\n', outFile.text)
|
||||
assertEquals(0, result.v1.size())
|
||||
assertEquals(2, result.v2.size())
|
||||
|
||||
def p0 = result.v2[0]
|
||||
assertEquals('special', p0.path)
|
||||
assertEquals('<p>Hello, World!</p>\n', p0.html)
|
||||
}
|
||||
|
||||
}
|
@ -3,6 +3,7 @@ package com.jessebrault.ssg.part
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue
|
||||
|
||||
class GspPartRendererTests {
|
||||
|
||||
@ -10,20 +11,26 @@ class GspPartRendererTests {
|
||||
|
||||
@Test
|
||||
void rendersWithNoBindingOrGlobals() {
|
||||
def r = this.renderer.render('Hello, World!', [:], [:])
|
||||
assertEquals('Hello, World!', r)
|
||||
def part = new Part('', null, 'Hello, World!')
|
||||
def r = this.renderer.render(part, [:], [:])
|
||||
assertTrue(r.v1.size() == 0)
|
||||
assertEquals('Hello, World!', r.v2)
|
||||
}
|
||||
|
||||
@Test
|
||||
void rendersWithBinding() {
|
||||
def r = this.renderer.render("<%= binding['greeting'] %>", [greeting: 'Hello, World!'], [:])
|
||||
assertEquals('Hello, World!', r)
|
||||
def part = new Part('', null, "<%= binding['greeting'] %>")
|
||||
def r = this.renderer.render(part, [greeting: 'Hello, World!'], [:])
|
||||
assertTrue(r.v1.size() == 0)
|
||||
assertEquals('Hello, World!', r.v2)
|
||||
}
|
||||
|
||||
@Test
|
||||
void rendersWithGlobals() {
|
||||
def r = this.renderer.render("<%= globals['greeting'] %>", [:], [greeting: 'Hello, World!'])
|
||||
assertEquals('Hello, World!', r)
|
||||
def part = new Part(null, null, "<%= globals['greeting'] %>")
|
||||
def r = this.renderer.render(part, [:], [greeting: 'Hello, World!'])
|
||||
assertTrue(r.v1.size() == 0)
|
||||
assertEquals('Hello, World!', r.v2)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import org.mockito.Mock
|
||||
import org.mockito.junit.jupiter.MockitoExtension
|
||||
|
||||
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.argThat
|
||||
import static org.mockito.Mockito.when
|
||||
@ -24,39 +25,47 @@ class GspSpecialPageRendererTests {
|
||||
|
||||
@Test
|
||||
void rendersGlobal() {
|
||||
def specialPage = new SpecialPage("<%= globals['greeting'] %>", null, null)
|
||||
def globals = [greeting: 'Hello, World!']
|
||||
def r = this.renderer.render("<%= globals['greeting'] %>", [], [], globals)
|
||||
assertEquals('Hello, World!', r)
|
||||
def r = this.renderer.render(specialPage, [], [], globals)
|
||||
assertTrue(r.v1.size() == 0)
|
||||
assertEquals('Hello, World!', r.v2)
|
||||
}
|
||||
|
||||
@Test
|
||||
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 part = new Part('test', partType , '')
|
||||
|
||||
def r = this.renderer.render("<%= parts['test'].render() %>", [], [part], [:])
|
||||
assertEquals('Hello, World!', r)
|
||||
def specialPage = new SpecialPage("<%= parts['test'].render() %>", null, null)
|
||||
def r = this.renderer.render(specialPage, [], [part], [:])
|
||||
assertTrue(r.v1.size() == 0)
|
||||
assertEquals('Hello, World!', r.v2)
|
||||
}
|
||||
|
||||
@Test
|
||||
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 part = new Part('test', partType, '')
|
||||
|
||||
def r = this.renderer.render("<%= parts['test'].render([greeting: 'Hello, World!'])", [], [part], [:])
|
||||
assertEquals('Hello, World!', r)
|
||||
def specialPage = new SpecialPage("<%= parts['test'].render([greeting: 'Hello, World!'])", null, null)
|
||||
def r = this.renderer.render(specialPage, [], [part], [:])
|
||||
assertTrue(r.v1.size() == 0)
|
||||
assertEquals('Hello, World!', r.v2)
|
||||
}
|
||||
|
||||
@Test
|
||||
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 text = new Text('', 'test', textType)
|
||||
|
||||
def r = this.renderer.render("<%= texts.find { it.path == 'test' }.render() %>", [text], [], [:])
|
||||
assertEquals('<p><strong>Hello, World!</strong></p>\n', r)
|
||||
def specialPage = new SpecialPage("<%= texts.find { it.path == 'test' }.render() %>", null, null)
|
||||
def r = this.renderer.render(specialPage, [text], [], [:])
|
||||
assertTrue(r.v1.size() == 0)
|
||||
assertEquals('<p><strong>Hello, World!</strong></p>\n', r.v2)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import org.mockito.Mock
|
||||
import org.mockito.junit.jupiter.MockitoExtension
|
||||
|
||||
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.argThat
|
||||
import static org.mockito.Mockito.when
|
||||
@ -27,12 +28,13 @@ class GspTemplateRendererTests {
|
||||
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 part = new Part('test', partType, null)
|
||||
|
||||
def r = this.renderer.render(template, new FrontMatter([:]), '', [part], [:])
|
||||
assertEquals('Hello, World!', r)
|
||||
assertTrue(r.v1.size() == 0)
|
||||
assertEquals('Hello, World!', r.v2)
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -43,33 +45,37 @@ class GspTemplateRendererTests {
|
||||
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 part = new Part('greeting', partType, null)
|
||||
|
||||
def r = this.renderer.render(template, new FrontMatter([:]), '', [part], [:])
|
||||
assertEquals('Hello, World!', r)
|
||||
assertTrue(r.v1.size() == 0)
|
||||
assertEquals('Hello, World!', r.v2)
|
||||
}
|
||||
|
||||
@Test
|
||||
void rendersFrontMatter() {
|
||||
def template = new Template("<%= frontMatter['title'] %>", null, null)
|
||||
def r = this.renderer.render(template, new FrontMatter([title: ['Hello!']]), '', [], [:])
|
||||
assertEquals('Hello!', r)
|
||||
assertTrue(r.v1.size() == 0)
|
||||
assertEquals('Hello!', r.v2)
|
||||
}
|
||||
|
||||
@Test
|
||||
void rendersGlobal() {
|
||||
def template = new Template("<%= globals['test'] %>", null, null)
|
||||
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
|
||||
void rendersText() {
|
||||
def template = new Template('<%= text %>', null, null)
|
||||
def r = this.renderer.render(template, new FrontMatter([:]), 'Hello, World!', [], [:])
|
||||
assertEquals('Hello, World!', r)
|
||||
assertTrue(r.v1.size() == 0)
|
||||
assertEquals('Hello, World!', r.v2)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ class PageTemplatesProviderTests {
|
||||
def r = this.templatesProvider.getTemplates()
|
||||
assertEquals(1, r.size())
|
||||
def t0 = r[0]
|
||||
assertEquals('test.gsp', t0.relativePath)
|
||||
assertEquals('test.gsp', t0.path)
|
||||
assertEquals('<% out << text %>', t0.text)
|
||||
assertEquals(gspType, t0.type)
|
||||
}
|
||||
@ -41,7 +41,7 @@ class PageTemplatesProviderTests {
|
||||
def r = this.templatesProvider.getTemplates()
|
||||
assertEquals(1, r.size())
|
||||
def t0 = r[0]
|
||||
assertEquals('nested/nested.gsp', t0.relativePath)
|
||||
assertEquals('nested/nested.gsp', t0.path)
|
||||
assertEquals('<%= text %>', t0.text)
|
||||
assertEquals(gspType, t0.type)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user