Skip to content

Commit 8be0209

Browse files
committed
Merge pull request #29 from css-modules/updates
Updates
2 parents c12754d + 6b93624 commit 8be0209

File tree

6 files changed

+149
-65
lines changed

6 files changed

+149
-65
lines changed

package.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,12 @@
77
"node": ">=0.12"
88
},
99
"dependencies": {
10-
"lodash.isplainobject": "^3.2.0"
10+
"lodash.assign": "^3.2.0",
11+
"lodash.identity": "^3.0.0",
12+
"lodash.isarray": "^3.0.4",
13+
"lodash.isfunction": "^3.0.6",
14+
"lodash.isstring": "^3.0.1",
15+
"lodash.pick": "^3.1.0"
1116
},
1217
"devDependencies": {
1318
"babel": "^5.8.20",
@@ -19,6 +24,7 @@
1924
"eslint-watch": "^1.2.4",
2025
"in-publish": "^2.0.0",
2126
"isparta": "^3.0.3",
27+
"lodash": "^3.10.1",
2228
"mocha": "^2.2.5",
2329
"postcss": "4.x",
2430
"postcss-modules-extract-imports": "0.x",

src/fn.js

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

src/index.js

Lines changed: 27 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import hook from './hook';
22
import { readFileSync } from 'fs';
33
import { dirname, sep, relative, resolve } from 'path';
4-
import { identity, removeQuotes } from './fn';
4+
import { get, removeQuotes } from './utility';
5+
import assign from 'lodash.assign';
6+
import identity from 'lodash.identity';
7+
import pick from 'lodash.pick';
58
import postcss from 'postcss';
69

710
import ExtractImports from 'postcss-modules-extract-imports';
@@ -16,73 +19,50 @@ let tokensByFile = {};
1619
const preProcess = identity;
1720
let postProcess;
1821
// defaults
22+
let lazyResultOpts = {};
1923
let plugins = [LocalByDefault, ExtractImports, Scope];
2024
let rootDir = process.cwd();
2125

2226
/**
23-
* @param {object} opts
27+
* @param {object} opts
2428
* @param {function} opts.createImportedName
2529
* @param {function} opts.generateScopedName
2630
* @param {function} opts.processCss
2731
* @param {string} opts.rootDir
32+
* @param {string} opts.to
2833
* @param {array} opts.use
2934
*/
3035
export default function setup(opts = {}) {
3136
// clearing cache
3237
importNr = 0;
3338
tokensByFile = {};
3439

35-
if (opts.processCss && typeof opts.processCss !== 'function') {
36-
throw new Error('should specify function for processCss');
37-
}
38-
39-
postProcess = opts.processCss || null;
40-
41-
if (opts.rootDir && typeof opts.rootDir !== 'string') {
42-
throw new Error('should specify string for rootDir');
43-
}
44-
45-
rootDir = opts.rootDir || process.cwd();
46-
47-
if (opts.use) {
48-
if (!Array.isArray(opts.use)) {
49-
throw new Error('should specify array for use');
50-
}
40+
postProcess = get('processCss', null, 'function', opts) || null;
41+
rootDir = get('rootDir', ['root', 'd'], 'string', opts) || process.cwd();
42+
// https://github.com/postcss/postcss/blob/master/docs/api.md#processorprocesscss-opts
43+
lazyResultOpts = pick(opts, ['to']);
5144

52-
return void (plugins = opts.use);
45+
const customPlugins = get('use', ['u'], 'array', opts);
46+
if (customPlugins) {
47+
return void (plugins = customPlugins);
5348
}
5449

5550
plugins = [];
5651

57-
if (opts.mode) {
58-
if (typeof opts.mode !== 'string') {
59-
throw new Error('should specify string for mode');
60-
}
52+
const mode = get('mode', null, 'string', opts);
53+
plugins.push(mode
54+
? new LocalByDefault({mode: opts.mode})
55+
: LocalByDefault);
6156

62-
plugins.push(new LocalByDefault({mode: opts.mode}));
63-
} else {
64-
plugins.push(LocalByDefault);
65-
}
66-
67-
if (opts.createImportedName) {
68-
if (typeof opts.createImportedName !== 'function') {
69-
throw new Error('should specify function for createImportedName');
70-
}
71-
72-
plugins.push(new ExtractImports({createImportedName: opts.createImportedName}));
73-
} else {
74-
plugins.push(ExtractImports);
75-
}
76-
77-
if (opts.generateScopedName) {
78-
if (typeof opts.generateScopedName !== 'function') {
79-
throw new Error('should specify function for generateScopedName');
80-
}
57+
const createImportedName = get('createImportedName', null, 'function', opts);
58+
plugins.push(createImportedName
59+
? new ExtractImports({createImportedName: opts.createImportedName})
60+
: ExtractImports);
8161

82-
plugins.push(new Scope({generateScopedName: opts.generateScopedName}));
83-
} else {
84-
plugins.push(Scope);
85-
}
62+
const generateScopedName = get('generateScopedName', null, 'function', opts);
63+
plugins.push(generateScopedName
64+
? new Scope({generateScopedName: opts.generateScopedName})
65+
: Scope);
8666
}
8767

8868
/**
@@ -109,7 +89,7 @@ function fetch(_newPath, _sourcePath, _trace) {
10989
const CSSSource = preProcess(readFileSync(filename, 'utf8'));
11090

11191
const result = postcss(plugins.concat(new Parser({ fetch, trace })))
112-
.process(CSSSource, {from: rootRelativePath})
92+
.process(CSSSource, assign(lazyResultOpts, {from: rootRelativePath}))
11393
.root;
11494

11595
tokens = result.tokens;

src/utility.js

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import isArray from 'lodash.isarray';
2+
import isFunction from 'lodash.isfunction';
3+
import isString from 'lodash.isstring';
4+
import { format } from 'util';
5+
6+
const check = {
7+
'array': isArray,
8+
'function': isFunction,
9+
'string': isString,
10+
};
11+
12+
/**
13+
* @param {string} prop
14+
* @param {string[]} aliases
15+
* @param {string} type
16+
* @param {object} source
17+
* @return {*}
18+
*/
19+
export function get(prop, aliases, type, source) {
20+
if (source[prop]) {
21+
if (!is(type, source[prop])) {
22+
throw new Error(format('should specify %s for %s', type, prop));
23+
}
24+
25+
return source[prop];
26+
}
27+
28+
if (!isArray(aliases)) {
29+
return null;
30+
}
31+
32+
let deprecatedProp;
33+
const match = aliases.some(alias => Boolean(source[(deprecatedProp = alias)]));
34+
35+
if (match) {
36+
if (!is(type, source[deprecatedProp])) {
37+
throw new Error(format('should specify %s for %s', type, deprecatedProp));
38+
}
39+
40+
// deprecated message
41+
return source[deprecatedProp];
42+
}
43+
44+
return null;
45+
}
46+
47+
/**
48+
* @param {string} type
49+
* @param {*} value
50+
* @return {boolean}
51+
*/
52+
export function is(type, value) {
53+
return check[type](value);
54+
}
55+
56+
/**
57+
* @param {string} str
58+
* @return {string}
59+
*/
60+
export function removeQuotes(str) {
61+
return str.replace(/^["']|["']$/g, '');
62+
}

test/plugins.js

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,28 @@ import { equal } from 'assert';
22
import { identity } from 'lodash';
33
import hook from '../src';
44

5+
import ExtractImports from 'postcss-modules-extract-imports';
6+
import LocalByDefault from 'postcss-modules-local-by-default';
7+
import Scope from 'postcss-modules-scope';
8+
59
describe('plugins', () => {
610
describe('custom generateScopedName() function', () => {
7-
before(() => {
8-
hook({generateScopedName: identity});
11+
before(() => hook({generateScopedName: identity}));
12+
13+
it('tokens should have the same generated names', () => {
14+
const tokens = require('awesome-theme/oceanic.css');
15+
equal(tokens.color, 'color');
916
});
17+
});
18+
19+
describe('explicit way to set generateScopedName() function', () => {
20+
before(() => hook({
21+
use: [
22+
ExtractImports,
23+
LocalByDefault,
24+
new Scope({generateScopedName: identity}),
25+
],
26+
}));
1027

1128
it('tokens should have the same generated names', () => {
1229
const tokens = require('awesome-theme/oceanic.css');

test/utility.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { ok, equal, throws } from 'assert';
2+
import { get, is, removeQuotes } from '../src/utility';
3+
4+
describe('utility', () => {
5+
describe('get()', () => {
6+
it('should return value for an existing property', () => equal(get('a', null, 'string', {a: 'val'}), 'val'));
7+
8+
it('should return value for an existing alias', () => equal(get('a', ['b'], 'string', {b: 'val'}), 'val'));
9+
10+
it('should return null for a non-existing property', () => equal(get('a', null, 'array', {}), null));
11+
12+
it('should throw an error for the specified key with wrong type of value', () => {
13+
throws(() => get('a', null, 'string', {a: 5}));
14+
});
15+
});
16+
17+
describe('is()', () => {
18+
it('should return true for an array', () => ok(is('array', [])));
19+
20+
it('should return false for not an array', () => ok(!is('array', null)));
21+
22+
it('should return true for a function', () => ok(is('function', () => {})));
23+
24+
it('should return false for not a function', () => ok(!is('function', null)));
25+
26+
it('should return true for a string', () => ok(is('string', '')));
27+
28+
it('should return false for not a string', () => ok(!is('string', null)));
29+
});
30+
31+
describe('removeQuotes()', () => {
32+
it('should remove quotes', () => equal(removeQuotes('"TEST"'), 'TEST'));
33+
});
34+
});

0 commit comments

Comments
 (0)