Search code examples
javascriptregexgulp

JS regular expresison add something before bracket


I have the following string:

@something {
  color: red;
  background: yellow;
}

I am trying to add heyaaa before the closing bracket, for example..

@something {
  color: red;
  background: yellow;
  heyaaa
}

I'm using gulp string replace to search a css file for @something and add the needed heyaaa string before the closing bracket.

I tried the following but does not work...

.pipe(replace('^(\@something\s*{(?:\n.*)*?\n)}', 'heyaaa'))

Other regular expressions work so I know there is nothing wrong with my setup.


Solution

  • You are capturing the part from the start until the last semicolon in a group and after that you are matching the closing curly brace. But to get that back in the replacement you have to refer to the capturing group. What you have matched will not be there because you are replacing what you have matched.

    To fix your regex you could capture the last } in a group ^(\@something\s*{(?:\n.*)*?\n)(}) and in the replacement refer to those groups.

    const regex = /^(\@something\s*{(?:\n.*)*?\n)(})/gm;
    const str = `@something {
      color: red;
      background: yellow;
    }`;
    const subst = `$1  heyaa\n$2`;
    const result = str.replace(regex, subst);
    console.log(result);

    To take the start of the string into account and the indentation of the last line, you could match the first line, then repeat while not looking at a new line followed by a }.

    You could capture the whitespace characters at the start in a capturing group and refer to that in the replacement to match the indenting for heyaaa:

    ^(@[^{]+{\s*(?:(?!\n})(\s+).*\n)*)(})
    

    Pattern explanation

    • ^ Start
    • ( Capture group
      • @[^{]+{\s* Match @, 1+t imes not {. Then match { and 0+ times a whitespace char
      • (?: Non capturing group
        • (?!\n})(\s+).*\n Assert what is on the right is not a newline followed by a }. If that is the case, match whole line followed by a new line
      • )* Close group and repeat 0+ times
    • ) Close capturing group
    • (}) Capture Closing parenthesis
    • $ End

    In the replacement you could use the 3 capturing groups:

    $1$2heyaaa\n$3
    

    Regex demo

    Using the callback function, your code might look like:

    .pipe(replace(/^(@[^{]+{\s*(?:(?!\n})(\s+).*\n)*)(})/, function(_,g1,g2,g3) { 
        return g1 + g2 + "heyaaa\n" + g3; }
        )
    )
    

    const regex = /^(@[^{]+{\s*(?:(?!\n})(\s+).*\n)*)(})/gm;
    const str = `@something {
      color: red;
      background: yellow;
    }`;
    const subst = `$1$2heyaaa\n$3`;
    const result = str.replace(regex, subst);
    console.log(result);