Skip to content

Commit 71d000e

Browse files
authored
Merge pull request #9 from css-modules/new-plugin
New plugin
2 parents a770436 + 865a431 commit 71d000e

File tree

13 files changed

+156
-182
lines changed

13 files changed

+156
-182
lines changed

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
"license": "MIT",
5454
"dependencies": {
5555
"icss-replace-symbols": "^1.0.2",
56+
"icss-utils": "^2.1.0",
5657
"lodash.foreach": "^3.0.3",
5758
"postcss": "^5.0.10"
5859
},
@@ -64,6 +65,7 @@
6465
"husky": "^0.13.3",
6566
"jest": "^20.0.4",
6667
"lint-staged": "^3.5.0",
67-
"prettier": "^1.3.1"
68+
"prettier": "^1.3.1",
69+
"strip-indent": "^2.0.0"
6870
}
6971
}

readme.md

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,21 @@
11
postcss-icss
22
============
33

4-
A CSS Modules parser to extract tokens from the css file. Provides opportunity to process multiple files. Supports both synchronous and asynchronous file loaders.
4+
A CSS Modules parser to extract tokens from the css file. Provides opportunity to process multiple files.
55

66
## API
77

8-
In order to use it you should provide a `fetch` function which should load contents of files and process it with the PostCSS instance. `fetch` function should return tokens or promise object which will resolve into tokens.
8+
In order to use it you should provide a `fetch` function which should load contents of files and process it with the PostCSS instance.
9+
`fetch` function should return promise object which will resolve into tokens.
910

10-
```javascript
11-
var Parser = require('postcss-modules-parser');
11+
```js
12+
const ICSS = require('postcss-icss');
1213

13-
/**
14-
* @param {string} to Path to the new file. Could be any.
15-
* @param {string} from Path to the source file. Should be absolute.
16-
* @return {object} Tokens
17-
*/
18-
function fetch(to, from) {
14+
function fetch(importee, importerDir, processor) {
1915
// load content
20-
return instance.process(css, {from: filename}).root.tokens;
16+
return processor.process(css, { from: filename })
17+
.then(result => result.messages.find(d => d.type === "icss").exportTokens);
2118
}
2219

23-
new Parser({fetch: fetch});
20+
postcss([ ICSS({ fetch }) ]);
2421
```
25-
26-
See the examples:
27-
- asynchronous loader: [test/helper/async-loader.js](https://github.com/css-modules/postcss-modules-parser/blob/master/test/helper/async-loader.js)
28-
- synchronous loader: [test/helper/sync-loader.js](https://github.com/css-modules/postcss-modules-parser/blob/master/test/helper/sync-loader.js)

src/index.js

Lines changed: 53 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,67 @@
11
/* eslint-env node */
2+
import fs from "fs";
3+
import path from "path";
24
import postcss from "postcss";
3-
import forEach from "lodash.foreach";
4-
import replaceSymbols from "icss-replace-symbols";
5-
const importRegexp = /^:import\((.+)\)$/;
6-
const exportRegexp = /^:export$/;
5+
import { replaceSymbols, replaceValueSymbols, extractICSS } from "icss-utils";
76

8-
/**
9-
* @param {object} promise
10-
* @return {boolean}
11-
*/
12-
function isPromise(promise) {
13-
return typeof promise === "object" && typeof promise.then === "function";
14-
}
15-
16-
/**
17-
* @param {object} css
18-
* @param {object} translations
19-
*/
20-
function proceed(css, translations) {
21-
const exportTokens = {};
22-
23-
replaceSymbols(css, translations);
24-
25-
css.walkRules(exportRegexp, rule => {
26-
rule.walkDecls(decl => {
27-
forEach(
28-
translations,
29-
(value, key) => (decl.value = decl.value.replace(key, value))
30-
);
31-
exportTokens[decl.prop] = decl.value;
7+
const readFile = filepath =>
8+
new Promise((resolve, reject) => {
9+
fs.readFile(filepath, "utf-8", (err, content) => {
10+
if (err) {
11+
reject(err);
12+
} else {
13+
resolve(content);
14+
}
3215
});
33-
34-
rule.remove();
3516
});
3617

37-
css.tokens = exportTokens;
38-
}
18+
const defaultFetch = (importee, importerDir, processor) => {
19+
const ext = path.extname(importee);
20+
if (ext !== ".css") {
21+
return Promise.resolve({
22+
default: importee
23+
});
24+
}
25+
const from = path.resolve(importerDir, importee);
26+
return readFile(from)
27+
.then(content => processor.process(content, { from }))
28+
.then(result => result.messages.find(d => d.type === "icss").exportTokens);
29+
};
3930

40-
/**
41-
* @param {function} options.fetch
42-
* @return {function}
43-
*/
44-
module.exports = postcss.plugin("postcss-icss", ({ fetch } = {}) => css => {
45-
// https://github.com/postcss/postcss/blob/master/docs/api.md#inputfile
46-
const file = css.source.input.file;
31+
module.exports = postcss.plugin("postcss-icss", (options = {}) => (
32+
css,
33+
result
34+
) => {
35+
const importerDir = css.source.input.file
36+
? path.dirname(css.source.input.file)
37+
: process.cwd();
38+
const fetch = options.fetch || defaultFetch;
4739

48-
const translations = {};
49-
const promises = [];
40+
const { icssImports, icssExports } = extractICSS(css);
5041

51-
let iteration = 0;
42+
const promises = Object.keys(icssImports).map(key => {
43+
const importee = key.replace(/^['"]|['"]$/g, "");
44+
return fetch(importee, importerDir, result.processor).then(exportTokens => {
45+
const importTokens = icssImports[key];
46+
return Object.keys(importTokens).reduce((acc, token) => {
47+
acc[token] = exportTokens[importTokens[token]];
48+
return acc;
49+
}, {});
50+
});
51+
});
5252

53-
css.walkRules(importRegexp, rule => {
54-
const dependency = RegExp.$1.replace(/^["']|["']$/g, "");
55-
const result = fetch(dependency, file, iteration++);
53+
return Promise.all(promises).then(results => {
54+
const replacements = Object.assign({}, ...results);
55+
replaceSymbols(css, replacements);
5656

57-
if (isPromise(result)) {
58-
result.then(exports => {
59-
rule.walkDecls(decl => (translations[decl.prop] = exports[decl.value]));
60-
rule.remove();
61-
});
57+
Object.keys(icssExports).forEach(key => {
58+
icssExports[key] = replaceValueSymbols(icssExports[key], replacements);
59+
});
6260

63-
promises.push(result);
64-
} else {
65-
rule.walkDecls(decl => (translations[decl.prop] = result[decl.value]));
66-
rule.remove();
67-
}
61+
result.messages.push({
62+
type: "icss",
63+
plugin: "postcss-icss",
64+
exportTokens: icssExports
65+
});
6866
});
69-
70-
if (promises.length === 0) {
71-
return void proceed(css, translations);
72-
}
73-
74-
return Promise.all(promises).then(() => proceed(css, translations));
7567
});

test/fixture/multiple/expected.json

Lines changed: 0 additions & 3 deletions
This file was deleted.

test/fixture/multiple/external.css

Lines changed: 0 additions & 4 deletions
This file was deleted.

test/fixture/multiple/source.css

Lines changed: 0 additions & 9 deletions
This file was deleted.

test/fixture/single/expected.json

Lines changed: 0 additions & 3 deletions
This file was deleted.

test/fixture/single/source.css

Lines changed: 0 additions & 4 deletions
This file was deleted.

test/fixtures/exports.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
:export {
2+
export1: exported1;
3+
export2: exported2;
4+
}

test/helper/async-loader.js

Lines changed: 0 additions & 24 deletions
This file was deleted.

0 commit comments

Comments
 (0)