User Rating 0.0
Total Usage 0 times
JavaScript Source
Is this tool helpful?

Your feedback helps us improve.

About

Incorrect AST manipulation leads to silent code generation bugs: malformed output, lost scope bindings, or invalid syntax that only surfaces at runtime. This tool implements a full recursive-descent parser conforming to the ESTree specification, producing the same node types (Program, FunctionExpression, MemberExpression, etc.) used by Esprima, Acorn, and Babel. It parses raw JavaScript source into a complete AST, renders the tree as inspectable JSON, and regenerates valid source code via a recursive walker. The parser handles ES6+ constructs including arrow functions, template literals, destructuring, spread operators, classes, and computed properties. A CSS-like selector engine lets you query nodes (e.g., function > id or call[callee = "require"]) for targeted inspection. Note: this parser approximates a subset of ECMAScript 2020. Edge cases involving obscure automatic semicolon insertion rules or exotic Unicode escapes may produce divergent results compared to V8's internal parser.

ast javascript parser code-generator abstract-syntax-tree estree source-code ast-explorer

Formulas

The parser operates as a two-phase pipeline. Phase 1 is lexical analysis (tokenization). The source string S of length n is scanned character-by-character producing a token stream T.

S tokenize(S) = T = [t0, t1, …, tm]

Each token ti carries a type (keyword, identifier, literal, punctuator) and value. Phase 2 applies a Pratt parser (top-down operator precedence). Each token type has a binding power bp and optional null-denotation (nud) and left-denotation (led) functions.

parseExpr(rbp) = left nud(t) ; while bp(next) > rbp : left led(left, next)

Source regeneration walks the AST recursively. For each node type, a visitor function emits the corresponding JavaScript syntax with proper indentation depth d.

toSource(node, d) = emit(node.type, node.children, d)

Where S = source string, n = source length, T = token array, m = token count, ti = individual token, bp = binding power (integer precedence), rbp = right binding power threshold, nud = null denotation (prefix handler), led = left denotation (infix handler), d = indentation depth.

Reference Data

Short NameESTree Node TypeDescriptionExample
programProgramRoot node of any parsed sourcevar x = 1;
varVariableDeclarationVariable declaration with kindlet a = 5
declVariableDeclaratorSingle declarator within a declarationa = 5 (inside var)
functionFunctionExpressionAnonymous or named function expressionfunction(x){}
functiondeclFunctionDeclarationNamed function declaration (hoisted)function foo(){}
arrowArrowFunctionExpressionES6 arrow functionx => x+1
callCallExpressionFunction invocationfoo(1, 2)
memberMemberExpressionProperty access (dot or bracket)obj.prop
objectObjectExpressionObject literal{a: 1}
arrayArrayExpressionArray literal[1, 2, 3]
binaryBinaryExpressionBinary operator expressiona + b
logicalLogicalExpressionLogical operator expressiona && b
unaryUnaryExpressionUnary prefix operator!x
updateUpdateExpressionIncrement or decrementi++
assignAssignmentExpressionAssignment with operatorx = 10
conditionalConditionalExpressionTernary operatora ? b : c
ifIfStatementConditional branchingif(x){}
forForStatementC-style for loopfor(;;){}
forinForInStatementFor-in enumerationfor(k in o){}
whileWhileStatementWhile loopwhile(x){}
dowhileDoWhileStatementDo-while loopdo{}while(x)
returnReturnStatementReturn from functionreturn x;
throwThrowStatementThrow an exceptionthrow e;
tryTryStatementTry-catch-finallytry{}catch(e){}
switchSwitchStatementSwitch statementswitch(x){}
caseSwitchCaseCase clause in switchcase 1:
thisThisExpressionReference to thisthis
newNewExpressionConstructor invocationnew Foo()
sequenceSequenceExpressionComma-separated expressionsa, b, c
propertyPropertyKey-value pair in objectkey: val
literalLiteralPrimitive value42, "hello"
identifierIdentifierNamed referencemyVar
templateTemplateLiteralTemplate string`hello ${x}`
spreadSpreadElementSpread operator...args
classClassDeclarationES6 classclass Foo{}

Frequently Asked Questions

The parser implements a simplified ASI model. When a newline is encountered before a token that cannot continue the current statement (such as a closing brace, another statement keyword, or end of input), the parser inserts a virtual semicolon. This covers the majority of real-world code but may diverge from V8's behavior in edge cases involving return/throw followed by a newline before their argument.
The parser supports arrow functions (including concise body), template literals with expression interpolation, let/const declarations, destructuring assignment (object and array patterns), spread/rest operators, shorthand property syntax, computed property names, class declarations with constructors and methods, for-of loops, default parameter values, and getter/setter properties. Generator functions (function*) and async/await are recognized at the token level but have limited AST support.
The selector engine maps ESTree node types to short aliases (e.g., function maps to FunctionExpression and FunctionDeclaration). Descendant selectors (space-separated) traverse the full subtree. Child selectors (>) require direct parent-child relationships in the AST. Attribute selectors like [callee = "require"] match against stringified property values. Pseudo-classes :first and :last-child filter by position within parent arrays. The .property syntax selects named children (e.g., function.params selects the params array of function nodes).
The code generator (toSource) produces canonically formatted output. It normalizes whitespace, applies consistent 2-space indentation, adds semicolons explicitly, and uses a fixed brace style. Comments are not preserved in the AST (per ESTree convention) and therefore do not appear in regenerated source. Parenthesization follows operator precedence rules and may add or remove parentheses compared to the original. The semantic meaning is preserved even when surface syntax differs.
Inputs under 10 KB parse in under 50 ms on modern hardware and execute on the main thread. For inputs between 10 KB and 500 KB, parsing is offloaded to a Web Worker to prevent UI blocking. The AST tree view uses lazy rendering: only visible nodes are rendered to the DOM. Inputs exceeding 500 KB may produce ASTs with hundreds of thousands of nodes; the JSON output remains accurate but the tree visualization will only render the first 5000 nodes with a truncation notice.
No. This parser targets standard ECMAScript. TypeScript type annotations (: string, interface, type) and JSX elements () are not recognized and will produce parse errors. For TypeScript, the source must first be transpiled to plain JavaScript. JSX requires a dedicated transform pass (e.g., converting
to React.createElement calls) before this parser can process it.