diff --git a/lib/index.js b/lib/index.js index c5ca771..07251f1 100644 --- a/lib/index.js +++ b/lib/index.js @@ -126,8 +126,24 @@ function exitLiteralAutolink(token) { this.exit(token) } -/** @type {FromMarkdownTransform} */ -function transformGfmAutolinkLiterals(tree) { +// Regex support detector +const regexSupport = { + lookbehind: (() => { + try { + // Using regex literal instead of RegExp constructor + ;/(?<=x)/.test('x') + return true + } catch { + return false + } + })() +} + +/** + * Modern version of autolink transform using lookbehind + * @type {FromMarkdownTransform} + */ +function modernAutolinkTransform(tree) { findAndReplace( tree, [ @@ -138,6 +154,46 @@ function transformGfmAutolinkLiterals(tree) { ) } +/** + * Legacy version of autolink transform for older Node.js versions + * @type {FromMarkdownTransform} + */ +function legacyAutolinkTransform(tree) { + findAndReplace( + tree, + [ + [/(https?:\/\/|www(?=\.))([-.\w]+)([^ \t\r\n]*)/gi, findUrl], + // [/([-.\w+]+)@([-\w]+(?:\.[-\w]+)+)/g, findEmail] # NOTE: this is your version, we can use your if you want + [/(^|\s|\p{P}|\p{S})([-.\w+]+)@([-\w]+(?:\.[-\w]+)+)/gu, findEmailLegacy] + ], + {ignore: ['link', 'linkReference']} + ) +} + +/** + * Helper function for legacy email matching + * @param {string} _ - Unused parameter + * @param {string} prefix - Email prefix + * @param {string} name - Email name + * @param {string} domain - Email domain + * @returns {*} The processed email + */ +function findEmailLegacy(_, prefix, name, domain) { + return findEmail(name + '@' + domain) +} + +/** + * Main transform function that uses the appropriate version based on regex support + * @type {FromMarkdownTransform} + */ +function transformGfmAutolinkLiterals(tree) { + if (regexSupport.lookbehind) { + modernAutolinkTransform(tree) + } else { + legacyAutolinkTransform(tree) + } +} + /** * @type {ReplaceFunction} * @param {string} _ diff --git a/test/index.js b/test/index.js index ca830e0..c8fa04d 100644 --- a/test/index.js +++ b/test/index.js @@ -452,6 +452,15 @@ test('gfmAutolinkLiteralToMarkdown()', async function (t) { ) }) +/** + * Normalizes line endings to Unix style (\n) + * @param {string} text - The text to normalize + * @returns {string} The normalized text + */ +function normalizeLineEndings(text) { + return text.replaceAll('\r\n', '\n') +} + test('fixtures', async function (t) { const root = new URL('fixture/', import.meta.url) @@ -469,8 +478,10 @@ test('fixtures', async function (t) { const inputUrl = new URL(file, root) const expectedUrl = new URL(stem + '.html', root) - const input = await fs.readFile(inputUrl) - const expected = String(await fs.readFile(expectedUrl)) + const input = normalizeLineEndings(String(await fs.readFile(inputUrl))) + const expected = normalizeLineEndings( + String(await fs.readFile(expectedUrl)) + ) const mdast = fromMarkdown(input, { extensions: [gfmAutolinkLiteral()],