diff --git a/include/config.js b/include/config.js index 5ac6220..76f1846 100644 --- a/include/config.js +++ b/include/config.js @@ -4,71 +4,104 @@ const path = require('path'); const util = require('util'); const crypto = require('crypto'); const logger = require('hexo-log')(); +const yaml = require('hexo-component-inferno/lib/util/yaml'); const { Migrator } = require('hexo-component-inferno/lib/core/migrate'); +const { SchemaLoader } = require('hexo-component-inferno/lib/core/schema'); +const { yellow } = require('./util/console'); -module.exports = hexo => { +function loadThemeConfig(hexo, cfgPaths) { + const configs = cfgPaths.map(cfgPath => fs.readFileSync(cfgPath)) + .map(cfgPath => yaml.parse(cfgPath)); + return Object.assign({}, ...configs, hexo.config.theme_config); +} + +function generateThemeConfigFile(schema, cfgPath) { + const defaultValue = schema.getDefaultValue(); + fs.writeFileSync(cfgPath, defaultValue.toYaml()); +} + +function hashConfigFile(cfgPath) { + const content = fs.readFileSync(cfgPath); + return crypto.createHash('md5').update(content).digest('hex'); +} + +function checkConfig(hexo) { if (!process.argv.includes('--icarus-dont-check-config')) { - const SCHEMA_ROOT = path.join(hexo.theme_dir, 'include/schema/'); - const CONFIG_PATH = path.join(hexo.theme_dir, '_config.yml'); + logger.info('=== Checking theme configurations ==='); - const yaml = require('hexo-component-inferno/lib/util/yaml'); - const { SchemaLoader } = require('hexo-component-inferno/lib/core/schema'); - const loader = SchemaLoader.load(require(path.join(SCHEMA_ROOT, 'config.json')), SCHEMA_ROOT); + const siteCfgFile = path.join(hexo.base_dir, '_config.yml'); + const themeSiteCfg = path.join(hexo.base_dir, '_config.icarus.yml'); + const themeDirCfg = path.join(hexo.theme_dir, '_config.yml'); + const themeCfgPaths = [themeDirCfg, themeSiteCfg].filter(cfgPath => fs.existsSync(cfgPath)); + const themeSiteCfgExample = themeSiteCfg + '.example'; + + const schemaDir = path.join(hexo.theme_dir, 'include/schema/'); + const loader = SchemaLoader.load(require(path.join(schemaDir, 'config.json')), schemaDir); const schema = loader.getSchema('/config.json'); - logger.info('=== Checking the configuration file ==='); - // Generate config file if not exist if (!process.argv.includes('--icarus-dont-generate-config')) { - if (!fs.existsSync(CONFIG_PATH)) { - logger.warn(`${CONFIG_PATH} is not found. We are creating one for you...`); - logger.info('You may add \'--icarus-dont-generate-config\' to prevent creating the configuration file.'); - const defaultValue = schema.getDefaultValue(); - fs.writeFileSync(CONFIG_PATH, defaultValue.toYaml()); - logger.info(`${CONFIG_PATH} created successfully.`); + if (!themeCfgPaths.length) { + logger.warn('None of the following configuration files is found:'); + logger.warn(`- ${yellow(themeSiteCfg)}`); + logger.warn(`- ${yellow(themeDirCfg)}`); + logger.info('Generating theme configuration file...'); + generateThemeConfigFile(schema, themeSiteCfg); + themeCfgPaths.push(themeSiteCfg); + logger.info(`${yellow(themeSiteCfg)} created successfully.`); + logger.info('To skip configuration generation, use "--icarus-dont-generate-config".'); } } - try { - const cfgStr = fs.readFileSync(CONFIG_PATH); - let cfg = yaml.parse(cfgStr); - // Check config version - if (!process.argv.includes('--icarus-dont-upgrade-config')) { - const head = require(path.join(hexo.theme_dir, 'include/migration/head')); - const migrator = new Migrator(head); - // Upgrade config - if (migrator.isOudated(cfg.version)) { - logger.info(`Your configuration file is outdated (${cfg.version} < ${migrator.getLatestVersion()}). ` - + 'Trying to upgrade it...'); - // Backup old config - const hash = crypto.createHash('sha256').update(cfgStr).digest('hex'); - const backupPath = CONFIG_PATH + '.' + hash.substring(0, 16); - fs.writeFileSync(backupPath, cfgStr); - logger.info(`Current configurations are written up to ${backupPath}`); - // Migrate config - cfg = migrator.migrate(cfg); - // Save config - fs.writeFileSync(CONFIG_PATH, yaml.stringify(cfg)); - logger.info(`${CONFIG_PATH} upgraded successfully.`); - const defaultValue = schema.getDefaultValue(); - fs.writeFileSync(CONFIG_PATH + '.example', defaultValue.toYaml()); - logger.info(`We also created an example at ${CONFIG_PATH + '.example'} for your reference.`); - } - } + let cfg = loadThemeConfig(hexo, themeCfgPaths); - // Check config file against schemas - const result = schema.validate(cfg); - if (result !== true) { - logger.warn('Configuration file failed one or more checks.'); - logger.warn('Icarus may still run, but you will encounter unexcepted results.'); - logger.warn('Here is some information for you to correct the configuration file.'); - logger.warn(util.inspect(result)); + if (!process.argv.includes('--icarus-dont-upgrade-config')) { + const migrator = new Migrator(require(path.join(hexo.theme_dir, 'include/migration/head'))); + if (cfg.version && migrator.isOudated(cfg.version)) { + logger.warn(`Your theme configuration is outdated (${cfg.version} < ${migrator.getLatestVersion()}).`); + logger.info('To skip the configuration upgrade, use "--icarus-dont-upgrade-config".'); + + logger.info('Backing up theme configuration files...'); + for (const cfgPath of themeCfgPaths) { + const backupPath = cfgPath + '.' + hashConfigFile(cfgPath); + const relCfgPath = path.relative(hexo.base_dir, cfgPath); + const relBackupPath = path.relative(hexo.base_dir, backupPath); + fs.renameSync(cfgPath, backupPath); + logger.info(`${yellow(relCfgPath)} => ${yellow(relBackupPath)}`); + } + + logger.info('Upgrading theme configurations...'); + cfg = migrator.migrate(cfg); + fs.writeFileSync(themeSiteCfg, yaml.stringify(cfg)); + logger.info(`Theme configurations are written to ${yellow(themeSiteCfg)}.`); + + generateThemeConfigFile(schema, themeSiteCfgExample); + logger.info(`Example configurations is at ${yellow(themeSiteCfgExample)}.`); } - } catch (e) { - logger.error(e); - logger.error(`Failed to load the configuration file ${CONFIG_PATH}.`); - logger.error('Please add \'--icarus-dont-check-config\' to your Hexo command if you'); - logger.error('wish to skip the config file checking.'); - process.exit(-1); + } + + const validation = schema.validate(cfg); + if (validation !== true) { + logger.warn('Theme configurations failed one or more checks.'); + logger.warn('Icarus may still run, but you will encounter unexcepted results.'); + logger.warn('Here is some information for you to correct the configuration file.'); + logger.warn(util.inspect(validation)); + } + + const rootCfg = yaml.parse(fs.readFileSync(siteCfgFile)); + if (rootCfg.theme_config) { + logger.warn(`"theme_config" found in ${yellow(siteCfgFile)}.`); + logger.warn(`Please remove theme configurations from ${yellow(siteCfgFile)}.`); } } +} + +module.exports = hexo => { + try { + checkConfig(hexo); + } catch (e) { + logger.error(e); + logger.error('Theme configuration checking failed.'); + logger.info('You may use \'--icarus-dont-check-config\' to skip configuration checking.'); + process.exit(-1); + } }; diff --git a/package.json b/package.json index 1312c3a..cfe2ab8 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "3.1.1", "private": true, "engines": { - "node": ">=8.3.0" + "node": ">=10.13.0" }, "description": "A simple, delicate, and modern theme for Hexo", "repository": "https://github.com/ppoffice/hexo-theme-icarus.git", @@ -27,7 +27,7 @@ "hexo-pagination": "^1.0.0", "hexo-renderer-inferno": "^0.1.3", "hexo-renderer-stylus": "^1.1.0", - "hexo-util": "^2.3.0", + "hexo-util": "^2.2.0", "inferno": "^7.3.3", "inferno-create-element": "^7.3.3", "moment": "^2.22.2",