From 72a9497e5b6a39d28f9a84308bf3be560168a6aa Mon Sep 17 00:00:00 2001 From: Devon Govett Date: Wed, 11 May 2022 01:03:35 -0400 Subject: [PATCH 1/2] Serde support --- Cargo.lock | 4 +++ Cargo.toml | 2 ++ src/declaration.rs | 2 ++ src/dependencies.rs | 24 ++++++++++---- src/error.rs | 2 ++ src/macros.rs | 5 +++ src/media_query.rs | 33 +++++++++++++++++++ src/printer.rs | 4 +-- src/properties/align.rs | 45 ++++++++++++++++++++++++++ src/properties/animation.rs | 12 +++++++ src/properties/background.rs | 8 +++++ src/properties/border.rs | 6 ++++ src/properties/border_image.rs | 8 +++++ src/properties/box_shadow.rs | 1 + src/properties/css_modules.rs | 17 ++++++++-- src/properties/custom.rs | 20 ++++++++++-- src/properties/display.rs | 11 +++++++ src/properties/effects.rs | 13 ++++++++ src/properties/font.rs | 42 ++++++++++++++++++++++++ src/properties/grid.rs | 55 +++++++++++++++++++++++++++++++- src/properties/list.rs | 23 ++++++++++++- src/properties/masking.rs | 13 ++++++++ src/properties/mod.rs | 7 ++++ src/properties/outline.rs | 5 +++ src/properties/position.rs | 10 ++++++ src/properties/size.rs | 10 ++++++ src/properties/svg.rs | 26 ++++++++++++++- src/properties/text.rs | 23 +++++++++++++ src/properties/transform.rs | 16 ++++++++++ src/properties/transition.rs | 1 + src/properties/ui.rs | 12 ++++++- src/rules/counter_style.rs | 2 ++ src/rules/custom_media.rs | 2 ++ src/rules/document.rs | 2 ++ src/rules/font_face.rs | 53 ++++++++++++++++++++++++++++-- src/rules/font_palette_values.rs | 14 ++++++++ src/rules/import.rs | 2 ++ src/rules/keyframes.rs | 9 ++++++ src/rules/layer.rs | 7 +++- src/rules/media.rs | 2 ++ src/rules/mod.rs | 10 +++++- src/rules/namespace.rs | 3 ++ src/rules/nesting.rs | 2 ++ src/rules/page.rs | 4 +++ src/rules/property.rs | 2 ++ src/rules/style.rs | 13 ++++++++ src/rules/supports.rs | 8 +++++ src/rules/viewport.rs | 2 ++ src/selector.rs | 44 +++++++++++++++++++++++++ src/stylesheet.rs | 3 ++ src/values/alpha.rs | 1 + src/values/angle.rs | 5 +++ src/values/calc.rs | 10 ++++++ src/values/color.rs | 21 ++++++++++++ src/values/easing.rs | 10 ++++++ src/values/gradient.rs | 46 ++++++++++++++++++++++++++ src/values/ident.rs | 6 ++-- src/values/image.rs | 15 ++++++++- src/values/length.rs | 16 ++++++++++ src/values/percentage.rs | 11 +++++++ src/values/position.rs | 6 ++++ src/values/ratio.rs | 1 + src/values/rect.rs | 1 + src/values/resolution.rs | 5 +++ src/values/shape.rs | 15 +++++++++ src/values/size.rs | 1 + src/values/string.rs | 46 +++++++++++++++++++++++++- src/values/syntax.rs | 22 +++++++++++++ src/values/time.rs | 5 +++ src/values/url.rs | 8 +++-- src/vendor_prefix.rs | 1 + 71 files changed, 867 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c11f2012..c6bc5771 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -273,6 +273,7 @@ dependencies = [ "phf", "proc-macro2", "quote", + "serde", "smallvec", "syn", ] @@ -1290,6 +1291,9 @@ name = "smallvec" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" +dependencies = [ + "serde", +] [[package]] name = "string_cache" diff --git a/Cargo.toml b/Cargo.toml index 09c63aef..54c62f56 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,11 +52,13 @@ indoc = "1.0.3" assert_cmd = "2.0" assert_fs = "1.0" predicates = "2.1" +serde_json = "1.0.78" [features] default = ["grid"] cli = ["clap", "serde_json", "pathdiff", "browserslist-rs", "jemallocator"] grid = [] +serde = ["smallvec/serde", "cssparser/serde"] [[test]] name = "cli_integration_tests" diff --git a/src/declaration.rs b/src/declaration.rs index b8e62efc..6948233b 100644 --- a/src/declaration.rs +++ b/src/declaration.rs @@ -41,8 +41,10 @@ use cssparser::*; /// and a list of normal declarations. This reduces memory usage compared /// with storing a boolean along with each property. #[derive(Debug, PartialEq, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct DeclarationBlock<'i> { /// A list of `!important` declarations in the block. + #[cfg_attr(feature = "serde", serde(borrow))] pub important_declarations: Vec>, /// A list of normal declarations in the block. pub declarations: Vec>, diff --git a/src/dependencies.rs b/src/dependencies.rs index 1f31af92..69c6684e 100644 --- a/src/dependencies.rs +++ b/src/dependencies.rs @@ -62,8 +62,8 @@ impl ImportDependency { media, loc: SourceRange::new( filename, - SourceLocation { - line: rule.loc.line, + Location { + line: rule.loc.line + 1, column: rule.loc.column, }, 8, @@ -109,24 +109,34 @@ pub struct SourceRange { } /// A line and column position within a source file. -#[derive(Serialize)] +#[derive(Serialize, Debug, Clone, Copy, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize))] pub struct Location { - /// The line number, starting from 0. + /// The line number, starting from 1. pub line: u32, /// The column number, starting from 1. pub column: u32, } +impl From for Location { + fn from(loc: SourceLocation) -> Location { + Location { + line: loc.line + 1, + column: loc.column, + } + } +} + impl SourceRange { - fn new(filename: &str, loc: SourceLocation, offset: u32, len: usize) -> SourceRange { + fn new(filename: &str, loc: Location, offset: u32, len: usize) -> SourceRange { SourceRange { file_path: filename.into(), start: Location { - line: loc.line + 1, + line: loc.line, column: loc.column + offset, }, end: Location { - line: loc.line + 1, + line: loc.line, column: loc.column + offset + (len as u32) - 1, }, } diff --git a/src/error.rs b/src/error.rs index d1945c98..c4186871 100644 --- a/src/error.rs +++ b/src/error.rs @@ -10,6 +10,7 @@ use std::fmt; /// An error with a source location. #[derive(Debug, PartialEq, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Error { /// The type of error that occurred. pub kind: T, @@ -31,6 +32,7 @@ impl std::error::Error for Error {} /// A line and column location within a source file. #[derive(Debug, PartialEq, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct ErrorLocation { /// The filename in which the error occurred. pub filename: String, diff --git a/src/macros.rs b/src/macros.rs index e93b023a..c8374184 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -10,6 +10,7 @@ macro_rules! enum_property { ) => { $(#[$outer])* #[derive(Debug, Clone, Copy, PartialEq)] + #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(rename_all = "lowercase"))] $vis enum $name { $( $(#[$meta])* @@ -66,9 +67,11 @@ macro_rules! enum_property { ) => { $(#[$outer])* #[derive(Debug, Clone, Copy, PartialEq)] + #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] $vis enum $name { $( $(#[$meta])* + #[cfg_attr(feature = "serde", serde(rename = $str))] $id, )+ } @@ -319,6 +322,7 @@ macro_rules! define_shorthand { ) => { $(#[$outer])* #[derive(Debug, Clone, PartialEq)] + #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct $name$(<$l>)? { $( $(#[$meta])* @@ -532,6 +536,7 @@ macro_rules! define_list_shorthand { ) => { $(#[$outer])* #[derive(Debug, Clone, PartialEq)] + #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct $name$(<$l>)? { $( $(#[$meta])* diff --git a/src/media_query.rs b/src/media_query.rs index 3610b004..650e1c53 100644 --- a/src/media_query.rs +++ b/src/media_query.rs @@ -16,8 +16,10 @@ use std::collections::{HashMap, HashSet}; /// A [media query list](https://drafts.csswg.org/mediaqueries/#mq-list). #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct MediaList<'i> { /// The list of media queries. + #[cfg_attr(feature = "serde", serde(borrow))] pub media_queries: Vec>, } @@ -141,6 +143,11 @@ enum_property! { /// A [media type](https://drafts.csswg.org/mediaqueries/#media-types) within a media query. #[derive(Clone, Debug, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum MediaType<'i> { /// Matches all devices. All, @@ -150,6 +157,7 @@ pub enum MediaType<'i> { /// Matches all devices that aren’t matched by print. Screen, /// An unknown media type. + #[cfg_attr(feature = "serde", serde(borrow))] Custom(CowArcStr<'i>), } @@ -167,10 +175,12 @@ impl<'i> Parse<'i> for MediaType<'i> { /// A [media query](https://drafts.csswg.org/mediaqueries/#media). #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct MediaQuery<'i> { /// The qualifier for this query. pub qualifier: Option, /// The media type for this query, that can be known, unknown, or "all". + #[cfg_attr(feature = "serde", serde(borrow))] pub media_type: MediaType<'i>, /// The condition that this media query contains. This cannot have `or` /// in the first level. @@ -354,8 +364,14 @@ enum_property! { /// Represents a media condition. #[derive(Clone, Debug, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum MediaCondition<'i> { /// A media feature, implicitly parenthesized. + #[cfg_attr(feature = "serde", serde(borrow))] Feature(MediaFeature<'i>), /// A negation of a condition. Not(Box>), @@ -460,6 +476,11 @@ impl<'i> ToCss for MediaCondition<'i> { /// A [comparator](https://drafts.csswg.org/mediaqueries/#typedef-mf-comparison) within a media query. #[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum MediaFeatureComparison { /// `=` Equal, @@ -511,10 +532,16 @@ impl MediaFeatureComparison { /// A [media feature](https://drafts.csswg.org/mediaqueries/#typedef-media-feature) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum MediaFeature<'i> { /// A plain media feature, e.g. `(min-width: 240px)`. Plain { /// The name of the feature. + #[cfg_attr(feature = "serde", serde(borrow))] name: CowArcStr<'i>, /// The feature value. value: MediaFeatureValue<'i>, @@ -707,6 +734,11 @@ where /// /// See [MediaFeature](MediaFeature). #[derive(Clone, Debug, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum MediaFeatureValue<'i> { /// A length value. Length(Length), @@ -717,6 +749,7 @@ pub enum MediaFeatureValue<'i> { /// A ratio. Ratio(Ratio), /// An indentifier. + #[cfg_attr(feature = "serde", serde(borrow))] Ident(CowArcStr<'i>), } diff --git a/src/printer.rs b/src/printer.rs index ed195294..ffcfe0a8 100644 --- a/src/printer.rs +++ b/src/printer.rs @@ -240,12 +240,12 @@ impl<'a, W: std::fmt::Write + Sized> Printer<'a, W> { } /// Returns an error of the given kind at the provided location in the current source file. - pub fn error(&self, kind: PrinterErrorKind, loc: SourceLocation) -> Error { + pub fn error(&self, kind: PrinterErrorKind, loc: crate::dependencies::Location) -> Error { Error { kind, loc: Some(ErrorLocation { filename: self.filename().into(), - line: loc.line, + line: loc.line - 1, column: loc.column, }), } diff --git a/src/properties/align.rs b/src/properties/align.rs index 0ae6145a..a319939e 100644 --- a/src/properties/align.rs +++ b/src/properties/align.rs @@ -18,6 +18,11 @@ use cssparser::*; /// A [``](https://www.w3.org/TR/css-align-3/#typedef-baseline-position) value, /// as used in the alignment properties. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum BaselinePosition { /// The first baseline. First, @@ -102,6 +107,11 @@ enum_property! { /// A value for the [align-content](https://www.w3.org/TR/css-align-3/#propdef-align-content) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum AlignContent { /// Default alignment. Normal, @@ -156,6 +166,11 @@ impl ToCss for AlignContent { /// A value for the [justify-content](https://www.w3.org/TR/css-align-3/#propdef-justify-content) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum JustifyContent { /// Default justification. Normal, @@ -312,6 +327,11 @@ enum_property! { /// A value for the [align-self](https://www.w3.org/TR/css-align-3/#align-self-property) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum AlignSelf { /// Automatic alignment. Auto, @@ -373,6 +393,11 @@ impl ToCss for AlignSelf { /// A value for the [justify-self](https://www.w3.org/TR/css-align-3/#justify-self-property) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum JustifySelf { /// Automatic justification. Auto, @@ -524,6 +549,11 @@ impl ToCss for PlaceSelf { /// A value for the [align-items](https://www.w3.org/TR/css-align-3/#align-items-property) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum AlignItems { /// Default alignment. Normal, @@ -578,6 +608,11 @@ impl ToCss for AlignItems { /// A legacy justification keyword, as used in the `justify-items` property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum LegacyJustify { /// Left justify. Left, @@ -639,6 +674,11 @@ impl ToCss for LegacyJustify { /// A value for the [justify-items](https://www.w3.org/TR/css-align-3/#justify-items-property) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum JustifyItems { /// Default justification. Normal, @@ -789,6 +829,11 @@ impl ToCss for PlaceItems { /// A [gap](https://www.w3.org/TR/css-align-3/#column-row-gap) value, as used in the /// `column-gap` and `row-gap` properties. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum GapValue { /// Equal to `1em` for multi-column containers, and zero otherwise. Normal, diff --git a/src/properties/animation.rs b/src/properties/animation.rs index 8adcbb67..5b9afb32 100644 --- a/src/properties/animation.rs +++ b/src/properties/animation.rs @@ -17,10 +17,16 @@ use smallvec::SmallVec; /// A value for the [animation-name](https://drafts.csswg.org/css-animations/#animation-name) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum AnimationName<'i> { /// The `none` keyword. None, /// An identifier of a `@keyframes` rule. + #[cfg_attr(feature = "serde", serde(borrow))] Ident(CustomIdent<'i>), } @@ -62,6 +68,11 @@ pub type AnimationNameList<'i> = SmallVec<[AnimationName<'i>; 1]>; /// A value for the [animation-iteration-count](https://drafts.csswg.org/css-animations/#animation-iteration-count) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum AnimationIterationCount { /// The animation will repeat the specified number of times. Number(CSSNumber), @@ -134,6 +145,7 @@ define_list_shorthand! { /// A value for the [animation](https://drafts.csswg.org/css-animations/#animation) shorthand property. pub struct Animation<'i>(VendorPrefix) { /// The animation name. + #[cfg_attr(feature = "serde", serde(borrow))] name: AnimationName(AnimationName<'i>, VendorPrefix), /// The animation duration. duration: AnimationDuration(Time, VendorPrefix), diff --git a/src/properties/background.rs b/src/properties/background.rs index 8655ef78..96e08b16 100644 --- a/src/properties/background.rs +++ b/src/properties/background.rs @@ -18,6 +18,11 @@ use smallvec::SmallVec; /// A value for the [background-size](https://www.w3.org/TR/css-backgrounds-3/#background-size) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum BackgroundSize { /// An explicit background size. Explicit { @@ -104,6 +109,7 @@ enum_property! { /// A value for the [background-repeat](https://www.w3.org/TR/css-backgrounds-3/#background-repeat) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct BackgroundRepeat { /// A repeat style for the x direction. pub x: BackgroundRepeatKeyword, @@ -293,8 +299,10 @@ impl ToCss for BackgroundPosition { /// A value for the [background](https://www.w3.org/TR/css-backgrounds-3/#background) shorthand property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Background<'i> { /// The background image. + #[cfg_attr(feature = "serde", serde(borrow))] pub image: Image<'i>, /// The background color. pub color: CssColor, diff --git a/src/properties/border.rs b/src/properties/border.rs index 2971a598..c8e30878 100644 --- a/src/properties/border.rs +++ b/src/properties/border.rs @@ -21,6 +21,11 @@ use cssparser::*; /// A value for the [border-width](https://www.w3.org/TR/css-backgrounds-3/#border-width) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum BorderSideWidth { /// A UA defined `thin` value. Thin, @@ -103,6 +108,7 @@ impl Default for LineStyle { /// A generic type that represents the `border` and `outline` shorthand properties. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct GenericBorder { /// The width of the border. pub width: BorderSideWidth, diff --git a/src/properties/border_image.rs b/src/properties/border_image.rs index 200714f3..982f847d 100644 --- a/src/properties/border_image.rs +++ b/src/properties/border_image.rs @@ -37,6 +37,7 @@ enum_property! { /// A value for the [border-image-repeat](https://www.w3.org/TR/css-backgrounds-3/#border-image-repeat) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct BorderImageRepeat { /// The horizontal repeat value. pub horizontal: BorderImageRepeatKeyword, @@ -80,6 +81,11 @@ impl ToCss for BorderImageRepeat { /// A value for the [border-image-width](https://www.w3.org/TR/css-backgrounds-3/#border-image-width) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum BorderImageSideWidth { /// A number representing a multiple of the border width. Number(CSSNumber), @@ -129,6 +135,7 @@ impl ToCss for BorderImageSideWidth { /// A value for the [border-image-slice](https://www.w3.org/TR/css-backgrounds-3/#border-image-slice) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct BorderImageSlice { /// The offsets from the edges of the image. pub offsets: Rect, @@ -174,6 +181,7 @@ define_shorthand! { #[derive(Default)] pub struct BorderImage<'i>(VendorPrefix) { /// The border image. + #[cfg_attr(feature = "serde", serde(borrow))] source: BorderImageSource(Image<'i>), /// The offsets that define where the image is sliced. slice: BorderImageSlice(BorderImageSlice), diff --git a/src/properties/box_shadow.rs b/src/properties/box_shadow.rs index d66430fa..24fc3392 100644 --- a/src/properties/box_shadow.rs +++ b/src/properties/box_shadow.rs @@ -17,6 +17,7 @@ use smallvec::SmallVec; /// A value for the [box-shadow](https://drafts.csswg.org/css-backgrounds/#box-shadow) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct BoxShadow { /// The color of the box shadow. pub color: CssColor, diff --git a/src/properties/css_modules.rs b/src/properties/css_modules.rs index d78cc3f7..cb5094f1 100644 --- a/src/properties/css_modules.rs +++ b/src/properties/css_modules.rs @@ -1,5 +1,6 @@ //! Properties related to CSS modules. +use crate::dependencies::Location; use crate::error::{ParserError, PrinterError}; use crate::printer::Printer; use crate::traits::{Parse, ToCss}; @@ -10,23 +11,31 @@ use smallvec::SmallVec; /// A value for the [composes](https://github.com/css-modules/css-modules/#dependencies) property from CSS modules. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Composes<'i> { /// A list of class names to compose. + #[cfg_attr(feature = "serde", serde(borrow))] pub names: CustomIdentList<'i>, /// Where the class names are composed from. pub from: Option>, /// The source location of the `composes` property. - pub loc: SourceLocation, + pub loc: Location, } /// Defines where the class names referenced in the `composes` property are located. /// /// See [Composes](Composes). #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum ComposesFrom<'i> { /// The class name is global. Global, /// The class name comes from the specified file. + #[cfg_attr(feature = "serde", serde(borrow))] File(CowArcStr<'i>), } @@ -53,7 +62,11 @@ impl<'i> Parse<'i> for Composes<'i> { None }; - Ok(Composes { names, from, loc }) + Ok(Composes { + names, + from, + loc: loc.into(), + }) } } diff --git a/src/properties/custom.rs b/src/properties/custom.rs index 031035c0..e8b0f068 100644 --- a/src/properties/custom.rs +++ b/src/properties/custom.rs @@ -16,8 +16,10 @@ use cssparser::*; /// A CSS custom property, representing any unknown property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct CustomProperty<'i> { /// The name of the property. + #[cfg_attr(feature = "serde", serde(borrow))] pub name: CowArcStr<'i>, /// The property value, stored as a raw token list. pub value: TokenList<'i>, @@ -40,10 +42,12 @@ impl<'i> CustomProperty<'i> { /// be parsed, e.g. in the case css `var()` references are encountered. /// In this case, the raw tokens are stored instead. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct UnparsedProperty<'i> { /// The id of the property. pub property_id: PropertyId<'i>, /// The property value, stored as a raw token list. + #[cfg_attr(feature = "serde", serde(borrow))] pub value: TokenList<'i>, } @@ -78,12 +82,19 @@ impl<'i> UnparsedProperty<'i> { /// A raw list of CSS tokens, with embedded parsed values. #[derive(Debug, Clone, PartialEq)] -pub struct TokenList<'i>(pub Vec>); +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct TokenList<'i>(#[cfg_attr(feature = "serde", serde(borrow))] pub Vec>); /// A raw CSS token, or a parsed value. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum TokenOrValue<'i> { /// A token. + #[cfg_attr(feature = "serde", serde(borrow))] Token(Token<'i>), /// A parsed CSS color. Color(CssColor), @@ -321,9 +332,14 @@ impl<'i> TokenList<'i> { /// A raw CSS token. // Copied from cssparser to change CowRcStr to CowArcStr #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum Token<'a> { /// A [``](https://drafts.csswg.org/css-syntax/#ident-token-diagram) - Ident(CowArcStr<'a>), + Ident(#[cfg_attr(feature = "serde", serde(borrow))] CowArcStr<'a>), /// A [``](https://drafts.csswg.org/css-syntax/#at-keyword-token-diagram) /// diff --git a/src/properties/display.rs b/src/properties/display.rs index aae51761..c39d042d 100644 --- a/src/properties/display.rs +++ b/src/properties/display.rs @@ -25,6 +25,11 @@ enum_property! { /// A [``](https://drafts.csswg.org/css-display-3/#typedef-display-inside) value. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(rename_all = "kebab-case") +)] #[allow(missing_docs)] pub enum DisplayInside { Flow, @@ -101,6 +106,7 @@ impl DisplayInside { /// /// See [Display](Display). #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct DisplayPair { /// The outside display value. pub outside: DisplayOutside, @@ -313,6 +319,11 @@ enum_property! { /// A value for the [display](https://drafts.csswg.org/css-display-3/#the-display-properties) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum Display { /// A display keyword. Keyword(DisplayKeyword), diff --git a/src/properties/effects.rs b/src/properties/effects.rs index a2a725dc..e6ee4864 100644 --- a/src/properties/effects.rs +++ b/src/properties/effects.rs @@ -11,6 +11,11 @@ use smallvec::SmallVec; /// A [filter](https://drafts.fxtf.org/filter-effects-1/#filter-functions) function. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum Filter<'i> { /// A `blur()` filter. Blur(Length), @@ -33,6 +38,7 @@ pub enum Filter<'i> { /// A `drop-shadow()` filter. DropShadow(DropShadow), /// A `url()` reference to an SVG filter. + #[cfg_attr(feature = "serde", serde(borrow))] Url(Url<'i>), } @@ -192,6 +198,7 @@ impl<'i> Filter<'i> { /// A [`drop-shadow()`](https://drafts.fxtf.org/filter-effects-1/#funcdef-filter-drop-shadow) filter function. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct DropShadow { /// The color of the drop shadow. pub color: CssColor, @@ -278,10 +285,16 @@ impl DropShadow { /// A value for the [filter](https://drafts.fxtf.org/filter-effects-1/#FilterProperty) and /// [backdrop-filter](https://drafts.fxtf.org/filter-effects-2/#BackdropFilterProperty) properties. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum FilterList<'i> { /// The `none` keyword. None, /// A list of filter functions. + #[cfg_attr(feature = "serde", serde(borrow))] Filters(SmallVec<[Filter<'i>; 1]>), } diff --git a/src/properties/font.rs b/src/properties/font.rs index af858443..5d55c57a 100644 --- a/src/properties/font.rs +++ b/src/properties/font.rs @@ -14,6 +14,11 @@ use cssparser::*; /// A value for the [font-weight](https://www.w3.org/TR/css-fonts-4/#font-weight-prop) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum FontWeight { /// An absolute font weight. Absolute(AbsoluteFontWeight), @@ -66,6 +71,11 @@ impl ToCss for FontWeight { /// /// See [FontWeight](FontWeight). #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum AbsoluteFontWeight { /// An explicit weight. Weight(CSSNumber), @@ -144,6 +154,11 @@ enum_property! { /// A value for the [font-size](https://www.w3.org/TR/css-fonts-4/#font-size-prop) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum FontSize { /// An explicit size. Length(LengthPercentage), @@ -235,6 +250,11 @@ impl Into for &FontStretchKeyword { /// A value for the [font-stretch](https://www.w3.org/TR/css-fonts-4/#font-stretch-prop) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum FontStretch { /// A font stretch keyword. Keyword(FontStretchKeyword), @@ -325,8 +345,14 @@ enum_property! { /// A value for the [font-family](https://www.w3.org/TR/css-fonts-4/#font-family-prop) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum FontFamily<'i> { /// A custom family name. + #[cfg_attr(feature = "serde", serde(borrow))] FamilyName(CowArcStr<'i>), /// A generic family name. Generic(GenericFontFamily), @@ -400,6 +426,11 @@ impl<'i> ToCss for FontFamily<'i> { /// A value for the [font-style](https://www.w3.org/TR/css-fonts-4/#font-style-prop) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum FontStyle { /// Normal font style. Normal, @@ -495,6 +526,11 @@ impl FontVariantCaps { /// A value for the [line-height](https://www.w3.org/TR/2020/WD-css-inline-3-20200827/#propdef-line-height) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum LineHeight { /// The UA sets the line height based on the font. Normal, @@ -562,6 +598,11 @@ enum_property! { /// A value for the [vertical align](https://drafts.csswg.org/css2/#propdef-vertical-align) property. // TODO: there is a more extensive spec in CSS3 but it doesn't seem any browser implements it? https://www.w3.org/TR/css-inline-3/#transverse-alignment #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum VerticalAlign { /// A vertical align keyword. Keyword(VerticalAlignKeyword), @@ -596,6 +637,7 @@ define_shorthand! { /// A value for the [font](https://www.w3.org/TR/css-fonts-4/#font-prop) shorthand property. pub struct Font<'i> { /// The font family. + #[cfg_attr(feature = "serde", serde(borrow))] family: FontFamily(Vec>), /// The font size. size: FontSize(FontSize), diff --git a/src/properties/grid.rs b/src/properties/grid.rs index 668079ae..16ec5991 100644 --- a/src/properties/grid.rs +++ b/src/properties/grid.rs @@ -20,10 +20,16 @@ use smallvec::SmallVec; /// A [track sizing](https://drafts.csswg.org/css-grid-2/#track-sizing) value /// for the `grid-template-rows` and `grid-template-columns` properties. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum TrackSizing<'i> { /// No explicit grid tracks. None, /// A list of grid tracks. + #[cfg_attr(feature = "serde", serde(borrow))] TrackList(TrackList<'i>), } @@ -32,8 +38,10 @@ pub enum TrackSizing<'i> { /// /// See [TrackSizing](TrackSizing). #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct TrackList<'i> { /// A list of line names. + #[cfg_attr(feature = "serde", serde(borrow))] pub line_names: Vec>, /// A list of grid track items. pub items: Vec>, @@ -43,10 +51,16 @@ pub struct TrackList<'i> { /// /// See [TrackList](TrackList). #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum TrackListItem<'i> { /// A track size. TrackSize(TrackSize), /// A `repeat()` function. + #[cfg_attr(feature = "serde", serde(borrow))] TrackRepeat(TrackRepeat<'i>), } @@ -55,6 +69,11 @@ pub enum TrackListItem<'i> { /// /// See [TrackListItem](TrackListItem). #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum TrackSize { /// An explicit track breadth. TrackBreadth(TrackBreadth), @@ -73,12 +92,18 @@ impl Default for TrackSize { /// A [track size list](https://drafts.csswg.org/css-grid-2/#auto-tracks), as used /// in the `grid-auto-rows` and `grid-auto-columns` properties. #[derive(Debug, Clone, PartialEq, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct TrackSizeList(pub SmallVec<[TrackSize; 1]>); /// A [``](https://drafts.csswg.org/css-grid-2/#typedef-track-breadth) value. /// /// See [TrackSize](TrackSize). #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum TrackBreadth { /// An explicit length. Length(LengthPercentage), @@ -97,10 +122,12 @@ pub enum TrackBreadth { /// /// See [TrackListItem](TrackListItem). #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct TrackRepeat<'i> { /// The repeat count. count: RepeatCount, /// The line names to repeat. + #[cfg_attr(feature = "serde", serde(borrow))] line_names: Vec>, /// The track sizes to repeat. track_sizes: Vec, @@ -111,6 +138,11 @@ pub struct TrackRepeat<'i> { /// /// See [TrackRepeat](TrackRepeat). #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum RepeatCount { /// The number of times to repeat. Number(CSSInteger), @@ -484,6 +516,11 @@ impl ToCss for TrackSizeList { /// A value for the [grid-template-areas](https://drafts.csswg.org/css-grid-2/#grid-template-areas-property) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum GridTemplateAreas { /// No named grid areas. None, @@ -648,8 +685,10 @@ impl GridTemplateAreas { /// /// If `areas` is not `None`, then `rows` must also not be `None`. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct GridTemplate<'i> { /// The grid template rows. + #[cfg_attr(feature = "serde", serde(borrow))] pub rows: TrackSizing<'i>, /// The grid template columns. pub columns: TrackSizing<'i>, @@ -874,6 +913,7 @@ bitflags! { /// /// The `Row` or `Column` flags may be combined with the `Dense` flag, but the `Row` and `Column` flags may /// not be combined. + #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct GridAutoFlow: u8 { /// The auto-placement algorithm places items by filling each row, adding new rows as necessary. const Row = 0b00; @@ -973,8 +1013,10 @@ impl ToCss for GridAutoFlow { /// /// Explicit and implicit values may not be combined. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Grid<'i> { /// Explicit grid template rows. + #[cfg_attr(feature = "serde", serde(borrow))] pub rows: TrackSizing<'i>, /// Explicit grid template columns. pub columns: TrackSizing<'i>, @@ -1153,13 +1195,21 @@ impl_shorthand! { /// A [``](https://drafts.csswg.org/css-grid-2/#typedef-grid-row-start-grid-line) value, /// used in the `grid-row-start`, `grid-row-end`, `grid-column-start`, and `grid-column-end` properties. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum GridLine<'i> { /// Automatic placement. Auto, /// A named grid area name (automatically postfixed by `-start` or `-end`), or and explicit grid line name. Ident(CustomIdent<'i>), /// The Nth grid line, optionally filtered by line name. Negative numbers count backwards from the end. - Line(CSSInteger, Option>), + Line( + CSSInteger, + #[cfg_attr(feature = "serde", serde(borrow))] Option>, + ), /// A grid span based on the Nth grid line from the opposite edge, optionally filtered by line name. Span(CSSInteger, Option>), } @@ -1299,6 +1349,7 @@ define_shorthand! { /// A value for the [grid-row](https://drafts.csswg.org/css-grid-2/#propdef-grid-row) shorthand property. pub struct GridRow<'i> { /// The starting line. + #[cfg_attr(feature = "serde", serde(borrow))] start: GridRowStart(GridLine<'i>), /// The ending line. end: GridRowEnd(GridLine<'i>), @@ -1309,6 +1360,7 @@ define_shorthand! { /// A value for the [grid-row](https://drafts.csswg.org/css-grid-2/#propdef-grid-column) shorthand property. pub struct GridColumn<'i> { /// The starting line. + #[cfg_attr(feature = "serde", serde(borrow))] start: GridColumnStart(GridLine<'i>), /// The ending line. end: GridColumnEnd(GridLine<'i>), @@ -1322,6 +1374,7 @@ define_shorthand! { /// A value for the [grid-area](https://drafts.csswg.org/css-grid-2/#propdef-grid-area) shorthand property. pub struct GridArea<'i> { /// The grid row start placement. + #[cfg_attr(feature = "serde", serde(borrow))] row_start: GridRowStart(GridLine<'i>), /// The grid column start placement. column_start: GridColumnStart(GridLine<'i>), diff --git a/src/properties/list.rs b/src/properties/list.rs index 9150bfb8..5e361d9c 100644 --- a/src/properties/list.rs +++ b/src/properties/list.rs @@ -14,10 +14,16 @@ use cssparser::*; /// A value for the [list-style-type](https://www.w3.org/TR/2020/WD-css-lists-3-20201117/#text-markers) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum ListStyleType<'i> { /// No marker. None, /// An explicit marker string. + #[cfg_attr(feature = "serde", serde(borrow))] String(CowArcStr<'i>), /// A named counter style. CounterStyle(CounterStyle<'i>), @@ -62,13 +68,21 @@ impl ToCss for ListStyleType<'_> { /// A [counter-style](https://www.w3.org/TR/css-counter-styles-3/#typedef-counter-style) name. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum CounterStyle<'i> { /// A predefined counter style name. Predefined(PredefinedCounterStyle), /// A custom counter style name. Name(CustomIdent<'i>), /// An inline [`symbols()`](https://www.w3.org/TR/css-counter-styles-3/#symbols-function) definition. - Symbols(SymbolsType, Vec>), + Symbols( + SymbolsType, + #[cfg_attr(feature = "serde", serde(borrow))] Vec>, + ), } enum_property! { @@ -219,8 +233,14 @@ enum_property! { /// /// See [CounterStyle](CounterStyle). #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum Symbol<'i> { /// A string. + #[cfg_attr(feature = "serde", serde(borrow))] String(CowArcStr<'i>), /// An image. Image(Image<'i>), @@ -281,6 +301,7 @@ shorthand_property! { /// A value for the [list-style](https://www.w3.org/TR/2020/WD-css-lists-3-20201117/#list-style-property) shorthand property. pub struct ListStyle<'i> { /// The list style type. + #[cfg_attr(feature = "serde", serde(borrow))] list_style_type: ListStyleType(ListStyleType<'i>), /// The list marker image. image: ListStyleImage(Image<'i>), diff --git a/src/properties/masking.rs b/src/properties/masking.rs index 92f099ab..8d9a4683 100644 --- a/src/properties/masking.rs +++ b/src/properties/masking.rs @@ -103,6 +103,11 @@ impl Default for GeometryBox { /// A value for the [mask-clip](https://www.w3.org/TR/css-masking-1/#the-mask-clip) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum MaskClip { /// A geometry box. GeometryBox(GeometryBox), @@ -199,6 +204,7 @@ define_list_shorthand! { /// A value for the [mask](https://www.w3.org/TR/css-masking-1/#the-mask) shorthand property. pub struct Mask<'i>(VendorPrefix) { /// The mask image. + #[cfg_attr(feature = "serde", serde(borrow))] image: MaskImage(Image<'i>, VendorPrefix), /// The position of the mask. position: MaskPosition(Position, VendorPrefix), @@ -367,10 +373,16 @@ impl<'i> ImageFallback<'i> for Mask<'i> { /// A value for the [clip-path](https://www.w3.org/TR/css-masking-1/#the-clip-path) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum ClipPath<'i> { /// No clip path. None, /// A url reference to an SVG path element. + #[cfg_attr(feature = "serde", serde(borrow))] Url(Url<'i>), /// A basic shape, positioned according to the reference box. Shape(Box, GeometryBox), @@ -443,6 +455,7 @@ define_shorthand! { #[derive(Default)] pub struct MaskBorder<'i> { /// The mask image. + #[cfg_attr(feature = "serde", serde(borrow))] source: MaskBorderSource(Image<'i>), /// The offsets that define where the image is sliced. slice: MaskBorderSlice(BorderImageSlice), diff --git a/src/properties/mod.rs b/src/properties/mod.rs index 1c4cd894..22f0e2bf 100644 --- a/src/properties/mod.rs +++ b/src/properties/mod.rs @@ -172,15 +172,18 @@ macro_rules! define_properties { ) => { /// A CSS property id. #[derive(Debug, Clone, PartialEq)] + #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum PropertyId<'i> { $( #[doc=concat!("The `", $name, "` property.")] $(#[$meta])* + #[cfg_attr(feature = "serde", serde(rename = $name))] $property$(($vp))?, )+ /// The `all` property. All, /// An unknown or custom property name. + #[cfg_attr(feature = "serde", serde(borrow))] Custom(CowArcStr<'i>) } @@ -517,13 +520,17 @@ macro_rules! define_properties { /// A CSS property. #[derive(Debug, Clone, PartialEq)] + #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] + #[cfg_attr(feature = "serde", serde(tag = "property", content = "value"))] pub enum Property<'i> { $( #[doc=concat!("The `", $name, "` property.")] $(#[$meta])* + #[cfg_attr(feature = "serde", serde(rename = $name))] $property($type, $($vp)?), )+ /// An unparsed property. + #[cfg_attr(feature = "serde", serde(borrow))] Unparsed(UnparsedProperty<'i>), /// A custom or unknown property. Custom(CustomProperty<'i>), diff --git a/src/properties/outline.rs b/src/properties/outline.rs index 95d5c82c..2bf4690c 100644 --- a/src/properties/outline.rs +++ b/src/properties/outline.rs @@ -14,6 +14,11 @@ use cssparser::*; /// A value for the [outline-style](https://drafts.csswg.org/css-ui/#outline-style) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum OutlineStyle { /// The `auto` keyword. Auto, diff --git a/src/properties/position.rs b/src/properties/position.rs index 136605e4..b9f8bcb8 100644 --- a/src/properties/position.rs +++ b/src/properties/position.rs @@ -14,6 +14,11 @@ use cssparser::*; /// A value for the [position](https://www.w3.org/TR/css-position-3/#position-property) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum Position { /// The box is laid in the document flow. Static, @@ -65,6 +70,11 @@ impl ToCss for Position { /// A value for the [z-index](https://drafts.csswg.org/css2/#z-index) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum ZIndex { /// The `auto` keyword. Auto, diff --git a/src/properties/size.rs b/src/properties/size.rs index 8c270478..f6d4d8ad 100644 --- a/src/properties/size.rs +++ b/src/properties/size.rs @@ -16,6 +16,11 @@ use cssparser::*; /// A value for the [preferred size properties](https://drafts.csswg.org/css-sizing-3/#preferred-size-properties), /// i.e. `width` and `height. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum Size { /// The `auto` keyword. Auto, @@ -79,6 +84,11 @@ impl ToCss for Size { /// and [maximum](https://drafts.csswg.org/css-sizing-3/#max-size-properties) size properties, /// e.g. `min-width` and `max-height`. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum MinMaxSize { /// The `none` keyword. None, diff --git a/src/properties/svg.rs b/src/properties/svg.rs index 38f402eb..d14b98a4 100644 --- a/src/properties/svg.rs +++ b/src/properties/svg.rs @@ -12,12 +12,20 @@ use cssparser::*; /// An SVG [``](https://www.w3.org/TR/SVG2/painting.html#SpecifyingPaint) value /// used in the `fill` and `stroke` properties. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum SVGPaint<'i> { /// No paint. None, /// A URL reference to a paint server element, e.g. `linearGradient`, `radialGradient`, and `pattern`. /// The fallback is used in case the paint server cannot be resolved. - Url(Url<'i>, Option), + Url( + #[cfg_attr(feature = "serde", serde(borrow))] Url<'i>, + Option, + ), /// A solid color paint. Color(CssColor), /// Use the paint value of fill from a context element. @@ -30,6 +38,11 @@ pub enum SVGPaint<'i> { /// /// See [SVGPaint](SVGPaint). #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum SVGPaintFallback { /// No fallback. None, @@ -153,6 +166,11 @@ enum_property! { /// A value for the [stroke-dasharray](https://www.w3.org/TR/SVG2/painting.html#StrokeDashing) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum StrokeDasharray { /// No dashing is used. None, @@ -210,10 +228,16 @@ impl ToCss for StrokeDasharray { /// A value for the [marker](https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties) properties. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum Marker<'i> { /// No marker. None, /// A url reference to a `` element. + #[cfg_attr(feature = "serde", serde(borrow))] Url(Url<'i>), } diff --git a/src/properties/text.rs b/src/properties/text.rs index 5ab53c77..bccbddb3 100644 --- a/src/properties/text.rs +++ b/src/properties/text.rs @@ -47,6 +47,7 @@ bitflags! { /// [text-transform](https://www.w3.org/TR/2021/CRD-css-text-3-20210422/#text-transform-property) property. /// /// All combinations of flags is supported. + #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct TextTransformOther: u8 { /// Puts all typographic character units in full-width form. const FullWidth = 0b00000001; @@ -93,6 +94,7 @@ impl ToCss for TextTransformOther { /// A value for the [text-transform](https://www.w3.org/TR/2021/CRD-css-text-3-20210422/#text-transform-property) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct TextTransform { /// How case should be transformed. pub case: TextTransformCase, @@ -286,6 +288,11 @@ enum_property! { /// A value for the [word-spacing](https://www.w3.org/TR/2021/CRD-css-text-3-20210422/#word-spacing-property) /// and [letter-spacing](https://www.w3.org/TR/2021/CRD-css-text-3-20210422/#letter-spacing-property) properties. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum Spacing { /// No additional spacing is applied. Normal, @@ -318,6 +325,7 @@ impl ToCss for Spacing { /// A value for the [text-indent](https://www.w3.org/TR/2021/CRD-css-text-3-20210422/#text-indent-property) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct TextIndent { /// The amount to indent. pub value: LengthPercentage, @@ -390,6 +398,7 @@ bitflags! { /// A value for the [text-decoration-line](https://www.w3.org/TR/2020/WD-css-text-decor-4-20200506/#text-decoration-line-property) property. /// /// Multiple lines may be specified by combining the flags. + #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct TextDecorationLine: u8 { /// Each line of text is underlined. const Underline = 0b00000001; @@ -514,6 +523,11 @@ impl Default for TextDecorationStyle { /// A value for the [text-decoration-thickness](https://www.w3.org/TR/2020/WD-css-text-decor-4-20200506/#text-decoration-width-property) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum TextDecorationThickness { /// The UA chooses an appropriate thickness for text decoration lines. Auto, @@ -697,6 +711,11 @@ enum_property! { /// A value for the [text-emphasis-style](https://www.w3.org/TR/2020/WD-css-text-decor-4-20200506/#text-emphasis-style-property) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum TextEmphasisStyle<'i> { /// No emphasis. None, @@ -708,6 +727,7 @@ pub enum TextEmphasisStyle<'i> { shape: Option, }, /// Display the given string as marks. + #[cfg_attr(feature = "serde", serde(borrow))] String(CowArcStr<'i>), } @@ -776,6 +796,7 @@ define_shorthand! { /// A value for the [text-emphasis](https://www.w3.org/TR/2020/WD-css-text-decor-4-20200506/#text-emphasis-property) shorthand property. pub struct TextEmphasis<'i>(VendorPrefix) { /// The text emphasis style. + #[cfg_attr(feature = "serde", serde(borrow))] style: TextEmphasisStyle(TextEmphasisStyle<'i>, VendorPrefix), /// The text emphasis color. color: TextEmphasisColor(CssColor, VendorPrefix), @@ -865,6 +886,7 @@ enum_property! { /// A value for the [text-emphasis-position](https://www.w3.org/TR/2020/WD-css-text-decor-4-20200506/#text-emphasis-position-property) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct TextEmphasisPosition { /// The vertical position. pub vertical: TextEmphasisPositionVertical, @@ -1197,6 +1219,7 @@ impl<'i> PropertyHandler<'i> for TextDecorationHandler<'i> { /// A value for the [text-shadow](https://www.w3.org/TR/2020/WD-css-text-decor-4-20200506/#text-shadow-property) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct TextShadow { /// The color of the text shadow. pub color: CssColor, diff --git a/src/properties/transform.rs b/src/properties/transform.rs index 9d1e5e58..914f2730 100644 --- a/src/properties/transform.rs +++ b/src/properties/transform.rs @@ -21,6 +21,7 @@ use std::f32::consts::PI; /// A value for the [transform](https://www.w3.org/TR/2019/CR-css-transforms-1-20190214/#propdef-transform) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct TransformList(pub Vec); impl<'i> Parse<'i> for TransformList { @@ -142,6 +143,11 @@ impl TransformList { /// An individual [transform function](https://www.w3.org/TR/2019/CR-css-transforms-1-20190214/#two-d-transform-functions). #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum Transform { /// A 2D translation. Translate(LengthPercentage, LengthPercentage), @@ -189,6 +195,7 @@ pub enum Transform { /// A 2D matrix. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[allow(missing_docs)] pub struct Matrix { pub a: T, @@ -225,6 +232,7 @@ impl Matrix { /// A 3D matrix. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[allow(missing_docs)] pub struct Matrix3d { pub m11: T, @@ -1373,6 +1381,11 @@ enum_property! { /// A value for the [perspective](https://drafts.csswg.org/css-transforms-2/#perspective-property) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum Perspective { /// No perspective transform is applied. None, @@ -1404,6 +1417,7 @@ impl ToCss for Perspective { /// A value for the [translate](https://drafts.csswg.org/css-transforms-2/#propdef-translate) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Translate { /// The x translation. pub x: LengthPercentage, @@ -1466,6 +1480,7 @@ impl Translate { /// A value for the [rotate](https://drafts.csswg.org/css-transforms-2/#propdef-rotate) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Rotate { /// Rotation around the x axis. pub x: f32, @@ -1549,6 +1564,7 @@ impl Rotate { /// A value for the [scale](https://drafts.csswg.org/css-transforms-2/#propdef-scale) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Scale { /// Scale on the x axis. pub x: NumberOrPercentage, diff --git a/src/properties/transition.rs b/src/properties/transition.rs index 252bb088..b07c9917 100644 --- a/src/properties/transition.rs +++ b/src/properties/transition.rs @@ -21,6 +21,7 @@ define_list_shorthand! { /// A value for the [transition](https://www.w3.org/TR/2018/WD-css-transitions-1-20181011/#transition-shorthand-property) property. pub struct Transition<'i>(VendorPrefix) { /// The property to transition. + #[cfg_attr(feature = "serde", serde(borrow))] property: TransitionProperty(PropertyId<'i>, VendorPrefix), /// The duration of the transition. duration: TransitionDuration(Time, VendorPrefix), diff --git a/src/properties/ui.rs b/src/properties/ui.rs index 36928b84..f124b128 100644 --- a/src/properties/ui.rs +++ b/src/properties/ui.rs @@ -36,8 +36,10 @@ enum_property! { /// /// See [Cursor](Cursor). #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct CursorImage<'i> { /// A url to the cursor image. + #[cfg_attr(feature = "serde", serde(borrow))] pub url: Url<'i>, /// The location in the image where the mouse pointer appears. pub hotspot: Option<(CSSNumber, CSSNumber)>, @@ -122,8 +124,10 @@ enum_property! { /// A value for the [cursor](https://www.w3.org/TR/2021/WD-css-ui-4-20210316/#cursor) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Cursor<'i> { /// A list of cursor images. + #[cfg_attr(feature = "serde", serde(borrow))] pub images: SmallVec<[CursorImage<'i>; 1]>, /// A pre-defined cursor. pub keyword: CursorKeyword, @@ -162,6 +166,11 @@ impl<'i> ToCss for Cursor<'i> { /// A value for the [caret-color](https://www.w3.org/TR/2021/WD-css-ui-4-20210316/#caret-color) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum ColorOrAuto { /// The `currentColor`, adjusted by the UA to ensure contrast against the background. Auto, @@ -273,6 +282,7 @@ enum_property! { /// A value for the [appearance](https://www.w3.org/TR/2021/WD-css-ui-4-20210316/#appearance-switching) property. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[allow(missing_docs)] pub enum Appearance<'i> { None, @@ -291,7 +301,7 @@ pub enum Appearance<'i> { SliderHorizontal, SquareButton, Textarea, - NonStandard(CowArcStr<'i>), + NonStandard(#[cfg_attr(feature = "serde", serde(borrow))] CowArcStr<'i>), } impl<'i> Parse<'i> for Appearance<'i> { diff --git a/src/rules/counter_style.rs b/src/rules/counter_style.rs index bc89455d..d5530d51 100644 --- a/src/rules/counter_style.rs +++ b/src/rules/counter_style.rs @@ -9,8 +9,10 @@ use crate::values::ident::CustomIdent; /// A [@counter-style](https://drafts.csswg.org/css-counter-styles/#the-counter-style-rule) rule. #[derive(Debug, PartialEq, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct CounterStyleRule<'i> { /// The name of the counter style to declare. + #[cfg_attr(feature = "serde", serde(borrow))] pub name: CustomIdent<'i>, // TODO: eventually parse these properties /// Declarations in the `@counter-style` rule. diff --git a/src/rules/custom_media.rs b/src/rules/custom_media.rs index 98d2cdf9..78f56b51 100644 --- a/src/rules/custom_media.rs +++ b/src/rules/custom_media.rs @@ -9,8 +9,10 @@ use crate::values::ident::DashedIdent; /// A [@custom-media](https://drafts.csswg.org/mediaqueries-5/#custom-mq) rule. #[derive(Debug, PartialEq, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct CustomMediaRule<'i> { /// The name of the declared media query. + #[cfg_attr(feature = "serde", serde(borrow))] pub name: DashedIdent<'i>, /// The media query to declare. pub query: MediaList<'i>, diff --git a/src/rules/document.rs b/src/rules/document.rs index 7b5afaf7..5f64f71c 100644 --- a/src/rules/document.rs +++ b/src/rules/document.rs @@ -11,8 +11,10 @@ use crate::traits::ToCss; /// Note that only the `url-prefix()` function with no arguments is supported, and only the `-moz` prefix /// is allowed since Firefox was the only browser that ever implemented this rule. #[derive(Debug, PartialEq, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct MozDocumentRule<'i> { /// Nested rules within the `@-moz-document` rule. + #[cfg_attr(feature = "serde", serde(borrow))] pub rules: CssRuleList<'i>, /// The location of the rule in the source file. pub loc: Location, diff --git a/src/rules/font_face.rs b/src/rules/font_face.rs index ada6414c..6aa120b9 100644 --- a/src/rules/font_face.rs +++ b/src/rules/font_face.rs @@ -15,8 +15,10 @@ use std::fmt::Write; /// A [@font-face](https://drafts.csswg.org/css-fonts/#font-face-rule) rule. #[derive(Debug, PartialEq, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct FontFaceRule<'i> { /// Declarations in the `@font-face` rule. + #[cfg_attr(feature = "serde", serde(borrow))] pub properties: Vec>, /// The location of the rule in the source file. pub loc: Location, @@ -26,8 +28,14 @@ pub struct FontFaceRule<'i> { /// /// See [FontFaceRule](FontFaceRule). #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum FontFaceProperty<'i> { /// The `src` property. + #[cfg_attr(feature = "serde", serde(borrow))] Source(Vec>), /// The `font-family` property. FontFamily(FontFamily<'i>), @@ -46,10 +54,16 @@ pub enum FontFaceProperty<'i> { /// A value for the [src](https://drafts.csswg.org/css-fonts/#src-desc) /// property in an `@font-face` rule. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum Source<'i> { /// A `url()` with optional format metadata. Url(UrlSource<'i>), /// The `local()` function. + #[cfg_attr(feature = "serde", serde(borrow))] Local(FontFamily<'i>), } @@ -84,10 +98,12 @@ impl<'i> ToCss for Source<'i> { /// A `url()` value for the [src](https://drafts.csswg.org/css-fonts/#src-desc) /// property in an `@font-face` rule. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct UrlSource<'i> { /// The URL. pub url: Url<'i>, /// Optional `format()` function. + #[cfg_attr(feature = "serde", serde(borrow))] pub format: Option>, } @@ -124,8 +140,10 @@ impl<'i> ToCss for UrlSource<'i> { /// The `format()` function within the [src](https://drafts.csswg.org/css-fonts/#src-desc) /// property of an `@font-face` rule. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Format<'i> { /// A font format name. + #[cfg_attr(feature = "serde", serde(borrow))] pub format: FontFormat<'i>, /// The `supports()` function. // TODO: did this get renamed to `tech()`? @@ -175,6 +193,11 @@ impl<'i> ToCss for Format<'i> { /// [src](https://drafts.csswg.org/css-fonts/#src-desc) /// property of an `@font-face` rule. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum FontFormat<'i> { /// A WOFF font. WOFF, @@ -191,6 +214,7 @@ pub enum FontFormat<'i> { /// An SVG font. SVG, /// An unknown format. + #[cfg_attr(feature = "serde", serde(borrow))] String(CowArcStr<'i>), } @@ -269,6 +293,11 @@ enum_property! { /// [src](https://drafts.csswg.org/css-fonts/#src-desc) /// property of an `@font-face` rule. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum FontTechnology { /// Supports font features. Features(FontFeatureTechnology), @@ -329,10 +358,25 @@ impl ToCss for FontTechnology { } } +/// A contiguous range of Unicode code points. +/// +/// Cannot be empty. Can represent a single code point when start == end. +#[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct UnicodeRange { + /// Inclusive start of the range. In [0, end]. + pub start: u32, + /// Inclusive end of the range. In [0, 0x10FFFF]. + pub end: u32, +} + impl<'i> Parse<'i> for UnicodeRange { fn parse<'t>(input: &mut Parser<'i, 't>) -> Result>> { - let range = UnicodeRange::parse(input)?; - Ok(range) + let range = cssparser::UnicodeRange::parse(input)?; + Ok(UnicodeRange { + start: range.start, + end: range.end, + }) } } @@ -381,7 +425,10 @@ impl ToCss for UnicodeRange { } } - cssparser::ToCss::to_css(self, dest)?; + write!(dest, "U+{:X}", self.start)?; + if self.end != self.start { + write!(dest, "-{:X}", self.end)?; + } Ok(()) } } diff --git a/src/rules/font_palette_values.rs b/src/rules/font_palette_values.rs index 7894e0c7..bb05268f 100644 --- a/src/rules/font_palette_values.rs +++ b/src/rules/font_palette_values.rs @@ -15,10 +15,12 @@ use cssparser::*; /// A [@font-palette-values](https://drafts.csswg.org/css-fonts-4/#font-palette-values) rule. #[derive(Debug, PartialEq, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct FontPaletteValuesRule<'i> { /// The name of the font palette. pub name: DashedIdent<'i>, /// Declarations in the `@font-palette-values` rule. + #[cfg_attr(feature = "serde", serde(borrow))] pub properties: Vec>, /// The location of the rule in the source file. pub loc: Location, @@ -28,8 +30,14 @@ pub struct FontPaletteValuesRule<'i> { /// /// See [FontPaletteValuesRule](FontPaletteValuesRule). #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum FontPaletteValuesProperty<'i> { /// The `font-family` property. + #[cfg_attr(feature = "serde", serde(borrow))] FontFamily(FontFamily<'i>), /// The `base-palette` property. BasePalette(BasePalette), @@ -42,6 +50,11 @@ pub enum FontPaletteValuesProperty<'i> { /// A value for the [base-palette](https://drafts.csswg.org/css-fonts-4/#base-palette-desc) /// property in an `@font-palette-values` rule. #[derive(Debug, PartialEq, Clone)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum BasePalette { /// A light color palette as defined within the font. Light, @@ -54,6 +67,7 @@ pub enum BasePalette { /// A value for the [override-colors](https://drafts.csswg.org/css-fonts-4/#override-color) /// property in an `@font-palette-values` rule. #[derive(Debug, PartialEq, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct OverrideColors { /// The index of the color within the palette to override. index: u16, diff --git a/src/rules/import.rs b/src/rules/import.rs index 0483fe4d..6b603983 100644 --- a/src/rules/import.rs +++ b/src/rules/import.rs @@ -12,8 +12,10 @@ use cssparser::*; /// A [@import](https://drafts.csswg.org/css-cascade/#at-import) rule. #[derive(Debug, PartialEq, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct ImportRule<'i> { /// The url to import. + #[cfg_attr(feature = "serde", serde(borrow))] pub url: CowArcStr<'i>, /// An optional cascade layer name, or `None` for an anonymous layer. pub layer: Option>>, diff --git a/src/rules/keyframes.rs b/src/rules/keyframes.rs index 93d9043a..22a10561 100644 --- a/src/rules/keyframes.rs +++ b/src/rules/keyframes.rs @@ -20,8 +20,10 @@ use cssparser::*; /// A [@keyframes](https://drafts.csswg.org/css-animations/#keyframes) rule. #[derive(Debug, PartialEq, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct KeyframesRule<'i> { /// The animation name. + #[cfg_attr(feature = "serde", serde(borrow))] pub name: CustomIdent<'i>, /// A list of keyframes in the animation. pub keyframes: Vec>, @@ -183,6 +185,11 @@ impl<'i> ToCss for KeyframesRule<'i> { /// A [keyframe selector](https://drafts.csswg.org/css-animations/#typedef-keyframe-selector) /// within an `@keyframes` rule. #[derive(Debug, PartialEq, Clone)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum KeyframeSelector { /// An explicit percentage. Percentage(Percentage), @@ -239,10 +246,12 @@ impl ToCss for KeyframeSelector { /// /// See [KeyframesRule](KeyframesRule). #[derive(Debug, PartialEq, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Keyframe<'i> { /// A list of keyframe selectors to associate with the declarations in this keyframe. pub selectors: Vec, /// The declarations for this keyframe. + #[cfg_attr(feature = "serde", serde(borrow))] pub declarations: DeclarationBlock<'i>, } diff --git a/src/rules/layer.rs b/src/rules/layer.rs index 4b231798..e90ebce0 100644 --- a/src/rules/layer.rs +++ b/src/rules/layer.rs @@ -13,7 +13,8 @@ use smallvec::SmallVec; /// /// Nested layers are represented using a list of identifiers. In CSS syntax, these are dot-separated. #[derive(Debug, Clone, PartialEq)] -pub struct LayerName<'i>(pub SmallVec<[CowArcStr<'i>; 1]>); +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct LayerName<'i>(#[cfg_attr(feature = "serde", serde(borrow))] pub SmallVec<[CowArcStr<'i>; 1]>); macro_rules! expect_non_whitespace { ($parser: ident, $($branches: tt)+) => {{ @@ -78,8 +79,10 @@ impl<'i> ToCss for LayerName<'i> { /// /// See also [LayerBlockRule](LayerBlockRule). #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct LayerStatementRule<'i> { /// The layer names to declare. + #[cfg_attr(feature = "serde", serde(borrow))] pub names: Vec>, /// The location of the rule in the source file. pub loc: Location, @@ -99,8 +102,10 @@ impl<'i> ToCss for LayerStatementRule<'i> { /// A [@layer block](https://drafts.csswg.org/css-cascade-5/#layer-block) rule. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct LayerBlockRule<'i> { /// The name of the layer to declare, or `None` to declare an anonymous layer. + #[cfg_attr(feature = "serde", serde(borrow))] pub name: Option>, /// The rules within the `@layer` rule. pub rules: CssRuleList<'i>, diff --git a/src/rules/media.rs b/src/rules/media.rs index 998f2bda..308f2929 100644 --- a/src/rules/media.rs +++ b/src/rules/media.rs @@ -10,8 +10,10 @@ use crate::traits::ToCss; /// A [@media](https://drafts.csswg.org/css-conditional-3/#at-media) rule. #[derive(Debug, PartialEq, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct MediaRule<'i> { /// The media query list. + #[cfg_attr(feature = "serde", serde(borrow))] pub query: MediaList<'i>, /// The rules within the `@media` rule. pub rules: CssRuleList<'i>, diff --git a/src/rules/mod.rs b/src/rules/mod.rs index 74c087e1..18c8eb79 100644 --- a/src/rules/mod.rs +++ b/src/rules/mod.rs @@ -103,6 +103,7 @@ pub(crate) struct StyleContext<'a, 'i> { /// A source location. #[derive(PartialEq, Eq, Debug, Clone, Copy, Serialize)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize))] pub struct Location { /// The index of the source file within the source map. pub source_index: u32, @@ -115,8 +116,14 @@ pub struct Location { /// A CSS rule. #[derive(Debug, PartialEq, Clone)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum CssRule<'i> { /// A `@media` rule. + #[cfg_attr(feature = "serde", serde(borrow))] Media(MediaRule<'i>), /// An `@import` rule. Import(ImportRule<'i>), @@ -215,7 +222,8 @@ impl<'i> ToCss for CssRule<'i> { /// A list of CSS rules. #[derive(Debug, PartialEq, Clone)] -pub struct CssRuleList<'i>(pub Vec>); +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct CssRuleList<'i>(#[cfg_attr(feature = "serde", serde(borrow))] pub Vec>); pub(crate) struct MinifyContext<'a, 'i> { pub targets: &'a Option, diff --git a/src/rules/namespace.rs b/src/rules/namespace.rs index 458439cf..8ace837e 100644 --- a/src/rules/namespace.rs +++ b/src/rules/namespace.rs @@ -9,10 +9,13 @@ use cssparser::*; /// A [@namespace](https://drafts.csswg.org/css-namespaces/#declaration) rule. #[derive(Debug, PartialEq, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct NamespaceRule<'i> { /// An optional namespace prefix to declare, or `None` to declare the default namespace. + #[cfg_attr(feature = "serde", serde(borrow))] pub prefix: Option>, /// The url of the namespace. + #[cfg_attr(feature = "serde", serde(borrow))] pub url: CowArcStr<'i>, /// The location of the rule in the source file. pub loc: Location, diff --git a/src/rules/nesting.rs b/src/rules/nesting.rs index 3d57e0b9..a2ee264d 100644 --- a/src/rules/nesting.rs +++ b/src/rules/nesting.rs @@ -9,8 +9,10 @@ use crate::rules::{StyleContext, ToCssWithContext}; /// A [@nest](https://www.w3.org/TR/css-nesting-1/#at-nest) rule. #[derive(Debug, PartialEq, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct NestingRule<'i> { /// The style rule that defines the selector and declarations for the `@nest` rule. + #[cfg_attr(feature = "serde", serde(borrow))] pub style: StyleRule<'i>, /// The location of the rule in the source file. pub loc: Location, diff --git a/src/rules/page.rs b/src/rules/page.rs index e336acc6..e95400df 100644 --- a/src/rules/page.rs +++ b/src/rules/page.rs @@ -14,8 +14,10 @@ use cssparser::*; /// /// Either a name or at least one pseudo class is required. #[derive(Debug, PartialEq, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct PageSelector<'i> { /// An optional named page type. + #[cfg_attr(feature = "serde", serde(borrow))] pub name: Option>, /// A list of page pseudo classes. pub pseudo_classes: Vec, @@ -68,8 +70,10 @@ impl<'i> Parse<'i> for PageSelector<'i> { /// A [@page](https://www.w3.org/TR/css-page-3/#at-page-rule) rule. #[derive(Debug, PartialEq, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct PageRule<'i> { /// A list of page selectors. + #[cfg_attr(feature = "serde", serde(borrow))] pub selectors: Vec>, /// The declarations within the `@page` rule. pub declarations: DeclarationBlock<'i>, diff --git a/src/rules/property.rs b/src/rules/property.rs index fb39f4ae..a8fd19a1 100644 --- a/src/rules/property.rs +++ b/src/rules/property.rs @@ -14,8 +14,10 @@ use cssparser::*; /// A [@property](https://drafts.css-houdini.org/css-properties-values-api/#at-property-rule) rule. #[derive(Debug, PartialEq, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct PropertyRule<'i> { /// The name of the custom property to declare. + #[cfg_attr(feature = "serde", serde(borrow))] name: DashedIdent<'i>, /// A syntax string to specify the grammar for the custom property. syntax: SyntaxString, diff --git a/src/rules/style.rs b/src/rules/style.rs index cbaf4c4b..249462fd 100644 --- a/src/rules/style.rs +++ b/src/rules/style.rs @@ -18,12 +18,25 @@ use crate::vendor_prefix::VendorPrefix; use cssparser::*; use parcel_selectors::SelectorList; +#[cfg(feature = "serde")] +use crate::selector::{deserialize_selectors, serialize_selectors}; + /// A CSS [style rule](https://drafts.csswg.org/css-syntax/#style-rules). #[derive(Debug, PartialEq, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct StyleRule<'i> { /// The selectors for the style rule. + #[cfg_attr( + feature = "serde", + serde( + serialize_with = "serialize_selectors", + deserialize_with = "deserialize_selectors", + borrow + ) + )] pub selectors: SelectorList<'i, Selectors>, /// A vendor prefix override, used during selector printing. + #[cfg_attr(feature = "serde", serde(skip))] pub(crate) vendor_prefix: VendorPrefix, /// The declarations within the style rule. pub declarations: DeclarationBlock<'i>, diff --git a/src/rules/supports.rs b/src/rules/supports.rs index fb58d9a8..5b01a23b 100644 --- a/src/rules/supports.rs +++ b/src/rules/supports.rs @@ -11,8 +11,10 @@ use cssparser::*; /// A [@supports](https://drafts.csswg.org/css-conditional-3/#at-supports) rule. #[derive(Debug, PartialEq, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct SupportsRule<'i> { /// The supports condition. + #[cfg_attr(feature = "serde", serde(borrow))] pub condition: SupportsCondition<'i>, /// The rules within the `@supports` rule. pub rules: CssRuleList<'i>, @@ -56,6 +58,11 @@ impl<'a, 'i> ToCssWithContext<'a, 'i> for SupportsRule<'i> { /// A [``](https://drafts.csswg.org/css-conditional-3/#typedef-supports-condition), /// as used in the `@supports` and `@import` rules. #[derive(Debug, PartialEq, Clone)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum SupportsCondition<'i> { /// A `not` expression. Not(Box>), @@ -64,6 +71,7 @@ pub enum SupportsCondition<'i> { /// An `or` expression. Or(Vec>), /// A declaration to evaluate. + #[cfg_attr(feature = "serde", serde(borrow))] Declaration(CowArcStr<'i>), /// A selector to evaluate. Selector(CowArcStr<'i>), diff --git a/src/rules/viewport.rs b/src/rules/viewport.rs index 22809576..a3277ead 100644 --- a/src/rules/viewport.rs +++ b/src/rules/viewport.rs @@ -9,10 +9,12 @@ use crate::vendor_prefix::VendorPrefix; /// A [@viewport](https://drafts.csswg.org/css-device-adapt/#atviewport-rule) rule. #[derive(Debug, PartialEq, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct ViewportRule<'i> { /// The vendor prefix for this rule, e.g. `@-ms-viewport`. pub vendor_prefix: VendorPrefix, /// The declarations within the `@viewport` rule. + #[cfg_attr(feature = "serde", serde(borrow))] pub declarations: DeclarationBlock<'i>, /// The location of the rule in the source file. pub loc: Location, diff --git a/src/selector.rs b/src/selector.rs index 81472280..079bbc9a 100644 --- a/src/selector.rs +++ b/src/selector.rs @@ -1596,3 +1596,47 @@ pub fn is_unused( false }) } + +#[cfg(feature = "serde")] +pub fn serialize_selectors(selectors: &SelectorList, s: S) -> Result +where + S: serde::Serializer, +{ + use serde::Serialize; + selectors + .0 + .iter() + .map(|selector| { + let mut dest = String::new(); + let mut printer = Printer::new(&mut dest, PrinterOptions::default()); + serialize_selector(selector, &mut printer, None, false).unwrap(); + dest + }) + .collect::>() + .serialize(s) +} + +#[cfg(feature = "serde")] +pub fn deserialize_selectors<'i, 'de: 'i, D>(deserializer: D) -> Result, D::Error> +where + D: serde::Deserializer<'de>, +{ + use serde::Deserialize; + + let selector_parser = SelectorParser { + default_namespace: &None, + namespace_prefixes: &HashMap::new(), + is_nesting_allowed: false, + css_modules: false, + }; + + let selectors = Vec::<&'i str>::deserialize(deserializer)? + .into_iter() + .map(|selector| { + let mut input = ParserInput::new(selector); + let mut parser = Parser::new(&mut input); + Selector::parse(&selector_parser, &mut parser).unwrap() + }) + .collect(); + Ok(SelectorList(selectors)) +} diff --git a/src/stylesheet.rs b/src/stylesheet.rs index b39d20a0..6eb6561c 100644 --- a/src/stylesheet.rs +++ b/src/stylesheet.rs @@ -57,12 +57,15 @@ pub use crate::printer::PseudoClasses; /// assert_eq!(res.code, ".foo, .bar {\n color: red;\n}\n"); /// ``` #[derive(Debug)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct StyleSheet<'i> { /// A list of top-level rules within the style sheet. + #[cfg_attr(feature = "serde", serde(borrow))] pub rules: CssRuleList<'i>, /// A list of file names for all source files included within the style sheet. /// Sources are referenced by index in the `loc` property of each rule. pub sources: Vec, + #[cfg_attr(feature = "serde", serde(skip))] /// The options the style sheet was originally parsed with. options: ParserOptions, } diff --git a/src/values/alpha.rs b/src/values/alpha.rs index 098853be..d8454f29 100644 --- a/src/values/alpha.rs +++ b/src/values/alpha.rs @@ -11,6 +11,7 @@ use cssparser::*; /// /// Parses either a `` or ``, but is always stored and serialized as a number. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct AlphaValue(pub f32); impl<'i> Parse<'i> for AlphaValue { diff --git a/src/values/angle.rs b/src/values/angle.rs index 960de3ae..6550d9a0 100644 --- a/src/values/angle.rs +++ b/src/values/angle.rs @@ -15,6 +15,11 @@ use std::f32::consts::PI; /// Angles may be explicit or computed by `calc()`, but are always stored and serialized /// as their computed value. #[derive(Debug, Clone)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum Angle { /// An angle in degrees. There are 360 degrees in a full circle. Deg(CSSNumber), diff --git a/src/values/calc.rs b/src/values/calc.rs index 850e0149..2d332f01 100644 --- a/src/values/calc.rs +++ b/src/values/calc.rs @@ -13,6 +13,11 @@ use super::number::CSSNumber; /// Math functions may be used in most properties and values that accept numeric /// values, including lengths, percentages, angles, times, etc. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum MathFunction { /// The [`calc()`](https://www.w3.org/TR/css-values-4/#calc-func) function. Calc(Calc), @@ -96,6 +101,11 @@ impl + std::ops::Mul + Clo /// This type supports generic value types. Values such as [Length](super::length::Length), [Percentage](super::percentage::Percentage), /// [Time](super::time::Time), and [Angle](super::angle::Angle) support `calc()` expressions. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum Calc { /// A literal value. Value(Box), diff --git a/src/values/color.rs b/src/values/color.rs index 7a287f72..8daf2025 100644 --- a/src/values/color.rs +++ b/src/values/color.rs @@ -24,6 +24,11 @@ use std::fmt::Write; /// for all other color spaces, so it is possible to convert between color spaces easily. /// In addition, colors support [interpolation](#method.interpolate) as in the `color-mix()` function. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum CssColor { /// The [`currentColor`](https://www.w3.org/TR/css-color-4/#currentcolor-color) keyword. CurrentColor, @@ -39,6 +44,11 @@ pub enum CssColor { /// A color in a LAB color space, including the `lab()`, `lch()`, `oklab()`, and `oklch()` functions. #[derive(Debug, Clone, Copy, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum LABColor { /// A `lab()` color. LAB(LAB), @@ -52,6 +62,11 @@ pub enum LABColor { /// A color in a predefined color space, e.g. `display-p3`. #[derive(Debug, Clone, Copy, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum PredefinedColor { /// A color in the `srgb` color space. SRGB(SRGB), @@ -75,6 +90,11 @@ pub enum PredefinedColor { /// are usually stored as RGBA. These are used when there /// are any `none` components, which are represented as NaN. #[derive(Debug, Clone, Copy, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum FloatColor { /// An RGB color. RGB(SRGB), @@ -784,6 +804,7 @@ macro_rules! define_colorspace { ) => { $(#[$outer])* #[derive(Debug, Clone, Copy, PartialEq)] + #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct $name { $(#[$a_meta])* pub $a: f32, diff --git a/src/values/easing.rs b/src/values/easing.rs index 79a42097..490495c9 100644 --- a/src/values/easing.rs +++ b/src/values/easing.rs @@ -9,6 +9,11 @@ use std::fmt::Write; /// A CSS [easing function](https://www.w3.org/TR/css-easing-1/#easing-functions). #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum EasingFunction { /// A linear easing function. Linear, @@ -126,6 +131,11 @@ impl EasingFunction { /// A [step position](https://www.w3.org/TR/css-easing-1/#step-position), used within the `steps()` function. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum StepPosition { /// The first rise occurs at input progress value of 0. Start, diff --git a/src/values/gradient.rs b/src/values/gradient.rs index ccd2e7e6..ab371b5e 100644 --- a/src/values/gradient.rs +++ b/src/values/gradient.rs @@ -19,6 +19,11 @@ use cssparser::*; /// A CSS [``](https://www.w3.org/TR/css-images-3/#gradients) value. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum Gradient { /// A `linear-gradient()`, and its vendor prefix. Linear(LinearGradient, VendorPrefix), @@ -194,6 +199,7 @@ impl ToCss for Gradient { /// A CSS [`linear-gradient()`](https://www.w3.org/TR/css-images-3/#linear-gradients) or `repeating-linear-gradient()`. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct LinearGradient { /// The direction of the gradient. pub direction: LineDirection, @@ -290,6 +296,7 @@ impl LinearGradient { /// A CSS [`radial-gradient()`](https://www.w3.org/TR/css-images-3/#radial-gradients) or `repeating-radial-gradient()`. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct RadialGradient { /// The shape of the gradient. pub shape: EndingShape, @@ -360,6 +367,11 @@ impl RadialGradient { /// /// See [LinearGradient](LinearGradient). #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum LineDirection { /// An angle. Angle(Angle), @@ -446,6 +458,11 @@ impl LineDirection { /// /// See [RadialGradient](RadialGradient). #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum EndingShape { /// A circle. Circle(Circle), @@ -490,6 +507,11 @@ impl ToCss for EndingShape { /// /// See [RadialGradient](RadialGradient). #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum Circle { /// A circle with a specified radius. Radius(Length), @@ -552,6 +574,11 @@ impl ToCss for Circle { /// /// See [RadialGradient](RadialGradient). #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum Ellipse { /// An ellipse with a specified horizontal and vertical radius. Size(LengthPercentage, LengthPercentage), @@ -631,6 +658,7 @@ enum_property! { /// A CSS [`conic-gradient()`](https://www.w3.org/TR/css-images-4/#conic-gradients) or `repeating-conic-gradient()`. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct ConicGradient { /// The angle of the gradient. pub angle: Angle, @@ -706,6 +734,7 @@ impl ConicGradient { /// This type is generic, and may be either a [LengthPercentage](super::length::LengthPercentage) /// or [Angle](super::angle::Angle) depending on what type of gradient it is within. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct ColorStop { /// The color of the color stop. pub color: CssColor, @@ -740,6 +769,11 @@ impl ToCss for ColorStop { /// This type is generic, and items may be either a [LengthPercentage](super::length::LengthPercentage) /// or [Angle](super::angle::Angle) depending on what type of gradient it is within. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum GradientItem { /// A color stop. ColorStop(ColorStop), @@ -884,6 +918,11 @@ where /// A legacy `-webkit-gradient()`. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum WebKitGradient { /// A linear `-webkit-gradient()`. Linear { @@ -1023,6 +1062,7 @@ impl WebKitGradient { /// A color stop within a legacy `-webkit-gradient()`. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct WebKitColorStop { /// The color of the color stop. pub color: CssColor, @@ -1083,6 +1123,7 @@ impl WebKitColorStop { /// An x/y position within a legacy `-webkit-gradient()`. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct WebKitGradientPoint { /// The x-position. pub x: WebKitGradientPointComponent, @@ -1111,6 +1152,11 @@ impl ToCss for WebKitGradientPoint { /// A keyword or number within a [WebKitGradientPoint](WebKitGradientPoint). #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum WebKitGradientPointComponent { /// The `center` keyword. Center, diff --git a/src/values/ident.rs b/src/values/ident.rs index db56db3d..edb5c2f2 100644 --- a/src/values/ident.rs +++ b/src/values/ident.rs @@ -13,7 +13,8 @@ use smallvec::SmallVec; /// [CSS-wide keywords](https://www.w3.org/TR/css-values-4/#css-wide-keywords). /// They may be renamed to include a hash when compiled as part of a CSS module. #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct CustomIdent<'i>(pub CowArcStr<'i>); +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct CustomIdent<'i>(#[cfg_attr(feature = "serde", serde(borrow))] pub CowArcStr<'i>); impl<'i> Parse<'i> for CustomIdent<'i> { fn parse<'t>(input: &mut Parser<'i, 't>) -> Result>> { @@ -49,7 +50,8 @@ pub type CustomIdentList<'i> = SmallVec<[CustomIdent<'i>; 1]>; /// Dashed idents are used in cases where an identifier can be either author defined _or_ CSS-defined. /// Author defined idents must start with two dash characters ("--") or parsing will fail. #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct DashedIdent<'i>(pub CowArcStr<'i>); +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct DashedIdent<'i>(#[cfg_attr(feature = "serde", serde(borrow))] pub CowArcStr<'i>); impl<'i> Parse<'i> for DashedIdent<'i> { fn parse<'t>(input: &mut Parser<'i, 't>) -> Result>> { diff --git a/src/values/image.rs b/src/values/image.rs index 22750a99..7ea196b6 100644 --- a/src/values/image.rs +++ b/src/values/image.rs @@ -17,10 +17,16 @@ use smallvec::SmallVec; /// A CSS [``](https://www.w3.org/TR/css-images-3/#image-values) value. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum Image<'i> { /// The `none` keyword. None, /// A `url()`. + #[cfg_attr(feature = "serde", serde(borrow))] Url(Url<'i>), /// A gradient. Gradient(Box), @@ -309,8 +315,10 @@ impl<'i> ToCss for Image<'i> { /// `image-set()` allows the user agent to choose between multiple versions of an image to /// display the most appropriate resolution or file type that it supports. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct ImageSet<'i> { /// The image options to choose from. + #[cfg_attr(feature = "serde", serde(borrow))] pub options: Vec>, /// The vendor prefix for the `image-set()` function. pub vendor_prefix: VendorPrefix, @@ -379,12 +387,14 @@ impl<'i> ToCss for ImageSet<'i> { /// An image option within the `image-set()` function. See [ImageSet](ImageSet). #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct ImageSetOption<'i> { /// The image for this option. pub image: Image<'i>, /// The resolution of the image. pub resolution: Resolution, /// The mime type of the image. + #[cfg_attr(feature = "serde", serde(borrow))] pub file_type: Option>, } @@ -392,7 +402,10 @@ impl<'i> Parse<'i> for ImageSetOption<'i> { fn parse<'t>(input: &mut Parser<'i, 't>) -> Result>> { let loc = input.current_source_location(); let image = if let Ok(url) = input.try_parse(|input| input.expect_url_or_string()) { - Image::Url(Url { url: url.into(), loc }) + Image::Url(Url { + url: url.into(), + loc: loc.into(), + }) } else { Image::parse(input)? }; diff --git a/src/values/length.rs b/src/values/length.rs index 6ab8e55b..ca867018 100644 --- a/src/values/length.rs +++ b/src/values/length.rs @@ -37,6 +37,11 @@ impl LengthPercentage { /// Either a [``](https://www.w3.org/TR/css-values-4/#typedef-length-percentage), or the `auto` keyword. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum LengthPercentageOrAuto { /// The `auto` keyword. Auto, @@ -88,6 +93,7 @@ macro_rules! define_length_units { /// A CSS [``](https://www.w3.org/TR/css-values-4/#lengths) value, /// without support for `calc()`. See also: [Length](Length). #[derive(Debug, Clone, PartialEq)] + #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(tag = "unit", content = "value", rename_all = "kebab-case"))] pub enum LengthValue { $( $(#[$meta])* @@ -386,6 +392,11 @@ impl LengthValue { /// A CSS [``](https://www.w3.org/TR/css-values-4/#lengths) value, with support for `calc()`. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum Length { /// An explicitly specified length value. Value(LengthValue), @@ -585,6 +596,11 @@ impl std::cmp::PartialOrd for Length { /// Either a [``](https://www.w3.org/TR/css-values-4/#lengths) or a [``](https://www.w3.org/TR/css-values-4/#numbers). #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum LengthOrNumber { /// A length. Length(Length), diff --git a/src/values/percentage.rs b/src/values/percentage.rs index 396c1158..c60da566 100644 --- a/src/values/percentage.rs +++ b/src/values/percentage.rs @@ -12,6 +12,7 @@ use cssparser::*; /// Percentages may be explicit or computed by `calc()`, but are always stored and serialized /// as their computed value. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Percentage(pub CSSNumber); impl<'i> Parse<'i> for Percentage { @@ -111,6 +112,11 @@ impl std::cmp::PartialOrd for Percentage { /// Either a `` or ``. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum NumberOrPercentage { /// A percentage. Percentage(Percentage), @@ -167,6 +173,11 @@ impl std::convert::Into for &NumberOrPercentage { /// /// #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum DimensionPercentage { /// An explicit dimension value. Dimension(D), diff --git a/src/values/position.rs b/src/values/position.rs index 490f2233..943de280 100644 --- a/src/values/position.rs +++ b/src/values/position.rs @@ -11,6 +11,7 @@ use cssparser::*; /// A CSS [``](https://www.w3.org/TR/css3-values/#position) value, /// as used in the `background-position` property, gradients, masks, etc. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Position { /// The x-position. pub x: HorizontalPosition, @@ -236,6 +237,11 @@ impl ToCss for Position { /// /// This type is generic over side keywords. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum PositionComponent { /// The `center` keyword. Center, diff --git a/src/values/ratio.rs b/src/values/ratio.rs index 844dc4e5..ba6d5c17 100644 --- a/src/values/ratio.rs +++ b/src/values/ratio.rs @@ -9,6 +9,7 @@ use cssparser::*; /// A CSS [``](https://www.w3.org/TR/css-values-4/#ratios) value, /// representing the ratio of two numeric values. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Ratio(pub CSSNumber, pub CSSNumber); impl<'i> Parse<'i> for Ratio { diff --git a/src/values/rect.rs b/src/values/rect.rs index 6e9f7511..303110cf 100644 --- a/src/values/rect.rs +++ b/src/values/rect.rs @@ -11,6 +11,7 @@ use cssparser::*; /// When serialized, as few components as possible are written when /// there are duplicate values. #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Rect( /// The top component. pub T, diff --git a/src/values/resolution.rs b/src/values/resolution.rs index f54025c7..d02a55dd 100644 --- a/src/values/resolution.rs +++ b/src/values/resolution.rs @@ -9,6 +9,11 @@ use cssparser::*; /// A CSS [``](https://www.w3.org/TR/css-values-4/#resolution) value. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum Resolution { /// A resolution in dots per inch. Dpi(CSSNumber), diff --git a/src/values/shape.rs b/src/values/shape.rs index dfd41a4e..7d9bda4b 100644 --- a/src/values/shape.rs +++ b/src/values/shape.rs @@ -12,6 +12,11 @@ use cssparser::*; /// A CSS [``](https://www.w3.org/TR/css-shapes-1/#basic-shape-functions) value. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum BasicShape { /// An inset rectangle. Inset(InsetRect), @@ -25,6 +30,7 @@ pub enum BasicShape { /// An [`inset()`](https://www.w3.org/TR/css-shapes-1/#funcdef-inset) rectangle shape. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct InsetRect { /// The rectangle. pub rect: Rect, @@ -34,6 +40,7 @@ pub struct InsetRect { /// A [`circle()`](https://www.w3.org/TR/css-shapes-1/#funcdef-circle) shape. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Circle { /// The radius of the circle. pub radius: ShapeRadius, @@ -44,6 +51,11 @@ pub struct Circle { /// A [``](https://www.w3.org/TR/css-shapes-1/#typedef-shape-radius) value /// that defines the radius of a `circle()` or `ellipse()` shape. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum ShapeRadius { /// An explicit length or percentage. LengthPercentage(LengthPercentage), @@ -55,6 +67,7 @@ pub enum ShapeRadius { /// An [`ellipse()`](https://www.w3.org/TR/css-shapes-1/#funcdef-ellipse) shape. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Ellipse { /// The x-radius of the ellipse. pub radius_x: ShapeRadius, @@ -66,6 +79,7 @@ pub struct Ellipse { /// A [`polygon()`](https://www.w3.org/TR/css-shapes-1/#funcdef-polygon) shape. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Polygon { /// The fill rule used to determine the interior of the polygon. pub fill_rule: FillRule, @@ -77,6 +91,7 @@ pub struct Polygon { /// /// See [Polygon](Polygon). #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Point { /// The x position of the point. x: LengthPercentage, diff --git a/src/values/size.rs b/src/values/size.rs index 14adc35c..f95af57a 100644 --- a/src/values/size.rs +++ b/src/values/size.rs @@ -9,6 +9,7 @@ use cssparser::*; /// /// When serialized, only a single component will be written if both are equal. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Size2D(pub T, pub T); impl<'i, T> Parse<'i> for Size2D diff --git a/src/values/string.rs b/src/values/string.rs index 0e0625f6..f1a42bb4 100644 --- a/src/values/string.rs +++ b/src/values/string.rs @@ -1,7 +1,8 @@ //! Types used to represent strings. use cssparser::CowRcStr; -use serde::{Serialize, Serializer}; +use serde::de::Visitor; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::borrow::Borrow; use std::cmp; use std::fmt; @@ -220,3 +221,46 @@ impl<'a> Serialize for CowArcStr<'a> { self.as_ref().serialize(serializer) } } + +#[cfg(feature = "serde")] +impl<'a, 'de: 'a> Deserialize<'de> for CowArcStr<'a> { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(CowArcStrVisitor) + } +} + +#[cfg(feature = "serde")] +struct CowArcStrVisitor; + +#[cfg(feature = "serde")] +impl<'de> Visitor<'de> for CowArcStrVisitor { + type Value = CowArcStr<'de>; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a CowArcStr") + } + + fn visit_borrowed_str(self, v: &'de str) -> Result + where + E: serde::de::Error, + { + Ok(v.into()) + } + + fn visit_str(self, v: &str) -> Result + where + E: serde::de::Error, + { + Ok(v.to_owned().into()) + } + + fn visit_string(self, v: String) -> Result + where + E: serde::de::Error, + { + Ok(v.into()) + } +} diff --git a/src/values/syntax.rs b/src/values/syntax.rs index df73299b..d170c1b4 100644 --- a/src/values/syntax.rs +++ b/src/values/syntax.rs @@ -11,6 +11,11 @@ use cssparser::*; /// A CSS [syntax string](https://drafts.css-houdini.org/css-properties-values-api/#syntax-strings) /// used to define the grammar for a registered custom property. #[derive(Debug, PartialEq, Clone)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum SyntaxString { /// A list of syntax components. Components(Vec), @@ -24,6 +29,7 @@ pub enum SyntaxString { /// A syntax component consists of a component kind an a multiplier, which indicates how the component /// may repeat during parsing. #[derive(Debug, PartialEq, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct SyntaxComponent { /// The kind of component. pub kind: SyntaxComponentKind, @@ -33,6 +39,11 @@ pub struct SyntaxComponent { /// A [syntax component component name](https://drafts.css-houdini.org/css-properties-values-api/#supported-names). #[derive(Debug, PartialEq, Clone)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum SyntaxComponentKind { /// A `` component. Length, @@ -69,6 +80,11 @@ pub enum SyntaxComponentKind { /// A [multiplier](https://drafts.css-houdini.org/css-properties-values-api/#multipliers) for a /// [SyntaxComponent](SyntaxComponent). Indicates whether and how the component may be repeated. #[derive(Debug, PartialEq, Clone)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum Multiplier { /// The component may not be repeated. None, @@ -80,6 +96,11 @@ pub enum Multiplier { /// A parsed value for a [SyntaxComponent](SyntaxComponent). #[derive(Debug, PartialEq, Clone)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum ParsedComponent<'i> { /// A `` value. Length(values::length::Length), @@ -92,6 +113,7 @@ pub enum ParsedComponent<'i> { /// A `` value. Color(values::color::CssColor), /// An `` value. + #[cfg_attr(feature = "serde", serde(borrow))] Image(values::image::Image<'i>), /// A `` value. Url(values::url::Url<'i>), diff --git a/src/values/time.rs b/src/values/time.rs index 001ee99c..a6b30454 100644 --- a/src/values/time.rs +++ b/src/values/time.rs @@ -13,6 +13,11 @@ use cssparser::*; /// Time values may be explicit or computed by `calc()`, but are always stored and serialized /// as their computed value. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", content = "value", rename_all = "kebab-case") +)] pub enum Time { /// A time in seconds. Seconds(CSSNumber), diff --git a/src/values/url.rs b/src/values/url.rs index c7a1b373..77333075 100644 --- a/src/values/url.rs +++ b/src/values/url.rs @@ -1,6 +1,6 @@ //! CSS url() values. -use crate::dependencies::{Dependency, UrlDependency}; +use crate::dependencies::{Dependency, Location, UrlDependency}; use crate::error::{ParserError, PrinterError}; use crate::printer::Printer; use crate::traits::{Parse, ToCss}; @@ -9,18 +9,20 @@ use cssparser::*; /// A CSS [url()](https://www.w3.org/TR/css-values-4/#urls) value and its source location. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Url<'i> { /// The url string. + #[cfg_attr(feature = "serde", serde(borrow))] pub url: CowArcStr<'i>, /// The location where the `url()` was seen in the CSS source file. - pub loc: SourceLocation, + pub loc: Location, } impl<'i> Parse<'i> for Url<'i> { fn parse<'t>(input: &mut Parser<'i, 't>) -> Result>> { let loc = input.current_source_location(); let url = input.expect_url()?.into(); - Ok(Url { url, loc }) + Ok(Url { url, loc: loc.into() }) } } diff --git a/src/vendor_prefix.rs b/src/vendor_prefix.rs index b93084e2..a99a4054 100644 --- a/src/vendor_prefix.rs +++ b/src/vendor_prefix.rs @@ -15,6 +15,7 @@ bitflags! { /// more than one prefix. During printing, the rule or property will /// be duplicated for each prefix flag that is enabled. This enables /// vendor prefixes to be added without increasing memory usage. + #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct VendorPrefix: u8 { /// No vendor prefixes. const None = 0b00000001; From 8687c05f4527517c17e353aa0729136bd2c7c3ab Mon Sep 17 00:00:00 2001 From: Devon Govett Date: Thu, 12 May 2022 00:37:29 -0400 Subject: [PATCH 2/2] Format improvements and example --- .github/workflows/test.yml | 2 +- examples/serialize.rs | 20 +++++++++++++ src/lib.rs | 2 +- src/printer.rs | 2 +- src/properties/custom.rs | 6 ++-- src/properties/mod.rs | 9 ++++-- src/properties/ui.rs | 6 +++- src/rules/style.rs | 2 +- src/values/color.rs | 16 +++++++--- src/values/string.rs | 5 ++-- src/vendor_prefix.rs | 54 +++++++++++++++++++++++++++++++++- tests/cli_integration_tests.rs | 12 ++++---- tests/test_serde.rs | 20 +++++++++++++ 13 files changed, 132 insertions(+), 24 deletions(-) create mode 100644 examples/serialize.rs create mode 100644 tests/test_serde.rs diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6b55f762..b9ea4b25 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,4 +18,4 @@ jobs: - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v1 - run: cargo fmt - - run: cargo test + - run: cargo test --all-features diff --git a/examples/serialize.rs b/examples/serialize.rs new file mode 100644 index 00000000..6101d857 --- /dev/null +++ b/examples/serialize.rs @@ -0,0 +1,20 @@ +fn main() { + parse(); +} + +#[cfg(feature = "serde")] +fn parse() { + use parcel_css::stylesheet::{ParserOptions, StyleSheet}; + use std::{env, fs}; + + let args: Vec = env::args().collect(); + let contents = fs::read_to_string(&args[1]).unwrap(); + let stylesheet = StyleSheet::parse(&args[1], &contents, ParserOptions::default()).unwrap(); + let json = serde_json::to_string(&stylesheet).unwrap(); + println!("{}", json); +} + +#[cfg(not(feature = "serde"))] +fn parse() { + panic!("serde feature is not enabled") +} diff --git a/src/lib.rs b/src/lib.rs index 6c8e5ee3..724470e7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14291,7 +14291,7 @@ mod tests { ); error_test( "@-moz-document url-prefix(\"foo\") {}", - ParserError::UnexpectedToken(crate::properties::custom::Token::QuotedString("foo".into())), + ParserError::UnexpectedToken(crate::properties::custom::Token::String("foo".into())), ); } diff --git a/src/printer.rs b/src/printer.rs index ffcfe0a8..7bd2936e 100644 --- a/src/printer.rs +++ b/src/printer.rs @@ -6,7 +6,7 @@ use crate::error::{Error, ErrorLocation, PrinterError, PrinterErrorKind}; use crate::rules::Location; use crate::targets::Browsers; use crate::vendor_prefix::VendorPrefix; -use cssparser::{serialize_identifier, SourceLocation}; +use cssparser::serialize_identifier; use parcel_sourcemap::{OriginalLocation, SourceMap}; /// Options that control how CSS is serialized to a string. diff --git a/src/properties/custom.rs b/src/properties/custom.rs index e8b0f068..f97eba1e 100644 --- a/src/properties/custom.rs +++ b/src/properties/custom.rs @@ -359,7 +359,7 @@ pub enum Token<'a> { /// A [``](https://drafts.csswg.org/css-syntax/#string-token-diagram) /// /// The value does not include the quotes. - QuotedString(CowArcStr<'a>), + String(CowArcStr<'a>), /// A [``](https://drafts.csswg.org/css-syntax/#url-token-diagram) /// @@ -506,7 +506,7 @@ impl<'a> From<&cssparser::Token<'a>> for Token<'a> { cssparser::Token::AtKeyword(x) => Token::AtKeyword(x.into()), cssparser::Token::Hash(x) => Token::Hash(x.into()), cssparser::Token::IDHash(x) => Token::IDHash(x.into()), - cssparser::Token::QuotedString(x) => Token::QuotedString(x.into()), + cssparser::Token::QuotedString(x) => Token::String(x.into()), cssparser::Token::UnquotedUrl(x) => Token::UnquotedUrl(x.into()), cssparser::Token::Function(x) => Token::Function(x.into()), cssparser::Token::BadUrl(x) => Token::BadUrl(x.into()), @@ -575,7 +575,7 @@ impl<'a> ToCss for Token<'a> { Token::AtKeyword(x) => cssparser::Token::AtKeyword(x.as_ref().into()).to_css(dest)?, Token::Hash(x) => cssparser::Token::Hash(x.as_ref().into()).to_css(dest)?, Token::IDHash(x) => cssparser::Token::IDHash(x.as_ref().into()).to_css(dest)?, - Token::QuotedString(x) => cssparser::Token::QuotedString(x.as_ref().into()).to_css(dest)?, + Token::String(x) => cssparser::Token::QuotedString(x.as_ref().into()).to_css(dest)?, Token::UnquotedUrl(x) => cssparser::Token::UnquotedUrl(x.as_ref().into()).to_css(dest)?, Token::Function(x) => cssparser::Token::Function(x.as_ref().into()).to_css(dest)?, Token::BadUrl(x) => cssparser::Token::BadUrl(x.as_ref().into()).to_css(dest)?, diff --git a/src/properties/mod.rs b/src/properties/mod.rs index 22f0e2bf..dcbb18bb 100644 --- a/src/properties/mod.rs +++ b/src/properties/mod.rs @@ -29,6 +29,7 @@ //! properties::{Property, PropertyId, background::*}, //! values::{url::Url, image::Image, color::CssColor, position::*, length::*}, //! stylesheet::{ParserOptions, PrinterOptions}, +//! dependencies::Location, //! }; //! //! let background = Property::parse_string( @@ -42,7 +43,7 @@ //! Property::Background(smallvec![Background { //! image: Image::Url(Url { //! url: "img.png".into(), -//! loc: cssparser::SourceLocation { line: 0, column: 1 } +//! loc: Location { line: 1, column: 1 } //! }), //! color: CssColor::RGBA(cssparser::RGBA { //! red: 0, @@ -181,9 +182,10 @@ macro_rules! define_properties { $property$(($vp))?, )+ /// The `all` property. + #[cfg_attr(feature = "serde", serde(rename = "all"))] All, /// An unknown or custom property name. - #[cfg_attr(feature = "serde", serde(borrow))] + #[cfg_attr(feature = "serde", serde(borrow, rename = "custom"))] Custom(CowArcStr<'i>) } @@ -530,9 +532,10 @@ macro_rules! define_properties { $property($type, $($vp)?), )+ /// An unparsed property. - #[cfg_attr(feature = "serde", serde(borrow))] + #[cfg_attr(feature = "serde", serde(borrow, rename = "unparsed"))] Unparsed(UnparsedProperty<'i>), /// A custom or unknown property. + #[cfg_attr(feature = "serde", serde(borrow, rename = "custom"))] Custom(CustomProperty<'i>), } diff --git a/src/properties/ui.rs b/src/properties/ui.rs index f124b128..cb676530 100644 --- a/src/properties/ui.rs +++ b/src/properties/ui.rs @@ -282,7 +282,11 @@ enum_property! { /// A value for the [appearance](https://www.w3.org/TR/2021/WD-css-ui-4-20210316/#appearance-switching) property. #[derive(Debug, Clone, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(rename_all = "kebab-case") +)] #[allow(missing_docs)] pub enum Appearance<'i> { None, diff --git a/src/rules/style.rs b/src/rules/style.rs index 249462fd..b0332509 100644 --- a/src/rules/style.rs +++ b/src/rules/style.rs @@ -36,7 +36,7 @@ pub struct StyleRule<'i> { )] pub selectors: SelectorList<'i, Selectors>, /// A vendor prefix override, used during selector printing. - #[cfg_attr(feature = "serde", serde(skip))] + #[cfg_attr(feature = "serde", serde(skip, default = "VendorPrefix::empty"))] pub(crate) vendor_prefix: VendorPrefix, /// The declarations within the style rule. pub declarations: DeclarationBlock<'i>, diff --git a/src/values/color.rs b/src/values/color.rs index 8daf2025..9727e7f4 100644 --- a/src/values/color.rs +++ b/src/values/color.rs @@ -27,7 +27,7 @@ use std::fmt::Write; #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), - serde(tag = "type", content = "value", rename_all = "kebab-case") + serde(tag = "type", content = "value", rename_all = "lowercase") )] pub enum CssColor { /// The [`currentColor`](https://www.w3.org/TR/css-color-4/#currentcolor-color) keyword. @@ -47,7 +47,7 @@ pub enum CssColor { #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), - serde(tag = "type", content = "value", rename_all = "kebab-case") + serde(tag = "type", content = "value", rename_all = "lowercase") )] pub enum LABColor { /// A `lab()` color. @@ -65,24 +65,32 @@ pub enum LABColor { #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), - serde(tag = "type", content = "value", rename_all = "kebab-case") + serde(tag = "type", content = "value") )] pub enum PredefinedColor { /// A color in the `srgb` color space. + #[cfg_attr(feature = "serde", serde(rename = "srgb"))] SRGB(SRGB), /// A color in the `srgb-linear` color space. + #[cfg_attr(feature = "serde", serde(rename = "srgb-linear"))] SRGBLinear(SRGBLinear), /// A color in the `display-p3` color space. + #[cfg_attr(feature = "serde", serde(rename = "display-p3"))] DisplayP3(P3), /// A color in the `a98-rgb` color space. + #[cfg_attr(feature = "serde", serde(rename = "a98-rgb"))] A98(A98), /// A color in the `prophoto-rgb` color space. + #[cfg_attr(feature = "serde", serde(rename = "prophoto-rgb"))] ProPhoto(ProPhoto), /// A color in the `rec2020` color space. + #[cfg_attr(feature = "serde", serde(rename = "rec2020"))] Rec2020(Rec2020), /// A color in the `xyz-d50` color space. + #[cfg_attr(feature = "serde", serde(rename = "xyz-d50"))] XYZd50(XYZd50), /// A color in the `xyz-d65` color space. + #[cfg_attr(feature = "serde", serde(rename = "xyz-d65"))] XYZd65(XYZd65), } @@ -93,7 +101,7 @@ pub enum PredefinedColor { #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), - serde(tag = "type", content = "value", rename_all = "kebab-case") + serde(tag = "type", content = "value", rename_all = "lowercase") )] pub enum FloatColor { /// An RGB color. diff --git a/src/values/string.rs b/src/values/string.rs index f1a42bb4..7b60a684 100644 --- a/src/values/string.rs +++ b/src/values/string.rs @@ -1,8 +1,9 @@ //! Types used to represent strings. use cssparser::CowRcStr; -use serde::de::Visitor; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; +#[cfg(feature = "serde")] +use serde::{de::Visitor, Deserialize, Deserializer}; +use serde::{Serialize, Serializer}; use std::borrow::Borrow; use std::cmp; use std::fmt; diff --git a/src/vendor_prefix.rs b/src/vendor_prefix.rs index a99a4054..2994156c 100644 --- a/src/vendor_prefix.rs +++ b/src/vendor_prefix.rs @@ -15,7 +15,6 @@ bitflags! { /// more than one prefix. During printing, the rule or property will /// be duplicated for each prefix flag that is enabled. This enables /// vendor prefixes to be added without increasing memory usage. - #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct VendorPrefix: u8 { /// No vendor prefixes. const None = 0b00000001; @@ -73,3 +72,56 @@ impl cssparser::ToCss for VendorPrefix { } } } + +#[cfg(feature = "serde")] +impl serde::Serialize for VendorPrefix { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut values = Vec::new(); + if *self != VendorPrefix::None { + if self.contains(VendorPrefix::None) { + values.push("none"); + } + if self.contains(VendorPrefix::WebKit) { + values.push("webkit"); + } + if self.contains(VendorPrefix::Moz) { + values.push("moz"); + } + if self.contains(VendorPrefix::Ms) { + values.push("ms"); + } + if self.contains(VendorPrefix::O) { + values.push("o"); + } + } + values.serialize(serializer) + } +} + +#[cfg(feature = "serde")] +impl<'de> serde::Deserialize<'de> for VendorPrefix { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let values = Vec::<&str>::deserialize(deserializer)?; + if values.is_empty() { + return Ok(VendorPrefix::None); + } + let mut res = VendorPrefix::empty(); + for value in values { + res |= match value { + "none" => VendorPrefix::None, + "webkit" => VendorPrefix::WebKit, + "moz" => VendorPrefix::Moz, + "ms" => VendorPrefix::Ms, + "o" => VendorPrefix::O, + _ => continue, + }; + } + Ok(res) + } +} diff --git a/tests/cli_integration_tests.rs b/tests/cli_integration_tests.rs index 4117b4ab..8fb3fb9c 100644 --- a/tests/cli_integration_tests.rs +++ b/tests/cli_integration_tests.rs @@ -24,7 +24,7 @@ fn css_module_test_vals() -> (String, String, String) { ( "fade", CssModuleExport { - name: "fade_EgL3uq".into(), + name: "EgL3uq_fade".into(), composes: vec![], is_referenced: false, }, @@ -32,7 +32,7 @@ fn css_module_test_vals() -> (String, String, String) { ( "foo", CssModuleExport { - name: "foo_EgL3uq".into(), + name: "EgL3uq_foo".into(), composes: vec![], is_referenced: false, }, @@ -40,7 +40,7 @@ fn css_module_test_vals() -> (String, String, String) { ( "circles", CssModuleExport { - name: "circles_EgL3uq".into(), + name: "EgL3uq_circles".into(), composes: vec![], is_referenced: true, }, @@ -48,7 +48,7 @@ fn css_module_test_vals() -> (String, String, String) { ( "id", CssModuleExport { - name: "id_EgL3uq".into(), + name: "EgL3uq_id".into(), composes: vec![], is_referenced: false, }, @@ -56,7 +56,7 @@ fn css_module_test_vals() -> (String, String, String) { ( "test", CssModuleExport { - name: "test_EgL3uq".into(), + name: "EgL3uq_test".into(), composes: vec![], is_referenced: true, }, @@ -201,7 +201,7 @@ fn minify_option() -> Result<(), Box> { cmd .assert() .success() - .stdout(predicate::str::contains(indoc! {r#".foo{border:0}"#})); + .stdout(predicate::str::contains(indoc! {r#".foo{border:none}"#})); Ok(()) } diff --git a/tests/test_serde.rs b/tests/test_serde.rs new file mode 100644 index 00000000..99bb3f33 --- /dev/null +++ b/tests/test_serde.rs @@ -0,0 +1,20 @@ +#[cfg(feature = "serde")] +use parcel_css::stylesheet::{ParserOptions, StyleSheet}; + +#[cfg(feature = "serde")] +#[test] +fn test_serde() { + let code = r#" + .foo { + color: red; + } + "#; + let (json, stylesheet) = { + let stylesheet = StyleSheet::parse("test.css", code, ParserOptions::default()).unwrap(); + let json = serde_json::to_string(&stylesheet).unwrap(); + (json, stylesheet) + }; + + let deserialized: StyleSheet = serde_json::from_str(&json).unwrap(); + assert_eq!(&deserialized.rules, &stylesheet.rules); +}