title: Why does JavaScript RegExp lack the "s" flag?
body: <p>I love Regular Expressions. However, I've just now come across the inability to use the <code>s</code> flag when running JavaScript RegExp in the browser. I'm curious as to why is this flag not included? It would be really helpful.</p>
  
  <p>I've seen there's an external library <a href="http://xregexp.com/flags/" rel="nofollow noreferrer">XRegExp</a> which enables this <code>s</code> flag (and a few others), but I'm also curious as to why those extra (and helpful) flags don't exist in standard JavaScript too. I'm also loath to include yet another external library...</p>
  
  <p>Here's an example where I'm trying to solve an issue with detecting open/closing tags for WordPress shortcodes which may have newlines within (or I have to insert newlines between to improve the detection).</p>
  
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>//
  // Let's take some input text, e.g. WordPress shortcodes
  //
  var exampleText = '[buttongroup class="vertical"][button content="Example 1" class="btn-default"][/button][button class="btn-primary"]Example 2[/button][/buttongroup]'
  
  //
  // Now let's say I want to extract the shortcodes and its attributes
  // keeping in mind shortcodes can or cannot have closing tags too
  //
  // Shortcodes which have content between the open/closing tags can contain
  // newlines. One of the issues with the flags is that I can't use `s` to make
  // the dot character.
  //
  // When I run this on regex101.com they support the `s` flag (probably with the
  // XRegExp library) and everything seems to work well. However when running this
  // in the browser I get the "Uncaught SyntaxError: Invalid regular expression
  // flags" error.
  //
  var reGetButtons = /\[button(?:\s+([^\]]+))?\](?:(.*)\[\/button\])?/gims
  var reGetButtonGroups = /\[buttongroup(?:\s+([^\]]+))?\](?:(.*)\[\/buttongroup\])?/gims
  
  //
  // Some utility methods to extract attributes:
  //
  
  // Get an attribute's value
  //
  // @param string input
  // @param string attrName
  // @returns string
  function getAttrValue (input, attrName) {
    var attrValue = new RegExp(attrName + '=\"([^\"]+)\"', 'g').exec(input)
    return (attrValue ?  window.decodeURIComponent(attrValue[1]) : '')
  }
  
  // Get all named shortcode attribute values as an object
  //
  // @param string input
  // @param array shortcodeAttrs
  // @returns object
  function getAttrsFromString (input, shortcodeAttrs) {
    var output = {}
    for (var index = 0; index &lt; shortcodeAttrs.length; index++) {
      output[shortcodeAttrs[index]] = getAttrValue(input, shortcodeAttrs[index])
    }
    return output
  }
  
  //
  // Extract all the buttons and get all their attributes and values
  //
  function replaceButtonShortcodes (input) {
    return input
      //
      // Need this to avoid some tomfoolery.
      // By splitting into newlines I can better detect between open/closing tags,
      // however it goes out the window when newlines are within the
      // open/closing tags.
      //
      // It's possible my RegExps above need some adjustments, but I'm unsure how,
      // or maybe I just need to replace newlines with a special character that I
      // can then swap back with newlines...
      //
      .replace(/\]\[/g, ']\n[')
      // Find and replace the [button] shortcodes
      .replace(reGetButtons, function (all, attr, content) {
        console.log('Detected [button] shortcode!')
        console.log('-- Extracted shortcode components', { all: all, attr: attr, content: content })
  
        // Built the output button's HTML attributes
        var attrs = getAttrsFromString(attr, ['class','content'])
        console.log('-- Extracted attributes', { attrs: attrs })
        
        // Return the button's HTML
        return '&lt;button class="btn ' + (typeof attrs.class !== 'undefined' ? attrs.class : '') + '"&gt;' + (content ? content : attrs.content) + '&lt;/button&gt;'
      })
  }
  
  //
  // Extract all the button groups like above
  //
  function replaceButtonGroupShortcodes (input) {
    return input
      // Same as above...
      .replace(/\]\[/g, ']\n[')
      // Find and replace the [buttongroup] shortcodes
      .replace(reGetButtonGroups, function (all, attr, content) {
        console.log('Detected [buttongroup] shortcode!')
        console.log('-- Extracted shortcode components', { all: all, attr: attr, content: content })
        
        // Built the output button's HTML attributes
        var attrs = getAttrsFromString(attr, ['class'])
        console.log('-- Extracted attributes', { attrs: attrs })
        
        // Return the button group's HTML
        return '&lt;div class="btn-group ' + (typeof attrs.class !== 'undefined' ? attrs.class : '' ) + '"&gt;' + (typeof content !== 'undefined' ? content : '') + '&lt;/div&gt;'
      })
  }
  
  //
  // Do all the extraction on our example text and set within the document's HTML
  //
  var outputText = replaceButtonShortcodes(exampleText)
  outputText = replaceButtonGroupShortcodes(outputText)
  document.write(outputText)</code></pre>
  </div>
  </div>
  </p>
  
  <p>Using the <code>s</code> flag would allow me to do it easily, however since it's unsupported, I can't utilise the benefits of the flag.</p>