diff options
Diffstat (limited to 'src_js/hatter/util.js')
| -rw-r--r-- | src_js/hatter/util.js | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/src_js/hatter/util.js b/src_js/hatter/util.js new file mode 100644 index 0000000..e3dbfeb --- /dev/null +++ b/src_js/hatter/util.js @@ -0,0 +1,172 @@ +
+
+export const isArray = Array.isArray;
+export const isObject = obj => obj !== null &&
+ typeof(obj) == 'object' &&
+ !isArray(obj);
+export const isNumber = n => typeof(n) == 'number';
+export const isInteger = Number.isInteger;
+export const isString = str => typeof(str) == 'string';
+
+
+export function clone(obj) {
+ if (isArray(obj))
+ return Array.from(obj, clone);
+ if (isObject(obj)) {
+ let ret = {};
+ for (let i in obj)
+ ret[i] = clone(obj[i]);
+ return ret;
+ }
+ return obj;
+}
+
+
+export function equals(x, y) {
+ if (x === y)
+ return true;
+ if (typeof(x) != 'object' || typeof(y) != 'object' || x === null || y === null)
+ return false;
+ if (Array.isArray(x) || Array.isArray(y)) {
+ if (!Array.isArray(x) || !Array.isArray(y) || x.length != y.length)
+ return false;
+ }
+ for (let i in x)
+ if (!equals(x[i], y[i]))
+ return false;
+ for (let i in y)
+ if (!equals(x[i], y[i]))
+ return false;
+ return true;
+}
+
+
+export function toPairs(obj) {
+ return Object.entries(obj);
+}
+
+
+export function fromPairs(arr) {
+ let ret = {};
+ for (let [k, v] of arr)
+ ret[k] = v;
+ return ret;
+}
+
+
+export function* flatten(arr) {
+ if (isArray(arr)) {
+ for (let i of arr)
+ if (isArray(i))
+ yield* flatten(i);
+ else
+ yield i;
+ } else {
+ yield arr;
+ }
+}
+
+
+export function pipe(...fns) {
+ if (fns.length < 1)
+ throw 'no functions';
+ return function (...args) {
+ let ret = fns[0].apply(this, args);
+ for (let fn of fns.slice(1))
+ ret = fn(ret);
+ return ret;
+ };
+}
+
+
+export function curry(fn) {
+ let wrapper = function(oldArgs) {
+ return function(...args) {
+ args = oldArgs.concat(args);
+ if (args.length >= fn.length)
+ return fn.apply(this, args);
+ return wrapper(args);
+ };
+ };
+ return wrapper([]);
+}
+
+
+export const get = curry((path, obj) => {
+ let ret = obj;
+ for (let i of flatten(path)) {
+ if (ret === null || typeof(ret) != 'object')
+ return undefined;
+ ret = ret[i];
+ }
+ return ret;
+});
+
+
+export const change = curry((path, fn, obj) => {
+ function _change(path, obj) {
+ if (isInteger(path[0])) {
+ obj = (isArray(obj) ? Array.from(obj) : []);
+ } else if (isString(path[0])) {
+ obj = (isObject(obj) ? Object.assign({}, obj) : {});
+ } else {
+ throw 'invalid path';
+ }
+ if (path.length > 1) {
+ obj[path[0]] = _change(path.slice(1), obj[path[0]]);
+ } else {
+ obj[path[0]] = fn(obj[path[0]]);
+ }
+ return obj;
+ }
+ path = Array.from(flatten(path));
+ if (path.length < 1)
+ return fn(obj);
+ return _change(path, obj);
+});
+
+
+export const set = curry((path, val, obj) => change(path, _ => val, obj));
+
+
+export const omit = curry((path, obj) => {
+ function _omit(path, obj) {
+ if (isInteger(path[0])) {
+ obj = (isArray(obj) ? Array.from(obj) : []);
+ } else if (isString(path[0])) {
+ obj = (isObject(obj) ? Object.assign({}, obj) : {});
+ } else {
+ throw 'invalid path';
+ }
+ if (path.length > 1) {
+ obj[path[0]] = _omit(path.slice(1), obj[path[0]]);
+ } else {
+ delete obj[path[0]];
+ }
+ return obj;
+ }
+ path = Array.from(flatten(path));
+ if (path.length < 1)
+ return undefined;
+ return _omit(path, obj);
+});
+
+
+export const sortBy = curry((fn, arr) => Array.from(arr).sort((x, y) => {
+ let xVal = fn(x);
+ let yVal = fn(y);
+ if (xVal < yVal)
+ return -1;
+ if (xVal > yVal)
+ return 1;
+ return 0;
+}));
+
+
+export const map = curry((fn, arr) => arr.map(fn));
+
+
+export const filter = curry((fn, arr) => arr.filter(fn));
+
+
+export const append = curry((val, arr) => arr.concat([val]));
|
