const struct = (query) => { const keys = Object.keys(query).sort(); keys.mapObj = (fn) => { let obj = {}; keys.forEach((k) => (obj[k] = fn(k))); return obj; }; return variants({ validate(val) { return keys.every((k) => query[k].validate(val[k])); }, descend([i, ...path]) { if (i === undefined) return this; return query[i] && query[i].descend(path); }, intoKey(val, arr) { keys.forEach((k) => query[k].intoKey(val[k], arr)); }, fromKey(arr) { return keys.mapObj((k) => query[k].fromKey(arr)); }, min: keys.mapObj((k) => query[k].min), max: keys.mapObj((k) => query[k].max), isBounded: keys.some((key) => query[key].isBounded), }); }