Skip to content

Commit 2dae82f

Browse files
committed
a passing test!
1 parent 57d6399 commit 2dae82f

File tree

4 files changed

+243
-2
lines changed

4 files changed

+243
-2
lines changed

lib/index.js

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
'use strict';
2+
3+
Object.defineProperty(exports, '__esModule', {
4+
value: true
5+
});
6+
7+
var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })();
8+
9+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
10+
11+
var _postcss = require('postcss');
12+
13+
var _postcss2 = _interopRequireDefault(_postcss);
14+
15+
var _icssReplaceSymbols = require('icss-replace-symbols');
16+
17+
var _icssReplaceSymbols2 = _interopRequireDefault(_icssReplaceSymbols);
18+
19+
var matchImports = /^(.+?)\s+from\s+("[^"]*"|'[^']*'|[\w-]+)$/;
20+
var matchLet = /(?:,\s+|^)([\w-]+):?\s+("[^"]*"|'[^']*'|[^,]+)\s?/g;
21+
var matchImport = /^([\w-]+)(?:\s+as\s+([\w-]+))?/;
22+
var options = {};
23+
var importIndex = 0;
24+
var createImportedName = options && options.createImportedName || function (importName /*, path*/) {
25+
return 'i__const_' + importName.replace(/\W/g, '_') + '_' + importIndex++;
26+
};
27+
28+
exports['default'] = function (css) {
29+
/* Find any local let rules and store them*/
30+
var translations = {};
31+
css.eachAtRule(/^define$/, function (atRule) {
32+
var matches = undefined;
33+
while (matches = matchLet.exec(atRule.params)) {
34+
var _matches = matches;
35+
36+
var _matches2 = _slicedToArray(_matches, 3);
37+
38+
var /*match*/key = _matches2[1];
39+
var value = _matches2[2];
40+
41+
translations[key] = value;
42+
atRule.removeSelf();
43+
}
44+
});
45+
46+
/* We want to export anything defined by now, but don't add it to the CSS yet or
47+
it well get picked up by the replacement stuff */
48+
var exportDeclarations = Object.keys(translations).map(function (key) {
49+
return _postcss2['default'].decl({
50+
value: translations[key],
51+
prop: key,
52+
before: "\n ",
53+
_autoprefixerDisabled: true
54+
});
55+
});
56+
57+
/* Find imports and insert ICSS tmp vars */
58+
var importAliases = [];
59+
css.eachAtRule(/^import(-define)?$/, function (atRule) {
60+
var matches = matchImports.exec(atRule.params);
61+
if (matches) {
62+
var _matches3 = _slicedToArray(matches, 3);
63+
64+
var /*match*/aliases = _matches3[1];
65+
var path = _matches3[2];
66+
67+
// We can use constants for path names
68+
if (translations[path]) path = translations[path];
69+
var imports = aliases.split(/\s*,\s*/).map(function (alias) {
70+
var tokens = matchImport.exec(alias);
71+
if (tokens) {
72+
var _tokens = _slicedToArray(tokens, 3);
73+
74+
var /*match*/theirName = _tokens[1];
75+
var _tokens$2 = _tokens[2];
76+
var myName = _tokens$2 === undefined ? theirName : _tokens$2;
77+
78+
var importedName = createImportedName(myName);
79+
translations[myName] = importedName;
80+
return { theirName: theirName, importedName: importedName };
81+
} else {
82+
throw new Error('@import statement "' + alias + '" is invalid!');
83+
}
84+
});
85+
importAliases.push({ path: path, imports: imports });
86+
atRule.removeSelf();
87+
}
88+
});
89+
90+
/* If we have no translations, don't continue */
91+
if (!Object.keys(translations).length) return;
92+
93+
/* Perform replacements */
94+
(0, _icssReplaceSymbols2['default'])(css, translations);
95+
96+
/* Add import rules */
97+
importAliases.forEach(function (_ref) {
98+
var path = _ref.path;
99+
var imports = _ref.imports;
100+
101+
css.prepend(_postcss2['default'].rule({
102+
selector: ':import(' + path + ')',
103+
after: "\n",
104+
nodes: imports.map(function (_ref2) {
105+
var theirName = _ref2.theirName;
106+
var importedName = _ref2.importedName;
107+
return _postcss2['default'].decl({
108+
value: theirName,
109+
prop: importedName,
110+
before: "\n ",
111+
_autoprefixerDisabled: true
112+
});
113+
})
114+
}));
115+
});
116+
117+
/* Add export rules if any */
118+
if (exportDeclarations.length > 0) {
119+
css.prepend(_postcss2['default'].rule({
120+
selector: ':export',
121+
after: "\n",
122+
nodes: exportDeclarations
123+
}));
124+
}
125+
};
126+
127+
module.exports = exports['default'];

package.json

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,12 @@
44
"description": "PostCSS plugin for CSS Modules to pass arbitrary constants between your module files",
55
"main": "lib/index.js",
66
"scripts": {
7-
"test": "mocha --compilers js:babel/register"
7+
"lint": "standard src test",
8+
"build": "babel --out-dir lib src",
9+
"autotest": "chokidar src test -c 'npm test'",
10+
"test": "mocha --compilers js:babel/register",
11+
"posttest": "npm run lint && npm run build",
12+
"prepublish": "npm run build"
813
},
914
"repository": {
1015
"type": "git",
@@ -23,9 +28,12 @@
2328
"homepage": "https://github.com/css-modules/postcss-modules-constants#readme",
2429
"devDependencies": {
2530
"babel": "^5.8.23",
26-
"mocha": "^2.3.2"
31+
"chokidar": "^1.0.6",
32+
"mocha": "^2.3.2",
33+
"standard": "^5.3.1"
2734
},
2835
"dependencies": {
36+
"icss-replace-symbols": "^1.0.0",
2937
"postcss": "^5.0.5"
3038
}
3139
}

src/index.js

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import postcss from 'postcss'
2+
import replaceSymbols from 'icss-replace-symbols'
3+
4+
const matchImports = /^(.+?)\s+from\s+("[^"]*"|'[^']*'|[\w-]+)$/
5+
const matchLet = /(?:,\s+|^)([\w-]+):?\s+("[^"]*"|'[^']*'|[^,]+)\s?/g
6+
const matchImport = /^([\w-]+)(?:\s+as\s+([\w-]+))?/
7+
let options = {}
8+
let importIndex = 0
9+
let createImportedName = options && options.createImportedName || ((importName/*, path*/) => `i__const_${importName.replace(/\W/g, '_')}_${importIndex++}`)
10+
11+
export default css => {
12+
/* Find any local let rules and store them*/
13+
let translations = {}
14+
css.eachAtRule(/^define$/, atRule => {
15+
let matches
16+
while (matches = matchLet.exec(atRule.params)) {
17+
let [/*match*/, key, value] = matches
18+
translations[key] = value
19+
atRule.removeSelf()
20+
}
21+
})
22+
23+
/* We want to export anything defined by now, but don't add it to the CSS yet or
24+
it well get picked up by the replacement stuff */
25+
let exportDeclarations = Object.keys(translations).map(key => postcss.decl({
26+
value: translations[key],
27+
prop: key,
28+
before: "\n ",
29+
_autoprefixerDisabled: true
30+
}))
31+
32+
/* Find imports and insert ICSS tmp vars */
33+
let importAliases = []
34+
css.eachAtRule(/^import(-define)?$/, atRule => {
35+
let matches = matchImports.exec(atRule.params)
36+
if (matches) {
37+
let [/*match*/, aliases, path] = matches
38+
// We can use constants for path names
39+
if (translations[path]) path = translations[path]
40+
let imports = aliases.split(/\s*,\s*/).map(alias => {
41+
let tokens = matchImport.exec(alias)
42+
if (tokens) {
43+
let [/*match*/, theirName, myName = theirName] = tokens
44+
let importedName = createImportedName(myName)
45+
translations[myName] = importedName
46+
return {theirName, importedName}
47+
} else {
48+
throw new Error(`@import statement "${alias}" is invalid!`)
49+
}
50+
})
51+
importAliases.push({path, imports})
52+
atRule.removeSelf()
53+
}
54+
})
55+
56+
/* If we have no translations, don't continue */
57+
if (!Object.keys(translations).length) return
58+
59+
/* Perform replacements */
60+
replaceSymbols(css, translations)
61+
62+
/* Add import rules */
63+
importAliases.forEach(({path, imports}) => {
64+
css.prepend(postcss.rule({
65+
selector: `:import(${path})`,
66+
after: "\n",
67+
nodes: imports.map(({theirName, importedName}) => postcss.decl({
68+
value: theirName,
69+
prop: importedName,
70+
before: "\n ",
71+
_autoprefixerDisabled: true
72+
}))
73+
}))
74+
})
75+
76+
/* Add export rules if any */
77+
if (exportDeclarations.length > 0) {
78+
css.prepend(postcss.rule({
79+
selector: `:export`,
80+
after: "\n",
81+
nodes: exportDeclarations
82+
}))
83+
}
84+
}

test/index.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/* global describe, it */
2+
3+
import postcss from 'postcss'
4+
import assert from 'assert'
5+
6+
import constants from '../src'
7+
8+
const test = (input, expected) => {
9+
let processor = postcss([constants])
10+
assert.equal(processor.process(input).css, expected)
11+
}
12+
13+
describe('constants', () => {
14+
it('should pass through an empty string', () => {
15+
test('','')
16+
})
17+
18+
it('should export a constant', () => {
19+
test('@define red blue;',':export {\n red: blue\n}')
20+
})
21+
})
22+

0 commit comments

Comments
 (0)