@weborigami/language 0.0.71-beta.1 → 0.0.72
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 +3 -3
- package/src/compiler/parserHelpers.js +9 -2
- package/src/runtime/extensions.js +2 -2
- package/src/runtime/ops.js +13 -18
- package/test/compiler/parse.test.js +12 -0
- package/test/runtime/expressionObject.test.js +1 -1
- package/test/runtime/extensions.test.js +1 -1
- package/test/runtime/ops.test.js +0 -9
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weborigami/language",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.72",
|
|
4
4
|
"description": "Web Origami expression language compiler and runtime",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./main.js",
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
"typescript": "5.6.2"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@weborigami/async-tree": "0.0.
|
|
15
|
-
"@weborigami/types": "0.0.
|
|
14
|
+
"@weborigami/async-tree": "0.0.72",
|
|
15
|
+
"@weborigami/types": "0.0.72",
|
|
16
16
|
"watcher": "2.3.1"
|
|
17
17
|
},
|
|
18
18
|
"scripts": {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { trailingSlash } from "@weborigami/async-tree";
|
|
1
2
|
import * as ops from "../runtime/ops.js";
|
|
2
3
|
|
|
3
4
|
// Parser helpers
|
|
@@ -21,9 +22,15 @@ function avoidRecursivePropertyCalls(code, key) {
|
|
|
21
22
|
return code;
|
|
22
23
|
}
|
|
23
24
|
let modified;
|
|
24
|
-
if (
|
|
25
|
+
if (
|
|
26
|
+
code[0] === ops.scope &&
|
|
27
|
+
trailingSlash.remove(code[1]) === trailingSlash.remove(key)
|
|
28
|
+
) {
|
|
25
29
|
// Rewrite to avoid recursion
|
|
26
|
-
modified = [ops.inherited,
|
|
30
|
+
modified = [ops.inherited, code[1]];
|
|
31
|
+
} else if (code[0] === ops.lambda && code[1].includes(key)) {
|
|
32
|
+
// Lambda that defines the key; don't rewrite
|
|
33
|
+
return code;
|
|
27
34
|
} else {
|
|
28
35
|
// Process any nested code
|
|
29
36
|
modified = code.map((value) => avoidRecursivePropertyCalls(value, key));
|
|
@@ -53,7 +53,7 @@ export async function getExtensionHandler(parent, extension) {
|
|
|
53
53
|
handlersForContainer.set(parent, handlers);
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
const handlerName = `${extension.slice(1)}
|
|
56
|
+
const handlerName = `${extension.slice(1)}.handler`;
|
|
57
57
|
const parentScope = scope(parent);
|
|
58
58
|
|
|
59
59
|
/** @type {Promise<ExtensionHandler>} */
|
|
@@ -95,7 +95,7 @@ export async function handleExtension(parent, value, key) {
|
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
// Special case: `.ori.<ext>` extensions are Origami documents.
|
|
98
|
-
const extension = key.match(/\.ori\.\S+$/) ? ".
|
|
98
|
+
const extension = key.match(/\.ori\.\S+$/) ? ".oridocument" : extname(key);
|
|
99
99
|
if (extension) {
|
|
100
100
|
const handler = await getExtensionHandler(parent, extension);
|
|
101
101
|
if (handler) {
|
package/src/runtime/ops.js
CHANGED
|
@@ -62,10 +62,6 @@ export async function cache(key, cache) {
|
|
|
62
62
|
return value;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
// The assign op is a placeholder for an assignment declaration.
|
|
66
|
-
// It is only used during parsing -- it shouldn't be executed.
|
|
67
|
-
export const assign = "«ops.assign»";
|
|
68
|
-
|
|
69
65
|
/**
|
|
70
66
|
* Concatenate the given arguments.
|
|
71
67
|
*
|
|
@@ -142,6 +138,18 @@ async function constructSiteTree(protocol, treeClass, parent, host, ...keys) {
|
|
|
142
138
|
return lastKey ? result.get(lastKey) : result;
|
|
143
139
|
}
|
|
144
140
|
|
|
141
|
+
/**
|
|
142
|
+
* A site tree with JSON Keys via HTTPS.
|
|
143
|
+
*
|
|
144
|
+
* @this {AsyncTree|null}
|
|
145
|
+
* @param {string} host
|
|
146
|
+
* @param {...string} keys
|
|
147
|
+
*/
|
|
148
|
+
export function explorableSite(host, ...keys) {
|
|
149
|
+
return constructSiteTree("https:", ExplorableSiteTree, this, host, ...keys);
|
|
150
|
+
}
|
|
151
|
+
addOpLabel(explorableSite, "«ops.explorableSite»");
|
|
152
|
+
|
|
145
153
|
/**
|
|
146
154
|
* Fetch the resource at the given href.
|
|
147
155
|
*
|
|
@@ -171,18 +179,6 @@ async function fetchResponse(href) {
|
|
|
171
179
|
*/
|
|
172
180
|
export const getter = new String("«ops.getter»");
|
|
173
181
|
|
|
174
|
-
/**
|
|
175
|
-
* A site tree with JSON Keys via HTTPS.
|
|
176
|
-
*
|
|
177
|
-
* @this {AsyncTree|null}
|
|
178
|
-
* @param {string} host
|
|
179
|
-
* @param {...string} keys
|
|
180
|
-
*/
|
|
181
|
-
export function explorableSite(host, ...keys) {
|
|
182
|
-
return constructSiteTree("https:", ExplorableSiteTree, this, host, ...keys);
|
|
183
|
-
}
|
|
184
|
-
addOpLabel(explorableSite, "«ops.explorableSite»");
|
|
185
|
-
|
|
186
182
|
/**
|
|
187
183
|
* Construct a files tree for the filesystem root.
|
|
188
184
|
*
|
|
@@ -257,12 +253,11 @@ export function lambda(parameters, code) {
|
|
|
257
253
|
|
|
258
254
|
/** @this {AsyncTree|null} */
|
|
259
255
|
async function invoke(...args) {
|
|
260
|
-
// Add arguments
|
|
256
|
+
// Add arguments to scope.
|
|
261
257
|
const ambients = {};
|
|
262
258
|
for (const parameter of parameters) {
|
|
263
259
|
ambients[parameter] = args.shift();
|
|
264
260
|
}
|
|
265
|
-
ambients["@recurse"] = invoke;
|
|
266
261
|
const ambientTree = new ObjectTree(ambients);
|
|
267
262
|
ambientTree.parent = this;
|
|
268
263
|
|
|
@@ -406,6 +406,18 @@ describe("Origami parser", () => {
|
|
|
406
406
|
assertParse("objectEntry", "foo", ["foo", [ops.inherited, "foo"]]);
|
|
407
407
|
assertParse("objectEntry", "x: y", ["x", [ops.scope, "y"]]);
|
|
408
408
|
assertParse("objectEntry", "a: a", ["a", [ops.inherited, "a"]]);
|
|
409
|
+
assertParse("objectEntry", "a: (a) => a", [
|
|
410
|
+
"a",
|
|
411
|
+
[ops.lambda, ["a"], [ops.scope, "a"]],
|
|
412
|
+
]);
|
|
413
|
+
assertParse("objectEntry", "posts/: @map(posts, post.ori)", [
|
|
414
|
+
"posts/",
|
|
415
|
+
[
|
|
416
|
+
[ops.scope, "@map"],
|
|
417
|
+
[ops.inherited, "posts"],
|
|
418
|
+
[ops.scope, "post.ori"],
|
|
419
|
+
],
|
|
420
|
+
]);
|
|
409
421
|
});
|
|
410
422
|
|
|
411
423
|
test("objectGetter", () => {
|
|
@@ -54,7 +54,7 @@ describe("expressionObject", () => {
|
|
|
54
54
|
test("returned object values can be unpacked", async () => {
|
|
55
55
|
const entries = [["data.json", `{ "a": 1 }`]];
|
|
56
56
|
const parent = new ObjectTree({
|
|
57
|
-
|
|
57
|
+
"json.handler": {
|
|
58
58
|
unpack: JSON.parse,
|
|
59
59
|
},
|
|
60
60
|
});
|
package/test/runtime/ops.test.js
CHANGED
|
@@ -79,15 +79,6 @@ describe("ops", () => {
|
|
|
79
79
|
assert.equal(result, "yx");
|
|
80
80
|
});
|
|
81
81
|
|
|
82
|
-
test("ops.lambda function can reference itself with @recurse", async () => {
|
|
83
|
-
const code = createCode([ops.lambda, ["_"], [ops.scope, "@recurse"]]);
|
|
84
|
-
const fn = await evaluate.call(null, code);
|
|
85
|
-
const result = await fn();
|
|
86
|
-
// We're expecting the function to return itself, but testing recursion is
|
|
87
|
-
// messy. We just confirm that the result has the same code as the original.
|
|
88
|
-
assert.equal(result.code, fn.code);
|
|
89
|
-
});
|
|
90
|
-
|
|
91
82
|
test("ops.object instantiates an object", async () => {
|
|
92
83
|
const scope = new ObjectTree({
|
|
93
84
|
upper: (s) => s.toUpperCase(),
|