├── .cjsescache ├── .editorconfig ├── .eslintrc.js ├── .github └── workflows │ └── test.yml ├── .gitignore ├── LICENSE ├── README.md ├── build-tlds.js ├── codecov.yml ├── demo ├── demo.css ├── demo.html └── demo.js ├── dist ├── linkify-plus-plus-core.esm.js ├── linkify-plus-plus-core.esm.js.map ├── linkify-plus-plus-core.js ├── linkify-plus-plus-core.js.map ├── linkify-plus-plus-core.min.js └── linkify-plus-plus-core.min.js.map ├── eslint.config.mjs ├── index.js ├── lib ├── linkifier.js ├── tlds.json └── url-matcher.js ├── package-lock.json ├── package.json ├── rollup.config.mjs ├── test ├── __snapshots__ │ └── test.snap.js └── test.mjs └── web-test-runner.config.mjs /.cjsescache: -------------------------------------------------------------------------------- 1 | [ 2 | "node_modules/event-lite/event-lite.mjs" 3 | ] -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | indent_style = space 3 | indent_size = 2 4 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "extends": [ 3 | "eslint:recommended", 4 | "plugin:compat/recommended" 5 | ], 6 | "env": { 7 | "es6": true, 8 | "node": true 9 | }, 10 | parserOptions: { 11 | ecmaVersion: 2024 12 | }, 13 | overrides: [ 14 | { 15 | files: ["**/__snapshots__/*.js"], 16 | parserOptions: { 17 | sourceType: "module" 18 | } 19 | } 20 | ] 21 | }; 22 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | on: [push, pull_request] 3 | 4 | jobs: 5 | test: 6 | runs-on: ubuntu-latest 7 | 8 | steps: 9 | - uses: actions/checkout@v3 10 | - uses: actions/setup-node@v3 11 | with: 12 | node-version: '18' 13 | - run: npm ci 14 | - run: npm run test-cover 15 | - uses: codecov/codecov-action@v5 16 | with: 17 | fail_ci_if_error: true 18 | verbose: true 19 | token: ${{ secrets.CODECOV_TOKEN }} 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | coverage 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011, Anthony Lieuallen 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | * Neither the name of Anthony Lieuallen nor the names of its contributors may 13 | be used to endorse or promote products derived from this software without 14 | specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Linkify Plus Plus Core 2 | ====================== 3 | 4 | [![test](https://github.com/eight04/linkify-plus-plus-core/actions/workflows/test.yml/badge.svg)](https://github.com/eight04/linkify-plus-plus-core/actions/workflows/test.yml) 5 | [![codecov](https://codecov.io/gh/eight04/linkify-plus-plus-core/branch/master/graph/badge.svg)](https://codecov.io/gh/eight04/linkify-plus-plus-core) 6 | 7 | A JavaScript library for linkification stuff. Used by [linkify-plus-plus](https://github.com/eight04/linkify-plus-plus). 8 | 9 | Demo 10 | ---- 11 | https://rawgit.com/eight04/linkify-plus-plus-core/master/demo/demo.html 12 | 13 | Features 14 | -------- 15 | 16 | This module exports 2 classes. 17 | 18 | * UrlMatcher - a URL matcher which can match almost all types of links from a string. 19 | * Linkifier - to linkify an element. 20 | 21 | Compatibility 22 | ------------- 23 | 24 | * Tested on Firefox >= 56. 25 | * Support HTML/XHTML pages. 26 | 27 | Installation 28 | ------------ 29 | 30 | ``` 31 | npm install linkify-plus-plus-core 32 | ``` 33 | 34 | ```JavaScript 35 | const {UrlMatcher, Linkifier} = require("linkify-plus-plus-core"); 36 | // or use the matcher only 37 | const {UrlMatcher} = require("linkify-plus-plus-core/lib/url-matcher") 38 | ``` 39 | 40 | There is also a browserified standalone build in `dist` folder, which can be included in your html directly. 41 | 42 | ``` 43 | 44 | 48 | ``` 49 | 50 | unpkg.com CDN: 51 | 52 | * https://unpkg.com/linkify-plus-plus-core/dist/linkify-plus-plus-core.js 53 | * https://unpkg.com/linkify-plus-plus-core/dist/linkify-plus-plus-core.min.js 54 | 55 | Usage 56 | ----- 57 | 58 | ```JavaScript 59 | // create a matcher 60 | const matcher = new UrlMatcher(); 61 | 62 | for (const link of matcher.match(text)) { 63 | // matcher.match() returns a generator, yielding an object for each match result 64 | console.log(link.start, link.end, link.text, link.url); 65 | } 66 | ``` 67 | 68 | ```JavaScript 69 | // Linkifier needs a matcher to work 70 | const linkifier = new Linkifier(document.body, {matcher: matcher}); 71 | 72 | // Linkifier will walk through the DOM tree, match url against all text nodes, and replace them with anchor element. 73 | linkifier.on("complete", elapse => { 74 | console.log(`finished in ${elapse}ms`); 75 | }); 76 | linkifier.on("error", err => { 77 | console.log("failed with error:", err); 78 | }); 79 | linkifier.start(); 80 | 81 | // It is suggested to use `linkify()` function which wraps Linkifier to a promise. 82 | linkify(document.body, {matcher}).then(onComplete, onError); 83 | ``` 84 | 85 | API references 86 | -------------- 87 | 88 | This module exports: 89 | 90 | * UrlMatcher - a class to find link from string 91 | * Linkifier - a class to linkify elements 92 | * linkify - a function wrapping Linkifier. Return a promise. 93 | * INVALID_TAGS - a table of uppercase tag name, which are invalid ancestors for `` element. 94 | 95 | ### UrlMatcher 96 | 97 | ```js 98 | const urlMatcher = new UrlMatcher({ 99 | fuzzyIp: Boolean, 100 | mail: Boolean, 101 | ignoreMustache: Boolean, 102 | unicode: Boolean, 103 | customRules: Array, 104 | standalone: Boolean, 105 | boundaryLeft: String, 106 | boundaryRight: String 107 | }); 108 | ``` 109 | 110 | All options are optional: 111 | 112 | * `fuzzyIp` - match 4 digits IP, which often looks like version numbers. Default: `true` 113 | * `mail` - match email. Default: `true` 114 | * `ignoreMustache` - ignore links inside mustache "{{", "}}". This is useful to work with other template library like Vue.js. Default: `false` 115 | * `unicode` - match unicode character. Default: `false` 116 | * `customRules` - a list of regex pattern (in string). E.g. `["file:///\\S+", "magnet:\\?\\S+"]`. Default: `[]` 117 | * `standalone` - the link must be surrounded by whitespace. Default: `false` 118 | * `boundaryLeft` - has no effect without the `standalone` option. Allow some characters to be placed between whitespace and link. Some common characters are `{[("'`. Default: `""` 119 | * `boundaryRight` - has no effect without the `standalone` option. Allow some characters to be placed between whitespace and link. Some common characters are `'")]},.;?!`. Default: `""` 120 | 121 | #### urlMatcher.match 122 | 123 | ```js 124 | for (const matchResult of urlMatcher.match(text: String)) { 125 | ... 126 | } 127 | ``` 128 | 129 | Match the text and return a generator which yields matched results. 130 | 131 | `matchResult` object: 132 | 133 | ```js 134 | matchResult: { 135 | start: Integer, 136 | end: Integer, 137 | text: String, 138 | url: String, 139 | custom: Boolean, 140 | protocol: String, 141 | auth: String, 142 | domain: String, 143 | port: String, 144 | path: String 145 | } 146 | ``` 147 | 148 | * `start` - the start position of the url. 149 | * `end` - the end position of the url. 150 | * `text` - matched text. 151 | * `url` - the url of the link. `.url` doesn't always equal `.text`, that `.text` might lack of the protocol but `.url` is always a full URL. 152 | * `custom` - indicate if the result is matched by custom 4rules. 153 | 154 | Other properties i.e. `.protocol`, `.auth`, `.domain`, `.port`, and `.path` are different parts of the URL. 155 | 156 | ### Linkifier 157 | 158 | ```js 159 | const linkifier = new Linkifier([root: Element, ] options: Object); 160 | ``` 161 | 162 | This class extends [`event-lite`](https://www.npmjs.com/package/event-lite). 163 | 164 | * `root` - the element that is going to be linkified. 165 | 166 | `options` object: 167 | 168 | ```js 169 | options: { 170 | matcher: UrlMatcher, 171 | validator?: Function, 172 | newTab?: Boolean, 173 | noOpener?: Boolean, 174 | root?: Element, 175 | embedImage?: Boolean, 176 | maxRunTime?: Number, 177 | timeout?: Number, 178 | recursive?: Boolean 179 | } 180 | ``` 181 | 182 | * `matcher` - A `UrlMatcher`, required. 183 | 184 | In fact, any object having a `.match` method which accepts a string and returns an iterable of matched result should work. 185 | 186 | The match result must have `.start`, `.end`, `.text`, and `.url` properties described above. 187 | 188 | * `validator` - A function recieving an element and returning a boolean to decide if the element should be linkified. Note that the elements in `INVALID_TAGS` are already filtered out before the validator. 189 | * `newTab` - add `target="_blank"` to the link. Default: `true` 190 | * `noOpener` - add `rel="noopener"` to the link. Default: `true` 191 | * `root` - if you didn't supply the position argument `root` argument to the constructor, this value is used. 192 | * `embedImage` - create `` for the link if the URL looks like an image. Default: `true` 193 | * `maxRunTime` - in milliseconds. The linkify process is split into small chunks to avoid blocking. This is the max execution time of each chunk. Default: `100` 194 | * `timeout` - in milliseconds. If linkification have processed over this value, an error is raised. Note that any heavy work between each chunks are counted as in timeout too. Default: `10000` 195 | * `recursive` - if true, linkify the entire node tree. Otherwise, only text nodes under `root` are linkified. Default: `true` 196 | 197 | #### linkifier.start 198 | 199 | ```js 200 | linkifier.start() 201 | ``` 202 | 203 | Start linkification. The linkifier would walk through the DOM tree, collect text nodes and `` tags, match URLs with matcher, and convert them into links. 204 | 205 | #### linkifier.abort 206 | 207 | ```js 208 | linkifier.abort() 209 | ``` 210 | 211 | Abort linkification. 212 | 213 | #### linkifier events 214 | 215 | `Linkifier` emits following events, which could be listened with `.on`: 216 | 217 | * `complete` - emitted when the linkification completed. Listener arguments: 218 | 219 | - `elapse: Number` - time in milliseconds that the linkifier took to complete. 220 | 221 | * `error` - emitted when the linkification failed. Listener arguments: 222 | 223 | - `error: Error` - The error. 224 | 225 | * `link` - emitted when a link is created. You can alter the style, or implement your link builder to replace the default one. Listener arguments: 226 | 227 | - An object containing following properties: 228 | 229 | - `result: Object` - the result object yielded by `UrlMatcher.match()` 230 | - `range: Range` - the text range that the linkifier is working on. Do not change the range unless you know what you are doing. 231 | - `link: AnchorElement` - the link element. 232 | - `content: DocumentFragment` - the text (including `` tags) extracted from matched text range, which is usually used as the content of the link. 233 | 234 | ### linkify 235 | 236 | ```js 237 | async linkify([root: Element, ] options: Object) 238 | ``` 239 | 240 | A convenient function to setup/start a linkifier. See `Linkifier` for the arguments. Additionally, if the options object has some keys starting with `on`, the function treats them as event listeners. You can register event listeners like: 241 | 242 | ```js 243 | linkify({ 244 | root, 245 | matcher, 246 | onlink: ({link}) => {...} 247 | }) 248 | .then(...); 249 | ``` 250 | 251 | Other notes 252 | ----------- 253 | * https://www.measurethat.net/Benchmarks/Show/1312/3/generator 254 | * https://www.measurethat.net/Benchmarks/Show/1313/0/generator-with-low-count-of-items 255 | 256 | License 257 | ------- 258 | In the very old days, the script is based on Linkify Plus. Although it has been rewritten multiple times, the original license can be found [here](https://github.com/eight04/linkify-plus-plus-core/blob/master/LICENSE). 259 | 260 | TLD list is grabbed from . 261 | 262 | TLD count is grabbed from . 263 | 264 | Changelog 265 | --------- 266 | 267 | * 0.7.0 (Feb 20, 2025) 268 | 269 | - Add: onion TLD. 270 | - Update TLDs. 271 | 272 | * 0.6.1 (Feb 16, 2024) 273 | 274 | - Fix: options is undefined error. 275 | 276 | * 0.6.0 (Feb 14, 2024) 277 | 278 | - Add: `recursive` option in `Linkifier`. 279 | - Update TLDs. 280 | 281 | * 0.5.3 (Mar 10, 2021) 282 | 283 | - Fix: allow domains starting with digits. 284 | 285 | * 0.5.2 (Feb 12, 2021) 286 | 287 | - Fix: infinite loop bug. 288 | 289 | * 0.5.1 (Feb 11, 2021) 290 | 291 | - Update TLDs. 292 | - Change: match custom rules first. 293 | - Fix: handle invalid domains in a better way. 294 | 295 | * 0.5.0 (Oct 29, 2020) 296 | 297 | - Update TLDs. 298 | - Add: mail option. 299 | - Add: embed webp and apng. 300 | - **Change: the matcher will only verify TLD if the protocol is http(s) or mailto.** 301 | 302 | * 0.4.1 (Jun 17, 2019) 303 | 304 | - Update TLDs. 305 | 306 | * 0.4.0 (Feb 17, 2019) 307 | 308 | - **Breaking: drop Firefox < 56.** 309 | - **Breaking: drop babel.** 310 | - **Breaking: INVALID_TAGS is now in lower-case.** 311 | - Add: support XHTML pages. 312 | - Update TLDs. 313 | 314 | * 0.3.0 (Aug 23, 2017) 315 | 316 | - **Drop: Linkifier.prototype.linkify. Now Linkifier uses event pattern.** 317 | - Add linkify function. 318 | - Update TLDs. 319 | 320 | * 0.2.0 (Mar 4, 2017) 321 | 322 | - Use standalone build instead of require. 323 | - Fix: blocking bug with large element without matching urls. 324 | 325 | * 0.1.0 (Feb 23, 2017) 326 | 327 | - First release 328 | -------------------------------------------------------------------------------- /build-tlds.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | const cheerio = require("cheerio"); 3 | const punycode = require("punycode"); 4 | 5 | async function rp(url) { 6 | const r = await fetch(url); 7 | if (!r.ok) { 8 | throw new Error(`Failed to fetch ${url}`); 9 | } 10 | return r.text(); 11 | } 12 | 13 | Promise.all([ 14 | rp("http://data.iana.org/TLD/tlds-alpha-by-domain.txt"), 15 | rp("http://research.domaintools.com/statistics/tld-counts/") 16 | ]).then(function([tlds, statistic]) { 17 | var $ = cheerio.load(statistic), 18 | tldCount = {}; 19 | 20 | $("#tld-counts tbody").children().each(function(){ 21 | var name = $(this).data("key"), 22 | amount = $(this).find(".amount").text().replace(/,/g, ""); 23 | 24 | if (amount == "N/A") { 25 | amount = 0; 26 | } 27 | 28 | tldCount[name] = +amount; 29 | }); 30 | 31 | tlds = tlds.split("\n") 32 | .map(line => line.toLowerCase()) 33 | .filter( 34 | line => 35 | line 36 | && line[0] != "#" 37 | && (tldCount[line] > 2 || tldCount[line] == undefined) 38 | ); 39 | 40 | tlds = tlds.concat( 41 | tlds.filter(tld => tld.startsWith("xn--")) 42 | .map(tld => punycode.decode(tld.substr(4))) 43 | ); 44 | 45 | tlds.push("onion"); 46 | 47 | var repl = { 48 | maxLength: tlds.reduce( 49 | (max, tld) => tld.length > max ? tld.length : max, 50 | 0 51 | ), 52 | 53 | chars: [...tlds.reduce( 54 | (s, tld) => { 55 | for (let c of tld) { 56 | if (c.charCodeAt(0) >= 128) { 57 | s.add(c); 58 | } 59 | } 60 | return s; 61 | }, 62 | new Set 63 | )].join(""), 64 | 65 | table: tlds.reduce( 66 | (o, tld) => { 67 | o[tld] = true; 68 | return o; 69 | }, 70 | {} 71 | ) 72 | }; 73 | 74 | process.stdout.write(JSON.stringify(repl, null, " ")); 75 | }); 76 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | ignore: 2 | - node_modules 3 | -------------------------------------------------------------------------------- /demo/demo.css: -------------------------------------------------------------------------------- 1 | body { 2 | word-wrap: break-word; 3 | } 4 | .main a { 5 | background-color: greenyellow; 6 | } 7 | img { 8 | color: red; 9 | } 10 | -------------------------------------------------------------------------------- /demo/demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Linkify Plus Plus Core 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |

Linkify Plus Plus Core Demo

14 | 18 | 22 | 26 | 30 | 34 |
35 |
36 |

Input:

37 | 38 |
39 |
40 |

Output:

41 |
42 |
43 |
44 |
45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /demo/demo.js: -------------------------------------------------------------------------------- 1 | /* eslint-env browser */ 2 | /* globals Vue, linkifyPlusPlusCore */ 3 | var {UrlMatcher, linkify} = linkifyPlusPlusCore; 4 | 5 | var app = new Vue({ 6 | el: ".main", 7 | data: { 8 | text: "Try some links here!\n\nexample.com\nhttp://www.example.com", 9 | options: { 10 | fuzzyIp: true, 11 | ignoreMustache: true, 12 | unicode: false, 13 | newTab: true, 14 | embedImage: true 15 | } 16 | } 17 | }); 18 | 19 | var state = { 20 | working: false, 21 | pending: false 22 | }; 23 | 24 | function output() { 25 | if (state.working) { 26 | state.pending = true; 27 | return; 28 | } 29 | state.working = true; 30 | var out = document.querySelector("#output"); 31 | out.textContent = app.text; 32 | var options = Object.assign(app.options); 33 | options.matcher = new UrlMatcher(options); 34 | linkify(out, options).then(() => { 35 | state.working = false; 36 | if (state.pending) { 37 | state.pending = false; 38 | output(); 39 | } 40 | }); 41 | } 42 | 43 | app.$watch(function() { 44 | return [this.text, this.options]; 45 | }, output, {deep: true}); 46 | 47 | output(); 48 | 49 | function resize() { 50 | var el = document.querySelector("#input"); 51 | el.style.minHeight = Math.max(el.scrollHeight, el.offsetHeight) + "px"; 52 | } 53 | 54 | app.$watch("text", resize); 55 | 56 | resize(); 57 | -------------------------------------------------------------------------------- /dist/linkify-plus-plus-core.esm.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"linkify-plus-plus-core.esm.js","sources":["../lib/url-matcher.js","../node_modules/event-lite/event-lite.mjs","../lib/linkifier.js"],"sourcesContent":["var tlds = require(\"./tlds.json\"),\n\tRE = {\n\t\tPROTOCOL: \"([a-z][-a-z*]+://)?\",\n\t\tUSER: \"(?:([\\\\w:.+-]+)@)?\",\n\t\tDOMAIN_UNI: `([a-z0-9-.\\\\u00A0-\\\\uFFFF]+\\\\.[a-z0-9-${tlds.chars}]{1,${tlds.maxLength}})`,\n\t\tDOMAIN: `([a-z0-9-.]+\\\\.[a-z0-9-]{1,${tlds.maxLength}})`,\n\t\tPORT: \"(:\\\\d+\\\\b)?\",\n\t\tPATH_UNI: \"([/?#]\\\\S*)?\",\n\t\tPATH: \"([/?#][\\\\w-.~!$&*+;=:@%/?#(),'\\\\[\\\\]]*)?\"\n\t},\n\tTLD_TABLE = tlds.table;\n\nfunction regexEscape(text) {\n\treturn text.replace(/[[\\]\\\\^-]/g, \"\\\\$&\");\n}\n\nfunction buildRegex({\n\tunicode = false, customRules = [], standalone = false,\n\tboundaryLeft, boundaryRight\n}) {\n\tvar pattern = RE.PROTOCOL + RE.USER;\n\t\n\tif (unicode) {\n\t\tpattern += RE.DOMAIN_UNI + RE.PORT + RE.PATH_UNI;\n\t} else {\n\t\tpattern += RE.DOMAIN + RE.PORT + RE.PATH;\n\t}\n\t\n\tif (customRules.length) {\n\t\tpattern = \"(?:(\" + customRules.join(\"|\") + \")|\" + pattern + \")\";\n\t} else {\n\t\tpattern = \"()\" + pattern;\n\t}\n\t\n\tvar prefix, suffix, invalidSuffix;\n\tif (standalone) {\n\t\tif (boundaryLeft) {\n\t\t\tprefix = \"((?:^|\\\\s)[\" + regexEscape(boundaryLeft) + \"]*?)\";\n\t\t} else {\n\t\t\tprefix = \"(^|\\\\s)\";\n\t\t}\n\t\tif (boundaryRight) {\n\t\t\tsuffix = \"([\" + regexEscape(boundaryRight) + \"]*(?:$|\\\\s))\";\n\t\t} else {\n\t\t\tsuffix = \"($|\\\\s)\";\n\t\t}\n\t\tinvalidSuffix = \"[^\\\\s\" + regexEscape(boundaryRight) + \"]\";\n\t} else {\n\t\tprefix = \"(^|\\\\b|_)\";\n\t\tsuffix = \"()\";\n\t}\n\t\n\tpattern = prefix + pattern + suffix;\n\t\n\treturn {\n\t\turl: new RegExp(pattern, \"igm\"),\n\t\tinvalidSuffix: invalidSuffix && new RegExp(invalidSuffix),\n\t\tmustache: /\\{\\{[\\s\\S]+?\\}\\}/g\n\t};\n}\n\nfunction pathStrip(m, re, repl) {\n\tvar s = m.path.replace(re, repl);\n\n\tif (s == m.path) return;\n\t\n\tm.end -= m.path.length - s.length;\n\tm.suffix = m.path.slice(s.length) + m.suffix;\n\tm.path = s;\n}\n\nfunction pathStripQuote(m, c) {\n\tvar i = 0, s = m.path, end, pos = 0;\n\t\n\tif (!s.endsWith(c)) return;\n\t\n\twhile ((pos = s.indexOf(c, pos)) >= 0) {\n\t\tif (i % 2) {\n\t\t\tend = null;\n\t\t} else {\n\t\t\tend = pos;\n\t\t}\n\t\tpos++;\n\t\ti++;\n\t}\n\t\n\tif (!end) return;\n\t\n\tm.end -= s.length - end;\n\tm.path = s.slice(0, end);\n\tm.suffix = s.slice(end) + m.suffix;\n}\n\nfunction pathStripBrace(m, left, right) {\n\tvar str = m.path,\n\t\tre = new RegExp(\"[\\\\\" + left + \"\\\\\" + right + \"]\", \"g\"),\n\t\tmatch, count = 0, end;\n\n\t// Match loop\n\twhile ((match = re.exec(str))) {\n\t\tif (count % 2 == 0) {\n\t\t\tend = match.index;\n\t\t\tif (match[0] == right) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t} else {\n\t\t\tif (match[0] == left) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tcount++;\n\t}\n\n\tif (!match && count % 2 == 0) {\n\t\treturn;\n\t}\n\t\n\tm.end -= m.path.length - end;\n\tm.path = str.slice(0, end);\n\tm.suffix = str.slice(end) + m.suffix;\n}\n\nfunction isIP(s) {\n\tvar m, i;\n\tif (!(m = s.match(/^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$/))) {\n\t\treturn false;\n\t}\n\tfor (i = 1; i < m.length; i++) {\n\t\tif (+m[i] > 255 || (m[i].length > 1 && m[i][0] == \"0\")) {\n\t\t\treturn false;\n\t\t}\n\t}\n\treturn true;\n}\n\nfunction inTLDS(domain) {\n\tvar match = domain.match(/\\.([^.]+)$/);\n\tif (!match) {\n\t\treturn false;\n\t}\n\tvar key = match[1].toLowerCase();\n // eslint-disable-next-line no-prototype-builtins\n\treturn TLD_TABLE.hasOwnProperty(key);\n}\n\nclass UrlMatcher {\n\tconstructor(options = {}) {\n\t\tthis.options = options;\n\t\tthis.regex = buildRegex(options);\n\t}\n\t\n\t*match(text) {\n\t\tvar {\n\t\t\t\tfuzzyIp = true,\n\t\t\t\tignoreMustache = false,\n mail = true\n\t\t\t} = this.options,\n\t\t\t{\n\t\t\t\turl,\n\t\t\t\tinvalidSuffix,\n\t\t\t\tmustache\n\t\t\t} = this.regex,\n\t\t\turlLastIndex, mustacheLastIndex;\n\t\t\t\n\t\tmustache.lastIndex = 0;\n\t\turl.lastIndex = 0;\n\t\t\n\t\tvar mustacheMatch, mustacheRange;\n\t\tif (ignoreMustache) {\n\t\t\tmustacheMatch = mustache.exec(text);\n\t\t\tif (mustacheMatch) {\n\t\t\t\tmustacheRange = {\n\t\t\t\t\tstart: mustacheMatch.index,\n\t\t\t\t\tend: mustache.lastIndex\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\t\n\t\tvar urlMatch;\n\t\twhile ((urlMatch = url.exec(text))) {\n const result = {\n start: 0,\n end: 0,\n \n text: \"\",\n url: \"\",\n \n prefix: urlMatch[1],\n custom: urlMatch[2],\n protocol: urlMatch[3],\n auth: urlMatch[4] || \"\",\n domain: urlMatch[5],\n port: urlMatch[6] || \"\",\n path: urlMatch[7] || \"\",\n suffix: urlMatch[8]\n };\n \n if (result.custom) {\n result.start = urlMatch.index;\n result.end = url.lastIndex;\n result.text = result.url = urlMatch[0];\n\t\t\t} else {\n \n result.start = urlMatch.index + result.prefix.length;\n result.end = url.lastIndex - result.suffix.length;\n\t\t\t}\n\t\t\t\n\t\t\tif (mustacheRange && mustacheRange.end <= result.start) {\n\t\t\t\tmustacheMatch = mustache.exec(text);\n\t\t\t\tif (mustacheMatch) {\n\t\t\t\t\tmustacheRange.start = mustacheMatch.index;\n\t\t\t\t\tmustacheRange.end = mustache.lastIndex;\n\t\t\t\t} else {\n\t\t\t\t\tmustacheRange = null;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// ignore urls inside mustache pair\n\t\t\tif (mustacheRange && result.start < mustacheRange.end && result.end >= mustacheRange.start) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t\n\t\t\tif (!result.custom) {\n\t\t\t\t// adjust path and suffix\n\t\t\t\tif (result.path) {\n\t\t\t\t\t// Strip BBCode\n\t\t\t\t\tpathStrip(result, /\\[\\/?(b|i|u|url|img|quote|code|size|color)\\].*/i, \"\");\n\t\t\t\t\t\n\t\t\t\t\t// Strip braces\n\t\t\t\t\tpathStripBrace(result, \"(\", \")\");\n\t\t\t\t\tpathStripBrace(result, \"[\", \"]\");\n\t\t\t\t\tpathStripBrace(result, \"{\", \"}\");\n\t\t\t\t\t\n\t\t\t\t\t// Strip quotes\n\t\t\t\t\tpathStripQuote(result, \"'\");\n\t\t\t\t\tpathStripQuote(result, '\"');\n\t\t\t\t\t\n\t\t\t\t\t// Remove trailing \".,?\"\n\t\t\t\t\tpathStrip(result, /(^|[^-_])[.,?]+$/, \"$1\");\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// check suffix\n\t\t\t\tif (invalidSuffix && invalidSuffix.test(result.suffix)) {\n\t\t\t\t\tif (/\\s$/.test(result.suffix)) {\n\t\t\t\t\t\turl.lastIndex--;\n\t\t\t\t\t}\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n \n // ignore fuzzy ip\n\t\t\t\tif (!fuzzyIp && isIP(result.domain) &&\n !result.protocol && !result.auth && !result.path) {\n continue;\n }\n \n\t\t\t\t// mailto protocol\n\t\t\t\tif (!result.protocol && result.auth) {\n\t\t\t\t\tvar matchMail = result.auth.match(/^mailto:(.+)/);\n\t\t\t\t\tif (matchMail) {\n\t\t\t\t\t\tresult.protocol = \"mailto:\";\n\t\t\t\t\t\tresult.auth = matchMail[1];\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// http alias\n\t\t\t\tif (result.protocol && result.protocol.match(/^(hxxp|h\\*\\*p|ttp)/)) {\n\t\t\t\t\tresult.protocol = \"http://\";\n\t\t\t\t}\n\n\t\t\t\t// guess protocol\n\t\t\t\tif (!result.protocol) {\n\t\t\t\t\tvar domainMatch;\n\t\t\t\t\tif ((domainMatch = result.domain.match(/^(ftp|irc)/))) {\n\t\t\t\t\t\tresult.protocol = domainMatch[0] + \"://\";\n\t\t\t\t\t} else if (result.domain.match(/^(www|web)/)) {\n\t\t\t\t\t\tresult.protocol = \"http://\";\n\t\t\t\t\t} else if (result.auth && result.auth.indexOf(\":\") < 0 && !result.path) {\n\t\t\t\t\t\tresult.protocol = \"mailto:\";\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresult.protocol = \"http://\";\n\t\t\t\t\t}\n\t\t\t\t}\n \n // ignore mail\n if (!mail && result.protocol === \"mailto:\") {\n continue;\n }\n \n\t\t\t\t// verify domain\n if (!isIP(result.domain)) {\n if (/^(http|https|mailto)/.test(result.protocol) && !inTLDS(result.domain)) {\n continue;\n }\n \n const invalidLabel = getInvalidLabel(result.domain);\n if (invalidLabel) {\n url.lastIndex = urlMatch.index + invalidLabel.index + 1;\n continue;\n }\n }\n\n\t\t\t\t// Create URL\n\t\t\t\tresult.url = result.protocol + (result.auth && result.auth + \"@\") + result.domain + result.port + result.path;\n\t\t\t\tresult.text = text.slice(result.start, result.end);\n\t\t\t}\n\t\t\t\n\t\t\t// since regex is shared with other parse generators, cache lastIndex position and restore later\n\t\t\tmustacheLastIndex = mustache.lastIndex;\n\t\t\turlLastIndex = url.lastIndex;\n\t\t\t\n\t\t\tyield result;\n\t\t\t\n\t\t\turl.lastIndex = urlLastIndex;\n\t\t\tmustache.lastIndex = mustacheLastIndex;\n\t\t}\n\t}\n}\n\nfunction getInvalidLabel(domain) {\n // https://tools.ietf.org/html/rfc1035\n // https://serverfault.com/questions/638260/is-it-valid-for-a-hostname-to-start-with-a-digit\n let index = 0;\n const parts = domain.split(\".\");\n for (const part of parts) {\n if (\n !part ||\n part.startsWith(\"-\") ||\n part.endsWith(\"-\")\n ) {\n return {\n index,\n value: part\n };\n }\n index += part.length + 1;\n }\n}\n\nmodule.exports = {\n\tUrlMatcher\n};\n","/**\n * event-lite.js - Light-weight EventEmitter (less than 1KB when gzipped)\n *\n * @copyright Yusuke Kawasaki\n * @license MIT\n * @constructor\n * @see https://github.com/kawanet/event-lite\n * @see http://kawanet.github.io/event-lite/EventLite.html\n * @example\n * var EventLite = require(\"event-lite\");\n *\n * function MyClass() {...} // your class\n *\n * EventLite.mixin(MyClass.prototype); // import event methods\n *\n * var obj = new MyClass();\n * obj.on(\"foo\", function() {...}); // add event listener\n * obj.once(\"bar\", function() {...}); // add one-time event listener\n * obj.emit(\"foo\"); // dispatch event\n * obj.emit(\"bar\"); // dispatch another event\n * obj.off(\"foo\"); // remove event listener\n */\n\nexport default function EventLite() {\n if (!(this instanceof EventLite)) return new EventLite();\n}\n\n// (function(EventLite) {\n // export the class for node.js\n // if (\"undefined\" !== typeof module) module.exports = EventLite;\n\n // property name to hold listeners\n var LISTENERS = \"listeners\";\n\n // methods to export\n var methods = {\n on: on,\n once: once,\n off: off,\n emit: emit\n };\n\n // mixin to self\n mixin(EventLite.prototype);\n\n // export mixin function\n EventLite.mixin = mixin;\n\n /**\n * Import on(), once(), off() and emit() methods into target object.\n *\n * @function EventLite.mixin\n * @param target {Prototype}\n */\n\n function mixin(target) {\n for (var key in methods) {\n target[key] = methods[key];\n }\n return target;\n }\n\n /**\n * Add an event listener.\n *\n * @function EventLite.prototype.on\n * @param type {string}\n * @param func {Function}\n * @returns {EventLite} Self for method chaining\n */\n\n function on(type, func) {\n getListeners(this, type).push(func);\n return this;\n }\n\n /**\n * Add one-time event listener.\n *\n * @function EventLite.prototype.once\n * @param type {string}\n * @param func {Function}\n * @returns {EventLite} Self for method chaining\n */\n\n function once(type, func) {\n var that = this;\n wrap.originalListener = func;\n getListeners(that, type).push(wrap);\n return that;\n\n function wrap() {\n off.call(that, type, wrap);\n func.apply(this, arguments);\n }\n }\n\n /**\n * Remove an event listener.\n *\n * @function EventLite.prototype.off\n * @param [type] {string}\n * @param [func] {Function}\n * @returns {EventLite} Self for method chaining\n */\n\n function off(type, func) {\n var that = this;\n var listners;\n if (!arguments.length) {\n delete that[LISTENERS];\n } else if (!func) {\n listners = that[LISTENERS];\n if (listners) {\n delete listners[type];\n if (!Object.keys(listners).length) return off.call(that);\n }\n } else {\n listners = getListeners(that, type, true);\n if (listners) {\n listners = listners.filter(ne);\n if (!listners.length) return off.call(that, type);\n that[LISTENERS][type] = listners;\n }\n }\n return that;\n\n function ne(test) {\n return test !== func && test.originalListener !== func;\n }\n }\n\n /**\n * Dispatch (trigger) an event.\n *\n * @function EventLite.prototype.emit\n * @param type {string}\n * @param [value] {*}\n * @returns {boolean} True when a listener received the event\n */\n\n function emit(type, value) {\n var that = this;\n var listeners = getListeners(that, type, true);\n if (!listeners) return false;\n var arglen = arguments.length;\n if (arglen === 1) {\n listeners.forEach(zeroarg);\n } else if (arglen === 2) {\n listeners.forEach(onearg);\n } else {\n var args = Array.prototype.slice.call(arguments, 1);\n listeners.forEach(moreargs);\n }\n return !!listeners.length;\n\n function zeroarg(func) {\n func.call(that);\n }\n\n function onearg(func) {\n func.call(that, value);\n }\n\n function moreargs(func) {\n func.apply(that, args);\n }\n }\n\n /**\n * @ignore\n */\n\n function getListeners(that, type, readonly) {\n if (readonly && !that[LISTENERS]) return;\n var listeners = that[LISTENERS] || (that[LISTENERS] = {});\n return listeners[type] || (listeners[type] = []);\n }\n\n// })(EventLite);\n","/* eslint-env browser */\n\nvar Events = require(\"event-lite\");\n\nvar INVALID_TAGS = {\n\ta: true,\n\tnoscript: true,\n\toption: true,\n\tscript: true,\n\tstyle: true,\n\ttextarea: true,\n\tsvg: true,\n\tcanvas: true,\n\tbutton: true,\n\tselect: true,\n\ttemplate: true,\n\tmeter: true,\n\tprogress: true,\n\tmath: true,\n\ttime: true\n};\n\nclass Pos {\n\tconstructor(container, offset, i = 0) {\n\t\tthis.container = container;\n\t\tthis.offset = offset;\n\t\tthis.i = i;\n\t}\n\t\n\tadd(change) {\n\t\tvar cont = this.container,\n\t\t\toffset = this.offset;\n\n\t\tthis.i += change;\n\t\t\n\t\t// If the container is #text.parentNode\n\t\tif (cont.childNodes.length) {\n\t\t\tcont = cont.childNodes[offset];\n\t\t\toffset = 0;\n\t\t}\n\n\t\t// If the container is #text\n\t\twhile (cont) {\n\t\t\tif (cont.nodeType == 3) {\n\t\t\t\tif (!cont.LEN) {\n\t\t\t\t\tcont.LEN = cont.nodeValue.length;\n\t\t\t\t}\n\t\t\t\tif (offset + change <= cont.LEN) {\n\t\t\t\t\tthis.container = cont;\n\t\t\t\t\tthis.offset = offset + change;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tchange = offset + change - cont.LEN;\n\t\t\t\toffset = 0;\n\t\t\t}\n\t\t\tcont = cont.nextSibling;\n\t\t}\n\t}\n\t\n\tmoveTo(offset) {\n\t\tthis.add(offset - this.i);\n\t}\n}\n\nfunction cloneContents(range) {\n\tif (range.startContainer == range.endContainer) {\n\t\treturn document.createTextNode(range.toString());\n\t}\n\treturn range.cloneContents();\n}\n\nvar DEFAULT_OPTIONS = {\n\tmaxRunTime: 100,\n\ttimeout: 10000,\n\tnewTab: true,\n\tnoOpener: true,\n\tembedImage: true,\n recursive: true,\n};\n\nclass Linkifier extends Events {\n\tconstructor(root, options = {}) {\n\t\tsuper();\n\t\tif (!(root instanceof Node)) {\n\t\t\toptions = root;\n\t\t\troot = options.root;\n\t\t}\n\t\tthis.root = root;\n\t\tthis.options = Object.assign({}, DEFAULT_OPTIONS, options);\n\t\tthis.aborted = false;\n\t}\n\tstart() {\n\t\tvar time = Date.now,\n\t\t\tstartTime = time(),\n\t\t\tchunks = this.generateChunks();\n\t\t\t\n\t\tvar next = () => {\n\t\t\tif (this.aborted) {\n\t\t\t\tthis.emit(\"error\", new Error(\"Aborted\"));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvar chunkStart = time(),\n\t\t\t\tnow;\n\t\t\t\t\n\t\t\tdo {\n\t\t\t\tif (chunks.next().done) {\n\t\t\t\t\tthis.emit(\"complete\", time() - startTime);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t} while ((now = time()) - chunkStart < this.options.maxRunTime);\n\t\t\t\n\t\t\tif (now - startTime > this.options.timeout) {\n\t\t\t\tthis.emit(\"error\", new Error(`max execution time exceeded: ${now - startTime}, on ${this.root}`));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tsetTimeout(next);\n\t\t};\n\t\t\t\n\t\tsetTimeout(next);\n\t}\n\tabort() {\n\t\tthis.aborted = true;\n\t}\n\t*generateRanges() {\n\t\tvar {validator, recursive} = this.options;\n\t\tvar filter = {\n\t\t\tacceptNode: function(node) {\n\t\t\t\tif (validator && !validator(node)) {\n\t\t\t\t\treturn NodeFilter.FILTER_REJECT;\n\t\t\t\t}\n\t\t\t\tif (INVALID_TAGS[node.localName]) {\n\t\t\t\t\treturn NodeFilter.FILTER_REJECT;\n\t\t\t\t}\n\t\t\t\tif (node.localName == \"wbr\") {\n\t\t\t\t\treturn NodeFilter.FILTER_ACCEPT;\n\t\t\t\t}\n\t\t\t\tif (node.nodeType == 3) {\n\t\t\t\t\treturn NodeFilter.FILTER_ACCEPT;\n\t\t\t\t}\n\t\t\t\treturn recursive ? NodeFilter.FILTER_SKIP : NodeFilter.FILTER_REJECT;\n\t\t\t}\n\t\t};\n\t\t// Generate linkified ranges.\n\t\tvar walker = document.createTreeWalker(\n\t\t\tthis.root,\n\t\t\tNodeFilter.SHOW_TEXT + NodeFilter.SHOW_ELEMENT,\n\t\t\tfilter\n\t\t), start, end, current, range;\n\n\t\tend = start = walker.nextNode();\n\t\tif (!start) {\n\t\t\treturn;\n\t\t}\n\t\trange = document.createRange();\n\t\trange.setStartBefore(start);\n\t\twhile ((current = walker.nextNode())) {\n\t\t\tif (end.nextSibling == current) {\n\t\t\t\tend = current;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\trange.setEndAfter(end);\n\t\t\tyield range;\n\n\t\t\tend = start = current;\n\t\t\trange.setStartBefore(start);\n\t\t}\n\t\trange.setEndAfter(end);\n\t\tyield range;\n\t}\n\t*generateChunks() {\n\t\tvar {matcher} = this.options;\n\t\tfor (var range of this.generateRanges()) {\n\t\t\tvar frag = null,\n\t\t\t\tpos = null,\n\t\t\t\ttext = range.toString(),\n\t\t\t\ttextRange = null;\n\t\t\tfor (var result of matcher.match(text)) {\n\t\t\t\tif (!frag) {\n\t\t\t\t\tfrag = document.createDocumentFragment();\n\t\t\t\t\tpos = new Pos(range.startContainer, range.startOffset);\n\t\t\t\t\ttextRange = range.cloneRange();\n\t\t\t\t}\n\t\t\t\t// clone text\n\t\t\t\tpos.moveTo(result.start);\n\t\t\t\ttextRange.setEnd(pos.container, pos.offset);\n\t\t\t\tfrag.appendChild(cloneContents(textRange));\n\t\t\t\t\n\t\t\t\t// clone link\n\t\t\t\ttextRange.collapse();\n\t\t\t\tpos.moveTo(result.end);\n\t\t\t\ttextRange.setEnd(pos.container, pos.offset);\n\t\t\t\t\n\t\t\t\tvar content = cloneContents(textRange),\n\t\t\t\t\tlink = this.buildLink(result, content);\n\n\t\t\t\ttextRange.collapse();\n\n\t\t\t\tfrag.appendChild(link);\n\t\t\t\tthis.emit(\"link\", {link, range, result, content});\n\t\t\t}\n\t\t\tif (pos) {\n\t\t\t\tpos.moveTo(text.length);\n\t\t\t\ttextRange.setEnd(pos.container, pos.offset);\n\t\t\t\tfrag.appendChild(cloneContents(textRange));\n\t\t\t\t\n\t\t\t\trange.deleteContents();\n\t\t\t\trange.insertNode(frag);\n\t\t\t}\n\t\t\tyield;\n\t\t}\n\t}\n\tbuildLink(result, content) {\n\t\tvar {newTab, embedImage, noOpener} = this.options;\n\t\tvar link = document.createElement(\"a\");\n\t\tlink.href = result.url;\n\t\tlink.title = \"Linkify Plus Plus\";\n\t\tlink.className = \"linkifyplus\";\n\t\tif (newTab) {\n\t\t\tlink.target = \"_blank\";\n\t\t}\n\t\tif (noOpener) {\n\t\t\tlink.rel = \"noopener\";\n\t\t}\n\t\tvar child;\n\t\tif (embedImage && /^[^?#]+\\.(?:jpg|jpeg|png|apng|gif|svg|webp)(?:$|[?#])/i.test(result.url)) {\n\t\t\tchild = new Image;\n\t\t\tchild.src = result.url;\n\t\t\tchild.alt = result.text;\n\t\t} else {\n\t\t\tchild = content;\n\t\t}\n\t\tlink.appendChild(child);\n\t\treturn link;\n\t}\n}\n\nfunction linkify(...args) {\n\treturn new Promise((resolve, reject) => {\n\t\tvar linkifier = new Linkifier(...args);\n\t\tlinkifier.on(\"error\", reject);\n\t\tlinkifier.on(\"complete\", resolve);\n\t\tfor (var key of Object.keys(linkifier.options)) {\n\t\t\tif (key.startsWith(\"on\")) {\n\t\t\t\tlinkifier.on(key.slice(2), linkifier.options[key]);\n\t\t\t}\n\t\t}\n\t\tlinkifier.start();\n\t});\n}\n\nmodule.exports = {\n\tINVALID_TAGS,\n\tLinkifier,\n\tlinkify\n};\n"],"names":["tlds.chars","tlds.maxLength","tlds.table","Events"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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","x_google_ignoreList":[1]} -------------------------------------------------------------------------------- /dist/linkify-plus-plus-core.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"linkify-plus-plus-core.js","sources":["../lib/url-matcher.js","../node_modules/event-lite/event-lite.mjs","../lib/linkifier.js"],"sourcesContent":["var tlds = require(\"./tlds.json\"),\n\tRE = {\n\t\tPROTOCOL: \"([a-z][-a-z*]+://)?\",\n\t\tUSER: \"(?:([\\\\w:.+-]+)@)?\",\n\t\tDOMAIN_UNI: `([a-z0-9-.\\\\u00A0-\\\\uFFFF]+\\\\.[a-z0-9-${tlds.chars}]{1,${tlds.maxLength}})`,\n\t\tDOMAIN: `([a-z0-9-.]+\\\\.[a-z0-9-]{1,${tlds.maxLength}})`,\n\t\tPORT: \"(:\\\\d+\\\\b)?\",\n\t\tPATH_UNI: \"([/?#]\\\\S*)?\",\n\t\tPATH: \"([/?#][\\\\w-.~!$&*+;=:@%/?#(),'\\\\[\\\\]]*)?\"\n\t},\n\tTLD_TABLE = tlds.table;\n\nfunction regexEscape(text) {\n\treturn text.replace(/[[\\]\\\\^-]/g, \"\\\\$&\");\n}\n\nfunction buildRegex({\n\tunicode = false, customRules = [], standalone = false,\n\tboundaryLeft, boundaryRight\n}) {\n\tvar pattern = RE.PROTOCOL + RE.USER;\n\t\n\tif (unicode) {\n\t\tpattern += RE.DOMAIN_UNI + RE.PORT + RE.PATH_UNI;\n\t} else {\n\t\tpattern += RE.DOMAIN + RE.PORT + RE.PATH;\n\t}\n\t\n\tif (customRules.length) {\n\t\tpattern = \"(?:(\" + customRules.join(\"|\") + \")|\" + pattern + \")\";\n\t} else {\n\t\tpattern = \"()\" + pattern;\n\t}\n\t\n\tvar prefix, suffix, invalidSuffix;\n\tif (standalone) {\n\t\tif (boundaryLeft) {\n\t\t\tprefix = \"((?:^|\\\\s)[\" + regexEscape(boundaryLeft) + \"]*?)\";\n\t\t} else {\n\t\t\tprefix = \"(^|\\\\s)\";\n\t\t}\n\t\tif (boundaryRight) {\n\t\t\tsuffix = \"([\" + regexEscape(boundaryRight) + \"]*(?:$|\\\\s))\";\n\t\t} else {\n\t\t\tsuffix = \"($|\\\\s)\";\n\t\t}\n\t\tinvalidSuffix = \"[^\\\\s\" + regexEscape(boundaryRight) + \"]\";\n\t} else {\n\t\tprefix = \"(^|\\\\b|_)\";\n\t\tsuffix = \"()\";\n\t}\n\t\n\tpattern = prefix + pattern + suffix;\n\t\n\treturn {\n\t\turl: new RegExp(pattern, \"igm\"),\n\t\tinvalidSuffix: invalidSuffix && new RegExp(invalidSuffix),\n\t\tmustache: /\\{\\{[\\s\\S]+?\\}\\}/g\n\t};\n}\n\nfunction pathStrip(m, re, repl) {\n\tvar s = m.path.replace(re, repl);\n\n\tif (s == m.path) return;\n\t\n\tm.end -= m.path.length - s.length;\n\tm.suffix = m.path.slice(s.length) + m.suffix;\n\tm.path = s;\n}\n\nfunction pathStripQuote(m, c) {\n\tvar i = 0, s = m.path, end, pos = 0;\n\t\n\tif (!s.endsWith(c)) return;\n\t\n\twhile ((pos = s.indexOf(c, pos)) >= 0) {\n\t\tif (i % 2) {\n\t\t\tend = null;\n\t\t} else {\n\t\t\tend = pos;\n\t\t}\n\t\tpos++;\n\t\ti++;\n\t}\n\t\n\tif (!end) return;\n\t\n\tm.end -= s.length - end;\n\tm.path = s.slice(0, end);\n\tm.suffix = s.slice(end) + m.suffix;\n}\n\nfunction pathStripBrace(m, left, right) {\n\tvar str = m.path,\n\t\tre = new RegExp(\"[\\\\\" + left + \"\\\\\" + right + \"]\", \"g\"),\n\t\tmatch, count = 0, end;\n\n\t// Match loop\n\twhile ((match = re.exec(str))) {\n\t\tif (count % 2 == 0) {\n\t\t\tend = match.index;\n\t\t\tif (match[0] == right) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t} else {\n\t\t\tif (match[0] == left) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tcount++;\n\t}\n\n\tif (!match && count % 2 == 0) {\n\t\treturn;\n\t}\n\t\n\tm.end -= m.path.length - end;\n\tm.path = str.slice(0, end);\n\tm.suffix = str.slice(end) + m.suffix;\n}\n\nfunction isIP(s) {\n\tvar m, i;\n\tif (!(m = s.match(/^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$/))) {\n\t\treturn false;\n\t}\n\tfor (i = 1; i < m.length; i++) {\n\t\tif (+m[i] > 255 || (m[i].length > 1 && m[i][0] == \"0\")) {\n\t\t\treturn false;\n\t\t}\n\t}\n\treturn true;\n}\n\nfunction inTLDS(domain) {\n\tvar match = domain.match(/\\.([^.]+)$/);\n\tif (!match) {\n\t\treturn false;\n\t}\n\tvar key = match[1].toLowerCase();\n // eslint-disable-next-line no-prototype-builtins\n\treturn TLD_TABLE.hasOwnProperty(key);\n}\n\nclass UrlMatcher {\n\tconstructor(options = {}) {\n\t\tthis.options = options;\n\t\tthis.regex = buildRegex(options);\n\t}\n\t\n\t*match(text) {\n\t\tvar {\n\t\t\t\tfuzzyIp = true,\n\t\t\t\tignoreMustache = false,\n mail = true\n\t\t\t} = this.options,\n\t\t\t{\n\t\t\t\turl,\n\t\t\t\tinvalidSuffix,\n\t\t\t\tmustache\n\t\t\t} = this.regex,\n\t\t\turlLastIndex, mustacheLastIndex;\n\t\t\t\n\t\tmustache.lastIndex = 0;\n\t\turl.lastIndex = 0;\n\t\t\n\t\tvar mustacheMatch, mustacheRange;\n\t\tif (ignoreMustache) {\n\t\t\tmustacheMatch = mustache.exec(text);\n\t\t\tif (mustacheMatch) {\n\t\t\t\tmustacheRange = {\n\t\t\t\t\tstart: mustacheMatch.index,\n\t\t\t\t\tend: mustache.lastIndex\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\t\n\t\tvar urlMatch;\n\t\twhile ((urlMatch = url.exec(text))) {\n const result = {\n start: 0,\n end: 0,\n \n text: \"\",\n url: \"\",\n \n prefix: urlMatch[1],\n custom: urlMatch[2],\n protocol: urlMatch[3],\n auth: urlMatch[4] || \"\",\n domain: urlMatch[5],\n port: urlMatch[6] || \"\",\n path: urlMatch[7] || \"\",\n suffix: urlMatch[8]\n };\n \n if (result.custom) {\n result.start = urlMatch.index;\n result.end = url.lastIndex;\n result.text = result.url = urlMatch[0];\n\t\t\t} else {\n \n result.start = urlMatch.index + result.prefix.length;\n result.end = url.lastIndex - result.suffix.length;\n\t\t\t}\n\t\t\t\n\t\t\tif (mustacheRange && mustacheRange.end <= result.start) {\n\t\t\t\tmustacheMatch = mustache.exec(text);\n\t\t\t\tif (mustacheMatch) {\n\t\t\t\t\tmustacheRange.start = mustacheMatch.index;\n\t\t\t\t\tmustacheRange.end = mustache.lastIndex;\n\t\t\t\t} else {\n\t\t\t\t\tmustacheRange = null;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// ignore urls inside mustache pair\n\t\t\tif (mustacheRange && result.start < mustacheRange.end && result.end >= mustacheRange.start) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t\n\t\t\tif (!result.custom) {\n\t\t\t\t// adjust path and suffix\n\t\t\t\tif (result.path) {\n\t\t\t\t\t// Strip BBCode\n\t\t\t\t\tpathStrip(result, /\\[\\/?(b|i|u|url|img|quote|code|size|color)\\].*/i, \"\");\n\t\t\t\t\t\n\t\t\t\t\t// Strip braces\n\t\t\t\t\tpathStripBrace(result, \"(\", \")\");\n\t\t\t\t\tpathStripBrace(result, \"[\", \"]\");\n\t\t\t\t\tpathStripBrace(result, \"{\", \"}\");\n\t\t\t\t\t\n\t\t\t\t\t// Strip quotes\n\t\t\t\t\tpathStripQuote(result, \"'\");\n\t\t\t\t\tpathStripQuote(result, '\"');\n\t\t\t\t\t\n\t\t\t\t\t// Remove trailing \".,?\"\n\t\t\t\t\tpathStrip(result, /(^|[^-_])[.,?]+$/, \"$1\");\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// check suffix\n\t\t\t\tif (invalidSuffix && invalidSuffix.test(result.suffix)) {\n\t\t\t\t\tif (/\\s$/.test(result.suffix)) {\n\t\t\t\t\t\turl.lastIndex--;\n\t\t\t\t\t}\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n \n // ignore fuzzy ip\n\t\t\t\tif (!fuzzyIp && isIP(result.domain) &&\n !result.protocol && !result.auth && !result.path) {\n continue;\n }\n \n\t\t\t\t// mailto protocol\n\t\t\t\tif (!result.protocol && result.auth) {\n\t\t\t\t\tvar matchMail = result.auth.match(/^mailto:(.+)/);\n\t\t\t\t\tif (matchMail) {\n\t\t\t\t\t\tresult.protocol = \"mailto:\";\n\t\t\t\t\t\tresult.auth = matchMail[1];\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// http alias\n\t\t\t\tif (result.protocol && result.protocol.match(/^(hxxp|h\\*\\*p|ttp)/)) {\n\t\t\t\t\tresult.protocol = \"http://\";\n\t\t\t\t}\n\n\t\t\t\t// guess protocol\n\t\t\t\tif (!result.protocol) {\n\t\t\t\t\tvar domainMatch;\n\t\t\t\t\tif ((domainMatch = result.domain.match(/^(ftp|irc)/))) {\n\t\t\t\t\t\tresult.protocol = domainMatch[0] + \"://\";\n\t\t\t\t\t} else if (result.domain.match(/^(www|web)/)) {\n\t\t\t\t\t\tresult.protocol = \"http://\";\n\t\t\t\t\t} else if (result.auth && result.auth.indexOf(\":\") < 0 && !result.path) {\n\t\t\t\t\t\tresult.protocol = \"mailto:\";\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresult.protocol = \"http://\";\n\t\t\t\t\t}\n\t\t\t\t}\n \n // ignore mail\n if (!mail && result.protocol === \"mailto:\") {\n continue;\n }\n \n\t\t\t\t// verify domain\n if (!isIP(result.domain)) {\n if (/^(http|https|mailto)/.test(result.protocol) && !inTLDS(result.domain)) {\n continue;\n }\n \n const invalidLabel = getInvalidLabel(result.domain);\n if (invalidLabel) {\n url.lastIndex = urlMatch.index + invalidLabel.index + 1;\n continue;\n }\n }\n\n\t\t\t\t// Create URL\n\t\t\t\tresult.url = result.protocol + (result.auth && result.auth + \"@\") + result.domain + result.port + result.path;\n\t\t\t\tresult.text = text.slice(result.start, result.end);\n\t\t\t}\n\t\t\t\n\t\t\t// since regex is shared with other parse generators, cache lastIndex position and restore later\n\t\t\tmustacheLastIndex = mustache.lastIndex;\n\t\t\turlLastIndex = url.lastIndex;\n\t\t\t\n\t\t\tyield result;\n\t\t\t\n\t\t\turl.lastIndex = urlLastIndex;\n\t\t\tmustache.lastIndex = mustacheLastIndex;\n\t\t}\n\t}\n}\n\nfunction getInvalidLabel(domain) {\n // https://tools.ietf.org/html/rfc1035\n // https://serverfault.com/questions/638260/is-it-valid-for-a-hostname-to-start-with-a-digit\n let index = 0;\n const parts = domain.split(\".\");\n for (const part of parts) {\n if (\n !part ||\n part.startsWith(\"-\") ||\n part.endsWith(\"-\")\n ) {\n return {\n index,\n value: part\n };\n }\n index += part.length + 1;\n }\n}\n\nmodule.exports = {\n\tUrlMatcher\n};\n","/**\n * event-lite.js - Light-weight EventEmitter (less than 1KB when gzipped)\n *\n * @copyright Yusuke Kawasaki\n * @license MIT\n * @constructor\n * @see https://github.com/kawanet/event-lite\n * @see http://kawanet.github.io/event-lite/EventLite.html\n * @example\n * var EventLite = require(\"event-lite\");\n *\n * function MyClass() {...} // your class\n *\n * EventLite.mixin(MyClass.prototype); // import event methods\n *\n * var obj = new MyClass();\n * obj.on(\"foo\", function() {...}); // add event listener\n * obj.once(\"bar\", function() {...}); // add one-time event listener\n * obj.emit(\"foo\"); // dispatch event\n * obj.emit(\"bar\"); // dispatch another event\n * obj.off(\"foo\"); // remove event listener\n */\n\nexport default function EventLite() {\n if (!(this instanceof EventLite)) return new EventLite();\n}\n\n// (function(EventLite) {\n // export the class for node.js\n // if (\"undefined\" !== typeof module) module.exports = EventLite;\n\n // property name to hold listeners\n var LISTENERS = \"listeners\";\n\n // methods to export\n var methods = {\n on: on,\n once: once,\n off: off,\n emit: emit\n };\n\n // mixin to self\n mixin(EventLite.prototype);\n\n // export mixin function\n EventLite.mixin = mixin;\n\n /**\n * Import on(), once(), off() and emit() methods into target object.\n *\n * @function EventLite.mixin\n * @param target {Prototype}\n */\n\n function mixin(target) {\n for (var key in methods) {\n target[key] = methods[key];\n }\n return target;\n }\n\n /**\n * Add an event listener.\n *\n * @function EventLite.prototype.on\n * @param type {string}\n * @param func {Function}\n * @returns {EventLite} Self for method chaining\n */\n\n function on(type, func) {\n getListeners(this, type).push(func);\n return this;\n }\n\n /**\n * Add one-time event listener.\n *\n * @function EventLite.prototype.once\n * @param type {string}\n * @param func {Function}\n * @returns {EventLite} Self for method chaining\n */\n\n function once(type, func) {\n var that = this;\n wrap.originalListener = func;\n getListeners(that, type).push(wrap);\n return that;\n\n function wrap() {\n off.call(that, type, wrap);\n func.apply(this, arguments);\n }\n }\n\n /**\n * Remove an event listener.\n *\n * @function EventLite.prototype.off\n * @param [type] {string}\n * @param [func] {Function}\n * @returns {EventLite} Self for method chaining\n */\n\n function off(type, func) {\n var that = this;\n var listners;\n if (!arguments.length) {\n delete that[LISTENERS];\n } else if (!func) {\n listners = that[LISTENERS];\n if (listners) {\n delete listners[type];\n if (!Object.keys(listners).length) return off.call(that);\n }\n } else {\n listners = getListeners(that, type, true);\n if (listners) {\n listners = listners.filter(ne);\n if (!listners.length) return off.call(that, type);\n that[LISTENERS][type] = listners;\n }\n }\n return that;\n\n function ne(test) {\n return test !== func && test.originalListener !== func;\n }\n }\n\n /**\n * Dispatch (trigger) an event.\n *\n * @function EventLite.prototype.emit\n * @param type {string}\n * @param [value] {*}\n * @returns {boolean} True when a listener received the event\n */\n\n function emit(type, value) {\n var that = this;\n var listeners = getListeners(that, type, true);\n if (!listeners) return false;\n var arglen = arguments.length;\n if (arglen === 1) {\n listeners.forEach(zeroarg);\n } else if (arglen === 2) {\n listeners.forEach(onearg);\n } else {\n var args = Array.prototype.slice.call(arguments, 1);\n listeners.forEach(moreargs);\n }\n return !!listeners.length;\n\n function zeroarg(func) {\n func.call(that);\n }\n\n function onearg(func) {\n func.call(that, value);\n }\n\n function moreargs(func) {\n func.apply(that, args);\n }\n }\n\n /**\n * @ignore\n */\n\n function getListeners(that, type, readonly) {\n if (readonly && !that[LISTENERS]) return;\n var listeners = that[LISTENERS] || (that[LISTENERS] = {});\n return listeners[type] || (listeners[type] = []);\n }\n\n// })(EventLite);\n","/* eslint-env browser */\n\nvar Events = require(\"event-lite\");\n\nvar INVALID_TAGS = {\n\ta: true,\n\tnoscript: true,\n\toption: true,\n\tscript: true,\n\tstyle: true,\n\ttextarea: true,\n\tsvg: true,\n\tcanvas: true,\n\tbutton: true,\n\tselect: true,\n\ttemplate: true,\n\tmeter: true,\n\tprogress: true,\n\tmath: true,\n\ttime: true\n};\n\nclass Pos {\n\tconstructor(container, offset, i = 0) {\n\t\tthis.container = container;\n\t\tthis.offset = offset;\n\t\tthis.i = i;\n\t}\n\t\n\tadd(change) {\n\t\tvar cont = this.container,\n\t\t\toffset = this.offset;\n\n\t\tthis.i += change;\n\t\t\n\t\t// If the container is #text.parentNode\n\t\tif (cont.childNodes.length) {\n\t\t\tcont = cont.childNodes[offset];\n\t\t\toffset = 0;\n\t\t}\n\n\t\t// If the container is #text\n\t\twhile (cont) {\n\t\t\tif (cont.nodeType == 3) {\n\t\t\t\tif (!cont.LEN) {\n\t\t\t\t\tcont.LEN = cont.nodeValue.length;\n\t\t\t\t}\n\t\t\t\tif (offset + change <= cont.LEN) {\n\t\t\t\t\tthis.container = cont;\n\t\t\t\t\tthis.offset = offset + change;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tchange = offset + change - cont.LEN;\n\t\t\t\toffset = 0;\n\t\t\t}\n\t\t\tcont = cont.nextSibling;\n\t\t}\n\t}\n\t\n\tmoveTo(offset) {\n\t\tthis.add(offset - this.i);\n\t}\n}\n\nfunction cloneContents(range) {\n\tif (range.startContainer == range.endContainer) {\n\t\treturn document.createTextNode(range.toString());\n\t}\n\treturn range.cloneContents();\n}\n\nvar DEFAULT_OPTIONS = {\n\tmaxRunTime: 100,\n\ttimeout: 10000,\n\tnewTab: true,\n\tnoOpener: true,\n\tembedImage: true,\n recursive: true,\n};\n\nclass Linkifier extends Events {\n\tconstructor(root, options = {}) {\n\t\tsuper();\n\t\tif (!(root instanceof Node)) {\n\t\t\toptions = root;\n\t\t\troot = options.root;\n\t\t}\n\t\tthis.root = root;\n\t\tthis.options = Object.assign({}, DEFAULT_OPTIONS, options);\n\t\tthis.aborted = false;\n\t}\n\tstart() {\n\t\tvar time = Date.now,\n\t\t\tstartTime = time(),\n\t\t\tchunks = this.generateChunks();\n\t\t\t\n\t\tvar next = () => {\n\t\t\tif (this.aborted) {\n\t\t\t\tthis.emit(\"error\", new Error(\"Aborted\"));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvar chunkStart = time(),\n\t\t\t\tnow;\n\t\t\t\t\n\t\t\tdo {\n\t\t\t\tif (chunks.next().done) {\n\t\t\t\t\tthis.emit(\"complete\", time() - startTime);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t} while ((now = time()) - chunkStart < this.options.maxRunTime);\n\t\t\t\n\t\t\tif (now - startTime > this.options.timeout) {\n\t\t\t\tthis.emit(\"error\", new Error(`max execution time exceeded: ${now - startTime}, on ${this.root}`));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tsetTimeout(next);\n\t\t};\n\t\t\t\n\t\tsetTimeout(next);\n\t}\n\tabort() {\n\t\tthis.aborted = true;\n\t}\n\t*generateRanges() {\n\t\tvar {validator, recursive} = this.options;\n\t\tvar filter = {\n\t\t\tacceptNode: function(node) {\n\t\t\t\tif (validator && !validator(node)) {\n\t\t\t\t\treturn NodeFilter.FILTER_REJECT;\n\t\t\t\t}\n\t\t\t\tif (INVALID_TAGS[node.localName]) {\n\t\t\t\t\treturn NodeFilter.FILTER_REJECT;\n\t\t\t\t}\n\t\t\t\tif (node.localName == \"wbr\") {\n\t\t\t\t\treturn NodeFilter.FILTER_ACCEPT;\n\t\t\t\t}\n\t\t\t\tif (node.nodeType == 3) {\n\t\t\t\t\treturn NodeFilter.FILTER_ACCEPT;\n\t\t\t\t}\n\t\t\t\treturn recursive ? NodeFilter.FILTER_SKIP : NodeFilter.FILTER_REJECT;\n\t\t\t}\n\t\t};\n\t\t// Generate linkified ranges.\n\t\tvar walker = document.createTreeWalker(\n\t\t\tthis.root,\n\t\t\tNodeFilter.SHOW_TEXT + NodeFilter.SHOW_ELEMENT,\n\t\t\tfilter\n\t\t), start, end, current, range;\n\n\t\tend = start = walker.nextNode();\n\t\tif (!start) {\n\t\t\treturn;\n\t\t}\n\t\trange = document.createRange();\n\t\trange.setStartBefore(start);\n\t\twhile ((current = walker.nextNode())) {\n\t\t\tif (end.nextSibling == current) {\n\t\t\t\tend = current;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\trange.setEndAfter(end);\n\t\t\tyield range;\n\n\t\t\tend = start = current;\n\t\t\trange.setStartBefore(start);\n\t\t}\n\t\trange.setEndAfter(end);\n\t\tyield range;\n\t}\n\t*generateChunks() {\n\t\tvar {matcher} = this.options;\n\t\tfor (var range of this.generateRanges()) {\n\t\t\tvar frag = null,\n\t\t\t\tpos = null,\n\t\t\t\ttext = range.toString(),\n\t\t\t\ttextRange = null;\n\t\t\tfor (var result of matcher.match(text)) {\n\t\t\t\tif (!frag) {\n\t\t\t\t\tfrag = document.createDocumentFragment();\n\t\t\t\t\tpos = new Pos(range.startContainer, range.startOffset);\n\t\t\t\t\ttextRange = range.cloneRange();\n\t\t\t\t}\n\t\t\t\t// clone text\n\t\t\t\tpos.moveTo(result.start);\n\t\t\t\ttextRange.setEnd(pos.container, pos.offset);\n\t\t\t\tfrag.appendChild(cloneContents(textRange));\n\t\t\t\t\n\t\t\t\t// clone link\n\t\t\t\ttextRange.collapse();\n\t\t\t\tpos.moveTo(result.end);\n\t\t\t\ttextRange.setEnd(pos.container, pos.offset);\n\t\t\t\t\n\t\t\t\tvar content = cloneContents(textRange),\n\t\t\t\t\tlink = this.buildLink(result, content);\n\n\t\t\t\ttextRange.collapse();\n\n\t\t\t\tfrag.appendChild(link);\n\t\t\t\tthis.emit(\"link\", {link, range, result, content});\n\t\t\t}\n\t\t\tif (pos) {\n\t\t\t\tpos.moveTo(text.length);\n\t\t\t\ttextRange.setEnd(pos.container, pos.offset);\n\t\t\t\tfrag.appendChild(cloneContents(textRange));\n\t\t\t\t\n\t\t\t\trange.deleteContents();\n\t\t\t\trange.insertNode(frag);\n\t\t\t}\n\t\t\tyield;\n\t\t}\n\t}\n\tbuildLink(result, content) {\n\t\tvar {newTab, embedImage, noOpener} = this.options;\n\t\tvar link = document.createElement(\"a\");\n\t\tlink.href = result.url;\n\t\tlink.title = \"Linkify Plus Plus\";\n\t\tlink.className = \"linkifyplus\";\n\t\tif (newTab) {\n\t\t\tlink.target = \"_blank\";\n\t\t}\n\t\tif (noOpener) {\n\t\t\tlink.rel = \"noopener\";\n\t\t}\n\t\tvar child;\n\t\tif (embedImage && /^[^?#]+\\.(?:jpg|jpeg|png|apng|gif|svg|webp)(?:$|[?#])/i.test(result.url)) {\n\t\t\tchild = new Image;\n\t\t\tchild.src = result.url;\n\t\t\tchild.alt = result.text;\n\t\t} else {\n\t\t\tchild = content;\n\t\t}\n\t\tlink.appendChild(child);\n\t\treturn link;\n\t}\n}\n\nfunction linkify(...args) {\n\treturn new Promise((resolve, reject) => {\n\t\tvar linkifier = new Linkifier(...args);\n\t\tlinkifier.on(\"error\", reject);\n\t\tlinkifier.on(\"complete\", resolve);\n\t\tfor (var key of Object.keys(linkifier.options)) {\n\t\t\tif (key.startsWith(\"on\")) {\n\t\t\t\tlinkifier.on(key.slice(2), linkifier.options[key]);\n\t\t\t}\n\t\t}\n\t\tlinkifier.start();\n\t});\n}\n\nmodule.exports = {\n\tINVALID_TAGS,\n\tLinkifier,\n\tlinkify\n};\n"],"names":["tlds.chars","tlds.maxLength","tlds.table","Events"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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","x_google_ignoreList":[1]} -------------------------------------------------------------------------------- /dist/linkify-plus-plus-core.min.js: -------------------------------------------------------------------------------- 1 | var linkifyPlusPlusCore=function(e){"use strict";var t="(:\\d+\\b)?",a={aaa:!0,aarp:!0,abb:!0,abbott:!0,abbvie:!0,abc:!0,able:!0,abogado:!0,abudhabi:!0,ac:!0,academy:!0,accountant:!0,accountants:!0,aco:!0,actor:!0,ad:!0,adult:!0,ae:!0,aeg:!0,aero:!0,aetna:!0,af:!0,afl:!0,africa:!0,ag:!0,agency:!0,ai:!0,aig:!0,airbus:!0,airforce:!0,akdn:!0,al:!0,allfinanz:!0,allstate:!0,ally:!0,alsace:!0,alstom:!0,am:!0,amazon:!0,americanexpress:!0,amex:!0,amfam:!0,amica:!0,amsterdam:!0,analytics:!0,android:!0,anz:!0,ao:!0,apartments:!0,app:!0,apple:!0,aq:!0,aquarelle:!0,ar:!0,archi:!0,army:!0,arpa:!0,art:!0,arte:!0,as:!0,asia:!0,associates:!0,at:!0,attorney:!0,au:!0,auction:!0,audi:!0,audio:!0,auspost:!0,auto:!0,autos:!0,aw:!0,aws:!0,ax:!0,axa:!0,az:!0,azure:!0,ba:!0,baby:!0,band:!0,bank:!0,bar:!0,barcelona:!0,barclaycard:!0,barclays:!0,bargains:!0,basketball:!0,bauhaus:!0,bayern:!0,bb:!0,bbc:!0,bbva:!0,bcn:!0,bd:!0,be:!0,beauty:!0,beer:!0,bentley:!0,berlin:!0,best:!0,bet:!0,bf:!0,bg:!0,bh:!0,bi:!0,bible:!0,bid:!0,bike:!0,bing:!0,bingo:!0,bio:!0,biz:!0,bj:!0,black:!0,blackfriday:!0,blog:!0,bloomberg:!0,blue:!0,bm:!0,bmw:!0,bn:!0,bnpparibas:!0,bo:!0,boats:!0,bond:!0,boo:!0,bostik:!0,boston:!0,bot:!0,boutique:!0,box:!0,br:!0,bradesco:!0,bridgestone:!0,broadway:!0,broker:!0,brother:!0,brussels:!0,bs:!0,bt:!0,build:!0,builders:!0,business:!0,buzz:!0,bw:!0,by:!0,bz:!0,bzh:!0,ca:!0,cab:!0,cafe:!0,cam:!0,camera:!0,camp:!0,canon:!0,capetown:!0,capital:!0,car:!0,cards:!0,care:!0,career:!0,careers:!0,cars:!0,casa:!0,case:!0,cash:!0,casino:!0,cat:!0,catering:!0,catholic:!0,cba:!0,cbn:!0,cc:!0,cd:!0,center:!0,ceo:!0,cern:!0,cf:!0,cfa:!0,cfd:!0,cg:!0,ch:!0,chanel:!0,channel:!0,charity:!0,chase:!0,chat:!0,cheap:!0,chintai:!0,christmas:!0,church:!0,ci:!0,cisco:!0,citi:!0,citic:!0,city:!0,ck:!0,cl:!0,claims:!0,cleaning:!0,click:!0,clinic:!0,clothing:!0,cloud:!0,club:!0,clubmed:!0,cm:!0,cn:!0,co:!0,coach:!0,codes:!0,coffee:!0,college:!0,cologne:!0,com:!0,commbank:!0,community:!0,company:!0,compare:!0,computer:!0,condos:!0,construction:!0,consulting:!0,contact:!0,contractors:!0,cooking:!0,cool:!0,coop:!0,corsica:!0,country:!0,coupons:!0,courses:!0,cpa:!0,cr:!0,credit:!0,creditcard:!0,creditunion:!0,cricket:!0,crown:!0,crs:!0,cruises:!0,cu:!0,cuisinella:!0,cv:!0,cw:!0,cx:!0,cy:!0,cymru:!0,cyou:!0,cz:!0,dad:!0,dance:!0,date:!0,dating:!0,day:!0,de:!0,deal:!0,dealer:!0,deals:!0,degree:!0,delivery:!0,dell:!0,deloitte:!0,democrat:!0,dental:!0,dentist:!0,desi:!0,design:!0,dev:!0,dhl:!0,diamonds:!0,diet:!0,digital:!0,direct:!0,directory:!0,discount:!0,discover:!0,diy:!0,dj:!0,dk:!0,dm:!0,do:!0,doctor:!0,dog:!0,domains:!0,download:!0,dubai:!0,dupont:!0,durban:!0,dvag:!0,dz:!0,earth:!0,ec:!0,eco:!0,edeka:!0,edu:!0,education:!0,ee:!0,eg:!0,email:!0,emerck:!0,energy:!0,engineer:!0,engineering:!0,enterprises:!0,equipment:!0,er:!0,ericsson:!0,erni:!0,es:!0,esq:!0,estate:!0,et:!0,eu:!0,eurovision:!0,eus:!0,events:!0,exchange:!0,expert:!0,exposed:!0,express:!0,extraspace:!0,fage:!0,fail:!0,fairwinds:!0,faith:!0,family:!0,fan:!0,fans:!0,farm:!0,fashion:!0,feedback:!0,ferrero:!0,fi:!0,film:!0,finance:!0,financial:!0,firmdale:!0,fish:!0,fishing:!0,fit:!0,fitness:!0,fj:!0,fk:!0,flickr:!0,flights:!0,flir:!0,florist:!0,flowers:!0,fm:!0,fo:!0,foo:!0,food:!0,football:!0,ford:!0,forex:!0,forsale:!0,forum:!0,foundation:!0,fox:!0,fr:!0,fresenius:!0,frl:!0,frogans:!0,fujitsu:!0,fun:!0,fund:!0,furniture:!0,futbol:!0,fyi:!0,ga:!0,gal:!0,gallery:!0,game:!0,games:!0,garden:!0,gay:!0,gd:!0,gdn:!0,ge:!0,gea:!0,gent:!0,genting:!0,gf:!0,gg:!0,gh:!0,gi:!0,gift:!0,gifts:!0,gives:!0,giving:!0,gl:!0,glass:!0,gle:!0,global:!0,globo:!0,gm:!0,gmail:!0,gmbh:!0,gmo:!0,gmx:!0,gn:!0,godaddy:!0,gold:!0,golf:!0,goog:!0,google:!0,gop:!0,gov:!0,gp:!0,gq:!0,gr:!0,grainger:!0,graphics:!0,gratis:!0,green:!0,gripe:!0,group:!0,gs:!0,gt:!0,gu:!0,gucci:!0,guide:!0,guitars:!0,guru:!0,gw:!0,gy:!0,hair:!0,hamburg:!0,haus:!0,health:!0,healthcare:!0,help:!0,helsinki:!0,here:!0,hermes:!0,hiphop:!0,hisamitsu:!0,hitachi:!0,hiv:!0,hk:!0,hm:!0,hn:!0,hockey:!0,holdings:!0,holiday:!0,homes:!0,honda:!0,horse:!0,hospital:!0,host:!0,hosting:!0,hotmail:!0,house:!0,how:!0,hr:!0,hsbc:!0,ht:!0,hu:!0,hyatt:!0,hyundai:!0,ice:!0,icu:!0,id:!0,ie:!0,ieee:!0,ifm:!0,ikano:!0,il:!0,im:!0,imamat:!0,immo:!0,immobilien:!0,in:!0,inc:!0,industries:!0,info:!0,ing:!0,ink:!0,institute:!0,insurance:!0,insure:!0,int:!0,international:!0,investments:!0,io:!0,ipiranga:!0,iq:!0,ir:!0,irish:!0,is:!0,ismaili:!0,ist:!0,istanbul:!0,it:!0,itau:!0,itv:!0,jaguar:!0,java:!0,jcb:!0,je:!0,jetzt:!0,jewelry:!0,jio:!0,jll:!0,jm:!0,jmp:!0,jnj:!0,jo:!0,jobs:!0,joburg:!0,jp:!0,jpmorgan:!0,jprs:!0,juegos:!0,kaufen:!0,ke:!0,kfh:!0,kg:!0,kh:!0,ki:!0,kia:!0,kids:!0,kim:!0,kitchen:!0,kiwi:!0,km:!0,kn:!0,koeln:!0,komatsu:!0,kp:!0,kpmg:!0,kpn:!0,kr:!0,krd:!0,kred:!0,kw:!0,ky:!0,kyoto:!0,kz:!0,la:!0,lamborghini:!0,lancaster:!0,land:!0,landrover:!0,lanxess:!0,lat:!0,latrobe:!0,law:!0,lawyer:!0,lb:!0,lc:!0,lease:!0,leclerc:!0,legal:!0,lexus:!0,lgbt:!0,li:!0,lidl:!0,life:!0,lifestyle:!0,lighting:!0,lilly:!0,limited:!0,limo:!0,lincoln:!0,link:!0,live:!0,living:!0,lk:!0,llc:!0,loan:!0,loans:!0,locker:!0,locus:!0,lol:!0,london:!0,lotto:!0,love:!0,lr:!0,ls:!0,lt:!0,ltd:!0,ltda:!0,lu:!0,lundbeck:!0,luxe:!0,luxury:!0,lv:!0,ly:!0,ma:!0,madrid:!0,maif:!0,maison:!0,makeup:!0,man:!0,management:!0,mango:!0,market:!0,marketing:!0,markets:!0,marriott:!0,mattel:!0,mba:!0,mc:!0,md:!0,me:!0,med:!0,media:!0,meet:!0,melbourne:!0,meme:!0,memorial:!0,men:!0,menu:!0,mg:!0,mh:!0,miami:!0,microsoft:!0,mil:!0,mini:!0,mit:!0,mk:!0,ml:!0,mlb:!0,mm:!0,mma:!0,mn:!0,mo:!0,mobi:!0,moda:!0,moe:!0,moi:!0,mom:!0,monash:!0,money:!0,monster:!0,mortgage:!0,moscow:!0,motorcycles:!0,mov:!0,movie:!0,mp:!0,mq:!0,mr:!0,ms:!0,mt:!0,mtn:!0,mtr:!0,mu:!0,museum:!0,music:!0,mv:!0,mw:!0,mx:!0,my:!0,mz:!0,na:!0,nab:!0,nagoya:!0,name:!0,navy:!0,nc:!0,ne:!0,nec:!0,net:!0,netbank:!0,network:!0,neustar:!0,new:!0,news:!0,next:!0,nexus:!0,nf:!0,ng:!0,ngo:!0,nhk:!0,ni:!0,nico:!0,nike:!0,ninja:!0,nissan:!0,nl:!0,no:!0,nokia:!0,now:!0,nowruz:!0,np:!0,nr:!0,nra:!0,nrw:!0,ntt:!0,nu:!0,nyc:!0,nz:!0,observer:!0,office:!0,okinawa:!0,om:!0,omega:!0,one:!0,ong:!0,onl:!0,online:!0,ooo:!0,oracle:!0,orange:!0,org:!0,organic:!0,osaka:!0,otsuka:!0,ovh:!0,pa:!0,page:!0,panasonic:!0,paris:!0,partners:!0,parts:!0,party:!0,pe:!0,pet:!0,pf:!0,pfizer:!0,pg:!0,ph:!0,pharmacy:!0,phd:!0,philips:!0,photo:!0,photography:!0,photos:!0,physio:!0,pics:!0,pictet:!0,pictures:!0,ping:!0,pink:!0,pioneer:!0,pizza:!0,pk:!0,pl:!0,place:!0,play:!0,plumbing:!0,plus:!0,pm:!0,pn:!0,pohl:!0,poker:!0,politie:!0,porn:!0,post:!0,pr:!0,praxi:!0,press:!0,prime:!0,pro:!0,productions:!0,prof:!0,promo:!0,properties:!0,property:!0,protection:!0,pru:!0,prudential:!0,ps:!0,pt:!0,pub:!0,pw:!0,pwc:!0,py:!0,qa:!0,qpon:!0,quebec:!0,quest:!0,racing:!0,radio:!0,re:!0,realestate:!0,realtor:!0,realty:!0,recipes:!0,red:!0,redstone:!0,rehab:!0,reise:!0,reisen:!0,reit:!0,ren:!0,rent:!0,rentals:!0,repair:!0,report:!0,republican:!0,rest:!0,restaurant:!0,review:!0,reviews:!0,rexroth:!0,rich:!0,ricoh:!0,rio:!0,rip:!0,ro:!0,rocks:!0,rodeo:!0,rogers:!0,rs:!0,rsvp:!0,ru:!0,rugby:!0,ruhr:!0,run:!0,rw:!0,ryukyu:!0,sa:!0,saarland:!0,sale:!0,salon:!0,samsung:!0,sandvik:!0,sandvikcoromant:!0,sanofi:!0,sap:!0,sarl:!0,saxo:!0,sb:!0,sbi:!0,sbs:!0,sc:!0,scb:!0,schaeffler:!0,schmidt:!0,school:!0,schule:!0,schwarz:!0,science:!0,scot:!0,sd:!0,se:!0,seat:!0,security:!0,select:!0,sener:!0,services:!0,seven:!0,sew:!0,sex:!0,sexy:!0,sfr:!0,sg:!0,sh:!0,sharp:!0,shell:!0,shiksha:!0,shoes:!0,shop:!0,shopping:!0,show:!0,si:!0,singles:!0,site:!0,sk:!0,ski:!0,skin:!0,sky:!0,skype:!0,sl:!0,sm:!0,smart:!0,sn:!0,sncf:!0,so:!0,soccer:!0,social:!0,softbank:!0,software:!0,sohu:!0,solar:!0,solutions:!0,sony:!0,soy:!0,spa:!0,space:!0,sport:!0,sr:!0,srl:!0,ss:!0,st:!0,stada:!0,statebank:!0,statefarm:!0,stc:!0,stockholm:!0,storage:!0,store:!0,stream:!0,studio:!0,study:!0,style:!0,su:!0,sucks:!0,supplies:!0,supply:!0,support:!0,surf:!0,surgery:!0,suzuki:!0,sv:!0,swatch:!0,swiss:!0,sx:!0,sy:!0,sydney:!0,systems:!0,sz:!0,taipei:!0,target:!0,tatamotors:!0,tatar:!0,tattoo:!0,tax:!0,taxi:!0,tc:!0,td:!0,team:!0,tech:!0,technology:!0,tel:!0,temasek:!0,tennis:!0,teva:!0,tf:!0,tg:!0,th:!0,theater:!0,theatre:!0,tickets:!0,tienda:!0,tips:!0,tires:!0,tirol:!0,tj:!0,tk:!0,tl:!0,tm:!0,tn:!0,to:!0,today:!0,tokyo:!0,tools:!0,top:!0,toray:!0,toshiba:!0,total:!0,tours:!0,town:!0,toyota:!0,toys:!0,tr:!0,trade:!0,trading:!0,training:!0,travel:!0,travelers:!0,trust:!0,tt:!0,tube:!0,tui:!0,tv:!0,tvs:!0,tw:!0,tz:!0,ua:!0,ug:!0,uk:!0,unicom:!0,university:!0,uno:!0,uol:!0,us:!0,uy:!0,uz:!0,va:!0,vacations:!0,vana:!0,vanguard:!0,vc:!0,ve:!0,vegas:!0,ventures:!0,versicherung:!0,vet:!0,vg:!0,vi:!0,viajes:!0,video:!0,vig:!0,villas:!0,vin:!0,vip:!0,vision:!0,vivo:!0,vlaanderen:!0,vn:!0,vodka:!0,vote:!0,voting:!0,voto:!0,voyage:!0,vu:!0,wales:!0,walter:!0,wang:!0,watch:!0,watches:!0,webcam:!0,weber:!0,website:!0,wed:!0,wedding:!0,weir:!0,wf:!0,whoswho:!0,wien:!0,wiki:!0,williamhill:!0,win:!0,windows:!0,wine:!0,wme:!0,woodside:!0,work:!0,works:!0,world:!0,ws:!0,wtf:!0,xbox:!0,xin:!0,"xn--1ck2e1b":!0,"xn--1qqw23a":!0,"xn--2scrj9c":!0,"xn--3bst00m":!0,"xn--3ds443g":!0,"xn--3e0b707e":!0,"xn--3hcrj9c":!0,"xn--45br5cyl":!0,"xn--45brj9c":!0,"xn--45q11c":!0,"xn--4dbrk0ce":!0,"xn--4gbrim":!0,"xn--54b7fta0cc":!0,"xn--55qx5d":!0,"xn--5tzm5g":!0,"xn--6frz82g":!0,"xn--6qq986b3xl":!0,"xn--80adxhks":!0,"xn--80ao21a":!0,"xn--80asehdb":!0,"xn--80aswg":!0,"xn--8y0a063a":!0,"xn--90a3ac":!0,"xn--90ae":!0,"xn--90ais":!0,"xn--9dbq2a":!0,"xn--bck1b9a5dre4c":!0,"xn--c1avg":!0,"xn--cck2b3b":!0,"xn--clchc0ea0b2g2a9gcd":!0,"xn--czr694b":!0,"xn--czrs0t":!0,"xn--czru2d":!0,"xn--d1acj3b":!0,"xn--d1alf":!0,"xn--e1a4c":!0,"xn--fct429k":!0,"xn--fiq228c5hs":!0,"xn--fiq64b":!0,"xn--fiqs8s":!0,"xn--fiqz9s":!0,"xn--fjq720a":!0,"xn--fpcrj9c3d":!0,"xn--fzc2c9e2c":!0,"xn--g2xx48c":!0,"xn--gckr3f0f":!0,"xn--gecrj9c":!0,"xn--h2breg3eve":!0,"xn--h2brj9c":!0,"xn--h2brj9c8c":!0,"xn--hxt814e":!0,"xn--i1b6b1a6a2e":!0,"xn--imr513n":!0,"xn--io0a7i":!0,"xn--j1amh":!0,"xn--j6w193g":!0,"xn--jvr189m":!0,"xn--kcrx77d1x4a":!0,"xn--kprw13d":!0,"xn--kpry57d":!0,"xn--kput3i":!0,"xn--l1acc":!0,"xn--lgbbat1ad8j":!0,"xn--mgb9awbf":!0,"xn--mgba3a4f16a":!0,"xn--mgbaam7a8h":!0,"xn--mgbab2bd":!0,"xn--mgbah1a3hjkrd":!0,"xn--mgbai9azgqp6j":!0,"xn--mgbayh7gpa":!0,"xn--mgbbh1a":!0,"xn--mgbc0a9azcg":!0,"xn--mgbca7dzdo":!0,"xn--mgbcpq6gpa1a":!0,"xn--mgberp4a5d4ar":!0,"xn--mgbgu82a":!0,"xn--mgbpl2fh":!0,"xn--mgbtx2b":!0,"xn--mix891f":!0,"xn--mk1bu44c":!0,"xn--ngbc5azd":!0,"xn--ngbe9e0a":!0,"xn--node":!0,"xn--nqv7f":!0,"xn--nyqy26a":!0,"xn--o3cw4h":!0,"xn--ogbpf8fl":!0,"xn--otu796d":!0,"xn--p1acf":!0,"xn--p1ai":!0,"xn--pgbs0dh":!0,"xn--q7ce6a":!0,"xn--q9jyb4c":!0,"xn--qxa6a":!0,"xn--qxam":!0,"xn--rhqv96g":!0,"xn--rovu88b":!0,"xn--rvc1e0am3e":!0,"xn--s9brj9c":!0,"xn--ses554g":!0,"xn--t60b56a":!0,"xn--tckwe":!0,"xn--unup4y":!0,"xn--vermgensberatung-pwb":!0,"xn--vhquv":!0,"xn--vuq861b":!0,"xn--wgbh1c":!0,"xn--wgbl6a":!0,"xn--xhq521b":!0,"xn--xkc2al3hye2a":!0,"xn--xkc2dl3a5ee0h":!0,"xn--y9a3aq":!0,"xn--yfro4i67o":!0,"xn--ygbi2ammx":!0,"xn--zfr164b":!0,xxx:!0,xyz:!0,yachts:!0,yahoo:!0,yandex:!0,ye:!0,yodobashi:!0,yoga:!0,yokohama:!0,youtube:!0,yt:!0,za:!0,zappos:!0,zara:!0,zip:!0,zm:!0,zone:!0,zuerich:!0,zw:!0,"セール":!0,"佛山":!0,"ಭಾರತ":!0,"集团":!0,"在线":!0,"한국":!0,"ଭାରତ":!0,"ভাৰত":!0,"ভারত":!0,"八卦":!0,"ישראל":!0,"موقع":!0,"বাংলা":!0,"公司":!0,"网站":!0,"移动":!0,"我爱你":!0,"москва":!0,"қаз":!0,"онлайн":!0,"сайт":!0,"联通":!0,"срб":!0,"бг":!0,"бел":!0,"קום":!0,"ファッション":!0,"орг":!0,"ストア":!0,"சிங்கப்பூர்":!0,"商标":!0,"商店":!0,"商城":!0,"дети":!0,"мкд":!0,"ею":!0,"家電":!0,"中文网":!0,"中信":!0,"中国":!0,"中國":!0,"娱乐":!0,"భారత్":!0,"ලංකා":!0,"购物":!0,"クラウド":!0,"ભારત":!0,"भारतम्":!0,"भारत":!0,"भारोत":!0,"网店":!0,"संगठन":!0,"餐厅":!0,"网络":!0,"укр":!0,"香港":!0,"食品":!0,"飞利浦":!0,"台湾":!0,"台灣":!0,"手机":!0,"мон":!0,"الجزائر":!0,"عمان":!0,"ایران":!0,"امارات":!0,"بازار":!0,"موريتانيا":!0,"پاکستان":!0,"الاردن":!0,"بارت":!0,"المغرب":!0,"ابوظبي":!0,"البحرين":!0,"السعودية":!0,"ڀارت":!0,"سودان":!0,"عراق":!0,"澳門":!0,"닷컴":!0,"شبكة":!0,"بيتك":!0,"გე":!0,"机构":!0,"健康":!0,"ไทย":!0,"سورية":!0,"招聘":!0,"рус":!0,"рф":!0,"تونس":!0,"ລາວ":!0,"みんな":!0,"ευ":!0,"ελ":!0,"世界":!0,"書籍":!0,"ഭാരതം":!0,"ਭਾਰਤ":!0,"网址":!0,"닷넷":!0,"コム":!0,"游戏":!0,"vermögensberatung":!0,"企业":!0,"信息":!0,"مصر":!0,"قطر":!0,"广东":!0,"இலங்கை":!0,"இந்தியா":!0,"հայ":!0,"新加坡":!0,"فلسطين":!0,"政务":!0,onion:!0};function n(e){return e.replace(/[[\]\\^-]/g,"\\$&")}function i(e,t,a){var n=e.path.replace(t,a);n!=e.path&&(e.end-=e.path.length-n.length,e.suffix=e.path.slice(n.length)+e.suffix,e.path=n)}function o(e,t){var a,n=0,i=e.path,o=0;if(i.endsWith(t)){for(;(o=i.indexOf(t,o))>=0;)a=n%2?null:o,o++,n++;a&&(e.end-=i.length-a,e.path=i.slice(0,a),e.suffix=i.slice(a)+e.suffix)}}function r(e,t,a){for(var n,i,o=e.path,r=new RegExp("[\\"+t+"\\"+a+"]","g"),s=0;n=r.exec(o);){if(s%2==0){if(i=n.index,n[0]==a)break}else if(n[0]==t)break;s++}(n||s%2!=0)&&(e.end-=e.path.length-i,e.path=o.slice(0,i),e.suffix=o.slice(i)+e.suffix)}function s(e){var t,a;if(!(t=e.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/)))return!1;for(a=1;a255||t[a].length>1&&"0"==t[a][0])return!1;return!0}function c(e){var t=e.match(/\.([^.]+)$/);if(!t)return!1;var n=t[1].toLowerCase();return a.hasOwnProperty(n)}function l(e){let t=0;const a=e.split(".");for(const e of a){if(!e||e.startsWith("-")||e.endsWith("-"))return{index:t,value:e};t+=e.length+1}} 2 | /** 3 | * event-lite.js - Light-weight EventEmitter (less than 1KB when gzipped) 4 | * 5 | * @copyright Yusuke Kawasaki 6 | * @license MIT 7 | * @constructor 8 | * @see https://github.com/kawanet/event-lite 9 | * @see http://kawanet.github.io/event-lite/EventLite.html 10 | * @example 11 | * var EventLite = require("event-lite"); 12 | * 13 | * function MyClass() {...} // your class 14 | * 15 | * EventLite.mixin(MyClass.prototype); // import event methods 16 | * 17 | * var obj = new MyClass(); 18 | * obj.on("foo", function() {...}); // add event listener 19 | * obj.once("bar", function() {...}); // add one-time event listener 20 | * obj.emit("foo"); // dispatch event 21 | * obj.emit("bar"); // dispatch another event 22 | * obj.off("foo"); // remove event listener 23 | */function u(){if(!(this instanceof u))return new u}var d="listeners",m={on:function(e,t){return p(this,e).push(t),this},once:function(e,t){var a=this;return n.originalListener=t,p(a,e).push(n),a;function n(){g.call(a,e,n),t.apply(this,arguments)}},off:g,emit:function(e,t){var a=this,n=p(a,e,!0);if(!n)return!1;var i=arguments.length;if(1===i)n.forEach((function(e){e.call(a)}));else if(2===i)n.forEach((function(e){e.call(a,t)}));else{var o=Array.prototype.slice.call(arguments,1);n.forEach((function(e){e.apply(a,o)}))}return!!n.length}};function h(e){for(var t in m)e[t]=m[t];return e}function g(e,t){var a,n=this;if(arguments.length){if(t){if(a=p(n,e,!0)){if(!(a=a.filter((function(e){return e!==t&&e.originalListener!==t}))).length)return g.call(n,e);n[d][e]=a}}else if((a=n[d])&&(delete a[e],!Object.keys(a).length))return g.call(n)}else delete n[d];return n}function p(e,t,a){if(!a||e[d]){var n=e[d]||(e[d]={});return n[t]||(n[t]=[])}}h(u.prototype),u.mixin=h;var f={a:!0,noscript:!0,option:!0,script:!0,style:!0,textarea:!0,svg:!0,canvas:!0,button:!0,select:!0,template:!0,meter:!0,progress:!0,math:!0,time:!0};class b{constructor(e,t,a=0){this.container=e,this.offset=t,this.i=a}add(e){var t=this.container,a=this.offset;for(this.i+=e,t.childNodes.length&&(t=t.childNodes[a],a=0);t;){if(3==t.nodeType){if(t.LEN||(t.LEN=t.nodeValue.length),a+e<=t.LEN)return this.container=t,void(this.offset=a+e);e=a+e-t.LEN,a=0}t=t.nextSibling}}moveTo(e){this.add(e-this.i)}}function x(e){return e.startContainer==e.endContainer?document.createTextNode(e.toString()):e.cloneContents()}var v={maxRunTime:100,timeout:1e4,newTab:!0,noOpener:!0,embedImage:!0,recursive:!0};class y extends u{constructor(e,t={}){super(),e instanceof Node||(e=(t=e).root),this.root=e,this.options=Object.assign({},v,t),this.aborted=!1}start(){var e=Date.now,t=e(),a=this.generateChunks(),n=()=>{if(this.aborted)this.emit("error",new Error("Aborted"));else{var i,o=e();do{if(a.next().done)return void this.emit("complete",e()-t)}while((i=e())-othis.options.timeout?this.emit("error",new Error(`max execution time exceeded: ${i-t}, on ${this.root}`)):setTimeout(n)}};setTimeout(n)}abort(){this.aborted=!0}*generateRanges(){var e,t,a,n,{validator:i,recursive:o}=this.options,r={acceptNode:function(e){return i&&!i(e)||f[e.localName]?NodeFilter.FILTER_REJECT:"wbr"==e.localName||3==e.nodeType?NodeFilter.FILTER_ACCEPT:o?NodeFilter.FILTER_SKIP:NodeFilter.FILTER_REJECT}},s=document.createTreeWalker(this.root,NodeFilter.SHOW_TEXT+NodeFilter.SHOW_ELEMENT,r);if(t=e=s.nextNode(),e){for((n=document.createRange()).setStartBefore(e);a=s.nextNode();)t.nextSibling!=a?(n.setEndAfter(t),yield n,t=e=a,n.setStartBefore(e)):t=a;n.setEndAfter(t),yield n}}*generateChunks(){var{matcher:e}=this.options;for(var t of this.generateRanges()){var a=null,n=null,i=t.toString(),o=null;for(var r of e.match(i)){a||(a=document.createDocumentFragment(),n=new b(t.startContainer,t.startOffset),o=t.cloneRange()),n.moveTo(r.start),o.setEnd(n.container,n.offset),a.appendChild(x(o)),o.collapse(),n.moveTo(r.end),o.setEnd(n.container,n.offset);var s=x(o),c=this.buildLink(r,s);o.collapse(),a.appendChild(c),this.emit("link",{link:c,range:t,result:r,content:s})}n&&(n.moveTo(i.length),o.setEnd(n.container,n.offset),a.appendChild(x(o)),t.deleteContents(),t.insertNode(a)),yield}}buildLink(e,t){var a,{newTab:n,embedImage:i,noOpener:o}=this.options,r=document.createElement("a");return r.href=e.url,r.title="Linkify Plus Plus",r.className="linkifyplus",n&&(r.target="_blank"),o&&(r.rel="noopener"),i&&/^[^?#]+\.(?:jpg|jpeg|png|apng|gif|svg|webp)(?:$|[?#])/i.test(e.url)?((a=new Image).src=e.url,a.alt=e.text):a=t,r.appendChild(a),r}}return e.INVALID_TAGS=f,e.Linkifier=y,e.UrlMatcher=class{constructor(e={}){this.options=e,this.regex=function({unicode:e=!1,customRules:a=[],standalone:i=!1,boundaryLeft:o,boundaryRight:r}){var s,c,l,u="([a-z][-a-z*]+://)?(?:([\\w:.+-]+)@)?";return u+=e?"([a-z0-9-.\\u00A0-\\uFFFF]+\\.[a-z0-9-セール佛山ಭಾರತ集团在线한국ଭାରତভাৰতর八卦ישראלموقعবংল公司网站移动我爱你москвақзнлйт联通рбгеקוםファッションストアசிங்கபூர商标店城дию家電中文信国國娱乐భారత్ලංකා购物クラウドભારતभारतम्ोसंगठन餐厅络у香港食品飞利浦台湾灣手机الجزئرنیتبيپکسدغظحةڀ澳門닷컴شكგე构健康ไทย招聘фລາວみんなευλ世界書籍ഭാരതംਭਾਰਤ址넷コム游戏ö企业息صط广东இலைநதயாհայ新加坡ف政务]{1,24})"+t+"([/?#]\\S*)?":"([a-z0-9-.]+\\.[a-z0-9-]{1,24})"+t+"([/?#][\\w-.~!$&*+;=:@%/?#(),'\\[\\]]*)?",u=a.length?"(?:("+a.join("|")+")|"+u+")":"()"+u,i?(s=o?"((?:^|\\s)["+n(o)+"]*?)":"(^|\\s)",c=r?"(["+n(r)+"]*(?:$|\\s))":"($|\\s)",l="[^\\s"+n(r)+"]"):(s="(^|\\b|_)",c="()"),u=s+u+c,{url:new RegExp(u,"igm"),invalidSuffix:l&&new RegExp(l),mustache:/\{\{[\s\S]+?\}\}/g}}(e)}*match(e){var t,a,n,u,d,{fuzzyIp:m=!0,ignoreMustache:h=!1,mail:g=!0}=this.options,{url:p,invalidSuffix:f,mustache:b}=this.regex;for(b.lastIndex=0,p.lastIndex=0,h&&(n=b.exec(e))&&(u={start:n.index,end:b.lastIndex});d=p.exec(e);){const h={start:0,end:0,text:"",url:"",prefix:d[1],custom:d[2],protocol:d[3],auth:d[4]||"",domain:d[5],port:d[6]||"",path:d[7]||"",suffix:d[8]};if(h.custom?(h.start=d.index,h.end=p.lastIndex,h.text=h.url=d[0]):(h.start=d.index+h.prefix.length,h.end=p.lastIndex-h.suffix.length),u&&u.end<=h.start&&((n=b.exec(e))?(u.start=n.index,u.end=b.lastIndex):u=null),!(u&&h.start=u.start)){if(!h.custom){if(h.path&&(i(h,/\[\/?(b|i|u|url|img|quote|code|size|color)\].*/i,""),r(h,"(",")"),r(h,"[","]"),r(h,"{","}"),o(h,"'"),o(h,'"'),i(h,/(^|[^-_])[.,?]+$/,"$1")),f&&f.test(h.suffix)){/\s$/.test(h.suffix)&&p.lastIndex--;continue}if(!m&&s(h.domain)&&!h.protocol&&!h.auth&&!h.path)continue;if(!h.protocol&&h.auth){var x=h.auth.match(/^mailto:(.+)/);x&&(h.protocol="mailto:",h.auth=x[1])}var v;if(h.protocol&&h.protocol.match(/^(hxxp|h\*\*p|ttp)/)&&(h.protocol="http://"),h.protocol||((v=h.domain.match(/^(ftp|irc)/))?h.protocol=v[0]+"://":h.domain.match(/^(www|web)/)?h.protocol="http://":h.auth&&h.auth.indexOf(":")<0&&!h.path?h.protocol="mailto:":h.protocol="http://"),!g&&"mailto:"===h.protocol)continue;if(!s(h.domain)){if(/^(http|https|mailto)/.test(h.protocol)&&!c(h.domain))continue;const e=l(h.domain);if(e){p.lastIndex=d.index+e.index+1;continue}}h.url=h.protocol+(h.auth&&h.auth+"@")+h.domain+h.port+h.path,h.text=e.slice(h.start,h.end)}a=b.lastIndex,t=p.lastIndex,yield h,p.lastIndex=t,b.lastIndex=a}}}},e.linkify=function(...e){return new Promise(((t,a)=>{var n=new y(...e);for(var i of(n.on("error",a),n.on("complete",t),Object.keys(n.options)))i.startsWith("on")&&n.on(i.slice(2),n.options[i]);n.start()}))},e}({}); 24 | //# sourceMappingURL=linkify-plus-plus-core.min.js.map 25 | -------------------------------------------------------------------------------- /dist/linkify-plus-plus-core.min.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"linkify-plus-plus-core.min.js","sources":["../lib/url-matcher.js","../node_modules/event-lite/event-lite.mjs","../lib/linkifier.js"],"sourcesContent":["var tlds = require(\"./tlds.json\"),\n\tRE = {\n\t\tPROTOCOL: \"([a-z][-a-z*]+://)?\",\n\t\tUSER: \"(?:([\\\\w:.+-]+)@)?\",\n\t\tDOMAIN_UNI: `([a-z0-9-.\\\\u00A0-\\\\uFFFF]+\\\\.[a-z0-9-${tlds.chars}]{1,${tlds.maxLength}})`,\n\t\tDOMAIN: `([a-z0-9-.]+\\\\.[a-z0-9-]{1,${tlds.maxLength}})`,\n\t\tPORT: \"(:\\\\d+\\\\b)?\",\n\t\tPATH_UNI: \"([/?#]\\\\S*)?\",\n\t\tPATH: \"([/?#][\\\\w-.~!$&*+;=:@%/?#(),'\\\\[\\\\]]*)?\"\n\t},\n\tTLD_TABLE = tlds.table;\n\nfunction regexEscape(text) {\n\treturn text.replace(/[[\\]\\\\^-]/g, \"\\\\$&\");\n}\n\nfunction buildRegex({\n\tunicode = false, customRules = [], standalone = false,\n\tboundaryLeft, boundaryRight\n}) {\n\tvar pattern = RE.PROTOCOL + RE.USER;\n\t\n\tif (unicode) {\n\t\tpattern += RE.DOMAIN_UNI + RE.PORT + RE.PATH_UNI;\n\t} else {\n\t\tpattern += RE.DOMAIN + RE.PORT + RE.PATH;\n\t}\n\t\n\tif (customRules.length) {\n\t\tpattern = \"(?:(\" + customRules.join(\"|\") + \")|\" + pattern + \")\";\n\t} else {\n\t\tpattern = \"()\" + pattern;\n\t}\n\t\n\tvar prefix, suffix, invalidSuffix;\n\tif (standalone) {\n\t\tif (boundaryLeft) {\n\t\t\tprefix = \"((?:^|\\\\s)[\" + regexEscape(boundaryLeft) + \"]*?)\";\n\t\t} else {\n\t\t\tprefix = \"(^|\\\\s)\";\n\t\t}\n\t\tif (boundaryRight) {\n\t\t\tsuffix = \"([\" + regexEscape(boundaryRight) + \"]*(?:$|\\\\s))\";\n\t\t} else {\n\t\t\tsuffix = \"($|\\\\s)\";\n\t\t}\n\t\tinvalidSuffix = \"[^\\\\s\" + regexEscape(boundaryRight) + \"]\";\n\t} else {\n\t\tprefix = \"(^|\\\\b|_)\";\n\t\tsuffix = \"()\";\n\t}\n\t\n\tpattern = prefix + pattern + suffix;\n\t\n\treturn {\n\t\turl: new RegExp(pattern, \"igm\"),\n\t\tinvalidSuffix: invalidSuffix && new RegExp(invalidSuffix),\n\t\tmustache: /\\{\\{[\\s\\S]+?\\}\\}/g\n\t};\n}\n\nfunction pathStrip(m, re, repl) {\n\tvar s = m.path.replace(re, repl);\n\n\tif (s == m.path) return;\n\t\n\tm.end -= m.path.length - s.length;\n\tm.suffix = m.path.slice(s.length) + m.suffix;\n\tm.path = s;\n}\n\nfunction pathStripQuote(m, c) {\n\tvar i = 0, s = m.path, end, pos = 0;\n\t\n\tif (!s.endsWith(c)) return;\n\t\n\twhile ((pos = s.indexOf(c, pos)) >= 0) {\n\t\tif (i % 2) {\n\t\t\tend = null;\n\t\t} else {\n\t\t\tend = pos;\n\t\t}\n\t\tpos++;\n\t\ti++;\n\t}\n\t\n\tif (!end) return;\n\t\n\tm.end -= s.length - end;\n\tm.path = s.slice(0, end);\n\tm.suffix = s.slice(end) + m.suffix;\n}\n\nfunction pathStripBrace(m, left, right) {\n\tvar str = m.path,\n\t\tre = new RegExp(\"[\\\\\" + left + \"\\\\\" + right + \"]\", \"g\"),\n\t\tmatch, count = 0, end;\n\n\t// Match loop\n\twhile ((match = re.exec(str))) {\n\t\tif (count % 2 == 0) {\n\t\t\tend = match.index;\n\t\t\tif (match[0] == right) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t} else {\n\t\t\tif (match[0] == left) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tcount++;\n\t}\n\n\tif (!match && count % 2 == 0) {\n\t\treturn;\n\t}\n\t\n\tm.end -= m.path.length - end;\n\tm.path = str.slice(0, end);\n\tm.suffix = str.slice(end) + m.suffix;\n}\n\nfunction isIP(s) {\n\tvar m, i;\n\tif (!(m = s.match(/^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$/))) {\n\t\treturn false;\n\t}\n\tfor (i = 1; i < m.length; i++) {\n\t\tif (+m[i] > 255 || (m[i].length > 1 && m[i][0] == \"0\")) {\n\t\t\treturn false;\n\t\t}\n\t}\n\treturn true;\n}\n\nfunction inTLDS(domain) {\n\tvar match = domain.match(/\\.([^.]+)$/);\n\tif (!match) {\n\t\treturn false;\n\t}\n\tvar key = match[1].toLowerCase();\n // eslint-disable-next-line no-prototype-builtins\n\treturn TLD_TABLE.hasOwnProperty(key);\n}\n\nclass UrlMatcher {\n\tconstructor(options = {}) {\n\t\tthis.options = options;\n\t\tthis.regex = buildRegex(options);\n\t}\n\t\n\t*match(text) {\n\t\tvar {\n\t\t\t\tfuzzyIp = true,\n\t\t\t\tignoreMustache = false,\n mail = true\n\t\t\t} = this.options,\n\t\t\t{\n\t\t\t\turl,\n\t\t\t\tinvalidSuffix,\n\t\t\t\tmustache\n\t\t\t} = this.regex,\n\t\t\turlLastIndex, mustacheLastIndex;\n\t\t\t\n\t\tmustache.lastIndex = 0;\n\t\turl.lastIndex = 0;\n\t\t\n\t\tvar mustacheMatch, mustacheRange;\n\t\tif (ignoreMustache) {\n\t\t\tmustacheMatch = mustache.exec(text);\n\t\t\tif (mustacheMatch) {\n\t\t\t\tmustacheRange = {\n\t\t\t\t\tstart: mustacheMatch.index,\n\t\t\t\t\tend: mustache.lastIndex\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\t\n\t\tvar urlMatch;\n\t\twhile ((urlMatch = url.exec(text))) {\n const result = {\n start: 0,\n end: 0,\n \n text: \"\",\n url: \"\",\n \n prefix: urlMatch[1],\n custom: urlMatch[2],\n protocol: urlMatch[3],\n auth: urlMatch[4] || \"\",\n domain: urlMatch[5],\n port: urlMatch[6] || \"\",\n path: urlMatch[7] || \"\",\n suffix: urlMatch[8]\n };\n \n if (result.custom) {\n result.start = urlMatch.index;\n result.end = url.lastIndex;\n result.text = result.url = urlMatch[0];\n\t\t\t} else {\n \n result.start = urlMatch.index + result.prefix.length;\n result.end = url.lastIndex - result.suffix.length;\n\t\t\t}\n\t\t\t\n\t\t\tif (mustacheRange && mustacheRange.end <= result.start) {\n\t\t\t\tmustacheMatch = mustache.exec(text);\n\t\t\t\tif (mustacheMatch) {\n\t\t\t\t\tmustacheRange.start = mustacheMatch.index;\n\t\t\t\t\tmustacheRange.end = mustache.lastIndex;\n\t\t\t\t} else {\n\t\t\t\t\tmustacheRange = null;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// ignore urls inside mustache pair\n\t\t\tif (mustacheRange && result.start < mustacheRange.end && result.end >= mustacheRange.start) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t\n\t\t\tif (!result.custom) {\n\t\t\t\t// adjust path and suffix\n\t\t\t\tif (result.path) {\n\t\t\t\t\t// Strip BBCode\n\t\t\t\t\tpathStrip(result, /\\[\\/?(b|i|u|url|img|quote|code|size|color)\\].*/i, \"\");\n\t\t\t\t\t\n\t\t\t\t\t// Strip braces\n\t\t\t\t\tpathStripBrace(result, \"(\", \")\");\n\t\t\t\t\tpathStripBrace(result, \"[\", \"]\");\n\t\t\t\t\tpathStripBrace(result, \"{\", \"}\");\n\t\t\t\t\t\n\t\t\t\t\t// Strip quotes\n\t\t\t\t\tpathStripQuote(result, \"'\");\n\t\t\t\t\tpathStripQuote(result, '\"');\n\t\t\t\t\t\n\t\t\t\t\t// Remove trailing \".,?\"\n\t\t\t\t\tpathStrip(result, /(^|[^-_])[.,?]+$/, \"$1\");\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// check suffix\n\t\t\t\tif (invalidSuffix && invalidSuffix.test(result.suffix)) {\n\t\t\t\t\tif (/\\s$/.test(result.suffix)) {\n\t\t\t\t\t\turl.lastIndex--;\n\t\t\t\t\t}\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n \n // ignore fuzzy ip\n\t\t\t\tif (!fuzzyIp && isIP(result.domain) &&\n !result.protocol && !result.auth && !result.path) {\n continue;\n }\n \n\t\t\t\t// mailto protocol\n\t\t\t\tif (!result.protocol && result.auth) {\n\t\t\t\t\tvar matchMail = result.auth.match(/^mailto:(.+)/);\n\t\t\t\t\tif (matchMail) {\n\t\t\t\t\t\tresult.protocol = \"mailto:\";\n\t\t\t\t\t\tresult.auth = matchMail[1];\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// http alias\n\t\t\t\tif (result.protocol && result.protocol.match(/^(hxxp|h\\*\\*p|ttp)/)) {\n\t\t\t\t\tresult.protocol = \"http://\";\n\t\t\t\t}\n\n\t\t\t\t// guess protocol\n\t\t\t\tif (!result.protocol) {\n\t\t\t\t\tvar domainMatch;\n\t\t\t\t\tif ((domainMatch = result.domain.match(/^(ftp|irc)/))) {\n\t\t\t\t\t\tresult.protocol = domainMatch[0] + \"://\";\n\t\t\t\t\t} else if (result.domain.match(/^(www|web)/)) {\n\t\t\t\t\t\tresult.protocol = \"http://\";\n\t\t\t\t\t} else if (result.auth && result.auth.indexOf(\":\") < 0 && !result.path) {\n\t\t\t\t\t\tresult.protocol = \"mailto:\";\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresult.protocol = \"http://\";\n\t\t\t\t\t}\n\t\t\t\t}\n \n // ignore mail\n if (!mail && result.protocol === \"mailto:\") {\n continue;\n }\n \n\t\t\t\t// verify domain\n if (!isIP(result.domain)) {\n if (/^(http|https|mailto)/.test(result.protocol) && !inTLDS(result.domain)) {\n continue;\n }\n \n const invalidLabel = getInvalidLabel(result.domain);\n if (invalidLabel) {\n url.lastIndex = urlMatch.index + invalidLabel.index + 1;\n continue;\n }\n }\n\n\t\t\t\t// Create URL\n\t\t\t\tresult.url = result.protocol + (result.auth && result.auth + \"@\") + result.domain + result.port + result.path;\n\t\t\t\tresult.text = text.slice(result.start, result.end);\n\t\t\t}\n\t\t\t\n\t\t\t// since regex is shared with other parse generators, cache lastIndex position and restore later\n\t\t\tmustacheLastIndex = mustache.lastIndex;\n\t\t\turlLastIndex = url.lastIndex;\n\t\t\t\n\t\t\tyield result;\n\t\t\t\n\t\t\turl.lastIndex = urlLastIndex;\n\t\t\tmustache.lastIndex = mustacheLastIndex;\n\t\t}\n\t}\n}\n\nfunction getInvalidLabel(domain) {\n // https://tools.ietf.org/html/rfc1035\n // https://serverfault.com/questions/638260/is-it-valid-for-a-hostname-to-start-with-a-digit\n let index = 0;\n const parts = domain.split(\".\");\n for (const part of parts) {\n if (\n !part ||\n part.startsWith(\"-\") ||\n part.endsWith(\"-\")\n ) {\n return {\n index,\n value: part\n };\n }\n index += part.length + 1;\n }\n}\n\nmodule.exports = {\n\tUrlMatcher\n};\n","/**\n * event-lite.js - Light-weight EventEmitter (less than 1KB when gzipped)\n *\n * @copyright Yusuke Kawasaki\n * @license MIT\n * @constructor\n * @see https://github.com/kawanet/event-lite\n * @see http://kawanet.github.io/event-lite/EventLite.html\n * @example\n * var EventLite = require(\"event-lite\");\n *\n * function MyClass() {...} // your class\n *\n * EventLite.mixin(MyClass.prototype); // import event methods\n *\n * var obj = new MyClass();\n * obj.on(\"foo\", function() {...}); // add event listener\n * obj.once(\"bar\", function() {...}); // add one-time event listener\n * obj.emit(\"foo\"); // dispatch event\n * obj.emit(\"bar\"); // dispatch another event\n * obj.off(\"foo\"); // remove event listener\n */\n\nexport default function EventLite() {\n if (!(this instanceof EventLite)) return new EventLite();\n}\n\n// (function(EventLite) {\n // export the class for node.js\n // if (\"undefined\" !== typeof module) module.exports = EventLite;\n\n // property name to hold listeners\n var LISTENERS = \"listeners\";\n\n // methods to export\n var methods = {\n on: on,\n once: once,\n off: off,\n emit: emit\n };\n\n // mixin to self\n mixin(EventLite.prototype);\n\n // export mixin function\n EventLite.mixin = mixin;\n\n /**\n * Import on(), once(), off() and emit() methods into target object.\n *\n * @function EventLite.mixin\n * @param target {Prototype}\n */\n\n function mixin(target) {\n for (var key in methods) {\n target[key] = methods[key];\n }\n return target;\n }\n\n /**\n * Add an event listener.\n *\n * @function EventLite.prototype.on\n * @param type {string}\n * @param func {Function}\n * @returns {EventLite} Self for method chaining\n */\n\n function on(type, func) {\n getListeners(this, type).push(func);\n return this;\n }\n\n /**\n * Add one-time event listener.\n *\n * @function EventLite.prototype.once\n * @param type {string}\n * @param func {Function}\n * @returns {EventLite} Self for method chaining\n */\n\n function once(type, func) {\n var that = this;\n wrap.originalListener = func;\n getListeners(that, type).push(wrap);\n return that;\n\n function wrap() {\n off.call(that, type, wrap);\n func.apply(this, arguments);\n }\n }\n\n /**\n * Remove an event listener.\n *\n * @function EventLite.prototype.off\n * @param [type] {string}\n * @param [func] {Function}\n * @returns {EventLite} Self for method chaining\n */\n\n function off(type, func) {\n var that = this;\n var listners;\n if (!arguments.length) {\n delete that[LISTENERS];\n } else if (!func) {\n listners = that[LISTENERS];\n if (listners) {\n delete listners[type];\n if (!Object.keys(listners).length) return off.call(that);\n }\n } else {\n listners = getListeners(that, type, true);\n if (listners) {\n listners = listners.filter(ne);\n if (!listners.length) return off.call(that, type);\n that[LISTENERS][type] = listners;\n }\n }\n return that;\n\n function ne(test) {\n return test !== func && test.originalListener !== func;\n }\n }\n\n /**\n * Dispatch (trigger) an event.\n *\n * @function EventLite.prototype.emit\n * @param type {string}\n * @param [value] {*}\n * @returns {boolean} True when a listener received the event\n */\n\n function emit(type, value) {\n var that = this;\n var listeners = getListeners(that, type, true);\n if (!listeners) return false;\n var arglen = arguments.length;\n if (arglen === 1) {\n listeners.forEach(zeroarg);\n } else if (arglen === 2) {\n listeners.forEach(onearg);\n } else {\n var args = Array.prototype.slice.call(arguments, 1);\n listeners.forEach(moreargs);\n }\n return !!listeners.length;\n\n function zeroarg(func) {\n func.call(that);\n }\n\n function onearg(func) {\n func.call(that, value);\n }\n\n function moreargs(func) {\n func.apply(that, args);\n }\n }\n\n /**\n * @ignore\n */\n\n function getListeners(that, type, readonly) {\n if (readonly && !that[LISTENERS]) return;\n var listeners = that[LISTENERS] || (that[LISTENERS] = {});\n return listeners[type] || (listeners[type] = []);\n }\n\n// })(EventLite);\n","/* eslint-env browser */\n\nvar Events = require(\"event-lite\");\n\nvar INVALID_TAGS = {\n\ta: true,\n\tnoscript: true,\n\toption: true,\n\tscript: true,\n\tstyle: true,\n\ttextarea: true,\n\tsvg: true,\n\tcanvas: true,\n\tbutton: true,\n\tselect: true,\n\ttemplate: true,\n\tmeter: true,\n\tprogress: true,\n\tmath: true,\n\ttime: true\n};\n\nclass Pos {\n\tconstructor(container, offset, i = 0) {\n\t\tthis.container = container;\n\t\tthis.offset = offset;\n\t\tthis.i = i;\n\t}\n\t\n\tadd(change) {\n\t\tvar cont = this.container,\n\t\t\toffset = this.offset;\n\n\t\tthis.i += change;\n\t\t\n\t\t// If the container is #text.parentNode\n\t\tif (cont.childNodes.length) {\n\t\t\tcont = cont.childNodes[offset];\n\t\t\toffset = 0;\n\t\t}\n\n\t\t// If the container is #text\n\t\twhile (cont) {\n\t\t\tif (cont.nodeType == 3) {\n\t\t\t\tif (!cont.LEN) {\n\t\t\t\t\tcont.LEN = cont.nodeValue.length;\n\t\t\t\t}\n\t\t\t\tif (offset + change <= cont.LEN) {\n\t\t\t\t\tthis.container = cont;\n\t\t\t\t\tthis.offset = offset + change;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tchange = offset + change - cont.LEN;\n\t\t\t\toffset = 0;\n\t\t\t}\n\t\t\tcont = cont.nextSibling;\n\t\t}\n\t}\n\t\n\tmoveTo(offset) {\n\t\tthis.add(offset - this.i);\n\t}\n}\n\nfunction cloneContents(range) {\n\tif (range.startContainer == range.endContainer) {\n\t\treturn document.createTextNode(range.toString());\n\t}\n\treturn range.cloneContents();\n}\n\nvar DEFAULT_OPTIONS = {\n\tmaxRunTime: 100,\n\ttimeout: 10000,\n\tnewTab: true,\n\tnoOpener: true,\n\tembedImage: true,\n recursive: true,\n};\n\nclass Linkifier extends Events {\n\tconstructor(root, options = {}) {\n\t\tsuper();\n\t\tif (!(root instanceof Node)) {\n\t\t\toptions = root;\n\t\t\troot = options.root;\n\t\t}\n\t\tthis.root = root;\n\t\tthis.options = Object.assign({}, DEFAULT_OPTIONS, options);\n\t\tthis.aborted = false;\n\t}\n\tstart() {\n\t\tvar time = Date.now,\n\t\t\tstartTime = time(),\n\t\t\tchunks = this.generateChunks();\n\t\t\t\n\t\tvar next = () => {\n\t\t\tif (this.aborted) {\n\t\t\t\tthis.emit(\"error\", new Error(\"Aborted\"));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvar chunkStart = time(),\n\t\t\t\tnow;\n\t\t\t\t\n\t\t\tdo {\n\t\t\t\tif (chunks.next().done) {\n\t\t\t\t\tthis.emit(\"complete\", time() - startTime);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t} while ((now = time()) - chunkStart < this.options.maxRunTime);\n\t\t\t\n\t\t\tif (now - startTime > this.options.timeout) {\n\t\t\t\tthis.emit(\"error\", new Error(`max execution time exceeded: ${now - startTime}, on ${this.root}`));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tsetTimeout(next);\n\t\t};\n\t\t\t\n\t\tsetTimeout(next);\n\t}\n\tabort() {\n\t\tthis.aborted = true;\n\t}\n\t*generateRanges() {\n\t\tvar {validator, recursive} = this.options;\n\t\tvar filter = {\n\t\t\tacceptNode: function(node) {\n\t\t\t\tif (validator && !validator(node)) {\n\t\t\t\t\treturn NodeFilter.FILTER_REJECT;\n\t\t\t\t}\n\t\t\t\tif (INVALID_TAGS[node.localName]) {\n\t\t\t\t\treturn NodeFilter.FILTER_REJECT;\n\t\t\t\t}\n\t\t\t\tif (node.localName == \"wbr\") {\n\t\t\t\t\treturn NodeFilter.FILTER_ACCEPT;\n\t\t\t\t}\n\t\t\t\tif (node.nodeType == 3) {\n\t\t\t\t\treturn NodeFilter.FILTER_ACCEPT;\n\t\t\t\t}\n\t\t\t\treturn recursive ? NodeFilter.FILTER_SKIP : NodeFilter.FILTER_REJECT;\n\t\t\t}\n\t\t};\n\t\t// Generate linkified ranges.\n\t\tvar walker = document.createTreeWalker(\n\t\t\tthis.root,\n\t\t\tNodeFilter.SHOW_TEXT + NodeFilter.SHOW_ELEMENT,\n\t\t\tfilter\n\t\t), start, end, current, range;\n\n\t\tend = start = walker.nextNode();\n\t\tif (!start) {\n\t\t\treturn;\n\t\t}\n\t\trange = document.createRange();\n\t\trange.setStartBefore(start);\n\t\twhile ((current = walker.nextNode())) {\n\t\t\tif (end.nextSibling == current) {\n\t\t\t\tend = current;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\trange.setEndAfter(end);\n\t\t\tyield range;\n\n\t\t\tend = start = current;\n\t\t\trange.setStartBefore(start);\n\t\t}\n\t\trange.setEndAfter(end);\n\t\tyield range;\n\t}\n\t*generateChunks() {\n\t\tvar {matcher} = this.options;\n\t\tfor (var range of this.generateRanges()) {\n\t\t\tvar frag = null,\n\t\t\t\tpos = null,\n\t\t\t\ttext = range.toString(),\n\t\t\t\ttextRange = null;\n\t\t\tfor (var result of matcher.match(text)) {\n\t\t\t\tif (!frag) {\n\t\t\t\t\tfrag = document.createDocumentFragment();\n\t\t\t\t\tpos = new Pos(range.startContainer, range.startOffset);\n\t\t\t\t\ttextRange = range.cloneRange();\n\t\t\t\t}\n\t\t\t\t// clone text\n\t\t\t\tpos.moveTo(result.start);\n\t\t\t\ttextRange.setEnd(pos.container, pos.offset);\n\t\t\t\tfrag.appendChild(cloneContents(textRange));\n\t\t\t\t\n\t\t\t\t// clone link\n\t\t\t\ttextRange.collapse();\n\t\t\t\tpos.moveTo(result.end);\n\t\t\t\ttextRange.setEnd(pos.container, pos.offset);\n\t\t\t\t\n\t\t\t\tvar content = cloneContents(textRange),\n\t\t\t\t\tlink = this.buildLink(result, content);\n\n\t\t\t\ttextRange.collapse();\n\n\t\t\t\tfrag.appendChild(link);\n\t\t\t\tthis.emit(\"link\", {link, range, result, content});\n\t\t\t}\n\t\t\tif (pos) {\n\t\t\t\tpos.moveTo(text.length);\n\t\t\t\ttextRange.setEnd(pos.container, pos.offset);\n\t\t\t\tfrag.appendChild(cloneContents(textRange));\n\t\t\t\t\n\t\t\t\trange.deleteContents();\n\t\t\t\trange.insertNode(frag);\n\t\t\t}\n\t\t\tyield;\n\t\t}\n\t}\n\tbuildLink(result, content) {\n\t\tvar {newTab, embedImage, noOpener} = this.options;\n\t\tvar link = document.createElement(\"a\");\n\t\tlink.href = result.url;\n\t\tlink.title = \"Linkify Plus Plus\";\n\t\tlink.className = \"linkifyplus\";\n\t\tif (newTab) {\n\t\t\tlink.target = \"_blank\";\n\t\t}\n\t\tif (noOpener) {\n\t\t\tlink.rel = \"noopener\";\n\t\t}\n\t\tvar child;\n\t\tif (embedImage && /^[^?#]+\\.(?:jpg|jpeg|png|apng|gif|svg|webp)(?:$|[?#])/i.test(result.url)) {\n\t\t\tchild = new Image;\n\t\t\tchild.src = result.url;\n\t\t\tchild.alt = result.text;\n\t\t} else {\n\t\t\tchild = content;\n\t\t}\n\t\tlink.appendChild(child);\n\t\treturn link;\n\t}\n}\n\nfunction linkify(...args) {\n\treturn new Promise((resolve, reject) => {\n\t\tvar linkifier = new Linkifier(...args);\n\t\tlinkifier.on(\"error\", reject);\n\t\tlinkifier.on(\"complete\", resolve);\n\t\tfor (var key of Object.keys(linkifier.options)) {\n\t\t\tif (key.startsWith(\"on\")) {\n\t\t\t\tlinkifier.on(key.slice(2), linkifier.options[key]);\n\t\t\t}\n\t\t}\n\t\tlinkifier.start();\n\t});\n}\n\nmodule.exports = {\n\tINVALID_TAGS,\n\tLinkifier,\n\tlinkify\n};\n"],"names":["RE","TLD_TABLE","regexEscape","text","replace","pathStrip","m","re","repl","s","path","end","length","suffix","slice","pathStripQuote","c","i","pos","endsWith","indexOf","pathStripBrace","left","right","match","str","RegExp","count","exec","index","isIP","inTLDS","domain","key","toLowerCase","hasOwnProperty","getInvalidLabel","parts","split","part","startsWith","value","EventLite","this","LISTENERS","methods","on","type","func","getListeners","push","once","that","wrap","originalListener","off","call","apply","arguments","emit","listeners","arglen","forEach","args","Array","prototype","mixin","target","listners","filter","test","Object","keys","readonly","INVALID_TAGS","a","noscript","option","script","style","textarea","svg","canvas","button","select","template","meter","progress","math","time","Pos","constructor","container","offset","add","change","cont","childNodes","nodeType","LEN","nodeValue","nextSibling","moveTo","cloneContents","range","startContainer","endContainer","document","createTextNode","toString","DEFAULT_OPTIONS","maxRunTime","timeout","newTab","noOpener","embedImage","recursive","Linkifier","Events","root","options","super","Node","assign","aborted","start","Date","now","startTime","chunks","generateChunks","next","Error","chunkStart","done","setTimeout","abort","generateRanges","current","validator","acceptNode","node","localName","NodeFilter","FILTER_REJECT","FILTER_ACCEPT","FILTER_SKIP","walker","createTreeWalker","SHOW_TEXT","SHOW_ELEMENT","nextNode","createRange","setStartBefore","setEndAfter","matcher","frag","textRange","result","createDocumentFragment","startOffset","cloneRange","setEnd","appendChild","collapse","content","link","buildLink","deleteContents","insertNode","child","createElement","href","url","title","className","rel","Image","src","alt","regex","unicode","customRules","standalone","boundaryLeft","boundaryRight","prefix","invalidSuffix","pattern","join","mustache","buildRegex","urlLastIndex","mustacheLastIndex","mustacheMatch","mustacheRange","urlMatch","fuzzyIp","ignoreMustache","mail","lastIndex","custom","protocol","auth","port","matchMail","domainMatch","invalidLabel","Promise","resolve","reject","linkifier"],"mappings":"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","x_google_ignoreList":[1]} -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import js from "@eslint/js"; 2 | import globals from "globals"; 3 | import compat from "eslint-plugin-compat"; 4 | 5 | export default [ 6 | { 7 | ignores: [ 8 | "dist", 9 | "dist-extension", 10 | "**/__snapshots__/*.js" 11 | ] 12 | }, 13 | js.configs.recommended, 14 | compat.configs["flat/recommended"], 15 | { 16 | "rules": { 17 | "dot-notation": 2, 18 | "max-statements-per-line": 2, 19 | }, 20 | languageOptions: { 21 | globals: { 22 | ...globals.browser, 23 | ...globals.node, 24 | ...globals.mocha 25 | } 26 | } 27 | }, 28 | ]; 29 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var {UrlMatcher} = require("./lib/url-matcher"), 2 | {INVALID_TAGS, Linkifier, linkify} = require("./lib/linkifier"); 3 | 4 | module.exports = { 5 | UrlMatcher, 6 | Linkifier, 7 | INVALID_TAGS, 8 | linkify 9 | }; 10 | -------------------------------------------------------------------------------- /lib/linkifier.js: -------------------------------------------------------------------------------- 1 | /* eslint-env browser */ 2 | 3 | var Events = require("event-lite"); 4 | 5 | var INVALID_TAGS = { 6 | a: true, 7 | noscript: true, 8 | option: true, 9 | script: true, 10 | style: true, 11 | textarea: true, 12 | svg: true, 13 | canvas: true, 14 | button: true, 15 | select: true, 16 | template: true, 17 | meter: true, 18 | progress: true, 19 | math: true, 20 | time: true 21 | }; 22 | 23 | class Pos { 24 | constructor(container, offset, i = 0) { 25 | this.container = container; 26 | this.offset = offset; 27 | this.i = i; 28 | } 29 | 30 | add(change) { 31 | var cont = this.container, 32 | offset = this.offset; 33 | 34 | this.i += change; 35 | 36 | // If the container is #text.parentNode 37 | if (cont.childNodes.length) { 38 | cont = cont.childNodes[offset]; 39 | offset = 0; 40 | } 41 | 42 | // If the container is #text 43 | while (cont) { 44 | if (cont.nodeType == 3) { 45 | if (!cont.LEN) { 46 | cont.LEN = cont.nodeValue.length; 47 | } 48 | if (offset + change <= cont.LEN) { 49 | this.container = cont; 50 | this.offset = offset + change; 51 | return; 52 | } 53 | change = offset + change - cont.LEN; 54 | offset = 0; 55 | } 56 | cont = cont.nextSibling; 57 | } 58 | } 59 | 60 | moveTo(offset) { 61 | this.add(offset - this.i); 62 | } 63 | } 64 | 65 | function cloneContents(range) { 66 | if (range.startContainer == range.endContainer) { 67 | return document.createTextNode(range.toString()); 68 | } 69 | return range.cloneContents(); 70 | } 71 | 72 | var DEFAULT_OPTIONS = { 73 | maxRunTime: 100, 74 | timeout: 10000, 75 | newTab: true, 76 | noOpener: true, 77 | embedImage: true, 78 | recursive: true, 79 | }; 80 | 81 | class Linkifier extends Events { 82 | constructor(root, options = {}) { 83 | super(); 84 | if (!(root instanceof Node)) { 85 | options = root; 86 | root = options.root; 87 | } 88 | this.root = root; 89 | this.options = Object.assign({}, DEFAULT_OPTIONS, options); 90 | this.aborted = false; 91 | } 92 | start() { 93 | var time = Date.now, 94 | startTime = time(), 95 | chunks = this.generateChunks(); 96 | 97 | var next = () => { 98 | if (this.aborted) { 99 | this.emit("error", new Error("Aborted")); 100 | return; 101 | } 102 | var chunkStart = time(), 103 | now; 104 | 105 | do { 106 | if (chunks.next().done) { 107 | this.emit("complete", time() - startTime); 108 | return; 109 | } 110 | } while ((now = time()) - chunkStart < this.options.maxRunTime); 111 | 112 | if (now - startTime > this.options.timeout) { 113 | this.emit("error", new Error(`max execution time exceeded: ${now - startTime}, on ${this.root}`)); 114 | return; 115 | } 116 | 117 | setTimeout(next); 118 | }; 119 | 120 | setTimeout(next); 121 | } 122 | abort() { 123 | this.aborted = true; 124 | } 125 | *generateRanges() { 126 | var {validator, recursive} = this.options; 127 | var filter = { 128 | acceptNode: function(node) { 129 | if (validator && !validator(node)) { 130 | return NodeFilter.FILTER_REJECT; 131 | } 132 | if (INVALID_TAGS[node.localName]) { 133 | return NodeFilter.FILTER_REJECT; 134 | } 135 | if (node.localName == "wbr") { 136 | return NodeFilter.FILTER_ACCEPT; 137 | } 138 | if (node.nodeType == 3) { 139 | return NodeFilter.FILTER_ACCEPT; 140 | } 141 | return recursive ? NodeFilter.FILTER_SKIP : NodeFilter.FILTER_REJECT; 142 | } 143 | }; 144 | // Generate linkified ranges. 145 | var walker = document.createTreeWalker( 146 | this.root, 147 | NodeFilter.SHOW_TEXT + NodeFilter.SHOW_ELEMENT, 148 | filter 149 | ), start, end, current, range; 150 | 151 | end = start = walker.nextNode(); 152 | if (!start) { 153 | return; 154 | } 155 | range = document.createRange(); 156 | range.setStartBefore(start); 157 | while ((current = walker.nextNode())) { 158 | if (end.nextSibling == current) { 159 | end = current; 160 | continue; 161 | } 162 | range.setEndAfter(end); 163 | yield range; 164 | 165 | end = start = current; 166 | range.setStartBefore(start); 167 | } 168 | range.setEndAfter(end); 169 | yield range; 170 | } 171 | *generateChunks() { 172 | var {matcher} = this.options; 173 | for (var range of this.generateRanges()) { 174 | var frag = null, 175 | pos = null, 176 | text = range.toString(), 177 | textRange = null; 178 | for (var result of matcher.match(text)) { 179 | if (!frag) { 180 | frag = document.createDocumentFragment(); 181 | pos = new Pos(range.startContainer, range.startOffset); 182 | textRange = range.cloneRange(); 183 | } 184 | // clone text 185 | pos.moveTo(result.start); 186 | textRange.setEnd(pos.container, pos.offset); 187 | frag.appendChild(cloneContents(textRange)); 188 | 189 | // clone link 190 | textRange.collapse(); 191 | pos.moveTo(result.end); 192 | textRange.setEnd(pos.container, pos.offset); 193 | 194 | var content = cloneContents(textRange), 195 | link = this.buildLink(result, content); 196 | 197 | textRange.collapse(); 198 | 199 | frag.appendChild(link); 200 | this.emit("link", {link, range, result, content}); 201 | } 202 | if (pos) { 203 | pos.moveTo(text.length); 204 | textRange.setEnd(pos.container, pos.offset); 205 | frag.appendChild(cloneContents(textRange)); 206 | 207 | range.deleteContents(); 208 | range.insertNode(frag); 209 | } 210 | yield; 211 | } 212 | } 213 | buildLink(result, content) { 214 | var {newTab, embedImage, noOpener} = this.options; 215 | var link = document.createElement("a"); 216 | link.href = result.url; 217 | link.title = "Linkify Plus Plus"; 218 | link.className = "linkifyplus"; 219 | if (newTab) { 220 | link.target = "_blank"; 221 | } 222 | if (noOpener) { 223 | link.rel = "noopener"; 224 | } 225 | var child; 226 | if (embedImage && /^[^?#]+\.(?:jpg|jpeg|png|apng|gif|svg|webp)(?:$|[?#])/i.test(result.url)) { 227 | child = new Image; 228 | child.src = result.url; 229 | child.alt = result.text; 230 | } else { 231 | child = content; 232 | } 233 | link.appendChild(child); 234 | return link; 235 | } 236 | } 237 | 238 | function linkify(...args) { 239 | return new Promise((resolve, reject) => { 240 | var linkifier = new Linkifier(...args); 241 | linkifier.on("error", reject); 242 | linkifier.on("complete", resolve); 243 | for (var key of Object.keys(linkifier.options)) { 244 | if (key.startsWith("on")) { 245 | linkifier.on(key.slice(2), linkifier.options[key]); 246 | } 247 | } 248 | linkifier.start(); 249 | }); 250 | } 251 | 252 | module.exports = { 253 | INVALID_TAGS, 254 | Linkifier, 255 | linkify 256 | }; 257 | -------------------------------------------------------------------------------- /lib/tlds.json: -------------------------------------------------------------------------------- 1 | { 2 | "maxLength": 24, 3 | "chars": "セール佛山ಭಾರತ集团在线한국ଭାରତভাৰতর八卦ישראלموقعবংল公司网站移动我爱你москвақзнлйт联通рбгеקוםファッションストアசிங்கபூர商标店城дию家電中文信国國娱乐భారత్ලංකා购物クラウドભારતभारतम्ोसंगठन餐厅络у香港食品飞利浦台湾灣手机الجزئرنیتبيپکسدغظحةڀ澳門닷컴شكგე构健康ไทย招聘фລາວみんなευλ世界書籍ഭാരതംਭਾਰਤ址넷コム游戏ö企业息صط广东இலைநதயாհայ新加坡ف政务", 4 | "table": { 5 | "aaa": true, 6 | "aarp": true, 7 | "abb": true, 8 | "abbott": true, 9 | "abbvie": true, 10 | "abc": true, 11 | "able": true, 12 | "abogado": true, 13 | "abudhabi": true, 14 | "ac": true, 15 | "academy": true, 16 | "accountant": true, 17 | "accountants": true, 18 | "aco": true, 19 | "actor": true, 20 | "ad": true, 21 | "adult": true, 22 | "ae": true, 23 | "aeg": true, 24 | "aero": true, 25 | "aetna": true, 26 | "af": true, 27 | "afl": true, 28 | "africa": true, 29 | "ag": true, 30 | "agency": true, 31 | "ai": true, 32 | "aig": true, 33 | "airbus": true, 34 | "airforce": true, 35 | "akdn": true, 36 | "al": true, 37 | "allfinanz": true, 38 | "allstate": true, 39 | "ally": true, 40 | "alsace": true, 41 | "alstom": true, 42 | "am": true, 43 | "amazon": true, 44 | "americanexpress": true, 45 | "amex": true, 46 | "amfam": true, 47 | "amica": true, 48 | "amsterdam": true, 49 | "analytics": true, 50 | "android": true, 51 | "anz": true, 52 | "ao": true, 53 | "apartments": true, 54 | "app": true, 55 | "apple": true, 56 | "aq": true, 57 | "aquarelle": true, 58 | "ar": true, 59 | "archi": true, 60 | "army": true, 61 | "arpa": true, 62 | "art": true, 63 | "arte": true, 64 | "as": true, 65 | "asia": true, 66 | "associates": true, 67 | "at": true, 68 | "attorney": true, 69 | "au": true, 70 | "auction": true, 71 | "audi": true, 72 | "audio": true, 73 | "auspost": true, 74 | "auto": true, 75 | "autos": true, 76 | "aw": true, 77 | "aws": true, 78 | "ax": true, 79 | "axa": true, 80 | "az": true, 81 | "azure": true, 82 | "ba": true, 83 | "baby": true, 84 | "band": true, 85 | "bank": true, 86 | "bar": true, 87 | "barcelona": true, 88 | "barclaycard": true, 89 | "barclays": true, 90 | "bargains": true, 91 | "basketball": true, 92 | "bauhaus": true, 93 | "bayern": true, 94 | "bb": true, 95 | "bbc": true, 96 | "bbva": true, 97 | "bcn": true, 98 | "bd": true, 99 | "be": true, 100 | "beauty": true, 101 | "beer": true, 102 | "bentley": true, 103 | "berlin": true, 104 | "best": true, 105 | "bet": true, 106 | "bf": true, 107 | "bg": true, 108 | "bh": true, 109 | "bi": true, 110 | "bible": true, 111 | "bid": true, 112 | "bike": true, 113 | "bing": true, 114 | "bingo": true, 115 | "bio": true, 116 | "biz": true, 117 | "bj": true, 118 | "black": true, 119 | "blackfriday": true, 120 | "blog": true, 121 | "bloomberg": true, 122 | "blue": true, 123 | "bm": true, 124 | "bmw": true, 125 | "bn": true, 126 | "bnpparibas": true, 127 | "bo": true, 128 | "boats": true, 129 | "bond": true, 130 | "boo": true, 131 | "bostik": true, 132 | "boston": true, 133 | "bot": true, 134 | "boutique": true, 135 | "box": true, 136 | "br": true, 137 | "bradesco": true, 138 | "bridgestone": true, 139 | "broadway": true, 140 | "broker": true, 141 | "brother": true, 142 | "brussels": true, 143 | "bs": true, 144 | "bt": true, 145 | "build": true, 146 | "builders": true, 147 | "business": true, 148 | "buzz": true, 149 | "bw": true, 150 | "by": true, 151 | "bz": true, 152 | "bzh": true, 153 | "ca": true, 154 | "cab": true, 155 | "cafe": true, 156 | "cam": true, 157 | "camera": true, 158 | "camp": true, 159 | "canon": true, 160 | "capetown": true, 161 | "capital": true, 162 | "car": true, 163 | "cards": true, 164 | "care": true, 165 | "career": true, 166 | "careers": true, 167 | "cars": true, 168 | "casa": true, 169 | "case": true, 170 | "cash": true, 171 | "casino": true, 172 | "cat": true, 173 | "catering": true, 174 | "catholic": true, 175 | "cba": true, 176 | "cbn": true, 177 | "cc": true, 178 | "cd": true, 179 | "center": true, 180 | "ceo": true, 181 | "cern": true, 182 | "cf": true, 183 | "cfa": true, 184 | "cfd": true, 185 | "cg": true, 186 | "ch": true, 187 | "chanel": true, 188 | "channel": true, 189 | "charity": true, 190 | "chase": true, 191 | "chat": true, 192 | "cheap": true, 193 | "chintai": true, 194 | "christmas": true, 195 | "church": true, 196 | "ci": true, 197 | "cisco": true, 198 | "citi": true, 199 | "citic": true, 200 | "city": true, 201 | "ck": true, 202 | "cl": true, 203 | "claims": true, 204 | "cleaning": true, 205 | "click": true, 206 | "clinic": true, 207 | "clothing": true, 208 | "cloud": true, 209 | "club": true, 210 | "clubmed": true, 211 | "cm": true, 212 | "cn": true, 213 | "co": true, 214 | "coach": true, 215 | "codes": true, 216 | "coffee": true, 217 | "college": true, 218 | "cologne": true, 219 | "com": true, 220 | "commbank": true, 221 | "community": true, 222 | "company": true, 223 | "compare": true, 224 | "computer": true, 225 | "condos": true, 226 | "construction": true, 227 | "consulting": true, 228 | "contact": true, 229 | "contractors": true, 230 | "cooking": true, 231 | "cool": true, 232 | "coop": true, 233 | "corsica": true, 234 | "country": true, 235 | "coupons": true, 236 | "courses": true, 237 | "cpa": true, 238 | "cr": true, 239 | "credit": true, 240 | "creditcard": true, 241 | "creditunion": true, 242 | "cricket": true, 243 | "crown": true, 244 | "crs": true, 245 | "cruises": true, 246 | "cu": true, 247 | "cuisinella": true, 248 | "cv": true, 249 | "cw": true, 250 | "cx": true, 251 | "cy": true, 252 | "cymru": true, 253 | "cyou": true, 254 | "cz": true, 255 | "dad": true, 256 | "dance": true, 257 | "date": true, 258 | "dating": true, 259 | "day": true, 260 | "de": true, 261 | "deal": true, 262 | "dealer": true, 263 | "deals": true, 264 | "degree": true, 265 | "delivery": true, 266 | "dell": true, 267 | "deloitte": true, 268 | "democrat": true, 269 | "dental": true, 270 | "dentist": true, 271 | "desi": true, 272 | "design": true, 273 | "dev": true, 274 | "dhl": true, 275 | "diamonds": true, 276 | "diet": true, 277 | "digital": true, 278 | "direct": true, 279 | "directory": true, 280 | "discount": true, 281 | "discover": true, 282 | "diy": true, 283 | "dj": true, 284 | "dk": true, 285 | "dm": true, 286 | "do": true, 287 | "doctor": true, 288 | "dog": true, 289 | "domains": true, 290 | "download": true, 291 | "dubai": true, 292 | "dupont": true, 293 | "durban": true, 294 | "dvag": true, 295 | "dz": true, 296 | "earth": true, 297 | "ec": true, 298 | "eco": true, 299 | "edeka": true, 300 | "edu": true, 301 | "education": true, 302 | "ee": true, 303 | "eg": true, 304 | "email": true, 305 | "emerck": true, 306 | "energy": true, 307 | "engineer": true, 308 | "engineering": true, 309 | "enterprises": true, 310 | "equipment": true, 311 | "er": true, 312 | "ericsson": true, 313 | "erni": true, 314 | "es": true, 315 | "esq": true, 316 | "estate": true, 317 | "et": true, 318 | "eu": true, 319 | "eurovision": true, 320 | "eus": true, 321 | "events": true, 322 | "exchange": true, 323 | "expert": true, 324 | "exposed": true, 325 | "express": true, 326 | "extraspace": true, 327 | "fage": true, 328 | "fail": true, 329 | "fairwinds": true, 330 | "faith": true, 331 | "family": true, 332 | "fan": true, 333 | "fans": true, 334 | "farm": true, 335 | "fashion": true, 336 | "feedback": true, 337 | "ferrero": true, 338 | "fi": true, 339 | "film": true, 340 | "finance": true, 341 | "financial": true, 342 | "firmdale": true, 343 | "fish": true, 344 | "fishing": true, 345 | "fit": true, 346 | "fitness": true, 347 | "fj": true, 348 | "fk": true, 349 | "flickr": true, 350 | "flights": true, 351 | "flir": true, 352 | "florist": true, 353 | "flowers": true, 354 | "fm": true, 355 | "fo": true, 356 | "foo": true, 357 | "food": true, 358 | "football": true, 359 | "ford": true, 360 | "forex": true, 361 | "forsale": true, 362 | "forum": true, 363 | "foundation": true, 364 | "fox": true, 365 | "fr": true, 366 | "fresenius": true, 367 | "frl": true, 368 | "frogans": true, 369 | "fujitsu": true, 370 | "fun": true, 371 | "fund": true, 372 | "furniture": true, 373 | "futbol": true, 374 | "fyi": true, 375 | "ga": true, 376 | "gal": true, 377 | "gallery": true, 378 | "game": true, 379 | "games": true, 380 | "garden": true, 381 | "gay": true, 382 | "gd": true, 383 | "gdn": true, 384 | "ge": true, 385 | "gea": true, 386 | "gent": true, 387 | "genting": true, 388 | "gf": true, 389 | "gg": true, 390 | "gh": true, 391 | "gi": true, 392 | "gift": true, 393 | "gifts": true, 394 | "gives": true, 395 | "giving": true, 396 | "gl": true, 397 | "glass": true, 398 | "gle": true, 399 | "global": true, 400 | "globo": true, 401 | "gm": true, 402 | "gmail": true, 403 | "gmbh": true, 404 | "gmo": true, 405 | "gmx": true, 406 | "gn": true, 407 | "godaddy": true, 408 | "gold": true, 409 | "golf": true, 410 | "goog": true, 411 | "google": true, 412 | "gop": true, 413 | "gov": true, 414 | "gp": true, 415 | "gq": true, 416 | "gr": true, 417 | "grainger": true, 418 | "graphics": true, 419 | "gratis": true, 420 | "green": true, 421 | "gripe": true, 422 | "group": true, 423 | "gs": true, 424 | "gt": true, 425 | "gu": true, 426 | "gucci": true, 427 | "guide": true, 428 | "guitars": true, 429 | "guru": true, 430 | "gw": true, 431 | "gy": true, 432 | "hair": true, 433 | "hamburg": true, 434 | "haus": true, 435 | "health": true, 436 | "healthcare": true, 437 | "help": true, 438 | "helsinki": true, 439 | "here": true, 440 | "hermes": true, 441 | "hiphop": true, 442 | "hisamitsu": true, 443 | "hitachi": true, 444 | "hiv": true, 445 | "hk": true, 446 | "hm": true, 447 | "hn": true, 448 | "hockey": true, 449 | "holdings": true, 450 | "holiday": true, 451 | "homes": true, 452 | "honda": true, 453 | "horse": true, 454 | "hospital": true, 455 | "host": true, 456 | "hosting": true, 457 | "hotmail": true, 458 | "house": true, 459 | "how": true, 460 | "hr": true, 461 | "hsbc": true, 462 | "ht": true, 463 | "hu": true, 464 | "hyatt": true, 465 | "hyundai": true, 466 | "ice": true, 467 | "icu": true, 468 | "id": true, 469 | "ie": true, 470 | "ieee": true, 471 | "ifm": true, 472 | "ikano": true, 473 | "il": true, 474 | "im": true, 475 | "imamat": true, 476 | "immo": true, 477 | "immobilien": true, 478 | "in": true, 479 | "inc": true, 480 | "industries": true, 481 | "info": true, 482 | "ing": true, 483 | "ink": true, 484 | "institute": true, 485 | "insurance": true, 486 | "insure": true, 487 | "int": true, 488 | "international": true, 489 | "investments": true, 490 | "io": true, 491 | "ipiranga": true, 492 | "iq": true, 493 | "ir": true, 494 | "irish": true, 495 | "is": true, 496 | "ismaili": true, 497 | "ist": true, 498 | "istanbul": true, 499 | "it": true, 500 | "itau": true, 501 | "itv": true, 502 | "jaguar": true, 503 | "java": true, 504 | "jcb": true, 505 | "je": true, 506 | "jetzt": true, 507 | "jewelry": true, 508 | "jio": true, 509 | "jll": true, 510 | "jm": true, 511 | "jmp": true, 512 | "jnj": true, 513 | "jo": true, 514 | "jobs": true, 515 | "joburg": true, 516 | "jp": true, 517 | "jpmorgan": true, 518 | "jprs": true, 519 | "juegos": true, 520 | "kaufen": true, 521 | "ke": true, 522 | "kfh": true, 523 | "kg": true, 524 | "kh": true, 525 | "ki": true, 526 | "kia": true, 527 | "kids": true, 528 | "kim": true, 529 | "kitchen": true, 530 | "kiwi": true, 531 | "km": true, 532 | "kn": true, 533 | "koeln": true, 534 | "komatsu": true, 535 | "kp": true, 536 | "kpmg": true, 537 | "kpn": true, 538 | "kr": true, 539 | "krd": true, 540 | "kred": true, 541 | "kw": true, 542 | "ky": true, 543 | "kyoto": true, 544 | "kz": true, 545 | "la": true, 546 | "lamborghini": true, 547 | "lancaster": true, 548 | "land": true, 549 | "landrover": true, 550 | "lanxess": true, 551 | "lat": true, 552 | "latrobe": true, 553 | "law": true, 554 | "lawyer": true, 555 | "lb": true, 556 | "lc": true, 557 | "lease": true, 558 | "leclerc": true, 559 | "legal": true, 560 | "lexus": true, 561 | "lgbt": true, 562 | "li": true, 563 | "lidl": true, 564 | "life": true, 565 | "lifestyle": true, 566 | "lighting": true, 567 | "lilly": true, 568 | "limited": true, 569 | "limo": true, 570 | "lincoln": true, 571 | "link": true, 572 | "live": true, 573 | "living": true, 574 | "lk": true, 575 | "llc": true, 576 | "loan": true, 577 | "loans": true, 578 | "locker": true, 579 | "locus": true, 580 | "lol": true, 581 | "london": true, 582 | "lotto": true, 583 | "love": true, 584 | "lr": true, 585 | "ls": true, 586 | "lt": true, 587 | "ltd": true, 588 | "ltda": true, 589 | "lu": true, 590 | "lundbeck": true, 591 | "luxe": true, 592 | "luxury": true, 593 | "lv": true, 594 | "ly": true, 595 | "ma": true, 596 | "madrid": true, 597 | "maif": true, 598 | "maison": true, 599 | "makeup": true, 600 | "man": true, 601 | "management": true, 602 | "mango": true, 603 | "market": true, 604 | "marketing": true, 605 | "markets": true, 606 | "marriott": true, 607 | "mattel": true, 608 | "mba": true, 609 | "mc": true, 610 | "md": true, 611 | "me": true, 612 | "med": true, 613 | "media": true, 614 | "meet": true, 615 | "melbourne": true, 616 | "meme": true, 617 | "memorial": true, 618 | "men": true, 619 | "menu": true, 620 | "mg": true, 621 | "mh": true, 622 | "miami": true, 623 | "microsoft": true, 624 | "mil": true, 625 | "mini": true, 626 | "mit": true, 627 | "mk": true, 628 | "ml": true, 629 | "mlb": true, 630 | "mm": true, 631 | "mma": true, 632 | "mn": true, 633 | "mo": true, 634 | "mobi": true, 635 | "moda": true, 636 | "moe": true, 637 | "moi": true, 638 | "mom": true, 639 | "monash": true, 640 | "money": true, 641 | "monster": true, 642 | "mortgage": true, 643 | "moscow": true, 644 | "motorcycles": true, 645 | "mov": true, 646 | "movie": true, 647 | "mp": true, 648 | "mq": true, 649 | "mr": true, 650 | "ms": true, 651 | "mt": true, 652 | "mtn": true, 653 | "mtr": true, 654 | "mu": true, 655 | "museum": true, 656 | "music": true, 657 | "mv": true, 658 | "mw": true, 659 | "mx": true, 660 | "my": true, 661 | "mz": true, 662 | "na": true, 663 | "nab": true, 664 | "nagoya": true, 665 | "name": true, 666 | "navy": true, 667 | "nc": true, 668 | "ne": true, 669 | "nec": true, 670 | "net": true, 671 | "netbank": true, 672 | "network": true, 673 | "neustar": true, 674 | "new": true, 675 | "news": true, 676 | "next": true, 677 | "nexus": true, 678 | "nf": true, 679 | "ng": true, 680 | "ngo": true, 681 | "nhk": true, 682 | "ni": true, 683 | "nico": true, 684 | "nike": true, 685 | "ninja": true, 686 | "nissan": true, 687 | "nl": true, 688 | "no": true, 689 | "nokia": true, 690 | "now": true, 691 | "nowruz": true, 692 | "np": true, 693 | "nr": true, 694 | "nra": true, 695 | "nrw": true, 696 | "ntt": true, 697 | "nu": true, 698 | "nyc": true, 699 | "nz": true, 700 | "observer": true, 701 | "office": true, 702 | "okinawa": true, 703 | "om": true, 704 | "omega": true, 705 | "one": true, 706 | "ong": true, 707 | "onl": true, 708 | "online": true, 709 | "ooo": true, 710 | "oracle": true, 711 | "orange": true, 712 | "org": true, 713 | "organic": true, 714 | "osaka": true, 715 | "otsuka": true, 716 | "ovh": true, 717 | "pa": true, 718 | "page": true, 719 | "panasonic": true, 720 | "paris": true, 721 | "partners": true, 722 | "parts": true, 723 | "party": true, 724 | "pe": true, 725 | "pet": true, 726 | "pf": true, 727 | "pfizer": true, 728 | "pg": true, 729 | "ph": true, 730 | "pharmacy": true, 731 | "phd": true, 732 | "philips": true, 733 | "photo": true, 734 | "photography": true, 735 | "photos": true, 736 | "physio": true, 737 | "pics": true, 738 | "pictet": true, 739 | "pictures": true, 740 | "ping": true, 741 | "pink": true, 742 | "pioneer": true, 743 | "pizza": true, 744 | "pk": true, 745 | "pl": true, 746 | "place": true, 747 | "play": true, 748 | "plumbing": true, 749 | "plus": true, 750 | "pm": true, 751 | "pn": true, 752 | "pohl": true, 753 | "poker": true, 754 | "politie": true, 755 | "porn": true, 756 | "post": true, 757 | "pr": true, 758 | "praxi": true, 759 | "press": true, 760 | "prime": true, 761 | "pro": true, 762 | "productions": true, 763 | "prof": true, 764 | "promo": true, 765 | "properties": true, 766 | "property": true, 767 | "protection": true, 768 | "pru": true, 769 | "prudential": true, 770 | "ps": true, 771 | "pt": true, 772 | "pub": true, 773 | "pw": true, 774 | "pwc": true, 775 | "py": true, 776 | "qa": true, 777 | "qpon": true, 778 | "quebec": true, 779 | "quest": true, 780 | "racing": true, 781 | "radio": true, 782 | "re": true, 783 | "realestate": true, 784 | "realtor": true, 785 | "realty": true, 786 | "recipes": true, 787 | "red": true, 788 | "redstone": true, 789 | "rehab": true, 790 | "reise": true, 791 | "reisen": true, 792 | "reit": true, 793 | "ren": true, 794 | "rent": true, 795 | "rentals": true, 796 | "repair": true, 797 | "report": true, 798 | "republican": true, 799 | "rest": true, 800 | "restaurant": true, 801 | "review": true, 802 | "reviews": true, 803 | "rexroth": true, 804 | "rich": true, 805 | "ricoh": true, 806 | "rio": true, 807 | "rip": true, 808 | "ro": true, 809 | "rocks": true, 810 | "rodeo": true, 811 | "rogers": true, 812 | "rs": true, 813 | "rsvp": true, 814 | "ru": true, 815 | "rugby": true, 816 | "ruhr": true, 817 | "run": true, 818 | "rw": true, 819 | "ryukyu": true, 820 | "sa": true, 821 | "saarland": true, 822 | "sale": true, 823 | "salon": true, 824 | "samsung": true, 825 | "sandvik": true, 826 | "sandvikcoromant": true, 827 | "sanofi": true, 828 | "sap": true, 829 | "sarl": true, 830 | "saxo": true, 831 | "sb": true, 832 | "sbi": true, 833 | "sbs": true, 834 | "sc": true, 835 | "scb": true, 836 | "schaeffler": true, 837 | "schmidt": true, 838 | "school": true, 839 | "schule": true, 840 | "schwarz": true, 841 | "science": true, 842 | "scot": true, 843 | "sd": true, 844 | "se": true, 845 | "seat": true, 846 | "security": true, 847 | "select": true, 848 | "sener": true, 849 | "services": true, 850 | "seven": true, 851 | "sew": true, 852 | "sex": true, 853 | "sexy": true, 854 | "sfr": true, 855 | "sg": true, 856 | "sh": true, 857 | "sharp": true, 858 | "shell": true, 859 | "shiksha": true, 860 | "shoes": true, 861 | "shop": true, 862 | "shopping": true, 863 | "show": true, 864 | "si": true, 865 | "singles": true, 866 | "site": true, 867 | "sk": true, 868 | "ski": true, 869 | "skin": true, 870 | "sky": true, 871 | "skype": true, 872 | "sl": true, 873 | "sm": true, 874 | "smart": true, 875 | "sn": true, 876 | "sncf": true, 877 | "so": true, 878 | "soccer": true, 879 | "social": true, 880 | "softbank": true, 881 | "software": true, 882 | "sohu": true, 883 | "solar": true, 884 | "solutions": true, 885 | "sony": true, 886 | "soy": true, 887 | "spa": true, 888 | "space": true, 889 | "sport": true, 890 | "sr": true, 891 | "srl": true, 892 | "ss": true, 893 | "st": true, 894 | "stada": true, 895 | "statebank": true, 896 | "statefarm": true, 897 | "stc": true, 898 | "stockholm": true, 899 | "storage": true, 900 | "store": true, 901 | "stream": true, 902 | "studio": true, 903 | "study": true, 904 | "style": true, 905 | "su": true, 906 | "sucks": true, 907 | "supplies": true, 908 | "supply": true, 909 | "support": true, 910 | "surf": true, 911 | "surgery": true, 912 | "suzuki": true, 913 | "sv": true, 914 | "swatch": true, 915 | "swiss": true, 916 | "sx": true, 917 | "sy": true, 918 | "sydney": true, 919 | "systems": true, 920 | "sz": true, 921 | "taipei": true, 922 | "target": true, 923 | "tatamotors": true, 924 | "tatar": true, 925 | "tattoo": true, 926 | "tax": true, 927 | "taxi": true, 928 | "tc": true, 929 | "td": true, 930 | "team": true, 931 | "tech": true, 932 | "technology": true, 933 | "tel": true, 934 | "temasek": true, 935 | "tennis": true, 936 | "teva": true, 937 | "tf": true, 938 | "tg": true, 939 | "th": true, 940 | "theater": true, 941 | "theatre": true, 942 | "tickets": true, 943 | "tienda": true, 944 | "tips": true, 945 | "tires": true, 946 | "tirol": true, 947 | "tj": true, 948 | "tk": true, 949 | "tl": true, 950 | "tm": true, 951 | "tn": true, 952 | "to": true, 953 | "today": true, 954 | "tokyo": true, 955 | "tools": true, 956 | "top": true, 957 | "toray": true, 958 | "toshiba": true, 959 | "total": true, 960 | "tours": true, 961 | "town": true, 962 | "toyota": true, 963 | "toys": true, 964 | "tr": true, 965 | "trade": true, 966 | "trading": true, 967 | "training": true, 968 | "travel": true, 969 | "travelers": true, 970 | "trust": true, 971 | "tt": true, 972 | "tube": true, 973 | "tui": true, 974 | "tv": true, 975 | "tvs": true, 976 | "tw": true, 977 | "tz": true, 978 | "ua": true, 979 | "ug": true, 980 | "uk": true, 981 | "unicom": true, 982 | "university": true, 983 | "uno": true, 984 | "uol": true, 985 | "us": true, 986 | "uy": true, 987 | "uz": true, 988 | "va": true, 989 | "vacations": true, 990 | "vana": true, 991 | "vanguard": true, 992 | "vc": true, 993 | "ve": true, 994 | "vegas": true, 995 | "ventures": true, 996 | "versicherung": true, 997 | "vet": true, 998 | "vg": true, 999 | "vi": true, 1000 | "viajes": true, 1001 | "video": true, 1002 | "vig": true, 1003 | "villas": true, 1004 | "vin": true, 1005 | "vip": true, 1006 | "vision": true, 1007 | "vivo": true, 1008 | "vlaanderen": true, 1009 | "vn": true, 1010 | "vodka": true, 1011 | "vote": true, 1012 | "voting": true, 1013 | "voto": true, 1014 | "voyage": true, 1015 | "vu": true, 1016 | "wales": true, 1017 | "walter": true, 1018 | "wang": true, 1019 | "watch": true, 1020 | "watches": true, 1021 | "webcam": true, 1022 | "weber": true, 1023 | "website": true, 1024 | "wed": true, 1025 | "wedding": true, 1026 | "weir": true, 1027 | "wf": true, 1028 | "whoswho": true, 1029 | "wien": true, 1030 | "wiki": true, 1031 | "williamhill": true, 1032 | "win": true, 1033 | "windows": true, 1034 | "wine": true, 1035 | "wme": true, 1036 | "woodside": true, 1037 | "work": true, 1038 | "works": true, 1039 | "world": true, 1040 | "ws": true, 1041 | "wtf": true, 1042 | "xbox": true, 1043 | "xin": true, 1044 | "xn--1ck2e1b": true, 1045 | "xn--1qqw23a": true, 1046 | "xn--2scrj9c": true, 1047 | "xn--3bst00m": true, 1048 | "xn--3ds443g": true, 1049 | "xn--3e0b707e": true, 1050 | "xn--3hcrj9c": true, 1051 | "xn--45br5cyl": true, 1052 | "xn--45brj9c": true, 1053 | "xn--45q11c": true, 1054 | "xn--4dbrk0ce": true, 1055 | "xn--4gbrim": true, 1056 | "xn--54b7fta0cc": true, 1057 | "xn--55qx5d": true, 1058 | "xn--5tzm5g": true, 1059 | "xn--6frz82g": true, 1060 | "xn--6qq986b3xl": true, 1061 | "xn--80adxhks": true, 1062 | "xn--80ao21a": true, 1063 | "xn--80asehdb": true, 1064 | "xn--80aswg": true, 1065 | "xn--8y0a063a": true, 1066 | "xn--90a3ac": true, 1067 | "xn--90ae": true, 1068 | "xn--90ais": true, 1069 | "xn--9dbq2a": true, 1070 | "xn--bck1b9a5dre4c": true, 1071 | "xn--c1avg": true, 1072 | "xn--cck2b3b": true, 1073 | "xn--clchc0ea0b2g2a9gcd": true, 1074 | "xn--czr694b": true, 1075 | "xn--czrs0t": true, 1076 | "xn--czru2d": true, 1077 | "xn--d1acj3b": true, 1078 | "xn--d1alf": true, 1079 | "xn--e1a4c": true, 1080 | "xn--fct429k": true, 1081 | "xn--fiq228c5hs": true, 1082 | "xn--fiq64b": true, 1083 | "xn--fiqs8s": true, 1084 | "xn--fiqz9s": true, 1085 | "xn--fjq720a": true, 1086 | "xn--fpcrj9c3d": true, 1087 | "xn--fzc2c9e2c": true, 1088 | "xn--g2xx48c": true, 1089 | "xn--gckr3f0f": true, 1090 | "xn--gecrj9c": true, 1091 | "xn--h2breg3eve": true, 1092 | "xn--h2brj9c": true, 1093 | "xn--h2brj9c8c": true, 1094 | "xn--hxt814e": true, 1095 | "xn--i1b6b1a6a2e": true, 1096 | "xn--imr513n": true, 1097 | "xn--io0a7i": true, 1098 | "xn--j1amh": true, 1099 | "xn--j6w193g": true, 1100 | "xn--jvr189m": true, 1101 | "xn--kcrx77d1x4a": true, 1102 | "xn--kprw13d": true, 1103 | "xn--kpry57d": true, 1104 | "xn--kput3i": true, 1105 | "xn--l1acc": true, 1106 | "xn--lgbbat1ad8j": true, 1107 | "xn--mgb9awbf": true, 1108 | "xn--mgba3a4f16a": true, 1109 | "xn--mgbaam7a8h": true, 1110 | "xn--mgbab2bd": true, 1111 | "xn--mgbah1a3hjkrd": true, 1112 | "xn--mgbai9azgqp6j": true, 1113 | "xn--mgbayh7gpa": true, 1114 | "xn--mgbbh1a": true, 1115 | "xn--mgbc0a9azcg": true, 1116 | "xn--mgbca7dzdo": true, 1117 | "xn--mgbcpq6gpa1a": true, 1118 | "xn--mgberp4a5d4ar": true, 1119 | "xn--mgbgu82a": true, 1120 | "xn--mgbpl2fh": true, 1121 | "xn--mgbtx2b": true, 1122 | "xn--mix891f": true, 1123 | "xn--mk1bu44c": true, 1124 | "xn--ngbc5azd": true, 1125 | "xn--ngbe9e0a": true, 1126 | "xn--node": true, 1127 | "xn--nqv7f": true, 1128 | "xn--nyqy26a": true, 1129 | "xn--o3cw4h": true, 1130 | "xn--ogbpf8fl": true, 1131 | "xn--otu796d": true, 1132 | "xn--p1acf": true, 1133 | "xn--p1ai": true, 1134 | "xn--pgbs0dh": true, 1135 | "xn--q7ce6a": true, 1136 | "xn--q9jyb4c": true, 1137 | "xn--qxa6a": true, 1138 | "xn--qxam": true, 1139 | "xn--rhqv96g": true, 1140 | "xn--rovu88b": true, 1141 | "xn--rvc1e0am3e": true, 1142 | "xn--s9brj9c": true, 1143 | "xn--ses554g": true, 1144 | "xn--t60b56a": true, 1145 | "xn--tckwe": true, 1146 | "xn--unup4y": true, 1147 | "xn--vermgensberatung-pwb": true, 1148 | "xn--vhquv": true, 1149 | "xn--vuq861b": true, 1150 | "xn--wgbh1c": true, 1151 | "xn--wgbl6a": true, 1152 | "xn--xhq521b": true, 1153 | "xn--xkc2al3hye2a": true, 1154 | "xn--xkc2dl3a5ee0h": true, 1155 | "xn--y9a3aq": true, 1156 | "xn--yfro4i67o": true, 1157 | "xn--ygbi2ammx": true, 1158 | "xn--zfr164b": true, 1159 | "xxx": true, 1160 | "xyz": true, 1161 | "yachts": true, 1162 | "yahoo": true, 1163 | "yandex": true, 1164 | "ye": true, 1165 | "yodobashi": true, 1166 | "yoga": true, 1167 | "yokohama": true, 1168 | "youtube": true, 1169 | "yt": true, 1170 | "za": true, 1171 | "zappos": true, 1172 | "zara": true, 1173 | "zip": true, 1174 | "zm": true, 1175 | "zone": true, 1176 | "zuerich": true, 1177 | "zw": true, 1178 | "セール": true, 1179 | "佛山": true, 1180 | "ಭಾರತ": true, 1181 | "集团": true, 1182 | "在线": true, 1183 | "한국": true, 1184 | "ଭାରତ": true, 1185 | "ভাৰত": true, 1186 | "ভারত": true, 1187 | "八卦": true, 1188 | "ישראל": true, 1189 | "موقع": true, 1190 | "বাংলা": true, 1191 | "公司": true, 1192 | "网站": true, 1193 | "移动": true, 1194 | "我爱你": true, 1195 | "москва": true, 1196 | "қаз": true, 1197 | "онлайн": true, 1198 | "сайт": true, 1199 | "联通": true, 1200 | "срб": true, 1201 | "бг": true, 1202 | "бел": true, 1203 | "קום": true, 1204 | "ファッション": true, 1205 | "орг": true, 1206 | "ストア": true, 1207 | "சிங்கப்பூர்": true, 1208 | "商标": true, 1209 | "商店": true, 1210 | "商城": true, 1211 | "дети": true, 1212 | "мкд": true, 1213 | "ею": true, 1214 | "家電": true, 1215 | "中文网": true, 1216 | "中信": true, 1217 | "中国": true, 1218 | "中國": true, 1219 | "娱乐": true, 1220 | "భారత్": true, 1221 | "ලංකා": true, 1222 | "购物": true, 1223 | "クラウド": true, 1224 | "ભારત": true, 1225 | "भारतम्": true, 1226 | "भारत": true, 1227 | "भारोत": true, 1228 | "网店": true, 1229 | "संगठन": true, 1230 | "餐厅": true, 1231 | "网络": true, 1232 | "укр": true, 1233 | "香港": true, 1234 | "食品": true, 1235 | "飞利浦": true, 1236 | "台湾": true, 1237 | "台灣": true, 1238 | "手机": true, 1239 | "мон": true, 1240 | "الجزائر": true, 1241 | "عمان": true, 1242 | "ایران": true, 1243 | "امارات": true, 1244 | "بازار": true, 1245 | "موريتانيا": true, 1246 | "پاکستان": true, 1247 | "الاردن": true, 1248 | "بارت": true, 1249 | "المغرب": true, 1250 | "ابوظبي": true, 1251 | "البحرين": true, 1252 | "السعودية": true, 1253 | "ڀارت": true, 1254 | "سودان": true, 1255 | "عراق": true, 1256 | "澳門": true, 1257 | "닷컴": true, 1258 | "شبكة": true, 1259 | "بيتك": true, 1260 | "გე": true, 1261 | "机构": true, 1262 | "健康": true, 1263 | "ไทย": true, 1264 | "سورية": true, 1265 | "招聘": true, 1266 | "рус": true, 1267 | "рф": true, 1268 | "تونس": true, 1269 | "ລາວ": true, 1270 | "みんな": true, 1271 | "ευ": true, 1272 | "ελ": true, 1273 | "世界": true, 1274 | "書籍": true, 1275 | "ഭാരതം": true, 1276 | "ਭਾਰਤ": true, 1277 | "网址": true, 1278 | "닷넷": true, 1279 | "コム": true, 1280 | "游戏": true, 1281 | "vermögensberatung": true, 1282 | "企业": true, 1283 | "信息": true, 1284 | "مصر": true, 1285 | "قطر": true, 1286 | "广东": true, 1287 | "இலங்கை": true, 1288 | "இந்தியா": true, 1289 | "հայ": true, 1290 | "新加坡": true, 1291 | "فلسطين": true, 1292 | "政务": true, 1293 | "onion": true 1294 | } 1295 | } -------------------------------------------------------------------------------- /lib/url-matcher.js: -------------------------------------------------------------------------------- 1 | var tlds = require("./tlds.json"), 2 | RE = { 3 | PROTOCOL: "([a-z][-a-z*]+://)?", 4 | USER: "(?:([\\w:.+-]+)@)?", 5 | DOMAIN_UNI: `([a-z0-9-.\\u00A0-\\uFFFF]+\\.[a-z0-9-${tlds.chars}]{1,${tlds.maxLength}})`, 6 | DOMAIN: `([a-z0-9-.]+\\.[a-z0-9-]{1,${tlds.maxLength}})`, 7 | PORT: "(:\\d+\\b)?", 8 | PATH_UNI: "([/?#]\\S*)?", 9 | PATH: "([/?#][\\w-.~!$&*+;=:@%/?#(),'\\[\\]]*)?" 10 | }, 11 | TLD_TABLE = tlds.table; 12 | 13 | function regexEscape(text) { 14 | return text.replace(/[[\]\\^-]/g, "\\$&"); 15 | } 16 | 17 | function buildRegex({ 18 | unicode = false, customRules = [], standalone = false, 19 | boundaryLeft, boundaryRight 20 | }) { 21 | var pattern = RE.PROTOCOL + RE.USER; 22 | 23 | if (unicode) { 24 | pattern += RE.DOMAIN_UNI + RE.PORT + RE.PATH_UNI; 25 | } else { 26 | pattern += RE.DOMAIN + RE.PORT + RE.PATH; 27 | } 28 | 29 | if (customRules.length) { 30 | pattern = "(?:(" + customRules.join("|") + ")|" + pattern + ")"; 31 | } else { 32 | pattern = "()" + pattern; 33 | } 34 | 35 | var prefix, suffix, invalidSuffix; 36 | if (standalone) { 37 | if (boundaryLeft) { 38 | prefix = "((?:^|\\s)[" + regexEscape(boundaryLeft) + "]*?)"; 39 | } else { 40 | prefix = "(^|\\s)"; 41 | } 42 | if (boundaryRight) { 43 | suffix = "([" + regexEscape(boundaryRight) + "]*(?:$|\\s))"; 44 | } else { 45 | suffix = "($|\\s)"; 46 | } 47 | invalidSuffix = "[^\\s" + regexEscape(boundaryRight) + "]"; 48 | } else { 49 | prefix = "(^|\\b|_)"; 50 | suffix = "()"; 51 | } 52 | 53 | pattern = prefix + pattern + suffix; 54 | 55 | return { 56 | url: new RegExp(pattern, "igm"), 57 | invalidSuffix: invalidSuffix && new RegExp(invalidSuffix), 58 | mustache: /\{\{[\s\S]+?\}\}/g 59 | }; 60 | } 61 | 62 | function pathStrip(m, re, repl) { 63 | var s = m.path.replace(re, repl); 64 | 65 | if (s == m.path) return; 66 | 67 | m.end -= m.path.length - s.length; 68 | m.suffix = m.path.slice(s.length) + m.suffix; 69 | m.path = s; 70 | } 71 | 72 | function pathStripQuote(m, c) { 73 | var i = 0, s = m.path, end, pos = 0; 74 | 75 | if (!s.endsWith(c)) return; 76 | 77 | while ((pos = s.indexOf(c, pos)) >= 0) { 78 | if (i % 2) { 79 | end = null; 80 | } else { 81 | end = pos; 82 | } 83 | pos++; 84 | i++; 85 | } 86 | 87 | if (!end) return; 88 | 89 | m.end -= s.length - end; 90 | m.path = s.slice(0, end); 91 | m.suffix = s.slice(end) + m.suffix; 92 | } 93 | 94 | function pathStripBrace(m, left, right) { 95 | var str = m.path, 96 | re = new RegExp("[\\" + left + "\\" + right + "]", "g"), 97 | match, count = 0, end; 98 | 99 | // Match loop 100 | while ((match = re.exec(str))) { 101 | if (count % 2 == 0) { 102 | end = match.index; 103 | if (match[0] == right) { 104 | break; 105 | } 106 | } else { 107 | if (match[0] == left) { 108 | break; 109 | } 110 | } 111 | count++; 112 | } 113 | 114 | if (!match && count % 2 == 0) { 115 | return; 116 | } 117 | 118 | m.end -= m.path.length - end; 119 | m.path = str.slice(0, end); 120 | m.suffix = str.slice(end) + m.suffix; 121 | } 122 | 123 | function isIP(s) { 124 | var m, i; 125 | if (!(m = s.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/))) { 126 | return false; 127 | } 128 | for (i = 1; i < m.length; i++) { 129 | if (+m[i] > 255 || (m[i].length > 1 && m[i][0] == "0")) { 130 | return false; 131 | } 132 | } 133 | return true; 134 | } 135 | 136 | function inTLDS(domain) { 137 | var match = domain.match(/\.([^.]+)$/); 138 | if (!match) { 139 | return false; 140 | } 141 | var key = match[1].toLowerCase(); 142 | // eslint-disable-next-line no-prototype-builtins 143 | return TLD_TABLE.hasOwnProperty(key); 144 | } 145 | 146 | class UrlMatcher { 147 | constructor(options = {}) { 148 | this.options = options; 149 | this.regex = buildRegex(options); 150 | } 151 | 152 | *match(text) { 153 | var { 154 | fuzzyIp = true, 155 | ignoreMustache = false, 156 | mail = true 157 | } = this.options, 158 | { 159 | url, 160 | invalidSuffix, 161 | mustache 162 | } = this.regex, 163 | urlLastIndex, mustacheLastIndex; 164 | 165 | mustache.lastIndex = 0; 166 | url.lastIndex = 0; 167 | 168 | var mustacheMatch, mustacheRange; 169 | if (ignoreMustache) { 170 | mustacheMatch = mustache.exec(text); 171 | if (mustacheMatch) { 172 | mustacheRange = { 173 | start: mustacheMatch.index, 174 | end: mustache.lastIndex 175 | }; 176 | } 177 | } 178 | 179 | var urlMatch; 180 | while ((urlMatch = url.exec(text))) { 181 | const result = { 182 | start: 0, 183 | end: 0, 184 | 185 | text: "", 186 | url: "", 187 | 188 | prefix: urlMatch[1], 189 | custom: urlMatch[2], 190 | protocol: urlMatch[3], 191 | auth: urlMatch[4] || "", 192 | domain: urlMatch[5], 193 | port: urlMatch[6] || "", 194 | path: urlMatch[7] || "", 195 | suffix: urlMatch[8] 196 | }; 197 | 198 | if (result.custom) { 199 | result.start = urlMatch.index; 200 | result.end = url.lastIndex; 201 | result.text = result.url = urlMatch[0]; 202 | } else { 203 | 204 | result.start = urlMatch.index + result.prefix.length; 205 | result.end = url.lastIndex - result.suffix.length; 206 | } 207 | 208 | if (mustacheRange && mustacheRange.end <= result.start) { 209 | mustacheMatch = mustache.exec(text); 210 | if (mustacheMatch) { 211 | mustacheRange.start = mustacheMatch.index; 212 | mustacheRange.end = mustache.lastIndex; 213 | } else { 214 | mustacheRange = null; 215 | } 216 | } 217 | 218 | // ignore urls inside mustache pair 219 | if (mustacheRange && result.start < mustacheRange.end && result.end >= mustacheRange.start) { 220 | continue; 221 | } 222 | 223 | if (!result.custom) { 224 | // adjust path and suffix 225 | if (result.path) { 226 | // Strip BBCode 227 | pathStrip(result, /\[\/?(b|i|u|url|img|quote|code|size|color)\].*/i, ""); 228 | 229 | // Strip braces 230 | pathStripBrace(result, "(", ")"); 231 | pathStripBrace(result, "[", "]"); 232 | pathStripBrace(result, "{", "}"); 233 | 234 | // Strip quotes 235 | pathStripQuote(result, "'"); 236 | pathStripQuote(result, '"'); 237 | 238 | // Remove trailing ".,?" 239 | pathStrip(result, /(^|[^-_])[.,?]+$/, "$1"); 240 | } 241 | 242 | // check suffix 243 | if (invalidSuffix && invalidSuffix.test(result.suffix)) { 244 | if (/\s$/.test(result.suffix)) { 245 | url.lastIndex--; 246 | } 247 | continue; 248 | } 249 | 250 | // ignore fuzzy ip 251 | if (!fuzzyIp && isIP(result.domain) && 252 | !result.protocol && !result.auth && !result.path) { 253 | continue; 254 | } 255 | 256 | // mailto protocol 257 | if (!result.protocol && result.auth) { 258 | var matchMail = result.auth.match(/^mailto:(.+)/); 259 | if (matchMail) { 260 | result.protocol = "mailto:"; 261 | result.auth = matchMail[1]; 262 | } 263 | } 264 | 265 | // http alias 266 | if (result.protocol && result.protocol.match(/^(hxxp|h\*\*p|ttp)/)) { 267 | result.protocol = "http://"; 268 | } 269 | 270 | // guess protocol 271 | if (!result.protocol) { 272 | var domainMatch; 273 | if ((domainMatch = result.domain.match(/^(ftp|irc)/))) { 274 | result.protocol = domainMatch[0] + "://"; 275 | } else if (result.domain.match(/^(www|web)/)) { 276 | result.protocol = "http://"; 277 | } else if (result.auth && result.auth.indexOf(":") < 0 && !result.path) { 278 | result.protocol = "mailto:"; 279 | } else { 280 | result.protocol = "http://"; 281 | } 282 | } 283 | 284 | // ignore mail 285 | if (!mail && result.protocol === "mailto:") { 286 | continue; 287 | } 288 | 289 | // verify domain 290 | if (!isIP(result.domain)) { 291 | if (/^(http|https|mailto)/.test(result.protocol) && !inTLDS(result.domain)) { 292 | continue; 293 | } 294 | 295 | const invalidLabel = getInvalidLabel(result.domain); 296 | if (invalidLabel) { 297 | url.lastIndex = urlMatch.index + invalidLabel.index + 1; 298 | continue; 299 | } 300 | } 301 | 302 | // Create URL 303 | result.url = result.protocol + (result.auth && result.auth + "@") + result.domain + result.port + result.path; 304 | result.text = text.slice(result.start, result.end); 305 | } 306 | 307 | // since regex is shared with other parse generators, cache lastIndex position and restore later 308 | mustacheLastIndex = mustache.lastIndex; 309 | urlLastIndex = url.lastIndex; 310 | 311 | yield result; 312 | 313 | url.lastIndex = urlLastIndex; 314 | mustache.lastIndex = mustacheLastIndex; 315 | } 316 | } 317 | } 318 | 319 | function getInvalidLabel(domain) { 320 | // https://tools.ietf.org/html/rfc1035 321 | // https://serverfault.com/questions/638260/is-it-valid-for-a-hostname-to-start-with-a-digit 322 | let index = 0; 323 | const parts = domain.split("."); 324 | for (const part of parts) { 325 | if ( 326 | !part || 327 | part.startsWith("-") || 328 | part.endsWith("-") 329 | ) { 330 | return { 331 | index, 332 | value: part 333 | }; 334 | } 335 | index += part.length + 1; 336 | } 337 | } 338 | 339 | module.exports = { 340 | UrlMatcher 341 | }; 342 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "linkify-plus-plus-core", 3 | "version": "0.7.0", 4 | "description": "A JavaScript library for linkification stuff", 5 | "keywords": [ 6 | "linkify" 7 | ], 8 | "homepage": "https://github.com/eight04/linkify-plus-plus-core", 9 | "bugs": { 10 | "url": "https://github.com/eight04/linkify-plus-plus-core/issues", 11 | "email": "eight04@gmail.com" 12 | }, 13 | "license": "BSD-3-Clause", 14 | "author": "eight ", 15 | "main": "index.js", 16 | "repository": "eight04/linkify-plus-plus-core", 17 | "devDependencies": { 18 | "@open-wc/testing": "^4.0.0", 19 | "@rollup/plugin-json": "^6.1.0", 20 | "@rollup/plugin-node-resolve": "^16.0.0", 21 | "@rollup/plugin-terser": "^0.4.4", 22 | "@web/dev-server": "^0.4.6", 23 | "@web/dev-server-rollup": "^0.6.4", 24 | "@web/test-runner": "^0.20.0", 25 | "@web/test-runner-commands": "^0.9.0", 26 | "c8": "^10.1.3", 27 | "cheerio": "^1.0.0", 28 | "eslint": "^9.20.1", 29 | "eslint-plugin-compat": "^6.0.2", 30 | "rollup": "^4.34.8", 31 | "rollup-plugin-cjs-es": "^3.0.0" 32 | }, 33 | "scripts": { 34 | "build-tlds": "node build-tlds.js > lib/tlds.json", 35 | "build": "rollup -c", 36 | "test": "eslint . && npm run build && web-test-runner test/*", 37 | "test-cover": "npm test -- --coverage", 38 | "preversion": "npm test", 39 | "version": "npm run build && git add .", 40 | "postversion": "git push --follow-tags && npm publish" 41 | }, 42 | "dependencies": { 43 | "event-lite": "^1.0.0" 44 | }, 45 | "browserslist": [ 46 | "Firefox >= 56" 47 | ], 48 | "eslintIgnore": [ 49 | "dist" 50 | ], 51 | "files": [ 52 | "dist", 53 | "lib" 54 | ] 55 | } 56 | -------------------------------------------------------------------------------- /rollup.config.mjs: -------------------------------------------------------------------------------- 1 | import cjs from "rollup-plugin-cjs-es"; 2 | import resolve from "@rollup/plugin-node-resolve"; 3 | import terser from "@rollup/plugin-terser"; 4 | import json from "@rollup/plugin-json"; 5 | 6 | export default [ 7 | createConfig({ 8 | output: {file: "dist/linkify-plus-plus-core.js"} 9 | }), 10 | createConfig({ 11 | output: {file: "dist/linkify-plus-plus-core.esm.js", format: "es"} 12 | }), 13 | createConfig({ 14 | output: {file: "dist/linkify-plus-plus-core.min.js"}, 15 | plugins: [ 16 | terser({ 17 | compress: { 18 | passes: 3 19 | } 20 | }) 21 | ] 22 | }) 23 | ]; 24 | 25 | function createConfig({output, plugins = []}) { 26 | return { 27 | input: "index.js", 28 | output: { 29 | format: "iife", 30 | name: "linkifyPlusPlusCore", 31 | sourcemap: true, 32 | ...output 33 | }, 34 | plugins: [ 35 | resolve(), 36 | json(), 37 | cjs({ 38 | nested: true 39 | }), 40 | ...plugins 41 | ] 42 | }; 43 | } 44 | -------------------------------------------------------------------------------- /test/__snapshots__/test.snap.js: -------------------------------------------------------------------------------- 1 | /* @web/test-runner snapshot v1 */ 2 | export const snapshots = {}; 3 | 4 | snapshots["recursive off"] = 5 | `
example.com example.com`; 6 | /* end snapshot recursive off */ 7 | 8 | snapshots["basic"] = 9 | `example.com example.com`; 10 | /* end snapshot basic */ 11 | 12 | snapshots["wbr"] = 13 | `example.com`; 14 | /* end snapshot wbr */ 15 | 16 | snapshots["invalid tags"] = 17 | ``; 18 | /* end snapshot invalid tags */ 19 | 20 | -------------------------------------------------------------------------------- /test/test.mjs: -------------------------------------------------------------------------------- 1 | /* eslint-env mocha browser */ 2 | import {assert} from "@open-wc/testing"; 3 | import {compareSnapshot} from "@web/test-runner-commands"; 4 | 5 | import {UrlMatcher, linkify} from "../dist/linkify-plus-plus-core.esm.js"; 6 | 7 | describe("UrlMatcher", () => { 8 | 9 | function prepare(options) { 10 | var matcher = new UrlMatcher(options), 11 | match = (text, start = 0, end = text.length) => { 12 | if (end <= 0) { 13 | end += text.length; 14 | } 15 | var [result] = matcher.match(text); 16 | assert.equal(result.start, start); 17 | assert.equal(result.end, end); 18 | return result; 19 | }; 20 | 21 | match.no = (text) => { 22 | var [result] = matcher.match(text); 23 | assert.equal(result, undefined); 24 | }; 25 | 26 | return match; 27 | } 28 | 29 | var match = prepare(); 30 | 31 | it("basic", () => { 32 | match("http://example.com"); 33 | match("http://example.com/"); 34 | match("http://example.com/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-.~!$&*+;=:@%/?#(),'[]"); 35 | match("test@google.com"); 36 | }); 37 | 38 | it("domain", () => { 39 | match("http://exa-mple.com"); 40 | }); 41 | 42 | it("braces", () => { 43 | match("(http://example.com)", 1, -1); 44 | match("http://example.com)", 0, -1); 45 | match("http://example.com/(foo)"); 46 | match("http://example.com/(f o o)", 0, 19); 47 | }); 48 | 49 | it("http alias", () => { 50 | assert.equal(match("ttp://example.com").protocol, "http://"); 51 | assert.equal(match("h**p://example.com").protocol, "http://"); 52 | assert.equal(match("hxxp://example.com").protocol, "http://"); 53 | }); 54 | 55 | it("IP address", () => { 56 | match("http://127.0.0.1"); 57 | match.no("http://127.0.0.256"); 58 | match.no("http://127.0.0.01"); 59 | }); 60 | 61 | it("protocol guessing", () => { 62 | assert.equal(match("example.com").protocol, "http://"); 63 | assert.equal(match("user@example.com").protocol, "mailto:"); 64 | assert.equal(match("user@www.example.com").protocol, "http://"); 65 | assert.equal(match("user:pass@example.com").protocol, "http://"); 66 | assert.equal(match("user@example.com/path/").protocol, "http://"); 67 | assert.equal(match("ftp.example.com").protocol, "ftp://"); 68 | assert.equal(match("irc.example.com").protocol, "irc://"); 69 | }); 70 | 71 | it("dots", () => { 72 | match("http://example.com.", 0, -1); 73 | match("http://example.com..", 0, -2); 74 | match("http://example.com...", 0, -3); 75 | match("http://example.com/.", 0, -1); 76 | match("http://example.com/..", 0, -2); 77 | match("http://example.com/...", 0, -3); 78 | }); 79 | 80 | it("question mark", () => { 81 | match("http://example.com?", 0, -1); 82 | }); 83 | 84 | it("comma", () => { 85 | match("http://example.com/path,", 0, -1); 86 | match("http://example.com/path,path-continue"); 87 | }); 88 | 89 | it("bad tlds", () => { 90 | // now .zip is more common 91 | // match.no("http://example.zip"); 92 | match.no("http://example.free"); 93 | match.no("http://example.call"); 94 | match.no("http://example.constructor"); 95 | }); 96 | 97 | it("ignore bad tlds for unknown protocol", () => { 98 | match("macupdater://com.busymac.busycal3"); 99 | }); 100 | 101 | it("bbcode", () => { 102 | match("[img]http://example.com[/img]", 5, -6); 103 | match("http://example.com[b]something-else[/b]", 0, 18); 104 | }); 105 | 106 | it("mustache", () => { 107 | var match = prepare({ignoreMustache: true}); 108 | match.no("{{http://example.com}}"); 109 | match.no("{{\nhttp://example.com\n}}"); 110 | }); 111 | 112 | it("custom rules", () => { 113 | const match = prepare({customRules: [ 114 | "magnet:\\?\\S+" 115 | ]}); 116 | match("magnet:?xt=urn:btih:c12fe1c06bba254a9dc9f519b335aa7c1367a88a&dn"); 117 | }); 118 | 119 | it("custom rules should take priority", () => { 120 | const match = prepare({customRules: [ 121 | "http://...example\\.com" 122 | ]}); 123 | match("http://-.-example.com", 0); 124 | }); 125 | 126 | it("no mail", () => { 127 | const match = prepare({mail: false}); 128 | match.no("test@google.com"); 129 | }); 130 | 131 | it("domain with dash or dot", () => { 132 | match("-example.com", 1); 133 | match(".example.com", 1); 134 | match("-.example.com", 2); 135 | }); 136 | 137 | it("infinite loop bug", () => { 138 | match("example com example.-invalid.com", 21); 139 | }); 140 | 141 | it("match domains starting with numbers", () => { 142 | match("https://1fichier.com"); 143 | match("https://9292.nl"); 144 | }); 145 | 146 | it("onion links", () => { 147 | match("http://example.onion"); 148 | }); 149 | }); 150 | 151 | describe("Linkifier", () => { 152 | let matcher; 153 | let body; 154 | before(() => { 155 | matcher = new UrlMatcher(); 156 | body = document.querySelector("body"); 157 | }); 158 | 159 | it("basic", async () => { 160 | body.innerHTML = "example.com example.com"; 161 | await linkify(body, {matcher}); 162 | await compareSnapshot({ 163 | name: "basic", 164 | content: body.innerHTML 165 | }); 166 | }); 167 | 168 | it("recursive off", async () => { 169 | body.innerHTML = "example.com example.com"; 170 | await linkify(body, {matcher, recursive: false}); 171 | await compareSnapshot({ 172 | name: "recursive off", 173 | content: body.innerHTML 174 | }); 175 | }); 176 | 177 | it("wbr", async () => { 178 | body.innerHTML = "example.com"; 179 | await linkify(body, {matcher, recursive: false}); 180 | await compareSnapshot({ 181 | name: "wbr", 182 | content: body.innerHTML 183 | }); 184 | }); 185 | 186 | it("invalid tags", async () => { 187 | body.innerHTML = ""; 188 | await linkify(body, {matcher, recursive: false}); 189 | await compareSnapshot({ 190 | name: "invalid tags", 191 | content: body.innerHTML 192 | }); 193 | }); 194 | 195 | }); 196 | -------------------------------------------------------------------------------- /web-test-runner.config.mjs: -------------------------------------------------------------------------------- 1 | // import { fromRollup } from '@web/dev-server-rollup'; 2 | // import cjs from 'rollup-plugin-cjs-es'; 3 | 4 | export default { 5 | nodeResolve: true, 6 | // FIXME: https://github.com/modernweb-dev/web/issues/2637 7 | // coverageConfig: { 8 | // exclude: [ 9 | // "node_modules/**/*", 10 | // ] 11 | // } 12 | // FIXME: https://github.com/modernweb-dev/web/issues/2640 13 | // plugins: [ 14 | // [cjs, { nested: true, cache: false, include: ["lib/**/*"]}] 15 | // ].map(([plugin, options]) => fromRollup(plugin)(options)) 16 | }; 17 | 18 | --------------------------------------------------------------------------------