Skip to content

Commit 031a910

Browse files
committed
add a JS implementation of RegexTreeViewSig
1 parent 4a2472a commit 031a910

File tree

1 file changed

+73
-0
lines changed

1 file changed

+73
-0
lines changed
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/**
2+
* Provides JavaScript-specific definitions for use in the NfaUtils module.
3+
*/
4+
5+
private import codeql.regex.nfa.NfaUtils as NfaUtils
6+
private import codeql.regex.RegexTreeView
7+
8+
/** An implementation that parses a regular expression into a tree of `RegExpTerm`s. */
9+
module RegexTreeView implements RegexTreeViewSig {
10+
import javascript
11+
12+
class Top = Locatable;
13+
14+
/**
15+
* Holds if `term` is an escape class representing e.g. `\d`.
16+
* `clazz` is which character class it represents, e.g. "d" for `\d`.
17+
*/
18+
predicate isEscapeClass(RegExpTerm term, string clazz) {
19+
exists(RegExpCharacterClassEscape escape | term = escape | escape.getValue() = clazz)
20+
}
21+
22+
/**
23+
* Holds if `term` is a possessive quantifier.
24+
* As javascript's regexes do not support possessive quantifiers, this never holds, but is used by the shared library.
25+
*/
26+
predicate isPossessive(RegExpQuantifier term) { none() }
27+
28+
/**
29+
* Holds if the regex that `term` is part of is used in a way that ignores any leading prefix of the input it's matched against.
30+
* Not yet implemented for JavaScript.
31+
*/
32+
predicate matchesAnyPrefix(RegExpTerm term) { any() }
33+
34+
/**
35+
* Holds if the regex that `term` is part of is used in a way that ignores any trailing suffix of the input it's matched against.
36+
* Not yet implemented for JavaScript.
37+
*/
38+
predicate matchesAnySuffix(RegExpTerm term) { any() }
39+
40+
/**
41+
* Holds if the regular expression should not be considered.
42+
*
43+
* For javascript we make the pragmatic performance optimization to ignore minified files.
44+
*/
45+
predicate isExcluded(RegExpParent parent) { parent.(Expr).getTopLevel().isMinified() }
46+
47+
/**
48+
* Holds if `root` has the `i` flag for case-insensitive matching.
49+
*/
50+
predicate isIgnoreCase(RegExpTerm root) { RegExp::isIgnoreCase(getFlags(root)) }
51+
52+
/**
53+
* Gets the flags for `root`, or the empty string if `root` has no flags.
54+
*/
55+
private string getFlags(RegExpTerm root) {
56+
root.isRootTerm() and
57+
exists(DataFlow::RegExpCreationNode node | node.getRoot() = root |
58+
result = node.getFlags()
59+
or
60+
not exists(node.getFlags()) and
61+
result = ""
62+
)
63+
or
64+
exists(RegExpPatternSource source | source.getRegExpTerm() = root |
65+
result = source.getARegExpObject().(DataFlow::RegExpCreationNode).getFlags()
66+
)
67+
}
68+
69+
/**
70+
* Holds if `root` has the `s` flag for multi-line matching.
71+
*/
72+
predicate isDotAll(RegExpTerm root) { RegExp::isDotAll(getFlags(root)) }
73+
}

0 commit comments

Comments
 (0)