@canvasengine/compiler 2.0.0-beta.5 → 2.0.0-beta.7

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/grammar.pegjs CHANGED
@@ -72,15 +72,17 @@ eventHandler
72
72
 
73
73
  dynamicAttribute
74
74
  = attributeName:attributeName _ "=" _ "{" _ attributeValue:attributeValue _ "}" {
75
- if (attributeValue.trim().match(/^[a-zA-Z_]\w*$/)) {
75
+ if (attributeValue.startsWith('h(') || attributeValue.includes('=>')) {
76
+ return `${attributeName}: ${attributeValue}`;
77
+ } else if (attributeValue.trim().match(/^[a-zA-Z_]\w*$/)) {
76
78
  return `${attributeName}: ${attributeValue}`;
77
79
  } else {
78
- let foundSignal = false
80
+ let foundSignal = false;
79
81
  const computedValue = attributeValue.replace(/@?[a-zA-Z_][a-zA-Z0-9_]*(?!:)/g, (match) => {
80
82
  if (match.startsWith('@')) {
81
83
  return match.substring(1);
82
84
  }
83
- foundSignal = true
85
+ foundSignal = true;
84
86
  return `${match}()`;
85
87
  });
86
88
  if (foundSignal) {
@@ -94,7 +96,9 @@ dynamicAttribute
94
96
  }
95
97
 
96
98
  attributeValue
97
- = $([^{}]* ("{" [^{}]* "}" [^{}]*)*) {
99
+ = element
100
+ / functionWithElement
101
+ / $([^{}]* ("{" [^{}]* "}" [^{}]*)*) {
98
102
  const t = text().trim()
99
103
  if (t.startsWith("{") && t.endsWith("}")) {
100
104
  return `(${t})`;
@@ -102,6 +106,25 @@ attributeValue
102
106
  return t
103
107
  }
104
108
 
109
+ functionWithElement
110
+ = "(" _ params:functionParams? _ ")" _ "=>" _ elem:element {
111
+ return `${params ? `(${params}) =>` : '() =>'} ${elem}`;
112
+ }
113
+
114
+ functionParams
115
+ = destructuredParams
116
+ / simpleParams
117
+
118
+ destructuredParams
119
+ = "{" _ param:identifier rest:(_ "," _ identifier)* _ "}" {
120
+ return `{${[param].concat(rest.map(r => r[3])).join(', ')}}`;
121
+ }
122
+
123
+ simpleParams
124
+ = param:identifier rest:(_ "," _ identifier)* {
125
+ return [param].concat(rest.map(r => r[3])).join(', ');
126
+ }
127
+
105
128
  staticAttribute
106
129
  = attributeName:attributeName _ "=" _ "\"" attributeValue:staticValue "\"" {
107
130
  return `${attributeName}: ${attributeValue}`;
@@ -139,8 +162,13 @@ textElement
139
162
  }
140
163
 
141
164
  forLoop
142
- = _ "@for" _ "(" _ variableName:identifier _ "of" _ iterable:identifier _ ")" _ "{" _ content:content _ "}" _ {
143
- return `loop(${iterable}, (${variableName}) => ${content})`;
165
+ = _ "@for" _ "(" _ variableName:(tupleDestructuring / identifier) _ "of" _ iterable:identifier _ ")" _ "{" _ content:content _ "}" _ {
166
+ return `loop(${iterable}, ${variableName} => ${content})`;
167
+ }
168
+
169
+ tupleDestructuring
170
+ = "(" _ first:identifier _ "," _ second:identifier _ ")" {
171
+ return `(${first}, ${second})`;
144
172
  }
145
173
 
146
174
  ifCondition
@@ -164,7 +192,30 @@ iterable
164
192
  = [a-zA-Z_][a-zA-Z0-9_]* { return text(); }
165
193
 
166
194
  condition
167
- = $([^)]*) { return text().trim(); }
195
+ = functionCall
196
+ / $([^)]*) { return text().trim(); }
197
+
198
+ functionCall
199
+ = name:identifier "(" args:functionArgs? ")" {
200
+ return `${name}(${args || ''})`;
201
+ }
202
+
203
+ functionArgs
204
+ = arg:functionArg rest:("," _ functionArg)* {
205
+ return [arg].concat(rest.map(r => r[2])).join(', ');
206
+ }
207
+
208
+ functionArg
209
+ = _ value:(identifier / number / string) _ {
210
+ return value;
211
+ }
212
+
213
+ number
214
+ = [0-9]+ ("." [0-9]+)? { return text(); }
215
+
216
+ string
217
+ = '"' chars:[^"]* '"' { return text(); }
218
+ / "'" chars:[^']* "'" { return text(); }
168
219
 
169
220
  eventAction
170
221
  = [^"]* { return text(); }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canvasengine/compiler",
3
- "version": "2.0.0-beta.5",
3
+ "version": "2.0.0-beta.7",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -177,11 +177,52 @@ describe("Compiler", () => {
177
177
  expect(output).toBe(`h(Sprite, { click: () => console.log('click') })`);
178
178
  });
179
179
 
180
- // test("should compile component with component attribute", () => {
181
- // const input = `<Canvas child={<Sprite />} />`;
182
- // const output = parser.parse(input);
183
- // expect(output).toBe(`h(Canvas, { child: h(Sprite) })`);
184
- // });
180
+ test("should compile component with component attribute", () => {
181
+ const input = `<Canvas child={<Sprite />} />`;
182
+ const output = parser.parse(input);
183
+ expect(output).toBe(`h(Canvas, { child: h(Sprite) })`);
184
+ });
185
+
186
+ test("should compile component with function returns component attribute", () => {
187
+ const input = `<Canvas child={() => <Sprite />} />`;
188
+ const output = parser.parse(input);
189
+ expect(output).toBe(`h(Canvas, { child: () => h(Sprite) })`);
190
+ });
191
+
192
+ test("should compile component with function (with params) returns component attribute", () => {
193
+ const input = `<Canvas child={(x, y) => <Sprite />} />`;
194
+ const output = parser.parse(input);
195
+ expect(output).toBe(`h(Canvas, { child: (x, y) => h(Sprite) })`);
196
+ });
197
+
198
+ test("should compile component with destructuring function (with params)", () => {
199
+ const input = `<Canvas child={({ x, y }) => <Sprite />} />`;
200
+ const output = parser.parse(input);
201
+ expect(output).toBe(`h(Canvas, { child: ({x, y}) => h(Sprite) })`);
202
+ });
203
+
204
+ test("should compile component with function returns component attribute and data", () => {
205
+ const input = `<Canvas child={() => <Text text="Hello" />} />`;
206
+ const output = parser.parse(input);
207
+ expect(output).toBe(`h(Canvas, { child: () => h(Text, { text: 'Hello' }) })`);
208
+ });
209
+
210
+ test("should compile component with function returns component attribute and child", () => {
211
+ const input = `<Canvas child={() => <Container>
212
+ <Text text="Hello" />
213
+ </Container>} />`;
214
+ const output = parser.parse(input);
215
+ expect(output).toBe(`h(Canvas, { child: () => h(Container, null, h(Text, { text: 'Hello' })) })`);
216
+ });
217
+
218
+ test("should compile component with function returns component attribute and children", () => {
219
+ const input = `<Canvas child={() => <Container>
220
+ <Text text="Hello 1" />
221
+ <Text text="Hello 2" />
222
+ </Container>} />`;
223
+ const output = parser.parse(input);
224
+ expect(output).toBe(`h(Canvas, { child: () => h(Container, null, [h(Text, { text: 'Hello 1' }), h(Text, { text: 'Hello 2' })]) })`);
225
+ });
185
226
  });
186
227
 
187
228
  describe("Loop", () => {
@@ -195,7 +236,7 @@ describe("Loop", () => {
195
236
  `;
196
237
  const output = parser.parse(input);
197
238
  expect(output.replace(/\s+/g, "")).toBe(
198
- `h(Canvas,null,loop(sprites,(sprite)=>h(Sprite)))`.replace(/\s+/g, "")
239
+ `h(Canvas,null,loop(sprites,sprite=>h(Sprite)))`.replace(/\s+/g, "")
199
240
  );
200
241
  });
201
242
 
@@ -207,7 +248,19 @@ describe("Loop", () => {
207
248
  `;
208
249
  const output = parser.parse(input);
209
250
  expect(output.replace(/\s+/g, "")).toBe(
210
- `loop(sprites,(sprite)=>h(Sprite))`.replace(/\s+/g, "")
251
+ `loop(sprites,sprite=>h(Sprite))`.replace(/\s+/g, "")
252
+ );
253
+ });
254
+
255
+ test("should compile loop with destructuring", () => {
256
+ const input = `
257
+ @for ((sprite, index) of sprites) {
258
+ <Sprite key={index} />
259
+ }
260
+ `;
261
+ const output = parser.parse(input);
262
+ expect(output.replace(/\s+/g, "")).toBe(
263
+ `loop(sprites,(sprite,index)=>h(Sprite, { key: index }))`.replace(/\s+/g, "")
211
264
  );
212
265
  });
213
266
 
@@ -221,7 +274,7 @@ describe("Loop", () => {
221
274
  `;
222
275
  const output = parser.parse(input);
223
276
  expect(output.replace(/\s+/g, "")).toBe(
224
- `loop(sprites,(sprite)=>loop(others,(other)=>h(Sprite)))`.replace(
277
+ `loop(sprites,sprite=>loop(others,other=>h(Sprite)))`.replace(
225
278
  /\s+/g,
226
279
  ""
227
280
  )
@@ -240,6 +293,16 @@ describe("Condition", () => {
240
293
  expect(output).toBe(`cond(sprite.visible, () => h(Sprite))`);
241
294
  });
242
295
 
296
+ test("should compile condition when function value", () => {
297
+ const input = `
298
+ @if (val()) {
299
+ <Sprite />
300
+ }
301
+ `;
302
+ const output = parser.parse(input);
303
+ expect(output).toBe(`cond(val(), () => h(Sprite))`);
304
+ });
305
+
243
306
  test("should compile condition for multiple sprites", () => {
244
307
  const input = `
245
308
  @if (sprite) {
@@ -314,7 +377,7 @@ describe("Condition in Loops", () => {
314
377
  `;
315
378
  const output = parser.parse(input);
316
379
  expect(output.replace(/\s+/g, "")).toBe(
317
- `h(Canvas,null,loop(sprites,(sprite)=>cond(sprite.visible,()=>h(Sprite))))`.replace(/\s+/g, "")
380
+ `h(Canvas,null,loop(sprites,sprite=>cond(sprite.visible,()=>h(Sprite))))`.replace(/\s+/g, "")
318
381
  );
319
382
  });
320
383
 
@@ -328,7 +391,7 @@ describe("Condition in Loops", () => {
328
391
  `;
329
392
  const output = parser.parse(input);
330
393
  expect(output.replace(/\s+/g, "")).toBe(
331
- `h(Canvas,null,loop(sprites,(sprite)=>h(Sprite)))`.replace(/\s+/g, "")
394
+ `h(Canvas,null,loop(sprites,sprite=>h(Sprite)))`.replace(/\s+/g, "")
332
395
  );
333
396
  });
334
397
 
@@ -345,7 +408,7 @@ describe("Condition in Loops", () => {
345
408
  `;
346
409
  const output = parser.parse(input);
347
410
  expect(output.replace(/\s+/g, "")).toBe(
348
- `h(Canvas,null,[loop(sprites,(sprite)=>h(Sprite)),loop(others,(other)=>h(Sprite))])`.replace(/\s+/g, "")
411
+ `h(Canvas,null,[loop(sprites,sprite=>h(Sprite)),loop(others,other=>h(Sprite))])`.replace(/\s+/g, "")
349
412
  );
350
413
  });
351
414