@virtualstate/app-history
Version:
Native JavaScript [app-history](https://github.com/WICG/app-history) implementation
133 lines (107 loc) • 4.28 kB
text/typescript
import { createServer } from "http";
import { resolve, dirname, join } from "path";
import * as Cheerio from "cheerio";
import { promises as fs } from "fs";
const namespacePath = "/node_modules/wpt";
const buildPath = "/esnext";
const resourcesInput = "/resources";
const resourcesTarget = "/node_modules/wpt/resources";
export function startServer(port: number) {
const server = createServer(
(request, response) => {
const url = new URL(request.url, `http://localhost:${port}`);
let promise = Promise.resolve("");
response.setHeader("Access-Control-Allow-Origin", "*");
console.log({ pathname: url.pathname });
if (url.pathname.endsWith(".html.js")) {
promise = createJavaScriptBundle(url);
response.setHeader("Content-Type", "application/javascript");
}
promise
.then(contents => {
response.writeHead(200);
response.write(contents);
})
.catch((error) => {
console.log({ error });
response.writeHead(500);
})
.then(() => response.end())
}
);
server.listen(port, () => {
console.log(`Running Web Platform Tests ECMAScript Modules server on port ${port}`)
})
return () => {
}
}
export async function createJavaScriptBundle(url: URL) {
const cwd = resolve(dirname(new URL(import.meta.url).pathname), "../..");
const withoutExtension = url.pathname.replace(/\.html\.js$/, "");
console.log({ cwd, withoutExtension });
if (withoutExtension.includes(".")) throw new Error("Unexpected dot in path");
const htmlPath = join(cwd, namespacePath, `${withoutExtension}.html`);
console.log({ cwd, withoutExtension, htmlPath });
const html = await fs.readFile(htmlPath, "utf-8");
if (!html) return "";
const $ = Cheerio.load(html);
const dependencies = await Promise.all(
$("script[src]")
.map(function () {
return $(this).attr("src")
})
.toArray()
.filter(dependency => url.searchParams.get("localDependenciesOnly") ? !dependency.startsWith("/") : true)
.map(async (dependency): Promise<[string, string]> => [
dependency,
await fs.readFile(join(cwd, namespacePath, new URL(dependency, url.toString()).pathname), "utf-8").catch(() => "// Could not load")
])
);
const dependenciesJoined = `
//
const self = globalThis;
${dependencies
.map(([name, contents]) => `// ${name.replace(cwd, "")}\n${contents}`)
.join("\n")}
`;
const scripts = $("script:not([src])")
.map(function () {
return $(this).html() ?? ""
})
.toArray();
let scriptsJoined = scripts.join('\n');
if (url.searchParams.get("preferUndefined")) {
// eek
scriptsJoined = scriptsJoined.replace(/null/g, "undefined");
}
let fnName = url.searchParams.get("exportAs");
// https://stackoverflow.com/a/2008353/1174869
const identifierTest = /^[$A-Z_][0-9A-Z_$]*$/i;
if (!fnName || !identifierTest.test(fnName)) {
fnName = "runTests";
}
let globalNames = (url.searchParams.get("globals") ?? "")
.split(",")
.filter(name => identifierTest.test(name));
if (!globalNames.length) {
globalNames = ["______globals_object_key"]
}
const globalsDestructure = `{${globalNames.join(", ")}}`;
const scriptHarness = `
export function ${fnName}(${globalsDestructure}) {${url.searchParams.get("debugger") ? "\nconsole.log('debugger start');debugger;\n" : ""}
${scriptsJoined}
}
`.trim();
if (url.searchParams.get("dependenciesOnly")) {
return dependenciesJoined;
}
if (url.searchParams.get("scriptsOnly")) {
return scriptHarness;
}
return `${dependenciesJoined}\n${scriptHarness}`;
}
if (typeof process !== "undefined" && process.argv.includes(new URL(import.meta.url).pathname)) {
const portString = process.env.PORT || '';
const port = /^\d+$/.test(portString) ? +portString : 3000;
void startServer(port);
}