├── public ├── empty.html ├── logo.png ├── favicon.ico ├── logo-bg.png ├── favicon-16x16.png ├── favicon-32x32.png ├── mstile-70x70.png ├── apple-touch-icon.png ├── mstile-144x144.png ├── mstile-150x150.png ├── mstile-310x150.png ├── mstile-310x310.png ├── sponsor-placeholder.png ├── android-chrome-192x192.png ├── android-chrome-512x512.png ├── site.webmanifest ├── browserconfig.xml ├── safari-pinned-tab.svg ├── badge.svg └── powered-by-vercel.svg ├── .husky ├── .gitignore ├── pre-commit ├── pre-push └── commit-msg ├── commitlint.config.js ├── .eslintrc ├── postcss.config.js ├── vercel.json ├── src ├── data │ ├── window-script.ts │ ├── vercel-url.ts │ ├── bookmarklets.ts │ ├── dark-mode-script.ts │ ├── heroicons-license.ts │ ├── modern-normalize-license.ts │ ├── tailwind-css-license.ts │ ├── sponsors.ts │ └── examples.ts ├── lib │ ├── sort-by-id.ts │ ├── has-package-declarations.ts │ ├── is-valid-license.ts │ ├── package-page-kind.ts │ ├── revalidate-times.ts │ ├── min-semver-version.ts │ ├── load-nprogress.ts │ ├── clean-object.ts │ ├── is-callable-declaration-kind.ts │ ├── get-package-page-error-props.ts │ ├── parse-json-stream.ts │ ├── storage.ts │ ├── registry-package-info-storage.ts │ ├── analyze-registry-package-with-worker.ts │ ├── get-oss-libraries.ts │ ├── get-declaration-kind-description.ts │ ├── flatten-package-api.ts │ ├── get-package-page-static-props.ts │ ├── get-registry-package-info.ts │ ├── get-package-page-available-versions-props.ts │ ├── parse-package-route.ts │ └── get-package-page-docs-props.ts ├── worker │ └── analyze-registry-package-worker.js ├── components │ ├── common │ │ ├── InlineCode.tsx │ │ ├── Main.tsx │ │ ├── CodeBlock.tsx │ │ ├── PackageVersionsLink.tsx │ │ ├── NavbarLink.tsx │ │ ├── A.tsx │ │ ├── TimeAgo.tsx │ │ ├── Layout.tsx │ │ ├── PackageLink.tsx │ │ ├── NavbarLinks.tsx │ │ ├── SyntaxHighlight.tsx │ │ ├── InternalLink.tsx │ │ ├── CodeBlockContents.tsx │ │ ├── Navbar.tsx │ │ ├── Head.tsx │ │ └── SearchBar.tsx │ ├── CharSetTag.tsx │ ├── TitleTag.tsx │ ├── DescriptionTag.tsx │ ├── ViewportTag.tsx │ ├── package │ │ ├── PackageLicenseAlert.tsx │ │ ├── PackageMissingTypesAlert.tsx │ │ ├── PackageFilesSection.tsx │ │ ├── PackageIndexEnumsSection.tsx │ │ ├── PackageInstallSection.tsx │ │ ├── PackageIndexClassesSection.tsx │ │ ├── PackageOverviewSection.tsx │ │ ├── PackageIndexFunctionsSection.tsx │ │ ├── PackageIndexVariablesList.tsx │ │ ├── PackageIndexVariablesSection.tsx │ │ ├── PackageIndexFunctionsList.tsx │ │ ├── PackageExternalTypesAlert.tsx │ │ ├── PackageIndexInterfacesSection.tsx │ │ ├── PackageIndexNamespacesSection.tsx │ │ ├── PackageIndexTypeAliasesList.tsx │ │ ├── PackageIndexTypeAliasesSection.tsx │ │ ├── PackageEnumsSection.tsx │ │ ├── PackageIndexEnumMembersList.tsx │ │ ├── PackageClassesSection.tsx │ │ ├── PackageFunctionsSection.tsx │ │ ├── PackageVariablesSection.tsx │ │ ├── PackageFilesList.tsx │ │ ├── PackageTypeAliasesSection.tsx │ │ ├── PackageIndexEnumsList.tsx │ │ ├── PackageInterfacesSection.tsx │ │ ├── PackageNamespacesSection.tsx │ │ ├── PackageEnumDeclarationSections.tsx │ │ ├── PackageAlerts.tsx │ │ ├── PackageIndexClassesList.tsx │ │ ├── PackageIndexInterfacesList.tsx │ │ ├── PackageIndexNamespacesList.tsx │ │ ├── PackageDependenciesList.tsx │ │ ├── PackageDependenciesSection.tsx │ │ ├── PackageDistTagsSection.tsx │ │ ├── PackageNav.tsx │ │ ├── PackageDeclarationSection.tsx │ │ ├── PackageTitleSection.tsx │ │ ├── PackageDeclarationTitle.tsx │ │ ├── PackageNavExternalResourcesList.tsx │ │ ├── PackageVersionsSection.tsx │ │ ├── PackageIndexNamespaceMembersList.tsx │ │ ├── PackageClassDeclarationSections.tsx │ │ ├── PackageIndexClassMembersList.tsx │ │ ├── PackageIndexInterfaceMembersList.tsx │ │ ├── PackageNavPackagesList.tsx │ │ ├── PackageBadgeSection.tsx │ │ ├── PackageInterfaceDeclarationSections.tsx │ │ ├── PackageIndexSection.tsx │ │ ├── PackageFooterSection.tsx │ │ ├── PackageNamespaceDeclarationSections.tsx │ │ └── PackageNavDocsResourcesList.tsx │ ├── Footer.tsx │ ├── Logo.tsx │ ├── PageHead.tsx │ ├── Favicon.tsx │ ├── OpenGraphTags.tsx │ ├── TwitterTags.tsx │ ├── FooterLinks.tsx │ ├── ThemeButton.tsx │ ├── pages │ │ └── PackagePageAvailableVersions.tsx │ └── search │ │ └── SearchResults.tsx ├── hooks │ ├── useAnchorLinks.ts │ ├── useLocationHashRefresh.ts │ ├── useSearch.ts │ └── useSearchPackages.ts ├── types │ └── window.ts └── pages │ ├── _app.tsx │ ├── _document.tsx │ ├── 404.tsx │ ├── search.tsx │ ├── package │ └── [...slug].tsx │ ├── index.tsx │ ├── privacy.tsx │ ├── credits.tsx │ └── sponsor.tsx ├── config └── jest │ └── cssTransform.js ├── tailwind.config.js ├── next-env.d.ts ├── setupTests.js ├── test └── lib │ ├── revalidate-times.test.ts │ ├── sort-by-id.test.ts │ ├── parse-json-stream.test.ts │ ├── get-oss-libraries.test.ts │ ├── analyze-registry-package-with-worker.test.ts │ ├── clean-object.test.ts │ ├── min-semver-version.test.ts │ ├── is-valid-license.test.ts │ ├── registry-info-storage.test.ts │ ├── get-declaration-kind-description.test.ts │ ├── is-callable-declaration-kind.test.ts │ ├── has-package-declarations.test.ts │ ├── storage.test.ts │ └── parse-package-route.test.ts ├── .prettierignore ├── .github ├── dependabot.yml ├── FUNDING.yml ├── workflows │ ├── not-main.yml │ └── main.yml └── ISSUE_TEMPLATE │ └── package-with-missing-or-incorrect-documentation.md ├── jest.config.js ├── .gitignore ├── tsconfig.json ├── config.ts ├── scripts ├── update-robots-txt.ts └── update-sitemap.ts ├── styles └── index.css ├── faviconDescription.json ├── next.config.js ├── README.md ├── .vscode └── settings.json ├── faviconData.json └── package.json /public/empty.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsdocs-io/web/HEAD/public/logo.png -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | pnpm lint 5 | -------------------------------------------------------------------------------- /.husky/pre-push: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | pnpm pre-push 5 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsdocs-io/web/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/logo-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsdocs-io/web/HEAD/public/logo-bg.png -------------------------------------------------------------------------------- /public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsdocs-io/web/HEAD/public/favicon-16x16.png -------------------------------------------------------------------------------- /public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsdocs-io/web/HEAD/public/favicon-32x32.png -------------------------------------------------------------------------------- /public/mstile-70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsdocs-io/web/HEAD/public/mstile-70x70.png -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | pnpm commitlint --edit $1 5 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ["@commitlint/config-conventional"], 3 | }; 4 | -------------------------------------------------------------------------------- /public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsdocs-io/web/HEAD/public/apple-touch-icon.png -------------------------------------------------------------------------------- /public/mstile-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsdocs-io/web/HEAD/public/mstile-144x144.png -------------------------------------------------------------------------------- /public/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsdocs-io/web/HEAD/public/mstile-150x150.png -------------------------------------------------------------------------------- /public/mstile-310x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsdocs-io/web/HEAD/public/mstile-310x150.png -------------------------------------------------------------------------------- /public/mstile-310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsdocs-io/web/HEAD/public/mstile-310x310.png -------------------------------------------------------------------------------- /public/sponsor-placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsdocs-io/web/HEAD/public/sponsor-placeholder.png -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next", 3 | "rules": { 4 | "@next/next/no-img-element": "off" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsdocs-io/web/HEAD/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /public/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsdocs-io/web/HEAD/public/android-chrome-512x512.png -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /vercel.json: -------------------------------------------------------------------------------- 1 | { 2 | "functions": { 3 | "src/pages/**/*": { 4 | "memory": 1024, 5 | "maxDuration": 30 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/data/window-script.ts: -------------------------------------------------------------------------------- 1 | export const windowScript = "window.jsdocsio = {};"; 2 | 3 | export const windowScriptMinified = "window.jsdocsio={}"; 4 | -------------------------------------------------------------------------------- /config/jest/cssTransform.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | process() { 3 | return "module.exports = {};"; 4 | }, 5 | getCacheKey() { 6 | return "cssTransform"; 7 | }, 8 | }; 9 | -------------------------------------------------------------------------------- /src/lib/sort-by-id.ts: -------------------------------------------------------------------------------- 1 | const sortByID = (items: T[]): T[] => { 2 | return items.sort((a, b) => a.id.localeCompare(b.id)); 3 | }; 4 | 5 | export default sortByID; 6 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | darkMode: "class", 4 | content: ["src/**/*.tsx"], 5 | theme: { 6 | extend: {}, 7 | }, 8 | plugins: [], 9 | }; 10 | -------------------------------------------------------------------------------- /src/worker/analyze-registry-package-worker.js: -------------------------------------------------------------------------------- 1 | const { analyzeRegistryPackage } = require("@jsdocs-io/extractor"); 2 | 3 | module.exports = async ({ name, version }) => { 4 | return analyzeRegistryPackage({ name, version }); 5 | }; 6 | -------------------------------------------------------------------------------- /src/components/common/InlineCode.tsx: -------------------------------------------------------------------------------- 1 | const InlineCode = ({ code }: { code: string }) => { 2 | return ( 3 | {code} 4 | ); 5 | }; 6 | 7 | export default InlineCode; 8 | -------------------------------------------------------------------------------- /src/data/vercel-url.ts: -------------------------------------------------------------------------------- 1 | export const vercelURL = 2 | "https://vercel.com/?utm_source=jsdocs-io&utm_campaign=oss"; 3 | 4 | export const vercelPrivacyPolicyURL = 5 | "https://vercel.com/legal/privacy-policy?utm_source=jsdocs-io&utm_campaign=oss"; 6 | -------------------------------------------------------------------------------- /src/components/CharSetTag.tsx: -------------------------------------------------------------------------------- 1 | import Head from "next/head"; 2 | 3 | const CharSetTag = () => { 4 | return ( 5 | 6 | 7 | 8 | ); 9 | }; 10 | 11 | export default CharSetTag; 12 | -------------------------------------------------------------------------------- /next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/pages/building-your-application/configuring/typescript for more information. 6 | -------------------------------------------------------------------------------- /src/components/TitleTag.tsx: -------------------------------------------------------------------------------- 1 | import Head from "next/head"; 2 | 3 | const TitleTag = ({ title }: { title: string }) => { 4 | return ( 5 | 6 | {title} 7 | 8 | ); 9 | }; 10 | 11 | export default TitleTag; 12 | -------------------------------------------------------------------------------- /src/lib/has-package-declarations.ts: -------------------------------------------------------------------------------- 1 | import { PackageAPI } from "@jsdocs-io/extractor"; 2 | 3 | const hasPackageDeclarations = ({ api }: { api?: PackageAPI }): boolean => { 4 | return Object.values(api?.declarations ?? {}).flat().length > 0; 5 | }; 6 | 7 | export default hasPackageDeclarations; 8 | -------------------------------------------------------------------------------- /src/hooks/useAnchorLinks.ts: -------------------------------------------------------------------------------- 1 | import AnchorJS from "anchor-js"; 2 | import { useEffect } from "react"; 3 | 4 | const useAnchorLinks = () => { 5 | useEffect(() => { 6 | const anchors = new AnchorJS(); 7 | anchors.add("h2, h3"); 8 | }, []); 9 | }; 10 | 11 | export default useAnchorLinks; 12 | -------------------------------------------------------------------------------- /src/lib/is-valid-license.ts: -------------------------------------------------------------------------------- 1 | const isValidLicense = ({ license }: { license?: string }): boolean => { 2 | return ( 3 | license !== undefined && 4 | license.toLowerCase() !== "unlicensed" && 5 | !license.toLowerCase().startsWith("see ") 6 | ); 7 | }; 8 | 9 | export default isValidLicense; 10 | -------------------------------------------------------------------------------- /src/types/window.ts: -------------------------------------------------------------------------------- 1 | /** Augment global window */ 2 | declare global { 3 | interface Window { 4 | jsdocsio: JSDOCSIO; 5 | } 6 | } 7 | 8 | /** Custom namespace for storing globals in window */ 9 | export interface JSDOCSIO { 10 | /** Hash present in URL on fallback pages */ 11 | prevHash?: string; 12 | } 13 | -------------------------------------------------------------------------------- /setupTests.js: -------------------------------------------------------------------------------- 1 | // optional: configure or set up a testing framework before each test 2 | // if you delete this file, remove `setupFilesAfterEnv` from `jest.config.js` 3 | 4 | // used for __tests__/testing-library.js 5 | // learn more: https://github.com/testing-library/jest-dom 6 | import "@testing-library/jest-dom/extend-expect"; 7 | -------------------------------------------------------------------------------- /src/components/DescriptionTag.tsx: -------------------------------------------------------------------------------- 1 | import Head from "next/head"; 2 | 3 | const DescriptionTag = ({ description }: { description: string }) => { 4 | return ( 5 | 6 | 7 | 8 | ); 9 | }; 10 | 11 | export default DescriptionTag; 12 | -------------------------------------------------------------------------------- /src/components/ViewportTag.tsx: -------------------------------------------------------------------------------- 1 | import Head from "next/head"; 2 | 3 | const ViewportTag = () => { 4 | return ( 5 | 6 | 11 | 12 | ); 13 | }; 14 | 15 | export default ViewportTag; 16 | -------------------------------------------------------------------------------- /src/components/common/Main.tsx: -------------------------------------------------------------------------------- 1 | const Main = (props: any) => { 2 | return ( 3 |
4 |
5 | {props.children} 6 |
7 |
8 | ); 9 | }; 10 | 11 | export default Main; 12 | -------------------------------------------------------------------------------- /src/lib/package-page-kind.ts: -------------------------------------------------------------------------------- 1 | export enum PackagePageKind { 2 | /** Documentation page for a specific package version */ 3 | Docs = "Docs", 4 | 5 | /** Package versions and dist tags */ 6 | AvailableVersions = "AvailableVersions", 7 | 8 | /** Error page (invalid route, package not found, version not found) */ 9 | Error = "Error", 10 | } 11 | -------------------------------------------------------------------------------- /src/lib/revalidate-times.ts: -------------------------------------------------------------------------------- 1 | // Time durations for the `revalidate` option used in `getStaticProps`. 2 | // See https://nextjs.org/docs/basic-features/data-fetching#incremental-static-regeneration 3 | 4 | export const second = 1; 5 | export const minute = 60 * second; 6 | export const hour = 60 * minute; 7 | export const day = 24 * hour; 8 | export const week = 7 * day; 9 | -------------------------------------------------------------------------------- /src/components/package/PackageLicenseAlert.tsx: -------------------------------------------------------------------------------- 1 | const PackageLicenseAlert = () => { 2 | return ( 3 |
4 |

5 | API extraction from unlicensed or proprietary packages is not supported 6 |

7 |
8 | ); 9 | }; 10 | 11 | export default PackageLicenseAlert; 12 | -------------------------------------------------------------------------------- /src/lib/min-semver-version.ts: -------------------------------------------------------------------------------- 1 | import semverMinVersion from "semver/ranges/min-version"; 2 | 3 | const minSemverVersion = ({ 4 | semver, 5 | }: { 6 | semver: string; 7 | }): string | undefined => { 8 | let version; 9 | try { 10 | version = semverMinVersion(semver)?.version; 11 | } catch {} 12 | return version !== "0.0.0" ? version : undefined; 13 | }; 14 | 15 | export default minSemverVersion; 16 | -------------------------------------------------------------------------------- /src/components/package/PackageMissingTypesAlert.tsx: -------------------------------------------------------------------------------- 1 | const PackageMissingTypesAlert = () => { 2 | return ( 3 |
4 |

5 | Unfortunately type definitions are currently not available for this 6 | package 7 |

8 |
9 | ); 10 | }; 11 | 12 | export default PackageMissingTypesAlert; 13 | -------------------------------------------------------------------------------- /src/lib/load-nprogress.ts: -------------------------------------------------------------------------------- 1 | import Router from "next/router"; 2 | import NProgress from "nprogress"; 3 | 4 | const loadNProgress = () => { 5 | NProgress.configure({ showSpinner: false }); 6 | Router.events.on("routeChangeStart", () => NProgress.start()); 7 | Router.events.on("routeChangeComplete", () => NProgress.done()); 8 | Router.events.on("routeChangeError", () => NProgress.done()); 9 | }; 10 | 11 | export default loadNProgress; 12 | -------------------------------------------------------------------------------- /src/pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import type { AppProps } from "next/app"; 2 | import "../../node_modules/nprogress/nprogress.css"; 3 | import "../../node_modules/prismjs/themes/prism-tomorrow.css"; 4 | import "../../styles/index.css"; 5 | import loadNProgress from "../lib/load-nprogress"; 6 | 7 | loadNProgress(); 8 | 9 | const MyApp = ({ Component, pageProps }: AppProps) => { 10 | return ; 11 | }; 12 | 13 | export default MyApp; 14 | -------------------------------------------------------------------------------- /test/lib/revalidate-times.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | day, 3 | hour, 4 | minute, 5 | second, 6 | week, 7 | } from "../../src/lib/revalidate-times"; 8 | 9 | describe("Revalidation times", () => { 10 | it("should be correctly defined", () => { 11 | expect(second).toEqual(1); 12 | expect(minute).toEqual(60); 13 | expect(hour).toEqual(3600); 14 | expect(day).toEqual(86400); 15 | expect(week).toEqual(604800); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /src/components/common/CodeBlock.tsx: -------------------------------------------------------------------------------- 1 | import CodeBlockContents from "./CodeBlockContents"; 2 | 3 | const CodeBlock = ({ 4 | code, 5 | language, 6 | className, 7 | }: { 8 | code: string; 9 | language: string; 10 | className?: string; 11 | }) => { 12 | return ( 13 |
14 | 15 |
16 | ); 17 | }; 18 | 19 | export default CodeBlock; 20 | -------------------------------------------------------------------------------- /src/components/common/PackageVersionsLink.tsx: -------------------------------------------------------------------------------- 1 | import InternalLink from "./InternalLink"; 2 | 3 | const PackageVersionsLink = ({ 4 | name, 5 | title, 6 | children, 7 | }: { 8 | name: string; 9 | title?: string; 10 | children: React.ReactNode; 11 | }) => { 12 | return ( 13 | 14 | {children} 15 | 16 | ); 17 | }; 18 | 19 | export default PackageVersionsLink; 20 | -------------------------------------------------------------------------------- /src/lib/clean-object.ts: -------------------------------------------------------------------------------- 1 | import cleanDeep from "clean-deep"; 2 | 3 | /** 4 | * cleanObject returns a new object corresponding to the given one 5 | * without null and undefined values. 6 | * 7 | * @param obj - the object to clean 8 | */ 9 | const cleanObject = (obj: T): T => { 10 | return cleanDeep(obj, { 11 | emptyArrays: false, 12 | emptyObjects: false, 13 | emptyStrings: false, 14 | }) as T; 15 | }; 16 | 17 | export default cleanObject; 18 | -------------------------------------------------------------------------------- /public/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jsDocs.io", 3 | "short_name": "jsDocs.io", 4 | "icons": [ 5 | { 6 | "src": "/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/android-chrome-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#2d3748", 17 | "background_color": "#2d3748", 18 | "display": "standalone" 19 | } 20 | -------------------------------------------------------------------------------- /public/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | #2d3748 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/components/package/PackageFilesSection.tsx: -------------------------------------------------------------------------------- 1 | import { PackageFile } from "@jsdocs-io/extractor"; 2 | import PackageFilesList from "./PackageFilesList"; 3 | 4 | const PackageFilesSection = ({ files }: { files: PackageFile[] }) => { 5 | return ( 6 |
7 |

Package Files ({files.length})

8 | 9 | 10 |
11 | ); 12 | }; 13 | 14 | export default PackageFilesSection; 15 | -------------------------------------------------------------------------------- /src/data/bookmarklets.ts: -------------------------------------------------------------------------------- 1 | export const redirectBookmarklet = 2 | // eslint-disable-next-line no-script-url 3 | "javascript:(function(){const{href:h,pathname:p}=window.location;h.startsWith('https://www.npmjs.com/package/')&&(window.location='https://www.jsdocs.io'+p)})();"; 4 | 5 | export const newTabBookmarklet = 6 | // eslint-disable-next-line no-script-url 7 | "javascript:(function(){const{href:h,pathname:p}=window.location;h.startsWith('https://www.npmjs.com/package/')&&window.open('https://www.jsdocs.io'+p)})();"; 8 | -------------------------------------------------------------------------------- /test/lib/sort-by-id.test.ts: -------------------------------------------------------------------------------- 1 | import sortByID from "../../src/lib/sort-by-id"; 2 | 3 | describe("sortByID", () => { 4 | it("supports empty lists", () => { 5 | expect(sortByID([])).toEqual([]); 6 | }); 7 | 8 | it("supports lists with one item", () => { 9 | expect(sortByID([{ id: "a" }])).toEqual([{ id: "a" }]); 10 | }); 11 | 12 | it("sorts list of items with an ID", () => { 13 | expect(sortByID([{ id: "b" }, { id: "a" }])).toEqual([ 14 | { id: "a" }, 15 | { id: "b" }, 16 | ]); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /src/components/common/NavbarLink.tsx: -------------------------------------------------------------------------------- 1 | import Link from "next/link"; 2 | 3 | const NavbarLink = ({ 4 | href, 5 | children, 6 | }: { 7 | href: string; 8 | children: React.ReactNode; 9 | }) => { 10 | return ( 11 | 12 | {/* eslint-disable-next-line jsx-a11y/anchor-is-valid */} 13 | 14 | {children} 15 | 16 | 17 | ); 18 | }; 19 | 20 | export default NavbarLink; 21 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env.local 29 | .env.development.local 30 | .env.test.local 31 | .env.production.local 32 | 33 | # vercel 34 | .vercel 35 | -------------------------------------------------------------------------------- /src/components/package/PackageIndexEnumsSection.tsx: -------------------------------------------------------------------------------- 1 | import { EnumDeclaration } from "@jsdocs-io/extractor"; 2 | import PackageIndexEnumsList from "./PackageIndexEnumsList"; 3 | 4 | const PackageIndexEnumsSection = ({ enums }: { enums: EnumDeclaration[] }) => { 5 | if (!enums.length) { 6 | return null; 7 | } 8 | 9 | return ( 10 |
11 |

Enums

12 | 13 | 14 |
15 | ); 16 | }; 17 | 18 | export default PackageIndexEnumsSection; 19 | -------------------------------------------------------------------------------- /src/components/common/A.tsx: -------------------------------------------------------------------------------- 1 | import { sanitizeUrl } from "@braintree/sanitize-url"; 2 | import React from "react"; 3 | 4 | const A = ({ 5 | href: rawHref, 6 | title, 7 | children, 8 | }: { 9 | href: string; 10 | title?: string; 11 | children: React.ReactNode; 12 | }) => { 13 | const href = sanitizeUrl(rawHref); 14 | 15 | return ( 16 | 21 | {children} 22 | 23 | ); 24 | }; 25 | 26 | export default A; 27 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "github-actions" 9 | directory: "/" 10 | schedule: 11 | interval: "monthly" 12 | 13 | - package-ecosystem: "npm" 14 | directory: "/" 15 | schedule: 16 | interval: "monthly" 17 | -------------------------------------------------------------------------------- /src/components/package/PackageInstallSection.tsx: -------------------------------------------------------------------------------- 1 | import CodeBlock from "../common/CodeBlock"; 2 | 3 | const PackageInstallSection = ({ name }: { name: string }) => { 4 | const installCommands = [ 5 | `npm i ${name}`, 6 | `yarn add ${name}`, 7 | `pnpm add ${name}`, 8 | ]; 9 | 10 | return ( 11 |
12 |

Install

13 | 14 | {installCommands.map((command) => ( 15 | 16 | ))} 17 |
18 | ); 19 | }; 20 | 21 | export default PackageInstallSection; 22 | -------------------------------------------------------------------------------- /src/components/package/PackageIndexClassesSection.tsx: -------------------------------------------------------------------------------- 1 | import { ClassDeclaration } from "@jsdocs-io/extractor"; 2 | import PackageIndexClassesList from "./PackageIndexClassesList"; 3 | 4 | const PackageIndexClassesSection = ({ 5 | classes, 6 | }: { 7 | classes: ClassDeclaration[]; 8 | }) => { 9 | if (!classes.length) { 10 | return null; 11 | } 12 | 13 | return ( 14 |
15 |

Classes

16 | 17 | 18 |
19 | ); 20 | }; 21 | 22 | export default PackageIndexClassesSection; 23 | -------------------------------------------------------------------------------- /src/lib/is-callable-declaration-kind.ts: -------------------------------------------------------------------------------- 1 | import { DeclarationKinds } from "@jsdocs-io/extractor"; 2 | 3 | const isCallableDeclarationKind = ({ 4 | kind, 5 | }: { 6 | kind: DeclarationKinds; 7 | }): boolean => { 8 | switch (kind) { 9 | case "FunctionDeclaration": 10 | case "ClassConstructorDeclaration": 11 | case "InterfaceConstructSignatureDeclaration": 12 | case "ClassMethodDeclaration": 13 | case "InterfaceMethodDeclaration": 14 | case "InterfaceCallSignatureDeclaration": 15 | return true; 16 | default: 17 | return false; 18 | } 19 | }; 20 | 21 | export default isCallableDeclarationKind; 22 | -------------------------------------------------------------------------------- /src/components/package/PackageOverviewSection.tsx: -------------------------------------------------------------------------------- 1 | import DocComment from "../common/DocComment"; 2 | 3 | const PackageOverviewSection = ({ 4 | overview, 5 | description, 6 | }: { 7 | overview?: string; 8 | description?: string; 9 | }) => { 10 | return ( 11 |
12 |

Overview

13 | 14 | {overview && } 15 | 16 | {!overview && description &&

{description}

} 17 | 18 | {!overview && !description &&

Overview not available.

} 19 |
20 | ); 21 | }; 22 | 23 | export default PackageOverviewSection; 24 | -------------------------------------------------------------------------------- /src/components/package/PackageIndexFunctionsSection.tsx: -------------------------------------------------------------------------------- 1 | import { FunctionDeclaration } from "@jsdocs-io/extractor"; 2 | import PackageIndexFunctionsList from "./PackageIndexFunctionsList"; 3 | 4 | const PackageIndexFunctionsSection = ({ 5 | functions, 6 | }: { 7 | functions: FunctionDeclaration[]; 8 | }) => { 9 | if (!functions.length) { 10 | return null; 11 | } 12 | 13 | return ( 14 |
15 |

Functions

16 | 17 | 18 |
19 | ); 20 | }; 21 | 22 | export default PackageIndexFunctionsSection; 23 | -------------------------------------------------------------------------------- /src/components/package/PackageIndexVariablesList.tsx: -------------------------------------------------------------------------------- 1 | import { VariableDeclaration } from "@jsdocs-io/extractor"; 2 | import InternalLink from "../common/InternalLink"; 3 | 4 | const PackageIndexVariablesList = ({ 5 | variables, 6 | }: { 7 | variables: VariableDeclaration[]; 8 | }) => { 9 | return ( 10 |
    11 | {variables.map(({ id, name }) => ( 12 |
  • 13 | 14 | {name} 15 | 16 |
  • 17 | ))} 18 |
19 | ); 20 | }; 21 | 22 | export default PackageIndexVariablesList; 23 | -------------------------------------------------------------------------------- /src/components/package/PackageIndexVariablesSection.tsx: -------------------------------------------------------------------------------- 1 | import { VariableDeclaration } from "@jsdocs-io/extractor"; 2 | import PackageIndexVariablesList from "./PackageIndexVariablesList"; 3 | 4 | const PackageIndexVariablesSection = ({ 5 | variables, 6 | }: { 7 | variables: VariableDeclaration[]; 8 | }) => { 9 | if (!variables.length) { 10 | return null; 11 | } 12 | 13 | return ( 14 |
15 |

Variables

16 | 17 | 18 |
19 | ); 20 | }; 21 | 22 | export default PackageIndexVariablesSection; 23 | -------------------------------------------------------------------------------- /src/components/package/PackageIndexFunctionsList.tsx: -------------------------------------------------------------------------------- 1 | import { FunctionDeclaration } from "@jsdocs-io/extractor"; 2 | import InternalLink from "../common/InternalLink"; 3 | 4 | const PackageIndexFunctionsList = ({ 5 | functions, 6 | }: { 7 | functions: FunctionDeclaration[]; 8 | }) => { 9 | return ( 10 |
    11 | {functions.map(({ id, name }) => ( 12 |
  • 13 | 14 | {`${name}()`} 15 | 16 |
  • 17 | ))} 18 |
19 | ); 20 | }; 21 | 22 | export default PackageIndexFunctionsList; 23 | -------------------------------------------------------------------------------- /src/components/package/PackageExternalTypesAlert.tsx: -------------------------------------------------------------------------------- 1 | import PackageLink from "../common/PackageLink"; 2 | 3 | const PackageExternalTypesAlert = ({ 4 | definitelyTypedName, 5 | }: { 6 | definitelyTypedName: string; 7 | }) => { 8 | return ( 9 |
10 |

11 | Type definitions are available in the{" "} 12 | 13 | {definitelyTypedName} 14 | {" "} 15 | package 16 |

17 |
18 | ); 19 | }; 20 | 21 | export default PackageExternalTypesAlert; 22 | -------------------------------------------------------------------------------- /src/components/package/PackageIndexInterfacesSection.tsx: -------------------------------------------------------------------------------- 1 | import { InterfaceDeclaration } from "@jsdocs-io/extractor"; 2 | import PackageIndexInterfacesList from "./PackageIndexInterfacesList"; 3 | 4 | const PackageIndexInterfacesSection = ({ 5 | interfaces, 6 | }: { 7 | interfaces: InterfaceDeclaration[]; 8 | }) => { 9 | if (!interfaces.length) { 10 | return null; 11 | } 12 | 13 | return ( 14 |
15 |

Interfaces

16 | 17 | 18 |
19 | ); 20 | }; 21 | 22 | export default PackageIndexInterfacesSection; 23 | -------------------------------------------------------------------------------- /src/components/package/PackageIndexNamespacesSection.tsx: -------------------------------------------------------------------------------- 1 | import { NamespaceDeclaration } from "@jsdocs-io/extractor"; 2 | import PackageIndexNamespacesList from "./PackageIndexNamespacesList"; 3 | 4 | const PackageIndexNamespacesSection = ({ 5 | namespaces, 6 | }: { 7 | namespaces: NamespaceDeclaration[]; 8 | }) => { 9 | if (!namespaces.length) { 10 | return null; 11 | } 12 | 13 | return ( 14 |
15 |

Namespaces

16 | 17 | 18 |
19 | ); 20 | }; 21 | 22 | export default PackageIndexNamespacesSection; 23 | -------------------------------------------------------------------------------- /src/components/package/PackageIndexTypeAliasesList.tsx: -------------------------------------------------------------------------------- 1 | import { TypeAliasDeclaration } from "@jsdocs-io/extractor"; 2 | import InternalLink from "../common/InternalLink"; 3 | 4 | const PackageIndexTypeAliasesList = ({ 5 | typeAliases, 6 | }: { 7 | typeAliases: TypeAliasDeclaration[]; 8 | }) => { 9 | return ( 10 |
    11 | {typeAliases.map(({ id, name }) => ( 12 |
  • 13 | 14 | {name} 15 | 16 |
  • 17 | ))} 18 |
19 | ); 20 | }; 21 | 22 | export default PackageIndexTypeAliasesList; 23 | -------------------------------------------------------------------------------- /src/components/Footer.tsx: -------------------------------------------------------------------------------- 1 | import clsx from "clsx"; 2 | import FooterLinks from "./FooterLinks"; 3 | import Logo from "./Logo"; 4 | import PoweredByVercelBanner from "./PoweredByVercelBanner"; 5 | 6 | const Footer = () => { 7 | return ( 8 |
15 |
16 | 17 | 18 | 19 |
20 |
21 | ); 22 | }; 23 | 24 | export default Footer; 25 | -------------------------------------------------------------------------------- /src/components/common/TimeAgo.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | import { timeAgo } from "short-time-ago"; 3 | 4 | const TimeAgo = ({ date: rawDate }: { date: string }) => { 5 | const date = new Date(rawDate); 6 | const [description, setDescription] = useState(timeAgo(date)); 7 | 8 | useEffect(() => { 9 | const interval = setInterval(() => { 10 | setDescription(timeAgo(date)); 11 | }, 60000); 12 | 13 | return () => clearInterval(interval); 14 | }); 15 | 16 | return ( 17 | 20 | ); 21 | }; 22 | 23 | export default TimeAgo; 24 | -------------------------------------------------------------------------------- /src/components/package/PackageIndexTypeAliasesSection.tsx: -------------------------------------------------------------------------------- 1 | import { TypeAliasDeclaration } from "@jsdocs-io/extractor"; 2 | import PackageIndexTypeAliasesList from "./PackageIndexTypeAliasesList"; 3 | 4 | const PackageIndexTypeAliasesSection = ({ 5 | typeAliases, 6 | }: { 7 | typeAliases: TypeAliasDeclaration[]; 8 | }) => { 9 | if (!typeAliases.length) { 10 | return null; 11 | } 12 | 13 | return ( 14 |
15 |

Type Aliases

16 | 17 | 18 |
19 | ); 20 | }; 21 | 22 | export default PackageIndexTypeAliasesSection; 23 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testEnvironment: "node", 3 | collectCoverageFrom: ["src/**/*.{ts,tsx,js,jsx}", "!src/data/**"], 4 | setupFilesAfterEnv: ["/setupTests.js"], 5 | testMatch: ["/**/*.test.{ts,tsx,js,jsx}"], 6 | testPathIgnorePatterns: ["/node_modules/", "/.next/"], 7 | transform: { 8 | "^.+\\.(js|jsx|ts|tsx)$": ["babel-jest", { presets: ["next/babel"] }], 9 | "^.+\\.css$": "/config/jest/cssTransform.js", 10 | }, 11 | transformIgnorePatterns: [ 12 | "/node_modules/", 13 | "^.+\\.module\\.(css|sass|scss)$", 14 | ], 15 | moduleNameMapper: { 16 | "^.+\\.module\\.(css|sass|scss)$": "identity-obj-proxy", 17 | }, 18 | }; 19 | -------------------------------------------------------------------------------- /src/components/common/Layout.tsx: -------------------------------------------------------------------------------- 1 | import useAnchorLinks from "../../hooks/useAnchorLinks"; 2 | import useLocationHashRefresh from "../../hooks/useLocationHashRefresh"; 3 | import Footer from "../Footer"; 4 | import Head from "./Head"; 5 | import Main from "./Main"; 6 | import Navbar from "./Navbar"; 7 | 8 | const Layout = (props: any) => { 9 | useAnchorLinks(); 10 | useLocationHashRefresh(); 11 | 12 | return ( 13 | <> 14 | 15 | 16 |
17 | 18 | 19 |
20 | 21 |
22 |
23 | 24 | ); 25 | }; 26 | 27 | export default Layout; 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env.local 29 | .env.development.local 30 | .env.test.local 31 | .env.production.local 32 | 33 | # vercel 34 | .vercel 35 | 36 | # tsconfig build info 37 | tsconfig.tsbuildinfo 38 | 39 | # SvelteKit 40 | .svelte-kit 41 | 42 | # Env 43 | .env 44 | 45 | # Vite 46 | vite.config.ts.timestamp-* 47 | -------------------------------------------------------------------------------- /src/data/dark-mode-script.ts: -------------------------------------------------------------------------------- 1 | export const darkModeScript = ` 2 | if (localStorage.darkMode === 'true' || (!localStorage.darkMode && window.matchMedia('(prefers-color-scheme: dark)').matches)) { 3 | document.documentElement.classList.add('dark'); 4 | localStorage.darkMode = 'true'; 5 | } else { 6 | document.documentElement.classList.remove('dark'); 7 | localStorage.darkMode = 'false'; 8 | }`; 9 | 10 | export const darkModeScriptMinified = `"true"===localStorage.darkMode||!localStorage.darkMode&&window.matchMedia("(prefers-color-scheme: dark)").matches?(document.documentElement.classList.add("dark"),localStorage.darkMode="true"):(document.documentElement.classList.remove("dark"),localStorage.darkMode="false")`; 11 | -------------------------------------------------------------------------------- /src/components/Logo.tsx: -------------------------------------------------------------------------------- 1 | import clsx from "clsx"; 2 | import Link from "next/link"; 3 | 4 | const Logo = ({ hideText = false }: { hideText?: boolean }) => { 5 | return ( 6 | 7 | 8 | Logo for jsDocs.io 13 | 19 | jsDocs.io 20 | 21 | 22 | 23 | ); 24 | }; 25 | 26 | export default Logo; 27 | -------------------------------------------------------------------------------- /test/lib/parse-json-stream.test.ts: -------------------------------------------------------------------------------- 1 | import stream from "stream"; 2 | import parseJSONStream from "../../src/lib/parse-json-stream"; 3 | 4 | describe("parseJSONStream", () => { 5 | it("rejects when the JSON stream is invalid", async () => { 6 | expect.assertions(1); 7 | 8 | try { 9 | await parseJSONStream({ jsonStream: stream.Readable.from(["{"]) }); 10 | } catch (err) { 11 | expect(err).toBeDefined(); 12 | } 13 | }); 14 | 15 | it("resolves when the JSON stream is valid", async () => { 16 | expect.assertions(1); 17 | 18 | const got = await parseJSONStream({ 19 | jsonStream: stream.Readable.from(['{"x":1}']), 20 | }); 21 | 22 | expect(got).toStrictEqual({ x: 1 }); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | # github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: jsdocs_io 5 | # open_collective: # Replace with a single Open Collective username 6 | # ko_fi: # Replace with a single Ko-fi username 7 | # tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | # community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | # liberapay: # Replace with a single Liberapay username 10 | # issuehunt: # Replace with a single IssueHunt username 11 | # otechie: # Replace with a single Otechie username 12 | # custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /src/lib/get-package-page-error-props.ts: -------------------------------------------------------------------------------- 1 | import { GetStaticPropsResult } from "next"; 2 | import { PackagePageKind } from "./package-page-kind"; 3 | import { week } from "./revalidate-times"; 4 | 5 | export interface PackagePagePropsError { 6 | readonly kind: PackagePageKind.Error; 7 | readonly message?: string; 8 | } 9 | 10 | const getPackagePageErrorProps = ({ 11 | message = "Page Not Found", 12 | revalidate = week, 13 | }: { 14 | message?: string; 15 | revalidate?: number | boolean; 16 | } = {}): GetStaticPropsResult => { 17 | return { 18 | props: { 19 | kind: PackagePageKind.Error, 20 | message, 21 | }, 22 | revalidate, 23 | }; 24 | }; 25 | 26 | export default getPackagePageErrorProps; 27 | -------------------------------------------------------------------------------- /src/components/common/PackageLink.tsx: -------------------------------------------------------------------------------- 1 | import InternalLink from "./InternalLink"; 2 | 3 | const PackageLink = ({ 4 | name, 5 | version, 6 | declarationID, 7 | title, 8 | children, 9 | }: { 10 | name: string; 11 | version?: string; 12 | declarationID?: string; 13 | title?: string; 14 | children: React.ReactNode; 15 | }) => { 16 | const packageBaseRoute = version 17 | ? `/package/${name}/v/${version}` 18 | : `/package/${name}`; 19 | 20 | const packageRoute = declarationID 21 | ? `${packageBaseRoute}#${declarationID}` 22 | : packageBaseRoute; 23 | 24 | return ( 25 | 26 | {children} 27 | 28 | ); 29 | }; 30 | 31 | export default PackageLink; 32 | -------------------------------------------------------------------------------- /src/components/package/PackageEnumsSection.tsx: -------------------------------------------------------------------------------- 1 | import { EnumDeclaration } from "@jsdocs-io/extractor"; 2 | import PackageEnumDeclarationSections from "./PackageEnumDeclarationSections"; 3 | 4 | const PackageEnumsSection = ({ enums }: { enums: EnumDeclaration[] }) => { 5 | if (!enums.length) { 6 | return null; 7 | } 8 | 9 | return ( 10 |
11 |

Enums

12 | 13 |
14 | {enums.map((declaration) => ( 15 | 19 | ))} 20 |
21 |
22 | ); 23 | }; 24 | 25 | export default PackageEnumsSection; 26 | -------------------------------------------------------------------------------- /src/components/package/PackageIndexEnumMembersList.tsx: -------------------------------------------------------------------------------- 1 | import { EnumMemberDeclaration } from "@jsdocs-io/extractor"; 2 | import InternalLink from "../common/InternalLink"; 3 | 4 | const PackageIndexEnumMembersList = ({ 5 | members, 6 | }: { 7 | members: EnumMemberDeclaration[]; 8 | }) => { 9 | if (!members.length) { 10 | return null; 11 | } 12 | 13 | return ( 14 |
    15 | {members.map(({ id, name }) => ( 16 |
  • 17 | 18 | {name} 19 | 20 |
  • 21 | ))} 22 |
23 | ); 24 | }; 25 | 26 | export default PackageIndexEnumMembersList; 27 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["next-env.d.ts", "src", "config.ts"], 3 | "compilerOptions": { 4 | "target": "es5", 5 | "module": "esnext", 6 | "lib": ["dom", "dom.iterable", "esnext"], 7 | "strict": true, 8 | "noUnusedLocals": true, 9 | "noUnusedParameters": true, 10 | "noImplicitReturns": true, 11 | "noFallthroughCasesInSwitch": true, 12 | "noUncheckedIndexedAccess": true, 13 | "forceConsistentCasingInFileNames": true, 14 | "noEmit": true, 15 | "esModuleInterop": true, 16 | "moduleResolution": "node", 17 | "resolveJsonModule": true, 18 | "isolatedModules": true, 19 | "jsx": "preserve", 20 | "allowJs": true, 21 | "skipLibCheck": true, 22 | "incremental": true 23 | }, 24 | "exclude": ["node_modules"] 25 | } 26 | -------------------------------------------------------------------------------- /src/lib/parse-json-stream.ts: -------------------------------------------------------------------------------- 1 | import stream from "stream"; 2 | import StreamValues from "stream-json/streamers/StreamValues"; 3 | import { promisify } from "util"; 4 | 5 | const pipeline = promisify(stream.pipeline); 6 | 7 | const parseJSONStream = async ({ 8 | jsonStream, 9 | }: { 10 | jsonStream: stream.Readable; 11 | }): Promise => { 12 | let data; 13 | 14 | await pipeline( 15 | jsonStream, 16 | StreamValues.withParser(), 17 | new stream.Writable({ 18 | // See https://github.com/uhop/stream-json/wiki/StreamValues 19 | write: ({ value }, _, done) => { 20 | data = value; 21 | done(); 22 | }, 23 | objectMode: true, 24 | }) 25 | ); 26 | 27 | return data as unknown as T; 28 | }; 29 | 30 | export default parseJSONStream; 31 | -------------------------------------------------------------------------------- /test/lib/get-oss-libraries.test.ts: -------------------------------------------------------------------------------- 1 | import * as path from "path"; 2 | import getOSSLibraries from "../../src/lib/get-oss-libraries"; 3 | 4 | describe("getOSSLibraries", () => { 5 | it("rejects when the licenses file is not found", async () => { 6 | expect.assertions(1); 7 | 8 | try { 9 | await getOSSLibraries({ licensesFile: "" }); 10 | } catch (err) { 11 | expect(err).toBeDefined(); 12 | } 13 | }); 14 | 15 | it("resolves when the licenses file is found", async () => { 16 | expect.assertions(1); 17 | 18 | const licenses = await getOSSLibraries({ 19 | licensesFile: path.join( 20 | __dirname, 21 | "../../test-data/sample-oss-licenses.json" 22 | ), 23 | }); 24 | 25 | expect(licenses.length).toEqual(32); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /src/components/package/PackageClassesSection.tsx: -------------------------------------------------------------------------------- 1 | import { ClassDeclaration } from "@jsdocs-io/extractor"; 2 | import PackageClassDeclarationSections from "./PackageClassDeclarationSections"; 3 | 4 | const PackageClassesSection = ({ 5 | classes, 6 | }: { 7 | classes: ClassDeclaration[]; 8 | }) => { 9 | if (!classes.length) { 10 | return null; 11 | } 12 | 13 | return ( 14 |
15 |

Classes

16 | 17 |
18 | {classes.map((declaration) => ( 19 | 23 | ))} 24 |
25 |
26 | ); 27 | }; 28 | 29 | export default PackageClassesSection; 30 | -------------------------------------------------------------------------------- /src/components/package/PackageFunctionsSection.tsx: -------------------------------------------------------------------------------- 1 | import { FunctionDeclaration } from "@jsdocs-io/extractor"; 2 | import PackageDeclarationSection from "./PackageDeclarationSection"; 3 | 4 | const PackageFunctionsSection = ({ 5 | functions, 6 | }: { 7 | functions: FunctionDeclaration[]; 8 | }) => { 9 | if (!functions.length) { 10 | return null; 11 | } 12 | 13 | return ( 14 |
15 |

Functions

16 | 17 |
18 | {functions.map((declaration) => ( 19 | 23 | ))} 24 |
25 |
26 | ); 27 | }; 28 | 29 | export default PackageFunctionsSection; 30 | -------------------------------------------------------------------------------- /src/components/package/PackageVariablesSection.tsx: -------------------------------------------------------------------------------- 1 | import { VariableDeclaration } from "@jsdocs-io/extractor"; 2 | import PackageDeclarationSection from "./PackageDeclarationSection"; 3 | 4 | const PackageVariablesSection = ({ 5 | variables, 6 | }: { 7 | variables: VariableDeclaration[]; 8 | }) => { 9 | if (!variables.length) { 10 | return null; 11 | } 12 | 13 | return ( 14 |
15 |

Variables

16 | 17 |
18 | {variables.map((declaration) => ( 19 | 23 | ))} 24 |
25 |
26 | ); 27 | }; 28 | 29 | export default PackageVariablesSection; 30 | -------------------------------------------------------------------------------- /src/components/package/PackageFilesList.tsx: -------------------------------------------------------------------------------- 1 | import { PackageFile } from "@jsdocs-io/extractor"; 2 | import A from "../common/A"; 3 | 4 | const PackageFilesList = ({ files }: { files: PackageFile[] }) => { 5 | return ( 6 | 23 | ); 24 | }; 25 | 26 | export default PackageFilesList; 27 | -------------------------------------------------------------------------------- /src/components/package/PackageTypeAliasesSection.tsx: -------------------------------------------------------------------------------- 1 | import { TypeAliasDeclaration } from "@jsdocs-io/extractor"; 2 | import PackageDeclarationSection from "./PackageDeclarationSection"; 3 | 4 | const PackageTypeAliasesSection = ({ 5 | typeAliases, 6 | }: { 7 | typeAliases: TypeAliasDeclaration[]; 8 | }) => { 9 | if (!typeAliases.length) { 10 | return null; 11 | } 12 | 13 | return ( 14 |
15 |

Type Aliases

16 | 17 |
18 | {typeAliases.map((declaration) => ( 19 | 23 | ))} 24 |
25 |
26 | ); 27 | }; 28 | 29 | export default PackageTypeAliasesSection; 30 | -------------------------------------------------------------------------------- /src/components/package/PackageIndexEnumsList.tsx: -------------------------------------------------------------------------------- 1 | import { EnumDeclaration } from "@jsdocs-io/extractor"; 2 | import InternalLink from "../common/InternalLink"; 3 | import PackageIndexEnumMembersList from "./PackageIndexEnumMembersList"; 4 | 5 | const PackageIndexEnumsList = ({ enums }: { enums: EnumDeclaration[] }) => { 6 | return ( 7 |
    8 | {enums.map(({ id, name, members }) => ( 9 |
  • 10 |
    11 | 12 | 13 | {name} 14 | 15 | 16 | 17 | 18 |
    19 |
  • 20 | ))} 21 |
22 | ); 23 | }; 24 | 25 | export default PackageIndexEnumsList; 26 | -------------------------------------------------------------------------------- /src/components/package/PackageInterfacesSection.tsx: -------------------------------------------------------------------------------- 1 | import { InterfaceDeclaration } from "@jsdocs-io/extractor"; 2 | import PackageInterfaceDeclarationSections from "./PackageInterfaceDeclarationSections"; 3 | 4 | const PackageInterfacesSection = ({ 5 | interfaces, 6 | }: { 7 | interfaces: InterfaceDeclaration[]; 8 | }) => { 9 | if (!interfaces.length) { 10 | return null; 11 | } 12 | 13 | return ( 14 |
15 |

Interfaces

16 | 17 |
18 | {interfaces.map((declaration) => ( 19 | 23 | ))} 24 |
25 |
26 | ); 27 | }; 28 | 29 | export default PackageInterfacesSection; 30 | -------------------------------------------------------------------------------- /src/components/package/PackageNamespacesSection.tsx: -------------------------------------------------------------------------------- 1 | import { NamespaceDeclaration } from "@jsdocs-io/extractor"; 2 | import PackageNamespaceDeclarationSections from "./PackageNamespaceDeclarationSections"; 3 | 4 | const PackageNamespacesSection = ({ 5 | namespaces, 6 | }: { 7 | namespaces: NamespaceDeclaration[]; 8 | }) => { 9 | if (!namespaces.length) { 10 | return null; 11 | } 12 | 13 | return ( 14 |
15 |

Namespaces

16 | 17 |
18 | {namespaces.map((declaration) => ( 19 | 23 | ))} 24 |
25 |
26 | ); 27 | }; 28 | 29 | export default PackageNamespacesSection; 30 | -------------------------------------------------------------------------------- /test/lib/analyze-registry-package-with-worker.test.ts: -------------------------------------------------------------------------------- 1 | import analyzeRegistryPackageWithWorker from "../../src/lib/analyze-registry-package-with-worker"; 2 | 3 | describe("analyzeRegistryPackageWithWorker", () => { 4 | it("rejects when the timeout expires", async () => { 5 | expect.assertions(1); 6 | 7 | try { 8 | await analyzeRegistryPackageWithWorker({ 9 | name: "short-time-ago", 10 | version: "2.0.0", 11 | timeout: 100, 12 | }); 13 | } catch (err) { 14 | expect(err).toBeDefined(); 15 | } 16 | }); 17 | 18 | it("resolves when the package analysis is done", async () => { 19 | expect.assertions(1); 20 | 21 | const info = await analyzeRegistryPackageWithWorker({ 22 | name: "short-time-ago", 23 | version: "2.0.0", 24 | }); 25 | 26 | expect(info).toBeDefined(); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/components/package/PackageEnumDeclarationSections.tsx: -------------------------------------------------------------------------------- 1 | import { EnumDeclaration } from "@jsdocs-io/extractor"; 2 | import PackageDeclarationSection from "./PackageDeclarationSection"; 3 | 4 | const PackageEnumDeclarationSections = ({ 5 | declaration, 6 | }: { 7 | declaration: EnumDeclaration; 8 | }) => { 9 | const hasMembers = declaration.members.length > 0; 10 | 11 | return ( 12 |
13 | 14 | 15 | {hasMembers && ( 16 |
17 | {declaration.members.map((decl) => ( 18 | 19 | ))} 20 |
21 | )} 22 |
23 | ); 24 | }; 25 | 26 | export default PackageEnumDeclarationSections; 27 | -------------------------------------------------------------------------------- /src/components/PageHead.tsx: -------------------------------------------------------------------------------- 1 | import CharSetTag from "./CharSetTag"; 2 | import DescriptionTag from "./DescriptionTag"; 3 | import Favicon from "./Favicon"; 4 | import OpenGraphTags from "./OpenGraphTags"; 5 | import TitleTag from "./TitleTag"; 6 | import TwitterTags from "./TwitterTags"; 7 | import ViewportTag from "./ViewportTag"; 8 | 9 | const PageHead = ({ 10 | title, 11 | description, 12 | url, 13 | }: { 14 | title: string; 15 | description: string; 16 | url: string; 17 | }) => { 18 | return ( 19 | <> 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | ); 29 | }; 30 | 31 | export default PageHead; 32 | -------------------------------------------------------------------------------- /src/pages/_document.tsx: -------------------------------------------------------------------------------- 1 | import { Head, Html, Main, NextScript } from "next/document"; 2 | import Script from "next/script"; 3 | import { darkModeScriptMinified } from "../data/dark-mode-script"; 4 | import { windowScriptMinified } from "../data/window-script"; 5 | 6 | const MyDocument = () => { 7 | return ( 8 | 9 | 10 | 11 |
12 | 13 |