Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@
exports[`transformLinks plugin > transform md links to <a /> 1`] = `
"[asset](https://example.com/asset.pdf)

<a target="_blank" data-noBrokenLinkCheck={true} href={require("!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset.pdf").default} />
<a target="_blank" data-noBrokenLinkCheck={true} data-noTrailingSlash={true} href={require("!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset.pdf").default} />

<a target="_blank" data-noBrokenLinkCheck={true} href={require("!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset.pdf").default}>asset</a>
<a target="_blank" data-noBrokenLinkCheck={true} data-noTrailingSlash={true} href={require("!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset.pdf").default}>asset</a>

in paragraph <a target="_blank" data-noBrokenLinkCheck={true} href={require("!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset.pdf").default}>asset</a>
in paragraph <a target="_blank" data-noBrokenLinkCheck={true} data-noTrailingSlash={true} href={require("!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset.pdf").default}>asset</a>

<a target="_blank" data-noBrokenLinkCheck={true} href={require("!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset (2).pdf").default}>asset with URL encoded chars</a>
<a target="_blank" data-noBrokenLinkCheck={true} data-noTrailingSlash={true} href={require("!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset (2).pdf").default}>asset with URL encoded chars</a>

<a target="_blank" data-noBrokenLinkCheck={true} href={require("!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset.pdf").default + '#page=2'}>asset with hash</a>
<a target="_blank" data-noBrokenLinkCheck={true} data-noTrailingSlash={true} href={require("!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset.pdf").default + '#page=2'}>asset with hash</a>

<a target="_blank" data-noBrokenLinkCheck={true} href={require("!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset.pdf").default} title="Title">asset</a>
<a target="_blank" data-noBrokenLinkCheck={true} data-noTrailingSlash={true} href={require("!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset.pdf").default} title="Title">asset</a>

[page](noUrl.md)

Expand All @@ -27,23 +27,23 @@ in paragraph <a target="_blank" data-noBrokenLinkCheck={true} href={require("!<P

[assets](/github/!file-loader!/assets.pdf)

<a target="_blank" data-noBrokenLinkCheck={true} href={require("!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset.pdf").default}>asset</a>
<a target="_blank" data-noBrokenLinkCheck={true} data-noTrailingSlash={true} href={require("!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset.pdf").default}>asset</a>

<a target="_blank" data-noBrokenLinkCheck={true} href={require("!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static2/asset2.pdf").default}>asset2</a>
<a target="_blank" data-noBrokenLinkCheck={true} data-noTrailingSlash={true} href={require("!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static2/asset2.pdf").default}>asset2</a>

<a target="_blank" data-noBrokenLinkCheck={true} href={require("!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAsset.pdf").default}>staticAsset.pdf</a>
<a target="_blank" data-noBrokenLinkCheck={true} data-noTrailingSlash={true} href={require("!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAsset.pdf").default}>staticAsset.pdf</a>

<a target="_blank" data-noBrokenLinkCheck={true} href={require("!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAsset.pdf").default}>@site/static/staticAsset.pdf</a>
<a target="_blank" data-noBrokenLinkCheck={true} data-noTrailingSlash={true} href={require("!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAsset.pdf").default}>@site/static/staticAsset.pdf</a>

<a target="_blank" data-noBrokenLinkCheck={true} href={require("!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAsset.pdf").default + '#page=2'} title="Title">@site/static/staticAsset.pdf</a>
<a target="_blank" data-noBrokenLinkCheck={true} data-noTrailingSlash={true} href={require("!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAsset.pdf").default + '#page=2'} title="Title">@site/static/staticAsset.pdf</a>

<a target="_blank" data-noBrokenLinkCheck={true} href={require("!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAsset.pdf").default}>Just staticAsset.pdf</a>, and <a target="_blank" data-noBrokenLinkCheck={true} href={require("!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAsset.pdf").default}>**awesome** staticAsset 2.pdf 'It is really "AWESOME"'</a>, but also <a target="_blank" data-noBrokenLinkCheck={true} href={require("!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAsset.pdf").default}>coded \`staticAsset 3.pdf\`</a>
<a target="_blank" data-noBrokenLinkCheck={true} data-noTrailingSlash={true} href={require("!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAsset.pdf").default}>Just staticAsset.pdf</a>, and <a target="_blank" data-noBrokenLinkCheck={true} data-noTrailingSlash={true} href={require("!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAsset.pdf").default}>**awesome** staticAsset 2.pdf 'It is really "AWESOME"'</a>, but also <a target="_blank" data-noBrokenLinkCheck={true} data-noTrailingSlash={true} href={require("!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAsset.pdf").default}>coded \`staticAsset 3.pdf\`</a>

<a target="_blank" data-noBrokenLinkCheck={true} href={require("!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAssetImage.png").default}><img alt="Clickable Docusaurus logo" src={require("!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/staticAssetImage.png").default} width="200" height="200" /></a>
<a target="_blank" data-noBrokenLinkCheck={true} data-noTrailingSlash={true} href={require("!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/staticAssetImage.png").default}><img alt="Clickable Docusaurus logo" src={require("!<PROJECT_ROOT>/node_modules/url-loader/dist/cjs.js?limit=10000&name=assets/images/[name]-[contenthash].[ext]&fallback=<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js!./static/staticAssetImage.png").default} width="200" height="200" /></a>

<a target="_blank" data-noBrokenLinkCheck={true} href={require("!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset.pdf").default}><span style={{color: "red"}}>Stylized link to asset file</span></a>
<a target="_blank" data-noBrokenLinkCheck={true} data-noTrailingSlash={true} href={require("!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./asset.pdf").default}><span style={{color: "red"}}>Stylized link to asset file</span></a>

<a target="_blank" data-noBrokenLinkCheck={true} href={require("./data.raw!=!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./data.json").default}>JSON</a>
<a target="_blank" data-noBrokenLinkCheck={true} data-noTrailingSlash={true} href={require("./data.raw!=!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./data.json").default}>JSON</a>

<a target="_blank" data-noBrokenLinkCheck={true} href={require("./static/static-json.raw!=!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/static-json.json").default}>static JSON</a>"
<a target="_blank" data-noBrokenLinkCheck={true} data-noTrailingSlash={true} href={require("./static/static-json.raw!=!<PROJECT_ROOT>/node_modules/file-loader/dist/cjs.js?name=assets/files/[name]-[contenthash].[ext]!./static/static-json.json").default}>static JSON</a>"
`;
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ describe('transformLinks plugin', () => {
it('transform md links to <a />', async () => {
// TODO split fixture in many smaller test cases
const result = await processFixture('asset');
expect(result).toContain('data-noTrailingSlash={true}');
expect(result).toMatchSnapshot();
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ async function toAssetRequireNode(
});

// Assets are not routes, and are required by Webpack already
// They should not trigger the broken link checker
// They should not trigger route-specific link handling
attributes.push({
type: 'mdxJsxAttribute',
name: 'data-noBrokenLinkCheck',
Expand All @@ -147,6 +147,31 @@ async function toAssetRequireNode(
},
});

attributes.push({
type: 'mdxJsxAttribute',
name: 'data-noTrailingSlash',
value: {
type: 'mdxJsxAttributeValueExpression',
value: 'true',
data: {
estree: {
type: 'Program',
body: [
{
type: 'ExpressionStatement',
expression: {
type: 'Literal',
value: true,
raw: 'true',
},
},
],
sourceType: 'module',
comments: [],
},
},
},
});
attributes.push({
type: 'mdxJsxAttribute',
name: 'href',
Expand Down
3 changes: 3 additions & 0 deletions packages/docusaurus-module-type-aliases/src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,9 @@ declare module '@docusaurus/Link' {

/** Escape hatch in case broken links check doesn't make sense. */
readonly 'data-noBrokenLinkCheck'?: boolean;

/** Escape hatch for links that should preserve their exact URL. */
readonly 'data-noTrailingSlash'?: boolean;
};
export default function Link(props: Props): ReactNode;
}
Expand Down
3 changes: 2 additions & 1 deletion packages/docusaurus/src/client/exports/Link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ function Link({
activeClassName,
isActive,
'data-noBrokenLinkCheck': noBrokenLinkCheck,
'data-noTrailingSlash': noTrailingSlash,
autoAddBaseUrl = true,
...props
}: Props): ReactNode {
Expand Down Expand Up @@ -88,7 +89,7 @@ function Link({
targetLink = targetLink?.slice(1);
}

if (targetLink && isInternal) {
if (targetLink && isInternal && !noTrailingSlash) {
targetLink = applyTrailingSlash(targetLink, {trailingSlash, baseUrl});
}

Expand Down
18 changes: 18 additions & 0 deletions packages/docusaurus/src/client/exports/__tests__/Link.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,24 @@ describe('<Link>', () => {
`);
});

it('does not add a trailing slash to an asset link', () => {
const {container} = render(
<Link
href="/assets/files/example-a1b2c3.docx"
target="_blank"
data-noTrailingSlash
/>,
{trailingSlash: true},
);
expect(container.firstElementChild).toMatchInlineSnapshot(`
<a
data-test-link-type="regular"
href="/assets/files/example-a1b2c3.docx"
target="_blank"
/>
`);
});

it("can render '/docs/intro/' with trailingSlash false", () => {
const {container} = render(<Link to="/docs/intro/" />, {
trailingSlash: false,
Expand Down