@maizzle/framework 6.0.0-rc.16 → 6.0.0-rc.17

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 (228) hide show
  1. package/dist/{build.d.mts → build.d.ts} +2 -2
  2. package/dist/build.d.ts.map +1 -0
  3. package/dist/build.mjs +1 -1
  4. package/dist/build.mjs.map +1 -1
  5. package/dist/components/Row.vue +3 -2
  6. package/dist/components/Tailwind.vue +43 -0
  7. package/dist/components/{utils.d.mts → utils.d.ts} +1 -1
  8. package/dist/components/utils.d.ts.map +1 -0
  9. package/dist/composables/{defineConfig.d.mts → defineConfig.d.ts} +2 -2
  10. package/dist/composables/defineConfig.d.ts.map +1 -0
  11. package/dist/composables/{renderContext.d.mts → renderContext.d.ts} +11 -5
  12. package/dist/composables/renderContext.d.ts.map +1 -0
  13. package/dist/composables/renderContext.mjs.map +1 -1
  14. package/dist/composables/{useConfig.d.mts → useConfig.d.ts} +2 -2
  15. package/dist/composables/useConfig.d.ts.map +1 -0
  16. package/dist/composables/{useDoctype.d.mts → useDoctype.d.ts} +1 -1
  17. package/dist/composables/useDoctype.d.ts.map +1 -0
  18. package/dist/composables/{useEvent.d.mts → useEvent.d.ts} +2 -2
  19. package/dist/composables/useEvent.d.ts.map +1 -0
  20. package/dist/composables/{useFont.d.mts → useFont.d.ts} +1 -1
  21. package/dist/composables/useFont.d.ts.map +1 -0
  22. package/dist/composables/{useOutlookFallback.d.mts → useOutlookFallback.d.ts} +1 -1
  23. package/dist/composables/useOutlookFallback.d.ts.map +1 -0
  24. package/dist/composables/{usePlaintext.d.mts → usePlaintext.d.ts} +1 -1
  25. package/dist/composables/usePlaintext.d.ts.map +1 -0
  26. package/dist/composables/{usePreheader.d.mts → usePreheader.d.ts} +1 -1
  27. package/dist/composables/usePreheader.d.ts.map +1 -0
  28. package/dist/config/{defaults.d.mts → defaults.d.ts} +2 -2
  29. package/dist/config/defaults.d.ts.map +1 -0
  30. package/dist/config/{index.d.mts → index.d.ts} +4 -4
  31. package/dist/config/index.d.ts.map +1 -0
  32. package/dist/events/{index.d.mts → index.d.ts} +2 -2
  33. package/dist/events/index.d.ts.map +1 -0
  34. package/dist/index.d.ts +34 -0
  35. package/dist/{plaintext.d.mts → plaintext.d.ts} +1 -1
  36. package/dist/plaintext.d.ts.map +1 -0
  37. package/dist/{plugin.d.mts → plugin.d.ts} +2 -2
  38. package/dist/plugin.d.ts.map +1 -0
  39. package/dist/plugins/postcss/{mergeMediaQueries.d.mts → mergeMediaQueries.d.ts} +2 -2
  40. package/dist/plugins/postcss/mergeMediaQueries.d.ts.map +1 -0
  41. package/dist/plugins/postcss/{pruneVars.d.mts → pruneVars.d.ts} +1 -1
  42. package/dist/plugins/postcss/pruneVars.d.ts.map +1 -0
  43. package/dist/plugins/postcss/{quoteFontFamilies.d.mts → quoteFontFamilies.d.ts} +1 -1
  44. package/dist/plugins/postcss/quoteFontFamilies.d.ts.map +1 -0
  45. package/dist/plugins/postcss/{removeDeclarations.d.mts → removeDeclarations.d.ts} +1 -1
  46. package/dist/plugins/postcss/removeDeclarations.d.ts.map +1 -0
  47. package/dist/plugins/postcss/resolveMaizzleImports.d.ts +16 -0
  48. package/dist/plugins/postcss/resolveMaizzleImports.d.ts.map +1 -0
  49. package/dist/plugins/postcss/resolveMaizzleImports.mjs +40 -0
  50. package/dist/plugins/postcss/resolveMaizzleImports.mjs.map +1 -0
  51. package/dist/plugins/postcss/{resolveProps.d.mts → resolveProps.d.ts} +1 -1
  52. package/dist/plugins/postcss/resolveProps.d.ts.map +1 -0
  53. package/dist/plugins/postcss/{tailwindCleanup.d.mts → tailwindCleanup.d.ts} +2 -2
  54. package/dist/plugins/postcss/tailwindCleanup.d.ts.map +1 -0
  55. package/dist/{prepare.d.mts → prepare.d.ts} +1 -1
  56. package/dist/prepare.d.ts.map +1 -0
  57. package/dist/render/{createRenderer.d.mts → createRenderer.d.ts} +4 -3
  58. package/dist/render/createRenderer.d.ts.map +1 -0
  59. package/dist/render/createRenderer.mjs +2 -1
  60. package/dist/render/createRenderer.mjs.map +1 -1
  61. package/dist/render/index.d.ts +18 -0
  62. package/dist/render/index.d.ts.map +1 -0
  63. package/dist/render/index.mjs +13 -14
  64. package/dist/render/index.mjs.map +1 -1
  65. package/dist/render/{injectFonts.d.mts → injectFonts.d.ts} +2 -2
  66. package/dist/render/injectFonts.d.ts.map +1 -0
  67. package/dist/render/plugins/{codeBlockExtract.d.mts → codeBlockExtract.d.ts} +1 -1
  68. package/dist/render/plugins/codeBlockExtract.d.ts.map +1 -0
  69. package/dist/render/plugins/{markdownExtract.d.mts → markdownExtract.d.ts} +1 -1
  70. package/dist/render/plugins/markdownExtract.d.ts.map +1 -0
  71. package/dist/render/plugins/{rawExtract.d.mts → rawExtract.d.ts} +1 -1
  72. package/dist/render/plugins/rawExtract.d.ts.map +1 -0
  73. package/dist/render/plugins/{rowSourceLocation.d.mts → rowSourceLocation.d.ts} +1 -1
  74. package/dist/render/plugins/rowSourceLocation.d.ts.map +1 -0
  75. package/dist/{serve.d.mts → serve.d.ts} +2 -2
  76. package/dist/serve.d.ts.map +1 -0
  77. package/dist/serve.mjs +15 -6
  78. package/dist/serve.mjs.map +1 -1
  79. package/dist/server/{compatibility.d.mts → compatibility.d.ts} +2 -2
  80. package/dist/server/compatibility.d.ts.map +1 -0
  81. package/dist/server/{email.d.mts → email.d.ts} +2 -2
  82. package/dist/server/email.d.ts.map +1 -0
  83. package/dist/server/{linter.d.mts → linter.d.ts} +2 -2
  84. package/dist/server/linter.d.ts.map +1 -0
  85. package/dist/server/{sfc-utils.d.mts → sfc-utils.d.ts} +1 -1
  86. package/dist/server/sfc-utils.d.ts.map +1 -0
  87. package/dist/server/ui/pages/Preview.vue +78 -19
  88. package/dist/transformers/{addAttributes.d.mts → addAttributes.d.ts} +2 -2
  89. package/dist/transformers/addAttributes.d.ts.map +1 -0
  90. package/dist/transformers/{attributeToStyle.d.mts → attributeToStyle.d.ts} +2 -2
  91. package/dist/transformers/attributeToStyle.d.ts.map +1 -0
  92. package/dist/transformers/{base.d.mts → base.d.ts} +2 -2
  93. package/dist/transformers/base.d.ts.map +1 -0
  94. package/dist/transformers/{columnWidth.d.mts → columnWidth.d.ts} +1 -1
  95. package/dist/transformers/columnWidth.d.ts.map +1 -0
  96. package/dist/transformers/{entities.d.mts → entities.d.ts} +2 -2
  97. package/dist/transformers/entities.d.ts.map +1 -0
  98. package/dist/transformers/filters/{defaults.d.mts → defaults.d.ts} +1 -1
  99. package/dist/transformers/filters/defaults.d.ts.map +1 -0
  100. package/dist/transformers/filters/{index.d.mts → index.d.ts} +2 -2
  101. package/dist/transformers/filters/index.d.ts.map +1 -0
  102. package/dist/transformers/{format.d.mts → format.d.ts} +2 -2
  103. package/dist/transformers/format.d.ts.map +1 -0
  104. package/dist/transformers/{index.d.mts → index.d.ts} +4 -3
  105. package/dist/transformers/index.d.ts.map +1 -0
  106. package/dist/transformers/index.mjs +3 -1
  107. package/dist/transformers/index.mjs.map +1 -1
  108. package/dist/transformers/{inlineCSS.d.mts → inlineCSS.d.ts} +2 -2
  109. package/dist/transformers/inlineCSS.d.ts.map +1 -0
  110. package/dist/transformers/inlineCSS.mjs +7 -1
  111. package/dist/transformers/inlineCSS.mjs.map +1 -1
  112. package/dist/transformers/{inlineLink.d.mts → inlineLink.d.ts} +1 -1
  113. package/dist/transformers/inlineLink.d.ts.map +1 -0
  114. package/dist/transformers/{minify.d.mts → minify.d.ts} +2 -2
  115. package/dist/transformers/minify.d.ts.map +1 -0
  116. package/dist/transformers/{msoWidthFromClass.d.mts → msoWidthFromClass.d.ts} +1 -1
  117. package/dist/transformers/msoWidthFromClass.d.ts.map +1 -0
  118. package/dist/transformers/{purgeCSS.d.mts → purgeCSS.d.ts} +2 -2
  119. package/dist/transformers/purgeCSS.d.ts.map +1 -0
  120. package/dist/transformers/purgeCSS.mjs +44 -2
  121. package/dist/transformers/purgeCSS.mjs.map +1 -1
  122. package/dist/transformers/{removeAttributes.d.mts → removeAttributes.d.ts} +2 -2
  123. package/dist/transformers/removeAttributes.d.ts.map +1 -0
  124. package/dist/transformers/{replaceStrings.d.mts → replaceStrings.d.ts} +2 -2
  125. package/dist/transformers/replaceStrings.d.ts.map +1 -0
  126. package/dist/transformers/{safeClassNames.d.mts → safeClassNames.d.ts} +2 -2
  127. package/dist/transformers/safeClassNames.d.ts.map +1 -0
  128. package/dist/transformers/{shorthandCSS.d.mts → shorthandCSS.d.ts} +2 -2
  129. package/dist/transformers/shorthandCSS.d.ts.map +1 -0
  130. package/dist/transformers/{sixHex.d.mts → sixHex.d.ts} +2 -2
  131. package/dist/transformers/sixHex.d.ts.map +1 -0
  132. package/dist/transformers/tailwindComponent.d.ts +16 -0
  133. package/dist/transformers/tailwindComponent.d.ts.map +1 -0
  134. package/dist/transformers/tailwindComponent.mjs +93 -0
  135. package/dist/transformers/tailwindComponent.mjs.map +1 -0
  136. package/dist/transformers/{tailwindcss.d.mts → tailwindcss.d.ts} +2 -2
  137. package/dist/transformers/tailwindcss.d.ts.map +1 -0
  138. package/dist/transformers/tailwindcss.mjs +2 -54
  139. package/dist/transformers/tailwindcss.mjs.map +1 -1
  140. package/dist/transformers/{urlQuery.d.mts → urlQuery.d.ts} +2 -2
  141. package/dist/transformers/urlQuery.d.ts.map +1 -0
  142. package/dist/types/{config.d.mts → config.d.ts} +2 -2
  143. package/dist/types/config.d.ts.map +1 -0
  144. package/dist/types/{index.d.mts → index.d.ts} +1 -1
  145. package/dist/utils/ast/index.d.ts +4 -0
  146. package/dist/utils/ast/{parser.d.mts → parser.d.ts} +1 -1
  147. package/dist/utils/ast/parser.d.ts.map +1 -0
  148. package/dist/utils/ast/{serializer.d.mts → serializer.d.ts} +1 -1
  149. package/dist/utils/ast/serializer.d.ts.map +1 -0
  150. package/dist/utils/ast/{walker.d.mts → walker.d.ts} +1 -1
  151. package/dist/utils/ast/walker.d.ts.map +1 -0
  152. package/dist/utils/compileTailwindCss.d.ts +16 -0
  153. package/dist/utils/compileTailwindCss.d.ts.map +1 -0
  154. package/dist/utils/compileTailwindCss.mjs +55 -0
  155. package/dist/utils/compileTailwindCss.mjs.map +1 -0
  156. package/dist/utils/{decodeStyleEntities.d.mts → decodeStyleEntities.d.ts} +1 -1
  157. package/dist/utils/decodeStyleEntities.d.ts.map +1 -0
  158. package/dist/utils/{detect.d.mts → detect.d.ts} +1 -1
  159. package/dist/utils/detect.d.ts.map +1 -0
  160. package/dist/utils/{url.d.mts → url.d.ts} +1 -1
  161. package/dist/utils/url.d.ts.map +1 -0
  162. package/package.json +13 -6
  163. package/dist/build.d.mts.map +0 -1
  164. package/dist/components/utils.d.mts.map +0 -1
  165. package/dist/composables/defineConfig.d.mts.map +0 -1
  166. package/dist/composables/renderContext.d.mts.map +0 -1
  167. package/dist/composables/useConfig.d.mts.map +0 -1
  168. package/dist/composables/useDoctype.d.mts.map +0 -1
  169. package/dist/composables/useEvent.d.mts.map +0 -1
  170. package/dist/composables/useFont.d.mts.map +0 -1
  171. package/dist/composables/useOutlookFallback.d.mts.map +0 -1
  172. package/dist/composables/usePlaintext.d.mts.map +0 -1
  173. package/dist/composables/usePreheader.d.mts.map +0 -1
  174. package/dist/config/defaults.d.mts.map +0 -1
  175. package/dist/config/index.d.mts.map +0 -1
  176. package/dist/events/index.d.mts.map +0 -1
  177. package/dist/index.d.mts +0 -34
  178. package/dist/plaintext.d.mts.map +0 -1
  179. package/dist/plugin.d.mts.map +0 -1
  180. package/dist/plugins/postcss/mergeMediaQueries.d.mts.map +0 -1
  181. package/dist/plugins/postcss/pruneVars.d.mts.map +0 -1
  182. package/dist/plugins/postcss/quoteFontFamilies.d.mts.map +0 -1
  183. package/dist/plugins/postcss/removeDeclarations.d.mts.map +0 -1
  184. package/dist/plugins/postcss/resolveProps.d.mts.map +0 -1
  185. package/dist/plugins/postcss/tailwindCleanup.d.mts.map +0 -1
  186. package/dist/prepare.d.mts.map +0 -1
  187. package/dist/render/createRenderer.d.mts.map +0 -1
  188. package/dist/render/index.d.mts +0 -26
  189. package/dist/render/index.d.mts.map +0 -1
  190. package/dist/render/injectFonts.d.mts.map +0 -1
  191. package/dist/render/plugins/codeBlockExtract.d.mts.map +0 -1
  192. package/dist/render/plugins/markdownExtract.d.mts.map +0 -1
  193. package/dist/render/plugins/rawExtract.d.mts.map +0 -1
  194. package/dist/render/plugins/rowSourceLocation.d.mts.map +0 -1
  195. package/dist/serve.d.mts.map +0 -1
  196. package/dist/server/compatibility.d.mts.map +0 -1
  197. package/dist/server/email.d.mts.map +0 -1
  198. package/dist/server/linter.d.mts.map +0 -1
  199. package/dist/server/sfc-utils.d.mts.map +0 -1
  200. package/dist/transformers/addAttributes.d.mts.map +0 -1
  201. package/dist/transformers/attributeToStyle.d.mts.map +0 -1
  202. package/dist/transformers/base.d.mts.map +0 -1
  203. package/dist/transformers/columnWidth.d.mts.map +0 -1
  204. package/dist/transformers/entities.d.mts.map +0 -1
  205. package/dist/transformers/filters/defaults.d.mts.map +0 -1
  206. package/dist/transformers/filters/index.d.mts.map +0 -1
  207. package/dist/transformers/format.d.mts.map +0 -1
  208. package/dist/transformers/index.d.mts.map +0 -1
  209. package/dist/transformers/inlineCSS.d.mts.map +0 -1
  210. package/dist/transformers/inlineLink.d.mts.map +0 -1
  211. package/dist/transformers/minify.d.mts.map +0 -1
  212. package/dist/transformers/msoWidthFromClass.d.mts.map +0 -1
  213. package/dist/transformers/purgeCSS.d.mts.map +0 -1
  214. package/dist/transformers/removeAttributes.d.mts.map +0 -1
  215. package/dist/transformers/replaceStrings.d.mts.map +0 -1
  216. package/dist/transformers/safeClassNames.d.mts.map +0 -1
  217. package/dist/transformers/shorthandCSS.d.mts.map +0 -1
  218. package/dist/transformers/sixHex.d.mts.map +0 -1
  219. package/dist/transformers/tailwindcss.d.mts.map +0 -1
  220. package/dist/transformers/urlQuery.d.mts.map +0 -1
  221. package/dist/types/config.d.mts.map +0 -1
  222. package/dist/utils/ast/index.d.mts +0 -4
  223. package/dist/utils/ast/parser.d.mts.map +0 -1
  224. package/dist/utils/ast/serializer.d.mts.map +0 -1
  225. package/dist/utils/ast/walker.d.mts.map +0 -1
  226. package/dist/utils/decodeStyleEntities.d.mts.map +0 -1
  227. package/dist/utils/detect.d.mts.map +0 -1
  228. package/dist/utils/url.d.mts.map +0 -1
@@ -56,6 +56,7 @@ const copied = ref(false)
56
56
  const iframeEl = ref<HTMLIFrameElement>()
57
57
  const compiledSourceEl = ref<HTMLElement>()
58
58
  const vueSourceEl = ref<HTMLElement>()
59
+ const plaintextEl = ref<HTMLElement>()
59
60
  const containerEl = ref<HTMLElement>()
60
61
  const wrapperEl = ref<HTMLElement>()
61
62
 
@@ -282,19 +283,52 @@ async function fetchTemplate() {
282
283
  }
283
284
  }
284
285
 
286
+ const sourceLoading = ref(false)
287
+ const vueSourceLoading = ref(false)
288
+ const plaintextLoading = ref(false)
289
+
285
290
  async function fetchSource() {
286
- const res = await fetch(`/__maizzle/source/${route.params.template}`)
287
- sourceHtml.value = await res.text()
291
+ if (sourceLoading.value) return
292
+ sourceLoading.value = true
293
+ try {
294
+ const res = await fetch(`/__maizzle/source/${route.params.template}`)
295
+ sourceHtml.value = await res.text()
296
+ } finally {
297
+ sourceLoading.value = false
298
+ }
288
299
  }
289
300
 
290
301
  async function fetchVueSource() {
291
- const res = await fetch(`/__maizzle/vue-source/${route.params.template}`)
292
- vueSourceHtml.value = await res.text()
302
+ if (vueSourceLoading.value) return
303
+ vueSourceLoading.value = true
304
+ try {
305
+ const res = await fetch(`/__maizzle/vue-source/${route.params.template}`)
306
+ vueSourceHtml.value = await res.text()
307
+ } finally {
308
+ vueSourceLoading.value = false
309
+ }
293
310
  }
294
311
 
295
312
  async function fetchPlaintext() {
296
- const res = await fetch(`/__maizzle/plaintext/${route.params.template}`)
297
- plaintextContent.value = await res.text()
313
+ if (plaintextLoading.value) return
314
+ plaintextLoading.value = true
315
+ try {
316
+ const res = await fetch(`/__maizzle/plaintext/${route.params.template}`)
317
+ plaintextContent.value = await res.text()
318
+ } finally {
319
+ plaintextLoading.value = false
320
+ }
321
+ }
322
+
323
+ /**
324
+ * Warm the three source views in the background so switching from the
325
+ * preview is instant. Single-flight guards above prevent duplication
326
+ * with any in-flight fetch from a view-switch watcher.
327
+ */
328
+ function prefetchSources() {
329
+ if (!sourceHtml.value) fetchSource()
330
+ if (!vueSourceHtml.value) fetchVueSource()
331
+ if (!plaintextContent.value) fetchPlaintext()
298
332
  }
299
333
 
300
334
  async function fetchStats() {
@@ -368,7 +402,7 @@ watch(() => route.params.template, () => {
368
402
  stats.value = null
369
403
  emailResult.value = null
370
404
  sourceView.value = 'compiled'
371
- fetchTemplate()
405
+ fetchTemplate().then(prefetchSources)
372
406
  fetchCompatibility()
373
407
  fetchStats()
374
408
  fetchEmailConfig()
@@ -396,23 +430,47 @@ watch(sourceView, (view) => {
396
430
  if (view === 'plaintext' && !plaintextContent.value) fetchPlaintext()
397
431
  })
398
432
 
433
+ /**
434
+ * Preserve scrollTop across in-place content updates (HMR refetch).
435
+ * Vue's default `flush: 'pre'` runs the watcher BEFORE the DOM is
436
+ * updated — so we read the current scrollTop, then restore it on the
437
+ * next tick after the new content has rendered. Skip the case where
438
+ * the value transitions from empty (first paint / route change) so a
439
+ * fresh template doesn't snap to a stale offset.
440
+ */
441
+ function viewportFor(el: HTMLElement | undefined): HTMLElement | null {
442
+ return (el?.closest('[data-slot="scroll-area-viewport"]') as HTMLElement | null) ?? null
443
+ }
444
+
445
+ function preserveScroll(getEl: () => HTMLElement | undefined) {
446
+ return async (newVal: string, oldVal: string) => {
447
+ if (!oldVal || !newVal) return
448
+ const vp = viewportFor(getEl())
449
+ if (!vp) return
450
+ const top = vp.scrollTop
451
+ await nextTick()
452
+ vp.scrollTop = top
453
+ }
454
+ }
455
+
456
+ watch(sourceHtml, preserveScroll(() => compiledSourceEl.value))
457
+ watch(vueSourceHtml, preserveScroll(() => vueSourceEl.value))
458
+ watch(plaintextContent, preserveScroll(() => plaintextEl.value))
459
+
399
460
  if ((import.meta as any).hot) {
400
461
  ;(import.meta as any).hot.on('maizzle:template-updated', () => {
401
- fetchTemplate()
402
462
  fetchCompatibility()
403
463
  fetchStats()
404
464
 
405
- // Always clear all source views so they re-fetch when switched to
406
- sourceHtml.value = ''
407
- vueSourceHtml.value = ''
408
- plaintextContent.value = ''
409
-
410
- // Re-fetch the active source view immediately if currently visible
411
- if (viewMode.value === 'source') {
412
- if (sourceView.value === 'compiled') fetchSource()
413
- if (sourceView.value === 'vue') fetchVueSource()
414
- if (sourceView.value === 'plaintext') fetchPlaintext()
415
- }
465
+ // Refetch in place don't clear the previous values first. v-html
466
+ // replaces the highlighted block atomically when the new content
467
+ // arrives, and the ScrollArea viewport keeps its scrollTop as long
468
+ // as the new content's height is similar. Plaintext interpolation
469
+ // updates a single text node, so scroll is naturally preserved.
470
+ fetchTemplate()
471
+ fetchSource()
472
+ fetchVueSource()
473
+ fetchPlaintext()
416
474
  })
417
475
 
418
476
  // Keep the UI in sync with live config edits. Payload is the same shape
@@ -747,6 +805,7 @@ const stripeBg = {
747
805
  </ScrollArea>
748
806
  <ScrollArea v-show="sourceView === 'plaintext'" class="h-full [&_[data-slot=scroll-area-viewport]>div]:flex [&_[data-slot=scroll-area-viewport]>div]:flex-col [&_[data-slot=scroll-area-viewport]>div]:min-h-full">
749
807
  <pre
808
+ ref="plaintextEl"
750
809
  class="p-6 pt-14 text-sm leading-6 flex-1 text-gray-300 bg-[#27212e] dark:bg-gray-950 whitespace-pre-wrap break-words"
751
810
  >{{ plaintextContent }}</pre>
752
811
  </ScrollArea>
@@ -1,4 +1,4 @@
1
- import { AttributesConfig } from "../types/config.mjs";
1
+ import { AttributesConfig } from "../types/config.js";
2
2
  import { ChildNode } from "domhandler";
3
3
 
4
4
  //#region src/transformers/addAttributes.d.ts
@@ -29,4 +29,4 @@ import { ChildNode } from "domhandler";
29
29
  declare function addAttributes(dom: ChildNode[], config?: AttributesConfig): ChildNode[];
30
30
  //#endregion
31
31
  export { addAttributes };
32
- //# sourceMappingURL=addAttributes.d.mts.map
32
+ //# sourceMappingURL=addAttributes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"addAttributes.d.ts","names":[],"sources":["../../src/transformers/addAttributes.ts"],"mappings":";;;;;;AA2CA;;;;;;;;;;;;;;;;;;;;;;iBAAgB,aAAA,CAAc,GAAA,EAAK,SAAA,IAAa,MAAA,GAAQ,gBAAA,GAAwB,SAAA"}
@@ -1,4 +1,4 @@
1
- import { CssConfig } from "../types/config.mjs";
1
+ import { CssConfig } from "../types/config.js";
2
2
  import { ChildNode } from "domhandler";
3
3
 
4
4
  //#region src/transformers/attributeToStyle.d.ts
@@ -22,4 +22,4 @@ import { ChildNode } from "domhandler";
22
22
  declare function attributeToStyle(dom: ChildNode[], config?: CssConfig): ChildNode[];
23
23
  //#endregion
24
24
  export { attributeToStyle };
25
- //# sourceMappingURL=attributeToStyle.d.mts.map
25
+ //# sourceMappingURL=attributeToStyle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attributeToStyle.d.ts","names":[],"sources":["../../src/transformers/attributeToStyle.ts"],"mappings":";;;;;;AA0BA;;;;;;;;;;;;;;;iBAAgB,gBAAA,CAAiB,GAAA,EAAK,SAAA,IAAa,MAAA,GAAQ,SAAA,GAAiB,SAAA"}
@@ -1,8 +1,8 @@
1
- import { UrlConfig } from "../types/config.mjs";
1
+ import { UrlConfig } from "../types/config.js";
2
2
  import { ChildNode } from "domhandler";
3
3
 
4
4
  //#region src/transformers/base.d.ts
5
5
  declare function base(dom: ChildNode[], config?: UrlConfig): ChildNode[];
6
6
  //#endregion
7
7
  export { base };
8
- //# sourceMappingURL=base.d.mts.map
8
+ //# sourceMappingURL=base.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.d.ts","names":[],"sources":["../../src/transformers/base.ts"],"mappings":";;;;iBAwHgB,IAAA,CAAK,GAAA,EAAK,SAAA,IAAa,MAAA,GAAQ,SAAA,GAAiB,SAAA"}
@@ -28,4 +28,4 @@ import { ChildNode } from "domhandler";
28
28
  declare function columnWidth(dom: ChildNode[]): ChildNode[];
29
29
  //#endregion
30
30
  export { columnWidth };
31
- //# sourceMappingURL=columnWidth.d.mts.map
31
+ //# sourceMappingURL=columnWidth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"columnWidth.d.ts","names":[],"sources":["../../src/transformers/columnWidth.ts"],"mappings":";;;;;AAwTA;;;;;;;;;;;;;;;;;;;;;;iBAAgB,WAAA,CAAY,GAAA,EAAK,SAAA,KAAc,SAAA"}
@@ -1,8 +1,8 @@
1
- import { EntitiesConfig } from "../types/config.mjs";
1
+ import { EntitiesConfig } from "../types/config.js";
2
2
  import { ChildNode } from "domhandler";
3
3
 
4
4
  //#region src/transformers/entities.d.ts
5
5
  declare function entities(dom: ChildNode[], config?: EntitiesConfig): ChildNode[];
6
6
  //#endregion
7
7
  export { entities };
8
- //# sourceMappingURL=entities.d.mts.map
8
+ //# sourceMappingURL=entities.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entities.d.ts","names":[],"sources":["../../src/transformers/entities.ts"],"mappings":";;;;iBA8BgB,QAAA,CAAS,GAAA,EAAK,SAAA,IAAa,MAAA,GAAQ,cAAA,GAAwB,SAAA"}
@@ -3,4 +3,4 @@ type FilterFunction = (str: string, value: string) => string;
3
3
  declare const defaults: Record<string, FilterFunction>;
4
4
  //#endregion
5
5
  export { FilterFunction, defaults };
6
- //# sourceMappingURL=defaults.d.mts.map
6
+ //# sourceMappingURL=defaults.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defaults.d.ts","names":[],"sources":["../../../src/transformers/filters/defaults.ts"],"mappings":";KAAY,cAAA,IAAkB,GAAA,UAAa,KAAA;AAAA,cAgB9B,QAAA,EAAU,MAAA,SAAe,cAAA"}
@@ -1,4 +1,4 @@
1
- import { FilterFunction } from "./defaults.mjs";
1
+ import { FilterFunction } from "./defaults.js";
2
2
  import { ChildNode } from "domhandler";
3
3
 
4
4
  //#region src/transformers/filters/index.d.ts
@@ -19,4 +19,4 @@ type FiltersConfig = false | Record<string, (str: string, value: string) => stri
19
19
  declare function filters(dom: ChildNode[], config?: FiltersConfig): ChildNode[];
20
20
  //#endregion
21
21
  export { type FilterFunction, FiltersConfig, filters };
22
- //# sourceMappingURL=index.d.mts.map
22
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/transformers/filters/index.ts"],"mappings":";;;;KAMY,aAAA,WAAwB,MAAA,UAAgB,GAAA,UAAa,KAAA;;AAAjE;;;;;;;;;AA4BA;;;iBAAgB,OAAA,CAAQ,GAAA,EAAK,SAAA,IAAa,MAAA,GAAQ,aAAA,GAAqB,SAAA"}
@@ -1,4 +1,4 @@
1
- import { MaizzleConfig } from "../types/config.mjs";
1
+ import { MaizzleConfig } from "../types/config.js";
2
2
 
3
3
  //#region src/transformers/format.d.ts
4
4
  /**
@@ -12,4 +12,4 @@ import { MaizzleConfig } from "../types/config.mjs";
12
12
  declare function format(html: string, config?: MaizzleConfig): Promise<string>;
13
13
  //#endregion
14
14
  export { format };
15
- //# sourceMappingURL=format.d.mts.map
15
+ //# sourceMappingURL=format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.d.ts","names":[],"sources":["../../src/transformers/format.ts"],"mappings":";;;;;AAmBA;;;;;;iBAAsB,MAAA,CAAO,IAAA,UAAc,MAAA,GAAQ,aAAA,GAAqB,OAAA"}
@@ -1,4 +1,5 @@
1
- import { MaizzleConfig } from "../types/config.mjs";
1
+ import { MaizzleConfig } from "../types/config.js";
2
+ import { TailwindBlock } from "../composables/renderContext.js";
2
3
 
3
4
  //#region src/transformers/index.d.ts
4
5
  /**
@@ -31,7 +32,7 @@ import { MaizzleConfig } from "../types/config.mjs";
31
32
  * 15. Prettify
32
33
  * 16. Minify
33
34
  */
34
- declare function runTransformers(html: string, config: MaizzleConfig, filePath?: string, doctype?: string): Promise<string>;
35
+ declare function runTransformers(html: string, config: MaizzleConfig, filePath?: string, doctype?: string, tailwindBlocks?: TailwindBlock[]): Promise<string>;
35
36
  //#endregion
36
37
  export { runTransformers };
37
- //# sourceMappingURL=index.d.mts.map
38
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/transformers/index.ts"],"mappings":";;;;;;AAsDA;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAAsB,eAAA,CACpB,IAAA,UACA,MAAA,EAAQ,aAAA,EACR,QAAA,WACA,OAAA,WACA,cAAA,GAAiB,aAAA,KAChB,OAAA"}
@@ -2,6 +2,7 @@ import { parse } from "../utils/ast/parser.mjs";
2
2
  import { serialize } from "../utils/ast/serializer.mjs";
3
3
  import "../utils/ast/index.mjs";
4
4
  import { inlineLink } from "./inlineLink.mjs";
5
+ import { tailwindComponent } from "./tailwindComponent.mjs";
5
6
  import { tailwindcss } from "./tailwindcss.mjs";
6
7
  import { safeClassNames } from "./safeClassNames.mjs";
7
8
  import { attributeToStyle } from "./attributeToStyle.mjs";
@@ -52,10 +53,11 @@ import { minify } from "./minify.mjs";
52
53
  * 15. Prettify
53
54
  * 16. Minify
54
55
  */
55
- async function runTransformers(html, config, filePath, doctype) {
56
+ async function runTransformers(html, config, filePath, doctype, tailwindBlocks) {
56
57
  html = html.replaceAll("<!--[-->", "").replaceAll("<!--]-->", "").replaceAll("<!--teleport start anchor-->", "").replaceAll("<!--teleport anchor-->", "").replaceAll("<!--teleport start-->", "").replaceAll("<!--teleport end-->", "");
57
58
  let dom = parse(html);
58
59
  dom = await inlineLink(dom, filePath);
60
+ if (tailwindBlocks?.length) dom = await tailwindComponent(dom, tailwindBlocks, config, filePath);
59
61
  dom = await tailwindcss(dom, config, filePath);
60
62
  dom = safeClassNames(dom, config.css);
61
63
  dom = attributeToStyle(dom, config.css);
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../src/transformers/index.ts"],"sourcesContent":["import { parse, serialize } from '../utils/ast/index.ts'\nimport { inlineLink } from './inlineLink.ts'\nimport { tailwindcss } from './tailwindcss.ts'\nimport { safeClassNames } from './safeClassNames.ts'\nimport { attributeToStyle } from './attributeToStyle.ts'\nimport { inlineCSS } from './inlineCSS.ts'\nimport { msoWidthFromClass } from './msoWidthFromClass.ts'\nimport { columnWidth } from './columnWidth.ts'\nimport { removeAttributes } from './removeAttributes.ts'\nimport { shorthandCSS } from './shorthandCSS.ts'\nimport { sixHex } from './sixHex.ts'\nimport { addAttributes } from './addAttributes.ts'\nimport { filters } from './filters/index.ts'\nimport { base } from './base.ts'\nimport { entities } from './entities.ts'\nimport { urlQuery } from './urlQuery.ts'\nimport { purgeCSS } from './purgeCSS.ts'\nimport { replaceStrings } from './replaceStrings.ts'\nimport { format } from './format.ts'\nimport { minify } from './minify.ts'\nimport type { MaizzleConfig } from '../types/config.ts'\n\n/**\n * Run all Maizzle transformers on the rendered HTML.\n *\n * The HTML is parsed into a DOM once at the start and passed through all\n * DOM-based transformers as a shared `ChildNode[]`. After all DOM transformers\n * complete, the DOM is serialized back to a string exactly once.\n *\n * String-only transformers (those that rely on external tools that require a\n * raw HTML string) then run on the serialized output.\n *\n * Transformers run in a specific order:\n * 0. Inline link stylesheets — replace `<link rel=\"stylesheet\">` with `<style>` tags\n * 1. Tailwind CSS — compile CSS, lower syntax, optimize (cleanup + merge media queries)\n * 2. Safe class names\n * 3. Attribute to style\n * 4. CSS inliner\n * 5. Remove attributes\n * 6. Shorthand CSS\n * 7. Six-digit HEX\n * 8. Add attributes\n * 9. Filters\n * 10. Base URL\n * 11. URL query\n * 12. Purge CSS (serializes/parses internally around email-comb)\n * 13. Entities\n * + Vue-generated comments stripped here (on serialized string)\n * 14. Replace strings\n * 15. Prettify\n * 16. Minify\n */\nexport async function runTransformers(\n html: string,\n config: MaizzleConfig,\n filePath?: string,\n doctype?: string,\n): Promise<string> {\n // Strip Vue SSR fragment markers before parsing. They contain `-->`, which\n // prematurely terminates conditional comments like `<!--[if mso]>...<![endif]-->`\n // when htmlparser2 reads them, swallowing real markup into comment data.\n html = html\n .replaceAll('<!--[-->', '')\n .replaceAll('<!--]-->', '')\n .replaceAll('<!--teleport start anchor-->', '')\n .replaceAll('<!--teleport anchor-->', '')\n .replaceAll('<!--teleport start-->', '')\n .replaceAll('<!--teleport end-->', '')\n\n // Parse once — all DOM transformers share this array\n let dom = parse(html)\n\n // 0. Inline <link> stylesheets\n dom = await inlineLink(dom, filePath)\n\n // 1. Tailwind CSS — always runs first\n dom = await tailwindcss(dom, config, filePath)\n\n // 2. Safe class names\n dom = safeClassNames(dom, config.css)\n\n // 3. Attribute to style\n dom = attributeToStyle(dom, config.css)\n\n // 4. CSS inliner (serializes/parses internally around juice)\n dom = inlineCSS(dom, config.css)\n\n // 4.5. Resolve MSO width placeholders from inlined max-width/width\n dom = msoWidthFromClass(dom)\n\n // 4.6. Resolve Column min-width placeholders from nearest sized ancestor\n dom = columnWidth(dom)\n\n // 5. Remove attributes\n dom = removeAttributes(dom, config.html?.attributes)\n\n // 6. Shorthand CSS\n dom = shorthandCSS(dom, config.css)\n\n // 7. Six-digit HEX\n dom = sixHex(dom, config.css)\n\n // 8. Add attributes\n dom = addAttributes(dom, config.html?.attributes)\n\n // 9. Filters\n dom = filters(dom, config.filters)\n\n // 10. Base URL (serializes/parses internally for VML/MSO regex passes)\n dom = base(dom, config.url)\n\n // 11. URL query\n dom = urlQuery(dom, config.url)\n\n // 12. Purge CSS (serializes/parses internally around email-comb)\n dom = purgeCSS(dom, config.css)\n\n // 13. Entities\n dom = entities(dom, config.html?.decodeEntities)\n\n // Serialize once — remaining transformers operate on the HTML string\n const isXhtml = doctype ? /xhtml/i.test(doctype) : false\n let result = serialize(dom, { selfClosingTags: isXhtml })\n\n // 14. Replace strings\n result = replaceStrings(result, config)\n\n // 15. Format\n result = await format(result, config)\n\n // 16. Minify\n result = minify(result, config)\n\n // Strip self-closing slashes for HTML5 doctypes\n if (!isXhtml) {\n result = result.replace(/ \\/>/g, '>')\n }\n\n return result\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoDA,eAAsB,gBACpB,MACA,QACA,UACA,SACiB;AAIjB,QAAO,KACJ,WAAW,YAAY,GAAG,CAC1B,WAAW,YAAY,GAAG,CAC1B,WAAW,gCAAgC,GAAG,CAC9C,WAAW,0BAA0B,GAAG,CACxC,WAAW,yBAAyB,GAAG,CACvC,WAAW,uBAAuB,GAAG;CAGxC,IAAI,MAAM,MAAM,KAAK;AAGrB,OAAM,MAAM,WAAW,KAAK,SAAS;AAGrC,OAAM,MAAM,YAAY,KAAK,QAAQ,SAAS;AAG9C,OAAM,eAAe,KAAK,OAAO,IAAI;AAGrC,OAAM,iBAAiB,KAAK,OAAO,IAAI;AAGvC,OAAM,UAAU,KAAK,OAAO,IAAI;AAGhC,OAAM,kBAAkB,IAAI;AAG5B,OAAM,YAAY,IAAI;AAGtB,OAAM,iBAAiB,KAAK,OAAO,MAAM,WAAW;AAGpD,OAAM,aAAa,KAAK,OAAO,IAAI;AAGnC,OAAM,OAAO,KAAK,OAAO,IAAI;AAG7B,OAAM,cAAc,KAAK,OAAO,MAAM,WAAW;AAGjD,OAAM,QAAQ,KAAK,OAAO,QAAQ;AAGlC,OAAM,KAAK,KAAK,OAAO,IAAI;AAG3B,OAAM,SAAS,KAAK,OAAO,IAAI;AAG/B,OAAM,SAAS,KAAK,OAAO,IAAI;AAG/B,OAAM,SAAS,KAAK,OAAO,MAAM,eAAe;CAGhD,MAAM,UAAU,UAAU,SAAS,KAAK,QAAQ,GAAG;CACnD,IAAI,SAAS,UAAU,KAAK,EAAE,iBAAiB,SAAS,CAAC;AAGzD,UAAS,eAAe,QAAQ,OAAO;AAGvC,UAAS,MAAM,OAAO,QAAQ,OAAO;AAGrC,UAAS,OAAO,QAAQ,OAAO;AAG/B,KAAI,CAAC,QACH,UAAS,OAAO,QAAQ,SAAS,IAAI;AAGvC,QAAO"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/transformers/index.ts"],"sourcesContent":["import { parse, serialize } from '../utils/ast/index.ts'\nimport { inlineLink } from './inlineLink.ts'\nimport { tailwindComponent } from './tailwindComponent.ts'\nimport { tailwindcss } from './tailwindcss.ts'\nimport { safeClassNames } from './safeClassNames.ts'\nimport { attributeToStyle } from './attributeToStyle.ts'\nimport { inlineCSS } from './inlineCSS.ts'\nimport { msoWidthFromClass } from './msoWidthFromClass.ts'\nimport { columnWidth } from './columnWidth.ts'\nimport { removeAttributes } from './removeAttributes.ts'\nimport { shorthandCSS } from './shorthandCSS.ts'\nimport { sixHex } from './sixHex.ts'\nimport { addAttributes } from './addAttributes.ts'\nimport { filters } from './filters/index.ts'\nimport { base } from './base.ts'\nimport { entities } from './entities.ts'\nimport { urlQuery } from './urlQuery.ts'\nimport { purgeCSS } from './purgeCSS.ts'\nimport { replaceStrings } from './replaceStrings.ts'\nimport { format } from './format.ts'\nimport { minify } from './minify.ts'\nimport type { MaizzleConfig } from '../types/config.ts'\nimport type { TailwindBlock } from '../composables/renderContext.ts'\n\n/**\n * Run all Maizzle transformers on the rendered HTML.\n *\n * The HTML is parsed into a DOM once at the start and passed through all\n * DOM-based transformers as a shared `ChildNode[]`. After all DOM transformers\n * complete, the DOM is serialized back to a string exactly once.\n *\n * String-only transformers (those that rely on external tools that require a\n * raw HTML string) then run on the serialized output.\n *\n * Transformers run in a specific order:\n * 0. Inline link stylesheets — replace `<link rel=\"stylesheet\">` with `<style>` tags\n * 1. Tailwind CSS — compile CSS, lower syntax, optimize (cleanup + merge media queries)\n * 2. Safe class names\n * 3. Attribute to style\n * 4. CSS inliner\n * 5. Remove attributes\n * 6. Shorthand CSS\n * 7. Six-digit HEX\n * 8. Add attributes\n * 9. Filters\n * 10. Base URL\n * 11. URL query\n * 12. Purge CSS (serializes/parses internally around email-comb)\n * 13. Entities\n * + Vue-generated comments stripped here (on serialized string)\n * 14. Replace strings\n * 15. Prettify\n * 16. Minify\n */\nexport async function runTransformers(\n html: string,\n config: MaizzleConfig,\n filePath?: string,\n doctype?: string,\n tailwindBlocks?: TailwindBlock[],\n): Promise<string> {\n // Strip Vue SSR fragment markers before parsing. They contain `-->`, which\n // prematurely terminates conditional comments like `<!--[if mso]>...<![endif]-->`\n // when htmlparser2 reads them, swallowing real markup into comment data.\n html = html\n .replaceAll('<!--[-->', '')\n .replaceAll('<!--]-->', '')\n .replaceAll('<!--teleport start anchor-->', '')\n .replaceAll('<!--teleport anchor-->', '')\n .replaceAll('<!--teleport start-->', '')\n .replaceAll('<!--teleport end-->', '')\n\n // Parse once — all DOM transformers share this array\n let dom = parse(html)\n\n // 0. Inline <link> stylesheets\n dom = await inlineLink(dom, filePath)\n\n // 0.5. <Tailwind> component — compile per-block scoped CSS, inject into <head>\n if (tailwindBlocks?.length) {\n dom = await tailwindComponent(dom, tailwindBlocks, config, filePath)\n }\n\n // 1. Tailwind CSS — always runs first\n dom = await tailwindcss(dom, config, filePath)\n\n // 2. Safe class names\n dom = safeClassNames(dom, config.css)\n\n // 3. Attribute to style\n dom = attributeToStyle(dom, config.css)\n\n // 4. CSS inliner (serializes/parses internally around juice)\n dom = inlineCSS(dom, config.css)\n\n // 4.5. Resolve MSO width placeholders from inlined max-width/width\n dom = msoWidthFromClass(dom)\n\n // 4.6. Resolve Column min-width placeholders from nearest sized ancestor\n dom = columnWidth(dom)\n\n // 5. Remove attributes\n dom = removeAttributes(dom, config.html?.attributes)\n\n // 6. Shorthand CSS\n dom = shorthandCSS(dom, config.css)\n\n // 7. Six-digit HEX\n dom = sixHex(dom, config.css)\n\n // 8. Add attributes\n dom = addAttributes(dom, config.html?.attributes)\n\n // 9. Filters\n dom = filters(dom, config.filters)\n\n // 10. Base URL (serializes/parses internally for VML/MSO regex passes)\n dom = base(dom, config.url)\n\n // 11. URL query\n dom = urlQuery(dom, config.url)\n\n // 12. Purge CSS (serializes/parses internally around email-comb)\n dom = purgeCSS(dom, config.css)\n\n // 13. Entities\n dom = entities(dom, config.html?.decodeEntities)\n\n // Serialize once — remaining transformers operate on the HTML string\n const isXhtml = doctype ? /xhtml/i.test(doctype) : false\n let result = serialize(dom, { selfClosingTags: isXhtml })\n\n // 14. Replace strings\n result = replaceStrings(result, config)\n\n // 15. Format\n result = await format(result, config)\n\n // 16. Minify\n result = minify(result, config)\n\n // Strip self-closing slashes for HTML5 doctypes\n if (!isXhtml) {\n result = result.replace(/ \\/>/g, '>')\n }\n\n return result\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsDA,eAAsB,gBACpB,MACA,QACA,UACA,SACA,gBACiB;AAIjB,QAAO,KACJ,WAAW,YAAY,GAAG,CAC1B,WAAW,YAAY,GAAG,CAC1B,WAAW,gCAAgC,GAAG,CAC9C,WAAW,0BAA0B,GAAG,CACxC,WAAW,yBAAyB,GAAG,CACvC,WAAW,uBAAuB,GAAG;CAGxC,IAAI,MAAM,MAAM,KAAK;AAGrB,OAAM,MAAM,WAAW,KAAK,SAAS;AAGrC,KAAI,gBAAgB,OAClB,OAAM,MAAM,kBAAkB,KAAK,gBAAgB,QAAQ,SAAS;AAItE,OAAM,MAAM,YAAY,KAAK,QAAQ,SAAS;AAG9C,OAAM,eAAe,KAAK,OAAO,IAAI;AAGrC,OAAM,iBAAiB,KAAK,OAAO,IAAI;AAGvC,OAAM,UAAU,KAAK,OAAO,IAAI;AAGhC,OAAM,kBAAkB,IAAI;AAG5B,OAAM,YAAY,IAAI;AAGtB,OAAM,iBAAiB,KAAK,OAAO,MAAM,WAAW;AAGpD,OAAM,aAAa,KAAK,OAAO,IAAI;AAGnC,OAAM,OAAO,KAAK,OAAO,IAAI;AAG7B,OAAM,cAAc,KAAK,OAAO,MAAM,WAAW;AAGjD,OAAM,QAAQ,KAAK,OAAO,QAAQ;AAGlC,OAAM,KAAK,KAAK,OAAO,IAAI;AAG3B,OAAM,SAAS,KAAK,OAAO,IAAI;AAG/B,OAAM,SAAS,KAAK,OAAO,IAAI;AAG/B,OAAM,SAAS,KAAK,OAAO,MAAM,eAAe;CAGhD,MAAM,UAAU,UAAU,SAAS,KAAK,QAAQ,GAAG;CACnD,IAAI,SAAS,UAAU,KAAK,EAAE,iBAAiB,SAAS,CAAC;AAGzD,UAAS,eAAe,QAAQ,OAAO;AAGvC,UAAS,MAAM,OAAO,QAAQ,OAAO;AAGrC,UAAS,OAAO,QAAQ,OAAO;AAG/B,KAAI,CAAC,QACH,UAAS,OAAO,QAAQ,SAAS,IAAI;AAGvC,QAAO"}
@@ -1,4 +1,4 @@
1
- import { CssConfig } from "../types/config.mjs";
1
+ import { CssConfig } from "../types/config.js";
2
2
  import { ChildNode } from "domhandler";
3
3
 
4
4
  //#region src/transformers/inlineCSS.d.ts
@@ -14,4 +14,4 @@ import { ChildNode } from "domhandler";
14
14
  declare function inlineCSS(dom: ChildNode[], config?: CssConfig): ChildNode[];
15
15
  //#endregion
16
16
  export { inlineCSS };
17
- //# sourceMappingURL=inlineCSS.d.mts.map
17
+ //# sourceMappingURL=inlineCSS.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inlineCSS.d.ts","names":[],"sources":["../../src/transformers/inlineCSS.ts"],"mappings":";;;;;;AAeA;;;;;;;iBAAgB,SAAA,CAAU,GAAA,EAAK,SAAA,IAAa,MAAA,GAAQ,SAAA,GAAiB,SAAA"}
@@ -59,11 +59,17 @@ function inlineCSS(dom, config = {}) {
59
59
  el.attribs.style = style;
60
60
  }
61
61
  });
62
+ /**
63
+ * Restore `embed` from our marker so the purge step can detect
64
+ * these tags and skip them. Drop `data-embed` (juice's name)
65
+ * since it's redundant once `embed` is back, and let purge
66
+ * strip `embed` itself at the end of its run.
67
+ */
62
68
  walk(result, (node) => {
63
69
  const el = node;
64
70
  if (el.name === "style" && el.attribs && "data-maizzle-embed" in el.attribs) {
65
- el.attribs["data-embed"] = "";
66
71
  el.attribs.embed = "";
72
+ delete el.attribs["data-embed"];
67
73
  delete el.attribs["data-maizzle-embed"];
68
74
  }
69
75
  });
@@ -1 +1 @@
1
- {"version":3,"file":"inlineCSS.mjs","names":[],"sources":["../../src/transformers/inlineCSS.ts"],"sourcesContent":["import juice from 'juice'\nimport { walk, parse, serialize } from '../utils/ast/index.ts'\nimport type { ChildNode, Element } from 'domhandler'\nimport type { Options as JuiceOptions } from 'juice'\nimport type { CssConfig } from '../types/config.ts'\n\n/**\n * Inline CSS transformer.\n *\n * Inlines CSS from `<style>` tags into inline style attributes on HTML elements.\n * This is important for email client compatibility (especially Outlook on Windows).\n *\n * Enabled when `css.inline` is set to `true` or an object with options.\n * All Juice options are supported and passed through directly.\n */\nexport function inlineCSS(dom: ChildNode[], config: CssConfig = {}): ChildNode[] {\n const inline = config.inline\n\n // Disabled when inline is falsy or not an object/truthy\n if (!inline) {\n return dom\n }\n\n // Build options from config\n const options = typeof inline === 'object' ? inline : {}\n\n // Separate Maizzle-specific options from Juice options\n const {\n preferUnitlessValues = true,\n safelist,\n customCSS = '',\n styleToAttribute,\n excludedProperties,\n widthElements,\n heightElements,\n codeBlocks,\n ...juicePassthrough\n } = options\n\n // Configure Juice static properties\n juice.styleToAttribute = styleToAttribute ?? {}\n juice.excludedProperties = ['--tw-shadow', ...(excludedProperties ?? [])]\n juice.widthElements = (widthElements ?? ['img', 'video']).map(i => i.toUpperCase()) as unknown as HTMLElement[]\n juice.heightElements = (heightElements ?? ['img', 'video']).map(i => i.toUpperCase()) as unknown as HTMLElement[]\n\n // Add custom code blocks\n if (codeBlocks && typeof codeBlocks === 'object') {\n Object.entries(codeBlocks).forEach(([key, value]) => {\n if (value.start && value.end) {\n juice.codeBlocks[key] = value\n }\n })\n }\n\n // Handle style tags with embed attributes.\n // We add a marker attribute that persists through the pipeline,\n // then restore data-embed from it after Juice runs.\n walk(dom, (node) => {\n const el = node as Element\n if (el.name === 'style' && el.attribs) {\n // Sync data-embed ↔ embed. Use `in` so presence-only attrs\n // (<style embed> → attribs.embed === '') still count.\n if ('embed' in el.attribs && !('data-embed' in el.attribs)) {\n el.attribs['data-embed'] = ''\n }\n if ('data-embed' in el.attribs && !('embed' in el.attribs)) {\n el.attribs.embed = ''\n }\n\n // Add marker that persists through the pipeline\n if ('data-embed' in el.attribs) {\n el.attribs['data-maizzle-embed'] = ''\n }\n }\n })\n\n // Serialize for juice (juice requires a string)\n const serialized = serialize(dom)\n\n let inlinedHtml: string\n\n try {\n const juiceOptions: JuiceOptions = {\n removeStyleTags: juicePassthrough.removeStyleTags ?? false,\n removeInlinedSelectors: juicePassthrough.removeInlinedSelectors ?? true,\n applyWidthAttributes: juicePassthrough.applyWidthAttributes ?? true,\n applyHeightAttributes: juicePassthrough.applyHeightAttributes ?? true,\n preservedSelectors: safelist ?? [],\n ...customCSS ? { extraCss: customCSS } : {},\n inlineDuplicateProperties: juicePassthrough.inlineDuplicateProperties ?? true,\n ...juicePassthrough,\n }\n\n inlinedHtml = juice(serialized, juiceOptions)\n } catch {\n // If Juice fails, return the dom unchanged\n return dom\n }\n\n // Post-process for preferUnitlessValues\n const result = parse(inlinedHtml)\n\n walk(result, (node) => {\n const el = node as Element\n if (el.attribs?.style) {\n // Normalize style formatting: ensure spaces after : and ;\n let style = el.attribs.style\n .replace(/:\\s*/g, ': ')\n .replace(/;\\s*/g, '; ')\n .trimEnd()\n\n // Ensure trailing semicolon\n if (!style.endsWith(';')) {\n style += ';'\n }\n\n if (preferUnitlessValues) {\n style = style.replace(\n /\\b0(px|rem|em|%|vh|vw|vmin|vmax|in|cm|mm|pt|pc|ex|ch)\\b/g,\n '0'\n )\n }\n\n el.attribs.style = style\n }\n })\n\n // Restore data-embed from our marker, then remove the marker.\n // The purge step will handle final data-embed/embed removal.\n walk(result, (node) => {\n const el = node as Element\n if (el.name === 'style' && el.attribs && 'data-maizzle-embed' in el.attribs) {\n el.attribs['data-embed'] = ''\n el.attribs.embed = ''\n delete el.attribs['data-maizzle-embed']\n }\n })\n\n return result\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAeA,SAAgB,UAAU,KAAkB,SAAoB,EAAE,EAAe;CAC/E,MAAM,SAAS,OAAO;AAGtB,KAAI,CAAC,OACH,QAAO;CAOT,MAAM,EACJ,uBAAuB,MACvB,UACA,YAAY,IACZ,kBACA,oBACA,eACA,gBACA,YACA,GAAG,qBAZW,OAAO,WAAW,WAAW,SAAS,EAAE;AAgBxD,OAAM,mBAAmB,oBAAoB,EAAE;AAC/C,OAAM,qBAAqB,CAAC,eAAe,GAAI,sBAAsB,EAAE,CAAE;AACzE,OAAM,iBAAiB,iBAAiB,CAAC,OAAO,QAAQ,EAAE,KAAI,MAAK,EAAE,aAAa,CAAC;AACnF,OAAM,kBAAkB,kBAAkB,CAAC,OAAO,QAAQ,EAAE,KAAI,MAAK,EAAE,aAAa,CAAC;AAGrF,KAAI,cAAc,OAAO,eAAe,SACtC,QAAO,QAAQ,WAAW,CAAC,SAAS,CAAC,KAAK,WAAW;AACnD,MAAI,MAAM,SAAS,MAAM,IACvB,OAAM,WAAW,OAAO;GAE1B;AAMJ,MAAK,MAAM,SAAS;EAClB,MAAM,KAAK;AACX,MAAI,GAAG,SAAS,WAAW,GAAG,SAAS;AAGrC,OAAI,WAAW,GAAG,WAAW,EAAE,gBAAgB,GAAG,SAChD,IAAG,QAAQ,gBAAgB;AAE7B,OAAI,gBAAgB,GAAG,WAAW,EAAE,WAAW,GAAG,SAChD,IAAG,QAAQ,QAAQ;AAIrB,OAAI,gBAAgB,GAAG,QACrB,IAAG,QAAQ,wBAAwB;;GAGvC;CAGF,MAAM,aAAa,UAAU,IAAI;CAEjC,IAAI;AAEJ,KAAI;AAYF,gBAAc,MAAM,YAXe;GACjC,iBAAiB,iBAAiB,mBAAmB;GACrD,wBAAwB,iBAAiB,0BAA0B;GACnE,sBAAsB,iBAAiB,wBAAwB;GAC/D,uBAAuB,iBAAiB,yBAAyB;GACjE,oBAAoB,YAAY,EAAE;GAClC,GAAG,YAAY,EAAE,UAAU,WAAW,GAAG,EAAE;GAC3C,2BAA2B,iBAAiB,6BAA6B;GACzE,GAAG;GACJ,CAE4C;SACvC;AAEN,SAAO;;CAIT,MAAM,SAAS,MAAM,YAAY;AAEjC,MAAK,SAAS,SAAS;EACrB,MAAM,KAAK;AACX,MAAI,GAAG,SAAS,OAAO;GAErB,IAAI,QAAQ,GAAG,QAAQ,MACpB,QAAQ,SAAS,KAAK,CACtB,QAAQ,SAAS,KAAK,CACtB,SAAS;AAGZ,OAAI,CAAC,MAAM,SAAS,IAAI,CACtB,UAAS;AAGX,OAAI,qBACF,SAAQ,MAAM,QACZ,4DACA,IACD;AAGH,MAAG,QAAQ,QAAQ;;GAErB;AAIF,MAAK,SAAS,SAAS;EACrB,MAAM,KAAK;AACX,MAAI,GAAG,SAAS,WAAW,GAAG,WAAW,wBAAwB,GAAG,SAAS;AAC3E,MAAG,QAAQ,gBAAgB;AAC3B,MAAG,QAAQ,QAAQ;AACnB,UAAO,GAAG,QAAQ;;GAEpB;AAEF,QAAO"}
1
+ {"version":3,"file":"inlineCSS.mjs","names":[],"sources":["../../src/transformers/inlineCSS.ts"],"sourcesContent":["import juice from 'juice'\nimport { walk, parse, serialize } from '../utils/ast/index.ts'\nimport type { ChildNode, Element } from 'domhandler'\nimport type { Options as JuiceOptions } from 'juice'\nimport type { CssConfig } from '../types/config.ts'\n\n/**\n * Inline CSS transformer.\n *\n * Inlines CSS from `<style>` tags into inline style attributes on HTML elements.\n * This is important for email client compatibility (especially Outlook on Windows).\n *\n * Enabled when `css.inline` is set to `true` or an object with options.\n * All Juice options are supported and passed through directly.\n */\nexport function inlineCSS(dom: ChildNode[], config: CssConfig = {}): ChildNode[] {\n const inline = config.inline\n\n // Disabled when inline is falsy or not an object/truthy\n if (!inline) {\n return dom\n }\n\n // Build options from config\n const options = typeof inline === 'object' ? inline : {}\n\n // Separate Maizzle-specific options from Juice options\n const {\n preferUnitlessValues = true,\n safelist,\n customCSS = '',\n styleToAttribute,\n excludedProperties,\n widthElements,\n heightElements,\n codeBlocks,\n ...juicePassthrough\n } = options\n\n // Configure Juice static properties\n juice.styleToAttribute = styleToAttribute ?? {}\n juice.excludedProperties = ['--tw-shadow', ...(excludedProperties ?? [])]\n juice.widthElements = (widthElements ?? ['img', 'video']).map(i => i.toUpperCase()) as unknown as HTMLElement[]\n juice.heightElements = (heightElements ?? ['img', 'video']).map(i => i.toUpperCase()) as unknown as HTMLElement[]\n\n // Add custom code blocks\n if (codeBlocks && typeof codeBlocks === 'object') {\n Object.entries(codeBlocks).forEach(([key, value]) => {\n if (value.start && value.end) {\n juice.codeBlocks[key] = value\n }\n })\n }\n\n // Handle style tags with embed attributes.\n // We add a marker attribute that persists through the pipeline,\n // then restore data-embed from it after Juice runs.\n walk(dom, (node) => {\n const el = node as Element\n if (el.name === 'style' && el.attribs) {\n // Sync data-embed ↔ embed. Use `in` so presence-only attrs\n // (<style embed> → attribs.embed === '') still count.\n if ('embed' in el.attribs && !('data-embed' in el.attribs)) {\n el.attribs['data-embed'] = ''\n }\n if ('data-embed' in el.attribs && !('embed' in el.attribs)) {\n el.attribs.embed = ''\n }\n\n // Add marker that persists through the pipeline\n if ('data-embed' in el.attribs) {\n el.attribs['data-maizzle-embed'] = ''\n }\n }\n })\n\n // Serialize for juice (juice requires a string)\n const serialized = serialize(dom)\n\n let inlinedHtml: string\n\n try {\n const juiceOptions: JuiceOptions = {\n removeStyleTags: juicePassthrough.removeStyleTags ?? false,\n removeInlinedSelectors: juicePassthrough.removeInlinedSelectors ?? true,\n applyWidthAttributes: juicePassthrough.applyWidthAttributes ?? true,\n applyHeightAttributes: juicePassthrough.applyHeightAttributes ?? true,\n preservedSelectors: safelist ?? [],\n ...customCSS ? { extraCss: customCSS } : {},\n inlineDuplicateProperties: juicePassthrough.inlineDuplicateProperties ?? true,\n ...juicePassthrough,\n }\n\n inlinedHtml = juice(serialized, juiceOptions)\n } catch {\n // If Juice fails, return the dom unchanged\n return dom\n }\n\n // Post-process for preferUnitlessValues\n const result = parse(inlinedHtml)\n\n walk(result, (node) => {\n const el = node as Element\n if (el.attribs?.style) {\n // Normalize style formatting: ensure spaces after : and ;\n let style = el.attribs.style\n .replace(/:\\s*/g, ': ')\n .replace(/;\\s*/g, '; ')\n .trimEnd()\n\n // Ensure trailing semicolon\n if (!style.endsWith(';')) {\n style += ';'\n }\n\n if (preferUnitlessValues) {\n style = style.replace(\n /\\b0(px|rem|em|%|vh|vw|vmin|vmax|in|cm|mm|pt|pc|ex|ch)\\b/g,\n '0'\n )\n }\n\n el.attribs.style = style\n }\n })\n\n /**\n * Restore `embed` from our marker so the purge step can detect\n * these tags and skip them. Drop `data-embed` (juice's name)\n * since it's redundant once `embed` is back, and let purge\n * strip `embed` itself at the end of its run.\n */\n walk(result, (node) => {\n const el = node as Element\n if (el.name === 'style' && el.attribs && 'data-maizzle-embed' in el.attribs) {\n el.attribs.embed = ''\n delete el.attribs['data-embed']\n delete el.attribs['data-maizzle-embed']\n }\n })\n\n return result\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAeA,SAAgB,UAAU,KAAkB,SAAoB,EAAE,EAAe;CAC/E,MAAM,SAAS,OAAO;AAGtB,KAAI,CAAC,OACH,QAAO;CAOT,MAAM,EACJ,uBAAuB,MACvB,UACA,YAAY,IACZ,kBACA,oBACA,eACA,gBACA,YACA,GAAG,qBAZW,OAAO,WAAW,WAAW,SAAS,EAAE;AAgBxD,OAAM,mBAAmB,oBAAoB,EAAE;AAC/C,OAAM,qBAAqB,CAAC,eAAe,GAAI,sBAAsB,EAAE,CAAE;AACzE,OAAM,iBAAiB,iBAAiB,CAAC,OAAO,QAAQ,EAAE,KAAI,MAAK,EAAE,aAAa,CAAC;AACnF,OAAM,kBAAkB,kBAAkB,CAAC,OAAO,QAAQ,EAAE,KAAI,MAAK,EAAE,aAAa,CAAC;AAGrF,KAAI,cAAc,OAAO,eAAe,SACtC,QAAO,QAAQ,WAAW,CAAC,SAAS,CAAC,KAAK,WAAW;AACnD,MAAI,MAAM,SAAS,MAAM,IACvB,OAAM,WAAW,OAAO;GAE1B;AAMJ,MAAK,MAAM,SAAS;EAClB,MAAM,KAAK;AACX,MAAI,GAAG,SAAS,WAAW,GAAG,SAAS;AAGrC,OAAI,WAAW,GAAG,WAAW,EAAE,gBAAgB,GAAG,SAChD,IAAG,QAAQ,gBAAgB;AAE7B,OAAI,gBAAgB,GAAG,WAAW,EAAE,WAAW,GAAG,SAChD,IAAG,QAAQ,QAAQ;AAIrB,OAAI,gBAAgB,GAAG,QACrB,IAAG,QAAQ,wBAAwB;;GAGvC;CAGF,MAAM,aAAa,UAAU,IAAI;CAEjC,IAAI;AAEJ,KAAI;AAYF,gBAAc,MAAM,YAXe;GACjC,iBAAiB,iBAAiB,mBAAmB;GACrD,wBAAwB,iBAAiB,0BAA0B;GACnE,sBAAsB,iBAAiB,wBAAwB;GAC/D,uBAAuB,iBAAiB,yBAAyB;GACjE,oBAAoB,YAAY,EAAE;GAClC,GAAG,YAAY,EAAE,UAAU,WAAW,GAAG,EAAE;GAC3C,2BAA2B,iBAAiB,6BAA6B;GACzE,GAAG;GACJ,CAE4C;SACvC;AAEN,SAAO;;CAIT,MAAM,SAAS,MAAM,YAAY;AAEjC,MAAK,SAAS,SAAS;EACrB,MAAM,KAAK;AACX,MAAI,GAAG,SAAS,OAAO;GAErB,IAAI,QAAQ,GAAG,QAAQ,MACpB,QAAQ,SAAS,KAAK,CACtB,QAAQ,SAAS,KAAK,CACtB,SAAS;AAGZ,OAAI,CAAC,MAAM,SAAS,IAAI,CACtB,UAAS;AAGX,OAAI,qBACF,SAAQ,MAAM,QACZ,4DACA,IACD;AAGH,MAAG,QAAQ,QAAQ;;GAErB;;;;;;;AAQF,MAAK,SAAS,SAAS;EACrB,MAAM,KAAK;AACX,MAAI,GAAG,SAAS,WAAW,GAAG,WAAW,wBAAwB,GAAG,SAAS;AAC3E,MAAG,QAAQ,QAAQ;AACnB,UAAO,GAAG,QAAQ;AAClB,UAAO,GAAG,QAAQ;;GAEpB;AAEF,QAAO"}
@@ -11,4 +11,4 @@ import { ChildNode } from "domhandler";
11
11
  declare function inlineLink(dom: ChildNode[], filePath?: string): Promise<ChildNode[]>;
12
12
  //#endregion
13
13
  export { inlineLink };
14
- //# sourceMappingURL=inlineLink.d.mts.map
14
+ //# sourceMappingURL=inlineLink.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inlineLink.d.ts","names":[],"sources":["../../src/transformers/inlineLink.ts"],"mappings":";;;;;AAYA;;;;;iBAAsB,UAAA,CAAW,GAAA,EAAK,SAAA,IAAa,QAAA,YAAoB,OAAA,CAAQ,SAAA"}
@@ -1,4 +1,4 @@
1
- import { MaizzleConfig } from "../types/config.mjs";
1
+ import { MaizzleConfig } from "../types/config.js";
2
2
 
3
3
  //#region src/transformers/minify.d.ts
4
4
  /**
@@ -14,4 +14,4 @@ import { MaizzleConfig } from "../types/config.mjs";
14
14
  declare function minify(html: string, config?: MaizzleConfig): string;
15
15
  //#endregion
16
16
  export { minify };
17
- //# sourceMappingURL=minify.d.mts.map
17
+ //# sourceMappingURL=minify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"minify.d.ts","names":[],"sources":["../../src/transformers/minify.ts"],"mappings":";;;;;AAmBA;;;;;;;;iBAAgB,MAAA,CAAO,IAAA,UAAc,MAAA,GAAQ,aAAA"}
@@ -16,4 +16,4 @@ import { ChildNode } from "domhandler";
16
16
  declare function msoWidthFromClass(dom: ChildNode[]): ChildNode[];
17
17
  //#endregion
18
18
  export { msoWidthFromClass };
19
- //# sourceMappingURL=msoWidthFromClass.d.mts.map
19
+ //# sourceMappingURL=msoWidthFromClass.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"msoWidthFromClass.d.ts","names":[],"sources":["../../src/transformers/msoWidthFromClass.ts"],"mappings":";;;;;AAkCA;;;;;;;;;;iBAAgB,iBAAA,CAAkB,GAAA,EAAK,SAAA,KAAc,SAAA"}
@@ -1,4 +1,4 @@
1
- import { CssConfig } from "../types/config.mjs";
1
+ import { CssConfig } from "../types/config.js";
2
2
  import { ChildNode } from "domhandler";
3
3
 
4
4
  //#region src/transformers/purgeCSS.d.ts
@@ -20,4 +20,4 @@ import { ChildNode } from "domhandler";
20
20
  declare function purgeCSS(dom: ChildNode[], config?: CssConfig): ChildNode[];
21
21
  //#endregion
22
22
  export { purgeCSS };
23
- //# sourceMappingURL=purgeCSS.d.mts.map
23
+ //# sourceMappingURL=purgeCSS.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"purgeCSS.d.ts","names":[],"sources":["../../src/transformers/purgeCSS.ts"],"mappings":";;;;;;AAiDA;;;;;;;;;;;;;iBAAgB,QAAA,CAAS,GAAA,EAAK,SAAA,IAAa,MAAA,GAAQ,SAAA,GAAiB,SAAA"}
@@ -3,7 +3,6 @@ import { walk } from "../utils/ast/walker.mjs";
3
3
  import { serialize } from "../utils/ast/serializer.mjs";
4
4
  import "../utils/ast/index.mjs";
5
5
  import { defu } from "defu";
6
- import postcss from "postcss";
7
6
  import safeParser from "postcss-safe-parser";
8
7
  import { selectAll } from "css-select";
9
8
  import { comb } from "email-comb";
@@ -63,8 +62,51 @@ function purgeCSS(dom, config = {}) {
63
62
  }, DEFAULT_OPTIONS);
64
63
  const safelist = [...DEFAULT_SAFELIST, ...userSafelist];
65
64
  dom = deepPurge(dom, safelist);
65
+ /**
66
+ * Shield embed style tags from email-comb. Comb has no skip option,
67
+ * so it strips CSS comments and drops class refs it can't match
68
+ * against visible CSS. Swap each embed tag's body for a unique
69
+ * stub rule (`.maizzle-keep-N{}`) so comb keeps the tag, then
70
+ * whitelist that stub plus every selector from the original
71
+ * CSS so comb leaves matching refs alone elsewhere — and
72
+ * finally restore the original CSS once comb has run.
73
+ */
74
+ const stash = [];
75
+ const extraWhitelist = [];
76
+ walk(dom, (node) => {
77
+ const el = node;
78
+ if (el.name !== "style" || !el.attribs) return;
79
+ if (!("embed" in el.attribs) && !("data-embed" in el.attribs)) return;
80
+ const textNode = el.children?.find((c) => c.type === "text");
81
+ if (!textNode?.data) return;
82
+ const token = `.maizzle-keep-${stash.length}`;
83
+ extraWhitelist.push(token);
84
+ for (const m of textNode.data.matchAll(/(?<![\w-])[.#][a-zA-Z_][\w-]*/g)) extraWhitelist.push(m[0]);
85
+ stash.push({
86
+ token,
87
+ original: textNode.data,
88
+ textNode
89
+ });
90
+ textNode.data = `${token}{}`;
91
+ });
92
+ if (extraWhitelist.length) options.whitelist = [...options.whitelist ?? [], ...extraWhitelist];
66
93
  const { result } = comb(serialize(dom), options);
94
+ /**
95
+ * Comb returns a fresh string, so we work off the post-parse tree:
96
+ * find each embed style tag whose body still starts with the stub
97
+ * token we planted earlier and swap the original CSS back in.
98
+ */
67
99
  let purgedDom = parse(result);
100
+ if (stash.length) walk(purgedDom, (node) => {
101
+ const el = node;
102
+ if (el.name !== "style" || !el.attribs) return;
103
+ if (!("embed" in el.attribs) && !("data-embed" in el.attribs)) return;
104
+ const textNode = el.children?.find((c) => c.type === "text");
105
+ if (!textNode?.data) return;
106
+ const trimmed = textNode.data.trim();
107
+ const match = stash.find((s) => trimmed === `${s.token}{}` || trimmed.startsWith(`${s.token}{`));
108
+ if (match) textNode.data = match.original;
109
+ });
68
110
  walk(purgedDom, (node) => {
69
111
  const el = node;
70
112
  if (el.name === "style" && el.attribs) {
@@ -94,7 +136,7 @@ function deepPurge(dom, safelist) {
94
136
  if ("data-embed" in el.attribs || "embed" in el.attribs) return;
95
137
  const textNode = el.children?.find((c) => c.type === "text");
96
138
  if (!textNode?.data?.trim()) return;
97
- const root = postcss.parse(textNode.data, { parser: safeParser });
139
+ const root = safeParser(textNode.data);
98
140
  root.walkRules((rule) => {
99
141
  if (rule.parent?.type === "atrule") return;
100
142
  const selectors = rule.selectors ?? [rule.selector];
@@ -1 +1 @@
1
- {"version":3,"file":"purgeCSS.mjs","names":["merge"],"sources":["../../src/transformers/purgeCSS.ts"],"sourcesContent":["import { comb } from 'email-comb'\nimport { defu as merge } from 'defu'\nimport postcss from 'postcss'\nimport safeParser from 'postcss-safe-parser'\nimport { selectAll } from 'css-select'\nimport type { ChildNode, Element } from 'domhandler'\nimport { parse, serialize, walk } from '../utils/ast/index.ts'\nimport type { CssConfig } from '../types/config.ts'\n\nconst DEFAULT_SAFELIST: string[] = [\n '*body*', // Gmail\n '.gmail*', // Gmail\n '.apple*', // Apple Mail\n '.ios*', // Mail on iOS\n '.ox-*', // Open-Xchange\n '.outlook*', // Outlook.com\n '[data-ogs*', // Outlook.com\n '.bloop_container', // Airmail\n '.Singleton', // Apple Mail 10\n '.unused', // Notes 8\n '.moz-text-html', // Thunderbird\n '.mail-detail-content', // Comcast, Libero webmail\n '*edo*', // Edison (all)\n '#*', // Freenet uses #msgBody\n '.lang*', // Fenced code blocks\n]\n\nconst DEFAULT_OPTIONS = {\n backend: [\n { heads: '{{', tails: '}}' },\n { heads: '{%', tails: '%}' },\n ],\n whitelist: [...DEFAULT_SAFELIST],\n}\n\n/**\n * Remove unused CSS transformer.\n *\n * Uses `email-comb` to strip CSS selectors and corresponding class/id\n * references that are not matched anywhere in the HTML body.\n *\n * Enable by setting `css.purge: true` (or passing options).\n * The user-supplied options are merged on top of the defaults, so\n * `safelist` values are **appended** to the built-in safelist rather\n * than replacing it.\n *\n * Accepts `ChildNode[]` as input, serializes internally before passing\n * to email-comb (which requires a raw HTML string), then parses the\n * result back to `ChildNode[]` so it fits in the DOM pipeline.\n */\nexport function purgeCSS(dom: ChildNode[], config: CssConfig = {}): ChildNode[] {\n const option = config.purge\n\n if (!option) return dom\n\n const userOptions = typeof option === 'object' ? option : {}\n\n // Merge user options on top of defaults.\n // defu merges objects deeply; for arrays it appends user values.\n // We want the user safelist appended to the default safelist,\n // so we build whitelist manually.\n const userSafelist = Array.isArray((userOptions as any).safelist)\n ? (userOptions as any).safelist as string[]\n : []\n\n const { safelist: _discard, ...restUserOptions } = userOptions as any\n\n const options = merge(\n { ...restUserOptions, whitelist: [...DEFAULT_SAFELIST, ...userSafelist] },\n DEFAULT_OPTIONS,\n )\n\n // Deep purge first: DOM-aware selector removal using PostCSS + css-select.\n // Runs before email-comb so that email-comb can clean up orphaned classes\n // in HTML attributes left behind by removed CSS rules.\n const safelist = [...DEFAULT_SAFELIST, ...userSafelist]\n dom = deepPurge(dom, safelist)\n\n const { result } = comb(serialize(dom), options)\n\n let purgedDom = parse(result)\n\n // Clean up data-embed/embed attributes — no longer needed after purging\n walk(purgedDom, (node) => {\n const el = node as Element\n if (el.name === 'style' && el.attribs) {\n delete el.attribs['data-embed']\n delete el.attribs.embed\n }\n })\n\n return purgedDom\n}\n\n/**\n * Deep purge: uses PostCSS to parse CSS in non-embedded style tags,\n * then checks each selector against the DOM with css-select.\n * Removes rules where no selector matches any element.\n */\nfunction isSafelisted(selector: string, safelist: string[]): boolean {\n return safelist.some((pattern) => {\n if (pattern.startsWith('*') && pattern.endsWith('*')) {\n return selector.includes(pattern.slice(1, -1))\n }\n if (pattern.endsWith('*')) {\n return selector.startsWith(pattern.slice(0, -1))\n }\n if (pattern.startsWith('*')) {\n return selector.endsWith(pattern.slice(1))\n }\n return selector === pattern\n })\n}\n\nfunction deepPurge(dom: ChildNode[], safelist: string[]): ChildNode[] {\n walk(dom, (node) => {\n const el = node as Element\n\n if (el.name !== 'style' || !el.attribs) return\n if ('data-embed' in el.attribs || 'embed' in el.attribs) return\n\n const textNode = el.children?.find((c: any) => c.type === 'text') as any\n if (!textNode?.data?.trim()) return\n\n const root = postcss.parse(textNode.data, { parser: safeParser })\n\n root.walkRules((rule) => {\n // Skip rules inside @media or other at-rules — those may target\n // states we can't match statically (hover, responsive, etc.)\n if (rule.parent?.type === 'atrule') return\n\n const selectors = rule.selectors ?? [rule.selector]\n const matched = selectors.filter((sel) => {\n // Keep safelisted selectors\n if (isSafelisted(sel, safelist)) return true\n\n // Skip pseudo-classes/elements that can't be matched statically.\n // Functional pseudos like :not(), :is(), :where(), :has() are\n // matchable by css-select, so we only skip dynamic/state ones.\n if (/::[\\w-]/.test(sel)) return true\n if (/(?<!:):(?!not\\b|is\\b|where\\b|has\\b)[\\w-]/.test(sel.replace(/\\\\./g, ''))) return true\n\n try {\n return selectAll(sel, dom).length > 0\n } catch {\n // If css-select can't parse the selector, keep it\n return true\n }\n })\n\n if (matched.length === 0) {\n rule.remove()\n } else if (matched.length < selectors.length) {\n rule.selectors = matched\n }\n })\n\n // Remove empty at-rules\n root.walkAtRules((atRule) => {\n if (atRule.nodes?.length === 0) {\n atRule.remove()\n }\n })\n\n const purgedCss = root.toString()\n\n if (purgedCss.trim()) {\n textNode.data = purgedCss\n } else {\n // Remove the style tag entirely if empty\n const parent = el.parent\n if (parent && 'children' in parent) {\n const idx = parent.children.indexOf(el as any)\n if (idx !== -1) parent.children.splice(idx, 1)\n }\n }\n })\n\n return dom\n}\n"],"mappings":";;;;;;;;;;;AASA,MAAM,mBAA6B;CACjC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AAED,MAAM,kBAAkB;CACtB,SAAS,CACP;EAAE,OAAO;EAAM,OAAO;EAAM,EAC5B;EAAE,OAAO;EAAM,OAAO;EAAM,CAC7B;CACD,WAAW,CAAC,GAAG,iBAAiB;CACjC;;;;;;;;;;;;;;;;AAiBD,SAAgB,SAAS,KAAkB,SAAoB,EAAE,EAAe;CAC9E,MAAM,SAAS,OAAO;AAEtB,KAAI,CAAC,OAAQ,QAAO;CAEpB,MAAM,cAAc,OAAO,WAAW,WAAW,SAAS,EAAE;CAM5D,MAAM,eAAe,MAAM,QAAS,YAAoB,SAAS,GAC5D,YAAoB,WACrB,EAAE;CAEN,MAAM,EAAE,UAAU,UAAU,GAAG,oBAAoB;CAEnD,MAAM,UAAUA,KACd;EAAE,GAAG;EAAiB,WAAW,CAAC,GAAG,kBAAkB,GAAG,aAAa;EAAE,EACzE,gBACD;CAKD,MAAM,WAAW,CAAC,GAAG,kBAAkB,GAAG,aAAa;AACvD,OAAM,UAAU,KAAK,SAAS;CAE9B,MAAM,EAAE,WAAW,KAAK,UAAU,IAAI,EAAE,QAAQ;CAEhD,IAAI,YAAY,MAAM,OAAO;AAG7B,MAAK,YAAY,SAAS;EACxB,MAAM,KAAK;AACX,MAAI,GAAG,SAAS,WAAW,GAAG,SAAS;AACrC,UAAO,GAAG,QAAQ;AAClB,UAAO,GAAG,QAAQ;;GAEpB;AAEF,QAAO;;;;;;;AAQT,SAAS,aAAa,UAAkB,UAA6B;AACnE,QAAO,SAAS,MAAM,YAAY;AAChC,MAAI,QAAQ,WAAW,IAAI,IAAI,QAAQ,SAAS,IAAI,CAClD,QAAO,SAAS,SAAS,QAAQ,MAAM,GAAG,GAAG,CAAC;AAEhD,MAAI,QAAQ,SAAS,IAAI,CACvB,QAAO,SAAS,WAAW,QAAQ,MAAM,GAAG,GAAG,CAAC;AAElD,MAAI,QAAQ,WAAW,IAAI,CACzB,QAAO,SAAS,SAAS,QAAQ,MAAM,EAAE,CAAC;AAE5C,SAAO,aAAa;GACpB;;AAGJ,SAAS,UAAU,KAAkB,UAAiC;AACpE,MAAK,MAAM,SAAS;EAClB,MAAM,KAAK;AAEX,MAAI,GAAG,SAAS,WAAW,CAAC,GAAG,QAAS;AACxC,MAAI,gBAAgB,GAAG,WAAW,WAAW,GAAG,QAAS;EAEzD,MAAM,WAAW,GAAG,UAAU,MAAM,MAAW,EAAE,SAAS,OAAO;AACjE,MAAI,CAAC,UAAU,MAAM,MAAM,CAAE;EAE7B,MAAM,OAAO,QAAQ,MAAM,SAAS,MAAM,EAAE,QAAQ,YAAY,CAAC;AAEjE,OAAK,WAAW,SAAS;AAGvB,OAAI,KAAK,QAAQ,SAAS,SAAU;GAEpC,MAAM,YAAY,KAAK,aAAa,CAAC,KAAK,SAAS;GACnD,MAAM,UAAU,UAAU,QAAQ,QAAQ;AAExC,QAAI,aAAa,KAAK,SAAS,CAAE,QAAO;AAKxC,QAAI,UAAU,KAAK,IAAI,CAAE,QAAO;AAChC,QAAI,2CAA2C,KAAK,IAAI,QAAQ,QAAQ,GAAG,CAAC,CAAE,QAAO;AAErF,QAAI;AACF,YAAO,UAAU,KAAK,IAAI,CAAC,SAAS;YAC9B;AAEN,YAAO;;KAET;AAEF,OAAI,QAAQ,WAAW,EACrB,MAAK,QAAQ;YACJ,QAAQ,SAAS,UAAU,OACpC,MAAK,YAAY;IAEnB;AAGF,OAAK,aAAa,WAAW;AAC3B,OAAI,OAAO,OAAO,WAAW,EAC3B,QAAO,QAAQ;IAEjB;EAEF,MAAM,YAAY,KAAK,UAAU;AAEjC,MAAI,UAAU,MAAM,CAClB,UAAS,OAAO;OACX;GAEL,MAAM,SAAS,GAAG;AAClB,OAAI,UAAU,cAAc,QAAQ;IAClC,MAAM,MAAM,OAAO,SAAS,QAAQ,GAAU;AAC9C,QAAI,QAAQ,GAAI,QAAO,SAAS,OAAO,KAAK,EAAE;;;GAGlD;AAEF,QAAO"}
1
+ {"version":3,"file":"purgeCSS.mjs","names":["merge"],"sources":["../../src/transformers/purgeCSS.ts"],"sourcesContent":["import { comb } from 'email-comb'\nimport { defu as merge } from 'defu'\nimport safeParser from 'postcss-safe-parser'\nimport { selectAll } from 'css-select'\nimport type { ChildNode, Element } from 'domhandler'\nimport { parse, serialize, walk } from '../utils/ast/index.ts'\nimport type { CssConfig } from '../types/config.ts'\n\nconst DEFAULT_SAFELIST: string[] = [\n '*body*', // Gmail\n '.gmail*', // Gmail\n '.apple*', // Apple Mail\n '.ios*', // Mail on iOS\n '.ox-*', // Open-Xchange\n '.outlook*', // Outlook.com\n '[data-ogs*', // Outlook.com\n '.bloop_container', // Airmail\n '.Singleton', // Apple Mail 10\n '.unused', // Notes 8\n '.moz-text-html', // Thunderbird\n '.mail-detail-content', // Comcast, Libero webmail\n '*edo*', // Edison (all)\n '#*', // Freenet uses #msgBody\n '.lang*', // Fenced code blocks\n]\n\nconst DEFAULT_OPTIONS = {\n backend: [\n { heads: '{{', tails: '}}' },\n { heads: '{%', tails: '%}' },\n ],\n whitelist: [...DEFAULT_SAFELIST],\n}\n\n/**\n * Remove unused CSS transformer.\n *\n * Uses `email-comb` to strip CSS selectors and corresponding class/id\n * references that are not matched anywhere in the HTML body.\n *\n * Enable by setting `css.purge: true` (or passing options).\n * The user-supplied options are merged on top of the defaults, so\n * `safelist` values are **appended** to the built-in safelist rather\n * than replacing it.\n *\n * Accepts `ChildNode[]` as input, serializes internally before passing\n * to email-comb (which requires a raw HTML string), then parses the\n * result back to `ChildNode[]` so it fits in the DOM pipeline.\n */\nexport function purgeCSS(dom: ChildNode[], config: CssConfig = {}): ChildNode[] {\n const option = config.purge\n\n if (!option) return dom\n\n const userOptions = typeof option === 'object' ? option : {}\n\n // Merge user options on top of defaults.\n // defu merges objects deeply; for arrays it appends user values.\n // We want the user safelist appended to the default safelist,\n // so we build whitelist manually.\n const userSafelist = Array.isArray((userOptions as any).safelist)\n ? (userOptions as any).safelist as string[]\n : []\n\n const { safelist: _discard, ...restUserOptions } = userOptions as any\n\n const options = merge(\n { ...restUserOptions, whitelist: [...DEFAULT_SAFELIST, ...userSafelist] },\n DEFAULT_OPTIONS,\n )\n\n // Deep purge first: DOM-aware selector removal using PostCSS + css-select.\n // Runs before email-comb so that email-comb can clean up orphaned classes\n // in HTML attributes left behind by removed CSS rules.\n const safelist = [...DEFAULT_SAFELIST, ...userSafelist]\n dom = deepPurge(dom, safelist)\n\n /**\n * Shield embed style tags from email-comb. Comb has no skip option,\n * so it strips CSS comments and drops class refs it can't match\n * against visible CSS. Swap each embed tag's body for a unique\n * stub rule (`.maizzle-keep-N{}`) so comb keeps the tag, then\n * whitelist that stub plus every selector from the original\n * CSS so comb leaves matching refs alone elsewhere — and\n * finally restore the original CSS once comb has run.\n */\n const stash: { token: string; original: string; textNode: any }[] = []\n const extraWhitelist: string[] = []\n walk(dom, (node) => {\n const el = node as Element\n if (el.name !== 'style' || !el.attribs) return\n if (!('embed' in el.attribs) && !('data-embed' in el.attribs)) return\n const textNode = el.children?.find((c: any) => c.type === 'text') as any\n if (!textNode?.data) return\n const idx = stash.length\n const token = `.maizzle-keep-${idx}`\n extraWhitelist.push(token)\n for (const m of textNode.data.matchAll(/(?<![\\w-])[.#][a-zA-Z_][\\w-]*/g)) {\n extraWhitelist.push(m[0])\n }\n stash.push({ token, original: textNode.data, textNode })\n textNode.data = `${token}{}`\n })\n\n if (extraWhitelist.length) {\n options.whitelist = [...(options.whitelist as string[] ?? []), ...extraWhitelist]\n }\n\n const { result } = comb(serialize(dom), options)\n\n /**\n * Comb returns a fresh string, so we work off the post-parse tree:\n * find each embed style tag whose body still starts with the stub\n * token we planted earlier and swap the original CSS back in.\n */\n let purgedDom = parse(result)\n\n if (stash.length) {\n walk(purgedDom, (node) => {\n const el = node as Element\n if (el.name !== 'style' || !el.attribs) return\n if (!('embed' in el.attribs) && !('data-embed' in el.attribs)) return\n const textNode = el.children?.find((c: any) => c.type === 'text') as any\n if (!textNode?.data) return\n const trimmed = textNode.data.trim()\n const match = stash.find(s => trimmed === `${s.token}{}` || trimmed.startsWith(`${s.token}{`))\n if (match) textNode.data = match.original\n })\n }\n\n // Clean up data-embed/embed attributes — no longer needed after purging\n walk(purgedDom, (node) => {\n const el = node as Element\n if (el.name === 'style' && el.attribs) {\n delete el.attribs['data-embed']\n delete el.attribs.embed\n }\n })\n\n return purgedDom\n}\n\n/**\n * Deep purge: uses PostCSS to parse CSS in non-embedded style tags,\n * then checks each selector against the DOM with css-select.\n * Removes rules where no selector matches any element.\n */\nfunction isSafelisted(selector: string, safelist: string[]): boolean {\n return safelist.some((pattern) => {\n if (pattern.startsWith('*') && pattern.endsWith('*')) {\n return selector.includes(pattern.slice(1, -1))\n }\n if (pattern.endsWith('*')) {\n return selector.startsWith(pattern.slice(0, -1))\n }\n if (pattern.startsWith('*')) {\n return selector.endsWith(pattern.slice(1))\n }\n return selector === pattern\n })\n}\n\nfunction deepPurge(dom: ChildNode[], safelist: string[]): ChildNode[] {\n walk(dom, (node) => {\n const el = node as Element\n\n if (el.name !== 'style' || !el.attribs) return\n if ('data-embed' in el.attribs || 'embed' in el.attribs) return\n\n const textNode = el.children?.find((c: any) => c.type === 'text') as any\n if (!textNode?.data?.trim()) return\n\n const root = safeParser(textNode.data)\n\n root.walkRules((rule) => {\n // Skip rules inside @media or other at-rules — those may target\n // states we can't match statically (hover, responsive, etc.)\n if (rule.parent?.type === 'atrule') return\n\n const selectors = rule.selectors ?? [rule.selector]\n const matched = selectors.filter((sel) => {\n // Keep safelisted selectors\n if (isSafelisted(sel, safelist)) return true\n\n // Skip pseudo-classes/elements that can't be matched statically.\n // Functional pseudos like :not(), :is(), :where(), :has() are\n // matchable by css-select, so we only skip dynamic/state ones.\n if (/::[\\w-]/.test(sel)) return true\n if (/(?<!:):(?!not\\b|is\\b|where\\b|has\\b)[\\w-]/.test(sel.replace(/\\\\./g, ''))) return true\n\n try {\n return selectAll(sel, dom).length > 0\n } catch {\n // If css-select can't parse the selector, keep it\n return true\n }\n })\n\n if (matched.length === 0) {\n rule.remove()\n } else if (matched.length < selectors.length) {\n rule.selectors = matched\n }\n })\n\n // Remove empty at-rules\n root.walkAtRules((atRule) => {\n if (atRule.nodes?.length === 0) {\n atRule.remove()\n }\n })\n\n const purgedCss = root.toString()\n\n if (purgedCss.trim()) {\n textNode.data = purgedCss\n } else {\n // Remove the style tag entirely if empty\n const parent = el.parent\n if (parent && 'children' in parent) {\n const idx = parent.children.indexOf(el as any)\n if (idx !== -1) parent.children.splice(idx, 1)\n }\n }\n })\n\n return dom\n}\n"],"mappings":";;;;;;;;;;AAQA,MAAM,mBAA6B;CACjC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AAED,MAAM,kBAAkB;CACtB,SAAS,CACP;EAAE,OAAO;EAAM,OAAO;EAAM,EAC5B;EAAE,OAAO;EAAM,OAAO;EAAM,CAC7B;CACD,WAAW,CAAC,GAAG,iBAAiB;CACjC;;;;;;;;;;;;;;;;AAiBD,SAAgB,SAAS,KAAkB,SAAoB,EAAE,EAAe;CAC9E,MAAM,SAAS,OAAO;AAEtB,KAAI,CAAC,OAAQ,QAAO;CAEpB,MAAM,cAAc,OAAO,WAAW,WAAW,SAAS,EAAE;CAM5D,MAAM,eAAe,MAAM,QAAS,YAAoB,SAAS,GAC5D,YAAoB,WACrB,EAAE;CAEN,MAAM,EAAE,UAAU,UAAU,GAAG,oBAAoB;CAEnD,MAAM,UAAUA,KACd;EAAE,GAAG;EAAiB,WAAW,CAAC,GAAG,kBAAkB,GAAG,aAAa;EAAE,EACzE,gBACD;CAKD,MAAM,WAAW,CAAC,GAAG,kBAAkB,GAAG,aAAa;AACvD,OAAM,UAAU,KAAK,SAAS;;;;;;;;;;CAW9B,MAAM,QAA8D,EAAE;CACtE,MAAM,iBAA2B,EAAE;AACnC,MAAK,MAAM,SAAS;EAClB,MAAM,KAAK;AACX,MAAI,GAAG,SAAS,WAAW,CAAC,GAAG,QAAS;AACxC,MAAI,EAAE,WAAW,GAAG,YAAY,EAAE,gBAAgB,GAAG,SAAU;EAC/D,MAAM,WAAW,GAAG,UAAU,MAAM,MAAW,EAAE,SAAS,OAAO;AACjE,MAAI,CAAC,UAAU,KAAM;EAErB,MAAM,QAAQ,iBADF,MAAM;AAElB,iBAAe,KAAK,MAAM;AAC1B,OAAK,MAAM,KAAK,SAAS,KAAK,SAAS,iCAAiC,CACtE,gBAAe,KAAK,EAAE,GAAG;AAE3B,QAAM,KAAK;GAAE;GAAO,UAAU,SAAS;GAAM;GAAU,CAAC;AACxD,WAAS,OAAO,GAAG,MAAM;GACzB;AAEF,KAAI,eAAe,OACjB,SAAQ,YAAY,CAAC,GAAI,QAAQ,aAAyB,EAAE,EAAG,GAAG,eAAe;CAGnF,MAAM,EAAE,WAAW,KAAK,UAAU,IAAI,EAAE,QAAQ;;;;;;CAOhD,IAAI,YAAY,MAAM,OAAO;AAE7B,KAAI,MAAM,OACR,MAAK,YAAY,SAAS;EACxB,MAAM,KAAK;AACX,MAAI,GAAG,SAAS,WAAW,CAAC,GAAG,QAAS;AACxC,MAAI,EAAE,WAAW,GAAG,YAAY,EAAE,gBAAgB,GAAG,SAAU;EAC/D,MAAM,WAAW,GAAG,UAAU,MAAM,MAAW,EAAE,SAAS,OAAO;AACjE,MAAI,CAAC,UAAU,KAAM;EACrB,MAAM,UAAU,SAAS,KAAK,MAAM;EACpC,MAAM,QAAQ,MAAM,MAAK,MAAK,YAAY,GAAG,EAAE,MAAM,OAAO,QAAQ,WAAW,GAAG,EAAE,MAAM,GAAG,CAAC;AAC9F,MAAI,MAAO,UAAS,OAAO,MAAM;GACjC;AAIJ,MAAK,YAAY,SAAS;EACxB,MAAM,KAAK;AACX,MAAI,GAAG,SAAS,WAAW,GAAG,SAAS;AACrC,UAAO,GAAG,QAAQ;AAClB,UAAO,GAAG,QAAQ;;GAEpB;AAEF,QAAO;;;;;;;AAQT,SAAS,aAAa,UAAkB,UAA6B;AACnE,QAAO,SAAS,MAAM,YAAY;AAChC,MAAI,QAAQ,WAAW,IAAI,IAAI,QAAQ,SAAS,IAAI,CAClD,QAAO,SAAS,SAAS,QAAQ,MAAM,GAAG,GAAG,CAAC;AAEhD,MAAI,QAAQ,SAAS,IAAI,CACvB,QAAO,SAAS,WAAW,QAAQ,MAAM,GAAG,GAAG,CAAC;AAElD,MAAI,QAAQ,WAAW,IAAI,CACzB,QAAO,SAAS,SAAS,QAAQ,MAAM,EAAE,CAAC;AAE5C,SAAO,aAAa;GACpB;;AAGJ,SAAS,UAAU,KAAkB,UAAiC;AACpE,MAAK,MAAM,SAAS;EAClB,MAAM,KAAK;AAEX,MAAI,GAAG,SAAS,WAAW,CAAC,GAAG,QAAS;AACxC,MAAI,gBAAgB,GAAG,WAAW,WAAW,GAAG,QAAS;EAEzD,MAAM,WAAW,GAAG,UAAU,MAAM,MAAW,EAAE,SAAS,OAAO;AACjE,MAAI,CAAC,UAAU,MAAM,MAAM,CAAE;EAE7B,MAAM,OAAO,WAAW,SAAS,KAAK;AAEtC,OAAK,WAAW,SAAS;AAGvB,OAAI,KAAK,QAAQ,SAAS,SAAU;GAEpC,MAAM,YAAY,KAAK,aAAa,CAAC,KAAK,SAAS;GACnD,MAAM,UAAU,UAAU,QAAQ,QAAQ;AAExC,QAAI,aAAa,KAAK,SAAS,CAAE,QAAO;AAKxC,QAAI,UAAU,KAAK,IAAI,CAAE,QAAO;AAChC,QAAI,2CAA2C,KAAK,IAAI,QAAQ,QAAQ,GAAG,CAAC,CAAE,QAAO;AAErF,QAAI;AACF,YAAO,UAAU,KAAK,IAAI,CAAC,SAAS;YAC9B;AAEN,YAAO;;KAET;AAEF,OAAI,QAAQ,WAAW,EACrB,MAAK,QAAQ;YACJ,QAAQ,SAAS,UAAU,OACpC,MAAK,YAAY;IAEnB;AAGF,OAAK,aAAa,WAAW;AAC3B,OAAI,OAAO,OAAO,WAAW,EAC3B,QAAO,QAAQ;IAEjB;EAEF,MAAM,YAAY,KAAK,UAAU;AAEjC,MAAI,UAAU,MAAM,CAClB,UAAS,OAAO;OACX;GAEL,MAAM,SAAS,GAAG;AAClB,OAAI,UAAU,cAAc,QAAQ;IAClC,MAAM,MAAM,OAAO,SAAS,QAAQ,GAAU;AAC9C,QAAI,QAAQ,GAAI,QAAO,SAAS,OAAO,KAAK,EAAE;;;GAGlD;AAEF,QAAO"}
@@ -1,4 +1,4 @@
1
- import { AttributesConfig } from "../types/config.mjs";
1
+ import { AttributesConfig } from "../types/config.js";
2
2
  import { ChildNode } from "domhandler";
3
3
 
4
4
  //#region src/transformers/removeAttributes.d.ts
@@ -28,4 +28,4 @@ import { ChildNode } from "domhandler";
28
28
  declare function removeAttributes(dom: ChildNode[], config?: AttributesConfig): ChildNode[];
29
29
  //#endregion
30
30
  export { removeAttributes };
31
- //# sourceMappingURL=removeAttributes.d.mts.map
31
+ //# sourceMappingURL=removeAttributes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"removeAttributes.d.ts","names":[],"sources":["../../src/transformers/removeAttributes.ts"],"mappings":";;;;;;AAkCA;;;;;;;;;;;;;;;;;;;;;iBAAgB,gBAAA,CAAiB,GAAA,EAAK,SAAA,IAAa,MAAA,GAAQ,gBAAA,GAAwB,SAAA"}
@@ -1,4 +1,4 @@
1
- import { MaizzleConfig } from "../types/config.mjs";
1
+ import { MaizzleConfig } from "../types/config.js";
2
2
 
3
3
  //#region src/transformers/replaceStrings.d.ts
4
4
  /**
@@ -13,4 +13,4 @@ import { MaizzleConfig } from "../types/config.mjs";
13
13
  declare function replaceStrings(html: string, config?: MaizzleConfig): string;
14
14
  //#endregion
15
15
  export { replaceStrings };
16
- //# sourceMappingURL=replaceStrings.d.mts.map
16
+ //# sourceMappingURL=replaceStrings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replaceStrings.d.ts","names":[],"sources":["../../src/transformers/replaceStrings.ts"],"mappings":";;;;;AAWA;;;;;;;iBAAgB,cAAA,CAAe,IAAA,UAAc,MAAA,GAAQ,aAAA"}