fix lists
add test
This commit is contained in:
parent
1bcedc2042
commit
86e9e8b660
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -2,3 +2,4 @@ node_modules/
|
||||||
capsule/
|
capsule/
|
||||||
gmi.js
|
gmi.js
|
||||||
gmi.min.js
|
gmi.min.js
|
||||||
|
example/test.html
|
||||||
|
|
3
Makefile
3
Makefile
|
@ -14,6 +14,9 @@ format:
|
||||||
./node_modules/prettier/bin-prettier.js --write gmi.css
|
./node_modules/prettier/bin-prettier.js --write gmi.css
|
||||||
./node_modules/prettier/bin-prettier.js --write *.js !*.min.js
|
./node_modules/prettier/bin-prettier.js --write *.js !*.min.js
|
||||||
|
|
||||||
|
example/test.html: example/test.gmi
|
||||||
|
./test.sh
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf gmi.min.* gmi-web.1 node_modules
|
rm -rf gmi.min.* gmi-web.1 node_modules
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,8 @@ The generated HTML document must have a `<head>` tag with _at minimum_ the follo
|
||||||
```html
|
```html
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta language="en" />
|
|
||||||
<!-- set this accordingly! -->
|
<!-- set this accordingly! -->
|
||||||
|
<meta language="en" />
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
</head>
|
</head>
|
||||||
```
|
```
|
||||||
|
@ -84,7 +84,7 @@ Currently approaching a v1 release 🎉 Would you like to help test the RC? _You
|
||||||
Install the binary via npm.
|
Install the binary via npm.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
npm install --global gmi-web-cli@1.0.4-rc.1
|
npm install --global gmi-web-cli
|
||||||
```
|
```
|
||||||
|
|
||||||
Render .html for all the .gmi files in the current directory
|
Render .html for all the .gmi files in the current directory
|
||||||
|
|
42
example/expected.html
Normal file
42
example/expected.html
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html style="">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta language="en">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
|
<meta name="color-scheme" content="dark light">
|
||||||
|
<style>:root{--foreground:black;--background:white;--p-size:1.25rem;--p-indent:0rem;--p-line-height:1.5;--a-size:var(--p-size);--pre-size:1rem;--pre-line-height:1;--h1-size:3rem;--h2-size:2.25rem;--h3-size:1.5rem;--heading-line-height:1.25;--ul-size:var(--p-size);--ul-line-height:1.25;--blockquote-size:var(--p-size);--blockquote-line-height:1.25;--mono:Consolas,monaco,monospace;--serif:georgia,times,serif;--sans-serif:-apple-system,BlinkMacSystemFont,"avenir next",avenir,helvetica,"helvetica neue",ubuntu,roboto,noto,"segoe ui",arial,sans-serif}body{max-width:48rem;padding:.5rem;margin:0 auto}a,audio,blockquote,h1,h2,h3,img,p,pre,ul,video{display:block;max-width:100%;margin:0;padding:0;overflow-wrap:anywhere}h1,h2,h3{font-family:var(--sans-serif);line-height:var(--heading-line-height)}p{font-size:var(--p-size);font-family:var(--serif);text-indent:var(--p-indent);line-height:var(--p-line-height)}a::before{font-size:var(--p-size);font-family:var(--mono);content:"⇒";padding-right:.25rem;vertical-align:middle}a{font-size:var(--p-size);font-family:var(--serif);text-decoration:none}pre{font-size:var(--pre-size);font-family:var(--mono);line-height:var(--pre-line-height);padding:1.25rem;overflow-y:auto}h1{font-size:var(--h1-size)}h2{font-size:var(--h2-size)}h3{font-size:var(--h3-size)}ul{font-size:var(--p-size);font-family:var(--serif);line-height:var(--ul-line-height);list-style-type:none}li::before{font-size:var(--p-size);font-family:var(--mono);content:"*";vertical-align:middle;padding-right:.5rem}blockquote{font-size:var(--p-size);font-family:var(--serif);line-height:var(--blockquote-line-height);padding-left:.75rem}pre+blockquote{padding-top:.5rem;padding-bottom:.5rem}a,blockquote,body,h1,h2,h3,html,p,pre::-moz-selection,pre::selection,ul{color:var(--foreground);background-color:var(--background)}blockquote{border-left:.5rem solid var(--foreground)}::-moz-selection,::selection,a:hover,pre{color:var(--background);background-color:var(--foreground)}@media (prefers-color-scheme:dark){a,blockquote,body,h1,h2,h3,html,p,pre::-moz-selection,pre::selection,ul{color:var(--background);background-color:var(--foreground)}blockquote{border-left:.5rem solid var(--background)}::-moz-selection,::selection,a:hover,pre{color:var(--foreground);background-color:var(--background)}}
|
||||||
|
</style>
|
||||||
|
<title>heading 1</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>heading 1</h1>
|
||||||
|
<h2>heading 2</h2>
|
||||||
|
<h3>heading 3</h3>
|
||||||
|
<p>checkout this empty line:</p>
|
||||||
|
<p><br></p>
|
||||||
|
<ul>
|
||||||
|
<li>and</li>
|
||||||
|
<li>this</li>
|
||||||
|
<li>list</li>
|
||||||
|
</ul>
|
||||||
|
<p><br></p>
|
||||||
|
<blockquote>here's what a blockquote is like</blockquote>
|
||||||
|
<p><br></p>
|
||||||
|
<pre title="pre tags can have alt text">
|
||||||
|
preformatted text
|
||||||
|
means that it already has formatting
|
||||||
|
which means it should show
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
as is
|
||||||
|
</pre>
|
||||||
|
<p><br></p>
|
||||||
|
<p><b>watch out!</b> a gemtext line could have html in it that you'll need to escape!</p>
|
||||||
|
<p><br></p>
|
||||||
|
<img src="https://www.learningcontainer.com/wp-content/uploads/2020/07/Large-Sample-Image-download-for-Testing.jpg" title="JPG image that can render inline!"/>
|
||||||
|
<audio controls src="https://www.learningcontainer.com/wp-content/uploads/2020/02/Kalimba.mp3" title="MP3 audio that can render inline!"></audio>
|
||||||
|
<video controls src="https://www.learningcontainer.com/wp-content/uploads/2020/05/sample-mp4-file.mp4" title="MP4 Video that can render inline!"/></video>
|
||||||
|
</body>
|
||||||
|
</html>
|
26
example/test.gmi
Normal file
26
example/test.gmi
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
# heading 1
|
||||||
|
## heading 2
|
||||||
|
### heading 3
|
||||||
|
checkout this empty line:
|
||||||
|
|
||||||
|
* and
|
||||||
|
* this
|
||||||
|
* list
|
||||||
|
|
||||||
|
> here's what a blockquote is like
|
||||||
|
|
||||||
|
```pre tags can have alt text
|
||||||
|
preformatted text
|
||||||
|
means that it already has formatting
|
||||||
|
which means it should show
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
as is
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>watch out!</b> a gemtext line could have html in it that you'll need to escape!
|
||||||
|
|
||||||
|
=> https://www.learningcontainer.com/wp-content/uploads/2020/07/Large-Sample-Image-download-for-Testing.jpg JPG image that can render inline!
|
||||||
|
=> https://www.learningcontainer.com/wp-content/uploads/2020/02/Kalimba.mp3 MP3 audio that can render inline!
|
||||||
|
=> https://www.learningcontainer.com/wp-content/uploads/2020/05/sample-mp4-file.mp4 MP4 Video that can render inline!
|
9
test.sh
Executable file
9
test.sh
Executable file
|
@ -0,0 +1,9 @@
|
||||||
|
./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"
|
||||||
|
else
|
||||||
|
printf "FAIL: test.html DOES NOT match expected.html!\n"
|
||||||
|
cmp "example/test.html" "example/expected.html"
|
||||||
|
diff "example/test.html" "example/expected.html"
|
||||||
|
exit 1
|
||||||
|
fi
|
22
to-html.js
22
to-html.js
|
@ -9,14 +9,17 @@ const AUDIO_EXT = (exports.AUDIO_EXT = /\.(mp3|wav|aac|aacp|mpeg|off|flac)$/);
|
||||||
const VIDEO_EXT = (exports.VIDEO_EXT = /\.(mp4|webm)$/);
|
const VIDEO_EXT = (exports.VIDEO_EXT = /\.(mp4|webm)$/);
|
||||||
const BASE_STYLE = (exports.BASE_STYLE =
|
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>");
|
"<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"),
|
||||||
|
"utf8"
|
||||||
|
);
|
||||||
|
|
||||||
const toHTML = (exports.toHTML = (file, options) => {
|
const toHTML = (exports.toHTML = (file, options) => {
|
||||||
const tokens = JSON.parse(file.contents.toString("utf8"));
|
const tokens = JSON.parse(file.contents.toString("utf8"));
|
||||||
const title = tokens[0].h1;
|
const title = tokens[0].h1;
|
||||||
return `<!DOCTYPE html>
|
return `<!DOCTYPE html>
|
||||||
<html style="${options.override}">
|
<html style="${options.override}">
|
||||||
${head(file.path, title, options)}
|
${head(file.path, title, options)}<body>
|
||||||
<body>
|
|
||||||
${gemtext(tokens, options)}
|
${gemtext(tokens, options)}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -38,10 +41,7 @@ function head(file, title, options) {
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1">${
|
<meta name="viewport" content="width=device-width,initial-scale=1">${
|
||||||
!options.css
|
!options.css
|
||||||
? BASE_STYLE
|
? BASE_STYLE
|
||||||
: `\n<meta name="color-scheme" content="dark light">\n<style>${fs.readFileSync(
|
: `\n<meta name="color-scheme" content="dark light">\n<style>${GMI_CSS}</style>`
|
||||||
path.resolve(__dirname, "./gmi.min.css"),
|
|
||||||
"utf8"
|
|
||||||
)}</style>`
|
|
||||||
}${
|
}${
|
||||||
!options.canonical
|
!options.canonical
|
||||||
? ""
|
? ""
|
||||||
|
@ -60,7 +60,7 @@ function gemtext(tokens, options) {
|
||||||
let cursor = tokens.shift();
|
let cursor = tokens.shift();
|
||||||
while (tokens.length) {
|
while (tokens.length) {
|
||||||
if (cursor.pre) {
|
if (cursor.pre) {
|
||||||
body.push(`<pre${cursor.alt ? `title="${cursor.alt}"` : ""}>`);
|
body.push(`<pre${cursor.alt ? ` title="${cursor.alt}"` : ""}>`);
|
||||||
const closing = tokens.findIndex((token) => token.pre);
|
const closing = tokens.findIndex((token) => token.pre);
|
||||||
body = body.concat(tokens.slice(0, closing).map(({ text }) => text));
|
body = body.concat(tokens.slice(0, closing).map(({ text }) => text));
|
||||||
body.push("</pre>");
|
body.push("</pre>");
|
||||||
|
@ -68,9 +68,11 @@ function gemtext(tokens, options) {
|
||||||
} else if (cursor.li) {
|
} else if (cursor.li) {
|
||||||
body.push(`<ul>`);
|
body.push(`<ul>`);
|
||||||
const closing = tokens.findIndex((token) => !token.li);
|
const closing = tokens.findIndex((token) => !token.li);
|
||||||
body = body.concat(tokens.slice(0, closing).map(line));
|
body = body
|
||||||
|
.concat([line(cursor)])
|
||||||
|
.concat(tokens.slice(0, closing).map(line));
|
||||||
body.push("</ul>");
|
body.push("</ul>");
|
||||||
tokens = tokens.slice(closing + 1);
|
tokens = tokens.slice(closing);
|
||||||
} else {
|
} else {
|
||||||
body.push(line(cursor, options));
|
body.push(line(cursor, options));
|
||||||
}
|
}
|
||||||
|
@ -82,7 +84,7 @@ function gemtext(tokens, options) {
|
||||||
|
|
||||||
function line(
|
function line(
|
||||||
{ text, href, title, pre, alt, h1, h2, h3, li, quote },
|
{ text, href, title, pre, alt, h1, h2, h3, li, quote },
|
||||||
{ images, audio, video }
|
{ images, audio, video } = {}
|
||||||
) {
|
) {
|
||||||
if (text) return `<p>${escape(text)}</p>`;
|
if (text) return `<p>${escape(text)}</p>`;
|
||||||
if (href) {
|
if (href) {
|
||||||
|
|
Loading…
Reference in a new issue