@weborigami/language 0.5.8 → 0.6.1
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/index.ts +3 -4
- package/main.js +2 -4
- package/package.json +4 -5
- package/src/compiler/optimize.js +3 -1
- package/src/compiler/parserHelpers.js +1 -7
- package/src/handlers/csv_handler.js +13 -8
- package/src/handlers/getSource.js +36 -0
- package/src/handlers/ori_handler.js +5 -20
- package/src/handlers/oridocument_handler.js +5 -28
- package/src/handlers/tsv_handler.js +10 -1
- package/src/handlers/yaml_handler.js +75 -3
- package/src/project/jsGlobals.js +5 -1
- package/src/project/projectConfig.js +4 -4
- package/src/project/projectRoot.js +8 -9
- package/src/protocols/constructSiteTree.js +4 -4
- package/src/protocols/explore.js +2 -3
- package/src/protocols/fetchAndHandleExtension.js +0 -1
- package/src/protocols/files.js +2 -3
- package/src/protocols/http.js +0 -1
- package/src/protocols/https.js +0 -1
- package/src/protocols/httpstree.js +2 -3
- package/src/protocols/httptree.js +2 -3
- package/src/runtime/HandleExtensionsTransform.js +32 -8
- package/src/runtime/ImportModulesMixin.js +2 -2
- package/src/runtime/{OrigamiFiles.js → OrigamiFileMap.d.ts} +3 -3
- package/src/runtime/{OrigamiFiles.d.ts → OrigamiFileMap.js} +3 -5
- package/src/runtime/errors.js +9 -2
- package/src/runtime/evaluate.js +1 -1
- package/src/runtime/expressionFunction.js +3 -3
- package/src/runtime/expressionObject.js +19 -8
- package/src/runtime/handleExtension.js +2 -11
- package/src/runtime/mergeTrees.js +4 -7
- package/src/runtime/ops.js +13 -13
- package/test/cases/logicalAndExpression.yaml +7 -8
- package/test/compiler/compile.test.js +1 -1
- package/test/compiler/optimize.test.js +2 -2
- package/test/compiler/parse.test.js +13 -19
- package/test/generated/logicalAndExpression.test.js +4 -0
- package/test/handlers/csv_handler.test.js +5 -5
- package/test/handlers/js_handler.test.js +2 -2
- package/test/handlers/ori_handler.test.js +8 -8
- package/test/handlers/oridocument_handler.test.js +3 -3
- package/test/handlers/tsv_handler.test.js +5 -5
- package/test/handlers/wasm_handler.test.js +2 -2
- package/test/handlers/yaml_handler.test.js +31 -1
- package/test/runtime/OrigamiFileMap.test.js +40 -0
- package/test/runtime/evaluate.test.js +3 -3
- package/test/runtime/expressionObject.test.js +14 -6
- package/test/runtime/handleExtension.test.js +2 -9
- package/test/runtime/mergeTrees.test.js +2 -2
- package/test/runtime/ops.test.js +18 -12
- package/src/runtime/InvokeFunctionsTransform.d.ts +0 -5
- package/src/runtime/InvokeFunctionsTransform.js +0 -25
- package/src/runtime/functionResultsMap.js +0 -17
- package/test/runtime/OrigamiFiles.test.js +0 -35
- package/test/runtime/fixtures/subgraph = this.js +0 -5
- package/test/runtime/functionResultsMap.test.js +0 -20
package/index.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { UnpackFunction } from "@weborigami/async-tree";
|
|
2
|
-
import { AsyncTree } from "@weborigami/types";
|
|
1
|
+
import { SyncOrAsyncMap, UnpackFunction } from "@weborigami/async-tree";
|
|
3
2
|
|
|
4
3
|
export * from "./main.js";
|
|
5
4
|
|
|
@@ -59,9 +58,9 @@ export type Position = {
|
|
|
59
58
|
|
|
60
59
|
export type RuntimeState = {
|
|
61
60
|
/** The container (e.g., file system) that holds the code */
|
|
62
|
-
container?:
|
|
61
|
+
container?: SyncOrAsyncMap | null;
|
|
63
62
|
/** The object to which this code is attached */
|
|
64
|
-
object?:
|
|
63
|
+
object?: SyncOrAsyncMap | null;
|
|
65
64
|
/** The current stack of function parameter assignments */
|
|
66
65
|
stack?: Array<Record<string, any>>;
|
|
67
66
|
}
|
package/main.js
CHANGED
|
@@ -8,18 +8,16 @@ export { default as jsGlobals } from "./src/project/jsGlobals.js";
|
|
|
8
8
|
export { default as projectGlobals } from "./src/project/projectGlobals.js";
|
|
9
9
|
export { default as projectRoot } from "./src/project/projectRoot.js";
|
|
10
10
|
export * as Protocols from "./src/protocols/protocols.js";
|
|
11
|
-
export { formatError } from "./src/runtime/errors.js";
|
|
11
|
+
export { formatError, highlightError } from "./src/runtime/errors.js";
|
|
12
12
|
export { default as evaluate } from "./src/runtime/evaluate.js";
|
|
13
13
|
export { default as EventTargetMixin } from "./src/runtime/EventTargetMixin.js";
|
|
14
14
|
export * as expressionFunction from "./src/runtime/expressionFunction.js";
|
|
15
|
-
export { default as functionResultsMap } from "./src/runtime/functionResultsMap.js";
|
|
16
15
|
export * from "./src/runtime/handleExtension.js";
|
|
17
16
|
export { default as handleExtension } from "./src/runtime/handleExtension.js";
|
|
18
17
|
export { default as HandleExtensionsTransform } from "./src/runtime/HandleExtensionsTransform.js";
|
|
19
18
|
export { default as ImportModulesMixin } from "./src/runtime/ImportModulesMixin.js";
|
|
20
|
-
export { default as InvokeFunctionsTransform } from "./src/runtime/InvokeFunctionsTransform.js";
|
|
21
19
|
export * as moduleCache from "./src/runtime/moduleCache.js";
|
|
22
|
-
export { default as
|
|
20
|
+
export { default as OrigamiFileMap } from "./src/runtime/OrigamiFileMap.js";
|
|
23
21
|
export * as symbols from "./src/runtime/symbols.js";
|
|
24
22
|
export { default as TreeEvent } from "./src/runtime/TreeEvent.js";
|
|
25
23
|
export { default as WatchFilesMixin } from "./src/runtime/WatchFilesMixin.js";
|
package/package.json
CHANGED
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weborigami/language",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "Web Origami expression language compiler and runtime",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./main.js",
|
|
7
7
|
"types": "./index.ts",
|
|
8
8
|
"devDependencies": {
|
|
9
|
-
"@types/node": "24.
|
|
9
|
+
"@types/node": "24.10.1",
|
|
10
10
|
"peggy": "5.0.6",
|
|
11
|
-
"typescript": "5.9.
|
|
11
|
+
"typescript": "5.9.3"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@weborigami/async-tree": "0.
|
|
15
|
-
"@weborigami/types": "0.5.8",
|
|
14
|
+
"@weborigami/async-tree": "0.6.1",
|
|
16
15
|
"exif-parser": "0.1.12",
|
|
17
16
|
"watcher": "2.3.1",
|
|
18
17
|
"yaml": "2.8.1"
|
package/src/compiler/optimize.js
CHANGED
|
@@ -2,7 +2,7 @@ import { pathFromKeys, trailingSlash } from "@weborigami/async-tree";
|
|
|
2
2
|
import jsGlobals from "../project/jsGlobals.js";
|
|
3
3
|
import { entryKey } from "../runtime/expressionObject.js";
|
|
4
4
|
import { ops } from "../runtime/internal.js";
|
|
5
|
-
import { annotate, markers } from "./parserHelpers.js";
|
|
5
|
+
import { annotate, markers, spanLocations } from "./parserHelpers.js";
|
|
6
6
|
|
|
7
7
|
export const REFERENCE_PARAM = 1;
|
|
8
8
|
export const REFERENCE_INHERITED = 2;
|
|
@@ -334,6 +334,8 @@ function resolvePath(code, globals, parent, locals, cache) {
|
|
|
334
334
|
result[0][0] === ops.inherited);
|
|
335
335
|
if (extendResult) {
|
|
336
336
|
result.push(...tail);
|
|
337
|
+
result.location = spanLocations(args);
|
|
338
|
+
result.source = code.source;
|
|
337
339
|
} else {
|
|
338
340
|
result = annotate([result, ...tail], code.location);
|
|
339
341
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { trailingSlash } from "@weborigami/async-tree";
|
|
2
1
|
import * as YAMLModule from "yaml";
|
|
3
2
|
import codeFragment from "../runtime/codeFragment.js";
|
|
4
3
|
import * as ops from "../runtime/ops.js";
|
|
@@ -380,11 +379,6 @@ export function makePath(keys) {
|
|
|
380
379
|
const location = spanLocations(code);
|
|
381
380
|
code = annotate(code, location);
|
|
382
381
|
|
|
383
|
-
// Last key has trailing slash implies unpack operation
|
|
384
|
-
if (trailingSlash.has(args.at(-1)[1])) {
|
|
385
|
-
code = annotate([ops.unpack, code], location);
|
|
386
|
-
}
|
|
387
|
-
|
|
388
382
|
return code;
|
|
389
383
|
}
|
|
390
384
|
|
|
@@ -518,7 +512,7 @@ export function makeYamlObject(text, location) {
|
|
|
518
512
|
|
|
519
513
|
// Create a locations that spans those in the array. This assumes the locations
|
|
520
514
|
// are in order and non-overlapping.
|
|
521
|
-
function spanLocations(code) {
|
|
515
|
+
export function spanLocations(code) {
|
|
522
516
|
const first = code.find((item) => item.location).location;
|
|
523
517
|
const last = code[code.findLastIndex((item) => item.location)].location;
|
|
524
518
|
return {
|
|
@@ -34,11 +34,21 @@ function csvParse(text) {
|
|
|
34
34
|
const rows = [];
|
|
35
35
|
let currentRow = [];
|
|
36
36
|
let currentField = "";
|
|
37
|
+
let wasQuoted = false; // True if the current field was quoted
|
|
37
38
|
|
|
38
39
|
const pushField = () => {
|
|
39
|
-
|
|
40
|
-
|
|
40
|
+
/** @type {string|number} */
|
|
41
|
+
let parsedField = currentField;
|
|
42
|
+
if (!wasQuoted) {
|
|
43
|
+
// Field wasn't quoted: if it's a valid number, convert it
|
|
44
|
+
const n = Number(currentField);
|
|
45
|
+
if (!isNaN(n)) {
|
|
46
|
+
parsedField = n;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
currentRow.push(parsedField);
|
|
41
50
|
currentField = "";
|
|
51
|
+
wasQuoted = false; // Reset the flag for the next field
|
|
42
52
|
};
|
|
43
53
|
|
|
44
54
|
const pushRow = () => {
|
|
@@ -54,29 +64,24 @@ function csvParse(text) {
|
|
|
54
64
|
const char = text[i];
|
|
55
65
|
|
|
56
66
|
if (inQuotes) {
|
|
57
|
-
// In a quoted field
|
|
58
67
|
if (char === '"') {
|
|
59
|
-
// Check if next character is also a quote
|
|
60
68
|
if (i + 1 < text.length && text[i + 1] === '"') {
|
|
61
|
-
// Append a literal double quote and skip the next character
|
|
62
69
|
currentField += '"';
|
|
63
70
|
i += 2;
|
|
64
71
|
continue;
|
|
65
72
|
} else {
|
|
66
|
-
// End of the quoted field
|
|
67
73
|
inQuotes = false;
|
|
68
74
|
i++;
|
|
69
75
|
continue;
|
|
70
76
|
}
|
|
71
77
|
} else {
|
|
72
|
-
// All other characters within quotes are taken literally.
|
|
73
78
|
currentField += char;
|
|
74
79
|
i++;
|
|
75
80
|
continue;
|
|
76
81
|
}
|
|
77
82
|
} else if (char === '"') {
|
|
78
|
-
// Start of a quoted field
|
|
79
83
|
inQuotes = true;
|
|
84
|
+
wasQuoted = true; // Mark the field as quoted
|
|
80
85
|
i++;
|
|
81
86
|
continue;
|
|
82
87
|
} else if (char === ",") {
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { getParent, toString } from "@weborigami/async-tree";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Given packed source text and a handler's options, return a source
|
|
5
|
+
* object that can be passed to the compiler.
|
|
6
|
+
*/
|
|
7
|
+
export default function getSource(packed, options = {}) {
|
|
8
|
+
const parent = getParent(packed, options);
|
|
9
|
+
|
|
10
|
+
// Try to determine a URL for error messages
|
|
11
|
+
const sourceName = options.key;
|
|
12
|
+
let url;
|
|
13
|
+
if (sourceName) {
|
|
14
|
+
if (/** @type {any} */ (parent)?.url) {
|
|
15
|
+
let parentHref = /** @type {any} */ (parent).url.href;
|
|
16
|
+
if (!parentHref.endsWith("/")) {
|
|
17
|
+
parentHref += "/";
|
|
18
|
+
}
|
|
19
|
+
url = new URL(sourceName, parentHref);
|
|
20
|
+
} else if (/** @type {any} */ (parent)?.path) {
|
|
21
|
+
let parentHref = new URL(/** @type {any} */ (parent).path, "file:///")
|
|
22
|
+
.href;
|
|
23
|
+
if (!parentHref.endsWith("/")) {
|
|
24
|
+
parentHref += "/";
|
|
25
|
+
}
|
|
26
|
+
url = new URL(sourceName, parentHref);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const source = {
|
|
31
|
+
text: toString(packed),
|
|
32
|
+
name: options.key,
|
|
33
|
+
url,
|
|
34
|
+
};
|
|
35
|
+
return source;
|
|
36
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { getParent, setParent
|
|
1
|
+
import { getParent, setParent } from "@weborigami/async-tree";
|
|
2
2
|
import * as compile from "../compiler/compile.js";
|
|
3
3
|
import projectGlobals from "../project/projectGlobals.js";
|
|
4
|
+
import getSource from "./getSource.js";
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* An Origami expression file
|
|
@@ -13,34 +14,18 @@ export default {
|
|
|
13
14
|
/** @type {import("@weborigami/async-tree").UnpackFunction} */
|
|
14
15
|
async unpack(packed, options = {}) {
|
|
15
16
|
const parent = getParent(packed, options);
|
|
17
|
+
const source = getSource(packed, options);
|
|
16
18
|
|
|
17
|
-
//
|
|
18
|
-
const sourceName = options.key;
|
|
19
|
-
let url;
|
|
20
|
-
if (sourceName && /** @type {any} */ (parent)?.url) {
|
|
21
|
-
let parentHref = /** @type {any} */ (parent).url.href;
|
|
22
|
-
if (!parentHref.endsWith("/")) {
|
|
23
|
-
parentHref += "/";
|
|
24
|
-
}
|
|
25
|
-
url = new URL(sourceName, parentHref);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const source = {
|
|
29
|
-
text: toString(packed),
|
|
30
|
-
name: options.key,
|
|
31
|
-
url,
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
// Compile the source code as an Origami program and evaluate it.
|
|
19
|
+
// Compile the source code as an Origami program
|
|
35
20
|
const compiler = options.compiler ?? compile.program;
|
|
36
21
|
const globals = options.globals ?? (await projectGlobals());
|
|
37
|
-
|
|
38
22
|
const fn = compiler(source, {
|
|
39
23
|
globals,
|
|
40
24
|
mode: "program",
|
|
41
25
|
parent,
|
|
42
26
|
});
|
|
43
27
|
|
|
28
|
+
// Evaluate the program
|
|
44
29
|
const result = await fn();
|
|
45
30
|
|
|
46
31
|
if (parent) {
|
|
@@ -1,11 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
extension,
|
|
3
|
-
getParent,
|
|
4
|
-
toString,
|
|
5
|
-
trailingSlash,
|
|
6
|
-
} from "@weborigami/async-tree";
|
|
1
|
+
import { extension, getParent, trailingSlash } from "@weborigami/async-tree";
|
|
7
2
|
import * as compile from "../compiler/compile.js";
|
|
8
3
|
import projectGlobals from "../project/projectGlobals.js";
|
|
4
|
+
import getSource from "./getSource.js";
|
|
9
5
|
|
|
10
6
|
/**
|
|
11
7
|
* An Origami template document: a plain text file that contains Origami
|
|
@@ -17,30 +13,10 @@ export default {
|
|
|
17
13
|
/** @type {import("@weborigami/async-tree").UnpackFunction} */
|
|
18
14
|
async unpack(packed, options = {}) {
|
|
19
15
|
const parent = getParent(packed, options);
|
|
16
|
+
const source = getSource(packed, options);
|
|
20
17
|
|
|
21
|
-
//
|
|
22
|
-
const text = toString(packed);
|
|
23
|
-
|
|
24
|
-
// See if we can construct a URL to use in error messages
|
|
25
|
-
const key = options.key;
|
|
26
|
-
let url;
|
|
27
|
-
if (key && /** @type {any} */ (parent)?.url) {
|
|
28
|
-
let parentHref = /** @type {any} */ (parent).url.href;
|
|
29
|
-
if (!parentHref.endsWith("/")) {
|
|
30
|
-
parentHref += "/";
|
|
31
|
-
}
|
|
32
|
-
url = new URL(key, parentHref);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Compile the text as an Origami template document
|
|
36
|
-
const source = {
|
|
37
|
-
name: key,
|
|
38
|
-
text,
|
|
39
|
-
url,
|
|
40
|
-
};
|
|
41
|
-
|
|
18
|
+
// Compile the source code as an Origami template document
|
|
42
19
|
const globals = options.globals ?? (await projectGlobals());
|
|
43
|
-
|
|
44
20
|
const defineFn = compile.templateDocument(source, {
|
|
45
21
|
front: options.front,
|
|
46
22
|
globals,
|
|
@@ -51,6 +27,7 @@ export default {
|
|
|
51
27
|
// Invoke the definition to get back the template function
|
|
52
28
|
const result = await defineFn();
|
|
53
29
|
|
|
30
|
+
const key = options.key;
|
|
54
31
|
const resultExtension = key ? extension.extname(key) : null;
|
|
55
32
|
if (resultExtension && Object.isExtensible(result)) {
|
|
56
33
|
// Add sidecar function so this template can be used in a map.
|
|
@@ -45,7 +45,16 @@ function tsvParse(text) {
|
|
|
45
45
|
const values = lines[i].split("\t");
|
|
46
46
|
const entry = {};
|
|
47
47
|
for (let j = 0; j < headers.length; j++) {
|
|
48
|
-
|
|
48
|
+
/** @type {string|number} */
|
|
49
|
+
let value = values[j];
|
|
50
|
+
if (value !== undefined) {
|
|
51
|
+
// Attempt to convert to number if possible
|
|
52
|
+
const n = Number(value);
|
|
53
|
+
if (!isNaN(n)) {
|
|
54
|
+
value = n;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
entry[headers[j]] = value ?? "";
|
|
49
58
|
}
|
|
50
59
|
data.push(entry);
|
|
51
60
|
}
|
|
@@ -1,5 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
getParent,
|
|
3
|
+
isUnpackable,
|
|
4
|
+
symbols,
|
|
5
|
+
toString,
|
|
6
|
+
} from "@weborigami/async-tree";
|
|
2
7
|
import * as YAMLModule from "yaml";
|
|
8
|
+
import * as compile from "../compiler/compile.js";
|
|
9
|
+
import projectGlobals from "../project/projectGlobals.js";
|
|
10
|
+
import * as expressionFunction from "../runtime/expressionFunction.js";
|
|
11
|
+
import getSource from "./getSource.js";
|
|
3
12
|
|
|
4
13
|
// The "yaml" package doesn't seem to provide a default export that the browser can
|
|
5
14
|
// recognize, so we have to handle two ways to accommodate Node and the browser.
|
|
@@ -16,12 +25,20 @@ export default {
|
|
|
16
25
|
mediaType: "application/yaml",
|
|
17
26
|
|
|
18
27
|
/** @type {import("@weborigami/async-tree").UnpackFunction} */
|
|
19
|
-
unpack(packed) {
|
|
28
|
+
async unpack(packed, options = {}) {
|
|
20
29
|
const yaml = toString(packed);
|
|
21
30
|
if (!yaml) {
|
|
22
31
|
throw new Error("Tried to parse something as YAML but it wasn't text.");
|
|
23
32
|
}
|
|
24
|
-
const
|
|
33
|
+
const parent = getParent(packed, options);
|
|
34
|
+
const oriCallTag = await oriCallTagForParent(parent, options);
|
|
35
|
+
const oriTag = await oriTagForParent(parent, options);
|
|
36
|
+
// YAML parser is sync, but top-level !ori or !ori.call tags will return a
|
|
37
|
+
// promise.
|
|
38
|
+
// @ts-ignore TypeScript complains customTags isn't valid here but it is.
|
|
39
|
+
const data = await YAML.parse(yaml, {
|
|
40
|
+
customTags: [oriCallTag, oriTag],
|
|
41
|
+
});
|
|
25
42
|
if (data && typeof data === "object" && Object.isExtensible(data)) {
|
|
26
43
|
Object.defineProperty(data, symbols.deep, {
|
|
27
44
|
enumerable: false,
|
|
@@ -31,3 +48,58 @@ export default {
|
|
|
31
48
|
return data;
|
|
32
49
|
},
|
|
33
50
|
};
|
|
51
|
+
|
|
52
|
+
async function oriCallTagForParent(parent, options) {
|
|
53
|
+
const globals = await projectGlobals();
|
|
54
|
+
return {
|
|
55
|
+
collection: "seq",
|
|
56
|
+
|
|
57
|
+
tag: "!ori.call",
|
|
58
|
+
|
|
59
|
+
identify: (value) => false,
|
|
60
|
+
|
|
61
|
+
async resolve(value) {
|
|
62
|
+
/** @type {any[]} */
|
|
63
|
+
const args = typeof value?.toJSON === "function" ? value.toJSON() : value;
|
|
64
|
+
|
|
65
|
+
// First arg is Origami source
|
|
66
|
+
const text = args.shift();
|
|
67
|
+
const source = getSource(text, options);
|
|
68
|
+
|
|
69
|
+
const codeFn = compile.expression(source, {
|
|
70
|
+
globals,
|
|
71
|
+
parent,
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// Evaluate the code to get a function
|
|
75
|
+
let fn = await codeFn.call(parent);
|
|
76
|
+
|
|
77
|
+
// Call the function with the rest of the args
|
|
78
|
+
if (isUnpackable(fn)) {
|
|
79
|
+
fn = await fn.unpack();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return fn.call(null, ...args);
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Define the !ori tag for YAML parsing. This will run in the context of the
|
|
88
|
+
// supplied parent.
|
|
89
|
+
async function oriTagForParent(parent, options) {
|
|
90
|
+
const globals = await projectGlobals();
|
|
91
|
+
return {
|
|
92
|
+
identify: expressionFunction.isExpressionFunction,
|
|
93
|
+
|
|
94
|
+
resolve(text) {
|
|
95
|
+
const source = getSource(text, options);
|
|
96
|
+
const fn = compile.expression(source, {
|
|
97
|
+
globals,
|
|
98
|
+
parent,
|
|
99
|
+
});
|
|
100
|
+
return fn.call(parent);
|
|
101
|
+
},
|
|
102
|
+
|
|
103
|
+
tag: "!ori",
|
|
104
|
+
};
|
|
105
|
+
}
|
package/src/project/jsGlobals.js
CHANGED
|
@@ -168,7 +168,11 @@ async function fetchWrapper(resource, options) {
|
|
|
168
168
|
return response.ok ? await response.arrayBuffer() : undefined;
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
-
/**
|
|
171
|
+
/**
|
|
172
|
+
* @typedef {import("@weborigami/async-tree").AsyncMap} AsyncMap
|
|
173
|
+
*
|
|
174
|
+
* @this {AsyncMap|null|undefined}
|
|
175
|
+
*/
|
|
172
176
|
async function importWrapper(modulePath) {
|
|
173
177
|
// Walk up parent tree looking for a FileTree or other object with a `path`
|
|
174
178
|
/** @type {any} */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { FileMap, toString } from "@weborigami/async-tree";
|
|
2
2
|
import ori_handler from "../handlers/ori_handler.js";
|
|
3
3
|
import coreGlobals from "./coreGlobals.js";
|
|
4
4
|
import projectRoot from "./projectRoot.js";
|
|
@@ -14,9 +14,9 @@ export default async function config(dir = process.cwd()) {
|
|
|
14
14
|
return cached;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
// Use a plain
|
|
18
|
-
const
|
|
19
|
-
const configBuffer = await
|
|
17
|
+
// Use a plain FileMap to avoid loading extension handlers
|
|
18
|
+
const rootFileMap = new FileMap(rootPath);
|
|
19
|
+
const configBuffer = await rootFileMap.get("config.ori");
|
|
20
20
|
let configObject = {};
|
|
21
21
|
if (configBuffer) {
|
|
22
22
|
const configText = toString(configBuffer);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { FileMap } from "@weborigami/async-tree";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import
|
|
3
|
+
import OrigamiFileMap from "../runtime/OrigamiFileMap.js";
|
|
4
4
|
|
|
5
5
|
const configFileName = "config.ori";
|
|
6
6
|
const packageFileName = "package.json";
|
|
@@ -8,7 +8,7 @@ const packageFileName = "package.json";
|
|
|
8
8
|
const mapPathToRoot = new Map();
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
* Return an
|
|
11
|
+
* Return an OrigamiFileMap object for the current project.
|
|
12
12
|
*
|
|
13
13
|
* This searches the current directory and its ancestors for an Origami file
|
|
14
14
|
* called `config.ori`. If an Origami configuration file is found, the
|
|
@@ -17,7 +17,6 @@ const mapPathToRoot = new Map();
|
|
|
17
17
|
* Otherwise, this looks for a package.json file to determine the project root.
|
|
18
18
|
* If no package.json is found, the current folder is used as the project root.
|
|
19
19
|
*
|
|
20
|
-
* @typedef {import("@weborigami/types").AsyncTree} AsyncTree
|
|
21
20
|
*
|
|
22
21
|
* @param {string} [dirname]
|
|
23
22
|
*/
|
|
@@ -29,19 +28,19 @@ export default async function projectRoot(dirname = process.cwd()) {
|
|
|
29
28
|
|
|
30
29
|
let root;
|
|
31
30
|
let value;
|
|
32
|
-
// Use a plain
|
|
33
|
-
const currentTree = new
|
|
31
|
+
// Use a plain FileMap to avoid loading extension handlers
|
|
32
|
+
const currentTree = new FileMap(dirname);
|
|
34
33
|
// Try looking for config file
|
|
35
34
|
value = await currentTree.get(configFileName);
|
|
36
35
|
if (value) {
|
|
37
36
|
// Found config file
|
|
38
|
-
root = new
|
|
37
|
+
root = new OrigamiFileMap(currentTree.path);
|
|
39
38
|
} else {
|
|
40
39
|
// Try looking for package.json
|
|
41
40
|
value = await currentTree.get(packageFileName);
|
|
42
41
|
if (value) {
|
|
43
42
|
// Found package.json
|
|
44
|
-
root = new
|
|
43
|
+
root = new OrigamiFileMap(currentTree.path);
|
|
45
44
|
} else {
|
|
46
45
|
// Move up a folder and try again
|
|
47
46
|
const parentPath = path.dirname(dirname);
|
|
@@ -49,7 +48,7 @@ export default async function projectRoot(dirname = process.cwd()) {
|
|
|
49
48
|
root = await projectRoot(parentPath);
|
|
50
49
|
} else {
|
|
51
50
|
// At filesystem root, use current working directory
|
|
52
|
-
root = new
|
|
51
|
+
root = new OrigamiFileMap(process.cwd());
|
|
53
52
|
}
|
|
54
53
|
}
|
|
55
54
|
}
|
|
@@ -5,14 +5,14 @@ import constructHref from "./constructHref.js";
|
|
|
5
5
|
/**
|
|
6
6
|
* Given a protocol, a host, and a list of keys, construct an href.
|
|
7
7
|
*
|
|
8
|
-
* @typedef {import("@weborigami/
|
|
8
|
+
* @typedef {import("@weborigami/async-tree").SyncOrAsyncMap} SyncOrAsyncMap
|
|
9
9
|
*
|
|
10
10
|
* @param {string} protocol
|
|
11
|
-
* @param {import("../../index.ts").Constructor<
|
|
11
|
+
* @param {import("../../index.ts").Constructor<SyncOrAsyncMap>} mapClass
|
|
12
12
|
* @param {string} host
|
|
13
13
|
* @param {string[]} keys
|
|
14
14
|
*/
|
|
15
|
-
export default function constructSiteTree(protocol,
|
|
15
|
+
export default function constructSiteTree(protocol, mapClass, host, ...keys) {
|
|
16
16
|
// If the last key doesn't end in a slash, remove it for now.
|
|
17
17
|
let lastKey;
|
|
18
18
|
if (keys.length > 0 && keys.at(-1) && !trailingSlash.has(keys.at(-1))) {
|
|
@@ -20,7 +20,7 @@ export default function constructSiteTree(protocol, treeClass, host, ...keys) {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
const href = constructHref(protocol, host, ...keys);
|
|
23
|
-
let result = new (HandleExtensionsTransform(
|
|
23
|
+
let result = new (HandleExtensionsTransform(mapClass))(href);
|
|
24
24
|
|
|
25
25
|
return lastKey ? result.get(lastKey) : result;
|
|
26
26
|
}
|
package/src/protocols/explore.js
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ExplorableSiteMap } from "@weborigami/async-tree";
|
|
2
2
|
import constructSiteTree from "./constructSiteTree.js";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* A site tree with JSON Keys via HTTPS.
|
|
6
6
|
*
|
|
7
|
-
* @typedef {import("@weborigami/types").AsyncTree} AsyncTree
|
|
8
7
|
*
|
|
9
8
|
* @param {string} host
|
|
10
9
|
* @param {...string} keys
|
|
11
10
|
*/
|
|
12
11
|
export default function explore(host, ...keys) {
|
|
13
|
-
return constructSiteTree("https:",
|
|
12
|
+
return constructSiteTree("https:", ExplorableSiteMap, host, ...keys);
|
|
14
13
|
}
|
package/src/protocols/files.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import os from "node:os";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import process from "node:process";
|
|
4
|
-
import
|
|
4
|
+
import OrigamiFileMap from "../runtime/OrigamiFileMap.js";
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* @typedef {import("@weborigami/types").AsyncTree} AsyncTree
|
|
8
7
|
*
|
|
9
8
|
* @param {string[]} keys
|
|
10
9
|
*/
|
|
@@ -21,6 +20,6 @@ export default async function files(...keys) {
|
|
|
21
20
|
}
|
|
22
21
|
const resolved = path.resolve(basePath, relativePath);
|
|
23
22
|
|
|
24
|
-
const result = new
|
|
23
|
+
const result = new OrigamiFileMap(resolved);
|
|
25
24
|
return result;
|
|
26
25
|
}
|
package/src/protocols/http.js
CHANGED
package/src/protocols/https.js
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SiteMap } from "@weborigami/async-tree";
|
|
2
2
|
import constructSiteTree from "./constructSiteTree.js";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Return a website tree via HTTPS.
|
|
6
6
|
*
|
|
7
|
-
* @typedef {import("@weborigami/types").AsyncTree} AsyncTree
|
|
8
7
|
*
|
|
9
8
|
* @param {string} host
|
|
10
9
|
* @param {...string} keys
|
|
11
10
|
*/
|
|
12
11
|
export default function httpstree(host, ...keys) {
|
|
13
|
-
return constructSiteTree("https:",
|
|
12
|
+
return constructSiteTree("https:", SiteMap, host, ...keys);
|
|
14
13
|
}
|
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SiteMap } from "@weborigami/async-tree";
|
|
2
2
|
import constructSiteTree from "./constructSiteTree.js";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Return a website tree via HTTP.
|
|
6
6
|
*
|
|
7
|
-
* @typedef {import("@weborigami/types").AsyncTree} AsyncTree
|
|
8
7
|
*
|
|
9
8
|
* @param {string} host
|
|
10
9
|
* @param {...string} keys
|
|
11
10
|
*/
|
|
12
11
|
export default function httptree(host, ...keys) {
|
|
13
|
-
return constructSiteTree("http:",
|
|
12
|
+
return constructSiteTree("http:", SiteMap, host, ...keys);
|
|
14
13
|
}
|