@weborigami/origami 0.5.4 → 0.5.6

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 (131) hide show
  1. package/index.ts +0 -4
  2. package/main.js +2 -9
  3. package/package.json +4 -5
  4. package/src/cli/cli.js +10 -8
  5. package/src/common/documentObject.js +3 -3
  6. package/src/common/loadJsDom.js +13 -0
  7. package/src/common/utilities.d.ts +0 -2
  8. package/src/common/utilities.js +1 -55
  9. package/src/dev/ExplorableSiteTransform.js +2 -6
  10. package/src/dev/OriCommandTransform.js +25 -7
  11. package/src/dev/changes.js +10 -5
  12. package/src/dev/code.js +1 -6
  13. package/src/dev/copy.js +4 -8
  14. package/src/dev/crawler/audit.js +8 -8
  15. package/src/dev/crawler/crawl.js +3 -5
  16. package/src/dev/crawler/findPaths.js +9 -3
  17. package/src/dev/crawler/pathsInHtml.js +4 -3
  18. package/src/dev/debug.js +4 -7
  19. package/src/dev/dev.js +4 -2
  20. package/src/dev/explore.js +17 -39
  21. package/src/dev/help.js +0 -4
  22. package/src/dev/help.yaml +18 -14
  23. package/src/dev/log.js +1 -2
  24. package/src/dev/serve.js +5 -18
  25. package/src/dev/svg.js +5 -5
  26. package/src/dev/treeDot.js +5 -6
  27. package/src/dev/watch.js +8 -12
  28. package/src/initializeBuiltins.js +23 -0
  29. package/src/origami/csv.js +1 -5
  30. package/src/origami/document.js +2 -5
  31. package/src/origami/fetch.js +4 -8
  32. package/src/origami/htmlDom.js +3 -2
  33. package/src/origami/image/format.js +0 -5
  34. package/src/origami/image/resize.js +0 -3
  35. package/src/origami/indexPage.js +4 -4
  36. package/src/origami/inline.js +4 -10
  37. package/src/origami/json.js +2 -6
  38. package/src/origami/jsonKeys.js +4 -10
  39. package/src/origami/jsonParse.js +1 -1
  40. package/src/origami/mdHtml.js +5 -9
  41. package/src/origami/mdOutline.js +3 -3
  42. package/src/origami/once.js +3 -7
  43. package/src/origami/ori.js +21 -24
  44. package/src/origami/origami.js +1 -4
  45. package/src/origami/pack.js +0 -5
  46. package/src/origami/post.js +4 -3
  47. package/src/origami/rss.js +7 -8
  48. package/src/origami/sitemap.js +7 -9
  49. package/src/origami/static.js +7 -9
  50. package/src/origami/string.js +1 -14
  51. package/src/origami/unpack.js +0 -5
  52. package/src/origami/yaml.js +1 -5
  53. package/src/origami/yamlParse.js +1 -1
  54. package/src/server/constructResponse.js +3 -3
  55. package/src/server/server.js +8 -59
  56. package/src/builtinsProgram.js +0 -65
  57. package/src/builtinsShell.js +0 -18
  58. package/src/cli/getConfig.js +0 -11
  59. package/src/common/ConstantTree.js +0 -18
  60. package/src/common/constructHref.js +0 -20
  61. package/src/common/constructSiteTree.js +0 -34
  62. package/src/common/fetchAndHandleExtension.js +0 -27
  63. package/src/handlers/css.handler.js +0 -7
  64. package/src/handlers/csv.handler.js +0 -126
  65. package/src/handlers/handlerBuiltins.js +0 -27
  66. package/src/handlers/handlers.js +0 -33
  67. package/src/handlers/htm.handler.js +0 -2
  68. package/src/handlers/html.handler.js +0 -7
  69. package/src/handlers/jpeg.handler.js +0 -62
  70. package/src/handlers/jpg.handler.js +0 -2
  71. package/src/handlers/js.handler.js +0 -20
  72. package/src/handlers/json.handler.js +0 -27
  73. package/src/handlers/md.handler.js +0 -7
  74. package/src/handlers/mjs.handler.js +0 -2
  75. package/src/handlers/ori.handler.js +0 -55
  76. package/src/handlers/oridocument.handler.js +0 -78
  77. package/src/handlers/parseFrontMatter.js +0 -16
  78. package/src/handlers/processUnpackedContent.js +0 -35
  79. package/src/handlers/ts.handler.js +0 -1
  80. package/src/handlers/txt.handler.js +0 -91
  81. package/src/handlers/wasm.handler.js +0 -17
  82. package/src/handlers/xhtml.handler.js +0 -2
  83. package/src/handlers/yaml.handler.js +0 -36
  84. package/src/handlers/yml.handler.js +0 -2
  85. package/src/origami/config.js +0 -18
  86. package/src/origami/project.js +0 -111
  87. package/src/protocols/explore.js +0 -19
  88. package/src/protocols/files.js +0 -31
  89. package/src/protocols/http.js +0 -18
  90. package/src/protocols/https.js +0 -18
  91. package/src/protocols/httpstree.js +0 -19
  92. package/src/protocols/httptree.js +0 -19
  93. package/src/protocols/js.js +0 -13
  94. package/src/protocols/node.js +0 -13
  95. package/src/protocols/package.js +0 -70
  96. package/src/tree/addNextPrevious.js +0 -22
  97. package/src/tree/cache.js +0 -22
  98. package/src/tree/calendar.js +0 -1
  99. package/src/tree/clear.js +0 -19
  100. package/src/tree/concat.js +0 -17
  101. package/src/tree/constant.js +0 -1
  102. package/src/tree/deepMap.js +0 -32
  103. package/src/tree/deepMerge.js +0 -18
  104. package/src/tree/deepReverse.js +0 -23
  105. package/src/tree/deepTake.js +0 -26
  106. package/src/tree/deepValues.js +0 -22
  107. package/src/tree/defineds.js +0 -30
  108. package/src/tree/filter.js +0 -19
  109. package/src/tree/first.js +0 -19
  110. package/src/tree/fromFn.js +0 -29
  111. package/src/tree/globKeys.js +0 -19
  112. package/src/tree/group.js +0 -26
  113. package/src/tree/inners.js +0 -30
  114. package/src/tree/keys.js +0 -15
  115. package/src/tree/length.js +0 -15
  116. package/src/tree/map.d.ts +0 -11
  117. package/src/tree/map.js +0 -125
  118. package/src/tree/mask.js +0 -19
  119. package/src/tree/match.js +0 -79
  120. package/src/tree/merge.js +0 -41
  121. package/src/tree/paginate.js +0 -20
  122. package/src/tree/parent.js +0 -15
  123. package/src/tree/plain.js +0 -15
  124. package/src/tree/regExpKeys.js +0 -19
  125. package/src/tree/reverse.js +0 -17
  126. package/src/tree/setDeep.js +0 -49
  127. package/src/tree/shuffle.js +0 -57
  128. package/src/tree/sort.js +0 -52
  129. package/src/tree/take.js +0 -19
  130. package/src/tree/tree.js +0 -52
  131. package/src/tree/values.js +0 -15
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  Tree,
3
3
  getRealmObjectPrototype,
4
+ isStringlike,
4
5
  toString,
5
6
  } from "@weborigami/async-tree";
6
7
  import { compile } from "@weborigami/language";
7
- import builtinsShell from "../builtinsShell.js";
8
- import getConfig from "../cli/getConfig.js";
9
- import assertTreeIsDefined from "../common/assertTreeIsDefined.js";
8
+ import projectGlobals from "@weborigami/language/src/project/projectGlobals.js";
10
9
  import { toYaml } from "../common/serialize.js";
10
+ import * as dev from "../dev/dev.js";
11
11
 
12
12
  const TypedArray = Object.getPrototypeOf(Uint8Array);
13
13
 
@@ -17,50 +17,47 @@ const TypedArray = Object.getPrototypeOf(Uint8Array);
17
17
  *
18
18
  * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
19
19
  *
20
- * @this {AsyncTree|null}
21
20
  * @param {string} expression
22
21
  */
23
- export default async function ori(
24
- expression,
25
- options = { formatResult: true }
26
- ) {
27
- assertTreeIsDefined(this, "ori");
22
+ export default async function ori(expression, options = {}) {
23
+ const parent = options.parent ?? null;
24
+ const formatResult = options.formatResult ?? true;
28
25
 
29
26
  // In case expression has come from a file, cast it to a string.
27
+ if (!isStringlike(expression)) {
28
+ throw new TypeError("ori: The expression is not text.");
29
+ }
30
+ // @ts-ignore
30
31
  expression = toString(expression);
31
32
 
32
- // Run in the context of `this` if defined
33
- const tree = this;
34
-
35
- const config = getConfig(tree);
36
- const globals = config
37
- ? {
38
- ...builtinsShell(),
39
- ...config,
40
- }
41
- : builtinsShell();
33
+ // Add Dev builtins as top-level globals
34
+ const globals = {
35
+ ...(await projectGlobals()),
36
+ ...dev,
37
+ };
42
38
 
43
39
  // Compile the expression. Avoid caching scope references so that, e.g.,
44
40
  // passing a function to the `watch` builtin will always look the current
45
41
  // value of things in scope.
46
42
  const fn = compile.expression(expression, {
47
43
  globals,
48
- mode: "shell",
49
44
  enableCaching: false,
45
+ mode: "shell",
46
+ parent,
50
47
  });
51
48
 
52
49
  // Execute
53
- let result = await fn.call(tree);
50
+ let result = await fn();
54
51
 
55
52
  // If result was a function, execute it.
56
53
  if (typeof result === "function") {
57
- result = await result.call(tree);
54
+ result = await result();
58
55
  }
59
56
 
60
- return options.formatResult ? await formatResult(result) : result;
57
+ return formatResult ? await format(result) : result;
61
58
  }
62
59
 
63
- async function formatResult(result) {
60
+ async function format(result) {
64
61
  if (
65
62
  typeof result === "string" ||
66
63
  result instanceof ArrayBuffer ||
@@ -1,8 +1,7 @@
1
1
  export { extension } from "@weborigami/async-tree";
2
- export { toFunction } from "../common/utilities.js";
3
2
  export { default as help } from "../dev/help.js"; // Alias
4
3
  export { default as document } from "../origami/document.js";
5
- export { default as htmlDom } from "../origami/htmlDom.js";
4
+ // export { default as htmlDom } from "../origami/htmlDom.js";
6
5
  export { default as indexPage } from "../origami/indexPage.js";
7
6
  export { default as inline } from "../origami/inline.js";
8
7
  export { default as jsonKeys } from "../origami/jsonKeys.js";
@@ -13,7 +12,6 @@ export { default as sitemap } from "../origami/sitemap.js";
13
12
  export { default as slug } from "../origami/slug.js";
14
13
  export { default as static } from "../origami/static.js";
15
14
  export { default as basename } from "./basename.js";
16
- export { default as config } from "./config.js";
17
15
  export { default as csv } from "./csv.js";
18
16
  export { default as fetch } from "./fetch.js";
19
17
  export { default as format } from "./image/format.js";
@@ -27,7 +25,6 @@ export { default as once } from "./once.js";
27
25
  export { default as ori } from "./ori.js";
28
26
  export { default as pack } from "./pack.js";
29
27
  export { default as post } from "./post.js";
30
- export { default as project } from "./project.js";
31
28
  export { default as repeat } from "./repeat.js";
32
29
  export { default as shell } from "./shell.js";
33
30
  export { default as slash } from "./slash.js";
@@ -1,13 +1,8 @@
1
- import assertTreeIsDefined from "../common/assertTreeIsDefined.js";
2
-
3
1
  /**
4
2
  * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
5
3
  *
6
- * @this {AsyncTree|null}
7
4
  * @param {any} obj
8
- * @returns
9
5
  */
10
6
  export default function pack(obj) {
11
- assertTreeIsDefined(this, "pack");
12
7
  return obj?.pack?.();
13
8
  }
@@ -1,5 +1,5 @@
1
1
  import {
2
- isStringLike,
2
+ isStringlike,
3
3
  isUnpackable,
4
4
  toPlainValue,
5
5
  toString,
@@ -7,7 +7,8 @@ import {
7
7
  } from "@weborigami/async-tree";
8
8
 
9
9
  /**
10
- * @this {import("@weborigami/types").AsyncTree|null}
10
+ * POST data to the indicated URL.
11
+ *
11
12
  * @param {string} url
12
13
  * @param {any} data
13
14
  */
@@ -23,7 +24,7 @@ export default async function post(url, data) {
23
24
  headers = {
24
25
  "Content-Type": "application/json",
25
26
  };
26
- } else if (isStringLike(data)) {
27
+ } else if (isStringlike(data)) {
27
28
  body = toString(data);
28
29
  headers = {
29
30
  "Content-Type": "text/plain",
@@ -1,16 +1,15 @@
1
- import { Tree } from "@weborigami/async-tree";
1
+ import { getTreeArgument, Tree } from "@weborigami/async-tree";
2
2
  import jsonFeedToRss from "@weborigami/json-feed-to-rss";
3
- import assertTreeIsDefined from "../common/assertTreeIsDefined.js";
4
3
 
5
4
  /**
6
5
  * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
7
6
  * @typedef {import("@weborigami/async-tree").Treelike} Treelike
8
- * @this {AsyncTree|null}
9
- * @param {Treelike} jsonFeedTree
7
+ *
8
+ * @param {Treelike} jsonFeed
10
9
  * @param {any} options
11
10
  */
12
- export default async function rss(jsonFeedTree, options = {}) {
13
- assertTreeIsDefined(this, "rss");
14
- const jsonFeed = await Tree.plain(jsonFeedTree);
15
- return jsonFeedToRss(jsonFeed, options);
11
+ export default async function rss(jsonFeed, options = {}) {
12
+ const tree = await getTreeArgument(jsonFeed, "rss");
13
+ const jsonFeedPlain = await Tree.plain(tree);
14
+ return jsonFeedToRss(jsonFeedPlain, options);
16
15
  }
@@ -1,7 +1,5 @@
1
- import { Tree } from "@weborigami/async-tree";
2
- import assertTreeIsDefined from "../common/assertTreeIsDefined.js";
3
- import getTreeArgument from "../common/getTreeArgument.js";
4
- import { oriHandler } from "../handlers/handlers.js";
1
+ import { getTreeArgument, Tree } from "@weborigami/async-tree";
2
+ import { ori_handler } from "@weborigami/language/src/handlers/handlers.js";
5
3
 
6
4
  const templateText = `(urls) => \`<?xml version="1.0" encoding="UTF-8"?>
7
5
  <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
@@ -15,13 +13,13 @@ const templateText = `(urls) => \`<?xml version="1.0" encoding="UTF-8"?>
15
13
  /**
16
14
  * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
17
15
  * @typedef {import("@weborigami/async-tree").Treelike} Treelike
18
- * @this {AsyncTree|null}
16
+ *
19
17
  * @param {Treelike} treelike
20
18
  * @param {{ assumeSlashes?: boolean, base?: string }} options
19
+ * @returns {Promise<string>}
21
20
  */
22
21
  export default async function sitemap(treelike, options = {}) {
23
- assertTreeIsDefined(this, "sitemap");
24
- const tree = await getTreeArgument(this, arguments, treelike, "sitemap");
22
+ const tree = await getTreeArgument(treelike, "sitemap");
25
23
 
26
24
  // We're only interested in keys that end in .html or with no extension.
27
25
  function test(key) {
@@ -47,7 +45,7 @@ export default async function sitemap(treelike, options = {}) {
47
45
  .filter((path) => path.endsWith(".html"))
48
46
  .map((path) => (path.endsWith("index.html") ? path.slice(0, -10) : path));
49
47
 
50
- const templateFn = await oriHandler.unpack(templateText);
51
- const templateResult = await templateFn.call(this, htmlPaths);
48
+ const templateFn = await ori_handler.unpack(templateText);
49
+ const templateResult = await templateFn(htmlPaths);
52
50
  return String(templateResult);
53
51
  }
@@ -1,20 +1,18 @@
1
- import { Tree, jsonKeys } from "@weborigami/async-tree";
2
- import getTreeArgument from "../common/getTreeArgument.js";
3
- import index from "./indexPage.js";
1
+ import { Tree, getTreeArgument, jsonKeys } from "@weborigami/async-tree";
2
+ import indexPage from "./indexPage.js";
4
3
 
5
4
  /**
6
5
  * Expose common static keys (index.html, .keys.json) for a tree.
7
6
  *
8
7
  * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
9
8
  * @typedef {import("@weborigami/async-tree").Treelike} Treelike
10
- * @this {AsyncTree|null}
9
+ *
11
10
  * @param {Treelike} treelike
11
+ * @returns {Promise<AsyncTree>}
12
12
  */
13
13
  export default async function staticBuiltin(treelike) {
14
- const tree = await getTreeArgument(this, arguments, treelike, "static");
15
- const result = staticTree(tree);
16
- result.parent = this;
17
- return result;
14
+ const tree = await getTreeArgument(treelike, "static");
15
+ return staticTree(tree);
18
16
  }
19
17
 
20
18
  // The name we'll register as a builtin
@@ -25,7 +23,7 @@ function staticTree(tree) {
25
23
  async get(key) {
26
24
  let value = await tree.get(key);
27
25
  if (value === undefined && key === "index.html") {
28
- value = await index.call(this, this);
26
+ value = await indexPage(this);
29
27
  } else if (value === undefined && key === ".keys.json") {
30
28
  value = await jsonKeys.stringify(this);
31
29
  } else if (Tree.isTreelike(value)) {
@@ -1,14 +1 @@
1
- import assertTreeIsDefined from "../common/assertTreeIsDefined.js";
2
- import { toString } from "../common/utilities.js";
3
-
4
- /**
5
- * Convert an object to a string.
6
- *
7
- * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
8
- * @this {AsyncTree|null}
9
- * @param {any} object
10
- */
11
- export default function stringBuiltin(object) {
12
- assertTreeIsDefined(this, "string");
13
- return toString(object);
14
- }
1
+ export { toString as default } from "@weborigami/async-tree";
@@ -1,14 +1,9 @@
1
- import assertTreeIsDefined from "../common/assertTreeIsDefined.js";
2
-
3
1
  /**
4
2
  * Unpack a packed format like a Uint8Array or ArrayBuffer to a usable form like
5
3
  * text or a plain JavaScript object.
6
4
  *
7
- * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
8
- * @this {AsyncTree|null}
9
5
  * @param {any} obj
10
6
  */
11
7
  export default function unpack(obj) {
12
- assertTreeIsDefined(this, "unpack");
13
8
  return obj?.unpack?.() ?? obj;
14
9
  }
@@ -1,23 +1,19 @@
1
1
  /** @typedef {import("@weborigami/types").AsyncTree} AsyncTree */
2
2
  import { isUnpackable, toPlainValue } from "@weborigami/async-tree";
3
3
  import YAML from "yaml";
4
- import assertTreeIsDefined from "../common/assertTreeIsDefined.js";
5
4
 
6
5
  /**
7
6
  * Render the object as text in YAML format.
8
7
  *
9
- * @this {AsyncTree|null}
10
8
  * @param {any} [obj]
11
9
  */
12
- export default async function toYaml(obj) {
13
- assertTreeIsDefined(this, "yaml");
10
+ export default async function yamlBuiltin(obj) {
14
11
  // A fragment of the logic from getTreeArgument.js
15
12
  if (arguments.length > 0 && obj === undefined) {
16
13
  throw new Error(
17
14
  "An Origami function was called with an initial argument, but its value is undefined."
18
15
  );
19
16
  }
20
- obj = obj ?? this;
21
17
  if (obj === undefined) {
22
18
  return undefined;
23
19
  }
@@ -1,5 +1,5 @@
1
+ import { toString } from "@weborigami/async-tree";
1
2
  import * as serialize from "../common/serialize.js";
2
- import { toString } from "../common/utilities.js";
3
3
 
4
4
  export default async function yamlParse(input) {
5
5
  const text = toString(input);
@@ -2,12 +2,12 @@ import {
2
2
  extension,
3
3
  isPacked,
4
4
  isPlainObject,
5
- isStringLike,
5
+ isStringlike,
6
6
  SiteTree,
7
+ toString,
7
8
  Tree,
8
9
  } from "@weborigami/async-tree";
9
10
  import * as serialize from "../common/serialize.js";
10
- import { toString } from "../common/utilities.js";
11
11
  import { mediaTypeForExtension } from "./mediaTypes.js";
12
12
 
13
13
  /**
@@ -63,7 +63,7 @@ export default async function constructResponse(request, resource) {
63
63
 
64
64
  if (
65
65
  (mediaType === "application/json" || mediaType === "text/yaml") &&
66
- !isStringLike(resource)
66
+ !isStringlike(resource)
67
67
  ) {
68
68
  // The request is for a JSON or YAML result, and the resource we got isn't
69
69
  // yet a string: convert the resource to JSON or YAML now.
@@ -1,4 +1,4 @@
1
- import { ObjectTree, Tree, keysFromPath } from "@weborigami/async-tree";
1
+ import { Tree, keysFromPath } from "@weborigami/async-tree";
2
2
  import { formatError } from "@weborigami/language";
3
3
  import { ServerResponse } from "node:http";
4
4
  import constructResponse from "./constructResponse.js";
@@ -39,32 +39,6 @@ async function copyResponse(constructed, response) {
39
39
  return true;
40
40
  }
41
41
 
42
- // Extend the tree's scope with the URL's search parameters.
43
- function extendTreeScopeWithParams(tree, url) {
44
- // Create a tree that includes the URL's search parameters.
45
- const params = {};
46
- for (const [key, value] of url.searchParams) {
47
- params[key] = value;
48
- }
49
-
50
- if (Object.keys(params).length === 0) {
51
- // No search parameters, so return the tree as is.
52
- return tree;
53
- }
54
-
55
- const paramTree = new ObjectTree({
56
- "@params": params,
57
- });
58
-
59
- // Create a new tree that's like the original one, but has the parameters in
60
- // its parent hierarchy.
61
- const extendedTree = Object.create(tree);
62
- const realParent = tree.parent;
63
- paramTree.parent = realParent;
64
- extendedTree.parent = paramTree;
65
- return extendedTree;
66
- }
67
-
68
42
  /**
69
43
  * Handle a client request.
70
44
  *
@@ -77,17 +51,12 @@ export async function handleRequest(request, response, tree) {
77
51
  const url = new URL(request.url ?? "", `https://${request.headers.host}`);
78
52
  const keys = keysFromUrl(url);
79
53
 
80
- const extendedTree =
81
- url.searchParams && "parent" in tree
82
- ? extendTreeScopeWithParams(tree, url)
83
- : tree;
84
-
85
54
  const data = request.method === "POST" ? await parsePostData(request) : null;
86
55
 
87
56
  // Ask the tree for the resource with those keys.
88
57
  let resource;
89
58
  try {
90
- resource = await Tree.traverseOrThrow(extendedTree, ...keys);
59
+ resource = await Tree.traverseOrThrow(tree, ...keys);
91
60
 
92
61
  // If resource is a function, invoke to get the object we want to return.
93
62
  // For a POST request, pass the data to the function.
@@ -112,35 +81,15 @@ export async function handleRequest(request, response, tree) {
112
81
  }
113
82
 
114
83
  function keysFromUrl(url) {
115
- // Split on occurrences of `/!`, which represent Origami debug commands.
116
- // Command arguments can contain slashes; don't treat those as path keys.
117
- const parts = url.pathname.split(/\/!/);
118
-
119
- // Split everything before the first command by slashes and decode those.
120
- let path = parts.shift();
121
- if (parts.length > 0) {
122
- // HACK: Add back trailing slash that was removed by split
123
- path += "/";
124
- }
125
- const pathKeys = keysFromPath(path).map((key) => decodeURIComponent(key));
126
- if (parts.length > 0 && pathKeys.at(-1) === "") {
127
- // HACK part 2: Remove empty string that was added for trailing slash
128
- pathKeys.pop();
129
- }
84
+ const encodedKeys = keysFromPath(url.pathname);
85
+ const keys = encodedKeys.map((key) => decodeURIComponent(key));
130
86
 
131
- // If there are no commands, and the path ends with a trailing slash, the
132
- // final key will be an empty string. Change that to "index.html".
133
- if (parts.length === 0 && pathKeys[pathKeys.length - 1] === "") {
134
- pathKeys[pathKeys.length - 1] = "index.html";
87
+ // If the path ends with a trailing slash, the final key will be an empty
88
+ // string. Change that to "index.html".
89
+ if (keys.at(-1) === "") {
90
+ keys[keys.length - 1] = "index.html";
135
91
  }
136
92
 
137
- // Decode the text of the commands, prefix spaces with a backslash, and add
138
- // back the `!` character.
139
- const commandKeys = parts.map(
140
- (command) => `!${decodeURIComponent(command).replace(/ /g, "\\ ")}`
141
- );
142
-
143
- const keys = [...pathKeys, ...commandKeys];
144
93
  return keys;
145
94
  }
146
95
 
@@ -1,65 +0,0 @@
1
- import { deepText, indent, json, text } from "@weborigami/async-tree";
2
- import { jsGlobals } from "@weborigami/language";
3
- import * as dev from "./dev/dev.js";
4
- import help from "./dev/help.js";
5
- import handlerBuiltins from "./handlers/handlerBuiltins.js";
6
- import * as origami from "./origami/origami.js";
7
- import explore from "./protocols/explore.js";
8
- import files from "./protocols/files.js";
9
- import http from "./protocols/http.js";
10
- import https from "./protocols/https.js";
11
- import httpstree from "./protocols/httpstree.js";
12
- import httptree from "./protocols/httptree.js";
13
- import node from "./protocols/node.js";
14
- import packageNamespace from "./protocols/package.js";
15
- import * as tree from "./tree/tree.js";
16
-
17
- let builtins;
18
-
19
- export default function builtinsProgram() {
20
- if (!builtins) {
21
- const Tree = {
22
- ...tree,
23
- deepText,
24
- indent,
25
- json,
26
- text,
27
- };
28
-
29
- const Protocol = {
30
- explore,
31
- files,
32
- http,
33
- https,
34
- httpstree,
35
- httptree,
36
- node,
37
- package: packageNamespace,
38
- };
39
-
40
- /** @type {any} */
41
- builtins = {
42
- ...jsGlobals,
43
-
44
- "explore:": explore,
45
- "files:": files,
46
- "help:": help,
47
- "http:": http,
48
- "https:": https,
49
- "httpstree:": httpstree,
50
- "httptree:": httptree,
51
- "node:": node,
52
- "package:": packageNamespace,
53
-
54
- Dev: dev,
55
- Tree,
56
- Origami: origami,
57
- Protocol,
58
-
59
- // Handlers need to be exposed at top level
60
- ...handlerBuiltins(),
61
- };
62
- }
63
-
64
- return builtins;
65
- }
@@ -1,18 +0,0 @@
1
- import builtinsProgram from "./builtinsProgram.js";
2
- import * as dev from "./dev/dev.js";
3
-
4
- let builtins;
5
-
6
- export default function builtinsShell() {
7
- if (!builtins) {
8
- builtins = {
9
- // All program builtins
10
- ...builtinsProgram(),
11
-
12
- // Dev builtins exposed at the top level in shell
13
- ...dev,
14
- };
15
- }
16
-
17
- return builtins;
18
- }
@@ -1,11 +0,0 @@
1
- import { Tree } from "@weborigami/async-tree";
2
-
3
- // Return the config for the given tree
4
- export default function getConfig(tree) {
5
- if (!tree) {
6
- return null;
7
- }
8
- /** @type {any} */
9
- const root = Tree.root(tree);
10
- return root.config;
11
- }
@@ -1,18 +0,0 @@
1
- /**
2
- * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
3
- * @implements {AsyncTree}
4
- */
5
- export default class ConstantTree {
6
- constructor(value) {
7
- this.value = value;
8
- this.parent = null;
9
- }
10
-
11
- async get(key) {
12
- return this.value;
13
- }
14
-
15
- async keys() {
16
- return [];
17
- }
18
- }
@@ -1,20 +0,0 @@
1
- import { pathFromKeys } from "@weborigami/async-tree";
2
-
3
- /**
4
- * Given a protocol, a host, and a list of keys, construct an href.
5
- *
6
- * @param {string} protocol
7
- * @param {string} host
8
- * @param {string[]} keys
9
- */
10
- export default function constructHref(protocol, host, ...keys) {
11
- const path = pathFromKeys(keys);
12
- let href = [host, path].join("/");
13
- if (!href.startsWith(protocol)) {
14
- if (!href.startsWith("//")) {
15
- href = `//${href}`;
16
- }
17
- href = `${protocol}${href}`;
18
- }
19
- return href;
20
- }
@@ -1,34 +0,0 @@
1
- import { trailingSlash } from "@weborigami/async-tree";
2
- import { HandleExtensionsTransform } from "@weborigami/language";
3
- import constructHref from "./constructHref.js";
4
-
5
- /**
6
- * Given a protocol, a host, and a list of keys, construct an href.
7
- *
8
- * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
9
- *
10
- * @param {string} protocol
11
- * @param {import("../../index.ts").Constructor<AsyncTree>} treeClass
12
- * @param {AsyncTree|null} parent
13
- * @param {string} host
14
- * @param {string[]} keys
15
- */
16
- export default function constructSiteTree(
17
- protocol,
18
- treeClass,
19
- parent,
20
- host,
21
- ...keys
22
- ) {
23
- // If the last key doesn't end in a slash, remove it for now.
24
- let lastKey;
25
- if (keys.length > 0 && keys.at(-1) && !trailingSlash.has(keys.at(-1))) {
26
- lastKey = keys.pop();
27
- }
28
-
29
- const href = constructHref(protocol, host, ...keys);
30
- let result = new (HandleExtensionsTransform(treeClass))(href);
31
- result.parent = parent;
32
-
33
- return lastKey ? result.get(lastKey) : result;
34
- }
@@ -1,27 +0,0 @@
1
- import { getHandlers, handleExtension } from "@weborigami/language";
2
-
3
- /**
4
- * Fetch the resource at the given href.
5
- *
6
- * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
7
- *
8
- * @this {AsyncTree|null}
9
- * @param {string} href
10
- */
11
- export default async function fetchAndHandleExtension(href) {
12
- const response = await fetch(href);
13
- if (!response.ok) {
14
- return undefined;
15
- }
16
- let buffer = await response.arrayBuffer();
17
-
18
- // Attach any loader defined for the file type.
19
- const url = new URL(href);
20
- const filename = url.pathname.split("/").pop();
21
- if (this && filename) {
22
- const handlers = getHandlers(this);
23
- buffer = await handleExtension(this, buffer, filename, handlers);
24
- }
25
-
26
- return buffer;
27
- }
@@ -1,7 +0,0 @@
1
- // .css files use the .txt loader
2
- import { txtHandler } from "./handlers.js";
3
-
4
- export default {
5
- ...txtHandler,
6
- mediaType: "text/css",
7
- };