immutable-js
Version:
Immutable types in JavaScript
149 lines (130 loc) • 4.35 kB
JavaScript
/**
* Copyright (c) 2015, Jan Biasi.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
import { KeyedIterable } from './Iterable';
import { KeyedCollection } from './Collection';
import { NativeObject } from './Native';
import { Map, emptyMap, makeMap } from './Map';
import { invariant, typedef as defineTypeOf } from './util/toolset';
import { nullOrUndefined } from './util/is';
export var RECORD_TYPEDEF = '[KeyedCollection Record]';
export class Record extends KeyedCollection {
constructor(defaultValues, name) {
var init;
var RecordType = function Record(values) {
if(values instanceof RecordType) {
return values;
}
if(!(this instanceof RecordType)) {
return new RecordType(values);
}
if(!init) {
init = true;
var keys = Object.keys(defaultValues);
setProps(RecordTypePrototype, keys);
RecordTypePrototype.size = keys.length || 0;
RecordTypePrototype.name = name;
RecordTypePrototype.__keys = keys;
RecordTypePrototype.__defaultValues = defaultValues;
}
RecordTypePrototype.__internal = new Map();
return RecordTypePrototype;
}
var RecordTypePrototype = RecordType.prototype = Object.create(Record.prototype);
RecordTypePrototype.constructor = RecordType;
return RecordType;
}
toString() {
return this.__toString(recordName(this) + '{', this.__keys.join(','), '}');
}
toMap() {
return makeMap(this.__internal, this.__ownerID);
}
has(key) {
return this.__defaultValues.hasOwnProperty(key);
}
get(key, notSetValue) {
if(!this.has(key)) {
return notSetValue;
}
var defval = this.__defaultValues[key];
return this.__internal ? this.__internal.get(key, defval) : defval;
}
set(key, value) {
if(!this.has(key)) {
throw new Error('Can\'t set unknown key "' + key + '" on ' + recordName(this));
}
var newMap = this.__internal && this.__internal.set(key, value);
if(this.__ownerID || newMap === this.__internal) {
return this;
}
return makeRecord(this, newMap);
}
remove(key) {
if (!this.has(key)) {
return this;
}
var newMap = this._map && this.__internal.remove(key);
if (this.__ownerID || newMap === this.__internal) {
return this;
}
return makeRecord(this, newMap);
}
clear() {
if(this.__ownerID) {
this.__internal && this.__internal.clear();
return this;
}
var RecordType = this.constructor;
return RecordType.__empty || (RecordType.__empty = makeRecord(this, emptyMap()))
}
wasAltered() {
return this.__internal.wasAltered();
}
__ensureOwner(ownerID) {
if(ownerID === this.__ownerID) {
return this;
}
if(!ownerID || nullOrUndefined(ownerID)) {
this.__ownerID = ownerID;
this.__altered = false;
return this;
}
return makeRecord(this, this.__internal, ownerID);
}
}
function makeRecord(recordType, map, ownerID) {
var record = Object.create(Object.getPrototypeOf(recordType));
record.__internal = map;
record.__ownerID = ownerID;
return record;
}
function recordName(record) {
return record._name || record.constructor.name || 'Record';
}
function setProp(prototype, name) {
Object.defineProperty(prototype, name, {
get: function() {
return this.get(name);
},
set: function(value) {
invariant(this.__ownerID, 'Can\'t call set on an immutable record.');
this.set(name, value);
}
});
}
function setProps(prototype, names) {
try {
names.forEach(setProp.bind(undefined, prototype));
} catch (error) {
// Maybe IE8.
}
}
defineTypeOf({
Record: RECORD_TYPEDEF
});