From ad574136e8a0e81d9aa2d6ba28d32ea023a8baae Mon Sep 17 00:00:00 2001
From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com>
Date: Thu, 2 Oct 2025 21:30:40 -0400
Subject: [PATCH 01/12] Add failing tests
---
src/lib.rs | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/src/lib.rs b/src/lib.rs
index 52b24ae..7bd419e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -324,3 +324,26 @@ testcase! {
return template_UUID(``, { eval() { return eval(arguments[0]) } });
}"#
}
+
+testcase! {
+ extraneous_indentation_strip,
+ r#"let x =
+ hello
+ "#,
+ r#"import { template as template_UUID } from "@ember/template-compiler";
+ let x = template_UUID(`hello`, { eval() { return eval(arguments[0])} });"#
+}
+
+testcase! {
+ multiline_extraneous_indentation_strip,
+ r#"let x =
+ hello
+
+ extra line break
+
+ content
+
+ "#,
+ r#"import { template as template_UUID } from "@ember/template-compiler";
+ let x = template_UUID(`hello\n\nextra line break\n
\n content\n
`, { eval() { return eval(arguments[0])} });"#
+}
From 20234b48a527ae5fdd513c12324c2ea9f26a399c Mon Sep 17 00:00:00 2001
From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com>
Date: Mon, 24 Nov 2025 01:16:14 -0500
Subject: [PATCH 02/12] Implement RFC#1121
---
src/lib.rs | 7 +-
src/transform.rs | 214 +++++++++++++++++++++++++++++++++++++-
test/node/process.test.js | 184 ++++++++++++++++++++++++++++++++
3 files changed, 403 insertions(+), 2 deletions(-)
diff --git a/src/lib.rs b/src/lib.rs
index 7bd419e..f0f9377 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -345,5 +345,10 @@ testcase! {
"#,
r#"import { template as template_UUID } from "@ember/template-compiler";
- let x = template_UUID(`hello\n\nextra line break\n\n content\n
`, { eval() { return eval(arguments[0])} });"#
+ let x = template_UUID(`hello
+
+extra line break
+
+ content
+
`, { eval() { return eval(arguments[0])} });"#
}
diff --git a/src/transform.rs b/src/transform.rs
index d171af8..e2ebe03 100644
--- a/src/transform.rs
+++ b/src/transform.rs
@@ -54,13 +54,14 @@ impl<'a> TransformVisitor<'a> {
}
fn content_literal(&self, contents: &Box) -> ExprOrSpread {
+ let stripped_content = strip_indent(&contents.value);
Box::new(Expr::Tpl(Tpl {
span: contents.span,
exprs: vec![],
quasis: vec![TplElement {
span: contents.span,
cooked: None,
- raw: escape_template_literal(&contents.value),
+ raw: escape_template_literal(&stripped_content.into()),
tail: false,
}],
}))
@@ -76,6 +77,78 @@ fn escape_template_literal(input: &Atom) -> Atom {
.into()
}
+// https://rfcs.emberjs.com/id/1121-extraneous-invisible-character-stripping/
+fn strip_indent(input: &str) -> String {
+ let lines: Vec<&str> = input.lines().collect();
+
+ if lines.is_empty() {
+ return String::new();
+ }
+
+ let first_non_empty = lines.iter().position(|line| !line.trim().is_empty());
+ let last_non_empty = lines.iter().rposition(|line| !line.trim().is_empty());
+
+ let (first_idx, last_idx) = match (first_non_empty, last_non_empty) {
+ (Some(first), Some(last)) => (first, last),
+ _ => return String::new(), // All lines are empty
+ };
+
+ // Get the trimmed lines (removing leading/trailing empty lines)
+ let trimmed_lines = &lines[first_idx..=last_idx];
+
+ let mut min_indent: Option = None;
+ let mut uses_spaces = false;
+ let mut uses_tabs = false;
+
+ for line in trimmed_lines {
+ if line.trim().is_empty() {
+ continue;
+ }
+
+ let leading_whitespace: String = line.chars()
+ .take_while(|c| *c == ' ' || *c == '\t')
+ .collect();
+
+ let indent_count = leading_whitespace.len();
+
+ if leading_whitespace.contains(' ') {
+ uses_spaces = true;
+ }
+ if leading_whitespace.contains('\t') {
+ uses_tabs = true;
+ }
+
+ min_indent = Some(match min_indent {
+ None => indent_count,
+ Some(current) => current.min(indent_count),
+ });
+ }
+
+ if uses_spaces && uses_tabs {
+ return trimmed_lines.join("\n");
+ }
+
+ let min_indent = min_indent.unwrap_or(0);
+
+ if min_indent == 0 {
+ return trimmed_lines.join("\n");
+ }
+
+ let stripped_lines: Vec = trimmed_lines
+ .iter()
+ .map(|line| {
+ if line.trim().is_empty() {
+ String::new()
+ } else {
+ let chars: Vec = line.chars().collect();
+ chars.iter().skip(min_indent).collect()
+ }
+ })
+ .collect();
+
+ stripped_lines.join("\n")
+}
+
impl<'a> VisitMut for TransformVisitor<'a> {
fn visit_mut_expr(&mut self, n: &mut Expr) {
n.visit_mut_children_with(self);
@@ -301,3 +374,142 @@ test!(
r#"let x = Hello\nWorld\u1234"#,
r#"let x = template(`Hello\\nWorld\\u1234`, { eval() { return eval(arguments[0]) }})"#
);
+
+test!(
+ Default::default(),
+ |_| as_folder(TransformVisitor::new(
+ &Ident::new("template".into(), Default::default()),
+ None,
+ )),
+ strips_leading_trailing_whitespace,
+ r#"let x =
+ Hello
+"#,
+ r#"let x = template(`Hello`, { eval() { return eval(arguments[0]) }})"#
+);
+
+test!(
+ Default::default(),
+ |_| as_folder(TransformVisitor::new(
+ &Ident::new("template".into(), Default::default()),
+ None,
+ )),
+ strips_common_indentation,
+ r#"let x =
+
+ Hello
+
+ "#,
+ r#"let x = template(`
+ Hello
+
`, { eval() { return eval(arguments[0]) }})"#
+);
+
+test!(
+ Default::default(),
+ |_| as_folder(TransformVisitor::new(
+ &Ident::new("template".into(), Default::default()),
+ None,
+ )),
+ strips_indentation_multiline,
+ r#"
+ Hello
+ there.
+
+ how are you
+
+"#,
+ r#"export default template(`Hello
+there.
+
+ how are you
+
`, { eval() { return eval(arguments[0]) }},);"#
+);
+
+test!(
+ Default::default(),
+ |_| as_folder(TransformVisitor::new(
+ &Ident::new("template".into(), Default::default()),
+ None,
+ )),
+ class_member_strips_indentation,
+ r#"class X {
+
+ Hello
+
+}"#,
+ r#"class X {
+ static {
+ template(`Hello`, { component: this, eval() { return eval(arguments[0]) }},);
+ }
+}"#
+);
+
+test!(
+ Default::default(),
+ |_| as_folder(TransformVisitor::new(
+ &Ident::new("template".into(), Default::default()),
+ None,
+ )),
+ deeply_nested_indentation,
+ r#"class Component {
+ method() {
+ return
+
+ Nested
+
+ ;
+ }
+}"#,
+ r#"class Component {
+ method() {
+ return template(`
+ Nested
+
`, { eval() { return eval(arguments[0]) }});
+ }
+}"#
+);
+
+test!(
+ Default::default(),
+ |_| as_folder(TransformVisitor::new(
+ &Ident::new("template".into(), Default::default()),
+ None,
+ )),
+ preserves_internal_indentation,
+ r#"let x =
+
+
+ some code
+ with indentation
+
+
+"#,
+ r#"let x = template(`
+
+ some code
+ with indentation
+
+
`, { eval() { return eval(arguments[0]) }})"#
+);
+
+test!(
+ Default::default(),
+ |_| as_folder(TransformVisitor::new(
+ &Ident::new("template".into(), Default::default()),
+ None,
+ )),
+ opt_out_with_comment,
+ r#"let x =
+{{!-- prevent automatic de-indent --}}
+
+ content here
+
+ "#,
+ r#"let x = template(`
+{{!-- prevent automatic de-indent --}}
+
+ content here
+
+ `, { eval() { return eval(arguments[0]) }})"#
+);
diff --git a/test/node/process.test.js b/test/node/process.test.js
index 6e8a005..2dd1b85 100644
--- a/test/node/process.test.js
+++ b/test/node/process.test.js
@@ -108,4 +108,188 @@ describe(`process`, function () {
let output = p.process(`class X { declare a: string; }`);
expect(output.code).to.match(/declare a: string/);
});
+
+ describe("indentation stripping (RFC #1121)", function () {
+ it("strips leading and trailing whitespace from simple template", function () {
+ let output = p.process(`
+ Hello
+`);
+
+ expect(normalizeOutput(output.code)).to.equalCode(
+ `import { template as template_UUID } from "@ember/template-compiler";
+ export default template_UUID(\`Hello\`, {
+ eval () {
+ return eval(arguments[0]);
+ }
+ });`,
+ );
+ });
+
+ it("strips common indentation from nested templates", function () {
+ let input = `
+ class Foo extends Component {
+
+
+ {{this.greeting}}
+
+
+ }
+ `;
+
+ let output = p.process(input);
+
+ expect(normalizeOutput(output.code)).to.equalCode(
+ `import { template as template_UUID } from "@ember/template-compiler";
+ class Foo extends Component {
+ static{
+ template_UUID(\`
+ {{this.greeting}}
+
\`, {
+ component: this,
+ eval () {
+ return eval(arguments[0]);
+ }
+ });
+ }
+ };`,
+ );
+ });
+
+ it("strips indentation from multiline content", function () {
+ let input = `
+ Hello
+ there.
+
+ how are you
+
+`;
+
+ let output = p.process(input);
+
+ expect(normalizeOutput(output.code)).to.equalCode(
+ `import { template as template_UUID } from "@ember/template-compiler";
+ export default template_UUID(\`Hello
+there.
+
+ how are you
+
\`, {
+ eval () {
+ return eval(arguments[0]);
+ }
+ });`,
+ );
+ });
+
+ it("preserves relative indentation within template", function () {
+ let input = `
+ let x =
+
+
+ some code
+ with indentation
+
+
+
+ `;
+
+ let output = p.process(input);
+
+ expect(normalizeOutput(output.code)).to.equalCode(
+ `import { template as template_UUID } from "@ember/template-compiler";
+ let x = template_UUID(\`
+
+ some code
+ with indentation
+
+
\`, {
+ eval () {
+ return eval(arguments[0]);
+ }
+ });`,
+ );
+ });
+
+ it("allows opt-out with comment", function () {
+ let input = `let x =
+{{!-- prevent automatic de-indent --}}
+
+ content here
+
+ `;
+
+ let output = p.process(input);
+
+ // When opted out, original whitespace is preserved
+ expect(normalizeOutput(output.code)).to.equalCode(
+ `import { template as template_UUID } from "@ember/template-compiler";
+ let x = template_UUID(\`
+{{!-- prevent automatic de-indent --}}
+
+ content here
+
+ \`, {
+ eval () {
+ return eval(arguments[0]);
+ }
+ });`,
+ );
+ });
+
+ it("handles deeply nested indentation", function () {
+ let input = `
+ class Component {
+ method() {
+ return
+
+ Nested
+
+ ;
+ }
+ }
+ `;
+
+ let output = p.process(input);
+
+ expect(normalizeOutput(output.code)).to.equalCode(
+ `import { template as template_UUID } from "@ember/template-compiler";
+ class Component {
+ method() {
+ return template_UUID(\`
+ Nested
+
\`, {
+ eval () {
+ return eval(arguments[0]);
+ }
+ });
+ }
+ }`,
+ );
+ });
+
+ it("works with template expressions", function () {
+ let input = `const MyTemplate =
+ x
+
+
+
+
+`;
+
+ let output = p.process(input);
+
+ expect(normalizeOutput(output.code)).to.equalCode(
+ `import { template as template_UUID } from "@ember/template-compiler";
+ const MyTemplate = template_UUID(\`x\`, {
+ eval () {
+ return eval(arguments[0]);
+ }
+ });
+ export default template_UUID(\`\`, {
+ eval () {
+ return eval(arguments[0]);
+ }
+ });`,
+ );
+ });
+ });
});
From cfd9770edba892d178ee01b841a751d1c0e92c47 Mon Sep 17 00:00:00 2001
From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com>
Date: Mon, 24 Nov 2025 01:23:32 -0500
Subject: [PATCH 03/12] Update src/transform.rs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---
src/transform.rs | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/transform.rs b/src/transform.rs
index e2ebe03..38d26eb 100644
--- a/src/transform.rs
+++ b/src/transform.rs
@@ -140,8 +140,7 @@ fn strip_indent(input: &str) -> String {
if line.trim().is_empty() {
String::new()
} else {
- let chars: Vec = line.chars().collect();
- chars.iter().skip(min_indent).collect()
+ line.chars().skip(min_indent).collect()
}
})
.collect();
From 3cdc1158914744efb53819059bd0e01a9f4b29d1 Mon Sep 17 00:00:00 2001
From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com>
Date: Mon, 24 Nov 2025 01:23:50 -0500
Subject: [PATCH 04/12] Update src/transform.rs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---
src/transform.rs | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/src/transform.rs b/src/transform.rs
index 38d26eb..a384e25 100644
--- a/src/transform.rs
+++ b/src/transform.rs
@@ -105,17 +105,17 @@ fn strip_indent(input: &str) -> String {
continue;
}
- let leading_whitespace: String = line.chars()
- .take_while(|c| *c == ' ' || *c == '\t')
- .collect();
-
- let indent_count = leading_whitespace.len();
-
- if leading_whitespace.contains(' ') {
- uses_spaces = true;
- }
- if leading_whitespace.contains('\t') {
- uses_tabs = true;
+ let mut indent_count = 0;
+ for c in line.chars() {
+ if c == ' ' {
+ uses_spaces = true;
+ indent_count += 1;
+ } else if c == '\t' {
+ uses_tabs = true;
+ indent_count += 1;
+ } else {
+ break;
+ }
}
min_indent = Some(match min_indent {
From 1644b961ae03473cfd6db4766b0377f339584130 Mon Sep 17 00:00:00 2001
From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com>
Date: Mon, 24 Nov 2025 01:28:45 -0500
Subject: [PATCH 05/12] Fix test that forgot that indentation stripping is
separate from leading/trailing newline stripping
---
src/transform.rs | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/src/transform.rs b/src/transform.rs
index a384e25..9861e95 100644
--- a/src/transform.rs
+++ b/src/transform.rs
@@ -505,10 +505,8 @@ test!(
content here
"#,
- r#"let x = template(`
-{{!-- prevent automatic de-indent --}}
+ r#"let x = template(`{{!-- prevent automatic de-indent --}}
content here
-
- `, { eval() { return eval(arguments[0]) }})"#
+ `, { eval() { return eval(arguments[0]) }})"#
);
From 43b7dc76cab4875ed84d02aacd35fae98d84fb4f Mon Sep 17 00:00:00 2001
From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com>
Date: Mon, 24 Nov 2025 01:33:57 -0500
Subject: [PATCH 06/12] Don't lose significant empty lines
---
src/transform.rs | 2 +-
test/node/process.test.js | 6 ++----
2 files changed, 3 insertions(+), 5 deletions(-)
diff --git a/src/transform.rs b/src/transform.rs
index 9861e95..cb0e1d2 100644
--- a/src/transform.rs
+++ b/src/transform.rs
@@ -138,7 +138,7 @@ fn strip_indent(input: &str) -> String {
.iter()
.map(|line| {
if line.trim().is_empty() {
- String::new()
+ line.to_string()
} else {
line.chars().skip(min_indent).collect()
}
diff --git a/test/node/process.test.js b/test/node/process.test.js
index 2dd1b85..8b46900 100644
--- a/test/node/process.test.js
+++ b/test/node/process.test.js
@@ -222,12 +222,10 @@ describe(`process`, function () {
// When opted out, original whitespace is preserved
expect(normalizeOutput(output.code)).to.equalCode(
`import { template as template_UUID } from "@ember/template-compiler";
- let x = template_UUID(\`
-{{!-- prevent automatic de-indent --}}
+ let x = template_UUID(\`{{!-- prevent automatic de-indent --}}
content here
-
- \`, {
+ \`, {
eval () {
return eval(arguments[0]);
}
From e79ff804b6f2cc021378b052f2ccc373400c7b28 Mon Sep 17 00:00:00 2001
From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com>
Date: Mon, 24 Nov 2025 01:39:31 -0500
Subject: [PATCH 07/12] Update src/transform.rs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---
src/transform.rs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/transform.rs b/src/transform.rs
index cb0e1d2..5866eb0 100644
--- a/src/transform.rs
+++ b/src/transform.rs
@@ -77,7 +77,7 @@ fn escape_template_literal(input: &Atom) -> Atom {
.into()
}
-// https://rfcs.emberjs.com/id/1121-extraneous-invisible-character-stripping/
+// RFC: https://github.com/emberjs/rfcs/pull/1121
fn strip_indent(input: &str) -> String {
let lines: Vec<&str> = input.lines().collect();
From ed6d660f0552b9b1ba89dfe84be83a0507f6c2ea Mon Sep 17 00:00:00 2001
From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com>
Date: Mon, 24 Nov 2025 01:42:41 -0500
Subject: [PATCH 08/12] cleanup
---
src/transform.rs | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/transform.rs b/src/transform.rs
index 5866eb0..2f23dfc 100644
--- a/src/transform.rs
+++ b/src/transform.rs
@@ -90,10 +90,9 @@ fn strip_indent(input: &str) -> String {
let (first_idx, last_idx) = match (first_non_empty, last_non_empty) {
(Some(first), Some(last)) => (first, last),
- _ => return String::new(), // All lines are empty
+ _ => return String::new(),
};
- // Get the trimmed lines (removing leading/trailing empty lines)
let trimmed_lines = &lines[first_idx..=last_idx];
let mut min_indent: Option = None;
From 6d852c976021e535b27ca5d7256a8c84454bcea5 Mon Sep 17 00:00:00 2001
From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com>
Date: Mon, 24 Nov 2025 02:14:13 -0500
Subject: [PATCH 09/12] =?UTF-8?q?Cleanup=20--=20account=20for=20case=20not?=
=?UTF-8?q?=20covered=20by=20the=20RFC=20=F0=9F=99=88=20(sorta,=20it's=20a?=
=?UTF-8?q?=20little=20ambiguous,=20oops)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/transform.rs | 72 +++++++++++++++++----------------------
test/node/process.test.js | 13 +++++++
2 files changed, 44 insertions(+), 41 deletions(-)
diff --git a/src/transform.rs b/src/transform.rs
index 2f23dfc..98f9ee2 100644
--- a/src/transform.rs
+++ b/src/transform.rs
@@ -77,74 +77,64 @@ fn escape_template_literal(input: &Atom) -> Atom {
.into()
}
-// RFC: https://github.com/emberjs/rfcs/pull/1121
fn strip_indent(input: &str) -> String {
- let lines: Vec<&str> = input.lines().collect();
+ let mut lines: Vec<&str> = input.lines().collect();
if lines.is_empty() {
return String::new();
}
- let first_non_empty = lines.iter().position(|line| !line.trim().is_empty());
- let last_non_empty = lines.iter().rposition(|line| !line.trim().is_empty());
+ if lines.len() == 1 {
+ return lines[0].to_string();
+ }
- let (first_idx, last_idx) = match (first_non_empty, last_non_empty) {
- (Some(first), Some(last)) => (first, last),
- _ => return String::new(),
- };
+ while lines.first().is_some_and(|l| l.trim().is_empty()) {
+ lines.remove(0);
+ }
+ while lines.last().is_some_and(|l| l.trim().is_empty()) {
+ lines.pop();
+ }
- let trimmed_lines = &lines[first_idx..=last_idx];
+ if lines.is_empty() {
+ return String::new();
+ }
let mut min_indent: Option = None;
- let mut uses_spaces = false;
- let mut uses_tabs = false;
+ let mut has_spaces = false;
+ let mut has_tabs = false;
- for line in trimmed_lines {
- if line.trim().is_empty() {
+ for line in &lines {
+ let content = line.trim_start();
+ if content.is_empty() {
continue;
}
- let mut indent_count = 0;
- for c in line.chars() {
- if c == ' ' {
- uses_spaces = true;
- indent_count += 1;
- } else if c == '\t' {
- uses_tabs = true;
- indent_count += 1;
- } else {
- break;
- }
- }
+ let indent_size = line.len() - content.len();
+ let indent_chars = &line[..indent_size];
- min_indent = Some(match min_indent {
- None => indent_count,
- Some(current) => current.min(indent_count),
- });
- }
+ has_spaces |= indent_chars.contains(' ');
+ has_tabs |= indent_chars.contains('\t');
- if uses_spaces && uses_tabs {
- return trimmed_lines.join("\n");
+ min_indent = Some(min_indent.map_or(indent_size, |current| current.min(indent_size)));
}
let min_indent = min_indent.unwrap_or(0);
- if min_indent == 0 {
- return trimmed_lines.join("\n");
+ if (has_spaces && has_tabs) || min_indent == 0 {
+ return lines.join("\n");
}
- let stripped_lines: Vec = trimmed_lines
+ lines
.iter()
.map(|line| {
- if line.trim().is_empty() {
- line.to_string()
+ if line.len() >= min_indent {
+ &line[min_indent..]
} else {
- line.chars().skip(min_indent).collect()
+ line
}
})
- .collect();
-
- stripped_lines.join("\n")
+ .collect::>()
+ .join("\n")
}
impl<'a> VisitMut for TransformVisitor<'a> {
diff --git a/test/node/process.test.js b/test/node/process.test.js
index 8b46900..6e875fa 100644
--- a/test/node/process.test.js
+++ b/test/node/process.test.js
@@ -289,5 +289,18 @@ describe(`process`, function () {
});`,
);
});
+
+ it("prerves whitespace when component is one line", function () {
+ let output = p.process(` Hello `);
+
+ expect(normalizeOutput(output.code)).to.equalCode(
+ `import { template as template_UUID } from "@ember/template-compiler";
+ export default template_UUID(\` Hello \`, {
+ eval () {
+ return eval(arguments[0]);
+ }
+ });`,
+ );
+ });
});
});
From f7cd15d361510df2935a3d64ddc1a44952783844 Mon Sep 17 00:00:00 2001
From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com>
Date: Mon, 24 Nov 2025 02:18:33 -0500
Subject: [PATCH 10/12] Cleanup
---
src/transform.rs | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/src/transform.rs b/src/transform.rs
index 98f9ee2..4d12b43 100644
--- a/src/transform.rs
+++ b/src/transform.rs
@@ -80,12 +80,8 @@ fn escape_template_literal(input: &Atom) -> Atom {
fn strip_indent(input: &str) -> String {
let mut lines: Vec<&str> = input.lines().collect();
- if lines.is_empty() {
- return String::new();
- }
-
- if lines.len() == 1 {
- return lines[0].to_string();
+ if lines.len() <= 1 {
+ return input.to_string();
}
while lines.first().is_some_and(|l| l.trim().is_empty()) {
From 0c08fa9f0e6e79e63f114c65f0c48df1d4f9f2d2 Mon Sep 17 00:00:00 2001
From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com>
Date: Mon, 24 Nov 2025 02:22:55 -0500
Subject: [PATCH 11/12] How about this
---
src/transform.rs | 16 +++++++---------
1 file changed, 7 insertions(+), 9 deletions(-)
diff --git a/src/transform.rs b/src/transform.rs
index 4d12b43..d7debd8 100644
--- a/src/transform.rs
+++ b/src/transform.rs
@@ -78,28 +78,26 @@ fn escape_template_literal(input: &Atom) -> Atom {
}
fn strip_indent(input: &str) -> String {
- let mut lines: Vec<&str> = input.lines().collect();
+ let lines: Vec<&str> = input.lines().collect();
if lines.len() <= 1 {
return input.to_string();
}
- while lines.first().is_some_and(|l| l.trim().is_empty()) {
- lines.remove(0);
- }
- while lines.last().is_some_and(|l| l.trim().is_empty()) {
- lines.pop();
- }
+ let start = lines.iter().position(|l| !l.trim().is_empty()).unwrap_or(lines.len());
+ let end = lines.iter().rposition(|l| !l.trim().is_empty()).map(|i| i + 1).unwrap_or(0);
- if lines.is_empty() {
+ if start >= end {
return String::new();
}
+ let lines = &lines[start..end];
+
let mut min_indent: Option = None;
let mut has_spaces = false;
let mut has_tabs = false;
- for line in &lines {
+ for line in lines {
let content = line.trim_start();
if content.is_empty() {
continue;
From a087571862bb07c762f9c88bc4afcbd753a91959 Mon Sep 17 00:00:00 2001
From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com>
Date: Mon, 24 Nov 2025 02:27:59 -0500
Subject: [PATCH 12/12] Early return
---
src/transform.rs | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/transform.rs b/src/transform.rs
index d7debd8..e392824 100644
--- a/src/transform.rs
+++ b/src/transform.rs
@@ -109,12 +109,16 @@ fn strip_indent(input: &str) -> String {
has_spaces |= indent_chars.contains(' ');
has_tabs |= indent_chars.contains('\t');
+ if has_spaces && has_tabs {
+ return lines.join("\n");
+ }
+
min_indent = Some(min_indent.map_or(indent_size, |current| current.min(indent_size)));
}
let min_indent = min_indent.unwrap_or(0);
- if (has_spaces && has_tabs) || min_indent == 0 {
+ if min_indent == 0 {
return lines.join("\n");
}