mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 12:19:15 +00:00
feat(transfrom): transform-json-strings (#2168)
The pr intends to implement the plugin `babel-plugin-transform-json-strings`. But here is only mutate `Directive`, the `StringLiteral` is not implement. It need to changed the `StringLiteral` printer. I'm intend to add the raw of `StringLiteral`, it will be mutate at plugin, and using the `raw` to print `StringLiteral`. If you other ideas, please let me know. --------- Co-authored-by: Boshen <boshenc@gmail.com>
This commit is contained in:
parent
8ca1812ad1
commit
2794064eef
7 changed files with 91 additions and 13 deletions
|
|
@ -46,9 +46,9 @@ language-tags = { workspace = true }
|
|||
mime_guess = { workspace = true }
|
||||
url = { workspace = true }
|
||||
|
||||
rust-lapper = "1.1.0"
|
||||
once_cell = "1.19.0"
|
||||
memchr = "2.7.1"
|
||||
rust-lapper = "1.1.0"
|
||||
once_cell = "1.19.0"
|
||||
memchr = "2.7.1"
|
||||
json-strip-comments = "1.0.1"
|
||||
|
||||
[dev-dependencies]
|
||||
|
|
|
|||
56
crates/oxc_transformer/src/es2019/json_strings.rs
Normal file
56
crates/oxc_transformer/src/es2019/json_strings.rs
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
use oxc_ast::ast::*;
|
||||
use oxc_span::Atom;
|
||||
use oxc_syntax::identifier::{LS, PS};
|
||||
|
||||
use crate::options::{TransformOptions, TransformTarget};
|
||||
|
||||
/// ES2019: Json Strings
|
||||
///
|
||||
/// References:
|
||||
/// * <https://babeljs.io/docs/babel-plugin-transform-json-strings>
|
||||
/// * <https://github.com/babel/babel/tree/main/packages/babel-plugin-transform-json-strings>
|
||||
pub struct JsonStrings;
|
||||
|
||||
impl JsonStrings {
|
||||
pub fn new(options: &TransformOptions) -> Option<Self> {
|
||||
(options.target < TransformTarget::ES2019 || options.json_strings).then(|| Self {})
|
||||
}
|
||||
|
||||
// Allow `U+2028` and `U+2029` in string literals
|
||||
// <https://tc39.es/proposal-json-superset>
|
||||
// <https://github.com/tc39/proposal-json-superset>
|
||||
fn normalize_str(str: &str) -> Option<Atom> {
|
||||
if !str.contains(LS) && !str.contains(PS) {
|
||||
return None;
|
||||
}
|
||||
let mut buf = String::new();
|
||||
let mut is_escaped = false;
|
||||
for c in str.chars() {
|
||||
match (is_escaped, c) {
|
||||
(false, LS) => buf.push_str("\\u2028"),
|
||||
(false, PS) => buf.push_str("\\u2029"),
|
||||
_ => buf.push(c),
|
||||
}
|
||||
is_escaped = !is_escaped && matches!(c, '\\');
|
||||
}
|
||||
Some(buf.into())
|
||||
}
|
||||
|
||||
#[allow(clippy::unused_self)]
|
||||
// TODO oxc_codegen currently prints json strings correctly,
|
||||
// but we need a way to turn off this behaviour from codegen
|
||||
// and do the transformation here.
|
||||
pub fn transform_string_literal(&mut self, _literal: &mut StringLiteral) {
|
||||
// let str = &self.ctx.semantic().source_text()[literal.span.start as usize + 1..literal.span.end as usize - 1];
|
||||
// if let Some(value) = Self::normalize_str(str) {
|
||||
// literal.value = value;
|
||||
// }
|
||||
}
|
||||
|
||||
#[allow(clippy::unused_self)]
|
||||
pub fn transform_directive(&mut self, directive: &mut Directive) {
|
||||
if let Some(value) = Self::normalize_str(directive.directive.as_str()) {
|
||||
directive.directive = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
mod json_strings;
|
||||
mod optional_catch_binding;
|
||||
|
||||
pub use json_strings::JsonStrings;
|
||||
pub use optional_catch_binding::OptionalCatchBinding;
|
||||
|
|
|
|||
|
|
@ -35,10 +35,18 @@ use oxc_span::SourceType;
|
|||
use proposals::Decorators;
|
||||
|
||||
use crate::{
|
||||
context::TransformerCtx, es2015::*, es2016::ExponentiationOperator,
|
||||
es2019::OptionalCatchBinding, es2020::NullishCoalescingOperator,
|
||||
es2021::LogicalAssignmentOperators, es2022::ClassStaticBlock, es3::PropertyLiteral,
|
||||
react_jsx::ReactJsx, regexp::RegexpFlags, typescript::TypeScript, utils::CreateVars,
|
||||
context::TransformerCtx,
|
||||
es2015::*,
|
||||
es2016::ExponentiationOperator,
|
||||
es2019::{JsonStrings, OptionalCatchBinding},
|
||||
es2020::NullishCoalescingOperator,
|
||||
es2021::LogicalAssignmentOperators,
|
||||
es2022::ClassStaticBlock,
|
||||
es3::PropertyLiteral,
|
||||
react_jsx::ReactJsx,
|
||||
regexp::RegexpFlags,
|
||||
typescript::TypeScript,
|
||||
utils::CreateVars,
|
||||
};
|
||||
|
||||
pub use crate::{
|
||||
|
|
@ -64,6 +72,7 @@ pub struct Transformer<'a> {
|
|||
// es2020
|
||||
es2020_nullish_coalescing_operators: Option<NullishCoalescingOperator<'a>>,
|
||||
// es2019
|
||||
es2019_json_strings: Option<JsonStrings>,
|
||||
es2019_optional_catch_binding: Option<OptionalCatchBinding<'a>>,
|
||||
// es2016
|
||||
es2016_exponentiation_operator: Option<ExponentiationOperator<'a>>,
|
||||
|
|
@ -105,6 +114,7 @@ impl<'a> Transformer<'a> {
|
|||
// es2020
|
||||
es2020_nullish_coalescing_operators: NullishCoalescingOperator::new(Rc::clone(&ast), ctx.clone(), &options),
|
||||
// es2019
|
||||
es2019_json_strings: JsonStrings::new(&options),
|
||||
es2019_optional_catch_binding: OptionalCatchBinding::new(Rc::clone(&ast), &options),
|
||||
// es2016
|
||||
es2016_exponentiation_operator: ExponentiationOperator::new(Rc::clone(&ast), ctx.clone(), &options),
|
||||
|
|
@ -291,4 +301,16 @@ impl<'a> VisitMut<'a> for Transformer<'a> {
|
|||
|
||||
self.leave_node(kind);
|
||||
}
|
||||
|
||||
fn visit_directive(&mut self, directive: &mut Directive) {
|
||||
self.es2019_json_strings
|
||||
.as_mut()
|
||||
.map(|t: &mut JsonStrings| t.transform_directive(directive));
|
||||
}
|
||||
|
||||
fn visit_string_literal(&mut self, lit: &mut StringLiteral) {
|
||||
self.es2019_json_strings
|
||||
.as_mut()
|
||||
.map(|t: &mut JsonStrings| t.transform_string_literal(lit));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ pub struct TransformOptions {
|
|||
pub nullish_coalescing_operator: Option<NullishCoalescingOperatorOptions>,
|
||||
// es2019
|
||||
pub optional_catch_binding: bool,
|
||||
pub json_strings: bool,
|
||||
// es2016
|
||||
pub exponentiation_operator: bool,
|
||||
// es2015
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
Passed: 327/1369
|
||||
Passed: 329/1369
|
||||
|
||||
# All Passed:
|
||||
* babel-plugin-transform-numeric-separator
|
||||
* babel-plugin-transform-optional-catch-binding
|
||||
* babel-plugin-transform-json-strings
|
||||
* babel-plugin-transform-shorthand-properties
|
||||
* babel-plugin-transform-sticky-regex
|
||||
* babel-plugin-transform-instanceof
|
||||
|
|
@ -607,10 +608,6 @@ Passed: 327/1369
|
|||
* transparent-expr-wrappers/ts-as-member-expression/input.ts
|
||||
* transparent-expr-wrappers/ts-parenthesized-expression-member-call/input.ts
|
||||
|
||||
# babel-plugin-transform-json-strings (2/4)
|
||||
* json-strings/directive-line-separator/input.js
|
||||
* json-strings/directive-paragraph-separator/input.js
|
||||
|
||||
# babel-plugin-transform-async-generator-functions (0/22)
|
||||
* async-generators/class-method/input.js
|
||||
* async-generators/class-private-method/input.js
|
||||
|
|
|
|||
|
|
@ -111,6 +111,7 @@ pub trait TestCase {
|
|||
nullish_coalescing_operator: options
|
||||
.get_plugin("transform-nullish-coalescing-operator")
|
||||
.map(get_options::<NullishCoalescingOperatorOptions>),
|
||||
json_strings: options.get_plugin("transform-json-strings").is_some(),
|
||||
optional_catch_binding: options
|
||||
.get_plugin("transform-optional-catch-binding")
|
||||
.is_some(),
|
||||
|
|
|
|||
Loading…
Reference in a new issue