immutable-js
Version:
Immutable types in JavaScript
263 lines (227 loc) • 6.99 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 {
isIterable, isKeyed, isIndexed, isAssociative, isOrdered, isSequence, hasCache,
IS_ITERABLE_FLAG, IS_KEYED_FLAG, IS_INDEXED_FLAG, IS_ORDERED_FLAG, IS_SEQUENCE_FLAG
} from './Flags';
import { arrayLike as isArrayLike, nullOrUndefined } from './util/is';
import { Iterable } from './Iterable';
import { typedef as defineTypeOf } from './util/toolset';
export var SEQUENCE_TYPEDEF = '[Iterable ImmutableSequence]';
export class Sequence extends Iterable {
constructor(value) {
if(value === null || value === undefined) {
return emptySequence();
} else if(isIterable(value)) {
return value.toSequence();
} else {
return sequenceFromValue(value);
}
throw new Error(
'Couldn\'t create an immutable-sequence of: ' + value
);
}
static of(...value) {
return Sequence(value);
}
toSequence() {
return this;
}
cacheResult() {
if (!this._cache) {
this._cache = 'this.entrySeq().toArray()';
//this.size = this._cache.length;
}
return this;
}
toString() {
return this.__toString('Sequence [', null, ']');
}
}
export var INDEXED_SEQUENCE_TYPEDEF = '[Sequence IndexedSequence]';
export class IndexedSequence extends Sequence {
constructor(value) {
if(nullOrUndefined(value)) {
return emptySequence();
} else if(!isIterable(value)) {
return indexedSequenceFromData(value);
} else if(isKeyed(value)) {
return value.entrySequence();
} else {
return value.toIndexedSequence();
}
throw new Error(
'Couldn\'t create an indexed-sequence of: ' + value
);
}
static of(sequence) {
return IndexedSequence(sequence);
}
toIndexedSequence() {
return this;
}
toString() {
return this.__toString(INDEXED_SEQUENCE_TYPEDEF)
}
__iterate() {
console.log('Iterate on IterableSequence');
}
}
export var ARRAY_SEQUENCE_TYPEDEF = '[IndexedSequence ArraySequence]';
export class ArraySequence extends IndexedSequence {
constructor(array) {
this.__internal = array;
this.size = array.length;
}
__iterate(handle, reverse) {
var array = this.__internal;
var maxIndex = array.length - 1;
for(var n = 0; n <= maxIndex; n++) {
let findex = reverse ? maxIndex - n : n;
if(handle(array[findex], n, this) === false) {
return n + 1;
}
}
return n;
}
static of(array) {
return new ArraySequence(array);
}
toArraySequence() {
return this;
}
}
export var KEYED_SEQUENCE_TYPEDEF = '[Sequence KeyedSequence]';
export class KeyedSequence extends Sequence {
constructor(obj) {
}
toKeyedSequence() {
return this;
}
}
export var OBJECT_SEQUENCE_TYPEDEF = '[KeyedSequence ObjectSequence]';
export class ObjectSequence extends KeyedSequence {
constructor(object) {
var keys = Object.keys(object);
this.__object = object;
this.__keys = keys;
this.size = keys.length;
}
__iterate(handle, reverse) {
var object = this.__object;
var keys = this.__keys;
var maxIndex = keys.length - 1;
for(var n = 0; n <= maxIndex; n++) {
let key = keys[reverse ? maxIndex - n: n];
if(handle(object[key], key, this) === false) {
return n + 1;
}
}
return n;
}
static of(object) {
return new ObjectSequence(object);
}
toObjectSequence() {
return this;
}
has(key) {
return this._object.hasOwnProperty(key);
}
keys() {
return this.__keys;
}
values() {
var results = [];
this.keys().map(val => results.push(val));
return results;
}
}
export var SET_SEQUENCE_TYPEDEF = '[ArraySequence SetSequence]';
export class SetSequence extends ArraySequence {
constructor(value) {
if(nullOrUndefined(value)) {
/* If no value is given, return an empty sequence */
return emptySequence().toSetSequence();
} else if(!isIterable(value)) {
/* If not is iterable, return a index sequence */
return indexedSequenceFromData(value).toSetSequence();
} else if(isKeyed(value)) {
/* If has keys, get the raw sequence */
return value.entrySequence().toSetSequence();
} else {
return emptySequence(value);
}
throw new Error(
'Couldn\'t create a set-sequence of: ' + value
);
}
toSetSequence() {
return this;
}
}
ObjectSequence.prototype[IS_ORDERED_FLAG] = true;
var EMPTY_SEQUENCE;
function emptySequence() {
return EMPTY_SEQUENCE || (EMPTY_SEQUENCE = new ArraySequence([]));
}
function maybeIndexedSequenceFromData(value) {
return(
isArrayLike(value) ? new ArraySequence(value) :
isIterable(value) ? new IndexedSequence(value) :
undefined
);
}
function keyedSequenceFromData(value) {
var seq = Array.isArray(value) ? new ArraySequence(value) :
typeof value === 'object' ? new ObjectSequence(value) :
undefined;
if(!seq) {
throw new TypeError(
'Expected Array or iterable obejct of [k, v] entries, ' +
'or keyed object: ' + value
);
}
return seq;
}
function indexedSequenceFromData(value) {
var seq = maybeIndexedSequenceFromData(value);
if(!seq) {
throw new TypeError(
'Expected Array-like or iterable object of values: ' + value
);
}
return seq;
}
function sequenceFromValue(value) {
var seq = (typeof value === 'object' && new ObjectSequence(value)) ||
maybeIndexedSequenceFromData(value);
if(!seq) {
throw new TypeError(
'Expected Array or iterable object of values, ' +
'or keyed objects: ' + value
);
}
return seq;
}
defineTypeOf({
Sequence: SEQUENCE_TYPEDEF,
ArraySequence: ARRAY_SEQUENCE_TYPEDEF,
IndexedSequence: INDEXED_SEQUENCE_TYPEDEF,
KeyedSequence: KEYED_SEQUENCE_TYPEDEF,
ObjectSequence: OBJECT_SEQUENCE_TYPEDEF,
SetSequence: SET_SEQUENCE_TYPEDEF
});
Sequence.Object = ObjectSequence;
Sequence.Indexed = IndexedSequence;
Sequence.Keyed = KeyedSequence;
Sequence.Array = ArraySequence;
Sequence.Set = SetSequence;
Sequence.isSequence = isSequence;
Sequence.prototype[IS_SEQUENCE_FLAG] = true;