# nv-js-parse

> nv-js-parse ============ - nv-js-parse - wrap of @babel/parser - add some display/show/path/traverse methods , make it easy for manual-edit ast - nv-js-parse is slow, coz it insert some functions to original-babel-parser - and rebuild the path/traverse o

Latest version **1.4.25** (published 2023-09-19) · ISC license · 0 weekly downloads

## Install

```sh
npm install nv-js-parse
pnpm add nv-js-parse
yarn add nv-js-parse
bun add nv-js-parse
```

## Health

**Score 15/100 (F)** — status: abandoned.

Positive: no vulnerabilities.

Warnings: low downloads; no types; no esm support.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 1.4.25 |
| Published | 2023-09-19 |
| First published | 2020-11-30 |
| Weekly downloads | 0 |
| License | ISC |
| TypeScript types | none |
| Module format | CommonJS |
| Dependencies | 7 |
| Unpacked size | 1.1 MB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Maintainers | ihgazni2 |

## Links

- npm: https://www.npmjs.com/package/nv-js-parse
- npm.io page: https://npm.io/package/nv-js-parse

## Dependencies (7)

- [nv-js-dot-ir](https://npm.io/package/nv-js-dot-ir.md) ^1.0.0
- [nv-char-jsid2](https://npm.io/package/nv-char-jsid2.md) ^1.0.4
- [nv-js-infix-ir](https://npm.io/package/nv-js-infix-ir.md) ^1.0.3
- [nv-jsparser-helper](https://npm.io/package/nv-jsparser-helper.md) ^1.0.22
- [nv-string-match-by](https://npm.io/package/nv-string-match-by.md) ^1.0.1
- [nv-facutil-optimize](https://npm.io/package/nv-facutil-optimize.md) ^1.0.0
- [nv-js-bin-asgn-expr-ir](https://npm.io/package/nv-js-bin-asgn-expr-ir.md) ^1.0.1

## Recent versions

- 1.4.25 (latest) — 2023-09-19
- 1.4.23 — 2023-09-19
- 1.4.21 — 2023-09-16
- 1.4.18 — 2023-09-15
- 1.4.17 — 2023-09-15
- 1.4.16 — 2023-09-15
- 1.4.15 — 2023-09-15
- 1.4.14 — 2023-09-15
- 1.4.7 — 2023-09-03
- 1.4.6 — 2023-08-31
- 1.4.5 — 2023-08-31
- 1.4.2 — 2023-08-31
- 1.4.1 — 2023-08-31
- 1.3.98 — 2023-08-25
- 1.3.96 — 2023-08-24
- … 147 more at https://npm.io/package/nv-js-parse/versions

## README

nv-js-parse
============
- nv-js-parse 
- wrap of @babel/parser
- add some display/show/path/traverse methods , make it easy for manual-edit ast
- nv-js-parse is slow, coz it insert some functions to original-babel-parser
- and rebuild the path/traverse of babel
- its for build cli-code-tools,NOT for creat-runtime

install
=======
- npm install nv-js-parse 

usage
=====
    
basic
-------

    const {tree,parse,unparse,pprint_ast} = require('nv-js-parse')

###
    var code = `class T {
        #a = 1999
        get() {
          return this.#a
        }
    }`

    > var t = tree(code)
    > t
     [program <Program> {"sourceType":"module","interpreter":null}] {}

###

- astml is a simple syntax for manually writing ast
- shape: 
         %key                    <%type:String>        %attr:Object  %NL
         %listKey[%index:Int]    <%type:String>        %attr:Object  %NL

         %type must be ast-node-type of estree/ts/flow/jsx
         %key AND %listKey  must be visitor/list-visitor of %type 

#### 
    
        > t.show_astml()
        program <Program> {"sourceType":"module","interpreter":null}
            body[0] <ClassDeclaration> {}
                id <Identifier> {"name":"T"}
                body <ClassBody> {}
                    body[0] <ClassPrivateProperty> {"static":false}
                        key <PrivateName> {}
                            id <Identifier> {"name":"a"}
                        value <NumericLiteral> {"value":1999}
                    body[1] <ClassMethod> {"generator":false,"async":false,"static":false,"computed":false,"kind":"method"}
                        key <Identifier> {"name":"get"}
                        body <BlockStatement> {}
                            body[0] <ReturnStatement> {}
                                argument <MemberExpression> {"computed":false}
                                    object <ThisExpression> {}
                                    property <PrivateName> {}
                                        id <Identifier> {"name":"a"}



            > t.show_code()
            class T {
              #a = 1999;

              get() {
                return this.#a;
              }

            }



            > t.get_all_ast_bracket_paths()
            [
              '',
              '["body"]["0"]',
              '["body"]["0"]["id"]',
              '["body"]["0"]["body"]',
              '["body"]["0"]["body"]["body"]["0"]',
              '["body"]["0"]["body"]["body"]["0"]["key"]',
              '["body"]["0"]["body"]["body"]["0"]["key"]["id"]',
              '["body"]["0"]["body"]["body"]["0"]["value"]',
              '["body"]["0"]["body"]["body"]["1"]',
              '["body"]["0"]["body"]["body"]["1"]["key"]',
              '["body"]["0"]["body"]["body"]["1"]["body"]',
              '["body"]["0"]["body"]["body"]["1"]["body"]["body"]["0"]',
              '["body"]["0"]["body"]["body"]["1"]["body"]["body"]["0"]["argument"]',
              '["body"]["0"]["body"]["body"]["1"]["body"]["body"]["0"]["argument"]["object"]',
              '["body"]["0"]["body"]["body"]["1"]["body"]["body"]["0"]["argument"]["property"]',
              '["body"]["0"]["body"]["body"]["1"]["body"]["body"]["0"]["argument"]["property"]["id"]'
            ]
            > t.ast["body"]["0"]["body"]["body"]["1"]["body"]["body"]["0"]["argument"]["property"]["id"]
            Node {
              type: 'Identifier',
              start: 67,
              end: 68,
              loc: SourceLocation {
                start: Position { line: 4, column: 23 },
                end: Position { line: 4, column: 24 },
                filename: undefined,
                identifierName: 'a'
              },
              name: 'a'
            }



const2let
---------------
- for debug using
- actually ,const is a runtime-check feature


        /*
        > function tst() {
        ...     const a;
            const a;
                  ^

        Uncaught SyntaxError: Missing initializer in const declaration
        >     a=100
        100
        > }
        }
        ^

        */

        cd =`function tst() {
            const a;
            a=100
        }`


        > cd =`function tst() {
             const a;
            a=100
        }`
        'function tst() {\n    const a;\n    a=100\n}'
        >
        > const2let(cd)
        'function tst() {\n  let a;\n  a = 100;\n}'
        >



hoist\_func\_decl
------------------
- stage0, func declaration hoist
- not the final ,only hoist to first ance-block, not to function block

         var cd =`function A () {
               let x = 0
               console.log(tst())
               {
                  console.log(tst())
                  function tst() {return(x+1)}
               }
               function tst() {return(x)}
         }`


          s0 = split_var_decl(cd)
          s1 = split_var_declor(s0)
          s2 = hoist_var(s1)
          s3 = hoist_func_decl(s2)

         > console.log(s3)
         function A() {
           function tst() {
             return x;
           }

           let x;
           x = 0;
           console.log(tst());
           {
             function tst() {
               return x + 1;
             }

             console.log(tst());
           }
         }


fdecl2fexpr
-------------
- must be used after hoist\_func\_decl


                  var cd = `
                      function tst(u,v) {
                           let a=100;
                           function inner() {
                               var x;
                               function tst() {}
                           }
                      }
                  `

                > console.log(fdecl2fexpr(cd))
                var tst = function tst(u, v) {
                  let a = 100;

                  var inner = function inner() {
                    var x;

                    var tst = function tst() {};
                  };
                };


cdecl2cexpr
----------------
- class declaration to class expression



         var cd = `
             class A {
                 method() {
                     class B {}
                     class C {}
                     function tst() {
                         class D {}
                     }
                 }
             }
         `


         > console.log(cdecl2cexpr(cd))
         let A = class A {
           method() {
             let B = class B {};
             let C = class C {};

             function tst() {
               let D = class D {};
             }
           }

         };


split\_var\_decl
-----------------
- for debug AND hoist using

###

    const {split_var_decl} = require("nv-js-parse")
    var code = `
        function tst() {
            let a,b=3,c;
            return(a+b+c)
    }`


    > console.log(split_var_decl(code))
    function tst() {
      let a;
      let b = 3;
      let c;
      return a + b + c;
    }

    var code = `
        function tst() {
            let x,[{a,b},c]=[{a:666,b:777},3],y;
            return(a+b+c)
    }`
    
    > console.log(split_var_decl(code))
    function tst() {
      let x;
      let [{
        a,
        b
      }, c] = [{
        a: 666,
        b: 777
      }, 3];
      let y;
      return a + b + c;
    }
    
    > tst()
    1446
    >


        >      var cd = `function tst() {
        ...          var a,b=8;
        ...          for(let i=0,j;i<3;i++,j++) {let {x,y}={}}
        ...          var c = a+b
        ...      }`
        > console.log(split_var_decl(cd))
        function tst() {
          var a;
          var b = 8;
          {                               //----------------
            let i = 0;
            let j;

            for (; i < 3; i++, j++) {
              let {
                x,
                y
              } = {};
            }
          }                             //------------------special handle of for AND forin AND forof
          var c = a + b;
        }




split\_var\_declor
-------------------
- for debug AND hoist using
- must be used after split\_var\_decl


### 


          var cd = `
              function tst(u,v) {
                  let x,e,ee;
                  let [{a,b=e='EEEEE',...f},c=333,d,...g]=[{a:666,b:777},3];
                  let [{aa,bb=ee='1111111',...ff},cc=333,dd,...gg]=[{aa:666,bb:777},3];
                  let [] = [],[,] =[],[...args] = [1,2],{...D} = {1:2,3:4},[A] = [1,2],{B} = {B:2,3:4},[C=10] = [],{E=999} = {};
                  return([u,v,x,a,b,e,f,c,d,g,aa,bb,ee,ff,cc,dd,gg,args,D,A,B,C,E])
              }
          `
          
          /*
          > eval(`(${cd})(100,500)`)
          [
            100,                500,
            undefined,          666,
            777,                undefined,
            {},                 3,
            undefined,          [],
            666,                777,
            undefined,          {},
            3,                  undefined,
            [],                 [ 1, 2 ],
            { '1': 2, '3': 4 }, 1,
            2,                  10,
            999
          ]
          >
          
          */
          s0 = split_var_decl(cd)
          console.log(s0)
          /*
          function tst(u, v) {
            let x;
            let e;
            let ee;
            let [{
              a,
              b = e = 'EEEEE',
              ...f
            }, c = 333, d, ...g] = [{
              a: 666,
              b: 777
            }, 3];
            let [{
              aa,
              bb = ee = '1111111',
              ...ff
            }, cc = 333, dd, ...gg] = [{
              aa: 666,
              bb: 777
            }, 3];
            let [] = [];
            let [,] = [];
            let [...args] = [1, 2];
            let { ...D
            } = {
              1: 2,
              3: 4
            };
            let [A] = [1, 2];
            let {
              B
            } = {
              B: 2,
              3: 4
            };
            let [C = 10] = [];
            let {
              E = 999
            } = {};
            return [u, v, x, a, b, e, f, c, d, g, aa, bb, ee, ff, cc, dd, gg, args, D, A, B, C, E];
          }
          
          */
          /*
          > eval(`(${s0})(100,500)`)
          [
            100,                500,
            undefined,          666,
            777,                undefined,
            {},                 3,
            undefined,          [],
            666,                777,
            undefined,          {},
            3,                  undefined,
            [],                 [ 1, 2 ],
            { '1': 2, '3': 4 }, 1,
            2,                  10,
            999
          ]
          >
          
          */
          s1 = split_var_declor(s0)
          console.log(s1)
          
          /*
          function tst(u, v) {
            let x;
            let e;
            let ee;
            let a;
            let b;
            let f;
            let c;
            let d;
            let g;
            [{
              a,
              b = e = 'EEEEE',
              ...f
            }, c = 333, d, ...g] = [{
              a: 666,
              b: 777
            }, 3];
            let aa;
            let bb;
            let ff;
            let cc;
            let dd;
            let gg;
            [{
              aa,
              bb = ee = '1111111',
              ...ff
            }, cc = 333, dd, ...gg] = [{
              aa: 666,
              bb: 777
            }, 3];
            [] = [];
            [,] = [];
            let args;
            [...args] = [1, 2];
            let D;
            ({ ...D
            } = {
              1: 2,
              3: 4
            });
            let A;
            [A] = [1, 2];
            let B;
            ({
              B
            } = {
              B: 2,
              3: 4
            });
            let C;
            [C = 10] = [];
            let E;
            ({
              E = 999
            } = {});
            return [u, v, x, a, b, e, f, c, d, g, aa, bb, ee, ff, cc, dd, gg, args, D, A, B, C, E];
          }
          
          */
          
          /*
          > eval(`(${s1})(100,500)`)
          [
            100,                500,
            undefined,          666,
            777,                undefined,
            {},                 3,
            undefined,          [],
            666,                777,
            undefined,          {},
            3,                  undefined,
            [],                 [ 1, 2 ],
            { '1': 2, '3': 4 }, 1,
            2,                  10,
            999
          ]
          >
          
          */



          var cd = `function tst() {for(let i=1,[x,y]=[888];i<3;i++) {}}`
          s0 = split_var_decl(cd)
          s1 = split_var_declor(s0)
          console.log(s1)

          /*
             function tst() {
               {
                 let i;
                 i = 1;
                 let x;
                 let y;
                 [x, y] = [888];
             
                 for (; i < 3; i++) {}
               }
             }
          */


          var cd = `function tst() {for(let i;i<3;i++) {}}`
          s0 = split_var_decl(cd)
          s1 = split_var_declor(s0)
          console.log(s1)

           /*
           function tst() {
             {
               let i;
           
               for (; i < 3; i++) {}
             }
           }
           */

         var cd = `
             async function tst() {
                 let arr =[];
                 let d = {};
                 let g = (async function *(){})();
                 for(let i=1,y;i<3;i++) {}
                 for(let ele of arr) {}
                 for(let k in d) {}
                 for await (let  each of g) {}
             }
         `

          s0 = split_var_decl(cd)
          s1 = split_var_declor(s0)
          console.log(s1)
           /*
           async function tst() {
             let arr;
             arr = [];
             let d;
             d = {};
             let g;
           
             g = async function* () {}();
           
             {
               let i;
               i = 1;
               let y;
           
               for (; i < 3; i++) {}
             }
             {
               let ele;
           
               for (ele of arr) {}
             }
             {
               let k;
           
               for (k in d) {}
             }
             {
               let each;
           
               for await (each of g) {}
             }
           }
            */


hoist\_var
-------------------
- must be used after split\_var\_decl ->  split\_var\_declor


        const {
            split_var_decl,
            split_var_declor,
            tree,
            hoist_var,
        } = require("nv-js-parse")
        
                  var cd = `
                      function tst(u,v) {
                          let x;
                          {
                              var y=888;
                              {
                                  var [z,{w,r}] = [1,{w:2,r:3}];
                                   let A;
                              }
                          }
                      }
                  `
                  
                  s0 = split_var_decl(cd)
                  s1 = split_var_declor(s0)
                  s2 = hoist_var(s1)
        
        
        > console.log(s2)
        function tst(u, v) {
          let x;
          var y;
          var z;
          var w;
          var r;
          {
            y = 888;
            {
              [z, {
                w,
                r
              }] = [1, {
                w: 2,
                r: 3
              }];
              let A;
            }
          }
        }


### rare special cases


        > var cd =`
        ... function tst() {
        ...   var a;
        ...   {
        .....     var a;
        .....     a = 13;
        .....   }
        ... }`
        >
        > hoist_var(cd)
        'function tst() {\n  var a;\n  var a;\n  {\n    a = 13;\n  }\n}'
        > console.log(hoist_var(cd))
        function tst() {
          var a;
          var a;
          {
            a = 13;
          }
        }






        var cd =`
        var tst;

        tst = function tst() {
          var a;
          {
            var a;
          }
        };
        `

        > var cd =`
        ... var tst;
        ...
        ... tst = function tst() {
        ...   var a;
        ...   {
        .....     var a;
        .....   }
        ... };
        ... `
        > console.log(hoist_var(cd))
        var tst;

        tst = function tst() {
          var a;
          var a;
          {}
        };
        >



merge\_dupe\_var\_decl
----------------------
- must be used after hoist\_var

### 

        var cd = `
        function tst() {
          var a;
          var a;
          {
            a = 13;
          }
        }`

        merge_dupe_var_decl(cd)


        > console.log(merge_dupe_var_decl(cd))
        [
          ‍ [        id <Identifier> {"name":"tst"}] {},
          ‍ [                    id <Identifier> {"name":"a"}] {},
          ‍ [                    id <Identifier> {"name":"a"}] {},
          ‍ [                        left <Identifier> {"name":"a"}] {}
        ]
        function tst() {
          var a;
          {
            a = 13;
          }
        }


###when conflict with params- 

    var cd= `function tst(a) {
        var a;
        return(a)
    }`


    > console.log(merge_dupe_var_decl(cd))
    function tst(a) {
      return a;
    }



split\_nonidlval\_asgn\_expr
-----------------------------
- must be used after split\_var\_declor
- if the AssignmentExpression left(LVal) is NOT direct Identifier
-   (such as MemberExpression,ArrayPattern,ObjectPattern....)
- it will split it to three part, see below

###

        var cd =`[z,{w,r}] = [1,{w:2,r:3}]`

        console.log(split_nonidlval_asgn_expr(cd))

        /*
            let ___swapper_b1cf8a9c_$AssignmentExpression___ = [1, {
              w: 2,
              r: 3
            }];

            [z, {
              w,
              r
            }] = ___swapper_b1cf8a9c_$AssignmentExpression___;


        */


###

              var cd = `
                function tst(u,v) {
                    let x;
                    {
                        var y=888;
                        {
                            var [z,{w,r}] = [1,{w:2,r:3}];
							var [u,{v},...X] = [10,{v:20}];
                            let A;
							var B=D=E=1111
                        }
                    }
					var [z,{w,r}] = [10,{w:20,r:30}];
                }
            `
            
            s0 = split_var_decl(cd)
            s1 = split_var_declor(s0)
            s2 = hoist_var(s1)
            s3 = split_nonidlval_asgn_expr(s2)
			s4 = merge_dupe_var_decl(s3)
			console.log(s4)
			
        /*
        function tst(u, v) {
          var y;
          var z;
          var w;
          var r;
          var X;
          var B;
          let x;
          {
            y = 888;
            {
              let ___swapper_ec071153_$AssignmentExpression___ = [1, {
                w: 2,
                r: 3
              }];
              [z, {
                w,
                r
              }] = ___swapper_ec071153_$AssignmentExpression___;
              let ___swapper_fcc8fd5d_$AssignmentExpression___ = [10, {
                v: 20
              }];
              [u, {
                v
              }, ...X] = ___swapper_fcc8fd5d_$AssignmentExpression___;
              let A;
              B = D = E = 1111;
            }
          }
          let ___swapper_b72b9d99_$AssignmentExpression___ = [10, {
            w: 20,
            r: 30
          }];
          [z, {
            w,
            r
          }] = ___swapper_b72b9d99_$AssignmentExpression___;
        }
        */



var\_to\_let
------------
- must be used after merge\_dupe\_var\_decl

        var cd = `
        function tst() {
          var a;
          var a;
          {
            a = 13;
          }
        }`

        var s0 = merge_dupe_var_decl(cd)
        var s1 = var2let(s0)
        > console.log(s1)
        function tst() {
          let a;
          {
            a = 13;
          }
        }

split\_rtrn\_stmt
-----------------
- move argument of return-statement out


###
    
    const {split_rtrn_stmt} = require("nv-js-parse");


        var cd =`
        function tst(a,b,c) {
            function inner() {
                return(c*3)
            }
            return((a+b+inner()))
        }
        `
     
        console.log(split_rtrn_stmt(cd))




        function tst(a, b, c) {
          function inner() {
            let ___rslt_0296616b_$ReturnStatement___;

            ___rslt_0296616b_$ReturnStatement___ = c * 3;
            return ___rslt_0296616b_$ReturnStatement___;
          }

          let ___rslt_32b00b98_$ReturnStatement___;

          ___rslt_32b00b98_$ReturnStatement___ = a + b + inner();
          return ___rslt_32b00b98_$ReturnStatement___;
        }

split\_thrw\_stmt
-------------------


        var src = `
        function tst() {
            throw(new Error("!!"));
            {
                throw a;
            }
        }
        `

        > console.log(x.split_thrw_stmt(src))
        function tst() {
          let ___rslt_2a23863e_$ThrowStatement___;

          ___rslt_2a23863e_$ThrowStatement___ = new Error("!!");
          throw ___rslt_2a23863e_$ThrowStatement___;
          {
            let ___rslt_91675550_$ThrowStatement___;

            ___rslt_91675550_$ThrowStatement___ = a;
            throw ___rslt_91675550_$ThrowStatement___;
          }
        }



ternery to if-else
--------------------

        const {conexpr_to_ifelse} = require("nv-js-parse");

        var cd0 = `function tst(a,b,c,d,e) {return(a?b:c?d:e)}`;

        /*
        > function tst(a,b,c,d,e) {return(a?b:c?d:e)}
        > tst(true,false,true,'d','e')
        false
        >
        */

        console.log(conexpr_to_ifelse(cd0));

        /*
        function tst(a, b, c, d, e) {
          return (() => {
            if (a) {
              return b;
            } else {
              return (() => {
                if (c) {
                  return d;
                } else {
                  return e;
                }
              })();
            }
          })();
        }

        > tst(true,false,true,'d','e')
        false
        >

        */



        var cd1 = `function tst(a,b,c,d,e) {return((a?b:c)?d:e)}`;

        /*
        function tst(a,b,c,d,e) {return((a?b:c)?d:e)}
        > tst(true,false,true,'d','e')
        'e'
        >
        */

        console.log(conexpr_to_ifelse(cd1));

        /*
        function tst(a, b, c, d, e) {
          return (() => {
            if ((() => {
              if (a) {
                return b;
              } else {
                return c;
              }
            })()) {
              return d;
            } else {
              return e;
            }
          })();
        }

        > tst(true,false,true,'d','e')
        'e'
        >

        */

        var cd2 = `
            function tst(a,b,c,d,e) {
                let x = a?b:null
                function inner() {
                    let y = a?(
                       c?d:e
                    ):(
                       d?100:(e?200:300)
                    )
                }
                return(inner())
            }
        `

        console.log(conexpr_to_ifelse(cd2));

        /*
        function tst(a, b, c, d, e) {
          let x = (() => {
            if (a) {
              return b;
            } else {
              return null;
            }
          })();

          function inner() {
            let y = (() => {
              if (a) {
                return (() => {
                  if (c) {
                    return d;
                  } else {
                    return e;
                  }
                })();
              } else {
                return (() => {
                  if (d) {
                    return 100;
                  } else {
                    return (() => {
                      if (e) {
                        return 200;
                      } else {
                        return 300;
                      }
                    })();
                  }
                })();
              }
            })();
          }

          return inner();
        }
        */



tree
----------
- read-only

###
        const {tree} = require("nv-js-parse");
        
        
        var cd2 =`
            function outter() {
                let a ;
                function inner() {
                    b
                    a;
                    {
                        a;
                    }
                }
            }
        `
        
        var t = tree(cd2);
        var arr = t.$sdfs()
        var ids = arr.filter(r=>r.path.node.type==='Identifier')
        
        > ids.map(r=>r.path.node.name)
        [ 'outter', 'a', 'inner', 'b', 'a', 'a' ]
        >
        > ids[0].get_closure_scope_nd()
         [Program] {}
        >
        
        > ids[1].get_closure_scope_nd().show_code()
        
        > ids[1].get_ast().name
        'a'
        > ids[1].get_closure_scope_nd().show_code()
        function outter() {
          let a;
        
          function inner() {
            b;
            a;
            {
              a;
            }
          }
        }
        
        > ids[2].get_ast().name
        'inner'
        > ids[2].get_closure_scope_nd().show_code()
        function outter() {
          let a;
        
          function inner() {
            b;
            a;
            {
              a;
            }
          }
        }
        
        > ids[3].get_ast().name
        'b'
        > var top = ids[3].get_closure_scope_nd()
         [Program] {}
        >
        > top.path.scope.globals
        [Object: null prototype] {
          b: Node {
            type: 'Identifier',
            start: 80,
            end: 81,
            loc: SourceLocation {
              start: [Position],
              end: [Position],
              filename: undefined,
              identifierName: 'b'
            },
            name: 'b'
          }
        }
        >
        
        > ids[5].get_ast().name
        'a'
        >
        > ids[5].get_closure_scope_nd().show_code()
        function outter() {
          let a;
        
          function inner() {
            b;
            a;
            {
              a;
            }
          }
        }
        
        
        
        var cd3 = `
           function tst(A,B) {
               function inner() {
                   return(A)
               }
           }
        `
        
        
        var t = tree(cd3);
        var arr = t.$sdfs()
        var ids = arr.filter(r=>r.path.node.type==='Identifier')
        ids.map(r=>r.path.node.name)
        [ 'tst', 'A', 'B', 'inner', 'A' ]
        
        > ids[1].get_closure_scope_nd().show_code()
        function tst(A, B) {
          function inner() {
            return A;
          }
        }
        undefined
        > ids[1].get_ast().name
        'A'
        > ids[1].get_closure_scope_nd().show_code()
        function tst(A, B) {
          function inner() {
            return A;
          }
        }
        > ids[4].get_ast().name
        'A'
        > ids[4].get_closure_scope_nd().show_code()
        function tst(A, B) {
          function inner() {
            return A;
          }
        }

binding
-------

          var t = tree(`
               let P;
               function X([tst=666,{a,b}]){
                   let uuu=y;
                   class C {}
               }
               try{}catch({e}) { let vvv;}
               var D = { s(u,{v}){} }
               class U {}
               {let m;}
               for(let j=0;j<5;j++) {}
               for(let k in X) {}
               for(let ele of X) {}
          `)
          t.get_decl_ids().map(r=>r.get_sig_plstr())
          /*

          [
            'body-declarations-id',
            'body-id',
            'params-elements-left',
            'params-elements-properties-key',
            'params-elements-properties-key',
            'body-body-declarations-id',
            'body-body-id',
            'param-properties-key',
            'body-body-declarations-id',
            'body-declarations-id',
            'params',
            'params-properties-key',
            'body-id',
            'body-declarations-id',
            'init-declarations-id',
            'left-declarations-id',
            'left-declarations-id'
          ]
          */
          var fdecl = t.FunctionDeclaration()[0];

          /*
          > fdecl.show_code()
          function X([tst = 666, {
            a,
            b
          }]) {
            let uuu = y;

            class C {}
          }

          */

          > fdecl.get_binding_def_ids()
          {
            var: [],
            let: [
              ‍ [                    id <Identifier> {"name":"uuu"}] {}
            ],
            const: [],
            fdecl: [],
            cdecl: [
              ‍ [                id <Identifier> {"name":"C"}] {}
            ],
            params: [
              ‍ [                left <Identifier> {"name":"tst"}] {},
              ‍ [                    value <Identifier> {"name":"a"}] {},
              ‍ [                    value <Identifier> {"name":"b"}] {}
            ],
            global: [],
            catch_param: []
          }
          >


            var cd = `
            function tst() {
                let [{
                          a,
                          b = e = 'EEEEE',
                          ...f
                        }, 
                        c = 333, d, 
                        [A,B,C,{E,F}],
                        ...g
              ] =[];
            }
            `


            var t = tree(cd);
            var fdecl = t.$sdfs()[1]

            > fdecl.get_decl_ids().map(r=>r.ast.name)
            [
              'a', 'b', 'f', 'c',
              'd', 'A', 'B', 'C',
              'E', 'F', 'g'
            ]
            >


            function tst() {
                let [{
                          a,
                          b = e = 'EEEEE',               //identifier-e ast-path-sign not match
                          ...f
                        },
                        c = 333, d,
                        [A,B,C,{E,F}],
                        ...g
              ] =[{},undefined,undefined,[1,2,3,{}]];
            }

            /*
            > tst()
            > e
            'EEEEE'                   //e is global

            */


decl id type
-------------
- for static trace using


        var cd = `
            function tst(a,{b}) {
                let c;
                {
                   var d;
                }
                try{}catch(e){}
            }
            let _f1       = function (f) {}
            const _lambda = (g)=> {}
            class C {
                method(h,[j]) {}
                #method([k,{l}]){}
            }
            let O = {m(n){}}
            try{}catch({p}){}
            for(let i=0;i<5;i++) {}
            for(let {I}={I:0};i<5;i++) {}
            for(let ele of []) {}
            for(let [ELE] of [[1],[2]]) {}
            for(let k in {}) {}
            for(let {length} in [0,1,2,3,4,5,6,7,8,9,10]) {}              //this is a valid syntax
        `

        var t = tree(cd)

        > ids = t.get_decl_ids()
        [
          ‍ [        id <Identifier> {"name":"tst"}] {},
          ‍ [        params[0] <Identifier> {"name":"a"}] {},
          ‍ [                value <Identifier> {"name":"b"}] {},
          ‍ [                    id <Identifier> {"name":"c"}] {},
          ‍ [                        id <Identifier> {"name":"d"}] {},
          ‍ [                    param <Identifier> {"name":"e"}] {},
          ‍ [            id <Identifier> {"name":"_f1"}] {},
          ‍ [                params[0] <Identifier> {"name":"f"}] {},
          ‍ [            id <Identifier> {"name":"_lambda"}] {},
          ‍ [                params[0] <Identifier> {"name":"g"}] {},
          ‍ [        id <Identifier> {"name":"C"}] {},
          ‍ [                params[0] <Identifier> {"name":"h"}] {},
          ‍ [                    elements[0] <Identifier> {"name":"j"}] {},
          ‍ [                    elements[0] <Identifier> {"name":"k"}] {},
          ‍ [                            value <Identifier> {"name":"l"}] {},
          ‍ [            id <Identifier> {"name":"O"}] {},
          ‍ [                    params[0] <Identifier> {"name":"n"}] {},
          ‍ [                    value <Identifier> {"name":"p"}] {},
          ‍ [                id <Identifier> {"name":"i"}] {},
          ‍ [                        value <Identifier> {"name":"I"}] {},
          ‍ [                id <Identifier> {"name":"ele"}] {},
          ‍ [                    elements[0] <Identifier> {"name":"ELE"}] {},
          ‍ [                id <Identifier> {"name":"k"}] {},
          ‍ [                        value <Identifier> {"name":"length"}] {}
        ]
        >


        > ids[0].is_fdecl_id()
        true
        > ids[1].is_fdecl_param_id()
        true
        > ids[2].is_fdecl_param_id()
        true
        >
        > ids[3].is_let_decl_id()
        true
        >
        > ids[4].is_var_decl_id()
        true
        >
        > ids[5].is_catch_param_id()
        true
        >
        > ids[6].is_let_decl_id()
        true
        >
        > ids[7].is_fexpr_param_id()
        true
        >
        > ids[8].is_const_decl_id()
        true
        >
        > ids[9].is_arrow_param_id()
        true
        >
        > ids[10].is_cdecl_id()
        true
        >
        > ids[11].is_cls_method_param_id()
        true
        >
        > ids[12].is_cls_method_param_id()
        true
        >
        > ids[13].is_cls_priv_method_param_id()
        true
        >
        > ids[14].is_cls_priv_method_param_id()
        true
        >
        > ids[15].is_let_decl_id()
        true
        >
        > ids[16].is_obj_method_param_id()
        true
        >
        > ids[17].is_catch_param_id()
        true
        >
        > ids[18].is_for_init_id()
        true
        >
        > ids[19].is_for_init_id()
        true
        >
        > ids[20].is_forof_id()
        true
        > ids[21].is_forof_id()
        true
        > ids[22].is_forin_id()
        true
        > ids[23].is_forin_id()
        true
        >

find escaped  id
----------------


        var cd = `
            function tst(a) {
                let b=10,c={'key':X};
                a = b+c ;
                {
                    let u = 5;
                    a = a + u;
                }
                return(a)
            }
        `

        var t = tree(cd)
        var f = t.$fstch()

        > f.get_decl_ids()
        [
          ‍ [        params[0] <Identifier> {"name":"a"}] {},
          ‍ [                    id <Identifier> {"name":"b"}] {},
          ‍ [                    id <Identifier> {"name":"c"}] {},
          ‍ [                        id <Identifier> {"name":"u"}] {}          //后代block内的
        ]
        >

        > f.get_own_local_decl_ids()
        {
          var: [],
          let: [
            ‍ [                    id <Identifier> {"name":"b"}] {},
            ‍ [                    id <Identifier> {"name":"c"}] {}
          ],
          const: [],
          fdecl: [],
          cdecl: [],
          params: [
            ‍ [        params[0] <Identifier> {"name":"a"}] {}
          ],
          global: [],
          catch_param: []
        }
        >

        > f.get_own_local_escaped_decl_ids()
        [
          ‍ [        params[0] <Identifier> {"name":"a"}] {}            // 参数 a 被里层 block 使用
        ]
        >

        > f.get_own_local_noescaped_decl_ids()
        [
          ‍ [                    id <Identifier> {"name":"b"}] {},
          ‍ [                    id <Identifier> {"name":"c"}] {}
        ]
        >

        > f.get_nolocal_refed_ids()
        [
          ‍ [                            value <Identifier> {"name":"X"}] {}
        ]
        >




        > f.get_nodecl_notation_ids()
        [
          ‍ [                            value <Identifier> {"name":"X"}] {},
          ‍ [                    left <Identifier> {"name":"a"}] {},
          ‍ [                        left <Identifier> {"name":"b"}] {},
          ‍ [                        right <Identifier> {"name":"c"}] {},
          ‍ [                        left <Identifier> {"name":"a"}] {},             //<a> = a + u
          ‍ [                            left <Identifier> {"name":"a"}] {},         //  a = <a> + u
          ‍ [                            right <Identifier> {"name":"u"}] {},        // a = a + <u>
          ‍ [                argument <Identifier> {"name":"a"}] {}
        ]
        >
        > f.get_own_local_nodecl_ids()
        [
          ‍ [                    left <Identifier> {"name":"a"}] {},              //<a>=b+c
          ‍ [                        left <Identifier> {"name":"b"}] {},         //a=<b>+c
          ‍ [                        right <Identifier> {"name":"c"}] {},        //a=b+<c>
          ‍ [                argument <Identifier> {"name":"a"}] {}              //return(<a>)
        ]
        >


### TAC format
- used in a special js-runtime
- normally useless

        > const {tree} = require("nv-js-parse")
        > var src =`ReactDOM.render(<App />, document.getElementById('root'));`
        > var t = tree(src,{plugins:["typescript","jsx"]})

        > t.$sdfs()
        [
          ‍ [program <Program> {"sourceType":"module","interpreter":null}] {},
          ‍ [    body[0] <ExpressionStatement> {}] {},
          ‍ [        expression <CallExpression> {}] {},
          ‍ [            callee <MemberExpression> {"computed":false}] {},
          ‍ [                object <Identifier> {"name":"ReactDOM"}] {},
          ‍ [                property <Identifier> {"name":"render"}] {},
          ‍ [            arguments[0] <JSXElement> {}] {},
          ‍ [                openingElement <JSXOpeningElement> {"selfClosing":true}] {},
          ‍ [                    name <JSXIdentifier> {"name":"App"}] {},
          ‍ [            arguments[1] <CallExpression> {}] {},
          ‍ [                callee <MemberExpression> {"computed":false}] {},
          ‍ [                    object <Identifier> {"name":"document"}] {},
          ‍ [                    property <Identifier> {"name":"getElementById"}] {},
          ‍ [                arguments[0] <StringLiteral> {"value":"root"}] {}
        ]
        >

        // K = listKey:AstString | Key:AstString
        // T = K@TYPE
        // Attr = Object
        // Ele  = [T,Attr?,Array<Ele>?]
        //

        > var tac = t.to_tac()
        > console.dir(tac,{depth:null})
        [
          'program@Program',{ sourceType: 'module', interpreter: null }, [
            'body@ExpressionStatement', [
              'expression@CallExpression', [
                'callee@MemberExpression',{ computed: false },[
                  'object@Identifier',{ name: 'ReactDOM' },
                  'property@Identifier',{ name: 'render' }
                ],
                'arguments@JSXElement',[
                  'openingElement@JSXOpeningElement',{ selfClosing: true },[
                      'name@JSXIdentifier', { name: 'App' }
                   ]
                ],
                'arguments@CallExpression',[
                  'callee@MemberExpression',{ computed: false },[
                    'object@Identifier',{ name: 'document' },
                    'property@Identifier',{ name: 'getElementById' }
                  ],
                  'arguments@StringLiteral',{ value: 'root' }
                ]
              ]
            ]
          ]
        ]


### rplc\_nodecl\_undef\_with\_void0


        var code =`
        function tst() {
            let a = undefined;                          //============================>this undefined is right-hand  and on global,SHOULD-BE-REPLACED
            function inner() {
                let undefined = 999       //this undefined is left-hand and local #0
                return(undefined)          //this undefined is #0
            }
            console.log(1,inner())           //999
            function inner2() {
                function undefined () {     //this undefined is left-hand and local   #1
                    return(undefined)       //this undefined is #1
                }
                return(undefined)          //this undefined is #1
            }
            console.log(2,inner2())           //[Function: undefined]
            function inner3() {
                let undefined =888;        //this undefined is left-hand and local #2
                let r = (()=> {
                    return(undefined)      //this undefined is #2
                })();
                return(r)
            }
            console.log(3,inner3())                  //888
            /////
            function inner4() {
                 try {
                     x = undefined ;   // ============================>this undefined is right-hand  and on global ,SHOULD-BE-REPLACED
                     throw(x)
                 } catch(e){
                     return(e)
                 }
            }
            console.log(4,inner4())    // undefined
            /////
            function inner5() {
               class undefined {
                  m() {return(undefined)}                   //class undefined
               }
               t= new undefined()
               return(t)
            }
            console.log(5,inner5())   //undefined {}
            ////
            function inner6() {
               class C {
                  undefined() {return(undefined)}            //global undefined coz classMethod
               }
               t= new C()
               return(t.undefined())
            }
            console.log(6,inner6())           //undefined
            /////
            function inner7() {
               let D= {
                  undefined() {return(undefined)}            //global undefined coz ObjectMethod
               }
               return(D.undefined())
            }
            console.log(7,inner7())          //undefined
            /////
            function inner8() {
                 function undefined() {
                     console.log('in fdecl',undefined)
                     return(undefined)                //function, coz FunctionDeclaration
                 }
                 console.log('in outter',undefined)
                 return(undefined())
            }
            console.log(8,inner8())          //[Function: undefined]
            ////
            function inner9() {
                 let _f = function undefined() {
                     console.log('A',undefined===_f)   //true
                     return(undefined)                //function coz FunctionExpression
                 }
                 console.log('B:',undefined===_f)    //false
                 return(_f())
            }
            console.log(9,inner9())
        }
        `

        /*
        > tst()
        1 999
        2 [Function: undefined]
        3 888
        4 undefined
        5 undefined {}
        6 undefined
        7 undefined
        in outter [Function: undefined]
        in fdecl [Function: undefined]
        8 [Function: undefined]
        B: false
        A true
        9 [Function: undefined]
        undefined

        */

        console.log(rplc_nodecl_undef_with_void0(code))

        /*
        function tst() {
          let a = void 0; //============================>this undefined is right-hand  and on global,SHOULD-BE-REPLACED

          function inner() {
            let undefined = 999; //this undefined is left-hand and local #0

            return undefined; //this undefined is #0
          }

          console.log(1, inner()); //999

          function inner2() {
            function undefined() {
              //this undefined is left-hand and local   #1
              return undefined; //this undefined is #1
            }

            return undefined; //this undefined is #1
          }

          console.log(2, inner2()); //[Function: undefined]

          function inner3() {
            let undefined = 888; //this undefined is left-hand and local #2

            let r = (() => {
              return undefined; //this undefined is #2
            })();

            return r;
          }

          console.log(3, inner3()); //888
          /////

          function inner4() {
            try {
              x = void 0; // ============================>this undefined is right-hand  and on global ,SHOULD-BE-REPLACED

              throw x;
            } catch (e) {
              return e;
            }
          }

          console.log(4, inner4()); // undefined
          /////

          function inner5() {
            class undefined {
              m() {
                return undefined;
              } //class undefined


            }

            t = new undefined();
            return t;
          }

          console.log(5, inner5()); //undefined {}
          ////

          function inner6() {
            class C {
              undefined() {
                return void 0;
              } //global undefined coz classMethod


            }

            t = new C();
            return t.undefined();
          }

          console.log(6, inner6()); //undefined
          /////

          function inner7() {
            let D = {
              undefined() {
                return void 0;
              } //global undefined coz ObjectMethod


            };
            return D.undefined();
          }

          console.log(7, inner7()); //undefined
          /////

          function inner8() {
            function undefined() {
              console.log('in fdecl', undefined);
              return undefined; //function, coz FunctionDeclaration
            }

            console.log('in outter', undefined);
            return undefined();
          }

          console.log(8, inner8()); //[Function: undefined]
          ////

          function inner9() {
            let _f = function undefined() {
              console.log('A', undefined === _f); //true

              return undefined; //function coz FunctionExpression
            };

            console.log('B:', void 0 === _f); //false

            return _f();
          }

          console.log(9, inner9());
        }


        */

        /*
        > tst()
        1 999
        2 [Function: undefined]
        3 888
        4 undefined
        5 undefined {}
        6 undefined
        7 undefined
        in outter [Function: undefined]
        in fdecl [Function: undefined]
        8 [Function: undefined]
        B: false
        A true
        9 [Function: undefined]

        */


### get funclike description 
- funclike: it is for convert a func/lambda/method  to a single-param-function-without-any-lexical-binding
- used in nvlang for fctx grammar
- similiar to with , but NOT permit any lexical VarDeclaration
- for tracing purpose

        {
          FunctionParent: [
            'FunctionDeclaration',
            'FunctionExpression',
            'ObjectMethod',
            'ArrowFunctionExpression',
            'ClassMethod',
            'ClassPrivateMethod'
          ]
        }
 
####
        var t = tree(`
            function tst(a,{b,c},...args) {
                let A;
                let B;
                let {x,y} = {};
            }
        `)

        /*
        > f.get_desc_of_funclike()
        [
          'tst',                                       //name
          'FunctionDeclaration',                       //ast-type
          { generator: false, async: false },          //attribs
          {
            A: null,
            B: null,
            x: null,
            y: null,
            a: null,
            b: null,
            c: null,
            args: []
          }                                            //---ctx after extract all params AND lexical-binding
        ]
        >
        */


### signed-pl
- find all declaration/def ids in a file, and generate a unique-path
- it is used in nvlang for gproc grammar, which NOT permit any local variable

####

    > t.$sdfs().filter(nd=>nd.is_decl_id()).map(id=>id.get_id_plsign())
    [
      'body-0-declarations-0-id:traverse',
      'body-1-declarations-0-id-properties-0-value:SimpleStack',
      'body-1-declarations-0-id-properties-1-value:DPGT',
      'body-1-declarations-0-id-properties-2-value:is_int',
      'body-1-declarations-0-id-properties-3-value:is_str',
      'body-2-declarations-0-id-properties-0-value:Root',
      'body-3-declarations-0-id:ary_clu',
      .....


### for stmt  to while


        var cd = `
        function tst() {
            for(let i=0;i<999;i++) {
                console.log(i);
                let b = i +666
            }
        }`


        console.log(for_stmt_to_while(cd))
        /*
        function tst() {
          {
            let i = 0;

            while (i < 999) {
              console.log(i);
              let b = i + 666;
              i++
            }
          }
        }

        */


        var cd = `
        async function tst() {
            let b;
            for(let i=0;i<999;i++) {
                await i;
                console.log(i);
                b = i +666;
                if(b>1500) {
                    break
                }
            }
            return(b)
        }`

        console.log(for_stmt_to_while(cd))
        /*
        async function tst() {
          let b;
          {
            let i = 0;

            while (i < 999) {
              await i;
              console.log(i);
              b = i + 666;

              if (b > 1500) {
                break;
              }

              i++
            }
          }
          return b;
        }

        */


### fmt-una-expr
- wrap UnaryExpression in a SequenceExpression 
- normally useless 


####

        > x.fmt_una_expr('!a')
        '!(0, a);'
        >


        > x.fmt_una_expr('!(typeof u.v)')
        '!(0, typeof (0, u.v));'
        >


### replace update-expression WITH a closure

- update-expr  is boring to do static tracing

####

        var cd =`
        function tst(arr) {
            let v = 100;
            let d = {prop:100}
            arr = arr.forEach(
                nd => {
                   v = v++;
                   v = v--;
                   v = ++v;
                   --v;
                   d.prop++;
                   d.prop=++d.prop;
                   d.prop--;
                   d.prop=--d.prop;
                }
            )
            return([v,d])
        }
        `

        /*
        > tst([1,1,1])
        [ 100, { prop: 100 } ]
        >

        */

        console.log(rplc_updt_expr_with_closure(cd))


        /*
        function tst(arr) {
          let v = 100;
          let d = {
            prop: 100
          };
          arr = arr.forEach(nd => {
            v = (() => {
              let old_val = v;
              let new_val = old_val + 1;
              v = new_val;
              return old_val;                                    // v++  postfix-rtrn-old
            })();

            v = (() => {
              let old_val = v;
              let new_val = old_val - 1;
              v = new_val;
              return old_val;                                  //v--   postfix-rtrn-old
            })();

            v = (() => {
              let old_val = v;
              let new_val = old_val + 1;
              v = new_val;
              return new_val;                                 //++v  prefix-rtrn-new
            })();

            (() => {
              let old_val = v;
              let new_val = old_val - 1;
              v = new_val;
              return new_val;                                  //--v  prefix-rtrn-new
            })();

            (() => {
              let old_val = d.prop;
              let new_val = old_val + 1;
              d.prop = new_val;
              return old_val;
            })();

            d.prop = (() => {
              let old_val = d.prop;
              let new_val = old_val + 1;
              d.prop = new_val;
              return new_val;
            })();

            (() => {
              let old_val = d.prop;
              let new_val = old_val - 1;
              d.prop = new_val;
              return old_val;
            })();

            d.prop = (() => {
              let old_val = d.prop;
              let new_val = old_val - 1;
              d.prop = new_val;
              return new_val;
            })();
          });
          return [v, d];
        }

        */

        > tst([1,1,1])
        [ 100, { prop: 100 } ]
        >

###  get\_completion\_parent\_nd
- get the completion parent closure/block of
- return/throw/break/continue


####


        var src = `
        function tst() {
            var m=0
            xx:while(m<3){
                console.log("here")
                i = 0;
                n = 0;
                while (i < 5) {
                   i++;
                   if (i === 3) {
                      continue xx;
                   }
                   n += i;
                }
                m=m+1
            }
            function inner() {
                for(let i=0;i<5;i++){
                    break
                    return(i)
                }
            }
        }
        `

        //return

        var t = tree(src);
        var rtrn_stmt = t.ReturnStatement()[0];
        > rtrn_stmt
         [69:                            body[1] <ReturnStatement> {}] {}
        >
        > var completion = rtrn_stmt.get_completion_parent_nd()

        > completion
         [54:            body[2] <FunctionDeclaration> {"generator":false,"async":false}] {}
        >
        > completion.show_code()
        function inner() {
          for (let i = 0; i < 5; i++) {
            break;
            return i;
          }
        }


        //break
        > var brk_stmt = t.BreakStatement()[0]

        > brk_stmt
         [68:                            body[0] <BreakStatement> {}] {}
        >
        > var completion = brk_stmt.get_completion_parent_nd()
        > completion
         [57:                    body[0] <ForStatement> {}] {}
        > completion.show_code()
        for (let i = 0; i < 5; i++) {
          break;
          return i;
        }


        //continue label

        > var conti_stmt = t.ContinueStatement()[0]
        undefined
        > conti_stmt
         [42:                                        body[0] <ContinueStatement> {}] {}
        >
        > var completion = conti_stmt.get_completion_parent_nd()
        undefined
        > completion
         [10:                body <WhileStatement> {}] {}
        >
        > completion.show_code()
        while (m < 3) {
          console.log("here");
          i = 0;
          n = 0;

          while (i < 5) {
            i++;

            if (i === 3) {
              continue xx;
            }

            n += i;
          }

          m = m + 1;
        }
        > completion.$parent()
         [8:            body[1] <LabeledStatement> {}] {}
        > completion.$parent().show_code()
        xx: while (m < 3) {
          console.log("here");
          i = 0;
          n = 0;

          while (i < 5) {
            i++;

            if (i === 3) {
              continue xx;
            }

            n += i;
          }

          m = m + 1;
        }

### get\_completion\_check\_points
- find break/continue  's corresponding  block/forin/forof/for/while/dowhile/switch
- find return/throw    's corresponding  func-decl/func-expr/cls-method/obj-method/arrow/cls-priv-method 


####


        var src = `
        function tst() {
            while(true) {
                return(100)
            }
            try {
                return(200)
            } catch(e) {
                 ()=> {
                     return('!!')
                 }
            } finally {
            }
            {
               throw(400)
            }
        }`

        > var t = tree(src)
        > t.FunctionDeclaration()[0]
         [1:    body[0] <FunctionDeclaration> {"generator":false,"async":false}] {}
        > var fdecl = t.FunctionDeclaration()[0]
        > fdecl.get_rtrn_check_points()
        [
          ‍ [7:                    body[0] <ReturnStatement> {}] {},
          ‍ [11:                    body[0] <ReturnStatement> {}] {}
        ]
        > var rtrns = fdecl.get_rtrn_check_points()
        > rtrns
        [
          ‍ [7:                    body[0] <ReturnStatement> {}] {},
          ‍ [11:                    body[0] <ReturnStatement> {}] {}
        ]
        > rtrns.map(nd=>nd.show_code())
        return 100;
        return 200;


rm\_sibs\_after\_completion
----------------------------
- remove following-sibs of completion-node ,see below  

###

        var src = `
        function tst() {
            try {
               let a = 1;
               return(a);
               let b = a*2;
               console.log(b)               //-----------------------------remove
            } catch(e) {
               LBL:for(let a in M) {
                 while(true) {
                      if(x) {
                          break;
                          console.log(x)     //-----------------------------remove
                      } else if(y) {
                           continue LBL;
                           console.log(666)   //-----------------------------remove
                      } else {
                           switch(XX) {
                              case(0): {
                              }
                              case(1): {
                                  break;
                                  console.log(UUU)  //-----------------------------remove
                              }
                           }
                      }
                 }
              }
            }
        }
        `

        console.log(x.rm_sibs_after_completion(src))


        /*
        function tst() {
          try {
            let a = 1;
            return a;
          } catch (e) {
            LBL: for (let a in M) {
              while (true) {
                if (x) {
                  break;
                } else if (y) {
                  continue LBL;
                } else {
                  switch (XX) {
                    case 0:
                      {}

                    case 1:
                      {
                        break;
                      }
                  }
                }
              }
            }
          }
        }

        */


### tailize\_try\_catch\_final

#### why
- finalizer of try-statement is confusing
- its write-order is at last, but its executing order is just before return/throw in try/catch
- but the write-order of try/catch is BEFORE finalizer
- I can NOT  understand this
- so transform the finalizer AND make it "reasonable" 

#### example

        > function tst() {
        ...     try {
        .....         console.log(`before-return-in-try`)
                                                             //<====  #0
        .....         return(`i-am-returned`)
        .....     } finally {
        .....         console.log(`finalizer write after try-block`)
        .....     }
        ... }
        >
        > tst()
        before-return-in-try
        finalizer write after try-block   // 
        'i-am-returned'
        >
        >



#### step
- 1. this will take the return-statement|throw-statement out from try-stmt-block|try-catch-handler
- 2. convert 【return-statement|throw-statement in 1.】 to a 【if/esle block】
- 3. convert try-stmt-finalizer to 【a block】 
- 4. delete the original try-stmt-finalizer
- 5. put the 【if/esle block in 2.】 after 【converted-block-from-try-stmt-finalizer in 3.】 
- 6. generate a 【block-contain-return|throw】
- 7. put the 【block-contain-return|throw in 6.】 at end

#### purpose
- its purpose is to tailized rtrn/thrw of try-stmt AND transform the finalizer to its proper position
- to make the write/read order same-as the execution-order
- coz, the finally block is boring for static-tracing 
- hard to explain , just see the below examples,example is easy to understand

#### input 

        var src =`
        function tst() {
            let a = 100;

                try {
                    let a = (()=>{
                            try {
                                    throw(1);
                                        console.log("unreachable")
                                } catch(e) {
                                    return(e);
                                        console.log("unreachable")
                                } finally {
                                    console.log('inner')
                                }
                        })();
                        if(a>0) {
                                return(a*2);
                                console.log("unreachable")
                        } else {
                            return(a*3)
                                console.log("unreachable")
                        }

                } catch ({e}) {
                    console.log("unreachable")
                } finally {
                    let arr = [a,a*2,a*3]
                    console.log(arr)
                }

                let c = a*3;
                return(c)

        }
        `


        /*
        > tst()
        inner
        [ 100, 200, 300 ]
        2
        >

        */



#### output


       > console.log(x.tailize_try_catch_final(src))


        function tst() {
          let a = 100;
          //outer-try-catch-final
          {
            let ___τfinalización = [undefined, undefined];
            //outer-try-block
            {
              let a = (() => {
                //inner-  try-catch-final
                {
                  let ___τfinalización = [undefined, undefined];
                  //inner-try-block
                  {
                    ___τfinalización = [false, 1];
                  }
                  //inner-catch-handle
                  if (___τfinalización[0] === false) {
                    let ___τcatch_clause_value = ___τfinalización[1];
                    {
                      let e = ___τcatch_clause_value;
                      ___τfinalización = [true, e];
                    }
                  } else {}
                  //inner-final-block
                  {
                    console.log('inner');
                  }
                  //inner-tailized-completion-of-try-catch-final-stmt
                  if (___τfinalización[0] === undefined) {} else if (___τfinalización[0] === true) {
                    return ___τfinalización[1];
                  } else {
                    throw ___τfinalización[1];
                  }
                }
              })();

              if (a > 0) {
                ___τfinalización = [true, a * 2];
              } else {
                ___τfinalización = [true, a * 3];
              }
            }

            //outer-catch-handle
            if (___τfinalización[0] === false) {
              let ___τcatch_clause_value = ___τfinalización[1];
              {
                let {
                  e
                } = ___τcatch_clause_value;
                console.log("unreachable");
              }
            } else {}
            
            //outer-final-block
            {
              let arr = [a, a * 2, a * 3];
              console.log(arr);
            }

            //out-tailized-completion-of-try-catch-final-stmt
            if (___τfinalización[0] === undefined) {} else if (___τfinalización[0] === true) {
              return ___τfinalización[1];
            } else {
              throw ___τfinalización[1];
            }
          }
          let c = a * 3;
          return c;
        }


        /*
        > tst()
        inner
        [ 100, 200, 300 ]
        2
        >

        */


### fmt-asgn-expr
- must used after split\_var\_decl  AND split\_var\_declor

####  

     replace the below with a = a<op> b

          OP_TO_BINOP: {
            '+=': '+',
            '-=': '-',
            '/=': '/',
            '%=': '%',
            '*=': '*',
            '**=': '**',
            '&=': '&',
            '|=': '|',
            '>>=': '>>',
            '>>>=': '>>>',
            '<<=': '<<',
            '^=': '^',
            '||=': '||',
            '&&=': '&&',
            '??=': '??'
          },

      for example:
           a+=999
           will be replaced to 
              a = a + 999;
    
      this is for functionize-bin-operator, which will remove all bin-operator
      normally useless

####      


        var  cd =`
            function tst() {
                let a=10;
                a+=8;
                {
                    a-=a*2;
                    function inner() {
                      return(a = a / a);
                    }
                    a**=inner()
                }
                return(a)
            }
        `

        console.log(x.fmt_asgn_expr(cd))
        /*
            function tst() {
              let a = 10;
              a = a + 8;
              {
                a = a - a * 2;

                function inner() {
                  return a = a / a;
                }

                a = a ** inner();
              }
              return a;
            }        
        */


### funcize-bin-expr
- convert binary-expr to a function, such as  a+b , a-b ...
- it is pre-step for converting javascript to a list-format (which can be describe in a list-only-style-ast)
- this list-format can-be interpreted char-by-char from remote js-source input without handling precedence
- normally useless


####


        var cd = `
        function tst() {
            let c = a+b;
            {
                let e = c - d;
                function inner() {
                   return(e/f)
                }
                let g = inner();
                h = g % i *j ** k & l | m >> n >>> o << p ^ q == r === s != t !== u in v instanceof w > x < y >= z <= $;
                return(h)
            }
        }
        `

        console.log(funcize_bin_expr(cd))

        //// <@nv-binop-func>
        const ___add = (a,b)=>a+b;
        const ___sub = (a,b)=>a-b;
        const ___div = (a,b)=>a/b;
        const ___mod = (a,b)=>a%b;
        const ___mul = (a,b)=>a*b;
        const ___pow = (a,b)=>a**b;
        const ___band = (a,b)=>a&b;
        const ___bor = (a,b)=>a|b;
        const ___shr = (a,b)=>a>>b;
        const ___ushr = (a,b)=>a>>>b;
        const ___shl = (a,b)=>a<<b;
        const ___bxor = (a,b)=>a^b;
        const ___eq = (a,b)=>a==b;
        const ___teq = (a,b)=>a===b;
        const ___neq = (a,b)=>a!=b;
        const ___nteq = (a,b)=>a!==b;
        const ___in = (a,b)=>(a in b);
        const ___instof = (a,b)=>(a instanceof b);
        const ___gt = (a,b)=>a>b;
        const ___lt = (a,b)=>a<b;
        const ___ge = (a,b)=>a>=b;
        const ___le = (a,b)=>a<=b;

        const ___lor=(a,b)=>a||b;
        const ___land=(a,b)=>a&&b;
        const ___nc=(a,b)=>a??b;
        

        //// </@nv-binop-func>


        function tst() {
          let c = ___add(a, b);

          {
            let e = ___sub(c, d);

            function inner() {
              return ___div(e, f);
            }

            let g = inner();
            h = ___bor(
                  ___band(
                      ___mul(
                          ___mod(g, i),
                          ___pow(j, k)
                      ),
                      l
                  ),
                  ___bxor(
                      ___shl(
                          ___ushr(
                              ___shr(m, n),
                              o
                          ),
                          p
                      ),
                      ___nteq(
                          ___neq(
                              ___teq(
                                  ___eq(q, r),
                                  s
                              ),
                              t
                          ),
                          ___le(
                              ___ge(
                                  ___lt(
                                      ___gt(
                                          ___instof(
                                              ___in(u, v),
                                              w
                                          ),
                                          x
                                      ),
                                      y
                                  ),
                                  z
                             ),
                             $
                        )
                      )
                    )
                );
            return h;
          }
        }


### json-literal
- if nd is a json-literal 
- json-literal matches the below condition

####

      0.  the node must be 
          ObjectExpression OR 
          ArrayExpression  OR
          NullLiteral      OR
          BooleanLiteral   OR
          StringLiteral    OR
          NumericLiteral   

      1.  only  


        NumericLiteral  OR
        BooleanLiteral  OR
        NullLiteral     OR
        StringLiteral   OR 
        Identifier      OR
        NumericLiteral  OR
        ArrayExpression OR
        ObjectProperty  

        permitted in the des-tree 

      2. if Identifier
         
         the Identifier must be key-of-ObjectProperty  AND
         the-parent-ObjectProperty's computed === false AND
         the-parent-ObjectProperty's shorthand === false 


####

        > var t = tree(`let ___json___ ={a:100,"b":[1,true,false,null,'str'],["c"]:3333,5555:5555}`)
        > var nd = t.$sdfs()[4];
        > nd.to_json_if_json_lit()
        { '5555': 5555, a: 100, b: [ 1, true, false, null, 'str' ], c: 3333 }
        >


### pure template literal
      0. all the expressions must be one of:
	 
          BigIntLiteral
	  BooleanLiteral
	  NullLiteral
	  NumericLiteral
	  RegExpLiteral
	  StringLiteral  
                   
          UndefinedRefToGlobal  
          JSONliteral         

          PureTemplateLiteral  // recursive  

      this is for reduce unecessary  nodes in compile-time 


####

		 var t = tree("`${[1,2,3]}`")
		 var tmplit = t.TemplateLiteral()[0];
		 tmplit.get_cond_pair_for_pure_tmplit()
		 > [ true, '1,2,3' ]
		 
		 var t = tree("`a${[1,2,3]}`")
		 var tmplit = t.TemplateLiteral()[0];
		 tmplit.get_cond_pair_for_pure_tmplit()
		 > [ true, 'a1,2,3' ]
		 
		 var t = tree("`${[1,2,3]}b`")
		 var tmplit = t.TemplateLiteral()[0];
		 tmplit.get_cond_pair_for_pure_tmplit() 
		 > [ true, '1,2,3b' ]
		 
		 var t = tree("`a${[1,2,3]}b`")
		 var tmplit = t.TemplateLiteral()[0];
		 tmplit.get_cond_pair_for_pure_tmplit() 
		 > [ true, 'a1,2,3b' ]
		 
		 
		 var t = tree("`m ${`x ${[1,2,3]} yz`} n`")
		 var tmplit = t.TemplateLiteral()[0];
		 /*
		    > `m ${`x ${[1,2,3]} yz`} n`
		    'm x 1,2,3 yz n'
		    > 
		    > tmplit.get_cond_pair_for_pure_tmplit()
		    [ true, 'm x 1,2,3 yz n' ]
		    > 
		    > 
		 */             

		> x.rplc_pure_temlit_with_str_lit("let V  = `m ${`x ${[1,2,3]} yz`} n`")
		'let V = "m x 1,2,3 yz n";'
		> 


### cls\_find\_same\_name\_gtst\_mthds

      //FIND methods ARE (BOTH setter AND getter) (VIA method-name) IF (method key-node is NOT expr)

    var cd =`
    class Cls {
        get get_only() {}
        method() {}
        ////
        get gt1() {}
        set ["gt1"](v) {}
        ////
        method2() {}
        set set_only(v) {}
        ////
        get [100]() {}
        set ["100"](v) {}
        ////
    }
    `
    var t = tree(cd);

    > t.cls_find_same_name_gtst_mthds()
    Map(1) {
      ‍ [3:        body <ClassBody> {}] {} => {
        '100': {
          getter: ‍ [24:            body[6] <ClassMethod> {"generator":false,"async":false,"static":false,"computed":true,"kind":"get"}] {},
          setter: ‍ [27:            body[7] <ClassMethod> {"generator":false,"async":false,"static":false,"computed":true,"kind":"set"}] {}
        },
        gt1: {
          getter: ‍ [10:            body[2] <ClassMethod> {"generator":false,"async":false,"static":false,"computed":false,"kind":"get"}] {},
          setter: ‍ [13:            body[3] <ClassMethod> {"generator":false,"async":false,"static":false,"computed":true,"kind":"set"}] {}
        }
      }
    }
    > 
   

### find import-source/import-arg/require-arg

        var cd =`
        const babel = require("@babel/parser");
        function wrap() {
             const _cjs_loader = require('internal/modules/cjs/loader');
        }
        import defaultExport1 from "module-name1";
        import * as name2 from "module-name2";
        import { export3 } from "module-name3";
        import { export4 as alias } from "module-name4";
        import { export50 , export51 } from "module-name5";
        import { foo , bar } from "module-name/path/to/specific/un-exported/file";
        import defaultExport6, * as name from "module-name6";
        import "module-name7";
        var promise = import("module-name8");
        `;

        x.get_non_dynamic_impt_and_require_src(cd)

        > x.get_non_dynamic_impt_and_require_src(cd)
        [
          '@babel/parser',
          'internal/modules/cjs/loader',
          'module-name1',
          'module-name2',
          'module-name3',
          'module-name4',
          'module-name5',
          'module-name/path/to/specific/un-exported/file',
          'module-name6',
          'module-name7',
          'module-name8'
        ]
        >

### try-spread-if-can

     remove redudancy ary-ptrn OR ary-expr:
               

	var cd = `
	    const [a,b,...[c,d]] = [1,2,3,4,5];
		{
			 let v = [a,b,...[c,d]]
		}
	`

	console.log(try_spread_if_can(cd))
	/*
	const [a, b, c, d] = [1, 2, 3, 4, 5];
	{
	  let v = [a, b, c, d];
	}

	*/

###  find all bad access before initialization id    


		var {find_all_bad_access_before_initialization_id} = require("./index")
		var cd = `
		var outter = 999;
		function tst(es) { 
		    outter = 888;
		    {
			a = es[0];
			let es = [1,2,3];
		    }
		    let outter;
		    return(outter)
		}
		/*
		tst([11,22])
		ReferenceError: Cannot access 'outter' before initialization
		    at tst (REPL30:2:12)

		*/
		`


		var bad = find_all_bad_access_before_initialization_id(cd)

		/*
		[
		  {
		    defined_at: [ [ 9, 8 ], [ 9, 14 ], 'outter' ],
		    access_at: [ [ 4, 4 ], [ 4, 10 ], 'outter = 888' ],
		    scope_code: 'function tst(es) {\n' +
		      '  outter = 888;\n' +
		      '  {\n' +
		      '    a = es[0];\n' +
		      '    let es = [1, 2, 3];\n' +
		      '  }\n' +
		      '  let outter;\n' +
		      '  return outter;\n' +
		      '}'
		  },
		  {
		    defined_at: [ [ 7, 12 ], [ 7, 14 ], 'es = [1, 2, 3]' ],
		    access_at: [ [ 6, 12 ], [ 6, 14 ], 'es[0]' ],
		    scope_code: '{\n  a = es[0];\n  let es = [1, 2, 3];\n}'
		  }
		]
		*/


###

            // just for repl testing  in  nvlang,  USELESS 

            allow struct 

            struct C {}   IS SAME AS
            class  C {}

###

            // just for repl testing in nvtype , USELESS

            allow generic Type with constructor, the velow is valid
               class C {
                   constructor<T1,T2,T3>(p0:T1|T2,p1:T2|T3) {}  
               }


API
====
- tree(code)
- parse(code)
- unparse(ast)
- pprint\_ast(ast)                                                      //add default dark style color for print
- light\_code(code,color\_dict,decoratorsBeforeExport=true,rtrn=false)  //self-define node color


- const2let(code) 
- hoist\_func\_decl(code)
- fdecl2fexpr(code)
- cdecl2cexpr(code)
- split\_var\_decl(code)
- split\_var\_declor(code)
- hoist\_var(code)
- split\_nonidlval\_asgn\_expr(code)
- merge\_dupe\_var\_decl(code)
- var\_to\_let(code)
- split\_rtrn\_stmt(code)
- split\_thrw\_stmt(code)
- rplc\_nodecl\_undef\_with\_void0(code)
- for\_stmt\_to\_while(code)
- rm\_sibs\_after\_completion(code)
- tailize\_try\_catch\_final(code)
- fmt\_asgn\_expr(code)
- funcize\_bin\_expr(code)



- get\_non\_dynamic\_impt\_and\_require\_src(code)

LICENSE
=======
- ISC

---
_Source: https://npm.io/package/nv-js-parse · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
