snice 4.17.0 → 4.18.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 (252) hide show
  1. package/adapters/react/code-block.d.ts +1 -0
  2. package/adapters/react/code-block.d.ts.map +1 -1
  3. package/adapters/react/code-block.js +1 -1
  4. package/adapters/react/code-block.js.map +1 -1
  5. package/adapters/react/code-block.tsx +2 -1
  6. package/dist/cdn/accordion/snice-accordion.js +1 -1
  7. package/dist/cdn/accordion/snice-accordion.min.js +1 -1
  8. package/dist/cdn/alert/snice-alert.js +1 -1
  9. package/dist/cdn/alert/snice-alert.min.js +1 -1
  10. package/dist/cdn/app-tiles/snice-app-tiles.js +1 -1
  11. package/dist/cdn/app-tiles/snice-app-tiles.min.js +1 -1
  12. package/dist/cdn/audio-recorder/snice-audio-recorder.js +1 -1
  13. package/dist/cdn/audio-recorder/snice-audio-recorder.min.js +1 -1
  14. package/dist/cdn/avatar/snice-avatar.js +1 -1
  15. package/dist/cdn/avatar/snice-avatar.min.js +1 -1
  16. package/dist/cdn/badge/snice-badge.js +1 -1
  17. package/dist/cdn/badge/snice-badge.min.js +1 -1
  18. package/dist/cdn/banner/snice-banner.js +1 -1
  19. package/dist/cdn/banner/snice-banner.min.js +1 -1
  20. package/dist/cdn/book/snice-book.js +1 -1
  21. package/dist/cdn/book/snice-book.min.js +1 -1
  22. package/dist/cdn/breadcrumbs/snice-breadcrumbs.js +1 -1
  23. package/dist/cdn/breadcrumbs/snice-breadcrumbs.min.js +1 -1
  24. package/dist/cdn/button/snice-button.js +1 -1
  25. package/dist/cdn/button/snice-button.min.js +1 -1
  26. package/dist/cdn/calendar/snice-calendar.js +1 -1
  27. package/dist/cdn/calendar/snice-calendar.min.js +1 -1
  28. package/dist/cdn/camera/snice-camera.js +1 -1
  29. package/dist/cdn/camera/snice-camera.min.js +1 -1
  30. package/dist/cdn/camera-annotate/snice-camera-annotate.js +1 -1
  31. package/dist/cdn/camera-annotate/snice-camera-annotate.min.js +1 -1
  32. package/dist/cdn/candlestick/snice-candlestick.js +1 -1
  33. package/dist/cdn/candlestick/snice-candlestick.min.js +1 -1
  34. package/dist/cdn/card/snice-card.js +1 -1
  35. package/dist/cdn/card/snice-card.min.js +1 -1
  36. package/dist/cdn/carousel/snice-carousel.js +1 -1
  37. package/dist/cdn/carousel/snice-carousel.min.js +1 -1
  38. package/dist/cdn/chart/snice-chart.js +1 -1
  39. package/dist/cdn/chart/snice-chart.min.js +1 -1
  40. package/dist/cdn/chat/snice-chat.js +1 -1
  41. package/dist/cdn/chat/snice-chat.min.js +1 -1
  42. package/dist/cdn/checkbox/snice-checkbox.js +1 -1
  43. package/dist/cdn/checkbox/snice-checkbox.min.js +1 -1
  44. package/dist/cdn/chip/snice-chip.js +1 -1
  45. package/dist/cdn/chip/snice-chip.min.js +1 -1
  46. package/dist/cdn/code-block/README.md +2 -2
  47. package/dist/cdn/code-block/snice-code-block.js +314 -3
  48. package/dist/cdn/code-block/snice-code-block.js.map +1 -1
  49. package/dist/cdn/code-block/snice-code-block.min.js +3 -3
  50. package/dist/cdn/code-block/snice-code-block.min.js.map +1 -1
  51. package/dist/cdn/color-display/snice-color-display.js +1 -1
  52. package/dist/cdn/color-display/snice-color-display.min.js +1 -1
  53. package/dist/cdn/color-picker/snice-color-picker.js +1 -1
  54. package/dist/cdn/color-picker/snice-color-picker.min.js +1 -1
  55. package/dist/cdn/command-palette/snice-command-palette.js +1 -1
  56. package/dist/cdn/command-palette/snice-command-palette.min.js +1 -1
  57. package/dist/cdn/comments/snice-comments.js +1 -1
  58. package/dist/cdn/comments/snice-comments.min.js +1 -1
  59. package/dist/cdn/countdown/snice-countdown.js +1 -1
  60. package/dist/cdn/countdown/snice-countdown.min.js +1 -1
  61. package/dist/cdn/cropper/snice-cropper.js +1 -1
  62. package/dist/cdn/cropper/snice-cropper.min.js +1 -1
  63. package/dist/cdn/date-picker/snice-date-picker.js +1 -1
  64. package/dist/cdn/date-picker/snice-date-picker.min.js +1 -1
  65. package/dist/cdn/diff/snice-diff.js +1 -1
  66. package/dist/cdn/diff/snice-diff.min.js +1 -1
  67. package/dist/cdn/divider/snice-divider.js +1 -1
  68. package/dist/cdn/divider/snice-divider.min.js +1 -1
  69. package/dist/cdn/doc/snice-doc.js +1 -1
  70. package/dist/cdn/doc/snice-doc.min.js +1 -1
  71. package/dist/cdn/draw/snice-draw.js +1 -1
  72. package/dist/cdn/draw/snice-draw.min.js +1 -1
  73. package/dist/cdn/drawer/snice-drawer.js +1 -1
  74. package/dist/cdn/drawer/snice-drawer.min.js +1 -1
  75. package/dist/cdn/empty-state/snice-empty-state.js +1 -1
  76. package/dist/cdn/empty-state/snice-empty-state.min.js +1 -1
  77. package/dist/cdn/file-gallery/snice-file-gallery.js +1 -1
  78. package/dist/cdn/file-gallery/snice-file-gallery.min.js +1 -1
  79. package/dist/cdn/file-upload/snice-file-upload.js +1 -1
  80. package/dist/cdn/file-upload/snice-file-upload.min.js +1 -1
  81. package/dist/cdn/flip-card/snice-flip-card.js +1 -1
  82. package/dist/cdn/flip-card/snice-flip-card.min.js +1 -1
  83. package/dist/cdn/flow/snice-flow.js +1 -1
  84. package/dist/cdn/flow/snice-flow.min.js +1 -1
  85. package/dist/cdn/funnel/snice-funnel.js +1 -1
  86. package/dist/cdn/funnel/snice-funnel.min.js +1 -1
  87. package/dist/cdn/gantt/snice-gantt.js +1 -1
  88. package/dist/cdn/gantt/snice-gantt.min.js +1 -1
  89. package/dist/cdn/gauge/snice-gauge.js +1 -1
  90. package/dist/cdn/gauge/snice-gauge.min.js +1 -1
  91. package/dist/cdn/heatmap/snice-heatmap.js +1 -1
  92. package/dist/cdn/heatmap/snice-heatmap.min.js +1 -1
  93. package/dist/cdn/image/snice-image.js +1 -1
  94. package/dist/cdn/image/snice-image.min.js +1 -1
  95. package/dist/cdn/input/snice-input.js +1 -1
  96. package/dist/cdn/input/snice-input.min.js +1 -1
  97. package/dist/cdn/kanban/snice-kanban.js +1 -1
  98. package/dist/cdn/kanban/snice-kanban.min.js +1 -1
  99. package/dist/cdn/kpi/snice-kpi.js +1 -1
  100. package/dist/cdn/kpi/snice-kpi.min.js +1 -1
  101. package/dist/cdn/layout/snice-layout.js +1 -1
  102. package/dist/cdn/layout/snice-layout.min.js +1 -1
  103. package/dist/cdn/link/snice-link.js +1 -1
  104. package/dist/cdn/link/snice-link.min.js +1 -1
  105. package/dist/cdn/link-preview/snice-link-preview.js +1 -1
  106. package/dist/cdn/link-preview/snice-link-preview.min.js +1 -1
  107. package/dist/cdn/list/snice-list.js +1 -1
  108. package/dist/cdn/list/snice-list.min.js +1 -1
  109. package/dist/cdn/location/snice-location.js +1 -1
  110. package/dist/cdn/location/snice-location.min.js +1 -1
  111. package/dist/cdn/login/snice-login.js +1 -1
  112. package/dist/cdn/login/snice-login.min.js +1 -1
  113. package/dist/cdn/map/snice-map.js +1 -1
  114. package/dist/cdn/map/snice-map.min.js +1 -1
  115. package/dist/cdn/markdown/snice-markdown.js +1 -1
  116. package/dist/cdn/markdown/snice-markdown.min.js +1 -1
  117. package/dist/cdn/masonry/snice-masonry.js +1 -1
  118. package/dist/cdn/masonry/snice-masonry.min.js +1 -1
  119. package/dist/cdn/menu/snice-menu.js +1 -1
  120. package/dist/cdn/menu/snice-menu.min.js +1 -1
  121. package/dist/cdn/modal/snice-modal.js +1 -1
  122. package/dist/cdn/modal/snice-modal.min.js +1 -1
  123. package/dist/cdn/music-player/snice-music-player.js +1 -1
  124. package/dist/cdn/music-player/snice-music-player.min.js +1 -1
  125. package/dist/cdn/nav/snice-nav.js +1 -1
  126. package/dist/cdn/nav/snice-nav.min.js +1 -1
  127. package/dist/cdn/network-graph/snice-network-graph.js +1 -1
  128. package/dist/cdn/network-graph/snice-network-graph.min.js +1 -1
  129. package/dist/cdn/notification-center/snice-notification-center.js +1 -1
  130. package/dist/cdn/notification-center/snice-notification-center.min.js +1 -1
  131. package/dist/cdn/org-chart/snice-org-chart.js +1 -1
  132. package/dist/cdn/org-chart/snice-org-chart.min.js +1 -1
  133. package/dist/cdn/pagination/snice-pagination.js +1 -1
  134. package/dist/cdn/pagination/snice-pagination.min.js +1 -1
  135. package/dist/cdn/paint/snice-paint.js +1 -1
  136. package/dist/cdn/paint/snice-paint.min.js +1 -1
  137. package/dist/cdn/pdf-viewer/snice-pdf-viewer.js +1 -1
  138. package/dist/cdn/pdf-viewer/snice-pdf-viewer.min.js +1 -1
  139. package/dist/cdn/podcast-player/snice-podcast-player.js +1 -1
  140. package/dist/cdn/podcast-player/snice-podcast-player.min.js +1 -1
  141. package/dist/cdn/pricing-table/snice-pricing-table.js +1 -1
  142. package/dist/cdn/pricing-table/snice-pricing-table.min.js +1 -1
  143. package/dist/cdn/progress/snice-progress.js +1 -1
  144. package/dist/cdn/progress/snice-progress.min.js +1 -1
  145. package/dist/cdn/qr-code/snice-qr-code.js +1 -1
  146. package/dist/cdn/qr-code/snice-qr-code.min.js +1 -1
  147. package/dist/cdn/qr-reader/snice-qr-reader.js +1 -1
  148. package/dist/cdn/qr-reader/snice-qr-reader.min.js +1 -1
  149. package/dist/cdn/radio/snice-radio.js +1 -1
  150. package/dist/cdn/radio/snice-radio.min.js +1 -1
  151. package/dist/cdn/rating/snice-rating.js +1 -1
  152. package/dist/cdn/rating/snice-rating.min.js +1 -1
  153. package/dist/cdn/recipe/snice-recipe.js +1 -1
  154. package/dist/cdn/recipe/snice-recipe.min.js +1 -1
  155. package/dist/cdn/runtime/snice-runtime.esm.js +4 -4
  156. package/dist/cdn/runtime/snice-runtime.esm.js.map +1 -1
  157. package/dist/cdn/runtime/snice-runtime.esm.min.js +4 -4
  158. package/dist/cdn/runtime/snice-runtime.esm.min.js.map +1 -1
  159. package/dist/cdn/runtime/snice-runtime.js +4 -4
  160. package/dist/cdn/runtime/snice-runtime.js.map +1 -1
  161. package/dist/cdn/runtime/snice-runtime.min.js +4 -4
  162. package/dist/cdn/runtime/snice-runtime.min.js.map +1 -1
  163. package/dist/cdn/sankey/snice-sankey.js +1 -1
  164. package/dist/cdn/sankey/snice-sankey.min.js +1 -1
  165. package/dist/cdn/select/snice-select.js +1 -1
  166. package/dist/cdn/select/snice-select.min.js +1 -1
  167. package/dist/cdn/skeleton/snice-skeleton.js +1 -1
  168. package/dist/cdn/skeleton/snice-skeleton.min.js +1 -1
  169. package/dist/cdn/slider/snice-slider.js +1 -1
  170. package/dist/cdn/slider/snice-slider.min.js +1 -1
  171. package/dist/cdn/sortable/snice-sortable.js +1 -1
  172. package/dist/cdn/sortable/snice-sortable.min.js +1 -1
  173. package/dist/cdn/sparkline/snice-sparkline.js +1 -1
  174. package/dist/cdn/sparkline/snice-sparkline.min.js +1 -1
  175. package/dist/cdn/spinner/snice-spinner.js +1 -1
  176. package/dist/cdn/spinner/snice-spinner.min.js +1 -1
  177. package/dist/cdn/split-pane/snice-split-pane.js +1 -1
  178. package/dist/cdn/split-pane/snice-split-pane.min.js +1 -1
  179. package/dist/cdn/spotlight/snice-spotlight.js +1 -1
  180. package/dist/cdn/spotlight/snice-spotlight.min.js +1 -1
  181. package/dist/cdn/spreadsheet/snice-spreadsheet.js +1 -1
  182. package/dist/cdn/spreadsheet/snice-spreadsheet.min.js +1 -1
  183. package/dist/cdn/stepper/snice-stepper.js +1 -1
  184. package/dist/cdn/stepper/snice-stepper.min.js +1 -1
  185. package/dist/cdn/switch/snice-switch.js +1 -1
  186. package/dist/cdn/switch/snice-switch.min.js +1 -1
  187. package/dist/cdn/table/snice-table.js +1 -1
  188. package/dist/cdn/table/snice-table.min.js +1 -1
  189. package/dist/cdn/tabs/snice-tabs.js +1 -1
  190. package/dist/cdn/tabs/snice-tabs.min.js +1 -1
  191. package/dist/cdn/tag-input/snice-tag-input.js +1 -1
  192. package/dist/cdn/tag-input/snice-tag-input.min.js +1 -1
  193. package/dist/cdn/terminal/snice-terminal.js +1 -1
  194. package/dist/cdn/terminal/snice-terminal.min.js +1 -1
  195. package/dist/cdn/testimonial/snice-testimonial.js +1 -1
  196. package/dist/cdn/testimonial/snice-testimonial.min.js +1 -1
  197. package/dist/cdn/textarea/snice-textarea.js +1 -1
  198. package/dist/cdn/textarea/snice-textarea.min.js +1 -1
  199. package/dist/cdn/time-range-picker/snice-time-range-picker.js +1 -1
  200. package/dist/cdn/time-range-picker/snice-time-range-picker.min.js +1 -1
  201. package/dist/cdn/timeline/snice-timeline.js +1 -1
  202. package/dist/cdn/timeline/snice-timeline.min.js +1 -1
  203. package/dist/cdn/timer/snice-timer.js +1 -1
  204. package/dist/cdn/timer/snice-timer.min.js +1 -1
  205. package/dist/cdn/toast/snice-toast.js +1 -1
  206. package/dist/cdn/toast/snice-toast.min.js +1 -1
  207. package/dist/cdn/tooltip/snice-tooltip.js +1 -1
  208. package/dist/cdn/tooltip/snice-tooltip.min.js +1 -1
  209. package/dist/cdn/tree/snice-tree.js +1 -1
  210. package/dist/cdn/tree/snice-tree.min.js +1 -1
  211. package/dist/cdn/treemap/snice-treemap.js +1 -1
  212. package/dist/cdn/treemap/snice-treemap.min.js +1 -1
  213. package/dist/cdn/video-player/snice-video-player.js +1 -1
  214. package/dist/cdn/video-player/snice-video-player.min.js +1 -1
  215. package/dist/cdn/virtual-scroller/snice-virtual-scroller.js +1 -1
  216. package/dist/cdn/virtual-scroller/snice-virtual-scroller.min.js +1 -1
  217. package/dist/cdn/waterfall/snice-waterfall.js +1 -1
  218. package/dist/cdn/waterfall/snice-waterfall.min.js +1 -1
  219. package/dist/cdn/weather/snice-weather.js +1 -1
  220. package/dist/cdn/weather/snice-weather.min.js +1 -1
  221. package/dist/components/code-block/formatter.d.ts +26 -0
  222. package/dist/components/code-block/formatter.js +245 -0
  223. package/dist/components/code-block/formatter.js.map +1 -0
  224. package/dist/components/code-block/formatters/indent.d.ts +25 -0
  225. package/dist/components/code-block/formatters/indent.js +95 -0
  226. package/dist/components/code-block/formatters/indent.js.map +1 -0
  227. package/dist/components/code-block/formatters/json.d.ts +25 -0
  228. package/dist/components/code-block/formatters/json.js +38 -0
  229. package/dist/components/code-block/formatters/json.js.map +1 -0
  230. package/dist/components/code-block/formatters/prettier.d.ts +53 -0
  231. package/dist/components/code-block/formatters/prettier.js +82 -0
  232. package/dist/components/code-block/formatters/prettier.js.map +1 -0
  233. package/dist/components/code-block/grammars/css.json +13 -0
  234. package/dist/components/code-block/grammars/json.json +13 -0
  235. package/dist/components/code-block/grammars/snice.json +14 -0
  236. package/dist/components/code-block/grammars/typescript.json +14 -0
  237. package/dist/components/code-block/highlighter.d.ts +1 -0
  238. package/dist/components/code-block/highlighter.js.map +1 -1
  239. package/dist/components/code-block/snice-code-block.d.ts +7 -1
  240. package/dist/components/code-block/snice-code-block.js +71 -2
  241. package/dist/components/code-block/snice-code-block.js.map +1 -1
  242. package/dist/components/code-block/snice-code-block.types.d.ts +11 -0
  243. package/dist/index.cjs +1 -1
  244. package/dist/index.esm.js +1 -1
  245. package/dist/index.iife.js +1 -1
  246. package/dist/symbols.cjs +1 -1
  247. package/dist/symbols.esm.js +1 -1
  248. package/dist/transitions.cjs +1 -1
  249. package/dist/transitions.esm.js +1 -1
  250. package/docs/ai/components/code-block.md +71 -0
  251. package/docs/components/code-block.md +126 -0
  252. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * snice v4.16.0
2
+ * snice v4.17.0
3
3
  * Imperative TypeScript framework for building vanilla web components with decorators, differential rendering, routing, and controllers. No virtual DOM, no build complexity.
4
4
  * (c) 2024
5
5
  * Released under the MIT License.
@@ -239,10 +239,265 @@ var SniceCodeBlock = (function (exports, snice) {
239
239
  return tokensToHtml(tokens);
240
240
  }
241
241
 
242
+ /**
243
+ * Declarative grammar-based code formatter for snice-code-block.
244
+ *
245
+ * Rules are defined in grammar JSON files under "formatters" section.
246
+ * The engine scans code char by char, tracks string/comment context,
247
+ * and applies newline/space/indent rules based on regex char classes.
248
+ */
249
+ /**
250
+ * Format code using declarative rules.
251
+ */
252
+ function formatCode(code, rules) {
253
+ const tabSize = rules.tabSize ?? 2;
254
+ const useTabs = rules.useTabs ?? false;
255
+ const indentUnit = useTabs ? '\t' : ' '.repeat(tabSize);
256
+ const trimTrailing = rules.trimTrailing ?? true;
257
+ const skipStrings = rules.skipStrings ?? true;
258
+ const skipComments = rules.skipComments ?? true;
259
+ const newlineAfter = rules.newlineAfter ? new RegExp(rules.newlineAfter) : null;
260
+ const newlineBefore = rules.newlineBefore ? new RegExp(rules.newlineBefore) : null;
261
+ const spaceAfter = rules.spaceAfter ? new RegExp(rules.spaceAfter) : null;
262
+ const spaceBefore = rules.spaceBefore ? new RegExp(rules.spaceBefore) : null;
263
+ const spaceAround = rules.spaceAround ? new RegExp(rules.spaceAround) : null;
264
+ const indentRe = rules.indent ? new RegExp(rules.indent) : null;
265
+ const dedentRe = rules.dedent ? new RegExp(rules.dedent) : null;
266
+ // Strip existing formatting: collapse whitespace outside strings/comments
267
+ const stripped = stripWhitespace(code, skipStrings, skipComments);
268
+ // Build formatted output
269
+ let result = '';
270
+ let depth = 0;
271
+ let lineStart = true;
272
+ let inString = null;
273
+ let inComment = false; // block comment
274
+ let inLineComment = false;
275
+ for (let i = 0; i < stripped.length; i++) {
276
+ const ch = stripped[i];
277
+ const prev = i > 0 ? stripped[i - 1] : '';
278
+ const next = i + 1 < stripped.length ? stripped[i + 1] : '';
279
+ // Track string context
280
+ if (!inComment && !inLineComment && skipStrings) {
281
+ if (inString) {
282
+ result += ch;
283
+ if (ch === inString && prev !== '\\') {
284
+ inString = null;
285
+ }
286
+ continue;
287
+ }
288
+ if (ch === '"' || ch === "'" || ch === '`') {
289
+ inString = ch;
290
+ if (lineStart) {
291
+ result += indentUnit.repeat(depth);
292
+ lineStart = false;
293
+ }
294
+ result += ch;
295
+ continue;
296
+ }
297
+ }
298
+ // Track comment context
299
+ if (skipComments) {
300
+ if (inLineComment) {
301
+ result += ch;
302
+ if (ch === '\n') {
303
+ inLineComment = false;
304
+ lineStart = true;
305
+ }
306
+ continue;
307
+ }
308
+ if (inComment) {
309
+ result += ch;
310
+ if (ch === '/' && prev === '*') {
311
+ inComment = false;
312
+ }
313
+ continue;
314
+ }
315
+ if (ch === '/' && next === '/') {
316
+ if (lineStart) {
317
+ result += indentUnit.repeat(depth);
318
+ lineStart = false;
319
+ }
320
+ inLineComment = true;
321
+ result += ch;
322
+ continue;
323
+ }
324
+ if (ch === '/' && next === '*') {
325
+ if (lineStart) {
326
+ result += indentUnit.repeat(depth);
327
+ lineStart = false;
328
+ }
329
+ inComment = true;
330
+ result += ch;
331
+ continue;
332
+ }
333
+ }
334
+ // Dedent before the char
335
+ if (dedentRe && dedentRe.test(ch)) {
336
+ depth = Math.max(0, depth - 1);
337
+ }
338
+ // Newline before
339
+ if (newlineBefore && newlineBefore.test(ch)) {
340
+ if (!lineStart) {
341
+ result = trimTrailingSpaces(result);
342
+ result += '\n';
343
+ lineStart = true;
344
+ }
345
+ }
346
+ // Space before (including spaceAround)
347
+ if ((spaceBefore && spaceBefore.test(ch)) || (spaceAround && spaceAround.test(ch))) {
348
+ if (!lineStart && result.length > 0 && result[result.length - 1] !== ' ' && result[result.length - 1] !== '\n') {
349
+ result += ' ';
350
+ }
351
+ }
352
+ // Write indent if at line start
353
+ if (lineStart && ch !== '\n') {
354
+ result += indentUnit.repeat(depth);
355
+ lineStart = false;
356
+ }
357
+ result += ch;
358
+ // Indent after the char
359
+ if (indentRe && indentRe.test(ch)) {
360
+ depth++;
361
+ }
362
+ // Space after (including spaceAround)
363
+ if ((spaceAfter && spaceAfter.test(ch)) || (spaceAround && spaceAround.test(ch))) {
364
+ if (next && next !== '\n' && next !== ' ') {
365
+ result += ' ';
366
+ }
367
+ }
368
+ // Newline after
369
+ if (newlineAfter && newlineAfter.test(ch)) {
370
+ result = trimTrailingSpaces(result);
371
+ result += '\n';
372
+ lineStart = true;
373
+ }
374
+ }
375
+ // Post-processing
376
+ let lines = result.split('\n');
377
+ if (trimTrailing) {
378
+ lines = lines.map(l => l.replace(/\s+$/, ''));
379
+ }
380
+ if (rules.collapseBlankLines !== undefined) {
381
+ lines = collapseBlankLinesArr(lines, rules.collapseBlankLines);
382
+ }
383
+ // Trim leading/trailing blank lines
384
+ while (lines.length > 0 && lines[0].trim() === '')
385
+ lines.shift();
386
+ while (lines.length > 0 && lines[lines.length - 1].trim() === '')
387
+ lines.pop();
388
+ return lines.join('\n');
389
+ }
390
+ /**
391
+ * Strip existing whitespace: replace runs of whitespace (outside strings/comments)
392
+ * with a single space, and remove all newlines.
393
+ */
394
+ function stripWhitespace(code, skipStrings, skipComments) {
395
+ let result = '';
396
+ let inString = null;
397
+ let inComment = false;
398
+ let inLineComment = false;
399
+ for (let i = 0; i < code.length; i++) {
400
+ const ch = code[i];
401
+ const prev = i > 0 ? code[i - 1] : '';
402
+ const next = i + 1 < code.length ? code[i + 1] : '';
403
+ // Track strings
404
+ if (!inComment && !inLineComment && skipStrings) {
405
+ if (inString) {
406
+ result += ch;
407
+ if (ch === inString && prev !== '\\') {
408
+ inString = null;
409
+ }
410
+ continue;
411
+ }
412
+ if (ch === '"' || ch === "'" || ch === '`') {
413
+ inString = ch;
414
+ result += ch;
415
+ continue;
416
+ }
417
+ }
418
+ // Track comments
419
+ if (skipComments) {
420
+ if (inLineComment) {
421
+ if (ch === '\n') {
422
+ inLineComment = false;
423
+ // Emit the newline so line comments stay separate
424
+ result += ch;
425
+ }
426
+ else {
427
+ result += ch;
428
+ }
429
+ continue;
430
+ }
431
+ if (inComment) {
432
+ result += ch;
433
+ if (ch === '/' && prev === '*') {
434
+ inComment = false;
435
+ }
436
+ continue;
437
+ }
438
+ if (ch === '/' && next === '/') {
439
+ inLineComment = true;
440
+ result += ch;
441
+ continue;
442
+ }
443
+ if (ch === '/' && next === '*') {
444
+ inComment = true;
445
+ result += ch;
446
+ continue;
447
+ }
448
+ }
449
+ // Collapse whitespace
450
+ if (/\s/.test(ch)) {
451
+ if (result.length > 0 && !/\s/.test(result[result.length - 1])) {
452
+ result += ' ';
453
+ }
454
+ }
455
+ else {
456
+ result += ch;
457
+ }
458
+ }
459
+ return result;
460
+ }
461
+ function trimTrailingSpaces(s) {
462
+ let end = s.length;
463
+ while (end > 0 && s[end - 1] === ' ')
464
+ end--;
465
+ return s.slice(0, end);
466
+ }
467
+ function collapseBlankLinesArr(lines, max) {
468
+ const result = [];
469
+ let blankCount = 0;
470
+ for (const line of lines) {
471
+ if (line.trim() === '') {
472
+ blankCount++;
473
+ if (blankCount <= max) {
474
+ result.push(line);
475
+ }
476
+ }
477
+ else {
478
+ blankCount = 0;
479
+ result.push(line);
480
+ }
481
+ }
482
+ return result;
483
+ }
484
+
242
485
  var cssContent = ":host{display:block}.code-block{position:relative;background:hsl(var(--snice-color-gray-900));border-radius:var(--snice-border-radius-md,.375rem);overflow:hidden}.code-block__header{display:flex;justify-content:space-between;align-items:center;padding:var(--snice-spacing-sm,.75rem) var(--snice-spacing-md,1rem);background:hsl(var(--snice-color-gray-800));border-bottom:1px solid hsl(var(--snice-color-gray-700))}.code-block__filename{font-size:var(--snice-font-size-sm, .875rem);color:hsl(var(--snice-color-gray-300));font-family:var(--snice-font-family-mono, monospace)}.code-block__copy{background:0 0;border:1px solid hsl(var(--snice-color-gray-600));color:hsl(var(--snice-color-gray-300));padding:.25rem .5rem;border-radius:var(--snice-border-radius-sm,.25rem);cursor:pointer;font-size:var(--snice-font-size-xs, .75rem);transition:.2s}.code-block__copy:hover{background:hsl(var(--snice-color-gray-700));border-color:hsl(var(--snice-color-gray-500))}.code-block__copy--copied{background:var(--snice-color-success);border-color:hsl(var(--snice-color-green-500));color:hsl(0 0% 100%)}.code-block__content{overflow-x:auto}.code-block__pre{margin:0;padding:var(--snice-spacing-md,1rem);background:0 0;overflow-x:auto}.code-block__code{font-family:var(--snice-font-family-mono, 'Courier New', monospace);font-size:var(--snice-font-size-sm, .875rem);line-height:1.5;color:hsl(var(--snice-color-gray-100));display:block}.code-block__line{display:block}.code-block__line--highlight{background:hsl(0 0% 100% / .1);border-left:3px solid var(--snice-color-primary);padding-left:calc(var(--snice-spacing-sm,.75rem) - 3px);margin-left:calc(-1 * var(--snice-spacing-md,1rem));padding-right:var(--snice-spacing-md,1rem)}.code-block__line-number{display:inline-block;width:3rem;text-align:right;margin-right:var(--snice-spacing-md,1rem);color:hsl(var(--snice-color-gray-500));user-select:none}.token.keyword{color:var(--code-keyword-color,#c678dd)}.token.function{color:var(--code-function-color,#61afef)}.token.string{color:var(--code-string-color,#98c379)}.token.number{color:var(--code-number-color,#d19a66)}.token.comment{color:var(--code-comment-color,#6a9955);font-style:italic}.token.operator{color:var(--code-operator-color,#56b6c2)}.token.punctuation{color:var(--code-punctuation-color,#abb2bf)}.token.tag{color:var(--code-tag-color,#e06c75)}.token.attr-name,.token.property{color:var(--code-attr-name-color,#d19a66)}.token.attr-value{color:var(--code-attr-value-color,#98c379)}.token.boolean,.token.constant{color:var(--code-constant-color,#d19a66)}.token.class-name{color:var(--code-class-color,#e5c07b)}.token.builtin{color:var(--code-builtin-color,#e06c75)}.token.regex{color:var(--code-regex-color,#98c379)}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}";
243
486
 
244
487
  const LOAD_GRAMMAR_REQUEST = 'snice/code-block/load-grammar';
245
488
 
489
+ function dedent(text) {
490
+ const lines = text.replace(/^\n+/, '').replace(/\n\s*$/, '').split('\n');
491
+ if (lines.length === 0)
492
+ return '';
493
+ const indents = lines.filter(l => l.trim()).map(l => l.match(/^(\s*)/)?.[1].length ?? 0);
494
+ if (indents.length === 0)
495
+ return lines.join('\n');
496
+ const minIndent = Math.min(...indents);
497
+ if (minIndent === 0)
498
+ return lines.join('\n');
499
+ return lines.map(l => l.slice(minIndent)).join('\n');
500
+ }
246
501
  let SniceCodeBlock = (() => {
247
502
  let _classDecorators = [snice.element('snice-code-block')];
248
503
  let _classDescriptor;
@@ -274,6 +529,9 @@ var SniceCodeBlock = (function (exports, snice) {
274
529
  let _fetchMode_decorators;
275
530
  let _fetchMode_initializers = [];
276
531
  let _fetchMode_extraInitializers = [];
532
+ let _format_decorators;
533
+ let _format_initializers = [];
534
+ let _format_extraInitializers = [];
277
535
  let _codeEl_decorators;
278
536
  let _codeEl_initializers = [];
279
537
  let _codeEl_extraInitializers = [];
@@ -289,6 +547,8 @@ var SniceCodeBlock = (function (exports, snice) {
289
547
  let _dispatchCopyEvent_decorators;
290
548
  let _dispatchBeforeHighlightEvent_decorators;
291
549
  let _dispatchAfterHighlightEvent_decorators;
550
+ let _dispatchBeforeFormatEvent_decorators;
551
+ let _dispatchAfterFormatEvent_decorators;
292
552
  let _dispatchGrammarRequestEvent_decorators;
293
553
  let _dispatchGrammarLoadedEvent_decorators;
294
554
  let _requestGrammar_decorators;
@@ -298,6 +558,7 @@ var SniceCodeBlock = (function (exports, snice) {
298
558
  let _handleSlotChange_decorators;
299
559
  let _onGrammarChange_decorators;
300
560
  let _onFetchModeChange_decorators;
561
+ let _onFormatChange_decorators;
301
562
  let _updateHeader_decorators;
302
563
  let _onLanguageChange_decorators;
303
564
  (class extends _classSuper {
@@ -312,6 +573,7 @@ var SniceCodeBlock = (function (exports, snice) {
312
573
  _filename_decorators = [snice.property({})];
313
574
  _grammar_decorators = [snice.property({})];
314
575
  _fetchMode_decorators = [snice.property({ attribute: 'fetch-mode' })];
576
+ _format_decorators = [snice.property({})];
315
577
  _codeEl_decorators = [snice.query('.code-block__code')];
316
578
  _headerEl_decorators = [snice.query('.code-block__header')];
317
579
  _filenameEl_decorators = [snice.query('.code-block__filename')];
@@ -319,6 +581,8 @@ var SniceCodeBlock = (function (exports, snice) {
319
581
  _dispatchCopyEvent_decorators = [snice.dispatch('code-copy', { bubbles: true, composed: true })];
320
582
  _dispatchBeforeHighlightEvent_decorators = [snice.dispatch('code-before-highlight', { bubbles: true, composed: true })];
321
583
  _dispatchAfterHighlightEvent_decorators = [snice.dispatch('code-after-highlight', { bubbles: true, composed: true })];
584
+ _dispatchBeforeFormatEvent_decorators = [snice.dispatch('code-before-format', { bubbles: true, composed: true })];
585
+ _dispatchAfterFormatEvent_decorators = [snice.dispatch('code-after-format', { bubbles: true, composed: true })];
322
586
  _dispatchGrammarRequestEvent_decorators = [snice.dispatch('grammar-request', { bubbles: true, composed: true })];
323
587
  _dispatchGrammarLoadedEvent_decorators = [snice.dispatch('grammar-loaded', { bubbles: true, composed: true })];
324
588
  _requestGrammar_decorators = [snice.request(LOAD_GRAMMAR_REQUEST)];
@@ -328,11 +592,14 @@ var SniceCodeBlock = (function (exports, snice) {
328
592
  _handleSlotChange_decorators = [snice.on('slotchange', { target: 'slot' })];
329
593
  _onGrammarChange_decorators = [snice.watch('grammar')];
330
594
  _onFetchModeChange_decorators = [snice.watch('fetchMode')];
595
+ _onFormatChange_decorators = [snice.watch('format')];
331
596
  _updateHeader_decorators = [snice.watch('filename', 'copyable')];
332
597
  _onLanguageChange_decorators = [snice.watch('language')];
333
598
  __esDecorate(this, null, _dispatchCopyEvent_decorators, { kind: "method", name: "dispatchCopyEvent", static: false, private: false, access: { has: obj => "dispatchCopyEvent" in obj, get: obj => obj.dispatchCopyEvent }, metadata: _metadata }, null, _instanceExtraInitializers);
334
599
  __esDecorate(this, null, _dispatchBeforeHighlightEvent_decorators, { kind: "method", name: "dispatchBeforeHighlightEvent", static: false, private: false, access: { has: obj => "dispatchBeforeHighlightEvent" in obj, get: obj => obj.dispatchBeforeHighlightEvent }, metadata: _metadata }, null, _instanceExtraInitializers);
335
600
  __esDecorate(this, null, _dispatchAfterHighlightEvent_decorators, { kind: "method", name: "dispatchAfterHighlightEvent", static: false, private: false, access: { has: obj => "dispatchAfterHighlightEvent" in obj, get: obj => obj.dispatchAfterHighlightEvent }, metadata: _metadata }, null, _instanceExtraInitializers);
601
+ __esDecorate(this, null, _dispatchBeforeFormatEvent_decorators, { kind: "method", name: "dispatchBeforeFormatEvent", static: false, private: false, access: { has: obj => "dispatchBeforeFormatEvent" in obj, get: obj => obj.dispatchBeforeFormatEvent }, metadata: _metadata }, null, _instanceExtraInitializers);
602
+ __esDecorate(this, null, _dispatchAfterFormatEvent_decorators, { kind: "method", name: "dispatchAfterFormatEvent", static: false, private: false, access: { has: obj => "dispatchAfterFormatEvent" in obj, get: obj => obj.dispatchAfterFormatEvent }, metadata: _metadata }, null, _instanceExtraInitializers);
336
603
  __esDecorate(this, null, _dispatchGrammarRequestEvent_decorators, { kind: "method", name: "dispatchGrammarRequestEvent", static: false, private: false, access: { has: obj => "dispatchGrammarRequestEvent" in obj, get: obj => obj.dispatchGrammarRequestEvent }, metadata: _metadata }, null, _instanceExtraInitializers);
337
604
  __esDecorate(this, null, _dispatchGrammarLoadedEvent_decorators, { kind: "method", name: "dispatchGrammarLoadedEvent", static: false, private: false, access: { has: obj => "dispatchGrammarLoadedEvent" in obj, get: obj => obj.dispatchGrammarLoadedEvent }, metadata: _metadata }, null, _instanceExtraInitializers);
338
605
  __esDecorate(this, null, _requestGrammar_decorators, { kind: "method", name: "requestGrammar", static: false, private: false, access: { has: obj => "requestGrammar" in obj, get: obj => obj.requestGrammar }, metadata: _metadata }, null, _instanceExtraInitializers);
@@ -342,6 +609,7 @@ var SniceCodeBlock = (function (exports, snice) {
342
609
  __esDecorate(this, null, _handleSlotChange_decorators, { kind: "method", name: "handleSlotChange", static: false, private: false, access: { has: obj => "handleSlotChange" in obj, get: obj => obj.handleSlotChange }, metadata: _metadata }, null, _instanceExtraInitializers);
343
610
  __esDecorate(this, null, _onGrammarChange_decorators, { kind: "method", name: "onGrammarChange", static: false, private: false, access: { has: obj => "onGrammarChange" in obj, get: obj => obj.onGrammarChange }, metadata: _metadata }, null, _instanceExtraInitializers);
344
611
  __esDecorate(this, null, _onFetchModeChange_decorators, { kind: "method", name: "onFetchModeChange", static: false, private: false, access: { has: obj => "onFetchModeChange" in obj, get: obj => obj.onFetchModeChange }, metadata: _metadata }, null, _instanceExtraInitializers);
612
+ __esDecorate(this, null, _onFormatChange_decorators, { kind: "method", name: "onFormatChange", static: false, private: false, access: { has: obj => "onFormatChange" in obj, get: obj => obj.onFormatChange }, metadata: _metadata }, null, _instanceExtraInitializers);
345
613
  __esDecorate(this, null, _updateHeader_decorators, { kind: "method", name: "updateHeader", static: false, private: false, access: { has: obj => "updateHeader" in obj, get: obj => obj.updateHeader }, metadata: _metadata }, null, _instanceExtraInitializers);
346
614
  __esDecorate(this, null, _onLanguageChange_decorators, { kind: "method", name: "onLanguageChange", static: false, private: false, access: { has: obj => "onLanguageChange" in obj, get: obj => obj.onLanguageChange }, metadata: _metadata }, null, _instanceExtraInitializers);
347
615
  __esDecorate(null, null, _language_decorators, { kind: "field", name: "language", static: false, private: false, access: { has: obj => "language" in obj, get: obj => obj.language, set: (obj, value) => { obj.language = value; } }, metadata: _metadata }, _language_initializers, _language_extraInitializers);
@@ -352,6 +620,7 @@ var SniceCodeBlock = (function (exports, snice) {
352
620
  __esDecorate(null, null, _filename_decorators, { kind: "field", name: "filename", static: false, private: false, access: { has: obj => "filename" in obj, get: obj => obj.filename, set: (obj, value) => { obj.filename = value; } }, metadata: _metadata }, _filename_initializers, _filename_extraInitializers);
353
621
  __esDecorate(null, null, _grammar_decorators, { kind: "field", name: "grammar", static: false, private: false, access: { has: obj => "grammar" in obj, get: obj => obj.grammar, set: (obj, value) => { obj.grammar = value; } }, metadata: _metadata }, _grammar_initializers, _grammar_extraInitializers);
354
622
  __esDecorate(null, null, _fetchMode_decorators, { kind: "field", name: "fetchMode", static: false, private: false, access: { has: obj => "fetchMode" in obj, get: obj => obj.fetchMode, set: (obj, value) => { obj.fetchMode = value; } }, metadata: _metadata }, _fetchMode_initializers, _fetchMode_extraInitializers);
623
+ __esDecorate(null, null, _format_decorators, { kind: "field", name: "format", static: false, private: false, access: { has: obj => "format" in obj, get: obj => obj.format, set: (obj, value) => { obj.format = value; } }, metadata: _metadata }, _format_initializers, _format_extraInitializers);
355
624
  __esDecorate(null, null, _codeEl_decorators, { kind: "field", name: "codeEl", static: false, private: false, access: { has: obj => "codeEl" in obj, get: obj => obj.codeEl, set: (obj, value) => { obj.codeEl = value; } }, metadata: _metadata }, _codeEl_initializers, _codeEl_extraInitializers);
356
625
  __esDecorate(null, null, _headerEl_decorators, { kind: "field", name: "headerEl", static: false, private: false, access: { has: obj => "headerEl" in obj, get: obj => obj.headerEl, set: (obj, value) => { obj.headerEl = value; } }, metadata: _metadata }, _headerEl_initializers, _headerEl_extraInitializers);
357
626
  __esDecorate(null, null, _filenameEl_decorators, { kind: "field", name: "filenameEl", static: false, private: false, access: { has: obj => "filenameEl" in obj, get: obj => obj.filenameEl, set: (obj, value) => { obj.filenameEl = value; } }, metadata: _metadata }, _filenameEl_initializers, _filenameEl_extraInitializers);
@@ -370,6 +639,12 @@ var SniceCodeBlock = (function (exports, snice) {
370
639
  dispatchAfterHighlightEvent() {
371
640
  return { code: this.code, language: this.language, codeBlock: this };
372
641
  }
642
+ dispatchBeforeFormatEvent() {
643
+ return { code: this.code, language: this.language, codeBlock: this };
644
+ }
645
+ dispatchAfterFormatEvent() {
646
+ return { code: this.code, language: this.language, codeBlock: this };
647
+ }
373
648
  dispatchGrammarRequestEvent() {
374
649
  return { url: this.grammar, language: this.language, codeBlock: this };
375
650
  }
@@ -415,7 +690,10 @@ var SniceCodeBlock = (function (exports, snice) {
415
690
  this.readSlottedContent();
416
691
  }
417
692
  readSlottedContent() {
418
- const text = this.textContent?.trim();
693
+ const raw = this.textContent;
694
+ if (!raw)
695
+ return;
696
+ const text = dedent(raw);
419
697
  if (text) {
420
698
  this.code = text;
421
699
  this.highlight();
@@ -435,6 +713,11 @@ var SniceCodeBlock = (function (exports, snice) {
435
713
  this.highlight();
436
714
  }
437
715
  }
716
+ onFormatChange() {
717
+ if (this.code) {
718
+ this.highlight();
719
+ }
720
+ }
438
721
  updateHeader() {
439
722
  if (!this.headerEl)
440
723
  return;
@@ -500,6 +783,9 @@ var SniceCodeBlock = (function (exports, snice) {
500
783
  setHighlighter(highlighter) {
501
784
  this.highlighter = highlighter;
502
785
  }
786
+ setFormatter(formatter) {
787
+ this._formatter = formatter;
788
+ }
503
789
  setGrammar(grammar) {
504
790
  this.loadedGrammar = grammar;
505
791
  this.loadedGrammarUrl = null;
@@ -551,6 +837,30 @@ var SniceCodeBlock = (function (exports, snice) {
551
837
  if (!this.code)
552
838
  return;
553
839
  const version = ++this.highlightVersion;
840
+ // Resolve formatter: imperative setFormatter() wins, then grammar-based
841
+ let formatFn = this._formatter;
842
+ if (!formatFn && this.format) {
843
+ const grammar = await this.resolveGrammar();
844
+ if (version !== this.highlightVersion)
845
+ return;
846
+ if (grammar?.formatters?.[this.format]) {
847
+ const rules = grammar.formatters[this.format];
848
+ formatFn = (code) => formatCode(code, rules);
849
+ }
850
+ }
851
+ if (formatFn && this.format) {
852
+ this.dispatchBeforeFormatEvent();
853
+ try {
854
+ const formatted = await formatFn(this.code, this.language);
855
+ if (version !== this.highlightVersion)
856
+ return;
857
+ this.code = formatted;
858
+ this.dispatchAfterFormatEvent();
859
+ }
860
+ catch (error) {
861
+ console.error('Code formatting failed:', error);
862
+ }
863
+ }
554
864
  this.dispatchBeforeHighlightEvent();
555
865
  try {
556
866
  if (this.highlighter) {
@@ -585,7 +895,8 @@ var SniceCodeBlock = (function (exports, snice) {
585
895
  this.filename = (__runInitializers(this, _copyable_extraInitializers), __runInitializers(this, _filename_initializers, ''));
586
896
  this.grammar = (__runInitializers(this, _filename_extraInitializers), __runInitializers(this, _grammar_initializers, ''));
587
897
  this.fetchMode = (__runInitializers(this, _grammar_extraInitializers), __runInitializers(this, _fetchMode_initializers, 'native'));
588
- this.highlighter = __runInitializers(this, _fetchMode_extraInitializers);
898
+ this.format = (__runInitializers(this, _fetchMode_extraInitializers), __runInitializers(this, _format_initializers, ''));
899
+ this.highlighter = __runInitializers(this, _format_extraInitializers);
589
900
  this.copied = false;
590
901
  this.highlightedCode = '';
591
902
  this.loadedGrammar = null;