-
Notifications
You must be signed in to change notification settings - Fork 1
/
onCreateNode.ts
154 lines (131 loc) · 4.94 KB
/
onCreateNode.ts
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
import path from 'path'
import crypto from 'crypto'
import slugify from '@sindresorhus/slugify'
import { GatsbyNode } from 'gatsby'
import { FileSystemNode } from 'gatsby-source-filesystem'
import { siteUrl, githubRepoUrl } from '@shared/config'
import { convertLangKeyToGraphQLEnum, getLangKeyFromFilePath, trim } from './utils'
interface MdxNode extends FileSystemNode {
fileAbsolutePath: string
frontmatter: Record<string, any>
}
const convertToPosixPath = (nonPosixPath: string) => nonPosixPath.replace(/\\/g, '/')
// https://www.gatsbyjs.org/docs/node-apis/#onCreateNode
export const onCreateNode: GatsbyNode['onCreateNode'] = async ({
createContentDigest,
createNodeId,
node,
getNode,
actions,
}) => {
// eslint-disable-next-line @typescript-eslint/unbound-method
const { createNode, createParentChildLink } = actions
// We only care for Mdx nodes here.
if (node.internal.type !== `Mdx`) {
return
}
const mdxNode = (node as unknown) as MdxNode
const fileNode = getNode(mdxNode.parent) as FileSystemNode
const { fileAbsolutePath } = mdxNode
const { sourceInstanceName } = fileNode
// ***************************
// * AUTOMATIC SLUG HANDLING
// ***************************
// We can specify on the file directly if we want to, otherwise one is going to be generated
// based on the relative path of the file.
const relativePath = convertToPosixPath(
path.relative(
path.resolve(__dirname, '..', 'content'),
path.dirname(fileAbsolutePath),
),
)
const fileRelativePath = convertToPosixPath(
path.relative(path.resolve(__dirname, '..', 'content'), fileAbsolutePath),
)
// Using the source instance name (we have multiple filesystem sources)
let pageLocation = sourceInstanceName === 'pages' ? '/' : `/${sourceInstanceName}/`
// default is false
const isDraft = mdxNode.frontmatter.isDraft ?? false
if (isDraft) {
pageLocation = `${pageLocation}draft/`
}
// remove date from path and add draft if it's a draft
const filePathWithoutDate = relativePath.replace(
/[0-9]{4}-[0-9]{2}-[0-9]{2}_/,
isDraft ? 'draft/' : '',
)
let slug = mdxNode.frontmatter.slug
? `${pageLocation}${trim(mdxNode.frontmatter.slug, '/')}`
: filePathWithoutDate
.split('/')
.map((p) => slugify(p))
.join('/')
// ***************************
// * i18n handling
// ***************************
// This is heavily inspired on the https://github.com/angeloocana/gatsby-plugin-i18n plugin
const langKey = getLangKeyFromFilePath(fileAbsolutePath)
const trimmedSlug = trim(slug, '/')
slug = `/${langKey}/${trimmedSlug}/`
const slugLastPart = trimmedSlug.split('/').pop()
const globalBlogPostId = crypto.createHash('sha1').update(relativePath).digest('base64')
// ***************************
// End of special handling
// ***************************
const date = mdxNode.frontmatter.date
if (!date) {
throw new Error('All mdx content must have a date field on the frontmatter')
}
const blogFields = {
title: mdxNode.frontmatter.title,
description: mdxNode.frontmatter.description,
slug,
langKey: convertLangKeyToGraphQLEnum(langKey),
globalBlogPostId,
publisher: mdxNode.frontmatter.publisher,
externalLinks: {
github: `${trim(githubRepoUrl, '/')}/blob/master/content/${fileRelativePath.replace(
/\\/g,
'/',
)}`,
...(mdxNode.frontmatter.externalLinks || {}),
},
date,
dateModified: mdxNode.frontmatter.dateModified || fileNode.modifiedTime || date,
banner: mdxNode.frontmatter.banner,
bannerStyle:
mdxNode.frontmatter.banner && (mdxNode.frontmatter.bannerStyle || 'FULL_WIDTH'),
hasNonDefaultSocialImageUrl: !!mdxNode.frontmatter.socialImageUrl,
socialImageUrl:
mdxNode.frontmatter.socialImageUrl ??
`${trim(siteUrl, '/')}/og-images/${sourceInstanceName}/${slugLastPart}.png`,
// If we wanted to have a separated class for categories
// Same could be done for tags
// category: {
// name: node.frontmatter.category,
// slug: slugify(node.frontmatter.category),
// },
category: mdxNode.frontmatter.category,
categorySlug: slugify(mdxNode.frontmatter.category),
tags: mdxNode.frontmatter.tags ?? mdxNode.frontmatter.keywords ?? [],
keywords: mdxNode.frontmatter.keywords ?? mdxNode.frontmatter.tags ?? [],
isDraft,
reviewers: mdxNode.frontmatter.reviewers ?? [],
}
// https://www.gatsbyjs.org/docs/actions/#createNode
const mdxBlogPostId = createNodeId(`MdxBlogPost:${mdxNode.id}`)
// eslint-disable-next-line @typescript-eslint/await-thenable
await createNode({
...blogFields,
// Required fields.
id: mdxBlogPostId,
parent: mdxNode.id,
children: [],
internal: {
type: `MdxBlogPost`,
contentDigest: createContentDigest(blogFields),
description: 'Mdx implementation of the BlogPost interface',
},
})
createParentChildLink({ parent: mdxNode, child: getNode(mdxBlogPostId) })
}