-
Notifications
You must be signed in to change notification settings - Fork 88
Expand file tree
/
Copy pathcontentlayer.config.ts
More file actions
131 lines (122 loc) · 3.79 KB
/
contentlayer.config.ts
File metadata and controls
131 lines (122 loc) · 3.79 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
import {defineDocumentType, makeSource} from 'contentlayer/source-files';
import fs from 'fs';
import rehypeAutolinkHeadings from 'rehype-autolink-headings';
import rehypePrettyCode from 'rehype-pretty-code';
import rehypeSlug from 'rehype-slug';
import remarkGfm from 'remark-gfm';
import {MDXDocument, allCoreContent} from './src/utils/contentlayer';
import {searchMetadata} from './src/data/search';
import GithubSlugger from 'github-slugger';
import {visit} from 'unist-util-visit';
export const Post = defineDocumentType(() => ({
name: 'Post',
filePathPattern: `**/*.mdx`,
contentType: 'mdx',
fields: {
title: {type: 'string', required: false},
date: {type: 'date', required: false},
seoPriority: {type: 'number', required: false},
// Preview posts are excluded in the sitemap and the search index. They return a 404
// unless the ?preview query parameter is present. This is useful for sharing early
// docs pages internally or with select early customers.
preview: {type: 'boolean', required: false}
},
computedFields: {
url: {type: 'string', resolve: post => `/${post._raw.flattenedPath}`},
headings: {
type: 'json',
resolve: async doc => {
const regXHeader = /^ *(?<flag>#{1,6})\s+(?<content>.+)/gm;
const regXCodeBlock = /```[\s\S]*?```/g;
const slugger = new GithubSlugger();
// Ignore content within code blocks – No headings there
const bodyWithoutCodeBlocks = doc.body.raw.replace(
regXCodeBlock,
''
);
const headings = Array.from(
bodyWithoutCodeBlocks.matchAll(regXHeader)
).map(({groups}) => {
const flag = groups?.flag;
// Handles headings with links eg:
// Converts '##[Getting started](/getting-started)' to 'Getting started'
const match = groups?.content?.match(
/\[([^\]]+)\]\([^)]+\)/
);
const title = match ? match[1] : groups?.content;
return {
level: flag?.length,
title: title,
id: title ? slugger.slug(title) : undefined
};
});
return headings;
}
}
}
}));
function createSearchIndex(allPosts: MDXDocument[]) {
if (
searchMetadata?.provider === 'kbar' &&
searchMetadata.kbarConfig.searchDocumentsPath
) {
fs.writeFileSync(
`public/search.json`,
JSON.stringify(allCoreContent(allPosts))
);
console.log('Search index generated...');
}
}
const prettyCodeOptions = {
keepBackground: true,
theme: JSON.parse(
fs.readFileSync(
new URL(
'./../../../src/styles/shades-of-purple.json',
import.meta.url
),
'utf-8'
)
)
};
const rehypePlugins: any = [
// Extract raw code content from code elements within pre elements
() => (tree: any) => {
visit(tree, (node: any) => {
if (node?.type === 'element' && node?.tagName === 'pre') {
const [codeEl] = node.children;
if (codeEl.tagName !== 'code') return;
node.raw = codeEl.children?.[0].value;
}
});
},
[rehypePrettyCode, prettyCodeOptions],
// Add raw code content as a property to pre elements within div elements containing data-rehype-pretty-code-fragment attribute
() => (tree: any) => {
visit(tree, (node: any) => {
if (node?.type === 'element' && node?.tagName === 'div') {
if (!('data-rehype-pretty-code-fragment' in node.properties))
return;
for (const child of node.children)
if (child.tagName === 'pre')
child.properties['raw'] = node.raw;
}
});
},
rehypeSlug,
[rehypeAutolinkHeadings]
];
export default makeSource({
contentDirPath: 'docs',
documentTypes: [Post],
mdx: {
remarkPlugins: [remarkGfm],
rehypePlugins: rehypePlugins,
// Externalize mermaid to prevent bundling its problematic Unicode regex patterns
esbuildOptions: options => ({...options, external: [...(options.external ?? []), 'mermaid']})
},
onSuccess: async importData => {
const {allPosts} = await importData();
createSearchIndex(allPosts);
}
});