@ox-content/vite-plugin 2.87.0 → 2.89.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -1,3 +1,4 @@
1
+ import { a as JSXProps, c as jsxs, d as when, i as JSXNode, l as raw, n as JSXChild, o as each, r as JSXElementType, s as jsx, t as Fragment, u as renderToString } from "./jsx-html.cjs";
1
2
  import { EnvironmentOptions, Plugin } from "vite";
2
3
  import { LanguageRegistration, LanguageRegistration as LanguageRegistration$1, ThemeRegistration, ThemeRegistration as ThemeRegistration$1 } from "shiki";
3
4
  //#region src/theme-tokens.d.ts
@@ -567,218 +568,562 @@ interface TransformAllOptions {
567
568
  */
568
569
  declare function transformAllPlugins(html: string, options?: TransformAllOptions): Promise<string>;
569
570
  //#endregion
570
- //#region src/types.d.ts
571
+ //#region src/page-context.d.ts
571
572
  /**
572
- * Hero section action button.
573
+ * Base page props available for all pages.
573
574
  */
574
- interface HeroAction {
575
- /** Button theme: 'brand' (primary) or 'alt' (secondary) */
576
- theme?: "brand" | "alt";
577
- /** Button text */
578
- text: string;
579
- /** Link URL */
580
- link: string;
575
+ interface BasePageProps {
576
+ /** Page title from frontmatter or first heading */
577
+ title: string;
578
+ /** Page description from frontmatter */
579
+ description?: string;
580
+ /** Rendered HTML content */
581
+ html: string;
582
+ /** Table of contents entries */
583
+ toc: TocEntry[];
584
+ /** Last git commit timestamp in milliseconds */
585
+ lastUpdated?: number;
586
+ /** Source file path (relative to docs root) */
587
+ path: string;
588
+ /** Output URL path */
589
+ url: string;
590
+ /** Raw frontmatter object */
591
+ frontmatter: Record<string, unknown>;
592
+ /** Layout name from frontmatter */
593
+ layout?: string;
581
594
  }
582
595
  /**
583
- * Hero section image configuration.
596
+ * Extended page props with custom frontmatter.
584
597
  */
585
- interface HeroImage {
586
- /** Image source URL */
587
- src: string;
588
- /** Light mode image source URL */
589
- lightSrc?: string;
590
- /** Dark mode image source URL */
591
- darkSrc?: string;
592
- /** Alt text */
593
- alt?: string;
594
- /** Image width */
595
- width?: number;
596
- /** Image height */
597
- height?: number;
598
- }
598
+ type PageProps<T extends Record<string, unknown> = Record<string, unknown>> = BasePageProps & {
599
+ /** Custom frontmatter fields */
600
+ frontmatter: T & Record<string, unknown>;
601
+ };
599
602
  /**
600
- * Hero notice configuration.
603
+ * Site-wide configuration available in context.
601
604
  */
602
- interface HeroNotice {
603
- /** Notice title */
604
- title?: string;
605
- /** Notice paragraphs */
606
- body?: string[];
605
+ interface SiteConfig {
606
+ /** Site name */
607
+ name: string;
608
+ /** Base URL path */
609
+ base: string;
610
+ /** All pages in the site */
611
+ pages: BasePageProps[];
612
+ /** Navigation groups */
613
+ nav: NavGroup[];
607
614
  }
608
615
  /**
609
- * Hero section configuration for entry page.
616
+ * Navigation group.
610
617
  */
611
- interface HeroConfig {
612
- /** Main title (large, gradient text) */
613
- name?: string;
614
- /** Secondary text (medium size) */
615
- text?: string;
616
- /** Tagline (smaller, muted) */
617
- tagline?: string;
618
- /** Notice shown near the top of the hero */
619
- notice?: HeroNotice;
620
- /** Hero image */
621
- image?: HeroImage;
622
- /** Action buttons */
623
- actions?: HeroAction[];
618
+ interface NavGroup {
619
+ title: string;
620
+ items: NavItem[];
624
621
  }
625
622
  /**
626
- * Feature card for entry page.
623
+ * Navigation item.
627
624
  */
628
- interface FeatureConfig {
629
- /** Icon - supports: "mdi:icon-name" (Iconify), image URL, or emoji */
630
- icon?: string;
631
- /** Feature title */
625
+ interface NavItem {
632
626
  title: string;
633
- /** Feature description */
634
- details?: string;
635
- /** Optional link */
636
- link?: string;
637
- /** Link text */
638
- linkText?: string;
627
+ path: string;
628
+ href: string;
639
629
  }
640
630
  /**
641
- * Entry page frontmatter configuration.
631
+ * Complete render context.
642
632
  */
643
- interface EntryPageConfig {
644
- /** Layout type - set to 'entry' for entry page */
645
- layout: "entry";
646
- /** Hero section */
647
- hero?: HeroConfig;
648
- /** Feature cards */
649
- features?: FeatureConfig[];
633
+ interface RenderContext<T extends Record<string, unknown> = Record<string, unknown>> {
634
+ /** Current page props */
635
+ page: PageProps<T>;
636
+ /** Site configuration */
637
+ site: SiteConfig;
650
638
  }
651
639
  /**
652
- * Navigation item for SSG sidebar rendering.
640
+ * Sets the current render context.
641
+ * Called internally during page rendering.
642
+ * @internal
653
643
  */
654
- interface SsgNavigationItem {
655
- /** Display title */
656
- title: string;
657
- /**
658
- * Route path used for active-state matching.
659
- * Internal links should use site-relative paths such as `/getting-started`.
660
- */
661
- path?: string;
662
- /**
663
- * Final href used in the rendered HTML.
664
- * When omitted for internal links, ox-content derives it from `path`.
665
- */
666
- href?: string;
667
- }
644
+ declare function setRenderContext(ctx: RenderContext): void;
668
645
  /**
669
- * Navigation group for SSG sidebar rendering.
646
+ * Clears the current render context.
647
+ * Called internally after page rendering.
648
+ * @internal
670
649
  */
671
- interface SsgNavigationGroup {
672
- /** Group heading */
673
- title: string;
674
- /** Navigation items within this group */
675
- items: SsgNavigationItem[];
676
- }
650
+ declare function clearRenderContext(): void;
677
651
  /**
678
- * Static Site Generation options.
652
+ * Gets the current page props.
679
653
  *
680
- * These options control the HTML files emitted at build time and the matching
681
- * dev-server preview behavior. Pass `false` to the top-level `ssg` option to
682
- * disable the whole SSG pipeline, or pass an object to customize the defaults.
654
+ * @returns The current page props
655
+ * @throws Error if called outside of a render context
656
+ *
657
+ * @example
658
+ * ```tsx
659
+ * function PageTitle() {
660
+ * const page = usePageProps();
661
+ * return <h1>{page.title}</h1>;
662
+ * }
663
+ * ```
683
664
  */
684
- interface SsgOptions {
685
- /**
686
- * Enable the SSG pipeline.
687
- *
688
- * Keep this enabled when ox-content owns page rendering. Disable it only when
689
- * another framework integration will consume the Markdown modules directly.
690
- *
691
- * @default true
692
- */
693
- enabled?: boolean;
694
- /**
695
- * File extension used for generated routes.
696
- *
697
- * The value should include the leading dot. For example, `.html` emits
698
- * `guide.html`, while an empty string can be used by custom deployments that
699
- * map extensionless output themselves.
700
- *
701
- * @default '.html'
702
- */
703
- extension?: string;
704
- /**
705
- * Remove previously generated files from the output directory before writing
706
- * the new SSG result.
707
- *
708
- * Leave this disabled when the output directory also contains assets produced
709
- * by other Vite plugins or external build steps.
710
- *
711
- * @default false
712
- */
713
- clean?: boolean;
714
- /**
715
- * Emit bare HTML with only the rendered Markdown body.
716
- *
717
- * This skips the default navigation, layout shell, and theme styles. It is
718
- * mainly useful for benchmarking, fixture generation, or projects that wrap
719
- * the output in their own shell.
720
- *
721
- * @default false
722
- */
723
- bare?: boolean;
724
- /**
725
- * Site name shown in the default theme header and title suffix.
726
- *
727
- * When omitted, the renderer falls back to project metadata where available.
728
- *
729
- * @default undefined
730
- */
731
- siteName?: string;
732
- /**
733
- * Static Open Graph image URL used for social sharing.
734
- *
735
- * When `generateOgImage` is enabled, this value is still useful as a fallback
736
- * for pages that cannot produce a generated image.
737
- *
738
- * @default undefined
739
- */
740
- ogImage?: string;
741
- /**
742
- * Generate one Open Graph image per page.
743
- *
744
- * Generated images are written alongside the SSG output and referenced from
745
- * each page's metadata. Configure rendering details with the top-level
746
- * `ogImageOptions` option.
747
- *
748
- * @default false
749
- */
750
- generateOgImage?: boolean;
751
- /**
752
- * Add each page's last git commit timestamp to the default theme.
753
- * @default false
754
- */
755
- lastUpdated?: boolean;
756
- /**
757
- * Absolute site URL used when generating social metadata.
758
- *
759
- * Set this when pages need absolute Open Graph image URLs. Include the origin
760
- * and any deployment base path, without a trailing page path.
761
- *
762
- * @example
763
- * ```ts
764
- * siteUrl: 'https://example.com/docs'
765
- * ```
766
- *
767
- * @default undefined
768
- */
769
- siteUrl?: string;
770
- /**
771
- * Theme configuration for generated pages.
772
- *
773
- * Use `defineTheme()` to build this object so custom theme modules and the
774
- * default theme extension points keep their expected shape.
775
- *
776
- * An array composes layers left to right, which is how a skin package and a
777
- * color package are combined:
778
- *
779
- * ```ts
780
- * theme: [pixelSkin, tokyoNight, { footer: { copyright: "2026" } }]
781
- * ```
665
+ declare function usePageProps<T extends Record<string, unknown> = Record<string, unknown>>(): PageProps<T>;
666
+ /**
667
+ * Gets the site configuration.
668
+ *
669
+ * @returns The site configuration
670
+ * @throws Error if called outside of a render context
671
+ *
672
+ * @example
673
+ * ```tsx
674
+ * function SiteHeader() {
675
+ * const site = useSiteConfig();
676
+ * return <header>{site.name}</header>;
677
+ * }
678
+ * ```
679
+ */
680
+ declare function useSiteConfig(): SiteConfig;
681
+ /**
682
+ * Gets the full render context.
683
+ *
684
+ * @returns The complete render context
685
+ * @throws Error if called outside of a render context
686
+ *
687
+ * @example
688
+ * ```tsx
689
+ * function Layout({ children }) {
690
+ * const ctx = useRenderContext();
691
+ * return (
692
+ * <html>
693
+ * <head><title>{ctx.page.title} - {ctx.site.name}</title></head>
694
+ * <body>{children}</body>
695
+ * </html>
696
+ * );
697
+ * }
698
+ * ```
699
+ */
700
+ declare function useRenderContext<T extends Record<string, unknown> = Record<string, unknown>>(): RenderContext<T>;
701
+ /**
702
+ * Gets the navigation groups.
703
+ *
704
+ * @example
705
+ * ```tsx
706
+ * function Sidebar() {
707
+ * const nav = useNav();
708
+ * return (
709
+ * <nav>
710
+ * {each(nav, (group) => (
711
+ * <div>
712
+ * <h3>{group.title}</h3>
713
+ * <ul>
714
+ * {each(group.items, (item) => (
715
+ * <li><a href={item.href}>{item.title}</a></li>
716
+ * ))}
717
+ * </ul>
718
+ * </div>
719
+ * ))}
720
+ * </nav>
721
+ * );
722
+ * }
723
+ * ```
724
+ */
725
+ declare function useNav(): NavGroup[];
726
+ /**
727
+ * Checks if the given path is the current page.
728
+ *
729
+ * @example
730
+ * ```tsx
731
+ * function NavLink({ href, children }) {
732
+ * const isActive = useIsActive(href);
733
+ * return <a href={href} class={isActive ? 'active' : ''}>{children}</a>;
734
+ * }
735
+ * ```
736
+ */
737
+ declare function useIsActive(path: string): boolean;
738
+ /**
739
+ * Schema for frontmatter type generation.
740
+ */
741
+ interface FrontmatterSchema {
742
+ /** Field name */
743
+ name: string;
744
+ /** TypeScript type */
745
+ type: string;
746
+ /** Whether the field is optional */
747
+ optional: boolean;
748
+ /** JSDoc description */
749
+ description?: string;
750
+ }
751
+ /**
752
+ * Infers TypeScript types from frontmatter values.
753
+ */
754
+ declare function inferType(value: unknown): string;
755
+ /**
756
+ * Generates TypeScript interface from frontmatter samples.
757
+ */
758
+ declare function generateFrontmatterTypes(samples: Record<string, unknown>[], interfaceName?: string): string;
759
+ //#endregion
760
+ //#region src/theme-renderer.d.ts
761
+ /**
762
+ * Theme component type.
763
+ */
764
+ type ThemeComponent = (props: ThemeProps) => JSXNode;
765
+ /**
766
+ * Props passed to the theme component.
767
+ */
768
+ interface ThemeProps {
769
+ /** Rendered page content as JSX */
770
+ children: JSXNode;
771
+ }
772
+ /**
773
+ * Page data for rendering.
774
+ */
775
+ interface PageData {
776
+ /** Page title */
777
+ title: string;
778
+ /** Page description */
779
+ description?: string;
780
+ /** Rendered HTML content */
781
+ html: string;
782
+ /** Table of contents */
783
+ toc: TocEntry[];
784
+ /** Last git commit timestamp in milliseconds */
785
+ lastUpdated?: number;
786
+ /** Source file path */
787
+ path: string;
788
+ /** Output URL path */
789
+ url: string;
790
+ /** Frontmatter */
791
+ frontmatter: Record<string, unknown>;
792
+ /** Layout name */
793
+ layout?: string;
794
+ }
795
+ /**
796
+ * Theme render options.
797
+ */
798
+ interface ThemeRenderOptions {
799
+ /** Theme component to use */
800
+ theme: ThemeComponent;
801
+ /** Site name */
802
+ siteName: string;
803
+ /** Base URL path */
804
+ base: string;
805
+ /** Navigation groups */
806
+ nav: NavGroup[];
807
+ /** All pages (for site context) */
808
+ pages: PageData[];
809
+ /** Output directory for type definitions */
810
+ typesOutDir?: string;
811
+ }
812
+ /**
813
+ * Renders a page using the theme component.
814
+ *
815
+ * @param page - Page data to render
816
+ * @param options - Theme render options
817
+ * @returns Rendered HTML string
818
+ */
819
+ declare function renderPage(page: PageData, options: ThemeRenderOptions): string;
820
+ /**
821
+ * Renders all pages and generates type definitions.
822
+ *
823
+ * @param pages - All pages to render
824
+ * @param options - Theme render options
825
+ * @returns Map of output paths to rendered HTML
826
+ */
827
+ declare function renderAllPages(pages: PageData[], options: ThemeRenderOptions): Promise<Map<string, string>>;
828
+ /**
829
+ * Generates TypeScript type definitions from page frontmatter.
830
+ *
831
+ * @param pages - All pages
832
+ * @param outDir - Output directory for types
833
+ */
834
+ declare function generateTypes(pages: PageData[], outDir: string): Promise<void>;
835
+ /**
836
+ * Default theme component.
837
+ * A minimal theme that renders page content with basic styling.
838
+ */
839
+ declare function DefaultTheme({ children }: ThemeProps): JSXNode;
840
+ /**
841
+ * Creates a theme with layout switching support.
842
+ *
843
+ * @example
844
+ * ```tsx
845
+ * import { createTheme } from '@ox-content/vite-plugin';
846
+ * import { DefaultLayout } from './layouts/Default';
847
+ * import { EntryLayout } from './layouts/Entry';
848
+ *
849
+ * export default createTheme({
850
+ * layouts: {
851
+ * default: DefaultLayout,
852
+ * entry: EntryLayout,
853
+ * },
854
+ * });
855
+ * ```
856
+ */
857
+ declare function createTheme(config: {
858
+ layouts: Record<string, ThemeComponent>;
859
+ defaultLayout?: string;
860
+ }): ThemeComponent;
861
+ //#endregion
862
+ //#region src/types.d.ts
863
+ /**
864
+ * Hero section action button.
865
+ */
866
+ interface HeroAction {
867
+ /** Button theme: 'brand' (primary) or 'alt' (secondary) */
868
+ theme?: "brand" | "alt";
869
+ /** Button text */
870
+ text: string;
871
+ /** Link URL */
872
+ link: string;
873
+ }
874
+ /**
875
+ * Hero section image configuration.
876
+ */
877
+ interface HeroImage {
878
+ /** Image source URL */
879
+ src: string;
880
+ /** Light mode image source URL */
881
+ lightSrc?: string;
882
+ /** Dark mode image source URL */
883
+ darkSrc?: string;
884
+ /** Alt text */
885
+ alt?: string;
886
+ /** Image width */
887
+ width?: number;
888
+ /** Image height */
889
+ height?: number;
890
+ }
891
+ /**
892
+ * Hero notice configuration.
893
+ */
894
+ interface HeroNotice {
895
+ /** Notice title */
896
+ title?: string;
897
+ /** Notice paragraphs */
898
+ body?: string[];
899
+ }
900
+ /**
901
+ * Hero section configuration for entry page.
902
+ */
903
+ interface HeroConfig {
904
+ /** Main title (large, gradient text) */
905
+ name?: string;
906
+ /** Secondary text (medium size) */
907
+ text?: string;
908
+ /** Tagline (smaller, muted) */
909
+ tagline?: string;
910
+ /** Notice shown near the top of the hero */
911
+ notice?: HeroNotice;
912
+ /** Hero image */
913
+ image?: HeroImage;
914
+ /** Action buttons */
915
+ actions?: HeroAction[];
916
+ }
917
+ /**
918
+ * Feature card for entry page.
919
+ */
920
+ interface FeatureConfig {
921
+ /** Icon - supports: "mdi:icon-name" (Iconify), image URL, or emoji */
922
+ icon?: string;
923
+ /** Feature title */
924
+ title: string;
925
+ /** Feature description */
926
+ details?: string;
927
+ /** Optional link */
928
+ link?: string;
929
+ /** Link text */
930
+ linkText?: string;
931
+ }
932
+ /**
933
+ * Entry page frontmatter configuration.
934
+ */
935
+ interface EntryPageConfig {
936
+ /** Layout type - set to 'entry' for entry page */
937
+ layout: "entry";
938
+ /** Hero section */
939
+ hero?: HeroConfig;
940
+ /** Feature cards */
941
+ features?: FeatureConfig[];
942
+ }
943
+ /**
944
+ * Navigation item for SSG sidebar rendering.
945
+ */
946
+ interface SsgNavigationItem {
947
+ /** Display title */
948
+ title: string;
949
+ /**
950
+ * Route path used for active-state matching.
951
+ * Internal links should use site-relative paths such as `/getting-started`.
952
+ */
953
+ path?: string;
954
+ /**
955
+ * Final href used in the rendered HTML.
956
+ * When omitted for internal links, ox-content derives it from `path`.
957
+ */
958
+ href?: string;
959
+ }
960
+ /**
961
+ * Navigation group for SSG sidebar rendering.
962
+ */
963
+ interface SsgNavigationGroup {
964
+ /** Group heading */
965
+ title: string;
966
+ /** Navigation items within this group */
967
+ items: SsgNavigationItem[];
968
+ }
969
+ /**
970
+ * Static Site Generation options.
971
+ *
972
+ * These options control the HTML files emitted at build time and the matching
973
+ * dev-server preview behavior. Pass `false` to the top-level `ssg` option to
974
+ * disable the whole SSG pipeline, or pass an object to customize the defaults.
975
+ */
976
+ interface SsgOptions {
977
+ /**
978
+ * Enable the SSG pipeline.
979
+ *
980
+ * Keep this enabled when ox-content owns page rendering. Disable it only when
981
+ * another framework integration will consume the Markdown modules directly.
982
+ *
983
+ * @default true
984
+ */
985
+ enabled?: boolean;
986
+ /**
987
+ * File extension used for generated routes.
988
+ *
989
+ * The value should include the leading dot. For example, `.html` emits
990
+ * `guide.html`, while an empty string can be used by custom deployments that
991
+ * map extensionless output themselves.
992
+ *
993
+ * @default '.html'
994
+ */
995
+ extension?: string;
996
+ /**
997
+ * Remove previously generated files from the output directory before writing
998
+ * the new SSG result.
999
+ *
1000
+ * Leave this disabled when the output directory also contains assets produced
1001
+ * by other Vite plugins or external build steps.
1002
+ *
1003
+ * @default false
1004
+ */
1005
+ clean?: boolean;
1006
+ /**
1007
+ * Emit bare HTML with only the rendered Markdown body.
1008
+ *
1009
+ * This skips the default navigation, layout shell, and theme styles. It is
1010
+ * mainly useful for benchmarking, fixture generation, or projects that wrap
1011
+ * the output in their own shell.
1012
+ *
1013
+ * @default false
1014
+ */
1015
+ bare?: boolean;
1016
+ /**
1017
+ * Site name shown in the default theme header and title suffix.
1018
+ *
1019
+ * When omitted, the renderer falls back to project metadata where available.
1020
+ *
1021
+ * @default undefined
1022
+ */
1023
+ siteName?: string;
1024
+ /**
1025
+ * Static Open Graph image URL used for social sharing.
1026
+ *
1027
+ * When `generateOgImage` is enabled, this value is still useful as a fallback
1028
+ * for pages that cannot produce a generated image.
1029
+ *
1030
+ * @default undefined
1031
+ */
1032
+ ogImage?: string;
1033
+ /**
1034
+ * Render each page with a JSX theme component instead of the built-in
1035
+ * renderer.
1036
+ *
1037
+ * The component owns the whole document, so `theme`, `bare` and the head
1038
+ * metadata options do not apply — everything from `<html>` down is yours.
1039
+ * Compose one per layout with `createTheme()`, and read the current page
1040
+ * through `usePageProps()` / `useSiteConfig()`.
1041
+ *
1042
+ * ```ts
1043
+ * ssg: { render: createTheme({ layouts: { default: DefaultLayout } }) }
1044
+ * ```
1045
+ *
1046
+ * @default undefined
1047
+ */
1048
+ render?: ThemeComponent;
1049
+ /**
1050
+ * `lang` attribute for the generated `<html>` element.
1051
+ *
1052
+ * Bare mode uses this verbatim; themed pages derive it from `i18n` instead.
1053
+ *
1054
+ * @default "en"
1055
+ */
1056
+ lang?: string;
1057
+ /**
1058
+ * Raw markup appended to `<head>`.
1059
+ *
1060
+ * Bare mode only — themed pages own their head. Use it for the stylesheet
1061
+ * your own build emits, or any tag the plugin does not generate.
1062
+ *
1063
+ * @default undefined
1064
+ */
1065
+ head?: string;
1066
+ /**
1067
+ * Raw markup inserted directly after `<body>`.
1068
+ *
1069
+ * Bare mode only. Use it for a site header that wraps the rendered page.
1070
+ *
1071
+ * @default undefined
1072
+ */
1073
+ bodyStart?: string;
1074
+ /**
1075
+ * Raw markup inserted directly before `</body>`.
1076
+ *
1077
+ * Bare mode only. Use it for a site footer, or scripts you inject yourself.
1078
+ *
1079
+ * @default undefined
1080
+ */
1081
+ bodyEnd?: string;
1082
+ /**
1083
+ * Generate one Open Graph image per page.
1084
+ *
1085
+ * Generated images are written alongside the SSG output and referenced from
1086
+ * each page's metadata. Configure rendering details with the top-level
1087
+ * `ogImageOptions` option.
1088
+ *
1089
+ * Under `bare`, the images are still written but nothing references them,
1090
+ * because bare output has no `<head>` to put the `<meta>` tags in — inject
1091
+ * them from your own shell.
1092
+ *
1093
+ * @default false
1094
+ */
1095
+ generateOgImage?: boolean;
1096
+ /**
1097
+ * Add each page's last git commit timestamp to the default theme.
1098
+ * @default false
1099
+ */
1100
+ lastUpdated?: boolean;
1101
+ /**
1102
+ * Absolute site URL used when generating social metadata.
1103
+ *
1104
+ * Set this when pages need absolute Open Graph image URLs. Include the origin
1105
+ * and any deployment base path, without a trailing page path.
1106
+ *
1107
+ * @example
1108
+ * ```ts
1109
+ * siteUrl: 'https://example.com/docs'
1110
+ * ```
1111
+ *
1112
+ * @default undefined
1113
+ */
1114
+ siteUrl?: string;
1115
+ /**
1116
+ * Theme configuration for generated pages.
1117
+ *
1118
+ * Use `defineTheme()` to build this object so custom theme modules and the
1119
+ * default theme extension points keep their expected shape.
1120
+ *
1121
+ * An array composes layers left to right, which is how a skin package and a
1122
+ * color package are combined:
1123
+ *
1124
+ * ```ts
1125
+ * theme: [pixelSkin, tokyoNight, { footer: { copyright: "2026" } }]
1126
+ * ```
782
1127
  *
783
1128
  * @default defaultTheme
784
1129
  */
@@ -802,6 +1147,11 @@ interface ResolvedSsgOptions {
802
1147
  extension: string;
803
1148
  clean: boolean;
804
1149
  bare: boolean;
1150
+ render?: ThemeComponent;
1151
+ lang?: string;
1152
+ head?: string;
1153
+ bodyStart?: string;
1154
+ bodyEnd?: string;
805
1155
  siteName?: string;
806
1156
  ogImage?: string;
807
1157
  generateOgImage: boolean;
@@ -3135,754 +3485,378 @@ interface MarkdownLintStandardDictionaryOptions {
3135
3485
  *
3136
3486
  * @default new URL(".", import.meta.url)
3137
3487
  */
3138
- resolveImportsRelativeTo?: string | URL;
3139
- }
3140
- /**
3141
- * Additional dictionary configuration for the Markdown linter.
3142
- */
3143
- interface MarkdownLintDictionaryOptions {
3144
- /**
3145
- * Words ignored across all configured languages.
3146
- * @default []
3147
- */
3148
- words?: string[];
3149
- /**
3150
- * Extra words to allow per language.
3151
- * @default {}
3152
- */
3153
- byLanguage?: Partial<Record<MarkdownLintLanguage, string[]>>;
3154
- /**
3155
- * Words that should never produce diagnostics.
3156
- * @default []
3157
- */
3158
- ignoredWords?: string[];
3159
- /**
3160
- * Opt-in standard dictionary datasets.
3161
- *
3162
- * By default the linter stays on a minimal built-in dictionary. Enable this
3163
- * to load larger locale dictionaries from a standard external source.
3164
- * @default false
3165
- */
3166
- standard?: MarkdownLintStandardDictionaryOptions | false;
3167
- }
3168
- /**
3169
- * Rule switches for Markdown linting.
3170
- */
3171
- interface MarkdownLintRuleOptions {
3172
- /**
3173
- * Report headings that repeat the same visible text.
3174
- * @default true
3175
- */
3176
- duplicateHeadings?: boolean;
3177
- /**
3178
- * Report heading depth jumps such as `#` -> `###`.
3179
- * @default true
3180
- */
3181
- headingIncrement?: boolean;
3182
- /**
3183
- * Maximum number of blank lines allowed in a row.
3184
- * @default 1
3185
- */
3186
- maxConsecutiveBlankLines?: number;
3187
- /**
3188
- * Report duplicated terminal punctuation such as `!!` or `??`.
3189
- * @default true
3190
- */
3191
- repeatedPunctuation?: boolean;
3192
- /**
3193
- * Report adjacent repeated words in visible prose.
3194
- * @default true
3195
- */
3196
- repeatedWords?: boolean;
3197
- /**
3198
- * Enable built-in multilingual spellchecking.
3199
- * @default true
3200
- */
3201
- spellcheck?: boolean;
3202
- /**
3203
- * Report trailing spaces.
3204
- * @default true
3205
- */
3206
- trailingSpaces?: boolean;
3207
- }
3208
- /**
3209
- * Options for linting Markdown documents.
3210
- */
3211
- interface MarkdownLintOptions {
3212
- /**
3213
- * Languages enabled for spellchecking.
3214
- *
3215
- * When `dictionary.standard.languages` is provided and this option is
3216
- * omitted, those languages are used instead.
3217
- *
3218
- * @default ['en']
3219
- */
3220
- languages?: MarkdownLintLanguage[];
3221
- /**
3222
- * Rule configuration.
3223
- * Omitted fields use `MarkdownLintRuleOptions` defaults.
3224
- * @default {}
3225
- */
3226
- rules?: MarkdownLintRuleOptions;
3227
- /**
3228
- * Built-in and opt-in standard dictionary overrides.
3229
- * @default {}
3230
- */
3231
- dictionary?: MarkdownLintDictionaryOptions;
3232
- }
3233
- /**
3234
- * A single Markdown lint diagnostic.
3235
- */
3236
- interface MarkdownLintDiagnostic {
3237
- /**
3238
- * Stable rule identifier.
3239
- */
3240
- ruleId: string;
3241
- /**
3242
- * Diagnostic severity.
3243
- */
3244
- severity: MarkdownLintSeverity;
3245
- /**
3246
- * Human-readable explanation.
3247
- */
3248
- message: string;
3249
- /**
3250
- * 1-indexed line number.
3251
- */
3252
- line: number;
3253
- /**
3254
- * 1-indexed start column.
3255
- */
3256
- column: number;
3257
- /**
3258
- * 1-indexed end line.
3259
- */
3260
- endLine: number;
3261
- /**
3262
- * 1-indexed end column.
3263
- */
3264
- endColumn: number;
3265
- /**
3266
- * Language used for spellchecking, when relevant.
3267
- */
3268
- language?: MarkdownLintLanguage;
3269
- /**
3270
- * Suggested replacements, when available.
3271
- */
3272
- suggestions?: string[];
3488
+ resolveImportsRelativeTo?: string | URL;
3273
3489
  }
3274
3490
  /**
3275
- * Markdown lint report.
3491
+ * Additional dictionary configuration for the Markdown linter.
3276
3492
  */
3277
- interface MarkdownLintResult {
3493
+ interface MarkdownLintDictionaryOptions {
3278
3494
  /**
3279
- * All collected diagnostics.
3495
+ * Words ignored across all configured languages.
3496
+ * @default []
3280
3497
  */
3281
- diagnostics: MarkdownLintDiagnostic[];
3498
+ words?: string[];
3282
3499
  /**
3283
- * Number of error diagnostics.
3500
+ * Extra words to allow per language.
3501
+ * @default {}
3284
3502
  */
3285
- errorCount: number;
3503
+ byLanguage?: Partial<Record<MarkdownLintLanguage, string[]>>;
3286
3504
  /**
3287
- * Number of warning diagnostics.
3505
+ * Words that should never produce diagnostics.
3506
+ * @default []
3288
3507
  */
3289
- warningCount: number;
3508
+ ignoredWords?: string[];
3290
3509
  /**
3291
- * Number of info diagnostics.
3510
+ * Opt-in standard dictionary datasets.
3511
+ *
3512
+ * By default the linter stays on a minimal built-in dictionary. Enable this
3513
+ * to load larger locale dictionaries from a standard external source.
3514
+ * @default false
3292
3515
  */
3293
- infoCount: number;
3516
+ standard?: MarkdownLintStandardDictionaryOptions | false;
3294
3517
  }
3295
3518
  /**
3296
- * Lints Markdown prose with the Rust-backed built-in rule engine.
3297
- */
3298
- declare function lintMarkdown(source: string, options?: MarkdownLintOptions): MarkdownLintResult;
3299
- /**
3300
- * Async Markdown linter that supports opt-in standard dictionaries.
3301
- */
3302
- declare function lintMarkdownAsync(source: string, options?: MarkdownLintOptions): Promise<MarkdownLintResult>;
3303
- //#endregion
3304
- //#region src/lint-files.d.ts
3305
- /**
3306
- * File-oriented Markdown lint options for end-user configuration.
3307
- *
3308
- * This extends the content-level lint options with project-level targeting,
3309
- * so consumers can decide which files should be checked and which paths should
3310
- * be ignored.
3519
+ * Rule switches for Markdown linting.
3311
3520
  */
3312
- interface MarkdownLintFileOptions extends MarkdownLintOptions {
3521
+ interface MarkdownLintRuleOptions {
3313
3522
  /**
3314
- * Base directory used to resolve `include` and `exclude` patterns.
3315
- * @default process.cwd()
3523
+ * Report headings that repeat the same visible text.
3524
+ * @default true
3316
3525
  */
3317
- cwd?: string;
3526
+ duplicateHeadings?: boolean;
3318
3527
  /**
3319
- * Glob patterns for files to lint.
3320
- * @default ['**\/*.md', '**\/*.markdown', '**\/*.mdx']
3528
+ * Report heading depth jumps such as `#` -> `###`.
3529
+ * @default true
3321
3530
  */
3322
- include?: string[];
3531
+ headingIncrement?: boolean;
3323
3532
  /**
3324
- * Glob patterns for files to exclude from linting.
3325
- * @default ['**\/node_modules/**', '**\/.git/**', '**\/dist/**']
3533
+ * Maximum number of blank lines allowed in a row.
3534
+ * @default 1
3326
3535
  */
3327
- exclude?: string[];
3536
+ maxConsecutiveBlankLines?: number;
3328
3537
  /**
3329
- * Alias of `exclude`.
3330
- * When omitted, only `exclude` is used.
3331
- * @default undefined
3538
+ * Report duplicated terminal punctuation such as `!!` or `??`.
3539
+ * @default true
3332
3540
  */
3333
- ignore?: string[];
3334
- }
3335
- /**
3336
- * A lint diagnostic annotated with file metadata.
3337
- */
3338
- interface MarkdownLintFileDiagnostic extends MarkdownLintDiagnostic {
3339
- filePath: string;
3340
- relativePath: string;
3341
- }
3342
- /**
3343
- * Lint result for a single file.
3344
- */
3345
- interface MarkdownLintFileResult extends MarkdownLintResult {
3346
- filePath: string;
3347
- relativePath: string;
3348
- skipped: boolean;
3349
- }
3350
- /**
3351
- * Aggregated lint result for multiple files.
3352
- */
3353
- interface MarkdownLintFilesResult {
3354
- checkedFileCount: number;
3355
- diagnostics: MarkdownLintFileDiagnostic[];
3356
- errorCount: number;
3357
- files: MarkdownLintFileResult[];
3358
- infoCount: number;
3359
- warningCount: number;
3360
- }
3361
- /**
3362
- * Returns true if the file path is included by the configured glob filters.
3363
- */
3364
- declare function shouldLintMarkdownFile(filePath: string, options?: MarkdownLintFileOptions): boolean;
3365
- /**
3366
- * Lints a single Markdown file using project-style include/exclude settings.
3367
- *
3368
- * If the file is filtered out by `include` / `exclude`, the returned result is
3369
- * marked as `skipped` and contains no diagnostics.
3370
- */
3371
- declare function lintMarkdownFile(filePath: string, options?: MarkdownLintFileOptions): Promise<MarkdownLintFileResult>;
3372
- /**
3373
- * Lints all Markdown files matched by the configured include/exclude patterns.
3374
- */
3375
- declare function lintMarkdownFiles(options?: MarkdownLintFileOptions): Promise<MarkdownLintFilesResult>;
3376
- //#endregion
3377
- //#region src/ssg.d.ts
3378
- /**
3379
- * Deprecated compatibility export for consumers that imported the former
3380
- * TypeScript SSG template. HTML generation is Rust-backed now.
3381
- *
3382
- * @deprecated Use `generateHtmlPage`/`buildSsg` instead.
3383
- */
3384
- declare const DEFAULT_HTML_TEMPLATE = "<!-- ox-content default HTML template is Rust-backed -->";
3385
- /**
3386
- * Resolves SSG options with defaults.
3387
- */
3388
- declare function resolveSsgOptions(ssg: SsgOptions | boolean | undefined): ResolvedSsgOptions;
3389
- /**
3390
- * Builds all markdown files to static HTML.
3391
- */
3392
- declare function buildSsg(options: ResolvedOptions, root: string): Promise<{
3393
- files: string[];
3394
- errors: string[];
3395
- }>;
3396
- //#endregion
3397
- //#region src/search.d.ts
3398
- /**
3399
- * Resolves search options with defaults.
3400
- */
3401
- declare function resolveSearchOptions(options: SearchOptions | boolean | undefined): ResolvedSearchOptions;
3402
- /**
3403
- * Builds the search index from Markdown files.
3404
- */
3405
- declare function buildSearchIndex(srcDir: string, base: string, extensions?: readonly string[]): Promise<string>;
3406
- /**
3407
- * Writes the search index to a file.
3408
- */
3409
- declare function writeSearchIndex(indexJson: string, outDir: string): Promise<void>;
3410
- //#endregion
3411
- //#region src/collections.d.ts
3412
- declare function defineCollection<T extends CollectionOptions>(collection: T): T;
3413
- declare function defineCollections<T extends CollectionsOptions>(collections: T): T;
3414
- declare function resolveCollectionsOptions(options: CollectionsOptions | boolean | undefined): ResolvedCollectionsOptions;
3415
- declare function buildCollectionManifest(root: string, options: ResolvedOptions): Promise<CollectionManifest>;
3416
- declare function generateCollectionsVirtualModule(root: string, options: ResolvedOptions): Promise<string>;
3417
- //#endregion
3418
- //#region src/markdown.d.ts
3419
- declare const DEFAULT_MARKDOWN_EXTENSIONS: readonly [".md", ".markdown", ".mdx"];
3420
- declare function normalizeMarkdownExtensions(extensions?: readonly string[]): string[];
3421
- declare function isMarkdownFilePath(filePath: string, extensions?: readonly string[]): boolean;
3422
- declare function stripMarkdownExtension(filePath: string, extensions?: readonly string[]): string;
3423
- //#endregion
3424
- //#region src/vitepress.d.ts
3425
- interface VitePressLogo {
3426
- light?: string;
3427
- dark?: string;
3428
- src?: string;
3429
- alt?: string;
3430
- }
3431
- interface VitePressSocialLink {
3432
- icon: string;
3433
- link: string;
3434
- ariaLabel?: string;
3435
- }
3436
- interface VitePressFooter {
3437
- message?: string;
3438
- copyright?: string;
3439
- }
3440
- interface VitePressSidebarItem {
3441
- text?: string;
3442
- link?: string;
3443
- items?: VitePressSidebarItem[];
3444
- collapsed?: boolean;
3445
- }
3446
- type VitePressSidebar = VitePressSidebarItem[] | Record<string, VitePressSidebarItem[]>;
3447
- interface VitePressNavItem {
3448
- text?: string;
3449
- link?: string;
3450
- items?: VitePressNavItem[];
3451
- activeMatch?: string;
3452
- }
3453
- interface VitePressThemeConfig {
3454
- siteTitle?: string | false;
3455
- logo?: string | VitePressLogo;
3456
- nav?: VitePressNavItem[];
3457
- sidebar?: VitePressSidebar;
3458
- socialLinks?: VitePressSocialLink[];
3459
- footer?: VitePressFooter;
3460
- search?: {
3461
- placeholder?: string;
3462
- };
3463
- }
3464
- interface VitePressConfig {
3465
- title?: string;
3466
- description?: string;
3467
- base?: string;
3468
- themeConfig?: VitePressThemeConfig;
3469
- }
3470
- interface GenerateVitePressMigrationConfigOptions {
3471
- importSource?: string;
3472
- }
3473
- /**
3474
- * Converts a VitePress sidebar config into ox-content navigation groups.
3475
- * Nested VitePress items are flattened into the nearest ox-content group.
3476
- */
3477
- declare function convertVitePressSidebar(sidebar: VitePressSidebar): SsgNavigationGroup[];
3478
- /**
3479
- * Converts VitePress top navigation into ox-content sidebar groups.
3480
- * This is used as a fallback when no explicit sidebar is defined.
3481
- */
3482
- declare function convertVitePressNav(nav: VitePressNavItem[]): SsgNavigationGroup[];
3483
- /**
3484
- * Creates ox-content plugin options from an existing VitePress config.
3485
- */
3486
- declare function fromVitePressConfig(config: VitePressConfig, overrides?: OxContentOptions): OxContentOptions;
3487
- /**
3488
- * Generates a TypeScript module exporting migrated ox-content options.
3489
- *
3490
- * This is used by the migration CLI so users can inspect and edit the resulting
3491
- * object instead of keeping a runtime dependency on their VitePress config.
3492
- */
3493
- declare function generateVitePressMigrationConfig(config: VitePressConfig, overrides?: OxContentOptions, options?: GenerateVitePressMigrationConfigOptions): string;
3494
- /**
3495
- * Normalizes VitePress-specific frontmatter into ox-content's entry-page shape.
3496
- */
3497
- declare function normalizeVitePressFrontmatter(frontmatter: Record<string, unknown>): Record<string, unknown>;
3498
- //#endregion
3499
- //#region src/jsx-runtime.d.ts
3500
- /**
3501
- * Custom JSX Runtime for Static HTML Generation
3502
- *
3503
- * This module provides a JSX runtime that outputs static HTML strings.
3504
- * No React, no hydration, no client-side JavaScript - just pure HTML.
3505
- *
3506
- * @example
3507
- * ```tsx
3508
- * // tsconfig.json or vite.config.ts
3509
- * {
3510
- * "compilerOptions": {
3511
- * "jsx": "react-jsx",
3512
- * "jsxImportSource": "@ox-content/vite-plugin"
3513
- * }
3514
- * }
3515
- *
3516
- * // MyComponent.tsx
3517
- * export function Hero({ title }: { title: string }) {
3518
- * return (
3519
- * <section class="hero">
3520
- * <h1>{title}</h1>
3521
- * </section>
3522
- * );
3523
- * }
3524
- * ```
3525
- */
3526
- /**
3527
- * JSX element type - either a string (intrinsic) or a function component.
3528
- */
3529
- type JSXElementType = string | ((props: Record<string, unknown>) => JSXNode);
3530
- /**
3531
- * Valid JSX child types.
3532
- */
3533
- type JSXChild = string | number | boolean | null | undefined | JSXNode | JSXChild[];
3534
- /**
3535
- * JSX node - the result of JSX expressions.
3536
- */
3537
- interface JSXNode {
3538
- __html: string;
3541
+ repeatedPunctuation?: boolean;
3542
+ /**
3543
+ * Report adjacent repeated words in visible prose.
3544
+ * @default true
3545
+ */
3546
+ repeatedWords?: boolean;
3547
+ /**
3548
+ * Enable built-in multilingual spellchecking.
3549
+ * @default true
3550
+ */
3551
+ spellcheck?: boolean;
3552
+ /**
3553
+ * Report trailing spaces.
3554
+ * @default true
3555
+ */
3556
+ trailingSpaces?: boolean;
3539
3557
  }
3540
3558
  /**
3541
- * Props with children.
3559
+ * Options for linting Markdown documents.
3542
3560
  */
3543
- interface JSXProps {
3544
- children?: JSXChild;
3545
- [key: string]: unknown;
3561
+ interface MarkdownLintOptions {
3562
+ /**
3563
+ * Languages enabled for spellchecking.
3564
+ *
3565
+ * When `dictionary.standard.languages` is provided and this option is
3566
+ * omitted, those languages are used instead.
3567
+ *
3568
+ * @default ['en']
3569
+ */
3570
+ languages?: MarkdownLintLanguage[];
3571
+ /**
3572
+ * Rule configuration.
3573
+ * Omitted fields use `MarkdownLintRuleOptions` defaults.
3574
+ * @default {}
3575
+ */
3576
+ rules?: MarkdownLintRuleOptions;
3577
+ /**
3578
+ * Built-in and opt-in standard dictionary overrides.
3579
+ * @default {}
3580
+ */
3581
+ dictionary?: MarkdownLintDictionaryOptions;
3546
3582
  }
3547
3583
  /**
3548
- * Creates a JSX element.
3549
- * This is the core function called by the JSX transform.
3550
- */
3551
- declare function jsx(type: JSXElementType, props: JSXProps, _key?: string): JSXNode;
3552
- /**
3553
- * Creates a JSX element with static children.
3554
- * Called by the JSX transform for elements with multiple children.
3555
- */
3556
- declare function jsxs(type: JSXElementType, props: JSXProps, key?: string): JSXNode;
3557
- /**
3558
- * Fragment component - renders children without a wrapper element.
3559
- */
3560
- declare function Fragment({ children }: {
3561
- children?: JSXChild;
3562
- }): JSXNode;
3563
- /**
3564
- * Renders a JSX node to an HTML string.
3565
- */
3566
- declare function renderToString(node: JSXNode): string;
3567
- /**
3568
- * Creates raw HTML without escaping.
3569
- * Use with caution - only for trusted content.
3570
- *
3571
- * @example
3572
- * ```tsx
3573
- * <div>{raw('<strong>Bold</strong>')}</div>
3574
- * ```
3575
- */
3576
- declare function raw(html: string): JSXNode;
3577
- /**
3578
- * Conditionally renders content.
3579
- *
3580
- * @example
3581
- * ```tsx
3582
- * {when(isLoggedIn, <UserMenu />)}
3583
- * ```
3584
- */
3585
- declare function when(condition: boolean, content: JSXNode): JSXNode;
3586
- /**
3587
- * Maps over an array and renders each item.
3588
- *
3589
- * @example
3590
- * ```tsx
3591
- * {each(items, (item) => <li>{item.name}</li>)}
3592
- * ```
3584
+ * A single Markdown lint diagnostic.
3593
3585
  */
3594
- declare function each<T>(items: T[], render: (item: T, index: number) => JSXNode): JSXNode;
3595
- //#endregion
3596
- //#region src/page-context.d.ts
3586
+ interface MarkdownLintDiagnostic {
3587
+ /**
3588
+ * Stable rule identifier.
3589
+ */
3590
+ ruleId: string;
3591
+ /**
3592
+ * Diagnostic severity.
3593
+ */
3594
+ severity: MarkdownLintSeverity;
3595
+ /**
3596
+ * Human-readable explanation.
3597
+ */
3598
+ message: string;
3599
+ /**
3600
+ * 1-indexed line number.
3601
+ */
3602
+ line: number;
3603
+ /**
3604
+ * 1-indexed start column.
3605
+ */
3606
+ column: number;
3607
+ /**
3608
+ * 1-indexed end line.
3609
+ */
3610
+ endLine: number;
3611
+ /**
3612
+ * 1-indexed end column.
3613
+ */
3614
+ endColumn: number;
3615
+ /**
3616
+ * Language used for spellchecking, when relevant.
3617
+ */
3618
+ language?: MarkdownLintLanguage;
3619
+ /**
3620
+ * Suggested replacements, when available.
3621
+ */
3622
+ suggestions?: string[];
3623
+ }
3597
3624
  /**
3598
- * Base page props available for all pages.
3625
+ * Markdown lint report.
3599
3626
  */
3600
- interface BasePageProps {
3601
- /** Page title from frontmatter or first heading */
3602
- title: string;
3603
- /** Page description from frontmatter */
3604
- description?: string;
3605
- /** Rendered HTML content */
3606
- html: string;
3607
- /** Table of contents entries */
3608
- toc: TocEntry[];
3609
- /** Last git commit timestamp in milliseconds */
3610
- lastUpdated?: number;
3611
- /** Source file path (relative to docs root) */
3612
- path: string;
3613
- /** Output URL path */
3614
- url: string;
3615
- /** Raw frontmatter object */
3616
- frontmatter: Record<string, unknown>;
3617
- /** Layout name from frontmatter */
3618
- layout?: string;
3627
+ interface MarkdownLintResult {
3628
+ /**
3629
+ * All collected diagnostics.
3630
+ */
3631
+ diagnostics: MarkdownLintDiagnostic[];
3632
+ /**
3633
+ * Number of error diagnostics.
3634
+ */
3635
+ errorCount: number;
3636
+ /**
3637
+ * Number of warning diagnostics.
3638
+ */
3639
+ warningCount: number;
3640
+ /**
3641
+ * Number of info diagnostics.
3642
+ */
3643
+ infoCount: number;
3619
3644
  }
3620
3645
  /**
3621
- * Extended page props with custom frontmatter.
3646
+ * Lints Markdown prose with the Rust-backed built-in rule engine.
3622
3647
  */
3623
- type PageProps<T extends Record<string, unknown> = Record<string, unknown>> = BasePageProps & {
3624
- /** Custom frontmatter fields */
3625
- frontmatter: T & Record<string, unknown>;
3626
- };
3648
+ declare function lintMarkdown(source: string, options?: MarkdownLintOptions): MarkdownLintResult;
3627
3649
  /**
3628
- * Site-wide configuration available in context.
3650
+ * Async Markdown linter that supports opt-in standard dictionaries.
3629
3651
  */
3630
- interface SiteConfig {
3631
- /** Site name */
3632
- name: string;
3633
- /** Base URL path */
3634
- base: string;
3635
- /** All pages in the site */
3636
- pages: BasePageProps[];
3637
- /** Navigation groups */
3638
- nav: NavGroup[];
3639
- }
3652
+ declare function lintMarkdownAsync(source: string, options?: MarkdownLintOptions): Promise<MarkdownLintResult>;
3653
+ //#endregion
3654
+ //#region src/lint-files.d.ts
3640
3655
  /**
3641
- * Navigation group.
3656
+ * File-oriented Markdown lint options for end-user configuration.
3657
+ *
3658
+ * This extends the content-level lint options with project-level targeting,
3659
+ * so consumers can decide which files should be checked and which paths should
3660
+ * be ignored.
3642
3661
  */
3643
- interface NavGroup {
3644
- title: string;
3645
- items: NavItem[];
3662
+ interface MarkdownLintFileOptions extends MarkdownLintOptions {
3663
+ /**
3664
+ * Base directory used to resolve `include` and `exclude` patterns.
3665
+ * @default process.cwd()
3666
+ */
3667
+ cwd?: string;
3668
+ /**
3669
+ * Glob patterns for files to lint.
3670
+ * @default ['**\/*.md', '**\/*.markdown', '**\/*.mdx']
3671
+ */
3672
+ include?: string[];
3673
+ /**
3674
+ * Glob patterns for files to exclude from linting.
3675
+ * @default ['**\/node_modules/**', '**\/.git/**', '**\/dist/**']
3676
+ */
3677
+ exclude?: string[];
3678
+ /**
3679
+ * Alias of `exclude`.
3680
+ * When omitted, only `exclude` is used.
3681
+ * @default undefined
3682
+ */
3683
+ ignore?: string[];
3646
3684
  }
3647
3685
  /**
3648
- * Navigation item.
3686
+ * A lint diagnostic annotated with file metadata.
3649
3687
  */
3650
- interface NavItem {
3651
- title: string;
3652
- path: string;
3653
- href: string;
3688
+ interface MarkdownLintFileDiagnostic extends MarkdownLintDiagnostic {
3689
+ filePath: string;
3690
+ relativePath: string;
3654
3691
  }
3655
3692
  /**
3656
- * Complete render context.
3693
+ * Lint result for a single file.
3657
3694
  */
3658
- interface RenderContext<T extends Record<string, unknown> = Record<string, unknown>> {
3659
- /** Current page props */
3660
- page: PageProps<T>;
3661
- /** Site configuration */
3662
- site: SiteConfig;
3695
+ interface MarkdownLintFileResult extends MarkdownLintResult {
3696
+ filePath: string;
3697
+ relativePath: string;
3698
+ skipped: boolean;
3663
3699
  }
3664
3700
  /**
3665
- * Sets the current render context.
3666
- * Called internally during page rendering.
3667
- * @internal
3668
- */
3669
- declare function setRenderContext(ctx: RenderContext): void;
3670
- /**
3671
- * Clears the current render context.
3672
- * Called internally after page rendering.
3673
- * @internal
3674
- */
3675
- declare function clearRenderContext(): void;
3676
- /**
3677
- * Gets the current page props.
3678
- *
3679
- * @returns The current page props
3680
- * @throws Error if called outside of a render context
3681
- *
3682
- * @example
3683
- * ```tsx
3684
- * function PageTitle() {
3685
- * const page = usePageProps();
3686
- * return <h1>{page.title}</h1>;
3687
- * }
3688
- * ```
3701
+ * Aggregated lint result for multiple files.
3689
3702
  */
3690
- declare function usePageProps<T extends Record<string, unknown> = Record<string, unknown>>(): PageProps<T>;
3691
- /**
3692
- * Gets the site configuration.
3693
- *
3694
- * @returns The site configuration
3695
- * @throws Error if called outside of a render context
3696
- *
3697
- * @example
3698
- * ```tsx
3699
- * function SiteHeader() {
3700
- * const site = useSiteConfig();
3701
- * return <header>{site.name}</header>;
3702
- * }
3703
- * ```
3703
+ interface MarkdownLintFilesResult {
3704
+ checkedFileCount: number;
3705
+ diagnostics: MarkdownLintFileDiagnostic[];
3706
+ errorCount: number;
3707
+ files: MarkdownLintFileResult[];
3708
+ infoCount: number;
3709
+ warningCount: number;
3710
+ }
3711
+ /**
3712
+ * Returns true if the file path is included by the configured glob filters.
3704
3713
  */
3705
- declare function useSiteConfig(): SiteConfig;
3714
+ declare function shouldLintMarkdownFile(filePath: string, options?: MarkdownLintFileOptions): boolean;
3706
3715
  /**
3707
- * Gets the full render context.
3708
- *
3709
- * @returns The complete render context
3710
- * @throws Error if called outside of a render context
3716
+ * Lints a single Markdown file using project-style include/exclude settings.
3711
3717
  *
3712
- * @example
3713
- * ```tsx
3714
- * function Layout({ children }) {
3715
- * const ctx = useRenderContext();
3716
- * return (
3717
- * <html>
3718
- * <head><title>{ctx.page.title} - {ctx.site.name}</title></head>
3719
- * <body>{children}</body>
3720
- * </html>
3721
- * );
3722
- * }
3723
- * ```
3718
+ * If the file is filtered out by `include` / `exclude`, the returned result is
3719
+ * marked as `skipped` and contains no diagnostics.
3724
3720
  */
3725
- declare function useRenderContext<T extends Record<string, unknown> = Record<string, unknown>>(): RenderContext<T>;
3721
+ declare function lintMarkdownFile(filePath: string, options?: MarkdownLintFileOptions): Promise<MarkdownLintFileResult>;
3726
3722
  /**
3727
- * Gets the navigation groups.
3728
- *
3729
- * @example
3730
- * ```tsx
3731
- * function Sidebar() {
3732
- * const nav = useNav();
3733
- * return (
3734
- * <nav>
3735
- * {each(nav, (group) => (
3736
- * <div>
3737
- * <h3>{group.title}</h3>
3738
- * <ul>
3739
- * {each(group.items, (item) => (
3740
- * <li><a href={item.href}>{item.title}</a></li>
3741
- * ))}
3742
- * </ul>
3743
- * </div>
3744
- * ))}
3745
- * </nav>
3746
- * );
3747
- * }
3748
- * ```
3723
+ * Lints all Markdown files matched by the configured include/exclude patterns.
3749
3724
  */
3750
- declare function useNav(): NavGroup[];
3725
+ declare function lintMarkdownFiles(options?: MarkdownLintFileOptions): Promise<MarkdownLintFilesResult>;
3726
+ //#endregion
3727
+ //#region src/ssg.d.ts
3751
3728
  /**
3752
- * Checks if the given path is the current page.
3729
+ * Deprecated compatibility export for consumers that imported the former
3730
+ * TypeScript SSG template. HTML generation is Rust-backed now.
3753
3731
  *
3754
- * @example
3755
- * ```tsx
3756
- * function NavLink({ href, children }) {
3757
- * const isActive = useIsActive(href);
3758
- * return <a href={href} class={isActive ? 'active' : ''}>{children}</a>;
3759
- * }
3760
- * ```
3732
+ * @deprecated Use `generateHtmlPage`/`buildSsg` instead.
3761
3733
  */
3762
- declare function useIsActive(path: string): boolean;
3734
+ declare const DEFAULT_HTML_TEMPLATE = "<!-- ox-content default HTML template is Rust-backed -->";
3763
3735
  /**
3764
- * Schema for frontmatter type generation.
3736
+ * Resolves SSG options with defaults.
3765
3737
  */
3766
- interface FrontmatterSchema {
3767
- /** Field name */
3768
- name: string;
3769
- /** TypeScript type */
3770
- type: string;
3771
- /** Whether the field is optional */
3772
- optional: boolean;
3773
- /** JSDoc description */
3774
- description?: string;
3738
+ declare function resolveSsgOptions(ssg: SsgOptions | boolean | undefined): ResolvedSsgOptions;
3739
+ /** Result of an SSG build. */
3740
+ interface SsgBuildResult {
3741
+ /** Every file written, HTML pages and generated OG images alike. */
3742
+ files: string[];
3743
+ /** Per-page failures that did not abort the build. */
3744
+ errors: string[];
3745
+ /**
3746
+ * Generated OG image URL per source file, keyed by absolute input path.
3747
+ *
3748
+ * Bare mode renders these into the page itself, but a consumer
3749
+ * post-processing the output had no way to find them short of probing the
3750
+ * output directory for `og-image.png`.
3751
+ */
3752
+ ogImages: Record<string, string>;
3775
3753
  }
3776
3754
  /**
3777
- * Infers TypeScript types from frontmatter values.
3778
- */
3779
- declare function inferType(value: unknown): string;
3780
- /**
3781
- * Generates TypeScript interface from frontmatter samples.
3755
+ * Builds all markdown files to static HTML.
3782
3756
  */
3783
- declare function generateFrontmatterTypes(samples: Record<string, unknown>[], interfaceName?: string): string;
3757
+ declare function buildSsg(options: ResolvedOptions, root: string): Promise<SsgBuildResult>;
3784
3758
  //#endregion
3785
- //#region src/theme-renderer.d.ts
3759
+ //#region src/search.d.ts
3786
3760
  /**
3787
- * Theme component type.
3761
+ * Resolves search options with defaults.
3788
3762
  */
3789
- type ThemeComponent = (props: ThemeProps) => JSXNode;
3763
+ declare function resolveSearchOptions(options: SearchOptions | boolean | undefined): ResolvedSearchOptions;
3790
3764
  /**
3791
- * Props passed to the theme component.
3765
+ * Builds the search index from Markdown files.
3792
3766
  */
3793
- interface ThemeProps {
3794
- /** Rendered page content as JSX */
3795
- children: JSXNode;
3796
- }
3767
+ declare function buildSearchIndex(srcDir: string, base: string, extensions?: readonly string[]): Promise<string>;
3797
3768
  /**
3798
- * Page data for rendering.
3769
+ * Writes the search index to a file.
3799
3770
  */
3800
- interface PageData {
3801
- /** Page title */
3802
- title: string;
3803
- /** Page description */
3771
+ declare function writeSearchIndex(indexJson: string, outDir: string): Promise<void>;
3772
+ //#endregion
3773
+ //#region src/collections.d.ts
3774
+ declare function defineCollection<T extends CollectionOptions>(collection: T): T;
3775
+ declare function defineCollections<T extends CollectionsOptions>(collections: T): T;
3776
+ declare function resolveCollectionsOptions(options: CollectionsOptions | boolean | undefined): ResolvedCollectionsOptions;
3777
+ declare function buildCollectionManifest(root: string, options: ResolvedOptions): Promise<CollectionManifest>;
3778
+ declare function generateCollectionsVirtualModule(root: string, options: ResolvedOptions): Promise<string>;
3779
+ //#endregion
3780
+ //#region src/markdown.d.ts
3781
+ declare const DEFAULT_MARKDOWN_EXTENSIONS: readonly [".md", ".markdown", ".mdx"];
3782
+ declare function normalizeMarkdownExtensions(extensions?: readonly string[]): string[];
3783
+ declare function isMarkdownFilePath(filePath: string, extensions?: readonly string[]): boolean;
3784
+ declare function stripMarkdownExtension(filePath: string, extensions?: readonly string[]): string;
3785
+ //#endregion
3786
+ //#region src/vitepress.d.ts
3787
+ interface VitePressLogo {
3788
+ light?: string;
3789
+ dark?: string;
3790
+ src?: string;
3791
+ alt?: string;
3792
+ }
3793
+ interface VitePressSocialLink {
3794
+ icon: string;
3795
+ link: string;
3796
+ ariaLabel?: string;
3797
+ }
3798
+ interface VitePressFooter {
3799
+ message?: string;
3800
+ copyright?: string;
3801
+ }
3802
+ interface VitePressSidebarItem {
3803
+ text?: string;
3804
+ link?: string;
3805
+ items?: VitePressSidebarItem[];
3806
+ collapsed?: boolean;
3807
+ }
3808
+ type VitePressSidebar = VitePressSidebarItem[] | Record<string, VitePressSidebarItem[]>;
3809
+ interface VitePressNavItem {
3810
+ text?: string;
3811
+ link?: string;
3812
+ items?: VitePressNavItem[];
3813
+ activeMatch?: string;
3814
+ }
3815
+ interface VitePressThemeConfig {
3816
+ siteTitle?: string | false;
3817
+ logo?: string | VitePressLogo;
3818
+ nav?: VitePressNavItem[];
3819
+ sidebar?: VitePressSidebar;
3820
+ socialLinks?: VitePressSocialLink[];
3821
+ footer?: VitePressFooter;
3822
+ search?: {
3823
+ placeholder?: string;
3824
+ };
3825
+ }
3826
+ interface VitePressConfig {
3827
+ title?: string;
3804
3828
  description?: string;
3805
- /** Rendered HTML content */
3806
- html: string;
3807
- /** Table of contents */
3808
- toc: TocEntry[];
3809
- /** Last git commit timestamp in milliseconds */
3810
- lastUpdated?: number;
3811
- /** Source file path */
3812
- path: string;
3813
- /** Output URL path */
3814
- url: string;
3815
- /** Frontmatter */
3816
- frontmatter: Record<string, unknown>;
3817
- /** Layout name */
3818
- layout?: string;
3829
+ base?: string;
3830
+ themeConfig?: VitePressThemeConfig;
3819
3831
  }
3820
- /**
3821
- * Theme render options.
3822
- */
3823
- interface ThemeRenderOptions {
3824
- /** Theme component to use */
3825
- theme: ThemeComponent;
3826
- /** Site name */
3827
- siteName: string;
3828
- /** Base URL path */
3829
- base: string;
3830
- /** Navigation groups */
3831
- nav: NavGroup[];
3832
- /** All pages (for site context) */
3833
- pages: PageData[];
3834
- /** Output directory for type definitions */
3835
- typesOutDir?: string;
3832
+ interface GenerateVitePressMigrationConfigOptions {
3833
+ importSource?: string;
3836
3834
  }
3837
3835
  /**
3838
- * Renders a page using the theme component.
3839
- *
3840
- * @param page - Page data to render
3841
- * @param options - Theme render options
3842
- * @returns Rendered HTML string
3836
+ * Converts a VitePress sidebar config into ox-content navigation groups.
3837
+ * Nested VitePress items are flattened into the nearest ox-content group.
3843
3838
  */
3844
- declare function renderPage(page: PageData, options: ThemeRenderOptions): string;
3839
+ declare function convertVitePressSidebar(sidebar: VitePressSidebar): SsgNavigationGroup[];
3845
3840
  /**
3846
- * Renders all pages and generates type definitions.
3847
- *
3848
- * @param pages - All pages to render
3849
- * @param options - Theme render options
3850
- * @returns Map of output paths to rendered HTML
3841
+ * Converts VitePress top navigation into ox-content sidebar groups.
3842
+ * This is used as a fallback when no explicit sidebar is defined.
3851
3843
  */
3852
- declare function renderAllPages(pages: PageData[], options: ThemeRenderOptions): Promise<Map<string, string>>;
3844
+ declare function convertVitePressNav(nav: VitePressNavItem[]): SsgNavigationGroup[];
3853
3845
  /**
3854
- * Generates TypeScript type definitions from page frontmatter.
3855
- *
3856
- * @param pages - All pages
3857
- * @param outDir - Output directory for types
3846
+ * Creates ox-content plugin options from an existing VitePress config.
3858
3847
  */
3859
- declare function generateTypes(pages: PageData[], outDir: string): Promise<void>;
3848
+ declare function fromVitePressConfig(config: VitePressConfig, overrides?: OxContentOptions): OxContentOptions;
3860
3849
  /**
3861
- * Default theme component.
3862
- * A minimal theme that renders page content with basic styling.
3850
+ * Generates a TypeScript module exporting migrated ox-content options.
3851
+ *
3852
+ * This is used by the migration CLI so users can inspect and edit the resulting
3853
+ * object instead of keeping a runtime dependency on their VitePress config.
3863
3854
  */
3864
- declare function DefaultTheme({ children }: ThemeProps): JSXNode;
3855
+ declare function generateVitePressMigrationConfig(config: VitePressConfig, overrides?: OxContentOptions, options?: GenerateVitePressMigrationConfigOptions): string;
3865
3856
  /**
3866
- * Creates a theme with layout switching support.
3867
- *
3868
- * @example
3869
- * ```tsx
3870
- * import { createTheme } from '@ox-content/vite-plugin';
3871
- * import { DefaultLayout } from './layouts/Default';
3872
- * import { EntryLayout } from './layouts/Entry';
3873
- *
3874
- * export default createTheme({
3875
- * layouts: {
3876
- * default: DefaultLayout,
3877
- * entry: EntryLayout,
3878
- * },
3879
- * });
3880
- * ```
3857
+ * Normalizes VitePress-specific frontmatter into ox-content's entry-page shape.
3881
3858
  */
3882
- declare function createTheme(config: {
3883
- layouts: Record<string, ThemeComponent>;
3884
- defaultLayout?: string;
3885
- }): ThemeComponent;
3859
+ declare function normalizeVitePressFrontmatter(frontmatter: Record<string, unknown>): Record<string, unknown>;
3886
3860
  //#endregion
3887
3861
  //#region src/island/parse.d.ts
3888
3862
  /**