@weborigami/origami 0.6.14 → 0.6.16
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 +3 -0
- package/package.json +4 -3
- package/src/common/findOpenPort.js +58 -0
- package/src/dev/debug2/debug2.js +30 -300
- package/src/dev/debug2/debugChild.js +11 -4
- package/src/dev/debug2/debugCommands.js +11 -0
- package/src/dev/debug2/debugParent.js +369 -0
- package/src/dev/debug2/debugTransform.js +37 -25
- package/src/dev/debug2/expressionTree.js +6 -3
- package/src/dev/debug2/oriEval.js +49 -0
- package/src/dev/help.yaml +12 -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/htmlParse.js +22 -0
- package/src/origami/mdOutline.js +17 -5
- package/src/origami/origami.js +2 -1
- package/src/origami/xmlParse.js +33 -0
- package/src/server/server.js +30 -6
- package/src/origami/htmlDom.js +0 -14
package/main.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
export { default as documentObject } from "./src/common/documentObject.js";
|
|
2
2
|
export * from "./src/common/serialize.js";
|
|
3
|
+
export { default as debugParent } from "./src/dev/debug2/debugParent.js";
|
|
4
|
+
export { default as debugTransform } from "./src/dev/debug2/debugTransform.js";
|
|
3
5
|
export * as Dev from "./src/dev/dev.js";
|
|
6
|
+
export * from "./src/handlers/origamiHandlers.js";
|
|
4
7
|
export * as Origami from "./src/origami/origami.js";
|
|
5
8
|
export { default as origamiHighlightDefinition } from "./src/origami/origamiHighlightDefinition.js";
|
|
6
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.16",
|
|
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.16",
|
|
22
22
|
"@weborigami/json-feed-to-rss": "1.0.1",
|
|
23
|
-
"@weborigami/language": "0.6.
|
|
23
|
+
"@weborigami/language": "0.6.16",
|
|
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
|
+
}
|
package/src/dev/debug2/debug2.js
CHANGED
|
@@ -1,37 +1,20 @@
|
|
|
1
1
|
import { OrigamiFileMap } from "@weborigami/language";
|
|
2
|
-
import { fork } from "node:child_process";
|
|
3
|
-
import http from "node:http";
|
|
4
|
-
import net from "node:net";
|
|
5
2
|
import path from "node:path";
|
|
6
|
-
|
|
7
|
-
const PUBLIC_HOST = "127.0.0.1";
|
|
8
|
-
const DEFAULT_PORT = 5000;
|
|
9
|
-
|
|
10
|
-
// Module that loads the server in the child process
|
|
11
|
-
const childModuleUrl = new URL("./debugChild.js", import.meta.url);
|
|
12
|
-
|
|
13
|
-
// The active child process and port
|
|
14
|
-
/** @typedef {import("node:child_process").ChildProcess} ChildProcess */
|
|
15
|
-
/** @typedef {{ process: ChildProcess, port: number | null }} ChildInfo */
|
|
16
|
-
/** @type {ChildInfo | null} */
|
|
17
|
-
let activeChild = null;
|
|
18
|
-
|
|
19
|
-
// The most recently started child (may not be ready yet)
|
|
20
|
-
/** @type {ChildInfo | null} */
|
|
21
|
-
let pendingChild = null;
|
|
3
|
+
import debugParent from "./debugParent.js";
|
|
22
4
|
|
|
23
5
|
/**
|
|
24
|
-
* Given an Origami
|
|
25
|
-
*
|
|
26
|
-
*
|
|
6
|
+
* Given an Origami expression, start a new debug server with that parent as the
|
|
7
|
+
* root of the resource tree.
|
|
8
|
+
*
|
|
9
|
+
* This function expects unevaluated arguments. This is what it allows it to
|
|
10
|
+
* extract the source code of the expression to be debugged. (If it were
|
|
11
|
+
* evaluated, the function will be called with the result of the expression.)
|
|
27
12
|
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* arrangement ensures the expression is evaluated in a clean Node context (not
|
|
31
|
-
* polluted by previous evaluations).
|
|
13
|
+
* @typedef {import("@weborigami/language").RuntimeState} RuntimeState
|
|
14
|
+
* @typedef {import("@weborigami/language").AnnotatedCode} AnnotatedCode
|
|
32
15
|
*
|
|
33
|
-
* @param {
|
|
34
|
-
* @param {
|
|
16
|
+
* @param {AnnotatedCode} code
|
|
17
|
+
* @param {RuntimeState} state
|
|
35
18
|
*/
|
|
36
19
|
export default async function debug2(code, state) {
|
|
37
20
|
if (
|
|
@@ -43,6 +26,9 @@ export default async function debug2(code, state) {
|
|
|
43
26
|
"Dev.debug2 expects an Origami expression to evaluate: `debug2 <expression>`",
|
|
44
27
|
);
|
|
45
28
|
}
|
|
29
|
+
|
|
30
|
+
const expression = code.source;
|
|
31
|
+
|
|
46
32
|
const { parent } = state;
|
|
47
33
|
// @ts-ignore
|
|
48
34
|
const parentPath = parent?.path;
|
|
@@ -50,301 +36,45 @@ export default async function debug2(code, state) {
|
|
|
50
36
|
throw new Error("Dev.debug2 couldn't work out the parent path.");
|
|
51
37
|
}
|
|
52
38
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
39
|
+
// Start the debug server
|
|
40
|
+
const server = await debugParent({
|
|
41
|
+
expression,
|
|
42
|
+
parentPath,
|
|
43
|
+
});
|
|
57
44
|
|
|
45
|
+
// Watch the parent files for changes
|
|
58
46
|
const tree = new OrigamiFileMap(parentPath);
|
|
59
47
|
tree.watch();
|
|
60
|
-
tree.addEventListener?.("change", (event) => {
|
|
48
|
+
tree.addEventListener?.("change", async (event) => {
|
|
61
49
|
// @ts-ignore
|
|
62
50
|
const { filePath } = event.options;
|
|
63
51
|
if (isJavaScriptFile(filePath)) {
|
|
64
52
|
// Need to restart the child process
|
|
65
53
|
console.log("JavaScript file changed, restarting server…");
|
|
66
|
-
|
|
67
|
-
} else if (
|
|
54
|
+
await server.restart();
|
|
55
|
+
} else if (path.basename(filePath) === "package.json") {
|
|
68
56
|
// Need to restart the child process
|
|
69
57
|
console.log("package.json changed, restarting server…");
|
|
70
|
-
|
|
58
|
+
await server.restart();
|
|
71
59
|
} else {
|
|
72
60
|
// Just have the child reevaluate the expression
|
|
73
61
|
console.log("File changed, reloading site…");
|
|
74
|
-
|
|
62
|
+
await server.reevaluate();
|
|
75
63
|
}
|
|
76
64
|
});
|
|
77
65
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const publicServer = http.createServer(proxyRequest);
|
|
82
|
-
publicServer.listen(port, PUBLIC_HOST, () => {
|
|
83
|
-
startChild(serverOptions);
|
|
84
|
-
console.log(
|
|
85
|
-
`Server running at http://localhost:${port}. Press Ctrl+C to stop.`,
|
|
86
|
-
);
|
|
66
|
+
// When server closes, stop watching for file changes
|
|
67
|
+
server.on("close", () => {
|
|
68
|
+
tree.unwatch();
|
|
87
69
|
});
|
|
70
|
+
|
|
71
|
+
console.log(`Server running at ${server.origin}. Press Ctrl+C to stop.`);
|
|
88
72
|
}
|
|
89
73
|
debug2.needsState = true;
|
|
90
74
|
debug2.unevaluatedArgs = true;
|
|
91
75
|
|
|
92
|
-
/**
|
|
93
|
-
* Give a child process a chance to finish any in-flight requests before we kill
|
|
94
|
-
* it.
|
|
95
|
-
*
|
|
96
|
-
* @param {ChildProcess} childProcess
|
|
97
|
-
*/
|
|
98
|
-
async function drainAndStopChild(childProcess) {
|
|
99
|
-
if (childProcess.killed) {
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// Ask it to drain first.
|
|
104
|
-
try {
|
|
105
|
-
childProcess.send({ type: "DRAIN" });
|
|
106
|
-
} catch {
|
|
107
|
-
// ignore
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const drained = new Promise((resolve) => {
|
|
111
|
-
const onMessage = (msg) => {
|
|
112
|
-
if (msg && typeof msg === "object" && msg.type === "DRAINED") {
|
|
113
|
-
cleanup(resolve);
|
|
114
|
-
}
|
|
115
|
-
};
|
|
116
|
-
const onExit = () => cleanup(resolve);
|
|
117
|
-
|
|
118
|
-
function cleanup(done) {
|
|
119
|
-
childProcess.off("message", onMessage);
|
|
120
|
-
childProcess.off("exit", onExit);
|
|
121
|
-
done();
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
childProcess.on("message", onMessage);
|
|
125
|
-
childProcess.on("exit", onExit);
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
// Give it a short grace window to finish in-flight work.
|
|
129
|
-
const GRACE_MS = 1500;
|
|
130
|
-
await Promise.race([
|
|
131
|
-
drained,
|
|
132
|
-
new Promise((r) => setTimeout(r, GRACE_MS).unref()),
|
|
133
|
-
]);
|
|
134
|
-
|
|
135
|
-
if (!childProcess.killed) {
|
|
136
|
-
childProcess.kill("SIGTERM");
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// Final escalation.
|
|
140
|
-
setTimeout(() => {
|
|
141
|
-
// Child should have exited by now, but if not kill it
|
|
142
|
-
if (!childProcess.killed) {
|
|
143
|
-
childProcess.kill("SIGKILL");
|
|
144
|
-
}
|
|
145
|
-
}, GRACE_MS).unref();
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// Return the first open port number on or after the given port number.
|
|
149
|
-
async function findOpenPort(host, startPort = DEFAULT_PORT) {
|
|
150
|
-
for (let port = startPort; port <= 65535; port++) {
|
|
151
|
-
const open = await isPortAvailable(host, port);
|
|
152
|
-
if (open) {
|
|
153
|
-
return port;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
throw new Error(`No open port found on or after ${startPort}`);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
76
|
function isJavaScriptFile(filePath) {
|
|
161
77
|
const extname = path.extname(filePath).toLowerCase();
|
|
162
78
|
const jsExtensions = [".cjs", ".js", ".mjs", ".ts"];
|
|
163
79
|
return jsExtensions.includes(extname);
|
|
164
80
|
}
|
|
165
|
-
|
|
166
|
-
function isPackageJsonFile(filePath) {
|
|
167
|
-
return path.basename(filePath).toLowerCase() === "package.json";
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* Check whether a TCP port can be bound.
|
|
172
|
-
*
|
|
173
|
-
* @param {string} host
|
|
174
|
-
* @param {number} port
|
|
175
|
-
* @returns {Promise<boolean>}
|
|
176
|
-
*/
|
|
177
|
-
async function isPortAvailable(host, port) {
|
|
178
|
-
return new Promise((resolve) => {
|
|
179
|
-
const server = net.createServer();
|
|
180
|
-
|
|
181
|
-
server.unref();
|
|
182
|
-
|
|
183
|
-
server.once("error", (/** @type {any} */ error) => {
|
|
184
|
-
// Port is unavailable or cannot be bound on this host.
|
|
185
|
-
if (
|
|
186
|
-
error.code === "EADDRINUSE" ||
|
|
187
|
-
error.code === "EACCES" ||
|
|
188
|
-
error.code === "EADDRNOTAVAIL"
|
|
189
|
-
) {
|
|
190
|
-
resolve(false);
|
|
191
|
-
} else {
|
|
192
|
-
resolve(false);
|
|
193
|
-
}
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
server.once("listening", () => {
|
|
197
|
-
server.close(() => resolve(true));
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
server.listen(port, host);
|
|
201
|
-
});
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* Proxy incoming requests to the active child server, or return a 503 if not
|
|
206
|
-
* ready.
|
|
207
|
-
*
|
|
208
|
-
* @param {import("node:http").IncomingMessage} request
|
|
209
|
-
* @param {import("node:http").ServerResponse} response
|
|
210
|
-
*/
|
|
211
|
-
function proxyRequest(request, response) {
|
|
212
|
-
if (!activeChild) {
|
|
213
|
-
response.statusCode = 503;
|
|
214
|
-
response.setHeader("content-type", "text/plain; charset=utf-8");
|
|
215
|
-
response.end("Dev server is starting…\n");
|
|
216
|
-
return;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
const { port } = activeChild;
|
|
220
|
-
|
|
221
|
-
// Minimal hop-by-hop header stripping
|
|
222
|
-
const headers = { ...request.headers };
|
|
223
|
-
delete headers.connection;
|
|
224
|
-
delete headers["proxy-connection"];
|
|
225
|
-
delete headers["keep-alive"];
|
|
226
|
-
delete headers.te;
|
|
227
|
-
delete headers.trailer;
|
|
228
|
-
delete headers["transfer-encoding"];
|
|
229
|
-
delete headers.upgrade;
|
|
230
|
-
|
|
231
|
-
const upstreamRequest = http.request(
|
|
232
|
-
{
|
|
233
|
-
host: PUBLIC_HOST,
|
|
234
|
-
port,
|
|
235
|
-
method: request.method,
|
|
236
|
-
path: request.url,
|
|
237
|
-
headers,
|
|
238
|
-
},
|
|
239
|
-
(upstreamResponse) => {
|
|
240
|
-
response.writeHead(
|
|
241
|
-
upstreamResponse.statusCode ?? 502,
|
|
242
|
-
upstreamResponse.statusMessage,
|
|
243
|
-
upstreamResponse.headers,
|
|
244
|
-
);
|
|
245
|
-
upstreamResponse.pipe(response);
|
|
246
|
-
},
|
|
247
|
-
);
|
|
248
|
-
|
|
249
|
-
upstreamRequest.on("error", (err) => {
|
|
250
|
-
// Stop piping the request body
|
|
251
|
-
request.unpipe(upstreamRequest);
|
|
252
|
-
upstreamRequest.destroy();
|
|
253
|
-
|
|
254
|
-
// Only send error response if headers haven't been sent yet
|
|
255
|
-
if (!response.headersSent) {
|
|
256
|
-
response.statusCode = 502;
|
|
257
|
-
response.setHeader("content-type", "text/plain; charset=utf-8");
|
|
258
|
-
response.end(`Upstream error: ${err.message}\n`);
|
|
259
|
-
} else {
|
|
260
|
-
// Headers already sent, can't send error message - just close
|
|
261
|
-
response.destroy();
|
|
262
|
-
}
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
// Also handle errors on the incoming request
|
|
266
|
-
request.on("error", () => {
|
|
267
|
-
upstreamRequest.destroy();
|
|
268
|
-
});
|
|
269
|
-
|
|
270
|
-
request.pipe(upstreamRequest);
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
/**
|
|
274
|
-
* Start a new child process.
|
|
275
|
-
*
|
|
276
|
-
* This will be a pending process until it sends a READY message, at which point
|
|
277
|
-
* it becomes active and any previous active child is drained and stopped.
|
|
278
|
-
*/
|
|
279
|
-
function startChild(serverOptions) {
|
|
280
|
-
const { expression, parent } = serverOptions;
|
|
281
|
-
|
|
282
|
-
// Start the child process, passing parent path via an environment variable.
|
|
283
|
-
/** @type {ChildProcess} */
|
|
284
|
-
let childProcess;
|
|
285
|
-
try {
|
|
286
|
-
childProcess = fork(childModuleUrl, [], {
|
|
287
|
-
stdio: ["inherit", "inherit", "inherit", "ipc"],
|
|
288
|
-
env: {
|
|
289
|
-
...process.env,
|
|
290
|
-
ORIGAMI_EXPRESSION: expression,
|
|
291
|
-
ORIGAMI_PARENT: parent,
|
|
292
|
-
},
|
|
293
|
-
});
|
|
294
|
-
} catch (error) {
|
|
295
|
-
throw new Error("Dev.debug2: failed to start child server:", {
|
|
296
|
-
cause: error,
|
|
297
|
-
});
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
// This becomes the pending child immediately
|
|
301
|
-
pendingChild = { process: childProcess, port: null };
|
|
302
|
-
|
|
303
|
-
// Listen for messages from the child about its status
|
|
304
|
-
childProcess.on("message", (/** @type {any} */ message) => {
|
|
305
|
-
if (!message || typeof message !== "object") {
|
|
306
|
-
return;
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
if (message.type === "READY" && typeof message.port === "number") {
|
|
310
|
-
// Only promote to active if this is still the pending child
|
|
311
|
-
if (pendingChild?.process === childProcess) {
|
|
312
|
-
const previousChild = activeChild;
|
|
313
|
-
|
|
314
|
-
activeChild = pendingChild;
|
|
315
|
-
pendingChild.port = message.port;
|
|
316
|
-
pendingChild = null;
|
|
317
|
-
|
|
318
|
-
// Drain previous child in background (don't wait)
|
|
319
|
-
if (previousChild?.process && previousChild.process !== childProcess) {
|
|
320
|
-
drainAndStopChild(previousChild.process).catch((err) =>
|
|
321
|
-
console.error("[drain]", err),
|
|
322
|
-
);
|
|
323
|
-
}
|
|
324
|
-
} else {
|
|
325
|
-
// This child was superseded by a newer one, kill it
|
|
326
|
-
// console.log("Child process superseded by newer one, killing it...");
|
|
327
|
-
childProcess.kill("SIGTERM");
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
if (message.type === "FATAL") {
|
|
332
|
-
// Child couldn't start (import error, etc.)
|
|
333
|
-
// Keep previous active child if any; otherwise we'll serve 500/503.
|
|
334
|
-
console.error("[child fatal]", message.error ?? message);
|
|
335
|
-
if (pendingChild?.process === childProcess) {
|
|
336
|
-
pendingChild = null;
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
});
|
|
340
|
-
|
|
341
|
-
childProcess.on("exit", (code, signal) => {
|
|
342
|
-
if (activeChild?.process === childProcess) {
|
|
343
|
-
// Active child died unexpectedly.
|
|
344
|
-
activeChild = null;
|
|
345
|
-
}
|
|
346
|
-
if (pendingChild?.process === childProcess) {
|
|
347
|
-
pendingChild = null;
|
|
348
|
-
}
|
|
349
|
-
});
|
|
350
|
-
}
|
|
@@ -3,7 +3,7 @@ import { requestListener } from "../../server/server.js";
|
|
|
3
3
|
import expressionTree from "./expressionTree.js";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* The
|
|
6
|
+
* The debug parent runs this module in a child process, passing in a parent
|
|
7
7
|
* path in an environment variable.
|
|
8
8
|
*
|
|
9
9
|
* This module starts an HTTP server that will serve resources from that tree.
|
|
@@ -31,11 +31,13 @@ if (expression === undefined) {
|
|
|
31
31
|
|
|
32
32
|
/** @type {string} */
|
|
33
33
|
// @ts-ignore
|
|
34
|
-
const parentPath = process.env.
|
|
34
|
+
const parentPath = process.env.ORIGAMI_PARENT_PATH;
|
|
35
35
|
if (parentPath === undefined) {
|
|
36
36
|
fail("Missing Origami parent");
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
const quiet = process.env.ORIGAMI_QUIET === "1";
|
|
40
|
+
|
|
39
41
|
// An indirect pointer to the tree of resources;
|
|
40
42
|
let treeHandle = {};
|
|
41
43
|
|
|
@@ -43,7 +45,7 @@ let treeHandle = {};
|
|
|
43
45
|
await evaluateExpression();
|
|
44
46
|
|
|
45
47
|
// Serve the tree of resources
|
|
46
|
-
const listener = requestListener(treeHandle);
|
|
48
|
+
const listener = requestListener(treeHandle, { quiet });
|
|
47
49
|
const server = http.createServer(listener);
|
|
48
50
|
|
|
49
51
|
// Track live connections so we can drain/close cleanly.
|
|
@@ -88,7 +90,10 @@ function beginDrain() {
|
|
|
88
90
|
}
|
|
89
91
|
|
|
90
92
|
async function evaluateExpression() {
|
|
91
|
-
const tree = await expressionTree(
|
|
93
|
+
const tree = await expressionTree({
|
|
94
|
+
expression,
|
|
95
|
+
parentPath,
|
|
96
|
+
});
|
|
92
97
|
if (!tree) {
|
|
93
98
|
fail("Dev.debug2: expression did not evaluate to a maplike resource tree");
|
|
94
99
|
}
|
|
@@ -106,6 +111,8 @@ async function evaluateExpression() {
|
|
|
106
111
|
} catch {
|
|
107
112
|
// Ignore errors.
|
|
108
113
|
}
|
|
114
|
+
|
|
115
|
+
process.send?.({ type: "EVALUATED" });
|
|
109
116
|
}
|
|
110
117
|
|
|
111
118
|
function maybeFinishDrain() {
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Subset of commands made available via debugTransform
|
|
2
|
+
|
|
3
|
+
import { Tree } from "@weborigami/async-tree";
|
|
4
|
+
export const keys = Tree.keys;
|
|
5
|
+
export const json = Tree.json;
|
|
6
|
+
|
|
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";
|