add content type library
This commit is contained in:
parent
7242c6eb89
commit
46a67453a1
12 changed files with 153 additions and 40 deletions
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"lint": {
|
"lint": {
|
||||||
"exclude": ["framework/meta"], // OLD
|
"exclude": ["src"], // OLD
|
||||||
"rules": {
|
"rules": {
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"no-explicit-any" // TODO
|
"no-explicit-any" // TODO
|
||||||
|
|
|
@ -97,3 +97,4 @@ import * as fs from "./fs.ts";
|
||||||
import type { Context, Next } from "hono";
|
import type { Context, Next } from "hono";
|
||||||
import type { StatusCode } from "hono/utils/http-status";
|
import type { StatusCode } from "hono/utils/http-status";
|
||||||
import type { BuiltAsset, BuiltAssetMap, View } from "./incremental.ts";
|
import type { BuiltAsset, BuiltAssetMap, View } from "./incremental.ts";
|
||||||
|
import { Buffer } from "node:buffer";
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
// This file implements client-side bundling, mostly wrapping esbuild.
|
// This file implements client-side bundling, mostly wrapping esbuild.
|
||||||
import process from "node:process";
|
|
||||||
const plugins: esbuild.Plugin[] = [
|
const plugins: esbuild.Plugin[] = [
|
||||||
// There are currently no plugins needed by 'paperclover.net'
|
// There are currently no plugins needed by 'paperclover.net'
|
||||||
];
|
];
|
||||||
|
@ -80,6 +79,7 @@ export async function bundleClientJavaScript(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
import * as path from "node:path";
|
|
||||||
import * as esbuild from "esbuild";
|
import * as esbuild from "esbuild";
|
||||||
|
import * as path from "node:path";
|
||||||
|
import process from "node:process";
|
||||||
import { Incremental } from "./incremental.ts";
|
import { Incremental } from "./incremental.ts";
|
||||||
|
|
|
@ -35,7 +35,7 @@ declare global {
|
||||||
[name: string]: Record<string, unknown>;
|
[name: string]: Record<string, unknown>;
|
||||||
}
|
}
|
||||||
interface ElementChildrenAttribute {
|
interface ElementChildrenAttribute {
|
||||||
children: {};
|
children: unknown;
|
||||||
}
|
}
|
||||||
type Element = engine.Node;
|
type Element = engine.Node;
|
||||||
type ElementType = keyof IntrinsicElements | engine.Component;
|
type ElementType = keyof IntrinsicElements | engine.Component;
|
||||||
|
|
|
@ -157,11 +157,13 @@ function loadMarko(module: NodeJS.Module, filepath: string) {
|
||||||
// bare client import statements to it's own usage.
|
// bare client import statements to it's own usage.
|
||||||
if (src.match(/^\s*client\s+import\s+["']/m)) {
|
if (src.match(/^\s*client\s+import\s+["']/m)) {
|
||||||
src = src.replace(
|
src = src.replace(
|
||||||
/^\s*client\s+import\s+("[^"]+|'[^']+)[^\n]+/m,
|
/^\s*client\s+import\s+("[^"]+"|'[^']+')[^\n]+/m,
|
||||||
"<CloverScriptInclude src=$1 />",
|
"<CloverScriptInclude src=$1 />",
|
||||||
) + '\nimport { Script as CloverScriptInclude } from "#sitegen";';
|
) + '\nimport { Script as CloverScriptInclude } from "#sitegen";\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log(src);
|
||||||
|
console.log("---");
|
||||||
src = marko.compileSync(src, filepath).code;
|
src = marko.compileSync(src, filepath).code;
|
||||||
src = src.replace("marko/debug/html", "#ssr/marko");
|
src = src.replace("marko/debug/html", "#ssr/marko");
|
||||||
return loadEsbuildCode(module, filepath, src);
|
return loadEsbuildCode(module, filepath, src);
|
||||||
|
|
|
@ -1,29 +1,30 @@
|
||||||
const db = new Map(
|
const entries = fs.readFileSync(
|
||||||
fs.readFileSync(path.join(import.meta.dirname, "mime.txt"), "utf8")
|
path.join(import.meta.dirname, "mime.txt"),
|
||||||
.split("\n").filter(Boolean).map((line) =>
|
"utf8",
|
||||||
line.split(/\s+/) as [string, string]
|
)
|
||||||
),
|
.split("\n")
|
||||||
);
|
.map((line) => line.trim())
|
||||||
|
.filter((line) => line && !line.startsWith("#"))
|
||||||
|
.map((line) => line.split(/\s+/, 2) as [string, string]);
|
||||||
|
const extensions = new Map(entries.filter((x) => x[0].startsWith(".")));
|
||||||
|
const fullNames = new Map(entries.filter((x) => !x[0].startsWith(".")));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Accepts:
|
* Accepts:
|
||||||
* - Full file path
|
* - Full file path or basename
|
||||||
* - Extension (with or without dot)
|
* - Extension (with or without dot)
|
||||||
*/
|
*/
|
||||||
export function contentTypeFor(file: string) {
|
export function contentTypeFor(file: string) {
|
||||||
if (file.includes("/") || file.includes("\\")) {
|
const slash = file.indexOf("/");
|
||||||
// Some file names are special cased.
|
if (slash !== -1) file = file.slice(slash + 1);
|
||||||
switch (path.basename(file)) {
|
|
||||||
case "rss.xml":
|
|
||||||
return "application/rss+xml";
|
|
||||||
}
|
|
||||||
|
|
||||||
file = path.extname(file);
|
|
||||||
}
|
|
||||||
const dot = file.indexOf(".");
|
const dot = file.indexOf(".");
|
||||||
if (dot === -1) file = "." + file;
|
if (dot === -1) file = "." + file;
|
||||||
else if (dot > 0) file = file.slice(dot);
|
else if (dot > 0) {
|
||||||
return db.get(file) ?? "application/octet-stream";
|
let entry = fullNames.get(file);
|
||||||
|
if (entry) return entry;
|
||||||
|
file = file.slice(dot);
|
||||||
|
}
|
||||||
|
return extensions.get(file) ?? "application/octet-stream";
|
||||||
}
|
}
|
||||||
|
|
||||||
import * as fs from "./fs.ts";
|
import * as fs from "./fs.ts";
|
||||||
|
|
99
framework/mime.txt
Normal file
99
framework/mime.txt
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
# media types
|
||||||
|
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/MIME_types
|
||||||
|
.aac audio/x-aac
|
||||||
|
.aif audio/x-aiff
|
||||||
|
.aifc audio/x-aiff
|
||||||
|
.aiff audio/x-aiff
|
||||||
|
.asm text/x-asm
|
||||||
|
.avi video/x-msvideo
|
||||||
|
.bat application/x-msdownload
|
||||||
|
.c text/x-c
|
||||||
|
.chat text/x-clover-chatlog
|
||||||
|
.class application/java-vm
|
||||||
|
.cmd application/x-msdownload
|
||||||
|
.com application/x-msdownload
|
||||||
|
.conf text/plain
|
||||||
|
.cpp text/x-c
|
||||||
|
.css text/css
|
||||||
|
.csv text/csv
|
||||||
|
.cxx text/x-c
|
||||||
|
.def text/plain
|
||||||
|
.diff text/plain
|
||||||
|
.dll application/x-msdownload
|
||||||
|
.dmg application/octet-stream
|
||||||
|
.doc application/msword
|
||||||
|
.docx application/vnd.openxmlformats-officedocument.wordprocessingml.document
|
||||||
|
.epub application/epub+zip
|
||||||
|
.exe application/x-msdownload
|
||||||
|
.flv video/x-flv
|
||||||
|
.fbx application/fbx
|
||||||
|
.gz application/x-gzip
|
||||||
|
.h text/x-c
|
||||||
|
.h264 video/h264
|
||||||
|
.hh text/x-c
|
||||||
|
.htm text/html;charset=utf-8
|
||||||
|
.html text/html;charset=utf-8
|
||||||
|
.ico image/x-icon
|
||||||
|
.ics text/calendar
|
||||||
|
.in text/plain
|
||||||
|
.jar application/java-archive
|
||||||
|
.java text/x-java-source
|
||||||
|
.jpeg image/jpeg
|
||||||
|
.jpg image/jpeg
|
||||||
|
.jpgv video/jpeg
|
||||||
|
.jxl image/jxl
|
||||||
|
.js application/javascript
|
||||||
|
.json application/json
|
||||||
|
.latex application/x-latex
|
||||||
|
.list text/plain
|
||||||
|
.log text/plain
|
||||||
|
.m4a audio/mp4
|
||||||
|
.man text/troff
|
||||||
|
.mid audio/midi
|
||||||
|
.midi audio/midi
|
||||||
|
.mov video/quicktime
|
||||||
|
.mp3 audio/mpeg
|
||||||
|
.mp4 video/mp4
|
||||||
|
.msh model/mesh
|
||||||
|
.msi application/x-msdownload
|
||||||
|
.obj application/octet-stream
|
||||||
|
.ogg audio/ogg
|
||||||
|
.otf application/x-font-otf
|
||||||
|
.pdf application/pdf
|
||||||
|
.png image/png
|
||||||
|
.ppt application/vnd.ms-powerpoint
|
||||||
|
.pptx application/vnd.openxmlformats-officedocument.presentationml.presentation
|
||||||
|
.psd image/vnd.adobe.photoshop
|
||||||
|
.py text/x-python
|
||||||
|
.rar application/x-rar-compressed
|
||||||
|
.rss application/rss+xml
|
||||||
|
.rtf application/rtf
|
||||||
|
.rtx text/richtext
|
||||||
|
.s text/x-asm
|
||||||
|
.pem application/x-pem-file"
|
||||||
|
.ser application/java-serialized-object
|
||||||
|
.sh application/x-sh
|
||||||
|
.sig application/pgp-signature
|
||||||
|
.silo model/mesh
|
||||||
|
.svg image/svg+xml
|
||||||
|
.t text/troff
|
||||||
|
.tar application/x-tar
|
||||||
|
.text text/plain
|
||||||
|
.tgz application/x-gzip
|
||||||
|
.tif image/tiff
|
||||||
|
.tiff image/tiff
|
||||||
|
.torrent application/x-bittorrent
|
||||||
|
.ttc application/x-font-ttf
|
||||||
|
.ttf application/x-font-ttf
|
||||||
|
.txt text/plain
|
||||||
|
.urls text/uri-list
|
||||||
|
.v text/x-v
|
||||||
|
.wav audio/x-wav
|
||||||
|
.wmv video/x-ms-wmv
|
||||||
|
.xls application/vnd.ms-excel
|
||||||
|
.xlsx application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
|
||||||
|
.xml application/xml
|
||||||
|
.xps application/vnd.ms-xpsdocument
|
||||||
|
|
||||||
|
# special cased based on file name
|
||||||
|
rss.xml application/rss+xml
|
|
@ -1,8 +1,3 @@
|
||||||
import { Progress } from "@paperclover/console/Progress";
|
|
||||||
import { Spinner } from "@paperclover/console/Spinner";
|
|
||||||
import * as path from "node:path";
|
|
||||||
import process from "node:process";
|
|
||||||
|
|
||||||
interface QueueOptions<T, R> {
|
interface QueueOptions<T, R> {
|
||||||
name: string;
|
name: string;
|
||||||
fn: (item: T, spin: Spinner) => Promise<R>;
|
fn: (item: T, spin: Spinner) => Promise<R>;
|
||||||
|
@ -204,3 +199,8 @@ export class OnceMap<T> {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import { Progress } from "@paperclover/console/Progress";
|
||||||
|
import { Spinner } from "@paperclover/console/Spinner";
|
||||||
|
import * as path from "node:path";
|
||||||
|
import process from "node:process";
|
||||||
|
|
6
package-lock.json
generated
6
package-lock.json
generated
|
@ -1027,9 +1027,9 @@
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/acorn": {
|
"node_modules/acorn": {
|
||||||
"version": "8.14.1",
|
"version": "8.15.0",
|
||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
||||||
"integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==",
|
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
{
|
{
|
||||||
"private": true,
|
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hono/node-server": "^1.14.3",
|
"@hono/node-server": "^1.14.3",
|
||||||
|
@ -23,9 +22,9 @@
|
||||||
"#ssr/jsx-runtime": "./framework/engine/jsx-runtime.ts",
|
"#ssr/jsx-runtime": "./framework/engine/jsx-runtime.ts",
|
||||||
"#ssr/marko": "./framework/engine/marko-runtime.ts",
|
"#ssr/marko": "./framework/engine/marko-runtime.ts",
|
||||||
"#marko/html": {
|
"#marko/html": {
|
||||||
"development": "marko/debug/html",
|
"types": "marko/html",
|
||||||
"production": "marko/html",
|
"production": "marko/production",
|
||||||
"types": "marko/html"
|
"node": "marko/debug/html"
|
||||||
},
|
},
|
||||||
"#hono/platform": {
|
"#hono/platform": {
|
||||||
"bun": "hono/bun",
|
"bun": "hono/bun",
|
||||||
|
|
2
repl.js
2
repl.js
|
@ -18,7 +18,7 @@ hot.load("node:repl").start({
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
// TODO: improve @paperclover/console's ability to print AggregateError
|
// TODO: improve @paperclover/console's ability to print AggregateError
|
||||||
// and errors with extra random properties
|
// and errors with extra random properties
|
||||||
console.error(inspect(err));
|
console.error(util.inspect(err));
|
||||||
})
|
})
|
||||||
.then((result) => done(null, result));
|
.then((result) => done(null, result));
|
||||||
},
|
},
|
||||||
|
|
17
run.js
17
run.js
|
@ -1,6 +1,5 @@
|
||||||
// This file allows using Node.js in combination with
|
// This file allows using Node.js in combination with
|
||||||
// all available plugins. Usage: "node run <script>"
|
// all available plugins. Usage: "node run <script>"
|
||||||
import * as path from "node:path";
|
|
||||||
import * as util from "node:util";
|
import * as util from "node:util";
|
||||||
import process from "node:process";
|
import process from "node:process";
|
||||||
|
|
||||||
|
@ -47,9 +46,21 @@ if (process.argv[1].startsWith(import.meta.filename.slice(0, -".js".length))) {
|
||||||
console.error("usage: node run <script> [...args]");
|
console.error("usage: node run <script> [...args]");
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
const file = path.resolve(process.argv[2]);
|
let found;
|
||||||
|
for (const dir of ["./", "./src/", "./framework/"]) {
|
||||||
|
try {
|
||||||
|
found = hot.resolveFrom(import.meta.filename, dir + process.argv[2]);
|
||||||
|
break;
|
||||||
|
} catch (e) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
console.error("Cannot find script: " + process.argv[2]);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
process.argv = [process.argv[0], ...process.argv.slice(2)];
|
process.argv = [process.argv[0], ...process.argv.slice(2)];
|
||||||
hot.load(file).main?.();
|
hot.load(found).main?.();
|
||||||
}
|
}
|
||||||
|
|
||||||
export { hot };
|
export { hot };
|
||||||
|
|
Loading…
Reference in a new issue