@weborigami/origami 0.6.15 → 0.6.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/main.js +2 -0
- package/package.json +4 -3
- package/src/common/findOpenPort.js +58 -0
- package/src/common/hashBytes.js +26 -0
- package/src/dev/changes2.js +38 -0
- package/src/dev/debug2/debug2.js +39 -28
- package/src/dev/debug2/debugChild.js +5 -10
- package/src/dev/debug2/debugCommands.js +7 -25
- package/src/dev/debug2/debugParent.js +113 -158
- package/src/dev/debug2/debugTransform.js +37 -43
- package/src/dev/debug2/expressionTree.js +2 -4
- package/src/dev/debug2/oriEval.js +43 -11
- package/src/dev/dev.js +1 -1
- package/src/dev/help.yaml +18 -0
- package/src/handlers/origamiHandlers.js +1 -0
- package/src/handlers/xml_handler.js +23 -0
- package/src/origami/domNodeToObject.js +93 -0
- package/src/origami/hash.js +17 -0
- package/src/origami/htmlParse.js +22 -0
- package/src/origami/mdHtml.js +1 -0
- package/src/origami/mdOutline.js +17 -5
- package/src/origami/origami.js +5 -1
- package/src/origami/randomFrom.js +15 -0
- package/src/origami/randomsFrom.js +65 -0
- package/src/origami/xmlParse.js +33 -0
- package/src/server/server.js +15 -3
- package/src/origami/htmlDom.js +0 -14
package/main.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
export { default as documentObject } from "./src/common/documentObject.js";
|
|
2
2
|
export * from "./src/common/serialize.js";
|
|
3
3
|
export { default as debugParent } from "./src/dev/debug2/debugParent.js";
|
|
4
|
+
export { default as debugTransform } from "./src/dev/debug2/debugTransform.js";
|
|
4
5
|
export * as Dev from "./src/dev/dev.js";
|
|
6
|
+
export * from "./src/handlers/origamiHandlers.js";
|
|
5
7
|
export * as Origami from "./src/origami/origami.js";
|
|
6
8
|
export { default as origamiHighlightDefinition } from "./src/origami/origamiHighlightDefinition.js";
|
|
7
9
|
export { default as constructResponse } from "./src/server/constructResponse.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weborigami/origami",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.17",
|
|
4
4
|
"description": "Web Origami language, CLI, framework, and server",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -18,9 +18,9 @@
|
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"@hpcc-js/wasm-graphviz": "^1.21.0",
|
|
21
|
-
"@weborigami/async-tree": "0.6.
|
|
21
|
+
"@weborigami/async-tree": "0.6.17",
|
|
22
22
|
"@weborigami/json-feed-to-rss": "1.0.1",
|
|
23
|
-
"@weborigami/language": "0.6.
|
|
23
|
+
"@weborigami/language": "0.6.17",
|
|
24
24
|
"css-tree": "3.1.0",
|
|
25
25
|
"highlight.js": "11.11.1",
|
|
26
26
|
"jsdom": "28.1.0",
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"marked-highlight": "2.2.3",
|
|
30
30
|
"marked-smartypants": "1.1.11",
|
|
31
31
|
"sharp": "0.34.5",
|
|
32
|
+
"whatwg-mimetype": "5.0.0",
|
|
32
33
|
"yaml": "2.8.2"
|
|
33
34
|
},
|
|
34
35
|
"scripts": {
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import net from "node:net";
|
|
2
|
+
|
|
3
|
+
const DEFAULT_PORT = 5000;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Return the first open port number on or after the given port number.
|
|
7
|
+
*
|
|
8
|
+
* @param {number} startPort
|
|
9
|
+
* @returns {Promise<number>}
|
|
10
|
+
*/
|
|
11
|
+
export async function findOpenPort(startPort = DEFAULT_PORT) {
|
|
12
|
+
for (let port = startPort; port <= 65535; port++) {
|
|
13
|
+
if (await isPortAvailable(port)) {
|
|
14
|
+
return port;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
throw new Error(`No open port found on or after ${startPort}`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Check whether a port is available on both IPv4 and IPv6 loopback addresses
|
|
23
|
+
* by attempting TCP connections. On macOS, IPv4 and IPv6 port spaces are
|
|
24
|
+
* independent (IPV6_V6ONLY=1 by default), so a server bound to [::]:PORT is
|
|
25
|
+
* invisible to a 127.0.0.1 bind check. Using connect probes on both loopbacks
|
|
26
|
+
* catches servers regardless of which protocol family they listen on. Any
|
|
27
|
+
* connection error (ECONNREFUSED, EADDRNOTAVAIL, etc.) means nothing is
|
|
28
|
+
* listening there, so the function is safe on systems without IPv6.
|
|
29
|
+
*
|
|
30
|
+
* @param {number} port
|
|
31
|
+
* @returns {Promise<boolean>}
|
|
32
|
+
*/
|
|
33
|
+
async function isPortAvailable(port) {
|
|
34
|
+
const [v4, v6] = await Promise.all([
|
|
35
|
+
isPortListening("127.0.0.1", port),
|
|
36
|
+
isPortListening("::1", port),
|
|
37
|
+
]);
|
|
38
|
+
return !v4 && !v6;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @param {string} host
|
|
43
|
+
* @param {number} port
|
|
44
|
+
* @returns {Promise<boolean>}
|
|
45
|
+
*/
|
|
46
|
+
function isPortListening(host, port) {
|
|
47
|
+
return new Promise((resolve) => {
|
|
48
|
+
const socket = net.createConnection(port, host);
|
|
49
|
+
socket.once("connect", () => {
|
|
50
|
+
socket.destroy();
|
|
51
|
+
resolve(true);
|
|
52
|
+
});
|
|
53
|
+
socket.once("error", () => {
|
|
54
|
+
socket.destroy();
|
|
55
|
+
resolve(false);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { toString } from "@weborigami/async-tree";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Given data, return a 256-bit hash of that data. The data can be a string or a
|
|
6
|
+
* Uint8Array.
|
|
7
|
+
*
|
|
8
|
+
* @typedef {import("@weborigami/async-tree").Stringlike} Stringlike
|
|
9
|
+
*
|
|
10
|
+
* @param {Uint8Array|Stringlike} data
|
|
11
|
+
*/
|
|
12
|
+
export default function hashBytes(data) {
|
|
13
|
+
let bytes;
|
|
14
|
+
if (data instanceof Uint8Array) {
|
|
15
|
+
bytes = data;
|
|
16
|
+
} else {
|
|
17
|
+
const text = toString(data);
|
|
18
|
+
if (!text) {
|
|
19
|
+
throw new TypeError("Data must be a string or Uint8Array");
|
|
20
|
+
}
|
|
21
|
+
bytes = new TextEncoder().encode(text);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const hash = createHash("sha256").update(bytes).digest();
|
|
25
|
+
return hash;
|
|
26
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { args, isStringlike, toString, Tree } from "@weborigami/async-tree";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Given an old tree and a new tree, return a tree of changes indicated
|
|
5
|
+
* by the values: "added", "changed", or "deleted".
|
|
6
|
+
*
|
|
7
|
+
* @typedef {import("@weborigami/async-tree").Maplike} Maplike
|
|
8
|
+
*
|
|
9
|
+
* @param {Maplike} oldMaplike
|
|
10
|
+
* @param {Maplike} newMaplike
|
|
11
|
+
*/
|
|
12
|
+
export default async function changes(oldMaplike, newMaplike) {
|
|
13
|
+
const oldTree = await args.map(oldMaplike, "Dev.changes", {
|
|
14
|
+
deep: true,
|
|
15
|
+
position: 1,
|
|
16
|
+
});
|
|
17
|
+
const newTree = await args.map(newMaplike, "Dev.changes", {
|
|
18
|
+
deep: true,
|
|
19
|
+
position: 2,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const combination = await Tree.combine(oldTree, newTree, compare);
|
|
23
|
+
return combination;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function compare(oldValue, newValue) {
|
|
27
|
+
if (oldValue !== undefined && newValue === undefined) {
|
|
28
|
+
return "deleted";
|
|
29
|
+
} else if (oldValue === undefined && newValue !== undefined) {
|
|
30
|
+
return "added";
|
|
31
|
+
} else if (isStringlike(oldValue) && isStringlike(newValue)) {
|
|
32
|
+
const oldText = toString(oldValue);
|
|
33
|
+
const newText = toString(newValue);
|
|
34
|
+
return oldText === newText ? undefined : "changed";
|
|
35
|
+
} else {
|
|
36
|
+
return oldValue === newValue ? undefined : "changed";
|
|
37
|
+
}
|
|
38
|
+
}
|
package/src/dev/debug2/debug2.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { OrigamiFileMap } from "@weborigami/language";
|
|
2
|
+
import path from "node:path";
|
|
2
3
|
import debugParent from "./debugParent.js";
|
|
3
4
|
|
|
4
5
|
/**
|
|
@@ -9,25 +10,13 @@ import debugParent from "./debugParent.js";
|
|
|
9
10
|
* extract the source code of the expression to be debugged. (If it were
|
|
10
11
|
* evaluated, the function will be called with the result of the expression.)
|
|
11
12
|
*
|
|
12
|
-
* The `options` argument can include:
|
|
13
|
-
* - `enableUnsafeEval`: if true, enables the `!eval` debug command in the child
|
|
14
|
-
* process; default is false
|
|
15
|
-
* - `debugFilesPath`: path to resources that will be added to the served tree
|
|
16
|
-
*
|
|
17
13
|
* @typedef {import("@weborigami/language").RuntimeState} RuntimeState
|
|
18
14
|
* @typedef {import("@weborigami/language").AnnotatedCode} AnnotatedCode
|
|
19
15
|
*
|
|
20
16
|
* @param {AnnotatedCode} code
|
|
21
|
-
* @param {any | RuntimeState} options
|
|
22
17
|
* @param {RuntimeState} state
|
|
23
18
|
*/
|
|
24
|
-
export default async function debug2(code,
|
|
25
|
-
if (state === undefined) {
|
|
26
|
-
// Options were omitted; shift arguments
|
|
27
|
-
state = options;
|
|
28
|
-
options = [];
|
|
29
|
-
}
|
|
30
|
-
|
|
19
|
+
export default async function debug2(code, state) {
|
|
31
20
|
if (
|
|
32
21
|
!(code instanceof Array) ||
|
|
33
22
|
code.source === undefined ||
|
|
@@ -47,23 +36,45 @@ export default async function debug2(code, options, state) {
|
|
|
47
36
|
throw new Error("Dev.debug2 couldn't work out the parent path.");
|
|
48
37
|
}
|
|
49
38
|
|
|
50
|
-
//
|
|
51
|
-
|
|
52
|
-
options = await execute(options, state);
|
|
53
|
-
} else {
|
|
54
|
-
options = {};
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// @ts-ignore
|
|
58
|
-
const enableUnsafeEval = options.enableUnsafeEval ?? false;
|
|
59
|
-
const debugFilesPath = options.debugFilesPath ?? "";
|
|
60
|
-
|
|
61
|
-
await debugParent({
|
|
62
|
-
debugFilesPath,
|
|
63
|
-
enableUnsafeEval,
|
|
39
|
+
// Start the debug server
|
|
40
|
+
const server = await debugParent({
|
|
64
41
|
expression,
|
|
65
42
|
parentPath,
|
|
66
43
|
});
|
|
44
|
+
|
|
45
|
+
// Watch the parent files for changes
|
|
46
|
+
const tree = new OrigamiFileMap(parentPath);
|
|
47
|
+
tree.watch();
|
|
48
|
+
tree.addEventListener?.("change", async (event) => {
|
|
49
|
+
// @ts-ignore
|
|
50
|
+
const { filePath } = event.options;
|
|
51
|
+
if (isJavaScriptFile(filePath)) {
|
|
52
|
+
// Need to restart the child process
|
|
53
|
+
console.log("JavaScript file changed, restarting server…");
|
|
54
|
+
await server.restart();
|
|
55
|
+
} else if (path.basename(filePath) === "package.json") {
|
|
56
|
+
// Need to restart the child process
|
|
57
|
+
console.log("package.json changed, restarting server…");
|
|
58
|
+
await server.restart();
|
|
59
|
+
} else {
|
|
60
|
+
// Just have the child reevaluate the expression
|
|
61
|
+
console.log("File changed, reloading site…");
|
|
62
|
+
await server.reevaluate();
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// When server closes, stop watching for file changes
|
|
67
|
+
server.on("close", () => {
|
|
68
|
+
tree.unwatch();
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
console.log(`Server running at ${server.origin}. Press Ctrl+C to stop.`);
|
|
67
72
|
}
|
|
68
73
|
debug2.needsState = true;
|
|
69
74
|
debug2.unevaluatedArgs = true;
|
|
75
|
+
|
|
76
|
+
function isJavaScriptFile(filePath) {
|
|
77
|
+
const extname = path.extname(filePath).toLowerCase();
|
|
78
|
+
const jsExtensions = [".cjs", ".js", ".mjs", ".ts"];
|
|
79
|
+
return jsExtensions.includes(extname);
|
|
80
|
+
}
|
|
@@ -22,13 +22,6 @@ function fail(message) {
|
|
|
22
22
|
process.exit(1);
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
/** @type {string} */
|
|
26
|
-
const debugFilesPath = process.env.ORIGAMI_DEBUG_FILES_PATH ?? "";
|
|
27
|
-
|
|
28
|
-
/** @type {boolean} */
|
|
29
|
-
// @ts-ignore
|
|
30
|
-
const enableUnsafeEval = process.env.ORIGAMI_ENABLE_UNSAFE_EVAL === "1";
|
|
31
|
-
|
|
32
25
|
/** @type {string} */
|
|
33
26
|
// @ts-ignore
|
|
34
27
|
const expression = process.env.ORIGAMI_EXPRESSION;
|
|
@@ -43,6 +36,8 @@ if (parentPath === undefined) {
|
|
|
43
36
|
fail("Missing Origami parent");
|
|
44
37
|
}
|
|
45
38
|
|
|
39
|
+
const quiet = process.env.ORIGAMI_QUIET === "1";
|
|
40
|
+
|
|
46
41
|
// An indirect pointer to the tree of resources;
|
|
47
42
|
let treeHandle = {};
|
|
48
43
|
|
|
@@ -50,7 +45,7 @@ let treeHandle = {};
|
|
|
50
45
|
await evaluateExpression();
|
|
51
46
|
|
|
52
47
|
// Serve the tree of resources
|
|
53
|
-
const listener = requestListener(treeHandle);
|
|
48
|
+
const listener = requestListener(treeHandle, { quiet });
|
|
54
49
|
const server = http.createServer(listener);
|
|
55
50
|
|
|
56
51
|
// Track live connections so we can drain/close cleanly.
|
|
@@ -96,10 +91,8 @@ function beginDrain() {
|
|
|
96
91
|
|
|
97
92
|
async function evaluateExpression() {
|
|
98
93
|
const tree = await expressionTree({
|
|
99
|
-
debugFilesPath,
|
|
100
94
|
expression,
|
|
101
95
|
parentPath,
|
|
102
|
-
enableUnsafeEval,
|
|
103
96
|
});
|
|
104
97
|
if (!tree) {
|
|
105
98
|
fail("Dev.debug2: expression did not evaluate to a maplike resource tree");
|
|
@@ -118,6 +111,8 @@ async function evaluateExpression() {
|
|
|
118
111
|
} catch {
|
|
119
112
|
// Ignore errors.
|
|
120
113
|
}
|
|
114
|
+
|
|
115
|
+
process.send?.({ type: "EVALUATED" });
|
|
121
116
|
}
|
|
122
117
|
|
|
123
118
|
function maybeFinishDrain() {
|
|
@@ -1,29 +1,11 @@
|
|
|
1
1
|
// Subset of commands made available via debugTransform
|
|
2
2
|
|
|
3
3
|
import { Tree } from "@weborigami/async-tree";
|
|
4
|
+
export const keys = Tree.keys;
|
|
5
|
+
export const json = Tree.json;
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
import oriEval from "./oriEval.js";
|
|
11
|
-
|
|
12
|
-
export default function debugCommands(enableUnsafeEval = false) {
|
|
13
|
-
return Object.assign(
|
|
14
|
-
{
|
|
15
|
-
keys: Tree.keys,
|
|
16
|
-
json: Tree.json,
|
|
17
|
-
index,
|
|
18
|
-
yaml,
|
|
19
|
-
explore,
|
|
20
|
-
svg,
|
|
21
|
-
version,
|
|
22
|
-
},
|
|
23
|
-
enableUnsafeEval
|
|
24
|
-
? {
|
|
25
|
-
eval: oriEval,
|
|
26
|
-
}
|
|
27
|
-
: {},
|
|
28
|
-
);
|
|
29
|
-
}
|
|
7
|
+
export { default as index } from "../../origami/indexPage.js";
|
|
8
|
+
export { default as yaml } from "../../origami/yaml.js";
|
|
9
|
+
export { default as explore } from "../explore.js";
|
|
10
|
+
export { default as svg } from "../svg.js";
|
|
11
|
+
export { default as version } from "../version.js";
|