function getAreasIndex(config) {
const index = {};
config.areas.forEach((row, rowId) => {
row.forEach((key, colId) => {
if (key === ".") return;
let area;
if ((area = index[key])) {
area.rows = [
Math.min(rowId, area.rows[0]),
Math.max(rowId, area.rows[1])
];
area.columns = [
Math.min(colId, area.columns[0]),
Math.max(colId, area.columns[1])
];
} else {
index[key] = {
rows: [rowId, rowId],
columns: [colId, colId]
};
}
});
});
let children;
for (let [key, area] of Object.entries(index)) {
for (let rowId = area.rows[0]; rowId <= area.rows[1]; rowId++) {
for (let colId = area.columns[0]; colId <= area.columns[1]; colId++) {
const areaKey = config.areas[rowId][colId];
if (areaKey !== key) {
const errorMsg =
`Areas "${areaKey}" and "${key}" ` +
`intersect at [${rowId}, ${colId}].`;
throw new Error(errorMsg);
}
}
}
updatePositionAndDimentions(config, area);
if (config.children && config.children[key]) {
children = children || {};
children[key] = getAreasIndex(config.children[key]);
}
}
const result = updatePositionAndDimentions(config, {
areas: index,
rows: [0, config.rows.length - 1],
columns: [0, config.columns.length - 1]
});
if (children) result.children = children;
return result;
function updatePositionAndDimentions(config, area) {
area.top = {};
area.left = {};
area.width = {};
area.height = {};
for (let y = 0; y < area.rows[0]; y++) update(area.top, config.rows[y]);
for (let y = area.rows[0]; y <= area.rows[1]; y++)
update(area.height, config.rows[y]);
for (let x = 0; x < area.columns[0]; x++)
update(area.left, config.columns[x]);
for (let x = area.columns[0]; x <= area.columns[1]; x++)
update(area.width, config.columns[x]);
return area;
function update(dim, { unit, value } = {}) {
if (!unit) return;
dim[unit] = (dim[unit] || 0) + value;
}
}
}