1
0

Migrated to pacel and removed deno

This commit is contained in:
Zef Hemel 2022-03-04 10:26:41 +01:00
parent f73acae41a
commit 24ceaea9d5
31 changed files with 4685 additions and 281 deletions

3
.gitignore vendored
View File

@ -1,3 +1,6 @@
pages
logo.pxd
.DS_Store
node_modules
.parcel-cache
dist

View File

@ -1,22 +0,0 @@
{
"folders": [
{
"path": ".."
},
{
"path": "../server"
},
{
"path": "../plugin-bundler"
}
],
"settings": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"javascript.format.enable": false,
"typescript.format.enable": false,
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
}
}

View File

@ -1,16 +0,0 @@
{
"folders": [
{
"path": "webapp"
},
{
"path": "plugins"
},
{
"path": "server"
}
],
"settings": {
"editor.formatOnSave": true
}
}

View File

@ -1,6 +1,6 @@
import { IndexEvent } from "../../webapp/src/app_event.ts";
import { pageLinkRegex } from "../../webapp/src/constant.ts";
import { syscall } from "./lib/syscall.ts";
import { IndexEvent } from "../../webapp/src/app_event";
import { pageLinkRegex } from "../../webapp/src/constant";
import { syscall } from "./lib/syscall";
const wikilinkRegex = new RegExp(pageLinkRegex, "g");
@ -29,7 +29,6 @@ export async function deletePage() {
}
export async function renamePage() {
// console.log("HELLO WORLD");
const pageMeta = await syscall("editor.getCurrentPage");
const oldName = pageMeta.name;
console.log("Old name is", oldName);

22
plugbox/package.json Normal file
View File

@ -0,0 +1,22 @@
{
"name": "plugbox",
"version": "1.0.0",
"type": "module",
"source": "src/bundle.ts",
"main": "dist/bundle.js",
"scripts": {
"build": "parcel build",
"core": "node dist/bundle.js --debug core/core.plugin.json ../webapp/src/generated/core.plugin.json"
},
"dependencies": {
"esbuild": "^0.14.24",
"typescript": ">=3.0.0",
"vm2": "^3.9.9",
"yargs": "^17.3.1"
},
"devDependencies": {
"@types/node": "^17.0.21",
"@types/yargs": "^17.0.9",
"parcel": "^2.3.2"
}
}

63
plugbox/src/bundle.ts Normal file
View File

@ -0,0 +1,63 @@
import esbuild from "esbuild";
import { readFile, unlink, writeFile } from "fs/promises";
import path from "path";
import yargs from "yargs";
import { hideBin } from "yargs/helpers";
import { Manifest } from "../../webapp/src/plugins/types";
async function compile(filePath: string, sourceMap: string) {
let tempFile = "out.js";
let js = await esbuild.build({
entryPoints: [filePath],
bundle: true,
format: "iife",
globalName: "mod",
platform: "neutral",
sourcemap: sourceMap ? "inline" : false,
minify: true,
outfile: tempFile,
});
let jsCode = (await readFile(tempFile)).toString();
jsCode = jsCode.replace(/^var mod ?= ?/, "");
await unlink(tempFile);
return jsCode;
}
async function bundle(manifestPath, sourceMaps) {
const rootPath = path.dirname(manifestPath);
const manifest = JSON.parse(
(await readFile(manifestPath)).toString()
) as Manifest;
for (let [name, def] of Object.entries(manifest.functions)) {
let jsFunctionName = def.functionName,
filePath = path.join(rootPath, def.path);
if (filePath.indexOf(":") !== -1) {
[filePath, jsFunctionName] = filePath.split(":");
} else if (!jsFunctionName) {
jsFunctionName = "default";
}
def.code = await compile(filePath, sourceMaps);
def.path = filePath;
def.functionName = jsFunctionName;
}
return manifest;
}
async function run() {
let args = await yargs(hideBin(process.argv))
.option("debug", {
type: "boolean",
})
.parse();
let generatedManifest = await bundle(args._[0], !!args.debug);
writeFile(args._[1] as string, JSON.stringify(generatedManifest, null, 2));
}
run().catch((e) => {
console.error(e);
process.exit(1);
});

1768
plugbox/yarn.lock Normal file

File diff suppressed because it is too large Load Diff

0
plugins/.gitignore vendored
View File

View File

@ -1,4 +0,0 @@
{
"deno.enable": true,
"deno.unstable": true
}

View File

@ -1,7 +0,0 @@
DENO_BUNDLE=deno run --allow-read --allow-write --unstable bundle.ts --debug
build: *
mkdir -p dist
$(DENO_BUNDLE) core/core.plugin.json ../webapp/src/generated/core.plugin.json
entr:
ls core/* | entr make

View File

@ -1,73 +0,0 @@
import { parse } from "https://deno.land/std@0.121.0/flags/mod.ts";
import * as path from "https://deno.land/std@0.121.0/path/mod.ts";
import { Manifest, FunctionDef } from "../webapp/src/plugins/types.ts";
async function compile(filePath: string, sourceMaps: boolean): Promise<string> {
// @ts-ignore for Deno.emit (unstable API)
let { files, diagnostics } = await Deno.emit(filePath, {
bundle: "classic",
check: true,
compilerOptions: {
lib: ["WebWorker", "ES2020"],
inlineSourceMap: sourceMaps,
sourceMap: false,
},
});
let bundleSource = files["deno:///bundle.js"];
if (diagnostics.length > 0) {
for (let diagnostic of diagnostics) {
if (diagnostic.start) {
console.error(
`In ${diagnostic.fileName}:${diagnostic.start!.line + 1}: ${
diagnostic.messageText
}`
);
} else {
console.error(diagnostic);
}
}
throw new Error("Diagnostics");
}
return bundleSource;
}
async function bundle(
manifestPath: string,
sourceMaps: boolean
): Promise<Manifest> {
const rootPath = path.dirname(manifestPath);
const manifest = JSON.parse(
new TextDecoder().decode(await Deno.readFile(manifestPath))
) as Manifest;
for (let [name, def] of Object.entries(manifest.functions) as Array<
[string, FunctionDef]
>) {
let jsFunctionName = def.functionName,
filePath = path.join(rootPath, def.path);
if (filePath.indexOf(":") !== -1) {
[filePath, jsFunctionName] = filePath.split(":");
} else if (!jsFunctionName) {
jsFunctionName = "default";
}
def.code = await compile(filePath, sourceMaps);
def.path = filePath;
def.functionName = jsFunctionName;
}
return manifest;
}
let commandLineArguments = parse(Deno.args, {
boolean: true,
});
let [manifestPath, outputPath] = commandLineArguments._ as string[];
console.log(`Generating bundle for ${manifestPath} to ${outputPath}`);
let b = await bundle(manifestPath, !!commandLineArguments.debug);
await Deno.writeFile(
outputPath,
new TextEncoder().encode(JSON.stringify(b, null, 2))
);

View File

@ -1,4 +1,4 @@
{
"deno.enable": true,
"deno.enable": false,
"deno.unstable": true
}

24
server/package.json Normal file
View File

@ -0,0 +1,24 @@
{
"name": "server",
"version": "1.0.0",
"license": "MIT",
"source": "src/server.ts",
"main": "dist/server.js",
"scripts": {
"build": "parcel build",
"watch": "parcel watch",
"start": "node dist/server.js",
"nodemon": "nodemon dist/server.js"
},
"dependencies": {
"cors": "^2.8.5",
"express": "^4.17.3",
"typescript": "^4.6.2"
},
"devDependencies": {
"@types/cors": "^2.8.12",
"@types/express": "^4.17.13",
"nodemon": "^2.0.15",
"parcel": "^2.3.2"
}
}

View File

@ -1,3 +0,0 @@
#!/bin/bash
ls | entr -s 'deno run --allow-net --allow-read --allow-write server.ts'

View File

@ -1,133 +0,0 @@
import * as path from "https://deno.land/std@0.125.0/path/mod.ts";
import FileInfo = Deno.FileInfo;
import { Application, Router } from "https://deno.land/x/oak/mod.ts";
import { oakCors } from "https://deno.land/x/cors@v1.2.0/mod.ts";
import { readAll } from "https://deno.land/std@0.126.0/streams/mod.ts";
import { exists } from "https://deno.land/std@0.126.0/fs/mod.ts";
import { recursiveReaddir } from "https://deno.land/x/recursive_readdir@v2.0.0/mod.ts";
type PageMeta = {
name: string;
lastModified: number;
};
const fsPrefix = "/fs";
const pagesPath = "../pages";
const fsRouter = new Router();
fsRouter.use(oakCors({ methods: ["OPTIONS", "GET", "PUT", "POST", "DELETE"] }));
fsRouter.get("/", async (context) => {
const localPath = pagesPath;
let fileNames: PageMeta[] = [];
const markdownFiles = (await recursiveReaddir(localPath)).filter(
(file: string) => path.extname(file) === ".md"
);
for (const p of markdownFiles) {
const stat = await Deno.stat(p);
fileNames.push({
name: p.substring(
localPath.length + 1,
p.length - path.extname(p).length
),
lastModified: stat.mtime?.getTime()!,
});
}
context.response.body = JSON.stringify(fileNames);
});
fsRouter.get("/:page(.*)", async (context) => {
const pageName = context.params.page;
const localPath = `${pagesPath}/${pageName}.md`;
try {
const stat = await Deno.stat(localPath);
const text = await Deno.readTextFile(localPath);
context.response.headers.set("Last-Modified", "" + stat.mtime?.getTime());
context.response.body = text;
} catch (e) {
context.response.status = 404;
context.response.body = "";
}
});
fsRouter.options("/:page(.*)", async (context) => {
const localPath = `${pagesPath}/${context.params.page}.md`;
try {
const stat = await Deno.stat(localPath);
context.response.headers.set("Content-length", `${stat.size}`);
context.response.headers.set("Last-Modified", "" + stat.mtime?.getTime());
} catch (e) {
// For CORS
context.response.status = 200;
context.response.body = "";
}
});
fsRouter.put("/:page(.*)", async (context) => {
const pageName = context.params.page;
const localPath = `${pagesPath}/${pageName}.md`;
const existingPage = await exists(localPath);
let dirName = path.dirname(localPath);
if (!(await exists(dirName))) {
await Deno.mkdir(dirName, {
recursive: true,
});
}
let file;
try {
file = await Deno.create(localPath);
} catch (e) {
console.error("Error opening file for writing", localPath, e);
context.response.status = 500;
context.response.body = e.message;
return;
}
const result = context.request.body({ type: "reader" });
const text = await readAll(result.value);
file.write(text);
file.close();
console.log("Wrote to", localPath);
const stat = await Deno.stat(localPath);
context.response.status = existingPage ? 200 : 201;
context.response.headers.set("Last-Modified", "" + stat.mtime?.getTime());
context.response.body = "OK";
});
fsRouter.delete("/:page(.*)", async (context) => {
const pageName = context.params.page;
const localPath = `${pagesPath}/${pageName}.md`;
try {
await Deno.remove(localPath);
} catch (e) {
console.error("Error deleting file", localPath, e);
context.response.status = 500;
context.response.body = e.message;
return;
}
console.log("Deleted", localPath);
context.response.body = "OK";
});
const app = new Application();
app.use(
new Router()
.use(fsPrefix, fsRouter.routes(), fsRouter.allowedMethods())
.routes()
);
app.use(async (context, next) => {
try {
await context.send({
root: "../webapp/dist",
index: "index.html",
});
} catch {
await context.send({ root: "../webapp/dist", path: "index.html" });
// next();
}
});
await app.listen({ port: 2222 });

136
server/src/server.ts Normal file
View File

@ -0,0 +1,136 @@
import cors from "cors";
import express from "express";
import fs from "fs";
import { readdir, readFile, stat, unlink } from "fs/promises";
import path from "path";
import stream from "stream";
import {} from "stream/promises";
import { promisify } from "util";
const app = express();
const port = 3000;
const pipeline = promisify(stream.pipeline);
const pagesPath = "../pages";
const distDir = `${__dirname}/../../webapp/dist`;
type PageMeta = {
name: string;
lastModified: number;
};
app.use("/", express.static(distDir));
let fsRouter = express.Router();
// Page list
fsRouter.route("/").get(async (req, res) => {
const localPath = pagesPath;
let fileNames: PageMeta[] = [];
async function walkPath(dir: string) {
let files = await readdir(dir);
for (let file of files) {
const fullPath = path.join(dir, file);
let s = await stat(fullPath);
if (s.isDirectory()) {
await walkPath(fullPath);
} else {
if (path.extname(file) === ".md") {
fileNames.push({
name: fullPath.substring(pagesPath.length + 1, fullPath.length - 3),
lastModified: s.mtime.getTime(),
});
}
}
}
}
await walkPath(pagesPath);
res.json(fileNames);
});
fsRouter
.route(/\/(.+)/)
.get(async (req, res) => {
let reqPath = req.params[0];
console.log("Getting", reqPath);
try {
const localPath = path.join(pagesPath, reqPath + ".md");
const s = await stat(localPath);
let content = await readFile(localPath, "utf8");
res.status(200);
res.header("Last-Modified", "" + s.mtime.getTime());
res.header("Content-Type", "text/markdown");
res.send(content);
} catch (e) {
res.status(200);
res.send("");
}
})
.put(async (req, res) => {
let reqPath = req.params[0];
let localPath = path.join(pagesPath, reqPath + ".md");
try {
await pipeline(req, fs.createWriteStream(localPath));
console.log(`Wrote to ${localPath}`);
const s = await stat(localPath);
res.status(200);
res.header("Last-Modified", "" + s.mtime.getTime());
res.send("OK");
} catch (err) {
res.status(500);
res.send("Write failed");
console.error("Pipeline failed", err);
}
})
.options(async (req, res) => {
let reqPath = req.params[0];
try {
const localPath = path.join(pagesPath, reqPath + ".md");
const s = await stat(localPath);
res.status(200);
res.header("Last-Modified", "" + s.mtime.getTime());
res.header("Content-length", "" + s.size);
res.header("Content-Type", "text/markdown");
res.send("");
} catch (e) {
res.status(200);
res.send("");
}
})
.delete(async (req, res) => {
let reqPath = req.params[0];
const localPath = path.join(pagesPath, reqPath + ".md");
try {
await unlink(localPath);
res.status(200);
res.send("OK");
} catch (e) {
console.error("Error deleting file", localPath, e);
res.status(500);
res.send("OK");
}
});
app.use(
"/fs",
cors({
methods: "GET,HEAD,PUT,OPTIONS,POST,DELETE",
preflightContinue: true,
}),
fsRouter
);
// Fallback, serve index.html
let cachedIndex: string | undefined = undefined;
app.get("/*", async (req, res) => {
if (!cachedIndex) {
cachedIndex = await readFile(`${distDir}/index.html`, "utf8");
}
res.status(200).header("Content-Type", "text/html").send(cachedIndex);
});
app.listen(port, () => {
console.log(`Server istening on port ${port}`);
});

View File

@ -1,2 +0,0 @@
import { parser } from "https://unpkg.com/@lezer/markdown?module";
console.log(parser);

2650
server/yarn.lock Normal file

File diff suppressed because it is too large Load Diff

3
webapp/.gitignore vendored
View File

@ -1,3 +0,0 @@
.parcel-cache
dist
node_modules

View File

@ -3,7 +3,7 @@ import { HttpRemoteSpace } from "./space";
import { safeRun } from "./util";
let editor = new Editor(
new HttpRemoteSpace(`http://${location.hostname}:2222/fs`),
new HttpRemoteSpace(`http://${location.hostname}:3000/fs`),
document.getElementById("root")!
);

View File

@ -268,6 +268,8 @@ export class Editor implements AppEventDispatcher {
key: "Ctrl-.",
mac: "Cmd-.",
run: (target): boolean => {
console.log("YO");
this.viewDispatch({
type: "show-palette",
});

File diff suppressed because one or more lines are too long