@weborigami/language 0.0.39 → 0.0.41

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 CHANGED
@@ -15,6 +15,7 @@ export type Constructor<T> = new (...args: any[]) => T;
15
15
  export type FileUnpackFunction = (
16
16
  input: StringLike,
17
17
  options?: {
18
+ compiler?: any,
18
19
  key?: any,
19
20
  parent?: AsyncTree | null
20
21
  }
package/package.json CHANGED
@@ -1,24 +1,24 @@
1
1
  {
2
2
  "name": "@weborigami/language",
3
- "version": "0.0.39",
3
+ "version": "0.0.41",
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": "20.11.3",
9
+ "@types/node": "20.11.7",
10
10
  "typescript": "5.3.3"
11
11
  },
12
12
  "dependencies": {
13
- "@weborigami/types": "*",
14
- "@weborigami/async-tree": "*",
13
+ "@weborigami/async-tree": "0.0.41",
14
+ "@weborigami/types": "0.0.41",
15
15
  "peggy": "3.0.2",
16
16
  "watcher": "2.3.0"
17
17
  },
18
18
  "scripts": {
19
19
  "build": "peggy --allowed-start-rules=\"*\" --format es src/compiler/origami.pegjs --output src/compiler/parse.js",
20
20
  "prepublishOnly": "npm run build",
21
- "test": "node --test",
21
+ "test": "node --test --test-reporter=spec",
22
22
  "typecheck": "tsc"
23
23
  }
24
24
  }
@@ -15,54 +15,55 @@ __
15
15
  = (inlineSpace / newLine / comment)* { return ""; }
16
16
 
17
17
  // A filesystem path that begins with a slash: `/foo/bar`
18
- absoluteFilePath
18
+ absoluteFilePath "absolute file path"
19
19
  = path:leadingSlashPath { return [[ops.filesRoot], ...path]; }
20
20
 
21
- // A chain of arguments: `(arg1)(arg2)(arg3)`
22
- argsChain
23
- = parts:(parensArgs / leadingSlashPath)+ { return parts; }
21
+ args "function arguments"
22
+ = parensArgs
23
+ / path:leadingSlashPath { return [ops.traverse, ...path]; }
24
24
 
25
25
  // An assignment statement: `foo = 1`
26
- assignment
26
+ assignment "tree assignment"
27
27
  = @identifier __ "=" __ @expr
28
28
 
29
29
  assignmentOrShorthand
30
30
  = assignment
31
31
  / key:identifier { return [key, [ops.inherited, key]]; }
32
32
 
33
- array
33
+ array "array"
34
34
  = "[" __ list:list? "]" { return [ops.array, ...(list ?? [])]; }
35
35
 
36
36
  // Something that can be called. This is more restrictive than the `expr`
37
37
  // parser; it doesn't accept regular function calls.
38
- callTarget
38
+ callTarget "function call"
39
39
  = absoluteFilePath
40
40
  / array
41
41
  / object
42
42
  / tree
43
43
  / lambda
44
+ / parameterizedLambda
44
45
  / protocolCall
45
46
  / group
46
47
  / scopeReference
47
48
 
48
49
  // A single line comment
49
- comment
50
+ comment "comment"
50
51
  = "#" [^\n\r]*
51
52
 
52
53
  digits
53
54
  = @[0-9]+
54
55
 
55
- doubleQuoteString
56
+ doubleQuoteString "double quote string"
56
57
  = '"' chars:doubleQuoteStringChar* '"' { return chars.join(""); }
57
58
 
58
59
  doubleQuoteStringChar
59
60
  = !('"' / newLine) @textChar
60
61
 
61
- escapedChar
62
+ escapedChar "backslash-escaped character"
62
63
  = "\\" @.
63
64
 
64
65
  // An Origami expression, no leading/trailing whitespace
65
- expr
66
+ expr "expression"
66
67
  // Try function calls first, as they can start with expression types that
67
68
  // follow (array, object, etc.); we want to parse the largest thing first.
68
69
  = implicitParensCall
@@ -73,8 +74,9 @@ expr
73
74
  / array
74
75
  / object
75
76
  / tree
76
- / lambda
77
77
  / templateLiteral
78
+ / lambda
79
+ / parameterizedLambda
78
80
  / group
79
81
  / string
80
82
  / number
@@ -87,29 +89,35 @@ expr
87
89
  expression "Origami expression"
88
90
  = __ @expr __
89
91
 
90
- float
92
+ float "floating-point number"
91
93
  = sign? digits? "." digits {
92
94
  return parseFloat(text());
93
95
  }
94
96
 
95
97
  // Parse a function and its arguments, e.g. `fn(arg)`, possibly part of a chain
96
98
  // of function calls, like `fn(arg1)(arg2)(arg3)`.
97
- functionComposition
98
- = target:callTarget chain:argsChain { return makeFunctionCall(target, chain); }
99
+ functionComposition "function composition"
100
+ // = target:callTarget chain:argsChain { return makeFunctionCall(target, chain); }
101
+ = target:callTarget chain:args+ { return makeFunctionCall(target, chain); }
99
102
 
100
103
  // An expression in parentheses: `(foo)`
101
- group
104
+ group "parenthetical group"
102
105
  = "(" __ @expr __ ")"
103
106
 
104
- identifier
107
+ identifier "identifier"
105
108
  = chars:identifierChar+ { return chars.join(""); }
106
109
 
107
110
  identifierChar
108
- = [^(){}\[\],/:=\`"'\\# \t\n\r] // No unescaped whitespace or special chars
111
+ = [^(){}\[\]<>,/:=\`"'\\# \t\n\r] // No unescaped whitespace or special chars
109
112
  / escapedChar
110
113
 
114
+ identifierList
115
+ = head:identifier tail:(separator @identifier)* separator? {
116
+ return [head].concat(tail);
117
+ }
118
+
111
119
  // A function call with implicit parentheses: `fn 1, 2, 3`
112
- implicitParensCall
120
+ implicitParensCall "function call with implicit parentheses"
113
121
  = target:(functionComposition / callTarget) inlineSpace+ args:list {
114
122
  return [target, ...args];
115
123
  }
@@ -117,28 +125,29 @@ implicitParensCall
117
125
  // A host identifier that may include a colon and port number: `example.com:80`.
118
126
  // This is used as a special case at the head of a path, where we want to
119
127
  // interpret a colon as part of a text identifier.
120
- host
128
+ host "HTTP/HTTPS host"
121
129
  = identifier (":" number)? { return text(); }
122
130
 
123
131
  inlineSpace
124
132
  = [ \t]
125
133
 
126
- integer
134
+ integer "integer"
127
135
  = sign? digits {
128
136
  return parseInt(text());
129
137
  }
130
138
 
131
139
  // A lambda expression: `=foo()`
132
- lambda
133
- = "=" __ expr:expr { return [ops.lambda, expr]; }
140
+ lambda "lambda function"
141
+ = "=" __ expr:expr { return [ops.lambda, null, expr]; }
134
142
 
135
143
  // A path that begins with a slash: `/foo/bar`
136
- leadingSlashPath
144
+ leadingSlashPath "path with a leading slash"
137
145
  = "/" @path
138
146
  / "/" { return [""]; }
139
147
 
140
148
  // A separated list of expressions
141
- list = head:expr tail:(separator @expr)* separator? { return [head].concat(tail); }
149
+ list "list"
150
+ = head:expr tail:(separator @expr)* separator? { return [head].concat(tail); }
142
151
 
143
152
  newLine
144
153
  = "\n"
@@ -146,7 +155,7 @@ newLine
146
155
  / "\r"
147
156
 
148
157
  // A number
149
- number
158
+ number "number"
150
159
  = float
151
160
  / integer
152
161
 
@@ -154,7 +163,7 @@ number
154
163
  //
155
164
  // TODO: Use Object.fromEntries with array of key/value pairs
156
165
  //
157
- object
166
+ object "object literal"
158
167
  = "{" __ properties:objectProperties? "}" { return [ops.object, ...(properties ?? [])]; }
159
168
 
160
169
  // A separated list of object properties or shorthands
@@ -164,15 +173,20 @@ objectProperties
164
173
  }
165
174
 
166
175
  // A single object property with key and value: `x: 1`
167
- objectProperty
176
+ objectProperty "object property"
168
177
  = @identifier __ ":" __ @expr
169
178
 
170
179
  objectPropertyOrShorthand
171
180
  = objectProperty
172
181
  / key:identifier { return [key, [ops.scope, key]]; }
173
182
 
183
+ parameterizedLambda
184
+ = "(" __ parameters:identifierList? ")" __ ("=>"/"⇒") __ expr:expr {
185
+ return [ops.lambda, parameters ?? [], expr];
186
+ }
187
+
174
188
  // Function arguments in parentheses
175
- parensArgs
189
+ parensArgs "function arguments in parentheses"
176
190
  = "(" __ list:list? ")" { return list ?? [undefined]; }
177
191
 
178
192
  separator
@@ -183,26 +197,26 @@ sign
183
197
  = [+\-]
184
198
 
185
199
  // A slash-separated path of keys
186
- path
200
+ path "slash-separated path"
187
201
  = head:pathKey "/" tail:path { return [head].concat(tail); }
188
202
  / key:pathKey { return [key]; }
189
203
 
190
204
  // A single key in a slash-separated path
191
- pathKey
205
+ pathKey "path element"
192
206
  = key:identifierChar* { return key.join(""); }
193
207
 
194
208
  // Parse a protocol call like `fn://foo/bar`.
195
209
  // There can be zero, one, or two slashes after the colon.
196
- protocolCall
210
+ protocolCall "function call using protocol: syntax"
197
211
  = protocol:protocol ":" "/"|0..2| host:host path:leadingSlashPath? {
198
212
  return [protocol, host, ...(path ?? [])];
199
213
  }
200
214
 
201
- protocol
215
+ protocol "protocol"
202
216
  = reservedProtocol
203
217
  / scopeReference
204
218
 
205
- reservedProtocol
219
+ reservedProtocol "reserved protocol"
206
220
  = "https" { return ops.https; }
207
221
  / "http" { return ops.http; }
208
222
  / "package" { return [ops.scope, "@package"] } // Alias
@@ -210,10 +224,10 @@ reservedProtocol
210
224
  / "treehttp" { return ops.treeHttp; }
211
225
  / "tree" { return ops.treeHttps; } // Alias
212
226
 
213
- scopeReference
227
+ scopeReference "scope reference"
214
228
  = key:identifier { return [ops.scope, key]; }
215
229
 
216
- singleQuoteString
230
+ singleQuoteString "single quote string"
217
231
  = "'" chars:singleQuoteStringChar* "'" { return chars.join(""); }
218
232
 
219
233
  singleQuoteStringChar
@@ -222,14 +236,14 @@ singleQuoteStringChar
222
236
  start
223
237
  = number
224
238
 
225
- string
239
+ string "string"
226
240
  = doubleQuoteString
227
241
  / singleQuoteString
228
242
 
229
243
  // A top-level document defining a template. This is the same as a template
230
244
  // literal, but can contain backticks at the top level.
231
- templateDocument "Origami template"
232
- = contents:templateDocumentContents { return [ops.lambda, contents]; }
245
+ templateDocument "template"
246
+ = contents:templateDocumentContents { return [ops.lambda, null, contents]; }
233
247
 
234
248
  // Template documents can contain backticks at the top level.
235
249
  templateDocumentChar
@@ -239,11 +253,11 @@ templateDocumentChar
239
253
  templateDocumentContents
240
254
  = parts:(templateDocumentText / templateSubstitution)* { return makeTemplate(parts); }
241
255
 
242
- templateDocumentText
256
+ templateDocumentText "template text"
243
257
  = chars:templateDocumentChar+ { return chars.join(""); }
244
258
 
245
259
  // A backtick-quoted template literal
246
- templateLiteral
260
+ templateLiteral "template literal"
247
261
  = "`" @templateLiteralContents "`"
248
262
 
249
263
  templateLiteralChar
@@ -258,14 +272,14 @@ templateLiteralText
258
272
  = chars:templateLiteralChar+ { return chars.join(""); }
259
273
 
260
274
  // A substitution in a template literal: `{{ fn() }}`
261
- templateSubstitution
275
+ templateSubstitution "template substitution"
262
276
  = "{{" @expression "}}"
263
277
 
264
278
  textChar
265
279
  = escapedChar / .
266
280
 
267
281
  // A tree literal: `{ index.html = "Hello" }`
268
- tree
282
+ tree "tree literal"
269
283
  = "{" __ assignments:treeAssignments? "}" { return [ops.tree, ...(assignments ?? [])]; }
270
284
 
271
285
  // A separated list of assignments or shorthands