mirror of
https://github.com/danbulant/oxc
synced 2026-05-25 04:42:10 +00:00
feat(transformer/jsx-source): get the correct lineNumber and columnNumber from the span. (#3142)
This commit is contained in:
parent
bdae6b0e4e
commit
a52e321b25
7 changed files with 54 additions and 8 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -1683,6 +1683,7 @@ dependencies = [
|
|||
"oxc_parser",
|
||||
"oxc_span",
|
||||
"oxc_syntax",
|
||||
"ropey",
|
||||
"rustc-hash",
|
||||
"serde",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
use std::hash::{Hash, Hasher};
|
||||
|
||||
use miette::{SourceOffset, SourceSpan};
|
||||
|
||||
#[cfg(feature = "serialize")]
|
||||
use serde::Serialize;
|
||||
#[cfg(feature = "serialize")]
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ oxc_syntax = { workspace = true, features = ["to_js_string"] }
|
|||
rustc-hash = { workspace = true }
|
||||
indexmap = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
ropey = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
oxc_parser = { workspace = true }
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use std::rc::Rc;
|
|||
|
||||
use oxc_allocator::Vec;
|
||||
use oxc_ast::{ast::*, AstBuilder};
|
||||
use oxc_span::{CompactStr, GetSpan, SPAN};
|
||||
use oxc_span::{CompactStr, GetSpan, Span, SPAN};
|
||||
use oxc_syntax::{
|
||||
identifier::{is_irregular_whitespace, is_line_terminator},
|
||||
xml_entities::XML_ENTITIES,
|
||||
|
|
@ -12,6 +12,7 @@ use oxc_syntax::{
|
|||
|
||||
use crate::{context::Ctx, helpers::module_imports::NamedImport};
|
||||
|
||||
use super::utils::get_line_column;
|
||||
pub use super::{
|
||||
jsx_self::ReactJsxSelf,
|
||||
jsx_source::ReactJsxSource,
|
||||
|
|
@ -217,6 +218,13 @@ enum JSXElementOrFragment<'a, 'b> {
|
|||
}
|
||||
|
||||
impl<'a, 'b> JSXElementOrFragment<'a, 'b> {
|
||||
fn span(&self) -> Span {
|
||||
match self {
|
||||
Self::Element(e) => e.span(),
|
||||
Self::Fragment(e) => e.span,
|
||||
}
|
||||
}
|
||||
|
||||
fn attributes(&self) -> Option<&'b Vec<'a, JSXAttributeItem<'a>>> {
|
||||
match self {
|
||||
Self::Element(e) if !e.opening_element.attributes.is_empty() => {
|
||||
|
|
@ -367,7 +375,9 @@ impl<'a> ReactJsx<'a> {
|
|||
if let Some(span) = source_attr_span {
|
||||
self.jsx_source.report_error(span);
|
||||
} else {
|
||||
properties.push(self.jsx_source.get_object_property_kind_for_jsx_plugin());
|
||||
let (line, column) = get_line_column(e.span().start, self.ctx.source_text);
|
||||
properties
|
||||
.push(self.jsx_source.get_object_property_kind_for_jsx_plugin(line, column));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ use crate::context::Ctx;
|
|||
|
||||
use self::diagnostics::DuplicateSourceProp;
|
||||
|
||||
use super::utils::get_line_column;
|
||||
|
||||
const SOURCE: &str = "__source";
|
||||
const FILE_NAME_VAR: &str = "_jsxFileName";
|
||||
|
||||
|
|
@ -47,12 +49,16 @@ impl<'a> ReactJsxSource<'a> {
|
|||
self.add_source_attribute(elem);
|
||||
}
|
||||
|
||||
pub fn get_object_property_kind_for_jsx_plugin(&mut self) -> ObjectPropertyKind<'a> {
|
||||
pub fn get_object_property_kind_for_jsx_plugin(
|
||||
&mut self,
|
||||
line: usize,
|
||||
column: usize,
|
||||
) -> ObjectPropertyKind<'a> {
|
||||
self.should_add_jsx_file_name_variable = true;
|
||||
let kind = PropertyKind::Init;
|
||||
let ident = IdentifierName::new(SPAN, SOURCE.into());
|
||||
let key = self.ctx.ast.property_key_identifier(ident);
|
||||
let value = self.get_source_object();
|
||||
let value = self.get_source_object(line, column);
|
||||
let obj = self.ctx.ast.object_property(SPAN, kind, key, value, None, false, false, false);
|
||||
ObjectPropertyKind::ObjectProperty(obj)
|
||||
}
|
||||
|
|
@ -83,14 +89,16 @@ impl<'a> ReactJsxSource<'a> {
|
|||
let key = JSXAttributeName::Identifier(
|
||||
self.ctx.ast.alloc(self.ctx.ast.jsx_identifier(SPAN, SOURCE.into())),
|
||||
);
|
||||
let object = self.get_source_object();
|
||||
let (line, column) = get_line_column(elem.span.start, self.ctx.source_text);
|
||||
let object = self.get_source_object(line, column);
|
||||
let expr = self.ctx.ast.jsx_expression_container(SPAN, JSXExpression::from(object));
|
||||
let value = JSXAttributeValue::ExpressionContainer(expr);
|
||||
let attribute_item = self.ctx.ast.jsx_attribute(SPAN, key, Some(value));
|
||||
elem.attributes.push(JSXAttributeItem::Attribute(attribute_item));
|
||||
}
|
||||
|
||||
fn get_source_object(&self) -> Expression<'a> {
|
||||
#[allow(clippy::cast_precision_loss)]
|
||||
fn get_source_object(&self, line: usize, column: usize) -> Expression<'a> {
|
||||
let kind = PropertyKind::Init;
|
||||
|
||||
let filename = {
|
||||
|
|
@ -104,7 +112,12 @@ impl<'a> ReactJsxSource<'a> {
|
|||
let line_number = {
|
||||
let ident = IdentifierName::new(SPAN, "lineNumber".into());
|
||||
let key = self.ctx.ast.property_key_identifier(ident);
|
||||
let number = self.ctx.ast.number_literal(SPAN, 1.0, "1", NumberBase::Decimal);
|
||||
let number = self.ctx.ast.number_literal(
|
||||
SPAN,
|
||||
line as f64,
|
||||
self.ctx.ast.new_str(&line.to_string()),
|
||||
NumberBase::Decimal,
|
||||
);
|
||||
let value = self.ctx.ast.literal_number_expression(number);
|
||||
self.ctx.ast.object_property(SPAN, kind, key, value, None, false, false, false)
|
||||
};
|
||||
|
|
@ -112,7 +125,12 @@ impl<'a> ReactJsxSource<'a> {
|
|||
let column_number = {
|
||||
let ident = IdentifierName::new(SPAN, "columnNumber".into());
|
||||
let key = self.ctx.ast.property_key_identifier(ident);
|
||||
let number = self.ctx.ast.number_literal(SPAN, 1.0, "1", NumberBase::Decimal);
|
||||
let number = self.ctx.ast.number_literal(
|
||||
SPAN,
|
||||
column as f64,
|
||||
self.ctx.ast.new_str(&column.to_string()),
|
||||
NumberBase::Decimal,
|
||||
);
|
||||
let value = self.ctx.ast.literal_number_expression(number);
|
||||
self.ctx.ast.object_property(SPAN, kind, key, value, None, false, false, false)
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ mod jsx;
|
|||
mod jsx_self;
|
||||
mod jsx_source;
|
||||
mod options;
|
||||
mod utils;
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
|
|
|
|||
14
crates/oxc_transformer/src/react/utils.rs
Normal file
14
crates/oxc_transformer/src/react/utils.rs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
use ropey::Rope;
|
||||
|
||||
/// Get line and column from offset and source text
|
||||
pub fn get_line_column(offset: u32, source_text: &str) -> (usize, usize) {
|
||||
let offset = offset as usize;
|
||||
let rope = Rope::from_str(source_text);
|
||||
let line = rope.byte_to_line(offset);
|
||||
let first_char_of_line = rope.line_to_char(line);
|
||||
// Original offset is byte, but Rope uses char offset
|
||||
let offset = rope.byte_to_char(offset);
|
||||
let column = offset - first_char_of_line;
|
||||
// line and column is zero-indexed, but we want 1-indexed
|
||||
(line + 1, column + 1)
|
||||
}
|
||||
Loading…
Reference in a new issue