Skip to content

Commit c398e37

Browse files
committed
Support nested rules.
1 parent de2f5ca commit c398e37

File tree

9 files changed

+169
-90
lines changed

9 files changed

+169
-90
lines changed

.tape.js

+6
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,10 @@ module.exports = {
2626
text: "Could not find file './dummy.css'",
2727
},
2828
},
29+
'supportsCustomParents/test': {
30+
message: 'removes statements if non-existent files are provided',
31+
},
32+
// 'supportsMediaQueries/test': {
33+
// message: 'removes statements if non-existent files are provided',
34+
// },
2935
};

index.js

-84
This file was deleted.

package.json

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
{
2-
"name": "postcss-inline-class",
3-
"version": "0.0.1",
2+
"name": "@sector-labs/postcss-inline-class",
3+
"version": "0.0.2",
44
"description": "Inline the declarations of other CSS classes in your CSS classes.",
5-
"main": "index.js",
6-
"repository": "https://github.com/alexandrukis/postcss-inline-class",
5+
"main": "src/index.js",
6+
"repository": "https://github.com/sectorlabs/postcss-inline-class",
77
"author": "Sector Labs <open-source@sectorlabs.ro>",
88
"license": "MIT",
99
"keywords": [
@@ -16,7 +16,7 @@
1616
"class"
1717
],
1818
"files": [
19-
"index.js"
19+
"src/*"
2020
],
2121
"engines": {
2222
"node": ">=6.0.0"
@@ -38,7 +38,7 @@
3838
"ci": "eslint . && postcss-tape",
3939
"fix": "eslint . --fix --ignore-pattern '!.tape.js'",
4040
"lint": "eslint .",
41-
"test": "postcss-tape --plugin ./index.js"
41+
"test": "postcss-tape --plugin src/index.js"
4242
},
4343
"eslintConfig": {
4444
"extends": "eslint-config-i-am-meticulous",

src/findInlineDeclarations.js

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
const _ = require('lodash');
2+
3+
const findInlineDeclarations = (root, targetSelector) => {
4+
const inlineDeclarations = [];
5+
6+
root.walkRules((rule) => {
7+
if (rule.selectors.includes(targetSelector) && rule.parent.type === 'root') {
8+
inlineDeclarations.push(rule);
9+
}
10+
});
11+
12+
return _.flatten(inlineDeclarations.map((match) => match.clone().nodes));
13+
};
14+
15+
module.exports = findInlineDeclarations;

src/findNestedRules.js

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
const _ = require('lodash');
2+
3+
const findNestedRules = (root, targetSelector) => {
4+
const nestedMatches = [];
5+
6+
root.walkRules((rule) => {
7+
if (rule.selectors.includes(targetSelector) && rule.parent.type === 'root') {
8+
return;
9+
}
10+
11+
const isNestedRule = rule.selectors.find((selector) =>
12+
selector.split(' ').includes(targetSelector),
13+
);
14+
15+
if (isNestedRule) {
16+
nestedMatches.push(rule);
17+
}
18+
});
19+
20+
return _.flatten(nestedMatches.map((match) => match.clone()));
21+
};
22+
23+
module.exports = findNestedRules;

src/index.js

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
const path = require('path');
2+
3+
const postcss = require('postcss');
4+
5+
const readFile = require('./utils').readFile;
6+
const parseImportPath = require('./utils').parseImportPath;
7+
const findInlineDeclarations = require('./findInlineDeclarations');
8+
const findNestedRules = require('./findNestedRules');
9+
10+
const processAtRule = (onError, atRule, root, targetClass, importPath) => {
11+
const matchedDeclarations = findInlineDeclarations(root, targetClass);
12+
const nestedRules = findNestedRules(root, targetClass);
13+
14+
if (matchedDeclarations.length === 0 && nestedRules.length === 0) {
15+
if (importPath) {
16+
onError(`Could not find class '${targetClass}' in file '${importPath}'`);
17+
} else {
18+
onError(`Could not find class '${targetClass}'`);
19+
}
20+
}
21+
22+
nestedRules.forEach((nestedRule) => {
23+
nestedRule.selectors = nestedRule.selectors.map((selector) =>
24+
postcss.list
25+
.space(selector)
26+
.map((className) => (className === targetClass ? atRule.parent.selector : className))
27+
.join(' '),
28+
);
29+
root.append(nestedRule);
30+
});
31+
32+
atRule.replaceWith(matchedDeclarations);
33+
};
34+
35+
const walkAtRule = (root, result, promises) => (atRule) => {
36+
const params = postcss.list.space(atRule.params);
37+
const targetClass = params[0];
38+
39+
const onError = (message) => atRule.warn(result, message);
40+
41+
if (params.length === 1) {
42+
processAtRule(onError, atRule, root, targetClass);
43+
return;
44+
}
45+
46+
const importPath = parseImportPath(params.slice(-1)[0]);
47+
const resolvedPath = path.resolve(path.dirname(root.source.input.file), importPath);
48+
49+
promises.push(
50+
readFile(resolvedPath)
51+
.then((rawData) => {
52+
const importedRoot = postcss.parse(rawData);
53+
processAtRule(onError, atRule, importedRoot, targetClass, importPath);
54+
})
55+
.catch(() => {
56+
onError(`Could not find file '${importPath}'`);
57+
atRule.remove();
58+
}),
59+
);
60+
};
61+
62+
const processFile = (root, result) => (resolve) => {
63+
const promises = [];
64+
65+
const atRuleWalker = walkAtRule(root, result, promises);
66+
67+
root.walkRules((rule) => rule.walkAtRules('inline', atRuleWalker));
68+
69+
return Promise.all(promises).then(resolve).catch(resolve);
70+
};
71+
72+
module.exports = postcss.plugin('postcss-inline-class', () => (root, result) =>
73+
new Promise(processFile(root, result)),
74+
);

src/utils.js

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
const fs = require('fs');
2+
3+
module.exports.parseImportPath = (path) => {
4+
const matches = path.trim().match(/^['"](.+?)['"](.*)/);
5+
return matches[1];
6+
};
7+
8+
module.exports.readFile = (file) => {
9+
return new Promise((resolve, reject) => {
10+
fs.readFile(file, 'utf-8', (err, contents) => {
11+
if (err) {
12+
return reject(err);
13+
}
14+
return resolve(contents);
15+
});
16+
});
17+
};

test/supportsCustomParents/test.css

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
.ba {
2+
color: red;
3+
}
4+
5+
.bad .ba {
6+
color: blue;
7+
}
8+
9+
.b {
10+
@inline .ba;
11+
font-size: 14px;
12+
}
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
.ba {
2+
color: red;
3+
}
4+
5+
.bad .ba {
6+
color: blue;
7+
}
8+
9+
.b {
10+
color: red;
11+
font-size: 14px;
12+
}
13+
14+
.bad .b {
15+
color: blue;
16+
}

0 commit comments

Comments
 (0)