@weborigami/origami 0.5.8 → 0.6.1

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.
@@ -1,43 +1,68 @@
1
- import { Tree, getTreeArgument, jsonKeys } from "@weborigami/async-tree";
1
+ import {
2
+ AsyncMap,
3
+ Tree,
4
+ getTreeArgument,
5
+ jsonKeys,
6
+ } from "@weborigami/async-tree";
2
7
  import indexPage from "./indexPage.js";
3
8
 
4
9
  /**
5
10
  * Expose common static keys (index.html, .keys.json) for a tree.
6
11
  *
7
- * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
8
- * @typedef {import("@weborigami/async-tree").Treelike} Treelike
12
+ * @typedef {import("@weborigami/async-tree").Maplike} Maplike
9
13
  *
10
- * @param {Treelike} treelike
11
- * @returns {Promise<AsyncTree>}
14
+ * @param {Maplike} maplike
15
+ * @returns {Promise<AsyncMap>}
12
16
  */
13
- export default async function staticBuiltin(treelike) {
14
- const tree = await getTreeArgument(treelike, "static");
15
- return staticTree(tree);
17
+ export default async function staticBuiltin(maplike) {
18
+ const source = await getTreeArgument(maplike, "static");
19
+ return staticMap(source);
16
20
  }
17
21
 
18
22
  // The name we'll register as a builtin
19
23
  staticBuiltin.key = "static";
20
24
 
21
- function staticTree(tree) {
22
- return Object.assign(Object.create(tree), {
25
+ function staticMap(source) {
26
+ const result = Object.assign(new AsyncMap(), {
27
+ description: "static",
28
+
23
29
  async get(key) {
24
- let value = await tree.get(key);
30
+ let value = await source.get(key);
25
31
  if (value === undefined && key === "index.html") {
26
32
  value = await indexPage(this);
27
33
  } else if (value === undefined && key === ".keys.json") {
28
34
  value = await jsonKeys.stringify(this);
29
- } else if (Tree.isTreelike(value)) {
30
- const subtree = Tree.from(value, { parent: this });
31
- value = staticTree(subtree);
35
+ } else if (Tree.isMaplike(value)) {
36
+ const subtree = Tree.from(value, { parent: result });
37
+ value = staticMap(subtree);
32
38
  }
33
39
  return value;
34
40
  },
35
41
 
36
- async keys() {
37
- const keys = new Set(await tree.keys());
38
- keys.add("index.html");
39
- keys.add(".keys.json");
40
- return keys;
42
+ async *keys() {
43
+ let needsIndex = true;
44
+ let needsKeysJson = true;
45
+ for await (const key of source.keys()) {
46
+ if (key === "index.html") {
47
+ needsIndex = false;
48
+ }
49
+ if (key === ".keys.json") {
50
+ needsKeysJson = false;
51
+ }
52
+ yield key;
53
+ }
54
+ if (needsIndex) {
55
+ yield "index.html";
56
+ }
57
+ if (needsKeysJson) {
58
+ yield ".keys.json";
59
+ }
41
60
  },
61
+
62
+ source: source,
63
+
64
+ trailingSlashKeys: source.trailingSlashKeys,
42
65
  });
66
+
67
+ return result;
43
68
  }
@@ -5,5 +5,8 @@
5
5
  * @param {any} obj
6
6
  */
7
7
  export default function unpack(obj) {
8
- return obj?.unpack?.() ?? obj;
8
+ if (obj == null) {
9
+ throw new ReferenceError("Cannot unpack null or undefined value");
10
+ }
11
+ return obj.unpack?.() ?? obj;
9
12
  }
@@ -1,4 +1,3 @@
1
- /** @typedef {import("@weborigami/types").AsyncTree} AsyncTree */
2
1
  import { isUnpackable, toPlainValue } from "@weborigami/async-tree";
3
2
  import YAML from "yaml";
4
3
 
@@ -3,7 +3,7 @@ import {
3
3
  isPacked,
4
4
  isPlainObject,
5
5
  isStringlike,
6
- SiteTree,
6
+ SiteMap,
7
7
  toString,
8
8
  Tree,
9
9
  } from "@weborigami/async-tree";
@@ -30,8 +30,8 @@ export default async function constructResponse(request, resource) {
30
30
  // Determine media type, what data we'll send, and encoding.
31
31
  const url = new URL(request.url ?? "", `https://${request.headers.host}`);
32
32
 
33
- if (!url.pathname.endsWith("/") && Tree.isTreelike(resource)) {
34
- // Treelike resource: redirect to its index page.
33
+ if (!url.pathname.endsWith("/") && Tree.isMaplike(resource)) {
34
+ // Maplike resource: redirect to its index page.
35
35
  const Location = `${url.pathname}/`;
36
36
  return new Response("ok", {
37
37
  headers: {
@@ -87,11 +87,11 @@ export default async function constructResponse(request, resource) {
87
87
  if (!mediaType) {
88
88
  // Maybe it's HTML?
89
89
  const text = toString(resource);
90
- if (text && maybeHtml(text)) {
91
- mediaType = "text/html";
90
+ if (text) {
91
+ mediaType = maybeHtml(text) ? "text/html" : "text/plain";
92
92
  body = text;
93
93
  }
94
- } else if (mediaType && SiteTree.mediaTypeIsText(mediaType)) {
94
+ } else if (mediaType && SiteMap.mediaTypeIsText(mediaType)) {
95
95
  // Assume text is encoded in UTF-8.
96
96
  body = toString(resource);
97
97
  mediaType += "; charset=utf-8";
@@ -44,9 +44,9 @@ async function copyResponse(constructed, response) {
44
44
  *
45
45
  * @param {import("node:http").IncomingMessage} request
46
46
  * @param {ServerResponse} response
47
- * @param {import("@weborigami/types").AsyncTree} tree
47
+ * @param {import("@weborigami/async-tree").SyncOrAsyncMap} map
48
48
  */
49
- export async function handleRequest(request, response, tree) {
49
+ export async function handleRequest(request, response, map) {
50
50
  // For parsing purposes, we assume HTTPS -- it doesn't affect parsing.
51
51
  const url = new URL(request.url ?? "", `https://${request.headers.host}`);
52
52
  const keys = keysFromUrl(url);
@@ -56,7 +56,7 @@ export async function handleRequest(request, response, tree) {
56
56
  // Ask the tree for the resource with those keys.
57
57
  let resource;
58
58
  try {
59
- resource = await Tree.traverseOrThrow(tree, ...keys);
59
+ resource = await Tree.traverseOrThrow(map, ...keys);
60
60
 
61
61
  // If resource is a function, invoke to get the object we want to return.
62
62
  // For a POST request, pass the data to the function.
@@ -97,11 +97,11 @@ function keysFromUrl(url) {
97
97
  * A request listener for use with the node http.createServer and
98
98
  * https.createServer calls, letting you serve an async tree as a set of pages.
99
99
  *
100
- * @typedef {import("@weborigami/async-tree").Treelike} Treelike
101
- * @param {Treelike} treelike
100
+ * @typedef {import("@weborigami/async-tree").Maplike} Maplike
101
+ * @param {Maplike} maplike
102
102
  */
103
- export function requestListener(treelike) {
104
- const tree = Tree.from(treelike);
103
+ export function requestListener(maplike) {
104
+ const tree = Tree.from(maplike);
105
105
  return async function (request, response) {
106
106
  console.log(decodeURI(request.url));
107
107
  const handled = await handleRequest(request, response, tree);
@@ -142,8 +142,8 @@ ${message}
142
142
  }
143
143
 
144
144
  // Asynchronous tree router as Express middleware.
145
- export function treeRouter(treelike) {
146
- const tree = Tree.from(treelike, { deep: true });
145
+ export function treeRouter(maplike) {
146
+ const tree = Tree.from(maplike, { deep: true });
147
147
  // Return a router for the tree source.
148
148
  return async function (request, response, next) {
149
149
  const handled = await handleRequest(request, response, tree);
@@ -1,67 +0,0 @@
1
- import { Tree, isUnpackable } from "@weborigami/async-tree";
2
- import assertTreeIsDefined from "./assertTreeIsDefined.js";
3
-
4
- /**
5
- * Many Origami built-in functions accept an optional treelike object as their
6
- * first argument. If no tree is supplied, then the current context for the
7
- * Origami command is used as the tree.
8
- *
9
- * So the argument is optional -- but if supplied, it must be defined. The
10
- * caller should pass its `arguments` object to this function so that the actual
11
- * number of supplied arguments can be checked.
12
- *
13
- * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
14
- * @typedef {import("@weborigami/async-tree").Treelike} Treelike
15
- *
16
- * @param {AsyncTree|null} parent
17
- * @param {IArguments} args
18
- * @param {Treelike|undefined} treelike
19
- * @param {string} methodName
20
- * @param {boolean} [deep]
21
- * @returns {Promise<AsyncTree>}
22
- */
23
- export default async function getTreeArgument(
24
- parent,
25
- args,
26
- treelike,
27
- methodName,
28
- deep
29
- ) {
30
- assertTreeIsDefined(parent, methodName);
31
-
32
- if (treelike !== undefined) {
33
- if (isUnpackable(treelike)) {
34
- treelike = await treelike.unpack();
35
- }
36
- if (Tree.isTreelike(treelike)) {
37
- const options = deep !== undefined ? { deep } : undefined;
38
- let tree = Tree.from(treelike, options);
39
- // If the tree was created from a treelike object and does not yet have a
40
- // parent, make the current tree its parent.
41
- if (!tree.parent && parent !== undefined) {
42
- if (parent !== null && !Tree.isAsyncTree(parent)) {
43
- throw new Error(
44
- `The parent argument passed to ${methodName} must be a tree.`
45
- );
46
- }
47
- tree.parent = parent;
48
- }
49
- return tree;
50
- }
51
- throw new Error(
52
- `The first argument to ${methodName} must be a tree, like an array, object, or files.`
53
- );
54
- }
55
-
56
- if (args.length === 0) {
57
- if (!parent) {
58
- // Should never happen because assertTreeIsDefined throws an exception.
59
- throw new Error(
60
- `${methodName} was called with no tree argument and no parent.`
61
- );
62
- }
63
- return parent;
64
- }
65
-
66
- throw new Error(`The first argument to ${methodName} was undefined.`);
67
- }