| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576 | /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */"use strict";module.metadata = {  "stability": "experimental"};// Disclamer:// In this module we'll have some common argument / variable names// to hint their type or behavior.//// - `f` stands for "function" that is intended to be side effect//   free.// - `p` stands for "predicate" that is function which returns logical//   true or false and is intended to be side effect free.// - `x` / `y` single item of the sequence.// - `xs` / `ys` sequence of `x` / `y` items where `x` / `y` signifies//    type of the items in sequence, so sequence is not of the same item.// - `_` used for argument(s) or variable(s) who's values are ignored.const { complement, flip, identity } = require("../lang/functional");const { iteratorSymbol } = require("../util/iteration");const { isArray, isArguments, isMap, isSet,        isString, isBoolean, isNumber } = require("../lang/type");const Sequence = function Sequence(iterator) {  if (iterator.isGenerator && iterator.isGenerator())    this[iteratorSymbol] = iterator;  else    throw TypeError("Expected generator argument");};exports.Sequence = Sequence;const polymorphic = dispatch => x =>  x === null ? dispatch.null(null) :  x === void(0) ? dispatch.void(void(0)) :  isArray(x) ? (dispatch.array || dispatch.indexed)(x) :  isString(x) ? (dispatch.string || dispatch.indexed)(x) :  isArguments(x) ? (dispatch.arguments || dispatch.indexed)(x) :  isMap(x) ? dispatch.map(x) :  isSet(x) ? dispatch.set(x) :  isNumber(x) ? dispatch.number(x) :  isBoolean(x) ? dispatch.boolean(x) :  dispatch.default(x);const nogen = function*() {};const empty = () => new Sequence(nogen);exports.empty = empty;const seq = polymorphic({  null: empty,  void: empty,  array: identity,  string: identity,  arguments: identity,  map: identity,  set: identity,  default: x => x instanceof Sequence ? x : new Sequence(x)});exports.seq = seq;// Function to cast seq to string.const string = (...etc) => "".concat(...etc);exports.string = string;// Function for casting seq to plain object.const object = (...pairs) => {  let result = {};  for (let [key, value] of pairs)    result[key] = value;  return result;};exports.object = object;// Takes `getEnumerator` function that returns `nsISimpleEnumerator`// and creates lazy sequence of it's items. Note that function does// not take `nsISimpleEnumerator` itslef because that would allow// single iteration, which would not be consistent with rest of the// lazy sequences.const fromEnumerator = getEnumerator => seq(function* () {  const enumerator = getEnumerator();  while (enumerator.hasMoreElements())   yield enumerator.getNext();});exports.fromEnumerator = fromEnumerator;// Takes `object` and returns lazy sequence of own `[key, value]`// pairs (does not include inherited and non enumerable keys).const pairs = polymorphic({  null: empty,  void: empty,  map: identity,  indexed: indexed => seq(function* () {    const count = indexed.length;    let index = 0;    while (index < count) {      yield [index, indexed[index]];      index = index + 1;    }  }),  default: object => seq(function* () {    for (let key of Object.keys(object))      yield [key, object[key]];  })});exports.pairs = pairs;const keys = polymorphic({  null: empty,  void: empty,  indexed: indexed => seq(function* () {    const count = indexed.length;    let index = 0;    while (index < count) {      yield index;      index = index + 1;    }  }),  map: map => seq(function* () {    for (let [key, _] of map)      yield key;  }),  default: object => seq(function* () {    for (let key of Object.keys(object))      yield key;  })});exports.keys = keys;const values = polymorphic({  null: empty,  void: empty,  set: identity,  indexed: indexed => seq(function* () {    const count = indexed.length;    let index = 0;    while (index < count) {      yield indexed[index];      index = index + 1;    }  }),  map: map => seq(function* () {    for (let [_, value] of map) yield value;  }),  default: object => seq(function* () {    for (let key of Object.keys(object)) yield object[key];  })});exports.values = values;// Returns a lazy sequence of `x`, `f(x)`, `f(f(x))` etc.// `f` must be free of side-effects. Note that returned// sequence is infinite so it must be consumed partially.//// Implements clojure iterate:// http://clojuredocs.org/clojure_core/clojure.core/iterateconst iterate = (f, x) => seq(function* () {  let state = x;  while (true) {    yield state;    state = f(state);  }});exports.iterate = iterate;// Returns a lazy sequence of the items in sequence for which `p(item)`// returns `true`. `p` must be free of side-effects.//// Implements clojure filter:// http://clojuredocs.org/clojure_core/clojure.core/filterconst filter = (p, sequence) => seq(function* () {  if (sequence !== null && sequence !== void(0)) {    for (let item of sequence) {      if (p(item))        yield item;    }  }});exports.filter = filter;// Returns a lazy sequence consisting of the result of applying `f` to the// set of first items of each sequence, followed by applying f to the set// of second items in each sequence, until any one of the sequences is// exhausted. Any remaining items in other sequences are ignored. Function// `f` should accept number-of-sequences arguments.//// Implements clojure map:// http://clojuredocs.org/clojure_core/clojure.core/mapconst map = (f, ...sequences) => seq(function* () {  const count = sequences.length;  // Optimize a single sequence case  if (count === 1) {    let [sequence] = sequences;    if (sequence !== null && sequence !== void(0)) {      for (let item of sequence)        yield f(item);    }  }  else {    // define args array that will be recycled on each    // step to aggregate arguments to be passed to `f`.    let args = [];    // define inputs to contain started generators.    let inputs = [];    let index = 0;    while (index < count) {      inputs[index] = sequences[index][iteratorSymbol]();      index = index + 1;    }    // Run loop yielding of applying `f` to the set of    // items at each step until one of the `inputs` is    // exhausted.    let done = false;    while (!done) {      let index = 0;      let value = void(0);      while (index < count && !done) {        ({ done, value }) = inputs[index].next();        // If input is not exhausted yet store value in args.        if (!done) {          args[index] = value;          index = index + 1;        }      }      // If none of the inputs is exhasted yet, `args` contain items      // from each input so we yield application of `f` over them.      if (!done)        yield f(...args);    }  }});exports.map = map;// Returns a lazy sequence of the intermediate values of the reduction (as// per reduce) of sequence by `f`, starting with `initial` value if provided.//// Implements clojure reductions:// http://clojuredocs.org/clojure_core/clojure.core/reductionsconst reductions = (...params) => {  const count = params.length;  let hasInitial = false;  let f, initial, source;  if (count === 2) {    ([f, source]) = params;  }  else if (count === 3) {    ([f, initial, source]) = params;    hasInitial = true;  }  else {    throw Error("Invoked with wrong number of arguments: " + count);  }  const sequence = seq(source);  return seq(function* () {    let started = hasInitial;    let result = void(0);    // If initial is present yield it.    if (hasInitial)      yield (result = initial);    // For each item of the sequence accumulate new result.    for (let item of sequence) {      // If nothing has being yield yet set result to first      // item and yield it.      if (!started) {        started = true;        yield (result = item);      }      // Otherwise accumulate new result and yield it.      else {        yield (result = f(result, item));      }    }    // If nothing has being yield yet it's empty sequence and no    // `initial` was provided in which case we need to yield `f()`.    if (!started)      yield f();  });};exports.reductions = reductions;// `f` should be a function of 2 arguments. If `initial` is not supplied,// returns the result of applying `f` to the first 2 items in sequence, then// applying `f` to that result and the 3rd item, etc. If sequence contains no// items, `f` must accept no arguments as well, and reduce returns the// result of calling f with no arguments. If sequence has only 1 item, it// is returned and `f` is not called. If `initial` is supplied, returns the// result of applying `f` to `initial` and the first item in  sequence, then// applying `f` to that result and the 2nd item, etc. If sequence contains no// items, returns `initial` and `f` is not called.//// Implements clojure reduce:// http://clojuredocs.org/clojure_core/clojure.core/reduceconst reduce = (...args) => {  const xs = reductions(...args);  let x;  for (x of xs) void(0);  return x;};exports.reduce = reduce;const each = (f, sequence) => {  for (let x of seq(sequence)) void(f(x));};exports.each = each;const inc = x => x + 1;// Returns the number of items in the sequence. `count(null)` && `count()`// returns `0`. Also works on strings, arrays, Maps & Sets.// Implements clojure count:// http://clojuredocs.org/clojure_core/clojure.core/countconst count = polymorphic({  null: _ => 0,  void: _ => 0,  indexed: indexed => indexed.length,  map: map => map.size,  set: set => set.size,  default: xs => reduce(inc, 0, xs)});exports.count = count;// Returns `true` if sequence has no items.// Implements clojure empty?:// http://clojuredocs.org/clojure_core/clojure.core/empty_qconst isEmpty = sequence => {  // Treat `null` and `undefined` as empty sequences.  if (sequence === null || sequence === void(0))    return true;  // If contains any item non empty so return `false`.  for (let _ of sequence)    return false;  // If has not returned yet, there was nothing to iterate  // so it's empty.  return true;};exports.isEmpty = isEmpty;const and = (a, b) => a && b;// Returns true if `p(x)` is logical `true` for every `x` in sequence, else// `false`.//// Implements clojure every?:// http://clojuredocs.org/clojure_core/clojure.core/every_qconst isEvery = (p, sequence) => {  if (sequence !== null && sequence !== void(0)) {    for (let item of sequence) {      if (!p(item))        return false;    }  }  return true;};exports.isEvery = isEvery;// Returns the first logical true value of (p x) for any x in sequence,// else `null`.//// Implements clojure some:// http://clojuredocs.org/clojure_core/clojure.core/someconst some = (p, sequence) => {  if (sequence !== null && sequence !== void(0)) {    for (let item of sequence) {      if (p(item))        return true;    }  }  return null;};exports.some = some;// Returns a lazy sequence of the first `n` items in sequence, or all items if// there are fewer than `n`.//// Implements clojure take:// http://clojuredocs.org/clojure_core/clojure.core/takeconst take = (n, sequence) => n <= 0 ? empty() : seq(function* () {  let count = n;  for (let item of sequence) {    yield item;    count = count - 1;    if (count === 0) break;  }});exports.take = take;// Returns a lazy sequence of successive items from sequence while// `p(item)` returns `true`. `p` must be free of side-effects.//// Implements clojure take-while:// http://clojuredocs.org/clojure_core/clojure.core/take-whileconst takeWhile = (p, sequence) => seq(function* () {  for (let item of sequence) {    if (!p(item))      break;    yield item;  }});exports.takeWhile = takeWhile;// Returns a lazy sequence of all but the first `n` items in// sequence.//// Implements clojure drop:// http://clojuredocs.org/clojure_core/clojure.core/dropconst drop = (n, sequence) => seq(function* () {  if (sequence !== null && sequence !== void(0)) {    let count = n;    for (let item of sequence) {      if (count > 0)        count = count - 1;      else        yield item;    }  }});exports.drop = drop;// Returns a lazy sequence of the items in sequence starting from the// first item for which `p(item)` returns falsy value.//// Implements clojure drop-while:// http://clojuredocs.org/clojure_core/clojure.core/drop-whileconst dropWhile = (p, sequence) => seq(function* () {  let keep = false;  for (let item of sequence) {    keep = keep || !p(item);    if (keep) yield item;  }});exports.dropWhile = dropWhile;// Returns a lazy sequence representing the concatenation of the// suplied sequences.//// Implements clojure conact:// http://clojuredocs.org/clojure_core/clojure.core/concatconst concat = (...sequences) => seq(function* () {  for (let sequence of sequences)    for (let item of sequence)      yield item;});exports.concat = concat;// Returns the first item in the sequence.//// Implements clojure first:// http://clojuredocs.org/clojure_core/clojure.core/firstconst first = sequence => {  if (sequence !== null && sequence !== void(0)) {    for (let item of sequence)      return item;  }  return null;};exports.first = first;// Returns a possibly empty sequence of the items after the first.//// Implements clojure rest:// http://clojuredocs.org/clojure_core/clojure.core/restconst rest = sequence => drop(1, sequence);exports.rest = rest;// Returns the value at the index. Returns `notFound` or `undefined`// if index is out of bounds.const nth = (xs, n, notFound) => {  if (n >= 0) {    if (isArray(xs) || isArguments(xs) || isString(xs)) {      return n < xs.length ? xs[n] : notFound;    }    else if (xs !== null && xs !== void(0)) {      let count = n;      for (let x of xs) {        if (count <= 0)          return x;        count = count - 1;      }    }  }  return notFound;};exports.nth = nth;// Return the last item in sequence, in linear time.// If `sequence` is an array or string or arguments// returns in constant time.// Implements clojure last:// http://clojuredocs.org/clojure_core/clojure.core/lastconst last = polymorphic({  null: _ => null,  void: _ => null,  indexed: indexed => indexed[indexed.length - 1],  map: xs => reduce((_, x) => x, xs),  set: xs => reduce((_, x) => x, xs),  default: xs => reduce((_, x) => x, xs)});exports.last = last;// Return a lazy sequence of all but the last `n` (default 1) items// from the give `xs`.//// Implements clojure drop-last:// http://clojuredocs.org/clojure_core/clojure.core/drop-lastconst dropLast = flip((xs, n=1) => seq(function* () {  let ys = [];  for (let x of xs) {    ys.push(x);    if (ys.length > n)      yield ys.shift();  }}));exports.dropLast = dropLast;// Returns a lazy sequence of the elements of `xs` with duplicates// removed//// Implements clojure distinct// http://clojuredocs.org/clojure_core/clojure.core/distinctconst distinct = sequence => seq(function* () {  let items = new Set();  for (let item of sequence) {    if (!items.has(item)) {      items.add(item);      yield item;    }  }});exports.distinct = distinct;// Returns a lazy sequence of the items in `xs` for which// `p(x)` returns false. `p` must be free of side-effects.//// Implements clojure remove// http://clojuredocs.org/clojure_core/clojure.core/removeconst remove = (p, xs) => filter(complement(p), xs);exports.remove = remove;// Returns the result of applying concat to the result of// `map(f, xs)`. Thus function `f` should return a sequence.//// Implements clojure mapcat// http://clojuredocs.org/clojure_core/clojure.core/mapcatconst mapcat = (f, sequence) => seq(function* () {  const sequences = map(f, sequence);  for (let sequence of sequences)    for (let item of sequence)      yield item;});exports.mapcat = mapcat;
 |