@ox-content/vite-plugin 2.70.0 → 2.71.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/dist/github.cjs +270 -290
- package/dist/github.cjs.map +1 -1
- package/dist/github.mjs +622 -2
- package/dist/github.mjs.map +1 -0
- package/dist/github2.mjs +2 -632
- package/dist/index.cjs +126 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +56 -18
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +56 -18
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +126 -4
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/dist/github2.mjs.map +0 -1
package/dist/github.cjs
CHANGED
|
@@ -5,38 +5,32 @@ rehype_parse = require_chunk.__toESM(rehype_parse, 1);
|
|
|
5
5
|
let rehype_stringify = require("rehype-stringify");
|
|
6
6
|
rehype_stringify = require_chunk.__toESM(rehype_stringify, 1);
|
|
7
7
|
let node_buffer = require("node:buffer");
|
|
8
|
-
//#region src/plugins/github.ts
|
|
9
|
-
/**
|
|
10
|
-
* GitHub Plugin - Repository and source code embedding
|
|
11
|
-
*
|
|
12
|
-
* Transforms <GitHub> components into static repository and source code cards
|
|
13
|
-
* by fetching data from GitHub API at build time.
|
|
14
|
-
*/
|
|
15
|
-
var github_exports = /* @__PURE__ */ require_chunk.__exportAll({
|
|
16
|
-
collectGitHubRepos: () => collectGitHubRepos,
|
|
17
|
-
collectGitHubSources: () => collectGitHubSources,
|
|
18
|
-
createGitHubPermalink: () => createGitHubPermalink,
|
|
19
|
-
fetchGitHubSource: () => fetchGitHubSource,
|
|
20
|
-
fetchRepoData: () => fetchRepoData,
|
|
21
|
-
isSafeGitHubRepo: () => isSafeGitHubRepo,
|
|
22
|
-
parseGitHubLineRange: () => parseGitHubLineRange,
|
|
23
|
-
parseGitHubPermalink: () => parseGitHubPermalink,
|
|
24
|
-
prefetchGitHubRepos: () => prefetchGitHubRepos,
|
|
25
|
-
prefetchGitHubSources: () => prefetchGitHubSources,
|
|
26
|
-
transformGitHub: () => transformGitHub
|
|
27
|
-
});
|
|
28
|
-
const defaultOptions = {
|
|
29
|
-
token: "",
|
|
30
|
-
cache: true,
|
|
31
|
-
cacheTTL: 36e5,
|
|
32
|
-
maxSourceBytes: 2e5,
|
|
33
|
-
maxSourceLines: 120
|
|
34
|
-
};
|
|
35
|
-
const repoCache = /* @__PURE__ */ new Map();
|
|
36
|
-
const sourceCache = /* @__PURE__ */ new Map();
|
|
8
|
+
//#region src/plugins/github/validation.ts
|
|
37
9
|
const GITHUB_REPO_RE = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/;
|
|
38
|
-
|
|
39
|
-
|
|
10
|
+
function hasControlChar(value) {
|
|
11
|
+
for (let index = 0; index < value.length; index++) {
|
|
12
|
+
const code = value.charCodeAt(index);
|
|
13
|
+
if (code <= 31 || code === 127) return true;
|
|
14
|
+
}
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
function isSafeGitHubRepo(repo) {
|
|
18
|
+
return GITHUB_REPO_RE.test(repo) && !repo.split("/").some((part) => part === "." || part === "..");
|
|
19
|
+
}
|
|
20
|
+
function isSafeGitHubRef(ref) {
|
|
21
|
+
return Boolean(ref) && !hasControlChar(ref) && !hasUnsafePathSegment(ref);
|
|
22
|
+
}
|
|
23
|
+
function isSafeGitHubPath(path) {
|
|
24
|
+
return Boolean(path) && !hasControlChar(path) && !hasUnsafePathSegment(path);
|
|
25
|
+
}
|
|
26
|
+
function hasUnsafePathSegment(value) {
|
|
27
|
+
return value.split("/").some((part) => !part || part === "." || part === ".." || part.includes("\\"));
|
|
28
|
+
}
|
|
29
|
+
function encodePath(path) {
|
|
30
|
+
return path.split("/").map(encodeURIComponent).join("/");
|
|
31
|
+
}
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region src/plugins/github/source.ts
|
|
40
34
|
const EXTENSION_LANGUAGE_MAP = new Map([
|
|
41
35
|
["cjs", "javascript"],
|
|
42
36
|
["css", "css"],
|
|
@@ -60,28 +54,6 @@ const EXTENSION_LANGUAGE_MAP = new Map([
|
|
|
60
54
|
["yaml", "yaml"],
|
|
61
55
|
["yml", "yaml"]
|
|
62
56
|
]);
|
|
63
|
-
function hasControlChar(value) {
|
|
64
|
-
for (let index = 0; index < value.length; index++) {
|
|
65
|
-
const code = value.charCodeAt(index);
|
|
66
|
-
if (code <= 31 || code === 127) return true;
|
|
67
|
-
}
|
|
68
|
-
return false;
|
|
69
|
-
}
|
|
70
|
-
function isSafeGitHubRepo(repo) {
|
|
71
|
-
return GITHUB_REPO_RE.test(repo) && !repo.split("/").some((part) => part === "." || part === "..");
|
|
72
|
-
}
|
|
73
|
-
function isSafeGitHubRef(ref) {
|
|
74
|
-
return Boolean(ref) && !hasControlChar(ref) && !hasUnsafePathSegment(ref);
|
|
75
|
-
}
|
|
76
|
-
function isSafeGitHubPath(path) {
|
|
77
|
-
return Boolean(path) && !hasControlChar(path) && !hasUnsafePathSegment(path);
|
|
78
|
-
}
|
|
79
|
-
function hasUnsafePathSegment(value) {
|
|
80
|
-
return value.split("/").some((part) => !part || part === "." || part === ".." || part.includes("\\"));
|
|
81
|
-
}
|
|
82
|
-
function encodePath(path) {
|
|
83
|
-
return path.split("/").map(encodeURIComponent).join("/");
|
|
84
|
-
}
|
|
85
57
|
function sourceKey(source) {
|
|
86
58
|
return `${source.repo}@${source.ref}:${source.path}`;
|
|
87
59
|
}
|
|
@@ -134,21 +106,33 @@ function parseGitHubPermalink(value) {
|
|
|
134
106
|
permalink: createGitHubPermalink(source)
|
|
135
107
|
};
|
|
136
108
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
if (Array.isArray(value)) return value.join(" ");
|
|
109
|
+
function inferLanguage(path) {
|
|
110
|
+
const fileName = path.split("/").at(-1)?.toLowerCase() ?? "";
|
|
111
|
+
if (fileName === "dockerfile") return "dockerfile";
|
|
112
|
+
if (fileName === "makefile") return "makefile";
|
|
113
|
+
const extension = fileName.includes(".") ? fileName.split(".").at(-1) : void 0;
|
|
114
|
+
return extension ? EXTENSION_LANGUAGE_MAP.get(extension) ?? extension : null;
|
|
144
115
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
116
|
+
//#endregion
|
|
117
|
+
//#region src/plugins/github/types.ts
|
|
118
|
+
const defaultOptions = {
|
|
119
|
+
token: "",
|
|
120
|
+
cache: true,
|
|
121
|
+
cacheTTL: 36e5,
|
|
122
|
+
maxSourceBytes: 2e5,
|
|
123
|
+
maxSourceLines: 120
|
|
124
|
+
};
|
|
125
|
+
//#endregion
|
|
126
|
+
//#region src/plugins/github/api.ts
|
|
127
|
+
const repoCache = /* @__PURE__ */ new Map();
|
|
128
|
+
const sourceCache = /* @__PURE__ */ new Map();
|
|
129
|
+
function githubHeaders(options) {
|
|
130
|
+
const headers = {
|
|
131
|
+
Accept: "application/vnd.github.v3+json",
|
|
132
|
+
"User-Agent": "ox-content-github-plugin"
|
|
133
|
+
};
|
|
134
|
+
if (options.token) headers.Authorization = `Bearer ${options.token}`;
|
|
135
|
+
return headers;
|
|
152
136
|
}
|
|
153
137
|
/**
|
|
154
138
|
* Fetch repository data from GitHub API.
|
|
@@ -160,12 +144,7 @@ async function fetchRepoData(repo, options) {
|
|
|
160
144
|
if (cached && Date.now() - cached.timestamp < options.cacheTTL) return cached.data;
|
|
161
145
|
}
|
|
162
146
|
try {
|
|
163
|
-
const
|
|
164
|
-
Accept: "application/vnd.github.v3+json",
|
|
165
|
-
"User-Agent": "ox-content-github-plugin"
|
|
166
|
-
};
|
|
167
|
-
if (options.token) headers.Authorization = `Bearer ${options.token}`;
|
|
168
|
-
const response = await fetch(`https://api.github.com/repos/${repo}`, { headers });
|
|
147
|
+
const response = await fetch(`https://api.github.com/repos/${repo}`, { headers: githubHeaders(options) });
|
|
169
148
|
if (!response.ok) {
|
|
170
149
|
console.warn(`Failed to fetch GitHub repo ${repo}: ${response.status}`);
|
|
171
150
|
return null;
|
|
@@ -192,13 +171,8 @@ async function fetchGitHubSource(source, options) {
|
|
|
192
171
|
if (cached && Date.now() - cached.timestamp < options.cacheTTL) return cached.data;
|
|
193
172
|
}
|
|
194
173
|
try {
|
|
195
|
-
const headers = {
|
|
196
|
-
Accept: "application/vnd.github.v3+json",
|
|
197
|
-
"User-Agent": "ox-content-github-plugin"
|
|
198
|
-
};
|
|
199
|
-
if (options.token) headers.Authorization = `Bearer ${options.token}`;
|
|
200
174
|
const apiUrl = `https://api.github.com/repos/${source.repo}/contents/${encodePath(source.path)}?ref=${encodeURIComponent(source.ref)}`;
|
|
201
|
-
const response = await fetch(apiUrl, { headers });
|
|
175
|
+
const response = await fetch(apiUrl, { headers: githubHeaders(options) });
|
|
202
176
|
if (!response.ok) {
|
|
203
177
|
console.warn(`Failed to fetch GitHub source ${source.permalink}: ${response.status}`);
|
|
204
178
|
return null;
|
|
@@ -228,9 +202,189 @@ async function fetchGitHubSource(source, options) {
|
|
|
228
202
|
}
|
|
229
203
|
}
|
|
230
204
|
/**
|
|
231
|
-
*
|
|
205
|
+
* Pre-fetch all GitHub repos data.
|
|
232
206
|
*/
|
|
233
|
-
function
|
|
207
|
+
async function prefetchGitHubRepos(repos, options) {
|
|
208
|
+
const mergedOptions = {
|
|
209
|
+
...defaultOptions,
|
|
210
|
+
...options
|
|
211
|
+
};
|
|
212
|
+
const results = /* @__PURE__ */ new Map();
|
|
213
|
+
await Promise.all(Array.from(new Set(repos)).map(async (repo) => {
|
|
214
|
+
const data = await fetchRepoData(repo, mergedOptions);
|
|
215
|
+
results.set(repo, data);
|
|
216
|
+
}));
|
|
217
|
+
return results;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Pre-fetch all GitHub source files.
|
|
221
|
+
*/
|
|
222
|
+
async function prefetchGitHubSources(sources, options) {
|
|
223
|
+
const mergedOptions = {
|
|
224
|
+
...defaultOptions,
|
|
225
|
+
...options
|
|
226
|
+
};
|
|
227
|
+
const results = /* @__PURE__ */ new Map();
|
|
228
|
+
const uniqueSources = Array.from(new Map(sources.map((source) => [sourceKey(source), source])).values());
|
|
229
|
+
await Promise.all(uniqueSources.map(async (source) => {
|
|
230
|
+
const data = await fetchGitHubSource(source, mergedOptions);
|
|
231
|
+
results.set(sourceKey(source), data);
|
|
232
|
+
}));
|
|
233
|
+
return results;
|
|
234
|
+
}
|
|
235
|
+
//#endregion
|
|
236
|
+
//#region src/plugins/github/attributes.ts
|
|
237
|
+
const GITHUB_COMPONENT_RE = /<github\b([^>]*)>/gi;
|
|
238
|
+
const ATTRIBUTE_RE = /([:\w-]+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'>/]+)))?/g;
|
|
239
|
+
/**
|
|
240
|
+
* Collect all GitHub repos from HTML for pre-fetching.
|
|
241
|
+
*/
|
|
242
|
+
async function collectGitHubRepos(html) {
|
|
243
|
+
const repos = [];
|
|
244
|
+
GITHUB_COMPONENT_RE.lastIndex = 0;
|
|
245
|
+
let match;
|
|
246
|
+
while ((match = GITHUB_COMPONENT_RE.exec(html)) !== null) {
|
|
247
|
+
const attrs = parseAttributes(match[1]);
|
|
248
|
+
if (attrs.path || attrs.file || attrs.permalink || attrs.url || attrs.href) continue;
|
|
249
|
+
const repo = attrs.repo;
|
|
250
|
+
if (repo && isSafeGitHubRepo(repo)) repos.push(repo);
|
|
251
|
+
}
|
|
252
|
+
return repos;
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Collect all GitHub source references from HTML for pre-fetching.
|
|
256
|
+
*/
|
|
257
|
+
async function collectGitHubSources(html) {
|
|
258
|
+
const sources = [];
|
|
259
|
+
GITHUB_COMPONENT_RE.lastIndex = 0;
|
|
260
|
+
let match;
|
|
261
|
+
while ((match = GITHUB_COMPONENT_RE.exec(html)) !== null) {
|
|
262
|
+
const source = sourceRefFromAttributes(parseAttributes(match[1]));
|
|
263
|
+
if (source) sources.push(source);
|
|
264
|
+
}
|
|
265
|
+
return sources;
|
|
266
|
+
}
|
|
267
|
+
function parseAttributes(raw) {
|
|
268
|
+
const attrs = {};
|
|
269
|
+
ATTRIBUTE_RE.lastIndex = 0;
|
|
270
|
+
let match;
|
|
271
|
+
while ((match = ATTRIBUTE_RE.exec(raw)) !== null) attrs[match[1].toLowerCase()] = match[2] ?? match[3] ?? match[4] ?? "";
|
|
272
|
+
return attrs;
|
|
273
|
+
}
|
|
274
|
+
function attributesFromElement(el) {
|
|
275
|
+
const attrs = {};
|
|
276
|
+
for (const name of [
|
|
277
|
+
"permalink",
|
|
278
|
+
"url",
|
|
279
|
+
"href",
|
|
280
|
+
"repo",
|
|
281
|
+
"path",
|
|
282
|
+
"file",
|
|
283
|
+
"ref",
|
|
284
|
+
"sha",
|
|
285
|
+
"branch",
|
|
286
|
+
"loc",
|
|
287
|
+
"lines",
|
|
288
|
+
"line"
|
|
289
|
+
]) {
|
|
290
|
+
const value = getAttribute(el, name);
|
|
291
|
+
if (value !== void 0) attrs[name] = value;
|
|
292
|
+
}
|
|
293
|
+
return attrs;
|
|
294
|
+
}
|
|
295
|
+
function getAttribute(el, name) {
|
|
296
|
+
const value = el.properties?.[name];
|
|
297
|
+
if (typeof value === "string") return value;
|
|
298
|
+
if (Array.isArray(value)) return value.join(" ");
|
|
299
|
+
}
|
|
300
|
+
function sourceRefFromAttributes(attrs) {
|
|
301
|
+
const permalink = attrs.permalink ?? attrs.url ?? attrs.href;
|
|
302
|
+
if (permalink) return parseGitHubPermalink(permalink);
|
|
303
|
+
const repo = attrs.repo;
|
|
304
|
+
const path = attrs.path ?? attrs.file;
|
|
305
|
+
if (!repo || !path || !isSafeGitHubRepo(repo) || !isSafeGitHubPath(path)) return null;
|
|
306
|
+
const ref = attrs.ref ?? attrs.sha ?? attrs.branch ?? "main";
|
|
307
|
+
if (!isSafeGitHubRef(ref)) return null;
|
|
308
|
+
const source = {
|
|
309
|
+
repo,
|
|
310
|
+
ref,
|
|
311
|
+
path,
|
|
312
|
+
lines: parseGitHubLineRange(attrs.loc ?? attrs.lines ?? attrs.line)
|
|
313
|
+
};
|
|
314
|
+
return {
|
|
315
|
+
...source,
|
|
316
|
+
permalink: createGitHubPermalink(source)
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
//#endregion
|
|
320
|
+
//#region src/plugins/github/fallback-card.ts
|
|
321
|
+
/**
|
|
322
|
+
* Create fallback element when repo data is unavailable.
|
|
323
|
+
*/
|
|
324
|
+
function createFallbackCard(repo) {
|
|
325
|
+
return {
|
|
326
|
+
type: "element",
|
|
327
|
+
tagName: "a",
|
|
328
|
+
properties: {
|
|
329
|
+
className: ["ox-github-card", "error"],
|
|
330
|
+
href: isSafeGitHubRepo(repo) ? `https://github.com/${repo}` : "#",
|
|
331
|
+
target: "_blank",
|
|
332
|
+
rel: "noopener noreferrer"
|
|
333
|
+
},
|
|
334
|
+
children: [{
|
|
335
|
+
type: "element",
|
|
336
|
+
tagName: "div",
|
|
337
|
+
properties: { className: ["ox-github-header"] },
|
|
338
|
+
children: [{
|
|
339
|
+
type: "element",
|
|
340
|
+
tagName: "svg",
|
|
341
|
+
properties: {
|
|
342
|
+
className: ["ox-github-icon"],
|
|
343
|
+
viewBox: "0 0 16 16",
|
|
344
|
+
fill: "currentColor"
|
|
345
|
+
},
|
|
346
|
+
children: [{
|
|
347
|
+
type: "element",
|
|
348
|
+
tagName: "path",
|
|
349
|
+
properties: { d: "M8 0c4.42 0 8 3.58 8 8a8.013 8.013 0 0 1-5.45 7.59c-.4.08-.55-.17-.55-.38 0-.27.01-1.13.01-2.2 0-.75-.25-1.23-.54-1.48 1.78-.2 3.65-.88 3.65-3.95 0-.88-.31-1.59-.82-2.15.08-.2.36-1.02-.08-2.12 0 0-.67-.22-2.2.82-.64-.18-1.32-.27-2-.27-.68 0-1.36.09-2 .27-1.53-1.03-2.2-.82-2.2-.82-.44 1.1-.16 1.92-.08 2.12-.51.56-.82 1.28-.82 2.15 0 3.06 1.86 3.75 3.64 3.95-.23.2-.44.55-.51 1.07-.46.21-1.61.55-2.33-.66-.15-.24-.6-.83-1.23-.82-.67.01-.27.38.01.53.34.19.73.9.82 1.13.16.45.68 1.31 2.69.94 0 .67.01 1.3.01 1.49 0 .21-.15.45-.55.38A7.995 7.995 0 0 1 0 8c0-4.42 3.58-8 8-8Z" },
|
|
350
|
+
children: []
|
|
351
|
+
}]
|
|
352
|
+
}, {
|
|
353
|
+
type: "element",
|
|
354
|
+
tagName: "span",
|
|
355
|
+
properties: { className: ["ox-github-repo"] },
|
|
356
|
+
children: [{
|
|
357
|
+
type: "text",
|
|
358
|
+
value: repo
|
|
359
|
+
}]
|
|
360
|
+
}]
|
|
361
|
+
}]
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
//#endregion
|
|
365
|
+
//#region src/plugins/github/repo-card.ts
|
|
366
|
+
function formatNumber(num) {
|
|
367
|
+
if (num >= 1e6) return `${(num / 1e6).toFixed(1)}M`;
|
|
368
|
+
if (num >= 1e3) return `${(num / 1e3).toFixed(1)}k`;
|
|
369
|
+
return String(num);
|
|
370
|
+
}
|
|
371
|
+
function iconPath(d) {
|
|
372
|
+
return {
|
|
373
|
+
type: "element",
|
|
374
|
+
tagName: "svg",
|
|
375
|
+
properties: {
|
|
376
|
+
viewBox: "0 0 16 16",
|
|
377
|
+
fill: "currentColor"
|
|
378
|
+
},
|
|
379
|
+
children: [{
|
|
380
|
+
type: "element",
|
|
381
|
+
tagName: "path",
|
|
382
|
+
properties: { d },
|
|
383
|
+
children: []
|
|
384
|
+
}]
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
function createStatsChildren(repoData) {
|
|
234
388
|
const statsChildren = [];
|
|
235
389
|
if (repoData.language) statsChildren.push({
|
|
236
390
|
type: "element",
|
|
@@ -253,20 +407,7 @@ function createGitHubCard(repoData) {
|
|
|
253
407
|
type: "element",
|
|
254
408
|
tagName: "span",
|
|
255
409
|
properties: { className: ["ox-github-stat"] },
|
|
256
|
-
children: [{
|
|
257
|
-
type: "element",
|
|
258
|
-
tagName: "svg",
|
|
259
|
-
properties: {
|
|
260
|
-
viewBox: "0 0 16 16",
|
|
261
|
-
fill: "currentColor"
|
|
262
|
-
},
|
|
263
|
-
children: [{
|
|
264
|
-
type: "element",
|
|
265
|
-
tagName: "path",
|
|
266
|
-
properties: { d: "M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.751.751 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25Z" },
|
|
267
|
-
children: []
|
|
268
|
-
}]
|
|
269
|
-
}, {
|
|
410
|
+
children: [iconPath("M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.751.751 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25Z"), {
|
|
270
411
|
type: "text",
|
|
271
412
|
value: formatNumber(repoData.stargazers_count)
|
|
272
413
|
}]
|
|
@@ -275,24 +416,17 @@ function createGitHubCard(repoData) {
|
|
|
275
416
|
type: "element",
|
|
276
417
|
tagName: "span",
|
|
277
418
|
properties: { className: ["ox-github-stat"] },
|
|
278
|
-
children: [{
|
|
279
|
-
type: "element",
|
|
280
|
-
tagName: "svg",
|
|
281
|
-
properties: {
|
|
282
|
-
viewBox: "0 0 16 16",
|
|
283
|
-
fill: "currentColor"
|
|
284
|
-
},
|
|
285
|
-
children: [{
|
|
286
|
-
type: "element",
|
|
287
|
-
tagName: "path",
|
|
288
|
-
properties: { d: "M5 5.372v.878c0 .414.336.75.75.75h4.5a.75.75 0 0 0 .75-.75v-.878a2.25 2.25 0 1 1 1.5 0v.878a2.25 2.25 0 0 1-2.25 2.25h-1.5v2.128a2.251 2.251 0 1 1-1.5 0V8.5h-1.5A2.25 2.25 0 0 1 3.5 6.25v-.878a2.25 2.25 0 1 1 1.5 0ZM5 3.25a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Zm6.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm-3 8.75a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Z" },
|
|
289
|
-
children: []
|
|
290
|
-
}]
|
|
291
|
-
}, {
|
|
419
|
+
children: [iconPath("M5 5.372v.878c0 .414.336.75.75.75h4.5a.75.75 0 0 0 .75-.75v-.878a2.25 2.25 0 1 1 1.5 0v.878a2.25 2.25 0 0 1-2.25 2.25h-1.5v2.128a2.251 2.251 0 1 1-1.5 0V8.5h-1.5A2.25 2.25 0 0 1 3.5 6.25v-.878a2.25 2.25 0 1 1 1.5 0ZM5 3.25a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Zm6.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm-3 8.75a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Z"), {
|
|
292
420
|
type: "text",
|
|
293
421
|
value: formatNumber(repoData.forks_count)
|
|
294
422
|
}]
|
|
295
423
|
});
|
|
424
|
+
return statsChildren;
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* Create GitHub card element from repo data.
|
|
428
|
+
*/
|
|
429
|
+
function createGitHubCard(repoData) {
|
|
296
430
|
return {
|
|
297
431
|
type: "element",
|
|
298
432
|
tagName: "a",
|
|
@@ -308,19 +442,12 @@ function createGitHubCard(repoData) {
|
|
|
308
442
|
tagName: "div",
|
|
309
443
|
properties: { className: ["ox-github-header"] },
|
|
310
444
|
children: [{
|
|
311
|
-
|
|
312
|
-
tagName: "svg",
|
|
445
|
+
...iconPath("M2 2.5A2.5 2.5 0 0 1 4.5 0h8.75a.75.75 0 0 1 .75.75v12.5a.75.75 0 0 1-.75.75h-2.5a.75.75 0 0 1 0-1.5h1.75v-2h-8a1 1 0 0 0-.714 1.7.75.75 0 1 1-1.072 1.05A2.495 2.495 0 0 1 2 11.5Zm10.5-1h-8a1 1 0 0 0-1 1v6.708A2.486 2.486 0 0 1 4.5 9h8ZM5 12.25a.25.25 0 0 1 .25-.25h3.5a.25.25 0 0 1 .25.25v3.25a.25.25 0 0 1-.4.2l-1.45-1.087a.249.249 0 0 0-.3 0L5.4 15.7a.25.25 0 0 1-.4-.2Z"),
|
|
313
446
|
properties: {
|
|
314
447
|
className: ["ox-github-icon"],
|
|
315
448
|
viewBox: "0 0 16 16",
|
|
316
449
|
fill: "currentColor"
|
|
317
|
-
}
|
|
318
|
-
children: [{
|
|
319
|
-
type: "element",
|
|
320
|
-
tagName: "path",
|
|
321
|
-
properties: { d: "M2 2.5A2.5 2.5 0 0 1 4.5 0h8.75a.75.75 0 0 1 .75.75v12.5a.75.75 0 0 1-.75.75h-2.5a.75.75 0 0 1 0-1.5h1.75v-2h-8a1 1 0 0 0-.714 1.7.75.75 0 1 1-1.072 1.05A2.495 2.495 0 0 1 2 11.5Zm10.5-1h-8a1 1 0 0 0-1 1v6.708A2.486 2.486 0 0 1 4.5 9h8ZM5 12.25a.25.25 0 0 1 .25-.25h3.5a.25.25 0 0 1 .25.25v3.25a.25.25 0 0 1-.4.2l-1.45-1.087a.249.249 0 0 0-.3 0L5.4 15.7a.25.25 0 0 1-.4-.2Z" },
|
|
322
|
-
children: []
|
|
323
|
-
}]
|
|
450
|
+
}
|
|
324
451
|
}, {
|
|
325
452
|
type: "element",
|
|
326
453
|
tagName: "span",
|
|
@@ -344,61 +471,13 @@ function createGitHubCard(repoData) {
|
|
|
344
471
|
type: "element",
|
|
345
472
|
tagName: "div",
|
|
346
473
|
properties: { className: ["ox-github-stats"] },
|
|
347
|
-
children:
|
|
474
|
+
children: createStatsChildren(repoData)
|
|
348
475
|
}
|
|
349
476
|
]
|
|
350
477
|
};
|
|
351
478
|
}
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
*/
|
|
355
|
-
function createFallbackCard(repo) {
|
|
356
|
-
return {
|
|
357
|
-
type: "element",
|
|
358
|
-
tagName: "a",
|
|
359
|
-
properties: {
|
|
360
|
-
className: ["ox-github-card", "error"],
|
|
361
|
-
href: isSafeGitHubRepo(repo) ? `https://github.com/${repo}` : "#",
|
|
362
|
-
target: "_blank",
|
|
363
|
-
rel: "noopener noreferrer"
|
|
364
|
-
},
|
|
365
|
-
children: [{
|
|
366
|
-
type: "element",
|
|
367
|
-
tagName: "div",
|
|
368
|
-
properties: { className: ["ox-github-header"] },
|
|
369
|
-
children: [{
|
|
370
|
-
type: "element",
|
|
371
|
-
tagName: "svg",
|
|
372
|
-
properties: {
|
|
373
|
-
className: ["ox-github-icon"],
|
|
374
|
-
viewBox: "0 0 16 16",
|
|
375
|
-
fill: "currentColor"
|
|
376
|
-
},
|
|
377
|
-
children: [{
|
|
378
|
-
type: "element",
|
|
379
|
-
tagName: "path",
|
|
380
|
-
properties: { d: "M8 0c4.42 0 8 3.58 8 8a8.013 8.013 0 0 1-5.45 7.59c-.4.08-.55-.17-.55-.38 0-.27.01-1.13.01-2.2 0-.75-.25-1.23-.54-1.48 1.78-.2 3.65-.88 3.65-3.95 0-.88-.31-1.59-.82-2.15.08-.2.36-1.02-.08-2.12 0 0-.67-.22-2.2.82-.64-.18-1.32-.27-2-.27-.68 0-1.36.09-2 .27-1.53-1.03-2.2-.82-2.2-.82-.44 1.1-.16 1.92-.08 2.12-.51.56-.82 1.28-.82 2.15 0 3.06 1.86 3.75 3.64 3.95-.23.2-.44.55-.51 1.07-.46.21-1.61.55-2.33-.66-.15-.24-.6-.83-1.23-.82-.67.01-.27.38.01.53.34.19.73.9.82 1.13.16.45.68 1.31 2.69.94 0 .67.01 1.3.01 1.49 0 .21-.15.45-.55.38A7.995 7.995 0 0 1 0 8c0-4.42 3.58-8 8-8Z" },
|
|
381
|
-
children: []
|
|
382
|
-
}]
|
|
383
|
-
}, {
|
|
384
|
-
type: "element",
|
|
385
|
-
tagName: "span",
|
|
386
|
-
properties: { className: ["ox-github-repo"] },
|
|
387
|
-
children: [{
|
|
388
|
-
type: "text",
|
|
389
|
-
value: repo
|
|
390
|
-
}]
|
|
391
|
-
}]
|
|
392
|
-
}]
|
|
393
|
-
};
|
|
394
|
-
}
|
|
395
|
-
function inferLanguage(path) {
|
|
396
|
-
const fileName = path.split("/").at(-1)?.toLowerCase() ?? "";
|
|
397
|
-
if (fileName === "dockerfile") return "dockerfile";
|
|
398
|
-
if (fileName === "makefile") return "makefile";
|
|
399
|
-
const extension = fileName.includes(".") ? fileName.split(".").at(-1) : void 0;
|
|
400
|
-
return extension ? EXTENSION_LANGUAGE_MAP.get(extension) ?? extension : null;
|
|
401
|
-
}
|
|
479
|
+
//#endregion
|
|
480
|
+
//#region src/plugins/github/source-card.ts
|
|
402
481
|
function normalizeSourceLines(content) {
|
|
403
482
|
const lines = content.replace(/\r\n?/g, "\n").split("\n");
|
|
404
483
|
if (lines.length > 1 && lines.at(-1) === "") lines.pop();
|
|
@@ -494,112 +573,8 @@ function createGitHubSourceCard(source, lines, options) {
|
|
|
494
573
|
}]
|
|
495
574
|
};
|
|
496
575
|
}
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
*/
|
|
500
|
-
async function collectGitHubRepos(html) {
|
|
501
|
-
const repos = [];
|
|
502
|
-
GITHUB_COMPONENT_RE.lastIndex = 0;
|
|
503
|
-
let match;
|
|
504
|
-
while ((match = GITHUB_COMPONENT_RE.exec(html)) !== null) {
|
|
505
|
-
const attrs = parseAttributes(match[1]);
|
|
506
|
-
if (attrs.path || attrs.file || attrs.permalink || attrs.url || attrs.href) continue;
|
|
507
|
-
const repo = attrs.repo;
|
|
508
|
-
if (repo && isSafeGitHubRepo(repo)) repos.push(repo);
|
|
509
|
-
}
|
|
510
|
-
return repos;
|
|
511
|
-
}
|
|
512
|
-
/**
|
|
513
|
-
* Collect all GitHub source references from HTML for pre-fetching.
|
|
514
|
-
*/
|
|
515
|
-
async function collectGitHubSources(html) {
|
|
516
|
-
const sources = [];
|
|
517
|
-
GITHUB_COMPONENT_RE.lastIndex = 0;
|
|
518
|
-
let match;
|
|
519
|
-
while ((match = GITHUB_COMPONENT_RE.exec(html)) !== null) {
|
|
520
|
-
const source = sourceRefFromAttributes(parseAttributes(match[1]));
|
|
521
|
-
if (source) sources.push(source);
|
|
522
|
-
}
|
|
523
|
-
return sources;
|
|
524
|
-
}
|
|
525
|
-
function parseAttributes(raw) {
|
|
526
|
-
const attrs = {};
|
|
527
|
-
ATTRIBUTE_RE.lastIndex = 0;
|
|
528
|
-
let match;
|
|
529
|
-
while ((match = ATTRIBUTE_RE.exec(raw)) !== null) attrs[match[1].toLowerCase()] = match[2] ?? match[3] ?? match[4] ?? "";
|
|
530
|
-
return attrs;
|
|
531
|
-
}
|
|
532
|
-
function attributesFromElement(el) {
|
|
533
|
-
const attrs = {};
|
|
534
|
-
for (const name of [
|
|
535
|
-
"permalink",
|
|
536
|
-
"url",
|
|
537
|
-
"href",
|
|
538
|
-
"repo",
|
|
539
|
-
"path",
|
|
540
|
-
"file",
|
|
541
|
-
"ref",
|
|
542
|
-
"sha",
|
|
543
|
-
"branch",
|
|
544
|
-
"loc",
|
|
545
|
-
"lines",
|
|
546
|
-
"line"
|
|
547
|
-
]) {
|
|
548
|
-
const value = getAttribute(el, name);
|
|
549
|
-
if (value !== void 0) attrs[name] = value;
|
|
550
|
-
}
|
|
551
|
-
return attrs;
|
|
552
|
-
}
|
|
553
|
-
function sourceRefFromAttributes(attrs) {
|
|
554
|
-
const permalink = attrs.permalink ?? attrs.url ?? attrs.href;
|
|
555
|
-
if (permalink) return parseGitHubPermalink(permalink);
|
|
556
|
-
const repo = attrs.repo;
|
|
557
|
-
const path = attrs.path ?? attrs.file;
|
|
558
|
-
if (!repo || !path || !isSafeGitHubRepo(repo) || !isSafeGitHubPath(path)) return null;
|
|
559
|
-
const ref = attrs.ref ?? attrs.sha ?? attrs.branch ?? "main";
|
|
560
|
-
if (!isSafeGitHubRef(ref)) return null;
|
|
561
|
-
const source = {
|
|
562
|
-
repo,
|
|
563
|
-
ref,
|
|
564
|
-
path,
|
|
565
|
-
lines: parseGitHubLineRange(attrs.loc ?? attrs.lines ?? attrs.line)
|
|
566
|
-
};
|
|
567
|
-
return {
|
|
568
|
-
...source,
|
|
569
|
-
permalink: createGitHubPermalink(source)
|
|
570
|
-
};
|
|
571
|
-
}
|
|
572
|
-
/**
|
|
573
|
-
* Pre-fetch all GitHub repos data.
|
|
574
|
-
*/
|
|
575
|
-
async function prefetchGitHubRepos(repos, options) {
|
|
576
|
-
const mergedOptions = {
|
|
577
|
-
...defaultOptions,
|
|
578
|
-
...options
|
|
579
|
-
};
|
|
580
|
-
const results = /* @__PURE__ */ new Map();
|
|
581
|
-
await Promise.all(Array.from(new Set(repos)).map(async (repo) => {
|
|
582
|
-
const data = await fetchRepoData(repo, mergedOptions);
|
|
583
|
-
results.set(repo, data);
|
|
584
|
-
}));
|
|
585
|
-
return results;
|
|
586
|
-
}
|
|
587
|
-
/**
|
|
588
|
-
* Pre-fetch all GitHub source files.
|
|
589
|
-
*/
|
|
590
|
-
async function prefetchGitHubSources(sources, options) {
|
|
591
|
-
const mergedOptions = {
|
|
592
|
-
...defaultOptions,
|
|
593
|
-
...options
|
|
594
|
-
};
|
|
595
|
-
const results = /* @__PURE__ */ new Map();
|
|
596
|
-
const uniqueSources = Array.from(new Map(sources.map((source) => [sourceKey(source), source])).values());
|
|
597
|
-
await Promise.all(uniqueSources.map(async (source) => {
|
|
598
|
-
const data = await fetchGitHubSource(source, mergedOptions);
|
|
599
|
-
results.set(sourceKey(source), data);
|
|
600
|
-
}));
|
|
601
|
-
return results;
|
|
602
|
-
}
|
|
576
|
+
//#endregion
|
|
577
|
+
//#region src/plugins/github/transform.ts
|
|
603
578
|
/**
|
|
604
579
|
* Rehype plugin to transform GitHub components.
|
|
605
580
|
*/
|
|
@@ -608,21 +583,23 @@ function rehypeGitHub(repoDataMap, sourceDataMap, options) {
|
|
|
608
583
|
const visit = (node) => {
|
|
609
584
|
if ("children" in node) for (let i = 0; i < node.children.length; i++) {
|
|
610
585
|
const child = node.children[i];
|
|
611
|
-
if (child.type
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
const
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
586
|
+
if (child.type !== "element") continue;
|
|
587
|
+
if (child.tagName.toLowerCase() !== "github") {
|
|
588
|
+
visit(child);
|
|
589
|
+
continue;
|
|
590
|
+
}
|
|
591
|
+
const attrs = attributesFromElement(child);
|
|
592
|
+
const source = sourceRefFromAttributes(attrs);
|
|
593
|
+
if (source) {
|
|
594
|
+
const sourceData = sourceDataMap.get(sourceKey(source));
|
|
595
|
+
node.children[i] = sourceData ? createGitHubSourceCard(sourceData, source.lines, options) : createFallbackCard(source.permalink);
|
|
596
|
+
continue;
|
|
597
|
+
}
|
|
598
|
+
const repo = attrs.repo;
|
|
599
|
+
if (repo) {
|
|
600
|
+
const repoData = repoDataMap.get(repo);
|
|
601
|
+
node.children[i] = repoData ? createGitHubCard(repoData) : createFallbackCard(repo);
|
|
602
|
+
}
|
|
626
603
|
}
|
|
627
604
|
};
|
|
628
605
|
visit(tree);
|
|
@@ -643,6 +620,9 @@ async function transformGitHub(html, repoDataMap, options) {
|
|
|
643
620
|
return String(result);
|
|
644
621
|
}
|
|
645
622
|
//#endregion
|
|
623
|
+
//#region src/plugins/github.ts
|
|
624
|
+
var github_exports = /* @__PURE__ */ require_chunk.__exportAll({ transformGitHub: () => transformGitHub });
|
|
625
|
+
//#endregion
|
|
646
626
|
Object.defineProperty(exports, "collectGitHubRepos", {
|
|
647
627
|
enumerable: true,
|
|
648
628
|
get: function() {
|