#typescript-parser #javascript

swc_experimental_ecma_parser

An extensible Rust-based platform for the next generation of fast developer tools

12 releases (4 breaking)

Uses new Rust 2024

0.5.0 Feb 2, 2026
0.4.1 Jan 16, 2026
0.4.0 Dec 30, 2025
0.3.5 Dec 22, 2025
0.1.1 Dec 4, 2025

#421 in Web programming

Download history 28/week @ 2025-11-28 163/week @ 2025-12-05 1063/week @ 2025-12-12 1014/week @ 2025-12-19 622/week @ 2025-12-26 1124/week @ 2026-01-02 738/week @ 2026-01-09 1060/week @ 2026-01-16 541/week @ 2026-01-23 918/week @ 2026-01-30 823/week @ 2026-02-06

3,421 downloads per month
Used in 57 crates (via rspack_core)

Apache-2.0

2MB
50K SLoC

EcmaScript/TypeScript parser for the rust programming language.

Features

Heavily tested

Passes almost all tests from tc39/test262.

Error reporting

error: 'implements', 'interface', 'let', 'package', 'private', 'protected',  'public', 'static', or 'yield' cannot be used as an identifier in strict mode
 --> invalid.js:3:10
  |
3 | function yield() {
  |          ^^^^^

Error recovery

The parser can recover from some parsing errors. For example, parser returns Ok(Module) for the code below, while emitting error to handler.

const CONST = 9000 % 2;
const enum D {
    // Comma is required, but parser can recover because of the newline.
    d = 10
    g = CONST
}

Example (lexer)

See lexer.rs in examples directory.

Example (parser)

#[macro_use]
extern crate swc_common;
extern crate swc_ecma_parser;
use swc_core::common::sync::Lrc;
use swc_core::common::{
    errors::{ColorConfig, Handler},
    FileName, FilePathMapping, SourceMap,
};
use swc_ecma_parser::{lexer::Lexer, Parser, StringInput, Syntax};

fn main() {
    let cm: Lrc<SourceMap> = Default::default();
    let handler =
        Handler::with_tty_emitter(ColorConfig::Auto, true, false,
        Some(cm.clone()));

    // Real usage
    // let fm = cm
    //     .load_file(Path::new("test.js"))
    //     .expect("failed to load test.js");
    let fm = cm.new_source_file(
        FileName::Custom("test.js".into()).into(),
        "function foo() {}",
    );
    let lexer = Lexer::new(
        // We want to parse ecmascript
        Syntax::Es(Default::default()),
        // EsVersion defaults to es5
        Default::default(),
        StringInput::from(&*fm),
        None,
    );

    let mut parser = Parser::new_from(lexer);

    for e in parser.take_errors() {
        e.into_diagnostic(&handler).emit();
    }

    let _module = parser
        .parse_module()
        .map_err(|mut e| {
            // Unrecoverable fatal error occurred
            e.into_diagnostic(&handler).emit()
        })
        .expect("failed to parser module");
}

Cargo features

typescript

Enables typescript parser.

verify

Verify more errors, using swc_ecma_visit.

Known issues

Null character after \

Because [String] of rust should only contain valid utf-8 characters while javascript allows non-utf8 characters, the parser stores invalid utf8 characters in escaped form.

As a result, swc needs a way to distinguish invalid-utf8 code points and input specified by the user. The parser stores a null character right after \\ for non-utf8 code points. Note that other parts of swc is aware of this fact.

Note that this can be changed at anytime with a breaking change.

This module expose tokens related to the swc_ecma_parser::lexer.

Unlike the tokens re-exported from swc_ecma_lexer, the token kinds defined in the swc_ecma_parser here are non-strict for higher performance.

Although it's marked as unstable, we can ensure that we will not introduce too many breaking changes. And we also encourage the applications to migrate to the lexer and tokens in terms of the performance.

Also see the dicussion https://github.com/swc-project/swc/discussions/10683

Dependencies

~25MB
~411K SLoC