stimeo-ui 0.1.0-alpha.1

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 (238) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +72 -0
  3. package/dist/controllers/accordion_controller.d.ts +59 -0
  4. package/dist/controllers/accordion_controller.js +76 -0
  5. package/dist/controllers/accordion_controller.js.map +1 -0
  6. package/dist/controllers/announcer_controller.d.ts +78 -0
  7. package/dist/controllers/announcer_controller.js +184 -0
  8. package/dist/controllers/announcer_controller.js.map +1 -0
  9. package/dist/controllers/aspect_ratio_controller.d.ts +39 -0
  10. package/dist/controllers/aspect_ratio_controller.js +36 -0
  11. package/dist/controllers/aspect_ratio_controller.js.map +1 -0
  12. package/dist/controllers/auto_submit_controller.d.ts +74 -0
  13. package/dist/controllers/auto_submit_controller.js +147 -0
  14. package/dist/controllers/auto_submit_controller.js.map +1 -0
  15. package/dist/controllers/avatar_controller.d.ts +50 -0
  16. package/dist/controllers/avatar_controller.js +66 -0
  17. package/dist/controllers/avatar_controller.js.map +1 -0
  18. package/dist/controllers/breadcrumb_controller.d.ts +60 -0
  19. package/dist/controllers/breadcrumb_controller.js +123 -0
  20. package/dist/controllers/breadcrumb_controller.js.map +1 -0
  21. package/dist/controllers/bulk_select_controller.d.ts +67 -0
  22. package/dist/controllers/bulk_select_controller.js +104 -0
  23. package/dist/controllers/bulk_select_controller.js.map +1 -0
  24. package/dist/controllers/calendar_controller.d.ts +100 -0
  25. package/dist/controllers/calendar_controller.js +394 -0
  26. package/dist/controllers/calendar_controller.js.map +1 -0
  27. package/dist/controllers/character_counter_controller.d.ts +63 -0
  28. package/dist/controllers/character_counter_controller.js +179 -0
  29. package/dist/controllers/character_counter_controller.js.map +1 -0
  30. package/dist/controllers/checkbox_controller.d.ts +52 -0
  31. package/dist/controllers/checkbox_controller.js +73 -0
  32. package/dist/controllers/checkbox_controller.js.map +1 -0
  33. package/dist/controllers/combobox_controller.d.ts +76 -0
  34. package/dist/controllers/combobox_controller.js +186 -0
  35. package/dist/controllers/combobox_controller.js.map +1 -0
  36. package/dist/controllers/command_palette_controller.d.ts +103 -0
  37. package/dist/controllers/command_palette_controller.js +381 -0
  38. package/dist/controllers/command_palette_controller.js.map +1 -0
  39. package/dist/controllers/conditional_fields_controller.d.ts +56 -0
  40. package/dist/controllers/conditional_fields_controller.js +112 -0
  41. package/dist/controllers/conditional_fields_controller.js.map +1 -0
  42. package/dist/controllers/confirm_controller.d.ts +83 -0
  43. package/dist/controllers/confirm_controller.js +276 -0
  44. package/dist/controllers/confirm_controller.js.map +1 -0
  45. package/dist/controllers/context_menu_controller.d.ts +81 -0
  46. package/dist/controllers/context_menu_controller.js +112 -0
  47. package/dist/controllers/context_menu_controller.js.map +1 -0
  48. package/dist/controllers/countdown_controller.d.ts +93 -0
  49. package/dist/controllers/countdown_controller.js +202 -0
  50. package/dist/controllers/countdown_controller.js.map +1 -0
  51. package/dist/controllers/dialog_controller.d.ts +57 -0
  52. package/dist/controllers/dialog_controller.js +207 -0
  53. package/dist/controllers/dialog_controller.js.map +1 -0
  54. package/dist/controllers/direct_upload_controller.d.ts +77 -0
  55. package/dist/controllers/direct_upload_controller.js +212 -0
  56. package/dist/controllers/direct_upload_controller.js.map +1 -0
  57. package/dist/controllers/dirty_form_controller.d.ts +52 -0
  58. package/dist/controllers/dirty_form_controller.js +128 -0
  59. package/dist/controllers/dirty_form_controller.js.map +1 -0
  60. package/dist/controllers/dropdown_controller.d.ts +49 -0
  61. package/dist/controllers/dropdown_controller.js +66 -0
  62. package/dist/controllers/dropdown_controller.js.map +1 -0
  63. package/dist/controllers/empty_state_controller.d.ts +60 -0
  64. package/dist/controllers/empty_state_controller.js +67 -0
  65. package/dist/controllers/empty_state_controller.js.map +1 -0
  66. package/dist/controllers/flash_controller.d.ts +63 -0
  67. package/dist/controllers/flash_controller.js +221 -0
  68. package/dist/controllers/flash_controller.js.map +1 -0
  69. package/dist/controllers/focus_controller.d.ts +69 -0
  70. package/dist/controllers/focus_controller.js +216 -0
  71. package/dist/controllers/focus_controller.js.map +1 -0
  72. package/dist/controllers/form_field_controller.d.ts +79 -0
  73. package/dist/controllers/form_field_controller.js +154 -0
  74. package/dist/controllers/form_field_controller.js.map +1 -0
  75. package/dist/controllers/form_validation_controller.d.ts +114 -0
  76. package/dist/controllers/form_validation_controller.js +202 -0
  77. package/dist/controllers/form_validation_controller.js.map +1 -0
  78. package/dist/controllers/frame_loading_controller.d.ts +58 -0
  79. package/dist/controllers/frame_loading_controller.js +177 -0
  80. package/dist/controllers/frame_loading_controller.js.map +1 -0
  81. package/dist/controllers/highlight_controller.d.ts +50 -0
  82. package/dist/controllers/highlight_controller.js +107 -0
  83. package/dist/controllers/highlight_controller.js.map +1 -0
  84. package/dist/controllers/hover_card_controller.d.ts +79 -0
  85. package/dist/controllers/hover_card_controller.js +165 -0
  86. package/dist/controllers/hover_card_controller.js.map +1 -0
  87. package/dist/controllers/idle_controller.d.ts +51 -0
  88. package/dist/controllers/idle_controller.js +141 -0
  89. package/dist/controllers/idle_controller.js.map +1 -0
  90. package/dist/controllers/input_mask_controller.d.ts +74 -0
  91. package/dist/controllers/input_mask_controller.js +166 -0
  92. package/dist/controllers/input_mask_controller.js.map +1 -0
  93. package/dist/controllers/lazy_frame_controller.d.ts +53 -0
  94. package/dist/controllers/lazy_frame_controller.js +68 -0
  95. package/dist/controllers/lazy_frame_controller.js.map +1 -0
  96. package/dist/controllers/listbox_controller.d.ts +88 -0
  97. package/dist/controllers/listbox_controller.js +256 -0
  98. package/dist/controllers/listbox_controller.js.map +1 -0
  99. package/dist/controllers/local_time_controller.d.ts +60 -0
  100. package/dist/controllers/local_time_controller.js +81 -0
  101. package/dist/controllers/local_time_controller.js.map +1 -0
  102. package/dist/controllers/menu_controller.d.ts +81 -0
  103. package/dist/controllers/menu_controller.js +134 -0
  104. package/dist/controllers/menu_controller.js.map +1 -0
  105. package/dist/controllers/meter_controller.d.ts +93 -0
  106. package/dist/controllers/meter_controller.js +96 -0
  107. package/dist/controllers/meter_controller.js.map +1 -0
  108. package/dist/controllers/nested_form_controller.d.ts +85 -0
  109. package/dist/controllers/nested_form_controller.js +131 -0
  110. package/dist/controllers/nested_form_controller.js.map +1 -0
  111. package/dist/controllers/network_status_controller.d.ts +49 -0
  112. package/dist/controllers/network_status_controller.js +126 -0
  113. package/dist/controllers/network_status_controller.js.map +1 -0
  114. package/dist/controllers/number_input_controller.d.ts +93 -0
  115. package/dist/controllers/number_input_controller.js +306 -0
  116. package/dist/controllers/number_input_controller.js.map +1 -0
  117. package/dist/controllers/otp_controller.d.ts +68 -0
  118. package/dist/controllers/otp_controller.js +201 -0
  119. package/dist/controllers/otp_controller.js.map +1 -0
  120. package/dist/controllers/overflow_indicator_controller.d.ts +62 -0
  121. package/dist/controllers/overflow_indicator_controller.js +169 -0
  122. package/dist/controllers/overflow_indicator_controller.js.map +1 -0
  123. package/dist/controllers/overflow_menu_controller.d.ts +64 -0
  124. package/dist/controllers/overflow_menu_controller.js +274 -0
  125. package/dist/controllers/overflow_menu_controller.js.map +1 -0
  126. package/dist/controllers/pagination_controller.d.ts +69 -0
  127. package/dist/controllers/pagination_controller.js +89 -0
  128. package/dist/controllers/pagination_controller.js.map +1 -0
  129. package/dist/controllers/password_strength_controller.d.ts +67 -0
  130. package/dist/controllers/password_strength_controller.js +175 -0
  131. package/dist/controllers/password_strength_controller.js.map +1 -0
  132. package/dist/controllers/persist_controller.d.ts +63 -0
  133. package/dist/controllers/persist_controller.js +259 -0
  134. package/dist/controllers/persist_controller.js.map +1 -0
  135. package/dist/controllers/popover_controller.d.ts +63 -0
  136. package/dist/controllers/popover_controller.js +94 -0
  137. package/dist/controllers/popover_controller.js.map +1 -0
  138. package/dist/controllers/portal_controller.d.ts +58 -0
  139. package/dist/controllers/portal_controller.js +63 -0
  140. package/dist/controllers/portal_controller.js.map +1 -0
  141. package/dist/controllers/preview_guard_controller.d.ts +47 -0
  142. package/dist/controllers/preview_guard_controller.js +69 -0
  143. package/dist/controllers/preview_guard_controller.js.map +1 -0
  144. package/dist/controllers/progress_controller.d.ts +85 -0
  145. package/dist/controllers/progress_controller.js +93 -0
  146. package/dist/controllers/progress_controller.js.map +1 -0
  147. package/dist/controllers/radio_group_controller.d.ts +49 -0
  148. package/dist/controllers/radio_group_controller.js +128 -0
  149. package/dist/controllers/radio_group_controller.js.map +1 -0
  150. package/dist/controllers/rating_controller.d.ts +82 -0
  151. package/dist/controllers/rating_controller.js +179 -0
  152. package/dist/controllers/rating_controller.js.map +1 -0
  153. package/dist/controllers/relative_time_controller.d.ts +48 -0
  154. package/dist/controllers/relative_time_controller.js +129 -0
  155. package/dist/controllers/relative_time_controller.js.map +1 -0
  156. package/dist/controllers/reset_before_cache_controller.d.ts +54 -0
  157. package/dist/controllers/reset_before_cache_controller.js +62 -0
  158. package/dist/controllers/reset_before_cache_controller.js.map +1 -0
  159. package/dist/controllers/resizable_controller.d.ts +81 -0
  160. package/dist/controllers/resizable_controller.js +163 -0
  161. package/dist/controllers/resizable_controller.js.map +1 -0
  162. package/dist/controllers/roving_controller.d.ts +63 -0
  163. package/dist/controllers/roving_controller.js +116 -0
  164. package/dist/controllers/roving_controller.js.map +1 -0
  165. package/dist/controllers/scroll_area_controller.d.ts +45 -0
  166. package/dist/controllers/scroll_area_controller.js +183 -0
  167. package/dist/controllers/scroll_area_controller.js.map +1 -0
  168. package/dist/controllers/scroll_visibility_controller.d.ts +72 -0
  169. package/dist/controllers/scroll_visibility_controller.js +103 -0
  170. package/dist/controllers/scroll_visibility_controller.js.map +1 -0
  171. package/dist/controllers/scrollspy_controller.d.ts +65 -0
  172. package/dist/controllers/scrollspy_controller.js +171 -0
  173. package/dist/controllers/scrollspy_controller.js.map +1 -0
  174. package/dist/controllers/skeleton_controller.d.ts +50 -0
  175. package/dist/controllers/skeleton_controller.js +125 -0
  176. package/dist/controllers/skeleton_controller.js.map +1 -0
  177. package/dist/controllers/slider_controller.d.ts +76 -0
  178. package/dist/controllers/slider_controller.js +109 -0
  179. package/dist/controllers/slider_controller.js.map +1 -0
  180. package/dist/controllers/spinner_controller.d.ts +62 -0
  181. package/dist/controllers/spinner_controller.js +164 -0
  182. package/dist/controllers/spinner_controller.js.map +1 -0
  183. package/dist/controllers/step_indicator_controller.d.ts +55 -0
  184. package/dist/controllers/step_indicator_controller.js +55 -0
  185. package/dist/controllers/step_indicator_controller.js.map +1 -0
  186. package/dist/controllers/stepper_controller.d.ts +66 -0
  187. package/dist/controllers/stepper_controller.js +78 -0
  188. package/dist/controllers/stepper_controller.js.map +1 -0
  189. package/dist/controllers/stick_to_bottom_controller.d.ts +61 -0
  190. package/dist/controllers/stick_to_bottom_controller.js +100 -0
  191. package/dist/controllers/stick_to_bottom_controller.js.map +1 -0
  192. package/dist/controllers/sticky_observer_controller.d.ts +54 -0
  193. package/dist/controllers/sticky_observer_controller.js +53 -0
  194. package/dist/controllers/sticky_observer_controller.js.map +1 -0
  195. package/dist/controllers/submit_once_controller.d.ts +66 -0
  196. package/dist/controllers/submit_once_controller.js +206 -0
  197. package/dist/controllers/submit_once_controller.js.map +1 -0
  198. package/dist/controllers/switch_controller.d.ts +43 -0
  199. package/dist/controllers/switch_controller.js +50 -0
  200. package/dist/controllers/switch_controller.js.map +1 -0
  201. package/dist/controllers/tabs_controller.d.ts +48 -0
  202. package/dist/controllers/tabs_controller.js +63 -0
  203. package/dist/controllers/tabs_controller.js.map +1 -0
  204. package/dist/controllers/textarea_autosize_controller.d.ts +47 -0
  205. package/dist/controllers/textarea_autosize_controller.js +72 -0
  206. package/dist/controllers/textarea_autosize_controller.js.map +1 -0
  207. package/dist/controllers/theme_controller.d.ts +70 -0
  208. package/dist/controllers/theme_controller.js +154 -0
  209. package/dist/controllers/theme_controller.js.map +1 -0
  210. package/dist/controllers/toast_controller.d.ts +123 -0
  211. package/dist/controllers/toast_controller.js +310 -0
  212. package/dist/controllers/toast_controller.js.map +1 -0
  213. package/dist/controllers/toggle_group_controller.d.ts +56 -0
  214. package/dist/controllers/toggle_group_controller.js +130 -0
  215. package/dist/controllers/toggle_group_controller.js.map +1 -0
  216. package/dist/controllers/toolbar_controller.d.ts +59 -0
  217. package/dist/controllers/toolbar_controller.js +113 -0
  218. package/dist/controllers/toolbar_controller.js.map +1 -0
  219. package/dist/controllers/tooltip_controller.d.ts +74 -0
  220. package/dist/controllers/tooltip_controller.js +165 -0
  221. package/dist/controllers/tooltip_controller.js.map +1 -0
  222. package/dist/controllers/transition_controller.d.ts +86 -0
  223. package/dist/controllers/transition_controller.js +203 -0
  224. package/dist/controllers/transition_controller.js.map +1 -0
  225. package/dist/index.d.ts +1931 -0
  226. package/dist/index.js +12241 -0
  227. package/dist/index.js.map +1 -0
  228. package/dist/inspector/cli.d.ts +149 -0
  229. package/dist/inspector/cli.js +663 -0
  230. package/dist/inspector/cli.js.map +1 -0
  231. package/dist/inspector/cli_bin.d.ts +2 -0
  232. package/dist/inspector/cli_bin.js +665 -0
  233. package/dist/inspector/cli_bin.js.map +1 -0
  234. package/dist/inspector/manifest.json +2235 -0
  235. package/dist/positioning/index.d.ts +226 -0
  236. package/dist/positioning/index.js +145 -0
  237. package/dist/positioning/index.js.map +1 -0
  238. package/package.json +93 -0
@@ -0,0 +1,663 @@
1
+ import { readFileSync, statSync, readdirSync } from 'fs';
2
+ import { dirname, join, relative, extname } from 'path';
3
+ import process from 'process';
4
+ import { fileURLToPath } from 'url';
5
+
6
+ // src/inspector/cli.ts
7
+
8
+ // src/inspector/erb.ts
9
+ function neutralizeErb(source) {
10
+ return source.replace(/<%[\s\S]*?%>/g, (match) => match.replace(/[^\n]/g, " "));
11
+ }
12
+
13
+ // src/inspector/extract.ts
14
+ var NAMESPACE_PREFIX = "stimeo--";
15
+ function dasherize(value) {
16
+ return value.replace(/([A-Z])/g, (_match, char) => `-${char.toLowerCase()}`);
17
+ }
18
+ function controllerIdentifiers(dataControllerValue) {
19
+ const seen = /* @__PURE__ */ new Set();
20
+ for (const token of dataControllerValue.split(/\s+/)) {
21
+ if (token.startsWith(NAMESPACE_PREFIX)) seen.add(token);
22
+ }
23
+ return [...seen];
24
+ }
25
+ function parseTargetAttr(attrName) {
26
+ const match = /^data-(stimeo--[a-z0-9][a-z0-9-]*)-target$/.exec(attrName);
27
+ return match?.[1] ?? null;
28
+ }
29
+ function parseValueAttr(attrName, knownIdentifiers) {
30
+ const match = /^data-(stimeo--[a-z0-9-]+)-value$/.exec(attrName);
31
+ if (!match) return null;
32
+ const inner = match[1] ?? "";
33
+ let best = null;
34
+ for (const id of knownIdentifiers) {
35
+ if (inner.startsWith(`${id}-`)) {
36
+ const valueToken = inner.slice(id.length + 1);
37
+ if (valueToken.length > 0 && (!best || id.length > best.identifier.length)) {
38
+ best = { identifier: id, valueToken };
39
+ }
40
+ }
41
+ }
42
+ if (best) return best;
43
+ const rest = inner.slice(NAMESPACE_PREFIX.length);
44
+ const dash = rest.indexOf("-");
45
+ const identifierGuess = dash === -1 ? inner : `${NAMESPACE_PREFIX}${rest.slice(0, dash)}`;
46
+ const valueGuess = dash === -1 ? "" : rest.slice(dash + 1);
47
+ return { identifier: null, valueToken: valueGuess || identifierGuess };
48
+ }
49
+ function actionDescriptors(dataActionValue) {
50
+ const descriptors = [];
51
+ for (const descriptor of dataActionValue.split(/\s+/)) {
52
+ const hash = descriptor.indexOf("#");
53
+ if (hash === -1) continue;
54
+ let lhs = descriptor.slice(0, hash);
55
+ const arrow = lhs.indexOf("->");
56
+ if (arrow !== -1) lhs = lhs.slice(arrow + 2);
57
+ if (!lhs.startsWith(NAMESPACE_PREFIX)) continue;
58
+ const method = /^[a-zA-Z_$][\w$]*/.exec(descriptor.slice(hash + 1))?.[0] ?? "";
59
+ descriptors.push({ identifier: lhs, method });
60
+ }
61
+ return descriptors;
62
+ }
63
+ function isStimeoDataAttr(attrName) {
64
+ return attrName.startsWith(`data-${NAMESPACE_PREFIX}`);
65
+ }
66
+
67
+ // src/inspector/html_parser.ts
68
+ var VOID_ELEMENTS = /* @__PURE__ */ new Set([
69
+ "area",
70
+ "base",
71
+ "br",
72
+ "col",
73
+ "embed",
74
+ "hr",
75
+ "img",
76
+ "input",
77
+ "link",
78
+ "meta",
79
+ "param",
80
+ "source",
81
+ "track",
82
+ "wbr"
83
+ ]);
84
+ var RAW_TEXT_ELEMENTS = /* @__PURE__ */ new Set(["script", "style", "textarea", "title"]);
85
+ var WHITESPACE = /* @__PURE__ */ new Set([" ", " ", "\n", "\r", "\f"]);
86
+ var PositionIndex = class {
87
+ #lineStarts = [0];
88
+ constructor(source) {
89
+ for (let i = 0; i < source.length; i++) {
90
+ if (source[i] === "\n") this.#lineStarts.push(i + 1);
91
+ }
92
+ }
93
+ at(offset) {
94
+ let lo = 0;
95
+ let hi = this.#lineStarts.length - 1;
96
+ while (lo < hi) {
97
+ const mid = lo + hi + 1 >> 1;
98
+ if ((this.#lineStarts[mid] ?? 0) <= offset) lo = mid;
99
+ else hi = mid - 1;
100
+ }
101
+ return { line: lo + 1, column: offset - (this.#lineStarts[lo] ?? 0) + 1 };
102
+ }
103
+ };
104
+ function parseHtml(source) {
105
+ const pos = new PositionIndex(source);
106
+ const len = source.length;
107
+ const ch = (k) => k >= 0 && k < len ? source[k] : "";
108
+ const root = {
109
+ tag: "#root",
110
+ attrs: [],
111
+ children: [],
112
+ parent: null,
113
+ line: 1,
114
+ column: 1
115
+ };
116
+ const stack = [root];
117
+ let i = 0;
118
+ const top = () => stack[stack.length - 1];
119
+ while (i < len) {
120
+ if (ch(i) !== "<") {
121
+ i++;
122
+ continue;
123
+ }
124
+ const next = ch(i + 1);
125
+ if (source.startsWith("<!--", i)) {
126
+ const end = source.indexOf("-->", i + 4);
127
+ i = end === -1 ? len : end + 3;
128
+ continue;
129
+ }
130
+ if (next === "!" || next === "?") {
131
+ const end = source.indexOf(">", i);
132
+ i = end === -1 ? len : end + 1;
133
+ continue;
134
+ }
135
+ if (next === "/") {
136
+ let j2 = i + 2;
137
+ let name = "";
138
+ while (j2 < len && ch(j2) !== ">" && !WHITESPACE.has(ch(j2))) {
139
+ name += ch(j2);
140
+ j2++;
141
+ }
142
+ const end = source.indexOf(">", j2);
143
+ i = end === -1 ? len : end + 1;
144
+ closeTag(stack, name.toLowerCase());
145
+ continue;
146
+ }
147
+ if (!/[a-zA-Z]/.test(next)) {
148
+ i++;
149
+ continue;
150
+ }
151
+ const tagStart = i;
152
+ let j = i + 1;
153
+ let tagName = "";
154
+ while (j < len && !WHITESPACE.has(ch(j)) && ch(j) !== ">" && ch(j) !== "/") {
155
+ tagName += ch(j);
156
+ j++;
157
+ }
158
+ const lowerTag = tagName.toLowerCase();
159
+ const attrs = [];
160
+ let selfClosing = false;
161
+ while (j < len) {
162
+ while (j < len && WHITESPACE.has(ch(j))) j++;
163
+ if (j >= len) break;
164
+ if (ch(j) === ">") {
165
+ j++;
166
+ break;
167
+ }
168
+ if (ch(j) === "/") {
169
+ selfClosing = true;
170
+ j++;
171
+ continue;
172
+ }
173
+ const nameStart = j;
174
+ let attrName = "";
175
+ while (j < len && !WHITESPACE.has(ch(j)) && ch(j) !== "=" && ch(j) !== ">" && ch(j) !== "/") {
176
+ attrName += ch(j);
177
+ j++;
178
+ }
179
+ let attrValue = "";
180
+ let k = j;
181
+ while (k < len && WHITESPACE.has(ch(k))) k++;
182
+ if (ch(k) === "=") {
183
+ k++;
184
+ while (k < len && WHITESPACE.has(ch(k))) k++;
185
+ const quote = ch(k);
186
+ if (quote === '"' || quote === "'") {
187
+ k++;
188
+ const valStart = k;
189
+ while (k < len && ch(k) !== quote) k++;
190
+ attrValue = source.slice(valStart, k);
191
+ k++;
192
+ } else {
193
+ const valStart = k;
194
+ while (k < len && !WHITESPACE.has(ch(k)) && ch(k) !== ">") k++;
195
+ attrValue = source.slice(valStart, k);
196
+ }
197
+ j = k;
198
+ }
199
+ if (attrName.length > 0) {
200
+ const p = pos.at(nameStart);
201
+ attrs.push({
202
+ name: attrName.toLowerCase(),
203
+ value: attrValue,
204
+ line: p.line,
205
+ column: p.column
206
+ });
207
+ }
208
+ }
209
+ const startPos = pos.at(tagStart);
210
+ const node = {
211
+ tag: lowerTag,
212
+ attrs,
213
+ children: [],
214
+ parent: top(),
215
+ line: startPos.line,
216
+ column: startPos.column
217
+ };
218
+ top().children.push(node);
219
+ i = j;
220
+ if (selfClosing || VOID_ELEMENTS.has(lowerTag)) {
221
+ continue;
222
+ }
223
+ if (RAW_TEXT_ELEMENTS.has(lowerTag)) {
224
+ const closeNeedle = `</${lowerTag}`;
225
+ const idx = source.toLowerCase().indexOf(closeNeedle, i);
226
+ if (idx === -1) {
227
+ i = len;
228
+ } else {
229
+ const gt = source.indexOf(">", idx);
230
+ i = gt === -1 ? len : gt + 1;
231
+ }
232
+ continue;
233
+ }
234
+ stack.push(node);
235
+ }
236
+ return root;
237
+ }
238
+ function closeTag(stack, name) {
239
+ for (let depth = stack.length - 1; depth >= 1; depth--) {
240
+ if (stack[depth]?.tag === name) {
241
+ stack.length = depth;
242
+ return;
243
+ }
244
+ }
245
+ }
246
+ function walk(root, visit) {
247
+ for (const child of root.children) {
248
+ visit(child);
249
+ walk(child, visit);
250
+ }
251
+ }
252
+
253
+ // src/inspector/check.ts
254
+ function checkSource(source, manifest) {
255
+ const diagnostics = [];
256
+ const tree = parseHtml(neutralizeErb(source));
257
+ const known = manifest.controllers;
258
+ const knownIdentifiers = Object.keys(known);
259
+ const scopes = [];
260
+ const presence = /* @__PURE__ */ new Map();
261
+ const targetNodes = /* @__PURE__ */ new Map();
262
+ const recordPresence = (owner, identifier, target) => {
263
+ let byId = presence.get(owner);
264
+ if (!byId) {
265
+ byId = /* @__PURE__ */ new Map();
266
+ presence.set(owner, byId);
267
+ }
268
+ let set = byId.get(identifier);
269
+ if (!set) {
270
+ set = /* @__PURE__ */ new Set();
271
+ byId.set(identifier, set);
272
+ }
273
+ set.add(target);
274
+ };
275
+ const recordTargetNode = (owner, identifier, target, el) => {
276
+ let byId = targetNodes.get(owner);
277
+ if (!byId) {
278
+ byId = /* @__PURE__ */ new Map();
279
+ targetNodes.set(owner, byId);
280
+ }
281
+ let byName = byId.get(identifier);
282
+ if (!byName) {
283
+ byName = /* @__PURE__ */ new Map();
284
+ byId.set(identifier, byName);
285
+ }
286
+ const found = byName.get(target);
287
+ if (found) found.push(el);
288
+ else byName.set(target, [el]);
289
+ };
290
+ walk(tree, (node) => {
291
+ for (const attr of node.attrs) {
292
+ if (attr.name === "data-controller") {
293
+ for (const identifier of controllerIdentifiers(attr.value)) {
294
+ if (identifier in known) {
295
+ scopes.push({ node, identifier });
296
+ } else {
297
+ push(
298
+ diagnostics,
299
+ "unknown-controller",
300
+ "error",
301
+ `Unknown Stimeo controller "${identifier}".`,
302
+ attr,
303
+ didYouMean(identifier, knownIdentifiers)
304
+ );
305
+ }
306
+ }
307
+ continue;
308
+ }
309
+ const targetIdentifier = parseTargetAttr(attr.name);
310
+ if (targetIdentifier) {
311
+ const controller = known[targetIdentifier];
312
+ if (!controller) {
313
+ push(
314
+ diagnostics,
315
+ "unknown-controller",
316
+ "error",
317
+ `Target attribute "${attr.name}" references unknown Stimeo controller "${targetIdentifier}".`,
318
+ attr,
319
+ didYouMean(targetIdentifier, knownIdentifiers)
320
+ );
321
+ continue;
322
+ }
323
+ const targetName = attr.value.trim();
324
+ if (targetName.length > 0 && !controller.targets.includes(targetName)) {
325
+ push(
326
+ diagnostics,
327
+ "unknown-target",
328
+ "error",
329
+ `Unknown target "${targetName}" for "${targetIdentifier}". Known targets: ${list(controller.targets)}.`,
330
+ attr,
331
+ didYouMean(targetName, controller.targets)
332
+ );
333
+ }
334
+ const owner = findOwner(node, targetIdentifier);
335
+ if (owner) {
336
+ if (targetName.length > 0) {
337
+ recordPresence(owner, targetIdentifier, targetName);
338
+ recordTargetNode(owner, targetIdentifier, targetName, node);
339
+ }
340
+ } else {
341
+ push(
342
+ diagnostics,
343
+ "orphan-target",
344
+ "error",
345
+ `Target "${attr.name}" has no enclosing controller "${targetIdentifier}".`,
346
+ attr
347
+ );
348
+ }
349
+ continue;
350
+ }
351
+ if (isStimeoDataAttr(attr.name) && attr.name.endsWith("-value")) {
352
+ const parsed = parseValueAttr(attr.name, knownIdentifiers);
353
+ if (parsed) {
354
+ if (parsed.identifier === null) {
355
+ push(
356
+ diagnostics,
357
+ "unknown-controller",
358
+ "error",
359
+ `Value attribute "${attr.name}" references unknown Stimeo controller.`,
360
+ attr
361
+ );
362
+ } else {
363
+ const controller = known[parsed.identifier];
364
+ const valid = controller?.values.some((v) => dasherize(v) === parsed.valueToken) ?? false;
365
+ if (!valid) {
366
+ push(
367
+ diagnostics,
368
+ "unknown-value",
369
+ "error",
370
+ `Unknown value "${parsed.valueToken}" for "${parsed.identifier}". Known values: ${list((controller?.values ?? []).map(dasherize))}.`,
371
+ attr,
372
+ didYouMean(parsed.valueToken, (controller?.values ?? []).map(dasherize))
373
+ );
374
+ }
375
+ }
376
+ continue;
377
+ }
378
+ }
379
+ if (attr.name === "data-action") {
380
+ for (const { identifier, method } of actionDescriptors(attr.value)) {
381
+ const controller = known[identifier];
382
+ if (!controller) {
383
+ push(
384
+ diagnostics,
385
+ "unknown-action-controller",
386
+ "error",
387
+ `Action references unknown Stimeo controller "${identifier}".`,
388
+ attr,
389
+ didYouMean(identifier, knownIdentifiers)
390
+ );
391
+ } else if (method.length > 0 && !controller.actions.includes(method)) {
392
+ push(
393
+ diagnostics,
394
+ "unknown-action-method",
395
+ "error",
396
+ `Unknown action "${method}" for "${identifier}". Known actions: ${list(controller.actions)}.`,
397
+ attr,
398
+ didYouMean(method, controller.actions)
399
+ );
400
+ }
401
+ }
402
+ }
403
+ }
404
+ });
405
+ for (const { node, identifier } of scopes) {
406
+ const controller = known[identifier];
407
+ if (!controller) continue;
408
+ const present = presence.get(node)?.get(identifier) ?? /* @__PURE__ */ new Set();
409
+ for (const required of controller.requiredTargets) {
410
+ if (!present.has(required)) {
411
+ push(
412
+ diagnostics,
413
+ "missing-required-target",
414
+ "error",
415
+ `"${identifier}" is missing required target "${required}".`,
416
+ node
417
+ );
418
+ }
419
+ }
420
+ }
421
+ for (const { node, identifier } of scopes) {
422
+ const controller = known[identifier];
423
+ if (!controller) continue;
424
+ for (const req of controller.a11y) {
425
+ const elements = req.target === "" ? [node] : targetNodes.get(node)?.get(identifier)?.get(req.target) ?? [];
426
+ for (const el of elements) {
427
+ checkA11y(diagnostics, el, identifier, req);
428
+ }
429
+ }
430
+ }
431
+ diagnostics.sort((a, b) => a.line - b.line || a.column - b.column);
432
+ return diagnostics;
433
+ }
434
+ function checkA11y(out, el, identifier, req) {
435
+ const present = req.attrs.map((name) => el.attrs.find((a) => a.name === name)).filter((a) => a !== void 0);
436
+ const where = req.target === "" ? "scope element" : `"${req.target}" target`;
437
+ if (present.length === 0) {
438
+ push(
439
+ out,
440
+ "missing-aria",
441
+ "error",
442
+ `"${identifier}" requires ${describeAttrs(req.attrs)} on its ${where}.`,
443
+ el,
444
+ req.suggestion
445
+ );
446
+ return;
447
+ }
448
+ if (!req.values) return;
449
+ for (const attr of present) {
450
+ if (!req.values.includes(attr.value.trim())) {
451
+ push(
452
+ out,
453
+ "invalid-aria-value",
454
+ "error",
455
+ `${attr.name}="${attr.value}" is not valid on the ${where} of "${identifier}". Expected ${list(req.values)}.`,
456
+ attr,
457
+ `Set ${attr.name} to ${list(req.values)}.`
458
+ );
459
+ }
460
+ }
461
+ }
462
+ function findOwner(node, identifier) {
463
+ let current = node;
464
+ while (current && current.tag !== "#root") {
465
+ const dataController = current.attrs.find((a) => a.name === "data-controller");
466
+ if (dataController && controllerIdentifiers(dataController.value).includes(identifier)) {
467
+ return current;
468
+ }
469
+ current = current.parent;
470
+ }
471
+ return null;
472
+ }
473
+ function push(out, code, severity, message, at, suggestion) {
474
+ out.push({ code, severity, message, line: at.line, column: at.column, suggestion });
475
+ }
476
+ function list(names) {
477
+ return names.length > 0 ? names.map((n) => `"${n}"`).join(", ") : "(none)";
478
+ }
479
+ function describeAttrs(attrs) {
480
+ return attrs.length === 1 ? attrs[0] : attrs.join(" or ");
481
+ }
482
+ function didYouMean(name, candidates) {
483
+ if (name.length === 0) return void 0;
484
+ let best;
485
+ let bestDistance = Number.POSITIVE_INFINITY;
486
+ for (const candidate of candidates) {
487
+ const distance = levenshtein(name, candidate);
488
+ if (distance < bestDistance) {
489
+ bestDistance = distance;
490
+ best = candidate;
491
+ }
492
+ }
493
+ const threshold = Math.min(3, Math.floor(name.length / 2) + 1);
494
+ return best !== void 0 && bestDistance <= threshold ? `Did you mean "${best}"?` : void 0;
495
+ }
496
+ function levenshtein(a, b) {
497
+ const rows = a.length;
498
+ const cols = b.length;
499
+ if (rows === 0) return cols;
500
+ if (cols === 0) return rows;
501
+ let prev = Array.from({ length: cols + 1 }, (_, j) => j);
502
+ for (let i = 1; i <= rows; i++) {
503
+ const curr = [i];
504
+ for (let j = 1; j <= cols; j++) {
505
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
506
+ curr[j] = Math.min(
507
+ curr[j - 1] + 1,
508
+ prev[j] + 1,
509
+ prev[j - 1] + cost
510
+ );
511
+ }
512
+ prev = curr;
513
+ }
514
+ return prev[cols];
515
+ }
516
+
517
+ // src/inspector/cli.ts
518
+ var FILE_EXTENSIONS = /* @__PURE__ */ new Set([".erb", ".html", ".htm"]);
519
+ function loadManifest() {
520
+ const here = dirname(fileURLToPath(import.meta.url));
521
+ const manifestPath = join(here, "manifest.json");
522
+ const raw = readFileSync(manifestPath, "utf8");
523
+ return JSON.parse(raw);
524
+ }
525
+ function collectFiles(target, out) {
526
+ const stat = statSync(target);
527
+ if (stat.isDirectory()) {
528
+ for (const entry of readdirSync(target)) {
529
+ collectFiles(join(target, entry), out);
530
+ }
531
+ return;
532
+ }
533
+ if (FILE_EXTENSIONS.has(extname(target))) out.push(target);
534
+ }
535
+ function checkFile(file, manifest) {
536
+ const source = readFileSync(file, "utf8");
537
+ return { file, diagnostics: checkSource(source, manifest) };
538
+ }
539
+ function formatDiagnostic(d) {
540
+ const where = `${d.line}:${d.column}`.padEnd(7);
541
+ const head = ` ${where} ${d.severity.padEnd(7)} ${d.message} [${d.code}]`;
542
+ return d.suggestion ? `${head}
543
+ \u2192 ${d.suggestion}` : head;
544
+ }
545
+ function buildCheckReport(reports, checkedFiles) {
546
+ let errorCount = 0;
547
+ let warningCount = 0;
548
+ const files = [];
549
+ for (const report of reports) {
550
+ if (report.diagnostics.length === 0) continue;
551
+ files.push(report);
552
+ for (const d of report.diagnostics) {
553
+ if (d.severity === "error") errorCount++;
554
+ else warningCount++;
555
+ }
556
+ }
557
+ return { ok: errorCount === 0, checkedFiles, errorCount, warningCount, files };
558
+ }
559
+ function catalogSummary(manifest) {
560
+ const ids = Object.keys(manifest.controllers).sort();
561
+ const lines = [
562
+ `Stimeo UI catalog \u2014 ${ids.length} controller(s) (schema v${manifest.schemaVersion}, package ${manifest.packageVersion})`,
563
+ ""
564
+ ];
565
+ for (const id of ids) {
566
+ const c = manifest.controllers[id];
567
+ if (!c) continue;
568
+ lines.push(id);
569
+ if (c.targets.length > 0) lines.push(` targets: ${c.targets.join(", ")}`);
570
+ if (c.values.length > 0) lines.push(` values: ${c.values.join(", ")}`);
571
+ if (c.actions.length > 0) lines.push(` actions: ${c.actions.join(", ")}`);
572
+ if (c.events.length > 0) lines.push(` events: ${c.events.join(", ")}`);
573
+ }
574
+ return lines;
575
+ }
576
+ var USAGE = `stimeo \u2014 static checker and catalog for Stimeo UI markup
577
+
578
+ Usage:
579
+ stimeo check [--json] <path...> Check HTML/ERB files (or directories) for
580
+ unknown or misused stimeo--* controllers,
581
+ targets, values and action methods.
582
+ stimeo catalog [--json] Print the official controller catalog
583
+ (identifiers, targets, values, actions,
584
+ events).
585
+
586
+ --json makes either command emit machine-readable JSON (for tooling / MCP):
587
+ check prints a CheckReport, catalog prints the raw manifest.
588
+ Exit code is 1 when any error is found.`;
589
+ function runCli(argv, write = console.log, load = loadManifest) {
590
+ const [command, ...rest] = argv;
591
+ if (command === void 0 || command === "--help" || command === "-h") {
592
+ write(USAGE);
593
+ return command === void 0 ? 2 : 0;
594
+ }
595
+ const json = rest.includes("--json");
596
+ if (command === "catalog") {
597
+ const manifest2 = load();
598
+ if (json) {
599
+ write(JSON.stringify(manifest2, null, 2));
600
+ } else {
601
+ for (const line of catalogSummary(manifest2)) write(line);
602
+ }
603
+ return 0;
604
+ }
605
+ if (command !== "check") {
606
+ write(`Unknown command "${command}".
607
+
608
+ ${USAGE}`);
609
+ return 2;
610
+ }
611
+ const paths = rest.filter((arg) => !arg.startsWith("-"));
612
+ if (paths.length === 0) {
613
+ write(`No paths given.
614
+
615
+ ${USAGE}`);
616
+ return 2;
617
+ }
618
+ const files = [];
619
+ for (const path of paths) {
620
+ try {
621
+ collectFiles(path, files);
622
+ } catch (err) {
623
+ const code = err.code;
624
+ const reason = code === "ENOENT" ? "no such file or directory" : code === "EACCES" ? "permission denied" : err.message ?? "cannot access path";
625
+ write(`Cannot read path "${path}": ${reason}.
626
+
627
+ ${USAGE}`);
628
+ return 2;
629
+ }
630
+ }
631
+ const manifest = load();
632
+ const cwd = process.cwd();
633
+ const reports = [];
634
+ for (const file of files.sort()) {
635
+ reports.push({
636
+ file: relative(cwd, file) || file,
637
+ diagnostics: checkFile(file, manifest).diagnostics
638
+ });
639
+ }
640
+ const summary = buildCheckReport(reports, files.length);
641
+ if (json) {
642
+ write(JSON.stringify(summary, null, 2));
643
+ return summary.errorCount > 0 ? 1 : 0;
644
+ }
645
+ for (const report of summary.files) {
646
+ write(report.file);
647
+ for (const d of report.diagnostics) write(formatDiagnostic(d));
648
+ write("");
649
+ }
650
+ const total = summary.errorCount + summary.warningCount;
651
+ if (total === 0) {
652
+ write(`\u2713 Checked ${summary.checkedFiles} file(s); no problems found.`);
653
+ return 0;
654
+ }
655
+ write(
656
+ `\u2716 ${total} problem(s) (${summary.errorCount} error(s), ${summary.warningCount} warning(s)).`
657
+ );
658
+ return summary.errorCount > 0 ? 1 : 0;
659
+ }
660
+
661
+ export { buildCheckReport, catalogSummary, runCli };
662
+ //# sourceMappingURL=cli.js.map
663
+ //# sourceMappingURL=cli.js.map