You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
132 lines
2.9 KiB
132 lines
2.9 KiB
4 years ago
|
'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;
|
||
|
}
|