chore(lint): migrate repo to oxlint and stabilize validation#4075
chore(lint): migrate repo to oxlint and stabilize validation#4075Saadnajmi wants to merge 7 commits intomicrosoft:mainfrom
Conversation
🦋 Changeset detectedLatest commit: 9fad281 The changes in this PR will be included in the next version bump. This PR includes changesets to release 74 packages
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 |
ba05514 to
7ce82c8
Compare
|
Azure Pipelines: 1 pipeline(s) were filtered out due to trigger conditions. |
a89f2a3 to
9c3eaf4
Compare
|
Azure Pipelines: 1 pipeline(s) were filtered out due to trigger conditions. |
The TS build failed because private.ts imports from @rnx-kit/oxlint-config/* which ships no type declarations. Add a triple-slash reference so the existing types.d.ts is always in scope, even when other packages compile this file with their own tsconfig. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
b0aac5e to
b382af0
Compare
Two CI fixes: 1. types.d.ts: Use OxlintConfig type instead of unknown for the @rnx-kit/oxlint-config ambient module declarations, since the extends field in defineConfig expects OxlintConfig[]. 2. depcheck.ts: Fix injectedDevDeps() to read Object.keys from the nested .dependencies object rather than the wrapper, so dynamically injected deps like oxlint are properly ignored. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
b382af0 to
0413432
Compare
| userCallback && userCallback(!isChecked); | ||
| setChecked(!isChecked); | ||
| }, [isChecked, setChecked]); | ||
| }, [isChecked, setChecked, userCallback]); |
There was a problem hiding this comment.
Note, changes like this (And in useAsPressable) could change behavior
| setHoverState({ hovered: true }); | ||
| if (props.onHoverIn) { | ||
| props.onHoverIn(e); | ||
| if (onHoverInProp) { | ||
| onHoverInProp(e); | ||
| } | ||
| }, | ||
| [setHoverState, props.onHoverIn], | ||
| [onHoverInProp, setHoverState], | ||
| ); |
There was a problem hiding this comment.
Better code but could change behavior
| const slotProps = {}; | ||
| Object.keys(styles).forEach((key) => { | ||
| for (const key of Object.keys(styles)) { | ||
| const style = styles[key]; | ||
| slotProps[key] = typeof style === 'function' ? style(tokens, theme, cache(null, [key])[1]) : style; | ||
| }); | ||
| } | ||
| return slotProps as TSlotProps; |
| Object.keys(slotProps).forEach((key) => { | ||
| for (const key of Object.keys(slotProps)) { | ||
| expect(slotProps[key]).toBe(slotProps2[key]); | ||
| }); | ||
| } |
There was a problem hiding this comment.
same change here
| }), | ||
| [component, filter, slotData], | ||
| [filter, slotData], | ||
| ); |
There was a problem hiding this comment.
maybe behavioral change
| const hideOpacity = status === 'inactive' && hidesWhenStopped == true ? 0 : 1; | ||
| const rotationAngle = new Animated.Value(0); | ||
| const rotationAngle = useRef(new Animated.Value(0)).current; | ||
|
|
There was a problem hiding this comment.
Probably want to check this
| ).start(); | ||
| }, [memoizedShimmerData.delay, memoizedShimmerData.duration]); | ||
| }, [endValue, memoizedShimmerData.delay, memoizedShimmerData.duration, x1]); | ||
|
|
||
| useEffect(() => { | ||
| shimmerAnimation(); | ||
| }); | ||
| }, [shimmerAnimation]); | ||
|
|
There was a problem hiding this comment.
Probably check this
| // This effect should only run when the size of the item or container changes. | ||
| // eslint-disable-next-line react-hooks/exhaustive-deps -- intentionally only re-run when size or containerSize changes | ||
| }, [size, containerSize]); | ||
|
|
||
| const onLayout = React.useCallback( | ||
| (e: LayoutChangeEvent) => { | ||
| const itemSize = { width: e.nativeEvent.layout.width, height: e.nativeEvent.layout.height }; | ||
| setSize(itemSize); | ||
| props.onLayout && props.onLayout(e); | ||
| onLayoutProp && onLayoutProp(e); | ||
| }, | ||
| [props], | ||
| [onLayoutProp], | ||
| ); // Get item dimensions |
| '@rnx-kit/no-export-all': 'off', | ||
| 'typescript/class-literal-property-style': 'off', |
There was a problem hiding this comment.
These two seem added
| bail: 1, // If you only want to run your tests until a specific amount of tests have failed use bail (default is 0 - don't bail, run all tests). | ||
| waitforTimeout: defaultWaitForTimeout, // Default timeout for all waitForXXX commands. | ||
| connectionRetryTimeout: defaultConnectionRetryTimeout, // Timeout for any WebDriver request to a driver or grid. | ||
| connectionRetryCount: 2, // Maximum count of request retries to the Selenium server. |
There was a problem hiding this comment.
Why remove this?
| "build-cjs": "tsgo --outDir lib-commonjs", | ||
| "build-core": "tsgo --outDir lib --module esnext --moduleResolution bundler", | ||
| "bundle": "rnx-cli bundle --dev false", | ||
| "bundle": "yarn bundle:android && yarn bundle:ios && yarn bundle:macos", |
There was a problem hiding this comment.
Why this change?
| rules: { | ||
| '@rnx-kit/no-export-all': 'off', | ||
| '@rnx-kit/no-foreach-with-captured-variables': 'off', | ||
| 'react-hooks/exhaustive-deps': 'off', | ||
| 'typescript/array-type': 'off', | ||
| }, |
There was a problem hiding this comment.
Do we need to add these? Can they be in the base?
| } | ||
| }, | ||
| [checkedValue, showCloseIcon, closeIconOnPress], | ||
| [closeIconOnPress, closeIconVisibile], |
There was a problem hiding this comment.
Could be a change
| const dismissCallback = React.useCallback(() => { | ||
| userProps.onDismiss(); | ||
| onDismiss(); | ||
| setShowMenu?.(false); | ||
| }, [setShowMenu, userProps.onDismiss]); | ||
| }, [onDismiss, setShowMenu]); |
There was a problem hiding this comment.
Could be a change
| const transforms = []; | ||
| const transforms = useMemo(() => { | ||
| const nextTransforms = []; | ||
|
|
There was a problem hiding this comment.
Lot of changes here
| React.useEffect(() => { | ||
| listContext.addRadioItem(name); | ||
| addRadioItem(name); | ||
|
|
||
| return () => { | ||
| listContext.removeRadioItem(name); | ||
| removeRadioItem(name); | ||
| }; | ||
| // eslint-disable-next-line react-hooks/exhaustive-deps -- intentionally run only on mount/unmount |
| const doNotTakePointerCapture = props.doNotTakePointerCapture ?? openOnHover; | ||
| const doNotTakePointerCapture = doNotTakePointerCaptureProp ?? openOnHover; |
| } | ||
| }, | ||
| [...refs], | ||
| [refs], |
| menuItems.forEach((item) => { | ||
| for (const item of menuItems) { | ||
| const imageSource = extractResolvedImageSourceFromIcon(item.icon); |
| const onPressRerouted = () => { | ||
| const onPressRerouted = React.useCallback(() => { | ||
| // Prevent calls to RadioGroup's onChange on the currently selected button | ||
| if (buttonKey != info.selectedKey) { | ||
| info.onChange && info.onChange(buttonKey); | ||
| info.updateSelectedButtonRef && componentRef && info.updateSelectedButtonRef(componentRef); | ||
| if (buttonKey != selectedKey) { | ||
| onChange && onChange(buttonKey); | ||
| updateSelectedButtonRef && componentRef && updateSelectedButtonRef(componentRef); | ||
| } | ||
| }; | ||
| }, [buttonKey, componentRef, onChange, selectedKey, updateSelectedButtonRef]); |
There was a problem hiding this comment.
A lot of changes here
| const changeSelection = () => { | ||
| if (buttonKey != info.selectedKey) { | ||
| info.onChange && info.onChange(buttonKey); | ||
| info.updateSelectedButtonRef && componentRef && info.updateSelectedButtonRef(componentRef); | ||
| const changeSelection = React.useCallback(() => { | ||
| if (buttonKey != selectedKey) { | ||
| onChange && onChange(buttonKey); | ||
| updateSelectedButtonRef && componentRef && updateSelectedButtonRef(componentRef); | ||
| } |
| buttonKeys.push(buttonKey); | ||
| setButtonKeys(buttonKeys); | ||
| setButtonKeys((prevButtonKeys) => [...prevButtonKeys, buttonKey]); | ||
| }, |
| }, | ||
| [radioGroupContext], | ||
| [enabledValues, isRTL, onChange, selectedValue, updateInvoked], | ||
| ); |
| ".": { | ||
| "default": "./private.ts" | ||
| }, | ||
| "./private": { | ||
| "default": "./private.ts" | ||
| }, | ||
| "./package.json": "./package.json" |
| const resolvedSlotProps = { tokens: tokenPropInfo.tokens || {} }; | ||
|
|
||
| Object.getOwnPropertyNames(handlers).forEach((slotName) => { | ||
| for (const slotName of Object.getOwnPropertyNames(handlers)) { |
| }); | ||
| } | ||
| }, [rotationAngle, animating]); | ||
| }, [rotationAngle]); |
| stopRotation(); | ||
| } | ||
| }, [animating, hidesWhenStopped, rotationAngle]); | ||
| }, [animating, rotationAngle, startRotation]); |
| [props?.onScrimClick], | ||
| [onScrimClickProp], |
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
2. Fix oxlint violations across the repo
3. Stabilize full repo validation
Why this is split this way
The commit history is organized to make review easier:
This lets the tooling migration, rule-compliance changes, and validation fix be reviewed independently.
Validation