svelte-specma
Version:
Svelte store for data validation using Specma
1,177 lines (1,032 loc) • 33.9 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('svelte/store'), require('fast-deep-equal'), require('svelte')) :
typeof define === 'function' && define.amd ? define(['exports', 'svelte/store', 'fast-deep-equal', 'svelte'], factory) :
(global = global || self, factory(global.svelteSpecma = {}, global.store, global.fastDeepEqual, global.svelte));
}(this, (function (exports, store, fastEquals, svelte) {
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var fastEquals__default = /*#__PURE__*/_interopDefaultLegacy(fastEquals);
function _extends() {
_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;
};
return _extends.apply(this, arguments);
}
function _objectWithoutPropertiesLoose(source, excluded) {
if (source == null) return {};
var target = {};
var sourceKeys = Object.keys(source);
var key, i;
for (i = 0; i < sourceKeys.length; i++) {
key = sourceKeys[i];
if (excluded.indexOf(key) >= 0) continue;
target[key] = source[key];
}
return target;
}
var identity$1 = function identity(x) {
return x;
};
var noop = function noop() {};
function flexDerived(initialStores, fn, initialValue) {
if (initialStores === void 0) {
initialStores = [];
}
if (fn === void 0) {
fn = identity$1;
}
/* Used for ordering values */
var _stores = initialStores;
/* Store of stores. When last subscriber unsubscribes,
* will stop all stores subs. */
var $stores = store.writable(initialStores);
/* Callback function can use a second argument, a `publish` function to set result asynchronously.
* If not used, the return value of the function is the actual result to publish.
* Otherwise, the return value might be a function to call before each execution
* and when store is unsubscribed. */
var auto = fn.length < 2;
/* Use a readable store to manage subscribers. */
var mainStore = store.readable(initialValue, function (publish) {
var initialized = false;
var cleanup = noop;
var pending = 0;
var unsubs = new Map();
var values = new Map();
/* Unsubscribe saved stores not included in a new list of stores
* and create a new Map of unsub by store, reusing old ones when they exist. */
function updateUnsubs(stores) {
if (stores === void 0) {
stores = [];
}
stopUnusedSubs(stores);
unsubs = new Map(stores.map(function (store) {
return [store, unsubs.get(store)];
}));
}
function stopUnusedSubs(usedStores) {
if (usedStores === void 0) {
usedStores = [];
}
unsubs.forEach(function (unsub, store) {
if (!usedStores.includes(store) && unsub) unsub();
});
}
function stopSubscriptions() {
unsubs.forEach(function (unsub) {
return unsub && unsub();
});
}
/* Create a new map of values by store, reusing old ones when they exist. */
function updateValues(stores) {
if (stores === void 0) {
stores = [];
}
values = new Map(stores.map(function (store) {
return [store, values.get(store)];
}));
}
/* Recompute and publish the combined result on values,
* using `_stores` to ensure values order consistency. */
function sync() {
if (pending) return;
cleanup();
var vals = _stores.reduce(function (acc, store) {
return values.has(store) ? [].concat(acc, [values.get(store)]) : acc;
}, []);
var result = fn(vals, publish);
if (auto) {
publish(result);
} else {
cleanup = typeof result === "function" ? result : noop;
}
}
var unsubscribe = $stores.subscribe(function (stores) {
updateUnsubs(stores);
updateValues(stores);
/* Subscribe to each store if not alreay done.
* When a any store value changes,
* combined result will be updated and published. */
_stores = [];
stores.forEach(function (store, i) {
_stores[i] = store;
if (!unsubs.get(store)) {
unsubs.set(store, store.subscribe(function (value) {
values.set(store, value);
pending &= ~(1 << i);
if (initialized) sync();
}, function () {
pending |= 1 << i;
}));
}
});
if (initialized) sync();
});
initialized = true;
sync();
return function stop() {
unsubscribe();
stopSubscriptions();
cleanup();
};
});
/* Exclude one or mode stores from the list. */
function exclude() {
var _arguments = arguments;
$stores.update(function (prev) {
return prev.filter(function (store) {
return ![].slice.call(_arguments).includes(store);
});
});
}
/* Include one or more stores into the list. */
function include() {
var _arguments2 = arguments;
$stores.update(function (prev) {
return [].concat(prev, [].slice.call(_arguments2));
});
}
return {
exclude: exclude,
include: include,
set: $stores.set,
stores: $stores,
subscribe: mainStore.subscribe,
update: $stores.update
};
}
var identity = function identity(x) {
return x;
};
var isColl = function isColl(x) {
return ["array", "map", "object"].includes(typeOf(x));
};
var isFunc = function isFunc(x) {
return typeof x === "function";
};
var isStore = function isStore(x) {
return x && x.subscribe && isFunc(x.subscribe);
};
var typeOf = function typeOf(obj) {
return {}.toString.call(obj).split(" ")[1].slice(0, -1).toLowerCase();
};
function entries(coll) {
var fn = {
array: function array() {
return coll.map(function (v, i) {
return [i, v];
});
},
map: function map() {
return [].concat(coll.entries());
},
object: function object() {
return Object.entries(coll);
}
}[typeOf(coll)];
return fn ? fn(coll) : [];
}
function fromEntries(entries, toType) {
var fn = {
array: function array() {
return entries.map(function (_ref) {
var val = _ref[1];
return val;
});
},
map: function map() {
return new Map(entries);
},
object: function object() {
return Object.fromEntries(entries);
}
}[toType];
return fn ? fn() : fromEntries(entries, "map");
}
function values(coll) {
var fn = {
array: function array() {
return [].concat(coll);
},
map: function map() {
return [].concat(coll.values());
},
object: function object() {
return Object.values(coll);
}
}[typeOf(coll)];
return fn ? fn(coll) : [];
}
function keys(coll) {
var fn = {
array: function array() {
return coll.map(function (v, i) {
return i;
});
},
map: function map() {
return [].concat(coll.keys());
},
object: function object() {
return Object.keys(coll);
}
}[typeOf(coll)];
return fn ? fn(coll) : [];
}
/* Merge multiple collections of identical type with right to left arguments precedence. */
function merge() {
var colls = [].slice.call(arguments).filter(isColl);
var type = typeOf(colls[0]);
if (!colls.every(function (coll) {
return typeOf(coll) === type;
})) {
var collTypes = colls.map(typeOf).join(", ");
throw new TypeError("Collections must be of same type. Received '" + collTypes + "'.");
}
var fn = {
array: function array() {
return colls.reduce(function (acc, coll) {
if (coll.length >= acc.length) return coll;
return [].concat(coll, acc.slice(coll.length));
}, []);
},
map: function map() {
return new Map(colls.map(function (coll) {
return coll.entries();
}));
},
object: function object() {
return Object.assign.apply(Object, [{}].concat(colls));
}
}[type];
if (!fn) throw new Error("'merge' not implemented yet for " + type);
return fn();
}
function genRandomId() {
return (Math.random() * 1e9).toFixed(0);
}
function get(key, coll) {
var fn = {
array: function array() {
return coll[key];
},
map: function map() {
return coll.get(key);
},
object: function object() {
return coll[key];
}
}[typeOf(coll)];
return fn ? fn(key, coll) : undefined;
}
function getPath(path, value) {
if (path === void 0) {
path = [];
}
return path.reduce(function (parent, key) {
return get(key, parent);
}, value);
}
function countPathAncestors(str) {
if (str === void 0) {
str = "";
}
return (str.match(/\.\.\/|\.\.$/g) || []).length;
}
function keepForwardPath(str) {
if (str === void 0) {
str = "";
}
return str.split("/").reduce(function (acc, node) {
if (!node || node.startsWith(".")) return acc;
var index = parseInt(node, 10);
return [].concat(acc, [isNaN(index) ? node : index]);
}, []);
}
function equals(a, b, eqBy) {
if (eqBy === void 0) {
eqBy = defaultEqBy;
}
var _map = [a, b].map(eqBy),
_a = _map[0],
_b = _map[1];
return _a === _b || fastEquals__default['default'](_a, _b);
}
function defaultEqBy(x) {
if (x instanceof Date) return x.valueOf();
if (isColl(x)) return removeUndefined(x);
return x;
}
function removeUndefined(x) {
if (!isColl(x)) return x;
return fromEntries(entries(x).reduce(function (acc, _ref2) {
var key = _ref2[0],
val = _ref2[1];
return val === undefined ? acc : [].concat(acc, [[key, removeUndefined(val)]]);
}, []), typeOf(x));
}
function deriveState(coll) {
var storesEntries = entries(coll);
return {
coll: coll,
collType: typeOf(coll),
storesEntries: storesEntries,
keys: storesEntries.map(function (_ref) {
var key = _ref[0];
return key;
}),
stores: storesEntries.map(function (_ref2) {
var store = _ref2[1];
return store;
})
};
}
function collDerived(initialColl, fn, initialValue) {
if (fn === void 0) {
fn = identity;
}
var state = deriveState(initialColl);
/* The callback passed to `flexDerived` can have arity 1 or 2.
* The arity should match the one of the provided function.
* When using arity 2, a set function is provided so that
* result can be used asynchronously */
var auto = fn.length < 2;
var index$stores = function index$stores($stores) {
return fromEntries($stores.map(function (store, idx) {
return [state.keys[idx], store];
}), state.collType);
};
var values = flexDerived(state.stores, auto ? function ($stores) {
return fn(index$stores($stores));
} : function ($stores, _set) {
return fn(index$stores($stores), _set);
}, initialValue);
function set(newColl) {
state = deriveState(newColl);
values.set(state.stores);
}
return {
set: set,
subscribe: values.subscribe
};
}
var ALWAYS_VALID = {
valid: true
};
var REQUIRED_SPECMA_FNS = ["and", "getMessage", "getPred", "getSpread", "isOpt", "validatePred"];
var CONFIG_ERROR_MSG = "SvelteSpecma must be configured with a valid Specma version.";
var specma = undefined;
function ensureConfigured() {
if (!specma) {
throw new TypeError(CONFIG_ERROR_MSG);
}
}
function configure(specmaFns) {
if (!specmaFns || REQUIRED_SPECMA_FNS.some(function (key) {
return typeof specmaFns[key] !== "function";
})) {
throw new TypeError(CONFIG_ERROR_MSG);
}
specma = specmaFns;
}
/* Limited version of `writable` store that updates only
* if the new set value is different by value (deep equality) */
function wriableByValue(initialValue) {
var _value = initialValue;
var store$1 = store.writable.apply(void 0, [initialValue].concat([].slice.call(arguments, 1)));
return {
set: function set(newValue) {
if (fastEquals__default['default'](newValue, _value)) return;
_value = newValue;
store$1.set(_value);
},
subscribe: store$1.subscribe
};
}
var alwaysTrue = function alwaysTrue() {
return true;
};
var isMissing = function isMissing(x) {
return [undefined, null, ""].includes(x);
};
var defaultChangePred = function defaultChangePred(a, b) {
return !equals(a, b);
};
var reqSpec = function reqSpec(x) {
return !isMissing(x) || specma.getMessage("isRequired");
};
function predSpecable(initialValue, _temp, _extra) {
var submit = function submit() {
try {
if (!onSubmit) return Promise.resolve();
submitting.set(true);
return Promise.resolve(activate()).then(function (valid) {
function _temp3() {
submitting.set(false);
}
var _temp2 = function () {
if (valid) {
var currValue = store.get(value);
return Promise.resolve(onSubmit(currValue)).then(function () {});
}
}();
return _temp2 && _temp2.then ? _temp2.then(_temp3) : _temp3(_temp2);
});
} catch (e) {
return Promise.reject(e);
}
};
var activate = function activate(bool) {
if (bool === void 0) {
bool = true;
}
try {
active.set(bool);
return Promise.resolve(svelte.tick()).then(function () {
return Promise.resolve(currPromise).then(function (res) {
return res.valid;
});
});
} catch (e) {
return Promise.reject(e);
}
};
var _ref = _temp === void 0 ? {} : _temp,
_ref$changePred = _ref.changePred,
changePred = _ref$changePred === void 0 ? defaultChangePred : _ref$changePred,
id = _ref.id,
required = _ref.required,
spec = _ref.spec,
onSubmit = _ref.onSubmit;
if (_extra === void 0) {
_extra = {};
}
ensureConfigured();
var and = specma.and,
getPred = specma.getPred,
validatePred = specma.validatePred;
var _extra2 = _extra,
getAncestor = _extra2.getAncestor;
var pred = getPred(spec) || alwaysTrue;
var isRequired = !!required;
var ownSpec = isRequired ? and(reqSpec, pred) : pred;
var contextStores = {};
var context = collDerived(contextStores);
function addContext(relPath) {
/* If `getFrom` has already been called once,
* context store is already tracking the value. */
if (contextStores[relPath]) return;
var ancestor = getAncestor(countPathAncestors(relPath));
if (!ancestor) return;
var pathSinceAncestor = keepForwardPath(relPath);
contextStores[relPath] = store.derived(ancestor, function ($ancestor, set) {
var ancestorValue = $ancestor.value;
if (!ancestorValue) return;
var curr = contextStores[relPath].value;
var next = getPath(pathSinceAncestor, ancestorValue);
if (!equals(curr, next)) {
contextStores[relPath].value = next;
set(next);
}
});
context.set(contextStores);
/* If context has just been created, it won't be accessible
* in the derived store at first.
* In that case, return the static store value. */
return getPath(pathSinceAncestor, store.get(ancestor).value);
}
var currPromise;
var _initialValue = initialValue;
var active = store.writable(false);
var submitting = store.writable(false);
var value = wriableByValue(_initialValue);
var store$1 = store.derived([active, value, context, submitting], function (_ref2, set) {
var $active = _ref2[0],
$value = _ref2[1],
$context = _ref2[2],
$submitting = _ref2[3];
currPromise = undefined;
function getFrom(relPath) {
if (!contextStores[relPath]) {
return addContext(relPath);
}
return $context[relPath];
}
var shouldValidate = $active && ($value !== undefined || required);
var result = enhanceResult(shouldValidate ? validatePred(ownSpec, $value, getFrom) : ALWAYS_VALID);
var baseArgs = {
active: $active,
changePred: changePred,
initialValue: _initialValue,
id: id,
result: result,
submitting: $submitting,
value: $value
};
currPromise = result.promise;
set(interpretState(baseArgs));
if (result.valid === null) {
result.promise.then(function (resolvedResult) {
/* Promise might be outdated */
if (result.promise !== currPromise) return;
set(interpretState(_extends({}, baseArgs, {
result: resolvedResult
})));
});
}
});
return {
id: id,
isRequired: isRequired,
spec: pred,
activate: activate,
reset: function reset(newValue) {
if (newValue === void 0) {
newValue = _initialValue;
}
_initialValue = newValue;
this.activate(false);
this.set(newValue);
},
set: function set(newValue, shouldActivate) {
if (shouldActivate === void 0) {
shouldActivate = false;
}
value.set(newValue);
if (shouldActivate) activate();
},
submit: submit,
subscribe: store$1.subscribe
};
}
function enhanceResult(res) {
return _extends({}, res, {
promise: res.promise ? res.promise.then(function (promised) {
return enhanceResult(promised);
}) : Promise.resolve(res)
});
}
function interpretState(_ref3) {
var active = _ref3.active,
changePred = _ref3.changePred,
id = _ref3.id,
initialValue = _ref3.initialValue,
result = _ref3.result,
submitting = _ref3.submitting,
value = _ref3.value;
var changed = changePred(value, initialValue);
return {
active: active,
changed: changed,
error: result.valid === false && result.reason,
id: id,
initialValue: initialValue,
promise: result.promise || Promise.resolve(result),
submitting: submitting,
valid: !!result.valid,
validating: result.valid === null,
value: changed ? value : initialValue
};
}
function collSpecable(initialValue, _temp, _extra) {
var _this = this;
var submit = function submit() {
try {
if (!onSubmit) return Promise.resolve();
submitting.set(true);
return Promise.resolve(activate()).then(function (valid) {
function _temp4() {
submitting.set(false);
}
var _temp3 = function () {
if (valid) {
var currValue = store.get(ownSpecable).value;
return Promise.resolve(onSubmit(currValue)).then(function () {});
}
}();
return _temp3 && _temp3.then ? _temp3.then(_temp4) : _temp4(_temp3);
});
} catch (e) {
return Promise.reject(e);
}
};
var _ref = _temp === void 0 ? {} : _temp,
changePred = _ref.changePred,
fields = _ref.fields,
getId = _ref.getId,
id = _ref.id,
required = _ref.required,
spec = _ref.spec,
onSubmit = _ref.onSubmit;
if (_extra === void 0) {
_extra = {};
}
ensureConfigured();
var getPred = specma.getPred,
getSpread = specma.getSpread,
isOpt = specma.isOpt;
var collValue = initialValue; // For static properties
var isUndef = collValue === undefined;
var _extra2 = _extra,
_getAncestor = _extra2.getAncestor;
var collDefiner = [fields, spec, initialValue].find(isColl);
var collType = typeOf(collDefiner);
var isRequired = required && !isOpt(required);
var spreadGetId = getSpread(getId);
var spreadSpec = getSpread(spec);
var spreadFields = getSpread(fields);
var spreadRequired = getSpread(required);
var isSpread = spreadSpec || spreadFields || spreadRequired || spreadGetId || collType === "array";
var valueKeys = isSpread ? keys(initialValue) : [];
var allKeys = new Set(fields ? [].concat(keys(fields), valueKeys) : [].concat(keys(spec), keys(required), valueKeys));
var ownGetId = getPred(getId);
var idGen = function idGen(v, k) {
if (ownGetId) return ownGetId(v, k);
if (collType === "array") return genRandomId();
return k;
};
var ownSpecable = predSpecable(initialValue, {
changePred: getPred(changePred),
id: id,
required: isRequired,
spec: spec
}, _extra);
var createChildEntry = function createChildEntry(key, val) {
var subChangePred = get(key, changePred) || getSpread(changePred);
var subVal = val;
var subSpec = get(key, spec) || spreadSpec;
var subGetId = get(key, getId) || spreadGetId;
var subId = idGen(subVal, key);
var subFields = get(key, fields) || spreadFields;
var subRequired = get(key, required) || spreadRequired;
var subStore = _extra.specable(subVal, {
spec: subSpec,
changePred: subChangePred,
id: subId,
getId: subGetId,
fields: subFields,
required: subRequired
}, {
getAncestor: function getAncestor(n) {
return n <= 1 || !_getAncestor ? ownSpecable : _getAncestor(n - 1);
}
});
return [key, _extends({}, subStore, {
id: subId
})];
};
var childrenStores = fromEntries([].concat(allKeys).map(function (key) {
return createChildEntry(key, get(key, initialValue));
}), collType);
var children = store.writable(childrenStores);
var submitting = store.writable(false);
var derivedValue = collDerived(childrenStores, function ($childrenStores) {
if (isUndef) return undefined;
var $childrenEntries = entries($childrenStores);
var $childrenValues = $childrenEntries.map(function (_ref2) {
var key = _ref2[0],
state = _ref2[1];
return [key, state.value];
});
var childrenValue = fromEntries($childrenValues, collType);
var value = isSpread ? childrenValue : merge(collValue, childrenValue);
isUndef = value === undefined;
return value;
});
var aggregateStatusStores = function aggregateStatusStores() {
return [submitting, ownSpecable].concat(values(childrenStores));
};
var status = flexDerived(aggregateStatusStores(), function ($statusStores) {
var $submitting = $statusStores[0],
$ownSpecable = $statusStores[1],
$children = $statusStores.slice(2);
var combined = isUndef ? $ownSpecable : [$ownSpecable].concat($children).reduce(combineChildren);
if (combined.active !== false) ownSpecable.activate();
var value = $ownSpecable.value,
error = $ownSpecable.error;
var details = Object.fromEntries([["_", $ownSpecable]].concat(isUndef ? [] : $children.map(function (child) {
return [child.id, child];
})));
var errors = detailsToErrors(details, id);
var collErrors = errors.filter(function (_ref3) {
var isColl = _ref3.isColl;
return isColl;
});
return _extends({}, combined, {
id: id,
initialValue: $ownSpecable.initialValue,
value: value,
error: error,
errors: errors,
collErrors: collErrors,
details: details,
submitting: $submitting
});
});
function setChildrenStores(newChildrenStores) {
childrenStores = newChildrenStores;
children.set(newChildrenStores);
derivedValue.set(newChildrenStores);
status.set(aggregateStatusStores());
}
function addChildren(coll) {
if (!coll) return;
var newEntries = keys(coll).map(function (key) {
return createChildEntry(key, get(key, coll));
});
var updatedStores = fromEntries([].concat(entries(childrenStores), newEntries), collType);
setChildrenStores(updatedStores);
}
function removeChildrenById(idsToRemove) {
if (idsToRemove === void 0) {
idsToRemove = [];
}
if (idsToRemove.length < 1) return;
var updatedStores = fromEntries(entries(childrenStores).filter(function (_ref4) {
var store = _ref4[1];
return !idsToRemove.includes(store.id);
}), collType);
setChildrenStores(updatedStores);
}
function setValue(coll, _temp2) {
var _ref5 = _temp2 === void 0 ? {} : _temp2,
_ref5$partial = _ref5.partial,
partial = _ref5$partial === void 0 ? false : _ref5$partial,
_ref5$reset = _ref5.reset,
reset = _ref5$reset === void 0 ? false : _ref5$reset;
var setMethod = reset ? "reset" : "set";
collValue = !reset && partial && !isSpread ? merge(collValue, coll) : coll;
isUndef = collValue === undefined;
ownSpecable[setMethod](collValue);
var childrenEntries = entries(childrenStores);
childrenEntries.forEach(function (_ref6) {
var key = _ref6[0],
store = _ref6[1];
var newValue = get(key, coll);
if (partial && newValue === undefined) return;
store[setMethod](newValue, partial);
});
if (!isSpread) return;
/* If collection allows spread children... */
/* Add `coll` entries that are not yet part of the children stores. */
var childrenKeys = keys(childrenStores);
var missingChildrenEntries = entries(coll).filter(function (_ref7) {
var key = _ref7[0];
return !childrenKeys.includes(key);
});
if (missingChildrenEntries.length > 0) {
addChildren(fromEntries(missingChildrenEntries, collType));
}
if (partial) return;
/* If update is not partial, remove children stores that do not store
* a collection value anymore (garbage collection). */
var collKeys = keys(coll);
var unusedIds = childrenEntries.reduce(function (acc, _ref8) {
var key = _ref8[0],
childStore = _ref8[1];
return collKeys.includes(key) ? acc : [].concat(acc, [childStore.id]);
}, []);
removeChildrenById(unusedIds);
}
function activate(bool) {
if (bool === void 0) {
bool = true;
}
var storesToActivate = [ownSpecable].concat(isUndef ? [] : values(childrenStores));
var promises = storesToActivate.map(function (store) {
var promise = store.activate(bool);
return promise.then(function (valid) {
if (valid) return valid;
throw valid;
});
});
return Promise.all(promises).then(function () {
return true;
})["catch"](function () {
return false;
});
}
return {
id: id,
isRequired: isRequired,
spec: spec,
stores: childrenStores,
activate: activate,
add: function add(coll) {
if (coll !== undefined) isUndef = false;
addChildren(coll);
return this;
},
getChild: function getChild(path) {
if (path === void 0) {
path = [];
}
var reduced = path.reduce(function (acc, key) {
var children = acc.children;
if (!children) return {
res: null
};
var childStore = get(key, children);
if (!childStore) return {
res: null
};
return {
res: childStore,
children: childStore.getChildren ? childStore.getChildren() : []
};
}, {
children: childrenStores
});
return reduced.res;
},
getChildren: function getChildren() {
return childrenStores;
},
remove: function remove(idsToRemove) {
if (idsToRemove === void 0) {
idsToRemove = [];
}
removeChildrenById(idsToRemove);
return this;
},
reset: function reset(newInitialValue) {
if (newInitialValue === void 0) {
newInitialValue = initialValue;
}
setValue(newInitialValue, {
reset: true
});
activate(false);
return this;
},
set: function set(coll, partial, shouldActivate) {
if (partial === void 0) {
partial = false;
}
if (shouldActivate === void 0) {
shouldActivate = false;
}
setValue(coll, {
partial: partial
});
if (shouldActivate) activate();
return this;
},
update: function update(fn) {
setChildrenStores(fn(childrenStores));
return _this;
},
children: {
subscribe: children.subscribe
},
submit: submit,
subscribe: function subscribe(fn) {
var unsub1 = derivedValue.subscribe(function (value) {
return ownSpecable.set(value);
});
var unsub2 = status.subscribe(fn);
return function () {
unsub1();
unsub2();
};
}
};
}
function combineChildren(a, b) {
var validating = a.validating || b.validating;
return {
active: a.active === b.active ? b.active : null,
changed: a.changed || b.changed,
valid: validating ? null : a.valid && b.valid,
validating: validating
};
}
var liftError = function liftError(parentId) {
return function (_ref9) {
var path = _ref9.path,
error = _ref9.error,
rest = _objectWithoutPropertiesLoose(_ref9, ["path", "error"]);
var newPath = parentId === undefined ? path : [parentId].concat(path);
return _extends({}, rest, {
path: newPath,
which: newPath.join("."),
error: error
});
};
};
function detailsToErrors(details, parentId) {
return Object.entries(details).flatMap(function (_ref10) {
var key = _ref10[0],
status = _ref10[1];
if (!status.details) {
if (!status.error) return [];
if (key === "_") {
return [{
path: [],
error: status.error,
isColl: true
}];
}
return [summarizeStatusError(status)];
}
var subErrors = detailsToErrors(status.details, details.id);
return subErrors.map(liftError(status.id));
}).map(liftError(parentId));
}
function summarizeStatusError(_ref11) {
var id = _ref11.id,
error = _ref11.error;
return {
path: [id],
which: id,
error: error
};
}
function register(el, storeOrArgs) {
var args = normalizeArgs(storeOrArgs);
if (!el || !args.store) return;
var unsub;
listen();
function blurHandler() {
args.store.activate();
}
function inputHandler(e) {
args.store.set(args.toValue(e.target.value));
}
function listen() {
unsub = args.store.subscribe(function (_ref) {
var value = _ref.value;
var elValue = args.toInput(value);
if (el.value !== elValue) el.value = elValue;
});
el.addEventListener("blur", blurHandler);
el.addEventListener("input", inputHandler);
}
function unlisten() {
unsub();
el.removeEventListener("blur", blurHandler);
el.removeEventListener("input", inputHandler);
}
return {
destroy: unlisten,
update: function update(newArgs) {
unlisten();
if (!newArgs) return;
args = normalizeArgs(newArgs);
listen();
}
};
}
function normalizeArgs(storeOrArgs) {
if (!storeOrArgs) return {};
if (!Array.isArray(storeOrArgs)) {
return {
store: storeOrArgs,
toInput: function toInput(x) {
if (x === void 0) {
x = "";
}
return x;
},
toValue: identity
};
}
var store = storeOrArgs[0],
_storeOrArgs$ = storeOrArgs[1];
_storeOrArgs$ = _storeOrArgs$ === void 0 ? {} : _storeOrArgs$;
var _storeOrArgs$$toInput = _storeOrArgs$.toInput,
toInput = _storeOrArgs$$toInput === void 0 ? identity : _storeOrArgs$$toInput,
_storeOrArgs$$toValue = _storeOrArgs$.toValue,
toValue = _storeOrArgs$$toValue === void 0 ? identity : _storeOrArgs$$toValue;
return {
store: store,
toInput: toInput,
toValue: toValue
};
}
function specable(initialValue, options, _extra) {
if (options === void 0) {
options = {};
}
if (isStore(initialValue)) return initialValue;
var collCandidate = options.fields || options.spec || initialValue;
if (isColl(collCandidate)) {
return collSpecable(initialValue, options, _extends({}, _extra, {
specable: specable
}));
}
return predSpecable(initialValue, options, _extra);
}
exports.collSpecable = collSpecable;
exports.configure = configure;
exports.predSpecable = predSpecable;
exports.register = register;
exports.specable = specable;
})));
//# sourceMappingURL=svelte-specma.umd.js.map