UNPKG

@zensen/form-service

Version:
521 lines (520 loc) 23.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var _error = require("./error"); var _utils = require("./utils"); function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); } function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); } function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); } function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } } function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } var errCb = function errCb(selector) { return Array.isArray(selector) || selector.validators; }; var pristineCb = function pristineCb(selector) { return selector.clipPristine; }; function pathToKeyPath(path) { var str = "".concat(path); return str ? str.split('.') : []; } var Service = exports["default"] = /*#__PURE__*/function () { function Service(model, selectors, onChange) { _classCallCheck(this, Service); this.__state = {}; this.__errors = {}; this.__pristine = {}; this.__selectors = selectors; this.__onChange = onChange; this.refresh(model); this.__verifySelectors(); } return _createClass(Service, [{ key: "isDirty", get: function get() { return !(0, _utils.deepEqual)(this.__state, this.__initialState); } }, { key: "isPristine", get: function get() { var _fn = function fn(obj) { return !Object.values(obj).filter(function (v) { return _typeof(v) === 'object' ? _fn(v) : v; }).length; }; return _typeof(this.__pristine) === 'object' ? _fn(this.__pristine) : this.__pristine; } }, { key: "hasErrors", get: function get() { var _fn2 = function fn(obj) { return Object.values(obj).filter(function (v) { return _typeof(v) === 'object' ? _fn2(v) : v; }).length > 0; }; return _typeof(this.__errors) === 'object' ? _fn2(this.__errors) : Boolean(this.__errors); } }, { key: "state", get: function get() { return this.__state; } }, { key: "errors", get: function get() { return this.__errors; } }, { key: "refresh", value: function refresh(model) { this.__state = (0, _utils.deepCopy)(model); this.__state = this.convert(model, 'format'); this.__initialState = (0, _utils.deepCopy)(this.__state); this.__refreshErrors(); this.__refreshPristine(); this.__change(); } }, { key: "reset", value: function reset() { this.__state = (0, _utils.deepCopy)(this.__initialState); this.__refreshErrors(); this.__refreshPristine(); this.__change(); } }, { key: "apply", value: function apply(path, value) { var keyPath = pathToKeyPath(path); if (path && value === this.__state) { throw new _error.MutationError(keyPath, value, this.__state); } var pristine = (0, _utils.getValueByPath)(this.__pristine, keyPath); if (_typeof(pristine) === 'object') { throw new _error.PristineError(keyPath); } this.__verifyValue(keyPath, value); (0, _utils.setValueByPath)(this.__state, keyPath, value); this.validateKey(keyPath); (0, _utils.setValueByPath)(this.__pristine, keyPath, false); this.__spreadSchema('__state', keyPath); this.__modify(keyPath); } }, { key: "addItem", value: function addItem(path) { var index = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : -1; var keyPath = pathToKeyPath(path); var items = (0, _utils.getValueByPath)(this.__state, keyPath); var shiftedIndex = index !== -1 ? index : items.length; var selector = this.getSelector(keyPath); var model = this.convert(this.__state, 'unformat'); var rawItem = selector.createItem(keyPath, shiftedIndex, model, this); var item = this.__convertItem(rawItem, keyPath); items.splice(shiftedIndex, 0, item); this.__spreadSchema('__state', [].concat(_toConsumableArray(keyPath), [shiftedIndex])); this.__addItemToSchema('__errors', keyPath, shiftedIndex, item, '', errCb); this.__addItemToSchema('__pristine', keyPath, shiftedIndex, item, true, pristineCb); this.__modifyPristineItem([].concat(_toConsumableArray(keyPath), [shiftedIndex])); this.__modify(keyPath); this.__change(); } }, { key: "removeItem", value: function removeItem(path) { var index = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : -1; var keyPath = pathToKeyPath(path); var items = (0, _utils.getValueByPath)(this.__state, keyPath); var shiftedIndex = index === -1 ? items.length - 1 : index; items.splice(shiftedIndex, 1); this.__spreadSchema('__state', [].concat(_toConsumableArray(keyPath), ["".concat(shiftedIndex)])); this.__removeItemFromSchema('__errors', keyPath, shiftedIndex); this.__removeItemFromSchema('__pristine', keyPath, shiftedIndex); this.__modify(keyPath); this.__change(); } }, { key: "moveItem", value: function moveItem(path, fromIndex, toIndex) { var keyPath = pathToKeyPath(path); this.__moveItemInSchema('__state', keyPath, fromIndex, toIndex); this.__moveItemInSchema('__errors', keyPath, fromIndex, toIndex); this.__moveItemInSchema('__pristine', keyPath, fromIndex, toIndex); this.__change(); } }, { key: "swapItems", value: function swapItems(path, index1, index2) { var keyPath = pathToKeyPath(path); this.__swapItemsInSchema('__state', keyPath, index1, index2); this.__swapItemsInSchema('__errors', keyPath, index1, index2); this.__swapItemsInSchema('__pristine', keyPath, index1, index2); (0, _utils.setValueByPath)(this.__pristine, [].concat(_toConsumableArray(keyPath), [index1]), false); (0, _utils.setValueByPath)(this.__pristine, [].concat(_toConsumableArray(keyPath), [index2]), false); this.__change(); } }, { key: "convert", value: function convert(data, op) { var _this = this; var rootPath = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : []; var rootSelector = this.getSelector([], true); var action = rootSelector && rootSelector[op]; var copy = _typeof(data) === 'object' ? (0, _utils.deepCopy)(data) : data; var result = action ? action(copy, rootPath, data) : copy; (0, _utils.traverse)(result, function (keyPath, value) { var fullPath = [].concat(_toConsumableArray(rootPath), _toConsumableArray(keyPath)); var selector = _this.getSelector(fullPath, true); if (selector && selector[op]) { var selVal = selector[op](value, fullPath, data); if (selVal !== null && _typeof(selVal) === 'object') { var _copy = selVal instanceof Date ? new Date(selVal.getTime()) : (0, _utils.deepCopy)(selVal); (0, _utils.setValueByPath)(result, keyPath, _copy); } else { (0, _utils.setValueByPath)(result, keyPath, selVal); } } }); return result; } }, { key: "build", value: function build() { return this.convert(this.__state, 'unformat'); } }, { key: "validate", value: function validate() { var _this2 = this; this.__pristine = (0, _utils.map)(this.__pristine, function () { return false; }); (0, _utils.traverse)(this.__state, function (keyPath) { var pristine = (0, _utils.getValueByPath)(_this2.__pristine, keyPath); if (pristine !== undefined && _typeof(pristine) !== 'object') { _this2.validateKey(keyPath, true); } }); return !this.hasErrors; } }, { key: "validateKey", value: function validateKey(keyPath) { var _this3 = this; var force = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; var clippedPathIndex = keyPath.findIndex(function (_, index) { var subPath = keyPath.slice(0, index); return _this3.getValidators(subPath); }); var validatorPathLength = clippedPathIndex !== -1 ? clippedPathIndex : keyPath.length; var validatorPath = keyPath.slice(0, validatorPathLength); var validators = this.getValidators(validatorPath); var pristine = (0, _utils.getValueByPath)(this.__pristine, keyPath); var prevErrors = this.__errors; if (validators && (!pristine || force)) { var selector = this.getSelector(validatorPath); var useRaw = selector.validateRaw || false; if (!selector.validateManually || force) { this.__processValidator(validatorPath, validators, useRaw); } } if (prevErrors !== this.__errors) { this.__change(); } } }, { key: "unsetPristine", value: function unsetPristine(keyPath) { if (typeof (0, _utils.getValueByPath)(this.__pristine, keyPath) !== 'boolean') { throw new TypeError("Invalid path: ".concat(keyPath.join('.'))); } (0, _utils.setValueByPath)(this.__pristine, keyPath, false); } }, { key: "getSelectorPath", value: function getSelectorPath(keyPath) { var _this4 = this; var ignoreCheck = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; if (!ignoreCheck) { var value = (0, _utils.getValueByPath)(this.__state, keyPath); if (value === undefined) { throw new _error.PathError(keyPath); } } var initialValue = keyPath.length ? ['children'] : []; return keyPath.reduce(function (accum, curr, index) { var parentPath = keyPath.slice(0, index); var parent = (0, _utils.getValueByPath)(_this4.__state, parentPath); var key = Array.isArray(parent) ? '$' : curr; return index < keyPath.length - 1 ? [].concat(_toConsumableArray(accum), [key, 'children']) : [].concat(_toConsumableArray(accum), [key]); }, initialValue); } }, { key: "getSelector", value: function getSelector(keyPath) { var ignoreCheck = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; var selectorPath = this.getSelectorPath(keyPath, ignoreCheck); return (0, _utils.getValueByPath)(this.__selectors, selectorPath); } }, { key: "getValidators", value: function getValidators(keyPath) { var selector = this.getSelector(keyPath); if (selector) { return Array.isArray(selector) ? selector : selector.validators; } return null; } }, { key: "__change", value: function __change() { this.__onChange(this.isDirty, this.__state, this.__errors, this.__pristine); } }, { key: "__verifySelectors", value: function __verifySelectors() { var _this5 = this; (0, _utils.traverse)(this.__state, function (keyPath, v) { var validators = _this5.getValidators(keyPath); if (validators) { var parentPath = keyPath.slice(0, keyPath.length - 1); parentPath.forEach(function (_, index) { var ancestorPath = parentPath.slice(0, index + 1); var ancestorValidators = _this5.getValidators(ancestorPath); if (ancestorValidators) { throw new _error.VerificationError("Selector (".concat(keyPath.join('.'), ") has ancestor selector with validators: ").concat(ancestorPath.join('.'))); } }); } if (_typeof(v) === 'object') { var selectors = _this5.getSelector(keyPath); if (selectors && selectors.ignorePristine && !selectors.clipPristine) { var msg = "ignorePristine set object-type key for path: ".concat(keyPath.join('.'), ". Perhaps you meant to use clipPristine?"); throw new _error.VerificationError(msg); } } }); } }, { key: "__verifyValue", value: function __verifyValue(keyPath, value) { var selector = this.getSelector(keyPath, true); var oldValue = (0, _utils.getValueByPath)(this.__state, keyPath); if (!selector || !selector.unsafe) { if (oldValue === undefined) { throw new TypeError("Invalid path: ".concat(keyPath.join('.'))); } if (oldValue !== null && value !== null) { if (_typeof(oldValue) === 'object') { var oldPathMap = (0, _utils.getKeyPaths)(oldValue); if (_typeof(value) === 'object') { var pathMap = (0, _utils.getKeyPaths)(value); if (!(0, _utils.deepEqual)(oldPathMap, pathMap)) { throw new _error.MutationError(keyPath, oldValue, value); } } else { throw new _error.MutationError(keyPath, oldValue, value); } } } } } }, { key: "__buildSchema", value: function __buildSchema(refSchema, initialValue, fn) { var _this6 = this; var rootPath = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : []; var result = Array.isArray(refSchema) ? [] : {}; var rootSelector = this.getSelector(rootPath); if (rootSelector && fn(rootSelector)) { return initialValue; } (0, _utils.traverse)(refSchema, function (keyPath, value) { var dateType = value instanceof Date; if (!dateType && value !== null && _typeof(value) === 'object') { var fullPath = [].concat(_toConsumableArray(rootPath), _toConsumableArray(keyPath)); var selector = _this6.getSelector(fullPath); if (selector && fn(selector)) { (0, _utils.setValueByPath)(result, keyPath, initialValue); return false; } (0, _utils.setValueByPath)(result, keyPath, Array.isArray(value) ? [] : {}); } else { (0, _utils.setValueByPath)(result, keyPath, initialValue); } }, true); return result; } }, { key: "__convertItem", value: function __convertItem(data) { var rootPath = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; var item = _typeof(data) === 'object' ? (0, _utils.deepCopy)(data) : data; var result = this.convert([item], 'format', rootPath); return result[0]; } }, { key: "__spreadSchema", value: function __spreadSchema(schemaKey, keyPath) { var _this7 = this; var ref = this[schemaKey]; this[schemaKey] = Array.isArray(ref) ? _toConsumableArray(ref) : _objectSpread({}, ref); if (keyPath.length > 1) { keyPath.slice(0, keyPath.length - 1).forEach(function (_, index) { var subPath = keyPath.slice(0, index + 1); var subObj = (0, _utils.getValueByPath)(_this7[schemaKey], subPath); var result = Array.isArray(subObj) ? _toConsumableArray(subObj) : _objectSpread({}, subObj); (0, _utils.setValueByPath)(_this7[schemaKey], subPath, result); }); } } }, { key: "__addItemToSchema", value: function __addItemToSchema(schemaKey, keyPath, index, item, defaultValue, fn) { var value = (0, _utils.getValueByPath)(this[schemaKey], keyPath); if (_typeof(value) === 'object') { var selector = this.getSelector(keyPath); var clipElement = selector && selector.children && selector.children.$ && fn(selector.children.$); var subObj = !clipElement && _typeof(item) === 'object' ? this.__buildSchema(item, defaultValue, fn, [].concat(_toConsumableArray(keyPath), ["".concat(index)])) : defaultValue; value.splice(index, 0, subObj); this.__spreadSchema(schemaKey, [].concat(_toConsumableArray(keyPath), ["".concat(index)])); } } }, { key: "__removeItemFromSchema", value: function __removeItemFromSchema(schemaKey, keyPath, index) { var item = (0, _utils.getValueByPath)(this[schemaKey], keyPath); if (Array.isArray(item)) { item.splice(index, 1); this.__spreadSchema(schemaKey, [].concat(_toConsumableArray(keyPath), ["".concat(index)])); } } }, { key: "__moveItemInSchema", value: function __moveItemInSchema(schemaKey, keyPath, fromIndex, toIndex) { var items = (0, _utils.getValueByPath)(this[schemaKey], keyPath); if (Array.isArray(items)) { var result = (0, _utils.moveItem)(items, fromIndex, toIndex).map(function (item) { if (_typeof(item) === 'object') { return Array.isArray(item) ? _toConsumableArray(item) : _objectSpread({}, item); } return item; }); if (keyPath.length) { (0, _utils.setValueByPath)(this[schemaKey], keyPath, result); } else { this[schemaKey] = result; } this.__spreadSchema(schemaKey, keyPath); } } }, { key: "__swapItemsInSchema", value: function __swapItemsInSchema(schemaKey, keyPath, index1, index2) { var items = (0, _utils.getValueByPath)(this[schemaKey], keyPath); if (Array.isArray(items)) { var result = (0, _utils.swap)(items, index1, index2); if (keyPath.length) { (0, _utils.setValueByPath)(this[schemaKey], keyPath, result); } else { this[schemaKey] = result; } this.__spreadSchema(schemaKey, [].concat(_toConsumableArray(keyPath), [index1])); this.__spreadSchema(schemaKey, [].concat(_toConsumableArray(keyPath), [index2])); } } }, { key: "__modify", value: function __modify(keyPath) { var pristine = (0, _utils.getValueByPath)(this.__pristine, keyPath); if (pristine && _typeof(pristine) !== 'object') { (0, _utils.setValueByPath)(this.__pristine, keyPath, false); } this.__change(); } }, { key: "__processValidator", value: function __processValidator(keyPath, validators, useRaw) { var _this8 = this; var data = useRaw ? this.convert(this.__state, 'unformat') : this.__state; var value = (0, _utils.getValueByPath)(data, keyPath); try { validators.forEach(function (validator) { if (!validator.validate(value, keyPath, data, _this8)) { throw new _error.ValidationError(validator.error); } }); this.__setError(keyPath, ''); } catch (e) { if (e instanceof _error.ValidationError) { this.__setError(keyPath, e.message); } else { throw e; } } } }, { key: "__refreshErrors", value: function __refreshErrors() { this.__errors = this.__buildSchema(this.__state, '', function (selector) { return Array.isArray(selector) || selector.validators; }); } }, { key: "__setError", value: function __setError(keyPath, message) { if (keyPath.length) { (0, _utils.setValueByPath)(this.__errors, keyPath, message); this.__spreadSchema('__errors', keyPath); } else { this.__errors = message; } } }, { key: "__refreshPristine", value: function __refreshPristine() { var _this9 = this; this.__pristine = this.__buildSchema(this.__state, true, function (selector) { return selector.clipPristine; }); (0, _utils.traverse)(this.__pristine, function (keyPath) { var selector = _this9.getSelector(keyPath); if (selector && selector.ignorePristine) { (0, _utils.setValueByPath)(_this9.__pristine, keyPath, false); } }); } }, { key: "__modifyPristineItem", value: function __modifyPristineItem(keyPath) { var _this0 = this; var pristine = (0, _utils.getValueByPath)(this.__pristine, keyPath); if (_typeof(pristine) === 'object') { (0, _utils.traverse)(pristine, function (subPath) { var fullPath = [].concat(_toConsumableArray(keyPath), _toConsumableArray(subPath)); var selector = _this0.getSelector(fullPath); if (selector && selector.ignorePristine) { (0, _utils.setValueByPath)(_this0.__pristine, fullPath, false); } }); } else { var selector = this.getSelector(keyPath); if (selector && selector.ignorePristine) { (0, _utils.setValueByPath)(this.__pristine, keyPath, false); } } } }]); }();