Replacement

You can use the -R, --replace replacement::String flag to replace each matched node with the replacement text you specify instead of printing out the matches. In Grasp, positional arguments can be anywhere, not just at the end - this means that you can do grasp selector --replace replacement file.js, if that reads better for you.

For a bunch of examples, check out Refactoring your JavaScript code with Grasp.

There are a couple of special cases in the replacement text. First, the text {{}} will be replaced with the source of the matched node.

For instance, the replacement text f({{}}) would result in each match being replaced with a call to the function f with the match as its argument.

$ cat file.js
if (y < 2) {
  window.x = y + z;
}
$ grasp '[left=#y]' --replace 'f({{}})' file.js
if (f(y < 2)) {
  window.x = f(y + z);
}

Second, the text {{selector}} will be replaced with the first result of querying the matched node with the specified selector. The query engine used to process the selector will be the same as you used for searching, eg. if you used equery to search for matches (with the -e, --equery flag), then the replacement selector will also use equery.

An example:

$ cat file.js
if (y < 2) {
  window.x = y + z;
}
$ grasp if --replace 'while ({{.test}}) {\n  f(++{{assign bi.left}});\n}' file.js
while (y < 2) {
  f(++y);
}

If a node has any named matches (currently only a feature of equery, eg. $name or _$items), you can access this named submatch by simply using the name instead of a selector, eg. {{name}}, {{items}}.

If more than one match is found, the first match is used. If you would like to print out more than one match, you can use the join filter.

The replacement text you specify replaces the entire text of the matched node in the source - if you poorly form your replacement, then the result will be poorly formed as well.

By default, the results of using --replace will be printed out. If you wish to write new file(s), check out the --to option, or if you wish edit the input file(s) in place, check out the --in-place option.

Filters

You can append a variety of filters to your selector in the {{selector}} syntax. Each filter starts off with a spaced pipe, eg. {{ selector | filter1 | filter2 }}.

If the selector is left out (eg. {{ | filter | filter2 }}), the filters are applied to the whole matched node.

Filters may have zero of more arguments. Arguments are listed after the filter name and are separated by a comma. {{ selector | filter arg0, arg1 }}.

The available filters are (the code [1, 2, 3, 4]; will be used for the examples):

join

join [separator] - Takes the list of matches and joins them with the optional separator argument. If no separator is specified, they are joined with an empty string.

Eg. grasp arr --replace '[{{.elements | join "," }}]'[1,2,3,4];

prepend

prepend args... - Prepends (aka unshifts) its arguments to the list of matches.

Eg. grasp arr --replace '[{{.elements | prepend 0 | join "," }}]'[0,1,2,3,4];

append

append args... - Appends (aka pushes) its arguments to the list of matches.

Eg. grasp arr --replace '[{{.elements | append 5 | join "," }}]'[1,2,3,4,5];

before

before arg - Prepends its text argument to the entire result. Equivalent to arg{{}}. More useful with each.

Eg. grasp arr --replace '{{ 1 | before "0." }}'0.1;

after

after arg - Appends its text argument to the entire result. Equivalent to {{}}arg. More useful with each.

Eg. grasp arr --replace '{{ 1 | after 0 }}'10;

wrap

wrap arg, [arg] - Wraps its text arguments around the entire result. If only one argument is supplied, it uses that for both before and after. If two arguments are supplied, the first argument is prepended, and the second is appended. Equivalent to arg{{}}arg. Again, this is more useful with each.

Eg. grasp arr --replace '{{ 1 | wrap \" }}'"1";

Eg. grasp arr --replace '{{ 1 | wrap [ ] }}'[1];

each

each filter, [args...] - Takes a filter (either before, after, or wrap) and applies it to each matched node.

Eg. grasp arr --replace '[{{.elements | each before, 1 | join "," }}]'[11,12,13,14];

Eg. grasp arr --replace '[{{.elements | each after, 0 | join "," }}]'[10,20,30,40];

Eg. grasp arr --replace '[{{.elements | each wrap, "(", ")" | join "," }}]'[(1),(2),(3),(4)];

nth

nth num - Takes the nth node of the matched results. Zero based indexing.

Eg. grasp arr --replace '{{.elements | nth 0 }}'1;

nth-last

nth-last num - Takes the nth last node of the matched results. Zero based indexing.

Eg. grasp arr --replace '{{.elements | nth-last 0 }}'4;

first

first - Takes the first node of the matched results. Equivalent to nth 0.

Eg. grasp arr --replace '{{.elements | first }}'1;

tail

tail - Takes all but the first node of the matched results.

Eg. grasp arr --replace '[{{.elements | tail | join "," }}]'[2,3,4];

last

last - Takes the last node of the matched results. Equivalent to nth-last 0.

Eg. grasp arr --replace '{{.elements | last | join "," }}'4;

initial

initial - Takes all but the last node of the matched results.

Eg. grasp arr --replace '[{{.elements | initial | join "," }}]'[1,2,3];

slice

slice num, [num] - Acts like JavaScript’s slice on the matched results.

Eg. grasp arr --replace '[{{.elements | slice 2 | join "," }}]'[3,4];

Eg. grasp arr --replace '[{{.elements | slice 2 3 | join "," }}]'[3];

reverse

reverse - Reverses the list of matched results.

Eg. grasp arr --replace '[{{.elements | reverse | join "," }}]'[4,3,2,1];

replace

replace regex-pattern, replacement - String replacement of matched result, just like JavaScript’s "String".replace(pattern, replacement) function.

lowercase

lowercase - Lowercases string result of matched output, just like JavaScript’s "String".toLowerCase()

uppercase

uppercase - Uppercases string result of matched output, just like JavaScript’s "String".toUpperCase()

trim

trim - Trims string result of matched output, just like JavaScript’s "String".trim()

capitalize

capitalize - Capitalizes the string result of matched output.

uncapitalize

uncapitalize - Uncapitalizes the string result of matched output.

camelize

camelize - Camelizes the string result of matched output.

dasherize

dasherize - Dasherizes the string result of matched output.

substring

substring startIndex, [endIndex] - Gets substring of string result of matched output, just like JavaScript’s "String".substring(startIndex, endIndex)

substr

substring startIndex, [length] - Gets substring of string result of matched output, just like JavaScript’s "String".substr(startIndex, length)

str-slice

str-slice startIndex, [endIndex] - Gets substring of string result of matched output, just like JavaScript’s "String".slice(startIndex, endIndex)