Skip to main content

Crate oxc_parser

Crate oxc_parser 

Source
Expand description

Oxc Parser for JavaScript and TypeScript

Oxc’s Parser has full support for

§Usage

The parser has a minimal API with three inputs (a memory arena, a source string, and a SourceType) and one return struct (a ParserReturn).

ⓘ
let parser_return = Parser::new(&allocator, &source_text, source_type).parse();

§Abstract Syntax Tree (AST)

Oxc’s AST is located in a separate oxc_ast crate. You can find type definitions for AST nodes here.

§Performance

The following optimization techniques are used:

  • AST is allocated in a memory arena (oxc_allocator) for fast AST drop
  • oxc_span::Span offsets uses u32 instead of usize
  • Scope binding, symbol resolution and complicated syntax errors are not done in the parser, they are delegated to the semantic analyzer
Because [`oxc_span::Span`] uses `u32` instead of `usize`, Oxc can only parse files up to 4 GiB in size. This shouldn't be a limitation in almost all cases.

§Examples

https://github.com/oxc-project/oxc/blob/main/crates/oxc_parser/examples/parser.rs

ⓘ
#![expect(clippy::print_stdout)]
//! # Parser Example
//!
//! This example demonstrates how to use the Oxc parser to parse JavaScript and TypeScript files.
//!
//! ## Usage
//!
//! Create a `test.js` file and run:
//! ```bash
//! cargo run -p oxc_parser --example parser [filename] [--ast] [--estree] [--comments]
//! ```
//!
//! ## Options
//!
//! - `--ast`: Display the parsed AST structure
//! - `--estree`: Display the ESTree representation
//! - `--comments`: Display extracted comments

use std::{fs, path::Path};

use oxc_allocator::Allocator;
use oxc_ast_visit::utf8_to_utf16::Utf8ToUtf16;
use oxc_parser::{ParseOptions, Parser};
use oxc_span::SourceType;
use pico_args::Arguments;

// Instruction:
// create a `test.js`,
// run `cargo run -p oxc_parser --example parser`
// or `just watch "cargo run -p oxc_parser --example parser"`

/// Parse and display information about a JavaScript or TypeScript file
fn main() -> Result<(), String> {
    let mut args = Arguments::from_env();

    // Parse command line arguments
    let show_ast = args.contains("--ast");
    let show_estree = args.contains("--estree");
    let show_comments = args.contains("--comments");
    let name = args.free_from_str().unwrap_or_else(|_| "test.js".to_string());

    // Read source file
    let path = Path::new(&name);
    let source_text = fs::read_to_string(path).map_err(|_| format!("Missing '{name}'"))?;
    let source_type = SourceType::from_path(path).unwrap();

    // Parse the source code
    let allocator = Allocator::default();
    let ret = Parser::new(&allocator, &source_text, source_type)
        .with_options(ParseOptions { parse_regular_expression: true, ..ParseOptions::default() })
        .parse();
    let mut program = ret.program;

    // Display comments if requested
    if show_comments {
        println!("Comments:");
        for comment in &program.comments {
            let s = comment.content_span().source_text(&source_text);
            println!("{s}");
        }
    }

    // Display AST if requested
    if show_ast {
        println!("AST:");
        println!("{program:#?}");
    }

    // Display ESTree representation if requested
    if show_estree {
        Utf8ToUtf16::new(&source_text).convert_program(&mut program);
        if source_type.is_javascript() {
            println!("ESTree AST:");
        } else {
            println!("TS-ESTree AST:");
        }
        println!("{}", program.to_pretty_estree_json(!source_type.is_javascript(), false));
    }

    // Report parsing results
    if ret.diagnostics.is_empty() {
        println!("Parsed Successfully.");
    } else {
        for error in ret.diagnostics {
            let error = error.with_source_code(source_text.clone());
            println!("{error:?}");
        }
        println!("Parsed with Errors.");
    }

    Ok(())
}

§Parsing TSX

ⓘ
//! # TypeScript JSX Parsing Example
//!
//! This example demonstrates parsing TypeScript files with JSX syntax.
//! It shows how to parse a simple React component and validate the parsing results.
//!
//! ## Usage
//!
//! ```bash
//! cargo run -p oxc_parser --example parser_tsx
//! ```

use oxc_allocator::Allocator;
use oxc_parser::{Parser, ParserReturn};
use oxc_span::SourceType;

/// Parse a TypeScript JSX file and validate the results
fn main() -> Result<(), String> {
    let source_text = r"
import React from 'react';

/**
 * A simple counter component
 */
export const Counter: React.FC = () => {
    const [count, setCount] = React.useState(0);

    return (
        <div>
            <p>Count: {count}</p>
            <button onClick={() => setCount(count + 1)}>Increment</button>
            <button onClick={() => setCount(count - 1)}>Decrement</button>
        </div>
    )
}";

    // Memory arena where AST nodes get stored
    let allocator = Allocator::default();
    // Infers TypeScript + JSX + ESM modules
    let source_type = SourceType::from_path("Counter.tsx").unwrap();

    let ParserReturn {
        program,     // AST
        diagnostics, // Syntax errors
        panicked,    // Parser encountered an error it couldn't recover from
        ..
    } = Parser::new(&allocator, source_text, source_type).parse();

    if panicked {
        return Err("Parser panicked".to_string());
    }

    if !diagnostics.is_empty() {
        return Err(format!("Parsing errors: {}", diagnostics.len()));
    }

    assert!(!program.body.is_empty());
    assert_eq!(program.comments.len(), 1);

    Ok(())
}

§Visitor

See Visit and VisitMut.

§Visiting without a visitor

For ad-hoc tasks, the semantic analyzer can be used to get a parent pointing tree with untyped nodes, the nodes can be iterated through a sequential loop.

ⓘ
for node in semantic.nodes().iter() {
    match node.kind() {
        // check node
    }
}

See full linter example

Modules§

config

Structs§

AdmittedBorrowedExpression
A root authenticated by its original embedding owner, without moving it. The root remains borrowed for the owner’s lifetime, not the arena lifetime. No caller AST, source window or replacement admission status can mint this.
AdmittedExpression
A short private-origin borrow; raw ASTs and numeric windows cannot mint it.
AdmittedHandlerBody
A short private-origin borrow; raw ASTs and numeric windows cannot mint it.
AdmittedParameters
A short private-origin borrow; raw ASTs and numeric windows cannot mint it.
AdmittedProgram
A short immutable borrow minted only by a clean original observation.
EmbeddingInput
A private fixed wrapper and its original allocation/source identity. No caller AST, wrapper, options or lexer configuration can be substituted.
EmbeddingObservation
The complete ordinary result, including all diagnostics and parser fields. Shared selected syntax cannot mint a replacement admitted projection.
ExpressionObservation
An ordinarily owned complete parser observation and selected arena root.
HandlerBodyObservation
An ordinarily owned complete parser observation and selected arena root.
OriginalDefaultExport
The sole direct value-default export in the original parser’s ModuleRecord.
ParametersObservation
An ordinarily owned complete parser observation and selected arena root.
ParseOptions
Parse options
Parser
Recursive Descent Parser for ECMAScript and TypeScript
ParserReturn
Return value of Parser::parse consisting of AST, errors and comments
ProgramObservation
The complete ordinarily owned result of one parser invocation.
Token

Enums§

EmbeddingGoal
EmbeddingHole
EmbeddingInputError
Kind
Lexer token kind