Skip to content

Commit

Permalink
Allow for multiple different remark sources
Browse files Browse the repository at this point in the history
  • Loading branch information
Alexandre Kirszenberg committed Feb 8, 2019
1 parent 91341b4 commit c42671b
Show file tree
Hide file tree
Showing 5 changed files with 184 additions and 80 deletions.
5 changes: 5 additions & 0 deletions packages/gatsby-transformer-remark/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ plugins: [
{
resolve: `gatsby-transformer-remark`,
options: {

// Defaults to `() => true`
filter: node => node.sourceInstanceName === `blog`,
// Defaults to `MarkdownRemark`
type: `BlogPost`,
// CommonMark mode (default: true)
commonmark: true,
// Footnotes mode (default: true)
Expand Down
51 changes: 48 additions & 3 deletions packages/gatsby-transformer-remark/src/__tests__/extend-node.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ const {
GraphQLList,
GraphQLSchema,
} = require(`gatsby/graphql`)
const { onCreateNode } = require(`../gatsby-node`)
const { Promise } = require(`bluebird`)
const { onCreateNode, setFieldsOnGraphQLNodeType } = require(`../gatsby-node`)
const {
inferObjectStructureFromNodes,
} = require(`../../../gatsby/src/schema/infer-graphql-type`)
Expand All @@ -14,7 +15,7 @@ const extendNodeType = require(`../extend-node-type`)
async function queryResult(
nodes,
fragment,
{ types = [] } = {},
{ typeName = `MarkdownRemark`, types = [] } = {},
{ additionalParameters = {}, pluginOptions = {} }
) {
const inferredFields = inferObjectStructureFromNodes({
Expand Down Expand Up @@ -51,7 +52,7 @@ async function queryResult(
name: `LISTNODE`,
type: new GraphQLList(
new GraphQLObjectType({
name: `MarkdownRemark`,
name: typeName,
fields: markdownRemarkFields,
})
),
Expand Down Expand Up @@ -559,3 +560,47 @@ This is [a reference]
{ additionalParameters: { pathPrefix: `/prefix` } }
)
})

describe(`Adding fields to the GraphQL schema`, () => {
it(`only adds fields when the GraphQL type matches the provided type`, async () => {
const getNode = jest.fn()
const getNodesByType = jest.fn()

expect(
setFieldsOnGraphQLNodeType({
type: { name: `MarkdownRemark` },
getNode,
getNodesByType,
})
).toBeInstanceOf(Promise)

expect(
setFieldsOnGraphQLNodeType(
{ type: { name: `MarkdownRemark` }, getNode, getNodesByType },
{ type: `MarkdownRemark` }
)
).toBeInstanceOf(Promise)

expect(
setFieldsOnGraphQLNodeType(
{ type: { name: `MarkdownRemark` }, getNode, getNodesByType },
{ type: `GatsbyTestType` }
)
).toEqual({})

expect(
setFieldsOnGraphQLNodeType(
{ type: { name: `GatsbyTestType` }, getNode, getNodesByType },
{ type: `GatsbyTestType` }
)
).toBeInstanceOf(Promise)

expect(
setFieldsOnGraphQLNodeType({
type: { name: `GatsbyTestType` },
getNode,
getNodesByType,
})
).toEqual({})
})
})
44 changes: 44 additions & 0 deletions packages/gatsby-transformer-remark/src/__tests__/gatsby-node.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,50 @@ Sed bibendum sem iaculis, pellentesque leo sed, imperdiet ante. Sed consequat ma
expect(createParentChildLink).toHaveBeenCalledTimes(1)
})
})

it(`Filters nodes with the given filter function, if provided`, async () => {
const content = ``

node.content = content
node.sourceInstanceName = `gatsby-test-source`

const createNode = jest.fn()
const createParentChildLink = jest.fn()
const actions = { createNode, createParentChildLink }
const createNodeId = jest.fn()
createNodeId.mockReturnValue(`uuid-from-gatsby`)

await onCreateNode(
{
node,
loadNodeContent,
actions,
createNodeId,
},
{
filter: node =>
node.sourceInstanceName === `gatsby-other-test-source`,
}
).then(() => {
expect(createNode).toHaveBeenCalledTimes(0)
expect(createParentChildLink).toHaveBeenCalledTimes(0)
})

await onCreateNode(
{
node,
loadNodeContent,
actions,
createNodeId,
},
{
filter: node => node.sourceInstanceName === `gatsby-test-source`,
}
).then(() => {
expect(createNode).toHaveBeenCalledTimes(1)
expect(createParentChildLink).toHaveBeenCalledTimes(1)
})
})
})

describe(`process graphql correctly`, () => {
Expand Down
146 changes: 75 additions & 71 deletions packages/gatsby-transformer-remark/src/extend-node-type.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,59 @@ const safeGetCache = ({ getCache, cache }) => id => {
return getCache(id)
}

const HeadingType = new GraphQLObjectType({
name: `MarkdownHeading`,
fields: {
value: {
type: GraphQLString,
resolve(heading) {
return heading.value
},
},
depth: {
type: GraphQLInt,
resolve(heading) {
return heading.depth
},
},
},
})

const HeadingLevels = new GraphQLEnumType({
name: `HeadingLevels`,
values: {
h1: { value: 1 },
h2: { value: 2 },
h3: { value: 3 },
h4: { value: 4 },
h5: { value: 5 },
h6: { value: 6 },
},
})

const ExcerptFormats = new GraphQLEnumType({
name: `ExcerptFormats`,
values: {
PLAIN: { value: `plain` },
HTML: { value: `html` },
},
})

const wordCountType = new GraphQLObjectType({
name: `wordCount`,
fields: {
paragraphs: {
type: GraphQLInt,
},
sentences: {
type: GraphQLInt,
},
words: {
type: GraphQLInt,
},
},
})

/**
* Map that keeps track of generation of AST to not generate it multiple
* times in parallel.
Expand All @@ -87,29 +140,31 @@ module.exports = (
reporter,
...rest
},
pluginOptions
{
type: typeName = `MarkdownRemark`,
plugins = [],
blocks,
commonmark = true,
footnotes = true,
gfm = true,
pedantic = true,
tableOfContents = {
heading: null,
maxDepth: 6,
},
...grayMatterOptions
} = {}
) => {
if (type.name !== `MarkdownRemark`) {
if (type.name !== typeName) {
return {}
}
pluginsCacheStr = pluginOptions.plugins.map(p => p.name).join(``)
pluginsCacheStr = plugins.map(p => p.name).join(``)
pathPrefixCacheStr = pathPrefix || ``

const getCache = safeGetCache({ cache, getCache: possibleGetCache })

return new Promise((resolve, reject) => {
// Setup Remark.
const {
blocks,
commonmark = true,
footnotes = true,
gfm = true,
pedantic = true,
tableOfContents = {
heading: null,
maxDepth: 6,
},
} = pluginOptions
const tocOptions = tableOfContents
const remarkOptions = {
commonmark,
Expand All @@ -122,7 +177,7 @@ module.exports = (
}
let remark = new Remark().data(`settings`, remarkOptions)

for (let plugin of pluginOptions.plugins) {
for (let plugin of plugins) {
const requiredPlugin = require(plugin.resolve)
if (_.isFunction(requiredPlugin.setParserPlugins)) {
for (let parserPlugin of requiredPlugin.setParserPlugins(
Expand Down Expand Up @@ -167,7 +222,7 @@ module.exports = (
fileNodes = getNodesByType(`File`)
}
// Use Bluebird's Promise function "each" to run remark plugins serially.
await Promise.each(pluginOptions.plugins, plugin => {
await Promise.each(plugins, plugin => {
const requiredPlugin = require(plugin.resolve)
if (_.isFunction(requiredPlugin.mutateSource)) {
return requiredPlugin.mutateSource(
Expand Down Expand Up @@ -235,7 +290,7 @@ module.exports = (
fileNodes = getNodesByType(`File`)
}
// Use Bluebird's Promise function "each" to run remark plugins serially.
await Promise.each(pluginOptions.plugins, plugin => {
await Promise.each(plugins, plugin => {
const requiredPlugin = require(plugin.resolve)
if (_.isFunction(requiredPlugin)) {
return requiredPlugin(
Expand Down Expand Up @@ -362,44 +417,6 @@ module.exports = (
}
}

const HeadingType = new GraphQLObjectType({
name: `MarkdownHeading`,
fields: {
value: {
type: GraphQLString,
resolve(heading) {
return heading.value
},
},
depth: {
type: GraphQLInt,
resolve(heading) {
return heading.depth
},
},
},
})

const HeadingLevels = new GraphQLEnumType({
name: `HeadingLevels`,
values: {
h1: { value: 1 },
h2: { value: 2 },
h3: { value: 3 },
h4: { value: 4 },
h5: { value: 5 },
h6: { value: 6 },
},
})

const ExcerptFormats = new GraphQLEnumType({
name: `ExcerptFormats`,
values: {
PLAIN: { value: `plain` },
HTML: { value: `html` },
},
})

return resolve({
html: {
type: GraphQLString,
Expand Down Expand Up @@ -434,13 +451,13 @@ module.exports = (
},
async resolve(markdownNode, { format, pruneLength, truncate }) {
if (format === `html`) {
if (pluginOptions.excerpt_separator) {
if (grayMatterOptions.excerpt_separator) {
const fullAST = await getHTMLAst(markdownNode)
const excerptAST = cloneTreeUntil(
fullAST,
({ nextNode }) =>
nextNode.type === `raw` &&
nextNode.value === pluginOptions.excerpt_separator
nextNode.value === grayMatterOptions.excerpt_separator
)
return hastToHTML(excerptAST, {
allowDangerousHTML: true,
Expand Down Expand Up @@ -558,20 +575,7 @@ module.exports = (
},
// TODO add support for non-latin languages https://github.com/wooorm/remark/issues/251#issuecomment-296731071
wordCount: {
type: new GraphQLObjectType({
name: `wordCount`,
fields: {
paragraphs: {
type: GraphQLInt,
},
sentences: {
type: GraphQLInt,
},
words: {
type: GraphQLInt,
},
},
}),
type: wordCountType,
resolve(markdownNode) {
let counts = {}

Expand Down
18 changes: 12 additions & 6 deletions packages/gatsby-transformer-remark/src/on-node-create.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,36 @@ const crypto = require(`crypto`)

module.exports = async function onCreateNode(
{ node, loadNodeContent, actions, createNodeId, reporter },
pluginOptions
{
plugins = null,
filter = () => true,
type = `MarkdownRemark`,
...grayMatterOptions
} = {}
) {
const { createNode, createParentChildLink } = actions

// We only care about markdown content.
if (
node.internal.mediaType !== `text/markdown` &&
node.internal.mediaType !== `text/x-markdown`
(node.internal.mediaType !== `text/markdown` &&
node.internal.mediaType !== `text/x-markdown`) ||
!filter(node)
) {
return
}

const content = await loadNodeContent(node)

try {
const data = grayMatter(content, pluginOptions)
const data = grayMatter(content, grayMatterOptions)

const markdownNode = {
id: createNodeId(`${node.id} >>> MarkdownRemark`),
id: createNodeId(`${node.id} >>> ${type}`),
children: [],
parent: node.id,
internal: {
content: data.content,
type: `MarkdownRemark`,
type,
},
}

Expand Down

0 comments on commit c42671b

Please sign in to comment.