gitbook-plugin-json-schema
Version:
Gitbook plugin to convert JSON schema to markdown documentation
281 lines (211 loc) • 9.07 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.findMatchingDefinitions = exports.layout = exports.propertyList = exports.listItem = exports.resolveSchema = undefined;
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
exports.schema = schema;
var _fs = require('fs');
var _fs2 = _interopRequireDefault(_fs);
var _lodash = require('lodash');
var _lodash2 = _interopRequireDefault(_lodash);
var _deepmerge = require('deepmerge');
var _deepmerge2 = _interopRequireDefault(_deepmerge);
var _html = require('html');
var _jsonSchemaRefParser = require('json-schema-ref-parser');
var _jsonSchemaRefParser2 = _interopRequireDefault(_jsonSchemaRefParser);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
var plugins = {};
var traverseObjects = false;
var bundledSchema = {};
var OMIT_PROPERTIES = [];
var resolveRef = function resolveRef(value) {
if (!value.$ref) {
return value;
}
var pathParts = value.$ref.substring(2).split('/');
var pathLength = pathParts.length;
var currentParts = [pathParts.shift()];
var foundSchema = void 0;
while (currentParts.length <= pathLength) {
foundSchema = _lodash2.default.get(bundledSchema, currentParts.join('.'));
if (foundSchema.$ref) {
foundSchema = resolveRef(foundSchema);
foundSchema = foundSchema[0] || foundSchema;
return _lodash2.default.get(foundSchema, pathParts.join('.'));
}
currentParts.push(pathParts.shift());
}
return foundSchema;
};
var resolveSchema = exports.resolveSchema = function resolveSchema(definition) {
if (!definition) {
return definition;
}
if (definition.$ref) {
var resolved = resolveRef(definition);
return resolveSchema(resolved);
}
if (definition.allOf) {
var allOf = _lodash2.default.map(definition.allOf, function (def) {
var resolved = resolveSchema(def);
return _extends({}, resolved, {
properties: _lodash2.default.mapValues(resolved.properties, resolveSchema)
});
});
definition = _deepmerge2.default.all([].concat(_toConsumableArray(allOf), [definition]));
}
if (definition.anyOf) {
definition.anyOf = _lodash2.default.map(definition.anyOf, function (def) {
if (def.$ref) {
var _resolved = resolveRef(def);
return resolveSchema(_resolved);
}
return def;
});
}
return definition;
};
var tupleArray = function tupleArray(properties) {
return _lodash2.default.map(properties, function (value, key) {
return Object.assign({}, value, resolveRef(value), {
name: key
});
});
};
var listItem = function listItem(_ref) {
var name = _ref.name,
type = _ref.type,
description = _ref.description,
values = _ref.values,
rest = _objectWithoutProperties(_ref, ['name', 'type', 'description', 'values']);
values = _lodash2.default.map(values, function (value) {
return _lodash2.default.isObject(value) ? value.title : value;
});
values = _lodash2.default.isEmpty(values) ? '' : '<code>' + values + '</code>';
var subProps = void 0;
if (type === 'object' && traverseObjects) {
// eslint-disable-next-line no-use-before-define
subProps = propertyList(tupleArray(rest.properties));
}
return '\n <li>\n <b>' + name + '</b>\n <i>{' + type + '}</i>\n ' + (description || '') + '\n ' + values + '\n ' + (subProps || '') + '\n </li>\n ';
};
exports.listItem = listItem;
var propertyList = exports.propertyList = function propertyList(items) {
return '\n <ul>\n ' + _lodash2.default.map(items, listItem).join('') + '\n </ul>\n';
};
var layout = exports.layout = function layout(_ref2) {
var title = _ref2.title,
description = _ref2.description,
required = _ref2.required,
optional = _ref2.optional,
plugins = _ref2.plugins;
return '\n ' + (title ? '<h1>' + title + '</h1>' : '') + '\n ' + (description ? '<p>' + description + '</p>' : '') + '\n ' + (required || optional ? '<h2>Structure</h2>' : '') + '\n ' + (required ? '<h4>Required</h4>\n ' + required : '') + '\n ' + (optional ? '<h4>Optional</h4>\n ' + optional : '') + '\n ' + (plugins ? plugins.map(function (plugin) {
return plugin;
}).join('') : '') + '\n';
};
function escapeRegExp(string) {
if (typeof string !== 'string') {
return string;
}
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
}
var findMatchingDefinitions = exports.findMatchingDefinitions = function findMatchingDefinitions(schema, identifier) {
if (!_lodash2.default.isObject(schema)) {
return [];
}
var id = schema.$id || schema.id;
var idRegex = new RegExp(escapeRegExp(id), 'i');
if (typeof id === 'string' && identifier.match(idRegex)) {
return [schema];
}
var found = _lodash2.default.map(schema, function (schemaDef) {
return findMatchingDefinitions(schemaDef, identifier);
});
found = _lodash2.default.union.apply(_lodash2.default, _toConsumableArray(found));
found = _lodash2.default.filter(found, _lodash2.default.isObject);
return found;
};
var resolveWhole = function resolveWhole(definition) {
var levels = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 3;
if (levels === 0) {
return definition;
}
if (!_lodash2.default.isObject(definition)) {
return definition;
}
definition = resolveSchema(definition);
_lodash2.default.map(definition, function (schemaDef, key) {
definition[key] = resolveWhole(schemaDef, levels - 1);
});
return definition;
};
var getRootDefinition = function getRootDefinition(identifier) {
var definitions = findMatchingDefinitions(bundledSchema, identifier);
return resolveSchema(definitions[0]);
};
function schema(key) {
var id = key.args ? key.args[0] : key;
var rootDefinition = getRootDefinition(id);
if (!rootDefinition) {
return '<div />';
}
var requiredProperties = rootDefinition.required || [];
var properties = tupleArray(rootDefinition.properties);
properties = _lodash2.default.filter(properties, function (property) {
return !Object.keys(plugins).includes(property.name) && !OMIT_PROPERTIES.includes(property.name);
});
var required = properties.filter(function (prop) {
return requiredProperties.indexOf(prop.name) > -1;
});
var optional = properties.filter(function (prop) {
return requiredProperties.indexOf(prop.name) === -1;
});
var html = layout({
title: rootDefinition.title || rootDefinition.id || rootDefinition.$id,
description: rootDefinition.description,
required: propertyList(required),
optional: propertyList(optional),
plugins: _lodash2.default.map(plugins, function (render, name) {
return render(resolveWhole(_lodash2.default.get(rootDefinition, 'properties.' + name)));
})
});
return (0, _html.prettyPrint)(html, { indent_size: 2 }); // eslint-disable-line camelcase
}
exports.default = {
hooks: {
init: function init() {
var config = this.options.pluginsConfig['json-schema'];
traverseObjects = config.traverseObjects;
if (config.plugins) {
_lodash2.default.map(config.plugins, function (render, propertyName) {
var plugin = _fs2.default.readFileSync(render, 'utf8');
// eslint-disable-next-line no-eval
plugins[propertyName] = eval(plugin);
});
}
if (config.omitProperties) {
OMIT_PROPERTIES = [].concat(_toConsumableArray(OMIT_PROPERTIES), _toConsumableArray(config.omitProperties));
}
if (config.bundled && _typeof(config.schema) === 'object') {
bundledSchema = config.schema;
return true;
} else if (config.bundled) {
bundledSchema = JSON.parse(_fs2.default.readFileSync(config.schema, 'utf8'));
return true;
}
console.log('Bundling Schema...');
return _jsonSchemaRefParser2.default.bundle(config.schema).then(function (schema) {
bundledSchema = schema;
}).catch(function (err) {
throw err;
});
}
},
blocks: {
schema: schema
}
};