@spaceavocado/svelte-form
Version:
Simple Svelte form model handler and input validations.
504 lines (422 loc) • 11.2 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var tc = _interopDefault(require('@spaceavocado/type-check'));
var store = require('svelte/store');
function _slicedToArray(arr, i) {
return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest();
}
function _arrayWithHoles(arr) {
if (Array.isArray(arr)) return arr;
}
function _iterableToArrayLimit(arr, i) {
if (!(Symbol.iterator in Object(arr) || Object.prototype.toString.call(arr) === "[object Arguments]")) {
return;
}
var _arr = [];
var _n = true;
var _d = false;
var _e = undefined;
try {
for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
_arr.push(_s.value);
if (i && _arr.length === i) break;
}
} catch (err) {
_d = true;
_e = err;
} finally {
try {
if (!_n && _i["return"] != null) _i["return"]();
} finally {
if (_d) throw _e;
}
}
return _arr;
}
function _nonIterableRest() {
throw new TypeError("Invalid attempt to destructure non-iterable instance");
}
/**
* Svelte Form validation rules module.
* @module svelte-form/rule/required
*/
/**
* Required rule
* @param {string} msg error message.
* @return {boolean|string} true when valid, error message otherwise.
*/
var required = (function (msg) {
return function (value) {
if (tc.isNullOrUndefined(value) || tc.isObject(value) || tc.isFunction(value)) {
return msg;
}
if (tc.isString(value)) {
value = value.trim();
if (value.length == 0) {
return msg;
}
}
return true;
};
});
/**
* Svelte Form validation rules module.
* @module svelte-form/rule/ignore
*/
var BREAK_FLAG = Symbol('Break Validation');
/**
* Ignore empty rule
* This rule causes to break the validation chain for empty values.
* @return {boolean|string} true when valid, error message otherwise.
*/
var ignoreEmpty = (function () {
var req = required('');
return function (value) {
if (req(value) !== true) {
return BREAK_FLAG;
}
return true;
};
});
/**
* Svelte Form validation rules module.
* @module svelte-form/rule/email
*/
/**
* Email rule
* @param {string} msg error message.
* @return {boolean|string} true when valid, error message otherwise.
*/
var email = (function (msg) {
return function (value) {
if (tc.isNullOrUndefined(value) || tc.not.isString(value)) {
return msg;
}
var rule = /^([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$/;
if (value.match(rule) == null) {
return msg;
}
return true;
};
});
/**
* Svelte Form validation rules module.
* @module svelte-form/rule/url
*/
/**
* URL rule
* @param {string} msg error message.
* @return {boolean|string} true when valid, error message otherwise.
*/
var url = (function (msg) {
return function (value) {
if (tc.isNullOrUndefined(value) || tc.not.isString(value)) {
return msg;
}
if (value.match(/^https?:\/\/[^\s]*/i) == null) {
return msg;
}
return true;
};
});
/**
* Svelte Form validation rules module.
* @module svelte-form/rule/equal
*/
/**
* Equal rule.
* @param {string} msg error message.
* @param {mixed|function} arg a matcher object or
* matcher function = fn(val) returning true|false.
* @return {boolean|string} true when valid, error message otherwise.
*/
var equal = (function (msg, arg) {
var customMatcher = tc.isFunction(arg);
return function (value) {
if (customMatcher === false && tc.isNullOrUndefined(value)) {
return msg;
}
if (customMatcher) {
if (arg(value) === false) {
return msg;
}
} else if (value !== arg) {
return msg;
}
return true;
};
});
/**
* Svelte Form validation rules module.
* @module svelte-form/rule/min
*/
/**
* Min rule
* @param {string} msg error message.
* @param {number} arg min number.
* @return {boolean|string} true when valid, error message otherwise.
*/
var min = (function (msg, arg) {
return function (value) {
if (tc.isNullOrUndefined(value) || tc.not.isNumber(value) || tc.isNullOrUndefined(arg)) {
return msg;
}
if (value < arg) {
return msg;
}
return true;
};
});
/**
* Svelte Form validation rules module.
* @module svelte-form/rule/max
*/
/**
* Max rule
* @param {string} msg error message.
* @param {number} arg max number.
* @return {boolean|string} true when valid, error message otherwise.
*/
var max = (function (msg, arg) {
return function (value) {
if (tc.isNullOrUndefined(value) || tc.not.isNumber(value) || tc.isNullOrUndefined(arg)) {
return msg;
}
if (value > arg) {
return msg;
}
return true;
};
});
/**
* Svelte Form validation rules module.
* @module svelte-form/rule/between
*/
/**
* Between numbers rule
* @param {string} msg error message.
* @param {number} arg1 min number.
* @param {number} arg2 max number.
* @return {boolean|string} true when valid, error message otherwise.
*/
var between = (function (msg, arg1, arg2) {
return function (value) {
if (min('', arg1)(value) !== true || max('', arg2)(value) !== true) {
return msg;
}
return true;
};
});
/**
* Svelte Form validation rules module.
* @module svelte-form/rule/rx
*/
/**
* Custom regex rule.
* @param {string} msg error message.
* @param {number} arg Regular expression.
* @return {boolean|string} true when valid, error message otherwise.
*/
var rx = (function (msg, arg) {
return function (value) {
if (tc.isNullOrUndefined(value) || tc.not.isString(value)) {
return msg;
}
if (value.match(arg) == null) {
return msg;
}
return true;
};
});
/**
* Svelte Form validation rules module.
* @module svelte-form/rule/exclude
*/
/**
* Max rule
* @param {string} msg error message.
* @param {number[]|string[]} arg exclusion list.
* @return {boolean|string} true when valid, error message otherwise.
*/
var exclude = (function (msg, arg) {
return function (value) {
if (tc.isNullOrUndefined(value) || tc.not.isString(value) && tc.not.isNumber(value) || tc.isNullOrUndefined(arg)) {
return msg;
}
if (arg.indexOf(value) > -1) {
return msg;
}
return true;
};
});
/**
* Svelte Form validation rules module.
* @module svelte-form/rule/include
*/
/**
* Include rule
* @param {string} msg error message.
* @param {number[]|string[]} arg inclusion list.
* @return {boolean|string} true when valid, error message otherwise.
*/
var include = (function (msg, arg) {
return function (value) {
if (tc.isNullOrUndefined(value) || tc.not.isString(value) && tc.not.isNumber(value) || tc.isNullOrUndefined(arg)) {
return msg;
}
if (arg.indexOf(value) == -1) {
return msg;
}
return true;
};
});
/**
* Get input validation rules
* @private
* @param {string} key input key.
* @param {object} validation rules.
* @return {function[]} validation rules.
*/
function validationRules(key, validation) {
validation = validation || {};
if (tc.isNullOrUndefined(validation[key])) {
return [];
}
if (tc.isArray(validation[key])) {
return validation[key];
}
return [validation[key]];
}
/**
* Validate field
* @private
* @param {mixed} value field value.
* @param {function[]} rules filed validation rules.
* @return {boolean|string} true = no error, string = error message.
*/
function validate(value, rules) {
for (var i = 0; i < rules.length; i++) {
var err = rules[i](value);
if (err === BREAK_FLAG) {
return true;
} else if (err !== true) {
return err;
}
}
return true;
}
/**
* Form object
* @typedef Form
* @property {function} subscribe Svelte store, context {valid: boolean}.
* @property {function} field Get form field observable value and state.
* Signature fn(key), returns {module:svelte-form~FormField}.
* @property {function} validate Trigger all fields validation.
* @property {function} data Get all form fields data. Signature fn().
*/
/**
* FormField object
* @typedef FormField
* @property {function} value Writeable Svelte store, context: mixed value.
* @property {function} state Readonly Svelte store,
* context: {valid: boolean, error: string}.
*/
/**
* Create a new form store
* @param {object} fields Form fields.
* @param {object} validation Validation rules mapping.
* Where each key is a fn(val)->boolean validation function or
* an array of fn(val)->boolean validation functions.
* @param {object} opts Form options.
* @param {boolean} opts.onCreateValidation Validate form fields
* when the form is created. Defaults to false.
* @return {module:svelte-form~Form}
*/
function index (fields, validation, opts) {
opts = opts || {};
opts.onCreateValidation = opts.onCreateValidation || false;
var _fields = {};
var form = store.writable(Date.now()); // Field wrapper structure
var field = function field(key, rules) {
var firstPass = true;
var value = store.writable(fields[key]);
var state = store.derived([value, form], function (_ref) {
var _ref2 = _slicedToArray(_ref, 1),
$value = _ref2[0];
if (firstPass) {
firstPass = false;
if (opts.onCreateValidation === false) {
return {
valid: true,
error: ''
};
}
}
var res = validate($value, rules);
return {
valid: res === true,
error: res === true ? '' : res
};
});
return {
value: value,
state: state
};
}; // Convert all inputs into field wrappers
var key;
for (key in fields) {
if (fields.hasOwnProperty(key)) {
_fields[key] = field(key, validationRules(key, validation));
}
} // Overall valid state
var _derived = store.derived(Object.values(_fields).map(function (f) {
return f.state;
}), function ($states) {
return {
valid: $states.every(function (s) {
return s.valid === true;
})
};
}),
subscribe = _derived.subscribe;
return {
subscribe: subscribe,
field: function field(key) {
if (tc.isNullOrUndefined(_fields[key])) {
return undefined;
}
return {
value: _fields[key].value,
state: _fields[key].state
};
},
validate: function validate() {
form.set(Date.now());
},
data: function data() {
var data = {};
var key;
for (key in _fields) {
if (_fields.hasOwnProperty(key)) {
data[key] = store.get(_fields[key].value);
}
}
return data;
}
};
}
exports.between = between;
exports.default = index;
exports.email = email;
exports.equal = equal;
exports.exclude = exclude;
exports.ignoreEmpty = ignoreEmpty;
exports.include = include;
exports.max = max;
exports.min = min;
exports.required = required;
exports.rx = rx;
exports.url = url;
exports.validate = validate;
exports.validationRules = validationRules;