use oxc_ast_macros::ast_meta;
use oxc_estree::{
CompactFixesSerializer, CompactSerializer, Concat2, ESTree, JsonSafeString,
PrettyFixesSerializer, PrettySerializer, Serializer, StructSerializer,
};
use crate::ast::*;
pub mod basic;
pub mod js;
pub mod jsx;
pub mod literal;
pub mod ts;
use basic::{EmptyArray, Null};
const JSON_CAPACITY_RATIO_COMPACT: usize = 16;
const JSON_CAPACITY_RATIO_PRETTY: usize = 80;
impl Program<'_> {
pub fn to_estree_json(&self, include_ts_fields: bool, ranges: bool) -> String {
let capacity = self.source_text.len() * JSON_CAPACITY_RATIO_COMPACT;
let mut serializer = CompactSerializer::with_capacity(capacity, include_ts_fields, ranges);
self.serialize(&mut serializer);
serializer.into_string()
}
pub fn to_pretty_estree_json(&self, include_ts_fields: bool, ranges: bool) -> String {
let capacity = self.source_text.len() * JSON_CAPACITY_RATIO_PRETTY;
let mut serializer = PrettySerializer::with_capacity(capacity, include_ts_fields, ranges);
self.serialize(&mut serializer);
serializer.into_string()
}
pub fn to_estree_json_with_fixes(&self, include_ts_fields: bool, ranges: bool) -> String {
let capacity = self.source_text.len() * JSON_CAPACITY_RATIO_COMPACT;
let serializer = CompactFixesSerializer::with_capacity(capacity, include_ts_fields, ranges);
serializer.serialize_with_fixes(self)
}
pub fn to_pretty_estree_json_with_fixes(
&self,
include_ts_fields: bool,
ranges: bool,
) -> String {
let capacity = self.source_text.len() * JSON_CAPACITY_RATIO_PRETTY;
let serializer = PrettyFixesSerializer::with_capacity(capacity, include_ts_fields, ranges);
serializer.serialize_with_fixes(self)
}
}
#[ast_meta]
#[estree(raw_deser = "
const start = DESER[i32](POS_OFFSET.span.start),
end = DESER[i32](POS_OFFSET.span.end);
const program = parent = {
type: 'Program',
body: null,
sourceType: DESER[ModuleKind](POS_OFFSET.source_type.module_kind),
/* IF !LINTER */
hashbang: null,
/* END_IF */
/* IF LINTER */
get comments() {
if (comments === null) initComments();
return comments;
},
get tokens() {
if (tokens === null) initTokens();
return tokens;
},
/* END_IF */
start,
end,
...(RANGE && { range: [start, end] }),
...(PARENT && { parent: null }),
};
if (!LINTER) program.hashbang = DESER[Option<Hashbang>](POS_OFFSET.hashbang);
const body = program.body = DESER[Vec<Directive>](POS_OFFSET.directives);
body.push(...DESER[Vec<Statement>](POS_OFFSET.body));
if (PARENT) parent = null;
program
")]
pub struct ProgramConverter<'a, 'b>(pub &'b Program<'a>);
impl ESTree for ProgramConverter<'_, '_> {
fn serialize<S: Serializer>(&self, serializer: S) {
let program = self.0;
let mut state = serializer.serialize_struct();
state.serialize_field("type", &JsonSafeString("Program"));
state.serialize_field("body", &Concat2(&program.directives, &program.body));
state.serialize_field("sourceType", &program.source_type.module_kind());
state.serialize_field("hashbang", &program.hashbang);
state.serialize_span(program.span);
state.end();
}
}
#[ast_meta]
#[estree(
ts_type = "string",
raw_deser = "
// HTML comment discriminants equal their delimiter lengths (3 or 4).
const kind = DESER[u8](POS_OFFSET.kind);
SOURCE_TEXT.slice(THIS.start + (kind < 3 ? 2 : kind), THIS.end - (THIS.type === 'Line' ? 0 : 2))
",
raw_deser_inline
)]
pub struct CommentValue<'b>(#[expect(dead_code)] pub &'b Comment);
impl ESTree for CommentValue<'_> {
#[expect(clippy::unimplemented)]
fn serialize<S: Serializer>(&self, _serializer: S) {
unimplemented!();
}
}