From bbcf9ecfe0189fc2587e1fbb5b4f28ca68cb1543 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Sat, 12 Oct 2024 19:37:07 -0400 Subject: [PATCH] wip: testing --- crates/core/Cargo.toml | 3 + crates/core/src/lib.rs | 136 ++++++++++++++ crates/core/src/main.rs | 380 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 519 insertions(+) create mode 100644 crates/core/src/main.rs diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index ef2d27aed..c321d22b0 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -18,6 +18,9 @@ serde_json = "1.0.127" log = "0.4.22" wasm-bindgen = "0.2.93" bstr = "1.10.0" +memmem = "0.1.1" +memchr = "2.7.4" +tinyvec = { version = "1.8.0", features = ["alloc"] } [dev-dependencies] rstest = "0.22.0" diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index 389dd3264..03a336535 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -1 +1,137 @@ +mod compat; mod css; +mod util; + +use css::optimize::optimize_ast; +use css::parser::parse; +use wasm_bindgen::prelude::*; +use std::cell::Cell; +use css::ast::CssNode; +use css::visit::WalkAction; + +#[wasm_bindgen] +pub fn wip() { + // 1. Parse the CSS + let mut ast = parse(b"h1 { color: red; font-size: 2em; } h2 { color: blue; font-size: 1.5em; }").unwrap(); + + // 2. Walk the AST and mutate all color properties to green + ast.walk_mut(&mut |node| { + let CssNode::Declaration { property, value, .. } = node else { + return WalkAction::Continue; + }; + + if property != b"color" { + return WalkAction::Continue; + } + + *value = "green".into(); + + return WalkAction::Continue; + }); + + // 3. Walk the AST and count the number of font-size properties + let count = Cell::new(0); + + ast.walk(&|node| { + let CssNode::Declaration { property, .. } = node else { + return WalkAction::Continue; + }; + + if property != b"font-size" { + return WalkAction::Continue; + } + + count.set(count.get() + 1); + + WalkAction::Continue + }); + + // 4. Optimize the AST + optimize_ast(&mut ast); + + // 5. Serialize the AST back to CSS + let css = ast.to_css(); + + // 6. Print the CSS + println!("{}", String::from_utf8_lossy(&css)); + println!("{}", count.get()); +} + +// use css::ast::{decl, rule, Ast, AstNode, WalkAction}; + +// pub struct Compiler { +// ast: Stylesheet, +// config_paths: Vec, +// plugin_paths: Vec, +// } + +// impl Compiler { +// fn new(css: &[u8]) -> Compiler { +// let mut ast = parse_css(css); +// let mut plugin_paths = vec![]; +// let mut config_paths = vec![]; + +// ast.walk(&mut |node, _| { +// let AstNode::Rule { selector, .. } = node else { +// return WalkAction::Continue; +// }; + +// if selector.starts_with(b"@plugin") { +// let path = selector.split_at(7).1; +// let path = &path[2..path.len()-1]; +// let path = path.to_vec(); + +// plugin_paths.push(unsafe { +// String::from_utf8_unchecked(path) +// }); +// } + +// if selector.starts_with(b"@config") { +// let path = selector.split_at(7).1; +// let path = &path[2..path.len()-1]; +// let path = path.to_vec(); + +// config_paths.push(unsafe { +// String::from_utf8_unchecked(path) +// }); +// } + +// WalkAction::Continue +// }); + +// Compiler { +// ast, +// } +// } + +// // fn plugin_paths(&self) -> Vec { +// // vec![] +// // } + +// // fn config_paths(&self) -> Vec { +// // vec![] +// // } +// } + +// fn parse_css(css: &[u8]) -> Ast { +// // TODO: Parse the CSS into an AST +// _ = css; + +// Ast::from(vec![ +// rule(b"body", vec![ +// decl(b"color", Some(b"red"), false), +// ]), +// ]) +// } + +// fn foo() { +// let css = b"body { color: red; }"; +// let compiler = Compiler::new(css); +// } + +// enum UtilityDescriptor { +// Simple { +// name: String, +// ast: Ast, +// }, +// } diff --git a/crates/core/src/main.rs b/crates/core/src/main.rs new file mode 100644 index 000000000..187fdcc4d --- /dev/null +++ b/crates/core/src/main.rs @@ -0,0 +1,380 @@ +use std::hint::black_box; + +const PREFLIGHT: &'static str = r#"/* + 1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) + 2. Remove default margins and padding + 3. Reset all borders. +*/ + +*, +::after, +::before, +::backdrop, +::file-selector-button { + box-sizing: border-box; /* 1 */ + margin: 0; /* 2 */ + padding: 0; /* 2 */ + border: 0 solid; /* 3 */ +} + +/* + 1. Use a consistent sensible line-height in all browsers. + 2. Prevent adjustments of font size after orientation changes in iOS. + 3. Use a more readable tab size. + 4. Use the user's configured `sans` font-family by default. + 5. Use the user's configured `sans` font-feature-settings by default. + 6. Use the user's configured `sans` font-variation-settings by default. + 7. Disable tap highlights on iOS. +*/ + +html, +:host { + line-height: 1.5; /* 1 */ + -webkit-text-size-adjust: 100%; /* 2 */ + tab-size: 4; /* 3 */ + font-family: var( + --default-font-family, + ui-sans-serif, + system-ui, + sans-serif, + 'Apple Color Emoji', + 'Segoe UI Emoji', + 'Segoe UI Symbol', + 'Noto Color Emoji' + ); /* 4 */ + font-feature-settings: var(--default-font-feature-settings, normal); /* 5 */ + font-variation-settings: var(--default-font-variation-settings, normal); /* 6 */ + -webkit-tap-highlight-color: transparent; /* 7 */ +} + +/* + Inherit line-height from `html` so users can set them as a class directly on the `html` element. +*/ + +body { + line-height: inherit; +} + +/* + 1. Add the correct height in Firefox. + 2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) + 3. Reset the default border style to a 1px solid border. +*/ + +hr { + height: 0; /* 1 */ + color: inherit; /* 2 */ + border-top-width: 1px; /* 3 */ +} + +/* + Add the correct text decoration in Chrome, Edge, and Safari. +*/ + +abbr:where([title]) { + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; +} + +/* + Remove the default font size and weight for headings. +*/ + +h1, +h2, +h3, +h4, +h5, +h6 { + font-size: inherit; + font-weight: inherit; +} + +/* + Reset links to optimize for opt-in styling instead of opt-out. +*/ + +a { + color: inherit; + -webkit-text-decoration: inherit; + text-decoration: inherit; +} + +/* + Add the correct font weight in Edge and Safari. +*/ + +b, +strong { + font-weight: bolder; +} + +/* + 1. Use the user's configured `mono` font-family by default. + 2. Use the user's configured `mono` font-feature-settings by default. + 3. Use the user's configured `mono` font-variation-settings by default. + 4. Correct the odd `em` font sizing in all browsers. +*/ + +code, +kbd, +samp, +pre { + font-family: var( + --default-mono-font-family, + ui-monospace, + SFMono-Regular, + Menlo, + Monaco, + Consolas, + 'Liberation Mono', + 'Courier New', + monospace + ); /* 4 */ + font-feature-settings: var(--default-mono-font-feature-settings, normal); /* 5 */ + font-variation-settings: var(--default-mono-font-variation-settings, normal); /* 6 */ + font-size: 1em; /* 4 */ +} + +/* + Add the correct font size in all browsers. +*/ + +small { + font-size: 80%; +} + +/* + Prevent `sub` and `sup` elements from affecting the line height in all browsers. +*/ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* + 1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) + 2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) + 3. Remove gaps between table borders by default. +*/ + +table { + text-indent: 0; /* 1 */ + border-color: inherit; /* 2 */ + border-collapse: collapse; /* 3 */ +} + +/* + 1. Inherit the font styles in all browsers. + 2. Remove the default background color. +*/ + +button, +input, +optgroup, +select, +textarea, +::file-selector-button { + font: inherit; /* 1 */ + font-feature-settings: inherit; /* 1 */ + font-variation-settings: inherit; /* 1 */ + letter-spacing: inherit; /* 1 */ + color: inherit; /* 1 */ + background: transparent; /* 2 */ +} + +/* + Reset the default inset border style for form controls to solid. +*/ + +input:where(:not([type='button'], [type='reset'], [type='submit'])), +select, +textarea { + border: 1px solid; +} + +/* + Correct the inability to style the border radius in iOS Safari. +*/ +button, +input:where([type='button'], [type='reset'], [type='submit']), +::file-selector-button { + appearance: button; +} + +/* + Use the modern Firefox focus style for all focusable elements. +*/ + +:-moz-focusring { + outline: auto; +} + +/* + Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) +*/ + +:-moz-ui-invalid { + box-shadow: none; +} + +/* + Add the correct vertical alignment in Chrome and Firefox. +*/ + +progress { + vertical-align: baseline; +} + +/* + Correct the cursor style of increment and decrement buttons in Safari. +*/ + +::-webkit-inner-spin-button, +::-webkit-outer-spin-button { + height: auto; +} + +/* + Remove the inner padding in Chrome and Safari on macOS. +*/ + +::-webkit-search-decoration { + -webkit-appearance: none; +} + +/* + Add the correct display in Chrome and Safari. +*/ + +summary { + display: list-item; +} + +/* + Make lists unstyled by default. +*/ + +ol, +ul, +menu { + list-style: none; +} + +/* + Prevent resizing textareas horizontally by default. +*/ + +textarea { + resize: vertical; +} + +/* + 1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) + 2. Set the default placeholder color to a semi-transparent version of the current text color. +*/ + +::placeholder { + opacity: 1; /* 1 */ + color: color-mix(in srgb, currentColor 50%, transparent); /* 2 */ +} + +/* + 1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14) + 2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) + This can trigger a poorly considered lint error in some tools but is included by design. +*/ + +img, +svg, +video, +canvas, +audio, +iframe, +embed, +object { + display: block; /* 1 */ + vertical-align: middle; /* 2 */ +} + +/* + Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) +*/ + +img, +video { + max-width: 100%; + height: auto; +} + +/* + Make elements with the HTML hidden attribute stay hidden by default. +*/ + +[hidden] { + display: none !important; +} +"#; + +mod css; +mod util; + +pub fn main() { + let throughput = util::Throughput::compute(100_000, PREFLIGHT.len(), || { + _ = black_box(css::parse(PREFLIGHT.as_bytes())); + }); + + eprintln!("css::parse: {:}", throughput); + + let input = &b"var(--a, 0 0 1px rgb(0, 0, 0)), 0 0 1px rgb(0, 0, 0), var(--a, 0 0 1px rgb(0, 0, 0)), 0 0 1px rgb(0, 0, 0), ".repeat(500)[..]; + + let throughput = util::Throughput::compute(100_000, input.len(), || { + _ = black_box(util::segment(input, b',')); + }); + + eprintln!("util::segment: {:}", throughput); + + let input = &b"s\\o\\m\\e\\_\\identifier_token ".repeat(500)[..]; + + let throughput = util::Throughput::compute(100_000_000, input.len(), || { + _ = black_box(css::syntax::read_ident_token(input)); + }); + + eprintln!("css::syntax::read_ident_token: {:}", throughput); + + let input = &b"@media (min-width: 1280px) ".repeat(500)[..]; + + let throughput = util::Throughput::compute(2_000_000, input.len(), || { + _ = black_box(css::parser::parse_rule_header(input)); + }); + + eprintln!("css::parser::parse_rule_header (at rule): {:}", throughput); + + let input = &b".foo.bar:is(.baz:has(.qux:where(.foo + .bar))) + .thing::before".repeat(500)[..]; + + let throughput = util::Throughput::compute(2_000_000, input.len(), || { + _ = black_box(css::parser::parse_rule_header(input)); + }); + + eprintln!("css::parser::parse_rule_header (style rule): {:}", throughput); + + let input = &b"[content-start]_calc(100%-1px)_[content-end]_minmax(1rem,1fr)".repeat(500)[..]; + + let throughput = util::Throughput::compute(100_000, input.len(), || { + _ = black_box(util::convert_underscores_to_whitespace(input)); + }); + + eprintln!("util::convert_underscores_to_whitespace: {:}", throughput); +}