poe-code 14.0.64 → 14.0.65
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +7442 -6809
- package/dist/index.js.map +4 -4
- package/dist/metafile.json +1 -1
- package/package.json +1 -1
- package/packages/safe-js/dist/chunks/{chunk-3EXDJDQM.js → chunk-4VT2M7WL.js} +2 -2
- package/packages/safe-js/dist/chunks/{chunk-XO7B4P27.js → chunk-WBWD7ZCM.js} +8189 -7596
- package/packages/safe-js/dist/chunks/chunk-WBWD7ZCM.js.map +7 -0
- package/packages/safe-js/dist/cli.js +2 -2
- package/packages/safe-js/dist/core.js +1 -1
- package/packages/safe-js/dist/index.js +2 -2
- package/packages/safe-js/dist/index.js.map +1 -1
- package/packages/safe-js/dist/interp/async.d.ts +13 -2
- package/packages/safe-js/dist/interp/async.js +16 -6
- package/packages/safe-js/dist/interp/classes.d.ts +4 -0
- package/packages/safe-js/dist/interp/classes.js +176 -0
- package/packages/safe-js/dist/interp/exceptions.js +4 -1
- package/packages/safe-js/dist/interp/globals/object-array.d.ts +2 -1
- package/packages/safe-js/dist/interp/globals/object-array.js +1 -1
- package/packages/safe-js/dist/interp/globals/object.js +10 -2
- package/packages/safe-js/dist/interp/globals/primitives.js +8 -3
- package/packages/safe-js/dist/interp/interpreter.d.ts +1 -1
- package/packages/safe-js/dist/interp/interpreter.js +95 -27
- package/packages/safe-js/dist/interp/methods/function.d.ts +1 -1
- package/packages/safe-js/dist/interp/methods/function.js +1 -1
- package/packages/safe-js/dist/interp/patterns.d.ts +1 -1
- package/packages/safe-js/dist/interp/patterns.js +1 -1
- package/packages/safe-js/dist/interp/values.d.ts +2 -1
- package/packages/safe-js/dist/lint/class-elements.d.ts +5 -0
- package/packages/safe-js/dist/lint/class-elements.js +20 -0
- package/packages/safe-js/dist/lint/rules/AS-async-not-needed.js +16 -0
- package/packages/safe-js/dist/lint/rules/AS-destructure-null-default.js +9 -0
- package/packages/safe-js/dist/lint/rules/AS-export-import-meta.js +9 -0
- package/packages/safe-js/dist/lint/rules/AS-floating-promise.js +9 -0
- package/packages/safe-js/dist/lint/rules/AS-frontmatter-field-unused.js +9 -0
- package/packages/safe-js/dist/lint/rules/AS-jsdoc-type.js +9 -0
- package/packages/safe-js/dist/lint/rules/AS-large-literal.js +9 -0
- package/packages/safe-js/dist/lint/rules/AS-missing-async.js +16 -0
- package/packages/safe-js/dist/lint/rules/AS-mutating-frozen.js +9 -0
- package/packages/safe-js/dist/lint/rules/AS-needless-template.js +9 -0
- package/packages/safe-js/dist/lint/rules/AS-shadow-global.js +12 -0
- package/packages/safe-js/dist/lint/rules/AS-unbounded-loop.js +11 -0
- package/packages/safe-js/dist/lint/rules/AS-unreachable.js +9 -0
- package/packages/safe-js/dist/lint/rules/AS-unused-import.js +16 -2
- package/packages/safe-js/dist/lint/rules/AS001.js +0 -1
- package/packages/safe-js/dist/lint/rules/AS003.js +16 -2
- package/packages/safe-js/dist/lint/rules/AS006-007.js +16 -2
- package/packages/safe-js/dist/lint/rules/AS009.js +20 -1
- package/packages/safe-js/dist/lint/rules/AS010.js +9 -0
- package/packages/safe-js/dist/lint/rules/AS011.js +9 -0
- package/packages/safe-js/dist/lint/rules/AS015.js +9 -0
- package/packages/safe-js/dist/parse/function-source.d.ts +2 -2
- package/packages/safe-js/dist/parse/parser.d.ts +42 -2
- package/packages/safe-js/dist/parse/parser.js +180 -36
- package/packages/safe-js/dist/parse/tokenizer.js +3 -0
- package/packages/safe-js/dist/parse.d.ts +1 -1
- package/packages/safe-js/dist/chunks/chunk-XO7B4P27.js.map +0 -7
- /package/packages/safe-js/dist/chunks/{chunk-3EXDJDQM.js.map → chunk-4VT2M7WL.js.map} +0 -0
|
@@ -5,6 +5,7 @@ import { assertPromiseExecutionAllowed } from "./promise-tracker.js";
|
|
|
5
5
|
import { SandboxJobQueue, runAsyncPrefix, suspendJob } from "./jobs.js";
|
|
6
6
|
import { withCancellationSignal } from "./cancel.js";
|
|
7
7
|
import { retainValues } from "./resources.js";
|
|
8
|
+
import { evaluateClass } from "./classes.js";
|
|
8
9
|
import { sandboxString } from "./string-coercion.js";
|
|
9
10
|
import { attachErrorSpan, formatErrorStack, replaceErrorStack } from "../error/shape.js";
|
|
10
11
|
import { evaluateArrowFunctionExpression, evaluateFunctionExpression, evaluateAwaitExpression, emitResumeBreakpoint, createInterpretedClosure, normalizeClosureResult } from "./async.js";
|
|
@@ -50,6 +51,15 @@ const dispatchTable = {
|
|
|
50
51
|
BlockStatement: evaluateBlockStatement,
|
|
51
52
|
BooleanLiteral: evaluatePrimitiveLiteral,
|
|
52
53
|
CallExpression: evaluateCallExpression,
|
|
54
|
+
ClassDeclaration: (node, context) => evaluateClass(node, context, evaluateNode, createCoercionContext(context)),
|
|
55
|
+
ClassExpression: (node, context) => evaluateClass(node, context, evaluateNode, createCoercionContext(context)),
|
|
56
|
+
NewTargetExpression: async (_node, context) => ({ kind: "normal", hasValue: true, value: context.functionEnvironment?.newTarget }),
|
|
57
|
+
Super: async (_node, context) => {
|
|
58
|
+
const home = context.functionEnvironment?.homeObject;
|
|
59
|
+
if (home === undefined)
|
|
60
|
+
throw new ReferenceError("Super binding is unavailable.");
|
|
61
|
+
return { kind: "normal", hasValue: true, value: getSandboxPrototype(home, context.budget) };
|
|
62
|
+
},
|
|
53
63
|
ConditionalExpression: evaluateConditionalExpression,
|
|
54
64
|
ContinueStatement: evaluateContinueStatement,
|
|
55
65
|
DoWhileStatement: evaluateDoWhileStatement,
|
|
@@ -182,6 +192,8 @@ export async function interpret(node, options = {}) {
|
|
|
182
192
|
export { Scope } from "./scope.js";
|
|
183
193
|
async function evaluateNode(node, context) {
|
|
184
194
|
context.assertActive?.();
|
|
195
|
+
if (context.inferredName !== undefined && node.type !== "ClassExpression")
|
|
196
|
+
context = { ...context, inferredName: undefined };
|
|
185
197
|
const replayWait = promiseReplayContext.getStore()?.beforeNode(node.nodeId);
|
|
186
198
|
if (replayWait !== undefined)
|
|
187
199
|
await suspendJob(replayWait);
|
|
@@ -332,7 +344,7 @@ async function evaluateObjectExpression(node, context) {
|
|
|
332
344
|
const releaseKey = retainValues(context.budget, () => [key.value]);
|
|
333
345
|
let value;
|
|
334
346
|
try {
|
|
335
|
-
value = await evaluateNode(property.value, context);
|
|
347
|
+
value = await evaluateNode(property.value, { ...context, inferredName: String(key.value) });
|
|
336
348
|
}
|
|
337
349
|
finally {
|
|
338
350
|
releaseKey();
|
|
@@ -390,22 +402,32 @@ async function evaluateTemplateLiteral(node, context) {
|
|
|
390
402
|
}
|
|
391
403
|
}
|
|
392
404
|
async function evaluateTaggedTemplateExpression(node, context) {
|
|
393
|
-
const
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
405
|
+
const invokeTag = async (tag, receiver) => {
|
|
406
|
+
if (!isSandboxClosure(tag))
|
|
407
|
+
throw new TypeError("Tagged template tag must be a function.");
|
|
408
|
+
const release = retainValues(context.budget, () => [tag, receiver]);
|
|
409
|
+
try {
|
|
410
|
+
const values = await evaluateTemplateExpressionValues(node.quasi, context);
|
|
411
|
+
if (!values.ok)
|
|
412
|
+
return values.result;
|
|
413
|
+
return {
|
|
414
|
+
kind: "normal", hasValue: true,
|
|
415
|
+
value: await invokeSandboxClosure(tag, [createTaggedTemplateStrings(node.quasi, context), ...values.value], context, [...context.callStack, formatStackFrame(node, tag.name)], node.span, receiver)
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
finally {
|
|
419
|
+
release();
|
|
420
|
+
}
|
|
408
421
|
};
|
|
422
|
+
if (node.tag.type === "MemberExpression")
|
|
423
|
+
return evaluateMemberAccess(node.tag, context, async (member) => {
|
|
424
|
+
if (member.kind === "nullish")
|
|
425
|
+
throw new TypeError("Tagged template tag must be a function.");
|
|
426
|
+
const key = await toPropertyKey(member.property, context.budget, createCoercionContext(context));
|
|
427
|
+
return invokeTag(getPropertyValue(member.object, key, context), member.superReceiver === undefined ? member.object : member.superReceiver.value);
|
|
428
|
+
});
|
|
429
|
+
const tag = await evaluateNode(node.tag, context);
|
|
430
|
+
return tag.kind === "normal" ? invokeTag(tag.value, undefined) : tag;
|
|
409
431
|
}
|
|
410
432
|
async function evaluateTemplateExpressionValues(node, context) {
|
|
411
433
|
const values = [];
|
|
@@ -552,7 +574,7 @@ async function evaluateAssignmentExpression(node, context) {
|
|
|
552
574
|
value: current
|
|
553
575
|
};
|
|
554
576
|
}
|
|
555
|
-
const right = await evaluateNode(node.right, context);
|
|
577
|
+
const right = await evaluateNode(node.right, { ...context, inferredName: node.left.type === "Identifier" ? node.left.name : undefined });
|
|
556
578
|
if (right.kind !== "normal") {
|
|
557
579
|
return right;
|
|
558
580
|
}
|
|
@@ -626,7 +648,10 @@ async function evaluateMemberAssignmentExpression(node, context) {
|
|
|
626
648
|
}
|
|
627
649
|
operands = [value];
|
|
628
650
|
property ??= await toPropertyKey(member.property, context.budget, createCoercionContext(context));
|
|
629
|
-
|
|
651
|
+
if (member.superReceiver === undefined)
|
|
652
|
+
setSandboxProperty(member.object, property, value, context.budget);
|
|
653
|
+
else
|
|
654
|
+
setSuperProperty(member.object, member.superReceiver.value, property, value, context.budget);
|
|
630
655
|
return {
|
|
631
656
|
kind: "normal",
|
|
632
657
|
hasValue: true,
|
|
@@ -772,7 +797,7 @@ async function evaluateVariableDeclaration(node, context) {
|
|
|
772
797
|
hasValue: true,
|
|
773
798
|
value: undefined
|
|
774
799
|
}
|
|
775
|
-
: await evaluateNode(declarator.init, context);
|
|
800
|
+
: await evaluateNode(declarator.init, { ...context, inferredName: declarator.id.type === "Identifier" ? declarator.id.name : undefined });
|
|
776
801
|
if (value.kind !== "normal") {
|
|
777
802
|
return value;
|
|
778
803
|
}
|
|
@@ -946,6 +971,11 @@ function predeclareStatementListBindings(statements, context, functionBody = fal
|
|
|
946
971
|
const { scope } = context;
|
|
947
972
|
const names = new Set();
|
|
948
973
|
for (const statement of statements) {
|
|
974
|
+
if (statement.type === "ClassDeclaration") {
|
|
975
|
+
scope.predeclare(statement.id.name, "let");
|
|
976
|
+
names.add(statement.id.name);
|
|
977
|
+
continue;
|
|
978
|
+
}
|
|
949
979
|
if (statement.type === "FunctionDeclaration") {
|
|
950
980
|
const name = statement.id.name;
|
|
951
981
|
if (names.has(name) && !(functionBody && scope.getOwnBindingKind(name) === "var")) {
|
|
@@ -1646,6 +1676,8 @@ async function evaluateDeleteExpression(node, context) {
|
|
|
1646
1676
|
throw createError("UNSUPPORTED_NODE", node, "Unary operator 'delete' requires a member target.");
|
|
1647
1677
|
}
|
|
1648
1678
|
return evaluateMemberAccess(node.argument, context, async (member) => {
|
|
1679
|
+
if (member.kind === "resolved" && member.superReceiver !== undefined)
|
|
1680
|
+
throw new ReferenceError("Cannot delete a super property.");
|
|
1649
1681
|
if (member.kind === "nullish" || member.object === null || member.object === undefined) {
|
|
1650
1682
|
if (member.kind === "nullish") {
|
|
1651
1683
|
return {
|
|
@@ -1705,7 +1737,10 @@ async function evaluateMemberUpdateExpression(node, context) {
|
|
|
1705
1737
|
const property = await toPropertyKey(member.property, context.budget, createCoercionContext(context));
|
|
1706
1738
|
const current = toNumber(await toNumericPrimitive(getPropertyValue(member.object, property, context), context));
|
|
1707
1739
|
const next = node.operator === "++" ? current + 1 : current - 1;
|
|
1708
|
-
|
|
1740
|
+
if (member.superReceiver === undefined)
|
|
1741
|
+
setSandboxProperty(member.object, property, next, context.budget);
|
|
1742
|
+
else
|
|
1743
|
+
setSuperProperty(member.object, member.superReceiver.value, property, next, context.budget);
|
|
1709
1744
|
return {
|
|
1710
1745
|
kind: "normal",
|
|
1711
1746
|
hasValue: true,
|
|
@@ -1771,13 +1806,22 @@ export function createPatternContext(context, scope = context.scope, evaluate =
|
|
|
1771
1806
|
const evaluationContext = { ...context, scope };
|
|
1772
1807
|
return {
|
|
1773
1808
|
budget: context.budget,
|
|
1774
|
-
evaluate: node => evaluate(node, evaluationContext),
|
|
1809
|
+
evaluate: (node, inferredName) => evaluate(node, { ...evaluationContext, inferredName }),
|
|
1775
1810
|
toPropertyKey: value => toPropertyKey(value, context.budget, createCoercionContext(evaluationContext)),
|
|
1776
1811
|
getProperty: (value, key) => getPropertyValue(value, key, evaluationContext),
|
|
1777
1812
|
setProperty: (target, key, value) => setSandboxProperty(target, key, value, context.budget)
|
|
1778
1813
|
};
|
|
1779
1814
|
}
|
|
1780
1815
|
async function evaluateCallExpression(node, context) {
|
|
1816
|
+
if (node.callee.type === "Super") {
|
|
1817
|
+
const construction = context.functionEnvironment?.construction;
|
|
1818
|
+
if (construction === undefined)
|
|
1819
|
+
throw new ReferenceError("Super constructor binding is unavailable.");
|
|
1820
|
+
const args = await evaluateCallArguments(node.arguments, context);
|
|
1821
|
+
if (!args.ok)
|
|
1822
|
+
return args.result;
|
|
1823
|
+
return { kind: "normal", hasValue: true, value: await construction.superCall(args.value) };
|
|
1824
|
+
}
|
|
1781
1825
|
if (node.callee.type === "MemberExpression") {
|
|
1782
1826
|
context.budget.visitNode();
|
|
1783
1827
|
context.stats.nodeVisits += 1;
|
|
@@ -1847,6 +1891,7 @@ function attachFatalSandboxErrorContext(error, node, stackFrames) {
|
|
|
1847
1891
|
replaceErrorStack(error, stackFrames);
|
|
1848
1892
|
}
|
|
1849
1893
|
async function evaluateMemberAccess(node, context, consume) {
|
|
1894
|
+
const superReceiver = node.object.type === "Super" ? { value: context.scope.lookup("this") } : undefined;
|
|
1850
1895
|
const object = await evaluateNode(node.object, context);
|
|
1851
1896
|
if (object.kind !== "normal")
|
|
1852
1897
|
return object;
|
|
@@ -1862,7 +1907,8 @@ async function evaluateMemberAccess(node, context, consume) {
|
|
|
1862
1907
|
if (result.kind !== "normal")
|
|
1863
1908
|
return result;
|
|
1864
1909
|
property = result.value;
|
|
1865
|
-
return await consume({ kind: "resolved", object: object.value, property
|
|
1910
|
+
return await consume({ kind: "resolved", object: object.value, property,
|
|
1911
|
+
...(superReceiver === undefined ? {} : { superReceiver: { value: superReceiver.value.found ? superReceiver.value.value : undefined } }) });
|
|
1866
1912
|
}
|
|
1867
1913
|
finally {
|
|
1868
1914
|
release();
|
|
@@ -1918,6 +1964,8 @@ async function evaluateMemberCallExpression(node, context) {
|
|
|
1918
1964
|
...reference,
|
|
1919
1965
|
property: await toPropertyKey(reference.property, context.budget, createCoercionContext(context))
|
|
1920
1966
|
};
|
|
1967
|
+
if (member.superReceiver !== undefined)
|
|
1968
|
+
return evaluateResolvedCallExpression(node, getPropertyValue(member.object, member.property, context), context, member.superReceiver.value);
|
|
1921
1969
|
if ((typeof member.object === "string" || typeof member.object === "number" || typeof member.object === "boolean") &&
|
|
1922
1970
|
getBoxedPrototype(member.object, context.budget) !== undefined) {
|
|
1923
1971
|
if (isDefaultBoxedMethod(member.object, member.property, context.budget)) {
|
|
@@ -2468,7 +2516,7 @@ function getArrayMemberValue(target, property, context) {
|
|
|
2468
2516
|
}
|
|
2469
2517
|
return getArrayMember(target, property, createArrayMethodOptions(context));
|
|
2470
2518
|
}
|
|
2471
|
-
export function setSandboxProperty(target, property, value, budget) {
|
|
2519
|
+
export function setSandboxProperty(target, property, value, budget, checkInherited = true) {
|
|
2472
2520
|
if (isSandboxDate(target))
|
|
2473
2521
|
throw new TypeError("Date own properties are not supported.");
|
|
2474
2522
|
if (isGuestHostObject(target)) {
|
|
@@ -2505,7 +2553,7 @@ export function setSandboxProperty(target, property, value, budget) {
|
|
|
2505
2553
|
Object.defineProperty(target, key, { value });
|
|
2506
2554
|
}
|
|
2507
2555
|
else {
|
|
2508
|
-
if (typeof prototypeOwner === "object" && prototypeOwner !== null) {
|
|
2556
|
+
if (checkInherited && typeof prototypeOwner === "object" && prototypeOwner !== null) {
|
|
2509
2557
|
let depth = 0;
|
|
2510
2558
|
for (let prototype = getSandboxPrototype(prototypeOwner, budget); prototype !== null; prototype = getSandboxPrototype(prototype, budget)) {
|
|
2511
2559
|
budget.visitNode();
|
|
@@ -2522,6 +2570,25 @@ export function setSandboxProperty(target, property, value, budget) {
|
|
|
2522
2570
|
defineSandboxProperty(target, key, value);
|
|
2523
2571
|
}
|
|
2524
2572
|
}
|
|
2573
|
+
function setSuperProperty(base, receiver, key, value, budget) {
|
|
2574
|
+
if (typeof base !== "object" || base === null)
|
|
2575
|
+
throw new TypeError("Cannot assign a property of null.");
|
|
2576
|
+
let depth = 0;
|
|
2577
|
+
for (let current = base; current !== null; current = getSandboxPrototype(current, budget)) {
|
|
2578
|
+
budget.visitNode();
|
|
2579
|
+
assertSandboxDataDepth(depth++);
|
|
2580
|
+
const properties = isSandboxClosure(current) ? current.properties : current;
|
|
2581
|
+
const descriptor = properties === undefined ? undefined : Object.getOwnPropertyDescriptor(properties, key);
|
|
2582
|
+
if (descriptor === undefined)
|
|
2583
|
+
continue;
|
|
2584
|
+
if (descriptor.writable !== true)
|
|
2585
|
+
throw new TypeError(`Cannot assign to read only property '${key}'.`);
|
|
2586
|
+
break;
|
|
2587
|
+
}
|
|
2588
|
+
if (typeof receiver !== "object" || receiver === null)
|
|
2589
|
+
throw new TypeError("Super assignment requires an object receiver.");
|
|
2590
|
+
setSandboxProperty(receiver, key, value, budget, false);
|
|
2591
|
+
}
|
|
2525
2592
|
function deleteSandboxProperty(target, property) {
|
|
2526
2593
|
if (isGuestHostObject(target))
|
|
2527
2594
|
return deleteHostObjectMember(target, String(property));
|
|
@@ -2600,10 +2667,10 @@ function createSetMethodOptions(context) {
|
|
|
2600
2667
|
function createFunctionMethodOptions(context) {
|
|
2601
2668
|
return {
|
|
2602
2669
|
budget: context.budget,
|
|
2603
|
-
callClosure: (closure, args, stack, thisValue, construct) => invokeSandboxClosure(closure, args, context, stack, undefined, thisValue, construct)
|
|
2670
|
+
callClosure: (closure, args, stack, thisValue, construct, newTarget) => invokeSandboxClosure(closure, args, context, stack, undefined, thisValue, construct, newTarget)
|
|
2604
2671
|
};
|
|
2605
2672
|
}
|
|
2606
|
-
async function invokeSandboxClosure(callee, args, context, stack, span, thisValue = undefined, construct = false) {
|
|
2673
|
+
async function invokeSandboxClosure(callee, args, context, stack, span, thisValue = undefined, construct = false, newTarget) {
|
|
2607
2674
|
const leaveCall = context.budget.enterCall();
|
|
2608
2675
|
try {
|
|
2609
2676
|
const invoke = construct ? callee.construct : callee.call;
|
|
@@ -2614,10 +2681,11 @@ async function invokeSandboxClosure(callee, args, context, stack, span, thisValu
|
|
|
2614
2681
|
{
|
|
2615
2682
|
stack,
|
|
2616
2683
|
thisValue,
|
|
2684
|
+
newTarget: construct ? newTarget ?? callee : undefined,
|
|
2617
2685
|
compilation: context.compilation,
|
|
2618
2686
|
getProperty: (value, property) => getPropertyValue(value, property, context),
|
|
2619
2687
|
reconcileData: (value) => reconcileDataBudget(context.budget, context.stats, context.scope, value, context.compilation, context.compilation?.parent),
|
|
2620
|
-
invokeClosure: (closure, argumentsList, receiver, asConstructor) => invokeSandboxClosure(closure, argumentsList, context, stack, span, receiver, asConstructor),
|
|
2688
|
+
invokeClosure: (closure, argumentsList, receiver, asConstructor, target) => invokeSandboxClosure(closure, argumentsList, context, stack, span, receiver, asConstructor, target),
|
|
2621
2689
|
...(span === undefined ? {} : { span })
|
|
2622
2690
|
}
|
|
2623
2691
|
]);
|
|
@@ -2,6 +2,6 @@ import { type SandboxClosure, type SandboxValue } from "../values.js";
|
|
|
2
2
|
import type { Budget } from "../budget.js";
|
|
3
3
|
export type FunctionMethodOptions = {
|
|
4
4
|
budget?: Budget;
|
|
5
|
-
callClosure: (closure: SandboxClosure, args: readonly SandboxValue[], stack: readonly string[], thisValue: SandboxValue, construct?: boolean) => Promise<SandboxValue> | SandboxValue;
|
|
5
|
+
callClosure: (closure: SandboxClosure, args: readonly SandboxValue[], stack: readonly string[], thisValue: SandboxValue, construct?: boolean, newTarget?: SandboxClosure) => Promise<SandboxValue> | SandboxValue;
|
|
6
6
|
};
|
|
7
7
|
export declare function getFunctionMember(target: SandboxClosure, property: string | number, options: FunctionMethodOptions): SandboxValue | undefined;
|
|
@@ -69,7 +69,7 @@ function callFunctionMethod(target, methodName, args, options, stack) {
|
|
|
69
69
|
...(target.construct === undefined
|
|
70
70
|
? {}
|
|
71
71
|
: {
|
|
72
|
-
construct: (callArgs, context) => options.callClosure(target, [...boundArgs, ...callArgs], context?.stack ?? [], undefined, true)
|
|
72
|
+
construct: (callArgs, context) => options.callClosure(target, [...boundArgs, ...callArgs], context?.stack ?? [], undefined, true, context?.newTarget === bound ? target : context?.newTarget)
|
|
73
73
|
})
|
|
74
74
|
});
|
|
75
75
|
if (hasExplicitSandboxPrototype(target))
|
|
@@ -12,7 +12,7 @@ export type PatternTarget = {
|
|
|
12
12
|
};
|
|
13
13
|
export type PatternContext = {
|
|
14
14
|
budget?: Budget;
|
|
15
|
-
evaluate(node: ParseResult): Promise<AsyncEvaluationResult>;
|
|
15
|
+
evaluate(node: ParseResult, inferredName?: string): Promise<AsyncEvaluationResult>;
|
|
16
16
|
toPropertyKey(value: SandboxValue): Promise<string>;
|
|
17
17
|
getProperty(value: SandboxValue, key: string | number): SandboxValue;
|
|
18
18
|
setProperty(target: SandboxValue, key: string | number, value: SandboxValue): void;
|
|
@@ -40,7 +40,7 @@ async function bindAssignmentPattern(pattern, value, target, scope, context) {
|
|
|
40
40
|
if (value !== undefined) {
|
|
41
41
|
return bindPattern(pattern.left, value, target, scope, context);
|
|
42
42
|
}
|
|
43
|
-
const defaultValue = await context.evaluate(pattern.right);
|
|
43
|
+
const defaultValue = await context.evaluate(pattern.right, pattern.left.type === "Identifier" ? pattern.left.name : undefined);
|
|
44
44
|
if (defaultValue.kind !== "normal") {
|
|
45
45
|
return { ok: false, result: defaultValue };
|
|
46
46
|
}
|
|
@@ -38,6 +38,7 @@ export type SandboxRegex = {
|
|
|
38
38
|
readonly [sandboxRegexPattern]: RegexPattern;
|
|
39
39
|
};
|
|
40
40
|
export type SandboxCallContext = {
|
|
41
|
+
readonly newTarget?: SandboxClosure;
|
|
41
42
|
readonly compilation?: CompileScope;
|
|
42
43
|
readonly span?: {
|
|
43
44
|
readonly end: {
|
|
@@ -55,7 +56,7 @@ export type SandboxCallContext = {
|
|
|
55
56
|
readonly thisValue: SandboxValue;
|
|
56
57
|
readonly getProperty?: (value: SandboxValue, property: string | number) => SandboxValue;
|
|
57
58
|
readonly reconcileData?: (value: SandboxValue) => void;
|
|
58
|
-
readonly invokeClosure?: (closure: SandboxClosure, args: readonly SandboxValue[], thisValue: SandboxValue, construct?: boolean) => Promise<SandboxValue>;
|
|
59
|
+
readonly invokeClosure?: (closure: SandboxClosure, args: readonly SandboxValue[], thisValue: SandboxValue, construct?: boolean, newTarget?: SandboxClosure) => Promise<SandboxValue>;
|
|
59
60
|
};
|
|
60
61
|
export type SandboxClosure = {
|
|
61
62
|
readonly sourceRange?: FunctionSource;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { BlockStatement, ClassNode, Expression } from "../parse.js";
|
|
2
|
+
/** Visit both definition-time expressions and deferred element bodies. */
|
|
3
|
+
export declare function visitClassElements(node: ClassNode, expression: (node: Expression) => void, statement: (node: BlockStatement) => void): void;
|
|
4
|
+
/** Await in a computed key belongs to the defining function, unlike methods. */
|
|
5
|
+
export declare function classDefinitionContains(node: ClassNode, expression: (node: Expression) => boolean): boolean;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** Visit both definition-time expressions and deferred element bodies. */
|
|
2
|
+
export function visitClassElements(node, expression, statement) {
|
|
3
|
+
if (node.superClass !== undefined)
|
|
4
|
+
expression(node.superClass);
|
|
5
|
+
for (const element of node.body.body) {
|
|
6
|
+
if (element.type === "StaticBlock") {
|
|
7
|
+
statement(element.body);
|
|
8
|
+
continue;
|
|
9
|
+
}
|
|
10
|
+
if (element.computed)
|
|
11
|
+
expression(element.key);
|
|
12
|
+
if (element.value !== undefined)
|
|
13
|
+
expression(element.value);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/** Await in a computed key belongs to the defining function, unlike methods. */
|
|
17
|
+
export function classDefinitionContains(node, expression) {
|
|
18
|
+
return (node.superClass !== undefined && expression(node.superClass)) ||
|
|
19
|
+
node.body.body.some(element => element.type !== "StaticBlock" && element.computed && expression(element.key));
|
|
20
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { classDefinitionContains, visitClassElements } from "../class-elements.js";
|
|
1
2
|
import { parseModule } from "../../parse/parser.js";
|
|
2
3
|
export const AS_ASYNC_NOT_NEEDED_MESSAGE = "Async functions without await should remove the async keyword.";
|
|
3
4
|
export function AS_ASYNC_NOT_NEEDED(source, options = {}) {
|
|
@@ -32,6 +33,10 @@ class ASAsyncNotNeededScanner {
|
|
|
32
33
|
}
|
|
33
34
|
}
|
|
34
35
|
visitStatement(node) {
|
|
36
|
+
if (node.type === "ClassDeclaration") {
|
|
37
|
+
visitClassElements(node, expression => this.visitExpression(expression), statement => this.visitStatement(statement));
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
35
40
|
switch (node.type) {
|
|
36
41
|
case "FunctionDeclaration":
|
|
37
42
|
this.visitFunctionExpression(node);
|
|
@@ -166,6 +171,10 @@ class ASAsyncNotNeededScanner {
|
|
|
166
171
|
this.visitExpression(node.argument);
|
|
167
172
|
}
|
|
168
173
|
visitExpression(node) {
|
|
174
|
+
if (node.type === "ClassExpression") {
|
|
175
|
+
visitClassElements(node, expression => this.visitExpression(expression), statement => this.visitStatement(statement));
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
169
178
|
switch (node.type) {
|
|
170
179
|
case "YieldExpression":
|
|
171
180
|
if (node.argument !== undefined) {
|
|
@@ -406,6 +415,8 @@ function statementListContainsAwait(statements) {
|
|
|
406
415
|
}
|
|
407
416
|
function statementContainsAwait(node) {
|
|
408
417
|
switch (node.type) {
|
|
418
|
+
case "ClassDeclaration":
|
|
419
|
+
return classDefinitionContains(node, expressionContainsAwait);
|
|
409
420
|
case "BlockStatement":
|
|
410
421
|
return statementListContainsAwait(node.body);
|
|
411
422
|
case "ExpressionStatement":
|
|
@@ -468,6 +479,11 @@ function variableDeclarationContainsAwait(node) {
|
|
|
468
479
|
}
|
|
469
480
|
function expressionContainsAwait(node) {
|
|
470
481
|
switch (node.type) {
|
|
482
|
+
case "ClassExpression":
|
|
483
|
+
return classDefinitionContains(node, expressionContainsAwait);
|
|
484
|
+
case "NewTargetExpression":
|
|
485
|
+
case "Super":
|
|
486
|
+
return false;
|
|
471
487
|
case "AwaitExpression":
|
|
472
488
|
return true;
|
|
473
489
|
case "YieldExpression":
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { visitClassElements } from "../class-elements.js";
|
|
1
2
|
import { parseModule } from "../../parse/parser.js";
|
|
2
3
|
const MESSAGE = "Destructuring default values only apply to undefined, not null.";
|
|
3
4
|
const HINT = "Handle null explicitly before destructuring or use ?? after binding.";
|
|
@@ -20,6 +21,10 @@ class ASDestructureNullDefaultScanner {
|
|
|
20
21
|
}
|
|
21
22
|
}
|
|
22
23
|
visitStatement(node) {
|
|
24
|
+
if (node.type === "ClassDeclaration") {
|
|
25
|
+
visitClassElements(node, expression => this.visitExpression(expression), statement => this.visitStatement(statement));
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
23
28
|
switch (node.type) {
|
|
24
29
|
case "FunctionDeclaration":
|
|
25
30
|
this.visitArrowFunction(node);
|
|
@@ -147,6 +152,10 @@ class ASDestructureNullDefaultScanner {
|
|
|
147
152
|
this.visitExpression(node.argument);
|
|
148
153
|
}
|
|
149
154
|
visitExpression(node) {
|
|
155
|
+
if (node.type === "ClassExpression") {
|
|
156
|
+
visitClassElements(node, expression => this.visitExpression(expression), statement => this.visitStatement(statement));
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
150
159
|
switch (node.type) {
|
|
151
160
|
case "YieldExpression":
|
|
152
161
|
if (node.argument !== undefined) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { visitClassElements } from "../class-elements.js";
|
|
1
2
|
import { parseModule } from "../../parse/parser.js";
|
|
2
3
|
export function AS_EXPORT_IMPORT_META(source, options = {}) {
|
|
3
4
|
return new Scanner(options.filename ?? "<input>", new Set(options.allowedExportNames ?? []), options.defaultExport).scan(source);
|
|
@@ -35,6 +36,10 @@ class Scanner {
|
|
|
35
36
|
}
|
|
36
37
|
}
|
|
37
38
|
visitStatement(node) {
|
|
39
|
+
if (node.type === "ClassDeclaration") {
|
|
40
|
+
visitClassElements(node, expression => this.visitExpression(expression), statement => this.visitStatement(statement));
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
38
43
|
switch (node.type) {
|
|
39
44
|
case "FunctionDeclaration":
|
|
40
45
|
for (const param of node.params) {
|
|
@@ -176,6 +181,10 @@ class Scanner {
|
|
|
176
181
|
this.visitExpression(node.argument);
|
|
177
182
|
}
|
|
178
183
|
visitExpression(node) {
|
|
184
|
+
if (node.type === "ClassExpression") {
|
|
185
|
+
visitClassElements(node, expression => this.visitExpression(expression), statement => this.visitStatement(statement));
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
179
188
|
switch (node.type) {
|
|
180
189
|
case "YieldExpression":
|
|
181
190
|
if (node.argument !== undefined) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { visitClassElements } from "../class-elements.js";
|
|
1
2
|
import { parseModule } from "../../parse/parser.js";
|
|
2
3
|
import { normalizeModuleRegistrations } from "./module-registry.js";
|
|
3
4
|
const AS_FLOATING_PROMISE_MESSAGE = "Promise-returning call is not awaited, returned, stored, or chained.";
|
|
@@ -28,6 +29,10 @@ class ASFloatingPromiseScanner {
|
|
|
28
29
|
});
|
|
29
30
|
}
|
|
30
31
|
visitStatement(node) {
|
|
32
|
+
if (node.type === "ClassDeclaration") {
|
|
33
|
+
visitClassElements(node, expression => this.visitExpression(expression), statement => this.visitStatement(statement));
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
31
36
|
switch (node.type) {
|
|
32
37
|
case "FunctionDeclaration":
|
|
33
38
|
this.visitArrowFunction(node);
|
|
@@ -163,6 +168,10 @@ class ASFloatingPromiseScanner {
|
|
|
163
168
|
this.visitExpression(node.argument);
|
|
164
169
|
}
|
|
165
170
|
visitExpression(node) {
|
|
171
|
+
if (node.type === "ClassExpression") {
|
|
172
|
+
visitClassElements(node, expression => this.visitExpression(expression), statement => this.visitStatement(statement));
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
166
175
|
switch (node.type) {
|
|
167
176
|
case "YieldExpression":
|
|
168
177
|
if (node.argument !== undefined) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { visitClassElements } from "../class-elements.js";
|
|
1
2
|
import { parseModule } from "../../parse/parser.js";
|
|
2
3
|
export function AS_FRONTMATTER_FIELD_UNUSED(source, options = {}) {
|
|
3
4
|
if (options.frontmatterFields === undefined) {
|
|
@@ -34,6 +35,10 @@ class ASFrontmatterFieldUnusedScanner {
|
|
|
34
35
|
}
|
|
35
36
|
}
|
|
36
37
|
visitStatement(node) {
|
|
38
|
+
if (node.type === "ClassDeclaration") {
|
|
39
|
+
visitClassElements(node, expression => this.visitExpression(expression), statement => this.visitStatement(statement));
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
37
42
|
switch (node.type) {
|
|
38
43
|
case "FunctionDeclaration":
|
|
39
44
|
this.visitArrowFunction(node);
|
|
@@ -162,6 +167,10 @@ class ASFrontmatterFieldUnusedScanner {
|
|
|
162
167
|
this.visitExpression(node.argument);
|
|
163
168
|
}
|
|
164
169
|
visitExpression(node) {
|
|
170
|
+
if (node.type === "ClassExpression") {
|
|
171
|
+
visitClassElements(node, expression => this.visitExpression(expression), statement => this.visitStatement(statement));
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
165
174
|
switch (node.type) {
|
|
166
175
|
case "YieldExpression":
|
|
167
176
|
if (node.argument !== undefined) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { visitClassElements } from "../class-elements.js";
|
|
1
2
|
import { parseModule } from "../../parse/parser.js";
|
|
2
3
|
import { hasTypedModuleRegistrations } from "./module-registry.js";
|
|
3
4
|
export function AS_JSDOC_TYPE(source, options = {}) {
|
|
@@ -27,6 +28,10 @@ class ASJsdocTypeScanner {
|
|
|
27
28
|
}
|
|
28
29
|
}
|
|
29
30
|
visitStatement(node) {
|
|
31
|
+
if (node.type === "ClassDeclaration") {
|
|
32
|
+
visitClassElements(node, expression => this.visitExpression(expression), statement => this.visitStatement(statement));
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
30
35
|
switch (node.type) {
|
|
31
36
|
case "FunctionDeclaration":
|
|
32
37
|
this.visitArrowFunction(node);
|
|
@@ -166,6 +171,10 @@ class ASJsdocTypeScanner {
|
|
|
166
171
|
}
|
|
167
172
|
}
|
|
168
173
|
visitExpression(node) {
|
|
174
|
+
if (node.type === "ClassExpression") {
|
|
175
|
+
visitClassElements(node, expression => this.visitExpression(expression), statement => this.visitStatement(statement));
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
169
178
|
switch (node.type) {
|
|
170
179
|
case "YieldExpression":
|
|
171
180
|
if (node.argument !== undefined) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { visitClassElements } from "../class-elements.js";
|
|
1
2
|
import { parseModule } from "../../parse/parser.js";
|
|
2
3
|
const DEFAULT_LARGE_LITERAL_THRESHOLD = 1000;
|
|
3
4
|
export function AS_LARGE_LITERAL(source, options = {}) {
|
|
@@ -21,6 +22,10 @@ class ASLargeLiteralScanner {
|
|
|
21
22
|
}
|
|
22
23
|
}
|
|
23
24
|
visitStatement(node) {
|
|
25
|
+
if (node.type === "ClassDeclaration") {
|
|
26
|
+
visitClassElements(node, expression => this.visitExpression(expression), statement => this.visitStatement(statement));
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
24
29
|
switch (node.type) {
|
|
25
30
|
case "FunctionDeclaration":
|
|
26
31
|
this.visitArrowFunction(node);
|
|
@@ -144,6 +149,10 @@ class ASLargeLiteralScanner {
|
|
|
144
149
|
this.visitExpression(node.argument);
|
|
145
150
|
}
|
|
146
151
|
visitExpression(node) {
|
|
152
|
+
if (node.type === "ClassExpression") {
|
|
153
|
+
visitClassElements(node, expression => this.visitExpression(expression), statement => this.visitStatement(statement));
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
147
156
|
switch (node.type) {
|
|
148
157
|
case "YieldExpression":
|
|
149
158
|
if (node.argument !== undefined) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { classDefinitionContains, visitClassElements } from "../class-elements.js";
|
|
1
2
|
import { parseModule } from "../../parse/parser.js";
|
|
2
3
|
export const AS_MISSING_ASYNC_MESSAGE = "Functions that contain await must be marked async.";
|
|
3
4
|
export function AS_MISSING_ASYNC(source, options = {}) {
|
|
@@ -27,6 +28,10 @@ class ASMissingAsyncScanner {
|
|
|
27
28
|
}
|
|
28
29
|
}
|
|
29
30
|
visitStatement(node) {
|
|
31
|
+
if (node.type === "ClassDeclaration") {
|
|
32
|
+
visitClassElements(node, expression => this.visitExpression(expression), statement => this.visitStatement(statement));
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
30
35
|
switch (node.type) {
|
|
31
36
|
case "FunctionDeclaration":
|
|
32
37
|
this.visitFunctionExpression(node);
|
|
@@ -150,6 +155,10 @@ class ASMissingAsyncScanner {
|
|
|
150
155
|
this.visitExpression(node.argument);
|
|
151
156
|
}
|
|
152
157
|
visitExpression(node) {
|
|
158
|
+
if (node.type === "ClassExpression") {
|
|
159
|
+
visitClassElements(node, expression => this.visitExpression(expression), statement => this.visitStatement(statement));
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
153
162
|
switch (node.type) {
|
|
154
163
|
case "YieldExpression":
|
|
155
164
|
if (node.argument !== undefined) {
|
|
@@ -377,6 +386,8 @@ function statementListContainsAwait(statements) {
|
|
|
377
386
|
}
|
|
378
387
|
function statementContainsAwait(node) {
|
|
379
388
|
switch (node.type) {
|
|
389
|
+
case "ClassDeclaration":
|
|
390
|
+
return classDefinitionContains(node, expressionContainsAwait);
|
|
380
391
|
case "BlockStatement":
|
|
381
392
|
return statementListContainsAwait(node.body);
|
|
382
393
|
case "ExpressionStatement":
|
|
@@ -439,6 +450,11 @@ function variableDeclarationContainsAwait(node) {
|
|
|
439
450
|
}
|
|
440
451
|
function expressionContainsAwait(node) {
|
|
441
452
|
switch (node.type) {
|
|
453
|
+
case "ClassExpression":
|
|
454
|
+
return classDefinitionContains(node, expressionContainsAwait);
|
|
455
|
+
case "NewTargetExpression":
|
|
456
|
+
case "Super":
|
|
457
|
+
return false;
|
|
442
458
|
case "AwaitExpression":
|
|
443
459
|
return true;
|
|
444
460
|
case "YieldExpression":
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { visitClassElements } from "../class-elements.js";
|
|
1
2
|
import { parseModule } from "../../parse/parser.js";
|
|
2
3
|
const MUTATING_ARRAY_METHODS = new Set([
|
|
3
4
|
"copyWithin",
|
|
@@ -32,6 +33,10 @@ class ASMutatingFrozenScanner {
|
|
|
32
33
|
});
|
|
33
34
|
}
|
|
34
35
|
visitStatement(node) {
|
|
36
|
+
if (node.type === "ClassDeclaration") {
|
|
37
|
+
visitClassElements(node, expression => this.visitExpression(expression), statement => this.visitStatement(statement));
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
35
40
|
switch (node.type) {
|
|
36
41
|
case "FunctionDeclaration":
|
|
37
42
|
this.visitArrowFunction(node);
|
|
@@ -172,6 +177,10 @@ class ASMutatingFrozenScanner {
|
|
|
172
177
|
this.visitExpression(node.argument);
|
|
173
178
|
}
|
|
174
179
|
visitExpression(node) {
|
|
180
|
+
if (node.type === "ClassExpression") {
|
|
181
|
+
visitClassElements(node, expression => this.visitExpression(expression), statement => this.visitStatement(statement));
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
175
184
|
switch (node.type) {
|
|
176
185
|
case "YieldExpression":
|
|
177
186
|
if (node.argument !== undefined) {
|