This repository has been archived by the owner on Mar 23, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 34
/
babel-plugin-extract-frontmatter.js
75 lines (66 loc) · 2.71 KB
/
babel-plugin-extract-frontmatter.js
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
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
const path = require('path')
const { generateFrontmatterPath } = require('./util')
const debug = require('debug')('next-mdx-enhanced')
// This plugin expects to be called as a function with nextjs' config options, so that it is
// aware of the project root and can calculate paths relative to it.
module.exports = function nextBabelWrapper(nextConfig, pluginOptions) {
// The function it returns is the actual babel plugin
return function frontMatterExtractionPlugin({ types: t }) {
return {
visitor: {
ImportDeclaration(_path, state) {
// if we're not looking at a .mdx file import, do nothing
const importPath = _path.node.source.value
if (
!importPath.match(
new RegExp(`\\.(${pluginOptions.fileExtensions.join('|')})$`)
)
)
return
// if there are no "frontMatter" imports, do nothing
const frontMatterSpecifier = _path.node.specifiers.find((s) =>
importsFrontMatter(s)
)
if (!frontMatterSpecifier) return
debug(`start: extracting frontmatter for ${importPath}`)
// front matter is extracted and written out by the loader to .next/frontMatter/<filePathHashed>
// here, we're calculating the path
const currentPath = state.file.opts.filename
const frontMatterPath = generateFrontmatterPath(
path.resolve(path.dirname(currentPath), importPath),
nextConfig.dir
)
// now, we construct a new import statement
const localName = frontMatterSpecifier.local.name
const frontMatterImport = t.importDeclaration(
[t.importDefaultSpecifier(t.identifier(localName))],
t.stringLiteral(frontMatterPath)
)
// ...and insert it after the current import
_path.insertAfter([frontMatterImport])
// then we remove the front matter specifier from the current import
if (_path.node.specifiers.length === 1) {
// if its the only specifier, we remove the entire import
_path.remove()
} else {
_path.node.specifiers = _path.node.specifiers.reduce((acc, s) => {
// otherwise, we only remove the frontMatter import specifier
if (!importsFrontMatter(s)) acc.push(s)
return acc
}, [])
}
debug(`finish: extracting frontmatter for ${importPath}`)
},
},
}
}
}
function importsFrontMatter(specifier) {
return specifier.imported
? specifier.imported.name === 'frontMatter'
: specifier.local.name === 'frontMatter'
}