You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
92 lines
3.7 KiB
92 lines
3.7 KiB
"use strict"; |
|
Object.defineProperty(exports, "__esModule", { value: true }); |
|
exports.GlobMatcher = void 0; |
|
const mm = require("micromatch"); |
|
const path = require("path"); |
|
class GlobMatcher { |
|
/** |
|
* Construct a `.gitignore` emulator |
|
* @param patterns the contents of a `.gitignore` style file or an array of individual glob rules. |
|
* @param root the working directory |
|
*/ |
|
constructor(patterns, root, nodePath) { |
|
this.patterns = patterns; |
|
this.root = root; |
|
this.path = nodePath !== null && nodePath !== void 0 ? nodePath : path; |
|
this.matchEx = buildMatcherFn(this.path, patterns, root); |
|
} |
|
/** |
|
* Check to see if a filename matches any of the globs. |
|
* If filename is relative, it is considered relative to the root. |
|
* If filename is absolute and contained within the root, it will be made relative before being tested for a glob match. |
|
* If filename is absolute and not contained within the root, it will be tested as is. |
|
* @param filename full path of the file to check. |
|
*/ |
|
match(filename) { |
|
return this.matchEx(filename).matched; |
|
} |
|
} |
|
exports.GlobMatcher = GlobMatcher; |
|
/** |
|
* This function attempts to emulate .gitignore functionality as much as possible. |
|
* |
|
* The resulting matcher function: (filename: string) => GlobMatch |
|
* |
|
* If filename is relative, it is considered relative to the root. |
|
* If filename is absolute and contained within the root, it will be made relative before being tested for a glob match. |
|
* If filename is absolute and not contained within the root, it will be tested as is. |
|
* |
|
* @param patterns the contents of a .gitignore style file or an array of individual glob rules. |
|
* @param root the working directory |
|
* @returns a function given a filename returns true if it matches. |
|
*/ |
|
function buildMatcherFn(path, patterns, root) { |
|
if (typeof patterns == 'string') { |
|
patterns = patterns.split(/\r?\n/g); |
|
} |
|
const dirRoot = path.normalize(root || '/'); |
|
const rules = patterns |
|
.map((p) => p.trim()) |
|
.map((p, index) => ({ glob: p, index })) |
|
.filter((r) => !!r.glob) |
|
.map(({ glob, index }) => { |
|
const matchNeg = glob.match(/^!+/); |
|
const isNeg = (matchNeg && matchNeg[0].length & 1 && true) || false; |
|
const pattern = mutations.reduce((p, [regex, replace]) => p.replace(regex, replace), glob); |
|
const reg = mm.makeRe(pattern); |
|
const fn = (filename) => { |
|
const match = filename.match(reg); |
|
return !!match; |
|
}; |
|
return { glob, index, isNeg, fn, reg }; |
|
}); |
|
const negRules = rules.filter((r) => r.isNeg); |
|
const posRules = rules.filter((r) => !r.isNeg); |
|
const fn = (filename) => { |
|
filename = path.normalize(filename); |
|
const offset = dirRoot === filename.slice(0, dirRoot.length) ? dirRoot.length : 0; |
|
const lName = filename.slice(offset); |
|
const filePath = path.parse(lName); |
|
const relPath = path.join(filePath.dir.slice(filePath.root.length), filePath.base); |
|
const fname = relPath.split(path.sep).join('/'); |
|
for (const rule of negRules) { |
|
if (rule.fn(fname)) { |
|
return { matched: false, glob: rule.glob, index: rule.index, isNeg: rule.isNeg }; |
|
} |
|
} |
|
for (const rule of posRules) { |
|
if (rule.fn(fname)) { |
|
return { matched: true, glob: rule.glob, index: rule.index, isNeg: rule.isNeg }; |
|
} |
|
} |
|
return { matched: false }; |
|
}; |
|
return fn; |
|
} |
|
const mutations = [ |
|
[/^!+/, ''], |
|
[/^[^/#][^/]*$/, '**/{$&,$&/**}'], |
|
[/^\/(?!\/)/, ''], |
|
[/\/$/, '$&**'], |
|
]; |
|
//# sourceMappingURL=GlobMatcher.js.map
|