CommonMarkTemplateContextFactory.java

/**************************************************************************
 *
 * Copyright (c) 2019-2020 Yawg project contributors.
 *
 **************************************************************************/

package com.varmateo.yawg.commonmark;

import java.nio.file.Path;
import java.util.function.Function;

import io.vavr.control.Option;
import io.vavr.control.Try;
import org.commonmark.ext.front.matter.YamlFrontMatterVisitor;
import org.commonmark.node.Node;
import org.commonmark.parser.Parser;
import org.commonmark.renderer.html.HtmlRenderer;

import com.varmateo.yawg.spi.PageContext;
import com.varmateo.yawg.spi.TemplateContext;
import com.varmateo.yawg.spi.TemplateContextBuilder;
import com.varmateo.yawg.util.FileUtils;


/**
 *
 */
/* default */ final class CommonMarkTemplateContextFactory {


    private static final String KEY_TITLE = "title";

    private final Parser _markdownParser;
    private final HtmlRenderer _htmlRenderer;


    /**
     *
     */
    /* default */ CommonMarkTemplateContextFactory(
            final Parser markdownParser,
            final HtmlRenderer htmlRenderer) {

        _markdownParser = markdownParser;
        _htmlRenderer = htmlRenderer;
    }


    /**
     *
     */
    public Try<TemplateContext> build(
            final Path sourcePath,
            final Path targetDir,
            final Path targetPath,
            final PageContext context) {

        return parse(sourcePath)
                .map(buildTemplateContext(sourcePath, targetPath, context));
    }


    private Try<Node> parse(final Path sourcePath) {

        return FileUtils.safeReadFrom(sourcePath, _markdownParser::parseReader)
                .recoverWith(CommonMarkPageBakerException.parseFailureTry(sourcePath));
    }


    private Function<Node, TemplateContext> buildTemplateContext(
            final Path sourcePath,
            final Path targetPath,
            final PageContext context) {

        return (Node document) -> buildTemplateContext(sourcePath, targetPath, context, document);
    }


    private TemplateContext buildTemplateContext(
            final Path sourcePath,
            final Path targetPath,
            final PageContext context,
            final Node document) {

        final String title = documentTitle(sourcePath, document);
        final String body = _htmlRenderer.render(document);
        final String pageUrl = context.dirUrl() + "/" + targetPath.getFileName();

        return TemplateContextBuilder.create()
                .title(title)
                .body(body)
                .pageUrl(pageUrl)
                .rootRelativeUrl(context.rootRelativeUrl())
                .pageVars(context.pageVars())
                .bakeId(context.bakeId())
                .build();
    }


    private String documentTitle(
            final Path sourcePath,
            final Node document) {

        return frontMatterTitle(document)
                .getOrElse(() -> FileUtils.basename(sourcePath));
    }


    private Option<String> frontMatterTitle(final Node document) {

        final YamlFrontMatterVisitor frontMatterVisitor = new YamlFrontMatterVisitor();
        document.accept(frontMatterVisitor);

        return Option.of(frontMatterVisitor.getData().get(KEY_TITLE))
                .filter(xs -> xs.size() > 0)
                .map(xs -> xs.get(0));
    }


}