diff --git a/crates/oxc/src/lib.rs b/crates/oxc/src/lib.rs
index e079632279164..922c80dc124ab 100644
--- a/crates/oxc/src/lib.rs
+++ b/crates/oxc/src/lib.rs
@@ -28,7 +28,9 @@ pub mod index {
pub use oxc_index::*;
}
+#[allow(clippy::needless_doctest_main)]
pub mod parser {
+ #![doc = include_str!("../../oxc_parser/README.md")]
#[doc(inline)]
pub use oxc_parser::*;
}
diff --git a/crates/oxc_parser/README.md b/crates/oxc_parser/README.md
new file mode 100644
index 0000000000000..cfcc6cd9041f0
--- /dev/null
+++ b/crates/oxc_parser/README.md
@@ -0,0 +1,163 @@
+Oxc Parser for JavaScript and TypeScript
+
+Oxc's [`Parser`] has full support for
+
+- The latest stable ECMAScript syntax
+- TypeScript
+- JSX and TSX
+- [Stage 3 Decorators](https://github.com/tc39/proposal-decorator-metadata)
+
+# Usage
+
+The parser has a minimal API with three inputs (a [memory arena](oxc_allocator::Allocator), a
+source string, and a [`SourceType`]) and one return struct (a [ParserReturn]).
+
+```rust
+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][`oxc_ast::ast`].
+
+# Performance
+
+The following optimization techniques are used:
+
+- AST is allocated in a memory arena ([bumpalo](https://docs.rs/bumpalo)) 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](https://docs.rs/oxc_semantic)
+
+
+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
+
+
+
+```rust
+#![allow(clippy::print_stdout)]
+use std::{fs, path::Path};
+
+use oxc_allocator::Allocator;
+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 `cargo watch -x "run -p oxc_parser --example parser"`
+
+fn main() -> Result<(), String> {
+ let mut args = Arguments::from_env();
+
+ let name = args.subcommand().ok().flatten().unwrap_or_else(|| String::from("test.js"));
+ let show_ast = args.contains("--ast");
+ let show_comments = args.contains("--comments");
+
+ 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();
+
+ let allocator = Allocator::default();
+ let ret = Parser::new(&allocator, &source_text, source_type)
+ .with_options(ParseOptions { parse_regular_expression: true, ..ParseOptions::default() })
+ .parse();
+
+ if show_ast {
+ println!("AST:");
+ println!("{}", serde_json::to_string_pretty(&ret.program).unwrap());
+ }
+
+ if show_comments {
+ println!("Comments:");
+ for comment in ret.trivias.comments() {
+ let s = comment.real_span().source_text(&source_text);
+ println!("{s}");
+ }
+ }
+
+ if ret.errors.is_empty() {
+ println!("Parsed Successfully.");
+ } else {
+ for error in ret.errors {
+ let error = error.with_source_code(source_text.clone());
+ println!("{error:?}");
+ println!("Parsed with Errors.");
+ }
+ }
+
+ Ok(())
+}
+```
+
+### Parsing TSX
+
+```rust
+use oxc_allocator::Allocator;
+use oxc_parser::{Parser, ParserReturn};
+use oxc_span::SourceType;
+
+fn main() {
+ let source_text = r#"
+import React from 'react';
+
+/**
+ * A simple counter component
+ */
+export const Counter: React.FC = () => {
+ const [count, setCount] = React.useState(0);
+
+ return (
+
+
Count: {count}
+
+
+
+ )
+}"#;
+
+ // 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
+ errors, // Syntax errors
+ panicked, // Parser encountered an error it couldn't recover from
+ trivias, // Comments, whitespace, etc.
+ } = Parser::new(&allocator, source_text, source_type).parse();
+
+ assert!(!panicked);
+ assert!(errors.is_empty());
+ assert!(!program.body.is_empty());
+ assert_eq!(trivias.comments().count(), 1);
+}
+```
+
+# Visitor
+
+See [oxc_ast::Visit] and [oxc_ast::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.
+
+```rust
+for node in semantic.nodes().iter() {
+ match node.kind() {
+ // check node
+ }
+}
+```
+
+See [full linter example](https://github.com/Boshen/oxc/blob/ab2ef4f89ba3ca50c68abb2ca43e36b7793f3673/crates/oxc_linter/examples/linter.rs#L38-L39)
+
+[`SourceType`]: oxc_span::SourceType
diff --git a/crates/oxc_parser/src/lib.rs b/crates/oxc_parser/src/lib.rs
index 63fd7f575ad0c..4d89b8126cea3 100644
--- a/crates/oxc_parser/src/lib.rs
+++ b/crates/oxc_parser/src/lib.rs
@@ -1,69 +1,5 @@
-//! Oxc Parser for JavaScript and TypeScript
-//!
-//! Oxc's [`Parser`] has full support for
-//! - The latest stable ECMAScript syntax
-//! - TypeScript
-//! - JSX and TSX
-//! - [Stage 3 Decorators](https://github.com/tc39/proposal-decorator-metadata)
-//!
-//! # Usage
-//!
-//! The parser has a minimal API with three inputs (a [memory arena](oxc_allocator::Allocator), a
-//! source string, and a [`SourceType`]) and one return struct (a [ParserReturn]).
-//!
-//! ```rust
-//! 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][`oxc_ast::ast`].
-//!
-//! # Performance
-//!
-//! The following optimization techniques are used:
-//! * AST is allocated in a memory arena ([bumpalo](https://docs.rs/bumpalo)) 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](https://docs.rs/oxc_semantic)
-//!
-//!
-//! 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
-//!
-//!
-//!
-//! ```rust
-#![doc = include_str!("../examples/parser.rs")]
-//! ```
-//!
-//! ### Parsing TSX
-//! ```rust
-#![doc = include_str!("../examples/parser_tsx.rs")]
-//! ```
-//!
-//! # Visitor
-//!
-//! See [oxc_ast::Visit] and [oxc_ast::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.
-//!
-//! ```rust
-//! for node in semantic.nodes().iter() {
-//! match node.kind() {
-//! // check node
-//! }
-//! }
-//! ```
-//!
-//! See [full linter example](https://github.com/Boshen/oxc/blob/ab2ef4f89ba3ca50c68abb2ca43e36b7793f3673/crates/oxc_linter/examples/linter.rs#L38-L39)
-
+#![allow(clippy::needless_doctest_main)]
+#![doc = include_str!("../README.md")]
#![allow(clippy::wildcard_imports)] // allow for use `oxc_ast::ast::*`
mod context;