css_ast 0.0.31

CSS Abstract Syntax Trees with visitable nodes and style value types.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
use bitmask_enum::bitmask;

use crate::{CssAtomSet, UnitlessZeroResolves};

/// The CSS specification/module that a property belongs to.
#[bitmask(u128)]
#[bitmask_config(vec_debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum PropertyGroup {
	Align,
	AnchorPosition,
	Css2,
	AnimationTriggers,
	Animations,
	Backgrounds,
	Borders,
	Box,
	Break,
	Cascade,
	Color,
	ColorAdjust,
	ColorHdr,
	Compositing,
	Conditional,
	Contain,
	Content,
	CounterStyle,
	Display,
	Exclusions,
	FillStroke,
	FilterEffects,
	Flexbox,
	Fonts,
	Forms,
	Gaps,
	Gcpm,
	Grid,
	Images,
	ImageAnimation,
	Inline,
	LineGrid,
	LinkParams,
	Lists,
	Logical,
	Masking,
	Motion,
	Multicol,
	Nav,
	Overflow,
	Overscroll,
	Page,
	PageFloats,
	PointerAnimations,
	PointerEvents,
	Position,
	Regions,
	Rhythm,
	RoundDisplay,
	Ruby,
	ScrollAnchoring,
	ScrollAnimations,
	ScrollSnap,
	Scrollbars,
	Shaders,
	Shapes,
	SvgPainting,
	SizeAdjust,
	Sizing,
	Speech,
	Tables,
	Text,
	TextDecor,
	Transforms,
	Transitions,
	Ui,
	Values,
	Variables,
	ViewTransitions,
	Viewport,
	WillChange,
	WritingModes,
}

pub enum Inherits {
	False,
	True,
	Unknown,
}

impl Inherits {
	pub fn to_bool(self, unknown: bool) -> bool {
		match self {
			Self::False => false,
			Self::True => true,
			Self::Unknown => unknown,
		}
	}
}

pub enum Percentages {
	/// This style value has no way of expressing values as a percentage.
	None,
	/// Any percentage expressed in this value pertains to the size of the containing block.
	ContainingBlock,
	/// Any percentage expressed in this value pertains to the size of the border box.
	BorderBox,
	/// Any percentage expressed in this value is a syntax affordance; a Number token would be the equivalent value.
	Number,
	/// Relative to the 1em Font-Size
	FontSize,
	/// Relative to the Font-Size of the parent element
	ParentFontSize,
	/// Relative to the scroll container's scrollport
	Scrollport,
	/// Relative to the content area dimension
	ContentArea,
	/// Relative to the border-edge side length
	BorderEdge,
	/// Relative to the background positioning area
	BackgroundPositioningArea,
	/// Relative to the reference box size
	ReferenceBox,
	/// Relative to the element's own dimensions
	SelfSize,
	/// Relative to the line box
	LineBox,
	/// Relative to the flex container
	FlexContainer,
	/// Relative to the border image area
	BorderImageArea,
	/// Map to a normalized range (e.g., `[0,1]`)
	NormalizedRange,
	/// Unknown or complex percentage resolution
	Unknown,
}

/// The type of element or container this style value applies to.
#[bitmask(u16)]
#[bitmask_config(vec_debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum AppliesTo {
	/// Any element which is `display: block` or equivalent.
	Block,
	/// Any element which is `display: grid` or equivalent.
	Grid,
	/// Any element which is `display: flex` or equivalent.
	Flex,
	/// Any inline-level box.
	Inline,
	/// Any floated element.
	Float,
	/// Any Ruby container
	Ruby,
	/// Any absolutely positioned element.
	AbsPos,
	/// Any text node.
	Text,
	/// Any Pseudo Elements
	PseudoElements,
	/// Any Element
	Elements,
	/// What this applies to still needs to be established.
	Unknown,
}

pub enum AnimationType {
	/// This property is not animatable.
	None,
	/// This property animates between discrete values.
	Discrete,
	/// Animates by interpolating computed values
	ByComputedValue,
	/// Each item in a list animates independently
	RepeatableList,
	/// Animates as a transform list
	TransformList,
	/// Animates as a shadow list
	ShadowList,
	/// Animates as a length value
	Length,
	/// Animates as a number value
	Number,
	/// Unknown or complex animation behavior
	Unknown,
}

/// How the computed value is calculated from the specified value
pub enum ComputedValueType {
	/// The computed value is the same as the specified value
	AsSpecified,
	/// Computed to an absolute length
	AbsoluteLength,
	/// Computed to an absolute length or percentage
	AbsoluteLengthOrPercentage,
	/// Computed to an absolute length or 'none'
	AbsoluteLengthOrNone,
	/// A specified keyword plus an absolute length
	SpecifiedKeywordPlusAbsoluteLength,
	/// Two absolute lengths (e.g., for background-position)
	TwoAbsoluteLengths,
	/// A list of absolute lengths
	ListOfAbsoluteLengths,
	/// Computed as specified, but with relative lengths converted to absolute
	SpecifiedWithAbsoluteLengths,
	/// Computed as specified, but with relative URLs converted to absolute
	SpecifiedWithAbsoluteUrls,
	/// Special computation rules - see spec
	SeeIndividualProperties,
	/// Computed value calculation is complex or spec-specific
	Complex,
	/// Not yet categorized
	Unknown,
}

/// Which side(s) of the box a property applies to.
/// This is a bitmask so properties can apply to multiple sides.
#[bitmask(u8)]
#[bitmask_config(vec_debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum BoxSide {
	/// Applies to the physical top side
	Top = 0b00000001,
	/// Applies to the physical bottom side
	Bottom = 0b00000010,
	/// Applies to the physical left side
	Left = 0b00000100,
	/// Applies to the physical right side
	Right = 0b00001000,
	/// Applies to the logical block-start side
	BlockStart = 0b00010000,
	/// Applies to the logical block-end side
	BlockEnd = 0b00100000,
	/// Applies to the logical inline-start side
	InlineStart = 0b01000000,
	/// Applies to the logical inline-end side
	InlineEnd = 0b10000000,
}

impl BoxSide {
	#[inline]
	pub fn num_sides(&self, logical: bool) -> u32 {
		if logical { (self.bits() & 0b11110000).count_ones() } else { (self.bits() & 0b00001111).count_ones() }
	}
}

/// Which portion(s) of the box model a property affects.
/// This is a bitmask so properties can affect multiple portions.
#[bitmask(u8)]
#[bitmask_config(vec_debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum BoxPortion {
	/// Affects the content size (width/height)
	Size,
	/// Affects the margin area
	Margin,
	/// Affects the padding area
	Padding,
	/// Affects the border area
	Border,
	/// Affects the position/placement of the box
	Position,
}
/// Reset coverage recorded for a shorthand property.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ShorthandReset {
	/// Properties reset in addition to the expressible longhands.
	Properties(&'static [CssAtomSet]),
	/// All properties are reset except the exclusions defined for `all`.
	All,
}

pub trait DeclarationMetadata: Sized {
	/// Returns the initial value of this property, as a string
	fn initial() -> &'static str;

	/// Determines if this style value inherits from parent rules
	fn inherits() -> Inherits {
		// Most properties do not inherit, so this is a sensible default
		Inherits::False
	}

	/// Determines what types of frames this rule applies to
	fn applies_to() -> AppliesTo {
		AppliesTo::none()
	}

	/// Determines how this style value resolves percentages, if they are allowed as values
	fn percentages() -> Percentages {
		Percentages::None
	}

	/// Returns how this style value animates
	fn animation_type() -> AnimationType {
		// Most properties do not animate, so this is a sensible default
		AnimationType::None
	}

	/// Determines if this style value is a "shorthand" value, meaning it is comprised of other "longhand" style values.
	fn is_shorthand() -> bool {
		false
	}

	/// Determines if this style value is a "longhand" value, meaning a "shorthand" style value exists that could also
	/// express this.
	fn is_longhand() -> bool {
		Self::shorthand_group() == CssAtomSet::_None
	}

	/// Returns all transitive longhands for a shorthand property.
	/// For nested shorthands (e.g., `border-width`), this recursively expands to include
	/// all nested longhands (e.g., `border-top-width`, `border-left-width`, etc.).
	fn longhands() -> Option<&'static [CssAtomSet]> {
		None
	}

	/// Returns the declaration ID of the shorthand that this property is part of.
	/// If this is not a longhand then it will be `CssAtomSet::_None`.
	fn shorthand_group() -> CssAtomSet {
		CssAtomSet::_None
	}

	/// Returns how this property may reset others, if this is a shorthand property.
	fn shorthand_reset() -> ShorthandReset {
		ShorthandReset::Properties(&[])
	}

	/// Returns shorthands that will reset this property.
	fn reset_by_shorthands() -> &'static [CssAtomSet] {
		&[]
	}

	/// Returns which CSS specification(s) this property belongs to.
	/// This allows tracking which CSS modules are used in a stylesheet.
	fn property_group() -> PropertyGroup {
		PropertyGroup::none()
	}

	/// Returns how the computed value is calculated from the specified value.
	fn computed_value_type() -> ComputedValueType {
		ComputedValueType::Unknown
	}

	/// Returns the canonical order for serialization (e.g., "per grammar", "unique").
	/// Returns None if not specified or not applicable.
	fn canonical_order() -> Option<&'static str> {
		None
	}

	/// Returns the logical property group this property belongs to (e.g., "Margin", "Border").
	/// This groups related logical/physical properties together.
	/// Returns None if this is not part of a logical property group.
	fn logical_property_group() -> Option<CssAtomSet> {
		None
	}

	/// Returns which side(s) of the box this property applies to.
	/// For example, `margin-top` returns BoxSide::Top, while `margin` returns all sides.
	/// Returns BoxSide::none() if the property doesn't apply to a specific side.
	fn box_side() -> BoxSide {
		BoxSide::none()
	}

	/// Returns which portion(s) of the box model this property affects.
	/// For example, `margin-top` returns BoxPortion::Margin, `border-width` returns BoxPortion::Border.
	/// Returns BoxPortion::none() if the property doesn't affect the box model.
	fn box_portion() -> BoxPortion {
		BoxPortion::none()
	}

	/// Returns how unitless zero resolves for this property.
	///
	/// For properties that accept both `<number>` and `<length>`, unitless zero
	/// may resolve to a number rather than a length. This affects whether the
	/// minifier can safely reduce `0px` to `0`.
	///
	/// Examples where unitless zero resolves to Number (NOT safe to reduce):
	/// - `line-height: 0` means 0x font-size multiplier
	/// - `tab-size: 0` means 0 tab characters
	/// - `border-image-outset: 0` means 0x border-width
	fn unitless_zero_resolves() -> UnitlessZeroResolves {
		// Default: most properties accept unitless zero as length
		UnitlessZeroResolves::Length
	}
}

#[cfg(test)]
mod test {
	use crate::*;

	#[test]
	fn test_box_side_count() {
		assert_eq!(BoxSide::Top.num_sides(false), 1);
		assert_eq!((BoxSide::Top | BoxSide::Right).num_sides(false), 2);
		assert_eq!((BoxSide::Top | BoxSide::Right | BoxSide::Bottom).num_sides(false), 3);
		assert_eq!((BoxSide::Top | BoxSide::Right | BoxSide::Bottom | BoxSide::Left).num_sides(false), 4);
		assert_eq!((BoxSide::Top | BoxSide::Right | BoxSide::Bottom | BoxSide::Left).num_sides(true), 0);

		assert_eq!(BoxSide::all_bits().num_sides(false), 4);
		assert_eq!(BoxSide::all_bits().num_sides(true), 4);

		assert_eq!(BoxSide::BlockStart.num_sides(true), 1);
		assert_eq!((BoxSide::BlockStart | BoxSide::BlockEnd).num_sides(true), 2);
		assert_eq!((BoxSide::BlockStart | BoxSide::BlockEnd | BoxSide::InlineStart).num_sides(true), 3);
		assert_eq!(
			(BoxSide::BlockStart | BoxSide::BlockEnd | BoxSide::InlineStart | BoxSide::InlineEnd).num_sides(true),
			4
		);
		assert_eq!(
			(BoxSide::BlockStart | BoxSide::BlockEnd | BoxSide::InlineStart | BoxSide::InlineEnd).num_sides(false),
			0
		);
	}
}