graphql-input-string
Version:
A configurable custom input string type for GraphQL with sanitization and validation.
260 lines (216 loc) • 6.58 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
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; };
var _graphql = require('graphql');
var _error = require('graphql/error');
var _language = require('graphql/language');
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 coerceString(value) {
if (typeof value === 'string') {
return value;
}
return null;
}
// http://stackoverflow.com/a/7592235
var strToUpperCase = function strToUpperCase(str) {
return str.toUpperCase();
};
var wordRegex = /(?:^|\s)\S/g;
var sentenceRegex = /(?:^|\.\s)\S/g;
var newlineRegex = /[\r\n]+/g;
var newlineWithWSRegex = /\s*[\r\n]+\s*/g;
var whitespace = /\s+/g;
var collapseWS = function collapseWS(str) {
return str.replace(whitespace, ' ');
};
exports.default = function (_ref) {
var capitalize = _ref.capitalize;
var collapseWhitespace = _ref.collapseWhitespace;
var description = _ref.description;
var empty = _ref.empty;
var error = _ref.error;
var lowerCase = _ref.lowerCase;
var max = _ref.max;
var min = _ref.min;
var name = _ref.name;
var parse = _ref.parse;
var pattern = _ref.pattern;
var sanitize = _ref.sanitize;
var singleline = _ref.singleline;
var test = _ref.test;
var trim = _ref.trim;
var trimLeft = _ref.trimLeft;
var trimRight = _ref.trimRight;
var truncate = _ref.truncate;
var upperCase = _ref.upperCase;
var config = _objectWithoutProperties(_ref, ['capitalize', 'collapseWhitespace', 'description', 'empty', 'error', 'lowerCase', 'max', 'min', 'name', 'parse', 'pattern', 'sanitize', 'singleline', 'test', 'trim', 'trimLeft', 'trimRight', 'truncate', 'upperCase']);
if (!name) {
throw new Error('"name" is required');
}
if (typeof pattern === 'string') {
pattern = new RegExp(pattern);
}
if (typeof error !== 'function') {
error = function error(_ref2) {
var value = _ref2.value;
var ast = _ref2.ast;
var message = _ref2.message;
var more = message ? ' ' + message + '.' : '';
throw new _error.GraphQLError('Invalid value ' + JSON.stringify(value) + '.' + more, ast ? [ast] : []);
};
}
if (!description && !test) {
// Autogenerate a description if no test is present
description = 'A string';
if (min && max) {
description += ' between ' + min + ' and ' + max + ' characters';
} else if (min) {
description += ' of at least ' + min + ' characters';
} else if (max) {
description += ' at most ' + max + ' characters';
}
if (pattern) {
if (description.length > 'A string'.length) {
description += ' and';
}
description += ' that matches the pattern \'' + pattern + '\'';
}
if (trim || trimLeft || trimRight) {
if (trim) {
description += ' that is trimmed.';
} else {
description += 'that is trimmed to the ' + (trimLeft ? 'left' : 'right') + '.';
}
} else {
description += '.';
}
}
var parseValue = function parseValue(value, ast) {
value = coerceString(value);
if (value == null) {
return null;
}
// Sanitization Phase
if (value) {
if (trim) {
value = value.trim();
} else {
if (trimLeft) {
value = value.trimLeft();
}
if (trimRight) {
value = value.trimRight();
}
}
if (value) {
if (singleline) {
value = value.replace(newlineRegex, ' ');
}
if (collapseWhitespace) {
if (singleline) {
value = value.replace(whitespace, ' ');
} else {
value = value.split(newlineWithWSRegex).map(collapseWS).join('\n');
}
}
if (truncate != null && value.length > truncate) {
value = value.substring(0, truncate);
}
if (upperCase) {
value = value.toUpperCase();
} else if (lowerCase) {
value = value.toLowerCase();
}
if (capitalize) {
switch (capitalize) {
case 'characters':
value = value.toUpperCase();
break;
case 'words':
value = value.replace(wordRegex, strToUpperCase);
break;
case 'sentences':
value = value.replace(sentenceRegex, strToUpperCase);
break;
case 'first':
default:
value = value[0].toUpperCase() + value.slice(1);
break;
}
}
}
}
if (sanitize) {
value = sanitize(value);
if (typeof value !== 'string') {
return null;
}
}
// Validation Phase
if (!empty && !value) {
return error({
type: 'empty',
value: value,
message: 'Expected non-empty string',
ast: ast
});
}
if (min != null && value.length < min) {
return error({
type: 'min',
value: value,
min: min,
message: 'Expected minimum length "' + min + '"',
ast: ast
});
}
if (max != null && value.length > max) {
return error({
type: 'max',
value: value,
max: max,
message: 'Expected maximum length "' + max + '"',
ast: ast
});
}
if (pattern != null && !pattern.test(value)) {
return error({
type: 'pattern',
value: value,
pattern: pattern,
message: 'Unexpected pattern',
ast: ast
});
}
if (test && !test(value)) {
return error({
type: 'test',
value: value,
test: test,
ast: ast
});
}
// Parse Phase
if (parse) {
return parse(value);
}
return value;
};
return new _graphql.GraphQLScalarType(_extends({
name: name,
serialize: coerceString,
parseValue: parseValue,
description: description,
parseLiteral: function parseLiteral(ast) {
var kind = ast.kind;
var value = ast.value;
if (kind === _language.Kind.STRING) {
return parseValue(value, ast);
}
return null;
}
}, config));
};
module.exports = exports['default'];