UNPKG

@reliverse/rematch

Version:

@reliverse/rematch is a high-performance minimal glob matcher, with micromatch-level power, zepto-level size, and reliverse-grade dx.

182 lines (181 loc) 6.03 kB
import * as constants from "./constants.js"; import parse from "./parse.js"; import scan from "./scan.js"; import * as utils from "./utils.js"; const isObject = (val) => val && typeof val === "object" && !Array.isArray(val); const rematchInternal = (glob, options, returnState = false) => { if (Array.isArray(glob)) { const fns = glob.map( (input) => rematchInternal(input, options, returnState) ); const arrayMatcher = (str) => { for (const isMatch of fns) { const state2 = isMatch(str); if (state2) return state2; } return false; }; return arrayMatcher; } const isState = isObject(glob) && glob.tokens && glob.input; if (glob === "" || typeof glob !== "string" && !isState) { throw new TypeError("Expected pattern to be a non-empty string"); } const opts = options || {}; const posix = opts.windows; const regex = isState ? rematchInternal.compileRe(glob, options) : rematchInternal.makeRe(glob, options, false, true); let state = void 0; if (regex instanceof RegExp && "state" in regex) { state = regex.state; delete regex.state; } let isIgnored = () => false; if (opts.ignore) { const ignoreOpts = { ...options, ignore: null, onMatch: null, onResult: null }; isIgnored = rematchInternal( opts.ignore, ignoreOpts, returnState ); } const matcher = (input, returnObject = false) => { const safeRegex = regex instanceof RegExp ? regex : rematchInternal.makeRe(String(regex), options); const { isMatch, match, output } = rematchInternal.test( input, safeRegex, options, { glob, posix } ); const result = { glob, state, regex, posix, input, output, match, isMatch }; if (isMatch && safeRegex instanceof RegExp && !safeRegex.test(input)) { result.isMatch = false; return returnObject ? result : false; } if (typeof opts.onResult === "function") { opts.onResult(result); } if (isMatch === false) { result.isMatch = false; return returnObject ? result : false; } let ignored = false; if (typeof isIgnored === "function" && isIgnored.length > 0) { ignored = isIgnored(input); } else if (typeof isIgnored === "function") { ignored = isIgnored(); } if (ignored) { if (typeof opts.onIgnore === "function") { opts.onIgnore(result); } result.isMatch = false; return returnObject ? result : false; } if (typeof opts.onMatch === "function") { opts.onMatch(result); } return returnObject ? result : true; }; if (returnState) { matcher.state = state; } return matcher; }; rematchInternal.test = (input, regex, options, extra = {}) => { if (typeof input !== "string") { throw new TypeError("Expected input to be a string"); } if (input === "") { return { isMatch: false, output: "" }; } const opts = options || {}; const format = opts.format || (extra.posix ? utils.toPosixSlashes : null); let match = input === extra.glob; let output = match && typeof format === "function" ? format(input) : input; if (match === false) { output = typeof format === "function" ? format(input) : input; match = output === extra.glob; } if (match === false || opts.capture === true) { let safeRegex = regex; if (!(regex instanceof RegExp)) { safeRegex = rematchInternal.makeRe(String(regex), options); } if (opts.matchBase === true || opts.basename === true) { match = rematchInternal.matchBase(input, safeRegex, options, extra.posix); } else { match = safeRegex instanceof RegExp ? safeRegex.exec(output) !== null : false; } } return { isMatch: Boolean(match), match, output }; }; rematchInternal.matchBase = (input, glob, options, posix) => { const regex = glob instanceof RegExp ? glob : rematchInternal.makeRe(String(glob), options); return regex instanceof RegExp ? regex.test(utils.basename(input, { windows: posix })) : false; }; rematchInternal.isMatch = (str, patterns, options) => { const matcher = typeof patterns === "function" ? patterns : rematchInternal(patterns, options); return matcher(str); }; rematchInternal.parse = (pattern, options) => { if (Array.isArray(pattern)) return pattern.map((p) => rematchInternal.parse(p, options)); return parse(pattern, { ...options, fastpaths: false }); }; rematchInternal.scan = (input, options) => scan(input, options); rematchInternal.compileRe = (state, options, returnOutput = false, returnState = false) => { if (returnOutput === true) { return state.output; } const opts = options || {}; const prepend = opts.contains ? "" : "^"; const append = opts.contains ? "" : "$"; let source = `${prepend}(?:${state.output})${append}`; if (state && state.negated === true) { source = `^(?!${source}).*$`; } const regex = rematchInternal.toRegex(source, options); if (returnState === true && regex instanceof RegExp) { regex.state = state; } return regex; }; rematchInternal.makeRe = (input, options = {}, returnOutput = false, returnState = false) => { if (!input || typeof input !== "string") { throw new TypeError("Expected a non-empty string"); } let parsed = { negated: false, fastpaths: true }; if (options.fastpaths !== false && (input.startsWith(".") || input.startsWith("*"))) { parsed.output = parse.fastpaths(input, options); } if (!parsed.output) { parsed = parse(input, options); parsed.fastpaths = false; } return rematchInternal.compileRe( parsed, options, returnOutput, returnState ); }; rematchInternal.toRegex = (source, options) => { try { const opts = options || {}; return new RegExp(source, opts.flags || (opts.nocase ? "i" : "")); } catch (err) { if (options && options.debug === true) throw err; return /$^/; } }; rematchInternal.constants = constants; const rematch = rematchInternal; export default rematch;