Removed lib module.
This commit is contained in:
parent
95f86629f3
commit
fdc2c83e99
@ -1,22 +0,0 @@
|
||||
plugins {
|
||||
id 'ssg.common'
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// https://mvnrepository.com/artifact/org.apache.groovy/groovy-templates
|
||||
implementation 'org.apache.groovy:groovy-templates:4.0.9'
|
||||
|
||||
// https://mvnrepository.com/artifact/org.commonmark/commonmark
|
||||
implementation 'org.commonmark:commonmark:0.21.0'
|
||||
|
||||
// https://mvnrepository.com/artifact/org.commonmark/commonmark-ext-yaml-front-matter
|
||||
implementation 'org.commonmark:commonmark-ext-yaml-front-matter:0.21.0'
|
||||
}
|
||||
|
||||
jar {
|
||||
archivesBaseName = 'ssg-lib'
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
package com.jessebrault.ssg
|
||||
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
import groovy.transform.TupleConstructor
|
||||
|
||||
@TupleConstructor(defaults = false)
|
||||
@NullCheck(includeGenerated = true)
|
||||
@EqualsAndHashCode
|
||||
class Build {
|
||||
|
||||
String name
|
||||
Config config
|
||||
SiteSpec siteSpec
|
||||
Map globals
|
||||
File outDir
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
"Build(name: ${ this.name }, config: ${ this.config }, siteSpec: ${ this.siteSpec }, " +
|
||||
"globals: ${ this.globals }, outDir: ${ this.outDir })"
|
||||
}
|
||||
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
package com.jessebrault.ssg
|
||||
|
||||
import com.jessebrault.ssg.part.PartsProvider
|
||||
import com.jessebrault.ssg.specialpage.SpecialPagesProvider
|
||||
import com.jessebrault.ssg.template.TemplatesProvider
|
||||
import com.jessebrault.ssg.text.TextsProvider
|
||||
import groovy.transform.Canonical
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.MapConstructor
|
||||
import groovy.transform.NullCheck
|
||||
import groovy.transform.TupleConstructor
|
||||
|
||||
@TupleConstructor(force = true)
|
||||
@MapConstructor
|
||||
@NullCheck
|
||||
@EqualsAndHashCode
|
||||
class Config {
|
||||
|
||||
Collection<TextsProvider> textProviders
|
||||
Collection<TemplatesProvider> templatesProviders
|
||||
Collection<PartsProvider> partsProviders
|
||||
Collection<SpecialPagesProvider> specialPagesProviders
|
||||
|
||||
Config(Config source) {
|
||||
this.textProviders = [].tap {
|
||||
addAll(source.textProviders)
|
||||
}
|
||||
this.templatesProviders = [].tap {
|
||||
addAll(source.templatesProviders)
|
||||
}
|
||||
this.partsProviders = [].tap {
|
||||
addAll(source.partsProviders)
|
||||
}
|
||||
this.specialPagesProviders = [].tap {
|
||||
addAll(source.specialPagesProviders)
|
||||
}
|
||||
}
|
||||
|
||||
String toString() {
|
||||
"Config(textProviders: ${ this.textProviders }, templatesProviders: ${ this.templatesProviders }, " +
|
||||
"partsProviders: ${ this.partsProviders }, specialPagesProviders: ${ this.specialPagesProviders })"
|
||||
}
|
||||
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
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 })"
|
||||
}
|
||||
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
package com.jessebrault.ssg
|
||||
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
import groovy.transform.TupleConstructor
|
||||
|
||||
@TupleConstructor(defaults = false, includeFields = true)
|
||||
@NullCheck(includeGenerated = true)
|
||||
@EqualsAndHashCode
|
||||
final class Result<T> {
|
||||
|
||||
final Collection<Diagnostic> diagnostics
|
||||
private final T t
|
||||
|
||||
boolean hasDiagnostics() {
|
||||
!this.diagnostics.isEmpty()
|
||||
}
|
||||
|
||||
T get() {
|
||||
this.t
|
||||
}
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
"Result(diagnostics: ${ this.diagnostics }, t: ${ this.t })"
|
||||
}
|
||||
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
package com.jessebrault.ssg
|
||||
|
||||
import com.jessebrault.ssg.task.SpecialPageToHtmlFileTaskFactory
|
||||
import com.jessebrault.ssg.task.TaskContainer
|
||||
import com.jessebrault.ssg.task.TaskTypeContainer
|
||||
import com.jessebrault.ssg.task.TextToHtmlFileTaskFactory
|
||||
import groovy.transform.NullCheck
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.slf4j.Marker
|
||||
import org.slf4j.MarkerFactory
|
||||
|
||||
@NullCheck
|
||||
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 static final TextToHtmlFileTaskFactory textHtmlFactory = new TextToHtmlFileTaskFactory()
|
||||
private static final SpecialPageToHtmlFileTaskFactory specialPageHtmlFactory = new SpecialPageToHtmlFileTaskFactory()
|
||||
|
||||
@Override
|
||||
TaskTypeContainer getTaskTypes() {
|
||||
new TaskTypeContainer([textHtmlFactory.taskType, specialPageHtmlFactory.taskType])
|
||||
}
|
||||
|
||||
@Override
|
||||
Result<TaskContainer> generate(Build build) {
|
||||
logger.trace(enter, 'build: {}', build)
|
||||
logger.info('processing build with name: {}', build.name)
|
||||
|
||||
def tasks = new TaskContainer()
|
||||
def diagnostics = []
|
||||
|
||||
def textsResult = textHtmlFactory.getTasks(build)
|
||||
tasks.addAll(textsResult.get())
|
||||
diagnostics.addAll(textsResult.diagnostics)
|
||||
|
||||
def specialPagesResult = specialPageHtmlFactory.getTasks(build)
|
||||
tasks.addAll(specialPagesResult.get())
|
||||
diagnostics.addAll(specialPagesResult.diagnostics)
|
||||
|
||||
logger.trace(exit, '\n\tdiagnostics: {}\n\ttasks: {}', diagnostics, tasks)
|
||||
new Result<>(diagnostics, tasks)
|
||||
}
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
"SimpleStaticSiteGenerator()"
|
||||
}
|
||||
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
package com.jessebrault.ssg
|
||||
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.MapConstructor
|
||||
import groovy.transform.NullCheck
|
||||
import groovy.transform.TupleConstructor
|
||||
|
||||
@TupleConstructor(force = true, defaults = false)
|
||||
@MapConstructor
|
||||
@NullCheck
|
||||
@EqualsAndHashCode
|
||||
final class SiteSpec {
|
||||
|
||||
String name
|
||||
String baseUrl
|
||||
|
||||
SiteSpec(SiteSpec source) {
|
||||
this.name = source.name
|
||||
this.baseUrl = source.baseUrl
|
||||
}
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
"SiteSpec(${ this.name }, ${ this.baseUrl })"
|
||||
}
|
||||
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
package com.jessebrault.ssg
|
||||
|
||||
import com.jessebrault.ssg.task.TaskContainer
|
||||
import com.jessebrault.ssg.task.TaskTypeContainer
|
||||
|
||||
interface StaticSiteGenerator {
|
||||
TaskTypeContainer getTaskTypes()
|
||||
Result<TaskContainer> generate(Build build)
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
package com.jessebrault.ssg
|
||||
|
||||
trait WatchableProvider {
|
||||
File watchableDir
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
package com.jessebrault.ssg.buildscript
|
||||
|
||||
import com.jessebrault.ssg.Config
|
||||
import com.jessebrault.ssg.SiteSpec
|
||||
|
||||
class BuildClosureDelegate {
|
||||
|
||||
String name
|
||||
Config config
|
||||
SiteSpec siteSpec
|
||||
Map globals
|
||||
File outDir
|
||||
|
||||
void config(
|
||||
@DelegatesTo(value = ConfigClosureDelegate, strategy = Closure.DELEGATE_FIRST)
|
||||
Closure configClosure
|
||||
) {
|
||||
configClosure.setDelegate(new ConfigClosureDelegate(this.config))
|
||||
configClosure.setResolveStrategy(Closure.DELEGATE_FIRST)
|
||||
configClosure.run()
|
||||
}
|
||||
|
||||
void siteSpec(
|
||||
@DelegatesTo(value = SiteSpecClosureDelegate, strategy = Closure.DELEGATE_FIRST)
|
||||
Closure siteSpecClosure
|
||||
) {
|
||||
siteSpecClosure.setDelegate(new SiteSpecClosureDelegate(this.siteSpec))
|
||||
siteSpecClosure.setResolveStrategy(Closure.DELEGATE_FIRST)
|
||||
siteSpecClosure.run()
|
||||
}
|
||||
|
||||
void globals(
|
||||
@DelegatesTo(value = GlobalsClosureDelegate, strategy = Closure.DELEGATE_FIRST)
|
||||
Closure globalsClosure
|
||||
) {
|
||||
def globalsConfigurator = new GlobalsClosureDelegate(this.globals)
|
||||
globalsClosure.setDelegate(globalsConfigurator)
|
||||
globalsClosure.setResolveStrategy(Closure.DELEGATE_FIRST)
|
||||
globalsClosure.run()
|
||||
}
|
||||
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
package com.jessebrault.ssg.buildscript
|
||||
|
||||
import com.jessebrault.ssg.Build
|
||||
import com.jessebrault.ssg.Config
|
||||
import com.jessebrault.ssg.SiteSpec
|
||||
|
||||
abstract class BuildScriptBase extends Script {
|
||||
|
||||
Config defaultConfig
|
||||
SiteSpec defaultSiteSpec
|
||||
Map defaultGlobals
|
||||
|
||||
Collection<Build> builds = []
|
||||
|
||||
protected int currentBuildNumber = 0
|
||||
|
||||
void build(
|
||||
@DelegatesTo(value = BuildClosureDelegate, strategy = Closure.DELEGATE_FIRST)
|
||||
Closure buildClosure
|
||||
) {
|
||||
def buildClosureDelegate = new BuildClosureDelegate().tap {
|
||||
// Default values for Build properties
|
||||
name = 'build' + this.currentBuildNumber
|
||||
config = new Config(defaultConfig)
|
||||
siteSpec = new SiteSpec(defaultSiteSpec)
|
||||
globals = new LinkedHashMap(defaultGlobals)
|
||||
outDir = new File(name)
|
||||
}
|
||||
buildClosure.setDelegate(buildClosureDelegate)
|
||||
buildClosure.setResolveStrategy(Closure.DELEGATE_FIRST)
|
||||
buildClosure.run()
|
||||
this.builds << new Build(
|
||||
buildClosureDelegate.name,
|
||||
buildClosureDelegate.config,
|
||||
buildClosureDelegate.siteSpec,
|
||||
buildClosureDelegate.globals,
|
||||
buildClosureDelegate.outDir
|
||||
)
|
||||
this.currentBuildNumber++
|
||||
}
|
||||
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
package com.jessebrault.ssg.buildscript
|
||||
|
||||
import com.jessebrault.ssg.Build
|
||||
import com.jessebrault.ssg.Config
|
||||
|
||||
interface BuildScriptRunner {
|
||||
Collection<Build> runBuildScript(String relativePath, Config defaultConfig, Map defaultGlobals)
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
package com.jessebrault.ssg.buildscript
|
||||
|
||||
import com.jessebrault.ssg.Config
|
||||
import com.jessebrault.ssg.part.PartType
|
||||
import com.jessebrault.ssg.specialpage.SpecialPageType
|
||||
import com.jessebrault.ssg.template.TemplateType
|
||||
import com.jessebrault.ssg.text.TextType
|
||||
|
||||
class ConfigClosureDelegate {
|
||||
|
||||
@Delegate
|
||||
private final Config config
|
||||
|
||||
private final Collection<TextType> defaultTextTypes
|
||||
private final Collection<TemplateType> defaultTemplateTypes
|
||||
private final Collection<PartType> defaultPartTypes
|
||||
private final Collection<SpecialPageType> defaultSpecialPageTypes
|
||||
|
||||
ConfigClosureDelegate(Config config) {
|
||||
this.config = config
|
||||
this.defaultTextTypes = this.config.textProviders.collectMany { it.textTypes }
|
||||
this.defaultTemplateTypes = this.config.templatesProviders.collectMany { it.templateTypes }
|
||||
this.defaultPartTypes = this.config.partsProviders.collectMany { it.partTypes }
|
||||
this.defaultSpecialPageTypes = this.config.specialPagesProviders.collectMany { it.specialPageTypes }
|
||||
}
|
||||
|
||||
Collection<TextType> getDefaultTextTypes() {
|
||||
this.defaultTextTypes
|
||||
}
|
||||
|
||||
Collection<TemplateType> getDefaultTemplateTypes() {
|
||||
this.defaultTemplateTypes
|
||||
}
|
||||
|
||||
Collection<PartType> getDefaultPartTypes() {
|
||||
this.defaultPartTypes
|
||||
}
|
||||
|
||||
Collection<SpecialPageType> getDefaultSpecialPageTypes() {
|
||||
this.defaultSpecialPageTypes
|
||||
}
|
||||
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
package com.jessebrault.ssg.buildscript
|
||||
|
||||
import groovy.transform.TupleConstructor
|
||||
|
||||
@TupleConstructor(includeFields = true, defaults = false)
|
||||
class GlobalsClosureDelegate {
|
||||
|
||||
private final Map globals
|
||||
|
||||
@Override
|
||||
Object getProperty(String propertyName) {
|
||||
this.globals[propertyName]
|
||||
}
|
||||
|
||||
@Override
|
||||
void setProperty(String propertyName, Object newValue) {
|
||||
this.globals.put(propertyName, newValue)
|
||||
}
|
||||
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
package com.jessebrault.ssg.buildscript
|
||||
|
||||
import com.jessebrault.ssg.Build
|
||||
import com.jessebrault.ssg.Config
|
||||
import groovy.transform.NullCheck
|
||||
import org.codehaus.groovy.control.CompilerConfiguration
|
||||
import org.codehaus.groovy.control.customizers.ImportCustomizer
|
||||
|
||||
@NullCheck
|
||||
class GroovyBuildScriptRunner implements BuildScriptRunner {
|
||||
|
||||
@Override
|
||||
Collection<Build> runBuildScript(String relativePath, Config defaultConfig, Map defaultGlobals) {
|
||||
def engine = new GroovyScriptEngine([new File('.').toURI().toURL()] as URL[])
|
||||
engine.config = new CompilerConfiguration().tap {
|
||||
addCompilationCustomizers(new ImportCustomizer().tap {
|
||||
addStarImports(
|
||||
'com.jessebrault.ssg',
|
||||
'com.jessebrault.ssg.part',
|
||||
'com.jessebrault.ssg.specialpage',
|
||||
'com.jessebrault.ssg.template',
|
||||
'com.jessebrault.ssg.text',
|
||||
'com.jessebrault.ssg.util'
|
||||
)
|
||||
})
|
||||
scriptBaseClass = 'com.jessebrault.ssg.buildscript.BuildScriptBase'
|
||||
}
|
||||
|
||||
def buildScript = engine.createScript(relativePath, new Binding())
|
||||
assert buildScript instanceof BuildScriptBase
|
||||
buildScript.defaultConfig = defaultConfig
|
||||
buildScript.defaultGlobals = defaultGlobals
|
||||
buildScript.run()
|
||||
buildScript.builds
|
||||
}
|
||||
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
package com.jessebrault.ssg.buildscript
|
||||
|
||||
import com.jessebrault.ssg.SiteSpec
|
||||
|
||||
class SiteSpecClosureDelegate {
|
||||
|
||||
@Delegate
|
||||
private final SiteSpec siteSpec
|
||||
|
||||
SiteSpecClosureDelegate(SiteSpec siteSpec) {
|
||||
this.siteSpec = siteSpec
|
||||
}
|
||||
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
package com.jessebrault.ssg.dsl
|
||||
|
||||
import com.jessebrault.ssg.part.EmbeddablePartsMap
|
||||
import com.jessebrault.ssg.renderer.RenderContext
|
||||
import com.jessebrault.ssg.tagbuilder.DynamicTagBuilder
|
||||
import com.jessebrault.ssg.text.EmbeddableText
|
||||
import com.jessebrault.ssg.text.EmbeddableTextsCollection
|
||||
import com.jessebrault.ssg.text.Text
|
||||
import com.jessebrault.ssg.url.PathBasedUrlBuilder
|
||||
import groovy.transform.NullCheck
|
||||
import groovy.transform.stc.ClosureParams
|
||||
import groovy.transform.stc.SimpleType
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
final class StandardDslMap {
|
||||
|
||||
@NullCheck(includeGenerated = true)
|
||||
static final class Builder {
|
||||
|
||||
private final Map custom = [:]
|
||||
|
||||
String loggerName = ''
|
||||
Closure onDiagnostics = { }
|
||||
Text text = null
|
||||
|
||||
void putCustom(key, value) {
|
||||
this.custom.put(key, value)
|
||||
}
|
||||
|
||||
void putAllCustom(Map m) {
|
||||
this.custom.putAll(m)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static Map get(
|
||||
RenderContext context,
|
||||
@DelegatesTo(value = Builder, strategy = Closure.DELEGATE_FIRST)
|
||||
@ClosureParams(
|
||||
value = SimpleType,
|
||||
options = ['com.jessebrault.ssg.dsl.StandardDslMap.Builder']
|
||||
)
|
||||
Closure builderClosure
|
||||
) {
|
||||
def b = new Builder()
|
||||
builderClosure.resolveStrategy = Closure.DELEGATE_FIRST
|
||||
builderClosure.delegate = b
|
||||
builderClosure(b)
|
||||
|
||||
[:].tap {
|
||||
it.globals = context.globals
|
||||
it.logger = LoggerFactory.getLogger(b.loggerName)
|
||||
it.parts = new EmbeddablePartsMap(
|
||||
context.parts,
|
||||
context,
|
||||
b.onDiagnostics,
|
||||
b.text
|
||||
)
|
||||
it.siteSpec = context.siteSpec
|
||||
it.sourcePath = context.sourcePath
|
||||
it.tagBuilder = new DynamicTagBuilder()
|
||||
it.targetPath = context.targetPath
|
||||
it.tasks = context.tasks
|
||||
it.taskTypes = context.taskTypes
|
||||
it.text = b.text ? new EmbeddableText(
|
||||
b.text,
|
||||
context.globals,
|
||||
b.onDiagnostics
|
||||
) : null
|
||||
it.texts = new EmbeddableTextsCollection(
|
||||
context.texts,
|
||||
context.globals,
|
||||
b.onDiagnostics
|
||||
)
|
||||
it.urlBuilder = new PathBasedUrlBuilder(
|
||||
context.targetPath,
|
||||
context.siteSpec.baseUrl
|
||||
)
|
||||
|
||||
it.putAll(b.custom)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
package com.jessebrault.ssg.part
|
||||
|
||||
|
||||
import com.jessebrault.ssg.renderer.RenderContext
|
||||
import com.jessebrault.ssg.text.Text
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
import org.jetbrains.annotations.Nullable
|
||||
|
||||
import static java.util.Objects.requireNonNull
|
||||
|
||||
@EqualsAndHashCode(includeFields = true)
|
||||
class EmbeddablePart {
|
||||
|
||||
private final Part part
|
||||
private final RenderContext context
|
||||
private final Closure onDiagnostics
|
||||
|
||||
@Nullable
|
||||
private final Text text
|
||||
|
||||
EmbeddablePart(
|
||||
Part part,
|
||||
RenderContext context,
|
||||
Closure onDiagnostics,
|
||||
@Nullable Text text
|
||||
) {
|
||||
this.part = requireNonNull(part)
|
||||
this.context = requireNonNull(context)
|
||||
this.onDiagnostics = requireNonNull(onDiagnostics)
|
||||
this.text = text
|
||||
}
|
||||
|
||||
String render(Map binding = [:]) {
|
||||
def result = part.type.renderer.render(
|
||||
this.part,
|
||||
binding,
|
||||
this.context,
|
||||
this.text
|
||||
)
|
||||
if (result.v1.size() > 0) {
|
||||
this.onDiagnostics.call(result.v1)
|
||||
''
|
||||
} else {
|
||||
result.v2
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
"EmbeddablePart(part: ${ this.part })"
|
||||
}
|
||||
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
package com.jessebrault.ssg.part
|
||||
|
||||
import com.jessebrault.ssg.renderer.RenderContext
|
||||
import com.jessebrault.ssg.text.Text
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import org.jetbrains.annotations.Nullable
|
||||
|
||||
import static java.util.Objects.requireNonNull
|
||||
|
||||
@EqualsAndHashCode(includeFields = true)
|
||||
class EmbeddablePartsMap {
|
||||
|
||||
@Delegate
|
||||
private final Map<String, EmbeddablePart> partsMap = [:]
|
||||
|
||||
EmbeddablePartsMap(
|
||||
Collection<Part> parts,
|
||||
RenderContext context,
|
||||
Closure onDiagnostics,
|
||||
@Nullable Text text = null
|
||||
) {
|
||||
requireNonNull(parts)
|
||||
requireNonNull(context)
|
||||
requireNonNull(onDiagnostics)
|
||||
parts.each {
|
||||
this.put(it.path, new EmbeddablePart(it, context, onDiagnostics, text))
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
"EmbeddablePartsMap(partsMap: ${ this.partsMap })"
|
||||
}
|
||||
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
package com.jessebrault.ssg.part
|
||||
|
||||
import com.jessebrault.ssg.Diagnostic
|
||||
import com.jessebrault.ssg.dsl.StandardDslMap
|
||||
import com.jessebrault.ssg.renderer.RenderContext
|
||||
import com.jessebrault.ssg.text.EmbeddableText
|
||||
import com.jessebrault.ssg.text.Text
|
||||
import groovy.text.GStringTemplateEngine
|
||||
import groovy.text.TemplateEngine
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import org.jetbrains.annotations.Nullable
|
||||
|
||||
@EqualsAndHashCode
|
||||
class GspPartRenderer implements PartRenderer {
|
||||
|
||||
private static final TemplateEngine engine = new GStringTemplateEngine()
|
||||
|
||||
@Override
|
||||
Tuple2<Collection<Diagnostic>, String> render(
|
||||
Part part,
|
||||
Map binding,
|
||||
RenderContext context,
|
||||
@Nullable Text text
|
||||
) {
|
||||
Objects.requireNonNull(part)
|
||||
Objects.requireNonNull(binding)
|
||||
Objects.requireNonNull(context)
|
||||
def diagnostics = []
|
||||
try {
|
||||
def dslMap = StandardDslMap.get(context) {
|
||||
it.putCustom('binding', binding)
|
||||
it.loggerName = "GspPart(${ part.path })"
|
||||
it.onDiagnostics = diagnostics.&addAll
|
||||
if (text) {
|
||||
it.text = text
|
||||
}
|
||||
}
|
||||
def result = engine.createTemplate(part.text).make(dslMap)
|
||||
new Tuple2<>(diagnostics, result.toString())
|
||||
} catch (Exception e) {
|
||||
new Tuple2<>(
|
||||
[*diagnostics, new Diagnostic(
|
||||
"An exception occurred while rendering part ${ part.path }:\n${ e }",
|
||||
e
|
||||
)],
|
||||
''
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
"GspPartRenderer()"
|
||||
}
|
||||
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
package com.jessebrault.ssg.part
|
||||
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
import groovy.transform.TupleConstructor
|
||||
|
||||
@TupleConstructor(defaults = false)
|
||||
@NullCheck
|
||||
@EqualsAndHashCode
|
||||
class Part {
|
||||
|
||||
String path
|
||||
PartType type
|
||||
String text
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
"Part(path: ${ this.path }, type: ${ this.type })"
|
||||
}
|
||||
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
package com.jessebrault.ssg.part
|
||||
|
||||
import com.jessebrault.ssg.provider.AbstractFileCollectionProvider
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
import org.jetbrains.annotations.Nullable
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
@NullCheck
|
||||
@EqualsAndHashCode(includeFields = true)
|
||||
class PartFilePartsProvider extends AbstractFileCollectionProvider<Part> implements PartsProvider {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PartFilePartsProvider)
|
||||
|
||||
private final Collection<PartType> partTypes
|
||||
|
||||
PartFilePartsProvider(File partsDir, Collection<PartType> partTypes) {
|
||||
super(partsDir)
|
||||
this.partTypes = Objects.requireNonNull(partTypes)
|
||||
}
|
||||
|
||||
private @Nullable PartType getPartType(String extension) {
|
||||
this.partTypes.find {
|
||||
it.ids.contains(extension)
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable Part transformFileToT(File file, String relativePath, String extension) {
|
||||
def partType = getPartType(extension)
|
||||
if (!partType) {
|
||||
logger.warn('there is no PartType for {}, ignoring', relativePath)
|
||||
}
|
||||
partType ? new Part(relativePath, partType, file.text) : null
|
||||
}
|
||||
|
||||
@Override
|
||||
Collection<PartType> getPartTypes() {
|
||||
this.partTypes
|
||||
}
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
"PartFilePartsProvider(partsDir: ${ this.dir }, partTypes: ${ this.partTypes })"
|
||||
}
|
||||
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
package com.jessebrault.ssg.part
|
||||
|
||||
import com.jessebrault.ssg.Diagnostic
|
||||
import com.jessebrault.ssg.renderer.RenderContext
|
||||
import com.jessebrault.ssg.text.Text
|
||||
import org.jetbrains.annotations.Nullable
|
||||
|
||||
interface PartRenderer {
|
||||
|
||||
Tuple2<Collection<Diagnostic>, String> render(
|
||||
Part part,
|
||||
Map binding,
|
||||
RenderContext context,
|
||||
@Nullable Text text
|
||||
)
|
||||
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
package com.jessebrault.ssg.part
|
||||
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
import groovy.transform.TupleConstructor
|
||||
|
||||
@TupleConstructor(defaults = false)
|
||||
@NullCheck
|
||||
@EqualsAndHashCode
|
||||
class PartType {
|
||||
|
||||
Collection<String> ids
|
||||
PartRenderer renderer
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
"PartType(ids: ${ this.ids }, renderer: ${ this.renderer })"
|
||||
}
|
||||
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package com.jessebrault.ssg.part
|
||||
|
||||
import com.jessebrault.ssg.provider.Provider
|
||||
|
||||
interface PartsProvider extends Provider<Collection<Part>> {
|
||||
Collection<PartType> getPartTypes()
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
package com.jessebrault.ssg.provider
|
||||
|
||||
import groovy.io.FileType
|
||||
import org.jetbrains.annotations.Nullable
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
import static com.jessebrault.ssg.util.ExtensionsUtil.getExtension
|
||||
|
||||
abstract class AbstractFileCollectionProvider<T> implements Provider<Collection<T>>, WithWatchableDir {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(AbstractFileCollectionProvider)
|
||||
|
||||
protected final File dir
|
||||
|
||||
AbstractFileCollectionProvider(File dir) {
|
||||
this.dir = Objects.requireNonNull(dir)
|
||||
this.watchableDir = dir
|
||||
}
|
||||
|
||||
protected abstract @Nullable T transformFileToT(File file, String relativePath, String extension)
|
||||
|
||||
@Override
|
||||
Collection<T> provide() {
|
||||
if (!this.dir.isDirectory()) {
|
||||
logger.warn('{} does not exist or is not a directory; skipping', this.dir)
|
||||
[]
|
||||
} else {
|
||||
def ts = []
|
||||
this.dir.eachFileRecurse(FileType.FILES) {
|
||||
def t = transformFileToT(it, this.dir.relativePath(it), getExtension(it.path))
|
||||
if (t) {
|
||||
ts << t
|
||||
}
|
||||
}
|
||||
ts
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
package com.jessebrault.ssg.provider
|
||||
|
||||
interface Provider<T> {
|
||||
T provide()
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
package com.jessebrault.ssg.provider
|
||||
|
||||
trait WithWatchableDir {
|
||||
File watchableDir
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
package com.jessebrault.ssg.renderer
|
||||
|
||||
import com.jessebrault.ssg.Config
|
||||
import com.jessebrault.ssg.SiteSpec
|
||||
import com.jessebrault.ssg.part.Part
|
||||
import com.jessebrault.ssg.task.TaskContainer
|
||||
import com.jessebrault.ssg.task.TaskTypeContainer
|
||||
import com.jessebrault.ssg.text.Text
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
import groovy.transform.TupleConstructor
|
||||
|
||||
@TupleConstructor(defaults = false)
|
||||
@NullCheck(includeGenerated = true)
|
||||
@EqualsAndHashCode
|
||||
final class RenderContext {
|
||||
final Config config
|
||||
final SiteSpec siteSpec
|
||||
final Map globals
|
||||
final Collection<Text> texts
|
||||
final Collection<Part> parts
|
||||
final String sourcePath
|
||||
final String targetPath
|
||||
final TaskContainer tasks
|
||||
final TaskTypeContainer taskTypes
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
package com.jessebrault.ssg.specialpage
|
||||
|
||||
import com.jessebrault.ssg.Diagnostic
|
||||
import com.jessebrault.ssg.dsl.StandardDslMap
|
||||
import com.jessebrault.ssg.renderer.RenderContext
|
||||
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
|
||||
Tuple2<Collection<Diagnostic>, String> render(
|
||||
SpecialPage specialPage,
|
||||
RenderContext context
|
||||
) {
|
||||
def diagnostics = []
|
||||
try {
|
||||
def dslMap = StandardDslMap.get(context) {
|
||||
it.loggerName = "GspSpecialPage(${ specialPage.path })"
|
||||
it.onDiagnostics = diagnostics.&addAll
|
||||
}
|
||||
def result = engine.createTemplate(specialPage.text).make(dslMap)
|
||||
new Tuple2<>(diagnostics, result.toString())
|
||||
} catch (Exception e) {
|
||||
new Tuple2<>(
|
||||
[*diagnostics, new Diagnostic(
|
||||
"An exception occurred while rendering specialPage ${ specialPage.path }:\n${ e }",
|
||||
e
|
||||
)],
|
||||
''
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
"GspSpecialPageRenderer()"
|
||||
}
|
||||
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
package com.jessebrault.ssg.specialpage
|
||||
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
import groovy.transform.TupleConstructor
|
||||
|
||||
@TupleConstructor(defaults = false)
|
||||
@NullCheck(includeGenerated = true)
|
||||
@EqualsAndHashCode
|
||||
final class SpecialPage {
|
||||
|
||||
final String text
|
||||
final String path
|
||||
final SpecialPageType type
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
"SpecialPage(path: ${ this.path }, type: ${ this.type })"
|
||||
}
|
||||
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
package com.jessebrault.ssg.specialpage
|
||||
|
||||
import com.jessebrault.ssg.provider.AbstractFileCollectionProvider
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
import org.jetbrains.annotations.Nullable
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
@NullCheck
|
||||
@EqualsAndHashCode(includeFields = true)
|
||||
class SpecialPageFileSpecialPagesProvider extends AbstractFileCollectionProvider<SpecialPage>
|
||||
implements SpecialPagesProvider {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SpecialPageFileSpecialPagesProvider)
|
||||
|
||||
private final Collection<SpecialPageType> specialPageTypes
|
||||
|
||||
SpecialPageFileSpecialPagesProvider(File specialPagesDir, Collection<SpecialPageType> specialPageTypes) {
|
||||
super(specialPagesDir)
|
||||
this.specialPageTypes = Objects.requireNonNull(specialPageTypes)
|
||||
}
|
||||
|
||||
private @Nullable SpecialPageType getSpecialPageType(String extension) {
|
||||
this.specialPageTypes.find {
|
||||
it.ids.contains(extension)
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable SpecialPage transformFileToT(File file, String relativePath, String extension) {
|
||||
def specialPageType = getSpecialPageType(extension)
|
||||
if (!specialPageType) {
|
||||
logger.warn('there is no SpecialPageType for {}, ignoring', relativePath)
|
||||
}
|
||||
specialPageType ? new SpecialPage(file.text, relativePath, specialPageType) : null
|
||||
}
|
||||
|
||||
@Override
|
||||
Collection<SpecialPageType> getSpecialPageTypes() {
|
||||
this.specialPageTypes
|
||||
}
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
"SpecialPageFileSpecialPagesProvider(specialPagesDir: ${ this.dir }, " +
|
||||
"specialPageTypes: ${ this.specialPageTypes })"
|
||||
}
|
||||
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
package com.jessebrault.ssg.specialpage
|
||||
|
||||
import com.jessebrault.ssg.Diagnostic
|
||||
import com.jessebrault.ssg.SiteSpec
|
||||
import com.jessebrault.ssg.part.Part
|
||||
import com.jessebrault.ssg.renderer.RenderContext
|
||||
import com.jessebrault.ssg.text.Text
|
||||
|
||||
interface SpecialPageRenderer {
|
||||
|
||||
Tuple2<Collection<Diagnostic>, String> render(
|
||||
SpecialPage specialPage,
|
||||
RenderContext context
|
||||
)
|
||||
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
package com.jessebrault.ssg.specialpage
|
||||
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
import groovy.transform.TupleConstructor
|
||||
|
||||
@TupleConstructor(defaults = false)
|
||||
@NullCheck
|
||||
@EqualsAndHashCode
|
||||
class SpecialPageType {
|
||||
|
||||
Collection<String> ids
|
||||
SpecialPageRenderer renderer
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
"SpecialPageType(ids: ${ this.ids }, renderer: ${ this.renderer })"
|
||||
}
|
||||
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package com.jessebrault.ssg.specialpage
|
||||
|
||||
import com.jessebrault.ssg.provider.Provider
|
||||
|
||||
interface SpecialPagesProvider extends Provider<Collection<SpecialPage>> {
|
||||
Collection<SpecialPageType> getSpecialPageTypes()
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
package com.jessebrault.ssg.tagbuilder
|
||||
|
||||
import org.codehaus.groovy.runtime.InvokerHelper
|
||||
|
||||
class DynamicTagBuilder implements TagBuilder {
|
||||
|
||||
@Override
|
||||
String create(String name) {
|
||||
"<$name />"
|
||||
}
|
||||
|
||||
@Override
|
||||
String create(String name, Map<String, ?> attributes) {
|
||||
def formattedAttributes = attributes.collect {
|
||||
if (it.value instanceof String) {
|
||||
it.key + '="' + it.value + '"'
|
||||
} else if (it.value instanceof Integer) {
|
||||
it.key + '=' + it.value
|
||||
} else if (it.value instanceof Boolean && it.value == true) {
|
||||
it.key
|
||||
} else {
|
||||
it.key + '="' + it.value.toString() + '"'
|
||||
}
|
||||
}.join(' ')
|
||||
"<$name $formattedAttributes />"
|
||||
}
|
||||
|
||||
@Override
|
||||
String create(String name, String body) {
|
||||
"<$name>$body</$name>"
|
||||
}
|
||||
|
||||
@Override
|
||||
String create(String name, Map<String, ?> attributes, String body) {
|
||||
def formattedAttributes = attributes.collect {
|
||||
if (it.value instanceof String) {
|
||||
it.key + '="' + it.value + '"'
|
||||
} else if (it.value instanceof Integer) {
|
||||
it.key + '=' + it.value
|
||||
} else if (it.value instanceof Boolean && it.value == true) {
|
||||
it.key
|
||||
} else {
|
||||
it.key + '="' + it.value.toString() + '"'
|
||||
}
|
||||
}.join(' ')
|
||||
"<$name $formattedAttributes>$body</$name>"
|
||||
}
|
||||
|
||||
@Override
|
||||
Object invokeMethod(String name, Object args) {
|
||||
def argsList = InvokerHelper.asList(args)
|
||||
return switch (argsList.size()) {
|
||||
case 0 -> this.create(name)
|
||||
case 1 -> {
|
||||
def arg0 = argsList[0]
|
||||
if (arg0 instanceof Map) {
|
||||
this.create(name, arg0)
|
||||
} else if (arg0 instanceof String) {
|
||||
this.create(name, arg0)
|
||||
} else {
|
||||
throw new MissingMethodException(name, this.class, args, false)
|
||||
}
|
||||
}
|
||||
case 2 -> {
|
||||
def arg0 = argsList[0]
|
||||
def arg1 = argsList[1]
|
||||
if (arg0 instanceof Map && arg1 instanceof String) {
|
||||
this.create(name, arg0, arg1)
|
||||
} else {
|
||||
throw new MissingMethodException(name, this.class, args, false)
|
||||
}
|
||||
}
|
||||
default -> throw new MissingMethodException(name, this.class, args, false)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
package com.jessebrault.ssg.tagbuilder
|
||||
|
||||
interface TagBuilder {
|
||||
String create(String name)
|
||||
String create(String name, Map<String, ?> attributes)
|
||||
String create(String name, String body)
|
||||
String create(String name, Map<String, ?> attributes, String body)
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
package com.jessebrault.ssg.task
|
||||
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
|
||||
@NullCheck
|
||||
@EqualsAndHashCode
|
||||
abstract class AbstractTask<T extends Task> implements Task {
|
||||
|
||||
final TaskType<T> type
|
||||
final String name
|
||||
|
||||
AbstractTask(TaskType<T> type, String name) {
|
||||
this.type = type
|
||||
this.name = name
|
||||
}
|
||||
|
||||
protected abstract T getThis()
|
||||
|
||||
@Override
|
||||
void execute(TaskExecutorContext context) {
|
||||
// I am guessing that if we put this.getThis(), it will think the runtime type is AbstractTask? Not sure.
|
||||
this.type.executor.execute(getThis(), context)
|
||||
}
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
"AbstractTask(name: ${ this.name }, type: ${ this.type })"
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
package com.jessebrault.ssg.task
|
||||
|
||||
interface FileInput extends Input {
|
||||
File getFile()
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
package com.jessebrault.ssg.task
|
||||
|
||||
interface FileOutput extends Output {
|
||||
File getFile()
|
||||
String getContent()
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
package com.jessebrault.ssg.task
|
||||
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
import groovy.transform.TupleConstructor
|
||||
|
||||
@TupleConstructor(defaults = false, includeFields = true)
|
||||
@NullCheck(includeGenerated = true)
|
||||
@EqualsAndHashCode
|
||||
final class HtmlFileOutput {
|
||||
|
||||
final File file
|
||||
final String htmlPath
|
||||
|
||||
private final Closure<String> contentClosure
|
||||
|
||||
String getContent(TaskContainer tasks, TaskTypeContainer taskTypes, Closure onDiagnostics) {
|
||||
this.contentClosure(tasks, taskTypes, onDiagnostics)
|
||||
}
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
"HtmlFileOutput(file: ${ this.file }, htmlPath: ${ this.htmlPath })"
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
package com.jessebrault.ssg.task
|
||||
|
||||
interface Input {
|
||||
String getName()
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
package com.jessebrault.ssg.task
|
||||
|
||||
interface Output {
|
||||
String getName()
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
package com.jessebrault.ssg.task
|
||||
|
||||
import com.jessebrault.ssg.specialpage.SpecialPage
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
|
||||
@NullCheck
|
||||
@EqualsAndHashCode
|
||||
final class SpecialPageToHtmlFileTask extends AbstractTask<SpecialPageToHtmlFileTask> {
|
||||
|
||||
private static final class SpecialPageToHtmlFileTaskExecutor implements TaskExecutor<SpecialPageToHtmlFileTask> {
|
||||
|
||||
@Override
|
||||
void execute(SpecialPageToHtmlFileTask task, TaskExecutorContext context) {
|
||||
task.output.file.createParentDirectories()
|
||||
task.output.file.write(task.output.getContent(
|
||||
context.allTasks, context.allTypes, context.onDiagnostics
|
||||
))
|
||||
}
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
'SpecialPageToHtmlFileTaskExecutor()'
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static final TaskType<SpecialPageToHtmlFileTask> TYPE = new TaskType<>(
|
||||
'specialPageToHtmlFile', new SpecialPageToHtmlFileTaskExecutor()
|
||||
)
|
||||
|
||||
final SpecialPage input
|
||||
final HtmlFileOutput output
|
||||
|
||||
SpecialPageToHtmlFileTask(String name, SpecialPage input, HtmlFileOutput output) {
|
||||
super(TYPE, name)
|
||||
this.input = input
|
||||
this.output = output
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SpecialPageToHtmlFileTask getThis() {
|
||||
this
|
||||
}
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
"SpecialPageToHtmlFileTask(input: ${ this.input }, output: ${ this.output }, super: ${ super })"
|
||||
}
|
||||
|
||||
}
|
@ -1,87 +0,0 @@
|
||||
package com.jessebrault.ssg.task
|
||||
|
||||
import com.jessebrault.ssg.Build
|
||||
import com.jessebrault.ssg.Result
|
||||
import com.jessebrault.ssg.renderer.RenderContext
|
||||
import com.jessebrault.ssg.util.ExtensionsUtil
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.slf4j.Marker
|
||||
import org.slf4j.MarkerFactory
|
||||
|
||||
final class SpecialPageToHtmlFileTaskFactory implements TaskFactory<SpecialPageToHtmlFileTask> {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SpecialPageToHtmlFileTaskFactory)
|
||||
private static final Marker enter = MarkerFactory.getMarker('ENTER')
|
||||
private static final Marker exit = MarkerFactory.getMarker('EXIT')
|
||||
|
||||
@Override
|
||||
TaskType<SpecialPageToHtmlFileTask> getTaskType() {
|
||||
SpecialPageToHtmlFileTask.TYPE
|
||||
}
|
||||
|
||||
@Override
|
||||
Result<TaskCollection<SpecialPageToHtmlFileTask>> getTasks(Build build) {
|
||||
logger.trace(enter, 'build: {}', build)
|
||||
logger.info('processing build with name {} for SpecialPageToHtmlFileTasks', build.name)
|
||||
|
||||
def config = build.config
|
||||
def siteSpec = build.siteSpec
|
||||
def globals = build.globals
|
||||
|
||||
def specialPages = config.specialPagesProviders.collectMany { it.provide() }
|
||||
def templates = config.templatesProviders.collectMany { it.provide() }
|
||||
def parts = config.partsProviders.collectMany { it.provide() }
|
||||
def texts = config.textProviders.collectMany { it.provide() }
|
||||
|
||||
logger.debug('\n\tspecialPages: {}\n\ttemplates: {}\n\tparts: {}', specialPages, templates, parts)
|
||||
|
||||
def tasks = new TaskCollection<SpecialPageToHtmlFileTask>(specialPages.findResults {
|
||||
logger.trace(enter, 'specialPage: {}', it)
|
||||
logger.info('processing specialPage with path: {}', it.path)
|
||||
|
||||
def htmlPath = ExtensionsUtil.stripExtension(it.path) + '.html'
|
||||
|
||||
def renderSpecialPage = { TaskContainer tasks, TaskTypeContainer taskTypes, Closure<Void> onDiagnostics ->
|
||||
def renderResult = it.type.renderer.render(
|
||||
it,
|
||||
new RenderContext(
|
||||
config,
|
||||
siteSpec,
|
||||
globals,
|
||||
texts,
|
||||
parts,
|
||||
it.path,
|
||||
htmlPath,
|
||||
tasks,
|
||||
taskTypes
|
||||
)
|
||||
)
|
||||
|
||||
if (!renderResult.v1.isEmpty()) {
|
||||
onDiagnostics(renderResult.v1)
|
||||
''
|
||||
} else {
|
||||
renderResult.v2
|
||||
}
|
||||
}
|
||||
|
||||
def result = new SpecialPageToHtmlFileTask(
|
||||
"specialPageToHtmlFileTask:${ it.path }:${ htmlPath }",
|
||||
it,
|
||||
new HtmlFileOutput(
|
||||
new File(build.outDir, htmlPath),
|
||||
htmlPath,
|
||||
renderSpecialPage
|
||||
)
|
||||
)
|
||||
logger.trace(exit, 'result: {}', result)
|
||||
result
|
||||
})
|
||||
|
||||
def result = new Result<>([], tasks)
|
||||
logger.trace(exit, 'result: {}', result)
|
||||
result
|
||||
}
|
||||
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package com.jessebrault.ssg.task
|
||||
|
||||
interface Task {
|
||||
TaskType<? extends Task> getType()
|
||||
String getName()
|
||||
void execute(TaskExecutorContext context)
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
package com.jessebrault.ssg.task
|
||||
|
||||
import static java.util.Objects.requireNonNull
|
||||
|
||||
class TaskCollection<T extends Task> {
|
||||
|
||||
@Delegate
|
||||
private final Collection<T> tasks = new ArrayList<T>()
|
||||
|
||||
TaskCollection(Collection<? extends T> tasks = null) {
|
||||
if (tasks != null) {
|
||||
this.tasks.addAll(requireNonNull(tasks))
|
||||
}
|
||||
}
|
||||
|
||||
def <U extends T> TaskCollection<U> findAllByType(
|
||||
TaskType<U> taskType
|
||||
) {
|
||||
new TaskCollection<>(this.tasks.findResults {
|
||||
it.type == taskType ? it : null
|
||||
})
|
||||
}
|
||||
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
package com.jessebrault.ssg.task
|
||||
|
||||
final class TaskContainer extends TaskCollection<Task> {
|
||||
|
||||
TaskContainer(Collection<? extends Task> tasks = null) {
|
||||
super(tasks)
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
package com.jessebrault.ssg.task
|
||||
|
||||
interface TaskExecutor<T extends Task> {
|
||||
void execute(T task, TaskExecutorContext context)
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
package com.jessebrault.ssg.task
|
||||
|
||||
import com.jessebrault.ssg.Build
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
import groovy.transform.TupleConstructor
|
||||
|
||||
@TupleConstructor(defaults = false)
|
||||
@NullCheck(includeGenerated = true)
|
||||
@EqualsAndHashCode
|
||||
final class TaskExecutorContext {
|
||||
|
||||
final Build build
|
||||
final TaskContainer allTasks
|
||||
final TaskTypeContainer allTypes
|
||||
final Closure onDiagnostics
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
"TaskExecutorContext(build: ${ this.build }, allTasks: ${ this.allTasks }, allTypes: ${ this.allTypes })"
|
||||
}
|
||||
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
package com.jessebrault.ssg.task
|
||||
|
||||
import com.jessebrault.ssg.Build
|
||||
import com.jessebrault.ssg.Result
|
||||
|
||||
interface TaskFactory<T extends Task> {
|
||||
TaskType<T> getTaskType()
|
||||
Result<TaskCollection<T>> getTasks(Build build)
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
package com.jessebrault.ssg.task
|
||||
|
||||
import com.jessebrault.ssg.provider.Provider
|
||||
import groovy.io.FileType
|
||||
|
||||
final class TaskFactoryManager {
|
||||
|
||||
Collection<TaskFactory> getAllFactories(Collection<Provider<File>> factoryPluginDirectoryProviders) {
|
||||
def factories = []
|
||||
|
||||
def gcl = new GroovyClassLoader()
|
||||
def pluginDirectories = factoryPluginDirectoryProviders.collect { it.provide() }
|
||||
pluginDirectories.each {
|
||||
it.eachFileRecurse(FileType.FILES) {
|
||||
def cl = gcl.parseClass(it)
|
||||
def constructor = cl.getDeclaredConstructor()
|
||||
def factory = constructor.newInstance() as TaskFactory
|
||||
factories << factory
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
factories
|
||||
}
|
||||
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
package com.jessebrault.ssg.task
|
||||
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
import groovy.transform.TupleConstructor
|
||||
|
||||
@TupleConstructor(defaults = false)
|
||||
@NullCheck(includeGenerated = true)
|
||||
@EqualsAndHashCode
|
||||
final class TaskType<T extends Task> {
|
||||
|
||||
final String name
|
||||
final TaskExecutor<T> executor
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
"TaskType(${ this.name }, ${ this.executor })"
|
||||
}
|
||||
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
package com.jessebrault.ssg.task
|
||||
|
||||
final class TaskTypeContainer {
|
||||
|
||||
@Delegate
|
||||
private final Set<TaskType<? extends Task>> taskTypes = []
|
||||
|
||||
TaskTypeContainer(Collection<TaskType<? extends Task>> taskTypes) {
|
||||
if (taskTypes != null) {
|
||||
this.taskTypes.addAll(taskTypes)
|
||||
}
|
||||
}
|
||||
|
||||
TaskTypeContainer(TaskTypeContainer taskTypeContainer) {
|
||||
if (taskTypeContainer != null) {
|
||||
this.taskTypes.addAll(taskTypeContainer)
|
||||
}
|
||||
}
|
||||
|
||||
TaskTypeContainer() {}
|
||||
|
||||
@Override
|
||||
TaskType<? extends Task> getProperty(String propertyName) {
|
||||
def taskType = this.taskTypes.find { it.name == propertyName }
|
||||
if (!taskType) {
|
||||
throw new IllegalArgumentException("no such taskType: ${ propertyName }")
|
||||
}
|
||||
taskType
|
||||
}
|
||||
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
package com.jessebrault.ssg.task
|
||||
|
||||
import com.jessebrault.ssg.text.Text
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
import groovy.transform.TupleConstructor
|
||||
|
||||
@TupleConstructor(defaults = false)
|
||||
@NullCheck(includeGenerated = true)
|
||||
@EqualsAndHashCode
|
||||
final class TextInput implements Input {
|
||||
final String name
|
||||
final Text text
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
package com.jessebrault.ssg.task
|
||||
|
||||
import com.jessebrault.ssg.text.Text
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
|
||||
@NullCheck
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
final class TextToHtmlFileTask extends AbstractTask<TextToHtmlFileTask> {
|
||||
|
||||
private static final class TextToHtmlFileTaskExecutor implements TaskExecutor<TextToHtmlFileTask> {
|
||||
|
||||
@Override
|
||||
void execute(TextToHtmlFileTask task, TaskExecutorContext context) {
|
||||
task.output.file.createParentDirectories()
|
||||
task.output.file.write(task.output.getContent(
|
||||
context.allTasks, context.allTypes, context.onDiagnostics
|
||||
))
|
||||
}
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
'TextToHtmlFileTaskExecutor()'
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static final TaskType<TextToHtmlFileTask> TYPE = new TaskType<>(
|
||||
'textToHtmlFile', new TextToHtmlFileTaskExecutor()
|
||||
)
|
||||
|
||||
final Text input
|
||||
final HtmlFileOutput output
|
||||
|
||||
TextToHtmlFileTask(String name, Text input, HtmlFileOutput output) {
|
||||
super(TYPE, name)
|
||||
this.input = input
|
||||
this.output = output
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TextToHtmlFileTask getThis() {
|
||||
this
|
||||
}
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
"TextToHtmlFileTask(input: ${ this.input }, output: ${ this.output }, super: ${ super })"
|
||||
}
|
||||
|
||||
}
|
@ -1,117 +0,0 @@
|
||||
package com.jessebrault.ssg.task
|
||||
|
||||
import com.jessebrault.ssg.Build
|
||||
import com.jessebrault.ssg.Diagnostic
|
||||
import com.jessebrault.ssg.Result
|
||||
import com.jessebrault.ssg.renderer.RenderContext
|
||||
import com.jessebrault.ssg.text.FrontMatter
|
||||
import com.jessebrault.ssg.util.ExtensionsUtil
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.slf4j.Marker
|
||||
import org.slf4j.MarkerFactory
|
||||
|
||||
final class TextToHtmlFileTaskFactory implements TaskFactory<TextToHtmlFileTask> {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(TextToHtmlFileTaskFactory)
|
||||
private static final Marker enter = MarkerFactory.getMarker('ENTER')
|
||||
private static final Marker exit = MarkerFactory.getMarker('EXIT')
|
||||
|
||||
@Override
|
||||
TaskType<TextToHtmlFileTask> getTaskType() {
|
||||
TextToHtmlFileTask.TYPE
|
||||
}
|
||||
|
||||
@Override
|
||||
Result<TaskCollection<TextToHtmlFileTask>> getTasks(Build build) {
|
||||
logger.trace(enter, 'build: {}', build)
|
||||
logger.info('getting TextToHtmlFileTasks for build with name: {}', build.name)
|
||||
|
||||
def config = build.config
|
||||
def siteSpec = build.siteSpec
|
||||
def globals = build.globals
|
||||
def diagnostics = []
|
||||
|
||||
// Get all texts, templates, parts, and specialPages
|
||||
def texts = config.textProviders.collectMany { it.provide() }
|
||||
def templates = config.templatesProviders.collectMany { it.provide() }
|
||||
def parts = config.partsProviders.collectMany { it.provide() }
|
||||
|
||||
logger.debug('\n\ttexts: {}\n\ttemplates: {}\n\tparts: {}', texts, templates, parts)
|
||||
|
||||
def tasks = new TaskCollection<TextToHtmlFileTask>(texts.findResults {
|
||||
logger.trace(enter, 'text: {}', it)
|
||||
logger.info('processing text with path: {}', it.path)
|
||||
|
||||
def frontMatterResult = it.type.frontMatterGetter.get(it)
|
||||
FrontMatter frontMatter
|
||||
if (!frontMatterResult.v1.isEmpty()) {
|
||||
diagnostics.addAll(frontMatterResult.v1)
|
||||
logger.trace(exit, 'result: {}', null)
|
||||
return null
|
||||
} else {
|
||||
frontMatter = frontMatterResult.v2
|
||||
logger.debug('frontMatter: {}', frontMatter)
|
||||
}
|
||||
|
||||
def desiredTemplate = frontMatter.find('template')
|
||||
if (desiredTemplate.isEmpty()) {
|
||||
logger.info('text with path {} has no \'template\' key in its frontMatter; skipping', it.path)
|
||||
logger.trace(exit, 'result: {}', null)
|
||||
return null
|
||||
}
|
||||
def template = templates.find { it.path == desiredTemplate.get() }
|
||||
if (template == null) {
|
||||
diagnostics << new Diagnostic("in text with path ${ it.path }, frontMatter.template refers to an unknown template: ${ desiredTemplate.get() }")
|
||||
logger.trace(exit, 'result: {}', null)
|
||||
return null
|
||||
}
|
||||
logger.debug('found template: {}', template)
|
||||
|
||||
def htmlPath = ExtensionsUtil.stripExtension(it.path) + '.html'
|
||||
|
||||
def renderTemplate = { TaskContainer tasks, TaskTypeContainer taskTypes, Closure<Void> onDiagnostics ->
|
||||
def templateRenderResult = template.type.renderer.render(
|
||||
template,
|
||||
it,
|
||||
new RenderContext(
|
||||
config,
|
||||
siteSpec,
|
||||
globals,
|
||||
texts,
|
||||
parts,
|
||||
it.path,
|
||||
htmlPath,
|
||||
tasks,
|
||||
taskTypes
|
||||
)
|
||||
)
|
||||
|
||||
if (!templateRenderResult.v1.isEmpty()) {
|
||||
onDiagnostics(templateRenderResult.v1)
|
||||
''
|
||||
} else {
|
||||
templateRenderResult.v2
|
||||
}
|
||||
}
|
||||
|
||||
def result = new TextToHtmlFileTask(
|
||||
"textToHtmlFileTask:${ it.path }:${ htmlPath }",
|
||||
it,
|
||||
new HtmlFileOutput(
|
||||
new File(build.outDir, htmlPath),
|
||||
htmlPath,
|
||||
renderTemplate
|
||||
)
|
||||
)
|
||||
|
||||
logger.trace(exit, 'result: {}', result)
|
||||
result
|
||||
})
|
||||
|
||||
def result = new Result<>(diagnostics, tasks)
|
||||
logger.trace(exit, 'result: {}', result)
|
||||
result
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
package com.jessebrault.ssg.task
|
||||
|
||||
interface WithInput<I extends Input> {
|
||||
I getInput()
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
package com.jessebrault.ssg.task
|
||||
|
||||
interface WithOutput<O extends Output> {
|
||||
O getOutput()
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
package com.jessebrault.ssg.template
|
||||
|
||||
import com.jessebrault.ssg.Diagnostic
|
||||
import com.jessebrault.ssg.dsl.StandardDslMap
|
||||
import com.jessebrault.ssg.renderer.RenderContext
|
||||
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 GspTemplateRenderer implements TemplateRenderer {
|
||||
|
||||
private static final TemplateEngine engine = new GStringTemplateEngine()
|
||||
|
||||
@Override
|
||||
Tuple2<Collection<Diagnostic>, String> render(
|
||||
Template template,
|
||||
Text text,
|
||||
RenderContext context
|
||||
) {
|
||||
def diagnostics = []
|
||||
try {
|
||||
def dslMap = StandardDslMap.get(context) {
|
||||
it.loggerName = "GspTemplate(${ template.path })"
|
||||
it.onDiagnostics = diagnostics.&addAll
|
||||
it.text = text
|
||||
}
|
||||
def result = engine.createTemplate(template.text).make(dslMap)
|
||||
new Tuple2<>(diagnostics, result.toString())
|
||||
} catch (Exception e) {
|
||||
new Tuple2<>(
|
||||
[*diagnostics, new Diagnostic(
|
||||
"An exception occurred while rendering Template ${ template.path }:\n${ e }",
|
||||
e
|
||||
)],
|
||||
''
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
"GspTemplateRenderer()"
|
||||
}
|
||||
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
package com.jessebrault.ssg.template
|
||||
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
import groovy.transform.TupleConstructor
|
||||
|
||||
@TupleConstructor(defaults = false)
|
||||
@NullCheck
|
||||
@EqualsAndHashCode
|
||||
class Template {
|
||||
|
||||
String text
|
||||
String path
|
||||
TemplateType type
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
"Template(path: ${ this.path }, type: ${ this.type })"
|
||||
}
|
||||
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
package com.jessebrault.ssg.template
|
||||
|
||||
import com.jessebrault.ssg.provider.AbstractFileCollectionProvider
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
import org.jetbrains.annotations.Nullable
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
@NullCheck
|
||||
@EqualsAndHashCode(includeFields = true)
|
||||
class TemplateFileTemplatesProvider extends AbstractFileCollectionProvider<Template> implements TemplatesProvider {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(TemplateFileTemplatesProvider)
|
||||
|
||||
private final Collection<TemplateType> templateTypes
|
||||
|
||||
TemplateFileTemplatesProvider(File templatesDir, Collection<TemplateType> templateTypes) {
|
||||
super(templatesDir)
|
||||
this.templateTypes = Objects.requireNonNull(templateTypes)
|
||||
}
|
||||
|
||||
private @Nullable TemplateType getType(String extension) {
|
||||
this.templateTypes.find {
|
||||
it.ids.contains(extension)
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Template transformFileToT(File file, String relativePath, String extension) {
|
||||
def templateType = getType(extension)
|
||||
if (templateType == null) {
|
||||
logger.warn('there is no TemplateType for template {}, ignoring', relativePath)
|
||||
}
|
||||
templateType ? new Template(file.text, relativePath, templateType) : null
|
||||
}
|
||||
|
||||
@Override
|
||||
Collection<TemplateType> getTemplateTypes() {
|
||||
this.templateTypes
|
||||
}
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
"TemplateFileTemplatesProvider(templatesDir: ${ this.dir }, templateTypes: ${ this.templateTypes })"
|
||||
}
|
||||
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
package com.jessebrault.ssg.template
|
||||
|
||||
import com.jessebrault.ssg.Diagnostic
|
||||
import com.jessebrault.ssg.renderer.RenderContext
|
||||
import com.jessebrault.ssg.text.Text
|
||||
|
||||
interface TemplateRenderer {
|
||||
|
||||
Tuple2<Collection<Diagnostic>, String> render(
|
||||
Template template,
|
||||
Text text,
|
||||
RenderContext context
|
||||
)
|
||||
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
package com.jessebrault.ssg.template
|
||||
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
import groovy.transform.TupleConstructor
|
||||
|
||||
@TupleConstructor(defaults = false)
|
||||
@NullCheck
|
||||
@EqualsAndHashCode
|
||||
class TemplateType {
|
||||
|
||||
Collection<String> ids
|
||||
TemplateRenderer renderer
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
"TemplateType(ids: ${ this.ids }, renderer: ${ this.renderer })"
|
||||
}
|
||||
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package com.jessebrault.ssg.template
|
||||
|
||||
import com.jessebrault.ssg.provider.Provider
|
||||
|
||||
interface TemplatesProvider extends Provider<Collection<Template>> {
|
||||
Collection<TemplateType> getTemplateTypes()
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
package com.jessebrault.ssg.text
|
||||
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.Memoized
|
||||
import groovy.transform.NullCheck
|
||||
import groovy.transform.TupleConstructor
|
||||
|
||||
@TupleConstructor(includeFields = true, defaults = false)
|
||||
@NullCheck(includeGenerated = true)
|
||||
@EqualsAndHashCode(includeFields = true)
|
||||
class EmbeddableText {
|
||||
|
||||
private final Text text
|
||||
private final Map globals
|
||||
private final Closure onDiagnostics
|
||||
|
||||
@Memoized
|
||||
String render() {
|
||||
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() {
|
||||
def result = this.text.type.frontMatterGetter.get(this.text)
|
||||
if (result.v1.size() > 0) {
|
||||
this.onDiagnostics.call(result.v1)
|
||||
new FrontMatter(this.text, [:])
|
||||
} else {
|
||||
result.v2
|
||||
}
|
||||
}
|
||||
|
||||
@Memoized
|
||||
String getExcerpt(int limit) {
|
||||
def result = this.text.type.excerptGetter.getExcerpt(this.text, limit)
|
||||
if (result.v1.size() > 0) {
|
||||
this.onDiagnostics.call(result.v1)
|
||||
''
|
||||
} else {
|
||||
result.v2
|
||||
}
|
||||
}
|
||||
|
||||
String getPath() {
|
||||
this.text.path
|
||||
}
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
"EmbeddableText(text: ${ this.text }, globals: ${ this.globals })"
|
||||
}
|
||||
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
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, Closure onDiagnostics) {
|
||||
Objects.requireNonNull(texts).each {
|
||||
this << new EmbeddableText(it, globals, onDiagnostics)
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
"EmbeddableTextsCollection(embeddableTexts: ${ this.embeddableTexts })"
|
||||
}
|
||||
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package com.jessebrault.ssg.text
|
||||
|
||||
import com.jessebrault.ssg.Diagnostic
|
||||
|
||||
interface ExcerptGetter {
|
||||
Tuple2<Collection<Diagnostic>, String> getExcerpt(Text text, int limit)
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
package com.jessebrault.ssg.text
|
||||
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
import groovy.transform.TupleConstructor
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
@TupleConstructor(includeFields = true, defaults = false)
|
||||
@NullCheck
|
||||
@EqualsAndHashCode(includeFields = true)
|
||||
class FrontMatter {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(FrontMatter)
|
||||
|
||||
private final Text text
|
||||
private final Map<String, List<String>> data
|
||||
|
||||
String get(String key) {
|
||||
if (this.data[key] != null) {
|
||||
this.data[key][0]
|
||||
} else {
|
||||
logger.warn('in {} no entry for key {} in frontMatter, returning empty string', this.text, key)
|
||||
''
|
||||
}
|
||||
}
|
||||
|
||||
String getAt(String key) {
|
||||
this.get(key)
|
||||
}
|
||||
|
||||
List<String> getList(String key) {
|
||||
if (data[key] != null) {
|
||||
data[key]
|
||||
} else {
|
||||
logger.warn('in {} no entry for key {} in frontMatter, returning empty list: {}', this.text, key)
|
||||
[]
|
||||
}
|
||||
}
|
||||
|
||||
Optional<String> find(String key) {
|
||||
Optional.ofNullable(this.data[key]?[0])
|
||||
}
|
||||
|
||||
Optional<List<String>> findList(String key) {
|
||||
Optional.ofNullable(this.data[key])
|
||||
}
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
"FrontMatter(text: ${ this.text }, data: ${ this.data })"
|
||||
}
|
||||
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package com.jessebrault.ssg.text
|
||||
|
||||
import com.jessebrault.ssg.Diagnostic
|
||||
|
||||
interface FrontMatterGetter {
|
||||
Tuple2<Collection<Diagnostic>, FrontMatter> get(Text text)
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
package com.jessebrault.ssg.text
|
||||
|
||||
import com.jessebrault.ssg.Diagnostic
|
||||
import org.commonmark.ext.front.matter.YamlFrontMatterExtension
|
||||
import org.commonmark.node.AbstractVisitor
|
||||
import org.commonmark.parser.Parser
|
||||
|
||||
class MarkdownExcerptGetter implements ExcerptGetter {
|
||||
|
||||
private static class ExcerptVisitor extends AbstractVisitor {
|
||||
|
||||
final int limit
|
||||
List<String> words = []
|
||||
|
||||
ExcerptVisitor(int limit) {
|
||||
this.limit = limit
|
||||
}
|
||||
|
||||
@Override
|
||||
void visit(org.commonmark.node.Text text) {
|
||||
if (this.words.size() <= limit) {
|
||||
def textWords = text.literal.split('\\s+').toList()
|
||||
def taken = textWords.take(this.limit - this.words.size())
|
||||
this.words.addAll(taken)
|
||||
}
|
||||
}
|
||||
|
||||
String getResult() {
|
||||
this.words.take(this.limit).join(' ')
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final Parser parser = Parser.builder()
|
||||
.extensions([YamlFrontMatterExtension.create()])
|
||||
.build()
|
||||
|
||||
@Override
|
||||
Tuple2<Collection<Diagnostic>, String> getExcerpt(Text text, int limit) {
|
||||
try {
|
||||
def node = parser.parse(text.text)
|
||||
def visitor = new ExcerptVisitor(limit)
|
||||
node.accept(visitor)
|
||||
new Tuple2<>([], visitor.result)
|
||||
} catch (Exception e) {
|
||||
def diagnostic = new Diagnostic(
|
||||
"There was an exception while getting the excerpt for ${ text }:\n${ e }",
|
||||
e
|
||||
)
|
||||
new Tuple2<>([diagnostic], '')
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
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 {
|
||||
|
||||
private static final Parser parser = Parser.builder()
|
||||
.extensions([YamlFrontMatterExtension.create()])
|
||||
.build()
|
||||
|
||||
@Override
|
||||
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(text, v.data))
|
||||
} catch (Exception e) {
|
||||
new Tuple2<>([new Diagnostic("An exception occured while parsing frontMatter for ${ text.path }:\n${ e }", e)], new FrontMatter(text, [:]))
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
"MarkdownFrontMatterGetter()"
|
||||
}
|
||||
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
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 {
|
||||
|
||||
private static final Parser parser = Parser.builder()
|
||||
.extensions([YamlFrontMatterExtension.create()])
|
||||
.build()
|
||||
private static final HtmlRenderer htmlRenderer = HtmlRenderer.builder().build()
|
||||
|
||||
@Override
|
||||
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
|
||||
String toString() {
|
||||
"MarkdownTextRenderer()"
|
||||
}
|
||||
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
package com.jessebrault.ssg.text
|
||||
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
import groovy.transform.TupleConstructor
|
||||
|
||||
@TupleConstructor(defaults = false)
|
||||
@NullCheck(includeGenerated = true)
|
||||
@EqualsAndHashCode
|
||||
final class Text {
|
||||
|
||||
final String text
|
||||
final String path
|
||||
final TextType type
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
"Text(path: ${ this.path }, type: ${ this.type })"
|
||||
}
|
||||
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
package com.jessebrault.ssg.text
|
||||
|
||||
import com.jessebrault.ssg.provider.AbstractFileCollectionProvider
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
import org.jetbrains.annotations.Nullable
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
@NullCheck
|
||||
@EqualsAndHashCode(includeFields = true)
|
||||
class TextFileTextsProvider extends AbstractFileCollectionProvider<Text> implements TextsProvider {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(TextFileTextsProvider)
|
||||
|
||||
private final Collection<TextType> textTypes
|
||||
|
||||
TextFileTextsProvider(File textsDir, Collection<TextType> textTypes) {
|
||||
super(textsDir)
|
||||
this.textTypes = Objects.requireNonNull(textTypes)
|
||||
}
|
||||
|
||||
private TextType getTextType(String extension) {
|
||||
this.textTypes.find {
|
||||
it.ids.contains(extension)
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable Text transformFileToT(File file, String relativePath, String extension) {
|
||||
def textType = getTextType(extension)
|
||||
if (!textType) {
|
||||
logger.warn('no TextType for text {}, ignoring', file.path)
|
||||
}
|
||||
textType ? new Text(file.text, relativePath, textType) : null
|
||||
}
|
||||
|
||||
@Override
|
||||
Collection<TextType> getTextTypes() {
|
||||
this.textTypes
|
||||
}
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
"TextFileTextsProvider(textsDir: ${ this.dir }, textTypes: ${ this.textTypes })"
|
||||
}
|
||||
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package com.jessebrault.ssg.text
|
||||
|
||||
import com.jessebrault.ssg.Diagnostic
|
||||
|
||||
interface TextRenderer {
|
||||
Tuple2<Collection<Diagnostic>, String> render(Text text, Map globals)
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
package com.jessebrault.ssg.text
|
||||
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
import groovy.transform.TupleConstructor
|
||||
|
||||
@TupleConstructor(defaults = false)
|
||||
@NullCheck
|
||||
@EqualsAndHashCode
|
||||
class TextType {
|
||||
|
||||
Collection<String> ids
|
||||
TextRenderer renderer
|
||||
FrontMatterGetter frontMatterGetter
|
||||
ExcerptGetter excerptGetter
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
"TextType(ids: ${ this.ids }, renderer: ${ this.renderer }, frontMatterGetter: ${ this.renderer }, excerptGetter: ${ this.excerptGetter })"
|
||||
}
|
||||
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package com.jessebrault.ssg.text
|
||||
|
||||
import com.jessebrault.ssg.provider.Provider
|
||||
|
||||
interface TextsProvider extends Provider<Collection<Text>> {
|
||||
Collection<TextType> getTextTypes()
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
package com.jessebrault.ssg.url
|
||||
|
||||
import java.nio.file.Path
|
||||
|
||||
class PathBasedUrlBuilder implements UrlBuilder {
|
||||
|
||||
private final String absolute
|
||||
private final String baseUrl
|
||||
private final Path fromDirectory
|
||||
|
||||
PathBasedUrlBuilder(String targetPath, String baseUrl) {
|
||||
this.absolute = baseUrl + '/' + targetPath
|
||||
this.baseUrl = baseUrl
|
||||
def fromFilePath = Path.of(targetPath)
|
||||
if (fromFilePath.parent) {
|
||||
this.fromDirectory = fromFilePath.parent
|
||||
} else {
|
||||
this.fromDirectory = Path.of('')
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
String getAbsolute() {
|
||||
this.absolute
|
||||
}
|
||||
|
||||
@Override
|
||||
String absolute(String to) {
|
||||
this.baseUrl + '/' + to
|
||||
}
|
||||
|
||||
@Override
|
||||
String relative(String to) {
|
||||
this.fromDirectory.relativize(Path.of(to)).toString()
|
||||
}
|
||||
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package com.jessebrault.ssg.url
|
||||
|
||||
interface UrlBuilder {
|
||||
String getAbsolute()
|
||||
String absolute(String to)
|
||||
String relative(String to)
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
package com.jessebrault.ssg.util
|
||||
|
||||
import java.util.regex.Pattern
|
||||
|
||||
class ExtensionsUtil {
|
||||
|
||||
private static final Pattern stripExtensionPattern = ~/(.+)\..+$/
|
||||
private static final Pattern getExtensionPattern = ~/.+(\..+)$/
|
||||
|
||||
static String stripExtension(String path) {
|
||||
def m = stripExtensionPattern.matcher(path)
|
||||
m.matches() ? m.group(1) : path
|
||||
}
|
||||
|
||||
static String getExtension(String path) {
|
||||
def m = getExtensionPattern.matcher(path)
|
||||
if (m.matches()) {
|
||||
m.group(1)
|
||||
} else {
|
||||
throw new IllegalArgumentException("cannot get extension for path: ${ path }")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,156 +0,0 @@
|
||||
package com.jessebrault.ssg
|
||||
|
||||
import com.jessebrault.ssg.part.GspPartRenderer
|
||||
import com.jessebrault.ssg.part.PartFilePartsProvider
|
||||
import com.jessebrault.ssg.part.PartType
|
||||
import com.jessebrault.ssg.specialpage.GspSpecialPageRenderer
|
||||
import com.jessebrault.ssg.specialpage.SpecialPageFileSpecialPagesProvider
|
||||
import com.jessebrault.ssg.specialpage.SpecialPageType
|
||||
import com.jessebrault.ssg.task.SpecialPageToHtmlFileTask
|
||||
import com.jessebrault.ssg.task.Task
|
||||
import com.jessebrault.ssg.task.TaskTypeContainer
|
||||
import com.jessebrault.ssg.task.TextToHtmlFileTask
|
||||
import com.jessebrault.ssg.template.GspTemplateRenderer
|
||||
import com.jessebrault.ssg.template.TemplateFileTemplatesProvider
|
||||
import com.jessebrault.ssg.template.TemplateType
|
||||
import com.jessebrault.ssg.text.MarkdownExcerptGetter
|
||||
import com.jessebrault.ssg.text.MarkdownFrontMatterGetter
|
||||
import com.jessebrault.ssg.text.MarkdownTextRenderer
|
||||
import com.jessebrault.ssg.text.TextFileTextsProvider
|
||||
import com.jessebrault.ssg.text.TextType
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
import static com.jessebrault.ssg.testutil.DiagnosticsUtil.assertEmptyDiagnostics
|
||||
import static com.jessebrault.ssg.testutil.DiagnosticsUtil.getDiagnosticsMessageSupplier
|
||||
import static org.junit.jupiter.api.Assertions.*
|
||||
|
||||
class SimpleStaticSiteGeneratorIntegrationTests {
|
||||
|
||||
private File partsDir
|
||||
private File templatesDir
|
||||
private File textsDir
|
||||
private File specialPagesDir
|
||||
|
||||
private Build build
|
||||
private StaticSiteGenerator ssg
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
this.textsDir = File.createTempDir()
|
||||
this.templatesDir = File.createTempDir()
|
||||
this.partsDir = File.createTempDir()
|
||||
this.specialPagesDir = File.createTempDir()
|
||||
|
||||
def markdownTextType = new TextType(['.md'], new MarkdownTextRenderer(), new MarkdownFrontMatterGetter(), new MarkdownExcerptGetter())
|
||||
def gspTemplateType = new TemplateType(['.gsp'], new GspTemplateRenderer())
|
||||
def gspPartType = new PartType(['.gsp'], new GspPartRenderer())
|
||||
def gspSpecialPageType = new SpecialPageType(['.gsp'], new GspSpecialPageRenderer())
|
||||
|
||||
def textsProvider = new TextFileTextsProvider(this.textsDir, [markdownTextType])
|
||||
def templatesProvider = new TemplateFileTemplatesProvider(this.templatesDir, [gspTemplateType])
|
||||
def partsProvider = new PartFilePartsProvider(this.partsDir, [gspPartType])
|
||||
def specialPagesProvider = new SpecialPageFileSpecialPagesProvider(this.specialPagesDir, [gspSpecialPageType])
|
||||
|
||||
def config = new Config(
|
||||
textProviders: [textsProvider],
|
||||
templatesProviders: [templatesProvider],
|
||||
partsProviders: [partsProvider],
|
||||
specialPagesProviders: [specialPagesProvider]
|
||||
)
|
||||
def siteSpec = new SiteSpec('Test Site', 'https://test.com')
|
||||
def globals = [:]
|
||||
|
||||
this.build = new Build('testBuild', config, siteSpec, globals, new File('build'))
|
||||
this.ssg = new SimpleStaticSiteGenerator()
|
||||
}
|
||||
|
||||
@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.render() %>')
|
||||
|
||||
def result = this.ssg.generate(this.build)
|
||||
|
||||
assertEmptyDiagnostics(result)
|
||||
def tasks = result.get()
|
||||
assertTrue(tasks.size() == 1)
|
||||
|
||||
def t0 = tasks.findAllByType(TextToHtmlFileTask.TYPE)[0]
|
||||
assertEquals('test.html', t0.output.htmlPath)
|
||||
def contentResult = t0.output.getContent(tasks, new TaskTypeContainer([TextToHtmlFileTask.TYPE])) { Collection<Diagnostic> diagnostics ->
|
||||
fail(getDiagnosticsMessageSupplier(diagnostics))
|
||||
}
|
||||
assertEquals('<p><strong>Hello, World!</strong></p>\n', contentResult)
|
||||
}
|
||||
|
||||
@Test
|
||||
void nested() {
|
||||
new FileTreeBuilder(this.textsDir).with {
|
||||
dir('nested') {
|
||||
file('nested.md', '---\ntemplate: nested.gsp\n---\n**Hello, World!**')
|
||||
}
|
||||
}
|
||||
|
||||
new File(this.templatesDir, 'nested.gsp').write('<%= text.render() %>')
|
||||
|
||||
def result = this.ssg.generate(this.build)
|
||||
|
||||
assertEmptyDiagnostics(result)
|
||||
def tasks = result.get()
|
||||
assertTrue(tasks.size() == 1)
|
||||
|
||||
def t0 = tasks.findAllByType(TextToHtmlFileTask.TYPE)[0]
|
||||
assertEquals('nested/nested.html', t0.output.htmlPath)
|
||||
def contentResult = t0.output.getContent(
|
||||
tasks,
|
||||
new TaskTypeContainer([TextToHtmlFileTask.TYPE])
|
||||
) { Collection<Diagnostic> diagnostics ->
|
||||
fail(getDiagnosticsMessageSupplier(diagnostics))
|
||||
}
|
||||
assertEquals('<p><strong>Hello, World!</strong></p>\n', contentResult)
|
||||
}
|
||||
|
||||
@Test
|
||||
void outputsSpecialPage() {
|
||||
new FileTreeBuilder(this.specialPagesDir)
|
||||
.file('special.gsp', $/<%= texts.find { it.path == 'test.md' }.render() %>/$)
|
||||
new FileTreeBuilder(this.templatesDir).file('template.gsp', '<%= 1 + 1 %>')
|
||||
new FileTreeBuilder(this.textsDir).file('test.md', '---\ntemplate: template.gsp\n---\nHello, World!')
|
||||
|
||||
def result = this.ssg.generate(this.build)
|
||||
|
||||
assertEmptyDiagnostics(result)
|
||||
def tasks = result.get()
|
||||
assertEquals(2, tasks.size())
|
||||
|
||||
def taskTypes = new TaskTypeContainer([TextToHtmlFileTask.TYPE, SpecialPageToHtmlFileTask.TYPE])
|
||||
|
||||
def testPageTask = tasks.findAllByType(TextToHtmlFileTask.TYPE).find {
|
||||
it.output.htmlPath == 'test.html'
|
||||
}
|
||||
assertNotNull(testPageTask)
|
||||
def testPageContent = testPageTask.output.getContent(tasks, taskTypes) { Collection<Diagnostic> diagnostics ->
|
||||
fail(getDiagnosticsMessageSupplier(diagnostics))
|
||||
}
|
||||
assertEquals('2', testPageContent)
|
||||
|
||||
def specialPageTask = tasks.findAllByType(SpecialPageToHtmlFileTask.TYPE).find {
|
||||
it.output.htmlPath == 'special.html'
|
||||
}
|
||||
assertNotNull(specialPageTask)
|
||||
def specialPageContent = specialPageTask.output.getContent(tasks, taskTypes) { Collection<Diagnostic> diagnostics ->
|
||||
fail(getDiagnosticsMessageSupplier(diagnostics))
|
||||
}
|
||||
assertEquals('<p>Hello, World!</p>\n', specialPageContent)
|
||||
}
|
||||
|
||||
@Test
|
||||
void doesNotGenerateIfNoTemplateInFrontMatter() {
|
||||
new File(this.textsDir, 'test.md').write('Hello, World!')
|
||||
def result = this.ssg.generate(this.build)
|
||||
assertEmptyDiagnostics(result)
|
||||
assertEquals(0, result.get().size())
|
||||
}
|
||||
|
||||
}
|
@ -1,110 +0,0 @@
|
||||
package com.jessebrault.ssg.part
|
||||
|
||||
import com.jessebrault.ssg.Diagnostic
|
||||
import com.jessebrault.ssg.dsl.StandardDslConsumerTests
|
||||
import com.jessebrault.ssg.renderer.RenderContext
|
||||
import com.jessebrault.ssg.text.Text
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.mockito.junit.jupiter.MockitoExtension
|
||||
|
||||
import static com.jessebrault.ssg.testutil.DiagnosticsUtil.assertDiagnosticException
|
||||
import static com.jessebrault.ssg.testutil.RenderContextUtil.getRenderContext
|
||||
import static com.jessebrault.ssg.text.TextMocks.renderableText
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals
|
||||
|
||||
@ExtendWith(MockitoExtension)
|
||||
class GspPartRendererTests implements StandardDslConsumerTests {
|
||||
|
||||
private final PartRenderer renderer = new GspPartRenderer()
|
||||
|
||||
private Tuple2<Collection<Diagnostic>, String> doRender(
|
||||
String scriptlet,
|
||||
RenderContext context,
|
||||
Map binding = [:],
|
||||
Text text = null
|
||||
) {
|
||||
this.renderer.render(
|
||||
new Part('', new PartType([], this.renderer), scriptlet),
|
||||
binding,
|
||||
context,
|
||||
text
|
||||
)
|
||||
}
|
||||
|
||||
@Override
|
||||
Tuple2<Collection<Diagnostic>, String> render(String scriptlet, RenderContext context) {
|
||||
this.doRender(scriptlet, context)
|
||||
}
|
||||
|
||||
@Test
|
||||
void rendersWithBinding() {
|
||||
this.checkResult(
|
||||
'Hello, World!',
|
||||
this.doRender('<%= binding.greeting %>', getRenderContext(), [greeting: 'Hello, World!'])
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
void textAvailable() {
|
||||
this.checkResult('Hello, World!', this.renderer.render(
|
||||
new Part('', new PartType([], this.renderer), '<%= text.render() %>'),
|
||||
[:],
|
||||
getRenderContext(),
|
||||
renderableText('Hello, World!')
|
||||
))
|
||||
}
|
||||
|
||||
@Test
|
||||
void nestedPartDiagnosticBubblesUp() {
|
||||
def nestedProblemPart = new Part(
|
||||
'nestedProblem.gsp',
|
||||
new PartType([], this.renderer),
|
||||
'<% throw new RuntimeException() %>'
|
||||
)
|
||||
def callerPart = new Part(
|
||||
'caller.gsp',
|
||||
null,
|
||||
'<% parts["nestedProblem.gsp"].render() %>'
|
||||
)
|
||||
def r = this.renderer.render(
|
||||
callerPart,
|
||||
[:],
|
||||
getRenderContext(parts: [callerPart, nestedProblemPart]),
|
||||
null
|
||||
)
|
||||
assertEquals(1, r.v1.size())
|
||||
assertDiagnosticException(RuntimeException, r.v1[0])
|
||||
assertEquals('', r.v2)
|
||||
}
|
||||
|
||||
@Test
|
||||
void nestedPartIsBlankWhenThrowingExceptionButCallerRendered() {
|
||||
def nestedProblemPart = new Part(
|
||||
'nestedProblem.gsp',
|
||||
new PartType([], this.renderer),
|
||||
'<% throw new RuntimeException("nested problem exception") %>'
|
||||
)
|
||||
def callerPart = new Part(
|
||||
'caller.gsp',
|
||||
null,
|
||||
'Hello, World!<% parts["nestedProblem.gsp"].render() %>'
|
||||
)
|
||||
def r = this.renderer.render(
|
||||
callerPart,
|
||||
[:],
|
||||
getRenderContext(parts: [callerPart, nestedProblemPart]),
|
||||
null
|
||||
)
|
||||
assertEquals(1, r.v1.size())
|
||||
assertDiagnosticException(RuntimeException, r.v1[0]) { e ->
|
||||
assertEquals('nested problem exception', e.message, {
|
||||
def w = new StringWriter()
|
||||
e.printStackTrace(new PrintWriter(w))
|
||||
w.toString()
|
||||
})
|
||||
}
|
||||
assertEquals('Hello, World!', r.v2)
|
||||
}
|
||||
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
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
|
||||
import static org.mockito.Mockito.mock
|
||||
|
||||
class PartFilePartsProviderTests {
|
||||
|
||||
private static final PartType gspPartType = new PartType(['.gsp'], mock(PartRenderer))
|
||||
|
||||
private File partsDir
|
||||
private PartsProvider partsProvider
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
this.partsDir = File.createTempDir()
|
||||
partsProvider = new PartFilePartsProvider(this.partsDir, [gspPartType])
|
||||
}
|
||||
|
||||
@Test
|
||||
void findsPart() {
|
||||
new FileTreeBuilder(this.partsDir).file('testPart.gsp') {
|
||||
write('Hello <%= name %>!')
|
||||
}
|
||||
|
||||
def r = this.partsProvider.provide()
|
||||
assertEquals(1, r.size())
|
||||
def p0 = r[0]
|
||||
assertEquals('testPart.gsp', p0.path)
|
||||
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.provide()
|
||||
assertEquals(1, r.size())
|
||||
def p0 = r[0]
|
||||
assertEquals('nested/testPart.gsp', p0.path)
|
||||
assertEquals(gspPartType, p0.type)
|
||||
assertEquals('Hello, World!', p0.text)
|
||||
}
|
||||
|
||||
@Test
|
||||
void ignoresUnsupportedFile() {
|
||||
new FileTreeBuilder(this.partsDir).file('.ignored') {
|
||||
write 'Ignored!'
|
||||
}
|
||||
|
||||
def r = this.partsProvider.provide()
|
||||
assertEquals(0, r.size())
|
||||
}
|
||||
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
package com.jessebrault.ssg.specialpage
|
||||
|
||||
import com.jessebrault.ssg.Diagnostic
|
||||
import com.jessebrault.ssg.dsl.StandardDslConsumerTests
|
||||
import com.jessebrault.ssg.renderer.RenderContext
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.mockito.junit.jupiter.MockitoExtension
|
||||
|
||||
@ExtendWith(MockitoExtension)
|
||||
class GspSpecialPageRendererTests implements StandardDslConsumerTests {
|
||||
|
||||
private final SpecialPageRenderer renderer = new GspSpecialPageRenderer()
|
||||
|
||||
@Override
|
||||
Tuple2<Collection<Diagnostic>, String> render(String scriptlet, RenderContext context) {
|
||||
this.renderer.render(
|
||||
new SpecialPage(scriptlet, '', new SpecialPageType([], this.renderer)),
|
||||
context
|
||||
)
|
||||
}
|
||||
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
package com.jessebrault.ssg.specialpage
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals
|
||||
import static org.mockito.Mockito.mock
|
||||
|
||||
class SpecialPageFileSpecialPagesProviderTests {
|
||||
|
||||
private static final SpecialPageType gspType = new SpecialPageType(['.gsp'], mock(SpecialPageRenderer))
|
||||
|
||||
private File specialPagesDir
|
||||
private SpecialPagesProvider specialPagesProvider
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
this.specialPagesDir = File.createTempDir()
|
||||
this.specialPagesProvider = new SpecialPageFileSpecialPagesProvider(this.specialPagesDir, [gspType])
|
||||
}
|
||||
|
||||
@Test
|
||||
void findsSpecialPage() {
|
||||
new FileTreeBuilder(this.specialPagesDir)
|
||||
.file('test.gsp', '<%= "Hello, World!" %>')
|
||||
|
||||
def r = this.specialPagesProvider.provide()
|
||||
assertEquals(1, r.size())
|
||||
def f0 = r[0]
|
||||
assertEquals('test.gsp', f0.path)
|
||||
assertEquals('<%= "Hello, World!" %>', f0.text)
|
||||
assertEquals(gspType, f0.type)
|
||||
}
|
||||
|
||||
@Test
|
||||
void findsNestedSpecialPage() {
|
||||
new FileTreeBuilder(this.specialPagesDir).dir('nested') {
|
||||
file('nested.gsp', '<%= "Hello, World!" %>')
|
||||
}
|
||||
|
||||
def r = this.specialPagesProvider.provide()
|
||||
assertEquals(1, r.size())
|
||||
def f0 = r[0]
|
||||
assertEquals('nested/nested.gsp', f0.path)
|
||||
assertEquals('<%= "Hello, World!" %>', f0.text)
|
||||
assertEquals(gspType, f0.type)
|
||||
}
|
||||
|
||||
@Test
|
||||
void ignoresUnsupportedFile() {
|
||||
new FileTreeBuilder(this.specialPagesDir).file('.ignored', 'Ignored!')
|
||||
|
||||
def r = this.specialPagesProvider.provide()
|
||||
assertEquals(0, r.size())
|
||||
}
|
||||
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
package com.jessebrault.ssg.tagbuilder
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals
|
||||
|
||||
class TagBuilderTests {
|
||||
|
||||
private final TagBuilder tagBuilder = new DynamicTagBuilder()
|
||||
|
||||
@Test
|
||||
void simple() {
|
||||
assertEquals('<test />', this.tagBuilder.create('test'))
|
||||
}
|
||||
|
||||
@Test
|
||||
void withAttributes() {
|
||||
assertEquals('<test test="abc" />', this.tagBuilder.create('test', [test: 'abc']))
|
||||
}
|
||||
|
||||
@Test
|
||||
void withBody() {
|
||||
assertEquals('<test>test</test>', this.tagBuilder.create('test', 'test'))
|
||||
}
|
||||
|
||||
@Test
|
||||
void withAttributesAndBody() {
|
||||
assertEquals(
|
||||
'<test test="abc">test</test>',
|
||||
this.tagBuilder.create('test', [test: 'abc'], 'test')
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
void dynamicSimple() {
|
||||
assertEquals('<test />', this.tagBuilder.test())
|
||||
}
|
||||
|
||||
@Test
|
||||
void dynamicWithAttributes() {
|
||||
assertEquals('<test test="abc" />', this.tagBuilder.test([test: 'abc']))
|
||||
}
|
||||
|
||||
@Test
|
||||
void dynamicWithBody() {
|
||||
assertEquals('<test>test</test>', this.tagBuilder.test('test'))
|
||||
}
|
||||
|
||||
@Test
|
||||
void dynamicWithAttributesAndBody() {
|
||||
assertEquals('<test test="abc">test</test>', this.tagBuilder.test([test: 'abc'], 'test'))
|
||||
}
|
||||
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
package com.jessebrault.ssg.template
|
||||
|
||||
import com.jessebrault.ssg.Diagnostic
|
||||
import com.jessebrault.ssg.dsl.StandardDslConsumerTests
|
||||
import com.jessebrault.ssg.renderer.RenderContext
|
||||
import com.jessebrault.ssg.text.Text
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.mockito.junit.jupiter.MockitoExtension
|
||||
|
||||
import static com.jessebrault.ssg.testutil.DiagnosticsUtil.getDiagnosticsMessageSupplier
|
||||
import static com.jessebrault.ssg.testutil.RenderContextUtil.getRenderContext
|
||||
import static com.jessebrault.ssg.text.TextMocks.blankText
|
||||
import static com.jessebrault.ssg.text.TextMocks.renderableText
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue
|
||||
|
||||
@ExtendWith(MockitoExtension)
|
||||
class GspTemplateRendererTests implements StandardDslConsumerTests {
|
||||
|
||||
private final TemplateRenderer renderer = new GspTemplateRenderer()
|
||||
|
||||
private Tuple2<Collection<Diagnostic>, String> doRender(String scriptlet, Text text, RenderContext context) {
|
||||
this.renderer.render(new Template(scriptlet, '', null), text, context)
|
||||
}
|
||||
|
||||
@Override
|
||||
Tuple2<Collection<Diagnostic>, String> render(String scriptlet, RenderContext context) {
|
||||
this.doRender(scriptlet, blankText(), context)
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: refactor this and the super interface methods so that we can re-use rendering logic
|
||||
*/
|
||||
@Test
|
||||
void textAvailableToRender() {
|
||||
def template = new Template('<%= text.render() %>', null, null)
|
||||
def r = this.renderer.render(
|
||||
template,
|
||||
renderableText('Hello, World!'),
|
||||
getRenderContext()
|
||||
)
|
||||
assertTrue(r.v1.isEmpty(), getDiagnosticsMessageSupplier(r.v1))
|
||||
assertEquals('Hello, World!', r.v2)
|
||||
}
|
||||
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
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
|
||||
import static org.mockito.Mockito.mock
|
||||
|
||||
class TemplateFileTemplatesProviderTests {
|
||||
|
||||
private static final TemplateType gspType = new TemplateType(['.gsp'], mock(TemplateRenderer))
|
||||
|
||||
private File templatesDir
|
||||
private TemplatesProvider templatesProvider
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
this.templatesDir = File.createTempDir()
|
||||
this.templatesProvider = new TemplateFileTemplatesProvider(this.templatesDir, [gspType])
|
||||
}
|
||||
|
||||
@Test
|
||||
void findsTemplate() {
|
||||
new File(this.templatesDir, 'test.gsp').write('<% out << text %>')
|
||||
|
||||
def r = this.templatesProvider.provide()
|
||||
assertEquals(1, r.size())
|
||||
def t0 = r[0]
|
||||
assertEquals('test.gsp', t0.path)
|
||||
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.provide()
|
||||
assertEquals(1, r.size())
|
||||
def t0 = r[0]
|
||||
assertEquals('nested/nested.gsp', t0.path)
|
||||
assertEquals('<%= text %>', t0.text)
|
||||
assertEquals(gspType, t0.type)
|
||||
}
|
||||
|
||||
@Test
|
||||
void ignoresUnsupportedFile() {
|
||||
new File(this.templatesDir, '.ignored').with {
|
||||
write('Ignored!')
|
||||
}
|
||||
|
||||
def r = this.templatesProvider.provide()
|
||||
assertEquals(0, r.size())
|
||||
}
|
||||
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
package com.jessebrault.ssg.text
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
import static com.jessebrault.ssg.text.TextMocks.renderableText
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals
|
||||
|
||||
class ExcerptGetterTests {
|
||||
|
||||
ExcerptGetter excerptGetter = new MarkdownExcerptGetter()
|
||||
|
||||
@Test
|
||||
void takesAllIfTextLessThanLimit() {
|
||||
def text = renderableText('One Two Three Four Five')
|
||||
def result = this.excerptGetter.getExcerpt(text, 10)
|
||||
assertEquals(0, result.v1.size())
|
||||
assertEquals('One Two Three Four Five', result.v2)
|
||||
}
|
||||
|
||||
@Test
|
||||
void takesTheLimit() {
|
||||
def text = renderableText('One Two Three Four Five')
|
||||
def result = this.excerptGetter.getExcerpt(text, 2)
|
||||
assertEquals(0, result.v1.size())
|
||||
assertEquals('One Two', result.v2)
|
||||
}
|
||||
|
||||
@Test
|
||||
void worksWithHeading() {
|
||||
def text = renderableText('# Heading\nOne Two Three')
|
||||
def result = this.excerptGetter.getExcerpt(text, 1)
|
||||
assertEquals(0, result.v1.size())
|
||||
assertEquals('Heading', result.v2)
|
||||
}
|
||||
|
||||
@Test
|
||||
void worksWithFrontMatter() {
|
||||
def text = renderableText('---\ntest: hello\n---\nOne Two Three')
|
||||
def result = this.excerptGetter.getExcerpt(text, 1)
|
||||
assertEquals(0, result.v1.size())
|
||||
assertEquals('One', result.v2)
|
||||
}
|
||||
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
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
|
||||
import static org.mockito.Mockito.mock
|
||||
|
||||
class TextFileTextsProviderTests {
|
||||
|
||||
private static final TextType markdownType = new TextType(
|
||||
['.md'],
|
||||
mock(TextRenderer),
|
||||
mock(FrontMatterGetter),
|
||||
mock(ExcerptGetter)
|
||||
)
|
||||
|
||||
private File textsDir
|
||||
private TextsProvider textsProvider
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
this.textsDir = File.createTempDir()
|
||||
this.textsProvider = new TextFileTextsProvider(this.textsDir, [markdownType])
|
||||
}
|
||||
|
||||
@Test
|
||||
void findsFile() {
|
||||
new FileTreeBuilder(this.textsDir).file('test.md', '**Hello, World!**')
|
||||
|
||||
def r = this.textsProvider.provide()
|
||||
assertEquals(1, r.size())
|
||||
def f0 = r[0]
|
||||
assertEquals('test.md', 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 = this.textsProvider.provide()
|
||||
assertEquals(1, r.size())
|
||||
def f0 = r[0]
|
||||
assertEquals('nested/nested.md', f0.path)
|
||||
assertEquals('**Hello!**', f0.text)
|
||||
assertEquals(markdownType, f0.type)
|
||||
}
|
||||
|
||||
@Test
|
||||
void ignoresUnsupportedFile() {
|
||||
new FileTreeBuilder(this.textsDir).file('.ignored', 'Ignored!')
|
||||
|
||||
def r = this.textsProvider.provide()
|
||||
assertEquals(0, r.size())
|
||||
}
|
||||
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
package com.jessebrault.ssg.url
|
||||
|
||||
class PathBasedUrlBuilderTests extends AbstractUrlBuilderTests {
|
||||
|
||||
@Override
|
||||
protected UrlBuilder getUrlBuilder(String targetPath, String baseUrl) {
|
||||
new PathBasedUrlBuilder(targetPath, baseUrl)
|
||||
}
|
||||
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
package com.jessebrault.ssg.util
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
import static com.jessebrault.ssg.util.ExtensionsUtil.stripExtension
|
||||
import static com.jessebrault.ssg.util.ExtensionsUtil.getExtension
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals
|
||||
|
||||
class ExtensionsUtilTests {
|
||||
|
||||
static class StripExtensionTests {
|
||||
|
||||
@Test
|
||||
void simple() {
|
||||
assertEquals('test', stripExtension('test.txt'))
|
||||
}
|
||||
|
||||
@Test
|
||||
void withSlashes() {
|
||||
assertEquals('test/test', stripExtension('test/test.txt'))
|
||||
}
|
||||
|
||||
@Test
|
||||
void withMultipleExtensions() {
|
||||
assertEquals('test.txt', stripExtension('test.txt.html'))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class GetExtensionTests {
|
||||
|
||||
@Test
|
||||
void simple() {
|
||||
assertEquals('.txt', getExtension('test.txt'))
|
||||
}
|
||||
|
||||
@Test
|
||||
void withSlashes() {
|
||||
assertEquals('.txt', getExtension('test/test.txt'))
|
||||
}
|
||||
|
||||
@Test
|
||||
void withMultipleExtensions() {
|
||||
assertEquals('.txt', getExtension('test.test.txt'))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<Configuration name="ssg" status="WARN">
|
||||
<Appenders>
|
||||
<Console name="standard" target="SYSTEM_OUT">
|
||||
<PatternLayout>
|
||||
<MarkerPatternSelector defaultPattern="%highlight{%-5level} %logger{1}: %msg%n%ex">
|
||||
<PatternMatch key="FLOW" pattern="%highlight{%-5level} %logger{1}: %markerSimpleName %msg%n%ex" />
|
||||
</MarkerPatternSelector>
|
||||
</PatternLayout>
|
||||
</Console>
|
||||
</Appenders>
|
||||
<Loggers>
|
||||
<Root level="trace">
|
||||
<AppenderRef ref="standard" />
|
||||
</Root>
|
||||
</Loggers>
|
||||
</Configuration>
|
@ -1,28 +0,0 @@
|
||||
package com.jessebrault.ssg.dsl
|
||||
|
||||
interface DslScriptletProvider {
|
||||
String getGlobalsAvailable()
|
||||
String getRenderGlobal()
|
||||
|
||||
String getLoggerAvailable()
|
||||
|
||||
String getPartsAvailable()
|
||||
String getRenderPartFromParts()
|
||||
|
||||
String getSiteSpecAvailable()
|
||||
String getRenderSiteSpecValues()
|
||||
|
||||
String getSourcePathAvailable()
|
||||
String getRenderSourcePathValue()
|
||||
|
||||
String getTagBuilderAvailable()
|
||||
|
||||
String getTargetPathAvailable()
|
||||
String getRenderTargetPath()
|
||||
|
||||
String getTextsAvailable()
|
||||
String getRenderTextFromTexts()
|
||||
|
||||
String getUrlBuilderAvailable()
|
||||
String getUrlBuilderCorrectlyConfigured()
|
||||
}
|
@ -1,240 +0,0 @@
|
||||
package com.jessebrault.ssg.dsl
|
||||
|
||||
import com.jessebrault.ssg.Diagnostic
|
||||
import com.jessebrault.ssg.SiteSpec
|
||||
import com.jessebrault.ssg.part.EmbeddablePartsMap
|
||||
import com.jessebrault.ssg.part.Part
|
||||
import com.jessebrault.ssg.part.PartRenderer
|
||||
import com.jessebrault.ssg.part.PartType
|
||||
import com.jessebrault.ssg.renderer.RenderContext
|
||||
import com.jessebrault.ssg.tagbuilder.TagBuilder
|
||||
import com.jessebrault.ssg.task.HtmlFileOutput
|
||||
import com.jessebrault.ssg.task.SpecialPageToHtmlFileTask
|
||||
import com.jessebrault.ssg.task.TaskContainer
|
||||
import com.jessebrault.ssg.task.TaskTypeContainer
|
||||
import com.jessebrault.ssg.task.TextToHtmlFileTask
|
||||
import com.jessebrault.ssg.task.TextToHtmlFileTaskFactory
|
||||
import com.jessebrault.ssg.text.EmbeddableTextsCollection
|
||||
import com.jessebrault.ssg.url.UrlBuilder
|
||||
import net.bytebuddy.implementation.bytecode.Throw
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.mockito.Mock
|
||||
import org.mockito.MockedStatic
|
||||
import org.mockito.junit.jupiter.MockitoExtension
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
import static com.jessebrault.ssg.task.SpecialPageToHtmlFileTaskMocks.blankSpecialPageToHtmlFileTask
|
||||
import static com.jessebrault.ssg.task.TextToHtmlFileTaskMocks.blankTextToHtmlFileTask
|
||||
import static com.jessebrault.ssg.testutil.DiagnosticsUtil.assertEmptyDiagnostics
|
||||
import static com.jessebrault.ssg.testutil.RenderContextUtil.getRenderContext
|
||||
import static com.jessebrault.ssg.text.TextMocks.blankText
|
||||
import static com.jessebrault.ssg.text.TextMocks.renderableTextWithPath
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals
|
||||
import static org.junit.jupiter.api.Assertions.fail
|
||||
import static org.mockito.ArgumentMatchers.any
|
||||
import static org.mockito.ArgumentMatchers.anyString
|
||||
import static org.mockito.Mockito.*
|
||||
|
||||
@ExtendWith(MockitoExtension)
|
||||
interface StandardDslConsumerTests {
|
||||
|
||||
Tuple2<Collection<Diagnostic>, String> render(String scriptlet, RenderContext context)
|
||||
|
||||
default void checkResult(String expected, Tuple2<Collection<Diagnostic>, String> result) {
|
||||
assertEmptyDiagnostics(result)
|
||||
assertEquals(expected, result.v2)
|
||||
}
|
||||
|
||||
default void doDslRenderTest(String expected, String scriptlet, RenderContext context = null) {
|
||||
this.checkResult(expected, this.render(scriptlet, context ?: getRenderContext()))
|
||||
}
|
||||
|
||||
default void doDslAssertionTest(String scriptlet, RenderContext context = null) {
|
||||
Tuple2<Collection<Diagnostic>, String> result = null
|
||||
try {
|
||||
result = this.render(scriptlet, context ?: getRenderContext())
|
||||
} catch (Throwable e) {
|
||||
fail(e)
|
||||
}
|
||||
assertEmptyDiagnostics(result)
|
||||
}
|
||||
|
||||
@Test
|
||||
default void rendersGlobal() {
|
||||
this.doDslRenderTest(
|
||||
'Hello, World!',
|
||||
'<%= globals.test %>',
|
||||
getRenderContext(globals: [test: 'Hello, World!'])
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
default void loggerAvailable(@Mock Logger logger) {
|
||||
try (MockedStatic<LoggerFactory> loggerFactory = mockStatic(LoggerFactory)) {
|
||||
loggerFactory.when { LoggerFactory.getLogger(anyString()) }
|
||||
.thenReturn(logger)
|
||||
|
||||
this.doDslAssertionTest('<% assert logger; logger.info("Hello, World!") %>')
|
||||
verify(logger).info('Hello, World!')
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
default void partsAvailable() {
|
||||
this.doDslAssertionTest("<% assert parts != null && parts instanceof ${ EmbeddablePartsMap.name } %>")
|
||||
}
|
||||
|
||||
@Test
|
||||
default void partAvailableAndRenderable(@Mock PartRenderer partRenderer) {
|
||||
when(partRenderer.render(any(), any(), any(), any()))
|
||||
.thenReturn(new Tuple2<>([], 'Hello, World!'))
|
||||
def part = new Part(
|
||||
'test.gsp',
|
||||
new PartType([], partRenderer),
|
||||
'Hello, World!'
|
||||
)
|
||||
this.doDslRenderTest(
|
||||
'Hello, World!',
|
||||
'<%= parts["test.gsp"].render() %>',
|
||||
getRenderContext(parts: [part])
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
default void siteSpecAvailable() {
|
||||
this.doDslAssertionTest(
|
||||
"<% assert siteSpec && siteSpec instanceof ${ SiteSpec.name } %>"
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
default void siteSpecRendersCorrectValues() {
|
||||
def siteSpec = new SiteSpec('Test Site', 'https://test.com')
|
||||
this.doDslRenderTest(
|
||||
'Test Site https://test.com',
|
||||
'<%= siteSpec.name + " " + siteSpec.baseUrl %>',
|
||||
getRenderContext(siteSpec: siteSpec)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
default void sourcePathAvailable() {
|
||||
this.doDslAssertionTest(
|
||||
'<% assert sourcePath && sourcePath instanceof String %>',
|
||||
getRenderContext(sourcePath: 'test.md')
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
default void sourcePathRendersCorrectValue() {
|
||||
this.doDslRenderTest(
|
||||
'test.md',
|
||||
'<%= sourcePath %>',
|
||||
getRenderContext(sourcePath: 'test.md')
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
default void tagBuilderAvailable() {
|
||||
this.doDslAssertionTest("<% assert tagBuilder && tagBuilder instanceof ${ TagBuilder.name } %>")
|
||||
}
|
||||
|
||||
@Test
|
||||
default void targetPathAvailable() {
|
||||
this.doDslAssertionTest(
|
||||
'<% assert targetPath && targetPath instanceof String %>',
|
||||
getRenderContext(targetPath: 'test/test.html')
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
default void targetPathRendersCorrectValue() {
|
||||
this.doDslRenderTest(
|
||||
'test/test.html',
|
||||
'<%= targetPath %>',
|
||||
getRenderContext(targetPath: 'test/test.html')
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
default void tasksAvailable() {
|
||||
this.doDslAssertionTest("<% assert tasks != null && tasks instanceof ${ TaskContainer.name } %>")
|
||||
}
|
||||
|
||||
@Test
|
||||
default void tasksFind() {
|
||||
def task = new TextToHtmlFileTask(
|
||||
'testTask',
|
||||
blankText(),
|
||||
new HtmlFileOutput(
|
||||
new File('test.html'),
|
||||
'test.html',
|
||||
{ '' }
|
||||
)
|
||||
)
|
||||
this.doDslRenderTest(
|
||||
'test.html',
|
||||
'<%= tasks.find { it.name == "testTask" }.output.htmlPath %>',
|
||||
getRenderContext(
|
||||
tasks: new TaskContainer([task]),
|
||||
taskTypes: new TaskTypeContainer([TextToHtmlFileTask.TYPE])
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
default void taskTypesAvailable() {
|
||||
this.doDslAssertionTest(
|
||||
"<% assert taskTypes != null && taskTypes instanceof ${ TaskTypeContainer.name } %>"
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
default void taskFindAllByType() {
|
||||
def t0 = blankTextToHtmlFileTask()
|
||||
def t1 = blankSpecialPageToHtmlFileTask()
|
||||
this.doDslAssertionTest(
|
||||
'<% assert tasks.size() == 2 && ' +
|
||||
'tasks.findAllByType(taskTypes.textToHtmlFile).size() == 1 &&' +
|
||||
'tasks.findAllByType(taskTypes.specialPageToHtmlFile).size() == 1 %>',
|
||||
getRenderContext(
|
||||
tasks: new TaskContainer([t0, t1]),
|
||||
taskTypes: new TaskTypeContainer([TextToHtmlFileTask.TYPE, SpecialPageToHtmlFileTask.TYPE])
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
default void textsAvailable() {
|
||||
this.doDslAssertionTest(
|
||||
"<% assert texts != null && texts instanceof ${ EmbeddableTextsCollection.name } %>"
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
default void textsTextAvailableAndRenderable() {
|
||||
def testText = renderableTextWithPath('Hello, World!', 'test.md')
|
||||
this.doDslRenderTest(
|
||||
'Hello, World!',
|
||||
'<%= texts.find { it.path == "test.md" }.render() %>',
|
||||
getRenderContext(texts: [testText])
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
default void urlBuilderAvailable() {
|
||||
this.doDslAssertionTest("<% assert urlBuilder && urlBuilder instanceof ${ UrlBuilder.name } %>")
|
||||
}
|
||||
|
||||
@Test
|
||||
default void urlBuilderCorrectlyConfigured() {
|
||||
this.doDslRenderTest(
|
||||
'../images/test.jpg',
|
||||
'<%= urlBuilder.relative("images/test.jpg") %>',
|
||||
getRenderContext(targetPath: 'test/test.html')
|
||||
)
|
||||
}
|
||||
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
package com.jessebrault.ssg.specialpage
|
||||
|
||||
import static org.mockito.Mockito.mock
|
||||
|
||||
final class SpecialPageMocks {
|
||||
|
||||
static SpecialPage blankSpecialPage() {
|
||||
def renderer = mock(SpecialPageRenderer)
|
||||
new SpecialPage(
|
||||
'',
|
||||
'',
|
||||
new SpecialPageType([], renderer)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
package com.jessebrault.ssg.task
|
||||
|
||||
import static com.jessebrault.ssg.specialpage.SpecialPageMocks.blankSpecialPage
|
||||
|
||||
final class SpecialPageToHtmlFileTaskMocks {
|
||||
|
||||
static SpecialPageToHtmlFileTask blankSpecialPageToHtmlFileTask() {
|
||||
new SpecialPageToHtmlFileTask(
|
||||
'',
|
||||
blankSpecialPage(),
|
||||
new HtmlFileOutput(
|
||||
new File(''),
|
||||
'',
|
||||
{ '' }
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
package com.jessebrault.ssg.task
|
||||
|
||||
import static com.jessebrault.ssg.text.TextMocks.blankText
|
||||
|
||||
final class TextToHtmlFileTaskMocks {
|
||||
|
||||
static TextToHtmlFileTask blankTextToHtmlFileTask() {
|
||||
new TextToHtmlFileTask(
|
||||
'',
|
||||
blankText(),
|
||||
new HtmlFileOutput(
|
||||
new File(''),
|
||||
'',
|
||||
{ '' }
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
package com.jessebrault.ssg.testutil
|
||||
|
||||
import com.jessebrault.ssg.Diagnostic
|
||||
import com.jessebrault.ssg.Result
|
||||
import com.jessebrault.ssg.text.ExcerptGetter
|
||||
import groovy.transform.stc.ClosureParams
|
||||
import groovy.transform.stc.FirstParam
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue
|
||||
|
||||
class DiagnosticsUtil {
|
||||
|
||||
static Closure<String> getDiagnosticsMessageSupplier(Collection<Diagnostic> diagnostics) {
|
||||
return {
|
||||
diagnostics.collect {
|
||||
def writer = new StringWriter()
|
||||
it.exception.printStackTrace(new PrintWriter(writer))
|
||||
def stackTrace = writer.toString()
|
||||
"$it.message\n$stackTrace"
|
||||
}.join('\n')
|
||||
}
|
||||
}
|
||||
|
||||
static void assertEmptyDiagnostics(Tuple2<Collection<Diagnostic>, ?> result) {
|
||||
assertTrue(result.v1.isEmpty(), getDiagnosticsMessageSupplier(result.v1))
|
||||
}
|
||||
|
||||
static void assertEmptyDiagnostics(Result<?> result) {
|
||||
assertTrue(!result.hasDiagnostics(), getDiagnosticsMessageSupplier(result.diagnostics))
|
||||
}
|
||||
|
||||
static <E extends Exception> void assertDiagnosticException(
|
||||
Class<E> expectedException,
|
||||
Diagnostic diagnostic,
|
||||
@ClosureParams(FirstParam.FirstGenericType)
|
||||
Closure<Void> additionalAssertions = null
|
||||
) {
|
||||
assertInstanceOf(expectedException, diagnostic.exception, {
|
||||
"Incorrect diagnostic exception class; message: ${ diagnostic.message }"
|
||||
})
|
||||
if (additionalAssertions) {
|
||||
additionalAssertions(diagnostic.exception)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user