1 | const regexpTree = require('regexp-tree');
|
2 |
|
3 | module.exports = function (re, opts) {
|
4 | if (!opts) opts = {};
|
5 | const replimit = opts.limit === undefined ? 25 : opts.limit;
|
6 |
|
7 | let pattern = null;
|
8 | if (isRegExp(re)) pattern = re.source;
|
9 | else if (typeof re === 'string') pattern = re;
|
10 | else pattern = String(re);
|
11 |
|
12 | let ast = null;
|
13 | try {
|
14 | ast = regexpTree.parse(pattern);
|
15 | } catch (err) {
|
16 | try {
|
17 | ast = regexpTree.parse(`/${pattern}/`); }
|
18 | catch (err) {
|
19 | return false;
|
20 | }
|
21 | }
|
22 |
|
23 | let currentStarHeight = 0;
|
24 | let maxObservedStarHeight = 0;
|
25 |
|
26 | let repetitionCount = 0;
|
27 |
|
28 | regexpTree.traverse(ast, {
|
29 | 'Repetition': {
|
30 | pre ({node}) {
|
31 | repetitionCount++;
|
32 |
|
33 | currentStarHeight++;
|
34 | if (maxObservedStarHeight < currentStarHeight) {
|
35 | maxObservedStarHeight = currentStarHeight;
|
36 | }
|
37 | },
|
38 |
|
39 | post ({node}) {
|
40 | currentStarHeight--;
|
41 | }
|
42 | }
|
43 | });
|
44 |
|
45 | return (maxObservedStarHeight <= 1) && (repetitionCount <= replimit);
|
46 | };
|
47 |
|
48 | function isRegExp (x) {
|
49 | return {}.toString.call(x) === '[object RegExp]';
|
50 | }
|