Skip to content

Commit

Permalink
feature: robust JSX whitespace handling
Browse files Browse the repository at this point in the history
  • Loading branch information
timofei-iatsenko committed Mar 19, 2024
1 parent f2aab8d commit 63ef9db
Show file tree
Hide file tree
Showing 10 changed files with 416 additions and 536 deletions.
723 changes: 333 additions & 390 deletions Cargo.lock

Large diffs are not rendered by default.

3 changes: 1 addition & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ serde = "1"
serde_json = "1.0.95"
regex = "1.7.3"
once_cell = "1.17.1"
swc_common = "=0.33.15"
swc_core = { version = "0.87.28", features = [
swc_core = { version = "0.90.3", features = [
"ecma_plugin_transform",
"ecma_utils",
"ecma_visit",
Expand Down
1 change: 1 addition & 0 deletions src/ast_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ pub fn create_key_value_prop(key: &str, value: Box<Expr>) -> PropOrSpread {
pub fn create_import(source: JsWord, specifier: Ident) -> ModuleItem {
ModuleItem::ModuleDecl(ModuleDecl::Import(ImportDecl {
span: DUMMY_SP,
phase: ImportPhase::default(),
specifiers: vec![
ImportSpecifier::Named(ImportNamedSpecifier {
span: DUMMY_SP,
Expand Down
3 changes: 1 addition & 2 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ use swc_core::{

use crate::{
normalize_witespaces_js::normalize_whitespaces_js,
normalize_witespaces_jsx::normalize_whitespaces_jsx,
};
use crate::tokens::{IcuChoice, CaseOrOffset, MsgToken};

Expand Down Expand Up @@ -70,7 +69,7 @@ impl MessageBuilder {

pub fn to_args(mut self, jsx: bool) -> MessageBuilderResult {
let message_str = if jsx {
normalize_whitespaces_jsx(&self.message)
self.message
} else {
normalize_whitespaces_js(&self.message)
};
Expand Down
48 changes: 47 additions & 1 deletion src/jsx_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,51 @@ static WORD_OPTION: Lazy<Regex> = Lazy::new(|| Regex::new(r"_(\w+)").unwrap());
// const pluralRuleRe = /(_[\d\w]+|zero|one|two|few|many|other)/
// const jsx2icuExactChoice = (value: string) => value.replace(/_(\d+)/, "=$1").replace(/_(\w+)/, "$1")

// taken from babel repo -> packages/babel-types/src/utils/react/cleanJSXElementLiteralChild.ts
fn clean_jsx_element_literal_child(value: &str) -> String {
println!("bla {}", value);

let lines: Vec<&str> = value.split('\n').collect();
let mut last_non_empty_line = 0;

for (i, line) in lines.iter().enumerate() {
if line.trim().len() > 0 {
last_non_empty_line = i;
}
}

let mut result = String::new();

for (i, line) in lines.iter().enumerate() {
let is_first_line = i == 0;
let is_last_line = i == lines.len() - 1;
let is_last_non_empty_line = i == last_non_empty_line;

// replace rendered whitespace tabs with spaces
let mut trimmed_line = line.replace("\t", " ");

// trim whitespace touching a newline
if !is_first_line {
trimmed_line = trimmed_line.trim_start().to_string();
}

// trim whitespace touching an endline
if !is_last_line {
trimmed_line = trimmed_line.trim_end().to_string();
}

if !trimmed_line.is_empty() {
if !is_last_non_empty_line {
trimmed_line.push(' ');
}

result.push_str(&trimmed_line);
}
}

result
}

fn is_allowed_plural_option(key: &str) -> Option<JsWord> {
if PLURAL_OPTIONS_WHITELIST.is_match(key) {
let key = NUM_OPTION.replace(key, "=$1");
Expand Down Expand Up @@ -174,8 +219,9 @@ impl<'a> Visit for TransJSXVisitor<'a> {
}

fn visit_jsx_text(&mut self, el: &JSXText) {

self.tokens.push(
MsgToken::String(el.value.to_string())
MsgToken::String(clean_jsx_element_literal_child(&el.raw.to_string()))
);
}

Expand Down
1 change: 0 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ use swc_core::{
};

mod tests;
mod normalize_witespaces_jsx;
mod normalize_witespaces_js;
mod builder;
mod tokens;
Expand Down
117 changes: 0 additions & 117 deletions src/normalize_witespaces_jsx.rs

This file was deleted.

1 change: 0 additions & 1 deletion src/tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,3 @@ macro_rules! to {
);
}
}

51 changes: 31 additions & 20 deletions src/tests/jsx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ to!(

r#"
import { Trans } from "@lingui/react";
<Trans message={"<0>This should work \xa0</0>"} id={"K/1Xpr"}
<Trans message={"<0>This should work  </0>"} id={"K/1Xpr"}
components={{
0: <Text />,
}}
Expand Down Expand Up @@ -276,36 +276,20 @@ to!(
"#
);

to!(
keep_forced_newlines,
r#"
import { Trans } from "@lingui/macro";
<Trans>
Keep forced{"\\n"}
newlines!
</Trans>
"#,

r#"
import { Trans } from "@lingui/react";
<Trans message={"Keep forced\n newlines!"} id={"3zXXNh"}/>;
"#
);

to!(
keep_multiple_forced_newlines,
r#"
import { Trans } from "@lingui/macro";
<Trans>
Keep multiple{"\\n"}
forced{"\\n"}
Keep multiple{"\n"}
forced{"\n"}
newlines!
</Trans>
"#,

r#"
import { Trans } from "@lingui/react";
<Trans message={"Keep multiple\n forced\n newlines!"} id={"fP0nx0"}/>;
<Trans message={"Keep multiple\nforced\nnewlines!"} id={"9xE5pD"}/>;
"#
);

Expand Down Expand Up @@ -389,7 +373,34 @@ to!(
/>;
"#
);
to!(
strip_whitespaces_in_jsxtext_but_keep_in_jsx_expression_containers,
r#"
import { Trans } from "@lingui/macro";
<Trans>
{"Wonderful framework "}
<a href="https://nextjs.org">Next.js</a>
{" say hi. And "}
<a href="https://nextjs.org">Next.js</a>
{" say hi."}
</Trans>
"#,

r#"
import { Trans } from "@lingui/react";
<Trans
message={
"Wonderful framework <0>Next.js</0> say hi. And <1>Next.js</1> say hi."
}
id={"3YVd0H"}
components={{
0: <a href="https://nextjs.org" />,
1: <a href="https://nextjs.org" />,
}}
/>;
"#
);
// {
// name: "production - import_type_doesn't_interference_on_normal_import",
// production: true,
Expand Down
4 changes: 2 additions & 2 deletions src/tests/jsx_icu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -347,13 +347,13 @@ to!(
offset="1"
_0=" #st"
one=" #nd"
other='#rd'
other=' #rd'
/>;
"#,

r#"
import { Trans } from "@lingui/react";
<Trans message={"{count, selectordinal, offset:1 =0 {#st} one {#nd} other {#rd}}"} id={"6kK4rC"} values={{
<Trans message={"{count, selectordinal, offset:1 =0 { #st} one { #nd} other { #rd}}"} id={"cp8FR4"} values={{
count: count
}}/>;
"#
Expand Down

0 comments on commit 63ef9db

Please sign in to comment.