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 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
- this will take the return-statement|throw-statement out from try-stmt-block|try-catch-handler
- convert 【return-statement|throw-statement in 1.】 to a 【if/esle block】
- convert try-stmt-finalizer to 【a block】
- delete the original try-stmt-finalizer
- put the 【if/esle block in 2.】 after 【converted-block-from-try-stmt-finalizer in 3.】
- generate a 【block-contain-return|throw】
- 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