webpack/test/JavascriptParser.unittest.js

742 lines
20 KiB
JavaScript
Raw Normal View History

2017-01-18 22:24:20 +08:00
"use strict";
2013-01-31 01:49:25 +08:00
const BasicEvaluatedExpression = require("../lib/javascript/BasicEvaluatedExpression");
2019-10-11 21:46:57 +08:00
const JavascriptParser = require("../lib/javascript/JavascriptParser");
2017-01-18 22:24:20 +08:00
2018-07-03 16:15:48 +08:00
describe("JavascriptParser", () => {
2017-11-15 21:08:11 +08:00
/* eslint-disable no-undef */
/* eslint-disable no-unused-vars */
/* eslint-disable no-inner-declarations */
2017-01-18 22:24:20 +08:00
const testCases = {
2013-01-31 01:49:25 +08:00
"call ident": [
2020-03-29 06:10:15 +08:00
function () {
2013-01-31 01:49:25 +08:00
abc("test");
2018-02-25 18:46:17 +08:00
},
{
2013-01-31 01:49:25 +08:00
abc: ["test"]
}
],
"call member": [
2020-03-29 06:10:15 +08:00
function () {
2013-01-31 01:49:25 +08:00
cde.abc("membertest");
2018-02-25 18:46:17 +08:00
},
{
2013-01-31 01:49:25 +08:00
cdeabc: ["membertest"]
}
],
"call member using bracket notation": [
2020-03-29 06:10:15 +08:00
function () {
cde["abc"]("membertest");
2018-02-25 18:46:17 +08:00
},
{
cdeabc: ["membertest"]
}
],
2013-01-31 01:49:25 +08:00
"call inner member": [
2020-03-29 06:10:15 +08:00
function () {
2013-01-31 01:49:25 +08:00
cde.ddd.abc("inner");
2018-02-25 18:46:17 +08:00
},
{
2013-01-31 01:49:25 +08:00
cdedddabc: ["inner"]
}
],
"call inner member using bracket notation": [
2020-03-29 06:10:15 +08:00
function () {
cde.ddd["abc"]("inner");
2018-02-25 18:46:17 +08:00
},
{
cdedddabc: ["inner"]
}
],
2018-02-25 18:46:17 +08:00
expression: [
2020-03-29 06:10:15 +08:00
function () {
2013-01-31 01:49:25 +08:00
fgh;
2018-02-25 18:46:17 +08:00
},
{
2013-01-31 01:49:25 +08:00
fgh: [""]
}
],
"expression sub": [
2020-03-29 06:10:15 +08:00
function () {
2013-01-31 01:49:25 +08:00
fgh.sub;
2018-02-25 18:46:17 +08:00
},
{
2013-01-31 01:49:25 +08:00
fghsub: ["notry"]
}
],
"member expression": [
2020-03-29 06:10:15 +08:00
function () {
2017-11-15 21:08:11 +08:00
test[memberExpr];
test[+memberExpr];
2018-02-25 18:46:17 +08:00
},
{
expressions: ["memberExpr", "memberExpr"]
}
],
2013-01-31 01:49:25 +08:00
"in function definition": [
2020-03-29 06:10:15 +08:00
function () {
(function (abc, cde, fgh) {
2013-01-31 01:49:25 +08:00
abc("test");
cde.abc("test");
cde.ddd.abc("test");
fgh;
fgh.sub;
})();
2018-02-25 18:46:17 +08:00
},
{}
2013-01-31 01:49:25 +08:00
],
2017-01-18 22:24:20 +08:00
"const definition": [
2020-03-29 06:10:15 +08:00
function () {
2017-01-18 22:24:20 +08:00
let abc, cde, fgh;
2013-01-31 01:49:25 +08:00
abc("test");
cde.abc("test");
cde.ddd.abc("test");
fgh;
fgh.sub;
2018-02-25 18:46:17 +08:00
},
{}
2013-01-31 01:49:25 +08:00
],
2017-01-24 17:39:17 +08:00
"var definition": [
2020-03-29 06:10:15 +08:00
function () {
2017-01-25 20:43:17 +08:00
var abc, cde, fgh;
2017-01-24 17:39:17 +08:00
abc("test");
cde.abc("test");
cde.ddd.abc("test");
fgh;
fgh.sub;
2018-02-25 18:46:17 +08:00
},
{}
2017-01-24 17:39:17 +08:00
],
2013-01-31 01:49:25 +08:00
"function definition": [
2020-03-29 06:10:15 +08:00
function () {
2013-01-31 01:49:25 +08:00
function abc() {}
2015-08-09 18:42:43 +08:00
2013-01-31 01:49:25 +08:00
function cde() {}
2015-08-09 18:42:43 +08:00
2013-01-31 01:49:25 +08:00
function fgh() {}
abc("test");
cde.abc("test");
cde.ddd.abc("test");
fgh;
fgh.sub;
2018-02-25 18:46:17 +08:00
},
{}
2013-01-31 01:49:25 +08:00
],
2017-12-30 23:27:17 +08:00
"class definition": [
2020-03-29 06:10:15 +08:00
function () {
2017-12-30 23:27:17 +08:00
class memberExpr {
cde() {
abc("cde");
}
static fgh() {
abc("fgh");
fgh();
}
}
2018-02-25 18:46:17 +08:00
},
{
2017-12-30 23:27:17 +08:00
abc: ["cde", "fgh"],
fgh: ["memberExpr"]
}
],
2013-01-31 01:49:25 +08:00
"in try": [
2020-03-29 06:10:15 +08:00
function () {
2013-01-31 01:49:25 +08:00
try {
fgh.sub;
fgh;
2015-08-09 18:42:43 +08:00
2013-01-31 01:49:25 +08:00
function test(ttt) {
fgh.sub;
fgh;
}
2018-02-25 18:46:17 +08:00
} catch (e) {
2013-01-31 01:49:25 +08:00
fgh.sub;
fgh;
}
2018-02-25 18:46:17 +08:00
},
{
2013-01-31 01:49:25 +08:00
fghsub: ["try", "notry", "notry"],
fgh: ["test", "test ttt", "test e"]
2013-01-31 01:49:25 +08:00
}
],
2017-01-18 22:24:20 +08:00
"renaming with const": [
2020-03-29 06:10:15 +08:00
function () {
2017-01-18 22:24:20 +08:00
const xyz = abc;
xyz("test");
2018-02-25 18:46:17 +08:00
},
{
abc: ["test"]
}
],
2017-01-24 17:39:17 +08:00
"renaming with var": [
2020-03-29 06:10:15 +08:00
function () {
2017-01-25 20:43:17 +08:00
var xyz = abc;
2017-01-24 17:39:17 +08:00
xyz("test");
2018-02-25 18:46:17 +08:00
},
{
2017-01-24 17:39:17 +08:00
abc: ["test"]
}
],
"renaming with assignment": [
2020-03-29 06:10:15 +08:00
function () {
2017-01-18 22:24:20 +08:00
const xyz = abc;
xyz("test");
2018-02-25 18:46:17 +08:00
},
{
abc: ["test"]
}
],
"renaming with IIFE": [
2020-03-29 06:10:15 +08:00
function () {
!(function (xyz) {
xyz("test");
2018-02-25 18:46:17 +08:00
})(abc);
},
{
abc: ["test"]
}
],
2017-06-16 21:31:45 +08:00
"renaming arguments with IIFE (called)": [
2020-03-29 06:10:15 +08:00
function () {
!function (xyz) {
xyz("test");
}.call(fgh, abc);
2018-02-25 18:46:17 +08:00
},
{
abc: ["test"],
fgh: [""]
}
],
2017-06-16 21:31:45 +08:00
"renaming this's properties with IIFE (called)": [
2020-03-29 06:10:15 +08:00
function () {
!function () {
2017-06-16 21:31:45 +08:00
this.sub;
}.call(ijk);
2018-02-25 18:46:17 +08:00
},
{
2017-06-16 21:31:45 +08:00
ijksub: ["test"]
}
],
"renaming this's properties with nested IIFE (called)": [
2020-03-29 06:10:15 +08:00
function () {
!function () {
!function () {
this.sub;
}.call(this);
}.call(ijk);
2018-02-25 18:46:17 +08:00
},
{
ijksub: ["test"]
}
],
"new Foo(...)": [
2020-03-29 06:10:15 +08:00
function () {
2017-12-05 10:40:23 +08:00
new xyz("membertest");
2018-02-25 18:46:17 +08:00
},
{
xyz: ["membertest"]
}
],
2017-12-30 23:27:17 +08:00
"spread calls/literals": [
2020-03-29 06:10:15 +08:00
function () {
2017-12-30 23:27:17 +08:00
var xyz = [...abc("xyz"), cde];
Math.max(...fgh);
2018-02-25 18:46:17 +08:00
},
{
2017-12-30 23:27:17 +08:00
abc: ["xyz"],
fgh: ["xyz"]
}
]
2013-01-31 01:49:25 +08:00
};
2017-11-15 21:08:11 +08:00
/* eslint-enable no-undef */
/* eslint-enable no-unused-vars */
/* eslint-enable no-inner-declarations */
2013-01-31 01:49:25 +08:00
2018-02-25 18:46:17 +08:00
Object.keys(testCases).forEach(name => {
2017-01-18 22:24:20 +08:00
it("should parse " + name, () => {
let source = testCases[name][0].toString();
2013-01-31 01:49:25 +08:00
source = source.substr(13, source.length - 14).trim();
2017-01-18 22:24:20 +08:00
const state = testCases[name][1];
2013-01-31 01:49:25 +08:00
2018-07-03 16:15:48 +08:00
const testParser = new JavascriptParser({});
2019-07-24 16:51:04 +08:00
testParser.hooks.canRename
.for("abc")
.tap("JavascriptParserTest", expr => true);
testParser.hooks.canRename
.for("ijk")
.tap("JavascriptParserTest", expr => true);
testParser.hooks.call.for("abc").tap("JavascriptParserTest", expr => {
2018-02-25 18:46:17 +08:00
if (!testParser.state.abc) testParser.state.abc = [];
2017-01-18 22:24:20 +08:00
testParser.state.abc.push(testParser.parseString(expr.arguments[0]));
2013-01-31 01:49:25 +08:00
return true;
});
2019-07-24 16:51:04 +08:00
testParser.hooks.call.for("cde.abc").tap("JavascriptParserTest", expr => {
2018-02-25 18:46:17 +08:00
if (!testParser.state.cdeabc) testParser.state.cdeabc = [];
2017-01-18 22:24:20 +08:00
testParser.state.cdeabc.push(testParser.parseString(expr.arguments[0]));
2013-01-31 01:49:25 +08:00
return true;
});
2019-07-24 16:51:04 +08:00
testParser.hooks.call
.for("cde.ddd.abc")
.tap("JavascriptParserTest", expr => {
if (!testParser.state.cdedddabc) testParser.state.cdedddabc = [];
testParser.state.cdedddabc.push(
testParser.parseString(expr.arguments[0])
);
return true;
});
testParser.hooks.expression
.for("fgh")
.tap("JavascriptParserTest", expr => {
if (!testParser.state.fgh) testParser.state.fgh = [];
testParser.state.fgh.push(
Array.from(testParser.scope.definitions.asSet()).join(" ")
);
return true;
});
testParser.hooks.expression
.for("fgh.sub")
.tap("JavascriptParserTest", expr => {
2018-07-03 16:15:48 +08:00
if (!testParser.state.fghsub) testParser.state.fghsub = [];
testParser.state.fghsub.push(
testParser.scope.inTry ? "try" : "notry"
);
return true;
2019-07-24 16:51:04 +08:00
});
testParser.hooks.expression
.for("ijk.sub")
.tap("JavascriptParserTest", expr => {
2018-07-03 16:15:48 +08:00
if (!testParser.state.ijksub) testParser.state.ijksub = [];
testParser.state.ijksub.push("test");
return true;
2019-07-24 16:51:04 +08:00
});
testParser.hooks.expression
.for("memberExpr")
.tap("JavascriptParserTest", expr => {
2018-07-03 16:15:48 +08:00
if (!testParser.state.expressions) testParser.state.expressions = [];
testParser.state.expressions.push(expr.name);
return true;
2019-07-24 16:51:04 +08:00
});
2018-07-03 16:15:48 +08:00
testParser.hooks.new.tap("xyz", "JavascriptParserTest", expr => {
2018-02-25 18:46:17 +08:00
if (!testParser.state.xyz) testParser.state.xyz = [];
testParser.state.xyz.push(testParser.parseString(expr.arguments[0]));
return true;
});
const actual = testParser.parse(source, {});
2018-01-24 20:17:21 +08:00
expect(typeof actual).toBe("object");
expect(actual).toEqual(state);
2013-01-31 01:49:25 +08:00
});
});
2017-01-18 22:24:20 +08:00
it("should parse comments", () => {
const source = "//comment1\n/*comment2*/";
2018-02-25 18:46:17 +08:00
const state = [
{
type: "Line",
value: "comment1"
},
{
type: "Block",
value: "comment2"
}
];
2018-07-03 16:15:48 +08:00
const testParser = new JavascriptParser({});
2018-07-03 16:15:48 +08:00
testParser.hooks.program.tap("JavascriptParserTest", (ast, comments) => {
2018-02-25 18:46:17 +08:00
if (!testParser.state.comments) testParser.state.comments = comments;
return true;
});
const actual = testParser.parse(source, {});
2018-01-24 20:17:21 +08:00
expect(typeof actual).toBe("object");
expect(typeof actual.comments).toBe("object");
2017-01-18 22:24:20 +08:00
actual.comments.forEach((element, index) => {
2018-01-24 20:17:21 +08:00
expect(typeof element.type).toBe("string");
expect(typeof element.value).toBe("string");
expect(element.type).toBe(state[index].type);
expect(element.value).toBe(state[index].value);
});
});
2017-01-18 22:24:20 +08:00
describe("expression evaluation", () => {
2013-01-31 01:49:25 +08:00
function evaluateInParser(source) {
2018-07-03 16:15:48 +08:00
const parser = new JavascriptParser();
2019-07-24 16:51:04 +08:00
parser.hooks.call.for("test").tap("JavascriptParserTest", expr => {
2017-01-18 22:24:20 +08:00
parser.state.result = parser.evaluateExpression(expr.arguments[0]);
});
parser.hooks.evaluateIdentifier
.for("aString")
2019-07-24 16:51:04 +08:00
.tap("JavascriptParserTest", expr =>
2018-07-03 16:15:48 +08:00
new BasicEvaluatedExpression()
.setString("aString")
.setRange(expr.range)
);
parser.hooks.evaluateIdentifier
.for("b.Number")
2019-07-24 16:51:04 +08:00
.tap("JavascriptParserTest", expr =>
2018-07-03 16:15:48 +08:00
new BasicEvaluatedExpression().setNumber(123).setRange(expr.range)
);
return parser.parse("test(" + source + ");", {}).result;
2013-01-31 01:49:25 +08:00
}
2017-01-18 22:24:20 +08:00
const testCases = {
true: "bool=true",
false: "bool=false",
"!true": "bool=false",
"!false": "bool=true",
2018-02-25 18:46:17 +08:00
'"strrring"': "string=strrring",
'"strr" + "ring"': "string=strrring",
'"s" + ("trr" + "rin") + "g"': "string=strrring",
2013-01-31 01:49:25 +08:00
"'S' + (\"strr\" + \"ring\") + 'y'": "string=Sstrrringy",
2017-04-13 20:52:49 +08:00
"/abc/": "regExp=/abc/",
2020-09-01 17:30:46 +08:00
1: "number=1",
2013-01-31 01:49:25 +08:00
"1 + 3": "number=4",
2017-04-13 20:52:49 +08:00
"3 - 1": "number=2",
"2 * 3": "number=6",
"8 / 2": "number=4",
"2 ** 3": "number=8",
"12 & 5": "number=4",
"12 | 5": "number=13",
"12 ^ 5": "number=9",
"9 >>> 2": "number=2",
"9 >> 2": "number=2",
"9 << 2": "number=36",
"~3": "number=-4",
2017-04-13 20:52:49 +08:00
"1 == 1": "bool=true",
"1 === 1": "bool=true",
"3 != 1": "bool=true",
"3 !== 1": "bool=true",
"3 == 1": "bool=false",
"3 === 1": "bool=false",
"1 != 1": "bool=false",
"1 !== 1": "bool=false",
2020-09-01 17:30:46 +08:00
100.25: "number=100.25",
2020-03-02 21:47:04 +08:00
"!100.25": "bool=false",
"!+100.25": "bool=false",
"!-100.25": "bool=false",
2020-09-01 17:30:46 +08:00
0: "number=0",
2020-03-02 21:47:04 +08:00
"!0": "bool=true",
"!-0": "bool=true",
"!+0": "bool=true",
"20n": "bigint=20",
"10n + 10n": "bigint=20",
"10n - 5n": "bigint=5",
"10n * 5n": "bigint=50",
"10n / 5n": "bigint=2",
"5n ** 2n": "bigint=25",
"5n == 5n": "bool=true",
"5n === 5n": "bool=true",
"5n != 5n": "bool=false",
"5n !== 5n": "bool=false",
"5n != 1n": "bool=true",
"5n !== 1n": "bool=true",
"5n & 3n": "bigint=1",
"5n | 2n": "bigint=7",
"5n ^ 2n": "bigint=7",
"5n >> 2n": "bigint=1",
"5n << 2n": "bigint=20",
"null == null": "bool=true",
"null === null": "bool=true",
"null != null": "bool=false",
"null !== null": "bool=false",
2017-04-13 20:52:49 +08:00
"true === false": "bool=false",
"false !== false": "bool=false",
"true == true": "bool=true",
"false != true": "bool=true",
"!'a'": "bool=false",
"!''": "bool=true",
"!null": "bool=true",
2015-02-28 08:42:09 +08:00
"'pre' + a": "wrapped=['pre' string=pre]+[null]",
"a + 'post'": "wrapped=[null]+['post' string=post]",
2013-01-31 01:49:25 +08:00
"'pre' + a + 'post'": "wrapped=['pre' string=pre]+['post' string=post]",
"1 + a + 2": "",
2015-02-28 08:42:09 +08:00
"1 + a + 'post'": "wrapped=[null]+['post' string=post]",
2013-01-31 01:49:25 +08:00
"'' + 1 + a + 2": "wrapped=['' + 1 string=1]+[2 string=2]",
"'' + 1 + a + 2 + 3": "wrapped=['' + 1 string=1]+[2 + 3 string=23]",
"'' + 1 + a + (2 + 3)": "wrapped=['' + 1 string=1]+[2 + 3 string=5]",
2018-02-25 18:46:17 +08:00
"'pre' + (1 + a) + (2 + 3)":
"wrapped=['pre' string=pre]+[2 + 3 string=5]",
2013-01-31 01:49:25 +08:00
"a ? 'o1' : 'o2'": "options=['o1' string=o1],['o2' string=o2]",
2018-02-25 18:46:17 +08:00
"a ? 'o1' : b ? 'o2' : 'o3'":
"options=['o1' string=o1],['o2' string=o2],['o3' string=o3]",
"a ? (b ? 'o1' : 'o2') : 'o3'":
"options=['o1' string=o1],['o2' string=o2],['o3' string=o3]",
"a ? (b ? 'o1' : 'o2') : c ? 'o3' : 'o4'":
"options=['o1' string=o1],['o2' string=o2],['o3' string=o3],['o4' string=o4]",
"a ? 'o1' : b ? 'o2' : c ? 'o3' : 'o4'":
"options=['o1' string=o1],['o2' string=o2],['o3' string=o3],['o4' string=o4]",
"a ? 'o1' : b ? b : c ? 'o3' : c":
"options=['o1' string=o1],[b],['o3' string=o3],[c]",
"['i1', 'i2', 3, a, b ? 4 : 5]":
"items=['i1' string=i1],['i2' string=i2],[3 number=3],[a],[b ? 4 : 5 options=[4 number=4],[5 number=5]]",
"typeof 'str'": "string=string",
"typeof aString": "string=string",
"typeof b.Number": "string=number",
"typeof b['Number']": "string=number",
"typeof b[Number]": "",
"typeof true": "string=boolean",
"typeof null": "string=object",
"typeof 1": "string=number",
"typeof 1n": "string=bigint",
"b.Number": "number=123",
"b['Number']": "number=123",
"b[Number]": "",
2017-09-15 02:35:33 +08:00
"'str'.concat()": "string=str",
"'str'.concat('one')": "string=strone",
"'str'.concat('one').concat('two')": "string=stronetwo",
"'str'.concat('one').concat('two', 'three')": "string=stronetwothree",
"'str'.concat('one', 'two')": "string=stronetwo",
"'str'.concat('one', 'two').concat('three')": "string=stronetwothree",
2018-02-25 18:46:17 +08:00
"'str'.concat('one', 'two').concat('three', 'four')":
"string=stronetwothreefour",
2017-09-15 02:35:33 +08:00
"'str'.concat('one', obj)": "wrapped=['str' string=str]+[null]",
"'str'.concat('one', obj).concat()": "wrapped=['str' string=str]+[null]",
2018-02-25 18:46:17 +08:00
"'str'.concat('one', obj, 'two')":
"wrapped=['str' string=str]+['two' string=two]",
"'str'.concat('one', obj, 'two').concat()":
"wrapped=['str' string=str]+['two' string=two]",
"'str'.concat('one', obj, 'two').concat('three')":
"wrapped=['str' string=str]+['three' string=three]",
2017-09-15 02:35:33 +08:00
"'str'.concat(obj)": "wrapped=['str' string=str]+[null]",
"'str'.concat(obj).concat()": "wrapped=['str' string=str]+[null]",
2018-02-25 18:46:17 +08:00
"'str'.concat(obj).concat('one', 'two')":
"wrapped=['str' string=str]+['one', 'two' string=onetwo]",
"'str'.concat(obj).concat(obj, 'one')":
"wrapped=['str' string=str]+['one' string=one]",
"'str'.concat(obj).concat(obj, 'one', 'two')":
"wrapped=['str' string=str]+['one', 'two' string=onetwo]",
"'str'.concat(obj).concat('one', obj, 'one')":
"wrapped=['str' string=str]+['one' string=one]",
"'str'.concat(obj).concat('one', obj, 'two', 'three')":
"wrapped=['str' string=str]+['two', 'three' string=twothree]",
"'str'.concat(obj, 'one')":
"wrapped=['str' string=str]+['one' string=one]",
"'str'.concat(obj, 'one').concat()":
"wrapped=['str' string=str]+['one' string=one]",
"'str'.concat(obj, 'one').concat('two', 'three')":
"wrapped=['str' string=str]+['two', 'three' string=twothree]",
"'str'.concat(obj, 'one').concat(obj, 'two', 'three')":
"wrapped=['str' string=str]+['two', 'three' string=twothree]",
"'str'.concat(obj, 'one').concat('two', obj, 'three')":
"wrapped=['str' string=str]+['three' string=three]",
"'str'.concat(obj, 'one').concat('two', obj, 'three', 'four')":
"wrapped=['str' string=str]+['three', 'four' string=threefour]",
"'str'.concat(obj, 'one', 'two')":
"wrapped=['str' string=str]+['one', 'two' string=onetwo]",
"'str'.concat(obj, 'one', 'two').concat()":
"wrapped=['str' string=str]+['one', 'two' string=onetwo]",
"'str'.concat(obj, 'one', 'two').concat('three', 'four')":
"wrapped=['str' string=str]+['three', 'four' string=threefour]",
"'str'.concat(obj, 'one', 'two').concat(obj, 'three', 'four')":
"wrapped=['str' string=str]+['three', 'four' string=threefour]",
"'str'.concat(obj, 'one', 'two').concat('three', obj, 'four')":
"wrapped=['str' string=str]+['four' string=four]",
"'str'.concat(obj, 'one', 'two').concat('three', obj, 'four', 'five')":
"wrapped=['str' string=str]+['four', 'five' string=fourfive]",
// eslint-disable-next-line no-template-curly-in-string
2018-02-25 18:46:17 +08:00
"`start${obj}mid${obj2}end`":
"template=[start string=start],[mid string=mid],[end string=end]",
// eslint-disable-next-line no-template-curly-in-string
2018-02-25 18:46:17 +08:00
"`start${'str'}mid${obj2}end`":
// eslint-disable-next-line no-template-curly-in-string
"template=[start${'str'}mid string=startstrmid],[end string=end]",
"'abc'.substr(1)": "string=bc",
2017-04-13 20:52:49 +08:00
"'abcdef'.substr(2, 3)": "string=cde",
"'abcdef'.substring(2, 3)": "string=c",
"'abcdef'.substring(2, 3, 4)": "",
"'abc'[\"substr\"](1)": "string=bc",
"'abc'[substr](1)": "",
2017-04-13 20:52:49 +08:00
"'1,2+3'.split(/[,+]/)": "array=[1],[2],[3]",
"'1,2+3'.split(expr)": "",
"'a' + (expr + 'c')": "wrapped=['a' string=a]+['c' string=c]",
"1 + 'a'": "string=1a",
"'a' + 1": "string=a1",
2018-02-25 18:46:17 +08:00
"'a' + expr + 1": "wrapped=['a' string=a]+[1 string=1]"
2013-01-31 01:49:25 +08:00
};
2018-02-25 18:46:17 +08:00
Object.keys(testCases).forEach(key => {
2013-01-31 01:49:25 +08:00
function evalExprToString(evalExpr) {
2018-02-25 18:46:17 +08:00
if (!evalExpr) {
2013-01-31 01:49:25 +08:00
return "null";
} else {
2017-01-18 22:24:20 +08:00
const result = [];
2018-02-25 18:46:17 +08:00
if (evalExpr.isString()) result.push("string=" + evalExpr.string);
if (evalExpr.isNumber()) result.push("number=" + evalExpr.number);
if (evalExpr.isBigInt()) result.push("bigint=" + evalExpr.bigint);
2018-02-25 18:46:17 +08:00
if (evalExpr.isBoolean()) result.push("bool=" + evalExpr.bool);
if (evalExpr.isRegExp()) result.push("regExp=" + evalExpr.regExp);
if (evalExpr.isConditional())
result.push(
"options=[" +
evalExpr.options.map(evalExprToString).join("],[") +
"]"
);
if (evalExpr.isArray())
result.push(
"items=[" + evalExpr.items.map(evalExprToString).join("],[") + "]"
);
if (evalExpr.isConstArray())
result.push("array=[" + evalExpr.array.join("],[") + "]");
if (evalExpr.isTemplateString())
result.push(
"template=[" +
evalExpr.quasis.map(evalExprToString).join("],[") +
"]"
);
if (evalExpr.isWrapped())
result.push(
"wrapped=[" +
evalExprToString(evalExpr.prefix) +
"]+[" +
evalExprToString(evalExpr.postfix) +
"]"
);
if (evalExpr.range) {
2017-01-18 22:24:20 +08:00
const start = evalExpr.range[0] - 5;
const end = evalExpr.range[1] - 5;
2018-02-25 18:46:17 +08:00
return (
key.substr(start, end - start) +
(result.length > 0 ? " " + result.join(" ") : "")
);
2013-01-31 01:49:25 +08:00
}
return result.join(" ");
}
}
2015-08-09 18:42:43 +08:00
2017-01-18 22:24:20 +08:00
it("should eval " + key, () => {
const evalExpr = evaluateInParser(key);
2018-02-25 18:46:17 +08:00
expect(evalExprToString(evalExpr)).toBe(
testCases[key] ? key + " " + testCases[key] : key
);
2013-01-31 01:49:25 +08:00
});
});
});
2016-10-31 09:48:33 +08:00
2017-01-18 22:24:20 +08:00
describe("async/await support", () => {
describe("should accept", () => {
const cases = {
2016-10-31 09:48:33 +08:00
"async function": "async function x() {}",
"async arrow function": "async () => {}",
"await expression": "async function x(y) { await y }",
"await iteration": "async function f() { for await (x of xs); }"
2016-10-31 09:48:33 +08:00
};
2018-07-03 16:15:48 +08:00
const parser = new JavascriptParser();
2018-02-25 18:46:17 +08:00
Object.keys(cases).forEach(name => {
2017-01-18 22:24:20 +08:00
const expr = cases[name];
it(name, () => {
const actual = parser.parse(expr, {});
2018-01-24 20:17:21 +08:00
expect(typeof actual).toBe("object");
2016-10-31 09:48:33 +08:00
});
});
});
2017-01-18 22:24:20 +08:00
describe("should parse await", () => {
const cases = {
2018-02-25 18:46:17 +08:00
require: [
"async function x() { await require('y'); }",
{
2016-10-31 09:48:33 +08:00
param: "y"
}
],
2018-02-25 18:46:17 +08:00
import: [
"async function x() { const y = await import('z'); }",
{
2016-10-31 09:48:33 +08:00
param: "z"
}
]
};
2018-07-03 16:15:48 +08:00
const parser = new JavascriptParser();
2019-07-24 16:51:04 +08:00
parser.hooks.call.for("require").tap("JavascriptParserTest", expr => {
2017-01-18 22:24:20 +08:00
const param = parser.evaluateExpression(expr.arguments[0]);
parser.state.param = param.string;
2016-10-31 09:48:33 +08:00
});
2018-07-03 16:15:48 +08:00
parser.hooks.importCall.tap("JavascriptParserTest", expr => {
2019-08-14 20:42:07 +08:00
const param = parser.evaluateExpression(expr.source);
2017-01-18 22:24:20 +08:00
parser.state.param = param.string;
2016-10-31 09:48:33 +08:00
});
2018-02-25 18:46:17 +08:00
Object.keys(cases).forEach(name => {
2017-01-18 22:24:20 +08:00
it(name, () => {
const actual = parser.parse(cases[name][0], {});
2018-01-24 20:17:21 +08:00
expect(actual).toEqual(cases[name][1]);
2016-10-31 09:48:33 +08:00
});
});
});
2017-01-18 22:24:20 +08:00
});
describe("object rest/spread support", () => {
describe("should accept", () => {
const cases = {
"object spread": "({...obj})",
"object rest": "({...obj} = foo)"
};
2018-02-25 18:46:17 +08:00
Object.keys(cases).forEach(name => {
const expr = cases[name];
it(name, () => {
2020-08-28 08:33:06 +08:00
const actual = JavascriptParser._parse(expr, {});
expect(typeof actual).toBe("object");
});
});
});
it("should collect definitions from identifiers introduced in object patterns", () => {
let definitions;
2019-05-20 20:46:31 +08:00
const parser = new JavascriptParser();
2019-05-20 20:46:31 +08:00
parser.hooks.statement.tap("JavascriptParserTest", expr => {
definitions = parser.scope.definitions;
return true;
});
parser.parse("const { a, ...rest } = { a: 1, b: 2 };", {});
expect(definitions.has("a")).toBe(true);
expect(definitions.has("rest")).toBe(true);
});
});
describe("optional catch binding support", () => {
describe("should accept", () => {
const cases = {
"optional binding": "try {} catch {}"
};
Object.keys(cases).forEach(name => {
const expr = cases[name];
it(name, () => {
2020-08-28 08:33:06 +08:00
const actual = JavascriptParser._parse(expr);
expect(typeof actual).toBe("object");
});
});
});
});
describe("BasicEvaluatedExpression", () => {
/** @type [string, boolean][] */
const tests = [
...["i", "g", "m", "y"].reduce((acc, flag) => {
acc.push([flag, true]);
acc.push([flag + flag, false]);
return acc;
}, []),
["", true],
["igm", true],
["igmy", true],
["igmyi", false],
["igmya", false],
["ai", false],
["ia", false]
];
tests.forEach(([suite, expected]) => {
it(`BasicEvaluatedExpression.isValidRegExpFlags(${JSON.stringify(
suite
)})`, () => {
expect(BasicEvaluatedExpression.isValidRegExpFlags(suite)).toBe(
expected
);
});
});
});
2015-08-09 18:42:43 +08:00
});