Skip to content

Commit

Permalink
Merge de12650 into de78b58
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrew Abramov committed Nov 8, 2014
2 parents de78b58 + de12650 commit fbf062b
Show file tree
Hide file tree
Showing 5 changed files with 309 additions and 33 deletions.
36 changes: 34 additions & 2 deletions README.md
Expand Up @@ -10,7 +10,7 @@ This tool allows getting information about BEM entity using [string](#string-rep

String representation
---------------------
To define BEM-entities we often use a special string format that allows us 100% define what entity exactly is represented.
To define BEM entities we often use a special string format that allows us 100% define what entity exactly is represented.

According to original BEM-naming convention it looks like the following:

Expand Down Expand Up @@ -45,7 +45,7 @@ Also there is no such BEM entity as a modifier and an element modifier simultane
BEM-naming
----------

BEM-entities can be defined with a help of js-object with the following fields:
BEM entities can be defined with a help of js-object with the following fields:

* `block` — a block name. The field is required because only a block exists as an independent BEM entity
* `elem` — an element name.
Expand Down Expand Up @@ -103,6 +103,8 @@ API
* [`validate(str)`](#validatestr)
* [`parse(str)`](#parsestr)
* [`stringify(obj)`](#stringifyobj)
* [`typeOf(str)`](#typeofstr)
* [`typeOf(obj)`](#typeofobj)
* [`isBlock(str)`](#isblockstr)
* [`isBlock(obj)`](#isblockobj)
* [`isBlockMod(str)`](#isblockmodstr)
Expand Down Expand Up @@ -153,6 +155,36 @@ bemNaming.stringify({

<hr/>

### `typeOf(str)`

Returns a string indicating the type of the BEM entity.

Example:

```js
bemNaming.typeOf('block'); // block
bemNaming.typeOf('block_mod'); // blockMod
bemNaming.typeOf('block__elem'); // elem
bemNaming.typeOf('block__elem_mod'); // elemMod
```

<hr/>

### `typeOf(obj)`

Returns a string indicating the type of the BEM entity.

Example:

```js
bemNaming.isBlock({ block: 'block' }); // block
bemNaming.isBlock({ block: 'block', modName: 'mod' }); // blockMod
bemNaming.isBlock({ block: 'block', elem: 'elem' }); // elem
bemNaming.isBlock({ block: 'block', elem: 'elem' }); // elemMod
```

<hr/>

### `isBlock(str)`

Checks whether string `str` is a block.
Expand Down
32 changes: 32 additions & 0 deletions README.ru.md
Expand Up @@ -103,6 +103,8 @@ API
* [`validate(str)`](#validatestr)
* [`parse(str)`](#parsestr)
* [`stringify(obj)`](#stringifyobj)
* [`typeOf(str)`](#typeofstr)
* [`typeOf(obj)`](#typeofobj)
* [`isBlock(str)`](#isblockstr)
* [`isBlock(obj)`](#isblockobj)
* [`isBlockMod(str)`](#isblockmodstr)
Expand Down Expand Up @@ -153,6 +155,36 @@ bemNaming.stringify({

<hr/>

### `typeOf(str)`

Возвращает строку, указывающую тип БЭМ-сущности.

Пример:

```js
bemNaming.typeOf('block'); // block
bemNaming.typeOf('block_mod'); // blockMod
bemNaming.typeOf('block__elem'); // elem
bemNaming.typeOf('block__elem_mod'); // elemMod
```

<hr/>

### `typeOf(obj)`

Возвращает строку, указывающую тип БЭМ-сущности.

Пример:

```js
bemNaming.isBlock({ block: 'block' }); // block
bemNaming.isBlock({ block: 'block', modName: 'mod' }); // blockMod
bemNaming.isBlock({ block: 'block', elem: 'elem' }); // elem
bemNaming.isBlock({ block: 'block', elem: 'elem' }); // elemMod
```

<hr/>

### `isBlock(str)`

Проверяет обозначает ли строка `str` блок.
Expand Down
94 changes: 63 additions & 31 deletions lib/bem-naming.js
@@ -1,18 +1,30 @@
(function (global) {
/**
* BEMNaming allows getting information about BEM-entity using string as well as forming string
* Enum for types of BEM entities.
*
* @readonly
* @enum {String}
*/
var TYPES = {
BLOCK: 'block',
BLOCK_MOD: 'blockMod',
ELEM: 'elem',
ELEM_MOD: 'elemMod'
};

/**
* BEMNaming allows getting information about BEM entity using string as well as forming string
* representation based on BEM-naming.
*
* @param {Object} [options]
* @param {Object} [options.elem='__'] Separates element's name from block.
* @param {Object} [options.mod='_'] Separates names and values of modifiers from blocks and elements.
* @param {Object} [options.wordPattern='[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*] Defines which symbols can be used for block,
* element and modifier's names.
*
* @name BEMNaming
* @constructor
* @class
*/
var BEMNaming = function (options) {
function BEMNaming(options) {
options || (options = {});

this._elemDelimiter = options.elem || options.elemSeparator || '__';
Expand All @@ -21,70 +33,97 @@ var BEMNaming = function (options) {
'[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*';

this._buildRegex();
};
}

/**
* Checks a string to be valid BEM notation.
*
* @param {String} str String representation of BEM-entity.
* @param {String} str String representation of BEM entity.
* @returns {Boolean}
*/
BEMNaming.prototype.validate = function (str) {
return this._regex.test(str);
};

/**
* Returns a string indicating the type of the BEM entity.
*
* @param {Object|String} obj BEM-naming object or string representation of BEM entity.
* @returns {String}
*/
BEMNaming.prototype.typeOf = function (obj) {
if (typeof obj === 'string') {
obj = this.parse(obj);
}

if (!obj || !obj.block) { return; }

var hasModVal = obj.hasOwnProperty('modVal'),
isMod = obj.modName && (!hasModVal || obj.modVal);

if (obj.elem) {
if (isMod) {
return TYPES.ELEM_MOD;
}

if (!hasModVal) {
return TYPES.ELEM;
}
}

if (isMod) {
return TYPES.BLOCK_MOD;
}

if (!hasModVal) {
return TYPES.BLOCK;
}
};

/**
* Checks whether BEM-naming object or string is a block.
*
* @param {Object|String} obj BEM-naming object or string representation of BEM-entity.
* @param {Object|String} obj BEM-naming object or string representation of BEM entity.
* @returns {Boolean}
*/
BEMNaming.prototype.isBlock = function (obj) {
obj = this._parse(obj);

return !!obj.block && !obj.modName && !obj.elem;
return this.typeOf(obj) === TYPES.BLOCK;
};

/**
* Checks whether BEM-naming object or string is modifier of a block.
*
* @param {Object|String} obj BEM-naming object or string representation of BEM-entity.
* @param {Object|String} obj BEM-naming object or string representation of BEM entity.
* @returns {Boolean}
*/
BEMNaming.prototype.isBlockMod = function (obj) {
obj = this._parse(obj);

return !!(obj.block && obj.modName && (!obj.hasOwnProperty('modVal') || obj.modVal)) && !obj.elem;
return this.typeOf(obj) === TYPES.BLOCK_MOD;
};

/**
* Checks whether BEM-naming object or string is element of a block.
*
* @param {Object|String} obj BEM-naming object or string representation of BEM-entity.
* @param {Object|String} obj BEM-naming object or string representation of BEM entity.
* @returns {Boolean}
*/
BEMNaming.prototype.isElem = function (obj) {
obj = this._parse(obj);

return !!(obj.block && obj.elem) && !obj.modName;
return this.typeOf(obj) === TYPES.ELEM;
};

/**
* Checks whether BEM-naming object or string is element of a block.
*
* @param {Object|String} obj BEM-naming object or string representation of BEM-entity.
* @param {Object|String} obj BEM-naming object or string representation of BEM entity.
* @returns {Boolean}
*/
BEMNaming.prototype.isElemMod = function (obj) {
obj = this._parse(obj);

return !!(obj.block && obj.elem && obj.modName && (!obj.hasOwnProperty('modVal') || obj.modVal));
return this.typeOf(obj) === TYPES.ELEM_MOD;
};

/**
* Parses string into BEM-naming.
*
* @param {String} str String representation of BEM-entity.
* @param {String} str String representation of BEM entity.
* @returns {Object|undefined}
*/
BEMNaming.prototype.parse = function (str) {
Expand Down Expand Up @@ -152,14 +191,6 @@ BEMNaming.prototype._buildRegex = function () {
this._regex = new RegExp(['^', block, mod, mod, '$|^', block, elem, mod, mod, '$'].join(''));
};

BEMNaming.prototype._parse = function (obj) {
if (typeof obj === 'string') {
obj = this.parse(obj);
}

return obj || {};
};

var defineAsGlobal = true,
originalNaming = new BEMNaming(),
bemNaming = function (options) {
Expand All @@ -170,6 +201,7 @@ bemNaming.BEMNaming = BEMNaming;
bemNaming.validate = function () { return originalNaming.validate.apply(originalNaming, arguments); };
bemNaming.parse = function () { return originalNaming.parse.apply(originalNaming, arguments); };
bemNaming.stringify = function () { return originalNaming.stringify.apply(originalNaming, arguments); };
bemNaming.typeOf = function () { return originalNaming.typeOf.apply(originalNaming, arguments); };
bemNaming.isBlock = function () { return originalNaming.isBlock.apply(originalNaming, arguments); };
bemNaming.isElem = function () { return originalNaming.isElem.apply(originalNaming, arguments); };
bemNaming.isBlockMod = function () { return originalNaming.isBlockMod.apply(originalNaming, arguments); };
Expand Down
90 changes: 90 additions & 0 deletions test/harry-roberts/typeOf.test.js
@@ -0,0 +1,90 @@
var demand = require('should'),
naming = require('../../lib/bem-naming')({ elem: '__', mod: '--' });

describe('harry roberts', function () {
describe('typeOf', function () {
it('should not determine undefined', function () {
var type = naming.typeOf(undefined);

demand(type).be.undefined;
});

it('should not determine empty object', function () {
var type = naming.typeOf({});

demand(type).be.undefined;
});

it('should not determine not valid string', function () {
var type = naming.typeOf('(*)_(*)');

demand(type).be.undefined;
});

it('should not determine not valid object', function () {
var type = naming.typeOf({ elem: 'elem' });

demand(type).be.undefined;
});

it('should determine block by string', function () {
naming.typeOf('block').should.equal('block');
});

it('should determine block by object', function () {
var notation = { block: 'block' };

naming.typeOf(notation).should.equal('block');
});

it('should determine mod of block by string', function () {
naming.typeOf('block--mod--val').should.equal('blockMod');
});

it('should determine mod of block by object', function () {
var notation = { block: 'block', modName: 'mod', modVal: 'val' };

naming.typeOf(notation).should.equal('blockMod');
});

it('should determine boolean mod of block by string', function () {
naming.typeOf('block--mod').should.equal('blockMod');
});

it('should determine boolean mod of block by object', function () {
var notation = { block: 'block', modName: 'mod', modVal: true };

naming.typeOf(notation).should.equal('blockMod');
});

it('should determine elem by string', function () {
naming.typeOf('block__elem').should.equal('elem');
});

it('should determine elem by object', function () {
var notation = { block: 'block', elem: 'elem' };

naming.typeOf(notation).should.equal('elem');
});

it('should determine mod of elem by string', function () {
naming.typeOf('block__elem--mod--value').should.equal('elemMod');
});

it('should determine mod of elem by object', function () {
var notation = { block: 'block', elem: 'elem', modName: 'mod', modVal: 'val' };

naming.typeOf(notation).should.equal('elemMod');
});

it('should determine boolean mod of elem by string', function () {
naming.typeOf('block__elem--mod').should.equal('elemMod');
});

it('should determine boolean mod of elem by object', function () {
var notation = { block: 'block', elem: 'elem', modName: 'mod', modVal: true };

naming.typeOf(notation).should.equal('elemMod');
});
});
});

0 comments on commit fbf062b

Please sign in to comment.