mirror of
https://github.com/flynx/types.js.git
synced 2025-10-29 02:20:07 +00:00
minor fixes, not done yet...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
parent
e29ce4583c
commit
cdd9a5e2ba
162
README.md
162
README.md
@ -3,7 +3,9 @@
|
||||
A library of JavaScript type extensions, types and type utilities.
|
||||
|
||||
- [types.js](#typesjs)
|
||||
- [Built-in type extenstions](#built-in-type-extenstions)
|
||||
- [Installation](#installation)
|
||||
- [Basic usage](#basic-usage)
|
||||
- [Built-in type extensions](#built-in-type-extensions)
|
||||
- [`Object`](#object)
|
||||
- [`Object.deepKeys(..)`](#objectdeepkeys)
|
||||
- [`Object.match(..)`](#objectmatch)
|
||||
@ -43,13 +45,52 @@ A library of JavaScript type extensions, types and type utilities.
|
||||
- [`RegExp`](#regexp)
|
||||
- [`RegExp.quoteRegExp(..)`](#regexpquoteregexp)
|
||||
- [Containers](#containers)
|
||||
- [`UniqueKeyMap()` (`Map`)](#uniquekeymap-map)
|
||||
- [`containers.UniqueKeyMap()` (`Map`)](#containersuniquekeymap-map)
|
||||
- [`<unique-key-map>.reset(..)`](#unique-key-mapreset)
|
||||
- [`<unique-key-map>.uniqueKey(..)`](#unique-key-mapuniquekey)
|
||||
- [`<unique-key-map>.rename(..)`](#unique-key-maprename)
|
||||
- [`<unique-key-map>.keysOf(..)`](#unique-key-mapkeysof)
|
||||
- [`<unique-key-map>.__key_pattern__`](#unique-key-map__key_pattern__)
|
||||
- [License](#license)
|
||||
|
||||
## Built-in type extenstions
|
||||
## Installation
|
||||
|
||||
```shell
|
||||
$ npm install -s 'ig-types'
|
||||
```
|
||||
|
||||
|
||||
## Basic usage
|
||||
|
||||
To extend everything:
|
||||
```javascript
|
||||
require('ig-types')
|
||||
```
|
||||
|
||||
To have access to library types and utilities:
|
||||
```javascript
|
||||
var types = require('ig-types')
|
||||
```
|
||||
|
||||
`types.js` is organized so as to be able to import/extend only specific
|
||||
sub-modules mostly independently so...
|
||||
|
||||
In case there is a need to only extend a specific constructor:
|
||||
```javascript
|
||||
// require `ig-types/<constructor-name>`...
|
||||
require('ig-types/Array')
|
||||
```
|
||||
|
||||
And to import specific library modules only:
|
||||
```javascript
|
||||
var containers = require('ig-types/containers')
|
||||
```
|
||||
|
||||
Note that though mostly independent now some sub-modules may import
|
||||
others in the future.
|
||||
|
||||
|
||||
## Built-in type extensions
|
||||
|
||||
### `Object`
|
||||
|
||||
@ -63,6 +104,40 @@ A library of JavaScript type extensions, types and type utilities.
|
||||
|
||||
#### `<object>.run(..)`
|
||||
|
||||
```
|
||||
<object>.run(<func>)
|
||||
-> <object>
|
||||
-> <other>
|
||||
```
|
||||
|
||||
Run a function in the context of `<object>` returning either `<object>`
|
||||
itself (if returning `undefined`) or the result.
|
||||
|
||||
Note that this is accessible from all JavaScript non-primitive objects,
|
||||
i.e. everything that inherits from `Object`.
|
||||
|
||||
Example:
|
||||
```javascript
|
||||
var L = [1, 2, 3]
|
||||
.map(function(e){
|
||||
return e * 2 })
|
||||
// see if the first element is 1 and prepend 1 if it is not...
|
||||
.run(function(){
|
||||
if(this[0] != 1){
|
||||
this.unshift(1) } })
|
||||
|
||||
console.log(L) // -> [1, 2, 6, 8]
|
||||
```
|
||||
|
||||
`.run(..)` is also available standalone via:
|
||||
|
||||
```shell
|
||||
$ npm install -s object-run
|
||||
```
|
||||
|
||||
For more info see:
|
||||
https://github.com/flynx/object-run.js
|
||||
|
||||
|
||||
### `Array`
|
||||
|
||||
@ -148,15 +223,81 @@ Generate an array with all duplicate elements removed.
|
||||
|
||||
## Containers
|
||||
|
||||
### `UniqueKeyMap()` (`Map`)
|
||||
```javascript
|
||||
var containers = require('ig-types').containers
|
||||
```
|
||||
or, to only import containers:
|
||||
```javascript
|
||||
var containers = require('ig-types/containers')
|
||||
```
|
||||
|
||||
`UniqueKeyMap` extends the `Map` constructor.
|
||||
### `containers.UniqueKeyMap()` (`Map`)
|
||||
|
||||
`UniqueKeyMap` implements a key-value container (i.e. `Map`) that supports
|
||||
and maintains _duplicate_ keys by appending an index to them.
|
||||
The original keys are stored internally thus the renaming mechanics are
|
||||
stable.
|
||||
|
||||
`UniqueKeyMap` extends the `Map` constructor, so all the usual `Map`
|
||||
methods and properties apply here.
|
||||
|
||||
To construct an instance:
|
||||
```javascript
|
||||
var x = new UniqueKeyMap()
|
||||
```
|
||||
or:
|
||||
```javascript
|
||||
// new is optional...
|
||||
var y = UniqueKeyMap()
|
||||
```
|
||||
|
||||
`UniqueKeyMap` supports the same initialization signature as `Map` but
|
||||
treats repeating keys differently.
|
||||
```javascript
|
||||
var z = UniqueKeyMap([['a', 1], ['a', 2], ['b', 1]])
|
||||
```
|
||||
|
||||
The second `"a"` item will automatically get re-keyed as `"a (1)"`:
|
||||
```javascript
|
||||
console.log([...z.keys()]) // -> ['a', 'a (1)', 'b']
|
||||
```
|
||||
|
||||
Note that `.set(..)` will never rewrite an element:
|
||||
```javascript
|
||||
z.set('a', 3)
|
||||
|
||||
console.log([...z.keys()]) // -> ['a', 'a (1)', 'b', 'a (2)']
|
||||
|
||||
z.get('a') // -> 1
|
||||
z.get('a (1)') // -> 2
|
||||
```
|
||||
|
||||
To get the generated key:
|
||||
```javascript
|
||||
var k = z.set('a', 4, true)
|
||||
|
||||
console.log(k) // -> 'a (3)'
|
||||
```
|
||||
|
||||
To explicitly rewrite an item:
|
||||
```javascript
|
||||
z.reset('a (1)', 4)
|
||||
|
||||
z.get('a (1)') // -> 4
|
||||
```
|
||||
|
||||
And we can _rename_ items, i.e. change their key:
|
||||
```javascript
|
||||
z.rename('a (2)', 'c')
|
||||
|
||||
console.log([...z.keys()]) // -> ['a', 'a (1)', 'b', 'a (3)', 'c']
|
||||
```
|
||||
|
||||
XXX
|
||||
|
||||
For more info on `Map` see:
|
||||
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
|
||||
|
||||
|
||||
#### `<unique-key-map>.reset(..)`
|
||||
|
||||
#### `<unique-key-map>.uniqueKey(..)`
|
||||
@ -165,7 +306,16 @@ https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects
|
||||
|
||||
#### `<unique-key-map>.keysOf(..)`
|
||||
|
||||
#### `<unique-key-map>.__key_pattern__`
|
||||
|
||||
|
||||
|
||||
## License
|
||||
|
||||
[BSD 3-Clause License](./LICENSE)
|
||||
|
||||
Copyright (c) 2020, Alex A. Naanou,
|
||||
All rights reserved.
|
||||
|
||||
|
||||
<!-- vim:set ts=4 sw=4 spell : -->
|
||||
183
containers.js
183
containers.js
@ -26,10 +26,22 @@ module.UniqueKeyMap = object.Constructor('UniqueKeyMap', Map, {
|
||||
// ])
|
||||
//
|
||||
// XXX should .__keys_index be non-enumerable???
|
||||
__keys_index: null,
|
||||
get __keys(){
|
||||
return (this.__keys_index =
|
||||
this.__keys_index || new Map()) },
|
||||
|
||||
// Format:
|
||||
// Map([
|
||||
// [<unique-key>, <orig-key>],
|
||||
// ...
|
||||
// ])
|
||||
//
|
||||
__reverse_index: null,
|
||||
get __reverse(){
|
||||
return (this.__reverse_index =
|
||||
this.__reverse_index || new Map()) },
|
||||
|
||||
|
||||
// Patter to be used to generate unique key...
|
||||
__key_pattern__: '$KEY ($COUNT)',
|
||||
@ -47,39 +59,10 @@ module.UniqueKeyMap = object.Constructor('UniqueKeyMap', Map, {
|
||||
__unique_key_value__: false,
|
||||
|
||||
|
||||
// NOTE: this will never overwrite a key's value, to overwrite use .reset(..)
|
||||
set: function(key, elem, return_key=false){
|
||||
var names
|
||||
var n
|
||||
// index
|
||||
this.__keys.set(elem,
|
||||
names = this.__keys.get(elem) || new Set())
|
||||
// key/elem already exists...
|
||||
if(this.__unique_key_value__
|
||||
&& names.has(key)){
|
||||
return return_key ?
|
||||
key
|
||||
: this }
|
||||
names.add(key)
|
||||
// add the elem with the unique name...
|
||||
var res = object.parentCall(
|
||||
UniqueKeyMap.prototype,
|
||||
'set',
|
||||
this,
|
||||
n = this.uniqieKey(key),
|
||||
elem)
|
||||
return return_key ?
|
||||
n
|
||||
: res },
|
||||
reset: function(key, elem){
|
||||
return object.parentCall(UniqueKeyMap.prototype, 'set', this, key, elem) },
|
||||
delete: function(key){
|
||||
var s = this.__keys.get(this.get(key))
|
||||
if(s){
|
||||
s.delete(key)
|
||||
s.size == 0
|
||||
& this.__keys.delete(this.get(key)) }
|
||||
return object.parentCall(UniqueKeyMap.prototype, 'delete', this, key) },
|
||||
// helpers...
|
||||
//
|
||||
originalKey: function(key){
|
||||
return this.__reverse.get(key) },
|
||||
uniqieKey: function(key){
|
||||
var n = key
|
||||
var i = 0
|
||||
@ -89,10 +72,6 @@ module.UniqueKeyMap = object.Constructor('UniqueKeyMap', Map, {
|
||||
.replace(/\$KEY/, key)
|
||||
.replace(/\$COUNT/, i) }
|
||||
return n },
|
||||
rename: function(from, to, return_key=false){
|
||||
var e = this.get(from)
|
||||
this.delete(from)
|
||||
return this.set(to, e, return_key) },
|
||||
keysOf: function(elem, mode='original'){
|
||||
// get unique keys...
|
||||
if(mode == 'unique'){
|
||||
@ -104,6 +83,136 @@ module.UniqueKeyMap = object.Constructor('UniqueKeyMap', Map, {
|
||||
return res }, []) }
|
||||
// get keys used to set the values...
|
||||
return [...(this.__keys.get(elem) || [])] },
|
||||
// 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???
|
||||
sortKeysAs: function(keys){
|
||||
var del = object.parent(UniqueKeyMap.prototype, 'delete').bind(this)
|
||||
var set = object.parent(UniqueKeyMap.prototype, 'set').bind(this)
|
||||
new Set([...keys, ...this.keys()])
|
||||
.forEach(function(k){
|
||||
var v = this.get(k)
|
||||
del(k)
|
||||
set(k, v) }.bind(this))
|
||||
return this },
|
||||
|
||||
|
||||
// NOTE: this will never overwrite a key's value, to overwrite use .reset(..)
|
||||
set: function(key, elem, return_key=false){
|
||||
// index...
|
||||
var names
|
||||
this.__keys.set(elem,
|
||||
names = this.__keys.get(elem) || new Set())
|
||||
// key/elem already exists...
|
||||
if(this.__unique_key_value__
|
||||
&& names.has(key)){
|
||||
return return_key ?
|
||||
key
|
||||
: this }
|
||||
names.add(key)
|
||||
// add the elem with the unique name...
|
||||
var n
|
||||
var res = object.parentCall(
|
||||
UniqueKeyMap.prototype,
|
||||
'set',
|
||||
this,
|
||||
n = this.uniqieKey(key),
|
||||
elem)
|
||||
// reverse index...
|
||||
this.__reverse.set(n, key)
|
||||
return return_key ?
|
||||
n
|
||||
: res },
|
||||
// XXX in-place...
|
||||
// XXX feels odd....
|
||||
reset: function(key, elem, in_place=false){
|
||||
// rewrite...
|
||||
if(this.has(key)){
|
||||
// remove old elem/key from .__keys...
|
||||
var o = this.originalKey(key)
|
||||
var s = this.__keys.get(this.get(key))
|
||||
s.delete(o)
|
||||
s.size == 0
|
||||
&& this.__keys.delete(this.get(key))
|
||||
// add new elem/key to .__keys...
|
||||
var n
|
||||
this.__keys.set(elem, (n = this.__keys.get(elem) || new Set()))
|
||||
n.add(o)
|
||||
|
||||
return object.parentCall(UniqueKeyMap.prototype, 'set', this, key, elem)
|
||||
// add...
|
||||
} else {
|
||||
return this.set(...arguments) } },
|
||||
// XXX this affects order...
|
||||
_reset: function(key, elem, return_key=false){
|
||||
this.delete(key)
|
||||
return this.set(...arguments) },
|
||||
/*/
|
||||
// XXX this will rewrite the whole thing when it does not have to...
|
||||
_reset: function(key, elem, in_place=false){
|
||||
var keys = [...this.keys()]
|
||||
|
||||
this.delete(key)
|
||||
var res = this.set(...arguments)
|
||||
|
||||
// keep order...
|
||||
this.sortKeysAs(keys)
|
||||
|
||||
return res },
|
||||
//*/
|
||||
// XXX BUG: index leak...
|
||||
// to reproduce:
|
||||
// u = UniqueKeyMap([ ['a', 1], ['a', 2], ['a', 3] ])
|
||||
// u.delete('a (1)')
|
||||
// -> .__keys still contains [2, 'a'] -- should be gone...
|
||||
// XXX need a way to get the original key for a specific key, in
|
||||
// this case: 'a (1)' -> 'a'
|
||||
// ...add a reverse index???
|
||||
delete: function(key){
|
||||
var s = this.__keys.get(this.get(key))
|
||||
if(s){
|
||||
// XXX will this delete if key is with an index???
|
||||
//s.delete(key)
|
||||
s.delete(this.originalKey(key))
|
||||
this.__reverse.delete(key)
|
||||
s.size == 0
|
||||
&& this.__keys.delete(this.get(key)) }
|
||||
return object.parentCall(UniqueKeyMap.prototype, 'delete', this, key) },
|
||||
// XXX this affects order...
|
||||
rename: function(from, to, return_key=false){
|
||||
var e = this.get(from)
|
||||
this.delete(from)
|
||||
return this.set(to, e, return_key) },
|
||||
// XXX in-place...
|
||||
// XXX rename to .rename(..)
|
||||
/*/ XXX this is ugly...
|
||||
_rename: function(from, to, return_key=false){
|
||||
var res
|
||||
for([k, v] of [...this.entries()]){
|
||||
this.delete(k)
|
||||
if(k == from){
|
||||
res = this.set(to, v, return_key)
|
||||
} else if(k != to) {
|
||||
this.reset(k, v) } }
|
||||
return res },
|
||||
/*/
|
||||
// XXX do not se how can we avoid rewriting the map if we want to
|
||||
// keep order...
|
||||
_rename: function(from, to, return_key=false){
|
||||
var keys = [...this.keys()]
|
||||
|
||||
var e = this.get(from)
|
||||
this.delete(from)
|
||||
var n = this.set(to, e, true)
|
||||
|
||||
// keep order...
|
||||
keys.splice(keys.indexOf(from), 1, n)
|
||||
this.sortKeysAs(keys)
|
||||
|
||||
return return_key ?
|
||||
n
|
||||
: this },
|
||||
//*/
|
||||
})
|
||||
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ig-types",
|
||||
"version": "2.0.8",
|
||||
"version": "2.0.9",
|
||||
"description": "Generic JavaScript types and type extensions...",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
|
||||
6
test.js
6
test.js
@ -128,6 +128,7 @@ var cases = test.Cases({
|
||||
},
|
||||
|
||||
// containers.js
|
||||
// XXX .reset(..) and .rename(..) should not affect order...
|
||||
UniqueKeyMap: function(assert){
|
||||
var a = assert(containers.UniqueKeyMap(), '')
|
||||
var b = assert(containers.UniqueKeyMap([]), '')
|
||||
@ -162,7 +163,12 @@ var cases = test.Cases({
|
||||
|
||||
assert(c.keysOf(222).sort().cmp(['b', 'a'].sort()))
|
||||
|
||||
var k = [...c.keys()]
|
||||
|
||||
assert((n = c.rename('a', 'b', true)) == 'b (1)')
|
||||
|
||||
// XXX should .rename(..) affect element order??
|
||||
//console.log('>>>>>', k, [...c.keys()])
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user