-
Notifications
You must be signed in to change notification settings - Fork 33
Expand file tree
/
Copy pathplugin.ts
More file actions
211 lines (188 loc) · 6.52 KB
/
plugin.ts
File metadata and controls
211 lines (188 loc) · 6.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
import type { fs } from '@contentlayer2/utils'
import type { E, HasClock, HasConsole, OT, S, T } from '@contentlayer2/utils/effect'
import type { CompileOptions } from '@mdx-js/mdx'
import type * as mdxBundler from 'mdx-bundler/dist/types'
import type { LiteralUnion } from 'type-fest'
import type * as unified from 'unified'
import type { HasCwd } from './cwd.js'
import type { DataCache } from './DataCache.js'
import type { SourceFetchDataError, SourceProvideSchemaError } from './errors.js'
import type { GetDataExportsGen } from './gen.js'
import type { SchemaDef, StackbitExtension } from './schema/index.js'
export type SourcePluginType = LiteralUnion<'local' | 'contentful' | 'sanity', string>
export type PluginExtensions = {
// TODO decentralized extension definitions + logic
stackbit?: StackbitExtension.Config
}
export type PluginOptions = {
markdown: MarkdownOptions | MarkdownUnifiedBuilderCallback | undefined
mdx: MDXOptions | undefined
date: DateOptions | undefined
fieldOptions: FieldOptions
disableImportAliasWarning: boolean
experimental: PluginOptionsExperimental
onSuccess: SuccessCallback | undefined
}
export type SuccessCallback = (getData: () => Promise<GetDataExportsGen>) => Promise<void>
export type PluginOptionsExperimental = {
enableDynamicBuild: boolean
}
/**
* Please make sure to use the following Unified plugins for Contentlayer to work properly:
*
* @example
* ```ts
* import rehypeStringify from 'rehype-stringify'
* import remarkFrontmatter from 'remark-frontmatter'
* import remarkParse from 'remark-parse'
* import remark2rehype from 'remark-rehype'
*
* makeSource({
* // your other options ...
* markdown: (builder) => {
* builder
* .use(remarkFrontmatter)
* .use(remarkParse)
* .use(remark2rehype)
* .use(rehypeStringify)
* }
* })
* ```
*/
export type MarkdownUnifiedBuilderCallback = (builder: unified.Processor) => void
export type MarkdownOptions = {
remarkPlugins?: unified.Pluggable[]
rehypePlugins?: unified.Pluggable[]
}
export type MDXOptions = {
remarkPlugins?: unified.Pluggable[]
rehypePlugins?: unified.Pluggable[]
/** */
/**
* This allows you to modify the built-in MDX configuration (passed to @mdx-js/mdx compile via mdx-bundler).
* This can be helpful for specifying your own remarkPlugins/rehypePlugins.
*
* Note that Contentlayer by default applies the built-in `addRawDocumentToVFile` remark plugin
* which adds the raw document data to the vfile under `vfile.data.rawDocumentData`.
*/
mdxOptions?: MDXBundlerMapOptions
/**
* How we resolve the cwd passed to mdx-bundler when processing a file. If an explicit `cwd`
* is provided this option will be ignored.
* - `relative` sets the cwd to the directory the file resides in.
* - `contentDirPath` sets the cwd to the contentDirPath. This was the default behavior up until v0.2.6.
* @default "relative"
*/
resolveCwd?: 'relative' | 'contentDirPath'
} & Omit<mdxBundler.BundleMDXOptions<any>, 'mdxOptions'>
export type MDXBundlerMapOptions = (options: CompileOptions) => CompileOptions
export type DateOptions = {
/**
* Use provided timezone (e.g. `America/New_York`)
*
* Based on: https://tc39.es/proposal-temporal/docs/timezone.html
*
* NOTE The provided timezone will only be used for values that don't already have a timezone set.
*/
timezone?: string
}
export type FieldOptions = {
// TODO add to Jsdoc that `bodyFieldName` is just about the field name of the generated document type + data.
// not about some front matter (as opposed to `typeFieldName` which concerns the front matter as well)
/**
* Name of the field containing the body/content extracted when `contentType` is `markdown` or `mdx`.
* @default "body"
*/
bodyFieldName: string
/**
* Name of the field containing the name of the document type (or nested document type).
* @default "type"
*/
typeFieldName: string
}
export type SourcePlugin = {
type: SourcePluginType
provideSchema: ProvideSchema
fetchData: FetchData
options: PluginOptions
extensions: PluginExtensions
}
export type ProvideSchema = (
esbuildHash: string,
) => T.Effect<OT.HasTracer & HasConsole, SourceProvideSchemaError, SchemaDef>
export type FetchData = (_: {
schemaDef: SchemaDef
verbose: boolean
skipCachePersistence?: boolean
watch?: boolean
}) => S.Stream<
OT.HasTracer & HasClock & HasCwd & HasConsole & fs.HasFs,
never,
E.Either<SourceFetchDataError | SourceProvideSchemaError, DataCache.Cache>
>
// export type MakeSourcePlugin = (
// _: Args | Thunk<Args> | Thunk<Promise<Args>>,
// ) => Promise<core.SourcePlugin>
export type MakeSourcePlugin<TArgs extends PartialArgs> = (
_: TArgs | ThunkWithSourceKey<TArgs> | ThunkWithSourceKey<Promise<TArgs>>,
) => (sourceKey: string | undefined) => Promise<SourcePlugin>
export type ThunkWithSourceKey<T> = (sourceKey: string | undefined) => T
export type PartialArgs = {
markdown?: MarkdownOptions | MarkdownUnifiedBuilderCallback | undefined
mdx?: MDXOptions | undefined
date?: DateOptions | undefined
fieldOptions?: Partial<FieldOptions>
extensions?: PluginExtensions
disableImportAliasWarning?: boolean
experimental?: Partial<PluginOptionsExperimental>
onSuccess?: SuccessCallback | undefined
}
export const defaultFieldOptions: FieldOptions = {
bodyFieldName: 'body',
typeFieldName: 'type',
}
export const processArgs = async <TArgs extends PartialArgs>(
argsOrArgsThunk: TArgs | ThunkWithSourceKey<TArgs> | ThunkWithSourceKey<Promise<TArgs>>,
sourceKey: string | undefined,
): Promise<{
extensions: PluginExtensions
options: PluginOptions
restArgs: Omit<
TArgs,
| 'extensions'
| 'fieldOptions'
| 'markdown'
| 'mdx'
| 'date'
| 'disableImportAliasWarning'
| 'experimental'
| 'onSuccess'
>
}> => {
const {
extensions,
fieldOptions,
markdown,
mdx,
date,
disableImportAliasWarning,
experimental,
onSuccess,
...restArgs
} = typeof argsOrArgsThunk === 'function' ? await argsOrArgsThunk(sourceKey) : argsOrArgsThunk
const options: PluginOptions = {
markdown,
mdx,
date,
fieldOptions: {
bodyFieldName: fieldOptions?.bodyFieldName ?? defaultFieldOptions.bodyFieldName,
typeFieldName: fieldOptions?.typeFieldName ?? defaultFieldOptions.typeFieldName,
},
disableImportAliasWarning: disableImportAliasWarning ?? false,
experimental: {
enableDynamicBuild: experimental?.enableDynamicBuild ?? false,
},
onSuccess,
}
return { extensions: extensions ?? {}, options, restArgs }
}