@weborigami/language 0.0.66-beta.1 → 0.0.66

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,18 +1,18 @@
1
1
  {
2
2
  "name": "@weborigami/language",
3
- "version": "0.0.66-beta.1",
3
+ "version": "0.0.66",
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": "22.5.4",
9
+ "@types/node": "22.7.4",
10
10
  "peggy": "4.0.3",
11
- "typescript": "5.5.4"
11
+ "typescript": "5.6.2"
12
12
  },
13
13
  "dependencies": {
14
- "@weborigami/async-tree": "0.0.66-beta.1",
15
- "@weborigami/types": "0.0.66-beta.1",
14
+ "@weborigami/async-tree": "0.0.66",
15
+ "@weborigami/types": "0.0.66",
16
16
  "watcher": "2.3.1"
17
17
  },
18
18
  "scripts": {
@@ -63,6 +63,7 @@ callTarget "function call"
63
63
  / parameterizedLambda
64
64
  / protocolCall
65
65
  / group
66
+ / scopeTraverse
66
67
  / scopeReference
67
68
 
68
69
  // Required closing curly brace. We use this for the `object` term: if the
@@ -161,8 +162,10 @@ guillemetStringChar
161
162
  // This is used as a special case at the head of a path, where we want to
162
163
  // interpret a colon as part of a text identifier.
163
164
  host "HTTP/HTTPS host"
164
- = identifier (":" number)? {
165
- return annotate([ops.primitive, text()], location());
165
+ = identifier:identifier port:(":" @number)? {
166
+ const portText = port ? `:${port[1]}` : "";
167
+ const hostText = identifier + portText;
168
+ return annotate([ops.primitive, hostText], location());
166
169
  }
167
170
 
168
171
  identifier "identifier"
@@ -202,11 +205,8 @@ lambda "lambda function"
202
205
 
203
206
  // A path that begins with a slash: `/foo/bar`
204
207
  leadingSlashPath "path with a leading slash"
205
- = "/" path:path {
206
- return annotate(path, location());
207
- }
208
- / "/" {
209
- return annotate([""], location());
208
+ = "/" path:path? {
209
+ return annotate(path ?? [], location());
210
210
  }
211
211
 
212
212
  // A separated list of expressions
@@ -259,13 +259,6 @@ objectKey "object key"
259
259
  = objectHiddenKey
260
260
  / objectPublicKey
261
261
 
262
- objectPublicKey
263
- = identifier
264
- / string:string {
265
- // Remove `ops.primitive` from the string code
266
- return string[1];
267
- }
268
-
269
262
  // A property definition in an object literal: `x: 1`
270
263
  objectProperty "object property"
271
264
  = key:objectKey __ ":" __ value:expr {
@@ -278,6 +271,15 @@ objectShorthandProperty "object identifier"
278
271
  return annotate([key, [ops.inherited, key]], location());
279
272
  }
280
273
 
274
+ objectPublicKey
275
+ = identifier:identifier slash:"/"? {
276
+ return identifier + (slash ?? "");
277
+ }
278
+ / string:string {
279
+ // Remove `ops.primitive` from the string code
280
+ return string[1];
281
+ }
282
+
281
283
  parameterizedLambda
282
284
  = "(" __ parameters:identifierList? __ ")" __ doubleArrow __ expr:expr {
283
285
  return annotate([ops.lambda, parameters ?? [], expr], location());
@@ -296,14 +298,17 @@ pipeline
296
298
 
297
299
  // A slash-separated path of keys
298
300
  path "slash-separated path"
299
- = path:pathKey|1.., "/"| {
301
+ = head:pathElement|0..| tail:pathTail? {
302
+ let path = tail ? [...head, tail] : head;
303
+ // Remove parts for consecutive slashes
304
+ path = path.filter((part) => part[1] !== "/");
300
305
  return annotate(path, location());
301
306
  }
302
307
 
303
- // A single key in a slash-separated path
304
- pathKey "path element"
305
- = chars:pathKeyChar* {
306
- return annotate([ops.primitive, chars.join("")], location());
308
+ // A path key followed by a slash
309
+ pathElement
310
+ = chars:pathKeyChar* "/" {
311
+ return annotate([ops.primitive, chars.join("") + "/"], location());
307
312
  }
308
313
 
309
314
  // A single character in a slash-separated path.
@@ -313,6 +318,12 @@ pathKeyChar
313
318
  = [^(){}\[\],:/\\ \t\n\r]
314
319
  / escapedChar
315
320
 
321
+ // A path key without a slash
322
+ pathTail
323
+ = chars:pathKeyChar+ {
324
+ return annotate([ops.primitive, chars.join("")], location());
325
+ }
326
+
316
327
  // Parse a protocol call like `fn://foo/bar`.
317
328
  // There can be zero, one, or two slashes after the colon.
318
329
  protocolCall "function call using protocol: syntax"
@@ -325,19 +336,26 @@ protocol "protocol"
325
336
  / scopeReference
326
337
 
327
338
  reservedProtocol "reserved protocol"
328
- = "https" { return ops.https; }
339
+ = "explore" { return ops.explorableSite; }
340
+ / "https" { return ops.https; } // Must come before "http"
329
341
  / "http" { return ops.http; }
330
342
  / "new" { return ops.constructor; }
331
343
  / "package" { return [ops.scope, "@package"] } // Alias
332
- / "treehttps" { return ops.treeHttps; }
333
- / "treehttp" { return ops.treeHttp; }
334
- / "tree" { return ops.treeHttps; } // Alias
344
+ / "treehttps" { return ops.treeHttps; } // Must come before `treehttp`
345
+ / "treehttp" { return ops.treeHttp; } // Must come before `tree`
346
+ / "tree" { return ops.treeHttps; }
335
347
 
336
348
  scopeReference "scope reference"
337
349
  = key:identifier {
338
350
  return annotate([ops.scope, key], location());
339
351
  }
340
352
 
353
+ scopeTraverse
354
+ = ref:scopeReference "/" path:path {
355
+ const head = [ops.scope, `${ ref[1] }/`];
356
+ return annotate([ops.traverse, head, ...path], location());
357
+ }
358
+
341
359
  separator
342
360
  = __ "," __
343
361
  / whitespaceWithNewLine