1
- import type { GetDocumentTypeNamesGen } from '@contentlayer/core'
1
+ import type * as core from '@contentlayer/core'
2
2
import type * as SourceFiles from '@contentlayer/source-files'
3
- import { defineDocumentType } from '@contentlayer/source-files'
4
- import { not , partition } from '@contentlayer/utils'
3
+ import { defineDocumentType , defineNestedType } from '@contentlayer/source-files'
4
+ import type { PartialDeep } from '@contentlayer/utils'
5
+ import { mergeDeep , not , partition , pick } from '@contentlayer/utils'
5
6
import * as Stackbit from '@stackbit/sdk'
6
7
import { validateAndNormalizeConfig } from '@stackbit/sdk/dist/config/config-loader.js'
7
8
8
9
import type { SharedCtx } from './mapping.js'
9
10
import { stackbitDocumentLikeModelToDocumentType , stackbitObjectModelToDocumentType } from './mapping.js'
10
11
12
+ /** NOTE Overrides are currently not validated - use carefully */
11
13
export type ContentlayerOverrideArgs < TDocumentTypeNames extends string > = {
12
- documentTypes : Partial < {
14
+ documentTypes ? : Partial < {
13
15
[ TDocumentTypeName in TDocumentTypeNames ] : ContentlayerOverrideDocumentType < TDocumentTypeName >
14
16
} >
17
+ nestedTypes ?: Partial < {
18
+ [ TDocumentTypeName in TDocumentTypeNames ] : ContentlayerOverrideNestedType
19
+ } >
15
20
}
16
21
17
22
export type ContentlayerOverrideDocumentType < TDocumentTypeName extends string > = {
18
23
filePathPattern ?: string
24
+ fields ?: { [ fieldName : string ] : { type : SourceFiles . FieldDefType } }
19
25
computedFields ?: SourceFiles . ComputedFields < TDocumentTypeName >
20
26
}
21
27
28
+ export type ContentlayerOverrideNestedType = {
29
+ fields ?: { [ fieldName : string ] : { type : SourceFiles . FieldDefType } }
30
+ }
31
+
22
32
/**
23
33
* @example
24
34
* ```ts
@@ -32,9 +42,9 @@ export type ContentlayerOverrideDocumentType<TDocumentTypeName extends string> =
32
42
* })
33
43
* ```
34
44
*/
35
- export const loadStackbitConfigAsDocumentTypes = < TDocumentTypeNames extends GetDocumentTypeNamesGen > (
45
+ export const loadStackbitConfigAsDocumentTypes = < TDocumentTypeNames extends core . GetDocumentTypeNamesGen > (
36
46
options : Stackbit . ConfigLoaderOptions = { dirPath : '' } ,
37
- overrideArgs : ContentlayerOverrideArgs < TDocumentTypeNames > = { documentTypes : { } } ,
47
+ overrideArgs : ContentlayerOverrideArgs < TDocumentTypeNames > = { documentTypes : { } , nestedTypes : { } } ,
38
48
) : Promise < SourceFiles . DocumentType [ ] > =>
39
49
Stackbit . loadConfig ( options ) . then ( ( configResult ) => {
40
50
if ( configResult . errors . length > 0 ) {
@@ -58,9 +68,9 @@ export const loadStackbitConfigAsDocumentTypes = <TDocumentTypeNames extends Get
58
68
* export default makeSource({ contentDirPath: 'content', documentTypes })
59
69
* ```
60
70
*/
61
- export const stackbitConfigToDocumentTypes = < TDocumentTypeNames extends GetDocumentTypeNamesGen > (
71
+ export const stackbitConfigToDocumentTypes = < TDocumentTypeNames extends core . GetDocumentTypeNamesGen > (
62
72
stackbitConfig : Stackbit . Config | Stackbit . YamlConfig ,
63
- overrideArgs : ContentlayerOverrideArgs < TDocumentTypeNames > = { documentTypes : { } } ,
73
+ overrideArgs : ContentlayerOverrideArgs < TDocumentTypeNames > = { documentTypes : { } , nestedTypes : { } } ,
64
74
) : SourceFiles . DocumentType [ ] => {
65
75
const validatedStackbitConfig = validateStackbitConfig ( stackbitConfig )
66
76
@@ -76,15 +86,48 @@ export const stackbitConfigToDocumentTypes = <TDocumentTypeNames extends GetDocu
76
86
objectModels . forEach ( ( model ) => {
77
87
const nestedType = stackbitObjectModelToDocumentType ( ctx ) ( model )
78
88
ctx . nestedTypeMap [ model . name ] = nestedType
89
+
90
+ const nestedOverride = ( overrideArgs . nestedTypes as any ) ?. [ model . name ] as ContentlayerOverrideNestedType | undefined
91
+ const fields = nestedType . def ( ) . fields
92
+ if ( nestedOverride ?. fields && fields ) {
93
+ for ( const [ fieldName , { type } ] of Object . entries ( nestedOverride . fields ) ) {
94
+ const fieldDef = Array . isArray ( fields )
95
+ ? fields . find ( ( fieldDef ) => fieldDef . name === fieldName )
96
+ : fields [ fieldName ]
97
+
98
+ if ( fieldDef ) {
99
+ fieldDef . type = type
100
+ }
101
+ }
102
+
103
+ patchNestedType ( nestedType , { fields } )
104
+ }
79
105
} )
80
106
81
107
documentTypes . forEach ( ( documentType ) => {
82
108
const documentTypeName = documentType . def ( ) . name
83
109
ctx . documentTypeMap [ documentTypeName ] = documentType
84
110
85
- const documentOverride = ( overrideArgs . documentTypes as any ) [ documentTypeName ]
86
- if ( documentOverride ) {
87
- patchDocumentType ( documentType , documentOverride )
111
+ const documentOverride = ( overrideArgs . documentTypes as any ) ?. [ documentTypeName ] as
112
+ | ContentlayerOverrideDocumentType < string >
113
+ | undefined
114
+ if ( documentOverride ?. filePathPattern !== undefined || documentOverride ?. computedFields !== undefined ) {
115
+ patchDocumentType ( documentType , pick ( documentOverride , [ 'filePathPattern' , 'computedFields' ] ) )
116
+ }
117
+
118
+ const fields = documentType . def ( ) . fields
119
+ if ( documentOverride ?. fields && fields ) {
120
+ for ( const [ fieldName , { type } ] of Object . entries ( documentOverride . fields ) ) {
121
+ const fieldDef = Array . isArray ( fields )
122
+ ? fields . find ( ( fieldDef ) => fieldDef . name === fieldName )
123
+ : fields [ fieldName ]
124
+
125
+ if ( fieldDef ) {
126
+ fieldDef . type = type
127
+ }
128
+ }
129
+
130
+ patchDocumentType ( documentType , { fields } )
88
131
}
89
132
} )
90
133
@@ -93,10 +136,15 @@ export const stackbitConfigToDocumentTypes = <TDocumentTypeNames extends GetDocu
93
136
94
137
const patchDocumentType = (
95
138
documentType : SourceFiles . DocumentType ,
96
- patch : Partial < SourceFiles . DocumentTypeDef > ,
139
+ patch : PartialDeep < SourceFiles . DocumentTypeDef > ,
97
140
) : void => {
98
141
const previousDef = documentType . def ( )
99
- documentType . def = defineDocumentType ( ( ) => ( { ...previousDef , ...patch } ) ) . def
142
+ documentType . def = defineDocumentType ( ( ) => mergeDeep ( { ...previousDef , ...patch } ) ) . def
143
+ }
144
+
145
+ const patchNestedType = ( nestedType : SourceFiles . NestedType , patch : PartialDeep < SourceFiles . NestedTypeDef > ) : void => {
146
+ const previousDef = nestedType . def ( )
147
+ nestedType . def = defineNestedType ( ( ) => mergeDeep ( { ...previousDef , ...patch } ) ) . def
100
148
}
101
149
102
150
const validateStackbitConfig = ( stackbitConfig : Stackbit . Config | Stackbit . YamlConfig ) : Stackbit . Config => {
0 commit comments