Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@labshare/data-structures

Package Overview
Dependencies
Maintainers
3
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@labshare/data-structures - npm Package Compare versions

Comparing version 1.0.0 to 1.1.5

CHANGELOG.md

16

package.json
{
"name": "@labshare/data-structures",
"main": "./src/index.ts",
"version": "1.0.0",
"version": "1.1.5",
"description": "",

@@ -17,7 +17,7 @@ "contributors": "https://github.com/LabShare/data-structures/graphs/contributors",

"test": "karma start ./test/karma.conf.js",
"coverage": "karma start ./test/karma.conf.js",
"test:watch": "karma start ./test/karma.conf.js --single-run false",
"coverage": "npm run test",
"test:watch": "npm run test -- --single-run false",
"lint": "tslint -p tsconfig.json -c tslint.json",
"lint:fix": "tslint --fix -p tsconfig.json -c tslint.json",
"build": "tsc",
"lint:fix": "npm run lint -- --fix",
"build": "tsc --outDir build/",
"commitmsg": "commitlint -e $GIT_PARAMS",

@@ -57,3 +57,9 @@ "semantic-release": "semantic-release",

"tslint": "^5.9.1"
},
"publishConfig": {
"access": "public"
},
"release": {
"extends": "@labshare/semantic-release-config"
}
}

@@ -271,2 +271,112 @@ import {Collection} from './collection'

describe('getOne', () => {
it('should return a value from the Collection', () => {
let c = Collection.fromArray([
'firstItem'
]);
let item;
expect(() => item = c.getOne()).not.toThrow();
expect(item).toEqual('firstItem');
c = Collection.fromArray([]);
expect(() => item = c.getOne()).not.toThrow();
expect(item).toBeUndefined();
c = Collection.fromArray([
'firstItem',
'secondItem',
'thirdItem'
]);
expect(() => item = c.getOne()).not.toThrow();
/* must be any of the three */
expect(['firstItem', 'secondItem', 'thirdItem']).toContain(item);
})
})
describe('isEmpty', () => {
it ('should return true for empty collection', () => {
let c = Collection.fromArray([]);
expect(c.isEmpty()).toBeTruthy();
c = Collection.fromArray([
'firstItem'
]);
expect(c.isEmpty()).toBeFalsy();
c = Collection.fromArray([
'firstItem',
'secondItem'
]);
expect(c.isEmpty()).toBeFalsy();
})
})
describe('difference', () => {
it('should allow difference from another collection', () => {
let c = Collection.fromArray([5, 7, 8, 9, 12]),
c2 = Collection.fromArray([1, 2, 3, 4, 9, 6, 7]),
c3;
expect(() => c3 = c.difference(c2)).not.toThrow();
expect(c3.size()).toBe(3);
expect(c3.has(7)).toBeFalsy();
expect(c3.has(9)).toBeFalsy();
expect(c3.has(5)).toBeTruthy();
expect(c3.has(8)).toBeTruthy();
expect(c3.has(12)).toBeTruthy();
})
it('should return self reference when difference equals self', () => {
let c = Collection.fromArray([5, 7, 8, 9, 12]),
c2 = Collection.fromArray([89, 90, 8172, 123]),
c3;
expect(() => c3 = c.difference(c2)).not.toThrow();
expect(c3).toBe(c);
c2 = Collection.fromArray([5]);
expect(() => c3 = c.difference(c2)).not.toThrow();
expect(c3).not.toBe(c);
})
})
describe('iterators', () => {
it('should contain iterator for "for ... of" loops', () => {
let c = Collection.fromArray([1, 2, 3, 4]);
let str = "";
for (let item of c) {
str += `${item};`;
}
expect(str).toBe('2;1;3;4;')
})
it('should contain forEach method', () => {
const arr = [
'abc',
'def',
'ghi',
'jkl'
];
let c = Collection.fromArray(arr);
c.forEach(item => {
expect(c.has(item)).toBeTruthy()
expect(arr.find((i) => i === item)).toEqual(item);
arr.splice(arr.indexOf(item), 1);
})
expect(arr.length).toBe(0);
})
it('should contain filter method', () => {
const arr = ['Walked', 'Talked', 'Faked', 'Made', 'Did'].map(
i => ({id: i})
);
let c = Collection.fromArray(arr);
let c2 = c.filter(word => {
return word.id.match(/ed$/)
});
expect(c2.has({id: 'Walked'})).toBeTruthy();
expect(c2.has({id: 'Talked'})).toBeTruthy();
expect(c2.has({id: 'Faked'})).toBeTruthy();
expect(c2.has({id: 'Made'})).toBeFalsy();
expect(c2.has({id: 'Did'})).toBeFalsy();
})
})
})

@@ -168,2 +168,6 @@ import {SSet} from '../sset/sset';

public isEmpty(): any {
return this.size() === 0;
}
public remove(item) {

@@ -195,2 +199,12 @@ const newSet = this.internal.set.remove(item);

public forEach(fn) {
this.internal.set.forEach(fn);
}
public filter(fn) {
return new Collection({
set: this.internal.set.filter(fn),
});
}
public size() {

@@ -197,0 +211,0 @@ return this.internal.set.size();

@@ -89,2 +89,11 @@ import {Graph} from './graph'

})
it('should create empty graph', () => {
let graph;
expect(() => graph = Graph.fromEmpty()).not.toThrow();
expect(graph.toObject()).toEqual({
edges: [],
nodes: []
})
})
})

@@ -396,2 +405,597 @@

describe('nodes addition', () => {
it('should throw error if node already exists', () => {
let graph = Graph.fromObject({
edges: [],
nodes: [
{
name: 'Colin',
lastName: 'Creevey',
id: 'the-photographer'
}
]
});
expect(() => graph.nodes.add({
name: 'Colin',
lastName: 'Creevey',
id: 'the-photographer'
})).toThrowError(
`Could not add Node to Graph: Node already exists`
)
})
it('should add node to empty graph and preserve edges', () => {
let graph = Graph.fromEmpty();
expect(() => graph = graph.nodes.add({
name: 'Mundungus',
lastName: 'Fletcher',
id: 'mundungus'
})).not.toThrow()
expect(graph.toObject()).toEqual({
edges: [],
nodes: [{
name: 'Mundungus',
lastName: 'Fletcher',
id: 'mundungus'
}]
})
expect(() => graph = Graph.fromObject({
edges: [{
from: 'mundungus',
to: 'harry',
id: 'm-h',
labels: ['TELL_ON']
}],
nodes: [{
id: 'mundungus'
}]
})).not.toThrow()
expect(() => graph = graph.nodes.add({
id: 'harry'
})).not.toThrow();
expect(graph.toObject()).toEqual({
edges: [{
from: 'mundungus',
to: 'harry',
id: 'm-h',
labels: ['TELL_ON']
}],
nodes: [{
id: 'mundungus'
}, {
id: 'harry'
}]
})
})
})
describe('nodes hasId', () => {
it('should return true when it exists', () => {
let g = Graph.fromObject({
edges: [],
nodes: [{
id: 'node0'
}]
});
expect(g.nodes.hasId('node0')).toEqual(true);
expect(g.nodes.hasId('another-node')).toEqual(false);
})
})
describe('nodes update', () => {
it('should throw error when node does not exist', () => {
let g = Graph.fromEmpty();
expect(() => g = g.nodes.update({
id: 'inexistentId'
}, {
id: 'newId'
})).toThrowError(
`Could not update Node from Graph: Node does not exist`
);
g = Graph.fromObject({
edges: [],
nodes: [{
id: '1234'
}]
})
expect(() => g = g.nodes.update({
id: 'inexistentId'
}, {
id: 'newId'
})).toThrowError(
`Could not update Node from Graph: Node does not exist`
);
})
it('should update graph when node exists', () => {
let g = Graph.fromObject({
edges: [],
nodes: [{
id: '1234'
}, {
id: 'another-node'
}]
})
expect(() => g = g.nodes.update({
id: '1234'
}, {
id: 'newId'
})).not.toThrow();
expect(g.toObject().nodes).toContain({
id: 'newId'
})
expect(g.toObject().nodes).toContain({
id: 'another-node'
})
})
})
describe('nodes oneReachedById', () => {
it('should return one node reached by given node id', () => {
let g = Graph.fromObject({
edges: [{
from: 'a',
to: 'b',
id: 'a-b'
}],
nodes: [{
id: 'a'
}, {
id: 'b'
}]
});
expect(g.nodes.oneReachedById('a')).toEqual({
id: 'b'
})
})
it('should return undefined when there are no nodes reached by id', () => {
let g = Graph.fromObject({
edges: [{
from: 'a',
to: 'b',
id: 'a-b'
}],
nodes: [{
id: 'a'
}, {
id: 'b'
}]
});
expect(g.nodes.oneReachedById('inexistent')).toBeUndefined()
})
})
describe('nodes find', () => {
let g;
beforeEach(() => {
g = Graph.fromObject({
edges: [],
nodes: [{
id: 'n1'
}, {
id: 'n2',
name: 'Node 2'
}, {
id: 1
}]
});
})
it('should find node by id', () => {
expect(g.nodes.find({
id: 'n1'
}).toObject().nodes).toEqual([{
id: 'n1'
}]);
expect(g.nodes.find({
id: '1'
}).toObject().nodes).toEqual([])
expect(g.nodes.find({
id: 1
}).toObject().nodes).toEqual([{
id: 1
}])
})
it('should not fail for inexistent key', () => {
let result;
expect(() => result = g.nodes.find({
anyKey: 'anyValue'
})).not.toThrow();
expect(result.toObject().nodes).toEqual([]);
})
it('should not fail for keys that exist in only one object', () => {
let result;
expect(() => result = g.nodes.find({
name: 'Node 2'
})).not.toThrow();
expect(result.toObject().nodes).toEqual([{
id: 'n2',
name: 'Node 2'
}]);
})
})
describe('nodes filter', () => {
it('should filter the nodes', () => {
let g = Graph.fromObject({
edges: [],
nodes: [{
name: 'California',
country: 'USA'
}, {
name: 'DC',
country: 'USA'
}, {
name: 'Sao Paulo',
country: 'Brazil'
}, {
name: 'Missouri',
country: 'USA'
}, {
name: 'Maranhao',
country: 'Brazil'
}]
})
let fromUS = g.nodes.filter(n => n.country === 'USA')
expect(fromUS.toObject().nodes).toContain({
name: 'California',
country: 'USA'
})
expect(fromUS.toObject().nodes).toContain({
name: 'DC',
country: 'USA'
})
expect(fromUS.toObject().nodes).toContain({
name: 'Missouri',
country: 'USA'
})
expect(fromUS.toObject().nodes).not.toContain({
name: 'Sao Paulo',
country: 'Brazil'
})
expect(fromUS.toObject().nodes).not.toContain({
name: 'Maranhao',
country: 'Brazil'
})
let startsWithM = g.nodes.filter(n => n.name[0] === 'M');
expect(startsWithM.toObject().nodes).not.toContain({
name: 'California',
country: 'USA'
})
expect(startsWithM.toObject().nodes).not.toContain({
name: 'DC',
country: 'USA'
})
expect(startsWithM.toObject().nodes).toContain({
name: 'Missouri',
country: 'USA'
})
expect(startsWithM.toObject().nodes).not.toContain({
name: 'Sao Paulo',
country: 'Brazil'
})
expect(startsWithM.toObject().nodes).toContain({
name: 'Maranhao',
country: 'Brazil'
})
})
})
describe('nodes forEach', () => {
it('should iterate on nodes', () => {
let arr = [
{id: 'abc'},
{id: 'def'},
{id: 'ghi'},
{id: 'jkl'}
];
let c = Graph.fromObject({
nodes: arr,
edges: []
});
c.nodes.forEach(item => {
let index = arr.findIndex(i => i.id === item.id);
arr.splice(arr.indexOf(item), 1);
})
expect(arr.length).toBe(0);
})
})
describe('nodes has', () => {
it('should return true when node exists', () => {
let g = Graph.fromObject({
edges: [],
nodes: [{
name: 'California',
country: 'USA'
}, {
name: 'DC',
country: 'USA'
}, {
name: 'Sao Paulo',
country: 'Brazil'
}, {
name: 'Missouri',
country: 'USA'
}, {
name: 'Maranhao',
country: 'Brazil'
}]
})
expect(g.nodes.has({
name: 'California',
country: 'USA'
})).toBe(true);
expect(g.nodes.has({
name: 'Florida',
country: 'USA'
})).toBe(false);
})
})
describe('nodes isEmpty', () => {
it('should return true when empty', () => {
let g = Graph.fromObject({
edges: [],
nodes: [{
name: 'California',
country: 'USA'
}, {
name: 'DC',
country: 'USA'
}]
})
expect(g.nodes.isEmpty()).toBe(false);
g = Graph.fromEmpty();
expect(g.nodes.isEmpty()).toBe(true);
})
})
describe('nodes getStartingNodes', () => {
it('should return nodes without incoming connections', () => {
let g = Graph.fromObject({
edges: [{
from: 1,
to: 2
}],
nodes: [{
id: 1
}, {
id: 2
}]
});
expect(g.nodes.getStartingNodes().toObject()).toEqual({
edges: [],
nodes: [{
id: 1
}]
})
g = Graph.fromObject({
edges: [{
from: 1,
to: 2
}, {
from: 2,
to: 1
}],
nodes: [{
id: 1
}, {
id: 2
}]
})
expect(g.nodes.getStartingNodes().toObject()).toEqual({
edges: [],
nodes: []
})
g = Graph.fromObject({
edges: [{
from: 1,
to: 2
}, {
from: 1,
to: 3
}],
nodes: [{
id: 1
}, {
id: 2
}, {
id: 3
}]
})
expect(g.nodes.getStartingNodes().toObject()).toEqual({
edges: [],
nodes: [{
id: 1
}]
})
g = Graph.fromObject({
edges: [{
from: 1,
to: 3
}, {
from: 2,
to: 3
}],
nodes: [{
id: 1
}, {
id: 2
}, {
id: 3
}]
})
let n = g.nodes.getStartingNodes().toObject().nodes;
expect(n).toContain({
id: 1
})
expect(n).toContain({
id: 2
})
})
})
describe('nodes topologicalSort', () => {
it('should return topological levels', () => {
let g = Graph.fromObject({
edges: [{
from: 1,
to: 2
}],
nodes: [{
id: 1
}, {
id: 2
}]
})
let toArray = (arr) => arr.map(l => l.toObject().nodes);
expect(toArray(g.nodes.topologicalSort())).toEqual([
[{id: 1}],
[{id: 2}]
])
g = Graph.fromObject({
edges: [{
from: 1,
to: 2
}, {
from: 2,
to: 3
}],
nodes: [{
id: 1
}, {
id: 2
}, {
id: 3
}]
})
expect(toArray(g.nodes.topologicalSort())).toEqual([
[{id: 1}],
[{id: 2}],
[{id: 3}]
])
g = Graph.fromObject({
edges: [{
from: 1,
to: 2
}, {
from: 1,
to: 3
}, {
from: 2,
to: 4
}, {
from: 3,
to: 4
}],
nodes: [{
id: 1
}, {
id: 2
}, {
id: 3
}, {
id: 4
}]
})
expect(toArray(g.nodes.topologicalSort())).toEqual([
[{id: 1}],
[{id: 3}, {id: 2}],
[{id: 4}]
])
})
})
describe('nodes difference', () => {
it('should return self if difference equals itself', () => {
let g = Graph.fromObject({
edges: [],
nodes: [{id: 5}, {id: 7}, {id: 8}, {id: 9}, {id: 12}]
}),
g2 = Graph.fromObject({
edges: [],
nodes: [{id: 89}, {id: 90}, {id: 8172}, {id: 123}]
}),
g3;
expect(() => g3 = g.nodes.difference(g2)).not.toThrow();
expect(g3).toBe(g);
g2 = Graph.fromObject({
edges: [],
nodes: [{id:5}]
});
expect(() => g3 = g.nodes.difference(g2)).not.toThrow();
expect(g3).not.toBe(g);
})
})
describe('nodes iterator', () => {
it('should provide items to for ... of loop', () => {
let g = Graph.fromObject({
edges: [],
nodes: [{id: 5}, {id: 7}, {id: 11}, {id: 13}, {id: 1}]
})
let s = 0;
for (let i of (g.nodes as any)){
s += i.id;
}
expect(s).toBe(37);
})
})
describe('edges iterator', () => {
it('should provide items to for ... of loop', () => {
let g = Graph.fromObject({
edges: [{
from: 0,
to: 0,
id: 5
}, {
id: 7,
from: 0,
to: 0
}, {
id: 11,
from: 0,
to: 0,
}, {
id: 13,
from: 0,
to: 0,
}, {
id: 1,
from: 0,
to: 0,
}],
nodes: []
})
let s = 0;
for (let i of (g.edges as any)){
s += i.id;
}
expect(s).toBe(37);
})
})
describe('edges fromId', () => {

@@ -444,2 +1048,166 @@ it('should return graph with edges from given node id', () => {

describe('edges add', () => {
it('should not allow existing edge to be re-added', () => {
let g = Graph.fromObject({
edges: [{
from: 0,
to: 1,
id: 987
}],
nodes: []
})
expect(() => g.edges.add({
from: 0,
to: 1,
id: 987
})).toThrowError(
`Could not add Edge to Graph: Edge already exists`
)
})
})
describe('edges size', () => {
it('should return size of collection', () => {
let g = Graph.fromObject({
edges: [{
from: 0,
to: 1,
id: 987
}],
nodes: []
})
expect(g.edges.size()).toEqual(1)
g = Graph.fromObject({
edges: [{
from: 0,
to: 1,
id: 987
}, {
from: 1,
to: 2,
id: 765
}],
nodes: []
})
expect(g.edges.size()).toEqual(2);
g = Graph.fromEmpty();
expect(g.edges.size()).toEqual(0);
})
})
describe('edges update', () => {
it('should throw error if edge does not exist', () => {
let g = Graph.fromEmpty();
expect(() => g.edges.update({
from: 0,
to: 1
})).toThrowError(
`Could not update Edge from Graph: Edge does not exist`
)
})
it('should update edge', () => {
let g = Graph.fromObject({
edges: [{
from: 0,
to: 1,
labels: []
}],
nodes: [{
name: 'abc'
}]
});
expect(() => g = g.edges.update({
from: 0,
to: 1,
labels: []
}, {
from: 1,
to: 2,
labels: ['TEST']
})).not.toThrow();
expect(g.toObject()).toEqual({
edges: [{
from: 1,
to: 2,
labels: ['TEST']
}],
nodes: [{
name: 'abc'
}]
})
})
})
describe('edges updateId', () => {
it('should throw error if edge does not exist', () => {
let g = Graph.fromEmpty();
expect(() => g.edges.updateId({
id: 'inexistent'
})).toThrowError(
`Could not update Edge from Graph: Edge does not exist`
)
})
it('should update edge', () => {
let edge = {
from: 0,
id: 'edge',
to: 1,
labels: []
}
let g = Graph.fromObject({
edges: [edge],
nodes: [{
name: 'abc'
}]
});
let g2;
expect(() => g2 = g.edges.updateId('edge', {
from: 1,
to: 2,
labels: ['TEST']
})).not.toThrow();
expect(g2.toObject()).toEqual({
edges: [{
from: 1,
to: 2,
labels: ['TEST']
}],
nodes: [{
name: 'abc'
}]
})
expect(g2).not.toBe(g);
})
it('should return self if there were no changes', () => {
let obj = {
from: 0,
id: 'edge',
to: 1,
labels: []
}
let g = Graph.fromObject({
edges: [obj],
nodes: [{
name: 'abc'
}]
});
let g2;
expect(() => g2 = g.edges.updateId('edge', {
from: 0,
id: 'edge',
to: 1,
labels: []
})).not.toThrow();
expect(g2).toBe(g);
})
})
describe('edges union', () => {

@@ -621,2 +1389,178 @@ it('should merge empty edges graph into new graph', () => {

describe('edges map', () => {
it('should map edges into new values', () => {
let g = Graph.fromObject({
edges: [{
from: 0,
to: 1,
id: '0-1'
}, {
from: 1,
to: 2,
id: '0-2'
}],
nodes: []
})
let newGraph = g.edges.map(i => ({
...i,
to: 3
}))
expect(newGraph.toObject().edges).toContain({
from: 0,
to: 3,
id: '0-1'
})
expect(newGraph.toObject().edges).toContain({
from: 1,
to: 3,
id: '0-2'
})
expect(newGraph.toObject().edges).not.toContain({
from: 0,
to: 1,
id: '0-1'
})
expect(newGraph.toObject().edges).not.toContain({
from: 0,
to: 2,
id: '0-2'
})
})
})
describe('edges filter', () => {
it('should filter the edges', () => {
let g = Graph.fromObject({
edges: [{
from: 0,
to: 0,
name: 'California',
country: 'USA'
}, {
from: 0,
to: 0,
name: 'DC',
country: 'USA'
}, {
from: 0,
to: 0,
name: 'Sao Paulo',
country: 'Brazil'
}, {
from: 0,
to: 0,
name: 'Missouri',
country: 'USA'
}, {
from: 0,
to: 0,
name: 'Maranhao',
country: 'Brazil'
}],
nodes: []
})
let fromUS = g.edges.filter(n => n.country === 'USA')
expect(fromUS.toObject().edges).toContain({
from: 0,
to: 0,
name: 'California',
country: 'USA'
})
expect(fromUS.toObject().edges).toContain({
from: 0,
to: 0,
name: 'DC',
country: 'USA'
})
expect(fromUS.toObject().edges).toContain({
from: 0,
to: 0,
name: 'Missouri',
country: 'USA'
})
expect(fromUS.toObject().edges).not.toContain({
from: 0,
to: 0,
name: 'Sao Paulo',
country: 'Brazil'
})
expect(fromUS.toObject().edges).not.toContain({
from: 0,
to: 0,
name: 'Maranhao',
country: 'Brazil'
})
let startsWithM = g.edges.filter(n => n.name[0] === 'M');
expect(startsWithM.toObject().edges).not.toContain({
from: 0,
to: 0,
name: 'California',
country: 'USA'
})
expect(startsWithM.toObject().edges).not.toContain({
from: 0,
to: 0,
name: 'DC',
country: 'USA'
})
expect(startsWithM.toObject().edges).toContain({
from: 0,
to: 0,
name: 'Missouri',
country: 'USA'
})
expect(startsWithM.toObject().edges).not.toContain({
from: 0,
to: 0,
name: 'Sao Paulo',
country: 'Brazil'
})
expect(startsWithM.toObject().edges).toContain({
from: 0,
to: 0,
name: 'Maranhao',
country: 'Brazil'
})
})
})
describe('edges removal', () => {
it('should throw error if edge does not exist', () => {
let g1;
let result;
expect(() => g1 = Graph.fromObject({
edges: [
{
from: 0,
to: 0,
name: 'Albus',
lastName: 'Dumbledore'
},
{
from: 0,
to: 0,
name: 'Lord',
lastName: 'Voldemort'
}
],
nodes: [
]
})).not.toThrow()
expect(() => result = g1.edges.remove({
name: 'Inexistent',
lastName: 'Node'
})).toThrowError(
`Could not remove Edge from Graph: Edge does not exist`
);
})
})
describe('union', () => {

@@ -724,2 +1668,51 @@ it('should merge 2 graphs into a new one', () => {

})
describe('edges getId', () => {
it ('should throw error if id does not exist', () => {
let g1;
let result;
expect(() => g1 = Graph.fromObject({
nodes: [],
edges: []
})).not.toThrow();
expect(() => result = g1.edges.getId('inexistentId')).toThrowError(
`Could not get Edge: Edge Id 'inexistentId' does not exist in Graph`
)
})
it ('should return an edge given its id', () => {
let g1;
let result;
expect(() => g1 = Graph.fromObject({
nodes: [
{
name: 'Lord',
lastName: 'Voldemort',
id: 'the-evil-one'
},
{
name: 'Harry',
lastName: 'Potter',
id: 'expelliarmus!'
}
],
edges: [{
from: 'expelliarmus',
to: 'the-evil-one',
labels: ['SURVIVED'],
id: 'edge'
}]
})).not.toThrow();
expect(() => result = g1.edges.getId('inexistentId')).toThrowError(
`Could not get Edge: Edge Id 'inexistentId' does not exist in Graph`
)
expect(() => result = g1.edges.getId('edge')).not.toThrow()
expect(result).toEqual({
from: 'expelliarmus',
to: 'the-evil-one',
labels: ['SURVIVED'],
id: 'edge'
})
})
})
})

@@ -42,9 +42,19 @@ import * as _ from 'lodash';

public static fromEmpty() {
return Graph.fromObject({
edges: [],
nodes: [],
});
}
/* TODO: add wrapper for bind functions */
public nodes = {
add: ((item: any) => {
/** Adds a new Node to the Graph.
* Will throw an error if Node already exists
*/
add: ((item: any): Graph => {
const {nodes, edges} = this.internal;
if (nodes.has(item)) {
throw new Error (
`Could not add Node from Graph: Node already exists`,
`Could not add Node to Graph: Node already exists`,
);

@@ -58,3 +68,6 @@ }

remove: ((item: any) => {
/** Removes a Node from the Graph.
* Will throw an error if Node does not exist in Graph
*/
remove: ((item: any): Graph => {
const {nodes, edges} = this.internal;

@@ -72,3 +85,7 @@ if (!nodes.has(item)) {

union : ((g2: Graph) => {
/**
* Adds Nodes Graphs and keeps Edges as is for "this" Graph
* If you would like to add Edges as well, please use Graph.union()
*/
union : ((g2: Graph): Graph => {
const {nodes, edges} = this.internal;

@@ -81,7 +98,13 @@ return new Graph({

getAll : (() => {
/** Returns Nodes as Collection Type instead of Graph */
getAll : ((): Collection => {
return this.internal.nodes;
}).bind(this),
update: ((item, newItem) => {
/** Update a Node from the Graph.
* This method will update only one matching Node.
* Query must be exactly equal to the Node. If you'd like to
* query only by "id" property, please use updateId()
*/
update: ((item, newItem): Graph => {
const {nodes, edges} = this.internal;

@@ -99,2 +122,13 @@ if (!nodes.has(item)) {

/** Check if a given item is contained in the Graph Nodes
* Query must be exactly equal to the Node. If you'd like to
* query only by "id" property, please use hasId()
*/
has: ((item): boolean => {
return this.internal.nodes.has(item);
}).bind(this),
/** Gets Node by querying its id
* If Node Id does not exist in Graph, will throw an error.
*/
getId : ((id: any) => {

@@ -111,2 +145,3 @@ const {nodes, edges} = this.internal;

/** Check if a given item id is contained in the Graph Nodes */
hasId : ((id: any) => {

@@ -118,4 +153,8 @@ const {nodes, edges} = this.internal;

/** Get one Node that contains an incoming edge from id supplied */
oneReachedById: ((id) => {
const edgesGraph = this.edges.fromId(id);
if (edgesGraph.edges.isEmpty()) {
return;
}
const edge = edgesGraph.edges.getAll().getOne();

@@ -125,2 +164,5 @@ return this.nodes.getId(edge.to);

/* Get all Nodes that contain an incoming edge from id supplied
* Return does not contain Edges
*/
reachedById: ((id) => {

@@ -138,2 +180,7 @@ const edgesGraph = this.edges.fromId(id);

/** Find Nodes that satisfy a given query. Exactly matches one-level-deep
* property indexes, such as "id".
* If you would like to run a complex query, please use filter() instead
* Return does not contain Edges.
*/
find: ((query) => {

@@ -147,2 +194,85 @@ const {nodes, edges} = this.internal;

/** Run a query function against all Nodes and return the ones that pass the test
* Return does not contain Edges
*/
filter: ((query) => {
const {nodes, edges} = this.internal;
return new Graph({
edges: Collection.fromArray([]),
nodes: nodes.filter(query),
});
}).bind(this),
/** Run a function against all Nodes */
forEach: ((fn) => {
const {nodes, edges} = this.internal;
nodes.forEach(fn);
}).bind(this),
/** Check whether Graph contains no Nodes */
isEmpty: (() => {
return this.internal.nodes.isEmpty();
}).bind(this),
/** Get all Nodes that do not have incoming edges
* Return does not contain edges
*/
getStartingNodes: (() => {
return this.nodes.filter((i) => {
return this.edges.findOne({
to: i.id,
}) === undefined;
});
}).bind(this),
/** Sort Nodes topologically.
* Return contains an Array of Graphs that do not contain Edges
*/
topologicalSort: (() => {
/* TODO: Add cycle detection */
const step = (graph, arr = []) => {
if (graph.nodes.isEmpty()) {
return arr;
}
/* Get Nodes without Incoming Edges - "Starting" nodes */
const levelNodes = graph.nodes.getStartingNodes();
/* Remove levelNodes from graph */
const graphWithoutLevelNodes = graph.nodes.difference(levelNodes);
/* Remove edges attached to removed nodes */
/* TODO: Abstract step into custom method */
const nodesCollection = Collection.fromArray(levelNodes.toObject().nodes);
let graphWithoutLevelEdges = graphWithoutLevelNodes;
nodesCollection.forEach((item) => {
graphWithoutLevelEdges = graphWithoutLevelEdges.edges.findAndDifference({
from: item.id,
});
});
return step(
graphWithoutLevelEdges,
[...arr, levelNodes],
);
};
return step(this);
}).bind(this),
/** Get the Nodes difference between two Graphs.
* Edges remain unaltered for "this" Graph
*/
difference: ((g2: Graph) => {
const {nodes, edges} = this.internal;
const result = nodes.difference(g2.nodes.getAll());
/* Performance optimization */
if (result === nodes) {
return this;
}
return new Graph({
edges,
nodes: result,
});
}).bind(this),
/** Iterator for Nodes. Can be used in for ... of loops, for example */
[Symbol.iterator]: (() => {

@@ -155,2 +285,6 @@ return this.internal.nodes[Symbol.iterator]();

public edges = {
/**
* Adds Edges Graphs and keeps Nodes as is for "this" Graph
* If you would like to add Nodes as well, please use Graph.union()
*/
union : ((g2: Graph) => {

@@ -164,2 +298,5 @@ const {nodes, edges} = this.internal;

/** Get the Edges difference between two Graphs.
* Nodes remain unaltered for "this" Graph
*/
difference: ((g2: Graph) => {

@@ -178,2 +315,5 @@ const {nodes, edges} = this.internal;

/** Maps Edges to a new Graph
* Resulting Graph keep Nodes unaltered
*/
map: ((fn) => {

@@ -188,2 +328,18 @@ const {nodes, edges} = this.internal;

/** Run a query function against all Edges and return the ones that pass the test
* Return does not contain Nodes
*/
filter: ((query) => {
const {nodes, edges} = this.internal;
return new Graph({
edges: edges.filter(query),
nodes: Collection.fromArray([]),
});
}).bind(this),
/** Find Edges that satisfy a given query. Exactly matches one-level-deep
* property indexes, such as "id".
* If you would like to run a complex query, please use filter() instead
* Return does not contain Nodes.
*/
find: ((query) => {

@@ -197,2 +353,3 @@ const {nodes, edges} = this.internal;

/** Shortcut method for piping Edges.find() => Edges.difference */
findAndDifference: ((query) => {

@@ -202,2 +359,3 @@ return this.edges.difference(this.edges.find(query));

/** Returns Edges as Collection Type instead of Graph */
getAll : (() => {

@@ -221,2 +379,5 @@ return this.internal.edges;

/** Removes an Edge from the Graph.
* Will throw an error if Edge does not exist in Graph
*/
remove: ((item: any) => {

@@ -235,2 +396,5 @@ const {nodes, edges} = this.internal;

/** Adds a new Edge to the Graph.
* Will throw an error if Edge already exists
*/
add: ((item: any) => {

@@ -249,2 +413,7 @@ const {nodes, edges} = this.internal;

/** Updates an Edge from the Graph.
* This method will update only one matching Edge.
* Query must be exactly equal to the Edge. If you'd like to
* query only by "id" property, please use updateId()
*/
update: ((item, newItem) => {

@@ -263,2 +432,3 @@ const {nodes, edges} = this.internal;

/** Updates an Edge from Graph by querying its id */
updateId: ((id, newItem) => {

@@ -272,2 +442,6 @@ const {nodes, edges} = this.internal;

}
/* Performance improvement */
if (SSet.hashOf(item) === SSet.hashOf(newItem)) {
return this;
}
return new Graph({

@@ -279,2 +453,3 @@ edges: edges.remove(item).add(newItem),

/** Checks whether id is contained in Graph Edges */
hasId : ((id: any) => {

@@ -286,2 +461,5 @@ const {nodes, edges} = this.internal;

/** Gets All Edges that have "from" property set to given id
* Return does not contain Nodes
*/
fromId: ((from) => {

@@ -295,2 +473,3 @@ const {nodes, edges} = this.internal;

/** Iterator for Edges. Can be used in for ... of loops, for example */
[Symbol.iterator]: (() => {

@@ -300,2 +479,3 @@ return this.internal.edges[Symbol.iterator]();

/** Finds one item in Edges that satifies the query provided */
findOne: ((query) => {

@@ -306,2 +486,26 @@ const {nodes, edges} = this.internal;

/** Gets the number of Edges in the Graph */
size: (() => {
return this.internal.edges.size();
}).bind(this),
/** Check whether Graph contains no Edges */
isEmpty: (() => {
return this.internal.edges.isEmpty();
}).bind(this),
/** Gets Edge by querying its id
* If Edge Id does not exist in Graph, will throw an error.
*/
getId : ((id: any) => {
const {edges} = this.internal;
const maybeEdge = edges.findOne({id});
if (_.isUndefined(maybeEdge)) {
throw new Error (
`Could not get Edge: Edge Id '${id}' does not exist in Graph`,
);
}
return maybeEdge;
}).bind(this),
/* TODO: Follow up method, used for Tree Graphs.

@@ -308,0 +512,0 @@ Starting from a given node, will return the path order */

@@ -141,7 +141,6 @@ import _ = require('lodash');

let result;
for (const key in state) {
if (!state.hasOwnProperty(key)) { continue; }
_.forEach(state, (value, key) => {
result = key;
break;
}
return false;
});
return result;

@@ -148,0 +147,0 @@ }

@@ -20,4 +20,3 @@ {

],
"downlevelIteration": true,
"outDir": "build"
"downlevelIteration": true
},

@@ -24,0 +23,0 @@ "files": [

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc