Run `npm run install-deps` on NPM 7.4.5

This CL contains the output of running `npm run install-deps` on
NPM 7.4.5. This includes a version bump of the package-lock.json,
which means all DevTools engineers who run `npm run install-deps`
should use NPM 7+. Additionally, this allows `npm run dedupe` to
produce a better output and remove more duplicate packages.
For more information, see https://github.com/eslint/eslint/issues/14098

DISABLE_THIRD_PARTY_CHECK=NPM update
R=jacktfranklin@chromium.org

Bug: none
Change-Id: Id1ca2f33f3bb7d555dca1c0737d38bc1c7f5221c
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/2705386
Commit-Queue: Tim van der Lippe <tvanderlippe@chromium.org>
Reviewed-by: Jack Franklin <jacktfranklin@chromium.org>
diff --git a/node_modules/picomatch/lib/parse.js b/node_modules/picomatch/lib/parse.js
old mode 100644
new mode 100755
index ccb41de..34bdc2f
--- a/node_modules/picomatch/lib/parse.js
+++ b/node_modules/picomatch/lib/parse.js
@@ -1,7 +1,7 @@
 'use strict';
 
-const utils = require('./utils');
 const constants = require('./constants');
+const utils = require('./utils');
 
 /**
  * Constants
@@ -10,7 +10,7 @@
 const {
   MAX_LENGTH,
   POSIX_REGEX_SOURCE,
-  REGEX_NON_SPECIAL_CHAR,
+  REGEX_NON_SPECIAL_CHARS,
   REGEX_SPECIAL_CHARS_BACKREF,
   REPLACEMENTS
 } = constants;
@@ -25,10 +25,10 @@
   }
 
   args.sort();
-  let value = `[${args.join('-')}]`;
+  const value = `[${args.join('-')}]`;
 
   try {
-    /* eslint-disable no-new */
+    /* eslint-disable-next-line no-new */
     new RegExp(value);
   } catch (ex) {
     return args.map(v => utils.escapeRegex(v)).join('..');
@@ -37,24 +37,6 @@
   return value;
 };
 
-const negate = state => {
-  let count = 1;
-
-  while (state.peek() === '!' && (state.peek(2) !== '(' || state.peek(3) === '?')) {
-    state.advance();
-    state.start++;
-    count++;
-  }
-
-  if (count % 2 === 0) {
-    return false;
-  }
-
-  state.negated = true;
-  state.start++;
-  return true;
-};
-
 /**
  * Create the message for a syntax error
  */
@@ -77,18 +59,19 @@
 
   input = REPLACEMENTS[input] || input;
 
-  let opts = { ...options };
-  let max = typeof opts.maxLength === 'number' ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH;
+  const opts = { ...options };
+  const max = typeof opts.maxLength === 'number' ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH;
+
   let len = input.length;
   if (len > max) {
     throw new SyntaxError(`Input length: ${len}, exceeds maximum allowed length: ${max}`);
   }
 
-  let bos = { type: 'bos', value: '', output: opts.prepend || '' };
-  let tokens = [bos];
+  const bos = { type: 'bos', value: '', output: opts.prepend || '' };
+  const tokens = [bos];
 
-  let capture = opts.capture ? '' : '?:';
-  let win32 = utils.isWindows(options);
+  const capture = opts.capture ? '' : '?:';
+  const win32 = utils.isWindows(options);
 
   // create constants based on platform, for windows or posix
   const PLATFORM_CHARS = constants.globChars(win32);
@@ -113,9 +96,9 @@
     return `(${capture}(?:(?!${START_ANCHOR}${opts.dot ? DOTS_SLASH : DOT_LITERAL}).)*?)`;
   };
 
-  let nodot = opts.dot ? '' : NO_DOT;
+  const nodot = opts.dot ? '' : NO_DOT;
+  const qmarkNoDot = opts.dot ? QMARK : QMARK_NO_DOT;
   let star = opts.bash === true ? globstar(opts) : STAR;
-  let qmarkNoDot = opts.dot ? QMARK : QMARK_NO_DOT;
 
   if (opts.capture) {
     star = `(${star})`;
@@ -126,21 +109,30 @@
     opts.noextglob = opts.noext;
   }
 
-  let state = {
+  const state = {
+    input,
     index: -1,
     start: 0,
+    dot: opts.dot === true,
     consumed: '',
     output: '',
+    prefix: '',
     backtrack: false,
+    negated: false,
     brackets: 0,
     braces: 0,
     parens: 0,
     quotes: 0,
+    globstar: false,
     tokens
   };
 
-  let extglobs = [];
-  let stack = [];
+  input = utils.removePrefix(input, state);
+  len = input.length;
+
+  const extglobs = [];
+  const braces = [];
+  const stack = [];
   let prev = bos;
   let value;
 
@@ -151,9 +143,32 @@
   const eos = () => state.index === len - 1;
   const peek = state.peek = (n = 1) => input[state.index + n];
   const advance = state.advance = () => input[++state.index];
+  const remaining = () => input.slice(state.index + 1);
+  const consume = (value = '', num = 0) => {
+    state.consumed += value;
+    state.index += num;
+  };
   const append = token => {
     state.output += token.output != null ? token.output : token.value;
-    state.consumed += token.value || '';
+    consume(token.value);
+  };
+
+  const negate = () => {
+    let count = 1;
+
+    while (peek() === '!' && (peek(2) !== '(' || peek(3) === '?')) {
+      advance();
+      state.start++;
+      count++;
+    }
+
+    if (count % 2 === 0) {
+      return false;
+    }
+
+    state.negated = true;
+    state.start++;
+    return true;
   };
 
   const increment = type => {
@@ -176,8 +191,9 @@
 
   const push = tok => {
     if (prev.type === 'globstar') {
-      let isBrace = state.braces > 0 && (tok.type === 'comma' || tok.type === 'brace');
-      let isExtglob = extglobs.length && (tok.type === 'pipe' || tok.type === 'paren');
+      const isBrace = state.braces > 0 && (tok.type === 'comma' || tok.type === 'brace');
+      const isExtglob = tok.extglob === true || (extglobs.length && (tok.type === 'pipe' || tok.type === 'paren'));
+
       if (tok.type !== 'slash' && tok.type !== 'paren' && !isBrace && !isExtglob) {
         state.output = state.output.slice(0, -prev.output.length);
         prev.type = 'star';
@@ -194,6 +210,7 @@
     if (tok.value || tok.output) append(tok);
     if (prev && prev.type === 'text' && tok.type === 'text') {
       prev.value += tok.value;
+      prev.output = (prev.output || '') + tok.value;
       return;
     }
 
@@ -203,16 +220,16 @@
   };
 
   const extglobOpen = (type, value) => {
-    let token = { ...EXTGLOB_CHARS[value], conditions: 1, inner: '' };
+    const token = { ...EXTGLOB_CHARS[value], conditions: 1, inner: '' };
 
     token.prev = prev;
     token.parens = state.parens;
     token.output = state.output;
-    let output = (opts.capture ? '(' : '') + token.open;
+    const output = (opts.capture ? '(' : '') + token.open;
 
+    increment('parens');
     push({ type, value, output: state.output ? '' : ONE_CHAR });
     push({ type: 'paren', extglob: true, value: advance(), output });
-    increment('parens');
     extglobs.push(token);
   };
 
@@ -226,8 +243,8 @@
         extglobStar = globstar(opts);
       }
 
-      if (extglobStar !== star || eos() || /^\)+$/.test(input.slice(state.index + 1))) {
-        output = token.close = ')$))' + extglobStar;
+      if (extglobStar !== star || eos() || /^\)+$/.test(remaining())) {
+        output = token.close = `)$))${extglobStar}`;
       }
 
       if (token.prev.type === 'bos' && eos()) {
@@ -239,7 +256,11 @@
     decrement('parens');
   };
 
-  if (opts.fastpaths !== false && !/(^[*!]|[/{[()\]}"])/.test(input)) {
+  /**
+   * Fast paths
+   */
+
+  if (opts.fastpaths !== false && !/(^[*!]|[/()[\]{}"])/.test(input)) {
     let backslashes = false;
 
     let output = input.replace(REGEX_SPECIAL_CHARS_BACKREF, (m, esc, chars, first, rest, index) => {
@@ -268,7 +289,7 @@
         }
         return star;
       }
-      return esc ? m : '\\' + m;
+      return esc ? m : `\\${m}`;
     });
 
     if (backslashes === true) {
@@ -281,7 +302,12 @@
       }
     }
 
-    state.output = output;
+    if (output === input && opts.contains === true) {
+      state.output = input;
+      return state;
+    }
+
+    state.output = utils.wrapOutput(output, state, options);
     return state;
   }
 
@@ -301,7 +327,7 @@
      */
 
     if (value === '\\') {
-      let next = peek();
+      const next = peek();
 
       if (next === '/' && opts.bash !== true) {
         continue;
@@ -318,7 +344,7 @@
       }
 
       // collapse slashes to reduce potential for exploits
-      let match = /^\\+/.exec(input.slice(state.index + 1));
+      const match = /^\\+/.exec(remaining());
       let slashes = 0;
 
       if (match && match[0].length > 2) {
@@ -348,15 +374,15 @@
 
     if (state.brackets > 0 && (value !== ']' || prev.value === '[' || prev.value === '[^')) {
       if (opts.posix !== false && value === ':') {
-        let inner = prev.value.slice(1);
+        const inner = prev.value.slice(1);
         if (inner.includes('[')) {
           prev.posix = true;
 
           if (inner.includes(':')) {
-            let idx = prev.value.lastIndexOf('[');
-            let pre = prev.value.slice(0, idx);
-            let rest = prev.value.slice(idx + 2);
-            let posix = POSIX_REGEX_SOURCE[rest];
+            const idx = prev.value.lastIndexOf('[');
+            const pre = prev.value.slice(0, idx);
+            const rest = prev.value.slice(idx + 2);
+            const posix = POSIX_REGEX_SOURCE[rest];
             if (posix) {
               prev.value = pre + posix;
               state.backtrack = true;
@@ -372,11 +398,11 @@
       }
 
       if ((value === '[' && peek() !== ':') || (value === '-' && peek() === ']')) {
-        value = '\\' + value;
+        value = `\\${value}`;
       }
 
       if (value === ']' && (prev.value === '[' || prev.value === '[^')) {
-        value = '\\' + value;
+        value = `\\${value}`;
       }
 
       if (opts.posix === true && value === '!' && prev.value === '[') {
@@ -417,8 +443,8 @@
      */
 
     if (value === '(') {
-      push({ type: 'paren', value });
       increment('parens');
+      push({ type: 'paren', value });
       continue;
     }
 
@@ -427,7 +453,7 @@
         throw new SyntaxError(syntaxError('opening', '('));
       }
 
-      let extglob = extglobs[extglobs.length - 1];
+      const extglob = extglobs[extglobs.length - 1];
       if (extglob && state.parens === extglob.parens + 1) {
         extglobClose(extglobs.pop());
         continue;
@@ -439,16 +465,16 @@
     }
 
     /**
-     * Brackets
+     * Square brackets
      */
 
     if (value === '[') {
-      if (opts.nobracket === true || !input.slice(state.index + 1).includes(']')) {
+      if (opts.nobracket === true || !remaining().includes(']')) {
         if (opts.nobracket !== true && opts.strictBrackets === true) {
           throw new SyntaxError(syntaxError('closing', ']'));
         }
 
-        value = '\\' + value;
+        value = `\\${value}`;
       } else {
         increment('brackets');
       }
@@ -459,7 +485,7 @@
 
     if (value === ']') {
       if (opts.nobracket === true || (prev && prev.type === 'bracket' && prev.value.length === 1)) {
-        push({ type: 'text', value, output: '\\' + value });
+        push({ type: 'text', value, output: `\\${value}` });
         continue;
       }
 
@@ -468,15 +494,15 @@
           throw new SyntaxError(syntaxError('opening', '['));
         }
 
-        push({ type: 'text', value, output: '\\' + value });
+        push({ type: 'text', value, output: `\\${value}` });
         continue;
       }
 
       decrement('brackets');
 
-      let prevValue = prev.value.slice(1);
+      const prevValue = prev.value.slice(1);
       if (prev.posix !== true && prevValue[0] === '^' && !prevValue.includes('/')) {
-        value = '/' + value;
+        value = `/${value}`;
       }
 
       prev.value += value;
@@ -488,7 +514,7 @@
         continue;
       }
 
-      let escaped = utils.escapeRegex(prev.value);
+      const escaped = utils.escapeRegex(prev.value);
       state.output = state.output.slice(0, -prev.value.length);
 
       // when literal brackets are explicitly enabled
@@ -510,22 +536,34 @@
      */
 
     if (value === '{' && opts.nobrace !== true) {
-      push({ type: 'brace', value, output: '(' });
       increment('braces');
+
+      const open = {
+        type: 'brace',
+        value,
+        output: '(',
+        outputIndex: state.output.length,
+        tokensIndex: state.tokens.length
+      };
+
+      braces.push(open);
+      push(open);
       continue;
     }
 
     if (value === '}') {
-      if (opts.nobrace === true || state.braces === 0) {
-        push({ type: 'text', value, output: '\\' + value });
+      const brace = braces[braces.length - 1];
+
+      if (opts.nobrace === true || !brace) {
+        push({ type: 'text', value, output: value });
         continue;
       }
 
       let output = ')';
 
-      if (state.dots === true) {
-        let arr = tokens.slice();
-        let range = [];
+      if (brace.dots === true) {
+        const arr = tokens.slice();
+        const range = [];
 
         for (let i = arr.length - 1; i >= 0; i--) {
           tokens.pop();
@@ -541,8 +579,20 @@
         state.backtrack = true;
       }
 
+      if (brace.comma !== true && brace.dots !== true) {
+        const out = state.output.slice(0, brace.outputIndex);
+        const toks = state.tokens.slice(brace.tokensIndex);
+        brace.value = brace.output = '\\{';
+        value = output = '\\}';
+        state.output = out;
+        for (const t of toks) {
+          state.output += (t.output || t.value);
+        }
+      }
+
       push({ type: 'brace', value, output });
       decrement('braces');
+      braces.pop();
       continue;
     }
 
@@ -565,7 +615,9 @@
     if (value === ',') {
       let output = value;
 
-      if (state.braces > 0 && stack[stack.length - 1] === 'braces') {
+      const brace = braces[braces.length - 1];
+      if (brace && stack[stack.length - 1] === 'braces') {
+        brace.comma = true;
         output = '|';
       }
 
@@ -582,7 +634,7 @@
       // to the current index, and don't add the "./" characters
       // to the state. This greatly simplifies lookbehinds when
       // checking for BOS characters like "!" and "." (not "./")
-      if (prev.type === 'dot' && state.index === 1) {
+      if (prev.type === 'dot' && state.index === state.start + 1) {
         state.start = state.index + 1;
         state.consumed = '';
         state.output = '';
@@ -602,10 +654,16 @@
     if (value === '.') {
       if (state.braces > 0 && prev.type === 'dot') {
         if (prev.value === '.') prev.output = DOT_LITERAL;
+        const brace = braces[braces.length - 1];
         prev.type = 'dots';
         prev.output += value;
         prev.value += value;
-        state.dots = true;
+        brace.dots = true;
+        continue;
+      }
+
+      if ((state.braces + state.parens) === 0 && prev.type !== 'bos' && prev.type !== 'slash') {
+        push({ type: 'text', value, output: DOT_LITERAL });
         continue;
       }
 
@@ -618,27 +676,28 @@
      */
 
     if (value === '?') {
+      const isGroup = prev && prev.value === '(';
+      if (!isGroup && opts.noextglob !== true && peek() === '(' && peek(2) !== '?') {
+        extglobOpen('qmark', value);
+        continue;
+      }
+
       if (prev && prev.type === 'paren') {
-        let next = peek();
+        const next = peek();
         let output = value;
 
         if (next === '<' && !utils.supportsLookbehinds()) {
           throw new Error('Node.js v10 or higher is required for regex lookbehinds');
         }
 
-        if (prev.value === '(' && !/[!=<:]/.test(next) || (next === '<' && !/[!=]/.test(peek(2)))) {
-          output = '\\' + value;
+        if ((prev.value === '(' && !/[!=<:]/.test(next)) || (next === '<' && !/<([!=]|\w+>)/.test(remaining()))) {
+          output = `\\${value}`;
         }
 
         push({ type: 'text', value, output });
         continue;
       }
 
-      if (opts.noextglob !== true && peek() === '(' && peek(2) !== '?') {
-        extglobOpen('qmark', value);
-        continue;
-      }
-
       if (opts.dot !== true && (prev.type === 'slash' || prev.type === 'bos')) {
         push({ type: 'qmark', value, output: QMARK_NO_DOT });
         continue;
@@ -661,7 +720,7 @@
       }
 
       if (opts.nonegate !== true && state.index === 0) {
-        negate(state);
+        negate();
         continue;
       }
     }
@@ -676,14 +735,12 @@
         continue;
       }
 
-      if (prev && (prev.type === 'bracket' || prev.type === 'paren' || prev.type === 'brace')) {
-        let output = prev.extglob === true ? '\\' + value : value;
-        push({ type: 'plus', value, output });
+      if ((prev && prev.value === '(') || opts.regex === false) {
+        push({ type: 'plus', value, output: PLUS_LITERAL });
         continue;
       }
 
-      // use regex behavior inside parens
-      if (state.parens > 0 && opts.regex !== false) {
+      if ((prev && (prev.type === 'bracket' || prev.type === 'paren' || prev.type === 'brace')) || state.parens > 0) {
         push({ type: 'plus', value });
         continue;
       }
@@ -698,7 +755,7 @@
 
     if (value === '@') {
       if (opts.noextglob !== true && peek() === '(' && peek(2) !== '?') {
-        push({ type: 'at', value, output: '' });
+        push({ type: 'at', extglob: true, value, output: '' });
         continue;
       }
 
@@ -712,10 +769,10 @@
 
     if (value !== '*') {
       if (value === '$' || value === '^') {
-        value = '\\' + value;
+        value = `\\${value}`;
       }
 
-      let match = REGEX_NON_SPECIAL_CHAR.exec(input.slice(state.index + 1));
+      const match = REGEX_NON_SPECIAL_CHARS.exec(remaining());
       if (match) {
         value += match[0];
         state.index += match[0].length;
@@ -735,46 +792,48 @@
       prev.value += value;
       prev.output = star;
       state.backtrack = true;
-      state.consumed += value;
+      state.globstar = true;
+      consume(value);
       continue;
     }
 
-    if (opts.noextglob !== true && peek() === '(' && peek(2) !== '?') {
+    let rest = remaining();
+    if (opts.noextglob !== true && /^\([^?]/.test(rest)) {
       extglobOpen('star', value);
       continue;
     }
 
     if (prev.type === 'star') {
       if (opts.noglobstar === true) {
-        state.consumed += value;
+        consume(value);
         continue;
       }
 
-      let prior = prev.prev;
-      let before = prior.prev;
-      let isStart = prior.type === 'slash' || prior.type === 'bos';
-      let afterStar = before && (before.type === 'star' || before.type === 'globstar');
+      const prior = prev.prev;
+      const before = prior.prev;
+      const isStart = prior.type === 'slash' || prior.type === 'bos';
+      const afterStar = before && (before.type === 'star' || before.type === 'globstar');
 
-      if (opts.bash === true && (!isStart || (!eos() && peek() !== '/'))) {
+      if (opts.bash === true && (!isStart || (rest[0] && rest[0] !== '/'))) {
         push({ type: 'star', value, output: '' });
         continue;
       }
 
-      let isBrace = state.braces > 0 && (prior.type === 'comma' || prior.type === 'brace');
-      let isExtglob = extglobs.length && (prior.type === 'pipe' || prior.type === 'paren');
+      const isBrace = state.braces > 0 && (prior.type === 'comma' || prior.type === 'brace');
+      const isExtglob = extglobs.length && (prior.type === 'pipe' || prior.type === 'paren');
       if (!isStart && prior.type !== 'paren' && !isBrace && !isExtglob) {
         push({ type: 'star', value, output: '' });
         continue;
       }
 
       // strip consecutive `/**/`
-      while (input.slice(state.index + 1, state.index + 4) === '/**') {
-        let after = input[state.index + 4];
+      while (rest.slice(0, 3) === '/**') {
+        const after = input[state.index + 4];
         if (after && after !== '/') {
           break;
         }
-        state.consumed += '/**';
-        state.index += 3;
+        rest = rest.slice(3);
+        consume('/**', 3);
       }
 
       if (prior.type === 'bos' && eos()) {
@@ -782,48 +841,51 @@
         prev.value += value;
         prev.output = globstar(opts);
         state.output = prev.output;
-        state.consumed += value;
+        state.globstar = true;
+        consume(value);
         continue;
       }
 
       if (prior.type === 'slash' && prior.prev.type !== 'bos' && !afterStar && eos()) {
         state.output = state.output.slice(0, -(prior.output + prev.output).length);
-        prior.output = '(?:' + prior.output;
+        prior.output = `(?:${prior.output}`;
 
         prev.type = 'globstar';
-        prev.output = globstar(opts) + '|$)';
+        prev.output = globstar(opts) + (opts.strictSlashes ? ')' : '|$)');
         prev.value += value;
-
+        state.globstar = true;
         state.output += prior.output + prev.output;
-        state.consumed += value;
+        consume(value);
         continue;
       }
 
-      let next = peek();
-      if (prior.type === 'slash' && prior.prev.type !== 'bos' && next === '/') {
-        let end = peek(2) !== void 0 ? '|$' : '';
+      if (prior.type === 'slash' && prior.prev.type !== 'bos' && rest[0] === '/') {
+        const end = rest[1] !== void 0 ? '|$' : '';
 
         state.output = state.output.slice(0, -(prior.output + prev.output).length);
-        prior.output = '(?:' + prior.output;
+        prior.output = `(?:${prior.output}`;
 
         prev.type = 'globstar';
         prev.output = `${globstar(opts)}${SLASH_LITERAL}|${SLASH_LITERAL}${end})`;
         prev.value += value;
 
         state.output += prior.output + prev.output;
-        state.consumed += value + advance();
+        state.globstar = true;
 
-        push({ type: 'slash', value, output: '' });
+        consume(value + advance());
+
+        push({ type: 'slash', value: '/', output: '' });
         continue;
       }
 
-      if (prior.type === 'bos' && next === '/') {
+      if (prior.type === 'bos' && rest[0] === '/') {
         prev.type = 'globstar';
         prev.value += value;
         prev.output = `(?:^|${SLASH_LITERAL}|${globstar(opts)}${SLASH_LITERAL})`;
         state.output = prev.output;
-        state.consumed += value + advance();
-        push({ type: 'slash', value, output: '' });
+        state.globstar = true;
+        consume(value + advance());
+        push({ type: 'slash', value: '/', output: '' });
         continue;
       }
 
@@ -837,11 +899,12 @@
 
       // reset output with globstar
       state.output += prev.output;
-      state.consumed += value;
+      state.globstar = true;
+      consume(value);
       continue;
     }
 
-    let token = { type: 'star', value, output: star };
+    const token = { type: 'star', value, output: star };
 
     if (opts.bash === true) {
       token.output = '.*?';
@@ -907,7 +970,7 @@
   if (state.backtrack === true) {
     state.output = '';
 
-    for (let token of state.tokens) {
+    for (const token of state.tokens) {
       state.output += token.output != null ? token.output : token.value;
 
       if (token.suffix) {
@@ -926,15 +989,15 @@
  */
 
 parse.fastpaths = (input, options) => {
-  let opts = { ...options };
-  let max = typeof opts.maxLength === 'number' ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH;
-  let len = input.length;
+  const opts = { ...options };
+  const max = typeof opts.maxLength === 'number' ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH;
+  const len = input.length;
   if (len > max) {
     throw new SyntaxError(`Input length: ${len}, exceeds maximum allowed length: ${max}`);
   }
 
   input = REPLACEMENTS[input] || input;
-  let win32 = utils.isWindows(options);
+  const win32 = utils.isWindows(options);
 
   // create constants based on platform, for windows or posix
   const {
@@ -949,16 +1012,18 @@
     START_ANCHOR
   } = constants.globChars(win32);
 
-  let capture = opts.capture ? '' : '?:';
+  const nodot = opts.dot ? NO_DOTS : NO_DOT;
+  const slashDot = opts.dot ? NO_DOTS_SLASH : NO_DOT;
+  const capture = opts.capture ? '' : '?:';
+  const state = { negated: false, prefix: '' };
   let star = opts.bash === true ? '.*?' : STAR;
-  let nodot = opts.dot ? NO_DOTS : NO_DOT;
-  let slashDot = opts.dot ? NO_DOTS_SLASH : NO_DOT;
 
   if (opts.capture) {
     star = `(${star})`;
   }
 
   const globstar = (opts) => {
+    if (opts.noglobstar === true) return star;
     return `(${capture}(?:(?!${START_ANCHOR}${opts.dot ? DOTS_SLASH : DOT_LITERAL}).)*?)`;
   };
 
@@ -989,10 +1054,10 @@
         return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${DOT_LITERAL}${ONE_CHAR}${star}`;
 
       default: {
-        let match = /^(.*?)\.(\w+)$/.exec(str);
+        const match = /^(.*?)\.(\w+)$/.exec(str);
         if (!match) return;
 
-        let source = create(match[1], options);
+        const source = create(match[1]);
         if (!source) return;
 
         return source + DOT_LITERAL + match[2];
@@ -1000,12 +1065,14 @@
     }
   };
 
-  let output = create(input);
-  if (output && opts.strictSlashes !== true) {
-    output += `${SLASH_LITERAL}?`;
+  const output = utils.removePrefix(input, state);
+  let source = create(output);
+
+  if (source && opts.strictSlashes !== true) {
+    source += `${SLASH_LITERAL}?`;
   }
 
-  return output;
+  return source;
 };
 
 module.exports = parse;