Skip to content

Instantly share code, notes, and snippets.

@bholloway
Last active May 21, 2024 12:36
Show Gist options
  • Save bholloway/c9d3bca2265e49e19cd8d1d04e91ecf4 to your computer and use it in GitHub Desktop.
Save bholloway/c9d3bca2265e49e19cd8d1d04e91ecf4 to your computer and use it in GitHub Desktop.
Template literal for multiline regex with comments
/**
* Simple custom template literal that removes comments and whitespace in regex
*/
const regex = ({ raw }, ...substitutions) =>
new RegExp(
String.raw(
{ raw: raw.map(v => v.replace(/\s+#.*$/gm, '').replace(/[\s\r\n]+/g, '')) },
...substitutions,
),
);
/**
* Example: detect import syntax in text
*/
const detectImport = filename =>
regex`
import
[\s\r\n]+ # whitespace (possibly newline)
(?: # optional uncaptured
([\w$]+) # capture $1: default import
[\s\r\n]* # optional whitespace (possibly newline)
)?
(?: # optional uncaptured
,
[\s\r\n]* # optional whitespace (possibly newline)
)?
(?: # optional uncaptured
{
([^}]*) # capture $2: named imports text (anything but closing brace)
}
[\s\r\n]* # optional whitespace (possibly newline)
)?
from
[\s\r\n]+ # whitespace (possibly newline)
'[^']+/${filename}(?:\.js)?' # single quoted module specifier ending in given filename
`,
@DerekZiemba
Copy link

DerekZiemba commented May 21, 2024

Support for flags:

var { re } = (()=>{
  const reComments = /\s+#.*$/gm;
  const reWhitespace = /[\s\r\n]+/g;
  const reFlags = /^[dgimsuvy]+$/;
  const reEscape = /[-\\^$*+?.()|[\]{}]/g;
  function re(strings, ...values) {
    let flags = '';
    if (strings[0] === '' && reFlags.test(values[0])) {
      strings = strings.slice(1);
      flags = values.shift();  
    }
    values = values.map(x=> {
      return Array.isArray(x) 
        ? `(?:${x.map(y=>y.toString().replace(reEscape, '\\$&')).join('|')})` 
        : x.toString().replace(reEscape, '\\$&')
    });
    const raw = strings.map(v => v.replace(reComments, '').replace(reWhitespace, ''))
    const str = String.raw({ raw }, ...values);
    const rgx = new RegExp(str, flags);
    return rgx;
  };
  return { re };
})();
const filename = "/c/my/test/file.js";
re`${'igm'}
      import
      [\s\r\n]+                       # whitespace (possibly newline)
      (?:                             # optional uncaptured
          ([\w$]+)                    # capture $1: default import
          [\s\r\n]*                   # optional whitespace (possibly newline)
      )?
      (?:                             # optional uncaptured
          ,
          [\s\r\n]*                   # optional whitespace (possibly newline)
      )?                              
      (?:                             # optional uncaptured
          {
          ([^}]*)                     # capture $2: named imports text (anything but closing brace)
          }
          [\s\r\n]*                   # optional whitespace (possibly newline)
      )?
      from
      [\s\r\n]+                       # whitespace (possibly newline)
      '[^']+/${filename}(?:\.js)?'    # single quoted module specifier ending in given filename
    `;

=> /import[s]+(?:([w$]+)[s]*)?(?:,[s]*)?(?:{([^}]*)}[s]*)?from[s]+'[^']+\/\/c\/my\/test\/file\.js(?:.js)?'/gim

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment