declass
Version:
> Statically analyze HTML to detect potential class groupings
78 lines (71 loc) • 2.15 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
const cheerio2 = require('cheerio');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
const cheerio2__default = /*#__PURE__*/_interopDefaultLegacy(cheerio2);
function declass(html) {
const {items, map} = parseHTML(html);
const groups = makeGroups(items).filter((item) => item.uses.size > 5 && getClasses(item).length > 2).sort((a, b) => b.uses.size - a.uses.size);
return groups.map((g) => ({
class: g.class,
uses: Array.from(g.uses).map((u) => map[u])
}));
}
function makeGroups(items) {
const itemGroups = {};
for (let i = 0; i < items.length; i++) {
for (let j = i + 1; j < items.length; j++) {
const commonClasses = intersect(getClasses(items[i]), getClasses(items[j]));
if (commonClasses.length > 1) {
const uClass = commonClasses.join(" ");
if (!itemGroups[uClass]) {
itemGroups[uClass] = {class: uClass, uses: new Set()};
}
itemGroups[uClass].uses = union(itemGroups[uClass].uses, items[i].uses, items[j].uses);
}
}
}
return Object.values(itemGroups);
}
function getClasses(item) {
if (!item._class) {
item._class = uniq(item.class.split(" ").map((x) => x.trim()).filter(Boolean).sort());
}
return item._class;
}
function uniq(arr) {
return Array.from(new Set(arr));
}
function intersect(a, b) {
return a.filter((item) => b.includes(item));
}
function union(...args) {
const r = new Set();
for (const arg of args) {
arg.forEach((x) => {
r.add(x);
});
}
return r;
}
function parseHTML(html) {
const items = [];
const map = {};
const $ = cheerio2__default['default'].load(html);
$("*").each((id, el) => {
map[id] = `<${el.tagName} ${Object.entries(el.attribs).map((a) => `${a[0]}="${a[1]}"`).join(" ")}>`;
const item = {
uses: new Set(),
class: el.attribs.class || ""
};
item.uses.add(id);
if (getClasses(item).length > 1) {
items.push(item);
}
});
return {
items,
map
};
}
exports.declass = declass;