[lexical-markdown] Bug Fix: Link Transformer URL Protocol Handling (#7499)

This commit is contained in:
AashishRichhariya
2025-05-01 20:32:08 +05:30
committed by GitHub
parent 6c458e4289
commit 0aa2d5aa73
3 changed files with 75 additions and 1 deletions

View File

@ -37,6 +37,8 @@ import {
TextNode,
} from 'lexical';
import {formatUrl} from './utils';
export type Transformer =
| ElementTransformer
| MultilineElementTransformer
@ -559,7 +561,8 @@ export const LINK: TextMatchTransformer = {
/(?:\[([^[]+)\])(?:\((?:([^()\s]+)(?:\s"((?:[^"]*\\")*[^"]*)"\s*)?)\))$/,
replace: (textNode, match) => {
const [, linkText, linkUrl, linkTitle] = match;
const linkNode = $createLinkNode(linkUrl, {title: linkTitle});
const formattedUrl = formatUrl(linkUrl);
const linkNode = $createLinkNode(formattedUrl, {title: linkTitle});
const linkTextNode = $createTextNode(linkText);
linkTextNode.setFormat(textNode.getFormat());
linkNode.append(linkTextNode);

View File

@ -27,6 +27,7 @@ import {
MultilineElementTransformer,
normalizeMarkdown,
} from '../../MarkdownTransformers';
import {formatUrl} from '../../utils';
const SIMPLE_INLINE_JSX_MATCHER: TextMatchTransformer = {
dependencies: [LinkNode],
@ -888,3 +889,39 @@ E3
expect(normalizeMarkdown(markdown, false)).toBe(markdown);
});
});
describe('formatUrl', () => {
it('should not modify URLs with protocols', () => {
expect(formatUrl('https://example.com')).toBe('https://example.com');
expect(formatUrl('http://example.com')).toBe('http://example.com');
expect(formatUrl('mailto:user@example.com')).toBe(
'mailto:user@example.com',
);
expect(formatUrl('tel:+1234567890')).toBe('tel:+1234567890');
});
it('should not modify relative paths', () => {
expect(formatUrl('/path/to/resource')).toBe('/path/to/resource');
expect(formatUrl('/index.html')).toBe('/index.html');
});
it('should add mailto: to email addresses', () => {
expect(formatUrl('user@example.com')).toBe('mailto:user@example.com');
expect(formatUrl('name.lastname@domain.co.uk')).toBe(
'mailto:name.lastname@domain.co.uk',
);
});
it('should add tel: to phone numbers', () => {
expect(formatUrl('+1234567890')).toBe('tel:+1234567890');
expect(formatUrl('123-456-7890')).toBe('tel:123-456-7890');
});
it('should add https:// to URLs without protocols', () => {
expect(formatUrl('www.example.com')).toBe('https://www.example.com');
expect(formatUrl('example.com')).toBe('https://example.com');
expect(formatUrl('subdomain.example.com/path')).toBe(
'https://subdomain.example.com/path',
);
});
});

View File

@ -460,3 +460,37 @@ export function isEmptyParagraph(node: LexicalNode): boolean {
MARKDOWN_EMPTY_LINE_REG_EXP.test(firstChild.getTextContent()))
);
}
export const PHONE_NUMBER_REGEX = /^\+?[0-9\s()-]{5,}$/;
/**
* Formats a URL string by adding appropriate protocol if missing
*
* @param url - URL to format
* @returns Formatted URL with appropriate protocol
*/
export function formatUrl(url: string): string {
// Check if URL already has a protocol
if (url.match(/^[a-z][a-z0-9+.-]*:/i)) {
// URL already has a protocol, leave it as is
return url;
}
// Check if it's a relative path (starting with '/', '.', or '#')
else if (url.match(/^[/#.]/)) {
// Relative path, leave it as is
return url;
}
// Check for email address
else if (url.includes('@')) {
return `mailto:${url}`;
}
// Check for phone number
else if (PHONE_NUMBER_REGEX.test(url)) {
return `tel:${url}`;
}
// For everything else, return with https:// prefix
return `https://${url}`;
}