@weborigami/language 0.0.44 → 0.0.45

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@weborigami/language",
3
- "version": "0.0.44",
3
+ "version": "0.0.45",
4
4
  "description": "Web Origami expression language compiler and runtime",
5
5
  "type": "module",
6
6
  "main": "./main.js",
@@ -10,8 +10,8 @@
10
10
  "typescript": "5.3.3"
11
11
  },
12
12
  "dependencies": {
13
- "@weborigami/async-tree": "0.0.44",
14
- "@weborigami/types": "0.0.44",
13
+ "@weborigami/async-tree": "0.0.45",
14
+ "@weborigami/types": "0.0.45",
15
15
  "peggy": "3.0.2",
16
16
  "watcher": "2.3.0"
17
17
  },
@@ -1,7 +1,6 @@
1
- import { Tree, isStringLike } from "@weborigami/async-tree";
1
+ import { isStringLike } from "@weborigami/async-tree";
2
2
  import Scope from "./Scope.js";
3
- import extname from "./extname.js";
4
- import * as symbols from "./symbols.js";
3
+ import attachFileLoader from "./attachFileLoader.js";
5
4
 
6
5
  /**
7
6
  * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
@@ -15,33 +14,11 @@ export default function FileLoadersTransform(Base) {
15
14
  async get(key) {
16
15
  let value = await super.get(key);
17
16
 
18
- // If the key is string-like and has an extension, look for a loader that
19
- // handles that extension.
17
+ // If the key is string-like and has an extension, attach a loader (if one
18
+ // exists) that handles that extension.
20
19
  if (value && isStringLike(key)) {
21
- const extension = extname(String(key)).toLowerCase().slice(1);
22
- if (extension) {
23
- /** @type {any} */
24
- const scope = Scope.getScope(this);
25
- const loader = await Tree.traverse(scope, "@loaders", extension);
26
- if (loader) {
27
- const input = value;
28
- // If the input is a plain string, convert it to a String so we can
29
- // attach data to it.
30
- if (typeof input === "string") {
31
- value = new String(input);
32
- }
33
- const parent = this;
34
- value[symbols.parent] = parent;
35
-
36
- // Wrap the loader with a function that will only be called once per
37
- // value.
38
- let loaded;
39
- value.unpack = async () => {
40
- loaded ??= await loader(input, { key, parent });
41
- return loaded;
42
- };
43
- }
44
- }
20
+ const scope = Scope.getScope(this);
21
+ value = await attachFileLoader(scope, String(key), value, this);
45
22
  }
46
23
 
47
24
  return value;
@@ -0,0 +1,31 @@
1
+ import { Tree } from "@weborigami/async-tree";
2
+ import extname from "./extname.js";
3
+ import * as symbols from "./symbols.js";
4
+
5
+ export default async function attachFileLoader(scope, key, value, parent) {
6
+ const extension = extname(key);
7
+ let result = value;
8
+ if (extension) {
9
+ const loaderName = extension.slice(1);
10
+ const loader = await Tree.traverse(scope, "@loaders", loaderName);
11
+ if (loader) {
12
+ const input = value;
13
+
14
+ // If the result is a plain string, box it as a String so we can attach
15
+ // data to it.
16
+ if (typeof result === "string") {
17
+ result = new String(result);
18
+ }
19
+ result[symbols.parent] = parent;
20
+
21
+ // Wrap the loader with a function that will only be called once per
22
+ // value.
23
+ let loaded;
24
+ result.unpack = async () => {
25
+ loaded ??= await loader(input, { key, parent });
26
+ return loaded;
27
+ };
28
+ }
29
+ }
30
+ return result;
31
+ }
@@ -7,6 +7,7 @@ import { SiteTree, Tree } from "@weborigami/async-tree";
7
7
  import FileLoadersTransform from "./FileLoadersTransform.js";
8
8
  import OrigamiFiles from "./OrigamiFiles.js";
9
9
  import Scope from "./Scope.js";
10
+ import attachFileLoader from "./attachFileLoader.js";
10
11
  import concatTreeValues from "./concatTreeValues.js";
11
12
  import { OrigamiTree, evaluate, expressionFunction } from "./internal.js";
12
13
 
@@ -60,11 +61,24 @@ function constructHref(protocol, host, ...keys) {
60
61
  /**
61
62
  * Fetch the resource at the given href.
62
63
  *
64
+ * @this {AsyncTree|null}
63
65
  * @param {string} href
64
66
  */
65
67
  async function fetchResponse(href) {
66
68
  const response = await fetch(href);
67
- return response.ok ? await response.arrayBuffer() : undefined;
69
+ if (!response.ok) {
70
+ return undefined;
71
+ }
72
+ let buffer = await response.arrayBuffer();
73
+
74
+ // Attach any loader defined for the file type.
75
+ const url = new URL(href);
76
+ const filename = url.pathname.split("/").pop();
77
+ if (filename) {
78
+ buffer = await attachFileLoader(this, filename, buffer, null);
79
+ }
80
+
81
+ return buffer;
68
82
  }
69
83
 
70
84
  /**
@@ -93,7 +107,7 @@ export async function filesRoot() {
93
107
  */
94
108
  export async function http(host, ...keys) {
95
109
  const href = constructHref("http:", host, ...keys);
96
- return fetchResponse(href);
110
+ return fetchResponse.call(this, href);
97
111
  }
98
112
  http.toString = () => "«ops.http»";
99
113
 
@@ -106,7 +120,7 @@ http.toString = () => "«ops.http»";
106
120
  */
107
121
  export function https(host, ...keys) {
108
122
  const href = constructHref("https:", host, ...keys);
109
- return fetchResponse(href);
123
+ return fetchResponse.call(this, href);
110
124
  }
111
125
  https.toString = () => "«ops.https»";
112
126