@weborigami/origami 0.5.7 → 0.6.0

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.
Files changed (41) hide show
  1. package/package.json +11 -12
  2. package/src/cli/cli.js +1 -1
  3. package/src/common/assertTreeIsDefined.js +1 -1
  4. package/src/common/documentObject.js +1 -8
  5. package/src/common/serialize.d.ts +4 -4
  6. package/src/common/serialize.js +20 -24
  7. package/src/dev/ExplorableSiteTransform.js +6 -4
  8. package/src/dev/OriCommandTransform.js +4 -4
  9. package/src/dev/changes.js +9 -9
  10. package/src/dev/code.js +0 -1
  11. package/src/dev/copy.js +32 -6
  12. package/src/dev/crawler/audit.js +5 -6
  13. package/src/dev/crawler/crawl.js +10 -11
  14. package/src/dev/crawler/crawlResources.js +1 -1
  15. package/src/dev/debug.js +12 -10
  16. package/src/dev/explore.js +4 -5
  17. package/src/dev/help.js +0 -1
  18. package/src/dev/help.yaml +57 -54
  19. package/src/dev/serve.js +4 -5
  20. package/src/dev/svg.js +4 -5
  21. package/src/dev/treeDot.js +6 -6
  22. package/src/dev/watch.js +8 -8
  23. package/src/origami/csv.js +1 -1
  24. package/src/origami/document.js +0 -1
  25. package/src/origami/indexPage.js +7 -8
  26. package/src/origami/inline.js +0 -1
  27. package/src/origami/json.js +0 -1
  28. package/src/origami/jsonKeys.js +29 -18
  29. package/src/origami/once.js +0 -1
  30. package/src/origami/ori.js +2 -3
  31. package/src/origami/origami.js +1 -0
  32. package/src/origami/pack.js +0 -1
  33. package/src/origami/post.js +1 -1
  34. package/src/origami/rss.js +2 -3
  35. package/src/origami/sitemap.js +9 -19
  36. package/src/origami/static.js +44 -19
  37. package/src/origami/tsv.js +43 -0
  38. package/src/origami/yaml.js +0 -1
  39. package/src/server/constructResponse.js +6 -6
  40. package/src/server/server.js +9 -9
  41. package/src/common/getTreeArgument.js +0 -67
package/src/dev/help.yaml CHANGED
@@ -167,8 +167,8 @@ Tree:
167
167
  description: Work with trees of files and data
168
168
  commands:
169
169
  addNextPrevious:
170
- args: (tree)
171
- description: Add next/previous fields to the tree's values
170
+ args: (map)
171
+ description: Add next/previous fields to the map's values
172
172
  assign:
173
173
  args: (target, source)
174
174
  description: Apply key/values from source to target
@@ -179,8 +179,8 @@ Tree:
179
179
  args: (options)
180
180
  description: Return a tree structure for years/months/days
181
181
  clear:
182
- args: (tree)
183
- description: Remove all values from the tree
182
+ args: (map)
183
+ description: Remove all values from the map
184
184
  constant:
185
185
  args: (value)
186
186
  description: Return a deep tree with a single constant value
@@ -203,68 +203,65 @@ Tree:
203
203
  args: (tree)
204
204
  description: The in-order leaf values of the tree
205
205
  delete:
206
- args: (tree, key)
207
- description: Delete the value for the key from tree
206
+ args: (map, key)
207
+ description: Delete the value for the key from map
208
208
  entries:
209
- args: (tree)
210
- description: The tree's [key, value] pairs
209
+ args: (map)
210
+ description: The map's [key, value] pairs
211
211
  filter:
212
- args: (source, options)
213
- description: Filter the source tree
212
+ args: (tree, options)
213
+ description: Filter a tree by a condition
214
214
  first:
215
- args: (tree)
216
- description: The first value in the tree
215
+ args: (map)
216
+ description: The first value in the map
217
217
  forEach:
218
- args: (tree, fn)
218
+ args: (map, fn)
219
219
  description: Apply fn to each (value, key)
220
220
  from:
221
221
  args: (object, options)
222
- description: Create a tree from an object
222
+ description: Create a map from an object
223
223
  globKeys:
224
224
  args: (patterns)
225
225
  description: A tree whose keys can include glob wildcard patterns
226
226
  groupBy:
227
- args: (tree, fn)
228
- description: A new tree with values grouped by the function
227
+ args: (map, fn)
228
+ description: A new map with values grouped by the function
229
229
  has:
230
- args: (tree, key)
231
- description: True if key exists in tree
230
+ args: (map, key)
231
+ description: True if key exists in map
232
232
  indent:
233
233
  args: "`…`"
234
234
  description: Tagged template literal for normalizing indentation
235
235
  inners:
236
236
  args: (tree)
237
237
  description: The tree's interior nodes
238
- isAsyncMutableTree:
238
+ isMap:
239
+ args: (object)
240
+ description: True if object is a map
241
+ isMaplike:
239
242
  args: (object)
240
- description: True if object is an async mutable tree
241
- isAsyncTree:
243
+ description: True if object can be coerced to a tree
244
+ isReadOnlyMap:
242
245
  args: (object)
243
- description: True if object is an async tree
246
+ description: True if object is a read-only map
244
247
  isTraversable:
245
248
  args: (object)
246
249
  description: True if object is traversable
247
- isTreelike:
248
- args: (object)
249
- description: True if object can be coerced to a tree
250
250
  json:
251
251
  args: (tree)
252
252
  description: Render the tree in JSON format
253
253
  keys:
254
- args: (tree)
255
- description: The keys of the tree
256
- length:
257
- args: (tree)
258
- description: The tree's size (number of keys)
254
+ args: (map)
255
+ description: The keys of the map
259
256
  map:
260
- args: (tree, options)
261
- description: Create a new tree by mapping keys and/or values
257
+ args: (source, options)
258
+ description: Create a new map by transforming keys and/or values
262
259
  mapExtension:
263
- args: (tree, ext, options)
264
- description: Map extensions and values
260
+ args: (source, ext, options)
261
+ description: Create a new map by transforming extensions
265
262
  mapReduce:
266
263
  args: (tree, mapFn, reduceFn)
267
- description: Map values and reduce them
264
+ description: Map the keys and/or values in a tree and reduce them
268
265
  mask:
269
266
  args: (source, mask)
270
267
  description: Return the source tree with only the keys in the mask
@@ -272,11 +269,11 @@ Tree:
272
269
  args: (pattern, fn, [keys])
273
270
  description: Matches simple patterns or regular expressions
274
271
  merge:
275
- args: (...trees)
276
- description: Return a new tree merging the given trees
272
+ args: (...maps)
273
+ description: Return a new tree merging the given maps
277
274
  paginate:
278
- args: (tree, [n])
279
- description: Group the tree's values into fixed-size sets
275
+ args: (map, [n])
276
+ description: Group the map's values into fixed-size sets
280
277
  parent:
281
278
  args: (tree)
282
279
  description: The parent of the given tree node
@@ -290,23 +287,29 @@ Tree:
290
287
  args: (tree)
291
288
  description: A tree whose keys are regular expression strings
292
289
  reverse:
293
- args: (tree)
294
- description: Reverse the order of the tree's keys
290
+ args: (map)
291
+ description: Reverse the order of the map's keys
295
292
  root:
296
293
  args: (tree)
297
294
  description: The root node of the given tree
298
- setDeep:
299
- args: (target, source)
300
- description: Applies the source tree to the target
301
- shuffle:
295
+ scope:
302
296
  args: (tree)
303
- description: Shuffle the keys of the tree
297
+ description: A merged view of the tree and its ancestors
298
+ shuffle:
299
+ args: (map)
300
+ description: Shuffle the keys of the map
301
+ size:
302
+ args: (map)
303
+ description: The map's size (number of keys)
304
304
  sort:
305
- args: (tree, options)
306
- description: A new tree with its keys sorted
305
+ args: (map, options)
306
+ description: A new map with its keys sorted
307
+ sync:
308
+ args: (tree)
309
+ description: Awaits all asynchronous values in the tree
307
310
  take:
308
- args: (tree, n)
309
- description: The first n values in the tree
311
+ args: (map, n)
312
+ description: The first n values in the map
310
313
  text:
311
314
  args: "`…`"
312
315
  description: Tagged template literal for rendering trees
@@ -320,8 +323,8 @@ Tree:
320
323
  args: (tree, path)
321
324
  description: Traverse a slash-separated path
322
325
  values:
323
- args: (tree)
324
- description: The tree's values
326
+ args: (map)
327
+ description: The map's values
325
328
  withKeys:
326
- args: (tree, keys)
327
- description: Use the given keys for the tree
329
+ args: (map, keys)
330
+ description: Use the given keys for the map
package/src/dev/serve.js CHANGED
@@ -11,14 +11,13 @@ const defaultPort = 5000;
11
11
  /**
12
12
  * Start a local web server for the indicated tree.
13
13
  *
14
- * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
15
- * @typedef {import("@weborigami/async-tree").Treelike} Treelike
14
+ * @typedef {import("@weborigami/async-tree").Maplike} Maplike
16
15
  *
17
- * @param {Treelike} treelike
16
+ * @param {Maplike} maplike
18
17
  * @param {number} [port]
19
18
  */
20
- export default async function serve(treelike, port) {
21
- let tree = await getTreeArgument(treelike, "serve");
19
+ export default async function serve(maplike, port) {
20
+ let tree = await getTreeArgument(maplike, "serve");
22
21
 
23
22
  if (!isTransformApplied(ExplorableSiteTransform, tree)) {
24
23
  tree = transformObject(ExplorableSiteTransform, tree);
package/src/dev/svg.js CHANGED
@@ -8,19 +8,18 @@ let graphvizLoaded = false;
8
8
  /**
9
9
  * Render a tree visually in SVG format.
10
10
  *
11
- * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
12
- * @typedef {import("@weborigami/async-tree").Treelike} Treelike
11
+ * @typedef {import("@weborigami/async-tree").Maplike} Maplike
13
12
  * @typedef {import("@weborigami/async-tree").PlainObject} PlainObject
14
13
  *
15
- * @param {Treelike} treelike
14
+ * @param {Maplike} maplike
16
15
  * @param {PlainObject} [options]
17
16
  */
18
- export default async function svg(treelike, options = {}) {
17
+ export default async function svg(maplike, options = {}) {
19
18
  if (!graphvizLoaded) {
20
19
  await graphviz.loadWASM();
21
20
  graphvizLoaded = true;
22
21
  }
23
- const tree = await getTreeArgument(treelike, "svg", { deep: true });
22
+ const tree = await getTreeArgument(maplike, "svg", { deep: true });
24
23
  const dotText = await dot(tree, options);
25
24
  if (dotText === undefined) {
26
25
  return undefined;
@@ -12,14 +12,14 @@ import { getDescriptor } from "../common/utilities.js";
12
12
  /**
13
13
  * Render a tree in DOT format.
14
14
  *
15
- * @typedef {import("@weborigami/async-tree").Treelike} Treelike
15
+ * @typedef {import("@weborigami/async-tree").Maplike} Maplike
16
16
  * @typedef {import("@weborigami/async-tree").PlainObject} PlainObject
17
17
  *
18
- * @param {Treelike} treelike
18
+ * @param {Maplike} maplike
19
19
  * @param {PlainObject} [options]
20
20
  */
21
- export default async function dot(treelike, options = {}) {
22
- const tree = await getTreeArgument(treelike, "treeDot", { deep: true });
21
+ export default async function dot(maplike, options = {}) {
22
+ const tree = await getTreeArgument(maplike, "treeDot", { deep: true });
23
23
  const rootLabel = getDescriptor(tree) ?? "";
24
24
  const treeArcs = await statements(tree, "", rootLabel, options);
25
25
  return `digraph g {
@@ -48,7 +48,7 @@ async function statements(tree, nodePath, nodeLabel, options) {
48
48
 
49
49
  // Draw edges and collect labels for the nodes they lead to.
50
50
  let nodes = new Map();
51
- for (const key of await tree.keys()) {
51
+ for (const key of await Tree.keys(tree)) {
52
52
  const destPath = nodePath ? `${trailingSlash.add(nodePath)}${key}` : key;
53
53
  const labelUrl = createLinks ? `; labelURL="${destPath}"` : "";
54
54
  const arc = ` "${nodePath}" -> "${destPath}" [label="${key}"${labelUrl}];`;
@@ -67,7 +67,7 @@ async function statements(tree, nodePath, nodeLabel, options) {
67
67
  }
68
68
 
69
69
  const expandable =
70
- value instanceof Array || isPlainObject(value) || Tree.isAsyncTree(value);
70
+ value instanceof Array || isPlainObject(value) || Tree.isMap(value);
71
71
  if (expandable) {
72
72
  const subtree = Tree.from(value);
73
73
  const subStatements = await statements(subtree, destPath, null, options);
package/src/dev/watch.js CHANGED
@@ -1,19 +1,19 @@
1
- import { constant, getTreeArgument, Tree } from "@weborigami/async-tree";
1
+ import { ConstantMap, getTreeArgument, Tree } from "@weborigami/async-tree";
2
2
  import { formatError, moduleCache } from "@weborigami/language";
3
3
 
4
4
  /**
5
5
  * Let a tree (e.g., of files) respond to changes.
6
6
  *
7
+ * @typedef {import("@weborigami/async-tree").AsyncMap} AsyncMap
7
8
  * @typedef {import("@weborigami/async-tree").Invocable} Invocable
8
- * @typedef {import("@weborigami/async-tree").Treelike} Treelike
9
- * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
9
+ * @typedef {import("@weborigami/async-tree").Maplike} Maplike
10
10
  *
11
- * @param {Treelike} treelike
11
+ * @param {Maplike} maplike
12
12
  * @param {Invocable} [fn]
13
- * @returns {Promise<AsyncTree>}
13
+ * @returns {Promise<Map|AsyncMap>}
14
14
  */
15
- export default async function watch(treelike, fn) {
16
- const container = await getTreeArgument(treelike, "watch");
15
+ export default async function watch(maplike, fn) {
16
+ const container = await getTreeArgument(maplike, "watch");
17
17
 
18
18
  // Watch the indicated tree.
19
19
  await /** @type {any} */ (container).watch?.();
@@ -58,7 +58,7 @@ async function evaluateTree(parent, fn) {
58
58
  message = `Warning: watch expression did not return a tree`;
59
59
  }
60
60
  console.warn(message);
61
- tree = constant(message);
61
+ tree = new ConstantMap(message);
62
62
  return tree;
63
63
  }
64
64
 
@@ -3,7 +3,7 @@ import { isUnpackable, toPlainValue } from "@weborigami/async-tree";
3
3
  /**
4
4
  * Render the object as text in CSV format.
5
5
  *
6
- * The object should a treelike object such as an array. The output will include
6
+ * The object should a maplike object such as an array. The output will include
7
7
  * a header row with field names taken from the first item in the tree/array.
8
8
  *
9
9
  * @param {any} object
@@ -1,7 +1,6 @@
1
1
  import documentObject from "../common/documentObject.js";
2
2
 
3
3
  /**
4
- * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
5
4
  * @typedef {import("@weborigami/async-tree").Stringlike} Stringlike
6
5
  *
7
6
  * @param {Stringlike} text
@@ -1,21 +1,20 @@
1
- import { getTreeArgument } from "@weborigami/async-tree";
1
+ import { getTreeArgument, Tree } from "@weborigami/async-tree";
2
2
  import { getDescriptor } from "../common/utilities.js";
3
3
 
4
4
  /**
5
5
  * Return a default index.html page for the current tree.
6
6
  *
7
- * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
8
- * @typedef {import("@weborigami/async-tree").Treelike} Treelike
7
+ * @typedef {import("@weborigami/async-tree").Maplike} Maplike
9
8
  *
10
- * @param {Treelike} treelike
9
+ * @param {Maplike} maplike
11
10
  * @param {string} [basePath]
12
11
  */
13
- export default async function indexPage(treelike, basePath) {
14
- const tree = await getTreeArgument(treelike, "svg");
15
- const keys = Array.from(await tree.keys());
12
+ export default async function indexPage(maplike, basePath) {
13
+ const tree = await getTreeArgument(maplike, "svg");
14
+ const treeKeys = await Tree.keys(tree);
16
15
 
17
16
  // Skip system-ish files that start with a period. Also skip `index.html`.
18
- const filtered = keys.filter(
17
+ const filtered = treeKeys.filter(
19
18
  (key) => !(key.startsWith?.(".") || key === "index.html")
20
19
  );
21
20
 
@@ -6,7 +6,6 @@ import documentObject from "../common/documentObject.js";
6
6
  * Inline any Origami expressions found inside ${...} placeholders in the input
7
7
  * text.
8
8
  *
9
- * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
10
9
  *
11
10
  * @param {any} input
12
11
  */
@@ -3,7 +3,6 @@ import { isUnpackable, toPlainValue } from "@weborigami/async-tree";
3
3
  /**
4
4
  * Render the given object in JSON format.
5
5
  *
6
- * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
7
6
  *
8
7
  * @param {any} [obj]
9
8
  */
@@ -1,36 +1,47 @@
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
 
3
8
  /**
4
9
  * Expose .keys.json for a tree.
5
10
  *
6
- * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
7
- * @typedef {import("@weborigami/async-tree").Treelike} Treelike
11
+ * @typedef {import("@weborigami/async-tree").Maplike} Maplike
8
12
  *
9
- * @param {Treelike} treelike
10
- * @returns {Promise<AsyncTree>}
13
+ * @param {Maplike} maplike
14
+ * @returns {Promise<AsyncMap>}
11
15
  */
12
- export default async function jsonKeysBuiltin(treelike) {
13
- const tree = await getTreeArgument(treelike, "jsonKeys");
14
- return jsonKeysTree(tree);
16
+ export default async function jsonKeysBuiltin(maplike) {
17
+ const source = await getTreeArgument(maplike, "jsonKeys");
18
+ return jsonKeysMap(source);
15
19
  }
16
20
 
17
- function jsonKeysTree(tree) {
18
- return Object.assign(Object.create(tree), {
21
+ function jsonKeysMap(source) {
22
+ const result = Object.assign(new AsyncMap(), {
23
+ description: "jsonKeys",
24
+
19
25
  async get(key) {
20
- let value = await tree.get(key);
26
+ let value = await source.get(key);
21
27
  if (value === undefined && key === ".keys.json") {
22
28
  value = await jsonKeys.stringify(this);
23
- } else if (Tree.isTreelike(value)) {
24
- const subtree = Tree.from(value, { deep: true, parent: this });
25
- value = jsonKeysTree(subtree);
29
+ } else if (Tree.isMaplike(value)) {
30
+ const subtree = Tree.from(value, { deep: true, parent: result });
31
+ value = jsonKeysMap(subtree);
26
32
  }
27
33
  return value;
28
34
  },
29
35
 
30
- async keys() {
31
- const keys = new Set(await tree.keys());
32
- keys.add(".keys.json");
33
- return keys;
36
+ async *keys() {
37
+ const treeKeys = new Set(await Tree.keys(source));
38
+ treeKeys.add(".keys.json");
39
+ yield* treeKeys;
34
40
  },
41
+
42
+ source: source,
43
+
44
+ trailingSlashKeys: source.trailingSlashKeys,
35
45
  });
46
+ return result;
36
47
  }
@@ -4,7 +4,6 @@ const codePromiseMap = new Map();
4
4
  /**
5
5
  * Evaluate the given function only once and cache the result.
6
6
  *
7
- * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
8
7
  *
9
8
  * @param {Function} fn
10
9
  */
@@ -15,7 +15,6 @@ const TypedArray = Object.getPrototypeOf(Uint8Array);
15
15
  * Parse an Origami expression, evaluate it in the context of a tree (provided
16
16
  * by `this`), and return the result as text.
17
17
  *
18
- * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
19
18
  *
20
19
  * @param {string} expression
21
20
  */
@@ -90,8 +89,8 @@ async function format(result) {
90
89
  text = result;
91
90
  }
92
91
 
93
- // If the result is treelike, attach it to the text output.
94
- if (Tree.isTreelike(result)) {
92
+ // If the result is maplike, attach it to the text output.
93
+ if (Tree.isMaplike(result)) {
95
94
  if (typeof text === "string") {
96
95
  // @ts-ignore
97
96
  text = new String(text);
@@ -29,6 +29,7 @@ export { default as repeat } from "./repeat.js";
29
29
  export { default as shell } from "./shell.js";
30
30
  export { default as slash } from "./slash.js";
31
31
  export { default as string } from "./string.js";
32
+ export { default as tsv } from "./tsv.js";
32
33
  export { default as unpack } from "./unpack.js";
33
34
  export { default as yaml } from "./yaml.js";
34
35
  export { default as yamlParse } from "./yamlParse.js";
@@ -1,5 +1,4 @@
1
1
  /**
2
- * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
3
2
  *
4
3
  * @param {any} obj
5
4
  */
@@ -18,7 +18,7 @@ export default async function post(url, data) {
18
18
  if (isUnpackable(data)) {
19
19
  data = await data.unpack();
20
20
  }
21
- if (Tree.isTreelike(data)) {
21
+ if (Tree.isMaplike(data)) {
22
22
  const value = await toPlainValue(data);
23
23
  body = JSON.stringify(value);
24
24
  headers = {
@@ -2,10 +2,9 @@ import { getTreeArgument, Tree } from "@weborigami/async-tree";
2
2
  import jsonFeedToRss from "@weborigami/json-feed-to-rss";
3
3
 
4
4
  /**
5
- * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
6
- * @typedef {import("@weborigami/async-tree").Treelike} Treelike
5
+ * @typedef {import("@weborigami/async-tree").Maplike} Maplike
7
6
  *
8
- * @param {Treelike} jsonFeed
7
+ * @param {Maplike} jsonFeed
9
8
  * @param {any} options
10
9
  */
11
10
  export default async function rss(jsonFeed, options = {}) {
@@ -11,32 +11,22 @@ const templateText = `(urls) => \`<?xml version="1.0" encoding="UTF-8"?>
11
11
  `;
12
12
 
13
13
  /**
14
- * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
15
- * @typedef {import("@weborigami/async-tree").Treelike} Treelike
14
+ * @typedef {import("@weborigami/async-tree").Maplike} Maplike
16
15
  *
17
- * @param {Treelike} treelike
16
+ * @param {Maplike} maplike
18
17
  * @param {{ assumeSlashes?: boolean, base?: string }} options
19
18
  * @returns {Promise<string>}
20
19
  */
21
- export default async function sitemap(treelike, options = {}) {
22
- const tree = await getTreeArgument(treelike, "sitemap");
20
+ export default async function sitemap(maplike, options = {}) {
21
+ const tree = await getTreeArgument(maplike, "sitemap");
23
22
 
24
23
  // We're only interested in keys that end in .html or with no extension.
25
- function test(key) {
26
- return key.endsWith?.(".html") || !key.includes?.(".");
27
- }
28
- const filterTree = {
29
- async keys() {
30
- const keys = Array.from(await tree.keys());
31
- return keys.filter((key) => test(key));
32
- },
24
+ const filtered = await Tree.filter(
25
+ tree,
26
+ (value, key) => key.endsWith?.(".html") || !key.includes?.(".")
27
+ );
33
28
 
34
- async get(key) {
35
- return test(key) ? tree.get(key) : undefined;
36
- },
37
- };
38
-
39
- const treePaths = await Tree.paths(filterTree, options);
29
+ const treePaths = await Tree.paths(filtered, options);
40
30
 
41
31
  // For simplicity, we assume that HTML pages will end in .html.
42
32
  // If the page is named index.html, we remove index.html from
@@ -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
  }