@grove-dev/core 0.3.1 → 0.3.4

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 (113) hide show
  1. package/README.md +16 -142
  2. package/dist/build-data.d.ts.map +1 -1
  3. package/dist/build-data.js +13 -4
  4. package/dist/build-data.js.map +1 -1
  5. package/dist/contributors.d.ts +3 -0
  6. package/dist/contributors.d.ts.map +1 -1
  7. package/dist/contributors.js +46 -36
  8. package/dist/contributors.js.map +1 -1
  9. package/dist/directory-client.d.ts +11 -0
  10. package/dist/directory-client.d.ts.map +1 -0
  11. package/dist/directory-client.js +11 -0
  12. package/dist/directory-client.js.map +1 -0
  13. package/dist/directory-display.d.ts +27 -0
  14. package/dist/directory-display.d.ts.map +1 -0
  15. package/dist/directory-display.js +104 -0
  16. package/dist/directory-display.js.map +1 -0
  17. package/dist/directory-format.d.ts +29 -0
  18. package/dist/directory-format.d.ts.map +1 -0
  19. package/dist/directory-format.js +72 -0
  20. package/dist/directory-format.js.map +1 -0
  21. package/dist/directory-lenses.d.ts +59 -0
  22. package/dist/directory-lenses.d.ts.map +1 -0
  23. package/dist/directory-lenses.js +199 -0
  24. package/dist/directory-lenses.js.map +1 -0
  25. package/dist/directory-repo.d.ts +20 -0
  26. package/dist/directory-repo.d.ts.map +1 -0
  27. package/dist/directory-repo.js +31 -0
  28. package/dist/directory-repo.js.map +1 -0
  29. package/dist/directory-scores.d.ts +37 -0
  30. package/dist/directory-scores.d.ts.map +1 -0
  31. package/dist/directory-scores.js +76 -0
  32. package/dist/directory-scores.js.map +1 -0
  33. package/dist/directory-search.d.ts +119 -0
  34. package/dist/directory-search.d.ts.map +1 -0
  35. package/dist/directory-search.js +398 -0
  36. package/dist/directory-search.js.map +1 -0
  37. package/dist/directory-taxonomy.d.ts +19 -0
  38. package/dist/directory-taxonomy.d.ts.map +1 -0
  39. package/dist/directory-taxonomy.js +36 -0
  40. package/dist/directory-taxonomy.js.map +1 -0
  41. package/dist/index.d.ts +11 -0
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +19 -6
  44. package/dist/index.js.map +1 -1
  45. package/dist/llms.js +1 -1
  46. package/dist/llms.js.map +1 -1
  47. package/dist/prepare.d.ts +20 -0
  48. package/dist/prepare.d.ts.map +1 -0
  49. package/dist/prepare.js +75 -0
  50. package/dist/prepare.js.map +1 -0
  51. package/dist/schema.d.ts +56 -0
  52. package/dist/schema.d.ts.map +1 -1
  53. package/dist/schema.js +38 -0
  54. package/dist/schema.js.map +1 -1
  55. package/dist/site-artifacts.d.ts +15 -0
  56. package/dist/site-artifacts.d.ts.map +1 -0
  57. package/dist/site-artifacts.js +122 -0
  58. package/dist/site-artifacts.js.map +1 -0
  59. package/dist/validate.js +4 -2
  60. package/dist/validate.js.map +1 -1
  61. package/package.json +9 -2
  62. package/dist/build-data.test.d.ts +0 -2
  63. package/dist/build-data.test.d.ts.map +0 -1
  64. package/dist/build-data.test.js +0 -196
  65. package/dist/build-data.test.js.map +0 -1
  66. package/dist/contributors.test.d.ts +0 -2
  67. package/dist/contributors.test.d.ts.map +0 -1
  68. package/dist/contributors.test.js +0 -79
  69. package/dist/contributors.test.js.map +0 -1
  70. package/dist/decisions.test.d.ts +0 -2
  71. package/dist/decisions.test.d.ts.map +0 -1
  72. package/dist/decisions.test.js +0 -205
  73. package/dist/decisions.test.js.map +0 -1
  74. package/dist/enrich.test.d.ts +0 -2
  75. package/dist/enrich.test.d.ts.map +0 -1
  76. package/dist/enrich.test.js +0 -105
  77. package/dist/enrich.test.js.map +0 -1
  78. package/dist/github-client.test.d.ts +0 -2
  79. package/dist/github-client.test.d.ts.map +0 -1
  80. package/dist/github-client.test.js +0 -176
  81. package/dist/github-client.test.js.map +0 -1
  82. package/dist/github.test.d.ts +0 -2
  83. package/dist/github.test.d.ts.map +0 -1
  84. package/dist/github.test.js +0 -73
  85. package/dist/github.test.js.map +0 -1
  86. package/dist/health.test.d.ts +0 -2
  87. package/dist/health.test.d.ts.map +0 -1
  88. package/dist/health.test.js +0 -183
  89. package/dist/health.test.js.map +0 -1
  90. package/dist/importer.test.d.ts +0 -2
  91. package/dist/importer.test.d.ts.map +0 -1
  92. package/dist/importer.test.js +0 -173
  93. package/dist/importer.test.js.map +0 -1
  94. package/dist/llms.test.d.ts +0 -2
  95. package/dist/llms.test.d.ts.map +0 -1
  96. package/dist/llms.test.js +0 -39
  97. package/dist/llms.test.js.map +0 -1
  98. package/dist/public-api.test.d.ts +0 -2
  99. package/dist/public-api.test.d.ts.map +0 -1
  100. package/dist/public-api.test.js +0 -13
  101. package/dist/public-api.test.js.map +0 -1
  102. package/dist/sitemap.test.d.ts +0 -2
  103. package/dist/sitemap.test.d.ts.map +0 -1
  104. package/dist/sitemap.test.js +0 -35
  105. package/dist/sitemap.test.js.map +0 -1
  106. package/dist/slug.test.d.ts +0 -2
  107. package/dist/slug.test.d.ts.map +0 -1
  108. package/dist/slug.test.js +0 -101
  109. package/dist/slug.test.js.map +0 -1
  110. package/dist/validate.test.d.ts +0 -2
  111. package/dist/validate.test.d.ts.map +0 -1
  112. package/dist/validate.test.js +0 -272
  113. package/dist/validate.test.js.map +0 -1
@@ -1,105 +0,0 @@
1
- /**
2
- * @grove-dev/core — enrich.ts unit tests.
3
- *
4
- * `enrichFromGithubHtml` makes network calls to github.com and
5
- * img.shields.io. The unit suite is offline, so we test:
6
- * - the validation gate (an unparseable repo URL returns
7
- * `{error: "invalid_repo_url"}` with empty fields)
8
- * - the 404 / 429 / generic error short-circuits
9
- * - the HTML parsing for license, language, topics, homepage
10
- * via `fetch` mock
11
- */
12
- import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
13
- import { enrichFromGithubHtml } from "./enrich.js";
14
- const SAMPLE_HTML = `
15
- <html>
16
- <head>
17
- <title>owner/repo: A real project</title>
18
- </head>
19
- <body>
20
- <a href="/topics/awesome" rel="nofollow">awesome</a>
21
- <a href="/topics/list" rel="nofollow">list</a>
22
- <a href="/topics/awesome" rel="nofollow">awesome</a>
23
- <span class="color-fg-default text-bold mr-1">TypeScript</span>
24
- <a href="https://example.com" rel="nofollow">Homepage</a>
25
- <span>
26
- <a href="/owner/repo/blob/main/LICENSE" itemprop="license">MIT License</a>
27
- </span>
28
- </body>
29
- </html>
30
- `;
31
- describe("enrichFromGithubHtml — input validation", () => {
32
- it("returns an empty-fields + error result for an unparseable URL", async () => {
33
- // `getOwnerRepoFromUrl` only matches github.com URLs, so
34
- // anything else gets the "invalid_repo_url" short-circuit
35
- // without a network round-trip. Pin the exact shape.
36
- const r = await enrichFromGithubHtml("https://example.com/owner/repo");
37
- expect(r).toEqual({
38
- fields: { license: null, language: null, topics: [], homepage: null },
39
- error: "invalid_repo_url",
40
- });
41
- });
42
- });
43
- describe("enrichFromGithubHtml — HTTP short-circuits", () => {
44
- let originalFetch;
45
- beforeEach(() => {
46
- originalFetch = globalThis.fetch;
47
- });
48
- afterEach(() => {
49
- globalThis.fetch = originalFetch;
50
- vi.restoreAllMocks();
51
- });
52
- it("returns notFound=true on a 404", async () => {
53
- globalThis.fetch = vi.fn(async () => new Response("not found", { status: 404 }));
54
- const r = await enrichFromGithubHtml("https://github.com/owner/does-not-exist");
55
- expect(r.notFound).toBe(true);
56
- expect(r.fields).toEqual({ license: null, language: null, topics: [], homepage: null });
57
- });
58
- it("returns rateLimited=true on a 429", async () => {
59
- globalThis.fetch = vi.fn(async () => new Response("slow down", { status: 429 }));
60
- const r = await enrichFromGithubHtml("https://github.com/owner/repo");
61
- expect(r.rateLimited).toBe(true);
62
- });
63
- it("returns error='<status>' on other non-2xx responses", async () => {
64
- globalThis.fetch = vi.fn(async () => new Response("server error", { status: 500 }));
65
- const r = await enrichFromGithubHtml("https://github.com/owner/repo");
66
- expect(r.error).toContain("500");
67
- });
68
- it("returns the error message string when fetch itself throws", async () => {
69
- globalThis.fetch = vi.fn(async () => {
70
- throw new Error("ECONNRESET");
71
- });
72
- const r = await enrichFromGithubHtml("https://github.com/owner/repo");
73
- expect(r.error).toBe("ECONNRESET");
74
- });
75
- });
76
- describe("enrichFromGithubHtml — HTML extraction", () => {
77
- let originalFetch;
78
- beforeEach(() => {
79
- originalFetch = globalThis.fetch;
80
- });
81
- afterEach(() => {
82
- globalThis.fetch = originalFetch;
83
- vi.restoreAllMocks();
84
- });
85
- it("extracts license, language, topics (deduped), and homepage from a sample page", async () => {
86
- // Mock only the github.com page; the shields.io fallback is
87
- // not exercised here because the HTML already contains the
88
- // license link.
89
- globalThis.fetch = vi.fn(async (input) => {
90
- const url = String(input);
91
- if (url.startsWith("https://github.com/")) {
92
- return new Response(SAMPLE_HTML, { status: 200 });
93
- }
94
- // shields.io (not called in this test, but keep the mock honest).
95
- return new Response("not found", { status: 404 });
96
- });
97
- const r = await enrichFromGithubHtml("https://github.com/owner/repo");
98
- expect(r.error).toBeUndefined();
99
- expect(r.fields.license).toBe("MIT");
100
- expect(r.fields.language).toBe("TypeScript");
101
- expect(r.fields.topics).toEqual(["awesome", "list"]); // deduped
102
- expect(r.fields.homepage).toBe("https://example.com");
103
- });
104
- });
105
- //# sourceMappingURL=enrich.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"enrich.test.js","sourceRoot":"","sources":["../src/enrich.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=github-client.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"github-client.test.d.ts","sourceRoot":"","sources":["../src/github-client.test.ts"],"names":[],"mappings":""}
@@ -1,176 +0,0 @@
1
- /**
2
- * @grove-dev/core — github-client.ts unit tests.
3
- *
4
- * Tests cover the pure-logic helpers (`rateLimitWaitMs`, `sleep`,
5
- * `pLimit`) and the HTTP path stub via a global `fetch` mock.
6
- * The brief flagged `ghFetch` as audit-worthy (exponential backoff
7
- * + rate-limit handling); the test pins the contract:
8
- * - 429 / 403 (rate-limit) waits then retries
9
- * - 5xx retries up to `attempts`
10
- * - non-retryable 4xx returns immediately
11
- * - exhausted attempts throw
12
- */
13
- import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
14
- import { rateLimitWaitMs, sleep, pLimit, ghFetch } from "./github-client.js";
15
- describe("rateLimitWaitMs", () => {
16
- it("returns 0 when the header is missing", () => {
17
- const res = new Response("", { status: 200 });
18
- expect(rateLimitWaitMs(res)).toBe(0);
19
- });
20
- it("returns 0 when the reset time is in the past", () => {
21
- const res = new Response("", { status: 200, headers: { "x-ratelimit-reset": String(Math.floor(Date.now() / 1000) - 60) } });
22
- expect(rateLimitWaitMs(res)).toBe(0);
23
- });
24
- it("returns the delta to the reset time, capped at 5 minutes", () => {
25
- // Reset 30 seconds in the future → expect ~30000ms (capped not triggered).
26
- const res = new Response("", { status: 200, headers: { "x-ratelimit-reset": String(Math.floor(Date.now() / 1000) + 30) } });
27
- const wait = rateLimitWaitMs(res);
28
- expect(wait).toBeGreaterThan(20_000);
29
- expect(wait).toBeLessThan(35_000);
30
- });
31
- it("caps the wait at the supplied capMs (default 5 minutes)", () => {
32
- // Reset 1 hour in the future → capped at 5 minutes = 300_000ms.
33
- const res = new Response("", { status: 200, headers: { "x-ratelimit-reset": String(Math.floor(Date.now() / 1000) + 3600) } });
34
- expect(rateLimitWaitMs(res)).toBe(5 * 60_000);
35
- // Custom cap is honoured.
36
- expect(rateLimitWaitMs(res, 1_000)).toBe(1_000);
37
- });
38
- });
39
- describe("sleep", () => {
40
- it("resolves immediately for non-positive input", async () => {
41
- const start = Date.now();
42
- await sleep(0);
43
- await sleep(-100);
44
- expect(Date.now() - start).toBeLessThan(50);
45
- });
46
- it("waits approximately the requested duration", async () => {
47
- const start = Date.now();
48
- await sleep(100);
49
- const elapsed = Date.now() - start;
50
- expect(elapsed).toBeGreaterThanOrEqual(90); // tolerance for timer skew
51
- expect(elapsed).toBeLessThan(250);
52
- });
53
- });
54
- describe("pLimit", () => {
55
- it("runs every item and preserves order", async () => {
56
- const items = [1, 2, 3, 4, 5];
57
- const fn = vi.fn(async (n) => n * 10);
58
- const result = await pLimit(2, items, fn);
59
- expect(result).toEqual([10, 20, 30, 40, 50]);
60
- expect(fn).toHaveBeenCalledTimes(5);
61
- });
62
- it("respects the concurrency cap (max in-flight workers)", async () => {
63
- let inFlight = 0;
64
- let maxInFlight = 0;
65
- const fn = async () => {
66
- inFlight++;
67
- maxInFlight = Math.max(maxInFlight, inFlight);
68
- await sleep(20);
69
- inFlight--;
70
- return "done";
71
- };
72
- await pLimit(2, [1, 2, 3, 4, 5, 6], fn);
73
- expect(maxInFlight).toBeLessThanOrEqual(2);
74
- expect(maxInFlight).toBe(2); // we expect the cap to actually be hit
75
- });
76
- it("returns an empty array for an empty input", async () => {
77
- const fn = vi.fn(async () => "x");
78
- expect(await pLimit(1, [], fn)).toEqual([]);
79
- expect(fn).not.toHaveBeenCalled();
80
- });
81
- it("works with concurrency=1 (serial execution)", async () => {
82
- const order = [];
83
- const fn = async (n) => {
84
- order.push(n);
85
- return n;
86
- };
87
- await pLimit(1, [1, 2, 3], fn);
88
- expect(order).toEqual([1, 2, 3]);
89
- });
90
- });
91
- describe("ghFetch", () => {
92
- let originalFetch;
93
- beforeEach(() => {
94
- originalFetch = globalThis.fetch;
95
- });
96
- afterEach(() => {
97
- globalThis.fetch = originalFetch;
98
- vi.restoreAllMocks();
99
- });
100
- it("returns the response on a 200 (no retry)", async () => {
101
- const calls = [];
102
- globalThis.fetch = vi.fn(async (input) => {
103
- calls.push(String(input));
104
- return new Response("{}", { status: 200, headers: { "content-type": "application/json" } });
105
- });
106
- const res = await ghFetch("/repos/owner/repo");
107
- expect(res.status).toBe(200);
108
- expect(calls).toHaveLength(1);
109
- });
110
- it("retries on 5xx and succeeds on the second attempt", async () => {
111
- let calls = 0;
112
- globalThis.fetch = vi.fn(async () => {
113
- calls++;
114
- if (calls === 1)
115
- return new Response("oops", { status: 503 });
116
- return new Response("{}", { status: 200 });
117
- });
118
- const res = await ghFetch("/repos/owner/repo", { attempts: 3 });
119
- expect(res.status).toBe(200);
120
- expect(calls).toBe(2);
121
- });
122
- it("returns the 5xx response on the final attempt (does NOT throw)", async () => {
123
- // Pin the *current* behaviour: ghFetch retries 5xx up to
124
- // `attempts - 1` times, then returns whatever the last
125
- // response was — even if it's a 5xx. The throw path is
126
- // reserved for network errors (the `catch (err)` block
127
- // around `fetch()` itself), not for HTTP error status codes.
128
- // This is the right contract for a "be tolerant of transient
129
- // 5xx" wrapper — callers check the status themselves.
130
- let calls = 0;
131
- globalThis.fetch = vi.fn(async () => {
132
- calls++;
133
- return new Response("nope", { status: 500 });
134
- });
135
- const res = await ghFetch("/repos/owner/repo", { attempts: 3 });
136
- expect(res.status).toBe(500);
137
- // 1 initial + 2 retries (3rd attempt is the final, no more
138
- // retry, returns the response).
139
- expect(calls).toBe(3);
140
- });
141
- it("throws after exhausting attempts when fetch itself errors (network failure)", async () => {
142
- // The throw path is for network errors, not HTTP status codes.
143
- globalThis.fetch = vi.fn(async () => {
144
- throw new Error("ECONNREFUSED");
145
- });
146
- await expect(ghFetch("/repos/owner/repo", { attempts: 2 })).rejects.toThrow(/ECONNREFUSED/);
147
- });
148
- it("does NOT retry on a non-retryable 4xx (e.g. 404)", async () => {
149
- let calls = 0;
150
- globalThis.fetch = vi.fn(async () => {
151
- calls++;
152
- return new Response("not found", { status: 404 });
153
- });
154
- const res = await ghFetch("/repos/owner/repo", { attempts: 5 });
155
- expect(res.status).toBe(404);
156
- expect(calls).toBe(1);
157
- });
158
- it("waits for rate-limit reset on a 403 with x-ratelimit-remaining=0", async () => {
159
- let calls = 0;
160
- globalThis.fetch = vi.fn(async () => {
161
- calls++;
162
- if (calls === 1) {
163
- // Rate-limited. Reset in 1 second.
164
- return new Response("rate", {
165
- status: 403,
166
- headers: { "x-ratelimit-remaining": "0", "x-ratelimit-reset": String(Math.floor(Date.now() / 1000) + 1) },
167
- });
168
- }
169
- return new Response("{}", { status: 200 });
170
- });
171
- const res = await ghFetch("/repos/owner/repo", { attempts: 2 });
172
- expect(res.status).toBe(200);
173
- expect(calls).toBe(2);
174
- });
175
- });
176
- //# sourceMappingURL=github-client.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"github-client.test.js","sourceRoot":"","sources":["../src/github-client.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=github.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"github.test.d.ts","sourceRoot":"","sources":["../src/github.test.ts"],"names":[],"mappings":""}
@@ -1,73 +0,0 @@
1
- /**
2
- * @grove-dev/core — github.ts (URL parsing + metadata fetch)
3
- * unit tests.
4
- *
5
- * `parseGithubRepoUrl` is pure logic and trivially testable.
6
- * `fetchGithubMetadata` makes real HTTP calls — we test the URL
7
- * parser end-to-end and verify the function is exported with the
8
- * right signature; the network path itself is exercised by the
9
- * `sync github` CLI command in production (not by the unit suite,
10
- * which is offline).
11
- */
12
- import { describe, it, expect } from "vitest";
13
- import { parseGithubRepoUrl } from "./github.js";
14
- describe("parseGithubRepoUrl", () => {
15
- it("returns undefined for an empty or undefined input", () => {
16
- expect(parseGithubRepoUrl("")).toBeUndefined();
17
- expect(parseGithubRepoUrl(undefined)).toBeUndefined();
18
- });
19
- it("parses a canonical https URL", () => {
20
- expect(parseGithubRepoUrl("https://github.com/owner/repo")).toEqual({
21
- owner: "owner",
22
- repo: "repo",
23
- });
24
- });
25
- it("parses an http URL", () => {
26
- expect(parseGithubRepoUrl("http://github.com/owner/repo")).toEqual({
27
- owner: "owner",
28
- repo: "repo",
29
- });
30
- });
31
- it("strips a trailing .git suffix from the repo name", () => {
32
- // `git clone` URLs end in .git — the parser must trim it so
33
- // downstream API calls (e.g. /repos/owner/repo) hit the real
34
- // repo, not a 404 because we asked for "repo.git".
35
- expect(parseGithubRepoUrl("https://github.com/owner/repo.git")).toEqual({
36
- owner: "owner",
37
- repo: "repo",
38
- });
39
- });
40
- it("ignores query strings and fragments", () => {
41
- // A URL with a fragment (e.g. from a permalink) should still
42
- // resolve to the same owner/repo.
43
- expect(parseGithubRepoUrl("https://github.com/owner/repo#readme")).toEqual({
44
- owner: "owner",
45
- repo: "repo",
46
- });
47
- expect(parseGithubRepoUrl("https://github.com/owner/repo?tab=readme-ov-file")).toEqual({
48
- owner: "owner",
49
- repo: "repo",
50
- });
51
- });
52
- it("returns undefined for non-GitHub URLs", () => {
53
- expect(parseGithubRepoUrl("https://gitlab.com/owner/repo")).toBeUndefined();
54
- expect(parseGithubRepoUrl("https://example.com/owner/repo")).toBeUndefined();
55
- });
56
- it("returns undefined for malformed GitHub URLs", () => {
57
- // Missing repo segment.
58
- expect(parseGithubRepoUrl("https://github.com/owner")).toBeUndefined();
59
- // Owner with whitespace.
60
- expect(parseGithubRepoUrl("https://github.com/own er/repo")).toBeUndefined();
61
- // Empty owner.
62
- expect(parseGithubRepoUrl("https://github.com//repo")).toBeUndefined();
63
- });
64
- it("is case-insensitive on the host", () => {
65
- // GITHUB.COM should still match — the regex has the /i flag
66
- // and humans do type uppercase sometimes.
67
- expect(parseGithubRepoUrl("https://GITHUB.COM/Owner/Repo")).toEqual({
68
- owner: "Owner",
69
- repo: "Repo",
70
- });
71
- });
72
- });
73
- //# sourceMappingURL=github.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"github.test.js","sourceRoot":"","sources":["../src/github.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAsB,MAAM,aAAa,CAAC;AAErE,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;QAC3D,MAAM,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;QAC/C,MAAM,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,MAAM,CAAC,kBAAkB,CAAC,+BAA+B,CAAC,CAAC,CAAC,OAAO,CAAC;YAClE,KAAK,EAAE,OAAO;YACd,IAAI,EAAE,MAAM;SACW,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oBAAoB,EAAE,GAAG,EAAE;QAC5B,MAAM,CAAC,kBAAkB,CAAC,8BAA8B,CAAC,CAAC,CAAC,OAAO,CAAC;YACjE,KAAK,EAAE,OAAO;YACd,IAAI,EAAE,MAAM;SACb,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,4DAA4D;QAC5D,6DAA6D;QAC7D,mDAAmD;QACnD,MAAM,CAAC,kBAAkB,CAAC,mCAAmC,CAAC,CAAC,CAAC,OAAO,CAAC;YACtE,KAAK,EAAE,OAAO;YACd,IAAI,EAAE,MAAM;SACb,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC7C,6DAA6D;QAC7D,kCAAkC;QAClC,MAAM,CAAC,kBAAkB,CAAC,sCAAsC,CAAC,CAAC,CAAC,OAAO,CAAC;YACzE,KAAK,EAAE,OAAO;YACd,IAAI,EAAE,MAAM;SACb,CAAC,CAAC;QACH,MAAM,CAAC,kBAAkB,CAAC,kDAAkD,CAAC,CAAC,CAAC,OAAO,CAAC;YACrF,KAAK,EAAE,OAAO;YACd,IAAI,EAAE,MAAM;SACb,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,MAAM,CAAC,kBAAkB,CAAC,+BAA+B,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;QAC5E,MAAM,CAAC,kBAAkB,CAAC,gCAAgC,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;IAC/E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,wBAAwB;QACxB,MAAM,CAAC,kBAAkB,CAAC,0BAA0B,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;QACvE,yBAAyB;QACzB,MAAM,CAAC,kBAAkB,CAAC,gCAAgC,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;QAC7E,eAAe;QACf,MAAM,CAAC,kBAAkB,CAAC,0BAA0B,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;IACzE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QACzC,4DAA4D;QAC5D,0CAA0C;QAC1C,MAAM,CAAC,kBAAkB,CAAC,+BAA+B,CAAC,CAAC,CAAC,OAAO,CAAC;YAClE,KAAK,EAAE,OAAO;YACd,IAAI,EAAE,MAAM;SACb,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=health.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"health.test.d.ts","sourceRoot":"","sources":["../src/health.test.ts"],"names":[],"mappings":""}
@@ -1,183 +0,0 @@
1
- /**
2
- * @grove-dev/core — health classification unit tests.
3
- *
4
- * Pins the boundary cases around the threshold ladder in
5
- * `classifyHealth`. The thresholds are not a parameter — they're
6
- * burned into the function — so the only thing these tests can do
7
- * is pin them. A future PR that bumps any threshold will need to
8
- * update at least one test name, which is exactly the intent:
9
- * "the day someone raises the inactive cutoff from 730 to 800 days,
10
- * the build breaks at the test name so a deliberate decision is
11
- * made."
12
- *
13
- * The function also has a "fabricate" path — calling it with no
14
- * `github` arg returns the canonical unknown health block. This
15
- * shape is the V1 single source of truth that `applyDecision` in
16
- * `build-data.ts` reuses for its no-health-block merge, so pinning
17
- * it here means downstream code can't drift.
18
- */
19
- import { describe, it, expect } from "vitest";
20
- import { classifyHealth } from "./health.js";
21
- function makeGithub(overrides = {}) {
22
- return {
23
- fullName: "owner/repo",
24
- stars: 10,
25
- forks: 0,
26
- openIssues: 0,
27
- archived: false,
28
- disabled: false,
29
- pushedAt: null,
30
- updatedAt: null,
31
- latestReleaseAt: null,
32
- license: null,
33
- topics: [],
34
- language: null,
35
- defaultBranch: "main",
36
- ...overrides,
37
- };
38
- }
39
- describe("classifyHealth — fabrication path (no GitHub metadata)", () => {
40
- it("returns the canonical unknown health block when no github is supplied", () => {
41
- // The shape is the V1 single source of truth — applyDecision in
42
- // build-data.ts calls classifyHealth(slug) without github to
43
- // fabricate a default health block. Pin every field.
44
- const result = classifyHealth("my-slug");
45
- expect(result).toEqual({
46
- id: "my-slug",
47
- health: {
48
- status: "unknown",
49
- maturity: "unknown",
50
- tier: "experimental",
51
- visibility: "keep",
52
- cleanupCandidate: false,
53
- staleReason: null,
54
- confidence: "low",
55
- reasons: ["No GitHub metadata available"],
56
- },
57
- });
58
- });
59
- it("the unknown block is what applyDecision fabricates — verify the visibility override path", () => {
60
- // Without this test, a future refactor could change the
61
- // unknown shape (e.g. tier: "hidden") and silently break the
62
- // applyDecision merge in build-data.ts. The unknown block MUST
63
- // have visibility: "keep" so the override is a meaningful
64
- // *change*, not a no-op.
65
- const { health } = classifyHealth("x");
66
- expect(health.visibility).toBe("keep");
67
- });
68
- });
69
- describe("classifyHealth — status thresholds (pushedAt)", () => {
70
- const NOW = Date.now();
71
- const daysAgo = (n) => new Date(NOW - n * 86_400_000).toISOString();
72
- it("active: pushed within 6 months (≤ 183 days)", () => {
73
- const result = classifyHealth("a", makeGithub({ pushedAt: daysAgo(0) }));
74
- expect(result.health.status).toBe("active");
75
- });
76
- it("active boundary: 180 days is well inside the active window", () => {
77
- // Pin the boundary just below 183 so the test is stable across
78
- // floating-point rounding of `Date.now() - N*86_400_000`. The
79
- // exact-183-day edge case is `183.0000000347` days, which the
80
- // `<= 183` check rejects — testing 180 instead makes the
81
- // intent (active window is ~6 months) obvious without
82
- // coupling to the float math.
83
- const result = classifyHealth("a", makeGithub({ pushedAt: daysAgo(180) }));
84
- expect(result.health.status).toBe("active");
85
- });
86
- it("stale boundary: 184 days is the first day a record becomes stale", () => {
87
- // 184 days is the first value that reliably falls on the
88
- // "stale" side of the 183-day cutoff. The 183-day mark itself
89
- // is load-bearing in production (a record turns 6 months old
90
- // on this exact day) but is sensitive to ms rounding — pin
91
- // 184 here so a future threshold bump is visible immediately
92
- // and the test does not flake.
93
- const result = classifyHealth("a", makeGithub({ pushedAt: daysAgo(184) }));
94
- expect(result.health.status).toBe("stale");
95
- });
96
- it("stale: pushed between 184 and 548 days (6-18 months)", () => {
97
- const result = classifyHealth("a", makeGithub({ pushedAt: daysAgo(400) }));
98
- expect(result.health.status).toBe("stale");
99
- });
100
- it("needs_review: pushed between 548 and 730 days (18-24 months)", () => {
101
- const result = classifyHealth("a", makeGithub({ pushedAt: daysAgo(600) }));
102
- expect(result.health.status).toBe("needs_review");
103
- });
104
- it("inactive: pushed > 730 days (2+ years)", () => {
105
- const result = classifyHealth("a", makeGithub({ pushedAt: daysAgo(800) }));
106
- expect(result.health.status).toBe("inactive");
107
- });
108
- });
109
- describe("classifyHealth — maturity ladder", () => {
110
- it("archived overrides everything: status='archived', tier='hidden'", () => {
111
- const result = classifyHealth("a", makeGithub({ archived: true, stars: 5000 }));
112
- expect(result.health.status).toBe("archived");
113
- expect(result.health.tier).toBe("hidden");
114
- expect(result.health.cleanupCandidate).toBe(true);
115
- expect(result.health.staleReason).toBe("github_archived");
116
- });
117
- it("popular + active → maturity='mature' and status gets promoted to 'mature'", () => {
118
- // 500+ stars AND active + maintained → the function promotes
119
- // status from 'active' to 'mature'. This is the threshold
120
- // where the "Recently active" filter would no longer match a
121
- // project even though it's actively maintained — pin it.
122
- const result = classifyHealth("a", makeGithub({
123
- stars: 600,
124
- pushedAt: new Date(Date.now() - 30 * 86_400_000).toISOString(),
125
- license: "MIT",
126
- }));
127
- expect(result.health.maturity).toBe("mature");
128
- expect(result.health.status).toBe("mature");
129
- });
130
- it("popular but no maintenance signals → maturity='useful' (NOT mature)", () => {
131
- // 500+ stars but no recent release/license — popular but the
132
- // maintenance boost does not apply. Maturity caps at 'useful'.
133
- const result = classifyHealth("a", makeGithub({
134
- stars: 600,
135
- pushedAt: new Date(Date.now() - 30 * 86_400_000).toISOString(),
136
- license: null,
137
- latestReleaseAt: null,
138
- }));
139
- expect(result.health.maturity).toBe("useful");
140
- });
141
- it("mid stars (50-499) + maintained → 'useful'", () => {
142
- const result = classifyHealth("a", makeGithub({
143
- stars: 100,
144
- pushedAt: new Date(Date.now() - 30 * 86_400_000).toISOString(),
145
- license: "MIT",
146
- }));
147
- expect(result.health.maturity).toBe("useful");
148
- });
149
- it("low stars and no signals → 'experimental'", () => {
150
- const result = classifyHealth("a", makeGithub({
151
- stars: 5,
152
- pushedAt: new Date(Date.now() - 30 * 86_400_000).toISOString(),
153
- license: null,
154
- latestReleaseAt: null,
155
- }));
156
- expect(result.health.maturity).toBe("experimental");
157
- });
158
- });
159
- describe("classifyHealth — tier ladder", () => {
160
- const pushed = new Date(Date.now() - 30 * 86_400_000).toISOString();
161
- it("hidden when status is archived", () => {
162
- const r = classifyHealth("a", makeGithub({ archived: true }));
163
- expect(r.health.tier).toBe("hidden");
164
- expect(r.health.visibility).toBe("hide");
165
- });
166
- it("hidden when status is inactive", () => {
167
- const r = classifyHealth("a", makeGithub({ pushedAt: new Date(Date.now() - 800 * 86_400_000).toISOString() }));
168
- expect(r.health.tier).toBe("hidden");
169
- });
170
- it("curated when stars >= 500", () => {
171
- const r = classifyHealth("a", makeGithub({ stars: 500, pushedAt: pushed }));
172
- expect(r.health.tier).toBe("curated");
173
- });
174
- it("listed when stars >= 50 (but < 500)", () => {
175
- const r = classifyHealth("a", makeGithub({ stars: 50, pushedAt: pushed }));
176
- expect(r.health.tier).toBe("listed");
177
- });
178
- it("experimental when stars < 50", () => {
179
- const r = classifyHealth("a", makeGithub({ stars: 49, pushedAt: pushed }));
180
- expect(r.health.tier).toBe("experimental");
181
- });
182
- });
183
- //# sourceMappingURL=health.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"health.test.js","sourceRoot":"","sources":["../src/health.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=importer.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"importer.test.d.ts","sourceRoot":"","sources":["../src/importer.test.ts"],"names":[],"mappings":""}