Skip to content

Commit fea32af

Browse files
committed
Added Workers for handing certain expression timeout errors.
1 parent 038f078 commit fea32af

File tree

8 files changed

+125
-22
lines changed

8 files changed

+125
-22
lines changed

Gruntfile.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ module.exports = function (grunt) {
5050
},
5151
build: {
5252
files: {
53-
"<%= deployFolder %>js/uglify.min.js":getScripts().uglify
53+
"<%= deployFolder %>js/uglify.min.js":getScripts().uglify,
54+
"<%= deployFolder %>js/regExWorker.template.js":"js/regExWorker.template.js"
5455
}
5556
}
5657
},
@@ -153,6 +154,7 @@ module.exports = function (grunt) {
153154
grunt.registerTask("parse-index", function (type) {
154155
var templateFile = grunt.file.read("index.html");
155156
var indexJs = minifyJS(grunt.file.read("js/index.template.js"));
157+
156158
var buildIndexTag = "\n"+indexJs+"";
157159

158160
var output = grunt.template.process(templateFile, {data:{build:true, index:buildIndexTag, noCache:Date.now()}})

index.html

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
<meta name="description" content="Regular expression tester with syntax highlighting, contextual help, video tutorial, reference, and searchable community patterns." />
1111

12+
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
13+
1214
<!-- Windows8 Pin to home. -->
1315
<meta name="application-name" content="RegExr"/>
1416
<meta name="msapplication-TileColor" content="#44A4E0"/>
@@ -23,6 +25,7 @@
2325

2426
<!-- Only use these tags during a build. -->
2527
<!-- <% if (build) { %> -->
28+
<script src="js/regExWorker.template.js?no=<%=noCache %>"></script>
2629
<script src="js/scripts.min.js?no=<%=noCache %>"></script>
2730
<!-- <% } else { %> -->
2831
<!--
@@ -39,6 +42,7 @@
3942
<script src="js/third-party/placeholders.min.js"></script>
4043
<script src="js/third-party/history.adapter.native.js"></script>
4144
<script src="js/third-party/history.js"></script>
45+
<script src="js/RegExJS.js"></script>
4246
<script src="js/events/Event.js"></script>
4347
<script src="js/events/EventDispatcher.js"></script>
4448
<script src="js/Tracking.js"></script>
@@ -380,7 +384,6 @@ <h1 class="icon regexr-logo">&#xE600;</h1><h1 class="regexr-text">RegExr</h1><sp
380384
}
381385
}
382386
</script>
383-
384387
<!-- <% if (build) { %> -->
385388
<script>
386389
// injected on build:<%=index %>

js/RegExJS.js

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
(function (scope) {
2+
"use strict";
3+
4+
var s = {};
5+
6+
s.match = function (regex, str, callback) {
7+
var matches = [];
8+
var error = null;
9+
var match = null;
10+
var index = null;
11+
12+
if (!regex) {
13+
callback(error, matches);
14+
return;
15+
}
16+
17+
if (window.Worker) {
18+
if (s.worker) {
19+
clearTimeout(s.id);
20+
s.worker.terminate();
21+
}
22+
23+
s.worker = new Worker("js/regExWorker.template.js");
24+
25+
s.worker.onmessage = function (evt) {
26+
// When the worker says its loaded start a timer. (For IE 10);
27+
if (evt.data == "onload") {
28+
s.id = setTimeout(function () {
29+
callback("timeout", matches);
30+
s.worker.terminate();
31+
}, 250);
32+
} else {
33+
matches = evt.data.matches;
34+
error = evt.data.error;
35+
clearTimeout(s.id);
36+
callback(error, matches);
37+
}
38+
}
39+
s.worker.postMessage({regex: regex, str: str});
40+
} else {
41+
while (!error) {
42+
match = regex.exec(str);
43+
if (!match) { break; }
44+
if (regex.global && index === regex.lastIndex) {
45+
error = "infinite";
46+
break;
47+
}
48+
match.end = (index = match.index + match[0].length) - 1;
49+
match.input = null;
50+
matches.push(match);
51+
if (!regex.global) { break; } // or it will become infinite.
52+
}
53+
callback(error, matches);
54+
}
55+
};
56+
57+
scope.RegExJS = s;
58+
59+
}(window));

js/documentation.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,12 @@ var library = {
6161
label:"The 'infinite' error",
6262
desc:"The expression can match 0 characters, and therefore matches infinitely.",
6363
ext:" <h1>Example:</h1><code>.*</code> can match <code>0</code> characters, and therefore will match infinitely."
64+
},
65+
{
66+
id:"timeout",
67+
label:"The 'timeout' error",
68+
desc:"The expression took longer than 250ms to execute.<br><span class='small-text'><hr>** Certain patterns can cause exponential growth, and may timeout.</span>",
69+
ext:" <h1>Example:</h1> Using <code>^(a+)+$</code> to match <code>aaaaaaaaaaaaaaaaaaaaaaaaaaaaB</code> will match each 'a' an indeterminate number of times, and therefore will eventually timeout."
6470
}
6571
]
6672
},

js/regExWorker.template.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
onmessage = function (evt) {
2+
"use strict";
3+
var regex = evt.data.regex;
4+
var str = evt.data.str;
5+
var error = null;
6+
var matches = [];
7+
var match, index;
8+
9+
// Let the callee know we're loaded (for IE 10);
10+
postMessage("onload");
11+
12+
if (!regex) {
13+
postMessage({error: error, matches: matches});
14+
self.close();
15+
return;
16+
}
17+
18+
while (!error) {
19+
match = regex.exec(str);
20+
if (!match) { break; }
21+
if (regex.global && index === regex.lastIndex) {
22+
error = "infinite";
23+
break;
24+
}
25+
match.end = (index = match.index + match[0].length) - 1;
26+
match.input = null;
27+
matches.push(match);
28+
if (!regex.global) { break; } // or it will become infinite.
29+
}
30+
31+
postMessage({error: error, matches: matches});
32+
self.close();
33+
}

js/views/DocView.js

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2222
SOFTWARE.
2323
*/
2424
(function() {
25-
25+
2626
var DocView = function(element) {
2727
this.initialize(element);
2828
};
@@ -409,28 +409,24 @@ SOFTWARE.
409409
catch (e) { this.error = "ERROR"; }
410410
matches.length = index = 0;
411411

412-
while (!this.error) {
413-
match = regex.exec(str);
414-
if (!match) { break; }
415-
if (g && index === regex.lastIndex) { this.error = "infinite"; break; }
416-
match.end = (index = match.index+match[0].length)-1;
417-
match.input = null;
418-
matches.push(match);
419-
if (!g) { break; } // or it will become infinite.
420-
}
412+
var _this = this;
413+
RegExJS.match(regex, str, function(error, matches) {
414+
_this.error = error;
415+
_this.matches = matches;
421416

422-
this.updateResults();
423-
$.defer(this, this.drawSourceHighlights, "draw");
417+
_this.updateResults();
418+
$.defer(_this, _this.drawSourceHighlights, "draw");
424419

425-
if (ExpressionModel.isDirty()) {
426-
BrowserHistory.go();
427-
}
420+
if (ExpressionModel.isDirty()) {
421+
BrowserHistory.go();
422+
}
428423

429-
if (ExpressionModel.id) {
430-
BrowserHistory.go($.createID(ExpressionModel.id));
431-
}
424+
if (ExpressionModel.id) {
425+
BrowserHistory.go($.createID(ExpressionModel.id));
426+
}
432427

433-
this.updateSubst(str, regex);
428+
_this.updateSubst(str, regex);
429+
});
434430
};
435431

436432
p.updateSubst = function(source, regex) {

scripts.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"js/third-party/placeholders.min.js",
1313
"js/third-party/history.adapter.native.js",
1414
"js/third-party/history.js",
15+
"js/RegExJS.js",
1516
"js/events/Event.js",
1617
"js/events/EventDispatcher.js",
1718
"js/utils/Utils.js",

scss/shared.scss

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@
9191
background: $theme-color;
9292
color: $color;
9393
}
94-
94+
9595
.item.removed {
9696
text-decoration: line-through;
9797
opacity: 0.5;
@@ -187,3 +187,6 @@
187187
display: inline-block;
188188
}
189189

190+
.small-text {
191+
font-size: .7rem;
192+
}

0 commit comments

Comments
 (0)