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.

131 lines
2.9 KiB

4 years ago
  1. 'use strict'
  2. module.exports = adapterFactory;
  3. function adapterFactory(implementation){
  4. ensureImplementation(implementation);
  5. var adapter = {}
  6. var baseAdapter = {
  7. removeSubsets: function (nodes){
  8. return removeSubsets(adapter, nodes);
  9. },
  10. existsOne: function(test, elems){
  11. return existsOne(adapter, test, elems);
  12. },
  13. getSiblings: function(elem){
  14. return getSiblings(adapter, elem);
  15. },
  16. hasAttrib: function(elem, name){
  17. return hasAttrib(adapter, elem, name);
  18. },
  19. findOne: function(test, arr){
  20. return findOne(adapter, test, arr);
  21. },
  22. findAll: function(test, elems){
  23. return findAll(adapter, test, elems)
  24. }
  25. };
  26. Object.assign(adapter, baseAdapter, implementation);
  27. return adapter;
  28. }
  29. var expectImplemented = [
  30. "isTag", "getAttributeValue", "getChildren", "getName", "getParent",
  31. "getText"
  32. ];
  33. function ensureImplementation(implementation){
  34. if(!implementation) throw new TypeError("Expected implementation")
  35. var notImplemented = expectImplemented.filter(function(fname){
  36. return typeof implementation[fname] !== "function";
  37. });
  38. if(notImplemented.length){
  39. var notList = "(" + notImplemented.join(", ") + ")";
  40. var message = "Expected functions " + notList + " to be implemented";
  41. throw new Error(message);
  42. }
  43. }
  44. function removeSubsets(adapter, nodes){
  45. var idx = nodes.length, node, ancestor, replace;
  46. // Check if each node (or one of its ancestors) is already contained in the
  47. // array.
  48. while(--idx > -1){
  49. node = ancestor = nodes[idx];
  50. // Temporarily remove the node under consideration
  51. nodes[idx] = null;
  52. replace = true;
  53. while(ancestor){
  54. if(nodes.indexOf(ancestor) > -1){
  55. replace = false;
  56. nodes.splice(idx, 1);
  57. break;
  58. }
  59. ancestor = adapter.getParent(ancestor)
  60. }
  61. // If the node has been found to be unique, re-insert it.
  62. if(replace){
  63. nodes[idx] = node;
  64. }
  65. }
  66. return nodes;
  67. }
  68. function existsOne(adapter, test, elems){
  69. return elems.some(function(elem){
  70. return adapter.isTag(elem) ?
  71. test(elem) || adapter.existsOne(test, adapter.getChildren(elem)) :
  72. false;
  73. });
  74. }
  75. function getSiblings(adapter, elem){
  76. var parent = adapter.getParent(elem);
  77. return parent && adapter.getChildren(parent);
  78. }
  79. function hasAttrib(adapter, elem, name){
  80. return adapter.getAttributeValue(elem,name) !== undefined
  81. }
  82. function findOne(adapter, test, arr){
  83. var elem = null;
  84. for(var i = 0, l = arr.length; i < l && !elem; i++){
  85. if(test(arr[i])){
  86. elem = arr[i];
  87. } else {
  88. var childs = adapter.getChildren(arr[i]);
  89. if(childs && childs.length > 0){
  90. elem = adapter.findOne(test, childs);
  91. }
  92. }
  93. }
  94. return elem;
  95. }
  96. function findAll(adapter, test, elems){
  97. var result = [];
  98. for(var i = 0, j = elems.length; i < j; i++){
  99. if(!adapter.isTag(elems[i])) continue;
  100. if(test(elems[i])) result.push(elems[i]);
  101. var childs = adapter.getChildren(elems[i]);
  102. if(childs) result = result.concat(adapter.findAll(test, childs));
  103. }
  104. return result;
  105. }