1 |
|
2 | var Type = require('./type');
|
3 | var Val = require('./val');
|
4 | var Node = require('./node');
|
5 | var Graph = {};
|
6 | ;(function(){
|
7 | Graph.is = function(g, cb, fn, as){
|
8 | if(!g || !obj_is(g) || obj_empty(g)){ return false }
|
9 | return !obj_map(g, map, {cb:cb,fn:fn,as:as});
|
10 | }
|
11 | function map(n, s){
|
12 | if(!n || s !== Node.soul(n) || !Node.is(n, this.fn)){ return true }
|
13 | if(!this.cb){ return }
|
14 | nf.n = n; nf.as = this.as;
|
15 | this.cb.call(nf.as, n, s, nf);
|
16 | }
|
17 | function nf(fn){
|
18 | if(fn){ Node.is(nf.n, fn, nf.as) }
|
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 |
|
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._;
|
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;
|
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 | }());
|
115 | Graph.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 | }());
|
147 | var fn_is = Type.fn.is;
|
148 | var 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;
|
149 | var u;
|
150 | module.exports = Graph;
|
151 | |
\ | No newline at end of file |