@xaendar/compiler 0.6.17 → 0.6.18

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.
@@ -38,6 +38,10 @@ var LexerState = /* @__PURE__ */ function(LexerState) {
38
38
  */
39
39
  LexerState["EVENT"] = "event";
40
40
  /**
41
+ * Consuming a DOM event parameter
42
+ */
43
+ LexerState["EVENT_PARAMETER"] = "parameter";
44
+ /**
41
45
  * Dispatching a flow-control keyword (@if, @for, @switch, etc.).
42
46
  */
43
47
  LexerState["FLOW_CONTROL"] = "flow-control";
@@ -111,57 +115,61 @@ var TokenType = /* @__PURE__ */ function(TokenType) {
111
115
  */
112
116
  TokenType[TokenType["EVENT"] = 7] = "EVENT";
113
117
  /**
118
+ * An event paremeter included in a event call '()'
119
+ */
120
+ TokenType[TokenType["EVENT_PAREMETER"] = 8] = "EVENT_PAREMETER";
121
+ /**
114
122
  * A template-literal interpolation string enclosed in `` {`...`} ``.
115
123
  */
116
- TokenType[TokenType["INTERPOLATION_LITERAL"] = 8] = "INTERPOLATION_LITERAL";
124
+ TokenType[TokenType["INTERPOLATION_LITERAL"] = 9] = "INTERPOLATION_LITERAL";
117
125
  /**
118
126
  * A JavaScript expression interpolation enclosed in `{ }`.
119
127
  */
120
- TokenType[TokenType["INTERPOLATION_EXPRESSION"] = 9] = "INTERPOLATION_EXPRESSION";
128
+ TokenType[TokenType["INTERPOLATION_EXPRESSION"] = 10] = "INTERPOLATION_EXPRESSION";
121
129
  /**
122
130
  * Opening keyword of an `@if` directive.
123
131
  */
124
- TokenType[TokenType["IF"] = 10] = "IF";
132
+ TokenType[TokenType["IF"] = 11] = "IF";
125
133
  /**
126
134
  * Opening keyword of a `@for` directive.
127
135
  */
128
- TokenType[TokenType["FOR"] = 11] = "FOR";
136
+ TokenType[TokenType["FOR"] = 12] = "FOR";
129
137
  /**
130
138
  * Opening keyword of an `@else` branch.
131
139
  */
132
- TokenType[TokenType["ELSE"] = 12] = "ELSE";
140
+ TokenType[TokenType["ELSE"] = 13] = "ELSE";
133
141
  /**
134
142
  * Opening keyword of an `@else if` branch.
135
143
  */
136
- TokenType[TokenType["ELSE_IF"] = 13] = "ELSE_IF";
144
+ TokenType[TokenType["ELSE_IF"] = 14] = "ELSE_IF";
137
145
  /**
138
146
  * Opening keyword of a `@switch` directive.
139
147
  */
140
- TokenType[TokenType["SWITCH"] = 14] = "SWITCH";
148
+ TokenType[TokenType["SWITCH"] = 15] = "SWITCH";
141
149
  /**
142
150
  * Opening keyword of a `@case` branch.
143
151
  */
144
- TokenType[TokenType["CASE"] = 15] = "CASE";
152
+ TokenType[TokenType["CASE"] = 16] = "CASE";
145
153
  /**
146
154
  * Opening keyword of a `@default` branch.
147
155
  */
148
- TokenType[TokenType["DEFAULT"] = 16] = "DEFAULT";
156
+ TokenType[TokenType["DEFAULT"] = 17] = "DEFAULT";
149
157
  /**
150
158
  * The condition expression `(...)` associated with a flow-control directive.
151
159
  */
152
- TokenType[TokenType["CONDITION"] = 17] = "CONDITION";
160
+ TokenType[TokenType["CONDITION"] = 18] = "CONDITION";
153
161
  /**
154
162
  * The opening `{` of a flow-control block body.
155
163
  */
156
- TokenType[TokenType["BLOCK_OPEN"] = 18] = "BLOCK_OPEN";
164
+ TokenType[TokenType["BLOCK_OPEN"] = 19] = "BLOCK_OPEN";
157
165
  /**
158
166
  * The closing `}` of a flow-control block body.
159
167
  */
160
- TokenType[TokenType["BLOCK_CLOSE"] = 19] = "BLOCK_CLOSE";
168
+ TokenType[TokenType["BLOCK_CLOSE"] = 20] = "BLOCK_CLOSE";
161
169
  /**
162
170
  * Sentinel token emitted when the end of the input is reached.
163
171
  */
164
- TokenType[TokenType["EOF"] = 20] = "EOF";
172
+ TokenType[TokenType["EOF"] = 21] = "EOF";
165
173
  return TokenType;
166
174
  }({});
167
175
  //#endregion
@@ -270,7 +278,7 @@ function consumeFlowControlCondition(cursor, _context) {
270
278
  while (depth > 0) switch (cursor.peek()) {
271
279
  case 40:
272
280
  depth++;
273
- expression = addCharacter$2(cursor, expression);
281
+ expression = addCharacter$3(cursor, expression);
274
282
  break;
275
283
  case 41:
276
284
  depth--;
@@ -278,9 +286,9 @@ function consumeFlowControlCondition(cursor, _context) {
278
286
  cursor.advance();
279
287
  break;
280
288
  }
281
- expression = addCharacter$2(cursor, expression);
289
+ expression = addCharacter$3(cursor, expression);
282
290
  break;
283
- default: expression = addCharacter$2(cursor, expression);
291
+ default: expression = addCharacter$3(cursor, expression);
284
292
  }
285
293
  return expression;
286
294
  }
@@ -291,7 +299,7 @@ function consumeFlowControlCondition(cursor, _context) {
291
299
  * @param expression - The current accumulated expression string.
292
300
  * @returns The updated string with the newly consumed character appended.
293
301
  */
294
- function addCharacter$2(cursor, expression) {
302
+ function addCharacter$3(cursor, expression) {
295
303
  cursor.advance();
296
304
  return `${expression}${cursor.currentChar.value}`;
297
305
  }
@@ -340,6 +348,57 @@ function consumeDefaultFlowControlCondition(cursor, _context) {
340
348
  };
341
349
  }
342
350
  //#endregion
351
+ //#region ../packages/compiler/src/lexer/states/event-parameter.state.ts
352
+ /**
353
+ * Consumes an event parameter and reads until a ',' or ')'.
354
+ * Emits an EVENT_ATTRIBUTE token containing the raw paremeter string.
355
+ *
356
+ * @param cursor - The lexer cursor positioned on the `@` character.
357
+ * @param _context - Unused lexer context.
358
+ * @returns Transition result with the EVENT_PAREMETER token and the EVENT state.
359
+ */
360
+ function consumeEventParameter(cursor, _context) {
361
+ let read = true;
362
+ let eventParameter = "";
363
+ let charDelimiter = "";
364
+ const retVal = {
365
+ state: LexerState.TAG_BODY,
366
+ tokens: []
367
+ };
368
+ cursor.advance();
369
+ cursor.skipSpaces();
370
+ while (read) switch (cursor.peek()) {
371
+ case 91:
372
+ case 123:
373
+ case 34:
374
+ case 39:
375
+ case 40:
376
+ eventParameter = addCharacter$2(cursor, eventParameter);
377
+ if (!charDelimiter) charDelimiter = cursor.currentChar.value;
378
+ else if (charDelimiter === cursor.currentChar.value) charDelimiter = "";
379
+ break;
380
+ case 44:
381
+ if (!charDelimiter) {
382
+ retVal.tokens.push({
383
+ type: TokenType.EVENT_PAREMETER,
384
+ parts: [eventParameter]
385
+ });
386
+ cursor.advance();
387
+ eventParameter = "";
388
+ } else eventParameter = addCharacter$2(cursor, eventParameter);
389
+ break;
390
+ case 41:
391
+ cursor.advance();
392
+ read = false;
393
+ default: eventParameter = addCharacter$2(cursor, eventParameter);
394
+ }
395
+ return retVal;
396
+ }
397
+ function addCharacter$2(cursor, eventParameter) {
398
+ cursor.advance();
399
+ return `${eventParameter}${cursor.currentChar.value}`;
400
+ }
401
+ //#endregion
343
402
  //#region ../packages/compiler/src/lexer/states/event.state.ts
344
403
  /**
345
404
  * Consumes a DOM event binding starting with `@` and reads until a delimiter
@@ -353,34 +412,31 @@ function consumeEvent(cursor, _context) {
353
412
  let read = true;
354
413
  let event = "";
355
414
  let retVal;
356
- let deep = 0;
357
415
  cursor.advance();
358
416
  while (read) switch (cursor.peek()) {
359
417
  case 32:
360
418
  case 47:
361
419
  case 62:
362
- if (deep === 0) {
363
- retVal = {
364
- state: LexerState.TAG_BODY,
365
- tokens: [{
366
- type: TokenType.EVENT,
367
- parts: [event]
368
- }]
369
- };
370
- read = false;
371
- }
420
+ retVal = { state: LexerState.TAG_BODY };
421
+ read = false;
372
422
  break;
373
423
  case 40:
374
- deep++;
375
- cursor.advance();
424
+ case 44:
425
+ retVal = {
426
+ state: LexerState.EVENT_PARAMETER,
427
+ tokens: [{
428
+ type: TokenType.EVENT,
429
+ parts: [event]
430
+ }]
431
+ };
432
+ read = false;
376
433
  break;
377
434
  case 41:
378
- deep--;
379
- cursor.advance();
435
+ retVal = { state: LexerState.TAG_BODY };
380
436
  break;
381
437
  default:
382
438
  cursor.advance();
383
- if (deep === 0) event = `${event}${cursor.currentChar.value}`;
439
+ event = `${event}${cursor.currentChar.value}`;
384
440
  }
385
441
  return retVal;
386
442
  }
@@ -1025,11 +1081,12 @@ var Lexer = class {
1025
1081
  [LexerState.TAG_CLOSE]: consumeTagClose,
1026
1082
  [LexerState.ATTRIBUTE]: consumeAttribute,
1027
1083
  [LexerState.ATTRIBUTE_VALUE]: consumeAttributeValue,
1084
+ [LexerState.EVENT]: consumeEvent,
1085
+ [LexerState.EVENT_PARAMETER]: consumeEventParameter,
1028
1086
  [LexerState.FLOW_CONTROL]: consumeFlowControl,
1029
1087
  [LexerState.FLOW_CONTROL_CONDITION]: consumeDefaultFlowControlCondition,
1030
1088
  [LexerState.CASE_FLOW_CONTROL_CONDITION]: consumeCaseFlowControlCondition,
1031
1089
  [LexerState.FLOW_CONTROL_BLOCK]: consumeFlowControlBlock,
1032
- [LexerState.EVENT]: consumeEvent,
1033
1090
  [LexerState.INTERPOLATION]: consumeInterpolation,
1034
1091
  [LexerState.INTERPOLATION_EXPRESSION]: consumeInterpolationExpression,
1035
1092
  [LexerState.INTERPOLATION_LITERAL]: consumeInterpolationliteral
@@ -1100,7 +1157,7 @@ var ParserCursor = class {
1100
1157
  /**
1101
1158
  * Returns a read-only snapshot of the current token.
1102
1159
  */
1103
- get currentToken() {
1160
+ getCcurrentToken() {
1104
1161
  return this._currentToken;
1105
1162
  }
1106
1163
  /**
@@ -1435,9 +1492,15 @@ function parseEvent(cursor, _parseNode, token) {
1435
1492
  const raw = token.parts[0];
1436
1493
  const [name, value] = raw.split("=");
1437
1494
  if (!name || !value) throw new Error(`[Parser] Invalid event format: ${raw}`);
1495
+ const parameters = new Array();
1496
+ while (cursor.peek().type === TokenType.EVENT_PAREMETER) {
1497
+ cursor.advance();
1498
+ parameters.push(validateExpression(cursor.getCcurrentToken().value.parts[0]).node);
1499
+ }
1438
1500
  return {
1439
1501
  name,
1440
- handler: value.replace(/^[""]|[""]$/g, "")
1502
+ handler: value.replace(/^[""]|[""]$/g, ""),
1503
+ parameters
1441
1504
  };
1442
1505
  }
1443
1506
  //#endregion
@@ -1600,7 +1663,7 @@ function parseForExpression(source, baseOffset) {
1600
1663
  function parseImplicitAliases(source, baseOffset, out) {
1601
1664
  const entries = source.split(",");
1602
1665
  let cursor = 0;
1603
- const IMPLICIT_VARIABLES = new Set([
1666
+ const IMPLICIT_VARIABLES = /* @__PURE__ */ new Set([
1604
1667
  "$index",
1605
1668
  "$last",
1606
1669
  "$first",
@@ -1898,6 +1961,9 @@ var CompilerContext = class {
1898
1961
  if (this.hasIdentifier(name)) throw new Error(`Identifier "${name}" is already declared in this scope.`);
1899
1962
  this._identifiers.push(name);
1900
1963
  }
1964
+ removeIdentifier(name) {
1965
+ this._identifiers = this._identifiers.filter((identifier) => identifier !== name);
1966
+ }
1901
1967
  /**
1902
1968
  * Returns `true` if an identifier with the given name is declared in this
1903
1969
  * scope or any of its ancestor scopes.
@@ -1926,7 +1992,7 @@ var CompilerContext = class {
1926
1992
  *
1927
1993
  * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects
1928
1994
  */
1929
- var GLOBAL_IDENTIFIERS = new Set([
1995
+ var GLOBAL_IDENTIFIERS = /* @__PURE__ */ new Set([
1930
1996
  "undefined",
1931
1997
  "NaN",
1932
1998
  "Infinity",
@@ -2220,7 +2286,7 @@ function getBlockIdentifier(parentNode, index, prefix) {
2220
2286
  */
2221
2287
  function processElement(node, nodeName, parentNode, compilerContext) {
2222
2288
  const attributes = mapAttributes(node.attributes, compilerContext);
2223
- const events = mapEvents(node.events);
2289
+ const events = mapEvents(node.events, compilerContext);
2224
2290
  const code = [`const ${nodeName} = _renderElement(${parentNode}, context, '${node.tagName}',`];
2225
2291
  attributes.length ? code.push(...indent([
2226
2292
  "[",
@@ -2255,10 +2321,27 @@ function mapAttributes(attributes, compilerContext) {
2255
2321
  * to the component instance handler and exposing the native event as `$event`.
2256
2322
  *
2257
2323
  * @param events - The event nodes to bind to the element.
2324
+ * @param compilerContext - Current render scope context, used to resolve identifier references.
2258
2325
  * @returns Array of generated code lines, one per event listener.
2259
2326
  */
2260
- function mapEvents(events) {
2261
- return events?.map((event) => `{ name: '${event.name}', handler: '${event.handler}' }`);
2327
+ function mapEvents(events, compilerContext) {
2328
+ compilerContext.addIdentifier("$event");
2329
+ const mappedEvents = events?.map((event) => {
2330
+ const parameters = event.parameters.map((parameter) => `() => ${resolveExpression(parameter, compilerContext)},`);
2331
+ return [
2332
+ "{",
2333
+ ...indent([
2334
+ `name: '${event.name}',`,
2335
+ `handler: '${event.handler}',`,
2336
+ "parameters: [",
2337
+ ...indent(parameters),
2338
+ "]"
2339
+ ]),
2340
+ "}"
2341
+ ];
2342
+ }).flat();
2343
+ compilerContext.removeIdentifier("$event");
2344
+ return mappedEvents;
2262
2345
  }
2263
2346
  //#endregion
2264
2347
  //#region ../packages/compiler/src/render-generator/states/process-for.state.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xaendar/compiler",
3
- "version": "0.6.17",
3
+ "version": "0.6.18",
4
4
  "description": "A library for transpiling Xaendar Templates into JavaScript code",
5
5
  "sideEffects": false,
6
6
  "type": "module",
@@ -16,8 +16,8 @@
16
16
  }
17
17
  },
18
18
  "dependencies": {
19
- "@xaendar/common": "0.6.17",
20
- "@xaendar/types": "0.6.17",
19
+ "@xaendar/common": "0.6.18",
20
+ "@xaendar/types": "0.6.18",
21
21
  "typescript": "^6.0.3"
22
22
  }
23
23
  }