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

Usage no npm install needed!

<script type="module">
  import nvJsParse from 'https://cdn.skypack.dev/nv-js-parse';
</script>

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

install

  • npm install nv-js-parse

usage

basic

const {tree,parse,unparse} = 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___;

        ___swapper_b1cf8a9c_$AssignmentExpression___ = undefined;

    */

          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___;
          ___swapper_ec071153_$AssignmentExpression___ = undefined;
          let ___swapper_fcc8fd5d_$AssignmentExpression___ = [10, {
            v: 20
          }];
          [u, {
            v
          }, ...X] = ___swapper_fcc8fd5d_$AssignmentExpression___;
          ___swapper_fcc8fd5d_$AssignmentExpression___ = undefined;
          let A;
          B = D = E = 1111;
        }
      }
      let ___swapper_b72b9d99_$AssignmentExpression___ = [10, {
        w: 20,
        r: 30
      }];
      [z, {
        w,
        r
      }] = ___swapper_b72b9d99_$AssignmentExpression___;
      ___swapper_b72b9d99_$AssignmentExpression___ = undefined;
    }
    */

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;
        }
      }
    

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,false/*delete loc info*/);
    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,"typescript",true/*enable_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' }
              ]
            ]
          ]
        ]
      ]
    

API

  • parse(code)
  • unparse(ast)
  • 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)
  • tree(code)

LICENSE

  • ISC