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

Support custom modifier separator #76

Merged
merged 8 commits into from
Mar 24, 2016
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
44 changes: 30 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ API
* [`isElemMod(obj)`](#iselemmodobj)
* [`elemDelim`](#elemdelim)
* [`modDelim`](#moddelim)
* [`modValDelim`](#modvaldelim)

### `validate(str)`

Expand Down Expand Up @@ -316,7 +317,13 @@ String to separate elem from block.

### `modDelim`

String to separate names and values of modifiers from blocks and elements.
String to separate modifiers from blocks and elements.

-------------------------------------------------------------------------------

### `modValDelim`

String to separate value of modifier from name of modifier.

Custom naming convention
------------------------
Expand All @@ -325,22 +332,32 @@ Use `bemNaming` function to create instance to manage naming of your own naming

Function `bemNaming` gets the object from the following options:

* **String** `elem` — separates element's name from block. Default as `__`.
* **String** `mod` — separates names and values of modifiers from blocks and elements. Default as `_`.
* **String** `wordPattern` — defines which symbols can be used for block, element and modifier's names. Default as `[a-z0-9]+(?:-[a-z0-9]+)*`.
* **String** `elem` — separates element's name from block. Default as `__`.
* **String|Object** `mod` — separates modifiers from blocks and elements. Default as `_`.

This option can get object:

```js
{ name: String, val: String }
```

* **String** `name` — separates name of modifier from blocks and elements. Default as `_`.
* **String** `val` — separates value of modifier from name of modifier. Default as the value of the `name`.

* **String** `wordPattern` — defines which symbols can be used for block, element and modifier's names. Default as `[a-z0-9]+(?:-[a-z0-9]+)*`.

Example:

```js
var myNaming = bemNaming({
elem: '-',
mod: '--',
mod: { name: '--', val: '_' }
wordPattern: '[a-zA-Z0-9]+' // because element and modifier's separators include
}); // hyphen in it, we need to exclude it from block,
// element and modifier's name

myNaming.parse('block--mod'); // { block: 'block',
// modName: 'mod', modVal: true }
myNaming.parse('block--mod_val'); // { block: 'block',
// modName: 'mod', modVal: 'val' }

myNaming.stringify({ // 'blockName-elemName--boolElemMod'
block: 'blockName',
Expand All @@ -352,8 +369,7 @@ myNaming.stringify({ // 'blockName-elemName--boolElemMod'
Convention by Harry Roberts
---------------------------

According to this convention elements are delimited with two underscores (__), and boolean modifiers are delimited by two hyphens (--).
Key-value modifiers are not used.
According to this convention elements are delimited with two underscores (`__`), modifiers are delimited by two hyphens (`--`), and values of modifiers are delimited by one underscore (`_`).

Read more in the [Guidelines](http://cssguidelin.es/#bem-like-naming).

Expand All @@ -362,14 +378,14 @@ Example:
```js
var csswizardry = bemNaming({
elem: '__',
mod: '--'
mod: { name: '--', val: '_' }
});

csswizardry.parse('block__elem'); // { block: 'block', elem: 'elem' }
csswizardry.parse('block--mod'); // { block: 'block',
// modName: 'mod', modVal: true }
csswizardry.parse('block__elem'); // { block: 'block', elem: 'elem' }
csswizardry.parse('block--mod_val'); // { block: 'block',
// modName: 'mod', modVal: 'val' }

csswizardry.stringify({ // 'block__elem--mod'
csswizardry.stringify({ // 'block__elem--mod'
block: 'block',
elem: 'elem',
modName: 'mod'
Expand Down
45 changes: 31 additions & 14 deletions README.ru.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ API
* [`isElemMod(obj)`](#iselemmodobj)
* [`elemDelim`](#elemdelim)
* [`modDelim`](#moddelim)
* [`modValDelim`](#modvaldelim)

### `validate(str)`

Expand Down Expand Up @@ -312,11 +313,17 @@ bemNaming.isElemMod({ block: 'block',

Строка для разделения элемента от блока.

<hr/>
-------------------------------------------------------------------------------

### `modDelim`

Строка для разделения названия и значения модификатора от блока и элемента.
Строка для разделения модификатора от блока и элемента.

-------------------------------------------------------------------------------

### `modValDelim`

Строка для разделения значения модификатора от названия модификатора.

Собственный стиль
-----------------
Expand All @@ -325,22 +332,32 @@ bemNaming.isElemMod({ block: 'block',

Функция принимает объект из следующих опций:

* **String** `elem` — отделяет имя элемента от блока. По&nbsp;умолчанию&nbsp;—&nbsp;`__`.
* **String** `mod` — отделяет названия и значения модификаторов от блоков и элементов. По&nbsp;умолчанию&nbsp;—&nbsp;`_`.
* **String** `wordPattern` — определяет, какие символы могут быть использованы в именах блоков, элементов и модификаторов. По умолчанию&nbsp;—&nbsp;`[a-z0-9]+(?:-[a-z0-9]+)*`.
* **String** `elem` — отделяет имя элемента от блока. По умолчанию — `__`.
* **String|Object** `mod` — отделяет модификаторы от блоков и элементов. По умолчанию — `_`.

Опция может принимать объект вида:

```js
{ name: String, val: String }
```

* **String** `name` — отделяет название модификатора от блоков и элементов. По умолчанию — `_`.
* **String** `val` — отделяет значение модификатора от имени модификатора. По умолчанию принимает значение опции `name`.

* **String** `wordPattern` — определяет, какие символы могут быть использованы в именах блоков, элементов и модификаторов. По умолчанию — `[a-z0-9]+(?:-[a-z0-9]+)*`.

Пример:

```js
var myNaming = bemNaming({
elem: '-',
mod: '--',
mod: { name: '--', val: '_' },
wordPattern: '[a-zA-Z0-9]+' // т.к. сепараторы элемента и модификатора включают
}); // в себя дефис, исключим его из имён блоков,
// элементов и модификаторов

myNaming.parse('block--mod'); // { block: 'block',
// modName: 'mod', modVal: true }
myNaming.parse('block--mod_val'); // { block: 'block',
// modName: 'mod', modVal: 'val' }

myNaming.stringify({ // 'blockName-elemName--boolElemMod'
block: 'blockName',
Expand All @@ -352,7 +369,7 @@ myNaming.stringify({ // 'blockName-elemName--boolElemMod'
В стиле Гарри Робертса
----------------------

Согласно этому соглашению элементы отделяются от&nbsp;блока с&nbsp;помощью двух символов подчёркивания (__), а&nbsp;булевые модификаторы с&nbsp;помощью двух символов дефиса (--). Модификаторы вида ключ-значение не&nbsp;используются.
Согласно этому соглашению элементы отделяются от блока с помощью двух символов подчёркивания (`__`), модификаторы с помощью двух символов дефиса (`--`), а значения модификаторов с помощью одного символа подчёркивания (`_`).

Подробнее читайте в [руководстве](http://cssguidelin.es/#bem-like-naming).

Expand All @@ -361,14 +378,14 @@ myNaming.stringify({ // 'blockName-elemName--boolElemMod'
```js
var csswizardry = bemNaming({
elem: '__',
mod: '--'
mod: { name: '--', val: '_' }
});

csswizardry.parse('block__elem'); // { block: 'block', elem: 'elem' }
csswizardry.parse('block--mod'); // { block: 'block',
// modName: 'mod', modVal: true }
csswizardry.parse('block__elem'); // { block: 'block', elem: 'elem' }
csswizardry.parse('block--mod_val'); // { block: 'block',
// modName: 'mod', modVal: `val` }

csswizardry.stringify({ // 'block__elem--mod'
csswizardry.stringify({ // 'block__elem--mod'
block: 'block',
elem: 'elem',
modName: 'mod'
Expand Down
34 changes: 27 additions & 7 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ var TYPES = {
* @param {Object} options Options.
* @param {String} options.elem Separates element's name from block.
* @param {String} options.mod Separates names and values of modifiers from blocks and elements.
* @param {String} options.modVal Separates separate value of modifier from name of modifier.
* @param {String} options.wordPattern Defines which symbols can be used for block, element and modifier's names.
* @name BemNaming
* @class
Expand All @@ -33,11 +34,17 @@ function BemNaming(options) {
*/
this.elemDelim = options.elem;
/**
* String to separate names and values of modifiers from blocks and elements.
* String to separate modifiers from blocks and elements.
*
* @type {String}
*/
this.modDelim = options.mod;
this.modDelim = options.modName;
/**
* String to separate value of modifier from name of modifier.
*
* @type {String}
*/
this.modValDelim = options.modVal;

this._wordPattern = options.wordPattern;
this._buildRegex();
Expand Down Expand Up @@ -172,7 +179,7 @@ BemNaming.prototype.stringify = function (obj) {
}

if (modVal && modVal !== true) {
res += this.modDelim + modVal;
res += this.modValDelim + modVal;
}
}

Expand All @@ -183,8 +190,9 @@ BemNaming.prototype._buildRegex = function () {
var word = this._wordPattern,
block = '(' + word + ')',
elem = '(?:' + this.elemDelim + '(' + word + '))?',
modPart = '(?:' + this.modDelim + '(' + word + '))?',
mod = modPart + modPart;
modName = '(?:' + this.modDelim + '(' + word + '))?',
modVal = '(?:' + this.modValDelim + '(' + word + '))?',
mod = modName + modVal;

this._regex = new RegExp('^' + block + mod + '$|^' + block + elem + mod + '$');
};
Expand All @@ -196,13 +204,25 @@ var defineAsGlobal = true,
'parse', 'stringify',
'isBlock', 'isElem', 'isBlockMod', 'isElemMod'
],
fields = ['elemDelim', 'modDelim'],
fields = ['elemDelim', 'modDelim', 'modValDelim'],
bemNaming = function (options) {
options || (options = {});

var mod = options.mod || '_',
modName, modVal;

if (typeof mod === 'string') {
modName = mod;
modVal = mod;
} else {
modName = mod.name || '_';
modVal = mod.val || modName;
}

var naming = {
elem: options.elem || '__',
mod: options.mod || '_',
modName: modName,
modVal: modVal,
wordPattern: options.wordPattern || '[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*'
},
id = JSON.stringify(naming);
Expand Down
25 changes: 25 additions & 0 deletions test/defaults.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
'use strict';

const test = require('ava');
const naming = require('../index');

test('should be elem delim by default', t => {
const instance1 = naming({ elem: '__' });
const instance2 = naming();

t.is(instance1, instance2);
});

test('should be mod delim by default', t => {
const instance1 = naming({ mod: { name: '_' } });
const instance2 = naming();

t.is(instance1, instance2);
});

test('should be mod value delim by default', t => {
const instance1 = naming({ mod: { val: '_' } });
const instance2 = naming();

t.is(instance1, instance2);
});
10 changes: 10 additions & 0 deletions test/fields.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ test('should have modDelim field', t => {
t.ok(naming.modDelim);
});

test('should have modValDelim field', t => {
t.ok(naming.modValDelim);
});

test('should create namespace with elemDelim field', t => {
const myNaming = naming();

Expand All @@ -22,3 +26,9 @@ test('should create namespace with modDelim field', t => {

t.ok(myNaming.modDelim);
});

test('should create namespace with modValDelim field', t => {
const myNaming = naming();

t.ok(myNaming.modValDelim);
});
31 changes: 31 additions & 0 deletions test/options.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
'use strict';

const test = require('ava');
const naming = require('../index');

test('should provide elem option', t => {
const myNaming = naming({ elem: '==' });

t.is(myNaming.elemDelim, '==');
});

test('should support mod option as string', t => {
const myNaming = naming({ mod: '--' });

t.is(myNaming.modDelim, '--');
t.is(myNaming.modValDelim, '--');
});

test('should support mod option as object', t => {
const myNaming = naming({ mod: { name: '--', val: '_' } });

t.is(myNaming.modDelim, '--');
t.is(myNaming.modValDelim, '_');
});

test('should use modDelim if mod.val is not specified', t => {
const myNaming = naming({ mod: { name: '--' } });

t.is(myNaming.modDelim, '--');
t.is(myNaming.modValDelim, '--');
});
6 changes: 5 additions & 1 deletion test/presets/harry-roberts/is-block-mod.test.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
'use strict';

const test = require('ava');
const naming = require('../../../index')({ elem: '__', mod: '--' });
const naming = require('../../../index')({ elem: '__', mod: { name: '--', val: '_' } });

test('should detect mod of block', t => {
t.true(naming.isBlockMod('block--mod_val'));
});

test('should detect boolean mod of block', t => {
t.true(naming.isBlockMod('block--mod'));
});
6 changes: 5 additions & 1 deletion test/presets/harry-roberts/is-elem-mod.test.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
'use strict';

const test = require('ava');
const naming = require('../../../index')({ elem: '__', mod: '--' });
const naming = require('../../../index')({ elem: '__', mod: { name: '--', val: '_' } });

test('should detect mod of elem', t => {
t.true(naming.isElemMod('block__elem--mod_val'));
});

test('should detect boolean mod of elem', t => {
t.true(naming.isElemMod('block__elem--mod'));
});
2 changes: 1 addition & 1 deletion test/presets/harry-roberts/is-elem.test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use strict';

const test = require('ava');
const naming = require('../../../index')({ elem: '__', mod: '--' });
const naming = require('../../../index')({ elem: '__', mod: { name: '--', val: '_' } });

test('should detect elem', t => {
t.true(naming.isElem('block__elem'));
Expand Down
Loading