-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgatsby-node.js
More file actions
203 lines (177 loc) · 6.06 KB
/
Copy pathgatsby-node.js
File metadata and controls
203 lines (177 loc) · 6.06 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
const { paginate } = require('gatsby-awesome-pagination')
const path = require(`path`)
const makeSlug = require("./src/utils/make-slug")
const _ = require('lodash')
const { createFilePath } = require(`gatsby-source-filesystem`)
const siteConfig = require("./gatsby-config")
exports.onCreateNode = ({ node, getNode, actions }) => {
if (node.internal.type === `MarkdownRemark`) {
const { createNodeField } = actions
const title = node.frontmatter.title ? node.frontmatter.title : createFilePath({ node, getNode, basePath: `_notes` }).replace(/^\/(.+)\/$/, '$1')
const slug = node.frontmatter.slug ? makeSlug(node.frontmatter.slug) : makeSlug(title)
const fileNode = getNode(node.parent)
const date = node.frontmatter.date ? node.frontmatter.date : fileNode.ctime
createNodeField({
node,
name: `slug`,
value: `/${slug}`
})
createNodeField({
node,
name: `date`,
value: date
})
createNodeField({
node,
name: `title`,
value: title.replace(/\//g,'')
})
// :TODO: Add tags. Ideally, every supported frontmatter should be added as a field.
}
}
exports.createPages = async ({ graphql, actions }) => {
const { createPage, createRedirect } = actions
const result = await graphql(`
query {
allMarkdownRemark {
edges {
node {
fields {
slug
title
}
frontmatter {
title
tags
date
aliases
}
rawMarkdownBody
excerpt
fileAbsolutePath
}
}
}
tags: allMarkdownRemark(limit: 2000) {
group(field: frontmatter___tags) {
fieldValue
}
}
}
`)
const allNotes = _.get(result, "data.allMarkdownRemark.edges")
// Make a map of how notes link to other links. This is necessary to have back links and graph visualisation
let referenceMap = {}
let backLinkMap = {}
// I didn't used the much more cleaner foreach because the `referenceMap` was not working well with that.
for(let i = 0; i < result.data.allMarkdownRemark.edges.length; i++) {
const node = result.data.allMarkdownRemark.edges[i].node
const title = node.frontmatter.title ? node.frontmatter.title : node.fields.title
const noteTitle = getPreExistingTitle(title, backLinkMap)
if(!noteTitle || backLinkMap[noteTitle] === undefined) backLinkMap[title] = [] // Create a element in the back link map if its already not made.
// Go thru all the notes, create a map of how references map.
const refersNotes = findReferences( node.rawMarkdownBody )
referenceMap[title] = refersNotes
for(let j = 0; j < refersNotes.length; j++) {
const tle = refersNotes[j]
const noteTitle = getPreExistingTitle(tle, backLinkMap)
if(!noteTitle || backLinkMap[noteTitle] === undefined) backLinkMap[noteTitle] = [ title ]
else backLinkMap[noteTitle].push(title)
}
}
for(let i = 0; i < result.data.allMarkdownRemark.edges.length; i++) {
const node = result.data.allMarkdownRemark.edges[i].node
const title = node.frontmatter.title ? node.frontmatter.title : node.fields.title
const aliases = node.frontmatter.aliases ? node.frontmatter.aliases : []
createPage({
path: node.fields.slug,
component: path.resolve(`./src/templates/note.jsx`),
context: {
title: title,
slug: node.fields.slug,
refersTo: referenceMap[title] ? referenceMap[title] : [],
referredBy: backLinkMap[title] ? backLinkMap[title] : []
}
})
// Handling Aliases
for(let j = 0; j < aliases.length; j++) {
createRedirect({
fromPath: `/${makeSlug(aliases[j])}`,
toPath: node.fields.slug,
redirectInBrowser: true,
isPermanent: true,
})
}
}
createPage({
path: `/note-map`,
component: path.resolve('./src/templates/note-map.jsx'),
context: {
referenceMap,
backLinkMap
}
})
result.data.tags.group.forEach(( tag ) => {
const taggedNotes = allNotes.filter(note => note.node.frontmatter.tags ? note.node.frontmatter.tags.includes(tag.fieldValue) : false)
paginate({
createPage,
items: taggedNotes,
itemsPerPage: 10,
pathPrefix: `/tags/${makeSlug(tag.fieldValue)}`,
component: path.resolve('./src/templates/tag.jsx'),
context: {
tag: tag.fieldValue
}
})
})
createPage({
path: `/tags`,
component: path.resolve(`./src/templates/tag-list.jsx`)
})
// Paginate Sitemap - that page has list of all notes
paginate({
createPage,
items: allNotes,
itemsPerPage: 10,
pathPrefix: '/sitemap',
component: path.resolve('./src/templates/sitemap.jsx')
})
}
exports.createSchemaCustomization = ({ actions }) => {
const { createTypes } = actions
const typeDefs = `
"""
Markdown Node
"""
type MarkdownRemark implements Node @infer {
frontmatter: Frontmatter
}
"""
Markdown Frontmatter
"""
type Frontmatter @infer {
title: String
date: Date @dateformat
tags: [String]
aliases: [String]
slug: String
}
`
createTypes(typeDefs)
}
function findReferences( content ) {
// Handles both [[Note Title]] and [[Note Title|text to show]] formats
const linkRegex = /\[\[([^\]\|]+)(\|.+)?\]\]/g;
const links = [...content.matchAll(linkRegex)]
const matchedNotes = links.map( lnk => lnk[1] )
const uniqueNotes = _.uniqWith(matchedNotes, (a,b) => a.toLowerCase() === b.toLowerCase()) // Returns only the unique notes - in an case insensitive manner
// :TODO: Send a bit of text around the link back as well. Can be used in back links for context.
// :TODO: This will break if custom slug is used.
// :TODO: Handle # in the link - eg [[Note Title#section-3]]
return matchedNotes
}
// This makes the keys case insensitive. [Permenent Notes] and [permenant notes] should be treated the same.
function getPreExistingTitle(title, obj) {
const key = Object.keys(obj).find(key => key.toLowerCase() === title.toLowerCase())
return key
}