@maizzle/framework 6.0.0-rc.21 → 6.0.0-rc.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +11 -0
- package/dist/build.js.map +1 -1
- package/dist/components/Body.vue +1 -1
- package/dist/components/CodeBlock.vue +1 -1
- package/dist/components/CodeInline.vue +72 -2
- package/dist/components/Column.vue +2 -1
- package/dist/components/Container.vue +1 -11
- package/dist/components/Heading.vue +1 -1
- package/dist/components/Img.vue +252 -7
- package/dist/components/Link.vue +1 -1
- package/dist/components/Preheader.vue +35 -5
- package/dist/components/Section.vue +9 -14
- package/dist/components/Tailwind.vue +4 -2
- package/dist/components/Text.vue +2 -2
- package/dist/components/Vml.vue +354 -0
- package/dist/components/utils.d.ts.map +1 -1
- package/dist/components/utils.js.map +1 -1
- package/dist/composables/defineConfig.d.ts +3 -4
- package/dist/composables/defineConfig.d.ts.map +1 -1
- package/dist/composables/defineConfig.js +3 -4
- package/dist/composables/defineConfig.js.map +1 -1
- package/dist/composables/renderContext.d.ts +0 -1
- package/dist/composables/renderContext.d.ts.map +1 -1
- package/dist/composables/renderContext.js.map +1 -1
- package/dist/composables/useBaseUrl.d.ts.map +1 -1
- package/dist/composables/useBaseUrl.js.map +1 -1
- package/dist/composables/useConfig.d.ts.map +1 -1
- package/dist/composables/useConfig.js.map +1 -1
- package/dist/composables/useCurrentTemplate.d.ts.map +1 -1
- package/dist/composables/useCurrentTemplate.js +10 -3
- package/dist/composables/useCurrentTemplate.js.map +1 -1
- package/dist/composables/useDoctype.d.ts.map +1 -1
- package/dist/composables/useDoctype.js.map +1 -1
- package/dist/composables/useEvent.js.map +1 -1
- package/dist/composables/useFont.d.ts.map +1 -1
- package/dist/composables/useFont.js.map +1 -1
- package/dist/composables/useOutlookFallback.d.ts.map +1 -1
- package/dist/composables/useOutlookFallback.js.map +1 -1
- package/dist/composables/usePlaintext.d.ts.map +1 -1
- package/dist/composables/usePlaintext.js.map +1 -1
- package/dist/composables/usePreheader.d.ts +6 -5
- package/dist/composables/usePreheader.d.ts.map +1 -1
- package/dist/composables/usePreheader.js +3 -3
- package/dist/composables/usePreheader.js.map +1 -1
- package/dist/composables/useTransformers.d.ts +1 -1
- package/dist/composables/useTransformers.d.ts.map +1 -1
- package/dist/composables/useTransformers.js +1 -1
- package/dist/composables/useTransformers.js.map +1 -1
- package/dist/composables/useUrlQuery.d.ts.map +1 -1
- package/dist/composables/useUrlQuery.js.map +1 -1
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/index.js +12 -0
- package/dist/config/index.js.map +1 -1
- package/dist/events/index.d.ts +5 -0
- package/dist/events/index.d.ts.map +1 -1
- package/dist/events/index.js +5 -0
- package/dist/events/index.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/plaintext.d.ts.map +1 -1
- package/dist/plaintext.js.map +1 -1
- package/dist/plugin.js.map +1 -1
- package/dist/plugins/postcss/mergeMediaQueries.d.ts.map +1 -1
- package/dist/plugins/postcss/mergeMediaQueries.js.map +1 -1
- package/dist/plugins/postcss/pruneVars.d.ts.map +1 -1
- package/dist/plugins/postcss/pruneVars.js.map +1 -1
- package/dist/plugins/postcss/quoteFontFamilies.d.ts.map +1 -1
- package/dist/plugins/postcss/quoteFontFamilies.js.map +1 -1
- package/dist/plugins/postcss/removeDeclarations.d.ts.map +1 -1
- package/dist/plugins/postcss/removeDeclarations.js.map +1 -1
- package/dist/plugins/postcss/resolveMaizzleImports.d.ts.map +1 -1
- package/dist/plugins/postcss/resolveMaizzleImports.js.map +1 -1
- package/dist/plugins/postcss/resolveProps.d.ts.map +1 -1
- package/dist/plugins/postcss/resolveProps.js +14 -0
- package/dist/plugins/postcss/resolveProps.js.map +1 -1
- package/dist/plugins/postcss/tailwindCleanup.d.ts.map +1 -1
- package/dist/plugins/postcss/tailwindCleanup.js.map +1 -1
- package/dist/prepare.d.ts.map +1 -1
- package/dist/prepare.js.map +1 -1
- package/dist/render/active.d.ts.map +1 -1
- package/dist/render/active.js.map +1 -1
- package/dist/render/createRenderer.d.ts.map +1 -1
- package/dist/render/createRenderer.js +91 -3
- package/dist/render/createRenderer.js.map +1 -1
- package/dist/render/index.d.ts.map +1 -1
- package/dist/render/index.js +6 -0
- package/dist/render/index.js.map +1 -1
- package/dist/render/injectFonts.js.map +1 -1
- package/dist/render/plugins/codeBlockExtract.d.ts.map +1 -1
- package/dist/render/plugins/codeBlockExtract.js +4 -0
- package/dist/render/plugins/codeBlockExtract.js.map +1 -1
- package/dist/render/plugins/markdownExtract.d.ts.map +1 -1
- package/dist/render/plugins/markdownExtract.js.map +1 -1
- package/dist/render/plugins/rawExtract.d.ts.map +1 -1
- package/dist/render/plugins/rawExtract.js.map +1 -1
- package/dist/render/plugins/rowSourceLocation.d.ts.map +1 -1
- package/dist/render/plugins/rowSourceLocation.js.map +1 -1
- package/dist/serve.d.ts.map +1 -1
- package/dist/serve.js +48 -15
- package/dist/serve.js.map +1 -1
- package/dist/server/compatibility.d.ts.map +1 -1
- package/dist/server/compatibility.js +48 -0
- package/dist/server/compatibility.js.map +1 -1
- package/dist/server/email.js.map +1 -1
- package/dist/server/linter.js +6 -0
- package/dist/server/linter.js.map +1 -1
- package/dist/server/sfc-utils.d.ts.map +1 -1
- package/dist/server/sfc-utils.js.map +1 -1
- package/dist/server/ui/App.vue +17 -16
- package/dist/server/ui/components/Markdown.vue +17 -0
- package/dist/server/ui/components/SidebarClose.vue +1 -1
- package/dist/server/ui/components/ui/checkbox/Checkbox.vue +1 -1
- package/dist/server/ui/components/ui/command/CommandInput.vue +2 -2
- package/dist/server/ui/components/ui/dialog/DialogContent.vue +1 -1
- package/dist/server/ui/components/ui/dialog/DialogScrollContent.vue +1 -1
- package/dist/server/ui/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue +1 -1
- package/dist/server/ui/components/ui/dropdown-menu/DropdownMenuRadioItem.vue +1 -1
- package/dist/server/ui/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue +1 -1
- package/dist/server/ui/components/ui/sheet/SheetContent.vue +1 -1
- package/dist/server/ui/components/ui/sidebar/SidebarTrigger.vue +1 -1
- package/dist/server/ui/components/ui/tags-input/TagsInputItemDelete.vue +1 -1
- package/dist/server/ui/lib/emulated-dark-mode.ts +25 -10
- package/dist/server/ui/pages/Home.vue +1 -1
- package/dist/server/ui/pages/Preview.vue +32 -18
- package/dist/tests/render/_helpers.js.map +1 -1
- package/dist/transformers/addAttributes.d.ts +18 -8
- package/dist/transformers/addAttributes.d.ts.map +1 -1
- package/dist/transformers/addAttributes.js +22 -8
- package/dist/transformers/addAttributes.js.map +1 -1
- package/dist/transformers/attributeToStyle.d.ts.map +1 -1
- package/dist/transformers/attributeToStyle.js.map +1 -1
- package/dist/transformers/base.d.ts.map +1 -1
- package/dist/transformers/base.js +4 -0
- package/dist/transformers/base.js.map +1 -1
- package/dist/transformers/columnWidth.d.ts.map +1 -1
- package/dist/transformers/columnWidth.js +136 -150
- package/dist/transformers/columnWidth.js.map +1 -1
- package/dist/transformers/entities.d.ts.map +1 -1
- package/dist/transformers/entities.js +1 -0
- package/dist/transformers/entities.js.map +1 -1
- package/dist/transformers/filters/defaults.d.ts.map +1 -1
- package/dist/transformers/filters/defaults.js.map +1 -1
- package/dist/transformers/filters/index.d.ts.map +1 -1
- package/dist/transformers/filters/index.js.map +1 -1
- package/dist/transformers/format.d.ts.map +1 -1
- package/dist/transformers/format.js.map +1 -1
- package/dist/transformers/index.d.ts.map +1 -1
- package/dist/transformers/index.js +33 -5
- package/dist/transformers/index.js.map +1 -1
- package/dist/transformers/inlineCss.d.ts.map +1 -1
- package/dist/transformers/inlineCss.js +27 -9
- package/dist/transformers/inlineCss.js.map +1 -1
- package/dist/transformers/inlineLink.d.ts.map +1 -1
- package/dist/transformers/inlineLink.js.map +1 -1
- package/dist/transformers/minify.d.ts.map +1 -1
- package/dist/transformers/minify.js.map +1 -1
- package/dist/transformers/minifyCodeInline.d.ts +29 -0
- package/dist/transformers/minifyCodeInline.d.ts.map +1 -0
- package/dist/transformers/minifyCodeInline.js +36 -0
- package/dist/transformers/minifyCodeInline.js.map +1 -0
- package/dist/transformers/msoPlaceholders.d.ts +10 -5
- package/dist/transformers/msoPlaceholders.d.ts.map +1 -1
- package/dist/transformers/msoPlaceholders.js +38 -7
- package/dist/transformers/msoPlaceholders.js.map +1 -1
- package/dist/transformers/purgeCss.d.ts.map +1 -1
- package/dist/transformers/purgeCss.js +29 -3
- package/dist/transformers/purgeCss.js.map +1 -1
- package/dist/transformers/removeAttributes.d.ts.map +1 -1
- package/dist/transformers/removeAttributes.js.map +1 -1
- package/dist/transformers/replaceStrings.d.ts.map +1 -1
- package/dist/transformers/replaceStrings.js.map +1 -1
- package/dist/transformers/safeSelectors.d.ts +37 -0
- package/dist/transformers/safeSelectors.d.ts.map +1 -0
- package/dist/transformers/{safeClassNames.js → safeSelectors.js} +37 -6
- package/dist/transformers/safeSelectors.js.map +1 -0
- package/dist/transformers/shorthandCss.d.ts.map +1 -1
- package/dist/transformers/shorthandCss.js +38 -7
- package/dist/transformers/shorthandCss.js.map +1 -1
- package/dist/transformers/sixHex.d.ts.map +1 -1
- package/dist/transformers/sixHex.js.map +1 -1
- package/dist/transformers/tailwindComponent.js +9 -0
- package/dist/transformers/tailwindComponent.js.map +1 -1
- package/dist/transformers/tailwindcss.d.ts.map +1 -1
- package/dist/transformers/tailwindcss.js +22 -0
- package/dist/transformers/tailwindcss.js.map +1 -1
- package/dist/transformers/urlQuery.d.ts.map +1 -1
- package/dist/transformers/urlQuery.js.map +1 -1
- package/dist/types/config.d.ts +6 -10
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/utils/ast/parser.d.ts.map +1 -1
- package/dist/utils/ast/parser.js.map +1 -1
- package/dist/utils/ast/serializer.d.ts.map +1 -1
- package/dist/utils/ast/serializer.js +27 -17
- package/dist/utils/ast/serializer.js.map +1 -1
- package/dist/utils/ast/walker.d.ts.map +1 -1
- package/dist/utils/ast/walker.js.map +1 -1
- package/dist/utils/compileTailwindCss.d.ts.map +1 -1
- package/dist/utils/compileTailwindCss.js.map +1 -1
- package/dist/utils/componentSources.d.ts.map +1 -1
- package/dist/utils/componentSources.js.map +1 -1
- package/dist/utils/cssBox.d.ts +42 -0
- package/dist/utils/cssBox.d.ts.map +1 -0
- package/dist/utils/cssBox.js +156 -0
- package/dist/utils/cssBox.js.map +1 -0
- package/dist/utils/decodeStyleEntities.d.ts.map +1 -1
- package/dist/utils/decodeStyleEntities.js.map +1 -1
- package/dist/utils/detect.d.ts.map +1 -1
- package/dist/utils/detect.js.map +1 -1
- package/dist/utils/output-markers.d.ts.map +1 -1
- package/dist/utils/output-markers.js.map +1 -1
- package/dist/utils/url.d.ts.map +1 -1
- package/dist/utils/url.js.map +1 -1
- package/dist/utils/watchPaths.js.map +1 -1
- package/node_modules/@clack/core/CHANGELOG.md +6 -0
- package/node_modules/@clack/core/dist/index.d.mts +1 -1
- package/node_modules/@clack/core/dist/index.mjs +8 -8
- package/node_modules/@clack/core/dist/index.mjs.map +1 -1
- package/node_modules/@clack/core/package.json +1 -1
- package/node_modules/@clack/prompts/CHANGELOG.md +13 -0
- package/node_modules/@clack/prompts/README.md +2 -2
- package/node_modules/@clack/prompts/dist/index.d.mts +98 -0
- package/node_modules/@clack/prompts/dist/index.mjs +122 -121
- package/node_modules/@clack/prompts/dist/index.mjs.map +1 -1
- package/node_modules/@clack/prompts/package.json +2 -2
- package/node_modules/fast-wrap-ansi/lib/main.js +0 -1
- package/node_modules/fast-wrap-ansi/package.json +10 -10
- package/node_modules/maizzle/dist/commands/make/config.mjs +7 -6
- package/node_modules/maizzle/dist/commands/new.mjs +15 -84
- package/node_modules/maizzle/package.json +2 -2
- package/node_modules/tinyexec/README.md +8 -0
- package/node_modules/tinyexec/dist/main.d.mts +16 -1
- package/node_modules/tinyexec/dist/main.mjs +163 -457
- package/node_modules/tinyexec/package.json +12 -14
- package/package.json +3 -4
- package/dist/transformers/safeClassNames.d.ts +0 -22
- package/dist/transformers/safeClassNames.d.ts.map +0 -1
- package/dist/transformers/safeClassNames.js.map +0 -1
- package/node_modules/fast-wrap-ansi/lib/main.js.map +0 -1
- package/node_modules/tinyexec/dist/LICENSES.txt +0 -83
|
@@ -3,7 +3,7 @@ import type { ListboxFilterProps } from "reka-ui"
|
|
|
3
3
|
import type { HTMLAttributes } from "vue"
|
|
4
4
|
import { watch } from "vue"
|
|
5
5
|
import { reactiveOmit } from "@vueuse/core"
|
|
6
|
-
import { Search } from "lucide
|
|
6
|
+
import { Search } from "@lucide/vue"
|
|
7
7
|
import { ListboxFilter, useForwardProps } from "reka-ui"
|
|
8
8
|
import { cn } from "@/lib/utils"
|
|
9
9
|
import { useCommand } from "."
|
|
@@ -45,7 +45,7 @@ watch(() => filterState.search, (val) => {
|
|
|
45
45
|
data-slot="command-input-wrapper"
|
|
46
46
|
class="flex h-9 items-center gap-2 border-b px-3"
|
|
47
47
|
>
|
|
48
|
-
<Search class="size-4 shrink-0 opacity-
|
|
48
|
+
<Search class="size-4 shrink-0 opacity-70" :stroke-width="1" />
|
|
49
49
|
<ListboxFilter
|
|
50
50
|
v-bind="{ ...forwardedProps, ...$attrs }"
|
|
51
51
|
v-model="filterState.search"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import type { DialogContentEmits, DialogContentProps } from "reka-ui"
|
|
3
3
|
import type { HTMLAttributes } from "vue"
|
|
4
4
|
import { reactiveOmit } from "@vueuse/core"
|
|
5
|
-
import { X } from "lucide
|
|
5
|
+
import { X } from "@lucide/vue"
|
|
6
6
|
import {
|
|
7
7
|
DialogClose,
|
|
8
8
|
DialogContent,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import type { DialogContentEmits, DialogContentProps } from "reka-ui"
|
|
3
3
|
import type { HTMLAttributes } from "vue"
|
|
4
4
|
import { reactiveOmit } from "@vueuse/core"
|
|
5
|
-
import { X } from "lucide
|
|
5
|
+
import { X } from "@lucide/vue"
|
|
6
6
|
import {
|
|
7
7
|
DialogClose,
|
|
8
8
|
DialogContent,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import type { DropdownMenuCheckboxItemEmits, DropdownMenuCheckboxItemProps } from "reka-ui"
|
|
3
3
|
import type { HTMLAttributes } from "vue"
|
|
4
4
|
import { reactiveOmit } from "@vueuse/core"
|
|
5
|
-
import { Check } from "lucide
|
|
5
|
+
import { Check } from "@lucide/vue"
|
|
6
6
|
import {
|
|
7
7
|
DropdownMenuCheckboxItem,
|
|
8
8
|
DropdownMenuItemIndicator,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import type { DropdownMenuRadioItemEmits, DropdownMenuRadioItemProps } from "reka-ui"
|
|
3
3
|
import type { HTMLAttributes } from "vue"
|
|
4
4
|
import { reactiveOmit } from "@vueuse/core"
|
|
5
|
-
import { Circle } from "lucide
|
|
5
|
+
import { Circle } from "@lucide/vue"
|
|
6
6
|
import {
|
|
7
7
|
DropdownMenuItemIndicator,
|
|
8
8
|
DropdownMenuRadioItem,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import type { DropdownMenuSubTriggerProps } from "reka-ui"
|
|
3
3
|
import type { HTMLAttributes } from "vue"
|
|
4
4
|
import { reactiveOmit } from "@vueuse/core"
|
|
5
|
-
import { ChevronRight } from "lucide
|
|
5
|
+
import { ChevronRight } from "@lucide/vue"
|
|
6
6
|
import {
|
|
7
7
|
DropdownMenuSubTrigger,
|
|
8
8
|
useForwardProps,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import type { DialogContentEmits, DialogContentProps } from "reka-ui"
|
|
3
3
|
import type { HTMLAttributes } from "vue"
|
|
4
4
|
import { reactiveOmit } from "@vueuse/core"
|
|
5
|
-
import { X } from "lucide
|
|
5
|
+
import { X } from "@lucide/vue"
|
|
6
6
|
import {
|
|
7
7
|
DialogClose,
|
|
8
8
|
DialogContent,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { HTMLAttributes } from "vue"
|
|
3
|
-
import { PanelRightClose, PanelRightOpen } from "lucide
|
|
3
|
+
import { PanelRightClose, PanelRightOpen } from "@lucide/vue"
|
|
4
4
|
import { cn } from "@/lib/utils"
|
|
5
5
|
import { Button } from '@/components/ui/button'
|
|
6
6
|
import { useSidebar } from "./utils"
|
|
@@ -3,7 +3,7 @@ import type { TagsInputItemDeleteProps } from "reka-ui"
|
|
|
3
3
|
import type { HTMLAttributes } from "vue"
|
|
4
4
|
import { reactiveOmit } from "@vueuse/core"
|
|
5
5
|
import { TagsInputItemDelete, useForwardProps } from "reka-ui"
|
|
6
|
-
import { X } from "lucide
|
|
6
|
+
import { X } from "@lucide/vue"
|
|
7
7
|
import { cn } from "@/lib/utils"
|
|
8
8
|
|
|
9
9
|
const props = defineProps<TagsInputItemDeleteProps & { class?: HTMLAttributes["class"] }>()
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { parse, converter, formatRgb } from 'culori'
|
|
2
|
-
import safeParser from 'postcss-safe-parser'
|
|
3
2
|
|
|
4
3
|
const toLch = converter('lch')
|
|
5
4
|
|
|
6
5
|
type Mode = 'background' | 'foreground'
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
/**
|
|
8
|
+
* CSS properties whose values contain colors we should invert, mapped to
|
|
9
|
+
* the inversion mode. Kebab-case for <style> decls; inline styles
|
|
10
|
+
* are handled via the same lookup after lowercasing.
|
|
11
|
+
*/
|
|
11
12
|
const styleProps = new Map<string, Mode>([
|
|
12
13
|
['background', 'background'],
|
|
13
14
|
['background-color', 'background'],
|
|
@@ -71,12 +72,26 @@ function invertInlineStyle(style: string): string {
|
|
|
71
72
|
|
|
72
73
|
function invertStyleTag(css: string): string {
|
|
73
74
|
try {
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
75
|
+
const sheet = new CSSStyleSheet()
|
|
76
|
+
sheet.replaceSync(css)
|
|
77
|
+
const walk = (rules: CSSRuleList) => {
|
|
78
|
+
for (const rule of Array.from(rules)) {
|
|
79
|
+
if (rule instanceof CSSStyleRule) {
|
|
80
|
+
const props = Array.from({ length: rule.style.length }, (_, i) => rule.style.item(i))
|
|
81
|
+
for (const prop of props) {
|
|
82
|
+
const mode = styleProps.get(prop.toLowerCase())
|
|
83
|
+
if (!mode) continue
|
|
84
|
+
const value = rule.style.getPropertyValue(prop)
|
|
85
|
+
const priority = rule.style.getPropertyPriority(prop)
|
|
86
|
+
rule.style.setProperty(prop, invertValue(value, mode), priority)
|
|
87
|
+
}
|
|
88
|
+
} else if ('cssRules' in rule) {
|
|
89
|
+
walk((rule as CSSGroupingRule).cssRules)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
walk(sheet.cssRules)
|
|
94
|
+
return Array.from(sheet.cssRules).map(r => r.cssText).join('\n')
|
|
80
95
|
} catch {
|
|
81
96
|
return css
|
|
82
97
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { ref, computed, watch, nextTick, onMounted, onUnmounted } from 'vue'
|
|
3
3
|
import { useRoute } from 'vue-router'
|
|
4
|
-
import { ChevronUp, ChevronDown, Check } from 'lucide
|
|
4
|
+
import { ChevronUp, ChevronDown, Check } from '@lucide/vue'
|
|
5
5
|
import {
|
|
6
6
|
DropdownMenu,
|
|
7
7
|
DropdownMenuContent,
|
|
@@ -84,8 +84,10 @@ const iframeContentHeight = ref<number | null>(null)
|
|
|
84
84
|
function copySource() {
|
|
85
85
|
let text: string
|
|
86
86
|
if (sourceView.value === 'compiled') {
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
/**
|
|
88
|
+
* `renderedHtml` holds the raw compiled HTML (srcdoc is only populated
|
|
89
|
+
* for the initial iframe load; subsequent renders use doc.write).
|
|
90
|
+
*/
|
|
89
91
|
text = renderedHtml || srcdoc.value
|
|
90
92
|
} else if (sourceView.value === 'plaintext') {
|
|
91
93
|
text = plaintextContent.value
|
|
@@ -160,8 +162,10 @@ const compatibilityIssues = ref<CheckIssue[]>([])
|
|
|
160
162
|
const compatibilityLoading = ref(false)
|
|
161
163
|
const compatibilityError = ref('')
|
|
162
164
|
const compatibilityCategory = ref('')
|
|
163
|
-
|
|
164
|
-
|
|
165
|
+
/**
|
|
166
|
+
* Injected by serveDevUI into index.html — synchronous, available before
|
|
167
|
+
* any HTTP calls, so the Checks tab never flashes in when disabled.
|
|
168
|
+
*/
|
|
165
169
|
const checksConfig = (window as any).__MAIZZLE_CONFIG__?.checks
|
|
166
170
|
const compatibilityDisabled = ref(checksConfig === false)
|
|
167
171
|
const expandedIssueKeys = ref(new Set<string>())
|
|
@@ -266,8 +270,10 @@ async function fetchTemplate() {
|
|
|
266
270
|
const iframe = iframeEl.value
|
|
267
271
|
const doc = iframe?.contentDocument
|
|
268
272
|
|
|
269
|
-
|
|
270
|
-
|
|
273
|
+
/**
|
|
274
|
+
* Write directly into the iframe document to avoid a full reload,
|
|
275
|
+
* which preserves scroll position natively.
|
|
276
|
+
*/
|
|
271
277
|
if (doc) {
|
|
272
278
|
doc.open()
|
|
273
279
|
doc.write(renderedHtml)
|
|
@@ -359,9 +365,12 @@ async function fetchCompatibility() {
|
|
|
359
365
|
} else {
|
|
360
366
|
const issues: CheckIssue[] = Array.isArray(data) ? data : []
|
|
361
367
|
compatibilityIssues.value = issues
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
368
|
+
/**
|
|
369
|
+
* Keep the current category if it still has issues; otherwise fall
|
|
370
|
+
* back to the first category that does. Prevents a "refresh"
|
|
371
|
+
* during edits from snapping back to CSS when the user is
|
|
372
|
+
* on HTML/Image.
|
|
373
|
+
*/
|
|
365
374
|
const current = compatibilityCategory.value
|
|
366
375
|
const currentStillActive = current && issues.some((i) => i.category === current)
|
|
367
376
|
if (!currentStillActive) {
|
|
@@ -462,20 +471,25 @@ if ((import.meta as any).hot) {
|
|
|
462
471
|
fetchCompatibility()
|
|
463
472
|
fetchStats()
|
|
464
473
|
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
474
|
+
/**
|
|
475
|
+
* Refetch in place — don't clear the previous values first. v-html
|
|
476
|
+
* replaces the highlighted block atomically when the new content
|
|
477
|
+
* arrives, and the ScrollArea viewport keeps its scrollTop as
|
|
478
|
+
* long as the new content's height is similar. Plaintext
|
|
479
|
+
* interpolation updates a single text node, so scroll
|
|
480
|
+
* is naturally preserved.
|
|
481
|
+
*/
|
|
470
482
|
fetchTemplate()
|
|
471
483
|
fetchSource()
|
|
472
484
|
fetchVueSource()
|
|
473
485
|
fetchPlaintext()
|
|
474
486
|
})
|
|
475
487
|
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
488
|
+
/**
|
|
489
|
+
* Keep the UI in sync with live config edits. Payload is the same shape
|
|
490
|
+
* as the initial `window.__MAIZZLE_CONFIG__` inject — we replace it
|
|
491
|
+
* and derive per-feature flags from there.
|
|
492
|
+
*/
|
|
479
493
|
;(import.meta as any).hot.on('maizzle:config-updated', (data: Record<string, unknown>) => {
|
|
480
494
|
;(window as any).__MAIZZLE_CONFIG__ = data
|
|
481
495
|
const wasDisabled = compatibilityDisabled.value
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_helpers.js","names":[],"sources":["../../../src/tests/render/_helpers.ts"],"sourcesContent":["import { mkdtempSync, writeFileSync, mkdirSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { tmpdir } from 'node:os'\n\nexport function createTempProject() {\n const dir = mkdtempSync(join(tmpdir(), 'maizzle-render-'))\n return dir\n}\n\nexport function writeSfc(dir: string, path: string, content: string) {\n const full = join(dir, path)\n mkdirSync(join(dir, ...path.split('/').slice(0, -1)), { recursive: true })\n writeFileSync(full, content)\n}\n"],"mappings":";;;;AAIA,SAAgB,oBAAoB;CAElC,OADY,YAAY,KAAK,
|
|
1
|
+
{"version":3,"file":"_helpers.js","names":[],"sources":["../../../src/tests/render/_helpers.ts"],"sourcesContent":["import { mkdtempSync, writeFileSync, mkdirSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { tmpdir } from 'node:os'\n\nexport function createTempProject() {\n const dir = mkdtempSync(join(tmpdir(), 'maizzle-render-'))\n return dir\n}\n\nexport function writeSfc(dir: string, path: string, content: string) {\n const full = join(dir, path)\n mkdirSync(join(dir, ...path.split('/').slice(0, -1)), { recursive: true })\n writeFileSync(full, content)\n}\n"],"mappings":";;;;AAIA,SAAgB,oBAAoB;CAElC,OADY,YAAY,KAAK,OAAO,GAAG,iBAAiB,CAC/C;AACX;AAEA,SAAgB,SAAS,KAAa,MAAc,SAAiB;CACnE,MAAM,OAAO,KAAK,KAAK,IAAI;CAC3B,UAAU,KAAK,KAAK,GAAG,KAAK,MAAM,GAAG,EAAE,MAAM,GAAG,EAAE,CAAC,GAAG,EAAE,WAAW,KAAK,CAAC;CACzE,cAAc,MAAM,OAAO;AAC7B"}
|
|
@@ -14,19 +14,29 @@ import { ChildNode } from "domhandler";
|
|
|
14
14
|
* Supports tag, class, id, and attribute selectors.
|
|
15
15
|
* Multiple selectors can be specified by comma-separating them.
|
|
16
16
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
17
|
+
* @param html HTML string to transform.
|
|
18
|
+
* @param config Attributes config (see {@link AttributesConfig}).
|
|
19
|
+
* @returns The transformed HTML string.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* import { addAttributes } from '@maizzle/framework'
|
|
23
|
+
*
|
|
24
|
+
* const out = addAttributes('<div></div>', {
|
|
20
25
|
* add: {
|
|
21
26
|
* div: { role: 'article' },
|
|
22
27
|
* '.test': { editable: true },
|
|
23
28
|
* '#header': { 'data-id': 'main' },
|
|
24
29
|
* 'div, p': { class: 'content' },
|
|
25
|
-
* }
|
|
26
|
-
* }
|
|
27
|
-
|
|
30
|
+
* },
|
|
31
|
+
* })
|
|
32
|
+
*/
|
|
33
|
+
declare function addAttributes(html: string, config?: AttributesConfig): string;
|
|
34
|
+
/**
|
|
35
|
+
* DOM-form of {@link addAttributes} used by the internal transformer pipeline.
|
|
36
|
+
* Takes a parsed DOM, returns a parsed DOM — avoids redundant
|
|
37
|
+
* serialize/parse round-trips when chained with other transformers.
|
|
28
38
|
*/
|
|
29
|
-
declare function
|
|
39
|
+
declare function addAttributesDom(dom: ChildNode[], config?: AttributesConfig): ChildNode[];
|
|
30
40
|
//#endregion
|
|
31
|
-
export { addAttributes };
|
|
41
|
+
export { addAttributes, addAttributesDom };
|
|
32
42
|
//# sourceMappingURL=addAttributes.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"addAttributes.d.ts","names":[],"sources":["../../src/transformers/addAttributes.ts"],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"addAttributes.d.ts","names":[],"sources":["../../src/transformers/addAttributes.ts"],"mappings":";;;;;;AA+CA;;;;;;;;AAAyE;AASzE;;;;;;;;;;;;;;AAA4F;;;iBAT5E,aAAA,CAAc,IAAA,UAAc,MAAA,GAAQ,gBAAqB;;;;;;iBASzD,gBAAA,CAAiB,GAAA,EAAK,SAAA,IAAa,MAAA,GAAQ,gBAAA,GAAwB,SAAA"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { parse } from "../utils/ast/parser.js";
|
|
1
2
|
import { walk } from "../utils/ast/walker.js";
|
|
3
|
+
import { serialize } from "../utils/ast/serializer.js";
|
|
2
4
|
import "../utils/ast/index.js";
|
|
3
5
|
import { defu as defu$1 } from "defu";
|
|
4
6
|
//#region src/transformers/addAttributes.ts
|
|
@@ -25,19 +27,31 @@ const DEFAULT_ATTRIBUTES = {
|
|
|
25
27
|
* Supports tag, class, id, and attribute selectors.
|
|
26
28
|
* Multiple selectors can be specified by comma-separating them.
|
|
27
29
|
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
30
|
+
* @param html HTML string to transform.
|
|
31
|
+
* @param config Attributes config (see {@link AttributesConfig}).
|
|
32
|
+
* @returns The transformed HTML string.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* import { addAttributes } from '@maizzle/framework'
|
|
36
|
+
*
|
|
37
|
+
* const out = addAttributes('<div></div>', {
|
|
31
38
|
* add: {
|
|
32
39
|
* div: { role: 'article' },
|
|
33
40
|
* '.test': { editable: true },
|
|
34
41
|
* '#header': { 'data-id': 'main' },
|
|
35
42
|
* 'div, p': { class: 'content' },
|
|
36
|
-
* }
|
|
37
|
-
* }
|
|
38
|
-
|
|
43
|
+
* },
|
|
44
|
+
* })
|
|
45
|
+
*/
|
|
46
|
+
function addAttributes(html, config = {}) {
|
|
47
|
+
return serialize(addAttributesDom(parse(html), config));
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* DOM-form of {@link addAttributes} used by the internal transformer pipeline.
|
|
51
|
+
* Takes a parsed DOM, returns a parsed DOM — avoids redundant
|
|
52
|
+
* serialize/parse round-trips when chained with other transformers.
|
|
39
53
|
*/
|
|
40
|
-
function
|
|
54
|
+
function addAttributesDom(dom, config = {}) {
|
|
41
55
|
const addConfig = config.add;
|
|
42
56
|
if (addConfig === false) return dom;
|
|
43
57
|
const attributesToAdd = defu$1(typeof addConfig === "object" ? addConfig : {}, DEFAULT_ATTRIBUTES);
|
|
@@ -99,6 +113,6 @@ function elementMatches(el, selector) {
|
|
|
99
113
|
return el.name === selector;
|
|
100
114
|
}
|
|
101
115
|
//#endregion
|
|
102
|
-
export { addAttributes };
|
|
116
|
+
export { addAttributes, addAttributesDom };
|
|
103
117
|
|
|
104
118
|
//# sourceMappingURL=addAttributes.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"addAttributes.js","names":["merge"],"sources":["../../src/transformers/addAttributes.ts"],"sourcesContent":["import { defu as merge } from 'defu'\nimport type { ChildNode, Element } from 'domhandler'\nimport { walk } from '../utils/ast/index.ts'\nimport type { AttributesConfig } from '../types/config.ts'\n\n/**\n * Default attributes to add to elements.\n */\nconst DEFAULT_ATTRIBUTES: Record<string, Record<string, string | boolean | number>> = {\n table: {\n cellpadding: 0,\n cellspacing: 0,\n role: 'none',\n },\n img: {\n alt: '',\n },\n}\n\n/**\n * Add attributes transformer.\n *\n * Automatically adds attributes to HTML elements based on CSS selectors.\n *\n * Default attributes (can be disabled by setting `attributes.add` to false):\n * - table: cellpadding=\"0\", cellspacing=\"0\", role=\"none\"\n * - img: alt=\"\"\n *\n * Supports tag, class, id, and attribute selectors.\n * Multiple selectors can be specified by comma-separating them.\n *\n *
|
|
1
|
+
{"version":3,"file":"addAttributes.js","names":["merge"],"sources":["../../src/transformers/addAttributes.ts"],"sourcesContent":["import { defu as merge } from 'defu'\nimport type { ChildNode, Element } from 'domhandler'\nimport { parse, serialize, walk } from '../utils/ast/index.ts'\nimport type { AttributesConfig } from '../types/config.ts'\n\n/**\n * Default attributes to add to elements.\n */\nconst DEFAULT_ATTRIBUTES: Record<string, Record<string, string | boolean | number>> = {\n table: {\n cellpadding: 0,\n cellspacing: 0,\n role: 'none',\n },\n img: {\n alt: '',\n },\n}\n\n/**\n * Add attributes transformer.\n *\n * Automatically adds attributes to HTML elements based on CSS selectors.\n *\n * Default attributes (can be disabled by setting `attributes.add` to false):\n * - table: cellpadding=\"0\", cellspacing=\"0\", role=\"none\"\n * - img: alt=\"\"\n *\n * Supports tag, class, id, and attribute selectors.\n * Multiple selectors can be specified by comma-separating them.\n *\n * @param html HTML string to transform.\n * @param config Attributes config (see {@link AttributesConfig}).\n * @returns The transformed HTML string.\n *\n * @example\n * import { addAttributes } from '@maizzle/framework'\n *\n * const out = addAttributes('<div></div>', {\n * add: {\n * div: { role: 'article' },\n * '.test': { editable: true },\n * '#header': { 'data-id': 'main' },\n * 'div, p': { class: 'content' },\n * },\n * })\n */\nexport function addAttributes(html: string, config: AttributesConfig = {}): string {\n return serialize(addAttributesDom(parse(html), config))\n}\n\n/**\n * DOM-form of {@link addAttributes} used by the internal transformer pipeline.\n * Takes a parsed DOM, returns a parsed DOM — avoids redundant\n * serialize/parse round-trips when chained with other transformers.\n */\nexport function addAttributesDom(dom: ChildNode[], config: AttributesConfig = {}): ChildNode[] {\n const addConfig = config.add\n\n // Disabled when explicitly set to false\n if (addConfig === false) {\n return dom\n }\n\n // Deep merge user attributes on top of defaults using defu\n const userAttributes = typeof addConfig === 'object' ? addConfig : {}\n const attributesToAdd = merge(userAttributes, DEFAULT_ATTRIBUTES) as Record<string, false | Record<string, false | string | boolean | number>>\n\n if (Object.keys(attributesToAdd).length === 0) {\n return dom\n }\n\n // Process each selector pattern\n for (const [selectorPattern, attributes] of Object.entries(attributesToAdd)) {\n // User opted out of this selector entirely (e.g. `table: false`)\n if (attributes === false) continue\n // Split by comma for multiple selectors\n const selectors = selectorPattern.split(',').map(s => s.trim())\n\n walk(dom, (node) => {\n const el = node as Element\n if (!el.name) return\n\n // Check if element matches any selector in the pattern\n const matches = selectors.some(selector => elementMatches(el, selector))\n\n if (matches) {\n // Initialize attribs if needed\n if (!el.attribs) {\n el.attribs = {}\n }\n\n for (const [attrName, attrValue] of Object.entries(attributes)) {\n // User opted out of this specific attribute (e.g. `role: false`)\n if (attrValue === false) continue\n // Special handling for class - merge instead of replace\n if (attrName === 'class' && el.attribs.class) {\n const existingClasses = el.attribs.class.split(/\\s+/).filter(Boolean)\n const newClasses = String(attrValue).split(/\\s+/).filter(Boolean)\n const mergedClasses = [...new Set([...existingClasses, ...newClasses])]\n if (mergedClasses.join(' ') !== el.attribs.class) {\n el.attribs.class = mergedClasses.join(' ')\n }\n } else {\n // Only add attribute if not already present\n if (!(attrName in el.attribs)) {\n el.attribs[attrName] = String(attrValue)\n }\n }\n }\n }\n })\n }\n\n return dom\n}\n\n/**\n * Check if an element matches a CSS selector.\n * Supports: tag, .class, #id, [attribute], [attribute=value]\n */\nfunction elementMatches(el: Element, selector: string): boolean {\n // Remove whitespace\n selector = selector.trim()\n\n // Check for attribute selector [attr] or [attr=value]\n const attrMatch = selector.match(/^\\[([^\\]=]+)(?:=([^\\]]*))?\\]$/)\n if (attrMatch) {\n const [, attrName, attrValue] = attrMatch\n if (attrValue === undefined) {\n // Just checking if attribute exists\n return attrName in (el.attribs || {})\n } else {\n // Check if attribute has specific value\n return el.attribs?.[attrName] === attrValue\n }\n }\n\n // Check for class selector .class\n if (selector.startsWith('.')) {\n const className = selector.slice(1)\n const classes = el.attribs?.class?.split(/\\s+/) || []\n return classes.includes(className)\n }\n\n // Check for id selector #id\n if (selector.startsWith('#')) {\n const id = selector.slice(1)\n return el.attribs?.id === id\n }\n\n // Check for tag selector (possibly with attribute)\n // Split tag from attribute if present, e.g., \"div[role=alert]\"\n const tagAttrMatch = selector.match(/^([a-z][a-z0-9]*)\\[([^\\]]+)\\]$/i)\n if (tagAttrMatch) {\n const [, tagName, attrPart] = tagAttrMatch\n if (el.name !== tagName) return false\n\n // Parse attribute part: could be \"attr\" or \"attr=value\"\n const attrEqMatch = attrPart.match(/^([^=]+)(?:=(.*))?$/)\n if (attrEqMatch) {\n const [, attrName, attrValue] = attrEqMatch\n if (attrValue === undefined) {\n return attrName in (el.attribs || {})\n } else {\n return el.attribs?.[attrName] === attrValue\n }\n }\n return false\n }\n\n // Simple tag selector\n return el.name === selector\n}\n"],"mappings":";;;;;;;;;AAQA,MAAM,qBAAgF;CACpF,OAAO;EACL,aAAa;EACb,aAAa;EACb,MAAM;CACR;CACA,KAAK,EACH,KAAK,GACP;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BA,SAAgB,cAAc,MAAc,SAA2B,CAAC,GAAW;CACjF,OAAO,UAAU,iBAAiB,MAAM,IAAI,GAAG,MAAM,CAAC;AACxD;;;;;;AAOA,SAAgB,iBAAiB,KAAkB,SAA2B,CAAC,GAAgB;CAC7F,MAAM,YAAY,OAAO;CAGzB,IAAI,cAAc,OAChB,OAAO;CAKT,MAAM,kBAAkBA,OADD,OAAO,cAAc,WAAW,YAAY,CAAC,GACtB,kBAAkB;CAEhE,IAAI,OAAO,KAAK,eAAe,EAAE,WAAW,GAC1C,OAAO;CAIT,KAAK,MAAM,CAAC,iBAAiB,eAAe,OAAO,QAAQ,eAAe,GAAG;EAE3E,IAAI,eAAe,OAAO;EAE1B,MAAM,YAAY,gBAAgB,MAAM,GAAG,EAAE,KAAI,MAAK,EAAE,KAAK,CAAC;EAE9D,KAAK,MAAM,SAAS;GAClB,MAAM,KAAK;GACX,IAAI,CAAC,GAAG,MAAM;GAKd,IAFgB,UAAU,MAAK,aAAY,eAAe,IAAI,QAAQ,CAE5D,GAAG;IAEX,IAAI,CAAC,GAAG,SACN,GAAG,UAAU,CAAC;IAGhB,KAAK,MAAM,CAAC,UAAU,cAAc,OAAO,QAAQ,UAAU,GAAG;KAE9D,IAAI,cAAc,OAAO;KAEzB,IAAI,aAAa,WAAW,GAAG,QAAQ,OAAO;MAC5C,MAAM,kBAAkB,GAAG,QAAQ,MAAM,MAAM,KAAK,EAAE,OAAO,OAAO;MACpE,MAAM,aAAa,OAAO,SAAS,EAAE,MAAM,KAAK,EAAE,OAAO,OAAO;MAChE,MAAM,gBAAgB,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,iBAAiB,GAAG,UAAU,CAAC,CAAC;MACtE,IAAI,cAAc,KAAK,GAAG,MAAM,GAAG,QAAQ,OACzC,GAAG,QAAQ,QAAQ,cAAc,KAAK,GAAG;KAE7C,OAEE,IAAI,EAAE,YAAY,GAAG,UACnB,GAAG,QAAQ,YAAY,OAAO,SAAS;IAG7C;GACF;EACF,CAAC;CACH;CAEA,OAAO;AACT;;;;;AAMA,SAAS,eAAe,IAAa,UAA2B;CAE9D,WAAW,SAAS,KAAK;CAGzB,MAAM,YAAY,SAAS,MAAM,+BAA+B;CAChE,IAAI,WAAW;EACb,MAAM,GAAG,UAAU,aAAa;EAChC,IAAI,cAAc,KAAA,GAEhB,OAAO,aAAa,GAAG,WAAW,CAAC;OAGnC,OAAO,GAAG,UAAU,cAAc;CAEtC;CAGA,IAAI,SAAS,WAAW,GAAG,GAAG;EAC5B,MAAM,YAAY,SAAS,MAAM,CAAC;EAElC,QADgB,GAAG,SAAS,OAAO,MAAM,KAAK,KAAK,CAAC,GACrC,SAAS,SAAS;CACnC;CAGA,IAAI,SAAS,WAAW,GAAG,GAAG;EAC5B,MAAM,KAAK,SAAS,MAAM,CAAC;EAC3B,OAAO,GAAG,SAAS,OAAO;CAC5B;CAIA,MAAM,eAAe,SAAS,MAAM,iCAAiC;CACrE,IAAI,cAAc;EAChB,MAAM,GAAG,SAAS,YAAY;EAC9B,IAAI,GAAG,SAAS,SAAS,OAAO;EAGhC,MAAM,cAAc,SAAS,MAAM,qBAAqB;EACxD,IAAI,aAAa;GACf,MAAM,GAAG,UAAU,aAAa;GAChC,IAAI,cAAc,KAAA,GAChB,OAAO,aAAa,GAAG,WAAW,CAAC;QAEnC,OAAO,GAAG,UAAU,cAAc;EAEtC;EACA,OAAO;CACT;CAGA,OAAO,GAAG,SAAS;AACrB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attributeToStyle.d.ts","names":[],"sources":["../../src/transformers/attributeToStyle.ts"],"mappings":";;;;;AAiCA
|
|
1
|
+
{"version":3,"file":"attributeToStyle.d.ts","names":[],"sources":["../../src/transformers/attributeToStyle.ts"],"mappings":";;;;;AAiCA;;;;AAAoF;AASpF;;;;;;;;;AAAuG;;;;;;;;;iBATvF,gBAAA,CAAiB,IAAA,UAAc,UAAqC;;;;;;iBASpE,mBAAA,CAAoB,GAAA,EAAK,SAAA,IAAa,UAAA,wBAAwC,SAAS"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attributeToStyle.js","names":[],"sources":["../../src/transformers/attributeToStyle.ts"],"sourcesContent":["import type { ChildNode, Element } from 'domhandler'\nimport { parse, serialize, walk } from '../utils/ast/index.ts'\n\n/**\n * Default list of attributes that can be converted to inline styles.\n */\nconst DEFAULT_ATTRIBUTES = ['width', 'height', 'bgcolor', 'background', 'align', 'valign']\n\n/**\n * Convert HTML attributes to inline CSS styles.\n *\n * Supported attributes:\n * - `width`: `width: ${value}${unit}` (px and %, defaults to px)\n * - `height`: `height: ${value}${unit}` (px and %, defaults to px)\n * - `bgcolor`: `background-color: ${value}`\n * - `background`: `background-image: url('${value}')`\n * - `align`: on `<table>`, `left`/`right` become `float`, `center` becomes\n * `margin-left/right: auto`; on other elements, becomes `text-align`\n * - `valign`: `vertical-align: ${value}`\n *\n * @param html HTML string to transform.\n * @param attributes `true` to process the default set, an array to restrict\n * to specific attribute names, `false` to disable.\n * @returns The transformed HTML string.\n *\n * @example\n * import { attributeToStyle } from '@maizzle/framework'\n *\n * const out = attributeToStyle('<table align=\"center\"><tr><td bgcolor=\"#f00\">x</td></tr></table>')\n *\n * // Restrict to specific attributes:\n * const limited = attributeToStyle(html, ['width', 'height'])\n */\nexport function attributeToStyle(html: string, attributes: boolean | string[] = true): string {\n return serialize(attributeToStyleDom(parse(html), attributes))\n}\n\n/**\n * DOM-form of {@link attributeToStyle} used by the internal transformer\n * pipeline. Takes a parsed DOM, returns a parsed DOM — avoids redundant\n * serialize/parse round-trips when chained with other transformers.\n */\nexport function attributeToStyleDom(dom: ChildNode[], attributes: boolean | string[] = true): ChildNode[] {\n if (!attributes) return dom\n\n const attributesToProcess: string[] = attributes === true\n ? DEFAULT_ATTRIBUTES\n : Array.isArray(attributes)\n ? attributes\n : []\n\n if (attributesToProcess.length === 0) return dom\n\n walk(dom, (node) => {\n const el = node as Element\n\n if (!('attribs' in el) || !el.attribs) {\n return\n }\n\n const styles: string[] = []\n\n for (const attr of attributesToProcess) {\n const value = el.attribs[attr]\n if (!value) continue\n\n const styleValue = convertAttributeToStyle(el.name, attr, value)\n if (styleValue) {\n styles.push(styleValue)\n }\n }\n\n // Append new styles to existing style attribute\n if (styles.length > 0) {\n const existingStyle = el.attribs.style || ''\n const separator = existingStyle ? '; ' : ''\n el.attribs.style = existingStyle + separator + styles.join('; ')\n }\n })\n\n return dom\n}\n\n/**\n * Convert a single HTML attribute value to a CSS style declaration.\n */\nfunction convertAttributeToStyle(\n tagName: string,\n attr: string,\n value: string,\n): string | null {\n switch (attr) {\n case 'width':\n case 'height': {\n // Support px and % values, default to px if no unit\n const normalizedValue = /^\\d+$/.test(value) ? `${value}px` : value\n return `${attr}: ${normalizedValue}`\n }\n\n case 'bgcolor':\n return `background-color: ${value}`\n\n case 'background':\n return `background-image: url('${value}')`\n\n case 'align': {\n // On table elements: left/right -> float, center -> margin auto\n if (tagName === 'table') {\n if (value === 'left' || value === 'right') {\n return `float: ${value}`\n }\n if (value === 'center') {\n return 'margin-left: auto; margin-right: auto'\n }\n }\n // On other elements: text-align\n return `text-align: ${value}`\n }\n\n case 'valign':\n return `vertical-align: ${value}`\n\n default:\n return null\n }\n}\n"],"mappings":";;;;;;;;AAMA,MAAM,qBAAqB;CAAC;CAAS;CAAU;CAAW;CAAc;CAAS;
|
|
1
|
+
{"version":3,"file":"attributeToStyle.js","names":[],"sources":["../../src/transformers/attributeToStyle.ts"],"sourcesContent":["import type { ChildNode, Element } from 'domhandler'\nimport { parse, serialize, walk } from '../utils/ast/index.ts'\n\n/**\n * Default list of attributes that can be converted to inline styles.\n */\nconst DEFAULT_ATTRIBUTES = ['width', 'height', 'bgcolor', 'background', 'align', 'valign']\n\n/**\n * Convert HTML attributes to inline CSS styles.\n *\n * Supported attributes:\n * - `width`: `width: ${value}${unit}` (px and %, defaults to px)\n * - `height`: `height: ${value}${unit}` (px and %, defaults to px)\n * - `bgcolor`: `background-color: ${value}`\n * - `background`: `background-image: url('${value}')`\n * - `align`: on `<table>`, `left`/`right` become `float`, `center` becomes\n * `margin-left/right: auto`; on other elements, becomes `text-align`\n * - `valign`: `vertical-align: ${value}`\n *\n * @param html HTML string to transform.\n * @param attributes `true` to process the default set, an array to restrict\n * to specific attribute names, `false` to disable.\n * @returns The transformed HTML string.\n *\n * @example\n * import { attributeToStyle } from '@maizzle/framework'\n *\n * const out = attributeToStyle('<table align=\"center\"><tr><td bgcolor=\"#f00\">x</td></tr></table>')\n *\n * // Restrict to specific attributes:\n * const limited = attributeToStyle(html, ['width', 'height'])\n */\nexport function attributeToStyle(html: string, attributes: boolean | string[] = true): string {\n return serialize(attributeToStyleDom(parse(html), attributes))\n}\n\n/**\n * DOM-form of {@link attributeToStyle} used by the internal transformer\n * pipeline. Takes a parsed DOM, returns a parsed DOM — avoids redundant\n * serialize/parse round-trips when chained with other transformers.\n */\nexport function attributeToStyleDom(dom: ChildNode[], attributes: boolean | string[] = true): ChildNode[] {\n if (!attributes) return dom\n\n const attributesToProcess: string[] = attributes === true\n ? DEFAULT_ATTRIBUTES\n : Array.isArray(attributes)\n ? attributes\n : []\n\n if (attributesToProcess.length === 0) return dom\n\n walk(dom, (node) => {\n const el = node as Element\n\n if (!('attribs' in el) || !el.attribs) {\n return\n }\n\n const styles: string[] = []\n\n for (const attr of attributesToProcess) {\n const value = el.attribs[attr]\n if (!value) continue\n\n const styleValue = convertAttributeToStyle(el.name, attr, value)\n if (styleValue) {\n styles.push(styleValue)\n }\n }\n\n // Append new styles to existing style attribute\n if (styles.length > 0) {\n const existingStyle = el.attribs.style || ''\n const separator = existingStyle ? '; ' : ''\n el.attribs.style = existingStyle + separator + styles.join('; ')\n }\n })\n\n return dom\n}\n\n/**\n * Convert a single HTML attribute value to a CSS style declaration.\n */\nfunction convertAttributeToStyle(\n tagName: string,\n attr: string,\n value: string,\n): string | null {\n switch (attr) {\n case 'width':\n case 'height': {\n // Support px and % values, default to px if no unit\n const normalizedValue = /^\\d+$/.test(value) ? `${value}px` : value\n return `${attr}: ${normalizedValue}`\n }\n\n case 'bgcolor':\n return `background-color: ${value}`\n\n case 'background':\n return `background-image: url('${value}')`\n\n case 'align': {\n // On table elements: left/right -> float, center -> margin auto\n if (tagName === 'table') {\n if (value === 'left' || value === 'right') {\n return `float: ${value}`\n }\n if (value === 'center') {\n return 'margin-left: auto; margin-right: auto'\n }\n }\n // On other elements: text-align\n return `text-align: ${value}`\n }\n\n case 'valign':\n return `vertical-align: ${value}`\n\n default:\n return null\n }\n}\n"],"mappings":";;;;;;;;AAMA,MAAM,qBAAqB;CAAC;CAAS;CAAU;CAAW;CAAc;CAAS;AAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BzF,SAAgB,iBAAiB,MAAc,aAAiC,MAAc;CAC5F,OAAO,UAAU,oBAAoB,MAAM,IAAI,GAAG,UAAU,CAAC;AAC/D;;;;;;AAOA,SAAgB,oBAAoB,KAAkB,aAAiC,MAAmB;CACxG,IAAI,CAAC,YAAY,OAAO;CAExB,MAAM,sBAAgC,eAAe,OACjD,qBACA,MAAM,QAAQ,UAAU,IACtB,aACA,CAAC;CAEP,IAAI,oBAAoB,WAAW,GAAG,OAAO;CAE7C,KAAK,MAAM,SAAS;EAClB,MAAM,KAAK;EAEX,IAAI,EAAE,aAAa,OAAO,CAAC,GAAG,SAC5B;EAGF,MAAM,SAAmB,CAAC;EAE1B,KAAK,MAAM,QAAQ,qBAAqB;GACtC,MAAM,QAAQ,GAAG,QAAQ;GACzB,IAAI,CAAC,OAAO;GAEZ,MAAM,aAAa,wBAAwB,GAAG,MAAM,MAAM,KAAK;GAC/D,IAAI,YACF,OAAO,KAAK,UAAU;EAE1B;EAGA,IAAI,OAAO,SAAS,GAAG;GACrB,MAAM,gBAAgB,GAAG,QAAQ,SAAS;GAC1C,MAAM,YAAY,gBAAgB,OAAO;GACzC,GAAG,QAAQ,QAAQ,gBAAgB,YAAY,OAAO,KAAK,IAAI;EACjE;CACF,CAAC;CAED,OAAO;AACT;;;;AAKA,SAAS,wBACP,SACA,MACA,OACe;CACf,QAAQ,MAAR;EACE,KAAK;EACL,KAAK,UAGH,OAAO,GAAG,KAAK,IADS,QAAQ,KAAK,KAAK,IAAI,GAAG,MAAM,MAAM;EAI/D,KAAK,WACH,OAAO,qBAAqB;EAE9B,KAAK,cACH,OAAO,0BAA0B,MAAM;EAEzC,KAAK;GAEH,IAAI,YAAY,SAAS;IACvB,IAAI,UAAU,UAAU,UAAU,SAChC,OAAO,UAAU;IAEnB,IAAI,UAAU,UACZ,OAAO;GAEX;GAEA,OAAO,eAAe;EAGxB,KAAK,UACH,OAAO,mBAAmB;EAE5B,SACE,OAAO;CACX;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base.d.ts","names":[],"sources":["../../src/transformers/base.ts"],"mappings":";;;;;AAUA;UAAiB,cAAA;;EAEf,GAAA;EAUkB;;;;;;;;;EAAlB,IAAA,cAAkB,MAAA,SAAe,MAAA;EAWjC
|
|
1
|
+
{"version":3,"file":"base.d.ts","names":[],"sources":["../../src/transformers/base.ts"],"mappings":";;;;;AAUA;UAAiB,cAAA;;EAEf,GAAA;EAUkB;;;;;;;;;EAAlB,IAAA,cAAkB,MAAA,SAAe,MAAA;EAWjC;;;AAMS;EAZT,UAAA,GAAa,MAAA;EAuIK;;;;;EAjIlB,QAAA;EAiIiE;AAAA;AASnE;;;EApIE,SAAA;AAAA;;;;;;;;;;AAoI+G;;;;;;;;;;;;;;;iBATjG,IAAA,CAAK,IAAA,UAAc,OAAA,WAAkB,cAAc;;;;;;iBASnD,OAAA,CAAQ,GAAA,EAAK,SAAA,IAAa,OAAA,WAAkB,cAAA,8BAA4C,SAAA"}
|
|
@@ -146,6 +146,10 @@ function baseDom(dom, options) {
|
|
|
146
146
|
}
|
|
147
147
|
for (const [attr, url] of Object.entries(attributes)) if (el.attribs[attr] && !isAbsoluteUrl(el.attribs[attr])) el.attribs[attr] = url + el.attribs[attr];
|
|
148
148
|
});
|
|
149
|
+
/**
|
|
150
|
+
* VML and MSO comment rewrites require operating on serialized HTML
|
|
151
|
+
* (HTML comments are not represented as traversable DOM nodes).
|
|
152
|
+
*/
|
|
149
153
|
const serialized = serialize(dom);
|
|
150
154
|
const rewritten = rewriteMsoComments(rewriteVMLs(serialized, baseUrl), baseUrl);
|
|
151
155
|
if (rewritten !== serialized) return parse(rewritten);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base.js","names":[],"sources":["../../src/transformers/base.ts"],"sourcesContent":["import postcss from 'postcss'\nimport safeParser from 'postcss-safe-parser'\nimport valueParser from 'postcss-value-parser'\nimport { walk, serialize, parse } from '../utils/ast/index.ts'\nimport { isAbsoluteUrl, defaultTags, processSrcset } from '../utils/url.ts'\nimport type { ChildNode, Element } from 'domhandler'\n\n/**\n * Options for the `base` transformer.\n */\nexport interface BaseUrlOptions {\n /** Base URL to prepend to relative links. */\n url: string\n /**\n * Tag/attribute scope for prepending. Omit to use the built-in defaults\n * (`a[href]`, `img[src]`, `link[href]`, etc.).\n *\n * - Array of tag names — restrict the built-in defaults to these tags.\n * - Object — explicit per-tag attribute map. Each attribute value is\n * `true` (use the base url) or a string (use that string as the url\n * for this attribute only).\n */\n tags?: string[] | Record<string, Record<string, string | boolean>>\n /**\n * Custom attributes to rewrite globally, regardless of tag. Each key\n * is the attribute name; the value is the URL to prepend.\n */\n attributes?: Record<string, string>\n /**\n * Rewrite `url()` references inside `<style>` tag contents.\n *\n * @default true\n */\n styleTag?: boolean\n /**\n * Rewrite `url()` references inside inline `style` attributes.\n *\n * @default true\n */\n inlineCss?: boolean\n}\n\nconst sourceAttributes = ['src', 'href', 'srcset', 'poster', 'background', 'data']\n\n/**\n * Convert the shared `defaultTags` (tag → string[]) into the richer format\n * the transformer needs (tag → Record<attr, true>).\n */\nconst defaultTagConfig: Record<string, Record<string, string | boolean>> = Object.fromEntries(\n Object.entries(defaultTags).map(([tag, attrs]) => [\n tag,\n Object.fromEntries(attrs.map(attr => [attr, true])),\n ]),\n)\n\nconst postcssBaseUrl: postcss.PluginCreator<{ url: string }> = (opts) => {\n return {\n postcssPlugin: 'postcss-base-url',\n Declaration(decl) {\n if (!decl.value.includes('url(')) return\n\n const parsed = valueParser(decl.value)\n let changed = false\n\n parsed.walk(node => {\n if (node.type !== 'function' || node.value !== 'url') return\n\n const urlNode = node.nodes[0]\n if (!urlNode) return\n\n if (isAbsoluteUrl(urlNode.value)) return\n\n urlNode.value = opts!.url + urlNode.value\n changed = true\n })\n\n if (changed) {\n decl.value = parsed.toString()\n }\n }\n }\n}\npostcssBaseUrl.postcss = true\n\nfunction processCss(css: string, url: string): string {\n const { css: result } = postcss([postcssBaseUrl({ url })]).process(css, { parser: safeParser, from: undefined })\n return result\n}\n\nfunction processInlineStyle(style: string, url: string): string {\n try {\n const { css } = postcss([postcssBaseUrl({ url })]).process(`a{${style}}`, { parser: safeParser, from: undefined })\n const match = css.match(/a\\s*\\{\\s*([\\s\\S]*?)\\s*\\}/)\n return match?.[1]?.trim() ?? style\n } catch {\n return style\n }\n}\n\nfunction resolveOptions(input: string | BaseUrlOptions | undefined | null | false): BaseUrlOptions | undefined {\n if (!input) return undefined\n if (typeof input === 'string') {\n return { url: input, styleTag: true, inlineCss: true }\n }\n if (typeof input === 'object' && 'url' in input) {\n return {\n url: input.url ?? '',\n tags: input.tags,\n attributes: input.attributes,\n styleTag: input.styleTag ?? true,\n inlineCss: input.inlineCss ?? true,\n }\n }\n return undefined\n}\n\nfunction getTagConfig(\n tagName: string,\n options: BaseUrlOptions\n): Record<string, string | boolean> | undefined {\n const { tags } = options\n\n if (tags === undefined) {\n return defaultTagConfig[tagName]\n }\n\n if (Array.isArray(tags)) {\n if (!tags.includes(tagName)) return undefined\n return defaultTagConfig[tagName]\n }\n\n if (typeof tags === 'object') {\n return tags[tagName]\n }\n\n return undefined\n}\n\n/**\n * Prepend a base URL to relative `src`/`href`/etc. references throughout\n * the document, including inside `<style>` blocks, inline `style`\n * attributes, MSO conditional comments, and VML tags.\n *\n * @param html HTML string to transform.\n * @param options Either a base URL string, or a {@link BaseUrlOptions} object\n * for finer control.\n * @returns The transformed HTML string.\n *\n * @example\n * import { base } from '@maizzle/framework'\n *\n * // Just a URL — applied with the built-in tag/attribute defaults.\n * const out = base('<img src=\"/a.png\">', 'https://cdn.example.com/')\n *\n * // Restrict to specific tags, opt out of style rewriting:\n * const limited = base(html, {\n * url: 'https://cdn.example.com/',\n * tags: ['img'],\n * styleTag: false,\n * inlineCss: false,\n * })\n */\nexport function base(html: string, options: string | BaseUrlOptions): string {\n return serialize(baseDom(parse(html), options))\n}\n\n/**\n * DOM-form of {@link base} used by the internal transformer pipeline.\n * Takes a parsed DOM, returns a parsed DOM — avoids redundant\n * serialize/parse round-trips when chained with other transformers.\n */\nexport function baseDom(dom: ChildNode[], options: string | BaseUrlOptions | undefined | null | false): ChildNode[] {\n const resolved = resolveOptions(options)\n if (!resolved || !resolved.url) return dom\n\n const { url: baseUrl, styleTag = true, inlineCss = true, attributes = {} } = resolved\n\n walk(dom, (node) => {\n const el = node as Element\n if (!el.name) return\n\n // Process <style> tag content with PostCSS\n if (el.name === 'style' && styleTag && el.children) {\n for (const child of el.children) {\n if (child.type === 'text') {\n const textNode = child as unknown as { data: string }\n const processed = processCss(textNode.data, baseUrl)\n if (processed !== textNode.data) {\n textNode.data = processed\n }\n }\n }\n return\n }\n\n if (!el.attribs) return\n\n // Process tag-specific attributes (respects tags filter)\n const tagConfig = getTagConfig(el.name, resolved)\n\n if (tagConfig || resolved.tags === undefined) {\n for (const [attr, value] of Object.entries(el.attribs)) {\n if (!value) continue\n\n const attrConfig = tagConfig?.[attr]\n if (!attrConfig && attr !== 'style') continue\n\n if (attr === 'srcset' && (attrConfig === true || typeof attrConfig === 'string')) {\n const newSrcset = processSrcset(value, typeof attrConfig === 'string' ? attrConfig : baseUrl)\n if (newSrcset !== value) {\n el.attribs.srcset = newSrcset\n }\n } else if (attr === 'style' && inlineCss && value.includes('url(')) {\n const newStyle = processInlineStyle(value, baseUrl)\n if (newStyle !== value) {\n el.attribs.style = newStyle\n }\n } else if (attrConfig === true && !isAbsoluteUrl(value)) {\n el.attribs[attr] = baseUrl + value\n } else if (typeof attrConfig === 'string' && !isAbsoluteUrl(value)) {\n el.attribs[attr] = attrConfig + value\n }\n }\n }\n\n // Process custom attributes (not affected by tags filter)\n for (const [attr, url] of Object.entries(attributes)) {\n if (el.attribs[attr] && !isAbsoluteUrl(el.attribs[attr])) {\n el.attribs[attr] = url + el.attribs[attr]\n }\n }\n })\n\n // VML and MSO comment rewrites require operating on serialized HTML\n // (HTML comments are not represented as traversable DOM nodes)\n const serialized = serialize(dom)\n const rewritten = rewriteMsoComments(rewriteVMLs(serialized, baseUrl), baseUrl)\n\n // Only re-parse if the regex passes actually changed anything\n if (rewritten !== serialized) {\n return parse(rewritten)\n }\n\n return dom\n}\n\nfunction rewriteVMLs(html: string, url: string): string {\n html = html.replace(/<v:image[^>]+src=\"?([^\"\\s]+)\"/gi, (match, src) => {\n if (isAbsoluteUrl(src)) return match\n return match.replace(src, url + src)\n })\n\n html = html.replace(/<v:fill[^>]+src=\"?([^\"\\s]+)\"/gi, (match, src) => {\n if (isAbsoluteUrl(src)) return match\n return match.replace(src, url + src)\n })\n\n return html\n}\n\nfunction rewriteMsoComments(html: string, url: string): string {\n return html.replace(/<!--\\[if [^\\]]+\\]>[\\s\\S]*?<!\\[endif\\]-->/g, (msoBlock) => {\n let result = msoBlock\n\n for (const attr of sourceAttributes) {\n const attrRegex = new RegExp(`\\\\b${attr}=\"([^\"]+)\"`, 'gi')\n result = result.replace(attrRegex, (match, value) => {\n if (isAbsoluteUrl(value)) return match\n\n if (attr === 'srcset') {\n return `srcset=\"${processSrcset(value, url)}\"`\n }\n\n return `${attr}=\"${url}${value}\"`\n })\n }\n\n // Use PostCSS for style attribute url() rewriting inside MSO comments\n result = result.replace(/style=\"([^\"]+)\"/gi, (match, style) => {\n if (!style.includes('url(')) return match\n const processed = processInlineStyle(style, url)\n return `style=\"${processed}\"`\n })\n\n return result\n })\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"base.js","names":[],"sources":["../../src/transformers/base.ts"],"sourcesContent":["import postcss from 'postcss'\nimport safeParser from 'postcss-safe-parser'\nimport valueParser from 'postcss-value-parser'\nimport { walk, serialize, parse } from '../utils/ast/index.ts'\nimport { isAbsoluteUrl, defaultTags, processSrcset } from '../utils/url.ts'\nimport type { ChildNode, Element } from 'domhandler'\n\n/**\n * Options for the `base` transformer.\n */\nexport interface BaseUrlOptions {\n /** Base URL to prepend to relative links. */\n url: string\n /**\n * Tag/attribute scope for prepending. Omit to use the built-in defaults\n * (`a[href]`, `img[src]`, `link[href]`, etc.).\n *\n * - Array of tag names — restrict the built-in defaults to these tags.\n * - Object — explicit per-tag attribute map. Each attribute value is\n * `true` (use the base url) or a string (use that string as the url\n * for this attribute only).\n */\n tags?: string[] | Record<string, Record<string, string | boolean>>\n /**\n * Custom attributes to rewrite globally, regardless of tag. Each key\n * is the attribute name; the value is the URL to prepend.\n */\n attributes?: Record<string, string>\n /**\n * Rewrite `url()` references inside `<style>` tag contents.\n *\n * @default true\n */\n styleTag?: boolean\n /**\n * Rewrite `url()` references inside inline `style` attributes.\n *\n * @default true\n */\n inlineCss?: boolean\n}\n\nconst sourceAttributes = ['src', 'href', 'srcset', 'poster', 'background', 'data']\n\n/**\n * Convert the shared `defaultTags` (tag → string[]) into the richer format\n * the transformer needs (tag → Record<attr, true>).\n */\nconst defaultTagConfig: Record<string, Record<string, string | boolean>> = Object.fromEntries(\n Object.entries(defaultTags).map(([tag, attrs]) => [\n tag,\n Object.fromEntries(attrs.map(attr => [attr, true])),\n ]),\n)\n\nconst postcssBaseUrl: postcss.PluginCreator<{ url: string }> = (opts) => {\n return {\n postcssPlugin: 'postcss-base-url',\n Declaration(decl) {\n if (!decl.value.includes('url(')) return\n\n const parsed = valueParser(decl.value)\n let changed = false\n\n parsed.walk(node => {\n if (node.type !== 'function' || node.value !== 'url') return\n\n const urlNode = node.nodes[0]\n if (!urlNode) return\n\n if (isAbsoluteUrl(urlNode.value)) return\n\n urlNode.value = opts!.url + urlNode.value\n changed = true\n })\n\n if (changed) {\n decl.value = parsed.toString()\n }\n }\n }\n}\npostcssBaseUrl.postcss = true\n\nfunction processCss(css: string, url: string): string {\n const { css: result } = postcss([postcssBaseUrl({ url })]).process(css, { parser: safeParser, from: undefined })\n return result\n}\n\nfunction processInlineStyle(style: string, url: string): string {\n try {\n const { css } = postcss([postcssBaseUrl({ url })]).process(`a{${style}}`, { parser: safeParser, from: undefined })\n const match = css.match(/a\\s*\\{\\s*([\\s\\S]*?)\\s*\\}/)\n return match?.[1]?.trim() ?? style\n } catch {\n return style\n }\n}\n\nfunction resolveOptions(input: string | BaseUrlOptions | undefined | null | false): BaseUrlOptions | undefined {\n if (!input) return undefined\n if (typeof input === 'string') {\n return { url: input, styleTag: true, inlineCss: true }\n }\n if (typeof input === 'object' && 'url' in input) {\n return {\n url: input.url ?? '',\n tags: input.tags,\n attributes: input.attributes,\n styleTag: input.styleTag ?? true,\n inlineCss: input.inlineCss ?? true,\n }\n }\n return undefined\n}\n\nfunction getTagConfig(\n tagName: string,\n options: BaseUrlOptions\n): Record<string, string | boolean> | undefined {\n const { tags } = options\n\n if (tags === undefined) {\n return defaultTagConfig[tagName]\n }\n\n if (Array.isArray(tags)) {\n if (!tags.includes(tagName)) return undefined\n return defaultTagConfig[tagName]\n }\n\n if (typeof tags === 'object') {\n return tags[tagName]\n }\n\n return undefined\n}\n\n/**\n * Prepend a base URL to relative `src`/`href`/etc. references throughout\n * the document, including inside `<style>` blocks, inline `style`\n * attributes, MSO conditional comments, and VML tags.\n *\n * @param html HTML string to transform.\n * @param options Either a base URL string, or a {@link BaseUrlOptions} object\n * for finer control.\n * @returns The transformed HTML string.\n *\n * @example\n * import { base } from '@maizzle/framework'\n *\n * // Just a URL — applied with the built-in tag/attribute defaults.\n * const out = base('<img src=\"/a.png\">', 'https://cdn.example.com/')\n *\n * // Restrict to specific tags, opt out of style rewriting:\n * const limited = base(html, {\n * url: 'https://cdn.example.com/',\n * tags: ['img'],\n * styleTag: false,\n * inlineCss: false,\n * })\n */\nexport function base(html: string, options: string | BaseUrlOptions): string {\n return serialize(baseDom(parse(html), options))\n}\n\n/**\n * DOM-form of {@link base} used by the internal transformer pipeline.\n * Takes a parsed DOM, returns a parsed DOM — avoids redundant\n * serialize/parse round-trips when chained with other transformers.\n */\nexport function baseDom(dom: ChildNode[], options: string | BaseUrlOptions | undefined | null | false): ChildNode[] {\n const resolved = resolveOptions(options)\n if (!resolved || !resolved.url) return dom\n\n const { url: baseUrl, styleTag = true, inlineCss = true, attributes = {} } = resolved\n\n walk(dom, (node) => {\n const el = node as Element\n if (!el.name) return\n\n // Process <style> tag content with PostCSS\n if (el.name === 'style' && styleTag && el.children) {\n for (const child of el.children) {\n if (child.type === 'text') {\n const textNode = child as unknown as { data: string }\n const processed = processCss(textNode.data, baseUrl)\n if (processed !== textNode.data) {\n textNode.data = processed\n }\n }\n }\n return\n }\n\n if (!el.attribs) return\n\n // Process tag-specific attributes (respects tags filter)\n const tagConfig = getTagConfig(el.name, resolved)\n\n if (tagConfig || resolved.tags === undefined) {\n for (const [attr, value] of Object.entries(el.attribs)) {\n if (!value) continue\n\n const attrConfig = tagConfig?.[attr]\n if (!attrConfig && attr !== 'style') continue\n\n if (attr === 'srcset' && (attrConfig === true || typeof attrConfig === 'string')) {\n const newSrcset = processSrcset(value, typeof attrConfig === 'string' ? attrConfig : baseUrl)\n if (newSrcset !== value) {\n el.attribs.srcset = newSrcset\n }\n } else if (attr === 'style' && inlineCss && value.includes('url(')) {\n const newStyle = processInlineStyle(value, baseUrl)\n if (newStyle !== value) {\n el.attribs.style = newStyle\n }\n } else if (attrConfig === true && !isAbsoluteUrl(value)) {\n el.attribs[attr] = baseUrl + value\n } else if (typeof attrConfig === 'string' && !isAbsoluteUrl(value)) {\n el.attribs[attr] = attrConfig + value\n }\n }\n }\n\n // Process custom attributes (not affected by tags filter)\n for (const [attr, url] of Object.entries(attributes)) {\n if (el.attribs[attr] && !isAbsoluteUrl(el.attribs[attr])) {\n el.attribs[attr] = url + el.attribs[attr]\n }\n }\n })\n\n /**\n * VML and MSO comment rewrites require operating on serialized HTML\n * (HTML comments are not represented as traversable DOM nodes).\n */\n const serialized = serialize(dom)\n const rewritten = rewriteMsoComments(rewriteVMLs(serialized, baseUrl), baseUrl)\n\n // Only re-parse if the regex passes actually changed anything\n if (rewritten !== serialized) {\n return parse(rewritten)\n }\n\n return dom\n}\n\nfunction rewriteVMLs(html: string, url: string): string {\n html = html.replace(/<v:image[^>]+src=\"?([^\"\\s]+)\"/gi, (match, src) => {\n if (isAbsoluteUrl(src)) return match\n return match.replace(src, url + src)\n })\n\n html = html.replace(/<v:fill[^>]+src=\"?([^\"\\s]+)\"/gi, (match, src) => {\n if (isAbsoluteUrl(src)) return match\n return match.replace(src, url + src)\n })\n\n return html\n}\n\nfunction rewriteMsoComments(html: string, url: string): string {\n return html.replace(/<!--\\[if [^\\]]+\\]>[\\s\\S]*?<!\\[endif\\]-->/g, (msoBlock) => {\n let result = msoBlock\n\n for (const attr of sourceAttributes) {\n const attrRegex = new RegExp(`\\\\b${attr}=\"([^\"]+)\"`, 'gi')\n result = result.replace(attrRegex, (match, value) => {\n if (isAbsoluteUrl(value)) return match\n\n if (attr === 'srcset') {\n return `srcset=\"${processSrcset(value, url)}\"`\n }\n\n return `${attr}=\"${url}${value}\"`\n })\n }\n\n // Use PostCSS for style attribute url() rewriting inside MSO comments\n result = result.replace(/style=\"([^\"]+)\"/gi, (match, style) => {\n if (!style.includes('url(')) return match\n const processed = processInlineStyle(style, url)\n return `style=\"${processed}\"`\n })\n\n return result\n })\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"columnWidth.d.ts","names":[],"sources":["../../src/transformers/columnWidth.ts"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"columnWidth.d.ts","names":[],"sources":["../../src/transformers/columnWidth.ts"],"mappings":";;;;;AAyKA;;;;;;;;AAAwD;;;;;;;;;;;;;;iBAAxC,WAAA,CAAY,GAAA,EAAK,SAAA,KAAc,SAAS"}
|