@doccov/cli 0.28.1 → 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 +2047 -89
  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
 
@@ -1352,7 +1352,7 @@ function displayHealthTree(health, log) {
1352
1352
  const completenessLabel = missingTotal > 0 ? `${health.completeness.score}% (${missingTotal} missing docs)` : `${health.completeness.score}%`;
1353
1353
  const completenessColor = getHealthColor(getHealthStatus(health.completeness.score));
1354
1354
  log(`${tree.branch} ${colors.muted("completeness")} ${completenessColor(completenessLabel)}`);
1355
- const accuracyLabel = health.accuracy.issues > 0 ? `${health.accuracy.score}% (${health.accuracy.issues} drift issues${health.accuracy.fixable > 0 ? `, ${health.accuracy.fixable} fixable` : ""})` : `${health.accuracy.score}%`;
1355
+ const accuracyLabel = health.accuracy.fixable > 0 ? `${health.accuracy.score}% (${health.accuracy.fixable} fixable with --fix)` : `${health.accuracy.score}%`;
1356
1356
  const accuracyColor = getHealthColor(getHealthStatus(health.accuracy.score));
1357
1357
  const lastBranch = !health.examples ? tree.corner : tree.branch;
1358
1358
  log(`${lastBranch} ${colors.muted("accuracy")} ${accuracyColor(accuracyLabel)}`);
@@ -1401,6 +1401,7 @@ function displayTextOutput(options, deps) {
1401
1401
  warnBelowApiSurface,
1402
1402
  driftExports,
1403
1403
  typecheckErrors,
1404
+ runtimeErrors,
1404
1405
  staleRefs,
1405
1406
  specWarnings,
1406
1407
  specInfos,
@@ -1420,6 +1421,7 @@ function displayTextOutput(options, deps) {
1420
1421
  const apiSurfaceFailed = minApiSurface !== undefined && apiSurfaceScore < minApiSurface;
1421
1422
  const apiSurfaceWarn = warnBelowApiSurface !== undefined && apiSurfaceScore < warnBelowApiSurface && !apiSurfaceFailed;
1422
1423
  const hasTypecheckErrors = typecheckErrors.length > 0;
1424
+ const hasRuntimeErrors = runtimeErrors > 0;
1423
1425
  if (specWarnings.length > 0 || specInfos.length > 0) {
1424
1426
  log("");
1425
1427
  for (const diag of specWarnings) {
@@ -1514,7 +1516,7 @@ function displayTextOutput(options, deps) {
1514
1516
  }
1515
1517
  }
1516
1518
  log("");
1517
- const failed = healthFailed || apiSurfaceFailed || hasTypecheckErrors || hasStaleRefs;
1519
+ const failed = healthFailed || apiSurfaceFailed || hasTypecheckErrors || hasRuntimeErrors || hasStaleRefs;
1518
1520
  if (!failed) {
1519
1521
  const thresholdParts = [];
1520
1522
  thresholdParts.push(`health ${healthScore}% ≥ ${minHealth}%`);
@@ -1539,6 +1541,9 @@ function displayTextOutput(options, deps) {
1539
1541
  if (hasTypecheckErrors) {
1540
1542
  log(colors.error(`${sym.error} ${typecheckErrors.length} example type errors`));
1541
1543
  }
1544
+ if (hasRuntimeErrors) {
1545
+ log(colors.error(`${sym.error} ${runtimeErrors} example runtime errors`));
1546
+ }
1542
1547
  if (hasStaleRefs) {
1543
1548
  log(colors.error(`${sym.error} ${staleRefs.length} stale references in docs`));
1544
1549
  }
@@ -1556,6 +1561,7 @@ function handleNonTextOutput(options, deps) {
1556
1561
  minHealth,
1557
1562
  minApiSurface,
1558
1563
  typecheckErrors,
1564
+ runtimeErrors,
1559
1565
  limit,
1560
1566
  stdout,
1561
1567
  outputPath,
@@ -1592,7 +1598,8 @@ function handleNonTextOutput(options, deps) {
1592
1598
  const apiSurfaceScore = doccov.apiSurface?.completeness ?? 100;
1593
1599
  const apiSurfaceFailed = minApiSurface !== undefined && apiSurfaceScore < minApiSurface;
1594
1600
  const hasTypecheckErrors = typecheckErrors.length > 0;
1595
- return !(healthFailed || apiSurfaceFailed || hasTypecheckErrors);
1601
+ const hasRuntimeErrors = runtimeErrors > 0;
1602
+ return !(healthFailed || apiSurfaceFailed || hasTypecheckErrors || hasRuntimeErrors);
1596
1603
  }
1597
1604
  function displayApiSurfaceOutput(doccov, deps) {
1598
1605
  const { log } = deps;
@@ -1643,6 +1650,1897 @@ function displayApiSurfaceOutput(doccov, deps) {
1643
1650
 
1644
1651
  // src/commands/check/validation.ts
1645
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
1646
3544
  async function runExampleValidation(openpkg, options) {
1647
3545
  const { validations, targetDir, timeout = 5000, installTimeout = 60000 } = options;
1648
3546
  const typecheckErrors = [];
@@ -1675,18 +3573,62 @@ async function runExampleValidation(openpkg, options) {
1675
3573
  }
1676
3574
  return { result, typecheckErrors, runtimeDrifts };
1677
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
+ }
1678
3589
  async function validateMarkdownDocs(options) {
1679
- const { docsPatterns, targetDir, exportNames } = options;
3590
+ const { docsPatterns, targetDir, exportNames, useCache = true, fetchTimeout, cacheTtl } = options;
1680
3591
  const staleRefs = [];
1681
3592
  if (docsPatterns.length === 0) {
1682
3593
  return staleRefs;
1683
3594
  }
1684
- const markdownFiles = await loadMarkdownFiles(docsPatterns, targetDir);
1685
- 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) {
1686
3628
  return staleRefs;
1687
3629
  }
1688
3630
  const exportSet = new Set(exportNames);
1689
- for (const mdFile of markdownFiles) {
3631
+ for (const mdFile of allDocs) {
1690
3632
  for (const block of mdFile.codeBlocks) {
1691
3633
  const codeLines = block.code.split(`
1692
3634
  `);
@@ -1842,6 +3784,7 @@ function registerCheckCommand(program, dependencies = {}) {
1842
3784
  minHealth,
1843
3785
  minApiSurface,
1844
3786
  typecheckErrors,
3787
+ runtimeErrors: runtimeDrifts.length,
1845
3788
  limit: parseInt(options.limit, 10) || 20,
1846
3789
  stdout: options.stdout,
1847
3790
  outputPath: options.output,
@@ -1861,6 +3804,7 @@ function registerCheckCommand(program, dependencies = {}) {
1861
3804
  warnBelowApiSurface,
1862
3805
  driftExports,
1863
3806
  typecheckErrors,
3807
+ runtimeErrors: runtimeDrifts.length,
1864
3808
  staleRefs,
1865
3809
  specWarnings,
1866
3810
  specInfos,
@@ -1876,8 +3820,8 @@ function registerCheckCommand(program, dependencies = {}) {
1876
3820
  });
1877
3821
  }
1878
3822
  // src/commands/diff.ts
1879
- import * as fs4 from "node:fs";
1880
- import * as path6 from "node:path";
3823
+ import * as fs5 from "node:fs";
3824
+ import * as path8 from "node:path";
1881
3825
  import {
1882
3826
  diffSpecWithDocs,
1883
3827
  ensureSpecCoverage,
@@ -1891,7 +3835,7 @@ import { calculateNextVersion, recommendSemverBump } from "@openpkg-ts/spec";
1891
3835
  import chalk7 from "chalk";
1892
3836
  import { glob as glob2 } from "glob";
1893
3837
  var defaultDependencies2 = {
1894
- readFileSync: fs4.readFileSync,
3838
+ readFileSync: fs5.readFileSync,
1895
3839
  log: console.log,
1896
3840
  error: console.error
1897
3841
  };
@@ -1910,7 +3854,7 @@ function getStrictChecks(preset) {
1910
3854
  return checks;
1911
3855
  }
1912
3856
  function registerDiffCommand(program, dependencies = {}) {
1913
- const { readFileSync: readFileSync3, log, error } = {
3857
+ const { readFileSync: readFileSync4, log, error } = {
1914
3858
  ...defaultDependencies2,
1915
3859
  ...dependencies
1916
3860
  };
@@ -1924,18 +3868,18 @@ function registerDiffCommand(program, dependencies = {}) {
1924
3868
  ` + " or: doccov diff --base main.json --head feature.json");
1925
3869
  }
1926
3870
  const spin = spinner("Comparing specs...");
1927
- const baseSpec = loadSpec(baseFile, readFileSync3);
1928
- const headSpec = loadSpec(headFile, readFileSync3);
3871
+ const baseSpec = loadSpec(baseFile, readFileSync4);
3872
+ const headSpec = loadSpec(headFile, readFileSync4);
1929
3873
  const config = await loadDocCovConfig(options.cwd);
1930
3874
  const baseHash = hashString(JSON.stringify(baseSpec));
1931
3875
  const headHash = hashString(JSON.stringify(headSpec));
1932
3876
  const cacheEnabled = options.cache !== false;
1933
- const cachedReportPath = path6.resolve(options.cwd, getDiffReportPath(baseHash, headHash, "json"));
3877
+ const cachedReportPath = path8.resolve(options.cwd, getDiffReportPath(baseHash, headHash, "json"));
1934
3878
  let diff;
1935
3879
  let fromCache = false;
1936
- if (cacheEnabled && fs4.existsSync(cachedReportPath)) {
3880
+ if (cacheEnabled && fs5.existsSync(cachedReportPath)) {
1937
3881
  try {
1938
- const cached = JSON.parse(fs4.readFileSync(cachedReportPath, "utf-8"));
3882
+ const cached = JSON.parse(fs5.readFileSync(cachedReportPath, "utf-8"));
1939
3883
  diff = cached;
1940
3884
  fromCache = true;
1941
3885
  } catch {
@@ -1973,8 +3917,8 @@ function registerDiffCommand(program, dependencies = {}) {
1973
3917
  const format = options.format ?? "text";
1974
3918
  const limit = parseInt(options.limit, 10) || 10;
1975
3919
  const checks = getStrictChecks(options.strict);
1976
- const baseName = path6.basename(baseFile);
1977
- const headName = path6.basename(headFile);
3920
+ const baseName = path8.basename(baseFile);
3921
+ const headName = path8.basename(headFile);
1978
3922
  const reportData = {
1979
3923
  baseName,
1980
3924
  headName,
@@ -2079,7 +4023,7 @@ async function loadMarkdownFiles2(patterns) {
2079
4023
  const matches = await glob2(pattern, { nodir: true });
2080
4024
  for (const filePath of matches) {
2081
4025
  try {
2082
- const content = fs4.readFileSync(filePath, "utf-8");
4026
+ const content = fs5.readFileSync(filePath, "utf-8");
2083
4027
  files.push({ path: filePath, content });
2084
4028
  } catch {}
2085
4029
  }
@@ -2100,13 +4044,13 @@ async function generateDiff(baseSpec, headSpec, options, config, log) {
2100
4044
  }
2101
4045
  return diffSpecWithDocs(baseSpec, headSpec, { markdownFiles });
2102
4046
  }
2103
- function loadSpec(filePath, readFileSync3) {
2104
- const resolvedPath = path6.resolve(filePath);
2105
- if (!fs4.existsSync(resolvedPath)) {
4047
+ function loadSpec(filePath, readFileSync4) {
4048
+ const resolvedPath = path8.resolve(filePath);
4049
+ if (!fs5.existsSync(resolvedPath)) {
2106
4050
  throw new Error(`File not found: ${filePath}`);
2107
4051
  }
2108
4052
  try {
2109
- const content = readFileSync3(resolvedPath, "utf-8");
4053
+ const content = readFileSync4(resolvedPath, "utf-8");
2110
4054
  const spec = JSON.parse(content);
2111
4055
  return ensureSpecCoverage(spec);
2112
4056
  } catch (parseError) {
@@ -2226,34 +4170,34 @@ function printGitHubAnnotations(diff, log) {
2226
4170
  }
2227
4171
 
2228
4172
  // src/commands/init.ts
2229
- import * as fs5 from "node:fs";
2230
- import * as path7 from "node:path";
4173
+ import * as fs6 from "node:fs";
4174
+ import * as path9 from "node:path";
2231
4175
  import chalk8 from "chalk";
2232
4176
  var defaultDependencies3 = {
2233
- fileExists: fs5.existsSync,
2234
- writeFileSync: fs5.writeFileSync,
2235
- readFileSync: fs5.readFileSync,
2236
- mkdirSync: fs5.mkdirSync,
4177
+ fileExists: fs6.existsSync,
4178
+ writeFileSync: fs6.writeFileSync,
4179
+ readFileSync: fs6.readFileSync,
4180
+ mkdirSync: fs6.mkdirSync,
2237
4181
  log: console.log,
2238
4182
  error: console.error
2239
4183
  };
2240
4184
  function registerInitCommand(program, dependencies = {}) {
2241
- const { fileExists: fileExists2, writeFileSync: writeFileSync3, readFileSync: readFileSync4, mkdirSync: mkdirSync3, log, error } = {
4185
+ const { fileExists: fileExists2, writeFileSync: writeFileSync4, readFileSync: readFileSync5, mkdirSync: mkdirSync4, log, error } = {
2242
4186
  ...defaultDependencies3,
2243
4187
  ...dependencies
2244
4188
  };
2245
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) => {
2246
- const cwd = path7.resolve(options.cwd);
4190
+ const cwd = path9.resolve(options.cwd);
2247
4191
  const existing = findExistingConfig(cwd, fileExists2);
2248
4192
  if (existing) {
2249
- 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.*"}.`));
2250
4194
  process.exitCode = 1;
2251
4195
  return;
2252
4196
  }
2253
- const packageType = detectPackageType(cwd, fileExists2, readFileSync4);
4197
+ const packageType = detectPackageType(cwd, fileExists2, readFileSync5);
2254
4198
  const targetFormat = packageType === "module" ? "ts" : "mts";
2255
4199
  const fileName = `doccov.config.${targetFormat}`;
2256
- const outputPath = path7.join(cwd, fileName);
4200
+ const outputPath = path9.join(cwd, fileName);
2257
4201
  if (fileExists2(outputPath)) {
2258
4202
  error(chalk8.red(`Cannot create ${fileName}; file already exists.`));
2259
4203
  process.exitCode = 1;
@@ -2261,20 +4205,20 @@ function registerInitCommand(program, dependencies = {}) {
2261
4205
  }
2262
4206
  const sym = getSymbols(supportsUnicode());
2263
4207
  const template = buildConfigTemplate();
2264
- writeFileSync3(outputPath, template, { encoding: "utf8" });
4208
+ writeFileSync4(outputPath, template, { encoding: "utf8" });
2265
4209
  log(colors.success(`${sym.success} Created ${fileName}`));
2266
4210
  if (!options.skipAction) {
2267
- const workflowDir = path7.join(cwd, ".github", "workflows");
2268
- const workflowPath = path7.join(workflowDir, "doccov.yml");
4211
+ const workflowDir = path9.join(cwd, ".github", "workflows");
4212
+ const workflowPath = path9.join(workflowDir, "doccov.yml");
2269
4213
  if (!fileExists2(workflowPath)) {
2270
- mkdirSync3(workflowDir, { recursive: true });
2271
- writeFileSync3(workflowPath, buildWorkflowTemplate(), { encoding: "utf8" });
4214
+ mkdirSync4(workflowDir, { recursive: true });
4215
+ writeFileSync4(workflowPath, buildWorkflowTemplate(), { encoding: "utf8" });
2272
4216
  log(colors.success(`${sym.success} Created .github/workflows/doccov.yml`));
2273
4217
  } else {
2274
4218
  log(colors.warning(`${sym.bullet} Skipped .github/workflows/doccov.yml (already exists)`));
2275
4219
  }
2276
4220
  }
2277
- const repoInfo = detectRepoInfo(cwd, fileExists2, readFileSync4);
4221
+ const repoInfo = detectRepoInfo(cwd, fileExists2, readFileSync5);
2278
4222
  log("");
2279
4223
  log(chalk8.bold("Add this badge to your README:"));
2280
4224
  log("");
@@ -2289,11 +4233,11 @@ function registerInitCommand(program, dependencies = {}) {
2289
4233
  });
2290
4234
  }
2291
4235
  var findExistingConfig = (cwd, fileExists2) => {
2292
- let current = path7.resolve(cwd);
2293
- const { root } = path7.parse(current);
4236
+ let current = path9.resolve(cwd);
4237
+ const { root } = path9.parse(current);
2294
4238
  while (true) {
2295
4239
  for (const candidate of DOCCOV_CONFIG_FILENAMES) {
2296
- const candidatePath = path7.join(current, candidate);
4240
+ const candidatePath = path9.join(current, candidate);
2297
4241
  if (fileExists2(candidatePath)) {
2298
4242
  return candidatePath;
2299
4243
  }
@@ -2301,17 +4245,17 @@ var findExistingConfig = (cwd, fileExists2) => {
2301
4245
  if (current === root) {
2302
4246
  break;
2303
4247
  }
2304
- current = path7.dirname(current);
4248
+ current = path9.dirname(current);
2305
4249
  }
2306
4250
  return null;
2307
4251
  };
2308
- var detectPackageType = (cwd, fileExists2, readFileSync4) => {
4252
+ var detectPackageType = (cwd, fileExists2, readFileSync5) => {
2309
4253
  const packageJsonPath = findNearestPackageJson(cwd, fileExists2);
2310
4254
  if (!packageJsonPath) {
2311
4255
  return;
2312
4256
  }
2313
4257
  try {
2314
- const raw = readFileSync4(packageJsonPath, "utf8");
4258
+ const raw = readFileSync5(packageJsonPath, "utf8");
2315
4259
  const parsed = JSON.parse(raw);
2316
4260
  if (parsed.type === "module") {
2317
4261
  return "module";
@@ -2323,17 +4267,17 @@ var detectPackageType = (cwd, fileExists2, readFileSync4) => {
2323
4267
  return;
2324
4268
  };
2325
4269
  var findNearestPackageJson = (cwd, fileExists2) => {
2326
- let current = path7.resolve(cwd);
2327
- const { root } = path7.parse(current);
4270
+ let current = path9.resolve(cwd);
4271
+ const { root } = path9.parse(current);
2328
4272
  while (true) {
2329
- const candidate = path7.join(current, "package.json");
4273
+ const candidate = path9.join(current, "package.json");
2330
4274
  if (fileExists2(candidate)) {
2331
4275
  return candidate;
2332
4276
  }
2333
4277
  if (current === root) {
2334
4278
  break;
2335
4279
  }
2336
- current = path7.dirname(current);
4280
+ current = path9.dirname(current);
2337
4281
  }
2338
4282
  return null;
2339
4283
  };
@@ -2375,11 +4319,11 @@ jobs:
2375
4319
  comment-on-pr: true
2376
4320
  `;
2377
4321
  };
2378
- var detectRepoInfo = (cwd, fileExists2, readFileSync4) => {
4322
+ var detectRepoInfo = (cwd, fileExists2, readFileSync5) => {
2379
4323
  const packageJsonPath = findNearestPackageJson(cwd, fileExists2);
2380
4324
  if (packageJsonPath) {
2381
4325
  try {
2382
- const raw = readFileSync4(packageJsonPath, "utf8");
4326
+ const raw = readFileSync5(packageJsonPath, "utf8");
2383
4327
  const parsed = JSON.parse(raw);
2384
4328
  let repoUrl;
2385
4329
  if (typeof parsed.repository === "string") {
@@ -2388,20 +4332,20 @@ var detectRepoInfo = (cwd, fileExists2, readFileSync4) => {
2388
4332
  repoUrl = parsed.repository.url;
2389
4333
  }
2390
4334
  if (repoUrl) {
2391
- const match = repoUrl.match(/github\.com[/:]([^/]+)\/([^/.]+)/);
2392
- if (match) {
2393
- 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] };
2394
4338
  }
2395
4339
  }
2396
4340
  } catch {}
2397
4341
  }
2398
- const gitConfigPath = path7.join(cwd, ".git", "config");
4342
+ const gitConfigPath = path9.join(cwd, ".git", "config");
2399
4343
  if (fileExists2(gitConfigPath)) {
2400
4344
  try {
2401
- const config = readFileSync4(gitConfigPath, "utf8");
2402
- const match = config.match(/url\s*=\s*.*github\.com[/:]([^/]+)\/([^/.]+)/);
2403
- if (match) {
2404
- 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$/, "") };
2405
4349
  }
2406
4350
  } catch {}
2407
4351
  }
@@ -2409,8 +4353,8 @@ var detectRepoInfo = (cwd, fileExists2, readFileSync4) => {
2409
4353
  };
2410
4354
 
2411
4355
  // src/commands/spec.ts
2412
- import * as fs6 from "node:fs";
2413
- import * as path8 from "node:path";
4356
+ import * as fs7 from "node:fs";
4357
+ import * as path10 from "node:path";
2414
4358
  import {
2415
4359
  buildDocCovSpec as buildDocCovSpec2,
2416
4360
  DocCov as DocCov2,
@@ -2427,7 +4371,7 @@ import {
2427
4371
  import chalk9 from "chalk";
2428
4372
  var defaultDependencies4 = {
2429
4373
  createDocCov: (options) => new DocCov2(options),
2430
- writeFileSync: fs6.writeFileSync,
4374
+ writeFileSync: fs7.writeFileSync,
2431
4375
  log: console.log,
2432
4376
  error: console.error
2433
4377
  };
@@ -2436,13 +4380,13 @@ function getArrayLength(value) {
2436
4380
  }
2437
4381
  function formatDiagnosticOutput(prefix2, diagnostic, baseDir) {
2438
4382
  const location = diagnostic.location;
2439
- 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;
2440
4384
  const locationText = location && relativePath ? chalk9.gray(`${relativePath}:${location.line ?? 1}:${location.column ?? 1}`) : null;
2441
4385
  const locationPrefix = locationText ? `${locationText} ` : "";
2442
4386
  return `${prefix2} ${locationPrefix}${diagnostic.message}`;
2443
4387
  }
2444
4388
  function registerSpecCommand(program, dependencies = {}) {
2445
- const { createDocCov, writeFileSync: writeFileSync4, log, error } = {
4389
+ const { createDocCov, writeFileSync: writeFileSync5, log, error } = {
2446
4390
  ...defaultDependencies4,
2447
4391
  ...dependencies
2448
4392
  };
@@ -2519,24 +4463,38 @@ function registerSpecCommand(program, dependencies = {}) {
2519
4463
  }
2520
4464
  }
2521
4465
  const format = options.format ?? "json";
2522
- const outputDir = path8.resolve(options.cwd, options.output);
2523
- 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}`;
2524
4482
  if (format === "api-surface") {
2525
4483
  const apiSurface = renderApiSurface(normalized);
2526
- const apiSurfacePath = path8.join(outputDir, "api-surface.txt");
2527
- writeFileSync4(apiSurfacePath, apiSurface);
2528
- 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)`);
2529
4487
  } else {
2530
- const openpkgPath = path8.join(outputDir, "openpkg.json");
2531
- writeFileSync4(openpkgPath, JSON.stringify(normalized, null, 2));
4488
+ const openpkgPath = path10.join(outputDir, "openpkg.json");
4489
+ writeFileSync5(openpkgPath, JSON.stringify(normalized, null, 2));
2532
4490
  if (doccovSpec) {
2533
- const doccovPath = path8.join(outputDir, "doccov.json");
2534
- writeFileSync4(doccovPath, JSON.stringify(doccovSpec, null, 2));
2535
- 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}/`);
2536
4494
  log(chalk9.gray(` openpkg.json: ${getArrayLength(normalized.exports)} exports`));
2537
4495
  log(chalk9.gray(` doccov.json: ${doccovSpec.summary.score}% coverage, ${doccovSpec.summary.drift.total} drift issues`));
2538
4496
  } else {
2539
- spin.success(`Generated ${options.output}/openpkg.json`);
4497
+ spin.success(`Generated ${displayPath}/openpkg.json`);
2540
4498
  log(chalk9.gray(` ${getArrayLength(normalized.exports)} exports`));
2541
4499
  log(chalk9.gray(` ${getArrayLength(normalized.types)} types`));
2542
4500
  }
@@ -2612,8 +4570,8 @@ function registerSpecCommand(program, dependencies = {}) {
2612
4570
  }
2613
4571
 
2614
4572
  // src/commands/trends.ts
2615
- import * as fs7 from "node:fs";
2616
- import * as path9 from "node:path";
4573
+ import * as fs8 from "node:fs";
4574
+ import * as path11 from "node:path";
2617
4575
  import {
2618
4576
  formatDelta as formatDelta2,
2619
4577
  getExtendedTrend,
@@ -2663,7 +4621,7 @@ function formatVelocity(velocity) {
2663
4621
  }
2664
4622
  function registerTrendsCommand(program) {
2665
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) => {
2666
- const cwd = path9.resolve(options.cwd);
4624
+ const cwd = path11.resolve(options.cwd);
2667
4625
  if (options.prune) {
2668
4626
  const keepCount = parseInt(options.prune, 10);
2669
4627
  if (!Number.isNaN(keepCount)) {
@@ -2673,14 +4631,14 @@ function registerTrendsCommand(program) {
2673
4631
  return;
2674
4632
  }
2675
4633
  if (options.record) {
2676
- const specPath = path9.resolve(cwd, "openpkg.json");
2677
- if (!fs7.existsSync(specPath)) {
4634
+ const specPath = path11.resolve(cwd, "openpkg.json");
4635
+ if (!fs8.existsSync(specPath)) {
2678
4636
  console.error(chalk10.red("No openpkg.json found. Run `doccov spec` first to generate a spec."));
2679
4637
  process.exit(1);
2680
4638
  }
2681
4639
  const spin = spinner("Recording coverage snapshot");
2682
4640
  try {
2683
- const specContent = fs7.readFileSync(specPath, "utf-8");
4641
+ const specContent = fs8.readFileSync(specPath, "utf-8");
2684
4642
  const spec = JSON.parse(specContent);
2685
4643
  const trend = getTrend(spec, cwd);
2686
4644
  saveSnapshot(trend.current, cwd);
@@ -2731,10 +4689,10 @@ function registerTrendsCommand(program) {
2731
4689
  console.log("");
2732
4690
  }
2733
4691
  if (options.extended) {
2734
- const specPath = path9.resolve(cwd, "openpkg.json");
2735
- if (fs7.existsSync(specPath)) {
4692
+ const specPath = path11.resolve(cwd, "openpkg.json");
4693
+ if (fs8.existsSync(specPath)) {
2736
4694
  try {
2737
- const specContent = fs7.readFileSync(specPath, "utf-8");
4695
+ const specContent = fs8.readFileSync(specPath, "utf-8");
2738
4696
  const spec = JSON.parse(specContent);
2739
4697
  const extended = getExtendedTrend(spec, cwd);
2740
4698
  console.log(chalk10.bold("Extended Analysis"));
@@ -2792,8 +4750,8 @@ function registerTrendsCommand(program) {
2792
4750
 
2793
4751
  // src/cli.ts
2794
4752
  var __filename2 = fileURLToPath(import.meta.url);
2795
- var __dirname2 = path10.dirname(__filename2);
2796
- 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"));
2797
4755
  var program = new Command;
2798
4756
  program.name("doccov").description("DocCov - Documentation coverage and drift detection for TypeScript").version(packageJson.version);
2799
4757
  registerCheckCommand(program);