diff --git a/CHANGELOG.md b/CHANGELOG.md index de1df41..7db935f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -208,6 +208,12 @@ $ npm i @bem/naming [#158]: https://github.com/bem-sdk/bem-naming/pull/158 +### Presets + +* Added react preset (@yeti-or [#161]). + +[#161]: https://github.com/bem-sdk/bem-naming/pull/161 + ### Performance * Accelerated initialization for `origin` naming (@tadatuta [#134]). diff --git a/README.md b/README.md index ed13045..92d54ce 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,7 @@ Table of Contents * [String representation](#string-representation) * [Common misconceptions](#common-misconceptions) * [Harry Roberts' naming convention](#harry-roberts-naming-convention) +* [React naming convention](#react-naming-convention) * [Custom naming convention](#custom-naming-convention) * [API](#api) @@ -129,6 +130,31 @@ twoDashesNaming.stringify({ // ➜ block__elem--mod ``` +React naming convention +----------------------- + +According to this convention elements are delimited with one hyphen (`-`), modifiers are delimited by one underscore (`_`), and values of modifiers are delimited by one underscore (`_`). + +You can explore this convention at [bem-react-components](https://github.com/bem/bem-react-components). + +Example: + +```js +const reactNaming = require('@bem/naming')('react'); + +reactNaming.parse('block-elem'); // BemEntityName { block: 'block', elem: 'elem' } +reactNaming.parse('block_mod_val'); // BemEntityName { block: 'block', + // mod: { name: 'mod', val: 'val' } } + +reactNaming.stringify({ + block: 'block', + elem: 'elem', + mod: 'mod' +}); + +// ➜ block-elem_mod +``` + Custom naming convention ------------------------ diff --git a/lib/presets/index.js b/lib/presets/index.js index a5524a8..39577f0 100644 --- a/lib/presets/index.js +++ b/lib/presets/index.js @@ -2,5 +2,6 @@ module.exports = { origin: require('./origin'), + react: require('./react'), 'two-dashes': require('./two-dashes') }; diff --git a/lib/presets/react.js b/lib/presets/react.js new file mode 100644 index 0000000..0c61cc0 --- /dev/null +++ b/lib/presets/react.js @@ -0,0 +1,9 @@ +'use strict'; + +module.exports = { + delims: { + elem: '-', + mod: { name: '_', val: '_' } + }, + wordPattern: '[a-zA-Z0-9]+' +}; diff --git a/test/presets/react/parse.test.js b/test/presets/react/parse.test.js new file mode 100644 index 0000000..82bf799 --- /dev/null +++ b/test/presets/react/parse.test.js @@ -0,0 +1,70 @@ +'use strict'; + +const test = require('ava'); +const naming = require('../../../index')('react'); +const parse = naming.parse; + +test('should not parse not valid string', t => { + const obj = parse('(*)(*)'); + + t.is(obj, undefined); +}); + +test('should parse block', t => { + const obj = parse('Block'); + + t.is(obj.block, 'Block'); +}); + +test('should parse mod of block', t => { + t.plan(3); + + const obj = parse('Block_mod_val'); + + t.is(obj.block, 'Block'); + t.is(obj.mod && obj.mod.name, 'mod'); + t.is(obj.mod && obj.mod.val, 'val'); +}); + +test('should parse boolean mod of block', t => { + t.plan(3); + + const obj = parse('block_mod'); + + t.is(obj.block, 'block'); + t.is(obj.mod && obj.mod.name, 'mod'); + + t.true(obj.mod && obj.mod.val); +}); + +test('should parse elem', t => { + t.plan(2); + + const obj = parse('Block-Elem'); + + t.is(obj.block, 'Block'); + t.is(obj.elem, 'Elem'); +}); + +test('should parse mod of elem', t => { + t.plan(4); + + const obj = parse('block-elem_mod_val'); + + t.is(obj.block, 'block'); + t.is(obj.elem, 'elem'); + t.is(obj.mod && obj.mod.name, 'mod'); + t.is(obj.mod && obj.mod.val, 'val'); +}); + +test('should parse boolean mod of elem', t => { + t.plan(4); + + const obj = parse('block-elem_mod'); + + t.is(obj.block, 'block'); + t.is(obj.elem, 'elem'); + t.is(obj.mod && obj.mod.name, 'mod'); + + t.true(obj.mod && obj.mod.val); +}); diff --git a/test/presets/react/stringify.test.js b/test/presets/react/stringify.test.js new file mode 100644 index 0000000..6a5748e --- /dev/null +++ b/test/presets/react/stringify.test.js @@ -0,0 +1,96 @@ +'use strict'; + +const test = require('ava'); +const naming = require('../../../index')('react'); +const stringify = naming.stringify; + +test('should stringify block', t => { + const str = stringify({ block: 'Block' }); + + t.is(str, 'Block'); +}); + +test('should stringify modifier of block', t => { + const str = stringify({ + block: 'Block', + mod: { name: 'mod', val: 'val' } + }); + + t.is(str, 'Block_mod_val'); +}); + +test('should stringify simple modifier of block', t => { + const str = stringify({ + block: 'block', + mod: 'mod' + }); + + t.is(str, 'block_mod'); +}); + +test('should stringify boolean modifier of block', t => { + const str = stringify({ + block: 'block', + mod: { name: 'mod', val: true }, + }); + + t.is(str, 'block_mod'); +}); + +test('should stringify block if modifier value is `undefined`', t => { + const str = stringify({ + block: 'block', + mod: { name: 'mod', val: undefined } + }); + + t.is(str, 'block'); +}); + +test('should stringify element', t => { + const str = stringify({ + block: 'Block', + elem: 'Elem' + }); + + t.is(str, 'Block-Elem'); +}); + +test('should stringify modifier of element', t => { + const str = stringify({ + block: 'block', + elem: 'elem', + mod: { name: 'mod', val: 'val' } + }); + + t.is(str, 'block-elem_mod_val'); +}); + +test('should stringify simple modifier of element', t => { + const str = stringify({ + block: 'block', + elem: 'elem', + mod: 'mod' + }); + + t.is(str, 'block-elem_mod'); +}); + +test('should stringify boolean modifier of element', t => { + const str = stringify({ + block: 'block', + elem: 'elem', + mod: { name: 'mod', val: true } + }); + + t.is(str, 'block-elem_mod'); +}); + +test('should stringify element if modifier value is `undefined`', t => { + const str = stringify({ + block: 'block', + elem: 'elem', + mod: { name: 'mod', val: undefined } + }); + + t.is(str, 'block-elem'); +});