Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@
"yaml": "^2.3.4"
},
"resolutions": {
"rollup": "^4.59.0"
"rollup": "^4.59.0",
"tar": "7.5.11"
},
"workspaces": [
"test/httpClient",
Expand Down
3 changes: 2 additions & 1 deletion src/hooks/instrument.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import assert from "node:assert";
import { fileURLToPath, pathToFileURL } from "node:url";
import { debuglog } from "node:util";

import { ancestor as walk, base as walkBase } from "acorn-walk";
import { base as walkBase } from "acorn-walk";
import { walkAncestor as walk } from "../util/walk";
import { extend as extendWalkWithJsx } from "acorn-jsx-walk";

// Teach acorn-walk to traverse JSX nodes produced by meriyah.
Expand Down
2 changes: 1 addition & 1 deletion src/hooks/jest.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { pathToFileURL } from "node:url";

import type { Circus } from "@jest/types";
import { simple as walk } from "acorn-walk";
import { walkSimple as walk } from "../util/walk";
import type { ESTree } from "meriyah";
import StackUtils from "stack-utils";

Expand Down
2 changes: 1 addition & 1 deletion src/hooks/mocha.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import assert from "node:assert";
import { relative } from "node:path";
import { EventEmitter } from "node:stream";

import { simple as walk } from "acorn-walk";
import { walkSimple as walk } from "../util/walk";
import type { ESTree } from "meriyah";

import { expressionFor } from ".";
Expand Down
2 changes: 1 addition & 1 deletion src/hooks/next.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import assert from "node:assert";
import { resolve } from "node:path";

import { ancestor as walk } from "acorn-walk";
import { walkAncestor as walk } from "../util/walk";
import { ESTree } from "meriyah";

import type { NextConfig } from "next";
Expand Down
2 changes: 1 addition & 1 deletion src/hooks/vitest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { relative } from "node:path";
import { pathToFileURL } from "node:url";
import worker from "node:worker_threads";

import { simple as walk } from "acorn-walk";
import { walkSimple as walk } from "../util/walk";
import { type ESTree } from "meriyah";

import config from "../config";
Expand Down
61 changes: 61 additions & 0 deletions src/util/walk.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import {
simple as acornSimple,
ancestor as acornAncestor,
type RecursiveVisitors,
} from "acorn-walk";
import type { ESTree } from "meriyah";

/**
* Why is this necessary?
* The project uses `meriyah` to parse code into an ESTree AST, and `acorn-walk` to traverse it.
* Recent updates to `acorn-walk`'s TypeScript definitions made them stricter, expecting AST nodes
* that strictly match `acorn.Node` (where `start` and `end` are strictly `number`, and other
* properties have acorn-specific types). `meriyah`'s `ESTree.Node` defines `start` and `end` as
* `number | undefined` and has minor structural typing differences. This mismatch causes
* TypeScript compilation errors when passing meriyah nodes to acorn-walk.
*
* Why is this safe?
* At runtime, `acorn-walk` only relies on the `type` property of the node and standard ESTree
* child properties to perform the traversal. It does not strictly validate the types or rely on
* acorn-specific fields that differ from standard ESTree. We use `@ts-expect-error` to bypass
* the strict compiler checks internally while providing a strongly typed ESTree interface for
* the rest of the application.
*/

// Define a type for ESTree simple visitors
export type ESTreeSimpleVisitors<TState = unknown> = {
[Type in ESTree.Node["type"]]?: (
node: Extract<ESTree.Node, { type: Type }>,
state: TState,
) => void;
};

// Define a type for ESTree ancestor visitors
export type ESTreeAncestorVisitors<TState = unknown> = {
[Type in ESTree.Node["type"]]?: (
node: Extract<ESTree.Node, { type: Type }>,
state: TState,
ancestors: ESTree.Node[],
) => void;
};

// Strongly typed wrappers for acorn-walk
export function walkSimple<TState = unknown>(
node: ESTree.Node,
visitors: ESTreeSimpleVisitors<TState>,
base?: RecursiveVisitors<TState>,
state?: TState,
): void {
// @ts-expect-error adapter for acorn-walk
acornSimple(node, visitors, base, state);
}

export function walkAncestor<TState = unknown>(
node: ESTree.Node,
visitors: ESTreeAncestorVisitors<TState>,
base?: RecursiveVisitors<TState>,
state?: TState,
): void {
// @ts-expect-error adapter for acorn-walk
acornAncestor(node, visitors, base, state);
}
Loading
Loading