UNPKG

scontainers

Version:

A container/collection/iterator library for JavaScript, comfortable to use, performant and versatile.

159 lines (117 loc) 4.25 kB
"use strict"; function _implSymbol(target, sym, value) { Object.defineProperty(target, sym, { value, configurable: true }); return target[sym]; } function _getSymbol(targetSymName, ...traitSets) { let symbol; traitSets.forEach(traitSet => { const sym = traitSet[targetSymName]; if (typeof sym === 'symbol') { if (!!symbol && symbol !== sym) { throw new Error(`Symbol ${targetSymName} offered by multiple trait sets.`); } symbol = sym; } }); if (!symbol) { throw new Error(`No trait set is providing symbol ${targetSymName}.`); } return symbol; } function _testTraitSet(traitSet) { if (!traitSet || typeof traitSet === 'boolean' || typeof traitSet === 'number' || typeof traitSet === 'string') { throw new Error(`${traitSet} cannot be used as a trait set.`); } } const { traits, id } = require('../utils.js'); _testTraitSet(traits.utils); _testTraitSet(traits.scontainers); _testTraitSet(traits.semantics); const _describeScontainer = _getSymbol("describeScontainer", traits.utils, traits.scontainers, traits.semantics); const _implCoreTraits = _getSymbol("implCoreTraits", traits.utils, traits.scontainers, traits.semantics); const _map = _getSymbol("map", traits.utils, traits.scontainers, traits.semantics); const _count = _getSymbol("count", traits.utils, traits.scontainers, traits.semantics); const _sum = _getSymbol("sum", traits.utils, traits.scontainers, traits.semantics); const _kvIterator = _getSymbol("kvIterator", traits.utils, traits.scontainers, traits.semantics); const _reverse = _getSymbol("reverse", traits.utils, traits.scontainers, traits.semantics); const _flatten = _getSymbol("flatten", traits.utils, traits.scontainers, traits.semantics); module.exports = function (ParentCollection) { return function () { const parentProto = ParentCollection.prototype; class Flatten { static get name() { return `${ParentCollection.name}::Flatten`; } constructor(coll) { this.wrapped = coll; } toString() { return `${this.wrapped}.flatten()`; } } Flatten[_describeScontainer]({ InnerCollection: ParentCollection, innerCollectionKey: id`wrapped`, argKeys: [] }); Flatten[_implCoreTraits]({ count() { // NOTE: might throw if one of the elements of the collections of `this.wrapped` isn't countable if (parentProto[_map]) { return function count() { return this.wrapped[_map](value => value[_count] ? value[_count]() : 1)[_sum](); }; } }, kvIterator() { return function kvIterator() { // NOTE: might throw if one of the elements of the collections of `this.wrapped` isn't iterable return { it: this.wrapped[_kvIterator](), // iterator on `this.wrapped` jt: null, // iterator on latest returned element of `this.wrapped` next() { for (;;) { if (this.jt) { const j = this.jt.next(); if (j) { // found next element inside `jt` return j; } // reached the end of current `jt` this.jt = null; } const i = this.it.next(); if (!i) { // reached the end of `i` return; } // found `i`: next element inside `it` if (i.value && i.value[_kvIterator]) { this.jt = i.value[_kvIterator](); // `i` is iterable: iterating inside it continue; } // `i` was not iterable: just returning it return i; } } }; }; }, reverse() { // NOTE: might throw if one of the elements of the collections of `this.wrapped` isn't reversable if (parentProto[_reverse]) { return function reverse() { return this.wrapped[_reverse]()[_map](value => value[_kvIterator] ? value[_reverse]() : value)[_flatten](); }; } } }); return Flatten; }; };