Skip to content

Feature/inequality operator#4454

Open
Ritvik718 wants to merge 2 commits into
less:masterfrom
Ritvik718:feature/inequality-operator
Open

Feature/inequality operator#4454
Ritvik718 wants to merge 2 commits into
less:masterfrom
Ritvik718:feature/inequality-operator

Conversation

@Ritvik718

@Ritvik718 Ritvik718 commented Jun 15, 2026

Copy link
Copy Markdown

What:

  • Added parsing recognition for the inequality operator (!=) in packages/less/lib/less/parser/parser.js.
  • Implemented evaluation support for the inequality operator in packages/less/lib/less/tree/condition.js:
    • Returns true when comparison results in inequality (-1 or 1).
    • Returns false when comparison results in equality (0).
    • Returns true when comparison is undefined (types are not comparable, meaning they are not equal).
  • Added comprehensive unit tests in packages/test-data/tests-unit/css-guards/css-guards.less and css-guards.css.

Why:
Currently, Less lacks an inequality comparison operator, requiring users to write verbose guard checks like not (@foo = 1) rather than the cleaner and standard @foo != 1. This aligns Less with standard CSS/JS and other CSS preprocessors.

Checklist:

  • Documentation - N/A
  • Added/updated unit tests
  • Code complete

Summary by CodeRabbit

  • New Features

    • Added support for the != (not-equal) operator in guard conditions.
  • Improvements

    • Enhanced benchmark reporting with better compiler detection and error handling.
  • Tests

    • Added comprehensive test coverage for inequality guard operators.

@dosubot dosubot Bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Jun 15, 2026
@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds != as a recognized comparison operator in Less guard conditions by updating the parser's atomicCondition and the Condition.eval() switch logic, with new test fixtures covering all four inequality cases. Separately refactors benchmark-runner.js CLI parsing, compiler discovery, and benchmark execution flow, and changes a template literal to a quoted string in rollup.js.

Changes

!= guard operator support

Layer / File(s) Summary
Parser and eval logic for !=
packages/less/lib/less/parser/parser.js, packages/less/lib/less/tree/condition.js
atomicCondition detects the != token and sets op = '!='; Condition.eval() includes '!=' in the case -1/case 1 operator sets and replaces the hardcoded false default with this.op === '!='.
Guard inequality test fixtures
packages/test-data/tests-unit/css-guards/css-guards.less, packages/test-data/tests-unit/css-guards/css-guards.css
Adds four != guard selectors in the .less source; adds the expected .inequality-test-1 and .inequality-test-3 output rules in the .css fixture.

Benchmark runner refactor and rollup cosmetic fix

Layer / File(s) Summary
Benchmark runner CLI, compiler discovery, and execution
packages/less/benchmark/benchmark-runner.js, packages/less/build/rollup.js
Refactors --key=value parsing loop, adds a clearer missing-file guard, adds default-export interop and render/parse validation during compiler lookup, introduces hrNow(), completed/errors tracking, runOnce/runAll sequential execution with bail-out after 3 errors, and JSON reporting. rollup.js changes a template literal to a single-quoted string in moduleShim().load().

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • less/less.js#4410: Also modifies benchmark-runner.js's --key=value CLI option parsing and forwarding of extra options into less.render.

Poem

🐇 Hop, hop — not equal today!
The parser now knows != is here to stay,
Guards check the difference with logic so neat,
Green for the unequal, red for repeat.
The benchmark runs tidy, the rollup string plain —
A patch full of hops down the fast lane! 🌿

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Feature/inequality operator' clearly and specifically summarizes the main change: adding support for the inequality operator (!=) to the Less language, which is the primary objective across the parser, evaluation logic, and test additions.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/test-data/tests-unit/css-guards/css-guards.less (1)

104-115: ⚡ Quick win

Add one fixture that covers non-comparable inequality.

The new cases validate comparable != paths, but they don’t exercise the non-comparable branch that should still evaluate != as true. Add one guard like when (foo != 1) and assert it emits CSS.

Suggested fixture addition
 .inequality-test-4 when (`@b` != 2) {
   color: red;
 }
+
+.inequality-test-5 when (foo != 1) {
+  color: green;
+}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/test-data/tests-unit/css-guards/css-guards.less` around lines 104 -
115, Add a new test fixture after the existing inequality-test cases that
validates non-comparable inequality evaluation. Create a guard like when(foo !=
1) where foo is an undefined or non-comparable variable, and include a CSS rule
(such as color: green;) that should be emitted when the guard evaluates to true.
This test should demonstrate that the non-comparable branch in the inequality
operator evaluation correctly returns true when comparing incompatible types or
undefined values.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/less/benchmark/benchmark-runner.js`:
- Around line 46-47: The compiler discovery condition at line 46 currently uses
OR logic to accept compilers that have either `render` or `parse`, but the
`runOnce()` function always calls `less.render` at line 93. Change the condition
from `(less.render || less.parse)` to `(less.render && less.parse)` to require
both methods to be present, preventing runtime crashes when a parse-only
compiler is selected.

---

Nitpick comments:
In `@packages/test-data/tests-unit/css-guards/css-guards.less`:
- Around line 104-115: Add a new test fixture after the existing inequality-test
cases that validates non-comparable inequality evaluation. Create a guard like
when(foo != 1) where foo is an undefined or non-comparable variable, and include
a CSS rule (such as color: green;) that should be emitted when the guard
evaluates to true. This test should demonstrate that the non-comparable branch
in the inequality operator evaluation correctly returns true when comparing
incompatible types or undefined values.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 01e6e179-62bd-4278-9565-48b010ac24d4

📥 Commits

Reviewing files that changed from the base of the PR and between 7787557 and a1edc9c.

📒 Files selected for processing (6)
  • packages/less/benchmark/benchmark-runner.js
  • packages/less/build/rollup.js
  • packages/less/lib/less/parser/parser.js
  • packages/less/lib/less/tree/condition.js
  • packages/test-data/tests-unit/css-guards/css-guards.css
  • packages/test-data/tests-unit/css-guards/css-guards.less

Comment on lines +46 to +47
if (less && (less.render || less.parse)) {
lessPath = p;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Require render during compiler discovery to prevent runtime crashes.

At Line 46, discovery currently accepts compilers that only expose parse. But runOnce() always calls less.render (Line 93), so a parse-only module will fail at runtime with TypeError: less.render is not a function.

Proposed fix
-        if (less && (less.render || less.parse)) {
+        if (less && typeof less.render === 'function') {
             lessPath = p;
             break;
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (less && (less.render || less.parse)) {
lessPath = p;
if (less && typeof less.render === 'function') {
lessPath = p;
break;
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/less/benchmark/benchmark-runner.js` around lines 46 - 47, The
compiler discovery condition at line 46 currently uses OR logic to accept
compilers that have either `render` or `parse`, but the `runOnce()` function
always calls `less.render` at line 93. Change the condition from `(less.render
|| less.parse)` to `(less.render && less.parse)` to require both methods to be
present, preventing runtime crashes when a parse-only compiler is selected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant