mirror of
https://github.com/danbulant/oxc
synced 2026-05-25 04:42:10 +00:00
Part of #2295
This PR splits the `Atom` type into `Atom<'a>` and `CompactString`.
All the AST node strings now use `Atom<'a>` instead of `Atom` to signify
it belongs to the arena.
It is now up to the user to select which form of the string to use.
This PR essentially removes the really unsafe code
93742f89e9/crates/oxc_span/src/atom.rs (L98-L107)
which can lead to

138 lines
5.7 KiB
Rust
138 lines
5.7 KiB
Rust
#![allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
|
|
|
|
use std::{fs, path::Path, str::FromStr};
|
|
|
|
use oxc_allocator::Allocator;
|
|
use oxc_ast::{
|
|
ast::{Argument, ArrayExpressionElement, CallExpression, Expression, ObjectPropertyKind},
|
|
VisitMut,
|
|
};
|
|
use oxc_parser::Parser;
|
|
use oxc_prettier::{ArrowParens, EndOfLine, PrettierOptions, QuoteProps, TrailingComma};
|
|
use oxc_span::{GetSpan, SourceType};
|
|
|
|
#[derive(Default)]
|
|
pub struct SpecParser {
|
|
pub calls: Vec<(PrettierOptions, Vec<(String, String)>)>,
|
|
source_text: String,
|
|
}
|
|
|
|
impl SpecParser {
|
|
pub fn parse(&mut self, spec: &Path) {
|
|
let spec_content = fs::read_to_string(spec).unwrap_or_default();
|
|
let allocator = Allocator::default();
|
|
let source_type = SourceType::from_path(spec).unwrap_or_default();
|
|
let mut ret = Parser::new(&allocator, &spec_content, source_type).parse();
|
|
self.source_text = spec_content.clone();
|
|
self.calls = vec![];
|
|
self.visit_program(&mut ret.program);
|
|
}
|
|
}
|
|
|
|
impl VisitMut<'_> for SpecParser {
|
|
fn visit_call_expression(&mut self, expr: &mut CallExpression<'_>) {
|
|
let Some(ident) = expr.callee.get_identifier_reference() else { return };
|
|
// The `runFormatTest` function used on prettier's test cases. We need to collect all `run_spec` calls
|
|
// And then parse the arguments to get the options and parsers
|
|
// Finally we use this information to generate the snapshot tests
|
|
if ident.name != "runFormatTest" {
|
|
return;
|
|
}
|
|
let mut parsers = vec![];
|
|
let mut snapshot_options: Vec<(String, String)> = vec![];
|
|
let mut options = PrettierOptions::default();
|
|
|
|
if let Some(argument) = expr.arguments.get(1) {
|
|
let Argument::Expression(argument_expr) = argument else {
|
|
return;
|
|
};
|
|
|
|
if let Expression::ArrayExpression(arr_expr) = argument_expr {
|
|
parsers = arr_expr
|
|
.elements
|
|
.iter()
|
|
.filter_map(|el| {
|
|
if let ArrayExpressionElement::Expression(Expression::StringLiteral(
|
|
literal,
|
|
)) = el
|
|
{
|
|
return Some(literal.value.to_string());
|
|
}
|
|
None
|
|
})
|
|
.collect::<Vec<String>>();
|
|
}
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
if let Some(Argument::Expression(Expression::ObjectExpression(obj_expr))) =
|
|
expr.arguments.get(2)
|
|
{
|
|
obj_expr.properties.iter().for_each(|item| {
|
|
if let ObjectPropertyKind::ObjectProperty(obj_prop) = item {
|
|
if let Some(name) = obj_prop.key.static_name() {
|
|
match &obj_prop.value {
|
|
Expression::BooleanLiteral(literal) => {
|
|
if name == "semi" {
|
|
options.semi = literal.value;
|
|
} else if name == "bracketSpacing" {
|
|
options.bracket_spacing = literal.value;
|
|
} else if name == "singleQuote" {
|
|
options.single_quote = literal.value;
|
|
}
|
|
}
|
|
Expression::NumericLiteral(literal) => match name.as_str() {
|
|
"printWidth" => options.print_width = literal.value as usize,
|
|
"tabWidth" => options.tab_width = literal.value as usize,
|
|
_ => {}
|
|
},
|
|
Expression::StringLiteral(literal) => match name.as_str() {
|
|
"trailingComma" => {
|
|
options.trailing_comma =
|
|
TrailingComma::from_str(literal.value.as_str()).unwrap();
|
|
}
|
|
"endOfLine" => {
|
|
options.end_of_line =
|
|
EndOfLine::from_str(literal.value.as_str()).unwrap();
|
|
}
|
|
"quoteProps" => {
|
|
options.quote_props =
|
|
QuoteProps::from_str(literal.value.as_str()).unwrap();
|
|
}
|
|
"arrowParens" => {
|
|
options.arrow_parens =
|
|
ArrowParens::from_str(literal.value.as_str()).unwrap();
|
|
}
|
|
_ => {}
|
|
},
|
|
_ => {}
|
|
};
|
|
if name != "errors" {
|
|
snapshot_options.push((
|
|
name.to_string(),
|
|
obj_prop.value.span().source_text(&self.source_text).to_string(),
|
|
));
|
|
}
|
|
};
|
|
}
|
|
});
|
|
}
|
|
|
|
snapshot_options.push((
|
|
"parsers".to_string(),
|
|
format!(
|
|
"[{}]",
|
|
parsers.iter().map(|p| format!("\"{p}\"")).collect::<Vec<_>>().join(", ")
|
|
),
|
|
));
|
|
|
|
if !snapshot_options.iter().any(|item| item.0 == "printWidth") {
|
|
snapshot_options.push(("printWidth".to_string(), "80".into()));
|
|
}
|
|
|
|
snapshot_options.sort_by(|a, b| a.0.cmp(&b.0));
|
|
|
|
self.calls.push((options, snapshot_options));
|
|
}
|
|
}
|