mirror of
https://github.com/flynx/types.js.git
synced 2025-12-19 09:51:40 +00:00
major refactoring, should not affect functionality but may have minor bugs...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
parent
15e47ddfa7
commit
98e5346450
594
Array.js
594
Array.js
@ -35,194 +35,7 @@ module.StopIteration =
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
// Array.prototype.flat polyfill...
|
||||
//
|
||||
// NOTE: .flat(..) is not yet supported in IE/Edge...
|
||||
Array.prototype.flat
|
||||
|| (Array.prototype.flat = function(depth){
|
||||
depth = typeof(depth) == typeof(123) ? depth : 1
|
||||
return this.reduce(function(res, e){
|
||||
return res.concat(e instanceof Array && depth > 0 ?
|
||||
e.flat(depth-1)
|
||||
: [e]) }, []) })
|
||||
|
||||
|
||||
// Array.prototype.includes polyfill...
|
||||
//
|
||||
Array.prototype.includes
|
||||
|| (Array.prototype.includes = function(value){
|
||||
return this.indexOf(value) >= 0 })
|
||||
|
||||
|
||||
// first/last element access short-hands...
|
||||
//
|
||||
// .first()
|
||||
// .last()
|
||||
// -> elem
|
||||
//
|
||||
// .first(value)
|
||||
// .last(value)
|
||||
// -> array
|
||||
//
|
||||
// NOTE: setting a value will overwrite an existing first/last value.
|
||||
// NOTE: for an empty array both .first(..)/.last(..) will return undefined
|
||||
// when getting a value and set the 0'th value when setting...
|
||||
// NOTE: decided to keep these as methods and not props because methods
|
||||
// have one advantage: they can be chained
|
||||
// ...while you can't chain assignment unless you wrap it in .run(..)
|
||||
Array.prototype.first
|
||||
|| (Array.prototype.first = function(value){
|
||||
return arguments.length > 0 ?
|
||||
((this[0] = value), this)
|
||||
: this[0]})
|
||||
Array.prototype.last
|
||||
|| (Array.prototype.last = function(value){
|
||||
return arguments.length > 0 ?
|
||||
((this[this.length - 1 || 0] = value), this)
|
||||
: this[this.length - 1]})
|
||||
|
||||
|
||||
// Roll left/right (in-place)...
|
||||
//
|
||||
// NOTE: to .rol(..) left just pass a negative n value...
|
||||
// NOTE: we can't use ...[..] for sparse arrays as the will expand undefined
|
||||
// inplace of empty positions, this is thereason the .splice(..)
|
||||
// implementation was replaced by a less clear (but faster)
|
||||
// .copyWithin(..) version...
|
||||
Array.prototype.rol
|
||||
|| (Array.prototype.rol = function(n=1){
|
||||
var l = this.length
|
||||
n = (n >= 0 ?
|
||||
n
|
||||
: l - n)
|
||||
% l
|
||||
if(n != 0){
|
||||
this.length += n
|
||||
this.copyWithin(l, 0, n)
|
||||
this.splice(0, n) }
|
||||
return this })
|
||||
|
||||
|
||||
// Compact a sparse array...
|
||||
//
|
||||
// NOTE: this will not compact in-place.
|
||||
Array.prototype.compact = function(){
|
||||
return this.filter(function(){ return true }) }
|
||||
|
||||
|
||||
// like .length but for sparse arrays will return the element count...
|
||||
//
|
||||
'len' in Array.prototype
|
||||
|| Object.defineProperty(Array.prototype, 'len', {
|
||||
get : function () {
|
||||
// NOTE: if we don't do .slice() here this can count array
|
||||
// instance attributes...
|
||||
return Object.keys(this.slice()).length },
|
||||
set : function(val){},
|
||||
})
|
||||
|
||||
|
||||
// Return a new array with duplicate elements removed...
|
||||
//
|
||||
// NOTE: order is preserved...
|
||||
Array.prototype.unique = function(normalize){
|
||||
return normalize ?
|
||||
[...new Map(this.map(function(e){ return [normalize(e), e] })).values()]
|
||||
// NOTE: we are calling .compact() here to avoid creating undefined
|
||||
// items from empty slots in sparse arrays...
|
||||
: [...new Set(this.compact())] }
|
||||
Array.prototype.tailUnique = function(normalize){
|
||||
return this
|
||||
.slice()
|
||||
.reverse()
|
||||
.unique(normalize)
|
||||
.reverse() }
|
||||
|
||||
|
||||
// Compare two arrays...
|
||||
//
|
||||
// NOTE: this is diffectent from Object.match(..) in that this compares
|
||||
// self to other (internal) while match compares two entities
|
||||
// externally.
|
||||
// XXX not sure if we need the destinction in name, will have to
|
||||
// come back to this when refactoring diff.js -- all three have
|
||||
// to be similar...
|
||||
Array.prototype.cmp = function(other){
|
||||
if(this === other){
|
||||
return true }
|
||||
if(this.length != other.length){
|
||||
return false }
|
||||
for(var i=0; i<this.length; i++){
|
||||
if(this[i] != other[i]){
|
||||
return false } }
|
||||
return true }
|
||||
|
||||
|
||||
// Compare two Arrays as sets...
|
||||
//
|
||||
// NOTE: this will ignore order and repeating elments...
|
||||
Array.prototype.setCmp = function(other){
|
||||
return this === other
|
||||
|| (new Set([...this, ...other])).length == (new Set(this)).length }
|
||||
|
||||
|
||||
// Sort as the other array...
|
||||
//
|
||||
// Sort as array placing the sorted items at head...
|
||||
// .sortAs(array)
|
||||
// .sortAs(array, 'head')
|
||||
// -> sorted
|
||||
//
|
||||
// Sort as array placing the sorted items at tail...
|
||||
// .sortAs(array, 'tail')
|
||||
// -> sorted
|
||||
//
|
||||
// This will sort the intersecting items in the head keeping the rest
|
||||
// of the items in the same relative order...
|
||||
//
|
||||
// NOTE: if an item is in the array multiple times only the first index
|
||||
// is used...
|
||||
//
|
||||
// XXX should this extend/patch .sort(..)???
|
||||
// ...currently do not see a clean way to do this without extending
|
||||
// and replacing Array or directly re-wrapping .sort(..)...
|
||||
Array.prototype.sortAs = function(other, place='head'){
|
||||
place = place == 'tail' ? -1 : 1
|
||||
// NOTE: the memory overhead here is better than the time overhead
|
||||
// when using .indexOf(..)...
|
||||
other = other.toMap()
|
||||
var orig = this.toMap()
|
||||
return this.sort(function(a, b){
|
||||
var i = other.get(a)
|
||||
var j = other.get(b)
|
||||
return i == null && j == null ?
|
||||
orig.get(a) - orig.get(b)
|
||||
: i == null ?
|
||||
place
|
||||
: j == null ?
|
||||
-place
|
||||
: i - j }) }
|
||||
|
||||
|
||||
// Same as .sortAs(..) but will not change indexes of items not in other...
|
||||
//
|
||||
// Example:
|
||||
// ['a', 3, 'b', 1, 2, 'c']
|
||||
// .inplaceSortAs([1, 2, 3, 3]) // -> ['a', 1, 'b', 2, 3, 'c']
|
||||
//
|
||||
Array.prototype.inplaceSortAs = function(other){
|
||||
// sort only the intersection...
|
||||
var sorted = this
|
||||
.filter(function(e){
|
||||
return other.includes(e) })
|
||||
.sortAs(other)
|
||||
// "zip" the sorted items back into this...
|
||||
this.forEach(function(e, i, l){
|
||||
other.includes(e)
|
||||
&& (l[i] = sorted.shift()) })
|
||||
return this }
|
||||
|
||||
// Mixins...
|
||||
|
||||
// Equivalent to .map(..) / .filter(..) / .reduce(..) / .. with support for
|
||||
// StopIteration...
|
||||
@ -241,10 +54,6 @@ var wrapIterFunc = function(iter){
|
||||
} else if( err instanceof StopIteration){
|
||||
return err.msg }
|
||||
throw err } } }
|
||||
Array.prototype.smap = wrapIterFunc('map')
|
||||
Array.prototype.sfilter = wrapIterFunc('filter')
|
||||
Array.prototype.sreduce = wrapIterFunc('reduce')
|
||||
Array.prototype.sforEach = wrapIterFunc('forEach')
|
||||
|
||||
|
||||
// Equivalent to .map(..) / .filter(..) / .reduce(..) that process the
|
||||
@ -372,131 +181,304 @@ var makeChunkIter = function(iter, wrapper){
|
||||
: c.push([i, e])
|
||||
return res }, [[]])) }) } }
|
||||
|
||||
Array.prototype.CHUNK_SIZE = 50
|
||||
Array.prototype.mapChunks = makeChunkIter('map')
|
||||
Array.prototype.filterChunks = makeChunkIter('map',
|
||||
function(res, func, array, e){
|
||||
return !!func.call(this, e[1], e[0], array) ? [e[1]] : [] })
|
||||
Array.prototype.reduceChunks = makeChunkIter('reduce',
|
||||
function(total, func, array, res, e){
|
||||
return func.call(this,
|
||||
total.length > 0 ?
|
||||
total.pop()
|
||||
: res,
|
||||
e[1], e[0], array) })
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
var ArrayMixin =
|
||||
module.ArrayMixin =
|
||||
object.Mixin('ArrayMixin', 'soft', {
|
||||
// zip(array, array, ...)
|
||||
// -> [[item, item, ...], ...]
|
||||
//
|
||||
// zip(func, array, array, ...)
|
||||
// -> [func(i, [item, item, ...]), ...]
|
||||
//
|
||||
zip: function(func, ...arrays){
|
||||
var i = arrays[0] instanceof Array ?
|
||||
0
|
||||
: arrays.shift()
|
||||
if(func instanceof Array){
|
||||
arrays.splice(0, 0, func)
|
||||
func = null }
|
||||
// build the zip item...
|
||||
// NOTE: this is done this way to preserve array sparseness...
|
||||
var s = arrays
|
||||
.reduce(
|
||||
function(res, a, j){
|
||||
//a.length > i
|
||||
i in a
|
||||
&& (res[j] = a[i])
|
||||
return res },
|
||||
new Array(arrays.length))
|
||||
return arrays
|
||||
// check that at least one array is longer than i...
|
||||
.reduce(function(res, a){
|
||||
return Math.max(res, i, a.length) }, 0) > i ?
|
||||
// collect zip item...
|
||||
[func ? func(i, s) : s]
|
||||
// get next...
|
||||
.concat(this.zip(func, i+1, ...arrays))
|
||||
// done...
|
||||
: [] },
|
||||
|
||||
iter: function*(lst=[]){
|
||||
yield* lst.iter() },
|
||||
})
|
||||
|
||||
|
||||
// Convert an array to object...
|
||||
//
|
||||
// Format:
|
||||
// {
|
||||
// <item>: <index>,
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
// NOTE: items should be strings, other types will get converted to
|
||||
// strings and thus may mess things up.
|
||||
// NOTE: this will forget repeating items...
|
||||
// NOTE: normalize will slow things down...
|
||||
Array.prototype.toKeys = function(normalize){
|
||||
return normalize ?
|
||||
this.reduce(function(r, e, i){
|
||||
r[normalize(e)] = i
|
||||
return r }, {})
|
||||
: this.reduce(function(r, e, i){
|
||||
r[e] = i
|
||||
return r }, {}) }
|
||||
var ArrayProtoMixin =
|
||||
module.ArrayProtoMixin =
|
||||
object.Mixin('ArrayProtoMixin', 'soft', {
|
||||
// first/last element access short-hands...
|
||||
//
|
||||
// .first()
|
||||
// .last()
|
||||
// -> elem
|
||||
//
|
||||
// .first(value)
|
||||
// .last(value)
|
||||
// -> array
|
||||
//
|
||||
// NOTE: setting a value will overwrite an existing first/last value.
|
||||
// NOTE: for an empty array both .first(..)/.last(..) will return undefined
|
||||
// when getting a value and set the 0'th value when setting...
|
||||
// NOTE: decided to keep these as methods and not props because methods
|
||||
// have one advantage: they can be chained
|
||||
// ...while you can't chain assignment unless you wrap it in .run(..)
|
||||
first: function(value){
|
||||
return arguments.length > 0 ?
|
||||
((this[0] = value), this)
|
||||
: this[0]},
|
||||
last: function(value){
|
||||
return arguments.length > 0 ?
|
||||
((this[this.length - 1 || 0] = value), this)
|
||||
: this[this.length - 1]},
|
||||
|
||||
// Roll left/right (in-place)...
|
||||
//
|
||||
// NOTE: to .rol(..) left just pass a negative n value...
|
||||
// NOTE: we can't use ...[..] for sparse arrays as the will expand undefined
|
||||
// inplace of empty positions, this is thereason the .splice(..)
|
||||
// implementation was replaced by a less clear (but faster)
|
||||
// .copyWithin(..) version...
|
||||
rol: function(n=1){
|
||||
var l = this.length
|
||||
n = (n >= 0 ?
|
||||
n
|
||||
: l - n)
|
||||
% l
|
||||
if(n != 0){
|
||||
this.length += n
|
||||
this.copyWithin(l, 0, n)
|
||||
this.splice(0, n) }
|
||||
return this },
|
||||
|
||||
// Compact a sparse array...
|
||||
//
|
||||
// NOTE: this will not compact in-place.
|
||||
compact: function(){
|
||||
return this
|
||||
.filter(function(){ return true }) },
|
||||
|
||||
// like .length but for sparse arrays will return the element count...
|
||||
get len(){
|
||||
// NOTE: if we don't do .slice() here this can count array
|
||||
// instance attributes...
|
||||
return Object.keys(this.slice()).length },
|
||||
set len(val){},
|
||||
|
||||
|
||||
// Convert an array to a map...
|
||||
//
|
||||
// This is similar to Array.prototype.toKeys(..) but does not restrict
|
||||
// value type to string.
|
||||
//
|
||||
// Format:
|
||||
// Map([
|
||||
// [<item>, <index>],
|
||||
// ...
|
||||
// ])
|
||||
//
|
||||
// NOTE: this will forget repeating items...
|
||||
// NOTE: normalize will slow things down...
|
||||
Array.prototype.toMap = function(normalize){
|
||||
return normalize ?
|
||||
this
|
||||
.reduce(function(m, e, i){
|
||||
m.set(normalize(e), i)
|
||||
return m }, new Map())
|
||||
: this
|
||||
.reduce(function(m, e, i){
|
||||
m.set(e, i)
|
||||
return m }, new Map()) }
|
||||
// Return a new array with duplicate elements removed...
|
||||
//
|
||||
// NOTE: order is preserved...
|
||||
unique: function(normalize){
|
||||
return normalize ?
|
||||
[...new Map(this.map(function(e){ return [normalize(e), e] })).values()]
|
||||
// NOTE: we are calling .compact() here to avoid creating undefined
|
||||
// items from empty slots in sparse arrays...
|
||||
: [...new Set(this.compact())] },
|
||||
tailUnique: function(normalize){
|
||||
return this
|
||||
.slice()
|
||||
.reverse()
|
||||
.unique(normalize)
|
||||
.reverse() },
|
||||
|
||||
// Compare two arrays...
|
||||
//
|
||||
// NOTE: this is diffectent from Object.match(..) in that this compares
|
||||
// self to other (internal) while match compares two entities
|
||||
// externally.
|
||||
// XXX not sure if we need the destinction in name, will have to
|
||||
// come back to this when refactoring diff.js -- all three have
|
||||
// to be similar...
|
||||
cmp: function(other){
|
||||
if(this === other){
|
||||
return true }
|
||||
if(this.length != other.length){
|
||||
return false }
|
||||
for(var i=0; i<this.length; i++){
|
||||
if(this[i] != other[i]){
|
||||
return false } }
|
||||
return true },
|
||||
|
||||
// zip(array, array, ...)
|
||||
// -> [[item, item, ...], ...]
|
||||
//
|
||||
// zip(func, array, array, ...)
|
||||
// -> [func(i, [item, item, ...]), ...]
|
||||
//
|
||||
Array.zip =
|
||||
function(func, ...arrays){
|
||||
var i = arrays[0] instanceof Array ?
|
||||
0
|
||||
: arrays.shift()
|
||||
if(func instanceof Array){
|
||||
arrays.splice(0, 0, func)
|
||||
func = null }
|
||||
// build the zip item...
|
||||
// NOTE: this is done this way to preserve array sparseness...
|
||||
var s = arrays
|
||||
.reduce(
|
||||
function(res, a, j){
|
||||
//a.length > i
|
||||
i in a
|
||||
&& (res[j] = a[i])
|
||||
return res },
|
||||
new Array(arrays.length))
|
||||
return arrays
|
||||
// check that at least one array is longer than i...
|
||||
.reduce(function(res, a){
|
||||
return Math.max(res, i, a.length) }, 0) > i ?
|
||||
// collect zip item...
|
||||
[func ? func(i, s) : s]
|
||||
// get next...
|
||||
.concat(this.zip(func, i+1, ...arrays))
|
||||
// done...
|
||||
: [] }
|
||||
// XXX would be nice for this to use the instance .zip(..) in recursion...
|
||||
// ...this might be done by reversign the current implementation, i.e.
|
||||
// for instance .zip(..) to be the main implementation and for
|
||||
// Array.zip(..) to be a proxy to that...
|
||||
Array.prototype.zip =
|
||||
function(func, ...arrays){
|
||||
return func instanceof Array ?
|
||||
this.constructor.zip(this, func, ...arrays)
|
||||
: this.constructor.zip(func, this, ...arrays) }
|
||||
// Compare two Arrays as sets...
|
||||
//
|
||||
// NOTE: this will ignore order and repeating elments...
|
||||
setCmp: function(other){
|
||||
return this === other
|
||||
|| (new Set([...this, ...other])).length == (new Set(this)).length },
|
||||
|
||||
// Sort as the other array...
|
||||
//
|
||||
// Sort as array placing the sorted items at head...
|
||||
// .sortAs(array)
|
||||
// .sortAs(array, 'head')
|
||||
// -> sorted
|
||||
//
|
||||
// Sort as array placing the sorted items at tail...
|
||||
// .sortAs(array, 'tail')
|
||||
// -> sorted
|
||||
//
|
||||
// This will sort the intersecting items in the head keeping the rest
|
||||
// of the items in the same relative order...
|
||||
//
|
||||
// NOTE: if an item is in the array multiple times only the first index
|
||||
// is used...
|
||||
//
|
||||
// XXX should this extend/patch .sort(..)???
|
||||
// ...currently do not see a clean way to do this without extending
|
||||
// and replacing Array or directly re-wrapping .sort(..)...
|
||||
sortAs: function(other, place='head'){
|
||||
place = place == 'tail' ? -1 : 1
|
||||
// NOTE: the memory overhead here is better than the time overhead
|
||||
// when using .indexOf(..)...
|
||||
other = other.toMap()
|
||||
var orig = this.toMap()
|
||||
return this.sort(function(a, b){
|
||||
var i = other.get(a)
|
||||
var j = other.get(b)
|
||||
return i == null && j == null ?
|
||||
orig.get(a) - orig.get(b)
|
||||
: i == null ?
|
||||
place
|
||||
: j == null ?
|
||||
-place
|
||||
: i - j }) },
|
||||
|
||||
//
|
||||
// Array.iter()
|
||||
// Array.iter([ .. ])
|
||||
// -> iterator
|
||||
//
|
||||
// array.iter()
|
||||
// -> iterator
|
||||
//
|
||||
//
|
||||
// XXX should this take an argument and be like map??
|
||||
Array.prototype.iter =
|
||||
function*(){
|
||||
// Same as .sortAs(..) but will not change indexes of items not in other...
|
||||
//
|
||||
// Example:
|
||||
// ['a', 3, 'b', 1, 2, 'c']
|
||||
// .inplaceSortAs([1, 2, 3, 3]) // -> ['a', 1, 'b', 2, 3, 'c']
|
||||
//
|
||||
inplaceSortAs: function(other){
|
||||
// sort only the intersection...
|
||||
var sorted = this
|
||||
.filter(function(e){
|
||||
return other.includes(e) })
|
||||
.sortAs(other)
|
||||
// "zip" the sorted items back into this...
|
||||
this.forEach(function(e, i, l){
|
||||
other.includes(e)
|
||||
&& (l[i] = sorted.shift()) })
|
||||
return this },
|
||||
|
||||
// Convert an array to object...
|
||||
//
|
||||
// Format:
|
||||
// {
|
||||
// <item>: <index>,
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
// NOTE: items should be strings, other types will get converted to
|
||||
// strings and thus may mess things up.
|
||||
// NOTE: this will forget repeating items...
|
||||
// NOTE: normalize will slow things down...
|
||||
toKeys: function(normalize){
|
||||
return normalize ?
|
||||
this.reduce(function(r, e, i){
|
||||
r[normalize(e)] = i
|
||||
return r }, {})
|
||||
: this.reduce(function(r, e, i){
|
||||
r[e] = i
|
||||
return r }, {}) },
|
||||
|
||||
// Convert an array to a map...
|
||||
//
|
||||
// This is similar to Array.prototype.toKeys(..) but does not restrict
|
||||
// value type to string.
|
||||
//
|
||||
// Format:
|
||||
// Map([
|
||||
// [<item>, <index>],
|
||||
// ...
|
||||
// ])
|
||||
//
|
||||
// NOTE: this will forget repeating items...
|
||||
// NOTE: normalize will slow things down...
|
||||
toMap: function(normalize){
|
||||
return normalize ?
|
||||
this
|
||||
.reduce(function(m, e, i){
|
||||
m.set(normalize(e), i)
|
||||
return m }, new Map())
|
||||
: this
|
||||
.reduce(function(m, e, i){
|
||||
m.set(e, i)
|
||||
return m }, new Map()) },
|
||||
|
||||
// XXX would be nice for this to use the instance .zip(..) in recursion...
|
||||
// ...this might be done by reversign the current implementation, i.e.
|
||||
// for instance .zip(..) to be the main implementation and for
|
||||
// Array.zip(..) to be a proxy to that...
|
||||
zip: function(func, ...arrays){
|
||||
return func instanceof Array ?
|
||||
this.constructor.zip(this, func, ...arrays)
|
||||
: this.constructor.zip(func, this, ...arrays) },
|
||||
|
||||
// get iterator over array...
|
||||
//
|
||||
// Array.iter()
|
||||
// Array.iter([ .. ])
|
||||
// -> iterator
|
||||
//
|
||||
// array.iter()
|
||||
// -> iterator
|
||||
//
|
||||
// XXX should this take an argument and be like map??
|
||||
iter: function*(){
|
||||
for(var e of this){
|
||||
yield e } }
|
||||
Array.iter =
|
||||
function*(lst=[]){
|
||||
yield* lst.iter() }
|
||||
yield e } },
|
||||
|
||||
|
||||
// Stoppable iteration...
|
||||
//
|
||||
smap: wrapIterFunc('map'),
|
||||
sfilter: wrapIterFunc('filter'),
|
||||
sreduce: wrapIterFunc('reduce'),
|
||||
sforEach: wrapIterFunc('forEach'),
|
||||
|
||||
// Chunk iteration...
|
||||
//
|
||||
CHUNK_SIZE: 50,
|
||||
mapChunks: makeChunkIter('map'),
|
||||
filterChunks: makeChunkIter('map',
|
||||
function(res, func, array, e){
|
||||
return !!func.call(this, e[1], e[0], array) ? [e[1]] : [] }),
|
||||
reduceChunks: makeChunkIter('reduce',
|
||||
function(total, func, array, res, e){
|
||||
return func.call(this,
|
||||
total.length > 0 ?
|
||||
total.pop()
|
||||
: res,
|
||||
e[1], e[0], array) }),
|
||||
})
|
||||
|
||||
|
||||
ArrayMixin(Array)
|
||||
ArrayProtoMixin(Array.prototype)
|
||||
|
||||
|
||||
|
||||
|
||||
121
Date.js
121
Date.js
@ -7,62 +7,20 @@
|
||||
(function(require){ var module={} // make module AMD/node compatible...
|
||||
/*********************************************************************/
|
||||
|
||||
|
||||
var object = require('ig-object')
|
||||
|
||||
|
||||
/*********************************************************************/
|
||||
|
||||
// NOTE: repatching a date should not lead to any side effects as this
|
||||
// does not add any state...
|
||||
// NOTE: this is done differently as there are contexts where there may
|
||||
// be multiple Date objects in different contexts (nw/electron/..)
|
||||
var patchDate =
|
||||
module.patchDate = function(date){
|
||||
date = date || Date
|
||||
|
||||
date.prototype.toShortDate = function(show_ms){
|
||||
return ''
|
||||
+ this.getFullYear()
|
||||
+'-'+ ('0'+(this.getMonth()+1)).slice(-2)
|
||||
+'-'+ ('0'+this.getDate()).slice(-2)
|
||||
+' '+ ('0'+this.getHours()).slice(-2)
|
||||
+':'+ ('0'+this.getMinutes()).slice(-2)
|
||||
+':'+ ('0'+this.getSeconds()).slice(-2)
|
||||
+ (show_ms ?
|
||||
':'+(('000'+this.getMilliseconds()).slice(-3))
|
||||
: '') }
|
||||
|
||||
date.prototype.getTimeStamp = function(show_ms){
|
||||
return ''
|
||||
+ this.getFullYear()
|
||||
+ ('0'+(this.getMonth()+1)).slice(-2)
|
||||
+ ('0'+this.getDate()).slice(-2)
|
||||
+ ('0'+this.getHours()).slice(-2)
|
||||
+ ('0'+this.getMinutes()).slice(-2)
|
||||
+ ('0'+this.getSeconds()).slice(-2)
|
||||
+ (show_ms ?
|
||||
('000'+this.getMilliseconds()).slice(-3)
|
||||
: '') }
|
||||
|
||||
date.prototype.setTimeStamp = function(ts){
|
||||
ts = ts.replace(/[^0-9]*/g, '')
|
||||
this.setFullYear(ts.slice(0, 4))
|
||||
this.setMonth(ts.slice(4, 6)*1-1)
|
||||
this.setDate(ts.slice(6, 8))
|
||||
this.setHours(ts.slice(8, 10))
|
||||
this.setMinutes(ts.slice(10, 12))
|
||||
this.setSeconds(ts.slice(12, 14))
|
||||
this.setMilliseconds(ts.slice(14, 17) || 0)
|
||||
return this }
|
||||
|
||||
date.timeStamp = function(...args){
|
||||
return (new this()).getTimeStamp(...args) }
|
||||
|
||||
date.fromTimeStamp = function(ts){
|
||||
return (new this()).setTimeStamp(ts) }
|
||||
|
||||
var DateMixin =
|
||||
module.DateMixin =
|
||||
object.Mixin('DateMixin', 'soft', {
|
||||
timeStamp: function(...args){
|
||||
return (new this()).getTimeStamp(...args) },
|
||||
fromTimeStamp: function(ts){
|
||||
return (new this()).setTimeStamp(ts) },
|
||||
// convert string time period to milliseconds...
|
||||
date.str2ms = function(str, dfl){
|
||||
str2ms: function(str, dfl){
|
||||
dfl = dfl || 'ms'
|
||||
|
||||
if(typeof(str) == typeof(123)){
|
||||
@ -96,9 +54,68 @@ module.patchDate = function(date){
|
||||
|
||||
return c ?
|
||||
val * c
|
||||
: NaN }
|
||||
: NaN },
|
||||
})
|
||||
|
||||
|
||||
// XXX should this be flat???
|
||||
var DateProtoMixin =
|
||||
module.DateProtoMixin =
|
||||
object.Mixin('DateProtoMixin', 'soft', {
|
||||
toShortDate: function(show_ms){
|
||||
return ''
|
||||
+ this.getFullYear()
|
||||
+'-'+ ('0'+(this.getMonth()+1)).slice(-2)
|
||||
+'-'+ ('0'+this.getDate()).slice(-2)
|
||||
+' '+ ('0'+this.getHours()).slice(-2)
|
||||
+':'+ ('0'+this.getMinutes()).slice(-2)
|
||||
+':'+ ('0'+this.getSeconds()).slice(-2)
|
||||
+ (show_ms ?
|
||||
':'+(('000'+this.getMilliseconds()).slice(-3))
|
||||
: '') },
|
||||
getTimeStamp: function(show_ms){
|
||||
return ''
|
||||
+ this.getFullYear()
|
||||
+ ('0'+(this.getMonth()+1)).slice(-2)
|
||||
+ ('0'+this.getDate()).slice(-2)
|
||||
+ ('0'+this.getHours()).slice(-2)
|
||||
+ ('0'+this.getMinutes()).slice(-2)
|
||||
+ ('0'+this.getSeconds()).slice(-2)
|
||||
+ (show_ms ?
|
||||
('000'+this.getMilliseconds()).slice(-3)
|
||||
: '') },
|
||||
setTimeStamp: function(ts){
|
||||
ts = ts.replace(/[^0-9]*/g, '')
|
||||
this.setFullYear(ts.slice(0, 4))
|
||||
this.setMonth(ts.slice(4, 6)*1-1)
|
||||
this.setDate(ts.slice(6, 8))
|
||||
this.setHours(ts.slice(8, 10))
|
||||
this.setMinutes(ts.slice(10, 12))
|
||||
this.setSeconds(ts.slice(12, 14))
|
||||
this.setMilliseconds(ts.slice(14, 17) || 0)
|
||||
return this },
|
||||
})
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
// NOTE: repatching a date should not lead to any side effects as this
|
||||
// does not add any state...
|
||||
// NOTE: this is done differently as there are contexts where there may
|
||||
// be multiple Date objects in different contexts (nw/electron/..)
|
||||
var patchDate =
|
||||
module.patchDate =
|
||||
function(date){
|
||||
date = date || Date
|
||||
DateMixin(date)
|
||||
DateProtoMixin(date.prototype)
|
||||
return date }
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
// patch the root date...
|
||||
patchDate()
|
||||
|
||||
|
||||
58
Map.js
58
Map.js
@ -7,35 +7,43 @@
|
||||
(function(require){ var module={} // make module AMD/node compatible...
|
||||
/*********************************************************************/
|
||||
|
||||
|
||||
var object = require('ig-object')
|
||||
|
||||
|
||||
/*********************************************************************/
|
||||
|
||||
// NOTE: we do not touch .__keys here as no renaming is ever done...
|
||||
//
|
||||
// XXX this essentially rewrites the whole map, is there a faster/better
|
||||
// way to do this???
|
||||
// ...one way would be to decouple order from the container, i.e.
|
||||
// store the order in a separate attr/prop but this would require
|
||||
// a whole new set of ordered "type" that would overload every single
|
||||
// iteration method, not sure if this is a good idea untill we
|
||||
// reach a state whe JS "shuffles" (index-orders) its containers
|
||||
// (a-la Python)
|
||||
Map.prototype.sort = function(keys){
|
||||
keys = (typeof(keys) == 'function'
|
||||
|| keys === undefined) ?
|
||||
[...this.keys()].sort(keys)
|
||||
: keys
|
||||
var del = Map.prototype.delete.bind(this)
|
||||
var set = Map.prototype.set.bind(this)
|
||||
new Set([...keys, ...this.keys()])
|
||||
.forEach(function(k){
|
||||
if(this.has(k)){
|
||||
var v = this.get(k)
|
||||
del(k)
|
||||
set(k, v) } }.bind(this))
|
||||
return this }
|
||||
|
||||
var MapProtoMixin =
|
||||
module.MapProtoMixin =
|
||||
object.Mixin('MapProtoMixin', 'soft', {
|
||||
// NOTE: we do not touch .__keys here as no renaming is ever done...
|
||||
//
|
||||
// XXX this essentially rewrites the whole map, is there a faster/better
|
||||
// way to do this???
|
||||
// ...one way would be to decouple order from the container, i.e.
|
||||
// store the order in a separate attr/prop but this would require
|
||||
// a whole new set of ordered "type" that would overload every single
|
||||
// iteration method, not sure if this is a good idea untill we
|
||||
// reach a state whe JS "shuffles" (index-orders) its containers
|
||||
// (a-la Python)
|
||||
sort: function(keys){
|
||||
keys = (typeof(keys) == 'function'
|
||||
|| keys === undefined) ?
|
||||
[...this.keys()].sort(keys)
|
||||
: keys
|
||||
var del = this.delete.bind(this)
|
||||
var set = this.set.bind(this)
|
||||
new Set([...keys, ...this.keys()])
|
||||
.forEach(function(k){
|
||||
if(this.has(k)){
|
||||
var v = this.get(k)
|
||||
del(k)
|
||||
set(k, v) } }.bind(this))
|
||||
return this },
|
||||
})
|
||||
|
||||
|
||||
MapProtoMixin(Map.prototype)
|
||||
|
||||
|
||||
|
||||
|
||||
133
Object.js
133
Object.js
@ -16,97 +16,82 @@
|
||||
/*********************************************************************/
|
||||
|
||||
require('object-run')
|
||||
|
||||
var object = require('ig-object')
|
||||
|
||||
|
||||
|
||||
/*********************************************************************/
|
||||
// import stuff from object.js to Object...
|
||||
|
||||
var toObject = function(...keys){
|
||||
keys.forEach(function(key){
|
||||
Object[key]
|
||||
|| (Object[key] = object[key]) }) }
|
||||
var ObjectMixin =
|
||||
module.ObjectMixin =
|
||||
object.Mixin('ObjectMixin', 'soft', {
|
||||
// stuff from object.js...
|
||||
deepKeys: object.deepKeys,
|
||||
|
||||
toObject(
|
||||
'deepKeys',
|
||||
|
||||
// XXX these should be called logically relative to Array.js and diff.js...
|
||||
'match',
|
||||
'matchPartial',
|
||||
match: object.match,
|
||||
matchPartial: object.matchPartial,
|
||||
|
||||
/* XXX not yet sure about these...
|
||||
// XXX EXPERIMENTAL...
|
||||
'parent',
|
||||
'parentProperty',
|
||||
'parentCall',
|
||||
parent : object.parent,
|
||||
parentProperty: object.parentProperty,
|
||||
parentCall: object.parentCall,
|
||||
|
||||
'parentOf',
|
||||
'childOf',
|
||||
'related',
|
||||
parentOf: object.parentOf,
|
||||
childOf: object.childOf,
|
||||
related: object.related,
|
||||
//*/
|
||||
)
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
// Make a copy of an object...
|
||||
//
|
||||
// This will:
|
||||
// - create a new object linked to the same prototype chain as obj
|
||||
// - copy obj own state
|
||||
//
|
||||
// NOTE: this will copy prop values and not props...
|
||||
Object.copy = function(obj, constructor){
|
||||
return Object.assign(
|
||||
constructor == null ?
|
||||
Object.create(obj.__proto__)
|
||||
: constructor(),
|
||||
obj) }
|
||||
|
||||
|
||||
// Make a full key set copy of an object...
|
||||
//
|
||||
// NOTE: this will copy prop values and not props...
|
||||
// NOTE: this will not deep-copy the values...
|
||||
Object.flatCopy = function(obj, constructor){
|
||||
return Object.deepKeys(obj)
|
||||
.reduce(
|
||||
function(res, key){
|
||||
res[key] = obj[key]
|
||||
return res },
|
||||
// Make a copy of an object...
|
||||
//
|
||||
// This will:
|
||||
// - create a new object linked to the same prototype chain as obj
|
||||
// - copy obj own state
|
||||
//
|
||||
// NOTE: this will copy prop values and not props...
|
||||
copy: function(obj, constructor){
|
||||
return Object.assign(
|
||||
constructor == null ?
|
||||
{}
|
||||
: constructor()) }
|
||||
Object.create(obj.__proto__)
|
||||
: constructor(),
|
||||
obj) },
|
||||
|
||||
// Make a full key set copy of an object...
|
||||
//
|
||||
// NOTE: this will copy prop values and not props...
|
||||
// NOTE: this will not deep-copy the values...
|
||||
flatCopy: function(obj, constructor){
|
||||
return Object.deepKeys(obj)
|
||||
.reduce(
|
||||
function(res, key){
|
||||
res[key] = obj[key]
|
||||
return res },
|
||||
constructor == null ?
|
||||
{}
|
||||
: constructor()) },
|
||||
|
||||
// XXX for some reason neumric keys do not respect order...
|
||||
// to reproduce:
|
||||
// Object.keys({a:0, x:1, 10:2, 0:3, z:4, ' 1 ':5})
|
||||
// // -> ["0", "10", "a", "x", "z", " 1 "]
|
||||
// ...this is the same across Chrome and Firefox...
|
||||
sort: function(obj, keys){
|
||||
keys = (typeof(keys) == 'function'
|
||||
|| keys === undefined) ?
|
||||
[...Object.keys(obj)].sort(keys)
|
||||
: keys
|
||||
new Set([...keys, ...Object.keys(obj)])
|
||||
.forEach(function(k){
|
||||
if(k in obj){
|
||||
var v = Object.getOwnPropertyDescriptor(obj, k)
|
||||
delete obj[k]
|
||||
Object.defineProperty(obj, k, v) } })
|
||||
return obj },
|
||||
})
|
||||
|
||||
|
||||
// XXX for some reason neumric keys do not respect order...
|
||||
// to reproduce:
|
||||
// Object.keys({a:0, x:1, 10:2, 0:3, z:4, ' 1 ':5})
|
||||
// // -> ["0", "10", "a", "x", "z", " 1 "]
|
||||
// ...this is the same across Chrome and Firefox...
|
||||
Object.sort = function(obj, keys){
|
||||
keys = (typeof(keys) == 'function'
|
||||
|| keys === undefined) ?
|
||||
[...Object.keys(obj)].sort(keys)
|
||||
: keys
|
||||
new Set([...keys, ...Object.keys(obj)])
|
||||
.forEach(function(k){
|
||||
if(k in obj){
|
||||
var v = Object.getOwnPropertyDescriptor(obj, k)
|
||||
delete obj[k]
|
||||
Object.defineProperty(obj, k, v) } })
|
||||
return obj }
|
||||
/* XXX this messes up things...
|
||||
Object.prototype.sort
|
||||
|| Object.defineProperty(Object.prototype, 'sort', {
|
||||
writable: true,
|
||||
configurable: true,
|
||||
enumerable: false,
|
||||
value: function(keys){
|
||||
return Object.sort(this, keys) }, })
|
||||
//*/
|
||||
ObjectMixin(Object)
|
||||
|
||||
|
||||
|
||||
|
||||
91
Promise.js
91
Promise.js
@ -15,51 +15,9 @@ var object = require('ig-object')
|
||||
|
||||
/*********************************************************************/
|
||||
|
||||
// XXX does this need to be a distinct object/constructor???
|
||||
Promise.cooperative = function(){
|
||||
var handlers
|
||||
return object.mixinFlat(
|
||||
new Promise(function(resolve, reject){
|
||||
handlers = { resolve, reject, } }),
|
||||
{
|
||||
get isSet(){
|
||||
return handlers === false },
|
||||
//
|
||||
// Resolve promise with value...
|
||||
// .set(value)
|
||||
// -> this
|
||||
//
|
||||
// Reject promise with value...
|
||||
// .set(value, false)
|
||||
// -> this
|
||||
//
|
||||
set: function(value, resolve=true){
|
||||
// can't set twice...
|
||||
if(this.isSet){
|
||||
throw new Error('Promise.cooperative().set(..): can not set twice') }
|
||||
// bind to promise...
|
||||
if(value && value.then && value.catch){
|
||||
value.then(handlers.resolve)
|
||||
value.catch(handlers.reject)
|
||||
// resolve with value...
|
||||
} else {
|
||||
resolve ?
|
||||
handlers.resolve(value)
|
||||
: handlers.reject(value) }
|
||||
// cleanup and prevent setting twice...
|
||||
handlers = false
|
||||
return this },
|
||||
}) }
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// promise iterators...
|
||||
|
||||
// XXX should this be aborted on reject???
|
||||
var IterablePromise =
|
||||
module.IterablePromise =
|
||||
Promise.iter =
|
||||
object.Constructor('IterablePromise', Promise, {
|
||||
//
|
||||
// Format:
|
||||
@ -246,6 +204,55 @@ object.Constructor('IterablePromise', Promise, {
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
var PromiseMixin =
|
||||
module.PromiseMixin =
|
||||
object.Mixin('PromiseMixin', 'soft', {
|
||||
// XXX does this need to be a distinct object/constructor???
|
||||
cooperative: function(){
|
||||
var handlers
|
||||
return object.mixinFlat(
|
||||
new Promise(function(resolve, reject){
|
||||
handlers = { resolve, reject, } }),
|
||||
{
|
||||
get isSet(){
|
||||
return handlers === false },
|
||||
//
|
||||
// Resolve promise with value...
|
||||
// .set(value)
|
||||
// -> this
|
||||
//
|
||||
// Reject promise with value...
|
||||
// .set(value, false)
|
||||
// -> this
|
||||
//
|
||||
set: function(value, resolve=true){
|
||||
// can't set twice...
|
||||
if(this.isSet){
|
||||
throw new Error('Promise.cooperative().set(..): can not set twice') }
|
||||
// bind to promise...
|
||||
if(value && value.then && value.catch){
|
||||
value.then(handlers.resolve)
|
||||
value.catch(handlers.reject)
|
||||
// resolve with value...
|
||||
} else {
|
||||
resolve ?
|
||||
handlers.resolve(value)
|
||||
: handlers.reject(value) }
|
||||
// cleanup and prevent setting twice...
|
||||
handlers = false
|
||||
return this },
|
||||
}) },
|
||||
|
||||
iter: IterablePromise,
|
||||
})
|
||||
|
||||
|
||||
PromiseMixin(Promise)
|
||||
|
||||
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* vim:set ts=4 sw=4 : */ return module })
|
||||
|
||||
21
RegExp.js
21
RegExp.js
@ -7,17 +7,28 @@
|
||||
(function(require){ var module={} // make module AMD/node compatible...
|
||||
/*********************************************************************/
|
||||
|
||||
var object = require('ig-object')
|
||||
|
||||
|
||||
|
||||
/*********************************************************************/
|
||||
|
||||
// Quote a string and convert to RegExp to match self literally.
|
||||
var RegExpMixin =
|
||||
module.RegExpMixin =
|
||||
object.Mixin('RegExpMixin', 'soft', {
|
||||
// Quote a string and convert to RegExp to match self literally.
|
||||
quoteRegExp: function(str){
|
||||
return str
|
||||
.replace(/([\.\\\/\(\)\[\]\$\*\+\-\{\}\@\^\&\?\<\>])/g, '\\$1') }
|
||||
})
|
||||
|
||||
|
||||
RegExpMixin(RegExp)
|
||||
|
||||
|
||||
var quoteRegExp =
|
||||
RegExp.quoteRegExp =
|
||||
module.quoteRegExp =
|
||||
function(str){
|
||||
return str.replace(/([\.\\\/\(\)\[\]\$\*\+\-\{\}\@\^\&\?\<\>])/g, '\\$1') }
|
||||
RegExp.quoteRegExp =
|
||||
RegExp.quoteRegExp
|
||||
|
||||
|
||||
|
||||
|
||||
63
Set.js
63
Set.js
@ -7,41 +7,48 @@
|
||||
(function(require){ var module={} // make module AMD/node compatible...
|
||||
/*********************************************************************/
|
||||
|
||||
var object = require('ig-object')
|
||||
|
||||
|
||||
|
||||
/*********************************************************************/
|
||||
|
||||
// Set set operation shorthands...
|
||||
Set.prototype.unite = function(other=[]){
|
||||
return new Set([...this, ...other]) }
|
||||
Set.prototype.intersect = function(other){
|
||||
var test = other.has ?
|
||||
'has'
|
||||
: 'includes'
|
||||
return new Set([...this]
|
||||
.filter(function(e){
|
||||
return other[test](e) })) }
|
||||
Set.prototype.subtract = function(other=[]){
|
||||
other = new Set(other)
|
||||
return new Set([...this]
|
||||
.filter(function(e){
|
||||
return !other.has(e) })) }
|
||||
var SetProtoMixin =
|
||||
module.SetProtoMixin =
|
||||
object.Mixin('SetMixin', 'soft', {
|
||||
// Set set operation shorthands...
|
||||
unite: function(other=[]){
|
||||
return new Set([...this, ...other]) },
|
||||
intersect: function(other){
|
||||
var test = other.has ?
|
||||
'has'
|
||||
: 'includes'
|
||||
return new Set([...this]
|
||||
.filter(function(e){
|
||||
return other[test](e) })) },
|
||||
subtract: function(other=[]){
|
||||
other = new Set(other)
|
||||
return new Set([...this]
|
||||
.filter(function(e){
|
||||
return !other.has(e) })) },
|
||||
|
||||
sort: function(keys=[]){
|
||||
keys = (typeof(keys) == 'function'
|
||||
|| keys === undefined) ?
|
||||
[...this].sort(keys)
|
||||
: keys
|
||||
var del = this.delete.bind(this)
|
||||
var add = this.add.bind(this)
|
||||
new Set([...keys, ...this])
|
||||
.forEach(function(e){
|
||||
if(this.has(e)){
|
||||
del(e)
|
||||
add(e) } }.bind(this))
|
||||
return this },
|
||||
})
|
||||
|
||||
|
||||
Map.prototype.sort = function(keys=[]){
|
||||
keys = (typeof(keys) == 'function'
|
||||
|| keys === undefined) ?
|
||||
[...this].sort(keys)
|
||||
: keys
|
||||
var del = Set.prototype.delete.bind(this)
|
||||
var add = Set.prototype.add.bind(this)
|
||||
new Set([...keys, ...this])
|
||||
.forEach(function(e){
|
||||
if(this.has(e)){
|
||||
del(e)
|
||||
add(e) } }.bind(this))
|
||||
return this }
|
||||
SetProtoMixin(Set.prototype)
|
||||
|
||||
|
||||
|
||||
|
||||
18
String.js
18
String.js
@ -7,15 +7,23 @@
|
||||
(function(require){ var module={} // make module AMD/node compatible...
|
||||
/*********************************************************************/
|
||||
|
||||
|
||||
var object = require('ig-object')
|
||||
|
||||
|
||||
/*********************************************************************/
|
||||
|
||||
String.prototype.capitalize = function(){
|
||||
return this == '' ?
|
||||
this
|
||||
: this[0].toUpperCase() + this.slice(1) }
|
||||
var StringProtoMixin =
|
||||
module.StringProtoMixin =
|
||||
object.Mixin('StringProtoMixin', 'soft', {
|
||||
capitalize: function(){
|
||||
return this == '' ?
|
||||
this
|
||||
: this[0].toUpperCase() + this.slice(1) },
|
||||
})
|
||||
|
||||
|
||||
StringProtoMixin(String.prototype)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
247
generator.js
247
generator.js
@ -112,138 +112,147 @@ var makePromise = function(name){
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
// XXX should this be a generator???
|
||||
GeneratorPrototype.at = makeGenerator('at')
|
||||
var GeneratorMixin =
|
||||
module.GeneratorMixin =
|
||||
object.Mixin('GeneratorMixin', 'soft', {
|
||||
|
||||
GeneratorPrototype.slice = makeGenerator('slice')
|
||||
GeneratorPrototype.flat = makeGenerator('flat')
|
||||
// XXX should this be a generator???
|
||||
at: makeGenerator('at'),
|
||||
|
||||
GeneratorPrototype.map = makeGenerator('map')
|
||||
GeneratorPrototype.filter = makeGenerator('filter')
|
||||
GeneratorPrototype.reduce = makeGenerator('reduce')
|
||||
slice: makeGenerator('slice'),
|
||||
flat: makeGenerator('flat'),
|
||||
|
||||
// non-generators...
|
||||
//
|
||||
GeneratorPrototype.toArray = function(){
|
||||
var that = this
|
||||
return Object.assign(
|
||||
function(){
|
||||
return that(...arguments).toArray() },
|
||||
{ toString: function(){
|
||||
return that.toString()
|
||||
+ '\n .toString()'}, }) }
|
||||
GeneratorPrototype.pop = function(){
|
||||
var that = this
|
||||
return Object.assign(
|
||||
function(){
|
||||
return that(...arguments).toArray().pop() },
|
||||
{ toString: function(){
|
||||
return that.toString()
|
||||
+ '\n .pop()'}, }) }
|
||||
GeneratorPrototype.shift = function(){
|
||||
var that = this
|
||||
return Object.assign(
|
||||
function(){
|
||||
return that(...arguments).toArray().shift() },
|
||||
{ toString: function(){
|
||||
return that.toString()
|
||||
+ '\n .shift()'}, }) }
|
||||
map: makeGenerator('map'),
|
||||
filter: makeGenerator('filter'),
|
||||
reduce: makeGenerator('reduce'),
|
||||
|
||||
// promises...
|
||||
//
|
||||
GeneratorPrototype.then = makePromise('then')
|
||||
GeneratorPrototype.catch = makePromise('catch')
|
||||
GeneratorPrototype.finally = makePromise('finally')
|
||||
// non-generators...
|
||||
//
|
||||
toArray: function(){
|
||||
var that = this
|
||||
return Object.assign(
|
||||
function(){
|
||||
return that(...arguments).toArray() },
|
||||
{ toString: function(){
|
||||
return that.toString()
|
||||
+ '\n .toString()'}, }) },
|
||||
pop: function(){
|
||||
var that = this
|
||||
return Object.assign(
|
||||
function(){
|
||||
return that(...arguments).toArray().pop() },
|
||||
{ toString: function(){
|
||||
return that.toString()
|
||||
+ '\n .pop()'}, }) },
|
||||
shift: function(){
|
||||
var that = this
|
||||
return Object.assign(
|
||||
function(){
|
||||
return that(...arguments).toArray().shift() },
|
||||
{ toString: function(){
|
||||
return that.toString()
|
||||
+ '\n .shift()'}, }) },
|
||||
|
||||
// promises...
|
||||
//
|
||||
then: makePromise('then'),
|
||||
catch: makePromise('catch'),
|
||||
finally: makePromise('finally'),
|
||||
})
|
||||
|
||||
|
||||
var GeneratorProtoMixin =
|
||||
module.GeneratorProtoMixin =
|
||||
object.Mixin('GeneratorProtoMixin', 'soft', {
|
||||
// XXX should this be a generator???
|
||||
at: function*(i){
|
||||
// sanity check...
|
||||
if(i < 0){
|
||||
throw new Error('.at(..): '
|
||||
+'generator index can\'t be a negative value.')}
|
||||
for(var e of this){
|
||||
if(i-- == 0){
|
||||
yield e
|
||||
return } } },
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// GeneratorPrototype instance methods...
|
||||
// NOTE: this is different from Array's .slice(..) in that it does not
|
||||
// support negative indexes -- this is done because there is no way
|
||||
// to judge the length of a generator untill it is fully done...
|
||||
slice: function*(from=0, to=Infity){
|
||||
// sanity check...
|
||||
if(from < 0 || to < 0){
|
||||
throw new Error('.slice(..): '
|
||||
+'generator form/to indexes can\'t be negative values.')}
|
||||
var i = 0
|
||||
for(var e of this){
|
||||
// stop at end of seq...
|
||||
if(i >= to){
|
||||
return }
|
||||
// only yield from from...
|
||||
if(i >= from){
|
||||
yield e }
|
||||
i++ } },
|
||||
// XXX do we need a version that'll expand generators???
|
||||
flat: function*(depth=1){
|
||||
if(depth == 0){
|
||||
return this }
|
||||
for(var e of this){
|
||||
// expand array...
|
||||
if(e instanceof Array){
|
||||
for(var i=0; i < e.length; i++){
|
||||
if(depth <= 1){
|
||||
yield e[i]
|
||||
|
||||
// XXX should this be a generator???
|
||||
GeneratorPrototype.prototype.at = function*(i){
|
||||
// sanity check...
|
||||
if(i < 0){
|
||||
throw new Error('.at(..): '
|
||||
+'generator index can\'t be a negative value.')}
|
||||
for(var e of this){
|
||||
if(i-- == 0){
|
||||
yield e
|
||||
return } } },
|
||||
} else {
|
||||
yield* typeof(e[i].flat) == 'function' ?
|
||||
e[i].flat(depth-1)
|
||||
: e[i] } }
|
||||
// item as-is...
|
||||
} else {
|
||||
yield e } } },
|
||||
|
||||
// NOTE: this is different from Array's .slice(..) in that it does not
|
||||
// support negative indexes -- this is done because there is no way
|
||||
// to judge the length of a generator untill it is fully done...
|
||||
GeneratorPrototype.prototype.slice = function*(from=0, to=Infity){
|
||||
// sanity check...
|
||||
if(from < 0 || to < 0){
|
||||
throw new Error('.slice(..): '
|
||||
+'generator form/to indexes can\'t be negative values.')}
|
||||
var i = 0
|
||||
for(var e of this){
|
||||
// stop at end of seq...
|
||||
if(i >= to){
|
||||
return }
|
||||
// only yield from from...
|
||||
if(i >= from){
|
||||
yield e }
|
||||
i++ } },
|
||||
// XXX do we need a version that'll expand generators???
|
||||
GeneratorPrototype.prototype.flat = function*(depth=1){
|
||||
if(depth == 0){
|
||||
return this }
|
||||
for(var e of this){
|
||||
// expand array...
|
||||
if(e instanceof Array){
|
||||
for(var i=0; i < e.length; i++){
|
||||
if(depth <= 1){
|
||||
yield e[i]
|
||||
map: function*(func){
|
||||
var i = 0
|
||||
for(var e of this){
|
||||
yield func(e, i++, this) } },
|
||||
filter: function*(func){
|
||||
var i = 0
|
||||
for(var e of this){
|
||||
if(func(e, i++, this)){
|
||||
yield e } } },
|
||||
reduce: function*(func, res){
|
||||
var i = 0
|
||||
for(var e of this){
|
||||
res = func(res, e, i++, this) }
|
||||
yield res },
|
||||
|
||||
} else {
|
||||
yield* typeof(e[i].flat) == 'function' ?
|
||||
e[i].flat(depth-1)
|
||||
: e[i] } }
|
||||
// item as-is...
|
||||
} else {
|
||||
yield e } } }
|
||||
// non-generators...
|
||||
//
|
||||
toArray: function(){
|
||||
return [...this] },
|
||||
pop: function(){
|
||||
return [...this].pop() },
|
||||
shift: function(){
|
||||
return [...this].shift() },
|
||||
|
||||
GeneratorPrototype.prototype.map = function*(func){
|
||||
var i = 0
|
||||
for(var e of this){
|
||||
yield func(e, i++, this) } }
|
||||
GeneratorPrototype.prototype.filter = function*(func){
|
||||
var i = 0
|
||||
for(var e of this){
|
||||
if(func(e, i++, this)){
|
||||
yield e } } }
|
||||
GeneratorPrototype.prototype.reduce = function*(func, res){
|
||||
var i = 0
|
||||
for(var e of this){
|
||||
res = func(res, e, i++, this) }
|
||||
yield res }
|
||||
// promises...
|
||||
//
|
||||
// XXX how do we handle reject(..) / .catch(..)???
|
||||
promise: function(){
|
||||
var that = this
|
||||
return new Promise(function(resolve){
|
||||
resolve([...that]) }) },
|
||||
then: function(func){
|
||||
return this.promise().then(func) },
|
||||
catch: function(func){
|
||||
return this.promise().catch(func) },
|
||||
finally: function(func){
|
||||
return this.promise().finally(func) },
|
||||
})
|
||||
|
||||
// non-generators...
|
||||
//
|
||||
GeneratorPrototype.prototype.toArray = function(){
|
||||
return [...this] }
|
||||
GeneratorPrototype.prototype.pop = function(){
|
||||
return [...this].pop() }
|
||||
GeneratorPrototype.prototype.shift = function(){
|
||||
return [...this].shift() }
|
||||
|
||||
// promises...
|
||||
//
|
||||
// XXX how do we handle reject(..) / .catch(..)???
|
||||
GeneratorPrototype.prototype.promise = function(){
|
||||
var that = this
|
||||
return new Promise(function(resolve){
|
||||
resolve([...that]) }) }
|
||||
GeneratorPrototype.prototype.then = function(func){
|
||||
return this.promise().then(func) }
|
||||
GeneratorPrototype.prototype.catch = function(func){
|
||||
return this.promise().catch(func) }
|
||||
GeneratorPrototype.prototype.finally = function(func){
|
||||
return this.promise().finally(func) }
|
||||
GeneratorMixin(GeneratorPrototype)
|
||||
GeneratorProtoMixin(GeneratorPrototype.prototype)
|
||||
|
||||
|
||||
|
||||
|
||||
14
package-lock.json
generated
14
package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ig-types",
|
||||
"version": "3.7.11",
|
||||
"version": "3.7.14",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@ -265,14 +265,14 @@
|
||||
}
|
||||
},
|
||||
"ig-object": {
|
||||
"version": "5.4.2",
|
||||
"resolved": "https://registry.npmjs.org/ig-object/-/ig-object-5.4.2.tgz",
|
||||
"integrity": "sha512-xRJRI7Y5Cw0u7FZL/Ln/noitjQ9HFVLwHbnVozCZ1/95p/F9h+kenOzagj/Cm0uBsEdTi3KJfGrdmsyH5AM7cg=="
|
||||
"version": "5.4.11",
|
||||
"resolved": "https://registry.npmjs.org/ig-object/-/ig-object-5.4.11.tgz",
|
||||
"integrity": "sha512-WPPQ5C41c6q3tPfa2fBbWE2xcLF7LoGRu2E6Wr/aoA5oxAyl8lAuE7Kqt4TyPwfW9jVI0+ifBztg9e1tR5mG1Q=="
|
||||
},
|
||||
"ig-test": {
|
||||
"version": "1.4.6",
|
||||
"resolved": "https://registry.npmjs.org/ig-test/-/ig-test-1.4.6.tgz",
|
||||
"integrity": "sha512-Pv0+Zj3VXWjGhC05ueEcyBs6F1piQoXWj1ZR8azpLMdkivgJ3aHJFmawXDGCrc2T/IY1wPNYH1EGUG0OzcRnhw==",
|
||||
"version": "1.4.8",
|
||||
"resolved": "https://registry.npmjs.org/ig-test/-/ig-test-1.4.8.tgz",
|
||||
"integrity": "sha512-TwSVA/874sHTc05RE+HtMW1BEbgws868CTQzpBwnVMYTKj6Th0mrNSls9SsTM/Ias2giPRZfusg+U/vc/JIcQQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"colors": "^1.4.0",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ig-types",
|
||||
"version": "3.7.13",
|
||||
"version": "3.7.15",
|
||||
"description": "Generic JavaScript types and type extensions...",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
@ -23,12 +23,12 @@
|
||||
},
|
||||
"homepage": "https://github.com/flynx/types.js#readme",
|
||||
"dependencies": {
|
||||
"ig-object": "^5.4.2",
|
||||
"ig-object": "^5.4.11",
|
||||
"object-run": "^1.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"c8": "^7.3.5",
|
||||
"color": "^3.1.3",
|
||||
"ig-test": "^1.4.6"
|
||||
"ig-test": "^1.4.8"
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user