@hyperfixi/vite-plugin 2.3.1 → 2.5.0

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/dist/index.cjs CHANGED
@@ -70,6 +70,8 @@ var SUPPORTED_LANGUAGES = [
70
70
  // East Asian
71
71
  "ar",
72
72
  // RTL (Arabic script)
73
+ "he",
74
+ // RTL (Hebrew script)
73
75
  "hi",
74
76
  "bn",
75
77
  // South Asian (Indic scripts)
@@ -78,6 +80,8 @@ var SUPPORTED_LANGUAGES = [
78
80
  "tr",
79
81
  // Agglutinative Latin
80
82
  "id",
83
+ "ms",
84
+ // Malay (Latin script, closely related to id)
81
85
  "sw",
82
86
  "qu",
83
87
  // Other
@@ -125,7 +129,6 @@ var JAPANESE_KEYWORDS = /* @__PURE__ */ new Set([
125
129
  "\u975E\u8868\u793A\u306B\u3059\u308B",
126
130
  "\u8A2D\u5B9A",
127
131
  "\u8A2D\u5B9A\u3059\u308B",
128
- "\u30BB\u30C3\u30C8",
129
132
  "\u5897\u52A0",
130
133
  "\u5897\u3084\u3059",
131
134
  "\u30A4\u30F3\u30AF\u30EA\u30E1\u30F3\u30C8",
@@ -138,7 +141,6 @@ var JAPANESE_KEYWORDS = /* @__PURE__ */ new Set([
138
141
  "\u9001\u308B",
139
142
  "\u9001\u4FE1",
140
143
  "\u3082\u3057",
141
- "\u6761\u4EF6",
142
144
  "\u305D\u3046\u3067\u306A\u3051\u308C\u3070",
143
145
  "\u305D\u308C\u4EE5\u5916",
144
146
  "\u7E70\u308A\u8FD4\u3057",
@@ -151,7 +153,6 @@ var JAPANESE_KEYWORDS = /* @__PURE__ */ new Set([
151
153
  ]);
152
154
  var KOREAN_KEYWORDS = /* @__PURE__ */ new Set([
153
155
  "\uD1A0\uAE00",
154
- "\uC804\uD658",
155
156
  "\uCD94\uAC00",
156
157
  "\uC81C\uAC70",
157
158
  "\uC0AD\uC81C",
@@ -191,16 +192,15 @@ var CHINESE_KEYWORDS = /* @__PURE__ */ new Set([
191
192
  "\u5426\u5219",
192
193
  "\u91CD\u590D",
193
194
  "\u7B49\u5F85",
194
- "\u5F53"
195
+ "\u6301\u7EED"
195
196
  ]);
196
197
  var ARABIC_KEYWORDS = /* @__PURE__ */ new Set([
197
- "\u0628\u062F\u0644",
198
198
  "\u0628\u062F\u0651\u0644",
199
+ "\u0628\u062F\u0644",
199
200
  "\u063A\u064A\u0651\u0631",
200
201
  "\u063A\u064A\u0631",
201
202
  "\u0623\u0636\u0641",
202
203
  "\u0627\u0636\u0641",
203
- "\u0632\u0650\u062F",
204
204
  "\u0627\u062D\u0630\u0641",
205
205
  "\u0623\u0632\u0644",
206
206
  "\u0627\u0645\u0633\u062D",
@@ -210,11 +210,15 @@ var ARABIC_KEYWORDS = /* @__PURE__ */ new Set([
210
210
  "\u0627\u062E\u0641",
211
211
  "\u0623\u062E\u0641\u0650",
212
212
  "\u0627\u062E\u0641\u064A",
213
+ "\u0623\u062E\u0641",
213
214
  "\u0627\u0636\u0628\u0637",
214
215
  "\u0639\u064A\u0651\u0646",
215
216
  "\u062D\u062F\u062F",
217
+ "\u0632\u0650\u062F",
218
+ "\u0632\u062F",
216
219
  "\u0627\u0631\u0641\u0639",
217
220
  "\u0623\u0646\u0642\u0635",
221
+ "\u0627\u0646\u0642\u0635",
218
222
  "\u0642\u0644\u0644",
219
223
  "\u062A\u0634\u063A\u064A\u0644",
220
224
  "\u0623\u0637\u0644\u0642",
@@ -227,9 +231,37 @@ var ARABIC_KEYWORDS = /* @__PURE__ */ new Set([
227
231
  "\u0627\u0646\u062A\u0638\u0631",
228
232
  "\u0628\u064A\u0646\u0645\u0627"
229
233
  ]);
234
+ var HE_KEYWORDS = /* @__PURE__ */ new Set([
235
+ "\u05DE\u05EA\u05D2",
236
+ "\u05D4\u05D3\u05DC\u05E7 \u05DB\u05D1\u05D4",
237
+ "\u05D4\u05D5\u05E1\u05E3",
238
+ "\u05D4\u05E1\u05E8",
239
+ "\u05DE\u05D7\u05E7",
240
+ "\u05D4\u05D5\u05E8\u05D3",
241
+ "\u05D4\u05E8\u05D0\u05D4",
242
+ "\u05D4\u05E6\u05D2",
243
+ "\u05D4\u05E1\u05EA\u05E8",
244
+ "\u05D4\u05D7\u05D1\u05D0",
245
+ "\u05E7\u05D1\u05E2",
246
+ "\u05D4\u05D2\u05D3\u05E8",
247
+ "\u05D4\u05D2\u05D3\u05DC",
248
+ "\u05D4\u05D5\u05E1\u05E3 \u05D0\u05D7\u05D3",
249
+ "\u05D4\u05E7\u05D8\u05DF",
250
+ "\u05D4\u05E4\u05D7\u05EA",
251
+ "\u05D4\u05E4\u05E2\u05DC",
252
+ "\u05E9\u05D2\u05E8",
253
+ "\u05E9\u05DC\u05D7",
254
+ "\u05D0\u05DD",
255
+ "\u05D0\u05D7\u05E8\u05EA",
256
+ "\u05D0\u05DD \u05DC\u05D0",
257
+ "\u05D7\u05D6\u05D5\u05E8",
258
+ "\u05D7\u05DB\u05D4",
259
+ "\u05D4\u05DE\u05EA\u05DF",
260
+ "\u05DB\u05DC \u05E2\u05D5\u05D3",
261
+ "\u05D1\u05D6\u05DE\u05DF"
262
+ ]);
230
263
  var SPANISH_KEYWORDS = /* @__PURE__ */ new Set([
231
264
  "alternar",
232
- "cambiar",
233
265
  "conmutar",
234
266
  "agregar",
235
267
  "a\xF1adir",
@@ -237,6 +269,7 @@ var SPANISH_KEYWORDS = /* @__PURE__ */ new Set([
237
269
  "eliminar",
238
270
  "remover",
239
271
  "sacar",
272
+ "borrar",
240
273
  "mostrar",
241
274
  "ense\xF1ar",
242
275
  "ocultar",
@@ -256,11 +289,16 @@ var SPANISH_KEYWORDS = /* @__PURE__ */ new Set([
256
289
  "de lo contrario",
257
290
  "repetir",
258
291
  "esperar",
259
- "mientras"
292
+ "mientras",
293
+ "primero",
294
+ "primera",
295
+ "\xFAltimo",
296
+ "ultima",
297
+ "siguiente",
298
+ "anterior"
260
299
  ]);
261
300
  var PORTUGUESE_KEYWORDS = /* @__PURE__ */ new Set([
262
301
  "alternar",
263
- "trocar",
264
302
  "adicionar",
265
303
  "acrescentar",
266
304
  "remover",
@@ -288,7 +326,6 @@ var PORTUGUESE_KEYWORDS = /* @__PURE__ */ new Set([
288
326
  ]);
289
327
  var FRENCH_KEYWORDS = /* @__PURE__ */ new Set([
290
328
  "basculer",
291
- "permuter",
292
329
  "alterner",
293
330
  "ajouter",
294
331
  "supprimer",
@@ -330,8 +367,8 @@ var GERMAN_KEYWORDS = /* @__PURE__ */ new Set([
330
367
  "ausl\xF6sen",
331
368
  "senden",
332
369
  "schicken",
333
- "wenn",
334
370
  "falls",
371
+ "sofern",
335
372
  "sonst",
336
373
  "ansonsten",
337
374
  "wiederholen",
@@ -348,7 +385,6 @@ var TURKISH_KEYWORDS = /* @__PURE__ */ new Set([
348
385
  "g\xF6ster",
349
386
  "gizle",
350
387
  "ayarla",
351
- "yap",
352
388
  "belirle",
353
389
  "art\u0131r",
354
390
  "azalt",
@@ -358,12 +394,10 @@ var TURKISH_KEYWORDS = /* @__PURE__ */ new Set([
358
394
  "yoksa",
359
395
  "tekrarla",
360
396
  "bekle",
361
- "iken"
397
+ "s\xFCresince"
362
398
  ]);
363
399
  var INDONESIAN_KEYWORDS = /* @__PURE__ */ new Set([
364
400
  "alihkan",
365
- "ganti",
366
- "tukar",
367
401
  "tambah",
368
402
  "tambahkan",
369
403
  "hapus",
@@ -391,11 +425,33 @@ var INDONESIAN_KEYWORDS = /* @__PURE__ */ new Set([
391
425
  "tunggu",
392
426
  "selama"
393
427
  ]);
428
+ var MS_KEYWORDS = /* @__PURE__ */ new Set([
429
+ "togol",
430
+ "tukar",
431
+ "tambah",
432
+ "buang",
433
+ "padam",
434
+ "tunjuk",
435
+ "sembunyi",
436
+ "sorok",
437
+ "tetapkan",
438
+ "setkan",
439
+ "tambah_satu",
440
+ "kurang_satu",
441
+ "cetuskan",
442
+ "hantar",
443
+ "jika",
444
+ "kalau",
445
+ "kalau_tidak",
446
+ "jika_tidak",
447
+ "ulang",
448
+ "tunggu",
449
+ "selagi",
450
+ "semasa"
451
+ ]);
394
452
  var SWAHILI_KEYWORDS = /* @__PURE__ */ new Set([
395
453
  "badilisha",
396
- "geuza",
397
454
  "ongeza",
398
- "weka",
399
455
  "ondoa",
400
456
  "futa",
401
457
  "toa",
@@ -403,9 +459,9 @@ var SWAHILI_KEYWORDS = /* @__PURE__ */ new Set([
403
459
  "ficha",
404
460
  "mficho",
405
461
  "seti",
462
+ "ongezeko",
406
463
  "punguza",
407
464
  "chochea",
408
- "anzisha",
409
465
  "tuma",
410
466
  "peleka",
411
467
  "kama",
@@ -415,12 +471,11 @@ var SWAHILI_KEYWORDS = /* @__PURE__ */ new Set([
415
471
  "rudia",
416
472
  "subiri",
417
473
  "ngoja",
418
- "wakati"
474
+ "kadri"
419
475
  ]);
420
476
  var QUECHUA_KEYWORDS = /* @__PURE__ */ new Set([
421
477
  "t",
422
478
  "tikray",
423
- "kutichiy",
424
479
  "yapay",
425
480
  "yapaykuy",
426
481
  "qichuy",
@@ -430,11 +485,12 @@ var QUECHUA_KEYWORDS = /* @__PURE__ */ new Set([
430
485
  "qawachiy",
431
486
  "pakay",
432
487
  "pakakuy",
433
- "churay",
488
+ "churanay",
434
489
  "kamaykuy",
435
490
  "yapachiy",
436
491
  "pisiyachiy",
437
- "qallarichiy",
492
+ "kuyuchiy",
493
+ "kichay",
438
494
  "kachay",
439
495
  "apachiy",
440
496
  "sichus",
@@ -448,7 +504,6 @@ var QUECHUA_KEYWORDS = /* @__PURE__ */ new Set([
448
504
  var ITALIAN_KEYWORDS = /* @__PURE__ */ new Set([
449
505
  "commutare",
450
506
  "alternare",
451
- "cambiare",
452
507
  "aggiungere",
453
508
  "aggiungi",
454
509
  "rimuovere",
@@ -490,7 +545,6 @@ var VIETNAMESE_KEYWORDS = /* @__PURE__ */ new Set([
490
545
  "gi\u1EA5u",
491
546
  "g\xE1n",
492
547
  "thi\u1EBFt l\u1EADp",
493
- "\u0111\u1EB7t",
494
548
  "t\u0103ng",
495
549
  "t\u0103ng l\xEAn",
496
550
  "gi\u1EA3m",
@@ -525,10 +579,6 @@ var POLISH_KEYWORDS = /* @__PURE__ */ new Set([
525
579
  "zwi\u0119ksz",
526
580
  "zwieksz",
527
581
  "zmniejsz",
528
- "uzyskaj",
529
- "pobierz",
530
- "wywo\u0142aj",
531
- "wywolaj",
532
582
  "wyzw\xF3l",
533
583
  "wyzwol",
534
584
  "wy\u015Blij",
@@ -570,8 +620,9 @@ var RUSSIAN_KEYWORDS = /* @__PURE__ */ new Set([
570
620
  "\u0443\u0432\u0435\u043B\u0438\u0447\u044C",
571
621
  "\u0443\u043C\u0435\u043D\u044C\u0448\u0438\u0442\u044C",
572
622
  "\u0443\u043C\u0435\u043D\u044C\u0448\u0438",
573
- "\u0432\u044B\u0437\u0432\u0430\u0442\u044C",
574
- "\u0432\u044B\u0437\u043E\u0432\u0438",
623
+ "\u0438\u043D\u0438\u0446\u0438\u0438\u0440\u043E\u0432\u0430\u0442\u044C",
624
+ "\u0437\u0430\u043F\u0443\u0441\u0442\u0438\u0442\u044C",
625
+ "\u0437\u0430\u043F\u0443\u0441\u0442\u0438",
575
626
  "\u043E\u0442\u043F\u0440\u0430\u0432\u0438\u0442\u044C",
576
627
  "\u043E\u0442\u043F\u0440\u0430\u0432\u044C",
577
628
  "\u0435\u0441\u043B\u0438",
@@ -606,8 +657,9 @@ var UKRAINIAN_KEYWORDS = /* @__PURE__ */ new Set([
606
657
  "\u0437\u0431\u0456\u043B\u044C\u0448",
607
658
  "\u0437\u043C\u0435\u043D\u0448\u0438\u0442\u0438",
608
659
  "\u0437\u043C\u0435\u043D\u0448",
609
- "\u0432\u0438\u043A\u043B\u0438\u043A\u0430\u0442\u0438",
610
- "\u0432\u0438\u043A\u043B\u0438\u0447",
660
+ "\u0456\u043D\u0456\u0446\u0456\u044E\u0432\u0430\u0442\u0438",
661
+ "\u0437\u0430\u043F\u0443\u0441\u0442\u0438\u0442\u0438",
662
+ "\u0437\u0430\u043F\u0443\u0441\u0442\u0438",
611
663
  "\u043D\u0430\u0434\u0456\u0441\u043B\u0430\u0442\u0438",
612
664
  "\u043D\u0430\u0434\u0456\u0448\u043B\u0438",
613
665
  "\u044F\u043A\u0449\u043E",
@@ -653,7 +705,6 @@ var HINDI_KEYWORDS = /* @__PURE__ */ new Set([
653
705
  ]);
654
706
  var BENGALI_KEYWORDS = /* @__PURE__ */ new Set([
655
707
  "\u099F\u0997\u09B2",
656
- "\u09AA\u09B0\u09BF\u09AC\u09B0\u09CD\u09A4\u09A8",
657
708
  "\u09AF\u09CB\u0997",
658
709
  "\u09AF\u09CB\u0997 \u0995\u09B0\u09C1\u09A8",
659
710
  "\u09B8\u09B0\u09BE\u09A8",
@@ -678,7 +729,6 @@ var BENGALI_KEYWORDS = /* @__PURE__ */ new Set([
678
729
  "\u09AA\u09C1\u09A8\u09B0\u09BE\u09AC\u09C3\u09A4\u09CD\u09A4\u09BF",
679
730
  "\u09AC\u09BE\u09B0 \u09AC\u09BE\u09B0",
680
731
  "\u0985\u09AA\u09C7\u0995\u09CD\u09B7\u09BE",
681
- "\u09A5\u09BE\u09AE\u09C1\u09A8",
682
732
  "\u09AF\u09A4\u0995\u09CD\u09B7\u09A3"
683
733
  ]);
684
734
  var THAI_KEYWORDS = /* @__PURE__ */ new Set([
@@ -719,11 +769,11 @@ var TL_KEYWORDS = /* @__PURE__ */ new Set([
719
769
  "taasan",
720
770
  "bawasan",
721
771
  "ibaba",
772
+ "palitawin",
722
773
  "magpatugtog",
723
774
  "ipadala",
724
775
  "magpadala",
725
776
  "kung",
726
- "kapag",
727
777
  "kung_hindi",
728
778
  "kundi",
729
779
  "ulitin",
@@ -739,6 +789,7 @@ var LANGUAGE_KEYWORDS = {
739
789
  ko: KOREAN_KEYWORDS,
740
790
  zh: CHINESE_KEYWORDS,
741
791
  ar: ARABIC_KEYWORDS,
792
+ he: HE_KEYWORDS,
742
793
  es: SPANISH_KEYWORDS,
743
794
  pt: PORTUGUESE_KEYWORDS,
744
795
  fr: FRENCH_KEYWORDS,
@@ -753,6 +804,7 @@ var LANGUAGE_KEYWORDS = {
753
804
  th: THAI_KEYWORDS,
754
805
  tr: TURKISH_KEYWORDS,
755
806
  id: INDONESIAN_KEYWORDS,
807
+ ms: MS_KEYWORDS,
756
808
  sw: SWAHILI_KEYWORDS,
757
809
  qu: QUECHUA_KEYWORDS,
758
810
  tl: TL_KEYWORDS
@@ -760,7 +812,18 @@ var LANGUAGE_KEYWORDS = {
760
812
  function containsLanguageKeywords(script, language) {
761
813
  const keywords = LANGUAGE_KEYWORDS[language];
762
814
  if (!keywords || keywords.size === 0) return false;
763
- const nonLatinLangs = ["ja", "ko", "zh", "ar", "ru", "uk", "hi", "bn", "th"];
815
+ const nonLatinLangs = [
816
+ "ja",
817
+ "ko",
818
+ "zh",
819
+ "ar",
820
+ "he",
821
+ "ru",
822
+ "uk",
823
+ "hi",
824
+ "bn",
825
+ "th"
826
+ ];
764
827
  if (nonLatinLangs.includes(language)) {
765
828
  for (const keyword of keywords) {
766
829
  if (script.includes(keyword)) {
@@ -844,6 +907,61 @@ function getOptimalRegion(languages) {
844
907
  return "all";
845
908
  }
846
909
 
910
+ // src/htmx-localized-attrs.ts
911
+ var HX_LIVE_LOCALIZED = /* @__PURE__ */ new Set([
912
+ // Each entry is the suffix after the `hx-` prefix.
913
+ "\u0645\u0628\u0627\u0634\u0631",
914
+ // ar
915
+ "\u09B2\u09BE\u0987\u09AD",
916
+ // bn
917
+ "direkt",
918
+ // de
919
+ "en-vivo",
920
+ // es
921
+ "en-direct",
922
+ // fr
923
+ "\u05D7\u05D9",
924
+ // he
925
+ "\u0932\u093E\u0907\u0935",
926
+ // hi
927
+ "langsung",
928
+ // id
929
+ "in-diretta",
930
+ // it
931
+ "\u30E9\u30A4\u30D6",
932
+ // ja
933
+ "\uC2E4\uC2DC\uAC04",
934
+ // ko
935
+ "langsung",
936
+ // ms
937
+ "na-\u017Cywo",
938
+ // pl
939
+ "ao-vivo",
940
+ // pt
941
+ "kawsachkaq",
942
+ // qu
943
+ "\u0432-\u043F\u0440\u044F\u043C\u043E\u043C-\u044D\u0444\u0438\u0440\u0435",
944
+ // ru
945
+ "moja-kwa-moja",
946
+ // sw
947
+ "\u0E44\u0E25\u0E1F\u0E4C",
948
+ // th
949
+ "canl\u0131",
950
+ // tr
951
+ "\u043D\u0430\u0436\u0438\u0432\u043E",
952
+ // uk
953
+ "tr\u1EF1c-ti\u1EBFp",
954
+ // vi
955
+ "\u5B9E\u65F6"
956
+ // zh
957
+ ]);
958
+ function buildLocalizedHxLivePattern() {
959
+ const suffixes = [...HX_LIVE_LOCALIZED].map((s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
960
+ return new RegExp(`\\bhx-(?:${suffixes})\\s*=\\s*["']`, "u");
961
+ }
962
+ var SSE_NS_PATTERN = /\bsse-[\w\-\p{L}]+\s*=\s*["']/u;
963
+ var WS_NS_PATTERN = /\bws-[\w\-\p{L}]+\s*=\s*["']/u;
964
+
847
965
  // src/scanner.ts
848
966
  var HTMX_REQUEST_PATTERN = /\b(hx-get|hx-post|hx-put|hx-patch|hx-delete)\s*=\s*["']([^"']+)["']/gi;
849
967
  var FIXI_ACTION_PATTERN = /\bfx-action\s*=\s*["']([^"']+)["']/gi;
@@ -854,6 +972,14 @@ var HTMX_TRIGGER_PATTERN = /\b(hx-trigger|fx-trigger)\s*=\s*["']([^"']+)["']/gi;
854
972
  var HTMX_URL_PATTERN = /\b(hx-push-url|hx-replace-url)\s*=\s*["'][^"']+["']/gi;
855
973
  var HTMX_CONFIRM_PATTERN = /\bhx-confirm\s*=\s*["']/gi;
856
974
  var HTMX_ON_PATTERN = /\bhx-on:(\w+)\s*=\s*["']([^"']+)["']/g;
975
+ var HX_LIVE_PATTERN = /\bhx-live\s*=\s*["']/i;
976
+ var SSE_CONNECT_PATTERN = /\bsse-connect\s*=\s*["']/i;
977
+ var SSE_SWAP_PATTERN = /\bsse-swap\s*=\s*["']/i;
978
+ var WS_CONNECT_PATTERN = /\bws-connect\s*=\s*["']/i;
979
+ var WS_SEND_PATTERN = /\bws-send(\s*=\s*["']|\b)/i;
980
+ var HX_LIVE_LOCALIZED_PATTERN = buildLocalizedHxLivePattern();
981
+ var LOCALIZED_HX_PATTERN = /\b(hx|sse|ws)-[\w\-\p{L}]+\s*=\s*["']/u;
982
+ var BIND_TO_PROPERTY_PATTERN = /\bbind\s+\S+\s+to\s+\S+\.\w+/i;
857
983
  function toRegex(pattern, defaultPattern) {
858
984
  if (!pattern) return defaultPattern;
859
985
  if (pattern instanceof RegExp) return pattern;
@@ -886,7 +1012,9 @@ var Scanner = class {
886
1012
  commands: /* @__PURE__ */ new Set(),
887
1013
  blocks: /* @__PURE__ */ new Set(),
888
1014
  positional: false,
889
- detectedLanguages: /* @__PURE__ */ new Set()
1015
+ detectedLanguages: /* @__PURE__ */ new Set(),
1016
+ needsReactivity: false,
1017
+ needsBindToProperty: false
890
1018
  };
891
1019
  const attrPatterns = [
892
1020
  /_\s*=\s*"([^"]+)"/g,
@@ -921,6 +1049,7 @@ var Scanner = class {
921
1049
  if (/hx-target\s*=\s*["'](closest|next|previous|find)\s/i.test(code)) {
922
1050
  usage.positional = true;
923
1051
  }
1052
+ if (htmxUsage.needsReactivity) usage.needsReactivity = true;
924
1053
  }
925
1054
  if (this.debug && (usage.commands.size > 0 || usage.blocks.size > 0 || usage.detectedLanguages.size > 0 || usage.htmx?.hasHtmxAttributes)) {
926
1055
  console.log(`[hyperfixi] Scanned ${id}:`, {
@@ -960,6 +1089,13 @@ var Scanner = class {
960
1089
  for (const lang of languages) {
961
1090
  usage.detectedLanguages.add(lang);
962
1091
  }
1092
+ if (/\blive\b/.test(script) || /\bwhen\s+\S+\s+changes\b/i.test(script) || /\bbind\b/.test(script) || /\^\w/.test(script)) {
1093
+ usage.needsReactivity = true;
1094
+ }
1095
+ if (BIND_TO_PROPERTY_PATTERN.test(script)) {
1096
+ usage.needsBindToProperty = true;
1097
+ usage.needsReactivity = true;
1098
+ }
963
1099
  }
964
1100
  /**
965
1101
  * Scan for htmx/fixi attributes
@@ -973,7 +1109,12 @@ var Scanner = class {
973
1109
  onHandlers: [],
974
1110
  triggerModifiers: /* @__PURE__ */ new Set(),
975
1111
  urlManagement: /* @__PURE__ */ new Set(),
976
- usesConfirm: false
1112
+ usesConfirm: false,
1113
+ needsHxLive: false,
1114
+ needsSSE: false,
1115
+ needsWS: false,
1116
+ needsBindToProperty: false,
1117
+ needsReactivity: false
977
1118
  };
978
1119
  let match;
979
1120
  const requestPattern = new RegExp(HTMX_REQUEST_PATTERN.source, "gi");
@@ -1022,6 +1163,35 @@ var Scanner = class {
1022
1163
  while (match = targetPattern.exec(code)) {
1023
1164
  usage.hasHtmxAttributes = true;
1024
1165
  }
1166
+ if (HX_LIVE_PATTERN.test(code)) {
1167
+ usage.hasHtmxAttributes = true;
1168
+ usage.needsHxLive = true;
1169
+ usage.needsReactivity = true;
1170
+ }
1171
+ if (SSE_CONNECT_PATTERN.test(code) || SSE_SWAP_PATTERN.test(code)) {
1172
+ usage.hasHtmxAttributes = true;
1173
+ usage.needsSSE = true;
1174
+ }
1175
+ if (WS_CONNECT_PATTERN.test(code) || WS_SEND_PATTERN.test(code)) {
1176
+ usage.hasHtmxAttributes = true;
1177
+ usage.needsWS = true;
1178
+ }
1179
+ if (HX_LIVE_LOCALIZED_PATTERN.test(code)) {
1180
+ usage.hasHtmxAttributes = true;
1181
+ usage.needsHxLive = true;
1182
+ usage.needsReactivity = true;
1183
+ }
1184
+ if (!usage.needsSSE && SSE_NS_PATTERN.test(code)) {
1185
+ usage.hasHtmxAttributes = true;
1186
+ usage.needsSSE = true;
1187
+ }
1188
+ if (!usage.needsWS && WS_NS_PATTERN.test(code)) {
1189
+ usage.hasHtmxAttributes = true;
1190
+ usage.needsWS = true;
1191
+ }
1192
+ if (!usage.hasHtmxAttributes && LOCALIZED_HX_PATTERN.test(code)) {
1193
+ usage.hasHtmxAttributes = true;
1194
+ }
1025
1195
  return usage;
1026
1196
  }
1027
1197
  /**
@@ -1137,13 +1307,22 @@ var Aggregator = class {
1137
1307
  onHandlers: [],
1138
1308
  triggerModifiers: /* @__PURE__ */ new Set(),
1139
1309
  urlManagement: /* @__PURE__ */ new Set(),
1140
- usesConfirm: false
1310
+ usesConfirm: false,
1311
+ needsHxLive: false,
1312
+ needsSSE: false,
1313
+ needsWS: false,
1314
+ needsBindToProperty: false,
1315
+ needsReactivity: false
1141
1316
  };
1317
+ let needsReactivity = false;
1318
+ let needsBindToProperty = false;
1142
1319
  for (const usage of this.fileUsage.values()) {
1143
1320
  for (const cmd of usage.commands) commands.add(cmd);
1144
1321
  for (const block of usage.blocks) blocks.add(block);
1145
1322
  for (const lang of usage.detectedLanguages) detectedLanguages.add(lang);
1146
1323
  if (usage.positional) positional = true;
1324
+ if (usage.needsReactivity) needsReactivity = true;
1325
+ if (usage.needsBindToProperty) needsBindToProperty = true;
1147
1326
  if (usage.htmx) {
1148
1327
  if (usage.htmx.hasHtmxAttributes) htmx.hasHtmxAttributes = true;
1149
1328
  if (usage.htmx.hasFixiAttributes) htmx.hasFixiAttributes = true;
@@ -1153,6 +1332,14 @@ var Aggregator = class {
1153
1332
  for (const modifier of usage.htmx.triggerModifiers) htmx.triggerModifiers.add(modifier);
1154
1333
  for (const url of usage.htmx.urlManagement) htmx.urlManagement.add(url);
1155
1334
  if (usage.htmx.usesConfirm) htmx.usesConfirm = true;
1335
+ if (usage.htmx.needsHxLive) htmx.needsHxLive = true;
1336
+ if (usage.htmx.needsSSE) htmx.needsSSE = true;
1337
+ if (usage.htmx.needsWS) htmx.needsWS = true;
1338
+ if (usage.htmx.needsBindToProperty) htmx.needsBindToProperty = true;
1339
+ if (usage.htmx.needsReactivity) {
1340
+ htmx.needsReactivity = true;
1341
+ needsReactivity = true;
1342
+ }
1156
1343
  }
1157
1344
  }
1158
1345
  this.cachedUsage = {
@@ -1161,6 +1348,8 @@ var Aggregator = class {
1161
1348
  positional,
1162
1349
  detectedLanguages,
1163
1350
  htmx,
1351
+ needsReactivity,
1352
+ needsBindToProperty,
1164
1353
  fileUsage: new Map(this.fileUsage)
1165
1354
  };
1166
1355
  return this.cachedUsage;
@@ -1499,7 +1688,6 @@ var SINGLE_LANGUAGE_BUNDLES = [
1499
1688
  "de",
1500
1689
  "en",
1501
1690
  "es",
1502
- "es-MX",
1503
1691
  "fr",
1504
1692
  "he",
1505
1693
  "hi",
@@ -1552,7 +1740,6 @@ var SEMANTIC_BUNDLE_SIZES = {
1552
1740
  de: { raw: "57 KB", gzip: "~14 KB" },
1553
1741
  en: { raw: "82 KB", gzip: "~20 KB" },
1554
1742
  es: { raw: "64 KB", gzip: "~16 KB" },
1555
- "es-MX": { raw: "64 KB", gzip: "~16 KB" },
1556
1743
  fr: { raw: "57 KB", gzip: "~14 KB" },
1557
1744
  he: { raw: "56 KB", gzip: "~14 KB" },
1558
1745
  hi: { raw: "56 KB", gzip: "~14 KB" },
@@ -1588,7 +1775,6 @@ var LANGUAGES_WITH_ESM_EXPORTS = /* @__PURE__ */ new Set([
1588
1775
  "de",
1589
1776
  "en",
1590
1777
  "es",
1591
- "es-MX",
1592
1778
  "fr",
1593
1779
  "he",
1594
1780
  "hi",
@@ -1661,7 +1847,7 @@ function generateSemanticIntegrationCode(config) {
1661
1847
 
1662
1848
  // Core infrastructure (no language data bundled)
1663
1849
  import {
1664
- createSemanticAnalyzer,
1850
+ parseWithConfidence,
1665
1851
  buildAST,
1666
1852
  isLanguageSupported,
1667
1853
  } from '@lokascript/semantic/core';
@@ -1682,7 +1868,6 @@ const grammarTransformer = new GrammarTransformer();
1682
1868
  }
1683
1869
  const aliasesCode = generateMultilingualAliases(config.languages);
1684
1870
  code += `
1685
- const semanticAnalyzer = createSemanticAnalyzer();
1686
1871
  const SUPPORTED_SEMANTIC_LANGUAGES = ['${languages}', 'en'];
1687
1872
  const SEMANTIC_CONFIDENCE_THRESHOLD = 0.7;
1688
1873
 
@@ -1710,7 +1895,7 @@ function parseWithSemantic(code, lang = null) {
1710
1895
  for (const tryLang of languagesToTry) {
1711
1896
  if (!isLanguageSupported(tryLang)) continue;
1712
1897
  try {
1713
- const result = semanticAnalyzer.analyze(code, tryLang);
1898
+ const result = parseWithConfidence(code, tryLang);
1714
1899
  if (result && result.confidence >= SEMANTIC_CONFIDENCE_THRESHOLD) {
1715
1900
  // buildAST returns {ast, warnings} - extract the ast
1716
1901
  const buildResult = buildAST(result.node);
@@ -2194,6 +2379,28 @@ var Generator = class {
2194
2379
  if (commands.length === 0 && blocks.length === 0 && !positional && !semanticConfig.enabled) {
2195
2380
  return this.generateEmptyBundle(options);
2196
2381
  }
2382
+ const needsV4Bundle = usage.needsReactivity || usage.htmx?.needsHxLive || usage.htmx?.needsSSE || usage.htmx?.needsWS;
2383
+ if (needsV4Bundle) {
2384
+ if (this.debug) {
2385
+ const triggers = [];
2386
+ if (usage.htmx?.needsHxLive) triggers.push("hx-live");
2387
+ if (usage.htmx?.needsSSE) triggers.push("sse-connect/sse-swap");
2388
+ if (usage.htmx?.needsWS) triggers.push("ws-connect/ws-send");
2389
+ if (usage.needsBindToProperty) triggers.push("bind-to-property");
2390
+ else if (usage.needsReactivity) triggers.push("live/when/bind in _=");
2391
+ console.log(
2392
+ `[hyperfixi] Detected htmx v4 features: ${triggers.join(", ")}
2393
+ Using the hx-v4 premade bundle (auto-installs reactivity + SSE/WS).`
2394
+ );
2395
+ const onlyReactivity = usage.needsReactivity && !usage.htmx?.needsHxLive && !usage.htmx?.needsSSE && !usage.htmx?.needsWS && !usage.htmx?.hasHtmxAttributes;
2396
+ if (onlyReactivity) {
2397
+ console.log(
2398
+ ` Note: this project uses reactivity only (no hx-*/sse-*/ws-* attributes). A reactivity-only fallback is parked pending size feedback.`
2399
+ );
2400
+ }
2401
+ }
2402
+ return this.generateDevFallback("hx-v4");
2403
+ }
2197
2404
  const unsupportedCommands = this.getUnsupportedCommands(commands);
2198
2405
  if (unsupportedCommands.length > 0) {
2199
2406
  if (this.debug) {
@@ -2354,10 +2561,19 @@ export { api };
2354
2561
  `;
2355
2562
  }
2356
2563
  /**
2357
- * Generate a development fallback bundle
2564
+ * Generate a development fallback bundle.
2565
+ *
2566
+ * `hx-v4` re-exports the htmx v4 surface bundle: full runtime +
2567
+ * htmx-compat + reactivity (hx-live, bind, when) + SSE + WS, all
2568
+ * auto-installed. The vite plugin selects this when scanner detects
2569
+ * any of `hx-live`, `sse-connect`/`sse-swap`, `ws-connect`/`ws-send`,
2570
+ * or `bind ... to <expr>.<prop>` in `_=` bodies — the minimal
2571
+ * generator can't satisfy those features (the slim runtime lacks the
2572
+ * reactive notify chain and the SSE/WS modules). Larger artifact but
2573
+ * correct end-to-end.
2358
2574
  */
2359
2575
  generateDevFallback(fallback) {
2360
- const bundle = fallback === "full" ? "@hyperfixi/core/browser" : "@hyperfixi/core/browser/hybrid-complete";
2576
+ const bundle = fallback === "full" ? "@hyperfixi/core/browser" : fallback === "hx-v4" ? "@hyperfixi/core/browser/hybrid-hx-v4" : "@hyperfixi/core/browser/hybrid-complete";
2361
2577
  return `/**
2362
2578
  * LokaScript Dev Fallback Bundle
2363
2579
  *
@@ -2375,18 +2591,21 @@ export { default } from '${bundle}';
2375
2591
 
2376
2592
  // src/compiler.ts
2377
2593
  var import_parser_core = require("@hyperfixi/core/parser/hybrid/parser-core");
2378
- var semanticAnalyzer = null;
2594
+ var semanticParse = null;
2595
+ var supportsLanguage = null;
2379
2596
  var buildASTFn = null;
2380
- function setSemanticParser(analyzer, buildAST) {
2381
- semanticAnalyzer = analyzer;
2597
+ function setSemanticParser(parse, supports, buildAST) {
2598
+ semanticParse = parse;
2599
+ supportsLanguage = supports;
2382
2600
  buildASTFn = buildAST;
2383
2601
  }
2384
2602
  function clearSemanticParser() {
2385
- semanticAnalyzer = null;
2603
+ semanticParse = null;
2604
+ supportsLanguage = null;
2386
2605
  buildASTFn = null;
2387
2606
  }
2388
2607
  function hasSemanticParser() {
2389
- return semanticAnalyzer !== null && buildASTFn !== null;
2608
+ return semanticParse !== null && supportsLanguage !== null && buildASTFn !== null;
2390
2609
  }
2391
2610
  var SEMANTIC_CONFIDENCE_THRESHOLD = 0.7;
2392
2611
  var multilingualAliases = {};
@@ -2441,9 +2660,9 @@ function compile(script, options = {}) {
2441
2660
  const { language = "en", debug = false } = options;
2442
2661
  try {
2443
2662
  let ast;
2444
- if (language !== "en" && semanticAnalyzer && buildASTFn) {
2445
- if (semanticAnalyzer.supportsLanguage(language)) {
2446
- const result = semanticAnalyzer.analyze(script, language);
2663
+ if (language !== "en" && semanticParse && supportsLanguage && buildASTFn) {
2664
+ if (supportsLanguage(language)) {
2665
+ const result = semanticParse(script, language);
2447
2666
  if (result.node && result.confidence >= SEMANTIC_CONFIDENCE_THRESHOLD) {
2448
2667
  const { ast: builtAST, warnings } = buildASTFn(result.node);
2449
2668
  if (debug && warnings.length > 0) {
@@ -2457,7 +2676,7 @@ function compile(script, options = {}) {
2457
2676
  }
2458
2677
  } else {
2459
2678
  if (debug) {
2460
- const reason = result.errors?.join(", ") || `low confidence (${result.confidence.toFixed(2)})`;
2679
+ const reason = result.error || `low confidence (${result.confidence.toFixed(2)})`;
2461
2680
  console.log(`[hyperfixi] Semantic parse failed for "${script}": ${reason}`);
2462
2681
  }
2463
2682
  return null;