Skip to content

Commit 81f8a77

Browse files
committed
Enhance URL handling and improve value extraction logic
1 parent 2fc75fb commit 81f8a77

2 files changed

Lines changed: 49 additions & 3 deletions

File tree

__tests__/index.spec.ts

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ describe('node-detective-postcss', () => {
1010
assert('@import "foo.css"', ['foo.css']);
1111
});
1212

13+
it('works with single quotes', () => {
14+
assert("@import 'foo.css'", ['foo.css']);
15+
});
16+
1317
describe('url()', () => {
1418
it('works with url()', () => {
1519
assert('@import url("navigation.css");', ['navigation.css']);
@@ -57,6 +61,10 @@ describe('node-detective-postcss', () => {
5761
assert('@import url("//example.com/style.css");', []);
5862
});
5963

64+
it('ignores protocol-relative URLs without url()', () => {
65+
assert('@import "//example.com/style.css"', []);
66+
});
67+
6068
it('does not touch the paths', () => {
6169
assert('@import "../../././bla.css"', ['../../././bla.css']);
6270
});
@@ -89,6 +97,10 @@ describe('node-detective-postcss', () => {
8997
]);
9098
});
9199

100+
it('ignores absolute URLs', () => {
101+
assert("@value primary from 'https://example.com/colors.css';", []);
102+
});
103+
92104
it('leaves simple definitions alone', () => {
93105
assert('@value mine: #fff;', []);
94106
});
@@ -135,6 +147,24 @@ describe('node-detective-postcss', () => {
135147
assert('@value x: url(bummer.png)', ['bummer.png'], { url: true });
136148
});
137149

150+
it('ignores absolute urls', () => {
151+
assert('.x { background: url(https://example.com/img.png) }', [], {
152+
url: true,
153+
});
154+
});
155+
156+
it('ignores protocol-relative urls', () => {
157+
assert('.x { background: url(//example.com/img.png) }', [], {
158+
url: true,
159+
});
160+
});
161+
162+
it('finds multiple url() in one declaration', () => {
163+
assert('.x { background: url(a.png), url(b.png) }', ['a.png', 'b.png'], {
164+
url: true,
165+
});
166+
});
167+
138168
it('ignores base64 data: urls', () => {
139169
assert(
140170
'.x { background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)}',
@@ -144,8 +174,8 @@ describe('node-detective-postcss', () => {
144174

145175
it('ignores SVG data: urls', () => {
146176
const css = `svg {
147-
-webkit-mask-image: url('data:image/svg+xml;utf8,<svg viewBox="0 0 32 32" width="32" height="32" xmlns="http://www.w3.org/2000/svg"><defs><mask id="mask"><rect x="0" y="0" width="32" height="32" fill="#fff"/><rect x="14" y="-10" width="40" height="20" rx="10" fill="#000"/></mask></defs><rect x="0" y="0" width="32" height="32" mask="url(#mask)"/></svg>');
148-
}`;
177+
-webkit-mask-image: url('data:image/svg+xml;utf8,<svg viewBox="0 0 32 32" width="32" height="32" xmlns="http://www.w3.org/2000/svg"><defs><mask id="mask"><rect x="0" y="0" width="32" height="32" fill="#fff"/><rect x="14" y="-10" width="40" height="20" rx="10" fill="#000"/></mask></defs><rect x="0" y="0" width="32" height="32" mask="url(#mask)"/></svg>');
178+
}`;
149179
assert(css, []);
150180
});
151181
});

src/index.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,13 +75,29 @@ function detective(src, options: detective.Options = { url: false }) {
7575
}
7676

7777
function getValueOrUrl(node: ChildNode): string | false {
78-
const ret = isUrlNode(node) ? getValue(node.nodes[0]) : getValue(node);
78+
const ret = isUrlNode(node) ? getUrlContent(node) : getValue(node);
7979

8080
// is-url-superb uses new URL() which doesn't accept protocol-relative URLs;
8181
// prepend http: so they get correctly identified and filtered out
8282
return !isUrl(ret.startsWith('//') ? `http:${ret}` : ret) && ret;
8383
}
8484

85+
function getUrlContent(urlNode: Func): string {
86+
const first = urlNode.nodes[0];
87+
88+
// Quoted: url('foo.css') or url("foo.css")
89+
if (first && first.type === 'quoted') {
90+
return first.contents;
91+
}
92+
93+
// Unquoted: reconstruct the full string from all child nodes (handles
94+
// absolute URLs like url(https://...) which parse as multiple tokens)
95+
return urlNode.nodes
96+
.filter((n) => isNodeWithValue(n))
97+
.map((n) => getValue(n))
98+
.join('');
99+
}
100+
85101
function getValue(node: ChildNode) {
86102
if (!isNodeWithValue(node)) {
87103
throw new Error('Unexpectedly found a node without a value');

0 commit comments

Comments
 (0)