Skip to content

Commit

Permalink
feat: added option onlyInternal excluding external links
Browse files Browse the repository at this point in the history
  • Loading branch information
lukaszmn committed Apr 7, 2020
1 parent 9e9ca7a commit e246643
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 23 deletions.
15 changes: 5 additions & 10 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"style"
],
"dependencies": {
"is-absolute-url": "^3.0.3",
"is-url": "^1.2.4",
"nanoid": "^3.0.2",
"normalize-url": "5.0.0",
Expand Down
23 changes: 14 additions & 9 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,16 +66,21 @@ output.html
## Options

### `tags`
Type: `Array`
Default: `['script', 'link']`
Description: *You can also expand the list by adding the tags you need...*
Type: `Array`
Default: `['script', 'link']`
Description: *You can also expand the list by adding the tags you need...*

### `attributes`
Type: `Array`
Default: `['src', 'href']`
Description: *You can also expand the list by adding the attributes you need...*
Type: `Array`
Default: `['src', 'href']`
Description: *You can also expand the list by adding the attributes you need...*

### `exclude`
Type: `Array`
Default: `[]`
Description: *You can also exclude the list by adding the tags you need...*
Type: `Array`
Default: `[]`
Description: *You can also exclude the list by adding the tags you need...*

### `onlyInternal`
Type: `Array`
Default: `[]`
Description: *If you have external URL-s, some won't work if you add nanoid to them. If this list is empty, all external links are modified. Otherwise, only the URL-s starting with items in the array (case insensitive) will be modified. E.g. `['https://github.com/']` will add nanoid to all local links and only to `https://github.com/*`. It won't add nanoid to e.g. `http://github.com` or `https://fonts.google.com`. For simplicity, a link is considered external if it starts with a protocol (see [is-absolute-url](https://www.npmjs.com/package/is-absolute-url)) or with double slash `//`.*
22 changes: 18 additions & 4 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,30 @@ import {nanoid} from 'nanoid';
import isUrl from 'is-url';
import queryString from 'query-string';
import normalizeUrl from 'normalize-url';
import isAbsoluteUrl from 'is-absolute-url';

const setNanoid = url => {
const id = nanoid();
const setNanoid = (onlyInternal, url) => {
const fullUrl = /^[/?]/.test(url) ? `foo.bar${url}` : url;

if (onlyInternal.length > 0) {
const isAbsolute = isAbsoluteUrl(url) || url.startsWith('//');
if (isAbsolute) {
const absoluteUrl = normalizeUrl(url, {normalizeProtocol: false}).toLowerCase();
if (onlyInternal.every(start => !absoluteUrl.startsWith(start.toLowerCase()))) {
return url;
}
}
}

if (!isUrl(normalizeUrl(fullUrl))) {
return url;
}

const id = nanoid();

let [uri, query] = url.split('?');
query = queryString.parse(query);
query.v = query.v ? query.v : id;
query.v = query.v || id;
query = queryString.stringify(query);

return `${uri}?${query}`;
Expand Down Expand Up @@ -44,11 +56,13 @@ export default (options = {}) => {
resolve(tree);
}

const onlyInternal = options.onlyInternal && Array.isArray(options.onlyInternal) ? options.onlyInternal : [];

tree.walk(node => {
if (node.tag && node.attrs) {
node.attrs = Object.keys(node.attrs).reduce((attributeList, attr) => {
if (tags.includes(node.tag) && attributes.includes(attr)) {
return Object.assign(attributeList, {[attr]: setNanoid(node.attrs[attr])});
return Object.assign(attributeList, {[attr]: setNanoid(onlyInternal, node.attrs[attr])});
}

return attributeList;
Expand Down
63 changes: 63 additions & 0 deletions test/test-plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,69 @@ test('should add nano id for root path', async t => {
t.is(id.length, 21);
});

test('should add nano id for external link', async t => {
const input = '<link rel="stylesheet" href="https://foo.com/style.css">';
const html = (await processing(input)).html;

const {url, id} = getParts(html, 'href');
const rel = parser(html)[0].attrs.rel;
t.truthy(id);
t.truthy(rel);
t.is(rel, 'stylesheet');
t.is(url, 'https://foo.com/style.css');
t.is(id.length, 21);
});

test('should add nano id for allowed external link', async t => {
const input = '<link rel="stylesheet" href="https://FOO.com/style.css">';
const html = (await processing(input, {onlyInternal: ['https://foo.com/']})).html;

const {url, id} = getParts(html, 'href');
const rel = parser(html)[0].attrs.rel;
t.truthy(id);
t.truthy(rel);
t.is(rel, 'stylesheet');
t.is(url, 'https://FOO.com/style.css');
t.is(id.length, 21);
});

test('shouldn\'t add nano id for disallowed external link', async t => {
const input = '<link rel="stylesheet" href="https://foo.com/style.css">';
const html = (await processing(input, {onlyInternal: ['http://foo.com/']})).html;

const {url, id} = getParts(html, 'href');
const rel = parser(html)[0].attrs.rel;
t.falsy(id);
t.truthy(rel);
t.is(rel, 'stylesheet');
t.is(url, 'https://foo.com/style.css');
});

test('should add nano id for disallowed protocol-less external link', async t => {
const input = '<link rel="stylesheet" href="//FOO.com/style.css">';
const html = (await processing(input, {onlyInternal: ['//foo.com/']})).html;

const {url, id} = getParts(html, 'href');
const rel = parser(html)[0].attrs.rel;
t.truthy(id);
t.truthy(rel);
t.is(rel, 'stylesheet');
t.is(url, '//FOO.com/style.css');
t.is(id.length, 21);
});

test('shouldn\'t add nano id for disallowed protocol-less external link', async t => {
const input = '<link rel="stylesheet" href="//foo.com/style.css">';
const html = (await processing(input, {onlyInternal: ['//foo.org/']})).html;

const {url, id} = getParts(html, 'href');
const rel = parser(html)[0].attrs.rel;
t.falsy(id);
t.truthy(rel);
t.is(rel, 'stylesheet');
t.is(url, '//foo.com/style.css');
});

function getParts(html, attributeName) {
const parts = parser(html)[0].attrs[attributeName].split('?');
const url = parts[0];
Expand Down

0 comments on commit e246643

Please # to comment.