Compare commits
3 Commits
cacfdd3bfd
...
80ece66a0f
Author | SHA1 | Date | |
---|---|---|---|
80ece66a0f | |||
6b3d96b321 | |||
0b373fc57e |
17
bin/build.ts
17
bin/build.ts
|
@ -6,31 +6,32 @@ import { svg } from "../lib/tasks/svg.ts";
|
|||
|
||||
import { argv, exit } from "node:process";
|
||||
|
||||
const wrapTask = (name: string, task: () => Promise<void>) => async () => {
|
||||
type Task = () => Promise<void>;
|
||||
|
||||
const wrapTask = (name: string, task: Task) => async () => {
|
||||
console.log("[start]", name);
|
||||
await task();
|
||||
console.log("[end]", name);
|
||||
};
|
||||
|
||||
const TASKS: { [task: string]: () => Promise<void> } = {
|
||||
const TASKS = new Map<string, Task>(Object.entries({
|
||||
articles: wrapTask("articles", articles),
|
||||
css: wrapTask("css", css),
|
||||
fonts: wrapTask("fonts", fonts),
|
||||
images: wrapTask("images", images),
|
||||
svg: wrapTask("svg", svg),
|
||||
};
|
||||
}));
|
||||
|
||||
const ALL_TASKS = ["fonts", "images", "svg", "css", "articles"];
|
||||
|
||||
const args = argv.slice(2);
|
||||
console.log("args", args);
|
||||
(args.length ? args : ALL_TASKS)
|
||||
await (args.length ? args : ALL_TASKS)
|
||||
.map((task: string) => {
|
||||
if (!TASKS.hasOwnProperty(task)) {
|
||||
if (!TASKS.has(task)) {
|
||||
console.error("Unknown task", task);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return TASKS[task];
|
||||
return TASKS.get(task)!;
|
||||
})
|
||||
.reduce((prev: Promise<void>, cur: () => Promise<void>) => prev.then(cur), Promise.resolve());
|
||||
.reduce((prev: Promise<void>, cur: Task) => prev.then(cur), Promise.resolve());
|
||||
|
|
|
@ -19,9 +19,10 @@
|
|||
"rehype-stringify": "npm:rehype-stringify@^10.0.0",
|
||||
"rxjs": "npm:rxjs@^7.8.1",
|
||||
"tmp": "npm:tmp@^0.2.3",
|
||||
"to-vfile": "https://esm.sh/to-vfile@^8.0.0",
|
||||
"unified": "npm:unified@^11.0.4",
|
||||
"unist-util-visit": "npm:unist-util-visit@^5.0.0",
|
||||
"vinyl": "npm:vinyl@^3.0.0"
|
||||
"vfile": "https://esm.sh/vfile@^6.0.1"
|
||||
},
|
||||
"compilerOptions": {
|
||||
"jsx": "react-jsx",
|
||||
|
|
84
deno.lock
84
deno.lock
|
@ -20,8 +20,7 @@
|
|||
"npm:rxjs@^7.8.1": "npm:rxjs@7.8.1",
|
||||
"npm:tmp@^0.2.3": "npm:tmp@0.2.3",
|
||||
"npm:unified@^11.0.4": "npm:unified@11.0.5",
|
||||
"npm:unist-util-visit@^5.0.0": "npm:unist-util-visit@5.0.0",
|
||||
"npm:vinyl@^3.0.0": "npm:vinyl@3.0.0"
|
||||
"npm:unist-util-visit@^5.0.0": "npm:unist-util-visit@5.0.0"
|
||||
},
|
||||
"npm": {
|
||||
"@csstools/selector-resolve-nested@1.1.0_postcss-selector-parser@6.1.0": {
|
||||
|
@ -122,10 +121,6 @@
|
|||
"picomatch": "picomatch@2.3.1"
|
||||
}
|
||||
},
|
||||
"b4a@1.6.6": {
|
||||
"integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"bail@2.0.2": {
|
||||
"integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==",
|
||||
"dependencies": {}
|
||||
|
@ -134,10 +129,6 @@
|
|||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"bare-events@2.4.2": {
|
||||
"integrity": "sha512-qMKFd2qG/36aA4GwvKq8MxnPgCQAmBWmSyLWsJcbn8v03wvIPQ/hG1Ms8bPzndZxMDoHpxez5VOS+gC9Yi24/Q==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"bcp-47-match@2.0.3": {
|
||||
"integrity": "sha512-JtTezzbAibu8G0R9op9zb3vcWZd9JF6M0xOYGPn0fNCd7wOpRB1mU2mH9T8gaBGbAAyIIVgB2G7xG0GP98zMAQ==",
|
||||
"dependencies": {}
|
||||
|
@ -242,14 +233,6 @@
|
|||
"source-map": "source-map@0.6.1"
|
||||
}
|
||||
},
|
||||
"clone-stats@1.0.0": {
|
||||
"integrity": "sha512-au6ydSpg6nsrigcZ4m8Bc9hxjeW+GJ8xh5G3BJCMt4WXe1H10UNaVOamqQTmrx1kjVuxAHIQSNU6hY4Nsn9/ag==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"clone@2.1.2": {
|
||||
"integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"collapse-white-space@2.1.0": {
|
||||
"integrity": "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==",
|
||||
"dependencies": {}
|
||||
|
@ -454,10 +437,6 @@
|
|||
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"fast-fifo@1.3.2": {
|
||||
"integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"fill-range@7.1.1": {
|
||||
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
|
||||
"dependencies": {
|
||||
|
@ -1204,10 +1183,6 @@
|
|||
"integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"queue-tick@1.0.1": {
|
||||
"integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"read-cache@1.0.0": {
|
||||
"integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
|
||||
"dependencies": {
|
||||
|
@ -1486,14 +1461,6 @@
|
|||
"unified": "unified@11.0.5"
|
||||
}
|
||||
},
|
||||
"remove-trailing-separator@1.1.0": {
|
||||
"integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"replace-ext@2.0.0": {
|
||||
"integrity": "sha512-UszKE5KVK6JvyD92nzMn9cDapSk6w/CaFZ96CnmDMUqH9oowfxF/ZjRITD25H4DnOQClLA4/j7jLGXXLVKxAug==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"resolve@1.22.8": {
|
||||
"integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
|
||||
"dependencies": {
|
||||
|
@ -1538,15 +1505,6 @@
|
|||
"integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"streamx@2.18.0": {
|
||||
"integrity": "sha512-LLUC1TWdjVdn1weXGcSxyTR3T4+acB6tVGXT95y0nGbca4t4o/ng1wKAGTljm9VicuCVLvRlqFYXYy5GwgM7sQ==",
|
||||
"dependencies": {
|
||||
"bare-events": "bare-events@2.4.2",
|
||||
"fast-fifo": "fast-fifo@1.3.2",
|
||||
"queue-tick": "queue-tick@1.0.1",
|
||||
"text-decoder": "text-decoder@1.1.0"
|
||||
}
|
||||
},
|
||||
"string-width@4.2.3": {
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"dependencies": {
|
||||
|
@ -1606,18 +1564,6 @@
|
|||
"picocolors": "picocolors@1.0.1"
|
||||
}
|
||||
},
|
||||
"teex@1.0.1": {
|
||||
"integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==",
|
||||
"dependencies": {
|
||||
"streamx": "streamx@2.18.0"
|
||||
}
|
||||
},
|
||||
"text-decoder@1.1.0": {
|
||||
"integrity": "sha512-TmLJNj6UgX8xcUZo4UDStGQtDiTzF7BzWlzn9g7UWrjkpHr5uJTK1ld16wZ3LXb2vb6jH8qU89dW5whuMdXYdw==",
|
||||
"dependencies": {
|
||||
"b4a": "b4a@1.6.6"
|
||||
}
|
||||
},
|
||||
"tmp@0.2.3": {
|
||||
"integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==",
|
||||
"dependencies": {}
|
||||
|
@ -1742,16 +1688,6 @@
|
|||
"vfile-message": "vfile-message@4.0.2"
|
||||
}
|
||||
},
|
||||
"vinyl@3.0.0": {
|
||||
"integrity": "sha512-rC2VRfAVVCGEgjnxHUnpIVh3AGuk62rP3tqVrn+yab0YH7UULisC085+NYH+mnqf3Wx4SpSi1RQMwudL89N03g==",
|
||||
"dependencies": {
|
||||
"clone": "clone@2.1.2",
|
||||
"clone-stats": "clone-stats@1.0.0",
|
||||
"remove-trailing-separator": "remove-trailing-separator@1.1.0",
|
||||
"replace-ext": "replace-ext@2.0.0",
|
||||
"teex": "teex@1.0.1"
|
||||
}
|
||||
},
|
||||
"web-namespaces@2.0.1": {
|
||||
"integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==",
|
||||
"dependencies": {}
|
||||
|
@ -1789,12 +1725,23 @@
|
|||
}
|
||||
},
|
||||
"redirects": {
|
||||
"https://esm.sh/asciidoctor@^3.0.4": "https://esm.sh/asciidoctor@3.0.4"
|
||||
"https://esm.sh/asciidoctor@^3.0.4": "https://esm.sh/asciidoctor@3.0.4",
|
||||
"https://esm.sh/to-vfile@^8.0.0": "https://esm.sh/to-vfile@8.0.0",
|
||||
"https://esm.sh/vfile@^6.0.1": "https://esm.sh/vfile@6.0.1"
|
||||
},
|
||||
"remote": {
|
||||
"https://esm.sh/asciidoctor@3.0.4": "23f6b6ab844b5295074b6dd139b0153f4b6424df7f41aaa2fcec5004359bb094",
|
||||
"https://esm.sh/to-vfile@8.0.0": "05aa989433514d267833c5057b53935c837c1373824ed8b60ed38cae67655af5",
|
||||
"https://esm.sh/v135/@asciidoctor/core@3.0.4/denonext/core.mjs": "fbb624c9375ac40a70e586d84f6986ff7e8c1ff572e006284a08709e5118bbf7",
|
||||
"https://esm.sh/v135/asciidoctor@3.0.4/denonext/asciidoctor.mjs": "00c21f42422684a4bc5e35647d9495a6631632fdc4c97ddb045a1a3b46d58dba"
|
||||
"https://esm.sh/v135/asciidoctor@3.0.4/denonext/asciidoctor.mjs": "00c21f42422684a4bc5e35647d9495a6631632fdc4c97ddb045a1a3b46d58dba",
|
||||
"https://esm.sh/v135/to-vfile@8.0.0/denonext/to-vfile.mjs": "e9e39c7791eb0ea7055105ffd3eb6ccf3d36a1a4ddf6c5a3824bc3838544ad40",
|
||||
"https://esm.sh/v135/unist-util-stringify-position@4.0.0/denonext/unist-util-stringify-position.mjs": "dabd32cb2b590bbb077fc6f6591a2e065cffd6c55646ba383455926a27ea64d7",
|
||||
"https://esm.sh/v135/vfile-message@4.0.2/denonext/vfile-message.mjs": "efc85b18bedda337fb1c20cdc452fac3addac32ee55948cebf2845396ae641ac",
|
||||
"https://esm.sh/v135/vfile@6.0.1/denonext/do-not-use-conditional-minpath.js": "9a7ca0443aa0dff4d6a74822ba54cd1a5077a75d2f740d4d99cd8897a7f62a3c",
|
||||
"https://esm.sh/v135/vfile@6.0.1/denonext/do-not-use-conditional-minproc.js": "34e683b50c7d1e17a90a522afafcdb032ceaeff2e0eb5dbca28f9b4783de73ba",
|
||||
"https://esm.sh/v135/vfile@6.0.1/denonext/do-not-use-conditional-minurl.js": "79e90ed8915870371874d7ca17f8cbb3a8cab5b4e054bbcff85f7c91df32d0ba",
|
||||
"https://esm.sh/v135/vfile@6.0.1/denonext/vfile.mjs": "31065c960cf79824afc0bc6890688c540f09d067eb5415effb7fafac6ef33c13",
|
||||
"https://esm.sh/vfile@6.0.1": "a28180cc6d7bfad90237eddd9dbc8c840af0bc50e1220bb9b8dc670e96fe49aa"
|
||||
},
|
||||
"workspace": {
|
||||
"dependencies": [
|
||||
|
@ -1817,8 +1764,7 @@
|
|||
"npm:rxjs@^7.8.1",
|
||||
"npm:tmp@^0.2.3",
|
||||
"npm:unified@^11.0.4",
|
||||
"npm:unist-util-visit@^5.0.0",
|
||||
"npm:vinyl@^3.0.0"
|
||||
"npm:unist-util-visit@^5.0.0"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
18
lib/hash.ts
18
lib/hash.ts
|
@ -1,8 +1,8 @@
|
|||
import { createHash } from "node:crypto";
|
||||
import File from "vinyl";
|
||||
import { PRODUCTION } from "./environment.ts";
|
||||
import { Observable } from "rxjs";
|
||||
import { Buffer } from "node:buffer";
|
||||
import { VFile } from "vfile";
|
||||
|
||||
function fileHash(buffer: Buffer) {
|
||||
const hash = createHash("sha256");
|
||||
|
@ -10,22 +10,22 @@ function fileHash(buffer: Buffer) {
|
|||
return hash.digest("hex");
|
||||
}
|
||||
|
||||
const hashPath = (mappings: Map<string, string>) => (file: File): File => {
|
||||
const hash = PRODUCTION ? fileHash(file.contents as Buffer) : "00000000";
|
||||
const hashPath = (mappings: Map<string, string>) => (file: VFile): VFile => {
|
||||
const hash = PRODUCTION ? fileHash(file.value) : "00000000";
|
||||
const newName = [
|
||||
file.basename.substring(0, file.basename.length - file.extname.length),
|
||||
file.stem!,
|
||||
hash.substring(0, 8),
|
||||
file.extname.substring(1),
|
||||
file.extname!.substring(1),
|
||||
].join(".");
|
||||
|
||||
mappings.set(file.basename, newName);
|
||||
mappings.set(file.basename!, newName);
|
||||
file.basename = newName;
|
||||
|
||||
return file;
|
||||
};
|
||||
|
||||
export default function (manifestName: string) {
|
||||
return (observable: Observable<File>): Observable<File> =>
|
||||
return (observable: Observable<VFile>): Observable<VFile> =>
|
||||
new Observable((subscriber) => {
|
||||
const mappings = new Map<string, string>();
|
||||
const hash = hashPath(mappings);
|
||||
|
@ -38,9 +38,9 @@ export default function (manifestName: string) {
|
|||
subscriber.error(e);
|
||||
},
|
||||
complete() {
|
||||
const mappingFile = new File({
|
||||
const mappingFile = new VFile({
|
||||
path: manifestName,
|
||||
contents: Buffer.from(JSON.stringify(Object.fromEntries(mappings))),
|
||||
value: JSON.stringify(Object.fromEntries(mappings)),
|
||||
});
|
||||
|
||||
subscriber.next(mappingFile);
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
import { from, mergeMap, Observable, Subscriber } from "rxjs";
|
||||
import File from "vinyl";
|
||||
import { readFile } from "node:fs/promises";
|
||||
import { dirname, join } from "node:path";
|
||||
import { existsSync } from "node:fs";
|
||||
import { mkdir, writeFile } from "node:fs/promises";
|
||||
import { Glob } from "glob";
|
||||
import { VFile } from "vfile";
|
||||
import { read } from "to-vfile";
|
||||
|
||||
export function dest(prefix: string) {
|
||||
return async (file: File) => {
|
||||
return async (file: VFile) => {
|
||||
const actualPath = join(prefix, file.path);
|
||||
if (!existsSync(dirname(actualPath))) {
|
||||
await mkdir(dirname(actualPath), { recursive: true });
|
||||
}
|
||||
await writeFile(actualPath, file.contents as Buffer);
|
||||
await writeFile(actualPath, file.value);
|
||||
console.log("[-] Written", actualPath);
|
||||
|
||||
return file;
|
||||
|
@ -37,7 +37,11 @@ export function onComplete<T>(f: (sink: Subscriber<T>) => Promise<void>) {
|
|||
);
|
||||
}
|
||||
|
||||
const loadFile = async (path: string): Promise<File> => new File({ path, contents: await readFile(path) });
|
||||
const loadFile = (path: string): Promise<VFile> =>
|
||||
read(join(Deno.cwd(), path)).then((vfile) => {
|
||||
vfile.path = path;
|
||||
return vfile;
|
||||
});
|
||||
|
||||
export const fromGlob = (paths: string | string[]): Observable<File> =>
|
||||
export const fromGlob = (paths: string | string[]): Observable<VFile> =>
|
||||
from(new Glob(paths, {})).pipe(mergeMap(loadFile));
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
import { readFileSync } from "node:fs";
|
||||
import { basename, dirname, join } from "node:path";
|
||||
import asciidoctor from "asciidoctor";
|
||||
import File from "vinyl";
|
||||
import { DateTime } from "luxon";
|
||||
import { unified } from "unified";
|
||||
import rehypeParse from "rehype-parse";
|
||||
|
@ -20,7 +18,11 @@ import { JSX } from "preact/jsx-runtime";
|
|||
import { reloadAssets } from "../assets.ts";
|
||||
import { lastValueFrom, mergeMap, Observable, Subscriber } from "rxjs";
|
||||
import { dest, fromGlob, onComplete } from "../rx-utils.ts";
|
||||
import { Buffer } from "node:buffer";
|
||||
import { VFile } from "vfile";
|
||||
|
||||
const encoder = new TextEncoder();
|
||||
const decoder = new TextDecoder();
|
||||
const DOCTYPE = encoder.encode("<!doctype html>");
|
||||
|
||||
const Asciidoctor = asciidoctor();
|
||||
const EXTENSION_REGISTRY = Asciidoctor.Extensions.create();
|
||||
|
@ -34,7 +36,7 @@ EXTENSION_REGISTRY.inlineMacro("abbr", function () {
|
|||
});
|
||||
});
|
||||
|
||||
function extractImages(sink: (image: File) => void, articlePath: string) {
|
||||
function extractImages(sink: Subscriber<VFile>, articlePath: string) {
|
||||
return function () {
|
||||
return function (tree: any) {
|
||||
visit(tree, "element", function (node: any) {
|
||||
|
@ -43,24 +45,30 @@ function extractImages(sink: (image: File) => void, articlePath: string) {
|
|||
}
|
||||
|
||||
const imagePath = join(dirname(articlePath));
|
||||
const image = new File({
|
||||
const image = new VFile({
|
||||
path: join(basename(articlePath, ".asciidoc"), node.properties.src),
|
||||
contents: readFileSync(imagePath),
|
||||
value: Deno.readFileSync(imagePath),
|
||||
});
|
||||
|
||||
sink(image);
|
||||
sink.next(image);
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
function renderDocument(root: JSX.Element): Buffer {
|
||||
return Buffer.concat([Buffer.from("<!doctype html>"), Buffer.from(renderToStaticMarkup(root))]);
|
||||
function renderDocument(root: JSX.Element): Uint8Array {
|
||||
const result = encoder.encode(renderToStaticMarkup(root));
|
||||
const dest = new Uint8Array(DOCTYPE.length + result.length);
|
||||
|
||||
dest.set(DOCTYPE);
|
||||
dest.set(result, DOCTYPE.length);
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
const transformArticle = (sink: (file: File) => void, articles: Article[]) => async (file: File) => {
|
||||
const transformArticle = (sink: Subscriber<VFile>, articles: Article[]) => async (file: VFile) => {
|
||||
const slug = basename(file.path, ".asciidoc");
|
||||
const document = Asciidoctor.load(file.contents!.toString(), {
|
||||
const document = Asciidoctor.load(decoder.decode(file.value as Uint8Array), {
|
||||
extension_registry: EXTENSION_REGISTRY,
|
||||
});
|
||||
const date = DateTime.fromISO(document.getAttribute("docdate", { zone: "UTC" }));
|
||||
|
@ -94,13 +102,13 @@ const transformArticle = (sink: (file: File) => void, articles: Article[]) => as
|
|||
});
|
||||
|
||||
file.path = join(slug, "index.html");
|
||||
file.contents = renderDocument(content);
|
||||
file.value = renderDocument(content);
|
||||
|
||||
articles.push(article);
|
||||
sink(file);
|
||||
sink.next(file);
|
||||
};
|
||||
|
||||
const finalizeArticles = (articles: Article[]) => (sink: Subscriber<File>) => {
|
||||
const finalizeArticles = (articles: Article[]) => (sink: Subscriber<VFile>) => {
|
||||
articles.sort(({ date: a }, { date: b }) => b.diff(a).toMillis());
|
||||
const contents = renderLayout({
|
||||
meta: {
|
||||
|
@ -112,7 +120,7 @@ const finalizeArticles = (articles: Article[]) => (sink: Subscriber<File>) => {
|
|||
Content: () => renderIndex({ articles }),
|
||||
});
|
||||
|
||||
sink.next(new File({ path: "index.html", contents: renderDocument(contents) }));
|
||||
sink.next(new VFile({ path: "index.html", value: renderDocument(contents) }));
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
|
@ -124,9 +132,9 @@ export const articles = async () => {
|
|||
fromGlob("articles/**/*.asciidoc").pipe(
|
||||
mergeMap(
|
||||
(file) =>
|
||||
new Observable<File>((subscriber) => {
|
||||
new Observable<VFile>((subscriber) => {
|
||||
transformArticle(
|
||||
(f) => subscriber.next(f),
|
||||
subscriber,
|
||||
articles,
|
||||
)(file).then(() => subscriber.complete());
|
||||
}),
|
||||
|
|
|
@ -3,19 +3,20 @@ import config from "../../postcss.config.ts";
|
|||
import { dest, fromGlob } from "../rx-utils.ts";
|
||||
import { lastValueFrom, mergeMap } from "rxjs";
|
||||
import hashPaths from "../hash.ts";
|
||||
import File from "vinyl";
|
||||
import { Buffer } from "node:buffer";
|
||||
import { VFile } from "vfile";
|
||||
|
||||
export const css = async () => {
|
||||
await lastValueFrom(
|
||||
fromGlob("src/index.css").pipe(
|
||||
mergeMap(
|
||||
(file) =>
|
||||
new Promise<File>((resolve) =>
|
||||
new Promise<VFile>((resolve) =>
|
||||
postcss(config.plugins)
|
||||
.process(file.contents, { from: file.path })
|
||||
.process(file.value, { from: file.path })
|
||||
.then((result: Result) => {
|
||||
file.contents = Buffer.from(result.css);
|
||||
const encoder = new TextEncoder();
|
||||
|
||||
file.value = encoder.encode(result.css);
|
||||
file.path = "index.css";
|
||||
|
||||
resolve(file);
|
||||
|
|
|
@ -1,39 +1,33 @@
|
|||
import File from "vinyl";
|
||||
import tmp from "tmp";
|
||||
import { execFile } from "node:child_process";
|
||||
import { readFileSync, unlinkSync } from "node:fs";
|
||||
import hashPaths from "../hash.ts";
|
||||
import { dest, fromGlob } from "../rx-utils.ts";
|
||||
import { mergeMap } from "rxjs";
|
||||
import { lastValueFrom, mergeMap } from "rxjs";
|
||||
import { VFile } from "vfile";
|
||||
|
||||
const FONT_PRESETS: { [variant: string]: { ranges: string[] } } = {
|
||||
mono: { ranges: ["20-7F", "2205", "2E22-2E25", "2713", "2717"] },
|
||||
text: { ranges: ["20-7F", "A0-FF", "2000-206F", "20AC"] },
|
||||
};
|
||||
|
||||
function compileFont(font: File): Promise<File> {
|
||||
const [, variant, weight] = /([A-Z][a-z]+)-(\w+)\.ttf$/.exec(font.basename) as string[];
|
||||
async function compileFont(font: VFile): Promise<VFile> {
|
||||
const [, variant, weight] = /([A-Z][a-z]+)-(\w+)\.ttf$/.exec(font.basename!) as string[];
|
||||
const tmpOutput = tmp.fileSync({ discardDescriptor: true });
|
||||
const unicodes = FONT_PRESETS[variant.toLowerCase()].ranges;
|
||||
|
||||
return new Promise((resolve) => {
|
||||
execFile("pyftsubset", [
|
||||
font.path,
|
||||
`--unicodes=${unicodes.join(",")}`,
|
||||
`--output-file=${tmpOutput.name}`,
|
||||
"--flavor=woff2",
|
||||
]).once("exit", () => {
|
||||
font.path = `iosevka-adaedra-${variant.toLowerCase()}-${weight.toLowerCase()}.woff2`;
|
||||
font.contents = readFileSync(tmpOutput.name);
|
||||
(font as any).base = null;
|
||||
await new Deno.Command("pyftsubset", {
|
||||
args: [font.path, `--unicodes=${unicodes.join(",")}`, `--output-file=${tmpOutput.name}`, "--flavor=woff2"],
|
||||
}).output();
|
||||
|
||||
unlinkSync(tmpOutput.name);
|
||||
resolve(font);
|
||||
});
|
||||
});
|
||||
font.path = `iosevka-adaedra-${variant.toLowerCase()}-${weight.toLowerCase()}.woff2`;
|
||||
font.value = await Deno.readFile(tmpOutput.name);
|
||||
|
||||
await Deno.remove(tmpOutput.name);
|
||||
return font;
|
||||
}
|
||||
|
||||
export const fonts = () =>
|
||||
export const fonts = async () => {
|
||||
await lastValueFrom(
|
||||
fromGlob("vendor/*.ttf")
|
||||
.pipe(mergeMap(compileFont), hashPaths("fonts.manifest"))
|
||||
.forEach(dest("dist/_assets"));
|
||||
.pipe(mergeMap(compileFont), hashPaths("fonts.manifest"), mergeMap(dest("dist/_assets"))),
|
||||
);
|
||||
};
|
||||
|
|
|
@ -5,7 +5,7 @@ import { tap } from "rxjs";
|
|||
export const images = () =>
|
||||
fromGlob("src/*.avif")
|
||||
.pipe(
|
||||
tap((f) => (f.path = f.path.substring(4))),
|
||||
tap((f) => (f.path = f.basename!)),
|
||||
hashPaths("images.manifest"),
|
||||
)
|
||||
.forEach(dest("dist/_assets"));
|
||||
|
|
|
@ -4,5 +4,5 @@ import { dest, fromGlob } from "../rx-utils.ts";
|
|||
// SVG `use` has no way of allowing cross-origin, so we need to keep them with the HTML files.
|
||||
export const svg = () =>
|
||||
fromGlob("src/*.svg")
|
||||
.pipe(tap((f) => (f.path = f.path.substring(4))))
|
||||
.pipe(tap((f) => (f.path = f.basename!)))
|
||||
.forEach(dest("dist"));
|
||||
|
|
Loading…
Reference in New Issue
Block a user