diff --git a/lib/hexo/load_config.js b/lib/hexo/load_config.js index 6d0d974a43..86778a4dc2 100644 --- a/lib/hexo/load_config.js +++ b/lib/hexo/load_config.js @@ -7,6 +7,7 @@ const Source = require('./source'); const { exists, readdir } = require('hexo-fs'); const { magenta } = require('chalk'); const { deepMerge } = require('hexo-util'); +const validateConfig = require('./validate_config'); module.exports = async ctx => { if (!ctx.env.init) return; @@ -26,6 +27,8 @@ module.exports = async ctx => { ctx.config = deepMerge(ctx.config, config); config = ctx.config; + validateConfig(ctx); + ctx.config_path = configPath; config.root = config.root.replace(/\/*$/, '/'); diff --git a/lib/hexo/validate_config.js b/lib/hexo/validate_config.js new file mode 100644 index 0000000000..67cac859f7 --- /dev/null +++ b/lib/hexo/validate_config.js @@ -0,0 +1,33 @@ +'use strict'; + +module.exports = ctx => { + const { config, log } = ctx; + + log.info('Validating config'); + + // Validation for config.url && config.root + if (typeof config.url !== 'string') { + throw new TypeError(`Invalid config detected: "url" should be string, not ${typeof config.url}!`); + } + if (config.url.trim().length <= 0) { + throw new TypeError('Invalid config detected: "url" should not be empty!'); + } + + if (typeof config.root !== 'string') { + throw new TypeError(`Invalid config detected: "root" should be string, not ${typeof config.root}!`); + } + if (config.root.trim().length <= 0) { + throw new TypeError('Invalid config detected: "root" should not be empty!'); + } + + // Soft deprecate use_date_for_updated + if (typeof config.use_date_for_updated === 'boolean') { + log.warn('Deprecated config detected: "use_date_for_updated" is deprecated, please use "updated_option" instead. See https://hexo.io/docs/configuration for more details.'); + } + + // Soft deprecate external_link Boolean + if (typeof config.external_link === 'boolean') { + log.warn('Deprecated config detected: "external_link" with a Boolean value is deprecated. See https://hexo.io/docs/configuration for more details.'); + } +}; + diff --git a/test/scripts/hexo/index.js b/test/scripts/hexo/index.js index e654455d9b..94c443d65a 100644 --- a/test/scripts/hexo/index.js +++ b/test/scripts/hexo/index.js @@ -3,6 +3,7 @@ describe('Core', () => { require('./hexo'); require('./load_config'); + require('./validate_config'); require('./load_database'); require('./load_plugins'); require('./load_theme_config'); diff --git a/test/scripts/hexo/validate_config.js b/test/scripts/hexo/validate_config.js new file mode 100644 index 0000000000..c3813ead63 --- /dev/null +++ b/test/scripts/hexo/validate_config.js @@ -0,0 +1,108 @@ +'use strict'; + +const { spy } = require('sinon'); + +describe('Validate config', () => { + const Hexo = require('../../../lib/hexo'); + const hexo = new Hexo(); + const validateConfig = require('../../../lib/hexo/validate_config'); + const defaultConfig = require('../../../lib/hexo/default_config'); + let logSpy; + + beforeEach(() => { + logSpy = spy(); + hexo.config = JSON.parse(JSON.stringify(defaultConfig)); + hexo.log.warn = logSpy; + hexo.log.info = spy(); + }); + + it('config.url - undefined', () => { + delete hexo.config.url; + + try { + validateConfig(hexo); + should.fail(); + } catch (e) { + e.name.should.eql('TypeError'); + e.message.should.eql('Invalid config detected: "url" should be string, not undefined!'); + } + }); + + it('config.url - wrong type', () => { + hexo.config.url = true; + + try { + validateConfig(hexo); + should.fail(); + } catch (e) { + e.name.should.eql('TypeError'); + e.message.should.eql('Invalid config detected: "url" should be string, not boolean!'); + } + }); + + it('config.url - empty', () => { + hexo.config.url = ' '; + + try { + validateConfig(hexo); + should.fail(); + } catch (e) { + e.name.should.eql('TypeError'); + e.message.should.eql('Invalid config detected: "url" should not be empty!'); + } + }); + + it('config.root - undefined', () => { + delete hexo.config.root; + + try { + validateConfig(hexo); + should.fail(); + } catch (e) { + e.name.should.eql('TypeError'); + e.message.should.eql('Invalid config detected: "root" should be string, not undefined!'); + } + }); + + it('config.root - wrong type', () => { + hexo.config.root = true; + + try { + validateConfig(hexo); + should.fail(); + } catch (e) { + e.name.should.eql('TypeError'); + e.message.should.eql('Invalid config detected: "root" should be string, not boolean!'); + } + }); + + it('config.root - empty', () => { + hexo.config.root = ' '; + + try { + validateConfig(hexo); + should.fail(); + } catch (e) { + e.name.should.eql('TypeError'); + e.message.should.eql('Invalid config detected: "root" should not be empty!'); + } + }); + + it('config.use_date_for_updated - depreacte', () => { + hexo.config.use_date_for_updated = true; + + validateConfig(hexo); + + logSpy.calledOnce.should.be.true; + logSpy.calledWith('Deprecated config detected: "use_date_for_updated" is deprecated, please use "updated_option" instead. See https://hexo.io/docs/configuration for more details.').should.be.true; + }); + + it('config.external_link - depreacte Boolean value', () => { + hexo.config.external_link = false; + + validateConfig(hexo); + + logSpy.calledOnce.should.be.true; + logSpy.calledWith('Deprecated config detected: "external_link" with a Boolean value is deprecated. See https://hexo.io/docs/configuration for more details.').should.be.true; + }); +});