Files
rea/src/domain/javascript/javascriptStaticAnalysisCallableReceivers.test.ts
T

99 lines
2.9 KiB
TypeScript
Raw Normal View History

import { runInNewContext } from "node:vm";
import { expect, it } from "vitest";
import { analyzeJavaScriptStaticSource } from "./javascriptStaticAnalysis.js";
const generic = "const get=()=>({});const invoke=get.call;";
const cases = [
{
name: "plain object receiver",
source: `${generic}const holder={invoke,other:()=>module};holder.invoke(null)`,
callable: false,
},
{
name: "sequence object receiver",
source: `${generic}const holder={invoke,other:()=>module};(0,holder).invoke(null)`,
callable: false,
},
{
name: "spread object receiver",
source: `${generic}({...{invoke,other:()=>module}}).invoke(null)`,
callable: false,
},
{
name: "array receiver",
source: `${generic}const holder=[invoke,()=>module];holder[0](null)`,
callable: false,
},
{
name: "explicit object receiver",
source: `${generic}invoke.call({other:()=>module},null)`,
callable: false,
},
{
name: "conditional object receiver",
source: `${generic}const holder=flag?{invoke,other:()=>module}:{invoke,other:()=>module};holder.invoke(null)`,
callable: false,
},
{
name: "direct object callee",
source: "const holder={other:()=>module};holder(null)",
callable: false,
},
{
name: "direct array callee",
source: "const holder=[()=>module];holder(null)",
callable: false,
},
{
name: "callable receiver with an own invocation alias",
source: `${generic}const holder=()=>module;holder.invoke=invoke;holder.other=()=>({});holder.invoke(null)`,
callable: true,
},
{
name: "explicit callable member receiver",
source: `${generic}const holder={invoke,other:()=>module};holder.invoke.call(holder.other,null)`,
callable: true,
},
{
name: "selected object callable",
source: `${generic}const holder={other:()=>module};invoke.call(holder.other,null)`,
callable: true,
},
{
name: "selected array callable",
source: `${generic}const holder=[()=>module];invoke.call(holder[0],null)`,
callable: true,
},
{
name: "selected spread callable",
source: `${generic}const holder={...{other:()=>module}};invoke.call(holder.other,null)`,
callable: true,
},
];
it.each(cases)(
"distinguishes the callable value from children for $name",
({ source, callable }) => {
const invocation = `${source}.require('./shared.cjs');`;
expect(
runInNewContext(
`try{${invocation}}catch(error){error.name;}`,
{ module: { require: () => "host" }, flag: true },
{ timeout: 1_000 },
),
).toBe(callable ? "host" : "TypeError");
const analysis = analyzeJavaScriptStaticSource(invocation);
expect(analysis.parse_error_count).toBe(0);
expect(analysis.references).toEqual(
callable
? [
expect.objectContaining({
kind: "require",
specifier: null,
}),
]
: [],
);
},
);