hexo-theme-amane/includes/common/ConfigGenerator.js

104 lines
3.1 KiB
JavaScript

const yaml = require('js-yaml');
const Type = require('js-yaml/lib/js-yaml/type');
const Schema = require('js-yaml/lib/js-yaml/schema');
const { is, descriptors } = require('./utils');
const { doc, type, requires, defaultValue } = descriptors;
const UNDEFINED = Symbol('undefined');
// output null as empty in yaml
const YAML_SCHEMA = new Schema({
include: [
require('js-yaml/lib/js-yaml/schema/default_full')
],
implicit: [
new Type('tag:yaml.org,2002:null', {
kind: 'scalar',
resolve(data) {
if (data === null) {
return true;
}
const max = data.length;
return (max === 1 && data === '~') ||
(max === 4 && (data === 'null' || data === 'Null' || data === 'NULL'));
},
construct: () => null,
predicate: object => object === null,
represent: {
empty: function () { return ''; }
},
defaultStyle: 'empty'
})
]
});
function appendDoc(spec, defaults) {
if (defaults === null) {
return null;
}
if (is.array(defaults) && spec.hasOwnProperty('*')) {
return defaults.map(value => appendDoc(spec['*'], value));
} else if (is.object(defaults)) {
const _defaults = {};
for (let key in defaults) {
if (spec.hasOwnProperty(key) && spec[key].hasOwnProperty(doc)) {
let i = 0;
for (let line of spec[key][doc].split('\n')) {
_defaults['#' + key + i++] = line;
}
}
_defaults[key] = appendDoc(spec.hasOwnProperty(key) ? spec[key] : {}, defaults[key]);
}
return _defaults;
}
return defaults;
}
function generate(spec, parentConfig = null) {
if (!is.spec(spec)) {
return UNDEFINED;
}
if (spec.hasOwnProperty(requires) && !spec[requires](parentConfig)) {
return UNDEFINED;
}
if (spec.hasOwnProperty(defaultValue)) {
return appendDoc(spec, spec[defaultValue]);
}
const types = is.array(spec[type]) ? spec[type] : [spec[type]];
if (types.includes('object')) {
let defaults = UNDEFINED;
for (let key in spec) {
if (key === '*') {
continue;
}
const value = generate(spec[key], defaults);
if (value !== UNDEFINED) {
if (defaults === UNDEFINED) {
defaults = {};
}
defaults[key] = value;
}
}
return appendDoc(spec, defaults);
} else if (types.includes('array') && spec.hasOwnProperty('*')) {
return [generate(spec['*'], {})];
}
return UNDEFINED;
}
class ConfigGenerator {
constructor(spec) {
this.spec = spec;
}
generate() {
return yaml.safeDump(generate(this.spec), {
indent: 4,
lineWidth: 1024,
schema: YAML_SCHEMA
}).replace(/^(\s*)\'#.*?\':\s*\'*(.*?)\'*$/mg, '$1# $2'); // make comment lines
}
}
module.exports = ConfigGenerator;