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.
Files changed (39) hide show
  1. package/dist/index.js +218 -70
  2. package/dist/index.js.map +4 -4
  3. package/dist/metafile.json +1 -1
  4. package/package.json +1 -1
  5. package/packages/safe-js/dist/chunks/{chunk-VAYQP2VZ.js → chunk-F7TJSPDZ.js} +7 -3
  6. package/packages/safe-js/dist/chunks/chunk-F7TJSPDZ.js.map +7 -0
  7. package/packages/safe-js/dist/chunks/{chunk-ZTGKRKQH.js → chunk-VKGWGZBH.js} +181 -66
  8. package/packages/safe-js/dist/chunks/chunk-VKGWGZBH.js.map +7 -0
  9. package/packages/safe-js/dist/cli.js +2 -2
  10. package/packages/safe-js/dist/core.js +1 -1
  11. package/packages/safe-js/dist/index.js +2 -2
  12. package/packages/safe-js/dist/interp/async.js +3 -0
  13. package/packages/safe-js/dist/interp/function-string.d.ts +2 -0
  14. package/packages/safe-js/dist/interp/function-string.js +21 -0
  15. package/packages/safe-js/dist/interp/globals/misc.js +11 -12
  16. package/packages/safe-js/dist/interp/globals/numeric-parsers.d.ts +5 -0
  17. package/packages/safe-js/dist/interp/globals/numeric-parsers.js +47 -0
  18. package/packages/safe-js/dist/interp/globals/object-array.js +2 -10
  19. package/packages/safe-js/dist/interp/interpreter.js +1 -0
  20. package/packages/safe-js/dist/interp/methods/function.d.ts +2 -0
  21. package/packages/safe-js/dist/interp/methods/function.js +10 -1
  22. package/packages/safe-js/dist/interp/resources.d.ts +1 -0
  23. package/packages/safe-js/dist/interp/string-coercion.js +3 -0
  24. package/packages/safe-js/dist/interp/values.d.ts +3 -0
  25. package/packages/safe-js/dist/interp/values.js +3 -0
  26. package/packages/safe-js/dist/migrate.js +1 -1
  27. package/packages/safe-js/dist/parse/function-source.d.ts +7 -0
  28. package/packages/safe-js/dist/parse/function-source.js +1 -0
  29. package/packages/safe-js/dist/parse/hash.d.ts +2 -2
  30. package/packages/safe-js/dist/parse/hash.js +23 -9
  31. package/packages/safe-js/dist/parse/parser.js +36 -23
  32. package/packages/safe-js/dist/restore.js +2 -1
  33. package/packages/safe-js/dist/run.js +16 -5
  34. package/packages/safe-js/dist/snapshot/dump-format.d.ts +1 -1
  35. package/packages/safe-js/dist/snapshot/dump-format.js +1 -1
  36. package/packages/safe-js/dist/snapshot/migration.js +2 -2
  37. package/packages/safe-js/dist/snapshot/restore.js +2 -0
  38. package/packages/safe-js/dist/chunks/chunk-VAYQP2VZ.js.map +0 -7
  39. 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-VAYQP2VZ.js";
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-ZTGKRKQH.js";
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";
@@ -5,7 +5,7 @@ import {
5
5
  defineExtension,
6
6
  lint,
7
7
  run
8
- } from "./chunks/chunk-ZTGKRKQH.js";
8
+ } from "./chunks/chunk-VKGWGZBH.js";
9
9
  import "./chunks/chunk-4YIDX44G.js";
10
10
  export {
11
11
  Budget,
@@ -26,7 +26,7 @@ import {
26
26
  runWithSpawnUsageAccumulator,
27
27
  splitFrontmatter,
28
28
  supportsSpawnMode
29
- } from "./chunks/chunk-VAYQP2VZ.js";
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-ZTGKRKQH.js";
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,2 @@
1
+ import type { SandboxClosure } from "./values.js";
2
+ export declare function functionString(value: SandboxClosure): string;
@@ -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
- parseInt: createSandboxClosure({
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]) => globalThis.isNaN(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]) => globalThis.isFinite(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,5 @@
1
+ import type { Budget } from "../budget.js";
2
+ export declare function createNumericParsers(budget: Budget): {
3
+ parseInt: import("../values.js").SandboxClosure;
4
+ parseFloat: import("../values.js").SandboxClosure;
5
+ };
@@ -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
- parseInt: createSandboxClosure({
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
- const functionMethodNames = new Set(["apply", "bind", "call"]);
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);
@@ -2,6 +2,7 @@ import { AsyncLocalStorage } from "node:async_hooks";
2
2
  import type { Budget } from "./budget.js";
3
3
  export type RunResources = {
4
4
  signal: AbortSignal;
5
+ functionSourceText?: boolean;
5
6
  referenceReleases: Set<() => void>;
6
7
  add(close: () => Promise<void>): void;
7
8
  };
@@ -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,7 @@
1
+ import type { FunctionNode } from "./parser.js";
2
+ export type FunctionSource = {
3
+ readonly text: string;
4
+ readonly start: number;
5
+ readonly end: number;
6
+ };
7
+ export declare const functionSources: WeakMap<FunctionNode, FunctionSource>;
@@ -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 = 0; index < chunk.length; index += 1) {
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(parseTokens(tokenize(source, { allowRegexLiterals: true, compilation }), compilation));
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(parseModuleTokens(tokenize(source, { allowRegexLiterals: true, compilation }), compilation));
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(parseModuleTokens(tokenize(source, { allowRegexLiterals: true, compilation }), compilation));
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(), { allowMalformedEscapes: true, functionContext: this.functionContext }, this.compilation);
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, { allowMalformedEscapes: false, functionContext: this.functionContext }, this.compilation),
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) {