Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

camelCase #90

Merged
merged 4 commits into from
Mar 20, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,13 @@ charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[GNUmakefile]
indent_style = tab

[Makefile]
indent_style = tab

[makefile]
indent_style = tab

# cheat sheet: http://EditorConfig.org
35 changes: 5 additions & 30 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,30 +1,5 @@
# Logs
logs
*.log

# Runtime data
pids
*.pid
*.seed

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# node-waf configuration
.lock-wscript

# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release

# Dependency directory
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
node_modules/*

# added automatically by precommit-hook as defaults
.jshint*
.DS_Store
.npm
node_modules
npm-debug.log*
yarn.lock
3 changes: 2 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
language: node_js
node_js:
- "4.3"
- "4"
- "6"
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,10 +206,12 @@ hook({
});
```

### `camelCase boolean`
### `camelCase boolean|string`

Camelizes exported class names. Similar to [css-loader?camelCase](https://github.com/webpack/css-loader#camel-case).

Available options: `true`, `dashes`, `only`, `dashesOnly`.

### `append` array

Appends custom plugins to the end of the PostCSS pipeline. Since the `require` function is synchronous, you should provide synchronous plugins only.
Expand Down
2 changes: 2 additions & 0 deletions lib/attachHook.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
'use strict';

/**
* @param {function} compile
* @param {string} extension
Expand Down
30 changes: 14 additions & 16 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
const assign = require('lodash').assign;
'use strict';

const {assign, identity, negate, camelCase: camelCaseFunc, mapKeys} = require('lodash');
const {dirname, relative, resolve} = require('path');
const {readFileSync} = require('fs');
const {transformTokens} = require('./transformTokens');

const attachHook = require('./attachHook');
const dirname = require('path').dirname;
const genericNames = require('generic-names');
const globToRegex = require('glob-to-regexp');
const identity = require('lodash').identity;
const negate = require('lodash').negate;
const camelCaseFunc = require('lodash').camelCase;
const mapKeys = require('lodash').mapKeys;
const readFileSync = require('fs').readFileSync;
const relative = require('path').relative;
const resolve = require('path').resolve;
const validate = require('./validate');

const postcss = require('postcss');
Expand All @@ -23,13 +21,13 @@ const debugFetch = require('debug')('css-modules:fetch');
const debugSetup = require('debug')('css-modules:setup');

module.exports = function setupHook({
camelCase,
devMode,
extensions = '.css',
ignore,
preprocessCss = identity,
processCss,
processorOpts,
camelCase,
append = [],
prepend = [],
createImportedName,
Expand Down Expand Up @@ -89,7 +87,6 @@ module.exports = function setupHook({
? require.resolve(_to)
: resolve(dirname(from), _to);


// checking cache
let tokens = tokensByFile[filename];
if (tokens) {
Expand All @@ -107,10 +104,6 @@ module.exports = function setupHook({

tokens = lazyResult.root.tokens;

if (camelCase) {
tokens = assign(mapKeys(tokens, (value, key) => camelCaseFunc(key)), tokens);
}

if (!debugMode) {
// updating cache
tokensByFile[filename] = tokens;
Expand All @@ -132,8 +125,13 @@ module.exports = function setupHook({
const exts = toArray(extensions);
const isException = buildExceptionChecker(ignore);

const hook = filename => {
const tokens = fetch(filename, filename);
return camelCase ? transformTokens(tokens, camelCase) : tokens;
};

// @todo add possibility to specify particular config for each extension
exts.forEach(extension => attachHook(filename => fetch(filename, filename), extension, isException));
exts.forEach(extension => attachHook(hook, extension, isException));
};

/**
Expand Down
63 changes: 63 additions & 0 deletions lib/transformTokens.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
'use strict';

const {assign, camelCase, reduce} = require('lodash');

const camelizeKeys = (acc, value, key) => {
const camelizedKey = camelCase(key);
if (camelizedKey !== key) acc[camelizedKey] = value;
return acc;
};

const camelizeDashedKeys = (acc, value, key) => {
const camelizedKey = camelizeDashes(key);
if (camelizedKey !== key) acc[camelizedKey] = value;
return acc;
};

const camelizeOnlyKeys = (acc, value, key) => {
const camelizedKey = camelCase(key);
if (camelizedKey !== key) acc[camelizedKey] = value
else acc[key] = value;
return acc;
};

const camelizeOnlyDashedKeys = (acc, value, key) => {
const camelizedKey = camelizeDashes(key);
if (camelizedKey !== key) acc[camelizedKey] = value
else acc[key] = value;
return acc;
};

exports.camelizeDashes = camelizeDashes;
exports.transformTokens = transformTokens;

/**
* @param {string} str
* @return {string}
*/
function camelizeDashes(str) {
return str.replace(/-(\w)/g, (m, letter) => letter.toUpperCase());
}

/**
* @param {object} tokens
* @param {boolean|string} camelCase 'dashes|dashesOnly|only'
* @return {object}
*/
function transformTokens(tokens, camelCase) {
switch (camelCase) {
case true:
return reduce(tokens, camelizeKeys, assign({}, tokens));

case 'dashes':
return reduce(tokens, camelizeDashedKeys, assign({}, tokens));

case 'dashesOnly':
return reduce(tokens, camelizeOnlyDashedKeys, {});

case 'only':
return reduce(tokens, camelizeOnlyKeys, {});
}

return tokens;
}
30 changes: 20 additions & 10 deletions lib/validate.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
const difference = require('lodash').difference;
const forEach = require('lodash').forEach;
const keys = require('lodash').keys;
'use strict';

const {
difference,
forEach,
isArray,
isBoolean,
isFunction,
isPlainObject,
isRegExp,
isString,
keys,
} = require('lodash');

const rules = {
// hook
camelCase: 'boolean|string',
devMode: 'boolean',
extensions: 'array|string',
ignore: 'function|regex|string',
preprocessCss: 'function',
processCss: 'function',
processorOpts: 'object',
camelCase: 'boolean',
// plugins
append: 'array',
prepend: 'array',
Expand All @@ -23,12 +33,12 @@ const rules = {
};

const tests = {
array: require('lodash').isArray,
boolean: require('lodash').isBoolean,
function: require('lodash').isFunction,
object: require('lodash').isPlainObject,
regex: require('lodash').isRegExp,
string: require('lodash').isString,
array: isArray,
boolean: isBoolean,
function: isFunction,
object: isPlainObject,
regex: isRegExp,
string: isString,
};

module.exports = function validate(options) {
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
"test": "npm run test:babel",
"test:babel": "NODE_PATH=$(pwd)/test/tokens/node_modules $npm_package_scripts_test_unit --compilers js:babel-register",
"test:coverage": "NODE_PATH=$(pwd)/test/tokens/node_modules babel-node --presets es2015 `npm bin`/isparta cover --report text --report html `npm bin`/_mocha -- --require test/setup.js --ui tdd test/*/*.js",
"test:node": "NODE_PATH=$(pwd)/test/tokens/node_modules $npm_package_scripts_test_unit --use_strict",
"test:watch": "NODE_PATH=$(pwd)/test/tokens/node_modules $npm_package_scripts_test_unit --watch --use_strict",
"test:node": "NODE_PATH=$(pwd)/test/tokens/node_modules $npm_package_scripts_test_unit",
"test:watch": "NODE_PATH=$(pwd)/test/tokens/node_modules $npm_package_scripts_test_unit --watch",
"test:unit": "mocha --require test/setup.js --ui tdd test/*/*.js"
},
"repository": {
Expand Down
2 changes: 2 additions & 0 deletions preset.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
'use strict';

const basename = require('path').basename;
const debug = require('debug')('css-modules:preset');
const dirname = require('path').dirname;
Expand Down
36 changes: 27 additions & 9 deletions test/api/camelCase.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,36 @@ const detachHook = require('../sugar').detachHook;
const dropCache = require('../sugar').dropCache;

suite('api/camelCase', () => {
test('should add camel case keys in token', () => {
const tokens = require('./fixture/bem.css');
assert.deepEqual(tokens, {
blockElementModifier: '_test_api_fixture_bem__block__element--modifier',
'block__element--modifier': '_test_api_fixture_bem__block__element--modifier',
suite('-> `true`', () => {
test('should add camel case keys in token', () => {
const tokens = require('./fixture/bem.css');
assert.deepEqual(tokens, {
blockElementModifier: '_test_api_fixture_bem__block__element--modifier',
'block__element--modifier': '_test_api_fixture_bem__block__element--modifier',
});
});

setup(() => hook({ camelCase: true }));

teardown(() => {
detachHook('.css');
dropCache('./api/fixture/bem.css');
});
});

setup(() => hook({ camelCase: true }));
suite('-> `dashesOnly`', () => {
test('should replace keys with dashes by its camel-cased equivalent', () => {
const tokens = require('./fixture/bem.css');
assert.deepEqual(tokens, {
'block__element-Modifier': '_test_api_fixture_bem__block__element--modifier',
});
});

setup(() => hook({camelCase: 'dashesOnly'}));

teardown(() => {
detachHook('.css');
dropCache('./api/fixture/bem.css');
teardown(() => {
detachHook('.css');
dropCache('./api/fixture/bem.css');
});
});
});
65 changes: 65 additions & 0 deletions test/lib/transformTokens.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
'use strict';

const {camelizeDashes, transformTokens} = require('../../lib/transformTokens');

suite('lib/transformTokens', () => {
test('camelizeDashes', () => {
assert.equal(camelizeDashes(''), '');
assert.equal(camelizeDashes('a-a'), 'aA');
assert.equal(camelizeDashes('a-a-b'), 'aAB');
assert.equal(camelizeDashes('a-'), 'a-');
});

suite('transformTokens', () => {
test('`true -> should transform all the keys to CC, keeps original keys', () => {
assert.deepEqual(transformTokens({
'k-e-bab': 'kebab case',
's_na_ke': 'snake case',
'simple': 'aaa',
}, true), {
'k-e-bab': 'kebab case',
's_na_ke': 'snake case',
'simple': 'aaa',
'kEBab': 'kebab case',
'sNaKe': 'snake case',
});
});

test('`dashes` -> should transform the keys with dashed, keeps original keys', () => {
assert.deepEqual(transformTokens({
'k-e-bab': 'kebab case',
's_na_ke': 'snake case',
'simple': 'aaa',
}, 'dashes'), {
'k-e-bab': 'kebab case',
's_na_ke': 'snake case',
'simple': 'aaa',
'kEBab': 'kebab case',
});
});

test('`dashesOnly` -> should transform only keys with dashes', () => {
assert.deepEqual(transformTokens({
'k-e-bab': 'kebab case',
's_na_ke': 'snake case',
'simple': 'aaa',
}, 'dashesOnly'), {
's_na_ke': 'snake case',
'simple': 'aaa',
'kEBab': 'kebab case',
});
});

test('`only` -> should camelize keys', () => {
assert.deepEqual(transformTokens({
'k-e-bab': 'kebab case',
's_na_ke': 'snake case',
'simple': 'aaa',
}, 'only'), {
'simple': 'aaa',
'kEBab': 'kebab case',
'sNaKe': 'snake case',
});
});
});
});