Skip to content

chore(lint): migrate repo to oxlint and stabilize validation#4075

Merged
Saadnajmi merged 7 commits intomicrosoft:mainfrom
Saadnajmi:chore/oxlint-migration-review
Apr 24, 2026
Merged

chore(lint): migrate repo to oxlint and stabilize validation#4075
Saadnajmi merged 7 commits intomicrosoft:mainfrom
Saadnajmi:chore/oxlint-migration-review

Conversation

@Saadnajmi
Copy link
Copy Markdown
Collaborator

@Saadnajmi Saadnajmi commented Mar 26, 2026

Summary

This PR replaces the repo ESLint-based lint workflow with oxlint, fixes the violations surfaced by that migration, and closes the validation issue that was still breaking the full Lage run.

What changed

1. Migrate the repo from ESLint to oxlint

  • replace package-level eslint.config.js usage with oxlint config entrypoints
  • rename the shared config package to @fluentui-react-native/lint-config-rules
  • update workspace package manifests to use fluentui-scripts lint
  • switch the shared scripts task from eslint to lint
  • add targeted local oxlint overrides where packages need exceptions

2. Fix oxlint violations across the repo

  • replace broad export-all re-exports with explicit exports where required
  • tighten hook dependency lists and callback captures
  • replace ts-ignore with ts-expect-error where the suppression is intentional
  • remove forEach patterns that capture mutable variables
  • fix smaller rule violations across components, deprecated packages, theming, framework, and experimental packages

3. Stabilize full repo validation

  • update Fluent Tester bundling to run platform bundles sequentially
  • rename the root bundle convenience script to bundle:repo
  • avoid the recursive root bundle task that caused the full Lage validation run to exhaust heap
  • align repo docs with the actual supported root commands

Why this is split this way

The commit history is organized to make review easier:

  • chore(lint): migrate repo from eslint to oxlint
  • fix(lint): resolve oxlint violations across packages
  • fix(build): stabilize repo bundle validation

This lets the tooling migration, rule-compliance changes, and validation fix be reviewed independently.

Validation

  • yarn lage build ci-test lint bundle depcheck check-publishing

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Mar 26, 2026

🦋 Changeset detected

Latest commit: 9fad281

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 74 packages
Name Type
@uifabricshared/foundation-composable Patch
@fluentui-react-native/experimental-appearance-additions Patch
@uifabricshared/theming-react-native Patch
@uifabricshared/foundation-settings Patch
@fluentui-react-native/experimental-activity-indicator Patch
@fluentui-react-native/experimental-native-font-metrics Patch
@uifabricshared/foundation-compose Patch
@fluentui-react-native/experimental-native-date-picker Patch
@uifabricshared/foundation-tokens Patch
@fluentui-react-native/themed-stylesheet Patch
@uifabricshared/themed-settings Patch
@fluentui-react-native/contextual-menu Patch
@fluentui-react-native/lint-config-rules Patch
@uifabricshared/theme-registry Patch
@fluentui-react-native/vibrancy-view Patch
@fluentui-react-native/focus-trap-zone Patch
@fluentui-react-native/notification Patch
@uifabricshared/theming-ramp Patch
@fluentui-react-native/experimental-menu-button Patch
@fluentui-react-native/interactive-hooks Patch
@fluentui-react-native/persona-coin Patch
@fluentui-react-native/menu-button Patch
@fluentui-react-native/radio-group Patch
@fluentui-react-native/experimental-checkbox Patch
@fluentui-react-native/dropdown Patch
@fluentui-react-native/experimental-expander Patch
@fluentui-react-native/overflow Patch
@fluentui-react-native/composition Patch
@fluentui-react-native/use-styling Patch
@fluentui-react-native/android-theme Patch
@fluentui-react-native/default-theme Patch
@fluentui-react-native/theming-utils Patch
@fluentui-react-native/focus-zone Patch
@fluentui-react-native/pressable Patch
@fluentui-react-native/separator Patch
@fluentui-react-native/popover Patch
@fluentui-react-native/experimental-shimmer Patch
@fluentui-react-native/spinner Patch
@fluentui-react-native/tooltip Patch
@fluentui-react-native/use-tokens Patch
@fluentui-react-native/theme-tokens Patch
@fluentui-react-native/checkbox Patch
@fluentui-react-native/experimental-avatar Patch
@fluentui-react-native/drawer Patch
@fluentui-react-native/experimental-shadow Patch
@fluentui-react-native/framework Patch
@fluentui-react-native/use-slots Patch
@fluentui-react-native/apple-theme Patch
@fluentui-react-native/theme-types Patch
@fluentui-react-native/win32-theme Patch
@fluentui-react-native/callout Patch
@fluentui-react-native/divider Patch
@fluentui-react-native/persona Patch
@fluentui-react-native/tablist Patch
@fluentui-react-native/use-slot Patch
@fluentui-react-native/avatar Patch
@fluentui-react-native/button Patch
@fluentui-react-native/switch Patch
@fluentui-react-native/badge Patch
@fluentui-react-native/input Patch
@fluentui-react-native/stack Patch
@fluentui-react-native/chip Patch
@fluentui-react-native/icon Patch
@fluentui-react-native/link Patch
@fluentui-react-native/menu Patch
@fluentui-react-native/text Patch
@fluentui-react-native/theme Patch
@fluentui-react-native/framework-base Patch
@fluentui/react-native Patch
@fluentui-react-native/adapters Patch
@fluentui-react-native/styling-utils Patch
@fluentui-react-native/tokens Patch
@fluentui-react-native/tester Patch
@fluentui-react-native/codemods Patch

Not sure what this means? Click here to learn what changesets are.

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

@Saadnajmi Saadnajmi force-pushed the chore/oxlint-migration-review branch from ba05514 to 7ce82c8 Compare March 26, 2026 00:24
@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines:
1 pipeline(s) were filtered out due to trigger conditions.

@Saadnajmi Saadnajmi force-pushed the chore/oxlint-migration-review branch from a89f2a3 to 9c3eaf4 Compare April 16, 2026 01:04
@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines:
1 pipeline(s) were filtered out due to trigger conditions.

@Saadnajmi Saadnajmi force-pushed the chore/oxlint-migration-review branch 6 times, most recently from b382af0 to 0413432 Compare April 16, 2026 19:15
Comment thread packages/utils/interactive-hooks/src/useAsToggle.ts
Comment thread packages/utils/interactive-hooks/src/useAsPressable.ts
Comment thread packages/framework/use-styling/src/buildUseStyling.ts
Comment thread packages/framework/use-styling/src/buildUseStyling.test.ts
Comment thread packages/framework/use-slot/src/useSlot.ts
Comment thread packages/experimental/Spinner/src/Spinner.android.tsx
Comment thread packages/experimental/Shimmer/src/Shimmer.tsx
Comment thread packages/experimental/Overflow/src/OverflowItem/useOverflowItem.ts
Comment thread apps/E2E/oxlint.config.ts
Comment thread apps/E2E/wdio.conf.macos.js
Comment thread apps/fluent-tester/package.json Outdated
Comment thread apps/tester-core/oxlint.config.ts
Comment thread packages/components/Chip/src/useChip.ts
Comment thread packages/components/ContextualMenu/src/ContextualMenu.tsx
Comment thread packages/components/Menu/src/Menu/useMenu.android.ts
Comment thread packages/components/Menu/src/MenuItemRadio/useMenuItemRadio.ts
Comment thread packages/components/Menu/src/MenuPopover/useMenuPopover.ts
Comment thread packages/components/Menu/src/MenuTrigger/useMergeRefs.ts Outdated
Comment thread packages/components/MenuButton/src/MenuButton.macos.tsx
Comment thread packages/components/RadioGroup/src/legacy/RadioButton.macos.tsx
Comment thread packages/components/RadioGroup/src/legacy/RadioButton.tsx
Comment thread packages/components/RadioGroup/src/legacy/RadioGroup.tsx
Comment thread packages/components/RadioGroup/src/Radio/useRadio.win32.ts
Comment thread packages/configs/lint-config-rules/package.json
Comment thread packages/deprecated/foundation-tokens/src/Token.ts
Comment thread packages/experimental/Drawer/src/useDrawer.ts
Saadnajmi and others added 5 commits April 21, 2026 18:12
Swap ESLint for oxlint across the monorepo. This includes deleting all
per-package eslint.config.js files, adding oxlint.config.ts where needed,
updating package.json scripts/dependencies, renaming eslint-config-rules
to lint-config-rules, fixing depcheck dynamic dependency injection, and
updating dependency profiles and align-deps presets.

No behavioral code changes — only tooling and configuration.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Automated and trivial fixes flagged by oxlint rules:
- @ts-ignore@ts-expect-error
- export * → explicit named exports
- forEach → for-of loops
- Array<T> → T[] syntax
- Missing React key props
- Unused parameter underscoring
- Removed stale eslint-disable/ts-ignore comments
- Minor code simplifications (spread removal, type assertion fix)

No behavioral changes — all transformations are semantically equivalent.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add eslint-disable-next-line react-hooks/exhaustive-deps comments to hooks
that intentionally use empty or partial dependency arrays by design (e.g.,
mount-only effects, stable ref callbacks). These suppressions preserve the
existing intended behavior while satisfying oxlint's stricter linting.

No code logic changes — only lint suppression comments added/reworded.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Correctness fixes for React hook dependency arrays flagged by oxlint's
exhaustive-deps rule. Key changes:

- RadioGroup: destructure context, use functional state updaters (fixes
  state mutation bug where .push() didn't trigger re-render)
- ContextualMenu/Submenu: destructure callbacks, add missing deps
- Menu: fix comma expression bug in MenuPopover, fix self-referential
  useMemo in useMenu.android, destructure context
- Shimmer/Spinner/ActivityIndicator: useRef for Animated.Value (prevents
  recreation on re-render), correct animation effect deps
- Drawer: add isFirstOpen dep, destructure callbacks
- useAsPressable/useAsToggle: add missing callback deps (stale closures)
- TabListAnimatedIndicator: useMemo → useRef for stable animation values
- TabList: refactor disabled tab search loop
- useSlot/useMergeRefs: correct dependency arrays
- Chip/Checkbox/OverflowItem: narrow or correct dep arrays

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@Saadnajmi Saadnajmi force-pushed the chore/oxlint-migration-review branch from 0413432 to d04b0bf Compare April 22, 2026 18:43
Copy link
Copy Markdown
Contributor

@JasonVMo JasonVMo left a comment

Choose a reason for hiding this comment

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

I think only two things I'd flag as issues.

Comment thread packages/components/Menu/src/MenuTrigger/useMergeRefs.ts Outdated
Comment thread packages/components/Menu/src/MenuPopover/useMenuPopover.ts
Comment thread packages/components/MenuButton/src/MenuButton.macos.tsx
Comment thread packages/framework/use-slot/src/useSlot.ts
Comment thread packages/utils/interactive-hooks/src/useAsToggle.ts
Comment thread apps/tester-core/oxlint.config.ts
Comment thread apps/tester-core/oxlint.config.ts
Comment thread apps/fluent-tester/package.json Outdated
Comment thread apps/E2E/wdio.conf.macos.js
Comment thread apps/E2E/oxlint.config.ts
Saadnajmi and others added 2 commits April 22, 2026 17:24
…undle script

- useMergeRefs: restore [...refs] spread so React compares individual ref
  values rather than the always-new rest parameter array instance
- useSlot: re-add `component` to useMemo deps to ensure memo invalidates
  when the component prop changes
- fluent-tester: revert bundle script to original `rnx-cli bundle --dev false`
  which is more flexible than explicit per-platform chaining

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Destructuring onDismiss from userProps removed it from the ...rest spread
that gets passed to the Callout root slot. The Callout needs onDismiss to
function correctly — without it, the MenuButton SPACE key test consistently
failed because the menu couldn't dismiss/toggle properly.

Fix: destructure onDismiss AND explicitly pass it back in the root slot props.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@Saadnajmi Saadnajmi enabled auto-merge (squash) April 23, 2026 22:00
@Saadnajmi Saadnajmi merged commit 9cf4444 into microsoft:main Apr 24, 2026
14 checks passed
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.

2 participants