Migrated to pacel and removed deno
This commit is contained in:
parent
f73acae41a
commit
24ceaea9d5
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,3 +1,6 @@
|
||||
pages
|
||||
logo.pxd
|
||||
.DS_Store
|
||||
node_modules
|
||||
.parcel-cache
|
||||
dist
|
22
.vscode/noot.code-workspace
vendored
22
.vscode/noot.code-workspace
vendored
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
{
|
||||
"folders": [
|
||||
{
|
||||
"path": "webapp"
|
||||
},
|
||||
{
|
||||
"path": "plugins"
|
||||
},
|
||||
{
|
||||
"path": "server"
|
||||
}
|
||||
],
|
||||
"settings": {
|
||||
"editor.formatOnSave": true
|
||||
}
|
||||
}
|
@ -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
22
plugbox/package.json
Normal 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
63
plugbox/src/bundle.ts
Normal 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
1768
plugbox/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
0
plugins/.gitignore
vendored
0
plugins/.gitignore
vendored
4
plugins/.vscode/settings.json
vendored
4
plugins/.vscode/settings.json
vendored
@ -1,4 +0,0 @@
|
||||
{
|
||||
"deno.enable": true,
|
||||
"deno.unstable": true
|
||||
}
|
@ -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
|
@ -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))
|
||||
);
|
2
server/.vscode/settings.json
vendored
2
server/.vscode/settings.json
vendored
@ -1,4 +1,4 @@
|
||||
{
|
||||
"deno.enable": true,
|
||||
"deno.enable": false,
|
||||
"deno.unstable": true
|
||||
}
|
24
server/package.json
Normal file
24
server/package.json
Normal 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"
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
ls | entr -s 'deno run --allow-net --allow-read --allow-write server.ts'
|
133
server/server.ts
133
server/server.ts
@ -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
136
server/src/server.ts
Normal 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}`);
|
||||
});
|
@ -1,2 +0,0 @@
|
||||
import { parser } from "https://unpkg.com/@lezer/markdown?module";
|
||||
console.log(parser);
|
2650
server/yarn.lock
Normal file
2650
server/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
3
webapp/.gitignore
vendored
3
webapp/.gitignore
vendored
@ -1,3 +0,0 @@
|
||||
.parcel-cache
|
||||
dist
|
||||
node_modules
|
@ -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")!
|
||||
);
|
||||
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user