Skip to content

Commit 35c00e9

Browse files
correctly parse import arguments (#36)
Co-authored-by: Romain Menke <romainmenke@gmail.com>
1 parent 742419b commit 35c00e9

File tree

3 files changed

+64
-8
lines changed

3 files changed

+64
-8
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changes to Stylelint Value No Unknown Custom Properties
22

3+
### Unreleased
4+
5+
- Fix `@import` prelude parsing
6+
37
### 6.0.0 (Dec 28, 2023)
48

59
- Updated: peer `stylelint` to >=16 (breaking)

index.test.mjs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,15 @@ accept = [
3333
{ code: '.anything { --brand-blue: #33f; } body { color: var(--brand-blue); }' },
3434
{ code: ':root { --brand-blue: #33f; --brand-color: var(--brand-blue); }' },
3535
{ code: '@import \'./test/import-custom-properties.css\'; body { color: var(--brand-red); }' },
36+
{ code: '@import "./test/import-custom-properties.css" screen; body { color: var(--brand-red); }' },
37+
{ code: '@import "./test/import-custom-properties.css"/**/; body { color: var(--brand-red); }' },
38+
{ code: '@import url(./test/import-custom-properties.css); body { color: var(--brand-red); }' },
39+
{ code: '@import url(\'./test/import-custom-properties.css\'); body { color: var(--brand-red); }' },
40+
{ code: '@import url( \'./test/import-custom-properties.css\'/**/)/**/; body { color: var(--brand-red); }' },
41+
{ code: '@import url(\t\'./test/import-custom-properties.css\'\t)\t; body { color: var(--brand-red); }' },
42+
{ code: '@import url(./test/import-custom-properties.css) screen; body { color: var(--brand-red); }' },
43+
{ code: '@import url("./test/import-custom-properties.css") screen; body { color: var(--brand-red); }' },
44+
{ code: '@import url("./test/import-custom-properties.css" url-mod); body { color: var(--brand-red); }' },
3645
{ code: '@import \'./test/import-custom-properties.css\'; @import \'./test/import-custom-properties123.css\'; body { color: var(--brand-red); }' },
3746
];
3847
reject = [

src/lib/get-custom-properties-from-root.mjs

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import fs from 'node:fs/promises';
22
import path from 'node:path';
33
import postcss from 'postcss';
4+
import valueParser from 'postcss-value-parser';
45
import { resolveId } from './resolve-id.mjs';
56

67
// return custom selectors from the css root, conditionally removing them
@@ -17,7 +18,10 @@ export default async function getCustomPropertiesFromRoot(root, resolver) {
1718
// recursively add custom properties from @import statements
1819
const importPromises = [];
1920
root.walkAtRules('import', atRule => {
20-
const fileName = atRule.params.replace(/['|"]/g, '');
21+
const fileName = parseImportParams(atRule.params);
22+
if (!fileName) {
23+
return;
24+
}
2125

2226
if (path.isAbsolute(fileName)) {
2327
importPromises.push(getCustomPropertiesFromCSSFile(fileName, resolver));
@@ -39,21 +43,19 @@ export default async function getCustomPropertiesFromRoot(root, resolver) {
3943
});
4044

4145
// for each custom property declaration
42-
root.walkDecls(customPropertyRegExp, decl => {
43-
const { prop } = decl;
46+
root.walkDecls(decl => {
47+
if (!decl.variable || !decl.prop.startsWith('--')) {
48+
return;
49+
}
4450

4551
// write the parsed value to the custom property
46-
customProperties[prop] = decl.value;
52+
customProperties[decl.prop] = decl.value;
4753
});
4854

4955
// return all custom properties, preferring :root properties over html properties
5056
return customProperties;
5157
}
5258

53-
// match custom properties
54-
const customPropertyRegExp = /^--[A-z][\w-]*$/;
55-
56-
5759
async function getCustomPropertiesFromCSSFile(from, resolver) {
5860
try {
5961
const css = await fs.readFile(from, 'utf8');
@@ -64,3 +66,44 @@ async function getCustomPropertiesFromCSSFile(from, resolver) {
6466
return {};
6567
}
6668
}
69+
70+
function parseImportParams(params) {
71+
const nodes = valueParser(params).nodes;
72+
if (!nodes.length) {
73+
return;
74+
}
75+
76+
for (let i = 0; i < nodes.length; i++) {
77+
const node = nodes[i];
78+
if (node.type === 'space' || node.type === 'comment') {
79+
continue;
80+
}
81+
82+
if (node.type === 'string') {
83+
return node.value;
84+
}
85+
86+
if (node.type === 'function' && /url/i.test(node.value)) {
87+
for (let j = 0; j < node.nodes.length; j++) {
88+
const urlNode = node.nodes[j];
89+
if (urlNode.type === 'space' || urlNode.type === 'comment') {
90+
continue;
91+
}
92+
93+
if (urlNode.type === 'word') {
94+
return urlNode.value;
95+
}
96+
97+
if (urlNode.type === 'string') {
98+
return urlNode.value;
99+
}
100+
101+
return false;
102+
}
103+
}
104+
105+
return false;
106+
}
107+
108+
return false;
109+
}

0 commit comments

Comments
 (0)