Skip to content

chore(core): allow non-null assertion for specific scenarios only - #2612

Merged
nuke-ellington merged 9 commits into
mainfrom
chore/ban-operator
Aug 17, 2026
Merged

nuke-ellington merged 9 commits into
mainfrom
chore/ban-operator

Conversation

@danielleroux

@danielleroux danielleroux commented Jun 19, 2026 •

Copy link
Copy Markdown
Collaborator

🆕 What is the new behavior?

Enhance eslint config to

🏁 Checklist

A pull request can only be merged if all of these conditions are met (where applicable):

  • 🦮 Accessibility (a11y) features were implemented
  • 🗺️ Internationalization (i18n) - no hard coded strings
  • 📲 Responsiveness - components handle viewport changes and content overflow gracefully
  • 📕 Add or update a Storybook story
  • 📄 Documentation was reviewed/updated siemens/ix-docs
  • 🧪 Unit tests were added/updated and pass (pnpm test)
  • 📸 Visual regression tests were added/updated and pass (Guide)
  • 🧐 Static code analysis passes (pnpm lint)
  • 🏗️ Successful compilation (pnpm build, changes pushed)

👨‍💻 Help & support

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Improved stability when interactive elements, animation data, focus targets, or accessibility references are temporarily unavailable.
    • Enhanced handling of optional form values and dropdown, menu, modal, picker, tooltip, and tree interactions.
    • Improved animation behavior and safer handling of missing elements during component updates and teardown.
  • Tests

    • Strengthened automated coverage with clearer validation for missing elements, measurements, focus states, and accessibility attributes.
  • Chores

    • Updated linting guidance to encourage safer TypeScript patterns and defensive behavior.

@netlify

netlify Bot commented Jun 19, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for ix-storybook ready!

Name Link
🔨 Latest commit 18f274e
🔍 Latest deploy log https://app.netlify.com/projects/ix-storybook/deploys/6a8306aa569d640008c8ccb2
😎 Deploy Preview https://deploy-preview-2612--ix-storybook.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@changeset-bot

changeset-bot Bot commented Jun 19, 2026 •

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 18f274e

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai

coderabbitai Bot commented Jun 19, 2026 •

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: b42d55c3-d9e9-4302-b3ad-ced3ab77b941

📥 Commits

Reviewing files that changed from the base of the PR and between bee7bd8 and c74bc89.

📒 Files selected for processing (2)
  • packages/core/src/components/application-header/test/application-header.ct.ts
  • packages/core/src/components/dropdown/dropdown.tsx

📝 Walkthrough

Walkthrough

Adds ESLint restrictions for non-null and definite-assignment assertions. Updates core components, utilities, input handling, and tests with optional types, explicit null checks, throwing guards, and safer lookup paths.

Changes

Non-null Assertion Elimination

Layer / File(s) Summary
ESLint rule and shared utility hardening
packages/core/eslint.config.cjs, packages/core/src/components/utils/...
Adds assertion restrictions. Shared utilities support nullable traversal, return animation caches, allow a targeted lint exception, and validate host elements.
Component fields and modal access
packages/core/src/components/group/group.tsx, packages/core/src/components/tree/tree.tsx, packages/core/src/components/icon-button/icon-button.tsx, packages/core/src/components/modal-header/modal-header.tsx, packages/core/src/components/modal/modal.tsx
Component fields use optional types. Modal paths handle missing dialog references explicitly.
Component DOM and animation guards
packages/core/src/components/blind/blind.tsx, packages/core/src/components/card-accordion/card-accordion.tsx, packages/core/src/components/dropdown/*, packages/core/src/components/menu/*, packages/core/src/components/tooltip/tooltip.tsx, packages/core/src/components/date-picker/date-picker.tsx, packages/core/src/components/select/select.tsx, packages/core/src/components/chat-input/chat-input.tsx, packages/core/src/components/event-list/event-list.tsx
Component animation, layout, observer, menu, tooltip, date-picker, dropdown, select, and lifecycle paths validate missing references.
Input value and event handling
packages/core/src/components/input/input.util.ts, packages/core/src/components/input/number-input.tsx
Input blur events use EventEmitter<T>. Number input updates support undefined and null values across watcher, lifecycle, blur, and render paths.
Component and utility test validation
packages/core/src/components/*/test/*, packages/core/src/components/*/tests/*, packages/core/src/tests/utils/test/page.ts
Tests validate DOM elements, geometry, identifiers, attachment state, dropdown items, accessibility values, and defined time values before use.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Merge Risk: ⚪ Minimal · up to c74bc

This change is merge-ready after normal checks and review; no actionable merge-blocking risk remains.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 9.09% 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 clearly summarizes the main ESLint change: allowing non-null assertions only in specific scenarios.
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.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/ban-operator

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.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces new ESLint rules to restrict non-null (!) and definite assignment assertions, and updates numerous components and test files to use safer optional chaining, explicit null/undefined checks, or proper error handling instead. Feedback on these changes includes addressing a potential inconsistent state in dropdown.tsx by moving an active class assignment after a dropdown existence check, and removing a redundant duplicate call to updateOptionalFormInternalValue in number-input.tsx.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

@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: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/core/src/components/event-list/event-list.tsx (1)

119-121: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Return after resolving when animations are disabled.

At Line 120, the promise resolves but execution continues, so fade-out logic can still run when animated is false.

Suggested fix
       if (!this.animated) {
         resolve();
+        return;
       }
🤖 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/core/src/components/event-list/event-list.tsx` around lines 119 -
121, In the conditional block that checks `!this.animated` and calls
`resolve()`, add a return statement immediately after the `resolve()` call to
prevent execution from continuing to the fade-out logic. This ensures that when
animations are disabled, the promise resolves and the function exits without
executing any subsequent animation code.
packages/core/src/components/card-accordion/card-accordion.tsx (1)

83-90: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid re-querying with a non-null assertion after the guard.

Line 83 guards existence, but Line 89 performs a fresh querySelector(... )! that can still throw if the node is removed before scrollIntoView. Reuse one local reference for both calls.

Suggested fix
   private scrollExpandedContentIntoView() {
     setTimeout(() => {
-      if (!this.expandedContent) {
+      const expandedContent = this.expandedContent;
+      if (!expandedContent) {
         return;
       }
-      const rect = this.expandedContent.getBoundingClientRect();
+      const rect = expandedContent.getBoundingClientRect();
       if (rect.bottom > window.innerHeight) {
-        this.hostElement
-          .shadowRoot!.querySelector('.expand-content')!
-          .scrollIntoView(false);
+        expandedContent.scrollIntoView(false);
       }
     }, 150);
   }
🤖 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/core/src/components/card-accordion/card-accordion.tsx` around lines
83 - 90, The code guards against this.expandedContent being null on line 83 but
then performs a fresh DOM query with querySelector on line 89 to select the
expand-content element, which can fail if the node is removed between the guard
check and the scrollIntoView call. Instead of re-querying the DOM, directly
reuse the this.expandedContent reference that was already validated in the guard
condition by calling scrollIntoView directly on that reference, eliminating both
the redundant query and the potential race condition.
🤖 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/core/src/components/dropdown/dropdown.tsx`:
- Around line 922-929: The classList.add operation that adds the
`ix-dropdown-submenu-trigger-active` class to the event.detail.activeElement is
being executed before validating that the submenu exists via the
dropdownController.getDropdownById call. Move the classList.add call to after
the null/undefined check for the dropdown variable, so the active class is only
applied to the trigger element when the submenu lookup succeeds and the dropdown
is confirmed to exist.

In `@packages/core/src/components/input/input.util.ts`:
- Around line 243-246: The `ixChange` event has a type mismatch between its
declaration and actual emission behavior. The `ixChange` EventEmitter is
declared as `EventEmitter<number>` in number-input.tsx, but the
`onInputBlurWithChange` method in input.util.ts emits `undefined` when
currentValue is undefined. Update the type declaration of the `ixChange` event
in number-input.tsx from `EventEmitter<number>` to `EventEmitter<number |
undefined>` to match the actual emission behavior where the event can emit
either a number value or undefined.

In `@packages/core/src/components/input/number-input.tsx`:
- Around line 307-313: Remove the duplicate call to
updateOptionalFormInternalValue(parsedValue) in the blur event handler. The
method is being called twice consecutively on lines 307 and 312, with the second
invocation being redundant. Delete the second occurrence of
updateOptionalFormInternalValue(parsedValue) that appears before the
onInputBlurWithChange call to eliminate unnecessary form value updates and
validity checks.

---

Outside diff comments:
In `@packages/core/src/components/card-accordion/card-accordion.tsx`:
- Around line 83-90: The code guards against this.expandedContent being null on
line 83 but then performs a fresh DOM query with querySelector on line 89 to
select the expand-content element, which can fail if the node is removed between
the guard check and the scrollIntoView call. Instead of re-querying the DOM,
directly reuse the this.expandedContent reference that was already validated in
the guard condition by calling scrollIntoView directly on that reference,
eliminating both the redundant query and the potential race condition.

In `@packages/core/src/components/event-list/event-list.tsx`:
- Around line 119-121: In the conditional block that checks `!this.animated` and
calls `resolve()`, add a return statement immediately after the `resolve()` call
to prevent execution from continuing to the fade-out logic. This ensures that
when animations are disabled, the promise resolves and the function exits
without executing any subsequent animation code.
🪄 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: ASSERTIVE

Plan: Pro

Run ID: 4a593e55-3898-45c0-afc2-55fef4f683f3

📥 Commits

Reviewing files that changed from the base of the PR and between 7c34939 and c4c5900.

📒 Files selected for processing (38)
  • packages/core/eslint.config.cjs
  • packages/core/src/components/application-header/test/application-header.ct.ts
  • packages/core/src/components/blind/blind.tsx
  • packages/core/src/components/card-accordion/card-accordion.tsx
  • packages/core/src/components/date-picker/date-picker.tsx
  • packages/core/src/components/dropdown/dropdown-focus.ts
  • packages/core/src/components/dropdown/dropdown.tsx
  • packages/core/src/components/dropdown/test/dropdown-top-layer.ct.ts
  • packages/core/src/components/dropdown/test/dropdown.ct.ts
  • packages/core/src/components/event-list/event-list.tsx
  • packages/core/src/components/field-wrapper/tests/field-wrapper.ct.ts
  • packages/core/src/components/group/group.tsx
  • packages/core/src/components/icon-button/icon-button.tsx
  • packages/core/src/components/input/input.util.ts
  • packages/core/src/components/input/number-input.tsx
  • packages/core/src/components/menu-category/menu-category.tsx
  • packages/core/src/components/menu/menu.tsx
  • packages/core/src/components/modal-header/modal-header.tsx
  • packages/core/src/components/modal/modal.tsx
  • packages/core/src/components/select/select.tsx
  • packages/core/src/components/select/test/select-keyboard.ct.ts
  • packages/core/src/components/split-button/test/split-button.ct.ts
  • packages/core/src/components/tab-set/test/tab-set.ct.ts
  • packages/core/src/components/tabs/test/tabs.ct.ts
  • packages/core/src/components/time-picker/test/time-picker-compute-time.spec.ts
  • packages/core/src/components/time-picker/test/time-picker-constraints.spec.ts
  • packages/core/src/components/time-picker/test/time-picker-range.spec.ts
  • packages/core/src/components/time-picker/test/time-picker.ct.ts
  • packages/core/src/components/time-picker/time-picker.tsx
  • packages/core/src/components/tooltip/test/tooltip.ct.ts
  • packages/core/src/components/tooltip/tooltip.tsx
  • packages/core/src/components/tree/test/tree.ct.ts
  • packages/core/src/components/tree/tree.tsx
  • packages/core/src/components/utils/animation.ts
  • packages/core/src/components/utils/internal/mixins/accessibility/inherit-aria-attributes.mixin.ts
  • packages/core/src/components/utils/lazy-list/lazy.ts
  • packages/core/src/components/utils/shadow-dom.ts
  • packages/core/src/tests/utils/test/page.ts

@sonarqubecloud

Copy link
Copy Markdown

@nuke-ellington
nuke-ellington requested a review from a team as a code owner August 11, 2026 13:12
@nuke-ellington
nuke-ellington requested a review from lzeiml August 11, 2026 13:12
@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@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: 4

🤖 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/core/src/components/application-header/test/application-header.ct.ts`:
- Around line 55-57: Update both `#mount` lookup sites in the application-header
test to validate that document.querySelector('`#mount`') returns an element before
appending header. Remove optional chaining and throw an explicit error when the
required mount element is missing, preserving the append behavior when it
exists.

In `@packages/core/src/components/dropdown/test/dropdown-top-layer.ct.ts`:
- Around line 195-199: Add a makeAxeBuilder() accessibility scan and a
hydration/render assertion to the dropdown component tests in the existing test
suite. Reuse the established component setup and selectors, ensuring the
accessibility check runs against the rendered dropdown and the render test
verifies successful hydration without changing the current positioning
assertions.

In `@packages/core/src/components/utils/lazy-list/lazy.ts`:
- Line 1: Remove the file-wide no-restricted-syntax disable in lazy.ts and limit
the ESLint exception to the specific assertion that requires it by adding an
eslint-disable-next-line comment immediately before that assertion; otherwise
narrow or remove the assertion so no exception is needed.
- Line 1: Add the repository-standard SPDX license header at the very beginning
of lazy.ts, before the existing no-restricted-syntax ESLint directive, without
changing the directive or other file content.
🪄 Autofix

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: ASSERTIVE

Plan: Pro Plus

Run ID: 8c57380c-700c-4799-be4d-94500dcc0404

📥 Commits

Reviewing files that changed from the base of the PR and between 6479f9d and 821f57e.

📒 Files selected for processing (42)
  • packages/core/eslint.config.cjs
  • packages/core/src/components/application-header/test/application-header.ct.ts
  • packages/core/src/components/badge/test/badge.page.ts
  • packages/core/src/components/blind/blind.tsx
  • packages/core/src/components/card-accordion/card-accordion.tsx
  • packages/core/src/components/chat-input/chat-input.tsx
  • packages/core/src/components/chip/test/chip.ct.ts
  • packages/core/src/components/date-picker/date-picker.tsx
  • packages/core/src/components/dropdown/dropdown-focus.ts
  • packages/core/src/components/dropdown/dropdown.tsx
  • packages/core/src/components/dropdown/test/dropdown-top-layer.ct.ts
  • packages/core/src/components/dropdown/test/dropdown.ct.ts
  • packages/core/src/components/event-list/event-list.tsx
  • packages/core/src/components/field-wrapper/tests/field-wrapper.ct.ts
  • packages/core/src/components/group/group.tsx
  • packages/core/src/components/icon-button/icon-button.tsx
  • packages/core/src/components/input/input.util.ts
  • packages/core/src/components/input/number-input.tsx
  • packages/core/src/components/menu-category/menu-category.tsx
  • packages/core/src/components/menu/menu.tsx
  • packages/core/src/components/modal-header/modal-header.tsx
  • packages/core/src/components/modal/modal.tsx
  • packages/core/src/components/popover/test/popover.page.ts
  • packages/core/src/components/select/select.tsx
  • packages/core/src/components/select/test/select-keyboard.ct.ts
  • packages/core/src/components/split-button/test/split-button.ct.ts
  • packages/core/src/components/tab-set/test/tab-set.ct.ts
  • packages/core/src/components/tabs/test/tabs.ct.ts
  • packages/core/src/components/time-picker/test/time-picker-compute-time.spec.ts
  • packages/core/src/components/time-picker/test/time-picker-constraints.spec.ts
  • packages/core/src/components/time-picker/test/time-picker-range.spec.ts
  • packages/core/src/components/time-picker/test/time-picker.ct.ts
  • packages/core/src/components/time-picker/time-picker.tsx
  • packages/core/src/components/tooltip/test/tooltip.ct.ts
  • packages/core/src/components/tooltip/tooltip.tsx
  • packages/core/src/components/tree/test/tree.ct.ts
  • packages/core/src/components/tree/tree.tsx
  • packages/core/src/components/utils/animation.ts
  • packages/core/src/components/utils/internal/mixins/accessibility/inherit-aria-attributes.mixin.ts
  • packages/core/src/components/utils/lazy-list/lazy.ts
  • packages/core/src/components/utils/shadow-dom.ts
  • packages/core/src/tests/utils/test/page.ts

nuke-ellington
nuke-ellington previously approved these changes Aug 17, 2026
@sonarqubecloud

Copy link
Copy Markdown

@nuke-ellington
nuke-ellington enabled auto-merge (squash) August 17, 2026 13:26
@nuke-ellington
nuke-ellington merged commit 05afbdb into main Aug 17, 2026
19 checks passed
@nuke-ellington
nuke-ellington deleted the chore/ban-operator branch August 17, 2026 13:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants