From c46a894a011564a0268cc5ecdfd14d814658d824 Mon Sep 17 00:00:00 2001 From: Yangshun Tay Date: Sat, 23 Feb 2019 11:59:44 -0800 Subject: [PATCH] chore(v2): remove hardcoded references to config filename --- v2/lib/commands/deploy.js | 10 ++- v2/lib/commands/start.js | 3 +- v2/lib/core/sitemap.js | 5 +- v2/lib/load/config.js | 124 +++++++++++++++++++++--------------- v2/lib/load/env.js | 5 +- v2/lib/load/index.js | 4 +- v2/package.json | 1 + v2/test/load/config.test.js | 8 +-- 8 files changed, 96 insertions(+), 64 deletions(-) diff --git a/v2/lib/commands/deploy.js b/v2/lib/commands/deploy.js index 671bb71992..f96277e6d0 100644 --- a/v2/lib/commands/deploy.js +++ b/v2/lib/commands/deploy.js @@ -27,14 +27,16 @@ module.exports = async function deploy(siteDir) { process.env.CURRENT_BRANCH || shell.exec('git rev-parse --abbrev-ref HEAD').stdout.trim(); - const siteConfig = loadConfig(siteDir); + const siteConfig = loadConfig.loadConfig(siteDir); const organizationName = process.env.ORGANIZATION_NAME || process.env.CIRCLE_PROJECT_USERNAME || siteConfig.organizationName; if (!organizationName) { throw new Error( - "Missing project organization name. Did you forget to define 'organizationName' in docusaurus.config.js? You may also export it via the organizationName environment variable.", + `Missing project organization name. Did you forget to define 'organizationName' in ${ + loadConfig.configFileName + }? You may also export it via the organizationName environment variable.`, ); } const projectName = @@ -43,7 +45,9 @@ module.exports = async function deploy(siteDir) { siteConfig.projectName; if (!projectName) { throw new Error( - "Missing project name. Did you forget to define 'projectName' in docusaurus.config.js? You may also export it via the projectName environment variable.", + `Missing project name. Did you forget to define 'projectName' in ${ + loadConfig.configFileName + }? You may also export it via the projectName environment variable.`, ); } diff --git a/v2/lib/commands/start.js b/v2/lib/commands/start.js index 69163fc15d..41f170445b 100644 --- a/v2/lib/commands/start.js +++ b/v2/lib/commands/start.js @@ -19,6 +19,7 @@ const portfinder = require('portfinder'); const serve = require('webpack-serve'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const load = require('../load'); +const loadConfig = require('../load/config'); const createClientConfig = require('../webpack/client'); const {applyConfigureWebpack} = require('../webpack/utils'); @@ -50,7 +51,7 @@ module.exports = async function start(siteDir, cliOptions = {}) { [ `../${docsRelativeDir}/**/*.md`, 'blog/**/*.md', - 'docusaurus.config.js', + loadConfig.configFileName, 'sidebars.json', ], { diff --git a/v2/lib/core/sitemap.js b/v2/lib/core/sitemap.js index ab3cd33701..3f821aa6aa 100644 --- a/v2/lib/core/sitemap.js +++ b/v2/lib/core/sitemap.js @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +const loadConfig = require('../load/config'); const sitemap = require('sitemap'); module.exports = async function createSitemap({ @@ -22,7 +23,9 @@ module.exports = async function createSitemap({ const {url: siteUrl} = siteConfig; if (!siteUrl) { - throw new Error('Url in docusaurus.config.js cannot be empty/undefined'); + throw new Error( + `Url in ${loadConfig.configFileName} cannot be empty/undefined`, + ); } const urls = []; diff --git a/v2/lib/load/config.js b/v2/lib/load/config.js index 13d413b146..a6a73b2073 100644 --- a/v2/lib/load/config.js +++ b/v2/lib/load/config.js @@ -6,62 +6,73 @@ */ const fs = require('fs-extra'); +const _ = require('lodash'); const path = require('path'); -module.exports = function loadConfig(siteDir, deleteCache = true) { - const configPath = path.resolve(siteDir, 'docusaurus.config.js'); +const CONFIG_FILE_NAME = 'docusaurus.config.js'; + +const REQUIRED_FIELDS = [ + 'baseUrl', + 'favicon', + 'headerLinks', + 'headerIcon', + 'organizationName', + 'projectName', + 'title', + 'tagline', + 'url', +]; + +const OPTIONAL_FIELDS = [ + 'algolia', + 'chainWebpack', + 'configureWebpack', + 'customDocsPath', + 'customFields', + 'defaultLanguage', + 'docsUrl', + 'githubHost', + 'highlight', + 'markdownPlugins', +]; + +const DEFAULT_CONFIG = { + customDocsPath: 'docs', + docsUrl: 'docs', +}; + +function formatFields(fields) { + return fields.map(field => `'${field}'`).join(', '); +} + +function loadConfig(siteDir, deleteCache = true) { + const configPath = path.resolve(siteDir, CONFIG_FILE_NAME); if (deleteCache) { delete require.cache[configPath]; } - let config = {}; + let loadedConfig = {}; if (fs.existsSync(configPath)) { - config = require(configPath); // eslint-disable-line + loadedConfig = require(configPath); // eslint-disable-line } - const requiredFields = [ - 'title', - 'tagline', - 'organizationName', - 'projectName', - 'baseUrl', - 'url', - 'headerLinks', - 'headerIcon', - 'favicon', - ]; - const optionalFields = [ - 'customDocsPath', - 'defaultLanguage', - 'highlight', - 'markdownPlugins', - 'configureWebpack', - 'chainWebpack', - 'docsUrl', - 'customFields', - 'githubHost', - 'algolia', - ]; - const missingFields = requiredFields.filter(field => !config[field]); - if (missingFields && missingFields.length > 0) { + const missingFields = REQUIRED_FIELDS.filter( + field => !_.has(loadedConfig, field), + ); + if (missingFields.length > 0) { throw new Error( - `${missingFields.join(', ')} fields are missing in docusaurus.config.js`, + `The required field(s) ${formatFields( + missingFields, + )} are missing from ${CONFIG_FILE_NAME}`, ); } - /* Fill default value */ - const defaultConfig = { - customDocsPath: 'docs', - docsUrl: 'docs', - }; - Object.keys(defaultConfig).forEach(field => { - if (!config[field]) { - config[field] = defaultConfig[field]; - } - }); + // Merge default config with loaded config. + const config = {...DEFAULT_CONFIG, ...loadedConfig}; - /* Build final headerLinks based on siteConfig */ + // Build final headerLinks based on siteConfig. const {headerLinks} = config; - // add language drop down to end if location not specified + + // Add language dropdown to end if location not specified. let languages = false; headerLinks.forEach(link => { if (link.languages) { @@ -73,7 +84,7 @@ module.exports = function loadConfig(siteDir, deleteCache = true) { } let search = false; headerLinks.forEach(link => { - // We will add search bar to end if location not specified + // Append search bar if location not specified. if (link.search) { search = true; } @@ -83,24 +94,33 @@ module.exports = function loadConfig(siteDir, deleteCache = true) { } config.headerLinks = headerLinks; - /* - User's own array of custom fields, + /* + User's own array of custom fields, e.g: if they want to include some field so they can access it later from `props.siteConfig` */ const {customFields = []} = config; - // We don't allow unused fields. - const allowedFields = [...requiredFields, ...optionalFields, ...customFields]; - const uselessFields = Object.keys(config).filter( + // Don't allow unrecognized fields. + const allowedFields = [ + ...REQUIRED_FIELDS, + ...OPTIONAL_FIELDS, + ...customFields, + ]; + const unrecognizedFields = Object.keys(config).filter( field => !allowedFields.includes(field), ); - if (uselessFields && uselessFields.length > 0) { + if (unrecognizedFields && unrecognizedFields.length > 0) { throw new Error( - `The fields ${uselessFields.join( - ', ', - )} are not recognized in docusaurus.config.js`, + `The field(s) ${formatFields( + unrecognizedFields, + )} are not recognized in ${CONFIG_FILE_NAME}`, ); } return config; +} + +module.exports = { + configFileName: CONFIG_FILE_NAME, + loadConfig, }; diff --git a/v2/lib/load/env.js b/v2/lib/load/env.js index 682d711f73..4bcf87639e 100644 --- a/v2/lib/load/env.js +++ b/v2/lib/load/env.js @@ -8,6 +8,7 @@ const fs = require('fs-extra'); const path = require('path'); const {idx} = require('./utils'); +const loadConfig = require('./config'); module.exports = function loadEnv({siteDir, siteConfig}) { // Translation @@ -36,7 +37,9 @@ module.exports = function loadEnv({siteDir, siteConfig}) { ); if (!defaultLanguage) { throw new Error( - `Please set a default language in 'docusaurus.config.js' which is enabled in 'languages.js'`, + `Please set a default language in ${ + loadConfig.configFileName + } which is enabled in 'languages.js'`, ); } translation.defaultLanguage = defaultLanguage; diff --git a/v2/lib/load/index.js b/v2/lib/load/index.js index fadb33a251..7b9068053b 100644 --- a/v2/lib/load/index.js +++ b/v2/lib/load/index.js @@ -17,9 +17,9 @@ const genRoutesConfig = require('./routes'); module.exports = async function load(siteDir) { // @tested - siteConfig - const siteConfig = loadConfig(siteDir); + const siteConfig = loadConfig.loadConfig(siteDir); await generate( - 'docusaurus.config.js', + loadConfig.configFileName, `export default ${JSON.stringify(siteConfig, null, 2)};`, ); diff --git a/v2/package.json b/v2/package.json index 7273a30fb1..b3086cbe2e 100644 --- a/v2/package.json +++ b/v2/package.json @@ -77,6 +77,7 @@ "koa-range": "^0.3.0", "koa-static": "^5.0.0", "loader-utils": "^1.1.0", + "lodash": "^4.17.11", "mini-css-extract-plugin": "^0.4.1", "portfinder": "^1.0.13", "prismjs": "^1.15.0", diff --git a/v2/test/load/config.test.js b/v2/test/load/config.test.js index 71bb677062..a3fce966d8 100644 --- a/v2/test/load/config.test.js +++ b/v2/test/load/config.test.js @@ -6,7 +6,7 @@ */ import path from 'path'; -import loadConfig from '@lib/load/config'; +import {loadConfig} from '@lib/load/config'; import loadSetup from '../loadSetup'; describe('loadConfig', () => { @@ -48,7 +48,7 @@ Object { expect(() => { loadConfig(siteDir); }).toThrowErrorMatchingInlineSnapshot( - `"tagline, organizationName, projectName, url, headerLinks, headerIcon, favicon fields are missing in docusaurus.config.js"`, + `"The required field(s) 'favicon', 'headerLinks', 'headerIcon', 'organizationName', 'projectName', 'tagline', 'url' are missing from docusaurus.config.js"`, ); }); @@ -57,7 +57,7 @@ Object { expect(() => { loadConfig(siteDir); }).toThrowErrorMatchingInlineSnapshot( - `"headerLinks, headerIcon, favicon fields are missing in docusaurus.config.js"`, + `"The required field(s) 'favicon', 'headerLinks', 'headerIcon' are missing from docusaurus.config.js"`, ); }); @@ -66,7 +66,7 @@ Object { expect(() => { loadConfig(siteDir); }).toThrowErrorMatchingInlineSnapshot( - `"title, tagline, organizationName, projectName, baseUrl, url, headerLinks, headerIcon, favicon fields are missing in docusaurus.config.js"`, + `"The required field(s) 'baseUrl', 'favicon', 'headerLinks', 'headerIcon', 'organizationName', 'projectName', 'title', 'tagline', 'url' are missing from docusaurus.config.js"`, ); }); });