enb-bem-techs-2x
Version:
BEM methodology for ENB
256 lines (246 loc) • 8.44 kB
JavaScript
/**
* A set of utilities for work with dependencies.
*
* @namespace deps
*/
module.exports = {
/**
* Merges DEPS declarations.
*
* @memberof deps
* @param {Array} depsToMerge
* @returns {Array}
*/
merge: function (depsToMerge) {
depsToMerge = [].concat(depsToMerge);
var startingDep = depsToMerge.shift(),
index = buildDepsIndex(startingDep),
result = [].concat(startingDep),
currentDep,
dep,
key;
while (!!(currentDep = depsToMerge.shift())) {
for (var i = 0, l = currentDep.length; i < l; i++) {
dep = currentDep[i];
key = depKey(dep);
if (!index[key]) {
result.push(dep);
index[key] = true;
}
}
}
return result;
},
/**
* Subtracts DEPS declarations.
*
* @memberof deps
* @param {Array} from
* @param {Array} what
* @returns {Array}
*/
subtract: function (from, what) {
var whatIndex = buildDepsIndex(what);
return from.filter(function (dep) {
return !whatIndex[depKey(dep)];
});
},
/**
* Translates declaration from BEMDECL format to DEPS format (not resolve).
*
* @memberof deps
* @param {Object} bemdecl
* @returns {Array}
*/
fromBemdecl: function (bemdecl) {
if (bemdecl) {
var res = [];
bemdecl.forEach(function (block) {
res.push({ block: block.name });
if (block.mods) {
block.mods.forEach(function (mod) {
if (mod.vals) {
mod.vals.forEach(function (val) {
res.push({ block: block.name, mod: mod.name, val: val.name });
});
} else {
res.push({ block: block.name, mod: mod.name });
}
});
}
if (block.elems) {
block.elems.forEach(function (elem) {
res.push({ block: block.name, elem: elem.name });
if (elem.mods) {
elem.mods.forEach(function (mod) {
if (mod.vals) {
mod.vals.forEach(function (val) {
res.push({ block: block.name, elem: elem.name, mod: mod.name, val: val.name });
});
} else {
res.push({ block: block.name, elem: elem.name, mod: mod.name });
}
});
}
});
}
});
return res;
} else {
return [];
}
},
/**
* Translates declaration from DEPS format to BEMDECL format (not resolve).
*
* @memberof deps
* @param {Object} deps
* @returns {Array}
*/
toBemdecl: function (deps) {
if (deps) {
var res = [];
deps.forEach(function (dep) {
var item = { name: dep.block };
if (dep.elem) {
if (dep.mod) {
if (dep.val) {
item.elems = [{ name: dep.elem, mods: [{ name: dep.mod, vals: [{ name: dep.val }] }] }];
} else {
item.elems = [{ name: dep.elem, mods: [{ name: dep.mod }] }];
}
} else {
item.elems = [{ name: dep.elem }];
}
} else {
if (dep.mod) {
if (dep.val) {
item.mods = [{ name: dep.mod, vals: [{ name: dep.val }] }];
} else {
item.mods = [{ name: dep.mod }];
}
}
}
res.push(item);
});
return res;
} else {
return [];
}
},
/**
* Converts shortcut to verbose array.
*
* @memberof deps
* @param {Object} dep
* @param {String} [blockName]
* @returns {Array}
*/
flattenDep: function (dep, blockName) {
if (typeof dep === 'string') {
return [{ block: dep }];
}
var res = [];
if (!dep.block) {
dep.block = blockName;
}
if (dep.elem) {
if (dep.mods) {
Object.keys(dep.mods).forEach(function (modName) {
var modVals = dep.mods[modName];
if (!Array.isArray(modVals)) {
modVals = [modVals];
}
res = res.concat(modVals.map(function (modVal) {
return { block: dep.block, elem: dep.elem, mod: modName, val: modVal };
}));
});
} else if (dep.mod) {
if (dep.val) {
res.push({ block: dep.block, elem: dep.elem, mod: dep.mod, val: dep.val });
} else {
res.push({ block: dep.block, elem: dep.elem, mod: dep.mod });
}
} else {
res.push({ block: dep.block, elem: dep.elem });
}
} else if (dep.mods || dep.elems) {
Object.keys(dep.mods || {}).forEach(function (modName) {
var modVals = dep.mods[modName];
if (!Array.isArray(modVals)) {
modVals = [modVals];
}
res = res.concat(modVals.map(function (modVal) {
return { block: dep.block, mod: modName, val: modVal };
}));
});
if (dep.elems) {
res.push({ block: dep.block });
var elems = dep.elems;
if (!Array.isArray(elems)) {
elems = [elems];
}
elems.forEach(function (elem) {
if (typeof elem === 'object') {
res.push({ block: dep.block, elem: elem.elem });
Object.keys(elem.mods || {}).forEach(function (modName) {
var modVals = elem.mods[modName];
if (!Array.isArray(modVals)) {
modVals = [modVals];
}
res = res.concat(modVals.map(function (modVal) {
return { block: dep.block, elem: elem.elem, mod: modName, val: modVal };
}));
});
} else {
res.push({ block: dep.block, elem: elem });
}
});
}
} else if (dep.mod) {
if (dep.val) {
res.push({ block: dep.block, mod: dep.mod, val: dep.val });
} else {
res.push({ block: dep.block, mod: dep.mod });
}
} else {
res = [{ block: dep.block }];
}
if (dep.tech) {
res.forEach(function (resDep) {
resDep.tech = dep.tech;
});
}
return res;
},
/**
* Converts declaration with shortcuts to verbose array.
*
* @memberof deps
* @param {Array|Object} deps
* @returns {Array}
*/
flattenDeps: function (deps) {
if (Array.isArray(deps)) {
var result = [];
for (var i = 0, l = deps.length; i < l; i++) {
result = result.concat(this.flattenDep(deps[i]));
}
return result;
} else {
return this.flattenDep(deps);
}
}
};
function depKey(dep) {
return dep.block +
(dep.elem ? '__' + dep.elem : '') +
(dep.mod ? '_' + dep.mod + (dep.val ? '_' + dep.val : '') : '');
}
function buildDepsIndex(deps) {
var result = {};
for (var i = 0, l = deps.length; i < l; i++) {
result[depKey(deps[i])] = true;
}
return result;
}