diff --git a/packages/gatsby-transformer-yaml/README.md b/packages/gatsby-transformer-yaml/README.md index ff16754e10d94..cc5e48e336d0b 100644 --- a/packages/gatsby-transformer-yaml/README.md +++ b/packages/gatsby-transformer-yaml/README.md @@ -164,3 +164,77 @@ Which would return: ``` Please do **note** that `allLettersYaml` **will not** show up if you do not have any `.yaml` files. + +## Configuration options + +**`typeName`** [string|function][optional] + +The default naming convention documented above can be changed with +either a static string value (e.g. to be able to query all yaml with a +simple query): + +```javascript +module.exports = { + plugins: [ + { + resolve: `gatsby-transformer-yaml`, + options: { + typeName: `Yaml`, // a fixed string + }, + }, + ], +} +``` + +```graphql +{ + allYaml { + edges { + node { + value + } + } + } +} +``` + +or a function that receives the following arguments: + +- `node`: the graphql node that is being processed, e.g. a File node with + yaml content +- `object`: a single object (either an item from an array or the whole yaml content) +- `isArray`: boolean, true if `object` is part of an array + +```yaml +- level: info + message: hurray +- level: info + message: it works +- level: warning + message: look out +``` + +```javascript +module.exports = { + plugins: [ + { + resolve: `gatsby-transformer-yaml`, + options: { + typeName: ({ node, object, isArray }) => object.level, + }, + }, + ], +} +``` + +```graphql +{ + allInfo { + edges { + node { + message + } + } + } +} +``` diff --git a/packages/gatsby-transformer-yaml/src/__tests__/gatsby-node.js b/packages/gatsby-transformer-yaml/src/__tests__/gatsby-node.js index 350b191300651..7cd21f202b18f 100644 --- a/packages/gatsby-transformer-yaml/src/__tests__/gatsby-node.js +++ b/packages/gatsby-transformer-yaml/src/__tests__/gatsby-node.js @@ -69,4 +69,114 @@ describe(`Process YAML nodes correctly`, () => { expect(createParentChildLink).toHaveBeenCalledTimes(1) }) }) + + it(`correctly sets node type for array of objects`, () => + Promise.all( + [ + { + typeName: null, + expectedNodeTypes: [`TestYaml`, `TestYaml`], + }, + { + typeName: `fixed`, + expectedNodeTypes: [`fixed`, `fixed`], + }, + { + typeName: ({ node, object }) => object.funny, + expectedNodeTypes: [`yup`, `nope`], + }, + ].map( + async ({ typeName, expectedNodeTypes: [expectedOne, expectedTwo] }) => { + const data = [ + { id: `foo`, blue: true, funny: `yup` }, + { blue: false, funny: `nope` }, + ] + + node.content = yaml.safeDump(data) + node.dir = `${os.tmpdir()}/bar/` + + const createNode = jest.fn() + const createParentChildLink = jest.fn() + const actions = { createNode, createParentChildLink } + const createNodeId = jest.fn() + createNodeId.mockReturnValue(`uuid-from-gatsby`) + const createContentDigest = jest.fn().mockReturnValue(`contentDigest`) + + return onCreateNode( + { + node, + loadNodeContent, + actions, + createNodeId, + createContentDigest, + }, + { typeName } + ).then(() => { + expect(createNode).toBeCalledWith( + expect.objectContaining({ + internal: expect.objectContaining({ + type: expectedOne, + }), + }) + ) + expect(createNode).toBeCalledWith( + expect.objectContaining({ + internal: expect.objectContaining({ + type: expectedTwo, + }), + }) + ) + }) + } + ) + )) + + it(`correctly sets node type for single object`, () => + Promise.all( + [ + { + typeName: null, + expectedNodeType: `TestdirYaml`, + }, + { + typeName: `fixed`, + expectedNodeType: `fixed`, + }, + { + typeName: ({ node, object }) => object.funny, + expectedNodeType: `yup`, + }, + ].map(async ({ typeName, expectedNodeType }) => { + const data = { id: `foo`, blue: true, funny: `yup` } + + node.content = yaml.safeDump(data) + node.dir = `${os.tmpdir()}/testdir/` + + const createNode = jest.fn() + const createParentChildLink = jest.fn() + const actions = { createNode, createParentChildLink } + const createNodeId = jest.fn() + createNodeId.mockReturnValue(`uuid-from-gatsby`) + const createContentDigest = jest.fn().mockReturnValue(`contentDigest`) + + return onCreateNode( + { + node, + loadNodeContent, + actions, + createNodeId, + createContentDigest, + }, + { typeName } + ).then(() => { + expect(createNode).toBeCalledWith( + expect.objectContaining({ + internal: expect.objectContaining({ + type: expectedNodeType, + }), + }) + ) + }) + }) + )) }) diff --git a/packages/gatsby-transformer-yaml/src/gatsby-node.js b/packages/gatsby-transformer-yaml/src/gatsby-node.js index 5d675f43f7fdd..ccc7c8bba9ccb 100644 --- a/packages/gatsby-transformer-yaml/src/gatsby-node.js +++ b/packages/gatsby-transformer-yaml/src/gatsby-node.js @@ -2,13 +2,22 @@ const jsYaml = require(`js-yaml`) const _ = require(`lodash`) const path = require(`path`) -async function onCreateNode({ - node, - actions, - loadNodeContent, - createNodeId, - createContentDigest, -}) { +async function onCreateNode( + { node, actions, loadNodeContent, createNodeId, createContentDigest }, + pluginOptions +) { + function getType({ node, object, isArray }) { + if (pluginOptions && _.isFunction(pluginOptions.typeName)) { + return pluginOptions.typeName({ node, object, isArray }) + } else if (pluginOptions && _.isString(pluginOptions.typeName)) { + return pluginOptions.typeName + } else if (isArray) { + return _.upperFirst(_.camelCase(`${node.name} Yaml`)) + } else { + return _.upperFirst(_.camelCase(`${path.basename(node.dir)} Yaml`)) + } + } + function transformObject(obj, id, type) { const yamlNode = { ...obj, @@ -38,14 +47,14 @@ async function onCreateNode({ transformObject( obj, obj.id ? obj.id : createNodeId(`${node.id} [${i}] >>> YAML`), - _.upperFirst(_.camelCase(`${node.name} Yaml`)) + getType({ node, object: obj, isArray: true }) ) }) } else if (_.isPlainObject(parsedContent)) { transformObject( parsedContent, parsedContent.id ? parsedContent.id : createNodeId(`${node.id} >>> YAML`), - _.upperFirst(_.camelCase(`${path.basename(node.dir)} Yaml`)) + getType({ node, object: parsedContent, isArray: false }) ) } }