60 lines
1.6 KiB
JavaScript
60 lines
1.6 KiB
JavaScript
/**
|
|
* Grep helpers: glob match + output modes. No Bare imports.
|
|
*/
|
|
|
|
function globToRegExp(glob) {
|
|
const g = String(glob || '').replace(/\\/g, '/');
|
|
if (!g) return null;
|
|
let out = '^';
|
|
for (let i = 0; i < g.length; i++) {
|
|
const c = g[i];
|
|
if (c === '*' && g[i + 1] === '*') {
|
|
out += '.*';
|
|
i += 1;
|
|
if (g[i + 1] === '/') i += 1;
|
|
} else if (c === '*') out += '[^/]*';
|
|
else if (c === '?') out += '[^/]';
|
|
else if ('\\.()+^$[]{}|'.indexOf(c) >= 0) out += '\\' + c;
|
|
else out += c;
|
|
}
|
|
out += '$';
|
|
return new RegExp(out, 'i');
|
|
}
|
|
|
|
function matchGlob(relPath, glob) {
|
|
if (!glob) return true;
|
|
const rel = String(relPath || '').replace(/\\/g, '/');
|
|
const re = globToRegExp(glob);
|
|
if (!re) return true;
|
|
if (re.test(rel)) return true;
|
|
const base = rel.split('/').pop();
|
|
return re.test(base);
|
|
}
|
|
|
|
function formatHits(hits, mode, truncated) {
|
|
const list = hits || [];
|
|
const m = String(mode || 'content').toLowerCase();
|
|
if (m === 'count') {
|
|
const by = {};
|
|
for (const h of list) {
|
|
const p = h.path || '';
|
|
by[p] = (by[p] || 0) + 1;
|
|
}
|
|
return { mode: 'count', files: by, truncated: !!truncated };
|
|
}
|
|
if (m === 'files_with_matches' || m === 'files') {
|
|
const seen = [];
|
|
const set = new Set();
|
|
for (const h of list) {
|
|
if (!set.has(h.path)) {
|
|
set.add(h.path);
|
|
seen.push(h.path);
|
|
}
|
|
}
|
|
return { mode: 'files_with_matches', files: seen, truncated: !!truncated };
|
|
}
|
|
return { mode: 'content', hits: list, truncated: !!truncated };
|
|
}
|
|
|
|
module.exports = { globToRegExp, matchGlob, formatHits };
|