@maizzle/framework 6.0.11 → 6.0.13
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.
|
@@ -1,67 +1,67 @@
|
|
|
1
1
|
{
|
|
2
|
-
"hash": "
|
|
3
|
-
"configHash": "
|
|
2
|
+
"hash": "da0a6e25",
|
|
3
|
+
"configHash": "b212ebf5",
|
|
4
4
|
"lockfileHash": "e3b0c442",
|
|
5
|
-
"browserHash": "
|
|
5
|
+
"browserHash": "301a5498",
|
|
6
6
|
"optimized": {
|
|
7
7
|
"@lucide/vue": {
|
|
8
8
|
"src": "../../../../../node_modules/@lucide/vue/dist/esm/lucide-vue.mjs",
|
|
9
9
|
"file": "@lucide_vue.js",
|
|
10
|
-
"fileHash": "
|
|
10
|
+
"fileHash": "678a9764",
|
|
11
11
|
"needsInterop": false
|
|
12
12
|
},
|
|
13
13
|
"@vueuse/core": {
|
|
14
14
|
"src": "../../../../../node_modules/@vueuse/core/dist/index.js",
|
|
15
15
|
"file": "@vueuse_core.js",
|
|
16
|
-
"fileHash": "
|
|
16
|
+
"fileHash": "8ce516c5",
|
|
17
17
|
"needsInterop": false
|
|
18
18
|
},
|
|
19
19
|
"@vueuse/shared": {
|
|
20
20
|
"src": "../../../../../node_modules/@vueuse/shared/dist/index.js",
|
|
21
21
|
"file": "@vueuse_shared.js",
|
|
22
|
-
"fileHash": "
|
|
22
|
+
"fileHash": "794dbf7a",
|
|
23
23
|
"needsInterop": false
|
|
24
24
|
},
|
|
25
25
|
"class-variance-authority": {
|
|
26
26
|
"src": "../../../../../node_modules/class-variance-authority/dist/index.mjs",
|
|
27
27
|
"file": "class-variance-authority.js",
|
|
28
|
-
"fileHash": "
|
|
28
|
+
"fileHash": "d2ce50b9",
|
|
29
29
|
"needsInterop": false
|
|
30
30
|
},
|
|
31
31
|
"clsx": {
|
|
32
32
|
"src": "../../../../../node_modules/clsx/dist/clsx.mjs",
|
|
33
33
|
"file": "clsx.js",
|
|
34
|
-
"fileHash": "
|
|
34
|
+
"fileHash": "7c01443d",
|
|
35
35
|
"needsInterop": false
|
|
36
36
|
},
|
|
37
37
|
"culori": {
|
|
38
38
|
"src": "../../../../../node_modules/culori/src/index.js",
|
|
39
39
|
"file": "culori.js",
|
|
40
|
-
"fileHash": "
|
|
40
|
+
"fileHash": "c77a9983",
|
|
41
41
|
"needsInterop": false
|
|
42
42
|
},
|
|
43
43
|
"reka-ui": {
|
|
44
44
|
"src": "../../../../../node_modules/reka-ui/dist/index.js",
|
|
45
45
|
"file": "reka-ui.js",
|
|
46
|
-
"fileHash": "
|
|
46
|
+
"fileHash": "1032cd9a",
|
|
47
47
|
"needsInterop": false
|
|
48
48
|
},
|
|
49
49
|
"tailwind-merge": {
|
|
50
50
|
"src": "../../../../../node_modules/tailwind-merge/dist/bundle-cjs.js",
|
|
51
51
|
"file": "tailwind-merge.js",
|
|
52
|
-
"fileHash": "
|
|
52
|
+
"fileHash": "04e043e4",
|
|
53
53
|
"needsInterop": true
|
|
54
54
|
},
|
|
55
55
|
"vue-router": {
|
|
56
56
|
"src": "../../../../../node_modules/vue-router/dist/vue-router.js",
|
|
57
57
|
"file": "vue-router.js",
|
|
58
|
-
"fileHash": "
|
|
58
|
+
"fileHash": "5dd654c7",
|
|
59
59
|
"needsInterop": false
|
|
60
60
|
},
|
|
61
61
|
"vue": {
|
|
62
62
|
"src": "../../../../../node_modules/vue/dist/vue.runtime.esm-bundler.js",
|
|
63
63
|
"file": "vue.js",
|
|
64
|
-
"fileHash": "
|
|
64
|
+
"fileHash": "4ea85af4",
|
|
65
65
|
"needsInterop": false
|
|
66
66
|
}
|
|
67
67
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base.d.ts","names":[],"sources":["../../src/transformers/base.ts"],"mappings":";;;;;UAUiB;;EAEf;;;;;;;;;;EAUA,kBAAkB,eAAe;;;;;EAKjC,aAAa;;;;;;EAMb;;;;;;EAMA;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"base.d.ts","names":[],"sources":["../../src/transformers/base.ts"],"mappings":";;;;;UAUiB;;EAEf;;;;;;;;;;EAUA,kBAAkB,eAAe;;;;;EAKjC,aAAa;;;;;;EAMb;;;;;;EAMA;;;;;;;;;;;;;;;;;;;;;;;;;;iBAkIc,KAAK,cAAc,kBAAkB;;;;;;iBASrC,QAAQ,KAAK,aAAa,kBAAkB,4CAA4C"}
|
|
@@ -21,21 +21,32 @@ const sourceAttributes = [
|
|
|
21
21
|
*/
|
|
22
22
|
const defaultTagConfig = Object.fromEntries(Object.entries(defaultTags).map(([tag, attrs]) => [tag, Object.fromEntries(attrs.map((attr) => [attr, true]))]));
|
|
23
23
|
const postcssBaseUrl = (opts) => {
|
|
24
|
+
const rewriteDecl = (decl) => {
|
|
25
|
+
if (!decl.value.includes("url(")) return;
|
|
26
|
+
const parsed = valueParser(decl.value);
|
|
27
|
+
let changed = false;
|
|
28
|
+
parsed.walk((node) => {
|
|
29
|
+
if (node.type !== "function" || node.value !== "url") return;
|
|
30
|
+
const urlNode = node.nodes[0];
|
|
31
|
+
if (!urlNode) return;
|
|
32
|
+
if (isAbsoluteUrl(urlNode.value)) return;
|
|
33
|
+
urlNode.value = opts.url + urlNode.value;
|
|
34
|
+
changed = true;
|
|
35
|
+
});
|
|
36
|
+
if (changed) decl.value = parsed.toString();
|
|
37
|
+
};
|
|
24
38
|
return {
|
|
25
39
|
postcssPlugin: "postcss-base-url",
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
changed = true;
|
|
37
|
-
});
|
|
38
|
-
if (changed) decl.value = parsed.toString();
|
|
40
|
+
/**
|
|
41
|
+
* Walk declarations once, in `OnceExit`, rather than via the visitor
|
|
42
|
+
* `Declaration` hook. The visitor re-runs on nodes it mutates, and a
|
|
43
|
+
* relative base (e.g. `/images/`) never makes the URL absolute — so the
|
|
44
|
+
* guard `isAbsoluteUrl` stays false and it re-prepends the base forever
|
|
45
|
+
* (`/images//images/…`), hanging the build. A single manual pass rewrites
|
|
46
|
+
* each declaration exactly once.
|
|
47
|
+
*/
|
|
48
|
+
OnceExit(root) {
|
|
49
|
+
root.walkDecls(rewriteDecl);
|
|
39
50
|
}
|
|
40
51
|
};
|
|
41
52
|
};
|
|
@@ -125,17 +136,18 @@ function baseDom(dom, options) {
|
|
|
125
136
|
}
|
|
126
137
|
return;
|
|
127
138
|
}
|
|
139
|
+
if (inlineCss && el.attribs.style?.includes("url(")) {
|
|
140
|
+
const newStyle = processInlineStyle(el.attribs.style, baseUrl);
|
|
141
|
+
if (newStyle !== el.attribs.style) el.attribs.style = newStyle;
|
|
142
|
+
}
|
|
128
143
|
const tagConfig = getTagConfig(el.name, resolved);
|
|
129
144
|
if (tagConfig || resolved.tags === void 0) for (const [attr, value] of Object.entries(el.attribs)) {
|
|
130
|
-
if (!value) continue;
|
|
145
|
+
if (!value || attr === "style") continue;
|
|
131
146
|
const attrConfig = tagConfig?.[attr];
|
|
132
|
-
if (!attrConfig
|
|
147
|
+
if (!attrConfig) continue;
|
|
133
148
|
if (attr === "srcset" && (attrConfig === true || typeof attrConfig === "string")) {
|
|
134
149
|
const newSrcset = processSrcset(value, typeof attrConfig === "string" ? attrConfig : baseUrl);
|
|
135
150
|
if (newSrcset !== value) el.attribs.srcset = newSrcset;
|
|
136
|
-
} else if (attr === "style" && inlineCss && value.includes("url(")) {
|
|
137
|
-
const newStyle = processInlineStyle(value, baseUrl);
|
|
138
|
-
if (newStyle !== value) el.attribs.style = newStyle;
|
|
139
151
|
} else if (attrConfig === true && !isAbsoluteUrl(value)) el.attribs[attr] = baseUrl + value;
|
|
140
152
|
else if (typeof attrConfig === "string" && !isAbsoluteUrl(value)) el.attribs[attr] = attrConfig + value;
|
|
141
153
|
}
|
|
@@ -150,13 +162,22 @@ function baseDom(dom, options) {
|
|
|
150
162
|
if (rewritten !== serialized) return parse(rewritten);
|
|
151
163
|
return dom;
|
|
152
164
|
}
|
|
165
|
+
/**
|
|
166
|
+
* True when `value` already sits under `url` — used to skip re-prefixing an
|
|
167
|
+
* already-based URL (e.g. after `rewriteVMLs` runs before `rewriteMsoComments`)
|
|
168
|
+
* without matching a mere string prefix: base `/images` must NOT swallow
|
|
169
|
+
* `/images2/…`, so we require a path boundary (exact match or a following `/`).
|
|
170
|
+
*/
|
|
171
|
+
function isUnderBase(value, url) {
|
|
172
|
+
return value === url || value.startsWith(url.endsWith("/") ? url : `${url}/`);
|
|
173
|
+
}
|
|
153
174
|
function rewriteVMLs(html, url) {
|
|
154
175
|
html = html.replace(/<v:image[^>]+src="?([^"\s]+)"/gi, (match, src) => {
|
|
155
|
-
if (isAbsoluteUrl(src)) return match;
|
|
176
|
+
if (isAbsoluteUrl(src) || isUnderBase(src, url)) return match;
|
|
156
177
|
return match.replace(src, url + src);
|
|
157
178
|
});
|
|
158
179
|
html = html.replace(/<v:fill[^>]+src="?([^"\s]+)"/gi, (match, src) => {
|
|
159
|
-
if (isAbsoluteUrl(src)) return match;
|
|
180
|
+
if (isAbsoluteUrl(src) || isUnderBase(src, url)) return match;
|
|
160
181
|
return match.replace(src, url + src);
|
|
161
182
|
});
|
|
162
183
|
return html;
|
|
@@ -167,7 +188,14 @@ function rewriteMsoComments(html, url) {
|
|
|
167
188
|
for (const attr of sourceAttributes) {
|
|
168
189
|
const attrRegex = new RegExp(`\\b${attr}="([^"]+)"`, "gi");
|
|
169
190
|
result = result.replace(attrRegex, (match, value) => {
|
|
170
|
-
|
|
191
|
+
/**
|
|
192
|
+
* `isUnderBase` guards against a relative base being prepended twice:
|
|
193
|
+
* `rewriteVMLs` runs first and prefixes `v:image`/`v:fill` `src`; this
|
|
194
|
+
* generic pass would otherwise re-prefix the same attribute
|
|
195
|
+
* (`/images//images/…`) since a relative base never trips
|
|
196
|
+
* `isAbsoluteUrl`. Absolute bases self-guard via `isAbsoluteUrl`.
|
|
197
|
+
*/
|
|
198
|
+
if (isAbsoluteUrl(value) || isUnderBase(value, url)) return match;
|
|
171
199
|
if (attr === "srcset") return `srcset="${processSrcset(value, url)}"`;
|
|
172
200
|
return `${attr}="${url}${value}"`;
|
|
173
201
|
});
|
|
@@ -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 const { css } = postcss([postcssBaseUrl({ url })]).process(`a{${style}}`, { parser: safeParser, from: undefined })\n return css.slice(css.indexOf('{') + 1, css.lastIndexOf('}')).trim()\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 // 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
|
+
{"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 const rewriteDecl = (decl: postcss.Declaration) => {\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 return {\n postcssPlugin: 'postcss-base-url',\n /**\n * Walk declarations once, in `OnceExit`, rather than via the visitor\n * `Declaration` hook. The visitor re-runs on nodes it mutates, and a\n * relative base (e.g. `/images/`) never makes the URL absolute — so the\n * guard `isAbsoluteUrl` stays false and it re-prepends the base forever\n * (`/images//images/…`), hanging the build. A single manual pass rewrites\n * each declaration exactly once.\n */\n OnceExit(root) {\n root.walkDecls(rewriteDecl)\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 const { css } = postcss([postcssBaseUrl({ url })]).process(`a{${style}}`, { parser: safeParser, from: undefined })\n return css.slice(css.indexOf('{') + 1, css.lastIndexOf('}')).trim()\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 // Rewrite url() in an inline style attribute. Controlled by `inlineCss`\n // only — NOT the `tags` filter, which restricts source-attribute rewriting\n // (src/href/…). A `tags: ['img']` config must still rewrite the background\n // image on a `<td style=\"…url(bg.jpg)…\">`, matching how <style> tags work.\n if (inlineCss && el.attribs.style?.includes('url(')) {\n const newStyle = processInlineStyle(el.attribs.style, baseUrl)\n if (newStyle !== el.attribs.style) {\n el.attribs.style = newStyle\n }\n }\n\n // Process tag-specific source 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 || attr === 'style') continue\n\n const attrConfig = tagConfig?.[attr]\n if (!attrConfig) 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 (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\n/**\n * True when `value` already sits under `url` — used to skip re-prefixing an\n * already-based URL (e.g. after `rewriteVMLs` runs before `rewriteMsoComments`)\n * without matching a mere string prefix: base `/images` must NOT swallow\n * `/images2/…`, so we require a path boundary (exact match or a following `/`).\n */\nfunction isUnderBase(value: string, url: string): boolean {\n return value === url || value.startsWith(url.endsWith('/') ? url : `${url}/`)\n}\n\nfunction rewriteVMLs(html: string, url: string): string {\n html = html.replace(/<v:image[^>]+src=\"?([^\"\\s]+)\"/gi, (match, src) => {\n if (isAbsoluteUrl(src) || isUnderBase(src, url)) 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) || isUnderBase(src, url)) 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 /**\n * `isUnderBase` guards against a relative base being prepended twice:\n * `rewriteVMLs` runs first and prefixes `v:image`/`v:fill` `src`; this\n * generic pass would otherwise re-prefix the same attribute\n * (`/images//images/…`) since a relative base never trips\n * `isAbsoluteUrl`. Absolute bases self-guard via `isAbsoluteUrl`.\n */\n if (isAbsoluteUrl(value) || isUnderBase(value, url)) 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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"}
|