UNPKG

4.18 kBJavaScriptView Raw
1
2var Type = require('./type');
3var Val = require('./val');
4var Node = require('./node');
5var Graph = {};
6;(function(){
7 Graph.is = function(g, cb, fn, as){ // checks to see if an object is a valid graph.
8 if(!g || !obj_is(g) || obj_empty(g)){ return false } // must be an object.
9 return !obj_map(g, map, {cb:cb,fn:fn,as:as}); // makes sure it wasn't an empty object.
10 }
11 function map(n, s){ // we invert this because the way we check for this is via a negation.
12 if(!n || s !== Node.soul(n) || !Node.is(n, this.fn)){ return true } // it is true that this is an invalid graph.
13 if(!this.cb){ return }
14 nf.n = n; nf.as = this.as; // sequential race conditions aren't races.
15 this.cb.call(nf.as, n, s, nf);
16 }
17 function nf(fn){ // optional callback for each node.
18 if(fn){ Node.is(nf.n, fn, nf.as) } // where we then have an optional callback for each field/value.
19 }
20}());
21;(function(){
22 Graph.ify = function(obj, env, as){
23 var at = {path: [], obj: obj};
24 if(!env){
25 env = {};
26 } else
27 if(typeof env === 'string'){
28 env = {soul: env};
29 } else
30 if(env instanceof Function){
31 env.map = env;
32 }
33 if(env.soul){
34 at.rel = Val.rel.ify(env.soul);
35 }
36 env.graph = env.graph || {};
37 env.seen = env.seen || [];
38 env.as = env.as || as;
39 node(env, at);
40 env.root = at.node;
41 return env.graph;
42 }
43 function node(env, at){ var tmp;
44 if(tmp = seen(env, at)){ return tmp }
45 at.env = env;
46 at.soul = soul;
47 if(Node.ify(at.obj, map, at)){
48 //at.rel = at.rel || Val.rel.ify(Node.soul(at.node));
49 env.graph[Val.rel.is(at.rel)] = at.node;
50 }
51 return at;
52 }
53 function map(v,f,n){
54 var at = this, env = at.env, is, tmp;
55 if(Node._ === f && obj_has(v,Val.rel._)){
56 return n._; // TODO: Bug?
57 }
58 if(!(is = valid(v,f,n, at,env))){ return }
59 if(!f){
60 at.node = at.node || n || {};
61 if(obj_has(v, Node._)){
62 at.node._ = obj_copy(v._);
63 }
64 at.node = Node.soul.ify(at.node, Val.rel.is(at.rel));
65 at.rel = at.rel || Val.rel.ify(Node.soul(at.node));
66 }
67 if(tmp = env.map){
68 tmp.call(env.as || {}, v,f,n, at);
69 if(obj_has(n,f)){
70 v = n[f];
71 if(u === v){
72 obj_del(n, f);
73 return;
74 }
75 if(!(is = valid(v,f,n, at,env))){ return }
76 }
77 }
78 if(!f){ return at.node }
79 if(true === is){
80 return v;
81 }
82 tmp = node(env, {obj: v, path: at.path.concat(f)});
83 if(!tmp.node){ return }
84 return tmp.rel; //{'#': Node.soul(tmp.node)};
85 }
86 function soul(id){ var at = this;
87 var prev = Val.rel.is(at.rel), graph = at.env.graph;
88 at.rel = at.rel || Val.rel.ify(id);
89 at.rel[Val.rel._] = id;
90 if(at.node && at.node[Node._]){
91 at.node[Node._][Val.rel._] = id;
92 }
93 if(obj_has(graph, prev)){
94 graph[id] = graph[prev];
95 obj_del(graph, prev);
96 }
97 }
98 function valid(v,f,n, at,env){ var tmp;
99 if(Val.is(v)){ return true }
100 if(obj_is(v)){ return 1 }
101 if(tmp = env.invalid){
102 v = tmp.call(env.as || {}, v,f,n);
103 return valid(v,f,n, at,env);
104 }
105 env.err = "Invalid value at '" + at.path.concat(f).join('.') + "'!";
106 }
107 function seen(env, at){
108 var arr = env.seen, i = arr.length, has;
109 while(i--){ has = arr[i];
110 if(at.obj === has.obj){ return has }
111 }
112 arr.push(at);
113 }
114}());
115Graph.node = function(node){
116 var soul = Node.soul(node);
117 if(!soul){ return }
118 return obj_put({}, soul, node);
119}
120;(function(){
121 Graph.to = function(graph, root, opt){
122 if(!graph){ return }
123 var obj = {};
124 opt = opt || {seen: {}};
125 obj_map(graph[root], map, {obj:obj, graph: graph, opt: opt});
126 return obj;
127 }
128 function map(v,f){ var tmp, obj;
129 if(Node._ === f){
130 if(obj_empty(v, Val.rel._)){
131 return;
132 }
133 this.obj[f] = obj_copy(v);
134 return;
135 }
136 if(!(tmp = Val.rel.is(v))){
137 this.obj[f] = v;
138 return;
139 }
140 if(obj = this.opt.seen[tmp]){
141 this.obj[f] = obj;
142 return;
143 }
144 this.obj[f] = this.opt.seen[tmp] = Graph.to(this.graph, tmp, this.opt);
145 }
146}());
147var fn_is = Type.fn.is;
148var obj = Type.obj, obj_is = obj.is, obj_del = obj.del, obj_has = obj.has, obj_empty = obj.empty, obj_put = obj.put, obj_map = obj.map, obj_copy = obj.copy;
149var u;
150module.exports = Graph;
151
\No newline at end of file