diff --git a/cli.js b/cli.js index 4ba8a0a..d70e3d0 100755 --- a/cli.js +++ b/cli.js @@ -1,9 +1,10 @@ #!/usr/bin/env node -const path = require("path"); -const fs = require("vinyl-fs"); -const map = require("map-stream"); -const tokenize = require("./tokenize"); -const toHTML = require("./to-html"); +import path from "path"; +import fs from "vinyl-fs"; +import map from "map-stream"; +import tokenize from "./tokenize.js"; +import toHTML from "./to-html.js"; +import yargs from "yargs"; // TODO: automatically pull these in from gmi.css (also for gmi.css(5)) const GMI_CSS_VARS = [ @@ -28,7 +29,7 @@ const GMI_CSS_VARS = [ "sans-serif", ]; -require("yargs") +yargs(process.argv.slice(2)) .scriptName("gmi-web") .config() .command( diff --git a/example/expected.html b/example/expected.html index 0897e59..cd51695 100644 --- a/example/expected.html +++ b/example/expected.html @@ -1,5 +1,5 @@ - + diff --git a/gmi.regex.js b/gmi.regex.js deleted file mode 100644 index 155240a..0000000 --- a/gmi.regex.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = /^((=>\s?(?[^\s]+)(\s(?.+))?)|(?<pre>```\s?(?<alt>.+)?)|(###\s?(?<h3>.+))|(##\s?(?<h2>.+))|(#\s?(?<h1>.+))|(\*\s?(?<li>.+))|(>\s?(?<quote>.+))|(?<text>(.+)?))$/; diff --git a/package.json b/package.json index 474a1fd..e6d70ce 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "1.0.7-rc.1", "description": "A bridge between HTML and Gemini", "main": "cli.js", + "type": "module", "bin": { "gmi-web": "cli.js" }, diff --git a/test.sh b/test.sh index 9e1af98..808e2bb 100755 --- a/test.sh +++ b/test.sh @@ -1,3 +1,4 @@ +rm -rf "example/test.html" ./cli.js --lang en --images --audio --video "example/*.gmi" if cmp -s "example/test.html" "example/expected.html"; then printf "PASS: test.html matches expected.html!\n" diff --git a/to-html.js b/to-html.js index 30828f0..0c82c87 100644 --- a/to-html.js +++ b/to-html.js @@ -1,32 +1,20 @@ -const fs = require("fs"); -const path = require("path"); -const escape = require("escape-html"); +import fs from "fs"; +import path from "path"; +import escape from "escape-html"; const TOKENS_EXT = /\.tokens\.json$/; // https://developer.mozilla.org/en-US/docs/Web/Media/Formats -const IMG_EXT = (exports.IMG_EXT = /\.(apng|avif|gif|jpg|jpeg|jfif|pjpeg|pjp|png|svg|webp)$/); -const AUDIO_EXT = (exports.AUDIO_EXT = /\.(mp3|wav|aac|aacp|mpeg|off|flac)$/); -const VIDEO_EXT = (exports.VIDEO_EXT = /\.(mp4|webm)$/); -const BASE_STYLE = (exports.BASE_STYLE = - "<style>p,a,pre,h1,h2,h3,ul,blockquote,img,audio,video{display:block;max-width:100%;margin:0;padding:0;overflow-wrap:anywhere;}</style>"); -const GMI_CSS = fs.readFileSync( - path.resolve(__dirname, "./gmi.min.css"), +export const IMG_EXT = /\.(apng|avif|gif|jpg|jpeg|jfif|pjpeg|pjp|png|svg|webp)$/; +export const AUDIO_EXT = /\.(mp3|wav|aac|aacp|mpeg|off|flac)$/; +export const VIDEO_EXT = /\.(mp4|webm)$/; +export const BASE_STYLE = + "<style>p,a,pre,h1,h2,h3,ul,blockquote,img,audio,video{display:block;max-width:100%;margin:0;padding:0;overflow-wrap:anywhere;}</style>"; +export const GMI_CSS = fs.readFileSync( + path.resolve(path.dirname(new URL(import.meta.url).pathname), "./gmi.min.css"), "utf8" ); -const toHTML = (exports.toHTML = (file, options) => { - const tokens = JSON.parse(file.contents.toString("utf8")); - const title = tokens[0].h1; - return `<!DOCTYPE html> -<html style="${options.override}"> -${head(file.path, title, options)}<body> -${gemtext(tokens, options)} -</body> -</html> -`; -}); - -module.exports = (options) => (file, cb) => { +export default (options) => (file, cb) => { if (!TOKENS_EXT.test(file.path)) return cb(null); file.contents = Buffer.from(toHTML(file, options)); file.path = file.path.replace(TOKENS_EXT, ".html"); @@ -34,7 +22,19 @@ module.exports = (options) => (file, cb) => { return cb(null, file); }; -function head(file, title, options) { +export function toHTML (file, options) { + const tokens = JSON.parse(file.contents.toString("utf8")); + const title = tokens[0].h1; + return `<!DOCTYPE html> +<html lang="${options.language}" style="${options.override}"> +${head(file.path, title, options)}<body> +${gemtext(tokens, options)} +</body> +</html> +`; +}; + +export function head(file, title, options) { return `<head> <meta charset="utf-8"> <meta language="${options.language}"> @@ -45,14 +45,14 @@ function head(file, title, options) { }${ !options.canonical ? "" - : `<link rel="canonical" href="${ options.canonical }}">` + : `<link rel="canonical" href="${options.canonical}}">` } <title>${title} `; } -function gemtext(tokens, options) { +export function gemtext(tokens, options) { let body = []; let cursor = tokens.shift(); @@ -86,9 +86,8 @@ function line( ) { if (text) return `

${escape(text)}

`; if (href) { - const titleProp = title ? ` title="${title}"` : "" - if (images && IMG_EXT.test(href)) - return ``; + const titleProp = title ? ` title="${title}"` : ""; + if (images && IMG_EXT.test(href)) return ``; if (audio && AUDIO_EXT.test(href)) return ``; if (video && VIDEO_EXT.test(href)) diff --git a/tokenize.js b/tokenize.js index dc6581a..2477b4a 100644 --- a/tokenize.js +++ b/tokenize.js @@ -1,17 +1,14 @@ -const GMI_EXT = /\.gmi$/; -const GMI_REGEX = require("./gmi.regex"); -const tokenize = (exports.tokenize = (file) => +export const GMI_REGEX = /^((=>\s?(?[^\s]+)(\s(?.+))?)|(?<pre>```\s?(?<alt>.+)?)|(###\s?(?<h3>.+))|(##\s?(?<h2>.+))|(#\s?(?<h1>.+))|(\*\s?(?<li>.+))|(>\s?(?<quote>.+))|(?<text>(.+)?))$/; +export const GMI_EXT = /\.gmi$/; +export const tokenize = (gemtext) => JSON.stringify( - file.contents - .toString("utf8") - .split("\n") - .map((line) => GMI_REGEX.exec(line).groups), + gemtext.split("\n").map((line) => GMI_REGEX.exec(line).groups), null, 2 - )); -module.exports = (file, cb) => { + ); +export default (file, cb) => { if (!GMI_EXT.test(file.path)) return cb(null, file); - file.contents = Buffer.from(tokenize(file)); + file.contents = Buffer.from(tokenize(file.contents.toString("utf8"))); file.path = file.path.replace(GMI_EXT, ".tokens.json"); cb(null, file); };