All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.md2conf.converter.md2wiki.Md2WikiConverter Maven / Gradle / Ivy

The newest version!
package io.github.md2conf.converter.md2wiki;

import com.vladsch.flexmark.ext.gfm.strikethrough.StrikethroughExtension;
import com.vladsch.flexmark.ext.tables.TablesExtension;
import com.vladsch.flexmark.html.HtmlRenderer;
import com.vladsch.flexmark.jira.converter.JiraConverterExtension;
import com.vladsch.flexmark.parser.Parser;
import com.vladsch.flexmark.util.ast.Node;
import com.vladsch.flexmark.util.data.DataHolder;
import com.vladsch.flexmark.util.data.MutableDataSet;
import com.vladsch.flexmark.util.misc.Extension;
import io.github.md2conf.converter.AttachmentUtil;
import io.github.md2conf.converter.PageStructureConverter;
import io.github.md2conf.flexmart.ext.confluence.macros.ConfluenceMacroExtension;
import io.github.md2conf.flexmart.ext.crosspage.links.CrosspageLinkExtension;
import io.github.md2conf.flexmart.ext.curly.braced.escaper.CurlyBracedBlockExtension;
import io.github.md2conf.flexmart.ext.fenced.code.block.CustomFencedCodeBlockExtension;
import io.github.md2conf.flexmart.ext.local.attachments.LocalAttachmentLinkExtension;
import io.github.md2conf.flexmart.ext.local.image.LocalImageExtension;
import io.github.md2conf.flexmart.ext.plantuml.code.macro.PlantUmlCodeMacroExtension;
import io.github.md2conf.indexer.Page;
import io.github.md2conf.indexer.PagesStructure;
import io.github.md2conf.model.ConfluenceContentModel;
import io.github.md2conf.model.ConfluencePage;
import io.github.md2conf.title.processor.PageStructureTitleProcessor;
import io.github.md2conf.title.processor.WikiTitleRemover;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;

import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static com.vladsch.flexmark.html.HtmlRenderer.SUPPRESS_HTML_COMMENT_BLOCKS;
import static com.vladsch.flexmark.html.HtmlRenderer.SUPPRESS_INLINE_HTML_COMMENTS;
import static io.github.md2conf.converter.md2wiki.attachment.LocalPathUtil.collectLocalAttachmentPaths;
import static io.github.md2conf.converter.md2wiki.attachment.LocalPathUtil.collectLocalImagePaths;

public class Md2WikiConverter implements PageStructureConverter {

    private final PageStructureTitleProcessor pagesStructureTitleProcessor;
    private final Path outputPath;
    private final boolean needToRemoveTitle;
    private final boolean plantumlMacro;
    private final String plantumlCodeMacroName;


    public Md2WikiConverter(PageStructureTitleProcessor pagesStructureTitleProcessor,
                            Path outputPath, boolean needToRemoveTitle, boolean plantumlMacro, String plantumlCodeMacroName) {
        this.pagesStructureTitleProcessor = pagesStructureTitleProcessor;
        this.outputPath = outputPath;
        this.needToRemoveTitle = needToRemoveTitle;
        this.plantumlMacro = plantumlMacro;
        this.plantumlCodeMacroName = plantumlCodeMacroName;
    }

    private MutableDataSet flexmarkOptions() {
        List extensions = new ArrayList<>();
        MutableDataSet res =  new MutableDataSet().set(Parser.EXTENSIONS, extensions);
        extensions.add(TablesExtension.create());
        extensions.add(StrikethroughExtension.create());
        extensions.add(LocalAttachmentLinkExtension.create());
        extensions.add(LocalImageExtension.create());
        extensions.add(CrosspageLinkExtension.create());
        extensions.add(CurlyBracedBlockExtension.create());
        extensions.add(ConfluenceMacroExtension.create());
        extensions.add(JiraConverterExtension.create());
        if (plantumlMacro) {
            extensions.add(PlantUmlCodeMacroExtension.create());
            res.set(PlantUmlCodeMacroExtension.CONFLUENCE_PLANTUML_MACRO, plantumlCodeMacroName);
        }
        extensions.add(CustomFencedCodeBlockExtension.create());
        res.set(SUPPRESS_HTML_COMMENT_BLOCKS, true);
        res.set(SUPPRESS_INLINE_HTML_COMMENTS, true);
        return res;
    }

    @Override
    public ConfluenceContentModel convert(PagesStructure pagesStructure) throws IOException {
        Map titleMap = pagesStructureTitleProcessor.toTitleMap(pagesStructure);
        List confluencePages = new ArrayList<>();
        for (Page topLevelPage : pagesStructure.pages()) { //use "for" loop to throw exception to caller
            ConfluencePage confluencePage;
            confluencePage = convertAndCreateConfluencePage(topLevelPage, Paths.get(""), titleMap);
            confluencePages.add(confluencePage);
        }
        return new ConfluenceContentModel(confluencePages);
    }

    /**
     * @param page         - a Page
     * @param relativePart - relative path to target path, used to process children recursively
     * @param titleMap     -  title Map
     * @return ConfluencePage
     */
    private ConfluencePage convertAndCreateConfluencePage(Page page, Path relativePart, Map titleMap) throws IOException {

        //read markdown file from Page path
        String markdown = FileUtils.readFileToString(page.path().toFile(), Charset.defaultCharset()); //todo extract charset as parameter

        //Convert to wiki using FlexMark parser and renderer
        DataHolder flexmarkOptions = flexmarkOptions()
                .set(LocalAttachmentLinkExtension.CURRENT_FILE_PATH, page.path().getParent())
                .set(LocalImageExtension.CURRENT_FILE_PATH, page.path().getParent())
                .set(CrosspageLinkExtension.CURRENT_FILE_PATH, page.path().getParent())
                .set(CrosspageLinkExtension.TITLE_MAP, titleMap)
                .toImmutable();
        Parser parser = Parser.builder(flexmarkOptions).build();
        HtmlRenderer renderer = HtmlRenderer.builder(flexmarkOptions).build();
        Node document = parser.parse(markdown);
        String wiki = renderer.render(document);

        //collect attachments from local images and local file links
        List imagePaths = collectLocalImagePaths(document);
        List localAttachmentPaths = collectLocalAttachmentPaths(document);

        //calculate output file names
        String targetFileName = FilenameUtils.getBaseName(page.path().toString()) + ".wiki";
        Path targetPath = outputPath.resolve(relativePart).resolve(targetFileName);

        //copy converted content and attachments
        FileUtils.writeStringToFile(targetPath.toFile(), wiki, Charset.defaultCharset());
        Set copiedAttachments = AttachmentUtil.copyPageAttachments(targetPath, page.attachments(), imagePaths, localAttachmentPaths);

        // create ConfluencePage model
        ConfluencePage result = new ConfluencePage();
        result.setContentFilePath(targetPath.toString());
        result.setTitle(titleMap.get(page.path().toAbsolutePath()));
        result.setAttachments(AttachmentUtil.toAttachmentsMap(copiedAttachments));
        result.setType(ConfluenceContentModel.Type.WIKI);
        result.setAttachments(AttachmentUtil.toAttachmentsMap(copiedAttachments));
        result.setSkipUpdate(page.skipUpdate());
        // process children
        if (page.children() != null && !page.children().isEmpty()) {
            String childrenDirAsStr = FilenameUtils.concat(
                    relativePart.toString(),
                    FilenameUtils.removeExtension(targetPath.getFileName().toString()));
            Path childrenDir = outputPath.resolve(childrenDirAsStr);
            FileUtils.forceMkdir(childrenDir.toFile());
            for (Page childPage : page.children()) {
                result.getChildren().add(convertAndCreateConfluencePage(childPage, outputPath.relativize(childrenDir), titleMap));
            }
        }
        if (needToRemoveTitle) {
            WikiTitleRemover.removeTitle(targetPath);
        }
        return result;
    }

    @Override
    public String toString() {
        return "Md2WikiConverter";
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy