@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
package/index.ts CHANGED
@@ -3,16 +3,12 @@
3
3
  * tool to confirm our code is type safe.
4
4
  */
5
5
 
6
- import { Treelike, Unpackable } from "@weborigami/async-tree";
7
-
8
6
  /**
9
7
  * A class constructor is an object with a `new` method that returns an
10
8
  * instance of the indicated type.
11
9
  */
12
10
  export type Constructor<T> = new (...args: any[]) => T;
13
11
 
14
- export type Invocable = Function | Unpackable<Function|Treelike> | Treelike;
15
-
16
12
  export interface JsonObject {
17
13
  [key: string]: JsonValue;
18
14
  }
package/main.js CHANGED
@@ -1,12 +1,5 @@
1
1
  export { default as documentObject } from "./src/common/documentObject.js";
2
- export { toString } from "./src/common/utilities.js";
3
- export * from "./src/dev/dev.js";
4
- export { default as handlerBuiltins } from "./src/handlers/handlerBuiltins.js";
5
- export * from "./src/handlers/handlers.js";
6
- export * from "./src/origami/origami.js";
2
+ export * as Dev from "./src/dev/dev.js";
3
+ export * as Origami from "./src/origami/origami.js";
7
4
  export { default as origamiHighlightDefinition } from "./src/origami/origamiHighlightDefinition.js";
8
- export { default as package } from "./src/protocols/package.js";
9
5
  export * from "./src/server/server.js";
10
-
11
- // TODO: Remove once these async-tree owns sole copy of all tree builtins
12
- export * from "./src/tree/tree.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@weborigami/origami",
3
- "version": "0.5.4",
3
+ "version": "0.5.6",
4
4
  "description": "Web Origami language, CLI, framework, and server",
5
5
  "type": "module",
6
6
  "repository": {
@@ -17,12 +17,11 @@
17
17
  "typescript": "5.9.2"
18
18
  },
19
19
  "dependencies": {
20
- "@weborigami/async-tree": "0.5.4",
20
+ "@weborigami/async-tree": "0.5.6",
21
21
  "@weborigami/json-feed-to-rss": "1.0.0",
22
- "@weborigami/language": "0.5.4",
23
- "@weborigami/types": "0.5.4",
22
+ "@weborigami/language": "0.5.6",
23
+ "@weborigami/types": "0.5.6",
24
24
  "css-tree": "3.1.0",
25
- "exif-parser": "0.1.12",
26
25
  "graphviz-wasm": "3.0.2",
27
26
  "highlight.js": "11.11.1",
28
27
  "jsdom": "26.1.0",
package/src/cli/cli.js CHANGED
@@ -1,26 +1,28 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import { Tree } from "@weborigami/async-tree";
4
- import { formatError } from "@weborigami/language";
4
+ import { formatError, projectRoot } from "@weborigami/language";
5
5
  import path from "node:path";
6
6
  import process, { stdout } from "node:process";
7
7
  import help from "../dev/help.js";
8
+ import initializeBuiltins from "../initializeBuiltins.js";
8
9
  import ori from "../origami/ori.js";
9
- import project from "../origami/project.js";
10
10
 
11
11
  const TypedArray = Object.getPrototypeOf(Uint8Array);
12
12
 
13
13
  async function main(...args) {
14
14
  const expression = args.join(" ");
15
15
 
16
+ // Need to initialize builtins before calling projectRoot, which instantiates
17
+ // an OrigamiFiles object that handles extensions, which requires builtins.
18
+ initializeBuiltins();
19
+
16
20
  // Find the project root.
17
- const projectTree = await project.call(null);
21
+ const projectTree = await projectRoot();
18
22
 
19
23
  // If no arguments were passed, show usage.
20
24
  if (!expression) {
21
- // HACK: the config is the parent of the project tree.
22
- const config = projectTree.parent;
23
- const usage = await help.call(config);
25
+ const usage = await help();
24
26
  console.log(usage);
25
27
  return;
26
28
  }
@@ -28,9 +30,9 @@ async function main(...args) {
28
30
  // Traverse from the project root to the current directory.
29
31
  const currentDirectory = process.cwd();
30
32
  const relative = path.relative(projectTree.path, currentDirectory);
31
- const tree = await Tree.traversePath(projectTree, relative);
33
+ const parent = await Tree.traversePath(projectTree, relative);
32
34
 
33
- const result = await ori.call(tree, expression);
35
+ const result = await ori(expression, { parent });
34
36
 
35
37
  if (result !== undefined) {
36
38
  const output =
@@ -4,10 +4,10 @@ import { isPlainObject, isUnpackable, toString } from "@weborigami/async-tree";
4
4
  * In Origami, a text document object is any object with a `_body` property.
5
5
  * This function is a helper for constructing such text document objects.
6
6
  *
7
- * @typedef {import("@weborigami/async-tree").StringLike} StringLike
7
+ * @typedef {import("@weborigami/async-tree").Stringlike} Stringlike
8
8
  * @typedef {import("@weborigami/async-tree").PlainObject} PlainObject
9
9
  *
10
- * @param {StringLike|PlainObject} input
10
+ * @param {Stringlike|PlainObject} input
11
11
  * @param {any} [data]
12
12
  */
13
13
  export default async function documentObject(input, data) {
@@ -30,7 +30,7 @@ export default async function documentObject(input, data) {
30
30
  // document to HandleExtensionsTransform set().
31
31
  // const base = {
32
32
  // pack() {
33
- // return txtHandler.pack(this);
33
+ // return txt_handler.pack(this);
34
34
  // },
35
35
  // };
36
36
  // const result = Object.create(base);
@@ -0,0 +1,13 @@
1
+ let promise;
2
+
3
+ /**
4
+ * Lazy-load the jsdom library.
5
+ *
6
+ * Statically loading jsdom is slightly annoying. It's a large library that's
7
+ * rarely used. It also executes non-trivial code at load time. That includes a
8
+ * runtime test that (always?) throws an exception, which complicates debugging.
9
+ */
10
+ export default async function loadJsDom() {
11
+ promise ??= await import("jsdom");
12
+ return promise;
13
+ }
@@ -2,6 +2,4 @@
2
2
  export function getDescriptor(object: any): string;
3
3
  export function hasNonPrintableCharacters(text: string): boolean;
4
4
  export function isTransformApplied(Transform: Function, object: any): boolean;
5
- export function toFunction(object: any): Function;
6
- export function toString(object: any): string|null;
7
5
  export function transformObject(Transform: Function, object: any): any;
@@ -1,10 +1,4 @@
1
- import {
2
- Tree,
3
- toString as asyncTreeToString,
4
- isPlainObject,
5
- isUnpackable,
6
- trailingSlash,
7
- } from "@weborigami/async-tree";
1
+ import { trailingSlash } from "@weborigami/async-tree";
8
2
  import { symbols } from "@weborigami/language";
9
3
  import { basename } from "node:path";
10
4
 
@@ -52,54 +46,6 @@ export function isTransformApplied(Transform, obj) {
52
46
  return false;
53
47
  }
54
48
 
55
- /**
56
- * Convert the given object to a function.
57
- *
58
- * @typedef {import("../../index.ts").Invocable} Invocable
59
- * @param {any} obj
60
- * @returns {Function|null}
61
- */
62
- export function toFunction(obj) {
63
- if (typeof obj === "function") {
64
- // Return a function as is.
65
- return obj;
66
- } else if (isUnpackable(obj)) {
67
- // Extract the contents of the object and convert that to a function.
68
- let fnPromise;
69
- /** @this {any} */
70
- return async function (...args) {
71
- if (!fnPromise) {
72
- // unpack() may return a function or a promise for a function; normalize
73
- // to a promise for a function
74
- const unpackPromise = Promise.resolve(obj.unpack());
75
- fnPromise = unpackPromise.then((content) => toFunction(content));
76
- }
77
- const fn = await fnPromise;
78
- return fn.call(this, ...args);
79
- };
80
- } else if (Tree.isTreelike(obj)) {
81
- // Return a function that invokes the tree's getter.
82
- return Tree.toFunction(obj);
83
- } else {
84
- // Not a function
85
- return null;
86
- }
87
- }
88
-
89
- /**
90
- * Extend the async-tree toString method: objects that have a `_body` property
91
- * will return the value of that property as a string.
92
- *
93
- * @param {any} object
94
- * @returns {string|null}
95
- */
96
- export function toString(object) {
97
- if (isPlainObject(object) && "_body" in object) {
98
- object = object._body;
99
- }
100
- return asyncTreeToString(object);
101
- }
102
-
103
49
  /**
104
50
  * Apply a functional class mixin to an individual object instance.
105
51
  *
@@ -31,8 +31,8 @@ export default function ExplorableSiteTransform(Base) {
31
31
  if (value === undefined) {
32
32
  // The tree doesn't have the key; try the defaults.
33
33
  if (key === "index.html") {
34
- // This tree is both the function call target and the parameter.
35
- value = await indexPage.call(this, this);
34
+ // Generate an index page for this site
35
+ value = await indexPage(this);
36
36
  } else if (key === ".keys.json") {
37
37
  value = await jsonKeys.stringify(this);
38
38
  }
@@ -48,7 +48,6 @@ export default function ExplorableSiteTransform(Base) {
48
48
  // If the value isn't a tree, but has a tree attached via an `unpack`
49
49
  // method, wrap the unpack method to add this transform.
50
50
  const original = value.unpack.bind(value);
51
- const parent = this;
52
51
  value.unpack = async () => {
53
52
  const content = await original();
54
53
  // See function notes at @debug
@@ -57,9 +56,6 @@ export default function ExplorableSiteTransform(Base) {
57
56
  }
58
57
  /** @type {any} */
59
58
  let tree = Tree.from(content);
60
- if (!tree.parent) {
61
- tree.parent = parent;
62
- }
63
59
  if (!isTransformApplied(ExplorableSiteTransform, tree)) {
64
60
  tree = transformObject(ExplorableSiteTransform, tree);
65
61
  }
@@ -1,13 +1,16 @@
1
- /** @typedef {import("@weborigami/types").AsyncTree} AsyncTree */
2
- import ori from "../origami/ori.js";
1
+ import { scope, trailingSlash } from "@weborigami/async-tree";
2
+ import { projectGlobals } from "@weborigami/language";
3
3
 
4
4
  /**
5
5
  * Add support for commands prefixed with `!`.
6
6
  *
7
- * E.g., asking this tree for `!yaml` will invoke the yaml() builtin function
8
- * in the context of this tree.
7
+ * E.g., asking this tree for `!yaml` will invoke the yaml() builtin function,
8
+ * passing the current tree as the first argument.
9
+ *
10
+ * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
11
+ * @typedef {import("../../index.ts").Constructor<AsyncTree>}
12
+ * AsyncTreeConstructor
9
13
  *
10
- * @typedef {import("../../index.ts").Constructor<AsyncTree>} AsyncTreeConstructor
11
14
  * @param {AsyncTreeConstructor} Base
12
15
  */
13
16
  export default function OriCommandTransform(Base) {
@@ -23,9 +26,24 @@ export default function OriCommandTransform(Base) {
23
26
  ) {
24
27
  return undefined;
25
28
  }
29
+
26
30
  // Key is an Origami command; invoke it.
27
- const source = key.slice(1).trim();
28
- value = await ori.call(this, source, { formatResult: false });
31
+ const globals = await projectGlobals();
32
+ const commandName = trailingSlash.remove(key.slice(1).trim());
33
+
34
+ // Look for command as a global or Dev command
35
+ const command = globals[commandName] ?? globals.Dev?.[commandName];
36
+ if (command) {
37
+ value = await command(this);
38
+ } else {
39
+ // Look for command in scope
40
+ const parentScope = await scope(this);
41
+ value = await parentScope.get(commandName);
42
+ }
43
+
44
+ if (value === undefined) {
45
+ throw new Error(`Unknown Origami command: ${commandName}`);
46
+ }
29
47
  }
30
48
 
31
49
  return value;
@@ -1,4 +1,4 @@
1
- import { trailingSlash, Tree } from "@weborigami/async-tree";
1
+ import { getTreeArgument, trailingSlash, Tree } from "@weborigami/async-tree";
2
2
 
3
3
  /**
4
4
  * Given an old tree and a new tree, return a tree of changes indicated
@@ -6,13 +6,18 @@ import { trailingSlash, Tree } from "@weborigami/async-tree";
6
6
  *
7
7
  * @typedef {import("@weborigami/async-tree").Treelike} Treelike
8
8
  *
9
- * @this {import("@weborigami/types").AsyncTree|null}
10
9
  * @param {Treelike} oldTreelike
11
10
  * @param {Treelike} newTreelike
12
11
  */
13
12
  export default async function changes(oldTreelike, newTreelike) {
14
- const oldTree = Tree.from(oldTreelike, { deep: true, parent: this });
15
- const newTree = Tree.from(newTreelike, { deep: true, parent: this });
13
+ const oldTree = await getTreeArgument(oldTreelike, "changes", {
14
+ deep: true,
15
+ position: 0,
16
+ });
17
+ const newTree = await getTreeArgument(newTreelike, "changes", {
18
+ deep: true,
19
+ position: 1,
20
+ });
16
21
 
17
22
  const oldKeys = Array.from(await oldTree.keys());
18
23
  const newKeys = Array.from(await newTree.keys());
@@ -34,7 +39,7 @@ export default async function changes(oldTreelike, newTreelike) {
34
39
  const newValue = await newTree.get(oldKey);
35
40
 
36
41
  if (Tree.isAsyncTree(oldValue) && Tree.isAsyncTree(newValue)) {
37
- const treeChanges = await changes.call(this, oldValue, newValue);
42
+ const treeChanges = await changes(oldValue, newValue);
38
43
  if (treeChanges && Object.keys(treeChanges).length > 0) {
39
44
  result ??= {};
40
45
  result[oldKey] = treeChanges;
package/src/dev/code.js CHANGED
@@ -1,17 +1,12 @@
1
1
  import { toString } from "@weborigami/async-tree";
2
2
  import { compile } from "@weborigami/language";
3
- import getTreeArgument from "../common/getTreeArgument.js";
4
3
 
5
4
  /**
6
5
  * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
7
6
  *
8
- * @this {AsyncTree|null}
9
- * @param {import("@weborigami/async-tree").StringLike} input
7
+ * @param {import("@weborigami/async-tree").Stringlike} input
10
8
  */
11
9
  export default async function code(input) {
12
- if (input === undefined) {
13
- input = await getTreeArgument(this, arguments, input, "code");
14
- }
15
10
  if (input === undefined) {
16
11
  return undefined;
17
12
  }
package/src/dev/copy.js CHANGED
@@ -1,22 +1,18 @@
1
- import { Tree } from "@weborigami/async-tree";
1
+ import { getTreeArgument, Tree } from "@weborigami/async-tree";
2
2
  import { formatError } from "@weborigami/language";
3
3
  import process, { stdout } from "node:process";
4
- import assertTreeIsDefined from "../common/assertTreeIsDefined.js";
5
4
  import { transformObject } from "../common/utilities.js";
6
- import setDeep from "../tree/setDeep.js";
7
5
 
8
6
  /**
9
7
  * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
10
8
  * @typedef {import("@weborigami/async-tree").Treelike} Treelike
11
9
  *
12
- * @this {AsyncTree|null}
13
10
  * @param {Treelike} source
14
11
  * @param {Treelike} target
15
12
  */
16
13
  export default async function copy(source, target) {
17
- assertTreeIsDefined(this, "copy");
18
- const sourceTree = Tree.from(source, { parent: this });
19
- /** @type {any} */ let targetTree = Tree.from(target, { parent: this });
14
+ const sourceTree = await getTreeArgument(source, "copy", { position: 0 });
15
+ let targetTree = await getTreeArgument(target, "copy", { position: 1 });
20
16
 
21
17
  if (stdout.isTTY) {
22
18
  targetTree = transformObject(ProgressTransform, targetTree);
@@ -25,7 +21,7 @@ export default async function copy(source, target) {
25
21
  countCopied = 0;
26
22
  }
27
23
 
28
- await setDeep.call(this, targetTree, sourceTree);
24
+ await Tree.assign(targetTree, sourceTree);
29
25
 
30
26
  if (stdout.isTTY) {
31
27
  process.stdout.clearLine(0);
@@ -1,5 +1,9 @@
1
- import { pathFromKeys, symbols, Tree } from "@weborigami/async-tree";
2
- import getTreeArgument from "../../common/getTreeArgument.js";
1
+ import {
2
+ getTreeArgument,
3
+ pathFromKeys,
4
+ symbols,
5
+ Tree,
6
+ } from "@weborigami/async-tree";
3
7
  import crawlResources from "./crawlResources.js";
4
8
  import { getBaseUrl } from "./utilities.js";
5
9
 
@@ -10,12 +14,11 @@ import { getBaseUrl } from "./utilities.js";
10
14
  * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
11
15
  * @typedef {import("@weborigami/async-tree").Treelike} Treelike
12
16
  *
13
- * @this {AsyncTree|null}
14
17
  * @param {Treelike} treelike
15
18
  * @param {string} [baseHref]
16
19
  */
17
20
  export default async function audit(treelike, baseHref) {
18
- const tree = await getTreeArgument(this, arguments, treelike, "audit");
21
+ const tree = await getTreeArgument(treelike, "audit");
19
22
  const baseUrl = getBaseUrl(baseHref, treelike);
20
23
 
21
24
  let errors = {};
@@ -73,13 +76,10 @@ export default async function audit(treelike, baseHref) {
73
76
  return undefined;
74
77
  }
75
78
 
76
- Object.defineProperty(errors, symbols.parent, {
77
- enumerable: false,
78
- value: this,
79
- });
80
79
  Object.defineProperty(errors, symbols.deep, {
81
80
  enumerable: false,
82
81
  value: true,
83
82
  });
83
+
84
84
  return errors;
85
85
  }
@@ -1,11 +1,10 @@
1
1
  import {
2
2
  DeepObjectTree,
3
3
  Tree,
4
- deepMerge,
4
+ getTreeArgument,
5
5
  keysFromPath,
6
6
  } from "@weborigami/async-tree";
7
7
  import { InvokeFunctionsTransform } from "@weborigami/language";
8
- import getTreeArgument from "../../common/getTreeArgument.js";
9
8
  import crawlResources from "./crawlResources.js";
10
9
  import { addValueToObject, getBaseUrl } from "./utilities.js";
11
10
 
@@ -20,13 +19,12 @@ import { addValueToObject, getBaseUrl } from "./utilities.js";
20
19
  * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
21
20
  * @typedef {import("@weborigami/async-tree").Treelike} Treelike
22
21
  *
23
- * @this {AsyncTree|null}
24
22
  * @param {Treelike} treelike
25
23
  * @param {string} [baseHref]
26
24
  * @returns {Promise<AsyncTree>}
27
25
  */
28
26
  export default async function crawlBuiltin(treelike, baseHref) {
29
- const tree = await getTreeArgument(this, arguments, treelike, "crawl");
27
+ const tree = await getTreeArgument(treelike, "crawl");
30
28
  const baseUrl = getBaseUrl(baseHref, treelike);
31
29
 
32
30
  const cache = {};
@@ -55,7 +53,7 @@ export default async function crawlBuiltin(treelike, baseHref) {
55
53
  // Merge the cache on top of the resources tree. If we have an actual value
56
54
  // for something already, that's better than a function that will get that
57
55
  // value.
58
- const result = deepMerge(
56
+ const result = Tree.deepMerge(
59
57
  new DeepObjectTree(cache),
60
58
  new (InvokeFunctionsTransform(DeepObjectTree))(resources)
61
59
  );
@@ -41,15 +41,21 @@ function filterPaths(paths, baseUrl, localPath) {
41
41
  * Given a value retrieved from a site using a given key (name), determine what
42
42
  * kind of file it is and, based on that, find the paths it references.
43
43
  */
44
- export default function findPaths(value, key, baseUrl, localPath) {
44
+ export default async function findPaths(value, key, baseUrl, localPath) {
45
45
  const text = toString(value);
46
+ if (text === null) {
47
+ return {
48
+ crawlablePaths: [],
49
+ resourcePaths: [],
50
+ };
51
+ }
46
52
 
47
53
  // We guess the value is HTML is if its key has an .html extension or
48
54
  // doesn't have an extension, or the value starts with `<`.
49
55
  const ext = key ? extension.extname(key).toLowerCase() : "";
50
56
  let foundPaths;
51
57
  if (ext === ".html" || ext === ".htm" || ext === ".xhtml") {
52
- foundPaths = pathsInHtml(text);
58
+ foundPaths = await pathsInHtml(text);
53
59
  } else if (ext === ".css") {
54
60
  foundPaths = pathsInCss(text);
55
61
  } else if (ext === ".js") {
@@ -62,7 +68,7 @@ export default function findPaths(value, key, baseUrl, localPath) {
62
68
  foundPaths = pathsInSitemap(text);
63
69
  } else if (ext === "" && text?.trim().startsWith("<")) {
64
70
  // Probably HTML
65
- foundPaths = pathsInHtml(text);
71
+ foundPaths = await pathsInHtml(text);
66
72
  } else {
67
73
  // Doesn't have an extension we want to process
68
74
  return {
@@ -1,9 +1,10 @@
1
- import { JSDOM, VirtualConsole } from "jsdom";
1
+ import loadJsDom from "../../common/loadJsDom.js";
2
2
  import pathsInCss from "./pathsInCss.js";
3
3
  import pathsInJs from "./pathsInJs.js";
4
4
  import { addHref } from "./utilities.js";
5
5
 
6
- export default function pathsInHtml(html) {
6
+ export default async function pathsInHtml(html) {
7
+ const { JSDOM, VirtualConsole } = await loadJsDom();
7
8
  const paths = {
8
9
  /** @type {string[]} */
9
10
  crawlablePaths: [],
@@ -153,7 +154,7 @@ export default function pathsInHtml(html) {
153
154
  while ((match = noframesRegex.exec(html))) {
154
155
  const noframesHtml = match.groups?.html;
155
156
  if (noframesHtml) {
156
- const noframesPaths = pathsInHtml(noframesHtml);
157
+ const noframesPaths = await pathsInHtml(noframesHtml);
157
158
  paths.crawlablePaths.push(...noframesPaths.crawlablePaths);
158
159
  paths.resourcePaths.push(...noframesPaths.resourcePaths);
159
160
  }
package/src/dev/debug.js CHANGED
@@ -1,5 +1,4 @@
1
- import { Tree } from "@weborigami/async-tree";
2
- import getTreeArgument from "../common/getTreeArgument.js";
1
+ import { getTreeArgument, Tree } from "@weborigami/async-tree";
3
2
  import { isTransformApplied, transformObject } from "../common/utilities.js";
4
3
  import ExplorableSiteTransform from "./ExplorableSiteTransform.js";
5
4
  import OriCommandTransform from "./OriCommandTransform.js";
@@ -10,13 +9,11 @@ import OriCommandTransform from "./OriCommandTransform.js";
10
9
  * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
11
10
  * @typedef {import("@weborigami/async-tree").Treelike} Treelike
12
11
  *
13
- * @this {AsyncTree|null}
14
- * @param {Treelike} [treelike]
12
+ * @param {Treelike} treelike
13
+ * @returns {Promise<AsyncTree>}
15
14
  */
16
15
  export default async function debug(treelike) {
17
- // The debug command leaves the tree's existing scope intact; it does not
18
- // apply its own scope to the tree.
19
- let tree = await getTreeArgument(this, arguments, treelike, "debug");
16
+ let tree = await getTreeArgument(treelike, "debug");
20
17
 
21
18
  if (!isTransformApplied(DebugTransform, tree)) {
22
19
  tree = transformObject(DebugTransform, tree);
package/src/dev/dev.js CHANGED
@@ -1,7 +1,9 @@
1
+ import { Tree } from "@weborigami/async-tree";
2
+ export const clear = Tree.clear;
3
+ export const keys = Tree.keys;
4
+
1
5
  export { default as indexPage } from "../origami/indexPage.js";
2
6
  export { default as yaml } from "../origami/yaml.js";
3
- export { default as clear } from "../tree/clear.js";
4
- export { default as keys } from "../tree/keys.js";
5
7
  export { default as breakpoint } from "./breakpoint.js";
6
8
  export { default as changes } from "./changes.js";
7
9
  export { default as code } from "./code.js";
@@ -1,54 +1,30 @@
1
1
  /** @typedef {import("@weborigami/types").AsyncTree} AsyncTree */
2
- import { Tree, scope } from "@weborigami/async-tree";
3
- import { OrigamiFiles } from "@weborigami/language";
2
+ import { getTreeArgument, Tree } from "@weborigami/async-tree";
3
+ import { Handlers, OrigamiFiles } from "@weborigami/language";
4
4
  import path from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
- import assertTreeIsDefined from "../common/assertTreeIsDefined.js";
7
6
  import { getDescriptor } from "../common/utilities.js";
8
- import { oriHandler } from "../handlers/handlers.js";
9
7
  import debug from "./debug.js";
10
8
 
11
9
  let templatePromise;
12
10
 
13
11
  /**
14
- * @this {AsyncTree|null}
12
+ * Display a debug/explore page for the current tree.
15
13
  */
16
- export default async function explore(...keys) {
17
- assertTreeIsDefined(this, "explore");
18
- if (!this) {
19
- return undefined;
20
- }
14
+ export default async function explore(treelike) {
15
+ const tree = await getTreeArgument(treelike, "explore");
21
16
 
22
- const tree = Tree.from(this);
17
+ // Construct the template page
18
+ const scope = await Tree.scope(tree);
19
+ const data = await getScopeData(scope);
20
+ templatePromise ??= loadTemplate();
21
+ const template = await templatePromise;
22
+ const text = await template(data);
23
23
 
24
+ // If the user navigates inside this page, unpack back to the original tree.
24
25
  /** @type {any} */
25
- let result;
26
- if (keys.length > 0) {
27
- // Traverse the scope using the given keys.
28
- const debugTree = await debug.call(tree, this);
29
- if (!debugTree) {
30
- return undefined;
31
- }
32
- const debugScope = scope(debugTree);
33
- // HACK: reproduce logic of ExplorableSiteTransform that turns a trailing
34
- // slash into index.html. Calling `debug` applies that transform and the
35
- // transform should handle that logic, but unfortunately the `traverse`
36
- // operation has special casing to treat a trailing slash, and never gives
37
- // ExplorableSiteTransform a chance.
38
- if (keys.at(-1) === "") {
39
- keys[keys.length - 1] = "index.html";
40
- }
41
- result = await Tree.traverse(debugScope, ...keys);
42
- } else {
43
- // Return the Explore page for the current scope.
44
- const data = await getScopeData(scope(tree));
45
- templatePromise ??= loadTemplate();
46
- const template = await templatePromise;
47
- const text = await template.call(this, data);
48
-
49
- result = new String(text);
50
- result.unpack = () => debug.call(tree, tree);
51
- }
26
+ const result = new String(text);
27
+ result.unpack = () => debug(tree);
52
28
 
53
29
  return result;
54
30
  }
@@ -70,6 +46,8 @@ async function loadTemplate() {
70
46
  const folderPath = path.resolve(fileURLToPath(import.meta.url), "..");
71
47
  const folder = new OrigamiFiles(folderPath);
72
48
  const templateFile = await folder.get("explore.ori");
73
- const template = await oriHandler.unpack(templateFile, { parent: folder });
49
+ const template = await Handlers.ori_handler.unpack(templateFile, {
50
+ parent: folder,
51
+ });
74
52
  return template;
75
53
  }
package/src/dev/help.js CHANGED
@@ -2,18 +2,14 @@ import fs from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import { fileURLToPath } from "url";
4
4
  import YAML from "yaml";
5
- import assertTreeIsDefined from "../common/assertTreeIsDefined.js";
6
5
  import version from "./version.js";
7
6
 
8
7
  /**
9
8
  * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
10
9
  *
11
- * @this {AsyncTree|null}
12
10
  * @param {string} [key]
13
11
  */
14
12
  export default async function help(key) {
15
- assertTreeIsDefined(this, "help");
16
-
17
13
  const helpFilename = path.resolve(
18
14
  fileURLToPath(import.meta.url),
19
15
  "../help.yaml"