2017-01-18 22:24:20 +08:00
|
|
|
"use strict";
|
2013-01-31 01:49:25 +08:00
|
|
|
|
2025-07-03 17:06:45 +08:00
|
|
|
/* eslint-disable no-unused-expressions, no-unassigned-vars, func-names */
|
2025-07-02 20:10:54 +08:00
|
|
|
|
2022-01-18 17:38:06 +08:00
|
|
|
// cspell:ignore fghsub notry fghsub notry notry this's ijksub this's ijksub fghsub fghsub notry ijksub ijksub strrring strrring strr strrring strrring strr Sstrrringy strone stronetwo stronetwothree stronetwo stronetwothree stronetwothreefour onetwo onetwo twothree twothree twothree threefour onetwo onetwo threefour threefour fourfive startstrmid igmy igmyi igmya
|
2019-10-22 15:27:52 +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 */
|
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"]
|
|
|
|
}
|
|
|
|
],
|
2016-06-04 18:06:10 +08:00
|
|
|
"call member using bracket notation": [
|
2020-03-29 06:10:15 +08:00
|
|
|
function () {
|
2024-07-31 09:37:24 +08:00
|
|
|
// eslint-disable-next-line dot-notation
|
2016-06-04 18:06:10 +08:00
|
|
|
cde["abc"]("membertest");
|
2018-02-25 18:46:17 +08:00
|
|
|
},
|
|
|
|
{
|
2016-06-04 18:06:10 +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"]
|
|
|
|
}
|
|
|
|
],
|
2016-06-04 18:06:10 +08:00
|
|
|
"call inner member using bracket notation": [
|
2020-03-29 06:10:15 +08:00
|
|
|
function () {
|
2024-07-31 09:37:24 +08:00
|
|
|
// eslint-disable-next-line dot-notation
|
2016-06-04 18:06:10 +08:00
|
|
|
cde.ddd["abc"]("inner");
|
2018-02-25 18:46:17 +08:00
|
|
|
},
|
|
|
|
{
|
2016-06-04 18:06:10 +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"]
|
|
|
|
}
|
|
|
|
],
|
2014-12-16 15:00:05 +08:00
|
|
|
"member expression": [
|
2020-03-29 06:10:15 +08:00
|
|
|
function () {
|
2017-11-15 21:08:11 +08:00
|
|
|
test[memberExpr];
|
2025-07-02 20:10:54 +08:00
|
|
|
|
2024-07-31 11:11:11 +08:00
|
|
|
// eslint-disable-next-line no-implicit-coercion
|
2017-11-15 21:08:11 +08:00
|
|
|
test[+memberExpr];
|
2018-02-25 18:46:17 +08:00
|
|
|
},
|
|
|
|
{
|
2014-12-16 15:00:05 +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 () {
|
2024-07-31 09:56:53 +08:00
|
|
|
// eslint-disable-next-line one-var
|
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 () {
|
2024-07-31 09:56:53 +08:00
|
|
|
// eslint-disable-next-line one-var
|
2025-04-22 18:49:30 +08:00
|
|
|
let 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");
|
|
|
|
}
|
2024-07-31 12:23:44 +08:00
|
|
|
|
2017-12-30 23:27:17 +08:00
|
|
|
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;
|
|
|
|
}
|
2024-07-31 15:37:05 +08:00
|
|
|
} catch (err) {
|
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"],
|
2024-07-31 16:17:46 +08:00
|
|
|
fgh: ["test", "test ttt", "test err"]
|
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;
|
2014-01-31 17:57:28 +08:00
|
|
|
xyz("test");
|
2018-02-25 18:46:17 +08:00
|
|
|
},
|
|
|
|
{
|
2014-01-31 17:57:28 +08:00
|
|
|
abc: ["test"]
|
|
|
|
}
|
|
|
|
],
|
2017-01-24 17:39:17 +08:00
|
|
|
"renaming with var": [
|
2020-03-29 06:10:15 +08:00
|
|
|
function () {
|
2025-04-22 18:49:30 +08:00
|
|
|
const 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"]
|
|
|
|
}
|
|
|
|
],
|
2014-01-31 17:57:28 +08:00
|
|
|
"renaming with assignment": [
|
2020-03-29 06:10:15 +08:00
|
|
|
function () {
|
2017-01-18 22:24:20 +08:00
|
|
|
const xyz = abc;
|
2014-01-31 17:57:28 +08:00
|
|
|
xyz("test");
|
2018-02-25 18:46:17 +08:00
|
|
|
},
|
|
|
|
{
|
2014-01-31 17:57:28 +08:00
|
|
|
abc: ["test"]
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"renaming with IIFE": [
|
2020-03-29 06:10:15 +08:00
|
|
|
function () {
|
|
|
|
!(function (xyz) {
|
2014-01-31 17:57:28 +08:00
|
|
|
xyz("test");
|
2018-02-25 18:46:17 +08:00
|
|
|
})(abc);
|
|
|
|
},
|
|
|
|
{
|
2014-01-31 17:57:28 +08:00
|
|
|
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) {
|
2014-01-31 17:57:28 +08:00
|
|
|
xyz("test");
|
|
|
|
}.call(fgh, abc);
|
2018-02-25 18:46:17 +08:00
|
|
|
},
|
|
|
|
{
|
2014-01-31 17:57:28 +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"]
|
|
|
|
}
|
|
|
|
],
|
2017-07-12 00:12:15 +08:00
|
|
|
"renaming this's properties with nested IIFE (called)": [
|
2020-03-29 06:10:15 +08:00
|
|
|
function () {
|
|
|
|
!function () {
|
|
|
|
!function () {
|
2017-07-12 00:12:15 +08:00
|
|
|
this.sub;
|
|
|
|
}.call(this);
|
|
|
|
}.call(ijk);
|
2018-02-25 18:46:17 +08:00
|
|
|
},
|
|
|
|
{
|
2017-07-12 00:12:15 +08:00
|
|
|
ijksub: ["test"]
|
|
|
|
}
|
|
|
|
],
|
2017-12-05 10:03:50 +08:00
|
|
|
"new Foo(...)": [
|
2020-03-29 06:10:15 +08:00
|
|
|
function () {
|
2025-07-02 20:10:54 +08:00
|
|
|
// eslint-disable-next-line new-cap, no-new
|
2017-12-05 10:40:23 +08:00
|
|
|
new xyz("membertest");
|
2018-02-25 18:46:17 +08:00
|
|
|
},
|
|
|
|
{
|
2017-12-05 10:03:50 +08:00
|
|
|
xyz: ["membertest"]
|
|
|
|
}
|
|
|
|
],
|
2017-12-30 23:27:17 +08:00
|
|
|
"spread calls/literals": [
|
2020-03-29 06:10:15 +08:00
|
|
|
function () {
|
2025-04-22 18:49:30 +08:00
|
|
|
const xyz = [...abc("xyz"), cde];
|
2017-12-30 23:27:17 +08:00
|
|
|
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 */
|
2013-01-31 01:49:25 +08:00
|
|
|
|
2024-08-02 02:36:27 +08:00
|
|
|
for (const name of Object.keys(testCases)) {
|
2024-07-31 10:39:30 +08:00
|
|
|
it(`should parse ${name}`, () => {
|
2017-01-18 22:24:20 +08:00
|
|
|
let source = testCases[name][0].toString();
|
2022-03-14 05:54:18 +08:00
|
|
|
source = source.slice(13, -1).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")
|
2025-07-17 00:13:14 +08:00
|
|
|
.tap("JavascriptParserTest", (_expr) => true);
|
2019-07-24 16:51:04 +08:00
|
|
|
testParser.hooks.canRename
|
|
|
|
.for("ijk")
|
2025-07-17 00:13:14 +08:00
|
|
|
.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;
|
|
|
|
});
|
2025-07-17 00:13:14 +08:00
|
|
|
testParser.hooks.call
|
|
|
|
.for("cde.abc")
|
|
|
|
.tap("JavascriptParserTest", (expr) => {
|
|
|
|
if (!testParser.state.cdeabc) testParser.state.cdeabc = [];
|
|
|
|
testParser.state.cdeabc.push(
|
|
|
|
testParser.parseString(expr.arguments[0])
|
|
|
|
);
|
|
|
|
return true;
|
|
|
|
});
|
2019-07-24 16:51:04 +08:00
|
|
|
testParser.hooks.call
|
|
|
|
.for("cde.ddd.abc")
|
2025-07-17 00:13:14 +08:00
|
|
|
.tap("JavascriptParserTest", (expr) => {
|
2019-07-24 16:51:04 +08:00
|
|
|
if (!testParser.state.cdedddabc) testParser.state.cdedddabc = [];
|
|
|
|
testParser.state.cdedddabc.push(
|
|
|
|
testParser.parseString(expr.arguments[0])
|
|
|
|
);
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
testParser.hooks.expression
|
|
|
|
.for("fgh")
|
2025-07-17 00:13:14 +08:00
|
|
|
.tap("JavascriptParserTest", (_expr) => {
|
2019-07-24 16:51:04 +08:00
|
|
|
if (!testParser.state.fgh) testParser.state.fgh = [];
|
|
|
|
testParser.state.fgh.push(
|
2025-07-03 17:06:45 +08:00
|
|
|
[...testParser.scope.definitions.asSet()].join(" ")
|
2019-07-24 16:51:04 +08:00
|
|
|
);
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
testParser.hooks.expression
|
|
|
|
.for("fgh.sub")
|
2025-07-17 00:13:14 +08:00
|
|
|
.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")
|
2025-07-17 00:13:14 +08:00
|
|
|
.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")
|
2025-07-17 00:13:14 +08:00
|
|
|
.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
|
|
|
});
|
2025-07-17 00:13:14 +08:00
|
|
|
testParser.hooks.new.for("xyz").tap("JavascriptParserTest", (expr) => {
|
2018-02-25 18:46:17 +08:00
|
|
|
if (!testParser.state.xyz) testParser.state.xyz = [];
|
2017-12-05 10:03:50 +08:00
|
|
|
testParser.state.xyz.push(testParser.parseString(expr.arguments[0]));
|
|
|
|
return true;
|
|
|
|
});
|
2019-11-30 03:24:13 +08:00
|
|
|
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
|
|
|
});
|
2024-08-02 02:36:27 +08:00
|
|
|
}
|
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"
|
|
|
|
}
|
|
|
|
];
|
2016-09-09 02:52:53 +08:00
|
|
|
|
2018-07-03 16:15:48 +08:00
|
|
|
const testParser = new JavascriptParser({});
|
2016-09-09 02:52:53 +08:00
|
|
|
|
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;
|
2016-09-09 02:52:53 +08:00
|
|
|
return true;
|
|
|
|
});
|
|
|
|
|
2019-11-30 03:24:13 +08:00
|
|
|
const actual = testParser.parse(source, {});
|
2018-01-24 20:17:21 +08:00
|
|
|
expect(typeof actual).toBe("object");
|
|
|
|
expect(typeof actual.comments).toBe("object");
|
2024-08-02 02:36:27 +08:00
|
|
|
for (const [index, element] of actual.comments.entries()) {
|
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);
|
2024-08-02 02:36:27 +08:00
|
|
|
}
|
2016-09-09 02:52:53 +08:00
|
|
|
});
|
|
|
|
|
2017-01-18 22:24:20 +08:00
|
|
|
describe("expression evaluation", () => {
|
2025-04-22 20:42:33 +08:00
|
|
|
/**
|
|
|
|
* @param {string} source source
|
|
|
|
* @returns {import("../lib/javascript/JavascriptParser").ParserState} the parser state
|
|
|
|
*/
|
2013-01-31 01:49:25 +08:00
|
|
|
function evaluateInParser(source) {
|
2018-07-03 16:15:48 +08:00
|
|
|
const parser = new JavascriptParser();
|
2025-07-17 00:13:14 +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]);
|
2014-12-16 15:12:30 +08:00
|
|
|
});
|
2019-07-23 15:35:25 +08:00
|
|
|
parser.hooks.evaluateIdentifier
|
|
|
|
.for("aString")
|
2025-07-17 00:13:14 +08:00
|
|
|
.tap("JavascriptParserTest", (expr) =>
|
2018-07-03 16:15:48 +08:00
|
|
|
new BasicEvaluatedExpression()
|
|
|
|
.setString("aString")
|
|
|
|
.setRange(expr.range)
|
2019-07-23 15:35:25 +08:00
|
|
|
);
|
|
|
|
parser.hooks.evaluateIdentifier
|
|
|
|
.for("b.Number")
|
2025-07-17 00:13:14 +08:00
|
|
|
.tap("JavascriptParserTest", (expr) =>
|
2018-07-03 16:15:48 +08:00
|
|
|
new BasicEvaluatedExpression().setNumber(123).setRange(expr.range)
|
2019-07-23 15:35:25 +08:00
|
|
|
);
|
2024-07-31 10:39:30 +08:00
|
|
|
return parser.parse(`test(${source});`, {}).result;
|
2013-01-31 01:49:25 +08:00
|
|
|
}
|
|
|
|
|
2017-01-18 22:24:20 +08:00
|
|
|
const testCases = {
|
2020-03-02 19:16:36 +08:00
|
|
|
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",
|
2017-12-06 00:11:53 +08:00
|
|
|
"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",
|
2020-02-29 01:09:59 +08:00
|
|
|
"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",
|
2020-03-02 19:16:36 +08:00
|
|
|
"!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]]",
|
2014-12-16 15:12:30 +08:00
|
|
|
"typeof 'str'": "string=string",
|
|
|
|
"typeof aString": "string=string",
|
|
|
|
"typeof b.Number": "string=number",
|
2016-06-04 18:06:10 +08:00
|
|
|
"typeof b['Number']": "string=number",
|
2014-12-16 15:12:30 +08:00
|
|
|
"typeof b[Number]": "",
|
2020-02-29 01:09:59 +08:00
|
|
|
"typeof true": "string=boolean",
|
|
|
|
"typeof null": "string=object",
|
|
|
|
"typeof 1": "string=number",
|
|
|
|
"typeof 1n": "string=bigint",
|
2014-12-16 15:12:30 +08:00
|
|
|
"b.Number": "number=123",
|
2016-06-04 18:06:10 +08:00
|
|
|
"b['Number']": "number=123",
|
2014-12-16 15:12:30 +08:00
|
|
|
"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]",
|
2018-04-12 02:31:43 +08:00
|
|
|
// eslint-disable-next-line no-template-curly-in-string
|
2018-02-25 18:46:17 +08:00
|
|
|
"`start${obj}mid${obj2}end`":
|
2018-04-12 02:31:43 +08:00
|
|
|
"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`":
|
2018-04-12 02:31:43 +08:00
|
|
|
// eslint-disable-next-line no-template-curly-in-string
|
|
|
|
"template=[start${'str'}mid string=startstrmid],[end string=end]",
|
2023-04-27 19:30:37 +08:00
|
|
|
// eslint-disable-next-line no-template-curly-in-string
|
|
|
|
"`a${x}` === `b${x}`": "bool=false",
|
|
|
|
// eslint-disable-next-line no-template-curly-in-string
|
|
|
|
"`${x}a` === `${x}b`": "bool=false",
|
|
|
|
// eslint-disable-next-line no-template-curly-in-string
|
|
|
|
"`${a}${b}` === `a${b}`": "",
|
|
|
|
// eslint-disable-next-line no-template-curly-in-string
|
|
|
|
"`${a}${b}` === `${a}b`": "",
|
2022-03-14 05:54:18 +08:00
|
|
|
"'abc'.slice(1)": "string=bc",
|
|
|
|
"'abcdef'.slice(2, 5)": "string=cde",
|
2017-04-13 20:52:49 +08:00
|
|
|
"'abcdef'.substring(2, 3)": "string=c",
|
|
|
|
"'abcdef'.substring(2, 3, 4)": "",
|
2022-03-14 05:54:18 +08:00
|
|
|
"'abc'[\"slice\"](1)": "string=bc",
|
|
|
|
"'abc'[slice](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
|
|
|
};
|
|
|
|
|
2024-08-02 02:36:27 +08:00
|
|
|
for (const key of Object.keys(testCases)) {
|
2025-04-22 20:42:33 +08:00
|
|
|
/**
|
|
|
|
* @param {import("../lib/javascript/BasicEvaluatedExpression")} evalExpr eval expr
|
|
|
|
* @returns {string} result
|
|
|
|
*/
|
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";
|
|
|
|
}
|
2024-07-31 04:21:27 +08:00
|
|
|
const result = [];
|
2024-07-31 10:39:30 +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}`);
|
|
|
|
if (evalExpr.isBoolean()) result.push(`bool=${evalExpr.bool}`);
|
|
|
|
if (evalExpr.isRegExp()) result.push(`regExp=${evalExpr.regExp}`);
|
2025-07-02 20:10:54 +08:00
|
|
|
if (evalExpr.isConditional()) {
|
2024-07-31 04:21:27 +08:00
|
|
|
result.push(
|
2024-07-31 10:39:30 +08:00
|
|
|
`options=[${evalExpr.options.map(evalExprToString).join("],[")}]`
|
2024-07-31 04:21:27 +08:00
|
|
|
);
|
2025-07-02 20:10:54 +08:00
|
|
|
}
|
|
|
|
if (evalExpr.isArray()) {
|
2024-07-31 04:21:27 +08:00
|
|
|
result.push(
|
2024-07-31 10:39:30 +08:00
|
|
|
`items=[${evalExpr.items.map(evalExprToString).join("],[")}]`
|
2024-07-31 04:21:27 +08:00
|
|
|
);
|
2025-07-02 20:10:54 +08:00
|
|
|
}
|
|
|
|
if (evalExpr.isConstArray()) {
|
2024-07-31 10:39:30 +08:00
|
|
|
result.push(`array=[${evalExpr.array.join("],[")}]`);
|
2025-07-02 20:10:54 +08:00
|
|
|
}
|
|
|
|
if (evalExpr.isTemplateString()) {
|
2024-07-31 04:21:27 +08:00
|
|
|
result.push(
|
2024-07-31 10:39:30 +08:00
|
|
|
`template=[${evalExpr.quasis.map(evalExprToString).join("],[")}]`
|
2024-07-31 04:21:27 +08:00
|
|
|
);
|
2025-07-02 20:10:54 +08:00
|
|
|
}
|
|
|
|
if (evalExpr.isWrapped()) {
|
2024-07-31 04:21:27 +08:00
|
|
|
result.push(
|
2024-07-31 10:39:30 +08:00
|
|
|
`wrapped=[${evalExprToString(evalExpr.prefix)}]+[${evalExprToString(
|
|
|
|
evalExpr.postfix
|
|
|
|
)}]`
|
2024-07-31 04:21:27 +08:00
|
|
|
);
|
2025-07-02 20:10:54 +08:00
|
|
|
}
|
2024-07-31 04:21:27 +08:00
|
|
|
if (evalExpr.range) {
|
|
|
|
const start = evalExpr.range[0] - 5;
|
|
|
|
const end = evalExpr.range[1] - 5;
|
|
|
|
return (
|
|
|
|
key.slice(start, end) +
|
2024-07-31 10:39:30 +08:00
|
|
|
(result.length > 0 ? ` ${result.join(" ")}` : "")
|
2024-07-31 04:21:27 +08:00
|
|
|
);
|
|
|
|
}
|
|
|
|
return result.join(" ");
|
2013-01-31 01:49:25 +08:00
|
|
|
}
|
2015-08-09 18:42:43 +08:00
|
|
|
|
2024-07-31 10:39:30 +08:00
|
|
|
it(`should eval ${key}`, () => {
|
2017-01-18 22:24:20 +08:00
|
|
|
const evalExpr = evaluateInParser(key);
|
2018-02-25 18:46:17 +08:00
|
|
|
expect(evalExprToString(evalExpr)).toBe(
|
2024-07-31 10:39:30 +08:00
|
|
|
testCases[key] ? `${key} ${testCases[key]}` : key
|
2018-02-25 18:46:17 +08:00
|
|
|
);
|
2013-01-31 01:49:25 +08:00
|
|
|
});
|
2024-08-02 02:36:27 +08:00
|
|
|
}
|
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 () => {}",
|
2018-02-07 17:39:06 +08:00
|
|
|
"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();
|
2024-08-02 02:36:27 +08:00
|
|
|
for (const name of Object.keys(cases)) {
|
2017-01-18 22:24:20 +08:00
|
|
|
const expr = cases[name];
|
2025-07-02 20:10:54 +08:00
|
|
|
|
2017-01-18 22:24:20 +08:00
|
|
|
it(name, () => {
|
2019-11-30 03:24:13 +08:00
|
|
|
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
|
|
|
});
|
2024-08-02 02:36:27 +08:00
|
|
|
}
|
2016-10-31 09:48:33 +08:00
|
|
|
});
|
2025-07-02 20:10:54 +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();
|
2025-07-17 00:13:14 +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
|
|
|
});
|
2025-07-17 00:13:14 +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
|
|
|
});
|
|
|
|
|
2024-08-02 02:36:27 +08:00
|
|
|
for (const name of Object.keys(cases)) {
|
2017-01-18 22:24:20 +08:00
|
|
|
it(name, () => {
|
2019-11-30 03:24:13 +08:00
|
|
|
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
|
|
|
});
|
2024-08-02 02:36:27 +08:00
|
|
|
}
|
2016-10-31 09:48:33 +08:00
|
|
|
});
|
2017-01-18 22:24:20 +08:00
|
|
|
});
|
2018-02-07 17:39:06 +08:00
|
|
|
|
|
|
|
describe("object rest/spread support", () => {
|
|
|
|
describe("should accept", () => {
|
|
|
|
const cases = {
|
|
|
|
"object spread": "({...obj})",
|
|
|
|
"object rest": "({...obj} = foo)"
|
|
|
|
};
|
2024-08-02 02:36:27 +08:00
|
|
|
for (const name of Object.keys(cases)) {
|
2018-02-07 17:39:06 +08:00
|
|
|
const expr = cases[name];
|
2025-07-02 20:10:54 +08:00
|
|
|
|
2018-02-07 17:39:06 +08:00
|
|
|
it(name, () => {
|
2020-08-28 08:33:06 +08:00
|
|
|
const actual = JavascriptParser._parse(expr, {});
|
2018-02-25 18:41:05 +08:00
|
|
|
expect(typeof actual).toBe("object");
|
2018-02-07 17:39:06 +08:00
|
|
|
});
|
2024-08-02 02:36:27 +08:00
|
|
|
}
|
2018-02-07 17:39:06 +08:00
|
|
|
});
|
2019-04-25 21:42:01 +08:00
|
|
|
|
|
|
|
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-04-25 21:42:01 +08:00
|
|
|
|
2025-07-17 00:13:14 +08:00
|
|
|
parser.hooks.statement.tap("JavascriptParserTest", (_expr) => {
|
2019-04-25 21:42:01 +08:00
|
|
|
definitions = parser.scope.definitions;
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
|
2019-11-30 03:24:13 +08:00
|
|
|
parser.parse("const { a, ...rest } = { a: 1, b: 2 };", {});
|
2019-04-25 21:42:01 +08:00
|
|
|
|
|
|
|
expect(definitions.has("a")).toBe(true);
|
|
|
|
expect(definitions.has("rest")).toBe(true);
|
|
|
|
});
|
2018-02-07 17:39:06 +08:00
|
|
|
});
|
2018-06-04 20:03:38 +08:00
|
|
|
|
2025-05-23 21:39:55 +08:00
|
|
|
describe("parse calculated string", () => {
|
|
|
|
describe("should work", () => {
|
2018-06-04 20:03:38 +08:00
|
|
|
const cases = {
|
2025-05-23 21:39:55 +08:00
|
|
|
123: {
|
|
|
|
code: "123",
|
|
|
|
result: {
|
|
|
|
code: false,
|
|
|
|
conditional: false,
|
|
|
|
range: [0, 3],
|
|
|
|
value: "123"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"'test'": {
|
|
|
|
code: "'test'",
|
|
|
|
result: {
|
|
|
|
code: false,
|
|
|
|
conditional: false,
|
|
|
|
range: [0, 6],
|
|
|
|
value: "test"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"'test' + 'test'": {
|
|
|
|
code: "'test' + 'test'",
|
|
|
|
result: {
|
|
|
|
code: false,
|
|
|
|
conditional: false,
|
|
|
|
range: [0, 15],
|
|
|
|
value: "testtest"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"myVar + 'test'": {
|
|
|
|
code: "myVar + 'test'",
|
|
|
|
result: {
|
|
|
|
code: true,
|
|
|
|
conditional: false,
|
|
|
|
range: undefined,
|
|
|
|
value: ""
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"'test' + myVar": {
|
|
|
|
code: "'test' + myVar",
|
|
|
|
result: {
|
|
|
|
code: true,
|
|
|
|
conditional: false,
|
|
|
|
range: [0, 6],
|
|
|
|
value: "test"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"true ? 'one' : 'two'": {
|
|
|
|
code: "true ? 'one' : 'two'",
|
|
|
|
result: {
|
|
|
|
code: true,
|
|
|
|
conditional: [
|
|
|
|
{
|
|
|
|
code: false,
|
|
|
|
conditional: false,
|
|
|
|
range: [7, 12],
|
|
|
|
value: "one"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
code: false,
|
|
|
|
conditional: false,
|
|
|
|
range: [15, 20],
|
|
|
|
value: "two"
|
|
|
|
}
|
|
|
|
],
|
|
|
|
range: undefined,
|
|
|
|
value: ""
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"true ? true ? 'one' : 'two' : true ? 'three': 'four'": {
|
|
|
|
code: "true ? true ? 'one' : 'two' : true ? 'three': 'four'",
|
|
|
|
result: {
|
|
|
|
code: true,
|
|
|
|
conditional: [
|
|
|
|
{
|
|
|
|
code: false,
|
|
|
|
conditional: false,
|
|
|
|
range: [14, 19],
|
|
|
|
value: "one"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
code: false,
|
|
|
|
conditional: false,
|
|
|
|
range: [22, 27],
|
|
|
|
value: "two"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
code: false,
|
|
|
|
conditional: false,
|
|
|
|
range: [37, 44],
|
|
|
|
value: "three"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
code: false,
|
|
|
|
conditional: false,
|
|
|
|
range: [46, 52],
|
|
|
|
value: "four"
|
|
|
|
}
|
|
|
|
],
|
|
|
|
range: undefined,
|
|
|
|
value: ""
|
|
|
|
}
|
|
|
|
}
|
2018-06-04 20:03:38 +08:00
|
|
|
};
|
2024-08-02 02:36:27 +08:00
|
|
|
for (const name of Object.keys(cases)) {
|
2018-06-04 20:03:38 +08:00
|
|
|
const expr = cases[name];
|
2025-07-02 20:10:54 +08:00
|
|
|
|
2018-06-04 20:03:38 +08:00
|
|
|
it(name, () => {
|
2025-05-23 21:39:55 +08:00
|
|
|
const parser = new JavascriptParser();
|
|
|
|
const actual = JavascriptParser._parse(expr.code);
|
2018-06-04 20:03:38 +08:00
|
|
|
expect(typeof actual).toBe("object");
|
2025-05-23 21:39:55 +08:00
|
|
|
expect(
|
|
|
|
parser.parseCalculatedString(actual.body[0].expression)
|
|
|
|
).toEqual(expr.result);
|
2018-06-04 20:03:38 +08:00
|
|
|
});
|
2024-08-02 02:36:27 +08:00
|
|
|
}
|
2018-06-04 20:03:38 +08:00
|
|
|
});
|
|
|
|
});
|
2020-08-15 17:25:41 +08:00
|
|
|
|
|
|
|
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]
|
|
|
|
];
|
|
|
|
|
2024-08-02 02:36:27 +08:00
|
|
|
for (const [suite, expected] of tests) {
|
2020-08-15 17:25:41 +08:00
|
|
|
it(`BasicEvaluatedExpression.isValidRegExpFlags(${JSON.stringify(
|
|
|
|
suite
|
|
|
|
)})`, () => {
|
|
|
|
expect(BasicEvaluatedExpression.isValidRegExpFlags(suite)).toBe(
|
|
|
|
expected
|
|
|
|
);
|
|
|
|
});
|
2024-08-02 02:36:27 +08:00
|
|
|
}
|
2020-08-15 17:25:41 +08:00
|
|
|
});
|
2015-08-09 18:42:43 +08:00
|
|
|
});
|