Skip to content

[TASK] Use delegation for DeclarationBlock -> RuleSet #1194

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

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

JakeQZ
Copy link
Collaborator

@JakeQZ JakeQZ commented Mar 19, 2025

... rather than inheritance.

This will allow DeclarationBlock to instead extend CSSBlockList in order to support
CSS nesting.

This is a slightly-breaking change, since now CSSBlockList::getAllRuleSets() will include the RuleSet property of the DeclarationBlock instead of the DeclarationBlock itself.

Part of #1170.

@JakeQZ JakeQZ added cleanup css4 Relating to features introduced in CSS4 labels Mar 19, 2025
@JakeQZ JakeQZ self-assigned this Mar 19, 2025
@JakeQZ JakeQZ marked this pull request as draft March 19, 2025 00:56
@coveralls
Copy link

coveralls commented Mar 19, 2025

Coverage Status

coverage: 59.595% (-0.2%) from 59.816%
when pulling e666f5e on task/declarationblock-delegate-ruleset
into b2028eb on main.

@JakeQZ JakeQZ force-pushed the task/declarationblock-delegate-ruleset branch from 7800603 to 73956e9 Compare March 19, 2025 02:06
@JakeQZ JakeQZ added css3 and removed css4 Relating to features introduced in CSS4 labels Mar 20, 2025
@JakeQZ JakeQZ force-pushed the task/declarationblock-delegate-ruleset branch 5 times, most recently from c1c27a9 to 3a278e0 Compare April 2, 2025 00:31
@JakeQZ JakeQZ force-pushed the task/declarationblock-delegate-ruleset branch 5 times, most recently from c935f2c to 1f908cf Compare April 14, 2025 15:25
@JakeQZ
Copy link
Collaborator Author

JakeQZ commented Apr 15, 2025

Would be good to resolve #1247 before moving on with this.

@JakeQZ JakeQZ force-pushed the task/declarationblock-delegate-ruleset branch from 1f908cf to 1ce18b7 Compare May 6, 2025 17:40
@JakeQZ
Copy link
Collaborator Author

JakeQZ commented May 8, 2025

This is almost ready for review, but some tests need to be added. Before doing so, I'd appreciate a pre-review from you: @sabberworm, @oliverklee.

I'm not keen on the having the various chaining methods in DeclarationBlock, but to avoid breaking changes they are necessary. A trait can be used for testing them in the same way as their counterparts in RuleSet.

For DeclarationBlock to contain nested rules, it needs to extend CSSBlockList. RuleSet cannot be a trait; it needs to be a fully-fledged type for methods like getAllRuleSets().

This is the only realistic way forward I see for now, in an 'Agile' sense, which can deliver what is required now, without wholescale refactoring or breaking changes.

Copy link
Collaborator

@oliverklee oliverklee left a comment

Choose a reason for hiding this comment

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

I like this approach!

@oliverklee
Copy link
Collaborator

Maybe as another spin-off PR (or prepatch), we can introduce the interface and have one class implement it.

@JakeQZ
Copy link
Collaborator Author

JakeQZ commented Jul 18, 2025

I tried undoing lastest merge, but it's still a mess. I can't even get back to where I was now. Will take some time redoing.

In my experience, when I had a PR from which I spun off some pre-PRs, I also sometimes had nasty merge conflicts when rebasing. In those cases, it made things a lot easier if I squashed the existing commits in the PR branch before rebasing.

I think I have somehow managed to rebase without including any changes from main. So now the diffs are showing that all the changes from main are being reverted. I did git rebase --abort when I got in a muddle.

If I could somehow reset the branch to the state it was in immediately after the commit "Reorder construction", then squashing may be possible, but I'm not sure how to do that.

@oliverklee
Copy link
Collaborator

If I could somehow reset the branch to the state it was in immediately after the commit "Reorder construction", then squashing may be possible, but I'm not sure how to do that.

git reflog allows you to list all recent commits and which actions lead to them, including rebases, branch switches etc. So this might be helpful. (It has saved my work a couple of times.)

@JakeQZ JakeQZ force-pushed the task/declarationblock-delegate-ruleset branch 3 times, most recently from 184f865 to 34c8708 Compare July 19, 2025 00:22
@JakeQZ
Copy link
Collaborator Author

JakeQZ commented Jul 19, 2025

If I could somehow reset the branch to the state it was in immediately after the commit "Reorder construction"

git reset -hard {SHA-of-last-commit-before-attempted-rebase}

... undid the failed rebase/merge. I think when I tried merging instead (via GitHub), that moved the 'common ancestor' point, but when I reverted the merge, it was not moved back.

then squashing may be possible, but I'm not sure how to do that.

git reset -soft {SHA-of-first-branch-commit}
git commit --amend

... did the squashing.

In my experience, when I had a PR from which I spun off some pre-PRs, I also sometimes had nasty merge conflicts when rebasing. In those cases, it made things a lot easier if I squashed the existing commits in the PR branch before rebasing.

That helped immensely; thanks. Instead of (presumably) 9 rounds of conflict resolution, including for files with no overall conflict, there was just one round, for the two files that actually had conflicts. (I'm used to Perforce, which does the merge all at once, and also has a visual editor for 3-way merging. Keeping a cool head also helps ;))

Rebase now done !) Thanks <3

@oliverklee
Copy link
Collaborator

I'm used to Perforce, which does the merge all at once, and also has a visual editor for 3-way merging.

I use PhpStorm as my IDE, and IIRC it also have a nice 3-way-merge UI. (Disclaimer: I don't use UIs for git stuff and hence can only report what I hear and see from other people.)

oliverklee pushed a commit that referenced this pull request Jul 21, 2025
... adding internal `render` method.

Precursor to #1194.
@JakeQZ JakeQZ force-pushed the task/declarationblock-delegate-ruleset branch 2 times, most recently from 76f0b5f to 6d615c9 Compare July 21, 2025 14:06
JakeQZ added a commit that referenced this pull request Jul 21, 2025
... instead of `getAllRuleSets`.

This avoids testing if `RuleSet`s are `DeclarationBlock`s, and will be needed
for #1194.
oliverklee pushed a commit that referenced this pull request Jul 21, 2025
... instead of `getAllRuleSets`.

This avoids testing if `RuleSet`s are `DeclarationBlock`s, and will be needed
for #1194.
@JakeQZ JakeQZ force-pushed the task/declarationblock-delegate-ruleset branch from 6d615c9 to 38c7836 Compare July 21, 2025 16:55
@JakeQZ
Copy link
Collaborator Author

JakeQZ commented Jul 21, 2025

I think this is now ready for a final review.

@JakeQZ JakeQZ marked this pull request as ready for review July 21, 2025 16:56
@JakeQZ JakeQZ requested a review from oliverklee July 21, 2025 16:56
@@ -107,7 +132,9 @@ public static function parse(ParserState $parserState, ?CSSList $list = null): ?
}
}
$result->setComments($comments);
RuleSet::parseRuleSet($parserState, $result);

RuleSet::parseRuleSet($parserState, $result->ruleSet);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Even though this technically works, I'd find using the getter getRuleSet() more clean here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

parseRuleSet() takes the RuleSet argument by reference, in order to fill it in with the the parsed Rules, so the class property needs to be passed.

Copy link
Collaborator

@oliverklee oliverklee Jul 24, 2025

Choose a reason for hiding this comment

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

As far as I understand it, getRuleSet() returns the instance, not a clone of it.

(PHP by default passes object kind-of-by-reference. I explained this on page 17 of my diploma thesis back then.)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

You're right. I was thinking of arrays (even though I knew it was an object - my thinking cap must have been on back-to-front). Thanks for the thesis link; I will give it a read some time...

*/
public function __construct(?int $lineNumber = null)
{
$this->ruleSet = new RuleSet($lineNumber);
Copy link
Collaborator

Choose a reason for hiding this comment

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

We also need unit tests that the created RuleSet uses has line number from the DeclarationBlock constructor, and that it defaults to null.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We don't appear to have an existing test that RuleSet applies the line number provided, so perhaps another pre-PR is needed...

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

#1348 for RuleSet. Once that is approved, I can address this along similar lines.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Have added tests to cover:

  1. getLineNumber() returning line number passed to DeclarationBlock constructor (or null by default);
  2. getRuleSet()->getLineNumber() returning line number passed to DeclarationBlock constructor (or null by default);

But perhaps 1 could be covered by another pre-PR...

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

#1350 for item 1.

@@ -175,6 +202,73 @@ public function getSelectors(): array
return $this->selectors;
}

public function getRuleSet(): RuleSet
Copy link
Collaborator

Choose a reason for hiding this comment

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

We should have unit tests for the added methods.

Copy link
Collaborator Author

@JakeQZ JakeQZ Jul 22, 2025

Choose a reason for hiding this comment

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

getRuleSet() has some tests added for it. The methods that chain on to the equivalent RuleSet method have tests added via the RuleContainerTest trait (which is also used in the test case for RuleSet). So I think all the added methods have test coverage.

@JakeQZ JakeQZ force-pushed the task/declarationblock-delegate-ruleset branch from 38c7836 to d6c7420 Compare July 24, 2025 15:45
JakeQZ added 3 commits July 24, 2025 19:24
... rather than inheritance.

This will allow `DeclarationBlock` to instead extend `CSSBlockList` in order
to support
[CSS nesting](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_nesting).

This is a slightly-breaking change, since now `CSSBlockList::getAllRuleSets()`
will include the `RuleSet` property of the `DeclarationBlock` instead of the
`DeclarationBlock` itself.

Part of #1170.
@JakeQZ JakeQZ force-pushed the task/declarationblock-delegate-ruleset branch from cec8497 to 85dc980 Compare July 24, 2025 18:26
@JakeQZ
Copy link
Collaborator Author

JakeQZ commented Jul 24, 2025

This issues from the last review should all now be resolved.

@JakeQZ JakeQZ requested a review from oliverklee July 24, 2025 18:32
@JakeQZ JakeQZ force-pushed the task/declarationblock-delegate-ruleset branch from 9c1c62e to e666f5e Compare July 24, 2025 21:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants