Merge branch 'master' of http://git.roojs.com/roobuilder
[roobuilder] / tools / flutter_sqlite.php
1 <?php
2 /*
3  * files parsed from
4  * https://master-api.flutter.dev/offline/flutter.xml
5  
6  FIXMES
7  -- contructor with generic eg. const AlwaysStoppedAnimation<T>(
8  -- classes - we need to parse the right hand column to determine which properties/ methods  are static..
9  -- enums have methods !! 
10  -- types on topLevelconstants are broken (might be able to extract it from the implementation.)
11  -- parse packages on left, and create fake libraries for them...
12  */
13
14 class fsql {
15     var $pdo;
16     function __construct()
17     {
18         $this->opendb();
19         $this->create();
20     }
21     function opendb() {
22         $this->pdo = new PDO("sqlite:". TDIR . "doc.db");
23         $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
24       
25     }
26     function create()
27     {
28         $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
29
30         $this->pdo->exec("
31               CREATE TABLE IF NOT EXISTS node (
32                     id INTEGER PRIMARY KEY AUTOINCREMENT,
33
34                     href VARCHAR (255) NOT NULL DEFAULT '',
35                     name VARCHAR (255) NOT NULL DEFAULT '',
36                     type VARCHAR (32) NOT NULL DEFAULT '',
37                     overriddenDepth INTEGER NOT NULL DEFAULT '',
38                     qualifiedName VARCHAR (255) NOT NULL DEFAULT '',
39                     enclosedBy_name VARCHAR (255) NOT NULL DEFAULT '',
40                     enclosedBy_type VARCHAR (16) NOT NULL DEFAULT '',
41                     -- derived data / html extracted...
42                     
43                     memberOf            VARCHAR (255) NOT NULL DEFAULT '',
44                     is_constructor      INTEGER NOT NULL DEFAULT 0,
45                     is_static           INTEGER NOT NULL DEFAULT 0,
46                    
47                     example TEXT,
48                     desc TEXT,
49                     
50                     is_fake_namespace  INTEGER NOT NULL DEFAULT 0,
51                     is_mixin            INTEGER NOT NULL DEFAULT 0,
52                     is_enum             INTEGER NOT NULL DEFAULT 0,
53                     is_typedef          INTEGER NOT NULL DEFAULT 0,
54                     is_constant         INTEGER NOT NULL DEFAULT 0,
55                     is_abstract         INTEGER NOT NULL DEFAULT 0,
56                     parent_id           INTEGER NOT NULL DEFAULT 0,
57                     
58                     extends VARCHAR(255)  NOT NULL DEFAULT ''
59                     
60                 );
61                     
62         ");
63          
64         $this->pdo->exec("ALTER TABLE node ADD COLUMN         is_deprecated INTEGER NOT NULL DEFAULT 0");
65         // deals with param type or return type.
66         $this->pdo->exec("ALTER TABLE node ADD COLUMN         value_type VARCHAR (255) NOT NULL DEFAULT ''");
67         // for params
68         $this->pdo->exec("ALTER TABLE node ADD COLUMN         sequence_no INTEGER NOT NULL DEFAULT 0");
69          
70         $this->pdo->exec("create index lookup on node(name,qualifiedName,parent_id,type)");
71          
72         $this->pdo->exec("
73             CREATE TABLE IF NOT EXISTS extends (
74                 id INTEGER PRIMARY KEY AUTOINCREMENT,
75                 class_id INTEGER NOT NULL DEFAULT 0,
76                 extends_id INTEGER NOT NULL DEFAULT 0
77             );
78         ");
79          
80         $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
81         
82         
83         
84         
85     }
86     function fixParents()
87     {
88         echo "Grouping properties/methods with parents\n";
89         $this->pdo->exec("
90             UPDATE
91                 node as cn 
92               set
93                 parent_id = coalesce((
94                   SELECT 
95                     id
96                   FROM
97                     node as pn 
98                   where 
99                           pn.qualifiedName = substr(cn.qualifiedName, 0, length(cn.qualifiedName) - length(cn.name)) 
100                     AND
101                     pn.type = 'class'
102                   ),0) where
103                   enclosedBy_type ='class'
104                   and parent_id = 0
105         ");
106     }
107     
108     function get($k,$v)
109     {
110         //print_R(array($k,$v));
111         $s = $this->pdo->prepare("SELECT * FROM node where $k=?");
112         $s->execute(array($v));
113         $r = $s->fetchAll(PDO::FETCH_ASSOC);
114          
115         if (count($r) != 1) {
116             print_R(array($k,$v,$r));
117             throw new Exception("not 1 record when searching");
118         }
119         return $r[0];
120     }
121     function lookup($k,$v)
122     {
123         //print_R(array($k,$v));
124         $s = $this->pdo->prepare("SELECT id FROM node where $k=?");
125         $s->execute(array($v));
126         $r = $s->fetchAll(PDO::FETCH_ASSOC);
127         //print_R($r);
128         if (count($r) > 1) {
129             print_R(array($k,$v,$r));
130             die("more than one record when calling lookup");
131         }
132         return $r ? $r[0]['id'] : 0;
133     }
134     
135     function addExtends($class_id , $extends_id)
136     {
137         $s = $this->pdo->prepare("SELECT id FROM extends where class_id=? AND extends_id=?");
138         $s->execute(array($class_id , $extends_id));
139         if ($s->fetchAll(PDO::FETCH_ASSOC)) {
140             return;
141         }
142         $s = $this->pdo->prepare("INSERT INTO extends (class_id, extends_id) VALUES (?,?)");
143         $s->execute(array($class_id , $extends_id));
144         
145         
146     }
147     
148     function update($id, $o)
149     {
150         if (empty($o)) {
151             return;
152         }
153         //echo "UPDATE";print_r($o);
154         foreach((array) $o as $k=>$v) {
155             if (is_a($v,'stdClass')) {
156                 foreach((array)$v as $ik  => $iv) {
157                     $kk[] = $k . '_' . $ik;
158                     $vv[] = '?';
159                     $vvv[] = $iv;
160                     $kv[]="{$k}_{$ik}=?";
161                 }
162                 continue;
163             }
164             $kk[] = $k;
165             $vv[] = '?';
166             $vvv[] = $v;
167             $kv[]="{$k}=?";
168         }
169         if (!$id) {
170             $s = $this->pdo->prepare("INSERT INTO node (".
171                 implode(',',$kk) . ") VALUES (".
172                 implode(',',$vv) . ")");
173           //  var_dump($s);
174             $s->execute($vvv);
175             return;
176         }
177         $s = $this->pdo->prepare("UPDATE node SET ".
178                 implode(',',$kv) . " WHERE id = $id");
179         $s->execute($vvv);
180     }
181     
182     
183     
184     
185     function fromIndex($o)
186     {
187         $id = $this->lookup('href', $o->href);
188         $this->update($id, $o);
189         
190     }
191     function parseIndex()
192     {
193         
194         $this->pdo = null;
195         if (file_exists(TDIR. 'docs.db')) {
196             unlink(TDIR.'docs.db');
197         }
198         $this->opendb();
199         $js = json_decode(file_get_contents(FDIR.'index.json'));
200         foreach($js as $o) {
201             $this->fromIndex($o);
202         }
203         $sq->fixParents();
204     }
205     function readDom($url)
206     {
207         $dom = new DomDocument();
208         libxml_use_internal_errors(true);
209         echo "Reading : {$url}\n";
210         $dom->loadHTMLFile(FDIR . $url);
211         libxml_clear_errors();
212         $xp = new DomXPath($dom);
213         
214         return $dom;
215     }
216     function getElementsByClassName($dom, $class, $node = null)
217     {
218         $xp = new DomXPath($dom);
219         return $xp->query("//*[contains(concat(' ', @class, ' '), ' ".$class." ')]", $node);
220     }
221     function innerHTML($node)
222     {
223         if (!$node) {
224             print_r($this); 
225         }
226         $dom= $node->ownerDocument;
227         $ret = '';
228         foreach ($node->childNodes as $child) 
229         { 
230             $ret.= $dom->saveHTML($child);
231         }
232         return $ret;
233         
234     }
235     function readDesc($dom, $id)
236     {
237         $array = array();
238         $desc = $this->getElementsByClassName($dom, 'desc');
239         if ($desc->length) {
240             $array['desc'] = $this->innerHTML($desc->item(0));
241         }
242         $sc = $this->getElementsByClassName($dom, 'source-code');
243         if ($sc->length) {
244             $array['example'] = $this->innerHTML($sc->item(0));
245         }
246         $this->update($id, $array);
247         
248     }
249     function readClassData($dom, $id)
250     {
251         $ar = array();
252         $sc = $this->getElementsByClassName($dom,'self-crumb');
253
254         if ($sc->length) {
255             // abstracts actually impletment stuff in flutter...
256             if (preg_match('/abstract class/', $this->innerHTML($sc->item(0)))) {
257                 $ar['is_abstract'] = 1;
258             }
259         }
260         $this->update($id, $ar);
261         $dl = $dom->getElementsByTagName('dl')->item(0);
262         if ($dl->getAttribute('class') != 'dl-horizontal') {
263              return;
264         }
265         if (strpos($this->innerHTML($dl), '@deprecated')) {
266             $ar['is_deprecated'] = 1;
267             $this->update($id, $ar);
268         }
269         $dt = $dl->getElementsByTagName('dt');
270         if (!$dt->length || $this->innerHTML($dt->item(0)) != 'Inheritance') {
271             return;
272         }
273         $dd = $dl->getElementsByTagName('dd');
274         if (!$dd->length) {
275             return;
276         }
277         
278         $as = $dd->item(0)->getElementsByTagName('a');
279         $extends = array();        
280         for($i = $as->length-1;$i > -1; $i--) {
281
282             $ex = $this->get('href', $as->item($i)->getAttribute('href'));
283             if (!$ex) {
284                 die("could not find " . $as->item($i)->getAttribute('href') . " when parsing" . $id);
285             }
286             if (empty($ex['qualifiedName'])) {
287                 
288                 print_r($ex);die("missing qualifiedName");
289             }
290             $this->addExtends($id, $ex['id']);
291             $extends[] = $ex['qualifiedName'];
292             
293         }
294         $ar['extends'] = implode(',', $extends);
295         $this->update($id, $ar);
296         //print_r(array($extends, $id));exit;
297         
298     }
299     
300     function readReturnType($dom, $id)
301     {
302         
303         $sp = $this->getElementsByClassName($dom,'returntype')->item(0);
304         $vt = $this->readTypeToString($sp);
305         $this->update($id, array('value_type' => $vt));
306         
307         
308     }
309     function readSignature($dom, $id)
310     {
311         // simple type:
312         // String
313         // complex type
314         // List<Widget> ... --- List -> generic type = Widget
315         // let's start by just storing the values.
316         // in where? -
317         /*
318          * node
319          *    type='param'
320          *    href='';
321          *    parent_id
322          *
323          */
324         
325          $parent = $this->get('id',$id);
326         $ar = $this->getElementsByClassName($dom,'parameter');
327         for($i =0;$i<$ar->length;$i++) {
328             // paramenters are used where methods return callbacks with their own params..
329             if ($ar->item($i)->parentNode->getAttribute('class') == 'signature') {
330                 continue;
331             }
332             $this->readParam( $id,  $ar->item($i) ,  $parent['qualifiedName'] .'.param');
333         }   
334         return $dom;
335         
336     }
337     
338     function readParam($id, $node, $prefix)
339     {
340         $ar  = $node->getElementsByTagName('span');
341         if (!$ar->length) {
342             echo $this->innerHTML($node);
343             die("mssing paramter info");
344         }
345        
346         $o = array(
347             'type' => 'param',
348             'parent_id' => $id,
349             'href' => '',
350             
351         );
352         $seq = 1;
353         for($i = 0; $i < $ar->length; $i++) {
354             
355             switch($ar->item($i)->getAttribute('class')) {
356                 
357                 case 'parameter-name':
358                     $o['name'] = $ar->item($i)->textContent;
359                     $o['sequence_no'] = $seq++;
360                     $o['qualifiedName' ] = $prefix . '.'. $o['name'] ;
361                     break;
362                 
363                 case 'type-annotation':
364                     
365                     $o['value_type'] = $this->readTypeToString($ar->item($i) );
366                     break;
367                 
368             }
369         }
370         if (empty($o['qualifiedName' ])) {
371             $out = $this->get('id', $id);
372             print_r($out);
373             die("missing paramenter name onn this page:" .$out['href']);
374             
375         }
376         
377         $id = $this->lookup('qualifiedName',$o['qualifiedName' ] );
378         $this->update($id,$o);
379         
380     }
381    
382     function readTypeToString($sp)
383     {
384         if (!$sp) {
385             print_R($this);
386             die("readTypeToString got invalid value");
387             
388         }
389         $type = '';
390         $ar = $sp->getElementsByTagName('a');
391         if (!$ar->length) {
392             return '<'. $sp->textContent .'>'; // guessing these are generics..
393         }
394         if ($ar->length == 1) {
395             $rt = $this->get('href',$ar->item(0)->getAttribute('href'));
396             return  $rt['qualifiedName'];
397         } 
398         $types = array();
399         $t = '';
400         for($i =0;$i<$ar->length;$i++) {
401             $rt = $this->get('href',$ar->item($i)->getAttribute('href'));
402             
403             $types[] = $rt['qualifiedName'];
404              
405             //$t .= ($i == 0) ? $rt['qualifiedName'];: ('<'. $rt['qualifiedName'];);
406              
407         }
408         //for($i =0;$i<$ar->length-1;$i++) {
409         //    $t .= '>';
410        // }
411         return implode(',', $types);
412         
413          
414         
415     }
416     
417     var $blacklist = array(
418         'dart-io/HttpOverrides/runZoned.html', // very complex method call - object with callbacks..
419         'dart-io/IOOverrides/runZoned.html',// insanly complex method call - object with callbacks..
420         'dart-async/StreamTransformer/StreamTransformer.fromBind.html', // complex ctor
421     );
422     
423     function parse($type)
424     {
425         echo "Parse $type\n";
426         $s = $this->pdo->prepare("SELECT * FROM node  WHERE type = ?");
427         $s->execute(array($type));
428         $res = $s->fetchAll(PDO::FETCH_ASSOC);
429         foreach($res as $r) {
430             if (in_array($r['href'], $this->blacklist)) {
431                 continue;
432             }
433             $m  = "parse".preg_replace('/[^A-Z]/i', '', $type);
434             $this->$m($r);
435         }
436         
437     }
438     function parseClass($o)
439     {
440         $d = $this->readDom($o['href']);
441         $this->readDesc($d,$o['id']);
442         $this->readClassData($d,$o['id']);
443         
444     }
445     
446     function parseConstructor($o)
447     {
448         $d = $this->readDom($o['href']);
449         $this->readDesc($d,$o['id']);
450         $this->readSignature($d,$o['id']);
451     }
452     function parseMethod($o)
453     {
454         $d = $this->readDom($o['href']);
455         $this->readDesc($d,$o['id']);
456         $this->readReturnType($d,$o['id']);        
457         $this->readSignature($d,$o['id']);
458     }
459     function parseProperty($o)
460     {
461         $d = $this->readDom($o['href']);
462         $this->readDesc($d,$o['id']);
463         $this->readReturnType($d,$o['id']);        
464
465     }
466     function parseEnum($o)
467     {
468         $d = $this->readDom($o['href']);
469         $this->readDesc($d,$o['id']);
470         //$this->readReturnType($d,$o['id']);
471         $ct = $d->getElementById('constants');
472         $props = $this->getElementsByClassName($ct->ownerDocument,'properties',$ct)->item(0);
473         //echo $this->innerHTML($props);
474         for($i = 0; $i< $props->childNodes->length; $i++) {
475             $cn  = $props->childNodes->item($i);
476             //var_dump($cn->nodeName);
477             switch($cn->nodeName) {
478                 case 'dt': // look for name
479                     
480                     $name = $cn->getElementsByTagName('span')->item(0)->textContent; //$this->getElementsByClassName($cn->ownerDocument,'name',$cn)->item(0)->textContent;
481                     //var_Dump($name);
482                     $n = array(
483                         'type' => 'enum-value',
484                         'parent_id' => $o['id'],
485                         'qualifiedName' => $o['qualifiedName'] .'.' . $name,
486                         'name' => $name,
487                         // enclosed by?? - leave?
488                     );
489                     
490                     break;
491                 case 'dd': // the description
492                     //print_r($n);
493                     $n['desc']  =  $this->innerHTML($cn);
494                     
495                     $id = $this->lookup('qualifiedName', $n['qualifiedName']);
496                     if (!strlen(trim($n['name']))) {
497                         break;
498                     }
499                     $this->update($id, $n);
500                     //print_r($n);
501                     break;
502             }
503              
504         }
505         // we ignore methods???
506         //exit;
507         
508
509     }
510     function parseMixin($o)
511     {
512         // oddly enough mixin's have ctors???
513         $d = $this->readDom($o['href']);
514         $this->readDesc($d,$o['id']);
515         // methods and props should be handled ok anyway.. 
516         
517         //print_R($o);exit;
518         
519     }
520     function parsetypeDef($o)
521     {
522         // these appear to be function signatures really.
523         $d = $this->readDom($o['href']);
524         $this->readDesc($d,$o['id']);
525         // methods and props should be handled ok anyway.. 
526         
527         //print_R($o);exit;
528         
529     }
530     function parseConstant($o)
531     {
532         // these appear to be function signatures really.
533         $d = $this->readDom($o['href']);
534         $this->readDesc($d,$o['id']);
535         // methods and props should be handled ok anyway.. 
536         $this->readReturnType($d,$o['id']);  
537       
538         
539     }
540     
541     function parseTopLevelConstant($o)
542     {
543         
544        
545         // these appear to be function signatures really.
546         $d = $this->readDom($o['href']);
547         $this->readDesc($d,$o['id']);
548         // methods and props should be handled ok anyway.. 
549         //$this->readReturnType($d,$o['id']);  
550       
551     }
552     function parseTopLevelProperty($o)
553     {
554         
555         //print_r($o);exit;
556         // aliases to pre-created classes...
557         $d = $this->readDom($o['href']);
558         $this->readDesc($d,$o['id']);
559         // methods and props should be handled ok anyway.. 
560         $this->readReturnType($d,$o['id']);  
561       
562     }
563     function parseFunction($o)
564     {
565         
566       //  print_r($o);exit;
567         // these appear to be function signatures really.
568         $d = $this->readDom($o['href']);
569         $this->readDesc($d,$o['id']);
570         // methods and props should be handled ok anyway.. 
571         $this->readReturnType($d,$o['id']);
572         $this->readSignature($d,$o['id']);
573       
574         
575     }
576     /* ----------------------------- OUTPUT -----------------------------*/
577     
578     function outImplementorsToArray($id)
579     {
580         $res = $this->pdo->query("
581             SELECT
582                     qualifiedName
583                 FROM
584                     node
585                 where
586                     id IN (SELECT distinct(class_id) FROM extends WHERE extends_id = {$id})
587                 AND
588                     is_abstract = 0
589                 order by
590                     qualifiedName ASC
591         ");
592         return  $res->fetchAll(PDO::FETCH_COLUMN);
593     }
594     
595     function outTree()
596     {
597         ///make a tree of the classes, and collapse the classes that have same prefix into the prefix.
598         echo "Creating Tree.json\n";
599         // our tree should only include classes (non-abstract), and namespaces
600         $res = $this->pdo->query("
601             SELECT
602                     id,
603                     qualifiedName as name,
604                     qualifiedName,
605                     type,
606                     CASE WHEN type != 'library'  THEN 1 ELSE 0 END AS is_class,
607                     is_abstract,
608                     extends 
609                 from
610                     node
611                 where
612                     type IN ('class', 'library', 'enum', 'mixin')
613                 
614                 order by
615                     qualifiedName ASC
616         ");
617         $all = $res->fetchAll(PDO::FETCH_ASSOC);
618         $stack = array();
619         $nsmap = array();
620         foreach($all as $o) {
621             $add = (object) $o;
622             $add->cn = array();
623             $add->is_class = $add->is_class == 1;
624             unset($add->id);
625             $add->extends = strlen($add->extends) ? explode(',',$add->extends) : array();
626             if ($o['type'] == 'library') {
627                  
628                 $out[] = $add;
629                 $stack = array($add);
630                 continue;
631             }
632             
633             $add->implementors  = $this->outImplementorsToArray($o['id']);
634             
635             // find if the element has a child or children...
636             // this is not really where this should go.. but we will add it for the time being.
637             
638             
639             $res = $this->pdo->query("
640                 SELECT
641                         name, value_type
642                     FROM
643                         node
644                     where
645                         (
646                             parent_id = {$o['id']}
647                             OR
648                             parent_id IN (SELECT distinct(class_id) FROM extends WHERE extends_id = {$o['id']})
649                         )
650                     AND
651                         type = 'property'
652                     AND
653                         name IN ('child','children','home', 'body')
654                     order by
655                         name ASC
656                     limit 1
657             "); 
658             $types = $res->fetch(PDO::FETCH_ASSOC);
659             $add->childtype = '';
660             $add->childtypes = '0';
661             if ($types) {
662                 $car = explode(',', $types['value_type']);
663                 $add->childtype = array_pop($car);
664                 $add->childtypes = (count($car) && $car[0] == 'date:core.List') ? 2 : 1;
665             }
666             
667             
668             //echo "looking for " .$o['qualifiedName'];             print_R($stack);
669             for($i = count($stack)-1; $i > -1; $i--) {
670                 $last = $stack[$i];
671                 //print_r(array( substr($o['qualifiedName'], 0, strlen($last->qualifiedName)), $last->qualifiedName));
672                 if (substr($add->qualifiedName, 0, strlen($last->qualifiedName)) == $last->qualifiedName) {
673                     $last->cn[] = $add;
674                     $stack[$i+1] = $add;
675                     break;
676                 }
677                  
678                 
679             }
680         }
681         $libs = array();
682         foreach($out as $c) {
683             $this->outTreeGroups($c);
684             $bits = explode(".", $c->qualifiedName);
685             if (count($bits)< 2 || !isset($libs[$bits[0]])) {
686                 $libs[$c->qualifiedName]  = $c;
687                 continue;
688             }
689             $libs[$bits[0]]->cn[] = $c;
690         }
691         
692         $out = array_values($libs);
693         echo "WRITE: " .TDIR ."tree.json\n";
694         file_put_contents(TDIR .'tree.json', json_encode($out, JSON_PRETTY_PRINT));
695
696         //print_r($out);
697         
698         
699         
700     }
701     function outTreeGroups($obj)
702     {
703         $groups= array();
704         $libs = array();
705         foreach($obj->cn as $c) {
706             
707             $name = substr($c->qualifiedName, strlen($obj->qualifiedName) +1);
708             $bits = preg_split('/(?<=[a-z])(?=[A-Z])|(?=[A-Z][a-z])/',
709                                  $name, -1, PREG_SPLIT_NO_EMPTY);
710             if (!isset($groups[$bits[0]])) {
711                 $groups[$bits[0]] = array();
712             }
713             $groups[$bits[0]][] = $c;
714         }
715         $obj->cn = $libs;
716         foreach($groups as $k => $list) {
717             if (count($list) < 2) {
718                 $obj->cn[] = $list[0];
719                 continue;
720             }
721             $obj->cn[] = (object) array(
722                 'name' => $obj->qualifiedName .'.' . $k,
723                 'qualifiedName' => $obj->qualifiedName .'.' . $k,
724                 'cn' => $list,
725                 'is_class' => 'false',
726                 'type' => 'group',
727             );
728         }
729         
730     }
731     
732     function typeStringToGeneric($str)
733     {
734         $bits = explode(',', $str);
735         if (count($bits) < 2) {
736             return $str;
737         }
738         $t = '';
739         foreach($bits as $i => $add) {
740             $t .= ($i == 0) ? $add : ('<'. $add );
741              
742         }
743         for($i =0;$i<count($bits)-1;$i++) {
744             $t .= '>';
745         }
746         return $t;
747     }
748     
749      
750     function outClassSymbols()
751     {
752         echo "Writing Class Symbols\n";
753         $res = $this->pdo->query("
754             SELECT
755                     id,
756                     COALESCE(desc, '') as desc,
757                     type as dtype,
758                     COALESCE(example, '') as example,
759                     href,
760                     is_abstract as isAbstract,
761                     false as isConstant,
762                     is_deprecated as isDeprecated,
763                      
764                     enclosedBy_name as memberOf,
765                     qualifiedName as name,
766                     name as shortname,
767                     extends
768                 from
769                     node
770                 where
771                     type IN ('class', 'mixin', 'enum')
772                 
773                 order by
774                     qualifiedName ASC
775         ");
776         $all = $res->fetchAll(PDO::FETCH_ASSOC);
777         $ns = array();
778         foreach($all as $clsar) {
779             $cls = (object) $clsar;
780             unset($cls->id);
781             
782             if (!isset($ns[$cls->memberOf])) {
783                 $ns[$cls->memberOf] = (object) array(
784                     'class' => array(),
785                     'mixin' => array(),
786                     //'constants' => array(), // within a class.. - we could treat as static properties..
787                     'enum' => array(),  // like a class...
788                     'typedef' => array(), // need to query these seperatly... -- look very different to classes..
789                     // functions (within a library... )
790                     // top level constant? (within a library - without a class)
791                     // top level proeprty? (predefined instances of clases) - within a library
792                 );
793             }
794             
795             $cls->isConstant = $cls->isConstant == 1;
796
797             $cls->isAbstract = $cls->isAbstract == 1;
798             $cls->isDeprecated = $cls->isDeprecated == 1;
799             $cls->is_enum = $cls->dtype == 'enum';
800             $cls->is_mixin = $cls->dtype == 'mixin';
801             //$cls->is_typedef = $cls->is_typedef = 1;
802             $cls->extends = strlen($cls->extends) ? explode(',',$cls->extends) : array();
803             $cls->realImplementors  = $this->outImplementorsToArray($clsar['id']);
804             $cls->events = $this->outEventSymbols($clsar); // event's are properties that are typedefs..
805             $cls->methods = $this->outMethodSymbols($clsar);
806             $cls->props = $this->outPropertySymbols($clsar);
807             
808             echo "OUT:".TDIR .'symbols/'.$cls->name. '.json' ."\n";
809             file_put_contents(TDIR .'symbols/'.$cls->name. '.json', json_encode($cls,JSON_PRETTY_PRINT));
810             
811             
812             $ns[$cls->memberOf]->{$cls->dtype}[] = $cls;
813             
814         }
815         foreach($ns as $nm => $cls) {
816             echo "OUT:".TDIR .'ns/'.$nm. '.json' ."\n";
817             file_put_contents(TDIR .'ns/'.$nm. '.json', json_encode($cls,JSON_PRETTY_PRINT));
818         }
819         
820         
821         
822     }
823     
824     function outEventSymbols($c)
825     {
826         $res = $this->pdo->query("
827             SELECT
828                     id,
829                     COALESCE(desc, '') as desc,
830                     COALESCE(example, '') as example,
831                     href,
832                     is_deprecated as isDeprecated,
833                     value_type as type,
834                     name as name
835                 from 
836                         node 
837                 where 
838                         parent_id = {$c['id']}
839                         AND
840                         type IN ('property')
841                         AND
842                         'typedef' = (SELECT type from node as sc where sc.qualifiedName = (CASE 
843                         WHEN instr(node.value_type,',') > 0 
844                         THEN substr(node.value_type, 0, instr(node.value_type,',')) 
845                         ELSE node.value_type  
846                         END) limit 1) ;
847                     
848                 
849                 order by
850                     qualifiedName ASC
851         ");
852         $all = $res->fetchAll(PDO::FETCH_ASSOC);
853         $events = array();
854         foreach($all as $evar) {
855             $ev = (object) $evar;
856             unset($ev->id);
857             $ev->isDeprecated = $ev->isDeprecated == 1;
858             $ev->memberOf = $c['name'];
859             $ev->params = array(); // FIXME
860             $ev->type = $this->typeStringToGeneric($ev->type);
861             $events[] = $ev;
862             
863         }
864         return $events;
865         
866     }
867     
868     function outPropertySymbols($c)
869     {
870         $res = $this->pdo->query("
871             SELECT
872                     id,
873                     COALESCE(desc, '') as desc,
874                     COALESCE(example, '') as example,
875                     href,
876                     name as name,
877                     is_deprecated as isDeprecated,
878                     value_type as type,
879                     type as dtype
880                     
881                 from 
882                         node 
883                 where 
884                         parent_id = {$c['id']}
885                         AND
886                         (
887                             (
888                                 type IN ('property')
889                                 AND
890                                 'typedef' != (SELECT type from node as sc where sc.qualifiedName = (CASE 
891                                 WHEN instr(node.value_type,',') > 0 
892                                 THEN substr(node.value_type, 0, instr(node.value_type,',')) 
893                                 ELSE node.value_type  
894                                 END) limit 1)
895                             ) OR (
896                                 type IN ('constant', 'enum-value')
897                             )
898                             
899                         );
900                     
901                 
902                 order by
903                     qualifiedName ASC
904         ");
905         $all = $res->fetchAll(PDO::FETCH_ASSOC);
906         $events = array();
907         foreach($all as $evar) {
908             $ev = (object) $evar;
909             unset($ev->id);
910             $ev->isStatic = in_array($ev->dtype , array( 'constant', 'enum-value')); // since we do not know what static properties are...
911             $ev->isConstant = in_array($ev->dtype , array( 'constant', 'enum-value'));
912             $ev->memberOf = $c['name'];
913             $ev->isDeprecated = $ev->isDeprecated == 1;
914             $ev->params = array(); // FIXME
915             $ev->type = $this->typeStringToGeneric($ev->type);
916             $events[] = $ev;
917             
918         }
919         return $events;
920         
921     }
922     function outMethodSymbols($c)
923     {
924         
925           $res = $this->pdo->query("
926             SELECT
927                     id,
928                     COALESCE(desc, '') as desc,
929                     COALESCE(example, '') as example,
930                     href,
931                     is_deprecated as isDeprecated,
932                     value_type as type,
933                     name as name,
934                     type as dtype
935                 from 
936                         node 
937                 where 
938                         parent_id = {$c['id']}
939                         AND
940                         type IN ('method','constructor')
941                          
942                     
943                 
944                 order by
945                     qualifiedName ASC
946         ");
947         $all = $res->fetchAll(PDO::FETCH_ASSOC);
948         $events = array();
949         foreach($all as $evar) {
950             $ev = (object) $evar;
951             unset($ev->id);
952             $ev->isConstructor = $ev->dtype == 'constructor';
953              
954             $ev->static = false;
955             $ev->memberOf = $c['name'];
956             $ev->isDeprecated = $ev->isDeprecated == 1;            
957             $ev->params = $this->outParamSymbols($evar);
958             $ev->type = $this->typeStringToGeneric($ev->type);
959             $events[] = $ev;
960             
961         }
962         return $events;
963         
964     }
965     function outParamSymbols($c)
966     {
967         
968           $res = $this->pdo->query("
969             SELECT
970                     id,
971                     name as name,
972                     COALESCE(desc, '') as desc,
973                     COALESCE(example, '') as example,
974                     href,
975                     is_deprecated as isDeprecated,
976                     false as isOptional,
977                     value_type as type
978                 from 
979                         node 
980                 where 
981                         parent_id = {$c['id']}
982                         AND
983                         type IN ('param')
984                          
985                     
986                 
987                 order by
988                     qualifiedName ASC
989         ");
990         $all = $res->fetchAll(PDO::FETCH_ASSOC);
991         $events = array();
992         foreach($all as $evar) {
993             $ev = (object) $evar;
994             unset($ev->id);
995             $ev->isDeprecated = $ev->isDeprecated == 1;
996             $ev->isOptional = $c['dtype'] == 'constructor';
997             $ev->type = $this->typeStringToGeneric($ev->type);
998             $events[] = $ev;
999             
1000         }
1001         return $events;
1002         
1003     }
1004     
1005     
1006 }
1007
1008
1009 define( 'FDIR', '/home/alan/Downloads/flutterdocs/flutter/');
1010 define( 'TDIR', '/home/alan/gitlive/flutter-docs-json/'); 
1011  
1012 $sq = new fsql();
1013 print_r($_SERVER['argv']);
1014 if (!empty($_SERVER['argv'][1]) && $_SERVER['argv'][1] == 'index') {
1015     echo "rebuilding Index" ;$sq->parseIndex();exit;
1016 }
1017 //$sq->parse('library'); // what does this achieve?
1018 /*
1019 $sq->parse('class');
1020 $sq->parse('constructor');
1021 $sq->parse('method');
1022 $sq->parse('property');
1023 $sq->parse('enum');
1024 $sq->parse('mixin');
1025 $sq->parse('typedef');
1026 $sq->parse('constant');
1027 $sq->parse('top-level constant');
1028 $sq->parse('function');
1029 $sq->parse('top-level property');
1030
1031
1032 */
1033 //
1034 //
1035 //$sq->outTree();
1036 $sq->outClassSymbols();