rip-lang 3.13.28 → 3.13.30

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.
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rip-lang",
3
- "version": "3.13.28",
3
+ "version": "3.13.30",
4
4
  "description": "A modern language that compiles to JavaScript",
5
5
  "type": "module",
6
6
  "main": "src/compiler.js",
package/src/components.js CHANGED
@@ -433,7 +433,7 @@ export function installComponentSupport(CodeGenerator, Lexer) {
433
433
  isTemplateElement = true;
434
434
  } else if (tag === 'IDENTIFIER' && !isAfterControlFlow) {
435
435
  isTemplateElement = startsWithTag(tokens, i);
436
- } else if (tag === 'PROPERTY' || tag === 'STRING' || tag === 'STRING_END' || tag === 'NUMBER' || tag === 'BOOL' || tag === 'CALL_END' || tag === ')') {
436
+ } else if (tag === 'PROPERTY' || tag === 'STRING' || tag === 'STRING_END' || tag === 'NUMBER' || tag === 'BOOL' || tag === 'CALL_END' || tag === ')' || tag === 'PRESENCE') {
437
437
  isTemplateElement = startsWithTag(tokens, i);
438
438
  }
439
439
 
@@ -664,11 +664,21 @@ export function installComponentSupport(CodeGenerator, Lexer) {
664
664
  }
665
665
  }
666
666
 
667
+ // Auto-event map: onClick → 'click', onKeydown → 'keydown', etc.
668
+ const autoEventHandlers = new Map();
669
+ for (const { name } of methods) {
670
+ if (/^on[A-Z]/.test(name) && !LIFECYCLE_HOOKS.has(name)) {
671
+ autoEventHandlers.set(name[2].toLowerCase() + name.slice(3), name);
672
+ }
673
+ }
674
+
667
675
  // Save and set component context
668
676
  const prevComponentMembers = this.componentMembers;
669
677
  const prevReactiveMembers = this.reactiveMembers;
678
+ const prevAutoEventHandlers = this._autoEventHandlers;
670
679
  this.componentMembers = memberNames;
671
680
  this.reactiveMembers = reactiveMembers;
681
+ this._autoEventHandlers = autoEventHandlers.size > 0 ? autoEventHandlers : null;
672
682
 
673
683
  const lines = [];
674
684
  let blockFactoriesCode = '';
@@ -776,6 +786,7 @@ export function installComponentSupport(CodeGenerator, Lexer) {
776
786
  // Restore context
777
787
  this.componentMembers = prevComponentMembers;
778
788
  this.reactiveMembers = prevReactiveMembers;
789
+ this._autoEventHandlers = prevAutoEventHandlers;
779
790
 
780
791
  // If block factories exist, wrap in IIFE so they're in scope
781
792
  if (blockFactoriesCode) {
@@ -828,6 +839,9 @@ export function installComponentSupport(CodeGenerator, Lexer) {
828
839
  this._factoryMode = false;
829
840
  this._factoryVars = null;
830
841
  this._fragChildren = new Map();
842
+ this._pendingAutoWire = false;
843
+ this._autoWireEl = null;
844
+ this._autoWireExplicit = null;
831
845
 
832
846
  const statements = this.is(body, 'block') ? body.slice(1) : [body];
833
847
 
@@ -835,7 +849,9 @@ export function installComponentSupport(CodeGenerator, Lexer) {
835
849
  if (statements.length === 0) {
836
850
  rootVar = 'null';
837
851
  } else if (statements.length === 1) {
852
+ this._pendingAutoWire = !!this._autoEventHandlers;
838
853
  rootVar = this.generateNode(statements[0]);
854
+ this._pendingAutoWire = false;
839
855
  } else {
840
856
  rootVar = this.newElementVar('frag');
841
857
  this._createLines.push(`${rootVar} = document.createDocumentFragment();`);
@@ -1048,8 +1064,8 @@ export function installComponentSupport(CodeGenerator, Lexer) {
1048
1064
  else if (typeof arg === 'string' || arg instanceof String) {
1049
1065
  const val = arg.valueOf();
1050
1066
  // Template tag appearing as a string arg (e.g., slot after multi-line attrs)
1051
- const [tagPart, idPart] = val.split('#');
1052
- if (this.isHtmlTag(tagPart || 'div') || this.isComponent(val)) {
1067
+ const baseName = val.split(/[#.]/)[0];
1068
+ if (this.isHtmlTag(baseName || 'div') || this.isComponent(baseName)) {
1053
1069
  const childVar = this.generateNode(arg);
1054
1070
  this._createLines.push(`${elVar}.appendChild(${childVar});`);
1055
1071
  } else {
@@ -1074,6 +1090,29 @@ export function installComponentSupport(CodeGenerator, Lexer) {
1074
1090
  }
1075
1091
  };
1076
1092
 
1093
+ // --------------------------------------------------------------------------
1094
+ // Auto-wire event handlers — claim/emit helpers for on* convention
1095
+ // --------------------------------------------------------------------------
1096
+
1097
+ proto._claimAutoWire = function(elVar) {
1098
+ if (!this._pendingAutoWire || !this._autoEventHandlers?.size) return false;
1099
+ this._pendingAutoWire = false;
1100
+ this._autoWireEl = elVar;
1101
+ this._autoWireExplicit = new Set();
1102
+ return true;
1103
+ };
1104
+
1105
+ proto._emitAutoWire = function(elVar, claimed) {
1106
+ if (!claimed) return;
1107
+ for (const [eventName, methodName] of this._autoEventHandlers) {
1108
+ if (!this._autoWireExplicit.has(eventName)) {
1109
+ this._createLines.push(`${elVar}.addEventListener('${eventName}', (e) => __batch(() => ${this._self}.${methodName}(e)));`);
1110
+ }
1111
+ }
1112
+ this._autoWireEl = null;
1113
+ this._autoWireExplicit = null;
1114
+ };
1115
+
1077
1116
  // --------------------------------------------------------------------------
1078
1117
  // generateTag — HTML element with static classes and children
1079
1118
  // --------------------------------------------------------------------------
@@ -1091,6 +1130,8 @@ export function installComponentSupport(CodeGenerator, Lexer) {
1091
1130
  this._createLines.push(`${elVar}.id = '${id}';`);
1092
1131
  }
1093
1132
 
1133
+ const autoWireClaimed = this._claimAutoWire(elVar);
1134
+
1094
1135
  // Defer class emission when selector classes exist so class: attributes merge
1095
1136
  const prevClassArgs = this._pendingClassArgs;
1096
1137
  const prevClassEl = this._pendingClassEl;
@@ -1123,6 +1164,8 @@ export function installComponentSupport(CodeGenerator, Lexer) {
1123
1164
  this._pendingClassEl = prevClassEl;
1124
1165
  }
1125
1166
 
1167
+ this._emitAutoWire(elVar, autoWireClaimed);
1168
+
1126
1169
  return elVar;
1127
1170
  };
1128
1171
 
@@ -1138,6 +1181,8 @@ export function installComponentSupport(CodeGenerator, Lexer) {
1138
1181
  this._createLines.push(`${elVar} = document.createElement('${tag}');`);
1139
1182
  }
1140
1183
 
1184
+ const autoWireClaimed = this._claimAutoWire(elVar);
1185
+
1141
1186
  // Defer className emission so class: attributes can merge with .() classes
1142
1187
  const classArgs = classExprs.map(e => this.generateInComponent(e, 'value'));
1143
1188
  const prevClassArgs = this._pendingClassArgs;
@@ -1161,6 +1206,8 @@ export function installComponentSupport(CodeGenerator, Lexer) {
1161
1206
  this._pendingClassArgs = prevClassArgs;
1162
1207
  this._pendingClassEl = prevClassEl;
1163
1208
 
1209
+ this._emitAutoWire(elVar, autoWireClaimed);
1210
+
1164
1211
  return elVar;
1165
1212
  };
1166
1213
 
@@ -1177,6 +1224,9 @@ export function installComponentSupport(CodeGenerator, Lexer) {
1177
1224
  // Event handler: @click or (. this eventName)
1178
1225
  if (this.is(key, '.') && key[1] === 'this') {
1179
1226
  const eventName = key[2];
1227
+ if (this._autoWireExplicit && this._autoWireEl === elVar) {
1228
+ this._autoWireExplicit.add(eventName);
1229
+ }
1180
1230
  if (typeof value === 'string' && this.componentMembers?.has(value)) {
1181
1231
  this._createLines.push(`${elVar}.addEventListener('${eventName}', (e) => __batch(() => ${this._self}.${value}(e)));`);
1182
1232
  } else {
@@ -1330,6 +1380,7 @@ export function installComponentSupport(CodeGenerator, Lexer) {
1330
1380
  // --------------------------------------------------------------------------
1331
1381
 
1332
1382
  proto.generateConditional = function(sexpr) {
1383
+ this._pendingAutoWire = false;
1333
1384
  const [, condition, thenBlock, elseBlock] = sexpr;
1334
1385
 
1335
1386
  const anchorVar = this.newElementVar('anchor');
@@ -1496,6 +1547,7 @@ export function installComponentSupport(CodeGenerator, Lexer) {
1496
1547
  // --------------------------------------------------------------------------
1497
1548
 
1498
1549
  proto.generateTemplateLoop = function(sexpr) {
1550
+ this._pendingAutoWire = false;
1499
1551
  const [head, vars, collection, guard, step, body] = sexpr;
1500
1552
 
1501
1553
  const blockName = this.newBlockVar();
@@ -1581,6 +1633,7 @@ export function installComponentSupport(CodeGenerator, Lexer) {
1581
1633
  // --------------------------------------------------------------------------
1582
1634
 
1583
1635
  proto.generateChildComponent = function(componentName, args) {
1636
+ this._pendingAutoWire = false;
1584
1637
  const instVar = this.newElementVar('inst');
1585
1638
  const elVar = this.newElementVar('el');
1586
1639
  const { propsCode, reactiveProps, childrenSetupLines } = this.buildComponentProps(args);