Merge pull request 'FEATURE: Node implementations' (#17) from feature/node-impl into main

Reviewed-on: azpect/MarkdownToHtmlCompiler#17
Reviewed-by: shultzp1 <shultzp1@my.erau.edu>
This commit is contained in:
shultzp1 2025-10-16 15:13:16 -07:00
commit 26aae7cf98
11 changed files with 382 additions and 192 deletions

1
.gitignore vendored
View File

@ -2,3 +2,4 @@
/build
/build/*
parser
/.vscode

65
.vscode/settings.json vendored
View File

@ -1,65 +0,0 @@
{
"C_Cpp.errorSquiggles": "disabled",
"files.associations": {
"filesystem": "cpp",
"algorithm": "cpp",
"atomic": "cpp",
"bit": "cpp",
"cctype": "cpp",
"charconv": "cpp",
"chrono": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"compare": "cpp",
"concepts": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"deque": "cpp",
"exception": "cpp",
"format": "cpp",
"forward_list": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"ios": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"iterator": "cpp",
"limits": "cpp",
"locale": "cpp",
"memory": "cpp",
"new": "cpp",
"optional": "cpp",
"ostream": "cpp",
"ratio": "cpp",
"sstream": "cpp",
"stack": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"string": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"typeinfo": "cpp",
"utility": "cpp",
"vector": "cpp",
"xfacet": "cpp",
"xiosbase": "cpp",
"xlocale": "cpp",
"xlocbuf": "cpp",
"xlocinfo": "cpp",
"xlocmes": "cpp",
"xlocmon": "cpp",
"xlocnum": "cpp",
"xloctime": "cpp",
"xmemory": "cpp",
"xstring": "cpp",
"xtr1common": "cpp",
"xutility": "cpp"
}
}

View File

@ -41,9 +41,6 @@ $(BUILD_DIR)/%.o: $(LIB_DIR)/%.cpp
test: all
./$(TARGET)
./$(TARGET) ' '
./$(TARGET) ./test/input.md
./$(TARGET) ./test/input.md ./test/output.html
clean:
rm -rf $(BUILD_DIR) $(TARGET)

View File

@ -1,48 +0,0 @@
#ifndef INLINENODE_H
#define INLINENODE_H
#include "node.h"
#include <string>
/**
* @brief InlineNode class.
*
* Inherits from Node. Represents an inline object that is used
* by the DOM tree to convert inline tags from a markup file
* to an HTML file.
*
* @author Preston Shultz
*/
class InlineNode : public Node {
public:
InlineNode(const std::string& content) : content(content) {}
// Optional: allow access to the content
std::string getContent() const { return content; }
protected:
std::string content;
};
// These classes inherit the InlineNode constructor using `using`
class TextNode : public InlineNode {
public:
using InlineNode::InlineNode;
};
class BoldNode : public InlineNode {
public:
using InlineNode::InlineNode;
};
class ItalicNode : public InlineNode {
public:
using InlineNode::InlineNode;
};
class BoldItalicNode : public InlineNode {
public:
using InlineNode::InlineNode;
};
#endif // INLINENODE_H

View File

@ -0,0 +1,23 @@
#include "inlineNode.h"
#include <memory>
#include <stdexcept>
#include <string>
using std::string;
void InlineNode::AddChild(std::unique_ptr<Node> child) {
throw std::runtime_error("Cannot add a child to an InlineNode.");
}
string TextNode::ToHtml() const { return this->content; }
string ItalicNode::ToHtml() const { return "<em>" + this->content + "</em>"; }
string BoldNode::ToHtml() const {
return "<strong>" + this->content + "</strong>";
}
string BoldItalicNode::ToHtml() const {
return "<strong><em>" + this->content + "</em></strong>";
}

97
lib/inlineNode.h Normal file
View File

@ -0,0 +1,97 @@
#ifndef INLINENODE_H
#define INLINENODE_H
#include "node.h"
#include <vector>
/**
* @desc ABC inline node for textual nodes.
*
* An inline node has content, but no children. An attempt to add children to
* this node will result in a runtime exception.
* Inline nodes define text itself, not textual tags, but the actual text inside
* the tags.
*
* @author Hayden Hargreaves (hhargreaves2006@gmail.com)
*/
class InlineNode : public Node {
public:
InlineNode(std::string content) : content(content) {};
/**
* @brief Return node as HTML string.
*
* This method is virtual and required to be overridden.
*
* @author Hayden Hargreaves (hhargreaves2006@gmail.com)
*/
virtual std::string ToHtml() const = 0;
/**
* @brief Cannot add a child to this class.
*
* This method simply returns a runtime error, since there is no reason to add
* a child to a textual node.
*
* @author Hayden Hargreaves (hhargreaves2006@gmail.com)
*/
void AddChild(std::unique_ptr<Node> child);
protected:
std::string content;
};
/**
* @desc A raw textual node.
*
* This node is simple, it simple returns it's content with no formatting.
*
* @author Hayden Hargreaves (hhargreaves2006@gmail.com)
*/
class TextNode : public InlineNode {
public:
TextNode(std::string content) : InlineNode(content) {};
std::string ToHtml() const;
};
/**
* @desc A italic textual node.
*
* This node returns it's content wrapped with <em></em> tags.
*
* @author Hayden Hargreaves (hhargreaves2006@gmail.com)
*/
class ItalicNode : public InlineNode {
public:
ItalicNode(std::string content) : InlineNode(content) {};
std::string ToHtml() const;
};
/**
* @desc A bold textual node.
*
* This node returns it's content wrapped with <strong></strong> tags.
*
* @author Hayden Hargreaves (hhargreaves2006@gmail.com)
*/
class BoldNode : public InlineNode {
public:
BoldNode(std::string content) : InlineNode(content) {};
std::string ToHtml() const;
};
/**
* @desc A bold and italic textual node.
*
* This node returns it's content wrapped with <strong></strong> AND <em>/<em>
* tags.
*
* @author Hayden Hargreaves (hhargreaves2006@gmail.com)
*/
class BoldItalicNode : public InlineNode {
public:
BoldItalicNode(std::string content) : InlineNode(content) {};
std::string ToHtml() const;
};
#endif

View File

@ -16,6 +16,7 @@
/// method is required. When calling a function that accepts a reference, the
/// reference operator (*) works perfectly fine. Hence, in this project we will
/// try to avoid using raw pointers, and only use references when needed.
/// Reference: https://www.youtube.com/watch?v=AmjoK55h68Y&t=166s
// NOTE ABC
class Node {

View File

@ -1 +1,65 @@
#include "structureNode.h"
#include <cstdio>
#include <sstream>
#include <stdexcept>
#include <string>
using std::string;
string DocumentNode::ToHtml() const {
std::stringstream ss;
ss << "<!DOCTYPE html>\n\t<html lang=\"en\">\n\t\t<head>\n\t\t\t<meta "
"charset=\"UTF-8\">\n\t\t\t<meta "
"name=\"viewport\" content=\"width=device-width, "
"initial-scale=1.0\">\n\t\t\t<title>Document</title>\n\t\t</"
"head>\n\t<body>\n";
for (const auto &child : this->GetChilren()) {
ss << child->ToHtml();
}
ss << "\n\t</body>\n</html>";
return ss.str();
}
HeadingNode::HeadingNode(int size) {
if (1 <= size && size <= 6) {
this->size = size;
return;
}
throw std::runtime_error("HeadingNode.size must be between 1 and 6.");
}
string HeadingNode::ToHtml() const {
std::stringstream ss;
ss << "<h" << size << ">";
for (const auto &child : this->GetChilren()) {
ss << child->ToHtml();
}
ss << "</h" << size << ">\n";
return ss.str();
}
string ParagraphNode::ToHtml() const {
std::stringstream ss;
ss << "<p>";
for (const auto &child : this->GetChilren()) {
ss << child->ToHtml();
}
ss << "</p>\n";
return ss.str();
}
// TODO: Implement
string ListNode::ToHtml() const {
std::stringstream ss;
ss << (this->ordered ? "<ol>NOT YET IMPLEMENTED</ol>"
: "<ul>NOT YET IMPLEMENTED</ul>");
return ss.str();
}

View File

@ -2,12 +2,103 @@
#define STRUCTURENODE_H
#include "node.h"
#include <string>
class StructureNode : public Node {};
/**
* @desc ABC inline node for structure nodes.
*
* A structure node has no content, but instead it has children which contain
* content. These children can be other structure nodes, or they can be inline
* nodes. Inline nodes allow this node to display textual content.
*
* @author Hayden Hargreaves (hhargreaves2006@gmail.com)
*/
class StructureNode : public Node {
public:
/**
* @brief Return node as HTML string.
*
* This method is virtual and required to be overridden.
*
* @author Hayden Hargreaves (hhargreaves2006@gmail.com)
*/
virtual std::string ToHtml() const = 0;
};
class ListNode : public StructureNode {};
class HeadingNode : public StructureNode {};
class DocumentNode : public StructureNode {};
class ParagraphNode : public StructureNode {};
/**
* @desc A main HTML document node.
*
* This node should be used as the root of the DOM. Calling `ToHtml` will yield
* an HTML document boiler plate with it's children rendered as the body.
*
* @author Hayden Hargreaves (hhargreaves2006@gmail.com)
*/
class DocumentNode : public StructureNode {
public:
std::string ToHtml() const;
};
/**
* @desc A heading node.
*
* A heading contains children that are expected to be inline nodes. These
* children represent the textual content of the node. This heading node simply
* stores the children and the size of the heading. A size of 1 means <h1>, etc.
*
* @author Hayden Hargreaves (hhargreaves2006@gmail.com)
*/
class HeadingNode : public StructureNode {
protected:
/**
* @brief Size of the heading.
*
* The constructor will enforce size requirements.
*
* @author Hayden Hargreaves (hhargreaves2006@gmail.com)
*/
int size;
public:
HeadingNode(int size);
std::string ToHtml() const;
};
/**
* @desc A paragraph node.
*
* A paragraph contains children that are expected to be inline nodes. These
* children represent the textual content of the node. This heading node simply
* stores the children.
*
* @author Hayden Hargreaves (hhargreaves2006@gmail.com)
*/
class ParagraphNode : public StructureNode {
public:
std::string ToHtml() const;
};
/**
* @desc A list container node.
*
* This node is used to wrap list elements. Not to be confused with the list
* elements themselves. This is the parent (<ul> or <ol>), and must be created
* with a boolean which defines whether the list should be ordered or not.
* i.e., should have numbers (use the <ol> tags).
*
* @author Hayden Hargreaves (hhargreaves2006@gmail.com)
*/
class ListNode : public StructureNode {
protected:
/**
* @brief Should the list be ordered (numeric).
*
* @author Hayden Hargreaves (hhargreaves2006@gmail.com)
*/
bool ordered;
public:
ListNode(bool ordered = false) : ordered(ordered) {};
std::string ToHtml() const;
};
#endif

View File

@ -1,10 +1,64 @@
/*#include "../lib/parser.h"
#include "../lib/inlineNode.h"
#include "../lib/parser.h"
#include "../lib/structureNode.h"
#include "../lib/watchDog.h"
#include <memory>
#include <stdexcept>
int main(int argc, char **argv) {
void test_nodes() {
// For simplicity
using std::make_unique;
using std::unique_ptr;
DocumentNode root;
unique_ptr<TextNode> node = make_unique<TextNode>("text node");
unique_ptr<BoldNode> bold = make_unique<BoldNode>("bold node");
unique_ptr<ItalicNode> italic = make_unique<ItalicNode>("italic node");
unique_ptr<BoldItalicNode> bolditalic =
make_unique<BoldItalicNode>("bold italic node");
unique_ptr<HeadingNode> heading = make_unique<HeadingNode>(2);
heading->AddChild(std::move(node));
heading->AddChild(std::move(bold));
std::unique_ptr<ParagraphNode> para = std::make_unique<ParagraphNode>();
para->AddChild(std::move(italic));
para->AddChild(std::move(bolditalic));
unique_ptr<ListNode> list = make_unique<ListNode>();
root.AddChild(std::move(heading));
root.AddChild(std::move(para));
root.AddChild(std::move(list));
std::cout << root.ToHtml() << std::endl;
}
/**
*Preston: Test to see if watchdog works :)
*/
void test_watchdog() {
WatchDog wd("test/input.md");
wd.start();
std::cout << "Initial check (should do nothing if file unchanged):\n";
wd.checkFile();
std::cout << "Now, modify or create the file 'example.txt' manually and "
"press Enter:\n";
std::cin.get(); // Wait for user to press Enter
// Check again after manual change
wd.checkFile();
std::cout << "Done testing.\n";
}
void test_input(int argc, char **argv) {
if (argc <= 1) {
std::cerr << "Usage: <input_file> <?output_file>" << std::endl;
return 0; // TODO: Should return 1?
return;
}
try {
@ -22,31 +76,6 @@ int main(int argc, char **argv) {
}
std::cout << std::endl;
return 0;
}
*/
/**
*Preston: Test to see if watchdog works :)
*/
#include "watchDog.h"
#include <iostream>
int main() {
WatchDog wd("test/input.md");
wd.start();
std::cout << "Initial check (should do nothing if file unchanged):\n";
wd.checkFile();
std::cout << "Now, modify or create the file 'example.txt' manually and press Enter:\n";
std::cin.get(); //Wait for user to press Enter
//Check again after manual change
wd.checkFile();
std::cout << "Done testing.\n";
return 0;
}
int main(int argc, char **argv) { test_nodes(); }