atlassian-connect-validator
Version:
Utility to validate an Atlassian Connect add-on descriptor
91 lines (75 loc) • 3.08 kB
JavaScript
var util = require('util'),
_ = require('lodash'),
Validator = require('jsonschema').Validator,
helpers = require('jsonschema/lib/helpers');
var isDevMode = process.env.NODE_ENV === 'development'
if (isDevMode) {
require('longjohn');
}
function getModuleName(path) {
if ('instance' === path) {
return 'Root';
} else {
return path.substr(9);
}
}
function normalizePath(path) {
return ((path.length > 0 && path[0] != '/') ? '/' : '') + encodeURIComponent(path);
}
/**
* Rewrites a schema to not allow additional properties where they would usually be allowed.
* @param schema The original JSON schema
* @returns {Object} A copy of the schema with the 'additionalProperties' fields set to false at the root
*/
function noAdditionalRootProperties(schema) {
var copy = _.clone(schema);
copy.additionalProperties = false;
return copy;
}
function difference(strictErrors, errors) {
return _.differenceBy(strictErrors, errors, function(value) {
return value.module + value.description;
});
}
var parseValidationErrors = function(descriptor, errors) {
isDevMode && console.log(util.inspect(errors, {
colors: true
}));
var baseUrl = descriptor.baseUrl;
var validationErrors = [];
_.forEach(errors, function(e) {
var validationError = {
module: getModuleName(e.property),
description: e.message,
error: e
};
if ('enum' === e.name) {
validationError.description = "'" + e.instance + "' is not a valid enum value";
validationError.validValues = e.argument;
}
// 'jsonschema' rejects relative URLs for fields that are annotated with uri (and it doesn't handle uri-template).
// So we are constructing the absolute URL here and validate it again. If this second validation fails,
// we record the error, otherwise we can ignore it.
if ('format' === e.name && ('uri' === e.argument || 'uri-template' === e.argument) && baseUrl && e.instance != null) {
var absolute = baseUrl + normalizePath(e.instance);
if (!helpers.isFormat(absolute, 'uri')) {
validationErrors.push(validationError);
}
} else {
validationErrors.push(validationError);
}
});
return validationErrors;
};
module.exports = {
validateDescriptor: function(descriptor, schema, callback) {
var result = new Validator().validate(descriptor, schema);
var validationErrors = parseValidationErrors(descriptor, result.errors);
var strictResult = new Validator().validate(descriptor, noAdditionalRootProperties(schema));
var strictValidationErrors = parseValidationErrors(descriptor, strictResult.errors);
var validationWarnings = difference(strictValidationErrors, validationErrors);
if (callback) {
callback(validationErrors.length > 0 ? validationErrors: null, validationWarnings.length > 0 ? validationWarnings : null);
}
}
};