@t8/docsgen 0.3.32 → 0.3.33
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/bin.js +357 -304
- package/package.json +1 -1
- package/src/bin/content/createDirs.ts +21 -0
- package/src/bin/content/getCSSRoot.ts +44 -0
- package/src/bin/{getCounterContent.ts → content/getCounterContent.ts} +1 -1
- package/src/bin/content/getDefaultCodeStyleContent.ts +9 -0
- package/src/bin/{getIcon.ts → content/getIcon.ts} +1 -1
- package/src/bin/content/getIconTag.ts +10 -0
- package/src/bin/content/getIndexContent.ts +119 -0
- package/src/bin/{getInjectedContent.ts → content/getInjectedContent.ts} +3 -3
- package/src/bin/{getNav.ts → content/getNav.ts} +5 -5
- package/src/bin/content/getPlainTitle.ts +12 -0
- package/src/bin/content/getRedirectContent.ts +31 -0
- package/src/bin/content/getSectionContent.ts +80 -0
- package/src/bin/content/getStartContent.ts +40 -0
- package/src/bin/content/tweakTypography.ts +5 -0
- package/src/bin/parsing/getParsedContent.ts +28 -5
- package/src/bin/setContent.ts +16 -300
- package/.lintincludes +0 -2
- package/biome.json +0 -35
- /package/src/bin/{toFileContent.ts → content/toFileContent.ts} +0 -0
package/dist/bin.js
CHANGED
|
@@ -278,14 +278,26 @@ async function setCName({ dir = "", name, cname, jsorg }) {
|
|
|
278
278
|
}
|
|
279
279
|
|
|
280
280
|
// src/bin/setContent.ts
|
|
281
|
-
import {
|
|
282
|
-
import {
|
|
283
|
-
import { dirname, join as join3 } from "node:path";
|
|
284
|
-
import { fileURLToPath } from "node:url";
|
|
285
|
-
import { promisify } from "node:util";
|
|
281
|
+
import { writeFile as writeFile2 } from "node:fs/promises";
|
|
282
|
+
import { join as join5 } from "node:path";
|
|
286
283
|
|
|
287
|
-
// src/
|
|
288
|
-
|
|
284
|
+
// src/bin/content/createDirs.ts
|
|
285
|
+
import { access, mkdir } from "node:fs/promises";
|
|
286
|
+
import { join as join3 } from "node:path";
|
|
287
|
+
async function createDirs(ctx) {
|
|
288
|
+
let { dir = "", contentDir = "" } = ctx;
|
|
289
|
+
let dirs = [contentDir];
|
|
290
|
+
await Promise.all(
|
|
291
|
+
dirs.map(async (path) => {
|
|
292
|
+
let dirPath = join3(dir, path);
|
|
293
|
+
try {
|
|
294
|
+
await access(dirPath);
|
|
295
|
+
} catch {
|
|
296
|
+
await mkdir(dirPath);
|
|
297
|
+
}
|
|
298
|
+
})
|
|
299
|
+
);
|
|
300
|
+
}
|
|
289
301
|
|
|
290
302
|
// src/utils/escapeHTML.ts
|
|
291
303
|
var htmlEntityMap = [
|
|
@@ -302,70 +314,6 @@ function escapeHTML(x) {
|
|
|
302
314
|
return s;
|
|
303
315
|
}
|
|
304
316
|
|
|
305
|
-
// src/utils/escapeRegExp.ts
|
|
306
|
-
function escapeRegExp(s) {
|
|
307
|
-
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
// src/bin/getCounterContent.ts
|
|
311
|
-
function getCounterContent({ ymid }) {
|
|
312
|
-
if (!ymid) return "";
|
|
313
|
-
return `
|
|
314
|
-
<script>
|
|
315
|
-
(function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};
|
|
316
|
-
m[i].l=1*new Date();
|
|
317
|
-
for (var j = 0; j < document.scripts.length; j++) {if (document.scripts[j].src === r) { return; }}
|
|
318
|
-
k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)})
|
|
319
|
-
(window, document, "script", "https://mc.yandex.com/metrika/tag.js", "ym");
|
|
320
|
-
ym(${ymid}, "init", {clickmap: true, trackLinks: true, accurateTrackBounce: true});
|
|
321
|
-
</script>
|
|
322
|
-
<noscript><div><img src="https://mc.yandex.com/watch/${ymid}" style="position:absolute;left:-9999px;" alt=""></div></noscript>
|
|
323
|
-
`.trim();
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
// src/bin/getIcon.ts
|
|
327
|
-
var iconTypeMap = {
|
|
328
|
-
ico: "image/x-icon",
|
|
329
|
-
svg: "image/svg+xml",
|
|
330
|
-
png: "image/png",
|
|
331
|
-
gif: "image/gif",
|
|
332
|
-
jpg: "image/jpeg",
|
|
333
|
-
jpeg: "image/jpeg"
|
|
334
|
-
};
|
|
335
|
-
function getIcon({ favicon, faviconType }) {
|
|
336
|
-
let icon = {
|
|
337
|
-
url: favicon,
|
|
338
|
-
type: faviconType
|
|
339
|
-
};
|
|
340
|
-
if (icon.url && !icon.type) {
|
|
341
|
-
let ext = icon.url.split("/").at(-1)?.split(".").at(-1)?.toLowerCase();
|
|
342
|
-
if (ext) icon.type = iconTypeMap[ext];
|
|
343
|
-
}
|
|
344
|
-
return icon;
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
// src/bin/getInjectedContent.ts
|
|
348
|
-
function getInjectedContent(ctx, page, target, mode) {
|
|
349
|
-
let injectedContent = ctx[mode]?.[target];
|
|
350
|
-
if (!injectedContent) return "";
|
|
351
|
-
return (Array.isArray(injectedContent) ? injectedContent : [injectedContent]).reduce((s, item) => {
|
|
352
|
-
if (item === void 0) return s;
|
|
353
|
-
if (typeof item === "string") return `${s}${s ? "\n" : ""}${item}`;
|
|
354
|
-
let { content, pages } = item;
|
|
355
|
-
if (!content || pages && !pages.includes(page)) return s;
|
|
356
|
-
return `${s}${s ? "\n" : ""}${content}`;
|
|
357
|
-
}, "");
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
// src/bin/getNav.ts
|
|
361
|
-
import { JSDOM as JSDOM2 } from "jsdom";
|
|
362
|
-
|
|
363
|
-
// src/bin/getNpmLink.ts
|
|
364
|
-
function getNpmLink({ npm }, className) {
|
|
365
|
-
if (!npm) return "";
|
|
366
|
-
return `<a href="${npm}"${className ? ` class="${className}"` : ""} target="_blank">npm</a>`;
|
|
367
|
-
}
|
|
368
|
-
|
|
369
317
|
// src/bin/getRepoLink.ts
|
|
370
318
|
function getRepoLink({ repo }, className) {
|
|
371
319
|
if (!repo) return "";
|
|
@@ -373,82 +321,8 @@ function getRepoLink({ repo }, className) {
|
|
|
373
321
|
return `<a href="${repo}"${className ? ` class="${className}"` : ""} target="_blank">${caption}</a>`;
|
|
374
322
|
}
|
|
375
323
|
|
|
376
|
-
// src/bin/getNav.ts
|
|
377
|
-
async function getNav(ctx, navItems) {
|
|
378
|
-
let { name, root, contentDir, backstory, nav } = ctx;
|
|
379
|
-
let navContent = await fetchContent(nav);
|
|
380
|
-
let s = "";
|
|
381
|
-
if (navContent) {
|
|
382
|
-
let navDom = new JSDOM2(navContent).window.document.body;
|
|
383
|
-
for (let link of navDom.querySelectorAll("a")) {
|
|
384
|
-
if (link.dataset.name === name) {
|
|
385
|
-
let parent = link.parentElement;
|
|
386
|
-
link.remove();
|
|
387
|
-
while (parent && parent.innerHTML.trim() === "") {
|
|
388
|
-
let nextParent = parent.parentElement;
|
|
389
|
-
parent.remove();
|
|
390
|
-
parent = nextParent;
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
navContent = navDom.innerHTML;
|
|
395
|
-
}
|
|
396
|
-
let navItemCount = 0;
|
|
397
|
-
if (navItems.length === 1) {
|
|
398
|
-
let { id, items } = navItems[0];
|
|
399
|
-
let itemLink = `${root}${contentDir}/${encodeURIComponent(id)}`;
|
|
400
|
-
for (let { id: id2, title } of items) {
|
|
401
|
-
s += `
|
|
402
|
-
<li><a href="${itemLink}#${encodeURIComponent(id2)}">${title}</a></li>`;
|
|
403
|
-
navItemCount++;
|
|
404
|
-
}
|
|
405
|
-
} else {
|
|
406
|
-
for (let { id, title, items } of navItems) {
|
|
407
|
-
let itemLink = `${root}${contentDir}/${encodeURIComponent(id)}`;
|
|
408
|
-
s += `
|
|
409
|
-
<li data-id="${id}"><a href="${itemLink}">${title}</a>`;
|
|
410
|
-
if (items.length !== 0) {
|
|
411
|
-
s += "\n <ul>";
|
|
412
|
-
for (let { id: id2, title: title2 } of items) {
|
|
413
|
-
s += `
|
|
414
|
-
<li><a href="${itemLink}#${encodeURIComponent(id2)}">${title2}</a></li>`;
|
|
415
|
-
navItemCount++;
|
|
416
|
-
}
|
|
417
|
-
s += "\n </ul>\n";
|
|
418
|
-
}
|
|
419
|
-
s += "</li>";
|
|
420
|
-
navItemCount++;
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
if ((!s || navItemCount < 2) && !navContent) return "";
|
|
424
|
-
s = s.trim();
|
|
425
|
-
s = s ? `<p class="title">Contents</p>
|
|
426
|
-
<ul>${s}
|
|
427
|
-
</ul>
|
|
428
|
-
` : "";
|
|
429
|
-
let repoLink = getRepoLink(ctx);
|
|
430
|
-
let npmLink = getNpmLink(ctx);
|
|
431
|
-
if (repoLink || npmLink || backstory)
|
|
432
|
-
s += `
|
|
433
|
-
<p class="title">Resources</p>
|
|
434
|
-
<ul>
|
|
435
|
-
${repoLink ? `<li>${repoLink}</li>` : ""}
|
|
436
|
-
${npmLink ? `<li>${npmLink}</li>` : ""}
|
|
437
|
-
${backstory ? `<li><a href="${backstory}">Backstory</a></li>` : ""}
|
|
438
|
-
</ul>
|
|
439
|
-
`;
|
|
440
|
-
s = s.trim();
|
|
441
|
-
s = s ? `<section>
|
|
442
|
-
${s}
|
|
443
|
-
</section>` : "";
|
|
444
|
-
return `<nav class="aux">
|
|
445
|
-
${s}
|
|
446
|
-
${navContent}
|
|
447
|
-
</nav>`;
|
|
448
|
-
}
|
|
449
|
-
|
|
450
324
|
// src/bin/parsing/getParsedContent.ts
|
|
451
|
-
import { JSDOM as
|
|
325
|
+
import { JSDOM as JSDOM2 } from "jsdom";
|
|
452
326
|
import Markdown from "markdown-it";
|
|
453
327
|
|
|
454
328
|
// src/bin/getSlug.ts
|
|
@@ -576,13 +450,15 @@ function preprocessContent(s) {
|
|
|
576
450
|
var md = new Markdown({
|
|
577
451
|
html: true
|
|
578
452
|
});
|
|
453
|
+
var parsedContentCache = /* @__PURE__ */ new Map();
|
|
579
454
|
async function getParsedContent(ctx) {
|
|
455
|
+
let contentLocation = getLocation(ctx, "README.md", ctx.source);
|
|
456
|
+
let parsedContent = parsedContentCache.get(contentLocation);
|
|
457
|
+
if (parsedContent) return parsedContent;
|
|
580
458
|
let { singlePage, firstLineDescription, linkMap } = ctx;
|
|
581
|
-
let rawContent = await fetchContent(
|
|
582
|
-
getLocation(ctx, "README.md", ctx.source)
|
|
583
|
-
);
|
|
459
|
+
let rawContent = await fetchContent(contentLocation);
|
|
584
460
|
let content = md.render(preprocessContent(rawContent));
|
|
585
|
-
let dom = new
|
|
461
|
+
let dom = new JSDOM2(content);
|
|
586
462
|
let { nav, linkMap: navLinkMap } = buildNav(ctx, dom);
|
|
587
463
|
let badges = "";
|
|
588
464
|
let title = "";
|
|
@@ -650,7 +526,7 @@ async function getParsedContent(ctx) {
|
|
|
650
526
|
intro[i] = `<p><span class="li">${s}</span></p>`;
|
|
651
527
|
}
|
|
652
528
|
}
|
|
653
|
-
|
|
529
|
+
parsedContent = {
|
|
654
530
|
badges,
|
|
655
531
|
// postprocessBadges(joinLines(badges)),
|
|
656
532
|
title,
|
|
@@ -662,25 +538,63 @@ async function getParsedContent(ctx) {
|
|
|
662
538
|
sections: sections.map(postprocess),
|
|
663
539
|
nav
|
|
664
540
|
};
|
|
541
|
+
parsedContentCache.set(contentLocation, parsedContent);
|
|
542
|
+
return parsedContent;
|
|
665
543
|
}
|
|
666
544
|
|
|
667
|
-
// src/bin/
|
|
668
|
-
function
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
545
|
+
// src/bin/content/getCounterContent.ts
|
|
546
|
+
function getCounterContent({ ymid }) {
|
|
547
|
+
if (!ymid) return "";
|
|
548
|
+
return `
|
|
549
|
+
<script>
|
|
550
|
+
(function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};
|
|
551
|
+
m[i].l=1*new Date();
|
|
552
|
+
for (var j = 0; j < document.scripts.length; j++) {if (document.scripts[j].src === r) { return; }}
|
|
553
|
+
k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)})
|
|
554
|
+
(window, document, "script", "https://mc.yandex.com/metrika/tag.js", "ym");
|
|
555
|
+
ym(${ymid}, "init", {clickmap: true, trackLinks: true, accurateTrackBounce: true});
|
|
556
|
+
</script>
|
|
557
|
+
<noscript><div><img src="https://mc.yandex.com/watch/${ymid}" style="position:absolute;left:-9999px;" alt=""></div></noscript>
|
|
558
|
+
`.trim();
|
|
678
559
|
}
|
|
679
560
|
|
|
680
|
-
// src/bin/
|
|
561
|
+
// src/bin/content/getCSSRoot.ts
|
|
562
|
+
import { exec as defaultExec } from "node:child_process";
|
|
563
|
+
import { cp } from "node:fs/promises";
|
|
564
|
+
import { dirname, join as join4 } from "node:path";
|
|
565
|
+
import { fileURLToPath } from "node:url";
|
|
566
|
+
import { promisify } from "node:util";
|
|
567
|
+
|
|
568
|
+
// src/const/packageName.ts
|
|
569
|
+
var packageName = "@t8/docsgen";
|
|
570
|
+
|
|
571
|
+
// src/bin/content/getCSSRoot.ts
|
|
681
572
|
var exec = promisify(defaultExec);
|
|
682
573
|
var __filename = fileURLToPath(import.meta.url);
|
|
683
574
|
var __dirname = dirname(__filename);
|
|
575
|
+
async function getCSSRoot(ctx, type) {
|
|
576
|
+
let { dir = "", assetsDir } = ctx;
|
|
577
|
+
let cssRoot = {
|
|
578
|
+
index: "",
|
|
579
|
+
content: ""
|
|
580
|
+
};
|
|
581
|
+
if (assetsDir) {
|
|
582
|
+
cssRoot.index = assetsDir;
|
|
583
|
+
cssRoot.content = `../${assetsDir}`;
|
|
584
|
+
await cp(join4(__dirname, "css"), join4(dir, cssRoot.index), {
|
|
585
|
+
force: true,
|
|
586
|
+
recursive: true
|
|
587
|
+
});
|
|
588
|
+
} else {
|
|
589
|
+
let packageVersion = (await exec(`npm view ${packageName} version`)).stdout.trim().split(".").slice(0, 2).join(".");
|
|
590
|
+
let packageUrl = `https://unpkg.com/${packageName}@${packageVersion}`;
|
|
591
|
+
cssRoot.index = `${packageUrl}/dist/css`;
|
|
592
|
+
cssRoot.content = `${packageUrl}/dist/css`;
|
|
593
|
+
}
|
|
594
|
+
return cssRoot[type];
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
// src/bin/content/getDefaultCodeStyleContent.ts
|
|
684
598
|
function getDefaultCodeStyleContent(cssRoot) {
|
|
685
599
|
return `
|
|
686
600
|
<link rel="stylesheet" href="https://unpkg.com/@highlightjs/cdn-assets@11.11.1/styles/stackoverflow-light.min.css" media="(prefers-color-scheme: light)">
|
|
@@ -688,72 +602,87 @@ function getDefaultCodeStyleContent(cssRoot) {
|
|
|
688
602
|
<link rel="stylesheet" href="${cssRoot}/code.css">
|
|
689
603
|
<script src="https://unpkg.com/@highlightjs/cdn-assets@11.11.1/highlight.min.js"></script>
|
|
690
604
|
<script>hljs.highlightAll()</script>
|
|
691
|
-
|
|
605
|
+
`.trim();
|
|
692
606
|
}
|
|
607
|
+
|
|
608
|
+
// src/bin/content/getIcon.ts
|
|
609
|
+
var iconTypeMap = {
|
|
610
|
+
ico: "image/x-icon",
|
|
611
|
+
svg: "image/svg+xml",
|
|
612
|
+
png: "image/png",
|
|
613
|
+
gif: "image/gif",
|
|
614
|
+
jpg: "image/jpeg",
|
|
615
|
+
jpeg: "image/jpeg"
|
|
616
|
+
};
|
|
617
|
+
function getIcon({ favicon, faviconType }) {
|
|
618
|
+
let icon = {
|
|
619
|
+
url: favicon,
|
|
620
|
+
type: faviconType
|
|
621
|
+
};
|
|
622
|
+
if (icon.url && !icon.type) {
|
|
623
|
+
let ext = icon.url.split("/").at(-1)?.split(".").at(-1)?.toLowerCase();
|
|
624
|
+
if (ext) icon.type = iconTypeMap[ext];
|
|
625
|
+
}
|
|
626
|
+
return icon;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
// src/bin/content/getIconTag.ts
|
|
630
|
+
function getIconTag(ctx) {
|
|
631
|
+
let { url, type } = getIcon(ctx);
|
|
632
|
+
return url ? `<link rel="icon"${type ? ` type="${type}"` : ""} href="${url}">` : "";
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
// src/bin/content/getInjectedContent.ts
|
|
636
|
+
function getInjectedContent(ctx, page, target, mode) {
|
|
637
|
+
let injectedContent = ctx[mode]?.[target];
|
|
638
|
+
if (!injectedContent) return "";
|
|
639
|
+
return (Array.isArray(injectedContent) ? injectedContent : [injectedContent]).reduce((s, item) => {
|
|
640
|
+
if (item === void 0) return s;
|
|
641
|
+
if (typeof item === "string") return `${s}${s ? "\n" : ""}${item}`;
|
|
642
|
+
let { content, pages } = item;
|
|
643
|
+
if (!content || pages && !pages.includes(page)) return s;
|
|
644
|
+
return `${s}${s ? "\n" : ""}${content}`;
|
|
645
|
+
}, "");
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
// src/bin/content/getPlainTitle.ts
|
|
649
|
+
async function getPlainTitle(ctx) {
|
|
650
|
+
let { name, title, htmlTitle } = ctx;
|
|
651
|
+
let { title: parsedTitle } = await getParsedContent(ctx);
|
|
652
|
+
return escapeHTML(title || stripHTML(htmlTitle || parsedTitle, true) || name);
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
// src/bin/content/toFileContent.ts
|
|
656
|
+
function toFileContent(x) {
|
|
657
|
+
let s = x.replace(
|
|
658
|
+
/\s+(\r?\n *<\/?(script|link|head|body|html|meta|title)[> ])/g,
|
|
659
|
+
"$1"
|
|
660
|
+
).replace(
|
|
661
|
+
/\s+(\r?\n *<\/?(main|header|footer|nav|section|div|h\d|p|ul|ol|li|table)[> ])/g,
|
|
662
|
+
"$1"
|
|
663
|
+
).trim();
|
|
664
|
+
return `${s}
|
|
665
|
+
`;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
// src/bin/content/tweakTypography.ts
|
|
693
669
|
function tweakTypography(s = "") {
|
|
694
670
|
return s.replace(/\b(for|in|on|at|to|with|a|an|the|its)\s+/gi, "$1\xA0").replace(/\b(React)\s+(apps?)\b/gi, "$1\xA0$2");
|
|
695
671
|
}
|
|
696
|
-
|
|
672
|
+
|
|
673
|
+
// src/bin/content/getIndexContent.ts
|
|
674
|
+
async function getIndexContent(ctx) {
|
|
697
675
|
let {
|
|
698
|
-
dir = "",
|
|
699
|
-
assetsDir,
|
|
700
676
|
root,
|
|
701
677
|
contentDir = "",
|
|
702
678
|
name,
|
|
703
|
-
title,
|
|
704
679
|
htmlTitle,
|
|
705
680
|
description: packageDescription,
|
|
706
681
|
isDevDep,
|
|
707
|
-
backstory
|
|
708
|
-
redirect
|
|
682
|
+
backstory
|
|
709
683
|
} = ctx;
|
|
710
684
|
let counterContent = getCounterContent(ctx);
|
|
711
685
|
let escapedPackageDescription = escapeHTML(packageDescription);
|
|
712
|
-
let cssRoot = {
|
|
713
|
-
index: "",
|
|
714
|
-
content: ""
|
|
715
|
-
};
|
|
716
|
-
if (assetsDir) {
|
|
717
|
-
cssRoot.index = assetsDir;
|
|
718
|
-
cssRoot.content = `../${assetsDir}`;
|
|
719
|
-
await cp(join3(__dirname, "css"), join3(dir, cssRoot.index), {
|
|
720
|
-
force: true,
|
|
721
|
-
recursive: true
|
|
722
|
-
});
|
|
723
|
-
} else {
|
|
724
|
-
let packageVersion = (await exec(`npm view ${packageName} version`)).stdout.trim().split(".").slice(0, 2).join(".");
|
|
725
|
-
let packageUrl = `https://unpkg.com/${packageName}@${packageVersion}`;
|
|
726
|
-
cssRoot.index = `${packageUrl}/dist/css`;
|
|
727
|
-
cssRoot.content = `${packageUrl}/dist/css`;
|
|
728
|
-
}
|
|
729
|
-
let icon = getIcon(ctx);
|
|
730
|
-
let iconTag = icon.url ? `<link rel="icon"${icon.type ? ` type="${icon.type}"` : ""} href="${icon.url}">` : "";
|
|
731
|
-
if (redirect) {
|
|
732
|
-
let escapedRedirect = escapeHTML(redirect);
|
|
733
|
-
await writeFile2(
|
|
734
|
-
join3(dir, "index.html"),
|
|
735
|
-
toFileContent(`
|
|
736
|
-
<!DOCTYPE html>
|
|
737
|
-
<html lang="en" data-layout="redirect" class="blank">
|
|
738
|
-
<head>
|
|
739
|
-
${getInjectedContent(ctx, "redirect", "head", "prepend")}
|
|
740
|
-
<meta charset="utf-8">
|
|
741
|
-
<meta name="viewport" content="width=device-width">
|
|
742
|
-
<meta http-equiv="refresh" content="0; URL=${escapedRedirect}">
|
|
743
|
-
${iconTag}
|
|
744
|
-
${getInjectedContent(ctx, "redirect", "head", "append")}
|
|
745
|
-
</head>
|
|
746
|
-
<body>
|
|
747
|
-
${getInjectedContent(ctx, "redirect", "body", "prepend")}
|
|
748
|
-
${counterContent}
|
|
749
|
-
${getInjectedContent(ctx, "redirect", "body", "append")}
|
|
750
|
-
<script>window.location.replace("${escapedRedirect}");</script>
|
|
751
|
-
</body>
|
|
752
|
-
</html>
|
|
753
|
-
`)
|
|
754
|
-
);
|
|
755
|
-
return;
|
|
756
|
-
}
|
|
757
686
|
let {
|
|
758
687
|
title: parsedTitle,
|
|
759
688
|
description,
|
|
@@ -761,86 +690,15 @@ ${getInjectedContent(ctx, "redirect", "body", "append")}
|
|
|
761
690
|
features,
|
|
762
691
|
note,
|
|
763
692
|
installation,
|
|
764
|
-
sections,
|
|
765
693
|
nav
|
|
766
694
|
} = await getParsedContent(ctx);
|
|
767
|
-
let plainTitle =
|
|
768
|
-
title || stripHTML(htmlTitle || parsedTitle, true) || name
|
|
769
|
-
);
|
|
695
|
+
let plainTitle = await getPlainTitle(ctx);
|
|
770
696
|
let coverTitle = htmlTitle || parsedTitle || plainTitle;
|
|
771
697
|
let descriptionContent = tweakTypography(description) || (escapedPackageDescription ? `<p>${tweakTypography(escapedPackageDescription)}<p>` : "");
|
|
772
698
|
if (!installation || isDevDep !== void 0)
|
|
773
699
|
installation = `npm i${isDevDep ? " -D" : ""} ${name}`;
|
|
774
|
-
let
|
|
775
|
-
|
|
776
|
-
await Promise.all(
|
|
777
|
-
dirs.map(async (path) => {
|
|
778
|
-
let dirPath = join3(dir, path);
|
|
779
|
-
try {
|
|
780
|
-
await access(dirPath);
|
|
781
|
-
} catch {
|
|
782
|
-
await mkdir(dirPath);
|
|
783
|
-
}
|
|
784
|
-
})
|
|
785
|
-
);
|
|
786
|
-
await Promise.all([
|
|
787
|
-
...sections.map(
|
|
788
|
-
async (content, i) => writeFile2(
|
|
789
|
-
join3(dir, contentDir, `${nav[i]?.id ?? `_untitled_${i}`}.html`),
|
|
790
|
-
toFileContent(`
|
|
791
|
-
<!DOCTYPE html>
|
|
792
|
-
<html lang="en" data-layout="section">
|
|
793
|
-
<head>
|
|
794
|
-
${getInjectedContent(ctx, "section", "head", "prepend")}
|
|
795
|
-
<meta charset="utf-8">
|
|
796
|
-
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
797
|
-
<meta name="description" content="${plainTitle}: ${escapeHTML(stripHTML(nav[i]?.title, true))}">
|
|
798
|
-
<title>${escapeHTML(stripHTML(nav[i]?.title, true))} | ${plainTitle}</title>
|
|
799
|
-
<link rel="stylesheet" href="${cssRoot.content}/base.css">
|
|
800
|
-
<link rel="stylesheet" href="${cssRoot.content}/section.css">
|
|
801
|
-
${iconTag}
|
|
802
|
-
${nav[i + 1]?.id ? `<link rel="prefetch" href="${root}${contentDir}/${nav[i + 1]?.id}">` : ""}
|
|
803
|
-
${nav[i - 1]?.id ? `<link rel="prefetch" href="${root}${contentDir}/${nav[i - 1]?.id}">` : ""}
|
|
804
|
-
${getInjectedContent(ctx, "section", "head", "append")}
|
|
805
|
-
</head>
|
|
806
|
-
<body>
|
|
807
|
-
${getInjectedContent(ctx, "section", "body", "prepend")}
|
|
808
|
-
<div class="layout">
|
|
809
|
-
<div class="${navContent ? "" : "no-nav "}body">
|
|
810
|
-
<main>
|
|
811
|
-
<h1><a href="${root}">${plainTitle}</a></h1>
|
|
812
|
-
${content}
|
|
813
|
-
|
|
814
|
-
<p class="pagenav">
|
|
815
|
-
<span class="prev">
|
|
816
|
-
<span class="icon">\u2190</span>
|
|
817
|
-
${nav[i - 1]?.id ? `<a href="${root}${contentDir}/${nav[i - 1]?.id}">${nav[i - 1]?.title}</a>` : `<a href="${root}">Intro</a>`}
|
|
818
|
-
</span>
|
|
819
|
-
<span class="sep">|</span>
|
|
820
|
-
${nav[i + 1]?.id ? `<span class="next"><a href="${root}${contentDir}/${nav[i + 1]?.id}">${nav[i + 1]?.title}</a> <span class="icon">\u2192</span></span>` : `<span class="repo">${getRepoLink(ctx)}</span>`}
|
|
821
|
-
</p>
|
|
822
|
-
</main>
|
|
823
|
-
${navContent ? "<hr>" : ""}
|
|
824
|
-
${navContent.replace(
|
|
825
|
-
new RegExp(
|
|
826
|
-
`(<li data-id="${escapeRegExp(nav[i]?.id)}">)<a href="[^"]+">([^<]+)</a>`
|
|
827
|
-
),
|
|
828
|
-
"$1<strong>$2</strong>"
|
|
829
|
-
)}
|
|
830
|
-
</div>
|
|
831
|
-
</div>
|
|
832
|
-
|
|
833
|
-
${content.includes("<pre><code ") ? getInjectedContent(ctx, "section", ":has-code", "append") || getDefaultCodeStyleContent(cssRoot.content) : ""}
|
|
834
|
-
${counterContent}
|
|
835
|
-
${getInjectedContent(ctx, "section", "body", "append")}
|
|
836
|
-
</body>
|
|
837
|
-
</html>
|
|
838
|
-
`)
|
|
839
|
-
)
|
|
840
|
-
),
|
|
841
|
-
writeFile2(
|
|
842
|
-
join3(dir, "index.html"),
|
|
843
|
-
toFileContent(`
|
|
700
|
+
let cssRoot = await getCSSRoot(ctx, "index");
|
|
701
|
+
return toFileContent(`
|
|
844
702
|
<!DOCTYPE html>
|
|
845
703
|
<html lang="en" data-layout="index">
|
|
846
704
|
<head>
|
|
@@ -849,9 +707,9 @@ ${getInjectedContent(ctx, "section", "body", "append")}
|
|
|
849
707
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
850
708
|
<meta name="description" content="${plainTitle}${escapedPackageDescription ? `: ${escapedPackageDescription}` : ""}">
|
|
851
709
|
<title>${plainTitle}${escapedPackageDescription ? ` | ${escapedPackageDescription}` : ""}</title>
|
|
852
|
-
<link rel="stylesheet" href="${cssRoot
|
|
853
|
-
<link rel="stylesheet" href="${cssRoot
|
|
854
|
-
${
|
|
710
|
+
<link rel="stylesheet" href="${cssRoot}/base.css">
|
|
711
|
+
<link rel="stylesheet" href="${cssRoot}/index.css">
|
|
712
|
+
${getIconTag(ctx)}
|
|
855
713
|
<link rel="prefetch" href="${root}start">
|
|
856
714
|
${nav[0] ? `<link rel="prefetch" href="${root}${contentDir}/${nav[0]?.id ?? ""}">` : ""}
|
|
857
715
|
${getInjectedContent(ctx, "index", "head", "append")}
|
|
@@ -892,16 +750,192 @@ ${intro || features || note ? `
|
|
|
892
750
|
</main>
|
|
893
751
|
</div>
|
|
894
752
|
|
|
895
|
-
${[description, intro, features, note].some((s) => s.includes("<pre><code ")) ? getInjectedContent(ctx, "index", ":has-code", "append") || getDefaultCodeStyleContent(cssRoot
|
|
753
|
+
${[description, intro, features, note].some((s) => s.includes("<pre><code ")) ? getInjectedContent(ctx, "index", ":has-code", "append") || getDefaultCodeStyleContent(cssRoot) : ""}
|
|
896
754
|
${counterContent}
|
|
897
755
|
${getInjectedContent(ctx, "index", "body", "append")}
|
|
898
756
|
</body>
|
|
899
757
|
</html>
|
|
900
|
-
|
|
758
|
+
`);
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
// src/bin/content/getRedirectContent.ts
|
|
762
|
+
function getRedirectContent(ctx) {
|
|
763
|
+
let { redirect } = ctx;
|
|
764
|
+
let escapedRedirect = escapeHTML(redirect);
|
|
765
|
+
return toFileContent(`
|
|
766
|
+
<!DOCTYPE html>
|
|
767
|
+
<html lang="en" data-layout="redirect" class="blank">
|
|
768
|
+
<head>
|
|
769
|
+
${getInjectedContent(ctx, "redirect", "head", "prepend")}
|
|
770
|
+
<meta charset="utf-8">
|
|
771
|
+
<meta name="viewport" content="width=device-width">
|
|
772
|
+
<meta http-equiv="refresh" content="0; URL=${escapedRedirect}">
|
|
773
|
+
${getIconTag(ctx)}
|
|
774
|
+
${getInjectedContent(ctx, "redirect", "head", "append")}
|
|
775
|
+
</head>
|
|
776
|
+
<body>
|
|
777
|
+
${getInjectedContent(ctx, "redirect", "body", "prepend")}
|
|
778
|
+
${getCounterContent(ctx)}
|
|
779
|
+
${getInjectedContent(ctx, "redirect", "body", "append")}
|
|
780
|
+
<script>window.location.replace("${escapedRedirect}");</script>
|
|
781
|
+
</body>
|
|
782
|
+
</html>
|
|
783
|
+
`);
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
// src/utils/escapeRegExp.ts
|
|
787
|
+
function escapeRegExp(s) {
|
|
788
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
// src/bin/content/getNav.ts
|
|
792
|
+
import { JSDOM as JSDOM3 } from "jsdom";
|
|
793
|
+
|
|
794
|
+
// src/bin/getNpmLink.ts
|
|
795
|
+
function getNpmLink({ npm }, className) {
|
|
796
|
+
if (!npm) return "";
|
|
797
|
+
return `<a href="${npm}"${className ? ` class="${className}"` : ""} target="_blank">npm</a>`;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
// src/bin/content/getNav.ts
|
|
801
|
+
async function getNav(ctx, navItems) {
|
|
802
|
+
let { name, root, contentDir, backstory, nav } = ctx;
|
|
803
|
+
let navContent = await fetchContent(nav);
|
|
804
|
+
let s = "";
|
|
805
|
+
if (navContent) {
|
|
806
|
+
let navDom = new JSDOM3(navContent).window.document.body;
|
|
807
|
+
for (let link of navDom.querySelectorAll("a")) {
|
|
808
|
+
if (link.dataset.name === name) {
|
|
809
|
+
let parent = link.parentElement;
|
|
810
|
+
link.remove();
|
|
811
|
+
while (parent && parent.innerHTML.trim() === "") {
|
|
812
|
+
let nextParent = parent.parentElement;
|
|
813
|
+
parent.remove();
|
|
814
|
+
parent = nextParent;
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
navContent = navDom.innerHTML;
|
|
819
|
+
}
|
|
820
|
+
let navItemCount = 0;
|
|
821
|
+
if (navItems.length === 1) {
|
|
822
|
+
let { id, items } = navItems[0];
|
|
823
|
+
let itemLink = `${root}${contentDir}/${encodeURIComponent(id)}`;
|
|
824
|
+
for (let { id: id2, title } of items) {
|
|
825
|
+
s += `
|
|
826
|
+
<li><a href="${itemLink}#${encodeURIComponent(id2)}">${title}</a></li>`;
|
|
827
|
+
navItemCount++;
|
|
828
|
+
}
|
|
829
|
+
} else {
|
|
830
|
+
for (let { id, title, items } of navItems) {
|
|
831
|
+
let itemLink = `${root}${contentDir}/${encodeURIComponent(id)}`;
|
|
832
|
+
s += `
|
|
833
|
+
<li data-id="${id}"><a href="${itemLink}">${title}</a>`;
|
|
834
|
+
if (items.length !== 0) {
|
|
835
|
+
s += "\n <ul>";
|
|
836
|
+
for (let { id: id2, title: title2 } of items) {
|
|
837
|
+
s += `
|
|
838
|
+
<li><a href="${itemLink}#${encodeURIComponent(id2)}">${title2}</a></li>`;
|
|
839
|
+
navItemCount++;
|
|
840
|
+
}
|
|
841
|
+
s += "\n </ul>\n";
|
|
842
|
+
}
|
|
843
|
+
s += "</li>";
|
|
844
|
+
navItemCount++;
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
if ((!s || navItemCount < 2) && !navContent) return "";
|
|
848
|
+
s = s.trim();
|
|
849
|
+
s = s ? `<p class="title">Contents</p>
|
|
850
|
+
<ul>${s}
|
|
851
|
+
</ul>
|
|
852
|
+
` : "";
|
|
853
|
+
let repoLink = getRepoLink(ctx);
|
|
854
|
+
let npmLink = getNpmLink(ctx);
|
|
855
|
+
if (repoLink || npmLink || backstory)
|
|
856
|
+
s += `
|
|
857
|
+
<p class="title">Resources</p>
|
|
858
|
+
<ul>
|
|
859
|
+
${repoLink ? `<li>${repoLink}</li>` : ""}
|
|
860
|
+
${npmLink ? `<li>${npmLink}</li>` : ""}
|
|
861
|
+
${backstory ? `<li><a href="${backstory}">Backstory</a></li>` : ""}
|
|
862
|
+
</ul>
|
|
863
|
+
`;
|
|
864
|
+
s = s.trim();
|
|
865
|
+
s = s ? `<section>
|
|
866
|
+
${s}
|
|
867
|
+
</section>` : "";
|
|
868
|
+
return `<nav class="aux">
|
|
869
|
+
${s}
|
|
870
|
+
${navContent}
|
|
871
|
+
</nav>`;
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
// src/bin/content/getSectionContent.ts
|
|
875
|
+
async function getSectionContent(ctx, index) {
|
|
876
|
+
let { root, contentDir = "" } = ctx;
|
|
877
|
+
let cssRoot = await getCSSRoot(ctx, "content");
|
|
878
|
+
let { sections, nav } = await getParsedContent(ctx);
|
|
879
|
+
let content = sections[index];
|
|
880
|
+
let navContent = await getNav(ctx, nav);
|
|
881
|
+
let plainTitle = await getPlainTitle(ctx);
|
|
882
|
+
return toFileContent(`
|
|
883
|
+
<!DOCTYPE html>
|
|
884
|
+
<html lang="en" data-layout="section">
|
|
885
|
+
<head>
|
|
886
|
+
${getInjectedContent(ctx, "section", "head", "prepend")}
|
|
887
|
+
<meta charset="utf-8">
|
|
888
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
889
|
+
<meta name="description" content="${plainTitle}: ${escapeHTML(stripHTML(nav[index]?.title, true))}">
|
|
890
|
+
<title>${escapeHTML(stripHTML(nav[index]?.title, true))} | ${plainTitle}</title>
|
|
891
|
+
<link rel="stylesheet" href="${cssRoot}/base.css">
|
|
892
|
+
<link rel="stylesheet" href="${cssRoot}/section.css">
|
|
893
|
+
${getIconTag(ctx)}
|
|
894
|
+
${nav[index + 1]?.id ? `<link rel="prefetch" href="${root}${contentDir}/${nav[index + 1]?.id}">` : ""}
|
|
895
|
+
${nav[index - 1]?.id ? `<link rel="prefetch" href="${root}${contentDir}/${nav[index - 1]?.id}">` : ""}
|
|
896
|
+
${getInjectedContent(ctx, "section", "head", "append")}
|
|
897
|
+
</head>
|
|
898
|
+
<body>
|
|
899
|
+
${getInjectedContent(ctx, "section", "body", "prepend")}
|
|
900
|
+
<div class="layout">
|
|
901
|
+
<div class="${navContent ? "" : "no-nav "}body">
|
|
902
|
+
<main>
|
|
903
|
+
<h1><a href="${root}">${plainTitle}</a></h1>
|
|
904
|
+
${content}
|
|
905
|
+
|
|
906
|
+
<p class="pagenav">
|
|
907
|
+
<span class="prev">
|
|
908
|
+
<span class="icon">\u2190</span>
|
|
909
|
+
${nav[index - 1]?.id ? `<a href="${root}${contentDir}/${nav[index - 1]?.id}">${nav[index - 1]?.title}</a>` : `<a href="${root}">Intro</a>`}
|
|
910
|
+
</span>
|
|
911
|
+
<span class="sep">|</span>
|
|
912
|
+
${nav[index + 1]?.id ? `<span class="next"><a href="${root}${contentDir}/${nav[index + 1]?.id}">${nav[index + 1]?.title}</a> <span class="icon">\u2192</span></span>` : `<span class="repo">${getRepoLink(ctx)}</span>`}
|
|
913
|
+
</p>
|
|
914
|
+
</main>
|
|
915
|
+
${navContent ? "<hr>" : ""}
|
|
916
|
+
${navContent.replace(
|
|
917
|
+
new RegExp(
|
|
918
|
+
`(<li data-id="${escapeRegExp(nav[index]?.id)}">)<a href="[^"]+">([^<]+)</a>`
|
|
901
919
|
),
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
920
|
+
"$1<strong>$2</strong>"
|
|
921
|
+
)}
|
|
922
|
+
</div>
|
|
923
|
+
</div>
|
|
924
|
+
|
|
925
|
+
${content.includes("<pre><code ") ? getInjectedContent(ctx, "section", ":has-code", "append") || getDefaultCodeStyleContent(cssRoot) : ""}
|
|
926
|
+
${getCounterContent(ctx)}
|
|
927
|
+
${getInjectedContent(ctx, "section", "body", "append")}
|
|
928
|
+
</body>
|
|
929
|
+
</html>
|
|
930
|
+
`);
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
// src/bin/content/getStartContent.ts
|
|
934
|
+
async function getStartContent(ctx) {
|
|
935
|
+
let { root, contentDir = "" } = ctx;
|
|
936
|
+
let { nav } = await getParsedContent(ctx);
|
|
937
|
+
let plainTitle = await getPlainTitle(ctx);
|
|
938
|
+
return toFileContent(`
|
|
905
939
|
<!DOCTYPE html>
|
|
906
940
|
<html lang="en" data-layout="start" class="blank">
|
|
907
941
|
<head>
|
|
@@ -910,8 +944,8 @@ ${getInjectedContent(ctx, "index", "body", "append")}
|
|
|
910
944
|
<meta name="viewport" content="width=device-width">
|
|
911
945
|
<meta http-equiv="refresh" content="0; URL=${root}${contentDir}/${nav[0]?.id}">
|
|
912
946
|
<title>${plainTitle}</title>
|
|
913
|
-
<link rel="stylesheet" href="${
|
|
914
|
-
${
|
|
947
|
+
<link rel="stylesheet" href="${await getCSSRoot(ctx, "index")}/base.css">
|
|
948
|
+
${getIconTag(ctx)}
|
|
915
949
|
<script>window.location.replace("${root}${contentDir}/${nav[0]?.id}");</script>
|
|
916
950
|
${getInjectedContent(ctx, "start", "head", "append")}
|
|
917
951
|
</head>
|
|
@@ -921,18 +955,37 @@ ${getInjectedContent(ctx, "start", "body", "prepend")}
|
|
|
921
955
|
<h1>${plainTitle}</h1>
|
|
922
956
|
</div>
|
|
923
957
|
|
|
924
|
-
${
|
|
958
|
+
${getCounterContent(ctx)}
|
|
925
959
|
${getInjectedContent(ctx, "start", "body", "append")}
|
|
926
960
|
</body>
|
|
927
961
|
</html>
|
|
928
|
-
|
|
929
|
-
|
|
962
|
+
`);
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
// src/bin/setContent.ts
|
|
966
|
+
async function setContent(ctx) {
|
|
967
|
+
let { dir = "", contentDir = "", redirect } = ctx;
|
|
968
|
+
if (redirect) {
|
|
969
|
+
await writeFile2(join5(dir, "index.html"), getRedirectContent(ctx));
|
|
970
|
+
return;
|
|
971
|
+
}
|
|
972
|
+
let { sections, nav } = await getParsedContent(ctx);
|
|
973
|
+
await createDirs(ctx);
|
|
974
|
+
await Promise.all([
|
|
975
|
+
...sections.map(
|
|
976
|
+
async (_, i) => writeFile2(
|
|
977
|
+
join5(dir, contentDir, `${nav[i]?.id ?? `_Section_${i + 1}`}.html`),
|
|
978
|
+
await getSectionContent(ctx, i)
|
|
979
|
+
)
|
|
980
|
+
),
|
|
981
|
+
writeFile2(join5(dir, "index.html"), await getIndexContent(ctx)),
|
|
982
|
+
writeFile2(join5(dir, "start.html"), await getStartContent(ctx))
|
|
930
983
|
]);
|
|
931
984
|
}
|
|
932
985
|
|
|
933
986
|
// src/bin/setImages.ts
|
|
934
987
|
import { writeFile as writeFile3 } from "node:fs/promises";
|
|
935
|
-
import { join as
|
|
988
|
+
import { join as join6 } from "node:path";
|
|
936
989
|
|
|
937
990
|
// src/utils/getIconContent.ts
|
|
938
991
|
function getIconContent(baseColor = "gray") {
|
|
@@ -952,7 +1005,7 @@ function getIconContent(baseColor = "gray") {
|
|
|
952
1005
|
// src/bin/setImages.ts
|
|
953
1006
|
async function setImages({ dir = "", favicon }) {
|
|
954
1007
|
if (favicon) return;
|
|
955
|
-
await writeFile3(
|
|
1008
|
+
await writeFile3(join6(dir, "./favicon.svg"), `${getIconContent()}
|
|
956
1009
|
`);
|
|
957
1010
|
}
|
|
958
1011
|
|