Skip to content

Commit

Permalink
fix: ambiguous relative link problem in md (#1491)
Browse files Browse the repository at this point in the history
  • Loading branch information
PeachScript authored Feb 21, 2023
1 parent 96040d6 commit c60ab58
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 14 deletions.
2 changes: 1 addition & 1 deletion src/features/compile/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export default (api: IApi) => {
resolve: api.config.resolve,
extraRemarkPlugins: api.config.extraRemarkPlugins,
extraRehypePlugins: api.config.extraRehypePlugins,
routers: api.appData.routes,
routes: api.appData.routes,
};

memo.module
Expand Down
4 changes: 4 additions & 0 deletions src/features/tabs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ export function getTabKeyFromFile(file: string) {
return file.match(/\$tab-([^.]+)/)![1];
}

export function getHostForTabRouteFile(file: string) {
return file.replace(/\$tab-[^.]+\./, '');
}

/**
* plugin for add conventional tab and plugin tab into page content
*/
Expand Down
4 changes: 2 additions & 2 deletions src/loaders/markdown/transformer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export interface IMdTransformerOptions {
resolve: IDumiConfig['resolve'];
extraRemarkPlugins?: IDumiConfig['extraRemarkPlugins'];
extraRehypePlugins?: IDumiConfig['extraRehypePlugins'];
routers: Record<string, IRoute>;
routes: Record<string, IRoute>;
}

export interface IMdTransformerResult {
Expand Down Expand Up @@ -147,7 +147,7 @@ export default async (raw: string, opts: IMdTransformerOptions) => {
.use(rehypeSlug)
.use(rehypeLink, {
fileAbsPath: opts.fileAbsPath,
routers: opts.routers,
routes: opts.routes,
})
.use(rehypeAutolinkHeadings)
.use(rehypeIsolation)
Expand Down
53 changes: 42 additions & 11 deletions src/loaders/markdown/transformer/rehypeLink.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { getHostForTabRouteFile } from '@/features/tabs';
import type { Root } from 'hast';
import path from 'path';
import { lodash, winPath } from 'umi/plugin-utils';
import { lodash, logger, winPath } from 'umi/plugin-utils';
import type { Transformer } from 'unified';
import url from 'url';
import type { IMdTransformerOptions } from '.';
Expand All @@ -13,10 +14,7 @@ let SKIP: typeof import('unist-util-visit').SKIP;
({ visit, SKIP } = await import('unist-util-visit'));
})();

type IRehypeLinkOptions = Pick<
IMdTransformerOptions,
'fileAbsPath' | 'routers'
>;
type IRehypeLinkOptions = Pick<IMdTransformerOptions, 'fileAbsPath' | 'routes'>;

export default function rehypeLink(
opts: IRehypeLinkOptions,
Expand All @@ -26,22 +24,55 @@ export default function rehypeLink(
if (node.tagName === 'a' && typeof node.properties?.href === 'string') {
const href = node.properties.href;
const parsedUrl = url.parse(href);
const hostAbsPath = getHostForTabRouteFile(opts.fileAbsPath);

// handle internal link
if (parsedUrl.hostname) return SKIP;

// handle markdown link
if (/\.md$/i.test(parsedUrl.pathname!)) {
const { routers } = opts;
// handle markdown link
const { routes } = opts;
const absPath = winPath(
path.resolve(opts.fileAbsPath, '..', parsedUrl.pathname!),
path.resolve(hostAbsPath, '..', parsedUrl.pathname!),
);

Object.keys(routers).forEach((key) => {
if (routers[key].file === absPath) {
parsedUrl.pathname = routers[key].absPath;
Object.keys(routes).forEach((key) => {
if (routes[key].file === absPath) {
parsedUrl.pathname = routes[key].absPath;
}
});
} else if (
/^\.?\.\//.test(parsedUrl.pathname!) ||
/^(\w+:)?\/\//.test(parsedUrl.pathname!)
) {
// handle relative link
// transform relative link to absolute link
// because react-router@6 and HTML href are different in processing relative link
// e.g. in /a page, <Link to="./b">b</Link> will be resolved to /a/b in react-router@6
// but will be resolved to /b in <a href="./b">b</a>
const routes = Object.values(opts.routes);
const basePath = routes.find(
(route) => route.file === hostAbsPath,
)!.absPath;
const htmlTargetPath = url.resolve(basePath, parsedUrl.pathname!);
const rr6TargetPath = winPath(
path.resolve(basePath, parsedUrl.pathname!),
);

// use html way first
parsedUrl.pathname = htmlTargetPath;

// warn if user already use react-router@6 way
if (
routes.every((route) => route.absPath !== htmlTargetPath) &&
routes.some((route) => route.absPath === rr6TargetPath)
) {
parsedUrl.pathname = rr6TargetPath;
logger.warn(
`Detected ambiguous link \`${href}\` in \`${opts.fileAbsPath}\`, please use \`./xxx.md\` file path instead of normal relative path, dumi will deprecate this behavior in the future.
See more: https://github.com/umijs/dumi/pull/1491`,
);
}
}

parent!.children.splice(i!, 1, {
Expand Down

0 comments on commit c60ab58

Please sign in to comment.