diff --git a/docs/gatsby/api-reference/ocular-config.md b/docs/gatsby/api-reference/ocular-config.md index 79cfa571..7035e6ed 100644 --- a/docs/gatsby/api-reference/ocular-config.md +++ b/docs/gatsby/api-reference/ocular-config.md @@ -18,6 +18,7 @@ | `EXAMPLES` | `Array` | See below | | `INDEX_PAGE_URL` | `String` | Optional URL to a replacement component for the home page. | | `DOC_PAGE_URL` | `String` | Optional URL to a replacement component for doc pages. | +| `DOC_FOLDERS` | `Array` | A set of paths to the doc folders to source all markdown files. | | `EXAMPLE_GALLERY_PAGE_URL` | `String` | Optional URL to a replacement component for the example gallery page (`/examples`). | | `EXAMPLE_PAGE_URL` | `String` | Optional URL to a replacement component for the default example page. Normally `EXAMPLES[].componentUrl` is used instead. | diff --git a/modules/gatsby/src/gatsby-config/config-schema.json b/modules/gatsby/src/gatsby-config/config-schema.json index 56a25371..3d997e75 100644 --- a/modules/gatsby/src/gatsby-config/config-schema.json +++ b/modules/gatsby/src/gatsby-config/config-schema.json @@ -15,6 +15,17 @@ } }, + "DOC_FOLDERS": { + "arrayValidate": { + "allowEmpty": true, + "constraint": { + "anyString": { + "message": "should be the local path to the doc folder." + } + } + } + }, + "ROOT_FOLDER": { "anyString": { "allowEmpty": true, diff --git a/modules/gatsby/src/gatsby-config/get-gatsby-config.js b/modules/gatsby/src/gatsby-config/get-gatsby-config.js index 36848679..ec9cb186 100644 --- a/modules/gatsby/src/gatsby-config/get-gatsby-config.js +++ b/modules/gatsby/src/gatsby-config/get-gatsby-config.js @@ -6,7 +6,8 @@ const CONFIG_SCHEMA = require('./config-schema'); const defaults = { logLevel: 3, - DOC_FOLDER: '/docs', + DOC_FOLDER: '', + DOC_FOLDERS: [], ROOT_FOLDER: './', DIR_NAME: 'website', EXAMPLES: [], @@ -108,15 +109,6 @@ module.exports = function getGatsbyConfig(config) { } }, - // Generates gatsby nodes for markdown files and JSON file in the in the docs folder - { - resolve: 'gatsby-source-filesystem', - options: { - name: 'docs', - path: paddedConfig.DOC_FOLDER - } - }, - // Transforms markdown (.md) nodes, converting the raw markdown to HTML { resolve: 'gatsby-transformer-remark', @@ -323,6 +315,30 @@ module.exports = function getGatsbyConfig(config) { // conditional plug-ins - only added depending on options on config + // Generates gatsby nodes for markdown files and JSON file in the in the docs folder + if (paddedConfig.DOC_FOLDER) { + gatsbyConfig.plugins.push({ + resolve: 'gatsby-source-filesystem', + options: { + name: 'docs', + path: paddedConfig.DOC_FOLDER + } + }); + } + + if (paddedConfig.DOC_FOLDERS && paddedConfig.DOC_FOLDERS.length > 0) { + // Generates gatsby nodes for markdown files and JSON file in the in the docs folder + paddedConfig.DOC_FOLDERS.forEach(folderPath => { + gatsbyConfig.plugins.push({ + resolve: 'gatsby-source-filesystem', + options: { + name: 'docs', + path: folderPath + } + }); + }) + } + if (paddedConfig.DIR_NAME) { // Generates gatsby nodes for files in the website's src folder gatsbyConfig.plugins.push({ diff --git a/modules/gatsby/src/gatsby-node/process-nodes/process-nodes-markdown.js b/modules/gatsby/src/gatsby-node/process-nodes/process-nodes-markdown.js index 0898cbe3..5f71b567 100644 --- a/modules/gatsby/src/gatsby-node/process-nodes/process-nodes-markdown.js +++ b/modules/gatsby/src/gatsby-node/process-nodes/process-nodes-markdown.js @@ -50,12 +50,23 @@ module.exports.processNewMarkdownNode = function processNewMarkdownNode( // Update path let relPath = node.fields.slug; if (node.fileAbsolutePath) { - const index = node.fileAbsolutePath.indexOf('docs'); - if (index !== -1) { - relPath = node.fileAbsolutePath.slice(index); + + const {ocularConfig} = global; + if (ocularConfig.DOC_FOLDER) { + const src = path.resolve(ocularConfig.DOC_FOLDER); + const pathBeforeDir = src.substr(0, src.lastIndexOf('/') + 1); + relPath = node.fileAbsolutePath.replace(pathBeforeDir, ''); + } else if (ocularConfig.DOC_FOLDERS) { + const index = ocularConfig.DOC_FOLDERS.findIndex( + folder => node.fileAbsolutePath.includes(path.resolve(folder)) + ); + if (index !== -1) { + const src = path.resolve(ocularConfig.DOC_FOLDERS[index]); + const pathBeforeDir = src.substr(0, src.lastIndexOf('/') + 1); + relPath = node.fileAbsolutePath.replace(pathBeforeDir, ''); + } } - // relPath = path.relative(siteConfig.ROOT_FOLDER, node.fileAbsolutePath); const basename = path.basename(relPath, '.md'); const dirname = path.dirname(relPath); relPath = basename === 'README' ? dirname : `${dirname}/${basename}`; diff --git a/modules/gatsby/src/utils/validate-config.js b/modules/gatsby/src/utils/validate-config.js index 1d2667de..78702064 100644 --- a/modules/gatsby/src/utils/validate-config.js +++ b/modules/gatsby/src/utils/validate-config.js @@ -56,6 +56,9 @@ validate.validators.arrayValidate = function arrayValidate( key ) { const {allowEmpty, constraint} = options; + if (!value && allowEmpty) { + return null; + } // check value is array if (!validate.isArray(value)) { return `${key} needs to be an array.`; @@ -64,7 +67,12 @@ validate.validators.arrayValidate = function arrayValidate( return `${key} cannot be empty.`; } // check every element in the array - const messages = value.map(v => validate(v, constraint)).filter(Boolean); + const messages = value.map(v => { + if (validate.isObject(v)) { + return validate(v, constraint); + } + return validate.single(v, constraint); + }).filter(Boolean); if (messages.length > 0) { // consolidate error messages of each element return messages.map((m, idx) => { @@ -117,15 +125,19 @@ validate.validators.requiredForGithubProject = function prerequisite( return null; }; +const WILL_DEPRECATED = ['DOC_FOLDER']; + // validate the config and return a list of warnings. module.exports = function validateConfig(config, constraints) { // check unused/deprecated config const unusedProperties = Object.keys(config).filter(key => !constraints[key]); + const deprecatedProperties = Object.keys(config).filter(key => WILL_DEPRECATED.includes(key)); // check config, validate function will return a object with corresponding warnings. // ex: {GITHUB_KEY: ['must be provided if your project is hosted on Github.']} const messages = validate(config, constraints) || {}; const allMessages = [ ...unusedProperties.map(key => `${key} is not used in the gatsby config.`), + ...deprecatedProperties.map(key => `${key} will be deprecated soon.`), ...Object.keys(messages).map(key => messages[key].toString()) ]; // print out all warnings diff --git a/modules/gatsby/test/utils/validate-config.spec.js b/modules/gatsby/test/utils/validate-config.spec.js index fb38c75c..1b40a414 100644 --- a/modules/gatsby/test/utils/validate-config.spec.js +++ b/modules/gatsby/test/utils/validate-config.spec.js @@ -5,7 +5,7 @@ import CONFIG_SCHEMA from '../../src/gatsby-config/config-schema'; const GOOD_CONFIG = { logLevel: 4, - DOC_FOLDER: `./docs/`, + DOC_FOLDERS: [], ROOT_FOLDER: `/`, DIR_NAME: '/', EXAMPLES: [], @@ -51,22 +51,34 @@ test('validateConfig', t => { t.deepEquals( validateConfig({}, CONFIG_SCHEMA), [ - "Examples can't be blank,Examples EXAMPLES needs to be an array.", + 'Examples can\'t be blank', 'Docs DOCS needs to be an object.', - "Project type can't be blank", - "Project url can't be blank", - "Project desc can't be blank,Project desc should be the project's description", + 'Project type can\'t be blank', + 'Project url can\'t be blank', + 'Project desc can\'t be blank,Project desc should be the project\'s description', 'Path prefix should be the prefix added to all paths on the site', - 'Projects PROJECTS needs to be an array.', - "Home heading can't be blank,Home heading should be ...", - "Home bullets can't be blank,Home bullets HOME_BULLETS needs to be an array.", + 'Home heading can\'t be blank,Home heading should be ...', + 'Home bullets can\'t be blank,Home bullets HOME_BULLETS needs to be an array.', 'Theme overrides THEME_OVERRIDES needs to be an array.', - "Additional links can't be blank,Additional links ADDITIONAL_LINKS needs to be an array.", + 'Additional links can\'t be blank', 'Webpack webpack needs to be an object.' ], 'Get all errors when config is empty' ); + // will deprecated configs + t.deepEquals( + validateConfig( + { + ...GOOD_CONFIG, + DOC_FOLDER: './docs' + }, + CONFIG_SCHEMA + ), + ['DOC_FOLDER will be deprecated soon.'], + 'Check deprecated configs' + ); + // logLevel t.deepEquals( validateConfig(