adamreisnz / replace-in-file

A simple utility to quickly replace contents in one or more files
580 stars 65 forks source link

Parenthesis in replacement from string breaks match/replacement counting #156

Closed cnatis closed 1 year ago

cnatis commented 2 years ago

Steps to reproduce: Setup a from string with parenthesis ie. app.setVersion('${sourceVersion}'); Run the replacement Check the output value for numReplacements and numMatches, it will be 0, however the change was made

Change the from string to remove the parenthesis ie. '${sourceVersion}' Run the replacement Check the output value for numReplacements and numMatches, it will be 1 and the change was made

Note that including a single parenthesis seems to cause errors to be thrown

replace-in-file/lib/helpers/make-replacements.js:58
      const matches = contents.match(item);
                               ^

SyntaxError: Invalid regular expression: /'1.0.0');/: Unmatched ')'
    at String.match (<anonymous>)
    at node_modules/replace-in-file/lib/helpers/make-replacements.js:58:32
    at Array.reduce (<anonymous>)
    at makeReplacements (node_modules/replace-in-file/lib/helpers/make-replacements.js:37:28)
    at node_modules/replace-in-file/lib/helpers/replace-async.js:26:37
    at FSReqCallback.readFileAfterClose [as oncomplete] (node:internal/fs/read_file_context:68:3)
adamreisnz commented 2 years ago

Can you please supply an example with full options config that you're using, including from/to strings. It looks to me like you're perhaps supplying a regex but not escaping parenthesis properly.

PrescottPS commented 1 year ago

@adamreisnz @cnatis

I met same issue either.

After check the source code, seems this is because the count matches function use String.match() to get the number of matches, in which will try to convert the plain string of option from to a RegExp by using new RegExp(from).

So if the string in from option can not be converted to a RegExp, it will throw an error.

And if the from string contains some special character of regexp, there might have chance that the replacement was made but the number of matches is 0.

Check below code snippets for details:

const originStr = "app.setVersion('${sourceVersion}');"
const to = "1.0.0";
let from;

// Case 1: String can be converted to RegExp
from = "sourceVersion";
console.log(originStr.replace(from, to)); // output: app.setVersion('${1.0.0}');
console.log(originStr.match(from)); // matches length is 1

// Case 2: String can be converted to RegExp, but with char need to escaped
from = "${sourceVersion}"
console.log(originStr.replace(from, to)); // output: app.setVersion('1.0.0');
console.log(originStr.match(from)); // null, replacement made, but got 0 matches

// Case 3: String can not be converted to RegExp
from = "${sourceVersion}')";
console.log(originStr.replace(from, to)); // output: app.setVersion('1.0.0;
console.log(originStr.match(from)); // throw error
adamreisnz commented 1 year ago

Thanks, this has been fixed in 7.0.0