'use strict' module.exports = adapterFactory; function adapterFactory(implementation){ ensureImplementation(implementation); var adapter = {} var baseAdapter = { removeSubsets: function (nodes){ return removeSubsets(adapter, nodes); }, existsOne: function(test, elems){ return existsOne(adapter, test, elems); }, getSiblings: function(elem){ return getSiblings(adapter, elem); }, hasAttrib: function(elem, name){ return hasAttrib(adapter, elem, name); }, findOne: function(test, arr){ return findOne(adapter, test, arr); }, findAll: function(test, elems){ return findAll(adapter, test, elems) } }; Object.assign(adapter, baseAdapter, implementation); return adapter; } var expectImplemented = [ "isTag", "getAttributeValue", "getChildren", "getName", "getParent", "getText" ]; function ensureImplementation(implementation){ if(!implementation) throw new TypeError("Expected implementation") var notImplemented = expectImplemented.filter(function(fname){ return typeof implementation[fname] !== "function"; }); if(notImplemented.length){ var notList = "(" + notImplemented.join(", ") + ")"; var message = "Expected functions " + notList + " to be implemented"; throw new Error(message); } } function removeSubsets(adapter, nodes){ var idx = nodes.length, node, ancestor, replace; // Check if each node (or one of its ancestors) is already contained in the // array. while(--idx > -1){ node = ancestor = nodes[idx]; // Temporarily remove the node under consideration nodes[idx] = null; replace = true; while(ancestor){ if(nodes.indexOf(ancestor) > -1){ replace = false; nodes.splice(idx, 1); break; } ancestor = adapter.getParent(ancestor) } // If the node has been found to be unique, re-insert it. if(replace){ nodes[idx] = node; } } return nodes; } function existsOne(adapter, test, elems){ return elems.some(function(elem){ return adapter.isTag(elem) ? test(elem) || adapter.existsOne(test, adapter.getChildren(elem)) : false; }); } function getSiblings(adapter, elem){ var parent = adapter.getParent(elem); return parent && adapter.getChildren(parent); } function hasAttrib(adapter, elem, name){ return adapter.getAttributeValue(elem,name) !== undefined } function findOne(adapter, test, arr){ var elem = null; for(var i = 0, l = arr.length; i < l && !elem; i++){ if(test(arr[i])){ elem = arr[i]; } else { var childs = adapter.getChildren(arr[i]); if(childs && childs.length > 0){ elem = adapter.findOne(test, childs); } } } return elem; } function findAll(adapter, test, elems){ var result = []; for(var i = 0, j = elems.length; i < j; i++){ if(!adapter.isTag(elems[i])) continue; if(test(elems[i])) result.push(elems[i]); var childs = adapter.getChildren(elems[i]); if(childs) result = result.concat(adapter.findAll(test, childs)); } return result; }