Skip to content
Closed
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
29 changes: 22 additions & 7 deletions packages/import-notation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,14 @@ API

* [parse](#parsestr-ctx)
* [stringify](#stringify)
* [expand](#parsestr-ctx)

### parse(str, ctx)

Parameter | Type | Description
----------|----------|--------------------------------------------------------
`str` | `string` | BEM import notation check [notation section](#notation)
`ctx` | `object` | BEM entity name representation.
`[ctx]` | `object` | BEM entity name representation

Parses the string into BEM entities.

Expand All @@ -58,19 +59,16 @@ entity.elem // → 'text'

#### ctx

Context allows to extract portion of entities.
Context allows to use short form of notation.

```js
var enties = parse('m:theme=normal', { block: 'button' });

// → [ { block: 'button', mod: { name: 'theme' } },
// → [ { block: 'button' },
// { block: 'button', mod: { name: 'theme' } },
// { block: 'button', mod: { name: 'theme', val: 'normal' } } ]
```

Note that, using context exludes `{ block: 'button'}` from result.

So `parse('m:theme=normal', { block: 'button' })` is not same as `parse('b:button m:theme=normal')`

### stringify

Parameter | Type | Description
Expand All @@ -80,6 +78,23 @@ Parameter | Type | Description
Forms a string from [BEM entities]. Be aware to merge only one type of entities.
The array should contains one block or one elem and optionally it's modifiers.

### expand(str, ctx)

Parameter | Type | Description
----------|----------|--------------------------------------------------------
`str` | `string` | BEM import notation check [notation section](#notation)
`ctx` | `object` | BEM entity name representation

Expand notation string to full form by context BEM entity.

Example:

```js
var notation = parse('e:text', { block: 'button' });

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

expand?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, I didn't understand the difference from parse method.
Actually, I understood but it was not so obvious
add examples of the distinction between them, please

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure we need 2 methods? ;-)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure! expand gives us string and it is fast/lightweight

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure expand is the most viable name for this functionality?

I'd suggest:

  • fullfill
  • fillup
  • sate


// → 'b:button e:text'
```

Notation
--------

Expand Down
95 changes: 40 additions & 55 deletions packages/import-notation/index.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,7 @@
const hashSet = require('hash-set');
const helpers = require('./lib/helpers');

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add to package.json


const tmpl = {
b : b => `b:${b}`,
e : e => e ? ` e:${e}` : '',
m : m => Object.keys(m).map(name => `${tmpl.mn(name)}${tmpl.mv(m[name])}`).join(''),
mn : m => ` m:${m}`,
mv : v => v.length ? `=${v.join('|')}` : '',
t : t => t ? ` t:${t}` : ''
};

const btmpl = Object.assign({}, tmpl, {
m : m => m ? `${tmpl.mn(m['name'])}${tmpl.mv([m['val']])}` : ''
});

const BemCellSet = hashSet(cell =>
['block', 'elem', 'mod', 'tech']
.map(k => btmpl[k[0]](cell[k]))
.join('')
);
const BemCellSet = hashSet(helpers.stringifyCell);

/**
* Parse import statement and extract bem entities
Expand All @@ -37,43 +21,43 @@ const BemCellSet = hashSet(cell =>
* @returns {BemCell[]}
*/
function parse(importString, ctx) {
const main = {};
ctx || (ctx = {});
const cell = {};

ctx && (importString = helpers.expand(importString, ctx));

return Array.from(importString.split(' ').reduce((acc, importToken) => {
const split = importToken.split(':'),
type = split[0],
tail = split[1];

if(type === 'b') {
main.block = tail;
acc.add(main);
} else if(type === 'e') {
main.elem = tail;
if(!main.block && ctx.elem !== tail) {
main.block = ctx.block;
acc.add(main);
}
} else if(type === 'm' || type === 't') {
if(!main.block) {
main.block = ctx.block;
main.elem || ctx.elem && (main.elem = ctx.elem);
}
switch(type) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why switch here?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not?

case 'b':

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Тоже не любишь делать доп отступ для case? ;-)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vasiliy не любит =)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually, it's O2 team code style.

cell.block = tail;
acc.add(cell);
break;

if(type === 'm') {
const splitMod = tail.split('='),
modName = splitMod[0],
modVals = splitMod[1];
case 'e':
cell.elem = tail;
break;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is strange

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you add more details?

@qfox qfox Mar 13, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, sorry. we mutating cell but not adding it to acc. For the rest types we call acc.add one or more times.


acc.add(Object.assign({}, main, { mod : { name : modName } }));
case 'm': {
const splitMod = tail.split('='),
modName = splitMod[0],
modVals = splitMod[1];

acc.add(Object.assign({}, cell, { mod : { name : modName } }));

modVals && modVals.split('|').forEach(modVal => {
acc.add(Object.assign({}, cell, { mod : { name : modName, val : modVal } }));
});
break;
}

modVals && modVals.split('|').forEach(modVal => {
acc.add(Object.assign({}, main, { mod : { name : modName, val : modVal } }));
});
} else {
acc.size || acc.add(main);
acc.forEach(e => (e.tech = tail));
}
case 't':
acc.forEach(e => {
e.tech = tail;
});
break;
}
return acc;
}, new BemCellSet()));
Expand All @@ -93,20 +77,21 @@ function parse(importString, ctx) {
*/
function stringify(cells) {
const merged = [].concat(cells).reduce((acc, cell) => {
cell.block && (acc.b = cell.block);
cell.elem && (acc.e = cell.elem);
cell.mod && (acc.m[cell.mod.name] || (acc.m[cell.mod.name] = []))
cell.block && (acc.block = cell.block);
cell.elem && (acc.elem = cell.elem);
cell.mod && (acc.mod[cell.mod.name] || (acc.mod[cell.mod.name] = []))
&& cell.mod.val && typeof cell.mod.val !== 'boolean'
&& !~acc.m[cell.mod.name].indexOf(cell.mod.val)
&& acc.m[cell.mod.name].push(cell.mod.val);
cell.tech && (acc.t = cell.tech);
&& !~acc.mod[cell.mod.name].indexOf(cell.mod.val)
&& acc.mod[cell.mod.name].push(cell.mod.val);
cell.tech && (acc.tech = cell.tech);
return acc;
}, { m : {} });
}, { mod : {} });

return ['b', 'e', 'm', 't'].map(k => tmpl[k](merged[k])).join('');
return helpers.stringifyMergedCells(merged);
}

module.exports = {
parse,
stringify
stringify,
expand : helpers.expand
};
187 changes: 187 additions & 0 deletions packages/import-notation/lib/helpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
/**
* Helpers to test import-notation first part
*/
const tests = {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about this object. Prob it's enough to make 2 simple functions

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did it a group of functions like templates object after

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nvm, not a blocker.

/**
* Returns true if notation starts with block-part
*
* Example:
* ```js
* b('b:button e:icon') // true
* b('e:icon') // false
* ```
*
* @param {String} n - notation
*
* @returns {Boolean}
*/
b : n => /^b:/.test(n),

/**
* Returns true if notation starts with element-part
*
* Example:
* ```js
* b('b:button e:icon') // false
* b('e:icon') // true
* ```
*
* @param {String} n - notation
*
* @returns {Boolean}
*/
e : n => /^e:/.test(n)
};

/**
* @type {ImportNotationTemplates}
*/
const templates = {
/**
* Returns block-part of notation
*
* Example:
* ```js
* b('button') // 'b:button'
* ```
*
* @param {String} b - name of block
*
* @returns {String}
*/
b : b => `b:${b}`,

/**
* Returns element-part of notation
*
* Example:
* ```js
* e('icon') // ' e:icon'
* ```
*
* @param {String} e - name of element
*
* @returns {String}
*/
e : e => e ? ` e:${e}` : '',

/**
* Returns modifiers-part of notation
*
* Example:
* ```js
* m({ color: ['red', 'yellow'], theme: ['default'] })
* // ' m:color=red|yellow m:theme=default'
* ```
*
* @param {Object<String[]>} m - modifiers with values in arrays
*
* @returns {String}
*/
m : m => Object.keys(m).map(name => `${templates._mn(name)}${templates._mv(m[name])}`).join(''),

/**
* Returns modifier-name-part of notation
*
* Example:
* ```js
* _mn('color') // ' m:color'
* ```
*
* @param {String} mn - name of modifier
*
* @returns {String}
*/
_mn : mn => ` m:${mn}`,

/**
* Returns modifier-values-part of notation
*
* Example:
* ```js
* _mv(['red', 'yellow']) // '=red|yellow'
* ```
*
* @param {String[]} mv - modifier values in array
*
* @returns {String}
*/
_mv : mv => mv.length ? `=${mv.join('|')}` : '',

/**
* Returns technology-part of notation
*
* Example:
* ```js
* t('js') // ' t:js'
* ```
*
* @param {String[]} t - name of technology
*
* @returns {String}
*/
t : t => t ? ` t:${t}` : ''
};

/**
* Helpers for BemCell
*
* @type {ImportNotationTemplates}
*/
const cellTemplates = Object.assign({}, templates, {
/**
* Returns modifiers-part of notation
*
* Example:
* ```js
* m({ name: 'theme', val: 'default' }) // ' m:theme=default'
* ```
*
* @param {{ name: String, val: String }} m - modifier with single value
*
* @returns {String}
*/
m : m => m ? `${templates._mn(m['name'])}${templates._mv([m['val']])}` : ''
});

/**
* Returns import-notation stringify for set of templates
*
* @param {ImportNotationTemplates} ts - set of templates to build parts of import-notation
*
* @returns {String}
*/
const stringifyBuilder = ts => x => ['block', 'elem', 'mod', 'tech'].map(k => ts[k[0]](x[k])).join('');

/**
* Returns import-notation expanded by context entity
*
* @param {String} n - notation
* @param {BemEntity} ctx - context entity
*
* @returns {String}
*/
const expand = (n, ctx) => {
if(tests.b(n)) {
return n;
}

return templates.b(ctx.block) + (tests.e(n) ? '' : templates.e(ctx.elem)) + ' ' + n;
};

module.exports = {
expand,
stringifyMergedCells : stringifyBuilder(templates),
stringifyCell : stringifyBuilder(cellTemplates)
};

/**
* Helpers to build parts of import-notation. All parts concatenated by '' gives import-notation string
*
* @typedef {Object} ImportNotationTemplates
*
* @property {Function} b - returns block-part of notation
* @property {Function} e - returns element-part of notation
* @property {Function} m - returns modifiers-part of notation
* @property {Function} t - returns technology-part of notation
*/
Loading