diff --git a/gatsby-node.js b/gatsby-node.js index 8f64c729..fb7abe1b 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -1,24 +1,40 @@ import people from './src/data.js'; -import { tags, countries, devices } from './src/util/stats'; +import { tags, countries, devices, normalizeTag } from './src/util/stats'; + +function unique(arr) { + return Array.from(new Set(arr)); +} function sourceNodes({ actions, createNodeId, createContentDigest }) { + const normalizedTagMap = tags().reduce((acc, tag) => { + const normalizedTag = normalizeTag(tag.name); + acc[normalizedTag] = tag.name; + return acc; + }, {}); // Add People to the GraphQL API, we randomize the data on each build so no one gets their feelings hurt people .sort(() => Math.random() - 0.5) .forEach(person => { + const normalizedPerson = { + ...person, + // Clean out people that added basically the same tags twice + tags: unique( + person.tags.map(tag => normalizedTagMap[normalizeTag(tag)] || tag) + ), + }; const nodeMeta = { - id: createNodeId(`person-${person.name}`), + id: createNodeId(`person-${normalizedPerson.name}`), parent: null, children: [], internal: { type: `Person`, mediaType: `text/html`, - content: JSON.stringify(person), - contentDigest: createContentDigest(person), + content: JSON.stringify(normalizedPerson), + contentDigest: createContentDigest(normalizedPerson), }, }; - actions.createNode({ ...person, ...nodeMeta }); + actions.createNode({ ...normalizedPerson, ...nodeMeta }); }); // Add tags to GraphQL API diff --git a/src/util/stats.js b/src/util/stats.js index d41e05d8..3a8d9fd2 100644 --- a/src/util/stats.js +++ b/src/util/stats.js @@ -12,6 +12,23 @@ function countInstances(acc, tag) { return acc; } +export function normalizeTag(tag) { + return ( + tag + // Common mispellings currently seen in the data + // Do we want to go this far? + .replace(/frontend/i, 'Front End') + .replace(/backend/i, 'Back End') + .replace(/fullstack/i, 'Full Stack') + .replace(/a11y/i, 'Accessibility') + .replace(/next.?js/i, 'Next') + .replace(/react.?js/i, 'React') + + // Or is lowercase enough? + .toLowerCase() + ); +} + export function countries() { const data = people .map(person => ({ @@ -48,7 +65,25 @@ export function tags() { .filter(([, count]) => count >= 3) .map(([name, count]) => ({ name, count })); - return [{ name: 'all', count: people.length }, ...tags]; + const lowercaseTagMap = tags.reduce((acc, tag) => { + const normalizedName = normalizeTag(tag.name); + const currentCount = acc[normalizedName] || 0; + acc[normalizedName] = currentCount + tag.count; + return acc; + }, {}); + + // Merge tags like "JavaScript" and "Javascript" based on the + // count… Event though it's obviously JavaScript! + const normalizedTags = tags.reduce((acc, { name }) => { + const normalizedName = normalizeTag(name); + if (typeof lowercaseTagMap[normalizedName] !== 'undefined') { + acc.push({ name, count: lowercaseTagMap[normalizedName] }); + delete lowercaseTagMap[normalizedName]; + } + return acc; + }, []); + + return [{ name: 'all', count: people.length }, ...normalizedTags]; } export function devices() {