From 20cec3b315e85570b92f0da62ca2c1a22b9680da Mon Sep 17 00:00:00 2001 From: Devon Govett Date: Thu, 16 Apr 2026 16:29:40 -0700 Subject: [PATCH 1/2] Update docs for router config to use subpaths --- packages/dev/s2-docs/pages/s2/getting-started.mdx | 4 ++-- packages/dev/s2-docs/src/routers-s2.mdx | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/dev/s2-docs/pages/s2/getting-started.mdx b/packages/dev/s2-docs/pages/s2/getting-started.mdx index 584b9920c92..b7f5e2e36b2 100644 --- a/packages/dev/s2-docs/pages/s2/getting-started.mdx +++ b/packages/dev/s2-docs/pages/s2/getting-started.mdx @@ -307,7 +307,7 @@ Install React Spectrum with your preferred package manager. import {Provider} from '@react-spectrum/s2/Provider'; // Configure the type of the `routerOptions` prop on all React Spectrum components. - declare module '@react-spectrum/s2' { + declare module '@react-spectrum/s2/Provider' { interface RouterConfig { routerOptions: NonNullable['push']>[1]> } @@ -402,7 +402,7 @@ Install React Spectrum with your preferred package manager. /*- begin highlight -*/ // Configure the type of the `routerOptions` prop on all React Spectrum components. - declare module '@react-spectrum/s2' { + declare module '@react-spectrum/s2/Provider' { interface RouterConfig { routerOptions: NavigateOptions } diff --git a/packages/dev/s2-docs/src/routers-s2.mdx b/packages/dev/s2-docs/src/routers-s2.mdx index a399d3c4660..7fb2f4505ac 100644 --- a/packages/dev/s2-docs/src/routers-s2.mdx +++ b/packages/dev/s2-docs/src/routers-s2.mdx @@ -12,12 +12,12 @@ import {Step, Counter} from './Step'; ```tsx // src/app.tsx - import {Provider} from '@react-spectrum/s2'; + import {Provider} from '@react-spectrum/s2/Provider'; import {BrowserRouter, useNavigate, useHref, type NavigateOptions} from 'react-router'; /*- begin highlight -*/ // Configure the type of the `routerOptions` prop on all React Spectrum components. - declare module '@react-spectrum/s2' { + declare module '@react-spectrum/s2/Provider' { interface RouterConfig { routerOptions: NavigateOptions } @@ -43,12 +43,12 @@ import {Step, Counter} from './Step'; ```tsx // src/routes/__root.tsx - import {Provider} from '@react-spectrum/s2'; + import {Provider} from '@react-spectrum/s2/Provider'; import {useRouter, type NavigateOptions, type ToOptions} from '@tanstack/react-router'; /*- begin highlight -*/ // Configure the type of the `href` and `routerOptions` props on all React Spectrum components. - declare module '@react-spectrum/s2' { + declare module '@react-spectrum/s2/Provider' { interface RouterConfig { href: ToOptions, routerOptions: Omit From b88a47a8723db7da467ce6c3193ecfbd8d4894a2 Mon Sep 17 00:00:00 2001 From: Devon Govett Date: Thu, 16 Apr 2026 16:30:17 -0700 Subject: [PATCH 2/2] Update codemod --- .../src/use-subpaths/src/codemod.test.ts | 90 +++++++++++++++++++ .../codemods/src/use-subpaths/src/codemod.ts | 40 ++++++++- .../src/use-subpaths/src/specifiers.ts | 4 +- 3 files changed, 129 insertions(+), 5 deletions(-) diff --git a/packages/dev/codemods/src/use-subpaths/src/codemod.test.ts b/packages/dev/codemods/src/use-subpaths/src/codemod.test.ts index beb9e0fdc0d..35971ecee47 100644 --- a/packages/dev/codemods/src/use-subpaths/src/codemod.test.ts +++ b/packages/dev/codemods/src/use-subpaths/src/codemod.test.ts @@ -146,3 +146,93 @@ import {RangeCalendar, CalendarCell, Heading} from 'react-aria-components'; import { RangeCalendar, CalendarCell, Heading } from 'react-aria-components/RangeCalendar'; ` ); + +test( + 'rewrites declare module for RouterConfig on @react-spectrum/s2 to Provider subpath', + ` +declare module '@react-spectrum/s2' { + interface RouterConfig { + routerOptions: { x: string }; + } +} +`, + ` +declare module '@react-spectrum/s2/Provider' { + interface RouterConfig { + routerOptions: { x: string }; + } +} +` +); + +test( + 'rewrites declare module for RouterConfig on @adobe/react-spectrum to Provider subpath', + ` +declare module '@adobe/react-spectrum' { + interface RouterConfig { + routerOptions: { x: string }; + } +} +`, + ` +declare module '@adobe/react-spectrum/Provider' { + interface RouterConfig { + routerOptions: { x: string }; + } +} +` +); + +test( + 'leaves declare module on an existing Provider subpath unchanged', + ` +declare module '@react-spectrum/s2/Provider' { + interface RouterConfig { + routerOptions: { x: string }; + } +} +`, + ` +declare module '@react-spectrum/s2/Provider' { + interface RouterConfig { + routerOptions: { x: string }; + } +} +` +); + +test( + 'does not rewrite react-aria-components declare module when there is no Provider subpath', + ` +declare module 'react-aria-components' { + interface RouterConfig { + routerOptions: { x: string }; + } +} +`, + ` +declare module 'react-aria-components' { + interface RouterConfig { + routerOptions: { x: string }; + } +} +` +); + +test( + 'does not rewrite declare module on root package when not augmenting RouterConfig', + ` +declare module '@react-spectrum/s2' { + interface SomethingElse { + x: string; + } +} +`, + ` +declare module '@react-spectrum/s2' { + interface SomethingElse { + x: string; + } +} +` +); diff --git a/packages/dev/codemods/src/use-subpaths/src/codemod.ts b/packages/dev/codemods/src/use-subpaths/src/codemod.ts index e5a8b99622e..9f7e23a74b5 100644 --- a/packages/dev/codemods/src/use-subpaths/src/codemod.ts +++ b/packages/dev/codemods/src/use-subpaths/src/codemod.ts @@ -1,6 +1,6 @@ /* eslint-disable max-depth */ import {API, FileInfo} from 'jscodeshift'; -import {getSpecifiersByPackage} from './specifiers'; +import {getSpecifiersByPackage, MONOPACKAGE_ROOTS} from './specifiers'; import {parse} from '@babel/parser'; import {parse as recastParse} from 'recast'; import * as t from '@babel/types'; @@ -64,6 +64,25 @@ function resolveTargetSource( return candidates[0]; } +function moduleAugmentsRouterConfig(body: t.TSModuleBlock): boolean { + for (let stmt of body.body) { + if (stmt.type === 'TSInterfaceDeclaration' && stmt.id.type === 'Identifier' && stmt.id.name === 'RouterConfig') { + return true; + } + + if ( + stmt.type === 'ExportNamedDeclaration' && + stmt.declaration?.type === 'TSInterfaceDeclaration' && + stmt.declaration.id.type === 'Identifier' && + stmt.declaration.id.name === 'RouterConfig' + ) { + return true; + } + } + + return false; +} + export default function transformer(file: FileInfo, api: API): string { let specifiersByPackage = getSpecifiersByPackage(file.path); let j = api.jscodeshift.withParser({ @@ -102,6 +121,7 @@ export default function transformer(file: FileInfo, api: API): string { let program = root.get().node.program as t.Program; let uniqueSources = new Set(); let existingImports = new Map(); + let didChange = false; for (let node of program.body) { if (node.type === 'ImportDeclaration') { @@ -128,9 +148,23 @@ export default function transformer(file: FileInfo, api: API): string { } } } - } - let didChange = false; + if (node.type === 'TSModuleDeclaration' && node.declare && node.id.type === 'StringLiteral') { + let mod = node.id.value; + if (!MONOPACKAGE_ROOTS.includes(mod) || node.body?.type !== 'TSModuleBlock' || !moduleAugmentsRouterConfig(node.body)) { + continue; + } + + let target = `${mod}/Provider`; + let candidates = specifiersByPackage[mod]?.Provider; + if (!candidates?.includes(target)) { + continue; + } + + node.id = t.stringLiteral(target); + didChange = true; + } + } program.body = program.body.flatMap(node => { if (node.type !== 'ImportDeclaration') { diff --git a/packages/dev/codemods/src/use-subpaths/src/specifiers.ts b/packages/dev/codemods/src/use-subpaths/src/specifiers.ts index 13888cdbf9e..68207c0b51e 100644 --- a/packages/dev/codemods/src/use-subpaths/src/specifiers.ts +++ b/packages/dev/codemods/src/use-subpaths/src/specifiers.ts @@ -5,7 +5,7 @@ import {parse} from '@babel/parser'; import path from 'path'; import url from 'url'; -const PACKAGES = [ +export const MONOPACKAGE_ROOTS = [ '@adobe/react-spectrum', '@react-spectrum/s2', 'react-aria-components', @@ -17,7 +17,7 @@ const specifiersByPackage: Record> = {}; /** Builds a mapping of monopackage -> export -> subpaths that contain the export. */ export function getSpecifiersByPackage(from: string) { - for (let pkg of PACKAGES) { + for (let pkg of MONOPACKAGE_ROOTS) { if (specifiersByPackage[pkg]) { continue; }