UNPKG

@nodecg/json-schema-lib

Version:

Extensible JSON Schema library with support for multi-file schemas using $ref

192 lines (172 loc) 5.4 kB
'use strict'; var ono = require('ono'); var assign = require('../../util/assign'); var __internal = require('../../util/internal'); var validatePlugins = require('./validatePlugins'); var callSyncPlugin = require('./callSyncPlugin'); var callAsyncPlugin = require('./callAsyncPlugin'); module.exports = PluginHelper; /** * Helper methods for working with plugins. * * @param {object[]|null} plugins - The plugins to use * @param {Schema} schema - The {@link Schema} to apply the plugins to * * @class * @extends Array */ function PluginHelper (plugins, schema) { validatePlugins(plugins); plugins = plugins || []; // Clone the array of plugins, and sort by priority var pluginHelper = plugins.slice().sort(sortByPriority); /** * Internal stuff. Use at your own risk! * * @private */ pluginHelper[__internal] = { /** * A reference to the {@link Schema} object */ schema: schema, }; // Return an array that "inherits" from PluginHelper return assign(pluginHelper, PluginHelper.prototype); } /** * Resolves a URL, relative to a base URL. * * @param {?string} args.from - The base URL to resolve against, if any * @param {string} args.to - The URL to resolve. This may be absolute or relative. * @returns {string} - Returns an absolute URL */ PluginHelper.prototype.resolveURL = function resolveURL (args) { try { var handled = callSyncPlugin(this, 'resolveURL', args); var url = handled.result; var plugin = handled.plugin || { name: '' }; if (url === undefined || url === null) { throw ono('Error in %s.resolveURL: No value was returned', plugin.name); } else if (typeof url !== 'string') { throw ono('Error in %s.resolveURL: The return value was not a string (%s)', plugin.name, typeof url); } else { return url; } } catch (err) { throw ono(err, 'Unable to resolve %s', args.to); } }; /** * Synchronously reads the given file from its source (e.g. web server, filesystem, etc.) * * @param {File} args.file - The {@link File} to read */ PluginHelper.prototype.readFileSync = function readFileSync (args) { try { var handled = callSyncPlugin(this, 'readFileSync', args); if (!handled.plugin) { throw ono('Error in readFileSync: No plugin was able to read the file'); } else { // The file was read successfully, so set the file's data args.file.data = handled.result; } } catch (err) { throw ono(err, 'Unable to read %s', args.file.url); } }; /** * Asynchronously reads the given file from its source (e.g. web server, filesystem, etc.) * * @param {File} args.file * The {@link File} to read. Its {@link File#data} property will be set to the file's contents. * In addition, {@link File#mimeType} and {@link File#encoding} may be set, if determinable. * * @param {function} callback * The callback function to call after the file has been read */ PluginHelper.prototype.readFileAsync = function readFileAsync (args, callback) { callAsyncPlugin(this, 'readFileAsync', args, function (err, handled) { if (!err && !handled.plugin) { err = ono('Error in readFileAsync: No plugin was able to read the file'); } if (err) { err = ono(err, 'Unable to read %s', args.file.url); callback(err); } else { if (handled.plugin) { // The file was read successfully, so set the file's data args.file.data = handled.result; } callback(null); } }); }; /** * Decodes the given file's data, in place. * * @param {File} args.file - The {@link File} to decode. */ PluginHelper.prototype.decodeFile = function decodeFile (args) { try { var handled = callSyncPlugin(this, 'decodeFile', args); // NOTE: It's ok if no plugin handles this method. // The file data will just remain in its "raw" format. if (handled.plugin) { // The file was decoded successfully, so update the file's data args.file.data = handled.result; } } catch (err) { throw ono(err, 'Unable to parse %s', args.file.url); } }; /** * Parses the given file's data, in place. * * @param {File} args.file - The {@link File} to parse. */ PluginHelper.prototype.parseFile = function parseFile (args) { try { var handled = callSyncPlugin(this, 'parseFile', args); // NOTE: It's ok if no plugin handles this method. // The file data will just remain in its "raw" format. if (handled.plugin) { // The file was parsed successfully, so update the file's data args.file.data = handled.result; } } catch (err) { throw ono(err, 'Unable to parse %s', args.file.url); } }; /** * Performs final cleanup steps on the schema after all files have been read successfully. */ PluginHelper.prototype.finished = function finished () { try { // NOTE: It's ok if no plugin handles this method. // It's just an opportunity for plugins to perform cleanup tasks if necessary. callSyncPlugin(this, 'finished', {}); } catch (err) { throw ono(err, 'Error finalizing schema'); } }; /** * Used to sort plugins by priority, so that plugins with higher piority come first * in the __plugins array. * * @param {object} pluginA * @param {object} pluginB * @returns {number} */ function sortByPriority (pluginA, pluginB) { return (pluginB.priority || 0) - (pluginA.priority || 0); }