@weborigami/origami 0.6.17 → 0.7.0-beta.2
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/package.json +13 -13
- package/src/cli/cli.js +10 -5
- package/src/common/documentObject.js +26 -0
- package/src/common/serialize.js +3 -0
- package/src/dev/OriCommandTransform.js +3 -3
- package/src/dev/changes.js +15 -52
- package/src/dev/debug2/debug2.js +0 -34
- package/src/dev/debug2/debugChild.js +73 -43
- package/src/dev/debug2/debugCommands.js +1 -0
- package/src/dev/debug2/debugParent.js +30 -42
- package/src/dev/debug2/debugTransform.js +32 -20
- package/src/dev/debug2/expressionTree.js +10 -6
- package/src/dev/debug2/oriEval.js +2 -2
- package/src/dev/dev.js +1 -1
- package/src/dev/explore.js +1 -0
- package/src/dev/help.yaml +23 -11
- package/src/dev/syscache.js +56 -0
- package/src/handlers/xml_handler.js +1 -1
- package/src/origami/{domNodeToObject.js → domObject.js} +16 -4
- package/src/origami/fetch.js +1 -22
- package/src/origami/htmlDom.js +24 -0
- package/src/origami/htmlParse.js +6 -13
- package/src/origami/once.js +4 -1
- package/src/origami/ori.js +10 -11
- package/src/origami/origami.js +4 -1
- package/src/origami/volatile.js +1 -0
- package/src/origami/xmlDom.js +32 -0
- package/src/origami/xmlParse.js +6 -24
- package/src/server/constructResponse.js +49 -12
- package/src/server/server.js +69 -42
- package/src/dev/changes2.js +0 -38
- package/src/origami/project.js +0 -6
package/src/server/server.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
|
-
TraverseError,
|
|
3
|
-
Tree,
|
|
4
2
|
keysFromPath,
|
|
5
3
|
trailingSlash,
|
|
4
|
+
TraverseError,
|
|
5
|
+
Tree,
|
|
6
6
|
} from "@weborigami/async-tree";
|
|
7
|
-
import { formatError } from "@weborigami/language";
|
|
7
|
+
import { formatError, systemCache, SystemCacheMap } from "@weborigami/language";
|
|
8
8
|
import { ServerResponse } from "node:http";
|
|
9
9
|
import constructResponse from "./constructResponse.js";
|
|
10
10
|
import parsePostData from "./parsePostData.js";
|
|
@@ -13,35 +13,30 @@ import parsePostData from "./parsePostData.js";
|
|
|
13
13
|
* Copy a constructed response to a ServerResponse. Return true if the response
|
|
14
14
|
* was successfully copied, and false if there was a problem.
|
|
15
15
|
*
|
|
16
|
-
* @param {Response}
|
|
16
|
+
* @param {Response} original
|
|
17
17
|
* @param {ServerResponse} response
|
|
18
18
|
*/
|
|
19
|
-
async function copyResponse(
|
|
20
|
-
|
|
21
|
-
response.
|
|
19
|
+
async function copyResponse(original, response) {
|
|
20
|
+
const clone = original.clone();
|
|
21
|
+
response.statusCode = clone.status;
|
|
22
|
+
response.statusMessage = clone.statusText;
|
|
22
23
|
|
|
23
24
|
// @ts-ignore Headers has an iterator in ES2022 but tsc doesn't know that.
|
|
24
|
-
for (const [key, value] of
|
|
25
|
+
for (const [key, value] of clone.headers) {
|
|
25
26
|
response.setHeader(key, value);
|
|
26
27
|
}
|
|
27
28
|
|
|
28
|
-
if (
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
({ done, value } = await reader.read());
|
|
36
|
-
}
|
|
37
|
-
response.end();
|
|
38
|
-
} catch (/** @type {any} */ error) {
|
|
39
|
-
console.error(error.message);
|
|
40
|
-
return false;
|
|
29
|
+
if (clone.body) {
|
|
30
|
+
// Write the response body
|
|
31
|
+
const reader = clone.body.getReader();
|
|
32
|
+
let { done, value } = await reader.read();
|
|
33
|
+
while (!done) {
|
|
34
|
+
response.write(value);
|
|
35
|
+
({ done, value } = await reader.read());
|
|
41
36
|
}
|
|
42
37
|
}
|
|
43
38
|
|
|
44
|
-
|
|
39
|
+
response.end();
|
|
45
40
|
}
|
|
46
41
|
|
|
47
42
|
/**
|
|
@@ -54,36 +49,68 @@ async function copyResponse(constructed, response) {
|
|
|
54
49
|
export async function handleRequest(request, response, map) {
|
|
55
50
|
// For parsing purposes, we assume HTTPS -- it doesn't affect parsing.
|
|
56
51
|
const url = new URL(request.url ?? "", `https://${request.headers.host}`);
|
|
57
|
-
const keys = keysFromUrl(url);
|
|
58
52
|
|
|
53
|
+
// Do we already have an ETag for this resource?
|
|
54
|
+
let cachePath = SystemCacheMap.joinPath("_site", url.pathname.slice(1));
|
|
55
|
+
if (url.pathname.endsWith("/")) {
|
|
56
|
+
cachePath += "index.html";
|
|
57
|
+
}
|
|
58
|
+
const cacheEntry = systemCache.get(cachePath)?.value;
|
|
59
|
+
const etag = cacheEntry?.headers?.get("Etag");
|
|
60
|
+
if (etag) {
|
|
61
|
+
// Does the client already have this version?
|
|
62
|
+
const ifNoneMatch = request?.headers?.["if-none-match"];
|
|
63
|
+
if (ifNoneMatch === etag) {
|
|
64
|
+
// Client already has this version
|
|
65
|
+
response.writeHead(304, {
|
|
66
|
+
"Cache-Control": "no-cache",
|
|
67
|
+
ETag: etag,
|
|
68
|
+
});
|
|
69
|
+
response.end();
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const keys = keysFromUrl(url);
|
|
59
75
|
const data = request.method === "POST" ? await parsePostData(request) : null;
|
|
60
76
|
|
|
61
77
|
// Ask the tree for the resource with those keys.
|
|
62
|
-
let resource;
|
|
63
78
|
try {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
//
|
|
67
|
-
//
|
|
68
|
-
|
|
69
|
-
|
|
79
|
+
// We wrap the tree traversal in a call that will both set the etag for this
|
|
80
|
+
// resource and copy the constructed response to the ServerResponse. The
|
|
81
|
+
// etag is already included in the response headers so we don't need to
|
|
82
|
+
// receive it here.
|
|
83
|
+
const constructed = await systemCache.getOrInsertComputedAsync(
|
|
84
|
+
cachePath,
|
|
85
|
+
async () => {
|
|
86
|
+
let resource = await Tree.traverseOrThrow(map, ...keys);
|
|
87
|
+
|
|
88
|
+
// If resource is a function, invoke to get the object we want to return.
|
|
89
|
+
// For a POST request, pass the data to the function.
|
|
90
|
+
if (typeof resource === "function") {
|
|
91
|
+
resource = data ? await resource(data) : await resource();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Construct the response
|
|
95
|
+
return resource != null
|
|
96
|
+
? await constructResponse(request, resource)
|
|
97
|
+
: null;
|
|
98
|
+
},
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
// Copy the constructed (and cached) response to the server response
|
|
102
|
+
if (constructed) {
|
|
103
|
+
await copyResponse(constructed, response);
|
|
104
|
+
return true;
|
|
70
105
|
}
|
|
71
|
-
|
|
72
|
-
if (resource == null) {
|
|
73
|
-
return false;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Construct the response.
|
|
77
|
-
const constructed = await constructResponse(request, resource);
|
|
78
|
-
|
|
79
|
-
// Copy the construct response to the ServerResponse and return true if
|
|
80
|
-
// the response was valid.
|
|
81
|
-
return copyResponse(constructed, response);
|
|
82
106
|
} catch (/** @type {any} */ error) {
|
|
83
107
|
// Display an error
|
|
84
|
-
respondWithError(response, error);
|
|
108
|
+
await respondWithError(response, error);
|
|
85
109
|
return true;
|
|
86
110
|
}
|
|
111
|
+
|
|
112
|
+
// No resource found at this path.
|
|
113
|
+
return false;
|
|
87
114
|
}
|
|
88
115
|
|
|
89
116
|
export function keysFromUrl(url) {
|
package/src/dev/changes2.js
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
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
|
-
}
|