Skip to content

fix(compiler): support complex selectors in :nth-child()#65010

Merged
AndrewKushnir merged 1 commit intoangular:mainfrom
mattrbeck:i64913
Nov 11, 2025
Merged

fix(compiler): support complex selectors in :nth-child()#65010
AndrewKushnir merged 1 commit intoangular:mainfrom
mattrbeck:i64913

Conversation

@mattrbeck
Copy link
Copy Markdown
Member

:nth-child() (and its siblings) support complex expressions, e.g. :nth-child(2n of :is(.foo, .bar)). Previously we'd choke because of the :is(). Now, we reuse the _parenSuffix subexpression to match nested parentheses the same way we do for :host() and :host-context(). Note that we only support 3 levels of nesting, so a selector like :nth-child(n of :is(:has(:not(.foo)))) will still break.

I'll say yet again that we really should add a proper parser so we stop getting bug reports like this :)

Fixes #64913

:nth-child() (and its siblings) support complex expressions, e.g.
`:nth-child(2n of :is(.foo, .bar))`. Previously we'd choke because of
the `:is()`. Now, we reuse the `_parenSuffix` subexpression to match
nested parentheses the same way we do for :host() and :host-context().
Note that we only support 3 levels of nesting, so a selector like
`:nth-child(n of :is(:has(:not(.foo))))` will still break.

I'll say yet again that we really should add a proper parser so we stop
getting bug reports like this :)

Fixes angular#64913
@angular-robot angular-robot bot added the area: compiler Issues related to `ngc`, Angular's template compiler label Nov 7, 2025
@ngbot ngbot bot added this to the Backlog milestone Nov 7, 2025
// Matches content with at most TWO levels of nesting, e.g., "a(b(c)d)e"
const _level2Parens = String.raw`(?:\(${_level1Parens}\)|${_noParens})+?`;
const _parenSuffix = String.raw`(?:\((${_level2Parens})\))`;
const nthRegex = new RegExp(String.raw`(:nth-[-\w]+)` + _parenSuffix, 'g');
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regexes with the g flag have a state. Is that a concern for this case?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's a concern. You may know more or be more familiar, though. The existing expression also uses the global flag, so I believe this produces the same results. (I know regexp literals are compiled on script load, but IIRC otherwise they behave identically to instantiating a RegExp?)

From my read of the spec and docs on MDN, it looks like while using the g flag makes the RegExp track its lastIndex for the match. This is relevant for the RegExp.prototype.exec() method, which it appears String.prototype.replace() calls repeatedly. Since this should replace all occurrences in the string, lastIndex should be reset to 0 by the end (MDN description).

The statefulness seems like more of a concern if you exec against one string then exec against another string without resetting lastIndex.

@mattrbeck mattrbeck added action: merge The PR is ready for merge by the caretaker target: patch This PR is targeted for the next patch release labels Nov 10, 2025
@AndrewKushnir AndrewKushnir added action: presubmit The PR is in need of a google3 presubmit action: global presubmit The PR is in need of a google3 global presubmit and removed action: presubmit The PR is in need of a google3 presubmit labels Nov 10, 2025
@mattrbeck
Copy link
Copy Markdown
Member Author

@mattrbeck mattrbeck removed the action: global presubmit The PR is in need of a google3 global presubmit label Nov 11, 2025
@AndrewKushnir AndrewKushnir removed their request for review November 11, 2025 20:47
@AndrewKushnir AndrewKushnir merged commit 24cfd5a into angular:main Nov 11, 2025
27 checks passed
@AndrewKushnir
Copy link
Copy Markdown
Contributor

This PR was merged into the repository. The changes were merged into the following branches:

@angular-automatic-lock-bot
Copy link
Copy Markdown

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Dec 12, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

action: merge The PR is ready for merge by the caretaker area: compiler Issues related to `ngc`, Angular's template compiler target: patch This PR is targeted for the next patch release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

nth-child with of adds unexpected [_ngcontent] attr to selector

3 participants