```\s?(?.+)?)|(###\s?(? .+))|(##\s?(?
.+))|(#\s?(?
.+))|(\*\s?(?
.+))|(>\s?(? .+))|(?(.+)?))$/; + +export function html(file, options) { + const tokens = file.contents + .toString("utf8") + .split("\n") + .map((line) => GMI_REGEX.exec(line).groups); + + if (options.body) return body(tokens, options); + + return ` + +${head( + Object.assign(options, { + title: tokens[0].h1, + charset: "utf-8", + }) + )} +${body(tokens, options)} + +`; +} + +export const BASE_CSS = + "p,a,pre,h1,h2,h3,ul,blockquote,img,audio,video{display:block;max-width:100%;margin:0;padding:0;overflow-wrap:anywhere;}"; + export const GMI_CSS = fs.readFileSync( - path.resolve(path.dirname(new URL(import.meta.url).pathname), "./gmi.min.css"), + // TODO import.meta.resolve is supposed to accomplish this without "path" + path.resolve( + path.dirname(new URL(import.meta.url).pathname), + "./gmi.min.css" + ), "utf8" ); -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"); - if (options.verbose) console.log(file.path); - return cb(null, file); -}; - -export function toHTML (file, options) { - const tokens = JSON.parse(file.contents.toString("utf8")); - const title = tokens[0].h1; - return ` - -${head(file.path, title, options)} -${gemtext(tokens, options)} - - -`; -}; - -export function head(file, title, options) { - return ` - +export function head(options) { + return ` + + -${ + ${options.title} ${ + !options.description + ? "" + : `` + }${ !options.css - ? BASE_STYLE + ? `` : `\n\n` }${ !options.canonical ? "" : `` } -${title} - `; } -export function gemtext(tokens, options) { - let body = []; +export function body(tokens, options) { + let lines = []; let cursor = tokens.shift(); while (tokens.length) { if (cursor.pre) { - body.push(``); + lines.push(`"); tokens = tokens.slice(closing + 1); } else if (cursor.li) { - body.push(``); const closing = tokens.findIndex((token) => token.pre); - body = body.concat(tokens.slice(0, closing).map(({ text }) => text)); - body.push(""); + lines = lines.concat(tokens.slice(0, closing).map(({ text }) => text)); + lines.push("`); + lines.push(`
"); tokens = tokens.slice(closing); } else { - body.push(line(cursor, options)); + lines.push(line(cursor, options)); } cursor = tokens.shift(); } - return body.join("\n"); + return lines.join("\n"); } +export const IMAGE_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)$/; + function line( { text, href, title, pre, alt, h1, h2, h3, li, quote }, { images, audio, video } = {} @@ -87,7 +97,7 @@ function line( if (text) return ``); const closing = tokens.findIndex((token) => !token.li); - body = body + lines = lines .concat([line(cursor)]) .concat(tokens.slice(0, closing).map(line)); - body.push("
"); + lines.push("${escape(text)}
`; if (href) { const titleProp = title ? ` title="${title}"` : ""; - if (images && IMG_EXT.test(href)) return ``; + if (images && IMAGE_EXT.test(href)) return ``; if (audio && AUDIO_EXT.test(href)) return ``; if (video && VIDEO_EXT.test(href)) @@ -102,3 +112,13 @@ function line( if (quote) return `${escape(quote)}`; return ``; } + +export const GMI_EXT = /\.gmi$/; + +export default (options) => (file, cb) => { + if (!GMI_EXT.test(file.path)) return cb(null); + file.contents = Buffer.from(html(file, options)); + file.path = file.path.replace(GMI_EXT, ".html"); + if (options.verbose) console.log(file.path); + return cb(null, file); +}; diff --git a/package-lock.json b/package-lock.json index 08af3a1..134808a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "gmi-web-cli", - "version": "1.0.5-rc.1", + "version": "1.0.7-rc.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/tokenize.js b/tokenize.js deleted file mode 100644 index 2477b4a..0000000 --- a/tokenize.js +++ /dev/null @@ -1,14 +0,0 @@ -export const GMI_REGEX = /^((=>\s?(?
[^\s]+)(\s(? .+))?)|(? ```\s?(?.+)?)|(###\s?(? .+))|(##\s?(?
.+))|(#\s?(?
.+))|(\*\s?(?
.+))|(>\s?(? .+))|(?(.+)?))$/; -export const GMI_EXT = /\.gmi$/; -export const tokenize = (gemtext) => - JSON.stringify( - gemtext.split("\n").map((line) => GMI_REGEX.exec(line).groups), - null, - 2 - ); -export default (file, cb) => { - if (!GMI_EXT.test(file.path)) return cb(null, file); - file.contents = Buffer.from(tokenize(file.contents.toString("utf8"))); - file.path = file.path.replace(GMI_EXT, ".tokens.json"); - cb(null, file); -};