ronantakizawa/codereview-bench huggingface dataset:
Repository: facebook/docusaurus
File: packages/docusaurus-theme-classic/src/theme/Navbar/MobileSidebar/Header/index.tsx (TypeScript)

Code before:
/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import React from 'react';
import {useNavbarMobileSidebar} from '@docusaurus/theme-common/internal';
import NavbarColorModeToggle from '@theme/Navbar/ColorModeToggle';
import IconClose from '@theme/Icon/Close';
import NavbarLogo from '@theme/Navbar/Logo';

function CloseButton() {
  const mobileSidebar = useNavbarMobileSidebar();
  return (
    <button
      type="button"
      aria-label="Close navigation bar"
      className="clean-btn navbar-sidebar__close"
      onClick={() => mobileSidebar.toggle()}>
      <IconClose color="var(--ifm-color-emphasis-600)" />
    </button>
  );
}

export default function NavbarMobileSidebarHeader(): JSX.Element {
  return (
    <div className="navbar-sidebar__brand">
      <NavbarLogo />
      <NavbarColorModeToggle className="margin-right--md" />
      <CloseButton />
    </div>
  );
}


Review comment (suggestion):
We usually translate all our aria labels by default

You can use the Docusaurus `translate()` API and then update the default theme translations with `yarn workspace @docusaurus/theme-translations update` (so that translators can find and edit the untranslated strings)

Code after:
/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import React from 'react';
import {useNavbarMobileSidebar} from '@docusaurus/theme-common/internal';
import {translate} from '@docusaurus/Translate';
import NavbarColorModeToggle from '@theme/Navbar/ColorModeToggle';
import IconClose from '@theme/Icon/Close';
import NavbarLogo from '@theme/Navbar/Logo';

function CloseButton() {
  const mobileSidebar = useNavbarMobileSidebar();
  return (
    <button
      type="button"
      aria-label={translate({
        id: 'theme.docs.sidebar.closeSidebarButtonAriaLabel',
        message: 'Close navigation bar',
        description: 'The ARIA label for close button of mobile sidebar',
      })}
      className="clean-btn navbar-sidebar__close"
      onClick={() => mobileSidebar.toggle()}>
      <IconClose color="var(--ifm-color-emphasis-600)" />
    </button>
  );
}

export default function NavbarMobileSidebarHeader(): JSX.Element {
  return (
    <div className="navbar-sidebar__brand">
      <NavbarLogo />
      <NavbarColorModeToggle className="margin-right--md" />
      <CloseButton />
    </div>
  );
}
Repository: facebook/docusaurus
File: packages/docusaurus-theme-classic/src/theme/BlogPostPage/StructuredData/index.tsx (TypeScript)

Code before:
        : authorsStructuredData,
    ...(image
      ? {
          // details on structured data support: https://schema.org/ImageObject
          image: {
            '@type': 'ImageObject',
            '@id': imageUrl,
            url: imageUrl,
            contentUrl: imageUrl,
            caption: `title image for the blog post: ${title}`,
          },
        }
      : {}),
    ...(keywords ? {keywords} : {}),
    isPartOf: {
      '@type': 'Blog',
      '@id': `${siteConfig.url}${metadata.baseBlogPermalink}`,
      name: metadata.baseBlogTitle,
    },
  };

  return (
    <script
      type="application/ld+json"
      // We're using dangerouslySetInnerHTML because we want to avoid React
      // transforming transforming quotes into &quot; which upsets parsers.
      // The entire contents is a stringified JSON object so it is safe
      // eslint-disable-next-line react/no-danger
      dangerouslySetInnerHTML={{
        __html: JSON.stringify(blogPostStructuredData),
      }}
    />
  );
}


Review comment (suggestion):
```suggestion
      // transforming quotes into &quot; which upsets parsers.
```

Code after:
/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import React from 'react';
import Head from '@docusaurus/Head';
import {useBlogPostStructuredData} from '@docusaurus/theme-common';

export default function BlogPostStructuredData(): JSX.Element {
  const structuredData = useBlogPostStructuredData();
  return (
    <Head>
      <script type="application/ld+json">
        {JSON.stringify(structuredData)}
      </script>
    </Head>
  );
}
Repository: facebook/docusaurus
File: packages/docusaurus-theme-classic/src/theme/BlogListPage/StructuredData/index.tsx (TypeScript)

Code before:
        author:
          authorsStructuredData.length === 1
            ? authorsStructuredData[0]
            : authorsStructuredData,
        ...(image
          ? {
              // details on structured data support: https://schema.org/ImageObject
              image: {
                '@type': 'ImageObject',
                '@id': imageUrl,
                url: imageUrl,
                contentUrl: imageUrl,
                caption: `title image for the blog post: ${title}`,
              },
            }
          : {}),
        ...(keywords ? {keywords} : {}),
      };
    }),
  };

  return (
    <script
      type="application/ld+json"
      // We're using dangerouslySetInnerHTML because we want to avoid React
      // transforming transforming quotes into &quot; which upsets parsers.
      // The entire contents is a stringified JSON object so it is safe
      // eslint-disable-next-line react/no-danger
      dangerouslySetInnerHTML={{
        __html: JSON.stringify(blogStructuredData),
      }}
    />
  );
}


Review comment (suggestion):
```suggestion
      // transforming quotes into &quot; which upsets parsers.
```

Code after:
/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import React from 'react';
import Head from '@docusaurus/Head';
import {useBlogListPageStructuredData} from '@docusaurus/theme-common';
import type {Props} from '@theme/BlogListPage/StructuredData';

export default function BlogListPageStructuredData(props: Props): JSX.Element {
  const structuredData = useBlogListPageStructuredData(props);
  return (
    <Head>
      <script type="application/ld+json">
        {JSON.stringify(structuredData)}
      </script>
    </Head>
  );
}
Repository: facebook/docusaurus
File: packages/docusaurus-theme-classic/src/theme/BlogPostPage/StructuredData/index.tsx (TypeScript)

Code before:
/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import React from 'react';
import {useBaseUrlUtils} from '@docusaurus/useBaseUrl';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import type {Props} from '@theme/BlogPostPage/StructuredData';

export default function BlogPostStructuredData(props: Props): JSX.Element {
  const {siteConfig} = useDocusaurusContext();
  const {withBaseUrl} = useBaseUrlUtils();
  const {assets, frontMatter, metadata} = props;
  const {date, title, description} = metadata;

  const image = assets.image ?? frontMatter.image;
  const keywords = frontMatter.keywords ?? [];

  // an array of https://schema.org/Person
  const authorsStructuredData = metadata.authors.map((author) => ({
    '@type': 'Person',
    ...(author.name ? {name: author.name} : {}),
    ...(author.title ? {description: author.title} : {}),
    ...(author.url ? {url: author.url} : {}),
    ...(author.email ? {email: author.email} : {}),
    ...(author.imageURL ? {image: author.imageURL} : {}),
  }));

  const url = `${siteConfig.url}${metadata.permalink}`;
  const imageUrl = image ? withBaseUrl(image, {absolute: true}) : undefined;

  // details on structured data support: https://schema.org/BlogPosting
  // BlogPosting is one of the structured data types that Google explicitly
  // supports: https://developers.google.com/search/docs/appearance/structured-data/article#structured-data-type-definitions
  const blogPostStructuredData = {

Review comment (refactor):
FWIW there's slight duplication with `BlogListPage/StructuredData`. Don't have great refactoring suggestions though.

Code after:
/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import React from 'react';
import Head from '@docusaurus/Head';
import {useBlogPostStructuredData} from '@docusaurus/theme-common';

export default function BlogPostStructuredData(): JSX.Element {
  const structuredData = useBlogPostStructuredData();
  return (
    <Head>
      <script type="application/ld+json">
        {JSON.stringify(structuredData)}
      </script>
    </Head>
  );
}
Repository: facebook/docusaurus
File: packages/docusaurus-theme-classic/src/theme/BlogListPage/StructuredData/index.tsx (TypeScript)

Code before:
/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import React from 'react';
import {useBaseUrlUtils} from '@docusaurus/useBaseUrl';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import type {Props} from '@theme/BlogListPage/StructuredData';

export default function BlogListPageStructuredData(props: Props): JSX.Element {
  const {siteConfig} = useDocusaurusContext();
  const {withBaseUrl} = useBaseUrlUtils();

  const {
    metadata: {blogDescription, blogTitle, permalink},
  } = props;

  const url = `${siteConfig.url}${permalink}`;

  // details on structured data support: https://schema.org/Blog
  const blogStructuredData = {
    '@context': 'https://schema.org',
    '@type': 'Blog',
    '@id': url,
    mainEntityOfPage: url,
    headline: blogTitle,
    description: blogDescription,
    blogPost: props.items.map((blogItem) => {
      const {
        content: {assets, frontMatter, metadata},
      } = blogItem;
      const {date, title, description} = metadata;

      const image = assets.image ?? frontMatter.image;
      const keywords = frontMatter.keywords ?? [];

      // an array of https://schema.org/Person
      const authorsStructuredData = metadata.authors.map((author) => ({
        '@type': 'Person',
        ...(author.name ? {name: author.name} : {}),
        ...(author.title ? {description: author.title} : {}),
        ...(author.url ? {url: author.url} : {}),
        ...(author.email ? {email: author.email} : {}),
        ...(author.imageURL ? {image: author.imageURL} : {}),
      }));


Review comment (suggestion):
wonder if we could use TypeScript types for this?

https://github.com/google/schema-dts

Code after:
/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import React from 'react';
import Head from '@docusaurus/Head';
import {useBlogListPageStructuredData} from '@docusaurus/theme-common';
import type {Props} from '@theme/BlogListPage/StructuredData';

export default function BlogListPageStructuredData(props: Props): JSX.Element {
  const structuredData = useBlogListPageStructuredData(props);
  return (
    <Head>
      <script type="application/ld+json">
        {JSON.stringify(structuredData)}
      </script>
    </Head>
  );
}
Repository: facebook/docusaurus
File: packages/docusaurus-plugin-content-blog/src/blogUtils.ts (TypeScript)

Code before:

      const contentPathEditUrl = normalizeUrl([
        editUrl,
        posixPath(path.relative(siteDir, fileContentPath)),
      ]);

      return getEditUrl(blogPathRelative, contentPathEditUrl);
    }
    return undefined;
  }

  const baseBlogPermalink = normalizeUrl([baseUrl, routeBasePath]);

  const tagsBasePath = normalizeUrl([
    baseUrl,
    routeBasePath,
    tagsRouteBasePath,
  ]);
  const authors = getBlogPostAuthors({authorsMap, frontMatter, baseUrl});

  return {
    id: slug,
    metadata: {
      permalink,
      baseBlogPermalink,
      baseBlogTitle,
      editUrl: getBlogEditUrl(),
      source: aliasedSource,
      title,
      description,
      date,
      formattedDate,
      tags: normalizeFrontMatterTags(tagsBasePath, frontMatter.tags),
      readingTime: showReadingTime
        ? options.readingTime({
            content,
            frontMatter,
            defaultReadingTime,
          })
        : undefined,
      hasTruncateMarker: truncateMarker.test(content),
      authors,
      frontMatter,
      unlisted,
    },
    content,
  };
}

export async function generateBlogPosts(
  contentPaths: BlogContentPaths,

Review comment (suggestion):
that feels awkward to add those 2 attributes here, as they are global to the blog and not really blog post metadata

We'd rather create a new bundle/prop to inject it in all blog post routes instead of adding this here:

```js
          addRoute({
            path: metadata.permalink,
            component: blogPostComponent,
            exact: true,
            modules: {
              sidebar: aliasedSource(sidebarProp),
              content: metadata.source,
              // add blogMetadata bundle/prop here?
            },
          });
```

Since this data is relatively small we could also expose it through the blog global data too

Code after:
      const contentPathEditUrl = normalizeUrl([
        editUrl,
        posixPath(path.relative(siteDir, fileContentPath)),
      ]);

      return getEditUrl(blogPathRelative, contentPathEditUrl);
    }
    return undefined;
  }

  const tagsBasePath = normalizeUrl([
    baseUrl,
    routeBasePath,
    tagsRouteBasePath,
  ]);
  const authors = getBlogPostAuthors({authorsMap, frontMatter, baseUrl});

  return {
    id: slug,
    metadata: {
      permalink,
      editUrl: getBlogEditUrl(),
      source: aliasedSource,
      title,
      description,
      date,
      formattedDate,
      tags: normalizeFrontMatterTags(tagsBasePath, frontMatter.tags),
      readingTime: showReadingTime
        ? options.readingTime({
            content,
            frontMatter,
            defaultReadingTime,
          })
        : undefined,
      hasTruncateMarker: truncateMarker.test(content),
      authors,
      frontMatter,
      unlisted,
    },
    content,
  };
}

export async function generateBlogPosts(
  contentPaths: BlogContentPaths,
  context: LoadContext,
  options: PluginOptions,
): Promise<BlogPost[]> {
  const {include, exclude} = options;
Repository: facebook/docusaurus
File: packages/docusaurus-theme-classic/src/theme/BlogListPage/StructuredData/index.tsx (TypeScript)

Code before:
                '@type': 'ImageObject',
                '@id': imageUrl,
                url: imageUrl,
                contentUrl: imageUrl,
                caption: `title image for the blog post: ${title}`,
              },
            }
          : {}),
        ...(keywords ? {keywords} : {}),
      };
    }),
  };

  return (
    <script
      type="application/ld+json"
      // We're using dangerouslySetInnerHTML because we want to avoid React
      // transforming quotes into &quot; which upsets parsers.
      // The entire contents is a stringified JSON object so it is safe
      // eslint-disable-next-line react/no-danger
      dangerouslySetInnerHTML={{
        __html: JSON.stringify(blogStructuredData),
      }}
    />
  );
}


Review comment (refactor):
Maybe we'd want to create a helper component in theme-common to encapsulate this logic? 

We might use structured data in other places in the future, and we probably don't want to copy/paste this solution everywhere

Code after:
/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import React from 'react';
import Head from '@docusaurus/Head';
import {useBlogListPageStructuredData} from '@docusaurus/theme-common';
import type {Props} from '@theme/BlogListPage/StructuredData';

export default function BlogListPageStructuredData(props: Props): JSX.Element {
  const structuredData = useBlogListPageStructuredData(props);
  return (
    <Head>
      <script type="application/ld+json">
        {JSON.stringify(structuredData)}
      </script>
    </Head>
  );
}
Repository: facebook/docusaurus
File: packages/docusaurus-theme-classic/src/theme/BlogListPage/StructuredData/index.tsx (TypeScript)

Code before:
/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import React from 'react';
import {useBaseUrlUtils} from '@docusaurus/useBaseUrl';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import {
  makeImageStructuredData,
  makePersonStructuredData,
} from '@docusaurus/theme-common';
import type {Props} from '@theme/BlogListPage/StructuredData';
import StructuredData from '@theme/StructuredData';
import type {Blog, WithContext} from 'schema-dts';

export default function BlogListPageStructuredData(props: Props): JSX.Element {
  const {siteConfig} = useDocusaurusContext();
  const {withBaseUrl} = useBaseUrlUtils();

  const {
    metadata: {blogDescription, blogTitle, permalink},
  } = props;

  const url = `${siteConfig.url}${permalink}`;

  // details on structured data support: https://schema.org/Blog
  const blogStructuredData: WithContext<Blog> = {
    '@context': 'https://schema.org',
    '@type': 'Blog',
    '@id': url,
    mainEntityOfPage: url,
    headline: blogTitle,
    description: blogDescription,
    blogPost: props.items.map((blogItem) => {
      const {

Review comment (performance):
Can all this complexity be moved to `theme-common`?

This is not related to styling and is only technical so I'd rather put a minimal amount of code here. If we introduce a tailwind theme someday we shouldn't have to copy/paste this.

Code should be something such as:


```tsx
const structuredData = useBlogListPageStructuredData(props);
return <StructuredData structuredData={blogStructuredData} />
```

Or even just:

```tsx
<BlogListPageStructuredData (...props}/>
```

Users can still swizzle this and override the logic if they want. 

Of course they can't tweak the logic we use to generate that structured data but they could still copy/paste it and create their own blog structured data utils if they really want to.

Code after:
/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import React from 'react';
import Head from '@docusaurus/Head';
import {useBlogListPageStructuredData} from '@docusaurus/theme-common';
import type {Props} from '@theme/BlogListPage/StructuredData';

export default function BlogListPageStructuredData(props: Props): JSX.Element {
  const structuredData = useBlogListPageStructuredData(props);
  return (
    <Head>
      <script type="application/ld+json">
        {JSON.stringify(structuredData)}
      </script>
    </Head>
  );
}
Repository: facebook/docusaurus
File: packages/docusaurus-theme-classic/src/theme/BlogListPage/StructuredData/index.tsx (TypeScript)

Code before:
        content: {assets, frontMatter, metadata},
      } = blogItem;
      const {date, title, description} = metadata;

      const image = assets.image ?? frontMatter.image;
      const keywords = frontMatter.keywords ?? [];

      const authorsStructuredData = metadata.authors.map(
        makePersonStructuredData,
      );

      const blogUrl = `${siteConfig.url}${metadata.permalink}`;

      return {
        '@type': 'BlogPosting',
        '@id': blogUrl,
        mainEntityOfPage: blogUrl,
        url: blogUrl,
        headline: title,
        name: title,
        description,
        datePublished: date,
        author:
          authorsStructuredData.length === 1
            ? authorsStructuredData[0]
            : authorsStructuredData,
        ...(image
          ? {
              image: makeImageStructuredData({
                imageUrl: withBaseUrl(image, {absolute: true}),
                caption: `title image for the blog post: ${title}`,
              }),
            }
          : {}),
        ...(keywords ? {keywords} : {}),
      };
    }),
  };

  return <StructuredData structuredData={blogStructuredData} />;
}


Review comment (security):
that's complexity I'd isolate in a `getAuthor` function

Code after:
/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import React from 'react';
import Head from '@docusaurus/Head';
import {useBlogListPageStructuredData} from '@docusaurus/theme-common';
import type {Props} from '@theme/BlogListPage/StructuredData';

export default function BlogListPageStructuredData(props: Props): JSX.Element {
  const structuredData = useBlogListPageStructuredData(props);
  return (
    <Head>
      <script type="application/ld+json">
        {JSON.stringify(structuredData)}
      </script>
    </Head>
  );
}
Repository: facebook/docusaurus
File: packages/docusaurus-theme-classic/src/theme/BlogListPage/StructuredData/index.tsx (TypeScript)

Code before:
  makeImageStructuredData,
  makePersonStructuredData,
} from '@docusaurus/theme-common';
import type {Props} from '@theme/BlogListPage/StructuredData';
import StructuredData from '@theme/StructuredData';
import type {Blog, WithContext} from 'schema-dts';

export default function BlogListPageStructuredData(props: Props): JSX.Element {
  const {siteConfig} = useDocusaurusContext();
  const {withBaseUrl} = useBaseUrlUtils();

  const {
    metadata: {blogDescription, blogTitle, permalink},
  } = props;

  const url = `${siteConfig.url}${permalink}`;

  // details on structured data support: https://schema.org/Blog
  const blogStructuredData: WithContext<Blog> = {
    '@context': 'https://schema.org',
    '@type': 'Blog',
    '@id': url,
    mainEntityOfPage: url,
    headline: blogTitle,
    description: blogDescription,
    blogPost: props.items.map((blogItem) => {
      const {
        content: {assets, frontMatter, metadata},
      } = blogItem;
      const {date, title, description} = metadata;

      const image = assets.image ?? frontMatter.image;
      const keywords = frontMatter.keywords ?? [];

      const authorsStructuredData = metadata.authors.map(
        makePersonStructuredData,
      );

      const blogUrl = `${siteConfig.url}${metadata.permalink}`;

      return {
        '@type': 'BlogPosting',
        '@id': blogUrl,
        mainEntityOfPage: blogUrl,
        url: blogUrl,
        headline: title,
        name: title,
        description,
        datePublished: date,
        author:
          authorsStructuredData.length === 1

Review comment (performance):
that's complexity I'd encapsulate in a `getBlogPost` function

Code after:
/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import React from 'react';
import Head from '@docusaurus/Head';
import {useBlogListPageStructuredData} from '@docusaurus/theme-common';
import type {Props} from '@theme/BlogListPage/StructuredData';

export default function BlogListPageStructuredData(props: Props): JSX.Element {
  const structuredData = useBlogListPageStructuredData(props);
  return (
    <Head>
      <script type="application/ld+json">
        {JSON.stringify(structuredData)}
      </script>
    </Head>
  );
}