immutable-class
Version:
A template for creating immutable classes
165 lines (164 loc) • 5.62 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.NamedArray = exports.Diff = void 0;
const equality_1 = require("../equality/equality");
const keyed_array_1 = require("../keyed-array/keyed-array");
const simple_array_1 = require("../simple-array/simple-array");
function getName(thing) {
return thing.name;
}
function noop() { }
class Diff {
static inflateFromJS(Class, diffJS, context) {
let before;
let after;
if (diffJS.before)
before = Class.fromJS(diffJS.before, context);
if (diffJS.after)
after = Class.fromJS(diffJS.after, context);
return new Diff(before, after);
}
static inflateFromJSs(Class, diffJSs, context) {
if (!Array.isArray(diffJSs))
throw new Error('diffs must be an array');
return diffJSs.map(diffJS => Diff.inflateFromJS(Class, diffJS, context));
}
constructor(before, after) {
Object.defineProperty(this, "before", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "after", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
if (!before && !after)
throw new Error('must have either a before or an after');
if (before && after && before.name !== after.name)
throw new Error('before and after name must match');
this.before = before;
this.after = after;
}
toJS() {
const js = {};
if (this.before)
js.before = this.before;
if (this.after)
js.after = this.after;
return js;
}
toJSON() {
return this.toJS();
}
getAction() {
if (this.before) {
return this.after ? 'update' : 'delete';
}
else {
return 'create';
}
}
getName() {
const { before, after } = this;
if (before)
return before.name;
if (after)
return after.name;
throw new Error(`Invalid diff, no before or after`);
}
}
exports.Diff = Diff;
const KEYED_ARRAY = keyed_array_1.KeyedArray.withKey('name');
class NamedArray {
static isValid(array) {
return KEYED_ARRAY.isValid(array);
}
static checkValid(array, what, where) {
return KEYED_ARRAY.checkValid(array, what, where);
}
static get(array, name) {
return KEYED_ARRAY.get(array, name);
}
static toRecord(array) {
return KEYED_ARRAY.toRecord(array);
}
static containsByName(array, name) {
return simple_array_1.SimpleArray.contains(array, x => x.name === name);
}
static findByNameCI(array, name) {
const lowerName = name.toLowerCase();
return simple_array_1.SimpleArray.find(array, x => x.name.toLowerCase() === lowerName);
}
static findByName(array, name) {
return NamedArray.get(array, name);
}
static findIndexByName(array, name) {
return simple_array_1.SimpleArray.findIndex(array, x => x.name === name);
}
static overrideByName(things, thingOverride) {
return KEYED_ARRAY.overrideByKey(things, thingOverride);
}
static overridesByName(things, thingOverrides) {
return KEYED_ARRAY.overridesByKey(things, thingOverrides);
}
static dedupe(things) {
return KEYED_ARRAY.dedupe(things);
}
static deleteByName(array, name) {
return KEYED_ARRAY.deleteByKey(array, name);
}
static synchronize(oldThings, newThings, updatedOptions) {
const key = updatedOptions.key || getName;
const equals = updatedOptions.equals || equality_1.immutableEqual;
const onEnter = updatedOptions.onEnter || noop;
const onUpdate = updatedOptions.onUpdate || noop;
const onExit = updatedOptions.onExit || noop;
const initialByKey = Object.create(null);
for (let i = 0; i < oldThings.length; i++) {
const initialThing = oldThings[i];
const initialThingKey = key(initialThing);
if (initialByKey[initialThingKey])
throw new Error(`duplicate key '${initialThingKey}'`);
initialByKey[initialThingKey] = initialThing;
}
for (let j = 0; j < newThings.length; j++) {
const newThing = newThings[j];
const newThingKey = key(newThing);
const oldThing = initialByKey[newThingKey];
if (oldThing) {
if (!equals(newThing, oldThing)) {
onUpdate(newThing, oldThing);
}
delete initialByKey[newThingKey];
}
else {
onEnter(newThing);
}
}
for (const k in initialByKey) {
if (!initialByKey[k])
continue;
onExit(initialByKey[k]);
}
}
static computeDiffs(oldThings, newThings) {
const dataCubeDiffs = [];
NamedArray.synchronize(oldThings, newThings, {
onExit: oldDataCube => {
dataCubeDiffs.push(new Diff(oldDataCube, undefined));
},
onUpdate: (newDataCube, oldDataCube) => {
dataCubeDiffs.push(new Diff(oldDataCube, newDataCube));
},
onEnter: newDataCube => {
dataCubeDiffs.push(new Diff(undefined, newDataCube));
},
});
return dataCubeDiffs;
}
}
exports.NamedArray = NamedArray;
;