@bartificer/linkify 2.3.2 → 2.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1 -1
- package/docs/LinkData.class.mjs.html +150 -0
- package/docs/LinkTemplate.class.mjs.html +141 -0
- package/docs/Linkifier.class.mjs.html +411 -0
- package/docs/PageData.class.mjs.html +272 -0
- package/docs/data/search.json +1 -0
- package/docs/defaults.mjs.html +101 -0
- package/docs/externals.jsdoc.html +37 -0
- package/docs/fonts/Inconsolata-Regular.ttf +0 -0
- package/docs/fonts/OpenSans-Regular.ttf +0 -0
- package/docs/fonts/WorkSans-Bold.ttf +0 -0
- package/docs/index.html +28 -0
- package/docs/index.js.html +49 -0
- package/docs/module-LinkData.LinkData.html +13 -0
- package/docs/module-LinkData.html +3 -0
- package/docs/module-LinkTemplate.LinkTemplate.html +3 -0
- package/docs/module-LinkTemplate.html +3 -0
- package/docs/module-Linkifier.Linkifier.html +3 -0
- package/docs/module-Linkifier.html +3 -0
- package/docs/module-PageData.PageData.html +15 -0
- package/docs/module-PageData.html +3 -0
- package/docs/module-cheerio.html +3 -0
- package/docs/module-defaults.html +3 -0
- package/docs/module-linkify.html +3 -0
- package/docs/module-mustache.html +3 -0
- package/docs/module-node-fetch.html +3 -0
- package/docs/module-title-case.html +3 -0
- package/docs/module-urijs.html +3 -0
- package/docs/module-url-slug.html +3 -0
- package/docs/module-utilities.html +3 -0
- package/docs/scripts/core.js +726 -0
- package/docs/scripts/core.min.js +23 -0
- package/docs/scripts/resize.js +90 -0
- package/docs/scripts/search.js +265 -0
- package/docs/scripts/search.min.js +6 -0
- package/docs/scripts/third-party/Apache-License-2.0.txt +202 -0
- package/docs/scripts/third-party/fuse.js +9 -0
- package/docs/scripts/third-party/hljs-line-num-original.js +369 -0
- package/docs/scripts/third-party/hljs-line-num.js +1 -0
- package/docs/scripts/third-party/hljs-original.js +5171 -0
- package/docs/scripts/third-party/hljs.js +1 -0
- package/docs/scripts/third-party/popper.js +5 -0
- package/docs/scripts/third-party/tippy.js +1 -0
- package/docs/scripts/third-party/tocbot.js +672 -0
- package/docs/scripts/third-party/tocbot.min.js +1 -0
- package/docs/styles/clean-jsdoc-theme-base.css +1159 -0
- package/docs/styles/clean-jsdoc-theme-dark.css +412 -0
- package/docs/styles/clean-jsdoc-theme-light.css +482 -0
- package/docs/styles/clean-jsdoc-theme-scrollbar.css +30 -0
- package/docs/styles/clean-jsdoc-theme-without-scrollbar.min.css +1 -0
- package/docs/styles/clean-jsdoc-theme.min.css +1 -0
- package/docs/utilities.mjs.html +151 -0
- package/examples/clipboardURLToMarkdown.mjs +74 -0
- package/examples/debugClipboardURL.mjs +7 -0
- package/package.json +8 -3
- package/src/LinkData.class.mjs +13 -0
- package/src/LinkTemplate.class.mjs +14 -0
- package/src/Linkifier.class.mjs +22 -2
- package/src/PageData.class.mjs +13 -0
- package/src/defaults.mjs +11 -0
- package/src/externals.jsdoc +35 -0
- package/src/index.js +40 -5
- package/src/utilities.mjs +21 -7
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
<!DOCTYPE html><html lang="en" style="font-size:16px"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Source: utilities.mjs</title><!--[if lt IE 9]>
|
|
2
|
+
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
|
3
|
+
<![endif]--><script src="scripts/third-party/hljs.js" defer="defer"></script><script src="scripts/third-party/hljs-line-num.js" defer="defer"></script><script src="scripts/third-party/popper.js" defer="defer"></script><script src="scripts/third-party/tippy.js" defer="defer"></script><script src="scripts/third-party/tocbot.min.js"></script><script>var baseURL="/",locationPathname="";baseURL=(locationPathname=document.location.pathname).substr(0,locationPathname.lastIndexOf("/")+1)</script><link rel="stylesheet" href="styles/clean-jsdoc-theme.min.css"><svg aria-hidden="true" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="display:none"><defs><symbol id="copy-icon" viewbox="0 0 488.3 488.3"><g><path d="M314.25,85.4h-227c-21.3,0-38.6,17.3-38.6,38.6v325.7c0,21.3,17.3,38.6,38.6,38.6h227c21.3,0,38.6-17.3,38.6-38.6V124 C352.75,102.7,335.45,85.4,314.25,85.4z M325.75,449.6c0,6.4-5.2,11.6-11.6,11.6h-227c-6.4,0-11.6-5.2-11.6-11.6V124 c0-6.4,5.2-11.6,11.6-11.6h227c6.4,0,11.6,5.2,11.6,11.6V449.6z"/><path d="M401.05,0h-227c-21.3,0-38.6,17.3-38.6,38.6c0,7.5,6,13.5,13.5,13.5s13.5-6,13.5-13.5c0-6.4,5.2-11.6,11.6-11.6h227 c6.4,0,11.6,5.2,11.6,11.6v325.7c0,6.4-5.2,11.6-11.6,11.6c-7.5,0-13.5,6-13.5,13.5s6,13.5,13.5,13.5c21.3,0,38.6-17.3,38.6-38.6 V38.6C439.65,17.3,422.35,0,401.05,0z"/></g></symbol><symbol id="search-icon" viewBox="0 0 512 512"><g><g><path d="M225.474,0C101.151,0,0,101.151,0,225.474c0,124.33,101.151,225.474,225.474,225.474 c124.33,0,225.474-101.144,225.474-225.474C450.948,101.151,349.804,0,225.474,0z M225.474,409.323 c-101.373,0-183.848-82.475-183.848-183.848S124.101,41.626,225.474,41.626s183.848,82.475,183.848,183.848 S326.847,409.323,225.474,409.323z"/></g></g><g><g><path d="M505.902,476.472L386.574,357.144c-8.131-8.131-21.299-8.131-29.43,0c-8.131,8.124-8.131,21.306,0,29.43l119.328,119.328 c4.065,4.065,9.387,6.098,14.715,6.098c5.321,0,10.649-2.033,14.715-6.098C514.033,497.778,514.033,484.596,505.902,476.472z"/></g></g></symbol><symbol id="font-size-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M11.246 15H4.754l-2 5H.6L7 4h2l6.4 16h-2.154l-2-5zm-.8-2L8 6.885 5.554 13h4.892zM21 12.535V12h2v8h-2v-.535a4 4 0 1 1 0-6.93zM19 18a2 2 0 1 0 0-4 2 2 0 0 0 0 4z"/></symbol><symbol id="add-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M11 11V5h2v6h6v2h-6v6h-2v-6H5v-2z"/></symbol><symbol id="minus-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M5 11h14v2H5z"/></symbol><symbol id="dark-theme-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M10 7a7 7 0 0 0 12 4.9v.1c0 5.523-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2h.1A6.979 6.979 0 0 0 10 7zm-6 5a8 8 0 0 0 15.062 3.762A9 9 0 0 1 8.238 4.938 7.999 7.999 0 0 0 4 12z"/></symbol><symbol id="light-theme-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 18a6 6 0 1 1 0-12 6 6 0 0 1 0 12zm0-2a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM11 1h2v3h-2V1zm0 19h2v3h-2v-3zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85l1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM5.636 16.95l1.414 1.414-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3zM4 11v2H1v-2h3z"/></symbol><symbol id="reset-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M18.537 19.567A9.961 9.961 0 0 1 12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10c0 2.136-.67 4.116-1.81 5.74L17 12h3a8 8 0 1 0-2.46 5.772l.997 1.795z"/></symbol><symbol id="down-icon" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M12.7803 6.21967C13.0732 6.51256 13.0732 6.98744 12.7803 7.28033L8.53033 11.5303C8.23744 11.8232 7.76256 11.8232 7.46967 11.5303L3.21967 7.28033C2.92678 6.98744 2.92678 6.51256 3.21967 6.21967C3.51256 5.92678 3.98744 5.92678 4.28033 6.21967L8 9.93934L11.7197 6.21967C12.0126 5.92678 12.4874 5.92678 12.7803 6.21967Z"></path></symbol><symbol id="codepen-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M16.5 13.202L13 15.535v3.596L19.197 15 16.5 13.202zM14.697 12L12 10.202 9.303 12 12 13.798 14.697 12zM20 10.869L18.303 12 20 13.131V10.87zM19.197 9L13 4.869v3.596l3.5 2.333L19.197 9zM7.5 10.798L11 8.465V4.869L4.803 9 7.5 10.798zM4.803 15L11 19.131v-3.596l-3.5-2.333L4.803 15zM4 13.131L5.697 12 4 10.869v2.262zM2 9a1 1 0 0 1 .445-.832l9-6a1 1 0 0 1 1.11 0l9 6A1 1 0 0 1 22 9v6a1 1 0 0 1-.445.832l-9 6a1 1 0 0 1-1.11 0l-9-6A1 1 0 0 1 2 15V9z"/></symbol><symbol id="close-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 10.586l4.95-4.95 1.414 1.414-4.95 4.95 4.95 4.95-1.414 1.414-4.95-4.95-4.95 4.95-1.414-1.414 4.95-4.95-4.95-4.95L7.05 5.636z"/></symbol><symbol id="menu-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M3 4h18v2H3V4zm0 7h18v2H3v-2zm0 7h18v2H3v-2z"/></symbol></defs></svg></head><body data-theme="fallback-light"><div class="sidebar-container"><div class="sidebar" id="sidebar"><a href="/" class="sidebar-title sidebar-title-anchor">Bartificer Linkifier</a><div class="sidebar-items-container"><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-modules"><div>Modules</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="module-LinkData.html">LinkData</a></div><div class="sidebar-section-children"><a href="module-LinkTemplate.html">LinkTemplate</a></div><div class="sidebar-section-children"><a href="module-Linkifier.html">Linkifier</a></div><div class="sidebar-section-children"><a href="module-PageData.html">PageData</a></div><div class="sidebar-section-children"><a href="module-defaults.html">defaults</a></div><div class="sidebar-section-children"><a href="module-linkify.html">linkify</a></div><div class="sidebar-section-children"><a href="module-utilities.html">utilities</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-classes"><div>Classes</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="module-LinkData.LinkData.html">LinkData</a></div><div class="sidebar-section-children"><a href="module-LinkTemplate.LinkTemplate.html">LinkTemplate</a></div><div class="sidebar-section-children"><a href="module-Linkifier.Linkifier.html">Linkifier</a></div><div class="sidebar-section-children"><a href="module-PageData.PageData.html">PageData</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-externals"><div>Externals</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="module-cheerio.html">cheerio</a></div><div class="sidebar-section-children"><a href="module-mustache.html">mustache</a></div><div class="sidebar-section-children"><a href="module-node-fetch.html">node-fetch</a></div><div class="sidebar-section-children"><a href="module-title-case.html">title-case</a></div><div class="sidebar-section-children"><a href="module-urijs.html">urijs</a></div><div class="sidebar-section-children"><a href="module-url-slug.html">url-slug</a></div></div></div></div></div><div class="navbar-container" id="VuAckcnZhf"><nav class="navbar"><div class="navbar-left-items"></div><div class="navbar-right-items"><div class="navbar-right-item"><button class="icon-button search-button" aria-label="open-search"><svg><use xlink:href="#search-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button theme-toggle" aria-label="toggle-theme"><svg><use class="theme-svg-use" xlink:href="#dark-theme-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button font-size" aria-label="change-font-size"><svg><use xlink:href="#font-size-icon"></use></svg></button></div></div><nav></nav></nav></div><div class="toc-container"><div class="toc-content"><span class="bold">On this page</span><div id="eed4d2a0bfd64539bb9df78095dec881"></div></div></div><div class="body-wrapper"><div class="main-content"><div class="main-wrapper"><section id="source-page" class="source-page"><header><h1 id="title" class="has-anchor">utilities.mjs</h1></header><article><pre class="prettyprint source lang-js"><code>/**
|
|
4
|
+
* @file A collection of useful utility functions.
|
|
5
|
+
* @author Bart Busschots <opensource@bartificer.ie>
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* This module provides utility functions which are both used by the core code, and, available for use by users when defining link data transformers and link templates.
|
|
10
|
+
* @module utilities
|
|
11
|
+
* @requires module:defaults
|
|
12
|
+
* @requires module:urijs
|
|
13
|
+
* @requires module:url-slug
|
|
14
|
+
* @requires module:title-case
|
|
15
|
+
*/
|
|
16
|
+
import * as defaults from './defaults.mjs';
|
|
17
|
+
import URI from 'urijs';
|
|
18
|
+
import * as urlSlug from 'url-slug';
|
|
19
|
+
import * as titleCase from 'title-case';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Regularise white space by replacing all sequences of whitespace characters with a single space and trimming leading and trailing whitespace.
|
|
23
|
+
*
|
|
24
|
+
* @param {string} text
|
|
25
|
+
* @return {string}
|
|
26
|
+
*/
|
|
27
|
+
export function regulariseWhitespace(text){
|
|
28
|
+
return String(text).replace(/[\s\n]+/g, ' ').trim();
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Strip the query string from a URL.
|
|
33
|
+
*
|
|
34
|
+
* @param {string} url
|
|
35
|
+
* @return {string}
|
|
36
|
+
*/
|
|
37
|
+
export function stripQueryString(url){
|
|
38
|
+
return URI(url).query('').toString();
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Remove UTM parameters from the query string in a URL.
|
|
43
|
+
*
|
|
44
|
+
* @param {string} url
|
|
45
|
+
* @return {string}
|
|
46
|
+
* @see {@link https://en.wikipedia.org/wiki/UTM_parameters}
|
|
47
|
+
*/
|
|
48
|
+
export function stripUTMParameters(url){
|
|
49
|
+
return URI(url).removeQuery(['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content']).toString();
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Escape a string for use in regular expressions.
|
|
54
|
+
*
|
|
55
|
+
* _**Note:** this is not a standard Javascript feature as of April 2026, though it is coming in future versions of Javascript._
|
|
56
|
+
*
|
|
57
|
+
* @param {string} str - the string to escape.
|
|
58
|
+
* @returns {string}
|
|
59
|
+
* @see {@link https://stackoverflow.com/a/3561711/174985}
|
|
60
|
+
*/
|
|
61
|
+
export function escapeRegex(str) {
|
|
62
|
+
return String(str).replace(/[/\-\\^$*+?.()|[\]{}]/g, '\\$&');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Batch-customise word casings in a string. E.g. force `fbi` to `FBI`, `ios` to `iOS`, etc..
|
|
67
|
+
*
|
|
68
|
+
* @param {string} str - the string to apply the replacemnts to.
|
|
69
|
+
* @param {string[]} [words] - an array of words in their desired capitalisations. Defaults to the default list of custom capitalisations.
|
|
70
|
+
* @returns {string}
|
|
71
|
+
*/
|
|
72
|
+
export function batchFixCustomWordCases(str, words){
|
|
73
|
+
// coerce the first argument to a string
|
|
74
|
+
let ans = String(str);
|
|
75
|
+
|
|
76
|
+
// resolve the word list
|
|
77
|
+
if(arguments.length < 2){
|
|
78
|
+
// if none was passed, use the default list
|
|
79
|
+
words = defaults.speciallyCapitalisedWords;
|
|
80
|
+
} else {
|
|
81
|
+
// TO DO — add validation
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// build a mapping from the lower-case version of each word to custom version
|
|
85
|
+
const lowerToCustomMap = {};
|
|
86
|
+
words.map(word => lowerToCustomMap[word.toLowerCase()] = word);
|
|
87
|
+
|
|
88
|
+
// assemble an RE from all the words
|
|
89
|
+
const sortedWords = Object.keys(lowerToCustomMap).sort((a, b) => b.length - a.length); // sort for efficiency
|
|
90
|
+
const wordRE = new RegExp(
|
|
91
|
+
sortedWords.map(word => `\\b${escapeRegex(word)}\\b`).join('|'),
|
|
92
|
+
'gi'
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
// replace all the matches at once using an anonymous function as the replacement
|
|
96
|
+
ans = str.replace(wordRE, match => lowerToCustomMap[match.toLowerCase()]);
|
|
97
|
+
|
|
98
|
+
return ans;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Extract the slug from a URL and convert it to a title-case string.
|
|
103
|
+
*
|
|
104
|
+
* @param {string} url
|
|
105
|
+
* @param {string[]} [words] - a list of words with custom capitalisations to correct after title-casing.
|
|
106
|
+
* @return {string}
|
|
107
|
+
*/
|
|
108
|
+
export function extractSlug(url, words){
|
|
109
|
+
// TO DO - add validation
|
|
110
|
+
|
|
111
|
+
// resolve the list of words with custom capitalisations
|
|
112
|
+
if(arguments.length < 2){
|
|
113
|
+
words = [];
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// example URLs to try support:
|
|
117
|
+
// ----------------------------
|
|
118
|
+
// https://www.macobserver.com/news/apple-q2-2026-earnings-call-date-confirmed-heres-what-to-expect/
|
|
119
|
+
// https://appleinsider.com/articles/26/04/01/studio-display-xdr-without-tilt-adjustable-stand-now-costs-less
|
|
120
|
+
// https://www.bloomberg.com/news/articles/2026-04-03/ireland-tests-digital-id-to-verify-age-of-social-media-users?srnd=phx-technology&embedded-checkout=true
|
|
121
|
+
//
|
|
122
|
+
// Based on those examples, implement the following algorithm:
|
|
123
|
+
// 1. Parse the URL and extract the path (be sure not to capture the query string or fragment).
|
|
124
|
+
// 2. Trim leading and trailing slashes
|
|
125
|
+
// 3. Split the path on / into segments and take the last segment.
|
|
126
|
+
// 4. Remove any file extension.
|
|
127
|
+
// 5. Call slug reversing function with the lower-case option.
|
|
128
|
+
// 6. Intelligently Title-case the title.
|
|
129
|
+
|
|
130
|
+
// extract the path from the URL and clean up both ends
|
|
131
|
+
const uri = URI(url);
|
|
132
|
+
let path = uri.path();
|
|
133
|
+
path = path.replace(/^\/|\/$/g, ''); // trim leading and trailing slashes
|
|
134
|
+
let slug = path.split('/').pop() || ''; // get last segment of the path
|
|
135
|
+
slug = slug.replace(/\.[^/.]+$/, ''); // trim any file extension that might be present
|
|
136
|
+
|
|
137
|
+
// reverse the slug into a lower-case string
|
|
138
|
+
let title = urlSlug.revert(slug, {
|
|
139
|
+
transformer: urlSlug.LOWERCASE_TRANSFORMER,
|
|
140
|
+
camelCase: false
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
// convert the title to title case
|
|
144
|
+
titleCase.SMALL_WORDS.add('is');
|
|
145
|
+
title = titleCase.titleCase(title);
|
|
146
|
+
|
|
147
|
+
// fix any words with unusual customisations
|
|
148
|
+
title = batchFixCustomWordCases(title, words);
|
|
149
|
+
|
|
150
|
+
return title;
|
|
151
|
+
};</code></pre></article></section></div></div></div><div class="search-container" id="PkfLWpAbet" style="display:none"><div class="wrapper" id="iCxFxjkHbP"><button class="icon-button search-close-button" id="VjLlGakifb" aria-label="close search"><svg><use xlink:href="#close-icon"></use></svg></button><div class="search-box-c"><svg><use xlink:href="#search-icon"></use></svg> <input type="text" id="vpcKVYIppa" class="search-input" placeholder="Search..." autofocus></div><div class="search-result-c" id="fWwVHRuDuN"><span class="search-result-c-text">Type anything to view search result</span></div></div></div><div class="mobile-menu-icon-container"><button class="icon-button" id="mobile-menu" data-isopen="false" aria-label="menu"><svg><use xlink:href="#menu-icon"></use></svg></button></div><div id="mobile-sidebar" class="mobile-sidebar-container"><div class="mobile-sidebar-wrapper"><a href="/" class="sidebar-title sidebar-title-anchor">Bartificer Linkifier</a><div class="mobile-nav-links"></div><div class="mobile-sidebar-items-c"><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-modules"><div>Modules</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="module-LinkData.html">LinkData</a></div><div class="sidebar-section-children"><a href="module-LinkTemplate.html">LinkTemplate</a></div><div class="sidebar-section-children"><a href="module-Linkifier.html">Linkifier</a></div><div class="sidebar-section-children"><a href="module-PageData.html">PageData</a></div><div class="sidebar-section-children"><a href="module-defaults.html">defaults</a></div><div class="sidebar-section-children"><a href="module-linkify.html">linkify</a></div><div class="sidebar-section-children"><a href="module-utilities.html">utilities</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-classes"><div>Classes</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="module-LinkData.LinkData.html">LinkData</a></div><div class="sidebar-section-children"><a href="module-LinkTemplate.LinkTemplate.html">LinkTemplate</a></div><div class="sidebar-section-children"><a href="module-Linkifier.Linkifier.html">Linkifier</a></div><div class="sidebar-section-children"><a href="module-PageData.PageData.html">PageData</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-externals"><div>Externals</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="module-cheerio.html">cheerio</a></div><div class="sidebar-section-children"><a href="module-mustache.html">mustache</a></div><div class="sidebar-section-children"><a href="module-node-fetch.html">node-fetch</a></div><div class="sidebar-section-children"><a href="module-title-case.html">title-case</a></div><div class="sidebar-section-children"><a href="module-urijs.html">urijs</a></div><div class="sidebar-section-children"><a href="module-url-slug.html">url-slug</a></div></div></div><div class="mobile-navbar-actions"><div class="navbar-right-item"><button class="icon-button search-button" aria-label="open-search"><svg><use xlink:href="#search-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button theme-toggle" aria-label="toggle-theme"><svg><use class="theme-svg-use" xlink:href="#dark-theme-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button font-size" aria-label="change-font-size"><svg><use xlink:href="#font-size-icon"></use></svg></button></div></div></div></div><script type="text/javascript" src="scripts/core.min.js"></script><script src="scripts/search.min.js" defer="defer"></script><script src="scripts/third-party/fuse.js" defer="defer"></script><script type="text/javascript">var tocbotInstance=tocbot.init({tocSelector:"#eed4d2a0bfd64539bb9df78095dec881",contentSelector:".main-content",headingSelector:"h1, h2, h3",hasInnerContainers:!0,scrollContainer:".main-content",headingsOffset:130,onClick:bringLinkToView})</script></body></html>
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// import Linkify Lib
|
|
2
|
+
import { linkify, LinkTemplate, LinkData } from '../dist/index.js';
|
|
3
|
+
|
|
4
|
+
// import 3rd-party library for interacting with the clipboard
|
|
5
|
+
import clipboardy from 'clipboardy';
|
|
6
|
+
|
|
7
|
+
// register a custom Markdown link template and make it the default
|
|
8
|
+
linkify.registerTemplate('md-bartificer', new LinkTemplate(
|
|
9
|
+
'[{{{text}}} — {{{uri.hostname}}}{{#uri.hasPath}}/…{{/uri.hasPath}}]({{{url}}})',
|
|
10
|
+
[
|
|
11
|
+
['url', linkify.util.stripUTMParameters],
|
|
12
|
+
['text', linkify.util.regulariseWhitespace]
|
|
13
|
+
]
|
|
14
|
+
));
|
|
15
|
+
linkify.defaultTemplateName = 'md-bartificer';
|
|
16
|
+
|
|
17
|
+
// register a special Markdown template for Apple presss releases and make it the default for Apple's domain
|
|
18
|
+
linkify.registerTemplate('md-apr', new LinkTemplate(
|
|
19
|
+
'[{{{text}}} — 📣 Apple PR]({{{url}}})',
|
|
20
|
+
[
|
|
21
|
+
['url', linkify.util.stripUTMParameters],
|
|
22
|
+
['text', linkify.util.regulariseWhitespace]
|
|
23
|
+
]
|
|
24
|
+
));
|
|
25
|
+
linkify.registerDefaultTemplateMapping('apple.com', 'md-apr');
|
|
26
|
+
|
|
27
|
+
// define & register custom transformers for domains that need them
|
|
28
|
+
linkify.registerTransformer('9to5mac.com', function(pData){
|
|
29
|
+
return new LinkData(pData.url, pData.mainHeading);
|
|
30
|
+
});
|
|
31
|
+
linkify.registerTransformer('cultofmac.com', function(pData){
|
|
32
|
+
return new LinkData(pData.url, pData.mainHeading);
|
|
33
|
+
});
|
|
34
|
+
linkify.registerTransformer('daringfireball.net', function(pData){
|
|
35
|
+
return new LinkData(pData.url, pData.title.replace(/^Daring Fireball:[ ]/, ''));
|
|
36
|
+
});
|
|
37
|
+
linkify.registerTransformer('intego.com', function(pData){
|
|
38
|
+
return new LinkData(pData.url, pData.title.replace(' - The Mac Security Blog', ''));
|
|
39
|
+
});
|
|
40
|
+
linkify.registerTransformer('krebsonsecurity.com', function(pData){
|
|
41
|
+
return new LinkData(pData.url, pData.title.replace(' – Krebs on Security', ''));
|
|
42
|
+
});
|
|
43
|
+
linkify.registerTransformer('macstories.net', function(pData){
|
|
44
|
+
return new LinkData(pData.url, pData.title.replace(' - MacStories', ''));
|
|
45
|
+
});
|
|
46
|
+
linkify.registerTransformer('nakedsecurity.sophos.com', function(pData){
|
|
47
|
+
return new LinkData(pData.url, pData.title.replace(' – Naked Security', ''));
|
|
48
|
+
});
|
|
49
|
+
linkify.registerTransformer('overcast.fm', function(pData){
|
|
50
|
+
// strip Overcast append, split on em-dash to replace with n-dash and get podcast name
|
|
51
|
+
let textParts = pData.title.replace(' — Overcast', '').split('—');
|
|
52
|
+
let podcastName = textParts.pop();
|
|
53
|
+
|
|
54
|
+
// re-assemble the text
|
|
55
|
+
let linkText = podcastName.trim() + ': ' + textParts.join(' – ').replace(/[ ]+/g, ' ').replace(':', '-').trim();
|
|
56
|
+
return new LinkData(pData.url, linkText);
|
|
57
|
+
});
|
|
58
|
+
linkify.registerTransformer('sixcolors.com', function(pData){
|
|
59
|
+
return new LinkData(pData.url, pData.mainHeading);
|
|
60
|
+
});
|
|
61
|
+
linkify.registerTransformer('theverge.com', function(pData){
|
|
62
|
+
return new linkify.LinkData(pData.url, pData.title.replace(/[ ][-][ ]The[ ]Verge.*$/, ''));
|
|
63
|
+
});
|
|
64
|
+
linkify.registerTransformer('wired.com', function(pData){
|
|
65
|
+
return new linkify.LinkData(pData.url, pData.mainHeading);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// read the URL from the clipboard
|
|
69
|
+
let testURL = clipboardy.readSync();
|
|
70
|
+
|
|
71
|
+
// try generate the formatted link from the URL
|
|
72
|
+
linkify.generateLink(testURL).then(function(d){
|
|
73
|
+
console.log(d);
|
|
74
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bartificer/linkify",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.4",
|
|
4
4
|
"description": "An module for converting URLs into pretty links in any format.",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -11,11 +11,14 @@
|
|
|
11
11
|
".": "./dist/index.js"
|
|
12
12
|
},
|
|
13
13
|
"files": [
|
|
14
|
-
"src"
|
|
14
|
+
"src",
|
|
15
|
+
"docs",
|
|
16
|
+
"examples"
|
|
15
17
|
],
|
|
16
18
|
"scripts": {
|
|
17
19
|
"build": "webpack",
|
|
18
|
-
"
|
|
20
|
+
"docs": "rm -rf ./docs/* && npx jsdoc -c ./jsdoc.conf.json --destination ./docs",
|
|
21
|
+
"release": "npm run build && npm run docs && npm login && npm publish"
|
|
19
22
|
},
|
|
20
23
|
"repository": {
|
|
21
24
|
"type": "git",
|
|
@@ -37,6 +40,8 @@
|
|
|
37
40
|
"url-slug": "^5.0.0"
|
|
38
41
|
},
|
|
39
42
|
"devDependencies": {
|
|
43
|
+
"clean-jsdoc-theme": "^4.3.0",
|
|
44
|
+
"jsdoc": "^4.0.5",
|
|
40
45
|
"webpack": "^5.105.4",
|
|
41
46
|
"webpack-cli": "^7.0.2"
|
|
42
47
|
}
|
package/src/LinkData.class.mjs
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file The definition of the class representing a link.
|
|
3
|
+
* @author Bart Busschots <opensource@bartificer.ie>
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* This module provides as class for representing the information that can be used when rendering a link.
|
|
8
|
+
* @module LinkData
|
|
9
|
+
* @requires module:urijs
|
|
10
|
+
*/
|
|
1
11
|
import {default as URI} from 'urijs';
|
|
2
12
|
|
|
13
|
+
/**
|
|
14
|
+
* A class for representing the information about a link, in the abstract.
|
|
15
|
+
*/
|
|
3
16
|
export class LinkData {
|
|
4
17
|
/**
|
|
5
18
|
* This constructor throws a {@link ValidationError} unless a valid URL is passed.
|
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file The definition of the class representing a link generation template.
|
|
3
|
+
* @author Bart Busschots <opensource@bartificer.ie>
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* This module provides as class for representing a template used for generating links.
|
|
8
|
+
* @module LinkTemplate
|
|
9
|
+
* @requires module:urijs
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* A class representing the a template that can be used to render links.
|
|
14
|
+
*/
|
|
1
15
|
export class LinkTemplate{
|
|
2
16
|
/**
|
|
3
17
|
* @param {string} templateString - A Moustache template string.
|
package/src/Linkifier.class.mjs
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file The definition of the main Linkifier class which provides the link rendering functionality with the help of the other classes and modules.
|
|
3
|
+
* @author Bart Busschots <opensource@bartificer.ie>
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Linkifier's core link rendering functionality.
|
|
8
|
+
* @module Linkifier
|
|
9
|
+
* @requires LinkData
|
|
10
|
+
* @requires LinkTemplate
|
|
11
|
+
* @requires PageData
|
|
12
|
+
* @requires module:node-fetch
|
|
13
|
+
* @requires module:cheerio
|
|
14
|
+
* @requires module:mustache
|
|
15
|
+
*/
|
|
1
16
|
import { PageData } from './PageData.class.mjs';
|
|
2
17
|
import { LinkData } from './LinkData.class.mjs';
|
|
3
18
|
import { LinkTemplate } from './LinkTemplate.class.mjs';
|
|
@@ -8,6 +23,9 @@ import fetch from 'node-fetch';
|
|
|
8
23
|
import * as cheerio from 'cheerio';
|
|
9
24
|
import Mustache from 'mustache';
|
|
10
25
|
|
|
26
|
+
/**
|
|
27
|
+
* The class providing the link rendering functionality. Instances of this class capture the settings for generating links, and, generate links using these settings.
|
|
28
|
+
*/
|
|
11
29
|
export class Linkifier {
|
|
12
30
|
constructor(){
|
|
13
31
|
/**
|
|
@@ -157,7 +175,8 @@ export class Linkifier {
|
|
|
157
175
|
}
|
|
158
176
|
|
|
159
177
|
/**
|
|
160
|
-
*
|
|
178
|
+
* A list of the names of the registered link templates.
|
|
179
|
+
* @type {string[]}
|
|
161
180
|
*/
|
|
162
181
|
get templateNames() {
|
|
163
182
|
return Object.keys(this._linkTemplates);
|
|
@@ -183,7 +202,8 @@ export class Linkifier {
|
|
|
183
202
|
}
|
|
184
203
|
|
|
185
204
|
/**
|
|
186
|
-
*
|
|
205
|
+
* The default link template.
|
|
206
|
+
* @type {LinkTemplate}
|
|
187
207
|
*/
|
|
188
208
|
get defaultTemplate(){
|
|
189
209
|
return this._linkTemplates[this._pageDataToLinkTemplateName['.']];
|
package/src/PageData.class.mjs
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file The definition of the class representing a web page.
|
|
3
|
+
* @author Bart Busschots <opensource@bartificer.ie>
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* This module provides as class for representing the information extracted from web pages which can be used to generate the link data avaiable for rendering links.
|
|
8
|
+
* @module PageData
|
|
9
|
+
* @requires module:urijs
|
|
10
|
+
*/
|
|
1
11
|
import {default as URI} from 'urijs';
|
|
2
12
|
|
|
13
|
+
/**
|
|
14
|
+
* A class representing the data extracted from web pages that can be transformed into link data for use when rendering links.
|
|
15
|
+
*/
|
|
3
16
|
export class PageData {
|
|
4
17
|
/**
|
|
5
18
|
* This constructor throws a {@link ValidationError} unless a valid URL is passed.
|
package/src/defaults.mjs
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file The default values used throughout the linkifier classes.
|
|
3
|
+
* @author Bart Busschots <opensource@bartificer.ie>
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* This module provides default values for use by the various linkifier functions and classes. These separated out for clarity, helping users decide which values to override or augment.
|
|
8
|
+
* @module defaults
|
|
9
|
+
* @requires module:LinkTemplate
|
|
10
|
+
* @requires module:utilities
|
|
11
|
+
*/
|
|
1
12
|
import { LinkTemplate } from './LinkTemplate.class.mjs';
|
|
2
13
|
import * as utilities from "./utilities.mjs";
|
|
3
14
|
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The NPM module used to fetch URLs over HTTP(S).
|
|
3
|
+
* @external module:node-fetch
|
|
4
|
+
* @see {@link https://www.npmjs.com/package/node-fetch}
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The module used to parse HTML documents in a jQuery-like way in the NodeJS.
|
|
9
|
+
* @external module:cheerio
|
|
10
|
+
* @see {@link https://cheerio.js.org/docs/intro/}
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The templating system used to describe link templates and generaete links.
|
|
15
|
+
* @external module:mustache
|
|
16
|
+
* @see {@link https://github.com/janl/mustache.js}
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The URI (URL) parser used to parse and process link targets.
|
|
21
|
+
* @external module:urijs
|
|
22
|
+
* @see {@link https://www.npmjs.com/package/urijs}
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The module used to reverse URL slugs back to approximate page titles.
|
|
27
|
+
* @external module:url-slug
|
|
28
|
+
* @see {@link https://www.npmjs.com/package/url-slug}
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The module used for intelligent conversions to newspaper-style title-case.
|
|
33
|
+
* @external module:title-case
|
|
34
|
+
* @see {@link https://www.npmjs.com/package/title-case}
|
|
35
|
+
*/
|
package/src/index.js
CHANGED
|
@@ -1,12 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file The module's entry point. This file determines what does and does not get exported by the module.
|
|
3
|
+
* @author Bart Busschots <opensource@bartificer.ie>
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The package entry-point.
|
|
8
|
+
*
|
|
9
|
+
* @module linkify
|
|
10
|
+
* @requires Linkifier
|
|
11
|
+
* @requires LinkData
|
|
12
|
+
* @requires LinkTemplate
|
|
13
|
+
* @requires PageData
|
|
14
|
+
*/
|
|
1
15
|
import { Linkifier } from "./Linkifier.class.mjs";
|
|
2
16
|
import { LinkData } from "./LinkData.class.mjs";
|
|
3
17
|
import { LinkTemplate } from "./LinkTemplate.class.mjs";
|
|
4
18
|
import { PageData } from "./PageData.class.mjs";
|
|
5
19
|
|
|
6
|
-
//
|
|
20
|
+
//
|
|
21
|
+
// === export the public API ===
|
|
22
|
+
//
|
|
23
|
+
|
|
24
|
+
/** The module's current SEMVER version number. */
|
|
25
|
+
export const VERSION = process.env.VERSION; // Webpack replaces this line with the actual version string during build
|
|
26
|
+
|
|
27
|
+
/** An instantiated Linkifier object ready for use. */
|
|
28
|
+
export const linkify = new Linkifier();
|
|
29
|
+
|
|
30
|
+
export {
|
|
31
|
+
/** The Linkifier class that encapsulates the link generations functionality. */
|
|
32
|
+
Linkifier,
|
|
33
|
+
|
|
34
|
+
/** The PageData class used to store webpage properties like title and headings. */
|
|
35
|
+
PageData,
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The LinkData class use to store link properties like title and url. */
|
|
39
|
+
LinkData,
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* The LinkTempalte class used for defining the templates for generating links. */
|
|
43
|
+
LinkTemplate
|
|
44
|
+
};
|
|
7
45
|
|
|
8
|
-
|
|
9
|
-
const VERSION = process.env.VERSION; // Webpack replaces this line with the actual version string during build
|
|
10
|
-
const linkify = new Linkifier();
|
|
11
|
-
export { linkify, Linkifier, PageData, LinkData, LinkTemplate, VERSION};
|
|
46
|
+
/** The default export. */
|
|
12
47
|
export { linkify as default };
|
package/src/utilities.mjs
CHANGED
|
@@ -1,7 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file A collection of useful utility functions.
|
|
3
|
+
* @author Bart Busschots <opensource@bartificer.ie>
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* This module provides utility functions which are both used by the core code, and, available for use by users when defining link data transformers and link templates.
|
|
8
|
+
* @module utilities
|
|
9
|
+
* @requires module:defaults
|
|
10
|
+
* @requires module:urijs
|
|
11
|
+
* @requires module:url-slug
|
|
12
|
+
* @requires module:title-case
|
|
13
|
+
*/
|
|
14
|
+
import * as defaults from './defaults.mjs';
|
|
1
15
|
import URI from 'urijs';
|
|
2
16
|
import * as urlSlug from 'url-slug';
|
|
3
|
-
import * as titleCase from
|
|
4
|
-
import * as defaults from './defaults.mjs';
|
|
17
|
+
import * as titleCase from 'title-case';
|
|
5
18
|
|
|
6
19
|
/**
|
|
7
20
|
* Regularise white space by replacing all sequences of whitespace characters with a single space and trimming leading and trailing whitespace.
|
|
@@ -28,7 +41,7 @@ export function stripQueryString(url){
|
|
|
28
41
|
*
|
|
29
42
|
* @param {string} url
|
|
30
43
|
* @return {string}
|
|
31
|
-
* @see https://en.wikipedia.org/wiki/UTM_parameters
|
|
44
|
+
* @see {@link https://en.wikipedia.org/wiki/UTM_parameters}
|
|
32
45
|
*/
|
|
33
46
|
export function stripUTMParameters(url){
|
|
34
47
|
return URI(url).removeQuery(['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content']).toString();
|
|
@@ -37,10 +50,11 @@ export function stripUTMParameters(url){
|
|
|
37
50
|
/**
|
|
38
51
|
* Escape a string for use in regular expressions.
|
|
39
52
|
*
|
|
53
|
+
* _**Note:** this is not a standard Javascript feature as of April 2026, though it is coming in future versions of Javascript._
|
|
54
|
+
*
|
|
40
55
|
* @param {string} str - the string to escape.
|
|
41
56
|
* @returns {string}
|
|
42
|
-
* @
|
|
43
|
-
* @see https://stackoverflow.com/a/3561711/174985
|
|
57
|
+
* @see {@link https://stackoverflow.com/a/3561711/174985}
|
|
44
58
|
*/
|
|
45
59
|
export function escapeRegex(str) {
|
|
46
60
|
return String(str).replace(/[/\-\\^$*+?.()|[\]{}]/g, '\\$&');
|
|
@@ -50,7 +64,7 @@ export function escapeRegex(str) {
|
|
|
50
64
|
* Batch-customise word casings in a string. E.g. force `fbi` to `FBI`, `ios` to `iOS`, etc..
|
|
51
65
|
*
|
|
52
66
|
* @param {string} str - the string to apply the replacemnts to.
|
|
53
|
-
* @param {
|
|
67
|
+
* @param {string[]} [words] - an array of words in their desired capitalisations. Defaults to the default list of custom capitalisations.
|
|
54
68
|
* @returns {string}
|
|
55
69
|
*/
|
|
56
70
|
export function batchFixCustomWordCases(str, words){
|
|
@@ -86,7 +100,7 @@ export function batchFixCustomWordCases(str, words){
|
|
|
86
100
|
* Extract the slug from a URL and convert it to a title-case string.
|
|
87
101
|
*
|
|
88
102
|
* @param {string} url
|
|
89
|
-
* @param {
|
|
103
|
+
* @param {string[]} [words] - a list of words with custom capitalisations to correct after title-casing.
|
|
90
104
|
* @return {string}
|
|
91
105
|
*/
|
|
92
106
|
export function extractSlug(url, words){
|