linkify-it
Advanced tools
+99
-94
@@ -308,7 +308,2 @@ 'use strict'; | ||
| function resetScanCache (self) { | ||
| self.__index__ = -1; | ||
| self.__text_cache__ = ''; | ||
| } | ||
| function createValidator (re) { | ||
@@ -352,4 +347,7 @@ return function (text, pos) { | ||
| re.email_fuzzy = RegExp(untpl(re.tpl_email_fuzzy), 'i'); | ||
| re.email_fuzzy_global = RegExp(untpl(re.tpl_email_fuzzy), 'ig'); | ||
| re.link_fuzzy = RegExp(untpl(re.tpl_link_fuzzy), 'i'); | ||
| re.link_fuzzy_global = RegExp(untpl(re.tpl_link_fuzzy), 'ig'); | ||
| re.link_no_ip_fuzzy = RegExp(untpl(re.tpl_link_no_ip_fuzzy), 'i'); | ||
| re.link_no_ip_fuzzy_global = RegExp(untpl(re.tpl_link_no_ip_fuzzy), 'ig'); | ||
| re.host_fuzzy_test = RegExp(untpl(re.tpl_host_fuzzy_test), 'i'); | ||
@@ -448,8 +446,2 @@ | ||
| ); | ||
| // | ||
| // Cleanup | ||
| // | ||
| resetScanCache(self); | ||
| } | ||
@@ -462,6 +454,4 @@ | ||
| **/ | ||
| function Match (self, shift) { | ||
| const start = self.__index__; | ||
| const end = self.__last_index__; | ||
| const text = self.__text_cache__.slice(start, end); | ||
| function Match (text, schema, index, lastIndex) { | ||
| const raw = text.slice(index, lastIndex); | ||
@@ -473,3 +463,3 @@ /** | ||
| **/ | ||
| this.schema = self.__schema__.toLowerCase(); | ||
| this.schema = schema.toLowerCase(); | ||
| /** | ||
@@ -480,3 +470,3 @@ * Match#index -> Number | ||
| **/ | ||
| this.index = start + shift; | ||
| this.index = index; | ||
| /** | ||
@@ -487,3 +477,3 @@ * Match#lastIndex -> Number | ||
| **/ | ||
| this.lastIndex = end + shift; | ||
| this.lastIndex = lastIndex; | ||
| /** | ||
@@ -494,3 +484,3 @@ * Match#raw -> String | ||
| **/ | ||
| this.raw = text; | ||
| this.raw = raw; | ||
| /** | ||
@@ -501,3 +491,3 @@ * Match#text -> String | ||
| **/ | ||
| this.text = text; | ||
| this.text = raw; | ||
| /** | ||
@@ -508,13 +498,5 @@ * Match#url -> String | ||
| **/ | ||
| this.url = text; | ||
| this.url = raw; | ||
| } | ||
| function createMatch (self, shift) { | ||
| const match = new Match(self, shift); | ||
| self.__compiled__[match.schema].normalize(match, self); | ||
| return match | ||
| } | ||
| /** | ||
@@ -572,8 +554,2 @@ * class LinkifyIt | ||
| // Cache last tested result. Used to skip repeating steps on next `match` call. | ||
| this.__index__ = -1; | ||
| this.__last_index__ = -1; // Next scan position | ||
| this.__schema__ = ''; | ||
| this.__text_cache__ = ''; | ||
| this.__schemas__ = assign({}, defaultSchemas, schemas); | ||
@@ -620,9 +596,5 @@ this.__compiled__ = {}; | ||
| LinkifyIt.prototype.test = function test (text) { | ||
| // Reset scan cache | ||
| this.__text_cache__ = text; | ||
| this.__index__ = -1; | ||
| if (!text.length) { return false } | ||
| let m, ml, me, len, shift, next, re, tld_pos, at_pos; | ||
| let m, re; | ||
@@ -634,9 +606,3 @@ // try to scan for link with schema - that's the most simple rule | ||
| while ((m = re.exec(text)) !== null) { | ||
| len = this.testSchemaAt(text, m[2], re.lastIndex); | ||
| if (len) { | ||
| this.__schema__ = m[2]; | ||
| this.__index__ = m.index + m[1].length; | ||
| this.__last_index__ = m.index + m[0].length + len; | ||
| break | ||
| } | ||
| if (this.testSchemaAt(text, m[2], re.lastIndex)) { return true } | ||
| } | ||
@@ -647,15 +613,5 @@ } | ||
| // guess schemaless links | ||
| tld_pos = text.search(this.re.host_fuzzy_test); | ||
| if (tld_pos >= 0) { | ||
| // if tld is located after found link - no need to check fuzzy pattern | ||
| if (this.__index__ < 0 || tld_pos < this.__index__) { | ||
| if ((ml = text.match(this.__opts__.fuzzyIP ? this.re.link_fuzzy : this.re.link_no_ip_fuzzy)) !== null) { | ||
| shift = ml.index + ml[1].length; | ||
| if (this.__index__ < 0 || shift < this.__index__) { | ||
| this.__schema__ = ''; | ||
| this.__index__ = shift; | ||
| this.__last_index__ = ml.index + ml[0].length; | ||
| } | ||
| } | ||
| if (text.search(this.re.host_fuzzy_test) >= 0) { | ||
| if (text.match(this.__opts__.fuzzyIP ? this.re.link_fuzzy : this.re.link_no_ip_fuzzy) !== null) { | ||
| return true | ||
| } | ||
@@ -667,21 +623,10 @@ } | ||
| // guess schemaless emails | ||
| at_pos = text.indexOf('@'); | ||
| if (at_pos >= 0) { | ||
| if (text.indexOf('@') >= 0) { | ||
| // We can't skip this check, because this cases are possible: | ||
| // 192.168.1.1@gmail.com, my.in@example.com | ||
| if ((me = text.match(this.re.email_fuzzy)) !== null) { | ||
| shift = me.index + me[1].length; | ||
| next = me.index + me[0].length; | ||
| if (this.__index__ < 0 || shift < this.__index__ || | ||
| (shift === this.__index__ && next > this.__last_index__)) { | ||
| this.__schema__ = 'mailto:'; | ||
| this.__index__ = shift; | ||
| this.__last_index__ = next; | ||
| } | ||
| } | ||
| if (text.match(this.re.email_fuzzy) !== null) { return true } | ||
| } | ||
| } | ||
| return this.__index__ >= 0 | ||
| return false | ||
| }; | ||
@@ -735,21 +680,86 @@ | ||
| const result = []; | ||
| let shift = 0; | ||
| const type_schemed = []; | ||
| const type_fuzzy_link = []; | ||
| const type_fuzzy_email = []; | ||
| let m, len, re; | ||
| // Try to take previous element from cache, if .test() called before | ||
| if (this.__index__ >= 0 && this.__text_cache__ === text) { | ||
| result.push(createMatch(this, shift)); | ||
| shift = this.__last_index__; | ||
| function choose (a, b) { | ||
| if (!a) { return b } | ||
| if (!b) { return a } | ||
| if (a.index !== b.index) { return a.index < b.index ? a : b } | ||
| return a.lastIndex >= b.lastIndex ? a : b | ||
| } | ||
| // Cut head if cache was used | ||
| let tail = shift ? text.slice(shift) : text; | ||
| if (!text.length) { return null } | ||
| // Scan string until end reached | ||
| while (this.test(tail)) { | ||
| result.push(createMatch(this, shift)); | ||
| // scan for links with schema | ||
| if (this.re.schema_test.test(text)) { | ||
| re = this.re.schema_search; | ||
| re.lastIndex = 0; | ||
| while ((m = re.exec(text)) !== null) { | ||
| len = this.testSchemaAt(text, m[2], re.lastIndex); | ||
| if (len) { | ||
| type_schemed.push({ | ||
| schema: m[2], | ||
| index: m.index + m[1].length, | ||
| lastIndex: m.index + m[0].length + len | ||
| }); | ||
| } | ||
| } | ||
| } | ||
| tail = tail.slice(this.__last_index__); | ||
| shift += this.__last_index__; | ||
| if (this.__opts__.fuzzyLink && this.__compiled__['http:']) { | ||
| re = this.__opts__.fuzzyIP ? this.re.link_fuzzy_global : this.re.link_no_ip_fuzzy_global; | ||
| re.lastIndex = 0; | ||
| while ((m = re.exec(text)) !== null) { | ||
| type_fuzzy_link.push({ | ||
| schema: '', | ||
| index: m.index + m[1].length, | ||
| lastIndex: m.index + m[0].length | ||
| }); | ||
| } | ||
| } | ||
| if (this.__opts__.fuzzyEmail && this.__compiled__['mailto:']) { | ||
| re = this.re.email_fuzzy_global; | ||
| re.lastIndex = 0; | ||
| while ((m = re.exec(text)) !== null) { | ||
| type_fuzzy_email.push({ | ||
| schema: 'mailto:', | ||
| index: m.index + m[1].length, | ||
| lastIndex: m.index + m[0].length | ||
| }); | ||
| } | ||
| } | ||
| const indexes = [0, 0, 0]; | ||
| let lastIndex = 0; | ||
| for (;;) { | ||
| const candidates = [ | ||
| type_schemed[indexes[0]], | ||
| type_fuzzy_email[indexes[1]], | ||
| type_fuzzy_link[indexes[2]] | ||
| ]; | ||
| const candidate = choose(choose(candidates[0], candidates[1]), candidates[2]); | ||
| if (!candidate) { break } | ||
| if (candidate === candidates[0]) { | ||
| indexes[0]++; | ||
| } else if (candidate === candidates[1]) { | ||
| indexes[1]++; | ||
| } else { | ||
| indexes[2]++; | ||
| } | ||
| if (candidate.index < lastIndex) { continue } | ||
| const match = new Match(text, candidate.schema, candidate.index, candidate.lastIndex); | ||
| this.__compiled__[match.schema].normalize(match, this); | ||
| result.push(match); | ||
| lastIndex = candidate.lastIndex; | ||
| } | ||
| if (result.length) { | ||
@@ -769,6 +779,2 @@ return result | ||
| LinkifyIt.prototype.matchAtStart = function matchAtStart (text) { | ||
| // Reset scan cache | ||
| this.__text_cache__ = text; | ||
| this.__index__ = -1; | ||
| if (!text.length) return null | ||
@@ -782,7 +788,6 @@ | ||
| this.__schema__ = m[2]; | ||
| this.__index__ = m.index + m[1].length; | ||
| this.__last_index__ = m.index + m[0].length + len; | ||
| const match = new Match(text, m[2], m.index + m[1].length, m.index + m[0].length + len); | ||
| return createMatch(this, 0) | ||
| this.__compiled__[match.schema].normalize(match, this); | ||
| return match | ||
| }; | ||
@@ -789,0 +794,0 @@ |
+99
-94
@@ -118,7 +118,2 @@ import reFactory from './lib/re.mjs' | ||
| function resetScanCache (self) { | ||
| self.__index__ = -1 | ||
| self.__text_cache__ = '' | ||
| } | ||
| function createValidator (re) { | ||
@@ -162,4 +157,7 @@ return function (text, pos) { | ||
| re.email_fuzzy = RegExp(untpl(re.tpl_email_fuzzy), 'i') | ||
| re.email_fuzzy_global = RegExp(untpl(re.tpl_email_fuzzy), 'ig') | ||
| re.link_fuzzy = RegExp(untpl(re.tpl_link_fuzzy), 'i') | ||
| re.link_fuzzy_global = RegExp(untpl(re.tpl_link_fuzzy), 'ig') | ||
| re.link_no_ip_fuzzy = RegExp(untpl(re.tpl_link_no_ip_fuzzy), 'i') | ||
| re.link_no_ip_fuzzy_global = RegExp(untpl(re.tpl_link_no_ip_fuzzy), 'ig') | ||
| re.host_fuzzy_test = RegExp(untpl(re.tpl_host_fuzzy_test), 'i') | ||
@@ -258,8 +256,2 @@ | ||
| ) | ||
| // | ||
| // Cleanup | ||
| // | ||
| resetScanCache(self) | ||
| } | ||
@@ -272,6 +264,4 @@ | ||
| **/ | ||
| function Match (self, shift) { | ||
| const start = self.__index__ | ||
| const end = self.__last_index__ | ||
| const text = self.__text_cache__.slice(start, end) | ||
| function Match (text, schema, index, lastIndex) { | ||
| const raw = text.slice(index, lastIndex) | ||
@@ -283,3 +273,3 @@ /** | ||
| **/ | ||
| this.schema = self.__schema__.toLowerCase() | ||
| this.schema = schema.toLowerCase() | ||
| /** | ||
@@ -290,3 +280,3 @@ * Match#index -> Number | ||
| **/ | ||
| this.index = start + shift | ||
| this.index = index | ||
| /** | ||
@@ -297,3 +287,3 @@ * Match#lastIndex -> Number | ||
| **/ | ||
| this.lastIndex = end + shift | ||
| this.lastIndex = lastIndex | ||
| /** | ||
@@ -304,3 +294,3 @@ * Match#raw -> String | ||
| **/ | ||
| this.raw = text | ||
| this.raw = raw | ||
| /** | ||
@@ -311,3 +301,3 @@ * Match#text -> String | ||
| **/ | ||
| this.text = text | ||
| this.text = raw | ||
| /** | ||
@@ -318,13 +308,5 @@ * Match#url -> String | ||
| **/ | ||
| this.url = text | ||
| this.url = raw | ||
| } | ||
| function createMatch (self, shift) { | ||
| const match = new Match(self, shift) | ||
| self.__compiled__[match.schema].normalize(match, self) | ||
| return match | ||
| } | ||
| /** | ||
@@ -382,8 +364,2 @@ * class LinkifyIt | ||
| // Cache last tested result. Used to skip repeating steps on next `match` call. | ||
| this.__index__ = -1 | ||
| this.__last_index__ = -1 // Next scan position | ||
| this.__schema__ = '' | ||
| this.__text_cache__ = '' | ||
| this.__schemas__ = assign({}, defaultSchemas, schemas) | ||
@@ -430,9 +406,5 @@ this.__compiled__ = {} | ||
| LinkifyIt.prototype.test = function test (text) { | ||
| // Reset scan cache | ||
| this.__text_cache__ = text | ||
| this.__index__ = -1 | ||
| if (!text.length) { return false } | ||
| let m, ml, me, len, shift, next, re, tld_pos, at_pos | ||
| let m, re | ||
@@ -444,9 +416,3 @@ // try to scan for link with schema - that's the most simple rule | ||
| while ((m = re.exec(text)) !== null) { | ||
| len = this.testSchemaAt(text, m[2], re.lastIndex) | ||
| if (len) { | ||
| this.__schema__ = m[2] | ||
| this.__index__ = m.index + m[1].length | ||
| this.__last_index__ = m.index + m[0].length + len | ||
| break | ||
| } | ||
| if (this.testSchemaAt(text, m[2], re.lastIndex)) { return true } | ||
| } | ||
@@ -457,15 +423,5 @@ } | ||
| // guess schemaless links | ||
| tld_pos = text.search(this.re.host_fuzzy_test) | ||
| if (tld_pos >= 0) { | ||
| // if tld is located after found link - no need to check fuzzy pattern | ||
| if (this.__index__ < 0 || tld_pos < this.__index__) { | ||
| if ((ml = text.match(this.__opts__.fuzzyIP ? this.re.link_fuzzy : this.re.link_no_ip_fuzzy)) !== null) { | ||
| shift = ml.index + ml[1].length | ||
| if (this.__index__ < 0 || shift < this.__index__) { | ||
| this.__schema__ = '' | ||
| this.__index__ = shift | ||
| this.__last_index__ = ml.index + ml[0].length | ||
| } | ||
| } | ||
| if (text.search(this.re.host_fuzzy_test) >= 0) { | ||
| if (text.match(this.__opts__.fuzzyIP ? this.re.link_fuzzy : this.re.link_no_ip_fuzzy) !== null) { | ||
| return true | ||
| } | ||
@@ -477,21 +433,10 @@ } | ||
| // guess schemaless emails | ||
| at_pos = text.indexOf('@') | ||
| if (at_pos >= 0) { | ||
| if (text.indexOf('@') >= 0) { | ||
| // We can't skip this check, because this cases are possible: | ||
| // 192.168.1.1@gmail.com, my.in@example.com | ||
| if ((me = text.match(this.re.email_fuzzy)) !== null) { | ||
| shift = me.index + me[1].length | ||
| next = me.index + me[0].length | ||
| if (this.__index__ < 0 || shift < this.__index__ || | ||
| (shift === this.__index__ && next > this.__last_index__)) { | ||
| this.__schema__ = 'mailto:' | ||
| this.__index__ = shift | ||
| this.__last_index__ = next | ||
| } | ||
| } | ||
| if (text.match(this.re.email_fuzzy) !== null) { return true } | ||
| } | ||
| } | ||
| return this.__index__ >= 0 | ||
| return false | ||
| } | ||
@@ -545,21 +490,86 @@ | ||
| const result = [] | ||
| let shift = 0 | ||
| const type_schemed = [] | ||
| const type_fuzzy_link = [] | ||
| const type_fuzzy_email = [] | ||
| let m, len, re | ||
| // Try to take previous element from cache, if .test() called before | ||
| if (this.__index__ >= 0 && this.__text_cache__ === text) { | ||
| result.push(createMatch(this, shift)) | ||
| shift = this.__last_index__ | ||
| function choose (a, b) { | ||
| if (!a) { return b } | ||
| if (!b) { return a } | ||
| if (a.index !== b.index) { return a.index < b.index ? a : b } | ||
| return a.lastIndex >= b.lastIndex ? a : b | ||
| } | ||
| // Cut head if cache was used | ||
| let tail = shift ? text.slice(shift) : text | ||
| if (!text.length) { return null } | ||
| // Scan string until end reached | ||
| while (this.test(tail)) { | ||
| result.push(createMatch(this, shift)) | ||
| // scan for links with schema | ||
| if (this.re.schema_test.test(text)) { | ||
| re = this.re.schema_search | ||
| re.lastIndex = 0 | ||
| while ((m = re.exec(text)) !== null) { | ||
| len = this.testSchemaAt(text, m[2], re.lastIndex) | ||
| if (len) { | ||
| type_schemed.push({ | ||
| schema: m[2], | ||
| index: m.index + m[1].length, | ||
| lastIndex: m.index + m[0].length + len | ||
| }) | ||
| } | ||
| } | ||
| } | ||
| tail = tail.slice(this.__last_index__) | ||
| shift += this.__last_index__ | ||
| if (this.__opts__.fuzzyLink && this.__compiled__['http:']) { | ||
| re = this.__opts__.fuzzyIP ? this.re.link_fuzzy_global : this.re.link_no_ip_fuzzy_global | ||
| re.lastIndex = 0 | ||
| while ((m = re.exec(text)) !== null) { | ||
| type_fuzzy_link.push({ | ||
| schema: '', | ||
| index: m.index + m[1].length, | ||
| lastIndex: m.index + m[0].length | ||
| }) | ||
| } | ||
| } | ||
| if (this.__opts__.fuzzyEmail && this.__compiled__['mailto:']) { | ||
| re = this.re.email_fuzzy_global | ||
| re.lastIndex = 0 | ||
| while ((m = re.exec(text)) !== null) { | ||
| type_fuzzy_email.push({ | ||
| schema: 'mailto:', | ||
| index: m.index + m[1].length, | ||
| lastIndex: m.index + m[0].length | ||
| }) | ||
| } | ||
| } | ||
| const indexes = [0, 0, 0] | ||
| let lastIndex = 0 | ||
| for (;;) { | ||
| const candidates = [ | ||
| type_schemed[indexes[0]], | ||
| type_fuzzy_email[indexes[1]], | ||
| type_fuzzy_link[indexes[2]] | ||
| ] | ||
| const candidate = choose(choose(candidates[0], candidates[1]), candidates[2]) | ||
| if (!candidate) { break } | ||
| if (candidate === candidates[0]) { | ||
| indexes[0]++ | ||
| } else if (candidate === candidates[1]) { | ||
| indexes[1]++ | ||
| } else { | ||
| indexes[2]++ | ||
| } | ||
| if (candidate.index < lastIndex) { continue } | ||
| const match = new Match(text, candidate.schema, candidate.index, candidate.lastIndex) | ||
| this.__compiled__[match.schema].normalize(match, this) | ||
| result.push(match) | ||
| lastIndex = candidate.lastIndex | ||
| } | ||
| if (result.length) { | ||
@@ -579,6 +589,2 @@ return result | ||
| LinkifyIt.prototype.matchAtStart = function matchAtStart (text) { | ||
| // Reset scan cache | ||
| this.__text_cache__ = text | ||
| this.__index__ = -1 | ||
| if (!text.length) return null | ||
@@ -592,7 +598,6 @@ | ||
| this.__schema__ = m[2] | ||
| this.__index__ = m.index + m[1].length | ||
| this.__last_index__ = m.index + m[0].length + len | ||
| const match = new Match(text, m[2], m.index + m[1].length, m.index + m[0].length + len) | ||
| return createMatch(this, 0) | ||
| this.__compiled__[match.schema].normalize(match, this) | ||
| return match | ||
| } | ||
@@ -599,0 +604,0 @@ |
+11
-1
| { | ||
| "name": "linkify-it", | ||
| "version": "5.0.0", | ||
| "version": "5.0.1", | ||
| "description": "Links recognition library with FULL unicode support", | ||
@@ -30,2 +30,12 @@ "keywords": [ | ||
| "license": "MIT", | ||
| "funding": [ | ||
| { | ||
| "type": "github", | ||
| "url": "https://github.com/sponsors/puzrin" | ||
| }, | ||
| { | ||
| "type": "github", | ||
| "url": "https://github.com/sponsors/markdown-it" | ||
| } | ||
| ], | ||
| "scripts": { | ||
@@ -32,0 +42,0 @@ "lint": "eslint .", |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
56003
1.1%1374
1.18%0
-100%