diff --git a/CHANGELOG.md b/CHANGELOG.md index eded1e0eb..8a1101f26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -164,6 +164,7 @@ and adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - React Router routes are now read from every table a route-building function returns, an early `if (!user) return [];` and each branch alike, and never from a list that a function written inside it returns, like a `.forEach` callback's `return []` or a helper's menu. A function that returns another's table, as in `return buildRoutes()`, is followed too, and so is a table behind `useMemo`, like `useMemo(() => getRoutes(user), [user])` or `useMemo(getRoutes, [])`. Before, the first `return [` anywhere in the function was taken for the table, so an empty guard or a callback's list could hide an app's routes entirely, or a menu could be read in their place. Re-index React projects after upgrading. - In JavaScript and TypeScript, an import written `import { default as AppRoot } from './routes/app/root'`, as in bulletproof-react's router, now counts as the module's default import, the same as `import AppRoot from './routes/app/root'`. Before, it was read as an import of an export named `default`, which no module has, so a call, a route or a JSX attribute that used `AppRoot` was matched by its name alone: it could link to another file's `AppRoot`, or to nothing when the default export has a name of its own. Svelte, Vue and Astro script blocks are read the same way. - In React, a component's JSX no longer links it to a class or component that only shares a name with one of its type arguments or with a variable of its own. A type in angle brackets, like `Document` in ` items={…} />`, `User` in `useState()` or `Entry` in a generic `(…) =>` component, is no longer read as a tag. A tag naming a variable or parameter the component sets itself, like `` after `const Content = isDropdown ? DropdownMenu.SubContent : ContextMenu.SubContent` or `` in `widgets.map((Widget) => )`, now links to nothing, unless the component declares a component of that name inside itself. Before, these linked to an unrelated class or component elsewhere in the repository: outline's document lists showed up among the callers of its `Document` model class, and its menus among the callers of the command bar's `Content`, so `codegraph_explore`, callers and impact followed renders that never happen. Re-index React projects after upgrading. +- In React, a tag for a component a function destructures from its props or from an object, like `({ Header, Footer, children }) =>` in refine's layouts or `const { Sidebar, Footer } = excalidrawLib` in excalidraw's example app, now links to nothing, as a tag naming a variable the function sets itself already did, unless the function declares a component of that name inside itself. A function nested in the one that sets or destructures the name, like a `renderSidebar` helper inside the component, reads the tag the same way. A name destructured from `require(…)` or `import(…)` still links to that module's export. Before, these tags were matched by their name alone, so refine's layouts showed up among the callers of other examples' `Header` and `Footer` components, and `codegraph_explore`, callers and impact followed renders that never happen. Re-index React projects after upgrading. - In React, a tag a component only mentions in a comment or a string no longer links it to that component: a JSDoc example, markup commented out like `{/* */}`, or an error message like react-router's "You cannot render a inside another " or shadcn's "useCarousel must be used within a ". Nothing in a TypeScript `.ts` file, which can't hold JSX, is read as a tag either, like the XML in outline's OpenSearch template. Before, these counted as renders, so react-router's hooks showed up among the callers of `Router`, `Routes` and `Route`, and `codegraph_explore`, callers and impact followed renders that never happen. A tag after an apostrophe, a URL or a backtick in a component's text, like `

Don't have an account? `, still links as before. Re-index React projects after upgrading. - In JavaScript and TypeScript, a name imported from a package your `package.json` lists no longer links to a project symbol that only shares its name when `tsconfig.json` or `jsconfig.json` has a catch-all path alias, like `"*": ["./typings/*"]` or `"*": ["src/*", "node_modules/*"]`, or an alias that points the package at a file in `node_modules`, like `"lit/decorators": ["./node_modules/lit/decorators.js"]`. Such an alias made every package look like part of the project, so `import { Typography } from '@mui/material'` was linked to the project's own `Typography` and every lit `@property()` decorator to an unrelated class's `property` field, and `codegraph callers`, impact and `codegraph affected` listed code that never used them. An import the alias does map to a file of your project, like a `.d.ts` you keep for an untyped package or `components/Button` through `"*": ["src/*"]`, links as before. Re-index affected projects after upgrading. - In JavaScript and TypeScript, a function the file imports from a package and passes along as a value, like react-router's `Link` in `styled(Link)`, lodash's `noop` in `createContext({ onClose: noop })` or chart.js's `Legend` in `Chart.register(Legend)`, no longer links to a project function that only shares its name. Before, whenever the project had exactly one function of that name, every such value linked to it: outline's breadcrumbs, menus and document lists showed up among the callers of an email template's `Link`, and a test's own `noop` stub in cord-field among the code the app's contexts use, so `codegraph callers`, impact and `codegraph_explore` followed references that never happen. A function the file declares itself, including one that hides the import inside a function, and one imported from a file of your project link as before. Re-index JavaScript and TypeScript projects after upgrading. diff --git a/__tests__/jsx-child-disambiguation.test.ts b/__tests__/jsx-child-disambiguation.test.ts index a5d669e7b..4791a7db7 100644 --- a/__tests__/jsx-child-disambiguation.test.ts +++ b/__tests__/jsx-child-disambiguation.test.ts @@ -139,12 +139,15 @@ export function Header() { return

; } * writes a type's name right after another name. outline's document list * rendered its `Document` model class, its settings tables the `User` and * `Group` classes. - * - A name the parent binds itself, as a `const` or a parameter, is that local - * wherever its tags sit. outline's menus pick a Radix part into `const - * Content = variant === 'dropdown' ? DropdownMenu.SubContent : + * - A name the parent binds itself, as a `const`, a parameter or a name it + * destructures, is that local wherever its tags sit, and so is a name a + * function around the parent binds. outline's menus pick a Radix part into + * `const Content = variant === 'dropdown' ? DropdownMenu.SubContent : * ContextMenu.SubContent` and rendered the command bar's styled `Content` - * instead. A local is no node, so it renders nothing, unless the parent - * declares a component of that name inside itself. + * instead; refine's layout renders the `Header` and `Footer` its props hand + * in, and rendered other examples' components of those names. A local is no + * node, so it renders nothing, unless the function that binds it declares a + * component of that name inside itself. */ describe('JSX child: a name the parent writes only as a type, or binds itself', () => { let dir: string; @@ -322,24 +325,164 @@ export function Toolbar({ actions }) { expect(renders('Toolbar')).toEqual(['Icon app/icon.tsx:1']); }); - it('keeps a destructured name on the same-named component, as a destructured call does', async () => { - // excalidraw's example app: `const { Sidebar, Footer, … } = excalidrawLib`. - // Destructuring is not the parent's own binding here, as it is not for a - // bare call (`const { t } = useI18n()`), so the name links by name. + it('renders nothing for a name the parent destructures from a value or its props', async () => { write( 'packages/excalidraw/components/WelcomeScreen.tsx', 'export default function WelcomeScreen() {\n return
;\n}\n' ); + write('examples/app/sidebar/ExampleSidebar.tsx', 'export function Sidebar() {\n return