@@ -6,8 +6,7 @@ import type { CollectionDefinition } from '../cli/getConfig'
66import { convertToMDX } from '../cli/convertToMDX'
77
88function defineContent ( contentObj : CollectionDefinition ) {
9- const { base, packageName, pattern, name } = contentObj
10-
9+ const { base, packageName, pattern, name, frontmatterDefaults, frontmatterMapping } = contentObj
1110
1211 if ( ! base && ! packageName ) {
1312 // eslint-disable-next-line no-console
@@ -24,26 +23,57 @@ function defineContent(contentObj: CollectionDefinition) {
2423 convertToMDX ( `${ base } /${ pattern } ` )
2524 const mdxPattern = pattern . replace ( / \. m d $ / , '.mdx' )
2625
26+ const hasExternalFrontmatter = ! ! ( frontmatterDefaults || frontmatterMapping )
27+
28+ const baseSchema = z . object ( {
29+ id : hasExternalFrontmatter ? z . string ( ) . optional ( ) : z . string ( ) ,
30+ section : hasExternalFrontmatter ? z . string ( ) . optional ( ) : z . string ( ) ,
31+ subsection : z . string ( ) . optional ( ) ,
32+ title : z . string ( ) . optional ( ) ,
33+ // Generic frontmatter fields from external sources
34+ category : z . string ( ) . optional ( ) ,
35+ subcategory : z . string ( ) . optional ( ) ,
36+ description : z . string ( ) . optional ( ) ,
37+ tags : z . array ( z . string ( ) ) . optional ( ) ,
38+ propComponents : z . array ( z . string ( ) ) . optional ( ) ,
39+ tab : z . string ( ) . optional ( ) . default ( tabMap [ name ] ) , // for component tabs
40+ source : z . string ( ) . optional ( ) ,
41+ tabName : z . string ( ) . optional ( ) ,
42+ sortValue : z . number ( ) . optional ( ) , // used for sorting nav entries,
43+ cssPrefix : z
44+ . union ( [
45+ z . string ( ) . transform ( ( val : string ) => [ val ] ) ,
46+ z . array ( z . string ( ) ) ,
47+ z . null ( ) . transform ( ( ) => undefined ) ,
48+ ] )
49+ . optional ( ) ,
50+ } ) . transform ( ( data ) => {
51+ const result : Record < string , unknown > = { ...data }
52+
53+ // Apply frontmatter mapping (e.g. { title: "id" } maps the title value to id)
54+ if ( frontmatterMapping ) {
55+ for ( const [ sourceField , targetField ] of Object . entries ( frontmatterMapping ) ) {
56+ if ( result [ sourceField ] != null && result [ targetField ] == null ) {
57+ result [ targetField ] = result [ sourceField ]
58+ }
59+ }
60+ }
61+
62+ // Apply frontmatter defaults (e.g. { section: "AI" } sets section if not already present)
63+ if ( frontmatterDefaults ) {
64+ for ( const [ field , value ] of Object . entries ( frontmatterDefaults ) ) {
65+ if ( result [ field ] == null ) {
66+ result [ field ] = value
67+ }
68+ }
69+ }
70+
71+ return result
72+ } )
73+
2774 return defineCollection ( {
2875 loader : glob ( { base, pattern : mdxPattern } ) ,
29- schema : z . object ( {
30- id : z . string ( ) ,
31- section : z . string ( ) ,
32- subsection : z . string ( ) . optional ( ) ,
33- title : z . string ( ) . optional ( ) ,
34- propComponents : z . array ( z . string ( ) ) . optional ( ) ,
35- tab : z . string ( ) . optional ( ) . default ( tabMap [ name ] ) , // for component tabs
36- source : z . string ( ) . optional ( ) ,
37- tabName : z . string ( ) . optional ( ) ,
38- sortValue : z . number ( ) . optional ( ) , // used for sorting nav entries,
39- cssPrefix : z
40- . union ( [
41- z . string ( ) . transform ( ( val : string ) => [ val ] ) ,
42- z . array ( z . string ( ) ) ,
43- z . null ( ) . transform ( ( ) => undefined ) ,
44- ] )
45- . optional ( ) ,
46- } ) ,
76+ schema : baseSchema ,
4777 } )
4878}
4979
0 commit comments