Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Syntactically-aware grep for JavaScript
JavaScript
tree: 759c7c1d86

Fetching latest commit…

Cannot retrieve the latest commit at this time

Failed to load latest commit information.
lib
specs
tests
.gitignore
README.mdown
jsgrep
jspatch

README.mdown

jsgrep: a syntactically-aware grep for JavaScript

Jsgrep is program that searches for a particular JavaScript pattern using the abstract syntax tree (AST) of the program. This enables matching expressions based on their JavaScript meaning, rather than based on simple strings.

Examples

Find calls to window.setTimeout with a 0 timeout

$ jsgrep 'setTimeout(A, 0)' tests/*.js
tests/jquery.js:        setTimeout( function() {
tests/jquery.js:    setTimeout( clearFxNow, 0 );

Jsgrep uses metavariables as wildcards. Metavariables match any valid JavaScript chunk, so in this case, the first match was an entire inline function. In both cases, the second parameter to setTimeout was a literal value of 0.

Find value defaulting

$ jsgrep "A = A || B;" tests/*.js
tests/jquery.js:            args = args || [];
tests/jquery.js:    dataType = dataType || options.dataTypes[ 0 ];

When the pattern references the same metavariable multiple times, jsgrep ensures that the value of the metavariable is the same throughout the match.

Find the names of all invoked events

$ ./jsgrep -p B "A.fire(B, ...)" tests/*.js
tests/connect.js: 'auth.logout'
tests/connect.js: 'auth.login'

The ... operator matches 0 or more expressions in function calls and array initializers. This example also uses the -p flag to print only a particular matched variable.

Find classes that have a 'path' property

$ jsgrep -p C "JX.install(C, { properties: { path: X } })" tests/*.js
tests/javelin.js: 'Event'
tests/javelin.js: 'URI'

Jsgrep allows you to search object initializations partially, which enables easily drilling into the structure of JavaScript classes.

jspatch

Jsgrep allows you to identify source code that resembles a certain pattern. Jspatch is a tool to take that information and programmatically modify the original source code.

Replace setTimeout with window.setTimeout

$ ./jspatch -e 's/setTimeout( A, B )/window.setTimeout( A, B )/' tests/jquery.js
--- tests/jquery.js 2012-01-10 14:51:36.000000000 -0800
+++ /tmp/jspatch.jquery.js  2012-01-11 17:13:56.000000000 -0800
@@ -420,7 +420,7 @@
        if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) {
            // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
            if ( !document.body ) {
-               return setTimeout( jQuery.ready, 1 );
+               return window.setTimeout( jQuery.ready, 1 );
            }

            // Remember that the DOM is ready
@@ -1987,7 +1987,7 @@
        ( src === "mark" || !jQuery._data(elem, markDataKey) ) ) {
        // Give room for hard-coded callbacks to fire first
        // and eventually mark/queue something else on the element
-       setTimeout( function() {
+       window.setTimeout( function() {
            if ( !jQuery._data( elem, queueDataKey ) &&
                !jQuery._data( elem, markDataKey ) ) {
                jQuery.removeData( elem, deferDataKey, true );

Sed mode allows you to quickly perform simple substitutions on the source code.

TODO

  • Consider a metavar that matches but doesn't save, to prevent ambiguities.
  • Consider support for --where/--eval and/or not-patterns
  • Support for most statements in patterns
  • Formally testing the pattern matchers

jspatch:

  • Make the substitution work at the tokenizer level rather than the AST level.

Contributors

Jsgrep was written by Ryan Patterson at Facebook. Inspiration for this project draws heavily from pfff, a source code analyzer written at Facebook.

Something went wrong with that request. Please try again.