From 5e77adf0bab730bff43e2145c64debf3527b3a55 Mon Sep 17 00:00:00 2001 From: Vladimir Varankin Date: Sun, 19 Jan 2014 01:14:14 +0400 Subject: [PATCH] Poehali! --- .gitignore | 1 + README.md | 4 + index.js | 193 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 15 ++++ test/normalize.js | 175 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 388 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 index.js create mode 100644 package.json create mode 100644 test/normalize.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/README.md b/README.md new file mode 100644 index 0000000..5a39bd8 --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +depsormalize +============ + +`deps` normalizer diff --git a/index.js b/index.js new file mode 100644 index 0000000..5feb0e5 --- /dev/null +++ b/index.js @@ -0,0 +1,193 @@ +/* +{ + block : 'b1', + elem : 'e1', + mod : 'm1' + val : 'v1' + tech : 't1' +} +*/ + +var toString = Object.prototype.toString, + isArray = Array.isArray, + isObject = function(o) { + return toString.call(o) === '[object Object]'; + }; + +module.exports = function depsormalize(deps) { + if(isArray(deps)) return deps.map(normalize); + return normalize(deps); +}; + +function normalize(deps) { + if(!isObject(deps)) { + throw new Error('invalid declaration ' + deps); + } + + var result = [], + cache = {}; + + if(deps.blocks) { + var blocks = deps.blocks; + if(!isArray(blocks)) blocks = [blocks]; + + pushBlocks(blocks); + } + + var block = deps.block, + elem = deps.elem, + i, slen, decl; + + if(deps.elems) { + var elems = deps.elems; + + if(!isArray(elems)) elems = [elems]; + + i = 0; + slen = result.length; + + do { + decl = result[i] || {}; + + if(decl.block) block = decl.block; + pushElems(block, elems); + } while(++i < slen); + } + + if(deps.mods) { + var mods = deps.mods; + + if(!isArray(mods)) mods = [mods]; + + i = 0; + slen = result.length; + + do { + decl = result[i] || {}; + + if(decl.block) block = decl.block; + if(decl.elem) elem = decl.elem; + + pushMods(block, elem, mods); + } while(++i < slen); + } + + if(!result.length) { + push(extendDecl({}, deps)); + } + + return result; + + function push(decl) { + var key = identify(decl); + + if(cache[key]) return; + cache[key] = true; + + result.push(decl); + } + + function pushOne(block, elem) { + if(block) { + var d = { + block : block + }; + if(elem) d.elem = elem; + push(d); + } + } + + function pushBlocks(blocks) { + blocks.reduce(function(decls, block) { + pushOne(block); + push(extendDecl({ block : block }, deps)); + + return decls; + }, []); + } + + function pushElems(block, elems) { + pushOne(block); + + elems.forEach(function(elem) { + var d = {}; + + if(block) d.block = block; + d.elem = elem; + + push(extendDecl(d, deps)); + }); + } + + function pushMods(block, elem, mods) { + pushOne(block, elem); + + mods.forEach(function(mod) { + Object.keys(mod).forEach(function(name) { + var d = { mod : name }; + if(block) { + d.block = block; + if(elem) d.elem = elem; + } + + push(extendDecl({}, d)); + + var vals = mod[name]; + if(!vals) { + return; + } + + if(!isArray(vals)) vals = [vals]; + + vals.forEach(function(val) { + push(extendDecl({ val : val }, d)); + }); + }); + }); + } +} + +function extendDecl(dest, src) { + extendBlock(dest ,src); + extendElem(dest, src); + extendMod(dest, src); + extendVal(dest, src); + extendTech(dest, src); + return dest; +} + +function extendBlock(d, s) { + if(d.block) return d; + if(s.block) d.block = s.block; + return d; +} + +function extendElem(d, s) { + if(d.elem) return d; + if(s.elem) d.elem = s.elem; + return d; +} + +function extendMod(d, s) { + if(d.mod) return d; + if(s.mod) d.mod = s.mod; + return d; +} + +function extendVal(d, s) { + if(d.val) return d; + if(s.val) d.val = s.val; + return d; +} + +function extendTech(d, s) { + if(d.tech) return d; + if(s.tech) d.tech = s.tech; + return d; +} + +function identify(decl) { + return decl.block + + (decl.elem? '__' + decl.elem : '') + + (decl.mod? '_' + decl.mod + (decl.val? '_' + decl.val : '') : ''); +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..1971102 --- /dev/null +++ b/package.json @@ -0,0 +1,15 @@ +{ + "name": "depsormalize", + "version": "0.0.1", + "description": "deps normalizer", + "main": "index.js", + "scripts": { + "test": "mocha -R spec test" + }, + "author": "Vladimir Varankin (http://github.com/narqo)", + "license": "WTFPL", + "devDependencies": { + "mocha": "~1.17.0", + "must": "~0.10.0" + } +} diff --git a/test/normalize.js b/test/normalize.js new file mode 100644 index 0000000..2f10d41 --- /dev/null +++ b/test/normalize.js @@ -0,0 +1,175 @@ +require('must'); +var depsormalize = require('../'); + +describe('deps normalizer', function() { + describe('simple', function() { + it('should return array', function() { + var deps = depsormalize({ block : 'b1' }); + deps.must.be.array(); + deps.must.not.be.empty(); + }); + + it('should consume array of declarations', function() { + var deps = depsormalize([{ block : 'b1' }, { block : 'b2' }]); + deps.must.be.array(); + deps.must.have.length(2); + }); + }); + + describe('full declaration', function() { + var inDeps = [ + { block : 'b' }, + { block : 'b', mod : 'm' }, + { block : 'b', mod : 'm', val : 'v' }, + { block : 'b', elem : 'e' }, + { block : 'b', elem : 'e', mod : 'm' }, + { block : 'b', elem : 'e', mod : 'm', val : 'v' } + ]; + + it('should pass full declaration', function() { + inDeps.forEach(function(idep) { + depsormalize(idep).must.be.eql([idep]); + }); + }); + }); + + describe.skip('single forms', function() { + describe('block', function() { + it('should accept declare "block" with array', function() { + depsormalize({ block : ['b1', 'b2'] }) + .must.eql([ + { block : 'b1' }, + { block : 'b2' } + ]); + + depsormalize({ block : ['b1', 'b2'], elem : 'e' }) + .must.eql([ + { block : 'b1', elem : 'e' }, + { block : 'b2', elem : 'e' } + ]); + }); + }); + + describe('elem', function() { + it('should accept declare "elem" with array', function() { + depsormalize({ block : 'b', elem : ['e1', 'e2'] }) + .must.eql([ + { block : 'b', elem : 'e1' }, + { block : 'b', elem : 'e2' } + ]); + }); + }) + }); + + describe('plural forms', function() { + describe('blocks', function() { + it('should understand "blocks" declaration', function() { + depsormalize({ blocks : 'b1' }) + .must.eql([{ block : 'b1' }]); + + depsormalize({ blocks : ['b1'] }) + .must.eql([{ block : 'b1' }]); + + depsormalize({ blocks : ['b1'], elem : 'e' }) + .must.eql([{ block : 'b1' }, { block : 'b1', elem : 'e' }]); + + depsormalize({ blocks : ['b1', 'b2'] }) + .must.eql([{ block : 'b1' }, { block : 'b2'}]); + + depsormalize({ blocks : ['b1', 'b2'], elem : 'e' }) + .must.eql([ + { block : 'b1' }, + { block : 'b1', elem : 'e' }, + { block : 'b2' }, + { block : 'b2', elem : 'e' } + ]); + }); + }); + + describe('elems', function() { + it('should understand "elems" declaration', function() { + depsormalize({ block : 'b', elems : 'e1' }) + .must.eql([ + { block : 'b' }, + { block : 'b', elem : 'e1' } + ]); + + depsormalize({ block : 'b', elems : ['e1', 'e2'] }) + .must.eql([ + { block : 'b' }, + { block : 'b', elem : 'e1' }, + { block : 'b', elem : 'e2' } + ]); + }); + }); + + describe('mods', function() { + it('should understand "mods" declaration', function() { + depsormalize({ block : 'b', mods : { m : 'v' } }) + .must.eql([ + { block : 'b' }, + { block : 'b', mod : 'm' }, + { block : 'b', mod : 'm', val : 'v' } + ]); + + depsormalize({ block : 'b', mods : [{ m1 : 'v' }, { m2 : 'v' }] }) + .must.eql([ + { block : 'b' }, + { block : 'b', mod : 'm1' }, + { block : 'b', mod : 'm1', val : 'v' }, + { block : 'b', mod : 'm2' }, + { block : 'b', mod : 'm2', val : 'v' } + ]); + + depsormalize({ block : 'b', mods : { m : ['v1', 'v2'] } }) + .must.eql([ + { block : 'b' }, + { block : 'b', mod : 'm' }, + { block : 'b', mod : 'm', val : 'v1' }, + { block : 'b', mod : 'm', val : 'v2' } + ]); + + depsormalize({ block : 'b', mods : { m1 : 'v', m2 : 'v' } }) + .must.eql([ + { block : 'b' }, + { block : 'b', mod : 'm1' }, + { block : 'b', mod : 'm1', val : 'v' }, + { block : 'b', mod : 'm2' }, + { block : 'b', mod : 'm2', val : 'v' } + ]); + }); + + it.skip('should understand "mods-names" notations', function() { + depsormalize({ block : 'b', mod : { names : ['m1', 'm2'] } }) + .must.eql([ + { block : 'b' }, + { block : 'b', mod : 'm1' }, + { block : 'b', mod : 'm2' } + ]); + }); + }); + + describe('blocks + elems', function() { + it('should understand both "blocks" and "elems" declaration', function() { + depsormalize({ blocks : 'b1', elems : 'e1' }) + .must.eql([ + { block : 'b1' }, + { block : 'b1', elem : 'e1' } + ]); + }); + }); + + describe('uniqness', function() { + it('should return uniq set of declaration', function() { + depsormalize({ blocks : ['b', 'b', 'b'] }) + .must.eql([{ block : 'b' }]); + + depsormalize({ block : 'b', elems : ['e', 'e', 'e'] }) + .must.eql([ + { block : 'b' }, + { block : 'b', elem : 'e' } + ]); + }); + }); + }); +});