-
Notifications
You must be signed in to change notification settings - Fork 24
Fillup method in import-notation #312
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,23 +1,7 @@ | ||
| const hashSet = require('hash-set'); | ||
| const helpers = require('./lib/helpers'); | ||
|
|
||
| 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 | ||
|
|
@@ -38,43 +22,41 @@ const BemCellSet = hashSet(cell => | |
| */ | ||
| function parse(importString, scope) { | ||
| const main = {}; | ||
| scope || (scope = {}); | ||
|
|
||
| scope && (importString = helpers.fillup(importString, scope)); | ||
|
|
||
| return Array.from(importString.split(' ').reduce((acc, importToken) => { | ||
| const split = importToken.split(':'), | ||
| type = split[0], | ||
| tail = split[1]; | ||
| val = split[1]; | ||
|
|
||
| if(type === 'b') { | ||
| main.block = tail; | ||
| switch(type) { | ||
| case 'b': | ||
| main.block = val; | ||
| acc.add(main); | ||
| } else if(type === 'e') { | ||
| main.elem = tail; | ||
| if(!main.block && scope.elem !== tail) { | ||
| main.block = scope.block; | ||
| acc.add(main); | ||
| } | ||
| } else if(type === 'm' || type === 't') { | ||
| if(!main.block) { | ||
| main.block = scope.block; | ||
| main.elem || scope.elem && (main.elem = scope.elem); | ||
| acc.add(main); | ||
| } | ||
|
|
||
| if(type === 'm') { | ||
| const splitMod = tail.split('='), | ||
| modName = splitMod[0], | ||
| modVals = splitMod[1]; | ||
| break; | ||
| case 'e': | ||
| // mutates already added item | ||
| main.elem = val; | ||
| break; | ||
| case 'm': { | ||
| const splitMod = val.split('='), | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Аналогично — можно заменить на деструкторизацию
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Кажется, что стоит отказаться от
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. создай плиз issue про это со ссылкой на место, где написано, что она перестанет поддерживаться |
||
| modName = splitMod[0], | ||
| modVals = splitMod[1]; | ||
|
|
||
| acc.add(Object.assign({}, main, { mod : { name : modName } })); | ||
| acc.add(Object.assign({}, main, { mod : { name : modName } })); | ||
|
|
||
| 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)); | ||
| } | ||
| modVals && modVals.split('|').forEach(modVal => { | ||
| acc.add(Object.assign({}, main, { mod : { name : modName, val : modVal } })); | ||
| }); | ||
| break; | ||
| } | ||
| case 't': | ||
| // mutates already added items | ||
| acc.forEach(e => { | ||
| e.tech = val; | ||
| }); | ||
| break; | ||
| } | ||
| return acc; | ||
| }, new BemCellSet())); | ||
|
|
@@ -94,20 +76,21 @@ function parse(importString, scope) { | |
| */ | ||
| 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) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ну камон ребята:
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. тут везде такое кунфу) но мне тож не нравится
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. через includes? |
||
| && 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, | ||
| fillup : helpers.fillup | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,176 @@ | ||
| /** | ||
| * Helpers to test import-notation first part | ||
| */ | ||
| const tests = { | ||
| /** | ||
| * 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) | ||
| }; | ||
|
|
||
| /** | ||
| * Helpers to build parts of import-notation. | ||
| * All parts concatenated by '' gives full import-notation string | ||
| */ | ||
| 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}` : '' | ||
| }; | ||
|
|
||
| /** | ||
| * BemCell variant of templates | ||
| */ | ||
| 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 ? ` m:${m.name}=${m.val}` : '' | ||
| }); | ||
|
|
||
| /** | ||
| * Returns import-notation stringify method for set of templates | ||
| * | ||
| * @param {Object} ts - helpers to build parts of import-notation | ||
| * | ||
| * @returns {String} | ||
| */ | ||
| const stringifyMethod = ts => x => ['block', 'elem', 'mod', 'tech'].map(k => ts[k[0]](x[k])).join(''); | ||
|
|
||
| /** | ||
| * Returns import-notation filled up by context entity | ||
| * | ||
| * @param {String} n - notation | ||
| * @param {BemEntity} scope - context entity | ||
| * | ||
| * @returns {String} | ||
| */ | ||
| const fillup = (n, scope) => { | ||
| if(tests.b(n)) { | ||
| return n; | ||
| } | ||
|
|
||
| return templates.b(scope.block) + | ||
| (tests.e(n) ? '' : templates.e(scope.elem)) + ' ' + n; | ||
| }; | ||
|
|
||
| module.exports = { | ||
| fillup, | ||
| stringifyMergedCells : stringifyMethod(templates), | ||
| stringifyCell : stringifyMethod(cellTemplates) | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| var expect = require('chai').expect, | ||
| f = require('..').fillup; | ||
|
|
||
| describe('scope', () => { | ||
| describe('block', () => { | ||
| it('should copy block if notation has no block #1', () => { | ||
| expect(f('e:icon', { block : 'button' })).to.eql('b:button e:icon'); | ||
| }); | ||
|
|
||
| it('should copy block if notation has no block #2', () => { | ||
| expect(f('m:theme=default', { block : 'button' })).to.eql('b:button m:theme=default'); | ||
| }); | ||
|
|
||
| it('should not copy block if notation has block', () => { | ||
| expect(f('b:button e:icon', { block : 'input' })).to.eql('b:button e:icon'); | ||
| }); | ||
| }); | ||
|
|
||
| describe('elem', () => { | ||
| it('should copy elem if notation has no elem', () => { | ||
| expect(f('m:theme=default', { block : 'button', elem : 'icon' })).to.eql('b:button e:icon m:theme=default'); | ||
| }); | ||
|
|
||
| it('should not copy elem if notation has elem', () => { | ||
| expect(f('b:button e:icon', { block : 'input', elem : 'clear' })).to.eql('b:button e:icon'); | ||
| }); | ||
| }); | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Кажется, что
splitбольше нигде не используется, можно на деструкторизацию заменить: