UNPKG

posthtml-external-link

Version:

Add 'rel="external noopener nofollow"' and 'target="_blank"' to all external links [PostHTML Plugin]

82 lines (81 loc) 2.65 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.posthtmlExternalLink = void 0; function posthtmlExternalLink(config) { return function postHtmlExternalLinkPlugin(tree) { if (!config) return tree; tree.walk((node) => { if (node.tag && node.tag === 'a' && node.attrs && node.attrs.href) { if (config) { const exclude = Array.isArray(config.exclude) ? config.exclude : [config.exclude]; if (!isExternalLink(node.attrs.href, exclude)) { return node; } } // :: append rels to the element's [rel] value. // failsafes in case [rel] is not defined yet. const rels = node.attrs.rel ? new Set(node.attrs.rel.split(/\s+/)) : new Set(); // config.noreferrer && rels.add('noreferrer'); if (config.noreferrer) rels.add('noreferrer'); rels.add('noopener'); rels.add('nofollow'); rels.add('external'); node.attrs.rel = Array.from(rels).join(' '); node.attrs.target = '_blank'; } return node; }); return tree; }; } exports.posthtmlExternalLink = posthtmlExternalLink; const cache = new Map(); function cacheApply(key, value) { var _a; if (cache.has(key)) return (_a = cache.get(key)) !== null && _a !== void 0 ? _a : false; if (typeof value === 'function') value = value(); cache.set(key, value); return value; } function isExternalLink(input, exclude) { return cacheApply(input, () => { if (!input.startsWith('//') && !input.startsWith('http://') && !input.startsWith('https://')) { return false; } let urlObj; try { urlObj = new URL(input); } catch (_a) { } // urlObj will be undefined if "input" is an invalid URL if (!(urlObj instanceof URL)) { return false; } // handle mailto: javascript: vbscript: etc. if (urlObj.origin === 'null') { return false; } if (exclude) { for (const i of exclude) { if (urlObj.hostname === i) { return false; } } } if (urlObj.hostname !== input) { return true; } return false; }); }