rfmt 1.4.1 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -0
- data/Cargo.lock +7 -7
- data/ext/rfmt/Cargo.toml +3 -3
- data/ext/rfmt/src/emitter/mod.rs +122 -74
- data/ext/rfmt/src/lib.rs +3 -3
- data/lib/rfmt/prism_bridge.rb +33 -3
- data/lib/rfmt/version.rb +1 -1
- metadata +3 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2df39db6eb525d4ca6bc42d55e01057e5a12772f0b61a7a8e3101e3a8fff76ec
|
|
4
|
+
data.tar.gz: b34bbf251457c8eb0d9174497c124f71d6a7b098ad506712acaec54812bcc674
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1d341d108c8875f683a2ef3654e6e540b1fe9840a4f908abc75725da544c0b8be2b27cf5534cdf634eb2e9eaaa36bed0df9500f978a6fffc95ec7379e2485cf3
|
|
7
|
+
data.tar.gz: 9cbce53637c758998c79c77af60d10130dd293dac67c4a7918d882e816d848ef525400bd6fcebc030523a2407e08140dc1bc9227cbd9c1cfc3f579f0e5b477be
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [1.5.0] - 2026-01-25
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- Docker Compose test environment setup (#84)
|
|
7
|
+
- Support for `then` expression emission (#80)
|
|
8
|
+
- CI support for Ruby 3.4 and Ruby 4 (#82)
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
- Upgrade Magnus (Rust-Ruby FFI library) (#83)
|
|
12
|
+
- Optimize Docker build with multi-stage and caching (#84)
|
|
13
|
+
- Upgrade unicode-emoji dependency
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
- Preserve heredoc content and closing identifier (#81)
|
|
17
|
+
- Fix `rescue`/`ensure` clauses being deleted inside `do...end` blocks (#78)
|
|
18
|
+
- Fix inline comment node handling (#77)
|
|
19
|
+
- Fix BTreeMap range error (Issue #71)
|
|
20
|
+
|
|
3
21
|
## [1.4.1] - 2026-01-17
|
|
4
22
|
|
|
5
23
|
### Fixed
|
data/Cargo.lock
CHANGED
|
@@ -838,9 +838,9 @@ dependencies = [
|
|
|
838
838
|
|
|
839
839
|
[[package]]
|
|
840
840
|
name = "magnus"
|
|
841
|
-
version = "0.
|
|
841
|
+
version = "0.8.2"
|
|
842
842
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
843
|
-
checksum = "
|
|
843
|
+
checksum = "3b36a5b126bbe97eb0d02d07acfeb327036c6319fd816139a49824a83b7f9012"
|
|
844
844
|
dependencies = [
|
|
845
845
|
"magnus-macros",
|
|
846
846
|
"rb-sys",
|
|
@@ -850,9 +850,9 @@ dependencies = [
|
|
|
850
850
|
|
|
851
851
|
[[package]]
|
|
852
852
|
name = "magnus-macros"
|
|
853
|
-
version = "0.
|
|
853
|
+
version = "0.8.0"
|
|
854
854
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
855
|
-
checksum = "
|
|
855
|
+
checksum = "47607461fd8e1513cb4f2076c197d8092d921a1ea75bd08af97398f593751892"
|
|
856
856
|
dependencies = [
|
|
857
857
|
"proc-macro2",
|
|
858
858
|
"quote",
|
|
@@ -1168,9 +1168,9 @@ dependencies = [
|
|
|
1168
1168
|
|
|
1169
1169
|
[[package]]
|
|
1170
1170
|
name = "rb-sys-env"
|
|
1171
|
-
version = "0.
|
|
1171
|
+
version = "0.2.3"
|
|
1172
1172
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1173
|
-
checksum = "
|
|
1173
|
+
checksum = "cca7ad6a7e21e72151d56fe2495a259b5670e204c3adac41ee7ef676ea08117a"
|
|
1174
1174
|
|
|
1175
1175
|
[[package]]
|
|
1176
1176
|
name = "redox_users"
|
|
@@ -1214,7 +1214,7 @@ checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
|
|
|
1214
1214
|
|
|
1215
1215
|
[[package]]
|
|
1216
1216
|
name = "rfmt"
|
|
1217
|
-
version = "1.
|
|
1217
|
+
version = "1.5.0"
|
|
1218
1218
|
dependencies = [
|
|
1219
1219
|
"anyhow",
|
|
1220
1220
|
"clap",
|
data/ext/rfmt/Cargo.toml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "rfmt"
|
|
3
|
-
version = "1.
|
|
3
|
+
version = "1.5.0"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
authors = ["fujitani sora <fujitanisora0414@gmail.com>"]
|
|
6
6
|
license = "MIT"
|
|
@@ -12,8 +12,8 @@ crate-type = ["cdylib"]
|
|
|
12
12
|
|
|
13
13
|
[dependencies]
|
|
14
14
|
# Ruby FFI
|
|
15
|
-
magnus = { version = "0.
|
|
16
|
-
rb-sys = "0.9.
|
|
15
|
+
magnus = { version = "0.8.2" }
|
|
16
|
+
rb-sys = "0.9.124"
|
|
17
17
|
|
|
18
18
|
# Serialization
|
|
19
19
|
serde = { version = "1.0", features = ["derive"] }
|
data/ext/rfmt/src/emitter/mod.rs
CHANGED
|
@@ -144,6 +144,10 @@ impl Emitter {
|
|
|
144
144
|
/// Get comment indices in the given line range [start_line, end_line)
|
|
145
145
|
/// Uses BTreeMap range for O(log n) lookup instead of O(n) iteration
|
|
146
146
|
fn get_comment_indices_in_range(&self, start_line: usize, end_line: usize) -> Vec<usize> {
|
|
147
|
+
// Guard against invalid range (e.g., endless methods where start_line >= end_line)
|
|
148
|
+
if start_line >= end_line {
|
|
149
|
+
return Vec::new();
|
|
150
|
+
}
|
|
147
151
|
self.comments_by_line
|
|
148
152
|
.range(start_line..end_line)
|
|
149
153
|
.flat_map(|(_, indices)| indices.iter().copied())
|
|
@@ -228,6 +232,10 @@ impl Emitter {
|
|
|
228
232
|
/// Check if there are any unemitted comments in the given line range
|
|
229
233
|
/// Uses BTreeMap index for O(log n) lookup instead of O(n) iteration
|
|
230
234
|
fn has_comments_in_range(&self, start_line: usize, end_line: usize) -> bool {
|
|
235
|
+
// Guard against invalid range (e.g., endless methods where start_line >= end_line)
|
|
236
|
+
if start_line >= end_line {
|
|
237
|
+
return false;
|
|
238
|
+
}
|
|
231
239
|
self.comments_by_line
|
|
232
240
|
.range(start_line..end_line)
|
|
233
241
|
.flat_map(|(_, indices)| indices.iter())
|
|
@@ -344,6 +352,31 @@ impl Emitter {
|
|
|
344
352
|
false
|
|
345
353
|
}
|
|
346
354
|
|
|
355
|
+
/// Check if the node spans only a single line
|
|
356
|
+
fn is_single_line(&self, node: &Node) -> bool {
|
|
357
|
+
node.location.start_line == node.location.end_line
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/// Extract and write source text for a node
|
|
361
|
+
fn write_source_text(&mut self, node: &Node) -> Result<()> {
|
|
362
|
+
let start = node.location.start_offset;
|
|
363
|
+
let end = node.location.end_offset;
|
|
364
|
+
if let Some(text) = self.source.get(start..end) {
|
|
365
|
+
write!(self.buffer, "{}", text)?;
|
|
366
|
+
}
|
|
367
|
+
Ok(())
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/// Extract and write trimmed source text for a node
|
|
371
|
+
fn write_source_text_trimmed(&mut self, node: &Node) -> Result<()> {
|
|
372
|
+
let start = node.location.start_offset;
|
|
373
|
+
let end = node.location.end_offset;
|
|
374
|
+
if let Some(text) = self.source.get(start..end) {
|
|
375
|
+
write!(self.buffer, "{}", text.trim())?;
|
|
376
|
+
}
|
|
377
|
+
Ok(())
|
|
378
|
+
}
|
|
379
|
+
|
|
347
380
|
/// Emit comments that are within a given line range, preserving blank lines from prev_line
|
|
348
381
|
/// Uses BTreeMap index for O(log n) lookup instead of O(n) iteration
|
|
349
382
|
fn emit_comments_in_range_with_prev_line(
|
|
@@ -899,25 +932,30 @@ impl Emitter {
|
|
|
899
932
|
|
|
900
933
|
// Emit conditions with comma separator
|
|
901
934
|
for (i, cond) in conditions.iter().enumerate() {
|
|
902
|
-
|
|
903
|
-
let end = cond.location.end_offset;
|
|
904
|
-
if let Some(text) = self.source.get(start..end) {
|
|
905
|
-
write!(self.buffer, "{}", text)?;
|
|
906
|
-
}
|
|
935
|
+
self.write_source_text(cond)?;
|
|
907
936
|
if i < conditions.len() - 1 {
|
|
908
937
|
write!(self.buffer, ", ")?;
|
|
909
938
|
}
|
|
910
939
|
}
|
|
911
940
|
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
// Emit statements body
|
|
915
|
-
if let Some(statements) = node
|
|
941
|
+
let statements = node
|
|
916
942
|
.children
|
|
917
943
|
.iter()
|
|
918
|
-
.find(|c| matches!(c.node_type, NodeType::StatementsNode))
|
|
919
|
-
|
|
920
|
-
|
|
944
|
+
.find(|c| matches!(c.node_type, NodeType::StatementsNode));
|
|
945
|
+
|
|
946
|
+
if self.is_single_line(node) {
|
|
947
|
+
// Inline style: when X then Y
|
|
948
|
+
if let Some(statements) = statements {
|
|
949
|
+
write!(self.buffer, " then ")?;
|
|
950
|
+
self.write_source_text(statements)?;
|
|
951
|
+
}
|
|
952
|
+
} else {
|
|
953
|
+
// Multi-line style: when X\n Y
|
|
954
|
+
self.buffer.push('\n');
|
|
955
|
+
|
|
956
|
+
if let Some(statements) = statements {
|
|
957
|
+
self.emit_statements(statements, indent_level + 1)?;
|
|
958
|
+
}
|
|
921
959
|
}
|
|
922
960
|
|
|
923
961
|
Ok(())
|
|
@@ -951,14 +989,7 @@ impl Emitter {
|
|
|
951
989
|
// Emit statement
|
|
952
990
|
if let Some(statements) = node.children.get(1) {
|
|
953
991
|
if matches!(statements.node_type, NodeType::StatementsNode) {
|
|
954
|
-
|
|
955
|
-
if !self.source.is_empty() {
|
|
956
|
-
let start = statements.location.start_offset;
|
|
957
|
-
let end = statements.location.end_offset;
|
|
958
|
-
if let Some(text) = self.source.get(start..end) {
|
|
959
|
-
write!(self.buffer, "{}", text.trim())?;
|
|
960
|
-
}
|
|
961
|
-
}
|
|
992
|
+
self.write_source_text_trimmed(statements)?;
|
|
962
993
|
}
|
|
963
994
|
}
|
|
964
995
|
|
|
@@ -966,13 +997,7 @@ impl Emitter {
|
|
|
966
997
|
|
|
967
998
|
// Emit condition
|
|
968
999
|
if let Some(predicate) = node.children.first() {
|
|
969
|
-
|
|
970
|
-
let start = predicate.location.start_offset;
|
|
971
|
-
let end = predicate.location.end_offset;
|
|
972
|
-
if let Some(text) = self.source.get(start..end) {
|
|
973
|
-
write!(self.buffer, "{}", text)?;
|
|
974
|
-
}
|
|
975
|
-
}
|
|
1000
|
+
self.write_source_text(predicate)?;
|
|
976
1001
|
}
|
|
977
1002
|
|
|
978
1003
|
return Ok(());
|
|
@@ -991,26 +1016,14 @@ impl Emitter {
|
|
|
991
1016
|
|
|
992
1017
|
// Emit condition
|
|
993
1018
|
if let Some(predicate) = node.children.first() {
|
|
994
|
-
|
|
995
|
-
let start = predicate.location.start_offset;
|
|
996
|
-
let end = predicate.location.end_offset;
|
|
997
|
-
if let Some(text) = self.source.get(start..end) {
|
|
998
|
-
write!(self.buffer, "{}", text)?;
|
|
999
|
-
}
|
|
1000
|
-
}
|
|
1019
|
+
self.write_source_text(predicate)?;
|
|
1001
1020
|
}
|
|
1002
1021
|
|
|
1003
1022
|
write!(self.buffer, " ? ")?;
|
|
1004
1023
|
|
|
1005
1024
|
// Emit then expression
|
|
1006
1025
|
if let Some(statements) = node.children.get(1) {
|
|
1007
|
-
|
|
1008
|
-
let start = statements.location.start_offset;
|
|
1009
|
-
let end = statements.location.end_offset;
|
|
1010
|
-
if let Some(text) = self.source.get(start..end) {
|
|
1011
|
-
write!(self.buffer, "{}", text.trim())?;
|
|
1012
|
-
}
|
|
1013
|
-
}
|
|
1026
|
+
self.write_source_text_trimmed(statements)?;
|
|
1014
1027
|
}
|
|
1015
1028
|
|
|
1016
1029
|
write!(self.buffer, " : ")?;
|
|
@@ -1018,19 +1031,40 @@ impl Emitter {
|
|
|
1018
1031
|
// Emit else expression
|
|
1019
1032
|
if let Some(else_node) = node.children.get(2) {
|
|
1020
1033
|
if let Some(else_statements) = else_node.children.first() {
|
|
1021
|
-
|
|
1022
|
-
let start = else_statements.location.start_offset;
|
|
1023
|
-
let end = else_statements.location.end_offset;
|
|
1024
|
-
if let Some(text) = self.source.get(start..end) {
|
|
1025
|
-
write!(self.buffer, "{}", text.trim())?;
|
|
1026
|
-
}
|
|
1027
|
-
}
|
|
1034
|
+
self.write_source_text_trimmed(else_statements)?;
|
|
1028
1035
|
}
|
|
1029
1036
|
}
|
|
1030
1037
|
|
|
1031
1038
|
return Ok(());
|
|
1032
1039
|
}
|
|
1033
1040
|
|
|
1041
|
+
// Check for inline then style: "if true then 1 end"
|
|
1042
|
+
// Single line, not postfix, not ternary, no else clause
|
|
1043
|
+
let is_inline_then =
|
|
1044
|
+
!is_elsif && self.is_single_line(node) && node.children.get(2).is_none();
|
|
1045
|
+
|
|
1046
|
+
if is_inline_then {
|
|
1047
|
+
self.emit_comments_before(node.location.start_line, indent_level)?;
|
|
1048
|
+
self.emit_indent(indent_level)?;
|
|
1049
|
+
write!(self.buffer, "{} ", keyword)?;
|
|
1050
|
+
|
|
1051
|
+
// Emit condition
|
|
1052
|
+
if let Some(predicate) = node.children.first() {
|
|
1053
|
+
self.write_source_text(predicate)?;
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
write!(self.buffer, " then ")?;
|
|
1057
|
+
|
|
1058
|
+
// Emit statement
|
|
1059
|
+
if let Some(statements) = node.children.get(1) {
|
|
1060
|
+
self.write_source_text_trimmed(statements)?;
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
write!(self.buffer, " end")?;
|
|
1064
|
+
self.emit_trailing_comments(node.location.end_line)?;
|
|
1065
|
+
return Ok(());
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1034
1068
|
// Normal if/unless/elsif
|
|
1035
1069
|
if !is_elsif {
|
|
1036
1070
|
self.emit_comments_before(node.location.start_line, indent_level)?;
|
|
@@ -1046,14 +1080,7 @@ impl Emitter {
|
|
|
1046
1080
|
|
|
1047
1081
|
// Emit predicate (condition) - first child
|
|
1048
1082
|
if let Some(predicate) = node.children.first() {
|
|
1049
|
-
|
|
1050
|
-
if !self.source.is_empty() {
|
|
1051
|
-
let start = predicate.location.start_offset;
|
|
1052
|
-
let end = predicate.location.end_offset;
|
|
1053
|
-
if let Some(text) = self.source.get(start..end) {
|
|
1054
|
-
write!(self.buffer, "{}", text)?;
|
|
1055
|
-
}
|
|
1056
|
-
}
|
|
1083
|
+
self.write_source_text(predicate)?;
|
|
1057
1084
|
}
|
|
1058
1085
|
|
|
1059
1086
|
// Emit trailing comment on same line as if/unless/elsif
|
|
@@ -1193,14 +1220,27 @@ impl Emitter {
|
|
|
1193
1220
|
let mut last_stmt_end_line = block_start_line;
|
|
1194
1221
|
|
|
1195
1222
|
for child in &block_node.children {
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1223
|
+
match &child.node_type {
|
|
1224
|
+
NodeType::StatementsNode => {
|
|
1225
|
+
self.emit_statements(child, indent_level + 1)?;
|
|
1226
|
+
// Track the last statement's end line for blank line preservation
|
|
1227
|
+
if let Some(last_child) = child.children.last() {
|
|
1228
|
+
last_stmt_end_line = last_child.location.end_line;
|
|
1229
|
+
}
|
|
1230
|
+
self.buffer.push('\n');
|
|
1231
|
+
break;
|
|
1232
|
+
}
|
|
1233
|
+
NodeType::BeginNode => {
|
|
1234
|
+
// Block with rescue/ensure/else - delegate to emit_begin
|
|
1235
|
+
// which handles implicit begin (no "begin" keyword)
|
|
1236
|
+
self.emit_begin(child, indent_level + 1)?;
|
|
1237
|
+
self.buffer.push('\n');
|
|
1238
|
+
last_stmt_end_line = child.location.end_line;
|
|
1239
|
+
break;
|
|
1240
|
+
}
|
|
1241
|
+
_ => {
|
|
1242
|
+
// Skip parameter nodes
|
|
1201
1243
|
}
|
|
1202
|
-
self.buffer.push('\n');
|
|
1203
|
-
break;
|
|
1204
1244
|
}
|
|
1205
1245
|
}
|
|
1206
1246
|
|
|
@@ -1236,6 +1276,7 @@ impl Emitter {
|
|
|
1236
1276
|
fn emit_brace_block(&mut self, block_node: &Node, indent_level: usize) -> Result<()> {
|
|
1237
1277
|
// Determine if block should be inline or multiline
|
|
1238
1278
|
let is_multiline = block_node.location.start_line != block_node.location.end_line;
|
|
1279
|
+
let block_end_line = block_node.location.end_line;
|
|
1239
1280
|
|
|
1240
1281
|
if is_multiline {
|
|
1241
1282
|
// Multiline brace block
|
|
@@ -1254,6 +1295,7 @@ impl Emitter {
|
|
|
1254
1295
|
|
|
1255
1296
|
self.emit_indent(indent_level)?;
|
|
1256
1297
|
write!(self.buffer, "}}")?;
|
|
1298
|
+
self.emit_trailing_comments(block_end_line)?;
|
|
1257
1299
|
} else {
|
|
1258
1300
|
// Inline brace block - extract from source to preserve spacing
|
|
1259
1301
|
write!(self.buffer, " ")?;
|
|
@@ -1263,6 +1305,7 @@ impl Emitter {
|
|
|
1263
1305
|
{
|
|
1264
1306
|
write!(self.buffer, "{}", text)?;
|
|
1265
1307
|
}
|
|
1308
|
+
self.emit_trailing_comments(block_end_line)?;
|
|
1266
1309
|
}
|
|
1267
1310
|
|
|
1268
1311
|
Ok(())
|
|
@@ -1571,7 +1614,6 @@ impl Emitter {
|
|
|
1571
1614
|
match &child.node_type {
|
|
1572
1615
|
NodeType::InNode => {
|
|
1573
1616
|
self.emit_in(child, indent_level)?;
|
|
1574
|
-
self.buffer.push('\n');
|
|
1575
1617
|
}
|
|
1576
1618
|
NodeType::ElseNode => {
|
|
1577
1619
|
self.emit_indent(indent_level)?;
|
|
@@ -1607,19 +1649,25 @@ impl Emitter {
|
|
|
1607
1649
|
|
|
1608
1650
|
// First child is the pattern
|
|
1609
1651
|
if let Some(pattern) = node.children.first() {
|
|
1610
|
-
|
|
1611
|
-
let end = pattern.location.end_offset;
|
|
1612
|
-
if let Some(text) = self.source.get(start..end) {
|
|
1613
|
-
write!(self.buffer, "{}", text)?;
|
|
1614
|
-
}
|
|
1652
|
+
self.write_source_text(pattern)?;
|
|
1615
1653
|
}
|
|
1616
1654
|
|
|
1617
|
-
self.
|
|
1655
|
+
if self.is_single_line(node) {
|
|
1656
|
+
// Inline style: in X then Y
|
|
1657
|
+
if let Some(statements) = node.children.get(1) {
|
|
1658
|
+
write!(self.buffer, " then ")?;
|
|
1659
|
+
self.write_source_text(statements)?;
|
|
1660
|
+
}
|
|
1661
|
+
self.buffer.push('\n');
|
|
1662
|
+
} else {
|
|
1663
|
+
// Multi-line style: in X\n Y
|
|
1664
|
+
self.buffer.push('\n');
|
|
1618
1665
|
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1666
|
+
// Second child is the statements body
|
|
1667
|
+
if let Some(statements) = node.children.get(1) {
|
|
1668
|
+
if matches!(statements.node_type, NodeType::StatementsNode) {
|
|
1669
|
+
self.emit_statements(statements, indent_level + 1)?;
|
|
1670
|
+
}
|
|
1623
1671
|
}
|
|
1624
1672
|
}
|
|
1625
1673
|
|
data/ext/rfmt/src/lib.rs
CHANGED
|
@@ -10,7 +10,7 @@ use policy::SecurityPolicy;
|
|
|
10
10
|
|
|
11
11
|
use config::Config;
|
|
12
12
|
use emitter::Emitter;
|
|
13
|
-
use magnus::{
|
|
13
|
+
use magnus::{function, prelude::*, Error, Ruby};
|
|
14
14
|
use parser::{PrismAdapter, RubyParser};
|
|
15
15
|
|
|
16
16
|
fn format_ruby_code(ruby: &Ruby, source: String, json: String) -> Result<String, Error> {
|
|
@@ -45,10 +45,10 @@ fn rust_version() -> String {
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
#[magnus::init]
|
|
48
|
-
fn init(
|
|
48
|
+
fn init(ruby: &Ruby) -> Result<(), Error> {
|
|
49
49
|
logging::RfmtLogger::init();
|
|
50
50
|
|
|
51
|
-
let module = define_module("Rfmt")?;
|
|
51
|
+
let module = ruby.define_module("Rfmt")?;
|
|
52
52
|
|
|
53
53
|
module.define_singleton_method("format_code", function!(format_ruby_code, 2))?;
|
|
54
54
|
module.define_singleton_method("parse_to_json", function!(parse_to_json, 1))?;
|
data/lib/rfmt/prism_bridge.rb
CHANGED
|
@@ -108,13 +108,42 @@ module Rfmt
|
|
|
108
108
|
# Extract location information from node
|
|
109
109
|
def self.extract_location(node)
|
|
110
110
|
loc = node.location
|
|
111
|
+
|
|
112
|
+
# For heredoc nodes, the location only covers the opening tag (<<~CSV)
|
|
113
|
+
# We need to find the maximum end_offset including closing_loc
|
|
114
|
+
end_offset = loc.end_offset
|
|
115
|
+
end_line = loc.end_line
|
|
116
|
+
end_column = loc.end_column
|
|
117
|
+
|
|
118
|
+
# Check this node's closing_loc
|
|
119
|
+
if node.respond_to?(:closing_loc) && node.closing_loc
|
|
120
|
+
closing = node.closing_loc
|
|
121
|
+
if closing.end_offset > end_offset
|
|
122
|
+
end_offset = closing.end_offset
|
|
123
|
+
end_line = closing.end_line
|
|
124
|
+
end_column = closing.end_column
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Check child nodes for heredoc (e.g., LocalVariableWriteNode containing StringNode)
|
|
129
|
+
node.child_nodes.compact.each do |child|
|
|
130
|
+
next unless child.respond_to?(:closing_loc) && child.closing_loc
|
|
131
|
+
|
|
132
|
+
closing = child.closing_loc
|
|
133
|
+
next unless closing.end_offset > end_offset
|
|
134
|
+
|
|
135
|
+
end_offset = closing.end_offset
|
|
136
|
+
end_line = closing.end_line
|
|
137
|
+
end_column = closing.end_column
|
|
138
|
+
end
|
|
139
|
+
|
|
111
140
|
{
|
|
112
141
|
start_line: loc.start_line,
|
|
113
142
|
start_column: loc.start_column,
|
|
114
|
-
end_line:
|
|
115
|
-
end_column:
|
|
143
|
+
end_line: end_line,
|
|
144
|
+
end_column: end_column,
|
|
116
145
|
start_offset: loc.start_offset,
|
|
117
|
-
end_offset:
|
|
146
|
+
end_offset: end_offset
|
|
118
147
|
}
|
|
119
148
|
end
|
|
120
149
|
|
|
@@ -176,6 +205,7 @@ module Rfmt
|
|
|
176
205
|
[
|
|
177
206
|
node.statements,
|
|
178
207
|
node.rescue_clause,
|
|
208
|
+
node.else_clause,
|
|
179
209
|
node.ensure_clause
|
|
180
210
|
].compact
|
|
181
211
|
when Prism::EnsureNode
|
data/lib/rfmt/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rfmt
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- fujitani sora
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: exe
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: diff-lcs
|
|
@@ -113,7 +112,6 @@ metadata:
|
|
|
113
112
|
source_code_uri: https://github.com/fs0414/rfmt
|
|
114
113
|
changelog_uri: https://github.com/fs0414/rfmt/releases
|
|
115
114
|
ruby_lsp_addon: 'true'
|
|
116
|
-
post_install_message:
|
|
117
115
|
rdoc_options: []
|
|
118
116
|
require_paths:
|
|
119
117
|
- lib
|
|
@@ -128,8 +126,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
128
126
|
- !ruby/object:Gem::Version
|
|
129
127
|
version: 3.0.0
|
|
130
128
|
requirements: []
|
|
131
|
-
rubygems_version: 3.
|
|
132
|
-
signing_key:
|
|
129
|
+
rubygems_version: 3.6.9
|
|
133
130
|
specification_version: 4
|
|
134
131
|
summary: Ruby Formatter impl Rust lang.
|
|
135
132
|
test_files: []
|