@doccov/cli 0.28.2 → 0.29.0

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.
Files changed (2) hide show
  1. package/dist/cli.js +2035 -86
  2. package/package.json +3 -2
package/dist/cli.js CHANGED
@@ -74,8 +74,8 @@ ${formatIssues(issues)}`);
74
74
  // src/config/index.ts
75
75
  var defineConfig = (config) => config;
76
76
  // src/cli.ts
77
- import { readFileSync as readFileSync5 } from "node:fs";
78
- import * as path10 from "node:path";
77
+ import { readFileSync as readFileSync7 } from "node:fs";
78
+ import * as path12 from "node:path";
79
79
  import { fileURLToPath } from "node:url";
80
80
  import { Command } from "commander";
81
81
 
@@ -1650,6 +1650,1897 @@ function displayApiSurfaceOutput(doccov, deps) {
1650
1650
 
1651
1651
  // src/commands/check/validation.ts
1652
1652
  import { validateExamples } from "@doccov/sdk";
1653
+
1654
+ // src/commands/check/docs-fetcher.ts
1655
+ import * as cheerio from "cheerio";
1656
+
1657
+ // src/commands/check/docsCache.ts
1658
+ import * as crypto from "node:crypto";
1659
+ import * as fs4 from "node:fs";
1660
+ import * as path6 from "node:path";
1661
+ var DEFAULT_TTL = 60 * 60 * 1000;
1662
+ function getCacheDir(cwd) {
1663
+ return path6.join(cwd, ".doccov", "cache");
1664
+ }
1665
+ function getCacheSubdir(cwd, type) {
1666
+ return path6.join(getCacheDir(cwd), type);
1667
+ }
1668
+ function ensureCacheDir(cwd) {
1669
+ const subdirs = ["urls", "github", "gitlab"];
1670
+ for (const subdir of subdirs) {
1671
+ const dir = getCacheSubdir(cwd, subdir);
1672
+ if (!fs4.existsSync(dir)) {
1673
+ fs4.mkdirSync(dir, { recursive: true });
1674
+ }
1675
+ }
1676
+ }
1677
+ function getCacheFilename(key) {
1678
+ const hash = crypto.createHash("sha256").update(key).digest("hex").slice(0, 16);
1679
+ const sanitized = key.replace(/[^a-zA-Z0-9-_]/g, "_").slice(0, 50);
1680
+ return `${sanitized}_${hash}.json`;
1681
+ }
1682
+ function getFromCache(cwd, type, key, ttl = DEFAULT_TTL) {
1683
+ const cacheFile = path6.join(getCacheSubdir(cwd, type), getCacheFilename(key));
1684
+ if (!fs4.existsSync(cacheFile)) {
1685
+ return null;
1686
+ }
1687
+ try {
1688
+ const data = JSON.parse(fs4.readFileSync(cacheFile, "utf-8"));
1689
+ if (Date.now() - data.fetchedAt > ttl) {
1690
+ return null;
1691
+ }
1692
+ return data;
1693
+ } catch {
1694
+ return null;
1695
+ }
1696
+ }
1697
+ function writeToCache(cwd, type, key, content) {
1698
+ ensureCacheDir(cwd);
1699
+ const cacheFile = path6.join(getCacheSubdir(cwd, type), getCacheFilename(key));
1700
+ const entry = {
1701
+ content,
1702
+ fetchedAt: Date.now(),
1703
+ source: key
1704
+ };
1705
+ fs4.writeFileSync(cacheFile, JSON.stringify(entry, null, 2));
1706
+ }
1707
+
1708
+ // src/commands/check/docs-fetcher.ts
1709
+ var DEFAULT_TIMEOUT = 1e4;
1710
+ var DEFAULT_TTL2 = 60 * 60 * 1000;
1711
+ async function fetchUrlDocs(source, options = {}) {
1712
+ const { timeout = DEFAULT_TIMEOUT, ttl = DEFAULT_TTL2, useCache = true, cwd = process.cwd() } = options;
1713
+ if (useCache) {
1714
+ const cached = getFromCache(cwd, "urls", source.url, ttl);
1715
+ if (cached) {
1716
+ const doc = parseContentToDoc(cached.content, source.url);
1717
+ return { source, doc, cached: true };
1718
+ }
1719
+ }
1720
+ try {
1721
+ const controller = new AbortController;
1722
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
1723
+ const response = await fetch(source.url, {
1724
+ signal: controller.signal,
1725
+ headers: {
1726
+ "User-Agent": "doccov-cli",
1727
+ Accept: "text/html, text/markdown, text/plain, */*"
1728
+ },
1729
+ redirect: "follow"
1730
+ });
1731
+ clearTimeout(timeoutId);
1732
+ if (!response.ok) {
1733
+ return {
1734
+ source,
1735
+ doc: null,
1736
+ error: `HTTP ${response.status}: ${response.statusText}`
1737
+ };
1738
+ }
1739
+ const content = await response.text();
1740
+ const contentType = response.headers.get("content-type") ?? "";
1741
+ if (useCache) {
1742
+ writeToCache(cwd, "urls", source.url, content);
1743
+ }
1744
+ const doc = parseContentToDoc(content, source.url, contentType);
1745
+ return { source, doc };
1746
+ } catch (err) {
1747
+ const message = err instanceof Error ? err.message : String(err);
1748
+ if (message.includes("abort")) {
1749
+ return { source, doc: null, error: `Timeout after ${timeout}ms` };
1750
+ }
1751
+ return { source, doc: null, error: message };
1752
+ }
1753
+ }
1754
+ async function fetchUrlDocsBatch(sources, options = {}) {
1755
+ return Promise.all(sources.map((s) => fetchUrlDocs(s, options)));
1756
+ }
1757
+ function parseContentToDoc(content, url, contentType) {
1758
+ const isMarkdown = contentType?.includes("markdown") || url.endsWith(".md") || url.endsWith(".mdx");
1759
+ if (isMarkdown) {
1760
+ return parseMarkdownContent(content, url);
1761
+ }
1762
+ return parseHtmlContent(content, url);
1763
+ }
1764
+ function parseMarkdownContent(content, url) {
1765
+ const codeBlocks = extractMarkdownCodeBlocks(content);
1766
+ return { path: url, codeBlocks };
1767
+ }
1768
+ function parseHtmlContent(content, url) {
1769
+ const $ = cheerio.load(content);
1770
+ const codeBlocks = [];
1771
+ const selectors = [
1772
+ "pre code",
1773
+ "pre.highlight code",
1774
+ "pre.prism-code",
1775
+ ".theme-code-block pre",
1776
+ "pre.nextra-code",
1777
+ "[data-language] code",
1778
+ "pre.shiki code",
1779
+ ".code-block pre",
1780
+ ".codeblock pre"
1781
+ ];
1782
+ const seen = new Set;
1783
+ for (const selector of selectors) {
1784
+ $(selector).each((_, el) => {
1785
+ const $el = $(el);
1786
+ const code = $el.text().trim();
1787
+ if (!code || seen.has(code))
1788
+ return;
1789
+ seen.add(code);
1790
+ const lang = detectLanguage($el, $);
1791
+ if (!isExecutableLang(lang))
1792
+ return;
1793
+ codeBlocks.push({
1794
+ lang: lang || "ts",
1795
+ code,
1796
+ lineStart: 0,
1797
+ lineEnd: 0
1798
+ });
1799
+ });
1800
+ }
1801
+ return { path: url, codeBlocks };
1802
+ }
1803
+ function detectLanguage($el, $) {
1804
+ const classes = [
1805
+ $el.attr("class") ?? "",
1806
+ $el.parent().attr("class") ?? "",
1807
+ $el.attr("data-language") ?? "",
1808
+ $el.parent().attr("data-language") ?? ""
1809
+ ].join(" ");
1810
+ const langMatch = classes.match(/(?:language|lang|prism)-(\w+)/i);
1811
+ if (langMatch) {
1812
+ return normalizeLanguage(langMatch[1]);
1813
+ }
1814
+ const dataLang = $el.attr("data-lang") || $el.parent().attr("data-lang");
1815
+ if (dataLang) {
1816
+ return normalizeLanguage(dataLang);
1817
+ }
1818
+ return null;
1819
+ }
1820
+ function normalizeLanguage(lang) {
1821
+ const lower = lang.toLowerCase();
1822
+ const aliases = {
1823
+ typescript: "ts",
1824
+ javascript: "js",
1825
+ tsx: "tsx",
1826
+ jsx: "jsx",
1827
+ node: "js",
1828
+ esm: "js"
1829
+ };
1830
+ return aliases[lower] ?? lower;
1831
+ }
1832
+ function isExecutableLang(lang) {
1833
+ if (!lang)
1834
+ return false;
1835
+ const executableLangs = new Set(["ts", "typescript", "js", "javascript", "tsx", "jsx", "mts", "mjs"]);
1836
+ return executableLangs.has(lang.toLowerCase());
1837
+ }
1838
+ function extractMarkdownCodeBlocks(content) {
1839
+ const codeBlocks = [];
1840
+ const lines = content.split(`
1841
+ `);
1842
+ let inBlock = false;
1843
+ let blockLang = "";
1844
+ let blockCode = [];
1845
+ let blockStart = 0;
1846
+ for (let i = 0;i < lines.length; i++) {
1847
+ const line = lines[i];
1848
+ if (!inBlock && line.startsWith("```")) {
1849
+ inBlock = true;
1850
+ blockLang = line.slice(3).trim().split(/\s/)[0] || "";
1851
+ blockCode = [];
1852
+ blockStart = i + 1;
1853
+ } else if (inBlock && line.startsWith("```")) {
1854
+ if (isExecutableLang(blockLang)) {
1855
+ codeBlocks.push({
1856
+ lang: normalizeLanguage(blockLang) || "ts",
1857
+ code: blockCode.join(`
1858
+ `),
1859
+ lineStart: blockStart,
1860
+ lineEnd: i
1861
+ });
1862
+ }
1863
+ inBlock = false;
1864
+ blockLang = "";
1865
+ blockCode = [];
1866
+ } else if (inBlock) {
1867
+ blockCode.push(line);
1868
+ }
1869
+ }
1870
+ return codeBlocks;
1871
+ }
1872
+
1873
+ // ../../node_modules/@isaacs/balanced-match/dist/esm/index.js
1874
+ var balanced = (a, b, str) => {
1875
+ const ma = a instanceof RegExp ? maybeMatch(a, str) : a;
1876
+ const mb = b instanceof RegExp ? maybeMatch(b, str) : b;
1877
+ const r = ma !== null && mb != null && range(ma, mb, str);
1878
+ return r && {
1879
+ start: r[0],
1880
+ end: r[1],
1881
+ pre: str.slice(0, r[0]),
1882
+ body: str.slice(r[0] + ma.length, r[1]),
1883
+ post: str.slice(r[1] + mb.length)
1884
+ };
1885
+ };
1886
+ var maybeMatch = (reg, str) => {
1887
+ const m = str.match(reg);
1888
+ return m ? m[0] : null;
1889
+ };
1890
+ var range = (a, b, str) => {
1891
+ let begs, beg, left, right = undefined, result;
1892
+ let ai = str.indexOf(a);
1893
+ let bi = str.indexOf(b, ai + 1);
1894
+ let i = ai;
1895
+ if (ai >= 0 && bi > 0) {
1896
+ if (a === b) {
1897
+ return [ai, bi];
1898
+ }
1899
+ begs = [];
1900
+ left = str.length;
1901
+ while (i >= 0 && !result) {
1902
+ if (i === ai) {
1903
+ begs.push(i);
1904
+ ai = str.indexOf(a, i + 1);
1905
+ } else if (begs.length === 1) {
1906
+ const r = begs.pop();
1907
+ if (r !== undefined)
1908
+ result = [r, bi];
1909
+ } else {
1910
+ beg = begs.pop();
1911
+ if (beg !== undefined && beg < left) {
1912
+ left = beg;
1913
+ right = bi;
1914
+ }
1915
+ bi = str.indexOf(b, i + 1);
1916
+ }
1917
+ i = ai < bi && ai >= 0 ? ai : bi;
1918
+ }
1919
+ if (begs.length && right !== undefined) {
1920
+ result = [left, right];
1921
+ }
1922
+ }
1923
+ return result;
1924
+ };
1925
+
1926
+ // ../../node_modules/@isaacs/brace-expansion/dist/esm/index.js
1927
+ var escSlash = "\x00SLASH" + Math.random() + "\x00";
1928
+ var escOpen = "\x00OPEN" + Math.random() + "\x00";
1929
+ var escClose = "\x00CLOSE" + Math.random() + "\x00";
1930
+ var escComma = "\x00COMMA" + Math.random() + "\x00";
1931
+ var escPeriod = "\x00PERIOD" + Math.random() + "\x00";
1932
+ var escSlashPattern = new RegExp(escSlash, "g");
1933
+ var escOpenPattern = new RegExp(escOpen, "g");
1934
+ var escClosePattern = new RegExp(escClose, "g");
1935
+ var escCommaPattern = new RegExp(escComma, "g");
1936
+ var escPeriodPattern = new RegExp(escPeriod, "g");
1937
+ var slashPattern = /\\\\/g;
1938
+ var openPattern = /\\{/g;
1939
+ var closePattern = /\\}/g;
1940
+ var commaPattern = /\\,/g;
1941
+ var periodPattern = /\\./g;
1942
+ function numeric(str) {
1943
+ return !isNaN(str) ? parseInt(str, 10) : str.charCodeAt(0);
1944
+ }
1945
+ function escapeBraces(str) {
1946
+ return str.replace(slashPattern, escSlash).replace(openPattern, escOpen).replace(closePattern, escClose).replace(commaPattern, escComma).replace(periodPattern, escPeriod);
1947
+ }
1948
+ function unescapeBraces(str) {
1949
+ return str.replace(escSlashPattern, "\\").replace(escOpenPattern, "{").replace(escClosePattern, "}").replace(escCommaPattern, ",").replace(escPeriodPattern, ".");
1950
+ }
1951
+ function parseCommaParts(str) {
1952
+ if (!str) {
1953
+ return [""];
1954
+ }
1955
+ const parts = [];
1956
+ const m = balanced("{", "}", str);
1957
+ if (!m) {
1958
+ return str.split(",");
1959
+ }
1960
+ const { pre, body, post } = m;
1961
+ const p = pre.split(",");
1962
+ p[p.length - 1] += "{" + body + "}";
1963
+ const postParts = parseCommaParts(post);
1964
+ if (post.length) {
1965
+ p[p.length - 1] += postParts.shift();
1966
+ p.push.apply(p, postParts);
1967
+ }
1968
+ parts.push.apply(parts, p);
1969
+ return parts;
1970
+ }
1971
+ function expand(str) {
1972
+ if (!str) {
1973
+ return [];
1974
+ }
1975
+ if (str.slice(0, 2) === "{}") {
1976
+ str = "\\{\\}" + str.slice(2);
1977
+ }
1978
+ return expand_(escapeBraces(str), true).map(unescapeBraces);
1979
+ }
1980
+ function embrace(str) {
1981
+ return "{" + str + "}";
1982
+ }
1983
+ function isPadded(el) {
1984
+ return /^-?0\d/.test(el);
1985
+ }
1986
+ function lte(i, y) {
1987
+ return i <= y;
1988
+ }
1989
+ function gte(i, y) {
1990
+ return i >= y;
1991
+ }
1992
+ function expand_(str, isTop) {
1993
+ const expansions = [];
1994
+ const m = balanced("{", "}", str);
1995
+ if (!m)
1996
+ return [str];
1997
+ const pre = m.pre;
1998
+ const post = m.post.length ? expand_(m.post, false) : [""];
1999
+ if (/\$$/.test(m.pre)) {
2000
+ for (let k = 0;k < post.length; k++) {
2001
+ const expansion = pre + "{" + m.body + "}" + post[k];
2002
+ expansions.push(expansion);
2003
+ }
2004
+ } else {
2005
+ const isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body);
2006
+ const isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body);
2007
+ const isSequence = isNumericSequence || isAlphaSequence;
2008
+ const isOptions = m.body.indexOf(",") >= 0;
2009
+ if (!isSequence && !isOptions) {
2010
+ if (m.post.match(/,(?!,).*\}/)) {
2011
+ str = m.pre + "{" + m.body + escClose + m.post;
2012
+ return expand_(str);
2013
+ }
2014
+ return [str];
2015
+ }
2016
+ let n;
2017
+ if (isSequence) {
2018
+ n = m.body.split(/\.\./);
2019
+ } else {
2020
+ n = parseCommaParts(m.body);
2021
+ if (n.length === 1 && n[0] !== undefined) {
2022
+ n = expand_(n[0], false).map(embrace);
2023
+ if (n.length === 1) {
2024
+ return post.map((p) => m.pre + n[0] + p);
2025
+ }
2026
+ }
2027
+ }
2028
+ let N;
2029
+ if (isSequence && n[0] !== undefined && n[1] !== undefined) {
2030
+ const x = numeric(n[0]);
2031
+ const y = numeric(n[1]);
2032
+ const width = Math.max(n[0].length, n[1].length);
2033
+ let incr = n.length === 3 && n[2] !== undefined ? Math.abs(numeric(n[2])) : 1;
2034
+ let test = lte;
2035
+ const reverse = y < x;
2036
+ if (reverse) {
2037
+ incr *= -1;
2038
+ test = gte;
2039
+ }
2040
+ const pad = n.some(isPadded);
2041
+ N = [];
2042
+ for (let i = x;test(i, y); i += incr) {
2043
+ let c;
2044
+ if (isAlphaSequence) {
2045
+ c = String.fromCharCode(i);
2046
+ if (c === "\\") {
2047
+ c = "";
2048
+ }
2049
+ } else {
2050
+ c = String(i);
2051
+ if (pad) {
2052
+ const need = width - c.length;
2053
+ if (need > 0) {
2054
+ const z = new Array(need + 1).join("0");
2055
+ if (i < 0) {
2056
+ c = "-" + z + c.slice(1);
2057
+ } else {
2058
+ c = z + c;
2059
+ }
2060
+ }
2061
+ }
2062
+ }
2063
+ N.push(c);
2064
+ }
2065
+ } else {
2066
+ N = [];
2067
+ for (let j = 0;j < n.length; j++) {
2068
+ N.push.apply(N, expand_(n[j], false));
2069
+ }
2070
+ }
2071
+ for (let j = 0;j < N.length; j++) {
2072
+ for (let k = 0;k < post.length; k++) {
2073
+ const expansion = pre + N[j] + post[k];
2074
+ if (!isTop || isSequence || expansion) {
2075
+ expansions.push(expansion);
2076
+ }
2077
+ }
2078
+ }
2079
+ }
2080
+ return expansions;
2081
+ }
2082
+
2083
+ // ../../node_modules/minimatch/dist/esm/assert-valid-pattern.js
2084
+ var MAX_PATTERN_LENGTH = 1024 * 64;
2085
+ var assertValidPattern = (pattern) => {
2086
+ if (typeof pattern !== "string") {
2087
+ throw new TypeError("invalid pattern");
2088
+ }
2089
+ if (pattern.length > MAX_PATTERN_LENGTH) {
2090
+ throw new TypeError("pattern is too long");
2091
+ }
2092
+ };
2093
+
2094
+ // ../../node_modules/minimatch/dist/esm/brace-expressions.js
2095
+ var posixClasses = {
2096
+ "[:alnum:]": ["\\p{L}\\p{Nl}\\p{Nd}", true],
2097
+ "[:alpha:]": ["\\p{L}\\p{Nl}", true],
2098
+ "[:ascii:]": ["\\x" + "00-\\x" + "7f", false],
2099
+ "[:blank:]": ["\\p{Zs}\\t", true],
2100
+ "[:cntrl:]": ["\\p{Cc}", true],
2101
+ "[:digit:]": ["\\p{Nd}", true],
2102
+ "[:graph:]": ["\\p{Z}\\p{C}", true, true],
2103
+ "[:lower:]": ["\\p{Ll}", true],
2104
+ "[:print:]": ["\\p{C}", true],
2105
+ "[:punct:]": ["\\p{P}", true],
2106
+ "[:space:]": ["\\p{Z}\\t\\r\\n\\v\\f", true],
2107
+ "[:upper:]": ["\\p{Lu}", true],
2108
+ "[:word:]": ["\\p{L}\\p{Nl}\\p{Nd}\\p{Pc}", true],
2109
+ "[:xdigit:]": ["A-Fa-f0-9", false]
2110
+ };
2111
+ var braceEscape = (s) => s.replace(/[[\]\\-]/g, "\\$&");
2112
+ var regexpEscape = (s) => s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
2113
+ var rangesToString = (ranges) => ranges.join("");
2114
+ var parseClass = (glob2, position) => {
2115
+ const pos = position;
2116
+ if (glob2.charAt(pos) !== "[") {
2117
+ throw new Error("not in a brace expression");
2118
+ }
2119
+ const ranges = [];
2120
+ const negs = [];
2121
+ let i = pos + 1;
2122
+ let sawStart = false;
2123
+ let uflag = false;
2124
+ let escaping = false;
2125
+ let negate = false;
2126
+ let endPos = pos;
2127
+ let rangeStart = "";
2128
+ WHILE:
2129
+ while (i < glob2.length) {
2130
+ const c = glob2.charAt(i);
2131
+ if ((c === "!" || c === "^") && i === pos + 1) {
2132
+ negate = true;
2133
+ i++;
2134
+ continue;
2135
+ }
2136
+ if (c === "]" && sawStart && !escaping) {
2137
+ endPos = i + 1;
2138
+ break;
2139
+ }
2140
+ sawStart = true;
2141
+ if (c === "\\") {
2142
+ if (!escaping) {
2143
+ escaping = true;
2144
+ i++;
2145
+ continue;
2146
+ }
2147
+ }
2148
+ if (c === "[" && !escaping) {
2149
+ for (const [cls, [unip, u, neg]] of Object.entries(posixClasses)) {
2150
+ if (glob2.startsWith(cls, i)) {
2151
+ if (rangeStart) {
2152
+ return ["$.", false, glob2.length - pos, true];
2153
+ }
2154
+ i += cls.length;
2155
+ if (neg)
2156
+ negs.push(unip);
2157
+ else
2158
+ ranges.push(unip);
2159
+ uflag = uflag || u;
2160
+ continue WHILE;
2161
+ }
2162
+ }
2163
+ }
2164
+ escaping = false;
2165
+ if (rangeStart) {
2166
+ if (c > rangeStart) {
2167
+ ranges.push(braceEscape(rangeStart) + "-" + braceEscape(c));
2168
+ } else if (c === rangeStart) {
2169
+ ranges.push(braceEscape(c));
2170
+ }
2171
+ rangeStart = "";
2172
+ i++;
2173
+ continue;
2174
+ }
2175
+ if (glob2.startsWith("-]", i + 1)) {
2176
+ ranges.push(braceEscape(c + "-"));
2177
+ i += 2;
2178
+ continue;
2179
+ }
2180
+ if (glob2.startsWith("-", i + 1)) {
2181
+ rangeStart = c;
2182
+ i += 2;
2183
+ continue;
2184
+ }
2185
+ ranges.push(braceEscape(c));
2186
+ i++;
2187
+ }
2188
+ if (endPos < i) {
2189
+ return ["", false, 0, false];
2190
+ }
2191
+ if (!ranges.length && !negs.length) {
2192
+ return ["$.", false, glob2.length - pos, true];
2193
+ }
2194
+ if (negs.length === 0 && ranges.length === 1 && /^\\?.$/.test(ranges[0]) && !negate) {
2195
+ const r = ranges[0].length === 2 ? ranges[0].slice(-1) : ranges[0];
2196
+ return [regexpEscape(r), false, endPos - pos, false];
2197
+ }
2198
+ const sranges = "[" + (negate ? "^" : "") + rangesToString(ranges) + "]";
2199
+ const snegs = "[" + (negate ? "" : "^") + rangesToString(negs) + "]";
2200
+ const comb = ranges.length && negs.length ? "(" + sranges + "|" + snegs + ")" : ranges.length ? sranges : snegs;
2201
+ return [comb, uflag, endPos - pos, true];
2202
+ };
2203
+
2204
+ // ../../node_modules/minimatch/dist/esm/unescape.js
2205
+ var unescape = (s, { windowsPathsNoEscape = false, magicalBraces = true } = {}) => {
2206
+ if (magicalBraces) {
2207
+ return windowsPathsNoEscape ? s.replace(/\[([^\/\\])\]/g, "$1") : s.replace(/((?!\\).|^)\[([^\/\\])\]/g, "$1$2").replace(/\\([^\/])/g, "$1");
2208
+ }
2209
+ return windowsPathsNoEscape ? s.replace(/\[([^\/\\{}])\]/g, "$1") : s.replace(/((?!\\).|^)\[([^\/\\{}])\]/g, "$1$2").replace(/\\([^\/{}])/g, "$1");
2210
+ };
2211
+
2212
+ // ../../node_modules/minimatch/dist/esm/ast.js
2213
+ var types = new Set(["!", "?", "+", "*", "@"]);
2214
+ var isExtglobType = (c) => types.has(c);
2215
+ var startNoTraversal = "(?!(?:^|/)\\.\\.?(?:$|/))";
2216
+ var startNoDot = "(?!\\.)";
2217
+ var addPatternStart = new Set(["[", "."]);
2218
+ var justDots = new Set(["..", "."]);
2219
+ var reSpecials = new Set("().*{}+?[]^$\\!");
2220
+ var regExpEscape = (s) => s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
2221
+ var qmark = "[^/]";
2222
+ var star = qmark + "*?";
2223
+ var starNoEmpty = qmark + "+?";
2224
+
2225
+ class AST {
2226
+ type;
2227
+ #root;
2228
+ #hasMagic;
2229
+ #uflag = false;
2230
+ #parts = [];
2231
+ #parent;
2232
+ #parentIndex;
2233
+ #negs;
2234
+ #filledNegs = false;
2235
+ #options;
2236
+ #toString;
2237
+ #emptyExt = false;
2238
+ constructor(type, parent, options = {}) {
2239
+ this.type = type;
2240
+ if (type)
2241
+ this.#hasMagic = true;
2242
+ this.#parent = parent;
2243
+ this.#root = this.#parent ? this.#parent.#root : this;
2244
+ this.#options = this.#root === this ? options : this.#root.#options;
2245
+ this.#negs = this.#root === this ? [] : this.#root.#negs;
2246
+ if (type === "!" && !this.#root.#filledNegs)
2247
+ this.#negs.push(this);
2248
+ this.#parentIndex = this.#parent ? this.#parent.#parts.length : 0;
2249
+ }
2250
+ get hasMagic() {
2251
+ if (this.#hasMagic !== undefined)
2252
+ return this.#hasMagic;
2253
+ for (const p of this.#parts) {
2254
+ if (typeof p === "string")
2255
+ continue;
2256
+ if (p.type || p.hasMagic)
2257
+ return this.#hasMagic = true;
2258
+ }
2259
+ return this.#hasMagic;
2260
+ }
2261
+ toString() {
2262
+ if (this.#toString !== undefined)
2263
+ return this.#toString;
2264
+ if (!this.type) {
2265
+ return this.#toString = this.#parts.map((p) => String(p)).join("");
2266
+ } else {
2267
+ return this.#toString = this.type + "(" + this.#parts.map((p) => String(p)).join("|") + ")";
2268
+ }
2269
+ }
2270
+ #fillNegs() {
2271
+ if (this !== this.#root)
2272
+ throw new Error("should only call on root");
2273
+ if (this.#filledNegs)
2274
+ return this;
2275
+ this.toString();
2276
+ this.#filledNegs = true;
2277
+ let n;
2278
+ while (n = this.#negs.pop()) {
2279
+ if (n.type !== "!")
2280
+ continue;
2281
+ let p = n;
2282
+ let pp = p.#parent;
2283
+ while (pp) {
2284
+ for (let i = p.#parentIndex + 1;!pp.type && i < pp.#parts.length; i++) {
2285
+ for (const part of n.#parts) {
2286
+ if (typeof part === "string") {
2287
+ throw new Error("string part in extglob AST??");
2288
+ }
2289
+ part.copyIn(pp.#parts[i]);
2290
+ }
2291
+ }
2292
+ p = pp;
2293
+ pp = p.#parent;
2294
+ }
2295
+ }
2296
+ return this;
2297
+ }
2298
+ push(...parts) {
2299
+ for (const p of parts) {
2300
+ if (p === "")
2301
+ continue;
2302
+ if (typeof p !== "string" && !(p instanceof AST && p.#parent === this)) {
2303
+ throw new Error("invalid part: " + p);
2304
+ }
2305
+ this.#parts.push(p);
2306
+ }
2307
+ }
2308
+ toJSON() {
2309
+ const ret = this.type === null ? this.#parts.slice().map((p) => typeof p === "string" ? p : p.toJSON()) : [this.type, ...this.#parts.map((p) => p.toJSON())];
2310
+ if (this.isStart() && !this.type)
2311
+ ret.unshift([]);
2312
+ if (this.isEnd() && (this === this.#root || this.#root.#filledNegs && this.#parent?.type === "!")) {
2313
+ ret.push({});
2314
+ }
2315
+ return ret;
2316
+ }
2317
+ isStart() {
2318
+ if (this.#root === this)
2319
+ return true;
2320
+ if (!this.#parent?.isStart())
2321
+ return false;
2322
+ if (this.#parentIndex === 0)
2323
+ return true;
2324
+ const p = this.#parent;
2325
+ for (let i = 0;i < this.#parentIndex; i++) {
2326
+ const pp = p.#parts[i];
2327
+ if (!(pp instanceof AST && pp.type === "!")) {
2328
+ return false;
2329
+ }
2330
+ }
2331
+ return true;
2332
+ }
2333
+ isEnd() {
2334
+ if (this.#root === this)
2335
+ return true;
2336
+ if (this.#parent?.type === "!")
2337
+ return true;
2338
+ if (!this.#parent?.isEnd())
2339
+ return false;
2340
+ if (!this.type)
2341
+ return this.#parent?.isEnd();
2342
+ const pl = this.#parent ? this.#parent.#parts.length : 0;
2343
+ return this.#parentIndex === pl - 1;
2344
+ }
2345
+ copyIn(part) {
2346
+ if (typeof part === "string")
2347
+ this.push(part);
2348
+ else
2349
+ this.push(part.clone(this));
2350
+ }
2351
+ clone(parent) {
2352
+ const c = new AST(this.type, parent);
2353
+ for (const p of this.#parts) {
2354
+ c.copyIn(p);
2355
+ }
2356
+ return c;
2357
+ }
2358
+ static #parseAST(str, ast, pos, opt) {
2359
+ let escaping = false;
2360
+ let inBrace = false;
2361
+ let braceStart = -1;
2362
+ let braceNeg = false;
2363
+ if (ast.type === null) {
2364
+ let i2 = pos;
2365
+ let acc2 = "";
2366
+ while (i2 < str.length) {
2367
+ const c = str.charAt(i2++);
2368
+ if (escaping || c === "\\") {
2369
+ escaping = !escaping;
2370
+ acc2 += c;
2371
+ continue;
2372
+ }
2373
+ if (inBrace) {
2374
+ if (i2 === braceStart + 1) {
2375
+ if (c === "^" || c === "!") {
2376
+ braceNeg = true;
2377
+ }
2378
+ } else if (c === "]" && !(i2 === braceStart + 2 && braceNeg)) {
2379
+ inBrace = false;
2380
+ }
2381
+ acc2 += c;
2382
+ continue;
2383
+ } else if (c === "[") {
2384
+ inBrace = true;
2385
+ braceStart = i2;
2386
+ braceNeg = false;
2387
+ acc2 += c;
2388
+ continue;
2389
+ }
2390
+ if (!opt.noext && isExtglobType(c) && str.charAt(i2) === "(") {
2391
+ ast.push(acc2);
2392
+ acc2 = "";
2393
+ const ext = new AST(c, ast);
2394
+ i2 = AST.#parseAST(str, ext, i2, opt);
2395
+ ast.push(ext);
2396
+ continue;
2397
+ }
2398
+ acc2 += c;
2399
+ }
2400
+ ast.push(acc2);
2401
+ return i2;
2402
+ }
2403
+ let i = pos + 1;
2404
+ let part = new AST(null, ast);
2405
+ const parts = [];
2406
+ let acc = "";
2407
+ while (i < str.length) {
2408
+ const c = str.charAt(i++);
2409
+ if (escaping || c === "\\") {
2410
+ escaping = !escaping;
2411
+ acc += c;
2412
+ continue;
2413
+ }
2414
+ if (inBrace) {
2415
+ if (i === braceStart + 1) {
2416
+ if (c === "^" || c === "!") {
2417
+ braceNeg = true;
2418
+ }
2419
+ } else if (c === "]" && !(i === braceStart + 2 && braceNeg)) {
2420
+ inBrace = false;
2421
+ }
2422
+ acc += c;
2423
+ continue;
2424
+ } else if (c === "[") {
2425
+ inBrace = true;
2426
+ braceStart = i;
2427
+ braceNeg = false;
2428
+ acc += c;
2429
+ continue;
2430
+ }
2431
+ if (isExtglobType(c) && str.charAt(i) === "(") {
2432
+ part.push(acc);
2433
+ acc = "";
2434
+ const ext = new AST(c, part);
2435
+ part.push(ext);
2436
+ i = AST.#parseAST(str, ext, i, opt);
2437
+ continue;
2438
+ }
2439
+ if (c === "|") {
2440
+ part.push(acc);
2441
+ acc = "";
2442
+ parts.push(part);
2443
+ part = new AST(null, ast);
2444
+ continue;
2445
+ }
2446
+ if (c === ")") {
2447
+ if (acc === "" && ast.#parts.length === 0) {
2448
+ ast.#emptyExt = true;
2449
+ }
2450
+ part.push(acc);
2451
+ acc = "";
2452
+ ast.push(...parts, part);
2453
+ return i;
2454
+ }
2455
+ acc += c;
2456
+ }
2457
+ ast.type = null;
2458
+ ast.#hasMagic = undefined;
2459
+ ast.#parts = [str.substring(pos - 1)];
2460
+ return i;
2461
+ }
2462
+ static fromGlob(pattern, options = {}) {
2463
+ const ast = new AST(null, undefined, options);
2464
+ AST.#parseAST(pattern, ast, 0, options);
2465
+ return ast;
2466
+ }
2467
+ toMMPattern() {
2468
+ if (this !== this.#root)
2469
+ return this.#root.toMMPattern();
2470
+ const glob2 = this.toString();
2471
+ const [re, body, hasMagic, uflag] = this.toRegExpSource();
2472
+ const anyMagic = hasMagic || this.#hasMagic || this.#options.nocase && !this.#options.nocaseMagicOnly && glob2.toUpperCase() !== glob2.toLowerCase();
2473
+ if (!anyMagic) {
2474
+ return body;
2475
+ }
2476
+ const flags = (this.#options.nocase ? "i" : "") + (uflag ? "u" : "");
2477
+ return Object.assign(new RegExp(`^${re}$`, flags), {
2478
+ _src: re,
2479
+ _glob: glob2
2480
+ });
2481
+ }
2482
+ get options() {
2483
+ return this.#options;
2484
+ }
2485
+ toRegExpSource(allowDot) {
2486
+ const dot = allowDot ?? !!this.#options.dot;
2487
+ if (this.#root === this)
2488
+ this.#fillNegs();
2489
+ if (!this.type) {
2490
+ const noEmpty = this.isStart() && this.isEnd() && !this.#parts.some((s) => typeof s !== "string");
2491
+ const src = this.#parts.map((p) => {
2492
+ const [re, _, hasMagic, uflag] = typeof p === "string" ? AST.#parseGlob(p, this.#hasMagic, noEmpty) : p.toRegExpSource(allowDot);
2493
+ this.#hasMagic = this.#hasMagic || hasMagic;
2494
+ this.#uflag = this.#uflag || uflag;
2495
+ return re;
2496
+ }).join("");
2497
+ let start2 = "";
2498
+ if (this.isStart()) {
2499
+ if (typeof this.#parts[0] === "string") {
2500
+ const dotTravAllowed = this.#parts.length === 1 && justDots.has(this.#parts[0]);
2501
+ if (!dotTravAllowed) {
2502
+ const aps = addPatternStart;
2503
+ const needNoTrav = dot && aps.has(src.charAt(0)) || src.startsWith("\\.") && aps.has(src.charAt(2)) || src.startsWith("\\.\\.") && aps.has(src.charAt(4));
2504
+ const needNoDot = !dot && !allowDot && aps.has(src.charAt(0));
2505
+ start2 = needNoTrav ? startNoTraversal : needNoDot ? startNoDot : "";
2506
+ }
2507
+ }
2508
+ }
2509
+ let end = "";
2510
+ if (this.isEnd() && this.#root.#filledNegs && this.#parent?.type === "!") {
2511
+ end = "(?:$|\\/)";
2512
+ }
2513
+ const final2 = start2 + src + end;
2514
+ return [
2515
+ final2,
2516
+ unescape(src),
2517
+ this.#hasMagic = !!this.#hasMagic,
2518
+ this.#uflag
2519
+ ];
2520
+ }
2521
+ const repeated = this.type === "*" || this.type === "+";
2522
+ const start = this.type === "!" ? "(?:(?!(?:" : "(?:";
2523
+ let body = this.#partsToRegExp(dot);
2524
+ if (this.isStart() && this.isEnd() && !body && this.type !== "!") {
2525
+ const s = this.toString();
2526
+ this.#parts = [s];
2527
+ this.type = null;
2528
+ this.#hasMagic = undefined;
2529
+ return [s, unescape(this.toString()), false, false];
2530
+ }
2531
+ let bodyDotAllowed = !repeated || allowDot || dot || !startNoDot ? "" : this.#partsToRegExp(true);
2532
+ if (bodyDotAllowed === body) {
2533
+ bodyDotAllowed = "";
2534
+ }
2535
+ if (bodyDotAllowed) {
2536
+ body = `(?:${body})(?:${bodyDotAllowed})*?`;
2537
+ }
2538
+ let final = "";
2539
+ if (this.type === "!" && this.#emptyExt) {
2540
+ final = (this.isStart() && !dot ? startNoDot : "") + starNoEmpty;
2541
+ } else {
2542
+ const close = this.type === "!" ? "))" + (this.isStart() && !dot && !allowDot ? startNoDot : "") + star + ")" : this.type === "@" ? ")" : this.type === "?" ? ")?" : this.type === "+" && bodyDotAllowed ? ")" : this.type === "*" && bodyDotAllowed ? `)?` : `)${this.type}`;
2543
+ final = start + body + close;
2544
+ }
2545
+ return [
2546
+ final,
2547
+ unescape(body),
2548
+ this.#hasMagic = !!this.#hasMagic,
2549
+ this.#uflag
2550
+ ];
2551
+ }
2552
+ #partsToRegExp(dot) {
2553
+ return this.#parts.map((p) => {
2554
+ if (typeof p === "string") {
2555
+ throw new Error("string type in extglob ast??");
2556
+ }
2557
+ const [re, _, _hasMagic, uflag] = p.toRegExpSource(dot);
2558
+ this.#uflag = this.#uflag || uflag;
2559
+ return re;
2560
+ }).filter((p) => !(this.isStart() && this.isEnd()) || !!p).join("|");
2561
+ }
2562
+ static #parseGlob(glob2, hasMagic, noEmpty = false) {
2563
+ let escaping = false;
2564
+ let re = "";
2565
+ let uflag = false;
2566
+ for (let i = 0;i < glob2.length; i++) {
2567
+ const c = glob2.charAt(i);
2568
+ if (escaping) {
2569
+ escaping = false;
2570
+ re += (reSpecials.has(c) ? "\\" : "") + c;
2571
+ continue;
2572
+ }
2573
+ if (c === "\\") {
2574
+ if (i === glob2.length - 1) {
2575
+ re += "\\\\";
2576
+ } else {
2577
+ escaping = true;
2578
+ }
2579
+ continue;
2580
+ }
2581
+ if (c === "[") {
2582
+ const [src, needUflag, consumed, magic] = parseClass(glob2, i);
2583
+ if (consumed) {
2584
+ re += src;
2585
+ uflag = uflag || needUflag;
2586
+ i += consumed - 1;
2587
+ hasMagic = hasMagic || magic;
2588
+ continue;
2589
+ }
2590
+ }
2591
+ if (c === "*") {
2592
+ re += noEmpty && glob2 === "*" ? starNoEmpty : star;
2593
+ hasMagic = true;
2594
+ continue;
2595
+ }
2596
+ if (c === "?") {
2597
+ re += qmark;
2598
+ hasMagic = true;
2599
+ continue;
2600
+ }
2601
+ re += regExpEscape(c);
2602
+ }
2603
+ return [re, unescape(glob2), !!hasMagic, uflag];
2604
+ }
2605
+ }
2606
+
2607
+ // ../../node_modules/minimatch/dist/esm/escape.js
2608
+ var escape = (s, { windowsPathsNoEscape = false, magicalBraces = false } = {}) => {
2609
+ if (magicalBraces) {
2610
+ return windowsPathsNoEscape ? s.replace(/[?*()[\]{}]/g, "[$&]") : s.replace(/[?*()[\]\\{}]/g, "\\$&");
2611
+ }
2612
+ return windowsPathsNoEscape ? s.replace(/[?*()[\]]/g, "[$&]") : s.replace(/[?*()[\]\\]/g, "\\$&");
2613
+ };
2614
+
2615
+ // ../../node_modules/minimatch/dist/esm/index.js
2616
+ var minimatch = (p, pattern, options = {}) => {
2617
+ assertValidPattern(pattern);
2618
+ if (!options.nocomment && pattern.charAt(0) === "#") {
2619
+ return false;
2620
+ }
2621
+ return new Minimatch(pattern, options).match(p);
2622
+ };
2623
+ var starDotExtRE = /^\*+([^+@!?\*\[\(]*)$/;
2624
+ var starDotExtTest = (ext) => (f) => !f.startsWith(".") && f.endsWith(ext);
2625
+ var starDotExtTestDot = (ext) => (f) => f.endsWith(ext);
2626
+ var starDotExtTestNocase = (ext) => {
2627
+ ext = ext.toLowerCase();
2628
+ return (f) => !f.startsWith(".") && f.toLowerCase().endsWith(ext);
2629
+ };
2630
+ var starDotExtTestNocaseDot = (ext) => {
2631
+ ext = ext.toLowerCase();
2632
+ return (f) => f.toLowerCase().endsWith(ext);
2633
+ };
2634
+ var starDotStarRE = /^\*+\.\*+$/;
2635
+ var starDotStarTest = (f) => !f.startsWith(".") && f.includes(".");
2636
+ var starDotStarTestDot = (f) => f !== "." && f !== ".." && f.includes(".");
2637
+ var dotStarRE = /^\.\*+$/;
2638
+ var dotStarTest = (f) => f !== "." && f !== ".." && f.startsWith(".");
2639
+ var starRE = /^\*+$/;
2640
+ var starTest = (f) => f.length !== 0 && !f.startsWith(".");
2641
+ var starTestDot = (f) => f.length !== 0 && f !== "." && f !== "..";
2642
+ var qmarksRE = /^\?+([^+@!?\*\[\(]*)?$/;
2643
+ var qmarksTestNocase = ([$0, ext = ""]) => {
2644
+ const noext = qmarksTestNoExt([$0]);
2645
+ if (!ext)
2646
+ return noext;
2647
+ ext = ext.toLowerCase();
2648
+ return (f) => noext(f) && f.toLowerCase().endsWith(ext);
2649
+ };
2650
+ var qmarksTestNocaseDot = ([$0, ext = ""]) => {
2651
+ const noext = qmarksTestNoExtDot([$0]);
2652
+ if (!ext)
2653
+ return noext;
2654
+ ext = ext.toLowerCase();
2655
+ return (f) => noext(f) && f.toLowerCase().endsWith(ext);
2656
+ };
2657
+ var qmarksTestDot = ([$0, ext = ""]) => {
2658
+ const noext = qmarksTestNoExtDot([$0]);
2659
+ return !ext ? noext : (f) => noext(f) && f.endsWith(ext);
2660
+ };
2661
+ var qmarksTest = ([$0, ext = ""]) => {
2662
+ const noext = qmarksTestNoExt([$0]);
2663
+ return !ext ? noext : (f) => noext(f) && f.endsWith(ext);
2664
+ };
2665
+ var qmarksTestNoExt = ([$0]) => {
2666
+ const len = $0.length;
2667
+ return (f) => f.length === len && !f.startsWith(".");
2668
+ };
2669
+ var qmarksTestNoExtDot = ([$0]) => {
2670
+ const len = $0.length;
2671
+ return (f) => f.length === len && f !== "." && f !== "..";
2672
+ };
2673
+ var defaultPlatform = typeof process === "object" && process ? typeof process.env === "object" && process.env && process.env.__MINIMATCH_TESTING_PLATFORM__ || process.platform : "posix";
2674
+ var path7 = {
2675
+ win32: { sep: "\\" },
2676
+ posix: { sep: "/" }
2677
+ };
2678
+ var sep = defaultPlatform === "win32" ? path7.win32.sep : path7.posix.sep;
2679
+ minimatch.sep = sep;
2680
+ var GLOBSTAR = Symbol("globstar **");
2681
+ minimatch.GLOBSTAR = GLOBSTAR;
2682
+ var qmark2 = "[^/]";
2683
+ var star2 = qmark2 + "*?";
2684
+ var twoStarDot = "(?:(?!(?:\\/|^)(?:\\.{1,2})($|\\/)).)*?";
2685
+ var twoStarNoDot = "(?:(?!(?:\\/|^)\\.).)*?";
2686
+ var filter = (pattern, options = {}) => (p) => minimatch(p, pattern, options);
2687
+ minimatch.filter = filter;
2688
+ var ext = (a, b = {}) => Object.assign({}, a, b);
2689
+ var defaults = (def) => {
2690
+ if (!def || typeof def !== "object" || !Object.keys(def).length) {
2691
+ return minimatch;
2692
+ }
2693
+ const orig = minimatch;
2694
+ const m = (p, pattern, options = {}) => orig(p, pattern, ext(def, options));
2695
+ return Object.assign(m, {
2696
+ Minimatch: class Minimatch extends orig.Minimatch {
2697
+ constructor(pattern, options = {}) {
2698
+ super(pattern, ext(def, options));
2699
+ }
2700
+ static defaults(options) {
2701
+ return orig.defaults(ext(def, options)).Minimatch;
2702
+ }
2703
+ },
2704
+ AST: class AST2 extends orig.AST {
2705
+ constructor(type, parent, options = {}) {
2706
+ super(type, parent, ext(def, options));
2707
+ }
2708
+ static fromGlob(pattern, options = {}) {
2709
+ return orig.AST.fromGlob(pattern, ext(def, options));
2710
+ }
2711
+ },
2712
+ unescape: (s, options = {}) => orig.unescape(s, ext(def, options)),
2713
+ escape: (s, options = {}) => orig.escape(s, ext(def, options)),
2714
+ filter: (pattern, options = {}) => orig.filter(pattern, ext(def, options)),
2715
+ defaults: (options) => orig.defaults(ext(def, options)),
2716
+ makeRe: (pattern, options = {}) => orig.makeRe(pattern, ext(def, options)),
2717
+ braceExpand: (pattern, options = {}) => orig.braceExpand(pattern, ext(def, options)),
2718
+ match: (list, pattern, options = {}) => orig.match(list, pattern, ext(def, options)),
2719
+ sep: orig.sep,
2720
+ GLOBSTAR
2721
+ });
2722
+ };
2723
+ minimatch.defaults = defaults;
2724
+ var braceExpand = (pattern, options = {}) => {
2725
+ assertValidPattern(pattern);
2726
+ if (options.nobrace || !/\{(?:(?!\{).)*\}/.test(pattern)) {
2727
+ return [pattern];
2728
+ }
2729
+ return expand(pattern);
2730
+ };
2731
+ minimatch.braceExpand = braceExpand;
2732
+ var makeRe = (pattern, options = {}) => new Minimatch(pattern, options).makeRe();
2733
+ minimatch.makeRe = makeRe;
2734
+ var match = (list, pattern, options = {}) => {
2735
+ const mm = new Minimatch(pattern, options);
2736
+ list = list.filter((f) => mm.match(f));
2737
+ if (mm.options.nonull && !list.length) {
2738
+ list.push(pattern);
2739
+ }
2740
+ return list;
2741
+ };
2742
+ minimatch.match = match;
2743
+ var globMagic = /[?*]|[+@!]\(.*?\)|\[|\]/;
2744
+ var regExpEscape2 = (s) => s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
2745
+
2746
+ class Minimatch {
2747
+ options;
2748
+ set;
2749
+ pattern;
2750
+ windowsPathsNoEscape;
2751
+ nonegate;
2752
+ negate;
2753
+ comment;
2754
+ empty;
2755
+ preserveMultipleSlashes;
2756
+ partial;
2757
+ globSet;
2758
+ globParts;
2759
+ nocase;
2760
+ isWindows;
2761
+ platform;
2762
+ windowsNoMagicRoot;
2763
+ regexp;
2764
+ constructor(pattern, options = {}) {
2765
+ assertValidPattern(pattern);
2766
+ options = options || {};
2767
+ this.options = options;
2768
+ this.pattern = pattern;
2769
+ this.platform = options.platform || defaultPlatform;
2770
+ this.isWindows = this.platform === "win32";
2771
+ this.windowsPathsNoEscape = !!options.windowsPathsNoEscape || options.allowWindowsEscape === false;
2772
+ if (this.windowsPathsNoEscape) {
2773
+ this.pattern = this.pattern.replace(/\\/g, "/");
2774
+ }
2775
+ this.preserveMultipleSlashes = !!options.preserveMultipleSlashes;
2776
+ this.regexp = null;
2777
+ this.negate = false;
2778
+ this.nonegate = !!options.nonegate;
2779
+ this.comment = false;
2780
+ this.empty = false;
2781
+ this.partial = !!options.partial;
2782
+ this.nocase = !!this.options.nocase;
2783
+ this.windowsNoMagicRoot = options.windowsNoMagicRoot !== undefined ? options.windowsNoMagicRoot : !!(this.isWindows && this.nocase);
2784
+ this.globSet = [];
2785
+ this.globParts = [];
2786
+ this.set = [];
2787
+ this.make();
2788
+ }
2789
+ hasMagic() {
2790
+ if (this.options.magicalBraces && this.set.length > 1) {
2791
+ return true;
2792
+ }
2793
+ for (const pattern of this.set) {
2794
+ for (const part of pattern) {
2795
+ if (typeof part !== "string")
2796
+ return true;
2797
+ }
2798
+ }
2799
+ return false;
2800
+ }
2801
+ debug(..._) {}
2802
+ make() {
2803
+ const pattern = this.pattern;
2804
+ const options = this.options;
2805
+ if (!options.nocomment && pattern.charAt(0) === "#") {
2806
+ this.comment = true;
2807
+ return;
2808
+ }
2809
+ if (!pattern) {
2810
+ this.empty = true;
2811
+ return;
2812
+ }
2813
+ this.parseNegate();
2814
+ this.globSet = [...new Set(this.braceExpand())];
2815
+ if (options.debug) {
2816
+ this.debug = (...args) => console.error(...args);
2817
+ }
2818
+ this.debug(this.pattern, this.globSet);
2819
+ const rawGlobParts = this.globSet.map((s) => this.slashSplit(s));
2820
+ this.globParts = this.preprocess(rawGlobParts);
2821
+ this.debug(this.pattern, this.globParts);
2822
+ let set = this.globParts.map((s, _, __) => {
2823
+ if (this.isWindows && this.windowsNoMagicRoot) {
2824
+ const isUNC = s[0] === "" && s[1] === "" && (s[2] === "?" || !globMagic.test(s[2])) && !globMagic.test(s[3]);
2825
+ const isDrive = /^[a-z]:/i.test(s[0]);
2826
+ if (isUNC) {
2827
+ return [...s.slice(0, 4), ...s.slice(4).map((ss) => this.parse(ss))];
2828
+ } else if (isDrive) {
2829
+ return [s[0], ...s.slice(1).map((ss) => this.parse(ss))];
2830
+ }
2831
+ }
2832
+ return s.map((ss) => this.parse(ss));
2833
+ });
2834
+ this.debug(this.pattern, set);
2835
+ this.set = set.filter((s) => s.indexOf(false) === -1);
2836
+ if (this.isWindows) {
2837
+ for (let i = 0;i < this.set.length; i++) {
2838
+ const p = this.set[i];
2839
+ if (p[0] === "" && p[1] === "" && this.globParts[i][2] === "?" && typeof p[3] === "string" && /^[a-z]:$/i.test(p[3])) {
2840
+ p[2] = "?";
2841
+ }
2842
+ }
2843
+ }
2844
+ this.debug(this.pattern, this.set);
2845
+ }
2846
+ preprocess(globParts) {
2847
+ if (this.options.noglobstar) {
2848
+ for (let i = 0;i < globParts.length; i++) {
2849
+ for (let j = 0;j < globParts[i].length; j++) {
2850
+ if (globParts[i][j] === "**") {
2851
+ globParts[i][j] = "*";
2852
+ }
2853
+ }
2854
+ }
2855
+ }
2856
+ const { optimizationLevel = 1 } = this.options;
2857
+ if (optimizationLevel >= 2) {
2858
+ globParts = this.firstPhasePreProcess(globParts);
2859
+ globParts = this.secondPhasePreProcess(globParts);
2860
+ } else if (optimizationLevel >= 1) {
2861
+ globParts = this.levelOneOptimize(globParts);
2862
+ } else {
2863
+ globParts = this.adjascentGlobstarOptimize(globParts);
2864
+ }
2865
+ return globParts;
2866
+ }
2867
+ adjascentGlobstarOptimize(globParts) {
2868
+ return globParts.map((parts) => {
2869
+ let gs = -1;
2870
+ while ((gs = parts.indexOf("**", gs + 1)) !== -1) {
2871
+ let i = gs;
2872
+ while (parts[i + 1] === "**") {
2873
+ i++;
2874
+ }
2875
+ if (i !== gs) {
2876
+ parts.splice(gs, i - gs);
2877
+ }
2878
+ }
2879
+ return parts;
2880
+ });
2881
+ }
2882
+ levelOneOptimize(globParts) {
2883
+ return globParts.map((parts) => {
2884
+ parts = parts.reduce((set, part) => {
2885
+ const prev = set[set.length - 1];
2886
+ if (part === "**" && prev === "**") {
2887
+ return set;
2888
+ }
2889
+ if (part === "..") {
2890
+ if (prev && prev !== ".." && prev !== "." && prev !== "**") {
2891
+ set.pop();
2892
+ return set;
2893
+ }
2894
+ }
2895
+ set.push(part);
2896
+ return set;
2897
+ }, []);
2898
+ return parts.length === 0 ? [""] : parts;
2899
+ });
2900
+ }
2901
+ levelTwoFileOptimize(parts) {
2902
+ if (!Array.isArray(parts)) {
2903
+ parts = this.slashSplit(parts);
2904
+ }
2905
+ let didSomething = false;
2906
+ do {
2907
+ didSomething = false;
2908
+ if (!this.preserveMultipleSlashes) {
2909
+ for (let i = 1;i < parts.length - 1; i++) {
2910
+ const p = parts[i];
2911
+ if (i === 1 && p === "" && parts[0] === "")
2912
+ continue;
2913
+ if (p === "." || p === "") {
2914
+ didSomething = true;
2915
+ parts.splice(i, 1);
2916
+ i--;
2917
+ }
2918
+ }
2919
+ if (parts[0] === "." && parts.length === 2 && (parts[1] === "." || parts[1] === "")) {
2920
+ didSomething = true;
2921
+ parts.pop();
2922
+ }
2923
+ }
2924
+ let dd = 0;
2925
+ while ((dd = parts.indexOf("..", dd + 1)) !== -1) {
2926
+ const p = parts[dd - 1];
2927
+ if (p && p !== "." && p !== ".." && p !== "**") {
2928
+ didSomething = true;
2929
+ parts.splice(dd - 1, 2);
2930
+ dd -= 2;
2931
+ }
2932
+ }
2933
+ } while (didSomething);
2934
+ return parts.length === 0 ? [""] : parts;
2935
+ }
2936
+ firstPhasePreProcess(globParts) {
2937
+ let didSomething = false;
2938
+ do {
2939
+ didSomething = false;
2940
+ for (let parts of globParts) {
2941
+ let gs = -1;
2942
+ while ((gs = parts.indexOf("**", gs + 1)) !== -1) {
2943
+ let gss = gs;
2944
+ while (parts[gss + 1] === "**") {
2945
+ gss++;
2946
+ }
2947
+ if (gss > gs) {
2948
+ parts.splice(gs + 1, gss - gs);
2949
+ }
2950
+ let next = parts[gs + 1];
2951
+ const p = parts[gs + 2];
2952
+ const p2 = parts[gs + 3];
2953
+ if (next !== "..")
2954
+ continue;
2955
+ if (!p || p === "." || p === ".." || !p2 || p2 === "." || p2 === "..") {
2956
+ continue;
2957
+ }
2958
+ didSomething = true;
2959
+ parts.splice(gs, 1);
2960
+ const other = parts.slice(0);
2961
+ other[gs] = "**";
2962
+ globParts.push(other);
2963
+ gs--;
2964
+ }
2965
+ if (!this.preserveMultipleSlashes) {
2966
+ for (let i = 1;i < parts.length - 1; i++) {
2967
+ const p = parts[i];
2968
+ if (i === 1 && p === "" && parts[0] === "")
2969
+ continue;
2970
+ if (p === "." || p === "") {
2971
+ didSomething = true;
2972
+ parts.splice(i, 1);
2973
+ i--;
2974
+ }
2975
+ }
2976
+ if (parts[0] === "." && parts.length === 2 && (parts[1] === "." || parts[1] === "")) {
2977
+ didSomething = true;
2978
+ parts.pop();
2979
+ }
2980
+ }
2981
+ let dd = 0;
2982
+ while ((dd = parts.indexOf("..", dd + 1)) !== -1) {
2983
+ const p = parts[dd - 1];
2984
+ if (p && p !== "." && p !== ".." && p !== "**") {
2985
+ didSomething = true;
2986
+ const needDot = dd === 1 && parts[dd + 1] === "**";
2987
+ const splin = needDot ? ["."] : [];
2988
+ parts.splice(dd - 1, 2, ...splin);
2989
+ if (parts.length === 0)
2990
+ parts.push("");
2991
+ dd -= 2;
2992
+ }
2993
+ }
2994
+ }
2995
+ } while (didSomething);
2996
+ return globParts;
2997
+ }
2998
+ secondPhasePreProcess(globParts) {
2999
+ for (let i = 0;i < globParts.length - 1; i++) {
3000
+ for (let j = i + 1;j < globParts.length; j++) {
3001
+ const matched = this.partsMatch(globParts[i], globParts[j], !this.preserveMultipleSlashes);
3002
+ if (matched) {
3003
+ globParts[i] = [];
3004
+ globParts[j] = matched;
3005
+ break;
3006
+ }
3007
+ }
3008
+ }
3009
+ return globParts.filter((gs) => gs.length);
3010
+ }
3011
+ partsMatch(a, b, emptyGSMatch = false) {
3012
+ let ai = 0;
3013
+ let bi = 0;
3014
+ let result = [];
3015
+ let which = "";
3016
+ while (ai < a.length && bi < b.length) {
3017
+ if (a[ai] === b[bi]) {
3018
+ result.push(which === "b" ? b[bi] : a[ai]);
3019
+ ai++;
3020
+ bi++;
3021
+ } else if (emptyGSMatch && a[ai] === "**" && b[bi] === a[ai + 1]) {
3022
+ result.push(a[ai]);
3023
+ ai++;
3024
+ } else if (emptyGSMatch && b[bi] === "**" && a[ai] === b[bi + 1]) {
3025
+ result.push(b[bi]);
3026
+ bi++;
3027
+ } else if (a[ai] === "*" && b[bi] && (this.options.dot || !b[bi].startsWith(".")) && b[bi] !== "**") {
3028
+ if (which === "b")
3029
+ return false;
3030
+ which = "a";
3031
+ result.push(a[ai]);
3032
+ ai++;
3033
+ bi++;
3034
+ } else if (b[bi] === "*" && a[ai] && (this.options.dot || !a[ai].startsWith(".")) && a[ai] !== "**") {
3035
+ if (which === "a")
3036
+ return false;
3037
+ which = "b";
3038
+ result.push(b[bi]);
3039
+ ai++;
3040
+ bi++;
3041
+ } else {
3042
+ return false;
3043
+ }
3044
+ }
3045
+ return a.length === b.length && result;
3046
+ }
3047
+ parseNegate() {
3048
+ if (this.nonegate)
3049
+ return;
3050
+ const pattern = this.pattern;
3051
+ let negate = false;
3052
+ let negateOffset = 0;
3053
+ for (let i = 0;i < pattern.length && pattern.charAt(i) === "!"; i++) {
3054
+ negate = !negate;
3055
+ negateOffset++;
3056
+ }
3057
+ if (negateOffset)
3058
+ this.pattern = pattern.slice(negateOffset);
3059
+ this.negate = negate;
3060
+ }
3061
+ matchOne(file, pattern, partial = false) {
3062
+ const options = this.options;
3063
+ if (this.isWindows) {
3064
+ const fileDrive = typeof file[0] === "string" && /^[a-z]:$/i.test(file[0]);
3065
+ const fileUNC = !fileDrive && file[0] === "" && file[1] === "" && file[2] === "?" && /^[a-z]:$/i.test(file[3]);
3066
+ const patternDrive = typeof pattern[0] === "string" && /^[a-z]:$/i.test(pattern[0]);
3067
+ const patternUNC = !patternDrive && pattern[0] === "" && pattern[1] === "" && pattern[2] === "?" && typeof pattern[3] === "string" && /^[a-z]:$/i.test(pattern[3]);
3068
+ const fdi = fileUNC ? 3 : fileDrive ? 0 : undefined;
3069
+ const pdi = patternUNC ? 3 : patternDrive ? 0 : undefined;
3070
+ if (typeof fdi === "number" && typeof pdi === "number") {
3071
+ const [fd, pd] = [file[fdi], pattern[pdi]];
3072
+ if (fd.toLowerCase() === pd.toLowerCase()) {
3073
+ pattern[pdi] = fd;
3074
+ if (pdi > fdi) {
3075
+ pattern = pattern.slice(pdi);
3076
+ } else if (fdi > pdi) {
3077
+ file = file.slice(fdi);
3078
+ }
3079
+ }
3080
+ }
3081
+ }
3082
+ const { optimizationLevel = 1 } = this.options;
3083
+ if (optimizationLevel >= 2) {
3084
+ file = this.levelTwoFileOptimize(file);
3085
+ }
3086
+ this.debug("matchOne", this, { file, pattern });
3087
+ this.debug("matchOne", file.length, pattern.length);
3088
+ for (var fi = 0, pi = 0, fl = file.length, pl = pattern.length;fi < fl && pi < pl; fi++, pi++) {
3089
+ this.debug("matchOne loop");
3090
+ var p = pattern[pi];
3091
+ var f = file[fi];
3092
+ this.debug(pattern, p, f);
3093
+ if (p === false) {
3094
+ return false;
3095
+ }
3096
+ if (p === GLOBSTAR) {
3097
+ this.debug("GLOBSTAR", [pattern, p, f]);
3098
+ var fr = fi;
3099
+ var pr = pi + 1;
3100
+ if (pr === pl) {
3101
+ this.debug("** at the end");
3102
+ for (;fi < fl; fi++) {
3103
+ if (file[fi] === "." || file[fi] === ".." || !options.dot && file[fi].charAt(0) === ".")
3104
+ return false;
3105
+ }
3106
+ return true;
3107
+ }
3108
+ while (fr < fl) {
3109
+ var swallowee = file[fr];
3110
+ this.debug(`
3111
+ globstar while`, file, fr, pattern, pr, swallowee);
3112
+ if (this.matchOne(file.slice(fr), pattern.slice(pr), partial)) {
3113
+ this.debug("globstar found match!", fr, fl, swallowee);
3114
+ return true;
3115
+ } else {
3116
+ if (swallowee === "." || swallowee === ".." || !options.dot && swallowee.charAt(0) === ".") {
3117
+ this.debug("dot detected!", file, fr, pattern, pr);
3118
+ break;
3119
+ }
3120
+ this.debug("globstar swallow a segment, and continue");
3121
+ fr++;
3122
+ }
3123
+ }
3124
+ if (partial) {
3125
+ this.debug(`
3126
+ >>> no match, partial?`, file, fr, pattern, pr);
3127
+ if (fr === fl) {
3128
+ return true;
3129
+ }
3130
+ }
3131
+ return false;
3132
+ }
3133
+ let hit;
3134
+ if (typeof p === "string") {
3135
+ hit = f === p;
3136
+ this.debug("string match", p, f, hit);
3137
+ } else {
3138
+ hit = p.test(f);
3139
+ this.debug("pattern match", p, f, hit);
3140
+ }
3141
+ if (!hit)
3142
+ return false;
3143
+ }
3144
+ if (fi === fl && pi === pl) {
3145
+ return true;
3146
+ } else if (fi === fl) {
3147
+ return partial;
3148
+ } else if (pi === pl) {
3149
+ return fi === fl - 1 && file[fi] === "";
3150
+ } else {
3151
+ throw new Error("wtf?");
3152
+ }
3153
+ }
3154
+ braceExpand() {
3155
+ return braceExpand(this.pattern, this.options);
3156
+ }
3157
+ parse(pattern) {
3158
+ assertValidPattern(pattern);
3159
+ const options = this.options;
3160
+ if (pattern === "**")
3161
+ return GLOBSTAR;
3162
+ if (pattern === "")
3163
+ return "";
3164
+ let m;
3165
+ let fastTest = null;
3166
+ if (m = pattern.match(starRE)) {
3167
+ fastTest = options.dot ? starTestDot : starTest;
3168
+ } else if (m = pattern.match(starDotExtRE)) {
3169
+ fastTest = (options.nocase ? options.dot ? starDotExtTestNocaseDot : starDotExtTestNocase : options.dot ? starDotExtTestDot : starDotExtTest)(m[1]);
3170
+ } else if (m = pattern.match(qmarksRE)) {
3171
+ fastTest = (options.nocase ? options.dot ? qmarksTestNocaseDot : qmarksTestNocase : options.dot ? qmarksTestDot : qmarksTest)(m);
3172
+ } else if (m = pattern.match(starDotStarRE)) {
3173
+ fastTest = options.dot ? starDotStarTestDot : starDotStarTest;
3174
+ } else if (m = pattern.match(dotStarRE)) {
3175
+ fastTest = dotStarTest;
3176
+ }
3177
+ const re = AST.fromGlob(pattern, this.options).toMMPattern();
3178
+ if (fastTest && typeof re === "object") {
3179
+ Reflect.defineProperty(re, "test", { value: fastTest });
3180
+ }
3181
+ return re;
3182
+ }
3183
+ makeRe() {
3184
+ if (this.regexp || this.regexp === false)
3185
+ return this.regexp;
3186
+ const set = this.set;
3187
+ if (!set.length) {
3188
+ this.regexp = false;
3189
+ return this.regexp;
3190
+ }
3191
+ const options = this.options;
3192
+ const twoStar = options.noglobstar ? star2 : options.dot ? twoStarDot : twoStarNoDot;
3193
+ const flags = new Set(options.nocase ? ["i"] : []);
3194
+ let re = set.map((pattern) => {
3195
+ const pp = pattern.map((p) => {
3196
+ if (p instanceof RegExp) {
3197
+ for (const f of p.flags.split(""))
3198
+ flags.add(f);
3199
+ }
3200
+ return typeof p === "string" ? regExpEscape2(p) : p === GLOBSTAR ? GLOBSTAR : p._src;
3201
+ });
3202
+ pp.forEach((p, i) => {
3203
+ const next = pp[i + 1];
3204
+ const prev = pp[i - 1];
3205
+ if (p !== GLOBSTAR || prev === GLOBSTAR) {
3206
+ return;
3207
+ }
3208
+ if (prev === undefined) {
3209
+ if (next !== undefined && next !== GLOBSTAR) {
3210
+ pp[i + 1] = "(?:\\/|" + twoStar + "\\/)?" + next;
3211
+ } else {
3212
+ pp[i] = twoStar;
3213
+ }
3214
+ } else if (next === undefined) {
3215
+ pp[i - 1] = prev + "(?:\\/|\\/" + twoStar + ")?";
3216
+ } else if (next !== GLOBSTAR) {
3217
+ pp[i - 1] = prev + "(?:\\/|\\/" + twoStar + "\\/)" + next;
3218
+ pp[i + 1] = GLOBSTAR;
3219
+ }
3220
+ });
3221
+ const filtered = pp.filter((p) => p !== GLOBSTAR);
3222
+ if (this.partial && filtered.length >= 1) {
3223
+ const prefixes = [];
3224
+ for (let i = 1;i <= filtered.length; i++) {
3225
+ prefixes.push(filtered.slice(0, i).join("/"));
3226
+ }
3227
+ return "(?:" + prefixes.join("|") + ")";
3228
+ }
3229
+ return filtered.join("/");
3230
+ }).join("|");
3231
+ const [open, close] = set.length > 1 ? ["(?:", ")"] : ["", ""];
3232
+ re = "^" + open + re + close + "$";
3233
+ if (this.partial) {
3234
+ re = "^(?:\\/|" + open + re.slice(1, -1) + close + ")$";
3235
+ }
3236
+ if (this.negate)
3237
+ re = "^(?!" + re + ").+$";
3238
+ try {
3239
+ this.regexp = new RegExp(re, [...flags].join(""));
3240
+ } catch (ex) {
3241
+ this.regexp = false;
3242
+ }
3243
+ return this.regexp;
3244
+ }
3245
+ slashSplit(p) {
3246
+ if (this.preserveMultipleSlashes) {
3247
+ return p.split("/");
3248
+ } else if (this.isWindows && /^\/\/[^\/]+/.test(p)) {
3249
+ return ["", ...p.split(/\/+/)];
3250
+ } else {
3251
+ return p.split(/\/+/);
3252
+ }
3253
+ }
3254
+ match(f, partial = this.partial) {
3255
+ this.debug("match", f, this.pattern);
3256
+ if (this.comment) {
3257
+ return false;
3258
+ }
3259
+ if (this.empty) {
3260
+ return f === "";
3261
+ }
3262
+ if (f === "/" && partial) {
3263
+ return true;
3264
+ }
3265
+ const options = this.options;
3266
+ if (this.isWindows) {
3267
+ f = f.split("\\").join("/");
3268
+ }
3269
+ const ff = this.slashSplit(f);
3270
+ this.debug(this.pattern, "split", ff);
3271
+ const set = this.set;
3272
+ this.debug(this.pattern, "set", set);
3273
+ let filename = ff[ff.length - 1];
3274
+ if (!filename) {
3275
+ for (let i = ff.length - 2;!filename && i >= 0; i--) {
3276
+ filename = ff[i];
3277
+ }
3278
+ }
3279
+ for (let i = 0;i < set.length; i++) {
3280
+ const pattern = set[i];
3281
+ let file = ff;
3282
+ if (options.matchBase && pattern.length === 1) {
3283
+ file = [filename];
3284
+ }
3285
+ const hit = this.matchOne(file, pattern, partial);
3286
+ if (hit) {
3287
+ if (options.flipNegate) {
3288
+ return true;
3289
+ }
3290
+ return !this.negate;
3291
+ }
3292
+ }
3293
+ if (options.flipNegate) {
3294
+ return false;
3295
+ }
3296
+ return this.negate;
3297
+ }
3298
+ static defaults(def) {
3299
+ return minimatch.defaults(def).Minimatch;
3300
+ }
3301
+ }
3302
+ minimatch.AST = AST;
3303
+ minimatch.Minimatch = Minimatch;
3304
+ minimatch.escape = escape;
3305
+ minimatch.unescape = unescape;
3306
+
3307
+ // src/commands/check/github-fetcher.ts
3308
+ var DEFAULT_TIMEOUT2 = 15000;
3309
+ var DEFAULT_TTL3 = 60 * 60 * 1000;
3310
+ function getGitHubToken() {
3311
+ return process.env.GITHUB_TOKEN || process.env.GH_TOKEN;
3312
+ }
3313
+ function buildHeaders() {
3314
+ const headers = {
3315
+ Accept: "application/vnd.github.v3+json",
3316
+ "User-Agent": "doccov-cli"
3317
+ };
3318
+ const token = getGitHubToken();
3319
+ if (token) {
3320
+ headers.Authorization = `Bearer ${token}`;
3321
+ }
3322
+ return headers;
3323
+ }
3324
+ async function fetchFileTree(owner, repo, ref, timeout) {
3325
+ const url = `https://api.github.com/repos/${owner}/${repo}/git/trees/${ref}?recursive=1`;
3326
+ const controller = new AbortController;
3327
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
3328
+ try {
3329
+ const response = await fetch(url, {
3330
+ signal: controller.signal,
3331
+ headers: buildHeaders()
3332
+ });
3333
+ clearTimeout(timeoutId);
3334
+ if (!response.ok) {
3335
+ if (response.status === 401 || response.status === 403) {
3336
+ throw new Error(`GitHub API auth error (${response.status}). Set GITHUB_TOKEN for private repos or higher rate limits.`);
3337
+ }
3338
+ if (response.status === 404) {
3339
+ throw new Error(`GitHub repo not found: ${owner}/${repo}@${ref}`);
3340
+ }
3341
+ throw new Error(`GitHub API error: ${response.status} ${response.statusText}`);
3342
+ }
3343
+ return response.json();
3344
+ } catch (err) {
3345
+ clearTimeout(timeoutId);
3346
+ if (err instanceof Error && err.name === "AbortError") {
3347
+ throw new Error(`GitHub API timeout after ${timeout}ms`);
3348
+ }
3349
+ throw err;
3350
+ }
3351
+ }
3352
+ async function fetchRawContent(owner, repo, ref, path8, timeout) {
3353
+ const url = `https://raw.githubusercontent.com/${owner}/${repo}/${ref}/${path8}`;
3354
+ const controller = new AbortController;
3355
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
3356
+ try {
3357
+ const response = await fetch(url, {
3358
+ signal: controller.signal,
3359
+ headers: {
3360
+ "User-Agent": "doccov-cli",
3361
+ ...getGitHubToken() ? { Authorization: `Bearer ${getGitHubToken()}` } : {}
3362
+ }
3363
+ });
3364
+ clearTimeout(timeoutId);
3365
+ if (!response.ok) {
3366
+ throw new Error(`Failed to fetch ${path8}: ${response.status}`);
3367
+ }
3368
+ return response.text();
3369
+ } catch (err) {
3370
+ clearTimeout(timeoutId);
3371
+ if (err instanceof Error && err.name === "AbortError") {
3372
+ throw new Error(`Timeout fetching ${path8}`);
3373
+ }
3374
+ throw err;
3375
+ }
3376
+ }
3377
+ function matchGlob(files, pattern) {
3378
+ const glob2 = pattern || "**/*.md";
3379
+ return files.filter((file) => minimatch(file, glob2, { matchBase: true }));
3380
+ }
3381
+ function parseMarkdownContent2(content, sourcePath) {
3382
+ const codeBlocks = [];
3383
+ const lines = content.split(`
3384
+ `);
3385
+ let inBlock = false;
3386
+ let blockLang = "";
3387
+ let blockCode = [];
3388
+ let blockStart = 0;
3389
+ const executableLangs = new Set(["ts", "typescript", "js", "javascript", "tsx", "jsx", "mts", "mjs"]);
3390
+ for (let i = 0;i < lines.length; i++) {
3391
+ const line = lines[i];
3392
+ if (!inBlock && line.startsWith("```")) {
3393
+ inBlock = true;
3394
+ blockLang = line.slice(3).trim().split(/\s/)[0] || "";
3395
+ blockCode = [];
3396
+ blockStart = i + 1;
3397
+ } else if (inBlock && line.startsWith("```")) {
3398
+ const normalizedLang = normalizeLang(blockLang);
3399
+ if (executableLangs.has(normalizedLang.toLowerCase())) {
3400
+ codeBlocks.push({
3401
+ lang: normalizedLang || "ts",
3402
+ code: blockCode.join(`
3403
+ `),
3404
+ lineStart: blockStart,
3405
+ lineEnd: i
3406
+ });
3407
+ }
3408
+ inBlock = false;
3409
+ blockLang = "";
3410
+ blockCode = [];
3411
+ } else if (inBlock) {
3412
+ blockCode.push(line);
3413
+ }
3414
+ }
3415
+ return { path: sourcePath, codeBlocks };
3416
+ }
3417
+ function normalizeLang(lang) {
3418
+ const aliases = {
3419
+ typescript: "ts",
3420
+ javascript: "js",
3421
+ tsx: "tsx",
3422
+ jsx: "jsx"
3423
+ };
3424
+ return aliases[lang.toLowerCase()] ?? lang;
3425
+ }
3426
+ function getCacheKey(source) {
3427
+ return `${source.org}/${source.repo}/${source.path ?? "**/*.md"}#${source.branch ?? "HEAD"}`;
3428
+ }
3429
+ async function fetchGitHubDocs(source, options = {}) {
3430
+ const {
3431
+ timeout = DEFAULT_TIMEOUT2,
3432
+ ttl = DEFAULT_TTL3,
3433
+ useCache = true,
3434
+ cwd = process.cwd()
3435
+ } = options;
3436
+ const cacheKey = getCacheKey(source);
3437
+ if (useCache) {
3438
+ const cached = getFromCache(cwd, "github", cacheKey, ttl);
3439
+ if (cached) {
3440
+ try {
3441
+ const docs = JSON.parse(cached.content);
3442
+ return { source, docs, cached: true };
3443
+ } catch {}
3444
+ }
3445
+ }
3446
+ try {
3447
+ const ref = source.branch ?? "HEAD";
3448
+ const tree = await fetchFileTree(source.org, source.repo, ref, timeout);
3449
+ const allPaths = tree.tree.filter((item) => item.type === "blob").map((item) => item.path);
3450
+ const mdPaths = matchGlob(allPaths, source.path ?? "**/*.md").filter((p) => p.endsWith(".md") || p.endsWith(".mdx"));
3451
+ if (mdPaths.length === 0) {
3452
+ return { source, docs: [] };
3453
+ }
3454
+ const docs = [];
3455
+ const BATCH_SIZE = 5;
3456
+ for (let i = 0;i < mdPaths.length; i += BATCH_SIZE) {
3457
+ const batch = mdPaths.slice(i, i + BATCH_SIZE);
3458
+ const results = await Promise.all(batch.map(async (filePath) => {
3459
+ try {
3460
+ const content = await fetchRawContent(source.org, source.repo, ref, filePath, timeout);
3461
+ const sourcePath = `github:${source.org}/${source.repo}/${filePath}`;
3462
+ return parseMarkdownContent2(content, sourcePath);
3463
+ } catch {
3464
+ return null;
3465
+ }
3466
+ }));
3467
+ for (const doc of results) {
3468
+ if (doc && doc.codeBlocks.length > 0) {
3469
+ docs.push(doc);
3470
+ }
3471
+ }
3472
+ }
3473
+ if (useCache) {
3474
+ writeToCache(cwd, "github", cacheKey, JSON.stringify(docs));
3475
+ }
3476
+ return { source, docs };
3477
+ } catch (err) {
3478
+ const message = err instanceof Error ? err.message : String(err);
3479
+ return { source, docs: [], error: message };
3480
+ }
3481
+ }
3482
+ async function fetchGitHubDocsBatch(sources, options = {}) {
3483
+ const results = [];
3484
+ for (const source of sources) {
3485
+ results.push(await fetchGitHubDocs(source, options));
3486
+ }
3487
+ return results;
3488
+ }
3489
+
3490
+ // src/commands/check/parseDocsPattern.ts
3491
+ function parseDocsPattern(pattern) {
3492
+ if (/^https?:\/\//i.test(pattern)) {
3493
+ return { type: "url", url: pattern };
3494
+ }
3495
+ if (/^(github|gh):/i.test(pattern)) {
3496
+ return parseGitHubPattern(pattern);
3497
+ }
3498
+ if (/^(gitlab|gl):/i.test(pattern)) {
3499
+ return parseGitLabPattern(pattern);
3500
+ }
3501
+ return { type: "local", pattern };
3502
+ }
3503
+ function parseGitHubPattern(pattern) {
3504
+ const rest = pattern.replace(/^(github|gh):/i, "");
3505
+ const [pathPart, branch] = rest.split("#");
3506
+ const parts = pathPart.split("/");
3507
+ if (parts.length < 2) {
3508
+ throw new Error(`Invalid GitHub pattern: ${pattern}. Expected format: github:org/repo[/path][#branch]`);
3509
+ }
3510
+ const org = parts[0];
3511
+ const repo = parts[1];
3512
+ const path8 = parts.length > 2 ? parts.slice(2).join("/") : undefined;
3513
+ return {
3514
+ type: "github",
3515
+ org,
3516
+ repo,
3517
+ ...path8 && { path: path8 },
3518
+ ...branch && { branch }
3519
+ };
3520
+ }
3521
+ function parseGitLabPattern(pattern) {
3522
+ const rest = pattern.replace(/^(gitlab|gl):/i, "");
3523
+ const [pathPart, branch] = rest.split("#");
3524
+ const parts = pathPart.split("/");
3525
+ if (parts.length < 2) {
3526
+ throw new Error(`Invalid GitLab pattern: ${pattern}. Expected format: gitlab:org/repo[/path][#branch]`);
3527
+ }
3528
+ const org = parts[0];
3529
+ const repo = parts[1];
3530
+ const path8 = parts.length > 2 ? parts.slice(2).join("/") : undefined;
3531
+ return {
3532
+ type: "gitlab",
3533
+ org,
3534
+ repo,
3535
+ ...path8 && { path: path8 },
3536
+ ...branch && { branch }
3537
+ };
3538
+ }
3539
+ function parseDocsPatterns(patterns) {
3540
+ return patterns.map(parseDocsPattern);
3541
+ }
3542
+
3543
+ // src/commands/check/validation.ts
1653
3544
  async function runExampleValidation(openpkg, options) {
1654
3545
  const { validations, targetDir, timeout = 5000, installTimeout = 60000 } = options;
1655
3546
  const typecheckErrors = [];
@@ -1682,18 +3573,62 @@ async function runExampleValidation(openpkg, options) {
1682
3573
  }
1683
3574
  return { result, typecheckErrors, runtimeDrifts };
1684
3575
  }
3576
+ function parseAndSeparateDocsSources(patterns) {
3577
+ const sources = parseDocsPatterns(patterns);
3578
+ const local = [];
3579
+ const remote = [];
3580
+ for (const source of sources) {
3581
+ if (source.type === "local") {
3582
+ local.push(source.pattern);
3583
+ } else {
3584
+ remote.push(source);
3585
+ }
3586
+ }
3587
+ return { local, remote };
3588
+ }
1685
3589
  async function validateMarkdownDocs(options) {
1686
- const { docsPatterns, targetDir, exportNames } = options;
3590
+ const { docsPatterns, targetDir, exportNames, useCache = true, fetchTimeout, cacheTtl } = options;
1687
3591
  const staleRefs = [];
1688
3592
  if (docsPatterns.length === 0) {
1689
3593
  return staleRefs;
1690
3594
  }
1691
- const markdownFiles = await loadMarkdownFiles(docsPatterns, targetDir);
1692
- if (markdownFiles.length === 0) {
3595
+ const { local, remote } = parseAndSeparateDocsSources(docsPatterns);
3596
+ const allDocs = [];
3597
+ if (local.length > 0) {
3598
+ const localDocs = await loadMarkdownFiles(local, targetDir);
3599
+ allDocs.push(...localDocs);
3600
+ }
3601
+ const urlSources = remote.filter((s) => s.type === "url");
3602
+ if (urlSources.length > 0) {
3603
+ const results = await fetchUrlDocsBatch(urlSources, {
3604
+ useCache,
3605
+ timeout: fetchTimeout,
3606
+ ttl: cacheTtl,
3607
+ cwd: targetDir
3608
+ });
3609
+ for (const result of results) {
3610
+ if (result.doc) {
3611
+ allDocs.push(result.doc);
3612
+ }
3613
+ }
3614
+ }
3615
+ const githubSources = remote.filter((s) => s.type === "github");
3616
+ if (githubSources.length > 0) {
3617
+ const results = await fetchGitHubDocsBatch(githubSources, {
3618
+ useCache,
3619
+ timeout: fetchTimeout,
3620
+ ttl: cacheTtl,
3621
+ cwd: targetDir
3622
+ });
3623
+ for (const result of results) {
3624
+ allDocs.push(...result.docs);
3625
+ }
3626
+ }
3627
+ if (allDocs.length === 0) {
1693
3628
  return staleRefs;
1694
3629
  }
1695
3630
  const exportSet = new Set(exportNames);
1696
- for (const mdFile of markdownFiles) {
3631
+ for (const mdFile of allDocs) {
1697
3632
  for (const block of mdFile.codeBlocks) {
1698
3633
  const codeLines = block.code.split(`
1699
3634
  `);
@@ -1885,8 +3820,8 @@ function registerCheckCommand(program, dependencies = {}) {
1885
3820
  });
1886
3821
  }
1887
3822
  // src/commands/diff.ts
1888
- import * as fs4 from "node:fs";
1889
- import * as path6 from "node:path";
3823
+ import * as fs5 from "node:fs";
3824
+ import * as path8 from "node:path";
1890
3825
  import {
1891
3826
  diffSpecWithDocs,
1892
3827
  ensureSpecCoverage,
@@ -1900,7 +3835,7 @@ import { calculateNextVersion, recommendSemverBump } from "@openpkg-ts/spec";
1900
3835
  import chalk7 from "chalk";
1901
3836
  import { glob as glob2 } from "glob";
1902
3837
  var defaultDependencies2 = {
1903
- readFileSync: fs4.readFileSync,
3838
+ readFileSync: fs5.readFileSync,
1904
3839
  log: console.log,
1905
3840
  error: console.error
1906
3841
  };
@@ -1919,7 +3854,7 @@ function getStrictChecks(preset) {
1919
3854
  return checks;
1920
3855
  }
1921
3856
  function registerDiffCommand(program, dependencies = {}) {
1922
- const { readFileSync: readFileSync3, log, error } = {
3857
+ const { readFileSync: readFileSync4, log, error } = {
1923
3858
  ...defaultDependencies2,
1924
3859
  ...dependencies
1925
3860
  };
@@ -1933,18 +3868,18 @@ function registerDiffCommand(program, dependencies = {}) {
1933
3868
  ` + " or: doccov diff --base main.json --head feature.json");
1934
3869
  }
1935
3870
  const spin = spinner("Comparing specs...");
1936
- const baseSpec = loadSpec(baseFile, readFileSync3);
1937
- const headSpec = loadSpec(headFile, readFileSync3);
3871
+ const baseSpec = loadSpec(baseFile, readFileSync4);
3872
+ const headSpec = loadSpec(headFile, readFileSync4);
1938
3873
  const config = await loadDocCovConfig(options.cwd);
1939
3874
  const baseHash = hashString(JSON.stringify(baseSpec));
1940
3875
  const headHash = hashString(JSON.stringify(headSpec));
1941
3876
  const cacheEnabled = options.cache !== false;
1942
- const cachedReportPath = path6.resolve(options.cwd, getDiffReportPath(baseHash, headHash, "json"));
3877
+ const cachedReportPath = path8.resolve(options.cwd, getDiffReportPath(baseHash, headHash, "json"));
1943
3878
  let diff;
1944
3879
  let fromCache = false;
1945
- if (cacheEnabled && fs4.existsSync(cachedReportPath)) {
3880
+ if (cacheEnabled && fs5.existsSync(cachedReportPath)) {
1946
3881
  try {
1947
- const cached = JSON.parse(fs4.readFileSync(cachedReportPath, "utf-8"));
3882
+ const cached = JSON.parse(fs5.readFileSync(cachedReportPath, "utf-8"));
1948
3883
  diff = cached;
1949
3884
  fromCache = true;
1950
3885
  } catch {
@@ -1982,8 +3917,8 @@ function registerDiffCommand(program, dependencies = {}) {
1982
3917
  const format = options.format ?? "text";
1983
3918
  const limit = parseInt(options.limit, 10) || 10;
1984
3919
  const checks = getStrictChecks(options.strict);
1985
- const baseName = path6.basename(baseFile);
1986
- const headName = path6.basename(headFile);
3920
+ const baseName = path8.basename(baseFile);
3921
+ const headName = path8.basename(headFile);
1987
3922
  const reportData = {
1988
3923
  baseName,
1989
3924
  headName,
@@ -2088,7 +4023,7 @@ async function loadMarkdownFiles2(patterns) {
2088
4023
  const matches = await glob2(pattern, { nodir: true });
2089
4024
  for (const filePath of matches) {
2090
4025
  try {
2091
- const content = fs4.readFileSync(filePath, "utf-8");
4026
+ const content = fs5.readFileSync(filePath, "utf-8");
2092
4027
  files.push({ path: filePath, content });
2093
4028
  } catch {}
2094
4029
  }
@@ -2109,13 +4044,13 @@ async function generateDiff(baseSpec, headSpec, options, config, log) {
2109
4044
  }
2110
4045
  return diffSpecWithDocs(baseSpec, headSpec, { markdownFiles });
2111
4046
  }
2112
- function loadSpec(filePath, readFileSync3) {
2113
- const resolvedPath = path6.resolve(filePath);
2114
- if (!fs4.existsSync(resolvedPath)) {
4047
+ function loadSpec(filePath, readFileSync4) {
4048
+ const resolvedPath = path8.resolve(filePath);
4049
+ if (!fs5.existsSync(resolvedPath)) {
2115
4050
  throw new Error(`File not found: ${filePath}`);
2116
4051
  }
2117
4052
  try {
2118
- const content = readFileSync3(resolvedPath, "utf-8");
4053
+ const content = readFileSync4(resolvedPath, "utf-8");
2119
4054
  const spec = JSON.parse(content);
2120
4055
  return ensureSpecCoverage(spec);
2121
4056
  } catch (parseError) {
@@ -2235,34 +4170,34 @@ function printGitHubAnnotations(diff, log) {
2235
4170
  }
2236
4171
 
2237
4172
  // src/commands/init.ts
2238
- import * as fs5 from "node:fs";
2239
- import * as path7 from "node:path";
4173
+ import * as fs6 from "node:fs";
4174
+ import * as path9 from "node:path";
2240
4175
  import chalk8 from "chalk";
2241
4176
  var defaultDependencies3 = {
2242
- fileExists: fs5.existsSync,
2243
- writeFileSync: fs5.writeFileSync,
2244
- readFileSync: fs5.readFileSync,
2245
- mkdirSync: fs5.mkdirSync,
4177
+ fileExists: fs6.existsSync,
4178
+ writeFileSync: fs6.writeFileSync,
4179
+ readFileSync: fs6.readFileSync,
4180
+ mkdirSync: fs6.mkdirSync,
2246
4181
  log: console.log,
2247
4182
  error: console.error
2248
4183
  };
2249
4184
  function registerInitCommand(program, dependencies = {}) {
2250
- const { fileExists: fileExists2, writeFileSync: writeFileSync3, readFileSync: readFileSync4, mkdirSync: mkdirSync3, log, error } = {
4185
+ const { fileExists: fileExists2, writeFileSync: writeFileSync4, readFileSync: readFileSync5, mkdirSync: mkdirSync4, log, error } = {
2251
4186
  ...defaultDependencies3,
2252
4187
  ...dependencies
2253
4188
  };
2254
4189
  program.command("init").description("Initialize DocCov: config, GitHub Action, and badge").option("--cwd <dir>", "Working directory", process.cwd()).option("--skip-action", "Skip GitHub Action workflow creation").action((options) => {
2255
- const cwd = path7.resolve(options.cwd);
4190
+ const cwd = path9.resolve(options.cwd);
2256
4191
  const existing = findExistingConfig(cwd, fileExists2);
2257
4192
  if (existing) {
2258
- error(chalk8.red(`A DocCov config already exists at ${path7.relative(cwd, existing) || "./doccov.config.*"}.`));
4193
+ error(chalk8.red(`A DocCov config already exists at ${path9.relative(cwd, existing) || "./doccov.config.*"}.`));
2259
4194
  process.exitCode = 1;
2260
4195
  return;
2261
4196
  }
2262
- const packageType = detectPackageType(cwd, fileExists2, readFileSync4);
4197
+ const packageType = detectPackageType(cwd, fileExists2, readFileSync5);
2263
4198
  const targetFormat = packageType === "module" ? "ts" : "mts";
2264
4199
  const fileName = `doccov.config.${targetFormat}`;
2265
- const outputPath = path7.join(cwd, fileName);
4200
+ const outputPath = path9.join(cwd, fileName);
2266
4201
  if (fileExists2(outputPath)) {
2267
4202
  error(chalk8.red(`Cannot create ${fileName}; file already exists.`));
2268
4203
  process.exitCode = 1;
@@ -2270,20 +4205,20 @@ function registerInitCommand(program, dependencies = {}) {
2270
4205
  }
2271
4206
  const sym = getSymbols(supportsUnicode());
2272
4207
  const template = buildConfigTemplate();
2273
- writeFileSync3(outputPath, template, { encoding: "utf8" });
4208
+ writeFileSync4(outputPath, template, { encoding: "utf8" });
2274
4209
  log(colors.success(`${sym.success} Created ${fileName}`));
2275
4210
  if (!options.skipAction) {
2276
- const workflowDir = path7.join(cwd, ".github", "workflows");
2277
- const workflowPath = path7.join(workflowDir, "doccov.yml");
4211
+ const workflowDir = path9.join(cwd, ".github", "workflows");
4212
+ const workflowPath = path9.join(workflowDir, "doccov.yml");
2278
4213
  if (!fileExists2(workflowPath)) {
2279
- mkdirSync3(workflowDir, { recursive: true });
2280
- writeFileSync3(workflowPath, buildWorkflowTemplate(), { encoding: "utf8" });
4214
+ mkdirSync4(workflowDir, { recursive: true });
4215
+ writeFileSync4(workflowPath, buildWorkflowTemplate(), { encoding: "utf8" });
2281
4216
  log(colors.success(`${sym.success} Created .github/workflows/doccov.yml`));
2282
4217
  } else {
2283
4218
  log(colors.warning(`${sym.bullet} Skipped .github/workflows/doccov.yml (already exists)`));
2284
4219
  }
2285
4220
  }
2286
- const repoInfo = detectRepoInfo(cwd, fileExists2, readFileSync4);
4221
+ const repoInfo = detectRepoInfo(cwd, fileExists2, readFileSync5);
2287
4222
  log("");
2288
4223
  log(chalk8.bold("Add this badge to your README:"));
2289
4224
  log("");
@@ -2298,11 +4233,11 @@ function registerInitCommand(program, dependencies = {}) {
2298
4233
  });
2299
4234
  }
2300
4235
  var findExistingConfig = (cwd, fileExists2) => {
2301
- let current = path7.resolve(cwd);
2302
- const { root } = path7.parse(current);
4236
+ let current = path9.resolve(cwd);
4237
+ const { root } = path9.parse(current);
2303
4238
  while (true) {
2304
4239
  for (const candidate of DOCCOV_CONFIG_FILENAMES) {
2305
- const candidatePath = path7.join(current, candidate);
4240
+ const candidatePath = path9.join(current, candidate);
2306
4241
  if (fileExists2(candidatePath)) {
2307
4242
  return candidatePath;
2308
4243
  }
@@ -2310,17 +4245,17 @@ var findExistingConfig = (cwd, fileExists2) => {
2310
4245
  if (current === root) {
2311
4246
  break;
2312
4247
  }
2313
- current = path7.dirname(current);
4248
+ current = path9.dirname(current);
2314
4249
  }
2315
4250
  return null;
2316
4251
  };
2317
- var detectPackageType = (cwd, fileExists2, readFileSync4) => {
4252
+ var detectPackageType = (cwd, fileExists2, readFileSync5) => {
2318
4253
  const packageJsonPath = findNearestPackageJson(cwd, fileExists2);
2319
4254
  if (!packageJsonPath) {
2320
4255
  return;
2321
4256
  }
2322
4257
  try {
2323
- const raw = readFileSync4(packageJsonPath, "utf8");
4258
+ const raw = readFileSync5(packageJsonPath, "utf8");
2324
4259
  const parsed = JSON.parse(raw);
2325
4260
  if (parsed.type === "module") {
2326
4261
  return "module";
@@ -2332,17 +4267,17 @@ var detectPackageType = (cwd, fileExists2, readFileSync4) => {
2332
4267
  return;
2333
4268
  };
2334
4269
  var findNearestPackageJson = (cwd, fileExists2) => {
2335
- let current = path7.resolve(cwd);
2336
- const { root } = path7.parse(current);
4270
+ let current = path9.resolve(cwd);
4271
+ const { root } = path9.parse(current);
2337
4272
  while (true) {
2338
- const candidate = path7.join(current, "package.json");
4273
+ const candidate = path9.join(current, "package.json");
2339
4274
  if (fileExists2(candidate)) {
2340
4275
  return candidate;
2341
4276
  }
2342
4277
  if (current === root) {
2343
4278
  break;
2344
4279
  }
2345
- current = path7.dirname(current);
4280
+ current = path9.dirname(current);
2346
4281
  }
2347
4282
  return null;
2348
4283
  };
@@ -2384,11 +4319,11 @@ jobs:
2384
4319
  comment-on-pr: true
2385
4320
  `;
2386
4321
  };
2387
- var detectRepoInfo = (cwd, fileExists2, readFileSync4) => {
4322
+ var detectRepoInfo = (cwd, fileExists2, readFileSync5) => {
2388
4323
  const packageJsonPath = findNearestPackageJson(cwd, fileExists2);
2389
4324
  if (packageJsonPath) {
2390
4325
  try {
2391
- const raw = readFileSync4(packageJsonPath, "utf8");
4326
+ const raw = readFileSync5(packageJsonPath, "utf8");
2392
4327
  const parsed = JSON.parse(raw);
2393
4328
  let repoUrl;
2394
4329
  if (typeof parsed.repository === "string") {
@@ -2397,20 +4332,20 @@ var detectRepoInfo = (cwd, fileExists2, readFileSync4) => {
2397
4332
  repoUrl = parsed.repository.url;
2398
4333
  }
2399
4334
  if (repoUrl) {
2400
- const match = repoUrl.match(/github\.com[/:]([^/]+)\/([^/.]+)/);
2401
- if (match) {
2402
- return { owner: match[1], repo: match[2] };
4335
+ const match2 = repoUrl.match(/github\.com[/:]([^/]+)\/([^/.]+)/);
4336
+ if (match2) {
4337
+ return { owner: match2[1], repo: match2[2] };
2403
4338
  }
2404
4339
  }
2405
4340
  } catch {}
2406
4341
  }
2407
- const gitConfigPath = path7.join(cwd, ".git", "config");
4342
+ const gitConfigPath = path9.join(cwd, ".git", "config");
2408
4343
  if (fileExists2(gitConfigPath)) {
2409
4344
  try {
2410
- const config = readFileSync4(gitConfigPath, "utf8");
2411
- const match = config.match(/url\s*=\s*.*github\.com[/:]([^/]+)\/([^/.]+)/);
2412
- if (match) {
2413
- return { owner: match[1], repo: match[2].replace(/\.git$/, "") };
4345
+ const config = readFileSync5(gitConfigPath, "utf8");
4346
+ const match2 = config.match(/url\s*=\s*.*github\.com[/:]([^/]+)\/([^/.]+)/);
4347
+ if (match2) {
4348
+ return { owner: match2[1], repo: match2[2].replace(/\.git$/, "") };
2414
4349
  }
2415
4350
  } catch {}
2416
4351
  }
@@ -2418,8 +4353,8 @@ var detectRepoInfo = (cwd, fileExists2, readFileSync4) => {
2418
4353
  };
2419
4354
 
2420
4355
  // src/commands/spec.ts
2421
- import * as fs6 from "node:fs";
2422
- import * as path8 from "node:path";
4356
+ import * as fs7 from "node:fs";
4357
+ import * as path10 from "node:path";
2423
4358
  import {
2424
4359
  buildDocCovSpec as buildDocCovSpec2,
2425
4360
  DocCov as DocCov2,
@@ -2436,7 +4371,7 @@ import {
2436
4371
  import chalk9 from "chalk";
2437
4372
  var defaultDependencies4 = {
2438
4373
  createDocCov: (options) => new DocCov2(options),
2439
- writeFileSync: fs6.writeFileSync,
4374
+ writeFileSync: fs7.writeFileSync,
2440
4375
  log: console.log,
2441
4376
  error: console.error
2442
4377
  };
@@ -2445,13 +4380,13 @@ function getArrayLength(value) {
2445
4380
  }
2446
4381
  function formatDiagnosticOutput(prefix2, diagnostic, baseDir) {
2447
4382
  const location = diagnostic.location;
2448
- const relativePath = location?.file ? path8.relative(baseDir, location.file) || location.file : undefined;
4383
+ const relativePath = location?.file ? path10.relative(baseDir, location.file) || location.file : undefined;
2449
4384
  const locationText = location && relativePath ? chalk9.gray(`${relativePath}:${location.line ?? 1}:${location.column ?? 1}`) : null;
2450
4385
  const locationPrefix = locationText ? `${locationText} ` : "";
2451
4386
  return `${prefix2} ${locationPrefix}${diagnostic.message}`;
2452
4387
  }
2453
4388
  function registerSpecCommand(program, dependencies = {}) {
2454
- const { createDocCov, writeFileSync: writeFileSync4, log, error } = {
4389
+ const { createDocCov, writeFileSync: writeFileSync5, log, error } = {
2455
4390
  ...defaultDependencies4,
2456
4391
  ...dependencies
2457
4392
  };
@@ -2528,24 +4463,38 @@ function registerSpecCommand(program, dependencies = {}) {
2528
4463
  }
2529
4464
  }
2530
4465
  const format = options.format ?? "json";
2531
- const outputDir = path8.resolve(options.cwd, options.output);
2532
- fs6.mkdirSync(outputDir, { recursive: true });
4466
+ let packageName;
4467
+ if (resolved.packageInfo) {
4468
+ packageName = resolved.packageInfo.name;
4469
+ } else {
4470
+ const pkgJsonPath = path10.join(targetDir, "package.json");
4471
+ try {
4472
+ const pkgJson = JSON.parse(fs7.readFileSync(pkgJsonPath, "utf-8"));
4473
+ packageName = pkgJson.name ?? "unknown";
4474
+ } catch {
4475
+ packageName = "unknown";
4476
+ }
4477
+ }
4478
+ const baseOutputDir = path10.resolve(options.cwd, options.output);
4479
+ const outputDir = path10.join(baseOutputDir, packageName);
4480
+ fs7.mkdirSync(outputDir, { recursive: true });
4481
+ const displayPath = `${options.output}/${packageName}`;
2533
4482
  if (format === "api-surface") {
2534
4483
  const apiSurface = renderApiSurface(normalized);
2535
- const apiSurfacePath = path8.join(outputDir, "api-surface.txt");
2536
- writeFileSync4(apiSurfacePath, apiSurface);
2537
- spin.success(`Generated ${options.output}/ (API surface)`);
4484
+ const apiSurfacePath = path10.join(outputDir, "api-surface.txt");
4485
+ writeFileSync5(apiSurfacePath, apiSurface);
4486
+ spin.success(`Generated ${displayPath}/ (API surface)`);
2538
4487
  } else {
2539
- const openpkgPath = path8.join(outputDir, "openpkg.json");
2540
- writeFileSync4(openpkgPath, JSON.stringify(normalized, null, 2));
4488
+ const openpkgPath = path10.join(outputDir, "openpkg.json");
4489
+ writeFileSync5(openpkgPath, JSON.stringify(normalized, null, 2));
2541
4490
  if (doccovSpec) {
2542
- const doccovPath = path8.join(outputDir, "doccov.json");
2543
- writeFileSync4(doccovPath, JSON.stringify(doccovSpec, null, 2));
2544
- spin.success(`Generated ${options.output}/`);
4491
+ const doccovPath = path10.join(outputDir, "doccov.json");
4492
+ writeFileSync5(doccovPath, JSON.stringify(doccovSpec, null, 2));
4493
+ spin.success(`Generated ${displayPath}/`);
2545
4494
  log(chalk9.gray(` openpkg.json: ${getArrayLength(normalized.exports)} exports`));
2546
4495
  log(chalk9.gray(` doccov.json: ${doccovSpec.summary.score}% coverage, ${doccovSpec.summary.drift.total} drift issues`));
2547
4496
  } else {
2548
- spin.success(`Generated ${options.output}/openpkg.json`);
4497
+ spin.success(`Generated ${displayPath}/openpkg.json`);
2549
4498
  log(chalk9.gray(` ${getArrayLength(normalized.exports)} exports`));
2550
4499
  log(chalk9.gray(` ${getArrayLength(normalized.types)} types`));
2551
4500
  }
@@ -2621,8 +4570,8 @@ function registerSpecCommand(program, dependencies = {}) {
2621
4570
  }
2622
4571
 
2623
4572
  // src/commands/trends.ts
2624
- import * as fs7 from "node:fs";
2625
- import * as path9 from "node:path";
4573
+ import * as fs8 from "node:fs";
4574
+ import * as path11 from "node:path";
2626
4575
  import {
2627
4576
  formatDelta as formatDelta2,
2628
4577
  getExtendedTrend,
@@ -2672,7 +4621,7 @@ function formatVelocity(velocity) {
2672
4621
  }
2673
4622
  function registerTrendsCommand(program) {
2674
4623
  program.command("trends").description("Show coverage trends over time").option("--cwd <dir>", "Working directory", process.cwd()).option("-n, --limit <count>", "Number of snapshots to show", "10").option("--prune <count>", "Prune history to keep only N snapshots").option("--record", "Record current coverage to history").option("--json", "Output as JSON").option("--extended", "Show extended trend analysis (velocity, projections)").option("--weekly", "Show weekly summary breakdown").action(async (options) => {
2675
- const cwd = path9.resolve(options.cwd);
4624
+ const cwd = path11.resolve(options.cwd);
2676
4625
  if (options.prune) {
2677
4626
  const keepCount = parseInt(options.prune, 10);
2678
4627
  if (!Number.isNaN(keepCount)) {
@@ -2682,14 +4631,14 @@ function registerTrendsCommand(program) {
2682
4631
  return;
2683
4632
  }
2684
4633
  if (options.record) {
2685
- const specPath = path9.resolve(cwd, "openpkg.json");
2686
- if (!fs7.existsSync(specPath)) {
4634
+ const specPath = path11.resolve(cwd, "openpkg.json");
4635
+ if (!fs8.existsSync(specPath)) {
2687
4636
  console.error(chalk10.red("No openpkg.json found. Run `doccov spec` first to generate a spec."));
2688
4637
  process.exit(1);
2689
4638
  }
2690
4639
  const spin = spinner("Recording coverage snapshot");
2691
4640
  try {
2692
- const specContent = fs7.readFileSync(specPath, "utf-8");
4641
+ const specContent = fs8.readFileSync(specPath, "utf-8");
2693
4642
  const spec = JSON.parse(specContent);
2694
4643
  const trend = getTrend(spec, cwd);
2695
4644
  saveSnapshot(trend.current, cwd);
@@ -2740,10 +4689,10 @@ function registerTrendsCommand(program) {
2740
4689
  console.log("");
2741
4690
  }
2742
4691
  if (options.extended) {
2743
- const specPath = path9.resolve(cwd, "openpkg.json");
2744
- if (fs7.existsSync(specPath)) {
4692
+ const specPath = path11.resolve(cwd, "openpkg.json");
4693
+ if (fs8.existsSync(specPath)) {
2745
4694
  try {
2746
- const specContent = fs7.readFileSync(specPath, "utf-8");
4695
+ const specContent = fs8.readFileSync(specPath, "utf-8");
2747
4696
  const spec = JSON.parse(specContent);
2748
4697
  const extended = getExtendedTrend(spec, cwd);
2749
4698
  console.log(chalk10.bold("Extended Analysis"));
@@ -2801,8 +4750,8 @@ function registerTrendsCommand(program) {
2801
4750
 
2802
4751
  // src/cli.ts
2803
4752
  var __filename2 = fileURLToPath(import.meta.url);
2804
- var __dirname2 = path10.dirname(__filename2);
2805
- var packageJson = JSON.parse(readFileSync5(path10.join(__dirname2, "../package.json"), "utf-8"));
4753
+ var __dirname2 = path12.dirname(__filename2);
4754
+ var packageJson = JSON.parse(readFileSync7(path12.join(__dirname2, "../package.json"), "utf-8"));
2806
4755
  var program = new Command;
2807
4756
  program.name("doccov").description("DocCov - Documentation coverage and drift detection for TypeScript").version(packageJson.version);
2808
4757
  registerCheckCommand(program);