| 
									
										
										
										
											2018-10-23 14:18:46 +01:00
										 |  |  | const { createFilePath } = require('gatsby-source-filesystem'); | 
					
						
							| 
									
										
										
										
											2021-04-28 23:11:20 +02:00
										 |  |  | // TODO: ideally we'd remove lodash and just use lodash-es, but we can't require
 | 
					
						
							|  |  |  | // es modules here.
 | 
					
						
							| 
									
										
										
										
											2020-09-10 12:40:41 +02:00
										 |  |  | const uniq = require('lodash/uniq'); | 
					
						
							| 
									
										
										
										
											2021-08-02 15:39:40 +02:00
										 |  |  | const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin'); | 
					
						
							|  |  |  | const webpack = require('webpack'); | 
					
						
							|  |  |  | const env = require('../config/env.json'); | 
					
						
							| 
									
										
										
										
											2018-10-04 14:47:55 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-13 11:27:15 +02:00
										 |  |  | const { blockNameify } = require('../utils/block-nameify'); | 
					
						
							| 
									
										
										
										
											2018-10-04 14:47:55 +01:00
										 |  |  | const { | 
					
						
							|  |  |  |   createChallengePages, | 
					
						
							|  |  |  |   createBlockIntroPages, | 
					
						
							| 
									
										
										
										
											2019-07-25 13:53:42 +05:30
										 |  |  |   createSuperBlockIntroPages | 
					
						
							| 
									
										
										
										
											2018-10-04 14:47:55 +01:00
										 |  |  | } = require('./utils/gatsby'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const createByIdentityMap = { | 
					
						
							|  |  |  |   blockIntroMarkdown: createBlockIntroPages, | 
					
						
							|  |  |  |   superBlockIntroMarkdown: createSuperBlockIntroPages | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2018-09-30 11:37:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-04 14:47:55 +01:00
										 |  |  | exports.onCreateNode = function onCreateNode({ node, actions, getNode }) { | 
					
						
							| 
									
										
										
										
											2018-09-30 11:37:19 +01:00
										 |  |  |   const { createNodeField } = actions; | 
					
						
							|  |  |  |   if (node.internal.type === 'ChallengeNode') { | 
					
						
							| 
									
										
										
										
											2020-10-01 15:07:03 +02:00
										 |  |  |     const { tests = [], block, dashedName, superBlock } = node; | 
					
						
							| 
									
										
										
										
											2021-02-23 05:22:48 +01:00
										 |  |  |     const slug = `/learn/${superBlock}/${block}/${dashedName}`; | 
					
						
							| 
									
										
										
										
											2018-09-30 11:37:19 +01:00
										 |  |  |     createNodeField({ node, name: 'slug', value: slug }); | 
					
						
							|  |  |  |     createNodeField({ node, name: 'blockName', value: blockNameify(block) }); | 
					
						
							|  |  |  |     createNodeField({ node, name: 'tests', value: tests }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (node.internal.type === 'MarkdownRemark') { | 
					
						
							| 
									
										
										
										
											2019-02-04 03:46:27 +03:00
										 |  |  |     const slug = createFilePath({ node, getNode }); | 
					
						
							| 
									
										
										
										
											2018-10-04 14:47:55 +01:00
										 |  |  |     if (!slug.includes('LICENSE')) { | 
					
						
							| 
									
										
										
										
											2019-02-04 03:46:27 +03:00
										 |  |  |       const { | 
					
						
							|  |  |  |         frontmatter: { component = '' } | 
					
						
							|  |  |  |       } = node; | 
					
						
							| 
									
										
										
										
											2018-10-04 14:47:55 +01:00
										 |  |  |       createNodeField({ node, name: 'slug', value: slug }); | 
					
						
							| 
									
										
										
										
											2019-02-04 03:46:27 +03:00
										 |  |  |       createNodeField({ node, name: 'component', value: component }); | 
					
						
							| 
									
										
										
										
											2018-09-30 11:37:19 +01:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-08 10:19:43 +02:00
										 |  |  | exports.createPages = function createPages({ graphql, actions, reporter }) { | 
					
						
							|  |  |  |   if (!env.algoliaAPIKey || !env.algoliaAppId) { | 
					
						
							|  |  |  |     if (process.env.FREECODECAMP_NODE_ENV === 'production') { | 
					
						
							|  |  |  |       throw new Error( | 
					
						
							|  |  |  |         'Algolia App id and API key are required to start the client!' | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       reporter.info( | 
					
						
							|  |  |  |         'Algolia keys missing or invalid. Required for search to yield results.' | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-11-29 21:11:31 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-08 23:22:25 +03:00
										 |  |  |   if (!env.stripePublicKey) { | 
					
						
							|  |  |  |     if (process.env.FREECODECAMP_NODE_ENV === 'production') { | 
					
						
							|  |  |  |       throw new Error('Stripe public key is required to start the client!'); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       reporter.info( | 
					
						
							|  |  |  |         'Stripe public key is missing or invalid. Required for Stripe integration.' | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-30 11:37:19 +01:00
										 |  |  |   const { createPage } = actions; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return new Promise((resolve, reject) => { | 
					
						
							|  |  |  |     // Query for all markdown 'nodes' and for the slug we previously created.
 | 
					
						
							|  |  |  |     resolve( | 
					
						
							|  |  |  |       graphql(`
 | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2018-10-04 14:47:55 +01:00
										 |  |  |           allChallengeNode( | 
					
						
							|  |  |  |             sort: { fields: [superOrder, order, challengeOrder] } | 
					
						
							|  |  |  |           ) { | 
					
						
							| 
									
										
										
										
											2018-09-30 11:37:19 +01:00
										 |  |  |             edges { | 
					
						
							|  |  |  |               node { | 
					
						
							|  |  |  |                 block | 
					
						
							|  |  |  |                 challengeType | 
					
						
							|  |  |  |                 fields { | 
					
						
							|  |  |  |                   slug | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 id | 
					
						
							|  |  |  |                 order | 
					
						
							|  |  |  |                 required { | 
					
						
							|  |  |  |                   link | 
					
						
							|  |  |  |                   src | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2018-10-04 14:47:55 +01:00
										 |  |  |                 challengeOrder | 
					
						
							| 
									
										
										
										
											2018-09-30 11:37:19 +01:00
										 |  |  |                 superBlock | 
					
						
							|  |  |  |                 superOrder | 
					
						
							|  |  |  |                 template | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           allMarkdownRemark { | 
					
						
							|  |  |  |             edges { | 
					
						
							|  |  |  |               node { | 
					
						
							|  |  |  |                 fields { | 
					
						
							|  |  |  |                   slug | 
					
						
							| 
									
										
										
										
											2018-10-23 14:18:46 +01:00
										 |  |  |                   nodeIdentity | 
					
						
							| 
									
										
										
										
											2019-02-04 03:46:27 +03:00
										 |  |  |                   component | 
					
						
							| 
									
										
										
										
											2018-09-30 11:37:19 +01:00
										 |  |  |                 } | 
					
						
							|  |  |  |                 frontmatter { | 
					
						
							|  |  |  |                   block | 
					
						
							|  |  |  |                   superBlock | 
					
						
							|  |  |  |                   title | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2018-10-04 14:47:55 +01:00
										 |  |  |                 htmlAst | 
					
						
							|  |  |  |                 id | 
					
						
							|  |  |  |                 excerpt | 
					
						
							| 
									
										
										
										
											2018-09-30 11:37:19 +01:00
										 |  |  |               } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       `).then(result => {
 | 
					
						
							|  |  |  |         if (result.errors) { | 
					
						
							|  |  |  |           console.log(result.errors); | 
					
						
							| 
									
										
										
										
											2018-10-23 14:18:46 +01:00
										 |  |  |           return reject(result.errors); | 
					
						
							| 
									
										
										
										
											2018-09-30 11:37:19 +01:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Create challenge pages.
 | 
					
						
							| 
									
										
										
										
											2020-05-28 17:26:19 +02:00
										 |  |  |         result.data.allChallengeNode.edges.forEach( | 
					
						
							|  |  |  |           createChallengePages(createPage) | 
					
						
							| 
									
										
										
										
											2018-09-30 11:37:19 +01:00
										 |  |  |         ); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-10 12:40:41 +02:00
										 |  |  |         const blocks = uniq( | 
					
						
							|  |  |  |           result.data.allChallengeNode.edges.map(({ node: { block } }) => block) | 
					
						
							|  |  |  |         ).map(block => blockNameify(block)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const superBlocks = uniq( | 
					
						
							|  |  |  |           result.data.allChallengeNode.edges.map( | 
					
						
							|  |  |  |             ({ node: { superBlock } }) => superBlock | 
					
						
							|  |  |  |           ) | 
					
						
							| 
									
										
										
										
											2021-02-13 06:06:04 +01:00
										 |  |  |         ); | 
					
						
							| 
									
										
										
										
											2020-09-10 12:40:41 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-30 11:37:19 +01:00
										 |  |  |         // Create intro pages
 | 
					
						
							| 
									
										
										
										
											2021-04-23 20:29:17 +01:00
										 |  |  |         // TODO: Remove allMarkdownRemark (populate from elsewhere)
 | 
					
						
							| 
									
										
										
										
											2018-10-04 14:47:55 +01:00
										 |  |  |         result.data.allMarkdownRemark.edges.forEach(edge => { | 
					
						
							|  |  |  |           const { | 
					
						
							| 
									
										
										
										
											2018-10-23 14:18:46 +01:00
										 |  |  |             node: { frontmatter, fields } | 
					
						
							| 
									
										
										
										
											2018-10-04 14:47:55 +01:00
										 |  |  |           } = edge; | 
					
						
							| 
									
										
										
										
											2018-10-23 14:18:46 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-04 14:47:55 +01:00
										 |  |  |           if (!fields) { | 
					
						
							| 
									
										
										
										
											2021-07-19 05:18:17 -07:00
										 |  |  |             return; | 
					
						
							| 
									
										
										
										
											2018-10-04 14:47:55 +01:00
										 |  |  |           } | 
					
						
							| 
									
										
										
										
											2018-10-23 14:18:46 +01:00
										 |  |  |           const { slug, nodeIdentity } = fields; | 
					
						
							| 
									
										
										
										
											2018-10-04 14:47:55 +01:00
										 |  |  |           if (slug.includes('LICENCE')) { | 
					
						
							| 
									
										
										
										
											2021-07-19 05:18:17 -07:00
										 |  |  |             return; | 
					
						
							| 
									
										
										
										
											2018-10-04 14:47:55 +01:00
										 |  |  |           } | 
					
						
							|  |  |  |           try { | 
					
						
							| 
									
										
										
										
											2020-09-10 12:40:41 +02:00
										 |  |  |             if (nodeIdentity === 'blockIntroMarkdown') { | 
					
						
							| 
									
										
										
										
											2021-07-19 05:18:17 -07:00
										 |  |  |               if (!blocks.includes(frontmatter.block)) { | 
					
						
							|  |  |  |                 return; | 
					
						
							| 
									
										
										
										
											2020-09-10 12:40:41 +02:00
										 |  |  |               } | 
					
						
							| 
									
										
										
										
											2021-07-19 05:18:17 -07:00
										 |  |  |             } else if (!superBlocks.includes(frontmatter.superBlock)) { | 
					
						
							|  |  |  |               return; | 
					
						
							| 
									
										
										
										
											2020-09-10 12:40:41 +02:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2018-10-23 14:18:46 +01:00
										 |  |  |             const pageBuilder = createByIdentityMap[nodeIdentity](createPage); | 
					
						
							| 
									
										
										
										
											2021-07-19 05:18:17 -07:00
										 |  |  |             pageBuilder(edge); | 
					
						
							| 
									
										
										
										
											2018-10-04 14:47:55 +01:00
										 |  |  |           } catch (e) { | 
					
						
							|  |  |  |             console.log(`
 | 
					
						
							| 
									
										
										
										
											2018-10-23 14:18:46 +01:00
										 |  |  |             ident: ${nodeIdentity} does not belong to a function | 
					
						
							| 
									
										
										
										
											2018-10-04 14:47:55 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |             ${frontmatter ? JSON.stringify(edge.node) : 'no frontmatter'} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             `);
 | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }); | 
					
						
							| 
									
										
										
										
											2018-09-30 11:37:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-23 14:18:46 +01:00
										 |  |  |         return null; | 
					
						
							| 
									
										
										
										
											2018-09-30 11:37:19 +01:00
										 |  |  |       }) | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-27 17:35:14 +02:00
										 |  |  | exports.onCreateWebpackConfig = ({ stage, actions }) => { | 
					
						
							| 
									
										
										
										
											2020-02-06 12:24:00 +01:00
										 |  |  |   const newPlugins = [ | 
					
						
							| 
									
										
										
										
											2021-03-26 00:43:43 +05:30
										 |  |  |     // We add the shims of the node globals to the global scope
 | 
					
						
							|  |  |  |     new webpack.ProvidePlugin({ | 
					
						
							|  |  |  |       Buffer: ['buffer', 'Buffer'] | 
					
						
							|  |  |  |     }), | 
					
						
							|  |  |  |     new webpack.ProvidePlugin({ | 
					
						
							|  |  |  |       process: 'process/browser' | 
					
						
							| 
									
										
										
										
											2020-02-06 12:24:00 +01:00
										 |  |  |     }) | 
					
						
							|  |  |  |   ]; | 
					
						
							|  |  |  |   // The monaco editor relies on some browser only globals so should not be
 | 
					
						
							|  |  |  |   // involved in SSR. Also, if the plugin is used during the 'build-html' stage
 | 
					
						
							|  |  |  |   // it overwrites the minfied files with ordinary ones.
 | 
					
						
							|  |  |  |   if (stage !== 'build-html') { | 
					
						
							| 
									
										
										
										
											2021-05-11 14:56:06 +02:00
										 |  |  |     newPlugins.push( | 
					
						
							|  |  |  |       new MonacoWebpackPlugin({ filename: '[name].worker-[contenthash].js' }) | 
					
						
							|  |  |  |     ); | 
					
						
							| 
									
										
										
										
											2020-02-06 12:24:00 +01:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-09-30 11:37:19 +01:00
										 |  |  |   actions.setWebpackConfig({ | 
					
						
							| 
									
										
										
										
											2021-03-26 00:43:43 +05:30
										 |  |  |     resolve: { | 
					
						
							|  |  |  |       fallback: { | 
					
						
							|  |  |  |         fs: false, | 
					
						
							| 
									
										
										
										
											2021-03-27 14:49:30 +01:00
										 |  |  |         path: require.resolve('path-browserify'), | 
					
						
							| 
									
										
										
										
											2021-03-26 00:43:43 +05:30
										 |  |  |         assert: require.resolve('assert'), | 
					
						
							|  |  |  |         crypto: require.resolve('crypto-browserify'), | 
					
						
							|  |  |  |         util: false, | 
					
						
							|  |  |  |         buffer: require.resolve('buffer'), | 
					
						
							|  |  |  |         stream: require.resolve('stream-browserify'), | 
					
						
							|  |  |  |         process: require.resolve('process/browser') | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2018-09-30 11:37:19 +01:00
										 |  |  |     }, | 
					
						
							| 
									
										
										
										
											2020-02-06 12:24:00 +01:00
										 |  |  |     plugins: newPlugins | 
					
						
							| 
									
										
										
										
											2018-09-30 11:37:19 +01:00
										 |  |  |   }); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | exports.onCreateBabelConfig = ({ actions }) => { | 
					
						
							|  |  |  |   actions.setBabelPlugin({ | 
					
						
							|  |  |  |     name: '@babel/plugin-proposal-function-bind' | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   actions.setBabelPlugin({ | 
					
						
							|  |  |  |     name: '@babel/plugin-proposal-export-default-from' | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   actions.setBabelPlugin({ | 
					
						
							|  |  |  |     name: 'babel-plugin-transform-imports', | 
					
						
							|  |  |  |     options: { | 
					
						
							|  |  |  |       '@freecodecamp/react-bootstrap': { | 
					
						
							|  |  |  |         transform: '@freecodecamp/react-bootstrap/lib/${member}', | 
					
						
							|  |  |  |         preventFullImport: true | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2020-03-04 15:37:06 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-21 18:50:05 +02:00
										 |  |  | exports.onCreatePage = async ({ page, actions }) => { | 
					
						
							|  |  |  |   const { createPage } = actions; | 
					
						
							|  |  |  |   // Only update the `/challenges` page.
 | 
					
						
							|  |  |  |   if (page.path.match(/^\/challenges/)) { | 
					
						
							|  |  |  |     // page.matchPath is a special key that's used for matching pages
 | 
					
						
							|  |  |  |     // with corresponding routes only on the client.
 | 
					
						
							|  |  |  |     page.matchPath = '/challenges/*'; | 
					
						
							|  |  |  |     // Update the page.
 | 
					
						
							|  |  |  |     createPage(page); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-09 19:22:20 +02:00
										 |  |  | exports.createSchemaCustomization = ({ actions }) => { | 
					
						
							|  |  |  |   const { createTypes } = actions; | 
					
						
							|  |  |  |   const typeDefs = `
 | 
					
						
							|  |  |  |     type ChallengeNode implements Node { | 
					
						
							| 
									
										
										
										
											2021-08-12 19:48:28 +01:00
										 |  |  |       challengeFiles: [FileContents] | 
					
						
							| 
									
										
										
										
											2021-06-15 10:37:13 -05:00
										 |  |  |       url: String | 
					
						
							| 
									
										
										
										
											2020-09-09 19:22:20 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |     type FileContents { | 
					
						
							| 
									
										
										
										
											2021-08-12 19:48:28 +01:00
										 |  |  |       fileKey: String | 
					
						
							| 
									
										
										
										
											2020-09-09 19:22:20 +02:00
										 |  |  |       ext: String | 
					
						
							|  |  |  |       name: String | 
					
						
							|  |  |  |       contents: String | 
					
						
							|  |  |  |       head: String | 
					
						
							|  |  |  |       tail: String | 
					
						
							|  |  |  |       editableRegionBoundaries: [Int] | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   `;
 | 
					
						
							|  |  |  |   createTypes(typeDefs); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-18 03:09:19 +02:00
										 |  |  | // TODO: this broke the React challenges, not sure why, but I'll investigate
 | 
					
						
							|  |  |  | // further and reimplement if it's possible and necessary (Oliver)
 | 
					
						
							| 
									
										
										
										
											2020-09-09 19:22:20 +02:00
										 |  |  | // I'm still not sure why, but the above schema seems to work.
 | 
					
						
							| 
									
										
										
										
											2020-03-04 15:37:06 +01:00
										 |  |  | // Typically the schema can be inferred, but not when some challenges are
 | 
					
						
							|  |  |  | // skipped (at time of writing the Chinese only has responsive web design), so
 | 
					
						
							|  |  |  | // this makes the missing fields explicit.
 | 
					
						
							| 
									
										
										
										
											2020-08-18 03:09:19 +02:00
										 |  |  | // exports.createSchemaCustomization = ({ actions }) => {
 | 
					
						
							|  |  |  | //   const { createTypes } = actions;
 | 
					
						
							|  |  |  | //   const typeDefs = `
 | 
					
						
							|  |  |  | //     type ChallengeNode implements Node {
 | 
					
						
							|  |  |  | //       question: Question
 | 
					
						
							|  |  |  | //       videoId: String
 | 
					
						
							|  |  |  | //       required: ExternalFile
 | 
					
						
							|  |  |  | //       files: ChallengeFile
 | 
					
						
							|  |  |  | //     }
 | 
					
						
							|  |  |  | //     type Question {
 | 
					
						
							|  |  |  | //       text: String
 | 
					
						
							|  |  |  | //       answers: [String]
 | 
					
						
							|  |  |  | //       solution: Int
 | 
					
						
							|  |  |  | //     }
 | 
					
						
							|  |  |  | //     type ChallengeFile {
 | 
					
						
							|  |  |  | //       indexhtml: FileContents
 | 
					
						
							|  |  |  | //       indexjs: FileContents
 | 
					
						
							|  |  |  | //       indexjsx: FileContents
 | 
					
						
							|  |  |  | //     }
 | 
					
						
							|  |  |  | //     type ExternalFile {
 | 
					
						
							|  |  |  | //       link: String
 | 
					
						
							|  |  |  | //       src: String
 | 
					
						
							|  |  |  | //     }
 | 
					
						
							|  |  |  | //     type FileContents {
 | 
					
						
							|  |  |  | //       key: String
 | 
					
						
							|  |  |  | //       ext: String
 | 
					
						
							|  |  |  | //       name: String
 | 
					
						
							|  |  |  | //       contents: String
 | 
					
						
							|  |  |  | //       head: String
 | 
					
						
							|  |  |  | //       tail: String
 | 
					
						
							|  |  |  | //     }
 | 
					
						
							|  |  |  | //   `;
 | 
					
						
							|  |  |  | //   createTypes(typeDefs);
 | 
					
						
							|  |  |  | // };
 |