@weborigami/origami 0.0.58 → 0.0.60

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 (86) hide show
  1. package/exports/buildExports.js +6 -2
  2. package/exports/exports.js +2 -6
  3. package/package.json +12 -12
  4. package/src/builtins/@arrowsMap.js +4 -5
  5. package/src/builtins/@breakpoint.js +12 -0
  6. package/src/builtins/@cache.js +3 -6
  7. package/src/builtins/@concat.js +3 -4
  8. package/src/builtins/@config.js +3 -12
  9. package/src/builtins/@constructor.js +3 -7
  10. package/src/builtins/@copy.js +2 -2
  11. package/src/builtins/@crawl.js +4 -6
  12. package/src/builtins/@debug.js +5 -6
  13. package/src/builtins/@deepMap.js +2 -2
  14. package/src/builtins/@deepMapFn.js +2 -2
  15. package/src/builtins/@deepMerge.js +3 -18
  16. package/src/builtins/@deepReverse.js +1 -3
  17. package/src/builtins/@deepTakeFn.js +5 -6
  18. package/src/builtins/@defineds.js +4 -7
  19. package/src/builtins/@document.js +2 -2
  20. package/src/builtins/@exceptions.js +1 -5
  21. package/src/builtins/@explore.js +15 -14
  22. package/src/builtins/@files.js +4 -6
  23. package/src/builtins/@filter.js +3 -6
  24. package/src/builtins/@fnTree.js +8 -22
  25. package/src/builtins/@globs.js +3 -6
  26. package/src/builtins/@groupFn.js +7 -8
  27. package/src/builtins/@help.js +2 -2
  28. package/src/builtins/@http.js +2 -2
  29. package/src/builtins/@https.js +2 -2
  30. package/src/builtins/@if.js +2 -2
  31. package/src/builtins/@image/format.js +5 -5
  32. package/src/builtins/@image/formatFn.js +6 -3
  33. package/src/builtins/@image/resize.js +5 -5
  34. package/src/builtins/@image/resizeFn.js +6 -3
  35. package/src/builtins/@inherited.js +2 -2
  36. package/src/builtins/@inline.js +5 -9
  37. package/src/builtins/@inners.js +0 -1
  38. package/src/builtins/@invoke.js +4 -7
  39. package/src/builtins/@json.js +5 -6
  40. package/src/builtins/@map.js +2 -2
  41. package/src/builtins/@mapFn.js +9 -10
  42. package/src/builtins/@match.js +17 -16
  43. package/src/builtins/@mdHtml.js +4 -1
  44. package/src/builtins/@merge.js +3 -18
  45. package/src/builtins/@once.js +2 -2
  46. package/src/builtins/@ori.js +8 -7
  47. package/src/builtins/@pack.js +2 -2
  48. package/src/builtins/@package.js +4 -8
  49. package/src/builtins/@paginateFn.js +1 -6
  50. package/src/builtins/@perf.js +4 -3
  51. package/src/builtins/@project.js +31 -22
  52. package/src/builtins/@reverse.js +1 -3
  53. package/src/builtins/@rss.js +2 -2
  54. package/src/builtins/@serve.js +2 -2
  55. package/src/builtins/@sitemap.js +4 -1
  56. package/src/builtins/@sortFn.js +6 -7
  57. package/src/builtins/@stdin.js +7 -1
  58. package/src/builtins/@string.js +2 -2
  59. package/src/builtins/@takeFn.js +5 -6
  60. package/src/builtins/@treeHttp.js +2 -2
  61. package/src/builtins/@treeHttps.js +2 -2
  62. package/src/builtins/@unpack.js +3 -3
  63. package/src/builtins/@watch.js +5 -12
  64. package/src/builtins/@yaml.js +5 -6
  65. package/src/builtins/jpeg_handler.js +4 -0
  66. package/src/builtins/ori_handler.js +3 -3
  67. package/src/builtins/~.js +3 -3
  68. package/src/cli/cli.js +6 -19
  69. package/src/common/ConstantTree.js +1 -0
  70. package/src/common/ExplorableSiteTransform.js +9 -12
  71. package/src/common/documentObject.js +2 -2
  72. package/src/common/processUnpackedContent.js +12 -18
  73. package/src/common/serialize.d.ts +0 -2
  74. package/src/common/serialize.js +3 -90
  75. package/src/misc/OriCommandTransform.js +1 -9
  76. package/src/misc/assertTreeIsDefined.d.ts +1 -0
  77. package/src/misc/assertTreeIsDefined.js +7 -0
  78. package/src/misc/getTreeArgument.js +11 -12
  79. package/src/server/constructResponse.js +4 -4
  80. package/src/server/server.js +3 -10
  81. package/src/builtins/@scope/extend.js +0 -22
  82. package/src/builtins/@scope/get.js +0 -25
  83. package/src/builtins/@scope/invoke.js +0 -22
  84. package/src/builtins/@scope/set.js +0 -25
  85. package/src/common/addValueKeyToScope.js +0 -23
  86. package/src/misc/assertScopeIsDefined.js +0 -7
@@ -1,7 +1,6 @@
1
- import { FunctionTree, ObjectTree } from "@weborigami/async-tree";
2
- import { Scope } from "@weborigami/language";
1
+ import { FunctionTree } from "@weborigami/async-tree";
3
2
  import { toFunction } from "../common/utilities.js";
4
- import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
3
+ import assertTreeIsDefined from "../misc/assertTreeIsDefined.js";
5
4
 
6
5
  /**
7
6
  * Create a tree from a function and a set of keys.
@@ -14,29 +13,16 @@ import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
14
13
  * @param {Invocable} [invocable]
15
14
  */
16
15
  export default async function fnTree(invocable, keys = []) {
17
- assertScopeIsDefined(this, "fnTree");
18
- // A fragment of the logic from getTreeArgument.js
19
- if (arguments.length > 0 && invocable === undefined) {
16
+ assertTreeIsDefined(this, "fnTree");
17
+ if (invocable === undefined) {
20
18
  throw new Error(
21
19
  "An Origami function was called with an initial argument, but its value is undefined."
22
20
  );
23
21
  }
24
- invocable = invocable ?? (await this?.get("@current"));
25
- if (invocable === undefined) {
26
- return undefined;
27
- }
28
- const invocableFn = toFunction(invocable);
29
-
30
- /** @this {AsyncTree|null} */
31
- async function extendedFn(key) {
32
- const ambientsTree = Scope.treeWithScope(
33
- new ObjectTree({ "@key": key }),
34
- this
35
- );
36
- return invocableFn.call(ambientsTree, key);
37
- }
38
-
39
- return new FunctionTree(extendedFn, keys);
22
+ const fn = toFunction(invocable);
23
+ const tree = new FunctionTree(fn, keys);
24
+ tree.parent = this;
25
+ return tree;
40
26
  }
41
27
 
42
28
  fnTree.usage = `@fnTree <fn>, [<keys>]\tCreate a tree from a function and a set of keys`;
@@ -1,6 +1,5 @@
1
- import { Scope } from "@weborigami/language";
2
1
  import GlobTree from "../common/GlobTree.js";
3
- import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
2
+ import assertTreeIsDefined from "../misc/assertTreeIsDefined.js";
4
3
 
5
4
  /**
6
5
  * Define a tree whose keys are globs.
@@ -12,10 +11,8 @@ import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
12
11
  * @this {AsyncTree|null}
13
12
  */
14
13
  export default async function globs(tree) {
15
- assertScopeIsDefined(this, "globs");
16
- /** @type {AsyncTree} */
17
- let result = new GlobTree(tree);
18
- result = Scope.treeWithScope(result, this);
14
+ assertTreeIsDefined(this, "globs");
15
+ const result = new GlobTree(tree);
19
16
  return result;
20
17
  }
21
18
 
@@ -1,7 +1,6 @@
1
1
  import { groupFn } from "@weborigami/async-tree";
2
- import { Scope } from "@weborigami/language";
3
2
  import { toFunction } from "../common/utilities.js";
4
- import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
3
+ import assertTreeIsDefined from "../misc/assertTreeIsDefined.js";
5
4
 
6
5
  /**
7
6
  * Return a function that maps a tree to a new tree with the values from the
@@ -13,19 +12,19 @@ import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
13
12
  * @param {import("../../index.ts").Invocable} groupKey
14
13
  */
15
14
  export default function groupFnBuiltin(groupKey) {
16
- assertScopeIsDefined(this);
17
- const scope = this;
15
+ assertTreeIsDefined(this, "groupFn");
16
+ const tree = this;
18
17
 
19
18
  const groupKeyFn = toFunction(groupKey);
20
- // Have the group key function run in this scope.
21
- const extendedGroupKeyFn = groupKeyFn.bind(scope);
19
+ // Have the group key function run in this tree.
20
+ const extendedGroupKeyFn = groupKeyFn.bind(tree);
22
21
 
23
22
  // @ts-ignore
24
23
  const fn = groupFn(extendedGroupKeyFn);
25
24
  return async (treelike) => {
26
25
  const grouped = await fn(treelike);
27
- const scoped = Scope.treeWithScope(grouped, scope);
28
- return scoped;
26
+ grouped.parent = tree;
27
+ return grouped;
29
28
  };
30
29
  }
31
30
 
@@ -1,6 +1,6 @@
1
1
  /** @typedef {import("@weborigami/types").AsyncTree} AsyncTree */
2
2
  import child_process from "node:child_process";
3
- import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
3
+ import assertTreeIsDefined from "../misc/assertTreeIsDefined.js";
4
4
 
5
5
  const groupUrls = {
6
6
  "@cache": "https://weborigami.org/language/@cache.html",
@@ -15,7 +15,7 @@ const groupUrls = {
15
15
  * @param {string} [name]
16
16
  */
17
17
  export default async function help(name) {
18
- assertScopeIsDefined(this, "help");
18
+ assertTreeIsDefined(this, "help");
19
19
  let url;
20
20
  const scope = this;
21
21
  if (scope && name) {
@@ -1,5 +1,5 @@
1
1
  import { ops } from "@weborigami/language";
2
- import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
2
+ import assertTreeIsDefined from "../misc/assertTreeIsDefined.js";
3
3
 
4
4
  /**
5
5
  * Retrieve the indicated web resource via HTTP.
@@ -11,7 +11,7 @@ import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
11
11
  * @param {...string} keys
12
12
  */
13
13
  export default async function http(host, ...keys) {
14
- assertScopeIsDefined(this, "http");
14
+ assertTreeIsDefined(this, "http");
15
15
  return ops.http.call(this, host, ...keys);
16
16
  }
17
17
 
@@ -1,5 +1,5 @@
1
1
  import { ops } from "@weborigami/language";
2
- import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
2
+ import assertTreeIsDefined from "../misc/assertTreeIsDefined.js";
3
3
 
4
4
  /**
5
5
  * Retrieve the indicated web resource via HTTPS.
@@ -11,7 +11,7 @@ import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
11
11
  * @param {...string} keys
12
12
  */
13
13
  export default async function https(host, ...keys) {
14
- assertScopeIsDefined(this, "https");
14
+ assertTreeIsDefined(this, "https");
15
15
  return ops.https.call(this, host, ...keys);
16
16
  }
17
17
 
@@ -1,6 +1,6 @@
1
1
  /** @typedef {import("@weborigami/types").AsyncTree} AsyncTree */
2
2
  import { Tree } from "@weborigami/async-tree";
3
- import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
3
+ import assertTreeIsDefined from "../misc/assertTreeIsDefined.js";
4
4
 
5
5
  /**
6
6
  * @this {AsyncTree|null}
@@ -9,7 +9,7 @@ import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
9
9
  * @param {any} [falseResult]
10
10
  */
11
11
  export default async function ifCommand(value, trueResult, falseResult) {
12
- assertScopeIsDefined(this, "if");
12
+ assertTreeIsDefined(this, "if");
13
13
  let condition = await value;
14
14
  if (Tree.isAsyncTree(condition)) {
15
15
  const keys = Array.from(await condition.keys());
@@ -1,4 +1,4 @@
1
- import assertScopeIsDefined from "../../misc/assertScopeIsDefined.js";
1
+ import assertTreeIsDefined from "../../misc/assertTreeIsDefined.js";
2
2
  import imageFormatFn from "./formatFn.js";
3
3
 
4
4
  /**
@@ -7,12 +7,12 @@ import imageFormatFn from "./formatFn.js";
7
7
  * @this {import("@weborigami/types").AsyncTree|null}
8
8
  *
9
9
  * @this {import("@weborigami/types").AsyncTree|null}
10
- * @param {Buffer} buffer
10
+ * @param {import("@weborigami/async-tree").Packed} input
11
11
  * @param {keyof import("sharp").FormatEnum|import("sharp").AvailableFormatInfo}
12
12
  * format
13
13
  * @param {any} options
14
14
  */
15
- export default async function imageFormat(buffer, format, options) {
16
- assertScopeIsDefined(this, "image/format");
17
- return imageFormatFn.call(this, format, options)(buffer);
15
+ export default async function imageFormat(input, format, options) {
16
+ assertTreeIsDefined(this, "image/format");
17
+ return imageFormatFn.call(this, format, options)(input);
18
18
  }
@@ -1,5 +1,5 @@
1
1
  import sharp from "sharp";
2
- import assertScopeIsDefined from "../../misc/assertScopeIsDefined.js";
2
+ import assertTreeIsDefined from "../../misc/assertTreeIsDefined.js";
3
3
 
4
4
  /**
5
5
  * Return a function that transforms an input image to a different format.
@@ -10,6 +10,9 @@ import assertScopeIsDefined from "../../misc/assertScopeIsDefined.js";
10
10
  * @param {any} options
11
11
  */
12
12
  export default function imageFormatFn(format, options) {
13
- assertScopeIsDefined(this, "image/formatFn");
14
- return (buffer) => sharp(buffer).toFormat(format, options).toBuffer();
13
+ assertTreeIsDefined(this, "image/formatFn");
14
+ return (buffer) =>
15
+ buffer instanceof Uint8Array || buffer instanceof ArrayBuffer
16
+ ? sharp(buffer).toFormat(format, options).toBuffer()
17
+ : undefined;
15
18
  }
@@ -1,14 +1,14 @@
1
- import assertScopeIsDefined from "../../misc/assertScopeIsDefined.js";
1
+ import assertTreeIsDefined from "../../misc/assertTreeIsDefined.js";
2
2
  import imageResizeFn from "./resizeFn.js";
3
3
 
4
4
  /**
5
5
  * Resize an image.
6
6
  *
7
7
  * @this {import("@weborigami/types").AsyncTree|null}
8
- * @param {Buffer} buffer
8
+ * @param {import("@weborigami/async-tree").Packed} input
9
9
  * @param {import("sharp").ResizeOptions} options
10
10
  */
11
- export default async function resize(buffer, options) {
12
- assertScopeIsDefined(this, "image/resize");
13
- return imageResizeFn.call(this, options)(buffer);
11
+ export default async function resize(input, options) {
12
+ assertTreeIsDefined(this, "image/resize");
13
+ return imageResizeFn.call(this, options)(input);
14
14
  }
@@ -1,5 +1,5 @@
1
1
  import sharp from "sharp";
2
- import assertScopeIsDefined from "../../misc/assertScopeIsDefined.js";
2
+ import assertTreeIsDefined from "../../misc/assertTreeIsDefined.js";
3
3
 
4
4
  /**
5
5
  * Return a function that resizes an image.
@@ -8,7 +8,10 @@ import assertScopeIsDefined from "../../misc/assertScopeIsDefined.js";
8
8
  * @param {import("sharp").ResizeOptions} options
9
9
  */
10
10
  export default function imageResizeFn(options) {
11
- assertScopeIsDefined(this, "image/resizeFn");
11
+ assertTreeIsDefined(this, "image/resizeFn");
12
12
  // Include `rotate()` to auto-rotate according to EXIF data.
13
- return (buffer) => sharp(buffer).rotate().resize(options).toBuffer();
13
+ return (buffer) =>
14
+ buffer instanceof Uint8Array || buffer instanceof ArrayBuffer
15
+ ? sharp(buffer).rotate().resize(options).toBuffer()
16
+ : undefined;
14
17
  }
@@ -1,6 +1,6 @@
1
1
  /** @typedef {import("@weborigami/types").AsyncTree} AsyncTree */
2
2
  import { ops } from "@weborigami/language";
3
- import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
3
+ import assertTreeIsDefined from "../misc/assertTreeIsDefined.js";
4
4
 
5
5
  /**
6
6
  * Return the inherited value (if any) for the indicated key.
@@ -9,7 +9,7 @@ import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
9
9
  * @this {AsyncTree|null}
10
10
  */
11
11
  export default async function inherited(key) {
12
- assertScopeIsDefined(this, "inherited");
12
+ assertTreeIsDefined(this, "inherited");
13
13
  return ops.inherited.call(this, key);
14
14
  }
15
15
 
@@ -1,8 +1,8 @@
1
- import { ObjectTree, isUnpackable, symbols } from "@weborigami/async-tree";
1
+ import { isUnpackable, symbols } from "@weborigami/async-tree";
2
2
  import { compile } from "@weborigami/language";
3
3
  import documentObject from "../common/documentObject.js";
4
4
  import { toString } from "../common/utilities.js";
5
- import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
5
+ import assertTreeIsDefined from "../misc/assertTreeIsDefined.js";
6
6
  import fileTypeOrigami from "./ori_handler.js";
7
7
 
8
8
  /**
@@ -16,7 +16,7 @@ import fileTypeOrigami from "./ori_handler.js";
16
16
  * @param {StringLike} input
17
17
  */
18
18
  export default async function inline(input) {
19
- assertScopeIsDefined(this, "inline");
19
+ assertTreeIsDefined(this, "inline");
20
20
 
21
21
  // Get the input text and any attached front matter.
22
22
  if (isUnpackable(input)) {
@@ -25,12 +25,8 @@ export default async function inline(input) {
25
25
  const inputIsDocument = input["@text"] !== undefined;
26
26
  const origami = inputIsDocument ? input["@text"] : toString(input);
27
27
 
28
- let parent = /** @type {any} */ (input).parent ?? input[symbols.parent];
29
- if (!parent) {
30
- // Construct a temporary parent that has the right scope.
31
- parent = new ObjectTree({});
32
- parent.scope = this;
33
- }
28
+ const parent =
29
+ /** @type {any} */ (input).parent ?? input[symbols.parent] ?? this;
34
30
 
35
31
  // If the input document is a plain object, include it in scope for the
36
32
  // evaluated expression.
@@ -12,7 +12,6 @@ import getTreeArgument from "../misc/getTreeArgument.js";
12
12
  export default async function inners(treelike) {
13
13
  const tree = await getTreeArgument(this, arguments, treelike, "@inners");
14
14
 
15
- /** @type {AsyncTree} */
16
15
  const result = {
17
16
  async get(key) {
18
17
  const value = await tree.get(key);
@@ -1,6 +1,5 @@
1
1
  import { isUnpackable } from "@weborigami/async-tree";
2
- import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
3
- import builtins from "./@builtins.js";
2
+ import assertTreeIsDefined from "../misc/assertTreeIsDefined.js";
4
3
 
5
4
  /**
6
5
  * Invoke the given text as an Origami function.
@@ -24,9 +23,8 @@ import builtins from "./@builtins.js";
24
23
  * @this {import("@weborigami/types").AsyncTree|null}
25
24
  */
26
25
  export default async function invoke(fn) {
27
- assertScopeIsDefined(this, "invoke");
28
- // A fragment of the logic from getTreeArgument.js
29
- if (arguments.length > 0 && fn === undefined) {
26
+ assertTreeIsDefined(this, "invoke");
27
+ if (fn === undefined) {
30
28
  throw new Error(
31
29
  "An Origami function was called with an initial argument, but its value is undefined."
32
30
  );
@@ -34,6 +32,5 @@ export default async function invoke(fn) {
34
32
  if (isUnpackable(fn)) {
35
33
  fn = await fn.unpack();
36
34
  }
37
- const scope = (await this?.get("@current")) ?? builtins;
38
- return typeof fn === "function" ? fn.call(scope) : fn;
35
+ return typeof fn === "function" ? fn.call(this) : fn;
39
36
  }
@@ -1,7 +1,6 @@
1
1
  /** @typedef {import("@weborigami/types").AsyncTree} AsyncTree */
2
- import { isUnpackable } from "@weborigami/async-tree";
3
- import * as serialize from "../common/serialize.js";
4
- import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
2
+ import { isUnpackable, toPlainValue } from "@weborigami/async-tree";
3
+ import assertTreeIsDefined from "../misc/assertTreeIsDefined.js";
5
4
 
6
5
  /**
7
6
  * Render the given object in JSON format.
@@ -10,21 +9,21 @@ import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
10
9
  * @param {any} [obj]
11
10
  */
12
11
  export default async function json(obj) {
13
- assertScopeIsDefined(this, "json");
12
+ assertTreeIsDefined(this, "json");
14
13
  // A fragment of the logic from getTreeArgument.js
15
14
  if (arguments.length > 0 && obj === undefined) {
16
15
  throw new Error(
17
16
  "An Origami function was called with an initial argument, but its value is undefined."
18
17
  );
19
18
  }
20
- obj = obj ?? (await this?.get("@current"));
19
+ obj = obj ?? this;
21
20
  if (obj === undefined) {
22
21
  return undefined;
23
22
  }
24
23
  if (isUnpackable(obj)) {
25
24
  obj = await obj.unpack();
26
25
  }
27
- const value = await serialize.toJsonValue(obj);
26
+ const value = await toPlainValue(obj);
28
27
  return JSON.stringify(value, null, 2);
29
28
  }
30
29
 
@@ -1,4 +1,4 @@
1
- import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
1
+ import assertTreeIsDefined from "../misc/assertTreeIsDefined.js";
2
2
  import mapFn from "./@mapFn.js";
3
3
 
4
4
  /**
@@ -14,6 +14,6 @@ import mapFn from "./@mapFn.js";
14
14
  * @param {ValueKeyFn|TreeMapOptions} operation
15
15
  */
16
16
  export default function map(source, operation) {
17
- assertScopeIsDefined(this, "map");
17
+ assertTreeIsDefined(this, "map");
18
18
  return mapFn.call(this, operation)(source);
19
19
  }
@@ -4,9 +4,8 @@ import {
4
4
  keyFunctionsForExtensions,
5
5
  mapFn,
6
6
  } from "@weborigami/async-tree";
7
- import { Scope } from "@weborigami/language";
8
7
  import { toFunction } from "../common/utilities.js";
9
- import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
8
+ import assertTreeIsDefined from "../misc/assertTreeIsDefined.js";
10
9
 
11
10
  /**
12
11
  * Return a function that transforms a tree of keys and values to a new tree of
@@ -21,8 +20,8 @@ import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
21
20
  * @param {ValueKeyFn|TreeMapOptions} operation
22
21
  */
23
22
  export default function mapFnBuiltin(operation) {
24
- assertScopeIsDefined(this, "map");
25
- const scope = this;
23
+ assertTreeIsDefined(this, "map");
24
+ const tree = this;
26
25
 
27
26
  // Identify whether the map instructions take the form of a value function or
28
27
  // a dictionary of options.
@@ -63,11 +62,11 @@ export default function mapFnBuiltin(operation) {
63
62
  let extendedValueFn;
64
63
  if (valueFn) {
65
64
  const resolvedValueFn = toFunction(valueFn);
66
- // Have the value function run in this scope.
67
- extendedValueFn = resolvedValueFn.bind(scope);
65
+ // Have the value function run in this tree.
66
+ extendedValueFn = resolvedValueFn.bind(tree);
68
67
  }
69
68
 
70
- // Extend the value function to run in scope.
69
+ // Extend the key functions to run in this tree.
71
70
  let extendedKeyFn;
72
71
  let extendedInverseKeyFn;
73
72
  if (extension) {
@@ -83,7 +82,7 @@ export default function mapFnBuiltin(operation) {
83
82
  async function scopedKeyFn(sourceKey, tree) {
84
83
  const sourceValue = await tree.get(sourceKey);
85
84
  const resultKey = await resolvedKeyFn.call(
86
- scope,
85
+ tree,
87
86
  sourceValue,
88
87
  sourceKey,
89
88
  tree
@@ -110,8 +109,8 @@ export default function mapFnBuiltin(operation) {
110
109
 
111
110
  return (treelike) => {
112
111
  const mapped = fn(treelike);
113
- const scoped = Scope.treeWithScope(mapped, scope);
114
- return scoped;
112
+ mapped.parent = tree;
113
+ return mapped;
115
114
  };
116
115
  }
117
116
 
@@ -1,6 +1,5 @@
1
- import { Tree } from "@weborigami/async-tree";
2
- import { Scope } from "@weborigami/language";
3
- import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
1
+ import { ObjectTree, Tree } from "@weborigami/async-tree";
2
+ import assertTreeIsDefined from "../misc/assertTreeIsDefined.js";
4
3
 
5
4
  /**
6
5
  * Return a tree with the indicated keys (if provided).
@@ -20,13 +19,13 @@ import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
20
19
  * @typedef {import("@weborigami/async-tree").Treelike} Treelike
21
20
  * @typedef {import("../../index.ts").Invocable} Invocable
22
21
  *
22
+ * @this {AsyncTree|null}
23
23
  * @param {string|RegExp} pattern
24
24
  * @param {Invocable} resultFn
25
25
  * @param {Treelike} [keys]
26
- * @this {AsyncTree|null}
27
26
  */
28
27
  export default function match(pattern, resultFn, keys = []) {
29
- assertScopeIsDefined(this, "match");
28
+ assertTreeIsDefined(this, "match");
30
29
  let regex;
31
30
  if (typeof pattern === "string") {
32
31
  // Convert the simple pattern format into a regular expression.
@@ -41,11 +40,9 @@ export default function match(pattern, resultFn, keys = []) {
41
40
  throw new Error(`match(): Unsupported pattern`);
42
41
  }
43
42
 
44
- // Remember the scope used to invoke this function so we can extend it below.
45
- const scope = this;
43
+ const tree = this;
46
44
 
47
- /** @type {AsyncTree} */
48
- let result = {
45
+ const result = {
49
46
  async get(key) {
50
47
  const keyMatch = regex.exec(key);
51
48
  if (!keyMatch) {
@@ -63,15 +60,20 @@ export default function match(pattern, resultFn, keys = []) {
63
60
  // If the pattern contained named wildcards, extend the scope. It appears
64
61
  // that the `groups` property of a match is *not* a real plain object, so
65
62
  // we have to make one.
66
- const bindings = keyMatch.groups
67
- ? Object.fromEntries(Object.entries(keyMatch.groups))
68
- : null;
69
- const fnScope = bindings ? new Scope(bindings, scope) : scope;
63
+ let target;
64
+ if (keyMatch.groups) {
65
+ target = new ObjectTree(
66
+ Object.fromEntries(Object.entries(keyMatch.groups))
67
+ );
68
+ target.parent = tree;
69
+ } else {
70
+ target = tree;
71
+ }
70
72
 
71
73
  // Invoke the result function with the extended scope.
72
74
  let value;
73
75
  if (typeof resultFn === "function") {
74
- value = await resultFn.call(fnScope);
76
+ value = await resultFn.call(target);
75
77
  } else {
76
78
  value = Object.create(resultFn);
77
79
  }
@@ -80,11 +82,10 @@ export default function match(pattern, resultFn, keys = []) {
80
82
  },
81
83
 
82
84
  async keys() {
83
- return typeof keys === "function" ? await keys.call(scope) : keys;
85
+ return typeof keys === "function" ? await keys.call(tree) : keys;
84
86
  },
85
87
  };
86
88
 
87
- result = Scope.treeWithScope(result, this);
88
89
  return result;
89
90
  }
90
91
 
@@ -39,7 +39,10 @@ export default async function mdHtml(input) {
39
39
  input = await input.unpack();
40
40
  }
41
41
  const inputIsDocument = input["@text"] !== undefined;
42
- const markdown = inputIsDocument ? input["@text"] : toString(input);
42
+ const markdown = toString(input);
43
+ if (markdown === null) {
44
+ throw new Error("@mdHtml: The provided input couldn't be treated as text.");
45
+ }
43
46
  const html = marked(markdown);
44
47
  return inputIsDocument ? documentObject(html, input) : html;
45
48
  }
@@ -1,6 +1,5 @@
1
1
  import { isPlainObject, isUnpackable, merge } from "@weborigami/async-tree";
2
- import { Scope } from "@weborigami/language";
3
- import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
2
+ import assertTreeIsDefined from "../misc/assertTreeIsDefined.js";
4
3
 
5
4
  /**
6
5
  * Create a tree that's the result of merging the given trees.
@@ -12,7 +11,7 @@ import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
12
11
  * @param {(Treelike|null)[]} trees
13
12
  */
14
13
  export default async function treeMerge(...trees) {
15
- assertScopeIsDefined(this, "merge");
14
+ assertTreeIsDefined(this, "merge");
16
15
 
17
16
  // Filter out null or undefined trees.
18
17
  /** @type {Treelike[]}
@@ -36,22 +35,8 @@ export default async function treeMerge(...trees) {
36
35
  return merge(...unpacked);
37
36
  }
38
37
 
39
- // If a tree can take a scope, give it one that includes the other trees and
40
- // the current scope.
41
- const scopedTrees = unpacked.map((tree) => {
42
- const otherTrees = unpacked.filter((g) => g !== tree);
43
- const scope = new Scope(...otherTrees, this);
44
- // Each tree will be included first in its own scope.
45
- return Scope.treeWithScope(tree, scope);
46
- });
47
-
48
38
  // Merge the trees.
49
- const result = merge(...scopedTrees);
50
-
51
- // Give the overall mixed tree a scope that includes the component trees and
52
- // the current scope.
53
- /** @type {any} */ (result).scope = new Scope(result, this);
54
-
39
+ const result = merge(...unpacked);
55
40
  return result;
56
41
  }
57
42
 
@@ -1,4 +1,4 @@
1
- import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
1
+ import assertTreeIsDefined from "../misc/assertTreeIsDefined.js";
2
2
 
3
3
  const fnPromiseMap = new WeakMap();
4
4
 
@@ -10,7 +10,7 @@ const fnPromiseMap = new WeakMap();
10
10
  * @param {Function} fn
11
11
  */
12
12
  export default async function once(fn) {
13
- assertScopeIsDefined(this, "once");
13
+ assertTreeIsDefined(this, "once");
14
14
  if (!fnPromiseMap.has(fn)) {
15
15
  fnPromiseMap.set(fn, fn.call(this));
16
16
  }
@@ -2,7 +2,7 @@ import { Tree, getRealmObjectPrototype } from "@weborigami/async-tree";
2
2
  import { compile } from "@weborigami/language";
3
3
  import builtins from "../builtins/@builtins.js";
4
4
  import { toYaml } from "../common/serialize.js";
5
- import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
5
+ import assertTreeIsDefined from "../misc/assertTreeIsDefined.js";
6
6
 
7
7
  const TypedArray = Object.getPrototypeOf(Uint8Array);
8
8
 
@@ -19,22 +19,23 @@ export default async function ori(
19
19
  expression,
20
20
  options = { formatResult: true }
21
21
  ) {
22
- assertScopeIsDefined(this, "ori");
23
- // In case expression is a Buffer, cast it to a string.
22
+ assertTreeIsDefined(this, "ori");
23
+
24
+ // In case expression has come from a file, cast it to a string.
24
25
  expression = String(expression);
25
26
 
26
- // Obtain the scope from `this` or builtins.
27
- let scope = this ?? builtins;
27
+ // Run in the context of `this` if defined, otherwise use the builtins.
28
+ const tree = this ?? builtins;
28
29
 
29
30
  // Parse
30
31
  const fn = compile.expression(expression);
31
32
 
32
33
  // Execute
33
- let result = await fn.call(scope);
34
+ let result = await fn.call(tree);
34
35
 
35
36
  // If result was a function, execute it.
36
37
  if (typeof result === "function") {
37
- result = await result.call(scope);
38
+ result = await result.call(tree);
38
39
  }
39
40
 
40
41
  return options.formatResult ? await formatResult(result) : result;
@@ -1,4 +1,4 @@
1
- import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
1
+ import assertTreeIsDefined from "../misc/assertTreeIsDefined.js";
2
2
 
3
3
  /**
4
4
  * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
@@ -8,6 +8,6 @@ import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
8
8
  * @returns
9
9
  */
10
10
  export default function pack(obj) {
11
- assertScopeIsDefined(this, "pack");
11
+ assertTreeIsDefined(this, "pack");
12
12
  return obj?.pack?.();
13
13
  }