split-by-codeowners 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +78 -7
- package/dist/index.js.map +1 -1
- package/dist-cli/index.js +78 -7
- package/dist-cli/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -27714,6 +27714,35 @@ exports.parseCodeowners = parseCodeowners;
|
|
|
27714
27714
|
exports.ownersForFile = ownersForFile;
|
|
27715
27715
|
const node_fs_1 = __importDefault(__nccwpck_require__(3024));
|
|
27716
27716
|
const minimatch_1 = __nccwpck_require__(6507);
|
|
27717
|
+
function splitPatternOwners(line) {
|
|
27718
|
+
// CODEOWNERS lines are: <pattern><whitespace><owner>...
|
|
27719
|
+
// Patterns may contain spaces if escaped as `\ `.
|
|
27720
|
+
// We parse by finding the first whitespace not escaped by a backslash.
|
|
27721
|
+
let i = 0;
|
|
27722
|
+
let escaped = false;
|
|
27723
|
+
for (; i < line.length; i++) {
|
|
27724
|
+
const ch = line[i];
|
|
27725
|
+
if (escaped) {
|
|
27726
|
+
escaped = false;
|
|
27727
|
+
continue;
|
|
27728
|
+
}
|
|
27729
|
+
if (ch === "\\") {
|
|
27730
|
+
escaped = true;
|
|
27731
|
+
continue;
|
|
27732
|
+
}
|
|
27733
|
+
if (/\s/.test(ch))
|
|
27734
|
+
break;
|
|
27735
|
+
}
|
|
27736
|
+
const rawPattern = line.slice(0, i).trim();
|
|
27737
|
+
const rest = line.slice(i).trim();
|
|
27738
|
+
if (!rawPattern || !rest)
|
|
27739
|
+
return null;
|
|
27740
|
+
const pattern = rawPattern.replaceAll("\\ ", " ");
|
|
27741
|
+
const owners = rest.split(/\s+/).filter(Boolean);
|
|
27742
|
+
if (!owners.length)
|
|
27743
|
+
return null;
|
|
27744
|
+
return { pattern, owners };
|
|
27745
|
+
}
|
|
27717
27746
|
function parseCodeowners(path) {
|
|
27718
27747
|
const text = node_fs_1.default.readFileSync(path, "utf8");
|
|
27719
27748
|
const rules = [];
|
|
@@ -27721,18 +27750,60 @@ function parseCodeowners(path) {
|
|
|
27721
27750
|
const line = raw.trim();
|
|
27722
27751
|
if (!line || line.startsWith("#"))
|
|
27723
27752
|
continue;
|
|
27724
|
-
const
|
|
27725
|
-
if (
|
|
27753
|
+
const parsed = splitPatternOwners(line);
|
|
27754
|
+
if (!parsed)
|
|
27726
27755
|
continue;
|
|
27727
|
-
rules.push({ pattern:
|
|
27756
|
+
rules.push({ pattern: parsed.pattern, owners: parsed.owners });
|
|
27728
27757
|
}
|
|
27729
27758
|
return rules;
|
|
27730
27759
|
}
|
|
27760
|
+
function hasGlobMagic(p) {
|
|
27761
|
+
// Good-enough heuristic for gitignore-style globs.
|
|
27762
|
+
return /[*?\[]/.test(p);
|
|
27763
|
+
}
|
|
27731
27764
|
function matches(file, pattern) {
|
|
27732
|
-
|
|
27733
|
-
//
|
|
27734
|
-
|
|
27735
|
-
|
|
27765
|
+
// GitHub CODEOWNERS patterns are gitignore-like:
|
|
27766
|
+
// - Leading `/` anchors to repo root
|
|
27767
|
+
// - Pattern without `/` matches a basename anywhere
|
|
27768
|
+
// - A directory pattern matches everything under it (e.g. `/frontend/admin` should match `/frontend/admin/**`)
|
|
27769
|
+
const f = file.replace(/\\/g, "/").replace(/^\.?\//, "");
|
|
27770
|
+
let pat = pattern.replace(/\\/g, "/").trim();
|
|
27771
|
+
if (!pat)
|
|
27772
|
+
return false;
|
|
27773
|
+
const anchored = pat.startsWith("/");
|
|
27774
|
+
if (anchored)
|
|
27775
|
+
pat = pat.slice(1);
|
|
27776
|
+
// Directory patterns: trailing `/` means directory; also treat non-glob literal paths as directory-or-file match.
|
|
27777
|
+
const trailingSlash = pat.endsWith("/");
|
|
27778
|
+
if (trailingSlash)
|
|
27779
|
+
pat = pat.slice(0, -1);
|
|
27780
|
+
const isLiteral = !hasGlobMagic(pat);
|
|
27781
|
+
const hasSlash = pat.includes("/");
|
|
27782
|
+
// Literal path: match exact file OR directory subtree.
|
|
27783
|
+
if (isLiteral && (anchored || hasSlash)) {
|
|
27784
|
+
return f === pat || f.startsWith(pat + "/");
|
|
27785
|
+
}
|
|
27786
|
+
// Literal basename: match basename OR directory subtree anywhere.
|
|
27787
|
+
if (isLiteral && !hasSlash) {
|
|
27788
|
+
const base = f.split("/").pop() ?? f;
|
|
27789
|
+
if (base === pat)
|
|
27790
|
+
return true;
|
|
27791
|
+
return f.includes("/" + pat + "/");
|
|
27792
|
+
}
|
|
27793
|
+
// Glob patterns: use minimatch.
|
|
27794
|
+
// - If anchored: match from repo root.
|
|
27795
|
+
// - If not anchored and no slash: match basename anywhere.
|
|
27796
|
+
// - If not anchored but includes a slash: match relative to repo root (like a root CODEOWNERS / .gitignore).
|
|
27797
|
+
const matchBase = !anchored && !hasSlash;
|
|
27798
|
+
const mm = (0, minimatch_1.minimatch)(f, pat, { dot: true, matchBase });
|
|
27799
|
+
if (mm)
|
|
27800
|
+
return true;
|
|
27801
|
+
// If the pattern explicitly denotes a directory (trailing slash), also match directory subtree.
|
|
27802
|
+
if (trailingSlash) {
|
|
27803
|
+
// Convert `dir/` to subtree match.
|
|
27804
|
+
return (0, minimatch_1.minimatch)(f, pat + "/**", { dot: true, matchBase: false });
|
|
27805
|
+
}
|
|
27806
|
+
return false;
|
|
27736
27807
|
}
|
|
27737
27808
|
function ownersForFile(file, rules) {
|
|
27738
27809
|
let hit;
|