Repository: facebook/docusaurus
File: packages/docusaurus-plugin-content-blog/src/blogUtils.ts (TypeScript)

Code before:
  BlogTags,
  BlogPaginated,
} from '@docusaurus/plugin-content-blog';
import type {BlogContentPaths} from './types';

export function truncate(fileString: string, truncateMarker: RegExp): string {
  return fileString.split(truncateMarker, 1).shift()!;
}

function reportTruncateMarkerProblem({
  blogSourceRelative,
  truncateMarker,
  options,
  content,
}: {
  content: string;
  truncateMarker: RegExp;
  blogSourceRelative: string;
  options: Pick<PluginOptions, 'onUntruncatedBlogPost'>;
}): void {
  if (!truncateMarker.test(content)) {
    logger.report(options.onUntruncatedBlogPost)(
      logger.interpolate`Blog post path=${blogSourceRelative} is not truncated.`,
    );
  }
}

export function paginateBlogPosts({
  blogPosts,
  basePageUrl,
  blogTitle,
  blogDescription,
  postsPerPageOption,
  pageBasePath,
}: {
  blogPosts: BlogPost[];
  basePageUrl: string;
  blogTitle: string;
  blogDescription: string;
  postsPerPageOption: number | 'ALL';
  pageBasePath: string;
}): BlogPaginated[] {
  const totalCount = blogPosts.length;
  const postsPerPage =
    postsPerPageOption === 'ALL' ? totalCount : postsPerPageOption;
  const numberOfPages = Math.max(1, Math.ceil(totalCount / postsPerPage));

  const pages: BlogPaginated[] = [];

  function permalink(page: number) {
    return page > 0

Review comment (performance):
We shouldn't run this Regex against the content twice: this can be expensive and is useless work. We already run it later in the blog post processing to compute the `hasTruncateMarker` meta attribute. 

Note that in the future we'll probably handle that with Remark (the RegExp is the historical solution).

I'd prefer if:
- we emit the warning based on `blogPost.metadata.hasTruncateMarker`
- we emit a single report for all the blog posts
- we explain in the message that this can be turned off with the blog `onUntruncatedBlogPost: 'ignore'` option. Many sites run with untruncated blogs on purpose, let's give them a better upgrading experience if warn is the default.


The function should rather be something like this:

```ts
function reportTruncateMarkerProblem({
  blogPosts,
  onUntruncatedBlogPost,
}: {
  blogPosts: BlogPost[],
  onUntruncatedBlogPost: PluginOptions['onUntruncatedBlogPost']
}): void {
  const untruncatedBlogPosts = blogPosts.filter(p => !p.metadata.hasTruncateMarker)
  if (onUntruncatedBlogPost !== "ignore" && onUntruncatedBlogPost.length > 0) {
    const message = `Blabla there are untruncated blog posts:
${untruncatedBlogPosts.map(getPath).join('\n- ')}
Blabla additional help`
    logger.report(options.onUntruncatedBlogPost)(message);
  }
}
```


Code after:
  BlogPost,
  BlogTags,
  BlogPaginated,
} from '@docusaurus/plugin-content-blog';
import type {BlogContentPaths} from './types';

export function truncate(fileString: string, truncateMarker: RegExp): string {
  return fileString.split(truncateMarker, 1).shift()!;
}

export function reportUntruncatedBlogPosts({
  blogPosts,
  onUntruncatedBlogPosts,
}: {
  blogPosts: BlogPost[];
  onUntruncatedBlogPosts: PluginOptions['onUntruncatedBlogPosts'];
}): void {
  const untruncatedBlogPosts = blogPosts.filter(
    (p) => !p.metadata.hasTruncateMarker,
  );
  if (onUntruncatedBlogPosts !== 'ignore' && untruncatedBlogPosts.length > 0) {
    const message = logger.interpolate`Docusaurus found blog posts without truncation markers:
- ${untruncatedBlogPosts
      .map((p) => logger.path(aliasedSitePathToRelativePath(p.metadata.source)))
      .join('\n- ')}

We recommend using truncation markers (code=${`<!-- truncate -->`} or code=${`{/* truncate */}`}) in blog posts to create shorter previews on blog paginated lists.
Tip: turn this security off with the code=${`onUntruncatedBlogPosts: 'ignore'`} blog plugin option.`;
    logger.report(onUntruncatedBlogPosts)(message);
  }
}

export function paginateBlogPosts({
  blogPosts,
  basePageUrl,
  blogTitle,
  blogDescription,
  postsPerPageOption,
  pageBasePath,
}: {
  blogPosts: BlogPost[];
  basePageUrl: string;
  blogTitle: string;
  blogDescription: string;
  postsPerPageOption: number | 'ALL';
  pageBasePath: string;
}): BlogPaginated[] {
  const totalCount = blogPosts.length;
  const postsPerPage =
    postsPerPageOption === 'ALL' ? totalCount : postsPerPageOption;
  const numberOfPages = Math.max(1, Math.ceil(totalCount / postsPerPage));