Initial site generation
This commit is contained in:
parent
f44c79dc1f
commit
fc44290e3f
35 changed files with 667 additions and 303 deletions
|
@ -1,8 +1,11 @@
|
|||
#include "ContentFile.h"
|
||||
|
||||
#include "PathUtils.h"
|
||||
#include "StringUtils.h"
|
||||
|
||||
#include "MarkdownDocument.h"
|
||||
#include "MarkdownElement.h"
|
||||
#include "MarkdownComponents.h"
|
||||
|
||||
ContentFile::ContentFile(const Path& filename)
|
||||
: mFilename(filename)
|
||||
|
@ -35,6 +38,23 @@ void ContentFile::load()
|
|||
mContentBody = std::move(result.second);
|
||||
}
|
||||
|
||||
void ContentFile::doLinkTagSubstitution(const Path& basePath)
|
||||
{
|
||||
auto links = mContentBody->getAllLinks();
|
||||
for (const auto link : links)
|
||||
{
|
||||
auto target = link->getTarget();
|
||||
auto replaced_target = StringUtils::removeUpTo(target, "{filename}");
|
||||
if (replaced_target != target)
|
||||
{
|
||||
auto full_path = mFilename.parent_path() / Path(replaced_target);
|
||||
auto base_relative_path = PathUtils::getRelativePath(full_path, basePath);
|
||||
auto output_path = PathUtils::getPathDelimited(base_relative_path);
|
||||
link->setTarget(Path(output_path).replace_extension(".html"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string ContentFile::getMetadataItem(const std::string& key) const
|
||||
{
|
||||
const auto check = mMetadata.find(key);
|
||||
|
@ -50,5 +70,6 @@ std::string ContentFile::getMetadataItem(const std::string& key) const
|
|||
|
||||
void ContentFile::write(const Path& path)
|
||||
{
|
||||
|
||||
File file(path);
|
||||
file.writeText(mProcessedOutput);
|
||||
}
|
||||
|
|
|
@ -32,7 +32,14 @@ public:
|
|||
return mContentBody.get();
|
||||
}
|
||||
|
||||
void doLinkTagSubstitution(const Path& basePath);
|
||||
|
||||
void write(const Path& path);
|
||||
|
||||
void setProcessedOutput(const std::string& output)
|
||||
{
|
||||
mProcessedOutput = output;
|
||||
}
|
||||
protected:
|
||||
Path mFilename;
|
||||
FileMetadata mMetadata;
|
||||
|
|
|
@ -6,9 +6,14 @@
|
|||
#include "ContentPage.h"
|
||||
#include "TemplateFile.h"
|
||||
#include "TemplatingEngine.h"
|
||||
#include "TemplateSubstitutionContext.h"
|
||||
#include "SiteGeneratorConfig.h"
|
||||
#include "PathUtils.h"
|
||||
|
||||
#include "MarkdownConverter.h"
|
||||
#include "HtmlElement.h"
|
||||
#include "HtmlWriter.h"
|
||||
|
||||
#include "FileLogger.h"
|
||||
|
||||
WebsiteGenerator::WebsiteGenerator()
|
||||
|
@ -104,18 +109,35 @@ void WebsiteGenerator::parseTemplateFiles()
|
|||
{
|
||||
const auto template_path = mProjectPath / mConfig->getThemePath() / mConfig->getActiveTheme();
|
||||
mTemplateEngine = std::make_unique<TemplatingEngine>(template_path);
|
||||
mTemplateEngine->loadTemplateFiles();
|
||||
}
|
||||
|
||||
void WebsiteGenerator::doSubstitutions()
|
||||
{
|
||||
auto article_template = mTemplateEngine->processTemplate("article");
|
||||
MarkdownConverter converter;
|
||||
|
||||
for (auto& article : mArticles)
|
||||
{
|
||||
article->doLinkTagSubstitution(getArticlesPath());
|
||||
|
||||
auto containing_div = std::make_unique<HtmlDivElement>();
|
||||
converter.convert(article->getContentBody(), containing_div.get());
|
||||
|
||||
HtmlWriter writer;
|
||||
auto md_html_content = writer.toString(containing_div.get());
|
||||
|
||||
TemplateSubstitutionContext sub_context;
|
||||
sub_context.addSubstitution("content", md_html_content);
|
||||
|
||||
auto content = mTemplateEngine->renderTemplate("article", &sub_context);
|
||||
article->setProcessedOutput(content);
|
||||
}
|
||||
}
|
||||
|
||||
Path WebsiteGenerator::getOutputPath() const
|
||||
{
|
||||
return mProjectPath / "output";
|
||||
}
|
||||
|
||||
void WebsiteGenerator::write()
|
||||
{
|
||||
// Setup output dir
|
||||
|
@ -129,6 +151,7 @@ void WebsiteGenerator::write()
|
|||
auto relative_path = PathUtils::getRelativePath(article_path, getArticlesPath());
|
||||
auto updated_filename = PathUtils::getPathDelimited(relative_path);
|
||||
auto final_path = output_dir / Path(updated_filename).replace_extension(".html");
|
||||
article->write(final_path);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,8 @@ private:
|
|||
|
||||
Path getConfigPath() const;
|
||||
|
||||
Path getOutputPath() const;
|
||||
|
||||
std::filesystem::path mProjectPath;
|
||||
|
||||
std::unique_ptr<SiteGeneratorConfig> mConfig;
|
||||
|
|
|
@ -2,22 +2,25 @@ set(MODULE_NAME compiler)
|
|||
|
||||
list(APPEND TARGET_HEADERS
|
||||
Lexer.h
|
||||
TemplatingEngine.h
|
||||
TemplateFile.h
|
||||
TemplateNodes.h
|
||||
template_engine/TemplatingEngine.h
|
||||
template_engine/TemplateFile.h
|
||||
template_engine/TemplateNode.h
|
||||
template_engine/TemplateElements.h
|
||||
)
|
||||
|
||||
list(APPEND TARGET_SOURCES
|
||||
Lexer.cpp
|
||||
TemplatingEngine.cpp
|
||||
TemplateFile.cpp
|
||||
TemplateNodes.cpp
|
||||
template_engine/TemplatingEngine.cpp
|
||||
template_engine/TemplateFile.cpp
|
||||
template_engine/TemplateNode.cpp
|
||||
template_engine/TemplateElements.cpp
|
||||
)
|
||||
|
||||
add_library(${MODULE_NAME} SHARED ${TARGET_SOURCES} ${TARGET_HEADERS})
|
||||
|
||||
target_include_directories(${MODULE_NAME} PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/template_engine
|
||||
)
|
||||
target_link_libraries( ${MODULE_NAME} PUBLIC core)
|
||||
|
||||
|
|
|
@ -1,124 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class TemplateNode
|
||||
{
|
||||
public:
|
||||
TemplateNode(TemplateNode* parent);
|
||||
|
||||
virtual ~TemplateNode() = default;
|
||||
|
||||
TemplateNode* getParent() const;
|
||||
|
||||
virtual void addChild(std::unique_ptr<TemplateNode> child);
|
||||
|
||||
std::size_t getNumChildren() const;
|
||||
|
||||
virtual std::string getIdentifier() const;
|
||||
|
||||
TemplateNode* getChild(std::size_t index) const;
|
||||
|
||||
virtual std::string getRawContent() const;
|
||||
|
||||
template<typename T>
|
||||
T* getFirstChildShallow(const std::string& identifier = {}) const
|
||||
{
|
||||
for (const auto& child : mChildren)
|
||||
{
|
||||
if (auto ret = dynamic_cast<T*>(child.get()))
|
||||
{
|
||||
if (!identifier.empty())
|
||||
{
|
||||
if (child->getIdentifier() == identifier)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void setExtensionParent(TemplateNode* parent);
|
||||
|
||||
virtual std::string render(TemplateNode* parentContext = nullptr);
|
||||
|
||||
protected:
|
||||
std::vector<std::unique_ptr<TemplateNode> > mChildren;
|
||||
TemplateNode* mParent{ nullptr };
|
||||
TemplateNode* mExtensionParent{ nullptr };
|
||||
};
|
||||
|
||||
using TemplateNodePtr = std::unique_ptr<TemplateNode>;
|
||||
|
||||
class TemplateExtends : public TemplateNode
|
||||
{
|
||||
public:
|
||||
TemplateExtends(TemplateNode* parent, const std::string& path);
|
||||
|
||||
virtual ~TemplateExtends() = default;
|
||||
|
||||
std::string getRawContent() const override;
|
||||
std::string getPath() const;
|
||||
|
||||
private:
|
||||
std::string mPath;
|
||||
};
|
||||
|
||||
class TemplateBlock : public TemplateNode
|
||||
{
|
||||
public:
|
||||
TemplateBlock(TemplateNode* parent, const std::string& name);
|
||||
|
||||
virtual ~TemplateBlock() = default;
|
||||
|
||||
void addLine(const std::string& line);
|
||||
|
||||
std::string getRawContent() const override;
|
||||
|
||||
std::string renderAsParent(TemplateNode* base);
|
||||
|
||||
std::string render(TemplateNode* parentContext) override;
|
||||
|
||||
private:
|
||||
std::string mName;
|
||||
std::vector<std::string> mBody;
|
||||
};
|
||||
|
||||
class TemplateExpression : public TemplateNode
|
||||
{
|
||||
public:
|
||||
TemplateExpression(TemplateNode* parent, const std::string& content);
|
||||
|
||||
virtual ~TemplateExpression() = default;
|
||||
|
||||
std::string getRawContent() const override;
|
||||
|
||||
private:
|
||||
std::string mContent;
|
||||
};
|
||||
|
||||
class TemplateTextBody : public TemplateNode
|
||||
{
|
||||
public:
|
||||
TemplateTextBody(TemplateNode* parent);
|
||||
|
||||
virtual ~TemplateTextBody() = default;
|
||||
|
||||
void addLine(const std::string& content);
|
||||
|
||||
std::string getRawContent() const override;
|
||||
|
||||
bool hasContent() const;
|
||||
|
||||
std::string render(TemplateNode* parentContext) override;
|
||||
private:
|
||||
std::vector<std::string> mContent;
|
||||
};
|
|
@ -1,67 +1,9 @@
|
|||
#include "TemplateNodes.h"
|
||||
#include "TemplateElements.h"
|
||||
|
||||
#include "StringUtils.h"
|
||||
#include "TemplateSubstitutionContext.h"
|
||||
|
||||
TemplateNode::TemplateNode(TemplateNode* parent)
|
||||
: mParent(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
TemplateNode* TemplateNode::getParent() const
|
||||
{
|
||||
return mParent;
|
||||
}
|
||||
|
||||
void TemplateNode::addChild(std::unique_ptr<TemplateNode> child)
|
||||
{
|
||||
mChildren.push_back(std::move(child));
|
||||
}
|
||||
|
||||
std::size_t TemplateNode::getNumChildren() const
|
||||
{
|
||||
return mChildren.size();
|
||||
}
|
||||
|
||||
std::string TemplateNode::getIdentifier() const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
TemplateNode* TemplateNode::getChild(std::size_t index) const
|
||||
{
|
||||
return mChildren[index].get();
|
||||
}
|
||||
|
||||
std::string TemplateNode::getRawContent() const
|
||||
{
|
||||
std::string content;
|
||||
for (const auto& child : mChildren)
|
||||
{
|
||||
content += child->getRawContent() + "\n";
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
void TemplateNode::setExtensionParent(TemplateNode* parent)
|
||||
{
|
||||
mExtensionParent = parent;
|
||||
}
|
||||
|
||||
std::string TemplateNode::render(TemplateNode* parentContext)
|
||||
{
|
||||
if (!parentContext && mExtensionParent)
|
||||
{
|
||||
parentContext = mExtensionParent;
|
||||
}
|
||||
|
||||
std::string content;
|
||||
for (size_t idx = 0; idx < mChildren.size(); idx++)
|
||||
{
|
||||
content += mChildren[idx]->render(parentContext);
|
||||
}
|
||||
return content;
|
||||
}
|
||||
#include <iostream>
|
||||
|
||||
TemplateExtends::TemplateExtends(TemplateNode* parent, const std::string& path)
|
||||
: TemplateNode(parent)
|
||||
|
@ -98,24 +40,64 @@ std::string TemplateBlock::getRawContent() const
|
|||
return content;
|
||||
}
|
||||
|
||||
std::string TemplateBlock::renderAsParent(TemplateNode* base)
|
||||
std::string TemplateBlock::getIdentifier() const
|
||||
{
|
||||
return {};
|
||||
return mName;
|
||||
}
|
||||
|
||||
std::string TemplateBlock::render(TemplateNode* parentContext)
|
||||
std::string TemplateBlock::renderAsParent(TemplateSubstitutionContext* substitutions, TemplateBlock* base)
|
||||
{
|
||||
std::string content;
|
||||
for (auto& child : mChildren)
|
||||
{
|
||||
if (child->getType() == Type::EXPRESSION)
|
||||
{
|
||||
auto expression = dynamic_cast<TemplateExpression*>(child.get());
|
||||
std::cout << "Got expression with content " << expression->getContent() << std::endl;
|
||||
if (expression->getContent() == "super()")
|
||||
{
|
||||
std::cout << "Adding expression base" << std::endl;
|
||||
content += base->render(substitutions, nullptr);
|
||||
}
|
||||
}
|
||||
else if(child->getType() == Type::TEXT_BODY)
|
||||
{
|
||||
content += child->render(substitutions, nullptr);
|
||||
}
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
std::string TemplateBlock::renderAsLeaf(TemplateSubstitutionContext* substitutions)
|
||||
{
|
||||
std::string content;
|
||||
for (auto& child : mChildren)
|
||||
{
|
||||
if(child->getType() == Type::TEXT_BODY)
|
||||
{
|
||||
content += child->render(substitutions, nullptr);
|
||||
}
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
std::string TemplateBlock::render(TemplateSubstitutionContext* substitutions, TemplateNode* parentContext)
|
||||
{
|
||||
std::string content;
|
||||
if (parentContext)
|
||||
{
|
||||
if (auto parent_node = parentContext->getFirstChildShallow<TemplateBlock>(getIdentifier()))
|
||||
if (auto parent_node = parentContext->getFirstChildShallow(Type::BLOCK, getIdentifier()))
|
||||
{
|
||||
content = dynamic_cast<TemplateBlock*>(parent_node)->renderAsParent(this);
|
||||
content = dynamic_cast<TemplateBlock*>(parent_node)->renderAsParent(substitutions, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
content= renderAsLeaf(substitutions);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
content= renderAsLeaf(substitutions);
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
@ -127,6 +109,20 @@ TemplateExpression::TemplateExpression(TemplateNode* parent, const std::string&
|
|||
|
||||
}
|
||||
|
||||
const std::string& TemplateExpression::getContent() const
|
||||
{
|
||||
return mContent;
|
||||
}
|
||||
|
||||
std::string TemplateExpression::render(TemplateSubstitutionContext* substitutions, TemplateNode* parentContext)
|
||||
{
|
||||
if (substitutions->hasSubstitution(mContent))
|
||||
{
|
||||
return substitutions->getSubstitution(mContent);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string TemplateExpression::getRawContent() const
|
||||
{
|
||||
return "TemplateExpression: " + mContent;
|
||||
|
@ -148,7 +144,7 @@ bool TemplateTextBody::hasContent() const
|
|||
return !mContent.empty();
|
||||
}
|
||||
|
||||
std::string TemplateTextBody::render(TemplateNode* parentContext)
|
||||
std::string TemplateTextBody::render(TemplateSubstitutionContext* substitutions, TemplateNode* parentContext)
|
||||
{
|
||||
std::string content;
|
||||
for (const auto& line : mContent)
|
96
src/compiler/template_engine/TemplateElements.h
Normal file
96
src/compiler/template_engine/TemplateElements.h
Normal file
|
@ -0,0 +1,96 @@
|
|||
#pragma once
|
||||
|
||||
#include "TemplateNode.h"
|
||||
|
||||
class TemplateExtends : public TemplateNode
|
||||
{
|
||||
public:
|
||||
TemplateExtends(TemplateNode* parent, const std::string& path);
|
||||
|
||||
virtual ~TemplateExtends() = default;
|
||||
|
||||
std::string getRawContent() const override;
|
||||
std::string getPath() const;
|
||||
|
||||
Type getType() const override
|
||||
{
|
||||
return Type::EXTENDS;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string mPath;
|
||||
};
|
||||
|
||||
class TemplateBlock : public TemplateNode
|
||||
{
|
||||
public:
|
||||
TemplateBlock(TemplateNode* parent, const std::string& name);
|
||||
|
||||
virtual ~TemplateBlock() = default;
|
||||
|
||||
void addLine(const std::string& line);
|
||||
|
||||
std::string getRawContent() const override;
|
||||
|
||||
std::string getIdentifier() const override;
|
||||
|
||||
Type getType() const override
|
||||
{
|
||||
return Type::BLOCK;
|
||||
}
|
||||
|
||||
std::string renderAsParent(TemplateSubstitutionContext* substitutions, TemplateBlock* base);
|
||||
|
||||
std::string renderAsLeaf(TemplateSubstitutionContext* substitutions);
|
||||
|
||||
std::string render(TemplateSubstitutionContext* substitutions, TemplateNode* parentContext) override;
|
||||
|
||||
private:
|
||||
std::string mName;
|
||||
std::vector<std::string> mBody;
|
||||
};
|
||||
|
||||
class TemplateExpression : public TemplateNode
|
||||
{
|
||||
public:
|
||||
TemplateExpression(TemplateNode* parent, const std::string& content);
|
||||
|
||||
virtual ~TemplateExpression() = default;
|
||||
|
||||
std::string getRawContent() const override;
|
||||
|
||||
const std::string& getContent() const;
|
||||
|
||||
Type getType() const override
|
||||
{
|
||||
return Type::EXPRESSION;
|
||||
}
|
||||
|
||||
std::string render(TemplateSubstitutionContext* substitutions, TemplateNode* parentContext) override;
|
||||
|
||||
private:
|
||||
std::string mContent;
|
||||
};
|
||||
|
||||
class TemplateTextBody : public TemplateNode
|
||||
{
|
||||
public:
|
||||
TemplateTextBody(TemplateNode* parent);
|
||||
|
||||
virtual ~TemplateTextBody() = default;
|
||||
|
||||
void addLine(const std::string& content);
|
||||
|
||||
std::string getRawContent() const override;
|
||||
|
||||
bool hasContent() const;
|
||||
|
||||
std::string render(TemplateSubstitutionContext* substitutions, TemplateNode* parentContext) override;
|
||||
|
||||
Type getType() const override
|
||||
{
|
||||
return Type::TEXT_BODY;
|
||||
}
|
||||
private:
|
||||
std::vector<std::string> mContent;
|
||||
};
|
|
@ -1,6 +1,7 @@
|
|||
#include "TemplateFile.h"
|
||||
|
||||
#include "StringUtils.h"
|
||||
#include "TemplateElements.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
@ -11,9 +12,9 @@ TemplateFile::TemplateFile(const Path& path)
|
|||
|
||||
}
|
||||
|
||||
std::vector<std::string> TemplateFile::getProcessedContent() const
|
||||
TemplateFile::~TemplateFile()
|
||||
{
|
||||
return mProcessedContent;
|
||||
|
||||
}
|
||||
|
||||
std::string TemplateFile::getName() const
|
||||
|
@ -21,9 +22,23 @@ std::string TemplateFile::getName() const
|
|||
return mPath.stem().string();
|
||||
}
|
||||
|
||||
bool TemplateFile::hasLoaded() const
|
||||
{
|
||||
return mHasLoaded;
|
||||
}
|
||||
|
||||
TemplateNode* TemplateFile::getContent() const
|
||||
{
|
||||
return mRootNode.get();
|
||||
}
|
||||
|
||||
void TemplateFile::loadContent()
|
||||
{
|
||||
//std::cout << "Trying to load file at: " << mPath << std::endl;
|
||||
if (mHasLoaded)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
mRawContent = File(mPath).readLines();
|
||||
mWorkingLine = 0;
|
||||
mWorkingNode = mRootNode.get();
|
||||
|
@ -34,6 +49,8 @@ void TemplateFile::loadContent()
|
|||
mWorkingLine++;
|
||||
}
|
||||
onTextBodyFinished();
|
||||
|
||||
mHasLoaded = true;
|
||||
}
|
||||
|
||||
void TemplateFile::onTextBodyFinished(std::string working_string)
|
||||
|
@ -178,12 +195,12 @@ void TemplateFile::onFoundExtends(const std::vector<std::string> args)
|
|||
|
||||
void TemplateFile::onFoundExpression(const std::string& expression_string)
|
||||
{
|
||||
auto expression = std::make_unique<TemplateExpression>(mWorkingNode, expression_string);
|
||||
auto stripped = StringUtils::strip(expression_string);
|
||||
auto expression = std::make_unique<TemplateExpression>(mWorkingNode, stripped);
|
||||
mWorkingNode->addChild(std::move(expression));
|
||||
}
|
||||
|
||||
void TemplateFile::dumpContent()
|
||||
std::string TemplateFile::dumpContent()
|
||||
{
|
||||
auto content = mRootNode->getRawContent();
|
||||
//std::cout << content << std::endl;
|
||||
return mRootNode->getRawContent();
|
||||
}
|
|
@ -2,21 +2,31 @@
|
|||
|
||||
#include "File.h"
|
||||
|
||||
#include "TemplateNodes.h"
|
||||
#include "TemplateNode.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class TemplateNode;
|
||||
class TemplateTextBody;
|
||||
|
||||
class TemplateFile
|
||||
{
|
||||
public:
|
||||
TemplateFile(const Path& path);
|
||||
|
||||
std::vector<std::string> getProcessedContent() const;
|
||||
~TemplateFile();
|
||||
|
||||
std::string dumpContent();
|
||||
|
||||
std::string getName() const;
|
||||
|
||||
TemplateNode* getContent() const;
|
||||
|
||||
bool hasLoaded() const;
|
||||
|
||||
void loadContent();
|
||||
|
||||
private:
|
||||
void onTextBodyFinished(std::string working_string = {});
|
||||
|
||||
void processLine(const std::string& line);
|
||||
|
@ -31,19 +41,12 @@ public:
|
|||
|
||||
void onFoundExpression(const std::string& expression_string);
|
||||
|
||||
void dumpContent();
|
||||
|
||||
TemplateNode* getContent() const
|
||||
{
|
||||
return mRootNode.get();
|
||||
}
|
||||
|
||||
private:
|
||||
Path mPath;
|
||||
unsigned mWorkingLine{ 0 };
|
||||
std::string mParentName;
|
||||
std::vector<std::string> mRawContent;
|
||||
std::vector<std::string> mProcessedContent;
|
||||
bool mHasLoaded{false};
|
||||
|
||||
unsigned mWorkingLine{ 0 };
|
||||
std::unique_ptr<TemplateNode> mRootNode;
|
||||
TemplateNode* mWorkingNode{ nullptr };
|
||||
std::unique_ptr<TemplateTextBody> mWorkingTextBody;
|
91
src/compiler/template_engine/TemplateNode.cpp
Normal file
91
src/compiler/template_engine/TemplateNode.cpp
Normal file
|
@ -0,0 +1,91 @@
|
|||
#include "TemplateNode.h"
|
||||
|
||||
#include "TemplateSubstitutionContext.h"
|
||||
|
||||
TemplateNode::TemplateNode(TemplateNode* parent)
|
||||
: mParent(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
TemplateNode* TemplateNode::getParent() const
|
||||
{
|
||||
return mParent;
|
||||
}
|
||||
|
||||
void TemplateNode::addChild(std::unique_ptr<TemplateNode> child)
|
||||
{
|
||||
mChildren.push_back(std::move(child));
|
||||
}
|
||||
|
||||
std::size_t TemplateNode::getNumChildren() const
|
||||
{
|
||||
return mChildren.size();
|
||||
}
|
||||
|
||||
TemplateNode* TemplateNode::getFirstChildShallow(Type type, const std::string& identifier) const
|
||||
{
|
||||
for (const auto& child : mChildren)
|
||||
{
|
||||
if (child->getType() == type)
|
||||
{
|
||||
if (!identifier.empty())
|
||||
{
|
||||
if (child->getIdentifier() == identifier)
|
||||
{
|
||||
return child.get();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return child.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TemplateNode::Type TemplateNode::getType() const
|
||||
{
|
||||
return Type::NONE;
|
||||
}
|
||||
|
||||
std::string TemplateNode::getIdentifier() const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
TemplateNode* TemplateNode::getChild(std::size_t index) const
|
||||
{
|
||||
return mChildren[index].get();
|
||||
}
|
||||
|
||||
std::string TemplateNode::getRawContent() const
|
||||
{
|
||||
std::string content;
|
||||
for (const auto& child : mChildren)
|
||||
{
|
||||
content += child->getRawContent() + "\n";
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
void TemplateNode::setExtensionParent(TemplateNode* parent)
|
||||
{
|
||||
mExtensionParent = parent;
|
||||
}
|
||||
|
||||
std::string TemplateNode::render(TemplateSubstitutionContext* substitutions, TemplateNode* parentContext)
|
||||
{
|
||||
if (!parentContext && mExtensionParent)
|
||||
{
|
||||
parentContext = mExtensionParent;
|
||||
}
|
||||
|
||||
std::string content;
|
||||
for (size_t idx = 0; idx < mChildren.size(); idx++)
|
||||
{
|
||||
content += mChildren[idx]->render(substitutions, parentContext);
|
||||
}
|
||||
return content;
|
||||
}
|
51
src/compiler/template_engine/TemplateNode.h
Normal file
51
src/compiler/template_engine/TemplateNode.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class TemplateSubstitutionContext;
|
||||
|
||||
class TemplateNode
|
||||
{
|
||||
public:
|
||||
enum class Type
|
||||
{
|
||||
NONE,
|
||||
BLOCK,
|
||||
EXPRESSION,
|
||||
EXTENDS,
|
||||
TEXT_BODY
|
||||
};
|
||||
|
||||
TemplateNode(TemplateNode* parent);
|
||||
|
||||
virtual ~TemplateNode() = default;
|
||||
|
||||
virtual void addChild(std::unique_ptr<TemplateNode> child);
|
||||
|
||||
TemplateNode* getChild(std::size_t index) const;
|
||||
|
||||
TemplateNode* getFirstChildShallow(Type type, const std::string& identifier = {}) const;
|
||||
|
||||
virtual std::string getIdentifier() const;
|
||||
|
||||
std::size_t getNumChildren() const;
|
||||
|
||||
TemplateNode* getParent() const;
|
||||
|
||||
virtual std::string getRawContent() const;
|
||||
|
||||
virtual Type getType() const;
|
||||
|
||||
virtual std::string render(TemplateSubstitutionContext* substitutions, TemplateNode* parentContext = nullptr);
|
||||
|
||||
void setExtensionParent(TemplateNode* parent);
|
||||
|
||||
protected:
|
||||
std::vector<std::unique_ptr<TemplateNode> > mChildren;
|
||||
TemplateNode* mParent{ nullptr };
|
||||
TemplateNode* mExtensionParent{ nullptr };
|
||||
};
|
||||
|
||||
using TemplateNodePtr = std::unique_ptr<TemplateNode>;
|
35
src/compiler/template_engine/TemplateSubstitutionContext.h
Normal file
35
src/compiler/template_engine/TemplateSubstitutionContext.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
class TemplateSubstitutionContext
|
||||
{
|
||||
public:
|
||||
|
||||
void addSubstitution(const std::string& key, const std::string& value)
|
||||
{
|
||||
mSubstitutions[key] = value;
|
||||
}
|
||||
|
||||
bool hasSubstitution(const std::string& key) const
|
||||
{
|
||||
return mSubstitutions.find(key) != mSubstitutions.end();
|
||||
}
|
||||
|
||||
std::string getSubstitution(const std::string& key) const
|
||||
{
|
||||
auto iter = mSubstitutions.find(key);
|
||||
if(iter != mSubstitutions.end())
|
||||
{
|
||||
return iter->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, std::string> mSubstitutions;
|
||||
};
|
|
@ -3,6 +3,9 @@
|
|||
#include "Directory.h"
|
||||
#include "FileLogger.h"
|
||||
|
||||
#include "TemplateElements.h"
|
||||
#include "TemplateSubstitutionContext.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
TemplatingEngine::TemplatingEngine(const Path& workingDirectory)
|
||||
|
@ -11,6 +14,32 @@ TemplatingEngine::TemplatingEngine(const Path& workingDirectory)
|
|||
|
||||
}
|
||||
|
||||
std::string TemplatingEngine::renderTemplate(const std::string& name, TemplateSubstitutionContext* substitutionContext)
|
||||
{
|
||||
if (mTemplateFiles.empty())
|
||||
{
|
||||
loadTemplateFiles();
|
||||
}
|
||||
|
||||
if (auto file = getTemplateFile(name))
|
||||
{
|
||||
if (!file->hasLoaded())
|
||||
{
|
||||
file->loadContent();
|
||||
std::cout << file->dumpContent();
|
||||
|
||||
processTemplate(file, nullptr);
|
||||
}
|
||||
|
||||
return file->getContent()->render(substitutionContext, nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void TemplatingEngine::loadTemplateFiles()
|
||||
{
|
||||
const auto files = Directory::getFilesWithExtension(mWorkingDirectory, mTemplateExtension);
|
||||
|
@ -21,15 +50,6 @@ void TemplatingEngine::loadTemplateFiles()
|
|||
MLOG_INFO("Found: " << mTemplateFiles.size() << " templates in " << mWorkingDirectory);
|
||||
}
|
||||
|
||||
std::string TemplatingEngine::processTemplate(const std::string& name)
|
||||
{
|
||||
if (auto file = getTemplateFile(name))
|
||||
{
|
||||
return processTemplate(file);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
TemplateFile* TemplatingEngine::getTemplateFile(const Path& path)
|
||||
{
|
||||
return getTemplateFile(path.stem().string());
|
||||
|
@ -40,37 +60,24 @@ TemplateFile* TemplatingEngine::getTemplateFile(const std::string& name)
|
|||
return mTemplateFiles[name].get();
|
||||
}
|
||||
|
||||
std::string TemplatingEngine::processTemplate(TemplateFile* file, TemplateNode* parent)
|
||||
void TemplatingEngine::processTemplate(TemplateFile* file, TemplateNode* parent)
|
||||
{
|
||||
file->loadContent();
|
||||
file->dumpContent();
|
||||
std::cout << "Processing file " << file->getName() << std::endl;
|
||||
|
||||
auto content = file->getContent();
|
||||
if (parent)
|
||||
{
|
||||
std::cout << "Setting extension parent" << std::endl;
|
||||
content->setExtensionParent(parent);
|
||||
}
|
||||
|
||||
if (auto extension_node = content->getFirstChildShallow<TemplateExtends>())
|
||||
if (auto extension_node = dynamic_cast<TemplateExtends*>(content->getFirstChildShallow(TemplateNode::Type::EXTENDS)))
|
||||
{
|
||||
//std::cout << "Found extension node" << std::endl;
|
||||
std::cout << "Found extension node " << std::endl;
|
||||
if (auto extension_template = getTemplateFile(Path(extension_node->getPath())))
|
||||
{
|
||||
//std::cout << "Found extension template" << std::endl;
|
||||
return processTemplate(extension_template, parent);
|
||||
}
|
||||
else
|
||||
{
|
||||
return render(content);
|
||||
std::cout << "Found extension template " << std::endl;
|
||||
processTemplate(extension_template, content);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return render(content);
|
||||
}
|
||||
}
|
||||
|
||||
std::string TemplatingEngine::render(TemplateNode* content)
|
||||
{
|
||||
return content->render();
|
||||
}
|
|
@ -8,20 +8,21 @@
|
|||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
class TemplateSubstitutionContext;
|
||||
|
||||
class TemplatingEngine
|
||||
{
|
||||
public:
|
||||
TemplatingEngine(const Path& workingDirectory);
|
||||
|
||||
void loadTemplateFiles();
|
||||
std::string renderTemplate(const std::string& name, TemplateSubstitutionContext* substitutionContext);
|
||||
|
||||
std::string processTemplate(const std::string& name);
|
||||
private:
|
||||
TemplateFile* getTemplateFile(const std::string& name);
|
||||
TemplateFile* getTemplateFile(const Path& path);
|
||||
std::string render(TemplateNode* content);
|
||||
|
||||
std::string processTemplate(TemplateFile* file, TemplateNode* parent = nullptr);
|
||||
void loadTemplateFiles();
|
||||
void processTemplate(TemplateFile* file, TemplateNode* parent = nullptr);
|
||||
|
||||
std::unordered_map<std::string, std::unique_ptr<TemplateFile> > mTemplateFiles;
|
||||
Path mWorkingDirectory;
|
|
@ -53,13 +53,11 @@ std::string StringUtils::strip(const std::string& input)
|
|||
return {};
|
||||
}
|
||||
|
||||
std::locale loc;
|
||||
std::string working_string;
|
||||
std::size_t first_nonspace = 0;
|
||||
std::size_t last_nonspace = working_string.size() - 1;
|
||||
for (std::size_t idx = 0; idx < working_string.size(); idx++)
|
||||
std::size_t last_nonspace = input.size() - 1;
|
||||
for (std::size_t idx = 0; idx < input.size(); idx++)
|
||||
{
|
||||
if (!std::isspace(working_string[idx], loc))
|
||||
if (!std::isspace(input[idx]))
|
||||
{
|
||||
first_nonspace = idx;
|
||||
break;
|
||||
|
@ -73,13 +71,13 @@ std::string StringUtils::strip(const std::string& input)
|
|||
|
||||
for (std::size_t idx = last_nonspace; idx > 0; idx--)
|
||||
{
|
||||
if (!std::isspace(working_string[idx], loc))
|
||||
if (!std::isspace(input[idx]))
|
||||
{
|
||||
last_nonspace = idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return working_string.substr(first_nonspace, last_nonspace-first_nonspace);
|
||||
return input.substr(first_nonspace, last_nonspace-first_nonspace + 1);
|
||||
}
|
||||
|
||||
std::vector<std::string> StringUtils::split(const std::string& input)
|
||||
|
@ -166,3 +164,21 @@ std::string StringUtils::stripQuotes(const std::string& input)
|
|||
}
|
||||
return input.substr(start_index, end_index - start_index + 1);
|
||||
}
|
||||
|
||||
std::string StringUtils::replaceWith(const std::string& inputString, const std::string& searchString, const std::string& replaceString)
|
||||
{
|
||||
return inputString;
|
||||
}
|
||||
|
||||
std::string StringUtils::removeUpTo(const std::string& input, const std::string& prefix)
|
||||
{
|
||||
std::size_t found = input.find(prefix);
|
||||
if (found!=std::string::npos)
|
||||
{
|
||||
return input.substr(found, prefix.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
return input;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,8 @@ public:
|
|||
static std::vector<std::string> split(const std::string& input);
|
||||
static std::string strip(const std::string& input);
|
||||
|
||||
static std::string removeUpTo(const std::string& input, const std::string& prefix);
|
||||
|
||||
static std::vector<std::string> toLines(const std::string& input);
|
||||
|
||||
static std::string stripQuotes(const std::string& input);
|
||||
|
@ -34,4 +36,6 @@ public:
|
|||
static std::vector<unsigned char> toBytes(const std::string& input);
|
||||
static std::string toString(const std::vector<unsigned char>& bytes);
|
||||
|
||||
static std::string replaceWith(const std::string& inputString, const std::string& searchString, const std::string& replaceString);
|
||||
|
||||
};
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "MarkdownParser.h"
|
||||
#include "MarkdownDocument.h"
|
||||
#include "MarkdownConverter.h"
|
||||
#include "MarkdownElement.h"
|
||||
|
||||
#include "HtmlDocument.h"
|
||||
#include "HtmlWriter.h"
|
||||
|
|
|
@ -31,3 +31,8 @@ void HtmlDocument::addElementToBody(std::unique_ptr<HtmlElement> element)
|
|||
body_element->addChild(std::move(element));
|
||||
}
|
||||
}
|
||||
|
||||
HtmlBodyElement* HtmlDocument::getBodyElement() const
|
||||
{
|
||||
return dynamic_cast<HtmlBodyElement*>(getRoot()->getFirstChildWithTagName("body"));
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <memory>
|
||||
|
||||
class HtmlElement;
|
||||
class HtmlBodyElement;
|
||||
|
||||
class HtmlDocument : public XmlDocument
|
||||
{
|
||||
|
@ -17,6 +18,8 @@ public:
|
|||
|
||||
void addElementToBody(std::unique_ptr<HtmlElement> element);
|
||||
|
||||
HtmlBodyElement* getBodyElement() const;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
|
|
|
@ -19,7 +19,8 @@ public:
|
|||
HYPERLINK,
|
||||
IMAGE,
|
||||
UNORDERED_LIST,
|
||||
LIST_ITEM
|
||||
LIST_ITEM,
|
||||
DIV
|
||||
};
|
||||
|
||||
HtmlElement(const std::string& tagName);
|
||||
|
@ -27,6 +28,20 @@ public:
|
|||
virtual Type getType() const = 0;
|
||||
};
|
||||
|
||||
class HtmlDivElement : public HtmlElement
|
||||
{
|
||||
public:
|
||||
HtmlDivElement() : HtmlElement("div")
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Type getType() const override
|
||||
{
|
||||
return Type::DIV;
|
||||
}
|
||||
};
|
||||
|
||||
class HtmlCodeElement : public HtmlElement
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
#include "HtmlWriter.h"
|
||||
|
||||
#include "HtmlDocument.h"
|
||||
#include "HtmlElement.h"
|
||||
#include "XmlElement.h"
|
||||
#include "XmlAttribute.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
HtmlWriter::HtmlWriter()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::string HtmlWriter::toString(HtmlElement* element, unsigned startDepth)
|
||||
{
|
||||
return element->toString(startDepth);
|
||||
}
|
||||
|
||||
std::string HtmlWriter::toString(HtmlDocument* document)
|
||||
{
|
||||
std::string content = "<!DOCTYPE html>\n";
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <string>
|
||||
|
||||
class HtmlDocument;
|
||||
class HtmlElement;
|
||||
|
||||
class HtmlWriter
|
||||
{
|
||||
|
@ -10,4 +11,6 @@ public:
|
|||
HtmlWriter();
|
||||
|
||||
std::string toString(HtmlDocument* document);
|
||||
|
||||
std::string toString(HtmlElement* element, unsigned startDepth=0);
|
||||
};
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include "MarkdownComponents.h"
|
||||
|
||||
#include "StringUtils.h"
|
||||
|
||||
MarkdownTextSpan::Type MarkdownTextSpan::getType() const
|
||||
{
|
||||
return Type::TEXT_SPAN;
|
||||
|
@ -87,6 +89,13 @@ MarkdownLink::Type MarkdownLink::getType() const
|
|||
return Type::LINK;
|
||||
}
|
||||
|
||||
void MarkdownLink::doFieldSubstitution(Type elementType, const std::string& searchPhrase, const std::string& replacementPhrase)
|
||||
{
|
||||
if (elementType == Type::LINK)
|
||||
{
|
||||
mTarget = StringUtils::replaceWith(mTarget, searchPhrase, replacementPhrase);
|
||||
}
|
||||
}
|
||||
|
||||
MarkdownImage::MarkdownImage(const std::string& source, const std::string& alt)
|
||||
: mSource(source),
|
||||
|
|
|
@ -13,6 +13,28 @@ public:
|
|||
Type getType() const override;
|
||||
};
|
||||
|
||||
|
||||
class MarkdownLink : public MarkdownInlineElement
|
||||
{
|
||||
public:
|
||||
MarkdownLink(const std::string& target);
|
||||
|
||||
virtual ~MarkdownLink() = default;
|
||||
|
||||
const std::string& getTarget() const;
|
||||
|
||||
Type getType() const override;
|
||||
|
||||
void setTarget(const std::string& target)
|
||||
{
|
||||
mTarget = target;
|
||||
}
|
||||
|
||||
void doFieldSubstitution(Type elementType, const std::string& searchPhrase, const std::string& replacementPhrase) override;
|
||||
private:
|
||||
std::string mTarget;
|
||||
};
|
||||
|
||||
class MarkdownParagraph : public MarkdownElement
|
||||
{
|
||||
public:
|
||||
|
@ -26,6 +48,27 @@ public:
|
|||
|
||||
MarkdownInlineElement* getChild(std::size_t idx) const;
|
||||
|
||||
void doFieldSubstitution(Type elementType, const std::string& searchPhrase, const std::string& replacementPhrase) override
|
||||
{
|
||||
for(auto& child : mChildren)
|
||||
{
|
||||
child->doFieldSubstitution(elementType, searchPhrase, replacementPhrase);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<MarkdownLink*> getAllLinks() const
|
||||
{
|
||||
std::vector<MarkdownLink*> links;
|
||||
for(auto& child : mChildren)
|
||||
{
|
||||
if (child->getType() == Type::LINK)
|
||||
{
|
||||
links.push_back(dynamic_cast<MarkdownLink*>(child.get()));
|
||||
}
|
||||
}
|
||||
return links;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<MarkdownInlineElement> > mChildren;
|
||||
};
|
||||
|
@ -79,20 +122,6 @@ public:
|
|||
Type getType() const override;
|
||||
};
|
||||
|
||||
class MarkdownLink : public MarkdownInlineElement
|
||||
{
|
||||
public:
|
||||
MarkdownLink(const std::string& target);
|
||||
|
||||
virtual ~MarkdownLink() = default;
|
||||
|
||||
const std::string& getTarget() const;
|
||||
|
||||
Type getType() const override;
|
||||
private:
|
||||
std::string mTarget;
|
||||
};
|
||||
|
||||
class MarkdownImage : public MarkdownInlineElement
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -3,16 +3,15 @@
|
|||
#include "HtmlDocument.h"
|
||||
#include "HtmlElement.h"
|
||||
#include "HtmlParagraphElement.h"
|
||||
#include "HtmlBodyElement.h"
|
||||
#include "HtmlTextRun.h"
|
||||
#include "MarkdownElement.h"
|
||||
#include "MarkdownComponents.h"
|
||||
|
||||
#include "MarkdownDocument.h"
|
||||
|
||||
std::unique_ptr<HtmlDocument> MarkdownConverter::convert(MarkdownDocument* markdownDoc) const
|
||||
void MarkdownConverter::convert(MarkdownDocument* markdownDoc, HtmlElement* parentElement) const
|
||||
{
|
||||
auto html_doc = std::make_unique<HtmlDocument>();
|
||||
|
||||
for(unsigned idx=0; idx<markdownDoc->getNumElements();idx++)
|
||||
{
|
||||
auto md_element = markdownDoc->getElement(idx);
|
||||
|
@ -23,7 +22,7 @@ std::unique_ptr<HtmlDocument> MarkdownConverter::convert(MarkdownDocument* markd
|
|||
auto html_element = std::make_unique<HtmlHeadingElement>(heading_level);
|
||||
html_element->setText(md_element->getTextContent());
|
||||
|
||||
html_doc->addElementToBody(std::move(html_element));
|
||||
parentElement->addChild(std::move(html_element));
|
||||
}
|
||||
else if(md_element->getType() == MarkdownElement::Type::PARAGRAPH)
|
||||
{
|
||||
|
@ -59,7 +58,7 @@ std::unique_ptr<HtmlDocument> MarkdownConverter::convert(MarkdownDocument* markd
|
|||
html_p_element->addChild(std::move(html_text));
|
||||
}
|
||||
}
|
||||
html_doc->addElementToBody(std::move(html_p_element));
|
||||
parentElement->addChild(std::move(html_p_element));
|
||||
}
|
||||
else if(md_element->getType() == MarkdownElement::Type::BULLET_LIST)
|
||||
{
|
||||
|
@ -72,15 +71,23 @@ std::unique_ptr<HtmlDocument> MarkdownConverter::convert(MarkdownDocument* markd
|
|||
html_list_item->setText(child->getTextContent());
|
||||
html_list->addChild(std::move(html_list_item));
|
||||
}
|
||||
html_doc->addElementToBody(std::move(html_list));
|
||||
parentElement->addChild(std::move(html_list));
|
||||
}
|
||||
else if(md_element->getType() == MarkdownElement::Type::MULTILINE_QUOTE)
|
||||
{
|
||||
auto html_quote = std::make_unique<HtmlCodeElement>();
|
||||
html_quote->setText(md_element->getTextContent());
|
||||
html_doc->addElementToBody(std::move(html_quote));
|
||||
parentElement->addChild(std::move(html_quote));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<HtmlDocument> MarkdownConverter::convert(MarkdownDocument* markdownDoc) const
|
||||
{
|
||||
auto html_doc = std::make_unique<HtmlDocument>();
|
||||
|
||||
auto body_element = html_doc->getBodyElement();
|
||||
convert(markdownDoc, body_element);
|
||||
|
||||
return std::move(html_doc);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <memory>
|
||||
|
||||
class HtmlDocument;
|
||||
class HtmlElement;
|
||||
class MarkdownDocument;
|
||||
|
||||
class MarkdownConverter
|
||||
|
@ -10,4 +11,6 @@ class MarkdownConverter
|
|||
public:
|
||||
std::unique_ptr<HtmlDocument> convert(MarkdownDocument* markdownDoc) const;
|
||||
|
||||
void convert(MarkdownDocument* markdownDoc, HtmlElement* parentElement) const;
|
||||
|
||||
};
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#include "MarkdownDocument.h"
|
||||
|
||||
#include "MarkdownElement.h"
|
||||
#include "MarkdownComponents.h"
|
||||
|
||||
|
||||
void MarkdownDocument::addElement(std::unique_ptr<MarkdownElement> element)
|
||||
{
|
||||
|
@ -16,3 +18,25 @@ MarkdownElement* MarkdownDocument::getElement(std::size_t idx) const
|
|||
{
|
||||
return mElements[idx].get();
|
||||
}
|
||||
|
||||
void MarkdownDocument::doLinkTargetSubstitution(const std::string& targetString, const std::string& replacementString)
|
||||
{
|
||||
for(auto& element : mElements)
|
||||
{
|
||||
element->doFieldSubstitution(MarkdownElement::Type::LINK, targetString, replacementString);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<MarkdownLink*> MarkdownDocument::getAllLinks() const
|
||||
{
|
||||
std::vector<MarkdownLink*> links;
|
||||
for(auto& element : mElements)
|
||||
{
|
||||
if (element->getType() == MarkdownElement::Type::PARAGRAPH)
|
||||
{
|
||||
auto para_links = dynamic_cast<MarkdownParagraph*>(element.get())->getAllLinks();
|
||||
links.insert(links.end(), para_links.begin(), para_links.end());
|
||||
}
|
||||
}
|
||||
return links;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <memory>
|
||||
|
||||
class MarkdownElement;
|
||||
class MarkdownLink;
|
||||
|
||||
class MarkdownDocument
|
||||
{
|
||||
|
@ -14,6 +15,10 @@ public:
|
|||
|
||||
MarkdownElement* getElement(std::size_t idx) const;
|
||||
|
||||
void doLinkTargetSubstitution(const std::string& targetString, const std::string& replacementString);
|
||||
|
||||
std::vector<MarkdownLink*> getAllLinks() const;
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<MarkdownElement> > mElements;
|
||||
};
|
||||
|
|
|
@ -29,6 +29,11 @@ public:
|
|||
const std::string& getTextContent() const;
|
||||
|
||||
virtual Type getType() const = 0;
|
||||
|
||||
virtual void doFieldSubstitution(Type elementType, const std::string& searchPhrase, const std::string& replacementPhrase)
|
||||
{
|
||||
|
||||
}
|
||||
private:
|
||||
std::string mTextContent;
|
||||
};
|
||||
|
|
|
@ -19,7 +19,6 @@ MarkdownParser::~MarkdownParser()
|
|||
|
||||
void MarkdownParser::onMultilineQuote()
|
||||
{
|
||||
std::cout << "Adding multiline quote " << mDocumentContent << std::endl;
|
||||
auto quote = std::make_unique<MarkdownMultilineQuote>(mWorkingTag);
|
||||
quote->appendTextContent(mDocumentContent);
|
||||
|
||||
|
@ -34,8 +33,6 @@ void MarkdownParser::onMultilineQuote()
|
|||
|
||||
void MarkdownParser::onInlineQuote()
|
||||
{
|
||||
std::cout << "Adding inline quote " << mLineContent << std::endl;
|
||||
|
||||
auto quote = std::make_unique<MarkdownInlineQuote>();
|
||||
quote->appendTextContent(mLineContent);
|
||||
mLineContent.clear();
|
||||
|
@ -49,8 +46,6 @@ void MarkdownParser::onInlineQuote()
|
|||
|
||||
void MarkdownParser::onHeading(unsigned level)
|
||||
{
|
||||
std::cout << "Adding heading: " << mLineContent << std::endl;
|
||||
|
||||
auto heading = std::make_unique<MarkdownHeading>(level);
|
||||
heading->appendTextContent(mLineContent);
|
||||
mMarkdownDocument->addElement(std::move(heading));
|
||||
|
@ -60,7 +55,6 @@ void MarkdownParser::onNewParagraph()
|
|||
{
|
||||
if (mWorkingBulletList)
|
||||
{
|
||||
std::cout << "Adding bullets to document" << std::endl;
|
||||
mMarkdownDocument->addElement(std::move(mWorkingBulletList));
|
||||
mWorkingBulletList.reset();
|
||||
mDocumentState == DocumentState::NONE;
|
||||
|
@ -71,7 +65,6 @@ void MarkdownParser::onNewParagraph()
|
|||
|
||||
if (!mWorkingParagraph->getNumChildren() == 0)
|
||||
{
|
||||
std::cout << "Adding para to document" << std::endl;
|
||||
mMarkdownDocument->addElement(std::move(mWorkingParagraph));
|
||||
}
|
||||
}
|
||||
|
@ -84,8 +77,6 @@ void MarkdownParser::onTextSpan()
|
|||
|
||||
if(mWorkingParagraph && !mDocumentContent.empty())
|
||||
{
|
||||
std::cout << "Adding text " << mDocumentContent << std::endl;
|
||||
|
||||
auto text_span = std::make_unique<MarkdownTextSpan>();
|
||||
text_span->appendTextContent(mDocumentContent);
|
||||
mWorkingParagraph->addChild(std::move(text_span));
|
||||
|
@ -141,7 +132,6 @@ std::pair<unsigned, bool> MarkdownParser::onTick(unsigned tickCount)
|
|||
|
||||
void MarkdownParser::onLink()
|
||||
{
|
||||
std::cout << "Adding hyperlink to " << mLineContent << " with tag " << mWorkingTag << std::endl;
|
||||
auto element = std::make_unique<MarkdownLink>(mLineContent);
|
||||
mLineContent.clear();
|
||||
|
||||
|
@ -157,7 +147,6 @@ void MarkdownParser::onLink()
|
|||
|
||||
void MarkdownParser::onImage()
|
||||
{
|
||||
std::cout << "Adding image with path " << mLineContent << " and alt" << mWorkingTag << std::endl;
|
||||
auto element = std::make_unique<MarkdownImage>(mLineContent, mWorkingTag);
|
||||
mLineContent.clear();
|
||||
|
||||
|
@ -173,8 +162,6 @@ void MarkdownParser::onImage()
|
|||
|
||||
void MarkdownParser::onBulletItem()
|
||||
{
|
||||
std::cout << "Adding bullet item " << mLineContent << std::endl;
|
||||
|
||||
if (!mWorkingBulletList)
|
||||
{
|
||||
mWorkingBulletList = std::make_unique<MarkdownBulletList>();
|
||||
|
@ -231,7 +218,6 @@ void MarkdownParser::processLine()
|
|||
{
|
||||
if (!flushed_pre_inline)
|
||||
{
|
||||
std::cout << "Flushing pre-line " << std::endl;
|
||||
mDocumentContent += mLineContent;
|
||||
onTextSpan();
|
||||
flushed_pre_inline = true;
|
||||
|
|
|
@ -8,8 +8,7 @@
|
|||
TEST_CASE(TestTemplatingEngine, "compiler")
|
||||
{
|
||||
auto engine = TemplatingEngine(TestUtils::getTestDataDir());
|
||||
engine.loadTemplateFiles();
|
||||
const auto content = engine.processTemplate("index");
|
||||
const auto content = engine.renderTemplate("index", nullptr);
|
||||
|
||||
File outfile(TestUtils::getTestOutputDir() / "index.html");
|
||||
outfile.writeText(content);
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
set(CORE_UNIT_TEST_FILES
|
||||
core/TestByteUtils.cpp
|
||||
core/TestBitStream.cpp
|
||||
core/TestTomlReader.cpp
|
||||
core/TestDataStructures.cpp
|
||||
core/TestTomlReader.cpp
|
||||
core/TestStringUtils.cpp
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
|
|
15
test/core/TestStringUtils.cpp
Normal file
15
test/core/TestStringUtils.cpp
Normal file
|
@ -0,0 +1,15 @@
|
|||
#include "StringUtils.h"
|
||||
|
||||
#include "TestFramework.h"
|
||||
#include "TestUtils.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
TEST_CASE(TestStringUtils_Strip, "core")
|
||||
{
|
||||
std::string input = " super() ";
|
||||
std::string stripped = StringUtils::strip(input);
|
||||
|
||||
auto predicate = stripped == "super()";
|
||||
REQUIRE(predicate);
|
||||
}
|
|
@ -5,6 +5,7 @@
|
|||
#include "HtmlDocument.h"
|
||||
#include "MarkdownDocument.h"
|
||||
#include "MarkdownConverter.h"
|
||||
#include "MarkdownElement.h"
|
||||
#include "HtmlWriter.h"
|
||||
|
||||
#include "TestFramework.h"
|
||||
|
|
Loading…
Reference in a new issue