Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,6 @@
"*.min.*",
"jest/vendor"
],
"ignoreRegExpList": ["Email", "Urls", "#[\\w-]*"],
"ignoreRegExpList": ["Email", "Urls", "#[\\w-]*", "\\u\\{[0-9A-F]{4}\\}"],
"enableFiletypes": ["mdx"]
}
12 changes: 6 additions & 6 deletions .github/workflows/argos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,11 @@ jobs:
- name: Take and upload Argos screenshots
run: pnpm argos:screenshot

# We rebuild the site with unminified assets
# This makes it easier to review text snapshots on Argos
- name: Build website for text snapshots
run: pnpm argos:build
env:
# Easier HTML diffs to review on Argos
# an alternative could be to use Prettier/Oxfmt on build output
SKIP_HTML_MINIFICATION: true
run: pnpm argos:build:text-snapshots
- name: Format HTML for easier Argos diffs
run: pnpm argos:format:text-snapshots
- name: Upload Argos text snapshots
run: pnpm argos:upload-text-snapshots
run: pnpm argos:upload:text-snapshots
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ jobs:
env:
# Our website should build even with limited memory
# See https://github.com/facebook/docusaurus/pull/10590
NODE_OPTIONS: '--max-old-space-size=250'
NODE_OPTIONS: '--max-old-space-size=300'
DOCUSAURUS_PERF_LOGGER: 'true'
- name: Docusaurus site CSS order
run: pnpm --filter website test:css-order
Expand Down
5 changes: 5 additions & 0 deletions .oxfmtrc.website.build.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"$schema": "./node_modules/oxfmt/configuration_schema.json",
"printWidth": 80,
"ignorePatterns": ["**/badSyntax.css", "**/badSyntax.js"]
}
23 changes: 17 additions & 6 deletions argos/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,38 @@ This workspace can be run manually, but is generally run through the [Argos GitH

## Workflow overview

The workflow execute those following steps:
This workflow runs for `main` and PR branches, and add a commit status to each PR with a visual diff that we can easily inspect.

The workflow execute the 2 main steps below:

### Screenshots

- Build the website locally with `pnpm argos:build` (a variant of `pnpm build:website:fast`)
- Start the website server with `pnpm serve:website` on [http://localhost:3000](http://localhost:3000)
- Take screenshots of all pages found in `sitemap.xml` with Playwright
- Upload all screenshots to [Argos CI](https://argos-ci.com) using the [Playwright reporter](https://argos-ci.com/docs/reference/playwright)
- Upload [HTML/CSS/JS files to also diff them on Argos](https://argos-ci.com/docs/learn/how-to-guides/visual-coverage/compare-non-image-files) using `pnpm argos:upload-text-snapshots`

This workflow runs for `main` and PR branches, and add a commit status to each PR with a visual diff that we can easily inspect.
### Text snapshots

- Rebuild - this time with HTML unminified/formatted.
- Upload [HTML/CSS/JS files to also diff them on Argos](https://argos-ci.com/docs/learn/how-to-guides/visual-coverage/compare-non-image-files) using `pnpm argos:upload-text-snapshots`

## Run manually

To run this manually, use:
To run the screenshot step manually:

```bash
pnpm argos:build
pnpm argos:screenshot
pnpm argos:upload-text-snapshots
```

The Playwright reporter will upload the screenshots to Argos.
To run the text-snapshots step manually:

```bash
pnpm argos:build:text-snapshots
pnpm argos:format:text-snapshots
pnpm argos:upload:text-snapshots
```

## How to modify

Expand Down
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@
"argos": "pnpm argos:build && pnpm argos:screenshot && argos:upload-text-snapshots",
"argos:build": "cross-env DOCUSAURUS_ARGOS_BUILD=true pnpm build:website:fast --dev",
"argos:screenshot": "pnpm --filter argos screenshot",
"argos:upload-text-snapshots": "pnpm --filter argos upload-text-snapshots",
"argos:build:text-snapshots": "cross-env DOCUSAURUS_ARGOS_BUILD=true SKIP_HTML_MINIFICATION=true pnpm build:website:fast --dev --no-minify",
"argos:format:text-snapshots": "pnpm format:website:build",
"argos:upload:text-snapshots": "pnpm --filter argos upload-text-snapshots",
"canary": "pnpm canary:bumpVersion && pnpm canary:publish",
"canary:getCoreVersion": "node -p \"require('./packages/docusaurus/package.json').version.split('-')[0]\"",
"canary:version": "echo `pnpm --silent canary:getCoreVersion`-canary-`git rev-list --count HEAD`+`git rev-parse --short HEAD`",
Expand All @@ -48,6 +50,7 @@
"postinstall": "pnpm build:packages",
"prepare": "husky",
"format": "oxfmt .",
"format:website:build": "oxfmt --config .oxfmtrc.website.build.json website/build",
"format:diff": "oxfmt --list-different .",
"lint": "pnpm lint:js && pnpm lint:style && pnpm lint:SPELLING && pnpm lint:syncpack",
"lint:ci": "pnpm lint:js --quiet && pnpm lint:style && pnpm lint:spelling && pnpm lint:syncpack",
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

65 changes: 65 additions & 0 deletions packages/docusaurus-utils/src/__tests__/markdownUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,71 @@ describe('createExcerpt', () => {
`),
).toBe('Lorem ipsum dolor sit amet, consectetur adipiscing elit.');
});

it('creates excerpt with XML tag inside inline code', () => {
expect(
createExcerpt(dedent`
# Markdown Regular Title

This paragraph includes a link to the \`<metadata>\` documentation.
`),
).toBe('This paragraph includes a link to the <metadata> documentation.');
});

it('creates excerpt with XML tag inside inline code with hyperlink', () => {
expect(
createExcerpt(dedent`
# Markdown Regular Title

This paragraph includes a link to the [\`<metadata>\`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/metadata) documentation.
`),
).toBe('This paragraph includes a link to the <metadata> documentation.');
});

describe('complex case', () => {
const complexString =
'_aa_ *bb* **cc** ~~dd~~ <ee>ff</ee> ![gg](hh.png) [ii](jj) {#kk}';

it('creates excerpt for complex string', () => {
expect(
createExcerpt(dedent`
# Markdown Regular Title

Escaping ${complexString} is hard.
`),
).toBe('Escaping aa bb cc dd ff gg ii is hard.');
});

it('creates excerpt for complex string in inline code block', () => {
expect(
createExcerpt(dedent`
# Markdown Regular Title

Escaping \`${complexString}\` is hard.
`),
).toBe(
'Escaping _aa_ *bb* **cc** ~~dd~~ <ee>ff</ee> ![gg](hh.png) [ii](jj) {#kk} is hard.',
);
});
});

describe('internal markers', () => {
// Internal markers are used to escape/unescape MDX special chars
// within inline code blocks. We want to make sure the provided input
// doesn't conflict with the internal usage we have.

it('creates excerpt without letting the input forge internal markers', () => {
expect(createExcerpt('A \u{FFFE}60\u{FFFF} B')).toBe('A 60 B');
});

it('creates excerpt without letting inline code forge internal markers', () => {
expect(createExcerpt('A `\u{FFFE}60\u{FFFF}` B')).toBe('A 60 B');
});

it('creates no excerpt for a line of Unicode non-characters', () => {
expect(createExcerpt('\u{FFFE}\u{FFFF}')).toBeUndefined();
});
});
});

describe('parseMarkdownContentTitle', () => {
Expand Down
63 changes: 59 additions & 4 deletions packages/docusaurus-utils/src/markdownUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import logger from '@docusaurus/logger';
import matter from '@11ty/gray-matter';

import type {
ParseFrontMatter,
DefaultParseFrontMatter,
Expand All @@ -16,6 +17,41 @@ import type {
// server-side when we infer metadata like `title` and `description` from the
// content. Most parsing is still done in MDX through the mdx-loader.

const MDXEscapingUtils = (function () {
const MARKUP_CHARS = ['_', ':', '*', '<', '>', '~', '!', '[', ']', '{', '}'];

const markerOf = (char: string) => `\u{FFFE}${char.codePointAt(0)}\u{FFFF}`;

const MARKUP_CHARS_ESCAPE_MAP = new Map(
MARKUP_CHARS.map((char) => [char, markerOf(char)]),
);
const MARKUP_CHARS_UNESCAPE_MAP = new Map(
MARKUP_CHARS.map((char) => [markerOf(char), char]),
);

const MARKUP_CHARS_REGEX = new RegExp(
`[${RegExp.escape(MARKUP_CHARS.join(''))}]`,
'g',
);
const MARKUP_MARKERS_REGEX = /\u{FFFE}\d+\u{FFFF}/gu;

function escapeMDX(str: string) {
return str.replace(
MARKUP_CHARS_REGEX,
(char) => MARKUP_CHARS_ESCAPE_MAP.get(char)!,
);
}

function unescapeMDX(str: string) {
return str.replace(
MARKUP_MARKERS_REGEX,
(marker) => MARKUP_CHARS_UNESCAPE_MAP.get(marker) ?? marker,
);
}

return {escapeMDX, unescapeMDX};
})();

/**
* Hacky temporary escape hatch for Crowdin bad MDX support
* See https://docusaurus.io/docs/i18n/crowdin#mdx
Expand Down Expand Up @@ -142,7 +178,26 @@ export function createExcerpt(fileString: string): string | undefined {
continue;
}

const cleanedLine = fileLine
// Pre/postprocessing to handle MDX special chars within inline code blocks
// See https://github.com/facebook/docusaurus/pull/11821
function preprocessLine(str: string) {
return (
str
// Ignore internal Unicode markers found in input
// This ensures no possible conflict with our MDX escaping logic
.replace(/[\u{FFFE}\u{FFFF}]/gu, '')
// Unwrap inline code and escape special MDX chars within it
.replace(/`(?<text>.+?)`/g, (_, text) => {
return MDXEscapingUtils.escapeMDX(text);
})
);
}
function postProcessLine(str: string) {
// Restore escaped MDX chars that have been previously escaped
return MDXEscapingUtils.unescapeMDX(str);
}

const cleanedLine = preprocessLine(fileLine)
// Remove HTML tags.
.replace(/<[^>]*>/g, '')
// Remove Title headers
Expand All @@ -159,8 +214,6 @@ export function createExcerpt(fileString: string): string | undefined {
.replace(/\[\^.+?\](?:: .*$)?/g, '')
// Remove inline links.
.replace(/\[(?<alt>.*?)\][[(].*?[\])]/g, '$1')
// Remove inline code.
.replace(/`(?<text>.+?)`/g, '$1')
// Remove blockquotes.
.replace(/^\s{0,3}>\s?/g, '')
// Remove admonition definition.
Expand All @@ -169,10 +222,12 @@ export function createExcerpt(fileString: string): string | undefined {
.replace(/\s?:(?:::|[^:\n])+:/g, '')
// Remove custom Markdown heading id.
.replace(/\{#*[\w-]+\}/, '')
// Collapse whitespace left behind by the removals above.
.replace(/\s+/g, ' ')
.trim();

if (cleanedLine) {
return cleanedLine;
return postProcessLine(cleanedLine);
}
}

Expand Down
1 change: 1 addition & 0 deletions project-words.txt
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,7 @@ unlinkable
Unlisteds
unlisteds
unlocalized
unminified
unstub
unswizzle
upvotes
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Doc with Complex Description

One <strong>Two</strong> _Three_ `<Four>` `:Five:` <em>Six</em> ![Seven](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII)
1 change: 1 addition & 0 deletions website/_dogfooding/docs-tests-sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const sidebars = {
},
'doc-without-sidebar',
'doc-with-another-sidebar',
'doc-with-complex-description',
'doc-with-last-update',
{
type: 'category',
Expand Down
Loading