Created
January 30, 2022 17:59
-
-
Save RPGillespie6/b133854b8ebf5a983cf32c26d684cff3 to your computer and use it in GitHub Desktop.
Super Simple Static Site Generator (SSSSG)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
""" | |
Author: Bryan Gillespie | |
License: MIT | |
Super Simple Static Site Generator (SSSSG) | |
A tiny Markdown -> HTML converter | |
""" | |
import os | |
import re | |
import json | |
import pathlib | |
import argparse | |
# Indentation | |
II = " " | |
PAGE_TEMPLATE = """ | |
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="UTF-8"/> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<link rel ="stylesheet" href="/css/main.css"> | |
<title>Bryan Gillespie</title> | |
</head> | |
<body> | |
<a class="mr-nav" href="/">Home</a> | |
<a class="mr-nav" href="/about">About</a> | |
{page_content} | |
</body> | |
</html> | |
""".strip() | |
# From: https://davidwells.io/snippets/regex-match-markdown-links | |
# Modified to support markdown of the form: [a](b){c} | |
REGEX_ANCHOR_STR = '\[([\w\s\d\']+)\]\(((?:\/|https?:\/\/)[\w\d./?=#]+)\)(?:{(.*?)})?' | |
P_VIDEO = re.compile("!!"+REGEX_ANCHOR_STR) | |
P_IMG = re.compile("!"+REGEX_ANCHOR_STR) | |
P_ANCHOR = re.compile(REGEX_ANCHOR_STR) | |
P_BOLD = re.compile(f"\*\*(.*?)\*\*") | |
P_ITALICS = re.compile(f"\*(.*?)\*") | |
def formatLine(line): | |
line = line.strip() | |
# Order is important here - video always needs to come before img, etc. | |
pattern_templates = [ | |
(P_VIDEO, '<video {2}{0}><source src="{1}" type="video/mp4"></video>'), | |
(P_IMG, '<img {2}src="{1}" alt="{0}">'), | |
(P_ANCHOR, '<a {2}href="{1}">{0}</a>'), | |
(P_BOLD, '<strong>{0}</strong>'), | |
(P_ITALICS, '<em>{0}</em>'), | |
] | |
for pattern, template in pattern_templates: | |
m = True | |
while m: | |
m = pattern.search(line) | |
if m: | |
cgroups = list(m.groups()) | |
if len(cgroups) == 3: | |
cgroups[2] = f'class="{cgroups[2]}" ' if cgroups[2] else "" | |
tag = template.format(*cgroups) | |
line = re.sub(pattern, tag, line, 1) | |
return line | |
def preprocessPage(page): | |
with open(page) as f: | |
lines = f.readlines() | |
metadata = lines[0] | |
md = lines[1:] | |
if not metadata.startswith(">> "): | |
print("Fatal: incorrectly formatted metadata") | |
os.exit(1) | |
# Parse metadata as JSON | |
metadata = json.loads(metadata[3:]) | |
# Make sure md always ends with an empty string line | |
if md[-1].strip(): | |
md.append("") | |
return metadata, md | |
def getHTMLPath(md_path, metadata): | |
page_name = pathlib.Path(md_path).stem + ".html" | |
target_path = os.path.abspath(metadata["target_path"].replace("#", ".")) | |
return os.path.join(target_path, page_name) | |
def processPage(md_path, metadata, md): | |
html_path = getHTMLPath(md_path, metadata) | |
page_content = [] | |
current_paragraph = [] | |
for line in md: | |
line = formatLine(line) | |
if not line: | |
if current_paragraph: | |
paragraph = f"<br>\n{II}".join(current_paragraph) | |
paragraph = f"<p>{paragraph}</p>" | |
page_content.append(paragraph) | |
current_paragraph = [] | |
continue | |
if line.startswith("#"): | |
left, heading = line.split(" ", 1) | |
hll = len(left) | |
page_content.append(f"<h{hll}>{heading}</h{hll}>") | |
continue | |
current_paragraph.append(line) | |
with open(html_path, "w") as f: | |
f.write(PAGE_TEMPLATE.format(page_content=f"\n{II}".join(page_content))) | |
def processPages(pages): | |
for page in pages: | |
print(page) | |
metadata, md = preprocessPage(page) | |
processPage(page, metadata, md) | |
def parseArgs(): | |
parser = argparse.ArgumentParser(description="SSSSG - Super Simple Static Site Generator") | |
parser.add_argument("pages", nargs="+", help="Pages to generate") | |
# parser.add_argument("-f", "--flag", action="store_true", help="Some bool flag") | |
return parser.parse_args() | |
def main(): | |
args = parseArgs() | |
processPages(args.pages) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment