Compare commits
2 commits
647f77b266
...
3aaceb9080
Author | SHA1 | Date | |
---|---|---|---|
3aaceb9080 | |||
60c0a04fc9 |
4 changed files with 134 additions and 23 deletions
134
compilar.ts
134
compilar.ts
|
@ -19,6 +19,10 @@ import {
|
||||||
ul,
|
ul,
|
||||||
h2,
|
h2,
|
||||||
raw,
|
raw,
|
||||||
|
p,
|
||||||
|
VirtualElement,
|
||||||
|
time,
|
||||||
|
article,
|
||||||
} from "@nulo/html.js";
|
} from "@nulo/html.js";
|
||||||
|
|
||||||
const execFile = promisify(execFileCallback);
|
const execFile = promisify(execFileCallback);
|
||||||
|
@ -26,6 +30,13 @@ const execFile = promisify(execFileCallback);
|
||||||
const reader = new commonmark.Parser({ smart: true });
|
const reader = new commonmark.Parser({ smart: true });
|
||||||
const writer = new commonmark.HtmlRenderer({ safe: false, smart: true });
|
const writer = new commonmark.HtmlRenderer({ safe: false, smart: true });
|
||||||
|
|
||||||
|
const dateFormatter = new Intl.DateTimeFormat("es-AR", {
|
||||||
|
weekday: "long",
|
||||||
|
day: "numeric",
|
||||||
|
month: "long",
|
||||||
|
year: "numeric",
|
||||||
|
});
|
||||||
|
|
||||||
const wikilinkExp = /\[\[(.+?)\]\]/giu;
|
const wikilinkExp = /\[\[(.+?)\]\]/giu;
|
||||||
|
|
||||||
const compilers: {
|
const compilers: {
|
||||||
|
@ -85,18 +96,21 @@ async function compileFile(name: string) {
|
||||||
async function compilePage(config: Config, sourceFileName: string) {
|
async function compilePage(config: Config, sourceFileName: string) {
|
||||||
const name = basename(sourceFileName, extname(sourceFileName));
|
const name = basename(sourceFileName, extname(sourceFileName));
|
||||||
const isIndex = name === "index";
|
const isIndex = name === "index";
|
||||||
const title = isIndex ? "nulo.in" : name;
|
const title = isIndex ? "nulo.in" : formatNameToPlainText(name);
|
||||||
const fileConnections = connections.filter(({ linked }) => linked === name);
|
const fileConnections = connections.filter(({ linked }) => linked === name);
|
||||||
|
|
||||||
const contentHtml = await compileContentHtml(config, sourceFileName);
|
const contentHtml = await compileContentHtml(config, sourceFileName);
|
||||||
|
|
||||||
const html = render(
|
const html = render(
|
||||||
...generateHead(title, name),
|
...generateHead(title, name),
|
||||||
|
article(
|
||||||
|
{ itemscope: "", itemtype: "https://schema.org/CreativeWork" },
|
||||||
...(isIndex
|
...(isIndex
|
||||||
? []
|
? []
|
||||||
: generateHeader(title, sourceFileName, fileConnections.length > 0)),
|
: generateHeader(name, sourceFileName, fileConnections.length > 0)),
|
||||||
raw(contentHtml),
|
raw(contentHtml),
|
||||||
...generateConnectionsSection(fileConnections)
|
...generateConnectionsSection(fileConnections)
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
const outputPath = join(config.buildPath, name + ".html");
|
const outputPath = join(config.buildPath, name + ".html");
|
||||||
|
@ -185,15 +199,112 @@ function generateHead(titlee: string, outputName: string): Renderable[] {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function formatDate(dateish: Dateish, upper: boolean = false): string {
|
||||||
|
const date = new Date(dateish.year, dateish.month - 1, dateish.day);
|
||||||
|
const formatted = dateFormatter.format(date);
|
||||||
|
if (upper) {
|
||||||
|
// no le digan a la policía del unicode!
|
||||||
|
return formatted[0].toUpperCase() + formatted.slice(1);
|
||||||
|
} else return formatted;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Dateish {
|
||||||
|
year: number;
|
||||||
|
month: number;
|
||||||
|
day: number;
|
||||||
|
}
|
||||||
|
function dateishToString({ year, month, day }: Dateish): string {
|
||||||
|
return `${year}-${String(month).padStart(2, "0")}-${String(day).padStart(
|
||||||
|
2,
|
||||||
|
"0"
|
||||||
|
)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
type TitleMetadata =
|
||||||
|
| {
|
||||||
|
// title puede tener length == 0 y por lo tanto ser falseish
|
||||||
|
title: string;
|
||||||
|
date?: Dateish;
|
||||||
|
}
|
||||||
|
| { date: Dateish };
|
||||||
|
function parseName(name: string): TitleMetadata {
|
||||||
|
const titleWithDate =
|
||||||
|
/^((?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2}))? ?(?<title>.*)$/;
|
||||||
|
|
||||||
|
const found = name.match(titleWithDate);
|
||||||
|
if (!found || !found.groups) throw new Error("Algo raro pasó");
|
||||||
|
const { title } = found.groups;
|
||||||
|
|
||||||
|
const date =
|
||||||
|
(found.groups.year && {
|
||||||
|
year: parseInt(found.groups.year),
|
||||||
|
month: parseInt(found.groups.month),
|
||||||
|
day: parseInt(found.groups.day),
|
||||||
|
}) ||
|
||||||
|
undefined;
|
||||||
|
// no definir title si es length == 0
|
||||||
|
if (!title && date) return { date };
|
||||||
|
return { title, date };
|
||||||
|
}
|
||||||
|
|
||||||
|
function dateishToElement(
|
||||||
|
dateish: Dateish,
|
||||||
|
{ itemprop, upper }: { itemprop?: string; upper?: boolean } = {}
|
||||||
|
): VirtualElement {
|
||||||
|
return time(
|
||||||
|
{ datetime: dateishToString(dateish), ...(itemprop ? { itemprop } : {}) },
|
||||||
|
formatDate(dateish, upper)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatNameToInline(name: string): Renderable[] {
|
||||||
|
const parsed = parseName(name);
|
||||||
|
if ("title" in parsed) {
|
||||||
|
const { title, date } = parsed;
|
||||||
|
return [title, ...(date ? [` (`, dateishToElement(date), `)`] : [])];
|
||||||
|
} else {
|
||||||
|
return [dateishToElement(parsed.date, { upper: true })];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function formatNameToPlainText(name: string): string {
|
||||||
|
const parsed = parseName(name);
|
||||||
|
if ("title" in parsed) {
|
||||||
|
const { title, date } = parsed;
|
||||||
|
return title + (date ? ` (${formatDate(date)})` : "");
|
||||||
|
} else {
|
||||||
|
return formatDate(parsed.date, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function generateHeader(
|
function generateHeader(
|
||||||
title: string,
|
name: string,
|
||||||
sourceCodePath: string,
|
sourceCodePath: string,
|
||||||
linkConexiones = false
|
linkConexiones = false
|
||||||
): Renderable[] {
|
): Renderable[] {
|
||||||
|
const parsedTitle = parseName(name);
|
||||||
return [
|
return [
|
||||||
a({ href: "." }, "☚ Volver al inicio"),
|
a({ href: "." }, "☚ Volver al inicio"),
|
||||||
header(
|
header(
|
||||||
h1(title),
|
...("title" in parsedTitle
|
||||||
|
? [
|
||||||
|
h1(parsedTitle.title),
|
||||||
|
...(parsedTitle.date
|
||||||
|
? [
|
||||||
|
dateishToElement(parsedTitle.date, {
|
||||||
|
itemprop: "datePublished",
|
||||||
|
}),
|
||||||
|
" / ",
|
||||||
|
]
|
||||||
|
: []),
|
||||||
|
]
|
||||||
|
: [
|
||||||
|
h1(
|
||||||
|
dateishToElement(parsedTitle.date, {
|
||||||
|
itemprop: "datePublished",
|
||||||
|
upper: true,
|
||||||
|
})
|
||||||
|
),
|
||||||
|
]),
|
||||||
a(
|
a(
|
||||||
{
|
{
|
||||||
href: `https://gitea.nulo.in/Nulo/sitio/commits/branch/ANTIFASCISTA/${sourceCodePath}`,
|
href: `https://gitea.nulo.in/Nulo/sitio/commits/branch/ANTIFASCISTA/${sourceCodePath}`,
|
||||||
|
@ -215,11 +326,7 @@ function generateConnectionsSection(
|
||||||
section(
|
section(
|
||||||
{ id: "conexiones" },
|
{ id: "conexiones" },
|
||||||
h2(`⥆ Conexiones (${fileConnections.length})`),
|
h2(`⥆ Conexiones (${fileConnections.length})`),
|
||||||
ul(
|
ul(...fileConnections.map(({ linker }) => li(internalLink(linker))))
|
||||||
...fileConnections.map(({ linker }) =>
|
|
||||||
li(a({ href: internalLink(linker) }, linker))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
: [];
|
: [];
|
||||||
|
@ -234,7 +341,7 @@ async function compilePageList(config: Config, pageList: string[]) {
|
||||||
ul(
|
ul(
|
||||||
...pageList
|
...pageList
|
||||||
.sort((a, b) => a.localeCompare(b, "es", { sensitivity: "base" }))
|
.sort((a, b) => a.localeCompare(b, "es", { sensitivity: "base" }))
|
||||||
.map((name) => li(a({ href: internalLink(name) }, name)))
|
.map((name) => li(internalLink(name)))
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
await writeFile(outputPath, html);
|
await writeFile(outputPath, html);
|
||||||
|
@ -277,7 +384,7 @@ function renderMarkdown(markdown: string) {
|
||||||
async function hackilyTransformHtml(html: string): Promise<string> {
|
async function hackilyTransformHtml(html: string): Promise<string> {
|
||||||
html = html
|
html = html
|
||||||
.replaceAll("<a h", '<a rel="noopener noreferrer" h')
|
.replaceAll("<a h", '<a rel="noopener noreferrer" h')
|
||||||
.replaceAll(wikilinkExp, (_, l) => render(a({ href: internalLink(l) }, l)));
|
.replaceAll(wikilinkExp, (_, l) => render(internalLink(l)));
|
||||||
for (const [match, archivo] of html.matchAll(
|
for (const [match, archivo] of html.matchAll(
|
||||||
/<nulo-sitio-reemplazar-con archivo="(.+?)" \/>/g
|
/<nulo-sitio-reemplazar-con archivo="(.+?)" \/>/g
|
||||||
)) {
|
)) {
|
||||||
|
@ -290,6 +397,7 @@ async function hackilyTransformHtml(html: string): Promise<string> {
|
||||||
// Linking
|
// Linking
|
||||||
// ==============================================
|
// ==============================================
|
||||||
|
|
||||||
function internalLink(path: string) {
|
function internalLink(path: string): VirtualElement {
|
||||||
return encodeURI(`./${path}.html`);
|
const href = encodeURI(`./${path}.html`);
|
||||||
|
return a({ href }, ...formatNameToInline(path));
|
||||||
}
|
}
|
||||||
|
|
5
drip.css
5
drip.css
|
@ -15,10 +15,13 @@ body {
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
header {
|
article header {
|
||||||
margin: 2rem 0;
|
margin: 2rem 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
article h1 {
|
||||||
|
font-size: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
border-bottom: var(--foreground) solid 1px;
|
border-bottom: var(--foreground) solid 1px;
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
"typescript": "^4.9.4"
|
"typescript": "^4.9.4"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nulo/html.js": "^0.0.7",
|
"@nulo/html.js": "^0.0.8",
|
||||||
"commonmark": "^0.30.0"
|
"commonmark": "^0.30.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
lockfileVersion: 5.4
|
lockfileVersion: 5.4
|
||||||
|
|
||||||
specifiers:
|
specifiers:
|
||||||
'@nulo/html.js': ^0.0.7
|
'@nulo/html.js': ^0.0.8
|
||||||
'@types/commonmark': ^0.27.5
|
'@types/commonmark': ^0.27.5
|
||||||
'@types/node': ^18.11.18
|
'@types/node': ^18.11.18
|
||||||
commonmark: ^0.30.0
|
commonmark: ^0.30.0
|
||||||
|
@ -9,7 +9,7 @@ specifiers:
|
||||||
typescript: ^4.9.4
|
typescript: ^4.9.4
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
'@nulo/html.js': 0.0.7
|
'@nulo/html.js': 0.0.8
|
||||||
commonmark: 0.30.0
|
commonmark: 0.30.0
|
||||||
|
|
||||||
devDependencies:
|
devDependencies:
|
||||||
|
@ -218,8 +218,8 @@ packages:
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@nulo/html.js/0.0.7:
|
/@nulo/html.js/0.0.8:
|
||||||
resolution: {integrity: sha512-4xzxbrovLRlS36RrQx9AtEc6OQZSIOK1cWuda7AYQFv3aQSkGAIuEgJK3FvvtgHMIi9AOcQuD/T9c9VpK4NAkA==, tarball: https://gitea.nulo.in/api/packages/Nulo/npm/%40nulo%2Fhtml.js/-/0.0.7/html.js-0.0.7.tgz}
|
resolution: {integrity: sha512-fi2VrrdTx2ivWPyUuZpnuBxelGoxWzbvyo/iki222AfYlPa9/xMwAXz+9q8vdtHOP5/3E/z30YDp+Sq5TkRZhg==, tarball: https://gitea.nulo.in/api/packages/Nulo/npm/%40nulo%2Fhtml.js/-/0.0.8/html.js-0.0.8.tgz}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@types/commonmark/0.27.5:
|
/@types/commonmark/0.27.5:
|
||||||
|
|
Reference in a new issue