More refactoring, added parts.

This commit is contained in:
JesseBrault0709 2023-01-04 20:29:46 -06:00
parent c91700aecd
commit 5b2f83898d
46 changed files with 678 additions and 401 deletions

View File

@ -1,31 +1,39 @@
package com.jessebrault.ssg
import com.jessebrault.ssg.pagetemplate.GspRenderer
import com.jessebrault.ssg.pagetemplate.PageTemplateType
import com.jessebrault.ssg.pagetemplate.PageTemplatesFactoryImpl
import com.jessebrault.ssg.part.GspPartRenderer
import com.jessebrault.ssg.part.PartFilePartsProvider
import com.jessebrault.ssg.part.PartType
import com.jessebrault.ssg.template.GspTemplateRenderer
import com.jessebrault.ssg.template.TemplateType
import com.jessebrault.ssg.template.TemplateFileTemplatesProvider
import com.jessebrault.ssg.text.MarkdownFrontMatterGetter
import com.jessebrault.ssg.text.MarkdownRenderer
import com.jessebrault.ssg.text.TextFileType
import com.jessebrault.ssg.text.TextFilesFactoryImpl
import com.jessebrault.ssg.text.MarkdownTextRenderer
import com.jessebrault.ssg.text.TextType
import com.jessebrault.ssg.text.TextFileTextsProvider
class StaticSiteGeneratorCli {
static void main(String[] args) {
def markdown = new TextFileType(['.md'], new MarkdownRenderer(), new MarkdownFrontMatterGetter())
def gsp = new PageTemplateType(['.gsp'], new GspRenderer())
def markdownText = new TextType(['.md'], new MarkdownTextRenderer(), new MarkdownFrontMatterGetter())
def gspTemplate = new TemplateType(['.gsp'], new GspTemplateRenderer())
def gspPart = new PartType(['.gsp'], new GspPartRenderer())
def config = new Config(
textFileTypes: [markdown],
pageTemplateTypes: [gsp],
textFileFactoryGetter: { Config config -> new TextFilesFactoryImpl(config.textFileTypes) },
pageTemplatesFactoryGetter: { Config config -> new PageTemplatesFactoryImpl(config.pageTemplateTypes) }
)
def ssg = new StaticSiteGeneratorImpl(config)
def defaultSpec = new SiteSpec(
buildDir: new File('build'),
textTypes: [markdownText],
templateTypes: [gspTemplate],
partTypes: [gspPart],
textsDir: new File('texts'),
templatesDir: new File('templates')
templatesDir: new File('templates'),
partsDir: new File('parts'),
textsProviderGetter: { Config config -> new TextFileTextsProvider(config.textTypes, config.textsDir) },
templatesProviderGetter: { Config config -> new TemplateFileTemplatesProvider(config.templateTypes, config.templatesDir) },
partsProviderGetter: { Config config -> new PartFilePartsProvider(config.partTypes, config.partsDir) }
)
ssg.generate(defaultSpec)
def ssg = new SimpleStaticSiteGenerator(config)
ssg.generate(new File('build'))
}
}

View File

@ -1,20 +1,30 @@
package com.jessebrault.ssg
import com.jessebrault.ssg.pagetemplate.PageTemplateType
import com.jessebrault.ssg.pagetemplate.PageTemplatesFactory
import com.jessebrault.ssg.text.TextFileType
import com.jessebrault.ssg.text.TextFilesFactory
import com.jessebrault.ssg.part.PartType
import com.jessebrault.ssg.part.PartsProvider
import com.jessebrault.ssg.template.TemplateType
import com.jessebrault.ssg.template.TemplatesProvider
import com.jessebrault.ssg.text.TextType
import com.jessebrault.ssg.text.TextsProvider
import groovy.transform.Canonical
import groovy.transform.MapConstructor
import groovy.transform.NullCheck
import java.util.function.Function
@Canonical
@MapConstructor
@NullCheck
class Config {
Collection<TextFileType> textFileTypes
Collection<PageTemplateType> pageTemplateTypes
Collection<TextType> textTypes
Collection<TemplateType> templateTypes
Collection<PartType> partTypes
Function<Config, TextFilesFactory> textFileFactoryGetter
Function<Config, PageTemplatesFactory> pageTemplatesFactoryGetter
File textsDir
File templatesDir
File partsDir
Function<Config, TextsProvider> textsProviderGetter
Function<Config, TemplatesProvider> templatesProviderGetter
Function<Config, PartsProvider> partsProviderGetter
}

View File

@ -0,0 +1,81 @@
package com.jessebrault.ssg
import com.jessebrault.ssg.part.PartsProvider
import com.jessebrault.ssg.template.TemplatesProvider
import com.jessebrault.ssg.text.TextsProvider
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.slf4j.Marker
import org.slf4j.MarkerFactory
class SimpleStaticSiteGenerator implements StaticSiteGenerator {
private static final Logger logger = LoggerFactory.getLogger(SimpleStaticSiteGenerator)
private static final Marker enter = MarkerFactory.getMarker('ENTER')
private static final Marker exit = MarkerFactory.getMarker('EXIT')
private final Config config
private final TextsProvider textsProvider
private final TemplatesProvider templatesProvider
private final PartsProvider partsProvider
SimpleStaticSiteGenerator(Config config) {
this.config = config
this.textsProvider = config.textsProviderGetter.apply(config)
this.templatesProvider = config.templatesProviderGetter.apply(config)
this.partsProvider = config.partsProviderGetter.apply(config)
}
@Override
void generate(File buildDir) {
logger.trace(enter, 'buildDir: {}', buildDir)
// Get all texts, templates, and parts
def texts = this.textsProvider.getTextFiles()
def templates = this.templatesProvider.getTemplates()
def parts = this.partsProvider.getParts()
logger.debug('texts: {}, templates: {}, parts: {}', texts, templates, parts)
texts.each {
logger.info('processing text: {}', it.path)
// Render the text (i.e., transform text to html)
def renderedText = it.type.renderer.render(it.text)
logger.debug('renderedText: {}', renderedText)
// Extract frontMatter from text
def frontMatter = it.type.frontMatterGetter.get(it.text)
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')
}
def template = templates.find {
it.relativePath == desiredTemplate
}
logger.debug('template: {}', template)
if (template == null) {
throw new IllegalArgumentException('in textFile' + it.path + ' unknown template: ' + desiredTemplate)
}
// Render the template using the result of rendering the text earlier
def result = template.type.renderer.render(template, renderedText, parts)
logger.debug('result: {}', result)
// Output the result to the outfile, an .html file
def outFile = new File(buildDir, it.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)
}
logger.trace(exit, '')
}
}

View File

@ -1,14 +0,0 @@
package com.jessebrault.ssg
import groovy.transform.Canonical
import groovy.transform.MapConstructor
@Canonical
@MapConstructor
class SiteSpec {
File buildDir
File staticDir
File textsDir
File templatesDir
File templatePartsDir
}

View File

@ -1,5 +1,5 @@
package com.jessebrault.ssg
interface StaticSiteGenerator {
void generate(SiteSpec spec)
void generate(File buildDir)
}

View File

@ -1,79 +0,0 @@
package com.jessebrault.ssg
import com.jessebrault.ssg.pagetemplate.PageTemplatesFactory
import com.jessebrault.ssg.text.TextFilesFactory
import com.jessebrault.ssg.util.FileNameHandler
import com.jessebrault.ssg.util.RelativePathHandler
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.slf4j.Marker
import org.slf4j.MarkerFactory
class StaticSiteGeneratorImpl implements StaticSiteGenerator {
private static final Logger logger = LoggerFactory.getLogger(StaticSiteGeneratorImpl)
private static final Marker enter = MarkerFactory.getMarker('ENTER')
private static final Marker exit = MarkerFactory.getMarker('EXIT')
private final Config config
private final TextFilesFactory textFilesFactory
private final PageTemplatesFactory pageTemplatesFactory
StaticSiteGeneratorImpl(Config config) {
this.config = config
this.textFilesFactory = config.textFileFactoryGetter.apply(config)
this.pageTemplatesFactory = config.pageTemplatesFactoryGetter.apply(config)
}
@Override
void generate(SiteSpec spec) {
logger.trace(enter, 'spec: {}', spec)
def textFiles = this.textFilesFactory.getTextFiles(spec.textsDir)
def pageTemplates = this.pageTemplatesFactory.getTemplates(spec.templatesDir)
logger.debug('textFiles: {}, pageTemplates: {}', textFiles, pageTemplates)
textFiles.each {
logger.info('processing textFile: {}', it.relativePath)
def fileNameHandler = new FileNameHandler(it.file)
def textFileType = this.config.textFileTypes.find {
it.extensions.contains(fileNameHandler.getExtension())
}
logger.debug('textFileType: {}', textFileType)
if (textFileType == null) {
throw new IllegalArgumentException('unknown textFile type: ' + it.relativePath)
}
def renderedText = textFileType.renderer.render(it.file.text)
logger.debug('renderedText: {}', renderedText)
def frontMatter = textFileType.frontMatterGetter.get(it.file.text)
logger.debug('frontMatter: {}', frontMatter)
def desiredPageTemplate = frontMatter['template']
logger.debug('desiredPageTemplate name: {}', desiredPageTemplate)
if (desiredPageTemplate == null) {
throw new IllegalArgumentException('in textFile ' + it.relativePath + ' template must not be null')
}
def pageTemplate = pageTemplates.find {
it.relativePath == desiredPageTemplate
}
logger.debug('pageTemplate: {}', pageTemplate)
if (pageTemplate == null) {
throw new IllegalArgumentException('in textFile' + it.relativePath + ' unknown pageTemplate: ' + desiredPageTemplate)
}
def result = pageTemplate.type.renderer.render(pageTemplate, renderedText)
logger.debug('result: {}', result)
def outFile = new File(spec.buildDir, new RelativePathHandler(it.relativePath).getWithoutExtension() + '.html')
if (outFile.exists()) {
logger.info('outFile {} already exists, deleting', outFile)
outFile.delete()
}
outFile.createParentDirectories()
logger.info('writing result to {}', outFile)
outFile.write(result)
}
logger.trace(exit, '')
}
}

View File

@ -1,18 +0,0 @@
package com.jessebrault.ssg.pagetemplate
import groovy.text.GStringTemplateEngine
import groovy.text.TemplateEngine
class GspRenderer implements PageRenderer {
private static final TemplateEngine engine = new GStringTemplateEngine()
@Override
String render(PageTemplate template, String text) {
engine.createTemplate(template.file.text).make([
text: text
])
}
}

View File

@ -1,5 +0,0 @@
package com.jessebrault.ssg.pagetemplate
interface PageRenderer {
String render(PageTemplate template, String text)
}

View File

@ -1,10 +0,0 @@
package com.jessebrault.ssg.pagetemplate
import groovy.transform.Canonical
@Canonical
class PageTemplate {
File file
String relativePath
PageTemplateType type
}

View File

@ -1,9 +0,0 @@
package com.jessebrault.ssg.pagetemplate
import groovy.transform.Canonical
@Canonical
class PageTemplateType {
Collection<String> extensions
PageRenderer renderer
}

View File

@ -1,5 +0,0 @@
package com.jessebrault.ssg.pagetemplate
interface PageTemplatesFactory {
Collection<PageTemplate> getTemplates(File templatesDir)
}

View File

@ -0,0 +1,15 @@
package com.jessebrault.ssg.part
import groovy.text.GStringTemplateEngine
import groovy.text.TemplateEngine
class GspPartRenderer implements PartRenderer {
private static final TemplateEngine engine = new GStringTemplateEngine()
@Override
String render(String partText, Map binding) {
engine.createTemplate(partText).make(binding)
}
}

View File

@ -0,0 +1,14 @@
package com.jessebrault.ssg.part
import groovy.transform.Canonical
import groovy.transform.NullCheck
import groovy.transform.TupleConstructor
@Canonical
@TupleConstructor(defaults = false)
@NullCheck
class Part {
String name
PartType type
String text
}

View File

@ -0,0 +1,44 @@
package com.jessebrault.ssg.part
import com.jessebrault.ssg.util.FileNameHandler
import groovy.transform.NullCheck
import groovy.transform.TupleConstructor
import org.slf4j.Logger
import org.slf4j.LoggerFactory
@TupleConstructor(includeFields = true, defaults = false)
@NullCheck
class PartFilePartsProvider implements PartsProvider {
private static final Logger logger = LoggerFactory.getLogger(PartFilePartsProvider)
private final Collection<PartType> partTypes
private final File partsDir
private PartType getPartType(File file) {
partTypes.find {
it.extensions.contains(new FileNameHandler(file).getExtension())
}
}
@Override
Collection<Part> getParts() {
if (!partsDir.isDirectory()) {
throw new IllegalArgumentException('partsDir must be a directory')
}
def parts = []
partsDir.eachFileRecurse {
if (it.isFile()) {
def type = this.getPartType(it)
if (type != null) {
def relativePath = this.partsDir.relativePath(it)
logger.debug('found part {}', relativePath)
parts << new Part(relativePath, type, it.text)
}
}
}
parts
}
}

View File

@ -0,0 +1,5 @@
package com.jessebrault.ssg.part
interface PartRenderer {
String render(String partText, Map binding)
}

View File

@ -0,0 +1,13 @@
package com.jessebrault.ssg.part
import groovy.transform.Canonical
import groovy.transform.NullCheck
import groovy.transform.TupleConstructor
@Canonical
@TupleConstructor(defaults = false)
@NullCheck
class PartType {
Collection<String> extensions
PartRenderer renderer
}

View File

@ -0,0 +1,35 @@
package com.jessebrault.ssg.part
import groovy.transform.TupleConstructor
class PartsMap {
@TupleConstructor(includeFields = true, defaults = false)
class RenderingPart {
private final Part part
String render(Map binding) {
part.type.renderer.render(part.text, binding)
}
}
private final Map<String, RenderingPart> partsMap = new LinkedHashMap<>()
PartsMap(Collection<Part> parts) {
Objects.requireNonNull(parts)
parts.each {
this.partsMap.put(it.name, new RenderingPart(it))
}
}
RenderingPart get(String name) {
this.partsMap.get(Objects.requireNonNull(name))
}
RenderingPart getAt(String name) {
this.get(Objects.requireNonNull(name))
}
}

View File

@ -0,0 +1,5 @@
package com.jessebrault.ssg.part
interface PartsProvider {
Collection<Part> getParts()
}

View File

@ -0,0 +1,20 @@
package com.jessebrault.ssg.template
import com.jessebrault.ssg.part.Part
import com.jessebrault.ssg.part.PartsMap
import groovy.text.GStringTemplateEngine
import groovy.text.TemplateEngine
class GspTemplateRenderer implements TemplateRenderer {
private static final TemplateEngine engine = new GStringTemplateEngine()
@Override
String render(Template template, String text, Collection<Part> parts) {
engine.createTemplate(template.text).make([
text: text,
parts: new PartsMap(parts)
])
}
}

View File

@ -0,0 +1,14 @@
package com.jessebrault.ssg.template
import groovy.transform.Canonical
import groovy.transform.NullCheck
import groovy.transform.TupleConstructor
@Canonical
@TupleConstructor(defaults = false)
@NullCheck
class Template {
String text
String relativePath
TemplateType type
}

View File

@ -1,36 +1,39 @@
package com.jessebrault.ssg.pagetemplate
package com.jessebrault.ssg.template
import com.jessebrault.ssg.util.FileNameHandler
import groovy.transform.NullCheck
import groovy.transform.TupleConstructor
import org.slf4j.Logger
import org.slf4j.LoggerFactory
@TupleConstructor(includeFields = true)
class PageTemplatesFactoryImpl implements PageTemplatesFactory {
@TupleConstructor(includeFields = true, defaults = false)
@NullCheck
class TemplateFileTemplatesProvider implements TemplatesProvider {
private static final Logger logger = LoggerFactory.getLogger(PageTemplatesFactoryImpl)
private static final Logger logger = LoggerFactory.getLogger(TemplateFileTemplatesProvider)
private final Collection<PageTemplateType> types
private final Collection<TemplateType> types
private final File templatesDir
private PageTemplateType getType(File file) {
private TemplateType getType(File file) {
this.types.find {
it.extensions.contains(new FileNameHandler(file).getExtension())
}
}
@Override
Collection<PageTemplate> getTemplates(File templatesDir) {
if (!templatesDir.isDirectory()) {
Collection<Template> getTemplates() {
if (!this.templatesDir.isDirectory()) {
throw new IllegalArgumentException('templatesDir must be a directory')
}
def templates = []
templatesDir.eachFileRecurse {
this.templatesDir.eachFileRecurse {
if (it.isFile()) {
def type = this.getType(it)
if (type != null) {
def relativePath = templatesDir.relativePath(it)
def relativePath = this.templatesDir.relativePath(it)
logger.debug('found template {}', relativePath)
templates << new PageTemplate(it, relativePath, type)
templates << new Template(it.text, relativePath, type)
}
}
}

View File

@ -0,0 +1,7 @@
package com.jessebrault.ssg.template
import com.jessebrault.ssg.part.Part
interface TemplateRenderer {
String render(Template template, String text, Collection<Part> parts)
}

View File

@ -0,0 +1,13 @@
package com.jessebrault.ssg.template
import groovy.transform.Canonical
import groovy.transform.NullCheck
import groovy.transform.TupleConstructor
@Canonical
@TupleConstructor(defaults = false)
@NullCheck
class TemplateType {
Collection<String> extensions
TemplateRenderer renderer
}

View File

@ -0,0 +1,5 @@
package com.jessebrault.ssg.template
interface TemplatesProvider {
Collection<Template> getTemplates()
}

View File

@ -1,9 +1,11 @@
package com.jessebrault.ssg.text
import groovy.transform.NullCheck
import groovy.transform.ToString
import groovy.transform.TupleConstructor
@TupleConstructor(includeFields = true)
@TupleConstructor(includeFields = true, defaults = false)
@NullCheck
@ToString
class FrontMatter {

View File

@ -0,0 +1,5 @@
package com.jessebrault.ssg.text
interface FrontMatterGetter {
FrontMatter get(String text)
}

View File

@ -1,5 +0,0 @@
package com.jessebrault.ssg.text;
public interface FrontMatterGetter {
FrontMatter get(String text);
}

View File

@ -4,7 +4,7 @@ import org.commonmark.ext.front.matter.YamlFrontMatterExtension
import org.commonmark.parser.Parser
import org.commonmark.renderer.html.HtmlRenderer
class MarkdownRenderer implements TextRenderer {
class MarkdownTextRenderer implements TextRenderer {
private static final Parser parser = Parser.builder()
.extensions([YamlFrontMatterExtension.create()])

View File

@ -0,0 +1,14 @@
package com.jessebrault.ssg.text
import groovy.transform.Canonical
import groovy.transform.NullCheck
import groovy.transform.TupleConstructor
@Canonical
@TupleConstructor(defaults = false)
@NullCheck
class Text {
String text
String path
TextType type
}

View File

@ -1,10 +0,0 @@
package com.jessebrault.ssg.text
import groovy.transform.Canonical
@Canonical
class TextFile {
File file
String relativePath
TextFileType type
}

View File

@ -0,0 +1,46 @@
package com.jessebrault.ssg.text
import com.jessebrault.ssg.util.FileNameHandler
import com.jessebrault.ssg.util.RelativePathHandler
import groovy.transform.NullCheck
import groovy.transform.TupleConstructor
import org.slf4j.Logger
import org.slf4j.LoggerFactory
@TupleConstructor(includeFields = true, defaults = false)
@NullCheck
class TextFileTextsProvider implements TextsProvider {
private static final Logger logger = LoggerFactory.getLogger(TextFileTextsProvider)
private final Collection<TextType> textTypes
private final File textsDir
private TextType getTextType(File file) {
this.textTypes.find {
it.ids.contains(new FileNameHandler(file).getExtension())
}
}
@Override
Collection<Text> getTextFiles() {
if (!this.textsDir.isDirectory()) {
throw new IllegalArgumentException('textsDir must be a directory')
}
def textFiles = []
this.textsDir.eachFileRecurse {
if (it.isFile()) {
def type = this.getTextType(it)
if (type != null) {
def relativePath = this.textsDir.relativePath(it)
def path = new RelativePathHandler(relativePath).getWithoutExtension()
logger.debug('found textFile {} with type {}', path, type)
textFiles << new Text(it.text, path, type)
}
}
}
textFiles
}
}

View File

@ -1,10 +0,0 @@
package com.jessebrault.ssg.text
import groovy.transform.Canonical
@Canonical
class TextFileType {
Collection<String> extensions
TextRenderer renderer
FrontMatterGetter frontMatterGetter
}

View File

@ -1,5 +0,0 @@
package com.jessebrault.ssg.text
interface TextFilesFactory {
Collection<TextFile> getTextFiles(File textsDir)
}

View File

@ -1,41 +0,0 @@
package com.jessebrault.ssg.text
import com.jessebrault.ssg.util.FileNameHandler
import groovy.transform.TupleConstructor
import org.slf4j.Logger
import org.slf4j.LoggerFactory
@TupleConstructor(includeFields = true)
class TextFilesFactoryImpl implements TextFilesFactory {
private static final Logger logger = LoggerFactory.getLogger(TextFilesFactoryImpl)
private final Collection<TextFileType> textFileTypes
private TextFileType getTextFileType(File file) {
textFileTypes.find {
it.extensions.contains(new FileNameHandler(file).getExtension())
}
}
@Override
Collection<TextFile> getTextFiles(File textsDir) {
if (!textsDir.isDirectory()) {
throw new IllegalArgumentException('textsDir must be a directory')
}
def textFiles = []
textsDir.eachFileRecurse {
if (it.isFile()) {
def type = this.getTextFileType(it)
if (type != null) {
def relativePath = textsDir.relativePath(it)
logger.debug('found textFile {}', relativePath)
textFiles << new TextFile(it, relativePath, type)
}
}
}
textFiles
}
}

View File

@ -0,0 +1,14 @@
package com.jessebrault.ssg.text
import groovy.transform.Canonical
import groovy.transform.NullCheck
import groovy.transform.TupleConstructor
@Canonical
@TupleConstructor(defaults = false)
@NullCheck
class TextType {
Collection<String> ids
TextRenderer renderer
FrontMatterGetter frontMatterGetter
}

View File

@ -0,0 +1,5 @@
package com.jessebrault.ssg.text
interface TextsProvider {
Collection<Text> getTextFiles()
}

View File

@ -1,8 +1,10 @@
package com.jessebrault.ssg.util
import groovy.transform.NullCheck
import groovy.transform.TupleConstructor
@TupleConstructor(includeFields = true)
@TupleConstructor(includeFields = true, defaults = false)
@NullCheck
class FileNameHandler {
private final File file
@ -11,4 +13,8 @@ class FileNameHandler {
this.file.name.substring(this.file.name.lastIndexOf('.'))
}
String getWithoutExtension() {
this.file.name.substring(0, this.file.name.lastIndexOf('.'))
}
}

View File

@ -1,8 +1,10 @@
package com.jessebrault.ssg.util
import groovy.transform.NullCheck
import groovy.transform.TupleConstructor
@TupleConstructor(includeFields = true)
@TupleConstructor(includeFields = true, defaults = false)
@NullCheck
class RelativePathHandler {
private final String relativePath

View File

@ -1,44 +1,58 @@
package com.jessebrault.ssg
import com.jessebrault.ssg.pagetemplate.GspRenderer
import com.jessebrault.ssg.pagetemplate.PageTemplateType
import com.jessebrault.ssg.pagetemplate.PageTemplatesFactoryImpl
import com.jessebrault.ssg.part.GspPartRenderer
import com.jessebrault.ssg.part.PartFilePartsProvider
import com.jessebrault.ssg.part.PartType
import com.jessebrault.ssg.template.GspTemplateRenderer
import com.jessebrault.ssg.template.TemplateType
import com.jessebrault.ssg.template.TemplateFileTemplatesProvider
import com.jessebrault.ssg.text.MarkdownFrontMatterGetter
import com.jessebrault.ssg.text.MarkdownRenderer
import com.jessebrault.ssg.text.TextFileType
import com.jessebrault.ssg.text.TextFilesFactoryImpl
import com.jessebrault.ssg.text.MarkdownTextRenderer
import com.jessebrault.ssg.text.TextType
import com.jessebrault.ssg.text.TextFileTextsProvider
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import static org.junit.jupiter.api.Assertions.assertEquals
import static org.junit.jupiter.api.Assertions.assertTrue
class StaticSiteGeneratorTests {
private final StaticSiteGenerator ssg = new StaticSiteGeneratorImpl(new Config(
textFileTypes: [new TextFileType(['.md'], new MarkdownRenderer(), new MarkdownFrontMatterGetter())],
pageTemplateTypes: [new PageTemplateType(['.gsp'], new GspRenderer())],
textFileFactoryGetter: { Config config -> new TextFilesFactoryImpl(config.textFileTypes) },
pageTemplatesFactoryGetter: { Config config -> new PageTemplatesFactoryImpl(config.pageTemplateTypes) }
))
private File partsDir
private File templatesDir
private File textsDir
private StaticSiteGenerator ssg
@BeforeEach
void beforeEach() {
this.textsDir = File.createTempDir()
this.templatesDir = File.createTempDir()
this.partsDir = File.createTempDir()
def config = new Config(
textTypes: [new TextType(['.md'], new MarkdownTextRenderer(), new MarkdownFrontMatterGetter())],
templateTypes: [new TemplateType(['.gsp'], new GspTemplateRenderer())],
partTypes: [new PartType(['.gsp'], new GspPartRenderer())],
textsDir: this.textsDir,
templatesDir: this.templatesDir,
partsDir: this.partsDir,
textsProviderGetter: { Config config -> new TextFileTextsProvider(config.textTypes, config.textsDir) },
templatesProviderGetter: { Config config -> new TemplateFileTemplatesProvider(config.templateTypes, config.templatesDir) },
partsProviderGetter: { Config config -> new PartFilePartsProvider(config.partTypes, config.partsDir) }
)
this.ssg = new SimpleStaticSiteGenerator(config)
}
@Test
void simple() {
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()
def textsDir = File.createTempDir()
def templatesDir = File.createTempDir()
new File(textsDir, 'test.md').write('---\ntemplate: test.gsp\n---\n**Hello, World!**')
new File(templatesDir, 'test.gsp').write('<%= text %>')
def spec = new SiteSpec(
buildDir: buildDir,
textsDir: textsDir,
templatesDir: templatesDir
)
this.ssg.generate(spec)
this.ssg.generate(buildDir)
def outFile = new File(buildDir, 'test.html')
assertTrue(outFile.exists())
@ -47,23 +61,16 @@ class StaticSiteGeneratorTests {
@Test
void nested() {
def buildDir = File.createTempDir()
def textsDir = File.createTempDir()
def templatesDir = File.createTempDir()
new FileTreeBuilder(textsDir).with {
new FileTreeBuilder(this.textsDir).with {
dir('nested') {
file('nested.md', '---\ntemplate: nested.gsp\n---\n**Hello, World!**')
}
}
new File(templatesDir, 'nested.gsp').write('<%= text %>')
new File(this.templatesDir, 'nested.gsp').write('<%= text %>')
this.ssg.generate(new SiteSpec(
buildDir: buildDir,
textsDir: textsDir,
templatesDir: templatesDir
))
def buildDir = File.createTempDir()
this.ssg.generate(buildDir)
def outFile = new File(new File(buildDir, 'nested'), 'nested.html')
assertTrue(outFile.exists())

View File

@ -1,55 +0,0 @@
package com.jessebrault.ssg.pagetemplate
import org.junit.jupiter.api.Test
import static org.junit.jupiter.api.Assertions.assertEquals
class PageTemplatesFactoryTests {
private static final PageTemplateType gspType = new PageTemplateType(['.gsp'], null)
private final PageTemplatesFactory templateFactory = new PageTemplatesFactoryImpl([gspType])
@Test
void findsTemplate() {
def templatesDir = File.createTempDir()
def templateFile = new File(templatesDir, 'test.gsp')
templateFile.write('<% out << text %>')
def r = this.templateFactory.getTemplates(templatesDir)
assertEquals(1, r.size())
def t0 = r[0]
assertEquals('test.gsp', t0.relativePath)
assertEquals('<% out << text %>', t0.file.text)
assertEquals(gspType, t0.type)
}
@Test
void findsNestedTemplate() {
def templatesDir = File.createTempDir()
new FileTreeBuilder(templatesDir).with {
dir('nested') {
file('nested.gsp', '<%= text %>')
}
}
def r = this.templateFactory.getTemplates(templatesDir)
assertEquals(1, r.size())
def t0 = r[0]
assertEquals('nested/nested.gsp', t0.relativePath)
assertEquals('<%= text %>', t0.file.text)
assertEquals(gspType, t0.type)
}
@Test
void ignoresUnsupportedFile() {
def templatesDir = File.createTempDir()
new File(templatesDir, '.ignored').with {
write('Ignored!')
}
def r = this.templateFactory.getTemplates(templatesDir)
assertEquals(0, r.size())
}
}

View File

@ -0,0 +1,61 @@
package com.jessebrault.ssg.part
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import static org.junit.jupiter.api.Assertions.assertEquals
class PartFilePartsProviderTests {
private static final PartType gspPartType = new PartType(['.gsp'], null)
private File partsDir
private PartsProvider partsProvider
@BeforeEach
void beforeEach() {
this.partsDir = File.createTempDir()
partsProvider = new PartFilePartsProvider([gspPartType], this.partsDir)
}
@Test
void findsPart() {
new FileTreeBuilder(this.partsDir).file('testPart.gsp') {
write('Hello <%= name %>!')
}
def r = this.partsProvider.getParts()
assertEquals(1, r.size())
def p0 = r[0]
assertEquals('testPart.gsp', p0.name)
assertEquals(gspPartType, p0.type)
assertEquals('Hello <%= name %>!', p0.text)
}
@Test
void findsNested() {
new FileTreeBuilder(this.partsDir).dir('nested') {
file('testPart.gsp') {
write('Hello, World!')
}
}
def r = this.partsProvider.getParts()
assertEquals(1, r.size())
def p0 = r[0]
assertEquals('nested/testPart.gsp', p0.name)
assertEquals(gspPartType, p0.type)
assertEquals('Hello, World!', p0.text)
}
@Test
void ignoresUnsupportedFile() {
new FileTreeBuilder(this.partsDir).file('.ignored') {
write 'Ignored!'
}
def r = this.partsProvider.getParts()
assertEquals(0, r.size())
}
}

View File

@ -0,0 +1,30 @@
package com.jessebrault.ssg.template
import com.jessebrault.ssg.part.GspPartRenderer
import com.jessebrault.ssg.part.Part
import com.jessebrault.ssg.part.PartType
import org.junit.jupiter.api.Test
import static org.junit.jupiter.api.Assertions.assertEquals
class GspTemplateRendererTests {
private final TemplateRenderer renderer = new GspTemplateRenderer()
@Test
void rendersPart() {
def template = new Template(
"<%= parts['greeting'].render([person: 'World']) %>",
null,
null
)
def part = new Part(
'greeting',
new PartType(['.gsp'], new GspPartRenderer()),
'Hello, $person!'
)
def r = this.renderer.render(template, '', [part])
assertEquals('Hello, World!', r)
}
}

View File

@ -0,0 +1,59 @@
package com.jessebrault.ssg.template
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import static org.junit.jupiter.api.Assertions.assertEquals
class PageTemplatesProviderTests {
private static final TemplateType gspType = new TemplateType(['.gsp'], null)
private File templatesDir
private TemplatesProvider templatesProvider
@BeforeEach
void beforeEach() {
this.templatesDir = File.createTempDir()
this.templatesProvider = new TemplateFileTemplatesProvider([gspType], this.templatesDir)
}
@Test
void findsTemplate() {
new File(this.templatesDir, 'test.gsp').write('<% out << text %>')
def r = this.templatesProvider.getTemplates()
assertEquals(1, r.size())
def t0 = r[0]
assertEquals('test.gsp', t0.relativePath)
assertEquals('<% out << text %>', t0.text)
assertEquals(gspType, t0.type)
}
@Test
void findsNestedTemplate() {
new FileTreeBuilder(this.templatesDir).with {
dir('nested') {
file('nested.gsp', '<%= text %>')
}
}
def r = this.templatesProvider.getTemplates()
assertEquals(1, r.size())
def t0 = r[0]
assertEquals('nested/nested.gsp', t0.relativePath)
assertEquals('<%= text %>', t0.text)
assertEquals(gspType, t0.type)
}
@Test
void ignoresUnsupportedFile() {
new File(this.templatesDir, '.ignored').with {
write('Ignored!')
}
def r = this.templatesProvider.getTemplates()
assertEquals(0, r.size())
}
}

View File

@ -0,0 +1,55 @@
package com.jessebrault.ssg.text
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import static org.junit.jupiter.api.Assertions.assertEquals
class TextFileTextsProviderTests {
private static final TextType markdownType = new TextType(['.md'], null, null)
private File textsDir
private TextsProvider textsProvider
@BeforeEach
void beforeEach() {
this.textsDir = File.createTempDir()
this.textsProvider = new TextFileTextsProvider([markdownType], this.textsDir)
}
@Test
void findsFile() {
new FileTreeBuilder(this.textsDir).file('test.md', '**Hello, World!**')
def r = textsProvider.getTextFiles()
assertEquals(1, r.size())
def f0 = r[0]
assertEquals('test', f0.path)
assertEquals('**Hello, World!**', f0.text)
assertEquals(markdownType, f0.type)
}
@Test
void findsNestedFiles() {
new FileTreeBuilder(this.textsDir).dir('nested') {
file('nested.md', '**Hello!**')
}
def r = textsProvider.getTextFiles()
assertEquals(1, r.size())
def f0 = r[0]
assertEquals('nested/nested', f0.path)
assertEquals('**Hello!**', f0.text)
assertEquals(markdownType, f0.type)
}
@Test
void ignoresUnsupportedFile() {
new FileTreeBuilder(this.textsDir).file('.ignored', 'Ignored!')
def r = textsProvider.getTextFiles()
assertEquals(0, r.size())
}
}

View File

@ -1,53 +0,0 @@
package com.jessebrault.ssg.text
import org.junit.jupiter.api.Test
import static org.junit.jupiter.api.Assertions.assertEquals
class TextsFilesFactoryTests {
private static final TextFileType markdownType = new TextFileType(['.md'], null, null)
private final TextFilesFactory textFilesFactory = new TextFilesFactoryImpl([markdownType])
@Test
void findsFile() {
def baseDir = File.createTempDir()
def ftb = new FileTreeBuilder(baseDir)
ftb.file('test.md', '**Hello, World!**')
def r = textFilesFactory.getTextFiles(baseDir)
assertEquals(1, r.size())
def f0 = r[0]
assertEquals('test.md', f0.relativePath)
assertEquals('**Hello, World!**', f0.file.text)
assertEquals(markdownType, f0.type)
}
@Test
void findsNestedFiles() {
def baseDir = File.createTempDir()
def ftb = new FileTreeBuilder(baseDir)
ftb.dir('nested') {
file('nested.md', '**Hello!**')
}
def r = textFilesFactory.getTextFiles(baseDir)
assertEquals(1, r.size())
def f0 = r[0]
assertEquals('nested/nested.md', f0.relativePath)
assertEquals('**Hello!**', f0.file.text)
assertEquals(markdownType, f0.type)
}
@Test
void ignoresUnsupportedFile() {
def baseDir = File.createTempDir()
def ftb = new FileTreeBuilder(baseDir)
ftb.file('.ignored', 'Ignored!')
def r = textFilesFactory.getTextFiles(baseDir)
assertEquals(0, r.size())
}
}

View File

@ -6,8 +6,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals
class FileNameHandlerTests {
private final FileNameHandler fileNameHandler = new FileNameHandler()
@Test
void getsCorrectExtension() {
def file = new File('hello.txt')