Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add initial support for Markdown #13

Merged
merged 10 commits into from
Sep 21, 2023
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# til-to-html

This tool converts [TIL](https://simonwillison.net/2022/Nov/6/what-to-blog-about/) posts written in [Markdown](https://www.markdownguide.org/) into static HTML pages.
This tool converts [TIL](https://simonwillison.net/2022/Nov/6/what-to-blog-about/) posts written in [Markdown](https://www.markdownguide.org/) (.txt, .md) into static HTML pages.

## Setup

Expand Down
20 changes: 20 additions & 0 deletions examples/dir/markdown1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
This is a Heading 2 markdown test file 1


First Heading 2 ## Testing out
--
A TIL—Today I Learned—is the most liberating form of content I know of.

Did you just learn how to do something? Write about that.

Call it a TIL—that way you’re not promising anyone a revelation or an in-depth tutorial. You’re saying “I just figured this out: here are my notes, you may find them useful too”.

I also like the humility of this kind of content. Part of the reason I publish them is to emphasize that even with 25 years of professional experience you should still celebrate learning even the most basic of things.

Second Heading 2
-----------------------------------------
I learned the “interact” command in pdb the other day! [Here’s my TIL](https://til.simonwillison.net/python/pdb-interact).

I started publishing TILs [in April 2020](https://simonwillison.net/2020/Apr/20/self-rewriting-readme/). I’m up to 346 now, and most of them took less than 10 minutes to write. It’s such a great format for quick and satisfying online writing.

My collection lives at https://til.simonwillison.net/—which publishes content from my [simonw/til](https://github.com/simonw/til) GitHub repository.
16 changes: 16 additions & 0 deletions examples/markdown.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
markdown-to-html test


A tool to convert [TIL](https://simonwillison.net/2022/Nov/6/what-to-blog-about/) posts written in [Markdown](https://www.markdownguide.org/) into **static HTML pages**.

## Usage for Flags - Heading 2
Run **til-to-html -h** for additional help.

Run **til-to-html -v** for version information.

## Usage for Paths - Heading 2
Run **til-to-html ./examples/til.txt** to generate a single webpage.

Run **til-to-html ./examples/dir** to generate multiple webpages from a folder.

Refer to the [til-to-html repository](https://github.com/paulkim26/til-to-html) for additional information.
14 changes: 13 additions & 1 deletion src/parse-markdown/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ export default function parseMarkdown(md: string, fname: string) {
const hasTitle =
paragraphs[0].length > 0 && paragraphs[1] === "" && paragraphs[2] === "";

// Check for alternative Heading Two syntax
for (let i = 0; i < paragraphs.length; i++) {
Copy link
Owner

@paulkim26 paulkim26 Sep 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can eliminate checking for condition i < paragraphs.length - 1 by limiting the iteration condition.

Example:

for (let i = 0; i < (paragraphs.length - 1); i++) {
  if (i < paragraphs[i + 1].match(/^( {0,3}-+\s*)$/) !== null) {
    paragraphs[i] = `${paragraphs[i]}\n${paragraphs[i + 1]}`;
    paragraphs[i + 1] = "";
  }
}

if (i < paragraphs.length - 1 && paragraphs[i + 1].match(/^( {0,3}-+\s*)$/) != null) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strict type checking operators are preferred (!==)

paragraphs[i] = `${paragraphs[i]}\n${paragraphs[i + 1]}`;
paragraphs[i + 1] = "";
}
}

// Clear empty paragraphs
paragraphs = paragraphs.filter((paragraph) => paragraph !== "");

Expand All @@ -22,7 +30,11 @@ export default function parseMarkdown(md: string, fname: string) {
lineHtml += `<h1>${parsedParagraph}</h1>`;
title = parsedParagraph; // Set <title> tag
} else {
lineHtml += `<p>${parsedParagraph}</p>`;
if (parsedParagraph.startsWith("<h2>") && parsedParagraph.endsWith("</h2>")) {
lineHtml += `${parsedParagraph}`;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for template syntax, can simply do:

lineHtml += parsedParagraph;

} else {
lineHtml += `<p>${parsedParagraph}</p>`;
}
}

bodyHtml += `${lineHtml}\n`;
Expand Down
2 changes: 2 additions & 0 deletions src/parse-markdown/parseBlock.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import parseLink from "@/parse-markdown/parseLink";
import parseBold from "@/parse-markdown/parseBold";
import parseItalics from "@/parse-markdown/parseItalics";
import parseHeadingTwo from "./parseHeadingTwo";

// Parse text within paragraph tag
export default function parseBlock(text: string) {
let html = text;

html = parseHeadingTwo(html);
html = parseLink(html);
html = parseBold(html);
html = parseItalics(html);
Expand Down
17 changes: 17 additions & 0 deletions src/parse-markdown/parseHeadingTwo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export default function parseHeadingTwo(text: string) {
let html = text;

const headingTwoPattern = /^( {0,3}##\s+.*)/;
html = html.replace(headingTwoPattern, (match, headingTwoText) => {
let headingTwo = headingTwoText.split(/##/).slice(1).join("##").trim();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer using const whenever possible if a value does not need to be mutated within its scope.

return `<h2>${headingTwo}</h2>`;
});

const headingTwoPattern2 = /^(.*\n {0,3}-+\s*)/;
html = html.replace(headingTwoPattern2, (match, headingTwoText) => {
let altHeadingTwo = headingTwoText.split(/\n/)[0].trim();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer using const whenever possible if a value does not need to be mutated within its scope. I'd also prefer using the same variable headingTwo like last time since it's a good variable name and the two scopes are distinct.

return `<h2>${altHeadingTwo}</h2>`;
});

return html;
}
4 changes: 2 additions & 2 deletions src/parseArguments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,14 @@ export default async function parseArguments(args: string[]) {

if (foundTarget) {
const filesToProcess = [];
const isFolder = !target.endsWith(".txt");
const isFolder = !(target.endsWith(".txt") || target.endsWith(".md"));

console.log(`Reading files...`);

if (isFolder) {
// Parse folder of text files
const dir = target;
let files = readdirSync(dir).filter((file) => file.endsWith(".txt"));
let files = readdirSync(dir).filter((file) => file.endsWith(".txt") || file.endsWith(".md"));
files = files.map((file) => `${dir}/${file}`);

files.forEach((file) => filesToProcess.push(file));
Expand Down