jamdesk 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +323 -0
- package/bin/jamdesk.js +76 -0
- package/dist/__tests__/integration/deprecated-components.integration.test.d.ts +8 -0
- package/dist/__tests__/integration/deprecated-components.integration.test.d.ts.map +1 -0
- package/dist/__tests__/integration/deprecated-components.integration.test.js +165 -0
- package/dist/__tests__/integration/deprecated-components.integration.test.js.map +1 -0
- package/dist/__tests__/integration/migrate.integration.test.d.ts +2 -0
- package/dist/__tests__/integration/migrate.integration.test.d.ts.map +1 -0
- package/dist/__tests__/integration/migrate.integration.test.js +64 -0
- package/dist/__tests__/integration/migrate.integration.test.js.map +1 -0
- package/dist/__tests__/integration/prepublish.integration.test.d.ts +2 -0
- package/dist/__tests__/integration/prepublish.integration.test.d.ts.map +1 -0
- package/dist/__tests__/integration/prepublish.integration.test.js +27 -0
- package/dist/__tests__/integration/prepublish.integration.test.js.map +1 -0
- package/dist/__tests__/integration/validate.integration.test.d.ts +2 -0
- package/dist/__tests__/integration/validate.integration.test.d.ts.map +1 -0
- package/dist/__tests__/integration/validate.integration.test.js +56 -0
- package/dist/__tests__/integration/validate.integration.test.js.map +1 -0
- package/dist/__tests__/unit/deploy-templates.test.d.ts +2 -0
- package/dist/__tests__/unit/deploy-templates.test.d.ts.map +1 -0
- package/dist/__tests__/unit/deploy-templates.test.js +124 -0
- package/dist/__tests__/unit/deploy-templates.test.js.map +1 -0
- package/dist/__tests__/unit/deprecated-components-sync.test.d.ts +2 -0
- package/dist/__tests__/unit/deprecated-components-sync.test.d.ts.map +1 -0
- package/dist/__tests__/unit/deprecated-components-sync.test.js +69 -0
- package/dist/__tests__/unit/deprecated-components-sync.test.js.map +1 -0
- package/dist/__tests__/unit/deps-sync.test.d.ts +14 -0
- package/dist/__tests__/unit/deps-sync.test.d.ts.map +1 -0
- package/dist/__tests__/unit/deps-sync.test.js +166 -0
- package/dist/__tests__/unit/deps-sync.test.js.map +1 -0
- package/dist/__tests__/unit/docs-config.test.d.ts +2 -0
- package/dist/__tests__/unit/docs-config.test.d.ts.map +1 -0
- package/dist/__tests__/unit/docs-config.test.js +288 -0
- package/dist/__tests__/unit/docs-config.test.js.map +1 -0
- package/dist/__tests__/unit/errors.test.d.ts +2 -0
- package/dist/__tests__/unit/errors.test.d.ts.map +1 -0
- package/dist/__tests__/unit/errors.test.js +27 -0
- package/dist/__tests__/unit/errors.test.js.map +1 -0
- package/dist/__tests__/unit/extract-hooks.test.d.ts +5 -0
- package/dist/__tests__/unit/extract-hooks.test.d.ts.map +1 -0
- package/dist/__tests__/unit/extract-hooks.test.js +205 -0
- package/dist/__tests__/unit/extract-hooks.test.js.map +1 -0
- package/dist/__tests__/unit/frontmatter-sync.test.d.ts +8 -0
- package/dist/__tests__/unit/frontmatter-sync.test.d.ts.map +1 -0
- package/dist/__tests__/unit/frontmatter-sync.test.js +26 -0
- package/dist/__tests__/unit/frontmatter-sync.test.js.map +1 -0
- package/dist/__tests__/unit/mdx-validator.test.d.ts +2 -0
- package/dist/__tests__/unit/mdx-validator.test.d.ts.map +1 -0
- package/dist/__tests__/unit/mdx-validator.test.js +264 -0
- package/dist/__tests__/unit/mdx-validator.test.js.map +1 -0
- package/dist/__tests__/unit/migrate-convert.test.d.ts +2 -0
- package/dist/__tests__/unit/migrate-convert.test.d.ts.map +1 -0
- package/dist/__tests__/unit/migrate-convert.test.js +297 -0
- package/dist/__tests__/unit/migrate-convert.test.js.map +1 -0
- package/dist/__tests__/unit/migrate-detect.test.d.ts +2 -0
- package/dist/__tests__/unit/migrate-detect.test.d.ts.map +1 -0
- package/dist/__tests__/unit/migrate-detect.test.js +35 -0
- package/dist/__tests__/unit/migrate-detect.test.js.map +1 -0
- package/dist/__tests__/unit/migrate-mdx.test.d.ts +2 -0
- package/dist/__tests__/unit/migrate-mdx.test.d.ts.map +1 -0
- package/dist/__tests__/unit/migrate-mdx.test.js +158 -0
- package/dist/__tests__/unit/migrate-mdx.test.js.map +1 -0
- package/dist/__tests__/unit/openapi.test.d.ts +2 -0
- package/dist/__tests__/unit/openapi.test.d.ts.map +1 -0
- package/dist/__tests__/unit/openapi.test.js +52 -0
- package/dist/__tests__/unit/openapi.test.js.map +1 -0
- package/dist/__tests__/unit/package-config.test.d.ts +2 -0
- package/dist/__tests__/unit/package-config.test.d.ts.map +1 -0
- package/dist/__tests__/unit/package-config.test.js +63 -0
- package/dist/__tests__/unit/package-config.test.js.map +1 -0
- package/dist/__tests__/unit/port.test.d.ts +2 -0
- package/dist/__tests__/unit/port.test.d.ts.map +1 -0
- package/dist/__tests__/unit/port.test.js +20 -0
- package/dist/__tests__/unit/port.test.js.map +1 -0
- package/dist/__tests__/unit/vendored-sync.test.d.ts +14 -0
- package/dist/__tests__/unit/vendored-sync.test.d.ts.map +1 -0
- package/dist/__tests__/unit/vendored-sync.test.js +90 -0
- package/dist/__tests__/unit/vendored-sync.test.js.map +1 -0
- package/dist/commands/broken-links.d.ts +11 -0
- package/dist/commands/broken-links.d.ts.map +1 -0
- package/dist/commands/broken-links.js +95 -0
- package/dist/commands/broken-links.js.map +1 -0
- package/dist/commands/clean.d.ts +7 -0
- package/dist/commands/clean.d.ts.map +1 -0
- package/dist/commands/clean.js +59 -0
- package/dist/commands/clean.js.map +1 -0
- package/dist/commands/deploy/cloudflare.d.ts +12 -0
- package/dist/commands/deploy/cloudflare.d.ts.map +1 -0
- package/dist/commands/deploy/cloudflare.js +409 -0
- package/dist/commands/deploy/cloudflare.js.map +1 -0
- package/dist/commands/deploy/templates.d.ts +23 -0
- package/dist/commands/deploy/templates.d.ts.map +1 -0
- package/dist/commands/deploy/templates.js +179 -0
- package/dist/commands/deploy/templates.js.map +1 -0
- package/dist/commands/deploy/types.d.ts +19 -0
- package/dist/commands/deploy/types.d.ts.map +1 -0
- package/dist/commands/deploy/types.js +5 -0
- package/dist/commands/deploy/types.js.map +1 -0
- package/dist/commands/dev.d.ts +14 -0
- package/dist/commands/dev.d.ts.map +1 -0
- package/dist/commands/dev.js +817 -0
- package/dist/commands/dev.js.map +1 -0
- package/dist/commands/doctor.d.ts +7 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +159 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/init.d.ts +7 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +96 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/migrate/convert-mdx.d.ts +50 -0
- package/dist/commands/migrate/convert-mdx.d.ts.map +1 -0
- package/dist/commands/migrate/convert-mdx.js +108 -0
- package/dist/commands/migrate/convert-mdx.js.map +1 -0
- package/dist/commands/migrate/convert.d.ts +80 -0
- package/dist/commands/migrate/convert.d.ts.map +1 -0
- package/dist/commands/migrate/convert.js +158 -0
- package/dist/commands/migrate/convert.js.map +1 -0
- package/dist/commands/migrate/detect.d.ts +31 -0
- package/dist/commands/migrate/detect.d.ts.map +1 -0
- package/dist/commands/migrate/detect.js +62 -0
- package/dist/commands/migrate/detect.js.map +1 -0
- package/dist/commands/migrate/extract-hooks.d.ts +71 -0
- package/dist/commands/migrate/extract-hooks.d.ts.map +1 -0
- package/dist/commands/migrate/extract-hooks.js +473 -0
- package/dist/commands/migrate/extract-hooks.js.map +1 -0
- package/dist/commands/migrate/index.d.ts +17 -0
- package/dist/commands/migrate/index.d.ts.map +1 -0
- package/dist/commands/migrate/index.js +282 -0
- package/dist/commands/migrate/index.js.map +1 -0
- package/dist/commands/migrate/prompts.d.ts +22 -0
- package/dist/commands/migrate/prompts.d.ts.map +1 -0
- package/dist/commands/migrate/prompts.js +67 -0
- package/dist/commands/migrate/prompts.js.map +1 -0
- package/dist/commands/migrate/types.d.ts +22 -0
- package/dist/commands/migrate/types.d.ts.map +1 -0
- package/dist/commands/migrate/types.js +26 -0
- package/dist/commands/migrate/types.js.map +1 -0
- package/dist/commands/openapi-check.d.ts +11 -0
- package/dist/commands/openapi-check.d.ts.map +1 -0
- package/dist/commands/openapi-check.js +88 -0
- package/dist/commands/openapi-check.js.map +1 -0
- package/dist/commands/rename.d.ts +10 -0
- package/dist/commands/rename.d.ts.map +1 -0
- package/dist/commands/rename.js +125 -0
- package/dist/commands/rename.js.map +1 -0
- package/dist/commands/update.d.ts +10 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +57 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/validate.d.ts +12 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +163 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +334 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/config.d.ts +7 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +18 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/deprecated-components.d.ts +72 -0
- package/dist/lib/deprecated-components.d.ts.map +1 -0
- package/dist/lib/deprecated-components.js +138 -0
- package/dist/lib/deprecated-components.js.map +1 -0
- package/dist/lib/deps.d.ts +17 -0
- package/dist/lib/deps.d.ts.map +1 -0
- package/dist/lib/deps.js +186 -0
- package/dist/lib/deps.js.map +1 -0
- package/dist/lib/docs-config.d.ts +67 -0
- package/dist/lib/docs-config.d.ts.map +1 -0
- package/dist/lib/docs-config.js +294 -0
- package/dist/lib/docs-config.js.map +1 -0
- package/dist/lib/errors.d.ts +23 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/errors.js +32 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/frontmatter-utils.d.ts +25 -0
- package/dist/lib/frontmatter-utils.d.ts.map +1 -0
- package/dist/lib/frontmatter-utils.js +64 -0
- package/dist/lib/frontmatter-utils.js.map +1 -0
- package/dist/lib/mdx-validator.d.ts +27 -0
- package/dist/lib/mdx-validator.d.ts.map +1 -0
- package/dist/lib/mdx-validator.js +148 -0
- package/dist/lib/mdx-validator.js.map +1 -0
- package/dist/lib/navigation-validator.d.ts +31 -0
- package/dist/lib/navigation-validator.d.ts.map +1 -0
- package/dist/lib/navigation-validator.js +75 -0
- package/dist/lib/navigation-validator.js.map +1 -0
- package/dist/lib/normalize-config.d.ts +57 -0
- package/dist/lib/normalize-config.d.ts.map +1 -0
- package/dist/lib/normalize-config.js +63 -0
- package/dist/lib/normalize-config.js.map +1 -0
- package/dist/lib/openapi/cache.d.ts +40 -0
- package/dist/lib/openapi/cache.d.ts.map +1 -0
- package/dist/lib/openapi/cache.js +76 -0
- package/dist/lib/openapi/cache.js.map +1 -0
- package/dist/lib/openapi/errors.d.ts +36 -0
- package/dist/lib/openapi/errors.d.ts.map +1 -0
- package/dist/lib/openapi/errors.js +162 -0
- package/dist/lib/openapi/errors.js.map +1 -0
- package/dist/lib/openapi/index.d.ts +10 -0
- package/dist/lib/openapi/index.d.ts.map +1 -0
- package/dist/lib/openapi/index.js +12 -0
- package/dist/lib/openapi/index.js.map +1 -0
- package/dist/lib/openapi/types.d.ts +198 -0
- package/dist/lib/openapi/types.d.ts.map +1 -0
- package/dist/lib/openapi/types.js +8 -0
- package/dist/lib/openapi/types.js.map +1 -0
- package/dist/lib/openapi/validator.d.ts +45 -0
- package/dist/lib/openapi/validator.d.ts.map +1 -0
- package/dist/lib/openapi/validator.js +128 -0
- package/dist/lib/openapi/validator.js.map +1 -0
- package/dist/lib/openapi.d.ts +7 -0
- package/dist/lib/openapi.d.ts.map +1 -0
- package/dist/lib/openapi.js +7 -0
- package/dist/lib/openapi.js.map +1 -0
- package/dist/lib/output.d.ts +14 -0
- package/dist/lib/output.d.ts.map +1 -0
- package/dist/lib/output.js +19 -0
- package/dist/lib/output.js.map +1 -0
- package/dist/lib/path-security.d.ts +23 -0
- package/dist/lib/path-security.d.ts.map +1 -0
- package/dist/lib/path-security.js +35 -0
- package/dist/lib/path-security.js.map +1 -0
- package/dist/lib/port.d.ts +18 -0
- package/dist/lib/port.d.ts.map +1 -0
- package/dist/lib/port.js +65 -0
- package/dist/lib/port.js.map +1 -0
- package/dist/lib/spinner.d.ts +4 -0
- package/dist/lib/spinner.d.ts.map +1 -0
- package/dist/lib/spinner.js +16 -0
- package/dist/lib/spinner.js.map +1 -0
- package/dist/lib/version.d.ts +2 -0
- package/dist/lib/version.d.ts.map +1 -0
- package/dist/lib/version.js +49 -0
- package/dist/lib/version.js.map +1 -0
- package/dist/utils/update-checker.d.ts +34 -0
- package/dist/utils/update-checker.d.ts.map +1 -0
- package/dist/utils/update-checker.js +142 -0
- package/dist/utils/update-checker.js.map +1 -0
- package/package.json +125 -0
- package/templates/docs.json +11 -0
- package/templates/introduction.mdx +19 -0
- package/templates/quickstart.mdx +20 -0
- package/vendored/app/[[...slug]]/error.tsx +103 -0
- package/vendored/app/[[...slug]]/page.tsx +690 -0
- package/vendored/app/api/assets/[...path]/route.ts +78 -0
- package/vendored/app/api/ev/route.ts +61 -0
- package/vendored/app/api/isr-health/route.ts +66 -0
- package/vendored/app/api/mcp/[project]/route.ts +435 -0
- package/vendored/app/api/og/route.tsx +167 -0
- package/vendored/app/api/r2/[project]/[...path]/route.ts +214 -0
- package/vendored/app/api/revalidate/route.ts +76 -0
- package/vendored/app/globals.css +37 -0
- package/vendored/app/layout.tsx +571 -0
- package/vendored/app/not-found.tsx +47 -0
- package/vendored/components/CodeBlockCopyButton.tsx +146 -0
- package/vendored/components/HeaderLinkCopy.tsx +135 -0
- package/vendored/components/errors/NotFoundContent.tsx +147 -0
- package/vendored/components/layout/LayoutWrapper.tsx +128 -0
- package/vendored/components/mdx/Accordion.tsx +91 -0
- package/vendored/components/mdx/ApiCodePanel.tsx +51 -0
- package/vendored/components/mdx/ApiEndpoint.tsx +104 -0
- package/vendored/components/mdx/ApiPage.tsx +379 -0
- package/vendored/components/mdx/Badge.tsx +169 -0
- package/vendored/components/mdx/Callouts.tsx +140 -0
- package/vendored/components/mdx/Card.tsx +214 -0
- package/vendored/components/mdx/CodeGroup.tsx +136 -0
- package/vendored/components/mdx/Color.tsx +244 -0
- package/vendored/components/mdx/Columns.tsx +37 -0
- package/vendored/components/mdx/Expandable.tsx +37 -0
- package/vendored/components/mdx/Frame.tsx +51 -0
- package/vendored/components/mdx/Icon.tsx +132 -0
- package/vendored/components/mdx/Latex.tsx +75 -0
- package/vendored/components/mdx/MDXComponents.tsx +414 -0
- package/vendored/components/mdx/Mermaid.tsx +35 -0
- package/vendored/components/mdx/MermaidInner.tsx +342 -0
- package/vendored/components/mdx/OpenApiEndpoint.tsx +971 -0
- package/vendored/components/mdx/Panel.tsx +26 -0
- package/vendored/components/mdx/PanelWrapper.tsx +100 -0
- package/vendored/components/mdx/ParamField.tsx +75 -0
- package/vendored/components/mdx/RequestExample.tsx +91 -0
- package/vendored/components/mdx/ResponseExample.tsx +145 -0
- package/vendored/components/mdx/ResponseField.tsx +109 -0
- package/vendored/components/mdx/Steps.tsx +173 -0
- package/vendored/components/mdx/Table.tsx +352 -0
- package/vendored/components/mdx/Tabs.tsx +147 -0
- package/vendored/components/mdx/Tile.tsx +127 -0
- package/vendored/components/mdx/Tooltip.tsx +111 -0
- package/vendored/components/mdx/Tree.tsx +484 -0
- package/vendored/components/mdx/Update.tsx +90 -0
- package/vendored/components/mdx/View.tsx +354 -0
- package/vendored/components/mdx/YouTube.tsx +35 -0
- package/vendored/components/mdx/ZoomableImage.tsx +83 -0
- package/vendored/components/navigation/Breadcrumb.tsx +241 -0
- package/vendored/components/navigation/DefaultLogo.tsx +81 -0
- package/vendored/components/navigation/Header.tsx +512 -0
- package/vendored/components/navigation/LanguageSelector.tsx +249 -0
- package/vendored/components/navigation/PageNavigation.tsx +174 -0
- package/vendored/components/navigation/Sidebar.tsx +713 -0
- package/vendored/components/navigation/SocialFooter.tsx +186 -0
- package/vendored/components/navigation/TableOfContents.tsx +435 -0
- package/vendored/components/navigation/TabsNav.tsx +182 -0
- package/vendored/components/search/LazySearchModal.tsx +19 -0
- package/vendored/components/search/SearchModal.tsx +573 -0
- package/vendored/components/snippets/ProjectSnippets.tsx +4 -0
- package/vendored/components/theme/ThemeProvider.tsx +31 -0
- package/vendored/components/theme/ThemeToggle.tsx +134 -0
- package/vendored/components/ui/CodePanel.tsx +517 -0
- package/vendored/components/ui/CodePanelModal.tsx +342 -0
- package/vendored/contexts/TabSyncContext.tsx +30 -0
- package/vendored/hooks/useFocusTrap.ts +42 -0
- package/vendored/hooks/useHashNavigation.ts +39 -0
- package/vendored/hooks/useShikiHighlight.ts +101 -0
- package/vendored/lib/analytics-client.ts +77 -0
- package/vendored/lib/build/cache.ts +138 -0
- package/vendored/lib/build/error-parser.ts +690 -0
- package/vendored/lib/build/estimation.ts +113 -0
- package/vendored/lib/build/index.ts +17 -0
- package/vendored/lib/build/page-file-map.ts +48 -0
- package/vendored/lib/build/r2-upload.ts +179 -0
- package/vendored/lib/cache-keys.ts +117 -0
- package/vendored/lib/code-utils.ts +42 -0
- package/vendored/lib/content-loader.ts +176 -0
- package/vendored/lib/deprecated-components.ts +185 -0
- package/vendored/lib/docs-isr.ts +180 -0
- package/vendored/lib/docs-types.ts +874 -0
- package/vendored/lib/docs.ts +203 -0
- package/vendored/lib/domain-helpers.ts +107 -0
- package/vendored/lib/email-notifier.ts +102 -0
- package/vendored/lib/email-templates/build-failure.tsx +193 -0
- package/vendored/lib/email-templates/components/base-layout.tsx +150 -0
- package/vendored/lib/email-templates/components/error-box.tsx +88 -0
- package/vendored/lib/email-templates/components/info-row.tsx +63 -0
- package/vendored/lib/email-templates/index.ts +13 -0
- package/vendored/lib/empty-polyfill.js +3 -0
- package/vendored/lib/extract-highlights.ts +124 -0
- package/vendored/lib/fonts.ts +227 -0
- package/vendored/lib/frontmatter-utils.ts +77 -0
- package/vendored/lib/fs-utils.ts +20 -0
- package/vendored/lib/git-utils.ts +87 -0
- package/vendored/lib/health-checks.ts +224 -0
- package/vendored/lib/icon-utils.ts +492 -0
- package/vendored/lib/infer-page-type.ts +14 -0
- package/vendored/lib/isr-build-executor.ts +185 -0
- package/vendored/lib/language-icons.ts +152 -0
- package/vendored/lib/language-utils.ts +338 -0
- package/vendored/lib/latex-config.ts +64 -0
- package/vendored/lib/link-prefix-context.tsx +32 -0
- package/vendored/lib/logger.ts +63 -0
- package/vendored/lib/mcp-search.ts +255 -0
- package/vendored/lib/mdx-inline-components.ts +155 -0
- package/vendored/lib/mdx.ts +100 -0
- package/vendored/lib/middleware-helpers.ts +519 -0
- package/vendored/lib/navigation-resolver.ts +621 -0
- package/vendored/lib/navigation-utils.ts +103 -0
- package/vendored/lib/normalize-config.ts +94 -0
- package/vendored/lib/openapi/cache.ts +92 -0
- package/vendored/lib/openapi/code-examples.ts +389 -0
- package/vendored/lib/openapi/errors.ts +253 -0
- package/vendored/lib/openapi/generator.ts +230 -0
- package/vendored/lib/openapi/index.ts +84 -0
- package/vendored/lib/openapi/parser.ts +474 -0
- package/vendored/lib/openapi/types.ts +232 -0
- package/vendored/lib/openapi/validator.ts +156 -0
- package/vendored/lib/openapi-isr.ts +121 -0
- package/vendored/lib/page-isr-helpers.ts +137 -0
- package/vendored/lib/path-safety.ts +130 -0
- package/vendored/lib/paths.ts +35 -0
- package/vendored/lib/preprocess-mdx.ts +951 -0
- package/vendored/lib/process-mdx-with-exports.ts +75 -0
- package/vendored/lib/project-resolver.ts +165 -0
- package/vendored/lib/r2-content.ts +60 -0
- package/vendored/lib/r2-manifest.ts +84 -0
- package/vendored/lib/recent-searches.ts +41 -0
- package/vendored/lib/recma-compound-components.ts +84 -0
- package/vendored/lib/redirect-compiler.ts +160 -0
- package/vendored/lib/redirect-matcher.ts +296 -0
- package/vendored/lib/redis.ts +23 -0
- package/vendored/lib/rehype-class-to-classname.ts +31 -0
- package/vendored/lib/rehype-code-meta.ts +275 -0
- package/vendored/lib/rehype-nozoom-to-data.ts +45 -0
- package/vendored/lib/remark-extract-exports.ts +104 -0
- package/vendored/lib/resilience.ts +260 -0
- package/vendored/lib/revalidation-helpers.ts +200 -0
- package/vendored/lib/revalidation-trigger.ts +150 -0
- package/vendored/lib/screenshot-capture.ts +229 -0
- package/vendored/lib/search-client.ts +91 -0
- package/vendored/lib/search-suggestions.ts +38 -0
- package/vendored/lib/search.ts +158 -0
- package/vendored/lib/seo.ts +264 -0
- package/vendored/lib/shiki-client.ts +131 -0
- package/vendored/lib/shiki-config.ts +289 -0
- package/vendored/lib/shiki-css-theme.ts +46 -0
- package/vendored/lib/shiki-highlighter.ts +62 -0
- package/vendored/lib/shiki-transformers.ts +337 -0
- package/vendored/lib/slack-notifier.ts +248 -0
- package/vendored/lib/snippet-compiler-isr.ts +114 -0
- package/vendored/lib/snippet-loader-isr.ts +276 -0
- package/vendored/lib/static-artifacts.ts +375 -0
- package/vendored/lib/static-file-route.ts +72 -0
- package/vendored/lib/tracking-script.ts +19 -0
- package/vendored/lib/typography-config.ts +42 -0
- package/vendored/lib/validate-config.ts +268 -0
- package/vendored/next.config.js +45 -0
- package/vendored/postcss.config.js +6 -0
- package/vendored/schema/README.md +28 -0
- package/vendored/schema/docs-schema.json +4631 -0
- package/vendored/scripts/build-project.cjs +174 -0
- package/vendored/scripts/build-search-index.cjs +347 -0
- package/vendored/scripts/compile-snippets.cjs +488 -0
- package/vendored/scripts/copy-files.cjs +295 -0
- package/vendored/scripts/dev-project.cjs +534 -0
- package/vendored/scripts/enhance-navigation.cjs +354 -0
- package/vendored/scripts/validate-links.cjs +423 -0
- package/vendored/shared/constants.ts +6 -0
- package/vendored/shared/index.ts +19 -0
- package/vendored/shared/logger.ts +62 -0
- package/vendored/shared/memory-monitor.ts +190 -0
- package/vendored/shared/navigation-validator.ts +101 -0
- package/vendored/shared/path-security.ts +39 -0
- package/vendored/shared/status-reporter.ts +199 -0
- package/vendored/shared/timer.ts +51 -0
- package/vendored/shared/types.ts +102 -0
- package/vendored/tailwind.config.ts +39 -0
- package/vendored/themes/base.css +1311 -0
- package/vendored/themes/index.ts +119 -0
- package/vendored/themes/jam/variables.css +835 -0
- package/vendored/themes/nebula/variables.css +282 -0
- package/vendored/themes/pulsar/variables.css +1009 -0
- package/vendored/themes/types.ts +89 -0
- package/vendored/tsconfig.json +48 -0
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SEO Metadata Builder
|
|
3
|
+
*
|
|
4
|
+
* Builds Next.js Metadata objects from docs.json config and page frontmatter.
|
|
5
|
+
* Supports 19+ meta tags with per-page overrides.
|
|
6
|
+
*
|
|
7
|
+
* Priority order: Page frontmatter > Global config > Auto-generated
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { Metadata } from 'next';
|
|
11
|
+
import type { DocsConfig, Logo, LogoConfig, LanguageConfig, LanguageCode } from './docs-types';
|
|
12
|
+
import { transformLanguagePath, extractLanguageFromPath, isValidLanguageCode } from './language-utils';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Build the OG image URL for a page using the proxy's /api/og endpoint.
|
|
16
|
+
* Returns undefined if og:image is explicitly set in metatags.
|
|
17
|
+
*/
|
|
18
|
+
function buildOgImageUrl(
|
|
19
|
+
baseUrl: string,
|
|
20
|
+
title: string,
|
|
21
|
+
siteName: string,
|
|
22
|
+
options?: {
|
|
23
|
+
description?: string;
|
|
24
|
+
section?: string;
|
|
25
|
+
logo?: Logo;
|
|
26
|
+
theme?: 'light' | 'dark';
|
|
27
|
+
}
|
|
28
|
+
): string {
|
|
29
|
+
const params = new URLSearchParams();
|
|
30
|
+
params.set('title', title);
|
|
31
|
+
params.set('siteName', siteName);
|
|
32
|
+
|
|
33
|
+
if (options?.description) {
|
|
34
|
+
params.set('description', options.description);
|
|
35
|
+
}
|
|
36
|
+
if (options?.section) {
|
|
37
|
+
params.set('section', options.section);
|
|
38
|
+
}
|
|
39
|
+
if (options?.theme) {
|
|
40
|
+
params.set('theme', options.theme);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Get root URL (strip /docs path if present, since API endpoints are at domain root)
|
|
44
|
+
const rootUrl = baseUrl.replace(/\/docs$/, '');
|
|
45
|
+
|
|
46
|
+
// Handle logo - prefer dark variant for OG images (dark background)
|
|
47
|
+
if (options?.logo) {
|
|
48
|
+
let logoPath: string;
|
|
49
|
+
if (typeof options.logo === 'string') {
|
|
50
|
+
logoPath = options.logo;
|
|
51
|
+
} else {
|
|
52
|
+
logoPath = (options.logo as LogoConfig).dark || (options.logo as LogoConfig).light;
|
|
53
|
+
}
|
|
54
|
+
// Make logo URL absolute (use root URL since assets are at domain root)
|
|
55
|
+
if (logoPath && !logoPath.startsWith('http')) {
|
|
56
|
+
logoPath = `${rootUrl}${logoPath.startsWith('/') ? '' : '/'}${logoPath}`;
|
|
57
|
+
}
|
|
58
|
+
if (logoPath) {
|
|
59
|
+
params.set('logo', logoPath);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return `${rootUrl}/api/og?${params.toString()}`;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface PageFrontmatter {
|
|
67
|
+
title?: string;
|
|
68
|
+
description?: string;
|
|
69
|
+
noindex?: boolean;
|
|
70
|
+
hidden?: boolean;
|
|
71
|
+
/** Section/group name for OG image (optional) */
|
|
72
|
+
section?: string;
|
|
73
|
+
seo?: {
|
|
74
|
+
noindex?: boolean;
|
|
75
|
+
canonical?: string;
|
|
76
|
+
[key: string]: unknown;
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Build hreflang alternate links for multi-language pages.
|
|
82
|
+
* Generates links for each language version of the page, plus x-default.
|
|
83
|
+
*
|
|
84
|
+
* @param baseUrl - The base URL (e.g., "https://docs.example.com")
|
|
85
|
+
* @param pagePath - The current page path (e.g., "es/getting-started")
|
|
86
|
+
* @param languages - Array of language configurations from docs.json
|
|
87
|
+
* @returns Record of language code to URL for alternates.languages
|
|
88
|
+
*/
|
|
89
|
+
function buildHreflangAlternates(
|
|
90
|
+
baseUrl: string,
|
|
91
|
+
pagePath: string,
|
|
92
|
+
languages: LanguageConfig[]
|
|
93
|
+
): Record<string, string> | undefined {
|
|
94
|
+
// Only generate hreflang if there are multiple languages
|
|
95
|
+
if (!languages || languages.length <= 1) {
|
|
96
|
+
return undefined;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Find the default language
|
|
100
|
+
const defaultLang = languages.find((l) => l.default)?.language || languages[0]?.language || 'en';
|
|
101
|
+
|
|
102
|
+
// Detect current language from path
|
|
103
|
+
const currentLang = extractLanguageFromPath(pagePath) || defaultLang;
|
|
104
|
+
|
|
105
|
+
// Build alternates for each language
|
|
106
|
+
const alternates: Record<string, string> = {};
|
|
107
|
+
|
|
108
|
+
for (const langConfig of languages) {
|
|
109
|
+
const lang = langConfig.language;
|
|
110
|
+
// Transform current path to this language's version
|
|
111
|
+
// transformLanguagePath returns paths relative to app root (e.g., '/es/intro' or '/intro')
|
|
112
|
+
const langPath = transformLanguagePath(pagePath, currentLang, lang, defaultLang);
|
|
113
|
+
const cleanPath = langPath.replace(/^\//, ''); // Remove leading slash for URL building
|
|
114
|
+
alternates[lang] = cleanPath ? `${baseUrl}/${cleanPath}` : baseUrl;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Add x-default pointing to the default language version
|
|
118
|
+
const defaultPath = transformLanguagePath(pagePath, currentLang, defaultLang, defaultLang);
|
|
119
|
+
const cleanDefaultPath = defaultPath.replace(/^\//, '');
|
|
120
|
+
alternates['x-default'] = cleanDefaultPath ? `${baseUrl}/${cleanDefaultPath}` : baseUrl;
|
|
121
|
+
|
|
122
|
+
return alternates;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Build SEO metadata for a documentation page.
|
|
127
|
+
*
|
|
128
|
+
* @param config - The docs.json configuration
|
|
129
|
+
* @param frontmatter - Page frontmatter data
|
|
130
|
+
* @param pagePath - The page path (e.g., "getting-started/installation")
|
|
131
|
+
* @param baseUrl - The base URL (e.g., "https://docs.example.com")
|
|
132
|
+
* @param languages - Optional array of language configurations for hreflang tags
|
|
133
|
+
* @returns Partial<Metadata> to spread into generateMetadata return
|
|
134
|
+
*/
|
|
135
|
+
export function buildSeoMetadata(
|
|
136
|
+
config: DocsConfig,
|
|
137
|
+
frontmatter: PageFrontmatter,
|
|
138
|
+
pagePath: string,
|
|
139
|
+
baseUrl: string,
|
|
140
|
+
languages?: LanguageConfig[]
|
|
141
|
+
): Partial<Metadata> {
|
|
142
|
+
const globalMeta = config.seo?.metatags || {};
|
|
143
|
+
const pageMeta = (frontmatter.seo as Record<string, string>) || {};
|
|
144
|
+
// Merge: page overrides global
|
|
145
|
+
const metatags: Record<string, string> = { ...globalMeta, ...pageMeta };
|
|
146
|
+
const metadata: Partial<Metadata> = {};
|
|
147
|
+
|
|
148
|
+
// 1. Generator - always add
|
|
149
|
+
metadata.generator = 'Jamdesk';
|
|
150
|
+
|
|
151
|
+
// 2. Robots (priority: page > global)
|
|
152
|
+
// Page noindex can be set via frontmatter.noindex or frontmatter.seo.noindex
|
|
153
|
+
const pageNoindex = frontmatter.noindex ?? frontmatter.seo?.noindex;
|
|
154
|
+
if (pageNoindex === true) {
|
|
155
|
+
// noindex does NOT imply nofollow - use follow: true
|
|
156
|
+
metadata.robots = { index: false, follow: true };
|
|
157
|
+
} else if (pageNoindex !== false && metatags.robots) {
|
|
158
|
+
// Page didn't explicitly set noindex: false, so use global robots
|
|
159
|
+
metadata.robots = metatags.robots;
|
|
160
|
+
}
|
|
161
|
+
// If pageNoindex === false, it overrides any global noindex (no robots meta = index)
|
|
162
|
+
|
|
163
|
+
// 3. Googlebot (separate from robots)
|
|
164
|
+
if (metatags.googlebot) {
|
|
165
|
+
// Merge googlebot with existing robots config
|
|
166
|
+
const existingRobots = typeof metadata.robots === 'object' ? metadata.robots : {};
|
|
167
|
+
metadata.robots = {
|
|
168
|
+
...existingRobots,
|
|
169
|
+
googleBot: metatags.googlebot,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// 4. Google site verification
|
|
174
|
+
if (metatags['google-site-verification']) {
|
|
175
|
+
metadata.verification = { google: metatags['google-site-verification'] };
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// 5. Keywords
|
|
179
|
+
if (metatags.keywords) {
|
|
180
|
+
metadata.keywords = metatags.keywords.split(',').map((k) => k.trim());
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// 6. Description (global fallback only - page description handled separately)
|
|
184
|
+
if (!frontmatter.description && metatags.description) {
|
|
185
|
+
metadata.description = metatags.description;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// 7. Canonical (auto-generate if not specified)
|
|
189
|
+
const cleanPath = pagePath.replace(/^\/+|\/+$/g, ''); // Remove leading/trailing slashes
|
|
190
|
+
const pageUrl = cleanPath ? `${baseUrl}/${cleanPath}` : baseUrl;
|
|
191
|
+
const canonical = pageMeta.canonical || metatags.canonical || pageUrl;
|
|
192
|
+
|
|
193
|
+
// 7b. Hreflang alternates for multi-language support
|
|
194
|
+
const hreflangLanguages = buildHreflangAlternates(baseUrl, pagePath, languages || []);
|
|
195
|
+
|
|
196
|
+
metadata.alternates = {
|
|
197
|
+
canonical,
|
|
198
|
+
...(hreflangLanguages && { languages: hreflangLanguages }),
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
// 8. Open Graph
|
|
202
|
+
const hasOgTags = Object.keys(metatags).some((k) => k.startsWith('og:'));
|
|
203
|
+
if (hasOgTags || frontmatter.title) {
|
|
204
|
+
// Auto-generate OG image URL if not explicitly set
|
|
205
|
+
const ogImageUrl = metatags['og:image'] || buildOgImageUrl(
|
|
206
|
+
baseUrl,
|
|
207
|
+
frontmatter.title || 'Documentation',
|
|
208
|
+
config.name,
|
|
209
|
+
{
|
|
210
|
+
description: frontmatter.description,
|
|
211
|
+
section: frontmatter.section,
|
|
212
|
+
logo: config.logo,
|
|
213
|
+
theme: 'dark', // Dark theme looks better for OG images
|
|
214
|
+
}
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
metadata.openGraph = {
|
|
218
|
+
title: metatags['og:title'] || frontmatter.title,
|
|
219
|
+
description: metatags['og:description'] || frontmatter.description,
|
|
220
|
+
url: metatags['og:url'] || pageUrl,
|
|
221
|
+
siteName: metatags['og:site_name'] || config.name,
|
|
222
|
+
type: (metatags['og:type'] as 'website' | 'article') || 'website',
|
|
223
|
+
images: [ogImageUrl],
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// 9. Twitter Cards
|
|
228
|
+
// Auto-generate Twitter card with OG image
|
|
229
|
+
const twitterImageUrl = metatags['twitter:image'] || (metadata.openGraph as { images?: string[] })?.images?.[0];
|
|
230
|
+
metadata.twitter = {
|
|
231
|
+
card: (metatags['twitter:card'] as 'summary' | 'summary_large_image') || 'summary_large_image',
|
|
232
|
+
site: metatags['twitter:site'],
|
|
233
|
+
title: metatags['twitter:title'] || frontmatter.title,
|
|
234
|
+
description: metatags['twitter:description'] || frontmatter.description,
|
|
235
|
+
...(twitterImageUrl && { images: [twitterImageUrl] }),
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
// 10. Theme color
|
|
239
|
+
if (metatags['theme-color']) {
|
|
240
|
+
metadata.themeColor = metatags['theme-color'];
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// 11. Authors
|
|
244
|
+
if (metatags.author) {
|
|
245
|
+
metadata.authors = [{ name: metatags.author }];
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// 12. Other tags (google, copyright, etc.)
|
|
249
|
+
const other: Record<string, string> = {};
|
|
250
|
+
if (metatags.google) other.google = metatags.google;
|
|
251
|
+
if (metatags.copyright) other.copyright = metatags.copyright;
|
|
252
|
+
|
|
253
|
+
// 13. Build metadata - commit SHA helps identify which version created this page
|
|
254
|
+
// Note: We use commit SHA (not unique build ID) to ensure identical content = identical HTML
|
|
255
|
+
if (process.env.BUILD_ID) {
|
|
256
|
+
other['jamdesk:build-id'] = process.env.BUILD_ID;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
if (Object.keys(other).length > 0) {
|
|
260
|
+
metadata.other = other;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
return metadata;
|
|
264
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-side Shiki syntax highlighting utility
|
|
3
|
+
* Used for dynamic code highlighting (e.g., OpenAPI code examples)
|
|
4
|
+
*/
|
|
5
|
+
'use client';
|
|
6
|
+
|
|
7
|
+
import type { Highlighter, BundledLanguage, BundledTheme } from 'shiki';
|
|
8
|
+
|
|
9
|
+
let highlighter: Highlighter | null = null;
|
|
10
|
+
|
|
11
|
+
// Languages needed for API code examples
|
|
12
|
+
const CLIENT_LANGUAGES: BundledLanguage[] = [
|
|
13
|
+
'javascript',
|
|
14
|
+
'typescript',
|
|
15
|
+
'python',
|
|
16
|
+
'bash',
|
|
17
|
+
'json',
|
|
18
|
+
'shell',
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
// Dual themes for light/dark mode support
|
|
22
|
+
const THEMES = {
|
|
23
|
+
light: 'github-light-default' as BundledTheme,
|
|
24
|
+
dark: 'github-dark-default' as BundledTheme,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Get or initialize the Shiki highlighter for client-side use
|
|
29
|
+
*/
|
|
30
|
+
async function getHighlighter(): Promise<Highlighter> {
|
|
31
|
+
if (!highlighter) {
|
|
32
|
+
const { createHighlighter } = await import('shiki');
|
|
33
|
+
|
|
34
|
+
highlighter = await createHighlighter({
|
|
35
|
+
themes: [THEMES.dark, THEMES.light],
|
|
36
|
+
langs: CLIENT_LANGUAGES,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
return highlighter;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Escape HTML entities for fallback rendering
|
|
44
|
+
*/
|
|
45
|
+
function escapeHtml(text: string): string {
|
|
46
|
+
return text
|
|
47
|
+
.replace(/&/g, '&')
|
|
48
|
+
.replace(/</g, '<')
|
|
49
|
+
.replace(/>/g, '>')
|
|
50
|
+
.replace(/"/g, '"')
|
|
51
|
+
.replace(/'/g, ''');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Highlight code synchronously if highlighter is ready, otherwise return escaped code
|
|
56
|
+
* This is useful for initial render - the component can re-render when highlighting is done
|
|
57
|
+
*/
|
|
58
|
+
export function highlightCodeSync(code: string, language: string): string {
|
|
59
|
+
if (!highlighter) {
|
|
60
|
+
// Return escaped code if highlighter not ready yet
|
|
61
|
+
return escapeHtml(code);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
try {
|
|
65
|
+
const lang = normalizeLanguage(language);
|
|
66
|
+
return highlighter.codeToHtml(code, {
|
|
67
|
+
lang,
|
|
68
|
+
themes: THEMES,
|
|
69
|
+
defaultColor: 'dark',
|
|
70
|
+
});
|
|
71
|
+
} catch {
|
|
72
|
+
return escapeHtml(code);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Highlight code asynchronously
|
|
78
|
+
* Returns full HTML with pre.shiki element for proper theme background support
|
|
79
|
+
*/
|
|
80
|
+
export async function highlightCode(
|
|
81
|
+
code: string,
|
|
82
|
+
language: string
|
|
83
|
+
): Promise<string> {
|
|
84
|
+
try {
|
|
85
|
+
const shiki = await getHighlighter();
|
|
86
|
+
const lang = normalizeLanguage(language);
|
|
87
|
+
|
|
88
|
+
// Return full HTML - the pre.shiki element contains background styles
|
|
89
|
+
// that switch via CSS variables in light mode
|
|
90
|
+
return shiki.codeToHtml(code, {
|
|
91
|
+
lang,
|
|
92
|
+
themes: THEMES,
|
|
93
|
+
defaultColor: 'dark',
|
|
94
|
+
});
|
|
95
|
+
} catch {
|
|
96
|
+
return escapeHtml(code);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Preload the highlighter (call early to reduce latency)
|
|
102
|
+
*/
|
|
103
|
+
export async function preloadHighlighter(): Promise<void> {
|
|
104
|
+
await getHighlighter();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Normalize language aliases
|
|
109
|
+
*/
|
|
110
|
+
function normalizeLanguage(lang: string): BundledLanguage {
|
|
111
|
+
const normalized = lang.toLowerCase().trim();
|
|
112
|
+
|
|
113
|
+
const aliases: Record<string, BundledLanguage> = {
|
|
114
|
+
js: 'javascript',
|
|
115
|
+
ts: 'typescript',
|
|
116
|
+
sh: 'bash',
|
|
117
|
+
curl: 'bash',
|
|
118
|
+
py: 'python',
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
if (normalized in aliases) {
|
|
122
|
+
return aliases[normalized];
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (CLIENT_LANGUAGES.includes(normalized as BundledLanguage)) {
|
|
126
|
+
return normalized as BundledLanguage;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Default to text-like rendering
|
|
130
|
+
return 'bash';
|
|
131
|
+
}
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shiki syntax highlighting configuration
|
|
3
|
+
* Reads theme settings from docs.json and provides rehype plugin options
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { RehypeShikiOptions } from '@shikijs/rehype';
|
|
7
|
+
import rehypeShikiFromHighlighter, { type RehypeShikiCoreOptions } from '@shikijs/rehype/core';
|
|
8
|
+
import type { BuiltinLanguage, Highlighter, ThemeRegistration } from 'shiki';
|
|
9
|
+
import type { Pluggable } from 'unified';
|
|
10
|
+
import type { DocsConfig, StylingConfig } from './docs-types';
|
|
11
|
+
import { transformerLineFeatures } from './shiki-transformers';
|
|
12
|
+
import { JAMDESK_CSS_THEME } from './shiki-css-theme';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Preloaded languages for faster static generation.
|
|
16
|
+
* These are loaded upfront when the highlighter initializes,
|
|
17
|
+
* avoiding I/O during page rendering.
|
|
18
|
+
*
|
|
19
|
+
* ## What happens if a language is NOT in this list?
|
|
20
|
+
* - The code block renders WITHOUT syntax highlighting (plain monospace text)
|
|
21
|
+
* - A warning is logged during build: "[shiki] Unknown language: <lang>"
|
|
22
|
+
* - The build continues successfully (no errors)
|
|
23
|
+
*
|
|
24
|
+
* ## How to add a new language:
|
|
25
|
+
* 1. Find the language ID from Shiki's bundled languages:
|
|
26
|
+
* https://shiki.style/languages
|
|
27
|
+
* 2. Add it to this array (must match the exact Shiki language ID)
|
|
28
|
+
* 3. Deploy to Cloud Run and rebuild affected projects
|
|
29
|
+
*
|
|
30
|
+
* Each language adds ~100-500KB to highlighter init time.
|
|
31
|
+
* Keep this list focused on commonly-used documentation languages.
|
|
32
|
+
*/
|
|
33
|
+
export const PRELOADED_LANGUAGES: BuiltinLanguage[] = [
|
|
34
|
+
// Web fundamentals
|
|
35
|
+
'javascript',
|
|
36
|
+
'typescript',
|
|
37
|
+
'js', // Alias for javascript
|
|
38
|
+
'ts', // Alias for typescript
|
|
39
|
+
'jsx',
|
|
40
|
+
'tsx',
|
|
41
|
+
'html',
|
|
42
|
+
'css',
|
|
43
|
+
'json',
|
|
44
|
+
'yaml',
|
|
45
|
+
// Shell/scripting
|
|
46
|
+
'bash',
|
|
47
|
+
'shell', // Alias for shellscript, commonly used in markdown
|
|
48
|
+
'shellscript',
|
|
49
|
+
'powershell',
|
|
50
|
+
// Backend languages
|
|
51
|
+
'python',
|
|
52
|
+
'ruby',
|
|
53
|
+
'go',
|
|
54
|
+
'rust',
|
|
55
|
+
'java',
|
|
56
|
+
'kotlin',
|
|
57
|
+
'swift',
|
|
58
|
+
'php',
|
|
59
|
+
'csharp',
|
|
60
|
+
'c',
|
|
61
|
+
'cpp',
|
|
62
|
+
'clojure',
|
|
63
|
+
// Data/query
|
|
64
|
+
'sql',
|
|
65
|
+
'graphql',
|
|
66
|
+
// Config/markup
|
|
67
|
+
'xml',
|
|
68
|
+
'toml',
|
|
69
|
+
'markdown',
|
|
70
|
+
'md', // Alias for markdown - some docs use ```md instead of ```markdown
|
|
71
|
+
'mdx',
|
|
72
|
+
// DevOps
|
|
73
|
+
'dockerfile',
|
|
74
|
+
// Utility
|
|
75
|
+
'diff',
|
|
76
|
+
'log', // Log files
|
|
77
|
+
'http', // HTTP requests (GET https://api.example.com)
|
|
78
|
+
// Note: 'text' and 'plaintext' are NOT valid Shiki languages.
|
|
79
|
+
// Code blocks with these will render without highlighting (which is correct).
|
|
80
|
+
];
|
|
81
|
+
|
|
82
|
+
// Set for O(1) language lookups in the unknown language warning transformer
|
|
83
|
+
const PRELOADED_LANGUAGES_SET = new Set<string>(PRELOADED_LANGUAGES);
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Languages that intentionally don't have syntax highlighting.
|
|
87
|
+
* Adding them here prevents the "Unknown language" warning during build.
|
|
88
|
+
*
|
|
89
|
+
* Note: 'mermaid' is included because it's rendered client-side by the Mermaid
|
|
90
|
+
* component. The data-language attribute is still set by Shiki's transformer,
|
|
91
|
+
* which MDXComponents.tsx uses to route to the Mermaid component.
|
|
92
|
+
*/
|
|
93
|
+
const NO_HIGHLIGHT_LANGS = new Set(['text', 'plaintext', 'plain', 'txt', 'raw', 'mermaid']);
|
|
94
|
+
|
|
95
|
+
// Curated list of supported themes (reduces bundle size vs bundling all ~50)
|
|
96
|
+
export const SUPPORTED_THEMES = [
|
|
97
|
+
// GitHub family (default themes - matching marketing)
|
|
98
|
+
'github-dark',
|
|
99
|
+
'github-light',
|
|
100
|
+
'github-dark-default',
|
|
101
|
+
'github-light-default',
|
|
102
|
+
// Popular dark themes
|
|
103
|
+
'tokyo-night',
|
|
104
|
+
'one-dark-pro',
|
|
105
|
+
'dracula',
|
|
106
|
+
'nord',
|
|
107
|
+
'vitesse-dark',
|
|
108
|
+
// Popular light themes
|
|
109
|
+
'vitesse-light',
|
|
110
|
+
'min-light',
|
|
111
|
+
// Catppuccin variants
|
|
112
|
+
'catppuccin-mocha',
|
|
113
|
+
'catppuccin-latte',
|
|
114
|
+
// Custom CSS styling
|
|
115
|
+
'css-variables',
|
|
116
|
+
] as const;
|
|
117
|
+
|
|
118
|
+
export type SupportedTheme = (typeof SUPPORTED_THEMES)[number];
|
|
119
|
+
|
|
120
|
+
// Default themes - github-dark-default has the darker #0d1117 background
|
|
121
|
+
const DEFAULT_DARK_THEME: SupportedTheme = 'github-dark-default';
|
|
122
|
+
const DEFAULT_LIGHT_THEME: SupportedTheme = 'github-light-default';
|
|
123
|
+
|
|
124
|
+
// Type for theme values (can be string or ThemeRegistration for css-variables)
|
|
125
|
+
type ThemeValue = SupportedTheme | ThemeRegistration;
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Parse codeblocks config from docs.json styling section
|
|
129
|
+
*/
|
|
130
|
+
function parseCodeblocksConfig(styling?: StylingConfig): {
|
|
131
|
+
darkTheme: ThemeValue;
|
|
132
|
+
lightTheme: ThemeValue;
|
|
133
|
+
} {
|
|
134
|
+
const codeblocks = styling?.codeblocks;
|
|
135
|
+
|
|
136
|
+
// Default: use github themes
|
|
137
|
+
if (!codeblocks || codeblocks === 'system') {
|
|
138
|
+
return { darkTheme: DEFAULT_DARK_THEME, lightTheme: DEFAULT_LIGHT_THEME };
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// 'dark' mode only
|
|
142
|
+
if (codeblocks === 'dark') {
|
|
143
|
+
return { darkTheme: DEFAULT_DARK_THEME, lightTheme: DEFAULT_DARK_THEME };
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Object config with theme property
|
|
147
|
+
const themeConfig = codeblocks.theme;
|
|
148
|
+
|
|
149
|
+
if (!themeConfig) {
|
|
150
|
+
return { darkTheme: DEFAULT_DARK_THEME, lightTheme: DEFAULT_LIGHT_THEME };
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Single theme string - use for both
|
|
154
|
+
if (typeof themeConfig === 'string') {
|
|
155
|
+
const theme = validateTheme(themeConfig);
|
|
156
|
+
return { darkTheme: theme, lightTheme: theme };
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Light/dark theme pair
|
|
160
|
+
return {
|
|
161
|
+
darkTheme: validateTheme(themeConfig.dark),
|
|
162
|
+
lightTheme: validateTheme(themeConfig.light),
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Validate a theme name against supported themes
|
|
168
|
+
* Returns ThemeRegistration object for css-variables, string for built-in themes
|
|
169
|
+
*/
|
|
170
|
+
function validateTheme(theme: string | undefined): ThemeValue {
|
|
171
|
+
if (!theme) return DEFAULT_DARK_THEME;
|
|
172
|
+
|
|
173
|
+
// Special handling for css-variables theme
|
|
174
|
+
if (theme === 'css-variables') {
|
|
175
|
+
return JAMDESK_CSS_THEME;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (SUPPORTED_THEMES.includes(theme as SupportedTheme)) {
|
|
179
|
+
return theme as SupportedTheme;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
console.warn(
|
|
183
|
+
`[shiki-config] Unsupported theme "${theme}", falling back to "${DEFAULT_DARK_THEME}". ` +
|
|
184
|
+
`Supported themes: ${SUPPORTED_THEMES.join(', ')}`
|
|
185
|
+
);
|
|
186
|
+
return DEFAULT_DARK_THEME;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Get Shiki rehype plugin options based on docs.json config
|
|
191
|
+
*/
|
|
192
|
+
export function getShikiOptions(config?: DocsConfig): Partial<RehypeShikiOptions> {
|
|
193
|
+
const { darkTheme, lightTheme } = parseCodeblocksConfig(config?.styling);
|
|
194
|
+
|
|
195
|
+
// Use dual themes for light/dark mode support
|
|
196
|
+
// The 'themes' option enables CSS variable-based theme switching
|
|
197
|
+
return {
|
|
198
|
+
themes: {
|
|
199
|
+
light: lightTheme,
|
|
200
|
+
dark: darkTheme,
|
|
201
|
+
},
|
|
202
|
+
// Preload common languages for faster static generation
|
|
203
|
+
// Unknown languages fall back to plaintext (no highlighting)
|
|
204
|
+
langs: PRELOADED_LANGUAGES,
|
|
205
|
+
// Default color mode (used when no preference is specified)
|
|
206
|
+
defaultColor: 'dark',
|
|
207
|
+
// Safety: skip highlighting lines >1000 chars to prevent OOM on minified code
|
|
208
|
+
// Lines exceeding this limit render without syntax highlighting
|
|
209
|
+
tokenizeMaxLineLength: 1000,
|
|
210
|
+
// Add transformers for language/meta attributes and line features
|
|
211
|
+
// Performance note: Order matters - cheaper transformers first, lazy notation last
|
|
212
|
+
transformers: [
|
|
213
|
+
{
|
|
214
|
+
name: 'log-unknown-languages',
|
|
215
|
+
preprocess(code: string, options: { lang?: string }) {
|
|
216
|
+
// Log warning for unknown languages so we know to add them
|
|
217
|
+
const lang = options.lang;
|
|
218
|
+
// Skip warning for intentionally unhighlighted languages
|
|
219
|
+
if (
|
|
220
|
+
lang &&
|
|
221
|
+
!PRELOADED_LANGUAGES_SET.has(lang) && // O(1) Set lookup instead of O(n) array
|
|
222
|
+
!NO_HIGHLIGHT_LANGS.has(lang) // O(1) Set lookup
|
|
223
|
+
) {
|
|
224
|
+
console.warn(
|
|
225
|
+
`[shiki] Unknown language: "${lang}" - code block will render without highlighting. ` +
|
|
226
|
+
`To add support, add "${lang}" to PRELOADED_LANGUAGES in lib/shiki-config.ts`
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
return code;
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
name: 'add-data-attributes',
|
|
234
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
235
|
+
pre(this: any, node: any) {
|
|
236
|
+
// Add data-language attribute to pre element for tab label extraction
|
|
237
|
+
if (this.options.lang) {
|
|
238
|
+
node.properties['data-language'] = this.options.lang;
|
|
239
|
+
}
|
|
240
|
+
// Add data-meta attribute to pre element
|
|
241
|
+
// This preserves the raw meta string from code fences (e.g., "Header" from ```json Header)
|
|
242
|
+
// A post-Shiki rehype plugin (rehypeRestoreDataTitle) converts this to data-title
|
|
243
|
+
if (this.options.meta?.__raw) {
|
|
244
|
+
node.properties['data-meta'] = this.options.meta.__raw;
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
// Add line highlighting ({1,3-5} syntax) and line numbers support
|
|
249
|
+
// Note: This handles all meta string parsing with caching for performance
|
|
250
|
+
transformerLineFeatures(),
|
|
251
|
+
// NOTE: Notation transformers ([!code highlight], [!code focus], [!code ++/--])
|
|
252
|
+
// were removed for performance. Use {1,3-5} meta syntax for line highlighting.
|
|
253
|
+
// If notation support is needed, add createLazyNotationTransformer() here.
|
|
254
|
+
],
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Create a rehype plugin that uses a pre-existing Shiki highlighter.
|
|
260
|
+
* This is more efficient than the default rehypeShiki plugin which
|
|
261
|
+
* creates a new highlighter for each page render.
|
|
262
|
+
*
|
|
263
|
+
* @param highlighter - Pre-created highlighter from getHighlighter()
|
|
264
|
+
* @param config - Docs configuration for theme selection
|
|
265
|
+
* @returns A rehype plugin that can be used in MDXRemote options
|
|
266
|
+
*/
|
|
267
|
+
export function createShikiRehypePlugin(
|
|
268
|
+
highlighter: Highlighter,
|
|
269
|
+
config?: DocsConfig
|
|
270
|
+
): Pluggable {
|
|
271
|
+
const options = getShikiOptions(config) as RehypeShikiCoreOptions;
|
|
272
|
+
// Return a plugin function that creates the transformer
|
|
273
|
+
// This matches unified's expected plugin signature
|
|
274
|
+
return () => rehypeShikiFromHighlighter(highlighter, options);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Get themes array for preloading (excludes css-variables which is a ThemeRegistration)
|
|
279
|
+
*/
|
|
280
|
+
export function getThemesToLoad(config?: DocsConfig): SupportedTheme[] {
|
|
281
|
+
const { darkTheme, lightTheme } = parseCodeblocksConfig(config?.styling);
|
|
282
|
+
const themes = new Set<SupportedTheme>();
|
|
283
|
+
|
|
284
|
+
// Only add string themes (not ThemeRegistration objects like css-variables)
|
|
285
|
+
if (typeof darkTheme === 'string') themes.add(darkTheme);
|
|
286
|
+
if (typeof lightTheme === 'string') themes.add(lightTheme);
|
|
287
|
+
|
|
288
|
+
return Array.from(themes);
|
|
289
|
+
}
|