-
-
Notifications
You must be signed in to change notification settings - Fork 475
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(css_formatter): Formatting for border
property
#1453
Conversation
✅ Deploy Preview for biomejs canceled.
|
Parser conformance results onjs/262
jsx/babel
symbols/microsoft
ts/babel
ts/microsoft
|
CodSpeed Performance ReportMerging #1453 will improve performances by 9.2%Comparing Summary
Benchmarks breakdown
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the very detailed docs; they helped a lot in understanding the idea behind the PR!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's NEAT! Amazing work
Summary
#1285. Continuing on the demonstration of
border
being the first property to be parsed exactly, this is a demonstration of how the property can be formatted` exactly as well.Turns out it gets a little complicated! The primary addition here is the new
FormatPropertyValueFields
struct, which implements all of the logic. Given a list of fields, and optionally a slot map, it takes care of building up theFill
element with all of the values. This is whatwrite_component_value_list
was already doing for the generic versions, but for the new exact versions it needs to be a bit more involved (the generic ones will still use that function as the fallback).When there's no
slot_map
given, the new struct just iterates the fields and adds them as entries to theFill
element. When there is aslot_map
, though, the struct iterates the indices of that map and uses the value at each one as the index to pull from thefields
for that position in the list. It also handles skipping over empty and missing fields from the syntax, preventing empty elements from being formatted into the fill and causing double spaces or line breaks accidentally.The
slot_map
in this case is not the same as the slot_map that gets built when constructing anAstNode
, though! Instead, it's the inverse of that map (i.e., the value at index 0 of the inverted map is the index of the value 0 in the original map). This gives theconcrete_order_slot_map()
, which is implemented on a newAstNodeSlotMap
trait that dynamic nodes implement, and is what gets passed to the formatting struct to use for iteration. More information about how this works can be found in the doc comment forconcrete_order_slot_map
.The
border
formatter uses this new struct to easily implement formatting for the value with unordered fields, like:Notice that it uses
&format_args!
to group the slot map pieces together. This isn't strictly necessary right now, but will probably make things in the future easier to deal with (exactly the reason it's used for things likegroup
andindent
now). Also note that it formats all of the fields of the node, not just the unordered ones. That includes any tokens or other ordered fields as well. All of them must be present in theformat_args!
slice, but the nice thing is that extra formatting can still be applied to each, like wrapping one field with agroup
to preserve flattening/expansion, or indenting one specific field, or anything else.One thing that I would like to enable in with that is added in the doc comment for the struct under
Grouping Fields (Future)
. The idea here would be that you could say that two fields in a node get formatted together, no matter what their original ordering was, or to be able to add additional formatting like grouping, line breaks, indents, or whatever else makes sense for the fields being put together. Right now that doesn't work with the slot_map iterator solution, since all of the fields have to be present (the slice of args and the slot map have to have the same length), and iteration would cause the grouped field to be formatted twice: once when it comes up naturally, and again when it gets formatted as part of the group with another field.I spent quite a while trying to make a clean solution work where the fields were wrapped as an
Option
type and you could insertEmptyFieldSlot
values in the slots where a field was moved away from. Unfortunately, it just doesn't look good at all and would be super verbose, and macros aren't quite powerful enough to make it work efficiently either. Since it's unlikely that we'll even need that behavior for a long time, I figure it's fine to leave out for now.Test Plan
Added a snapshot test for
border
that includes various permutations of all the allowed properties, including switching up their ordering, and the output matches exactly as expected, preserving the order from the input source!