Repository: nuxt/nuxt
File: packages/nuxt/src/core/utils/parse.ts (TypeScript)

Code before:
import { parseSync } from 'oxc-parser'
import type { CatchClause, ClassBody, Declaration, Expression, MethodDefinition, ModuleDeclaration, ObjectProperty, Pattern, PrivateIdentifier, Program, PropertyDefinition, SpreadElement, Statement, Super, SwitchCase, TemplateElement } from 'oxc-parser'
import { walk as _walk } from 'estree-walker'
import type { SyncHandler } from 'estree-walker'
import type { Node as ESTreeNode, Program as ESTreeProgram, ModuleSpecifier } from 'estree'

/** estree also has AssignmentProperty, Identifier and Literal as possible node types */
export type Node = Declaration | Expression | ClassBody | CatchClause | MethodDefinition | ModuleDeclaration | ModuleSpecifier | Pattern | PrivateIdentifier | Program | SpreadElement | Statement | Super | SwitchCase | TemplateElement | ObjectProperty | PropertyDefinition

type InferThis<T extends (...args: any[]) => any> = T extends (this: infer U, ...args: infer A) => any ? U : unknown

type WalkerCallback = (this: InferThis<SyncHandler>, node: Node, parent: Node | null, ctx: { key: string | number | symbol | null | undefined, index: number | null | undefined, ast: Program | Node }) => void

export function walk (ast: Program | Node, callback: { enter?: WalkerCallback, leave?: WalkerCallback }) {
  return _walk(ast as unknown as ESTreeProgram | ESTreeNode, {
    enter (node, parent, key, index) {
      callback.enter?.call(this, node as Node, parent as Node | null, { key, index, ast })
    },
    leave (node, parent, key, index) {
      callback.leave?.call(this, node as Node, parent as Node | null, { key, index, ast })
    },
  })
}

export function parseAndWalk (code: string, sourceFilename: string, callback: WalkerCallback): Program
export function parseAndWalk (code: string, sourceFilename: string, object: { enter?: WalkerCallback, leave?: WalkerCallback }): Program
export function parseAndWalk (code: string, sourceFilename: string, callback: { enter?: WalkerCallback, leave?: WalkerCallback } | WalkerCallback) {
  const ast = parseSync(code, { sourceType: 'module', sourceFilename }).program
  walk(ast, typeof callback === 'function' ? { enter: callback } : callback)
  return ast
}


Review comment (refactor):
Can `InferThis` be replaced with `ThisParameterType` [handbook link](https://www.typescriptlang.org/docs/handbook/utility-types.html#thisparametertypetype)

Courtesy of [Dillon](https://bsky.app/profile/dillonis.online/post/3lbwtwbf4ck2b), thanks @dmmulroy

Code after:
import { walk as _walk } from 'estree-walker'
import type { Node, SyncHandler } from 'estree-walker'
import type { ArrowFunctionExpression, CatchClause, FunctionDeclaration, FunctionExpression, Identifier, ImportDefaultSpecifier, ImportNamespaceSpecifier, ImportSpecifier, Program, VariableDeclaration } from 'estree'
import { parseSync } from 'oxc-parser'
import { type SameShape, type TransformOptions, type TransformResult, transform as esbuildTransform } from 'esbuild'
import { tryUseNuxt } from '@nuxt/kit'

export type { Node }

export async function transform<T extends TransformOptions> (input: string | Uint8Array, options?: SameShape<TransformOptions, T>): Promise<TransformResult<T>> {
  return await esbuildTransform(input, { ...tryUseNuxt()?.options.esbuild.options, ...options })
}

type WithLocations<T> = T & { start: number, end: number }
type WalkerCallback = (this: ThisParameterType<SyncHandler>, node: WithLocations<Node>, parent: WithLocations<Node> | null, ctx: { key: string | number | symbol | null | undefined, index: number | null | undefined, ast: Program | Node }) => void

interface WalkOptions {
  enter: WalkerCallback
  leave: WalkerCallback
  scopeTracker: ScopeTracker
}

export function walk (ast: Program | Node, callback: Partial<WalkOptions>) {
  return _walk(ast, {
    enter (node, parent, key, index) {
      // @ts-expect-error - accessing a protected property
      callback.scopeTracker?.processNodeEnter(node as WithLocations<Node>)
      callback.enter?.call(this, node as WithLocations<Node>, parent as WithLocations<Node> | null, { key, index, ast })
    },
    leave (node, parent, key, index) {
      // @ts-expect-error - accessing a protected property
      callback.scopeTracker?.processNodeLeave(node as WithLocations<Node>)
      callback.leave?.call(this, node as WithLocations<Node>, parent as WithLocations<Node> | null, { key, index, ast })
    },
  })