diff --git a/Cargo.lock b/Cargo.lock index 144b0db..8bb4f6f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,1065 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +dependencies = [ + "lazy_static", + "regex", +] + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "ariadne" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8454c8a44ce2cb9cc7e7fae67fc6128465b343b92c6631e94beca3c8d1524ea5" +dependencies = [ + "unicode-width", + "yansi", +] + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" + +[[package]] +name = "blake3" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2468ef7d57b3fb7e16b576e8377cdbde2320c60e1491e961d11da40fc4f02a2d" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "cpufeatures", +] + +[[package]] +name = "bstr" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "bumpalo" +version = "3.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" +dependencies = [ + "serde", +] + +[[package]] +name = "cc" +version = "1.2.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a0dd1ca384932ff3641c8718a02769f1698e7563dc6974ffd03346116310423" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "codespan-reporting" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af491d569909a7e4dee0ad7db7f5341fef5c614d5b8ec8cf765732aba3cff681" +dependencies = [ + "serde", + "termcolor", + "unicode-width", +] + +[[package]] +name = "constant_time_eq" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "fsevent-sys" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2" +dependencies = [ + "libc", +] + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "globset" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3" +dependencies = [ + "aho-corasick", + "bstr", + "log", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "inotify" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd5b3eaf1a28b758ac0faa5a4254e8ab2705605496f1b1f3fbbc3988ad73d199" +dependencies = [ + "bitflags 2.11.0", + "inotify-sys", + "libc", +] + +[[package]] +name = "inotify-sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +dependencies = [ + "libc", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "kqueue" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac30106d7dce88daf4a3fcb4879ea939476d5074a9b7ddd0fb97fa4bed5596a" +dependencies = [ + "kqueue-sys", + "libc", +] + +[[package]] +name = "kqueue-sys" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b" +dependencies = [ + "bitflags 1.3.2", + "libc", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.183" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "mago-database" +version = "1.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c7b10a23e6d5f1589de8809052b48d6523475cb7a4ab7fc1da783959f501074" +dependencies = [ + "foldhash", + "glob", + "globset", + "memchr", + "notify", + "rayon", + "serde", + "simdutf8", + "tracing", + "walkdir", +] + +[[package]] +name = "mago-php-version" +version = "1.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "735a537984399a6ef6b8284e156e72ad02d63921f46b97e241ee71cee2d2854b" +dependencies = [ + "schemars", + "serde", +] + +[[package]] +name = "mago-reporting" +version = "1.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b1f84031541e2848bfd59cfa2347260e799ba9a18ee7b732111170738b6593" +dependencies = [ + "ariadne", + "blake3", + "codespan-reporting", + "foldhash", + "mago-database", + "mago-span", + "mago-text-edit", + "schemars", + "serde", + "serde-sarif", + "serde_json", + "strum 0.28.0", + "termcolor", +] + +[[package]] +name = "mago-span" +version = "1.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9fab570c46da07b81629b2126e61dd984e565af9f9cb5909c21f431c9dd3a4" +dependencies = [ + "mago-database", + "serde", +] + +[[package]] +name = "mago-syntax" +version = "1.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec09761f36922845e0796a2be1428b79eb3c14af16ea1acd828b9e3ae78c77ff" +dependencies = [ + "bumpalo", + "mago-database", + "mago-php-version", + "mago-reporting", + "mago-span", + "mago-syntax-core", + "memchr", + "ordered-float", + "paste", + "serde", + "strum 0.28.0", +] + +[[package]] +name = "mago-syntax-core" +version = "1.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91dc4c4d95f0f536351bc703645763b75a6b7a802c5ff57a867f22491581190" +dependencies = [ + "bumpalo", + "mago-database", + "mago-span", + "memchr", +] + +[[package]] +name = "mago-text-edit" +version = "1.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e43928360868a349a6d7a1ab70cc1e8ad9e269c64b3c516c040ae44a993588e8" +dependencies = [ + "serde", + "strum 0.28.0", + "tracing", +] + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "mio" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "notify" +version = "8.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d3d07927151ff8575b7087f245456e549fea62edf0ec4e565a5ee50c8402bc3" +dependencies = [ + "bitflags 2.11.0", + "fsevent-sys", + "inotify", + "kqueue", + "libc", + "log", + "mio", + "notify-types", + "walkdir", + "windows-sys 0.60.2", +] + +[[package]] +name = "notify-types" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42b8cfee0e339a0337359f3c88165702ac6e600dc01c0cc9579a92d62b08477a" +dependencies = [ + "bitflags 2.11.0", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "ordered-float" +version = "5.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4779c6901a562440c3786d08192c6fbda7c1c2060edd10006b05ee35d10f2d" +dependencies = [ + "num-traits", + "rand", + "serde", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "php-refactor" version = "0.1.0" +dependencies = [ + "bumpalo", + "libc", + "mago-database", + "mago-span", + "mago-syntax", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.117", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "rand_core", + "serde", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "serde", +] + +[[package]] +name = "rayon" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "ref-cast" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schemafy_core" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bec29dddcfe60f92f3c0d422707b8b56473983ef0481df8d5236ed3ab8fdf24" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "schemafy_lib" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af3d87f1df246a9b7e2bfd1f4ee5f88e48b11ef9cfc62e63f0dead255b1a6f5f" +dependencies = [ + "Inflector", + "proc-macro2", + "quote", + "schemafy_core", + "serde", + "serde_derive", + "serde_json", + "syn 1.0.109", + "uriparse", +] + +[[package]] +name = "schemars" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" +dependencies = [ + "dyn-clone", + "ref-cast", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d115b50f4aaeea07e79c1912f645c7513d81715d0420f8bc77a18c6260b307f" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 2.0.117", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde-sarif" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a053c46f18a8043570d4e32fefc4c6377f82bf29ec310a33e93f273048e3b0be" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "schemafy_lib", + "serde", + "serde_json", + "strum 0.27.2", + "strum_macros 0.27.2", + "syn 2.0.117", + "thiserror", + "typed-builder", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "serde_derive_internals" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "indexmap", + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] +name = "strum" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" + +[[package]] +name = "strum" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9628de9b8791db39ceda2b119bbe13134770b56c138ec1d3af810d045c04f9bd" +dependencies = [ + "strum_macros 0.28.0", +] + +[[package]] +name = "strum_macros" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "strum_macros" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab85eea0270ee17587ed4156089e10b9e6880ee688791d45a905f5b1ca36f664" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "typed-builder" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fef81aec2ca29576f9f6ae8755108640d0a86dd3161b2e8bca6cfa554e98f77d" +dependencies = [ + "typed-builder-macro", +] + +[[package]] +name = "typed-builder-macro" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ecb9ecf7799210407c14a8cfdfe0173365780968dc57973ed082211958e0b18" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + +[[package]] +name = "uriparse" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0200d0fc04d809396c2ad43f3c95da3582a2556eba8d453c1087f4120ee352ff" +dependencies = [ + "fnv", + "lazy_static", +] + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/Cargo.toml b/Cargo.toml index 4cdeeeb..995e2fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,4 +3,17 @@ name = "php-refactor" version = "0.1.0" edition = "2024" +[[bin]] +name = "php-refactor" +path = "src/main.rs" + +[lib] +name = "php_refactor" +path = "src/lib.rs" + [dependencies] +libc = "0.2" +mago-syntax = "1.15.3" +mago-span = "1.15.3" +mago-database = "1.15.3" +bumpalo = "3" diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..5ee7f5c --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,2 @@ +pub mod reporter; +pub mod rules; diff --git a/src/main.rs b/src/main.rs index d9543de..3941227 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,60 @@ +use php_refactor::reporter; +use php_refactor::rules; +use std::fs; +use std::process; +use std::time::Instant; + fn main() { - println!("PHP Refactor"); + let total_start = Instant::now(); + + let path = match std::env::args().nth(1) { + Some(p) => p, + None => { + let elapsed = total_start.elapsed(); + eprintln!("[ERROR] Something went wrong: Usage: php-refactor "); + reporter::print_timing(&[], elapsed); + process::exit(1); + } + }; + + let original = match fs::read_to_string(&path) { + Ok(s) => s, + Err(e) => { + let elapsed = total_start.elapsed(); + eprintln!("[ERROR] Something went wrong: {}", e); + reporter::print_timing(&[], elapsed); + process::exit(1); + } + }; + + let mut rule_timings: Vec<(&str, std::time::Duration)> = Vec::new(); + let mut content = original.clone(); + + for (rule_name, rule_fn) in rules::all_rules() { + let rule_start = Instant::now(); + let result = rule_fn(&content); + rule_timings.push((rule_name, rule_start.elapsed())); + + if let Some(new_content) = result { + content = new_content; + } + } + + let total_elapsed = total_start.elapsed(); + + // Separate "needs update?" step — rule logic stays pure + let needs_update = content != original; + + if needs_update { + if let Err(e) = fs::write(&path, &content) { + eprintln!("[ERROR] Something went wrong: {}", e); + reporter::print_timing(&rule_timings, total_elapsed); + process::exit(1); + } + println!("[OK] 1 file has been changed, 1 file analyzed."); + } else { + println!("[OK] 1 file analyzed, nothing to do."); + } + + reporter::print_timing(&rule_timings, total_elapsed); } diff --git a/src/reporter.rs b/src/reporter.rs new file mode 100644 index 0000000..510e76c --- /dev/null +++ b/src/reporter.rs @@ -0,0 +1,52 @@ +use std::time::Duration; + +pub fn peak_memory_kb() -> u64 { + #[cfg(any(target_os = "macos", target_os = "linux"))] + unsafe { + let mut rusage: libc::rusage = std::mem::zeroed(); + libc::getrusage(libc::RUSAGE_SELF, &mut rusage); + #[cfg(target_os = "macos")] + return (rusage.ru_maxrss / 1024) as u64; + #[cfg(target_os = "linux")] + return rusage.ru_maxrss as u64; + } + #[cfg(not(any(target_os = "macos", target_os = "linux")))] + 0 +} + +pub fn format_memory(kb: u64) -> String { + if kb >= 1024 { + format!("{:.1}MB peak memory", kb as f64 / 1024.0) + } else { + format!("{}KB peak memory", kb) + } +} + +pub fn format_timing_line( + rule_timings: &[(&str, Duration)], + total: Duration, + memory_kb: u64, +) -> String { + let memory_str = format_memory(memory_kb); + let rules_str: String = rule_timings + .iter() + .map(|(name, d)| format!("{}: {:.2?}", name, d)) + .collect::>() + .join(", "); + + if rules_str.is_empty() { + format!("{:.2?} total duration, {}.", total, memory_str) + } else { + format!( + "{:.2?} total duration, {}. {}", + total, memory_str, rules_str + ) + } +} + +pub fn print_timing(rule_timings: &[(&str, Duration)], total: Duration) { + println!( + "{}", + format_timing_line(rule_timings, total, peak_memory_kb()) + ); +} diff --git a/src/rules/mod.rs b/src/rules/mod.rs new file mode 100644 index 0000000..7275e31 --- /dev/null +++ b/src/rules/mod.rs @@ -0,0 +1,10 @@ +pub mod quality; + +pub type RuleFn = fn(&str) -> Option; + +pub fn all_rules() -> Vec<(&'static str, RuleFn)> { + vec![( + "quality/add_final_keyword", + quality::add_final_keyword::apply, + )] +} diff --git a/src/rules/quality/add_final_keyword.rs b/src/rules/quality/add_final_keyword.rs new file mode 100644 index 0000000..99e0995 --- /dev/null +++ b/src/rules/quality/add_final_keyword.rs @@ -0,0 +1,57 @@ +use bumpalo::Bump; +use mago_database::file::FileId; +use mago_syntax::ast::{Modifier, Sequence, Statement}; +use mago_syntax::parser::parse_file_content; + +pub fn apply(source: &str) -> Option { + let arena = Bump::new(); + let file_id = FileId::zero(); + let program = parse_file_content(&arena, file_id, source); + + let mut insertions: Vec = Vec::new(); + collect_insertions(&program.statements, &mut insertions); + + if insertions.is_empty() { + return None; + } + + // Apply insertions back-to-front to preserve offsets + let mut result = source.to_string(); + insertions.sort_unstable_by(|a, b| b.cmp(a)); + for offset in insertions { + result.insert_str(offset, "final "); + } + + Some(result) +} + +fn collect_insertions<'a>( + statements: &'a Sequence<'a, Statement<'a>>, + insertions: &mut Vec, +) { + for stmt in statements { + match stmt { + Statement::Class(class) => { + let mods = &class.modifiers; + if mods.contains_final() || mods.contains_abstract() { + continue; + } + // Insert before `readonly` if present, else before `class` keyword + let offset = if mods.contains_readonly() { + match mods.get_readonly() { + Some(Modifier::Readonly(kw)) => kw.span.start.offset as usize, + _ => unreachable!(), + } + } else { + class.class.span.start.offset as usize + }; + insertions.push(offset); + } + Statement::Interface(_) => {} // skip + Statement::Namespace(ns) => { + collect_insertions(ns.statements(), insertions); + } + _ => {} + } + } +} diff --git a/src/rules/quality/mod.rs b/src/rules/quality/mod.rs new file mode 100644 index 0000000..662542f --- /dev/null +++ b/src/rules/quality/mod.rs @@ -0,0 +1 @@ +pub mod add_final_keyword; diff --git a/tests/integration_test.rs b/tests/integration_test.rs deleted file mode 100644 index befa082..0000000 --- a/tests/integration_test.rs +++ /dev/null @@ -1,11 +0,0 @@ -use std::process::Command; - -#[test] -fn test_main_output() { - let output = Command::new("target/debug/php-refactor") - .output() - .expect("Failed to run binary"); - - let stdout = String::from_utf8_lossy(&output.stdout); - assert!(stdout.contains("PHP Refactor")); -} diff --git a/tests/reporter_tests.rs b/tests/reporter_tests.rs new file mode 100644 index 0000000..44eaf63 --- /dev/null +++ b/tests/reporter_tests.rs @@ -0,0 +1,52 @@ +use php_refactor::reporter::{format_memory, format_timing_line}; +use std::time::Duration; + +// format_memory tests +#[test] +fn test_format_memory_bytes_under_mb() { + assert_eq!(format_memory(0), "0KB peak memory"); + assert_eq!(format_memory(512), "512KB peak memory"); + assert_eq!(format_memory(1023), "1023KB peak memory"); +} + +#[test] +fn test_format_memory_exact_mb() { + assert_eq!(format_memory(1024), "1.0MB peak memory"); + assert_eq!(format_memory(2048), "2.0MB peak memory"); +} + +#[test] +fn test_format_memory_fractional_mb() { + assert_eq!(format_memory(1536), "1.5MB peak memory"); + assert_eq!(format_memory(10240), "10.0MB peak memory"); +} + +// format_timing_line tests +#[test] +fn test_format_timing_line_no_rules() { + let line = format_timing_line(&[], Duration::from_millis(100), 512); + assert_eq!(line, "100.00ms total duration, 512KB peak memory."); +} + +#[test] +fn test_format_timing_line_with_rules() { + let timings = vec![("quality/add_final_keyword", Duration::from_millis(50))]; + let line = format_timing_line(&timings, Duration::from_millis(100), 2048); + assert_eq!( + line, + "100.00ms total duration, 2.0MB peak memory. quality/add_final_keyword: 50.00ms" + ); +} + +#[test] +fn test_format_timing_line_multiple_rules() { + let timings = vec![ + ("dir1/rule_a", Duration::from_millis(20)), + ("dir2/rule_b", Duration::from_millis(30)), + ]; + let line = format_timing_line(&timings, Duration::from_millis(100), 1024); + assert_eq!( + line, + "100.00ms total duration, 1.0MB peak memory. dir1/rule_a: 20.00ms, dir2/rule_b: 30.00ms" + ); +} diff --git a/tests/rules/quality/add_final_keyword/add_final_keyword.php.inc b/tests/rules/quality/add_final_keyword/add_final_keyword.php.inc new file mode 100644 index 0000000..597d14c --- /dev/null +++ b/tests/rules/quality/add_final_keyword/add_final_keyword.php.inc @@ -0,0 +1,10 @@ + = fs::read_dir(fixture_path) + .unwrap() + .map(|e| e.unwrap().path()) + .collect(); + entries.sort(); // deterministic order + + for path in entries { + // Skip non-.php.inc files + if path.extension().map(|e| e.to_str()).flatten() != Some("inc") { + continue; + } + + let content = fs::read_to_string(&path) + .unwrap_or_else(|_| panic!("Failed to read fixture: {}", path.display())); + let file_name = path.file_name().unwrap().to_str().unwrap(); + + if content.contains(SEPARATOR) { + // Transform fixture: expects Some(output) + let parts: Vec<&str> = content.splitn(2, SEPARATOR).collect(); + let input = parts[0]; + let expected = parts[1]; + + let result = rule_fn(input); + assert!( + result.is_some(), + "Rule '{}': Expected Some for fixture '{}', got None", + rule_path, + file_name + ); + assert_eq!( + result.unwrap().trim(), + expected.trim(), + "Rule '{}': Output mismatch for fixture '{}'", + rule_path, + file_name + ); + } else { + // No-transform fixture: expects None + let result = rule_fn(content.trim()); + assert!( + result.is_none(), + "Rule '{}': Expected None for fixture '{}', got Some", + rule_path, + file_name + ); + } + } + } +}