diff --git a/CHANGELOG.md b/CHANGELOG.md index 58f4f3bf7..1d7845d54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -113,6 +113,7 @@ and adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - `codegraph sync` and the file watcher now move a React Router route to its page when the router file loads that page lazily into a value of its own, like `const Docs = lazy(() => import('./pages/Docs'))` rendered by `} />`, and the page's file is added after the router was indexed, comes back after being deleted, or gets or changes its default export in a later edit. Before, the route kept pointing at the `Docs` declaration, or at the page's old component, until the router file itself changed or the project was re-indexed, unless the page's component happened to share the declaration's name. The same now holds for a `lazy: () => import('./pages/Docs')` route whose page switches its default export to another component. Re-index React projects after upgrading to correct routes an earlier version left behind. - `codegraph sync` and the file watcher now link a component to the JSX that renders it, like ``, when the component is added in a file with no JSX of its own, as in `export default function Team() { return null; }`. Before, the link waited for an unrelated change to a file with JSX, or for a re-index, so the new component looked unused. - In JavaScript and TypeScript, a default import now links to what the module's `export default` statement exports, wherever the statement sits in the file. Before, a module that declares its default, like `export default function Vans() {…}` or `export default class Store {…}`, had its default import linked to the first function it exports instead: in a React Router data-router app, where a page exports its `loader` or `action` above the page component, `import Vans, { loader as vansLoader } from './pages/Vans'` made the route `/vans` and every use of `Vans` lead to the loader. A component file that also exports a styled or memoized component no longer hands its default import to that component, and an anonymous default, like `export default function () {…}` or `export default () => …`, is no longer linked to a function exported beside it or nested inside it. Re-index JavaScript and TypeScript projects after upgrading. +- In React and Vue, a tag for a component the file imports from a package, like ` + + ); +} +` + ); + await index(); + expect(renders('Settings')).toEqual([]); + }); + + it('renders nothing for a default import from a package subpath, or a package import under another name', async () => { + // mantis/berry: `import Typography from '@mui/material/Typography'` beside + // the theme's own `Typography` override; a router link renamed on import. + write( + 'package.json', + JSON.stringify({ dependencies: { react: '^18.0.0', '@mui/material': '^5.0.0', 'react-router-dom': '^6.0.0' } }) + ); + write( + 'src/themes/overrides/Typography.js', + 'export default function Typography(theme) {\n return { MuiTypography: { styleOverrides: {} } };\n}\n' + ); + write('src/components/RouterLink.tsx', 'export function RouterLink() {\n return ;\n}\n'); + write( + 'src/pages/Login.tsx', + `import Typography from '@mui/material/Typography'; +import { Link as RouterLink } from 'react-router-dom'; + +export function Login() { + return ( + + Sign up + + ); +} +` + ); + await index(); + expect(renders('Login')).toEqual([]); + }); + + it('keeps a tag imported through an alias that reads like a package, or through a bare specifier no package.json declares', async () => { + write('package.json', JSON.stringify({ dependencies: { react: '^18.0.0', antd: '^5.0.0' } })); + write( + 'tsconfig.json', + JSON.stringify({ compilerOptions: { baseUrl: '.', paths: { 'components/*': ['src/components/*'] } } }) + ); + write('src/components/Modal/index.tsx', 'export default function Modal() {\n return
;\n}\n'); + write('src/layouts/Header.tsx', 'export default function Header() {\n return
;\n}\n'); + write( + 'src/container/Alerts.tsx', + `import Modal from 'components/Modal'; + +export function Alerts() { + return ; +} +` + ); + write( + 'src/container/Confirm.tsx', + `import { Modal } from 'antd'; + +export function Confirm() { + return ; +} +` + ); + // No alias maps `layouts/*` and no package.json declares `layouts`: the + // resolver can't follow it, which does not make it a package. + write( + 'src/App.tsx', + `import Header from 'layouts/Header'; + +export function App() { + return
; +} +` + ); + await index(); + expect(renders('Alerts')).toEqual(['Modal src/components/Modal/index.tsx:1']); + expect(renders('Confirm')).toEqual([]); + expect(renders('App')).toEqual(['Header src/layouts/Header.tsx:1']); + }); + + it('keeps a tag imported from a workspace package of the repository', async () => { + write('package.json', JSON.stringify({ private: true, workspaces: ['packages/*', 'apps/*'] })); + write('packages/ui/package.json', JSON.stringify({ name: '@acme/ui', version: '1.0.0' })); + write('packages/ui/index.tsx', 'export function Button() {\n return