Skip to content

Commit

Permalink
Refactoring ssg.py to improve code maintainability
Browse files Browse the repository at this point in the history
* Changed a word in a comment
* Simplified markdown header parsing
* Extracted SSGParser class
* Extracted SSGUtil class
  • Loading branch information
a-rokay committed Oct 14, 2021
1 parent fb0fd72 commit 0ffa06c
Show file tree
Hide file tree
Showing 6 changed files with 1,319 additions and 151 deletions.
3 changes: 2 additions & 1 deletion .gitignore
@@ -1 +1,2 @@
ssg/dist/
ssg/dist/
__pycache__
91 changes: 91 additions & 0 deletions ssg/SSGParser.py
@@ -0,0 +1,91 @@
import re
import SSGUtil

html_skeleton = """<!doctype html>
<html lang="{lang}">
<head>
<meta charset="utf-8">
<title>{title}</title>
<meta name="viewport" content="width=device-width, initial-scale=1">{stylesheet}
</head>
<body>
{content}
</body>
</html>
"""

# Returns None if no title is found
def get_txt_title(file_location):
title = None
first_3_lines = []
i = 0

# Read file line by line, up to line 3
with open(file_location, "r", encoding="utf8") as input_file:
while(line := input_file.readline()):

if(i == 3):
break

cleaned_line = line.rstrip()
first_3_lines.append(cleaned_line)
i += 1

# Check if title criteria is met
if(len(first_3_lines) == 3):
if(first_3_lines[0] and not first_3_lines[1] and not first_3_lines[2]):
title = first_3_lines[0]

return title

# Returns html content, including title, if set
def generate_content(file_location, title):
if(not SSGUtil.is_file_accepted(file_location)):
return

titled_format = "<h1>{}</h1>\n\n\n{}"
content = ""

with open(file_location, "r", encoding="utf8") as input_file:
content = input_file.read()

# Skip the first 3 lines if there's a title
if(title):
content = content.split("\n", 3)[3]

content = "<p>" + content
content = content.replace("\n\n", "</p>\n\n<p>")
content = content + "\n</p>"

if file_location.endswith(".md"):
content = process_markdown(content)

if(title):
content = titled_format.format(title, content)

return content

def process_markdown(content):
# Process bold markdown
content = re.sub('\*\*([^\s\*.].*?)\*\*|__([^\s_.].*?)__', r'<strong>\1</strong>', content, flags=re.DOTALL)

# Process italic markdown
content = re.sub('\*([^\s\*.].*?)\*|_([^\s\_.].*?)_', r'<em>\1\2</em>', content, flags=re.DOTALL)

# Process single backtick markdown
content = re.sub('`([^\r\n\`].*?)`', r'<code>\1</code>', content, flags=re.DOTALL)

# Process header markdown
headerTag = lambda s: '<h{size}>{content}</h{size}>\n'.format(size=s.group(2).count('#'), content=s.group(3))
content = re.sub(r'(|(?<!\n)\n|<p>)(#{1,5})\s(.*)(<\/p>|(?<!<\/p>)\n|$)', headerTag, content)

return content

# Inserts title, stylesheet, and content to html_skeleton, returns the result
def generate_html(lang, file_name, title, stylesheet, content):
ss_tag = ""

if(stylesheet):
ss_tag = '\n\t<link rel="stylesheet" href="{}">'.format(stylesheet)

return html_skeleton.format(lang=lang, title=title if title else file_name, stylesheet=ss_tag, content=content)
51 changes: 51 additions & 0 deletions ssg/SSGUtil.py
@@ -0,0 +1,51 @@
import json
import os

OUTPUT_FOLDER = "dist"
ACCEPTED_FILE_TYPES = [".txt", ".md"]

# Returns a list of files with acceptable file types by filtering all files in folder_name
def get_accepted_files(folder_name):
all_files = os.listdir(folder_name)
filtered_files = filter(lambda f: is_file_accepted(f), all_files)
return list(filtered_files)

def is_file_accepted(filename):
for type in ACCEPTED_FILE_TYPES:
if filename.endswith(type):
return True
return False

def output_to_file(file_name, html):
# Create output folder if it doesn't exist
if(not os.path.isdir(OUTPUT_FOLDER)):
os.mkdir(OUTPUT_FOLDER)

file_location = OUTPUT_FOLDER + "/" + file_name.replace(file_name[file_name.rfind("."):], ".html")
with open(file_location, "w", encoding="utf8") as output_file:
output_file.write(html)

def get_config(config, input, lang, stylesheet):
# Check to see if config file exists.
if config:
with open(config) as f:
try:
data = json.load(f)
if len(data) == 0:
print("\nConfig File is empty!\n")
exit(1)
except (json.decoder.JSONDecodeError) as err:
print("\nError parsing Config File: {0}\n".format(err))
exit(1)
# For each command from JSON config file, set local variables
for i in data:
if i == "input" or i == "i":
input = data[i]
elif i == "stylesheet" or i == "s":
stylesheet = data[i]
elif i == "lang" or i == "l":
lang = data[i]
if input == None:
print("No input file specified")
exit(1)
return input, lang, stylesheet

0 comments on commit 0ffa06c

Please sign in to comment.