Skip to content

Commit a06dfb9

Browse files
committed
Make declaration urls absolute
1 parent b8e53ff commit a06dfb9

File tree

6 files changed

+63
-13
lines changed

6 files changed

+63
-13
lines changed

Diff for: index.html

+6-1
Original file line numberDiff line numberDiff line change
@@ -1343,7 +1343,8 @@ <h2>
13431343
<p class="note">
13441344
With polyfill applied: Target and Anchor text is orange (from styles
13451345
defined in an imported stylesheet). Target One is positioned at the
1346-
bottom right corner of the Anchor.<br />
1346+
bottom right corner of the Anchor. The Anchor has an envelope icon on
1347+
both sides of the text.<br />
13471348

13481349
<strong>Note:</strong> Target Two has <code>position-area</code> defined
13491350
in an imported stylesheet, which is not parsed by the polyfill, so it is
@@ -1353,6 +1354,10 @@ <h2>
13531354
<pre><code class="language-css">@import url('./import-is-imported-url.css') supports(display: grid) screen and (min-width: 400px);
13541355
@import './import-is-imported-string.css';
13551356

1357+
#imports .anchor::after {
1358+
content: url('./mail.svg');
1359+
}
1360+
13561361
/* ./import-is-imported-url.css */
13571362
#imports #target-1{
13581363
color: var(--brand-orange);

Diff for: public/import-has-import.css

+4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
anchor-name: --import-anchor;
88
}
99

10+
#imports .anchor::after {
11+
content: url('./mail.svg');
12+
}
13+
1014
#imports .target {
1115
position: absolute;
1216
position-anchor: --import-anchor;

Diff for: public/import-is-imported-url.css

+4
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,7 @@
66
position-area: block-end inline-start;
77
color: var(--brand-orange);
88
}
9+
10+
#imports .anchor::before {
11+
content: url('./mail.svg');
12+
}

Diff for: public/mail.svg

+11
Loading

Diff for: src/parse.ts

+7
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import {
4444
getAST,
4545
getSelectors,
4646
isAnchorFunction,
47+
makeDeclarationValueUrlAbsolute,
4748
makeImportUrlAbsolute,
4849
type StyleData,
4950
} from './utils.js';
@@ -693,6 +694,12 @@ export async function parseCSS(styleData: StyleData[]) {
693694
changed = makeImportUrlAbsolute(node);
694695
},
695696
});
697+
walk(ast, {
698+
visit: 'Declaration',
699+
enter(node) {
700+
changed = makeDeclarationValueUrlAbsolute(node) || changed;
701+
},
702+
});
696703
if (changed) {
697704
// Update CSS
698705
styleObj.css = generateCSS(ast);

Diff for: src/utils.ts

+31-12
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
1-
import type {
2-
Atrule,
3-
CssNode,
4-
Declaration,
5-
FunctionNode,
6-
Identifier,
1+
import {
2+
type Atrule,
3+
type CssNode,
4+
type Declaration,
5+
type FunctionNode,
6+
type Identifier,
77
List,
8-
Selector as CssTreeSelector,
9-
SelectorList,
10-
Value,
11-
AtrulePrelude,
12-
StyleSheet,
8+
type Selector as CssTreeSelector,
9+
type SelectorList,
10+
type StyleSheet,
11+
type Value,
1312
} from 'css-tree';
1413
import generate from 'css-tree/generator';
1514
import parse from 'css-tree/parser';
@@ -59,7 +58,10 @@ function isImportRule(node: CssNode): node is Atrule {
5958

6059
export function makeImportUrlAbsolute(node: CssNode): boolean {
6160
if (!isImportRule(node)) return false;
62-
const reparsedNode = (getAST(generateCSS(node), true) as StyleSheet).children.first;
61+
// AtRulePreludes are not parsed by default, so we need to reparse the node
62+
// to get the URL.
63+
const reparsedNode = (getAST(generateCSS(node), true) as StyleSheet).children
64+
.first;
6365
if (!reparsedNode || !isImportRule(reparsedNode)) return false;
6466
if (reparsedNode.prelude?.type !== 'AtrulePrelude') return false;
6567

@@ -72,6 +74,23 @@ export function makeImportUrlAbsolute(node: CssNode): boolean {
7274
return true;
7375
}
7476

77+
export function makeDeclarationValueUrlAbsolute(node: CssNode): boolean {
78+
if (!isDeclaration(node)) return false;
79+
80+
if (node.value.type !== 'Value') return false;
81+
let changed = false;
82+
83+
const mapped = node.value.children.toArray().map((child) => {
84+
if (!child) return child;
85+
if (child.type !== 'Url') return child;
86+
child.value = new URL(child.value, document.baseURI).href;
87+
changed = true;
88+
return child;
89+
});
90+
node.value.children = new List<CssNode>().fromArray(mapped);
91+
return changed;
92+
}
93+
7594
export interface StyleData {
7695
el: HTMLElement;
7796
css: string;

0 commit comments

Comments
 (0)