Skip to content

Commit

Permalink
css: preserve subclass selector range in ast
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Aug 6, 2023
1 parent 652da8f commit 6108301
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 34 deletions.
6 changes: 3 additions & 3 deletions internal/css_ast/css_ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -799,7 +799,7 @@ func (sel CompoundSelector) FirstLoc() logger.Loc {
if sel.TypeSelector != nil {
firstLoc = ast.MakeIndex32(uint32(sel.TypeSelector.Range().Loc.Start))
} else if len(sel.SubclassSelectors) > 0 {
firstLoc = ast.MakeIndex32(uint32(sel.SubclassSelectors[0].Loc.Start))
firstLoc = ast.MakeIndex32(uint32(sel.SubclassSelectors[0].Range.Loc.Start))
}
if firstLoc.IsValid() && (!sel.NestingSelectorLoc.IsValid() || firstLoc.GetIndex() < sel.NestingSelectorLoc.GetIndex()) {
return logger.Loc{Start: int32(firstLoc.GetIndex())}
Expand Down Expand Up @@ -868,8 +868,8 @@ func (a NamespacedName) Equal(b NamespacedName) bool {
}

type SubclassSelector struct {
Data SS
Loc logger.Loc
Data SS
Range logger.Range
}

type SS interface {
Expand Down
10 changes: 5 additions & 5 deletions internal/css_parser/css_nesting.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ func (p *parser) lowerNestingInRule(rule css_ast.Rule, results []css_ast.Rule) [
return css_ast.ComplexSelector{
Selectors: []css_ast.CompoundSelector{{
SubclassSelectors: []css_ast.SubclassSelector{{
Loc: loc,
Data: &css_ast.SSPseudoClass{Name: "scope"},
Range: logger.Range{Loc: loc},
Data: &css_ast.SSPseudoClass{Name: "scope"},
}},
}},
}
Expand Down Expand Up @@ -377,7 +377,7 @@ func (p *parser) substituteAmpersandsInCompoundSelector(
p.reportNestingWithGeneratedPseudoClassIs(nestingSelectorLoc)
single = css_ast.CompoundSelector{
SubclassSelectors: []css_ast.SubclassSelector{{
Loc: nestingSelectorLoc,
Range: logger.Range{Loc: nestingSelectorLoc},
Data: &css_ast.SSPseudoClassWithSelectorList{
Kind: css_ast.PseudoClassIs,
Selectors: []css_ast.ComplexSelector{replacement.CloneWithoutLeadingCombinator()},
Expand All @@ -393,7 +393,7 @@ func (p *parser) substituteAmpersandsInCompoundSelector(
if sel.TypeSelector != nil {
p.reportNestingWithGeneratedPseudoClassIs(nestingSelectorLoc)
subclassSelectorPrefix = append(subclassSelectorPrefix, css_ast.SubclassSelector{
Loc: sel.TypeSelector.Range().Loc,
Range: sel.TypeSelector.Range(),
Data: &css_ast.SSPseudoClassWithSelectorList{
Kind: css_ast.PseudoClassIs,
Selectors: []css_ast.ComplexSelector{{Selectors: []css_ast.CompoundSelector{{TypeSelector: sel.TypeSelector}}}},
Expand Down Expand Up @@ -454,7 +454,7 @@ func (p *parser) multipleComplexSelectorsToSingleComplexSelector(selectors []css
Selectors: []css_ast.CompoundSelector{{
Combinator: leadingCombinator,
SubclassSelectors: []css_ast.SubclassSelector{{
Loc: loc,
Range: logger.Range{Loc: loc},
Data: &css_ast.SSPseudoClassWithSelectorList{
Kind: css_ast.PseudoClassIs,
Selectors: clones,
Expand Down
71 changes: 46 additions & 25 deletions internal/css_parser/css_parser_selector.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ func mergeCompoundSelectors(target *css_ast.CompoundSelector, source css_ast.Com
//
// But that just seems so obviously wrong that I'm not going to do that.
target.SubclassSelectors = append(target.SubclassSelectors, css_ast.SubclassSelector{
Loc: source.TypeSelector.Range().Loc,
Range: source.TypeSelector.Range(),
Data: &css_ast.SSPseudoClassWithSelectorList{
Kind: css_ast.PseudoClassIs,
Selectors: []css_ast.ComplexSelector{{Selectors: []css_ast.CompoundSelector{{TypeSelector: source.TypeSelector}}}},
Expand Down Expand Up @@ -370,7 +370,7 @@ subclassSelectors:
nameLoc := logger.Loc{Start: subclassToken.Range.Loc.Start + 1}
name := p.decoded()
sel.SubclassSelectors = append(sel.SubclassSelectors, css_ast.SubclassSelector{
Loc: subclassToken.Range.Loc,
Range: subclassToken.Range,
Data: &css_ast.SSHash{
Name: p.symbolForName(nameLoc, name),
},
Expand All @@ -379,26 +379,26 @@ subclassSelectors:

case css_lexer.TDelimDot:
p.advance()
nameLoc := p.current().Range.Loc
nameRange := p.current().Range
name := p.decoded()
sel.SubclassSelectors = append(sel.SubclassSelectors, css_ast.SubclassSelector{
Loc: subclassToken.Range.Loc,
Range: logger.Range{Loc: subclassToken.Range.Loc, Len: nameRange.End() - subclassToken.Range.Loc.Start},
Data: &css_ast.SSClass{
Name: p.symbolForName(nameLoc, name),
Name: p.symbolForName(nameRange.Loc, name),
},
})
if !p.expect(css_lexer.TIdent) {
return
}

case css_lexer.TOpenBracket:
attr, good := p.parseAttributeSelector()
if !good {
attr, r := p.parseAttributeSelector()
if r.Len == 0 {
return
}
sel.SubclassSelectors = append(sel.SubclassSelectors, css_ast.SubclassSelector{
Loc: subclassToken.Range.Loc,
Data: &attr,
Range: r,
Data: &attr,
})

case css_lexer.TColon:
Expand All @@ -410,7 +410,7 @@ subclassSelectors:
if isElement {
p.advance()
}
pseudo := p.parsePseudoClassSelector(isElement)
pseudo, r := p.parsePseudoClassSelector(firstColonLoc, isElement)

// https://www.w3.org/TR/selectors-4/#single-colon-pseudos
// The four Level 2 pseudo-elements (::before, ::after, ::first-line,
Expand All @@ -427,16 +427,17 @@ subclassSelectors:
}

sel.SubclassSelectors = append(sel.SubclassSelectors, css_ast.SubclassSelector{
Loc: firstColonLoc,
Data: pseudo,
Range: r,
Data: pseudo,
})
}
break subclassSelectors
}

pseudo, r := p.parsePseudoClassSelector(subclassToken.Range.Loc, false)
sel.SubclassSelectors = append(sel.SubclassSelectors, css_ast.SubclassSelector{
Loc: subclassToken.Range.Loc,
Data: p.parsePseudoClassSelector(false),
Range: r,
Data: pseudo,
})

case css_lexer.TDelimAmpersand:
Expand Down Expand Up @@ -500,7 +501,7 @@ subclassSelectors:
return
}

func (p *parser) parseAttributeSelector() (attr css_ast.SSAttribute, ok bool) {
func (p *parser) parseAttributeSelector() (attr css_ast.SSAttribute, r logger.Range) {
matchingLoc := p.current().Range.Loc
p.advance()

Expand Down Expand Up @@ -589,12 +590,15 @@ func (p *parser) parseAttributeSelector() (attr css_ast.SSAttribute, ok bool) {
}
}

p.expectWithMatchingLoc(css_lexer.TCloseBracket, matchingLoc)
ok = true
closeRange := p.current().Range
if !p.expectWithMatchingLoc(css_lexer.TCloseBracket, matchingLoc) {
closeRange.Len = 0
}
r = logger.Range{Loc: matchingLoc, Len: closeRange.End() - matchingLoc.Start}
return
}

func (p *parser) parsePseudoClassSelector(isElement bool) css_ast.SS {
func (p *parser) parsePseudoClassSelector(loc logger.Loc, isElement bool) (css_ast.SS, logger.Range) {
p.advance()

if p.peek(css_lexer.TFunction) {
Expand Down Expand Up @@ -667,8 +671,13 @@ func (p *parser) parsePseudoClassSelector(isElement bool) css_ast.SS {
}

// Match the closing ")"
if ok && p.expectWithMatchingLoc(css_lexer.TCloseParen, matchingLoc) {
return &css_ast.SSPseudoClassWithSelectorList{Kind: kind, Selectors: selectors, Index: index}
if ok {
closeRange := p.current().Range
if !p.expectWithMatchingLoc(css_lexer.TCloseParen, matchingLoc) {
closeRange.Len = 0
}
return &css_ast.SSPseudoClassWithSelectorList{Kind: kind, Selectors: selectors, Index: index},
logger.Range{Loc: loc, Len: closeRange.End() - loc.Start}
}
}
} else {
Expand All @@ -685,19 +694,29 @@ func (p *parser) parsePseudoClassSelector(isElement bool) css_ast.SS {
p.makeLocalSymbols = oldLocal

// Match the closing ")"
if ok && p.expectWithMatchingLoc(css_lexer.TCloseParen, matchingLoc) {
return &css_ast.SSPseudoClassWithSelectorList{Kind: kind, Selectors: selectors}
if ok {
closeRange := p.current().Range
if !p.expectWithMatchingLoc(css_lexer.TCloseParen, matchingLoc) {
closeRange.Len = 0
}
return &css_ast.SSPseudoClassWithSelectorList{Kind: kind, Selectors: selectors},
logger.Range{Loc: loc, Len: closeRange.End() - loc.Start}
}
}
p.index = old
}
}

args := p.convertTokens(p.parseAnyValue())
p.expectWithMatchingLoc(css_lexer.TCloseParen, matchingLoc)
return &css_ast.SSPseudoClass{IsElement: isElement, Name: text, Args: args}
closeRange := p.current().Range
if !p.expectWithMatchingLoc(css_lexer.TCloseParen, matchingLoc) {
closeRange.Len = 0
}
return &css_ast.SSPseudoClass{IsElement: isElement, Name: text, Args: args},
logger.Range{Loc: loc, Len: closeRange.End() - loc.Start}
}

nameRange := p.current().Range
name := p.decoded()
sel := css_ast.SSPseudoClass{IsElement: isElement}
if p.expect(css_lexer.TIdent) {
Expand All @@ -713,8 +732,10 @@ func (p *parser) parsePseudoClassSelector(isElement bool) css_ast.SS {
p.makeLocalSymbols = false
}
}
} else {
nameRange.Len = 0
}
return &sel
return &sel, logger.Range{Loc: loc, Len: nameRange.End() - loc.Start}
}

func (p *parser) parseAnyValue() []css_lexer.Token {
Expand Down
2 changes: 1 addition & 1 deletion internal/css_printer/css_printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ func (p *printer) printCompoundSelector(sel css_ast.CompoundSelector, isFirst bo
}

if p.options.AddSourceMappings {
p.builder.AddSourceMapping(ss.Loc, "", p.css)
p.builder.AddSourceMapping(ss.Range.Loc, "", p.css)
}

switch s := ss.Data.(type) {
Expand Down

0 comments on commit 6108301

Please sign in to comment.