@weborigami/origami 0.3.3-jse.1 → 0.3.3-jse.3

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 (46) hide show
  1. package/main.js +1 -2
  2. package/package.json +4 -4
  3. package/src/BuiltinsTree.js +18 -0
  4. package/src/builtinsJse.js +67 -0
  5. package/src/builtinsShell.js +83 -0
  6. package/src/cli/getConfig.js +10 -0
  7. package/src/common/documentObject.js +0 -1
  8. package/src/dev/crawler/crawlResources.js +1 -1
  9. package/src/dev/crawler/pathsInHtml.js +2 -0
  10. package/src/dev/explore.js +3 -8
  11. package/src/handlers/css.handler.js +2 -2
  12. package/src/handlers/handlerBuiltins.js +26 -0
  13. package/src/handlers/handlers.js +36 -45
  14. package/src/handlers/htm.handler.js +1 -1
  15. package/src/handlers/html.handler.js +2 -2
  16. package/src/handlers/jpg.handler.js +1 -1
  17. package/src/handlers/js.handler.js +1 -1
  18. package/src/handlers/jse.handler.js +4 -3
  19. package/src/handlers/jsedocument.handler.js +4 -3
  20. package/src/handlers/md.handler.js +2 -2
  21. package/src/handlers/mjs.handler.js +1 -1
  22. package/src/handlers/ori.handler.js +12 -5
  23. package/src/handlers/oridocument.handler.js +14 -2
  24. package/src/{common → handlers}/processUnpackedContent.js +1 -3
  25. package/src/handlers/ts.handler.js +1 -1
  26. package/src/handlers/txt.handler.js +1 -1
  27. package/src/handlers/wasm.handler.js +1 -1
  28. package/src/handlers/yaml.handler.js +1 -1
  29. package/src/handlers/yml.handler.js +1 -1
  30. package/src/origami/config.js +2 -4
  31. package/src/origami/ori.js +13 -4
  32. package/src/origami/origami.js +0 -5
  33. package/src/origami/project.js +49 -56
  34. package/src/protocols/files.js +2 -1
  35. package/src/protocols/inherited.js +6 -3
  36. package/src/protocols/scope.js +3 -3
  37. package/src/site/sitemap.js +2 -3
  38. package/src/text/inline.js +1 -1
  39. package/src/tree/map.js +1 -1
  40. package/src/builtins.js +0 -56
  41. package/src/builtinsNew.js +0 -84
  42. package/src/builtinsTree.js +0 -36
  43. package/src/handlers/handlerExports.js +0 -16
  44. package/src/handlers/jseModeParent.js +0 -30
  45. package/src/internal.js +0 -28
  46. package/src/js.js +0 -79
package/main.js CHANGED
@@ -1,10 +1,9 @@
1
1
  export { default as documentObject } from "./src/common/documentObject.js";
2
2
  export { toString } from "./src/common/utilities.js";
3
3
  export * from "./src/dev/dev.js";
4
- export * from "./src/handlers/handlerExports.js";
4
+ export { default as handlerBuiltins } from "./src/handlers/handlerBuiltins.js";
5
5
  export * from "./src/handlers/handlers.js";
6
6
  export * from "./src/image/image.js";
7
- export { builtinsTree } from "./src/internal.js";
8
7
  export * from "./src/origami/origami.js";
9
8
  export { default as packageBuiltin } from "./src/protocols/package.js";
10
9
  export * from "./src/server/server.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@weborigami/origami",
3
- "version": "0.3.3-jse.1",
3
+ "version": "0.3.3-jse.3",
4
4
  "description": "Web Origami language, CLI, framework, and server",
5
5
  "type": "module",
6
6
  "repository": {
@@ -17,10 +17,10 @@
17
17
  "typescript": "5.8.2"
18
18
  },
19
19
  "dependencies": {
20
- "@weborigami/async-tree": "0.3.3-jse.1",
20
+ "@weborigami/async-tree": "0.3.3-jse.3",
21
21
  "@weborigami/json-feed-to-rss": "1.0.0",
22
- "@weborigami/language": "0.3.3-jse.1",
23
- "@weborigami/types": "0.3.3-jse.1",
22
+ "@weborigami/language": "0.3.3-jse.3",
23
+ "@weborigami/types": "0.3.3-jse.3",
24
24
  "css-tree": "3.1.0",
25
25
  "exif-parser": "0.1.12",
26
26
  "graphviz-wasm": "3.0.2",
@@ -0,0 +1,18 @@
1
+ import { trailingSlash } from "@weborigami/async-tree";
2
+
3
+ // We create our own tree instead of using ObjectTree, since that binds the
4
+ // functions would be bound to the object. We want to leave them unbound.
5
+ export default class BuiltinsTree {
6
+ constructor(object) {
7
+ this.object = object;
8
+ }
9
+
10
+ async get(key) {
11
+ const normalizedKey = trailingSlash.remove(key);
12
+ return this.object[normalizedKey];
13
+ }
14
+
15
+ async keys() {
16
+ return Object.keys(this.object);
17
+ }
18
+ }
@@ -0,0 +1,67 @@
1
+ import { text as treeText } from "@weborigami/async-tree";
2
+ import { jsGlobals } from "@weborigami/language";
3
+ import BuiltinsTree from "./BuiltinsTree.js";
4
+ import * as dev from "./dev/dev.js";
5
+ import handlerBuiltins from "./handlers/handlerBuiltins.js";
6
+ import help from "./help/help.js";
7
+ import * as image from "./image/image.js";
8
+ import node from "./node.js";
9
+ import * as origami from "./origami/origami.js";
10
+ import explore from "./protocols/explore.js";
11
+ import files from "./protocols/files.js";
12
+ import http from "./protocols/http.js";
13
+ import https from "./protocols/https.js";
14
+ import httpstree from "./protocols/httpstree.js";
15
+ import httptree from "./protocols/httptree.js";
16
+ import inherited from "./protocols/inherited.js";
17
+ import packageNamespace from "./protocols/package.js";
18
+ import scope from "./protocols/scope.js";
19
+ import * as site from "./site/site.js";
20
+ import * as text from "./text/text.js";
21
+ import * as tree from "./tree/tree.js";
22
+
23
+ let result;
24
+
25
+ export default function builtinsJse() {
26
+ if (!result) {
27
+ const Tree = new BuiltinsTree({
28
+ ...tree,
29
+ indent: text.indent,
30
+ json: origami.json,
31
+ text: treeText,
32
+ });
33
+
34
+ const Origami = new BuiltinsTree({
35
+ ...dev,
36
+ image,
37
+ ...origami,
38
+ ...site,
39
+ ...text,
40
+ });
41
+
42
+ /** @type {any} */
43
+ result = new BuiltinsTree({
44
+ ...jsGlobals,
45
+
46
+ "explore:": explore,
47
+ "files:": files,
48
+ "help:": help,
49
+ "http:": http,
50
+ "https:": https,
51
+ "httpstree:": httpstree,
52
+ "httptree:": httptree,
53
+ "inherited:": inherited,
54
+ "node:": node,
55
+ "package:": packageNamespace,
56
+ "scope:": scope,
57
+
58
+ Tree,
59
+ Origami,
60
+
61
+ // Handlers need to be exposed at top level
62
+ ...handlerBuiltins(),
63
+ });
64
+ }
65
+
66
+ return result;
67
+ }
@@ -0,0 +1,83 @@
1
+ import { jsGlobals } from "@weborigami/language";
2
+ import BuiltinsTree from "./BuiltinsTree.js";
3
+ import * as dev from "./dev/dev.js";
4
+ import handlerBuiltins from "./handlers/handlerBuiltins.js";
5
+ import help from "./help/help.js";
6
+ import * as image from "./image/image.js";
7
+ import node from "./node.js";
8
+ import * as origami from "./origami/origami.js";
9
+ import explore from "./protocols/explore.js";
10
+ import files from "./protocols/files.js";
11
+ import http from "./protocols/http.js";
12
+ import https from "./protocols/https.js";
13
+ import httpstree from "./protocols/httpstree.js";
14
+ import httptree from "./protocols/httptree.js";
15
+ import inherited from "./protocols/inherited.js";
16
+ import instantiate from "./protocols/new.js";
17
+ import packageNamespace from "./protocols/package.js";
18
+ import scope from "./protocols/scope.js";
19
+ import * as site from "./site/site.js";
20
+ import * as text from "./text/text.js";
21
+ import * as tree from "./tree/tree.js";
22
+
23
+ let result;
24
+
25
+ export default function builtinsShell() {
26
+ if (!result) {
27
+ const builtins = {
28
+ "dev:": dev,
29
+ "explore:": explore,
30
+ "files:": files,
31
+ "help:": help,
32
+ "http:": http,
33
+ "https:": https,
34
+ "httpstree:": httpstree,
35
+ "httptree:": httptree,
36
+ "image:": image,
37
+ "inherited:": inherited,
38
+ "js:": jsGlobals,
39
+ "new:": instantiate,
40
+ "node:": node,
41
+ "origami:": origami,
42
+ "package:": packageNamespace,
43
+ "scope:": scope,
44
+ "site:": adjustReservedWords(site),
45
+ "text:": text,
46
+ "tree:": tree,
47
+
48
+ // Handlers need to be exposed at top level
49
+ ...handlerBuiltins(),
50
+ };
51
+
52
+ // For all builtins like `tree:keys`, add a shorthand `keys`.
53
+ for (const [key, value] of Object.entries(builtins)) {
54
+ const isNamespace = key.endsWith(":");
55
+ if (isNamespace) {
56
+ for (const [subKey, subValue] of Object.entries(value)) {
57
+ // HACK: Skip description keys until we can make them all non-enumerable.
58
+ if (subKey === "description") {
59
+ continue;
60
+ }
61
+ if (subKey in builtins) {
62
+ throw new Error(`Internal Origami error: Duplicate key: ${subKey}`);
63
+ }
64
+ builtins[subKey] = subValue;
65
+ }
66
+ }
67
+ }
68
+
69
+ result = new BuiltinsTree(builtins);
70
+ }
71
+
72
+ return result;
73
+ }
74
+
75
+ // Handle cases where a builtin name conflicts with a JS reserved word
76
+ function adjustReservedWords(obj) {
77
+ const result = {};
78
+ for (const [key, value] of Object.entries(obj)) {
79
+ const name = value.key ?? key;
80
+ result[name] = value;
81
+ }
82
+ return result;
83
+ }
@@ -0,0 +1,10 @@
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
+ const root = Tree.root(tree);
9
+ return root.config;
10
+ }
@@ -1,5 +1,4 @@
1
1
  import { isPlainObject, isUnpackable, toString } from "@weborigami/async-tree";
2
- // import txtHandler from "../builtins/txt.handler.js";
3
2
 
4
3
  /**
5
4
  * In Origami, a text document object is any object with a `@text` property and
@@ -130,7 +130,7 @@ async function processPath(tree, path, baseUrl) {
130
130
 
131
131
  // Traverse tree to get value.
132
132
  let value;
133
- let normalizedKeys;
133
+ let normalizedKeys = [];
134
134
  let normalizedPath;
135
135
  try {
136
136
  value = await Tree.traverse(tree, ...keys);
@@ -5,7 +5,9 @@ import { addHref } from "./utilities.js";
5
5
 
6
6
  export default function pathsInHtml(html) {
7
7
  const paths = {
8
+ /** @type {string[]} */
8
9
  crawlablePaths: [],
10
+ /** @type {string[]} */
9
11
  resourcePaths: [],
10
12
  };
11
13
 
@@ -5,7 +5,7 @@ import path from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
6
  import assertTreeIsDefined from "../common/assertTreeIsDefined.js";
7
7
  import { getDescriptor } from "../common/utilities.js";
8
- import { builtinsTree } from "../internal.js";
8
+ import oriHandler from "../handlers/ori.handler.js";
9
9
  import debug from "./debug.js";
10
10
 
11
11
  let templatePromise;
@@ -44,7 +44,7 @@ export default async function explore(...keys) {
44
44
  const data = await getScopeData(scope(tree));
45
45
  templatePromise ??= loadTemplate();
46
46
  const template = await templatePromise;
47
- const text = await template(data);
47
+ const text = await template.call(this, data);
48
48
 
49
49
  result = new String(text);
50
50
  result.unpack = () => debug.call(tree, tree);
@@ -57,10 +57,6 @@ async function getScopeData(scope) {
57
57
  const trees = scope.trees ?? [scope];
58
58
  const data = [];
59
59
  for (const tree of trees) {
60
- if (tree.parent === undefined) {
61
- // Skip builtins.
62
- continue;
63
- }
64
60
  const name = getDescriptor(tree);
65
61
  const treeKeys = Array.from(await tree.keys());
66
62
  // Skip system-ish files that start with a period.
@@ -73,8 +69,7 @@ async function getScopeData(scope) {
73
69
  async function loadTemplate() {
74
70
  const folderPath = path.resolve(fileURLToPath(import.meta.url), "..");
75
71
  const folder = new OrigamiFiles(folderPath);
76
- folder.parent = builtinsTree;
77
72
  const templateFile = await folder.get("explore.ori");
78
- const template = await templateFile.unpack();
73
+ const template = await oriHandler.unpack(templateFile, { parent: folder });
79
74
  return template;
80
75
  }
@@ -1,7 +1,7 @@
1
1
  // .css files use the .txt loader
2
- import fileTypeText from "./txt.handler.js";
2
+ import { txtHandler } from "./handlers.js";
3
3
 
4
4
  export default {
5
- ...fileTypeText,
5
+ ...txtHandler,
6
6
  mediaType: "text/css",
7
7
  };
@@ -0,0 +1,26 @@
1
+ import * as handlers from "./handlers.js";
2
+
3
+ export default function handlerBuiltins() {
4
+ return {
5
+ "css.handler": handlers.cssHandler,
6
+ "csv.handler": handlers.csvHandler,
7
+ "htm.handler": handlers.htmHandler,
8
+ "html.handler": handlers.htmlHandler,
9
+ "jpeg.handler": handlers.jpegHandler,
10
+ "jpg.handler": handlers.jpgHandler,
11
+ "js.handler": handlers.jsHandler,
12
+ "jse.handler": handlers.jseHandler,
13
+ "jsedocument.handler": handlers.jsedocumentHandler,
14
+ "json.handler": handlers.jsonHandler,
15
+ "md.handler": handlers.mdHandler,
16
+ "mjs.handler": handlers.mjsHandler,
17
+ "ori.handler": handlers.oriHandler,
18
+ "oridocument.handler": handlers.oridocumentHandler,
19
+ "ts.handler": handlers.tsHandler,
20
+ "txt.handler": handlers.txtHandler,
21
+ "wasm.handler": handlers.wasmHandler,
22
+ "xhtml.handler": handlers.xhtmlHandler,
23
+ "yaml.handler": handlers.yamlHandler,
24
+ "yml.handler": handlers.ymlHandler,
25
+ };
26
+ }
@@ -1,46 +1,37 @@
1
- import {
2
- jsHandler,
3
- oriHandler,
4
- oridocumentHandler,
5
- wasmHandler,
6
- yamlHandler,
7
- } from "../internal.js";
8
- import cssHandler from "./css.handler.js";
9
- import csvHandler from "./csv.handler.js";
10
- import htmHandler from "./htm.handler.js";
11
- import htmlHandler from "./html.handler.js";
12
- import jpegHandler from "./jpeg.handler.js";
13
- import jpgHandler from "./jpg.handler.js";
14
- import jseHandler from "./jse.handler.js";
15
- import jseDocumentHandler from "./jsedocument.handler.js";
16
- import jsonHandler from "./json.handler.js";
17
- import mdHandler from "./md.handler.js";
18
- import mjsHandler from "./mjs.handler.js";
19
- import tsHandler from "./ts.handler.js";
20
- import txtHandler from "./txt.handler.js";
21
- import xhtmlHandler from "./xhtml.handler.js";
22
- import ymlHandler from "./yml.handler.js";
1
+ //
2
+ // This library includes a number of modules with circular dependencies. This
3
+ // module exists to explicitly set the loading order for those modules. To
4
+ // enforce use of this loading order, other modules should only load the modules
5
+ // below via this module.
6
+ //
7
+ // About this pattern:
8
+ // https://medium.com/visual-development/how-to-fix-nasty-circular-dependency-issues-once-and-for-all-in-javascript-typescript-a04c987cf0de
9
+ //
10
+ // Note: to avoid having VS Code auto-sort the imports, keep lines between them.
23
11
 
24
- export default {
25
- "css.handler": cssHandler,
26
- "csv.handler": csvHandler,
27
- "htm.handler": htmHandler,
28
- "html.handler": htmlHandler,
29
- "jpeg.handler": jpegHandler,
30
- "jpg.handler": jpgHandler,
31
- "js.handler": jsHandler,
32
- "jse.handler": jseHandler,
33
- "jsep.handler": jseHandler,
34
- "jsedocument.handler": jseDocumentHandler,
35
- "json.handler": jsonHandler,
36
- "md.handler": mdHandler,
37
- "mjs.handler": mjsHandler,
38
- "ori.handler": oriHandler,
39
- "oridocument.handler": oridocumentHandler,
40
- "ts.handler": tsHandler,
41
- "txt.handler": txtHandler,
42
- "wasm.handler": wasmHandler,
43
- "xhtml.handler": xhtmlHandler,
44
- "yaml.handler": yamlHandler,
45
- "yml.handler": ymlHandler,
46
- };
12
+ export { default as jsHandler } from "./js.handler.js";
13
+ export { default as tsHandler } from "./ts.handler.js";
14
+
15
+ export { default as oriHandler } from "./ori.handler.js";
16
+
17
+ export { default as jseHandler } from "./jse.handler.js";
18
+
19
+ export { default as oridocumentHandler } from "./oridocument.handler.js";
20
+
21
+ export { default as jsedocumentHandler } from "./jsedocument.handler.js";
22
+
23
+ export { default as txtHandler } from "./txt.handler.js";
24
+
25
+ export { default as cssHandler } from "./css.handler.js";
26
+ export { default as csvHandler } from "./csv.handler.js";
27
+ export { default as htmHandler } from "./htm.handler.js";
28
+ export { default as htmlHandler } from "./html.handler.js";
29
+ export { default as jpegHandler } from "./jpeg.handler.js";
30
+ export { default as jpgHandler } from "./jpg.handler.js";
31
+ export { default as jsonHandler } from "./json.handler.js";
32
+ export { default as mdHandler } from "./md.handler.js";
33
+ export { default as mjsHandler } from "./mjs.handler.js";
34
+ export { default as wasmHandler } from "./wasm.handler.js";
35
+ export { default as xhtmlHandler } from "./xhtml.handler.js";
36
+ export { default as yamlHandler } from "./yaml.handler.js";
37
+ export { default as ymlHandler } from "./yml.handler.js";
@@ -1,2 +1,2 @@
1
1
  // .htm is a synonynm for .html
2
- export { default } from "./html.handler.js";
2
+ export { htmlHandler as default } from "./handlers.js";
@@ -1,7 +1,7 @@
1
1
  // .html files use the .txt loader
2
- import fileTypeText from "./txt.handler.js";
2
+ import { txtHandler } from "./handlers.js";
3
3
 
4
4
  export default {
5
- ...fileTypeText,
5
+ ...txtHandler,
6
6
  mediaType: "text/html",
7
7
  };
@@ -1,2 +1,2 @@
1
1
  // .jpg is a synonym for .jpeg
2
- export { default } from "./jpeg.handler.js";
2
+ export { jpegHandler as default } from "./handlers.js";
@@ -1,4 +1,4 @@
1
- import { processUnpackedContent } from "../internal.js";
1
+ import processUnpackedContent from "./processUnpackedContent.js";
2
2
 
3
3
  /**
4
4
  * A JavaScript file
@@ -1,6 +1,6 @@
1
- import { oriHandler } from "../internal.js";
1
+ import builtinsJse from "../builtinsJse.js";
2
2
  import getParent from "./getParent.js";
3
- import jseModeParent from "./jseModeParent.js";
3
+ import { oriHandler } from "./handlers.js";
4
4
 
5
5
  export default {
6
6
  ...oriHandler,
@@ -9,8 +9,9 @@ export default {
9
9
  const parent = getParent(packed, options);
10
10
  return oriHandler.unpack(packed, {
11
11
  ...options,
12
+ globals: builtinsJse(),
12
13
  mode: "jse",
13
- parent: await jseModeParent(parent),
14
+ parent,
14
15
  });
15
16
  },
16
17
  };
@@ -1,6 +1,6 @@
1
- import { oridocumentHandler } from "../internal.js";
1
+ import builtinsJse from "../builtinsJse.js";
2
2
  import getParent from "./getParent.js";
3
- import jseModeParent from "./jseModeParent.js";
3
+ import { oridocumentHandler } from "./handlers.js";
4
4
 
5
5
  export default {
6
6
  ...oridocumentHandler,
@@ -9,8 +9,9 @@ export default {
9
9
  const parent = getParent(packed, options);
10
10
  return oridocumentHandler.unpack(packed, {
11
11
  ...options,
12
+ globals: builtinsJse(),
12
13
  mode: "jse",
13
- parent: await jseModeParent(parent),
14
+ parent,
14
15
  });
15
16
  },
16
17
  };
@@ -1,7 +1,7 @@
1
1
  // .md files use the .txt loader
2
- import fileTypeText from "./txt.handler.js";
2
+ import { txtHandler } from "./handlers.js";
3
3
 
4
4
  export default {
5
- ...fileTypeText,
5
+ ...txtHandler,
6
6
  mediaType: "text/markdown",
7
7
  };
@@ -1,2 +1,2 @@
1
1
  // .mjs is a synonynm for .js
2
- export { jsHandler as default } from "../internal.js";
2
+ export { jsHandler as default } from "./handlers.js";
@@ -1,7 +1,10 @@
1
+ import { merge } from "@weborigami/async-tree";
1
2
  import { compile } from "@weborigami/language";
3
+ import builtinsShell from "../builtinsShell.js";
4
+ import getConfig from "../cli/getConfig.js";
2
5
  import * as utilities from "../common/utilities.js";
3
- import { builtinsTree, processUnpackedContent } from "../internal.js";
4
6
  import getParent from "./getParent.js";
7
+ import processUnpackedContent from "./processUnpackedContent.js";
5
8
 
6
9
  /**
7
10
  * An Origami expression file
@@ -34,11 +37,15 @@ export default {
34
37
 
35
38
  // Compile the source code as an Origami program and evaluate it.
36
39
  const compiler = options.compiler ?? compile.program;
40
+
41
+ const config = getConfig(parent);
42
+ const globals = merge(options.globals ?? builtinsShell(), config);
43
+
37
44
  const mode = options.mode ?? "shell";
38
- const fn = compiler(source, { mode });
39
- const target = parent ?? builtinsTree;
40
- let content = await fn.call(target);
45
+ const fn = compiler(source, { globals, mode });
46
+
47
+ let result = await fn.call(parent);
41
48
 
42
- return processUnpackedContent(content, parent);
49
+ return processUnpackedContent(result, parent);
43
50
  },
44
51
  };
@@ -1,8 +1,9 @@
1
1
  import { extension, trailingSlash } from "@weborigami/async-tree";
2
2
  import { compile } from "@weborigami/language";
3
+ import builtinsShell from "../builtinsShell.js";
3
4
  import { toString } from "../common/utilities.js";
4
- import { processUnpackedContent } from "../internal.js";
5
5
  import getParent from "./getParent.js";
6
+ import processUnpackedContent from "./processUnpackedContent.js";
6
7
 
7
8
  /**
8
9
  * An Origami template document: a plain text file that contains Origami
@@ -35,8 +36,19 @@ export default {
35
36
  text,
36
37
  url,
37
38
  };
39
+
40
+ let globals;
41
+ if (options.globals) {
42
+ globals = options.globals;
43
+ } else {
44
+ globals = builtinsShell();
45
+ }
46
+
38
47
  const mode = options.mode ?? "shell";
39
- const defineFn = compile.templateDocument(source, { mode });
48
+ const defineFn = compile.templateDocument(source, {
49
+ globals,
50
+ mode,
51
+ });
40
52
 
41
53
  // Invoke the definition to get back the template function
42
54
  const result = await defineFn.call(parent);
@@ -1,5 +1,4 @@
1
1
  import { symbols, Tree } from "@weborigami/async-tree";
2
- import { builtinsTree } from "../internal.js";
3
2
 
4
3
  /**
5
4
  * Perform any necessary post-processing on the unpacked content of a file. This
@@ -14,8 +13,7 @@ import { builtinsTree } from "../internal.js";
14
13
  export default function processUnpackedContent(content, parent) {
15
14
  if (typeof content === "function") {
16
15
  // Bind the function to the parent as the `this` context.
17
- const target = parent ?? builtinsTree;
18
- const result = content.bind(target);
16
+ const result = content.bind(parent);
19
17
  // Copy over any properties that were attached to the function
20
18
  Object.assign(result, content);
21
19
  return result;
@@ -1 +1 @@
1
- export { default as default } from "./js.handler.js";
1
+ export { jsHandler as default } from "./handlers.js";
@@ -77,7 +77,7 @@ export default {
77
77
  unpacked = Object.assign({}, frontData, { "@text": body });
78
78
  Object.defineProperty(unpacked, "_body", {
79
79
  configurable: true,
80
- value: text,
80
+ value: body,
81
81
  enumerable: false, // TODO: Make enumerable
82
82
  writable: true,
83
83
  });
@@ -1,4 +1,4 @@
1
- import { processUnpackedContent } from "../internal.js";
1
+ import processUnpackedContent from "./processUnpackedContent.js";
2
2
 
3
3
  /**
4
4
  * A WebAssembly module
@@ -2,7 +2,7 @@ import { symbols } from "@weborigami/async-tree";
2
2
  import * as YAMLModule from "yaml";
3
3
  import { parseYaml } from "../common/serialize.js";
4
4
  import * as utilities from "../common/utilities.js";
5
- import { processUnpackedContent } from "../internal.js";
5
+ import processUnpackedContent from "./processUnpackedContent.js";
6
6
 
7
7
  // See notes at serialize.js
8
8
  // @ts-ignore
@@ -1,2 +1,2 @@
1
1
  // .yml is a synonym for .yaml
2
- export { yamlHandler as default } from "../internal.js";
2
+ export { default } from "./yaml.handler.js";
@@ -13,8 +13,6 @@ import project from "./project.js";
13
13
  */
14
14
  export default async function config(key) {
15
15
  const projectTree = await project.call(this);
16
- // HACK: We use specific knowledge of how @project returns a tree to get the
17
- // config. The config is always the parent of the project folder.
18
- const parent = projectTree.parent;
19
- return key === undefined ? parent : parent.get(key);
16
+ const projectConfig = projectTree.config;
17
+ return key === undefined ? projectConfig : projectConfig.get(key);
20
18
  }
@@ -1,10 +1,12 @@
1
1
  import {
2
2
  Tree,
3
3
  getRealmObjectPrototype,
4
+ merge,
4
5
  toString,
5
6
  } from "@weborigami/async-tree";
6
7
  import { compile } from "@weborigami/language";
7
- import builtinsTree from "../builtinsTree.js";
8
+ import builtinsShell from "../builtinsShell.js";
9
+ import getConfig from "../cli/getConfig.js";
8
10
  import assertTreeIsDefined from "../common/assertTreeIsDefined.js";
9
11
  import { toYaml } from "../common/serialize.js";
10
12
 
@@ -28,13 +30,20 @@ export default async function ori(
28
30
  // In case expression has come from a file, cast it to a string.
29
31
  expression = toString(expression);
30
32
 
31
- // Run in the context of `this` if defined, otherwise use the builtins.
32
- const tree = this ?? builtinsTree;
33
+ // Run in the context of `this` if defined
34
+ const tree = this;
35
+
36
+ const config = getConfig(tree);
37
+ const globals = merge(builtinsShell(), config);
33
38
 
34
39
  // Compile the expression. Avoid caching scope references so that, e.g.,
35
40
  // passing a function to the `watch` builtin will always look the current
36
41
  // value of things in scope.
37
- const fn = compile.expression(expression, { scopeCaching: false });
42
+ const fn = compile.expression(expression, {
43
+ globals,
44
+ mode: "shell",
45
+ scopeCaching: false,
46
+ });
38
47
 
39
48
  // Execute
40
49
  let result = await fn.call(tree);
@@ -1,8 +1,3 @@
1
- // Use a dynamic import to avoid circular dependencies
2
- export const builtins = import("../internal.js").then(
3
- (internal) => internal.builtinsTree
4
- );
5
-
6
1
  export { extension } from "@weborigami/async-tree";
7
2
  export { toFunction } from "../common/utilities.js";
8
3
 
@@ -1,13 +1,17 @@
1
1
  /** @typedef {import("@weborigami/types").AsyncTree} AsyncTree */
2
- import { Tree } from "@weborigami/async-tree";
2
+ import { merge } from "@weborigami/async-tree";
3
3
  import { OrigamiFiles } from "@weborigami/language";
4
4
  import assertTreeIsDefined from "../common/assertTreeIsDefined.js";
5
- import { builtinsTree, oriHandler } from "../internal.js";
5
+ import handlerBuiltins from "../handlers/handlerBuiltins.js";
6
+ import { oriHandler } from "../handlers/handlers.js";
6
7
 
7
8
  const configFileName = "config.ori";
8
9
 
9
10
  /**
10
- * Return the tree for the current project's root folder.
11
+ * Return an object for the current project including
12
+ *
13
+ * `config`: the evaluated config.ori file
14
+ * `root`: the project's root folder
11
15
  *
12
16
  * This searches the current directory and its ancestors for an Origami file
13
17
  * called `config.ori`. If an Origami configuration file is found, the
@@ -19,81 +23,70 @@ const configFileName = "config.ori";
19
23
  * returned as a tree, with the builtins as its parent.
20
24
  *
21
25
  * @this {AsyncTree|null}
22
- * @param {any} [key]
23
26
  */
24
- export default async function project(key) {
27
+ export default async function project() {
25
28
  assertTreeIsDefined(this, "origami:project");
26
29
 
27
30
  const dirname = process.cwd();
28
31
  const currentTree = new OrigamiFiles(dirname);
29
- currentTree.parent = builtinsTree;
30
32
 
31
33
  // Search up the tree for the configuration file or package.json to determine
32
34
  // the project root.
33
- const configContainer =
34
- (await findAncestorFile(currentTree, configFileName)) ??
35
- (await findAncestorFile(currentTree, "package.json"));
36
-
37
- let projectRoot;
38
- if (!configContainer) {
39
- // No configuration file or package.json found; use the current directory.
40
- projectRoot = currentTree;
35
+ let root;
36
+ const foundConfig = await findAncestorFile(currentTree, configFileName);
37
+ if (foundConfig) {
38
+ root = foundConfig.container;
39
+ // Unpack Origami configuration file
40
+ const buffer = foundConfig.value;
41
+ root.config = await oriHandler.unpack(buffer, {
42
+ key: configFileName,
43
+ parent: root,
44
+ });
41
45
  } else {
42
- // Load the configuration file if one exists.
43
- const buffer = await configContainer.get(configFileName);
44
- if (!buffer) {
45
- // Project root defined by package.json
46
- projectRoot = configContainer;
46
+ // No Origami configuration file, look for package.json
47
+ const foundPackageJson = await findAncestorFile(
48
+ currentTree,
49
+ "package.json"
50
+ );
51
+ if (foundPackageJson) {
52
+ // Found package.json; use its parent as the project root
53
+ root = foundPackageJson.container;
47
54
  } else {
48
- // Load Origami configuration file
49
- const config = await oriHandler.unpack(buffer, {
50
- key: configFileName,
51
- parent: configContainer,
52
- });
53
- if (!config) {
54
- const configPath = /** @type {any} */ (configContainer).path;
55
- throw new Error(
56
- `Couldn't load the Origami configuration in ${configPath}/${configFileName}`
57
- );
58
- }
59
-
60
- // The config tree may refer to the container tree *and vice versa*. To
61
- // support this, we put the container in the tree twice. The chain will
62
- // be: projectRoot -> configTree -> configContainer -> builtins, where
63
- // the projectRoot and configContainer are the same folder.
64
- const configTree = Tree.from(config);
65
- projectRoot = new OrigamiFiles(configContainer.path);
66
- projectRoot.parent = configTree;
67
- configTree.parent = configContainer;
68
- configContainer.parent = builtinsTree;
55
+ // No package.json found; use the current directory as root
56
+ root = currentTree;
69
57
  }
70
58
  }
71
59
 
72
- return key === undefined ? projectRoot : projectRoot.get(key);
60
+ // Merge config if present into handlers
61
+ root.handlers = merge(handlerBuiltins(), root.config);
62
+
63
+ return root;
73
64
  }
74
65
 
75
- // Return the first ancestor of the given tree that contains a file with the
76
- // given name.
66
+ // Find the first ancestor of the given folder that contains a file with the
67
+ // given name. Return the container and the file contents.
77
68
  async function findAncestorFile(start, fileName) {
78
- let current = start;
79
- while (current) {
80
- const value = await current.get(fileName);
69
+ let container = start;
70
+ while (container) {
71
+ const value = await container.get(fileName);
81
72
  if (value) {
82
- // Found the desired file; its container is the project root. Set the
83
- // parent to the builtins; in the context of this project, there's nothing
84
- // higher up.
85
- current.parent = builtinsTree;
86
- return current;
73
+ // Found the desired file
74
+ return {
75
+ container,
76
+ value,
77
+ };
87
78
  }
88
- // Not found; try the parent.
89
- const parent = await current.get("..");
79
+ // Not found; try the parent
80
+ const parent = await container.get("..");
90
81
  if (
91
82
  !parent ||
92
- (parent.path && current.path && parent.path === current.path)
83
+ (parent.path && container.path && parent.path === container.path)
93
84
  ) {
94
85
  break;
95
86
  }
96
- current = parent;
87
+ container = parent;
97
88
  }
98
- return undefined;
89
+
90
+ // Not found
91
+ return null;
99
92
  }
@@ -1,4 +1,4 @@
1
- import { OrigamiFiles } from "@weborigami/language";
1
+ import { OrigamiFiles, getHandlers } from "@weborigami/language";
2
2
  import os from "node:os";
3
3
  import path from "node:path";
4
4
  import process from "node:process";
@@ -26,5 +26,6 @@ export default async function files(...keys) {
26
26
  const resolved = path.resolve(basePath, relativePath);
27
27
 
28
28
  const result = new OrigamiFiles(resolved);
29
+ result.handlers = getHandlers(this);
29
30
  return result;
30
31
  }
@@ -1,5 +1,4 @@
1
- import { Tree } from "@weborigami/async-tree";
2
- import { ops } from "@weborigami/language";
1
+ import { scope, Tree } from "@weborigami/async-tree";
3
2
  import assertTreeIsDefined from "../common/assertTreeIsDefined.js";
4
3
 
5
4
  /**
@@ -13,6 +12,10 @@ import assertTreeIsDefined from "../common/assertTreeIsDefined.js";
13
12
  export default async function inherited(...keys) {
14
13
  assertTreeIsDefined(this, "inherited:");
15
14
  const key = keys.shift();
16
- const value = await ops.inherited.call(this, key);
15
+ if (!this?.parent) {
16
+ return undefined;
17
+ }
18
+ const parentScope = scope(this.parent);
19
+ const value = await parentScope.get(key);
17
20
  return keys.length > 0 ? await Tree.traverse(value, ...keys) : value;
18
21
  }
@@ -1,5 +1,4 @@
1
- import { Tree } from "@weborigami/async-tree";
2
- import { ops } from "@weborigami/language";
1
+ import { Tree, scope as scopeFn } from "@weborigami/async-tree";
3
2
 
4
3
  /**
5
4
  * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
@@ -12,7 +11,8 @@ export default async function scope(...keys) {
12
11
  let value;
13
12
  try {
14
13
  // Look up key in scope but don't throw if it's undefined
15
- value = await ops.scope.call(this, key);
14
+ const thisScope = scopeFn(this);
15
+ value = await thisScope.get(key);
16
16
  } catch (error) {
17
17
  if (error instanceof ReferenceError) {
18
18
  value = undefined;
@@ -1,7 +1,7 @@
1
1
  import { Tree } from "@weborigami/async-tree";
2
2
  import assertTreeIsDefined from "../common/assertTreeIsDefined.js";
3
3
  import getTreeArgument from "../common/getTreeArgument.js";
4
- import { builtinsTree, oriHandler } from "../internal.js";
4
+ import { oriHandler } from "../handlers/handlers.js";
5
5
 
6
6
  const templateText = `(urls) => \`<?xml version="1.0" encoding="UTF-8"?>
7
7
  <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
@@ -48,7 +48,6 @@ export default async function sitemap(treelike, baseHref = "") {
48
48
  .map((path) => (path.endsWith("index.html") ? path.slice(0, -10) : path));
49
49
 
50
50
  const templateFn = await oriHandler.unpack(templateText);
51
- const target = this ?? builtinsTree;
52
- const templateResult = await templateFn.call(target, htmlPaths);
51
+ const templateResult = await templateFn.call(this, htmlPaths);
53
52
  return String(templateResult);
54
53
  }
@@ -6,7 +6,7 @@ import {
6
6
  } from "@weborigami/async-tree";
7
7
  import assertTreeIsDefined from "../common/assertTreeIsDefined.js";
8
8
  import documentObject from "../common/documentObject.js";
9
- import { oridocumentHandler } from "../internal.js";
9
+ import { oridocumentHandler } from "../handlers/handlers.js";
10
10
 
11
11
  /**
12
12
  * Inline any Origami expressions found inside ${...} placeholders in the input
package/src/tree/map.js CHANGED
@@ -69,7 +69,7 @@ function extendedOptions(context, operation) {
69
69
  options = {};
70
70
  } else {
71
71
  throw new TypeError(
72
- `map: You must specify a value function or options dictionary as the first parameter.`
72
+ `map: You must specify a value function or options dictionary as the second parameter.`
73
73
  );
74
74
  }
75
75
 
package/src/builtins.js DELETED
@@ -1,56 +0,0 @@
1
- import * as dev from "./dev/dev.js";
2
- import * as handlers from "./handlers/handlers.js";
3
- import help from "./help/help.js";
4
- import * as image from "./image/image.js";
5
- import js from "./js.js";
6
- import node from "./node.js";
7
- import * as origami from "./origami/origami.js";
8
- import explore from "./protocols/explore.js";
9
- import files from "./protocols/files.js";
10
- import http from "./protocols/http.js";
11
- import https from "./protocols/https.js";
12
- import httpstree from "./protocols/httpstree.js";
13
- import httptree from "./protocols/httptree.js";
14
- import inherited from "./protocols/inherited.js";
15
- import instantiate from "./protocols/new.js";
16
- import packageNamespace from "./protocols/package.js";
17
- import scope from "./protocols/scope.js";
18
- import * as site from "./site/site.js";
19
- import * as text from "./text/text.js";
20
- import * as tree from "./tree/tree.js";
21
-
22
- /** @type {any} */
23
- export default {
24
- "dev:": dev,
25
- "explore:": explore,
26
- "files:": files,
27
- "help:": help,
28
- "http:": http,
29
- "https:": https,
30
- "httpstree:": httpstree,
31
- "httptree:": httptree,
32
- "image:": image,
33
- "inherited:": inherited,
34
- "js:": js,
35
- "new:": instantiate,
36
- "node:": node,
37
- "origami:": origami,
38
- "package:": packageNamespace,
39
- "scope:": scope,
40
- "site:": adjustReservedWords(site),
41
- "text:": text,
42
- "tree:": tree,
43
-
44
- // Some builtins need to be exposed at top level
45
- ...handlers.default,
46
- };
47
-
48
- // Handle cases where a builtin name conflicts with a JS reserved word
49
- function adjustReservedWords(obj) {
50
- const result = {};
51
- for (const [key, value] of Object.entries(obj)) {
52
- const name = value.key ?? key;
53
- result[name] = value;
54
- }
55
- return result;
56
- }
@@ -1,84 +0,0 @@
1
- import {
2
- ObjectTree,
3
- trailingSlash,
4
- text as treeText,
5
- } from "@weborigami/async-tree";
6
- import * as dev from "./dev/dev.js";
7
- import * as handlers from "./handlers/handlers.js";
8
- import help from "./help/help.js";
9
- import * as image from "./image/image.js";
10
- import js from "./js.js";
11
- import node from "./node.js";
12
- import * as origami from "./origami/origami.js";
13
- import explore from "./protocols/explore.js";
14
- import files from "./protocols/files.js";
15
- import http from "./protocols/http.js";
16
- import https from "./protocols/https.js";
17
- import httpstree from "./protocols/httpstree.js";
18
- import httptree from "./protocols/httptree.js";
19
- import inherited from "./protocols/inherited.js";
20
- import instantiate from "./protocols/new.js";
21
- import packageNamespace from "./protocols/package.js";
22
- import scope from "./protocols/scope.js";
23
- import * as site from "./site/site.js";
24
- import * as text from "./text/text.js";
25
- import * as tree from "./tree/tree.js";
26
-
27
- // See notes in builtinsTree.js
28
- class BuiltinsTree {
29
- constructor(object) {
30
- this.object = object;
31
- }
32
-
33
- async get(key) {
34
- const normalizedKey = trailingSlash.remove(key);
35
- return this.object[normalizedKey];
36
- }
37
-
38
- async keys() {
39
- return Object.keys(this.object);
40
- }
41
- }
42
-
43
- const Tree = new BuiltinsTree({
44
- ...tree,
45
- indent: text.indent,
46
- json: origami.json,
47
- text: treeText,
48
- });
49
-
50
- const Origami = new BuiltinsTree({
51
- ...dev,
52
- ...origami,
53
- ...site,
54
- ...text,
55
- });
56
-
57
- const Image = new BuiltinsTree({
58
- ...image,
59
- });
60
-
61
- /** @type {any} */
62
- export default new ObjectTree({
63
- "explore:": explore,
64
- "files:": files,
65
- "help:": help,
66
- "http:": http,
67
- "https:": https,
68
- "httpstree:": httpstree,
69
- "httptree:": httptree,
70
- "inherited:": inherited,
71
- "new:": instantiate,
72
- "node:": node,
73
- "package:": packageNamespace,
74
- "scope:": scope,
75
-
76
- ...js,
77
-
78
- Tree,
79
- Origami,
80
- Image,
81
-
82
- // Some builtins need to be exposed at top level
83
- ...handlers.default,
84
- });
@@ -1,36 +0,0 @@
1
- import { trailingSlash } from "@weborigami/async-tree";
2
- import builtins from "./builtins.js";
3
-
4
- const expanded = { ...builtins };
5
-
6
- // For all builtins like `tree:keys`, add a shorthand `keys`.
7
- for (const [key, value] of Object.entries(expanded)) {
8
- const isNamespace = key.endsWith(":");
9
- if (isNamespace) {
10
- for (const [subKey, subValue] of Object.entries(value)) {
11
- // HACK: Skip description keys until we can make them all non-enumerable.
12
- if (subKey === "description") {
13
- continue;
14
- }
15
- if (subKey in expanded) {
16
- throw new Error(`Internal Origami error: Duplicate key: ${subKey}`);
17
- }
18
- expanded[subKey] = subValue;
19
- }
20
- }
21
- }
22
-
23
- // We create our own tree instead of using ObjectTree, since that binds the
24
- // functions would be bound to the object. We want to leave them unbound.
25
- class BuiltinsTree {
26
- async get(key) {
27
- const normalizedKey = trailingSlash.remove(key);
28
- return expanded[normalizedKey];
29
- }
30
-
31
- async keys() {
32
- return Object.keys(expanded);
33
- }
34
- }
35
-
36
- export default new BuiltinsTree();
@@ -1,16 +0,0 @@
1
- export { default as cssHandler } from "./css.handler.js";
2
- export { default as htmHandler } from "./htm.handler.js";
3
- export { default as htmlHandler } from "./html.handler.js";
4
- export { default as jpegHandler } from "./jpeg.handler.js";
5
- export { default as jpgHandler } from "./jpg.handler.js";
6
- export { default as jsHandler } from "./js.handler.js";
7
- export { default as jsonHandler } from "./json.handler.js";
8
- export { default as mdHandler } from "./md.handler.js";
9
- export { default as mjsHandler } from "./mjs.handler.js";
10
- export { default as oriHandler } from "./ori.handler.js";
11
- export { default as oridocumentHandler } from "./oridocument.handler.js";
12
- export { default as txtHandler } from "./txt.handler.js";
13
- export { default as wasmHandler } from "./wasm.handler.js";
14
- export { default as xhtmlHandler } from "./xhtml.handler.js";
15
- export { default as yamlHandler } from "./yaml.handler.js";
16
- export { default as ymlHandler } from "./yml.handler.js";
@@ -1,30 +0,0 @@
1
- import { FileTree, ObjectTree } from "@weborigami/async-tree";
2
-
3
- let builtinsNew;
4
-
5
- // Adapt the existing parent chain to use the new builtins
6
- export default async function jseModeParent(parent) {
7
- builtinsNew ??= (await import("../builtinsNew.js")).default;
8
- return cloneParent(parent);
9
- }
10
-
11
- function cloneParent(parent) {
12
- let clone;
13
- // We expect the parent to be a FileTree (or a subclass), ObjectTree (or a
14
- // subclass), or builtins.
15
- if (!parent) {
16
- return null;
17
- } else if (parent instanceof FileTree) {
18
- clone = Reflect.construct(parent.constructor, [parent.path]);
19
- } else if (parent instanceof ObjectTree) {
20
- clone = Reflect.construct(parent.constructor, [parent.object]);
21
- } else if (!parent.parent) {
22
- // Builtins
23
- clone = builtinsNew;
24
- } else {
25
- // Maybe a map? Skip it and hope for the best.
26
- return cloneParent(parent.parent);
27
- }
28
- clone.parent = cloneParent(parent.parent);
29
- return clone;
30
- }
package/src/internal.js DELETED
@@ -1,28 +0,0 @@
1
- //
2
- // This library includes a number of modules with circular dependencies. This
3
- // module exists to explicitly set the loading order for those modules. To
4
- // enforce use of this loading order, other modules should only load the modules
5
- // below via this module.
6
- //
7
- // About this pattern:
8
- // https://medium.com/visual-development/how-to-fix-nasty-circular-dependency-issues-once-and-for-all-in-javascript-typescript-a04c987cf0de
9
- //
10
- // Note: to avoid having VS Code auto-sort the imports, keep lines between them.
11
-
12
- export { default as jsHandler } from "./handlers/js.handler.js";
13
-
14
- export { default as oriHandler } from "./handlers/ori.handler.js";
15
-
16
- export { default as oridocumentHandler } from "./handlers/oridocument.handler.js";
17
-
18
- export { default as jseHandler } from "./handlers/jse.handler.js";
19
-
20
- export { default as jsedocumentHandler } from "./handlers/jsedocument.handler.js";
21
-
22
- export { default as processUnpackedContent } from "./common/processUnpackedContent.js";
23
-
24
- export { default as wasmHandler } from "./handlers/wasm.handler.js";
25
-
26
- export { default as yamlHandler } from "./handlers/yaml.handler.js";
27
-
28
- export { default as builtinsTree } from "./builtinsTree.js";
package/src/js.js DELETED
@@ -1,79 +0,0 @@
1
- /**
2
- * The complete set of support JavaScript globals and global-like values.
3
- *
4
- * See
5
- * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects.
6
- * That page lists some things like `TypedArrays` which are not globals so are
7
- * omitted here.
8
- */
9
- export default {
10
- AggregateError,
11
- Array,
12
- ArrayBuffer,
13
- Atomics,
14
- BigInt,
15
- BigInt64Array,
16
- BigUint64Array,
17
- Boolean,
18
- DataView,
19
- Date,
20
- Error,
21
- EvalError,
22
- FinalizationRegistry,
23
- Float32Array,
24
- Float64Array,
25
- Function,
26
- Infinity,
27
- Int16Array,
28
- Int32Array,
29
- Int8Array,
30
- Intl,
31
- // @ts-ignore Iterator does exist despite what TypeScript thinks
32
- Iterator,
33
- JSON,
34
- Map,
35
- Math,
36
- NaN,
37
- Number,
38
- Object,
39
- Promise,
40
- Proxy,
41
- RangeError,
42
- ReferenceError,
43
- Reflect,
44
- RegExp,
45
- Set,
46
- SharedArrayBuffer,
47
- String,
48
- Symbol,
49
- SyntaxError,
50
- TypeError,
51
- URIError,
52
- Uint16Array,
53
- Uint32Array,
54
- Uint8Array,
55
- Uint8ClampedArray,
56
- WeakMap,
57
- WeakRef,
58
- WeakSet,
59
- decodeURI,
60
- decodeURIComponent,
61
- encodeURI,
62
- encodeURIComponent,
63
- eval,
64
- false: false, // treat like a global
65
- fetch: fetchWrapper, // special case
66
- globalThis,
67
- isFinite,
68
- isNaN,
69
- null: null, // treat like a global
70
- parseFloat,
71
- parseInt,
72
- true: true, // treat like a global
73
- undefined,
74
- };
75
-
76
- async function fetchWrapper(resource, options) {
77
- const response = await fetch(resource, options);
78
- return response.ok ? await response.arrayBuffer() : undefined;
79
- }