@lokascript/vite-plugin 1.0.0 → 1.1.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.d.cts CHANGED
@@ -153,6 +153,27 @@ interface CustomLanguageKeywords {
153
153
  */
154
154
  extend?: boolean;
155
155
  }
156
+ /**
157
+ * HTMX/Fixi attribute usage information
158
+ */
159
+ interface HtmxUsage {
160
+ /** Whether any htmx attributes were found */
161
+ hasHtmxAttributes: boolean;
162
+ /** Whether any fixi-specific attributes were found (fx-action, etc.) */
163
+ hasFixiAttributes: boolean;
164
+ /** HTTP methods used (GET, POST, PUT, PATCH, DELETE) */
165
+ httpMethods: Set<string>;
166
+ /** Swap strategies used (innerHTML, morph, delete, beforeend, etc.) */
167
+ swapStrategies: Set<string>;
168
+ /** hx-on:* handler values (raw hyperscript) */
169
+ onHandlers: string[];
170
+ /** Trigger modifiers detected (debounce, throttle, once) */
171
+ triggerModifiers: Set<string>;
172
+ /** URL management strategies (push-url, replace-url) */
173
+ urlManagement: Set<string>;
174
+ /** Whether hx-confirm is used */
175
+ usesConfirm: boolean;
176
+ }
156
177
  /**
157
178
  * Usage information detected from a single file
158
179
  */
@@ -165,6 +186,8 @@ interface FileUsage {
165
186
  positional: boolean;
166
187
  /** Non-English languages detected in hyperscript (ISO 639-1 codes) */
167
188
  detectedLanguages: Set<string>;
189
+ /** HTMX/Fixi attribute usage (if detected) */
190
+ htmx?: HtmxUsage;
168
191
  }
169
192
  /**
170
193
  * Aggregated usage information across all files
@@ -178,6 +201,8 @@ interface AggregatedUsage {
178
201
  positional: boolean;
179
202
  /** All non-English languages detected across all files */
180
203
  detectedLanguages: Set<string>;
204
+ /** Aggregated HTMX/Fixi usage across all files */
205
+ htmx: HtmxUsage;
181
206
  /** Map of file paths to their usage */
182
207
  fileUsage: Map<string, FileUsage>;
183
208
  }
package/dist/index.d.ts CHANGED
@@ -153,6 +153,27 @@ interface CustomLanguageKeywords {
153
153
  */
154
154
  extend?: boolean;
155
155
  }
156
+ /**
157
+ * HTMX/Fixi attribute usage information
158
+ */
159
+ interface HtmxUsage {
160
+ /** Whether any htmx attributes were found */
161
+ hasHtmxAttributes: boolean;
162
+ /** Whether any fixi-specific attributes were found (fx-action, etc.) */
163
+ hasFixiAttributes: boolean;
164
+ /** HTTP methods used (GET, POST, PUT, PATCH, DELETE) */
165
+ httpMethods: Set<string>;
166
+ /** Swap strategies used (innerHTML, morph, delete, beforeend, etc.) */
167
+ swapStrategies: Set<string>;
168
+ /** hx-on:* handler values (raw hyperscript) */
169
+ onHandlers: string[];
170
+ /** Trigger modifiers detected (debounce, throttle, once) */
171
+ triggerModifiers: Set<string>;
172
+ /** URL management strategies (push-url, replace-url) */
173
+ urlManagement: Set<string>;
174
+ /** Whether hx-confirm is used */
175
+ usesConfirm: boolean;
176
+ }
156
177
  /**
157
178
  * Usage information detected from a single file
158
179
  */
@@ -165,6 +186,8 @@ interface FileUsage {
165
186
  positional: boolean;
166
187
  /** Non-English languages detected in hyperscript (ISO 639-1 codes) */
167
188
  detectedLanguages: Set<string>;
189
+ /** HTMX/Fixi attribute usage (if detected) */
190
+ htmx?: HtmxUsage;
168
191
  }
169
192
  /**
170
193
  * Aggregated usage information across all files
@@ -178,6 +201,8 @@ interface AggregatedUsage {
178
201
  positional: boolean;
179
202
  /** All non-English languages detected across all files */
180
203
  detectedLanguages: Set<string>;
204
+ /** Aggregated HTMX/Fixi usage across all files */
205
+ htmx: HtmxUsage;
181
206
  /** Map of file paths to their usage */
182
207
  fileUsage: Map<string, FileUsage>;
183
208
  }
package/dist/index.js CHANGED
@@ -791,6 +791,15 @@ function getOptimalRegion(languages) {
791
791
  }
792
792
 
793
793
  // src/scanner.ts
794
+ var HTMX_REQUEST_PATTERN = /\b(hx-get|hx-post|hx-put|hx-patch|hx-delete)\s*=\s*["']([^"']+)["']/gi;
795
+ var FIXI_ACTION_PATTERN = /\bfx-action\s*=\s*["']([^"']+)["']/gi;
796
+ var FIXI_METHOD_PATTERN = /\bfx-method\s*=\s*["'](GET|POST|PUT|PATCH|DELETE)["']/gi;
797
+ var HTMX_SWAP_PATTERN = /\b(hx-swap|fx-swap)\s*=\s*["']([^"']+)["']/gi;
798
+ var HTMX_TARGET_PATTERN = /\b(hx-target|fx-target)\s*=\s*["']([^"']+)["']/gi;
799
+ var HTMX_TRIGGER_PATTERN = /\b(hx-trigger|fx-trigger)\s*=\s*["']([^"']+)["']/gi;
800
+ var HTMX_URL_PATTERN = /\b(hx-push-url|hx-replace-url)\s*=\s*["'][^"']+["']/gi;
801
+ var HTMX_CONFIRM_PATTERN = /\bhx-confirm\s*=\s*["']/gi;
802
+ var HTMX_ON_PATTERN = /\bhx-on:(\w+)\s*=\s*["']([^"']+)["']/g;
794
803
  function toRegex(pattern, defaultPattern) {
795
804
  if (!pattern) return defaultPattern;
796
805
  if (pattern instanceof RegExp) return pattern;
@@ -848,12 +857,29 @@ var Scanner = class {
848
857
  while (match = scriptPattern.exec(code)) {
849
858
  this.analyzeScript(match[1], usage);
850
859
  }
851
- if (this.debug && (usage.commands.size > 0 || usage.blocks.size > 0 || usage.detectedLanguages.size > 0)) {
860
+ const htmxUsage = this.scanHtmxAttributes(code);
861
+ if (htmxUsage.hasHtmxAttributes) {
862
+ usage.htmx = htmxUsage;
863
+ this.inferCommandsFromHtmx(htmxUsage, usage);
864
+ for (const handlerCode of htmxUsage.onHandlers) {
865
+ this.analyzeScript(handlerCode, usage);
866
+ }
867
+ if (/hx-target\s*=\s*["'](closest|next|previous|find)\s/i.test(code)) {
868
+ usage.positional = true;
869
+ }
870
+ }
871
+ if (this.debug && (usage.commands.size > 0 || usage.blocks.size > 0 || usage.detectedLanguages.size > 0 || usage.htmx?.hasHtmxAttributes)) {
852
872
  console.log(`[hyperfixi] Scanned ${id}:`, {
853
873
  commands: [...usage.commands],
854
874
  blocks: [...usage.blocks],
855
875
  positional: usage.positional,
856
- languages: [...usage.detectedLanguages]
876
+ languages: [...usage.detectedLanguages],
877
+ htmx: usage.htmx ? {
878
+ hasHtmxAttributes: usage.htmx.hasHtmxAttributes,
879
+ hasFixiAttributes: usage.htmx.hasFixiAttributes,
880
+ httpMethods: [...usage.htmx.httpMethods],
881
+ swapStrategies: [...usage.htmx.swapStrategies]
882
+ } : void 0
857
883
  });
858
884
  }
859
885
  return usage;
@@ -881,6 +907,93 @@ var Scanner = class {
881
907
  usage.detectedLanguages.add(lang);
882
908
  }
883
909
  }
910
+ /**
911
+ * Scan for htmx/fixi attributes
912
+ */
913
+ scanHtmxAttributes(code) {
914
+ const usage = {
915
+ hasHtmxAttributes: false,
916
+ hasFixiAttributes: false,
917
+ httpMethods: /* @__PURE__ */ new Set(),
918
+ swapStrategies: /* @__PURE__ */ new Set(),
919
+ onHandlers: [],
920
+ triggerModifiers: /* @__PURE__ */ new Set(),
921
+ urlManagement: /* @__PURE__ */ new Set(),
922
+ usesConfirm: false
923
+ };
924
+ let match;
925
+ const requestPattern = new RegExp(HTMX_REQUEST_PATTERN.source, "gi");
926
+ while (match = requestPattern.exec(code)) {
927
+ usage.hasHtmxAttributes = true;
928
+ usage.httpMethods.add(match[1].replace("hx-", "").toUpperCase());
929
+ }
930
+ if (new RegExp(FIXI_ACTION_PATTERN.source, "gi").test(code)) {
931
+ usage.hasHtmxAttributes = true;
932
+ usage.hasFixiAttributes = true;
933
+ }
934
+ const fixiMethodPattern = new RegExp(FIXI_METHOD_PATTERN.source, "gi");
935
+ while (match = fixiMethodPattern.exec(code)) {
936
+ usage.hasHtmxAttributes = true;
937
+ usage.hasFixiAttributes = true;
938
+ usage.httpMethods.add(match[1].toUpperCase());
939
+ }
940
+ const swapPattern = new RegExp(HTMX_SWAP_PATTERN.source, "gi");
941
+ while (match = swapPattern.exec(code)) {
942
+ usage.hasHtmxAttributes = true;
943
+ usage.swapStrategies.add(match[2].split(/\s+/)[0]);
944
+ }
945
+ const triggerPattern = new RegExp(HTMX_TRIGGER_PATTERN.source, "gi");
946
+ while (match = triggerPattern.exec(code)) {
947
+ usage.hasHtmxAttributes = true;
948
+ const trigger = match[2];
949
+ if (/delay:/i.test(trigger)) usage.triggerModifiers.add("debounce");
950
+ if (/throttle:/i.test(trigger)) usage.triggerModifiers.add("throttle");
951
+ if (/\bonce\b/i.test(trigger)) usage.triggerModifiers.add("once");
952
+ }
953
+ if (new RegExp(HTMX_URL_PATTERN.source, "gi").test(code)) {
954
+ usage.hasHtmxAttributes = true;
955
+ if (/hx-push-url/i.test(code)) usage.urlManagement.add("push-url");
956
+ if (/hx-replace-url/i.test(code)) usage.urlManagement.add("replace-url");
957
+ }
958
+ if (new RegExp(HTMX_CONFIRM_PATTERN.source, "gi").test(code)) {
959
+ usage.hasHtmxAttributes = true;
960
+ usage.usesConfirm = true;
961
+ }
962
+ const onPattern = new RegExp(HTMX_ON_PATTERN.source, "g");
963
+ while (match = onPattern.exec(code)) {
964
+ usage.hasHtmxAttributes = true;
965
+ usage.onHandlers.push(match[2]);
966
+ }
967
+ const targetPattern = new RegExp(HTMX_TARGET_PATTERN.source, "gi");
968
+ while (match = targetPattern.exec(code)) {
969
+ usage.hasHtmxAttributes = true;
970
+ }
971
+ return usage;
972
+ }
973
+ /**
974
+ * Infer commands from htmx usage
975
+ */
976
+ inferCommandsFromHtmx(htmx, usage) {
977
+ if (htmx.httpMethods.size > 0) {
978
+ usage.blocks.add("fetch");
979
+ usage.commands.add("put");
980
+ }
981
+ for (const swap of htmx.swapStrategies) {
982
+ switch (swap.toLowerCase()) {
983
+ case "morph":
984
+ usage.commands.add("morph");
985
+ break;
986
+ case "delete":
987
+ usage.commands.add("remove");
988
+ break;
989
+ default:
990
+ usage.commands.add("put");
991
+ }
992
+ }
993
+ if (htmx.usesConfirm) {
994
+ usage.blocks.add("if");
995
+ }
996
+ }
884
997
  /**
885
998
  * Scan all files in a project directory
886
999
  * Used during production build to scan the entire codebase
@@ -931,7 +1044,8 @@ var Aggregator = class {
931
1044
  const blocksEqual = this.setsEqual(existing.blocks, usage.blocks);
932
1045
  const positionalEqual = existing.positional === usage.positional;
933
1046
  const languagesEqual = this.setsEqual(existing.detectedLanguages, usage.detectedLanguages);
934
- if (commandsEqual && blocksEqual && positionalEqual && languagesEqual) {
1047
+ const htmxEqual = this.htmxUsageEqual(existing.htmx, usage.htmx);
1048
+ if (commandsEqual && blocksEqual && positionalEqual && languagesEqual && htmxEqual) {
935
1049
  return false;
936
1050
  }
937
1051
  }
@@ -961,17 +1075,38 @@ var Aggregator = class {
961
1075
  const blocks = /* @__PURE__ */ new Set();
962
1076
  const detectedLanguages = /* @__PURE__ */ new Set();
963
1077
  let positional = false;
1078
+ const htmx = {
1079
+ hasHtmxAttributes: false,
1080
+ hasFixiAttributes: false,
1081
+ httpMethods: /* @__PURE__ */ new Set(),
1082
+ swapStrategies: /* @__PURE__ */ new Set(),
1083
+ onHandlers: [],
1084
+ triggerModifiers: /* @__PURE__ */ new Set(),
1085
+ urlManagement: /* @__PURE__ */ new Set(),
1086
+ usesConfirm: false
1087
+ };
964
1088
  for (const usage of this.fileUsage.values()) {
965
1089
  for (const cmd of usage.commands) commands.add(cmd);
966
1090
  for (const block of usage.blocks) blocks.add(block);
967
1091
  for (const lang of usage.detectedLanguages) detectedLanguages.add(lang);
968
1092
  if (usage.positional) positional = true;
1093
+ if (usage.htmx) {
1094
+ if (usage.htmx.hasHtmxAttributes) htmx.hasHtmxAttributes = true;
1095
+ if (usage.htmx.hasFixiAttributes) htmx.hasFixiAttributes = true;
1096
+ for (const method of usage.htmx.httpMethods) htmx.httpMethods.add(method);
1097
+ for (const swap of usage.htmx.swapStrategies) htmx.swapStrategies.add(swap);
1098
+ htmx.onHandlers.push(...usage.htmx.onHandlers);
1099
+ for (const modifier of usage.htmx.triggerModifiers) htmx.triggerModifiers.add(modifier);
1100
+ for (const url of usage.htmx.urlManagement) htmx.urlManagement.add(url);
1101
+ if (usage.htmx.usesConfirm) htmx.usesConfirm = true;
1102
+ }
969
1103
  }
970
1104
  this.cachedUsage = {
971
1105
  commands,
972
1106
  blocks,
973
1107
  positional,
974
1108
  detectedLanguages,
1109
+ htmx,
975
1110
  fileUsage: new Map(this.fileUsage)
976
1111
  };
977
1112
  return this.cachedUsage;
@@ -1020,6 +1155,14 @@ var Aggregator = class {
1020
1155
  }
1021
1156
  return true;
1022
1157
  }
1158
+ /**
1159
+ * Compare two HtmxUsage objects for equality
1160
+ */
1161
+ htmxUsageEqual(a, b) {
1162
+ if (!a && !b) return true;
1163
+ if (!a || !b) return false;
1164
+ return a.hasHtmxAttributes === b.hasHtmxAttributes && a.hasFixiAttributes === b.hasFixiAttributes && this.setsEqual(a.httpMethods, b.httpMethods) && this.setsEqual(a.swapStrategies, b.swapStrategies) && this.setsEqual(a.triggerModifiers, b.triggerModifiers) && this.setsEqual(a.urlManagement, b.urlManagement) && a.usesConfirm === b.usesConfirm;
1165
+ }
1023
1166
  };
1024
1167
 
1025
1168
  // src/generator.ts
@@ -1894,7 +2037,7 @@ var Generator = class {
1894
2037
  commands,
1895
2038
  blocks,
1896
2039
  positionalExpressions: positional,
1897
- htmxIntegration: options.htmx ?? false,
2040
+ htmxIntegration: options.htmx ?? usage.htmx?.hasHtmxAttributes ?? false,
1898
2041
  globalName: options.globalName ?? "hyperfixi",
1899
2042
  // Use @lokascript/core package path for virtual module
1900
2043
  parserImportPath: "@lokascript/core/parser/hybrid",