More refactoring, added parts.
This commit is contained in:
parent
c91700aecd
commit
5b2f83898d
@ -1,31 +1,39 @@
|
|||||||
package com.jessebrault.ssg
|
package com.jessebrault.ssg
|
||||||
|
|
||||||
import com.jessebrault.ssg.pagetemplate.GspRenderer
|
import com.jessebrault.ssg.part.GspPartRenderer
|
||||||
import com.jessebrault.ssg.pagetemplate.PageTemplateType
|
import com.jessebrault.ssg.part.PartFilePartsProvider
|
||||||
import com.jessebrault.ssg.pagetemplate.PageTemplatesFactoryImpl
|
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.MarkdownFrontMatterGetter
|
||||||
import com.jessebrault.ssg.text.MarkdownRenderer
|
import com.jessebrault.ssg.text.MarkdownTextRenderer
|
||||||
import com.jessebrault.ssg.text.TextFileType
|
import com.jessebrault.ssg.text.TextType
|
||||||
import com.jessebrault.ssg.text.TextFilesFactoryImpl
|
import com.jessebrault.ssg.text.TextFileTextsProvider
|
||||||
|
|
||||||
class StaticSiteGeneratorCli {
|
class StaticSiteGeneratorCli {
|
||||||
|
|
||||||
static void main(String[] args) {
|
static void main(String[] args) {
|
||||||
def markdown = new TextFileType(['.md'], new MarkdownRenderer(), new MarkdownFrontMatterGetter())
|
def markdownText = new TextType(['.md'], new MarkdownTextRenderer(), new MarkdownFrontMatterGetter())
|
||||||
def gsp = new PageTemplateType(['.gsp'], new GspRenderer())
|
def gspTemplate = new TemplateType(['.gsp'], new GspTemplateRenderer())
|
||||||
|
def gspPart = new PartType(['.gsp'], new GspPartRenderer())
|
||||||
|
|
||||||
def config = new Config(
|
def config = new Config(
|
||||||
textFileTypes: [markdown],
|
textTypes: [markdownText],
|
||||||
pageTemplateTypes: [gsp],
|
templateTypes: [gspTemplate],
|
||||||
textFileFactoryGetter: { Config config -> new TextFilesFactoryImpl(config.textFileTypes) },
|
partTypes: [gspPart],
|
||||||
pageTemplatesFactoryGetter: { Config config -> new PageTemplatesFactoryImpl(config.pageTemplateTypes) }
|
|
||||||
)
|
|
||||||
def ssg = new StaticSiteGeneratorImpl(config)
|
|
||||||
def defaultSpec = new SiteSpec(
|
|
||||||
buildDir: new File('build'),
|
|
||||||
textsDir: new File('texts'),
|
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'))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,30 @@
|
|||||||
package com.jessebrault.ssg
|
package com.jessebrault.ssg
|
||||||
|
|
||||||
import com.jessebrault.ssg.pagetemplate.PageTemplateType
|
import com.jessebrault.ssg.part.PartType
|
||||||
import com.jessebrault.ssg.pagetemplate.PageTemplatesFactory
|
import com.jessebrault.ssg.part.PartsProvider
|
||||||
import com.jessebrault.ssg.text.TextFileType
|
import com.jessebrault.ssg.template.TemplateType
|
||||||
import com.jessebrault.ssg.text.TextFilesFactory
|
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.Canonical
|
||||||
import groovy.transform.MapConstructor
|
import groovy.transform.MapConstructor
|
||||||
|
import groovy.transform.NullCheck
|
||||||
|
|
||||||
import java.util.function.Function
|
import java.util.function.Function
|
||||||
|
|
||||||
@Canonical
|
@Canonical
|
||||||
@MapConstructor
|
@MapConstructor
|
||||||
|
@NullCheck
|
||||||
class Config {
|
class Config {
|
||||||
Collection<TextFileType> textFileTypes
|
Collection<TextType> textTypes
|
||||||
Collection<PageTemplateType> pageTemplateTypes
|
Collection<TemplateType> templateTypes
|
||||||
|
Collection<PartType> partTypes
|
||||||
|
|
||||||
Function<Config, TextFilesFactory> textFileFactoryGetter
|
File textsDir
|
||||||
Function<Config, PageTemplatesFactory> pageTemplatesFactoryGetter
|
File templatesDir
|
||||||
|
File partsDir
|
||||||
|
|
||||||
|
Function<Config, TextsProvider> textsProviderGetter
|
||||||
|
Function<Config, TemplatesProvider> templatesProviderGetter
|
||||||
|
Function<Config, PartsProvider> partsProviderGetter
|
||||||
}
|
}
|
||||||
|
@ -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, '')
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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
|
|
||||||
}
|
|
@ -1,5 +1,5 @@
|
|||||||
package com.jessebrault.ssg
|
package com.jessebrault.ssg
|
||||||
|
|
||||||
interface StaticSiteGenerator {
|
interface StaticSiteGenerator {
|
||||||
void generate(SiteSpec spec)
|
void generate(File buildDir)
|
||||||
}
|
}
|
||||||
|
@ -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, '')
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -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
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
package com.jessebrault.ssg.pagetemplate
|
|
||||||
|
|
||||||
interface PageRenderer {
|
|
||||||
String render(PageTemplate template, String text)
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
package com.jessebrault.ssg.pagetemplate
|
|
||||||
|
|
||||||
import groovy.transform.Canonical
|
|
||||||
|
|
||||||
@Canonical
|
|
||||||
class PageTemplate {
|
|
||||||
File file
|
|
||||||
String relativePath
|
|
||||||
PageTemplateType type
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
package com.jessebrault.ssg.pagetemplate
|
|
||||||
|
|
||||||
import groovy.transform.Canonical
|
|
||||||
|
|
||||||
@Canonical
|
|
||||||
class PageTemplateType {
|
|
||||||
Collection<String> extensions
|
|
||||||
PageRenderer renderer
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
package com.jessebrault.ssg.pagetemplate
|
|
||||||
|
|
||||||
interface PageTemplatesFactory {
|
|
||||||
Collection<PageTemplate> getTemplates(File templatesDir)
|
|
||||||
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
14
lib/src/main/groovy/com/jessebrault/ssg/part/Part.groovy
Normal file
14
lib/src/main/groovy/com/jessebrault/ssg/part/Part.groovy
Normal 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
|
||||||
|
}
|
@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
package com.jessebrault.ssg.part
|
||||||
|
|
||||||
|
interface PartRenderer {
|
||||||
|
String render(String partText, Map binding)
|
||||||
|
}
|
13
lib/src/main/groovy/com/jessebrault/ssg/part/PartType.groovy
Normal file
13
lib/src/main/groovy/com/jessebrault/ssg/part/PartType.groovy
Normal 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
|
||||||
|
}
|
35
lib/src/main/groovy/com/jessebrault/ssg/part/PartsMap.groovy
Normal file
35
lib/src/main/groovy/com/jessebrault/ssg/part/PartsMap.groovy
Normal 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))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
package com.jessebrault.ssg.part
|
||||||
|
|
||||||
|
interface PartsProvider {
|
||||||
|
Collection<Part> getParts()
|
||||||
|
}
|
@ -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)
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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
|
||||||
|
}
|
@ -1,36 +1,39 @@
|
|||||||
package com.jessebrault.ssg.pagetemplate
|
package com.jessebrault.ssg.template
|
||||||
|
|
||||||
import com.jessebrault.ssg.util.FileNameHandler
|
import com.jessebrault.ssg.util.FileNameHandler
|
||||||
|
import groovy.transform.NullCheck
|
||||||
import groovy.transform.TupleConstructor
|
import groovy.transform.TupleConstructor
|
||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
|
|
||||||
@TupleConstructor(includeFields = true)
|
@TupleConstructor(includeFields = true, defaults = false)
|
||||||
class PageTemplatesFactoryImpl implements PageTemplatesFactory {
|
@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 {
|
this.types.find {
|
||||||
it.extensions.contains(new FileNameHandler(file).getExtension())
|
it.extensions.contains(new FileNameHandler(file).getExtension())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
Collection<PageTemplate> getTemplates(File templatesDir) {
|
Collection<Template> getTemplates() {
|
||||||
if (!templatesDir.isDirectory()) {
|
if (!this.templatesDir.isDirectory()) {
|
||||||
throw new IllegalArgumentException('templatesDir must be a directory')
|
throw new IllegalArgumentException('templatesDir must be a directory')
|
||||||
}
|
}
|
||||||
def templates = []
|
def templates = []
|
||||||
templatesDir.eachFileRecurse {
|
this.templatesDir.eachFileRecurse {
|
||||||
if (it.isFile()) {
|
if (it.isFile()) {
|
||||||
def type = this.getType(it)
|
def type = this.getType(it)
|
||||||
if (type != null) {
|
if (type != null) {
|
||||||
def relativePath = templatesDir.relativePath(it)
|
def relativePath = this.templatesDir.relativePath(it)
|
||||||
logger.debug('found template {}', relativePath)
|
logger.debug('found template {}', relativePath)
|
||||||
templates << new PageTemplate(it, relativePath, type)
|
templates << new Template(it.text, relativePath, type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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)
|
||||||
|
}
|
@ -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
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
package com.jessebrault.ssg.template
|
||||||
|
|
||||||
|
interface TemplatesProvider {
|
||||||
|
Collection<Template> getTemplates()
|
||||||
|
}
|
@ -1,9 +1,11 @@
|
|||||||
package com.jessebrault.ssg.text
|
package com.jessebrault.ssg.text
|
||||||
|
|
||||||
|
import groovy.transform.NullCheck
|
||||||
import groovy.transform.ToString
|
import groovy.transform.ToString
|
||||||
import groovy.transform.TupleConstructor
|
import groovy.transform.TupleConstructor
|
||||||
|
|
||||||
@TupleConstructor(includeFields = true)
|
@TupleConstructor(includeFields = true, defaults = false)
|
||||||
|
@NullCheck
|
||||||
@ToString
|
@ToString
|
||||||
class FrontMatter {
|
class FrontMatter {
|
||||||
|
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
package com.jessebrault.ssg.text
|
||||||
|
|
||||||
|
interface FrontMatterGetter {
|
||||||
|
FrontMatter get(String text)
|
||||||
|
}
|
@ -1,5 +0,0 @@
|
|||||||
package com.jessebrault.ssg.text;
|
|
||||||
|
|
||||||
public interface FrontMatterGetter {
|
|
||||||
FrontMatter get(String text);
|
|
||||||
}
|
|
@ -4,7 +4,7 @@ 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
|
||||||
|
|
||||||
class MarkdownRenderer implements TextRenderer {
|
class MarkdownTextRenderer implements TextRenderer {
|
||||||
|
|
||||||
private static final Parser parser = Parser.builder()
|
private static final Parser parser = Parser.builder()
|
||||||
.extensions([YamlFrontMatterExtension.create()])
|
.extensions([YamlFrontMatterExtension.create()])
|
14
lib/src/main/groovy/com/jessebrault/ssg/text/Text.groovy
Normal file
14
lib/src/main/groovy/com/jessebrault/ssg/text/Text.groovy
Normal 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
|
||||||
|
}
|
@ -1,10 +0,0 @@
|
|||||||
package com.jessebrault.ssg.text
|
|
||||||
|
|
||||||
import groovy.transform.Canonical
|
|
||||||
|
|
||||||
@Canonical
|
|
||||||
class TextFile {
|
|
||||||
File file
|
|
||||||
String relativePath
|
|
||||||
TextFileType type
|
|
||||||
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,10 +0,0 @@
|
|||||||
package com.jessebrault.ssg.text
|
|
||||||
|
|
||||||
import groovy.transform.Canonical
|
|
||||||
|
|
||||||
@Canonical
|
|
||||||
class TextFileType {
|
|
||||||
Collection<String> extensions
|
|
||||||
TextRenderer renderer
|
|
||||||
FrontMatterGetter frontMatterGetter
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
package com.jessebrault.ssg.text
|
|
||||||
|
|
||||||
interface TextFilesFactory {
|
|
||||||
Collection<TextFile> getTextFiles(File textsDir)
|
|
||||||
}
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
14
lib/src/main/groovy/com/jessebrault/ssg/text/TextType.groovy
Normal file
14
lib/src/main/groovy/com/jessebrault/ssg/text/TextType.groovy
Normal 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
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
package com.jessebrault.ssg.text
|
||||||
|
|
||||||
|
interface TextsProvider {
|
||||||
|
Collection<Text> getTextFiles()
|
||||||
|
}
|
@ -1,8 +1,10 @@
|
|||||||
package com.jessebrault.ssg.util
|
package com.jessebrault.ssg.util
|
||||||
|
|
||||||
|
import groovy.transform.NullCheck
|
||||||
import groovy.transform.TupleConstructor
|
import groovy.transform.TupleConstructor
|
||||||
|
|
||||||
@TupleConstructor(includeFields = true)
|
@TupleConstructor(includeFields = true, defaults = false)
|
||||||
|
@NullCheck
|
||||||
class FileNameHandler {
|
class FileNameHandler {
|
||||||
|
|
||||||
private final File file
|
private final File file
|
||||||
@ -11,4 +13,8 @@ class FileNameHandler {
|
|||||||
this.file.name.substring(this.file.name.lastIndexOf('.'))
|
this.file.name.substring(this.file.name.lastIndexOf('.'))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String getWithoutExtension() {
|
||||||
|
this.file.name.substring(0, this.file.name.lastIndexOf('.'))
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
package com.jessebrault.ssg.util
|
package com.jessebrault.ssg.util
|
||||||
|
|
||||||
|
import groovy.transform.NullCheck
|
||||||
import groovy.transform.TupleConstructor
|
import groovy.transform.TupleConstructor
|
||||||
|
|
||||||
@TupleConstructor(includeFields = true)
|
@TupleConstructor(includeFields = true, defaults = false)
|
||||||
|
@NullCheck
|
||||||
class RelativePathHandler {
|
class RelativePathHandler {
|
||||||
|
|
||||||
private final String relativePath
|
private final String relativePath
|
||||||
|
@ -1,44 +1,58 @@
|
|||||||
package com.jessebrault.ssg
|
package com.jessebrault.ssg
|
||||||
|
|
||||||
import com.jessebrault.ssg.pagetemplate.GspRenderer
|
import com.jessebrault.ssg.part.GspPartRenderer
|
||||||
import com.jessebrault.ssg.pagetemplate.PageTemplateType
|
import com.jessebrault.ssg.part.PartFilePartsProvider
|
||||||
import com.jessebrault.ssg.pagetemplate.PageTemplatesFactoryImpl
|
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.MarkdownFrontMatterGetter
|
||||||
import com.jessebrault.ssg.text.MarkdownRenderer
|
import com.jessebrault.ssg.text.MarkdownTextRenderer
|
||||||
import com.jessebrault.ssg.text.TextFileType
|
import com.jessebrault.ssg.text.TextType
|
||||||
import com.jessebrault.ssg.text.TextFilesFactoryImpl
|
import com.jessebrault.ssg.text.TextFileTextsProvider
|
||||||
|
import org.junit.jupiter.api.BeforeEach
|
||||||
import org.junit.jupiter.api.Test
|
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.assertEquals
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue
|
import static org.junit.jupiter.api.Assertions.assertTrue
|
||||||
|
|
||||||
class StaticSiteGeneratorTests {
|
class StaticSiteGeneratorTests {
|
||||||
|
|
||||||
private final StaticSiteGenerator ssg = new StaticSiteGeneratorImpl(new Config(
|
private File partsDir
|
||||||
textFileTypes: [new TextFileType(['.md'], new MarkdownRenderer(), new MarkdownFrontMatterGetter())],
|
private File templatesDir
|
||||||
pageTemplateTypes: [new PageTemplateType(['.gsp'], new GspRenderer())],
|
private File textsDir
|
||||||
textFileFactoryGetter: { Config config -> new TextFilesFactoryImpl(config.textFileTypes) },
|
|
||||||
pageTemplatesFactoryGetter: { Config config -> new PageTemplatesFactoryImpl(config.pageTemplateTypes) }
|
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
|
@Test
|
||||||
void simple() {
|
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 buildDir = File.createTempDir()
|
||||||
def textsDir = File.createTempDir()
|
this.ssg.generate(buildDir)
|
||||||
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)
|
|
||||||
|
|
||||||
def outFile = new File(buildDir, 'test.html')
|
def outFile = new File(buildDir, 'test.html')
|
||||||
assertTrue(outFile.exists())
|
assertTrue(outFile.exists())
|
||||||
@ -47,23 +61,16 @@ class StaticSiteGeneratorTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void nested() {
|
void nested() {
|
||||||
def buildDir = File.createTempDir()
|
new FileTreeBuilder(this.textsDir).with {
|
||||||
def textsDir = File.createTempDir()
|
|
||||||
def templatesDir = File.createTempDir()
|
|
||||||
|
|
||||||
new FileTreeBuilder(textsDir).with {
|
|
||||||
dir('nested') {
|
dir('nested') {
|
||||||
file('nested.md', '---\ntemplate: nested.gsp\n---\n**Hello, World!**')
|
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(
|
def buildDir = File.createTempDir()
|
||||||
buildDir: buildDir,
|
this.ssg.generate(buildDir)
|
||||||
textsDir: textsDir,
|
|
||||||
templatesDir: templatesDir
|
|
||||||
))
|
|
||||||
|
|
||||||
def outFile = new File(new File(buildDir, 'nested'), 'nested.html')
|
def outFile = new File(new File(buildDir, 'nested'), 'nested.html')
|
||||||
assertTrue(outFile.exists())
|
assertTrue(outFile.exists())
|
||||||
|
@ -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())
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -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())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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())
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -6,8 +6,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals
|
|||||||
|
|
||||||
class FileNameHandlerTests {
|
class FileNameHandlerTests {
|
||||||
|
|
||||||
private final FileNameHandler fileNameHandler = new FileNameHandler()
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void getsCorrectExtension() {
|
void getsCorrectExtension() {
|
||||||
def file = new File('hello.txt')
|
def file = new File('hello.txt')
|
||||||
|
Loading…
Reference in New Issue
Block a user