Index: frontend/node_modules/regjsgen/LICENSE-MIT.txt
===================================================================
--- frontend/node_modules/regjsgen/LICENSE-MIT.txt	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/regjsgen/LICENSE-MIT.txt	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright 2014-2020 Benjamin Tan <https://ofcr.se/>
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Index: frontend/node_modules/regjsgen/README.md
===================================================================
--- frontend/node_modules/regjsgen/README.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/regjsgen/README.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,41 @@
+# regjsgen [![Build status][ci-img]][ci] [![Code coverage status][codecov-img]][codecov]
+
+Generate regular expressions from [regjsparser][regjsparser]’s AST.
+
+## Installation
+
+```sh
+npm i regjsgen
+```
+
+## API
+
+### `regjsgen.generate(ast)`
+
+This function accepts an abstract syntax tree representing a regular expression (see [regjsparser][regjsparser]), and returns the generated regular expression string.
+
+```js
+const regjsparser = require('regjsparser');
+const regjsgen = require('regjsgen');
+
+// Generate an AST with `regjsparser`.
+let ast = regjsparser.parse(regex);
+
+// Modify AST
+// …
+
+// Generate `RegExp` string with `regjsgen`.
+let regex = regjsgen.generate(ast);
+```
+
+## Support
+
+Tested on Node.js 16 and 18.<br>
+Compatible with regjsparser v0.10.0’s AST.
+
+
+[ci]: https://github.com/bnjmnt4n/regjsgen/actions
+[ci-img]: https://github.com/bnjmnt4n/regjsgen/workflows/Node.js%20CI/badge.svg
+[codecov]: https://codecov.io/gh/bnjmnt4n/regjsgen
+[codecov-img]: https://codecov.io/gh/bnjmnt4n/regjsgen/branch/main/graph/badge.svg
+[regjsparser]: https://github.com/jviereck/regjsparser
Index: frontend/node_modules/regjsgen/package.json
===================================================================
--- frontend/node_modules/regjsgen/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/regjsgen/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,40 @@
+{
+  "name": "regjsgen",
+  "version": "0.8.0",
+  "description": "Generate regular expressions from regjsparser’s AST.",
+  "homepage": "https://github.com/bnjmnt4n/regjsgen",
+  "main": "regjsgen.js",
+  "keywords": [
+    "ast",
+    "generate",
+    "regex",
+    "regexp",
+    "regular expressions"
+  ],
+  "license": "MIT",
+  "author": {
+    "name": "Benjamin Tan",
+    "url": "https://ofcr.se/"
+  },
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/bnjmnt4n/regjsgen.git"
+  },
+  "bugs": "https://github.com/bnjmnt4n/regjsgen/issues",
+  "files": [
+    "LICENSE-MIT.txt",
+    "regjsgen.js"
+  ],
+  "scripts": {
+    "test": "node tests/tests.js",
+    "coverage": "nyc --reporter=html npm test",
+    "report-coverage": "nyc --reporter=lcov npm test && codecov",
+    "update-fixtures": "node tests/update-fixtures.js"
+  },
+  "devDependencies": {
+    "codecov": "^3.8.3",
+    "nyc": "^15.1.0",
+    "regjsparser": "^0.10.0",
+    "request": "^2.88.2"
+  }
+}
Index: frontend/node_modules/regjsgen/regjsgen.js
===================================================================
--- frontend/node_modules/regjsgen/regjsgen.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/regjsgen/regjsgen.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,425 @@
+/*!
+ * regjsgen 0.8.0
+ * Copyright 2014-2023 Benjamin Tan <https://ofcr.se/>
+ * Available under the MIT license <https://github.com/bnjmnt4n/regjsgen/blob/main/LICENSE-MIT.txt>
+ */
+;(function() {
+  'use strict';
+
+  // Used to determine if values are of the language type `Object`.
+  var objectTypes = {
+    'function': true,
+    'object': true
+  };
+
+  // Used as a reference to the global object.
+  var root = (objectTypes[typeof window] && window) || this;
+
+  // Detect free variable `exports`.
+  var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports;
+
+  // Detect free variable `module`.
+  var hasFreeModule = objectTypes[typeof module] && module && !module.nodeType;
+
+  // Detect free variable `global` from Node.js or Browserified code and use it as `root`.
+  var freeGlobal = freeExports && hasFreeModule && typeof global == 'object' && global;
+  if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal || freeGlobal.self === freeGlobal)) {
+    root = freeGlobal;
+  }
+
+  // Used to check objects for own properties.
+  var hasOwnProperty = Object.prototype.hasOwnProperty;
+
+  /*--------------------------------------------------------------------------*/
+
+  // Generates a string based on the given code point.
+  // Based on https://mths.be/fromcodepoint by @mathias.
+  function fromCodePoint() {
+    var codePoint = Number(arguments[0]);
+
+    if (
+      !isFinite(codePoint) || // `NaN`, `+Infinity`, or `-Infinity`
+      codePoint < 0 || // not a valid Unicode code point
+      codePoint > 0x10FFFF || // not a valid Unicode code point
+      Math.floor(codePoint) != codePoint // not an integer
+    ) {
+      throw RangeError('Invalid code point: ' + codePoint);
+    }
+
+    if (codePoint <= 0xFFFF) {
+      // BMP code point
+      return String.fromCharCode(codePoint);
+    } else {
+      // Astral code point; split in surrogate halves
+      // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
+      codePoint -= 0x10000;
+      var highSurrogate = (codePoint >> 10) + 0xD800;
+      var lowSurrogate = (codePoint % 0x400) + 0xDC00;
+      return String.fromCharCode(highSurrogate, lowSurrogate);
+    }
+  }
+
+  /*--------------------------------------------------------------------------*/
+
+  // Ensures that nodes have the correct types.
+  var assertTypeRegexMap = {};
+  function assertType(type, expected) {
+    if (expected.indexOf('|') == -1) {
+      if (type == expected) {
+        return;
+      }
+
+      throw Error('Invalid node type: ' + type + '; expected type: ' + expected);
+    }
+
+    expected = hasOwnProperty.call(assertTypeRegexMap, expected)
+      ? assertTypeRegexMap[expected]
+      : (assertTypeRegexMap[expected] = RegExp('^(?:' + expected + ')$'));
+
+    if (expected.test(type)) {
+      return;
+    }
+
+    throw Error('Invalid node type: ' + type + '; expected types: ' + expected);
+  }
+
+  /*--------------------------------------------------------------------------*/
+
+  // Generates a regular expression string based on an AST.
+  function generate(node) {
+    var type = node.type;
+
+    if (hasOwnProperty.call(generators, type)) {
+      return generators[type](node);
+    }
+
+    throw Error('Invalid node type: ' + type);
+  }
+
+  // Constructs a string by concatentating the output of each term.
+  function generateSequence(generator, terms, /* optional */  separator) {
+    var i = -1,
+        length = terms.length,
+        result = '',
+        term;
+
+    while (++i < length) {
+      term = terms[i];
+
+      if (separator && i > 0) result += separator;
+
+      // Ensure that `\0` null escapes followed by number symbols are not
+      // treated as backreferences.
+      if (
+        i + 1 < length &&
+        terms[i].type == 'value' &&
+        terms[i].kind == 'null' &&
+        terms[i + 1].type == 'value' &&
+        terms[i + 1].kind == 'symbol' &&
+        terms[i + 1].codePoint >= 48 &&
+        terms[i + 1].codePoint <= 57
+      ) {
+        result += '\\000';
+        continue;
+      }
+
+      result += generator(term);
+    }
+
+    return result;
+  }
+
+  /*--------------------------------------------------------------------------*/
+
+  function generateAlternative(node) {
+    assertType(node.type, 'alternative');
+
+    return generateSequence(generateTerm, node.body);
+  }
+
+  function generateAnchor(node) {
+    assertType(node.type, 'anchor');
+
+    switch (node.kind) {
+      case 'start':
+        return '^';
+      case 'end':
+        return '$';
+      case 'boundary':
+        return '\\b';
+      case 'not-boundary':
+        return '\\B';
+      default:
+        throw Error('Invalid assertion');
+    }
+  }
+
+  var atomType = 'anchor|characterClass|characterClassEscape|dot|group|reference|unicodePropertyEscape|value';
+
+  function generateAtom(node) {
+    assertType(node.type, atomType);
+
+    return generate(node);
+  }
+
+  function generateCharacterClass(node) {
+    assertType(node.type, 'characterClass');
+
+    var kind = node.kind;
+    var separator = kind === 'intersection' ? '&&' : kind === 'subtraction' ? '--' : '';
+
+    return '[' +
+      (node.negative ? '^' : '') +
+      generateSequence(generateClassAtom, node.body, separator) +
+    ']';
+  }
+
+  function generateCharacterClassEscape(node) {
+    assertType(node.type, 'characterClassEscape');
+
+    return '\\' + node.value;
+  }
+
+  function generateCharacterClassRange(node) {
+    assertType(node.type, 'characterClassRange');
+
+    var min = node.min,
+        max = node.max;
+
+    if (min.type == 'characterClassRange' || max.type == 'characterClassRange') {
+      throw Error('Invalid character class range');
+    }
+
+    return generateClassAtom(min) + '-' + generateClassAtom(max);
+  }
+
+  function generateClassAtom(node) {
+    assertType(node.type, 'anchor|characterClass|characterClassEscape|characterClassRange|dot|value|unicodePropertyEscape|classStrings');
+
+    return generate(node);
+  }
+
+  function generateClassStrings(node) {
+    assertType(node.type, 'classStrings');
+
+    return '\\q{' + generateSequence(generateClassString, node.strings, '|') + '}';
+  }
+
+  function generateClassString(node) {
+    assertType(node.type, 'classString');
+
+    return generateSequence(generate, node.characters);
+  }
+
+  function generateDisjunction(node) {
+    assertType(node.type, 'disjunction');
+
+    return generateSequence(generate, node.body, '|');
+  }
+
+
+  function generateDot(node) {
+    assertType(node.type, 'dot');
+
+    return '.';
+  }
+
+  function generateGroup(node) {
+    assertType(node.type, 'group');
+
+    var result = '';
+
+    switch (node.behavior) {
+      case 'normal':
+        if (node.name) {
+          result += '?<' + generateIdentifier(node.name) + '>';
+        }
+        break;
+      case 'ignore':
+        if (node.modifierFlags) {
+          result += '?';
+          if (node.modifierFlags.enabling) result += node.modifierFlags.enabling;
+          if (node.modifierFlags.disabling) result += "-" + node.modifierFlags.disabling;
+          result += ':';
+        } else {
+          result += '?:';
+        }
+        break;
+      case 'lookahead':
+        result += '?=';
+        break;
+      case 'negativeLookahead':
+        result += '?!';
+        break;
+      case 'lookbehind':
+        result += '?<=';
+        break;
+      case 'negativeLookbehind':
+        result += '?<!';
+        break;
+      default:
+        throw Error('Invalid behaviour: ' + node.behaviour);
+    }
+
+    result += generateSequence(generate, node.body);
+
+    return '(' + result + ')';
+  }
+
+  function generateIdentifier(node) {
+    assertType(node.type, 'identifier');
+
+    return node.value;
+  }
+
+  function generateQuantifier(node) {
+    assertType(node.type, 'quantifier');
+
+    var quantifier = '',
+        min = node.min,
+        max = node.max;
+
+    if (max == null) {
+      if (min == 0) {
+        quantifier = '*';
+      } else if (min == 1) {
+        quantifier = '+';
+      } else {
+        quantifier = '{' + min + ',}';
+      }
+    } else if (min == max) {
+      quantifier = '{' + min + '}';
+    } else if (min == 0 && max == 1) {
+      quantifier = '?';
+    } else {
+      quantifier = '{' + min + ',' + max + '}';
+    }
+
+    if (!node.greedy) {
+      quantifier += '?';
+    }
+
+    return generateAtom(node.body[0]) + quantifier;
+  }
+
+  function generateReference(node) {
+    assertType(node.type, 'reference');
+
+    if (node.matchIndex) {
+      return '\\' + node.matchIndex;
+    }
+    if (node.name) {
+      return '\\k<' + generateIdentifier(node.name) + '>';
+    }
+
+    throw new Error('Unknown reference type');
+  }
+
+  function generateTerm(node) {
+    assertType(node.type, atomType + '|empty|quantifier');
+
+    return generate(node);
+  }
+
+  function generateUnicodePropertyEscape(node) {
+    assertType(node.type, 'unicodePropertyEscape');
+
+    return '\\' + (node.negative ? 'P' : 'p') + '{' + node.value + '}';
+  }
+
+  function generateValue(node) {
+    assertType(node.type, 'value');
+
+    var kind = node.kind,
+        codePoint = node.codePoint;
+
+    if (typeof codePoint != 'number') {
+      throw new Error('Invalid code point: ' + codePoint);
+    }
+
+    switch (kind) {
+      case 'controlLetter':
+        return '\\c' + fromCodePoint(codePoint + 64);
+      case 'hexadecimalEscape':
+        return '\\x' + ('00' + codePoint.toString(16).toUpperCase()).slice(-2);
+      case 'identifier':
+        return '\\' + fromCodePoint(codePoint);
+      case 'null':
+        return '\\' + codePoint;
+      case 'octal':
+        return '\\' + ('000' + codePoint.toString(8)).slice(-3);
+      case 'singleEscape':
+        switch (codePoint) {
+          case 0x0008:
+            return '\\b';
+          case 0x0009:
+            return '\\t';
+          case 0x000A:
+            return '\\n';
+          case 0x000B:
+            return '\\v';
+          case 0x000C:
+            return '\\f';
+          case 0x000D:
+            return '\\r';
+          case 0x002D:
+            return '\\-';
+          default:
+            throw Error('Invalid code point: ' + codePoint);
+        }
+      case 'symbol':
+        return fromCodePoint(codePoint);
+      case 'unicodeEscape':
+        return '\\u' + ('0000' + codePoint.toString(16).toUpperCase()).slice(-4);
+      case 'unicodeCodePointEscape':
+        return '\\u{' + codePoint.toString(16).toUpperCase() + '}';
+      default:
+        throw Error('Unsupported node kind: ' + kind);
+    }
+  }
+
+  /*--------------------------------------------------------------------------*/
+
+  // Used to generate strings for each node type.
+  var generators = {
+    'alternative': generateAlternative,
+    'anchor': generateAnchor,
+    'characterClass': generateCharacterClass,
+    'characterClassEscape': generateCharacterClassEscape,
+    'characterClassRange': generateCharacterClassRange,
+    'classStrings': generateClassStrings,
+    'disjunction': generateDisjunction,
+    'dot': generateDot,
+    'group': generateGroup,
+    'quantifier': generateQuantifier,
+    'reference': generateReference,
+    'unicodePropertyEscape': generateUnicodePropertyEscape,
+    'value': generateValue
+  };
+
+  /*--------------------------------------------------------------------------*/
+
+  // Export regjsgen.
+  var regjsgen = {
+    'generate': generate
+  };
+
+  // Some AMD build optimizers, like r.js, check for condition patterns like the following:
+  if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
+    // Define as an anonymous module so it can be aliased through path mapping.
+    define(function() {
+      return regjsgen;
+    });
+
+    root.regjsgen = regjsgen;
+  }
+  // Check for `exports` after `define` in case a build optimizer adds an `exports` object.
+  else if (freeExports && hasFreeModule) {
+    // Export for CommonJS support.
+    freeExports.generate = generate;
+  }
+  else {
+    // Export to the global object.
+    root.regjsgen = regjsgen;
+  }
+}.call(this));
