@weborigami/language 0.3.3-jse.3 → 0.3.4-jse.4

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.
@@ -7,7 +7,7 @@ import { ops } from "../../src/runtime/internal.js";
7
7
  import { assertCodeEqual, createCode } from "./codeHelpers.js";
8
8
 
9
9
  describe("optimize", () => {
10
- test("change local references to context references", async () => {
10
+ test("change local references to context references", () => {
11
11
  const expression = `(name) => {
12
12
  a: name,
13
13
  b: a
@@ -17,15 +17,50 @@ describe("optimize", () => {
17
17
  [[ops.literal, "name"]],
18
18
  [
19
19
  ops.object,
20
- ["a", [[ops.context, 1], "name"]],
21
- ["b", [[ops.context], "a"]],
20
+ [
21
+ "a",
22
+ [
23
+ [ops.context, 1],
24
+ [ops.literal, "name"],
25
+ ],
26
+ ],
27
+ ["b", [[ops.context], [ops.literal, "a"]]],
22
28
  ],
23
29
  ];
24
- await assertCompile(expression, expected);
25
- await assertCompile(expression, expected, "jse");
30
+ assertCompile(expression, expected);
26
31
  });
27
32
 
28
- test("when defining a property, avoid recursive references", async () => {
33
+ test("resolve deeper context references", () => {
34
+ // Compilation of `{ a: 1, more: { a } }`
35
+ const code = createCode([
36
+ ops.object,
37
+ ["a", [ops.literal, 1]],
38
+ [
39
+ "more",
40
+ [ops.object, ["a", [markers.traverse, [markers.reference, "a"]]]],
41
+ ],
42
+ ]);
43
+ const expected = [
44
+ ops.object,
45
+ ["a", 1],
46
+ [
47
+ "more",
48
+ [
49
+ ops.object,
50
+ [
51
+ "a",
52
+ [
53
+ [ops.context, 1],
54
+ [ops.literal, "a"],
55
+ ],
56
+ ],
57
+ ],
58
+ ],
59
+ ];
60
+ assertCodeEqual(optimize(code), expected);
61
+ });
62
+
63
+ test("when defining a property, avoid recursive references", () => {
29
64
  const expression = `{
30
65
  name: "Alice",
31
66
  user: {
@@ -35,74 +70,209 @@ describe("optimize", () => {
35
70
  const expected = [
36
71
  ops.object,
37
72
  ["name", "Alice"],
38
- ["user", [ops.object, ["name", [[ops.context, 1], "name"]]]],
73
+ [
74
+ "user",
75
+ [
76
+ ops.object,
77
+ [
78
+ "name",
79
+ [
80
+ [ops.context, 1],
81
+ [ops.literal, "name"],
82
+ ],
83
+ ],
84
+ ],
85
+ ],
39
86
  ];
40
- await assertCompile(expression, expected);
41
- await assertCompile(expression, expected, "jse");
87
+ assertCompile(expression, expected);
88
+ assertCompile(expression, expected, "jse");
42
89
  });
43
90
 
44
- test("cache shell non-local references to globals+scope calls", async () => {
45
- // Compilation of `x/y/z.js`
46
- const code = createCode([
47
- markers.reference,
48
- [ops.literal, "x/"],
49
- [ops.literal, "y/"],
50
- [ops.literal, "z.js"],
51
- ]);
52
- const globals = {};
53
- const expected = [
54
- ops.cache,
55
- {},
56
- "x/y/z.js",
57
- [[ops.merge, globals, [ops.scope]], "x/", "y/", "z.js"],
58
- ];
59
- assertCodeEqual(optimize(code, { globals }), expected);
60
- });
91
+ describe("resolve reference", () => {
92
+ test("external reference", () => {
93
+ // Compilation of `folder` where folder isn't a variable
94
+ const code = createCode([
95
+ markers.traverse,
96
+ [markers.reference, "folder"],
97
+ ]);
98
+ const expected = [
99
+ ops.cache,
100
+ {},
101
+ "folder",
102
+ [[ops.scope], [ops.literal, "folder"]],
103
+ ];
104
+ const globals = {};
105
+ assertCodeEqual(optimize(code, { globals }), expected);
106
+ });
61
107
 
62
- test("change jse non-local references to globals", async () => {
63
- // Compilation of `x/y`
64
- const code = createCode([
65
- markers.reference,
66
- [ops.literal, "x/"],
67
- [ops.literal, "y"],
68
- ]);
69
- const globals = {};
70
- const expected = [globals, "x/", "y"];
71
- assertCodeEqual(optimize(code, { globals, mode: "jse" }), expected);
72
- });
108
+ test("external reference", () => {
109
+ // Compilation of `index.html` where `index` isn't a variable
110
+ const code = createCode([
111
+ markers.traverse,
112
+ [markers.reference, "index.html"],
113
+ ]);
114
+ const expected = [
115
+ ops.cache,
116
+ {},
117
+ "index.html",
118
+ [[ops.scope], [ops.literal, "index.html"]],
119
+ ];
120
+ const globals = {};
121
+ assertCodeEqual(optimize(code, { globals }), expected);
122
+ });
73
123
 
74
- test("cache jse top-level scope references", async () => {
75
- // Compilation of `x/y/z.js`
76
- const code = createCode([
77
- [ops.scope],
78
- [ops.literal, "x/"],
79
- [ops.literal, "y/"],
80
- [ops.literal, "z.js"],
81
- ]);
82
- const expected = [
83
- ops.cache,
84
- {},
85
- "x/y/z.js",
86
- [[ops.scope], "x/", "y/", "z.js"],
87
- ];
88
- assertCodeEqual(optimize(code, { mode: "jse" }), expected);
124
+ test("external reference inside object with matching key", () => {
125
+ // Compilation of `{ (posts) = posts.txt }`
126
+ const code = createCode([
127
+ ops.object,
128
+ [
129
+ "(posts)",
130
+ [ops.getter, [markers.traverse, [markers.reference, "posts.txt"]]],
131
+ ],
132
+ ]);
133
+ const expected = [
134
+ ops.object,
135
+ [
136
+ "(posts)",
137
+ [
138
+ ops.getter,
139
+ [
140
+ ops.cache,
141
+ {},
142
+ "posts.txt",
143
+ [
144
+ [ops.scope, [ops.context, 1]],
145
+ [ops.literal, "posts.txt"],
146
+ ],
147
+ ],
148
+ ],
149
+ ],
150
+ ];
151
+ const globals = {};
152
+ assertCodeEqual(optimize(code, { globals }), expected);
153
+ });
154
+
155
+ test("global reference", () => {
156
+ // Compilation of `Math` where Math is a global variable
157
+ const code = createCode([markers.traverse, [markers.reference, "Math"]]);
158
+ const globals = { Math: null }; // value doesn't matter
159
+ const expected = [globals, "Math"];
160
+ assertCodeEqual(optimize(code, { globals }), expected);
161
+ });
162
+
163
+ test("global reference", () => {
164
+ // Compilation of `Math.PI` where Math is a global variable
165
+ const code = createCode([
166
+ markers.traverse,
167
+ [markers.reference, "Math.PI"],
168
+ ]);
169
+ const globals = { Math: { PI: null } }; // value doesn't matter
170
+ const expected = [[globals, "Math"], "PI"];
171
+ assertCodeEqual(optimize(code, { globals }), expected);
172
+ });
173
+
174
+ test("local reference", () => {
175
+ // Compilation of `post` where post is a local variable
176
+ const code = createCode([markers.traverse, [markers.reference, "post"]]);
177
+ const globals = { post: {} }; // local should take precedence
178
+ const locals = [["post"]];
179
+ const actual = optimize(code, { globals, locals });
180
+ const expected = [[ops.context], [ops.literal, "post"]];
181
+ assertCodeEqual(actual, expected);
182
+ });
183
+
184
+ test("local reference and property", () => {
185
+ // Compilation of `post.author.name` where `post` is a local variable
186
+ const code = createCode([
187
+ markers.traverse,
188
+ [markers.reference, "post.author.name"],
189
+ ]);
190
+ const globals = { post: {} }; // local should take precedence
191
+ const locals = [["post"]];
192
+ const actual = optimize(code, { globals, locals });
193
+ const expected = [
194
+ [[[ops.context], [ops.literal, "post"]], "author"],
195
+ "name",
196
+ ];
197
+ assertCodeEqual(actual, expected);
198
+ });
199
+
200
+ test("root directory", () => {
201
+ // Compilation of `</>`
202
+ const code = createCode([markers.traverse, [markers.external, "/"]]);
203
+ const expected = [ops.cache, {}, "/", [ops.rootDirectory]];
204
+ assertCodeEqual(optimize(code), expected);
205
+ });
206
+
207
+ test("home directory", () => {
208
+ // Compilation of `<~>`
209
+ const code = createCode([markers.traverse, [ops.homeDirectory]]);
210
+ const expected = [ops.cache, {}, "~", [ops.homeDirectory]];
211
+ assertCodeEqual(optimize(code), expected);
212
+ });
89
213
  });
90
214
 
91
- test("cache jse deeper scope references", async () => {
92
- // Compilation of `{ property: <x> }`
93
- const code = createCode([
94
- ops.object,
95
- ["property", [[ops.scope], [ops.literal, "x"]]],
96
- ]);
97
- const expected = [
98
- ops.object,
99
- ["property", [ops.cache, {}, "x", [[ops.scope, [ops.context, 1]], "x"]]],
100
- ];
101
- assertCodeEqual(optimize(code, { mode: "jse" }), expected);
215
+ describe("path traversal", () => {
216
+ test("explicit external path", () => {
217
+ // `<path/to/file>`
218
+ const code = createCode([
219
+ markers.traverse,
220
+ [markers.external, "path/"],
221
+ [ops.literal, "to/"],
222
+ [ops.literal, "file"],
223
+ ]);
224
+ const expected = [
225
+ ops.cache,
226
+ {},
227
+ "path/to/file",
228
+ [
229
+ [ops.scope],
230
+ [ops.literal, "path/"],
231
+ [ops.literal, "to/"],
232
+ [ops.literal, "file"],
233
+ ],
234
+ ];
235
+ assertCodeEqual(optimize(code), expected);
236
+ });
237
+
238
+ test("implicit external path", () => {
239
+ // Compilation of `package.json/name` where package is neither local nor global
240
+ const code = createCode([
241
+ markers.traverse,
242
+ [markers.reference, "package.json/"],
243
+ [ops.literal, "name"],
244
+ ]);
245
+ const globals = {};
246
+ const expected = [
247
+ ops.cache,
248
+ {},
249
+ "package.json/name",
250
+ [[ops.scope], [ops.literal, "package.json/"], [ops.literal, "name"]],
251
+ ];
252
+ assertCodeEqual(optimize(code, { globals }), expected);
253
+ });
254
+
255
+ test("local path", () => {
256
+ // Compilation of `page/title` where page is a local variable
257
+ const code = createCode([
258
+ markers.traverse,
259
+ [markers.reference, "page/"],
260
+ [ops.literal, "title"],
261
+ ]);
262
+ const globals = {};
263
+ const locals = [["page"]];
264
+ const actual = optimize(code, { globals, locals });
265
+ const expected = [
266
+ [ops.context],
267
+ [ops.literal, "page/"],
268
+ [ops.literal, "title"],
269
+ ];
270
+ assertCodeEqual(actual, expected);
271
+ });
102
272
  });
103
273
  });
104
274
 
105
- async function assertCompile(expression, expected, mode = "shell") {
275
+ function assertCompile(expression, expected, mode = "shell") {
106
276
  const parent = new ObjectTree({});
107
277
  const globals = new ObjectTree({});
108
278
  const fn = compile.expression(expression, { globals, mode, parent });