|
const REGEX_SPECIAL = /[\\^$.*+?()[\]{}|]/g |
|
const REGEX_HAS_SPECIAL = RegExp(REGEX_SPECIAL.source) |
|
|
|
|
|
|
|
|
|
function toSource(source) { |
|
source = Array.isArray(source) ? source : [source] |
|
|
|
source = source.map((item) => (item instanceof RegExp ? item.source : item)) |
|
|
|
return source.join('') |
|
} |
|
|
|
|
|
|
|
|
|
export function pattern(source) { |
|
return new RegExp(toSource(source), 'g') |
|
} |
|
|
|
|
|
|
|
|
|
export function withoutCapturing(source) { |
|
return new RegExp(`(?:${toSource(source)})`, 'g') |
|
} |
|
|
|
|
|
|
|
|
|
export function any(sources) { |
|
return `(?:${sources.map(toSource).join('|')})` |
|
} |
|
|
|
|
|
|
|
|
|
export function optional(source) { |
|
return `(?:${toSource(source)})?` |
|
} |
|
|
|
|
|
|
|
|
|
export function zeroOrMore(source) { |
|
return `(?:${toSource(source)})*` |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function nestedBrackets(open, close, depth = 1) { |
|
return withoutCapturing([ |
|
escape(open), |
|
/[^\s]*/, |
|
depth === 1 |
|
? `[^${escape(open)}${escape(close)}\s]*` |
|
: any([`[^${escape(open)}${escape(close)}\s]*`, nestedBrackets(open, close, depth - 1)]), |
|
/[^\s]*/, |
|
escape(close), |
|
]) |
|
} |
|
|
|
export function escape(string) { |
|
return string && REGEX_HAS_SPECIAL.test(string) |
|
? string.replace(REGEX_SPECIAL, '\\$&') |
|
: string || '' |
|
} |
|
|