@weborigami/origami 0.0.38 → 0.0.40

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.
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2021–2023 Jan Miksovsky and other contributors
3
+ Copyright (c) 2024 Jan Miksovsky and other contributors
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -1,6 +1,6 @@
1
1
  /** @typedef {import("@weborigami/types").AsyncTree} AsyncTree */
2
2
  import { keyMapsForExtensions, map } from "@weborigami/async-tree";
3
- import unpackOrigamiTemplate from "../src/builtins/@loaders/orit.js";
3
+ import unpackOrigamiTemplate from "../src/builtins/@loaders/ori.js";
4
4
  import { transformObject } from "../src/common/utilities.js";
5
5
  import PathTransform from "./PathTransform.js";
6
6
 
@@ -14,8 +14,8 @@ const specialBuiltinNames = {
14
14
  };
15
15
 
16
16
  // Top-level template for the export file
17
- const templateText = `// This file is generated by running buildExports.js -- do not edit by hand.
18
- {{ _ }}`;
17
+ const templateText = `=\`// This file is generated by running buildExports.js -- do not edit by hand.
18
+ {{ _ }}\``;
19
19
 
20
20
  // Generate a top-level export file for the entire project. For each .js file in
21
21
  // the given source tree, generate an appropriate statement that includes that
@@ -1,6 +1,7 @@
1
1
  // This file is generated by running buildExports.js -- do not edit by hand.
2
2
  export { default as apply } from "../src/builtins/@apply.js";
3
3
  export { default as arrows } from "../src/builtins/@arrows.js";
4
+ export { default as basename } from "../src/builtins/@basename.js";
4
5
  export { default as builtins } from "../src/builtins/@builtins.js";
5
6
  export { default as cache } from "../src/builtins/@cache.js";
6
7
  export { default as config } from "../src/builtins/@config.js";
@@ -10,6 +11,7 @@ export { default as debug } from "../src/builtins/@debug.js";
10
11
  export { default as document } from "../src/builtins/@document.js";
11
12
  export { default as equals } from "../src/builtins/@equals.js";
12
13
  export { default as explore } from "../src/builtins/@explore.js";
14
+ export { default as fetch } from "../src/builtins/@fetch.js";
13
15
  export { default as files } from "../src/builtins/@files.js";
14
16
  export { default as filter } from "../src/builtins/@filter.js";
15
17
  export { default as globs } from "../src/builtins/@globs.js";
@@ -33,19 +35,21 @@ export { default as loadersJson } from "../src/builtins/@loaders/json.js";
33
35
  export { default as loadersMd } from "../src/builtins/@loaders/md.js";
34
36
  export { default as loadersMjs } from "../src/builtins/@loaders/mjs.js";
35
37
  export { default as loadersOri } from "../src/builtins/@loaders/ori.js";
36
- export { default as loadersOrit } from "../src/builtins/@loaders/orit.js";
37
38
  export { default as loadersTxt } from "../src/builtins/@loaders/txt.js";
38
39
  export { default as loadersXhtml } from "../src/builtins/@loaders/xhtml.js";
39
40
  export { default as loadersYaml } from "../src/builtins/@loaders/yaml.js";
40
41
  export { default as loadersYml } from "../src/builtins/@loaders/yml.js";
41
42
  export { default as map } from "../src/builtins/@map.js";
43
+ export { default as mapDeep } from "../src/builtins/@mapDeep.js";
42
44
  export { default as match } from "../src/builtins/@match.js";
43
45
  export { default as mdHtml } from "../src/builtins/@mdHtml.js";
44
46
  export { default as node } from "../src/builtins/@node.js";
45
47
  export { default as not } from "../src/builtins/@not.js";
48
+ export { default as once } from "../src/builtins/@once.js";
46
49
  export { default as or } from "../src/builtins/@or.js";
47
50
  export { default as ori } from "../src/builtins/@ori.js";
48
51
  export { default as pack } from "../src/builtins/@pack.js";
52
+ export { default as package } from "../src/builtins/@package.js";
49
53
  export { default as parseJson } from "../src/builtins/@parse/json.js";
50
54
  export { default as parseYaml } from "../src/builtins/@parse/yaml.js";
51
55
  export { default as project } from "../src/builtins/@project.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@weborigami/origami",
3
- "version": "0.0.38",
3
+ "version": "0.0.40",
4
4
  "description": "Web Origami language, CLI, framework, and server",
5
5
  "type": "module",
6
6
  "repository": {
@@ -13,28 +13,28 @@
13
13
  "main": "./exports/exports.js",
14
14
  "types": "./index.ts",
15
15
  "devDependencies": {
16
- "@types/chai": "4.3.9",
17
- "@types/mocha": "10.0.3",
18
- "@types/node": "20.8.10",
19
- "typescript": "5.2.2"
16
+ "@types/chai": "4.3.11",
17
+ "@types/mocha": "10.0.6",
18
+ "@types/node": "20.11.7",
19
+ "typescript": "5.3.3"
20
20
  },
21
21
  "dependencies": {
22
- "@weborigami/async-tree": "*",
23
- "@weborigami/language": "*",
24
- "@weborigami/types": "0.0.38",
22
+ "@weborigami/async-tree": "0.0.40",
23
+ "@weborigami/language": "0.0.40",
24
+ "@weborigami/types": "0.0.40",
25
25
  "graphviz-wasm": "3.0.1",
26
26
  "highlight.js": "11.9.0",
27
- "marked": "9.1.5",
28
- "marked-gfm-heading-id": "3.1.0",
29
- "marked-highlight": "2.0.6",
30
- "marked-smartypants": "1.1.3",
31
- "sharp": "0.32.6",
32
- "yaml": "2.3.3"
27
+ "marked": "11.1.1",
28
+ "marked-gfm-heading-id": "3.1.2",
29
+ "marked-highlight": "2.1.0",
30
+ "marked-smartypants": "1.1.5",
31
+ "sharp": "0.33.2",
32
+ "yaml": "2.3.4"
33
33
  },
34
34
  "scripts": {
35
35
  "build": "ori exports/buildExports.js src > exports/exports.js",
36
36
  "prepublishOnly": "npm run build",
37
- "test": "node --test --test-reporter=spec test/*/*.test.js test/*/*/*.test.js",
37
+ "test": "node --test --test-reporter=spec",
38
38
  "typecheck": "node node_modules/typescript/bin/tsc"
39
39
  }
40
40
  }
@@ -0,0 +1,6 @@
1
+ import { extname } from "@weborigami/language";
2
+
3
+ export default function basename(key) {
4
+ const ext = extname(key);
5
+ return ext ? key.slice(0, -ext.length) : key;
6
+ }
@@ -1,5 +1,5 @@
1
1
  /** @typedef {import("@weborigami/types").AsyncTree} AsyncTree */
2
- import { ObjectTree } from "@weborigami/async-tree";
2
+ import { ObjectTree, Tree } from "@weborigami/async-tree";
3
3
  import { OrigamiFiles, Scope } from "@weborigami/language";
4
4
  import path from "node:path";
5
5
  import { fileURLToPath } from "node:url";
@@ -14,14 +14,8 @@ const miscFiles = Scope.treeWithScope(new OrigamiFiles(miscDir), builtins);
14
14
  /**
15
15
  * @this {AsyncTree|null}
16
16
  */
17
- export default async function explore() {
17
+ export default async function explore(...keys) {
18
18
  const scope = Scope.getScope(this);
19
- const templateFile = await miscFiles.get("explore.orit");
20
- const template = await templateFile.unpack();
21
-
22
- const data = await getScopeData(scope);
23
- const text = await template(data);
24
-
25
19
  const ambientsTree = new ObjectTree({
26
20
  "@current": this,
27
21
  });
@@ -29,8 +23,34 @@ export default async function explore() {
29
23
  const extendedScope = new Scope(ambientsTree, scope);
30
24
 
31
25
  /** @type {any} */
32
- const result = new String(text);
33
- result.unpack = () => debug.call(scope, extendedScope);
26
+ let result;
27
+ if (keys.length > 0) {
28
+ // Traverse the scope using the given keys.
29
+ const debugScope = await debug.call(scope, extendedScope);
30
+ if (!debugScope) {
31
+ return undefined;
32
+ }
33
+
34
+ // HACK: reproduce logic of ExplorableSiteTransform that turns a trailing
35
+ // slash into index.html. Calling `debug` applies that transform and the
36
+ // transform should handle that logic, but unfortunately the `traverse`
37
+ // operation has special casing to treat a trailing slash, and never gives
38
+ // ExplorableSiteTransform a chance.
39
+ if (keys.at(-1) === "") {
40
+ keys[keys.length - 1] = "index.html";
41
+ }
42
+ result = await Tree.traverse(debugScope, ...keys);
43
+ } else {
44
+ // Return the Explore page for the current scope.
45
+ const templateFile = await miscFiles.get("explore.ori");
46
+ const template = await templateFile.unpack();
47
+
48
+ const data = await getScopeData(scope);
49
+ const text = await template(data);
50
+
51
+ result = new String(text);
52
+ result.unpack = () => debug.call(scope, extendedScope);
53
+ }
34
54
 
35
55
  return result;
36
56
  }
@@ -0,0 +1,7 @@
1
+ export default async function fetchBuiltin(href) {
2
+ const response = await fetch(href);
3
+ return response.ok ? await response.arrayBuffer() : undefined;
4
+ }
5
+
6
+ fetchBuiltin.usage = `@fetch href\tReturns the contents of the given URL as an ArrayBuffer`;
7
+ fetchBuiltin.documentation = "https://weborigami.org/languages/@fetch.html";
@@ -1,5 +1,7 @@
1
+ import { compile } from "@weborigami/language";
2
+ import unpackText from "../builtins/@loaders/txt.js";
1
3
  import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
2
- import unpackOrigamiTemplate from "./@loaders/orit.js";
4
+ import unpackOrigamiExpression from "./@loaders/ori.js";
3
5
 
4
6
  /**
5
7
  * Inline any Origami expressions found inside {{...}} placeholders in the input
@@ -13,16 +15,26 @@ import unpackOrigamiTemplate from "./@loaders/orit.js";
13
15
  */
14
16
  export default async function inline(input) {
15
17
  assertScopeIsDefined(this);
16
- if (/** @type {any} */ (input).unpack) {
17
- input = await /** @type {any} */ (input).unpack();
18
+
19
+ // Get the input text and any attached front matter.
20
+ let inputDocument;
21
+ if (input["@text"]) {
22
+ inputDocument = input;
23
+ } else if (/** @type {any} */ (input).unpack) {
24
+ // Have the input unpack itself.
25
+ inputDocument = await /** @type {any} */ (input).unpack();
26
+ } else {
27
+ // Unpack the input as a text document with possible front matter.
28
+ inputDocument = await unpackText(input);
18
29
  }
19
- const inputDocument = input["@text"] ? input : null;
20
- const templateInput = inputDocument ?? input;
21
- const templateFn = await unpackOrigamiTemplate(templateInput);
22
- const text = await templateFn(inputDocument);
30
+
31
+ const templateFn = await unpackOrigamiExpression(inputDocument, {
32
+ compiler: compile.templateDocument,
33
+ });
34
+ const templateResult = await templateFn(inputDocument);
23
35
  return inputDocument
24
- ? Object.assign({}, inputDocument, { "@text": String(text) })
25
- : text;
36
+ ? Object.assign({}, inputDocument, { "@text": String(templateResult) })
37
+ : templateResult;
26
38
  }
27
39
 
28
40
  inline.usage = `@inline <text>\tInline Origami expressions found in the text`;
@@ -1,6 +1,7 @@
1
1
  import { Scope } from "@weborigami/language";
2
2
  import * as compile from "../../../../language/src/compiler/compile.js";
3
3
  import processUnpackedContent from "../../common/processUnpackedContent.js";
4
+ import * as utilities from "../../common/utilities.js";
4
5
  import builtins from "../@builtins.js";
5
6
 
6
7
  /**
@@ -8,14 +9,37 @@ import builtins from "../@builtins.js";
8
9
  *
9
10
  * @type {import("@weborigami/language").FileUnpackFunction}
10
11
  */
11
- export default async function unpackOrigamiExpression(input, options = {}) {
12
- const parent = options.parent ?? null;
12
+ export default async function unpackOrigamiExpression(
13
+ inputDocument,
14
+ options = {}
15
+ ) {
16
+ const parent =
17
+ options.parent ??
18
+ /** @type {any} */ (inputDocument).parent ??
19
+ /** @type {any} */ (inputDocument)[utilities.parentSymbol];
20
+ const compiler = options.compiler ?? compile.expression;
13
21
 
14
22
  // Compile the body text as an Origami expression and evaluate it.
15
- const text = String(input);
16
- const fn = compile.expression(text);
23
+ const inputText = utilities.toString(inputDocument);
24
+ let fn;
25
+ try {
26
+ fn = compiler(inputText);
27
+ } catch (/** @type {any} */ error) {
28
+ let location = "";
29
+ if (options.key) {
30
+ location += `${options.key}`;
31
+ }
32
+ if (error.location) {
33
+ const { start } = error.location;
34
+ location += `, line ${start.line}, column ${start.column}`;
35
+ }
36
+ if (location) {
37
+ error.message += ` (${location})`;
38
+ }
39
+ throw error;
40
+ }
17
41
  const parentScope = parent ? Scope.getScope(parent) : builtins;
18
42
  let content = await fn.call(parentScope);
19
43
 
20
- return processUnpackedContent(content, parent);
44
+ return processUnpackedContent(content, parent, inputDocument);
21
45
  }
@@ -74,6 +74,7 @@ export default function treeMap(param1, param2) {
74
74
  inverseKeyMap,
75
75
  keyMap,
76
76
  keyName,
77
+ needsSourceValue,
77
78
  valueName,
78
79
  } = options;
79
80
 
@@ -105,7 +106,7 @@ export default function treeMap(param1, param2) {
105
106
 
106
107
  // Extend the key function to include the value and key in scope.
107
108
  let extendedKeyMap;
108
- let extendedInnerKeyMap;
109
+ let extendedInverseKeyMap;
109
110
  if (extensions) {
110
111
  let { resultExtension, sourceExtension } = parseExtensions(extensions);
111
112
  const keyFns = keyMapsForExtensions({
@@ -113,7 +114,7 @@ export default function treeMap(param1, param2) {
113
114
  sourceExtension,
114
115
  });
115
116
  extendedKeyMap = keyFns.keyMap;
116
- extendedInnerKeyMap = keyFns.inverseKeyMap;
117
+ extendedInverseKeyMap = keyFns.inverseKeyMap;
117
118
  } else if (keyMap) {
118
119
  const resolvedKeyFn = toFunction(keyMap);
119
120
  async function scopedKeyFn(sourceKey, tree) {
@@ -135,7 +136,11 @@ export default function treeMap(param1, param2) {
135
136
  }
136
137
  const keyFns = cachedKeyMaps(scopedKeyFn);
137
138
  extendedKeyMap = keyFns.keyMap;
138
- extendedInnerKeyMap = keyFns.inverseKeyMap;
139
+ extendedInverseKeyMap = keyFns.inverseKeyMap;
140
+ } else {
141
+ // Use sidecar keyMap/inverseKeyMap functions if the valueMap defines them.
142
+ extendedKeyMap = valueMap?.keyMap;
143
+ extendedInverseKeyMap = valueMap?.inverseKeyMap;
139
144
  }
140
145
 
141
146
  const transform = function mapTreelike(treelike) {
@@ -143,8 +148,9 @@ export default function treeMap(param1, param2) {
143
148
  return map({
144
149
  deep,
145
150
  description,
146
- inverseKeyMap: extendedInnerKeyMap,
151
+ inverseKeyMap: extendedInverseKeyMap,
147
152
  keyMap: extendedKeyMap,
153
+ needsSourceValue,
148
154
  valueMap: extendedValueFn,
149
155
  })(tree);
150
156
  };
@@ -0,0 +1,22 @@
1
+ import { isPlainObject } from "@weborigami/async-tree";
2
+ import treeMap from "./@map.js";
3
+
4
+ export default function mapDeep(param1, param2) {
5
+ // Identify whether the valueMap/options are the first parameter
6
+ // or the second.
7
+ let source;
8
+ let options;
9
+ if (param2 === undefined) {
10
+ options = param1;
11
+ } else {
12
+ source = param1;
13
+ if (isPlainObject(param2)) {
14
+ options = param2;
15
+ } else {
16
+ options = { valueMap: param2 };
17
+ }
18
+ }
19
+
20
+ options.deep = true;
21
+ return treeMap(source, options);
22
+ }
@@ -3,6 +3,7 @@ import { marked } from "marked";
3
3
  import { gfmHeadingId as markedGfmHeadingId } from "marked-gfm-heading-id";
4
4
  import { markedHighlight } from "marked-highlight";
5
5
  import { markedSmartypants } from "marked-smartypants";
6
+ import { replaceExtension } from "../common/utilities.js";
6
7
 
7
8
  marked.use(
8
9
  markedGfmHeadingId(),
@@ -41,5 +42,9 @@ export default async function mdHtml(input) {
41
42
  : html;
42
43
  }
43
44
 
45
+ mdHtml.keyMap = (sourceKey) => replaceExtension(sourceKey, ".md", ".html");
46
+ mdHtml.inverseKeyMap = (resultKey) =>
47
+ replaceExtension(resultKey, ".html", ".md");
48
+
44
49
  mdHtml.usage = `@mdHtml <markdown>\tRender the markdown text as HTML`;
45
50
  mdHtml.documentation = "https://weborigami.org/language/@mdHtml.html";
@@ -0,0 +1,18 @@
1
+ import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
2
+
3
+ const fnPromiseMap = new WeakMap();
4
+
5
+ /**
6
+ * Evaluate the given function only once and cache the result.
7
+ *
8
+ * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
9
+ * @this {AsyncTree|null}
10
+ * @param {Function} fn
11
+ */
12
+ export default async function once(fn) {
13
+ assertScopeIsDefined(this);
14
+ if (!fnPromiseMap.has(fn)) {
15
+ fnPromiseMap.set(fn, fn.call(this));
16
+ }
17
+ return fnPromiseMap.get(fn);
18
+ }
@@ -15,7 +15,10 @@ const TypedArray = Object.getPrototypeOf(Uint8Array);
15
15
  * @this {AsyncTree|null}
16
16
  * @param {string} expression
17
17
  */
18
- export default async function ori(expression) {
18
+ export default async function ori(
19
+ expression,
20
+ options = { formatResult: true }
21
+ ) {
19
22
  assertScopeIsDefined(this);
20
23
  // In case expression is a Buffer, cast it to a string.
21
24
  expression = String(expression);
@@ -34,12 +37,15 @@ export default async function ori(expression) {
34
37
  result = await result.call(scope);
35
38
  }
36
39
 
37
- const formatted = await formatResult(result);
38
- return formatted;
40
+ return options.formatResult ? await formatResult(result) : result;
39
41
  }
40
42
 
41
43
  async function formatResult(result) {
42
- if (typeof result === "string" || result instanceof TypedArray) {
44
+ if (
45
+ typeof result === "string" ||
46
+ result instanceof ArrayBuffer ||
47
+ result instanceof TypedArray
48
+ ) {
43
49
  // Use as is
44
50
  return result;
45
51
  }
@@ -0,0 +1,52 @@
1
+ import { Tree, keysFromPath } from "@weborigami/async-tree";
2
+ import { Scope } from "@weborigami/language";
3
+ import project from "./@project.js";
4
+
5
+ /**
6
+ * @this {import("@weborigami/types").AsyncTree|null}
7
+ * @param {string[]} keys
8
+ */
9
+ export default async function packageBuiltin(...keys) {
10
+ let scope = this;
11
+ if (!scope) {
12
+ const projectRoot = await project.call(null);
13
+ scope = Scope.getScope(projectRoot);
14
+ }
15
+
16
+ const packageKeys = [keys.shift()];
17
+ if (packageKeys[0]?.startsWith("@")) {
18
+ // First key is an npm organization, get the next key too.
19
+ packageKeys.push(keys.shift());
20
+ }
21
+
22
+ const packageRoot = await Tree.traverse(
23
+ // @ts-ignore
24
+ scope,
25
+ "node_modules",
26
+ ...packageKeys
27
+ );
28
+ if (!packageRoot) {
29
+ throw new Error(`Can't find node_modules/${packageKeys.join("/")}`);
30
+ }
31
+
32
+ const mainPath = await Tree.traverse(packageRoot, "package.json", "main");
33
+ if (!mainPath) {
34
+ throw new Error(
35
+ `node_modules/${keys.join(
36
+ "/"
37
+ )} doesn't contain a package.json with a "main" entry.`
38
+ );
39
+ }
40
+
41
+ const mainKeys = keysFromPath(mainPath);
42
+ const mainContainerKeys = mainKeys.slice(0, -1);
43
+ const mainFileName = mainKeys[mainKeys.length - 1];
44
+ const mainContainer = await Tree.traverse(packageRoot, ...mainContainerKeys);
45
+ const packageExports = await mainContainer.import(mainFileName);
46
+
47
+ const result =
48
+ keys.length > 0
49
+ ? await Tree.traverse(packageExports, ...keys)
50
+ : packageExports;
51
+ return result;
52
+ }
@@ -1,7 +1,10 @@
1
1
  import { Tree, isPlainObject, isStringLike } from "@weborigami/async-tree";
2
2
  import { extname } from "@weborigami/language";
3
3
  import * as serialize from "../../common/serialize.js";
4
- import { keySymbol } from "../../common/utilities.js";
4
+ import {
5
+ hasNonPrintableCharacters,
6
+ keySymbol,
7
+ } from "../../common/utilities.js";
5
8
  import assertScopeIsDefined from "../../misc/assertScopeIsDefined.js";
6
9
 
7
10
  /**
@@ -36,12 +39,6 @@ ${treeArcs.join("\n")}
36
39
  }`;
37
40
  }
38
41
 
39
- // Return true if the text appears to contain non-printable binary characters.
40
- function probablyBinary(text) {
41
- // https://stackoverflow.com/a/1677660/76472
42
- return /[\x00-\x08\x0E-\x1F]/.test(text);
43
- }
44
-
45
42
  async function statements(tree, nodePath, nodeLabel, options) {
46
43
  let result = [];
47
44
  const createLinks = options.createLinks ?? true;
@@ -110,7 +107,7 @@ async function statements(tree, nodePath, nodeLabel, options) {
110
107
  let i = 0;
111
108
  for (const key of Object.keys(nodes)) {
112
109
  let label = String(nodes[key].label);
113
- if (probablyBinary(label)) {
110
+ if (hasNonPrintableCharacters(label)) {
114
111
  nodes[key].label = "[binary data]";
115
112
  } else if (label) {
116
113
  let clippedStart = false;
@@ -1,10 +1,10 @@
1
1
  import { Tree } from "@weborigami/async-tree";
2
2
  import assertScopeIsDefined from "../../misc/assertScopeIsDefined.js";
3
3
  import builtins from "../@builtins.js";
4
- import unpackOrigamiTemplate from "../@loaders/orit.js";
4
+ import unpackOrigamiExpression from "../@loaders/ori.js";
5
5
  import paths from "./paths.js";
6
6
 
7
- const templateText = `<?xml version="1.0" encoding="UTF-8"?>
7
+ const templateText = `=\`<?xml version="1.0" encoding="UTF-8"?>
8
8
  <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
9
9
  {{ @map(=\`
10
10
  <url>
@@ -12,6 +12,7 @@ const templateText = `<?xml version="1.0" encoding="UTF-8"?>
12
12
  </url>
13
13
  \`)(_) }}
14
14
  </urlset>
15
+ \`
15
16
  `;
16
17
 
17
18
  /**
@@ -50,7 +51,7 @@ export default async function sitemap(treelike, baseHref = "") {
50
51
  .filter((path) => path.endsWith(".html"))
51
52
  .map((path) => (path.endsWith("index.html") ? path.slice(0, -10) : path));
52
53
 
53
- const templateFn = await unpackOrigamiTemplate(templateText);
54
+ const templateFn = await unpackOrigamiExpression(templateText);
54
55
  const templateResult = await templateFn.call(builtins, htmlPaths);
55
56
  return String(templateResult);
56
57
  }
package/src/cli/cli.js CHANGED
@@ -9,6 +9,8 @@ import project from "../builtins/@project.js";
9
9
  import { keySymbol } from "../common/utilities.js";
10
10
  import showUsage from "./showUsage.js";
11
11
 
12
+ const TypedArray = Object.getPrototypeOf(Uint8Array);
13
+
12
14
  async function main(...args) {
13
15
  const expression = args.join(" ");
14
16
 
@@ -42,7 +44,12 @@ async function main(...args) {
42
44
  const scope = Scope.getScope(tree);
43
45
  const result = await ori.call(scope, expression);
44
46
  if (result !== undefined) {
45
- const output = result instanceof Buffer ? result : String(result);
47
+ const output =
48
+ result instanceof ArrayBuffer
49
+ ? new Uint8Array(result)
50
+ : typeof result === "string" || result instanceof TypedArray
51
+ ? result
52
+ : String(result);
46
53
  await stdout.write(output);
47
54
 
48
55
  // If stdout points to the console, and the result didn't end in a newline,
@@ -1,4 +1,4 @@
1
- import { Tree } from "@weborigami/async-tree";
1
+ import { DeepObjectTree, Tree, isPlainObject } from "@weborigami/async-tree";
2
2
 
3
3
  /**
4
4
  * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
@@ -7,7 +7,9 @@ import { Tree } from "@weborigami/async-tree";
7
7
  export default class FilterTree {
8
8
  constructor(tree, filter) {
9
9
  this.tree = Tree.from(tree);
10
- this.filter = Tree.from(filter);
10
+ this.filter = isPlainObject(filter)
11
+ ? new DeepObjectTree(filter)
12
+ : Tree.from(filter);
11
13
  }
12
14
 
13
15
  async get(key) {
@@ -1,4 +1,10 @@
1
- import { ObjectTree, Tree, merge } from "@weborigami/async-tree";
1
+ import {
2
+ DeepObjectTree,
3
+ ObjectTree,
4
+ Tree,
5
+ isPlainObject,
6
+ merge,
7
+ } from "@weborigami/async-tree";
2
8
 
3
9
  const globstar = "**";
4
10
 
@@ -8,7 +14,9 @@ const globstar = "**";
8
14
  */
9
15
  export default class GlobTree {
10
16
  constructor(globs) {
11
- this.globs = Tree.from(globs);
17
+ this.globs = isPlainObject(globs)
18
+ ? new DeepObjectTree(globs)
19
+ : Tree.from(globs);
12
20
  }
13
21
 
14
22
  async get(key) {
@@ -10,17 +10,19 @@ import builtins from "../builtins/@builtins.js";
10
10
  *
11
11
  * @param {any} content
12
12
  * @param {AsyncTree|null} parent
13
- * @param {any} [attachedData]
13
+ * @param {any} [inputDocument]
14
14
  * @returns
15
15
  */
16
- export default function processUnpackedContent(content, parent, attachedData) {
16
+ export default function processUnpackedContent(content, parent, inputDocument) {
17
17
  if (typeof content === "function") {
18
18
  // Wrap the function such to add ambients to the scope.
19
19
  const fn = content;
20
20
 
21
21
  // Use the parent's scope, adding any attached data.
22
22
  const parentScope = parent ? Scope.getScope(parent) : builtins;
23
- const extendedScope = new Scope(attachedData, parentScope);
23
+ const extendedScope = Tree.isTreelike(inputDocument)
24
+ ? new Scope(inputDocument, parentScope)
25
+ : parentScope;
24
26
 
25
27
  /** @this {AsyncTree|null} */
26
28
  async function extendScope(input, ...rest) {
@@ -29,7 +31,10 @@ export default function processUnpackedContent(content, parent, attachedData) {
29
31
 
30
32
  extendScope.code = fn.code;
31
33
  return extendScope;
32
- } else if (Tree.isAsyncTree(content)) {
34
+ } else if (
35
+ Tree.isAsyncTree(content) &&
36
+ !(/** @type {any} */ (content).scope)
37
+ ) {
33
38
  const result = Object.create(content);
34
39
  result.parent = parent;
35
40
  return result;
@@ -1,7 +1,9 @@
1
1
 
2
2
  export const keySymbol: unique symbol;
3
3
  export const parentSymbol: unique symbol;
4
+ export function hasNonPrintableCharacters(text: string): boolean;
4
5
  export function isTransformApplied(Transform: Function, object: any): boolean;
6
+ export function replaceExtension(key: string, sourceExtension: string, resultExtension: string): string;
5
7
  export function toFunction(object: any): Function;
6
8
  export function toString(object: any): string|null;
7
9
  export function transformObject(Transform: Function, object: any): any;