@adonisjs/content 1.3.0 → 1.5.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.
- package/README.md +48 -1
- package/build/chunk-WO5VTK7D.js +331 -0
- package/build/index.d.ts +1 -0
- package/build/index.js +5 -1
- package/build/src/debug.d.ts +1 -1
- package/build/src/loaders/main.d.ts +30 -2
- package/build/src/loaders/main.js +210 -421
- package/build/src/loaders/oss_stats.d.ts +66 -0
- package/build/src/types.d.ts +61 -0
- package/build/src/utils.d.ts +98 -0
- package/package.json +15 -15
|
@@ -1,229 +1,163 @@
|
|
|
1
|
+
import {
|
|
2
|
+
aggregateInstalls,
|
|
3
|
+
aggregateStars,
|
|
4
|
+
createCache,
|
|
5
|
+
fetchAllSponsors,
|
|
6
|
+
fetchContributorsForOrg,
|
|
7
|
+
fetchReleases,
|
|
8
|
+
mergeArrays
|
|
9
|
+
} from "../../chunk-WO5VTK7D.js";
|
|
1
10
|
import {
|
|
2
11
|
debug_default
|
|
3
12
|
} from "../../chunk-LB6JFRVG.js";
|
|
4
13
|
|
|
5
|
-
// src/loaders/
|
|
6
|
-
import dayjs from "dayjs";
|
|
14
|
+
// src/loaders/json.ts
|
|
7
15
|
import vine from "@vinejs/vine";
|
|
8
16
|
import { dirname } from "path";
|
|
9
|
-
import {
|
|
17
|
+
import { readFile } from "fs/promises";
|
|
18
|
+
var JsonLoader = class {
|
|
19
|
+
/** Path to the JSON file to load */
|
|
20
|
+
#source;
|
|
21
|
+
/**
|
|
22
|
+
* Creates a new JSON loader instance.
|
|
23
|
+
*
|
|
24
|
+
* @param source - Absolute or relative path to the JSON file
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* const loader = new JsonLoader('./data/menu.json')
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
constructor(source) {
|
|
32
|
+
this.#source = source;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Loads and validates JSON data from the configured file.
|
|
36
|
+
* The directory of the source file is provided as metadata during validation.
|
|
37
|
+
*
|
|
38
|
+
* @param schema - VineJS schema to validate the loaded JSON data against
|
|
39
|
+
* @param metadata - Optional metadata to pass to the validator
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* const data = await loader.load(menuSchema)
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
async load(schema, metadata) {
|
|
47
|
+
const menuFileRoot = dirname(this.#source);
|
|
48
|
+
const menu = JSON.parse(await readFile(this.#source, "utf-8"));
|
|
49
|
+
debug_default('loading file "%s"', this.#source);
|
|
50
|
+
return vine.validate({ schema, data: menu, meta: { menuFileRoot, ...metadata } });
|
|
51
|
+
}
|
|
52
|
+
};
|
|
10
53
|
|
|
11
|
-
// src/
|
|
12
|
-
import
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
name
|
|
45
|
-
avatarUrl
|
|
46
|
-
url
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
pageInfo {
|
|
51
|
-
hasNextPage
|
|
52
|
-
endCursor
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
`;
|
|
58
|
-
while (hasNext) {
|
|
59
|
-
const data = await graphql(query, {
|
|
60
|
-
headers: {
|
|
61
|
-
authorization: `token ${ghToken}`
|
|
62
|
-
},
|
|
63
|
-
login,
|
|
64
|
-
cursor
|
|
54
|
+
// src/loaders/oss_stats.ts
|
|
55
|
+
import vine2 from "@vinejs/vine";
|
|
56
|
+
var OssStatsLoader = class {
|
|
57
|
+
/** Configuration options for the OSS stats loader */
|
|
58
|
+
#options;
|
|
59
|
+
/** Cache instance for storing and retrieving OSS stats data */
|
|
60
|
+
#cache;
|
|
61
|
+
/**
|
|
62
|
+
* Creates a new OSS stats loader instance.
|
|
63
|
+
*
|
|
64
|
+
* @param options - Configuration options for loading OSS statistics
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```ts
|
|
68
|
+
* const loader = new OssStatsLoader({
|
|
69
|
+
* outputPath: './cache/oss-stats.json',
|
|
70
|
+
* refresh: 'weekly',
|
|
71
|
+
* sources: [
|
|
72
|
+
* {
|
|
73
|
+
* type: 'github',
|
|
74
|
+
* org: 'adonisjs',
|
|
75
|
+
* ghToken: process.env.GITHUB_TOKEN
|
|
76
|
+
* }
|
|
77
|
+
* ]
|
|
78
|
+
* })
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
constructor(options) {
|
|
82
|
+
this.#options = options;
|
|
83
|
+
this.#cache = createCache({
|
|
84
|
+
key: "ossStats",
|
|
85
|
+
outputPath: options.outputPath,
|
|
86
|
+
refresh: options.refresh
|
|
65
87
|
});
|
|
66
|
-
const root = isOrg ? data.organization : data.user;
|
|
67
|
-
if (!root) {
|
|
68
|
-
break;
|
|
69
|
-
}
|
|
70
|
-
const conn = root.sponsorshipsAsMaintainer;
|
|
71
|
-
if (!conn || !conn.nodes) {
|
|
72
|
-
break;
|
|
73
|
-
}
|
|
74
|
-
for (const node of conn.nodes) {
|
|
75
|
-
const sponsorEntity = node.sponsorEntity;
|
|
76
|
-
allSponsors.push({
|
|
77
|
-
id: node.id,
|
|
78
|
-
createdAt: node.createdAt,
|
|
79
|
-
privacyLevel: node.privacyLevel,
|
|
80
|
-
tierName: node.tier?.name ?? null,
|
|
81
|
-
tierMonthlyPriceInCents: node.tier?.monthlyPriceInCents ?? null,
|
|
82
|
-
sponsorType: sponsorEntity.__typename,
|
|
83
|
-
sponsorLogin: sponsorEntity.login,
|
|
84
|
-
sponsorName: sponsorEntity.name ?? null,
|
|
85
|
-
sponsorAvatarUrl: sponsorEntity.avatarUrl ?? null,
|
|
86
|
-
sponsorUrl: sponsorEntity.url ?? null
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
hasNext = conn.pageInfo.hasNextPage;
|
|
90
|
-
cursor = conn.pageInfo.endCursor;
|
|
91
88
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
endCursor
|
|
124
|
-
hasNextPage
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
pageInfo {
|
|
129
|
-
endCursor
|
|
130
|
-
hasNextPage
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
}
|
|
89
|
+
/**
|
|
90
|
+
* Fetches and aggregates statistics from all configured sources.
|
|
91
|
+
* Processes GitHub and npm sources separately, then combines the results.
|
|
92
|
+
*
|
|
93
|
+
* @returns Aggregated statistics with total stars and installs
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* ```ts
|
|
97
|
+
* const stats = await loader.fetchStats()
|
|
98
|
+
* console.log(`Total stars: ${stats.stars}`)
|
|
99
|
+
* console.log(`Total installs: ${stats.installs}`)
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
async #fetchStats() {
|
|
103
|
+
const aggregates = [];
|
|
104
|
+
for (const source of this.#options.sources) {
|
|
105
|
+
if (typeof source === "function") {
|
|
106
|
+
aggregates.push(await source());
|
|
107
|
+
} else if (source.type === "github") {
|
|
108
|
+
aggregates.push({
|
|
109
|
+
key: "stars",
|
|
110
|
+
count: await aggregateStars({
|
|
111
|
+
org: source.org,
|
|
112
|
+
ghToken: source.ghToken
|
|
113
|
+
})
|
|
114
|
+
});
|
|
115
|
+
} else if (source.type === "npm") {
|
|
116
|
+
aggregates.push({
|
|
117
|
+
key: "installs",
|
|
118
|
+
count: await aggregateInstalls(source.packages)
|
|
119
|
+
});
|
|
134
120
|
}
|
|
135
|
-
`;
|
|
136
|
-
const data = await graphql(query, {
|
|
137
|
-
headers: {
|
|
138
|
-
authorization: `token ${ghToken}`
|
|
139
|
-
},
|
|
140
|
-
cursor: orgCursor
|
|
141
|
-
});
|
|
142
|
-
for (const repo of data.organization.repositories.nodes) {
|
|
143
|
-
const filtered = repo.releases.nodes.filter((r) => {
|
|
144
|
-
if (!filters) {
|
|
145
|
-
return true;
|
|
146
|
-
}
|
|
147
|
-
let pickRelease = true;
|
|
148
|
-
if (filters.nameDoesntInclude) {
|
|
149
|
-
pickRelease = !filters.nameDoesntInclude.some((substr) => r.name.includes(substr));
|
|
150
|
-
}
|
|
151
|
-
if (pickRelease && filters.nameIncludes) {
|
|
152
|
-
pickRelease = filters.nameIncludes.some((substr) => r.name.includes(substr));
|
|
153
|
-
}
|
|
154
|
-
return pickRelease;
|
|
155
|
-
}).map((r) => ({
|
|
156
|
-
repo: repo.name,
|
|
157
|
-
...r
|
|
158
|
-
}));
|
|
159
|
-
allReleases.push(...filtered);
|
|
160
|
-
}
|
|
161
|
-
hasMoreRepos = data.organization.repositories.pageInfo.hasNextPage;
|
|
162
|
-
orgCursor = data.organization.repositories.pageInfo.endCursor;
|
|
163
|
-
}
|
|
164
|
-
return allReleases;
|
|
165
|
-
}
|
|
166
|
-
async function fetchContributorsForOrg({
|
|
167
|
-
org,
|
|
168
|
-
ghToken
|
|
169
|
-
}) {
|
|
170
|
-
const REPO_PAGE_SIZE = 100;
|
|
171
|
-
const CONTRIB_PAGE_SIZE = 100;
|
|
172
|
-
const octokit = new Octokit({ auth: ghToken });
|
|
173
|
-
const repos = await octokit.paginate(octokit.repos.listForOrg, {
|
|
174
|
-
org,
|
|
175
|
-
type: "public",
|
|
176
|
-
per_page: REPO_PAGE_SIZE
|
|
177
|
-
});
|
|
178
|
-
const activeRepos = repos.filter((r) => !r.archived);
|
|
179
|
-
const result = [];
|
|
180
|
-
for (const repo of activeRepos) {
|
|
181
|
-
const repoName = repo.name;
|
|
182
|
-
try {
|
|
183
|
-
const contributors = await octokit.paginate(
|
|
184
|
-
octokit.repos.listContributors,
|
|
185
|
-
{
|
|
186
|
-
owner: org,
|
|
187
|
-
repo: repoName,
|
|
188
|
-
per_page: CONTRIB_PAGE_SIZE
|
|
189
|
-
},
|
|
190
|
-
(response) => response.data
|
|
191
|
-
);
|
|
192
|
-
contributors.forEach((c) => {
|
|
193
|
-
if (c.login) {
|
|
194
|
-
result.push({
|
|
195
|
-
login: c.login,
|
|
196
|
-
id: c.id,
|
|
197
|
-
avatar_url: c.avatar_url ?? null,
|
|
198
|
-
html_url: c.html_url ?? null,
|
|
199
|
-
contributions: c.contributions ?? 0
|
|
200
|
-
});
|
|
201
|
-
}
|
|
202
|
-
});
|
|
203
|
-
} catch (err) {
|
|
204
|
-
console.warn(
|
|
205
|
-
`Warning: failed to fetch contributors for ${org}/${repoName}: ${err?.message ?? err}`
|
|
206
|
-
);
|
|
207
121
|
}
|
|
122
|
+
return aggregates.reduce((result, { key, count }) => {
|
|
123
|
+
result[key] = count;
|
|
124
|
+
return result;
|
|
125
|
+
}, {});
|
|
208
126
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
127
|
+
/**
|
|
128
|
+
* Loads and validates OSS statistics data.
|
|
129
|
+
* Uses cached data if available and not expired, otherwise fetches fresh data
|
|
130
|
+
* from configured sources and updates the cache.
|
|
131
|
+
*
|
|
132
|
+
* @param schema - VineJS schema to validate the statistics data against
|
|
133
|
+
* @param metadata - Optional metadata to pass to the validator
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* ```ts
|
|
137
|
+
* const stats = await loader.load(ossStatsSchema)
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
async load(schema, metadata) {
|
|
141
|
+
let stats = await this.#cache.get();
|
|
142
|
+
if (!stats) {
|
|
143
|
+
stats = await this.#fetchStats();
|
|
144
|
+
await this.#cache.put(stats);
|
|
218
145
|
}
|
|
146
|
+
return vine2.validate({
|
|
147
|
+
schema,
|
|
148
|
+
data: stats,
|
|
149
|
+
meta: metadata
|
|
150
|
+
});
|
|
219
151
|
}
|
|
220
|
-
|
|
221
|
-
}
|
|
152
|
+
};
|
|
222
153
|
|
|
223
154
|
// src/loaders/gh_sponsors.ts
|
|
155
|
+
import vine3 from "@vinejs/vine";
|
|
224
156
|
var GithubSponsorsLoader = class {
|
|
225
157
|
/** Configuration options for the GitHub sponsors loader */
|
|
226
158
|
#options;
|
|
159
|
+
/** Cache instance for storing and retrieving sponsors data */
|
|
160
|
+
#cache;
|
|
227
161
|
/**
|
|
228
162
|
* Creates a new GitHub sponsors loader instance.
|
|
229
163
|
*
|
|
@@ -242,54 +176,11 @@ var GithubSponsorsLoader = class {
|
|
|
242
176
|
*/
|
|
243
177
|
constructor(options) {
|
|
244
178
|
this.#options = options;
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
*
|
|
251
|
-
* @internal
|
|
252
|
-
*/
|
|
253
|
-
async #loadExistingSponsors() {
|
|
254
|
-
try {
|
|
255
|
-
debug_default('loading existing sponsors file "%s"', this.#options.outputPath);
|
|
256
|
-
return JSON.parse(await readFile(this.#options.outputPath, "utf-8"));
|
|
257
|
-
} catch (error) {
|
|
258
|
-
if (error.code !== "ENOENT") {
|
|
259
|
-
throw error;
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
return null;
|
|
263
|
-
}
|
|
264
|
-
/**
|
|
265
|
-
* Writes sponsors to the cache file with the current timestamp.
|
|
266
|
-
* Creates the output directory if it doesn't exist.
|
|
267
|
-
*
|
|
268
|
-
* @param sponsors - Array of GitHub sponsors to cache
|
|
269
|
-
* @internal
|
|
270
|
-
*/
|
|
271
|
-
async #cacheSponsors(sponsors) {
|
|
272
|
-
debug_default('caching sponsors "%s"', this.#options.outputPath);
|
|
273
|
-
const fileContents = { lastFetched: (/* @__PURE__ */ new Date()).toISOString(), sponsors };
|
|
274
|
-
await mkdir(dirname(this.#options.outputPath), { recursive: true });
|
|
275
|
-
await writeFile(this.#options.outputPath, JSON.stringify(fileContents));
|
|
276
|
-
return fileContents;
|
|
277
|
-
}
|
|
278
|
-
/**
|
|
279
|
-
* Determines if the cached data has expired based on the refresh schedule.
|
|
280
|
-
*
|
|
281
|
-
* @param fetchDate - The date when data was last fetched
|
|
282
|
-
* @internal
|
|
283
|
-
*/
|
|
284
|
-
#isExpired(fetchDate) {
|
|
285
|
-
switch (this.#options.refresh) {
|
|
286
|
-
case "daily":
|
|
287
|
-
return dayjs().isAfter(fetchDate, "day");
|
|
288
|
-
case "weekly":
|
|
289
|
-
return dayjs().isAfter(fetchDate, "week");
|
|
290
|
-
case "monthly":
|
|
291
|
-
return dayjs().isAfter(fetchDate, "month");
|
|
292
|
-
}
|
|
179
|
+
this.#cache = createCache({
|
|
180
|
+
key: "sponsors",
|
|
181
|
+
outputPath: options.outputPath,
|
|
182
|
+
refresh: options.refresh
|
|
183
|
+
});
|
|
293
184
|
}
|
|
294
185
|
/**
|
|
295
186
|
* Loads and validates GitHub sponsors data.
|
|
@@ -305,28 +196,26 @@ var GithubSponsorsLoader = class {
|
|
|
305
196
|
* ```
|
|
306
197
|
*/
|
|
307
198
|
async load(schema, metadata) {
|
|
308
|
-
let
|
|
309
|
-
if (!
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
existingSponsors = await this.#cacheSponsors(sponsors);
|
|
199
|
+
let sponsors = await this.#cache.get();
|
|
200
|
+
if (!sponsors) {
|
|
201
|
+
sponsors = await fetchAllSponsors(this.#options);
|
|
202
|
+
await this.#cache.put(sponsors);
|
|
313
203
|
}
|
|
314
|
-
return
|
|
204
|
+
return vine3.validate({
|
|
315
205
|
schema,
|
|
316
|
-
data:
|
|
206
|
+
data: sponsors,
|
|
317
207
|
meta: metadata
|
|
318
208
|
});
|
|
319
209
|
}
|
|
320
210
|
};
|
|
321
211
|
|
|
322
212
|
// src/loaders/gh_releases.ts
|
|
323
|
-
import
|
|
324
|
-
import vine2 from "@vinejs/vine";
|
|
325
|
-
import { dirname as dirname2 } from "path";
|
|
326
|
-
import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
213
|
+
import vine4 from "@vinejs/vine";
|
|
327
214
|
var GithubReleasesLoader = class {
|
|
328
215
|
/** Configuration options for the GitHub release loader */
|
|
329
216
|
#options;
|
|
217
|
+
/** Cache instance for storing and retrieving releases data */
|
|
218
|
+
#cache;
|
|
330
219
|
/**
|
|
331
220
|
* Creates a new GitHub release loader instance.
|
|
332
221
|
*
|
|
@@ -344,54 +233,11 @@ var GithubReleasesLoader = class {
|
|
|
344
233
|
*/
|
|
345
234
|
constructor(options) {
|
|
346
235
|
this.#options = options;
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
*
|
|
353
|
-
* @internal
|
|
354
|
-
*/
|
|
355
|
-
async #loadExistingReleases() {
|
|
356
|
-
try {
|
|
357
|
-
debug_default('loading existing releases file "%s"', this.#options.outputPath);
|
|
358
|
-
return JSON.parse(await readFile2(this.#options.outputPath, "utf-8"));
|
|
359
|
-
} catch (error) {
|
|
360
|
-
if (error.code !== "ENOENT") {
|
|
361
|
-
throw error;
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
return null;
|
|
365
|
-
}
|
|
366
|
-
/**
|
|
367
|
-
* Writes releases to the cache file with the current timestamp.
|
|
368
|
-
* Creates the output directory if it doesn't exist.
|
|
369
|
-
*
|
|
370
|
-
* @param releases - Array of GitHub releases to cache
|
|
371
|
-
* @internal
|
|
372
|
-
*/
|
|
373
|
-
async #cacheReleases(releases) {
|
|
374
|
-
debug_default('caching releasing "%s"', this.#options.outputPath);
|
|
375
|
-
const fileContents = { lastFetched: (/* @__PURE__ */ new Date()).toISOString(), releases };
|
|
376
|
-
await mkdir2(dirname2(this.#options.outputPath), { recursive: true });
|
|
377
|
-
await writeFile2(this.#options.outputPath, JSON.stringify(fileContents));
|
|
378
|
-
return fileContents;
|
|
379
|
-
}
|
|
380
|
-
/**
|
|
381
|
-
* Determines if the cached data has expired based on the refresh schedule.
|
|
382
|
-
*
|
|
383
|
-
* @param fetchDate - The date when data was last fetched
|
|
384
|
-
* @internal
|
|
385
|
-
*/
|
|
386
|
-
#isExpired(fetchDate) {
|
|
387
|
-
switch (this.#options.refresh) {
|
|
388
|
-
case "daily":
|
|
389
|
-
return dayjs2().isAfter(fetchDate, "day");
|
|
390
|
-
case "weekly":
|
|
391
|
-
return dayjs2().isAfter(fetchDate, "week");
|
|
392
|
-
case "monthly":
|
|
393
|
-
return dayjs2().isAfter(fetchDate, "month");
|
|
394
|
-
}
|
|
236
|
+
this.#cache = createCache({
|
|
237
|
+
key: "releases",
|
|
238
|
+
outputPath: options.outputPath,
|
|
239
|
+
refresh: options.refresh
|
|
240
|
+
});
|
|
395
241
|
}
|
|
396
242
|
/**
|
|
397
243
|
* Loads and validates GitHub releases data.
|
|
@@ -407,29 +253,27 @@ var GithubReleasesLoader = class {
|
|
|
407
253
|
* ```
|
|
408
254
|
*/
|
|
409
255
|
async load(schema, metadata) {
|
|
410
|
-
let
|
|
411
|
-
if (!
|
|
412
|
-
|
|
413
|
-
const
|
|
414
|
-
|
|
415
|
-
existingReleases = await this.#cacheReleases(mergedReleases);
|
|
256
|
+
let cachedReleases = await this.#cache.get();
|
|
257
|
+
if (!cachedReleases) {
|
|
258
|
+
const freshReleases = await fetchReleases(this.#options);
|
|
259
|
+
const mergedReleases = cachedReleases ? mergeArrays(cachedReleases, freshReleases, "url") : freshReleases;
|
|
260
|
+
cachedReleases = await this.#cache.put(mergedReleases);
|
|
416
261
|
}
|
|
417
|
-
return
|
|
262
|
+
return vine4.validate({
|
|
418
263
|
schema,
|
|
419
|
-
data:
|
|
264
|
+
data: cachedReleases,
|
|
420
265
|
meta: metadata
|
|
421
266
|
});
|
|
422
267
|
}
|
|
423
268
|
};
|
|
424
269
|
|
|
425
270
|
// src/loaders/gh_contributors.ts
|
|
426
|
-
import
|
|
427
|
-
import vine3 from "@vinejs/vine";
|
|
428
|
-
import { dirname as dirname3 } from "path";
|
|
429
|
-
import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
|
|
271
|
+
import vine5 from "@vinejs/vine";
|
|
430
272
|
var GithubContributorsLoader = class {
|
|
431
273
|
/** Configuration options for the GitHub contributors loader */
|
|
432
274
|
#options;
|
|
275
|
+
/** Cache instance for storing and retrieving contributors data */
|
|
276
|
+
#cache;
|
|
433
277
|
/**
|
|
434
278
|
* Creates a new GitHub contributors loader instance.
|
|
435
279
|
*
|
|
@@ -447,54 +291,11 @@ var GithubContributorsLoader = class {
|
|
|
447
291
|
*/
|
|
448
292
|
constructor(options) {
|
|
449
293
|
this.#options = options;
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
*
|
|
456
|
-
* @internal
|
|
457
|
-
*/
|
|
458
|
-
async #loadExistingContributors() {
|
|
459
|
-
try {
|
|
460
|
-
debug_default('loading existing contributors file "%s"', this.#options.outputPath);
|
|
461
|
-
return JSON.parse(await readFile3(this.#options.outputPath, "utf-8"));
|
|
462
|
-
} catch (error) {
|
|
463
|
-
if (error.code !== "ENOENT") {
|
|
464
|
-
throw error;
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
return null;
|
|
468
|
-
}
|
|
469
|
-
/**
|
|
470
|
-
* Writes contributors to the cache file with the current timestamp.
|
|
471
|
-
* Creates the output directory if it doesn't exist.
|
|
472
|
-
*
|
|
473
|
-
* @param contributors - Array of GitHub contributors to cache
|
|
474
|
-
* @internal
|
|
475
|
-
*/
|
|
476
|
-
async #cacheContributors(contributors) {
|
|
477
|
-
debug_default('caching contributors "%s"', this.#options.outputPath);
|
|
478
|
-
const fileContents = { lastFetched: (/* @__PURE__ */ new Date()).toISOString(), contributors };
|
|
479
|
-
await mkdir3(dirname3(this.#options.outputPath), { recursive: true });
|
|
480
|
-
await writeFile3(this.#options.outputPath, JSON.stringify(fileContents));
|
|
481
|
-
return fileContents;
|
|
482
|
-
}
|
|
483
|
-
/**
|
|
484
|
-
* Determines if the cached data has expired based on the refresh schedule.
|
|
485
|
-
*
|
|
486
|
-
* @param fetchDate - The date when data was last fetched
|
|
487
|
-
* @internal
|
|
488
|
-
*/
|
|
489
|
-
#isExpired(fetchDate) {
|
|
490
|
-
switch (this.#options.refresh) {
|
|
491
|
-
case "daily":
|
|
492
|
-
return dayjs3().isAfter(fetchDate, "day");
|
|
493
|
-
case "weekly":
|
|
494
|
-
return dayjs3().isAfter(fetchDate, "week");
|
|
495
|
-
case "monthly":
|
|
496
|
-
return dayjs3().isAfter(fetchDate, "month");
|
|
497
|
-
}
|
|
294
|
+
this.#cache = createCache({
|
|
295
|
+
key: "contributors",
|
|
296
|
+
outputPath: options.outputPath,
|
|
297
|
+
refresh: options.refresh
|
|
298
|
+
});
|
|
498
299
|
}
|
|
499
300
|
/**
|
|
500
301
|
* Loads and validates GitHub contributors data.
|
|
@@ -510,60 +311,19 @@ var GithubContributorsLoader = class {
|
|
|
510
311
|
* ```
|
|
511
312
|
*/
|
|
512
313
|
async load(schema, metadata) {
|
|
513
|
-
let
|
|
514
|
-
if (!
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
existingContributors = await this.#cacheContributors(contributors);
|
|
314
|
+
let contributors = await this.#cache.get();
|
|
315
|
+
if (!contributors) {
|
|
316
|
+
contributors = await fetchContributorsForOrg(this.#options);
|
|
317
|
+
await this.#cache.put(contributors);
|
|
518
318
|
}
|
|
519
|
-
return
|
|
319
|
+
return vine5.validate({
|
|
520
320
|
schema,
|
|
521
|
-
data:
|
|
321
|
+
data: contributors,
|
|
522
322
|
meta: metadata
|
|
523
323
|
});
|
|
524
324
|
}
|
|
525
325
|
};
|
|
526
326
|
|
|
527
|
-
// src/loaders/json.ts
|
|
528
|
-
import vine4 from "@vinejs/vine";
|
|
529
|
-
import { dirname as dirname4 } from "path";
|
|
530
|
-
import { readFile as readFile4 } from "fs/promises";
|
|
531
|
-
var JsonLoader = class {
|
|
532
|
-
/** Path to the JSON file to load */
|
|
533
|
-
#source;
|
|
534
|
-
/**
|
|
535
|
-
* Creates a new JSON loader instance.
|
|
536
|
-
*
|
|
537
|
-
* @param source - Absolute or relative path to the JSON file
|
|
538
|
-
*
|
|
539
|
-
* @example
|
|
540
|
-
* ```ts
|
|
541
|
-
* const loader = new JsonLoader('./data/menu.json')
|
|
542
|
-
* ```
|
|
543
|
-
*/
|
|
544
|
-
constructor(source) {
|
|
545
|
-
this.#source = source;
|
|
546
|
-
}
|
|
547
|
-
/**
|
|
548
|
-
* Loads and validates JSON data from the configured file.
|
|
549
|
-
* The directory of the source file is provided as metadata during validation.
|
|
550
|
-
*
|
|
551
|
-
* @param schema - VineJS schema to validate the loaded JSON data against
|
|
552
|
-
* @param metadata - Optional metadata to pass to the validator
|
|
553
|
-
*
|
|
554
|
-
* @example
|
|
555
|
-
* ```ts
|
|
556
|
-
* const data = await loader.load(menuSchema)
|
|
557
|
-
* ```
|
|
558
|
-
*/
|
|
559
|
-
async load(schema, metadata) {
|
|
560
|
-
const menuFileRoot = dirname4(this.#source);
|
|
561
|
-
const menu = JSON.parse(await readFile4(this.#source, "utf-8"));
|
|
562
|
-
debug_default('loading file "%s"', this.#source);
|
|
563
|
-
return vine4.validate({ schema, data: menu, meta: { menuFileRoot, ...metadata } });
|
|
564
|
-
}
|
|
565
|
-
};
|
|
566
|
-
|
|
567
327
|
// src/loaders/main.ts
|
|
568
328
|
var loaders = {
|
|
569
329
|
/**
|
|
@@ -624,6 +384,35 @@ var loaders = {
|
|
|
624
384
|
ghReleases(options) {
|
|
625
385
|
return new GithubReleasesLoader(options);
|
|
626
386
|
},
|
|
387
|
+
/**
|
|
388
|
+
* Creates an OSS statistics loader instance.
|
|
389
|
+
*
|
|
390
|
+
* @param options - Configuration options for the OSS stats loader
|
|
391
|
+
*
|
|
392
|
+
* @example
|
|
393
|
+
* ```ts
|
|
394
|
+
* const loader = loaders.ossStats({
|
|
395
|
+
* outputPath: './cache/oss-stats.json',
|
|
396
|
+
* refresh: 'daily',
|
|
397
|
+
* sources: [
|
|
398
|
+
* {
|
|
399
|
+
* type: 'github',
|
|
400
|
+
* org: 'adonisjs',
|
|
401
|
+
* ghToken: process.env.GITHUB_TOKEN
|
|
402
|
+
* },
|
|
403
|
+
* {
|
|
404
|
+
* type: 'npm',
|
|
405
|
+
* packages: [
|
|
406
|
+
* { name: '@adonisjs/core', startDate: '2020-01-01' }
|
|
407
|
+
* ]
|
|
408
|
+
* }
|
|
409
|
+
* ]
|
|
410
|
+
* })
|
|
411
|
+
* ```
|
|
412
|
+
*/
|
|
413
|
+
ossStats(options) {
|
|
414
|
+
return new OssStatsLoader(options);
|
|
415
|
+
},
|
|
627
416
|
/**
|
|
628
417
|
* Creates a JSON file loader instance.
|
|
629
418
|
*
|