From 000181f6d99a7058ac630ad98841d2042bb6a6e7 Mon Sep 17 00:00:00 2001 From: Jeff Mendez Date: Fri, 6 Oct 2023 00:39:54 -0400 Subject: [PATCH] Get style for nodes (#15) * chore(parser): add fork parser scraper * chore(scraper): add style parsing scraper * chore(styles): add parsed styles * chore(innate): add parse inline css if sheet empty * chore(audit): add auditor base --- kayle_innate/Cargo.lock | 677 +++++++++++++++--- kayle_innate/Cargo.toml | 10 +- kayle_innate/src/engine/audit/auditor.rs | 65 ++ kayle_innate/src/engine/audit/mod.rs | 4 + kayle_innate/src/engine/audit/tree.rs | 74 ++ kayle_innate/src/engine/audit/wcag.rs | 10 +- kayle_innate/src/engine/rules/rule.rs | 12 +- .../src/engine/rules/wcag_rule_map.rs | 8 +- kayle_innate/src/engine/styles/css_cache.rs | 11 + kayle_innate/src/engine/styles/errors.rs | 12 +- kayle_innate/src/engine/styles/mod.rs | 88 +++ kayle_innate/src/engine/styles/rules.rs | 11 +- kayle_innate/src/lib.rs | 283 +------- kayle_innate/src/links.rs | 119 +++ 14 files changed, 993 insertions(+), 391 deletions(-) create mode 100644 kayle_innate/src/engine/audit/auditor.rs create mode 100644 kayle_innate/src/engine/audit/tree.rs create mode 100644 kayle_innate/src/engine/styles/css_cache.rs create mode 100644 kayle_innate/src/links.rs diff --git a/kayle_innate/Cargo.lock b/kayle_innate/Cargo.lock index f9d610c..52745e3 100644 --- a/kayle_innate/Cargo.lock +++ b/kayle_innate/Cargo.lock @@ -20,6 +20,21 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +[[package]] +name = "atomic_refcell" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f2bfe491d41d45507b8431da8274f7feeca64a49e86d980eed2937ec2ff020" + +[[package]] +name = "autocfg" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dde43e75fd43e8a1bf86103336bc699aa8d17ad1be60c76c0bdfd4828e19b78" +dependencies = [ + "autocfg 1.1.0", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -32,12 +47,6 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" -[[package]] -name = "bitflags" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" - [[package]] name = "bumpalo" version = "3.14.0" @@ -68,6 +77,15 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +dependencies = [ + "bitflags", +] + [[package]] name = "console_error_panic_hook" version = "0.1.7" @@ -78,42 +96,76 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +dependencies = [ + "autocfg 1.1.0", + "cfg-if 1.0.0", + "crossbeam-utils", + "memoffset", + "scopeguard 1.2.0", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +dependencies = [ + "cfg-if 1.0.0", +] + [[package]] name = "cssparser" -version = "0.31.0" +version = "0.25.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c18bf42b9ab91d1d7ce0192f5b432c9ab6a5728206f25ab6cb0eb61fea25bccc" +checksum = "fbe18ca4efb9ba3716c6da66cc3d7e673bf59fa576353011f48c4cfddbdd740e" dependencies = [ + "autocfg 0.1.8", "cssparser-macros", "dtoa-short", - "itoa", - "phf 0.11.2", - "proc-macro2", - "quote", - "smallvec", + "itoa 0.4.8", + "matches", + "phf 0.7.24", + "proc-macro2 1.0.67", + "procedural-masquerade", + "quote 1.0.33", + "smallvec 0.6.14", "syn 1.0.109", ] [[package]] name = "cssparser-macros" -version = "0.6.1" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" +checksum = "5bb1c84e87c717666564ec056105052331431803d606bd45529b28547b611eef" dependencies = [ - "quote", - "syn 2.0.37", + "phf_codegen 0.7.24", + "proc-macro2 1.0.67", + "procedural-masquerade", + "quote 1.0.33", + "syn 1.0.109", ] [[package]] -name = "derive_more" -version = "0.99.17" +name = "dtoa" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] +checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0" [[package]] name = "dtoa" @@ -127,7 +179,7 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbaceec3c6e4211c79e7b1800fb9680527106beb2f9c51904a3210c03a448c74" dependencies = [ - "dtoa", + "dtoa 1.0.9", ] [[package]] @@ -136,6 +188,33 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a68a4904193147e0a8dec3314640e6db742afd5f6e634f428a6af230d9b3591" +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "euclid" +version = "0.19.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "596b99621b9477e7a5f94d2d8dd13a9c5c302ac358b822c67a42b6f1054450e1" +dependencies = [ + "euclid_macros", + "num-traits", +] + +[[package]] +name = "euclid_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdcb84c18ea5037a1c5a23039b4ff29403abce2e0d6b1daa11cf0bde2b30be15" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "syn 0.15.44", +] + [[package]] name = "form_urlencoded" version = "1.2.0" @@ -145,6 +224,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + [[package]] name = "futf" version = "0.1.5" @@ -201,8 +286,8 @@ dependencies = [ "log", "mac", "markup5ever", - "proc-macro2", - "quote", + "proc-macro2 1.0.67", + "quote 1.0.33", "syn 1.0.109", ] @@ -216,6 +301,12 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "itoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" + [[package]] name = "itoa" version = "1.0.9" @@ -242,13 +333,15 @@ dependencies = [ "getrandom", "js-sys", "lazy_static", - "scraper", + "markup5ever", + "scraper_forky", "selectors", "serde", "serde-wasm-bindgen", - "smallvec", + "smallvec 0.6.14", "taffy", "url", + "victor_tree", "wasm-bindgen", "wasm-bindgen-test", "wee_alloc", @@ -266,14 +359,24 @@ version = "0.2.148" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" +[[package]] +name = "lock_api" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" +dependencies = [ + "owning_ref", + "scopeguard 0.3.3", +] + [[package]] name = "lock_api" version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" dependencies = [ - "autocfg", - "scopeguard", + "autocfg 1.1.0", + "scopeguard 1.2.0", ] [[package]] @@ -296,31 +399,64 @@ checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016" dependencies = [ "log", "phf 0.10.1", - "phf_codegen", + "phf_codegen 0.10.0", "string_cache", "string_cache_codegen", "tendril", ] +[[package]] +name = "matches" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" + +[[package]] +name = "maybe-uninit" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" + +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg 1.1.0", +] + [[package]] name = "memory_units" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" +[[package]] +name = "moite_moite" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eeb5a94c61e12e2cfc16ee3e2b6eca8f126a43c888586626337544a7e824a1af" + [[package]] name = "new_debug_unreachable" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" +[[package]] +name = "nodrop" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" + [[package]] name = "num-traits" version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" dependencies = [ - "autocfg", + "autocfg 1.1.0", ] [[package]] @@ -329,14 +465,46 @@ version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +[[package]] +name = "owning_ref" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ff55baddef9e4ad00f88b6c743a2a8062d4c6ade126c2a528644b8e444d52ce" +dependencies = [ + "stable_deref_trait", +] + +[[package]] +name = "parking_lot" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0802bff09003b291ba756dc7e79313e51cc31667e94afbe847def490424cde5" +dependencies = [ + "lock_api 0.1.5", + "parking_lot_core 0.3.1", +] + [[package]] name = "parking_lot" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ - "lock_api", - "parking_lot_core", + "lock_api 0.4.10", + "parking_lot_core 0.9.8", +] + +[[package]] +name = "parking_lot_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad7f7e6ebdc79edff6fdcb87a55b620174f7a989e3eb31b65231f4af57f00b8c" +dependencies = [ + "libc", + "rand 0.5.6", + "rustc_version", + "smallvec 0.6.14", + "winapi", ] [[package]] @@ -348,7 +516,7 @@ dependencies = [ "cfg-if 1.0.0", "libc", "redox_syscall", - "smallvec", + "smallvec 1.11.1", "windows-targets", ] @@ -358,6 +526,15 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +[[package]] +name = "phf" +version = "0.7.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3da44b85f8e8dfaec21adae67f95d93244b2ecf6ad2a692320598dcc8e6dd18" +dependencies = [ + "phf_shared 0.7.24", +] + [[package]] name = "phf" version = "0.10.1" @@ -368,13 +545,13 @@ dependencies = [ ] [[package]] -name = "phf" -version = "0.11.2" +name = "phf_codegen" +version = "0.7.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +checksum = "b03e85129e324ad4166b06b2c7491ae27fe3ec353af72e72cd1654c7225d517e" dependencies = [ - "phf_macros", - "phf_shared 0.11.2", + "phf_generator 0.7.24", + "phf_shared 0.7.24", ] [[package]] @@ -389,35 +566,31 @@ dependencies = [ [[package]] name = "phf_generator" -version = "0.10.0" +version = "0.7.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" +checksum = "09364cc93c159b8b06b1f4dd8a4398984503483891b0c26b867cf431fb132662" dependencies = [ - "phf_shared 0.10.0", - "rand", + "phf_shared 0.7.24", + "rand 0.6.5", ] [[package]] name = "phf_generator" -version = "0.11.2" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" dependencies = [ - "phf_shared 0.11.2", - "rand", + "phf_shared 0.10.0", + "rand 0.8.5", ] [[package]] -name = "phf_macros" -version = "0.11.2" +name = "phf_shared" +version = "0.7.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +checksum = "234f71a15de2288bcb7e3b6515828d22af7ec8598ee6d24c3b526fa0a80b67a0" dependencies = [ - "phf_generator 0.11.2", - "phf_shared 0.11.2", - "proc-macro2", - "quote", - "syn 2.0.37", + "siphasher 0.2.3", ] [[package]] @@ -426,16 +599,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" dependencies = [ - "siphasher", -] - -[[package]] -name = "phf_shared" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" -dependencies = [ - "siphasher", + "siphasher 0.3.11", ] [[package]] @@ -450,6 +614,15 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" +[[package]] +name = "proc-macro2" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +dependencies = [ + "unicode-xid", +] + [[package]] name = "proc-macro2" version = "1.0.67" @@ -459,13 +632,60 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "procedural-masquerade" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1383dff4092fe903ac180e391a8d4121cc48f08ccf850614b0290c6673b69d" + +[[package]] +name = "quote" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +dependencies = [ + "proc-macro2 0.4.30", +] + [[package]] name = "quote" version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ - "proc-macro2", + "proc-macro2 1.0.67", +] + +[[package]] +name = "rand" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9" +dependencies = [ + "cloudabi", + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "winapi", +] + +[[package]] +name = "rand" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" +dependencies = [ + "autocfg 0.1.8", + "libc", + "rand_chacha 0.1.1", + "rand_core 0.4.2", + "rand_hc", + "rand_isaac", + "rand_jitter", + "rand_os", + "rand_pcg", + "rand_xorshift", + "winapi", ] [[package]] @@ -475,8 +695,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", - "rand_core", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" +dependencies = [ + "autocfg 0.1.8", + "rand_core 0.3.1", ] [[package]] @@ -486,9 +716,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", ] +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + [[package]] name = "rand_core" version = "0.6.4" @@ -498,13 +743,123 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rand_hc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_isaac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_jitter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" +dependencies = [ + "libc", + "rand_core 0.4.2", + "winapi", +] + +[[package]] +name = "rand_os" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +dependencies = [ + "cloudabi", + "fuchsia-cprng", + "libc", + "rand_core 0.4.2", + "rdrand", + "winapi", +] + +[[package]] +name = "rand_pcg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" +dependencies = [ + "autocfg 0.1.8", + "rand_core 0.4.2", +] + +[[package]] +name = "rand_xorshift" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rayon" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "rayon_croissant" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b725e815f3aa08718063883a75003336889debafe2f8fa67fbe91563ddc4efa" +dependencies = [ + "moite_moite", + "rayon", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + [[package]] name = "redox_syscall" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags 1.3.2", + "bitflags", +] + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver", ] [[package]] @@ -519,6 +874,12 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" +[[package]] +name = "scopeguard" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" + [[package]] name = "scopeguard" version = "1.2.0" @@ -526,10 +887,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] -name = "scraper" +name = "scraper_forky" version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c95a930e03325234c18c7071fd2b60118307e025d6fff3e12745ffbf63a3d29c" +checksum = "6e58d69e133ec7908d0fe31de81e1e40f36bf5c33c8bd8e41a4a157d3a795bad" dependencies = [ "ahash", "cssparser", @@ -538,29 +899,44 @@ dependencies = [ "html5ever", "once_cell", "selectors", - "smallvec", + "smallvec 0.6.14", "tendril", ] [[package]] name = "selectors" -version = "0.25.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eb30575f3638fc8f6815f448d50cb1a2e255b0897985c8c59f4d37b72a07b06" +checksum = "1b86b100bede4f651059740afc3b6cb83458d7401cb7c1ad96d8a11e91742c86" dependencies = [ - "bitflags 2.4.0", + "bitflags", "cssparser", - "derive_more", "fxhash", "log", - "new_debug_unreachable", - "phf 0.10.1", - "phf_codegen", + "matches", + "phf 0.7.24", + "phf_codegen 0.7.24", "precomputed-hash", "servo_arc", - "smallvec", + "smallvec 0.6.14", + "thin-slice", +] + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", ] +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + [[package]] name = "serde" version = "1.0.188" @@ -587,8 +963,8 @@ version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.67", + "quote 1.0.33", "syn 2.0.37", ] @@ -598,20 +974,27 @@ version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" dependencies = [ - "itoa", + "itoa 1.0.9", "ryu", "serde", ] [[package]] name = "servo_arc" -version = "0.3.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d036d71a959e00c77a63538b90a6c2390969f9772b096ea837205c6bd0491a44" +checksum = "d98238b800e0d1576d8b6e3de32827c2d74bee68bb97748dcf5071fb53965432" dependencies = [ + "nodrop", "stable_deref_trait", ] +[[package]] +name = "siphasher" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac" + [[package]] name = "siphasher" version = "0.3.11" @@ -627,6 +1010,21 @@ dependencies = [ "version_check", ] +[[package]] +name = "smallbitvec" +version = "2.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75ce4f9dc4a41b4c3476cc925f1efb11b66df373a8fde5d4b8915fa91b5d995e" + +[[package]] +name = "smallvec" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97fcaeba89edba30f044a10c6a3cc39df9c3f17d7cd829dd1446cab35f890e0" +dependencies = [ + "maybe-uninit", +] + [[package]] name = "smallvec" version = "1.11.1" @@ -647,7 +1045,7 @@ checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" dependencies = [ "new_debug_unreachable", "once_cell", - "parking_lot", + "parking_lot 0.12.1", "phf_shared 0.10.0", "precomputed-hash", "serde", @@ -661,8 +1059,19 @@ checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" dependencies = [ "phf_generator 0.10.0", "phf_shared 0.10.0", - "proc-macro2", - "quote", + "proc-macro2 1.0.67", + "quote 1.0.33", +] + +[[package]] +name = "syn" +version = "0.15.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "unicode-xid", ] [[package]] @@ -671,8 +1080,8 @@ version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.67", + "quote 1.0.33", "unicode-ident", ] @@ -682,8 +1091,8 @@ version = "2.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.67", + "quote 1.0.33", "unicode-ident", ] @@ -710,6 +1119,12 @@ dependencies = [ "utf-8", ] +[[package]] +name = "thin-slice" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c" + [[package]] name = "tinyvec" version = "1.6.0" @@ -752,6 +1167,12 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" + [[package]] name = "url" version = "2.4.1" @@ -775,6 +1196,44 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "victor-tree-internal-proc-macros" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fb9a26b1452763752832db93fa95e9949fe7e4f5d44001a8712537897f2bb37" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "syn 0.15.44", +] + +[[package]] +name = "victor_tree" +version = "0.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b47ffd0cf2b7c91d117709862b6a8092c31e971d1e6af406876b7ccc3daafaf" +dependencies = [ + "atomic_refcell", + "cssparser", + "dtoa 0.4.8", + "euclid", + "html5ever", + "itoa 0.4.8", + "lazy_static", + "lock_api 0.1.5", + "num-traits", + "parking_lot 0.6.4", + "rayon", + "rayon_croissant", + "scraper_forky", + "selectors", + "smallbitvec", + "smallvec 0.6.14", + "victor-tree-internal-proc-macros", + "xi-unicode", + "xml-rs", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -802,8 +1261,8 @@ dependencies = [ "bumpalo", "log", "once_cell", - "proc-macro2", - "quote", + "proc-macro2 1.0.67", + "quote 1.0.33", "syn 2.0.37", "wasm-bindgen-shared", ] @@ -826,7 +1285,7 @@ version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" dependencies = [ - "quote", + "quote 1.0.33", "wasm-bindgen-macro-support", ] @@ -836,8 +1295,8 @@ version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.67", + "quote 1.0.33", "syn 2.0.37", "wasm-bindgen-backend", "wasm-bindgen-shared", @@ -869,8 +1328,8 @@ version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ecb993dd8c836930ed130e020e77d9b2e65dd0fbab1b67c790b0f5d80b11a575" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.67", + "quote 1.0.33", ] [[package]] @@ -973,3 +1432,15 @@ name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "xi-unicode" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12ea8eda4b1eb72f02d148402e23832d56a33f55d8c1b2d5bcdde91d79d47cb1" + +[[package]] +name = "xml-rs" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a" diff --git a/kayle_innate/Cargo.toml b/kayle_innate/Cargo.toml index c0dbc50..dcd2fcf 100644 --- a/kayle_innate/Cargo.toml +++ b/kayle_innate/Cargo.toml @@ -21,18 +21,20 @@ wee_alloc = { version = "0.4.5", optional = true } url = "2.4.0" lazy_static = "1.4.0" case_insensitive_string = "0.1.0" -scraper = { version = "0.17.1", features = ["main"], default-features = false } +scraper_forky = { version = "0.17.1", features = ["main"], default-features = false } getrandom = { version = "0.2", features = ["js"] } taffy = { version = "0.3.13", optional = true } serde = { version = "1.0", features = ["derive"] } serde-wasm-bindgen = "0.4" js-sys = "0.3.64" -selectors = "0.25.0" -smallvec = "1.11.1" +selectors = "=0.21.0" +smallvec = "0.6" ego-tree = "0.6.2" +victor_tree = { version = "0.0.7" } +markup5ever = "0.11.0" [dependencies.cssparser] -version = "^0.31.0" +version = "^0.25.0" [dev-dependencies] wasm-bindgen-test = "0.3.37" diff --git a/kayle_innate/src/engine/audit/auditor.rs b/kayle_innate/src/engine/audit/auditor.rs new file mode 100644 index 0000000..d4886b1 --- /dev/null +++ b/kayle_innate/src/engine/audit/auditor.rs @@ -0,0 +1,65 @@ +use scraper_forky::ElementRef; +use scraper_forky::Html; +use victor_tree::style::StyleSet; + +use super::tree::parse_accessibility_tree; + +/// the intro to an audit +pub struct Auditor<'a> { + /// the html document + pub document: &'a Html, + /// the tree to map to nodes + pub tree: std::collections::BTreeMap<&'a str, Vec>>, + /// styles for the audit + pub author: StyleSet, + // /// the matching context for css selectors + pub match_context: selectors::matching::MatchingContext<'a, scraper_forky::selector::Simple>, +} + +impl<'a> Auditor<'a> { + pub fn new( + document: &'a Html, + css_rules: &str, + match_context: selectors::matching::MatchingContext<'a, scraper_forky::selector::Simple>, + ) -> Auditor<'a> { + use crate::{console_log, now}; + let t = now(); + let tree = parse_accessibility_tree(&document); + console_log!("Tree Build Time {:?}", now() - t); + let tt = now(); + + // TODO: make stylesheet building optional and only on first requirement + let author = { + let mut author = victor_tree::style::StyleSetBuilder::new(); + if !css_rules.is_empty() { + author.add_stylesheet(css_rules); + } else { + use markup5ever::local_name; + match tree.get("style") { + Some(styles) => { + for node in styles { + // https://html.spec.whatwg.org/multipage/semantics.html#update-a-style-block + if let Some(type_attr) = node.attr(&local_name!("type")) { + if !type_attr.eq_ignore_ascii_case("text/css") { + continue; + } + author.add_stylesheet(&node.inner_html()) + } + } + } + _ => (), + } + } + author.finish() + }; + + console_log!("StyleSheets Build Time {:?}", now() - tt); + + Auditor { + document, + tree, + author, + match_context, + } + } +} diff --git a/kayle_innate/src/engine/audit/mod.rs b/kayle_innate/src/engine/audit/mod.rs index f039155..c31cc56 100644 --- a/kayle_innate/src/engine/audit/mod.rs +++ b/kayle_innate/src/engine/audit/mod.rs @@ -1,2 +1,6 @@ +/// the auditor +pub mod auditor; +/// the node tree +pub mod tree; /// WCAG audit pub mod wcag; diff --git a/kayle_innate/src/engine/audit/tree.rs b/kayle_innate/src/engine/audit/tree.rs new file mode 100644 index 0000000..153f5c9 --- /dev/null +++ b/kayle_innate/src/engine/audit/tree.rs @@ -0,0 +1,74 @@ +use scraper_forky::ElementRef; +use std::collections::BTreeMap; + +/// try to fix all possible issues using a spec against the tree. +pub fn parse_accessibility_tree( + html: &scraper_forky::Html, + // todo: return the nodes with a tuple of the layout node and the element node +) -> std::collections::BTreeMap<&str, Vec>> { + // use taffy::prelude::*; + // // todo: use optional variable for clips or layout creation + // let mut taffy = Taffy::new(); + + // let header_node = taffy + // .new_leaf(Style { + // size: Size { + // width: points(800.0), + // height: points(100.0), + // }, + // ..Default::default() + // }) + // .unwrap(); + + // let body_node = taffy + // .new_leaf(Style { + // size: Size { + // width: points(800.0), + // height: auto(), + // }, + // flex_grow: 1.0, + // ..Default::default() + // }) + // .unwrap(); + + // let root_node = taffy + // .new_with_children( + // Style { + // flex_direction: FlexDirection::Column, + // size: Size { + // width: points(800.0), + // height: points(600.0), + // }, + // ..Default::default() + // }, + // &[header_node, body_node], + // ) + // .unwrap(); + + // // Call compute_layout on the root of your tree to run the layout algorithm + // taffy.compute_layout(root_node, Size::MAX_CONTENT).unwrap(); + // console_log!("Header Layout {:?}", taffy.layout(header_node).unwrap()); + // We can get the x,y, and height, width of the element on proper tree insert + + // parse doc will start from html downwards + // accessibility tree for ordered element mappings + let mut accessibility_tree: BTreeMap<&str, Vec>> = + BTreeMap::from([("title".into(), Default::default())]); + + for node in html.tree.nodes() { + match scraper_forky::element_ref::ElementRef::wrap(node) { + Some(element) => { + accessibility_tree + .entry(element.value().name()) + .and_modify(|n| n.push(element)) + .or_insert(Vec::from([element])); + } + _ => (), + }; + } + + // console_log!("Getting tree links {:?}", accessibility_tree.get("a")); + // console_log!("Tree {:?}", accessibility_tree); + + accessibility_tree +} diff --git a/kayle_innate/src/engine/audit/wcag.rs b/kayle_innate/src/engine/audit/wcag.rs index b5de802..51a0a98 100644 --- a/kayle_innate/src/engine/audit/wcag.rs +++ b/kayle_innate/src/engine/audit/wcag.rs @@ -1,7 +1,7 @@ use crate::engine::rules::wcag_rule_map::RULES_A; use crate::i18n::locales::{get_message, Langs}; +use crate::Auditor; use crate::{console_log, engine::issue::Issue}; -use scraper::ElementRef; /// baseline for all rules #[derive(Default)] @@ -12,21 +12,19 @@ impl WCAG3AA { /// init the rules pub fn audit( // allow tree mutation until threads or setup the tree with initial elements. - tree: &std::collections::BTreeMap<&str, Vec>>, - _css: cssparser::Parser<'_, '_>, + auditor: &Auditor<'_>, // todo: get configs like viewport ) -> Vec { let mut issues: Vec = Vec::new(); // go through nodes and map to validation rules - for node in tree { + for node in &auditor.tree { if RULES_A.contains_key(&*node.0) { let rules = RULES_A.get(&*node.0); match rules { Some(rules) => { for rule in rules { - let (valid, section, selector) = - (rule.validate)(&node.0, &node.1, &_css); + let (valid, section, selector) = (rule.validate)(&node.0, &node.1); if !valid { // get locales prior or from document diff --git a/kayle_innate/src/engine/rules/rule.rs b/kayle_innate/src/engine/rules/rule.rs index 12e29d4..4af13d4 100644 --- a/kayle_innate/src/engine/rules/rule.rs +++ b/kayle_innate/src/engine/rules/rule.rs @@ -9,11 +9,7 @@ pub struct Rule { /// the type of rule pub criteria: Criteria, /// validate a test returns (valid, rule, selectors) - pub validate: fn( - &str, - &Vec>, - css: &cssparser::Parser<'_, '_>, - ) -> (bool, &'static str, Vec<&'static str>), + pub validate: fn(&str, &Vec>) -> (bool, &'static str, Vec<&'static str>), /// the principle type pub principle: Principle, /// the guideline to follow @@ -27,11 +23,7 @@ impl Rule { criteria: Criteria, principle: Principle, guideline: Guideline, - validate: fn( - &str, - &Vec>, - &cssparser::Parser<'_, '_>, - ) -> (bool, &'static str, Vec<&'static str>), + validate: fn(&str, &Vec>) -> (bool, &'static str, Vec<&'static str>), ) -> Rule { Rule { rule_id, diff --git a/kayle_innate/src/engine/rules/wcag_rule_map.rs b/kayle_innate/src/engine/rules/wcag_rule_map.rs index e4105e4..af604bc 100644 --- a/kayle_innate/src/engine/rules/wcag_rule_map.rs +++ b/kayle_innate/src/engine/rules/wcag_rule_map.rs @@ -1,7 +1,7 @@ use crate::engine::rules::ids::Techniques; use crate::engine::rules::rule::Rule; use crate::engine::rules::wcag_base::{Criteria, Guideline, Principle}; -use scraper::Selector; +use scraper_forky::Selector; use std::collections::BTreeMap; // todo: validate each element and add a shape that can prevent repitiion @@ -11,16 +11,16 @@ lazy_static! { vec![ // empty titles ("title", Vec::from([ - Rule::new(Techniques::H25, Criteria::Error, Principle::Operable, Guideline::Navigable, |_rule, nodes, _css_parser| { + Rule::new(Techniques::H25, Criteria::Error, Principle::Operable, Guideline::Navigable, |_rule, nodes| { (!nodes.is_empty(), "1.NoTitleEl", Default::default()) }), - Rule::new(Techniques::H25, Criteria::Error, Principle::Understandable, Guideline::Predictable, |_rule, nodes, _css_parser| { + Rule::new(Techniques::H25, Criteria::Error, Principle::Understandable, Guideline::Predictable, |_rule, nodes| { (nodes.is_empty() || nodes[0].html().is_empty(), "2", Default::default()) }), ])), // missing label ("form", Vec::from([ - Rule::new(Techniques::H32, Criteria::Error, Principle::Operable, Guideline::Predictable, |_rule, nodes, _css_parser| { + Rule::new(Techniques::H32, Criteria::Error, Principle::Operable, Guideline::Predictable, |_rule, nodes| { // check the first element for now let mut valid = false; let selector = unsafe { Selector::parse("button[type=submit]").unwrap_unchecked() }; diff --git a/kayle_innate/src/engine/styles/css_cache.rs b/kayle_innate/src/engine/styles/css_cache.rs new file mode 100644 index 0000000..08ade4f --- /dev/null +++ b/kayle_innate/src/engine/styles/css_cache.rs @@ -0,0 +1,11 @@ +/// build matching context +pub fn build_matching_context<'a>( + nth_index_cache: &'a mut selectors::NthIndexCache, +) -> selectors::matching::MatchingContext<'a, scraper_forky::selector::Simple> { + selectors::matching::MatchingContext::new( + selectors::matching::MatchingMode::Normal, + None, + Some(nth_index_cache), + selectors::matching::QuirksMode::NoQuirks, + ) +} diff --git a/kayle_innate/src/engine/styles/errors.rs b/kayle_innate/src/engine/styles/errors.rs index 01859f0..3114816 100644 --- a/kayle_innate/src/engine/styles/errors.rs +++ b/kayle_innate/src/engine/styles/errors.rs @@ -1,12 +1,12 @@ -use cssparser::{CowRcStr, ParseError}; +// use cssparser::{CowRcStr, ParseError}; use selectors::parser::SelectorParseErrorKind; -pub type PropertyParseError<'i> = ParseError<'i, PropertyParseErrorKind<'i>>; +// pub type PropertyParseError<'i> = ParseError<'i, PropertyParseErrorKind<'i>>; -pub enum PropertyParseErrorKind<'i> { - UnknownProperty(CowRcStr<'i>), - UnknownUnit(CowRcStr<'i>), -} +// pub enum PropertyParseErrorKind<'i> { +// UnknownProperty(CowRcStr<'i>), +// UnknownUnit(CowRcStr<'i>), +// } pub enum RuleParseErrorKind<'i> { Selector(SelectorParseErrorKind<'i>), diff --git a/kayle_innate/src/engine/styles/mod.rs b/kayle_innate/src/engine/styles/mod.rs index 9104ee7..ec5fbc3 100644 --- a/kayle_innate/src/engine/styles/mod.rs +++ b/kayle_innate/src/engine/styles/mod.rs @@ -1,2 +1,90 @@ +pub mod css_cache; pub mod errors; pub mod rules; + +use crate::console_log; +use cssparser::{Parser, ParserInput}; +use markup5ever::local_name; +use markup5ever::namespace_url; +use markup5ever::ns; +use scraper_forky::selector::Simple; +use scraper_forky::{ElementRef, Html}; +use selectors::matching::MatchingContext; +use std::sync::Arc; +use victor_tree::style::cascade::USER_AGENT_STYLESHEET; +use victor_tree::style::declaration_block::DeclarationBlock; +use victor_tree::style::values::{Direction, WritingMode}; +use victor_tree::style::{ComputedValues, StyleSet}; + +/// get the style for an element +pub fn style_for_element<'a>( + author: &StyleSet, + _document: &Html, + node: ElementRef<'a>, + parent_style: Option<&ComputedValues>, + match_context: &mut MatchingContext<'_, Simple>, +) -> Arc { + use smallvec::SmallVec; + let style_attr_block; + let mut matching = victor_tree::style::cascade::MatchingDeclarations { + ua: SmallVec::new(), + author: SmallVec::new(), + }; + + // let mut nth_index_cache = selectors::NthIndexCache::from(Default::default()); + // let mut match_context = selectors::matching::MatchingContext::new( + // selectors::matching::MatchingMode::Normal, + // None, + // Some(&mut nth_index_cache), + // selectors::matching::QuirksMode::NoQuirks, + // // selectors::matching::NeedsSelectorFlags::No, + // // selectors::matching::IgnoreNthChildForInvalidation::No, + // ); + + for &(ref selector, ref block) in &USER_AGENT_STYLESHEET.rules { + if selectors::matching::matches_selector( + selector, + 0, + None, + &node, + match_context, + &mut |_, _| {}, + ) { + matching.ua.push(block) + } + } + + // push author style sheet + for &(ref selector, ref block) in &author.rules { + if selectors::matching::matches_selector( + selector, + 0, + None, + &node, + match_context, + &mut |_, _| {}, + ) { + matching.author.push(block) + } + } + + if let ns!(html) | ns!(svg) | ns!(mathml) = node.value().name.ns { + if let Some(style_attr) = node.value().attr(&local_name!("style")) { + let mut input = ParserInput::new(style_attr); + let mut parser = Parser::new(&mut input); + style_attr_block = DeclarationBlock::parse(&mut parser); + matching.author.push(&style_attr_block); + } + } + + let styles = ComputedValues::new(parent_style, Some(&matching)); + + console_log!( + "{:?}", + styles + .box_size() + .size_to_physical((WritingMode::SidewaysLr, Direction::Ltr)) + ); + + styles +} diff --git a/kayle_innate/src/engine/styles/rules.rs b/kayle_innate/src/engine/styles/rules.rs index c00da29..e1a3de5 100644 --- a/kayle_innate/src/engine/styles/rules.rs +++ b/kayle_innate/src/engine/styles/rules.rs @@ -1,7 +1,6 @@ use crate::engine::styles::errors::RuleParseErrorKind; use cssparser::{AtRuleParser, ParseError, QualifiedRuleParser}; -use scraper::selector::Simple; -use selectors::parser::ParseRelative; +use scraper_forky::selector::Simple; use std::sync::Arc; #[derive(Debug)] @@ -33,13 +32,13 @@ impl<'i> QualifiedRuleParser<'i> for RulesParser { &mut self, parser: &mut cssparser::Parser<'i, 't>, ) -> Result> { - SelectorList::parse(&Parser, parser, ParseRelative::No) + SelectorList::parse(&Parser, parser) } fn parse_block<'t>( &mut self, prelude: Self::Prelude, - _location: &cssparser::ParserState, + _location: cssparser::SourceLocation, _parser: &mut cssparser::Parser<'i, 't>, ) -> Result> { Ok(CssRule::StyleRule { @@ -50,7 +49,9 @@ impl<'i> QualifiedRuleParser<'i> for RulesParser { } impl<'i> AtRuleParser<'i> for RulesParser { - type Prelude = (); + type PreludeBlock = (); + type PreludeNoBlock = (); + type AtRule = CssRule; type Error = RuleParseErrorKind<'i>; } diff --git a/kayle_innate/src/lib.rs b/kayle_innate/src/lib.rs index f6f7a6c..eb085d4 100644 --- a/kayle_innate/src/lib.rs +++ b/kayle_innate/src/lib.rs @@ -1,22 +1,24 @@ #[cfg(feature = "wee_alloc")] #[global_allocator] static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; -use wasm_bindgen::prelude::*; +pub use wasm_bindgen::prelude::*; #[macro_use] extern crate lazy_static; +/// the main engine for audits mod engine; +/// locales mod i18n; +/// used for auto-kayle to gather all links in a page. +mod links; +/// helpers mod utils; -use case_insensitive_string::CaseInsensitiveString; #[cfg(feature = "accessibility")] -use scraper::ElementRef; +use crate::engine::audit::auditor::Auditor; #[cfg(feature = "accessibility")] -use std::collections::BTreeMap; -use std::collections::HashSet; -use utils::{convert_abs_path, convert_base_path, domain_name, set_panic_hook}; +use scraper_forky::ElementRef; #[cfg(feature = "accessibility")] #[wasm_bindgen] @@ -37,259 +39,34 @@ macro_rules! console_log { ($($t:tt)*) => (crate::log(&format_args!($($t)*).to_string())) } -#[wasm_bindgen] -/// setup a structure tree alg for parsing and find links in document. Allow user to perform hybrid audits realtime. -pub fn get_document_links(res: &str, domain: &str) -> Box<[JsValue]> { - set_panic_hook(); - - lazy_static! { - /// include only list of resources - static ref ONLY_RESOURCES: HashSet = { - let mut m: HashSet = HashSet::with_capacity(14); - - m.extend([ - "html", "htm", "asp", "aspx", "php", "jps", "jpsx", - // handle .. prefix for urls ending with an extra ending - ".html", ".htm", ".asp", ".aspx", ".php", ".jps", ".jpsx", - ].map(|s| s.into())); - - m - }; - } - - let links = match url::Url::parse(domain) { - Ok(base) => { - let base_url = convert_base_path(base); - let base_domain = domain_name(&base_url); - let parent_host_scheme = base_url.scheme(); - let parent_host = base_url.host_str().unwrap_or_default(); - - let h = scraper::Html::parse_fragment(res); - - h.tree - .into_iter() - .filter_map(|node| { - if let Some(element) = node.as_element() { - if element.name() == "a" { - match element.attr("href") { - Some(link) => { - let mut abs = convert_abs_path(&base_url, link); - let mut can_process = match abs.host_str() { - Some(host) => parent_host.ends_with(host), - _ => false, - }; - - let process = if can_process { - if abs.scheme() != parent_host_scheme { - let _ = abs.set_scheme(parent_host_scheme); - } - - let hchars = abs.path(); - - if let Some(position) = hchars.find('.') { - let resource_ext = &hchars[position + 1..hchars.len()]; - - if !ONLY_RESOURCES.contains::( - &resource_ext.into(), - ) { - can_process = false; - } - } - - if can_process - && (base_domain.is_empty() - || base_domain == domain_name(&abs)) - { - Some(JsValue::from_str(&abs.as_str())) - } else { - None - } - } else { - None - }; - - process - } - _ => None, - } - } else { - None - } - } else { - None - } - }) - .collect::>() - } - _ => { - let h = scraper::Html::parse_fragment(res); - - h.tree - .into_iter() - .filter_map(|node| { - if let Some(element) = node.as_element() { - if element.name() == "a" { - match element.attr("href") { - Some(link) => { - // TODO: validate only web links - Some(JsValue::from_str(&link)) - } - _ => None, - } - } else { - None - } - } else { - None - } - }) - .collect::>() - } - }; - - links.into_boxed_slice() -} - -// RUST_LOG=info wasm-pack test --firefox --headless --features accessibility --release -#[cfg(feature = "accessibility")] -/// try to fix all possible issues using a spec against the tree. -pub fn parse_accessibility_tree( - html: &scraper::Html, - // todo: return the nodes with a tuple of the layout node and the element node -) -> std::collections::BTreeMap<&str, Vec>> { - // use taffy::prelude::*; - // // todo: use optional variable for clips or layout creation - // let mut taffy = Taffy::new(); - - // let header_node = taffy - // .new_leaf(Style { - // size: Size { - // width: points(800.0), - // height: points(100.0), - // }, - // ..Default::default() - // }) - // .unwrap(); - - // let body_node = taffy - // .new_leaf(Style { - // size: Size { - // width: points(800.0), - // height: auto(), - // }, - // flex_grow: 1.0, - // ..Default::default() - // }) - // .unwrap(); - - // let root_node = taffy - // .new_with_children( - // Style { - // flex_direction: FlexDirection::Column, - // size: Size { - // width: points(800.0), - // height: points(600.0), - // }, - // ..Default::default() - // }, - // &[header_node, body_node], - // ) - // .unwrap(); - - // // Call compute_layout on the root of your tree to run the layout algorithm - // taffy.compute_layout(root_node, Size::MAX_CONTENT).unwrap(); - // console_log!("Header Layout {:?}", taffy.layout(header_node).unwrap()); - // We can get the x,y, and height, width of the element on proper tree insert - - let t = now(); - // parse doc will start from html downwards - // accessibility tree for ordered element mappings - let mut accessibility_tree: BTreeMap<&str, Vec>> = - BTreeMap::from([("title".into(), Default::default())]); - - for node in html.tree.nodes() { - match scraper::element_ref::ElementRef::wrap(node) { - Some(element) => { - accessibility_tree - .entry(element.value().name()) - .and_modify(|n| n.push(element)) - .or_insert(Vec::from([element])); - } - _ => (), - }; - } - - console_log!("Scraper Parser: duration {:?}ms", now() - t); - // console_log!("Getting tree links {:?}", accessibility_tree.get("a")); - // console_log!("Tree {:?}", accessibility_tree); - - accessibility_tree -} - #[wasm_bindgen] #[cfg(feature = "accessibility")] /// audit a web page passing the html and css rules. -pub fn _audit_not_ready(html: &str, _css_rules: &str) -> Result { - // use selectors::matching::{MatchingContext, MatchingMode, QuirksMode}; - - let html = scraper::Html::parse_document(html); - let _tree = parse_accessibility_tree(&html); - // TODO: if the css rules are empty extract the css from the HTML - let css_rules = &mut cssparser::ParserInput::new(&_css_rules); - // TODO: build the rules to css blocks that selectors can be used to find the element of the style. - let mut _css_parser = cssparser::Parser::new(css_rules); - let css_rules_parser = cssparser::RuleListParser::new_for_stylesheet( - &mut _css_parser, - crate::engine::styles::rules::RulesParser, +pub fn _audit_not_ready(html: &str, css_rules: &str) -> Result { + let t = now(); + let document = scraper_forky::Html::parse_document(html); + console_log!("Parse Document Time {:?}", now() - t); + let mut nth_index_cache = selectors::NthIndexCache::from(Default::default()); + let auditor = Auditor::new( + &document, + &css_rules, + engine::styles::css_cache::build_matching_context(&mut nth_index_cache), ); + let ttt = now(); + let _audit = engine::audit::wcag::WCAG3AA::audit(&auditor); + console_log!("Audit Time {:?}", now() - ttt); + + // let mut _match_context = auditor.match_context; - let mut rules = Vec::new(); - - // todo: parse the rules out correctly to nodes and add declarations - for result in css_rules_parser { - match result { - Ok(crate::engine::styles::rules::CssRule::StyleRule { selectors, block }) => { - for selector in selectors.0 { - rules.push((selector, block.clone())); - } - } - _ => (), - }; - } - - console_log!("CSS RULES: {:?}", rules); - - let _audit = engine::audit::wcag::WCAG3AA::audit(&_tree, _css_parser); - - // TODO: build struct that can keep lifetimes - // let mut nth_index_cache = selectors::NthIndexCache::from(Default::default()); - // let mut match_context = MatchingContext::new( - // MatchingMode::Normal, - // None, - // &mut nth_index_cache, - // QuirksMode::NoQuirks, - // selectors::matching::NeedsSelectorFlags::No, - // selectors::matching::IgnoreNthChildForInvalidation::No, - // ); - - // for item in _tree { + // for item in auditor.tree { // for node in item.1 { - // let id = node.id(); - - // // todo: use the css block style to get computations - // for &(ref selector, ref _block) in &rules { - // if selectors::matching::matches_selector( - // selector, - // 0, - // None, - // &node, - // &mut match_context, - // ) { - // console_log!("Style Match {:?}", id); - // // build all the styles for the element based on the match - // // into.push(_block) - // } - // } + // let _style = victor_tree::style::cascade::style_for_element_ref( + // &node, + // &auditor.author, + // &document, + // &mut _match_context, + // ); + // console_log!("{:?}", _style.as_ref().box_size()) // } // } diff --git a/kayle_innate/src/links.rs b/kayle_innate/src/links.rs new file mode 100644 index 0000000..4bb6b77 --- /dev/null +++ b/kayle_innate/src/links.rs @@ -0,0 +1,119 @@ +use crate::wasm_bindgen; +use crate::JsValue; + +use crate::utils::{convert_abs_path, convert_base_path, domain_name, set_panic_hook}; +use case_insensitive_string::CaseInsensitiveString; +use std::collections::HashSet; + +#[wasm_bindgen] +/// setup a structure tree alg for parsing and find links in document. Allow user to perform hybrid audits realtime. +pub fn get_document_links(res: &str, domain: &str) -> Box<[JsValue]> { + set_panic_hook(); + + lazy_static! { + /// include only list of resources + static ref ONLY_RESOURCES: HashSet = { + let mut m: HashSet = HashSet::with_capacity(14); + + m.extend([ + "html", "htm", "asp", "aspx", "php", "jps", "jpsx", + // handle .. prefix for urls ending with an extra ending + ".html", ".htm", ".asp", ".aspx", ".php", ".jps", ".jpsx", + ].map(|s| s.into())); + + m + }; + } + + let links = match url::Url::parse(domain) { + Ok(base) => { + let base_url = convert_base_path(base); + let base_domain = domain_name(&base_url); + let parent_host_scheme = base_url.scheme(); + let parent_host = base_url.host_str().unwrap_or_default(); + + let h = scraper_forky::Html::parse_fragment(res); + + h.tree + .into_iter() + .filter_map(|node| { + if let Some(element) = node.as_element() { + if element.name() == "a" { + match element.attr("href") { + Some(link) => { + let mut abs = convert_abs_path(&base_url, link); + let mut can_process = match abs.host_str() { + Some(host) => parent_host.ends_with(host), + _ => false, + }; + + let process = if can_process { + if abs.scheme() != parent_host_scheme { + let _ = abs.set_scheme(parent_host_scheme); + } + + let hchars = abs.path(); + + if let Some(position) = hchars.find('.') { + let resource_ext = &hchars[position + 1..hchars.len()]; + + if !ONLY_RESOURCES.contains::( + &resource_ext.into(), + ) { + can_process = false; + } + } + + if can_process + && (base_domain.is_empty() + || base_domain == domain_name(&abs)) + { + Some(JsValue::from_str(&abs.as_str())) + } else { + None + } + } else { + None + }; + + process + } + _ => None, + } + } else { + None + } + } else { + None + } + }) + .collect::>() + } + _ => { + let h = scraper_forky::Html::parse_fragment(res); + + h.tree + .into_iter() + .filter_map(|node| { + if let Some(element) = node.as_element() { + if element.name() == "a" { + match element.attr("href") { + Some(link) => { + // TODO: validate only web links + Some(JsValue::from_str(&link)) + } + _ => None, + } + } else { + None + } + } else { + None + } + }) + .collect::>() + } + }; + + links.into_boxed_slice() +}