stimeo-ui 0.15.0 → 0.17.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.
Files changed (332) hide show
  1. package/CHANGELOG.md +209 -0
  2. package/README.md +128 -1
  3. package/dist/cable/index.d.ts +79 -23
  4. package/dist/cable/index.js +392 -417
  5. package/dist/cable/index.js.map +1 -1
  6. package/dist/controllers/accordion_controller.d.ts +34 -5
  7. package/dist/controllers/accordion_controller.js +228 -28
  8. package/dist/controllers/accordion_controller.js.map +1 -1
  9. package/dist/controllers/alert_dialog_controller.d.ts +20 -9
  10. package/dist/controllers/alert_dialog_controller.js +862 -221
  11. package/dist/controllers/alert_dialog_controller.js.map +1 -1
  12. package/dist/controllers/announcer_controller.d.ts +38 -7
  13. package/dist/controllers/announcer_controller.js +135 -191
  14. package/dist/controllers/announcer_controller.js.map +1 -1
  15. package/dist/controllers/aspect_ratio_controller.js +0 -10
  16. package/dist/controllers/aspect_ratio_controller.js.map +1 -1
  17. package/dist/controllers/auto_submit_controller.d.ts +30 -6
  18. package/dist/controllers/auto_submit_controller.js +295 -110
  19. package/dist/controllers/auto_submit_controller.js.map +1 -1
  20. package/dist/controllers/avatar_controller.js +172 -106
  21. package/dist/controllers/avatar_controller.js.map +1 -1
  22. package/dist/controllers/breadcrumb_controller.d.ts +10 -7
  23. package/dist/controllers/breadcrumb_controller.js +0 -129
  24. package/dist/controllers/breadcrumb_controller.js.map +1 -1
  25. package/dist/controllers/bulk_select_controller.d.ts +22 -4
  26. package/dist/controllers/bulk_select_controller.js +264 -53
  27. package/dist/controllers/bulk_select_controller.js.map +1 -1
  28. package/dist/controllers/calendar_controller.d.ts +109 -28
  29. package/dist/controllers/calendar_controller.js +346 -180
  30. package/dist/controllers/calendar_controller.js.map +1 -1
  31. package/dist/controllers/carousel_controller.d.ts +99 -27
  32. package/dist/controllers/carousel_controller.js +587 -300
  33. package/dist/controllers/carousel_controller.js.map +1 -1
  34. package/dist/controllers/character_counter_controller.d.ts +18 -2
  35. package/dist/controllers/character_counter_controller.js +271 -143
  36. package/dist/controllers/character_counter_controller.js.map +1 -1
  37. package/dist/controllers/checkbox_controller.d.ts +7 -2
  38. package/dist/controllers/checkbox_controller.js +77 -75
  39. package/dist/controllers/checkbox_controller.js.map +1 -1
  40. package/dist/controllers/clipboard_controller.d.ts +44 -7
  41. package/dist/controllers/clipboard_controller.js +187 -108
  42. package/dist/controllers/clipboard_controller.js.map +1 -1
  43. package/dist/controllers/collapsible_controller.d.ts +41 -5
  44. package/dist/controllers/collapsible_controller.js +374 -108
  45. package/dist/controllers/collapsible_controller.js.map +1 -1
  46. package/dist/controllers/color_picker_controller.d.ts +47 -14
  47. package/dist/controllers/color_picker_controller.js +183 -127
  48. package/dist/controllers/color_picker_controller.js.map +1 -1
  49. package/dist/controllers/combobox_controller.d.ts +33 -6
  50. package/dist/controllers/combobox_controller.js +426 -109
  51. package/dist/controllers/combobox_controller.js.map +1 -1
  52. package/dist/controllers/command_palette_controller.d.ts +45 -14
  53. package/dist/controllers/command_palette_controller.js +994 -350
  54. package/dist/controllers/command_palette_controller.js.map +1 -1
  55. package/dist/controllers/conditional_fields_controller.d.ts +15 -2
  56. package/dist/controllers/conditional_fields_controller.js +212 -125
  57. package/dist/controllers/conditional_fields_controller.js.map +1 -1
  58. package/dist/controllers/confirm_controller.d.ts +49 -12
  59. package/dist/controllers/confirm_controller.js +939 -245
  60. package/dist/controllers/confirm_controller.js.map +1 -1
  61. package/dist/controllers/context_menu_controller.d.ts +36 -3
  62. package/dist/controllers/context_menu_controller.js +275 -127
  63. package/dist/controllers/context_menu_controller.js.map +1 -1
  64. package/dist/controllers/count_up_controller.d.ts +13 -1
  65. package/dist/controllers/count_up_controller.js +73 -21
  66. package/dist/controllers/count_up_controller.js.map +1 -1
  67. package/dist/controllers/countdown_controller.d.ts +75 -2
  68. package/dist/controllers/countdown_controller.js +235 -97
  69. package/dist/controllers/countdown_controller.js.map +1 -1
  70. package/dist/controllers/currency_input_controller.d.ts +93 -15
  71. package/dist/controllers/currency_input_controller.js +241 -118
  72. package/dist/controllers/currency_input_controller.js.map +1 -1
  73. package/dist/controllers/data_grid_controller.d.ts +78 -22
  74. package/dist/controllers/data_grid_controller.js +229 -135
  75. package/dist/controllers/data_grid_controller.js.map +1 -1
  76. package/dist/controllers/date_range_picker_controller.d.ts +64 -11
  77. package/dist/controllers/date_range_picker_controller.js +359 -165
  78. package/dist/controllers/date_range_picker_controller.js.map +1 -1
  79. package/dist/controllers/dialog_controller.d.ts +22 -3
  80. package/dist/controllers/dialog_controller.js +887 -225
  81. package/dist/controllers/dialog_controller.js.map +1 -1
  82. package/dist/controllers/direct_upload_controller.d.ts +24 -7
  83. package/dist/controllers/direct_upload_controller.js +80 -142
  84. package/dist/controllers/direct_upload_controller.js.map +1 -1
  85. package/dist/controllers/dirty_form_controller.d.ts +2 -2
  86. package/dist/controllers/dirty_form_controller.js +26 -47
  87. package/dist/controllers/dirty_form_controller.js.map +1 -1
  88. package/dist/controllers/dismissible_controller.d.ts +19 -0
  89. package/dist/controllers/dismissible_controller.js +175 -20
  90. package/dist/controllers/dismissible_controller.js.map +1 -1
  91. package/dist/controllers/drawer_controller.d.ts +52 -16
  92. package/dist/controllers/drawer_controller.js +963 -336
  93. package/dist/controllers/drawer_controller.js.map +1 -1
  94. package/dist/controllers/dropdown_controller.d.ts +39 -3
  95. package/dist/controllers/dropdown_controller.js +342 -85
  96. package/dist/controllers/dropdown_controller.js.map +1 -1
  97. package/dist/controllers/editable_controller.d.ts +12 -1
  98. package/dist/controllers/editable_controller.js +182 -58
  99. package/dist/controllers/editable_controller.js.map +1 -1
  100. package/dist/controllers/empty_state_controller.js +67 -53
  101. package/dist/controllers/empty_state_controller.js.map +1 -1
  102. package/dist/controllers/file_dropzone_controller.d.ts +60 -18
  103. package/dist/controllers/file_dropzone_controller.js +426 -229
  104. package/dist/controllers/file_dropzone_controller.js.map +1 -1
  105. package/dist/controllers/filter_controller.d.ts +10 -4
  106. package/dist/controllers/filter_controller.js +78 -36
  107. package/dist/controllers/filter_controller.js.map +1 -1
  108. package/dist/controllers/flash_controller.d.ts +57 -14
  109. package/dist/controllers/flash_controller.js +328 -211
  110. package/dist/controllers/flash_controller.js.map +1 -1
  111. package/dist/controllers/focus_controller.d.ts +12 -3
  112. package/dist/controllers/focus_controller.js +654 -239
  113. package/dist/controllers/focus_controller.js.map +1 -1
  114. package/dist/controllers/form_field_controller.js +153 -136
  115. package/dist/controllers/form_field_controller.js.map +1 -1
  116. package/dist/controllers/form_validation_controller.js +29 -96
  117. package/dist/controllers/form_validation_controller.js.map +1 -1
  118. package/dist/controllers/frame_loading_controller.d.ts +41 -9
  119. package/dist/controllers/frame_loading_controller.js +263 -198
  120. package/dist/controllers/frame_loading_controller.js.map +1 -1
  121. package/dist/controllers/highlight_controller.d.ts +22 -2
  122. package/dist/controllers/highlight_controller.js +119 -70
  123. package/dist/controllers/highlight_controller.js.map +1 -1
  124. package/dist/controllers/hover_card_controller.d.ts +65 -4
  125. package/dist/controllers/hover_card_controller.js +335 -118
  126. package/dist/controllers/hover_card_controller.js.map +1 -1
  127. package/dist/controllers/idle_controller.d.ts +58 -4
  128. package/dist/controllers/idle_controller.js +316 -65
  129. package/dist/controllers/idle_controller.js.map +1 -1
  130. package/dist/controllers/input_mask_controller.d.ts +5 -2
  131. package/dist/controllers/input_mask_controller.js +116 -61
  132. package/dist/controllers/input_mask_controller.js.map +1 -1
  133. package/dist/controllers/intersection_controller.d.ts +32 -13
  134. package/dist/controllers/intersection_controller.js +147 -103
  135. package/dist/controllers/intersection_controller.js.map +1 -1
  136. package/dist/controllers/lazy_frame_controller.d.ts +16 -0
  137. package/dist/controllers/lazy_frame_controller.js +9 -56
  138. package/dist/controllers/lazy_frame_controller.js.map +1 -1
  139. package/dist/controllers/listbox_controller.d.ts +84 -10
  140. package/dist/controllers/listbox_controller.js +413 -153
  141. package/dist/controllers/listbox_controller.js.map +1 -1
  142. package/dist/controllers/local_time_controller.d.ts +1 -1
  143. package/dist/controllers/local_time_controller.js +54 -64
  144. package/dist/controllers/local_time_controller.js.map +1 -1
  145. package/dist/controllers/masonry_controller.d.ts +11 -3
  146. package/dist/controllers/masonry_controller.js +70 -95
  147. package/dist/controllers/masonry_controller.js.map +1 -1
  148. package/dist/controllers/menu_controller.d.ts +40 -9
  149. package/dist/controllers/menu_controller.js +254 -167
  150. package/dist/controllers/menu_controller.js.map +1 -1
  151. package/dist/controllers/menubar_controller.d.ts +15 -4
  152. package/dist/controllers/menubar_controller.js +206 -331
  153. package/dist/controllers/menubar_controller.js.map +1 -1
  154. package/dist/controllers/meter_controller.d.ts +20 -0
  155. package/dist/controllers/meter_controller.js +159 -71
  156. package/dist/controllers/meter_controller.js.map +1 -1
  157. package/dist/controllers/multi_select_controller.d.ts +50 -7
  158. package/dist/controllers/multi_select_controller.js +797 -388
  159. package/dist/controllers/multi_select_controller.js.map +1 -1
  160. package/dist/controllers/navigation_menu_controller.d.ts +19 -1
  161. package/dist/controllers/navigation_menu_controller.js +156 -231
  162. package/dist/controllers/navigation_menu_controller.js.map +1 -1
  163. package/dist/controllers/nested_form_controller.d.ts +10 -0
  164. package/dist/controllers/nested_form_controller.js +373 -174
  165. package/dist/controllers/nested_form_controller.js.map +1 -1
  166. package/dist/controllers/network_status_controller.d.ts +23 -0
  167. package/dist/controllers/network_status_controller.js +241 -45
  168. package/dist/controllers/network_status_controller.js.map +1 -1
  169. package/dist/controllers/number_input_controller.d.ts +62 -10
  170. package/dist/controllers/number_input_controller.js +387 -227
  171. package/dist/controllers/number_input_controller.js.map +1 -1
  172. package/dist/controllers/optimistic_controller.js +28 -75
  173. package/dist/controllers/optimistic_controller.js.map +1 -1
  174. package/dist/controllers/otp_controller.d.ts +38 -7
  175. package/dist/controllers/otp_controller.js +344 -196
  176. package/dist/controllers/otp_controller.js.map +1 -1
  177. package/dist/controllers/overflow_indicator_controller.d.ts +13 -12
  178. package/dist/controllers/overflow_indicator_controller.js +167 -93
  179. package/dist/controllers/overflow_indicator_controller.js.map +1 -1
  180. package/dist/controllers/overflow_menu_controller.d.ts +66 -9
  181. package/dist/controllers/overflow_menu_controller.js +408 -277
  182. package/dist/controllers/overflow_menu_controller.js.map +1 -1
  183. package/dist/controllers/pagination_controller.d.ts +52 -15
  184. package/dist/controllers/pagination_controller.js +342 -120
  185. package/dist/controllers/pagination_controller.js.map +1 -1
  186. package/dist/controllers/password_reveal_controller.d.ts +60 -9
  187. package/dist/controllers/password_reveal_controller.js +424 -99
  188. package/dist/controllers/password_reveal_controller.js.map +1 -1
  189. package/dist/controllers/password_strength_controller.d.ts +14 -5
  190. package/dist/controllers/password_strength_controller.js +99 -153
  191. package/dist/controllers/password_strength_controller.js.map +1 -1
  192. package/dist/controllers/persist_controller.d.ts +11 -4
  193. package/dist/controllers/persist_controller.js +252 -96
  194. package/dist/controllers/persist_controller.js.map +1 -1
  195. package/dist/controllers/pointer_drag_controller.d.ts +19 -7
  196. package/dist/controllers/pointer_drag_controller.js +263 -164
  197. package/dist/controllers/pointer_drag_controller.js.map +1 -1
  198. package/dist/controllers/popover_controller.d.ts +46 -4
  199. package/dist/controllers/popover_controller.js +267 -94
  200. package/dist/controllers/popover_controller.js.map +1 -1
  201. package/dist/controllers/portal_controller.d.ts +44 -4
  202. package/dist/controllers/portal_controller.js +209 -72
  203. package/dist/controllers/portal_controller.js.map +1 -1
  204. package/dist/controllers/preview_guard_controller.d.ts +10 -4
  205. package/dist/controllers/preview_guard_controller.js +243 -112
  206. package/dist/controllers/preview_guard_controller.js.map +1 -1
  207. package/dist/controllers/progress_controller.d.ts +11 -0
  208. package/dist/controllers/progress_controller.js +132 -59
  209. package/dist/controllers/progress_controller.js.map +1 -1
  210. package/dist/controllers/radio_group_controller.d.ts +19 -8
  211. package/dist/controllers/radio_group_controller.js +138 -133
  212. package/dist/controllers/radio_group_controller.js.map +1 -1
  213. package/dist/controllers/range_slider_controller.d.ts +92 -4
  214. package/dist/controllers/range_slider_controller.js +245 -112
  215. package/dist/controllers/range_slider_controller.js.map +1 -1
  216. package/dist/controllers/rating_controller.d.ts +33 -6
  217. package/dist/controllers/rating_controller.js +429 -194
  218. package/dist/controllers/rating_controller.js.map +1 -1
  219. package/dist/controllers/read_more_controller.d.ts +26 -2
  220. package/dist/controllers/read_more_controller.js +185 -47
  221. package/dist/controllers/read_more_controller.js.map +1 -1
  222. package/dist/controllers/reading_progress_controller.d.ts +1 -1
  223. package/dist/controllers/reading_progress_controller.js +147 -135
  224. package/dist/controllers/reading_progress_controller.js.map +1 -1
  225. package/dist/controllers/relative_time_controller.d.ts +18 -4
  226. package/dist/controllers/relative_time_controller.js +145 -110
  227. package/dist/controllers/relative_time_controller.js.map +1 -1
  228. package/dist/controllers/reset_on_restore_controller.d.ts +85 -0
  229. package/dist/controllers/{reset_before_cache_controller.js → reset_on_restore_controller.js} +97 -38
  230. package/dist/controllers/reset_on_restore_controller.js.map +1 -0
  231. package/dist/controllers/resizable_controller.d.ts +44 -4
  232. package/dist/controllers/resizable_controller.js +294 -118
  233. package/dist/controllers/resizable_controller.js.map +1 -1
  234. package/dist/controllers/roving_controller.js +39 -84
  235. package/dist/controllers/roving_controller.js.map +1 -1
  236. package/dist/controllers/scroll_area_controller.d.ts +7 -3
  237. package/dist/controllers/scroll_area_controller.js +428 -221
  238. package/dist/controllers/scroll_area_controller.js.map +1 -1
  239. package/dist/controllers/scroll_restore_controller.js +0 -53
  240. package/dist/controllers/scroll_restore_controller.js.map +1 -1
  241. package/dist/controllers/scroll_visibility_controller.d.ts +28 -12
  242. package/dist/controllers/scroll_visibility_controller.js +395 -146
  243. package/dist/controllers/scroll_visibility_controller.js.map +1 -1
  244. package/dist/controllers/scrollspy_controller.d.ts +9 -3
  245. package/dist/controllers/scrollspy_controller.js +181 -236
  246. package/dist/controllers/scrollspy_controller.js.map +1 -1
  247. package/dist/controllers/separator_controller.d.ts +59 -17
  248. package/dist/controllers/separator_controller.js +288 -132
  249. package/dist/controllers/separator_controller.js.map +1 -1
  250. package/dist/controllers/sidebar_controller.d.ts +81 -7
  251. package/dist/controllers/sidebar_controller.js +1071 -375
  252. package/dist/controllers/sidebar_controller.js.map +1 -1
  253. package/dist/controllers/skeleton_controller.d.ts +23 -0
  254. package/dist/controllers/skeleton_controller.js +248 -92
  255. package/dist/controllers/skeleton_controller.js.map +1 -1
  256. package/dist/controllers/slider_controller.d.ts +72 -8
  257. package/dist/controllers/slider_controller.js +211 -96
  258. package/dist/controllers/slider_controller.js.map +1 -1
  259. package/dist/controllers/smart_sticky_header_controller.d.ts +21 -3
  260. package/dist/controllers/smart_sticky_header_controller.js +163 -54
  261. package/dist/controllers/smart_sticky_header_controller.js.map +1 -1
  262. package/dist/controllers/sortable_controller.js +13 -110
  263. package/dist/controllers/sortable_controller.js.map +1 -1
  264. package/dist/controllers/spinner_controller.d.ts +39 -4
  265. package/dist/controllers/spinner_controller.js +277 -161
  266. package/dist/controllers/spinner_controller.js.map +1 -1
  267. package/dist/controllers/step_indicator_controller.d.ts +24 -17
  268. package/dist/controllers/step_indicator_controller.js +107 -53
  269. package/dist/controllers/step_indicator_controller.js.map +1 -1
  270. package/dist/controllers/stepper_controller.d.ts +43 -9
  271. package/dist/controllers/stepper_controller.js +171 -48
  272. package/dist/controllers/stepper_controller.js.map +1 -1
  273. package/dist/controllers/stick_to_bottom_controller.d.ts +25 -0
  274. package/dist/controllers/stick_to_bottom_controller.js +310 -116
  275. package/dist/controllers/stick_to_bottom_controller.js.map +1 -1
  276. package/dist/controllers/sticky_observer_controller.d.ts +11 -0
  277. package/dist/controllers/sticky_observer_controller.js +214 -49
  278. package/dist/controllers/sticky_observer_controller.js.map +1 -1
  279. package/dist/controllers/submit_once_controller.d.ts +22 -6
  280. package/dist/controllers/submit_once_controller.js +294 -192
  281. package/dist/controllers/submit_once_controller.js.map +1 -1
  282. package/dist/controllers/switch_controller.d.ts +40 -7
  283. package/dist/controllers/switch_controller.js +107 -43
  284. package/dist/controllers/switch_controller.js.map +1 -1
  285. package/dist/controllers/tabs_controller.d.ts +13 -1
  286. package/dist/controllers/tabs_controller.js +50 -25
  287. package/dist/controllers/tabs_controller.js.map +1 -1
  288. package/dist/controllers/tags_input_controller.d.ts +27 -3
  289. package/dist/controllers/tags_input_controller.js +290 -149
  290. package/dist/controllers/tags_input_controller.js.map +1 -1
  291. package/dist/controllers/textarea_autosize_controller.d.ts +10 -0
  292. package/dist/controllers/textarea_autosize_controller.js +71 -58
  293. package/dist/controllers/textarea_autosize_controller.js.map +1 -1
  294. package/dist/controllers/theme_controller.d.ts +37 -8
  295. package/dist/controllers/theme_controller.js +148 -80
  296. package/dist/controllers/theme_controller.js.map +1 -1
  297. package/dist/controllers/time_picker_controller.d.ts +18 -1
  298. package/dist/controllers/time_picker_controller.js +162 -81
  299. package/dist/controllers/time_picker_controller.js.map +1 -1
  300. package/dist/controllers/toast_controller.d.ts +85 -23
  301. package/dist/controllers/toast_controller.js +365 -193
  302. package/dist/controllers/toast_controller.js.map +1 -1
  303. package/dist/controllers/toggle_group_controller.d.ts +60 -9
  304. package/dist/controllers/toggle_group_controller.js +194 -99
  305. package/dist/controllers/toggle_group_controller.js.map +1 -1
  306. package/dist/controllers/toolbar_controller.js +92 -90
  307. package/dist/controllers/toolbar_controller.js.map +1 -1
  308. package/dist/controllers/tooltip_controller.d.ts +52 -2
  309. package/dist/controllers/tooltip_controller.js +185 -125
  310. package/dist/controllers/tooltip_controller.js.map +1 -1
  311. package/dist/controllers/transition_controller.d.ts +22 -4
  312. package/dist/controllers/transition_controller.js +123 -115
  313. package/dist/controllers/transition_controller.js.map +1 -1
  314. package/dist/controllers/tree_view_controller.d.ts +59 -18
  315. package/dist/controllers/tree_view_controller.js +248 -290
  316. package/dist/controllers/tree_view_controller.js.map +1 -1
  317. package/dist/index.d.ts +33 -3
  318. package/dist/index.js +8649 -8572
  319. package/dist/index.js.map +1 -1
  320. package/dist/inspector/cli.d.ts +95 -9
  321. package/dist/inspector/cli.js +343 -77
  322. package/dist/inspector/cli.js.map +1 -1
  323. package/dist/inspector/cli_bin.js +390 -96
  324. package/dist/inspector/cli_bin.js.map +1 -1
  325. package/dist/inspector/examples.json +45 -45
  326. package/dist/inspector/manifest.json +1308 -155
  327. package/dist/positioning/index.d.ts +8 -0
  328. package/dist/positioning/index.js +148 -45
  329. package/dist/positioning/index.js.map +1 -1
  330. package/package.json +7 -7
  331. package/dist/controllers/reset_before_cache_controller.d.ts +0 -76
  332. package/dist/controllers/reset_before_cache_controller.js.map +0 -1
@@ -3,9 +3,6 @@ import { relative, join, dirname, extname } from 'path';
3
3
  import process from 'process';
4
4
  import { fileURLToPath } from 'url';
5
5
 
6
- // src/inspector/cli.ts
7
-
8
- // src/inspector/announcer_rules.ts
9
6
  var ANNOUNCER_IDENTIFIER = "stimeo--announcer";
10
7
  var ANNOUNCING_CONTROLLERS = [
11
8
  "stimeo--auto-submit",
@@ -69,7 +66,30 @@ function announcerSeatingDiagnostic(sources) {
69
66
  };
70
67
  }
71
68
 
72
- // src/utils/declared_value.ts
69
+ function matchesNumberBounds(value, bounds) {
70
+ if (!Number.isFinite(value)) {
71
+ const direction = value === Infinity ? "positive" : value === -Infinity ? "negative" : null;
72
+ if (direction === null) return false;
73
+ if (bounds.allowInfinity !== "both" && bounds.allowInfinity !== direction) return false;
74
+ }
75
+ if (bounds.min !== void 0 && value < bounds.min) return false;
76
+ if (bounds.max !== void 0 && value > bounds.max) return false;
77
+ if (bounds.exclusiveMin !== void 0 && value <= bounds.exclusiveMin) return false;
78
+ if (bounds.integer && !Number.isInteger(value)) return false;
79
+ if (bounds.allowedValues !== void 0 && !bounds.allowedValues.includes(value)) return false;
80
+ return true;
81
+ }
82
+ function decodeNumberValue(raw) {
83
+ return Number(raw.replace(/_/g, ""));
84
+ }
85
+
86
+ function toFiniteNumber(raw) {
87
+ if (typeof raw !== "number" && typeof raw !== "string") return null;
88
+ if (typeof raw === "string" && raw.trim().length === 0) return null;
89
+ const value = Number(raw);
90
+ return Number.isFinite(value) ? value : null;
91
+ }
92
+
73
93
  function parseDeclared(raw, parse, fallback) {
74
94
  try {
75
95
  return parse(raw);
@@ -93,7 +113,6 @@ function parseJsonObject(raw) {
93
113
  return parsed;
94
114
  }
95
115
 
96
- // src/inspector/html_parser.ts
97
116
  var ERB_ELEMENT_TAG = "#erb";
98
117
  var VOID_ELEMENTS = /* @__PURE__ */ new Set([
99
118
  "area",
@@ -342,7 +361,6 @@ function walk(root, visit) {
342
361
  }
343
362
  }
344
363
 
345
- // src/inspector/ruby_scan.ts
346
364
  var SPACE = /* @__PURE__ */ new Set([" ", " ", "\n", "\r", "\f"]);
347
365
  var IDENT_START = /[A-Za-z_]/;
348
366
  var IDENT_CHAR = /[A-Za-z0-9_]/;
@@ -581,7 +599,6 @@ function heredocEnd(code, bodyStart, identifier) {
581
599
  return code.length;
582
600
  }
583
601
 
584
- // src/inspector/ruby_hash.ts
585
602
  function readDataOption(source, base) {
586
603
  const code = maskHeredocs(source);
587
604
  const attrs = [];
@@ -786,7 +803,6 @@ function skipValue(code, start) {
786
803
  return code.length;
787
804
  }
788
805
 
789
- // src/inspector/erb.ts
790
806
  var ERB_TAG = /<%[\s\S]*?%>/g;
791
807
  function neutralizeErb(source) {
792
808
  return source.replace(ERB_TAG, (match) => match.replace(/[^\n]/g, " "));
@@ -810,7 +826,6 @@ function erbElements(source) {
810
826
  tag: ERB_ELEMENT_TAG,
811
827
  attrs: option.attrs.map((attr) => toParsedAttr(attr, index)),
812
828
  start: tag.start,
813
- // The token a reader can act on is the delimiter that opens the call.
814
829
  sourceLength: tag.codeStart - tag.start,
815
830
  end,
816
831
  container: end > tag.end,
@@ -849,7 +864,6 @@ function readErbTags(source) {
849
864
  }
850
865
  let close = raw.length - 2;
851
866
  if (raw[close - 1] === "-") close--;
852
- if (close < open) close = open;
853
867
  tags.push({
854
868
  start,
855
869
  end: start + raw.length,
@@ -975,17 +989,28 @@ function identifierEnd(code, start) {
975
989
  return end;
976
990
  }
977
991
 
978
- // src/inspector/extract.ts
979
992
  var NAMESPACE_PREFIX = "stimeo--";
980
993
  function dasherize(value) {
981
994
  return value.replace(/([A-Z])/g, (_match, char) => `-${char.toLowerCase()}`);
982
995
  }
983
- function controllerIdentifiers(dataControllerValue) {
996
+ function attributeTokens(value) {
997
+ const tokens = [];
984
998
  const seen = /* @__PURE__ */ new Set();
985
- for (const token of dataControllerValue.split(/\s+/)) {
986
- if (token.startsWith(NAMESPACE_PREFIX)) seen.add(token);
999
+ const pattern = /\S+/g;
1000
+ for (let match = pattern.exec(value); match; match = pattern.exec(value)) {
1001
+ if (seen.has(match[0])) continue;
1002
+ seen.add(match[0]);
1003
+ tokens.push({ name: match[0], start: match.index });
987
1004
  }
988
- return [...seen];
1005
+ return tokens;
1006
+ }
1007
+ function controllerIdentifiers(dataControllerValue) {
1008
+ return controllerIdentifierTokens(dataControllerValue).map((token) => token.name);
1009
+ }
1010
+ function controllerIdentifierTokens(dataControllerValue) {
1011
+ return attributeTokens(dataControllerValue).filter(
1012
+ (token) => token.name.startsWith(NAMESPACE_PREFIX)
1013
+ );
989
1014
  }
990
1015
  function parseTargetAttr(attrName) {
991
1016
  const match = /^data-(stimeo--[a-z0-9][a-z0-9-]*)-target$/.exec(attrName);
@@ -1027,7 +1052,7 @@ function defaultEventFor(host) {
1027
1052
  }
1028
1053
  function actionDescriptors(dataActionValue, host) {
1029
1054
  const descriptors = [];
1030
- for (const descriptor of dataActionValue.split(/\s+/)) {
1055
+ for (const { name: descriptor, start } of attributeTokens(dataActionValue)) {
1031
1056
  const hash = descriptor.indexOf("#");
1032
1057
  if (hash === -1) continue;
1033
1058
  let lhs = descriptor.slice(0, hash);
@@ -1043,7 +1068,14 @@ function actionDescriptors(dataActionValue, host) {
1043
1068
  }
1044
1069
  if (!lhs.startsWith(NAMESPACE_PREFIX)) continue;
1045
1070
  const method = /^[a-zA-Z_$][\w$]*/.exec(descriptor.slice(hash + 1))?.[0] ?? "";
1046
- descriptors.push({ identifier: lhs, method, eventType });
1071
+ descriptors.push({
1072
+ identifier: lhs,
1073
+ identifierStart: start + (arrow === -1 ? 0 : arrow + 2),
1074
+ method,
1075
+ methodStart: start + hash + 1,
1076
+ eventType,
1077
+ eventStart: start
1078
+ });
1047
1079
  }
1048
1080
  return descriptors;
1049
1081
  }
@@ -1051,7 +1083,6 @@ function isStimeoDataAttr(attrName) {
1051
1083
  return attrName.startsWith(`data-${NAMESPACE_PREFIX}`);
1052
1084
  }
1053
1085
 
1054
- // src/inspector/types.ts
1055
1086
  var DIAGNOSTIC_CODES = [
1056
1087
  "unknown-controller",
1057
1088
  "unknown-target",
@@ -1059,9 +1090,11 @@ var DIAGNOSTIC_CODES = [
1059
1090
  "invalid-value",
1060
1091
  "unknown-action-controller",
1061
1092
  "unknown-action-method",
1093
+ "unknown-action-event",
1062
1094
  "orphan-target",
1063
1095
  "missing-required-target",
1064
1096
  "missing-conditional-target",
1097
+ "invalid-template-root",
1065
1098
  "missing-required-action",
1066
1099
  "missing-action-completion",
1067
1100
  "missing-action-event",
@@ -1077,11 +1110,13 @@ var DIAGNOSTIC_CODES = [
1077
1110
  "cardinality-violation",
1078
1111
  "forbidden-aria",
1079
1112
  "missing-announcer",
1113
+ "missing-action-param",
1114
+ "invalid-action-param",
1115
+ "confusable-action-param",
1080
1116
  "unknown-ignore-code"
1081
1117
  ];
1082
1118
 
1083
- // src/inspector/check.ts
1084
- function isInside(node, ancestor) {
1119
+ function isDescendantOf(node, ancestor) {
1085
1120
  for (let current = node.parent; current; current = current.parent) {
1086
1121
  if (current === ancestor) return true;
1087
1122
  }
@@ -1174,11 +1209,13 @@ function checkSource(source, manifest) {
1174
1209
  const unnamedTargets = [];
1175
1210
  const targetsUnreadable = (container, scope, identifier) => {
1176
1211
  for (const node of unresolved) {
1177
- if (isWithin(node, container) && findOwner(node, identifier) === scope) return true;
1212
+ if (isSelfOrDescendantOf(node, container) && findOwner(node, identifier) === scope)
1213
+ return true;
1178
1214
  }
1179
1215
  for (const { node, identifier: hidden } of unnamedTargets) {
1180
1216
  if (hidden !== identifier) continue;
1181
- if (isWithin(node, container) && findOwner(node, identifier) === scope) return true;
1217
+ if (isSelfOrDescendantOf(node, container) && findOwner(node, identifier) === scope)
1218
+ return true;
1182
1219
  }
1183
1220
  return false;
1184
1221
  };
@@ -1237,7 +1274,7 @@ function checkSource(source, manifest) {
1237
1274
  const nodes = targetNodes.get(scope)?.get(identifier)?.get(condition.target) ?? [];
1238
1275
  const container = condition.within === "scope" ? scope : element;
1239
1276
  let held = 0;
1240
- for (const node of nodes) if (isWithin(node, container)) held += 1;
1277
+ for (const node of nodes) if (isSelfOrDescendantOf(node, container)) held += 1;
1241
1278
  if (condition.min !== void 0 && held < condition.min) return false;
1242
1279
  if (condition.max !== void 0 && held > condition.max) return false;
1243
1280
  return true;
@@ -1274,9 +1311,9 @@ function checkSource(source, manifest) {
1274
1311
  const authoredValueIdentifiers = /* @__PURE__ */ new Set();
1275
1312
  for (const attr of node.attrs) {
1276
1313
  if (attr.name === IGNORE_ATTR) {
1277
- for (const token of attr.value.split(/\s+/).filter((t) => t.length > 0)) {
1278
- if (!DIAGNOSTIC_CODES.includes(token)) {
1279
- const best = nearestName(token, DIAGNOSTIC_CODES);
1314
+ for (const token of attributeTokens(attr.value)) {
1315
+ if (!DIAGNOSTIC_CODES.includes(token.name)) {
1316
+ const best = nearestName(token.name, DIAGNOSTIC_CODES);
1280
1317
  push(
1281
1318
  diagnostics,
1282
1319
  "unknown-ignore-code",
@@ -1291,7 +1328,7 @@ function checkSource(source, manifest) {
1291
1328
  continue;
1292
1329
  }
1293
1330
  if (attr.name === FRAGMENT_ATTR) {
1294
- const identifiers = attr.value.split(/\s+/).filter((token) => token.length > 0);
1331
+ const identifiers = attributeTokens(attr.value);
1295
1332
  if (identifiers.length === 0) {
1296
1333
  report(
1297
1334
  node,
@@ -1302,13 +1339,13 @@ function checkSource(source, manifest) {
1302
1339
  );
1303
1340
  }
1304
1341
  for (const identifier of identifiers) {
1305
- if (!(identifier in known)) {
1306
- const best = nearestName(identifier, knownIdentifiers);
1342
+ if (!(identifier.name in known)) {
1343
+ const best = nearestName(identifier.name, knownIdentifiers);
1307
1344
  report(
1308
1345
  node,
1309
1346
  "unknown-controller",
1310
1347
  "error",
1311
- `Fragment declaration references unknown Stimeo controller "${identifier}".`,
1348
+ `Fragment declaration references unknown Stimeo controller "${identifier.name}".`,
1312
1349
  attr,
1313
1350
  asDidYouMean(best),
1314
1351
  tokenFix(attr, identifier, best)
@@ -1318,7 +1355,8 @@ function checkSource(source, manifest) {
1318
1355
  continue;
1319
1356
  }
1320
1357
  if (attr.name === "data-controller") {
1321
- for (const identifier of controllerIdentifiers(attr.value)) {
1358
+ for (const token of controllerIdentifierTokens(attr.value)) {
1359
+ const identifier = token.name;
1322
1360
  if (identifier in known) {
1323
1361
  scopes.push({ node, identifier });
1324
1362
  } else {
@@ -1330,7 +1368,7 @@ function checkSource(source, manifest) {
1330
1368
  `Unknown Stimeo controller "${identifier}".`,
1331
1369
  attr,
1332
1370
  asDidYouMean(best),
1333
- tokenFix(attr, identifier, best)
1371
+ tokenFix(attr, token, best)
1334
1372
  );
1335
1373
  }
1336
1374
  }
@@ -1350,24 +1388,27 @@ function checkSource(source, manifest) {
1350
1388
  );
1351
1389
  continue;
1352
1390
  }
1353
- const targetName = isDynamicValue(attr) ? "" : attr.value.trim();
1354
- if (targetName.length > 0 && !controller.targets.includes(targetName)) {
1355
- const best = nearestName(targetName, controller.targets);
1391
+ const declared = isDynamicValue(attr) ? [] : attributeTokens(attr.value);
1392
+ for (const token of declared) {
1393
+ if (controller.targets.includes(token.name)) continue;
1394
+ const best = nearestName(token.name, controller.targets);
1356
1395
  report(
1357
1396
  node,
1358
1397
  "unknown-target",
1359
1398
  "error",
1360
- `Unknown target "${targetName}" for "${targetIdentifier}". Known targets: ${list(controller.targets)}.`,
1399
+ `Unknown target "${token.name}" for "${targetIdentifier}". Known targets: ${list(controller.targets)}.`,
1361
1400
  attr,
1362
1401
  asDidYouMean(best),
1363
- tokenFix(attr, targetName, best)
1402
+ tokenFix(attr, token, best)
1364
1403
  );
1365
1404
  }
1366
1405
  const owner = findOwner(node, targetIdentifier);
1367
1406
  if (owner) {
1368
- if (targetName.length > 0) {
1369
- recordPresence(owner, targetIdentifier, targetName);
1370
- recordTargetNode(owner, targetIdentifier, targetName, node);
1407
+ if (declared.length > 0) {
1408
+ for (const token of declared) {
1409
+ recordPresence(owner, targetIdentifier, token.name);
1410
+ recordTargetNode(owner, targetIdentifier, token.name, node);
1411
+ }
1371
1412
  } else if (isDynamicValue(attr)) {
1372
1413
  unnamedTargets.push({ node, identifier: targetIdentifier });
1373
1414
  }
@@ -1431,7 +1472,15 @@ function checkSource(source, manifest) {
1431
1472
  tag: node.tag,
1432
1473
  inputType: node.attrs.find((a) => a.name === "type")?.value
1433
1474
  };
1434
- for (const { identifier, method, eventType } of actionDescriptors(attr.value, host)) {
1475
+ const paramsChecked = /* @__PURE__ */ new Set();
1476
+ for (const {
1477
+ identifier,
1478
+ identifierStart,
1479
+ method,
1480
+ methodStart,
1481
+ eventType,
1482
+ eventStart
1483
+ } of actionDescriptors(attr.value, host)) {
1435
1484
  const controller = known[identifier];
1436
1485
  if (controller && method.length > 0) {
1437
1486
  const owner = findOwner(node, identifier);
@@ -1456,7 +1505,7 @@ function checkSource(source, manifest) {
1456
1505
  `Action references unknown Stimeo controller "${identifier}".`,
1457
1506
  attr,
1458
1507
  asDidYouMean(best),
1459
- tokenFix(attr, identifier, best)
1508
+ tokenFix(attr, { name: identifier, start: identifierStart }, best)
1460
1509
  );
1461
1510
  } else if (method.length > 0 && !controller.actions.includes(method)) {
1462
1511
  const best = nearestName(method, controller.actions);
@@ -1467,11 +1516,138 @@ function checkSource(source, manifest) {
1467
1516
  `Unknown action "${method}" for "${identifier}". Known actions: ${list(controller.actions)}.`,
1468
1517
  attr,
1469
1518
  asDidYouMean(best),
1470
- tokenFix(attr, method, best)
1519
+ tokenFix(attr, { name: method, start: methodStart }, best)
1520
+ );
1521
+ }
1522
+ if (controller && method.length > 0 && !paramsChecked.has(`${identifier}#${method}`)) {
1523
+ paramsChecked.add(`${identifier}#${method}`);
1524
+ checkActionParams(node, attr, identifier, method, controller);
1525
+ }
1526
+ if (!isDynamicValue(attr)) {
1527
+ const emitted = /^(stimeo--[a-z0-9-]+):(.+)$/.exec(eventType);
1528
+ const source2 = emitted ? known[emitted[1]] : void 0;
1529
+ const name = emitted?.[2];
1530
+ if (source2 && name !== void 0 && !source2.events.includes(name)) {
1531
+ const best = nearestName(name, source2.events);
1532
+ report(
1533
+ node,
1534
+ "unknown-action-event",
1535
+ "error",
1536
+ `Unknown event "${name}" for "${emitted?.[1]}". Known events: ${list(source2.events)}.`,
1537
+ attr,
1538
+ asDidYouMean(best),
1539
+ tokenFix(attr, { name, start: eventStart + eventType.length - name.length }, best)
1540
+ );
1541
+ }
1542
+ }
1543
+ }
1544
+ }
1545
+ }
1546
+ function checkActionParams(element, action, identifier, method, controller) {
1547
+ const rules = controller.actionParams.filter((rule) => rule.action === method);
1548
+ if (rules.length === 0) return;
1549
+ const readable = !isDynamicValue(action) && element.origin === "markup" && !element.opaque;
1550
+ const expected = new Map(
1551
+ rules.map((rule) => [`data-${identifier}-${dasherize(rule.param)}-param`, rule])
1552
+ );
1553
+ for (const [attrName, rule] of expected) {
1554
+ const written = element.attrs.find((candidate) => candidate.name === attrName);
1555
+ if (!written) {
1556
+ if (!rule.required || !readable) continue;
1557
+ const confusable = confusableParamAttr(element, attrName, rule.param);
1558
+ report(
1559
+ element,
1560
+ "missing-action-param",
1561
+ "error",
1562
+ confusable ? `"${identifier}#${method}" reads its "${rule.param}" param, and "${confusable.name}" is not the attribute Stimulus builds it from.` : `"${identifier}#${method}" reads its "${rule.param}" param, which nothing on this element supplies.`,
1563
+ confusable ?? action,
1564
+ rule.suggestion
1565
+ );
1566
+ continue;
1567
+ }
1568
+ if (isDynamicValue(written)) continue;
1569
+ const value = written.value;
1570
+ if (value.length === 0) {
1571
+ if (!readable) continue;
1572
+ if (rule.numeric && !rule.required) {
1573
+ report(
1574
+ element,
1575
+ "invalid-action-param",
1576
+ "error",
1577
+ `"${value}" is not a finite "${rule.param}" this action reads.`,
1578
+ written,
1579
+ rule.suggestion
1580
+ );
1581
+ continue;
1582
+ }
1583
+ if (!rule.required) continue;
1584
+ report(
1585
+ element,
1586
+ "missing-action-param",
1587
+ "error",
1588
+ `"${identifier}#${method}" reads its "${rule.param}" param, and "${attrName}" carries no value.`,
1589
+ written,
1590
+ rule.suggestion
1591
+ );
1592
+ continue;
1593
+ }
1594
+ if (rule.numeric || rule.integer) {
1595
+ const numeric = toFiniteNumber(decodeActionParamLiteral(value));
1596
+ if (numeric === null || rule.integer && !Number.isInteger(numeric)) {
1597
+ report(
1598
+ element,
1599
+ "invalid-action-param",
1600
+ "error",
1601
+ `"${value}" is not an "${rule.param}" this action reads. It accepts ${rule.integer ? "a whole number" : "a finite number"}.`,
1602
+ written,
1603
+ rule.suggestion
1471
1604
  );
1605
+ continue;
1472
1606
  }
1473
1607
  }
1608
+ if (!rule.allowedValues || rule.allowedValues.includes(value)) continue;
1609
+ const best = nearestName(value, rule.allowedValues);
1610
+ report(
1611
+ element,
1612
+ "invalid-action-param",
1613
+ "error",
1614
+ `"${value}" is not a "${rule.param}" this action reads. It accepts ${list(rule.allowedValues)}.`,
1615
+ written,
1616
+ asDidYouMean(best) ?? rule.suggestion,
1617
+ best !== void 0 && written.valueStart !== void 0 ? {
1618
+ start: written.valueStart,
1619
+ end: written.valueStart + written.value.length,
1620
+ text: best,
1621
+ title: `Replace with "${best}"`
1622
+ } : void 0
1623
+ );
1474
1624
  }
1625
+ if (!readable) return;
1626
+ for (const candidate of element.attrs) {
1627
+ if (!candidate.name.startsWith(`data-${identifier}-`)) continue;
1628
+ if (expected.has(candidate.name)) continue;
1629
+ if (parseTargetAttr(candidate.name) || candidate.name.endsWith("-value")) continue;
1630
+ const best = [...expected.keys()].find((name) => namesTheParam(candidate.name, name));
1631
+ if (best === void 0) continue;
1632
+ report(
1633
+ element,
1634
+ "confusable-action-param",
1635
+ "warning",
1636
+ `"${candidate.name}" is not an attribute Stimulus reads. Action params are named "<param>-param".`,
1637
+ candidate,
1638
+ `Did you mean ${best}?`
1639
+ );
1640
+ }
1641
+ }
1642
+ function namesTheParam(written, attrName) {
1643
+ if (written === attrName) return false;
1644
+ return `${written}-param` === attrName || nearestName(written, [attrName]) !== void 0;
1645
+ }
1646
+ function confusableParamAttr(element, attrName, param) {
1647
+ const bare = `data-${dasherize(param)}`;
1648
+ return element.attrs.find(
1649
+ (candidate) => candidate.name === bare || namesTheParam(candidate.name, attrName)
1650
+ );
1475
1651
  }
1476
1652
  for (const identifier of authoredValueIdentifiers) {
1477
1653
  const controller = known[identifier];
@@ -1532,19 +1708,30 @@ function checkSource(source, manifest) {
1532
1708
  const owners = nodesOf(rule.whenPresent);
1533
1709
  const hosts = rule.requireSameHost;
1534
1710
  const sharesHost = (target, selectors) => {
1535
- const ownerHosts = owners.map((owner) => nearestHost(owner, selectors));
1536
- if (ownerHosts.some((host) => !host)) return true;
1711
+ const hostOf = (el) => nearestHost(el, selectors);
1712
+ const ownerHosts = owners.map(hostOf).filter((host) => host !== null && host !== void 0);
1537
1713
  const candidates = nodesOf(target);
1538
- if (candidates.length === 0) return false;
1539
- return candidates.some((el) => {
1540
- const host = nearestHost(el, selectors);
1541
- return host ? ownerHosts.includes(host) : true;
1542
- });
1714
+ return ownerHosts.every(
1715
+ (ownerHost) => candidates.some((el) => {
1716
+ const host = hostOf(el);
1717
+ if (host === null) return false;
1718
+ return host ? host === ownerHost : true;
1719
+ })
1720
+ );
1721
+ };
1722
+ const sharesTargetHost = (target, hostTarget) => {
1723
+ const hostNodes = nodesOf(hostTarget);
1724
+ const hostOf = (el) => hostNodes.find((host) => isDescendantOf(el, host)) ?? null;
1725
+ const ownerHosts = owners.map(hostOf).filter((host) => host !== null);
1726
+ const candidates = nodesOf(target);
1727
+ return ownerHosts.every((ownerHost) => candidates.some((el) => hostOf(el) === ownerHost));
1543
1728
  };
1544
1729
  const satisfied = (target) => {
1730
+ const hostTarget = rule.requireSameTargetHost;
1731
+ if (hostTarget) return sharesTargetHost(target, hostTarget);
1545
1732
  if (hosts) return sharesHost(target, hosts);
1546
1733
  if (rule.requireInside)
1547
- return nodesOf(target).some((el) => owners.some((owner) => isInside(el, owner)));
1734
+ return nodesOf(target).some((el) => owners.some((owner) => isDescendantOf(el, owner)));
1548
1735
  return present.has(target);
1549
1736
  };
1550
1737
  const missing = rule.require.filter((target) => !satisfied(target));
@@ -1553,12 +1740,62 @@ function checkSource(source, manifest) {
1553
1740
  node,
1554
1741
  "missing-conditional-target",
1555
1742
  complete ? "error" : "warning",
1556
- hosts ? `"${identifier}" requires ${list(missing)} in the same ${rule.hostLabel ?? "element"} as its "${rule.whenPresent}".` : rule.requireInside ? `"${identifier}" requires ${list(missing)} inside its "${rule.whenPresent}".` : `"${identifier}" has a "${rule.whenPresent}" target, which also requires ${list(missing)}.`,
1743
+ rule.requireSameTargetHost ? `"${identifier}" requires ${list(missing)} in the same "${rule.requireSameTargetHost}" as its "${rule.whenPresent}".` : hosts ? `"${identifier}" requires ${list(missing)} in the same ${rule.hostLabel ?? "element"} as its "${rule.whenPresent}".` : rule.requireInside ? `"${identifier}" requires ${list(missing)} inside its "${rule.whenPresent}".` : `"${identifier}" has a "${rule.whenPresent}" target, which also requires ${list(missing)}.`,
1557
1744
  node,
1558
1745
  complete ? rule.suggestion : UNRESOLVED_TARGET_HINT
1559
1746
  );
1560
1747
  }
1561
1748
  }
1749
+ for (const { node, identifier } of scopes) {
1750
+ const controller = known[identifier];
1751
+ if (!controller) continue;
1752
+ const complete = scopeIsComplete(node, node, identifier);
1753
+ const nodesOf = (target) => targetNodes.get(node)?.get(identifier)?.get(target) ?? [];
1754
+ const hint = complete ? void 0 : UNRESOLVED_TARGET_HINT;
1755
+ for (const rule of controller.templateRoots) {
1756
+ for (const template of nodesOf(rule.template)) {
1757
+ if (template.origin === "markup" && template.tag !== "template") {
1758
+ report(
1759
+ node,
1760
+ "invalid-template-root",
1761
+ complete ? "error" : "warning",
1762
+ `"${identifier}" requires its "${rule.template}" to be a <template>, and it is a <${template.tag}>.`,
1763
+ template,
1764
+ hint ?? rule.suggestion
1765
+ );
1766
+ continue;
1767
+ }
1768
+ if (template.children.some((child) => child.origin === "erb")) continue;
1769
+ const rows = template.children;
1770
+ const row = rows[0];
1771
+ if (rows.length === 0) continue;
1772
+ if (rows.length !== 1 || !row) {
1773
+ report(
1774
+ node,
1775
+ "invalid-template-root",
1776
+ complete ? "error" : "warning",
1777
+ `"${identifier}" requires its "${rule.template}" to hold exactly one element, and it holds ${rows.length}.`,
1778
+ template,
1779
+ hint ?? rule.suggestion
1780
+ );
1781
+ continue;
1782
+ }
1783
+ if (!rule.rootTarget) continue;
1784
+ if (unnamedTargets.some((entry) => entry.node === row && entry.identifier === identifier)) {
1785
+ continue;
1786
+ }
1787
+ if (nodesOf(rule.rootTarget).includes(row)) continue;
1788
+ report(
1789
+ node,
1790
+ "invalid-template-root",
1791
+ complete ? "error" : "warning",
1792
+ `"${identifier}" requires the one element in its "${rule.template}" to be its "${rule.rootTarget}" itself.`,
1793
+ row,
1794
+ hint ?? rule.suggestion
1795
+ );
1796
+ }
1797
+ }
1798
+ }
1562
1799
  for (const { node, identifier } of scopes) {
1563
1800
  const controller = known[identifier];
1564
1801
  if (!controller) continue;
@@ -1658,8 +1895,9 @@ function checkSource(source, manifest) {
1658
1895
  for (const element of elements) {
1659
1896
  if (!hasReadableMarkup(element)) continue;
1660
1897
  if (hostIsAllowed(element, rule) !== false) continue;
1661
- const type = element.attrs.find((attr) => attr.name === "type");
1662
- const detail = element.tag === "button" ? `the unsupported ${type ? `type="${type.value}"` : 'implicit type="submit"'}` : `an unsupported interactive <${element.tag}>`;
1898
+ const byType = element.tag === "button" && rule.mode !== "non-interactive";
1899
+ const type = byType ? element.attrs.find((attr) => attr.name === "type") : void 0;
1900
+ const detail = byType ? `the unsupported ${type ? `type="${type.value}"` : 'implicit type="submit"'}` : `an unsupported interactive <${element.tag}>`;
1663
1901
  report(
1664
1902
  element,
1665
1903
  "invalid-host",
@@ -1784,8 +2022,6 @@ function checkSource(source, manifest) {
1784
2022
  `The ${where} of "${identifier}" must also declare "${rule.controller}" in data-controller.`,
1785
2023
  declared ?? el,
1786
2024
  rule.suggestion,
1787
- // Appending to an existing list is unambiguous; creating the
1788
- // attribute from nothing is an insertion the anchor cannot express.
1789
2025
  declared ? valueFix(
1790
2026
  declared,
1791
2027
  `${declared.value.trim()} ${rule.controller}`.trim(),
@@ -1809,7 +2045,7 @@ function checkSource(source, manifest) {
1809
2045
  if (rule.values && !rule.values.includes(value)) continue;
1810
2046
  if (findOwner(el, identifier) !== node) continue;
1811
2047
  const declaredAs = el.attrs.find((a) => a.name === targetAttrName);
1812
- if (declaredAs && !isDynamicValue(declaredAs) && declaredAs.value.trim() === rule.target) {
2048
+ if (declaredAs && !isDynamicValue(declaredAs) && attributeTokens(declaredAs.value).some((token) => token.name === rule.target)) {
1813
2049
  continue;
1814
2050
  }
1815
2051
  if (declaredAs && isDynamicValue(declaredAs)) continue;
@@ -1837,7 +2073,7 @@ function checkSource(source, manifest) {
1837
2073
  for (const container of containers) {
1838
2074
  const matched = [];
1839
2075
  for (const el of counted) {
1840
- if (!isWithin(el, container)) continue;
2076
+ if (!isSelfOrDescendantOf(el, container)) continue;
1841
2077
  if (rule.attr === void 0) {
1842
2078
  matched.push({ el, at: el });
1843
2079
  continue;
@@ -1893,14 +2129,14 @@ function checkSource(source, manifest) {
1893
2129
  for (const el of anchored) {
1894
2130
  for (const attr of el.attrs) {
1895
2131
  if (!IDREF_ATTRS.has(attr.name) || isDynamicValue(attr)) continue;
1896
- for (const token of attr.value.split(/\s+/).filter((t) => t.length > 0)) {
1897
- if (!ids.has(token)) {
1898
- const best = nearestName(token, [...ids]);
2132
+ for (const token of attributeTokens(attr.value)) {
2133
+ if (!ids.has(token.name)) {
2134
+ const best = nearestName(token.name, [...ids]);
1899
2135
  report(
1900
2136
  el,
1901
2137
  "unresolved-idref",
1902
2138
  "warning",
1903
- `${attr.name} references id "${token}", but no element in this file declares it.`,
2139
+ `${attr.name} references id "${token.name}", but no element in this file declares it.`,
1904
2140
  attr,
1905
2141
  asDidYouMean(best),
1906
2142
  tokenFix(attr, token, best)
@@ -1920,14 +2156,20 @@ function declaredConstraint(controller, valueToken) {
1920
2156
  function valueSatisfiesConstraint(raw, constraint) {
1921
2157
  if (constraint.type === "string") return stringValueSatisfies(raw, constraint);
1922
2158
  const value = decodeNumericValue(raw);
1923
- if (Number.isNaN(value)) return false;
1924
- if (constraint.finite && !Number.isFinite(value)) return false;
2159
+ if (constraint.finite === true && !matchesNumberBounds(value, { ...constraint}))
2160
+ return false;
2161
+ if (constraint.finite !== true) {
2162
+ const bounds = {
2163
+ ...constraint,
2164
+ allowInfinity: constraint.allowInfinity ?? "both"
2165
+ };
2166
+ if (!matchesNumberBounds(value, bounds)) return false;
2167
+ }
1925
2168
  if (constraint.greaterThan !== void 0 && !(value > constraint.greaterThan)) return false;
1926
- if (constraint.integer && !Number.isInteger(value)) return false;
1927
2169
  return true;
1928
2170
  }
1929
2171
  function decodeNumericValue(raw) {
1930
- return Number(raw.replace(/_/g, ""));
2172
+ return decodeNumberValue(raw);
1931
2173
  }
1932
2174
  function stringValueSatisfies(raw, constraint) {
1933
2175
  if (!("syntax" in constraint)) return constraint.allowedValues.includes(raw);
@@ -1941,10 +2183,15 @@ function stringValueSatisfies(raw, constraint) {
1941
2183
  }
1942
2184
  function describeValueConstraint(constraint) {
1943
2185
  if (constraint.type === "string") return describeStringConstraint(constraint);
1944
- const parts = [constraint.finite ? "a finite number" : "a number"];
2186
+ const parts = [constraint.finite || constraint.allowInfinity ? "a finite number" : "a number"];
1945
2187
  if (constraint.greaterThan !== void 0) {
1946
2188
  parts.push(`greater than ${constraint.greaterThan}`);
1947
2189
  }
2190
+ if (constraint.exclusiveMin !== void 0) parts.push(`greater than ${constraint.exclusiveMin}`);
2191
+ if (constraint.min !== void 0) parts.push(`at least ${constraint.min}`);
2192
+ if (constraint.max !== void 0) parts.push(`at most ${constraint.max}`);
2193
+ if (constraint.allowedValues) parts.push(`among ${constraint.allowedValues.join(", ")}`);
2194
+ if (constraint.allowInfinity) parts.push(`or ${constraint.allowInfinity} infinity`);
1948
2195
  if (constraint.integer) parts.push("with no fractional part");
1949
2196
  return parts.join(" ");
1950
2197
  }
@@ -2016,7 +2263,7 @@ function checkA11y(report, el, identifier, req, severity, isDynamicValue) {
2016
2263
  );
2017
2264
  }
2018
2265
  }
2019
- function isWithin(node, container) {
2266
+ function isSelfOrDescendantOf(node, container) {
2020
2267
  let current = node;
2021
2268
  while (current) {
2022
2269
  if (current === container) return true;
@@ -2121,15 +2368,13 @@ function push(out, code, severity, message, at, suggestion, fix) {
2121
2368
  });
2122
2369
  }
2123
2370
  function tokenFix(attr, token, replacement) {
2124
- if (replacement === void 0 || attr.valueStart === void 0 || token.length === 0) {
2371
+ if (replacement === void 0 || attr.valueStart === void 0 || token.name.length === 0) {
2125
2372
  return void 0;
2126
2373
  }
2127
- const index = attr.value.indexOf(token);
2128
- if (index < 0) return void 0;
2129
- const start = attr.valueStart + index;
2374
+ const start = attr.valueStart + token.start;
2130
2375
  return {
2131
2376
  start,
2132
- end: start + token.length,
2377
+ end: start + token.name.length,
2133
2378
  text: replacement,
2134
2379
  title: `Replace with "${replacement}"`
2135
2380
  };
@@ -2142,7 +2387,7 @@ function list(names) {
2142
2387
  return names.length > 0 ? names.map((n) => `"${n}"`).join(", ") : "(none)";
2143
2388
  }
2144
2389
  function describeAttrs(attrs) {
2145
- return attrs.length === 1 ? attrs[0] : attrs.join(" or ");
2390
+ return attrs.join(" or ");
2146
2391
  }
2147
2392
  function nearestName(name, candidates) {
2148
2393
  if (name.length === 0) return void 0;
@@ -2184,8 +2429,14 @@ function levenshtein(a, b) {
2184
2429
  }
2185
2430
  return prev[cols];
2186
2431
  }
2432
+ function decodeActionParamLiteral(raw) {
2433
+ try {
2434
+ return JSON.parse(raw);
2435
+ } catch {
2436
+ return raw;
2437
+ }
2438
+ }
2187
2439
 
2188
- // src/inspector/examples.ts
2189
2440
  var EXAMPLES_SCHEMA_VERSION = 1;
2190
2441
  var CHECKABLE_FILE_EXTENSIONS = /* @__PURE__ */ new Set([".erb", ".html", ".htm"]);
2191
2442
  function isCheckableFile(path) {
@@ -2196,10 +2447,12 @@ var CONTROLLER_ARRAY_FIELDS = [
2196
2447
  "values",
2197
2448
  "valueConstraints",
2198
2449
  "valueRelations",
2450
+ "actionParams",
2199
2451
  "actions",
2200
2452
  "events",
2201
2453
  "requiredTargets",
2202
2454
  "conditionalTargets",
2455
+ "templateRoots",
2203
2456
  "requiredActions",
2204
2457
  "actionCompletion",
2205
2458
  "a11y",
@@ -2227,6 +2480,21 @@ function isCompatibleManifest(value) {
2227
2480
  for (const field of CONTROLLER_ARRAY_FIELDS) {
2228
2481
  if (!Array.isArray(entry[field])) return false;
2229
2482
  }
2483
+ const constraints = entry.valueConstraints;
2484
+ for (const constraint of constraints) {
2485
+ if (typeof constraint !== "object" || constraint === null) return false;
2486
+ const numeric = constraint;
2487
+ if (numeric.type !== "number") continue;
2488
+ for (const field of ["min", "max", "exclusiveMin"]) {
2489
+ const bound = numeric[field];
2490
+ if (bound !== void 0 && (typeof bound !== "number" || !Number.isFinite(bound)))
2491
+ return false;
2492
+ }
2493
+ if (numeric.allowedValues !== void 0 && (!Array.isArray(numeric.allowedValues) || !numeric.allowedValues.every((item) => typeof item === "number" && Number.isFinite(item))))
2494
+ return false;
2495
+ if (numeric.allowInfinity !== void 0 && !["negative", "positive", "both"].includes(String(numeric.allowInfinity)))
2496
+ return false;
2497
+ }
2230
2498
  }
2231
2499
  return true;
2232
2500
  }
@@ -2238,7 +2506,6 @@ function readManifestFile(path) {
2238
2506
  return parsed;
2239
2507
  }
2240
2508
 
2241
- // src/inspector/cli.ts
2242
2509
  function bundledPath(name) {
2243
2510
  return join(dirname(fileURLToPath(import.meta.url)), name);
2244
2511
  }
@@ -2441,5 +2708,4 @@ ${USAGE}`);
2441
2708
  }
2442
2709
 
2443
2710
  export { buildCheckReport, catalogSummary, formatGithubAnnotation, loadExamplesIndex, loadManifest, runCli, sortedControllerEntries };
2444
- //# sourceMappingURL=cli.js.map
2445
2711
  //# sourceMappingURL=cli.js.map