poe-code 14.0.61 → 14.0.62
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 +218 -70
- 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-VAYQP2VZ.js → chunk-F7TJSPDZ.js} +7 -3
- package/packages/safe-js/dist/chunks/chunk-F7TJSPDZ.js.map +7 -0
- package/packages/safe-js/dist/chunks/{chunk-ZTGKRKQH.js → chunk-VKGWGZBH.js} +181 -66
- package/packages/safe-js/dist/chunks/chunk-VKGWGZBH.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/interp/async.js +3 -0
- package/packages/safe-js/dist/interp/function-string.d.ts +2 -0
- package/packages/safe-js/dist/interp/function-string.js +21 -0
- package/packages/safe-js/dist/interp/globals/misc.js +11 -12
- package/packages/safe-js/dist/interp/globals/numeric-parsers.d.ts +5 -0
- package/packages/safe-js/dist/interp/globals/numeric-parsers.js +47 -0
- package/packages/safe-js/dist/interp/globals/object-array.js +2 -10
- package/packages/safe-js/dist/interp/interpreter.js +1 -0
- package/packages/safe-js/dist/interp/methods/function.d.ts +2 -0
- package/packages/safe-js/dist/interp/methods/function.js +10 -1
- package/packages/safe-js/dist/interp/resources.d.ts +1 -0
- package/packages/safe-js/dist/interp/string-coercion.js +3 -0
- package/packages/safe-js/dist/interp/values.d.ts +3 -0
- package/packages/safe-js/dist/interp/values.js +3 -0
- package/packages/safe-js/dist/migrate.js +1 -1
- package/packages/safe-js/dist/parse/function-source.d.ts +7 -0
- package/packages/safe-js/dist/parse/function-source.js +1 -0
- package/packages/safe-js/dist/parse/hash.d.ts +2 -2
- package/packages/safe-js/dist/parse/hash.js +23 -9
- package/packages/safe-js/dist/parse/parser.js +36 -23
- package/packages/safe-js/dist/restore.js +2 -1
- package/packages/safe-js/dist/run.js +16 -5
- package/packages/safe-js/dist/snapshot/dump-format.d.ts +1 -1
- package/packages/safe-js/dist/snapshot/dump-format.js +1 -1
- package/packages/safe-js/dist/snapshot/migration.js +2 -2
- package/packages/safe-js/dist/snapshot/restore.js +2 -0
- package/packages/safe-js/dist/chunks/chunk-VAYQP2VZ.js.map +0 -7
- package/packages/safe-js/dist/chunks/chunk-ZTGKRKQH.js.map +0 -7
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
resolveFsConfig,
|
|
23
23
|
splitFrontmatter,
|
|
24
24
|
withBrokenPipeGuard
|
|
25
|
-
} from "./chunks/chunk-
|
|
25
|
+
} from "./chunks/chunk-F7TJSPDZ.js";
|
|
26
26
|
import {
|
|
27
27
|
Budget,
|
|
28
28
|
SandboxError,
|
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
replaceErrorStack,
|
|
35
35
|
restore,
|
|
36
36
|
run
|
|
37
|
-
} from "./chunks/chunk-
|
|
37
|
+
} from "./chunks/chunk-VKGWGZBH.js";
|
|
38
38
|
import "./chunks/chunk-UXMKEUH3.js";
|
|
39
39
|
import "./chunks/chunk-5DYEOCT5.js";
|
|
40
40
|
import "./chunks/chunk-4YIDX44G.js";
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
runWithSpawnUsageAccumulator,
|
|
27
27
|
splitFrontmatter,
|
|
28
28
|
supportsSpawnMode
|
|
29
|
-
} from "./chunks/chunk-
|
|
29
|
+
} from "./chunks/chunk-F7TJSPDZ.js";
|
|
30
30
|
import {
|
|
31
31
|
Budget,
|
|
32
32
|
FileSnapshotBackend,
|
|
@@ -50,7 +50,7 @@ import {
|
|
|
50
50
|
registerPendingHostCallPolicy,
|
|
51
51
|
restore,
|
|
52
52
|
run
|
|
53
|
-
} from "./chunks/chunk-
|
|
53
|
+
} from "./chunks/chunk-VKGWGZBH.js";
|
|
54
54
|
import "./chunks/chunk-UXMKEUH3.js";
|
|
55
55
|
import "./chunks/chunk-5DYEOCT5.js";
|
|
56
56
|
import "./chunks/chunk-4YIDX44G.js";
|
|
@@ -8,6 +8,7 @@ import { awaitSandboxValue } from "./cancel.js";
|
|
|
8
8
|
import { hoistVarDeclarations } from "./var-hoist.js";
|
|
9
9
|
import { createPatternContext } from "./interpreter.js";
|
|
10
10
|
import { getGuestFunctionProperty, setSandboxPrototype } from "./object-model.js";
|
|
11
|
+
import { functionSources } from "../parse/function-source.js";
|
|
11
12
|
import { boundIdentifiers, containsParameterExpression, getFunctionLength, hoistedVarDeclarations } from "../parse/bindings.js";
|
|
12
13
|
import { createSandboxArguments, createSandboxClosure, createSandboxGenerator, createSandboxPromise, allocateProducedSandboxValue, reconcileCompiledValues, isSandboxPromise } from "./values.js";
|
|
13
14
|
export function emitResumeBreakpoint(context, breakpoint) {
|
|
@@ -62,6 +63,7 @@ export function createInterpretedClosure(node, context, evaluateNode) {
|
|
|
62
63
|
}
|
|
63
64
|
: undefined;
|
|
64
65
|
const closure = createSandboxClosure({
|
|
66
|
+
sourceRange: functionSources.get(node),
|
|
65
67
|
guest: true,
|
|
66
68
|
sandbox: true,
|
|
67
69
|
length: getFunctionLength(node.params),
|
|
@@ -116,6 +118,7 @@ export function executeAsyncFunction(execute, budget, signal) {
|
|
|
116
118
|
}
|
|
117
119
|
function createGeneratorClosure(node, context, evaluateNode) {
|
|
118
120
|
return createSandboxClosure({
|
|
121
|
+
sourceRange: functionSources.get(node),
|
|
119
122
|
guest: true,
|
|
120
123
|
generator: true,
|
|
121
124
|
sandbox: true,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { runResources } from "./resources.js";
|
|
2
|
+
export function functionString(value) {
|
|
3
|
+
if (runResources.getStore()?.functionSourceText === false)
|
|
4
|
+
return "[object Object]";
|
|
5
|
+
const source = value.sourceRange;
|
|
6
|
+
if (source !== undefined)
|
|
7
|
+
return source.text.slice(source.start, source.end);
|
|
8
|
+
let name = value.boundTarget === undefined ? (value.name?.split("#").at(-1) ?? "") : "";
|
|
9
|
+
for (let index = 0; index < name.length; index++) {
|
|
10
|
+
const code = name.charCodeAt(index);
|
|
11
|
+
if (!((code >= 65 && code <= 90) ||
|
|
12
|
+
(code >= 97 && code <= 122) ||
|
|
13
|
+
code === 36 ||
|
|
14
|
+
code === 95 ||
|
|
15
|
+
(index > 0 && code >= 48 && code <= 57))) {
|
|
16
|
+
name = "";
|
|
17
|
+
break;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return `function ${name}() { [native code] }`;
|
|
21
|
+
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { isSandboxCollectionIterator } from "../collection-iterator.js";
|
|
2
2
|
import { assertSandboxGraphDepth } from "../../graph-depth.js";
|
|
3
3
|
import { CompileScope } from "../regex/compile-guard.js";
|
|
4
|
+
import { createNumericParsers } from "./numeric-parsers.js";
|
|
5
|
+
import { sandboxNumber } from "../string-coercion.js";
|
|
4
6
|
import { allocateProducedSandboxValue, cloneSandboxValue, createSandboxClosure, isSandboxClosure, isSandboxMap, isSandboxPromise, isSandboxSet, reconcileCompiledValues } from "../values.js";
|
|
5
7
|
export function createMiscGlobals(options) {
|
|
6
8
|
return {
|
|
@@ -9,24 +11,21 @@ export function createMiscGlobals(options) {
|
|
|
9
11
|
call: ([value], context) => structuredCloneSandboxValue(value, options.budget, context?.compilation),
|
|
10
12
|
name: "structuredClone"
|
|
11
13
|
}),
|
|
12
|
-
|
|
13
|
-
sandbox: true,
|
|
14
|
-
call: (args) => Reflect.apply(globalThis.parseInt, globalThis, [...args]),
|
|
15
|
-
name: "parseInt"
|
|
16
|
-
}),
|
|
17
|
-
parseFloat: createSandboxClosure({
|
|
18
|
-
sandbox: true,
|
|
19
|
-
call: (args) => Reflect.apply(globalThis.parseFloat, globalThis, [...args]),
|
|
20
|
-
name: "parseFloat"
|
|
21
|
-
}),
|
|
14
|
+
...createNumericParsers(options.budget),
|
|
22
15
|
isNaN: createSandboxClosure({
|
|
23
16
|
sandbox: true,
|
|
24
|
-
call: ([value]) =>
|
|
17
|
+
call: ([value], context) => {
|
|
18
|
+
const number = sandboxNumber(value, options.budget, context);
|
|
19
|
+
return typeof number === "number" ? Number.isNaN(number) : number.then(Number.isNaN);
|
|
20
|
+
},
|
|
25
21
|
name: "isNaN"
|
|
26
22
|
}),
|
|
27
23
|
isFinite: createSandboxClosure({
|
|
28
24
|
sandbox: true,
|
|
29
|
-
call: ([value]) =>
|
|
25
|
+
call: ([value], context) => {
|
|
26
|
+
const number = sandboxNumber(value, options.budget, context);
|
|
27
|
+
return typeof number === "number" ? Number.isFinite(number) : number.then(Number.isFinite);
|
|
28
|
+
},
|
|
30
29
|
name: "isFinite"
|
|
31
30
|
})
|
|
32
31
|
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { retainValues } from "../resources.js";
|
|
2
|
+
import { sandboxNumber, sandboxString } from "../string-coercion.js";
|
|
3
|
+
import { createSandboxClosure } from "../values.js";
|
|
4
|
+
export function createNumericParsers(budget) {
|
|
5
|
+
return {
|
|
6
|
+
parseInt: createSandboxClosure({
|
|
7
|
+
sandbox: true,
|
|
8
|
+
name: "parseInt",
|
|
9
|
+
call: ([value, radix], context) => {
|
|
10
|
+
const parse = (text) => {
|
|
11
|
+
const release = retainValues(budget, () => [text]);
|
|
12
|
+
let convertedRadix;
|
|
13
|
+
try {
|
|
14
|
+
convertedRadix = sandboxNumber(radix, budget, context);
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
release();
|
|
18
|
+
throw error;
|
|
19
|
+
}
|
|
20
|
+
if (typeof convertedRadix === "number") {
|
|
21
|
+
try {
|
|
22
|
+
return globalThis.parseInt(text, convertedRadix);
|
|
23
|
+
}
|
|
24
|
+
finally {
|
|
25
|
+
release();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return convertedRadix
|
|
29
|
+
.then((number) => globalThis.parseInt(text, number))
|
|
30
|
+
.finally(release);
|
|
31
|
+
};
|
|
32
|
+
const text = sandboxString(value, budget, context);
|
|
33
|
+
return typeof text === "string" ? parse(text) : text.then(parse);
|
|
34
|
+
}
|
|
35
|
+
}),
|
|
36
|
+
parseFloat: createSandboxClosure({
|
|
37
|
+
sandbox: true,
|
|
38
|
+
name: "parseFloat",
|
|
39
|
+
call: ([value], context) => {
|
|
40
|
+
const text = sandboxString(value, budget, context);
|
|
41
|
+
return typeof text === "string"
|
|
42
|
+
? globalThis.parseFloat(text)
|
|
43
|
+
: text.then(globalThis.parseFloat);
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
};
|
|
47
|
+
}
|
|
@@ -10,6 +10,7 @@ import { isFloat32Array } from "../float32.js";
|
|
|
10
10
|
import { setSandboxProperty } from "../interpreter.js";
|
|
11
11
|
import { getSandboxIterator } from "../iteration.js";
|
|
12
12
|
import { sandboxNumber, sandboxString } from "../string-coercion.js";
|
|
13
|
+
import { createNumericParsers } from "./numeric-parsers.js";
|
|
13
14
|
import { getSandboxDataProperty, getSandboxPrototype, isGuestClosure, markDescriptorObject, materializeFunctionProperties, setSandboxPrototype } from "../object-model.js";
|
|
14
15
|
import { allocateProducedSandboxValue, createSandboxClosure, deepCopyToSandbox, defineOwnDataProperty, isSandboxClosure, isSandboxGenerator, isSandboxMap, isSandboxPromise, isSandboxRegex, isSandboxSet, measureSandboxData, ownEnumerableSandboxEntries as getOwnEnumerableEntries } from "../values.js";
|
|
15
16
|
export function createObjectArrayGlobals(options) {
|
|
@@ -222,16 +223,7 @@ export function createObjectArrayGlobals(options) {
|
|
|
222
223
|
call: ([value]) => typeof value === "number" && Number.isInteger(value),
|
|
223
224
|
name: "isInteger"
|
|
224
225
|
}),
|
|
225
|
-
|
|
226
|
-
sandbox: true,
|
|
227
|
-
call: (args) => Reflect.apply(Number.parseInt, Number, [...args]),
|
|
228
|
-
name: "parseInt"
|
|
229
|
-
}),
|
|
230
|
-
parseFloat: createSandboxClosure({
|
|
231
|
-
sandbox: true,
|
|
232
|
-
call: (args) => Reflect.apply(Number.parseFloat, Number, [...args]),
|
|
233
|
-
name: "parseFloat"
|
|
234
|
-
}),
|
|
226
|
+
...createNumericParsers(options.budget),
|
|
235
227
|
isSafeInteger: createSandboxClosure({
|
|
236
228
|
sandbox: true,
|
|
237
229
|
call: ([value]) => typeof value === "number" && Number.isSafeInteger(value),
|
|
@@ -2546,6 +2546,7 @@ function createSetMethodOptions(context) {
|
|
|
2546
2546
|
}
|
|
2547
2547
|
function createFunctionMethodOptions(context) {
|
|
2548
2548
|
return {
|
|
2549
|
+
budget: context.budget,
|
|
2549
2550
|
callClosure: (closure, args, stack, thisValue, construct) => invokeSandboxClosure(closure, args, context, stack, undefined, thisValue, construct)
|
|
2550
2551
|
};
|
|
2551
2552
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { type SandboxClosure, type SandboxValue } from "../values.js";
|
|
2
|
+
import type { Budget } from "../budget.js";
|
|
2
3
|
export type FunctionMethodOptions = {
|
|
4
|
+
budget?: Budget;
|
|
3
5
|
callClosure: (closure: SandboxClosure, args: readonly SandboxValue[], stack: readonly string[], thisValue: SandboxValue, construct?: boolean) => Promise<SandboxValue> | SandboxValue;
|
|
4
6
|
};
|
|
5
7
|
export declare function getFunctionMember(target: SandboxClosure, property: string | number, options: FunctionMethodOptions): SandboxValue | undefined;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { createSandboxClosure, isSandboxClosure } from "../values.js";
|
|
2
2
|
import { getGuestFunctionProperty, isGuestClosure } from "../object-model.js";
|
|
3
|
-
|
|
3
|
+
import { functionString } from "../function-string.js";
|
|
4
|
+
import { runResources } from "../resources.js";
|
|
5
|
+
const functionMethodNames = new Set(["apply", "bind", "call", "toString"]);
|
|
4
6
|
export function getFunctionMember(target, property, options) {
|
|
5
7
|
if (isGuestClosure(target)) {
|
|
6
8
|
const value = getGuestFunctionProperty(target, String(property));
|
|
@@ -16,12 +18,15 @@ export function getFunctionMember(target, property, options) {
|
|
|
16
18
|
if (property === "length") {
|
|
17
19
|
return target.length;
|
|
18
20
|
}
|
|
21
|
+
if (property === "toString" && runResources.getStore()?.functionSourceText === false)
|
|
22
|
+
return undefined;
|
|
19
23
|
if (!isFunctionMethodName(property)) {
|
|
20
24
|
return undefined;
|
|
21
25
|
}
|
|
22
26
|
return createSandboxClosure({
|
|
23
27
|
sandbox: true,
|
|
24
28
|
name: `Function#${property}`,
|
|
29
|
+
...(property === "toString" ? { length: 0 } : {}),
|
|
25
30
|
call: (args, context) => callFunctionMethod(context?.thisValue, property, args, options, context?.stack ?? [])
|
|
26
31
|
});
|
|
27
32
|
}
|
|
@@ -32,6 +37,10 @@ function callFunctionMethod(target, methodName, args, options, stack) {
|
|
|
32
37
|
if (!isSandboxClosure(target)) {
|
|
33
38
|
throw new TypeError(`Function#${methodName} requires a callable receiver.`);
|
|
34
39
|
}
|
|
40
|
+
if (methodName === "toString") {
|
|
41
|
+
const text = functionString(target);
|
|
42
|
+
return options.budget?.allocateString(text) ?? text;
|
|
43
|
+
}
|
|
35
44
|
const thisValue = args[0];
|
|
36
45
|
if (methodName === "bind") {
|
|
37
46
|
const boundArgs = args.slice(1);
|
|
@@ -8,6 +8,7 @@ import { collectionIteratorState, isSandboxCollectionIterator } from "./collecti
|
|
|
8
8
|
import { getGuestFunctionProperties, getSandboxPrototype, hasExplicitSandboxPrototype, isGuestClosure } from "./object-model.js";
|
|
9
9
|
import { getRegexMember } from "./methods/regex.js";
|
|
10
10
|
import { retainValues } from "./resources.js";
|
|
11
|
+
import { functionString } from "./function-string.js";
|
|
11
12
|
import { isSandboxClosure, isSandboxPromise, isSandboxMap, isSandboxSet, isSandboxRegex, isSandboxGenerator } from "./values.js";
|
|
12
13
|
const defaultStringHook = Symbol("defaultStringHook");
|
|
13
14
|
const defaultValueHook = Symbol("defaultValueHook");
|
|
@@ -96,6 +97,8 @@ function conversionHook(value, name, budget) {
|
|
|
96
97
|
return undefined;
|
|
97
98
|
}
|
|
98
99
|
async function defaultToString(value, budget, context, joining) {
|
|
100
|
+
if (isSandboxClosure(value))
|
|
101
|
+
return budget.allocateString(functionString(value));
|
|
99
102
|
if (isSandboxMap(value))
|
|
100
103
|
return "[object Map]";
|
|
101
104
|
if (isSandboxSet(value))
|
|
@@ -4,6 +4,7 @@ import type { Budget, CompileTicket } from "./budget.js";
|
|
|
4
4
|
import { CompileScope } from "./regex/compile-guard.js";
|
|
5
5
|
import type { GeneratorChannel } from "./generator.js";
|
|
6
6
|
import { type RegexPattern } from "./regex/parse.js";
|
|
7
|
+
import type { FunctionSource } from "../parse/function-source.js";
|
|
7
8
|
export { createSandboxArguments, isSandboxArguments } from "./arguments.js";
|
|
8
9
|
export { isSandboxMap, isSandboxSet } from "./collection-brands.js";
|
|
9
10
|
declare const sandboxClosureBrand: unique symbol;
|
|
@@ -57,6 +58,7 @@ export type SandboxCallContext = {
|
|
|
57
58
|
readonly invokeClosure?: (closure: SandboxClosure, args: readonly SandboxValue[], thisValue: SandboxValue, construct?: boolean) => Promise<SandboxValue>;
|
|
58
59
|
};
|
|
59
60
|
export type SandboxClosure = {
|
|
61
|
+
readonly sourceRange?: FunctionSource;
|
|
60
62
|
readonly async?: true;
|
|
61
63
|
readonly generator?: true;
|
|
62
64
|
readonly sandbox?: true;
|
|
@@ -94,6 +96,7 @@ type CopyFromSandboxOptions = {
|
|
|
94
96
|
compilation?: CompileScope;
|
|
95
97
|
};
|
|
96
98
|
export declare function createSandboxClosure(input: {
|
|
99
|
+
sourceRange?: FunctionSource;
|
|
97
100
|
guest?: boolean;
|
|
98
101
|
async?: boolean;
|
|
99
102
|
generator?: boolean;
|
|
@@ -39,6 +39,9 @@ export function createSandboxClosure(input) {
|
|
|
39
39
|
enumerable: false,
|
|
40
40
|
value: true
|
|
41
41
|
});
|
|
42
|
+
if (input.sourceRange !== undefined) {
|
|
43
|
+
Object.defineProperty(closure, "sourceRange", { value: input.sourceRange });
|
|
44
|
+
}
|
|
42
45
|
if (input.sandbox === true) {
|
|
43
46
|
Object.defineProperty(closure, "sandbox", { value: true });
|
|
44
47
|
}
|
|
@@ -12,7 +12,7 @@ export function inspectSnapshotMigration(snapshot, options) {
|
|
|
12
12
|
validateSnapshotData(snapshot);
|
|
13
13
|
validateDumpEnvelope(snapshot);
|
|
14
14
|
validateMigrationSemantics(snapshot.executionSemantics);
|
|
15
|
-
const sourceHash = hashSource(options.source);
|
|
15
|
+
const sourceHash = hashSource(options.source, undefined, snapshot.executionSemantics === EXECUTION_SEMANTICS);
|
|
16
16
|
if (snapshot.sourceHash !== sourceHash)
|
|
17
17
|
throw new TypeError(`Migration requires the original executable source (checkpoint hash ${snapshot.sourceHash}, supplied ${sourceHash}). Preserve the checkpoint; do not replace its hash.`);
|
|
18
18
|
validateSnapshotMigration(snapshot.migration, sourceHash);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const functionSources = new WeakMap();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { type Module, type ParseResult } from "./parser.js";
|
|
2
2
|
import { type CompileOwner } from "../interp/budget.js";
|
|
3
|
-
export declare function hashSource(source: string, owner?: CompileOwner): string;
|
|
4
|
-
export declare function hashParsedAst(ast: Module | ParseResult): string;
|
|
3
|
+
export declare function hashSource(source: string, owner?: CompileOwner, includeFunctionSource?: boolean): string;
|
|
4
|
+
export declare function hashParsedAst(ast: Module | ParseResult, includeFunctionSource?: boolean): string;
|
|
@@ -1,23 +1,24 @@
|
|
|
1
1
|
import { parse, parseModule } from "./parser.js";
|
|
2
2
|
import { SandboxError } from "../interp/budget.js";
|
|
3
|
+
import { functionSources } from "./function-source.js";
|
|
3
4
|
const FNV_OFFSET_BASIS = 0x811c9dc5;
|
|
4
5
|
const FNV_PRIME = 0x01000193;
|
|
5
6
|
const IGNORED_KEYS = new Set(["nodeId", "raw", "span"]);
|
|
6
|
-
export function hashSource(source, owner) {
|
|
7
|
+
export function hashSource(source, owner, includeFunctionSource = true) {
|
|
7
8
|
try {
|
|
8
|
-
return hashParsedAst(parse(source, "<input>", owner));
|
|
9
|
+
return hashParsedAst(parse(source, "<input>", owner), includeFunctionSource);
|
|
9
10
|
}
|
|
10
11
|
catch (error) {
|
|
11
12
|
if (error instanceof SandboxError)
|
|
12
13
|
throw error;
|
|
13
|
-
return hashParsedAst(parseModule(source, "<input>", owner));
|
|
14
|
+
return hashParsedAst(parseModule(source, "<input>", owner), includeFunctionSource);
|
|
14
15
|
}
|
|
15
16
|
}
|
|
16
|
-
export function hashParsedAst(ast) {
|
|
17
|
+
export function hashParsedAst(ast, includeFunctionSource = true) {
|
|
17
18
|
let hash = FNV_OFFSET_BASIS;
|
|
18
19
|
visit(ast);
|
|
19
20
|
return hash.toString(16).padStart(8, "0");
|
|
20
|
-
function visit(value, includeTemplateRaw = false) {
|
|
21
|
+
function visit(value, includeTemplateRaw = false, enclosingSource) {
|
|
21
22
|
if (value === null) {
|
|
22
23
|
write("null");
|
|
23
24
|
return;
|
|
@@ -29,7 +30,7 @@ export function hashParsedAst(ast) {
|
|
|
29
30
|
if (Array.isArray(value)) {
|
|
30
31
|
write("[");
|
|
31
32
|
for (const entry of value) {
|
|
32
|
-
visit(entry, includeTemplateRaw);
|
|
33
|
+
visit(entry, includeTemplateRaw, enclosingSource);
|
|
33
34
|
write(",");
|
|
34
35
|
}
|
|
35
36
|
write("]");
|
|
@@ -47,6 +48,19 @@ export function hashParsedAst(ast) {
|
|
|
47
48
|
return;
|
|
48
49
|
case "object": {
|
|
49
50
|
const record = value;
|
|
51
|
+
const source = includeFunctionSource
|
|
52
|
+
? functionSources.get(value)
|
|
53
|
+
: undefined;
|
|
54
|
+
if (source !== undefined &&
|
|
55
|
+
!(enclosingSource !== undefined &&
|
|
56
|
+
source.text === enclosingSource.text &&
|
|
57
|
+
source.start >= enclosingSource.start &&
|
|
58
|
+
source.end <= enclosingSource.end)) {
|
|
59
|
+
write("function-source:");
|
|
60
|
+
write(String(source.end - source.start));
|
|
61
|
+
write(":");
|
|
62
|
+
write(source.text, source.start, source.end);
|
|
63
|
+
}
|
|
50
64
|
const keys = Object.keys(value)
|
|
51
65
|
.filter((key) => shouldHashKey(record, key, includeTemplateRaw))
|
|
52
66
|
.sort();
|
|
@@ -54,7 +68,7 @@ export function hashParsedAst(ast) {
|
|
|
54
68
|
for (const key of keys) {
|
|
55
69
|
write(JSON.stringify(key));
|
|
56
70
|
write(":");
|
|
57
|
-
visit(record[key], shouldIncludeTemplateRaw(record, key, includeTemplateRaw));
|
|
71
|
+
visit(record[key], shouldIncludeTemplateRaw(record, key, includeTemplateRaw), source ?? enclosingSource);
|
|
58
72
|
write(",");
|
|
59
73
|
}
|
|
60
74
|
write("}");
|
|
@@ -64,8 +78,8 @@ export function hashParsedAst(ast) {
|
|
|
64
78
|
throw new TypeError(`Unsupported AST value type: ${typeof value}`);
|
|
65
79
|
}
|
|
66
80
|
}
|
|
67
|
-
function write(chunk) {
|
|
68
|
-
for (let index =
|
|
81
|
+
function write(chunk, start = 0, end = chunk.length) {
|
|
82
|
+
for (let index = start; index < end; index += 1) {
|
|
69
83
|
hash ^= chunk.charCodeAt(index);
|
|
70
84
|
hash = Math.imul(hash, FNV_PRIME) >>> 0;
|
|
71
85
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { boundIdentifiers } from "./bindings.js";
|
|
2
2
|
import { tokenize } from "./tokenizer.js";
|
|
3
3
|
import { assignIds } from "./assign-ids.js";
|
|
4
|
+
import { functionSources } from "./function-source.js";
|
|
4
5
|
import { formatParseError } from "./format-error.js";
|
|
5
6
|
import { createExportDefaultDeclaration, createExportNamedDeclaration } from "./parse-export.js";
|
|
6
7
|
import { createImportMeta, isImportMetaTokenSequence } from "./parse-import-meta.js";
|
|
@@ -42,7 +43,7 @@ const TOP_LEVEL_STATEMENT_KEYWORDS = new Set([
|
|
|
42
43
|
export function parse(source, filename = "<input>", owner) {
|
|
43
44
|
const compilation = new CompileScope(owner);
|
|
44
45
|
try {
|
|
45
|
-
const result = assignIds(
|
|
46
|
+
const result = assignIds(new Parser(tokenize(source, { allowRegexLiterals: true, compilation }), source, compilation).parseTopLevel());
|
|
46
47
|
const regexLiteral = findRegexLiteral(result);
|
|
47
48
|
if (regexLiteral !== undefined) {
|
|
48
49
|
throw new Error(`Regular expression literals are not supported at line ${regexLiteral.span.start.line}, column ${regexLiteral.span.start.column}.`);
|
|
@@ -66,7 +67,7 @@ export function parse(source, filename = "<input>", owner) {
|
|
|
66
67
|
export function parseModule(source, filename = "<input>", owner) {
|
|
67
68
|
const compilation = new CompileScope(owner);
|
|
68
69
|
try {
|
|
69
|
-
return assignIds(
|
|
70
|
+
return assignIds(new Parser(tokenize(source, { allowRegexLiterals: true, compilation }), source, compilation).parseModule());
|
|
70
71
|
}
|
|
71
72
|
catch (error) {
|
|
72
73
|
if (error instanceof DisallowedSyntaxError || error instanceof SandboxError) {
|
|
@@ -84,7 +85,7 @@ export function parseModule(source, filename = "<input>", owner) {
|
|
|
84
85
|
export function parseExecutableModule(source, filename = "<input>", owner) {
|
|
85
86
|
const compilation = new CompileScope(owner);
|
|
86
87
|
try {
|
|
87
|
-
const result = assignIds(
|
|
88
|
+
const result = assignIds(new Parser(tokenize(source, { allowRegexLiterals: true, compilation }), source, compilation).parseModule());
|
|
88
89
|
throwIfImportMetaAssignment(result);
|
|
89
90
|
return result;
|
|
90
91
|
}
|
|
@@ -101,14 +102,9 @@ export function parseExecutableModule(source, filename = "<input>", owner) {
|
|
|
101
102
|
compilation.dispose();
|
|
102
103
|
}
|
|
103
104
|
}
|
|
104
|
-
function parseTokens(tokens, compilation) {
|
|
105
|
-
return new Parser(tokens, compilation).parseTopLevel();
|
|
106
|
-
}
|
|
107
|
-
function parseModuleTokens(tokens, compilation) {
|
|
108
|
-
return new Parser(tokens, compilation).parseModule();
|
|
109
|
-
}
|
|
110
105
|
class Parser {
|
|
111
106
|
tokens;
|
|
107
|
+
source;
|
|
112
108
|
compilation;
|
|
113
109
|
functionContext;
|
|
114
110
|
index = 0;
|
|
@@ -119,12 +115,21 @@ class Parser {
|
|
|
119
115
|
scopes = [new Map()];
|
|
120
116
|
functionScopes = new WeakSet();
|
|
121
117
|
varNames = new WeakMap();
|
|
122
|
-
constructor(tokens, compilation, functionContext = "normal") {
|
|
118
|
+
constructor(tokens, source, compilation, functionContext = "normal") {
|
|
123
119
|
this.tokens = tokens;
|
|
120
|
+
this.source = source;
|
|
124
121
|
this.compilation = compilation;
|
|
125
122
|
this.functionContext = functionContext;
|
|
126
123
|
this.functionScopes.add(this.scopes[0]);
|
|
127
124
|
}
|
|
125
|
+
withFunctionSource(node) {
|
|
126
|
+
functionSources.set(node, {
|
|
127
|
+
text: this.source,
|
|
128
|
+
start: node.span.start.offset,
|
|
129
|
+
end: node.span.end.offset
|
|
130
|
+
});
|
|
131
|
+
return node;
|
|
132
|
+
}
|
|
128
133
|
parseTopLevel() {
|
|
129
134
|
if (this.isExportToken(this.currentToken())) {
|
|
130
135
|
throw new DisallowedSyntaxError("export", this.currentToken().start);
|
|
@@ -270,14 +275,14 @@ class Parser {
|
|
|
270
275
|
});
|
|
271
276
|
this.expectPunctuator("=>");
|
|
272
277
|
const body = this.parseArrowFunctionBody(params);
|
|
273
|
-
return {
|
|
278
|
+
return this.withFunctionSource({
|
|
274
279
|
type: "ArrowFunctionExpression",
|
|
275
280
|
async: isAsync,
|
|
276
281
|
body,
|
|
277
282
|
expression: body.type !== "BlockStatement",
|
|
278
283
|
params,
|
|
279
284
|
span: createSpan(start, body.span.end)
|
|
280
|
-
};
|
|
285
|
+
});
|
|
281
286
|
}
|
|
282
287
|
parseConditionalExpression() {
|
|
283
288
|
if (this.conditionalExpressionDepth >= MAX_CONDITIONAL_EXPRESSION_DEPTH) {
|
|
@@ -920,7 +925,7 @@ class Parser {
|
|
|
920
925
|
});
|
|
921
926
|
const generator = generatorToken !== undefined;
|
|
922
927
|
const body = this.withFunctionContext(generator ? "generator" : "normal", () => this.parseBlockStatement(params));
|
|
923
|
-
return {
|
|
928
|
+
return this.withFunctionSource({
|
|
924
929
|
type: "FunctionDeclaration",
|
|
925
930
|
async: asyncToken !== undefined,
|
|
926
931
|
body,
|
|
@@ -928,7 +933,7 @@ class Parser {
|
|
|
928
933
|
id,
|
|
929
934
|
params,
|
|
930
935
|
span: createSpan(asyncToken?.start ?? functionToken.start, body.span.end)
|
|
931
|
-
};
|
|
936
|
+
});
|
|
932
937
|
}
|
|
933
938
|
parseVariableDeclarator(kind) {
|
|
934
939
|
const id = this.parseBindingTarget();
|
|
@@ -1669,7 +1674,11 @@ class Parser {
|
|
|
1669
1674
|
continue;
|
|
1670
1675
|
}
|
|
1671
1676
|
if (this.currentToken().type === "template") {
|
|
1672
|
-
const quasi = createTemplateLiteral(this.currentToken(), {
|
|
1677
|
+
const quasi = createTemplateLiteral(this.currentToken(), {
|
|
1678
|
+
allowMalformedEscapes: true,
|
|
1679
|
+
functionContext: this.functionContext,
|
|
1680
|
+
source: this.source
|
|
1681
|
+
}, this.compilation);
|
|
1673
1682
|
this.index += 1;
|
|
1674
1683
|
expression = {
|
|
1675
1684
|
node: {
|
|
@@ -1757,7 +1766,11 @@ class Parser {
|
|
|
1757
1766
|
if (token.type === "template") {
|
|
1758
1767
|
this.index += 1;
|
|
1759
1768
|
return {
|
|
1760
|
-
node: createTemplateLiteral(token, {
|
|
1769
|
+
node: createTemplateLiteral(token, {
|
|
1770
|
+
allowMalformedEscapes: false,
|
|
1771
|
+
functionContext: this.functionContext,
|
|
1772
|
+
source: this.source
|
|
1773
|
+
}, this.compilation),
|
|
1761
1774
|
parenthesized: false
|
|
1762
1775
|
};
|
|
1763
1776
|
}
|
|
@@ -1875,7 +1888,7 @@ class Parser {
|
|
|
1875
1888
|
});
|
|
1876
1889
|
const generator = generatorToken !== undefined;
|
|
1877
1890
|
const body = this.withFunctionContext(generator ? "generator" : "normal", () => this.parseBlockStatement(params));
|
|
1878
|
-
return {
|
|
1891
|
+
return this.withFunctionSource({
|
|
1879
1892
|
type: "FunctionExpression",
|
|
1880
1893
|
async: asyncToken !== undefined,
|
|
1881
1894
|
body,
|
|
@@ -1883,7 +1896,7 @@ class Parser {
|
|
|
1883
1896
|
id,
|
|
1884
1897
|
params,
|
|
1885
1898
|
span: createSpan(asyncToken?.start ?? functionToken.start, body.span.end)
|
|
1886
|
-
};
|
|
1899
|
+
});
|
|
1887
1900
|
}
|
|
1888
1901
|
parseArrayExpression() {
|
|
1889
1902
|
const start = this.expectPunctuator("[");
|
|
@@ -2139,7 +2152,7 @@ class Parser {
|
|
|
2139
2152
|
return parsedParams;
|
|
2140
2153
|
});
|
|
2141
2154
|
const body = this.withFunctionContext("normal", () => this.parseBlockStatement(params));
|
|
2142
|
-
return {
|
|
2155
|
+
return this.withFunctionSource({
|
|
2143
2156
|
type: "FunctionExpression",
|
|
2144
2157
|
async: asyncToken !== undefined,
|
|
2145
2158
|
body,
|
|
@@ -2148,7 +2161,7 @@ class Parser {
|
|
|
2148
2161
|
method: true,
|
|
2149
2162
|
params,
|
|
2150
2163
|
span: createSpan(asyncToken?.start ?? methodStart, body.span.end)
|
|
2151
|
-
};
|
|
2164
|
+
});
|
|
2152
2165
|
}
|
|
2153
2166
|
parseIdentifierName() {
|
|
2154
2167
|
const token = this.currentToken();
|
|
@@ -3033,7 +3046,7 @@ function createTemplateLiteral(token, options, compilation) {
|
|
|
3033
3046
|
quasis.push(createTemplateElement(token.start, raw, quasiStart, cursor, false, options));
|
|
3034
3047
|
const expressionStart = cursor + 2;
|
|
3035
3048
|
const expressionEnd = findTemplateExpressionEnd(raw, expressionStart);
|
|
3036
|
-
expressions.push(parseEmbeddedExpression(raw.slice(expressionStart, expressionEnd), positionWithinRaw(token.start, raw, expressionStart), options.functionContext, compilation));
|
|
3049
|
+
expressions.push(parseEmbeddedExpression(raw.slice(expressionStart, expressionEnd), positionWithinRaw(token.start, raw, expressionStart), options.functionContext, options.source, compilation));
|
|
3037
3050
|
quasiStart = expressionEnd + 1;
|
|
3038
3051
|
cursor = expressionEnd + 1;
|
|
3039
3052
|
continue;
|
|
@@ -3394,13 +3407,13 @@ function decodeHexEscape(value, start) {
|
|
|
3394
3407
|
end: index + 2
|
|
3395
3408
|
};
|
|
3396
3409
|
}
|
|
3397
|
-
function parseEmbeddedExpression(source, base, functionContext, compilation) {
|
|
3410
|
+
function parseEmbeddedExpression(source, base, functionContext, fullSource, compilation) {
|
|
3398
3411
|
const tokens = tokenize(source, { allowRegexLiterals: true, compilation }).map((token) => ({
|
|
3399
3412
|
...token,
|
|
3400
3413
|
start: rebasePosition(token.start, base),
|
|
3401
3414
|
end: rebasePosition(token.end, base)
|
|
3402
3415
|
}));
|
|
3403
|
-
return new Parser(tokens, compilation, functionContext).parseExpressionOnly();
|
|
3416
|
+
return new Parser(tokens, fullSource, compilation, functionContext).parseExpressionOnly();
|
|
3404
3417
|
}
|
|
3405
3418
|
export function findRegexLiteral(node) {
|
|
3406
3419
|
if (node === null || node === undefined) {
|