@weborigami/language 0.3.4-jse.6 → 0.3.4-jse.8
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/optimize.js +29 -18
- package/src/compiler/origami.pegjs +27 -7
- package/src/compiler/parse.js +268 -175
- package/src/runtime/errors.js +56 -24
- package/src/runtime/evaluate.js +5 -27
- package/src/runtime/symbols.js +1 -0
- package/test/compiler/optimize.test.js +3 -3
- package/test/compiler/parse.test.js +6 -0
package/src/runtime/errors.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Text we look for in an error stack to guess whether a given line represents a
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
|
+
box,
|
|
4
5
|
scope as scopeFn,
|
|
5
6
|
trailingSlash,
|
|
6
7
|
TraverseError,
|
|
@@ -8,6 +9,7 @@ import {
|
|
|
8
9
|
import path from "node:path";
|
|
9
10
|
import { fileURLToPath } from "node:url";
|
|
10
11
|
import codeFragment from "./codeFragment.js";
|
|
12
|
+
import * as symbols from "./symbols.js";
|
|
11
13
|
import { typos } from "./typos.js";
|
|
12
14
|
|
|
13
15
|
// function in the Origami source code.
|
|
@@ -18,6 +20,19 @@ const origamiSourceSignals = [
|
|
|
18
20
|
"at Scope.evaluate",
|
|
19
21
|
];
|
|
20
22
|
|
|
23
|
+
const displayedWarnings = new Set();
|
|
24
|
+
|
|
25
|
+
export function attachWarning(value, message) {
|
|
26
|
+
if (typeof value === "object" && value?.[symbols.warningSymbol]) {
|
|
27
|
+
// Already has a warning, don't overwrite it
|
|
28
|
+
return value;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const boxed = box(value);
|
|
32
|
+
boxed[symbols.warningSymbol] = message;
|
|
33
|
+
return boxed;
|
|
34
|
+
}
|
|
35
|
+
|
|
21
36
|
export async function builtinReferenceError(tree, builtins, key) {
|
|
22
37
|
// See if the key is in scope (but not as a builtin)
|
|
23
38
|
const scope = scopeFn(tree);
|
|
@@ -40,6 +55,16 @@ export async function builtinReferenceError(tree, builtins, key) {
|
|
|
40
55
|
return new ReferenceError(message);
|
|
41
56
|
}
|
|
42
57
|
|
|
58
|
+
// Display a warning message in the console, but only once for each unique
|
|
59
|
+
// message and location.
|
|
60
|
+
export function displayWarning(message, location) {
|
|
61
|
+
const warning = "Warning: " + message + lineInfo(location);
|
|
62
|
+
if (!displayedWarnings.has(warning)) {
|
|
63
|
+
displayedWarnings.add(warning);
|
|
64
|
+
console.warn(warning);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
43
68
|
/**
|
|
44
69
|
* Format an error for display in the console.
|
|
45
70
|
*
|
|
@@ -80,33 +105,10 @@ export function formatError(error) {
|
|
|
80
105
|
|
|
81
106
|
// Add location
|
|
82
107
|
if (location) {
|
|
83
|
-
let { source, start } = location;
|
|
84
|
-
// Adjust line number with offset if present (for example, if the code is in
|
|
85
|
-
// an Origami template document with front matter that was stripped)
|
|
86
|
-
let line = start.line + (source.offset ?? 0);
|
|
87
108
|
if (!fragmentInMessage) {
|
|
88
109
|
message += `\nevaluating: ${fragment}`;
|
|
89
110
|
}
|
|
90
|
-
|
|
91
|
-
if (typeof source === "object" && source.url) {
|
|
92
|
-
const { url } = source;
|
|
93
|
-
let fileRef;
|
|
94
|
-
// If URL is a file: URL, change to a relative path
|
|
95
|
-
if (url.protocol === "file:") {
|
|
96
|
-
fileRef = fileURLToPath(url);
|
|
97
|
-
const relativePath = path.relative(process.cwd(), fileRef);
|
|
98
|
-
if (!relativePath.startsWith("..")) {
|
|
99
|
-
fileRef = relativePath;
|
|
100
|
-
}
|
|
101
|
-
} else {
|
|
102
|
-
// Not a file: URL, use as is
|
|
103
|
-
fileRef = url.href;
|
|
104
|
-
}
|
|
105
|
-
message += `\n at ${fileRef}:${line}:${start.column}`;
|
|
106
|
-
} else if (source.text.includes("\n")) {
|
|
107
|
-
// Don't know the URL, but has multiple lines so add line number
|
|
108
|
-
message += `\n at line ${line}, column ${start.column}`;
|
|
109
|
-
}
|
|
111
|
+
message += lineInfo(location);
|
|
110
112
|
}
|
|
111
113
|
|
|
112
114
|
return message;
|
|
@@ -128,6 +130,36 @@ export function maybeOrigamiSourceCode(text) {
|
|
|
128
130
|
return origamiSourceSignals.some((signal) => text.includes(signal));
|
|
129
131
|
}
|
|
130
132
|
|
|
133
|
+
// Return user-friendly line information for the error location
|
|
134
|
+
function lineInfo(location) {
|
|
135
|
+
let { source, start } = location;
|
|
136
|
+
// Adjust line number with offset if present (for example, if the code is in
|
|
137
|
+
// an Origami template document with front matter that was stripped)
|
|
138
|
+
let line = start.line + (source.offset ?? 0);
|
|
139
|
+
|
|
140
|
+
if (typeof source === "object" && source.url) {
|
|
141
|
+
const { url } = source;
|
|
142
|
+
let fileRef;
|
|
143
|
+
// If URL is a file: URL, change to a relative path
|
|
144
|
+
if (url.protocol === "file:") {
|
|
145
|
+
fileRef = fileURLToPath(url);
|
|
146
|
+
const relativePath = path.relative(process.cwd(), fileRef);
|
|
147
|
+
if (!relativePath.startsWith("..")) {
|
|
148
|
+
fileRef = relativePath;
|
|
149
|
+
}
|
|
150
|
+
} else {
|
|
151
|
+
// Not a file: URL, use as is
|
|
152
|
+
fileRef = url.href;
|
|
153
|
+
}
|
|
154
|
+
return `\n at ${fileRef}:${line}:${start.column}`;
|
|
155
|
+
} else if (source.text.includes("\n")) {
|
|
156
|
+
// Don't know the URL, but has multiple lines so add line number
|
|
157
|
+
return `\n at line ${line}, column ${start.column}`;
|
|
158
|
+
} else {
|
|
159
|
+
return "";
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
131
163
|
export async function scopeReferenceError(scope, key) {
|
|
132
164
|
const messages = [
|
|
133
165
|
`"${key}" is not in scope or is undefined.`,
|
package/src/runtime/evaluate.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Tree, isUnpackable } from "@weborigami/async-tree";
|
|
2
|
+
import { displayWarning, symbols } from "@weborigami/language";
|
|
2
3
|
import codeFragment from "./codeFragment.js";
|
|
3
4
|
|
|
4
5
|
/**
|
|
@@ -66,33 +67,10 @@ export default async function evaluate(code) {
|
|
|
66
67
|
throw error;
|
|
67
68
|
}
|
|
68
69
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
// Object.defineProperty(result, sourceSymbol, {
|
|
74
|
-
// value: codeFragment(code.location),
|
|
75
|
-
// enumerable: false,
|
|
76
|
-
// });
|
|
77
|
-
// }
|
|
78
|
-
// if (!result[codeSymbol]) {
|
|
79
|
-
// Object.defineProperty(result, codeSymbol, {
|
|
80
|
-
// value: code,
|
|
81
|
-
// enumerable: false,
|
|
82
|
-
// });
|
|
83
|
-
// }
|
|
84
|
-
// if (!result[scopeSymbol]) {
|
|
85
|
-
// Object.defineProperty(result, scopeSymbol, {
|
|
86
|
-
// get() {
|
|
87
|
-
// return scope(this).trees;
|
|
88
|
-
// },
|
|
89
|
-
// enumerable: false,
|
|
90
|
-
// });
|
|
91
|
-
// }
|
|
92
|
-
// } catch (/** @type {any} */ error) {
|
|
93
|
-
// // Ignore errors.
|
|
94
|
-
// }
|
|
95
|
-
// }
|
|
70
|
+
if (result?.[symbols.warningSymbol]) {
|
|
71
|
+
displayWarning(result[symbols.warningSymbol], code.location);
|
|
72
|
+
delete result[symbols.warningSymbol];
|
|
73
|
+
}
|
|
96
74
|
|
|
97
75
|
return result;
|
|
98
76
|
}
|
package/src/runtime/symbols.js
CHANGED
|
@@ -155,8 +155,8 @@ describe("optimize", () => {
|
|
|
155
155
|
test("global reference", () => {
|
|
156
156
|
// Compilation of `Math` where Math is a global variable
|
|
157
157
|
const code = createCode([markers.traverse, [markers.reference, "Math"]]);
|
|
158
|
-
const globals = { Math:
|
|
159
|
-
const expected =
|
|
158
|
+
const globals = { Math: {} }; // value doesn't matter
|
|
159
|
+
const expected = globals.Math;
|
|
160
160
|
assertCodeEqual(optimize(code, { globals }), expected);
|
|
161
161
|
});
|
|
162
162
|
|
|
@@ -167,7 +167,7 @@ describe("optimize", () => {
|
|
|
167
167
|
[markers.reference, "Math.PI"],
|
|
168
168
|
]);
|
|
169
169
|
const globals = { Math: { PI: null } }; // value doesn't matter
|
|
170
|
-
const expected = [
|
|
170
|
+
const expected = [globals.Math, "PI"];
|
|
171
171
|
assertCodeEqual(optimize(code, { globals }), expected);
|
|
172
172
|
});
|
|
173
173
|
|
|
@@ -618,6 +618,12 @@ Body`,
|
|
|
618
618
|
[markers.traverse, [markers.reference, "keys"]],
|
|
619
619
|
[markers.traverse, [markers.external, "~"]],
|
|
620
620
|
]);
|
|
621
|
+
assertParse("expression", "!x ? 0 : 1", [
|
|
622
|
+
ops.conditional,
|
|
623
|
+
[ops.logicalNot, [markers.traverse, [markers.reference, "x"]]],
|
|
624
|
+
[ops.literal, 0],
|
|
625
|
+
[ops.literal, 1],
|
|
626
|
+
]);
|
|
621
627
|
});
|
|
622
628
|
|
|
623
629
|
test("complex object", () => {
|