diff --git a/Cargo.lock b/Cargo.lock index 94e3c71..39963e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,19 +4,13 @@ version = 4 [[package]] name = "addr2line" -version = "0.21.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - [[package]] name = "adler2" version = "2.0.0" @@ -82,6 +76,47 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "anyhow" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" + +[[package]] +name = "async-graphql-parser" +version = "7.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8531ee6d292c26df31c18c565ff22371e7bdfffe7f5e62b69537db0b8fd554dc" +dependencies = [ + "async-graphql-value", + "pest", + "serde", + "serde_json", +] + +[[package]] +name = "async-graphql-value" +version = "7.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "741110dda927420a28fbc1c310543d3416f789a6ba96859c2c265843a0a96887" +dependencies = [ + "bytes", + "indexmap", + "serde", + "serde_json", +] + +[[package]] +name = "async-trait" +version = "0.1.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "644dd749086bf3771a2fbc5f256fdb982d53f011c7d5d560304eafeecebce79d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "autocfg" version = "1.4.0" @@ -90,17 +125,17 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "backtrace" -version = "0.3.71" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", - "miniz_oxide 0.7.4", + "miniz_oxide", "object", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] @@ -112,6 +147,12 @@ dependencies = [ "backtrace", ] +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + [[package]] name = "base64" version = "0.22.1" @@ -140,10 +181,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" [[package]] -name = "bytes" -version = "1.9.0" +name = "bumpalo" +version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" + +[[package]] +name = "bytes" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9" +dependencies = [ + "serde", +] [[package]] name = "camino" @@ -156,9 +206,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.10" +version = "1.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229" +checksum = "c7777341816418c02e033934a09f20dc0ccaf65a5201ef8a450ae0105a573fda" dependencies = [ "shlex", ] @@ -171,9 +221,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "4.5.27" +version = "4.5.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "769b0145982b4b48713e01ec42d61614425f27b7058bda7180a3a41f30104796" +checksum = "3e77c3243bd94243c03672cb5154667347c457ca271254724f9f393aee1c05ff" dependencies = [ "clap_builder", "clap_derive", @@ -193,9 +243,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.24" +version = "4.5.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54b755194d6389280185988721fffba69495eed5ee9feeee9a599b53db80318c" +checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed" dependencies = [ "heck", "proc-macro2", @@ -215,6 +265,28 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + [[package]] name = "crc32fast" version = "1.4.2" @@ -233,6 +305,45 @@ dependencies = [ "powerfmt", ] +[[package]] +name = "derive_more" +version = "0.99.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3da29a38df43d6f156149c9b43ded5e018ddff2a855cf2cfd62e8cd7d079c69f" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -249,6 +360,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + [[package]] name = "flate2" version = "1.0.35" @@ -256,7 +373,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" dependencies = [ "crc32fast", - "miniz_oxide 0.8.3", + "miniz_oxide", ] [[package]] @@ -265,6 +382,30 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + [[package]] name = "futures" version = "0.3.31" @@ -356,20 +497,40 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.13.3+wasi-0.2.2", + "windows-targets 0.52.6", ] [[package]] name = "gimli" -version = "0.28.1" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[package]] +name = "h2" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] [[package]] name = "hashbrown" @@ -383,6 +544,40 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2d708df4e7140240a16cd6ab0ab65c972d7433ab77819ea693fde9c43811e2a" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + [[package]] name = "human-panic" version = "2.0.2" @@ -399,6 +594,182 @@ dependencies = [ "uuid", ] +[[package]] +name = "hyper" +version = "0.14.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + [[package]] name = "indexmap" version = "2.7.1" @@ -407,8 +778,15 @@ checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" dependencies = [ "equivalent", "hashbrown", + "serde", ] +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + [[package]] name = "is_ci" version = "1.2.0" @@ -421,6 +799,15 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.14" @@ -429,9 +816,9 @@ checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "jiff" -version = "0.1.28" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c607c728e28764fecde611a2764a3a5db19ae21dcec46f292244f5cc5c085a81" +checksum = "c04ef77ae73f3cf50510712722f0c4e8b46f5aaa1bf5ffad2ae213e6495e78e5" dependencies = [ "jiff-tzdb-platform", "log", @@ -456,6 +843,16 @@ dependencies = [ "jiff-tzdb", ] +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + [[package]] name = "kdl" version = "6.3.3" @@ -464,7 +861,7 @@ checksum = "412e2cf22cb560469db5b211c594ff9dcd490c6964e284ea64eddffe41c2249c" dependencies = [ "miette", "num", - "thiserror", + "thiserror 1.0.69", "winnow", ] @@ -492,6 +889,12 @@ version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" +[[package]] +name = "litemap" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" + [[package]] name = "lock_api" version = "0.4.12" @@ -508,6 +911,12 @@ version = "0.4.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" +[[package]] +name = "maplit" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" + [[package]] name = "matchers" version = "0.1.0" @@ -525,9 +934,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "miette" -version = "7.4.0" +version = "7.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317f146e2eb7021892722af37cf1b971f0a70c8406f487e24952667616192c64" +checksum = "1a955165f87b37fd1862df2a59547ac542c77ef6d17c666f619d1ad22dd89484" dependencies = [ "backtrace", "backtrace-ext", @@ -540,15 +949,15 @@ dependencies = [ "syntect", "terminal_size", "textwrap", - "thiserror", + "thiserror 1.0.69", "unicode-width", ] [[package]] name = "miette-derive" -version = "7.4.0" +version = "7.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23c9b935fbe1d6cbd1dac857b54a688145e2d93f48db36010514d0f612d0ad67" +checksum = "bf45bf44ab49be92fd1227a3be6fc6f617f1a337c06af54981048574d8783147" dependencies = [ "proc-macro2", "quote", @@ -556,13 +965,10 @@ dependencies = [ ] [[package]] -name = "miniz_oxide" -version = "0.7.4" +name = "mime" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" -dependencies = [ - "adler", -] +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "miniz_oxide" @@ -580,10 +986,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.52.0", ] +[[package]] +name = "native-tls" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dab59f8e050d5df8e4dd87d9206fb6f65a483e20ac9fda365ade4fab353196c" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -675,18 +1098,18 @@ dependencies = [ [[package]] name = "object" -version = "0.32.2" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.20.2" +version = "1.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" [[package]] name = "onig" @@ -710,6 +1133,50 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "openssl" +version = "0.10.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61cfb4e166a8bb8c9b55c500bc2308550148ece889be90f609377e58140f42c6" +dependencies = [ + "bitflags 2.8.0", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-sys" +version = "0.9.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b22d5b84be05a8d6947c7cb71f7c849aa0f112acd4bf51c2a7c1c988ac0a9dc" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "os_info" version = "3.9.2" @@ -733,6 +1200,21 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb37767f6569cd834a413442455e0f066d0d522de8630436e2a1761d9726ba56" +[[package]] +name = "paperless-rs" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e929358cf0d9963f0ee77487fc1b45d4bbc20542e79b072bec05b4bd66e085f4" +dependencies = [ + "async-trait", + "base64 0.21.7", + "bytes", + "derive_more", + "reqwest", + "serde", + "tokio", +] + [[package]] name = "parking_lot" version = "0.12.3" @@ -753,7 +1235,24 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets", + "windows-targets 0.52.6", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pest" +version = "2.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc" +dependencies = [ + "memchr", + "thiserror 2.0.11", + "ucd-trie", ] [[package]] @@ -776,7 +1275,7 @@ checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "plaixt" -version = "0.0.0" +version = "0.1.0" dependencies = [ "camino", "clap", @@ -786,10 +1285,12 @@ dependencies = [ "kdl", "miette", "owo-colors", + "paperless-rs", "tokio", "tokio-stream", "tracing", "tracing-subscriber", + "trustfall", ] [[package]] @@ -798,7 +1299,7 @@ version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016" dependencies = [ - "base64", + "base64 0.22.1", "indexmap", "quick-xml", "serde", @@ -906,12 +1407,61 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "reqwest" +version = "0.11.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +dependencies = [ + "base64 0.21.7", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "system-configuration", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + [[package]] name = "rustc-demangle" version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rustix" version = "0.38.44" @@ -926,10 +1476,25 @@ dependencies = [ ] [[package]] -name = "ryu" -version = "1.0.18" +name = "rustls-pemfile" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + +[[package]] +name = "rustversion" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" + +[[package]] +name = "ryu" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" [[package]] name = "same-file" @@ -940,12 +1505,50 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schannel" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.8.0", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03" + [[package]] name = "serde" version = "1.0.217" @@ -968,9 +1571,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.137" +version = "1.0.138" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b" +checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949" dependencies = [ "itoa", "memchr", @@ -987,6 +1590,18 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + [[package]] name = "sharded-slab" version = "0.1.7" @@ -1025,6 +1640,9 @@ name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +dependencies = [ + "serde", +] [[package]] name = "socket2" @@ -1036,6 +1654,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "strsim" version = "0.11.1" @@ -1065,15 +1689,32 @@ checksum = "b7401a30af6cb5818bb64852270bb722533397edcfc7344954a38f420819ece2" [[package]] name = "syn" -version = "2.0.96" +version = "2.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" +checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "syntect" version = "5.2.0" @@ -1091,11 +1732,46 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "thiserror", + "thiserror 1.0.69", "walkdir", "yaml-rust", ] +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tempfile" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91" +dependencies = [ + "cfg-if", + "fastrand", + "getrandom", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + [[package]] name = "terminal_size" version = "0.4.1" @@ -1122,7 +1798,16 @@ version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" +dependencies = [ + "thiserror-impl 2.0.11", ] [[package]] @@ -1136,6 +1821,17 @@ dependencies = [ "syn", ] +[[package]] +name = "thiserror-impl" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "thread_local" version = "1.1.8" @@ -1177,6 +1873,16 @@ dependencies = [ "time-core", ] +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + [[package]] name = "tokio" version = "1.43.0" @@ -1206,6 +1912,16 @@ dependencies = [ "syn", ] +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + [[package]] name = "tokio-stream" version = "0.1.17" @@ -1233,9 +1949,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" dependencies = [ "serde", "serde_spanned", @@ -1264,6 +1980,12 @@ dependencies = [ "toml_datetime", ] +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + [[package]] name = "tracing" version = "0.1.41" @@ -1325,6 +2047,57 @@ dependencies = [ "tracing-log", ] +[[package]] +name = "trustfall" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2c4d6f50f158998ff48a905a4f12e918b9dfd1274c0711c0f4485d8f7ff015e" +dependencies = [ + "anyhow", + "trustfall_core", + "trustfall_derive", +] + +[[package]] +name = "trustfall_core" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "363322af9d4d04fb0e298d8e9f97d9ef316a796f6f4e5f241060ad50a07d0334" +dependencies = [ + "async-graphql-parser", + "async-graphql-value", + "itertools", + "maplit", + "regex", + "serde", + "serde_json", + "smallvec", + "thiserror 1.0.69", +] + +[[package]] +name = "trustfall_derive" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb14eb4f23b3b669d232a5c7d2b3d6c89ad9e15be1cbdd2c1e14d87d62569ec" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + [[package]] name = "unicode-ident" version = "1.0.16" @@ -1343,6 +2116,29 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" +[[package]] +name = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "utf8parse" version = "0.2.2" @@ -1351,9 +2147,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.12.1" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3758f5e68192bb96cc8f9b7e2c2cfdabb435499a28499a42f8f984092adad4b" +checksum = "ced87ca4be083373936a67f8de945faa23b6b42384bd5b64434850802c6dccd0" dependencies = [ "getrandom", ] @@ -1364,6 +2160,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "walkdir" version = "2.5.0" @@ -1374,12 +2176,111 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasi" +version = "0.13.3+wasi-0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +dependencies = [ + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "winapi" version = "0.3.9" @@ -1411,13 +2312,22 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -1426,7 +2336,22 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] @@ -1435,28 +2360,46 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "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]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -1469,24 +2412,48 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -1495,13 +2462,44 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.25" +version = "0.6.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad699df48212c6cc6eb4435f35500ac6fd3b9913324f938aea302022ce19d310" +checksum = "1e90edd2ac1aa278a5c4599b1d89cf03074b610800f866d4026dc199d7929a28" dependencies = [ "memchr", ] +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "wit-bindgen-rt" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +dependencies = [ + "bitflags 2.8.0", +] + +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + [[package]] name = "yaml-rust" version = "0.4.5" @@ -1510,3 +2508,70 @@ checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" dependencies = [ "linked-hash-map", ] + +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerofrom" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml index 6c2d52a..5f55f38 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ resolver = "2" unsafe_code = "forbid" [workspace.package] -version = "0.0.0" +version = "0.1.0" edition = "2021" description = "PLAIn teXT tools for your data" license = "EUPL-1.2" diff --git a/crates/plaixt/Cargo.toml b/crates/plaixt/Cargo.toml index dd9158f..3ff7c07 100644 --- a/crates/plaixt/Cargo.toml +++ b/crates/plaixt/Cargo.toml @@ -14,10 +14,12 @@ jiff = "0.1.28" kdl.workspace = true miette = { version = "7.4.0", features = ["fancy", "syntect-highlighter"] } owo-colors = "4.1.0" +paperless-rs = "0.1.5" tokio = { version = "1.43.0", features = ["full"] } tokio-stream = { version = "0.1.17", features = ["full"] } tracing = "0.1.41" tracing-subscriber = { version = "0.3.19", features = ["env-filter"] } +trustfall = "0.8.1" [lints] workspace = true diff --git a/crates/plaixt/src/adapter/adapter_impl.rs b/crates/plaixt/src/adapter/adapter_impl.rs new file mode 100644 index 0000000..648f22a --- /dev/null +++ b/crates/plaixt/src/adapter/adapter_impl.rs @@ -0,0 +1,188 @@ +use std::collections::BTreeMap; +use std::collections::BTreeSet; +use std::sync::Arc; +use std::sync::OnceLock; + +use paperless_rs::PaperlessClient; +use tracing::debug; +use trustfall::provider::resolve_coercion_using_schema; +use trustfall::provider::resolve_property_with; +use trustfall::provider::AsVertex; +use trustfall::provider::ContextIterator; +use trustfall::provider::ContextOutcomeIterator; +use trustfall::provider::EdgeParameters; +use trustfall::provider::ResolveEdgeInfo; +use trustfall::provider::ResolveInfo; +use trustfall::provider::Typename; +use trustfall::provider::VertexIterator; +use trustfall::FieldValue; +use trustfall::Schema; + +use super::vertex::Vertex; +use crate::parsing::DefinitionKind; +use crate::parsing::Record; + +static SCHEMA: OnceLock = OnceLock::new(); + +#[non_exhaustive] +pub struct Adapter { + schema: Arc, + records: Vec, + definitions: Arc>>, + paperless_client: Option, + runtime_handle: tokio::runtime::Handle, +} + +impl std::fmt::Debug for Adapter { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Adapter").finish_non_exhaustive() + } +} + +impl Adapter { + pub fn new( + schema: Schema, + records: Vec, + definitions: BTreeMap>, + paperless_client: Option, + runtime: tokio::runtime::Handle, + ) -> Self { + Self { + schema: Arc::new(schema), + records, + definitions: Arc::new(definitions), + paperless_client, + runtime_handle: runtime, + } + } + + pub const SCHEMA_TEXT: &'static str = include_str!("./schema.graphql"); + + pub fn schema() -> &'static Schema { + SCHEMA.get_or_init(|| Schema::parse(Self::SCHEMA_TEXT).expect("not a valid schema")) + } +} + +impl<'a> trustfall::provider::Adapter<'a> for Adapter { + type Vertex = Vertex; + + fn resolve_starting_vertices( + &self, + edge_name: &Arc, + _parameters: &EdgeParameters, + resolve_info: &ResolveInfo, + ) -> VertexIterator<'a, Self::Vertex> { + match edge_name.as_ref() { + "Records" => super::entrypoints::records(resolve_info, &self.records), + _ => { + unreachable!( + "attempted to resolve starting vertices for unexpected edge name: {edge_name}" + ) + } + } + } + + fn resolve_property + 'a>( + &self, + contexts: ContextIterator<'a, V>, + type_name: &Arc, + property_name: &Arc, + resolve_info: &ResolveInfo, + ) -> ContextOutcomeIterator<'a, V, FieldValue> { + if property_name.as_ref() == "__typename" { + return resolve_property_with(contexts, |vertex| vertex.typename().into()); + } + + debug!(?type_name, ?property_name, "Resolving property"); + + match type_name.as_ref() { + "PaperlessDocument" => super::properties::resolve_paperless_document_property( + contexts, + property_name.as_ref(), + resolve_info, + ), + "Path" | "File" | "Directory" => super::properties::resolve_fs_property( + contexts, + type_name.as_ref(), + property_name.as_ref(), + resolve_info, + ), + "Record" => { + super::properties::resolve_record_property(contexts, property_name, resolve_info) + } + kind if kind.starts_with("p_") => { + super::properties::resolve_record_property(contexts, property_name, resolve_info) + } + _ => { + unreachable!( + "attempted to read property '{property_name}' on unexpected type: {type_name}" + ) + } + } + } + + fn resolve_neighbors + 'a>( + &self, + contexts: ContextIterator<'a, V>, + type_name: &Arc, + edge_name: &Arc, + parameters: &EdgeParameters, + resolve_info: &ResolveEdgeInfo, + ) -> ContextOutcomeIterator<'a, V, VertexIterator<'a, Self::Vertex>> { + match type_name.as_ref() { + "Directory" => super::edges::resolve_directory_edge( + contexts, + edge_name.as_ref(), + parameters, + resolve_info, + ), + kind if kind.starts_with("p_") => super::edges::resolve_record_edge( + contexts, + edge_name, + parameters, + resolve_info, + &self.definitions, + ), + _ => { + unreachable!( + "attempted to resolve edge '{edge_name}' on unexpected type: {type_name}" + ) + } + } + } + + fn resolve_coercion + 'a>( + &self, + contexts: ContextIterator<'a, V>, + type_name: &Arc, + coerce_to_type: &Arc, + _resolve_info: &ResolveInfo, + ) -> ContextOutcomeIterator<'a, V, bool> { + let schema = self.schema.clone(); + let coerce_to_type = coerce_to_type.clone(); + debug!(?coerce_to_type, ?type_name, "Trying to coerce"); + + Box::new(contexts.map(move |ctx| { + let subtypes: BTreeSet<_> = schema + .subtypes(coerce_to_type.as_ref()) + .unwrap_or_else(|| panic!("type {coerce_to_type} is not part of this schema")) + .collect(); + + match ctx.active_vertex::() { + None => (ctx, false), + Some(vertex) => { + let typename = vertex.typename(); + debug!(?coerce_to_type, ?vertex, "Trying to coerce"); + if let Some(rec) = vertex.as_record() { + let is_rec = coerce_to_type.starts_with("p_"); + let is_kind = rec.kind == coerce_to_type.as_ref()[2..]; + (ctx, is_rec && is_kind) + } else { + let can_coerce = subtypes.contains(typename); + (ctx, can_coerce) + } + } + } + })) + } +} diff --git a/crates/plaixt/src/adapter/edges.rs b/crates/plaixt/src/adapter/edges.rs new file mode 100644 index 0000000..bda40f6 --- /dev/null +++ b/crates/plaixt/src/adapter/edges.rs @@ -0,0 +1,96 @@ +use std::collections::BTreeMap; +use std::sync::Arc; + +use camino::Utf8PathBuf; +use trustfall::provider::resolve_neighbors_with; +use trustfall::provider::AsVertex; +use trustfall::provider::ContextIterator; +use trustfall::provider::ContextOutcomeIterator; +use trustfall::provider::EdgeParameters; +use trustfall::provider::ResolveEdgeInfo; +use trustfall::provider::VertexIterator; + +use super::Vertex; +use crate::parsing::DefinitionKind; +use crate::parsing::Record; + +pub(super) fn resolve_directory_edge<'a, V: AsVertex + 'a>( + contexts: ContextIterator<'a, V>, + edge_name: &str, + _parameters: &EdgeParameters, + resolve_info: &ResolveEdgeInfo, +) -> ContextOutcomeIterator<'a, V, VertexIterator<'a, Vertex>> { + match edge_name { + "Children" => directory::children(contexts, resolve_info), + _ => unreachable!("attempted to resolve unexpected edge '{edge_name}' on type 'Directory'"), + } +} + +mod directory { + use camino::Utf8Path; + use trustfall::provider::resolve_neighbors_with; + use trustfall::provider::AsVertex; + use trustfall::provider::ContextIterator; + use trustfall::provider::ContextOutcomeIterator; + use trustfall::provider::ResolveEdgeInfo; + use trustfall::provider::VertexIterator; + + use crate::adapter::Vertex; + + pub(super) fn children<'a, V: AsVertex + 'a>( + contexts: ContextIterator<'a, V>, + _resolve_info: &ResolveEdgeInfo, + ) -> ContextOutcomeIterator<'a, V, VertexIterator<'a, Vertex>> { + resolve_neighbors_with(contexts, move |vertex| { + let vertex = vertex + .as_directory() + .expect("conversion failed, vertex was not a Directory"); + + fn read_children(path: &Utf8Path) -> Option> { + Some( + path.read_dir_utf8() + .ok()? + .flat_map(|item| Some(Vertex::Path(item.ok()?.path().to_path_buf()))), + ) + } + + read_children(vertex) + .map(|i| { + let it: Box> = Box::new(i); + it + }) + .unwrap_or_else(|| Box::new(std::iter::empty())) + }) + } +} + +pub(super) fn resolve_record_edge<'a, V: AsVertex + 'a>( + contexts: ContextIterator<'a, V>, + edge_name: &Arc, + _parameters: &EdgeParameters, + _resolve_info: &ResolveEdgeInfo, + definitions: &Arc>>, +) -> ContextOutcomeIterator<'a, V, VertexIterator<'a, Vertex>> { + let edge_name = edge_name.clone(); + let definitions = definitions.clone(); + resolve_neighbors_with(contexts, move |v| { + let rec = v.as_record().expect("Expected a record"); + let def = &definitions[&rec.kind][edge_name.as_ref()]; + + match def { + DefinitionKind::Path => Box::new(std::iter::once(path_from_rec(rec, &edge_name))), + _ => unreachable!("Only `Path` can appear as edge for now"), + } + }) +} + +fn path_from_rec(rec: &Record, edge_name: &str) -> Vertex { + let pathb = Utf8PathBuf::from(rec.fields[edge_name].as_string().unwrap()); + if pathb.is_file() { + Vertex::File(pathb) + } else if pathb.is_dir() { + Vertex::Directory(pathb) + } else { + Vertex::Path(pathb) + } +} diff --git a/crates/plaixt/src/adapter/entrypoints.rs b/crates/plaixt/src/adapter/entrypoints.rs new file mode 100644 index 0000000..5ee05a5 --- /dev/null +++ b/crates/plaixt/src/adapter/entrypoints.rs @@ -0,0 +1,16 @@ +use trustfall::provider::ResolveInfo; +use trustfall::provider::VertexIterator; + +use super::vertex::Vertex; +use crate::parsing::Record; + +pub(super) fn records<'a>( + _resolve_info: &ResolveInfo, + records: &'_ [Record], +) -> VertexIterator<'a, Vertex> { + #[expect( + clippy::unnecessary_to_owned, + reason = "We have to go through a vec to satisfy the lifetimes" + )] + Box::new(records.to_vec().into_iter().map(Vertex::Record)) +} diff --git a/crates/plaixt/src/adapter/mod.rs b/crates/plaixt/src/adapter/mod.rs new file mode 100644 index 0000000..c2219c0 --- /dev/null +++ b/crates/plaixt/src/adapter/mod.rs @@ -0,0 +1,55 @@ +mod adapter_impl; +mod edges; +mod entrypoints; +mod properties; +mod vertex; + +#[cfg(test)] +mod tests; + +pub use adapter_impl::Adapter; +use tracing::trace; +use trustfall::Schema; +pub use vertex::Vertex; + +pub struct CustomVertex { + pub name: String, + pub definition: String, +} + +impl crate::parsing::Definition { + fn to_custom_vertices(&self) -> Vec { + let name = format!("p_{}", self.name); + + let fields = self + .fields + .iter() + .map(|(fname, ftype)| { + let kind = ftype.trustfall_kind(&format!("{name}{fname}")); + format!("{fname}: {kind}") + }) + .chain([String::from("_at: String!"), String::from("_kind: String!")]) + .collect::>(); + + let definition = format!("type {name} implements Record {{ {} }}", fields.join(",")); + + [CustomVertex { name, definition }].into_iter().collect() + } +} + +pub(crate) fn to_schema( + definitions: &std::collections::BTreeMap>, +) -> trustfall::Schema { + let base_text = Adapter::SCHEMA_TEXT; + + let generated = definitions + .values() + .flat_map(|defs| defs.last().unwrap().to_custom_vertices()) + .map(|v| v.definition) + .collect::>() + .join("\n"); + + let input = format!("{base_text}{generated}"); + trace!(%input, "Using schema"); + Schema::parse(input).unwrap() +} diff --git a/crates/plaixt/src/adapter/properties.rs b/crates/plaixt/src/adapter/properties.rs new file mode 100644 index 0000000..6a13dd4 --- /dev/null +++ b/crates/plaixt/src/adapter/properties.rs @@ -0,0 +1,180 @@ +use std::sync::Arc; + +use kdl::KdlValue; +use trustfall::provider::field_property; +use trustfall::provider::resolve_property_with; +use trustfall::provider::AsVertex; +use trustfall::provider::ContextIterator; +use trustfall::provider::ContextOutcomeIterator; +use trustfall::provider::ResolveInfo; +use trustfall::FieldValue; + +use super::vertex::Vertex; + +pub(super) fn resolve_fs_property<'a, V: AsVertex + 'a>( + contexts: ContextIterator<'a, V>, + type_name: &str, + property_name: &str, + resolve_info: &ResolveInfo, +) -> ContextOutcomeIterator<'a, V, FieldValue> { + match (type_name, property_name) { + (_, "exists" | "basename" | "path") => { + resolve_path_property(contexts, property_name, resolve_info) + } + ("Directory", _) => resolve_directory_property(contexts, property_name, resolve_info), + ("File", _) => resolve_file_property(contexts, property_name, resolve_info), + _ => { + unreachable!( + "attempted to read unexpected property '{property_name}' on type '{type_name}'" + ) + } + } +} + +pub(super) fn resolve_path_property<'a, V: AsVertex + 'a>( + contexts: ContextIterator<'a, V>, + property_name: &str, + _resolve_info: &ResolveInfo, +) -> ContextOutcomeIterator<'a, V, FieldValue> { + match property_name { + "exists" => resolve_property_with(contexts, move |v: &Vertex| match v { + Vertex::Path(p) | Vertex::File(p) | Vertex::Directory(p) => p.exists().into(), + _ => { + panic!("Vertex was not a filesystem type") + } + }), + "basename" => resolve_property_with(contexts, move |v: &Vertex| match v { + Vertex::Path(p) | Vertex::File(p) | Vertex::Directory(p) => p.file_name().into(), + _ => { + panic!("Vertex was not a filesystem type") + } + }), + "path" => resolve_property_with(contexts, move |v: &Vertex| match v { + Vertex::Path(p) | Vertex::File(p) | Vertex::Directory(p) => p.to_string().into(), + _ => { + panic!("Vertex was not a filesystem type") + } + }), + _ => { + unreachable!("attempted to read unexpected property '{property_name}' on type 'Path'") + } + } +} + +pub(super) fn resolve_directory_property<'a, V: AsVertex + 'a>( + contexts: ContextIterator<'a, V>, + property_name: &str, + _resolve_info: &ResolveInfo, +) -> ContextOutcomeIterator<'a, V, FieldValue> { + match property_name { + "exists" => resolve_property_with(contexts, move |v: &Vertex| { + let directory = v.as_directory().expect("vertex was not a Directory"); + + directory.exists().into() + }), + "basename" => resolve_property_with(contexts, move |v: &Vertex| { + let directory = v.as_directory().expect("vertex was not a Directory"); + + directory.file_name().into() + }), + "path" => resolve_property_with(contexts, move |v: &Vertex| { + let directory = v.as_directory().expect("vertex was not a Directory"); + + directory.to_string().into() + }), + _ => { + unreachable!("attempted to read unexpected property '{property_name}' on type 'File'") + } + } +} + +pub(super) fn resolve_file_property<'a, V: AsVertex + 'a>( + contexts: ContextIterator<'a, V>, + property_name: &str, + _resolve_info: &ResolveInfo, +) -> ContextOutcomeIterator<'a, V, FieldValue> { + match property_name { + "exists" => resolve_property_with(contexts, move |v: &Vertex| { + let file = v.as_file().expect("vertex was not a File"); + + file.exists().into() + }), + "basename" => resolve_property_with(contexts, move |v: &Vertex| { + let file = v.as_file().expect("vertex was not a File"); + + file.file_name().into() + }), + "path" => resolve_property_with(contexts, move |v: &Vertex| { + let file = v.as_file().expect("vertex was not a File"); + + file.to_string().into() + }), + "extension" => resolve_property_with(contexts, move |v: &Vertex| { + let file = v.as_file().expect("vertex was not a File"); + + file.extension().into() + }), + _ => { + unreachable!("attempted to read unexpected property '{property_name}' on type 'File'") + } + } +} + +pub(super) fn resolve_paperless_document_property<'a, V: AsVertex + 'a>( + contexts: ContextIterator<'a, V>, + property_name: &str, + _resolve_info: &ResolveInfo, +) -> ContextOutcomeIterator<'a, V, FieldValue> { + match property_name { + "added" => resolve_property_with(contexts, field_property!(as_paperless_document, added)), + "archive_serial_number" => resolve_property_with( + contexts, + field_property!(as_paperless_document, archive_serial_number), + ), + "content" => { + resolve_property_with(contexts, field_property!(as_paperless_document, content)) + } + "created" => { + resolve_property_with(contexts, field_property!(as_paperless_document, created)) + } + "id" => resolve_property_with(contexts, field_property!(as_paperless_document, id)), + "title" => resolve_property_with(contexts, field_property!(as_paperless_document, title)), + _ => { + unreachable!( + "attempted to read unexpected property '{property_name}' on type 'PaperlessDocument'" + ) + } + } +} + +pub(super) fn resolve_record_property<'a, V: AsVertex + 'a>( + contexts: ContextIterator<'a, V>, + property_name: &Arc, + _resolve_info: &ResolveInfo, +) -> ContextOutcomeIterator<'a, V, FieldValue> { + let property_name = property_name.clone(); + match property_name.as_ref() { + "_at" => resolve_property_with( + contexts, + field_property!(as_record, at, { at.to_string().into() }), + ), + "_kind" => resolve_property_with(contexts, field_property!(as_record, kind)), + _ => resolve_property_with(contexts, move |v: &Vertex| { + let rec = v + .as_record() + .expect("Called record property without it being a record"); + + kdl_to_trustfall_value(rec.fields[property_name.as_ref()].clone()) + }), + } +} + +fn kdl_to_trustfall_value(val: KdlValue) -> FieldValue { + match val { + KdlValue::Bool(b) => FieldValue::Boolean(b), + KdlValue::Float(f) => FieldValue::Float64(f), + KdlValue::Null => FieldValue::Null, + KdlValue::Integer(i) => FieldValue::Int64(i.try_into().unwrap()), + KdlValue::String(s) => FieldValue::String(s.into()), + } +} diff --git a/crates/plaixt/src/adapter/schema.graphql b/crates/plaixt/src/adapter/schema.graphql new file mode 100644 index 0000000..b56faad --- /dev/null +++ b/crates/plaixt/src/adapter/schema.graphql @@ -0,0 +1,88 @@ +schema { + query: RootSchemaQuery +} + +directive @filter( + """ + Name of the filter operation to perform. + """ + op: String! + """ + List of string operands for the operator. + """ + value: [String!] +) repeatable on FIELD | INLINE_FRAGMENT +directive @tag( + """ + Name to apply to the given property field. + """ + name: String +) on FIELD +directive @output( + """ + What to designate the output field generated from this property field. + """ + name: String +) on FIELD +directive @optional on FIELD +directive @recurse( + """ + Recurse up to this many times on this edge. A depth of 1 produces the current + vertex and its immediate neighbors along the given edge. + """ + depth: Int! +) on FIELD +directive @fold on FIELD +directive @transform( + """ + Name of the transformation operation to perform. + """ + op: String! +) on FIELD + + +""" +All the possible data types to begin querying +""" +type RootSchemaQuery { + """ + All records in your plaixt instance + """ + Records: [Record!]! +} + +interface Record { + _kind: String! + _at: String! +} + +interface Path { + path: String! + exists: Boolean! + basename: String! +} + +interface File implements Path { + path: String! + exists: Boolean! + basename: String! + + extension: String! +} + +type Directory implements Path { + path: String! + exists: Boolean! + basename: String! + + Children: [Path!]! +} + +type PaperlessDocument { + id: Int! + title: String! + content: String! + archive_serial_number: Int + created: String! + added: String! +} diff --git a/crates/plaixt/src/adapter/tests.rs b/crates/plaixt/src/adapter/tests.rs new file mode 100644 index 0000000..8acec27 --- /dev/null +++ b/crates/plaixt/src/adapter/tests.rs @@ -0,0 +1,16 @@ +use trustfall::provider::check_adapter_invariants; + +use super::Adapter; + +#[tokio::test] +async fn adapter_satisfies_trustfall_invariants() { + let schema = Adapter::schema(); + let adapter = Adapter::new( + schema.clone(), + vec![], + [].into(), + None, + tokio::runtime::Handle::current(), + ); + check_adapter_invariants(schema, adapter); +} diff --git a/crates/plaixt/src/adapter/vertex.rs b/crates/plaixt/src/adapter/vertex.rs new file mode 100644 index 0000000..3829e2e --- /dev/null +++ b/crates/plaixt/src/adapter/vertex.rs @@ -0,0 +1,15 @@ +use camino::Utf8PathBuf; +use paperless_rs::endpoint::documents::Document as PaperlessDocument; + +use crate::parsing::Record; + +#[non_exhaustive] +#[derive(Debug, Clone, trustfall::provider::TrustfallEnumVertex)] +pub enum Vertex { + Path(Utf8PathBuf), + File(Utf8PathBuf), + Directory(Utf8PathBuf), + + PaperlessDocument(PaperlessDocument), + Record(Record), +} diff --git a/crates/plaixt/src/config.rs b/crates/plaixt/src/config.rs new file mode 100644 index 0000000..0c09e69 --- /dev/null +++ b/crates/plaixt/src/config.rs @@ -0,0 +1,39 @@ +use camino::Utf8Path; +use camino::Utf8PathBuf; +use kdl::KdlDocument; +use miette::Context; +use miette::LabeledSpan; + +#[derive(Debug)] +pub struct Config { + pub(crate) root_folder: Utf8PathBuf, +} + +pub(crate) async fn parse_config(path: &Utf8Path) -> miette::Result { + let data = tokio::fs::read_to_string(path) + .await + .map_err(|e| miette::miette!(e)) + .wrap_err_with(|| miette::miette!("Could not read configuration at \"{path}\""))?; + + let doc: KdlDocument = data + .parse() + .map_err(|e| miette::Error::from(e).with_source_code(data.clone()))?; + + Ok(Config { + root_folder: doc + .get("root_folder") + .ok_or_else(|| miette::miette!("\"root_folder\" configuration value not found")) + .and_then(|val| { + val.get(0) + .and_then(|v| v.as_string().map(Into::into)) + .ok_or_else(|| { + miette::diagnostic!( + labels = vec![LabeledSpan::new_primary_with_span(None, val.span())], + "root_folder is expected to be a path" + ) + .into() + }) + .map_err(|e: miette::Report| e.with_source_code(data)) + })?, + }) +} diff --git a/crates/plaixt/src/main.rs b/crates/plaixt/src/main.rs index 9b28ba4..4361ea5 100644 --- a/crates/plaixt/src/main.rs +++ b/crates/plaixt/src/main.rs @@ -1,16 +1,24 @@ #![allow(dead_code)] -use camino::Utf8Path; +use std::collections::BTreeMap; +use std::io::Read; +use std::sync::Arc; + use camino::Utf8PathBuf; use clap::Parser; use clap::Subcommand; use clap::ValueHint; use human_panic::Metadata; -use kdl::KdlDocument; -use miette::LabeledSpan; -use miette::WrapErr; +use miette::IntoDiagnostic; +use parsing::Definition; +use parsing::Record; use tracing::info; +use tracing_subscriber::EnvFilter; +use trustfall::execute_query; +use trustfall::FieldValue; +mod adapter; +mod config; mod parsing; #[derive(Debug, Parser)] @@ -33,11 +41,7 @@ struct Args { #[derive(Debug, Subcommand)] enum ArgMode { Dump, -} - -#[derive(Debug)] -pub struct Config { - root_folder: Utf8PathBuf, + Query, } #[tokio::main] @@ -47,54 +51,107 @@ async fn main() -> miette::Result<()> { .authors(env!("CARGO_PKG_AUTHORS")) ); - tracing_subscriber::fmt().pretty().init(); + tracing_subscriber::fmt() + .with_env_filter(EnvFilter::from_default_env()) + .pretty() + .init(); let args = Args::parse(); - let config = parse_config(&args.config).await?; + let config = config::parse_config(&args.config).await?; let root_folder = args.root_folder.as_ref().unwrap_or(&config.root_folder); - let load_records = async { - let definitions = parsing::load_definitions(&root_folder.join("definitions")).await?; - parsing::load_records(root_folder, &definitions).await - }; + let definitions = parsing::load_definitions(&root_folder.join("definitions")).await?; + + let records = parsing::load_records(root_folder, &definitions).await?; + + let (schema, adapter) = get_schema_and_adapter(&definitions, records.clone()); match args.mode { - ArgMode::Dump => { - let records = load_records.await?; + ArgMode::Query => { + let mut query = String::new(); + std::io::stdin() + .read_to_string(&mut query) + .into_diagnostic()?; - info!("Got records: {records:#?}"); + let result = execute_query( + &schema, + Arc::new(adapter), + &query, + BTreeMap::, FieldValue>::from([]), + ) + .unwrap() + .collect::>(); + + info!("Got records: {result:#?}"); + } + ArgMode::Dump => { + print_records(&records); } } Ok(()) } -async fn parse_config(path: &Utf8Path) -> miette::Result { - let data = tokio::fs::read_to_string(path) - .await - .map_err(|e| miette::miette!(e)) - .wrap_err_with(|| miette::miette!("Could not read configuration at \"{path}\""))?; - - let doc: KdlDocument = data - .parse() - .map_err(|e| miette::Error::from(e).with_source_code(data.clone()))?; - - Ok(Config { - root_folder: doc - .get("root_folder") - .ok_or_else(|| miette::miette!("\"root_folder\" configuration value not found")) - .and_then(|val| { - val.get(0) - .and_then(|v| v.as_string().map(Into::into)) - .ok_or_else(|| { - miette::diagnostic!( - labels = vec![LabeledSpan::new_primary_with_span(None, val.span())], - "root_folder is expected to be a path" - ) - .into() - }) - .map_err(|e: miette::Report| e.with_source_code(data)) - })?, - }) +fn get_schema_and_adapter( + definitions: &BTreeMap>, + records: Vec, +) -> (trustfall::Schema, adapter::Adapter) { + let schema = adapter::to_schema(definitions); + let definitions = definitions + .iter() + .map(|(name, def)| (name.clone(), def.last().cloned().unwrap().fields)) + .collect(); + let adapter = adapter::Adapter::new( + schema.clone(), + records, + definitions, + None, + tokio::runtime::Handle::current(), + ); + (schema, adapter) +} + +fn print_records(records: &[Record]) { + for record in records { + println!("{kind} @ {at} {{", kind = record.kind, at = record.at); + for field in &record.fields { + println!("\t{name} = {value}", name = field.0, value = field.1); + } + println!("}}") + } +} + +#[cfg(test)] +mod tests { + use camino::Utf8PathBuf; + use tracing_subscriber::EnvFilter; + use trustfall::provider::check_adapter_invariants; + + use crate::get_schema_and_adapter; + use crate::parsing; + + #[tokio::test] + async fn ensure_adapter_satisfies_invariants() { + tracing_subscriber::fmt() + .with_env_filter(EnvFilter::from_default_env()) + .pretty() + .with_test_writer() + .init(); + + let root_folder = Utf8PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../examples"); + + println!("{root_folder}"); + let definitions = parsing::load_definitions(&root_folder.join("definitions")) + .await + .unwrap(); + + let records = parsing::load_records(&root_folder, &definitions) + .await + .unwrap(); + + let (schema, adapter) = get_schema_and_adapter(&definitions, records.clone()); + + check_adapter_invariants(&schema, adapter); + } } diff --git a/crates/plaixt/src/parsing.rs b/crates/plaixt/src/parsing.rs index 04f6d5a..f3ca840 100644 --- a/crates/plaixt/src/parsing.rs +++ b/crates/plaixt/src/parsing.rs @@ -1,5 +1,4 @@ use std::collections::BTreeMap; -use std::collections::HashMap; use camino::Utf8Path; use camino::Utf8PathBuf; @@ -15,7 +14,7 @@ use miette::NamedSource; use owo_colors::OwoColorize; use tokio_stream::wrappers::ReadDirStream; -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Record { pub(crate) kind: String, pub(crate) at: Timestamp, @@ -82,8 +81,7 @@ pub(crate) fn parse_record( .map(|field| { let Some(get) = field.get(0) else { return Err(miette::diagnostic!( - labels = - vec![LabeledSpan::new_primary_with_span(None, at_entry.span())], + labels = vec![LabeledSpan::new_primary_with_span(None, at_entry.span())], "This datetime should be a string formatted as RFC3339." ))?; }; @@ -143,9 +141,8 @@ pub(crate) async fn load_records( }) .flat_map(|val| futures::stream::iter(val.transpose())) .and_then(|(name, bytes)| async move { - parse_record(&bytes, definitions).map_err(|e| { - e.with_source_code(NamedSource::new(name, bytes).with_language("kdl")) - }) + parse_record(&bytes, definitions) + .map_err(|e| e.with_source_code(NamedSource::new(name, bytes).with_language("kdl"))) }) .map(|val| val.map(|recs| futures::stream::iter(recs).map(Ok::<_, miette::Report>))) .try_flatten() @@ -155,19 +152,32 @@ pub(crate) async fn load_records( Ok(defs) } -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum DefinitionKind { String, + Path, OneOf(Vec), } impl DefinitionKind { + pub(crate) fn trustfall_kind(&self, _namespace: &str) -> String { + match self { + DefinitionKind::String => String::from("String!"), + DefinitionKind::Path => String::from("Path!"), + DefinitionKind::OneOf(_vecs) => String::from("String!"), + } + } + pub(crate) fn validate(&self, val: &KdlValue) -> Result<(), String> { match self { DefinitionKind::String => val .is_string() .then_some(()) .ok_or("Expected a string here".to_string()), + DefinitionKind::Path => val + .is_string() + .then_some(()) + .ok_or("Expected a path encoded as a string here".to_string()), DefinitionKind::OneOf(options) => val .as_string() .is_some_and(|val| options.iter().any(|o| o == val)) @@ -175,6 +185,23 @@ impl DefinitionKind { .ok_or_else(|| format!("Expected one of: {}", options.join(", "))), } } + + pub(crate) fn extra_trustfall_kinds( + &self, + namespace: &str, + ) -> Vec { + match self { + DefinitionKind::OneOf(defs) => { + let name = format!("{namespace}Def"); + let vec = vec![crate::adapter::CustomVertex { + definition: format!("enum {name} {{ {} }}", defs.join(",")), + name, + }]; + vec + } + _ => vec![], + } + } } impl TryFrom<&str> for DefinitionKind { @@ -182,18 +209,23 @@ impl TryFrom<&str> for DefinitionKind { fn try_from(value: &str) -> Result { match value.to_ascii_lowercase().as_str() { "string" => Ok(DefinitionKind::String), + "path" => Ok(DefinitionKind::Path), other => miette::bail!("Did not recognize valid field kind: \"{other}\""), } } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Definition { + pub(crate) name: String, pub(crate) since: Timestamp, - pub(crate) fields: HashMap, + pub(crate) fields: BTreeMap, } -pub(crate) fn parse_definition(bytes: &str) -> miette::Result> { +pub(crate) fn parse_definition( + bytes: &str, + definition_name: String, +) -> miette::Result> { let doc: KdlDocument = bytes.parse()?; let mut defs = vec![]; @@ -288,11 +320,27 @@ pub(crate) fn parse_definition(bytes: &str) -> miette::Result> { } }; + match field.name().value() { + "at" | "kind" => return Err(miette::diagnostic!( + labels = vec![LabeledSpan::new_primary_with_span( + Some(String::from("this name")), + field.name().span() + )], + help = "Both `at` and `kind` are reserved field names.", + "Reserved field name." + ))?, + _ => {} + } + Ok((field.name().to_string(), kind)) }) .collect::>()?; - defs.push(Definition { since, fields }); + defs.push(Definition { + since, + fields, + name: definition_name.clone(), + }); } unknown => { return Err(miette::diagnostic!( @@ -332,9 +380,10 @@ pub(crate) async fn load_definitions( }) .flat_map(|val| futures::stream::iter(val.transpose())) .and_then(|(name, bytes)| async move { + let definition_name = name.file_stem().unwrap().to_string(); Ok(( - name.file_stem().unwrap().to_string(), - parse_definition(&bytes).map_err(|e| { + definition_name.clone(), + parse_definition(&bytes, definition_name).map_err(|e| { e.with_source_code(NamedSource::new(name, bytes).with_language("kdl")) })?, )) @@ -344,4 +393,3 @@ pub(crate) async fn load_definitions( Ok(defs) } - diff --git a/examples/changelog.plrecs b/examples/changelog.plrecs index c2514ec..7e5be24 100644 --- a/examples/changelog.plrecs +++ b/examples/changelog.plrecs @@ -1,11 +1,31 @@ changelog "2025-01-29" { title "Added parsing of plaixt definitions" version "0.1.0" - kind "Feature" + type "Feature" } changelog "2025-01-30 09:10:59+01:00" { title "Added parsing of plaixt records" version "0.1.0" - kind "Feature" + type "Feature" +} + +changelog "2025-02-01" { + title "Added CLI options" + version "0.1.0" + type "Feature" +} + +changelog "2025-02-07" { + title "Added trustfall as a query frontend" + version "0.1.0" + type "Feature" +} + +file_test "2025-02-08" { + path "Cargo.toml" +} + +file_test "2025-02-08" { + path "/etc" } diff --git a/examples/definitions/changelog.pldef b/examples/definitions/changelog.pldef index 195ed5c..5709003 100644 --- a/examples/definitions/changelog.pldef +++ b/examples/definitions/changelog.pldef @@ -4,6 +4,6 @@ define since="2025-01-29 20:27:30+01:00" { fields { title is=string version is=string - kind { oneOf "Bugfix" "Feature" "Chore" } + type { oneOf "Bugfix" "Feature" "Chore" } } } diff --git a/examples/definitions/file_test.pldef b/examples/definitions/file_test.pldef new file mode 100644 index 0000000..40b12c0 --- /dev/null +++ b/examples/definitions/file_test.pldef @@ -0,0 +1,7 @@ +// This is the default changelog entry for the plaixt project + +define since="2025-02-08 00:00:00+01:00" { + fields { + path is="Path" + } +} diff --git a/flake.lock b/flake.lock index 5db1f8b..8eff4fc 100644 --- a/flake.lock +++ b/flake.lock @@ -63,11 +63,11 @@ ] }, "locked": { - "lastModified": 1738117527, - "narHash": "sha256-GFviGfaezjGLFUlxdv3zyC7rSZvTXqwcG/YsF6MDkOw=", + "lastModified": 1738981474, + "narHash": "sha256-YIELTXxfATG0g1wXjyaOWA4qrlubds3MG4FvMPCxSGg=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "6a3dc6ce4132bd57359214d986db376f2333c14d", + "rev": "5c571e5ff246d8fc5f76ba6e38dc8edb6e4002fe", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index e5c7893..2d2449a 100644 --- a/flake.nix +++ b/flake.nix @@ -16,8 +16,17 @@ }; }; - outputs = { self, nixpkgs, crane, flake-utils, rust-overlay, ... }: - flake-utils.lib.eachDefaultSystem (system: + outputs = + { + self, + nixpkgs, + crane, + flake-utils, + rust-overlay, + ... + }: + flake-utils.lib.eachDefaultSystem ( + system: let pkgs = import nixpkgs { inherit system; @@ -25,29 +34,51 @@ }; rustTarget = pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml; - unstableRustTarget = pkgs.rust-bin.selectLatestNightlyWith (toolchain: toolchain.default.override { - extensions = [ "rust-src" "miri" "rustfmt" ]; - }); + unstableRustTarget = pkgs.rust-bin.selectLatestNightlyWith ( + toolchain: + toolchain.default.override { + extensions = [ + "rust-src" + "miri" + "rustfmt" + ]; + } + ); craneLib = (crane.mkLib pkgs).overrideToolchain rustTarget; unstableCraneLib = (crane.mkLib pkgs).overrideToolchain unstableRustTarget; tomlInfo = craneLib.crateNameFromCargoToml { cargoToml = ./Cargo.toml; }; - inherit (tomlInfo) pname version; + inherit (tomlInfo) version; + src = ./.; rustfmt' = pkgs.writeShellScriptBin "rustfmt" '' exec "${unstableRustTarget}/bin/rustfmt" "$@" ''; - cargoArtifacts = craneLib.buildDepsOnly { - inherit src; - cargoExtraArgs = "--all-features --all"; + common = { + src = ./.; + + buildInputs = [ + pkgs.openssl + pkgs.pkg-config + ]; }; - plaixt = craneLib.buildPackage { - inherit cargoArtifacts src version; - cargoExtraArgs = "--all-features --all"; - }; + cargoArtifacts = craneLib.buildDepsOnly ( + common + // { + cargoExtraArgs = "--all-features --all"; + } + ); + + plaixt = craneLib.buildPackage ( + common + // { + inherit cargoArtifacts version; + cargoExtraArgs = "--all-features --all"; + } + ); in rec { @@ -78,6 +109,8 @@ devShells.plaixt = pkgs.mkShell { buildInputs = [ ]; + inputsFrom = [ plaixt ]; + nativeBuildInputs = [ rustfmt' rustTarget diff --git a/query b/query new file mode 100644 index 0000000..d6ba545 --- /dev/null +++ b/query @@ -0,0 +1,27 @@ +{ + Records { + ... on p_file_test { + _at @output + _kind @output + path { + ... on Directory { + Children @recurse(depth: 10) { + path @output + } + } + } + } + } + + # fs__Path(path: "./crates/plaixt/") { + # ... on fs__Folder { + # directory: path @output + # children @fold { + # ... on fs__File { + # file: path @output + # size @output + # } + # } + # } + # } +} diff --git a/rust-toolchain.toml b/rust-toolchain.toml index efd9dc3..fcb78ec 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel = "1.84.0" +channel = "1.84.1"