xslt-processor 3.0.0 → 3.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (224) hide show
  1. package/README.md +2 -2
  2. package/constants.d.ts +12 -12
  3. package/constants.js +16 -16
  4. package/dom/functions.d.ts +14 -14
  5. package/dom/functions.js +56 -57
  6. package/dom/functions.js.map +1 -1
  7. package/dom/index.d.ts +6 -6
  8. package/dom/index.js +22 -22
  9. package/dom/util.d.ts +7 -7
  10. package/dom/util.js +42 -43
  11. package/dom/util.js.map +1 -1
  12. package/dom/xdocument.d.ts +16 -16
  13. package/dom/xdocument.js +73 -74
  14. package/dom/xdocument.js.map +1 -1
  15. package/dom/xml-functions.d.ts +58 -58
  16. package/dom/xml-functions.js +369 -370
  17. package/dom/xml-functions.js.map +1 -1
  18. package/dom/xml-output-options.d.ts +6 -6
  19. package/dom/xml-output-options.js +2 -2
  20. package/dom/xml-parser.d.ts +47 -47
  21. package/dom/xml-parser.js +307 -307
  22. package/dom/xml-parser.js.map +1 -1
  23. package/dom/xmltoken.d.ts +12 -12
  24. package/dom/xmltoken.js +101 -101
  25. package/dom/xnode.d.ts +73 -73
  26. package/dom/xnode.js +450 -450
  27. package/dom/xnode.js.map +1 -1
  28. package/index.d.ts +4 -4
  29. package/index.js +12 -12
  30. package/package.json +11 -11
  31. package/test-without-jest.d.ts +1 -0
  32. package/test-without-jest.js +63 -0
  33. package/test-without-jest.js.map +1 -0
  34. package/umd/constants.d.ts +12 -12
  35. package/umd/dom/functions.d.ts +14 -14
  36. package/umd/dom/index.d.ts +6 -6
  37. package/umd/dom/util.d.ts +7 -7
  38. package/umd/dom/xdocument.d.ts +16 -16
  39. package/umd/dom/xml-functions.d.ts +58 -58
  40. package/umd/dom/xml-output-options.d.ts +6 -6
  41. package/umd/dom/xml-parser.d.ts +47 -47
  42. package/umd/dom/xmltoken.d.ts +12 -12
  43. package/umd/dom/xnode.d.ts +73 -73
  44. package/umd/index.d.ts +4 -4
  45. package/umd/test-without-jest.d.ts +1 -0
  46. package/umd/xpath/common-function.d.ts +8 -8
  47. package/umd/xpath/expr-context.d.ts +111 -111
  48. package/umd/xpath/expressions/binary-expr.d.ts +11 -11
  49. package/umd/xpath/expressions/expression.d.ts +4 -4
  50. package/umd/xpath/expressions/filter-expr.d.ts +9 -9
  51. package/umd/xpath/expressions/function-call-expr.d.ts +12 -12
  52. package/umd/xpath/expressions/index.d.ts +13 -13
  53. package/umd/xpath/expressions/literal-expr.d.ts +7 -7
  54. package/umd/xpath/expressions/location-expr.d.ts +15 -15
  55. package/umd/xpath/expressions/number-expr.d.ts +7 -7
  56. package/umd/xpath/expressions/path-expr.d.ts +9 -9
  57. package/umd/xpath/expressions/predicate-expr.d.ts +8 -8
  58. package/umd/xpath/expressions/step-expr.d.ts +25 -25
  59. package/umd/xpath/expressions/token-expr.d.ts +7 -7
  60. package/umd/xpath/expressions/unary-minus-expr.d.ts +8 -8
  61. package/umd/xpath/expressions/union-expr.d.ts +9 -9
  62. package/umd/xpath/expressions/variable-expr.d.ts +7 -7
  63. package/umd/xpath/functions/index.d.ts +2 -2
  64. package/umd/xpath/functions/internal-functions.d.ts +2 -2
  65. package/umd/xpath/functions/non-standard.d.ts +12 -12
  66. package/umd/xpath/functions/standard-20.d.ts +5 -5
  67. package/umd/xpath/functions/standard.d.ts +40 -40
  68. package/umd/xpath/grammar-rule-candidate.d.ts +8 -8
  69. package/umd/xpath/index.d.ts +3 -3
  70. package/umd/xpath/match-resolver.d.ts +55 -55
  71. package/umd/xpath/node-tests/index.d.ts +8 -8
  72. package/umd/xpath/node-tests/node-test-any.d.ts +6 -6
  73. package/umd/xpath/node-tests/node-test-comment.d.ts +6 -6
  74. package/umd/xpath/node-tests/node-test-element-or-attribute.d.ts +6 -6
  75. package/umd/xpath/node-tests/node-test-name.d.ts +10 -10
  76. package/umd/xpath/node-tests/node-test-nc.d.ts +9 -9
  77. package/umd/xpath/node-tests/node-test-pi.d.ts +8 -8
  78. package/umd/xpath/node-tests/node-test-text.d.ts +6 -6
  79. package/umd/xpath/node-tests/node-test.d.ts +5 -5
  80. package/umd/xpath/tokens.d.ts +62 -62
  81. package/umd/xpath/values/boolean-value.d.ts +11 -11
  82. package/umd/xpath/values/index.d.ts +5 -5
  83. package/umd/xpath/values/node-set-value.d.ts +11 -11
  84. package/umd/xpath/values/node-value.d.ts +7 -7
  85. package/umd/xpath/values/number-value.d.ts +11 -11
  86. package/umd/xpath/values/string-value.d.ts +11 -11
  87. package/umd/xpath/xpath-grammar-rules.d.ts +68 -68
  88. package/umd/xpath/xpath-token-rule.d.ts +7 -7
  89. package/umd/xpath/xpath.d.ts +174 -170
  90. package/umd/xpathdebug.d.ts +2 -2
  91. package/umd/xslt/index.d.ts +3 -3
  92. package/umd/xslt/xslt-decimal-format-settings.d.ts +28 -28
  93. package/umd/xslt/xslt-options.d.ts +7 -7
  94. package/umd/xslt/xslt-parameter.d.ts +5 -5
  95. package/umd/xslt/xslt.d.ts +207 -190
  96. package/umd/xslt-processor.js +1 -15
  97. package/umd/xslt-processor.js.map +1 -1
  98. package/xpath/common-function.d.ts +8 -8
  99. package/xpath/common-function.js +31 -32
  100. package/xpath/common-function.js.map +1 -1
  101. package/xpath/expr-context.d.ts +111 -111
  102. package/xpath/expr-context.js +189 -189
  103. package/xpath/expr-context.js.map +1 -1
  104. package/xpath/expressions/binary-expr.d.ts +11 -11
  105. package/xpath/expressions/binary-expr.js +165 -165
  106. package/xpath/expressions/binary-expr.js.map +1 -1
  107. package/xpath/expressions/expression.d.ts +4 -4
  108. package/xpath/expressions/expression.js +9 -9
  109. package/xpath/expressions/filter-expr.d.ts +9 -9
  110. package/xpath/expressions/filter-expr.js +52 -52
  111. package/xpath/expressions/filter-expr.js.map +1 -1
  112. package/xpath/expressions/function-call-expr.d.ts +12 -12
  113. package/xpath/expressions/function-call-expr.js +95 -95
  114. package/xpath/expressions/function-call-expr.js.map +1 -1
  115. package/xpath/expressions/index.d.ts +13 -13
  116. package/xpath/expressions/index.js +29 -29
  117. package/xpath/expressions/literal-expr.d.ts +7 -7
  118. package/xpath/expressions/literal-expr.js +33 -33
  119. package/xpath/expressions/literal-expr.js.map +1 -1
  120. package/xpath/expressions/location-expr.d.ts +15 -15
  121. package/xpath/expressions/location-expr.js +98 -98
  122. package/xpath/expressions/location-expr.js.map +1 -1
  123. package/xpath/expressions/number-expr.d.ts +7 -7
  124. package/xpath/expressions/number-expr.js +33 -33
  125. package/xpath/expressions/number-expr.js.map +1 -1
  126. package/xpath/expressions/path-expr.d.ts +9 -9
  127. package/xpath/expressions/path-expr.js +51 -51
  128. package/xpath/expressions/path-expr.js.map +1 -1
  129. package/xpath/expressions/predicate-expr.d.ts +8 -8
  130. package/xpath/expressions/predicate-expr.js +40 -40
  131. package/xpath/expressions/predicate-expr.js.map +1 -1
  132. package/xpath/expressions/step-expr.d.ts +25 -25
  133. package/xpath/expressions/step-expr.js +280 -280
  134. package/xpath/expressions/step-expr.js.map +1 -1
  135. package/xpath/expressions/token-expr.d.ts +7 -7
  136. package/xpath/expressions/token-expr.js +33 -33
  137. package/xpath/expressions/token-expr.js.map +1 -1
  138. package/xpath/expressions/unary-minus-expr.d.ts +8 -8
  139. package/xpath/expressions/unary-minus-expr.js +33 -33
  140. package/xpath/expressions/unary-minus-expr.js.map +1 -1
  141. package/xpath/expressions/union-expr.d.ts +9 -9
  142. package/xpath/expressions/union-expr.js +50 -50
  143. package/xpath/expressions/union-expr.js.map +1 -1
  144. package/xpath/expressions/variable-expr.d.ts +7 -7
  145. package/xpath/expressions/variable-expr.js +32 -32
  146. package/xpath/expressions/variable-expr.js.map +1 -1
  147. package/xpath/functions/index.d.ts +2 -2
  148. package/xpath/functions/index.js +18 -18
  149. package/xpath/functions/internal-functions.d.ts +2 -2
  150. package/xpath/functions/internal-functions.js +21 -22
  151. package/xpath/functions/internal-functions.js.map +1 -1
  152. package/xpath/functions/non-standard.d.ts +12 -12
  153. package/xpath/functions/non-standard.js +44 -45
  154. package/xpath/functions/non-standard.js.map +1 -1
  155. package/xpath/functions/standard-20.d.ts +5 -5
  156. package/xpath/functions/standard-20.js +25 -26
  157. package/xpath/functions/standard-20.js.map +1 -1
  158. package/xpath/functions/standard.d.ts +40 -40
  159. package/xpath/functions/standard.js +441 -442
  160. package/xpath/functions/standard.js.map +1 -1
  161. package/xpath/grammar-rule-candidate.d.ts +8 -8
  162. package/xpath/grammar-rule-candidate.js +2 -2
  163. package/xpath/index.d.ts +3 -3
  164. package/xpath/index.js +19 -19
  165. package/xpath/match-resolver.d.ts +55 -55
  166. package/xpath/match-resolver.js +136 -136
  167. package/xpath/match-resolver.js.map +1 -1
  168. package/xpath/node-tests/index.d.ts +8 -8
  169. package/xpath/node-tests/index.js +17 -17
  170. package/xpath/node-tests/node-test-any.d.ts +6 -6
  171. package/xpath/node-tests/node-test-any.js +14 -14
  172. package/xpath/node-tests/node-test-comment.d.ts +6 -6
  173. package/xpath/node-tests/node-test-comment.js +14 -14
  174. package/xpath/node-tests/node-test-element-or-attribute.d.ts +6 -6
  175. package/xpath/node-tests/node-test-element-or-attribute.js +15 -15
  176. package/xpath/node-tests/node-test-name.d.ts +10 -10
  177. package/xpath/node-tests/node-test-name.js +38 -38
  178. package/xpath/node-tests/node-test-name.js.map +1 -1
  179. package/xpath/node-tests/node-test-nc.d.ts +9 -9
  180. package/xpath/node-tests/node-test-nc.js +16 -16
  181. package/xpath/node-tests/node-test-pi.d.ts +8 -8
  182. package/xpath/node-tests/node-test-pi.js +16 -16
  183. package/xpath/node-tests/node-test-pi.js.map +1 -1
  184. package/xpath/node-tests/node-test-text.d.ts +6 -6
  185. package/xpath/node-tests/node-test-text.js +14 -14
  186. package/xpath/node-tests/node-test.d.ts +5 -5
  187. package/xpath/node-tests/node-test.js +2 -2
  188. package/xpath/tokens.d.ts +62 -62
  189. package/xpath/tokens.js +300 -300
  190. package/xpath/tokens.js.map +1 -1
  191. package/xpath/values/boolean-value.d.ts +11 -11
  192. package/xpath/values/boolean-value.js +23 -23
  193. package/xpath/values/index.d.ts +5 -5
  194. package/xpath/values/index.js +46 -46
  195. package/xpath/values/node-set-value.d.ts +11 -11
  196. package/xpath/values/node-set-value.js +27 -27
  197. package/xpath/values/node-set-value.js.map +1 -1
  198. package/xpath/values/node-value.d.ts +7 -7
  199. package/xpath/values/node-value.js +2 -2
  200. package/xpath/values/number-value.d.ts +11 -11
  201. package/xpath/values/number-value.js +23 -23
  202. package/xpath/values/string-value.d.ts +11 -11
  203. package/xpath/values/string-value.js +23 -23
  204. package/xpath/xpath-grammar-rules.d.ts +68 -68
  205. package/xpath/xpath-grammar-rules.js +74 -74
  206. package/xpath/xpath-token-rule.d.ts +7 -7
  207. package/xpath/xpath-token-rule.js +2 -2
  208. package/xpath/xpath.d.ts +174 -170
  209. package/xpath/xpath.js +911 -909
  210. package/xpath/xpath.js.map +1 -1
  211. package/xpathdebug.d.ts +2 -2
  212. package/xpathdebug.js +187 -187
  213. package/xpathdebug.js.map +1 -1
  214. package/xslt/index.d.ts +3 -3
  215. package/xslt/index.js +19 -19
  216. package/xslt/xslt-decimal-format-settings.d.ts +28 -28
  217. package/xslt/xslt-decimal-format-settings.js +2 -2
  218. package/xslt/xslt-options.d.ts +7 -7
  219. package/xslt/xslt-options.js +2 -2
  220. package/xslt/xslt-parameter.d.ts +5 -5
  221. package/xslt/xslt-parameter.js +2 -2
  222. package/xslt/xslt.d.ts +207 -190
  223. package/xslt/xslt.js +1135 -1079
  224. package/xslt/xslt.js.map +1 -1
package/xpath/xpath.js CHANGED
@@ -1,910 +1,912 @@
1
- "use strict";
2
- // Copyright 2023-2024 Design Liquido
3
- // Copyright 2018 Johannes Wilm
4
- // Copyright 2005 Google Inc.
5
- // All Rights Reserved
6
- //
7
- // An XPath parser and evaluator written in JavaScript. The
8
- // implementation is complete except for functions handling
9
- // namespaces.
10
- //
11
- // Reference: [XPATH] XPath Specification
12
- // <http://www.w3.org/TR/1999/REC-xpath-19991116>.
13
- //
14
- //
15
- // The API of the parser has several parts:
16
- //
17
- // 1. The parser function xpathParse() that takes a string and returns
18
- // an expession object.
19
- //
20
- // 2. The expression object that has an evaluate() method to evaluate the
21
- // XPath expression it represents. (It is actually a hierarchy of
22
- // objects that resembles the parse tree, but an application will call
23
- // evaluate() only on the top node of this hierarchy.)
24
- //
25
- // 3. The context object that is passed as an argument to the evaluate()
26
- // method, which represents the DOM context in which the expression is
27
- // evaluated.
28
- //
29
- // 4. The value object that is returned from evaluate() and represents
30
- // values of the different types that are defined by XPath (number,
31
- // string, boolean, and node-set), and allows to convert between them.
32
- //
33
- // These parts are near the top of the file, the functions and data
34
- // that are used internally follow after them.
35
- //
36
- //
37
- // Original author: Steffen Meschkat <mesch@google.com>
38
- Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.XPath = void 0;
40
- var util_1 = require("../dom/util");
41
- var common_function_1 = require("./common-function");
42
- var expressions_1 = require("./expressions");
43
- var tokens_1 = require("./tokens");
44
- var xpath_grammar_rules_1 = require("./xpath-grammar-rules");
45
- var node_tests_1 = require("./node-tests");
46
- var constants_1 = require("../constants");
47
- var XPath = /** @class */ (function () {
48
- function XPath() {
49
- // The productions of the grammar. Columns of the table:
50
- //
51
- // - target nonterminal,
52
- // - pattern,
53
- // - precedence,
54
- // - semantic value factory
55
- //
56
- // The semantic value factory is a function that receives parse tree
57
- // nodes from the stack frames of the matched symbols as arguments and
58
- // returns an a node of the parse tree. The node is stored in the top
59
- // stack frame along with the target object of the rule. The node in
60
- // the parse tree is an expression object that has an evaluate() method
61
- // and thus evaluates XPath expressions.
62
- //
63
- // The precedence is used to decide between reducing and shifting by
64
- // comparing the precendence of the rule that is candidate for
65
- // reducing with the precedence of the look ahead token. Precedence of
66
- // -1 means that the precedence of the tokens in the pattern is used
67
- // instead. TODO: It shouldn't be necessary to explicitly assign
68
- // precedences to rules.
69
- // DGF As it stands, these precedences are purely empirical; we're
70
- // not sure they can be made to be consistent at all.
71
- this.xPathGrammarRules = [
72
- [xpath_grammar_rules_1.XPathLocationPath, [xpath_grammar_rules_1.XPathRelativeLocationPath], 18, this.passExpr],
73
- [xpath_grammar_rules_1.XPathLocationPath, [xpath_grammar_rules_1.XPathAbsoluteLocationPath], 18, this.passExpr],
74
- [xpath_grammar_rules_1.XPathAbsoluteLocationPath, [tokens_1.TOK_SLASH, xpath_grammar_rules_1.XPathRelativeLocationPath], 18, this.makeLocationExpr1],
75
- [xpath_grammar_rules_1.XPathAbsoluteLocationPath, [tokens_1.TOK_DSLASH, xpath_grammar_rules_1.XPathRelativeLocationPath], 18, this.makeLocationExpr2],
76
- [xpath_grammar_rules_1.XPathAbsoluteLocationPath, [tokens_1.TOK_SLASH], 0, this.makeLocationExpr3],
77
- [xpath_grammar_rules_1.XPathAbsoluteLocationPath, [tokens_1.TOK_DSLASH], 0, this.makeLocationExpr4],
78
- [xpath_grammar_rules_1.XPathRelativeLocationPath, [xpath_grammar_rules_1.XPathStep], 31, this.makeLocationExpr5],
79
- [xpath_grammar_rules_1.XPathRelativeLocationPath, [xpath_grammar_rules_1.XPathRelativeLocationPath, tokens_1.TOK_SLASH, xpath_grammar_rules_1.XPathStep], 31, this.makeLocationExpr6],
80
- [xpath_grammar_rules_1.XPathRelativeLocationPath, [xpath_grammar_rules_1.XPathRelativeLocationPath, tokens_1.TOK_DSLASH, xpath_grammar_rules_1.XPathStep], 31, this.makeLocationExpr7],
81
- [xpath_grammar_rules_1.XPathStep, [tokens_1.TOK_DOT], 33, this.makeStepExpr1],
82
- [xpath_grammar_rules_1.XPathStep, [tokens_1.TOK_DDOT], 33, this.makeStepExpr2],
83
- [xpath_grammar_rules_1.XPathStep, [tokens_1.TOK_AXISNAME, tokens_1.TOK_AXIS, xpath_grammar_rules_1.XPathNodeTest], 33, this.makeStepExpr3],
84
- [xpath_grammar_rules_1.XPathStep, [tokens_1.TOK_AT, xpath_grammar_rules_1.XPathNodeTest], 33, this.makeStepExpr4],
85
- [xpath_grammar_rules_1.XPathStep, [xpath_grammar_rules_1.XPathNodeTest], 33, this.makeStepExpr5],
86
- [xpath_grammar_rules_1.XPathStep, [xpath_grammar_rules_1.XPathStep, xpath_grammar_rules_1.XPathPredicate], 33, this.makeStepExpr6],
87
- [xpath_grammar_rules_1.XPathNodeTest, [tokens_1.TOK_ASTERISK], 33, this.makeNodeTestExpr1],
88
- [xpath_grammar_rules_1.XPathNodeTest, [tokens_1.TOK_NCNAME, tokens_1.TOK_COLON, tokens_1.TOK_ASTERISK], 33, this.makeNodeTestExpr2],
89
- [xpath_grammar_rules_1.XPathNodeTest, [tokens_1.TOK_QNAME], 33, this.makeNodeTestExpr3],
90
- [xpath_grammar_rules_1.XPathNodeTest, [tokens_1.TOK_NODEO, tokens_1.TOK_PARENC], 33, this.makeNodeTestExpr4],
91
- [xpath_grammar_rules_1.XPathNodeTest, [tokens_1.TOK_NODEO, xpath_grammar_rules_1.XPathLiteral, tokens_1.TOK_PARENC], 33, this.makeNodeTestExpr5],
92
- [xpath_grammar_rules_1.XPathPredicate, [tokens_1.TOK_BRACKO, xpath_grammar_rules_1.XPathExpr, tokens_1.TOK_BRACKC], 33, this.makePredicateExpr],
93
- [xpath_grammar_rules_1.XPathPrimaryExpr, [xpath_grammar_rules_1.XPathVariableReference], 33, this.passExpr],
94
- [xpath_grammar_rules_1.XPathPrimaryExpr, [tokens_1.TOK_PARENO, xpath_grammar_rules_1.XPathExpr, tokens_1.TOK_PARENC], 33, this.makePrimaryExpr],
95
- [xpath_grammar_rules_1.XPathPrimaryExpr, [xpath_grammar_rules_1.XPathLiteral], 30, this.passExpr],
96
- [xpath_grammar_rules_1.XPathPrimaryExpr, [xpath_grammar_rules_1.XPathNumber], 30, this.passExpr],
97
- [xpath_grammar_rules_1.XPathPrimaryExpr, [xpath_grammar_rules_1.XPathFunctionCall], 31, this.passExpr],
98
- [xpath_grammar_rules_1.XPathFunctionCall, [tokens_1.TOK_QNAME, tokens_1.TOK_PARENO, tokens_1.TOK_PARENC], -1, this.makeFunctionCallExpr1],
99
- [
100
- xpath_grammar_rules_1.XPathFunctionCall,
101
- [tokens_1.TOK_QNAME, tokens_1.TOK_PARENO, xpath_grammar_rules_1.XPathExpr, xpath_grammar_rules_1.XPathArgumentRemainder, tokens_1.Q_MM, tokens_1.TOK_PARENC],
102
- -1,
103
- this.makeFunctionCallExpr2
104
- ],
105
- [xpath_grammar_rules_1.XPathArgumentRemainder, [tokens_1.TOK_COMMA, xpath_grammar_rules_1.XPathExpr], -1, this.makeArgumentExpr],
106
- [xpath_grammar_rules_1.XPathUnionExpr, [xpath_grammar_rules_1.XPathPathExpr], 20, this.passExpr],
107
- [xpath_grammar_rules_1.XPathUnionExpr, [xpath_grammar_rules_1.XPathUnionExpr, tokens_1.TOK_PIPE, xpath_grammar_rules_1.XPathPathExpr], 20, this.makeUnionExpr],
108
- [xpath_grammar_rules_1.XPathPathExpr, [xpath_grammar_rules_1.XPathLocationPath], 20, this.passExpr],
109
- [xpath_grammar_rules_1.XPathPathExpr, [xpath_grammar_rules_1.XPathFilterExpr], 19, this.passExpr],
110
- [xpath_grammar_rules_1.XPathPathExpr, [xpath_grammar_rules_1.XPathFilterExpr, tokens_1.TOK_SLASH, xpath_grammar_rules_1.XPathRelativeLocationPath], 19, this.makePathExpr1],
111
- [xpath_grammar_rules_1.XPathPathExpr, [xpath_grammar_rules_1.XPathFilterExpr, tokens_1.TOK_DSLASH, xpath_grammar_rules_1.XPathRelativeLocationPath], 19, this.makePathExpr2],
112
- [xpath_grammar_rules_1.XPathFilterExpr, [xpath_grammar_rules_1.XPathPrimaryExpr, xpath_grammar_rules_1.XPathPredicate, tokens_1.Q_MM], 31, this.makeFilterExpr],
113
- [xpath_grammar_rules_1.XPathExpr, [xpath_grammar_rules_1.XPathPrimaryExpr], 16, this.passExpr],
114
- [xpath_grammar_rules_1.XPathExpr, [xpath_grammar_rules_1.XPathUnionExpr], 16, this.passExpr],
115
- [xpath_grammar_rules_1.XPathExpr, [tokens_1.TOK_MINUS, xpath_grammar_rules_1.XPathExpr], -1, this.makeUnaryMinusExpr],
116
- [xpath_grammar_rules_1.XPathExpr, [xpath_grammar_rules_1.XPathExpr, tokens_1.TOK_OR, xpath_grammar_rules_1.XPathExpr], -1, this.makeBinaryExpr],
117
- [xpath_grammar_rules_1.XPathExpr, [xpath_grammar_rules_1.XPathExpr, tokens_1.TOK_AND, xpath_grammar_rules_1.XPathExpr], -1, this.makeBinaryExpr],
118
- [xpath_grammar_rules_1.XPathExpr, [xpath_grammar_rules_1.XPathExpr, tokens_1.TOK_EQ, xpath_grammar_rules_1.XPathExpr], -1, this.makeBinaryExpr],
119
- [xpath_grammar_rules_1.XPathExpr, [xpath_grammar_rules_1.XPathExpr, tokens_1.TOK_NEQ, xpath_grammar_rules_1.XPathExpr], -1, this.makeBinaryExpr],
120
- [xpath_grammar_rules_1.XPathExpr, [xpath_grammar_rules_1.XPathExpr, tokens_1.TOK_LT, xpath_grammar_rules_1.XPathExpr], -1, this.makeBinaryExpr],
121
- [xpath_grammar_rules_1.XPathExpr, [xpath_grammar_rules_1.XPathExpr, tokens_1.TOK_LE, xpath_grammar_rules_1.XPathExpr], -1, this.makeBinaryExpr],
122
- [xpath_grammar_rules_1.XPathExpr, [xpath_grammar_rules_1.XPathExpr, tokens_1.TOK_GT, xpath_grammar_rules_1.XPathExpr], -1, this.makeBinaryExpr],
123
- [xpath_grammar_rules_1.XPathExpr, [xpath_grammar_rules_1.XPathExpr, tokens_1.TOK_GE, xpath_grammar_rules_1.XPathExpr], -1, this.makeBinaryExpr],
124
- [xpath_grammar_rules_1.XPathExpr, [xpath_grammar_rules_1.XPathExpr, tokens_1.TOK_PLUS, xpath_grammar_rules_1.XPathExpr], -1, this.makeBinaryExpr, tokens_1.ASSOC_LEFT],
125
- [xpath_grammar_rules_1.XPathExpr, [xpath_grammar_rules_1.XPathExpr, tokens_1.TOK_MINUS, xpath_grammar_rules_1.XPathExpr], -1, this.makeBinaryExpr, tokens_1.ASSOC_LEFT],
126
- [xpath_grammar_rules_1.XPathExpr, [xpath_grammar_rules_1.XPathExpr, tokens_1.TOK_ASTERISK, xpath_grammar_rules_1.XPathExpr], -1, this.makeBinaryExpr, tokens_1.ASSOC_LEFT],
127
- [xpath_grammar_rules_1.XPathExpr, [xpath_grammar_rules_1.XPathExpr, tokens_1.TOK_DIV, xpath_grammar_rules_1.XPathExpr], -1, this.makeBinaryExpr, tokens_1.ASSOC_LEFT],
128
- [xpath_grammar_rules_1.XPathExpr, [xpath_grammar_rules_1.XPathExpr, tokens_1.TOK_MOD, xpath_grammar_rules_1.XPathExpr], -1, this.makeBinaryExpr, tokens_1.ASSOC_LEFT],
129
- [xpath_grammar_rules_1.XPathLiteral, [tokens_1.TOK_LITERALQ], -1, this.makeLiteralExpr],
130
- [xpath_grammar_rules_1.XPathLiteral, [tokens_1.TOK_LITERALQQ], -1, this.makeLiteralExpr],
131
- [xpath_grammar_rules_1.XPathNumber, [tokens_1.TOK_NUMBER], -1, this.makeNumberExpr],
132
- [xpath_grammar_rules_1.XPathVariableReference, [tokens_1.TOK_DOLLAR, tokens_1.TOK_QNAME], 200, this.makeVariableReference]
133
- ];
134
- this.xPathParseCache = {};
135
- this.xPathRules = [];
136
- this.xPathLog = function () { };
137
- this.lexerCount = 0;
138
- this.parseCount = 0;
139
- this.reduceCount = 0;
140
- }
141
- // Factory functions for semantic values (i.e. Expressions) of the
142
- // productions in the grammar. When a production is matched to reduce
143
- // the current parse state stack, the export function is called with the
144
- // semantic values of the matched elements as arguments, and returns
145
- // another semantic value. The semantic value is a node of the parse
146
- // tree, an expression object with an evaluate() method that evaluates the
147
- // expression in an actual context. These factory functions are used
148
- // in the specification of the grammar rules, below.
149
- XPath.prototype.makeTokenExpr = function (m) {
150
- return new expressions_1.TokenExpr(m);
151
- };
152
- XPath.prototype.passExpr = function (e) {
153
- return e;
154
- };
155
- XPath.prototype.makeLocationExpr1 = function (slash, rel) {
156
- rel.absolute = true;
157
- return rel;
158
- };
159
- XPath.prototype.makeLocationExpr2 = function (dslash, rel) {
160
- rel.absolute = true;
161
- rel.prependStep(this.makeAbbrevStep(dslash.value));
162
- return rel;
163
- };
164
- XPath.prototype.makeLocationExpr3 = function () {
165
- var ret = new expressions_1.LocationExpr(this);
166
- ret.appendStep(this.makeAbbrevStep('.'));
167
- ret.absolute = true;
168
- return ret;
169
- };
170
- XPath.prototype.makeLocationExpr4 = function (dslash) {
171
- var ret = new expressions_1.LocationExpr(this);
172
- ret.absolute = true;
173
- ret.appendStep(this.makeAbbrevStep(dslash.value));
174
- return ret;
175
- };
176
- XPath.prototype.makeLocationExpr5 = function (step) {
177
- var ret = new expressions_1.LocationExpr(this);
178
- ret.appendStep(step);
179
- return ret;
180
- };
181
- XPath.prototype.makeLocationExpr6 = function (rel, slash, step) {
182
- rel.appendStep(step);
183
- return rel;
184
- };
185
- XPath.prototype.makeLocationExpr7 = function (rel, dslash, step) {
186
- rel.appendStep(this.makeAbbrevStep(dslash.value));
187
- rel.appendStep(step);
188
- return rel;
189
- };
190
- XPath.prototype.makeStepExpr1 = function (dot) {
191
- return this.makeAbbrevStep(dot.value);
192
- };
193
- XPath.prototype.makeStepExpr2 = function (ddot) {
194
- return this.makeAbbrevStep(ddot.value);
195
- };
196
- XPath.prototype.makeStepExpr3 = function (axisname, axis, nodeTest) {
197
- return new expressions_1.StepExpr(axisname.value, nodeTest, this);
198
- };
199
- XPath.prototype.makeStepExpr4 = function (at, nodeTest) {
200
- return new expressions_1.StepExpr('attribute', nodeTest, this);
201
- };
202
- XPath.prototype.makeStepExpr5 = function (nodeTest, axis) {
203
- return new expressions_1.StepExpr(axis || 'child', nodeTest, this);
204
- };
205
- XPath.prototype.makeStepExpr6 = function (step, predicate) {
206
- step.appendPredicate(predicate);
207
- return step;
208
- };
209
- XPath.prototype.makeAbbrevStep = function (abbrev) {
210
- switch (abbrev) {
211
- case '//':
212
- return new expressions_1.StepExpr('descendant-or-self', new node_tests_1.NodeTestAny(), this);
213
- case '.':
214
- return new expressions_1.StepExpr('self', new node_tests_1.NodeTestAny(), this);
215
- case '..':
216
- return new expressions_1.StepExpr('parent', new node_tests_1.NodeTestAny(), this);
217
- }
218
- };
219
- XPath.prototype.makeNodeTestExpr1 = function () {
220
- return new node_tests_1.NodeTestElementOrAttribute();
221
- };
222
- XPath.prototype.makeNodeTestExpr2 = function (ncname) {
223
- return new node_tests_1.NodeTestNC(ncname.value);
224
- };
225
- XPath.prototype.makeNodeTestExpr3 = function (qname) {
226
- return new node_tests_1.NodeTestName(qname.value);
227
- };
228
- XPath.prototype.makeNodeTestExpr4 = function (typeo) {
229
- var type = typeo.value.replace(/\s*\($/, '');
230
- switch (type) {
231
- case 'node':
232
- return new node_tests_1.NodeTestAny();
233
- case 'text':
234
- return new node_tests_1.NodeTestText();
235
- case 'comment':
236
- return new node_tests_1.NodeTestComment();
237
- case 'processing-instruction':
238
- return new node_tests_1.NodeTestPI('');
239
- }
240
- };
241
- XPath.prototype.makeNodeTestExpr5 = function (typeo, target) {
242
- var type = typeo.replace(/\s*\($/, '');
243
- if (type != 'processing-instruction') {
244
- throw type;
245
- }
246
- return new node_tests_1.NodeTestPI(target.value);
247
- };
248
- XPath.prototype.makePredicateExpr = function (pareno, expr) {
249
- return new expressions_1.PredicateExpr(expr);
250
- };
251
- XPath.prototype.makePrimaryExpr = function (pareno, expr) {
252
- return expr;
253
- };
254
- XPath.prototype.makeFunctionCallExpr1 = function (name) {
255
- return new expressions_1.FunctionCallExpr(name);
256
- };
257
- XPath.prototype.makeFunctionCallExpr2 = function (name, pareno, arg1, args) {
258
- var ret = new expressions_1.FunctionCallExpr(name);
259
- ret.appendArg(arg1);
260
- for (var i = 0; i < args.length; ++i) {
261
- ret.appendArg(args[i]);
262
- }
263
- return ret;
264
- };
265
- XPath.prototype.makeArgumentExpr = function (comma, expr) {
266
- return expr;
267
- };
268
- XPath.prototype.makeUnionExpr = function (expr1, pipe, expr2) {
269
- return new expressions_1.UnionExpr(expr1, expr2);
270
- };
271
- XPath.prototype.makePathExpr1 = function (filter, slash, rel) {
272
- return new expressions_1.PathExpr(filter, rel);
273
- };
274
- XPath.prototype.makePathExpr2 = function (filter, dslash, rel) {
275
- rel.prependStep(this.makeAbbrevStep(dslash.value));
276
- return new expressions_1.PathExpr(filter, rel);
277
- };
278
- XPath.prototype.makeFilterExpr = function (expr, predicates) {
279
- if (predicates.length > 0) {
280
- return new expressions_1.FilterExpr(expr, predicates);
281
- }
282
- return expr;
283
- };
284
- XPath.prototype.makeUnaryMinusExpr = function (minus, expr) {
285
- return new expressions_1.UnaryMinusExpr(expr);
286
- };
287
- XPath.prototype.makeBinaryExpr = function (expr1, op, expr2) {
288
- return new expressions_1.BinaryExpr(expr1, op, expr2);
289
- };
290
- XPath.prototype.makeLiteralExpr = function (token) {
291
- // remove quotes from the parsed value:
292
- var value = token.value.substring(1, token.value.length - 1);
293
- return new expressions_1.LiteralExpr(value);
294
- };
295
- XPath.prototype.makeNumberExpr = function (token) {
296
- return new expressions_1.NumberExpr(token.value);
297
- };
298
- XPath.prototype.makeVariableReference = function (dollar, name) {
299
- return new expressions_1.VariableExpr(name.value);
300
- };
301
- /**
302
- * Used before parsing for optimization of common simple cases. See
303
- * the begin of xPathParse() for which they are.
304
- * @param expression The XPath expression.
305
- * @param axis The axis, if required. Default is 'child'.
306
- * @returns An `Expression` object.
307
- */
308
- XPath.prototype.makeSimpleExpr = function (expression, axis) {
309
- if (expression.charAt(0) == '$') {
310
- return new expressions_1.VariableExpr(expression.substr(1));
311
- }
312
- if (expression.charAt(0) == '@') {
313
- var a_1 = new node_tests_1.NodeTestName(expression.substr(1));
314
- var b_1 = new expressions_1.StepExpr('attribute', a_1, this);
315
- var c_1 = new expressions_1.LocationExpr(this);
316
- c_1.appendStep(b_1);
317
- return c_1;
318
- }
319
- if (expression.match(/^[0-9]+$/)) {
320
- return new expressions_1.NumberExpr(expression);
321
- }
322
- var a = new node_tests_1.NodeTestName(expression);
323
- var b = new expressions_1.StepExpr(axis || tokens_1.xPathAxis.CHILD, a, this);
324
- var c = new expressions_1.LocationExpr(this);
325
- c.appendStep(b);
326
- return c;
327
- };
328
- XPath.prototype.makeSimpleExpr2 = function (expr) {
329
- var steps = expr.split('/');
330
- var c = new expressions_1.LocationExpr(this);
331
- for (var i = 0; i < steps.length; ++i) {
332
- var a = new node_tests_1.NodeTestName(steps[i]);
333
- var b = new expressions_1.StepExpr(tokens_1.xPathAxis.CHILD, a, this);
334
- c.appendStep(b);
335
- }
336
- return c;
337
- };
338
- XPath.prototype.stackToString = function (stack) {
339
- var ret = '';
340
- for (var i = 0; i < stack.length; ++i) {
341
- if (ret) {
342
- ret += '\n';
343
- }
344
- ret += stack[i].tag.label;
345
- }
346
- return ret;
347
- };
348
- XPath.prototype.xPathCacheLookup = function (expr) {
349
- return this.xPathParseCache[expr];
350
- };
351
- XPath.prototype.xPathCollectDescendants = function (nodeList, node, opt_tagName) {
352
- if (opt_tagName && node.getElementsByTagName) {
353
- (0, common_function_1.copyArray)(nodeList, node.getElementsByTagName(opt_tagName));
354
- return;
355
- }
356
- for (var n = node.firstChild; n; n = n.nextSibling) {
357
- if (n.nodeType !== constants_1.DOM_ATTRIBUTE_NODE) {
358
- nodeList.push(n);
359
- }
360
- this.xPathCollectDescendants(nodeList, n);
361
- }
362
- };
363
- XPath.prototype.xPathCollectDescendantsReverse = function (nodeList, node) {
364
- for (var n = node.lastChild; n; n = n.previousSibling) {
365
- nodeList.push(n);
366
- this.xPathCollectDescendantsReverse(nodeList, n);
367
- }
368
- };
369
- /**
370
- * Parses and then evaluates the given XPath expression in the given
371
- * input context.
372
- * @param select The xPath string.
373
- * @param context The Expression Context.
374
- * @returns A Node Value.
375
- */
376
- XPath.prototype.xPathEval = function (select, context) {
377
- var expression = this.xPathParse(select);
378
- var response = expression.evaluate(context);
379
- return response;
380
- };
381
- /**
382
- * DGF - extract a tag name suitable for getElementsByTagName
383
- *
384
- * @param nodeTest the node test
385
- * @param ignoreNonElementNodesForNTA if true, the node list returned when
386
- * evaluating "node()" will not contain
387
- * non-element nodes. This can boost
388
- * performance. This is false by default.
389
- */
390
- XPath.prototype.xPathExtractTagNameFromNodeTest = function (nodeTest, ignoreNonElementNodesForNTA) {
391
- if (nodeTest instanceof node_tests_1.NodeTestName) {
392
- return nodeTest.name;
393
- }
394
- if ((ignoreNonElementNodesForNTA && nodeTest instanceof node_tests_1.NodeTestAny) ||
395
- nodeTest instanceof node_tests_1.NodeTestElementOrAttribute) {
396
- return '*';
397
- }
398
- };
399
- XPath.prototype.xPathMatchStack = function (stack, pattern) {
400
- // NOTE(mesch): The stack matches for variable cardinality are
401
- // greedy but don't do backtracking. This would be an issue only
402
- // with rules of the form A* A, i.e. with an element with variable
403
- // cardinality followed by the same element. Since that doesn't
404
- // occur in the grammar at hand, all matches on the stack are
405
- // unambiguous.
406
- var S = stack.length;
407
- var P = pattern.length;
408
- var p;
409
- var s;
410
- var match = [];
411
- match.matchlength = 0;
412
- var ds = 0;
413
- for (p = P - 1, s = S - 1; p >= 0 && s >= 0; --p, s -= ds) {
414
- ds = 0;
415
- var qmatch = [];
416
- if (pattern[p] == tokens_1.Q_MM) {
417
- p -= 1;
418
- match.push(qmatch);
419
- while (s - ds >= 0 && stack[s - ds].tag == pattern[p]) {
420
- qmatch.push(stack[s - ds]);
421
- ds += 1;
422
- match.matchlength += 1;
423
- }
424
- }
425
- else if (pattern[p] == tokens_1.Q_01) {
426
- p -= 1;
427
- match.push(qmatch);
428
- while (s - ds >= 0 && ds < 2 && stack[s - ds].tag == pattern[p]) {
429
- qmatch.push(stack[s - ds]);
430
- ds += 1;
431
- match.matchlength += 1;
432
- }
433
- }
434
- else if (pattern[p] == tokens_1.Q_1M) {
435
- p -= 1;
436
- match.push(qmatch);
437
- if (stack[s].tag == pattern[p]) {
438
- while (s - ds >= 0 && stack[s - ds].tag == pattern[p]) {
439
- qmatch.push(stack[s - ds]);
440
- ds += 1;
441
- match.matchlength += 1;
442
- }
443
- }
444
- else {
445
- return [];
446
- }
447
- }
448
- else if (stack[s].tag == pattern[p]) {
449
- match.push(stack[s]);
450
- ds += 1;
451
- match.matchlength += 1;
452
- }
453
- else {
454
- return [];
455
- }
456
- (0, util_1.reverseInPlace)(qmatch);
457
- qmatch.expr = (0, util_1.mapExpr)(qmatch, function (m) { return m.expr; });
458
- }
459
- (0, util_1.reverseInPlace)(match);
460
- if (p === -1) {
461
- return match;
462
- }
463
- return [];
464
- };
465
- /**
466
- * Finds the best rule for the XPath expression provided.
467
- * @param expression The XPath string expression.
468
- * @param previous The previous matched XPath rule.
469
- * @returns The found rule and the corresponding match.
470
- */
471
- XPath.prototype.findXPathRuleForExpression = function (expression, previous) {
472
- var rule = null;
473
- var match = '';
474
- for (var i = 0; i < tokens_1.xPathTokenRules.length; ++i) {
475
- var result = tokens_1.xPathTokenRules[i].re.exec(expression);
476
- this.lexerCount++;
477
- if (result !== null && result.length > 0 && result[0].length > 0) {
478
- rule = tokens_1.xPathTokenRules[i];
479
- match = result[0];
480
- break;
481
- }
482
- }
483
- // Special case: allow operator keywords to be element and
484
- // variable names.
485
- // NOTE(mesch): The parser resolves conflicts by looking ahead,
486
- // and this is the only case where we look back to
487
- // disambiguate. So this is indeed something different, and
488
- // looking back is usually done in the lexer (via states in the
489
- // general case, called "start conditions" in flex(1)). Also, the
490
- // conflict resolution in the parser is not as robust as it could
491
- // be, so I'd like to keep as much off the parser as possible (all
492
- // these precedence values should be computed from the grammar
493
- // rules and possibly associativity declarations, as in bison(1),
494
- // and not explicitly set.
495
- if (rule &&
496
- (rule == tokens_1.TOK_DIV || rule == tokens_1.TOK_MOD || rule == tokens_1.TOK_AND || rule == tokens_1.TOK_OR) &&
497
- (!previous ||
498
- previous.tag == tokens_1.TOK_AT ||
499
- previous.tag == tokens_1.TOK_DSLASH ||
500
- previous.tag == tokens_1.TOK_SLASH ||
501
- previous.tag == tokens_1.TOK_AXIS ||
502
- previous.tag == tokens_1.TOK_DOLLAR)) {
503
- rule = tokens_1.TOK_QNAME;
504
- }
505
- return { rule: rule, match: match };
506
- };
507
- /**
508
- * Initialization for `xPathParse`.
509
- * @see xPathParse
510
- */
511
- XPath.prototype.xPathParseInit = function () {
512
- if (this.xPathRules.length) {
513
- return;
514
- }
515
- var xPathNonTerminals = [
516
- xpath_grammar_rules_1.XPathLocationPath,
517
- xpath_grammar_rules_1.XPathRelativeLocationPath,
518
- xpath_grammar_rules_1.XPathAbsoluteLocationPath,
519
- xpath_grammar_rules_1.XPathStep,
520
- xpath_grammar_rules_1.XPathNodeTest,
521
- xpath_grammar_rules_1.XPathPredicate,
522
- xpath_grammar_rules_1.XPathLiteral,
523
- xpath_grammar_rules_1.XPathExpr,
524
- xpath_grammar_rules_1.XPathPrimaryExpr,
525
- xpath_grammar_rules_1.XPathVariableReference,
526
- xpath_grammar_rules_1.XPathNumber,
527
- xpath_grammar_rules_1.XPathFunctionCall,
528
- xpath_grammar_rules_1.XPathArgumentRemainder,
529
- xpath_grammar_rules_1.XPathPathExpr,
530
- xpath_grammar_rules_1.XPathUnionExpr,
531
- xpath_grammar_rules_1.XPathFilterExpr,
532
- xpath_grammar_rules_1.XPathDigits
533
- ];
534
- // Some simple optimizations for the xpath expression parser: sort
535
- // grammar rules descending by length, so that the longest match is
536
- // first found.
537
- this.xPathGrammarRules.sort(function (a, b) {
538
- var la = a[1].length;
539
- var lb = b[1].length;
540
- if (la < lb) {
541
- return 1;
542
- }
543
- else if (la > lb) {
544
- return -1;
545
- }
546
- return 0;
547
- });
548
- var k = 1;
549
- for (var i = 0; i < xPathNonTerminals.length; ++i) {
550
- xPathNonTerminals[i].key = k++;
551
- }
552
- for (var i = 0; i < tokens_1.xPathTokenRules.length; ++i) {
553
- tokens_1.xPathTokenRules[i].key = k++;
554
- }
555
- this.xPathLog("XPath parse INIT: ".concat(k, " rules"));
556
- // Another slight optimization: sort the rules into bins according
557
- // to the last element (observing quantifiers), so we can restrict
558
- // the match against the stack to the subest of rules that match the
559
- // top of the stack.
560
- //
561
- // TODO(mesch): What we actually want is to compute states as in
562
- // bison, so that we don't have to do any explicit and iterated
563
- // match against the stack.
564
- function push_(array, position, element) {
565
- if (!array[position]) {
566
- array[position] = [];
567
- }
568
- array[position].push(element);
569
- }
570
- for (var i = 0; i < this.xPathGrammarRules.length; ++i) {
571
- var rule = this.xPathGrammarRules[i];
572
- var pattern = rule[1];
573
- for (var j = pattern.length - 1; j >= 0; --j) {
574
- if (pattern[j] == tokens_1.Q_1M) {
575
- push_(this.xPathRules, pattern[j - 1].key, rule);
576
- break;
577
- }
578
- else if (pattern[j] == tokens_1.Q_MM || pattern[j] == tokens_1.Q_01) {
579
- push_(this.xPathRules, pattern[j - 1].key, rule);
580
- --j;
581
- }
582
- else {
583
- push_(this.xPathRules, pattern[j].key, rule);
584
- break;
585
- }
586
- }
587
- }
588
- this.xPathLog("XPath parse INIT: ".concat(this.xPathRules.length, " rule bins"));
589
- var sum = 0;
590
- (0, util_1.mapExec)(this.xPathRules, function (i) {
591
- if (i) {
592
- sum += i.length;
593
- }
594
- });
595
- this.xPathLog("XPath parse INIT: ".concat(sum / this.xPathRules.length, " average bin size"));
596
- };
597
- /**
598
- * The entry point for the parser.
599
- * @param expression a string that contains an XPath expression.
600
- * @param axis The XPath axis. Used when the match does not start with the parent.
601
- * @returns an expression object that can be evaluated with an
602
- * expression context.
603
- */
604
- XPath.prototype.xPathParse = function (expression, axis) {
605
- var originalExpression = "".concat(expression);
606
- this.xPathLog("parse ".concat(expression));
607
- this.xPathParseInit();
608
- // TODO: Removing the cache for now.
609
- // The cache became a real problem when having to deal with `self-and-siblings`
610
- // axis.
611
- /* const cached = this.xPathCacheLookup(expression);
612
- if (cached && axis === undefined) {
613
- this.xPathLog(' ... cached');
614
- return cached;
615
- } */
616
- // Optimize for a few common cases: simple attribute node tests
617
- // (@id), simple element node tests (page), variable references
618
- // ($address), numbers (4), multi-step path expressions where each
619
- // step is a plain element node test
620
- // (page/overlay/locations/location).
621
- if (expression.match(/^(\$|@)?\w+$/i)) {
622
- var ret = this.makeSimpleExpr(expression, axis);
623
- this.xPathParseCache[expression] = ret;
624
- this.xPathLog(' ... simple');
625
- return ret;
626
- }
627
- if (expression.match(/^\w+(\/\w+)*$/i)) {
628
- var ret = this.makeSimpleExpr2(expression);
629
- this.xPathParseCache[expression] = ret;
630
- this.xPathLog(' ... simple 2');
631
- return ret;
632
- }
633
- var cachekey = expression; // expression is modified during parse
634
- var stack = [];
635
- var ahead = null;
636
- var previous = null;
637
- var done = false;
638
- var parseCount = 0;
639
- this.lexerCount = 0;
640
- var reduceCount = 0;
641
- while (!done) {
642
- parseCount++;
643
- expression = expression.replace(/^\s*/, '');
644
- previous = ahead;
645
- ahead = null;
646
- var _a = this.findXPathRuleForExpression(expression, previous), rule = _a.rule, match = _a.match;
647
- if (rule) {
648
- expression = expression.substr(match.length);
649
- this.xPathLog("token: ".concat(match, " -- ").concat(rule.label));
650
- ahead = {
651
- tag: rule,
652
- match: match,
653
- prec: rule.prec ? rule.prec : 0,
654
- expr: this.makeTokenExpr(match)
655
- };
656
- }
657
- else {
658
- this.xPathLog('DONE');
659
- done = true;
660
- }
661
- while (this.xPathReduce(stack, ahead)) {
662
- reduceCount++;
663
- this.xPathLog("stack: ".concat(this.stackToString(stack)));
664
- }
665
- }
666
- this.xPathLog("stack: ".concat(this.stackToString(stack)));
667
- // DGF any valid XPath should "reduce" to a single Expr token
668
- if (stack.length !== 1) {
669
- throw "XPath parse error ".concat(cachekey, ":\n").concat(this.stackToString(stack));
670
- }
671
- var result = stack[0].expr;
672
- // TODO: Remove this `if` after getting to rewrite `xPathReduce`.
673
- if (axis !== undefined &&
674
- !result.absolute &&
675
- !originalExpression.startsWith('*') &&
676
- result.steps &&
677
- Array.isArray(result.steps)) {
678
- result.steps[0].axis = axis;
679
- }
680
- this.xPathParseCache[cachekey] = result;
681
- this.xPathLog("XPath parse: ".concat(parseCount, " / ").concat(this.lexerCount, " / ").concat(reduceCount));
682
- return result;
683
- };
684
- XPath.prototype.findGrammarRuleCandidate = function (ruleset, stack) {
685
- for (var i = 0; i < ruleset.length; ++i) {
686
- var rule = ruleset[i];
687
- var match = this.xPathMatchStack(stack, rule[1]);
688
- if (match.length) {
689
- var candidate = {
690
- tag: rule[0],
691
- rule: rule,
692
- match: match,
693
- prec: undefined
694
- };
695
- candidate.prec = this.xPathGrammarPrecedence(candidate);
696
- return candidate;
697
- }
698
- }
699
- return null;
700
- };
701
- /**
702
- * DGF xPathReduce is where the magic happens in this parser.
703
- * Check `src\xpath\xpath-grammar-rules.ts` to find the table of
704
- * grammatical rules and precedence numbers, "The productions of the grammar".
705
- *
706
- * The idea here is that we want to take a stack of tokens and apply
707
- * grammatical rules to them, "reducing" them to higher-level
708
- * tokens. Ultimately, any valid XPath should reduce to exactly one
709
- * "Expr" token.
710
-
711
- * Reduce too early or too late and you'll have two tokens that can't reduce
712
- * to single Expr. For example, you may hastily reduce a qname that
713
- * should name a function, incorrectly treating it as a tag name.
714
- * Or you may reduce too late, accidentally reducing the last part of the
715
- * XPath into a top-level "Expr" that won't reduce with earlier parts of
716
- * the XPath.
717
- *
718
- * A "candidate" is a grammatical rule candidate, with a given precedence
719
- * number. "ahead" is the upcoming token, which also has a precedence
720
- * number. If the token has a higher precedence number than
721
- * the rule candidate, we'll "shift" the token onto the token stack,
722
- * instead of immediately applying the rule candidate.
723
- *
724
- * Some tokens have left associativity, in which case we shift when they
725
- * have LOWER precedence than the candidate.
726
- */
727
- XPath.prototype.xPathReduce = function (stack, ahead) {
728
- var candidate = null;
729
- if (stack.length > 0) {
730
- var top_1 = stack[stack.length - 1];
731
- var ruleset = this.xPathRules[top_1.tag.key];
732
- if (ruleset) {
733
- candidate = this.findGrammarRuleCandidate(ruleset, stack);
734
- }
735
- }
736
- var ret;
737
- if (candidate && (!ahead || candidate.prec > ahead.prec || (ahead.tag.left && candidate.prec >= ahead.prec))) {
738
- for (var i = 0; i < candidate.match.matchlength; ++i) {
739
- stack.pop();
740
- }
741
- this.xPathLog("reduce ".concat(candidate.tag.label, " ").concat(candidate.prec, " ahead ").concat(ahead ? ahead.tag.label + ' ' + ahead.prec + (ahead.tag.left ? ' left' : '') : ' none '));
742
- var matchExpression = (0, util_1.mapExpr)(candidate.match, function (m) { return m.expr; });
743
- this.xPathLog("going to apply ".concat(candidate.rule[3]));
744
- candidate.expr = candidate.rule[3].apply(this, matchExpression);
745
- stack.push(candidate);
746
- ret = true;
747
- }
748
- else {
749
- if (ahead) {
750
- this.xPathLog("shift ".concat(ahead.tag.label, " ").concat(ahead.prec).concat(ahead.tag.left ? ' left' : '', " over ").concat(candidate ? candidate.tag.label + ' ' + candidate.prec : ' none'));
751
- stack.push(ahead);
752
- }
753
- ret = false;
754
- }
755
- return ret;
756
- };
757
- /**
758
- * Utility function to sort a list of nodes. Used by xsltSort().
759
- * @param context The Expression Context.
760
- * @param sort TODO
761
- */
762
- XPath.prototype.xPathSort = function (context, sort) {
763
- if (sort.length === 0) {
764
- return;
765
- }
766
- var sortList = [];
767
- for (var i = 0; i < context.contextSize(); ++i) {
768
- var node = context.nodeList[i];
769
- var sortItem = {
770
- node: node,
771
- key: []
772
- };
773
- var clonedContext = context.clone([node], undefined, 0, undefined);
774
- for (var _i = 0, sort_1 = sort; _i < sort_1.length; _i++) {
775
- var s = sort_1[_i];
776
- var value = s.expr.evaluate(clonedContext);
777
- var evalue = void 0;
778
- if (s.type === 'text') {
779
- evalue = value.stringValue();
780
- }
781
- else if (s.type === 'number') {
782
- evalue = value.numberValue();
783
- }
784
- sortItem.key.push({
785
- value: evalue,
786
- order: s.order
787
- });
788
- }
789
- // Make the sort stable by adding a lowest priority sort by
790
- // id. This is very convenient and furthermore required by the
791
- // spec ([XSLT] - Section 10 Sorting).
792
- sortItem.key.push({
793
- value: i,
794
- order: 'ascending'
795
- });
796
- sortList.push(sortItem);
797
- }
798
- sortList.sort(this.xPathSortByKey);
799
- var nodes = [];
800
- for (var i = 0; i < sortList.length; ++i) {
801
- var node = sortList[i].node;
802
- node.siblingPosition = i;
803
- nodes.push(node);
804
- }
805
- context.nodeList = nodes;
806
- context.setNode(0);
807
- };
808
- // Sorts by all order criteria defined. According to the JavaScript
809
- // spec ([ECMA] Section 11.8.5), the compare operators compare strings
810
- // as strings and numbers as numbers.
811
- //
812
- // NOTE: In browsers which do not follow the spec, this breaks only in
813
- // the case that numbers should be sorted as strings, which is very
814
- // uncommon.
815
- XPath.prototype.xPathSortByKey = function (v1, v2) {
816
- // NOTE: Sort key vectors of different length never occur in
817
- // xsltSort.
818
- for (var i = 0; i < v1.key.length; ++i) {
819
- var o = v1.key[i].order == 'descending' ? -1 : 1;
820
- if (v1.key[i].value > v2.key[i].value) {
821
- return +1 * o;
822
- }
823
- if (v1.key[i].value < v2.key[i].value) {
824
- return -1 * o;
825
- }
826
- }
827
- return 0;
828
- };
829
- XPath.prototype.xPathStep = function (nodes, steps, step, input, context) {
830
- var s = steps[step];
831
- var ctx2 = context.clone([input], undefined, 0, undefined);
832
- if (context.returnOnFirstMatch && !s.hasPositionalPredicate) {
833
- var nodeList = s.evaluate(ctx2).nodeSetValue();
834
- // the predicates were not processed in the last evaluate(), so that we can
835
- // process them here with the returnOnFirstMatch optimization. We do a
836
- // depth-first grab at any nodes that pass the predicate tests. There is no
837
- // way to optimize when predicates contain positional selectors, including
838
- // indexes or uses of the last() or position() functions, because they
839
- // typically require the entire nodeList for context. Process without
840
- // optimization if we encounter such selectors.
841
- var nLength = nodeList.length;
842
- var pLength = s.predicate.length;
843
- nodeListLoop: for (var i = 0; i < nLength; ++i) {
844
- for (var j = 0; j < pLength; ++j) {
845
- if (!s.predicate[j].evaluate(context.clone(nodeList, undefined, i, undefined)).booleanValue()) {
846
- continue nodeListLoop;
847
- }
848
- }
849
- // n survived the predicate tests!
850
- if (step == steps.length - 1) {
851
- nodes.push(nodeList[i]);
852
- }
853
- else {
854
- this.xPathStep(nodes, steps, step + 1, nodeList[i], context);
855
- }
856
- if (nodes.length > 0) {
857
- break;
858
- }
859
- }
860
- }
861
- else {
862
- // set returnOnFirstMatch to false for the cloned ExprContext, because
863
- // behavior in StepExpr.prototype.evaluate is driven off its value. Note
864
- // that the original context may still have true for this value.
865
- ctx2.returnOnFirstMatch = false;
866
- var nodeList = s.evaluate(ctx2).nodeSetValue();
867
- for (var i = 0; i < nodeList.length; ++i) {
868
- if (step == steps.length - 1) {
869
- nodes.push(nodeList[i]);
870
- }
871
- else {
872
- this.xPathStep(nodes, steps, step + 1, nodeList[i], context);
873
- }
874
- }
875
- }
876
- };
877
- XPath.prototype.xPathGrammarPrecedence = function (frame) {
878
- var ret = 0;
879
- if (frame.rule) {
880
- /* normal reduce */
881
- if (frame.rule.length >= 3 && frame.rule[2] >= 0) {
882
- ret = frame.rule[2];
883
- }
884
- else {
885
- for (var i = 0; i < frame.rule[1].length; ++i) {
886
- var p = this.xPathTokenPrecedence(frame.rule[1][i]);
887
- ret = Math.max(ret, p);
888
- }
889
- }
890
- }
891
- else if (frame.tag) {
892
- /* TOKEN match */
893
- ret = this.xPathTokenPrecedence(frame.tag);
894
- }
895
- else if (frame.length) {
896
- /* Q_ match */
897
- for (var j = 0; j < frame.length; ++j) {
898
- var p = this.xPathGrammarPrecedence(frame[j]);
899
- ret = Math.max(ret, p);
900
- }
901
- }
902
- return ret;
903
- };
904
- XPath.prototype.xPathTokenPrecedence = function (tag) {
905
- return tag.prec || 2;
906
- };
907
- return XPath;
908
- }());
909
- exports.XPath = XPath;
1
+ "use strict";
2
+ // Copyright 2023-2024 Design Liquido
3
+ // Copyright 2018 Johannes Wilm
4
+ // Copyright 2005 Google Inc.
5
+ // All Rights Reserved
6
+ //
7
+ // An XPath parser and evaluator written in JavaScript. The
8
+ // implementation is complete except for functions handling
9
+ // namespaces.
10
+ //
11
+ // Reference: [XPATH] XPath Specification
12
+ // <http://www.w3.org/TR/1999/REC-xpath-19991116>.
13
+ //
14
+ //
15
+ // The API of the parser has several parts:
16
+ //
17
+ // 1. The parser function xpathParse() that takes a string and returns
18
+ // an expession object.
19
+ //
20
+ // 2. The expression object that has an evaluate() method to evaluate the
21
+ // XPath expression it represents. (It is actually a hierarchy of
22
+ // objects that resembles the parse tree, but an application will call
23
+ // evaluate() only on the top node of this hierarchy.)
24
+ //
25
+ // 3. The context object that is passed as an argument to the evaluate()
26
+ // method, which represents the DOM context in which the expression is
27
+ // evaluated.
28
+ //
29
+ // 4. The value object that is returned from evaluate() and represents
30
+ // values of the different types that are defined by XPath (number,
31
+ // string, boolean, and node-set), and allows to convert between them.
32
+ //
33
+ // These parts are near the top of the file, the functions and data
34
+ // that are used internally follow after them.
35
+ //
36
+ //
37
+ // Original author: Steffen Meschkat <mesch@google.com>
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.XPath = void 0;
40
+ var util_1 = require("../dom/util");
41
+ var common_function_1 = require("./common-function");
42
+ var expressions_1 = require("./expressions");
43
+ var tokens_1 = require("./tokens");
44
+ var xpath_grammar_rules_1 = require("./xpath-grammar-rules");
45
+ var node_tests_1 = require("./node-tests");
46
+ var constants_1 = require("../constants");
47
+ var XPath = /** @class */ (function () {
48
+ function XPath() {
49
+ // The productions of the grammar. Columns of the table:
50
+ //
51
+ // - target non-terminal,
52
+ // - pattern,
53
+ // - precedence,
54
+ // - semantic value factory
55
+ //
56
+ // The semantic value factory is a function that receives parse tree
57
+ // nodes from the stack frames of the matched symbols as arguments and
58
+ // returns an a node of the parse tree. The node is stored in the top
59
+ // stack frame along with the target object of the rule. The node in
60
+ // the parse tree is an expression object that has an evaluate() method
61
+ // and thus evaluates XPath expressions.
62
+ //
63
+ // The precedence is used to decide between reducing and shifting by
64
+ // comparing the precedence of the rule that is candidate for
65
+ // reducing with the precedence of the look ahead token. Precedence of
66
+ // -1 means that the precedence of the tokens in the pattern is used
67
+ // instead. TODO: It shouldn't be necessary to explicitly assign
68
+ // precedences to rules.
69
+ // DGF As it stands, these precedences are purely empirical; we're
70
+ // not sure if they can be made to be consistent at all.
71
+ this.xPathGrammarRules = [
72
+ [xpath_grammar_rules_1.XPathLocationPath, [xpath_grammar_rules_1.XPathRelativeLocationPath], 18, this.passExpr],
73
+ [xpath_grammar_rules_1.XPathLocationPath, [xpath_grammar_rules_1.XPathAbsoluteLocationPath], 18, this.passExpr],
74
+ [xpath_grammar_rules_1.XPathAbsoluteLocationPath, [tokens_1.TOK_SLASH, xpath_grammar_rules_1.XPathRelativeLocationPath], 18, this.makeLocationExpr1],
75
+ [xpath_grammar_rules_1.XPathAbsoluteLocationPath, [tokens_1.TOK_DSLASH, xpath_grammar_rules_1.XPathRelativeLocationPath], 18, this.makeLocationExpr2],
76
+ [xpath_grammar_rules_1.XPathAbsoluteLocationPath, [tokens_1.TOK_SLASH], 0, this.makeLocationExpr3],
77
+ [xpath_grammar_rules_1.XPathAbsoluteLocationPath, [tokens_1.TOK_DSLASH], 0, this.makeLocationExpr4],
78
+ [xpath_grammar_rules_1.XPathRelativeLocationPath, [xpath_grammar_rules_1.XPathStep], 31, this.makeLocationExpr5],
79
+ [xpath_grammar_rules_1.XPathRelativeLocationPath, [xpath_grammar_rules_1.XPathRelativeLocationPath, tokens_1.TOK_SLASH, xpath_grammar_rules_1.XPathStep], 31, this.makeLocationExpr6],
80
+ [xpath_grammar_rules_1.XPathRelativeLocationPath, [xpath_grammar_rules_1.XPathRelativeLocationPath, tokens_1.TOK_DSLASH, xpath_grammar_rules_1.XPathStep], 31, this.makeLocationExpr7],
81
+ [xpath_grammar_rules_1.XPathStep, [tokens_1.TOK_DOT], 33, this.makeStepExpr1],
82
+ [xpath_grammar_rules_1.XPathStep, [tokens_1.TOK_DDOT], 33, this.makeStepExpr2],
83
+ [xpath_grammar_rules_1.XPathStep, [tokens_1.TOK_AXISNAME, tokens_1.TOK_AXIS, xpath_grammar_rules_1.XPathNodeTest], 33, this.makeStepExpr3],
84
+ [xpath_grammar_rules_1.XPathStep, [tokens_1.TOK_AT, xpath_grammar_rules_1.XPathNodeTest], 33, this.makeStepExpr4],
85
+ [xpath_grammar_rules_1.XPathStep, [xpath_grammar_rules_1.XPathNodeTest], 33, this.makeStepExpr5],
86
+ [xpath_grammar_rules_1.XPathStep, [xpath_grammar_rules_1.XPathStep, xpath_grammar_rules_1.XPathPredicate], 33, this.makeStepExpr6],
87
+ [xpath_grammar_rules_1.XPathNodeTest, [tokens_1.TOK_ASTERISK], 33, this.makeNodeTestExpr1],
88
+ [xpath_grammar_rules_1.XPathNodeTest, [tokens_1.TOK_NCNAME, tokens_1.TOK_COLON, tokens_1.TOK_ASTERISK], 33, this.makeNodeTestExpr2],
89
+ [xpath_grammar_rules_1.XPathNodeTest, [tokens_1.TOK_QNAME], 33, this.makeNodeTestExpr3],
90
+ [xpath_grammar_rules_1.XPathNodeTest, [tokens_1.TOK_NODEO, tokens_1.TOK_PARENC], 33, this.makeNodeTestExpr4],
91
+ [xpath_grammar_rules_1.XPathNodeTest, [tokens_1.TOK_NODEO, xpath_grammar_rules_1.XPathLiteral, tokens_1.TOK_PARENC], 33, this.makeNodeTestExpr5],
92
+ [xpath_grammar_rules_1.XPathPredicate, [tokens_1.TOK_BRACKO, xpath_grammar_rules_1.XPathExpr, tokens_1.TOK_BRACKC], 33, this.makePredicateExpr],
93
+ [xpath_grammar_rules_1.XPathPrimaryExpr, [xpath_grammar_rules_1.XPathVariableReference], 33, this.passExpr],
94
+ [xpath_grammar_rules_1.XPathPrimaryExpr, [tokens_1.TOK_PARENO, xpath_grammar_rules_1.XPathExpr, tokens_1.TOK_PARENC], 33, this.makePrimaryExpr],
95
+ [xpath_grammar_rules_1.XPathPrimaryExpr, [xpath_grammar_rules_1.XPathLiteral], 30, this.passExpr],
96
+ [xpath_grammar_rules_1.XPathPrimaryExpr, [xpath_grammar_rules_1.XPathNumber], 30, this.passExpr],
97
+ [xpath_grammar_rules_1.XPathPrimaryExpr, [xpath_grammar_rules_1.XPathFunctionCall], 31, this.passExpr],
98
+ [xpath_grammar_rules_1.XPathFunctionCall, [tokens_1.TOK_QNAME, tokens_1.TOK_PARENO, tokens_1.TOK_PARENC], -1, this.makeFunctionCallExpr1],
99
+ [
100
+ xpath_grammar_rules_1.XPathFunctionCall,
101
+ [tokens_1.TOK_QNAME, tokens_1.TOK_PARENO, xpath_grammar_rules_1.XPathExpr, xpath_grammar_rules_1.XPathArgumentRemainder, tokens_1.Q_ZERO_OR_MULTIPLE, tokens_1.TOK_PARENC],
102
+ -1,
103
+ this.makeFunctionCallExpr2
104
+ ],
105
+ [xpath_grammar_rules_1.XPathArgumentRemainder, [tokens_1.TOK_COMMA, xpath_grammar_rules_1.XPathExpr], -1, this.makeArgumentExpr],
106
+ [xpath_grammar_rules_1.XPathUnionExpr, [xpath_grammar_rules_1.XPathPathExpr], 20, this.passExpr],
107
+ [xpath_grammar_rules_1.XPathUnionExpr, [xpath_grammar_rules_1.XPathUnionExpr, tokens_1.TOK_PIPE, xpath_grammar_rules_1.XPathPathExpr], 20, this.makeUnionExpr],
108
+ [xpath_grammar_rules_1.XPathPathExpr, [xpath_grammar_rules_1.XPathLocationPath], 20, this.passExpr],
109
+ [xpath_grammar_rules_1.XPathPathExpr, [xpath_grammar_rules_1.XPathFilterExpr], 19, this.passExpr],
110
+ [xpath_grammar_rules_1.XPathPathExpr, [xpath_grammar_rules_1.XPathFilterExpr, tokens_1.TOK_SLASH, xpath_grammar_rules_1.XPathRelativeLocationPath], 19, this.makePathExpr1],
111
+ [xpath_grammar_rules_1.XPathPathExpr, [xpath_grammar_rules_1.XPathFilterExpr, tokens_1.TOK_DSLASH, xpath_grammar_rules_1.XPathRelativeLocationPath], 19, this.makePathExpr2],
112
+ [xpath_grammar_rules_1.XPathFilterExpr, [xpath_grammar_rules_1.XPathPrimaryExpr, xpath_grammar_rules_1.XPathPredicate, tokens_1.Q_ZERO_OR_MULTIPLE], 31, this.makeFilterExpr],
113
+ [xpath_grammar_rules_1.XPathExpr, [xpath_grammar_rules_1.XPathPrimaryExpr], 16, this.passExpr],
114
+ [xpath_grammar_rules_1.XPathExpr, [xpath_grammar_rules_1.XPathUnionExpr], 16, this.passExpr],
115
+ [xpath_grammar_rules_1.XPathExpr, [tokens_1.TOK_MINUS, xpath_grammar_rules_1.XPathExpr], -1, this.makeUnaryMinusExpr],
116
+ [xpath_grammar_rules_1.XPathExpr, [xpath_grammar_rules_1.XPathExpr, tokens_1.TOK_OR, xpath_grammar_rules_1.XPathExpr], -1, this.makeBinaryExpr],
117
+ [xpath_grammar_rules_1.XPathExpr, [xpath_grammar_rules_1.XPathExpr, tokens_1.TOK_AND, xpath_grammar_rules_1.XPathExpr], -1, this.makeBinaryExpr],
118
+ [xpath_grammar_rules_1.XPathExpr, [xpath_grammar_rules_1.XPathExpr, tokens_1.TOK_EQ, xpath_grammar_rules_1.XPathExpr], -1, this.makeBinaryExpr],
119
+ [xpath_grammar_rules_1.XPathExpr, [xpath_grammar_rules_1.XPathExpr, tokens_1.TOK_NEQ, xpath_grammar_rules_1.XPathExpr], -1, this.makeBinaryExpr],
120
+ [xpath_grammar_rules_1.XPathExpr, [xpath_grammar_rules_1.XPathExpr, tokens_1.TOK_LT, xpath_grammar_rules_1.XPathExpr], -1, this.makeBinaryExpr],
121
+ [xpath_grammar_rules_1.XPathExpr, [xpath_grammar_rules_1.XPathExpr, tokens_1.TOK_LE, xpath_grammar_rules_1.XPathExpr], -1, this.makeBinaryExpr],
122
+ [xpath_grammar_rules_1.XPathExpr, [xpath_grammar_rules_1.XPathExpr, tokens_1.TOK_GT, xpath_grammar_rules_1.XPathExpr], -1, this.makeBinaryExpr],
123
+ [xpath_grammar_rules_1.XPathExpr, [xpath_grammar_rules_1.XPathExpr, tokens_1.TOK_GE, xpath_grammar_rules_1.XPathExpr], -1, this.makeBinaryExpr],
124
+ [xpath_grammar_rules_1.XPathExpr, [xpath_grammar_rules_1.XPathExpr, tokens_1.TOK_PLUS, xpath_grammar_rules_1.XPathExpr], -1, this.makeBinaryExpr, tokens_1.ASSOC_LEFT],
125
+ [xpath_grammar_rules_1.XPathExpr, [xpath_grammar_rules_1.XPathExpr, tokens_1.TOK_MINUS, xpath_grammar_rules_1.XPathExpr], -1, this.makeBinaryExpr, tokens_1.ASSOC_LEFT],
126
+ [xpath_grammar_rules_1.XPathExpr, [xpath_grammar_rules_1.XPathExpr, tokens_1.TOK_ASTERISK, xpath_grammar_rules_1.XPathExpr], -1, this.makeBinaryExpr, tokens_1.ASSOC_LEFT],
127
+ [xpath_grammar_rules_1.XPathExpr, [xpath_grammar_rules_1.XPathExpr, tokens_1.TOK_DIV, xpath_grammar_rules_1.XPathExpr], -1, this.makeBinaryExpr, tokens_1.ASSOC_LEFT],
128
+ [xpath_grammar_rules_1.XPathExpr, [xpath_grammar_rules_1.XPathExpr, tokens_1.TOK_MOD, xpath_grammar_rules_1.XPathExpr], -1, this.makeBinaryExpr, tokens_1.ASSOC_LEFT],
129
+ [xpath_grammar_rules_1.XPathLiteral, [tokens_1.TOK_LITERALQ], -1, this.makeLiteralExpr],
130
+ [xpath_grammar_rules_1.XPathLiteral, [tokens_1.TOK_LITERALQQ], -1, this.makeLiteralExpr],
131
+ [xpath_grammar_rules_1.XPathNumber, [tokens_1.TOK_NUMBER], -1, this.makeNumberExpr],
132
+ [xpath_grammar_rules_1.XPathVariableReference, [tokens_1.TOK_DOLLAR, tokens_1.TOK_QNAME], 200, this.makeVariableReference]
133
+ ];
134
+ this.xPathParseCache = {};
135
+ this.xPathRules = [];
136
+ this.xPathLog = function () { };
137
+ this.lexerCount = 0;
138
+ this.parseCount = 0;
139
+ this.reduceCount = 0;
140
+ }
141
+ // Factory functions for semantic values (i.e. Expressions) of the
142
+ // productions in the grammar. When a production is matched to reduce
143
+ // the current parse state stack, the export function is called with the
144
+ // semantic values of the matched elements as arguments, and returns
145
+ // another semantic value. The semantic value is a node of the parse
146
+ // tree, an expression object with an evaluate() method that evaluates the
147
+ // expression in an actual context. These factory functions are used
148
+ // in the specification of the grammar rules, below.
149
+ XPath.prototype.makeTokenExpr = function (m) {
150
+ return new expressions_1.TokenExpr(m);
151
+ };
152
+ XPath.prototype.passExpr = function (e) {
153
+ return e;
154
+ };
155
+ XPath.prototype.makeLocationExpr1 = function (slash, rel) {
156
+ rel.absolute = true;
157
+ return rel;
158
+ };
159
+ XPath.prototype.makeLocationExpr2 = function (dslash, rel) {
160
+ rel.absolute = true;
161
+ rel.prependStep(this.makeAbbrevStep(dslash.value));
162
+ return rel;
163
+ };
164
+ XPath.prototype.makeLocationExpr3 = function () {
165
+ var ret = new expressions_1.LocationExpr(this);
166
+ ret.appendStep(this.makeAbbrevStep('.'));
167
+ ret.absolute = true;
168
+ return ret;
169
+ };
170
+ XPath.prototype.makeLocationExpr4 = function (dslash) {
171
+ var ret = new expressions_1.LocationExpr(this);
172
+ ret.absolute = true;
173
+ ret.appendStep(this.makeAbbrevStep(dslash.value));
174
+ return ret;
175
+ };
176
+ XPath.prototype.makeLocationExpr5 = function (step) {
177
+ var ret = new expressions_1.LocationExpr(this);
178
+ ret.appendStep(step);
179
+ return ret;
180
+ };
181
+ XPath.prototype.makeLocationExpr6 = function (rel, slash, step) {
182
+ rel.appendStep(step);
183
+ return rel;
184
+ };
185
+ XPath.prototype.makeLocationExpr7 = function (rel, dslash, step) {
186
+ rel.appendStep(this.makeAbbrevStep(dslash.value));
187
+ rel.appendStep(step);
188
+ return rel;
189
+ };
190
+ XPath.prototype.makeStepExpr1 = function (dot) {
191
+ return this.makeAbbrevStep(dot.value);
192
+ };
193
+ XPath.prototype.makeStepExpr2 = function (ddot) {
194
+ return this.makeAbbrevStep(ddot.value);
195
+ };
196
+ XPath.prototype.makeStepExpr3 = function (axisname, axis, nodeTest) {
197
+ return new expressions_1.StepExpr(axisname.value, nodeTest, this);
198
+ };
199
+ XPath.prototype.makeStepExpr4 = function (at, nodeTest) {
200
+ return new expressions_1.StepExpr('attribute', nodeTest, this);
201
+ };
202
+ XPath.prototype.makeStepExpr5 = function (nodeTest, axis) {
203
+ return new expressions_1.StepExpr(axis || 'child', nodeTest, this);
204
+ };
205
+ XPath.prototype.makeStepExpr6 = function (step, predicate) {
206
+ step.appendPredicate(predicate);
207
+ return step;
208
+ };
209
+ XPath.prototype.makeAbbrevStep = function (abbrev) {
210
+ switch (abbrev) {
211
+ case '//':
212
+ return new expressions_1.StepExpr('descendant-or-self', new node_tests_1.NodeTestAny(), this);
213
+ case '.':
214
+ return new expressions_1.StepExpr('self', new node_tests_1.NodeTestAny(), this);
215
+ case '..':
216
+ return new expressions_1.StepExpr('parent', new node_tests_1.NodeTestAny(), this);
217
+ }
218
+ };
219
+ XPath.prototype.makeNodeTestExpr1 = function () {
220
+ return new node_tests_1.NodeTestElementOrAttribute();
221
+ };
222
+ XPath.prototype.makeNodeTestExpr2 = function (ncname) {
223
+ return new node_tests_1.NodeTestNC(ncname.value);
224
+ };
225
+ XPath.prototype.makeNodeTestExpr3 = function (qname) {
226
+ return new node_tests_1.NodeTestName(qname.value);
227
+ };
228
+ XPath.prototype.makeNodeTestExpr4 = function (typeo) {
229
+ var type = typeo.value.replace(/\s*\($/, '');
230
+ switch (type) {
231
+ case 'node':
232
+ return new node_tests_1.NodeTestAny();
233
+ case 'text':
234
+ return new node_tests_1.NodeTestText();
235
+ case 'comment':
236
+ return new node_tests_1.NodeTestComment();
237
+ case 'processing-instruction':
238
+ return new node_tests_1.NodeTestPI('');
239
+ }
240
+ };
241
+ XPath.prototype.makeNodeTestExpr5 = function (typeo, target) {
242
+ var type = typeo.replace(/\s*\($/, '');
243
+ if (type != 'processing-instruction') {
244
+ throw type;
245
+ }
246
+ return new node_tests_1.NodeTestPI(target.value);
247
+ };
248
+ XPath.prototype.makePredicateExpr = function (pareno, expression) {
249
+ return new expressions_1.PredicateExpr(expression);
250
+ };
251
+ XPath.prototype.makePrimaryExpr = function (pareno, expression) {
252
+ return expression;
253
+ };
254
+ XPath.prototype.makeFunctionCallExpr1 = function (name) {
255
+ return new expressions_1.FunctionCallExpr(name);
256
+ };
257
+ XPath.prototype.makeFunctionCallExpr2 = function (name, pareno, arg1, args) {
258
+ var ret = new expressions_1.FunctionCallExpr(name);
259
+ ret.appendArg(arg1);
260
+ for (var i = 0; i < args.length; ++i) {
261
+ ret.appendArg(args[i]);
262
+ }
263
+ return ret;
264
+ };
265
+ XPath.prototype.makeArgumentExpr = function (comma, expression) {
266
+ return expression;
267
+ };
268
+ XPath.prototype.makeUnionExpr = function (expr1, pipe, expr2) {
269
+ return new expressions_1.UnionExpr(expr1, expr2);
270
+ };
271
+ XPath.prototype.makePathExpr1 = function (filter, slash, rel) {
272
+ return new expressions_1.PathExpr(filter, rel);
273
+ };
274
+ XPath.prototype.makePathExpr2 = function (filter, dslash, rel) {
275
+ rel.prependStep(this.makeAbbrevStep(dslash.value));
276
+ return new expressions_1.PathExpr(filter, rel);
277
+ };
278
+ XPath.prototype.makeFilterExpr = function (expr, predicates) {
279
+ if (predicates.length > 0) {
280
+ return new expressions_1.FilterExpr(expr, predicates);
281
+ }
282
+ return expr;
283
+ };
284
+ XPath.prototype.makeUnaryMinusExpr = function (minus, expr) {
285
+ return new expressions_1.UnaryMinusExpr(expr);
286
+ };
287
+ XPath.prototype.makeBinaryExpr = function (expr1, op, expr2) {
288
+ return new expressions_1.BinaryExpr(expr1, op, expr2);
289
+ };
290
+ XPath.prototype.makeLiteralExpr = function (token) {
291
+ // remove quotes from the parsed value:
292
+ var value = token.value.substring(1, token.value.length - 1);
293
+ return new expressions_1.LiteralExpr(value);
294
+ };
295
+ XPath.prototype.makeNumberExpr = function (token) {
296
+ return new expressions_1.NumberExpr(token.value);
297
+ };
298
+ XPath.prototype.makeVariableReference = function (dollar, name) {
299
+ return new expressions_1.VariableExpr(name.value);
300
+ };
301
+ /**
302
+ * Used before parsing for optimization of common simple cases. See
303
+ * the begin of xPathParse() for which they are.
304
+ * @param expression The XPath expression.
305
+ * @param axis The axis, if required. Default is 'child'.
306
+ * @returns An `Expression` object.
307
+ */
308
+ XPath.prototype.makeSimpleExpr = function (expression, axis) {
309
+ if (expression.charAt(0) == '$') {
310
+ return new expressions_1.VariableExpr(expression.substr(1));
311
+ }
312
+ if (expression.charAt(0) == '@') {
313
+ var a_1 = new node_tests_1.NodeTestName(expression.substr(1));
314
+ var b_1 = new expressions_1.StepExpr('attribute', a_1, this);
315
+ var c_1 = new expressions_1.LocationExpr(this);
316
+ c_1.appendStep(b_1);
317
+ return c_1;
318
+ }
319
+ if (expression.match(/^[0-9]+$/)) {
320
+ return new expressions_1.NumberExpr(expression);
321
+ }
322
+ var a = new node_tests_1.NodeTestName(expression);
323
+ var b = new expressions_1.StepExpr(axis || tokens_1.xPathAxis.CHILD, a, this);
324
+ var c = new expressions_1.LocationExpr(this);
325
+ c.appendStep(b);
326
+ return c;
327
+ };
328
+ XPath.prototype.makeSimpleExpr2 = function (expr) {
329
+ var steps = expr.split('/');
330
+ var c = new expressions_1.LocationExpr(this);
331
+ for (var i = 0; i < steps.length; ++i) {
332
+ var a = new node_tests_1.NodeTestName(steps[i]);
333
+ var b = new expressions_1.StepExpr(tokens_1.xPathAxis.CHILD, a, this);
334
+ c.appendStep(b);
335
+ }
336
+ return c;
337
+ };
338
+ XPath.prototype.stackToString = function (stack) {
339
+ var ret = '';
340
+ for (var i = 0; i < stack.length; ++i) {
341
+ if (ret) {
342
+ ret += '\n';
343
+ }
344
+ ret += stack[i].tag.label;
345
+ }
346
+ return ret;
347
+ };
348
+ XPath.prototype.xPathCacheLookup = function (expr) {
349
+ return this.xPathParseCache[expr];
350
+ };
351
+ XPath.prototype.xPathCollectDescendants = function (nodeList, node, opt_tagName) {
352
+ if (opt_tagName && node.getElementsByTagName) {
353
+ (0, common_function_1.copyArray)(nodeList, node.getElementsByTagName(opt_tagName));
354
+ return;
355
+ }
356
+ for (var n = node.firstChild; n; n = n.nextSibling) {
357
+ if (n.nodeType !== constants_1.DOM_ATTRIBUTE_NODE) {
358
+ nodeList.push(n);
359
+ }
360
+ this.xPathCollectDescendants(nodeList, n);
361
+ }
362
+ };
363
+ XPath.prototype.xPathCollectDescendantsReverse = function (nodeList, node) {
364
+ for (var n = node.lastChild; n; n = n.previousSibling) {
365
+ nodeList.push(n);
366
+ this.xPathCollectDescendantsReverse(nodeList, n);
367
+ }
368
+ };
369
+ /**
370
+ * Parses and then evaluates the given XPath expression in the given
371
+ * input context.
372
+ * @param select The xPath string.
373
+ * @param context The Expression Context.
374
+ * @returns A Node Value.
375
+ */
376
+ XPath.prototype.xPathEval = function (select, context) {
377
+ var expression = this.xPathParse(select);
378
+ var response = expression.evaluate(context);
379
+ return response;
380
+ };
381
+ /**
382
+ * DGF - extract a tag name suitable for getElementsByTagName
383
+ *
384
+ * @param nodeTest the node test
385
+ * @param ignoreNonElementNodesForNTA if true, the node list returned when
386
+ * evaluating "node()" will not contain
387
+ * non-element nodes. This can boost
388
+ * performance. This is false by default.
389
+ */
390
+ XPath.prototype.xPathExtractTagNameFromNodeTest = function (nodeTest, ignoreNonElementNodesForNTA) {
391
+ if (nodeTest instanceof node_tests_1.NodeTestName) {
392
+ return nodeTest.name;
393
+ }
394
+ if ((ignoreNonElementNodesForNTA && nodeTest instanceof node_tests_1.NodeTestAny) ||
395
+ nodeTest instanceof node_tests_1.NodeTestElementOrAttribute) {
396
+ return '*';
397
+ }
398
+ };
399
+ XPath.prototype.xPathMatchStack = function (stack, pattern) {
400
+ // NOTE(mesch): The stack matches for variable cardinality are
401
+ // greedy but don't do backtracking. This would be an issue only
402
+ // with rules of the form A* A, i.e. with an element with variable
403
+ // cardinality followed by the same element. Since that doesn't
404
+ // occur in the grammar at hand, all matches on the stack are
405
+ // unambiguous.
406
+ var stackLength = stack.length;
407
+ var patternLength = pattern.length;
408
+ var p;
409
+ var s;
410
+ var match = [];
411
+ match.matchLength = 0;
412
+ var ds = 0;
413
+ for (p = patternLength - 1, s = stackLength - 1; p >= 0 && s >= 0; --p, s -= ds) {
414
+ ds = 0;
415
+ var qmatch = [];
416
+ if (pattern[p] == tokens_1.Q_ZERO_OR_MULTIPLE) {
417
+ p -= 1;
418
+ match.push(qmatch);
419
+ while (s - ds >= 0 && stack[s - ds].tag == pattern[p]) {
420
+ qmatch.push(stack[s - ds]);
421
+ ds += 1;
422
+ match.matchLength += 1;
423
+ }
424
+ }
425
+ else if (pattern[p] == tokens_1.Q_ZERO_OR_ONE) {
426
+ p -= 1;
427
+ match.push(qmatch);
428
+ while (s - ds >= 0 && ds < 2 && stack[s - ds].tag == pattern[p]) {
429
+ qmatch.push(stack[s - ds]);
430
+ ds += 1;
431
+ match.matchLength += 1;
432
+ }
433
+ }
434
+ else if (pattern[p] == tokens_1.Q_ONE_OR_MULTIPLE) {
435
+ p -= 1;
436
+ match.push(qmatch);
437
+ if (stack[s].tag == pattern[p]) {
438
+ while (s - ds >= 0 && stack[s - ds].tag == pattern[p]) {
439
+ qmatch.push(stack[s - ds]);
440
+ ds += 1;
441
+ match.matchLength += 1;
442
+ }
443
+ }
444
+ else {
445
+ return [];
446
+ }
447
+ }
448
+ else if (stack[s].tag == pattern[p]) {
449
+ match.push(stack[s]);
450
+ ds += 1;
451
+ match.matchLength += 1;
452
+ }
453
+ else {
454
+ return [];
455
+ }
456
+ (0, util_1.reverseInPlace)(qmatch);
457
+ qmatch.expr = (0, util_1.mapExpr)(qmatch, function (m) { return m.expr; });
458
+ }
459
+ (0, util_1.reverseInPlace)(match);
460
+ if (p === -1) {
461
+ return match;
462
+ }
463
+ return [];
464
+ };
465
+ /**
466
+ * Finds the best rule for the XPath expression provided.
467
+ * @param expression The XPath string expression.
468
+ * @param previous The previous matched XPath rule.
469
+ * @returns The found rule and the corresponding match.
470
+ */
471
+ XPath.prototype.findXPathRuleForExpression = function (expression, previous) {
472
+ var rule = null;
473
+ var match = '';
474
+ for (var i = 0; i < tokens_1.xPathTokenRules.length; ++i) {
475
+ var result = tokens_1.xPathTokenRules[i].re.exec(expression);
476
+ this.lexerCount++;
477
+ if (result !== null && result.length > 0 && result[0].length > 0) {
478
+ rule = tokens_1.xPathTokenRules[i];
479
+ match = result[0];
480
+ break;
481
+ }
482
+ }
483
+ // Special case: allow operator keywords to be element and
484
+ // variable names.
485
+ // NOTE(mesch): The parser resolves conflicts by looking ahead,
486
+ // and this is the only case where we look back to
487
+ // disambiguate. So this is indeed something different, and
488
+ // looking back is usually done in the lexer (via states in the
489
+ // general case, called "start conditions" in flex(1)). Also, the
490
+ // conflict resolution in the parser is not as robust as it could
491
+ // be, so I'd like to keep as much off the parser as possible (all
492
+ // these precedence values should be computed from the grammar
493
+ // rules and possibly associativity declarations, as in bison(1),
494
+ // and not explicitly set.
495
+ if (rule &&
496
+ (rule == tokens_1.TOK_DIV || rule == tokens_1.TOK_MOD || rule == tokens_1.TOK_AND || rule == tokens_1.TOK_OR) &&
497
+ (!previous ||
498
+ previous.tag == tokens_1.TOK_AT ||
499
+ previous.tag == tokens_1.TOK_DSLASH ||
500
+ previous.tag == tokens_1.TOK_SLASH ||
501
+ previous.tag == tokens_1.TOK_AXIS ||
502
+ previous.tag == tokens_1.TOK_DOLLAR)) {
503
+ rule = tokens_1.TOK_QNAME;
504
+ }
505
+ return { rule: rule, match: match };
506
+ };
507
+ /**
508
+ * Initialization for `xPathParse`.
509
+ * @see xPathParse
510
+ */
511
+ XPath.prototype.xPathParseInit = function () {
512
+ if (this.xPathRules.length) {
513
+ return;
514
+ }
515
+ var xPathNonTerminals = [
516
+ xpath_grammar_rules_1.XPathLocationPath,
517
+ xpath_grammar_rules_1.XPathRelativeLocationPath,
518
+ xpath_grammar_rules_1.XPathAbsoluteLocationPath,
519
+ xpath_grammar_rules_1.XPathStep,
520
+ xpath_grammar_rules_1.XPathNodeTest,
521
+ xpath_grammar_rules_1.XPathPredicate,
522
+ xpath_grammar_rules_1.XPathLiteral,
523
+ xpath_grammar_rules_1.XPathExpr,
524
+ xpath_grammar_rules_1.XPathPrimaryExpr,
525
+ xpath_grammar_rules_1.XPathVariableReference,
526
+ xpath_grammar_rules_1.XPathNumber,
527
+ xpath_grammar_rules_1.XPathFunctionCall,
528
+ xpath_grammar_rules_1.XPathArgumentRemainder,
529
+ xpath_grammar_rules_1.XPathPathExpr,
530
+ xpath_grammar_rules_1.XPathUnionExpr,
531
+ xpath_grammar_rules_1.XPathFilterExpr,
532
+ xpath_grammar_rules_1.XPathDigits
533
+ ];
534
+ // Some simple optimizations for the xpath expression parser: sort
535
+ // grammar rules descending by length, so that the longest match is
536
+ // first found.
537
+ this.xPathGrammarRules.sort(function (a, b) {
538
+ var la = a[1].length;
539
+ var lb = b[1].length;
540
+ if (la < lb) {
541
+ return 1;
542
+ }
543
+ else if (la > lb) {
544
+ return -1;
545
+ }
546
+ return 0;
547
+ });
548
+ var k = 1;
549
+ for (var i = 0; i < xPathNonTerminals.length; ++i) {
550
+ xPathNonTerminals[i].key = k++;
551
+ }
552
+ for (var i = 0; i < tokens_1.xPathTokenRules.length; ++i) {
553
+ tokens_1.xPathTokenRules[i].key = k++;
554
+ }
555
+ this.xPathLog("XPath parse INIT: ".concat(k, " rules"));
556
+ // Another slight optimization: sort the rules into bins according
557
+ // to the last element (observing quantifiers), so we can restrict
558
+ // the match against the stack to the subest of rules that match the
559
+ // top of the stack.
560
+ //
561
+ // TODO(mesch): What we actually want is to compute states as in
562
+ // bison, so that we don't have to do any explicit and iterated
563
+ // match against the stack.
564
+ function push_(array, position, element) {
565
+ if (!array[position]) {
566
+ array[position] = [];
567
+ }
568
+ array[position].push(element);
569
+ }
570
+ for (var i = 0; i < this.xPathGrammarRules.length; ++i) {
571
+ var rule = this.xPathGrammarRules[i];
572
+ var pattern = rule[1];
573
+ for (var j = pattern.length - 1; j >= 0; --j) {
574
+ if (pattern[j] == tokens_1.Q_ONE_OR_MULTIPLE) {
575
+ push_(this.xPathRules, pattern[j - 1].key, rule);
576
+ break;
577
+ }
578
+ else if (pattern[j] == tokens_1.Q_ZERO_OR_MULTIPLE || pattern[j] == tokens_1.Q_ZERO_OR_ONE) {
579
+ push_(this.xPathRules, pattern[j - 1].key, rule);
580
+ --j;
581
+ }
582
+ else {
583
+ push_(this.xPathRules, pattern[j].key, rule);
584
+ break;
585
+ }
586
+ }
587
+ }
588
+ this.xPathLog("XPath parse INIT: ".concat(this.xPathRules.length, " rule bins"));
589
+ var sum = 0;
590
+ (0, util_1.mapExec)(this.xPathRules, function (i) {
591
+ if (i) {
592
+ sum += i.length;
593
+ }
594
+ });
595
+ this.xPathLog("XPath parse INIT: ".concat(sum / this.xPathRules.length, " average bin size"));
596
+ };
597
+ /**
598
+ * The entry point for the parser.
599
+ * @param expression a string that contains an XPath expression.
600
+ * @param axis The XPath axis. Used when the match does not start with the parent.
601
+ * @returns an expression object that can be evaluated with an
602
+ * expression context.
603
+ */
604
+ XPath.prototype.xPathParse = function (expression, axis) {
605
+ var originalExpression = "".concat(expression);
606
+ this.xPathLog("parse ".concat(expression));
607
+ this.xPathParseInit();
608
+ // TODO: Removing the cache for now.
609
+ // The cache became a real problem when having to deal with `self-and-siblings`
610
+ // axis.
611
+ /* const cached = this.xPathCacheLookup(expression);
612
+ if (cached && axis === undefined) {
613
+ this.xPathLog(' ... cached');
614
+ return cached;
615
+ } */
616
+ // Optimize for a few common cases: simple attribute node tests
617
+ // (@id), simple element node tests (page), variable references
618
+ // ($address), numbers (4), multi-step path expressions where each
619
+ // step is a plain element node test
620
+ // (page/overlay/locations/location).
621
+ if (expression.match(/^(\$|@)?\w+$/i)) {
622
+ var ret = this.makeSimpleExpr(expression, axis);
623
+ this.xPathParseCache[expression] = ret;
624
+ this.xPathLog(' ... simple');
625
+ return ret;
626
+ }
627
+ if (expression.match(/^\w+(\/\w+)*$/i)) {
628
+ var ret = this.makeSimpleExpr2(expression);
629
+ this.xPathParseCache[expression] = ret;
630
+ this.xPathLog(' ... simple 2');
631
+ return ret;
632
+ }
633
+ var cachekey = expression; // expression is modified during parse
634
+ var stack = [];
635
+ var ahead = null;
636
+ var previous = null;
637
+ var done = false;
638
+ var parseCount = 0;
639
+ this.lexerCount = 0;
640
+ var reduceCount = 0;
641
+ while (!done) {
642
+ parseCount++;
643
+ expression = expression.replace(/^\s*/, '');
644
+ previous = ahead;
645
+ ahead = null;
646
+ var _a = this.findXPathRuleForExpression(expression, previous), rule = _a.rule, match = _a.match;
647
+ if (rule) {
648
+ expression = expression.substr(match.length);
649
+ this.xPathLog("token: ".concat(match, " -- ").concat(rule.label));
650
+ ahead = {
651
+ tag: rule,
652
+ match: match,
653
+ prec: rule.prec ? rule.prec : 0, // || 0 is removed by the compiler
654
+ expr: this.makeTokenExpr(match)
655
+ };
656
+ }
657
+ else {
658
+ this.xPathLog('DONE');
659
+ done = true;
660
+ }
661
+ while (this.xPathReduce(stack, ahead)) {
662
+ reduceCount++;
663
+ this.xPathLog("stack: ".concat(this.stackToString(stack)));
664
+ }
665
+ }
666
+ this.xPathLog("stack: ".concat(this.stackToString(stack)));
667
+ // DGF any valid XPath should "reduce" to a single Expr token
668
+ if (stack.length !== 1) {
669
+ throw "XPath parse error ".concat(cachekey, ":\n").concat(this.stackToString(stack));
670
+ }
671
+ var result = stack[0].expr;
672
+ // TODO: Remove this `if` after getting to rewrite `xPathReduce`.
673
+ if (axis !== undefined &&
674
+ !result.absolute &&
675
+ !originalExpression.startsWith('*') &&
676
+ result.steps &&
677
+ Array.isArray(result.steps)) {
678
+ result.steps[0].axis = axis;
679
+ }
680
+ this.xPathParseCache[cachekey] = result;
681
+ this.xPathLog("XPath parse: ".concat(parseCount, " / ").concat(this.lexerCount, " / ").concat(reduceCount));
682
+ return result;
683
+ };
684
+ XPath.prototype.findGrammarRuleCandidate = function (ruleset, stack) {
685
+ for (var i = 0; i < ruleset.length; ++i) {
686
+ var rule = ruleset[i];
687
+ var match = this.xPathMatchStack(stack, rule[1]);
688
+ if (match.length) {
689
+ var candidate = {
690
+ tag: rule[0],
691
+ rule: rule,
692
+ match: match,
693
+ prec: undefined
694
+ };
695
+ candidate.prec = this.xPathGrammarPrecedence(candidate);
696
+ return candidate;
697
+ }
698
+ }
699
+ return null;
700
+ };
701
+ /**
702
+ * DGF xPathReduce is where the magic happens in this parser.
703
+ * Check `src\xpath\xpath-grammar-rules.ts` to find the table of
704
+ * grammatical rules and precedence numbers, "The productions of the grammar".
705
+ *
706
+ * The idea here is that we want to take a stack of tokens and apply
707
+ * grammatical rules to them, "reducing" them to higher-level
708
+ * tokens. Ultimately, any valid XPath should reduce to exactly one
709
+ * "Expr" token.
710
+ *
711
+ * Reduce too early or too late, and you'll have two tokens that can't reduce
712
+ * to single Expr. For example, you may hastily reduce a qname that
713
+ * should name a function, incorrectly treating it as a tag name.
714
+ * Or you may reduce too late, accidentally reducing the last part of the
715
+ * XPath into a top-level "Expr" that won't reduce with earlier parts of
716
+ * the XPath.
717
+ *
718
+ * A "candidate" is a grammatical rule candidate, with a given precedence
719
+ * number. "ahead" is the upcoming token, which also has a precedence
720
+ * number. If the token has a higher precedence number than
721
+ * the rule candidate, we'll "shift" the token onto the token stack,
722
+ * instead of immediately applying the rule candidate.
723
+ *
724
+ * Some tokens have left associativity, in which case we shift when they
725
+ * have LOWER precedence than the candidate.
726
+ * @param stack The actual grammar rule stack.
727
+ * @param ahead The grammar rule ahead.
728
+ * @return `true` if a grammar rule candidate was applied. `false` otherwise.
729
+ * @private
730
+ */
731
+ XPath.prototype.xPathReduce = function (stack, ahead) {
732
+ var candidate = null;
733
+ if (stack.length > 0) {
734
+ var top_1 = stack[stack.length - 1];
735
+ var ruleset = this.xPathRules[top_1.tag.key];
736
+ if (ruleset) {
737
+ candidate = this.findGrammarRuleCandidate(ruleset, stack);
738
+ }
739
+ }
740
+ if (candidate && (!ahead || candidate.prec > ahead.prec || (ahead.tag.left && candidate.prec >= ahead.prec))) {
741
+ for (var i = 0; i < candidate.match.matchLength; ++i) {
742
+ stack.pop();
743
+ }
744
+ this.xPathLog("reduce ".concat(candidate.tag.label, " ").concat(candidate.prec, " ahead ").concat(ahead ? ahead.tag.label + ' ' + ahead.prec + (ahead.tag.left ? ' left' : '') : ' none '));
745
+ var matchExpression = (0, util_1.mapExpr)(candidate.match, function (m) { return m.expr; });
746
+ this.xPathLog("going to apply ".concat(candidate.rule[3]));
747
+ candidate.expr = candidate.rule[3].apply(this, matchExpression);
748
+ stack.push(candidate);
749
+ return true;
750
+ }
751
+ else {
752
+ if (ahead) {
753
+ this.xPathLog("shift ".concat(ahead.tag.label, " ").concat(ahead.prec).concat(ahead.tag.left ? ' left' : '', " over ").concat(candidate ? candidate.tag.label + ' ' + candidate.prec : ' none'));
754
+ stack.push(ahead);
755
+ }
756
+ return false;
757
+ }
758
+ };
759
+ /**
760
+ * Utility function to sort a list of nodes. Used by xsltSort().
761
+ * @param context The Expression Context.
762
+ * @param sort TODO
763
+ */
764
+ XPath.prototype.xPathSort = function (context, sort) {
765
+ if (sort.length === 0) {
766
+ return;
767
+ }
768
+ var sortList = [];
769
+ for (var i = 0; i < context.contextSize(); ++i) {
770
+ var node = context.nodeList[i];
771
+ var sortItem = {
772
+ node: node,
773
+ key: []
774
+ };
775
+ var clonedContext = context.clone([node], undefined, 0, undefined);
776
+ for (var _i = 0, sort_1 = sort; _i < sort_1.length; _i++) {
777
+ var s = sort_1[_i];
778
+ var value = s.expr.evaluate(clonedContext);
779
+ var evalue = void 0;
780
+ if (s.type === 'text') {
781
+ evalue = value.stringValue();
782
+ }
783
+ else if (s.type === 'number') {
784
+ evalue = value.numberValue();
785
+ }
786
+ sortItem.key.push({
787
+ value: evalue,
788
+ order: s.order
789
+ });
790
+ }
791
+ // Make the sort stable by adding a lowest priority sort by
792
+ // id. This is very convenient and furthermore required by the
793
+ // spec ([XSLT] - Section 10 Sorting).
794
+ sortItem.key.push({
795
+ value: i,
796
+ order: 'ascending'
797
+ });
798
+ sortList.push(sortItem);
799
+ }
800
+ sortList.sort(this.xPathSortByKey);
801
+ var nodes = [];
802
+ for (var i = 0; i < sortList.length; ++i) {
803
+ var node = sortList[i].node;
804
+ node.siblingPosition = i;
805
+ nodes.push(node);
806
+ }
807
+ context.nodeList = nodes;
808
+ context.setNode(0);
809
+ };
810
+ // Sorts by all order criteria defined. According to the JavaScript
811
+ // spec ([ECMA] Section 11.8.5), the compare operators compare strings
812
+ // as strings and numbers as numbers.
813
+ //
814
+ // NOTE: In browsers which do not follow the spec, this breaks only in
815
+ // the case that numbers should be sorted as strings, which is very
816
+ // uncommon.
817
+ XPath.prototype.xPathSortByKey = function (v1, v2) {
818
+ // NOTE: Sort key vectors of different length never occur in
819
+ // xsltSort.
820
+ for (var i = 0; i < v1.key.length; ++i) {
821
+ var o = v1.key[i].order == 'descending' ? -1 : 1;
822
+ if (v1.key[i].value > v2.key[i].value) {
823
+ return +1 * o;
824
+ }
825
+ if (v1.key[i].value < v2.key[i].value) {
826
+ return -1 * o;
827
+ }
828
+ }
829
+ return 0;
830
+ };
831
+ XPath.prototype.xPathStep = function (nodes, steps, step, input, context) {
832
+ var s = steps[step];
833
+ var ctx2 = context.clone([input], undefined, 0, undefined);
834
+ if (context.returnOnFirstMatch && !s.hasPositionalPredicate) {
835
+ var nodeList = s.evaluate(ctx2).nodeSetValue();
836
+ // the predicates were not processed in the last evaluate(), so that we can
837
+ // process them here with the returnOnFirstMatch optimization. We do a
838
+ // depth-first grab at any nodes that pass the predicate tests. There is no
839
+ // way to optimize when predicates contain positional selectors, including
840
+ // indexes or uses of the last() or position() functions, because they
841
+ // typically require the entire nodeList for context. Process without
842
+ // optimization if we encounter such selectors.
843
+ var nLength = nodeList.length;
844
+ var pLength = s.predicate.length;
845
+ nodeListLoop: for (var i = 0; i < nLength; ++i) {
846
+ for (var j = 0; j < pLength; ++j) {
847
+ if (!s.predicate[j].evaluate(context.clone(nodeList, undefined, i, undefined)).booleanValue()) {
848
+ continue nodeListLoop;
849
+ }
850
+ }
851
+ // n survived the predicate tests!
852
+ if (step == steps.length - 1) {
853
+ nodes.push(nodeList[i]);
854
+ }
855
+ else {
856
+ this.xPathStep(nodes, steps, step + 1, nodeList[i], context);
857
+ }
858
+ if (nodes.length > 0) {
859
+ break;
860
+ }
861
+ }
862
+ }
863
+ else {
864
+ // set returnOnFirstMatch to false for the cloned ExprContext, because
865
+ // behavior in StepExpr.prototype.evaluate is driven off its value. Note
866
+ // that the original context may still have true for this value.
867
+ ctx2.returnOnFirstMatch = false;
868
+ var nodeList = s.evaluate(ctx2).nodeSetValue();
869
+ for (var i = 0; i < nodeList.length; ++i) {
870
+ if (step == steps.length - 1) {
871
+ nodes.push(nodeList[i]);
872
+ }
873
+ else {
874
+ this.xPathStep(nodes, steps, step + 1, nodeList[i], context);
875
+ }
876
+ }
877
+ }
878
+ };
879
+ XPath.prototype.xPathGrammarPrecedence = function (frame) {
880
+ var ret = 0;
881
+ if (frame.rule) {
882
+ /* normal reduce */
883
+ if (frame.rule.length >= 3 && frame.rule[2] >= 0) {
884
+ ret = frame.rule[2];
885
+ }
886
+ else {
887
+ for (var i = 0; i < frame.rule[1].length; ++i) {
888
+ var p = this.xPathTokenPrecedence(frame.rule[1][i]);
889
+ ret = Math.max(ret, p);
890
+ }
891
+ }
892
+ }
893
+ else if (frame.tag) {
894
+ /* TOKEN match */
895
+ ret = this.xPathTokenPrecedence(frame.tag);
896
+ }
897
+ else if (frame.length) {
898
+ /* Q_ match */
899
+ for (var j = 0; j < frame.length; ++j) {
900
+ var p = this.xPathGrammarPrecedence(frame[j]);
901
+ ret = Math.max(ret, p);
902
+ }
903
+ }
904
+ return ret;
905
+ };
906
+ XPath.prototype.xPathTokenPrecedence = function (tag) {
907
+ return tag.prec || 2;
908
+ };
909
+ return XPath;
910
+ }());
911
+ exports.XPath = XPath;
910
912
  //# sourceMappingURL=xpath.js.map