trie_node_factory.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.getNode = getNode;
  4. const DomUtil = require("../common/dom_util.js");
  5. const XpathUtil = require("../common/xpath_util.js");
  6. const grammar_js_1 = require("../rule_engine/grammar.js");
  7. const MathCompoundStore = require("../rule_engine/math_compound_store.js");
  8. const abstract_trie_node_js_1 = require("./abstract_trie_node.js");
  9. const abstract_trie_node_js_2 = require("./abstract_trie_node.js");
  10. const trie_node_js_1 = require("./trie_node.js");
  11. function getNode(kind, constraint, context) {
  12. switch (kind) {
  13. case trie_node_js_1.TrieNodeKind.ROOT:
  14. return new RootTrieNode();
  15. case trie_node_js_1.TrieNodeKind.DYNAMIC:
  16. return new DynamicTrieNode(constraint);
  17. case trie_node_js_1.TrieNodeKind.QUERY:
  18. return new QueryTrieNode(constraint, context);
  19. case trie_node_js_1.TrieNodeKind.BOOLEAN:
  20. return new BooleanTrieNode(constraint, context);
  21. default:
  22. return null;
  23. }
  24. }
  25. class RootTrieNode extends abstract_trie_node_js_1.AbstractTrieNode {
  26. constructor() {
  27. super('', () => true);
  28. this.kind = trie_node_js_1.TrieNodeKind.ROOT;
  29. }
  30. }
  31. class DynamicTrieNode extends abstract_trie_node_js_1.AbstractTrieNode {
  32. constructor(constraint) {
  33. super(constraint, (axis) => axis === constraint);
  34. this.kind = trie_node_js_1.TrieNodeKind.DYNAMIC;
  35. }
  36. }
  37. const comparator = {
  38. '=': (x, y) => x === y,
  39. '!=': (x, y) => x !== y,
  40. '<': (x, y) => x < y,
  41. '>': (x, y) => x > y,
  42. '<=': (x, y) => x <= y,
  43. '>=': (x, y) => x >= y
  44. };
  45. function constraintTest(constraint) {
  46. if (constraint.match(/^self::\*$/)) {
  47. return (_node) => true;
  48. }
  49. if (constraint.match(/^self::\w+$/)) {
  50. const tag = constraint.slice(6).toUpperCase();
  51. return (node) => node.tagName && DomUtil.tagName(node) === tag;
  52. }
  53. if (constraint.match(/^self::\w+:\w+$/)) {
  54. const inter = constraint.split(':');
  55. const namespace = XpathUtil.resolveNameSpace(inter[2]);
  56. if (!namespace) {
  57. return null;
  58. }
  59. const tag = inter[3].toUpperCase();
  60. return (node) => node.localName &&
  61. node.localName.toUpperCase() === tag &&
  62. node.namespaceURI === namespace;
  63. }
  64. if (constraint.match(/^@\w+$/)) {
  65. const attr = constraint.slice(1);
  66. return (node) => node.hasAttribute && node.hasAttribute(attr);
  67. }
  68. if (constraint.match(/^@\w+="[\w\d ]+"$/)) {
  69. const split = constraint.split('=');
  70. const attr = split[0].slice(1);
  71. const value = split[1].slice(1, -1);
  72. return (node) => node.hasAttribute &&
  73. node.hasAttribute(attr) &&
  74. node.getAttribute(attr) === value;
  75. }
  76. if (constraint.match(/^@\w+!="[\w\d ]+"$/)) {
  77. const split = constraint.split('!=');
  78. const attr = split[0].slice(1);
  79. const value = split[1].slice(1, -1);
  80. return (node) => !node.hasAttribute ||
  81. !node.hasAttribute(attr) ||
  82. node.getAttribute(attr) !== value;
  83. }
  84. if (constraint.match(/^contains\(\s*@grammar\s*,\s*"[\w\d ]+"\s*\)$/)) {
  85. const split = constraint.split('"');
  86. const value = split[1];
  87. return (_node) => !!grammar_js_1.Grammar.getInstance().getParameter(value);
  88. }
  89. if (constraint.match(/^not\(\s*contains\(\s*@grammar\s*,\s*"[\w\d ]+"\s*\)\s*\)$/)) {
  90. const split = constraint.split('"');
  91. const value = split[1];
  92. return (_node) => !grammar_js_1.Grammar.getInstance().getParameter(value);
  93. }
  94. if (constraint.match(/^name\(\.\.\/\.\.\)="\w+"$/)) {
  95. const split = constraint.split('"');
  96. const tag = split[1].toUpperCase();
  97. return (node) => {
  98. var _a, _b;
  99. return ((_b = (_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.parentNode) === null || _b === void 0 ? void 0 : _b.tagName) &&
  100. DomUtil.tagName(node.parentNode.parentNode) === tag;
  101. };
  102. }
  103. if (constraint.match(/^count\(preceding-sibling::\*\)=\d+$/)) {
  104. const split = constraint.split('=');
  105. const num = parseInt(split[1], 10);
  106. return (node) => { var _a; return ((_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.childNodes[num]) === node; };
  107. }
  108. if (constraint.match(/^.+\[@category!?=".+"\]$/)) {
  109. let [, query, equality, category] = constraint.match(/^(.+)\[@category(!?=)"(.+)"\]$/);
  110. const unit = category.match(/^unit:(.+)$/);
  111. let add = '';
  112. if (unit) {
  113. category = unit[1];
  114. add = ':unit';
  115. }
  116. return (node) => {
  117. const xpath = XpathUtil.evalXPath(query, node)[0];
  118. if (xpath) {
  119. const result = MathCompoundStore.lookupCategory(xpath.textContent + add);
  120. return equality === '=' ? result === category : result !== category;
  121. }
  122. return false;
  123. };
  124. }
  125. if (constraint.match(/^string-length\(.+\)\W+\d+/)) {
  126. const [, select, comp, count] = constraint.match(/^string-length\((.+)\)(\W+)(\d+)/);
  127. const func = comparator[comp] || comparator['='];
  128. const numb = parseInt(count, 10);
  129. return (node) => {
  130. const xpath = XpathUtil.evalXPath(select, node)[0];
  131. if (!xpath) {
  132. return false;
  133. }
  134. return func(Array.from(xpath.textContent).length, numb);
  135. };
  136. }
  137. return null;
  138. }
  139. class QueryTrieNode extends abstract_trie_node_js_2.StaticTrieNode {
  140. constructor(constraint, context) {
  141. super(constraint, constraintTest(constraint));
  142. this.context = context;
  143. this.kind = trie_node_js_1.TrieNodeKind.QUERY;
  144. }
  145. applyTest(object) {
  146. return this.test
  147. ? this.test(object)
  148. : this.context.applyQuery(object, this.constraint) === object;
  149. }
  150. }
  151. class BooleanTrieNode extends abstract_trie_node_js_2.StaticTrieNode {
  152. constructor(constraint, context) {
  153. super(constraint, constraintTest(constraint));
  154. this.context = context;
  155. this.kind = trie_node_js_1.TrieNodeKind.BOOLEAN;
  156. }
  157. applyTest(object) {
  158. return this.test
  159. ? this.test(object)
  160. : this.context.applyConstraint(object, this.constraint);
  161. }
  162. }