@t8/docsgen 0.4.18 → 0.4.20

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 CHANGED
@@ -349,7 +349,7 @@ async function getRepoMetadata({
349
349
  }
350
350
 
351
351
  // src/bin/parsing/getParsedContent.ts
352
- import { JSDOM as JSDOM2 } from "jsdom";
352
+ import { JSDOM as JSDOM3 } from "jsdom";
353
353
  import Markdown from "markdown-it";
354
354
 
355
355
  // src/bin/getSlug.ts
@@ -424,15 +424,40 @@ function getInstallationCode(element) {
424
424
  }
425
425
 
426
426
  // src/bin/parsing/getSectionPostprocess.ts
427
+ import { JSDOM as JSDOM2 } from "jsdom";
428
+ function isPreviewURL(url) {
429
+ return url.startsWith("https://codesandbox.io/p/sandbox/");
430
+ }
431
+ function getPreviewContent(url, title) {
432
+ let { pathname, searchParams } = new URL(url);
433
+ let sandboxId = pathname.split("/").at(-1);
434
+ let file = searchParams.get("file");
435
+ let previewURL = new URL(`https://codesandbox.io/embed/${sandboxId}`);
436
+ let previewContent = title ? `<legend>${title}</legend>` : "";
437
+ previewURL.searchParams.set("view", "preview");
438
+ if (file) previewURL.searchParams.set("module", file);
439
+ previewContent += `<iframe src="${previewURL.href}"${title ? ` title="${title}"` : ""} sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts" loading="lazy"></iframe>`;
440
+ return previewContent;
441
+ }
427
442
  function getSectionPostprocess(linkMap) {
428
443
  return (content) => {
429
- let s = content;
430
- s = s.replace(/<a href="([^"]+)">/g, (_, url) => {
431
- let nextURL = linkMap[url] ?? url;
432
- let attrs = /^(https?:)?\/\//.test(nextURL) ? ' target="_blank"' : "";
433
- return `<a href="${nextURL}"${attrs}>`;
434
- });
435
- return s;
444
+ let { document } = new JSDOM2(content).window;
445
+ for (let a of document.querySelectorAll("a")) {
446
+ let href = a.getAttribute("href");
447
+ if (href === null) continue;
448
+ if (isPreviewURL(href) && a.parentElement) {
449
+ let preview = document.createElement("fieldset");
450
+ preview.innerHTML = getPreviewContent(href, a.innerHTML);
451
+ a.parentElement.insertBefore(preview, a);
452
+ a.remove();
453
+ } else {
454
+ let nextHref = linkMap[href] ?? href;
455
+ a.setAttribute("href", nextHref);
456
+ if (/^(https?:)?\/\//.test(nextHref))
457
+ a.setAttribute("target", "_blank");
458
+ }
459
+ }
460
+ return document.body.innerHTML;
436
461
  };
437
462
  }
438
463
 
@@ -485,7 +510,7 @@ async function getParsedContent(ctx) {
485
510
  let { singlePage, firstLineDescription, linkMap } = ctx;
486
511
  let rawContent = await fetchContent(contentLocation);
487
512
  let content = md.render(preprocessContent(rawContent));
488
- let dom = new JSDOM2(content);
513
+ let dom = new JSDOM3(content);
489
514
  let { nav, linkMap: navLinkMap } = buildNav(ctx, dom);
490
515
  let badges = "";
491
516
  let title = "";
@@ -801,17 +826,8 @@ function escapeRegExp(s) {
801
826
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
802
827
  }
803
828
 
804
- // src/bin/content/getInstallationContent.ts
805
- async function getInstallationContent(ctx) {
806
- let { name, isDevDep } = ctx;
807
- let { installation } = await getParsedContent(ctx);
808
- if (!installation || isDevDep !== void 0)
809
- installation = `npm i${isDevDep ? " -D" : ""} ${name}`;
810
- return `<code>${escapeHTML(installation)}</code>`;
811
- }
812
-
813
829
  // src/bin/content/getNav.ts
814
- import { JSDOM as JSDOM3 } from "jsdom";
830
+ import { JSDOM as JSDOM4 } from "jsdom";
815
831
 
816
832
  // src/bin/getNpmLink.ts
817
833
  function getNpmLink({ npm }, className) {
@@ -825,7 +841,7 @@ async function getNav(ctx, navItems) {
825
841
  let navContent = await fetchContent(nav);
826
842
  let s = "";
827
843
  if (navContent) {
828
- let navDom = new JSDOM3(navContent).window.document.body;
844
+ let navDom = new JSDOM4(navContent).window.document.body;
829
845
  for (let link of navDom.querySelectorAll("a")) {
830
846
  if (link.dataset.name === name) {
831
847
  let parent = link.parentElement;
@@ -896,12 +912,10 @@ ${navContent}
896
912
  // src/bin/content/getSectionContent.ts
897
913
  async function getSectionContent(ctx, index) {
898
914
  let { root, contentDir = "" } = ctx;
899
- let descriptionContent = escapeHTML(tweakTypography(ctx.description));
900
- let cssRoot = await getCSSRoot(ctx, "content");
901
915
  let { sections, nav } = await getParsedContent(ctx);
916
+ let cssRoot = await getCSSRoot(ctx, "content");
902
917
  let content = sections[index];
903
918
  let navContent = await getNav(ctx, nav);
904
- let mainTitle = await getMainTitle(ctx);
905
919
  let plainTitle = await getPlainTitle(ctx);
906
920
  return toFileContent(`
907
921
  <!DOCTYPE html>
@@ -922,11 +936,9 @@ async function getSectionContent(ctx, index) {
922
936
  <body>
923
937
  ${getInjectedContent(ctx, "section", "body", "prepend")}
924
938
  <div class="layout">
925
- <header class="compact">
926
- <h1><a href="${root}">${plainTitle}</a></h1>
927
- </header>
928
939
  <div class="${navContent ? "" : "no-nav "}body">
929
940
  <main>
941
+ <h1><a href="${root}">${plainTitle}</a></h1>
930
942
  ${content}
931
943
 
932
944
  <p class="pagenav">
@@ -935,22 +947,15 @@ ${content}
935
947
  ${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>`}
936
948
  </p>
937
949
  </main>
938
- <hr>
950
+ ${navContent && `<hr>
939
951
  <aside class="aux">
940
- <div class="header" hidden>
941
- <h1>${mainTitle}</h1>
942
- <div class="description">
943
- <p>${descriptionContent}</p>
944
- <p class="installation">${await getInstallationContent(ctx)}</p>
945
- </div>
946
- </div>
947
952
  ${navContent.replace(
948
953
  new RegExp(
949
954
  `(<li data-id="${escapeRegExp(nav[index]?.id)}">)<a href="[^"]+">([^<]+)</a>`
950
955
  ),
951
956
  "$1<strong>$2</strong>"
952
957
  )}
953
- </aside>
958
+ </aside>`}
954
959
  </div>
955
960
  </div>
956
961
 
@@ -80,29 +80,10 @@ aside {
80
80
  var(--aux-background-end)
81
81
  );
82
82
  border-right: 0.05em solid var(--aux-border-color);
83
- padding: var(--content-padding-y) var(--content-padding-x);
83
+ padding: 0 var(--content-padding-x);
84
84
  margin: 0;
85
85
  box-sizing: border-box;
86
86
  }
87
- aside > .header {
88
- display: block;
89
- margin: 0.5rem 0 0.25rem;
90
- }
91
- aside > .header .description p:not(.installation) {
92
- font-size: 0.9em;
93
- margin: 0.35em 0 0;
94
- }
95
- aside > .header .description p.installation {
96
- margin: 1em 0 0;
97
- }
98
- aside > .header .installation code {
99
- display: inline-block;
100
- background: transparent;
101
- border: 0.05em solid;
102
- border-radius: 0.5em;
103
- padding: 0.35em 0.75em;
104
- margin: 0;
105
- }
106
87
  aside h1 {
107
88
  font-size: 1.3rem;
108
89
  margin: 0;
@@ -113,7 +94,7 @@ aside nav {
113
94
  aside section {
114
95
  width: 100%;
115
96
  max-width: 16em;
116
- padding: 1rem 0;
97
+ padding: var(--content-padding-y) 0;
117
98
  box-sizing: border-box;
118
99
  }
119
100
  aside section + section {
@@ -179,9 +160,6 @@ aside li > strong {
179
160
  padding: 0.25rem var(--content-padding-x) 0.35rem;
180
161
  margin: 0;
181
162
  }
182
- aside > .header {
183
- display: none;
184
- }
185
163
  aside nav {
186
164
  font-size: inherit;
187
165
  }
@@ -246,6 +224,13 @@ main h1 {
246
224
  color: var(--secondary-color);
247
225
  margin: 0;
248
226
  }
227
+ main h1 a,
228
+ main h1 a:link,
229
+ main h1 a:visited,
230
+ main h1 a:hover,
231
+ main h1 a:active {
232
+ --color: var(--secondary-color);
233
+ }
249
234
  h1 .sep {
250
235
  margin: 0 0.1em;
251
236
  }
@@ -265,6 +250,20 @@ main h2 {
265
250
  main h2:first-child {
266
251
  margin-top: 0;
267
252
  }
253
+ main fieldset {
254
+ border: 0.05em solid var(--secondary-color);
255
+ }
256
+ main fieldset legend {
257
+ font-size: 0.8em;
258
+ color: var(--secondary-color);
259
+ }
260
+ main fieldset iframe {
261
+ width: 100%;
262
+ height: 360px;
263
+ background: var(--code-block-background);
264
+ border: none;
265
+ overflow: hidden;
266
+ }
268
267
 
269
268
  .pagenav {
270
269
  --icon-width: 1.25em;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@t8/docsgen",
3
- "version": "0.4.18",
3
+ "version": "0.4.20",
4
4
  "description": "",
5
5
  "main": "dist/bin.js",
6
6
  "type": "module",
@@ -9,24 +9,17 @@ import { getCSSRoot } from "./getCSSRoot.ts";
9
9
  import { getDefaultCodeStyleContent } from "./getDefaultCodeStyleContent.ts";
10
10
  import { getIconTag } from "./getIconTag.ts";
11
11
  import { getInjectedContent } from "./getInjectedContent.ts";
12
- import { getInstallationContent } from "./getInstallationContent.ts";
13
- import { getMainTitle } from "./getMainTitle.ts";
14
12
  import { getNav } from "./getNav.ts";
15
13
  import { getPlainTitle } from "./getPlainTitle.ts";
16
14
  import { toFileContent } from "./toFileContent.ts";
17
- import { tweakTypography } from "./tweakTypography.ts";
18
15
 
19
16
  export async function getSectionContent(ctx: Context, index: number) {
20
17
  let { root, contentDir = "" } = ctx;
21
- let descriptionContent = escapeHTML(tweakTypography(ctx.description));
22
-
23
- let cssRoot = await getCSSRoot(ctx, "content");
24
18
  let { sections, nav } = await getParsedContent(ctx);
19
+ let cssRoot = await getCSSRoot(ctx, "content");
25
20
 
26
21
  let content = sections[index];
27
22
  let navContent = await getNav(ctx, nav);
28
-
29
- let mainTitle = await getMainTitle(ctx);
30
23
  let plainTitle = await getPlainTitle(ctx);
31
24
 
32
25
  return toFileContent(`
@@ -48,11 +41,9 @@ export async function getSectionContent(ctx: Context, index: number) {
48
41
  <body>
49
42
  ${getInjectedContent(ctx, "section", "body", "prepend")}
50
43
  <div class="layout">
51
- <header class="compact">
52
- <h1><a href="${root}">${plainTitle}</a></h1>
53
- </header>
54
44
  <div class="${navContent ? "" : "no-nav "}body">
55
45
  <main>
46
+ <h1><a href="${root}">${plainTitle}</a></h1>
56
47
  ${content}
57
48
 
58
49
  <p class="pagenav">
@@ -60,22 +51,18 @@ ${content}
60
51
  ${nav[index + 1]?.id ? `<span class="next"><a href="${root}${contentDir}/${nav[index + 1]?.id}">${nav[index + 1]?.title}</a> <span class="icon">→</span></span>` : `<span class="repo">${getRepoLink(ctx)}</span>`}
61
52
  </p>
62
53
  </main>
63
- <hr>
54
+ ${
55
+ navContent &&
56
+ `<hr>
64
57
  <aside class="aux">
65
- <div class="header" hidden>
66
- <h1>${mainTitle}</h1>
67
- <div class="description">
68
- <p>${descriptionContent}</p>
69
- <p class="installation">${await getInstallationContent(ctx)}</p>
70
- </div>
71
- </div>
72
58
  ${navContent.replace(
73
59
  new RegExp(
74
60
  `(<li data-id="${escapeRegExp(nav[index]?.id)}">)<a href="[^"]+">([^<]+)</a>`,
75
61
  ),
76
62
  "$1<strong>$2</strong>",
77
63
  )}
78
- </aside>
64
+ </aside>`
65
+ }
79
66
  </div>
80
67
  </div>
81
68
 
@@ -1,16 +1,53 @@
1
+ import { JSDOM } from "jsdom";
2
+
3
+ function isPreviewURL(url: string) {
4
+ return url.startsWith("https://codesandbox.io/p/sandbox/");
5
+ }
6
+
7
+ function getPreviewContent(url: string, title?: string) {
8
+ let { pathname, searchParams } = new URL(url);
9
+ let sandboxId = pathname.split("/").at(-1);
10
+ let file = searchParams.get("file");
11
+
12
+ let previewURL = new URL(`https://codesandbox.io/embed/${sandboxId}`);
13
+ let previewContent = title ? `<legend>${title}</legend>` : "";
14
+
15
+ previewURL.searchParams.set("view", "preview");
16
+
17
+ if (file) previewURL.searchParams.set("module", file);
18
+
19
+ previewContent += `<iframe src="${previewURL.href}"${title ? ` title="${title}"` : ""} sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts" loading="lazy"></iframe>`;
20
+
21
+ return previewContent;
22
+ }
23
+
1
24
  export function getSectionPostprocess(
2
25
  linkMap: Record<string, string | undefined>,
3
26
  ) {
4
27
  return (content: string) => {
5
- let s = content;
28
+ let { document } = new JSDOM(content).window;
29
+
30
+ for (let a of document.querySelectorAll("a")) {
31
+ let href = a.getAttribute("href");
32
+
33
+ if (href === null) continue;
34
+
35
+ if (isPreviewURL(href) && a.parentElement) {
36
+ let preview = document.createElement("fieldset");
37
+
38
+ preview.innerHTML = getPreviewContent(href, a.innerHTML);
6
39
 
7
- s = s.replace(/<a href="([^"]+)">/g, (_, url) => {
8
- let nextURL = linkMap[url] ?? url;
9
- let attrs = /^(https?:)?\/\//.test(nextURL) ? ' target="_blank"' : "";
40
+ a.parentElement.insertBefore(preview, a);
41
+ a.remove();
42
+ } else {
43
+ let nextHref = linkMap[href] ?? href;
10
44
 
11
- return `<a href="${nextURL}"${attrs}>`;
12
- });
45
+ a.setAttribute("href", nextHref);
46
+ if (/^(https?:)?\/\//.test(nextHref))
47
+ a.setAttribute("target", "_blank");
48
+ }
49
+ }
13
50
 
14
- return s;
51
+ return document.body.innerHTML;
15
52
  };
16
53
  }
@@ -80,29 +80,10 @@ aside {
80
80
  var(--aux-background-end)
81
81
  );
82
82
  border-right: 0.05em solid var(--aux-border-color);
83
- padding: var(--content-padding-y) var(--content-padding-x);
83
+ padding: 0 var(--content-padding-x);
84
84
  margin: 0;
85
85
  box-sizing: border-box;
86
86
  }
87
- aside > .header {
88
- display: block;
89
- margin: 0.5rem 0 0.25rem;
90
- }
91
- aside > .header .description p:not(.installation) {
92
- font-size: 0.9em;
93
- margin: 0.35em 0 0;
94
- }
95
- aside > .header .description p.installation {
96
- margin: 1em 0 0;
97
- }
98
- aside > .header .installation code {
99
- display: inline-block;
100
- background: transparent;
101
- border: 0.05em solid;
102
- border-radius: 0.5em;
103
- padding: 0.35em 0.75em;
104
- margin: 0;
105
- }
106
87
  aside h1 {
107
88
  font-size: 1.3rem;
108
89
  margin: 0;
@@ -113,7 +94,7 @@ aside nav {
113
94
  aside section {
114
95
  width: 100%;
115
96
  max-width: 16em;
116
- padding: 1rem 0;
97
+ padding: var(--content-padding-y) 0;
117
98
  box-sizing: border-box;
118
99
  }
119
100
  aside section + section {
@@ -179,9 +160,6 @@ aside li > strong {
179
160
  padding: 0.25rem var(--content-padding-x) 0.35rem;
180
161
  margin: 0;
181
162
  }
182
- aside > .header {
183
- display: none;
184
- }
185
163
  aside nav {
186
164
  font-size: inherit;
187
165
  }
@@ -246,6 +224,13 @@ main h1 {
246
224
  color: var(--secondary-color);
247
225
  margin: 0;
248
226
  }
227
+ main h1 a,
228
+ main h1 a:link,
229
+ main h1 a:visited,
230
+ main h1 a:hover,
231
+ main h1 a:active {
232
+ --color: var(--secondary-color);
233
+ }
249
234
  h1 .sep {
250
235
  margin: 0 0.1em;
251
236
  }
@@ -265,6 +250,20 @@ main h2 {
265
250
  main h2:first-child {
266
251
  margin-top: 0;
267
252
  }
253
+ main fieldset {
254
+ border: 0.05em solid var(--secondary-color);
255
+ }
256
+ main fieldset legend {
257
+ font-size: 0.8em;
258
+ color: var(--secondary-color);
259
+ }
260
+ main fieldset iframe {
261
+ width: 100%;
262
+ height: 360px;
263
+ background: var(--code-block-background);
264
+ border: none;
265
+ overflow: hidden;
266
+ }
268
267
 
269
268
  .pagenav {
270
269
  --icon-width: 1.25em;