Skip to main content

acornwalk

A pure Python semantic walker for ECMAScript ESTree ASTs, targeting node shapes used by ECMAScript 2026 and the explicit JSX extension. Python 3.11+; no runtime dependencies. Native parser objects and deserialized mappings are accepted without copying nodes or mutating the AST.

python -m pip install "acornwalk>=2,<3"

The 2.x release preserves the import and camelCase APIs and requires Python 3.11 or newer. It has no runtime dependencies. For native parser ASTs, install esprima-fork 5.x separately (imported as esprima) and request range=True when using position searches. See the migration notes for the changes to searches, callback state and result objects.

import acornwalk as walk
ast = {"type": "Program", "range": [0, 2], "body": [
    {"type": "ExpressionStatement", "range": [0, 2], "expression":
        {"type": "Identifier", "name": "x", "range": [0, 1]}}
]}
names = []
walk.simple(ast, {"Identifier": lambda node, state: state.append(node["name"])}, state=names)
assert names == ["x"]
assert walk.findNodeAt(ast, 0, 1, "Identifier").node is ast["body"][0]["expression"]
API Callback or result
simple(node, visitors, baseVisitor=None, state=None, override=None) Postorder visitor(node, state)
ancestor(node, visitors, baseVisitor=None, state=None, override=None) Postorder visitor(node, state, ancestors)
recursive(node, state, funcs, baseVisitor=None, override=None) visitor(node, state, recurse) controls child recursion
full(node, callback, baseVisitor=None, state=None, override=None) callback(node, state, category)
fullAncestor(node, callback, baseVisitor=None, state=None, override=None) callback(node, state, ancestors, category)
make(funcs, baseVisitor=None) Independent handler overlay
findNodeAt(node, start, end, test=None, baseVisitor=None, state=None) Innermost exact range match; None bounds are wildcards
findNodeAround(node, pos, test=None, baseVisitor=None, state=None) Innermost containing match, including end boundary
findNodeAfter(node, pos, test=None, baseVisitor=None, state=None) First outermost match starting at/after pos
findNodeBefore(node, pos, test=None, baseVisitor=None, state=None) Greatest end at/before pos; ties favor outer nodes

Searches return Found(node, state) or None. Tests are node type strings, None for any type, or (category, node) -> bool callables. Callback exceptions propagate. Ancestor stacks contain the current node and are reused; copy the list when retaining it. State None supplies ancestors as state for ancestor walkers. Explicit False, 0, "", {} and [] remain the supplied state.

seen = []
walk.fullAncestor(ast, lambda node, state, stack, category:
    seen.append((walk.getField(node, "type"), len(stack))))
walk.recursive(ast, names, {"Identifier": lambda node, state, recurse:
    state.append(walk.getField(node, "name"))})
base = walk.make({"MyExtension": lambda node, state, recurse:
    recurse(walk.getField(node, "argument"), state, "Expression")})
walk.simple({"type": "MyExtension", "argument": ast["body"][0]["expression"]}, {}, base)

Visitor keys may be concrete types or categories such as Expression, Statement, Pattern and VariablePattern. Bindings use VariablePattern; ordinary references use Identifier. Noncomputed keys, labels, import binding metadata, export specifier metadata and meta-property names are skipped as evaluated references. Import attributes visit their value, not their key. This is semantic traversal, not an exhaustive serialization visitor.

Custom bases may be mappings, Base objects or overlays. Instance and subclass overrides are honored. Base handlers have the unbound signature (node, state, recurse); subclass handlers should use that signature or @staticmethod. make does not mutate the supplied base. Unknown types raise ValueError naming the type and the extension mechanism.

Positions are nonnegative integer UTF-16 code-unit offsets. Searches use start/end or two-element range; start/end take precedence. Astral characters occupy two units. Offsets are read as supplied, not converted from Python scalar indices. With esprima-fork, request range=True. Missing/invalid positions raise ValueError. nodeRange(node) exposes this accessor. getField(node, name, default=None) reads mapping/attribute fields and native isAsync/async_ and allowAwait/await_ aliases. An explicit canonical mapping field takes precedence. Missing native fields honor the supplied default even for esprima's permissive attribute lookup; declared null fields retain None.

Modern traversal covers object rest/spread, async functions/generators, for-await metadata, chains, private names, public/private fields, static blocks, module attributes and dynamic import options. Operators and literal metadata use ordinary expression/leaf shapes. Legacy FieldDefinition is accepted as a PropertyDefinition alias. Explicit JSX handlers cover elements, fragments, names, attributes, expression containers, spread attributes/children and empty expressions. JSX names keep their JSX-specific node types.

TypeScript, Flow, decorators and other proposal nodes require custom visitors. The walker does not validate grammar or editions. Mechanically walking an unknown declaration kind with existing node shapes does not advertise parser support for proposals. Circular graphs and excessive recursion depth are outside the AST contract.

See contributor instructions and CI results. Core parity is pinned to acorn-walk in acorn 8.15.0. Python differences include None state handling, mappings/ranges, validated offsets, native aliases and the documented JSX extension.

Performance measurements compare the original, modern starting and current versions, including the old destructuring omission and remaining native validation cost.

Release automation and version bumps are documented in RELEASING.md.

Metadata

Release files for acornwalk 2.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for acornwalk 2.0.0
File Size Uploaded Provenance
acornwalk-2.0.0.tar.gz 49.0 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for acornwalk 2.0.0
File Interpreter ABI Platform
acornwalk-2.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 62.1 kB

Release files / acornwalk-2.0.0.tar.gz

Download URL acornwalk-2.0.0.tar.gz
Size 49.0 kB
Tags Source
SHA-256 checksum
How to use checksums
0379d4b18f4aaa306831b12a72f5f66f2839d65d1ab8b21f5daad17d3dc82759
BLAKE2b-256 checksum
How to use checksums
7a5dee10ff07034d2445daacb08b325119af68b084f160fe3c9b548a5b1e151f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / acornwalk-2.0.0-py3-none-any.whl

Download URL acornwalk-2.0.0-py3-none-any.whl
Size 13.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
32da5ca532bf844a28da887a8b6f92888b860c21c8f4703f405c4c63d1d0bc8d
BLAKE2b-256 checksum
How to use checksums
b12b612bca05508d94d3909872a92daf43637cdce99b27f49adf172161e27357
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Security for acornwalk 2.0.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page