src/vs/base/common/glob.ts/parseRegExp
function parseRegExp(pattern: string): string {
	if (!pattern) {
		return '';
	}

	let regEx = '';

	// Split up into segments for each slash found
	const segments = splitGlobAware(pattern, GLOB_SPLIT);

	// Special case where we only have globstars
	if (segments.every(segment => segment === GLOBSTAR)) {
		regEx = '.*';
	}

	// Build regex over segments
	else {
		let previousSegmentWasGlobStar = false;
		segments.forEach((segment, index) => {

			// Treat globstar specially
			if (segment === GLOBSTAR) {

				// if we have more than one globstar after another, just ignore it
				if (previousSegmentWasGlobStar) {
					return;
				}

				regEx += starsToRegExp(2, index === segments.length - 1);
			}

			// Anything else, not globstar
			else {

				// States
				let inBraces = false;
				let braceVal = '';

				let inBrackets = false;
				let bracketVal = '';

				for (const char of segment) {

					// Support brace expansion
					if (char !== '}' && inBraces) {
						braceVal += char;
						continue;
					}

					// Support brackets
					if (inBrackets && (char !== ']' || !bracketVal) /* ] is literally only allowed as first character in brackets to match it */) {
						let res: string;

						// range operator
						if (char === '-') {
							res = char;
						}

						// negation operator (only valid on first index in bracket)
						else if ((char === '^' || char === '!') && !bracketVal) {
							res = '^';
						}

						// glob split matching is not allowed within character ranges
						// see http://man7.org/linux/man-pages/man7/glob.7.html
						else if (char === GLOB_SPLIT) {
							res = '';
						}

						// anything else gets escaped
						else {
							res = escapeRegExpCharacters(char);
						}

						bracketVal += res;
						continue;
					}

					switch (char) {
						case '{':
							inBraces = true;
							continue;

						case '[':
							inBrackets = true;
							continue;

						case '}': {
							const choices = splitGlobAware(braceVal, ',');

							// Converts {foo,bar} => [foo|bar]
							const braceRegExp = `(?:${choices.map(choice => parseRegExp(choice)).join('|')})`;

							regEx += braceRegExp;

							inBraces = false;
							braceVal = '';

							break;
						}

						case ']': {
							regEx += ('[' + bracketVal + ']');

							inBrackets = false;
							bracketVal = '';

							break;
						}

						case '?':
							regEx += NO_PATH_REGEX; // 1 ? matches any single character except path separator (/ and \)
							continue;

						case '*':
							regEx += starsToRegExp(1);
							continue;

						default:
							regEx += escapeRegExpCharacters(char);
					}
				}

				// Tail: Add the slash we had split on if there is more to
				// come and the remaining pattern is not a globstar
				// For example if pattern: some/**/*.js we want the "/" after
				// some to be included in the RegEx to prevent a folder called
				// "something" to match as well.
				if (
					index < segments.length - 1 &&			// more segments to come after this
					(
						segments[index + 1] !== GLOBSTAR ||	// next segment is not **, or...
						index + 2 < segments.length			// ...next segment is ** but there is more segments after that
					)
				) {
					regEx += PATH_REGEX;
				}
			}

			// update globstar state
			previousSegmentWasGlobStar = (segment === GLOBSTAR);
		});
	}

	return regEx;
}