From 561ce1d31473b3049e8cbfba731fc592154fb13e Mon Sep 17 00:00:00 2001 From: Arian Rezazadeh Date: Wed, 1 Jan 2025 19:49:37 +0330 Subject: [PATCH 01/31] feat: implement proof of concept of format command --- Cargo.lock | 799 ++++++++++++++++++++++++------ crates/cli/Cargo.toml | 5 +- crates/cli/src/commands/format.rs | 58 +++ crates/cli/src/commands/mod.rs | 6 + crates/cli/src/ux.rs | 2 +- 5 files changed, 723 insertions(+), 147 deletions(-) create mode 100644 crates/cli/src/commands/format.rs diff --git a/Cargo.lock b/Cargo.lock index 7a9088a7d..178f2f5cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" @@ -8,7 +8,16 @@ version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ - "gimli", + "gimli 0.28.1", +] + +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli 0.31.1", ] [[package]] @@ -17,6 +26,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + [[package]] name = "ahash" version = "0.8.11" @@ -147,7 +162,7 @@ checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.93", ] [[package]] @@ -158,7 +173,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.93", ] [[package]] @@ -271,17 +286,17 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ - "addr2line", - "cc", + "addr2line 0.24.2", "cfg-if", "libc", - "miniz_oxide", - "object", + "miniz_oxide 0.8.2", + "object 0.36.7", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] @@ -305,6 +320,259 @@ dependencies = [ "serde", ] +[[package]] +name = "biome_console" +version = "0.5.7" +source = "git+https://github.com/biomejs/biome#6ea885f0cec47a6db48d662cbd828f4f335209ba" +dependencies = [ + "biome_markup", + "biome_text_size", + "schemars", + "serde", + "termcolor", + "unicode-segmentation", + "unicode-width", +] + +[[package]] +name = "biome_deserialize" +version = "0.6.0" +source = "git+https://github.com/biomejs/biome#6ea885f0cec47a6db48d662cbd828f4f335209ba" +dependencies = [ + "biome_console", + "biome_deserialize_macros", + "biome_diagnostics", + "biome_json_parser", + "biome_json_syntax", + "biome_rowan", + "enumflags2", + "indexmap 2.7.0", + "serde", +] + +[[package]] +name = "biome_deserialize_macros" +version = "0.6.0" +source = "git+https://github.com/biomejs/biome#6ea885f0cec47a6db48d662cbd828f4f335209ba" +dependencies = [ + "biome_string_case", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "biome_diagnostics" +version = "0.5.7" +source = "git+https://github.com/biomejs/biome#6ea885f0cec47a6db48d662cbd828f4f335209ba" +dependencies = [ + "backtrace", + "biome_console", + "biome_diagnostics_categories", + "biome_diagnostics_macros", + "biome_rowan", + "biome_text_edit", + "biome_text_size", + "bpaf", + "enumflags2", + "oxc_resolver", + "serde", + "serde_ini", + "serde_json", + "termcolor", + "unicode-width", +] + +[[package]] +name = "biome_diagnostics_categories" +version = "0.5.7" +source = "git+https://github.com/biomejs/biome#6ea885f0cec47a6db48d662cbd828f4f335209ba" +dependencies = [ + "quote", + "serde", +] + +[[package]] +name = "biome_diagnostics_macros" +version = "0.5.7" +source = "git+https://github.com/biomejs/biome#6ea885f0cec47a6db48d662cbd828f4f335209ba" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "biome_formatter" +version = "0.5.7" +source = "git+https://github.com/biomejs/biome#6ea885f0cec47a6db48d662cbd828f4f335209ba" +dependencies = [ + "biome_console", + "biome_deserialize", + "biome_deserialize_macros", + "biome_diagnostics", + "biome_rowan", + "biome_string_case", + "cfg-if", + "countme", + "drop_bomb", + "indexmap 2.7.0", + "rustc-hash 2.1.0", + "tracing", + "unicode-width", +] + +[[package]] +name = "biome_grit_factory" +version = "0.5.7" +source = "git+https://github.com/biomejs/biome#6ea885f0cec47a6db48d662cbd828f4f335209ba" +dependencies = [ + "biome_grit_syntax", + "biome_rowan", +] + +[[package]] +name = "biome_grit_formatter" +version = "0.0.0" +source = "git+https://github.com/biomejs/biome#6ea885f0cec47a6db48d662cbd828f4f335209ba" +dependencies = [ + "biome_formatter", + "biome_grit_syntax", + "biome_rowan", +] + +[[package]] +name = "biome_grit_parser" +version = "0.1.0" +source = "git+https://github.com/biomejs/biome#6ea885f0cec47a6db48d662cbd828f4f335209ba" +dependencies = [ + "biome_console", + "biome_diagnostics", + "biome_grit_factory", + "biome_grit_syntax", + "biome_parser", + "biome_rowan", + "serde", + "serde_json", + "smallvec", + "tracing", + "unicode-bom", +] + +[[package]] +name = "biome_grit_syntax" +version = "0.5.7" +source = "git+https://github.com/biomejs/biome#6ea885f0cec47a6db48d662cbd828f4f335209ba" +dependencies = [ + "biome_rowan", + "biome_string_case", + "serde", +] + +[[package]] +name = "biome_json_factory" +version = "0.5.7" +source = "git+https://github.com/biomejs/biome#6ea885f0cec47a6db48d662cbd828f4f335209ba" +dependencies = [ + "biome_json_syntax", + "biome_rowan", +] + +[[package]] +name = "biome_json_parser" +version = "0.5.7" +source = "git+https://github.com/biomejs/biome#6ea885f0cec47a6db48d662cbd828f4f335209ba" +dependencies = [ + "biome_console", + "biome_diagnostics", + "biome_json_factory", + "biome_json_syntax", + "biome_parser", + "biome_rowan", + "biome_unicode_table", + "tracing", + "unicode-bom", +] + +[[package]] +name = "biome_json_syntax" +version = "0.5.7" +source = "git+https://github.com/biomejs/biome#6ea885f0cec47a6db48d662cbd828f4f335209ba" +dependencies = [ + "biome_rowan", + "biome_string_case", + "serde", +] + +[[package]] +name = "biome_markup" +version = "0.5.7" +source = "git+https://github.com/biomejs/biome#6ea885f0cec47a6db48d662cbd828f4f335209ba" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", +] + +[[package]] +name = "biome_parser" +version = "0.5.7" +source = "git+https://github.com/biomejs/biome#6ea885f0cec47a6db48d662cbd828f4f335209ba" +dependencies = [ + "biome_console", + "biome_diagnostics", + "biome_rowan", + "biome_unicode_table", + "drop_bomb", + "enumflags2", + "unicode-bom", +] + +[[package]] +name = "biome_rowan" +version = "0.5.7" +source = "git+https://github.com/biomejs/biome#6ea885f0cec47a6db48d662cbd828f4f335209ba" +dependencies = [ + "biome_text_edit", + "biome_text_size", + "countme", + "hashbrown 0.14.5", + "rustc-hash 2.1.0", + "serde", + "tracing", +] + +[[package]] +name = "biome_string_case" +version = "0.5.7" +source = "git+https://github.com/biomejs/biome#6ea885f0cec47a6db48d662cbd828f4f335209ba" + +[[package]] +name = "biome_text_edit" +version = "0.5.7" +source = "git+https://github.com/biomejs/biome#6ea885f0cec47a6db48d662cbd828f4f335209ba" +dependencies = [ + "biome_text_size", + "serde", + "similar", +] + +[[package]] +name = "biome_text_size" +version = "0.5.7" +source = "git+https://github.com/biomejs/biome#6ea885f0cec47a6db48d662cbd828f4f335209ba" +dependencies = [ + "schemars", + "serde", +] + +[[package]] +name = "biome_unicode_table" +version = "0.5.7" +source = "git+https://github.com/biomejs/biome#6ea885f0cec47a6db48d662cbd828f4f335209ba" + [[package]] name = "bitflags" version = "1.3.2" @@ -326,6 +594,26 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bpaf" +version = "0.9.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50fd5174866dc2fa2ddc96e8fb800852d37f064f32a45c7b7c2f8fa2c64c77fa" +dependencies = [ + "bpaf_derive", +] + +[[package]] +name = "bpaf_derive" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf95d9c7e6aba67f8fc07761091e93254677f4db9e27197adecebc7039a58722" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.93", +] + [[package]] name = "bstr" version = "1.9.1" @@ -500,7 +788,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets 0.52.4", + "windows-targets 0.52.6", ] [[package]] @@ -542,7 +830,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.93", ] [[package]] @@ -620,6 +908,12 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +[[package]] +name = "countme" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636" + [[package]] name = "cpp_demangle" version = "0.3.5" @@ -660,8 +954,8 @@ dependencies = [ "cranelift-control", "cranelift-entity", "cranelift-isle", - "gimli", - "hashbrown 0.14.3", + "gimli 0.28.1", + "hashbrown 0.14.5", "log", "regalloc2", "smallvec", @@ -807,7 +1101,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f" dependencies = [ "quote", - "syn 2.0.52", + "syn 2.0.93", ] [[package]] @@ -852,7 +1146,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ "cfg-if", - "hashbrown 0.14.3", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "dashmap" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown 0.14.5", "lock_api", "once_cell", "parking_lot_core", @@ -973,6 +1281,18 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" +[[package]] +name = "drop_bomb" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bda8e21c04aca2ae33ffc2fd8c23134f3cac46db123ba97bd9d3f3b8a4a85e1" + +[[package]] +name = "dyn-clone" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" + [[package]] name = "either" version = "1.10.0" @@ -1017,7 +1337,27 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.93", +] + +[[package]] +name = "enumflags2" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d232db7f5956f3f14313dc2f87985c58bd2c695ce124c8cdd984e08e15ac133d" +dependencies = [ + "enumflags2_derive", +] + +[[package]] +name = "enumflags2_derive" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.93", ] [[package]] @@ -1100,7 +1440,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.93", ] [[package]] @@ -1156,7 +1496,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" dependencies = [ "crc32fast", - "miniz_oxide", + "miniz_oxide 0.7.2", ] [[package]] @@ -1289,7 +1629,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.93", ] [[package]] @@ -1374,10 +1714,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" dependencies = [ "fallible-iterator", - "indexmap 2.2.5", + "indexmap 2.7.0", "stable_deref_trait", ] +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + [[package]] name = "git2" version = "0.19.0" @@ -1513,7 +1859,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.2.5", + "indexmap 2.7.0", "slab", "tokio", "tokio-util", @@ -1537,13 +1883,19 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash", ] +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" + [[package]] name = "heck" version = "0.4.1" @@ -1834,12 +2186,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.5" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", - "hashbrown 0.14.3", + "hashbrown 0.15.2", "serde", ] @@ -2007,6 +2359,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "json-strip-comments" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b271732a960335e715b6b2ae66a086f115c74eb97360e996d2bd809bfc063bba" +dependencies = [ + "memchr", +] + [[package]] name = "kqueue" version = "1.0.8" @@ -2041,9 +2402,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "libgit2-sys" @@ -2066,7 +2427,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" dependencies = [ "cfg-if", - "windows-targets 0.52.4", + "windows-targets 0.48.5", ] [[package]] @@ -2165,7 +2526,7 @@ dependencies = [ "manyhow-macros", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.93", ] [[package]] @@ -2201,13 +2562,15 @@ dependencies = [ "ai_builtins", "anyhow", "axoupdater", + "biome_grit_formatter", + "biome_grit_parser", "chrono", "clap", "clap-markdown", "cli_server", "colored", "console", - "dashmap", + "dashmap 5.5.3", "dialoguer", "env_logger", "flate2", @@ -2370,7 +2733,7 @@ version = "0.1.0" dependencies = [ "ai_builtins", "anyhow", - "dashmap", + "dashmap 5.5.3", "grit-util", "grit_cache", "marzano-core", @@ -2463,9 +2826,9 @@ checksum = "4facc753ae494aeb6e3c22f839b158aebd4f9270f55cd3c79906c45476c47ab4" [[package]] name = "memchr" -version = "2.7.1" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memfd" @@ -2514,7 +2877,7 @@ checksum = "dcf09caffaac8068c346b6df2a7fc27a177fd20b39421a39ce0a211bde679a6c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.93", ] [[package]] @@ -2532,6 +2895,15 @@ dependencies = [ "adler", ] +[[package]] +name = "miniz_oxide" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" +dependencies = [ + "adler2", +] + [[package]] name = "mio" version = "0.8.11" @@ -2569,7 +2941,7 @@ dependencies = [ "napi-derive-backend", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.93", ] [[package]] @@ -2584,7 +2956,7 @@ dependencies = [ "quote", "regex", "semver", - "syn 2.0.52", + "syn 2.0.93", ] [[package]] @@ -2738,8 +3110,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" dependencies = [ "crc32fast", - "hashbrown 0.14.3", - "indexmap 2.2.5", + "hashbrown 0.14.5", + "indexmap 2.7.0", + "memchr", +] + +[[package]] +name = "object" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ "memchr", ] @@ -2772,7 +3153,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.93", ] [[package]] @@ -2811,7 +3192,7 @@ checksum = "1e32339a5dc40459130b3bd269e9892439f55b33e772d2a9d402a789baaf4e8a" dependencies = [ "futures-core", "futures-sink", - "indexmap 2.2.5", + "indexmap 2.7.0", "js-sys", "once_cell", "pin-project-lite", @@ -2912,6 +3293,25 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +[[package]] +name = "oxc_resolver" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bed381b6ab4bbfebfc7a011ad43b110ace8d201d02a39c0e09855f16b8f3f741" +dependencies = [ + "cfg-if", + "dashmap 6.1.0", + "indexmap 2.7.0", + "json-strip-comments", + "once_cell", + "rustc-hash 2.1.0", + "serde", + "serde_json", + "simdutf8", + "thiserror", + "tracing", +] + [[package]] name = "parking_lot" version = "0.12.1" @@ -2996,7 +3396,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.93", ] [[package]] @@ -3027,7 +3427,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.93", ] [[package]] @@ -3099,6 +3499,29 @@ dependencies = [ "toml_edit 0.21.1", ] +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro-utils" version = "0.8.0" @@ -3112,9 +3535,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -3162,7 +3585,7 @@ dependencies = [ "itertools 0.11.0", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.93", ] [[package]] @@ -3184,7 +3607,7 @@ dependencies = [ "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "rustls 0.23.7", "socket2", "thiserror", @@ -3201,7 +3624,7 @@ dependencies = [ "bytes", "rand", "ring", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "rustls 0.23.7", "slab", "thiserror", @@ -3224,9 +3647,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.35" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] @@ -3442,6 +3865,12 @@ dependencies = [ "winreg 0.52.0", ] +[[package]] +name = "result" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194d8e591e405d1eecf28819740abed6d719d1a2db87fc0bcdedee9a26d55560" + [[package]] name = "ring" version = "0.17.8" @@ -3481,9 +3910,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc-hash" @@ -3493,9 +3922,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc-hash" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" +checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" [[package]] name = "rustix" @@ -3606,6 +4035,32 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "schemars" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92" +dependencies = [ + "dyn-clone", + "indexmap 2.7.0", + "schemars_derive", + "serde", + "serde_json", + "smallvec", +] + +[[package]] +name = "schemars_derive" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 2.0.93", +] + [[package]] name = "scoped-tls" version = "1.0.1" @@ -3649,9 +4104,9 @@ checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" [[package]] name = "serde" -version = "1.0.208" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" dependencies = [ "serde_derive", ] @@ -3669,22 +4124,44 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.208" +version = "1.0.217" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.93", +] + +[[package]] +name = "serde_derive_internals" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.93", +] + +[[package]] +name = "serde_ini" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb236687e2bb073a7521c021949be944641e671b8505a94069ca37b656c81139" +dependencies = [ + "result", + "serde", + "void", ] [[package]] name = "serde_json" -version = "1.0.125" +version = "1.0.134" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed" +checksum = "d00f4175c42ee48b15416f6193a959ba3a0d67fc699a0db9ad12df9f83991c7d" dependencies = [ - "indexmap 2.2.5", + "indexmap 2.7.0", "itoa", "memchr", "ryu", @@ -3699,7 +4176,7 @@ checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.93", ] [[package]] @@ -3729,7 +4206,7 @@ version = "0.9.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fd075d994154d4a774f95b51fb96bdc2832b0ea48425c92546073816cda1f2f" dependencies = [ - "indexmap 2.2.5", + "indexmap 2.7.0", "itoa", "ryu", "serde", @@ -3780,11 +4257,21 @@ dependencies = [ "libc", ] +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + [[package]] name = "similar" -version = "2.4.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32fea41aca09ee824cc9724996433064c89f7777e60762749a4170a14abbfa21" +checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e" +dependencies = [ + "bstr", + "unicode-segmentation", +] [[package]] name = "slab" @@ -3803,9 +4290,12 @@ checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7" [[package]] name = "smallvec" -version = "1.13.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +dependencies = [ + "serde", +] [[package]] name = "socket2" @@ -3866,9 +4356,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.52" +version = "2.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" +checksum = "9c786062daee0d6db1132800e623df74274a0a87322d8e183338e01b3d98d058" dependencies = [ "proc-macro2", "quote", @@ -3974,7 +4464,7 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.93", ] [[package]] @@ -4039,7 +4529,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.93", ] [[package]] @@ -4124,7 +4614,7 @@ version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" dependencies = [ - "indexmap 2.2.5", + "indexmap 2.7.0", "toml_datetime", "winnow 0.5.40", ] @@ -4135,7 +4625,7 @@ version = "0.22.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c1b5fd4128cc8d3e0cb74d4ed9a9cc7c7284becd4df68f5f940e1ad123606f6" dependencies = [ - "indexmap 2.2.5", + "indexmap 2.7.0", "serde", "serde_spanned", "toml_datetime", @@ -4205,7 +4695,7 @@ dependencies = [ "async-trait", "auto_impl", "bytes", - "dashmap", + "dashmap 5.5.3", "futures", "httparse", "lsp-types", @@ -4227,7 +4717,7 @@ checksum = "84fd902d4e0b9a4b27f2f440108dc034e1758628a9b702f8ec61ad66355422fa" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.93", ] [[package]] @@ -4238,9 +4728,9 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "log", "pin-project-lite", @@ -4250,20 +4740,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.93", ] [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", "valuable", @@ -4532,6 +5022,12 @@ version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +[[package]] +name = "unicode-bom" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eec5d1121208364f6793f7d2e222bf75a915c19557537745b195b253dd64217" + [[package]] name = "unicode-ident" version = "1.0.12" @@ -4549,15 +5045,15 @@ dependencies = [ [[package]] name = "unicode-segmentation" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-width" -version = "0.1.11" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unicode-xid" @@ -4646,6 +5142,12 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + [[package]] name = "wait-timeout" version = "0.2.0" @@ -4746,7 +5248,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.93", "wasm-bindgen-shared", ] @@ -4780,7 +5282,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.93", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -4813,7 +5315,7 @@ checksum = "b7f89739351a2e03cb94beb799d47fb2cac01759b40ec441f7de39b00cbf7ef0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.93", ] [[package]] @@ -4853,7 +5355,7 @@ version = "0.118.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77f1154f1ab868e2a01d9834a805faca7bf8b50d041b4ca714d005d0dab1c50c" dependencies = [ - "indexmap 2.2.5", + "indexmap 2.7.0", "semver", ] @@ -4864,7 +5366,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9dbe55c8f9d0dbd25d9447a5a889ff90c0cc3feaa7395310d3d826b2c703eaab" dependencies = [ "bitflags 2.4.2", - "indexmap 2.2.5", + "indexmap 2.7.0", "semver", ] @@ -4891,10 +5393,10 @@ dependencies = [ "cfg-if", "encoding_rs", "fxprof-processed-profile", - "indexmap 2.2.5", + "indexmap 2.7.0", "libc", "log", - "object", + "object 0.32.2", "once_cell", "paste", "rayon", @@ -4955,7 +5457,7 @@ dependencies = [ "anyhow", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.93", "wasmtime-component-util", "wasmtime-wit-bindgen", "wit-parser", @@ -4981,9 +5483,9 @@ dependencies = [ "cranelift-frontend", "cranelift-native", "cranelift-wasm", - "gimli", + "gimli 0.28.1", "log", - "object", + "object 0.32.2", "target-lexicon", "thiserror", "wasmparser 0.118.2", @@ -5002,8 +5504,8 @@ dependencies = [ "cranelift-codegen", "cranelift-control", "cranelift-native", - "gimli", - "object", + "gimli 0.28.1", + "object 0.32.2", "target-lexicon", "wasmtime-environ", ] @@ -5016,10 +5518,10 @@ checksum = "099836c3583b85d16e8d1801fe793fa017e9256c5d08bd032cdab0754425be64" dependencies = [ "anyhow", "cranelift-entity", - "gimli", - "indexmap 2.2.5", + "gimli 0.28.1", + "indexmap 2.7.0", "log", - "object", + "object 0.32.2", "serde", "serde_derive", "target-lexicon", @@ -5052,15 +5554,15 @@ version = "17.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdae2c6da571b051c3c1520c9c4206a49939e855cb64c4119ab06ff08a3fc460" dependencies = [ - "addr2line", + "addr2line 0.21.0", "anyhow", "bincode", "cfg-if", "cpp_demangle", - "gimli", + "gimli 0.28.1", "ittapi", "log", - "object", + "object 0.32.2", "rustc-demangle", "rustix", "serde", @@ -5079,7 +5581,7 @@ version = "17.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "793787308417b7ad72cfa22e54d97324d1d9810c2ecf47b8fd8263d5b122e30c" dependencies = [ - "object", + "object 0.32.2", "once_cell", "rustix", "wasmtime-versioned-export-macros", @@ -5106,7 +5608,7 @@ dependencies = [ "cc", "cfg-if", "encoding_rs", - "indexmap 2.2.5", + "indexmap 2.7.0", "libc", "log", "mach", @@ -5147,7 +5649,7 @@ checksum = "e78ba3989894471c172329d42d1fc03edf2efe883fcc05a5d42f7bd5030de0ff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.93", ] [[package]] @@ -5193,8 +5695,8 @@ checksum = "131924cb850fd2c96e87868e101490f738e607fe0eba5ec8dc7c3b43115d8223" dependencies = [ "anyhow", "cranelift-codegen", - "gimli", - "object", + "gimli 0.28.1", + "object 0.32.2", "target-lexicon", "wasmparser 0.118.2", "wasmtime-cranelift-shared", @@ -5210,7 +5712,7 @@ checksum = "81b149b61bd1402bcd5d456c616302812f8bebd65c56f720cefd86ab6cf5c8d8" dependencies = [ "anyhow", "heck", - "indexmap 2.2.5", + "indexmap 2.7.0", "wit-parser", ] @@ -5321,7 +5823,7 @@ dependencies = [ "proc-macro2", "quote", "shellexpand", - "syn 2.0.52", + "syn 2.0.93", "witx", ] @@ -5333,7 +5835,7 @@ checksum = "505e4f6b7b46e693e0027f650956b662de0fcedfc3a2506ce6a4f9f08281791c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.93", "wiggle-generate", ] @@ -5376,7 +5878,7 @@ checksum = "f114f3f980c00f13ee164e431e3abac9cd20b10853849fa6b030d3e4d6be307a" dependencies = [ "anyhow", "cranelift-codegen", - "gimli", + "gimli 0.28.1", "regalloc2", "smallvec", "target-lexicon", @@ -5393,7 +5895,7 @@ dependencies = [ "windows-core", "windows-implement", "windows-interface", - "windows-targets 0.52.4", + "windows-targets 0.52.6", ] [[package]] @@ -5402,7 +5904,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.4", + "windows-targets 0.52.6", ] [[package]] @@ -5413,7 +5915,7 @@ checksum = "12168c33176773b86799be25e2a2ba07c7aab9968b37541f1094dbd7a60c8946" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.93", ] [[package]] @@ -5424,7 +5926,7 @@ checksum = "9d8dc32e0095a7eeccebd0e3f09e9509365ecb3fc6ac4d6f5f14a3f6392942d1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.93", ] [[package]] @@ -5442,7 +5944,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.4", + "windows-targets 0.52.6", ] [[package]] @@ -5462,17 +5964,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.4", - "windows_aarch64_msvc 0.52.4", - "windows_i686_gnu 0.52.4", - "windows_i686_msvc 0.52.4", - "windows_x86_64_gnu 0.52.4", - "windows_x86_64_gnullvm 0.52.4", - "windows_x86_64_msvc 0.52.4", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -5483,9 +5986,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" @@ -5495,9 +5998,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" @@ -5507,9 +6010,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.4" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" @@ -5519,9 +6028,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" @@ -5531,9 +6040,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" @@ -5543,9 +6052,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" @@ -5555,9 +6064,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" @@ -5615,7 +6124,7 @@ checksum = "316b36a9f0005f5aa4b03c39bc3728d045df136f8c13a73b7db4510dec725e08" dependencies = [ "anyhow", "id-arena", - "indexmap 2.2.5", + "indexmap 2.7.0", "log", "semver", "serde", @@ -5676,7 +6185,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.93", ] [[package]] diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 65b90d1da..7bfd3b5c7 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -20,7 +20,8 @@ anyhow = { version = "1.0.70" } clap = { version = "4.1.13", features = ["derive"] } indicatif = { version = "0.17.5" } # Do *NOT* upgrade beyond 1.0.171 until https://github.com/serde-rs/serde/issues/2538 is fixed -serde = { version = "1.0.164", features = ["derive"] } +# TODO: find a work around instead of ignoring above +serde = { version = "1.0.217", features = ["derive"] } serde_json = { version = "1.0.96" } uuid = { version = "1.1", features = ["v4", "serde"] } tokio = { version = "1", features = ["full"] } @@ -88,6 +89,8 @@ tracing-subscriber = { version = "0.3", default-features = false, optional = tru tracing-log = { version = "0.2.0", optional = true } fs-err = { version = "2.11.0" } +biome_grit_parser = { git = "https://github.com/biomejs/biome" } +biome_grit_formatter = { git = "https://github.com/biomejs/biome" } [target.'cfg(not(windows))'.dependencies] openssl = { version = "0.10", features = ["vendored"] } diff --git a/crates/cli/src/commands/format.rs b/crates/cli/src/commands/format.rs new file mode 100644 index 000000000..400fcaa57 --- /dev/null +++ b/crates/cli/src/commands/format.rs @@ -0,0 +1,58 @@ +use crate::{ + resolver::{resolve_from_cwd, Source}, + ux::format_diff, +}; +use anyhow::{ensure, Context, Result}; +use biome_grit_formatter::context::GritFormatOptions; +use clap::Args; +use serde::Serialize; + +#[derive(Args, Debug, Serialize)] +pub struct FormatArgs { + /// Write formats to file instead of just showing them + #[clap(long)] + pub write: bool, +} + +pub async fn run_format(arg: &FormatArgs) -> Result<()> { + let (resolved, _) = resolve_from_cwd(&Source::Local).await?; + // TODO: make this run in parallel + for definition in resolved { + let old_body = &definition.body; + let parsed = biome_grit_parser::parse_grit(old_body); + let path = &definition.config.path; + ensure!( + parsed.diagnostics().is_empty(), + "couldn't parse '{path}': {}", + parsed + .diagnostics() + .iter() + .map(|diag| diag.message.to_string()) + .collect::>() + .join("\n") + ); + + let options = GritFormatOptions::default(); + let doc = biome_grit_formatter::format_node(options, &parsed.syntax()) + .with_context(|| format!("couldn't format '{path}'"))?; + let doc_print = doc.print()?; + let new_body = doc_print.as_code(); + + if arg.write { + // TODO: i think there is already a rewriting feature that `apply` subcommand uses + // that i think can be re used here, look into it or at least + // use definition.config.range instead of replacing + let raw_data = definition.config.raw.as_ref().unwrap(); + tokio::fs::write(path, raw_data.content.replace(old_body, new_body)) + .await + .with_context(|| format!("could not write to file at '{path}'"))?; + } else { + println!( + "{}:\n{}", + definition.config.path, + format_diff(&definition.body, new_body) + ); + } + } + Ok(()) +} diff --git a/crates/cli/src/commands/mod.rs b/crates/cli/src/commands/mod.rs index 28874b433..d446d89a1 100644 --- a/crates/cli/src/commands/mod.rs +++ b/crates/cli/src/commands/mod.rs @@ -22,6 +22,7 @@ pub(crate) mod patterns_list; pub(crate) mod patterns_test; pub(crate) mod plumbing; pub(crate) mod version; +pub(crate) mod format; #[cfg(feature = "workflows_v2")] pub(crate) mod apply_migration; @@ -84,6 +85,7 @@ use indicatif_log_bridge::LogWrapper; use init::InitArgs; use install::InstallArgs; use list::ListArgs; +use format::{run_format, FormatArgs}; use log::LevelFilter; use lsp::LspArgs; use marzano_messenger::emit::ApplyDetails; @@ -164,6 +166,8 @@ pub enum Commands { Plumbing(PlumbingArgs), /// Display version information about the CLI and agents Version(VersionArgs), + /// Format files using patterns in current directory + Format(FormatArgs), /// Generate documentation for the Grit CLI (internal use only) #[cfg(feature = "docgen")] #[clap(hide = true)] @@ -204,6 +208,7 @@ impl fmt::Display for Commands { }, Commands::Plumbing(_) => write!(f, "plumbing"), Commands::Version(_) => write!(f, "version"), + Commands::Format(_) => write!(f, "format"), #[cfg(feature = "docgen")] Commands::Docgen(_) => write!(f, "docgen"), #[cfg(feature = "server")] @@ -439,6 +444,7 @@ async fn run_command(_use_tracing: bool) -> Result<()> { run_plumbing(arg, multi, &mut apply_details, app.format_flags).await } Commands::Version(arg) => run_version(arg).await, + Commands::Format(arg) => run_format(&arg).await, #[cfg(feature = "docgen")] Commands::Docgen(arg) => run_docgen(arg).await, #[cfg(feature = "server")] diff --git a/crates/cli/src/ux.rs b/crates/cli/src/ux.rs index 22a5ea80f..96b7007c6 100644 --- a/crates/cli/src/ux.rs +++ b/crates/cli/src/ux.rs @@ -125,7 +125,7 @@ impl fmt::Display for DiffString { } } -fn format_diff(expected: &str, actual: &str) -> DiffString { +pub fn format_diff(expected: &str, actual: &str) -> DiffString { let mut output = String::new(); let diff = TextDiff::from_lines(expected, actual); From 03d22b211512568b1d632315fbefcbc31de1a8d6 Mon Sep 17 00:00:00 2001 From: Arian Rezazadeh Date: Thu, 2 Jan 2025 12:06:16 +0330 Subject: [PATCH 02/31] refactor: move format for loop body to different function --- crates/cli/src/commands/format.rs | 78 +++++++++++++++++-------------- 1 file changed, 44 insertions(+), 34 deletions(-) diff --git a/crates/cli/src/commands/format.rs b/crates/cli/src/commands/format.rs index 400fcaa57..dece2a73b 100644 --- a/crates/cli/src/commands/format.rs +++ b/crates/cli/src/commands/format.rs @@ -5,6 +5,7 @@ use crate::{ use anyhow::{ensure, Context, Result}; use biome_grit_formatter::context::GritFormatOptions; use clap::Args; +use marzano_gritmodule::config::ResolvedGritDefinition; use serde::Serialize; #[derive(Args, Debug, Serialize)] @@ -16,43 +17,52 @@ pub struct FormatArgs { pub async fn run_format(arg: &FormatArgs) -> Result<()> { let (resolved, _) = resolve_from_cwd(&Source::Local).await?; - // TODO: make this run in parallel + // TODO: make this run in parallel, if needed for definition in resolved { - let old_body = &definition.body; - let parsed = biome_grit_parser::parse_grit(old_body); - let path = &definition.config.path; - ensure!( - parsed.diagnostics().is_empty(), - "couldn't parse '{path}': {}", - parsed - .diagnostics() - .iter() - .map(|diag| diag.message.to_string()) - .collect::>() - .join("\n") - ); + if let Err(error) = format_resolv(&definition, &arg).await { + eprintln!("couldn't format '{}': {error:?}", definition.config.path) + } + } + Ok(()) +} - let options = GritFormatOptions::default(); - let doc = biome_grit_formatter::format_node(options, &parsed.syntax()) - .with_context(|| format!("couldn't format '{path}'"))?; - let doc_print = doc.print()?; - let new_body = doc_print.as_code(); +async fn format_resolv(definition: &ResolvedGritDefinition, arg: &FormatArgs) -> Result<()> { + let old_body = &definition.body; + let parsed = biome_grit_parser::parse_grit(old_body); + ensure!( + parsed.diagnostics().is_empty(), + "biome couldn't parse: {}", + parsed + .diagnostics() + .iter() + .map(|diag| diag.message.to_string()) + .collect::>() + .join("\n") + ); - if arg.write { - // TODO: i think there is already a rewriting feature that `apply` subcommand uses - // that i think can be re used here, look into it or at least - // use definition.config.range instead of replacing - let raw_data = definition.config.raw.as_ref().unwrap(); - tokio::fs::write(path, raw_data.content.replace(old_body, new_body)) - .await - .with_context(|| format!("could not write to file at '{path}'"))?; - } else { - println!( - "{}:\n{}", - definition.config.path, - format_diff(&definition.body, new_body) - ); - } + let options = GritFormatOptions::default(); + let doc = biome_grit_formatter::format_node(options, &parsed.syntax()) + .with_context(|| "biome couldn't format")?; + let doc_print = doc.print()?; + let new_body = doc_print.as_code(); + + if arg.write { + // TODO: i think there is already a rewriting feature that `apply` subcommand uses + // that i think can be re used here, look into it or at least + // use definition.config.range instead of replacing + let raw_data = definition.config.raw.as_ref().unwrap(); + tokio::fs::write( + &definition.config.path, + raw_data.content.replace(old_body, new_body), + ) + .await + .with_context(|| "could not write to file")?; + } else { + println!( + "{}:\n{}", + definition.config.path, + format_diff(&definition.body, new_body) + ); } Ok(()) } From 7b49f637bb543de59590c1e8004462d86dfc162e Mon Sep 17 00:00:00 2001 From: Arian Rezazadeh Date: Thu, 2 Jan 2025 17:57:10 +0330 Subject: [PATCH 03/31] feat: add tests for markdown and grit files (yaml currently has issues) --- crates/cli/src/commands/format.rs | 27 ++++++--- .../.grit/grit.yaml.disabled | 11 ++++ .../.grit/patterns/aspect_ratio.md | 57 +++++++++++++++++++ .../.grit/patterns/dependency.grit | 19 +++++++ crates/cli_bin/tests/format.rs | 57 +++++++++++++++++++ .../snapshots/format__format_patterns.snap | 6 ++ .../format__format_patterns_with_rewrite.snap | 7 +++ 7 files changed, 175 insertions(+), 9 deletions(-) create mode 100644 crates/cli_bin/fixtures/unformatted_patterns/.grit/grit.yaml.disabled create mode 100644 crates/cli_bin/fixtures/unformatted_patterns/.grit/patterns/aspect_ratio.md create mode 100644 crates/cli_bin/fixtures/unformatted_patterns/.grit/patterns/dependency.grit create mode 100644 crates/cli_bin/tests/format.rs create mode 100644 crates/cli_bin/tests/snapshots/format__format_patterns.snap create mode 100644 crates/cli_bin/tests/snapshots/format__format_patterns_with_rewrite.snap diff --git a/crates/cli/src/commands/format.rs b/crates/cli/src/commands/format.rs index dece2a73b..2086a648e 100644 --- a/crates/cli/src/commands/format.rs +++ b/crates/cli/src/commands/format.rs @@ -16,8 +16,11 @@ pub struct FormatArgs { } pub async fn run_format(arg: &FormatArgs) -> Result<()> { - let (resolved, _) = resolve_from_cwd(&Source::Local).await?; - // TODO: make this run in parallel, if needed + let (mut resolved, _) = resolve_from_cwd(&Source::Local).await?; + // sort to have consistent output for tests + resolved.sort(); + + // TODO: do we need this to be runned in parallel? for definition in resolved { if let Err(error) = format_resolv(&definition, &arg).await { eprintln!("couldn't format '{}': {error:?}", definition.config.path) @@ -46,17 +49,23 @@ async fn format_resolv(definition: &ResolvedGritDefinition, arg: &FormatArgs) -> let doc_print = doc.print()?; let new_body = doc_print.as_code(); + // don't show any output when the file is already formatted + if old_body == new_body { + return Ok(()); + } + if arg.write { // TODO: i think there is already a rewriting feature that `apply` subcommand uses // that i think can be re used here, look into it or at least // use definition.config.range instead of replacing - let raw_data = definition.config.raw.as_ref().unwrap(); - tokio::fs::write( - &definition.config.path, - raw_data.content.replace(old_body, new_body), - ) - .await - .with_context(|| "could not write to file")?; + let content = if let Some(raw_data) = &definition.config.raw { + raw_data.content.clone() + } else { + old_body.clone() + }; + tokio::fs::write(&definition.config.path, content.replace(old_body, new_body)) + .await + .with_context(|| "could not write to file")?; } else { println!( "{}:\n{}", diff --git a/crates/cli_bin/fixtures/unformatted_patterns/.grit/grit.yaml.disabled b/crates/cli_bin/fixtures/unformatted_patterns/.grit/grit.yaml.disabled new file mode 100644 index 000000000..e512e0a69 --- /dev/null +++ b/crates/cli_bin/fixtures/unformatted_patterns/.grit/grit.yaml.disabled @@ -0,0 +1,11 @@ +version: 0.0.1 +patterns: + - name: aspect_ratio_yaml + description: Yaml version of aspect_ratio.md + body: | + language css + + `a { $props }` where { + $props <: contains `aspect-ratio: $x` + } + diff --git a/crates/cli_bin/fixtures/unformatted_patterns/.grit/patterns/aspect_ratio.md b/crates/cli_bin/fixtures/unformatted_patterns/.grit/patterns/aspect_ratio.md new file mode 100644 index 000000000..99d39f5b9 --- /dev/null +++ b/crates/cli_bin/fixtures/unformatted_patterns/.grit/patterns/aspect_ratio.md @@ -0,0 +1,57 @@ +--- +title: Aspect ratio +--- + +```grit +language css + +`a { $props }` where { + $props <: contains `aspect-ratio: $x` +} +``` + +## Matches the right selector and declaration block + +```css +a { + width: calc(100% - 80px); + aspect-ratio: 1/2; + font-size: calc(10px + (56 - 10) * ((100vw - 320px) / (1920 - 320))); +} + +#some-id { + some-property: 5px; +} + +a.b ~ c.d { +} +.e.f + .g.h { +} + +@font-face { + font-family: 'Open Sans'; + src: url('/a') format('woff2'), url('/b/c') format('woff'); +} +``` + +```css +a { + width: calc(100% - 80px); + aspect-ratio: 1/2; + font-size: calc(10px + (56 - 10) * ((100vw - 320px) / (1920 - 320))); +} + +#some-id { + some-property: 5px; +} + +a.b ~ c.d { +} +.e.f + .g.h { +} + +@font-face { + font-family: 'Open Sans'; + src: url('/a') format('woff2'), url('/b/c') format('woff'); +} +``` diff --git a/crates/cli_bin/fixtures/unformatted_patterns/.grit/patterns/dependency.grit b/crates/cli_bin/fixtures/unformatted_patterns/.grit/patterns/dependency.grit new file mode 100644 index 000000000..961b9188c --- /dev/null +++ b/crates/cli_bin/fixtures/unformatted_patterns/.grit/patterns/dependency.grit @@ -0,0 +1,19 @@ +language json + +pattern upgrade_dependency($target_dep, $target_version, $dependency_key) { + or { + `$key: $value` where { + $key <: `"$target_dep"`, + $value => `"$target_version"` + }, + pair($key, $value) where { + $key <: `"$dependency_key"`, + $value <: object($properties) where { + $properties <: not contains pair(key=$dep_key) where { + $dep_key <: contains `$target_dep` + }, + $properties => `"$target_dep": "$target_version",\n$properties` + } + } + } +} diff --git a/crates/cli_bin/tests/format.rs b/crates/cli_bin/tests/format.rs new file mode 100644 index 000000000..fb9dff94d --- /dev/null +++ b/crates/cli_bin/tests/format.rs @@ -0,0 +1,57 @@ +use crate::common::get_test_cmd; +use anyhow::Result; +use common::get_fixture; +use insta::assert_yaml_snapshot; + +mod common; + +#[test] +fn format_patterns() -> Result<()> { + let (_temp_dir, grit_dir) = get_fixture("unformatted_patterns", true)?; + + let mut cmd = get_test_cmd()?; + cmd.arg("format").current_dir(grit_dir.clone()); + let output = cmd.output()?; + + println!("stderr: {}", String::from_utf8(output.stderr.clone())?); + println!("stdout: {}", String::from_utf8(output.stdout.clone())?); + + assert!( + output.status.success(), + "Command didn't finish successfully" + ); + assert_yaml_snapshot!(String::from_utf8(output.stdout)?); + Ok(()) +} + +#[test] +fn format_patterns_with_rewrite() -> Result<()> { + let (_temp_dir, grit_dir) = get_fixture("unformatted_patterns", true)?; + + let mut cmd = get_test_cmd()?; + cmd.arg("format") + .arg("--write") + .current_dir(grit_dir.clone()); + let output = cmd.output()?; + + println!("stderr: {}", String::from_utf8(output.stderr.clone())?); + println!("stdout: {}", String::from_utf8(output.stdout.clone())?); + + assert!(output.stdout.is_empty()); + assert!( + output.status.success(), + "Command didn't finish successfully" + ); + + // let aspect_ratio_yaml_file_content = std::fs::read_to_string(grit_dir.join(".grit/grit.yaml"))?; + let aspect_ratio_md_file_content = + std::fs::read_to_string(grit_dir.join(".grit/patterns/aspect_ratio.md"))?; + let dependency_grit_file_content = + std::fs::read_to_string(grit_dir.join(".grit/patterns/dependency.grit"))?; + assert_yaml_snapshot!(vec![ + // aspect_ratio_yaml_file_content, + aspect_ratio_md_file_content, + dependency_grit_file_content + ]); + Ok(()) +} diff --git a/crates/cli_bin/tests/snapshots/format__format_patterns.snap b/crates/cli_bin/tests/snapshots/format__format_patterns.snap new file mode 100644 index 000000000..73a2df283 --- /dev/null +++ b/crates/cli_bin/tests/snapshots/format__format_patterns.snap @@ -0,0 +1,6 @@ +--- +source: crates/cli_bin/tests/format.rs +expression: "String::from_utf8(output.stdout)?" +snapshot_kind: text +--- +".grit/patterns/aspect_ratio.md:\n -language css\n -\n -`a { $props }` where {\n - $props <: contains `aspect-ratio: $x`\n -}\n +language css;\n +`a { $props }` where { $props <: contains `aspect-ratio: $x` }\n \n\n.grit/patterns/dependency.grit:\n -language json\n -\n +language json;\n pattern upgrade_dependency($target_dep, $target_version, $dependency_key) {\n - or {\n - `$key: $value` where {\n - $key <: `\"$target_dep\"`,\n - $value => `\"$target_version\"`\n - },\n - pair($key, $value) where {\n - $key <: `\"$dependency_key\"`,\n - $value <: object($properties) where {\n - $properties <: not contains pair(key=$dep_key) where {\n - $dep_key <: contains `$target_dep`\n - },\n - $properties => `\"$target_dep\": \"$target_version\",\\n$properties`\n - }\n - }\n - }\n -}\n +\tor {\n +\t\t`$key: $value` where {\n +\t\t\t$key <: `\"$target_dep\"`,\n +\t\t\t$value => `\"$target_version\"`\n +\t\t},\n +\t\tpair($key, $value) where {\n +\t\t\t$key <: `\"$dependency_key\"`,\n +\t\t\t$value <: object($properties) where {\n +\t\t\t\t$properties <: notcontains pair(key = $dep_key) where {\n +\t\t\t\t\t$dep_key <: contains `$target_dep`\n +\t\t\t\t},\n +\t\t\t\t$properties => `\"$target_dep\": \"$target_version\",\\n$properties`\n +\t\t\t}\n +\t\t}\n +\t}}\n \n\n" diff --git a/crates/cli_bin/tests/snapshots/format__format_patterns_with_rewrite.snap b/crates/cli_bin/tests/snapshots/format__format_patterns_with_rewrite.snap new file mode 100644 index 000000000..8a0ad2986 --- /dev/null +++ b/crates/cli_bin/tests/snapshots/format__format_patterns_with_rewrite.snap @@ -0,0 +1,7 @@ +--- +source: crates/cli_bin/tests/format.rs +expression: "vec![aspect_ratio_md_file_content, dependency_grit_file_content]" +snapshot_kind: text +--- +- "---\ntitle: Aspect ratio\n---\n\n```grit\nlanguage css;\n`a { $props }` where { $props <: contains `aspect-ratio: $x` }\n```\n\n## Matches the right selector and declaration block\n\n```css\na {\n width: calc(100% - 80px);\n aspect-ratio: 1/2;\n font-size: calc(10px + (56 - 10) * ((100vw - 320px) / (1920 - 320)));\n}\n\n#some-id {\n some-property: 5px;\n}\n\na.b ~ c.d {\n}\n.e.f + .g.h {\n}\n\n@font-face {\n font-family: 'Open Sans';\n src: url('/a') format('woff2'), url('/b/c') format('woff');\n}\n```\n\n```css\na {\n width: calc(100% - 80px);\n aspect-ratio: 1/2;\n font-size: calc(10px + (56 - 10) * ((100vw - 320px) / (1920 - 320)));\n}\n\n#some-id {\n some-property: 5px;\n}\n\na.b ~ c.d {\n}\n.e.f + .g.h {\n}\n\n@font-face {\n font-family: 'Open Sans';\n src: url('/a') format('woff2'), url('/b/c') format('woff');\n}\n```\n" +- "language json;\npattern upgrade_dependency($target_dep, $target_version, $dependency_key) {\n\tor {\n\t\t`$key: $value` where {\n\t\t\t$key <: `\"$target_dep\"`,\n\t\t\t$value => `\"$target_version\"`\n\t\t},\n\t\tpair($key, $value) where {\n\t\t\t$key <: `\"$dependency_key\"`,\n\t\t\t$value <: object($properties) where {\n\t\t\t\t$properties <: notcontains pair(key = $dep_key) where {\n\t\t\t\t\t$dep_key <: contains `$target_dep`\n\t\t\t\t},\n\t\t\t\t$properties => `\"$target_dep\": \"$target_version\",\\n$properties`\n\t\t\t}\n\t\t}\n\t}}\n\n" From fc431ec60bc1c11930ef05d42f25d5308dfab707 Mon Sep 17 00:00:00 2001 From: Arian Rezazadeh Date: Thu, 2 Jan 2025 21:09:15 +0330 Subject: [PATCH 04/31] feat: add yaml support --- crates/cli/src/commands/format.rs | 82 ++++++++++++------- .../.grit/{grit.yaml.disabled => grit.yaml} | 1 + .../.grit/others/test_move_import.md | 11 +++ crates/cli_bin/tests/format.rs | 7 +- .../snapshots/format__format_patterns.snap | 2 +- .../format__format_patterns_with_rewrite.snap | 6 +- crates/gritmodule/src/yaml.rs | 14 ++-- 7 files changed, 84 insertions(+), 39 deletions(-) rename crates/cli_bin/fixtures/unformatted_patterns/.grit/{grit.yaml.disabled => grit.yaml} (84%) create mode 100644 crates/cli_bin/fixtures/unformatted_patterns/.grit/others/test_move_import.md diff --git a/crates/cli/src/commands/format.rs b/crates/cli/src/commands/format.rs index 2086a648e..7c63a0c8d 100644 --- a/crates/cli/src/commands/format.rs +++ b/crates/cli/src/commands/format.rs @@ -5,7 +5,7 @@ use crate::{ use anyhow::{ensure, Context, Result}; use biome_grit_formatter::context::GritFormatOptions; use clap::Args; -use marzano_gritmodule::config::ResolvedGritDefinition; +use marzano_gritmodule::{config::ResolvedGritDefinition, parser::PatternFileExt}; use serde::Serialize; #[derive(Args, Debug, Serialize)] @@ -30,48 +30,72 @@ pub async fn run_format(arg: &FormatArgs) -> Result<()> { } async fn format_resolv(definition: &ResolvedGritDefinition, arg: &FormatArgs) -> Result<()> { - let old_body = &definition.body; - let parsed = biome_grit_parser::parse_grit(old_body); - ensure!( - parsed.diagnostics().is_empty(), - "biome couldn't parse: {}", - parsed - .diagnostics() - .iter() - .map(|diag| diag.message.to_string()) - .collect::>() - .join("\n") - ); - - let options = GritFormatOptions::default(); - let doc = biome_grit_formatter::format_node(options, &parsed.syntax()) - .with_context(|| "biome couldn't format")?; - let doc_print = doc.print()?; - let new_body = doc_print.as_code(); - - // don't show any output when the file is already formatted - if old_body == new_body { + let mut unformatted_grit_code = definition.body.clone(); + let mut formatted_grit_code = format_grit_code(&unformatted_grit_code)?; + if unformatted_grit_code == formatted_grit_code { return Ok(()); } + let file_content = if let Some(raw_data) = &definition.config.raw { + // TODO: find a better way to do this + if raw_data.format == PatternFileExt::Yaml { + formatted_grit_code = grit_code_with_yaml_indent(&formatted_grit_code); + unformatted_grit_code = grit_code_with_yaml_indent(&unformatted_grit_code); + } + raw_data.content.clone() + } else { + unformatted_grit_code.clone() + }; + let new_file_content = file_content.replace(&unformatted_grit_code, &formatted_grit_code); + ensure!(file_content != new_file_content); + if arg.write { // TODO: i think there is already a rewriting feature that `apply` subcommand uses // that i think can be re used here, look into it or at least // use definition.config.range instead of replacing - let content = if let Some(raw_data) = &definition.config.raw { - raw_data.content.clone() - } else { - old_body.clone() - }; - tokio::fs::write(&definition.config.path, content.replace(old_body, new_body)) + tokio::fs::write(&definition.config.path, new_file_content) .await .with_context(|| "could not write to file")?; } else { println!( "{}:\n{}", definition.config.path, - format_diff(&definition.body, new_body) + format_diff(&file_content, &new_file_content) ); } Ok(()) } + +fn format_grit_code(source: &str) -> Result { + let parsed = biome_grit_parser::parse_grit(source); + ensure!( + parsed.diagnostics().is_empty(), + "biome couldn't parse: {}", + parsed + .diagnostics() + .iter() + .map(|diag| diag.message.to_string()) + .collect::>() + .join("\n") + ); + + let options = GritFormatOptions::default(); + let doc = biome_grit_formatter::format_node(options, &parsed.syntax()) + .with_context(|| "biome couldn't format")?; + let doc_print = doc.print()?; + Ok(doc_print.into_code()) +} + +fn grit_code_with_yaml_indent(grit_code: &str) -> String { + grit_code + .lines() + .map(|line| { + if !line.is_empty() { + format!(" {line}") + } else { + line.to_owned() + } + }) + .collect::>() + .join("\n") +} diff --git a/crates/cli_bin/fixtures/unformatted_patterns/.grit/grit.yaml.disabled b/crates/cli_bin/fixtures/unformatted_patterns/.grit/grit.yaml similarity index 84% rename from crates/cli_bin/fixtures/unformatted_patterns/.grit/grit.yaml.disabled rename to crates/cli_bin/fixtures/unformatted_patterns/.grit/grit.yaml index e512e0a69..e85ad7894 100644 --- a/crates/cli_bin/fixtures/unformatted_patterns/.grit/grit.yaml.disabled +++ b/crates/cli_bin/fixtures/unformatted_patterns/.grit/grit.yaml @@ -9,3 +9,4 @@ patterns: $props <: contains `aspect-ratio: $x` } + - file: ./others/test_move_import.md diff --git a/crates/cli_bin/fixtures/unformatted_patterns/.grit/others/test_move_import.md b/crates/cli_bin/fixtures/unformatted_patterns/.grit/others/test_move_import.md new file mode 100644 index 000000000..91c95f650 --- /dev/null +++ b/crates/cli_bin/fixtures/unformatted_patterns/.grit/others/test_move_import.md @@ -0,0 +1,11 @@ +--- +private: true +tags: [private] +--- +```grit +language js + +`sanitizeFilePath` as $s where { + move_import(`sanitizeFilePath`, `'@getgrit/universal'`) +} +``` diff --git a/crates/cli_bin/tests/format.rs b/crates/cli_bin/tests/format.rs index fb9dff94d..4bef9aa33 100644 --- a/crates/cli_bin/tests/format.rs +++ b/crates/cli_bin/tests/format.rs @@ -43,13 +43,16 @@ fn format_patterns_with_rewrite() -> Result<()> { "Command didn't finish successfully" ); - // let aspect_ratio_yaml_file_content = std::fs::read_to_string(grit_dir.join(".grit/grit.yaml"))?; + let yaml_file_content = std::fs::read_to_string(grit_dir.join(".grit/grit.yaml"))?; + let test_move_import_file_content = + std::fs::read_to_string(grit_dir.join(".grit/others/test_move_import.md"))?; let aspect_ratio_md_file_content = std::fs::read_to_string(grit_dir.join(".grit/patterns/aspect_ratio.md"))?; let dependency_grit_file_content = std::fs::read_to_string(grit_dir.join(".grit/patterns/dependency.grit"))?; assert_yaml_snapshot!(vec![ - // aspect_ratio_yaml_file_content, + yaml_file_content, + test_move_import_file_content, aspect_ratio_md_file_content, dependency_grit_file_content ]); diff --git a/crates/cli_bin/tests/snapshots/format__format_patterns.snap b/crates/cli_bin/tests/snapshots/format__format_patterns.snap index 73a2df283..a5e157fc5 100644 --- a/crates/cli_bin/tests/snapshots/format__format_patterns.snap +++ b/crates/cli_bin/tests/snapshots/format__format_patterns.snap @@ -3,4 +3,4 @@ source: crates/cli_bin/tests/format.rs expression: "String::from_utf8(output.stdout)?" snapshot_kind: text --- -".grit/patterns/aspect_ratio.md:\n -language css\n -\n -`a { $props }` where {\n - $props <: contains `aspect-ratio: $x`\n -}\n +language css;\n +`a { $props }` where { $props <: contains `aspect-ratio: $x` }\n \n\n.grit/patterns/dependency.grit:\n -language json\n -\n +language json;\n pattern upgrade_dependency($target_dep, $target_version, $dependency_key) {\n - or {\n - `$key: $value` where {\n - $key <: `\"$target_dep\"`,\n - $value => `\"$target_version\"`\n - },\n - pair($key, $value) where {\n - $key <: `\"$dependency_key\"`,\n - $value <: object($properties) where {\n - $properties <: not contains pair(key=$dep_key) where {\n - $dep_key <: contains `$target_dep`\n - },\n - $properties => `\"$target_dep\": \"$target_version\",\\n$properties`\n - }\n - }\n - }\n -}\n +\tor {\n +\t\t`$key: $value` where {\n +\t\t\t$key <: `\"$target_dep\"`,\n +\t\t\t$value => `\"$target_version\"`\n +\t\t},\n +\t\tpair($key, $value) where {\n +\t\t\t$key <: `\"$dependency_key\"`,\n +\t\t\t$value <: object($properties) where {\n +\t\t\t\t$properties <: notcontains pair(key = $dep_key) where {\n +\t\t\t\t\t$dep_key <: contains `$target_dep`\n +\t\t\t\t},\n +\t\t\t\t$properties => `\"$target_dep\": \"$target_version\",\\n$properties`\n +\t\t\t}\n +\t\t}\n +\t}}\n \n\n" +".grit/patterns/aspect_ratio.md:\n ---\n \n ```grit\n -language css\n -\n -`a { $props }` where {\n - $props <: contains `aspect-ratio: $x`\n -}\n +language css;\n +`a { $props }` where { $props <: contains `aspect-ratio: $x` }\n ```\n \n ## Matches the right selector and declaration block\n \n\n.grit/grit.yaml:\n - name: aspect_ratio_yaml\n description: Yaml version of aspect_ratio.md\n body: |\n - language css\n -\n - `a { $props }` where {\n - $props <: contains `aspect-ratio: $x`\n - }\n + language css;\n + `a { $props }` where { $props <: contains `aspect-ratio: $x` }\n \n - file: ./others/test_move_import.md\n \n\n.grit/./others/test_move_import.md:\n tags: [private]\n ---\n ```grit\n -language js\n -\n +language js;\n `sanitizeFilePath` as $s where {\n - move_import(`sanitizeFilePath`, `'@getgrit/universal'`)\n +\tmove_import(`sanitizeFilePath`, `'@getgrit/universal'`)\n }\n ```\n \n\n.grit/patterns/dependency.grit:\n -language json\n -\n +language json;\n pattern upgrade_dependency($target_dep, $target_version, $dependency_key) {\n - or {\n - `$key: $value` where {\n - $key <: `\"$target_dep\"`,\n - $value => `\"$target_version\"`\n - },\n - pair($key, $value) where {\n - $key <: `\"$dependency_key\"`,\n - $value <: object($properties) where {\n - $properties <: not contains pair(key=$dep_key) where {\n - $dep_key <: contains `$target_dep`\n - },\n - $properties => `\"$target_dep\": \"$target_version\",\\n$properties`\n - }\n - }\n - }\n -}\n +\tor {\n +\t\t`$key: $value` where {\n +\t\t\t$key <: `\"$target_dep\"`,\n +\t\t\t$value => `\"$target_version\"`\n +\t\t},\n +\t\tpair($key, $value) where {\n +\t\t\t$key <: `\"$dependency_key\"`,\n +\t\t\t$value <: object($properties) where {\n +\t\t\t\t$properties <: notcontains pair(key = $dep_key) where {\n +\t\t\t\t\t$dep_key <: contains `$target_dep`\n +\t\t\t\t},\n +\t\t\t\t$properties => `\"$target_dep\": \"$target_version\",\\n$properties`\n +\t\t\t}\n +\t\t}\n +\t}}\n \n\n" diff --git a/crates/cli_bin/tests/snapshots/format__format_patterns_with_rewrite.snap b/crates/cli_bin/tests/snapshots/format__format_patterns_with_rewrite.snap index 8a0ad2986..246aebb5c 100644 --- a/crates/cli_bin/tests/snapshots/format__format_patterns_with_rewrite.snap +++ b/crates/cli_bin/tests/snapshots/format__format_patterns_with_rewrite.snap @@ -1,7 +1,9 @@ --- source: crates/cli_bin/tests/format.rs -expression: "vec![aspect_ratio_md_file_content, dependency_grit_file_content]" +expression: "vec![yaml_file_content, test_move_import_file_content,\naspect_ratio_md_file_content, dependency_grit_file_content]" snapshot_kind: text --- +- "version: 0.0.1\npatterns:\n - name: aspect_ratio_yaml\n description: Yaml version of aspect_ratio.md\n body: |\n language css;\n `a { $props }` where { $props <: contains `aspect-ratio: $x` }\n\n - file: ./others/test_move_import.md\n" +- "---\nprivate: true\ntags: [private]\n---\n```grit\nlanguage js;\n`sanitizeFilePath` as $s where {\n\tmove_import(`sanitizeFilePath`, `'@getgrit/universal'`)\n}\n```\n" - "---\ntitle: Aspect ratio\n---\n\n```grit\nlanguage css;\n`a { $props }` where { $props <: contains `aspect-ratio: $x` }\n```\n\n## Matches the right selector and declaration block\n\n```css\na {\n width: calc(100% - 80px);\n aspect-ratio: 1/2;\n font-size: calc(10px + (56 - 10) * ((100vw - 320px) / (1920 - 320)));\n}\n\n#some-id {\n some-property: 5px;\n}\n\na.b ~ c.d {\n}\n.e.f + .g.h {\n}\n\n@font-face {\n font-family: 'Open Sans';\n src: url('/a') format('woff2'), url('/b/c') format('woff');\n}\n```\n\n```css\na {\n width: calc(100% - 80px);\n aspect-ratio: 1/2;\n font-size: calc(10px + (56 - 10) * ((100vw - 320px) / (1920 - 320)));\n}\n\n#some-id {\n some-property: 5px;\n}\n\na.b ~ c.d {\n}\n.e.f + .g.h {\n}\n\n@font-face {\n font-family: 'Open Sans';\n src: url('/a') format('woff2'), url('/b/c') format('woff');\n}\n```\n" -- "language json;\npattern upgrade_dependency($target_dep, $target_version, $dependency_key) {\n\tor {\n\t\t`$key: $value` where {\n\t\t\t$key <: `\"$target_dep\"`,\n\t\t\t$value => `\"$target_version\"`\n\t\t},\n\t\tpair($key, $value) where {\n\t\t\t$key <: `\"$dependency_key\"`,\n\t\t\t$value <: object($properties) where {\n\t\t\t\t$properties <: notcontains pair(key = $dep_key) where {\n\t\t\t\t\t$dep_key <: contains `$target_dep`\n\t\t\t\t},\n\t\t\t\t$properties => `\"$target_dep\": \"$target_version\",\\n$properties`\n\t\t\t}\n\t\t}\n\t}}\n\n" +- "language json;\npattern upgrade_dependency($target_dep, $target_version, $dependency_key) {\n\tor {\n\t\t`$key: $value` where {\n\t\t\t$key <: `\"$target_dep\"`,\n\t\t\t$value => `\"$target_version\"`\n\t\t},\n\t\tpair($key, $value) where {\n\t\t\t$key <: `\"$dependency_key\"`,\n\t\t\t$value <: object($properties) where {\n\t\t\t\t$properties <: notcontains pair(key = $dep_key) where {\n\t\t\t\t\t$dep_key <: contains `$target_dep`\n\t\t\t\t},\n\t\t\t\t$properties => `\"$target_dep\": \"$target_version\",\\n$properties`\n\t\t\t}\n\t\t}\n\t}}\n" diff --git a/crates/gritmodule/src/yaml.rs b/crates/gritmodule/src/yaml.rs index cfc6f6f37..86cc9586f 100644 --- a/crates/gritmodule/src/yaml.rs +++ b/crates/gritmodule/src/yaml.rs @@ -11,7 +11,8 @@ use tokio::fs; use crate::{ config::{ pattern_config_to_model, DefinitionKind, GritConfig, GritDefinitionConfig, - ModuleGritPattern, SerializedGritConfig, CONFIG_FILE_NAMES, REPO_CONFIG_DIR_NAME, + ModuleGritPattern, RawGritDefinition, SerializedGritConfig, CONFIG_FILE_NAMES, + REPO_CONFIG_DIR_NAME, }, fetcher::ModuleRepo, parser::{extract_relative_file_path, get_patterns_from_file, PatternFileExt}, @@ -38,10 +39,13 @@ pub fn get_grit_config(source: &str, source_path: &str) -> Result { pattern_files.push(file); } crate::config::GritPatternConfig::Pattern(p) => { - patterns.push(GritDefinitionConfig::from_serialized( - p, - source_path.to_string(), - )); + let mut definitation = + GritDefinitionConfig::from_serialized(p, source_path.to_string()); + definitation.raw = Some(RawGritDefinition { + content: source.to_owned(), + format: crate::parser::PatternFileExt::Yaml, + }); + patterns.push(definitation); } } } From 7f767a4ec923ea0701e9e05551390a223b6c263e Mon Sep 17 00:00:00 2001 From: Arian Rezazadeh Date: Thu, 2 Jan 2025 21:15:06 +0330 Subject: [PATCH 05/31] feat: make file path bold in print --- crates/cli/src/commands/format.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/cli/src/commands/format.rs b/crates/cli/src/commands/format.rs index 7c63a0c8d..9133c6669 100644 --- a/crates/cli/src/commands/format.rs +++ b/crates/cli/src/commands/format.rs @@ -5,6 +5,7 @@ use crate::{ use anyhow::{ensure, Context, Result}; use biome_grit_formatter::context::GritFormatOptions; use clap::Args; +use colored::Colorize; use marzano_gritmodule::{config::ResolvedGritDefinition, parser::PatternFileExt}; use serde::Serialize; @@ -59,7 +60,7 @@ async fn format_resolv(definition: &ResolvedGritDefinition, arg: &FormatArgs) -> } else { println!( "{}:\n{}", - definition.config.path, + definition.config.path.bold(), format_diff(&file_content, &new_file_content) ); } From 3b0de9e805906c5a35b98de8dad950c5a09b9b24 Mon Sep 17 00:00:00 2001 From: Arian Rezazadeh Date: Fri, 3 Jan 2025 09:33:56 +0330 Subject: [PATCH 06/31] feat: change format command help message --- crates/cli/src/commands/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/cli/src/commands/mod.rs b/crates/cli/src/commands/mod.rs index d446d89a1..4e8a7c5bd 100644 --- a/crates/cli/src/commands/mod.rs +++ b/crates/cli/src/commands/mod.rs @@ -166,7 +166,7 @@ pub enum Commands { Plumbing(PlumbingArgs), /// Display version information about the CLI and agents Version(VersionArgs), - /// Format files using patterns in current directory + /// Format grit files under current directory Format(FormatArgs), /// Generate documentation for the Grit CLI (internal use only) #[cfg(feature = "docgen")] From 5761689af1962bd1de3c768793829341c19a2cde Mon Sep 17 00:00:00 2001 From: Arian Rezazadeh Date: Fri, 3 Jan 2025 10:03:16 +0330 Subject: [PATCH 07/31] refactor: better explanation of grit_code_with_yaml_indent --- crates/cli/src/commands/format.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/crates/cli/src/commands/format.rs b/crates/cli/src/commands/format.rs index 9133c6669..b32a713bb 100644 --- a/crates/cli/src/commands/format.rs +++ b/crates/cli/src/commands/format.rs @@ -9,6 +9,21 @@ use colored::Colorize; use marzano_gritmodule::{config::ResolvedGritDefinition, parser::PatternFileExt}; use serde::Serialize; +/// Specifies amount of indent that consumed to get to grit body in yaml files +// Yaml files that contains grit body are like this: +// ```yaml +// patterns: +// - name: some_name +// body: | +// language css +// +// `a { $props }` where { +// $props <: contains `aspect-ratio: $x` +// } +// ``` +// the grit body is prefixed by some amount of spaces due to yaml format +const YAML_GRIT_BODY_INDENT_SIZE: usize = 6; + #[derive(Args, Debug, Serialize)] pub struct FormatArgs { /// Write formats to file instead of just showing them @@ -88,11 +103,12 @@ fn format_grit_code(source: &str) -> Result { } fn grit_code_with_yaml_indent(grit_code: &str) -> String { + let indent = " ".repeat(YAML_GRIT_BODY_INDENT_SIZE); grit_code .lines() .map(|line| { if !line.is_empty() { - format!(" {line}") + format!("{indent}{line}") } else { line.to_owned() } From 203de807ba27f3cf82424f3878fdecc750cc1af0 Mon Sep 17 00:00:00 2001 From: Arian Rezazadeh Date: Fri, 3 Jan 2025 16:37:32 +0330 Subject: [PATCH 08/31] refactor: rewrite file using hunks instead of find and replace --- crates/cli/src/commands/format.rs | 128 +++++++++++++++++++++++------- crates/gritmodule/src/dot_grit.rs | 20 +++-- 2 files changed, 112 insertions(+), 36 deletions(-) diff --git a/crates/cli/src/commands/format.rs b/crates/cli/src/commands/format.rs index b32a713bb..643c4149a 100644 --- a/crates/cli/src/commands/format.rs +++ b/crates/cli/src/commands/format.rs @@ -2,12 +2,13 @@ use crate::{ resolver::{resolve_from_cwd, Source}, ux::format_diff, }; -use anyhow::{ensure, Context, Result}; +use anyhow::{anyhow, ensure, Context, Result}; use biome_grit_formatter::context::GritFormatOptions; use clap::Args; use colored::Colorize; use marzano_gritmodule::{config::ResolvedGritDefinition, parser::PatternFileExt}; use serde::Serialize; +use std::collections::HashMap; /// Specifies amount of indent that consumed to get to grit body in yaml files // Yaml files that contains grit body are like this: @@ -24,7 +25,7 @@ use serde::Serialize; // the grit body is prefixed by some amount of spaces due to yaml format const YAML_GRIT_BODY_INDENT_SIZE: usize = 6; -#[derive(Args, Debug, Serialize)] +#[derive(Args, Debug, Serialize, Clone)] pub struct FormatArgs { /// Write formats to file instead of just showing them #[clap(long)] @@ -36,52 +37,95 @@ pub async fn run_format(arg: &FormatArgs) -> Result<()> { // sort to have consistent output for tests resolved.sort(); + // we process each file resolves separetly because we want + // to write to file once and also fix the bugs that may happen when + // overwriting same file multiple times for different patterns + let file_path_to_resolves: HashMap> = resolved + .into_iter() + .fold(HashMap::new(), |mut acc, resolved| { + let file_path = resolved.config.path.clone(); + acc.entry(file_path).or_insert_with(Vec::new).push(resolved); + acc + }); + // TODO: do we need this to be runned in parallel? - for definition in resolved { - if let Err(error) = format_resolv(&definition, &arg).await { - eprintln!("couldn't format '{}': {error:?}", definition.config.path) + for (file_path, definitions) in file_path_to_resolves { + if let Err(error) = + format_file_definitations(file_path.clone(), definitions, arg.clone()).await + { + eprintln!("couldn't format '{}': {error:?}", file_path) } } Ok(()) } -async fn format_resolv(definition: &ResolvedGritDefinition, arg: &FormatArgs) -> Result<()> { - let mut unformatted_grit_code = definition.body.clone(); - let mut formatted_grit_code = format_grit_code(&unformatted_grit_code)?; - if unformatted_grit_code == formatted_grit_code { +async fn format_file_definitations( + file_path: String, + definitions: Vec, + arg: FormatArgs, +) -> Result<()> { + let hunks = definitions + .iter() + .map(|definition| definitation_to_hunk(definition)) + .collect::>>()?; + + let first_definitation = definitions.first().unwrap(); + let first_definitation_raw_config = first_definitation.config.raw.as_ref().unwrap(); + let old_file_content = &first_definitation_raw_config.content; + let new_file_content = apply_hunk_changes(&old_file_content, hunks); + + if &new_file_content == old_file_content { return Ok(()); } - let file_content = if let Some(raw_data) = &definition.config.raw { - // TODO: find a better way to do this - if raw_data.format == PatternFileExt::Yaml { - formatted_grit_code = grit_code_with_yaml_indent(&formatted_grit_code); - unformatted_grit_code = grit_code_with_yaml_indent(&unformatted_grit_code); - } - raw_data.content.clone() - } else { - unformatted_grit_code.clone() - }; - let new_file_content = file_content.replace(&unformatted_grit_code, &formatted_grit_code); - ensure!(file_content != new_file_content); - if arg.write { - // TODO: i think there is already a rewriting feature that `apply` subcommand uses - // that i think can be re used here, look into it or at least - // use definition.config.range instead of replacing - tokio::fs::write(&definition.config.path, new_file_content) + tokio::fs::write(file_path, new_file_content) .await .with_context(|| "could not write to file")?; } else { println!( "{}:\n{}", - definition.config.path.bold(), - format_diff(&file_content, &new_file_content) + file_path.bold(), + format_diff(&old_file_content, &new_file_content) ); } + Ok(()) } +fn definitation_to_hunk(definition: &ResolvedGritDefinition) -> Result { + let unformatted_grit_code = &definition.body; + let mut formatted_grit_code = format_grit_code(unformatted_grit_code)?; + + let raw_data = definition + .config + .raw + .as_ref() + .ok_or_else(|| anyhow!("definition doesn't have raw_data"))?; + let body_range = definition + .config + .range + .as_ref() + .ok_or_else(|| anyhow!("definition doesn't have config range"))?; + + if raw_data.format == PatternFileExt::Grit { + // TODO: fix langauge line not getting formatted + // this needed because we add additional "language {}\n\n" to body when parsing .grit file + if formatted_grit_code.starts_with("language ") { + let formatted_lines = formatted_grit_code.lines(); + formatted_grit_code = formatted_lines.skip(1).collect::>().join("\n"); + } + } + println!("range: {:?}", body_range); + + Ok(HunkChange { + starting_byte: body_range.start_byte as usize, + ending_byte: body_range.end_byte as usize, + new_content: formatted_grit_code, + }) +} + +/// format grit code using `biome` fn format_grit_code(source: &str) -> Result { let parsed = biome_grit_parser::parse_grit(source); ensure!( @@ -116,3 +160,31 @@ fn grit_code_with_yaml_indent(grit_code: &str) -> String { .collect::>() .join("\n") } + +/// Represent a hunk of text that needs to be changed +#[derive(Debug)] +struct HunkChange { + starting_byte: usize, + ending_byte: usize, + new_content: String, +} + +/// returns a new string that applies hunk changes +fn apply_hunk_changes(input: &str, mut hunks: Vec) -> String { + if hunks.is_empty() { + return input.to_string(); + } + hunks.sort_by_key(|hunk| hunk.starting_byte); + let mut buffer = String::new(); + let mut last_ending_byte = 0; + for (index, hunk) in hunks.iter().enumerate() { + buffer.push_str(&input[last_ending_byte..hunk.starting_byte]); + buffer.push_str(&hunk.new_content); + last_ending_byte = hunk.ending_byte; + + if index == hunks.len() - 1 { + buffer.push_str(&input[last_ending_byte..]); + } + } + buffer +} diff --git a/crates/gritmodule/src/dot_grit.rs b/crates/gritmodule/src/dot_grit.rs index 13673647d..de44d247e 100644 --- a/crates/gritmodule/src/dot_grit.rs +++ b/crates/gritmodule/src/dot_grit.rs @@ -1,10 +1,10 @@ use crate::{ config::{ DefinitionKind, GritDefinitionConfig, GritPatternMetadata, ModuleGritPattern, - PatternVisibility, + PatternVisibility, RawGritDefinition, }, fetcher::ModuleRepo, - parser::extract_relative_file_path, + parser::{extract_relative_file_path, PatternFileExt}, }; use anyhow::{anyhow, bail, Result}; use grit_util::{Ast, AstNode, Position, Range}; @@ -61,15 +61,15 @@ pub fn get_patterns_from_grit( }; let range = Range::new( Position::new( - name_node.node.start_position().row() + 1, - name_node.node.start_position().column() + 1, + pattern_definition.node.start_position().row() + 1, + pattern_definition.node.start_position().column() + 1, ), Position::new( - name_node.node.end_position().row() + 1, - name_node.node.end_position().column() + 1, + pattern_definition.node.end_position().row() + 1, + pattern_definition.node.end_position().column() + 1, ), - name_node.node.start_byte(), - name_node.node.end_byte(), + pattern_definition.node.start_byte(), + pattern_definition.node.end_byte(), ); let module_grit_pattern = ModuleGritPattern { @@ -87,6 +87,10 @@ pub fn get_patterns_from_grit( }, ..Default::default() }, + raw: Some(RawGritDefinition { + format: PatternFileExt::Grit, + content: file.content.clone(), + }), ..Default::default() }, visibility: if is_public { From 18e038f580db08943b7151dc3aa93b9f5bfebd77 Mon Sep 17 00:00:00 2001 From: Arian Rezazadeh Date: Fri, 3 Jan 2025 17:52:46 +0330 Subject: [PATCH 09/31] feat: use better and consistent way of formating yaml files --- Cargo.lock | 1 + crates/cli/Cargo.toml | 1 + crates/cli/src/commands/format.rs | 74 +++++++++---------- .../.grit/patterns/dependency.grit | 4 + .../snapshots/format__format_patterns.snap | 2 +- .../format__format_patterns_with_rewrite.snap | 4 +- 6 files changed, 44 insertions(+), 42 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 178f2f5cd..bbf55302b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2603,6 +2603,7 @@ dependencies = [ "reqwest 0.11.24", "serde", "serde_json", + "serde_yaml", "similar", "tempfile", "tokio", diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 7bfd3b5c7..5d6b45f16 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -23,6 +23,7 @@ indicatif = { version = "0.17.5" } # TODO: find a work around instead of ignoring above serde = { version = "1.0.217", features = ["derive"] } serde_json = { version = "1.0.96" } +serde_yaml = { version = "0.9.25" } uuid = { version = "1.1", features = ["v4", "serde"] } tokio = { version = "1", features = ["full"] } chrono = { version = "0.4.26", features = ["serde"] } diff --git a/crates/cli/src/commands/format.rs b/crates/cli/src/commands/format.rs index 643c4149a..b27647024 100644 --- a/crates/cli/src/commands/format.rs +++ b/crates/cli/src/commands/format.rs @@ -10,21 +10,6 @@ use marzano_gritmodule::{config::ResolvedGritDefinition, parser::PatternFileExt} use serde::Serialize; use std::collections::HashMap; -/// Specifies amount of indent that consumed to get to grit body in yaml files -// Yaml files that contains grit body are like this: -// ```yaml -// patterns: -// - name: some_name -// body: | -// language css -// -// `a { $props }` where { -// $props <: contains `aspect-ratio: $x` -// } -// ``` -// the grit body is prefixed by some amount of spaces due to yaml format -const YAML_GRIT_BODY_INDENT_SIZE: usize = 6; - #[derive(Args, Debug, Serialize, Clone)] pub struct FormatArgs { /// Write formats to file instead of just showing them @@ -64,15 +49,20 @@ async fn format_file_definitations( definitions: Vec, arg: FormatArgs, ) -> Result<()> { - let hunks = definitions - .iter() - .map(|definition| definitation_to_hunk(definition)) - .collect::>>()?; - let first_definitation = definitions.first().unwrap(); let first_definitation_raw_config = first_definitation.config.raw.as_ref().unwrap(); let old_file_content = &first_definitation_raw_config.content; - let new_file_content = apply_hunk_changes(&old_file_content, hunks); + + let new_file_content = match first_definitation_raw_config.format { + PatternFileExt::Yaml => format_yaml_file(old_file_content)?, + PatternFileExt::Md | PatternFileExt::Grit => { + let hunks = definitions + .iter() + .map(|definition| format_definitions_as_hunk_changes(definition)) + .collect::>>()?; + apply_hunk_changes(&old_file_content, hunks) + } + }; if &new_file_content == old_file_content { return Ok(()); @@ -93,7 +83,29 @@ async fn format_file_definitations( Ok(()) } -fn definitation_to_hunk(definition: &ResolvedGritDefinition) -> Result { +fn format_yaml_file(file_content: &str) -> Result { + // deserializing manually and not using `SerializedGritConfig` because + // i don't want to remove any fields that `SerializedGritConfig` don't have such as 'version' + let mut config: serde_yaml::Value = serde_yaml::from_str(file_content)?; + let patterns = config + .get_mut("patterns") + .ok_or_else(|| anyhow!("couldn't parse yaml file"))? + .as_sequence_mut() + .ok_or_else(|| anyhow!("couldn't parse yaml file"))?; + for pattern in patterns { + let Some(body) = pattern.get_mut("body") else { + continue; + }; + if let serde_yaml::Value::String(body_str) = body { + *body_str = format_grit_code(&body_str)?; + // extra new line at end of grit body looks more readable + body_str.push('\n'); + } + } + Ok(serde_yaml::to_string(&config)?) +} + +fn format_definitions_as_hunk_changes(definition: &ResolvedGritDefinition) -> Result { let unformatted_grit_code = &definition.body; let mut formatted_grit_code = format_grit_code(unformatted_grit_code)?; @@ -110,13 +122,12 @@ fn definitation_to_hunk(definition: &ResolvedGritDefinition) -> Result>().join("\n"); } } - println!("range: {:?}", body_range); Ok(HunkChange { starting_byte: body_range.start_byte as usize, @@ -146,21 +157,6 @@ fn format_grit_code(source: &str) -> Result { Ok(doc_print.into_code()) } -fn grit_code_with_yaml_indent(grit_code: &str) -> String { - let indent = " ".repeat(YAML_GRIT_BODY_INDENT_SIZE); - grit_code - .lines() - .map(|line| { - if !line.is_empty() { - format!("{indent}{line}") - } else { - line.to_owned() - } - }) - .collect::>() - .join("\n") -} - /// Represent a hunk of text that needs to be changed #[derive(Debug)] struct HunkChange { diff --git a/crates/cli_bin/fixtures/unformatted_patterns/.grit/patterns/dependency.grit b/crates/cli_bin/fixtures/unformatted_patterns/.grit/patterns/dependency.grit index 961b9188c..d9f6f1f06 100644 --- a/crates/cli_bin/fixtures/unformatted_patterns/.grit/patterns/dependency.grit +++ b/crates/cli_bin/fixtures/unformatted_patterns/.grit/patterns/dependency.grit @@ -17,3 +17,7 @@ pattern upgrade_dependency($target_dep, $target_version, $dependency_key) { } } } + +pattern console_method_to_info($method) { + `console.$method($message)` => `console.info($message)` +} diff --git a/crates/cli_bin/tests/snapshots/format__format_patterns.snap b/crates/cli_bin/tests/snapshots/format__format_patterns.snap index a5e157fc5..2d6448a91 100644 --- a/crates/cli_bin/tests/snapshots/format__format_patterns.snap +++ b/crates/cli_bin/tests/snapshots/format__format_patterns.snap @@ -3,4 +3,4 @@ source: crates/cli_bin/tests/format.rs expression: "String::from_utf8(output.stdout)?" snapshot_kind: text --- -".grit/patterns/aspect_ratio.md:\n ---\n \n ```grit\n -language css\n -\n -`a { $props }` where {\n - $props <: contains `aspect-ratio: $x`\n -}\n +language css;\n +`a { $props }` where { $props <: contains `aspect-ratio: $x` }\n ```\n \n ## Matches the right selector and declaration block\n \n\n.grit/grit.yaml:\n - name: aspect_ratio_yaml\n description: Yaml version of aspect_ratio.md\n body: |\n - language css\n -\n - `a { $props }` where {\n - $props <: contains `aspect-ratio: $x`\n - }\n + language css;\n + `a { $props }` where { $props <: contains `aspect-ratio: $x` }\n \n - file: ./others/test_move_import.md\n \n\n.grit/./others/test_move_import.md:\n tags: [private]\n ---\n ```grit\n -language js\n -\n +language js;\n `sanitizeFilePath` as $s where {\n - move_import(`sanitizeFilePath`, `'@getgrit/universal'`)\n +\tmove_import(`sanitizeFilePath`, `'@getgrit/universal'`)\n }\n ```\n \n\n.grit/patterns/dependency.grit:\n -language json\n -\n +language json;\n pattern upgrade_dependency($target_dep, $target_version, $dependency_key) {\n - or {\n - `$key: $value` where {\n - $key <: `\"$target_dep\"`,\n - $value => `\"$target_version\"`\n - },\n - pair($key, $value) where {\n - $key <: `\"$dependency_key\"`,\n - $value <: object($properties) where {\n - $properties <: not contains pair(key=$dep_key) where {\n - $dep_key <: contains `$target_dep`\n - },\n - $properties => `\"$target_dep\": \"$target_version\",\\n$properties`\n - }\n - }\n - }\n -}\n +\tor {\n +\t\t`$key: $value` where {\n +\t\t\t$key <: `\"$target_dep\"`,\n +\t\t\t$value => `\"$target_version\"`\n +\t\t},\n +\t\tpair($key, $value) where {\n +\t\t\t$key <: `\"$dependency_key\"`,\n +\t\t\t$value <: object($properties) where {\n +\t\t\t\t$properties <: notcontains pair(key = $dep_key) where {\n +\t\t\t\t\t$dep_key <: contains `$target_dep`\n +\t\t\t\t},\n +\t\t\t\t$properties => `\"$target_dep\": \"$target_version\",\\n$properties`\n +\t\t\t}\n +\t\t}\n +\t}}\n \n\n" +".grit/patterns/aspect_ratio.md:\n ---\n \n ```grit\n -language css\n -\n -`a { $props }` where {\n - $props <: contains `aspect-ratio: $x`\n -}\n +language css;\n +`a { $props }` where { $props <: contains `aspect-ratio: $x` }\n ```\n \n ## Matches the right selector and declaration block\n \n\n.grit/./others/test_move_import.md:\n tags: [private]\n ---\n ```grit\n -language js\n -\n +language js;\n `sanitizeFilePath` as $s where {\n - move_import(`sanitizeFilePath`, `'@getgrit/universal'`)\n +\tmove_import(`sanitizeFilePath`, `'@getgrit/universal'`)\n }\n ```\n \n\n.grit/grit.yaml:\n version: 0.0.1\n patterns:\n - - name: aspect_ratio_yaml\n - description: Yaml version of aspect_ratio.md\n - body: |\n - language css\n -\n - `a { $props }` where {\n - $props <: contains `aspect-ratio: $x`\n - }\n +- name: aspect_ratio_yaml\n + description: Yaml version of aspect_ratio.md\n + body: |+\n + language css;\n + `a { $props }` where { $props <: contains `aspect-ratio: $x` }\n \n - - file: ./others/test_move_import.md\n +- file: ./others/test_move_import.md\n \n\n.grit/patterns/dependency.grit:\n language json\n \n pattern upgrade_dependency($target_dep, $target_version, $dependency_key) {\n - or {\n - `$key: $value` where {\n - $key <: `\"$target_dep\"`,\n - $value => `\"$target_version\"`\n - },\n - pair($key, $value) where {\n - $key <: `\"$dependency_key\"`,\n - $value <: object($properties) where {\n - $properties <: not contains pair(key=$dep_key) where {\n - $dep_key <: contains `$target_dep`\n - },\n - $properties => `\"$target_dep\": \"$target_version\",\\n$properties`\n - }\n - }\n - }\n -}\n +\tor {\n +\t\t`$key: $value` where {\n +\t\t\t$key <: `\"$target_dep\"`,\n +\t\t\t$value => `\"$target_version\"`\n +\t\t},\n +\t\tpair($key, $value) where {\n +\t\t\t$key <: `\"$dependency_key\"`,\n +\t\t\t$value <: object($properties) where {\n +\t\t\t\t$properties <: notcontains pair(key = $dep_key) where {\n +\t\t\t\t\t$dep_key <: contains `$target_dep`\n +\t\t\t\t},\n +\t\t\t\t$properties => `\"$target_dep\": \"$target_version\",\\n$properties`\n +\t\t\t}\n +\t\t}\n +\t}}\n \n pattern console_method_to_info($method) {\n - `console.$method($message)` => `console.info($message)`\n -}\n +\t`console.$method($message)` => `console.info($message)`}\n \n\n" diff --git a/crates/cli_bin/tests/snapshots/format__format_patterns_with_rewrite.snap b/crates/cli_bin/tests/snapshots/format__format_patterns_with_rewrite.snap index 246aebb5c..fae2166a6 100644 --- a/crates/cli_bin/tests/snapshots/format__format_patterns_with_rewrite.snap +++ b/crates/cli_bin/tests/snapshots/format__format_patterns_with_rewrite.snap @@ -3,7 +3,7 @@ source: crates/cli_bin/tests/format.rs expression: "vec![yaml_file_content, test_move_import_file_content,\naspect_ratio_md_file_content, dependency_grit_file_content]" snapshot_kind: text --- -- "version: 0.0.1\npatterns:\n - name: aspect_ratio_yaml\n description: Yaml version of aspect_ratio.md\n body: |\n language css;\n `a { $props }` where { $props <: contains `aspect-ratio: $x` }\n\n - file: ./others/test_move_import.md\n" +- "version: 0.0.1\npatterns:\n- name: aspect_ratio_yaml\n description: Yaml version of aspect_ratio.md\n body: |+\n language css;\n `a { $props }` where { $props <: contains `aspect-ratio: $x` }\n\n- file: ./others/test_move_import.md\n" - "---\nprivate: true\ntags: [private]\n---\n```grit\nlanguage js;\n`sanitizeFilePath` as $s where {\n\tmove_import(`sanitizeFilePath`, `'@getgrit/universal'`)\n}\n```\n" - "---\ntitle: Aspect ratio\n---\n\n```grit\nlanguage css;\n`a { $props }` where { $props <: contains `aspect-ratio: $x` }\n```\n\n## Matches the right selector and declaration block\n\n```css\na {\n width: calc(100% - 80px);\n aspect-ratio: 1/2;\n font-size: calc(10px + (56 - 10) * ((100vw - 320px) / (1920 - 320)));\n}\n\n#some-id {\n some-property: 5px;\n}\n\na.b ~ c.d {\n}\n.e.f + .g.h {\n}\n\n@font-face {\n font-family: 'Open Sans';\n src: url('/a') format('woff2'), url('/b/c') format('woff');\n}\n```\n\n```css\na {\n width: calc(100% - 80px);\n aspect-ratio: 1/2;\n font-size: calc(10px + (56 - 10) * ((100vw - 320px) / (1920 - 320)));\n}\n\n#some-id {\n some-property: 5px;\n}\n\na.b ~ c.d {\n}\n.e.f + .g.h {\n}\n\n@font-face {\n font-family: 'Open Sans';\n src: url('/a') format('woff2'), url('/b/c') format('woff');\n}\n```\n" -- "language json;\npattern upgrade_dependency($target_dep, $target_version, $dependency_key) {\n\tor {\n\t\t`$key: $value` where {\n\t\t\t$key <: `\"$target_dep\"`,\n\t\t\t$value => `\"$target_version\"`\n\t\t},\n\t\tpair($key, $value) where {\n\t\t\t$key <: `\"$dependency_key\"`,\n\t\t\t$value <: object($properties) where {\n\t\t\t\t$properties <: notcontains pair(key = $dep_key) where {\n\t\t\t\t\t$dep_key <: contains `$target_dep`\n\t\t\t\t},\n\t\t\t\t$properties => `\"$target_dep\": \"$target_version\",\\n$properties`\n\t\t\t}\n\t\t}\n\t}}\n" +- "language json\n\npattern upgrade_dependency($target_dep, $target_version, $dependency_key) {\n\tor {\n\t\t`$key: $value` where {\n\t\t\t$key <: `\"$target_dep\"`,\n\t\t\t$value => `\"$target_version\"`\n\t\t},\n\t\tpair($key, $value) where {\n\t\t\t$key <: `\"$dependency_key\"`,\n\t\t\t$value <: object($properties) where {\n\t\t\t\t$properties <: notcontains pair(key = $dep_key) where {\n\t\t\t\t\t$dep_key <: contains `$target_dep`\n\t\t\t\t},\n\t\t\t\t$properties => `\"$target_dep\": \"$target_version\",\\n$properties`\n\t\t\t}\n\t\t}\n\t}}\n\npattern console_method_to_info($method) {\n\t`console.$method($message)` => `console.info($message)`}\n" From ea820250e70ef09f3d294b66bc0378e8ac0c0be0 Mon Sep 17 00:00:00 2001 From: Arian Rezazadeh Date: Fri, 3 Jan 2025 18:02:45 +0330 Subject: [PATCH 10/31] chore: change some comments and variable names --- crates/cli/Cargo.toml | 2 +- crates/cli/src/commands/format.rs | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 5d6b45f16..66324354d 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -20,7 +20,7 @@ anyhow = { version = "1.0.70" } clap = { version = "4.1.13", features = ["derive"] } indicatif = { version = "0.17.5" } # Do *NOT* upgrade beyond 1.0.171 until https://github.com/serde-rs/serde/issues/2538 is fixed -# TODO: find a work around instead of ignoring above +# TODO: ask if above note is still important serde = { version = "1.0.217", features = ["derive"] } serde_json = { version = "1.0.96" } serde_yaml = { version = "0.9.25" } diff --git a/crates/cli/src/commands/format.rs b/crates/cli/src/commands/format.rs index b27647024..a44d72b18 100644 --- a/crates/cli/src/commands/format.rs +++ b/crates/cli/src/commands/format.rs @@ -22,10 +22,7 @@ pub async fn run_format(arg: &FormatArgs) -> Result<()> { // sort to have consistent output for tests resolved.sort(); - // we process each file resolves separetly because we want - // to write to file once and also fix the bugs that may happen when - // overwriting same file multiple times for different patterns - let file_path_to_resolves: HashMap> = resolved + let file_path_to_resolved: HashMap> = resolved .into_iter() .fold(HashMap::new(), |mut acc, resolved| { let file_path = resolved.config.path.clone(); @@ -33,8 +30,8 @@ pub async fn run_format(arg: &FormatArgs) -> Result<()> { acc }); - // TODO: do we need this to be runned in parallel? - for (file_path, definitions) in file_path_to_resolves { + // TODO: this can be easilly runned in parallel, just the test that reads stdout will get failed + for (file_path, definitions) in file_path_to_resolved { if let Err(error) = format_file_definitations(file_path.clone(), definitions, arg.clone()).await { @@ -83,6 +80,7 @@ async fn format_file_definitations( Ok(()) } +// TODO: ask if it's ok to format whole yaml file fn format_yaml_file(file_content: &str) -> Result { // deserializing manually and not using `SerializedGritConfig` because // i don't want to remove any fields that `SerializedGritConfig` don't have such as 'version' From 5ae0ebd01193a3360223cccc0e4f72ca5925d53f Mon Sep 17 00:00:00 2001 From: Arian Rezazadeh Date: Fri, 3 Jan 2025 18:49:45 +0330 Subject: [PATCH 11/31] fix: resolves not being sorted currectly --- crates/cli/src/commands/format.rs | 8 ++++++-- .../cli_bin/tests/snapshots/format__format_patterns.snap | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/crates/cli/src/commands/format.rs b/crates/cli/src/commands/format.rs index a44d72b18..7f833a7b4 100644 --- a/crates/cli/src/commands/format.rs +++ b/crates/cli/src/commands/format.rs @@ -22,13 +22,17 @@ pub async fn run_format(arg: &FormatArgs) -> Result<()> { // sort to have consistent output for tests resolved.sort(); - let file_path_to_resolved: HashMap> = resolved + // TODO: maybe rewrite this to use fewer allocations + let mut file_path_to_resolved: Vec<(String, Vec)> = resolved .into_iter() .fold(HashMap::new(), |mut acc, resolved| { let file_path = resolved.config.path.clone(); acc.entry(file_path).or_insert_with(Vec::new).push(resolved); acc - }); + }) + .into_iter() + .collect(); + file_path_to_resolved.sort_by_key(|(file_path, _)| file_path.clone()); // TODO: this can be easilly runned in parallel, just the test that reads stdout will get failed for (file_path, definitions) in file_path_to_resolved { diff --git a/crates/cli_bin/tests/snapshots/format__format_patterns.snap b/crates/cli_bin/tests/snapshots/format__format_patterns.snap index 2d6448a91..7928a4709 100644 --- a/crates/cli_bin/tests/snapshots/format__format_patterns.snap +++ b/crates/cli_bin/tests/snapshots/format__format_patterns.snap @@ -3,4 +3,4 @@ source: crates/cli_bin/tests/format.rs expression: "String::from_utf8(output.stdout)?" snapshot_kind: text --- -".grit/patterns/aspect_ratio.md:\n ---\n \n ```grit\n -language css\n -\n -`a { $props }` where {\n - $props <: contains `aspect-ratio: $x`\n -}\n +language css;\n +`a { $props }` where { $props <: contains `aspect-ratio: $x` }\n ```\n \n ## Matches the right selector and declaration block\n \n\n.grit/./others/test_move_import.md:\n tags: [private]\n ---\n ```grit\n -language js\n -\n +language js;\n `sanitizeFilePath` as $s where {\n - move_import(`sanitizeFilePath`, `'@getgrit/universal'`)\n +\tmove_import(`sanitizeFilePath`, `'@getgrit/universal'`)\n }\n ```\n \n\n.grit/grit.yaml:\n version: 0.0.1\n patterns:\n - - name: aspect_ratio_yaml\n - description: Yaml version of aspect_ratio.md\n - body: |\n - language css\n -\n - `a { $props }` where {\n - $props <: contains `aspect-ratio: $x`\n - }\n +- name: aspect_ratio_yaml\n + description: Yaml version of aspect_ratio.md\n + body: |+\n + language css;\n + `a { $props }` where { $props <: contains `aspect-ratio: $x` }\n \n - - file: ./others/test_move_import.md\n +- file: ./others/test_move_import.md\n \n\n.grit/patterns/dependency.grit:\n language json\n \n pattern upgrade_dependency($target_dep, $target_version, $dependency_key) {\n - or {\n - `$key: $value` where {\n - $key <: `\"$target_dep\"`,\n - $value => `\"$target_version\"`\n - },\n - pair($key, $value) where {\n - $key <: `\"$dependency_key\"`,\n - $value <: object($properties) where {\n - $properties <: not contains pair(key=$dep_key) where {\n - $dep_key <: contains `$target_dep`\n - },\n - $properties => `\"$target_dep\": \"$target_version\",\\n$properties`\n - }\n - }\n - }\n -}\n +\tor {\n +\t\t`$key: $value` where {\n +\t\t\t$key <: `\"$target_dep\"`,\n +\t\t\t$value => `\"$target_version\"`\n +\t\t},\n +\t\tpair($key, $value) where {\n +\t\t\t$key <: `\"$dependency_key\"`,\n +\t\t\t$value <: object($properties) where {\n +\t\t\t\t$properties <: notcontains pair(key = $dep_key) where {\n +\t\t\t\t\t$dep_key <: contains `$target_dep`\n +\t\t\t\t},\n +\t\t\t\t$properties => `\"$target_dep\": \"$target_version\",\\n$properties`\n +\t\t\t}\n +\t\t}\n +\t}}\n \n pattern console_method_to_info($method) {\n - `console.$method($message)` => `console.info($message)`\n -}\n +\t`console.$method($message)` => `console.info($message)`}\n \n\n" +".grit/./others/test_move_import.md:\n tags: [private]\n ---\n ```grit\n -language js\n -\n +language js;\n `sanitizeFilePath` as $s where {\n - move_import(`sanitizeFilePath`, `'@getgrit/universal'`)\n +\tmove_import(`sanitizeFilePath`, `'@getgrit/universal'`)\n }\n ```\n \n\n.grit/grit.yaml:\n version: 0.0.1\n patterns:\n - - name: aspect_ratio_yaml\n - description: Yaml version of aspect_ratio.md\n - body: |\n - language css\n -\n - `a { $props }` where {\n - $props <: contains `aspect-ratio: $x`\n - }\n +- name: aspect_ratio_yaml\n + description: Yaml version of aspect_ratio.md\n + body: |+\n + language css;\n + `a { $props }` where { $props <: contains `aspect-ratio: $x` }\n \n - - file: ./others/test_move_import.md\n +- file: ./others/test_move_import.md\n \n\n.grit/patterns/aspect_ratio.md:\n ---\n \n ```grit\n -language css\n -\n -`a { $props }` where {\n - $props <: contains `aspect-ratio: $x`\n -}\n +language css;\n +`a { $props }` where { $props <: contains `aspect-ratio: $x` }\n ```\n \n ## Matches the right selector and declaration block\n \n\n.grit/patterns/dependency.grit:\n language json\n \n pattern upgrade_dependency($target_dep, $target_version, $dependency_key) {\n - or {\n - `$key: $value` where {\n - $key <: `\"$target_dep\"`,\n - $value => `\"$target_version\"`\n - },\n - pair($key, $value) where {\n - $key <: `\"$dependency_key\"`,\n - $value <: object($properties) where {\n - $properties <: not contains pair(key=$dep_key) where {\n - $dep_key <: contains `$target_dep`\n - },\n - $properties => `\"$target_dep\": \"$target_version\",\\n$properties`\n - }\n - }\n - }\n -}\n +\tor {\n +\t\t`$key: $value` where {\n +\t\t\t$key <: `\"$target_dep\"`,\n +\t\t\t$value => `\"$target_version\"`\n +\t\t},\n +\t\tpair($key, $value) where {\n +\t\t\t$key <: `\"$dependency_key\"`,\n +\t\t\t$value <: object($properties) where {\n +\t\t\t\t$properties <: notcontains pair(key = $dep_key) where {\n +\t\t\t\t\t$dep_key <: contains `$target_dep`\n +\t\t\t\t},\n +\t\t\t\t$properties => `\"$target_dep\": \"$target_version\",\\n$properties`\n +\t\t\t}\n +\t\t}\n +\t}}\n \n pattern console_method_to_info($method) {\n - `console.$method($message)` => `console.info($message)`\n -}\n +\t`console.$method($message)` => `console.info($message)`}\n \n\n" From b744fdd843d30d349b8487bd60ef4f03ada603b9 Mon Sep 17 00:00:00 2001 From: Arian Rezazadeh Date: Sat, 4 Jan 2025 09:25:46 +0330 Subject: [PATCH 12/31] refactor: resolv todo --- crates/cli/src/commands/format.rs | 23 ++++++++++--------- .../snapshots/format__format_patterns.snap | 2 +- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/crates/cli/src/commands/format.rs b/crates/cli/src/commands/format.rs index 7f833a7b4..f90bd995c 100644 --- a/crates/cli/src/commands/format.rs +++ b/crates/cli/src/commands/format.rs @@ -8,7 +8,6 @@ use clap::Args; use colored::Colorize; use marzano_gritmodule::{config::ResolvedGritDefinition, parser::PatternFileExt}; use serde::Serialize; -use std::collections::HashMap; #[derive(Args, Debug, Serialize, Clone)] pub struct FormatArgs { @@ -22,17 +21,19 @@ pub async fn run_format(arg: &FormatArgs) -> Result<()> { // sort to have consistent output for tests resolved.sort(); - // TODO: maybe rewrite this to use fewer allocations - let mut file_path_to_resolved: Vec<(String, Vec)> = resolved - .into_iter() - .fold(HashMap::new(), |mut acc, resolved| { - let file_path = resolved.config.path.clone(); - acc.entry(file_path).or_insert_with(Vec::new).push(resolved); + let file_path_to_resolved: Vec<(String, Vec)> = + resolved.into_iter().fold(Vec::new(), |mut acc, resolved| { + let file_path = &resolved.config.path; + if let Some((_, resolves)) = acc + .iter_mut() + .find(|(resolv_file_path, _)| resolv_file_path == file_path) + { + resolves.push(resolved); + } else { + acc.push((file_path.clone(), vec![resolved])); + } acc - }) - .into_iter() - .collect(); - file_path_to_resolved.sort_by_key(|(file_path, _)| file_path.clone()); + }); // TODO: this can be easilly runned in parallel, just the test that reads stdout will get failed for (file_path, definitions) in file_path_to_resolved { diff --git a/crates/cli_bin/tests/snapshots/format__format_patterns.snap b/crates/cli_bin/tests/snapshots/format__format_patterns.snap index 7928a4709..3ac5899c5 100644 --- a/crates/cli_bin/tests/snapshots/format__format_patterns.snap +++ b/crates/cli_bin/tests/snapshots/format__format_patterns.snap @@ -3,4 +3,4 @@ source: crates/cli_bin/tests/format.rs expression: "String::from_utf8(output.stdout)?" snapshot_kind: text --- -".grit/./others/test_move_import.md:\n tags: [private]\n ---\n ```grit\n -language js\n -\n +language js;\n `sanitizeFilePath` as $s where {\n - move_import(`sanitizeFilePath`, `'@getgrit/universal'`)\n +\tmove_import(`sanitizeFilePath`, `'@getgrit/universal'`)\n }\n ```\n \n\n.grit/grit.yaml:\n version: 0.0.1\n patterns:\n - - name: aspect_ratio_yaml\n - description: Yaml version of aspect_ratio.md\n - body: |\n - language css\n -\n - `a { $props }` where {\n - $props <: contains `aspect-ratio: $x`\n - }\n +- name: aspect_ratio_yaml\n + description: Yaml version of aspect_ratio.md\n + body: |+\n + language css;\n + `a { $props }` where { $props <: contains `aspect-ratio: $x` }\n \n - - file: ./others/test_move_import.md\n +- file: ./others/test_move_import.md\n \n\n.grit/patterns/aspect_ratio.md:\n ---\n \n ```grit\n -language css\n -\n -`a { $props }` where {\n - $props <: contains `aspect-ratio: $x`\n -}\n +language css;\n +`a { $props }` where { $props <: contains `aspect-ratio: $x` }\n ```\n \n ## Matches the right selector and declaration block\n \n\n.grit/patterns/dependency.grit:\n language json\n \n pattern upgrade_dependency($target_dep, $target_version, $dependency_key) {\n - or {\n - `$key: $value` where {\n - $key <: `\"$target_dep\"`,\n - $value => `\"$target_version\"`\n - },\n - pair($key, $value) where {\n - $key <: `\"$dependency_key\"`,\n - $value <: object($properties) where {\n - $properties <: not contains pair(key=$dep_key) where {\n - $dep_key <: contains `$target_dep`\n - },\n - $properties => `\"$target_dep\": \"$target_version\",\\n$properties`\n - }\n - }\n - }\n -}\n +\tor {\n +\t\t`$key: $value` where {\n +\t\t\t$key <: `\"$target_dep\"`,\n +\t\t\t$value => `\"$target_version\"`\n +\t\t},\n +\t\tpair($key, $value) where {\n +\t\t\t$key <: `\"$dependency_key\"`,\n +\t\t\t$value <: object($properties) where {\n +\t\t\t\t$properties <: notcontains pair(key = $dep_key) where {\n +\t\t\t\t\t$dep_key <: contains `$target_dep`\n +\t\t\t\t},\n +\t\t\t\t$properties => `\"$target_dep\": \"$target_version\",\\n$properties`\n +\t\t\t}\n +\t\t}\n +\t}}\n \n pattern console_method_to_info($method) {\n - `console.$method($message)` => `console.info($message)`\n -}\n +\t`console.$method($message)` => `console.info($message)`}\n \n\n" +".grit/patterns/aspect_ratio.md:\n ---\n \n ```grit\n -language css\n -\n -`a { $props }` where {\n - $props <: contains `aspect-ratio: $x`\n -}\n +language css;\n +`a { $props }` where { $props <: contains `aspect-ratio: $x` }\n ```\n \n ## Matches the right selector and declaration block\n \n\n.grit/grit.yaml:\n version: 0.0.1\n patterns:\n - - name: aspect_ratio_yaml\n - description: Yaml version of aspect_ratio.md\n - body: |\n - language css\n -\n - `a { $props }` where {\n - $props <: contains `aspect-ratio: $x`\n - }\n +- name: aspect_ratio_yaml\n + description: Yaml version of aspect_ratio.md\n + body: |+\n + language css;\n + `a { $props }` where { $props <: contains `aspect-ratio: $x` }\n \n - - file: ./others/test_move_import.md\n +- file: ./others/test_move_import.md\n \n\n.grit/patterns/dependency.grit:\n language json\n \n pattern upgrade_dependency($target_dep, $target_version, $dependency_key) {\n - or {\n - `$key: $value` where {\n - $key <: `\"$target_dep\"`,\n - $value => `\"$target_version\"`\n - },\n - pair($key, $value) where {\n - $key <: `\"$dependency_key\"`,\n - $value <: object($properties) where {\n - $properties <: not contains pair(key=$dep_key) where {\n - $dep_key <: contains `$target_dep`\n - },\n - $properties => `\"$target_dep\": \"$target_version\",\\n$properties`\n - }\n - }\n - }\n -}\n +\tor {\n +\t\t`$key: $value` where {\n +\t\t\t$key <: `\"$target_dep\"`,\n +\t\t\t$value => `\"$target_version\"`\n +\t\t},\n +\t\tpair($key, $value) where {\n +\t\t\t$key <: `\"$dependency_key\"`,\n +\t\t\t$value <: object($properties) where {\n +\t\t\t\t$properties <: notcontains pair(key = $dep_key) where {\n +\t\t\t\t\t$dep_key <: contains `$target_dep`\n +\t\t\t\t},\n +\t\t\t\t$properties => `\"$target_dep\": \"$target_version\",\\n$properties`\n +\t\t\t}\n +\t\t}\n +\t}}\n \n pattern console_method_to_info($method) {\n - `console.$method($message)` => `console.info($message)`\n -}\n +\t`console.$method($message)` => `console.info($message)`}\n \n\n.grit/./others/test_move_import.md:\n tags: [private]\n ---\n ```grit\n -language js\n -\n +language js;\n `sanitizeFilePath` as $s where {\n - move_import(`sanitizeFilePath`, `'@getgrit/universal'`)\n +\tmove_import(`sanitizeFilePath`, `'@getgrit/universal'`)\n }\n ```\n \n\n" From f9b05e915fc352f5421e4355f927257edc20d5c6 Mon Sep 17 00:00:00 2001 From: Arian Rezazadeh Date: Sat, 4 Jan 2025 09:36:47 +0330 Subject: [PATCH 13/31] refactor: rename some functions and variables --- crates/cli/src/commands/format.rs | 79 +++++++++++++++++-------------- 1 file changed, 44 insertions(+), 35 deletions(-) diff --git a/crates/cli/src/commands/format.rs b/crates/cli/src/commands/format.rs index f90bd995c..85f06549d 100644 --- a/crates/cli/src/commands/format.rs +++ b/crates/cli/src/commands/format.rs @@ -21,24 +21,12 @@ pub async fn run_format(arg: &FormatArgs) -> Result<()> { // sort to have consistent output for tests resolved.sort(); - let file_path_to_resolved: Vec<(String, Vec)> = - resolved.into_iter().fold(Vec::new(), |mut acc, resolved| { - let file_path = &resolved.config.path; - if let Some((_, resolves)) = acc - .iter_mut() - .find(|(resolv_file_path, _)| resolv_file_path == file_path) - { - resolves.push(resolved); - } else { - acc.push((file_path.clone(), vec![resolved])); - } - acc - }); + let file_path_to_resolved = group_resolved_patterns_by_group(resolved); // TODO: this can be easilly runned in parallel, just the test that reads stdout will get failed - for (file_path, definitions) in file_path_to_resolved { + for (file_path, resovled_patterns) in file_path_to_resolved { if let Err(error) = - format_file_definitations(file_path.clone(), definitions, arg.clone()).await + format_file_resovled_patterns(file_path.clone(), resovled_patterns, arg.clone()).await { eprintln!("couldn't format '{}': {error:?}", file_path) } @@ -46,21 +34,42 @@ pub async fn run_format(arg: &FormatArgs) -> Result<()> { Ok(()) } -async fn format_file_definitations( +fn group_resolved_patterns_by_group( + resolved: Vec, +) -> Vec<(String, Vec)> { + resolved.into_iter().fold(Vec::new(), |mut acc, resolved| { + let file_path = &resolved.config.path; + if let Some((_, resolved_patterns)) = acc + .iter_mut() + .find(|(resolv_file_path, _)| resolv_file_path == file_path) + { + resolved_patterns.push(resolved); + } else { + acc.push((file_path.clone(), vec![resolved])); + } + acc + }) +} + +async fn format_file_resovled_patterns( file_path: String, - definitions: Vec, + patterns: Vec, arg: FormatArgs, ) -> Result<()> { - let first_definitation = definitions.first().unwrap(); - let first_definitation_raw_config = first_definitation.config.raw.as_ref().unwrap(); - let old_file_content = &first_definitation_raw_config.content; + let first_pattern = patterns.first().unwrap(); + let first_pattern_raw_data = first_pattern + .config + .raw + .as_ref() + .ok_or_else(|| anyhow!("pattern does not have config raw data"))?; + let old_file_content = &first_pattern_raw_data.content; - let new_file_content = match first_definitation_raw_config.format { + let new_file_content = match first_pattern_raw_data.format { PatternFileExt::Yaml => format_yaml_file(old_file_content)?, PatternFileExt::Md | PatternFileExt::Grit => { - let hunks = definitions + let hunks = patterns .iter() - .map(|definition| format_definitions_as_hunk_changes(definition)) + .map(format_pattern_as_hunk_changes) .collect::>>()?; apply_hunk_changes(&old_file_content, hunks) } @@ -78,7 +87,7 @@ async fn format_file_definitations( println!( "{}:\n{}", file_path.bold(), - format_diff(&old_file_content, &new_file_content) + format_diff(old_file_content, &new_file_content) ); } @@ -89,12 +98,13 @@ async fn format_file_definitations( fn format_yaml_file(file_content: &str) -> Result { // deserializing manually and not using `SerializedGritConfig` because // i don't want to remove any fields that `SerializedGritConfig` don't have such as 'version' - let mut config: serde_yaml::Value = serde_yaml::from_str(file_content)?; + let mut config: serde_yaml::Value = + serde_yaml::from_str(file_content).with_context(|| "couldn't parse yaml file")?; let patterns = config .get_mut("patterns") - .ok_or_else(|| anyhow!("couldn't parse yaml file"))? + .ok_or_else(|| anyhow!("couldn't find patterns in yaml file"))? .as_sequence_mut() - .ok_or_else(|| anyhow!("couldn't parse yaml file"))?; + .ok_or_else(|| anyhow!("patterns in yaml file are not sequence"))?; for pattern in patterns { let Some(body) = pattern.get_mut("body") else { continue; @@ -108,20 +118,20 @@ fn format_yaml_file(file_content: &str) -> Result { Ok(serde_yaml::to_string(&config)?) } -fn format_definitions_as_hunk_changes(definition: &ResolvedGritDefinition) -> Result { - let unformatted_grit_code = &definition.body; +fn format_pattern_as_hunk_changes(pattern: &ResolvedGritDefinition) -> Result { + let unformatted_grit_code = &pattern.body; let mut formatted_grit_code = format_grit_code(unformatted_grit_code)?; - let raw_data = definition + let raw_data = pattern .config .raw .as_ref() - .ok_or_else(|| anyhow!("definition doesn't have raw_data"))?; - let body_range = definition + .ok_or_else(|| anyhow!("pattern doesn't have raw_data"))?; + let body_range = pattern .config .range .as_ref() - .ok_or_else(|| anyhow!("definition doesn't have config range"))?; + .ok_or_else(|| anyhow!("pattern doesn't have config range"))?; if raw_data.format == PatternFileExt::Grit { // TODO: fix langauge line not getting formatted @@ -156,8 +166,7 @@ fn format_grit_code(source: &str) -> Result { let options = GritFormatOptions::default(); let doc = biome_grit_formatter::format_node(options, &parsed.syntax()) .with_context(|| "biome couldn't format")?; - let doc_print = doc.print()?; - Ok(doc_print.into_code()) + Ok(doc.print()?.into_code()) } /// Represent a hunk of text that needs to be changed From 5e697ad8e96aa8bb60cb1e36843a4c81595eb6aa Mon Sep 17 00:00:00 2001 From: Arian Rezazadeh Date: Sat, 4 Jan 2025 09:39:07 +0330 Subject: [PATCH 14/31] chore: fix clippy warnings --- crates/cli/src/commands/format.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/cli/src/commands/format.rs b/crates/cli/src/commands/format.rs index 85f06549d..3f423570e 100644 --- a/crates/cli/src/commands/format.rs +++ b/crates/cli/src/commands/format.rs @@ -71,7 +71,7 @@ async fn format_file_resovled_patterns( .iter() .map(format_pattern_as_hunk_changes) .collect::>>()?; - apply_hunk_changes(&old_file_content, hunks) + apply_hunk_changes(old_file_content, hunks) } }; @@ -110,7 +110,7 @@ fn format_yaml_file(file_content: &str) -> Result { continue; }; if let serde_yaml::Value::String(body_str) = body { - *body_str = format_grit_code(&body_str)?; + *body_str = format_grit_code(body_str)?; // extra new line at end of grit body looks more readable body_str.push('\n'); } From 1807c3c38d59b9213a1fe8dac763f7f055626ec5 Mon Sep 17 00:00:00 2001 From: Arian Rezazadeh Date: Sat, 4 Jan 2025 10:32:38 +0330 Subject: [PATCH 15/31] refactor: better format .grit files --- crates/cli/src/commands/format.rs | 23 +++---------------- .../snapshots/format__format_patterns.snap | 2 +- .../format__format_patterns_with_rewrite.snap | 2 +- 3 files changed, 5 insertions(+), 22 deletions(-) diff --git a/crates/cli/src/commands/format.rs b/crates/cli/src/commands/format.rs index 3f423570e..e6861357b 100644 --- a/crates/cli/src/commands/format.rs +++ b/crates/cli/src/commands/format.rs @@ -66,7 +66,8 @@ async fn format_file_resovled_patterns( let new_file_content = match first_pattern_raw_data.format { PatternFileExt::Yaml => format_yaml_file(old_file_content)?, - PatternFileExt::Md | PatternFileExt::Grit => { + PatternFileExt::Grit => format_grit_code(old_file_content)?, + PatternFileExt::Md => { let hunks = patterns .iter() .map(format_pattern_as_hunk_changes) @@ -119,29 +120,11 @@ fn format_yaml_file(file_content: &str) -> Result { } fn format_pattern_as_hunk_changes(pattern: &ResolvedGritDefinition) -> Result { - let unformatted_grit_code = &pattern.body; - let mut formatted_grit_code = format_grit_code(unformatted_grit_code)?; - - let raw_data = pattern - .config - .raw - .as_ref() - .ok_or_else(|| anyhow!("pattern doesn't have raw_data"))?; + let formatted_grit_code = format_grit_code(&pattern.body)?; let body_range = pattern .config .range - .as_ref() .ok_or_else(|| anyhow!("pattern doesn't have config range"))?; - - if raw_data.format == PatternFileExt::Grit { - // TODO: fix langauge line not getting formatted - // this needed because down the line the grit body gets prefixed with "language {}\n\n" - if formatted_grit_code.starts_with("language ") { - let formatted_lines = formatted_grit_code.lines(); - formatted_grit_code = formatted_lines.skip(1).collect::>().join("\n"); - } - } - Ok(HunkChange { starting_byte: body_range.start_byte as usize, ending_byte: body_range.end_byte as usize, diff --git a/crates/cli_bin/tests/snapshots/format__format_patterns.snap b/crates/cli_bin/tests/snapshots/format__format_patterns.snap index 3ac5899c5..8aa54338e 100644 --- a/crates/cli_bin/tests/snapshots/format__format_patterns.snap +++ b/crates/cli_bin/tests/snapshots/format__format_patterns.snap @@ -3,4 +3,4 @@ source: crates/cli_bin/tests/format.rs expression: "String::from_utf8(output.stdout)?" snapshot_kind: text --- -".grit/patterns/aspect_ratio.md:\n ---\n \n ```grit\n -language css\n -\n -`a { $props }` where {\n - $props <: contains `aspect-ratio: $x`\n -}\n +language css;\n +`a { $props }` where { $props <: contains `aspect-ratio: $x` }\n ```\n \n ## Matches the right selector and declaration block\n \n\n.grit/grit.yaml:\n version: 0.0.1\n patterns:\n - - name: aspect_ratio_yaml\n - description: Yaml version of aspect_ratio.md\n - body: |\n - language css\n -\n - `a { $props }` where {\n - $props <: contains `aspect-ratio: $x`\n - }\n +- name: aspect_ratio_yaml\n + description: Yaml version of aspect_ratio.md\n + body: |+\n + language css;\n + `a { $props }` where { $props <: contains `aspect-ratio: $x` }\n \n - - file: ./others/test_move_import.md\n +- file: ./others/test_move_import.md\n \n\n.grit/patterns/dependency.grit:\n language json\n \n pattern upgrade_dependency($target_dep, $target_version, $dependency_key) {\n - or {\n - `$key: $value` where {\n - $key <: `\"$target_dep\"`,\n - $value => `\"$target_version\"`\n - },\n - pair($key, $value) where {\n - $key <: `\"$dependency_key\"`,\n - $value <: object($properties) where {\n - $properties <: not contains pair(key=$dep_key) where {\n - $dep_key <: contains `$target_dep`\n - },\n - $properties => `\"$target_dep\": \"$target_version\",\\n$properties`\n - }\n - }\n - }\n -}\n +\tor {\n +\t\t`$key: $value` where {\n +\t\t\t$key <: `\"$target_dep\"`,\n +\t\t\t$value => `\"$target_version\"`\n +\t\t},\n +\t\tpair($key, $value) where {\n +\t\t\t$key <: `\"$dependency_key\"`,\n +\t\t\t$value <: object($properties) where {\n +\t\t\t\t$properties <: notcontains pair(key = $dep_key) where {\n +\t\t\t\t\t$dep_key <: contains `$target_dep`\n +\t\t\t\t},\n +\t\t\t\t$properties => `\"$target_dep\": \"$target_version\",\\n$properties`\n +\t\t\t}\n +\t\t}\n +\t}}\n \n pattern console_method_to_info($method) {\n - `console.$method($message)` => `console.info($message)`\n -}\n +\t`console.$method($message)` => `console.info($message)`}\n \n\n.grit/./others/test_move_import.md:\n tags: [private]\n ---\n ```grit\n -language js\n -\n +language js;\n `sanitizeFilePath` as $s where {\n - move_import(`sanitizeFilePath`, `'@getgrit/universal'`)\n +\tmove_import(`sanitizeFilePath`, `'@getgrit/universal'`)\n }\n ```\n \n\n" +".grit/patterns/aspect_ratio.md:\n ---\n \n ```grit\n -language css\n -\n -`a { $props }` where {\n - $props <: contains `aspect-ratio: $x`\n -}\n +language css;\n +`a { $props }` where { $props <: contains `aspect-ratio: $x` }\n ```\n \n ## Matches the right selector and declaration block\n \n\n.grit/grit.yaml:\n version: 0.0.1\n patterns:\n - - name: aspect_ratio_yaml\n - description: Yaml version of aspect_ratio.md\n - body: |\n - language css\n -\n - `a { $props }` where {\n - $props <: contains `aspect-ratio: $x`\n - }\n +- name: aspect_ratio_yaml\n + description: Yaml version of aspect_ratio.md\n + body: |+\n + language css;\n + `a { $props }` where { $props <: contains `aspect-ratio: $x` }\n \n - - file: ./others/test_move_import.md\n +- file: ./others/test_move_import.md\n \n\n.grit/patterns/dependency.grit:\n -language json\n -\n +language json;\n pattern upgrade_dependency($target_dep, $target_version, $dependency_key) {\n - or {\n - `$key: $value` where {\n - $key <: `\"$target_dep\"`,\n - $value => `\"$target_version\"`\n - },\n - pair($key, $value) where {\n - $key <: `\"$dependency_key\"`,\n - $value <: object($properties) where {\n - $properties <: not contains pair(key=$dep_key) where {\n - $dep_key <: contains `$target_dep`\n - },\n - $properties => `\"$target_dep\": \"$target_version\",\\n$properties`\n - }\n - }\n - }\n -}\n +\tor {\n +\t\t`$key: $value` where {\n +\t\t\t$key <: `\"$target_dep\"`,\n +\t\t\t$value => `\"$target_version\"`\n +\t\t},\n +\t\tpair($key, $value) where {\n +\t\t\t$key <: `\"$dependency_key\"`,\n +\t\t\t$value <: object($properties) where {\n +\t\t\t\t$properties <: notcontains pair(key = $dep_key) where {\n +\t\t\t\t\t$dep_key <: contains `$target_dep`\n +\t\t\t\t},\n +\t\t\t\t$properties => `\"$target_dep\": \"$target_version\",\\n$properties`\n +\t\t\t}\n +\t\t}\n +\t}}\n \n pattern console_method_to_info($method) {\n - `console.$method($message)` => `console.info($message)`\n -}\n +\t`console.$method($message)` => `console.info($message)`}\n \n\n.grit/./others/test_move_import.md:\n tags: [private]\n ---\n ```grit\n -language js\n -\n +language js;\n `sanitizeFilePath` as $s where {\n - move_import(`sanitizeFilePath`, `'@getgrit/universal'`)\n +\tmove_import(`sanitizeFilePath`, `'@getgrit/universal'`)\n }\n ```\n \n\n" diff --git a/crates/cli_bin/tests/snapshots/format__format_patterns_with_rewrite.snap b/crates/cli_bin/tests/snapshots/format__format_patterns_with_rewrite.snap index fae2166a6..533fba4f7 100644 --- a/crates/cli_bin/tests/snapshots/format__format_patterns_with_rewrite.snap +++ b/crates/cli_bin/tests/snapshots/format__format_patterns_with_rewrite.snap @@ -6,4 +6,4 @@ snapshot_kind: text - "version: 0.0.1\npatterns:\n- name: aspect_ratio_yaml\n description: Yaml version of aspect_ratio.md\n body: |+\n language css;\n `a { $props }` where { $props <: contains `aspect-ratio: $x` }\n\n- file: ./others/test_move_import.md\n" - "---\nprivate: true\ntags: [private]\n---\n```grit\nlanguage js;\n`sanitizeFilePath` as $s where {\n\tmove_import(`sanitizeFilePath`, `'@getgrit/universal'`)\n}\n```\n" - "---\ntitle: Aspect ratio\n---\n\n```grit\nlanguage css;\n`a { $props }` where { $props <: contains `aspect-ratio: $x` }\n```\n\n## Matches the right selector and declaration block\n\n```css\na {\n width: calc(100% - 80px);\n aspect-ratio: 1/2;\n font-size: calc(10px + (56 - 10) * ((100vw - 320px) / (1920 - 320)));\n}\n\n#some-id {\n some-property: 5px;\n}\n\na.b ~ c.d {\n}\n.e.f + .g.h {\n}\n\n@font-face {\n font-family: 'Open Sans';\n src: url('/a') format('woff2'), url('/b/c') format('woff');\n}\n```\n\n```css\na {\n width: calc(100% - 80px);\n aspect-ratio: 1/2;\n font-size: calc(10px + (56 - 10) * ((100vw - 320px) / (1920 - 320)));\n}\n\n#some-id {\n some-property: 5px;\n}\n\na.b ~ c.d {\n}\n.e.f + .g.h {\n}\n\n@font-face {\n font-family: 'Open Sans';\n src: url('/a') format('woff2'), url('/b/c') format('woff');\n}\n```\n" -- "language json\n\npattern upgrade_dependency($target_dep, $target_version, $dependency_key) {\n\tor {\n\t\t`$key: $value` where {\n\t\t\t$key <: `\"$target_dep\"`,\n\t\t\t$value => `\"$target_version\"`\n\t\t},\n\t\tpair($key, $value) where {\n\t\t\t$key <: `\"$dependency_key\"`,\n\t\t\t$value <: object($properties) where {\n\t\t\t\t$properties <: notcontains pair(key = $dep_key) where {\n\t\t\t\t\t$dep_key <: contains `$target_dep`\n\t\t\t\t},\n\t\t\t\t$properties => `\"$target_dep\": \"$target_version\",\\n$properties`\n\t\t\t}\n\t\t}\n\t}}\n\npattern console_method_to_info($method) {\n\t`console.$method($message)` => `console.info($message)`}\n" +- "language json;\npattern upgrade_dependency($target_dep, $target_version, $dependency_key) {\n\tor {\n\t\t`$key: $value` where {\n\t\t\t$key <: `\"$target_dep\"`,\n\t\t\t$value => `\"$target_version\"`\n\t\t},\n\t\tpair($key, $value) where {\n\t\t\t$key <: `\"$dependency_key\"`,\n\t\t\t$value <: object($properties) where {\n\t\t\t\t$properties <: notcontains pair(key = $dep_key) where {\n\t\t\t\t\t$dep_key <: contains `$target_dep`\n\t\t\t\t},\n\t\t\t\t$properties => `\"$target_dep\": \"$target_version\",\\n$properties`\n\t\t\t}\n\t\t}\n\t}}\n\npattern console_method_to_info($method) {\n\t`console.$method($message)` => `console.info($message)`}\n" From 570ff55339451616d680baf0313e08cc90a9c956 Mon Sep 17 00:00:00 2001 From: Arian Rezazadeh Date: Sat, 4 Jan 2025 10:43:12 +0330 Subject: [PATCH 16/31] revert: grit range pointing at pattern definition --- crates/gritmodule/src/dot_grit.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/gritmodule/src/dot_grit.rs b/crates/gritmodule/src/dot_grit.rs index de44d247e..e48c6281d 100644 --- a/crates/gritmodule/src/dot_grit.rs +++ b/crates/gritmodule/src/dot_grit.rs @@ -61,15 +61,15 @@ pub fn get_patterns_from_grit( }; let range = Range::new( Position::new( - pattern_definition.node.start_position().row() + 1, - pattern_definition.node.start_position().column() + 1, + name_node.node.start_position().row() + 1, + name_node.node.start_position().column() + 1, ), Position::new( - pattern_definition.node.end_position().row() + 1, - pattern_definition.node.end_position().column() + 1, + name_node.node.end_position().row() + 1, + name_node.node.end_position().column() + 1, ), - pattern_definition.node.start_byte(), - pattern_definition.node.end_byte(), + name_node.node.start_byte(), + name_node.node.end_byte(), ); let module_grit_pattern = ModuleGritPattern { From 828a2b5ab4bd8ed0d2475dedf23fd9bde52b1cfc Mon Sep 17 00:00:00 2001 From: Arian Rezazadeh Date: Sat, 4 Jan 2025 10:48:02 +0330 Subject: [PATCH 17/31] feat: unwrap instead of returning error when it's safe --- crates/cli/src/commands/format.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/crates/cli/src/commands/format.rs b/crates/cli/src/commands/format.rs index e6861357b..87187360e 100644 --- a/crates/cli/src/commands/format.rs +++ b/crates/cli/src/commands/format.rs @@ -56,12 +56,10 @@ async fn format_file_resovled_patterns( patterns: Vec, arg: FormatArgs, ) -> Result<()> { + // patterns has atleast one resolve so unwrap is safe let first_pattern = patterns.first().unwrap(); - let first_pattern_raw_data = first_pattern - .config - .raw - .as_ref() - .ok_or_else(|| anyhow!("pattern does not have config raw data"))?; + // currently all patterns has raw data so unwrap is safe + let first_pattern_raw_data = first_pattern.config.raw.as_ref().unwrap(); let old_file_content = &first_pattern_raw_data.content; let new_file_content = match first_pattern_raw_data.format { From 3dcc7191a843c58d1152dbc7568d356356d760fe Mon Sep 17 00:00:00 2001 From: Arian Rezazadeh Date: Sat, 4 Jan 2025 10:50:34 +0330 Subject: [PATCH 18/31] chore: format yaml.rs --- crates/gritmodule/src/yaml.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/gritmodule/src/yaml.rs b/crates/gritmodule/src/yaml.rs index 86cc9586f..593708c8d 100644 --- a/crates/gritmodule/src/yaml.rs +++ b/crates/gritmodule/src/yaml.rs @@ -42,8 +42,8 @@ pub fn get_grit_config(source: &str, source_path: &str) -> Result { let mut definitation = GritDefinitionConfig::from_serialized(p, source_path.to_string()); definitation.raw = Some(RawGritDefinition { + format: PatternFileExt::Yaml, content: source.to_owned(), - format: crate::parser::PatternFileExt::Yaml, }); patterns.push(definitation); } From 9a13522233448ff354a2dfb7240792fa000843d0 Mon Sep 17 00:00:00 2001 From: Arian Rezazadeh Date: Sat, 4 Jan 2025 10:55:36 +0330 Subject: [PATCH 19/31] chore: remove todo question that i need to ask in review --- crates/cli/Cargo.toml | 1 - crates/cli/src/commands/format.rs | 3 --- 2 files changed, 4 deletions(-) diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 66324354d..95ab2ce91 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -20,7 +20,6 @@ anyhow = { version = "1.0.70" } clap = { version = "4.1.13", features = ["derive"] } indicatif = { version = "0.17.5" } # Do *NOT* upgrade beyond 1.0.171 until https://github.com/serde-rs/serde/issues/2538 is fixed -# TODO: ask if above note is still important serde = { version = "1.0.217", features = ["derive"] } serde_json = { version = "1.0.96" } serde_yaml = { version = "0.9.25" } diff --git a/crates/cli/src/commands/format.rs b/crates/cli/src/commands/format.rs index 87187360e..64eef4078 100644 --- a/crates/cli/src/commands/format.rs +++ b/crates/cli/src/commands/format.rs @@ -22,8 +22,6 @@ pub async fn run_format(arg: &FormatArgs) -> Result<()> { resolved.sort(); let file_path_to_resolved = group_resolved_patterns_by_group(resolved); - - // TODO: this can be easilly runned in parallel, just the test that reads stdout will get failed for (file_path, resovled_patterns) in file_path_to_resolved { if let Err(error) = format_file_resovled_patterns(file_path.clone(), resovled_patterns, arg.clone()).await @@ -93,7 +91,6 @@ async fn format_file_resovled_patterns( Ok(()) } -// TODO: ask if it's ok to format whole yaml file fn format_yaml_file(file_content: &str) -> Result { // deserializing manually and not using `SerializedGritConfig` because // i don't want to remove any fields that `SerializedGritConfig` don't have such as 'version' From 1c11a9f3254b1f586c2bc286116c35af606b484b Mon Sep 17 00:00:00 2001 From: Arian Rezazadeh Date: Tue, 7 Jan 2025 14:57:35 +0330 Subject: [PATCH 20/31] refactor: return some errors instead of unwrapping --- crates/cli/src/commands/format.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/crates/cli/src/commands/format.rs b/crates/cli/src/commands/format.rs index 64eef4078..11d605e3f 100644 --- a/crates/cli/src/commands/format.rs +++ b/crates/cli/src/commands/format.rs @@ -54,10 +54,14 @@ async fn format_file_resovled_patterns( patterns: Vec, arg: FormatArgs, ) -> Result<()> { - // patterns has atleast one resolve so unwrap is safe - let first_pattern = patterns.first().unwrap(); - // currently all patterns has raw data so unwrap is safe - let first_pattern_raw_data = first_pattern.config.raw.as_ref().unwrap(); + let first_pattern = patterns + .first() + .ok_or_else(|| anyhow!("patterns is empty"))?; + let first_pattern_raw_data = first_pattern + .config + .raw + .as_ref() + .ok_or_else(|| anyhow!("pattern doesn't have raw data"))?; let old_file_content = &first_pattern_raw_data.content; let new_file_content = match first_pattern_raw_data.format { From e97fba850a7464150f8b826998c5c22192221706 Mon Sep 17 00:00:00 2001 From: Arian Rezazadeh Date: Tue, 7 Jan 2025 15:01:34 +0330 Subject: [PATCH 21/31] chore: fix typos --- crates/cli/src/commands/format.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/cli/src/commands/format.rs b/crates/cli/src/commands/format.rs index 11d605e3f..f091f60e6 100644 --- a/crates/cli/src/commands/format.rs +++ b/crates/cli/src/commands/format.rs @@ -22,9 +22,9 @@ pub async fn run_format(arg: &FormatArgs) -> Result<()> { resolved.sort(); let file_path_to_resolved = group_resolved_patterns_by_group(resolved); - for (file_path, resovled_patterns) in file_path_to_resolved { + for (file_path, resolved_patterns) in file_path_to_resolved { if let Err(error) = - format_file_resovled_patterns(file_path.clone(), resovled_patterns, arg.clone()).await + format_file_resolved_patterns(file_path.clone(), resolved_patterns, arg.clone()).await { eprintln!("couldn't format '{}': {error:?}", file_path) } @@ -49,7 +49,7 @@ fn group_resolved_patterns_by_group( }) } -async fn format_file_resovled_patterns( +async fn format_file_resolved_patterns( file_path: String, patterns: Vec, arg: FormatArgs, From 54076c7f329f66712db178d78ba8147b5348a2d1 Mon Sep 17 00:00:00 2001 From: Arian Rezazadeh Date: Tue, 7 Jan 2025 15:38:22 +0330 Subject: [PATCH 22/31] feat: format files in parallel --- crates/cli/src/commands/format.rs | 50 +++++++++++-------- .../snapshots/format__format_patterns.snap | 2 +- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/crates/cli/src/commands/format.rs b/crates/cli/src/commands/format.rs index f091f60e6..69a359307 100644 --- a/crates/cli/src/commands/format.rs +++ b/crates/cli/src/commands/format.rs @@ -1,12 +1,13 @@ use crate::{ resolver::{resolve_from_cwd, Source}, - ux::format_diff, + ux::{format_diff, DiffString}, }; use anyhow::{anyhow, ensure, Context, Result}; use biome_grit_formatter::context::GritFormatOptions; use clap::Args; use colored::Colorize; use marzano_gritmodule::{config::ResolvedGritDefinition, parser::PatternFileExt}; +use rayon::iter::{IntoParallelIterator, ParallelIterator}; use serde::Serialize; #[derive(Args, Debug, Serialize, Clone)] @@ -17,16 +18,28 @@ pub struct FormatArgs { } pub async fn run_format(arg: &FormatArgs) -> Result<()> { - let (mut resolved, _) = resolve_from_cwd(&Source::Local).await?; - // sort to have consistent output for tests - resolved.sort(); + let (resolved, _) = resolve_from_cwd(&Source::Local).await?; let file_path_to_resolved = group_resolved_patterns_by_group(resolved); - for (file_path, resolved_patterns) in file_path_to_resolved { - if let Err(error) = - format_file_resolved_patterns(file_path.clone(), resolved_patterns, arg.clone()).await - { - eprintln!("couldn't format '{}': {error:?}", file_path) + let mut results = file_path_to_resolved + .into_par_iter() + .map(|(file_path, resolved_patterns)| { + ( + file_path.clone(), + format_file_resolved_patterns(file_path, resolved_patterns, arg.clone()), + ) + }) + .collect::>(); + + // sort outputs to ensure consistent stdout output + // also avoid using sort_by_key to prevent additional cloning of file_path + results.sort_by(|(file_path, _), (other_file_path, _)| file_path.cmp(&other_file_path)); + + for (file_path, result) in results { + match result { + Err(error) => eprintln!("couldn't format '{}': {error:?}", file_path), + Ok(Some(diff)) => println!("{}:\n{}", file_path.bold(), diff), + Ok(None) => (), // `args.write` is true or file is already formated } } Ok(()) @@ -49,11 +62,11 @@ fn group_resolved_patterns_by_group( }) } -async fn format_file_resolved_patterns( +fn format_file_resolved_patterns( file_path: String, patterns: Vec, arg: FormatArgs, -) -> Result<()> { +) -> Result> { let first_pattern = patterns .first() .ok_or_else(|| anyhow!("patterns is empty"))?; @@ -77,22 +90,15 @@ async fn format_file_resolved_patterns( }; if &new_file_content == old_file_content { - return Ok(()); + return Ok(None); } if arg.write { - tokio::fs::write(file_path, new_file_content) - .await - .with_context(|| "could not write to file")?; + std::fs::write(file_path, new_file_content).with_context(|| "could not write to file")?; + Ok(None) } else { - println!( - "{}:\n{}", - file_path.bold(), - format_diff(old_file_content, &new_file_content) - ); + Ok(Some(format_diff(old_file_content, &new_file_content))) } - - Ok(()) } fn format_yaml_file(file_content: &str) -> Result { diff --git a/crates/cli_bin/tests/snapshots/format__format_patterns.snap b/crates/cli_bin/tests/snapshots/format__format_patterns.snap index 8aa54338e..24a4cbab1 100644 --- a/crates/cli_bin/tests/snapshots/format__format_patterns.snap +++ b/crates/cli_bin/tests/snapshots/format__format_patterns.snap @@ -3,4 +3,4 @@ source: crates/cli_bin/tests/format.rs expression: "String::from_utf8(output.stdout)?" snapshot_kind: text --- -".grit/patterns/aspect_ratio.md:\n ---\n \n ```grit\n -language css\n -\n -`a { $props }` where {\n - $props <: contains `aspect-ratio: $x`\n -}\n +language css;\n +`a { $props }` where { $props <: contains `aspect-ratio: $x` }\n ```\n \n ## Matches the right selector and declaration block\n \n\n.grit/grit.yaml:\n version: 0.0.1\n patterns:\n - - name: aspect_ratio_yaml\n - description: Yaml version of aspect_ratio.md\n - body: |\n - language css\n -\n - `a { $props }` where {\n - $props <: contains `aspect-ratio: $x`\n - }\n +- name: aspect_ratio_yaml\n + description: Yaml version of aspect_ratio.md\n + body: |+\n + language css;\n + `a { $props }` where { $props <: contains `aspect-ratio: $x` }\n \n - - file: ./others/test_move_import.md\n +- file: ./others/test_move_import.md\n \n\n.grit/patterns/dependency.grit:\n -language json\n -\n +language json;\n pattern upgrade_dependency($target_dep, $target_version, $dependency_key) {\n - or {\n - `$key: $value` where {\n - $key <: `\"$target_dep\"`,\n - $value => `\"$target_version\"`\n - },\n - pair($key, $value) where {\n - $key <: `\"$dependency_key\"`,\n - $value <: object($properties) where {\n - $properties <: not contains pair(key=$dep_key) where {\n - $dep_key <: contains `$target_dep`\n - },\n - $properties => `\"$target_dep\": \"$target_version\",\\n$properties`\n - }\n - }\n - }\n -}\n +\tor {\n +\t\t`$key: $value` where {\n +\t\t\t$key <: `\"$target_dep\"`,\n +\t\t\t$value => `\"$target_version\"`\n +\t\t},\n +\t\tpair($key, $value) where {\n +\t\t\t$key <: `\"$dependency_key\"`,\n +\t\t\t$value <: object($properties) where {\n +\t\t\t\t$properties <: notcontains pair(key = $dep_key) where {\n +\t\t\t\t\t$dep_key <: contains `$target_dep`\n +\t\t\t\t},\n +\t\t\t\t$properties => `\"$target_dep\": \"$target_version\",\\n$properties`\n +\t\t\t}\n +\t\t}\n +\t}}\n \n pattern console_method_to_info($method) {\n - `console.$method($message)` => `console.info($message)`\n -}\n +\t`console.$method($message)` => `console.info($message)`}\n \n\n.grit/./others/test_move_import.md:\n tags: [private]\n ---\n ```grit\n -language js\n -\n +language js;\n `sanitizeFilePath` as $s where {\n - move_import(`sanitizeFilePath`, `'@getgrit/universal'`)\n +\tmove_import(`sanitizeFilePath`, `'@getgrit/universal'`)\n }\n ```\n \n\n" +".grit/./others/test_move_import.md:\n tags: [private]\n ---\n ```grit\n -language js\n -\n +language js;\n `sanitizeFilePath` as $s where {\n - move_import(`sanitizeFilePath`, `'@getgrit/universal'`)\n +\tmove_import(`sanitizeFilePath`, `'@getgrit/universal'`)\n }\n ```\n \n\n.grit/grit.yaml:\n version: 0.0.1\n patterns:\n - - name: aspect_ratio_yaml\n - description: Yaml version of aspect_ratio.md\n - body: |\n - language css\n -\n - `a { $props }` where {\n - $props <: contains `aspect-ratio: $x`\n - }\n +- name: aspect_ratio_yaml\n + description: Yaml version of aspect_ratio.md\n + body: |+\n + language css;\n + `a { $props }` where { $props <: contains `aspect-ratio: $x` }\n \n - - file: ./others/test_move_import.md\n +- file: ./others/test_move_import.md\n \n\n.grit/patterns/aspect_ratio.md:\n ---\n \n ```grit\n -language css\n -\n -`a { $props }` where {\n - $props <: contains `aspect-ratio: $x`\n -}\n +language css;\n +`a { $props }` where { $props <: contains `aspect-ratio: $x` }\n ```\n \n ## Matches the right selector and declaration block\n \n\n.grit/patterns/dependency.grit:\n -language json\n -\n +language json;\n pattern upgrade_dependency($target_dep, $target_version, $dependency_key) {\n - or {\n - `$key: $value` where {\n - $key <: `\"$target_dep\"`,\n - $value => `\"$target_version\"`\n - },\n - pair($key, $value) where {\n - $key <: `\"$dependency_key\"`,\n - $value <: object($properties) where {\n - $properties <: not contains pair(key=$dep_key) where {\n - $dep_key <: contains `$target_dep`\n - },\n - $properties => `\"$target_dep\": \"$target_version\",\\n$properties`\n - }\n - }\n - }\n -}\n +\tor {\n +\t\t`$key: $value` where {\n +\t\t\t$key <: `\"$target_dep\"`,\n +\t\t\t$value => `\"$target_version\"`\n +\t\t},\n +\t\tpair($key, $value) where {\n +\t\t\t$key <: `\"$dependency_key\"`,\n +\t\t\t$value <: object($properties) where {\n +\t\t\t\t$properties <: notcontains pair(key = $dep_key) where {\n +\t\t\t\t\t$dep_key <: contains `$target_dep`\n +\t\t\t\t},\n +\t\t\t\t$properties => `\"$target_dep\": \"$target_version\",\\n$properties`\n +\t\t\t}\n +\t\t}\n +\t}}\n \n pattern console_method_to_info($method) {\n - `console.$method($message)` => `console.info($message)`\n -}\n +\t`console.$method($message)` => `console.info($message)`}\n \n\n" From b049607c534ff176c8637801b181962e5c651622 Mon Sep 17 00:00:00 2001 From: Arian Rezazadeh Date: Tue, 7 Jan 2025 16:44:05 +0330 Subject: [PATCH 23/31] refactor: remove useless reference --- crates/cli/src/commands/format.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/cli/src/commands/format.rs b/crates/cli/src/commands/format.rs index 69a359307..f5bafdb02 100644 --- a/crates/cli/src/commands/format.rs +++ b/crates/cli/src/commands/format.rs @@ -33,7 +33,7 @@ pub async fn run_format(arg: &FormatArgs) -> Result<()> { // sort outputs to ensure consistent stdout output // also avoid using sort_by_key to prevent additional cloning of file_path - results.sort_by(|(file_path, _), (other_file_path, _)| file_path.cmp(&other_file_path)); + results.sort_by(|(file_path, _), (other_file_path, _)| file_path.cmp(other_file_path)); for (file_path, result) in results { match result { From a977855644d7063532c90f935d9181e0f93b6067 Mon Sep 17 00:00:00 2001 From: Arian Rezazadeh Date: Tue, 7 Jan 2025 22:00:35 +0330 Subject: [PATCH 24/31] test: remove format_patterns test that snapshots the stdout --- crates/cli_bin/tests/format.rs | 19 ------------------- .../snapshots/format__format_patterns.snap | 6 ------ 2 files changed, 25 deletions(-) delete mode 100644 crates/cli_bin/tests/snapshots/format__format_patterns.snap diff --git a/crates/cli_bin/tests/format.rs b/crates/cli_bin/tests/format.rs index 4bef9aa33..0a5109272 100644 --- a/crates/cli_bin/tests/format.rs +++ b/crates/cli_bin/tests/format.rs @@ -5,25 +5,6 @@ use insta::assert_yaml_snapshot; mod common; -#[test] -fn format_patterns() -> Result<()> { - let (_temp_dir, grit_dir) = get_fixture("unformatted_patterns", true)?; - - let mut cmd = get_test_cmd()?; - cmd.arg("format").current_dir(grit_dir.clone()); - let output = cmd.output()?; - - println!("stderr: {}", String::from_utf8(output.stderr.clone())?); - println!("stdout: {}", String::from_utf8(output.stdout.clone())?); - - assert!( - output.status.success(), - "Command didn't finish successfully" - ); - assert_yaml_snapshot!(String::from_utf8(output.stdout)?); - Ok(()) -} - #[test] fn format_patterns_with_rewrite() -> Result<()> { let (_temp_dir, grit_dir) = get_fixture("unformatted_patterns", true)?; diff --git a/crates/cli_bin/tests/snapshots/format__format_patterns.snap b/crates/cli_bin/tests/snapshots/format__format_patterns.snap deleted file mode 100644 index 24a4cbab1..000000000 --- a/crates/cli_bin/tests/snapshots/format__format_patterns.snap +++ /dev/null @@ -1,6 +0,0 @@ ---- -source: crates/cli_bin/tests/format.rs -expression: "String::from_utf8(output.stdout)?" -snapshot_kind: text ---- -".grit/./others/test_move_import.md:\n tags: [private]\n ---\n ```grit\n -language js\n -\n +language js;\n `sanitizeFilePath` as $s where {\n - move_import(`sanitizeFilePath`, `'@getgrit/universal'`)\n +\tmove_import(`sanitizeFilePath`, `'@getgrit/universal'`)\n }\n ```\n \n\n.grit/grit.yaml:\n version: 0.0.1\n patterns:\n - - name: aspect_ratio_yaml\n - description: Yaml version of aspect_ratio.md\n - body: |\n - language css\n -\n - `a { $props }` where {\n - $props <: contains `aspect-ratio: $x`\n - }\n +- name: aspect_ratio_yaml\n + description: Yaml version of aspect_ratio.md\n + body: |+\n + language css;\n + `a { $props }` where { $props <: contains `aspect-ratio: $x` }\n \n - - file: ./others/test_move_import.md\n +- file: ./others/test_move_import.md\n \n\n.grit/patterns/aspect_ratio.md:\n ---\n \n ```grit\n -language css\n -\n -`a { $props }` where {\n - $props <: contains `aspect-ratio: $x`\n -}\n +language css;\n +`a { $props }` where { $props <: contains `aspect-ratio: $x` }\n ```\n \n ## Matches the right selector and declaration block\n \n\n.grit/patterns/dependency.grit:\n -language json\n -\n +language json;\n pattern upgrade_dependency($target_dep, $target_version, $dependency_key) {\n - or {\n - `$key: $value` where {\n - $key <: `\"$target_dep\"`,\n - $value => `\"$target_version\"`\n - },\n - pair($key, $value) where {\n - $key <: `\"$dependency_key\"`,\n - $value <: object($properties) where {\n - $properties <: not contains pair(key=$dep_key) where {\n - $dep_key <: contains `$target_dep`\n - },\n - $properties => `\"$target_dep\": \"$target_version\",\\n$properties`\n - }\n - }\n - }\n -}\n +\tor {\n +\t\t`$key: $value` where {\n +\t\t\t$key <: `\"$target_dep\"`,\n +\t\t\t$value => `\"$target_version\"`\n +\t\t},\n +\t\tpair($key, $value) where {\n +\t\t\t$key <: `\"$dependency_key\"`,\n +\t\t\t$value <: object($properties) where {\n +\t\t\t\t$properties <: notcontains pair(key = $dep_key) where {\n +\t\t\t\t\t$dep_key <: contains `$target_dep`\n +\t\t\t\t},\n +\t\t\t\t$properties => `\"$target_dep\": \"$target_version\",\\n$properties`\n +\t\t\t}\n +\t\t}\n +\t}}\n \n pattern console_method_to_info($method) {\n - `console.$method($message)` => `console.info($message)`\n -}\n +\t`console.$method($message)` => `console.info($message)`}\n \n\n" From f593bdd3397a7b371ea619c836694d4c02bd6abd Mon Sep 17 00:00:00 2001 From: Arian Rezazadeh Date: Wed, 8 Jan 2025 00:10:13 +0330 Subject: [PATCH 25/31] test: add test for not parsable patterns --- .../.grit/patterns/not_parsable.grit | 10 ++++++++++ crates/cli_bin/tests/format.rs | 1 + 2 files changed, 11 insertions(+) create mode 100644 crates/cli_bin/fixtures/unformatted_patterns/.grit/patterns/not_parsable.grit diff --git a/crates/cli_bin/fixtures/unformatted_patterns/.grit/patterns/not_parsable.grit b/crates/cli_bin/fixtures/unformatted_patterns/.grit/patterns/not_parsable.grit new file mode 100644 index 000000000..44f204705 --- /dev/null +++ b/crates/cli_bin/fixtures/unformatted_patterns/.grit/patterns/not_parsable.grit @@ -0,0 +1,10 @@ +language json + +pattern some_pattern($target_dep, $target_version) { + or { + `$key: $value` where { + $key <: `"$target_dep"`, + no_meta_variable => `"$target_version"` + }, + } +} diff --git a/crates/cli_bin/tests/format.rs b/crates/cli_bin/tests/format.rs index 0a5109272..67081ad4a 100644 --- a/crates/cli_bin/tests/format.rs +++ b/crates/cli_bin/tests/format.rs @@ -23,6 +23,7 @@ fn format_patterns_with_rewrite() -> Result<()> { output.status.success(), "Command didn't finish successfully" ); + assert_eq!(output.stderr, b"couldn't format '.grit/patterns/not_parsable.grit': biome couldn't parse: Expected a predicate here.\n"); let yaml_file_content = std::fs::read_to_string(grit_dir.join(".grit/grit.yaml"))?; let test_move_import_file_content = From 9e7c24b6eb5ae0fd869af2da3033c7a27cf9bd80 Mon Sep 17 00:00:00 2001 From: Arian Rezazadeh Date: Fri, 10 Jan 2025 21:29:47 +0330 Subject: [PATCH 26/31] feat: use grit pattern to find and replace grit code in yaml --- Cargo.lock | 1 - crates/cli/Cargo.toml | 1 - crates/cli/src/commands/format.rs | 104 ++++++++++++++---- .../unformatted_patterns/.grit/grit.yaml | 9 ++ .../format__format_patterns_with_rewrite.snap | 2 +- 5 files changed, 92 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bbf55302b..178f2f5cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2603,7 +2603,6 @@ dependencies = [ "reqwest 0.11.24", "serde", "serde_json", - "serde_yaml", "similar", "tempfile", "tokio", diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 95ab2ce91..dde1773a0 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -22,7 +22,6 @@ indicatif = { version = "0.17.5" } # Do *NOT* upgrade beyond 1.0.171 until https://github.com/serde-rs/serde/issues/2538 is fixed serde = { version = "1.0.217", features = ["derive"] } serde_json = { version = "1.0.96" } -serde_yaml = { version = "0.9.25" } uuid = { version = "1.1", features = ["v4", "serde"] } tokio = { version = "1", features = ["full"] } chrono = { version = "0.4.26", features = ["serde"] } diff --git a/crates/cli/src/commands/format.rs b/crates/cli/src/commands/format.rs index f5bafdb02..91c5b8413 100644 --- a/crates/cli/src/commands/format.rs +++ b/crates/cli/src/commands/format.rs @@ -1,14 +1,17 @@ use crate::{ - resolver::{resolve_from_cwd, Source}, + resolver::{resolve_from_cwd, GritModuleResolver, Source}, ux::{format_diff, DiffString}, }; -use anyhow::{anyhow, ensure, Context, Result}; +use anyhow::{anyhow, bail, ensure, Context, Result}; use biome_grit_formatter::context::GritFormatOptions; use clap::Args; use colored::Colorize; +use marzano_core::api::MatchResult; use marzano_gritmodule::{config::ResolvedGritDefinition, parser::PatternFileExt}; +use marzano_util::{rich_path::RichFile, runtime::ExecutionContext}; use rayon::iter::{IntoParallelIterator, ParallelIterator}; use serde::Serialize; +use std::collections::BTreeMap; #[derive(Args, Debug, Serialize, Clone)] pub struct FormatArgs { @@ -78,7 +81,7 @@ fn format_file_resolved_patterns( let old_file_content = &first_pattern_raw_data.content; let new_file_content = match first_pattern_raw_data.format { - PatternFileExt::Yaml => format_yaml_file(old_file_content)?, + PatternFileExt::Yaml => format_yaml_file(patterns.clone(), old_file_content)?, PatternFileExt::Grit => format_grit_code(old_file_content)?, PatternFileExt::Md => { let hunks = patterns @@ -101,27 +104,84 @@ fn format_file_resolved_patterns( } } -fn format_yaml_file(file_content: &str) -> Result { - // deserializing manually and not using `SerializedGritConfig` because - // i don't want to remove any fields that `SerializedGritConfig` don't have such as 'version' - let mut config: serde_yaml::Value = - serde_yaml::from_str(file_content).with_context(|| "couldn't parse yaml file")?; - let patterns = config - .get_mut("patterns") - .ok_or_else(|| anyhow!("couldn't find patterns in yaml file"))? - .as_sequence_mut() - .ok_or_else(|| anyhow!("patterns in yaml file are not sequence"))?; - for pattern in patterns { - let Some(body) = pattern.get_mut("body") else { - continue; - }; - if let serde_yaml::Value::String(body_str) = body { - *body_str = format_grit_code(body_str)?; - // extra new line at end of grit body looks more readable - body_str.push('\n'); +/// bubble clause that finds a grit pattern with name "" in yaml and +/// replaces it's body to new_body, `format_yaml_file` uses this pattern to replace +/// pattern bodies with formatted ones +const YAML_REPLACE_BODY_PATERN: &'static str = r#" + bubble file($body) where { + $body <: contains block_mapping(items=$items) where { + $items <: within `patterns: $_`, + $items <: contains `name: $name`, + $name <: "", + $items <: contains `body: $yaml_body`, + $new_body = "", + $yaml_body => $new_body + }, + } +"#; + +/// format each pattern and use gritql pattern to match and rewrite +fn format_yaml_file(patterns: Vec, file_content: &str) -> Result { + let bubbles = patterns + .iter() + .map(|pattern| { + let formatted_body = format_grit_code(&pattern.body) + .with_context(|| format!("could not format '{}'", pattern.name()))?; + let bubble = YAML_REPLACE_BODY_PATERN + .replace("", pattern.name()) + .replace("", &format_yaml_body_code(&formatted_body)); + Ok(bubble) + }) + .collect::>>()? + .join(",\n"); + let pattern_body = format!("language yaml\nsequential{{ {bubbles} }}"); + apply_grit_rewrite(file_content, &pattern_body) +} + +fn format_yaml_body_code(input: &str) -> String { + // yaml body still needs two indentation to look good + let body_with_prefix = prefix_lines(&input, &" ".repeat(2)); + let escaped_body = body_with_prefix.replace("\"", "\\\""); + // body: | + // escaped_body + format!("|\n{escaped_body}") +} + +fn prefix_lines(input: &str, prefix: &str) -> String { + input + .lines() + .map(|line| { + if line.is_empty() { + line.to_owned() + } else { + format!("{prefix}{line}") + } + }) + .collect::>() + .join("\n") +} + +fn apply_grit_rewrite(input: &str, pattern: &str) -> Result { + let resolver = GritModuleResolver::new(); + let rich_pattern = resolver.make_pattern(&pattern, None)?; + + let compiled = rich_pattern + .compile(&BTreeMap::new(), None, None, None) + .map(|cr| cr.problem) + .with_context(|| "could not compile pattern")?; + + let rich_file = RichFile::new(String::new(), input.to_owned()); + let runtime = ExecutionContext::default(); + for result in compiled.execute_file(&rich_file, &runtime) { + if let MatchResult::Rewrite(rewrite) = result { + let content = rewrite + .rewritten + .content + .ok_or_else(|| anyhow!("rewritten content is empty"))?; + return Ok(content); } } - Ok(serde_yaml::to_string(&config)?) + bail!("no rewrite result after applying grit pattern") } fn format_pattern_as_hunk_changes(pattern: &ResolvedGritDefinition) -> Result { diff --git a/crates/cli_bin/fixtures/unformatted_patterns/.grit/grit.yaml b/crates/cli_bin/fixtures/unformatted_patterns/.grit/grit.yaml index e85ad7894..58db20033 100644 --- a/crates/cli_bin/fixtures/unformatted_patterns/.grit/grit.yaml +++ b/crates/cli_bin/fixtures/unformatted_patterns/.grit/grit.yaml @@ -10,3 +10,12 @@ patterns: } - file: ./others/test_move_import.md + + - name: some_json_pattern + body: | + language json + + `account: $val` where { + $val <: contains `password: $password`, + $password => raw`hidden` + } diff --git a/crates/cli_bin/tests/snapshots/format__format_patterns_with_rewrite.snap b/crates/cli_bin/tests/snapshots/format__format_patterns_with_rewrite.snap index 533fba4f7..e0f02c9d0 100644 --- a/crates/cli_bin/tests/snapshots/format__format_patterns_with_rewrite.snap +++ b/crates/cli_bin/tests/snapshots/format__format_patterns_with_rewrite.snap @@ -3,7 +3,7 @@ source: crates/cli_bin/tests/format.rs expression: "vec![yaml_file_content, test_move_import_file_content,\naspect_ratio_md_file_content, dependency_grit_file_content]" snapshot_kind: text --- -- "version: 0.0.1\npatterns:\n- name: aspect_ratio_yaml\n description: Yaml version of aspect_ratio.md\n body: |+\n language css;\n `a { $props }` where { $props <: contains `aspect-ratio: $x` }\n\n- file: ./others/test_move_import.md\n" +- "version: 0.0.1\npatterns:\n - name: aspect_ratio_yaml\n description: Yaml version of aspect_ratio.md\n body: |\n language css;\n `a { $props }` where { $props <: contains `aspect-ratio: $x` }\n\n - file: ./others/test_move_import.md\n\n - name: some_json_pattern\n body: |\n language json;\n `account: $val` where {\n \t$val <: contains `password: $password`,\n \t$password => raw`hidden`\n }" - "---\nprivate: true\ntags: [private]\n---\n```grit\nlanguage js;\n`sanitizeFilePath` as $s where {\n\tmove_import(`sanitizeFilePath`, `'@getgrit/universal'`)\n}\n```\n" - "---\ntitle: Aspect ratio\n---\n\n```grit\nlanguage css;\n`a { $props }` where { $props <: contains `aspect-ratio: $x` }\n```\n\n## Matches the right selector and declaration block\n\n```css\na {\n width: calc(100% - 80px);\n aspect-ratio: 1/2;\n font-size: calc(10px + (56 - 10) * ((100vw - 320px) / (1920 - 320)));\n}\n\n#some-id {\n some-property: 5px;\n}\n\na.b ~ c.d {\n}\n.e.f + .g.h {\n}\n\n@font-face {\n font-family: 'Open Sans';\n src: url('/a') format('woff2'), url('/b/c') format('woff');\n}\n```\n\n```css\na {\n width: calc(100% - 80px);\n aspect-ratio: 1/2;\n font-size: calc(10px + (56 - 10) * ((100vw - 320px) / (1920 - 320)));\n}\n\n#some-id {\n some-property: 5px;\n}\n\na.b ~ c.d {\n}\n.e.f + .g.h {\n}\n\n@font-face {\n font-family: 'Open Sans';\n src: url('/a') format('woff2'), url('/b/c') format('woff');\n}\n```\n" - "language json;\npattern upgrade_dependency($target_dep, $target_version, $dependency_key) {\n\tor {\n\t\t`$key: $value` where {\n\t\t\t$key <: `\"$target_dep\"`,\n\t\t\t$value => `\"$target_version\"`\n\t\t},\n\t\tpair($key, $value) where {\n\t\t\t$key <: `\"$dependency_key\"`,\n\t\t\t$value <: object($properties) where {\n\t\t\t\t$properties <: notcontains pair(key = $dep_key) where {\n\t\t\t\t\t$dep_key <: contains `$target_dep`\n\t\t\t\t},\n\t\t\t\t$properties => `\"$target_dep\": \"$target_version\",\\n$properties`\n\t\t\t}\n\t\t}\n\t}}\n\npattern console_method_to_info($method) {\n\t`console.$method($message)` => `console.info($message)`}\n" From 0af5bf0ab83f8ec21debaed5555d6fbec58c0d35 Mon Sep 17 00:00:00 2001 From: Arian Rezazadeh Date: Sat, 11 Jan 2025 11:12:04 +0330 Subject: [PATCH 27/31] chore: fix comment --- crates/cli/src/commands/format.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/cli/src/commands/format.rs b/crates/cli/src/commands/format.rs index 91c5b8413..1f1a431e1 100644 --- a/crates/cli/src/commands/format.rs +++ b/crates/cli/src/commands/format.rs @@ -104,8 +104,8 @@ fn format_file_resolved_patterns( } } -/// bubble clause that finds a grit pattern with name "" in yaml and -/// replaces it's body to new_body, `format_yaml_file` uses this pattern to replace +/// bubble clause that finds a grit pattern with name "\" in yaml and +/// replaces it's body to "\", `format_yaml_file` uses this pattern to replace /// pattern bodies with formatted ones const YAML_REPLACE_BODY_PATERN: &'static str = r#" bubble file($body) where { From 409dcb37218e36119041292bf7c87bfee3dba322 Mon Sep 17 00:00:00 2001 From: Arian Rezazadeh Date: Sat, 11 Jan 2025 11:14:47 +0330 Subject: [PATCH 28/31] refactor: format_yaml_file take patterns by reference --- crates/cli/src/commands/format.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/cli/src/commands/format.rs b/crates/cli/src/commands/format.rs index 1f1a431e1..19e3c5023 100644 --- a/crates/cli/src/commands/format.rs +++ b/crates/cli/src/commands/format.rs @@ -81,7 +81,7 @@ fn format_file_resolved_patterns( let old_file_content = &first_pattern_raw_data.content; let new_file_content = match first_pattern_raw_data.format { - PatternFileExt::Yaml => format_yaml_file(patterns.clone(), old_file_content)?, + PatternFileExt::Yaml => format_yaml_file(&patterns, old_file_content)?, PatternFileExt::Grit => format_grit_code(old_file_content)?, PatternFileExt::Md => { let hunks = patterns @@ -121,7 +121,7 @@ const YAML_REPLACE_BODY_PATERN: &'static str = r#" "#; /// format each pattern and use gritql pattern to match and rewrite -fn format_yaml_file(patterns: Vec, file_content: &str) -> Result { +fn format_yaml_file(patterns: &[ResolvedGritDefinition], file_content: &str) -> Result { let bubbles = patterns .iter() .map(|pattern| { From 7bb262271a130f09e8b23ac2720116d97bb477ba Mon Sep 17 00:00:00 2001 From: Arian Rezazadeh Date: Sat, 11 Jan 2025 11:18:00 +0330 Subject: [PATCH 29/31] chore: fix clippy warnings --- crates/cli/src/commands/format.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/cli/src/commands/format.rs b/crates/cli/src/commands/format.rs index 19e3c5023..1e962299e 100644 --- a/crates/cli/src/commands/format.rs +++ b/crates/cli/src/commands/format.rs @@ -107,7 +107,7 @@ fn format_file_resolved_patterns( /// bubble clause that finds a grit pattern with name "\" in yaml and /// replaces it's body to "\", `format_yaml_file` uses this pattern to replace /// pattern bodies with formatted ones -const YAML_REPLACE_BODY_PATERN: &'static str = r#" +const YAML_REPLACE_BODY_PATERN: &str = r#" bubble file($body) where { $body <: contains block_mapping(items=$items) where { $items <: within `patterns: $_`, @@ -140,7 +140,7 @@ fn format_yaml_file(patterns: &[ResolvedGritDefinition], file_content: &str) -> fn format_yaml_body_code(input: &str) -> String { // yaml body still needs two indentation to look good - let body_with_prefix = prefix_lines(&input, &" ".repeat(2)); + let body_with_prefix = prefix_lines(input, &" ".repeat(2)); let escaped_body = body_with_prefix.replace("\"", "\\\""); // body: | // escaped_body @@ -163,7 +163,7 @@ fn prefix_lines(input: &str, prefix: &str) -> String { fn apply_grit_rewrite(input: &str, pattern: &str) -> Result { let resolver = GritModuleResolver::new(); - let rich_pattern = resolver.make_pattern(&pattern, None)?; + let rich_pattern = resolver.make_pattern(pattern, None)?; let compiled = rich_pattern .compile(&BTreeMap::new(), None, None, None) From 692673d7250fe2105c66f10f3ccd1d043e7033e3 Mon Sep 17 00:00:00 2001 From: Arian Rezazadeh Date: Sat, 11 Jan 2025 11:20:54 +0330 Subject: [PATCH 30/31] refactor: remove usesless clones --- crates/cli/src/commands/format.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/crates/cli/src/commands/format.rs b/crates/cli/src/commands/format.rs index 1e962299e..07d508502 100644 --- a/crates/cli/src/commands/format.rs +++ b/crates/cli/src/commands/format.rs @@ -27,10 +27,8 @@ pub async fn run_format(arg: &FormatArgs) -> Result<()> { let mut results = file_path_to_resolved .into_par_iter() .map(|(file_path, resolved_patterns)| { - ( - file_path.clone(), - format_file_resolved_patterns(file_path, resolved_patterns, arg.clone()), - ) + let result = format_file_resolved_patterns(&file_path, resolved_patterns, arg.clone()); + (file_path, result) }) .collect::>(); @@ -66,7 +64,7 @@ fn group_resolved_patterns_by_group( } fn format_file_resolved_patterns( - file_path: String, + file_path: &str, patterns: Vec, arg: FormatArgs, ) -> Result> { From ac8a0a878bf8452ce276ca18d99931f5069b284d Mon Sep 17 00:00:00 2001 From: Arian Rezazadeh Date: Sat, 11 Jan 2025 12:37:02 +0330 Subject: [PATCH 31/31] refactor: apply hunk changes in reverse to make our life easier --- crates/cli/src/commands/format.rs | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/crates/cli/src/commands/format.rs b/crates/cli/src/commands/format.rs index 07d508502..de6fa1160 100644 --- a/crates/cli/src/commands/format.rs +++ b/crates/cli/src/commands/format.rs @@ -228,17 +228,11 @@ fn apply_hunk_changes(input: &str, mut hunks: Vec) -> String { if hunks.is_empty() { return input.to_string(); } - hunks.sort_by_key(|hunk| hunk.starting_byte); - let mut buffer = String::new(); - let mut last_ending_byte = 0; - for (index, hunk) in hunks.iter().enumerate() { - buffer.push_str(&input[last_ending_byte..hunk.starting_byte]); - buffer.push_str(&hunk.new_content); - last_ending_byte = hunk.ending_byte; - - if index == hunks.len() - 1 { - buffer.push_str(&input[last_ending_byte..]); - } + hunks.sort_by_key(|hunk| -(hunk.starting_byte as isize)); + let mut buffer = input.to_owned(); + for hunk in hunks { + let hunk_range = hunk.starting_byte..hunk.ending_byte; + buffer.replace_range(hunk_range, &hunk.new_content); } buffer }